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