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 nullptr;
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 nullptr;
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", nullptr};
408  if (self && !self->sec_) {
409  delete[] self->name_;
410  self->name_ = nullptr;
411  self->cell_weakref_ = nullptr;
412  char* name = nullptr;
413  PyObject* cell = nullptr;
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, nullptr);
421  if (!self->cell_weakref_) {
422  return -1;
423  }
424  } else {
425  cell = nullptr;
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 && !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 nullptr;
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 nullptr;
532  }
533  NPySegObj* self;
534  self = (NPySegObj*) type->tp_alloc(type, 0);
535  // printf("NPySegObj_new %p\n", self);
536  if (self) {
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 nullptr;
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) {
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) {
582  self->pymech_ = nullptr;
583  self->sym_ = nullptr;
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", nullptr);
615  }
616  PyObject* po = nrnpy_hoc2pyobject(o);
617  if (!PyObject_TypeCheck(po, psection_type)) {
618  hoc_execerror("not a Python nrn.Section", nullptr);
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", nullptr);
627  }
628  PyObject* po = nrnpy_hoc2pyobject(o);
629  if (!PyObject_TypeCheck(po, psegment_type)) {
630  hoc_execerror("not a Python nrn.Segment", nullptr);
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", nullptr);
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) {
887  return nullptr;
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) {
900  return nullptr;
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) {
913  return nullptr;
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) {
926  return nullptr;
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) {
939  return nullptr;
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) {
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) {
1065  return nullptr;
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 || !psec->prop) {
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 || !psec->prop) {
1102  Py_RETURN_NONE;
1103  }
1104  if (nrn_at_beginning(sec)) {
1105  sec = psec;
1106  } else {
1107  break;
1108  }
1109  }
1110  if (!psec) {
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::cast(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 nullptr;
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 nullptr;
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) {
1614  return nullptr;
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 nullptr;
1657  }
1658  seg = PyObject_New(NPySegObj, psegment_type);
1659  if (!seg) {
1660  // error
1661  return nullptr;
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 nullptr;
1686  }
1687  seg = PyObject_New(NPySegObj, psegment_type);
1688  if (!seg) {
1689  // error
1690  return nullptr;
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  // Initialize pymech_ immediately so NPyMechOfSegIter_dealloc is safe on any
1891  // early return below (PyObject_New does not zero-initialize struct fields).
1892  ((NPyMechOfSegIter*) mi.ptr())->pymech_ = nullptr;
1893  NPyMechObj* mnew = nullptr;
1894  if (p) {
1895  mnew = new_pymechobj(self, p);
1896  if (!mnew) {
1897  return nullptr;
1898  }
1899  }
1900  ((NPyMechOfSegIter*) mi.ptr())->pymech_ = mnew;
1901  return mi.release().ptr();
1902 }
1903 
1906 }
1907 
1908 static Object* seg_from_sec_x(Section* sec, double x) {
1909  auto pyseg = nb::steal((PyObject*) PyObject_New(NPySegObj, psegment_type));
1910  auto* pseg = (NPySegObj*) pyseg.ptr();
1911  pseg->pysec_ = newpysechelp(sec); // newpysechelp() already increfs
1912  pseg->x_ = x;
1913  return nrnpy_pyobject_in_obj((PyObject*) pseg);
1914 }
1915 
1916 static Object** pp_get_segment(void* vptr) {
1917  Point_process* pnt = (Point_process*) vptr;
1918  // printf("pp_get_segment %s\n", hoc_object_name(pnt->ob));
1919  Object* ho = nullptr;
1920  if (pnt->prop) {
1921  Section* sec = pnt->sec;
1922  double x = nrn_arc_position(sec, pnt->node);
1923  ho = seg_from_sec_x(sec, x);
1924  }
1925  if (!ho) {
1926  ho = nrnpy_pyobject_in_obj(Py_None);
1927  }
1928  Object** tobj = hoc_temp_objptr(ho);
1929  --ho->refcount;
1930  return tobj;
1931 }
1932 
1933 static void rv_noexist(Section* sec, const char* n, double x, int err) {
1934  char buf[200];
1935  if (err == 2) {
1936  Sprintf(buf, "%s was not made to point to anything at %s(%g)", n, secname(sec), x);
1937  } else if (err == 1) {
1938  Sprintf(buf, "%s, the mechanism does not exist at %s(%g)", n, secname(sec), x);
1939  } else {
1940  Sprintf(buf, "%s does not exist at %s(%g)", n, secname(sec), x);
1941  }
1942  PyErr_SetString(PyExc_AttributeError, buf);
1943 }
1944 
1945 // Returns a (casted) new reference.
1946 static NPyRangeVar* rvnew(Symbol* sym, NPySecObj* sec, double x) {
1947  NPyRangeVar* r = PyObject_New(NPyRangeVar, range_type);
1948  if (!r) {
1949  return nullptr;
1950  }
1951  r->pymech_ = new_pymechobj();
1952  r->pymech_->pyseg_ = PyObject_New(NPySegObj, psegment_type);
1953  Py_INCREF(sec);
1954  r->pymech_->pyseg_->pysec_ = sec;
1955  r->pymech_->pyseg_->x_ = 0.5;
1956  r->sym_ = sym;
1957  r->isptr_ = 0;
1958  r->attr_from_sec_ = 1;
1959  return r;
1960 }
1961 
1962 // Returns a new reference.
1964  return PyObject_New(NPyOpaquePointer, opaque_pointer_type);
1965 }
1966 
1967 // Returns a new reference.
1969  if (dh.holds<double*>()) {
1970  return Py_BuildValue("d", *dh.get<double*>());
1971  } else {
1972  return (PyObject*) opaque_pointer_new();
1973  }
1974 }
1975 
1976 // Returns a new reference.
1978  if (dh.holds<double*>()) {
1980  } else {
1981  return (PyObject*) opaque_pointer_new();
1982  }
1983 }
1984 
1985 static PyObject* section_getattro(NPySecObj* self, PyObject* pyname) {
1986  Section* sec = self->sec_;
1988  PyObject* rv;
1989  auto _pyname_tracker = nb::borrow(pyname); // keep refcount+1 during use
1990  auto name = Py2NRNString::as_ascii(pyname);
1991  char* n = name.c_str();
1992  if (!name.is_valid()) {
1993  Py2NRNString::set_pyerr(PyExc_TypeError, "attribute name must be a string");
1994  return nullptr;
1995  }
1996  // printf("section_getattr %s\n", n);
1997  nb::object result;
1998  if (strcmp(n, "L") == 0) {
1999  result = nb::cast(section_length(sec));
2000  } else if (strcmp(n, "Ra") == 0) {
2001  result = nb::cast(nrn_ra(sec));
2002  } else if (strcmp(n, "nseg") == 0) {
2003  result = nb::cast(sec->nnode - 1);
2004  } else if ((rv = PyDict_GetItemString(rangevars_, n))) {
2005  Symbol* sym = ((NPyRangeVar*) rv)->sym_;
2006  if (is_array(*sym)) {
2007  result = nb::steal((PyObject*) rvnew(sym, self, 0.5));
2008  } else {
2009  int err;
2010  auto const d = nrnpy_rangepointer(sec, sym, 0.5, &err, 0 /* idx */);
2011  if (d.is_invalid_handle()) {
2012  rv_noexist(sec, n, 0.5, err);
2013  return nullptr;
2014  } else {
2015  if (sec->recalc_area_ && sym->u.rng.type == MORPHOLOGY) {
2016  nrn_area_ri(sec);
2017  }
2018  result = nb::steal(build_python_value(d));
2019  }
2020  }
2021  } else if (strcmp(n, "rallbranch") == 0) {
2022  result = nb::cast(sec->prop->dparam[4].get<double>());
2023  } else if (strcmp(n, "__dict__") == 0) {
2024  nb::dict out_dict{};
2025  out_dict["L"] = nb::none();
2026  out_dict["Ra"] = nb::none();
2027  out_dict["nseg"] = nb::none();
2028  out_dict["rallbranch"] = nb::none();
2029  result = std::move(out_dict);
2030  } else {
2031  result = nb::steal(PyObject_GenericGetAttr((PyObject*) self, pyname));
2032  }
2033  return result.release().ptr();
2034 }
2035 
2037  return nrn::convert_cxx_exceptions(section_getattro, self, pyname);
2038 }
2039 
2040 static int section_setattro(NPySecObj* self, PyObject* pyname, PyObject* value) {
2041  Section* sec = self->sec_;
2042  if (!sec->prop) {
2043  PyErr_SetString(PyExc_ReferenceError, "can't access a deleted section");
2044  return -1;
2045  }
2046  PyObject* rv;
2047  int err = 0;
2048  auto _pyname_tracker = nb::borrow(pyname); // keep refcount+1 during use
2049  auto name = Py2NRNString::as_ascii(pyname);
2050  char* n = name.c_str();
2051  if (!name.is_valid()) {
2052  Py2NRNString::set_pyerr(PyExc_TypeError, "attribute name must be a string");
2053  return -1;
2054  }
2055  // printf("section_setattro %s\n", n);
2056  if (strcmp(n, "L") == 0) {
2057  double x;
2058  if (PyArg_Parse(value, "d", &x) == 1 && x > 0.) {
2059  if (can_change_morph(sec)) {
2060  sec->prop->dparam[2] = x;
2061  nrn_length_change(sec, x);
2062  diam_changed = 1;
2063  sec->recalc_area_ = 1;
2064  }
2065  } else {
2066  PyErr_SetString(PyExc_ValueError, "L must be > 0.");
2067  return -1;
2068  }
2069  } else if (strcmp(n, "Ra") == 0) {
2070  double x;
2071  if (PyArg_Parse(value, "d", &x) == 1 && x > 0.) {
2072  sec->prop->dparam[7] = x;
2073  diam_changed = 1;
2074  sec->recalc_area_ = 1;
2075  } else {
2076  PyErr_SetString(PyExc_ValueError, "Ra must be > 0.");
2077  return -1;
2078  }
2079  } else if (strcmp(n, "nseg") == 0) {
2080  int nseg;
2081  if (PyArg_Parse(value, "i", &nseg) == 1 && nseg > 0 && nseg <= 32767) {
2082  nrn_change_nseg(sec, nseg);
2083  } else {
2084  PyErr_SetString(PyExc_ValueError, "nseg must be an integer in range 1 to 32767");
2085  return -1;
2086  }
2087  // printf("section_setattro err=%d nseg=%d nnode\n", err, nseg,
2088  // sec->nnode);
2089  } else if ((rv = PyDict_GetItemString(rangevars_, n))) {
2090  Symbol* sym = ((NPyRangeVar*) rv)->sym_;
2091  if (is_array(*sym)) {
2092  PyErr_SetString(PyExc_IndexError, "missing index");
2093  return -1;
2094  } else {
2095  int errp;
2096  auto d = nrnpy_rangepointer(sec, sym, 0.5, &errp, 0 /* idx */);
2097  if (d.is_invalid_handle()) {
2098  rv_noexist(sec, n, 0.5, errp);
2099  return -1;
2100  } else if (!d.holds<double*>()) {
2101  PyErr_SetString(PyExc_ValueError, "can't assign value to opaque pointer");
2102  return -1;
2103  } else if (!PyArg_Parse(value, "d", d.get<double*>())) {
2104  PyErr_SetString(PyExc_ValueError, "bad value");
2105  return -1;
2106  } else {
2107  // only need to do following if nseg > 1, VINDEX, or EXTRACELL
2109  }
2110  }
2111  } else if (strcmp(n, "rallbranch") == 0) {
2112  double x;
2113  if (PyArg_Parse(value, "d", &x) == 1 && x > 0.) {
2114  sec->prop->dparam[4] = x;
2115  diam_changed = 1;
2116  sec->recalc_area_ = 1;
2117  } else {
2118  PyErr_SetString(PyExc_ValueError, "rallbranch must be > 0");
2119  return -1;
2120  }
2121  } else {
2122  err = PyObject_GenericSetAttr((PyObject*) self, pyname, value);
2123  }
2124  return err;
2125 }
2126 
2128  return nrn::convert_cxx_exceptions(section_setattro, self, pyname, value);
2129 }
2130 
2132  // printf("mech_of_seg_next\n");
2133  // The return on this iteration is self->pymech_. nullptr means it's over.
2134  NPyMechObj* m = self->pymech_;
2135  if (!m) {
2136  return nullptr;
2137  }
2138  if (!m->prop_id_) {
2139  PyErr_SetString(PyExc_ReferenceError,
2140  "mechanism instance became invalid in middle of the mechanism iterator");
2141  return nullptr;
2142  }
2143  Prop* pnext = mech_of_segment_prop(m->prop_->next);
2144  NPyMechObj* mnext{};
2145  if (pnext) {
2146  mnext = new_pymechobj(m->pyseg_, pnext);
2147  }
2148  self->pymech_ = mnext;
2149  return (PyObject*) m;
2150 }
2151 
2154 }
2155 
2157  Section* sec = self->pyseg_->pysec_->sec_;
2159 
2160  // printf("var_of_mech_iter\n");
2162  if (!self->prop_) {
2163  return nullptr;
2164  }
2165  Py_INCREF(self);
2166  vmi->pymech_ = self;
2167  vmi->msym_ = memb_func[self->prop_->_type].sym;
2168  vmi->i_ = 0;
2169  return (PyObject*) vmi;
2170 }
2171 
2174 }
2175 
2177  if (self->i_ >= self->msym_->s_varn) {
2178  return nullptr;
2179  }
2180  // printf("var_of_mech_next %d %s\n", self->i_, self->msym_->name);
2181  Symbol* sym = self->msym_->u.ppsym[self->i_];
2182  self->i_++;
2183  NPyRangeVar* r = (NPyRangeVar*) PyObject_New(NPyRangeVar, range_type);
2184  Py_INCREF(self->pymech_);
2185  r->pymech_ = self->pymech_;
2186  r->sym_ = sym;
2187  r->isptr_ = 0;
2188  r->attr_from_sec_ = 0;
2189  return (PyObject*) r;
2190 }
2191 
2194 }
2195 
2196 // Returns new reference.
2197 static PyObject* segment_getattro(NPySegObj* self, PyObject* pyname) {
2198  Section* sec = self->pysec_->sec_;
2200 
2201  Symbol* sym;
2202  auto _pyname_tracker = nb::borrow(pyname); // keep refcount+1 during use
2203  auto name = Py2NRNString::as_ascii(pyname);
2204  char* n = name.c_str();
2205  if (!name.is_valid()) {
2206  Py2NRNString::set_pyerr(PyExc_TypeError, "attribute name must be a string");
2207  return nullptr;
2208  }
2209  // printf("segment_getattr %s\n", n);
2210  nb::object result;
2211  PyObject* otype = nullptr;
2212  PyObject* rv = nullptr;
2213  if (strcmp(n, "v") == 0) {
2214  Node* nd = node_exact(sec, self->x_);
2215  result = nb::cast(NODEV(nd));
2216  } else if ((otype = PyDict_GetItemString(pmech_types, n))) {
2217  int type = PyInt_AsLong(otype);
2218  // printf("segment_getattr type=%d\n", type);
2219  Node* nd = node_exact(sec, self->x_);
2220  Prop* p = nrn_mechanism(type, nd);
2221  if (!p) {
2222  rv_noexist(sec, n, self->x_, 1);
2223  return nullptr;
2224  } else {
2225  result = nb::steal((PyObject*) new_pymechobj(self, p));
2226  }
2227  } else if ((rv = PyDict_GetItemString(rangevars_, n))) {
2228  sym = ((NPyRangeVar*) rv)->sym_;
2229  if (sym->type == RANGEOBJ) {
2230  int mtype = sym->u.rng.type;
2231  Node* nd = node_exact(sec, self->x_);
2232  Prop* p = nrn_mechanism(mtype, nd);
2233  Object* ob = nrn_nmodlrandom_wrap(p, sym);
2234  result = nb::steal(nrnpy_ho2po(ob));
2235  } else if (is_array(*sym)) {
2236  result = nb::steal((PyObject*) PyObject_New(NPyRangeVar, range_type));
2237  auto r = (NPyRangeVar*) result.ptr();
2238  r->pymech_ = new_pymechobj();
2239  Py_INCREF(self);
2240  r->pymech_->pyseg_ = self;
2241  r->sym_ = sym;
2242  r->isptr_ = 0;
2243  r->attr_from_sec_ = 0;
2244  } else {
2245  int err;
2246  auto const d = nrnpy_rangepointer(sec, sym, self->x_, &err, 0 /* idx */);
2247  if (d.is_invalid_handle()) {
2248  rv_noexist(sec, n, self->x_, err);
2249  return nullptr;
2250  } else {
2251  if (sec->recalc_area_ && sym->u.rng.type == MORPHOLOGY) {
2252  nrn_area_ri(sec);
2253  }
2254  result = nb::steal(build_python_value(d));
2255  }
2256  }
2257  } else if (strncmp(n, "_ref_", 5) == 0) {
2258  if (strcmp(n + 5, "v") == 0) {
2259  Node* nd = node_exact(sec, self->x_);
2260  result = nb::steal(nrn_hocobj_handle(nd->v_handle()));
2261  } else if ((sym = hoc_table_lookup(n + 5, hoc_built_in_symlist)) != 0 &&
2262  sym->type == RANGEVAR) {
2263  if (is_array(*sym)) {
2264  NPyRangeVar* r = PyObject_New(NPyRangeVar, range_type);
2265  r->pymech_ = new_pymechobj();
2266  Py_INCREF(self);
2267  r->pymech_->pyseg_ = self;
2268  r->sym_ = sym;
2269  r->isptr_ = 1;
2270  r->attr_from_sec_ = 0;
2271  result = nb::steal((PyObject*) r);
2272  } else {
2273  int err;
2274  auto const d = nrnpy_rangepointer(sec, sym, self->x_, &err, 0 /* idx */);
2275  if (d.is_invalid_handle()) {
2276  rv_noexist(sec, n + 5, self->x_, err);
2277  return nullptr;
2278  } else {
2279  if (d.holds<double*>()) {
2280  result = nb::steal(
2282  } else {
2283  result = nb::steal((PyObject*) opaque_pointer_new());
2284  }
2285  }
2286  }
2287  } else {
2288  rv_noexist(sec, n, self->x_, 2);
2289  return nullptr;
2290  }
2291  } else if (strcmp(n, "__dict__") == 0) {
2292  Node* nd = node_exact(sec, self->x_);
2293  nb::dict out_dict{};
2294  out_dict["v"] = nb::none();
2295  out_dict["diam"] = nb::none();
2296  out_dict["cm"] = nb::none();
2297  for (Prop* p = nd->prop; p; p = p->next) {
2298  if (p->_type > CAP && !memb_func[p->_type].is_point) {
2299  char* pn = memb_func[p->_type].sym->name;
2300  out_dict[pn] = nb::none();
2301  }
2302  }
2303  result = out_dict;
2304  } else {
2305  result = nb::steal(PyObject_GenericGetAttr((PyObject*) self, pyname));
2306  }
2307  return result.release().ptr();
2308 }
2309 
2311  return nrn::convert_cxx_exceptions(segment_getattro, self, pyname);
2312 }
2313 
2315  int err = 0;
2316  if (sym->subtype == NRNPOINTER) {
2318  // The challenge is that we need to store a data handle here,
2319  // because POINTER variables are set up before the data are
2320  // permuted, but that handle then gets read as part of the
2321  // translated mechanism code, inside the translated MOD files, where
2322  // we might not otherwise like to pay the extra cost of indirection.
2323  prop->dparam[sym->u.rng.index] = std::move(dh);
2324  } else {
2325  PyErr_SetString(PyExc_ValueError, "must be a hoc pointer");
2326  err = -1;
2327  }
2328  } else {
2329  PyErr_SetString(PyExc_AttributeError,
2330  " For assignment, only POINTER var can have a _ref_ prefix");
2331  err = -1;
2332  }
2333  return err;
2334 }
2335 
2336 static int segment_setattro(NPySegObj* self, PyObject* pyname, PyObject* value) {
2337  Section* sec = self->pysec_->sec_;
2338  if (!sec->prop) {
2339  PyErr_SetString(PyExc_ReferenceError, "nrn.Segment can't access a deleted section");
2340  return -1;
2341  }
2342  PyObject* rv;
2343  Symbol* sym;
2344  int err = 0;
2345  auto _pyname_tracker = nb::borrow(pyname); // keep refcount+1 during use
2346  auto name = Py2NRNString::as_ascii(pyname);
2347  char* n = name.c_str();
2348  if (!name.is_valid()) {
2349  Py2NRNString::set_pyerr(PyExc_TypeError, "attribute name must be a string");
2350  return -1;
2351  }
2352  // printf("segment_setattro %s\n", n);
2353  if (strcmp(n, "x") == 0) {
2354  double x;
2355  if (PyArg_Parse(value, "d", &x) == 1 && x > 0. && x <= 1.) {
2356  if (x < 1e-9) {
2357  self->x_ = 0.;
2358  } else if (x > 1. - 1e-9) {
2359  self->x_ = 1.;
2360  } else {
2361  self->x_ = x;
2362  }
2363  } else {
2364  PyErr_SetString(PyExc_ValueError, "x must be in range 0. to 1.");
2365  return -1;
2366  }
2367  } else if ((rv = PyDict_GetItemString(rangevars_, n))) {
2368  sym = ((NPyRangeVar*) rv)->sym_;
2369  if (is_array(*sym)) {
2370  PyErr_Format(PyExc_IndexError, "%s needs an index for assignment", sym->name);
2371  return -1;
2372  } else {
2373  int errp;
2374  auto d = nrnpy_rangepointer(sec, sym, self->x_, &errp, 0 /* idx */);
2375  if (d.is_invalid_handle()) {
2376  rv_noexist(sec, n, self->x_, errp);
2377  return -1;
2378  }
2379  if (d.holds<double*>()) {
2380  if (!PyArg_Parse(value, "d", d.get<double*>())) {
2381  PyErr_SetString(PyExc_ValueError, "bad value");
2382  return -1;
2383  } else if (sym->u.rng.type == MORPHOLOGY) {
2384  diam_changed = 1;
2385  sec->recalc_area_ = 1;
2387  } else if (sym->u.rng.type == EXTRACELL && sym->u.rng.index == 0) {
2388  // cannot execute because xraxial is an array
2389  diam_changed = 1;
2390  }
2391  } else {
2392  PyErr_SetString(PyExc_ValueError, "can't assign value to opaque pointer");
2393  return -1;
2394  }
2395  }
2396  } else if (strncmp(n, "_ref_", 5) == 0) {
2398  if (rvsym && rvsym->type == RANGEVAR) {
2399  Node* nd = node_exact(sec, self->x_);
2400  assert(nd);
2401  Prop* prop = nrn_mechanism(rvsym->u.rng.type, nd);
2402  assert(prop);
2403  err = nrn_pointer_assign(prop, rvsym, value);
2404  } else {
2405  err = PyObject_GenericSetAttr((PyObject*) self, pyname, value);
2406  }
2407  } else {
2408  err = PyObject_GenericSetAttr((PyObject*) self, pyname, value);
2409  }
2410  return err;
2411 }
2412 
2414  return nrn::convert_cxx_exceptions(segment_setattro, self, pyname, value);
2415 }
2416 
2417 static bool striptrail(char* buf, int sz, const char* n, const char* m) {
2418  int nlen = strlen(n);
2419  int mlen = strlen(m);
2420  int u = nlen - mlen - 1; // should be location of _
2421  if (u > 0 && n[u] == '_') { // likely n is name_m
2422  if (strcmp(n + (u + 1), m) != 0) {
2423  return false;
2424  }
2425  strncpy(buf, n, sz);
2426  buf[u] = '\0';
2427  return true;
2428  }
2429  return false;
2430 }
2431 
2432 static Symbol* var_find_in_mech(Symbol* mech, const char* varname) {
2433  int cnt = mech->s_varn;
2434  for (int i = 0; i < cnt; ++i) {
2435  Symbol* sym = mech->u.ppsym[i];
2436  if (strcmp(sym->name, varname) == 0) {
2437  return sym;
2438  }
2439  }
2440  return nullptr;
2441 }
2442 
2444  Symbol* symvar,
2445  int index) {
2446  if (pymech->prop_->ob) { // HocMech created by make_mechanism
2447  Object* ob = pymech->prop_->ob;
2448  // strip suffix
2449  std::string s = symvar->name;
2450  std::string suffix{"_"};
2451  suffix += memb_func[pymech->type_].sym->name;
2452  s.resize(s.rfind(suffix));
2453 
2454  Symbol* sym = hoc_table_lookup(s.c_str(), ob->ctemplate->symtable);
2455  assert(sym);
2456  double* pd = ob->u.dataspace[sym->u.rng.index].pval + index;
2458  }
2459  int sym_index = symvar->u.rng.index;
2460  auto dh = pymech->prop_->param_handle_legacy(sym_index + index);
2461  return dh;
2462 }
2463 
2465  Symbol* symvar,
2466  int index) {
2467  if (pymech->prop_->ob) {
2468  // HocMech created by make_mechanism. It isn't obvious where HOC mechs
2469  // would store dparams.
2470  throw std::runtime_error("Not implemented.");
2471  }
2472 
2473  int sym_index = symvar->u.rng.index;
2474  return pymech->prop_->dparam[sym_index + index];
2475 }
2476 
2478  Symbol* symvar,
2479  int index) {
2480  if (symvar->subtype == NRNPOINTER) {
2481  return var_dparam(pymech, symvar, index);
2482  } else {
2483  return var_pval(pymech, symvar, index);
2484  }
2485 }
2486 
2487 
2488 // Returns a new reference.
2489 static PyObject* mech_getattro(NPyMechObj* self, PyObject* pyname) {
2490  Section* sec = self->pyseg_->pysec_->sec_;
2492  CHECK_PROP_INVALID(self->prop_id_);
2493  auto _pyname_tracker = nb::borrow(pyname); // keep refcount+1 during use
2494  auto name = Py2NRNString::as_ascii(pyname);
2495  char* n = name.c_str();
2496  if (!n) {
2497  Py2NRNString::set_pyerr(PyExc_TypeError, "attribute name must be a string");
2498  return nullptr;
2499  }
2500  // printf("mech_getattro %s\n", n);
2501  nb::object result;
2502  int isptr = (strncmp(n, "_ref_", 5) == 0);
2503  Symbol* mechsym = memb_func[self->type_].sym;
2504  char* mname = mechsym->name;
2505  int mnamelen = strlen(mname);
2506  int bufsz = strlen(n) + mnamelen + 2;
2507  std::vector<char> buf(bufsz);
2508  if (nrn_is_ion(self->prop_->_type)) {
2509  strcpy(buf.data(), isptr ? n + 5 : n);
2510  } else {
2511  std::snprintf(buf.data(), bufsz, "%s_%s", isptr ? n + 5 : n, mname);
2512  }
2513  Symbol* sym = var_find_in_mech(mechsym, buf.data());
2514  if (sym && sym->type == RANGEVAR) {
2515  // printf("mech_getattro sym %s\n", sym->name);
2516  if (is_array(*sym)) {
2517  result = nb::steal((PyObject*) PyObject_New(NPyRangeVar, range_type));
2518  NPyRangeVar* r = (NPyRangeVar*) result.ptr();
2519  Py_INCREF(self);
2520  r->pymech_ = self;
2521  r->sym_ = sym;
2522  r->isptr_ = isptr;
2523  r->attr_from_sec_ = 0;
2524  } else {
2525  auto const px = get_rangevar(self, sym, 0);
2526  if (px.is_invalid_handle()) {
2527  rv_noexist(sec, sym->name, self->pyseg_->x_, 2);
2528  result = nb::object();
2529  } else if (isptr) {
2530  result = nb::steal(build_python_reference(px));
2531  } else {
2532  result = nb::steal(build_python_value(px));
2533  }
2534  }
2535  } else if (sym && sym->type == RANGEOBJ) {
2536  Object* ob = nrn_nmodlrandom_wrap(self->prop_, sym);
2537  result = nb::steal(nrnpy_ho2po(ob));
2538  } else if (strcmp(n, "__dict__") == 0) {
2539  nb::dict out_dict{};
2540  int cnt = mechsym->s_varn;
2541  for (int i = 0; i < cnt; ++i) {
2542  Symbol* s = mechsym->u.ppsym[i];
2543  if (!striptrail(buf.data(), bufsz, s->name, mname)) {
2544  strcpy(buf.data(), s->name);
2545  }
2546  out_dict[buf.data()] = nb::none();
2547  }
2548  // FUNCTION and PROCEDURE
2549  for (auto& it: nrn_mech2funcs_map[self->prop_->_type]) {
2550  out_dict[it.first.c_str()] = nb::none();
2551  }
2552  result = out_dict;
2553  } else {
2554  bool found_func{false};
2555  if (self->prop_) {
2556  auto& funcs = nrn_mech2funcs_map[self->prop_->_type];
2557  if (funcs.count(n)) {
2558  found_func = true;
2559  auto& f = funcs[n];
2560  result = nb::steal((PyObject*) PyObject_New(NPyMechFunc, pmechfunc_generic_type));
2561  auto pymf = (NPyMechFunc*) result.ptr();
2562  Py_INCREF(self);
2563  pymf->pymech_ = self;
2564  pymf->f_ = f;
2565  }
2566  }
2567  if (!found_func) {
2568  result = nb::steal(PyObject_GenericGetAttr((PyObject*) self, pyname));
2569  }
2570  }
2571  return result.release().ptr();
2572 }
2573 
2575  return nrn::convert_cxx_exceptions(mech_getattro, self, pyname);
2576 }
2577 
2578 static int mech_setattro(NPyMechObj* self, PyObject* pyname, PyObject* value) {
2579  Section* sec = self->pyseg_->pysec_->sec_;
2580  if (!sec->prop) {
2581  PyErr_SetString(PyExc_ReferenceError, "nrn.Mechanism can't access a deleted section");
2582  return -1;
2583  }
2584 
2585  int err = 0;
2586  auto _pyname_tracker = nb::borrow(pyname); // keep refcount+1 during use
2587  auto name = Py2NRNString::as_ascii(pyname);
2588  char* n = name.c_str();
2589  if (!name.is_valid()) {
2590  Py2NRNString::set_pyerr(PyExc_TypeError, "attribute name must be a string");
2591  return -1;
2592  }
2593  // printf("mech_setattro %s\n", n);
2594  int isptr = (strncmp(n, "_ref_", 5) == 0);
2595  Symbol* mechsym = memb_func[self->type_].sym;
2596  char* mname = mechsym->name;
2597  int mnamelen = strlen(mname);
2598  int bufsz = strlen(n) + mnamelen + 2;
2599  std::vector<char> buf(bufsz);
2600  if (nrn_is_ion(self->prop_->_type)) {
2601  strcpy(buf.data(), isptr ? n + 5 : n);
2602  } else {
2603  std::snprintf(buf.data(), bufsz, "%s_%s", isptr ? n + 5 : n, mname);
2604  }
2605  Symbol* sym = var_find_in_mech(mechsym, buf.data());
2606  if (sym) {
2607  if (isptr) {
2608  err = nrn_pointer_assign(self->prop_, sym, value);
2609  } else {
2610  auto pd = get_rangevar(self, sym, 0);
2611  if (pd.is_invalid_handle()) {
2612  rv_noexist(sec, sym->name, self->pyseg_->x_, 2);
2613  return -1;
2614  } else if (!pd.holds<double*>()) {
2615  PyErr_SetString(PyExc_ValueError, "can't assign value to opaque pointer");
2616  return -1;
2617  } else if (!PyArg_Parse(value, "d", pd.get<double*>())) {
2618  PyErr_SetString(PyExc_ValueError, "must be a double");
2619  return -1;
2620  }
2621  }
2622  } else {
2623  err = PyObject_GenericSetAttr((PyObject*) self, pyname, value);
2624  }
2625  return err;
2626 }
2627 
2628 static int mech_setattro_safe(NPyMechObj* self, PyObject* pyname, PyObject* value) {
2629  return nrn::convert_cxx_exceptions(mech_setattro, self, pyname, value);
2630 }
2631 
2633  if (PyObject_TypeCheck(mech, pmech_generic_type) == 0) {
2634  return nullptr;
2635  }
2636  NPyMechObj* m = (NPyMechObj*) mech;
2637  Symbol* msym = memb_func[m->type_].sym;
2638  char buf[200];
2639  auto name = Py2NRNString::as_ascii(pyname);
2640  char* n = name.c_str();
2641  if (!n) {
2642  return nullptr;
2643  }
2644  Sprintf(buf, "%s_%s", n, msym->name);
2645  Symbol* sym = var_find_in_mech(msym, buf);
2646  if (!sym || sym->type != RANGEVAR || sym->subtype != NRNPOINTER) {
2647  return nullptr;
2648  }
2649  return &(m->prop_->dparam[sym->u.rng.index]);
2650 }
2651 
2653  CHECK_SEC_INVALID(self->sec_);
2654  double x = 0.5;
2655  PyArg_ParseTuple(args, "|d", &x);
2656  auto segargs = nb::steal(Py_BuildValue("(O,d)", self, x));
2657  return NPySegObj_new(psegment_type, segargs.ptr(), nullptr);
2658 }
2659 
2661  return nrn::convert_cxx_exceptions(NPySecObj_call, self, args);
2662 }
2663 
2664 static Py_ssize_t rv_len(PyObject* self) {
2665  NPyRangeVar* r = (NPyRangeVar*) self;
2666  assert(r->sym_);
2667  if (r->sym_->arayinfo) {
2668  assert(r->sym_->arayinfo->nsub == 1);
2669  return r->sym_->arayinfo->sub[0];
2670  }
2671  return 1;
2672 }
2673 
2674 static Py_ssize_t rv_len_safe(PyObject* self) {
2675  return nrn::convert_cxx_exceptions(rv_len, self);
2676 }
2677 
2678 // Returns a new reference.
2679 static PyObject* rv_getitem(PyObject* self, Py_ssize_t ix) {
2680  NPyRangeVar* r = (NPyRangeVar*) self;
2681  Section* sec = r->pymech_->pyseg_->pysec_->sec_;
2683 
2684  if (ix < 0 || ix >= rv_len(self)) {
2685  PyErr_SetString(PyExc_IndexError, r->sym_->name);
2686  return nullptr;
2687  }
2688  if (is_array(*r->sym_)) {
2689  assert(r->sym_->arayinfo->nsub == 1);
2690  auto const array_dim = r->sym_->arayinfo->sub[0];
2691  assert(ix < array_dim);
2692  // r represents a range variable that is an array of size array_dim, and
2693  // we need to apply the offset `ix` to get the correct element of that
2694  // array.
2695  } else {
2696  // Not an array variable, so the index should always be zero
2697  assert(ix == 0);
2698  }
2699  int err;
2700  auto const d = nrnpy_rangepointer(sec, r->sym_, r->pymech_->pyseg_->x_, &err, ix);
2701  if (d.is_invalid_handle()) {
2702  rv_noexist(sec, r->sym_->name, r->pymech_->pyseg_->x_, err);
2703  return nullptr;
2704  }
2705  if (r->isptr_) {
2707  } else {
2708  return build_python_value(d);
2709  }
2710 }
2711 
2712 static PyObject* rv_getitem_safe(PyObject* self, Py_ssize_t ix) {
2713  return nrn::convert_cxx_exceptions(rv_getitem, self, ix);
2714 }
2715 
2716 static int rv_setitem(PyObject* self, Py_ssize_t ix, PyObject* value) {
2717  NPyRangeVar* r = (NPyRangeVar*) self;
2718  Section* sec = r->pymech_->pyseg_->pysec_->sec_;
2719  if (!sec->prop) {
2720  PyErr_SetString(PyExc_ReferenceError, "nrn.RangeVar can't access a deleted section");
2721  return -1;
2722  }
2723 
2724  if (ix < 0 || ix >= rv_len(self)) {
2725  PyErr_SetString(PyExc_IndexError, r->sym_->name);
2726  return -1;
2727  }
2728  int err;
2729  auto d = nrnpy_rangepointer(sec, r->sym_, r->pymech_->pyseg_->x_, &err, ix);
2730  if (d.is_invalid_handle()) {
2731  rv_noexist(sec, r->sym_->name, r->pymech_->pyseg_->x_, err);
2732  return -1;
2733  }
2734  if (r->attr_from_sec_) {
2735  // the range variable array is from a section not a segment and so
2736  // assignment is over the entire section.
2737  double x;
2738  if (!PyArg_Parse(value, "d", &x)) {
2739  PyErr_SetString(PyExc_ValueError, "bad value");
2740  return -1;
2741  }
2742  hoc_pushx(double(ix));
2743  hoc_push_ndim(1);
2745  r->sym_,
2746  neuron::container::data_handle<double>{neuron::container::do_not_search, &x},
2747  0);
2748  } else {
2749  if (d.holds<double*>()) {
2750  if (!PyArg_Parse(value, "d", d.get<double*>())) {
2751  PyErr_SetString(PyExc_ValueError, "bad value");
2752  return -1;
2753  }
2754  } else {
2755  PyErr_SetString(PyExc_ValueError, "can't assign value to opaque pointer");
2756  return -1;
2757  }
2758  }
2759  if (r->sym_->u.rng.type == EXTRACELL && r->sym_->u.rng.index == 0) {
2760  diam_changed = 1;
2761  }
2762  return 0;
2763 }
2764 
2765 static int rv_setitem_safe(PyObject* self, Py_ssize_t ix, PyObject* value) {
2766  return nrn::convert_cxx_exceptions(rv_setitem, self, ix, value);
2767 }
2768 
2769 static PyMethodDef NPySecObj_methods[] = {
2770  {"name",
2771  (PyCFunction) NPySecObj_name_safe,
2772  METH_NOARGS,
2773  "Section name (same as hoc secname())"},
2774  {"hname",
2775  (PyCFunction) NPySecObj_name_safe,
2776  METH_NOARGS,
2777  "Section name (same as hoc secname())"},
2778  {"has_membrane",
2779  (PyCFunction) NPySecObj_has_membrane_safe,
2780  METH_VARARGS,
2781  "Returns True if the section's membrane has this density mechanism.\nThis "
2782  "is not for point processes."},
2783  {"connect",
2784  (PyCFunction) NPySecObj_connect_safe,
2785  METH_VARARGS,
2786  "childSection.connect(parentSection, [parentX], [childEnd]) "
2787  "or\nchildSection.connect(parentSegment, [childEnd])"},
2788  {"insert",
2789  (PyCFunction) NPySecObj_insert_safe,
2790  METH_VARARGS,
2791  "section.insert(densityMechanismName) e.g. soma.insert('hh')"},
2792  {"uninsert",
2793  (PyCFunction) NPySecObj_uninsert_safe,
2794  METH_VARARGS,
2795  "section.uninsert(densityMechanismName) e.g. soma.insert('hh')"},
2796  {"push",
2797  (PyCFunction) NPySecObj_push_safe,
2798  METH_VARARGS,
2799  "section.push() makes it the currently accessed section. Should end with "
2800  "a corresponding hoc.pop_section()"},
2801  {"allseg",
2802  (PyCFunction) allseg_safe,
2803  METH_VARARGS,
2804  "iterate over segments. Includes x=0 and x=1 zero-area nodes in the "
2805  "iteration."},
2806  {"cell",
2807  (PyCFunction) pysec2cell_safe,
2808  METH_NOARGS,
2809  "Return the object that owns the Section. Possibly None."},
2810  {"same",
2811  (PyCFunction) pysec_same_safe,
2812  METH_VARARGS,
2813  "sec1.same(sec2) returns True if sec1 and sec2 wrap the same NEURON "
2814  "Section"},
2815  {"hoc_internal_name",
2816  (PyCFunction) hoc_internal_name_safe,
2817  METH_NOARGS,
2818  "Hoc accepts this name wherever a section is syntactically valid."},
2819  {"disconnect",
2820  (PyCFunction) pysec_disconnect_safe,
2821  METH_NOARGS,
2822  "disconnect from the parent section."},
2823  {"parentseg",
2824  (PyCFunction) pysec_parentseg_safe,
2825  METH_NOARGS,
2826  "Return the nrn.Segment specified by the connect method. Possibly None."},
2827  {"trueparentseg",
2828  (PyCFunction) pysec_trueparentseg_safe,
2829  METH_NOARGS,
2830  "Return the nrn.Segment this section connects to which is closer to the "
2831  "root. Possibly None. (same as parentseg unless parentseg.x == "
2832  "parentseg.sec.orientation()"},
2833  {"orientation",
2834  (PyCFunction) pysec_orientation_safe,
2835  METH_NOARGS,
2836  "Returns 0.0 or 1.0 depending on the x value closest to parent."},
2837  {"children",
2838  (PyCFunction) pysec_children_safe,
2839  METH_NOARGS,
2840  "Return list of child sections. Possibly an empty list"},
2841  {"subtree",
2842  (PyCFunction) pysec_subtree_safe,
2843  METH_NOARGS,
2844  "Return list of sections in the subtree rooted at this section (including this section)."},
2845  {"wholetree",
2846  (PyCFunction) pysec_wholetree_safe,
2847  METH_NOARGS,
2848  "Return list of all sections with a path to this section (including this section). The list "
2849  "has the important property that sections are in root to leaf order, depth-first traversal."},
2850  {"n3d", (PyCFunction) NPySecObj_n3d_safe, METH_NOARGS, "Returns the number of 3D points."},
2851  {"x3d",
2852  (PyCFunction) NPySecObj_x3d_safe,
2853  METH_VARARGS,
2854  "Returns the x coordinate of the ith 3D point."},
2855  {"y3d",
2856  (PyCFunction) NPySecObj_y3d_safe,
2857  METH_VARARGS,
2858  "Returns the y coordinate of the ith 3D point."},
2859  {"z3d",
2860  (PyCFunction) NPySecObj_z3d_safe,
2861  METH_VARARGS,
2862  "Returns the z coordinate of the ith 3D point."},
2863  {"arc3d",
2864  (PyCFunction) NPySecObj_arc3d_safe,
2865  METH_VARARGS,
2866  "Returns the arc position of the ith 3D point."},
2867  {"diam3d",
2868  (PyCFunction) NPySecObj_diam3d_safe,
2869  METH_VARARGS,
2870  "Returns the diam of the ith 3D point."},
2871  {"spine3d",
2872  (PyCFunction) NPySecObj_spine3d_safe,
2873  METH_VARARGS,
2874  "Returns True or False depending on whether a spine exists at the ith 3D point."},
2875  {"pt3dremove", (PyCFunction) NPySecObj_pt3dremove, METH_VARARGS, "Removes the ith 3D point."},
2876  {"pt3dclear",
2877  (PyCFunction) NPySecObj_pt3dclear_safe,
2878  METH_VARARGS,
2879  "Clears all 3D points. Optionally takes a buffer size."},
2880  {"pt3dinsert",
2881  (PyCFunction) NPySecObj_pt3dinsert_safe,
2882  METH_VARARGS,
2883  "Insert the point (so it becomes the i'th point) to section. If i is equal to sec.n3d(), the "
2884  "point is appended (equivalent to sec.pt3dadd())"},
2885  {"pt3dchange",
2886  (PyCFunction) NPySecObj_pt3dchange_safe,
2887  METH_VARARGS,
2888  "Change the i'th 3-d point info. If only two args then the second arg is the diameter and the "
2889  "location is unchanged."},
2890  {"pt3dadd",
2891  (PyCFunction) NPySecObj_pt3dadd_safe,
2892  METH_VARARGS,
2893  "Add the 3d location and diameter point (or points in the second form) at the end of the "
2894  "current pt3d list. Assume that successive additions increase the arc length monotonically."},
2895  {"pt3dstyle",
2896  (PyCFunction) NPySecObj_pt3dstyle_safe,
2897  METH_VARARGS,
2898  "Returns True if using a logical connection point, else False. With first arg 0 sets to no "
2899  "logical connection point. With first arg 1 and x, y, z arguments, sets the logical "
2900  "connection point. Return value includes the result of any setting."},
2901  {"is_pysec",
2902  (PyCFunction) is_pysec_safe,
2903  METH_NOARGS,
2904  "Returns True if Section created from Python, False if created from HOC."},
2905  {"psection",
2906  (PyCFunction) NPySecObj_psection_safe,
2907  METH_NOARGS,
2908  "Returns dict of info about Section contents."},
2909  {NULL}};
2910 
2911 static PyMethodDef NPySegObj_methods[] = {
2912  {"point_processes",
2913  (PyCFunction) seg_point_processes_safe,
2914  METH_NOARGS,
2915  "seg.point_processes() returns list of POINT_PROCESS instances in the "
2916  "segment."},
2917  {"node_index",
2918  (PyCFunction) node_index1_safe,
2919  METH_NOARGS,
2920  "seg.node_index() returns index of v, rhs, etc. in the _actual arrays of "
2921  "the appropriate NrnThread."},
2922  {"area",
2923  (PyCFunction) seg_area_safe,
2924  METH_NOARGS,
2925  "Segment area (um2) (same as h.area(sec(x), sec=sec))"},
2926  {"ri",
2927  (PyCFunction) seg_ri_safe,
2928  METH_NOARGS,
2929  "Segment resistance to parent segment (Megohms) (same as h.ri(sec(x), "
2930  "sec=sec))"},
2931  {"volume", (PyCFunction) seg_volume_safe, METH_NOARGS, "Segment volume (um3)"},
2932  {NULL}};
2933 
2934 static PyMemberDef NPySegObj_members[] = {
2935  {"x", T_DOUBLE, offsetof(NPySegObj, x_), 0, "location in the section (segment containing x)"},
2936  {"sec", T_OBJECT_EX, offsetof(NPySegObj, pysec_), 0, "Section"},
2937  {NULL}};
2938 
2939 static PyMethodDef NPyMechObj_methods[] = {
2940  {"name",
2941  (PyCFunction) NPyMechObj_name_safe,
2942  METH_NOARGS,
2943  "Mechanism name (same as hoc suffix for density mechanism)"},
2944  {"is_ion",
2945  (PyCFunction) NPyMechObj_is_ion_safe,
2946  METH_NOARGS,
2947  "Returns True if an ion mechanism"},
2948  {"segment",
2949  (PyCFunction) NPyMechObj_segment_safe,
2950  METH_NOARGS,
2951  "Returns the segment of the Mechanism instance"},
2952  {NULL}};
2953 
2954 static PyMethodDef NPyMechFunc_methods[] = {
2955  {"name", (PyCFunction) NPyMechFunc_name_safe, METH_NOARGS, "Mechanism function"},
2956  {"mech",
2957  (PyCFunction) NPyMechFunc_mech_safe,
2958  METH_NOARGS,
2959  "Returns the Mechanism for this instance"},
2960  {NULL}};
2961 
2962 static PyMethodDef NPyRangeVar_methods[] = {
2963  {"name", (PyCFunction) NPyRangeVar_name_safe, METH_NOARGS, "Range variable name name"},
2964  {"mech",
2965  (PyCFunction) NPyRangeVar_mech_safe,
2966  METH_NOARGS,
2967  "Returns nrn.Mechanism of the RangeVariable instance"},
2968  {NULL}};
2969 
2970 static PyMemberDef NPyMechObj_members[] = {{NULL}};
2971 
2972 // Returns a new reference.
2975  if (!sec) {
2976  PyErr_SetString(PyExc_TypeError, "Section access unspecified");
2977  return nullptr;
2978  }
2979  // printf("nrnpy_cas %s\n", secname(sec));
2980  return (PyObject*) newpysechelp(sec);
2981 }
2982 
2984  return nrn::convert_cxx_exceptions(nrnpy_cas, self, args);
2985 }
2986 
2987 static PyMethodDef nrnpy_methods[] = {
2988  {"cas", nrnpy_cas_safe, METH_VARARGS, "Return the currently accessed section."},
2989  {"allsec", nrnpy_forall_safe, METH_VARARGS, "Return iterator over all sections."},
2990  {"set_psection",
2992  METH_VARARGS,
2993  "Specify the nrn.Section.psection callback."},
2994  {NULL}};
2995 
2996 #include "nrnpy_nrn.h"
2997 
2999 
3000 static void rangevars_add(Symbol* sym) {
3001  assert(sym && (sym->type == RANGEVAR || sym->type == RANGEOBJ));
3002  NPyRangeVar* r = PyObject_New(NPyRangeVar, range_type);
3003  // printf("%s\n", sym->name);
3004  r->sym_ = sym;
3005  r->isptr_ = 0;
3006  r->attr_from_sec_ = 0;
3007  PyDict_SetItemString(rangevars_, sym->name, (PyObject*) r);
3008 }
3009 
3010 // Returns a borrowed reference.
3012  nb::object m;
3013 
3014  int err = 0;
3015  PyObject* modules = PyImport_GetModuleDict();
3016  if ((m = nb::borrow(PyDict_GetItemString(modules, "nrn"))) && PyModule_Check(m.ptr())) {
3017  return m.ptr();
3018  }
3019  psection_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_SectionType_spec);
3020  psection_type->tp_new = PyType_GenericNew;
3021  if (PyType_Ready(psection_type) < 0)
3022  goto fail;
3023  Py_INCREF(psection_type);
3024 
3025  pallseg_of_sec_iter_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_AllSegOfSecIterType_spec);
3026  pseg_of_sec_iter_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_SegOfSecIterType_spec);
3027  pallseg_of_sec_iter_type->tp_new = PyType_GenericNew;
3028  pseg_of_sec_iter_type->tp_new = PyType_GenericNew;
3029  if (PyType_Ready(pallseg_of_sec_iter_type) < 0)
3030  goto fail;
3031  if (PyType_Ready(pseg_of_sec_iter_type) < 0)
3032  goto fail;
3033  Py_INCREF(pallseg_of_sec_iter_type);
3034  Py_INCREF(pseg_of_sec_iter_type);
3035 
3036  psegment_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_SegmentType_spec);
3037  psegment_type->tp_new = PyType_GenericNew;
3038  if (PyType_Ready(psegment_type) < 0)
3039  goto fail;
3040  if (PyType_Ready(pallseg_of_sec_iter_type) < 0)
3041  goto fail;
3042  if (PyType_Ready(pseg_of_sec_iter_type) < 0)
3043  goto fail;
3044  Py_INCREF(psegment_type);
3045  Py_INCREF(pallseg_of_sec_iter_type);
3046  Py_INCREF(pseg_of_sec_iter_type);
3047 
3048  range_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_RangeType_spec);
3049  range_type->tp_new = PyType_GenericNew;
3050  if (PyType_Ready(range_type) < 0)
3051  goto fail;
3052  Py_INCREF(range_type);
3053 
3054  opaque_pointer_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_OpaquePointerType_spec);
3055  opaque_pointer_type->tp_new = PyType_GenericNew;
3056  if (PyType_Ready(opaque_pointer_type) < 0)
3057  goto fail;
3058  Py_INCREF(opaque_pointer_type);
3059 
3060  m = nb::steal(PyModule_Create(&nrnsectionmodule)); // like nrn but namespace will not include
3061  // mechanims.
3062  PyModule_AddObject(m.ptr(), "Section", (PyObject*) psection_type);
3063  PyModule_AddObject(m.ptr(), "Segment", (PyObject*) psegment_type);
3064 
3065  err = PyDict_SetItemString(modules, "_neuron_section", m.ptr());
3066  assert(err == 0);
3067  m = nb::steal(PyModule_Create(&nrnmodule)); //
3068  nrnmodule_ = m.ptr();
3069  PyModule_AddObject(m.ptr(), "Section", (PyObject*) psection_type);
3070  PyModule_AddObject(m.ptr(), "Segment", (PyObject*) psegment_type);
3071  PyModule_AddObject(m.ptr(), "OpaquePointer", (PyObject*) opaque_pointer_type);
3072 
3073  pmech_generic_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_MechanismType_spec);
3074  pmechfunc_generic_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_MechFuncType_spec);
3075  pmech_of_seg_iter_generic_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_MechOfSegIterType_spec);
3076  pvar_of_mech_iter_generic_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_VarOfMechIterType_spec);
3077  pmech_generic_type->tp_new = PyType_GenericNew;
3078  pmechfunc_generic_type->tp_new = PyType_GenericNew;
3079  pmech_of_seg_iter_generic_type->tp_new = PyType_GenericNew;
3080  pvar_of_mech_iter_generic_type->tp_new = PyType_GenericNew;
3081  if (PyType_Ready(pmech_generic_type) < 0)
3082  goto fail;
3083  if (PyType_Ready(pmechfunc_generic_type) < 0)
3084  goto fail;
3085  if (PyType_Ready(pmech_of_seg_iter_generic_type) < 0)
3086  goto fail;
3087  if (PyType_Ready(pvar_of_mech_iter_generic_type) < 0)
3088  goto fail;
3089  Py_INCREF(pmech_generic_type);
3090  Py_INCREF(pmechfunc_generic_type);
3091  Py_INCREF(pmech_of_seg_iter_generic_type);
3092  Py_INCREF(pvar_of_mech_iter_generic_type);
3093  PyModule_AddObject(m.ptr(), "Mechanism", (PyObject*) pmech_generic_type);
3094  PyModule_AddObject(m.ptr(), "MechFunc", (PyObject*) pmechfunc_generic_type);
3095  PyModule_AddObject(m.ptr(), "MechOfSegIterator", (PyObject*) pmech_of_seg_iter_generic_type);
3096  PyModule_AddObject(m.ptr(), "VarOfMechIterator", (PyObject*) pvar_of_mech_iter_generic_type);
3107 
3108  err = PyDict_SetItemString(modules, "nrn", m.ptr());
3109  assert(err == 0);
3110  return m.ptr();
3111 fail:
3112  return NULL;
3113 }
3114 
3116  int i;
3117  Py_XDECREF(pmech_types);
3118  Py_XDECREF(rangevars_);
3119  pmech_types = PyDict_New();
3120  rangevars_ = PyDict_New();
3126  for (i = 4; i < n_memb_func; ++i) { // start at pas
3127  nrnpy_reg_mech(i);
3128  }
3129 }
3130 
3132  int i;
3133  char* s;
3134  Memb_func& mf = memb_func[type];
3135  if (!nrnmodule_) {
3136  return;
3137  }
3138  if (mf.is_point) {
3139  if (nrn_is_artificial_[type] == 0) {
3141  Symbol* s = hoc_table_lookup("get_segment", sl);
3142  if (!s) {
3143  s = hoc_install("get_segment", OBFUNCTION, 0, &sl);
3144  s->cpublic = 1;
3145  s->u.u_proc->defn.pfo = (Object * *(*) ()) pp_get_segment;
3146  }
3147  }
3148  return;
3149  }
3150  s = mf.sym->name;
3151  // printf("nrnpy_reg_mech %s %d\n", s, type);
3152  if (PyDict_GetItemString(pmech_types, s)) {
3153  hoc_execerror(s, "mechanism already exists");
3154  }
3155  Py_INCREF(pmech_generic_type);
3156  PyModule_AddObject(nrnmodule_, s, (PyObject*) pmech_generic_type);
3157  PyDict_SetItemString(pmech_types, s, Py_BuildValue("i", type));
3158  for (i = 0; i < mf.sym->s_varn; ++i) {
3159  Symbol* sym = mf.sym->u.ppsym[i];
3160  rangevars_add(sym);
3161  }
3162 }
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:830
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)
Type-safe sprintf replacement using snprintf with automatic buffer size deduction.
Definition: wrap_sprintf.h:28
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:3316
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:26
_object PyObject
Definition: nrnpy.h:12
int nrn_is_hocobj_ptr(PyObject *po, neuron::container::data_handle< double > &pd)
Definition: nrnpy_hoc.cpp:976
PyObject * nrn_hocobj_handle(neuron::container::data_handle< double > d)
Definition: nrnpy_hoc.cpp:963
Object * nrnpy_po2ho(PyObject *po)
Definition: nrnpy_hoc.cpp:598
PyObject * nrnpy_ho2po(Object *o)
Definition: nrnpy_hoc.cpp:572
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:2973
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:2954
static PyObject * nrnmodule_
Definition: nrnpy_nrn.cpp:2998
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:2176
static neuron::container::data_handle< double > var_pval(NPyMechObj *pymech, Symbol *symvar, int index)
Definition: nrnpy_nrn.cpp:2443
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:2432
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:2911
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:1908
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:2628
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:2765
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:1968
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:2712
static PyObject * section_getattro(NPySecObj *self, PyObject *pyname)
Definition: nrnpy_nrn.cpp:1985
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:1758
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:2664
static PyObject * segment_getattro_safe(NPySegObj *self, PyObject *pyname)
Definition: nrnpy_nrn.cpp:2310
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:1904
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:2040
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:2336
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:2417
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:3115
static PyObject * rv_getitem(PyObject *self, Py_ssize_t ix)
Definition: nrnpy_nrn.cpp:2679
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:2970
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:2632
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:1916
static Prop * mech_of_segment_prop(Prop *p)
Definition: nrnpy_nrn.cpp:1863
static PyMethodDef NPyMechObj_methods[]
Definition: nrnpy_nrn.cpp:2939
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:1946
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:2197
static PyObject * NPySecObj_call(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:2652
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:2464
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:2314
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:2769
static PyObject * NPySecObj_has_membrane(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1581
PyObject * nrnpy_nrn(void)
Definition: nrnpy_nrn.cpp:3011
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:2674
static PyObject * var_of_mech_next_safe(NPyVarOfMechIter *self)
Definition: nrnpy_nrn.cpp:2192
static void NPyAllSegOfSecIter_dealloc(NPyAllSegOfSecIter *self)
Definition: nrnpy_nrn.cpp:282
static PyObject * mech_of_seg_next_safe(NPyMechOfSegIter *self)
Definition: nrnpy_nrn.cpp:2152
static PyObject * NPySecObj_psection(NPySecObj *self)
Definition: nrnpy_nrn.cpp:1019
static PyMemberDef NPySegObj_members[]
Definition: nrnpy_nrn.cpp:2934
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:2660
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:1977
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:2477
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:2578
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:2036
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:2716
static void rv_noexist(Section *sec, const char *n, double x, int err)
Definition: nrnpy_nrn.cpp:1933
int hocobj_pushargs(PyObject *, std::vector< neuron::unique_cstr > &)
Definition: nrnpy_hoc.cpp:422
static PyObject * mech_getattro_safe(NPyMechObj *self, PyObject *pyname)
Definition: nrnpy_nrn.cpp:2574
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:3000
static PyObject * var_of_mech_iter_safe(NPyMechObj *self)
Definition: nrnpy_nrn.cpp:2172
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:2987
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:1963
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:2489
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:2131
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:3131
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:2127
PyObject * nrn_ptr_richcmp(void *self_ptr, void *other_ptr, int op)
Definition: nrnpy_hoc.cpp:2402
#define M_PI
Definition: nrnpy_nrn.cpp:17
static PyObject * var_of_mech_iter(NPyMechObj *self)
Definition: nrnpy_nrn.cpp:2156
static int NPyAllSegOfSecIter_init_safe(NPyAllSegOfSecIter *self, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:478
PyTypeObject * hocobject_type
Definition: nrnpy_hoc.cpp:136
static int segment_setattro_safe(NPySegObj *self, PyObject *pyname, PyObject *value)
Definition: nrnpy_nrn.cpp:2413
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:2962
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:2983
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:542
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