NEURON
nrnpy_nrn.cpp
Go to the documentation of this file.
1 
2 #include <nrnpython.h>
3 #include <structmember.h>
4 #include <InterViews/resource.h>
5 #include <nrnoc2iv.h>
6 #include "nrnpy_utils.h"
7 #include <cmath>
8 #ifndef M_PI
9 #define M_PI (3.14159265358979323846)
10 #endif
11 
12 #include <membfunc.h>
13 #include <parse.hpp>
14 extern void nrn_pt3dremove(Section* sec, int i0);
15 extern void nrn_pt3dinsert(Section* sec, int i0, double x, double y, double z, double d);
16 extern void nrn_pt3dclear(Section* sec, int req);
17 extern void nrn_pt3dchange1(Section* sec, int i, double d);
18 extern void nrn_pt3dchange2(Section* sec, int i, double x, double y, double z, double diam);
19 extern void stor_pt3d(Section* sec, double x, double y, double z, double d);
20 extern void nrn_pt3dstyle1(Section* sec, double x, double y, double z);
21 extern void nrn_pt3dstyle0(Section* sec);
22 extern void nrn_area_ri(Section* sec);
23 extern void sec_free(hoc_Item*);
25 extern Section* nrn_noerr_access();
26 double* nrnpy_rangepointer(Section*, Symbol*, double, int*);
27 extern PyObject* nrn_ptr_richcmp(void* self_ptr, void* other_ptr, int op);
28 extern int has_membrane(char*, Section*);
29 typedef struct {
30  PyObject_HEAD Section* sec_;
31  char* name_;
32  PyObject* cell_weakref_;
33 } NPySecObj;
35 
36 typedef struct {
37  PyObject_HEAD NPySecObj* pysec_;
40 
41 typedef struct {
42  PyObject_HEAD NPySecObj* pysec_;
43  int seg_iter_;
45 
46 typedef struct {
47  PyObject_HEAD NPySecObj* pysec_;
48  double x_;
49 } NPySegObj;
50 
51 typedef struct {
52  PyObject_HEAD NPySegObj* pyseg_;
55 
56 typedef struct {
57  PyObject_HEAD NPySegObj* pyseg_;
59 } NPyMechObj;
60 
61 typedef struct {
62  PyObject_HEAD NPyMechObj* pymech_;
64  int i_;
66 
67 typedef struct {
68  PyObject_HEAD NPyMechObj* pymech_;
69  int index_;
70 } NPyRVItr;
71 
72 typedef struct {
73  PyObject_HEAD NPyMechObj* pymech_;
75  int isptr_;
76  int attr_from_sec_; // so section.xraxial[0] = e assigns to all segments.
77 } NPyRangeVar;
78 
79 PyTypeObject* psection_type;
80 static PyTypeObject* pallseg_of_sec_iter_type;
81 static PyTypeObject* pseg_of_sec_iter_type;
82 static PyTypeObject* psegment_type;
83 static PyTypeObject* pmech_of_seg_iter_generic_type;
84 static PyTypeObject* pmech_generic_type;
85 static PyTypeObject* pvar_of_mech_iter_generic_type;
86 static PyTypeObject* range_type;
87 
88 PyObject* pmech_types; // Python map for name to Mechanism
89 PyObject* rangevars_; // Python map for name to Symbol
90 
91 extern PyTypeObject* hocobject_type;
93 extern void simpleconnectsection();
94 extern void nrn_change_nseg(Section*, int);
95 extern double section_length(Section*);
96 extern double nrn_ra(Section*);
97 extern int can_change_morph(Section*);
98 extern short* nrn_is_artificial_;
100 extern void nrn_diam_change(Section*);
101 extern void nrn_length_change(Section*, double);
102 extern int diam_changed;
103 extern void mech_insert1(Section*, int);
104 extern void mech_uninsert1(Section*, Symbol*);
105 extern "C" PyObject* nrn_hocobj_ptr(double*);
106 extern int nrn_is_hocobj_ptr(PyObject*, double*&);
107 extern PyObject* nrnpy_forall(PyObject* self, PyObject* args);
108 extern Object* nrnpy_po2ho(PyObject*);
109 extern Object* nrnpy_pyobject_in_obj(PyObject*);
110 extern Symbol* nrnpy_pyobj_sym_;
111 extern int nrnpy_ho_eq_po(Object*, PyObject*);
112 extern PyObject* nrnpy_hoc2pyobject(Object*);
113 extern PyObject* nrnpy_ho2po(Object*);
114 static void nrnpy_reg_mech(int);
115 extern void (*nrnpy_reg_mech_p_)(int);
116 static int ob_is_seg(Object*);
117 extern int (*nrnpy_ob_is_seg)(Object*);
118 static Object* seg_from_sec_x(Section*, double x);
119 extern Object* (*nrnpy_seg_from_sec_x)(Section*, double x);
120 static Section* o2sec(Object*);
121 extern Section* (*nrnpy_o2sec_p_)(Object*);
122 static void o2loc(Object*, Section**, double*);
123 extern void (*nrnpy_o2loc_p_)(Object*, Section**, double*);
124 extern void (*nrnpy_o2loc2_p_)(Object*, Section**, double*);
125 static void nrnpy_unreg_mech(int);
126 extern char* (*nrnpy_pysec_name_p_)(Section*);
127 static char* pysec_name(Section*);
128 extern Object* (*nrnpy_pysec_cell_p_)(Section*);
129 static Object* pysec_cell(Section*);
130 static PyObject* pysec2cell(NPySecObj*);
131 extern int (*nrnpy_pysec_cell_equals_p_)(Section*, Object*);
132 static int pysec_cell_equals(Section*, Object*);
133 static void remake_pmech_types();
134 
136  PyErr_SetString(PyExc_ReferenceError, "can't access a deleted section");
137 }
138 
139 static char* pysec_name(Section* sec) {
140  static char buf[512];
141  if (sec->prop) {
142  NPySecObj* ps = (NPySecObj*) sec->prop->dparam[PROP_PY_INDEX]._pvoid;
143  buf[0] = '\0';
144  char* cp = buf + strlen(buf);
145  if (ps->name_) {
146  sprintf(cp, "%s", ps->name_);
147  } else {
148  // sprintf(cp, "PySec_%p", ps);
149  sprintf(buf, "__nrnsec_%p", sec);
150  }
151  return buf;
152  }
153  return 0;
154 }
155 
157  if (sec->prop && sec->prop->dparam[PROP_PY_INDEX]._pvoid) {
158  PyObject* cell_weakref =
159  ((NPySecObj*) sec->prop->dparam[PROP_PY_INDEX]._pvoid)->cell_weakref_;
160  if (cell_weakref) {
161  PyObject* cell = PyWeakref_GetObject(cell_weakref);
162  if (!cell) {
163  PyErr_Print();
164  hoc_execerror("Error getting cell for", secname(sec));
165  } else if (cell != Py_None) {
166  return nrnpy_po2ho(cell);
167  }
168  }
169  }
170  return NULL;
171 }
172 
173 static int NPySecObj_contains(PyObject* sec, PyObject* obj) {
174  /* report that we contain the object if it has a .sec that is equal to ourselves */
175  PyObject* obj_sec;
176  int result;
177  if (!PyObject_HasAttrString(obj, "sec")) {
178  return 0;
179  }
180  Py_INCREF(obj);
181  obj_sec = PyObject_GetAttrString(obj, "sec");
182  Py_DECREF(obj);
183  result = PyObject_RichCompareBool(sec, obj_sec, Py_EQ);
184  Py_XDECREF(obj_sec);
185  return (result);
186 }
187 
188 static int pysec_cell_equals(Section* sec, Object* obj) {
189  if (sec->prop && sec->prop->dparam[PROP_PY_INDEX]._pvoid) {
190  PyObject* cell_weakref =
191  ((NPySecObj*) sec->prop->dparam[PROP_PY_INDEX]._pvoid)->cell_weakref_;
192  if (cell_weakref) {
193  PyObject* cell = PyWeakref_GetObject(cell_weakref);
194  if (!cell) {
195  PyErr_Print();
196  hoc_execerror("Error getting cell for", secname(sec));
197  }
198  return nrnpy_ho_eq_po(obj, cell);
199  }
200  return nrnpy_ho_eq_po(obj, Py_None);
201  }
202  return 0;
203 }
204 
205 static void NPySecObj_dealloc(NPySecObj* self) {
206  // printf("NPySecObj_dealloc %p %s\n", self, secname(self->sec_));
207  if (self->sec_) {
208  if (self->name_) {
209  nrnpy_pysecname2sec_remove(self->sec_);
210  delete[] self->name_;
211  }
212  Py_XDECREF(self->cell_weakref_);
213  if (self->sec_->prop) {
214  self->sec_->prop->dparam[PROP_PY_INDEX]._pvoid = 0;
215  }
216  if (self->sec_->prop && !self->sec_->prop->dparam[0].sym) {
217  sec_free(self->sec_->prop->dparam[8].itm);
218  } else {
219  section_unref(self->sec_);
220  }
221  }
222  ((PyObject*) self)->ob_type->tp_free((PyObject*) self);
223 }
224 
226  // printf("NPyAllSegOfSecIter_dealloc %p %s\n", self, secname(self->pysec_->sec_));
227  Py_XDECREF(self->pysec_);
228  ((PyObject*) self)->ob_type->tp_free((PyObject*) self);
229 }
230 
232  // printf("NPySegOfSecIter_dealloc %p %s\n", self, secname(self->pysec_->sec_));
233  Py_XDECREF(self->pysec_);
234  ((PyObject*) self)->ob_type->tp_free((PyObject*) self);
235 }
236 
237 static void NPySegObj_dealloc(NPySegObj* self) {
238  // printf("NPySegObj_dealloc %p\n", self);
239  Py_XDECREF(self->pysec_);
240  ((PyObject*) self)->ob_type->tp_free((PyObject*) self);
241 }
242 
243 static void NPyRangeVar_dealloc(NPyRangeVar* self) {
244  // printf("NPyRangeVar_dealloc %p\n", self);
245  Py_XDECREF(self->pymech_);
246  ((PyObject*) self)->ob_type->tp_free((PyObject*) self);
247 }
248 
249 static void NPyMechObj_dealloc(NPyMechObj* self) {
250  // printf("NPyMechObj_dealloc %p %s\n", self, self->ob_type->tp_name);
251  Py_XDECREF(self->pyseg_);
252  ((PyObject*) self)->ob_type->tp_free((PyObject*) self);
253 }
254 
256  // printf("NPyMechOfSegIter_dealloc %p %s\n", self, self->ob_type->tp_name);
257  Py_XDECREF(self->pyseg_);
258  ((PyObject*) self)->ob_type->tp_free((PyObject*) self);
259 }
260 
262  // printf("NPyVarOfMechIter_dealloc %p %s\n", self, self->ob_type->tp_name);
263  Py_XDECREF(self->pymech_);
264  ((PyObject*) self)->ob_type->tp_free((PyObject*) self);
265 }
266 
267 // A new (or inited) python Section object with no arg creates a nrnoc section
268 // which persists only while the python object exists. The nrnoc section
269 // structure
270 // has no hoc Symbol but the Python Section pointer is filled in
271 // and secname(sec) returns the Python Section object name from the hoc section.
272 // If a Python Section object is created from an existing nrnoc section
273 // (with a filled in Symbol) the nrnoc section will continue to exist until
274 // the hoc delete_section() is called on it.
275 //
276 
277 static int NPySecObj_init(NPySecObj* self, PyObject* args, PyObject* kwds) {
278  // printf("NPySecObj_init %p %p\n", self, self->sec_);
279  static const char* kwlist[] = {"name", "cell", NULL};
280  if (self != NULL && !self->sec_) {
281  if (self->name_) {
282  delete[] self->name_;
283  }
284  self->name_ = 0;
285  self->cell_weakref_ = 0;
286  char* name = 0;
287  PyObject* cell = 0;
288  // avoid "warning: deprecated conversion from string constant to char*"
289  // someday eliminate the (char**) when python changes their prototype
290  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sO", (char**) kwlist, &name, &cell)) {
291  return -1;
292  }
293  if (cell && cell != Py_None) {
294  self->cell_weakref_ = PyWeakref_NewRef(cell, NULL);
295  if (!self->cell_weakref_) {
296  return -1;
297  }
298  } else {
299  cell = 0;
300  }
301  if (name) {
302  size_t n = strlen(name) + 1; // include terminator
303 
304  if (cell) {
305  // include cellname in name so nrnpy_pysecname2sec_remove can determine
306 
307  cell = PyObject_Str(cell);
308  if (cell == NULL) {
309  Py_XDECREF(self->cell_weakref_);
310  return -1;
311  }
312  Py2NRNString str(cell);
313  Py_DECREF(cell);
314  if (str.err()) {
315  str.set_pyerr(PyExc_TypeError, "cell name contains non ascii character");
316  return -1;
317  }
318  char* cp = str.c_str();
319  n += strlen(cp) + 1; // include dot
320  self->name_ = new char[n];
321  sprintf(self->name_, "%s.%s", cp, name);
322  } else {
323  self->name_ = new char[n];
324  strcpy(self->name_, name);
325  }
326  }
327  self->sec_ = nrnpy_newsection(self);
328  nrnpy_pysecname2sec_add(self->sec_);
329  }
330  return 0;
331 }
332 
333 static int NPyAllSegOfSecIter_init(NPyAllSegOfSecIter* self, PyObject* args, PyObject* kwds) {
334  NPySecObj* pysec;
335  // printf("NPyAllSegOfSecIter_init %p %p\n", self, self->sec_);
336  if (self != NULL && !self->pysec_) {
337  if (!PyArg_ParseTuple(args, "O!", psection_type, &pysec)) {
338  return -1;
339  }
340  self->allseg_iter_ = 0;
341  self->pysec_ = pysec;
342  Py_INCREF(pysec);
343  }
344  return 0;
345 }
346 
347 PyObject* NPySecObj_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
348  NPySecObj* self;
349  self = (NPySecObj*) type->tp_alloc(type, 0);
350  // printf("NPySecObj_new %p\n", self);
351  if (self != NULL) {
352  if (NPySecObj_init(self, args, kwds) != 0) {
353  Py_DECREF(self);
354  return NULL;
355  }
356  }
357  return (PyObject*) self;
358 }
359 
360 PyObject* NPyAllSegOfSecIter_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
361  NPyAllSegOfSecIter* self;
362  self = (NPyAllSegOfSecIter*) type->tp_alloc(type, 0);
363  // printf("NPyAllSegOfSecIter_new %p\n", self);
364  if (self != NULL) {
365  if (NPyAllSegOfSecIter_init(self, args, kwds) != 0) {
366  Py_DECREF(self);
367  return NULL;
368  }
369  }
370  return (PyObject*) self;
371 }
372 
373 PyObject* nrnpy_newsecobj(PyObject* self, PyObject* args, PyObject* kwds) {
374  return NPySecObj_new(psection_type, args, kwds);
375 }
376 
377 static PyObject* NPySegObj_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
378  NPySecObj* pysec;
379  double x;
380  if (!PyArg_ParseTuple(args, "O!d", psection_type, &pysec, &x)) {
381  return NULL;
382  }
383  if (x > 1.0 && x < 1.0001) {
384  x = 1.0;
385  }
386  if (x < 0. || x > 1.0) {
387  PyErr_SetString(PyExc_ValueError, "segment position range is 0 <= x <= 1");
388  return NULL;
389  }
390  NPySegObj* self;
391  self = (NPySegObj*) type->tp_alloc(type, 0);
392  // printf("NPySegObj_new %p\n", self);
393  if (self != NULL) {
394  self->pysec_ = pysec;
395  self->x_ = x;
396  Py_INCREF(self->pysec_);
397  }
398  return (PyObject*) self;
399 }
400 
401 static PyObject* NPyMechObj_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
402  NPySegObj* pyseg;
403  if (!PyArg_ParseTuple(args, "O!", psegment_type, &pyseg)) {
404  return NULL;
405  }
406  NPyMechObj* self;
407  self = (NPyMechObj*) type->tp_alloc(type, 0);
408  // printf("NPyMechObj_new %p %s\n", self,
409  // ((PyObject*)self)->ob_type->tp_name);
410  if (self != NULL) {
411  self->pyseg_ = pyseg;
412  Py_INCREF(self->pyseg_);
413  }
414  return (PyObject*) self;
415 }
416 
417 static PyObject* NPyRangeVar_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
418  NPyRangeVar* self;
419  self = (NPyRangeVar*) type->tp_alloc(type, 0);
420  if (self != NULL) {
421  self->pymech_ = NULL;
422  self->sym_ = NULL;
423  self->isptr_ = 0;
424  self->attr_from_sec_ = 0;
425  }
426  return (PyObject*) self;
427 }
428 
429 static int NPySegObj_init(NPySegObj* self, PyObject* args, PyObject* kwds) {
430  // printf("NPySegObj_init %p %p\n", self, self->pysec_);
431  NPySecObj* pysec;
432  double x;
433  if (!PyArg_ParseTuple(args, "O!d", psection_type, &pysec, &x)) {
434  return -1;
435  }
436  if (x > 1.0 && x < 1.0001) {
437  x = 1.0;
438  }
439  if (x < 0. || x > 1.0) {
440  PyErr_SetString(PyExc_ValueError, "segment position range is 0 <= x <= 1");
441  return -1;
442  }
443  Py_INCREF(pysec);
444  if (self->pysec_) {
445  Py_DECREF(self->pysec_);
446  }
447  self->pysec_ = pysec;
448  self->x_ = x;
449  return 0;
450 }
451 
452 static int ob_is_seg(Object* o) {
453  if (!o || o->ctemplate->sym != nrnpy_pyobj_sym_) {
454  return 0;
455  }
456  PyObject* po = nrnpy_hoc2pyobject(o);
457  if (!PyObject_TypeCheck(po, psegment_type)) {
458  return 0;
459  }
460  return 1;
461 }
462 
463 static Section* o2sec(Object* o) {
464  if (o->ctemplate->sym != nrnpy_pyobj_sym_) {
465  hoc_execerror("not a Python nrn.Section", 0);
466  }
467  PyObject* po = nrnpy_hoc2pyobject(o);
468  if (!PyObject_TypeCheck(po, psection_type)) {
469  hoc_execerror("not a Python nrn.Section", 0);
470  }
471  NPySecObj* pysec = (NPySecObj*) po;
472  return pysec->sec_;
473 }
474 
475 static void o2loc(Object* o, Section** psec, double* px) {
476  if (o->ctemplate->sym != nrnpy_pyobj_sym_) {
477  hoc_execerror("not a Python nrn.Segment", 0);
478  }
479  PyObject* po = nrnpy_hoc2pyobject(o);
480  if (!PyObject_TypeCheck(po, psegment_type)) {
481  hoc_execerror("not a Python nrn.Segment", 0);
482  }
483  NPySegObj* pyseg = (NPySegObj*) po;
484  *psec = pyseg->pysec_->sec_;
485  if (!(*psec)->prop) {
486  hoc_execerr_ext("nrn.Segment associated with deleted internal Section");
487  }
488  *px = pyseg->x_;
489 }
490 
491 
492 static void o2loc2(Object* o, Section** psec, double* px) {
493  bool free_po = false;
494  if (o->ctemplate->sym != nrnpy_pyobj_sym_) {
495  hoc_execerror("not a Python nrn.Segment, rxd.node, or other with a segment property", 0);
496  }
497  PyObject* po = nrnpy_hoc2pyobject(o);
498  if (!PyObject_TypeCheck(po, psegment_type)) {
499  if (PyList_Check(po)) {
500  if (PyList_Size(po) != 1) {
501  hoc_execerror("If a list is supplied, it must be of length 1", 0);
502  } else {
503  PyObject* old_po = po;
504  Py_INCREF(old_po);
505  po = PyList_GetItem(po, 0);
506  Py_DECREF(old_po);
507  free_po = true;
508  }
509  }
510  if (!PyObject_HasAttrString(po, "segment")) {
511  if (free_po) {
512  Py_DECREF(po);
513  }
514  hoc_execerror("not a Python nrn.Segment, rxd.node, or other with a segment property",
515  0);
516  }
517  PyObject* obj = po;
518  Py_INCREF(obj);
519  po = PyObject_GetAttrString(obj, "segment");
520  Py_DECREF(obj);
521  if (free_po) {
522  // don't need the element from the list anymore
523  Py_DECREF(obj);
524  }
525  free_po = true;
526  }
527  NPySegObj* pyseg = (NPySegObj*) po;
528  *psec = pyseg->pysec_->sec_;
529  *px = pyseg->x_;
530  if (free_po) {
531  Py_DECREF(po);
532  }
533  if (!(*psec)->prop) {
534  hoc_execerr_ext("nrn.Segment associated with deleted internal Section");
535  }
536 }
537 
538 static int NPyMechObj_init(NPyMechObj* self, PyObject* args, PyObject* kwds) {
539  // printf("NPyMechObj_init %p %p %s\n", self, self->pyseg_,
540  // ((PyObject*)self)->ob_type->tp_name);
541  NPySegObj* pyseg;
542  if (!PyArg_ParseTuple(args, "O!", psegment_type, &pyseg)) {
543  return -1;
544  }
545  Py_INCREF(pyseg);
546  Py_XDECREF(self->pyseg_);
547  self->pyseg_ = pyseg;
548  return 0;
549 }
550 
551 static int NPyRangeVar_init(NPyRangeVar* self, PyObject* args, PyObject* kwds) {
552  return 0;
553 }
554 
555 static PyObject* NPySecObj_name(NPySecObj* self) {
556  PyObject* result;
557  result = PyString_FromString(secname(self->sec_));
558  return result;
559 }
560 
561 static PyObject* NPySecObj_n3d(NPySecObj* self) {
562  CHECK_SEC_INVALID(self->sec_);
563  return PyInt_FromLong(self->sec_->npt3d);
564 }
565 
566 static PyObject* NPySecObj_pt3dremove(NPySecObj* self, PyObject* args) {
567  Section* sec = self->sec_;
569  int i0, n;
570  if (!PyArg_ParseTuple(args, "i", &i0)) {
571  return NULL;
572  }
573  if (i0 < 0 || i0 >= sec->npt3d) {
574  PyErr_SetString(PyExc_Exception, "Arg out of range\n");
575  return NULL;
576  }
577 
578  nrn_pt3dremove(sec, i0);
579  Py_RETURN_NONE;
580 }
581 
582 static PyObject* NPySecObj_pt3dclear(NPySecObj* self, PyObject* args) {
583  Section* sec = self->sec_;
585  int req = 0;
586  Py_ssize_t narg = PyTuple_GET_SIZE(args);
587  if (narg) {
588  if (!PyArg_ParseTuple(args, "i", &req)) {
589  return NULL;
590  }
591  }
592  if (req < 0) {
593  PyErr_SetString(PyExc_Exception, "Arg out of range\n");
594  return NULL;
595  }
596  nrn_pt3dclear(sec, req);
597  return PyInt_FromLong(sec->pt3d_bsize);
598 }
599 
600 static PyObject* NPySecObj_pt3dchange(NPySecObj* self, PyObject* args) {
601  Section* sec = self->sec_;
603  int i;
604  double x, y, z, diam;
605  Py_ssize_t narg = PyTuple_GET_SIZE(args);
606  if (narg == 2) {
607  if (!PyArg_ParseTuple(args, "id", &i, &diam)) {
608  return NULL;
609  }
610  if (i < 0 || i >= sec->npt3d) {
611  PyErr_SetString(PyExc_Exception, "Arg out of range\n");
612  return NULL;
613  }
614  nrn_pt3dchange1(sec, i, diam);
615  } else if (narg == 5) {
616  if (!PyArg_ParseTuple(args, "idddd", &i, &x, &y, &z, &diam)) {
617  return NULL;
618  }
619  if (i < 0 || i >= sec->npt3d) {
620  PyErr_SetString(PyExc_Exception, "Arg out of range\n");
621  return NULL;
622  }
623  nrn_pt3dchange2(sec, i, x, y, z, diam);
624  } else {
625  PyErr_SetString(PyExc_Exception, "Wrong number of arguments\n");
626  return NULL;
627  }
628  Py_RETURN_NONE;
629 }
630 
631 static PyObject* NPySecObj_pt3dinsert(NPySecObj* self, PyObject* args) {
632  Section* sec = self->sec_;
634  int i;
635  double x, y, z, d;
636  if (!PyArg_ParseTuple(args, "idddd", &i, &x, &y, &z, &d)) {
637  return NULL;
638  }
639  if (i < 0 || i > sec->npt3d) {
640  PyErr_SetString(PyExc_Exception, "Arg out of range\n");
641  return NULL;
642  }
643  nrn_pt3dinsert(sec, i, x, y, z, d);
644  Py_RETURN_NONE;
645 }
646 
647 static PyObject* NPySecObj_pt3dadd(NPySecObj* self, PyObject* args) {
648  Section* sec = self->sec_;
650  double x, y, z, d;
651  // TODO: add support for iterables
652  if (!PyArg_ParseTuple(args, "dddd", &x, &y, &z, &d)) {
653  return NULL;
654  }
655  stor_pt3d(sec, x, y, z, d);
656  Py_RETURN_NONE;
657 }
658 
659 static PyObject* NPySecObj_pt3dstyle(NPySecObj* self, PyObject* args) {
660  Section* sec = self->sec_;
662  int style;
663  double x, y, z;
664  Py_ssize_t narg = PyTuple_GET_SIZE(args);
665 
666  if (narg) {
667  if (narg == 1) {
668  if (!PyArg_ParseTuple(args, "i", &style)) {
669  return NULL;
670  }
671  if (style) {
672  PyErr_SetString(PyExc_AttributeError, "If exactly one argument, it must be 0.");
673  return NULL;
674  }
676  } else if (narg == 4) {
677  // TODO: figure out some way of reading the logical connection point
678  // don't use hoc refs
679  if (!PyArg_ParseTuple(args, "iddd", &style, &x, &y, &z)) {
680  return NULL;
681  }
682  nrn_pt3dstyle1(sec, x, y, z);
683 
684  } else {
685  PyErr_SetString(PyExc_Exception, "Wrong number of arguments.");
686  return NULL;
687  }
688  }
689 
690  if (sec->logical_connection) {
691  Py_RETURN_TRUE;
692  }
693  Py_RETURN_FALSE;
694 }
695 
696 static PyObject* NPySecObj_x3d(NPySecObj* self,
697  PyObject* args) { // returns x value at index of 3d list
698  Section* sec = self->sec_;
700  int n, i;
701  if (!PyArg_ParseTuple(args, "i", &i)) {
702  return NULL;
703  }
704  n = sec->npt3d - 1;
705  if (i < 0 || i > n) {
706  PyErr_SetString(PyExc_Exception, "Arg out of range\n");
707  return NULL;
708  }
709  return PyFloat_FromDouble((double) sec->pt3d[i].x);
710 }
711 
712 static PyObject* NPySecObj_y3d(NPySecObj* self,
713  PyObject* args) { // returns y value at index of 3d list
714  Section* sec = self->sec_;
716  int n, i;
717  if (!PyArg_ParseTuple(args, "i", &i)) {
718  return NULL;
719  }
720  n = sec->npt3d - 1;
721  if (i < 0 || i > n) {
722  PyErr_SetString(PyExc_Exception, "Arg out of range\n");
723  return NULL;
724  }
725  return PyFloat_FromDouble((double) sec->pt3d[i].y);
726 }
727 
728 static PyObject* NPySecObj_z3d(NPySecObj* self,
729  PyObject* args) { // returns z value at index of 3d list
730  Section* sec = self->sec_;
732  int n, i;
733  if (!PyArg_ParseTuple(args, "i", &i)) {
734  return NULL;
735  }
736  n = sec->npt3d - 1;
737  if (i < 0 || i > n) {
738  PyErr_SetString(PyExc_Exception, "Arg out of range\n");
739  return NULL;
740  }
741  return PyFloat_FromDouble((double) sec->pt3d[i].z);
742 }
743 
744 static PyObject* NPySecObj_arc3d(NPySecObj* self,
745  PyObject* args) { // returns arc position value at index of 3d
746  // list
747  Section* sec = self->sec_;
749  int n, i;
750  if (!PyArg_ParseTuple(args, "i", &i)) {
751  return NULL;
752  }
753  n = sec->npt3d - 1;
754  if (i < 0 || i > n) {
755  PyErr_SetString(PyExc_Exception, "Arg out of range\n");
756  return NULL;
757  }
758  return PyFloat_FromDouble((double) sec->pt3d[i].arc);
759 }
760 
761 static PyObject* NPySecObj_diam3d(NPySecObj* self,
762  PyObject* args) { // returns diam value at index of 3d list
763  Section* sec = self->sec_;
765  int n, i;
766  if (!PyArg_ParseTuple(args, "i", &i)) {
767  return NULL;
768  }
769  n = sec->npt3d - 1;
770  if (i < 0 || i > n) {
771  PyErr_SetString(PyExc_Exception, "Arg out of range\n");
772  return NULL;
773  }
774  return PyFloat_FromDouble((double) fabs(sec->pt3d[i].d));
775 }
776 
777 static PyObject* NPySecObj_spine3d(NPySecObj* self,
778  PyObject* args) { // returns True/False depending on if spine
779  // present
780  Section* sec = self->sec_;
782  int n, i;
783  if (!PyArg_ParseTuple(args, "i", &i)) {
784  return NULL;
785  }
786  n = sec->npt3d - 1;
787  if (i < 0 || i > n) {
788  PyErr_SetString(PyExc_Exception, "Arg out of range\n");
789  return NULL;
790  }
791  if (sec->pt3d[i].d < 0) {
792  Py_RETURN_TRUE;
793  }
794  Py_RETURN_FALSE;
795 }
796 
797 static PyObject* pysec_repr(PyObject* p) {
798  NPySecObj* psec = (NPySecObj*) p;
799  if (psec->sec_ && psec->sec_->prop) {
800  return NPySecObj_name(psec);
801  }
802  return PyString_FromString("<deleted section>");
803 }
804 
805 static PyObject* pyseg_repr(PyObject* p) {
806  NPySegObj* pyseg = (NPySegObj*) p;
807  if (pyseg->pysec_->sec_ && pyseg->pysec_->sec_->prop) {
808  const char* sname = secname(pyseg->pysec_->sec_);
809  char* name = new char[strlen(sname) + 100];
810  sprintf(name, "%s(%g)", sname, pyseg->x_);
811  PyObject* result = PyString_FromString(name);
812  delete[] name;
813  return result;
814  }
815  return PyString_FromString("<segment of deleted section>");
816 }
817 
818 static PyObject* hoc_internal_name(NPySecObj* self) {
819  PyObject* result;
820  char buf[256];
821  sprintf(buf, "__nrnsec_%p", self->sec_);
823  return result;
824 }
825 
826 static PyObject* nrnpy_psection;
827 static PyObject* nrnpy_set_psection(PyObject* self, PyObject* args) {
828  PyObject* po;
829  if (!PyArg_ParseTuple(args, "O", &po)) {
830  return NULL;
831  }
832  if (PyCallable_Check(po) == 0) {
833  PyErr_SetString(PyExc_TypeError, "argument must be a callable");
834  return NULL;
835  }
836  if (nrnpy_psection) {
837  Py_DECREF(nrnpy_psection);
839  }
840  nrnpy_psection = po;
841  Py_INCREF(po);
842  return po;
843 }
844 
845 static PyObject* NPySecObj_psection(NPySecObj* self) {
846  CHECK_SEC_INVALID(self->sec_);
847  if (nrnpy_psection) {
848  PyObject* arglist = Py_BuildValue("(O)", self);
849  PyObject* result = PyObject_CallObject(nrnpy_psection, arglist);
850  Py_DECREF(arglist);
851  return result;
852  }
853  Py_INCREF(Py_None);
854  return Py_None;
855 }
856 
857 static PyObject* is_pysec(NPySecObj* self) {
858  CHECK_SEC_INVALID(self->sec_);
859  if (self->sec_->prop && self->sec_->prop->dparam[PROP_PY_INDEX]._pvoid) {
860  Py_RETURN_TRUE;
861  }
862  Py_RETURN_FALSE;
863 }
864 
866  if (!sec || !sec->prop) {
867  return NULL;
868  }
869  NPySecObj* pysec = NULL;
870  if (sec->prop->dparam[PROP_PY_INDEX]._pvoid) {
871  pysec = (NPySecObj*) sec->prop->dparam[PROP_PY_INDEX]._pvoid;
872  Py_INCREF(pysec);
873  assert(pysec->sec_ == sec);
874  } else {
875  pysec = (NPySecObj*) psection_type->tp_alloc(psection_type, 0);
876  pysec->sec_ = sec;
877  section_ref(sec);
878  pysec->name_ = 0;
879  pysec->cell_weakref_ = 0;
880  }
881  return pysec;
882 }
883 
884 static PyObject* newpyseghelp(Section* sec, double x) {
885  NPySegObj* seg = (NPySegObj*) PyObject_New(NPySegObj, psegment_type);
886  if (seg == NULL) {
887  return NULL;
888  }
889  seg->x_ = x;
890  seg->pysec_ = newpysechelp(sec);
891  return (PyObject*) seg;
892 }
893 
894 static PyObject* pysec_disconnect(NPySecObj* self) {
895  CHECK_SEC_INVALID(self->sec_);
896  nrn_disconnect(self->sec_);
897  Py_INCREF(Py_None);
898  return Py_None;
899 }
900 
901 static PyObject* pysec_parentseg(NPySecObj* self) {
902  CHECK_SEC_INVALID(self->sec_);
903  Section* psec = self->sec_->parentsec;
904  if (psec == NULL || psec->prop == NULL) {
905  Py_INCREF(Py_None);
906  return Py_None;
907  }
908  double x = nrn_connection_position(self->sec_);
909  return newpyseghelp(psec, x);
910 }
911 
912 static PyObject* pysec_trueparentseg(NPySecObj* self) {
913  Section* sec = self->sec_;
915  Section* psec = NULL;
916  for (psec = sec->parentsec; psec; psec = psec->parentsec) {
917  if (psec == NULL || psec->prop == NULL) {
918  Py_INCREF(Py_None);
919  return Py_None;
920  }
921  if (nrn_at_beginning(sec)) {
922  sec = psec;
923  } else {
924  break;
925  }
926  }
927  if (psec == NULL) {
928  Py_INCREF(Py_None);
929  return Py_None;
930  }
931 
932  double x = nrn_connection_position(sec);
933  return newpyseghelp(psec, x);
934 }
935 
936 static PyObject* pysec_orientation(NPySecObj* self) {
937  CHECK_SEC_INVALID(self->sec_);
938  double x = nrn_section_orientation(self->sec_);
939  return Py_BuildValue("d", x);
940 }
941 
942 static bool lappendsec(PyObject* const sl, Section* const s) {
943  PyObject* item = (PyObject*) newpysechelp(s);
944  if (!item) {
945  return false;
946  }
947  if (PyList_Append(sl, item) != 0) {
948  return false;
949  }
950  Py_XDECREF(item);
951  return true;
952 }
953 
954 static PyObject* pysec_children1(PyObject* const sl, Section* const sec) {
955  for (Section* s = sec->child; s; s = s->sibling) {
956  if (!lappendsec(sl, s)) {
957  return NULL;
958  }
959  }
960  return sl;
961 }
962 
963 static PyObject* pysec_children(NPySecObj* const self) {
964  Section* const sec = self->sec_;
966  PyObject* const result = PyList_New(0);
967  if (!result) {
968  return NULL;
969  }
970  return pysec_children1(result, sec);
971 }
972 
973 static PyObject* pysec_subtree1(PyObject* const sl, Section* const sec) {
974  if (!lappendsec(sl, sec)) {
975  return NULL;
976  }
977  for (Section* s = sec->child; s; s = s->sibling) {
978  if (!pysec_subtree1(sl, s)) {
979  return NULL;
980  }
981  }
982  return sl;
983 }
984 
985 static PyObject* pysec_subtree(NPySecObj* const self) {
986  Section* const sec = self->sec_;
988  PyObject* const result = PyList_New(0);
989  if (!result) {
990  return NULL;
991  }
992  return pysec_subtree1(result, sec);
993 }
994 
995 static PyObject* pysec_wholetree(NPySecObj* const self) {
996  Section* sec = self->sec_;
998  Section* s;
999  PyObject* result = PyList_New(0);
1000  if (!result) {
1001  return NULL;
1002  }
1003  for (s = sec; s->parentsec; s = s->parentsec) {
1004  }
1005  return pysec_subtree1(result, s);
1006 }
1007 
1008 static PyObject* pysec2cell(NPySecObj* self) {
1009  PyObject* result;
1010  if (self->cell_weakref_) {
1011  result = PyWeakref_GET_OBJECT(self->cell_weakref_);
1012  Py_INCREF(result);
1013  } else if (self->sec_->prop && self->sec_->prop->dparam[6].obj) {
1014  result = nrnpy_ho2po(self->sec_->prop->dparam[6].obj);
1015  } else {
1016  result = Py_None;
1017  Py_INCREF(result);
1018  }
1019  return result;
1020 }
1021 
1022 static long pysec_hash(PyObject* self) {
1023  return castptr2long((NPySecObj*) self)->sec_;
1024 }
1025 
1026 static long pyseg_hash(PyObject* self) {
1027  NPySegObj* seg = (NPySegObj*) self;
1028  return castptr2long node_exact(seg->pysec_->sec_, seg->x_);
1029 }
1030 
1031 static PyObject* pyseg_richcmp(NPySegObj* self, PyObject* other, int op) {
1032  PyObject* pysec;
1033  bool result = false;
1034  NPySegObj* seg = (NPySegObj*) self;
1035  void* self_ptr = (void*) node_exact(seg->pysec_->sec_, seg->x_);
1036  void* other_ptr = (void*) other;
1037  if (PyObject_TypeCheck(other, psegment_type)) {
1038  seg = (NPySegObj*) other;
1039  other_ptr = (void*) node_exact(seg->pysec_->sec_, seg->x_);
1040  }
1041  return nrn_ptr_richcmp(self_ptr, other_ptr, op);
1042 }
1043 
1044 static PyObject* pysec_richcmp(NPySecObj* self, PyObject* other, int op) {
1045  PyObject* pysec;
1046  bool result = false;
1047  void* self_ptr = (void*) (self->sec_);
1048  void* other_ptr = (void*) other;
1049  if (PyObject_TypeCheck(other, psection_type)) {
1050  void* self_ptr = (void*) (self->sec_);
1051  other_ptr = (void*) (((NPySecObj*) other)->sec_);
1052  return nrn_ptr_richcmp(self_ptr, other_ptr, op);
1053  }
1054  if (PyObject_TypeCheck(other, hocobject_type) || PyObject_TypeCheck(other, psegment_type)) {
1055  // preserves comparison with NEURON objects as it existed prior to 7.7
1056  return nrn_ptr_richcmp(self_ptr, other_ptr, op);
1057  }
1058  Py_INCREF(Py_NotImplemented);
1059  return Py_NotImplemented;
1060 }
1061 
1062 static PyObject* pysec_same(NPySecObj* self, PyObject* args) {
1063  PyObject* pysec;
1064  if (PyArg_ParseTuple(args, "O", &pysec)) {
1065  if (PyObject_TypeCheck(pysec, psection_type)) {
1066  if (((NPySecObj*) pysec)->sec_ == self->sec_) {
1067  Py_RETURN_TRUE;
1068  }
1069  }
1070  }
1071  Py_RETURN_FALSE;
1072 }
1073 
1074 static PyObject* NPyMechObj_name(NPyMechObj* self) {
1075  CHECK_SEC_INVALID(self->pyseg_->pysec_->sec_);
1076  PyObject* result = NULL;
1077  if (self->prop_) {
1078  result = PyString_FromString(memb_func[self->prop_->type].sym->name);
1079  }
1080  return result;
1081 }
1082 
1083 static PyObject* NPyMechObj_is_ion(NPyMechObj* self) {
1084  CHECK_SEC_INVALID(self->pyseg_->pysec_->sec_);
1085  if (self->prop_ && nrn_is_ion(self->prop_->type)) {
1086  Py_RETURN_TRUE;
1087  }
1088  Py_RETURN_FALSE;
1089 }
1090 
1091 static PyObject* NPyMechObj_segment(NPyMechObj* self) {
1092  CHECK_SEC_INVALID(self->pyseg_->pysec_->sec_);
1093  PyObject* result = NULL;
1094  if (self->pyseg_) {
1095  result = (PyObject*) (self->pyseg_);
1096  Py_INCREF(result);
1097  }
1098  return result;
1099 }
1100 
1101 static PyObject* pymech_repr(PyObject* p) {
1102  NPyMechObj* pymech = (NPyMechObj*) p;
1103  Section* sec = pymech->pyseg_->pysec_->sec_;
1104  if (sec && sec->prop) {
1105  return NPyMechObj_name(pymech);
1106  }
1107  return PyString_FromString("<mechanism of deleted section>");
1108 }
1109 
1110 static PyObject* NPyRangeVar_name(NPyRangeVar* self) {
1111  PyObject* result = NULL;
1112  if (self->sym_) {
1113  if (self->isptr_) {
1114  char buf[256];
1115  sprintf(buf, "_ref_%s", self->sym_->name);
1117  } else {
1118  result = PyString_FromString(self->sym_->name);
1119  }
1120  } else {
1121  CHECK_SEC_INVALID(self->pymech_->pyseg_->pysec_->sec_);
1122  PyErr_SetString(PyExc_ReferenceError, "no Symbol");
1123  }
1124  return result;
1125 }
1126 
1127 static PyObject* NPyRangeVar_mech(NPyRangeVar* self) {
1128  CHECK_SEC_INVALID(self->pymech_->pyseg_->pysec_->sec_);
1129  PyObject* result = NULL;
1130  if (self->pymech_) {
1131  result = (PyObject*) self->pymech_;
1132  Py_INCREF(result);
1133  }
1134  return result;
1135 }
1136 
1137 static PyObject* NPySecObj_connect(NPySecObj* self, PyObject* args) {
1138  CHECK_SEC_INVALID(self->sec_);
1139  PyObject* p;
1140  NPySecObj* parent;
1141  double parentx, childend;
1142  parentx = -1000.;
1143  childend = 0.;
1144  if (!PyArg_ParseTuple(args, "O|dd", &p, &parentx, &childend)) {
1145  return NULL;
1146  }
1147  if (PyObject_TypeCheck(p, psection_type)) {
1148  parent = (NPySecObj*) p;
1149  if (parentx == -1000.) {
1150  parentx = 1.;
1151  }
1152  } else if (PyObject_TypeCheck(p, psegment_type)) {
1153  parent = ((NPySegObj*) p)->pysec_;
1154  if (parentx != -1000.) {
1155  childend = parentx;
1156  }
1157  parentx = ((NPySegObj*) p)->x_;
1158  } else {
1159  PyErr_SetString(PyExc_TypeError, "first arg not a nrn.Section or nrn.Segment");
1160  return NULL;
1161  }
1162  CHECK_SEC_INVALID(parent->sec_);
1163 
1164  // printf("NPySecObj_connect %s %g %g\n", parent, parentx, childend);
1165  if (parentx > 1. || parentx < 0.) {
1166  PyErr_SetString(PyExc_ValueError, "out of range 0 <= parentx <= 1.");
1167  return NULL;
1168  }
1169  if (childend != 0. && childend != 1.) {
1170  PyErr_SetString(PyExc_ValueError, "child connection end must be 0 or 1");
1171  return NULL;
1172  }
1173  Py_INCREF(self);
1174  hoc_pushx(childend);
1175  hoc_pushx(parentx);
1176  nrn_pushsec(self->sec_);
1177  nrn_pushsec(parent->sec_);
1179  return (PyObject*) self;
1180 }
1181 
1182 static PyObject* NPySecObj_insert(NPySecObj* self, PyObject* args) {
1183  CHECK_SEC_INVALID(self->sec_);
1184  char* tname;
1185  PyObject *tpyobj, *tpyobj2;
1186  if (!PyArg_ParseTuple(args, "s", &tname)) {
1187  PyErr_Clear();
1188  // if called with an object that has an insert method, use that
1189  if (PyArg_ParseTuple(args, "O", &tpyobj)) {
1190  Py_INCREF(tpyobj);
1191  Py_INCREF((PyObject*) self);
1192  tpyobj2 = PyObject_CallMethod(tpyobj, "insert", "O", (PyObject*) self);
1193  Py_DECREF(tpyobj);
1194  if (tpyobj2 == NULL) {
1195  Py_DECREF((PyObject*) self);
1196  PyErr_Clear();
1197  PyErr_SetString(
1198  PyExc_TypeError,
1199  "insert argument must be either a string or an object with an insert method");
1200  return NULL;
1201  }
1202  Py_DECREF(tpyobj2);
1203  return (PyObject*) self;
1204  }
1205  PyErr_Clear();
1206  PyErr_SetString(PyExc_TypeError, "insert takes a single positional argument");
1207  return NULL;
1208  }
1209  PyObject* otype = PyDict_GetItemString(pmech_types, tname);
1210  if (!otype) {
1211  // check first to see if the pmech_types needs to be
1212  // augmented by any new KSChan
1214  otype = PyDict_GetItemString(pmech_types, tname);
1215  if (!otype) {
1216  PyErr_SetString(PyExc_ValueError, "argument not a density mechanism name.");
1217  return NULL;
1218  }
1219  }
1220  int type = PyInt_AsLong(otype);
1221  // printf("NPySecObj_insert %s %d\n", tname, type);
1222  mech_insert1(self->sec_, type);
1223  Py_INCREF(self);
1224  return (PyObject*) self;
1225 }
1226 
1227 static PyObject* NPySecObj_uninsert(NPySecObj* self, PyObject* args) {
1228  CHECK_SEC_INVALID(self->sec_);
1229  char* tname;
1230  if (!PyArg_ParseTuple(args, "s", &tname)) {
1231  return NULL;
1232  }
1233  PyObject* otype = PyDict_GetItemString(pmech_types, tname);
1234  if (!otype) {
1235  // check first to see if the pmech_types needs to be
1236  // augmented by any new KSChan
1238  otype = PyDict_GetItemString(pmech_types, tname);
1239  if (!otype) {
1240  PyErr_SetString(PyExc_ValueError, "argument not a density mechanism name.");
1241  return NULL;
1242  }
1243  }
1244  int type = PyInt_AsLong(otype);
1245  // printf("NPySecObj_uninsert %s %d\n", tname, memb_func[type].sym);
1246  mech_uninsert1(self->sec_, memb_func[type].sym);
1247  Py_INCREF(self);
1248  return (PyObject*) self;
1249 }
1250 
1251 static PyObject* NPySecObj_has_membrane(NPySecObj* self, PyObject* args) {
1252  CHECK_SEC_INVALID(self->sec_);
1253  char* mechanism_name;
1254  PyObject* result;
1255  if (!PyArg_ParseTuple(args, "s", &mechanism_name)) {
1256  return NULL;
1257  }
1258  result = has_membrane(mechanism_name, self->sec_) ? Py_True : Py_False;
1259  Py_XINCREF(result);
1260  return result;
1261 }
1262 
1263 PyObject* nrnpy_pushsec(PyObject* sec) {
1264  if (PyObject_TypeCheck(sec, psection_type)) {
1265  nrn_pushsec(((NPySecObj*) sec)->sec_);
1266  return sec;
1267  }
1268  return NULL;
1269 }
1270 
1271 static PyObject* NPySecObj_push(NPySecObj* self, PyObject* args) {
1272  CHECK_SEC_INVALID(self->sec_);
1273  nrn_pushsec(self->sec_);
1274  Py_INCREF(self);
1275  return (PyObject*) self;
1276 }
1277 
1278 static PyObject* seg_of_section_iter(NPySecObj* self) { // iterates over segments
1279  CHECK_SEC_INVALID(self->sec_);
1280  // printf("section_iter\n");
1281  NPySegOfSecIter* segiter;
1282  segiter = PyObject_New(NPySegOfSecIter, pseg_of_sec_iter_type);
1283  if (segiter == NULL) {
1284  return NULL;
1285  }
1286 
1287  segiter->seg_iter_ = 0;
1288  Py_INCREF(self);
1289  segiter->pysec_ = self;
1290  return (PyObject*) segiter;
1291 }
1292 
1293 static PyObject* allseg(NPySecObj* self) {
1294  CHECK_SEC_INVALID(self->sec_);
1295  // printf("allseg\n");
1297  ai->pysec_ = self;
1298  Py_INCREF(self);
1299  ai->allseg_iter_ = -1;
1300  return (PyObject*) ai;
1301 }
1302 
1303 static PyObject* allseg_of_sec_iter(NPyAllSegOfSecIter* self) {
1304  Py_INCREF(self);
1305  self->allseg_iter_ = -1;
1306  return (PyObject*) self;
1307 }
1308 
1309 static PyObject* allseg_of_sec_next(NPyAllSegOfSecIter* self) {
1310  NPySegObj* seg;
1311  int n1 = self->pysec_->sec_->nnode - 1;
1312  if (self->allseg_iter_ > n1) {
1313  // end of iteration
1314  return NULL;
1315  }
1316  seg = PyObject_New(NPySegObj, psegment_type);
1317  if (seg == NULL) {
1318  // error
1319  return NULL;
1320  }
1321  seg->pysec_ = self->pysec_;
1322  Py_INCREF(self->pysec_);
1323  if (self->allseg_iter_ == -1) {
1324  seg->x_ = 0.;
1325  } else if (self->allseg_iter_ == n1) {
1326  seg->x_ = 1.;
1327  } else {
1328  seg->x_ = (double(self->allseg_iter_) + 0.5) / ((double) n1);
1329  }
1330  ++self->allseg_iter_;
1331  return (PyObject*) seg;
1332 }
1333 
1334 static PyObject* seg_of_sec_next(NPySegOfSecIter* self) {
1335  NPySegObj* seg;
1336  int n1 = self->pysec_->sec_->nnode - 1;
1337  if (self->seg_iter_ >= n1) {
1338  // end of iteration
1339  return NULL;
1340  }
1341  seg = PyObject_New(NPySegObj, psegment_type);
1342  if (seg == NULL) {
1343  // error
1344  return NULL;
1345  }
1346  seg->pysec_ = self->pysec_;
1347  Py_INCREF(self->pysec_);
1348  seg->x_ = (double(self->seg_iter_) + 0.5) / ((double) n1);
1349  ++self->seg_iter_;
1350  return (PyObject*) seg;
1351 }
1352 
1353 static PyObject* seg_point_processes(NPySegObj* self) {
1354  Section* sec = self->pysec_->sec_;
1356  Node* nd = node_exact(sec, self->x_);
1357  PyObject* result = PyList_New(0);
1358  for (Prop* p = nd->prop; p; p = p->next) {
1359  if (memb_func[p->type].is_point) {
1360  Point_process* pp = (Point_process*) p->dparam[1]._pvoid;
1361  PyObject* item = nrnpy_ho2po(pp->ob);
1362  int err = PyList_Append(result, item);
1363  assert(err == 0);
1364  Py_XDECREF(item);
1365  }
1366  }
1367  return result;
1368 }
1369 
1370 static PyObject* node_index1(NPySegObj* self) {
1371  Section* sec = self->pysec_->sec_;
1373  Node* nd = node_exact(sec, self->x_);
1374  PyObject* result = Py_BuildValue("i", nd->v_node_index);
1375  return result;
1376 }
1377 
1378 static PyObject* seg_area(NPySegObj* self) {
1379  Section* sec = self->pysec_->sec_;
1381  if (sec->recalc_area_) {
1382  nrn_area_ri(sec);
1383  }
1384  double x = self->x_;
1385  double a = 0.0;
1386  if (x > 0. && x < 1.) {
1387  Node* nd = node_exact(sec, x);
1388  a = NODEAREA(nd);
1389  }
1390  PyObject* result = Py_BuildValue("d", a);
1391  return result;
1392 }
1393 
1394 static inline double scaled_frustum_volume(double length, double d0, double d1) {
1395  // this is proportional to the volume of a frustum... need to multiply by pi/12
1396  return length * (d0 * d0 + d0 * d1 + d1 * d1);
1397 }
1398 
1399 static inline double interpolate(double x0, double x1, double y0, double y1, double xnew) {
1400  // computes ynew on the line between (x0, y0) and (x1, y1)
1401  // recall: y - y0 = m (x - x0)
1402  if (x1 == x0) {
1403  // avoid dividing by 0 if no length...
1404  return y0;
1405  } else {
1406  return y0 + (y1 - y0) * (xnew - x0) / (x1 - x0);
1407  }
1408 }
1409 
1410 static int arg_bisect_arc3d(Section* sec, int npt3d, double x) {
1411  // returns the index in sec where the arc is no more than x, but where the next points arc is
1412  // more right endpoint is never included
1413  int left = 0;
1414  int right = npt3d;
1415  while (right - left > 1) {
1416  int mid = (left + right) / 2;
1417  if (sec->pt3d[mid].arc < x) {
1418  left = mid;
1419  } else {
1420  right = mid;
1421  }
1422  }
1423  return left;
1424 }
1425 
1426 static PyObject* seg_volume(NPySegObj* self) {
1427  Section* sec = self->pysec_->sec_;
1429  int i;
1430  if (sec->recalc_area_) {
1431  nrn_area_ri(sec);
1432  }
1433  double x = self->x_;
1434  double a = 0.0;
1435  // volume only exists on the interior
1436  if (x > 0. && x < 1.) {
1437  // every section owns one extra node (the conservation node)
1438  int nseg = sec->nnode - 1;
1439  double length = section_length(sec) / nseg;
1440  int iseg = x * nseg;
1441  double seg_left_arc = iseg * length;
1442  double seg_right_arc = (iseg + 1) * length;
1443  if (sec->npt3d > 1) {
1444  int i_left = arg_bisect_arc3d(sec, sec->npt3d, seg_left_arc);
1445  double left_diam = fabs(sec->pt3d[i_left].d);
1446  double right_diam = fabs(sec->pt3d[i_left + 1].d);
1447  double left_arc = seg_left_arc;
1448  left_diam = interpolate(
1449  sec->pt3d[i_left].arc, sec->pt3d[i_left + 1].arc, left_diam, right_diam, left_arc);
1450 
1451  for (i = i_left + 1; i < sec->npt3d && sec->pt3d[i].arc < seg_right_arc; i++) {
1452  right_diam = fabs(sec->pt3d[i].d);
1453  a += scaled_frustum_volume(sec->pt3d[i].arc - left_arc, left_diam, right_diam);
1454  left_arc = sec->pt3d[i].arc;
1455  left_diam = right_diam;
1456  }
1457  if (i < sec->npt3d) {
1458  right_diam = interpolate(
1459  left_arc, sec->pt3d[i].arc, left_diam, fabs(sec->pt3d[i].d), seg_right_arc);
1460  a += scaled_frustum_volume(seg_right_arc - left_arc, left_diam, right_diam);
1461  }
1462 
1463  // the scaled_frustum_volume formula factored out a pi/12
1464  a *= M_PI / 12;
1465  } else {
1466  // 0 or 1 3D points... so give cylinder volume
1467  Node* nd = node_exact(sec, x);
1468  for (Prop* p = nd->prop; p; p = p->next) {
1469  if (p->type == MORPHOLOGY) {
1470  double diam = p->param[0];
1471  a = M_PI * diam * diam / 4 * length;
1472  break;
1473  }
1474  }
1475  }
1476  }
1477  PyObject* result = Py_BuildValue("d", a);
1478  return result;
1479 }
1480 
1481 
1482 static PyObject* seg_ri(NPySegObj* self) {
1483  Section* sec = self->pysec_->sec_;
1485  if (sec->recalc_area_) {
1486  nrn_area_ri(sec);
1487  }
1488  double ri = 1e30;
1489  Node* nd = node_exact(sec, self->x_);
1490  if (NODERINV(nd)) {
1491  ri = 1. / NODERINV(nd);
1492  }
1493  PyObject* result = Py_BuildValue("d", ri);
1494  return result;
1495 }
1496 
1498  // p must be in the pmech_types list. But I no longer know if that
1499  // is ever not the case.
1500  for (;;) {
1501  if (!p) {
1502  break;
1503  }
1504  // printf("segment_iter %d %s\n", p->type, memb_func[p->type].sym->name);
1505  if (PyDict_GetItemString(pmech_types, memb_func[p->type].sym->name)) {
1506  // printf("segment_iter found\n");
1507  break;
1508  }
1509  p = p->next;
1510  }
1511  return p;
1512 }
1513 
1514 static PyObject* mech_of_segment_iter(NPySegObj* self) {
1515  Section* sec = self->pysec_->sec_;
1516  if (!sec->prop) {
1517  PyErr_SetString(PyExc_ReferenceError, "nrn.Segment can't access a deleted section");
1518  return NULL;
1519  }
1520  // printf("mech_of_segment_iter\n");
1521  Node* nd = node_exact(sec, self->x_);
1522  Prop* p = mech_of_segment_prop(nd->prop);
1524  m->pyseg_ = self;
1525  Py_INCREF(m->pyseg_);
1526  m->prop_ = p;
1527  return (PyObject*) m;
1528 }
1529 
1530 static Object* seg_from_sec_x(Section* sec, double x) {
1531  PyObject* pyseg = (PyObject*) PyObject_New(NPySegObj, psegment_type);
1532  NPySegObj* pseg = (NPySegObj*) pyseg;
1533  NPySecObj* pysec = (NPySecObj*) sec->prop->dparam[PROP_PY_INDEX]._pvoid;
1534  if (pysec) {
1535  pseg->pysec_ = pysec;
1536  Py_INCREF(pysec);
1537  } else {
1538  pysec = (NPySecObj*) psection_type->tp_alloc(psection_type, 0);
1539  pysec->sec_ = sec;
1540  pysec->name_ = 0;
1541  pysec->cell_weakref_ = 0;
1542  Py_INCREF(pysec);
1543  pseg->pysec_ = pysec;
1544  }
1545  pseg->x_ = x;
1546  Object* ho = nrnpy_pyobject_in_obj(pyseg);
1547  Py_DECREF(pyseg);
1548  return ho;
1549 }
1550 
1551 static Object** pp_get_segment(void* vptr) {
1552  Point_process* pnt = (Point_process*) vptr;
1553  // printf("pp_get_segment %s\n", hoc_object_name(pnt->ob));
1554  Object* ho = NULL;
1555  if (pnt->prop) {
1556  Section* sec = pnt->sec;
1557  double x = nrn_arc_position(sec, pnt->node);
1558  ho = seg_from_sec_x(sec, x);
1559  }
1560  if (!ho) {
1561  ho = nrnpy_pyobject_in_obj(Py_None);
1562  }
1563  Object** tobj = hoc_temp_objptr(ho);
1564  --ho->refcount;
1565  return tobj;
1566 }
1567 
1568 static void rv_noexist(Section* sec, const char* n, double x, int err) {
1569  char buf[200];
1570  if (err == 2) {
1571  sprintf(buf, "%s was not made to point to anything at %s(%g)", n, secname(sec), x);
1572  } else if (err == 1) {
1573  sprintf(buf, "%s, the mechanism does not exist at %s(%g)", n, secname(sec), x);
1574  } else {
1575  sprintf(buf, "%s does not exist at %s(%g)", n, secname(sec), x);
1576  }
1577  PyErr_SetString(PyExc_AttributeError, buf);
1578 }
1579 
1580 static NPyRangeVar* rvnew(Symbol* sym, NPySecObj* sec, double x) {
1581  NPyRangeVar* r = PyObject_New(NPyRangeVar, range_type);
1582  r->pymech_ = PyObject_New(NPyMechObj, pmech_generic_type);
1583  r->pymech_->pyseg_ = PyObject_New(NPySegObj, psegment_type);
1584  r->pymech_->pyseg_->pysec_ = sec;
1585  Py_INCREF(sec);
1586  r->pymech_->pyseg_->x_ = 0.5;
1587  r->sym_ = sym;
1588  r->isptr_ = 0;
1589  r->attr_from_sec_ = 1;
1590  return r;
1591 }
1592 
1593 static PyObject* section_getattro(NPySecObj* self, PyObject* pyname) {
1594  Section* sec = self->sec_;
1596  PyObject* rv;
1597  Py_INCREF(pyname);
1598  Py2NRNString name(pyname);
1599  char* n = name.c_str();
1600  if (name.err()) {
1601  name.set_pyerr(PyExc_TypeError, "attribute name must be a string");
1602  Py_DECREF(pyname);
1603  return NULL;
1604  }
1605  // printf("section_getattr %s\n", n);
1606  PyObject* result = 0;
1607  if (strcmp(n, "L") == 0) {
1608  result = Py_BuildValue("d", section_length(sec));
1609  } else if (strcmp(n, "Ra") == 0) {
1610  result = Py_BuildValue("d", nrn_ra(sec));
1611  } else if (strcmp(n, "nseg") == 0) {
1612  result = Py_BuildValue("i", sec->nnode - 1);
1613  } else if ((rv = PyDict_GetItemString(rangevars_, n)) != NULL) {
1614  Symbol* sym = ((NPyRangeVar*) rv)->sym_;
1615  if (ISARRAY(sym)) {
1616  NPyRangeVar* r = rvnew(sym, self, 0.5);
1617  result = (PyObject*) r;
1618  } else {
1619  int err;
1620  double* d = nrnpy_rangepointer(sec, sym, 0.5, &err);
1621  if (!d) {
1622  rv_noexist(sec, n, 0.5, err);
1623  result = NULL;
1624  } else {
1625  if (sec->recalc_area_ && sym->u.rng.type == MORPHOLOGY) {
1626  nrn_area_ri(sec);
1627  }
1628  result = Py_BuildValue("d", *d);
1629  }
1630  }
1631  } else if (strcmp(n, "rallbranch") == 0) {
1632  result = Py_BuildValue("d", sec->prop->dparam[4].val);
1633  } else if (strcmp(n, "__dict__") == 0) {
1634  result = PyDict_New();
1635  int err = PyDict_SetItemString(result, "L", Py_None);
1636  assert(err == 0);
1637  err = PyDict_SetItemString(result, "Ra", Py_None);
1638  assert(err == 0);
1639  err = PyDict_SetItemString(result, "nseg", Py_None);
1640  assert(err == 0);
1641  err = PyDict_SetItemString(result, "rallbranch", Py_None);
1642  assert(err == 0);
1643  } else {
1644  result = PyObject_GenericGetAttr((PyObject*) self, pyname);
1645  }
1646  Py_DECREF(pyname);
1647  return result;
1648 }
1649 
1650 static int section_setattro(NPySecObj* self, PyObject* pyname, PyObject* value) {
1651  Section* sec = self->sec_;
1652  if (!sec->prop) {
1653  PyErr_SetString(PyExc_ReferenceError, "can't access a deleted section");
1654  return -1;
1655  }
1656  PyObject* rv;
1657  int err = 0;
1658  Py_INCREF(pyname);
1659  Py2NRNString name(pyname);
1660  char* n = name.c_str();
1661  if (name.err()) {
1662  name.set_pyerr(PyExc_TypeError, "attribute name must be a string");
1663  Py_DECREF(pyname);
1664  return -1;
1665  }
1666  // printf("section_setattro %s\n", n);
1667  if (strcmp(n, "L") == 0) {
1668  double x;
1669  if (PyArg_Parse(value, "d", &x) == 1 && x > 0.) {
1670  if (can_change_morph(sec)) {
1671  sec->prop->dparam[2].val = x;
1672  nrn_length_change(sec, x);
1673  diam_changed = 1;
1674  sec->recalc_area_ = 1;
1675  }
1676  } else {
1677  PyErr_SetString(PyExc_ValueError, "L must be > 0.");
1678  err = -1;
1679  }
1680  } else if (strcmp(n, "Ra") == 0) {
1681  double x;
1682  if (PyArg_Parse(value, "d", &x) == 1 && x > 0.) {
1683  sec->prop->dparam[7].val = x;
1684  diam_changed = 1;
1685  sec->recalc_area_ = 1;
1686  } else {
1687  PyErr_SetString(PyExc_ValueError, "Ra must be > 0.");
1688  err = -1;
1689  }
1690  } else if (strcmp(n, "nseg") == 0) {
1691  int nseg;
1692  if (PyArg_Parse(value, "i", &nseg) == 1 && nseg > 0 && nseg <= 32767) {
1693  nrn_change_nseg(sec, nseg);
1694  } else {
1695  PyErr_SetString(PyExc_ValueError, "nseg must be an integer in range 1 to 32767");
1696  err = -1;
1697  }
1698  // printf("section_setattro err=%d nseg=%d nnode\n", err, nseg,
1699  // sec->nnode);
1700  } else if ((rv = PyDict_GetItemString(rangevars_, n)) != NULL) {
1701  Symbol* sym = ((NPyRangeVar*) rv)->sym_;
1702  if (ISARRAY(sym)) {
1703  PyErr_SetString(PyExc_IndexError, "missing index");
1704  err = -1;
1705  } else {
1706  int errp;
1707  double* d = nrnpy_rangepointer(sec, sym, 0.5, &errp);
1708  if (!d) {
1709  rv_noexist(sec, n, 0.5, errp);
1710  err = -1;
1711  } else if (!PyArg_Parse(value, "d", d)) {
1712  PyErr_SetString(PyExc_ValueError, "bad value");
1713  err = -1;
1714  } else {
1715  // only need to do following if nseg > 1, VINDEX, or EXTRACELL
1716  nrn_rangeconst(sec, sym, d, 0);
1717  }
1718  }
1719  } else if (strcmp(n, "rallbranch") == 0) {
1720  double x;
1721  if (PyArg_Parse(value, "d", &x) == 1 && x > 0.) {
1722  sec->prop->dparam[4].val = x;
1723  diam_changed = 1;
1724  sec->recalc_area_ = 1;
1725  } else {
1726  PyErr_SetString(PyExc_ValueError, "rallbranch must be > 0");
1727  err = -1;
1728  }
1729  } else {
1730  err = PyObject_GenericSetAttr((PyObject*) self, pyname, value);
1731  }
1732  Py_DECREF(pyname);
1733  return err;
1734 }
1735 
1736 static PyObject* mech_of_seg_next(NPyMechOfSegIter* self) {
1737  // printf("mech_of_seg_next\n");
1738  Prop* p = mech_of_segment_prop(self->prop_);
1739  NPyMechObj* m = NULL;
1740  if (p) {
1741  m = PyObject_New(NPyMechObj, pmech_generic_type);
1742  }
1743  if (m == NULL) {
1744  return NULL;
1745  }
1746  m->pyseg_ = self->pyseg_;
1747  Py_INCREF(m->pyseg_);
1748  m->prop_ = p;
1749  self->prop_ = p->next;
1750  return (PyObject*) m;
1751 }
1752 
1753 static PyObject* var_of_mech_iter(NPyMechObj* self) {
1754  Section* sec = self->pyseg_->pysec_->sec_;
1755  if (!sec->prop) {
1756  PyErr_SetString(PyExc_ReferenceError, "nrn.Mechanism can't access a deleted section");
1757  return NULL;
1758  }
1759 
1760  // printf("var_of_mech_iter\n");
1762  if (!self->prop_) {
1763  return NULL;
1764  }
1765  vmi->pymech_ = self;
1766  Py_INCREF(vmi->pymech_);
1767  vmi->msym_ = memb_func[self->prop_->type].sym;
1768  vmi->i_ = 0;
1769  return (PyObject*) vmi;
1770 }
1771 
1772 static PyObject* var_of_mech_next(NPyVarOfMechIter* self) {
1773  if (self->i_ >= self->msym_->s_varn) {
1774  return NULL;
1775  }
1776  // printf("var_of_mech_next %d %s\n", self->i_, self->msym_->name);
1777  Symbol* sym = self->msym_->u.ppsym[self->i_];
1778  self->i_++;
1779  NPyRangeVar* r = (NPyRangeVar*) PyObject_New(NPyRangeVar, range_type);
1780  r->pymech_ = self->pymech_;
1781  Py_INCREF(r->pymech_);
1782  r->sym_ = sym;
1783  r->isptr_ = 0;
1784  r->attr_from_sec_ = 0;
1785  return (PyObject*) r;
1786 }
1787 
1788 static PyObject* segment_getattro(NPySegObj* self, PyObject* pyname) {
1789  Section* sec = self->pysec_->sec_;
1790  if (!sec->prop) {
1791  PyErr_SetString(PyExc_ReferenceError, "nrn.Segment can't access a deleted section");
1792  return NULL;
1793  }
1794  Symbol* sym;
1795  Py_INCREF(pyname);
1796  Py2NRNString name(pyname);
1797  char* n = name.c_str();
1798  if (name.err()) {
1799  name.set_pyerr(PyExc_TypeError, "attribute name must be a string");
1800  Py_DECREF(pyname);
1801  return NULL;
1802  }
1803  // printf("segment_getattr %s\n", n);
1804  PyObject* result = NULL;
1805  PyObject* otype = NULL;
1806  PyObject* rv = NULL;
1807  if (strcmp(n, "v") == 0) {
1808  Node* nd = node_exact(sec, self->x_);
1809  result = Py_BuildValue("d", NODEV(nd));
1810  } else if ((otype = PyDict_GetItemString(pmech_types, n)) != NULL) {
1811  int type = PyInt_AsLong(otype);
1812  // printf("segment_getattr type=%d\n", type);
1813  Node* nd = node_exact(sec, self->x_);
1814  Prop* p = nrn_mechanism(type, nd);
1815  if (!p) {
1816  rv_noexist(sec, n, self->x_, 1);
1817  result = NULL;
1818  } else {
1819  NPyMechObj* m = PyObject_New(NPyMechObj, pmech_generic_type);
1820  if (m == NULL) {
1821  result = NULL;
1822  } else {
1823  m->pyseg_ = self;
1824  m->prop_ = p;
1825  Py_INCREF(m->pyseg_);
1826  result = (PyObject*) m;
1827  }
1828  }
1829  } else if ((rv = PyDict_GetItemString(rangevars_, n)) != NULL) {
1830  sym = ((NPyRangeVar*) rv)->sym_;
1831  if (ISARRAY(sym)) {
1832  NPyRangeVar* r = PyObject_New(NPyRangeVar, range_type);
1833  r->pymech_ = PyObject_New(NPyMechObj, pmech_generic_type);
1834  r->pymech_->pyseg_ = self;
1835  Py_INCREF(r->pymech_->pyseg_);
1836  r->sym_ = sym;
1837  r->isptr_ = 0;
1838  r->attr_from_sec_ = 0;
1839  result = (PyObject*) r;
1840  } else {
1841  int err;
1842  double* d = nrnpy_rangepointer(sec, sym, self->x_, &err);
1843  if (!d) {
1844  rv_noexist(sec, n, self->x_, err);
1845  result = NULL;
1846  } else {
1847  if (sec->recalc_area_ && sym->u.rng.type == MORPHOLOGY) {
1848  nrn_area_ri(sec);
1849  }
1850  result = Py_BuildValue("d", *d);
1851  }
1852  }
1853  } else if (strncmp(n, "_ref_", 5) == 0) {
1854  if (strcmp(n + 5, "v") == 0) {
1855  Node* nd = node_exact(sec, self->x_);
1856  result = nrn_hocobj_ptr(&(NODEV(nd)));
1857  } else if ((sym = hoc_table_lookup(n + 5, hoc_built_in_symlist)) != 0 &&
1858  sym->type == RANGEVAR) {
1859  if (ISARRAY(sym)) {
1860  NPyRangeVar* r = PyObject_New(NPyRangeVar, range_type);
1861  r->pymech_ = PyObject_New(NPyMechObj, pmech_generic_type);
1862  r->pymech_->pyseg_ = self;
1863  Py_INCREF(self);
1864  r->sym_ = sym;
1865  r->isptr_ = 1;
1866  r->attr_from_sec_ = 0;
1867  result = (PyObject*) r;
1868  } else {
1869  int err;
1870  double* d = nrnpy_rangepointer(sec, sym, self->x_, &err);
1871  if (!d) {
1872  rv_noexist(sec, n + 5, self->x_, err);
1873  result = NULL;
1874  } else {
1875  result = nrn_hocobj_ptr(d);
1876  }
1877  }
1878  } else {
1879  rv_noexist(sec, n, self->x_, 2);
1880  result = NULL;
1881  }
1882  } else if (strcmp(n, "__dict__") == 0) {
1883  Node* nd = node_exact(sec, self->x_);
1884  result = PyDict_New();
1885  int err = PyDict_SetItemString(result, "v", Py_None);
1886  assert(err == 0);
1887  PyDict_SetItemString(result, "diam", Py_None);
1888  assert(err == 0);
1889  PyDict_SetItemString(result, "cm", Py_None);
1890  assert(err == 0);
1891  for (Prop* p = nd->prop; p; p = p->next) {
1892  if (p->type > CAP && !memb_func[p->type].is_point) {
1893  char* pn = memb_func[p->type].sym->name;
1894  err = PyDict_SetItemString(result, pn, Py_None);
1895  assert(err == 0);
1896  }
1897  }
1898  } else {
1899  result = PyObject_GenericGetAttr((PyObject*) self, pyname);
1900  }
1901  Py_DECREF(pyname);
1902  return result;
1903 }
1904 
1905 int nrn_pointer_assign(Prop* prop, Symbol* sym, PyObject* value) {
1906  int err = 0;
1907  if (sym->subtype == NRNPOINTER) {
1908  double* pd;
1909  double** ppd = &prop->dparam[sym->u.rng.index].pval;
1910  assert(ppd);
1911  if (nrn_is_hocobj_ptr(value, pd)) {
1912  *ppd = pd;
1913  } else {
1914  PyErr_SetString(PyExc_ValueError, "must be a hoc pointer");
1915  err = -1;
1916  }
1917  } else {
1918  PyErr_SetString(PyExc_AttributeError,
1919  " For assignment, only POINTER var can have a _ref_ prefix");
1920  err = -1;
1921  }
1922  return err;
1923 }
1924 
1925 static int segment_setattro(NPySegObj* self, PyObject* pyname, PyObject* value) {
1926  Section* sec = self->pysec_->sec_;
1927  if (!sec->prop) {
1928  PyErr_SetString(PyExc_ReferenceError, "nrn.Segment can't access a deleted section");
1929  return -1;
1930  }
1931  PyObject* rv;
1932  Symbol* sym;
1933  int err = 0;
1934  Py_INCREF(pyname);
1935  Py2NRNString name(pyname);
1936  char* n = name.c_str();
1937  if (name.err()) {
1938  name.set_pyerr(PyExc_TypeError, "attribute name must be a string");
1939  Py_DECREF(pyname);
1940  return -1;
1941  }
1942  // printf("segment_setattro %s\n", n);
1943  if (strcmp(n, "x") == 0) {
1944  int nseg;
1945  double x;
1946  if (PyArg_Parse(value, "d", &x) == 1 && x > 0. && x <= 1.) {
1947  if (x < 1e-9) {
1948  self->x_ = 0.;
1949  } else if (x > 1. - 1e-9) {
1950  self->x_ = 1.;
1951  } else {
1952  self->x_ = x;
1953  }
1954  } else {
1955  PyErr_SetString(PyExc_ValueError, "x must be in range 0. to 1.");
1956  err = -1;
1957  }
1958  } else if ((rv = PyDict_GetItemString(rangevars_, n)) != NULL) {
1959  sym = ((NPyRangeVar*) rv)->sym_;
1960  if (ISARRAY(sym)) {
1961  char s[200];
1962  sprintf(s, "%s needs an index for assignment", sym->name);
1963  PyErr_SetString(PyExc_IndexError, s);
1964  err = -1;
1965  } else {
1966  int errp;
1967  double* d = nrnpy_rangepointer(sec, sym, self->x_, &errp);
1968  if (!d) {
1969  rv_noexist(sec, n, self->x_, errp);
1970  Py_DECREF(pyname);
1971  return -1;
1972  }
1973  if (!PyArg_Parse(value, "d", d)) {
1974  PyErr_SetString(PyExc_ValueError, "bad value");
1975  Py_DECREF(pyname);
1976  return -1;
1977  } else if (sym->u.rng.type == MORPHOLOGY) {
1978  diam_changed = 1;
1979  sec->recalc_area_ = 1;
1981  } else if (sym->u.rng.type == EXTRACELL && sym->u.rng.index == 0) {
1982  // cannot execute because xraxial is an array
1983  diam_changed = 1;
1984  }
1985  }
1986  } else if (strncmp(n, "_ref_", 5) == 0) {
1988  if (rvsym && rvsym->type == RANGEVAR) {
1989  Node* nd = node_exact(sec, self->x_);
1990  assert(nd);
1991  Prop* prop = nrn_mechanism(rvsym->u.rng.type, nd);
1992  assert(prop);
1993  err = nrn_pointer_assign(prop, rvsym, value);
1994  } else {
1995  err = PyObject_GenericSetAttr((PyObject*) self, pyname, value);
1996  }
1997  } else {
1998  err = PyObject_GenericSetAttr((PyObject*) self, pyname, value);
1999  }
2000  Py_DECREF(pyname);
2001  return err;
2002 }
2003 
2004 static bool striptrail(char* buf, int sz, const char* n, const char* m) {
2005  int nlen = strlen(n);
2006  int mlen = strlen(m);
2007  int u = nlen - mlen - 1; // should be location of _
2008  if (u > 0 && n[u] == '_') { // likely n is name_m
2009  if (strcmp(n + (u + 1), m) != 0) {
2010  return false;
2011  }
2012  strncpy(buf, n, sz);
2013  buf[u] = '\0';
2014  return true;
2015  }
2016  return false;
2017 }
2018 
2019 static PyObject* mech_getattro(NPyMechObj* self, PyObject* pyname) {
2020  Section* sec = self->pyseg_->pysec_->sec_;
2021  if (!sec->prop) {
2022  PyErr_SetString(PyExc_ReferenceError, "nrn.Mechanism can't access a deleted section");
2023  return NULL;
2024  }
2025 
2026  Py_INCREF(pyname);
2027  Py2NRNString name(pyname);
2028  char* n = name.c_str();
2029  if (!n) {
2030  name.set_pyerr(PyExc_TypeError, "attribute name must be a string");
2031  Py_DECREF(pyname);
2032  return NULL;
2033  }
2034  // printf("mech_getattro %s\n", n);
2035  PyObject* result = NULL;
2036  NrnProperty np(self->prop_);
2037  int isptr = (strncmp(n, "_ref_", 5) == 0);
2038  char* mname = memb_func[self->prop_->type].sym->name;
2039  int mnamelen = strlen(mname);
2040  int bufsz = strlen(n) + mnamelen + 2;
2041  char* buf = new char[bufsz];
2042  if (nrn_is_ion(self->prop_->type)) {
2043  strcpy(buf, isptr ? n + 5 : n);
2044  } else {
2045  sprintf(buf, "%s_%s", isptr ? n + 5 : n, mname);
2046  }
2047  Symbol* sym = np.find(buf);
2048  if (sym) {
2049  // printf("mech_getattro sym %s\n", sym->name);
2050  if (ISARRAY(sym)) {
2051  NPyRangeVar* r = PyObject_New(NPyRangeVar, range_type);
2052  r->pymech_ = PyObject_New(NPyMechObj, pmech_generic_type);
2053  r->pymech_->pyseg_ = self->pyseg_;
2054  Py_INCREF(self->pyseg_);
2055  r->sym_ = sym;
2056  r->isptr_ = isptr;
2057  r->attr_from_sec_ = 0;
2058  result = (PyObject*) r;
2059  } else {
2060  double* px = np.prop_pval(sym, 0);
2061  if (!px) {
2062  rv_noexist(sec, sym->name, self->pyseg_->x_, 2);
2063  } else if (isptr) {
2064  result = nrn_hocobj_ptr(px);
2065  } else {
2066  result = Py_BuildValue("d", *px);
2067  }
2068  }
2069  } else if (strcmp(n, "__dict__") == 0) {
2070  result = PyDict_New();
2071  for (Symbol* s = np.first_var(); np.more_var(); s = np.next_var()) {
2072  if (!striptrail(buf, bufsz, s->name, mname)) {
2073  strcpy(buf, s->name);
2074  }
2075  int err = PyDict_SetItemString(result, buf, Py_None);
2076  assert(err == 0);
2077  }
2078  } else {
2079  result = PyObject_GenericGetAttr((PyObject*) self, pyname);
2080  }
2081  Py_DECREF(pyname);
2082  delete[] buf;
2083  return result;
2084 }
2085 
2086 static int mech_setattro(NPyMechObj* self, PyObject* pyname, PyObject* value) {
2087  Section* sec = self->pyseg_->pysec_->sec_;
2088  if (!sec->prop) {
2089  PyErr_SetString(PyExc_ReferenceError, "nrn.Mechanism can't access a deleted section");
2090  return -1;
2091  }
2092 
2093  int err = 0;
2094  Py_INCREF(pyname);
2095  Py2NRNString name(pyname);
2096  char* n = name.c_str();
2097  if (name.err()) {
2098  name.set_pyerr(PyExc_TypeError, "attribute name must be a string");
2099  Py_DECREF(pyname);
2100  return -1;
2101  }
2102  // printf("mech_setattro %s\n", n);
2103  NrnProperty np(self->prop_);
2104  int isptr = (strncmp(n, "_ref_", 5) == 0);
2105  char* mname = memb_func[self->prop_->type].sym->name;
2106  int mnamelen = strlen(mname);
2107  int bufsz = strlen(n) + mnamelen + 2;
2108  char* buf = new char[bufsz];
2109  if (nrn_is_ion(self->prop_->type)) {
2110  strcpy(buf, isptr ? n + 5 : n);
2111  } else {
2112  sprintf(buf, "%s_%s", isptr ? n + 5 : n, mname);
2113  }
2114  Symbol* sym = np.find(buf);
2115  delete[] buf;
2116  if (sym) {
2117  if (isptr) {
2118  err = nrn_pointer_assign(self->prop_, sym, value);
2119  } else {
2120  double x;
2121  double* pd = np.prop_pval(sym, 0);
2122  if (pd) {
2123  if (PyArg_Parse(value, "d", &x) == 1) {
2124  *pd = x;
2125  } else {
2126  PyErr_SetString(PyExc_ValueError, "must be a double");
2127  err = -1;
2128  }
2129  } else {
2130  rv_noexist(sec, sym->name, self->pyseg_->x_, 2);
2131  err = 1;
2132  }
2133  }
2134  } else {
2135  err = PyObject_GenericSetAttr((PyObject*) self, pyname, value);
2136  }
2137  Py_DECREF(pyname);
2138  return err;
2139 }
2140 
2141 double** nrnpy_setpointer_helper(PyObject* pyname, PyObject* mech) {
2142  if (PyObject_TypeCheck(mech, pmech_generic_type) == 0) {
2143  return NULL;
2144  }
2145  NPyMechObj* m = (NPyMechObj*) mech;
2146  NrnProperty np(m->prop_);
2147  char buf[200];
2148  Py2NRNString name(pyname);
2149  char* n = name.c_str();
2150  if (!n) {
2151  return NULL;
2152  }
2153  sprintf(buf, "%s_%s", n, memb_func[m->prop_->type].sym->name);
2154  Symbol* sym = np.find(buf);
2155  if (!sym || sym->type != RANGEVAR || sym->subtype != NRNPOINTER) {
2156  return 0;
2157  }
2158  return &m->prop_->dparam[np.prop_index(sym)].pval;
2159 }
2160 
2161 static PyObject* NPySecObj_call(NPySecObj* self, PyObject* args) {
2162  CHECK_SEC_INVALID(self->sec_);
2163  double x = 0.5;
2164  PyArg_ParseTuple(args, "|d", &x);
2165  PyObject* segargs = Py_BuildValue("(O,d)", self, x);
2166  PyObject* seg = NPySegObj_new(psegment_type, segargs, 0);
2167  Py_DECREF(segargs);
2168  return seg;
2169 }
2170 
2171 static Py_ssize_t rv_len(PyObject* self) {
2172  NPyRangeVar* r = (NPyRangeVar*) self;
2173  assert(r->sym_);
2174  if (r->sym_->arayinfo) {
2175  assert(r->sym_->arayinfo->nsub == 1);
2176  return r->sym_->arayinfo->sub[0];
2177  }
2178  return 1;
2179 }
2180 static PyObject* rv_getitem(PyObject* self, Py_ssize_t ix) {
2181  NPyRangeVar* r = (NPyRangeVar*) self;
2182  Section* sec = r->pymech_->pyseg_->pysec_->sec_;
2183  if (!sec->prop) {
2184  PyErr_SetString(PyExc_ReferenceError, "nrn.RangeVar can't access a deleted section");
2185  return NULL;
2186  }
2187 
2188  PyObject* result = NULL;
2189  if (ix < 0 || ix >= rv_len(self)) {
2190  PyErr_SetString(PyExc_IndexError, r->sym_->name);
2191  return NULL;
2192  }
2193  int err;
2194  double* d = nrnpy_rangepointer(sec, r->sym_, r->pymech_->pyseg_->x_, &err);
2195  if (!d) {
2196  rv_noexist(sec, r->sym_->name, r->pymech_->pyseg_->x_, err);
2197  return NULL;
2198  }
2199  d += ix;
2200  if (r->isptr_) {
2201  result = nrn_hocobj_ptr(d);
2202  } else {
2203  result = Py_BuildValue("d", *d);
2204  }
2205  return result;
2206 }
2207 static int rv_setitem(PyObject* self, Py_ssize_t ix, PyObject* value) {
2208  NPyRangeVar* r = (NPyRangeVar*) self;
2209  Section* sec = r->pymech_->pyseg_->pysec_->sec_;
2210  if (!sec->prop) {
2211  PyErr_SetString(PyExc_ReferenceError, "nrn.RangeVar can't access a deleted section");
2212  return -1;
2213  }
2214 
2215  if (ix < 0 || ix >= rv_len(self)) {
2216  PyErr_SetString(PyExc_IndexError, r->sym_->name);
2217  return -1;
2218  }
2219  int err;
2220  double* d = nrnpy_rangepointer(sec, r->sym_, r->pymech_->pyseg_->x_, &err);
2221  if (!d) {
2222  rv_noexist(sec, r->sym_->name, r->pymech_->pyseg_->x_, err);
2223  return -1;
2224  }
2225  if (r->attr_from_sec_) {
2226  // the range variable array is from a section not a segment and so
2227  // assignment is over the entire section.
2228  double x;
2229  if (!PyArg_Parse(value, "d", &x)) {
2230  PyErr_SetString(PyExc_ValueError, "bad value");
2231  return -1;
2232  }
2233  hoc_pushx(double(ix));
2234  nrn_rangeconst(r->pymech_->pyseg_->pysec_->sec_, r->sym_, &x, 0);
2235  } else {
2236  d += ix;
2237  if (!PyArg_Parse(value, "d", d)) {
2238  PyErr_SetString(PyExc_ValueError, "bad value");
2239  return -1;
2240  }
2241  }
2242  if (r->sym_->u.rng.type == EXTRACELL && r->sym_->u.rng.index == 0) {
2243  diam_changed = 1;
2244  }
2245  return 0;
2246 }
2247 
2248 static PyMethodDef NPySecObj_methods[] = {
2249  {"name", (PyCFunction) NPySecObj_name, METH_NOARGS, "Section name (same as hoc secname())"},
2250  {"hname", (PyCFunction) NPySecObj_name, METH_NOARGS, "Section name (same as hoc secname())"},
2251  {"has_membrane",
2252  (PyCFunction) NPySecObj_has_membrane,
2253  METH_VARARGS,
2254  "Returns True if the section's membrane has this density mechanism.\nThis "
2255  "is not for point processes."},
2256  {"connect",
2257  (PyCFunction) NPySecObj_connect,
2258  METH_VARARGS,
2259  "childSection.connect(parentSection, [parentX], [childEnd]) "
2260  "or\nchildSection.connect(parentSegment, [childEnd])"},
2261  {"insert",
2262  (PyCFunction) NPySecObj_insert,
2263  METH_VARARGS,
2264  "section.insert(densityMechanismName) e.g. soma.insert('hh')"},
2265  {"uninsert",
2266  (PyCFunction) NPySecObj_uninsert,
2267  METH_VARARGS,
2268  "section.uninsert(densityMechanismName) e.g. soma.insert('hh')"},
2269  {"push",
2270  (PyCFunction) NPySecObj_push,
2271  METH_VARARGS,
2272  "section.push() makes it the currently accessed section. Should end with "
2273  "a corresponding hoc.pop_section()"},
2274  {"allseg",
2275  (PyCFunction) allseg,
2276  METH_VARARGS,
2277  "iterate over segments. Includes x=0 and x=1 zero-area nodes in the "
2278  "iteration."},
2279  {"cell",
2280  (PyCFunction) pysec2cell,
2281  METH_NOARGS,
2282  "Return the object that owns the Section. Possibly None."},
2283  {"same",
2284  (PyCFunction) pysec_same,
2285  METH_VARARGS,
2286  "sec1.same(sec2) returns True if sec1 and sec2 wrap the same NEURON "
2287  "Section"},
2288  {"hoc_internal_name",
2289  (PyCFunction) hoc_internal_name,
2290  METH_NOARGS,
2291  "Hoc accepts this name wherever a section is syntactically valid."},
2292  {"disconnect",
2293  (PyCFunction) pysec_disconnect,
2294  METH_NOARGS,
2295  "disconnect from the parent section."},
2296  {"parentseg",
2297  (PyCFunction) pysec_parentseg,
2298  METH_NOARGS,
2299  "Return the nrn.Segment specified by the connect method. Possibly None."},
2300  {"trueparentseg",
2301  (PyCFunction) pysec_trueparentseg,
2302  METH_NOARGS,
2303  "Return the nrn.Segment this section connects to which is closer to the "
2304  "root. Possibly None. (same as parentseg unless parentseg.x == "
2305  "parentseg.sec.orientation()"},
2306  {"orientation",
2307  (PyCFunction) pysec_orientation,
2308  METH_NOARGS,
2309  "Returns 0.0 or 1.0 depending on the x value closest to parent."},
2310  {"children",
2311  (PyCFunction) pysec_children,
2312  METH_NOARGS,
2313  "Return list of child sections. Possibly an empty list"},
2314  {"subtree",
2315  (PyCFunction) pysec_subtree,
2316  METH_NOARGS,
2317  "Return list of sections in the subtree rooted at this section (including this section)."},
2318  {"wholetree",
2319  (PyCFunction) pysec_wholetree,
2320  METH_NOARGS,
2321  "Return list of all sections with a path to this section (including this section). The list "
2322  "has the important property that sections are in root to leaf order, depth-first traversal."},
2323  {"n3d", (PyCFunction) NPySecObj_n3d, METH_NOARGS, "Returns the number of 3D points."},
2324  {"x3d",
2325  (PyCFunction) NPySecObj_x3d,
2326  METH_VARARGS,
2327  "Returns the x coordinate of the ith 3D point."},
2328  {"y3d",
2329  (PyCFunction) NPySecObj_y3d,
2330  METH_VARARGS,
2331  "Returns the y coordinate of the ith 3D point."},
2332  {"z3d",
2333  (PyCFunction) NPySecObj_z3d,
2334  METH_VARARGS,
2335  "Returns the z coordinate of the ith 3D point."},
2336  {"arc3d",
2337  (PyCFunction) NPySecObj_arc3d,
2338  METH_VARARGS,
2339  "Returns the arc position of the ith 3D point."},
2340  {"diam3d",
2341  (PyCFunction) NPySecObj_diam3d,
2342  METH_VARARGS,
2343  "Returns the diam of the ith 3D point."},
2344  {"spine3d",
2345  (PyCFunction) NPySecObj_spine3d,
2346  METH_VARARGS,
2347  "Returns True or False depending on whether a spine exists at the ith 3D point."},
2348  {"pt3dremove", (PyCFunction) NPySecObj_pt3dremove, METH_VARARGS, "Removes the ith 3D point."},
2349  {"pt3dclear",
2350  (PyCFunction) NPySecObj_pt3dclear,
2351  METH_VARARGS,
2352  "Clears all 3D points. Optionally takes a buffer size."},
2353  {"pt3dinsert",
2354  (PyCFunction) NPySecObj_pt3dinsert,
2355  METH_VARARGS,
2356  "Insert the point (so it becomes the i'th point) to section. If i is equal to sec.n3d(), the "
2357  "point is appended (equivalent to sec.pt3dadd())"},
2358  {"pt3dchange",
2359  (PyCFunction) NPySecObj_pt3dchange,
2360  METH_VARARGS,
2361  "Change the i'th 3-d point info. If only two args then the second arg is the diameter and the "
2362  "location is unchanged."},
2363  {"pt3dadd",
2364  (PyCFunction) NPySecObj_pt3dadd,
2365  METH_VARARGS,
2366  "Add the 3d location and diameter point (or points in the second form) at the end of the "
2367  "current pt3d list. Assume that successive additions increase the arc length monotonically."},
2368  {"pt3dstyle",
2369  (PyCFunction) NPySecObj_pt3dstyle,
2370  METH_VARARGS,
2371  "Returns True if using a logical connection point, else False. With first arg 0 sets to no "
2372  "logical connection point. With first arg 1 and x, y, z arguments, sets the logical "
2373  "connection point. Return value includes the result of any setting."},
2374  {"is_pysec",
2375  (PyCFunction) is_pysec,
2376  METH_NOARGS,
2377  "Returns True if Section created from Python, False if created from HOC."},
2378  {"psection",
2379  (PyCFunction) NPySecObj_psection,
2380  METH_NOARGS,
2381  "Returns dict of info about Section contents."},
2382  {NULL}};
2383 
2384 static PyMethodDef NPySegObj_methods[] = {
2385  {"point_processes",
2386  (PyCFunction) seg_point_processes,
2387  METH_NOARGS,
2388  "seg.point_processes() returns list of POINT_PROCESS instances in the "
2389  "segment."},
2390  {"node_index",
2391  (PyCFunction) node_index1,
2392  METH_NOARGS,
2393  "seg.node_index() returns index of v, rhs, etc. in the _actual arrays of "
2394  "the appropriate NrnThread."},
2395  {"area",
2396  (PyCFunction) seg_area,
2397  METH_NOARGS,
2398  "Segment area (um2) (same as h.area(sec(x), sec=sec))"},
2399  {"ri",
2400  (PyCFunction) seg_ri,
2401  METH_NOARGS,
2402  "Segment resistance to parent segment (Megohms) (same as h.ri(sec(x), "
2403  "sec=sec))"},
2404  {"volume", (PyCFunction) seg_volume, METH_NOARGS, "Segment volume (um3)"},
2405  {NULL}};
2406 
2407 // I'm guessing Python should change their typedef to get rid of the
2408 // four "deprecated conversion from string constant to 'char*'" warnings.
2409 // Could avoid by casting each to (char*) but probably better to keep the
2410 // warnings. For now we get rid of the warnings by copying the string to
2411 // char array.
2412 static char* cpstr(const char* s) {
2413  char* s2 = new char[strlen(s) + 1];
2414  strcpy(s2, s);
2415  return s2;
2416 }
2417 static PyMemberDef NPySegObj_members[] = {
2418  {cpstr("x"),
2419  T_DOUBLE,
2420  offsetof(NPySegObj, x_),
2421  0,
2422  cpstr("location in the section (segment containing x)")},
2423  {cpstr("sec"), T_OBJECT_EX, offsetof(NPySegObj, pysec_), 0, cpstr("Section")},
2424  {NULL}};
2425 
2426 static PyMethodDef NPyMechObj_methods[] = {
2427  {"name",
2428  (PyCFunction) NPyMechObj_name,
2429  METH_NOARGS,
2430  "Mechanism name (same as hoc suffix for density mechanism)"},
2431  {"is_ion", (PyCFunction) NPyMechObj_is_ion, METH_NOARGS, "Returns True if an ion mechanism"},
2432  {"segment",
2433  (PyCFunction) NPyMechObj_segment,
2434  METH_NOARGS,
2435  "Returns the segment of the Mechanism instance"},
2436  {NULL}};
2437 
2438 static PyMethodDef NPyRangeVar_methods[] = {
2439  {"name", (PyCFunction) NPyRangeVar_name, METH_NOARGS, "Range variable name name"},
2440  {"mech",
2441  (PyCFunction) NPyRangeVar_mech,
2442  METH_NOARGS,
2443  "Returns nrn.Mechanism of the RangeVariable instance"},
2444  {NULL}};
2445 
2446 static PyMemberDef NPyMechObj_members[] = {{NULL}};
2447 
2448 PyObject* nrnpy_cas(PyObject* self, PyObject* args) {
2450  if (!sec) {
2451  PyErr_SetString(PyExc_TypeError, "Section access unspecified");
2452  return NULL;
2453  }
2454  // printf("nrnpy_cas %s\n", secname(sec));
2455  return (PyObject*) newpysechelp(sec);
2456 }
2457 
2458 static PyMethodDef nrnpy_methods[] = {
2459  {"cas", nrnpy_cas, METH_VARARGS, "Return the currently accessed section."},
2460  {"allsec", nrnpy_forall, METH_VARARGS, "Return iterator over all sections."},
2461  {"set_psection",
2463  METH_VARARGS,
2464  "Specify the nrn.Section.psection callback."},
2465  {NULL}};
2466 
2467 #include "nrnpy_nrn.h"
2468 
2469 static PyObject* nrnmodule_;
2470 
2471 static void rangevars_add(Symbol* sym) {
2472  assert(sym && sym->type == RANGEVAR);
2473  NPyRangeVar* r = PyObject_New(NPyRangeVar, range_type);
2474  // printf("%s\n", sym->name);
2475  r->sym_ = sym;
2476  r->isptr_ = 0;
2477  r->attr_from_sec_ = 0;
2478  PyDict_SetItemString(rangevars_, sym->name, (PyObject*) r);
2479 }
2480 
2481 PyObject* nrnpy_nrn(void) {
2482  int i;
2483  PyObject* m;
2484 
2485  int err = 0;
2486  PyObject* modules = PyImport_GetModuleDict();
2487  if ((m = PyDict_GetItemString(modules, "nrn")) != NULL && PyModule_Check(m)) {
2488  return m;
2489  }
2490  psection_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_SectionType_spec);
2491  psection_type->tp_new = PyType_GenericNew;
2492  if (PyType_Ready(psection_type) < 0)
2493  goto fail;
2494  Py_INCREF(psection_type);
2495 
2496  pallseg_of_sec_iter_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_AllSegOfSecIterType_spec);
2497  pseg_of_sec_iter_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_SegOfSecIterType_spec);
2498  pallseg_of_sec_iter_type->tp_new = PyType_GenericNew;
2499  pseg_of_sec_iter_type->tp_new = PyType_GenericNew;
2500  if (PyType_Ready(pallseg_of_sec_iter_type) < 0)
2501  goto fail;
2502  if (PyType_Ready(pseg_of_sec_iter_type) < 0)
2503  goto fail;
2504  Py_INCREF(pallseg_of_sec_iter_type);
2505  Py_INCREF(pseg_of_sec_iter_type);
2506 
2507  psegment_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_SegmentType_spec);
2508  psegment_type->tp_new = PyType_GenericNew;
2509  if (PyType_Ready(psegment_type) < 0)
2510  goto fail;
2511  if (PyType_Ready(pallseg_of_sec_iter_type) < 0)
2512  goto fail;
2513  if (PyType_Ready(pseg_of_sec_iter_type) < 0)
2514  goto fail;
2515  Py_INCREF(psegment_type);
2516  Py_INCREF(pallseg_of_sec_iter_type);
2517  Py_INCREF(pseg_of_sec_iter_type);
2518 
2519  range_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_RangeType_spec);
2520  range_type->tp_new = PyType_GenericNew;
2521  if (PyType_Ready(range_type) < 0)
2522  goto fail;
2523  Py_INCREF(range_type);
2524 
2525  m = PyModule_Create(&nrnsectionmodule); // like nrn but namespace will not include mechanims.
2526  PyModule_AddObject(m, "Section", (PyObject*) psection_type);
2527  PyModule_AddObject(m, "Segment", (PyObject*) psegment_type);
2528 
2529  err = PyDict_SetItemString(modules, "_neuron_section", m);
2530  assert(err == 0);
2531  Py_DECREF(m);
2532  m = PyModule_Create(&nrnmodule); //
2533  nrnmodule_ = m;
2534  PyModule_AddObject(m, "Section", (PyObject*) psection_type);
2535  PyModule_AddObject(m, "Segment", (PyObject*) psegment_type);
2536 
2537  pmech_generic_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_MechanismType_spec);
2538  pmech_of_seg_iter_generic_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_MechOfSegIterType_spec);
2539  pvar_of_mech_iter_generic_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_VarOfMechIterType_spec);
2540  pmech_generic_type->tp_new = PyType_GenericNew;
2541  pmech_of_seg_iter_generic_type->tp_new = PyType_GenericNew;
2542  pvar_of_mech_iter_generic_type->tp_new = PyType_GenericNew;
2543  if (PyType_Ready(pmech_generic_type) < 0)
2544  goto fail;
2545  if (PyType_Ready(pmech_of_seg_iter_generic_type) < 0)
2546  goto fail;
2547  if (PyType_Ready(pvar_of_mech_iter_generic_type) < 0)
2548  goto fail;
2549  Py_INCREF(pmech_generic_type);
2550  Py_INCREF(pmech_of_seg_iter_generic_type);
2551  Py_INCREF(pvar_of_mech_iter_generic_type);
2552  PyModule_AddObject(m, "Mechanism", (PyObject*) pmech_generic_type);
2553  PyModule_AddObject(m, "MechOfSegIterator", (PyObject*) pmech_of_seg_iter_generic_type);
2554  PyModule_AddObject(m, "VarOfMechIterator", (PyObject*) pvar_of_mech_iter_generic_type);
2565 
2566  err = PyDict_SetItemString(modules, "nrn", m);
2567  assert(err == 0);
2568  Py_DECREF(m);
2569  return m;
2570 fail:
2571  return NULL;
2572 }
2573 
2575  int i;
2576  Py_XDECREF(pmech_types);
2577  Py_XDECREF(rangevars_);
2578  pmech_types = PyDict_New();
2579  rangevars_ = PyDict_New();
2585  for (i = 4; i < n_memb_func; ++i) { // start at pas
2586  nrnpy_reg_mech(i);
2587  }
2588 }
2589 
2591  int i;
2592  char* s;
2593  Memb_func* mf = memb_func + type;
2594  if (!nrnmodule_) {
2595  return;
2596  }
2597  if (mf->is_point) {
2598  if (nrn_is_artificial_[type] == 0) {
2600  Symbol* s = hoc_table_lookup("get_segment", sl);
2601  if (!s) {
2602  s = hoc_install("get_segment", OBFUNCTION, 0, &sl);
2603  s->cpublic = 1;
2604 #if MAC
2605  s->u.u_proc->defn.pfo = (Object * *(*) (...)) pp_get_segment;
2606 #else
2607  s->u.u_proc->defn.pfo = (Object * *(*) ()) pp_get_segment;
2608 #endif
2609  }
2610  }
2611  return;
2612  }
2613  s = mf->sym->name;
2614  // printf("nrnpy_reg_mech %s %d\n", s, type);
2615  if (PyDict_GetItemString(pmech_types, s)) {
2616  hoc_execerror(s, "mechanism already exists");
2617  }
2618  Py_INCREF(pmech_generic_type);
2619  PyModule_AddObject(nrnmodule_, s, (PyObject*) pmech_generic_type);
2620  PyDict_SetItemString(pmech_types, s, Py_BuildValue("i", type));
2621  for (i = 0; i < mf->sym->s_varn; ++i) {
2622  Symbol* sym = mf->sym->u.ppsym[i];
2623  rangevars_add(sym);
2624  }
2625 }
2626 
2628  // not implemented but needed when KSChan name changed.
2629 }
double nrn_section_orientation(Section *sec)
Definition: cabcode.cpp:1644
const char * secname(Section *sec)
Definition: cabcode.cpp:1776
void nrn_rangeconst(Section *sec, Symbol *s, double *pd, int op)
Definition: cabcode.cpp:958
void nrn_pushsec(Section *sec)
Definition: cabcode.cpp:99
double nrn_arc_position(Section *sec, Node *node)
Definition: cabcode.cpp:1867
Prop * nrn_mechanism(int type, Node *nd)
Definition: cabcode.cpp:1079
double nrn_connection_position(Section *sec)
Definition: cabcode.cpp:1639
void nrn_disconnect(Section *sec)
Definition: cabcode.cpp:594
Node * node_exact(Section *sec, double x)
Definition: cabcode.cpp:1940
int nrn_at_beginning(Section *sec)
Definition: cabcode.cpp:1648
Memb_func * memb_func
Definition: init.cpp:123
short type
Definition: cabvars.h:9
int prop_index(const Symbol *) const
Definition: ndatclas.cpp:215
Symbol * find(const char *rangevar)
Definition: ndatclas.cpp:203
double * prop_pval(const Symbol *, int arrayindex=0) const
Definition: ndatclas.cpp:223
Symbol * first_var()
Definition: ndatclas.cpp:127
Symbol * next_var()
Definition: ndatclas.cpp:140
bool more_var()
Definition: ndatclas.cpp:132
bool err() const
Definition: nrnpy_utils.h:45
char * c_str() const
Definition: nrnpy_utils.h:42
void set_pyerr(PyObject *type, const char *message)
Definition: nrnpy_utils.h:48
Symbol * hoc_table_lookup(const char *, Symlist *)
Definition: symbol.cpp:61
int nrn_is_ion(int)
Definition: eion.cpp:51
sprintf(buf, " if (secondorder) {\n" " int _i;\n" " for (_i = 0; _i < %d; ++_i) {\n" " _p[_slist%d[_i]] += dt*_p[_dlist%d[_i]];\n" " }}\n", numeqn, listnum, listnum)
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:754
char buf[512]
Definition: init.cpp:13
void hoc_execerr_ext(const char *fmt,...)
printf style specification of hoc_execerror message.
Definition: fileio.cpp:931
Symbol * hoc_install(const char *, int, double, Symlist **)
#define assert(ex)
Definition: hocassrt.h:32
#define ISARRAY(arg)
Definition: hocdec.h:164
void
void hoc_pushx(double)
static int narg()
Definition: ivocvect.cpp:150
Object ** hoc_temp_objptr(Object *)
Definition: code.cpp:216
#define sec
Definition: md1redef.h:13
#define i
Definition: md1redef.h:12
#define prop
Definition: md1redef.h:29
#define CAP
Definition: membfunc.h:64
#define MORPHOLOGY
Definition: membfunc.h:63
fabs
Definition: extdef.h:3
char * name
Definition: init.cpp:16
void ri()
#define NRNPOINTER
Definition: nocpout.cpp:100
void section_ref(Section *)
Definition: solve.cpp:575
void section_unref(Section *)
Definition: solve.cpp:565
int const size_t const size_t n
Definition: nrngsl.h:11
if(status)
size_t p
int n_memb_func
Definition: init.cpp:440
static PyTypeObject * pseg_of_sec_iter_type
Definition: nrnpy_nrn.cpp:81
static void nrnpy_unreg_mech(int)
Definition: nrnpy_nrn.cpp:2627
Section *(* nrnpy_o2sec_p_)(Object *)
Definition: seclist.cpp:21
static PyObject * NPySecObj_pt3dstyle(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:659
int diam_changed
Definition: cabcode.cpp:23
static PyObject * NPySecObj_pt3dinsert(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:631
Object *(* nrnpy_pysec_cell_p_)(Section *)
Definition: cabcode.cpp:30
void stor_pt3d(Section *sec, double x, double y, double z, double d)
Definition: treeset.cpp:1362
static PyObject * pysec_wholetree(NPySecObj *const self)
Definition: nrnpy_nrn.cpp:995
PyObject * nrnpy_cas(PyObject *self, PyObject *args)
Definition: nrnpy_nrn.cpp:2448
void nrn_pt3dremove(Section *sec, int i0)
Definition: treeset.cpp:1191
static PyObject * NPySecObj_pt3dremove(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:566
static PyObject * pysec_richcmp(NPySecObj *self, PyObject *other, int op)
Definition: nrnpy_nrn.cpp:1044
short * nrn_is_artificial_
Definition: init.cpp:193
static PyObject * nrnmodule_
Definition: nrnpy_nrn.cpp:2469
static void o2loc2(Object *o, Section **psec, double *px)
Definition: nrnpy_nrn.cpp:492
static PyObject * nrnpy_set_psection(PyObject *self, PyObject *args)
Definition: nrnpy_nrn.cpp:827
static PyObject * var_of_mech_next(NPyVarOfMechIter *self)
Definition: nrnpy_nrn.cpp:1772
static PyObject * seg_of_section_iter(NPySecObj *self)
Definition: nrnpy_nrn.cpp:1278
static PyTypeObject * pmech_of_seg_iter_generic_type
Definition: nrnpy_nrn.cpp:83
static PyObject * pysec_subtree1(PyObject *const sl, Section *const sec)
Definition: nrnpy_nrn.cpp:973
static PyTypeObject * pmech_generic_type
Definition: nrnpy_nrn.cpp:84
static PyObject * pysec_orientation(NPySecObj *self)
Definition: nrnpy_nrn.cpp:936
static PyObject * pysec_trueparentseg(NPySecObj *self)
Definition: nrnpy_nrn.cpp:912
void nrn_pt3dinsert(Section *sec, int i0, double x, double y, double z, double d)
Definition: treeset.cpp:1134
Object * nrnpy_pyobject_in_obj(PyObject *)
Definition: nrnpy_p2h.cpp:210
static void NPySecObj_dealloc(NPySecObj *self)
Definition: nrnpy_nrn.cpp:205
static PyMethodDef NPySegObj_methods[]
Definition: nrnpy_nrn.cpp:2384
static PyObject * pysec_same(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1062
static Object * seg_from_sec_x(Section *, double x)
Definition: nrnpy_nrn.cpp:1530
Object * nrnpy_po2ho(PyObject *)
Definition: nrnpy_hoc.cpp:520
static PyObject * NPySecObj_insert(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1182
static PyObject * pysec_parentseg(NPySecObj *self)
Definition: nrnpy_nrn.cpp:901
PyTypeObject * psection_type
Definition: nrnpy_nrn.cpp:79
static PyObject * mech_of_segment_iter(NPySegObj *self)
Definition: nrnpy_nrn.cpp:1514
static PyObject * NPySecObj_spine3d(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:777
static PyObject * NPyMechObj_name(NPyMechObj *self)
Definition: nrnpy_nrn.cpp:1074
static bool lappendsec(PyObject *const sl, Section *const s)
Definition: nrnpy_nrn.cpp:942
double * nrnpy_rangepointer(Section *, Symbol *, double, int *)
Definition: cabcode.cpp:1375
static PyObject * pysec_children(NPySecObj *const self)
Definition: nrnpy_nrn.cpp:963
static PyObject * NPySecObj_push(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1271
static PyObject * NPySecObj_uninsert(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1227
static PyObject * section_getattro(NPySecObj *self, PyObject *pyname)
Definition: nrnpy_nrn.cpp:1593
void(* nrnpy_o2loc2_p_)(Object *, Section **, double *)
Definition: point.cpp:30
static void o2loc(Object *, Section **, double *)
Definition: nrnpy_nrn.cpp:475
Symbol * nrnpy_pyobj_sym_
static PyObject * NPySecObj_pt3dchange(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:600
Section * nrn_noerr_access()
Definition: cabcode.cpp:472
static PyObject * pyseg_repr(PyObject *p)
Definition: nrnpy_nrn.cpp:805
static PyObject * NPySecObj_connect(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1137
static int NPySegObj_init(NPySegObj *self, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:429
static Py_ssize_t rv_len(PyObject *self)
Definition: nrnpy_nrn.cpp:2171
static int NPyAllSegOfSecIter_init(NPyAllSegOfSecIter *self, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:333
static int NPyMechObj_init(NPyMechObj *self, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:538
PyObject * nrnpy_hoc2pyobject(Object *)
Definition: nrnpy_p2h.cpp:196
static PyObject * pysec_subtree(NPySecObj *const self)
Definition: nrnpy_nrn.cpp:985
static PyObject * nrnpy_psection
Definition: nrnpy_nrn.cpp:826
static PyObject * pysec2cell(NPySecObj *)
Definition: nrnpy_nrn.cpp:1008
static int section_setattro(NPySecObj *self, PyObject *pyname, PyObject *value)
Definition: nrnpy_nrn.cpp:1650
static int segment_setattro(NPySegObj *self, PyObject *pyname, PyObject *value)
Definition: nrnpy_nrn.cpp:1925
Object *(* nrnpy_seg_from_sec_x)(Section *, double x)
Definition: netcvode.cpp:123
static PyObject * pysec_disconnect(NPySecObj *self)
Definition: nrnpy_nrn.cpp:894
void nrn_area_ri(Section *sec)
Definition: treeset.cpp:779
static bool striptrail(char *buf, int sz, const char *n, const char *m)
Definition: nrnpy_nrn.cpp:2004
static PyObject * pysec_repr(PyObject *p)
Definition: nrnpy_nrn.cpp:797
static PyObject * NPySecObj_pt3dadd(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:647
static void remake_pmech_types()
Definition: nrnpy_nrn.cpp:2574
static PyObject * rv_getitem(PyObject *self, Py_ssize_t ix)
Definition: nrnpy_nrn.cpp:2180
static PyObject * newpyseghelp(Section *sec, double x)
Definition: nrnpy_nrn.cpp:884
void simpleconnectsection()
Definition: cabcode.cpp:664
void(* nrnpy_o2loc_p_)(Object *, Section **, double *)
Definition: point.cpp:29
cTemplate ** nrn_pnt_template_
Definition: init.cpp:131
static PyMemberDef NPyMechObj_members[]
Definition: nrnpy_nrn.cpp:2446
static PyObject * NPySecObj_arc3d(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:744
static PyTypeObject * pallseg_of_sec_iter_type
Definition: nrnpy_nrn.cpp:80
static PyTypeObject * psegment_type
Definition: nrnpy_nrn.cpp:82
static Section * o2sec(Object *)
Definition: nrnpy_nrn.cpp:463
void mech_insert1(Section *, int)
Definition: cabcode.cpp:849
void nrnpy_sec_referr()
Definition: nrnpy_nrn.cpp:135
void nrn_pt3dchange2(Section *sec, int i, double x, double y, double z, double diam)
Definition: treeset.cpp:1170
static PyObject * is_pysec(NPySecObj *self)
Definition: nrnpy_nrn.cpp:857
static double interpolate(double x0, double x1, double y0, double y1, double xnew)
Definition: nrnpy_nrn.cpp:1399
static Object ** pp_get_segment(void *vptr)
Definition: nrnpy_nrn.cpp:1551
static Prop * mech_of_segment_prop(Prop *p)
Definition: nrnpy_nrn.cpp:1497
static PyMethodDef NPyMechObj_methods[]
Definition: nrnpy_nrn.cpp:2426
static void NPySegObj_dealloc(NPySegObj *self)
Definition: nrnpy_nrn.cpp:237
static PyObject * NPyMechObj_segment(NPyMechObj *self)
Definition: nrnpy_nrn.cpp:1091
static NPyRangeVar * rvnew(Symbol *sym, NPySecObj *sec, double x)
Definition: nrnpy_nrn.cpp:1580
static PyObject * pyseg_richcmp(NPySegObj *self, PyObject *other, int op)
Definition: nrnpy_nrn.cpp:1031
static PyObject * segment_getattro(NPySegObj *self, PyObject *pyname)
Definition: nrnpy_nrn.cpp:1788
static PyObject * NPySecObj_call(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:2161
double ** nrnpy_setpointer_helper(PyObject *pyname, PyObject *mech)
Definition: nrnpy_nrn.cpp:2141
PyObject * nrnpy_ho2po(Object *)
Definition: nrnpy_hoc.cpp:499
void nrn_pt3dstyle1(Section *sec, double x, double y, double z)
Definition: treeset.cpp:1015
static void NPySegOfSecIter_dealloc(NPySegOfSecIter *self)
Definition: nrnpy_nrn.cpp:231
static PyObject * pymech_repr(PyObject *p)
Definition: nrnpy_nrn.cpp:1101
static PyObject * seg_area(NPySegObj *self)
Definition: nrnpy_nrn.cpp:1378
int(* nrnpy_pysec_cell_equals_p_)(Section *, Object *)
Definition: cabcode.cpp:31
void mech_uninsert1(Section *, Symbol *)
Definition: cabcode.cpp:916
int nrn_pointer_assign(Prop *prop, Symbol *sym, PyObject *value)
Definition: nrnpy_nrn.cpp:1905
PyObject * nrnpy_newsecobj(PyObject *self, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:373
double nrn_ra(Section *)
Definition: cabcode.cpp:403
static PyObject * hoc_internal_name(NPySecObj *self)
Definition: nrnpy_nrn.cpp:818
PyObject * pmech_types
Definition: nrnpy_nrn.cpp:88
void nrn_pt3dchange1(Section *sec, int i, double d)
Definition: treeset.cpp:1163
static PyMethodDef NPySecObj_methods[]
Definition: nrnpy_nrn.cpp:2248
static PyObject * NPySecObj_has_membrane(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:1251
PyObject * nrnpy_nrn(void)
Definition: nrnpy_nrn.cpp:2481
PyObject * NPyAllSegOfSecIter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:360
static void NPyAllSegOfSecIter_dealloc(NPyAllSegOfSecIter *self)
Definition: nrnpy_nrn.cpp:225
static PyObject * NPySecObj_psection(NPySecObj *self)
Definition: nrnpy_nrn.cpp:845
static PyMemberDef NPySegObj_members[]
Definition: nrnpy_nrn.cpp:2417
static PyObject * NPySecObj_name(NPySecObj *self)
Definition: nrnpy_nrn.cpp:555
static PyObject * seg_point_processes(NPySegObj *self)
Definition: nrnpy_nrn.cpp:1353
static PyObject * NPySecObj_diam3d(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:761
static PyObject * NPySegObj_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:377
static PyObject * seg_of_sec_next(NPySegOfSecIter *self)
Definition: nrnpy_nrn.cpp:1334
static PyObject * NPySecObj_n3d(NPySecObj *self)
Definition: nrnpy_nrn.cpp:561
PyObject * nrnpy_forall(PyObject *self, PyObject *args)
Definition: nrnpy_hoc.cpp:1587
int can_change_morph(Section *)
Definition: treeset.cpp:1258
static void NPyMechOfSegIter_dealloc(NPyMechOfSegIter *self)
Definition: nrnpy_nrn.cpp:255
static int pysec_cell_equals(Section *, Object *)
Definition: nrnpy_nrn.cpp:188
static int ob_is_seg(Object *)
Definition: nrnpy_nrn.cpp:452
void nrn_pt3dclear(Section *sec, int req)
Definition: treeset.cpp:1117
static void NPyRangeVar_dealloc(NPyRangeVar *self)
Definition: nrnpy_nrn.cpp:243
static PyObject * seg_ri(NPySegObj *self)
Definition: nrnpy_nrn.cpp:1482
static int mech_setattro(NPyMechObj *self, PyObject *pyname, PyObject *value)
Definition: nrnpy_nrn.cpp:2086
static void NPyMechObj_dealloc(NPyMechObj *self)
Definition: nrnpy_nrn.cpp:249
void sec_free(hoc_Item *)
Definition: solve.cpp:521
static char * pysec_name(Section *)
Definition: nrnpy_nrn.cpp:139
void nrn_diam_change(Section *)
Definition: treeset.cpp:1215
int nrn_is_hocobj_ptr(PyObject *, double *&)
Definition: nrnpy_hoc.cpp:878
static PyObject * NPySecObj_x3d(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:696
double section_length(Section *)
Definition: cabcode.cpp:387
PyObject * nrnpy_pushsec(PyObject *sec)
Definition: nrnpy_nrn.cpp:1263
PyObject * rangevars_
Definition: nrnpy_nrn.cpp:89
static void NPyVarOfMechIter_dealloc(NPyVarOfMechIter *self)
Definition: nrnpy_nrn.cpp:261
static long pysec_hash(PyObject *self)
Definition: nrnpy_nrn.cpp:1022
int nrnpy_ho_eq_po(Object *, PyObject *)
Definition: nrnpy_p2h.cpp:182
static PyTypeObject * pvar_of_mech_iter_generic_type
Definition: nrnpy_nrn.cpp:85
static int NPyRangeVar_init(NPyRangeVar *self, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:551
static int rv_setitem(PyObject *self, Py_ssize_t ix, PyObject *value)
Definition: nrnpy_nrn.cpp:2207
static void rv_noexist(Section *sec, const char *n, double x, int err)
Definition: nrnpy_nrn.cpp:1568
static PyObject * NPyMechObj_is_ion(NPyMechObj *self)
Definition: nrnpy_nrn.cpp:1083
static void rangevars_add(Symbol *sym)
Definition: nrnpy_nrn.cpp:2471
void nrn_length_change(Section *, double)
Definition: treeset.cpp:1235
static double scaled_frustum_volume(double length, double d0, double d1)
Definition: nrnpy_nrn.cpp:1394
static PyMethodDef nrnpy_methods[]
Definition: nrnpy_nrn.cpp:2458
Section * nrnpy_newsection(NPySecObj *)
static PyObject * NPySecObj_z3d(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:728
static PyObject * node_index1(NPySegObj *self)
Definition: nrnpy_nrn.cpp:1370
static PyObject * mech_getattro(NPyMechObj *self, PyObject *pyname)
Definition: nrnpy_nrn.cpp:2019
char *(* nrnpy_pysec_name_p_)(Section *)
Definition: cabcode.cpp:29
static int NPySecObj_init(NPySecObj *self, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:277
static PyObject * mech_of_seg_next(NPyMechOfSegIter *self)
Definition: nrnpy_nrn.cpp:1736
static PyObject * NPySecObj_y3d(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:712
static void nrnpy_reg_mech(int)
Definition: nrnpy_nrn.cpp:2590
static PyObject * seg_volume(NPySegObj *self)
Definition: nrnpy_nrn.cpp:1426
void nrn_pt3dstyle0(Section *sec)
Definition: treeset.cpp:1006
int(* nrnpy_ob_is_seg)(Object *)
Definition: nrnmenu.cpp:47
static PyObject * NPyRangeVar_name(NPyRangeVar *self)
Definition: nrnpy_nrn.cpp:1110
void(* nrnpy_reg_mech_p_)(int)
Definition: init.cpp:94
static PyObject * allseg_of_sec_iter(NPyAllSegOfSecIter *self)
Definition: nrnpy_nrn.cpp:1303
Symlist * hoc_built_in_symlist
Definition: ivocmac.cpp:76
static PyObject * NPySecObj_pt3dclear(NPySecObj *self, PyObject *args)
Definition: nrnpy_nrn.cpp:582
static int NPySecObj_contains(PyObject *sec, PyObject *obj)
Definition: nrnpy_nrn.cpp:173
PyObject * nrn_ptr_richcmp(void *self_ptr, void *other_ptr, int op)
Definition: nrnpy_hoc.cpp:2107
PyObject * nrn_hocobj_ptr(double *)
Definition: nrnpy_hoc.cpp:870
#define M_PI
Definition: nrnpy_nrn.cpp:9
static PyObject * var_of_mech_iter(NPyMechObj *self)
Definition: nrnpy_nrn.cpp:1753
PyTypeObject * hocobject_type
Definition: nrnpy_hoc.cpp:159
static long pyseg_hash(PyObject *self)
Definition: nrnpy_nrn.cpp:1026
static char * cpstr(const char *s)
Definition: nrnpy_nrn.cpp:2412
void nrn_change_nseg(Section *, int)
Definition: cabcode.cpp:1557
static PyObject * NPyMechObj_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:401
static int arg_bisect_arc3d(Section *sec, int npt3d, double x)
Definition: nrnpy_nrn.cpp:1410
PyObject * NPySecObj_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:347
static PyMethodDef NPyRangeVar_methods[]
Definition: nrnpy_nrn.cpp:2438
int has_membrane(char *, Section *)
Definition: cabcode.cpp:2236
static PyObject * NPyRangeVar_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Definition: nrnpy_nrn.cpp:417
static PyObject * allseg(NPySecObj *self)
Definition: nrnpy_nrn.cpp:1293
static PyTypeObject * range_type
Definition: nrnpy_nrn.cpp:86
NPySecObj * newpysechelp(Section *sec)
Definition: nrnpy_nrn.cpp:865
static Object * pysec_cell(Section *)
Definition: nrnpy_nrn.cpp:156
static PyObject * pysec_children1(PyObject *const sl, Section *const sec)
Definition: nrnpy_nrn.cpp:954
static PyObject * NPyRangeVar_mech(NPyRangeVar *self)
Definition: nrnpy_nrn.cpp:1127
static PyObject * allseg_of_sec_next(NPyAllSegOfSecIter *self)
Definition: nrnpy_nrn.cpp:1309
static PyType_Spec nrnpy_MechOfSegIterType_spec
Definition: nrnpy_nrn.h:89
static PyType_Spec nrnpy_VarOfMechIterType_spec
Definition: nrnpy_nrn.h:125
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:166
static PyType_Spec nrnpy_MechanismType_spec
Definition: nrnpy_nrn.h:110
static PyType_Spec nrnpy_RangeType_spec
Definition: nrnpy_nrn.h:144
static struct PyModuleDef nrnmodule
Definition: nrnpy_nrn.h:152
static PyType_Spec nrnpy_SegmentType_spec
Definition: nrnpy_nrn.h:74
#define CHECK_SEC_INVALID(sec)
Definition: nrnpy_utils.h:134
#define PyInt_AsLong
Definition: nrnpython.h:28
#define PyInt_FromLong
Definition: nrnpython.h:29
#define castptr2long
Definition: nrnpython.h:40
#define PyString_FromString
Definition: nrnpython.h:24
static N_Vector x_
static double cell(void *v)
Definition: ocbbs.cpp:578
#define e
Definition: passive0.cpp:22
void nrnpy_pysecname2sec_add(Section *sec)
void nrnpy_pysecname2sec_remove(Section *sec)
#define left
Definition: rbtqueue.cpp:45
#define parent
Definition: rbtqueue.cpp:47
#define right
Definition: rbtqueue.cpp:46
static uint32_t value
Definition: scoprand.cpp:25
sl
Definition: seclist.cpp:181
o
Definition: seclist.cpp:175
#define PROP_PY_INDEX
Definition: section.h:212
#define NODEV(n)
Definition: section.h:115
#define NODERINV(n)
Definition: section.h:117
#define NODEAREA(n)
Definition: section.h:116
#define NULL
Definition: sptree.h:16
int nsub
Definition: hocdec.h:70
int sub[1]
Definition: hocdec.h:72
int is_point
Definition: membfunc.h:53
Symbol * sym
Definition: membfunc.h:38
PyObject_HEAD NPySecObj * pysec_
Definition: nrnpy_nrn.cpp:37
PyObject_HEAD NPySegObj * pyseg_
Definition: nrnpy_nrn.cpp:57
Prop * prop_
Definition: nrnpy_nrn.cpp:58
PyObject_HEAD NPySegObj * pyseg_
Definition: nrnpy_nrn.cpp:52
PyObject_HEAD NPyMechObj * pymech_
Definition: nrnpy_nrn.cpp:68
int index_
Definition: nrnpy_nrn.cpp:69
int attr_from_sec_
Definition: nrnpy_nrn.cpp:76
PyObject_HEAD NPyMechObj * pymech_
Definition: nrnpy_nrn.cpp:73
Symbol * sym_
Definition: nrnpy_nrn.cpp:74
PyObject * cell_weakref_
Definition: nrnpy_nrn.cpp:32
PyObject_HEAD Section * sec_
Definition: nrnpy_hoc.cpp:26
char * name_
Definition: nrnpy_hoc.cpp:27
double x_
Definition: nrnpy_nrn.cpp:48
PyObject_HEAD NPySecObj * pysec_
Definition: nrnpy_nrn.cpp:47
PyObject_HEAD NPySecObj * pysec_
Definition: nrnpy_nrn.cpp:42
Symbol * msym_
Definition: nrnpy_nrn.cpp:63
PyObject_HEAD NPyMechObj * pymech_
Definition: nrnpy_nrn.cpp:62
Definition: section.h:133
int v_node_index
Definition: section.h:175
struct Prop * prop
Definition: section.h:152
Definition: hocdec.h:227
int refcount
Definition: hocdec.h:228
Object * ob
Definition: section.h:267
Section * sec
Definition: section.h:263
Node * node
Definition: section.h:264
Prop * prop
Definition: section.h:265
Inst defn
Definition: hocdec.h:76
Definition: section.h:214
Datum * dparam
Definition: section.h:220
short type
Definition: section.h:216
struct Prop * prop
Definition: section.h:63
struct Section * parentsec
Definition: section.h:42
short nnode
Definition: section.h:41
Definition: model.h:57
Proc * u_proc
Definition: hocdec.h:145
short cpublic
Note: public is a reserved keyword.
Definition: hocdec.h:125
HocStruct Symbol ** ppsym
Definition: hocdec.h:150
short type
Definition: model.h:58
struct Symbol::@37::@38 rng
long subtype
Definition: model.h:59
union Symbol::@18 u
unsigned s_varn
Definition: hocdec.h:158
char * name
Definition: model.h:72
Arrayinfo * arayinfo
Definition: hocdec.h:159
Definition: hocdec.h:84
Symlist * symtable
Definition: hocdec.h:197
double * pval
Definition: hocdec.h:181
Pfro pfo
Definition: hocdec.h:54