NEURON
nrnpy_nrn.cpp
Go to the documentation of this file.
3 #include "nrn_ansi.h"
4 #include "cabcode.h"
5 #include "nrnpython.h"
6 #include <exception>
7 #include <structmember.h>
8 #include <InterViews/resource.h>
9 #include "nrniv_mf.h"
10 #include <nrnoc2iv.h>
11 #include "nrnpy.h"
12 #include "nrnpy_utils.h"
14 #include "neuron/unique_cstr.hpp"
15 
16 #ifndef M_PI
17 #define M_PI (3.14159265358979323846)
18 #endif
19 
20 #include <membfunc.h>
21 #include <parse.hpp>
22 
23 #include <cmath>
24 #include <cstdio>
25 #include <cstring>
26 #include <sstream>
27 #include <string>
28 #include <utility>
29 #include <vector>
30 
31 #include <nanobind/nanobind.h>
32 
33 namespace nb = nanobind;
34 
35 extern void nrn_pt3dremove(Section* sec, int i0);
36 extern void nrn_pt3dinsert(Section* sec, int i0, double x, double y, double z, double d);
37 extern void nrn_pt3dchange1(Section* sec, int i, double d);
38 extern void nrn_pt3dchange2(Section* sec, int i, double x, double y, double z, double diam);
39 extern void nrn_pt3dstyle1(Section* sec, double x, double y, double z);
40 extern void nrn_pt3dstyle0(Section* sec);
41 
42 extern PyObject* nrn_ptr_richcmp(void* self_ptr, void* other_ptr, int op);
43 // used to be static in nrnpy_hoc.cpp
44 extern int hocobj_pushargs(PyObject*, std::vector<neuron::unique_cstr>&);
45 
46 
48  PyObject_HEAD
51 };
52 
54  PyObject_HEAD
56  int seg_iter_;
57 };
58 
59 struct NPySegObj {
60  PyObject_HEAD
62  double x_;
63 };
64 
65 struct NPyMechObj {
66  PyObject_HEAD
69  // Following cannot be initialized when NPyMechObj allocated by Python. See new_pymechobj
70  // wrapper.
72  int type_;
73 };
74 
76  PyObject_HEAD
78 };
79 
80 struct NPyMechFunc {
81  PyObject_HEAD
84 };
85 
87  PyObject_HEAD
90  int i_;
91 };
92 
93 struct NPyRVItr {
94  PyObject_HEAD
96  int index_;
97 };
98 
99 struct NPyRangeVar {
100  PyObject_HEAD
103  int isptr_;
104  int attr_from_sec_; // so section.xraxial[0] = e assigns to all segments.
105 };
106 
108  PyObject_HEAD
109 };
110 
111 PyTypeObject* psection_type;
112 static PyTypeObject* pallseg_of_sec_iter_type;
113 static PyTypeObject* pseg_of_sec_iter_type;
114 static PyTypeObject* psegment_type;
115 static PyTypeObject* pmech_of_seg_iter_generic_type;
116 static PyTypeObject* pmech_generic_type;
117 static PyTypeObject* pmechfunc_generic_type;
118 static PyTypeObject* pvar_of_mech_iter_generic_type;
119 static PyTypeObject* range_type;
120 static PyTypeObject* opaque_pointer_type;
121 
122 PyObject* pmech_types; // Python map for name to Mechanism
123 PyObject* rangevars_; // Python map for name to Symbol
124 
125 extern PyTypeObject* hocobject_type;
126 extern void simpleconnectsection();
127 extern short* nrn_is_artificial_;
129 extern PyObject* nrnpy_forall_safe(PyObject* self, PyObject* args);
130 static void nrnpy_reg_mech(int);
131 extern void (*nrnpy_reg_mech_p_)(int);
132 static int ob_is_seg(Object*);
133 extern int (*nrnpy_ob_is_seg)(Object*);
134 static Object* seg_from_sec_x(Section*, double x);
135 extern Object* (*nrnpy_seg_from_sec_x)(Section*, double x);
136 static Section* o2sec(Object*);
137 extern Section* (*nrnpy_o2sec_p_)(Object*);
138 static void o2loc(Object*, Section**, double*);
139 extern void (*nrnpy_o2loc_p_)(Object*, Section**, double*);
140 extern void (*nrnpy_o2loc2_p_)(Object*, Section**, double*);
141 extern char* (*nrnpy_pysec_name_p_)(Section*);
142 static char* pysec_name(Section*);
143 extern Object* (*nrnpy_pysec_cell_p_)(Section*);
144 static Object* pysec_cell(Section*);
145 static PyObject* pysec2cell(NPySecObj*);
146 extern int (*nrnpy_pysec_cell_equals_p_)(Section*, Object*);
147 static int pysec_cell_equals(Section*, Object*);
148 static void remake_pmech_types();
149 
151  PyErr_SetString(PyExc_ReferenceError, "can't access a deleted section");
152 }
153 
155  PyErr_SetString(PyExc_ReferenceError, "mechanism instance is invalid");
156 }
157 
158 static char* pysec_name(Section* sec) {
159  static char buf[512];
160  if (sec->prop) {
161  auto* ps = static_cast<NPySecObj*>(sec->prop->dparam[PROP_PY_INDEX].get<void*>());
162  buf[0] = '\0';
163  if (ps->name_) {
164  Sprintf(buf, "%s", ps->name_);
165  } else {
166  Sprintf(buf, "__nrnsec_%p", sec);
167  }
168  return buf;
169  }
170  return 0;
171 }
172 
174  if (!sec->prop) {
175  return nullptr;
176  }
177  if (auto* pv = sec->prop->dparam[PROP_PY_INDEX].get<void*>(); pv) {
178  PyObject* cell_weakref = static_cast<NPySecObj*>(pv)->cell_weakref_;
179  if (cell_weakref) {
180 #if PY_VERSION_HEX >= 0x030D0000
181  PyObject* cell = nullptr;
182  int err = PyWeakref_GetRef(cell_weakref, &cell);
183  if (err == -1) {
184  PyErr_Print();
185  hoc_execerror("Error getting cell for", secname(sec));
186  } else if (err == 0) {
187  return nullptr;
188  }
189  auto ret = nrnpy_po2ho(cell);
190  Py_DECREF(cell);
191  return ret;
192 #else
193  PyObject* cell = PyWeakref_GetObject(cell_weakref);
194  if (!cell) {
195  PyErr_Print();
196  hoc_execerror("Error getting cell for", secname(sec));
197  } else if (cell != Py_None) {
198  return nrnpy_po2ho(cell);
199  }
200 #endif
201  }
202  }
203  return NULL;
204 }
205 
206 static int NpySObj_contains(PyObject* s, PyObject* obj, const char* string) {
207  /* Checks is provided PyObject* s matches obj.<string> */
208  auto pyobj = nb::borrow(obj); // keep refcount+1 during use
209  if (!nb::hasattr(pyobj, string)) {
210  return 0;
211  }
212  auto obj_seg = pyobj.attr(string);
213  return nb::handle{s}.equal(obj_seg);
214 }
215 
217  /* report that we contain the object if it has a .sec that is equal to ourselves */
218  return NpySObj_contains(sec, obj, "sec");
219 }
220 
223 }
224 
225 static int pysec_cell_equals(Section* sec, Object* obj) {
226  if (!sec->prop) {
227  return 0;
228  }
229  if (auto* pv = sec->prop->dparam[PROP_PY_INDEX].get<void*>(); pv) {
230  PyObject* cell_weakref = static_cast<NPySecObj*>(pv)->cell_weakref_;
231  if (cell_weakref) {
232 #if PY_VERSION_HEX >= 0x030D0000
233  PyObject* cell = nullptr;
234  int err = PyWeakref_GetRef(cell_weakref, &cell);
235  if (err == -1) {
236  PyErr_Print();
237  hoc_execerror("Error getting cell for", secname(sec));
238  }
239  auto ret = nrnpy_ho_eq_po(obj, cell);
240  Py_DECREF(cell);
241  return ret;
242 #else
243  PyObject* cell = PyWeakref_GetObject(cell_weakref);
244  if (!cell) {
245  PyErr_Print();
246  hoc_execerror("Error getting cell for", secname(sec));
247  }
248  return nrnpy_ho_eq_po(obj, cell);
249 #endif
250  }
251  return nrnpy_ho_eq_po(obj, Py_None);
252  }
253  return 0;
254 }
255 
256 static void NPySecObj_dealloc(NPySecObj* self) {
257  // printf("NPySecObj_dealloc %p %s\n", self, secname(self->sec_));
258  if (self->sec_) {
259  if (self->name_) {
260  nrnpy_pysecname2sec_remove(self->sec_);
261  delete[] self->name_;
262  }
263  Py_XDECREF(self->cell_weakref_);
264  if (self->sec_->prop) {
265  self->sec_->prop->dparam[PROP_PY_INDEX] = nullptr;
266  }
267  if (self->sec_->prop && !self->sec_->prop->dparam[0].get<Symbol*>()) {
268  sec_free(self->sec_->prop->dparam[8].get<hoc_Item*>());
269  } else {
270  section_unref(self->sec_);
271  }
272  }
273  ((PyObject*) self)->ob_type->tp_free((PyObject*) self);
274 }
275 
276 static void NPySecObj_dealloc_safe(NPySecObj* self) {
277  // Don't wrap because it must not fail.
278  NPySecObj_dealloc(self);
279 }
280 
281 
283  // printf("NPyAllSegOfSecIter_dealloc %p %s\n", self, secname(self->pysec_->sec_));
284  Py_XDECREF(self->pysec_);
285  ((PyObject*) self)->ob_type->tp_free((PyObject*) self);
286 }
287 
289  // No wrapping, because it must not throw.
291 }
292 
294  // printf("NPySegOfSecIter_dealloc %p %s\n", self, secname(self->pysec_->sec_));
295  Py_XDECREF(self->pysec_);
296  ((PyObject*) self)->ob_type->tp_free((PyObject*) self);
297 }
298 
300  // Not wrapped because it must not throw.
302 }
303 
304 static void NPySegObj_dealloc(NPySegObj* self) {
305  // printf("NPySegObj_dealloc %p\n", self);
306  Py_XDECREF(self->pysec_);
307  ((PyObject*) self)->ob_type->tp_free((PyObject*) self);
308 }
309 
310 static void NPySegObj_dealloc_safe(NPySegObj* self) {
311  // Not wrapped because it must not throw exceptions.
312  NPySegObj_dealloc(self);
313 }
314 
315 static void NPyRangeVar_dealloc(NPyRangeVar* self) {
316  // printf("NPyRangeVar_dealloc %p\n", self);
317  Py_XDECREF(self->pymech_);
318  ((PyObject*) self)->ob_type->tp_free((PyObject*) self);
319 }
320 
322  NPyRangeVar_dealloc(self);
323 }
324 
325 static void NPyMechObj_dealloc(NPyMechObj* self) {
326  // printf("NPyMechObj_dealloc %p %s\n", self, self->ob_type->tp_name);
327  Py_XDECREF(self->pyseg_);
328  // Must manually call destructor since it was manually constructed in new_pymechobj wrapper
329  self->prop_id_.~non_owning_identifier_without_container();
330  ((PyObject*) self)->ob_type->tp_free((PyObject*) self);
331 }
332 
334  NPyMechObj_dealloc(self);
335 }
336 
338  NPyMechObj* m = PyObject_New(NPyMechObj, pmech_generic_type);
339  if (m) {
340  // Use "placement new" idiom since Python C allocation cannot call the initializer to start
341  // it as "null". So later `a = b` might segfault because copy constructor decrements the
342  // refcount of `a`s nonsense memory.
344  m->pyseg_ = nullptr;
345  m->prop_ = nullptr;
346  }
347 
348  return m;
349 }
350 
351 // Only call if p is valid
353  NPyMechObj* m = new_pymechobj();
354  if (!m) {
355  return NULL;
356  }
357  Py_INCREF(pyseg);
358  m->pyseg_ = pyseg;
359  m->prop_ = p;
360  m->prop_id_ = p->id();
361  m->type_ = p->_type;
362  return m;
363 }
364 
365 static void NPyMechFunc_dealloc(NPyMechFunc* self) {
366  // printf("NPyMechFunc_dealloc %p %s\n", self, self->ob_type->tp_name);
367  Py_XDECREF(self->pymech_);
368  ((PyObject*) self)->ob_type->tp_free((PyObject*) self);
369 }
370 
372  NPyMechFunc_dealloc(self);
373 }
374 
376  // printf("NPyMechOfSegIter_dealloc %p %s\n", self, self->ob_type->tp_name);
377  Py_XDECREF(self->pymech_);
378  ((PyObject*) self)->ob_type->tp_free((PyObject*) self);
379 }
380 
383 }
384 
386  // printf("NPyVarOfMechIter_dealloc %p %s\n", self, self->ob_type->tp_name);
387  Py_XDECREF(self->pymech_);
388  ((PyObject*) self)->ob_type->tp_free((PyObject*) self);
389 }
390 
393 }
394 
395 // A new (or inited) python Section object with no arg creates a nrnoc section
396 // which persists only while the python object exists. The nrnoc section
397 // structure
398 // has no hoc Symbol but the Python Section pointer is filled in
399 // and secname(sec) returns the Python Section object name from the hoc section.
400 // If a Python Section object is created from an existing nrnoc section
401 // (with a filled in Symbol) the nrnoc section will continue to exist until
402 // the hoc delete_section() is called on it.
403 //
404 
405 static int NPySecObj_init(NPySecObj* self, PyObject* args, PyObject* kwds) {
406  // printf("NPySecObj_init %p %p\n", self, self->sec_);
407  static const char* kwlist[] = {"name", "cell", NULL};
408  if (self != NULL && !self->sec_) {
409  delete[] self->name_;
410  self->name_ = 0;
411  self->cell_weakref_ = 0;
412  char* name = 0;
413  PyObject* cell = 0;
414  // avoid "warning: deprecated conversion from string constant to char*"
415  // someday eliminate the (char**) when python changes their prototype
416  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sO", (char**) kwlist, &name, &cell)) {
417  return -1;
418  }
419  if (cell && cell != Py_None) {
420  self->cell_weakref_ = PyWeakref_NewRef(cell, NULL);
421  if (!self->cell_weakref_) {
422  return -1;
423  }
424  } else {
425  cell = 0;
426  }
427  if (name) {
428  size_t n = strlen(name) + 1; // include terminator
429 
430  if (cell) {
431  // include cellname in name so nrnpy_pysecname2sec_remove can determine
432 
433  auto cell_str = nb::steal(PyObject_Str(cell));
434  if (!cell_str) {
435  Py_XDECREF(self->cell_weakref_);
436  return -1;
437  }
438  auto str = Py2NRNString::as_ascii(cell_str.ptr());
439  if (!str.is_valid()) {
440  Py2NRNString::set_pyerr(PyExc_TypeError,
441  "cell name contains non ascii character");
442  Py_XDECREF(self->cell_weakref_);
443  return -1;
444  }
445  char* cp = str.c_str();
446  n += strlen(cp) + 1; // include dot
447  self->name_ = new char[n];
448  std::snprintf(self->name_, n, "%s.%s", cp, name);
449  } else {
450  self->name_ = new char[n];
451  std::strncpy(self->name_, name, n);
452  }
453  }
454  self->sec_ = nrnpy_newsection(self);
455  nrnpy_pysecname2sec_add(self->sec_);
456  }
457  return 0;
458 }
459 
460 static int NPySecObj_init_safe(NPySecObj* self, PyObject* args, PyObject* kwds) {
461  return nrn::convert_cxx_exceptions(NPySecObj_init, self, args, kwds);
462 }
463 
464 static int NPyAllSegOfSecIter_init(NPyAllSegOfSecIter* self, PyObject* args, PyObject* /* kwds */) {
465  NPySecObj* pysec;
466  // printf("NPyAllSegOfSecIter_init %p %p\n", self, self->sec_);
467  if (self != NULL && !self->pysec_) {
468  if (!PyArg_ParseTuple(args, "O!", psection_type, &pysec)) {
469  return -1;
470  }
471  self->allseg_iter_ = 0;
472  Py_INCREF(pysec);
473  self->pysec_ = pysec;
474  }
475  return 0;
476 }
477 
479  return nrn::convert_cxx_exceptions(NPyAllSegOfSecIter_init, self, args, kwds);
480 }
481 
482 PyObject* NPySecObj_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
483  auto self = nb::steal(type->tp_alloc(type, 0));
484  // printf("NPySecObj_new %p\n", self.ptr());
485  if (self) {
486  if (NPySecObj_init((NPySecObj*) self.ptr(), args, kwds) != 0) {
487  return nullptr;
488  }
489  }
490  return self.release().ptr();
491 }
492 
493 PyObject* NPySecObj_new_safe(PyTypeObject* type, PyObject* args, PyObject* kwds) {
494  return nrn::convert_cxx_exceptions(NPySecObj_new, type, args, kwds);
495 }
496 
497 PyObject* NPyAllSegOfSecIter_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
498  auto self = nb::steal(type->tp_alloc(type, 0));
499  // printf("NPyAllSegOfSecIter_new %p\n", self.ptr());
500  if (self) {
501  if (NPyAllSegOfSecIter_init((NPyAllSegOfSecIter*) self.ptr(), args, kwds) != 0) {
502  return nullptr;
503  }
504  }
505  return self.release().ptr();
506 }
507 
510 }
511 
512 PyObject* nrnpy_newsecobj(PyObject* /* self */, PyObject* args, PyObject* kwds) {
513  return NPySecObj_new(psection_type, args, kwds);
514 }
515 
517  return nrn::convert_cxx_exceptions(nrnpy_newsecobj, self, args, kwds);
518 }
519 
520 static PyObject* NPySegObj_new(PyTypeObject* type, PyObject* args, PyObject* /* kwds */) {
521  NPySecObj* pysec;
522  double x;
523  if (!PyArg_ParseTuple(args, "O!d", psection_type, &pysec, &x)) {
524  return NULL;
525  }
526  if (x > 1.0 && x < 1.0001) {
527  x = 1.0;
528  }
529  if (x < 0. || x > 1.0) {
530  PyErr_SetString(PyExc_ValueError, "segment position range is 0 <= x <= 1");
531  return NULL;
532  }
533  NPySegObj* self;
534  self = (NPySegObj*) type->tp_alloc(type, 0);
535  // printf("NPySegObj_new %p\n", self);
536  if (self != NULL) {
537  Py_INCREF(pysec);
538  self->pysec_ = pysec;
539  self->x_ = x;
540  }
541  return (PyObject*) self;
542 }
543 
544 static PyObject* NPySegObj_new_safe(PyTypeObject* type, PyObject* args, PyObject* kwds) {
545  return nrn::convert_cxx_exceptions(NPySegObj_new, type, args, kwds);
546 }
547 
548 static PyObject* NPyMechObj_new(PyTypeObject* type, PyObject* args, PyObject* /* kwds */) {
549  NPySegObj* pyseg;
550  if (!PyArg_ParseTuple(args, "O!", psegment_type, &pyseg)) {
551  return NULL;
552  }
553  NPyMechObj* self;
554  self = (NPyMechObj*) type->tp_alloc(type, 0);
555  // printf("NPyMechObj_new %p %s\n", self,
556  // ((PyObject*)self)->ob_type->tp_name);
557  if (self != NULL) {
558  new (self) NPyMechObj;
559  Py_INCREF(pyseg);
560  self->pyseg_ = pyseg;
561  }
562  return (PyObject*) self;
563 }
564 
565 static PyObject* NPyMechObj_new_safe(PyTypeObject* type, PyObject* args, PyObject* kwds) {
566  return nrn::convert_cxx_exceptions(NPyMechObj_new, type, args, kwds);
567 }
568 
569 static int NPySegObj_contains(PyObject* segment, PyObject* obj) {
570  /* report that we contain the object if it has a .segment that is equal to ourselves */
571  return NpySObj_contains(segment, obj, "segment");
572 }
573 
574 static int NPySegObj_contains_safe(PyObject* segment, PyObject* obj) {
575  return nrn::convert_cxx_exceptions(NPySegObj_contains, segment, obj);
576 }
577 
578 static PyObject* NPyRangeVar_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
579  NPyRangeVar* self;
580  self = (NPyRangeVar*) type->tp_alloc(type, 0);
581  if (self != NULL) {
582  self->pymech_ = NULL;
583  self->sym_ = NULL;
584  self->isptr_ = 0;
585  self->attr_from_sec_ = 0;
586  }
587  return (PyObject*) self;
588 }
589 
590 static PyObject* NPyRangeVar_new_safe(PyTypeObject* type, PyObject* args, PyObject* kwds) {
591  return nrn::convert_cxx_exceptions(NPyRangeVar_new, type, args, kwds);
592 }
593 
594 static int NPySegObj_init(NPySegObj* self, PyObject* /* args */, PyObject* /* kwds */) {
595  // PySeg objects are fully initialized in __new__
596  // And strangely Python seems to never call this, as if the __new__ objs were not its instances
597  // So don't implement anything here
598  return 0;
599 }
600 
601 static int ob_is_seg(Object* o) {
602  if (!o || o->ctemplate->sym != nrnpy_pyobj_sym_) {
603  return 0;
604  }
605  PyObject* po = nrnpy_hoc2pyobject(o);
606  if (!PyObject_TypeCheck(po, psegment_type)) {
607  return 0;
608  }
609  return 1;
610 }
611 
612 static Section* o2sec(Object* o) {
613  if (o->ctemplate->sym != nrnpy_pyobj_sym_) {
614  hoc_execerror("not a Python nrn.Section", 0);
615  }
616  PyObject* po = nrnpy_hoc2pyobject(o);
617  if (!PyObject_TypeCheck(po, psection_type)) {
618  hoc_execerror("not a Python nrn.Section", 0);
619  }
620  auto* pysec = (NPySecObj*) po;
621  return pysec->sec_;
622 }
623 
624 static void o2loc(Object* o, Section** psec, double* px) {
625  if (o->ctemplate->sym != nrnpy_pyobj_sym_) {
626  hoc_execerror("not a Python nrn.Segment", 0);
627  }
628  PyObject* po = nrnpy_hoc2pyobject(o);
629  if (!PyObject_TypeCheck(po, psegment_type)) {
630  hoc_execerror("not a Python nrn.Segment", 0);
631  }
632  auto* pyseg = (NPySegObj*) po;
633  *psec = pyseg->pysec_->sec_;
634  if (!(*psec)->prop) {
635  hoc_execerr_ext("nrn.Segment associated with deleted internal Section");
636  }
637  *px = pyseg->x_;
638 }
639 
640 inline nb::object obj_get_segment(nb::object py_obj) {
641  // If object is list of single elem, use it
642  if (PyList_Check(py_obj.ptr())) {
643  nb::list obj_list{std::move(py_obj)};
644  if (obj_list.size() != 1) {
645  hoc_execerror("If a list is supplied, it must be of length 1", 0);
646  }
647  py_obj = obj_list[0];
648  }
649 
650  auto seg_obj = py_obj.attr("segment");
651  if (!seg_obj.is_valid()) {
652  hoc_execerror("not a Python nrn.Segment, rxd.node, or other with a segment property",
653  nullptr);
654  }
655  return seg_obj;
656 }
657 
658 static void o2loc2(Object* o, Section** psec, double* px) {
659  if (o->ctemplate->sym != nrnpy_pyobj_sym_) {
660  hoc_execerror("not a Python nrn.Segment, rxd.node, or other with a segment property",
661  nullptr);
662  }
663 
664  // track objects with borrow so that ref-count ends up neutral
665  auto py_obj_seg = nb::borrow(nrnpy_hoc2pyobject(o));
666  if (!PyObject_TypeCheck(py_obj_seg.ptr(), psegment_type)) {
667  // Attempt to get a segment from any object. May throw
668  py_obj_seg = obj_get_segment(py_obj_seg);
669  }
670 
671  auto* pyseg = (NPySegObj*) py_obj_seg.ptr();
672  *psec = pyseg->pysec_->sec_;
673  *px = pyseg->x_;
674  if (!(*psec)->prop) {
675  hoc_execerr_ext("nrn.Segment associated with deleted internal Section");
676  }
677 }
678 
679 static int NPyMechObj_init(NPyMechObj* self, PyObject* args, PyObject* kwds) {
680  // printf("NPyMechObj_init %p %p %s\n", self, self->pyseg_,
681  // ((PyObject*)self)->ob_type->tp_name);
682  NPySegObj* pyseg;
683  if (!PyArg_ParseTuple(args, "O!", psegment_type, &pyseg)) {
684  return -1;
685  }
686  Py_INCREF(pyseg);
687  Py_XDECREF(self->pyseg_);
688  self->pyseg_ = pyseg;
689  return 0;
690 }
691 
692 static int NPyMechObj_init_safe(NPyMechObj* self, PyObject* args, PyObject* kwds) {
693  return nrn::convert_cxx_exceptions(NPyMechObj_init, self, args, kwds);
694 }
695 
696 static int NPyRangeVar_init(NPyRangeVar* self, PyObject* args, PyObject* kwds) {
697  return 0;
698 }
699 
700 static int NPyRangeVar_init_safe(NPyRangeVar* self, PyObject* args, PyObject* kwds) {
701  return nrn::convert_cxx_exceptions(NPyRangeVar_init, self, args, kwds);
702 }
703 
704 // Returns a new reference.
706  return PyString_FromString(secname(self->sec_));
707 }
708 
711 }
712 
714  CHECK_SEC_INVALID(self->sec_);
715  return PyInt_FromLong(self->sec_->npt3d);
716 }
717 
720 }
721 
723  Section* sec = self->sec_;
725  int i0;
726  if (!PyArg_ParseTuple(args, "i", &i0)) {
727  return NULL;
728  }
729  if (i0 < 0 || i0 >= sec->npt3d) {
730  PyErr_SetString(PyExc_Exception, "Arg out of range\n");
731  return NULL;
732  }
733 
734  nrn_pt3dremove(sec, i0);
735  Py_RETURN_NONE;
736 }
737 
739  Section* sec = self->sec_;
741  int req = 0;
742  Py_ssize_t narg = PyTuple_GET_SIZE(args);
743  if (narg) {
744  if (!PyArg_ParseTuple(args, "i", &req)) {
745  return NULL;
746  }
747  }
748  if (req < 0) {
749  PyErr_SetString(PyExc_Exception, "Arg out of range\n");
750  return NULL;
751  }
752  nrn_pt3dclear(sec, req);
753  return PyInt_FromLong(sec->pt3d_bsize);
754 }
755 
758 }
759 
761  Section* sec = self->sec_;
763  int i;
764  double x, y, z, diam;
765  Py_ssize_t narg = PyTuple_GET_SIZE(args);
766  if (narg == 2) {
767  if (!PyArg_ParseTuple(args, "id", &i, &diam)) {
768  return NULL;
769  }
770  if (i < 0 || i >= sec->npt3d) {
771  PyErr_SetString(PyExc_Exception, "Arg out of range\n");
772  return NULL;
773  }
774  nrn_pt3dchange1(sec, i, diam);
775  } else if (narg == 5) {
776  if (!PyArg_ParseTuple(args, "idddd", &i, &x, &y, &z, &diam)) {
777  return NULL;
778  }
779  if (i < 0 || i >= sec->npt3d) {
780  PyErr_SetString(PyExc_Exception, "Arg out of range\n");
781  return NULL;
782  }
783  nrn_pt3dchange2(sec, i, x, y, z, diam);
784  } else {
785  PyErr_SetString(PyExc_Exception, "Wrong number of arguments\n");
786  return NULL;
787  }
788  Py_RETURN_NONE;
789 }
790 
793 }
794 
796  Section* sec = self->sec_;
798  int i;
799  double x, y, z, d;
800  if (!PyArg_ParseTuple(args, "idddd", &i, &x, &y, &z, &d)) {
801  return NULL;
802  }
803  if (i < 0 || i > sec->npt3d) {
804  PyErr_SetString(PyExc_Exception, "Arg out of range\n");
805  return NULL;
806  }
807  nrn_pt3dinsert(sec, i, x, y, z, d);
808  Py_RETURN_NONE;
809 }
810 
813 }
814 
816  Section* sec = self->sec_;
818  double x, y, z, d;
819  // TODO: add support for iterables
820  if (!PyArg_ParseTuple(args, "dddd", &x, &y, &z, &d)) {
821  return NULL;
822  }
823  stor_pt3d(sec, x, y, z, d);
824  Py_RETURN_NONE;
825 }
826 
829 }
830 
832  Section* sec = self->sec_;
834  int style;
835  double x, y, z;
836  Py_ssize_t narg = PyTuple_GET_SIZE(args);
837 
838  if (narg) {
839  if (narg == 1) {
840  if (!PyArg_ParseTuple(args, "i", &style)) {
841  return NULL;
842  }
843  if (style) {
844  PyErr_SetString(PyExc_AttributeError, "If exactly one argument, it must be 0.");
845  return NULL;
846  }
848  } else if (narg == 4) {
849  // TODO: figure out some way of reading the logical connection point
850  // don't use hoc refs
851  if (!PyArg_ParseTuple(args, "iddd", &style, &x, &y, &z)) {
852  return NULL;
853  }
854  nrn_pt3dstyle1(sec, x, y, z);
855 
856  } else {
857  PyErr_SetString(PyExc_Exception, "Wrong number of arguments.");
858  return NULL;
859  }
860  }
861  return PyBool_FromLong(sec->logical_connection != nullptr);
862 }
863 
866 }
867 
869  Section* sec = self->sec_;
871  int n, i;
872  if (!PyArg_ParseTuple(args, "i", &i)) {
873  return NULL;
874  }
875  n = sec->npt3d - 1;
876  if (i < 0 || i > n) {
877  PyErr_SetString(PyExc_Exception, "Arg out of range\n");
878  return NULL;
879  }
880  return &sec->pt3d[i];
881 }
882 
884  PyObject* args) { // returns x value at index of 3d list
885  Pt3d* pt3d = get_pt3d_from_python_args(self, args);
886  if (pt3d == NULL) {
887  return NULL;
888  }
889  return PyFloat_FromDouble((double) pt3d->x);
890 }
891 
893  return nrn::convert_cxx_exceptions(NPySecObj_x3d, self, args);
894 }
895 
897  PyObject* args) { // returns y value at index of 3d list
898  Pt3d* pt3d = get_pt3d_from_python_args(self, args);
899  if (pt3d == NULL) {
900  return NULL;
901  }
902  return PyFloat_FromDouble((double) pt3d->y);
903 }
904 
906  return nrn::convert_cxx_exceptions(NPySecObj_y3d, self, args);
907 }
908 
910  PyObject* args) { // returns z value at index of 3d list
911  Pt3d* pt3d = get_pt3d_from_python_args(self, args);
912  if (pt3d == NULL) {
913  return NULL;
914  }
915  return PyFloat_FromDouble((double) pt3d->z);
916 }
917 
919  return nrn::convert_cxx_exceptions(NPySecObj_z3d, self, args);
920 }
921 
922 // returns arc position value at index of 3d list
924  Pt3d* pt3d = get_pt3d_from_python_args(self, args);
925  if (pt3d == NULL) {
926  return NULL;
927  }
928  return PyFloat_FromDouble((double) pt3d->arc);
929 }
930 
932  return nrn::convert_cxx_exceptions(NPySecObj_arc3d, self, args);
933 }
934 
936  PyObject* args) { // returns diam value at index of 3d list
937  Pt3d* pt3d = get_pt3d_from_python_args(self, args);
938  if (pt3d == NULL) {
939  return NULL;
940  }
941  return PyFloat_FromDouble((double) fabs(pt3d->d));
942 }
943 
945  return nrn::convert_cxx_exceptions(NPySecObj_diam3d, self, args);
946 }
947 
948 // returns True/False depending on if spine present
950  Pt3d* pt3d = get_pt3d_from_python_args(self, args);
951  if (pt3d == nullptr) {
952  return nullptr;
953  }
954  return PyBool_FromLong(pt3d->d < 0);
955 }
956 
959 }
960 
962  NPySecObj* psec = (NPySecObj*) p;
963  if (psec->sec_ && psec->sec_->prop) {
964  return NPySecObj_name(psec);
965  }
966  return PyString_FromString("<deleted section>");
967 }
968 
971 }
972 
973 // Returns a new reference.
975  NPySegObj* pyseg = (NPySegObj*) p;
976  if (pyseg->pysec_->sec_ && pyseg->pysec_->sec_->prop) {
977  const char* sname = secname(pyseg->pysec_->sec_);
978  std::string name = fmt::format("{}({:g})", sname, pyseg->x_);
979  return PyString_FromString(name.c_str());
980  }
981  return PyString_FromString("<segment of deleted section>");
982 }
983 
986 }
987 
988 // Returns a new reference.
990  auto buf = fmt::format("__nrnsec_{:p}", (void*) self->sec_);
991  return PyString_FromString(buf.c_str());
992 }
993 
996 }
997 
1000  PyObject* po;
1001  if (!PyArg_ParseTuple(args, "O", &po)) {
1002  return NULL;
1003  }
1004  if (PyCallable_Check(po) == 0) {
1005  PyErr_SetString(PyExc_TypeError, "argument must be a callable");
1006  return NULL;
1007  }
1008 
1009  Py_XDECREF(nrnpy_psection);
1010  nrnpy_psection = po;
1011  Py_INCREF(po);
1012  return po;
1013 }
1014 
1016  return nrn::convert_cxx_exceptions(nrnpy_set_psection, self, args);
1017 }
1018 
1020  CHECK_SEC_INVALID(self->sec_);
1021  if (nrnpy_psection) {
1022  auto arglist = nb::steal(Py_BuildValue("(O)", self));
1023  return PyObject_CallObject(nrnpy_psection, arglist.ptr());
1024  }
1025  Py_RETURN_NONE;
1026 }
1027 
1030 }
1031 
1032 static PyObject* is_pysec(NPySecObj* self) {
1033  CHECK_SEC_INVALID(self->sec_);
1034  return PyBool_FromLong(self->sec_->prop &&
1035  self->sec_->prop->dparam[PROP_PY_INDEX].get<void*>());
1036 }
1037 
1039  return nrn::convert_cxx_exceptions(is_pysec, self);
1040 }
1041 
1042 // Is expected to return a new reference.
1044  if (!sec || !sec->prop) {
1045  return NULL;
1046  }
1047  NPySecObj* pysec = NULL;
1048  if (auto* pv = sec->prop->dparam[PROP_PY_INDEX].get<void*>(); pv) {
1049  pysec = static_cast<NPySecObj*>(pv);
1050  Py_INCREF(pysec);
1051  assert(pysec->sec_ == sec);
1052  } else {
1053  pysec = (NPySecObj*) psection_type->tp_alloc(psection_type, 0);
1054  pysec->sec_ = sec;
1055  section_ref(sec);
1056  pysec->name_ = 0;
1057  pysec->cell_weakref_ = 0;
1058  }
1059  return pysec;
1060 }
1061 
1062 static PyObject* newpyseghelp(Section* sec, double x) {
1063  NPySegObj* seg = (NPySegObj*) PyObject_New(NPySegObj, psegment_type);
1064  if (seg == NULL) {
1065  return NULL;
1066  }
1067  seg->x_ = x;
1068  seg->pysec_ = newpysechelp(sec);
1069  return (PyObject*) seg;
1070 }
1071 
1073  CHECK_SEC_INVALID(self->sec_);
1074  nrn_disconnect(self->sec_);
1075  Py_RETURN_NONE;
1076 }
1077 
1080 }
1081 
1083  CHECK_SEC_INVALID(self->sec_);
1084  Section* psec = self->sec_->parentsec;
1085  if (psec == NULL || psec->prop == NULL) {
1086  Py_RETURN_NONE;
1087  }
1088  double x = nrn_connection_position(self->sec_);
1089  return newpyseghelp(psec, x);
1090 }
1091 
1094 }
1095 
1097  Section* sec = self->sec_;
1099  Section* psec = NULL;
1100  for (psec = sec->parentsec; psec; psec = psec->parentsec) {
1101  if (psec == NULL || psec->prop == NULL) {
1102  Py_RETURN_NONE;
1103  }
1104  if (nrn_at_beginning(sec)) {
1105  sec = psec;
1106  } else {
1107  break;
1108  }
1109  }
1110  if (psec == NULL) {
1111  Py_RETURN_NONE;
1112  }
1113 
1114  double x = nrn_connection_position(sec);
1115  return newpyseghelp(psec, x);
1116 }
1117 
1120 }
1121 
1123  CHECK_SEC_INVALID(self->sec_);
1124  double x = nrn_section_orientation(self->sec_);
1125  return Py_BuildValue("d", x);
1126 }
1129 }
1130 
1131 static bool lappendsec(PyObject* const sl, Section* const s) {
1132  auto item = nb::steal((PyObject*) newpysechelp(s));
1133  if (!item.is_valid()) {
1134  return false;
1135  }
1136  if (PyList_Append(sl, item.ptr()) != 0) {
1137  return false;
1138  }
1139  return true;
1140 }
1141 
1142 
1143 // Returns a new reference.
1144 static PyObject* pysec_children(NPySecObj* const self) {
1145  Section* const sec = self->sec_;
1147 
1148  nb::object result = nb::steal(PyList_New(0));
1149  if (!result) {
1150  return nullptr;
1151  }
1152 
1153  for (Section* s = sec->child; s; s = s->sibling) {
1154  if (!lappendsec(result.ptr(), s)) {
1155  return nullptr;
1156  }
1157  }
1158  return result.release().ptr();
1159 }
1160 
1163 }
1164 
1165 // Returns a borrowed reference (to `sl`).
1166 static PyObject* pysec_subtree1(PyObject* const sl, Section* const sec) {
1167  if (!lappendsec(sl, sec)) {
1168  return nullptr;
1169  }
1170  for (Section* s = sec->child; s; s = s->sibling) {
1171  if (!pysec_subtree1(sl, s)) {
1172  return nullptr;
1173  }
1174  }
1175  return sl;
1176 }
1177 
1178 // Returns a new reference.
1180  auto result = nb::steal(PyList_New(0));
1181  if (!result) {
1182  return nullptr;
1183  }
1184 
1185  if (!pysec_subtree1(result.ptr(), sec)) {
1186  return nullptr;
1187  }
1188 
1189  return result.release().ptr();
1190 }
1191 
1192 // Returns a new reference.
1193 static PyObject* pysec_subtree(NPySecObj* const self) {
1194  Section* const sec = self->sec_;
1196 
1197  return pysec_subtree_impl(sec);
1198 }
1199 
1200 static PyObject* pysec_subtree_safe(NPySecObj* const self) {
1202 }
1203 
1205  for (; sec->parentsec; sec = sec->parentsec) {
1206  }
1207 
1208  return sec;
1209 }
1210 
1211 static PyObject* pysec_wholetree(NPySecObj* const self) {
1212  Section* sec = self->sec_;
1214 
1216 }
1217 
1220 }
1221 
1222 // Returns a new reference.
1224  nb::object result;
1225  if (self->cell_weakref_) {
1226 #if PY_VERSION_HEX >= 0x030D0000
1227  PyObject* cell = nullptr;
1228  int ret = PyWeakref_GetRef(self->cell_weakref_, &cell);
1229  if (ret > 0) {
1230  result = nb::steal(cell);
1231  } else {
1232  result = nb::none();
1233  }
1234 #else
1235  result = nb::borrow(PyWeakref_GetObject(self->cell_weakref_));
1236 #endif
1237  } else if (auto* o = self->sec_->prop->dparam[6].get<Object*>(); self->sec_->prop && o) {
1238  result = nb::steal(nrnpy_ho2po(o));
1239  } else {
1240  result = nb::none();
1241  }
1242  return result.release().ptr();
1243 }
1244 
1247 }
1248 
1249 static long pysec_hash(PyObject* self) {
1250  return castptr2long((NPySecObj*) self)->sec_;
1251 }
1252 
1253 static long pysec_hash_safe(PyObject* self) {
1255 }
1256 
1257 static long pyseg_hash(PyObject* self) {
1258  NPySegObj* seg = (NPySegObj*) self;
1259  return castptr2long node_exact(seg->pysec_->sec_, seg->x_);
1260 }
1261 
1262 static long pyseg_hash_safe(PyObject* self) {
1264 }
1265 
1266 static PyObject* pyseg_richcmp(NPySegObj* self, PyObject* other, int op) {
1267  NPySegObj* seg = (NPySegObj*) self;
1268  void* self_ptr = (void*) node_exact(seg->pysec_->sec_, seg->x_);
1269  void* other_ptr = (void*) other;
1270  if (PyObject_TypeCheck(other, psegment_type)) {
1271  seg = (NPySegObj*) other;
1272  other_ptr = (void*) node_exact(seg->pysec_->sec_, seg->x_);
1273  }
1274  return nrn_ptr_richcmp(self_ptr, other_ptr, op);
1275 }
1276 
1277 static PyObject* pyseg_richcmp_safe(NPySegObj* self, PyObject* other, int op) {
1278  return nrn::convert_cxx_exceptions(pyseg_richcmp, self, other, op);
1279 }
1280 
1281 
1282 static PyObject* pysec_richcmp(NPySecObj* self, PyObject* other, int op) {
1283  void* self_ptr = (void*) (self->sec_);
1284  void* other_ptr = (void*) other;
1285  if (PyObject_TypeCheck(other, psection_type)) {
1286  void* self_ptr = (void*) (self->sec_);
1287  other_ptr = (void*) (((NPySecObj*) other)->sec_);
1288  return nrn_ptr_richcmp(self_ptr, other_ptr, op);
1289  }
1290  if (PyObject_TypeCheck(other, hocobject_type) || PyObject_TypeCheck(other, psegment_type)) {
1291  // preserves comparison with NEURON objects as it existed prior to 7.7
1292  return nrn_ptr_richcmp(self_ptr, other_ptr, op);
1293  }
1294  Py_INCREF(Py_NotImplemented);
1295  return Py_NotImplemented;
1296 }
1297 
1298 static PyObject* pysec_richcmp_safe(NPySecObj* self, PyObject* other, int op) {
1299  return nrn::convert_cxx_exceptions(pysec_richcmp, self, other, op);
1300 }
1301 
1302 static PyObject* pysec_same(NPySecObj* self, PyObject* args) {
1303  PyObject* pysec;
1304  return PyBool_FromLong(PyArg_ParseTuple(args, "O", &pysec) &&
1305  PyObject_TypeCheck(pysec, psection_type) &&
1306  ((NPySecObj*) pysec)->sec_ == self->sec_);
1307 }
1308 
1310  return nrn::convert_cxx_exceptions(pysec_same, self, args);
1311 }
1312 
1314  std::string s = memb_func[self->type_].sym->name;
1315  if (!self->prop_id_) {
1316  Section* sec = self->pyseg_->pysec_->sec_;
1317  if (!sec || !sec->prop) {
1318  s = "<mechanism of deleted section>"; // legacy message
1319  } else {
1320  s = "<segment invalid or or mechanism uninserted>";
1321  }
1322  }
1323  PyObject* result = PyString_FromString(s.c_str());
1324  return result;
1325 }
1326 
1329 }
1330 
1332  PyObject* result = NULL;
1333  std::string s = memb_func[self->pymech_->type_].sym->name;
1334  s += ".";
1335  s += self->f_->name;
1336  result = PyString_FromString(s.c_str());
1337  return result;
1338 }
1339 
1342 }
1343 
1344 // Returns a new reference.
1346  CHECK_PROP_INVALID(self->pymech_->prop_id_);
1347  nb::object result;
1348  auto& f = self->f_->func;
1349 
1350  // patterning after fcall
1351  Symbol sym{}; // in case of error, need the name.
1352  sym.name = (char*) self->f_->name;
1353  std::vector<neuron::unique_cstr> strings_to_free;
1354  int narg = hocobj_pushargs(args, strings_to_free);
1355  hoc_push_frame(&sym, narg); // get_argument uses the current frame
1356  try {
1357  double x = (f) (self->pymech_->prop_);
1358  result = nb::steal(Py_BuildValue("d", x));
1359  } catch (std::exception const& e) {
1360  std::ostringstream oss;
1361  oss << "mechanism.function call error: " << e.what();
1362  PyErr_SetString(PyExc_RuntimeError, oss.str().c_str());
1363  }
1364  hoc_pop_frame();
1365 
1366  return result.release().ptr();
1367 }
1368 
1370  return nrn::convert_cxx_exceptions(NPyMechFunc_call, self, args);
1371 }
1372 
1374  CHECK_PROP_INVALID(self->prop_id_);
1375  return PyBool_FromLong(nrn_is_ion(self->type_));
1376 }
1377 
1380 }
1381 
1383  CHECK_PROP_INVALID(self->prop_id_);
1384  Py_XINCREF(self->pyseg_);
1385  return (PyObject*) self->pyseg_;
1386 }
1387 
1390 }
1391 
1393  auto* pymech = self->pymech_;
1394  if (pymech) {
1395  CHECK_PROP_INVALID(pymech->prop_id_);
1396  Py_INCREF(pymech);
1397  }
1398  return (PyObject*) pymech;
1399 }
1400 
1403 }
1404 
1406  NPyMechObj* pymech = (NPyMechObj*) p;
1407  return NPyMechObj_name(pymech);
1408 }
1409 
1412 }
1413 
1415  NPyMechFunc* pyfunc = (NPyMechFunc*) p;
1416  return NPyMechFunc_name(pyfunc);
1417 }
1418 
1421 }
1422 
1424  PyObject* result = NULL;
1425  if (self->sym_) {
1426  if (self->isptr_) {
1427  char buf[256];
1428  Sprintf(buf, "_ref_%s", self->sym_->name);
1430  } else {
1431  result = PyString_FromString(self->sym_->name);
1432  }
1433  } else {
1434  CHECK_SEC_INVALID(self->pymech_->pyseg_->pysec_->sec_);
1435  PyErr_SetString(PyExc_ReferenceError, "no Symbol");
1436  }
1437  return result;
1438 }
1439 
1442 }
1443 
1445  auto* pymech = self->pymech_;
1446  if (pymech) {
1447  CHECK_SEC_INVALID(pymech->pyseg_->pysec_->sec_);
1448  Py_INCREF(pymech);
1449  }
1450  return (PyObject*) pymech;
1451 }
1452 
1455 }
1456 
1458  CHECK_SEC_INVALID(self->sec_);
1459  PyObject* p;
1460  NPySecObj* parent;
1461  double parentx, childend;
1462  parentx = -1000.;
1463  childend = 0.;
1464  if (!PyArg_ParseTuple(args, "O|dd", &p, &parentx, &childend)) {
1465  return NULL;
1466  }
1467  if (PyObject_TypeCheck(p, psection_type)) {
1468  parent = (NPySecObj*) p;
1469  if (parentx == -1000.) {
1470  parentx = 1.;
1471  }
1472  } else if (PyObject_TypeCheck(p, psegment_type)) {
1473  parent = ((NPySegObj*) p)->pysec_;
1474  if (parentx != -1000.) {
1475  childend = parentx;
1476  }
1477  parentx = ((NPySegObj*) p)->x_;
1478  } else {
1479  PyErr_SetString(PyExc_TypeError, "first arg not a nrn.Section or nrn.Segment");
1480  return NULL;
1481  }
1482  CHECK_SEC_INVALID(parent->sec_);
1483 
1484  // printf("NPySecObj_connect %s %g %g\n", parent, parentx, childend);
1485  if (parentx > 1. || parentx < 0.) {
1486  PyErr_SetString(PyExc_ValueError, "out of range 0 <= parentx <= 1.");
1487  return NULL;
1488  }
1489  if (childend != 0. && childend != 1.) {
1490  PyErr_SetString(PyExc_ValueError, "child connection end must be 0 or 1");
1491  return NULL;
1492  }
1493  hoc_pushx(childend);
1494  hoc_pushx(parentx);
1495  nrn_pushsec(self->sec_);
1496  nrn_pushsec(parent->sec_);
1498  Py_INCREF(self);
1499  return (PyObject*) self;
1500 }
1501 
1503  return nrn::convert_cxx_exceptions(NPySecObj_connect, self, args);
1504 }
1505 
1507  CHECK_SEC_INVALID(self->sec_);
1508  char* tname;
1509  if (!PyArg_ParseTuple(args, "s", &tname)) {
1510  PyErr_Clear();
1511  // if called with an object that has an insert method, use that
1512  PyObject* tpyobj;
1513  if (PyArg_ParseTuple(args, "O", &tpyobj)) {
1514  auto _tpyobj_tracker = nb::borrow(tpyobj);
1515  // Returned object to be discarded
1516  auto out_o = nb::steal(PyObject_CallMethod(tpyobj, "insert", "O", (PyObject*) self));
1517  if (!out_o.is_valid()) {
1518  PyErr_Clear();
1519  PyErr_SetString(
1520  PyExc_TypeError,
1521  "insert argument must be either a string or an object with an insert method");
1522  return nullptr;
1523  }
1524  Py_INCREF(self);
1525  return (PyObject*) self;
1526  }
1527  PyErr_Clear();
1528  PyErr_SetString(PyExc_TypeError, "insert takes a single positional argument");
1529  return nullptr;
1530  }
1531  PyObject* otype = PyDict_GetItemString(pmech_types, tname);
1532  if (!otype) {
1533  // check first to see if the pmech_types needs to be
1534  // augmented by any new KSChan
1536  otype = PyDict_GetItemString(pmech_types, tname);
1537  if (!otype) {
1538  PyErr_SetString(PyExc_ValueError, "argument not a density mechanism name.");
1539  return NULL;
1540  }
1541  }
1542  int type = PyInt_AsLong(otype);
1543  // printf("NPySecObj_insert %s %d\n", tname, type);
1544  mech_insert1(self->sec_, type);
1545  Py_INCREF(self);
1546  return (PyObject*) self;
1547 }
1548 
1550  return nrn::convert_cxx_exceptions(NPySecObj_insert, self, args);
1551 }
1552 
1554  CHECK_SEC_INVALID(self->sec_);
1555  char* tname;
1556  if (!PyArg_ParseTuple(args, "s", &tname)) {
1557  return NULL;
1558  }
1559  PyObject* otype = PyDict_GetItemString(pmech_types, tname);
1560  if (!otype) {
1561  // check first to see if the pmech_types needs to be
1562  // augmented by any new KSChan
1564  otype = PyDict_GetItemString(pmech_types, tname);
1565  if (!otype) {
1566  PyErr_SetString(PyExc_ValueError, "argument not a density mechanism name.");
1567  return NULL;
1568  }
1569  }
1570  int type = PyInt_AsLong(otype);
1571  // printf("NPySecObj_uninsert %s %d\n", tname, memb_func[type].sym);
1572  mech_uninsert1(self->sec_, memb_func[type].sym);
1573  Py_INCREF(self);
1574  return (PyObject*) self;
1575 }
1576 
1578  return nrn::convert_cxx_exceptions(NPySecObj_uninsert, self, args);
1579 }
1580 
1582  CHECK_SEC_INVALID(self->sec_);
1583  char* mechanism_name;
1584  PyObject* result;
1585  if (!PyArg_ParseTuple(args, "s", &mechanism_name)) {
1586  return NULL;
1587  }
1588  result = PyBool_FromLong(has_membrane(mechanism_name, self->sec_));
1589  Py_XINCREF(result);
1590  return result;
1591 }
1592 
1595 }
1596 
1597 static PyObject* NPySecObj_push(NPySecObj* self, PyObject* /* args */) {
1598  CHECK_SEC_INVALID(self->sec_);
1599  nrn_pushsec(self->sec_);
1600  Py_INCREF(self);
1601  return (PyObject*) self;
1602 }
1603 
1605  return nrn::convert_cxx_exceptions(NPySecObj_push, self, args);
1606 }
1607 
1608 static PyObject* seg_of_section_iter(NPySecObj* self) { // iterates over segments
1609  CHECK_SEC_INVALID(self->sec_);
1610  // printf("section_iter\n");
1611  NPySegOfSecIter* segiter;
1612  segiter = PyObject_New(NPySegOfSecIter, pseg_of_sec_iter_type);
1613  if (segiter == NULL) {
1614  return NULL;
1615  }
1616 
1617  segiter->seg_iter_ = 0;
1618  Py_INCREF(self);
1619  segiter->pysec_ = self;
1620  return (PyObject*) segiter;
1621 }
1622 
1623 static PyObject* seg_of_section_iter_safe(NPySecObj* self) { // iterates over segments
1625 }
1626 
1627 static PyObject* allseg(NPySecObj* self) {
1628  CHECK_SEC_INVALID(self->sec_);
1629  // printf("allseg\n");
1631  Py_INCREF(self);
1632  ai->pysec_ = self;
1633  ai->allseg_iter_ = -1;
1634  return (PyObject*) ai;
1635 }
1636 
1638  return nrn::convert_cxx_exceptions(allseg, self);
1639 }
1640 
1642  self->allseg_iter_ = -1;
1643  Py_INCREF(self);
1644  return (PyObject*) self;
1645 }
1646 
1649 }
1650 
1652  NPySegObj* seg;
1653  int n1 = self->pysec_->sec_->nnode - 1;
1654  if (self->allseg_iter_ > n1) {
1655  // end of iteration
1656  return NULL;
1657  }
1658  seg = PyObject_New(NPySegObj, psegment_type);
1659  if (seg == NULL) {
1660  // error
1661  return NULL;
1662  }
1663  Py_INCREF(self->pysec_);
1664  seg->pysec_ = self->pysec_;
1665  if (self->allseg_iter_ == -1) {
1666  seg->x_ = 0.;
1667  } else if (self->allseg_iter_ == n1) {
1668  seg->x_ = 1.;
1669  } else {
1670  seg->x_ = (double(self->allseg_iter_) + 0.5) / ((double) n1);
1671  }
1672  ++self->allseg_iter_;
1673  return (PyObject*) seg;
1674 }
1675 
1678 }
1679 
1681  NPySegObj* seg;
1682  int n1 = self->pysec_->sec_->nnode - 1;
1683  if (self->seg_iter_ >= n1) {
1684  // end of iteration
1685  return NULL;
1686  }
1687  seg = PyObject_New(NPySegObj, psegment_type);
1688  if (seg == NULL) {
1689  // error
1690  return NULL;
1691  }
1692  Py_INCREF(self->pysec_);
1693  seg->pysec_ = self->pysec_;
1694  seg->x_ = (double(self->seg_iter_) + 0.5) / ((double) n1);
1695  ++self->seg_iter_;
1696  return (PyObject*) seg;
1697 }
1698 
1701 }
1702 
1704  Section* sec = self->pysec_->sec_;
1706  Node* nd = node_exact(sec, self->x_);
1707  nb::list result{};
1708  for (Prop* p = nd->prop; p; p = p->next) {
1709  if (memb_func[p->_type].is_point) {
1710  auto* pp = p->dparam[1].get<Point_process*>();
1711  result.append(nb::steal(nrnpy_ho2po(pp->ob)));
1712  }
1713  }
1714  return result.release().ptr();
1715 }
1716 
1719 }
1720 
1721 // Returns a new reference.
1723  Section* sec = self->pysec_->sec_;
1725  Node* nd = node_exact(sec, self->x_);
1726  return Py_BuildValue("i", nd->v_node_index);
1727 }
1728 
1731 }
1732 
1733 // Returns a new reference.
1734 static PyObject* seg_area(NPySegObj* self) {
1735  Section* sec = self->pysec_->sec_;
1737  if (sec->recalc_area_) {
1738  nrn_area_ri(sec);
1739  }
1740  double x = self->x_;
1741  double a = 0.0;
1742  if (x > 0. && x < 1.) {
1743  Node* nd = node_exact(sec, x);
1744  a = NODEAREA(nd);
1745  }
1746  return Py_BuildValue("d", a);
1747 }
1748 
1750  return nrn::convert_cxx_exceptions(seg_area, self);
1751 }
1752 
1753 static inline double scaled_frustum_volume(double length, double d0, double d1) {
1754  // this is proportional to the volume of a frustum... need to multiply by pi/12
1755  return length * (d0 * d0 + d0 * d1 + d1 * d1);
1756 }
1757 
1758 static inline double interpolate(double x0, double x1, double y0, double y1, double xnew) {
1759  // computes ynew on the line between (x0, y0) and (x1, y1)
1760  // recall: y - y0 = m (x - x0)
1761  if (x1 == x0) {
1762  // avoid dividing by 0 if no length...
1763  return y0;
1764  } else {
1765  return y0 + (y1 - y0) * (xnew - x0) / (x1 - x0);
1766  }
1767 }
1768 
1769 static int arg_bisect_arc3d(Section* sec, int npt3d, double x) {
1770  // returns the index in sec where the arc is no more than x, but where the next points arc is
1771  // more right endpoint is never included
1772  int left = 0;
1773  int right = npt3d;
1774  while (right - left > 1) {
1775  int mid = (left + right) / 2;
1776  if (sec->pt3d[mid].arc < x) {
1777  left = mid;
1778  } else {
1779  right = mid;
1780  }
1781  }
1782  return left;
1783 }
1784 
1785 // Returns a new reference.
1787  Section* sec = self->pysec_->sec_;
1789  int i;
1790  if (sec->recalc_area_) {
1791  nrn_area_ri(sec);
1792  }
1793  double x = self->x_;
1794  double a = 0.0;
1795  // volume only exists on the interior
1796  if (x > 0. && x < 1.) {
1797  // every section owns one extra node (the conservation node)
1798  int nseg = sec->nnode - 1;
1799  double length = section_length(sec) / nseg;
1800  int iseg = x * nseg;
1801  double seg_left_arc = iseg * length;
1802  double seg_right_arc = (iseg + 1) * length;
1803  if (sec->npt3d > 1) {
1804  int i_left = arg_bisect_arc3d(sec, sec->npt3d, seg_left_arc);
1805  double left_diam = fabs(sec->pt3d[i_left].d);
1806  double right_diam = fabs(sec->pt3d[i_left + 1].d);
1807  double left_arc = seg_left_arc;
1808  left_diam = interpolate(
1809  sec->pt3d[i_left].arc, sec->pt3d[i_left + 1].arc, left_diam, right_diam, left_arc);
1810 
1811  for (i = i_left + 1; i < sec->npt3d && sec->pt3d[i].arc < seg_right_arc; i++) {
1812  right_diam = fabs(sec->pt3d[i].d);
1813  a += scaled_frustum_volume(sec->pt3d[i].arc - left_arc, left_diam, right_diam);
1814  left_arc = sec->pt3d[i].arc;
1815  left_diam = right_diam;
1816  }
1817  if (i < sec->npt3d) {
1818  right_diam = interpolate(
1819  left_arc, sec->pt3d[i].arc, left_diam, fabs(sec->pt3d[i].d), seg_right_arc);
1820  a += scaled_frustum_volume(seg_right_arc - left_arc, left_diam, right_diam);
1821  }
1822 
1823  // the scaled_frustum_volume formula factored out a pi/12
1824  a *= M_PI / 12;
1825  } else {
1826  // 0 or 1 3D points... so give cylinder volume
1827  Node* nd = node_exact(sec, x);
1828  for (Prop* p = nd->prop; p; p = p->next) {
1829  if (p->_type == MORPHOLOGY) {
1830  double diam = p->param(0);
1831  a = M_PI * diam * diam / 4 * length;
1832  break;
1833  }
1834  }
1835  }
1836  }
1837  return Py_BuildValue("d", a);
1838 }
1839 
1842 }
1843 
1844 // Returns a new reference.
1845 static PyObject* seg_ri(NPySegObj* self) {
1846  Section* sec = self->pysec_->sec_;
1848  if (sec->recalc_area_) {
1849  nrn_area_ri(sec);
1850  }
1851  double ri = 1e30;
1852  Node* nd = node_exact(sec, self->x_);
1853  if (NODERINV(nd)) {
1854  ri = 1. / NODERINV(nd);
1855  }
1856  return Py_BuildValue("d", ri);
1857 }
1858 
1860  return nrn::convert_cxx_exceptions(seg_ri, self);
1861 }
1862 
1864  // p must be in the pmech_types list. But I no longer know if that
1865  // is ever not the case.
1866  for (;;) {
1867  if (!p) {
1868  break;
1869  }
1870  // printf("segment_iter %d %s\n", p->_type, memb_func[p->_type].sym->name);
1871  // Only return density mechanisms (skip POINT_PROCESS)
1872  if (PyDict_GetItemString(pmech_types, memb_func[p->_type].sym->name)) {
1873  // printf("segment_iter found\n");
1874  break;
1875  }
1876  p = p->next;
1877  }
1878  return p;
1879 }
1880 
1882  Section* sec = self->pysec_->sec_;
1884  Node* nd = node_exact(sec, self->x_);
1885  Prop* p = mech_of_segment_prop(nd->prop);
1886  auto mi = nb::steal((PyObject*) PyObject_New(NPyMechOfSegIter, pmech_of_seg_iter_generic_type));
1887  if (!mi) {
1888  return nullptr;
1889  }
1890  auto m = nb::steal((PyObject*) new_pymechobj(self, p));
1891  if (!m) {
1892  return nullptr;
1893  }
1894  ((NPyMechOfSegIter*) mi.ptr())->pymech_ = (NPyMechObj*) m.release().ptr();
1895  return mi.release().ptr();
1896 }
1897 
1900 }
1901 
1902 static Object* seg_from_sec_x(Section* sec, double x) {
1903  auto pyseg = nb::steal((PyObject*) PyObject_New(NPySegObj, psegment_type));
1904  auto* pseg = (NPySegObj*) pyseg.ptr();
1905  pseg->pysec_ = newpysechelp(sec); // newpysechelp() already increfs
1906  pseg->x_ = x;
1907  return nrnpy_pyobject_in_obj((PyObject*) pseg);
1908 }
1909 
1910 static Object** pp_get_segment(void* vptr) {
1911  Point_process* pnt = (Point_process*) vptr;
1912  // printf("pp_get_segment %s\n", hoc_object_name(pnt->ob));
1913  Object* ho = NULL;
1914  if (pnt->prop) {
1915  Section* sec = pnt->sec;
1916  double x = nrn_arc_position(sec, pnt->node);
1917  ho = seg_from_sec_x(sec, x);
1918  }
1919  if (!ho) {
1920  ho = nrnpy_pyobject_in_obj(Py_None);
1921  }
1922  Object** tobj = hoc_temp_objptr(ho);
1923  --ho->refcount;
1924  return tobj;
1925 }
1926 
1927 static void rv_noexist(Section* sec, const char* n, double x, int err) {
1928  char buf[200];
1929  if (err == 2) {
1930  Sprintf(buf, "%s was not made to point to anything at %s(%g)", n, secname(sec), x);
1931  } else if (err == 1) {
1932  Sprintf(buf, "%s, the mechanism does not exist at %s(%g)", n, secname(sec), x);
1933  } else {
1934  Sprintf(buf, "%s does not exist at %s(%g)", n, secname(sec), x);
1935  }
1936  PyErr_SetString(PyExc_AttributeError, buf);
1937 }
1938 
1939 // Returns a (casted) new reference.
1940 static NPyRangeVar* rvnew(Symbol* sym, NPySecObj* sec, double x) {
1941  NPyRangeVar* r = PyObject_New(NPyRangeVar, range_type);
1942  if (!r) {
1943  return nullptr;
1944  }
1945  r->pymech_ = new_pymechobj();
1946  r->pymech_->pyseg_ = PyObject_New(NPySegObj, psegment_type);
1947  Py_INCREF(sec);
1948  r->pymech_->pyseg_->pysec_ = sec;
1949  r->pymech_->pyseg_->x_ = 0.5;
1950  r->sym_ = sym;
1951  r->isptr_ = 0;
1952  r->attr_from_sec_ = 1;
1953  return r;
1954 }
1955 
1956 // Returns a new reference.
1958  return PyObject_New(NPyOpaquePointer, opaque_pointer_type);
1959 }
1960 
1961 // Returns a new reference.
1963  if (dh.holds<double*>()) {
1964  return Py_BuildValue("d", *dh.get<double*>());
1965  } else {
1966  return (PyObject*) opaque_pointer_new();
1967  }
1968 }
1969 
1970 // Returns a new reference.
1972  if (dh.holds<double*>()) {
1974  } else {
1975  return (PyObject*) opaque_pointer_new();
1976  }
1977 }
1978 
1979 static PyObject* section_getattro(NPySecObj* self, PyObject* pyname) {
1980  Section* sec = self->sec_;
1982  PyObject* rv;
1983  auto _pyname_tracker = nb::borrow(pyname); // keep refcount+1 during use
1984  auto name = Py2NRNString::as_ascii(pyname);
1985  char* n = name.c_str();
1986  if (!name.is_valid()) {
1987  Py2NRNString::set_pyerr(PyExc_TypeError, "attribute name must be a string");
1988  return nullptr;
1989  }
1990  // printf("section_getattr %s\n", n);
1991  nb::object result;
1992  if (strcmp(n, "L") == 0) {
1993  result = nb::steal(Py_BuildValue("d", section_length(sec)));
1994  } else if (strcmp(n, "Ra") == 0) {
1995  result = nb::steal(Py_BuildValue("d", nrn_ra(sec)));
1996  } else if (strcmp(n, "nseg") == 0) {
1997  result = nb::steal(Py_BuildValue("i", sec->nnode - 1));
1998  } else if ((rv = PyDict_GetItemString(rangevars_, n)) != NULL) {
1999  Symbol* sym = ((NPyRangeVar*) rv)->sym_;
2000  if (is_array(*sym)) {
2001  result = nb::steal((PyObject*) rvnew(sym, self, 0.5));
2002  } else {
2003  int err;
2004  auto const d = nrnpy_rangepointer(sec, sym, 0.5, &err, 0 /* idx */);
2005  if (d.is_invalid_handle()) {
2006  rv_noexist(sec, n, 0.5, err);
2007  return nullptr;
2008  } else {
2009  if (sec->recalc_area_ && sym->u.rng.type == MORPHOLOGY) {
2010  nrn_area_ri(sec);
2011  }
2012  result = nb::steal(build_python_value(d));
2013  }
2014  }
2015  } else if (strcmp(n, "rallbranch") == 0) {
2016  result = nb::steal(Py_BuildValue("d", sec->prop->dparam[4].get<double>()));
2017  } else if (strcmp(n, "__dict__") == 0) {
2018  nb::dict out_dict{};
2019  out_dict["L"] = nb::none();
2020  out_dict["Ra"] = nb::none();
2021  out_dict["nseg"] = nb::none();
2022  out_dict["rallbranch"] = nb::none();
2023  result = std::move(out_dict);
2024  } else {
2025  result = nb::steal(PyObject_GenericGetAttr((PyObject*) self, pyname));
2026  }
2027  return result.release().ptr();
2028 }
2029 
2031  return nrn::convert_cxx_exceptions(section_getattro, self, pyname);
2032 }
2033 
2034 static int section_setattro(NPySecObj* self, PyObject* pyname, PyObject* value) {
2035  Section* sec = self->sec_;
2036  if (!sec->prop) {
2037  PyErr_SetString(PyExc_ReferenceError, "can't access a deleted section");
2038  return -1;
2039  }
2040  PyObject* rv;
2041  int err = 0;
2042  auto _pyname_tracker = nb::borrow(pyname); // keep refcount+1 during use
2043  auto name = Py2NRNString::as_ascii(pyname);
2044  char* n = name.c_str();
2045  if (!name.is_valid()) {
2046  Py2NRNString::set_pyerr(PyExc_TypeError, "attribute name must be a string");
2047  return -1;
2048  }
2049  // printf("section_setattro %s\n", n);
2050  if (strcmp(n, "L") == 0) {
2051  double x;
2052  if (PyArg_Parse(value, "d", &x) == 1 && x > 0.) {
2053  if (can_change_morph(sec)) {
2054  sec->prop->dparam[2] = x;
2055  nrn_length_change(sec, x);
2056  diam_changed = 1;
2057  sec->recalc_area_ = 1;
2058  }
2059  } else {
2060  PyErr_SetString(PyExc_ValueError, "L must be > 0.");
2061  return -1;
2062  }
2063  } else if (strcmp(n, "Ra") == 0) {
2064  double x;
2065  if (PyArg_Parse(value, "d", &x) == 1 && x > 0.) {
2066  sec->prop->dparam[7] = x;
2067  diam_changed = 1;
2068  sec->recalc_area_ = 1;
2069  } else {
2070  PyErr_SetString(PyExc_ValueError, "Ra must be > 0.");
2071  return -1;
2072  }
2073  } else if (strcmp(n, "nseg") == 0) {
2074  int nseg;
2075  if (PyArg_Parse(value, "i", &nseg) == 1 && nseg > 0 && nseg <= 32767) {
2076  nrn_change_nseg(sec, nseg);
2077  } else {
2078  PyErr_SetString(PyExc_ValueError, "nseg must be an integer in range 1 to 32767");
2079  return -1;
2080  }
2081  // printf("section_setattro err=%d nseg=%d nnode\n", err, nseg,
2082  // sec->nnode);
2083  } else if ((rv = PyDict_GetItemString(rangevars_, n)) != NULL) {
2084  Symbol* sym = ((NPyRangeVar*) rv)->sym_;
2085  if (is_array(*sym)) {
2086  PyErr_SetString(PyExc_IndexError, "missing index");
2087  return -1;
2088  } else {
2089  int errp;
2090  auto d = nrnpy_rangepointer(sec, sym, 0.5, &errp, 0 /* idx */);
2091  if (d.is_invalid_handle()) {
2092  rv_noexist(sec, n, 0.5, errp);
2093  return -1;
2094  } else if (!d.holds<double*>()) {
2095  PyErr_SetString(PyExc_ValueError, "can't assign value to opaque pointer");
2096  return -1;
2097  } else if (!PyArg_Parse(value, "d", d.get<double*>())) {
2098  PyErr_SetString(PyExc_ValueError, "bad value");
2099  return -1;
2100  } else {
2101  // only need to do following if nseg > 1, VINDEX, or EXTRACELL
2103  }
2104  }
2105  } else if (strcmp(n, "rallbranch") == 0) {
2106  double x;
2107  if (PyArg_Parse(value, "d", &x) == 1 && x > 0.) {
2108  sec->prop->dparam[4] = x;
2109  diam_changed = 1;
2110  sec->recalc_area_ = 1;
2111  } else {
2112  PyErr_SetString(PyExc_ValueError, "rallbranch must be > 0");
2113  return -1;
2114  }
2115  } else {
2116  err = PyObject_GenericSetAttr((PyObject*) self, pyname, value);
2117  }
2118  return err;
2119 }
2120 
2122  return nrn::convert_cxx_exceptions(section_setattro, self, pyname, value);
2123 }
2124 
2126  // printf("mech_of_seg_next\n");
2127  // The return on this iteration is self->pymech_. NULL means it's over.
2128  NPyMechObj* m = self->pymech_;
2129  if (!m) {
2130  return NULL;
2131  }
2132  if (!m->prop_id_) {
2133  PyErr_SetString(PyExc_ReferenceError,
2134  "mechanism instance became invalid in middle of the mechanism iterator");
2135  return NULL;
2136  }
2137  Prop* pnext = mech_of_segment_prop(m->prop_->next);
2138  NPyMechObj* mnext{};
2139  if (pnext) {
2140  mnext = new_pymechobj(m->pyseg_, pnext);
2141  }
2142  self->pymech_ = mnext;
2143  return (PyObject*) m;
2144 }
2145 
2148 }
2149 
2151  Section* sec = self->pyseg_->pysec_->sec_;
2153 
2154  // printf("var_of_mech_iter\n");
2156  if (!self->prop_) {
2157  return NULL;
2158  }
2159  Py_INCREF(self);
2160  vmi->pymech_ = self;
2161  vmi->msym_ = memb_func[self->prop_->_type].sym;
2162  vmi->i_ = 0;
2163  return (PyObject*) vmi;
2164 }
2165 
2168 }
2169 
2171  if (self->i_ >= self->msym_->s_varn) {
2172  return NULL;
2173  }
2174  // printf("var_of_mech_next %d %s\n", self->i_, self->msym_->name);
2175  Symbol* sym = self->msym_->u.ppsym[self->i_];
2176  self->i_++;
2177  NPyRangeVar* r = (NPyRangeVar*) PyObject_New(NPyRangeVar, range_type);
2178  Py_INCREF(self->pymech_);
2179  r->pymech_ = self->pymech_;
2180  r->sym_ = sym;
2181  r->isptr_ = 0;
2182  r->attr_from_sec_ = 0;
2183  return (PyObject*) r;
2184 }
2185 
2188 }
2189 
2190 // Returns new reference.
2191 static PyObject* segment_getattro(NPySegObj* self, PyObject* pyname) {
2192  Section* sec = self->pysec_->sec_;
2194 
2195  Symbol* sym;
2196  auto _pyname_tracker = nb::borrow(pyname); // keep refcount+1 during use
2197  auto name = Py2NRNString::as_ascii(pyname);
2198  char* n = name.c_str();
2199  if (!name.is_valid()) {
2200  Py2NRNString::set_pyerr(PyExc_TypeError, "attribute name must be a string");
2201  return nullptr;
2202  }
2203  // printf("segment_getattr %s\n", n);
2204  nb::object result;
2205  PyObject* otype = NULL;
2206  PyObject* rv = NULL;
2207  if (strcmp(n, "v") == 0) {
2208  Node* nd = node_exact(sec, self->x_);
2209  result = nb::steal(Py_BuildValue("d", NODEV(nd)));
2210  } else if ((otype = PyDict_GetItemString(pmech_types, n)) != NULL) {
2211  int type = PyInt_AsLong(otype);
2212  // printf("segment_getattr type=%d\n", type);
2213  Node* nd = node_exact(sec, self->x_);
2214  Prop* p = nrn_mechanism(type, nd);
2215  if (!p) {
2216  rv_noexist(sec, n, self->x_, 1);
2217  return nullptr;
2218  } else {
2219  result = nb::steal((PyObject*) new_pymechobj(self, p));
2220  }
2221  } else if ((rv = PyDict_GetItemString(rangevars_, n)) != NULL) {
2222  sym = ((NPyRangeVar*) rv)->sym_;
2223  if (sym->type == RANGEOBJ) {
2224  int mtype = sym->u.rng.type;
2225  Node* nd = node_exact(sec, self->x_);
2226  Prop* p = nrn_mechanism(mtype, nd);
2227  Object* ob = nrn_nmodlrandom_wrap(p, sym);
2228  result = nb::steal(nrnpy_ho2po(ob));
2229  } else if (is_array(*sym)) {
2230  result = nb::steal((PyObject*) PyObject_New(NPyRangeVar, range_type));
2231  auto r = (NPyRangeVar*) result.ptr();
2232  r->pymech_ = new_pymechobj();
2233  Py_INCREF(self);
2234  r->pymech_->pyseg_ = self;
2235  r->sym_ = sym;
2236  r->isptr_ = 0;
2237  r->attr_from_sec_ = 0;
2238  } else {
2239  int err;
2240  auto const d = nrnpy_rangepointer(sec, sym, self->x_, &err, 0 /* idx */);
2241  if (d.is_invalid_handle()) {
2242  rv_noexist(sec, n, self->x_, err);
2243  return nullptr;
2244  } else {
2245  if (sec->recalc_area_ && sym->u.rng.type == MORPHOLOGY) {
2246  nrn_area_ri(sec);
2247  }
2248  result = nb::steal(build_python_value(d));
2249  }
2250  }
2251  } else if (strncmp(n, "_ref_", 5) == 0) {
2252  if (strcmp(n + 5, "v") == 0) {
2253  Node* nd = node_exact(sec, self->x_);
2254  result = nb::steal(nrn_hocobj_handle(nd->v_handle()));
2255  } else if ((sym = hoc_table_lookup(n + 5, hoc_built_in_symlist)) != 0 &&
2256  sym->type == RANGEVAR) {
2257  if (is_array(*sym)) {
2258  NPyRangeVar* r = PyObject_New(NPyRangeVar, range_type);
2259  r->pymech_ = new_pymechobj();
2260  Py_INCREF(self);
2261  r->pymech_->pyseg_ = self;
2262  r->sym_ = sym;
2263  r->isptr_ = 1;
2264  r->attr_from_sec_ = 0;
2265  result = nb::steal((PyObject*) r);
2266  } else {
2267  int err;
2268  auto const d = nrnpy_rangepointer(sec, sym, self->x_, &err, 0 /* idx */);
2269  if (d.is_invalid_handle()) {
2270  rv_noexist(sec, n + 5, self->x_, err);
2271  return nullptr;
2272  } else {
2273  if (d.holds<double*>()) {
2274  result = nb::steal(
2276  } else {
2277  result = nb::steal((PyObject*) opaque_pointer_new());
2278  }
2279  }
2280  }
2281  } else {
2282  rv_noexist(sec, n, self->x_, 2);
2283  return nullptr;
2284  }
2285  } else if (strcmp(n, "__dict__") == 0) {
2286  Node* nd = node_exact(sec, self->x_);
2287  nb::dict out_dict{};
2288  out_dict["v"] = nb::none();
2289  out_dict["diam"] = nb::none();
2290  out_dict["cm"] = nb::none();
2291  for (Prop* p = nd->prop; p; p = p->next) {
2292  if (p->_type > CAP && !memb_func[p->_type].is_point) {
2293  char* pn = memb_func[p->_type].sym->name;
2294  out_dict[pn] = nb::none();
2295  }
2296  }
2297  result = out_dict;
2298  } else {
2299  result = nb::steal(PyObject_GenericGetAttr((PyObject*) self, pyname));
2300  }
2301  return result.release().ptr();
2302 }
2303 
2305  return nrn::convert_cxx_exceptions(segment_getattro, self, pyname);
2306 }
2307 
2309  int err = 0;
2310  if (sym->subtype == NRNPOINTER) {
2312  // The challenge is that we need to store a data handle here,
2313  // because POINTER variables are set up before the data are
2314  // permuted, but that handle then gets read as part of the
2315  // translated mechanism code, inside the translated MOD files, where
2316  // we might not otherwise like to pay the extra cost of indirection.
2317  prop->dparam[sym->u.rng.index] = std::move(dh);
2318  } else {
2319  PyErr_SetString(PyExc_ValueError, "must be a hoc pointer");
2320  err = -1;
2321  }
2322  } else {
2323  PyErr_SetString(PyExc_AttributeError,
2324  " For assignment, only POINTER var can have a _ref_ prefix");
2325  err = -1;
2326  }
2327  return err;
2328 }
2329 
2330 static int segment_setattro(NPySegObj* self, PyObject* pyname, PyObject* value) {
2331  Section* sec = self->pysec_->sec_;
2332  if (!sec->prop) {
2333  PyErr_SetString(PyExc_ReferenceError, "nrn.Segment can't access a deleted section");
2334  return -1;
2335  }
2336  PyObject* rv;
2337  Symbol* sym;
2338  int err = 0;
2339  auto _pyname_tracker = nb::borrow(pyname); // keep refcount+1 during use
2340  auto name = Py2NRNString::as_ascii(pyname);
2341  char* n = name.c_str();
2342  if (!name.is_valid()) {
2343  Py2NRNString::set_pyerr(PyExc_TypeError, "attribute name must be a string");
2344  return -1;
2345  }
2346  // printf("segment_setattro %s\n", n);
2347  if (strcmp(n, "x") == 0) {
2348  double x;
2349  if (PyArg_Parse(value, "d", &x) == 1 && x > 0. && x <= 1.) {
2350  if (x < 1e-9) {
2351  self->x_ = 0.;
2352  } else if (x > 1. - 1e-9) {
2353  self->x_ = 1.;
2354  } else {
2355  self->x_ = x;
2356  }
2357  } else {
2358  PyErr_SetString(PyExc_ValueError, "x must be in range 0. to 1.");
2359  return -1;
2360  }
2361  } else if ((rv = PyDict_GetItemString(rangevars_, n)) != NULL) {
2362  sym = ((NPyRangeVar*) rv)->sym_;
2363  if (is_array(*sym)) {
2364  PyErr_Format(PyExc_IndexError, "%s needs an index for assignment", sym->name);
2365  return -1;
2366  } else {
2367  int errp;
2368  auto d = nrnpy_rangepointer(sec, sym, self->x_, &errp, 0 /* idx */);
2369  if (d.is_invalid_handle()) {
2370  rv_noexist(sec, n, self->x_, errp);
2371  return -1;
2372  }
2373  if (d.holds<double*>()) {
2374  if (!PyArg_Parse(value, "d", d.get<double*>())) {
2375  PyErr_SetString(PyExc_ValueError, "bad value");
2376  return -1;
2377  } else if (sym->u.rng.type == MORPHOLOGY) {
2378  diam_changed = 1;
2379  sec->recalc_area_ = 1;
2381  } else if (sym->u.rng.type == EXTRACELL && sym->u.rng.index == 0) {
2382  // cannot execute because xraxial is an array
2383  diam_changed = 1;
2384  }
2385  } else {
2386  PyErr_SetString(PyExc_ValueError, "can't assign value to opaque pointer");
2387  return -1;
2388  }
2389  }
2390  } else if (strncmp(n, "_ref_", 5) == 0) {
2392  if (rvsym && rvsym->type == RANGEVAR) {
2393  Node* nd = node_exact(sec, self->x_);
2394  assert(nd);
2395  Prop* prop = nrn_mechanism(rvsym->u.rng.type, nd);
2396  assert(prop);
2397  err = nrn_pointer_assign(prop, rvsym, value);
2398  } else {
2399  err = PyObject_GenericSetAttr((PyObject*) self, pyname, value);
2400  }
2401  } else {
2402  err = PyObject_GenericSetAttr((PyObject*) self, pyname, value);
2403  }
2404  return err;
2405 }
2406 
2408  return nrn::convert_cxx_exceptions(segment_setattro, self, pyname, value);
2409 }
2410 
2411 static bool striptrail(char* buf, int sz, const char* n, const char* m) {
2412  int nlen = strlen(n);
2413  int mlen = strlen(m);
2414  int u = nlen - mlen - 1; // should be location of _
2415  if (u > 0 && n[u] == '_') { // likely n is name_m
2416  if (strcmp(n + (u + 1), m) != 0) {
2417  return false;
2418  }
2419  strncpy(buf, n, sz);
2420  buf[u] = '\0';
2421  return true;
2422  }
2423  return false;
2424 }
2425 
2426 static Symbol* var_find_in_mech(Symbol* mech, const char* varname) {
2427  int cnt = mech->s_varn;
2428  for (int i = 0; i < cnt; ++i) {
2429  Symbol* sym = mech->u.ppsym[i];
2430  if (strcmp(sym->name, varname) == 0) {
2431  return sym;
2432  }
2433  }
2434  return nullptr;
2435 }
2436 
2438  Symbol* symvar,
2439  int index) {
2440  if (pymech->prop_->ob) { // HocMech created by make_mechanism
2441  Object* ob = pymech->prop_->ob;
2442  // strip suffix
2443  std::string s = symvar->name;
2444  std::string suffix{"_"};
2445  suffix += memb_func[pymech->type_].sym->name;
2446  s.resize(s.rfind(suffix));
2447 
2448  Symbol* sym = hoc_table_lookup(s.c_str(), ob->ctemplate->symtable);
2449  assert(sym);
2450  double* pd = ob->u.dataspace[sym->u.rng.index].pval + index;
2452  }
2453  int sym_index = symvar->u.rng.index;
2454  auto dh = pymech->prop_->param_handle_legacy(sym_index + index);
2455  return dh;
2456 }
2457 
2459  Symbol* symvar,
2460  int index) {
2461  if (pymech->prop_->ob) {
2462  // HocMech created by make_mechanism. It isn't obvious where HOC mechs
2463  // would store dparams.
2464  throw std::runtime_error("Not implemented.");
2465  }
2466 
2467  int sym_index = symvar->u.rng.index;
2468  return pymech->prop_->dparam[sym_index + index];
2469 }
2470 
2472  Symbol* symvar,
2473  int index) {
2474  if (symvar->subtype == NRNPOINTER) {
2475  return var_dparam(pymech, symvar, index);
2476  } else {
2477  return var_pval(pymech, symvar, index);
2478  }
2479 }
2480 
2481 
2482 // Returns a new reference.
2483 static PyObject* mech_getattro(NPyMechObj* self, PyObject* pyname) {
2484  Section* sec = self->pyseg_->pysec_->sec_;
2486  CHECK_PROP_INVALID(self->prop_id_);
2487  auto _pyname_tracker = nb::borrow(pyname); // keep refcount+1 during use
2488  auto name = Py2NRNString::as_ascii(pyname);
2489  char* n = name.c_str();
2490  if (!n) {
2491  Py2NRNString::set_pyerr(PyExc_TypeError, "attribute name must be a string");
2492  return nullptr;
2493  }
2494  // printf("mech_getattro %s\n", n);
2495  nb::object result;
2496  int isptr = (strncmp(n, "_ref_", 5) == 0);
2497  Symbol* mechsym = memb_func[self->type_].sym;
2498  char* mname = mechsym->name;
2499  int mnamelen = strlen(mname);
2500  int bufsz = strlen(n) + mnamelen + 2;
2501  std::vector<char> buf(bufsz);
2502  if (nrn_is_ion(self->prop_->_type)) {
2503  strcpy(buf.data(), isptr ? n + 5 : n);
2504  } else {
2505  std::snprintf(buf.data(), bufsz, "%s_%s", isptr ? n + 5 : n, mname);
2506  }
2507  Symbol* sym = var_find_in_mech(mechsym, buf.data());
2508  if (sym && sym->type == RANGEVAR) {
2509  // printf("mech_getattro sym %s\n", sym->name);
2510  if (is_array(*sym)) {
2511  result = nb::steal((PyObject*) PyObject_New(NPyRangeVar, range_type));
2512  NPyRangeVar* r = (NPyRangeVar*) result.ptr();
2513  Py_INCREF(self);
2514  r->pymech_ = self;
2515  r->sym_ = sym;
2516  r->isptr_ = isptr;
2517  r->attr_from_sec_ = 0;
2518  } else {
2519  auto const px = get_rangevar(self, sym, 0);
2520  if (px.is_invalid_handle()) {
2521  rv_noexist(sec, sym->name, self->pyseg_->x_, 2);
2522  result = nb::object();
2523  } else if (isptr) {
2524  result = nb::steal(build_python_reference(px));
2525  } else {
2526  result = nb::steal(build_python_value(px));
2527  }
2528  }
2529  } else if (sym && sym->type == RANGEOBJ) {
2530  Object* ob = nrn_nmodlrandom_wrap(self->prop_, sym);
2531  result = nb::steal(nrnpy_ho2po(ob));
2532  } else if (strcmp(n, "__dict__") == 0) {
2533  nb::dict out_dict{};
2534  int cnt = mechsym->s_varn;
2535  for (int i = 0; i < cnt; ++i) {
2536  Symbol* s = mechsym->u.ppsym[i];
2537  if (!striptrail(buf.data(), bufsz, s->name, mname)) {
2538  strcpy(buf.data(), s->name);
2539  }
2540  out_dict[buf.data()] = nb::none();
2541  }
2542  // FUNCTION and PROCEDURE
2543  for (auto& it: nrn_mech2funcs_map[self->prop_->_type]) {
2544  out_dict[it.first.c_str()] = nb::none();
2545  }
2546  result = out_dict;
2547  } else {
2548  bool found_func{false};
2549  if (self->prop_) {
2550  auto& funcs = nrn_mech2funcs_map[self->prop_->_type];
2551  if (funcs.count(n)) {
2552  found_func = true;
2553  auto& f = funcs[n];
2554  result = nb::steal((PyObject*) PyObject_New(NPyMechFunc, pmechfunc_generic_type));
2555  auto pymf = (NPyMechFunc*) result.ptr();
2556  Py_INCREF(self);
2557  pymf->pymech_ = self;
2558  pymf->f_ = f;
2559  }
2560  }
2561  if (!found_func) {
2562  result = nb::steal(PyObject_GenericGetAttr((PyObject*) self, pyname));
2563  }
2564  }
2565  return result.release().ptr();
2566 }
2567 
2569  return nrn::convert_cxx_exceptions(mech_getattro, self, pyname);
2570 }
2571 
2572 static int mech_setattro(NPyMechObj* self, PyObject* pyname, PyObject* value) {
2573  Section* sec = self->pyseg_->pysec_->sec_;
2574  if (!sec->prop) {
2575  PyErr_SetString(PyExc_ReferenceError, "nrn.Mechanism can't access a deleted section");
2576  return -1;
2577  }
2578 
2579  int err = 0;
2580  auto _pyname_tracker = nb::borrow(pyname); // keep refcount+1 during use
2581  auto name = Py2NRNString::as_ascii(pyname);
2582  char* n = name.c_str();
2583  if (!name.is_valid()) {
2584  Py2NRNString::set_pyerr(PyExc_TypeError, "attribute name must be a string");
2585  return -1;
2586  }
2587  // printf("mech_setattro %s\n", n);
2588  int isptr = (strncmp(n, "_ref_", 5) == 0);
2589  Symbol* mechsym = memb_func[self->type_].sym;
2590  char* mname = mechsym->name;
2591  int mnamelen = strlen(mname);
2592  int bufsz = strlen(n) + mnamelen + 2;
2593  std::vector<char> buf(bufsz);
2594  if (nrn_is_ion(self->prop_->_type)) {
2595  strcpy(buf.data(), isptr ? n + 5 : n);
2596  } else {
2597  std::snprintf(buf.data(), bufsz, "%s_%s", isptr ? n + 5 : n, mname);
2598  }
2599  Symbol* sym = var_find_in_mech(mechsym, buf.data());
2600  if (sym) {
2601  if (isptr) {
2602  err = nrn_pointer_assign(self->prop_, sym, value);
2603  } else {
2604  auto pd = get_rangevar(self, sym, 0);
2605  if (pd.is_invalid_handle()) {
2606  rv_noexist(sec, sym->name, self->pyseg_->x_, 2);
2607  return -1;
2608  } else if (!pd.holds<double*>()) {
2609  PyErr_SetString(PyExc_ValueError, "can't assign value to opaque pointer");
2610  return -1;
2611  } else if (!PyArg_Parse(value, "d", pd.get<double*>())) {
2612  PyErr_SetString(PyExc_ValueError, "must be a double");
2613  return -1;
2614  }
2615  }
2616  } else {
2617  err = PyObject_GenericSetAttr((PyObject*) self, pyname, value);
2618  }
2619  return err;
2620 }
2621 
2622 static int mech_setattro_safe(NPyMechObj* self, PyObject* pyname, PyObject* value) {
2623  return nrn::convert_cxx_exceptions(mech_setattro, self, pyname, value);
2624 }
2625 
2627  if (PyObject_TypeCheck(mech, pmech_generic_type) == 0) {
2628  return nullptr;
2629  }
2630  NPyMechObj* m = (NPyMechObj*) mech;
2631  Symbol* msym = memb_func[m->type_].sym;
2632  char buf[200];
2633  auto name = Py2NRNString::as_ascii(pyname);
2634  char* n = name.c_str();
2635  if (!n) {
2636  return nullptr;
2637  }
2638  Sprintf(buf, "%s_%s", n, msym->name);
2639  Symbol* sym = var_find_in_mech(msym, buf);
2640  if (!sym || sym->type != RANGEVAR || sym->subtype != NRNPOINTER) {
2641  return nullptr;
2642  }
2643  return &(m->prop_->dparam[sym->u.rng.index]);
2644 }
2645 
2647  CHECK_SEC_INVALID(self->sec_);
2648  double x = 0.5;
2649  PyArg_ParseTuple(args, "|d", &x);
2650  auto segargs = nb::steal(Py_BuildValue("(O,d)", self, x));
2651  return NPySegObj_new(psegment_type, segargs.ptr(), nullptr);
2652 }
2653 
2655  return nrn::convert_cxx_exceptions(NPySecObj_call, self, args);
2656 }
2657 
2658 static Py_ssize_t rv_len(PyObject* self) {
2659  NPyRangeVar* r = (NPyRangeVar*) self;
2660  assert(r->sym_);
2661  if (r->sym_->arayinfo) {
2662  assert(r->sym_->arayinfo->nsub == 1);
2663  return r->sym_->arayinfo->sub[0];
2664  }
2665  return 1;
2666 }
2667 
2668 static Py_ssize_t rv_len_safe(PyObject* self) {
2669  return nrn::convert_cxx_exceptions(rv_len, self);
2670 }
2671 
2672 // Returns a new reference.
2673 static PyObject* rv_getitem(PyObject* self, Py_ssize_t ix) {
2674  NPyRangeVar* r = (NPyRangeVar*) self;
2675  Section* sec = r->pymech_->pyseg_->pysec_->sec_;
2677 
2678  if (ix < 0 || ix >= rv_len(self)) {
2679  PyErr_SetString(PyExc_IndexError, r->sym_->name);
2680  return nullptr;
2681  }
2682  if (is_array(*r->sym_)) {
2683  assert(r->sym_->arayinfo->nsub == 1);
2684  auto const array_dim = r->sym_->arayinfo->sub[0];
2685  assert(ix < array_dim);
2686  // r represents a range variable that is an array of size array_dim, and
2687  // we need to apply the offset `ix` to get the correct element of that
2688  // array.
2689  } else {
2690  // Not an array variable, so the index should always be zero
2691  assert(ix == 0);
2692  }
2693  int err;
2694  auto const d = nrnpy_rangepointer(sec, r->sym_, r->pymech_->pyseg_->x_, &err, ix);
2695  if (d.is_invalid_handle()) {
2696  rv_noexist(sec, r->sym_->name, r->pymech_->pyseg_->x_, err);
2697  return nullptr;
2698  }
2699  if (r->isptr_) {
2701  } else {
2702  return build_python_value(d);
2703  }
2704 }
2705 
2706 static PyObject* rv_getitem_safe(PyObject* self, Py_ssize_t ix) {
2707  return nrn::convert_cxx_exceptions(rv_getitem, self, ix);
2708 }
2709 
2710 static int rv_setitem(PyObject* self, Py_ssize_t ix, PyObject* value) {
2711  NPyRangeVar* r = (NPyRangeVar*) self;
2712  Section* sec = r->pymech_->pyseg_->pysec_->sec_;
2713  if (!sec->prop) {
2714  PyErr_SetString(PyExc_ReferenceError, "nrn.RangeVar can't access a deleted section");
2715  return -1;
2716  }
2717 
2718  if (ix < 0 || ix >= rv_len(self)) {
2719  PyErr_SetString(PyExc_IndexError, r->sym_->name);
2720  return -1;
2721  }
2722  int err;
2723  auto d = nrnpy_rangepointer(sec, r->sym_, r->pymech_->pyseg_->x_, &err, ix);
2724  if (d.is_invalid_handle()) {
2725  rv_noexist(sec, r->sym_->name, r->pymech_->pyseg_->x_, err);
2726  return -1;
2727  }
2728  if (r->attr_from_sec_) {
2729  // the range variable array is from a section not a segment and so
2730  // assignment is over the entire section.
2731  double x;
2732  if (!PyArg_Parse(value, "d", &x)) {
2733  PyErr_SetString(PyExc_ValueError, "bad value");
2734  return -1;
2735  }
2736  hoc_pushx(double(ix));
2737  hoc_push_ndim(1);
2739  r->sym_,
2740  neuron::container::data_handle<double>{neuron::container::do_not_search, &x},
2741  0);
2742  } else {
2743  if (d.holds<double*>()) {
2744  if (!PyArg_Parse(value, "d", d.get<double*>())) {
2745  PyErr_SetString(PyExc_ValueError, "bad value");
2746  return -1;
2747  }
2748  } else {
2749  PyErr_SetString(PyExc_ValueError, "can't assign value to opaque pointer");
2750  return -1;
2751  }
2752  }
2753  if (r->sym_->u.rng.type == EXTRACELL && r->sym_->u.rng.index == 0) {
2754  diam_changed = 1;
2755  }
2756  return 0;
2757 }
2758 
2759 static int rv_setitem_safe(PyObject* self, Py_ssize_t ix, PyObject* value) {
2760  return nrn::convert_cxx_exceptions(rv_setitem, self, ix, value);
2761 }
2762 
2763 static PyMethodDef NPySecObj_methods[] = {
2764  {"name",
2765  (PyCFunction) NPySecObj_name_safe,
2766  METH_NOARGS,
2767  "Section name (same as hoc secname())"},
2768  {"hname",
2769  (PyCFunction) NPySecObj_name_safe,
2770  METH_NOARGS,
2771  "Section name (same as hoc secname())"},
2772  {"has_membrane",
2773  (PyCFunction) NPySecObj_has_membrane_safe,
2774  METH_VARARGS,
2775  "Returns True if the section's membrane has this density mechanism.\nThis "
2776  "is not for point processes."},
2777  {"connect",
2778  (PyCFunction) NPySecObj_connect_safe,
2779  METH_VARARGS,
2780  "childSection.connect(parentSection, [parentX], [childEnd]) "
2781  "or\nchildSection.connect(parentSegment, [childEnd])"},
2782  {"insert",
2783  (PyCFunction) NPySecObj_insert_safe,
2784  METH_VARARGS,
2785  "section.insert(densityMechanismName) e.g. soma.insert('hh')"},
2786  {"uninsert",
2787  (PyCFunction) NPySecObj_uninsert_safe,
2788  METH_VARARGS,
2789  "section.uninsert(densityMechanismName) e.g. soma.insert('hh')"},
2790  {"push",
2791  (PyCFunction) NPySecObj_push_safe,
2792  METH_VARARGS,
2793  "section.push() makes it the currently accessed section. Should end with "
2794  "a corresponding hoc.pop_section()"},
2795  {"allseg",
2796  (PyCFunction) allseg_safe,
2797  METH_VARARGS,
2798  "iterate over segments. Includes x=0 and x=1 zero-area nodes in the "
2799  "iteration."},
2800  {"cell",
2801  (PyCFunction) pysec2cell_safe,
2802  METH_NOARGS,
2803  "Return the object that owns the Section. Possibly None."},
2804  {"same",
2805  (PyCFunction) pysec_same_safe,
2806  METH_VARARGS,
2807  "sec1.same(sec2) returns True if sec1 and sec2 wrap the same NEURON "
2808  "Section"},
2809  {"hoc_internal_name",
2810  (PyCFunction) hoc_internal_name_safe,
2811  METH_NOARGS,
2812  "Hoc accepts this name wherever a section is syntactically valid."},
2813  {"disconnect",
2814  (PyCFunction) pysec_disconnect_safe,
2815  METH_NOARGS,
2816  "disconnect from the parent section."},
2817  {"parentseg",
2818  (PyCFunction) pysec_parentseg_safe,
2819  METH_NOARGS,
2820  "Return the nrn.Segment specified by the connect method. Possibly None."},
2821  {"trueparentseg",
2822  (PyCFunction) pysec_trueparentseg_safe,
2823  METH_NOARGS,
2824  "Return the nrn.Segment this section connects to which is closer to the "
2825  "root. Possibly None. (same as parentseg unless parentseg.x == "
2826  "parentseg.sec.orientation()"},
2827  {"orientation",
2828  (PyCFunction) pysec_orientation_safe,
2829  METH_NOARGS,
2830  "Returns 0.0 or 1.0 depending on the x value closest to parent."},
2831  {"children",
2832  (PyCFunction) pysec_children_safe,
2833  METH_NOARGS,
2834  "Return list of child sections. Possibly an empty list"},
2835  {"subtree",
2836  (PyCFunction) pysec_subtree_safe,
2837  METH_NOARGS,
2838  "Return list of sections in the subtree rooted at this section (including this section)."},
2839  {"wholetree",
2840  (PyCFunction) pysec_wholetree_safe,
2841  METH_NOARGS,
2842  "Return list of all sections with a path to this section (including this section). The list "
2843  "has the important property that sections are in root to leaf order, depth-first traversal."},
2844  {"n3d", (PyCFunction) NPySecObj_n3d_safe, METH_NOARGS, "Returns the number of 3D points."},
2845  {"x3d",
2846  (PyCFunction) NPySecObj_x3d_safe,
2847  METH_VARARGS,
2848  "Returns the x coordinate of the ith 3D point."},
2849  {"y3d",
2850  (PyCFunction) NPySecObj_y3d_safe,
2851  METH_VARARGS,
2852  "Returns the y coordinate of the ith 3D point."},
2853  {"z3d",
2854  (PyCFunction) NPySecObj_z3d_safe,
2855  METH_VARARGS,
2856  "Returns the z coordinate of the ith 3D point."},
2857  {"arc3d",
2858  (PyCFunction) NPySecObj_arc3d_safe,
2859  METH_VARARGS,
2860  "Returns the arc position of the ith 3D point."},
2861  {"diam3d",
2862  (PyCFunction) NPySecObj_diam3d_safe,
2863  METH_VARARGS,
2864  "Returns the diam of the ith 3D point."},
2865  {"spine3d",
2866  (PyCFunction) NPySecObj_spine3d_safe,
2867  METH_VARARGS,
2868  "Returns True or False depending on whether a spine exists at the ith 3D point."},
2869  {"pt3dremove", (PyCFunction) NPySecObj_pt3dremove, METH_VARARGS, "Removes the ith 3D point."},
2870  {"pt3dclear",
2871  (PyCFunction) NPySecObj_pt3dclear_safe,
2872  METH_VARARGS,
2873  "Clears all 3D points. Optionally takes a buffer size."},
2874  {"pt3dinsert",
2875  (PyCFunction) NPySecObj_pt3dinsert_safe,
2876  METH_VARARGS,
2877  "Insert the point (so it becomes the i'th point) to section. If i is equal to sec.n3d(), the "
2878  "point is appended (equivalent to sec.pt3dadd())"},
2879  {"pt3dchange",
2880  (PyCFunction) NPySecObj_pt3dchange_safe,
2881  METH_VARARGS,
2882  "Change the i'th 3-d point info. If only two args then the second arg is the diameter and the "
2883  "location is unchanged."},
2884  {"pt3dadd",
2885  (PyCFunction) NPySecObj_pt3dadd_safe,
2886  METH_VARARGS,
2887  "Add the 3d location and diameter point (or points in the second form) at the end of the "
2888  "current pt3d list. Assume that successive additions increase the arc length monotonically."},
2889  {"pt3dstyle",
2890  (PyCFunction) NPySecObj_pt3dstyle_safe,
2891  METH_VARARGS,
2892  "Returns True if using a logical connection point, else False. With first arg 0 sets to no "
2893  "logical connection point. With first arg 1 and x, y, z arguments, sets the logical "
2894  "connection point. Return value includes the result of any setting."},
2895  {"is_pysec",
2896  (PyCFunction) is_pysec_safe,
2897  METH_NOARGS,
2898  "Returns True if Section created from Python, False if created from HOC."},
2899  {"psection",
2900  (PyCFunction) NPySecObj_psection_safe,
2901  METH_NOARGS,
2902  "Returns dict of info about Section contents."},
2903  {NULL}};
2904 
2905 static PyMethodDef NPySegObj_methods[] = {
2906  {"point_processes",
2907  (PyCFunction) seg_point_processes_safe,
2908  METH_NOARGS,
2909  "seg.point_processes() returns list of POINT_PROCESS instances in the "
2910  "segment."},
2911  {"node_index",
2912  (PyCFunction) node_index1_safe,
2913  METH_NOARGS,
2914  "seg.node_index() returns index of v, rhs, etc. in the _actual arrays of "
2915  "the appropriate NrnThread."},
2916  {"area",
2917  (PyCFunction) seg_area_safe,
2918  METH_NOARGS,
2919  "Segment area (um2) (same as h.area(sec(x), sec=sec))"},
2920  {"ri",
2921  (PyCFunction) seg_ri_safe,
2922  METH_NOARGS,
2923  "Segment resistance to parent segment (Megohms) (same as h.ri(sec(x), "
2924  "sec=sec))"},
2925  {"volume", (PyCFunction) seg_volume_safe, METH_NOARGS, "Segment volume (um3)"},
2926  {NULL}};
2927 
2928 static PyMemberDef NPySegObj_members[] = {
2929  {"x", T_DOUBLE, offsetof(NPySegObj, x_), 0, "location in the section (segment containing x)"},
2930  {"sec", T_OBJECT_EX, offsetof(NPySegObj, pysec_), 0, "Section"},
2931  {NULL}};
2932 
2933 static PyMethodDef NPyMechObj_methods[] = {
2934  {"name",
2935  (PyCFunction) NPyMechObj_name_safe,
2936  METH_NOARGS,
2937  "Mechanism name (same as hoc suffix for density mechanism)"},
2938  {"is_ion",
2939  (PyCFunction) NPyMechObj_is_ion_safe,
2940  METH_NOARGS,
2941  "Returns True if an ion mechanism"},
2942  {"segment",
2943  (PyCFunction) NPyMechObj_segment_safe,
2944  METH_NOARGS,
2945  "Returns the segment of the Mechanism instance"},
2946  {NULL}};
2947 
2948 static PyMethodDef NPyMechFunc_methods[] = {
2949  {"name", (PyCFunction) NPyMechFunc_name_safe, METH_NOARGS, "Mechanism function"},
2950  {"mech",
2951  (PyCFunction) NPyMechFunc_mech_safe,
2952  METH_NOARGS,
2953  "Returns the Mechanism for this instance"},
2954  {NULL}};
2955 
2956 static PyMethodDef NPyRangeVar_methods[] = {
2957  {"name", (PyCFunction) NPyRangeVar_name_safe, METH_NOARGS, "Range variable name name"},
2958  {"mech",
2959  (PyCFunction) NPyRangeVar_mech_safe,
2960  METH_NOARGS,
2961  "Returns nrn.Mechanism of the RangeVariable instance"},
2962  {NULL}};
2963 
2964 static PyMemberDef NPyMechObj_members[] = {{NULL}};
2965 
2966 // Returns a new reference.
2969  if (!sec) {
2970  PyErr_SetString(PyExc_TypeError, "Section access unspecified");
2971  return nullptr;
2972  }
2973  // printf("nrnpy_cas %s\n", secname(sec));
2974  return (PyObject*) newpysechelp(sec);
2975 }
2976 
2978  return nrn::convert_cxx_exceptions(nrnpy_cas, self, args);
2979 }
2980 
2981 static PyMethodDef nrnpy_methods[] = {
2982  {"cas", nrnpy_cas_safe, METH_VARARGS, "Return the currently accessed section."},
2983  {"allsec", nrnpy_forall_safe, METH_VARARGS, "Return iterator over all sections."},
2984  {"set_psection",
2986  METH_VARARGS,
2987  "Specify the nrn.Section.psection callback."},
2988  {NULL}};
2989 
2990 #include "nrnpy_nrn.h"
2991 
2993 
2994 static void rangevars_add(Symbol* sym) {
2995  assert(sym && (sym->type == RANGEVAR || sym->type == RANGEOBJ));
2996  NPyRangeVar* r = PyObject_New(NPyRangeVar, range_type);
2997  // printf("%s\n", sym->name);
2998  r->sym_ = sym;
2999  r->isptr_ = 0;
3000  r->attr_from_sec_ = 0;
3001  PyDict_SetItemString(rangevars_, sym->name, (PyObject*) r);
3002 }
3003 
3004 // Returns a borrowed reference.
3006  nb::object m;
3007 
3008  int err = 0;
3009  PyObject* modules = PyImport_GetModuleDict();
3010  if ((m = nb::borrow(PyDict_GetItemString(modules, "nrn"))) && PyModule_Check(m.ptr())) {
3011  return m.ptr();
3012  }
3013  psection_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_SectionType_spec);
3014  psection_type->tp_new = PyType_GenericNew;
3015  if (PyType_Ready(psection_type) < 0)
3016  goto fail;
3017  Py_INCREF(psection_type);
3018 
3019  pallseg_of_sec_iter_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_AllSegOfSecIterType_spec);
3020  pseg_of_sec_iter_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_SegOfSecIterType_spec);
3021  pallseg_of_sec_iter_type->tp_new = PyType_GenericNew;
3022  pseg_of_sec_iter_type->tp_new = PyType_GenericNew;
3023  if (PyType_Ready(pallseg_of_sec_iter_type) < 0)
3024  goto fail;
3025  if (PyType_Ready(pseg_of_sec_iter_type) < 0)
3026  goto fail;
3027  Py_INCREF(pallseg_of_sec_iter_type);
3028  Py_INCREF(pseg_of_sec_iter_type);
3029 
3030  psegment_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_SegmentType_spec);
3031  psegment_type->tp_new = PyType_GenericNew;
3032  if (PyType_Ready(psegment_type) < 0)
3033  goto fail;
3034  if (PyType_Ready(pallseg_of_sec_iter_type) < 0)
3035  goto fail;
3036  if (PyType_Ready(pseg_of_sec_iter_type) < 0)
3037  goto fail;
3038  Py_INCREF(psegment_type);
3039  Py_INCREF(pallseg_of_sec_iter_type);
3040  Py_INCREF(pseg_of_sec_iter_type);
3041 
3042  range_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_RangeType_spec);
3043  range_type->tp_new = PyType_GenericNew;
3044  if (PyType_Ready(range_type) < 0)
3045  goto fail;
3046  Py_INCREF(range_type);
3047 
3048  opaque_pointer_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_OpaquePointerType_spec);
3049  opaque_pointer_type->tp_new = PyType_GenericNew;
3050  if (PyType_Ready(opaque_pointer_type) < 0)
3051  goto fail;
3052  Py_INCREF(opaque_pointer_type);
3053 
3054  m = nb::steal(PyModule_Create(&nrnsectionmodule)); // like nrn but namespace will not include
3055  // mechanims.
3056  PyModule_AddObject(m.ptr(), "Section", (PyObject*) psection_type);
3057  PyModule_AddObject(m.ptr(), "Segment", (PyObject*) psegment_type);
3058 
3059  err = PyDict_SetItemString(modules, "_neuron_section", m.ptr());
3060  assert(err == 0);
3061  m = nb::steal(PyModule_Create(&nrnmodule)); //
3062  nrnmodule_ = m.ptr();
3063  PyModule_AddObject(m.ptr(), "Section", (PyObject*) psection_type);
3064  PyModule_AddObject(m.ptr(), "Segment", (PyObject*) psegment_type);
3065  PyModule_AddObject(m.ptr(), "OpaquePointer", (PyObject*) opaque_pointer_type);
3066 
3067  pmech_generic_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_MechanismType_spec);
3068  pmechfunc_generic_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_MechFuncType_spec);
3069  pmech_of_seg_iter_generic_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_MechOfSegIterType_spec);
3070  pvar_of_mech_iter_generic_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_VarOfMechIterType_spec);
3071  pmech_generic_type->tp_new = PyType_GenericNew;
3072  pmechfunc_generic_type->tp_new = PyType_GenericNew;
3073  pmech_of_seg_iter_generic_type->tp_new = PyType_GenericNew;
3074  pvar_of_mech_iter_generic_type->tp_new = PyType_GenericNew;
3075  if (PyType_Ready(pmech_generic_type) < 0)
3076  goto fail;
3077  if (PyType_Ready(pmechfunc_generic_type) < 0)
3078  goto fail;
3079  if (PyType_Ready(pmech_of_seg_iter_generic_type) < 0)
3080  goto fail;
3081  if (PyType_Ready(pvar_of_mech_iter_generic_type) < 0)
3082  goto fail;
3083  Py_INCREF(pmech_generic_type);
3084  Py_INCREF(pmechfunc_generic_type);
3085  Py_INCREF(pmech_of_seg_iter_generic_type);
3086  Py_INCREF(pvar_of_mech_iter_generic_type);
3087  PyModule_AddObject(m.ptr(), "Mechanism", (PyObject*) pmech_generic_type);
3088  PyModule_AddObject(m.ptr(), "MechFunc", (PyObject*) pmechfunc_generic_type);
3089  PyModule_AddObject(m.ptr(), "MechOfSegIterator", (PyObject*) pmech_of_seg_iter_generic_type);
3090  PyModule_AddObject(m.ptr(), "VarOfMechIterator", (PyObject*) pvar_of_mech_iter_generic_type);
3101 
3102  err = PyDict_SetItemString(modules, "nrn", m.ptr());
3103  assert(err == 0);
3104  return m.ptr();
3105 fail:
3106  return NULL;
3107 }
3108 
3110  int i;
3111  Py_XDECREF(pmech_types);
3112  Py_XDECREF(rangevars_);
3113  pmech_types = PyDict_New();
3114  rangevars_ = PyDict_New();
3120  for (i = 4; i < n_memb_func; ++i) { // start at pas
3121  nrnpy_reg_mech(i);
3122  }
3123 }
3124 
3126  int i;
3127  char* s;
3128  Memb_func& mf = memb_func[type];
3129  if (!nrnmodule_) {
3130  return;
3131  }
3132  if (mf.is_point) {
3133  if (nrn_is_artificial_[type] == 0) {
3135  Symbol* s = hoc_table_lookup("get_segment", sl);
3136  if (!s) {
3137  s = hoc_install("get_segment", OBFUNCTION, 0, &sl);
3138  s->cpublic = 1;
3139  s->u.u_proc->defn.pfo = (Object * *(*) ()) pp_get_segment;
3140  }
3141  }
3142  return;
3143  }
3144  s = mf.sym->name;
3145  // printf("nrnpy_reg_mech %s %d\n", s, type);
3146  if (PyDict_GetItemString(pmech_types, s)) {
3147  hoc_execerror(s, "mechanism already exists");
3148  }
3149  Py_INCREF(pmech_generic_type);
3150  PyModule_AddObject(nrnmodule_, s, (PyObject*) pmech_generic_type);
3151  PyDict_SetItemString(pmech_types, s, Py_BuildValue("i", type));
3152  for (i = 0; i < mf.sym->s_varn; ++i) {
3153  Symbol* sym = mf.sym->u.ppsym[i];
3154  rangevars_add(sym);
3155  }
3156 }
double nrn_section_orientation(Section *sec)
Definition: cabcode.cpp:1556
const char * secname(Section *sec)
name of section (for use in error messages)
Definition: cabcode.cpp:1674
void nrn_change_nseg(Section *sec, int n)
Definition: cabcode.cpp:1482
void mech_uninsert1(Section *sec, Symbol *s)
Definition: cabcode.cpp:898
void nrn_pushsec(Section *sec)
Definition: cabcode.cpp:130
double nrn_arc_position(Section *sec, Node *node)
Definition: cabcode.cpp:1755
int has_membrane(char *mechanism_name, Section *sec)
Definition: cabcode.cpp:2061
Prop * nrn_mechanism(int type, Node *nd)
Definition: cabcode.cpp:1038
double nrn_ra(Section *sec)
Definition: cabcode.cpp:417
void nrn_rangeconst(Section *sec, Symbol *s, neuron::container::data_handle< double > pd, int op)
Definition: cabcode.cpp:935
double section_length(Section *sec)
Definition: cabcode.cpp:401
neuron::container::generic_data_handle nrnpy_rangepointer(Section *sec, Symbol *s, double d, int *err, int idx)
return nullptr if failure instead of hoc_execerror and return pointer to the 0 element if an array
Definition: cabcode.cpp:1306
double nrn_connection_position(Section *sec)
Definition: cabcode.cpp:1552
Section * nrn_noerr_access(void)
return 0 if no accessed section
Definition: cabcode.cpp:474
void nrn_disconnect(Section *sec)
Definition: cabcode.cpp:593
Node * node_exact(Section *sec, double x)
like node_index but give proper node when x is 0 or 1 as well as in between
Definition: cabcode.cpp:1800
void mech_insert1(Section *sec, int type)
Definition: cabcode.cpp:852
int nrn_at_beginning(Section *sec)
Definition: cabcode.cpp:1560
static neuron::unique_cstr as_ascii(PyObject *python_string)
Definition: nrnpy_utils.cpp:17
static void set_pyerr(PyObject *type, const char *message)
Definition: nrnpy_utils.cpp:41
Symbol * hoc_table_lookup(const char *, Symlist *)
Definition: symbol.cpp:48
#define cnt
Definition: tqueue.hpp:44
#define sec
Definition: md1redef.h:20
#define i
Definition: md1redef.h:19
#define prop
Definition: md1redef.h:38
char buf[512]
Definition: init.cpp:13
void hoc_push_frame(Symbol *sp, int narg)
Definition: code.cpp:1376
void hoc_push_ndim(int d)
Definition: code.cpp:855
void hoc_execerr_ext(const char *fmt,...)
printf style specification of hoc_execerror message.
Definition: fileio.cpp:828
Object * nrn_nmodlrandom_wrap(Prop *prop, Symbol *sym)
Symbol * hoc_install(const char *, int, double, Symlist **)
Definition: symbol.cpp:77
void hoc_pop_frame(void)
Definition: code.cpp:1387
#define assert(ex)
Definition: hocassrt.h:24
bool is_array(const Symbol &sym)
Definition: hocdec.h:136
static int narg()
Definition: ivocvect.cpp:121
void hoc_pushx(double)
Definition: code.cpp:779
#define NRNPOINTER
Definition: membfunc.hpp:83
#define CAP
Definition: membfunc.hpp:60
#define MORPHOLOGY
Definition: membfunc.hpp:59
#define EXTRACELL
Definition: membfunc.hpp:61
#define RANGEOBJ
Definition: model.h:124
fabs
Definition: extdef.h:3
const char * name
Definition: init.cpp:16
void move(Item *q1, Item *q2, Item *q3)
Definition: list.cpp:200
void hoc_execerror(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:39
int nrn_is_ion(int)
int diam_changed
Definition: nrnoc_aux.cpp:21
handle_interface< non_owning_identifier< storage > > handle
Non-owning handle to a Mechanism instance.
int Sprintf(char(&buf)[N], const char *fmt, Args &&... args)
Redirect sprintf to snprintf if the buffer size can be deduced.
Definition: wrap_sprintf.h:14
static convert_cxx_exceptions_trait< F, Args... >::return_type convert_cxx_exceptions(F f, Args &&... args)
void ri()
static std::unordered_map< Symbol *, Info > funcs
Definition: nocpout.cpp:3314
static char suffix[256]
Definition: nocpout.cpp:135
void nrn_pt3dclear(Section *, int)
Definition: treeset.cpp:1087
void nrn_area_ri(Section *sec)
Definition: treeset.cpp:752
void stor_pt3d(Section *, double x, double y, double z, double d)
Definition: treeset.cpp:1332
void section_ref(Section *)
Definition: solve.cpp:520
int can_change_morph(Section *)
Definition: treeset.cpp:1228
void section_unref(Section *)
Definition: solve.cpp:509
void sec_free(hoc_Item *)
Definition: solve.cpp:467
void nrn_diam_change(Section *)
Definition: treeset.cpp:1185
void nrn_length_change(Section *, double)
Definition: treeset.cpp:1205
int const size_t const size_t n
Definition: nrngsl.h:10
size_t p
s
Definition: multisend.cpp:521
short index
Definition: cabvars.h:11
std::vector< Memb_func > memb_func
Definition: init.cpp:145
short type
Definition: cabvars.h:10
std::unordered_map< int, NPyDirectMechFuncs > nrn_mech2funcs_map
Definition: init.cpp:963
int n_memb_func
Definition: init.cpp:448
Symbol * nrnpy_pyobj_sym_
Definition: hoc_oop.cpp:25
_object PyObject
Definition: nrnpy.h:12
int nrn_is_hocobj_ptr(PyObject *po, neuron::container::data_handle< double > &pd)
Definition: nrnpy_hoc.cpp:970
PyObject * nrn_hocobj_handle(neuron::container::data_handle< double > d)
Definition: nrnpy_hoc.cpp:957
Object * nrnpy_po2ho(PyObject *po)
Definition: nrnpy_hoc.cpp:592
PyObject * nrnpy_ho2po(Object *o)
Definition: nrnpy_hoc.cpp:566
static PyTypeObject * pseg_of_sec_iter_type
Definition: nrnpy_nrn.cpp:113
static PyObject * NPySecObj_pt3dadd_safe(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:827
Section *(* nrnpy_o2sec_p_)(Object *)
Definition: seclist.cpp:42
static int NPyMechObj_init_safe(NPyMechObj *self, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:692
static PyObject * NPySecObj_pt3dstyle(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:831
static PyObject * NPyRangeVar_new_safe(PyTypeObject *type, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:590
static PyObject * NPySecObj_pt3dinsert(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:795
Object *(* nrnpy_pysec_cell_p_)(Section *)
Definition: cabcode.cpp:61
static PyObject * pysec_wholetree(NPySecObj *const self)
Definition: nrnpy_nrn.cpp:1211
PyObject * nrnpy_cas(PyObject *self, PyObject *args)
Definition: nrnpy_nrn.cpp:2967
void nrn_pt3dremove(Section *sec, int i0)
Definition: treeset.cpp:1161
static PyObject * NPySegObj_new_safe(PyTypeObject *type, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:544
static PyObject * pysec_wholetree_safe(NPySecObj *const self)
Definition: nrnpy_nrn.cpp:1218
static PyObject * NPySecObj_pt3dremove(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:722
static PyObject * pysec_richcmp(NPySecObj *self, PyObject *other, int op)
Definition: nrnpy_nrn.cpp:1282
short * nrn_is_artificial_
Definition: init.cpp:214
static PyMethodDef NPyMechFunc_methods[]
Definition: nrnpy_nrn.cpp:2948
static PyObject * nrnmodule_
Definition: nrnpy_nrn.cpp:2992
static void o2loc2(Object *o, Section **psec, double *px)
Definition: nrnpy_nrn.cpp:658
static PyObject * nrnpy_set_psection(PyObject *self, PyObject *args)
Definition: nrnpy_nrn.cpp:999
static PyObject * var_of_mech_next(NPyVarOfMechIter *self)
Definition: nrnpy_nrn.cpp:2170
static neuron::container::data_handle< double > var_pval(NPyMechObj *pymech, Symbol *symvar, int index)
Definition: nrnpy_nrn.cpp:2437
static PyObject * pysec_orientation_safe(NPySecObj *self)
Definition: nrnpy_nrn.cpp:1127
static Symbol * var_find_in_mech(Symbol *mech, const char *varname)
Definition: nrnpy_nrn.cpp:2426
static PyObject * seg_of_section_iter(NPySecObj *self)
Definition: nrnpy_nrn.cpp:1608
static PyTypeObject * pmech_of_seg_iter_generic_type
Definition: nrnpy_nrn.cpp:115
static PyObject * pysec_subtree1(PyObject *const sl, Section *const sec)
Definition: nrnpy_nrn.cpp:1166
static PyTypeObject * pmech_generic_type
Definition: nrnpy_nrn.cpp:116
static PyObject * pysec_orientation(NPySecObj *self)
Definition: nrnpy_nrn.cpp:1122
static PyObject * pysec_trueparentseg(NPySecObj *self)
Definition: nrnpy_nrn.cpp:1096
void nrn_pt3dinsert(Section *sec, int i0, double x, double y, double z, double d)
Definition: treeset.cpp:1104
static int NPySegObj_contains(PyObject *segment, PyObject *obj)
Definition: nrnpy_nrn.cpp:569
static PyObject * seg_point_processes_safe(NPySegObj *self)
Definition: nrnpy_nrn.cpp:1717
static void NPySecObj_dealloc(NPySecObj *self)
Definition: nrnpy_nrn.cpp:256
static PyMethodDef NPySegObj_methods[]
Definition: nrnpy_nrn.cpp:2905
static PyObject * pysec_same(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1302
static Object * seg_from_sec_x(Section *, double x)
Definition: nrnpy_nrn.cpp:1902
PyObject * NPySecObj_new_safe(PyTypeObject *type, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:493
static int NPySecObj_contains_safe(PyObject *sec, PyObject *obj)
Definition: nrnpy_nrn.cpp:221
static PyObject * NPySecObj_insert(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1506
static PyObject * pysec_parentseg(NPySecObj *self)
Definition: nrnpy_nrn.cpp:1082
PyTypeObject * psection_type
Definition: nrnpy_nrn.cpp:111
static PyObject * mech_of_segment_iter(NPySegObj *self)
Definition: nrnpy_nrn.cpp:1881
static PyTypeObject * opaque_pointer_type
Definition: nrnpy_nrn.cpp:120
static PyObject * NPySecObj_spine3d(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:949
static int mech_setattro_safe(NPyMechObj *self, PyObject *pyname, PyObject *value)
Definition: nrnpy_nrn.cpp:2622
static PyObject * NPyMechObj_name(NPyMechObj *self)
Definition: nrnpy_nrn.cpp:1313
static PyObject * pysec_richcmp_safe(NPySecObj *self, PyObject *other, int op)
Definition: nrnpy_nrn.cpp:1298
static int rv_setitem_safe(PyObject *self, Py_ssize_t ix, PyObject *value)
Definition: nrnpy_nrn.cpp:2759
static PyObject * NPySecObj_insert_safe(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1549
static bool lappendsec(PyObject *const sl, Section *const s)
Definition: nrnpy_nrn.cpp:1131
static PyObject * build_python_value(const neuron::container::generic_data_handle &dh)
Definition: nrnpy_nrn.cpp:1962
static void NPyMechOfSegIter_dealloc_safe(NPyMechOfSegIter *self)
Definition: nrnpy_nrn.cpp:381
static PyObject * allseg_of_sec_next_safe(NPyAllSegOfSecIter *self)
Definition: nrnpy_nrn.cpp:1676
nb::object obj_get_segment(nb::object py_obj)
Definition: nrnpy_nrn.cpp:640
static PyObject * pysec_children(NPySecObj *const self)
Definition: nrnpy_nrn.cpp:1144
static PyObject * NPyMechObj_name_safe(NPyMechObj *self)
Definition: nrnpy_nrn.cpp:1327
static PyObject * NPySecObj_uninsert(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1553
static PyObject * rv_getitem_safe(PyObject *self, Py_ssize_t ix)
Definition: nrnpy_nrn.cpp:2706
static PyObject * section_getattro(NPySecObj *self, PyObject *pyname)
Definition: nrnpy_nrn.cpp:1979
static PyObject * NPySecObj_pt3dclear_safe(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:756
static PyObject * NPyMechFunc_name(NPyMechFunc *self)
Definition: nrnpy_nrn.cpp:1331
void(* nrnpy_o2loc2_p_)(Object *, Section **, double *)
Definition: point.cpp:31
static void o2loc(Object *, Section **, double *)
Definition: nrnpy_nrn.cpp:624
static int NPySegObj_contains_safe(PyObject *segment, PyObject *obj)
Definition: nrnpy_nrn.cpp:574
static void NPyMechFunc_dealloc(NPyMechFunc *self)
Definition: nrnpy_nrn.cpp:365
static PyObject * NPySecObj_pt3dchange(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:760
PyObject * nrnpy_forall_safe(PyObject *self, PyObject *args)
Definition: nrnpy_hoc.cpp:1752
static PyObject * NPySecObj_pt3dchange_safe(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:791
PyObject * nrnpy_newsecobj(PyObject *, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:512
static PyObject * pyseg_repr(PyObject *p)
Definition: nrnpy_nrn.cpp:974
static PyObject * NPySecObj_connect(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1457
static PyObject * NPyMechObj_segment_safe(NPyMechObj *self)
Definition: nrnpy_nrn.cpp:1388
static PyObject * pysec2cell_safe(NPySecObj *self)
Definition: nrnpy_nrn.cpp:1245
static Py_ssize_t rv_len(PyObject *self)
Definition: nrnpy_nrn.cpp:2658
static PyObject * segment_getattro_safe(NPySegObj *self, PyObject *pyname)
Definition: nrnpy_nrn.cpp:2304
static PyObject * NPyMechObj_new_safe(PyTypeObject *type, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:565
static int NPyMechObj_init(NPyMechObj *self, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:679
static PyObject * mech_of_segment_iter_safe(NPySegObj *self)
Definition: nrnpy_nrn.cpp:1898
static PyObject * pysec_subtree(NPySecObj *const self)
Definition: nrnpy_nrn.cpp:1193
static PyObject * nrnpy_psection
Definition: nrnpy_nrn.cpp:998
static PyObject * pysec2cell(NPySecObj *)
Definition: nrnpy_nrn.cpp:1223
static int section_setattro(NPySecObj *self, PyObject *pyname, PyObject *value)
Definition: nrnpy_nrn.cpp:2034
static PyObject * node_index1_safe(NPySegObj *self)
Definition: nrnpy_nrn.cpp:1729
static int segment_setattro(NPySegObj *self, PyObject *pyname, PyObject *value)
Definition: nrnpy_nrn.cpp:2330
Object *(* nrnpy_seg_from_sec_x)(Section *, double x)
Definition: netcvode.cpp:89
static void NPySegOfSecIter_dealloc_safe(NPySegOfSecIter *self)
Definition: nrnpy_nrn.cpp:299
static PyObject * pyseg_richcmp_safe(NPySegObj *self, PyObject *other, int op)
Definition: nrnpy_nrn.cpp:1277
static PyObject * pysec_disconnect(NPySecObj *self)
Definition: nrnpy_nrn.cpp:1072
static PyObject * NPyMechFunc_name_safe(NPyMechFunc *self)
Definition: nrnpy_nrn.cpp:1340
static PyObject * NPySecObj_push(NPySecObj *self, PyObject *)
Definition: nrnpy_nrn.cpp:1597
static bool striptrail(char *buf, int sz, const char *n, const char *m)
Definition: nrnpy_nrn.cpp:2411
static PyObject * pysec_repr(PyObject *p)
Definition: nrnpy_nrn.cpp:961
static PyObject * NPySecObj_pt3dadd(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:815
static PyObject * NPyRangeVar_mech_safe(NPyRangeVar *self)
Definition: nrnpy_nrn.cpp:1453
static void remake_pmech_types()
Definition: nrnpy_nrn.cpp:3109
static PyObject * rv_getitem(PyObject *self, Py_ssize_t ix)
Definition: nrnpy_nrn.cpp:2673
static void NPySegObj_dealloc_safe(NPySegObj *self)
Definition: nrnpy_nrn.cpp:310
static PyObject * pysec_subtree_safe(NPySecObj *const self)
Definition: nrnpy_nrn.cpp:1200
static PyObject * newpyseghelp(Section *sec, double x)
Definition: nrnpy_nrn.cpp:1062
static PyObject * NPySecObj_pt3dstyle_safe(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:864
void simpleconnectsection()
Definition: cabcode.cpp:664
void(* nrnpy_o2loc_p_)(Object *, Section **, double *)
Definition: point.cpp:30
cTemplate ** nrn_pnt_template_
Definition: init.cpp:153
static PyMemberDef NPyMechObj_members[]
Definition: nrnpy_nrn.cpp:2964
static PyObject * NPySecObj_arc3d(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:923
static PyTypeObject * pallseg_of_sec_iter_type
Definition: nrnpy_nrn.cpp:112
static PyTypeObject * psegment_type
Definition: nrnpy_nrn.cpp:114
neuron::container::generic_data_handle * nrnpy_setpointer_helper(PyObject *pyname, PyObject *mech)
Definition: nrnpy_nrn.cpp:2626
static Section * o2sec(Object *)
Definition: nrnpy_nrn.cpp:612
static PyObject * NPyMechFunc_call_safe(NPyMechFunc *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1369
static PyObject * NPySecObj_psection_safe(NPySecObj *self)
Definition: nrnpy_nrn.cpp:1028
static void NPyAllSegOfSecIter_dealloc_safe(NPyAllSegOfSecIter *self)
Definition: nrnpy_nrn.cpp:288
static void NPyMechFunc_dealloc_safe(NPyMechFunc *self)
Definition: nrnpy_nrn.cpp:371
void nrnpy_sec_referr()
Definition: nrnpy_nrn.cpp:150
static PyObject * NPySecObj_uninsert_safe(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1577
PyObject * NPyAllSegOfSecIter_new_safe(PyTypeObject *type, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:508
static Section * find_root_section(Section *sec)
Definition: nrnpy_nrn.cpp:1204
void nrn_pt3dchange2(Section *sec, int i, double x, double y, double z, double diam)
Definition: treeset.cpp:1140
static PyObject * NPySecObj_y3d_safe(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:905
static PyObject * NPyMechObj_is_ion_safe(NPyMechObj *self)
Definition: nrnpy_nrn.cpp:1378
static PyObject * NPySecObj_connect_safe(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1502
static PyObject * is_pysec(NPySecObj *self)
Definition: nrnpy_nrn.cpp:1032
static double interpolate(double x0, double x1, double y0, double y1, double xnew)
Definition: nrnpy_nrn.cpp:1758
static Object ** pp_get_segment(void *vptr)
Definition: nrnpy_nrn.cpp:1910
static Prop * mech_of_segment_prop(Prop *p)
Definition: nrnpy_nrn.cpp:1863
static PyMethodDef NPyMechObj_methods[]
Definition: nrnpy_nrn.cpp:2933
static PyObject * NPyMechFunc_call(NPyMechFunc *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1345
static void NPySegObj_dealloc(NPySegObj *self)
Definition: nrnpy_nrn.cpp:304
static PyObject * NPyMechObj_segment(NPyMechObj *self)
Definition: nrnpy_nrn.cpp:1382
static PyObject * NPySecObj_diam3d_safe(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:944
static NPyRangeVar * rvnew(Symbol *sym, NPySecObj *sec, double x)
Definition: nrnpy_nrn.cpp:1940
static PyObject * pyseg_richcmp(NPySegObj *self, PyObject *other, int op)
Definition: nrnpy_nrn.cpp:1266
static int NPySegObj_init(NPySegObj *self, PyObject *, PyObject *)
Definition: nrnpy_nrn.cpp:594
static PyObject * segment_getattro(NPySegObj *self, PyObject *pyname)
Definition: nrnpy_nrn.cpp:2191
static PyObject * NPySecObj_call(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:2646
static PyObject * seg_of_sec_next_safe(NPySegOfSecIter *self)
Definition: nrnpy_nrn.cpp:1699
static PyObject * NPySecObj_has_membrane_safe(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1593
static PyObject * NPySecObj_x3d_safe(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:892
void nrn_pt3dstyle1(Section *sec, double x, double y, double z)
Definition: treeset.cpp:985
static void NPySegOfSecIter_dealloc(NPySegOfSecIter *self)
Definition: nrnpy_nrn.cpp:293
static PyObject * pymech_repr(PyObject *p)
Definition: nrnpy_nrn.cpp:1405
static PyObject * pymech_repr_safe(PyObject *p)
Definition: nrnpy_nrn.cpp:1410
static PyObject * seg_area(NPySegObj *self)
Definition: nrnpy_nrn.cpp:1734
static PyObject * NPySegObj_new(PyTypeObject *type, PyObject *args, PyObject *)
Definition: nrnpy_nrn.cpp:520
static int NpySObj_contains(PyObject *s, PyObject *obj, const char *string)
Definition: nrnpy_nrn.cpp:206
static PyObject * pysec_children_safe(NPySecObj *const self)
Definition: nrnpy_nrn.cpp:1161
static neuron::container::generic_data_handle var_dparam(NPyMechObj *pymech, Symbol *symvar, int index)
Definition: nrnpy_nrn.cpp:2458
int(* nrnpy_pysec_cell_equals_p_)(Section *, Object *)
Definition: cabcode.cpp:62
static PyObject * pysec_disconnect_safe(NPySecObj *self)
Definition: nrnpy_nrn.cpp:1078
static PyObject * pysec_parentseg_safe(NPySecObj *self)
Definition: nrnpy_nrn.cpp:1092
static PyObject * NPySecObj_arc3d_safe(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:931
int nrn_pointer_assign(Prop *prop, Symbol *sym, PyObject *value)
Definition: nrnpy_nrn.cpp:2308
static PyObject * hoc_internal_name(NPySecObj *self)
Definition: nrnpy_nrn.cpp:989
PyObject * pmech_types
Definition: nrnpy_nrn.cpp:122
void nrn_pt3dchange1(Section *sec, int i, double d)
Definition: treeset.cpp:1133
static PyMethodDef NPySecObj_methods[]
Definition: nrnpy_nrn.cpp:2763
static PyObject * NPySecObj_has_membrane(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1581
PyObject * nrnpy_nrn(void)
Definition: nrnpy_nrn.cpp:3005
static PyObject * hoc_internal_name_safe(NPySecObj *self)
Definition: nrnpy_nrn.cpp:994
PyObject * NPyAllSegOfSecIter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:497
PyObject * nrnpy_newsecobj_safe(PyObject *self, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:516
static Py_ssize_t rv_len_safe(PyObject *self)
Definition: nrnpy_nrn.cpp:2668
static PyObject * var_of_mech_next_safe(NPyVarOfMechIter *self)
Definition: nrnpy_nrn.cpp:2186
static void NPyAllSegOfSecIter_dealloc(NPyAllSegOfSecIter *self)
Definition: nrnpy_nrn.cpp:282
static PyObject * mech_of_seg_next_safe(NPyMechOfSegIter *self)
Definition: nrnpy_nrn.cpp:2146
static PyObject * NPySecObj_psection(NPySecObj *self)
Definition: nrnpy_nrn.cpp:1019
static PyMemberDef NPySegObj_members[]
Definition: nrnpy_nrn.cpp:2928
static PyObject * NPySecObj_push_safe(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1604
static PyObject * NPySecObj_name(NPySecObj *self)
Definition: nrnpy_nrn.cpp:705
static PyObject * seg_point_processes(NPySegObj *self)
Definition: nrnpy_nrn.cpp:1703
static PyObject * NPySecObj_diam3d(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:935
static void NPySecObj_dealloc_safe(NPySecObj *self)
Definition: nrnpy_nrn.cpp:276
static PyObject * seg_of_sec_next(NPySegOfSecIter *self)
Definition: nrnpy_nrn.cpp:1680
static PyObject * seg_volume_safe(NPySegObj *self)
Definition: nrnpy_nrn.cpp:1840
static PyObject * NPySecObj_n3d(NPySecObj *self)
Definition: nrnpy_nrn.cpp:713
static void NPyVarOfMechIter_dealloc_safe(NPyVarOfMechIter *self)
Definition: nrnpy_nrn.cpp:391
static PyObject * pysec_repr_safe(PyObject *p)
Definition: nrnpy_nrn.cpp:969
static PyObject * NPyRangeVar_name_safe(NPyRangeVar *self)
Definition: nrnpy_nrn.cpp:1440
static void NPyMechOfSegIter_dealloc(NPyMechOfSegIter *self)
Definition: nrnpy_nrn.cpp:375
static int pysec_cell_equals(Section *, Object *)
Definition: nrnpy_nrn.cpp:225
static PyObject * NPySecObj_call_safe(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:2654
static PyObject * NPyMechFunc_mech_safe(NPyMechFunc *self)
Definition: nrnpy_nrn.cpp:1401
static PyObject * build_python_reference(const neuron::container::generic_data_handle &dh)
Definition: nrnpy_nrn.cpp:1971
static int ob_is_seg(Object *)
Definition: nrnpy_nrn.cpp:601
static PyObject * pysec_trueparentseg_safe(NPySecObj *self)
Definition: nrnpy_nrn.cpp:1118
static neuron::container::generic_data_handle get_rangevar(NPyMechObj *pymech, Symbol *symvar, int index)
Definition: nrnpy_nrn.cpp:2471
static PyObject * NPySecObj_name_safe(NPySecObj *self)
Definition: nrnpy_nrn.cpp:709
static PyObject * seg_area_safe(NPySegObj *self)
Definition: nrnpy_nrn.cpp:1749
static void NPyRangeVar_dealloc(NPyRangeVar *self)
Definition: nrnpy_nrn.cpp:315
static PyObject * seg_ri(NPySegObj *self)
Definition: nrnpy_nrn.cpp:1845
static int mech_setattro(NPyMechObj *self, PyObject *pyname, PyObject *value)
Definition: nrnpy_nrn.cpp:2572
static PyObject * pymechfunc_repr(PyObject *p)
Definition: nrnpy_nrn.cpp:1414
static void NPyMechObj_dealloc(NPyMechObj *self)
Definition: nrnpy_nrn.cpp:325
static long pysec_hash_safe(PyObject *self)
Definition: nrnpy_nrn.cpp:1253
static PyObject * section_getattro_safe(NPySecObj *self, PyObject *pyname)
Definition: nrnpy_nrn.cpp:2030
static char * pysec_name(Section *)
Definition: nrnpy_nrn.cpp:158
static PyObject * NPySecObj_x3d(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:883
static NPyMechObj * new_pymechobj()
Definition: nrnpy_nrn.cpp:337
PyObject * rangevars_
Definition: nrnpy_nrn.cpp:123
static int NPySecObj_init_safe(NPySecObj *self, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:460
static void NPyVarOfMechIter_dealloc(NPyVarOfMechIter *self)
Definition: nrnpy_nrn.cpp:385
static long pysec_hash(PyObject *self)
Definition: nrnpy_nrn.cpp:1249
static PyTypeObject * pvar_of_mech_iter_generic_type
Definition: nrnpy_nrn.cpp:118
static int NPyRangeVar_init(NPyRangeVar *self, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:696
static int rv_setitem(PyObject *self, Py_ssize_t ix, PyObject *value)
Definition: nrnpy_nrn.cpp:2710
static void rv_noexist(Section *sec, const char *n, double x, int err)
Definition: nrnpy_nrn.cpp:1927
int hocobj_pushargs(PyObject *, std::vector< neuron::unique_cstr > &)
Definition: nrnpy_hoc.cpp:416
static PyObject * mech_getattro_safe(NPyMechObj *self, PyObject *pyname)
Definition: nrnpy_nrn.cpp:2568
static PyObject * NPyMechObj_is_ion(NPyMechObj *self)
Definition: nrnpy_nrn.cpp:1373
static PyObject * NPySecObj_spine3d_safe(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:957
static void rangevars_add(Symbol *sym)
Definition: nrnpy_nrn.cpp:2994
static PyObject * var_of_mech_iter_safe(NPyMechObj *self)
Definition: nrnpy_nrn.cpp:2166
static PyObject * is_pysec_safe(NPySecObj *self)
Definition: nrnpy_nrn.cpp:1038
static double scaled_frustum_volume(double length, double d0, double d1)
Definition: nrnpy_nrn.cpp:1753
static PyMethodDef nrnpy_methods[]
Definition: nrnpy_nrn.cpp:2981
static PyObject * pysec_same_safe(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1309
static long pyseg_hash_safe(PyObject *self)
Definition: nrnpy_nrn.cpp:1262
static PyObject * pymechfunc_repr_safe(PyObject *p)
Definition: nrnpy_nrn.cpp:1419
static NPyOpaquePointer * opaque_pointer_new()
Definition: nrnpy_nrn.cpp:1957
static PyObject * NPySecObj_z3d(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:909
static PyObject * allseg_of_sec_iter_safe(NPyAllSegOfSecIter *self)
Definition: nrnpy_nrn.cpp:1647
static PyObject * node_index1(NPySegObj *self)
Definition: nrnpy_nrn.cpp:1722
static PyObject * seg_of_section_iter_safe(NPySecObj *self)
Definition: nrnpy_nrn.cpp:1623
static PyObject * mech_getattro(NPyMechObj *self, PyObject *pyname)
Definition: nrnpy_nrn.cpp:2483
char *(* nrnpy_pysec_name_p_)(Section *)
Definition: cabcode.cpp:60
static int NPySecObj_init(NPySecObj *self, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:405
static PyObject * NPySecObj_n3d_safe(NPySecObj *self)
Definition: nrnpy_nrn.cpp:718
static PyObject * mech_of_seg_next(NPyMechOfSegIter *self)
Definition: nrnpy_nrn.cpp:2125
static PyObject * NPySecObj_y3d(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:896
static PyObject * NPyMechObj_new(PyTypeObject *type, PyObject *args, PyObject *)
Definition: nrnpy_nrn.cpp:548
static PyObject * pyseg_repr_safe(PyObject *p)
Definition: nrnpy_nrn.cpp:984
static PyObject * NPySecObj_z3d_safe(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:918
static void nrnpy_reg_mech(int)
Definition: nrnpy_nrn.cpp:3125
static PyObject * pysec_subtree_impl(Section *sec)
Definition: nrnpy_nrn.cpp:1179
static PyObject * seg_ri_safe(NPySegObj *self)
Definition: nrnpy_nrn.cpp:1859
static PyObject * seg_volume(NPySegObj *self)
Definition: nrnpy_nrn.cpp:1786
void nrn_pt3dstyle0(Section *sec)
Definition: treeset.cpp:976
int(* nrnpy_ob_is_seg)(Object *)
Definition: nrnmenu.cpp:38
static PyObject * NPyRangeVar_name(NPyRangeVar *self)
Definition: nrnpy_nrn.cpp:1423
void(* nrnpy_reg_mech_p_)(int)
Definition: init.cpp:105
static PyObject * allseg_safe(NPySecObj *self)
Definition: nrnpy_nrn.cpp:1637
static PyTypeObject * pmechfunc_generic_type
Definition: nrnpy_nrn.cpp:117
static PyObject * allseg_of_sec_iter(NPyAllSegOfSecIter *self)
Definition: nrnpy_nrn.cpp:1641
static PyObject * NPySecObj_pt3dinsert_safe(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:811
void nrnpy_prop_referr()
Definition: nrnpy_nrn.cpp:154
static PyObject * NPySecObj_pt3dclear(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:738
static void NPyMechObj_dealloc_safe(NPyMechObj *self)
Definition: nrnpy_nrn.cpp:333
static int NPySecObj_contains(PyObject *sec, PyObject *obj)
Definition: nrnpy_nrn.cpp:216
static Pt3d * get_pt3d_from_python_args(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:868
static int section_setattro_safe(NPySecObj *self, PyObject *pyname, PyObject *value)
Definition: nrnpy_nrn.cpp:2121
PyObject * nrn_ptr_richcmp(void *self_ptr, void *other_ptr, int op)
Definition: nrnpy_hoc.cpp:2396
#define M_PI
Definition: nrnpy_nrn.cpp:17
static PyObject * var_of_mech_iter(NPyMechObj *self)
Definition: nrnpy_nrn.cpp:2150
static int NPyAllSegOfSecIter_init_safe(NPyAllSegOfSecIter *self, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:478
PyTypeObject * hocobject_type
Definition: nrnpy_hoc.cpp:130
static int segment_setattro_safe(NPySegObj *self, PyObject *pyname, PyObject *value)
Definition: nrnpy_nrn.cpp:2407
static long pyseg_hash(PyObject *self)
Definition: nrnpy_nrn.cpp:1257
static int arg_bisect_arc3d(Section *sec, int npt3d, double x)
Definition: nrnpy_nrn.cpp:1769
PyObject * NPySecObj_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:482
static int NPyRangeVar_init_safe(NPyRangeVar *self, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:700
static PyMethodDef NPyRangeVar_methods[]
Definition: nrnpy_nrn.cpp:2956
static PyObject * NPyRangeVar_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:578
PyObject * nrnpy_cas_safe(PyObject *self, PyObject *args)
Definition: nrnpy_nrn.cpp:2977
static PyObject * allseg(NPySecObj *self)
Definition: nrnpy_nrn.cpp:1627
static PyTypeObject * range_type
Definition: nrnpy_nrn.cpp:119
static int NPyAllSegOfSecIter_init(NPyAllSegOfSecIter *self, PyObject *args, PyObject *)
Definition: nrnpy_nrn.cpp:464
NPySecObj * newpysechelp(Section *sec)
Definition: nrnpy_nrn.cpp:1043
static Object * pysec_cell(Section *)
Definition: nrnpy_nrn.cpp:173
static void NPyRangeVar_dealloc_safe(NPyRangeVar *self)
Definition: nrnpy_nrn.cpp:321
static PyObject * NPyMechFunc_mech(NPyMechFunc *self)
Definition: nrnpy_nrn.cpp:1392
static PyObject * nrnpy_set_psection_safe(PyObject *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1015
static PyObject * NPyRangeVar_mech(NPyRangeVar *self)
Definition: nrnpy_nrn.cpp:1444
static PyObject * allseg_of_sec_next(NPyAllSegOfSecIter *self)
Definition: nrnpy_nrn.cpp:1651
static PyType_Spec nrnpy_MechOfSegIterType_spec
Definition: nrnpy_nrn.h:90
static PyType_Spec nrnpy_VarOfMechIterType_spec
Definition: nrnpy_nrn.h:142
static PyType_Spec nrnpy_AllSegOfSecIterType_spec
Definition: nrnpy_nrn.h:35
static PyType_Spec nrnpy_SectionType_spec
Definition: nrnpy_nrn.h:17
static PyType_Spec nrnpy_SegOfSecIterType_spec
Definition: nrnpy_nrn.h:51
static struct PyModuleDef nrnsectionmodule
Definition: nrnpy_nrn.h:195
static PyType_Spec nrnpy_MechanismType_spec
Definition: nrnpy_nrn.h:111
static PyType_Spec nrnpy_RangeType_spec
Definition: nrnpy_nrn.h:161
static struct PyModuleDef nrnmodule
Definition: nrnpy_nrn.h:181
static PyType_Spec nrnpy_MechFuncType_spec
Definition: nrnpy_nrn.h:127
static PyType_Spec nrnpy_SegmentType_spec
Definition: nrnpy_nrn.h:75
static PyType_Spec nrnpy_OpaquePointerType_spec
Definition: nrnpy_nrn.h:173
Object * nrnpy_pyobject_in_obj(PyObject *po)
Definition: nrnpy_p2h.cpp:91
PyObject * nrnpy_hoc2pyobject(Object *ho)
Definition: nrnpy_p2h.cpp:77
int nrnpy_ho_eq_po(Object *ho, PyObject *po)
Definition: nrnpy_p2h.cpp:61
#define CHECK_SEC_INVALID(sec)
Definition: nrnpy_utils.h:27
#define CHECK_PROP_INVALID(propid)
Definition: nrnpy_utils.h:36
#define PyInt_AsLong
Definition: nrnpython.h:27
#define PyInt_FromLong
Definition: nrnpython.h:28
#define castptr2long
Definition: nrnpython.h:39
#define PyString_FromString
Definition: nrnpython.h:23
static N_Vector x_
static double cell(void *v)
Definition: ocbbs.cpp:540
void nrnpy_pysecname2sec_add(Section *sec)
void nrnpy_pysecname2sec_remove(Section *sec)
static uint32_t value
Definition: scoprand.cpp:25
#define PROP_PY_INDEX
Definition: section.h:230
#define NODERINV(n)
Definition: section.h:102
#define NODEAREA(n)
Definition: section.h:101
#define NODEV(n)
Definition: section_fwd.hpp:60
#define NULL
Definition: spdefs.h:105
Object ** hoc_temp_objptr(Object *)
Definition: code.cpp:151
Symlist * hoc_built_in_symlist
Definition: symbol.cpp:28
int nsub
Definition: hocdec.h:61
int sub[1]
Definition: hocdec.h:63
int is_point
Definition: membfunc.h:86
Symbol * sym
Definition: membfunc.h:74
PyObject_HEAD NPySecObj * pysec_
Definition: nrnpy_nrn.cpp:49
NPyDirectMechFunc * f_
Definition: nrnpy_nrn.cpp:83
PyObject_HEAD NPyMechObj * pymech_
Definition: nrnpy_nrn.cpp:82
neuron::container::non_owning_identifier_without_container prop_id_
Definition: nrnpy_nrn.cpp:71
PyObject_HEAD NPySegObj * pyseg_
Definition: nrnpy_nrn.cpp:67
Prop * prop_
Definition: nrnpy_nrn.cpp:68
PyObject_HEAD NPyMechObj * pymech_
Definition: nrnpy_nrn.cpp:77
PyObject_HEAD NPyMechObj * pymech_
Definition: nrnpy_nrn.cpp:95
int index_
Definition: nrnpy_nrn.cpp:96
int attr_from_sec_
Definition: nrnpy_nrn.cpp:104
PyObject_HEAD NPyMechObj * pymech_
Definition: nrnpy_nrn.cpp:101
Symbol * sym_
Definition: nrnpy_nrn.cpp:102
PyObject_HEAD Section * sec_
Definition: nrnpython.h:79
char * name_
Definition: nrnpython.h:80
PyObject * cell_weakref_
Definition: nrnpython.h:81
double x_
Definition: nrnpy_nrn.cpp:62
PyObject_HEAD NPySecObj * pysec_
Definition: nrnpy_nrn.cpp:61
PyObject_HEAD NPySecObj * pysec_
Definition: nrnpy_nrn.cpp:55
Symbol * msym_
Definition: nrnpy_nrn.cpp:89
PyObject_HEAD NPyMechObj * pymech_
Definition: nrnpy_nrn.cpp:88
Definition: section.h:105
auto v_handle()
Definition: section.h:153
int v_node_index
Definition: section.h:212
Prop * prop
Definition: section.h:190
Definition: hocdec.h:173
Objectdata * dataspace
Definition: hocdec.h:177
int refcount
Definition: hocdec.h:174
cTemplate * ctemplate
Definition: hocdec.h:180
union Object::@47 u
A point process is computed just like regular mechanisms.
Definition: section_fwd.hpp:77
Section * sec
Definition: section_fwd.hpp:78
Definition: section.h:231
Datum * dparam
Definition: section.h:247
Object * ob
Definition: section.h:252
auto param_handle_legacy(int legacy_index)
Definition: section.h:355
Prop * next
Definition: section.h:243
Definition: section.h:45
float z
Definition: section.h:46
double arc
Definition: section.h:47
float x
Definition: section.h:46
float y
Definition: section.h:46
float d
Definition: section.h:46
Prop * prop
Definition: section.h:71
short nnode
Definition: section.h:52
Section * parentsec
Definition: section.h:53
Definition: model.h:47
union Symbol::@28 u
Symbol ** ppsym
Definition: hocdec.h:125
struct Symbol::@45::@46 rng
short type
Definition: model.h:48
long subtype
Definition: model.h:49
unsigned s_varn
Definition: hocdec.h:129
char * name
Definition: model.h:61
Arrayinfo * arayinfo
Definition: hocdec.h:130
Definition: hocdec.h:75
Symbol * sym
Definition: hocdec.h:147
Symlist * symtable
Definition: hocdec.h:148
Non-template stable handle to a generic value.
bool holds() const
Check if this handle refers to the specific type.
T get() const
Explicit conversion to any T.
A non-owning permutation-stable identifier for an entry in a container.
double * pval
Definition: hocdec.h:164