NEURON
cabcode.cpp
Go to the documentation of this file.
2 #include <../../nrnconf.h>
3 /* /local/src/master/nrn/src/nrnoc/cabcode.cpp,v 1.37 1999/07/08 14:24:59 hines Exp */
4 
5 #include <regex>
6 #include <cstdio>
7 #include <cstdlib>
8 #include <cmath>
9 
10 #define HOC_L_LIST 1
11 #include "section.h"
12 #include "nrniv_mf.h"
13 #include "membfunc.h"
14 #include "parse.hpp"
15 #include "hocparse.h"
16 #include "membdef.h"
17 
18 static char* escape_bracket(const char* s) {
19  static char* b;
20  const char* p1;
21  char* p2;
22  if (!b) {
23  b = new char[256];
24  }
25  for (p1 = s, p2 = b; *p1; ++p1, ++p2) {
26  switch (*p1) {
27  case '<':
28  *p2 = '[';
29  break;
30  case '>':
31  *p2 = ']';
32  break;
33  case '[':
34  case ']':
35  *p2 = '\\';
36  *(++p2) = *p1;
37  break;
38  default:
39  *p2 = *p1;
40  break;
41  }
42  }
43  *p2 = '\0';
44  return b;
45 }
46 
47 
48 extern int hoc_execerror_messages;
49 #define symlist hoc_symlist
50 
51 int tree_changed = 1; /* installing section, changeing nseg
52  and connecting sections set this flag.
53  The flag is set to 0 when the topology
54  is set up */
55 int diam_changed = 1; /* changing diameter, length set this flag
56  The flag is set to 0 when node.a and node.b
57  is set up */
58 extern int nrn_shape_changed_;
59 
60 char* (*nrnpy_pysec_name_p_)(Section*);
61 Object* (*nrnpy_pysec_cell_p_)(Section*);
63 
64 /* switching from Ra being a global variable to it being a section variable
65 opens up the possibility of a great deal of confusion and inadvertant wrong
66 results. To help avoid this we print a warning message whenever the value
67 in one section is set but no others. But only the first time through treeset.
68 */
69 #if RA_WARNING
70 int nrn_ra_set = 0;
71 #endif
72 
73 #define NSECSTACK 200
74 static Section* secstack[NSECSTACK + 1];
75 static int isecstack = 0; /* stack index */
76 /* don't do section stack auto correction
77  in the interval between push_section() ... pop_section in hoc (also for
78  point process get_loc. These should be deprecated in favor of doing
79  everything with SectionRef
80 */
81 static int skip_secstack_check = 0;
82 
83 static int range_vec_indx(Symbol* s);
84 
85 int nrn_isecstack(void) {
86  return isecstack;
87 }
88 
89 void nrn_secstack(int i) {
90  if (skip_secstack_check) {
91  return;
92  }
93 #if 1
94  if (isecstack > i) {
95  Printf("The sectionstack index should be %d but it is %d\n", i, isecstack);
97  "prior to version 5.3 the section stack would not have been properly popped\n\
98 and the currently accessed section would have been ",
100  }
101 #endif
102  while (isecstack > i) {
103  nrn_popsec();
104  }
105 }
106 
107 void nrn_initcode(void) {
108  while (isecstack > 0) {
109  nrn_popsec();
110  }
111  isecstack = 0;
115 }
116 
117 void oc_save_cabcode(int* a1, int* a2) {
118  *a1 = isecstack;
119  *a2 = section_object_seen;
120 }
121 
122 void oc_restore_cabcode(int* a1, int* a2) {
123  while (isecstack > *a1) {
124  nrn_popsec();
125  }
126  isecstack = *a1;
127  section_object_seen = *a2;
128 }
129 
131  isecstack++;
132  if (isecstack >= NSECSTACK) {
133  int i = NSECSTACK;
134  hoc_warning("section stack overflow", (char*) 0);
135  while (--i >= 0) {
136  fprintf(stderr, "%*s%s\n", i, "", secname(secstack[i]));
137  --i;
138  }
139  hoc_execerror("section stack overflow", (char*) 0);
140  }
142  if (sec) {
143 #if 0
144  if (sec->prop && sec->prop->dparam[0].sym) {
145  printf("pushsec %s\n", sec->prop->dparam[0].sym->name);
146  }else{
147  printf("pushsec unnamed or deleted section\n");
148  }
149 #endif
150  ++sec->refcount;
151  }
152 }
153 
154 void nrn_popsec(void) {
155  if (isecstack > 0) {
157  if (!sec) {
158  return;
159  }
161  }
162 }
163 
164 void sec_access_pop(void) {
165  nrn_popsec();
166 }
167 
168 #if 0
169 static void free_point_process(void) {
170  free_all_point();
171  free_clamp();
172  free_stim();
173  free_syn();
174 }
175 #endif
176 
177 #if 0
178 void clear_sectionlist(void) /* merely change all SECTION to UNDEF */
179 {
180 printf("clear_sectionlist not fixed yet, doing nothing\n");
181 return;
182  Symbol *s;
183 
184  free_point_process();
185  if (symlist) for (s=symlist->first; s; s = s->next) {
186  if (s->type == SECTION) {
187  s->type = UNDEF;
188 no longer done this way see OPARINFO
189  if (s->arayinfo) {
190  free((char *)s->arayinfo);
191  s->arayinfo = (Arrayinfo *)0;
192  }
193  }
194  nrn_initcode();
195  secstack[0] = (Section *)0;
196  }
197  if (section) {
198  sec_free(section, nsection);
199  section = (Section *)0;
200  nsection = 0;
201  }
202 }
203 #endif
204 
205 void add_section(void) /* symbol at pc+1, number of indices at pc+2 */
206 {
207  Symbol* sym;
208  int nsub, size;
209  Item** pitm;
210 
211  sym = (pc++)->sym;
212  /*printf("declaring %s as section\n", sym->name);*/
213  if (sym->type == SECTION) {
214  int total, i;
215  total = hoc_total_array(sym);
216  for (i = 0; i < total; ++i) {
217  sec_free(*(OPSECITM(sym) + i));
218  }
219  free((char*) OPSECITM(sym));
220  hoc_freearay(sym);
221  } else {
222  assert(sym->type == UNDEF);
225  "First time declaration of Section %s in %s "
226  "must happen at command level (not in method)",
227  sym->name,
229  }
230  sym->type = SECTION;
232  }
233  nsub = (pc++)->i;
234  if (nsub) {
235  size = hoc_arayinfo_install(sym, nsub);
236  } else {
237  size = 1;
238  }
239  hoc_objectdata[sym->u.oboff].psecitm = pitm = (Item**) emalloc(size * sizeof(Item*));
241  new_sections((Object*) 0, sym, pitm, size);
242  } else {
243  new_sections(hoc_thisobject, sym, pitm, size);
244  }
245 #if 0
246 printf("%s", s->name);
247 for (i=0; i<ndim; i++) {printf("[%d]",s->arayinfo->sub[i]);}
248 printf(" is a section name\n");
249 #endif
250 }
251 
253  if (sec->prop) {
254  if (auto* o = sec->prop->dparam[6].get<Object*>(); o) {
255  return o;
256  } else if (nrnpy_pysec_cell_p_) {
257  Object* o = (*nrnpy_pysec_cell_p_)(sec);
258  if (o) {
259  --o->refcount;
260  }
261  return o;
262  }
263  }
264  return nullptr;
265 }
266 
268  if (sec && sec->prop) {
269  if (auto o = sec->prop->dparam[6].get<Object*>(); o) {
270  return o == obj;
271  } else if (nrnpy_pysec_cell_equals_p_) {
272  return (*nrnpy_pysec_cell_equals_p_)(sec, obj);
273  }
274  }
275  return 0;
276 }
277 
278 static Section* new_section(Object* ob, Symbol* sym, int i) {
279  Section* sec;
280  Prop* prop;
281  static Symbol* nseg;
282  double d;
283 
284  if (!nseg) {
285  nseg = hoc_lookup("nseg");
286  }
287  sec = sec_alloc();
288  section_ref(sec);
289  prop = prop_alloc(&(sec->prop), CABLESECTION, (Node*) 0);
290  prop->dparam[0] = {neuron::container::do_not_search, sym};
291  prop->dparam[5] = i;
292  prop->dparam[6] = {neuron::container::do_not_search, ob};
293 #if USE_PYTHON
294  prop->dparam[PROP_PY_INDEX] = nullptr;
295 #endif
296  nrn_pushsec(sec);
297  d = (double) DEF_nseg;
298  cable_prop_assign(nseg, &d, 0);
299  tree_changed = 1;
300  /*printf("new_section %s\n", secname(sec));*/
301  return sec;
302 }
303 
304 void new_sections(Object* ob, Symbol* sym, Item** pitm, int size) {
305  int i;
306  for (i = 0; i < size; ++i) {
307  Section* sec = new_section(ob, sym, i);
308  if (ob) {
309  if (ob->secelm_) {
310  pitm[i] = insertsec(ob->secelm_->next, sec);
311  } else {
312  pitm[i] = lappendsec(section_list, sec);
313  }
314  ob->secelm_ = pitm[i];
315  } else {
316  pitm[i] = lappendsec(section_list, sec);
317  }
318  sec->prop->dparam[8] = {neuron::container::do_not_search, pitm[i]};
319  }
320 }
321 
322 /// @brief Creates a new section and registers with the global section list
324  Section* sec = new_section(nullptr, sym, 0);
325  auto itm = lappendsec(section_list, sec);
326  sec->prop->dparam[8] = {neuron::container::do_not_search, itm};
327  return sec;
328 }
329 
330 #if USE_PYTHON
331 struct NPySecObj;
332 Section* nrnpy_newsection(NPySecObj* v) {
333  auto sec = section_new(nullptr);
334  sec->prop->dparam[PROP_PY_INDEX] = static_cast<void*>(v);
335  return sec;
336 }
337 #endif
338 
339 void delete_section(void) {
340  Section* sec;
341  Item** pitm;
342  if (ifarg(1)) {
344  "delete_section takes no positional arguments and deletes the HOC currently accessed "
345  "section. If using Python, did you mean a named arg of the form, sec=section?",
346  NULL);
347  }
348  sec = chk_access();
349  if (!sec->prop) { /* already deleted */
350  hoc_retpushx(0.0);
351  return;
352  }
353 #if USE_PYTHON
354  if (sec->prop->dparam[PROP_PY_INDEX].get<void*>()) { /* Python Section */
355  /* the Python Section will be a zombie section with a pointer
356  to an invalid Section*.
357  */
358  sec->prop->dparam[PROP_PY_INDEX] = nullptr;
359  section_ref(sec);
360  sec_free(sec->prop->dparam[8].get<hoc_Item*>());
361  hoc_retpushx(0.0);
362  return;
363  }
364 #endif
365  auto* sym = sec->prop->dparam[0].get<Symbol*>();
366  if (!sym) {
367  hoc_execerror("Cannot delete an unnamed hoc section", (char*) 0);
368  }
369  auto* ob = sec->prop->dparam[6].get<Object*>();
370  auto i = sec->prop->dparam[5].get<int>();
371  if (ob) {
372  pitm = ob->u.dataspace[sym->u.oboff].psecitm + i;
373  } else {
374  pitm = hoc_top_level_data[sym->u.oboff].psecitm + i;
375  }
376  sec_free(*pitm);
377  *pitm = 0;
378  hoc_retpushx(1.);
379 }
380 
381 /*
382 At this point, all the sections are cables and each section has the following
383 properties (except for section 0). Only one property with 9 Datums
384 
385 section[i].prop->dparam[0].sym pointer to section symbol
386  [1].val position (0--1) of connection to parent
387  [2].val length of section in microns
388  [3].val first node at position 0 or 1
389  [4].val rall branch
390  [5].i aray index
391  [6].obj pointer to the object pointer
392  [7].val Ra
393  [8].itm hoc_Item* with Section* as element
394  [9]._pvoid NrnThread*
395  [PROP_PY_INDEX].pvoid pointer to the Python Section object
396 The first element allows us to find the symbol when we know the section number.
397 If an array section the index can be computed with
398 i - (section[i].sym)->u.u_auto
399 */
400 
402  if (sec->recalc_area_ && sec->npt3d) {
403  sec->prop->dparam[2] = sec->pt3d[sec->npt3d - 1].arc;
404  }
405  double x = sec->prop->dparam[2].get<double>();
406  if (x <= 1e-9) {
407  x = 1e-9;
408  sec->prop->dparam[2] = x;
409  }
410  return x;
411 }
412 
414  return (sec->prop->dparam[3].get<double>() ? 0 : 1);
415 }
416 
417 double nrn_ra(Section* sec) {
418  return sec->prop->dparam[7].get<double>();
419 }
420 
421 void cab_alloc(Prop* p) {
422  Datum* pd;
423 #if USE_PYTHON
424 #define CAB_SIZE 11
425 #else
426 #define CAB_SIZE 10
427 #endif
429  pd[1] = 0.0;
430  pd[2] = DEF_L;
431  pd[3] = 0.0;
432  pd[4] = DEF_rallbranch;
433  pd[7] = DEF_Ra;
434  p->dparam = pd;
435  p->dparam_size = CAB_SIZE; /* this one is special since it refers to dparam */
436 }
437 
439  assert(p->param_size() == 1);
440  p->param(0) = DEF_diam; /* microns */
441  diam_changed = 1;
442 }
443 
444 double nrn_diameter(Node* nd) {
445  Prop* p = nrn_mechanism(MORPHOLOGY, nd);
446  return p->param(0);
447 }
448 
451  if (!sec || !sec->prop) {
452  /* use any existing section as a default section */
453  for (Section* lsec: range_sec(section_list)) {
454  if (lsec->prop) {
455  sec = lsec;
456  ++sec->refcount;
458  /*printf("automatic default section %s\n", secname(sec));*/
459  break;
460  }
461  }
462  }
463  if (!sec) {
464  execerror("Section access unspecified", (char*) 0);
465  }
466  if (sec->prop) {
467  return sec;
468  } else {
469  execerror("Accessing a deleted section", (char*) 0);
470  }
471  return NULL; /* never reached */
472 }
473 
474 Section* nrn_noerr_access(void) /* return 0 if no accessed section */
475 {
477  if (!sec || !sec->prop) {
478  /* use any existing section as a default section */
479  for (Section* lsec: range_sec(section_list)) {
480  if (lsec->prop) {
481  sec = lsec;
482  ++sec->refcount;
484  /*printf("automatic default section %s\n", secname(sec));*/
485  break;
486  }
487  }
488  }
489  if (!sec) {
490  return (Section*) 0;
491  }
492  if (sec->prop) {
493  return sec;
494  } else {
495  return (Section*) 0;
496  }
497 }
498 
499 /*sibling and child pointers do not ref sections to avoid mutual references */
500 /* the sibling list is ordered according to increasing distance from parent */
501 
503  Section* s;
504  if (sec->parentsec) {
505  if (sec->parentsec->child == sec) {
506  sec->parentsec->child = sec->sibling;
507  return;
508  }
509  for (s = sec->parentsec->child; s; s = s->sibling) {
510  if (s->sibling == sec) {
511  s->sibling = sec->sibling;
512  return;
513  }
514  }
515  }
516 }
517 
518 static double ncp_abs(Section* sec) {
519  double x = nrn_connection_position(sec);
520  if (sec->parentsec) {
521  if (!arc0at0(sec->parentsec)) {
522  return 1. - x;
523  }
524  }
525  return x;
526 }
527 
529  Section* s;
530  double x;
531  if (sec->parentsec) {
532  x = ncp_abs(sec);
533  s = sec->parentsec->child;
534  if (!s || x <= ncp_abs(s)) {
535  sec->sibling = s;
536  sec->parentsec->child = sec;
537  return;
538  }
539  for (; s->sibling; s = s->sibling) {
540  if (x <= ncp_abs(s->sibling)) {
541  sec->sibling = s->sibling;
542  s->sibling = sec;
543  return;
544  }
545  }
546  s->sibling = sec;
547  sec->sibling = 0;
548  }
549 }
550 
552  int scnt;
553  Section* ch;
554  Section** pch;
555  for (scnt = 0, ch = sec->child; ch; ++scnt, ch = ch->sibling) {
556  hoc_pushobj((Object**) ch);
557  }
558  pch = &sec->child;
559  while (scnt--) {
560  ch = (Section*) hoc_objpop();
561  *pch = ch;
562  pch = &ch->sibling;
563  ch->parentnode = 0;
564  }
565  *pch = 0;
566 }
567 
568 void disconnect() {
569  if (ifarg(1)) {
571  "disconnect takes no positional arguments and disconnects the HOC currently accessed "
572  "section. If using Python, did you mean a named arg of the form, sec=section? Or you "
573  "can use section.disconnect().",
574  NULL);
575  }
577  hoc_retpushx(0.);
578 }
579 
580 static void reverse_nodes(Section* sec) {
581  int i, j;
582  Node* nd;
583  /* printf("reverse %d nodes for %s\n", sec->nnode-1, secname(sec));*/
584  for (i = 0, j = sec->nnode - 2; i < j; ++i, --j) {
585  nd = sec->pnode[i];
586  sec->pnode[i] = sec->pnode[j];
587  sec->pnode[i]->sec_node_index_ = i;
588  sec->pnode[j] = nd;
589  nd->sec_node_index_ = j;
590  }
591 }
592 
594  Section* ch;
595  Section* oldpsec = sec->parentsec;
596  Node* oldpnode = sec->parentnode;
597  if (!oldpsec) {
598  return;
599  }
601  sec->parentsec = (Section*) 0;
602  sec->parentnode = (Node*) 0;
604  nrn_relocate_old_points(sec, oldpnode, sec, sec->parentnode);
605  for (ch = sec->child; ch; ch = ch->sibling)
606  if (nrn_at_beginning(ch)) {
607  ch->parentnode = sec->parentnode;
608  nrn_relocate_old_points(ch, oldpnode, ch, ch->parentnode);
609  }
610  section_unref(oldpsec);
611  tree_changed = 1;
613 }
614 
615 static void connectsec_impl(Section* parent, Section* sec) {
616  Section* ch;
617  Section* oldpsec = sec->parentsec;
618  Node* oldpnode = sec->parentnode;
619  double d1, d2;
620  Datum* pd;
621  d2 = xpop();
622  d1 = xpop();
623  if (d1 != 0. && d1 != 1.) {
624  hoc_execerror(secname(sec), " must connect at position 0 or 1");
625  }
626  if (d2 < 0. || d2 > 1.) {
627  hoc_execerror(secname(sec), " must connect from 0<=x<=1 of parent");
628  }
629  if (sec->parentsec) {
630  fprintf(stderr, "Notice: %s(%g)", secname(sec), nrn_section_orientation(sec));
631  fprintf(stderr,
632  " had previously been connected to parent %s(%g)\n",
633  secname(sec->parentsec),
636  }
637  if (nrn_section_orientation(sec) != d1) {
640  }
641  pd = sec->prop->dparam;
642  pd[1] = d2;
643  pd[3] = d1;
644  section_ref(parent);
645  sec->parentsec = parent;
647  sec->parentnode = (Node*) 0;
649  nrn_relocate_old_points(sec, oldpnode, sec, sec->parentnode);
650  for (ch = sec->child; ch; ch = ch->sibling)
651  if (nrn_at_beginning(ch)) {
652  ch->parentnode = sec->parentnode;
653  nrn_relocate_old_points(ch, oldpnode, ch, ch->parentnode);
654  }
655  if (oldpsec) {
656  section_unref(oldpsec);
657  } else if (oldpnode) {
658  delete oldpnode;
659  }
660  tree_changed = 1;
661  diam_changed = 1;
662 }
663 
664 void simpleconnectsection(void) /* 2 expr on stack and two sections on section stack */
665  /* for a prettier syntax: connect sec1(x), sec2(x) */
666 {
667  Section *parent, *child;
668  parent = nrn_sec_pop();
669  child = nrn_sec_pop();
670  connectsec_impl(parent, child);
671 }
672 
673 void connectsection(void) /* 2 expr on stack and section symbol on section stack */
674 {
675  Section *parent, *child;
676  child = nrn_sec_pop();
677  parent = chk_access();
678  connectsec_impl(parent, child);
679 }
680 
681 static Section* Sec_access(void) /* section symbol at pc */
682 {
683  Objectdata* odsav;
684  Object* obsav = 0;
685  Symlist* slsav;
686  Item* itm;
687  Symbol* s = (pc++)->sym;
688 
689  if (!s) {
690  return chk_access();
691  }
692 
693  if (s->cpublic == 2) {
694  s = s->u.sym;
695  odsav = hoc_objectdata_save();
696  obsav = hoc_thisobject;
697  slsav = hoc_symlist;
699  hoc_thisobject = 0;
701  }
702  if (s->type != SECTION) {
703  execerror("Not a SECTION name:", s->name);
704  }
705  itm = OPSECITM(s)[range_vec_indx(s)];
706  if (obsav) {
708  hoc_thisobject = obsav;
709  hoc_symlist = slsav;
710  }
711  if (!itm) {
712  hoc_execerror(s->name, ": section was deleted");
713  }
714  return itm->element.sec;
715 #if 0
716 printf("accessing %s with index %d\n", s->name, access_index);
717 #endif
718 }
719 
720 void sec_access(void) { /* access section */
721  Section** psec;
722  Section* sec = chk_access();
723  ++sec->refcount;
724  nrn_popsec();
725  psec = secstack + isecstack;
726  if (*psec) {
727  section_unref(*psec);
728  }
729  *psec = sec;
730 }
731 
732 void sec_access_object(void) { /* access section */
733  Section** psec;
734  Section* sec;
735  if (!section_object_seen) {
736  hoc_execerror("Access: Not a section", (char*) 0);
737  }
738  sec = chk_access();
739  ++sec->refcount;
740  nrn_popsec();
741  psec = secstack + isecstack;
742  if (*psec) {
743  section_unref(*psec);
744  }
745  *psec = sec;
747 }
748 
749 void sec_access_push(void) {
751 }
752 
754  Section* sec = chk_access();
755  nrn_popsec();
756  return sec;
757 }
758 
760  Section* sec = (Section*) ((pc++)->ptr);
761  nrn_pushsec(sec);
762 }
763 
764 void* hoc_sec_internal_name2ptr(const char* s, int eflag) {
765  /*
766  syntax is __nrnsec_0xff... and need to verify that ff... is a pointer
767  to a Section. To avoid invalid memory read errors, we changed
768  the section allocation/free in solve.cpp to use a SectionPool which
769  allows checking to see if a void* is a possible Section* from
770  the pool.
771  */
772  int n;
773  Section* sec;
774  void* vp = NULL;
775  int err = 0;
776  n = strlen(s);
777  if (n < 12 || strncmp(s, "__nrnsec_0x", 11) != 0) {
778  err = 1;
779  } else {
780  if (sscanf(s + 9, "%p", &vp) != 1) {
781  err = 1;
782  }
783  }
784  if (err) {
785  if (eflag) {
786  hoc_execerror("Invalid internal section name:", s);
787  } else {
788  hoc_warning("Invalid internal section name:", s);
789  }
790  return NULL;
791  }
792  sec = (Section*) vp;
793  if (nrn_is_valid_section_ptr(vp) == 0 || !sec->prop || !sec->prop->dparam ||
794  !sec->prop->dparam[8].get<hoc_Item*>() ||
795  sec->prop->dparam[8].get<hoc_Item*>()->itemtype != SECTION) {
796  if (eflag) {
797  hoc_execerror("Section associated with internal name does not exist:", s);
798  } else {
799  hoc_warning("Section associated with internal name does not exist:", s);
800  }
801  vp = NULL;
802  }
803  return vp;
804 }
805 
806 void* hoc_pysec_name2ptr(const char* s, int /* eflag */) {
807  /*
808  syntax is _pysec.<name> where <name> is the name of a python
809  nrn.Section from (*nrnpy_pysec_name_p_)(sec)
810 
811  */
813  return (void*) sec;
814 }
815 
816 /* in an object syntax a section may either be last or next to last
817 in either case it is pushed when it is seen in hoc_object_component
818 and section_object_seen is set.
819 If it was last then this is called with it set and we do nothing.
820 ie the section is on the stack till the end of the next statement.
821 If it was second to last then it hoc_object_component will set it
822 back to 0 and pop the section. Therefore we need to push a section
823 below to keep the stack ok when it is popped at the end of the next
824 statement.
825 */
826 
828  if (!qsec) {
829  hoc_execerror("section in the object was deleted", (char*) 0);
830  }
831  nrn_pushsec(qsec->element.sec);
832 }
833 
835  if (!section_object_seen) {
836  hoc_nopop();
838  }
840 }
841 
842 /* For now there is always one more node than segments and the last
843 node has no properties. This fact is spread everywhere in which
844 nnode is dealt with */
845 
846 void mech_access(void) { /* section symbol at pc */
847  Section* sec = chk_access();
848  Symbol* s = (pc++)->sym;
849  mech_insert1(sec, s->subtype);
850 }
851 
853  int n, i;
854  Node *nd, **pnd;
855  Prop* m;
856  /* make sure that all nodes but last of the current section have this
857  membrane type */
858  /* subsequent range variables refer to this mechanism */
859  /* For now, we assume:
860  1) Parameters for different mechanisms do not have to
861  have distinct names. Thus access mech marks those
862  symbols which are allowed.
863  Another access section gets back to the geometry properties.
864  2) Membrane is installed in entire section. (except last node)
865  */
866  /* Is the property already allocated*/
867  n = sec->nnode - 1;
868  pnd = sec->pnode;
869  nd = pnd[0];
870  m = nrn_mechanism(type, nd);
871  if (!m) { /* all nodes get the property */
872  for (i = n - 1; i >= 0; i--) {
873  IGNORE(prop_alloc(&(pnd[i]->prop), type, pnd[i]));
874  }
875 #if EXTRACELLULAR
876  if (type == EXTRACELL) {
877  prop_alloc(&(pnd[n]->prop), type, pnd[n]); /*even last node*/
878  /* if rootnode owned by section, it gets property as well*/
879  if (!sec->parentsec) {
880  nd = sec->parentnode;
881  if (nd) {
882  prop_alloc(&nd->prop, type, nd);
883  }
884  }
886  diam_changed = 1;
887  }
888 #endif
889  }
890 }
891 
892 void mech_uninsert(void) {
893  Section* sec = chk_access();
894  Symbol* s = (pc++)->sym;
895  mech_uninsert1(sec, s);
896 }
897 
899  /* remove the mechanism from the currently accessed section */
900  int n, i;
901  Prop *m, *mnext;
902  int type = s->subtype;
903 
904  if (type == MORPHOLOGY
905 #if EXTRACELLULAR
906  || type == EXTRACELL
907 #endif
908  ) {
909  hoc_warning("Can't uninsert mechanism", s->name);
910  return;
911  }
912  if (nrn_is_ion(type)) {
913  hoc_warning("Not allowed to uninsert ions at this time", s->name);
914  return;
915  }
916  n = sec->nnode;
917  for (i = 0; i < n; ++i) {
918  mnext = sec->pnode[i]->prop;
919  if (mnext && mnext->_type == type) {
920  sec->pnode[i]->prop = mnext->next;
921  single_prop_free(mnext);
922  continue;
923  }
924  for (m = mnext; m; m = mnext) {
925  mnext = m->next;
926  if (mnext && mnext->_type == type) {
927  m->next = mnext->next;
928  single_prop_free(mnext);
929  break;
930  }
931  }
932  }
933 }
934 
936  short n, i;
937  Node* nd;
938  int indx;
940  double d = *pd;
941  n = sec->nnode - 1;
942  if (s->u.rng.type == VINDEX) {
943  nd = node_ptr(sec, 0., (double*) 0);
944  if (op) {
945  *pd = hoc_opasgn(op, NODEV(nd), d);
946  }
947  nd->v() = *pd;
948  nd = node_ptr(sec, 1., (double*) 0);
949  if (op) {
950  *pd = hoc_opasgn(op, NODEV(nd), d);
951  }
952  nd->v() = *pd;
953  for (i = 0; i < n; i++) {
954  if (op) {
955  *pd = hoc_opasgn(op, NODEV(sec->pnode[i]), d);
956  }
957  sec->pnode[i]->v() = *pd;
958  }
959  } else {
960  if (s->u.rng.type == IMEMFAST) {
961  hoc_execerror("i_membrane_ cannot be assigned a value", 0);
962  }
963  indx = range_vec_indx(s);
964  if (s->u.rng.type == MORPHOLOGY) {
965  if (!can_change_morph(sec)) {
966  return;
967  }
968  diam_changed = 1;
969  if (sec->recalc_area_ && op != 0) {
970  nrn_area_ri(sec);
971  }
972  }
973 
974  for (i = 0; i < n; i++) {
975  dpr = dprop(s, indx, sec, i);
976  if (op) {
977  *pd = hoc_opasgn(op, *dpr, d);
978  }
979  *dpr = *pd;
980  }
981  if (s->u.rng.type == MORPHOLOGY) {
982  sec->recalc_area_ = 1;
984  }
985 #if EXTRACELLULAR
986  if (s->u.rng.type == EXTRACELL) {
987  if (s->u.rng.index == 0) {
988  diam_changed = 1;
989  }
991  nrn_vext_pd(s, indx, node_ptr(sec, 0., nullptr))};
992  if (dpr) {
993  if (op) {
994  *dpr = hoc_opasgn(op, *dpr, d);
995  } else {
996  *dpr = d;
997  }
998  }
1000  nrn_vext_pd(s, indx, node_ptr(sec, 1., nullptr))};
1001  if (dpr) {
1002  if (op) {
1003  *dpr = hoc_opasgn(op, *dpr, d);
1004  } else {
1005  *dpr = d;
1006  }
1007  }
1008  }
1009 #endif
1010  }
1011 }
1012 
1013 // rangevariable symbol at pc, value on stack
1014 void range_const() {
1015  Symbol* s = (hoc_pc++)->sym;
1016  int const op{(hoc_pc++)->i};
1017  double d{hoc_xpop()};
1018  auto* const sec = nrn_sec_pop();
1020  s,
1022  op);
1023  hoc_pushx(d);
1024 }
1025 
1026 static int range_vec_indx(Symbol* s) {
1027  int indx;
1028 
1029  if (is_array(*s)) {
1030  indx = hoc_araypt(s, SYMBOL);
1031  } else {
1032  indx = 0;
1033  }
1034  return indx;
1035 }
1036 
1037 /* returns property for mechanism at the node */
1039  Prop* m;
1040  for (m = nd->prop; m; m = m->next) {
1041  if (m->_type == type) {
1042  break;
1043  }
1044  }
1045  return m;
1046 }
1047 
1048 /*returns prop given mech type, section, and inode */
1049 /* error if mech not at this position */
1051  Prop* m;
1052  m = nrn_mechanism(type, sec->pnode[inode]);
1053  if (!m) {
1054  if (hoc_execerror_messages) {
1055  Fprintf(stderr,
1056  "%s mechanism not inserted in section %s\n",
1057  memb_func[type].sym->name,
1058  secname(sec));
1059  }
1060  hoc_execerror("", (char*) 0);
1061  }
1062  return m;
1063 }
1064 
1066  int inode;
1067  Section* sec;
1068  double x;
1069 
1070  nrn_seg_or_x_arg(1, &sec, &x);
1071  inode = node_index(sec, x);
1072  return nrn_mechanism_check(type, sec, inode);
1073 }
1074 
1075 static Datum* pdprop(Symbol* s, int indx, Section* sec, short inode) {
1076  /* basically copied from dprop for use to connect a nmodl POINTER */
1077  Prop* m;
1078 
1079  m = nrn_mechanism_check(s->u.rng.type, sec, inode);
1080  return m->dparam + s->u.rng.index + indx;
1081 }
1082 
1083 // pointer symbol at pc, target variable on stack, maybe range variable location on stack
1085  auto* const s = (hoc_pc++)->sym;
1086  auto const pd = hoc_pop_handle<double>();
1087  if (s->subtype != NRNPOINTER) {
1088  hoc_execerror(s->name, "not a model variable POINTER");
1089  }
1090  auto const d = hoc_xpop();
1091  auto* const sec = nrn_sec_pop();
1092  auto const i = node_index(sec, d);
1093  auto* const dat = pdprop(s, range_vec_indx(s), sec, i);
1094  *dat = pd;
1095 }
1096 
1097 void range_interpolate_single(void) /*symbol at pc, 2 values on stack*/
1098 {
1099  double x, y;
1100  Symbol* s;
1101  Section* sec;
1102  int op;
1103 
1104  s = (pc++)->sym;
1105  op = (pc++)->i;
1106  y = xpop();
1107  x = xpop();
1108  sec = nrn_sec_pop();
1109 
1110  if (s->u.rng.type == MORPHOLOGY) {
1111  if (!can_change_morph(sec)) {
1112  return;
1113  }
1114  diam_changed = 1;
1115  if (sec->recalc_area_ && op != 0) {
1116  nrn_area_ri(sec);
1117  }
1118  }
1119 
1120  auto pd = nrn_rangepointer(sec, s, x);
1121  if (op) {
1122  y = hoc_opasgn(op, *pd, y);
1123  }
1124  *pd = y;
1125 
1126  if (s->u.rng.type == MORPHOLOGY) {
1127  sec->recalc_area_ = 1;
1129  }
1130 
1131 #if EXTRACELLULAR
1132  if (s->u.rng.type == EXTRACELL && s->u.rng.index == 0) {
1133  diam_changed = 1;
1134  }
1135 #endif
1136 }
1137 
1138 void range_interpolate(void) /*symbol at pc, 4 values on stack*/
1139 {
1140  short i, i1, i2, di;
1141  Section* sec;
1142  double y1, y2, x1, x2, x, dx, thet, y;
1144  Symbol* s = (pc++)->sym;
1145  int indx, op;
1146  Node* nd;
1147 
1148  op = (pc++)->i;
1149  y2 = xpop();
1150  y1 = xpop();
1151  x2 = xpop();
1152  x1 = xpop();
1153  dx = x2 - x1;
1154  if (dx < 1e-10) {
1155  hoc_execerror("range variable notation r(x1:x2) requires", " x1 > x2");
1156  }
1157  sec = nrn_sec_pop();
1158  di = nrn_section_orientation(sec) ? -1 : 1;
1159  i2 = node_index(sec, x2) + di;
1160  i1 = node_index(sec, x1);
1161 
1162  if (s->u.rng.type == VINDEX) {
1163  if (x1 == 0. || x1 == 1.) {
1164  nd = node_ptr(sec, x1, (double*) 0);
1165  if (op) {
1166  nd->v() = hoc_opasgn(op, NODEV(nd), y1);
1167  } else {
1168  nd->v() = y1;
1169  }
1170  }
1171  if (x2 == 1. || x2 == 0.) {
1172  nd = node_ptr(sec, x2, (double*) 0);
1173  if (op) {
1174  nd->v() = hoc_opasgn(op, NODEV(nd), y2);
1175  } else {
1176  nd->v() = y2;
1177  }
1178  }
1179  for (i = i1; i != i2; i += di) {
1180  nd = sec->pnode[i];
1181  x = ((double) i + .5) / (sec->nnode - 1);
1182  if (di < 0) {
1183  x = 1. - x;
1184  }
1185  thet = (x - x1) / dx;
1186  if (thet >= -1e-9 && thet <= 1. + 1e-9) {
1187  y = y1 * (1. - thet) + y2 * thet;
1188  if (op) {
1189  nd->v() = hoc_opasgn(op, NODEV(nd), y);
1190  } else {
1191  nd->v() = y;
1192  }
1193  }
1194  }
1195  return;
1196  }
1197  if (s->u.rng.type == IMEMFAST) {
1198  hoc_execerror("i_membrane_ cannot be assigned a value", 0);
1199  }
1200  if (s->u.rng.type == MORPHOLOGY) {
1201  if (!can_change_morph(sec)) {
1202  return;
1203  }
1204  diam_changed = 1;
1205  }
1206  indx = range_vec_indx(s);
1207  for (i = i1; i != i2; i += di) {
1208  dpr = dprop(s, indx, sec, i);
1209  x = ((double) i + .5) / (sec->nnode - 1);
1210  if (di < 0) {
1211  x = 1. - x;
1212  }
1213  thet = (x - x1) / dx;
1214  if (thet >= -1e-9 && thet <= 1. + 1e-9) {
1215  y = y1 * (1. - thet) + y2 * thet;
1216  if (op) {
1217  *dpr = hoc_opasgn(op, *dpr, y);
1218  } else {
1219  *dpr = y;
1220  }
1221  }
1222  }
1223  if (s->u.rng.type == MORPHOLOGY) {
1224  sec->recalc_area_ = 1;
1226  }
1227 #if EXTRACELLULAR
1228  if (s->u.rng.type == EXTRACELL && s->u.rng.index == 0) {
1229  diam_changed = 1;
1230  }
1231  if (s->u.rng.type == EXTRACELL) {
1232  if (x1 == 0. || x1 == 1.) {
1234  nrn_vext_pd(s, indx, node_ptr(sec, x1, nullptr))};
1235  if (dpr) {
1236  if (op) {
1237  *dpr = hoc_opasgn(op, *dpr, y1);
1238  } else {
1239  *dpr = y1;
1240  }
1241  }
1242  }
1243  if (x2 == 1. || x2 == 0.) {
1245  nrn_vext_pd(s, indx, node_ptr(sec, x2, nullptr))};
1246  if (dpr) {
1247  if (op) {
1248  *dpr = hoc_opasgn(op, *dpr, y2);
1249  } else {
1250  *dpr = y2;
1251  }
1252  }
1253  }
1254  }
1255 #endif
1256 }
1257 
1259  if (s->u.rng.type == VINDEX) {
1260  return 1;
1261  } else if (nrn_mechanism(s->u.rng.type, node)) {
1262  return 1;
1263 #if EXTRACELLULAR
1264  } else if (nrn_vext_pd(s, 0, node)) {
1265  return 1;
1266 #endif
1267  } else if (s->u.rng.type == IMEMFAST && nrn_use_fast_imem) {
1268  return 1;
1269  } else {
1270  return 0;
1271  }
1272 }
1273 
1275  /* if you change this change nrnpy_rangepointer as well */
1276  short i;
1277  Node* nd;
1278  int indx;
1279 
1280  if (s->u.rng.type == VINDEX) {
1281  nd = node_ptr(sec, d, nullptr);
1282  return nd->v_handle();
1283  }
1284  if (s->u.rng.type == IMEMFAST) {
1285  if (nrn_use_fast_imem) {
1286  nd = node_ptr(sec, d, nullptr);
1287  return nd->sav_rhs_handle();
1288  } else {
1289  hoc_execerror(
1290  "cvode.use_fast_imem(1) has not been executed so i_membrane_ does not exist", 0);
1291  }
1292  }
1293  indx = range_vec_indx(s);
1294 #if EXTRACELLULAR
1295  if (s->u.rng.type == EXTRACELL) {
1296  double* const pd{nrn_vext_pd(s, indx, node_ptr(sec, d, (double*) 0))};
1297  if (pd) {
1299  }
1300  }
1301 #endif
1302  i = node_index(sec, d);
1303  return dprop(s, indx, sec, i);
1304 }
1305 
1307  Symbol* s,
1308  double d,
1309  int* err,
1310  int idx) {
1311  /* if you change this change nrn_rangepointer as well */
1312  *err = 0;
1313  if (s->u.rng.type == VINDEX) {
1314  auto* nd = node_ptr(sec, d, nullptr);
1315  return nd->v_handle();
1316  }
1317  if (s->u.rng.type == IMEMFAST) {
1318  if (nrn_use_fast_imem) {
1319  auto* nd = node_ptr(sec, d, nullptr);
1320  return nd->sav_rhs_handle();
1321  } else {
1322  return {};
1323  }
1324  }
1325 #if EXTRACELLULAR
1326  if (s->u.rng.type == EXTRACELL) {
1327  auto* nd = node_ptr(sec, d, nullptr);
1328  double* pd{nrn_vext_pd(s, 0, nd)};
1329  if (pd) {
1331  }
1332  }
1333 #endif
1334  auto const i = node_index(sec, d);
1335  return nrnpy_dprop(s, idx, sec, i, err);
1336 }
1337 
1338 // symbol at pc, location on stack, return pointer on stack
1340  Symbol* s{(pc++)->sym};
1341  double d = xpop();
1342  Section* sec{nrn_sec_pop()};
1343  if (s->u.rng.type == VINDEX) {
1344  auto* const nd = node_ptr(sec, d, nullptr);
1345  hoc_push(nd->v_handle());
1346  return;
1347  }
1348  if (s->u.rng.type == IMEMFAST) {
1349  if (nrn_use_fast_imem) {
1350  auto* nd = node_ptr(sec, d, nullptr);
1351  hoc_push(nd->sav_rhs_handle());
1352  } else {
1353  hoc_execerror(
1354  "cvode.use_fast_imem(1) has not been executed so i_membrane_ does not exist", 0);
1355  }
1356  return;
1357  }
1358  auto const indx = range_vec_indx(s);
1359  if (s->u.rng.type == MORPHOLOGY && sec->recalc_area_) {
1360  nrn_area_ri(sec);
1361  }
1362  if (s->u.rng.type == EXTRACELL) {
1363  double* pd{nrn_vext_pd(s, indx, node_ptr(sec, d, nullptr))};
1364  if (pd) {
1365  hoc_pushpx(pd);
1366  return;
1367  }
1368  }
1369  auto const i = node_index(sec, d);
1370  hoc_push(dprop(s, indx, sec, i));
1371 }
1372 
1373 void rangevareval(void) /* symbol at pc, location on stack, return value on stack */
1374 {
1375  double* pd;
1376 
1378  pd = hoc_pxpop();
1379  hoc_pushx(*pd);
1380 }
1381 
1382 void rangepoint(void) /* symbol at pc, return value on stack */
1383 {
1384  hoc_pushx(.5);
1385  rangevareval();
1386 }
1387 
1388 void rangeobjeval(void) /* symbol at pc, section location on stack, return object on stack*/
1389 {
1390  Symbol* s{(pc++)->sym};
1391  assert(s->subtype == NMODLRANDOM); // the only possibility at the moment
1392  double d = xpop();
1393  Section* sec{nrn_sec_pop()};
1394  auto const i = node_index(sec, d);
1395  Prop* m = nrn_mechanism_check(s->u.rng.type, sec, i);
1396  Object* ob = nrn_nmodlrandom_wrap(m, s);
1397  hoc_push_object(ob);
1398 }
1399 
1400 void rangeobjevalmiddle(void) /* symbol at pc, return object on stack*/
1401 {
1402  hoc_pushx(0.5);
1403  rangeobjeval();
1404 }
1405 
1406 int node_index(Section* sec, double x) /* returns nearest index to x */
1407 {
1408  int i;
1409  double n;
1410 
1411  if (x < 0. || x > 1.) {
1412  hoc_execerror("range variable domain is 0<=x<=1", (char*) 0);
1413  }
1414  n = (double) (sec->nnode - 1);
1415  assert(n >= 0.);
1416  i = n * x;
1417  if (i == (int) n) {
1418  i = n - 1;
1419  }
1420  if (sec->prop->dparam[3].get<double>()) {
1421  i = n - i - 1;
1422  }
1423  return i;
1424 }
1425 
1426 int node_index_exact(Section* sec, double x) {
1427  if (x == 0.) {
1428  if (arc0at0(sec)) {
1429  return -1;
1430  } else {
1431  return sec->nnode - 1;
1432  }
1433  } else if (x == 1.) {
1434  if (arc0at0(sec)) {
1435  return sec->nnode - 1;
1436  } else {
1437  return -1;
1438  }
1439  } else {
1440  return node_index(sec, x);
1441  }
1442 }
1443 /*USERPROPERTY subtype of VAR used for non range variables associated
1444 with section property
1445 may have special actions (eg. nseg)*/
1446 
1447 double cable_prop_eval(Symbol* sym) {
1448  Section* sec;
1449  sec = nrn_sec_pop();
1450  switch (sym->u.rng.type) {
1451  case 0: /* not in property list so must be nnode */
1452  return (double) sec->nnode - 1;
1453  case CABLESECTION:
1454  return sec->prop->dparam[sym->u.rng.index].get<double>();
1455  default:
1456  hoc_execerror(sym->name, " not a USERPROPERTY");
1457  }
1458  return 0.;
1459 }
1460 
1462  Section* sec;
1463  sec = nrn_sec_pop();
1464  switch (sym->u.rng.type) {
1465  case CABLESECTION:
1466  return &(sec->prop->dparam[sym->u.rng.index].literal_value<double>());
1467  default:
1468  hoc_execerror(sym->name, " not a USERPROPERTY that can be pointed to");
1469  }
1470  return nullptr;
1471 }
1472 
1473 #if KEEP_NSEG_PARM
1475 void keep_nseg_parm(void) {
1476  int i = keep_nseg_parm_;
1477  keep_nseg_parm_ = (int) chkarg(1, 0., 1.);
1478  hoc_retpushx((double) i);
1479 }
1480 #endif
1481 
1483  if (n > 32767.) {
1484  n = 1;
1485  fprintf(stderr, "requesting %s.nseg=%d but the maximum value is 32767.\n", secname(sec), n);
1486  hoc_warning("nseg too large, setting to 1.", (char*) 0);
1487  }
1488  if (n < 1) {
1489  hoc_execerror("nseg", " must be positive");
1490  }
1491  if (sec->nnode == n + 1) {
1492  return;
1493  } else {
1494  Node** pnd;
1495  int i;
1496  int nold = sec->nnode;
1497  node_alloc(sec, (short) n + 1);
1498  tree_changed = 1;
1499  diam_changed = 1;
1500  sec->recalc_area_ = 1;
1501  pnd = sec->pnode;
1502 #if KEEP_NSEG_PARM
1503  if (!keep_nseg_parm_ || nold == 0)
1504 #endif
1505  for (i = 0; i < n; i++) {
1506  IGNORE(prop_alloc(&(pnd[i]->prop), MORPHOLOGY, pnd[i]));
1507  IGNORE(prop_alloc(&(pnd[i]->prop), CAP, pnd[i]));
1508  }
1509  }
1510 }
1511 
1512 void cable_prop_assign(Symbol* sym, double* pd, int op) {
1513  Section* sec;
1514  sec = nrn_sec_pop();
1515  switch (sym->u.rng.type) {
1516  case 0: /* not in property list so must be nnode */
1517  if (op) {
1518  *pd = hoc_opasgn(op, (double) (sec->nnode - 1), *pd);
1519  }
1520  nrn_change_nseg(sec, (int) (*pd));
1521  break;
1522  case CABLESECTION:
1523  if (sym->u.rng.index == 2) {
1524  if (can_change_morph(sec)) {
1525  if (op) {
1526  *pd = hoc_opasgn(op, sec->prop->dparam[2].get<double>(), *pd);
1527  }
1528  sec->prop->dparam[2] = *pd;
1529  nrn_length_change(sec, *pd);
1530  diam_changed = 1;
1531  sec->recalc_area_ = 1;
1532  }
1533  } else {
1534  if (op) {
1535  *pd = hoc_opasgn(op, sec->prop->dparam[sym->u.rng.index].get<double>(), *pd);
1536  }
1537  diam_changed = 1;
1538  sec->recalc_area_ = 1;
1539  sec->prop->dparam[sym->u.rng.index] = *pd;
1540  }
1541 #if RA_WARNING
1542  if (sym->u.rng.index == 7) {
1543  ++nrn_ra_set;
1544  }
1545 #endif
1546  break;
1547  default:
1548  hoc_execerror(sym->name, " not a USERPROPERTY");
1549  }
1550 }
1551 
1553  return sec->prop->dparam[1].get<double>();
1554 }
1555 
1557  return sec->prop->dparam[3].get<double>();
1558 }
1559 
1561  assert(sec->parentsec);
1562  return nrn_connection_position(sec) == nrn_section_orientation(sec->parentsec);
1563 }
1564 
1566  sec->parentnode = new Node{};
1567  sec->parentnode->sec_node_index_ = 0;
1568  sec->parentnode->sec = sec;
1569 #if EXTRACELLULAR
1570  if (sec->pnode[0]->extnode) {
1571  prop_alloc(&sec->parentnode->prop, EXTRACELL, sec->parentnode);
1572  extcell_node_create(sec->parentnode);
1573  }
1574 #endif
1575 }
1576 
1578  Section* psec;
1579  for (psec = sec->parentsec; psec; psec = psec->parentsec) {
1580  if (nrn_at_beginning(sec)) {
1581  sec = psec;
1582  } else {
1583  break;
1584  }
1585  }
1586  return psec;
1587 }
1588 
1590  /* determine the parentnode using only the authoritative
1591  info of parentsec
1592  and arc length connection position */
1593  /* side effects are that on exit, s will have the right parentnode
1594  and the true parent (not connected to any section) will have the
1595  right parentnode
1596  */
1597 
1598  Section *sec, *psec, *true_parent;
1599  Node* pnode;
1600  double x;
1601 
1602  true_parent = (Section*) 0;
1603  for (sec = s, psec = sec->parentsec; psec; sec = psec, psec = sec->parentsec) {
1604  if (psec == s) {
1605  fprintf(stderr, "%s connection to ", secname(s));
1606  fprintf(stderr, "%s will form a loop\n", secname(s->parentsec));
1607  nrn_disconnect(s);
1608  hoc_execerror(secname(s), "connection will form loop");
1609  }
1611  if (x != nrn_section_orientation(psec)) {
1612  true_parent = psec;
1613  if (x == 1. || x == 0.) {
1614  pnode = psec->pnode[psec->nnode - 1];
1615  } else {
1616  pnode = psec->pnode[node_index(psec, x)];
1617  }
1618  break;
1619  }
1620  }
1621  if (true_parent == (Section*) 0) {
1622  if (sec->parentnode) {
1623  /* non nullptr parent node in section without a parent is
1624  definitely valid
1625  */
1626  pnode = sec->parentnode;
1627  } else {
1629  pnode = sec->parentnode;
1630  }
1631  }
1632  s->parentnode = pnode;
1633 }
1634 
1635 void setup_topology(void) {
1636  /* use connection info in section property to connect nodes. */
1637  /* for the moment we assume uniform dx and range 0-1 */
1638 
1639  /* Sections may be connected to a parent at an orientation (usually
1640  0) at which the node belongs to some ancestor of the parent.
1641  All difficulties derive from that fact.
1642  ie. the parentnode may not belong to the parentsec. And
1643  parent nodes may be invalid. And if they are valid then
1644  we want to maintain the useful info such as point processes
1645  which are in them. ie, we only change the parentnode here
1646  if it is invalid.
1647  */
1648 
1649  nrn_global_ncell = 0;
1650 
1651  for (Section* sec: range_sec(section_list)) {
1652 #if 0
1653  if (sec->nnode < 1) { /* last node is not a segment */
1655  " has no segments");
1656  }
1657 #else
1658  assert(sec->nnode > 0);
1659 #endif
1661  if (!sec->parentsec) {
1662  ++nrn_global_ncell;
1663  }
1664  }
1665 
1666  section_order();
1667  tree_changed = 0;
1668  diam_changed = 1;
1669  v_structure_change = 1;
1671 }
1672 
1673 // name of section (for use in error messages)
1674 const char* secname(Section* sec) {
1675  static char name[512];
1676  if (sec && sec->prop) {
1677  if (auto* s = sec->prop->dparam[0].get<Symbol*>(); s) {
1678  auto indx = sec->prop->dparam[5].get<int>();
1679  auto* ob = sec->prop->dparam[6].get<Object*>();
1680  if (ob) {
1681  Sprintf(name,
1682  "%s.%s%s",
1683  hoc_object_name(ob),
1684  s->name,
1685  hoc_araystr(s, indx, ob->u.dataspace));
1686  } else {
1687  Sprintf(name, "%s%s", s->name, hoc_araystr(s, indx, hoc_top_level_data));
1688  }
1689 #if USE_PYTHON
1690  } else if (sec->prop->dparam[PROP_PY_INDEX].get<void*>()) {
1692  return (*nrnpy_pysec_name_p_)(sec);
1693 #endif
1694  } else {
1695  name[0] = '\0';
1696  }
1697  } else {
1698  name[0] = '\0';
1699  }
1700  return name;
1701 }
1702 
1704 #if USE_PYTHON
1705  static char buf[256];
1706  const char* name = secname(sec);
1707  if (sec && sec->prop->dparam[PROP_PY_INDEX].get<void*>() &&
1708  strncmp(name, "__nrnsec_0x", 11) != 0) {
1709  Sprintf(buf, "_pysec.%s", name);
1710  } else {
1711  strcpy(buf, name);
1712  }
1713  return buf;
1714 #else
1715  return secname(sec);
1716 #endif
1717 }
1718 
1719 void section_owner(void) {
1720  Section* sec;
1721  Object* ob;
1722  sec = chk_access();
1723  ob = nrn_sec2cell(sec);
1724  hoc_ret();
1725  hoc_push_object(ob);
1726 }
1727 
1729  static char name[200];
1730  if (auto* s = sec->prop->dparam[0].get<Symbol*>(); sec && sec->prop && s) {
1731  auto indx = sec->prop->dparam[5].get<int>();
1732  auto* ob = sec->prop->dparam[6].get<Object*>();
1733  if (ob) {
1734  char* p = hoc_object_pathname(ob);
1735  if (p) {
1736  Sprintf(name, "%s.%s%s", p, s->name, hoc_araystr(s, indx, ob->u.dataspace));
1737  } else {
1738  hoc_warning("Can't find a pathname for", secname(sec));
1739  strcpy(name, secname(sec));
1740  return name;
1741  }
1742  } else {
1743  Sprintf(name, "%s%s", s->name, hoc_araystr(s, indx, hoc_objectdata));
1744  }
1745 #if USE_PYTHON
1746  } else if (sec && sec->prop && sec->prop->dparam[PROP_PY_INDEX].get<void*>()) {
1747  strcpy(name, nrn_sec2pysecname(sec));
1748 #endif
1749  } else {
1750  name[0] = '\0';
1751  }
1752  return name;
1753 }
1754 
1756  int inode;
1757  double x;
1758  assert(sec);
1759  if (sec->parentnode == node) {
1760  x = 0.;
1761  } else if ((inode = node->sec_node_index_) == sec->nnode - 1) {
1762  x = 1.;
1763  } else {
1764  x = ((double) inode + .5) / ((double) sec->nnode - 1.);
1765  }
1766  if (arc0at0(sec)) {
1767  return x;
1768  } else {
1769  return 1. - x;
1770  }
1771 }
1772 
1773 const char* sec_and_position(Section* sec, Node* nd) {
1774  const char* buf;
1775  static char buf1[200];
1776  double x;
1777  assert(sec);
1778  buf = secname(sec);
1779  x = nrn_arc_position(sec, nd);
1780  Sprintf(buf1, "%s(%g)", buf, x);
1781  return buf1;
1782 }
1783 
1784 int segment_limits(double* pdx) {
1785  int n;
1786  Section* sec;
1787  double l;
1788 
1789  sec = chk_access();
1790  n = sec->nnode - 1;
1791  /* l = sec->prop->dparam[2].val;*/
1792  l = 1.;
1793  *pdx = l / ((double) n);
1794  return sec->nnode;
1795 }
1796 
1797 #undef PI
1798 #define PI 3.14159265358979323846
1799 
1800 Node* node_exact(Section* sec, double x) {
1801  /* like node_index but give proper node when
1802  x is 0 or 1 as well as in between
1803  */
1804  Node* node;
1805  assert(sec);
1806  {
1807  if (x <= 0. || x >= 1.) {
1808  x = (x < 0.) ? 0. : x;
1809  x = (x > 1.) ? 1. : x;
1810  if (sec->prop->dparam[3].get<double>()) {
1811  x = 1. - x;
1812  }
1813  if (x == 0.) {
1814  if (tree_changed) {
1815  setup_topology();
1816  }
1817  node = sec->parentnode;
1818  } else {
1819  node = sec->pnode[sec->nnode - 1];
1820  }
1821  } else {
1822  node = sec->pnode[node_index(sec, x)];
1823  }
1824  }
1825  return node;
1826 }
1827 
1828 Node* node_ptr(Section* sec, double x, double* parea) {
1829  /* returns pointer to proper node and the area of the node */
1830  Node* nd;
1831 
1832  nd = node_exact(sec, x);
1833  if (parea) {
1834  if (nd->sec->recalc_area_) {
1835  nrn_area_ri(nd->sec);
1836  }
1837  *parea = NODEAREA(nd);
1838  }
1839  return nd;
1840 }
1841 
1842 int nrn_get_mechtype(const char* mechname) {
1843  Symbol* s;
1844  s = hoc_lookup(mechname);
1845  assert(s);
1846  if (s->type == TEMPLATE) {
1847  s = hoc_table_lookup(mechname, s->u.ctemplate->symtable);
1848  assert(s && s->type == MECHANISM);
1849  }
1850  return s->subtype;
1851 }
1852 
1853 #if EXTRACELLULAR
1854 /* want to handle vext(0), vext(1) correctly. No associated i_membrane though.*/
1855 /*
1856 otherwise return correct pointer to vext if it exists
1857 return pointer to zero if a child node has extnode
1858 return 0 if symbol is not vext.
1859 */
1860 double* nrn_vext_pd(Symbol* s, int indx, Node* nd) {
1861  static double zero;
1862  if (s->u.rng.type != EXTRACELL) {
1863  return (double*) 0;
1864  }
1865  if (std::size_t(s->u.rng.index) != neuron::extracellular::vext_pseudoindex()) {
1866  return nullptr;
1867  }
1868  zero = 0.;
1869  if (nd->extnode) {
1870  return nd->extnode->v + indx;
1871  } else {
1872  Section* sec;
1873  /* apparently not maintaining Node.child */
1874  /*for (sec = nd->child; sec; sec = sec->sibling) {*/
1875  for (sec = nd->sec->child; sec; sec = sec->sibling) {
1876  if (sec->pnode[0]->extnode) {
1877  return &zero;
1878  }
1879  }
1880  return (double*) 0;
1881  }
1882 }
1883 #endif
1884 
1885 class VoidPointerError: public std::runtime_error {
1886  public:
1887  using std::runtime_error::runtime_error;
1888 };
1889 
1891  Symbol* s,
1892  int indx,
1893  Section* sec,
1894  short inode) {
1895 #if EXTRACELLULAR
1896  // old comment: this does not handle vext(0) and vext(1) properly at this time
1897  if (m->_type == EXTRACELL &&
1898  std::size_t(s->u.rng.index) == neuron::extracellular::vext_pseudoindex()) {
1900  sec->pnode[inode]->extnode->v + indx};
1901  }
1902 #endif
1903  if (s->subtype != NRNPOINTER) {
1904  if (m->ob) {
1905  return neuron::container::data_handle<double>{m->ob->u.dataspace[s->u.rng.index].pval +
1906  indx};
1907  } else {
1908  return m->param_handle_legacy(s->u.rng.index + indx);
1909  }
1910  } else {
1911  neuron::container::generic_data_handle const p{m->dparam[s->u.rng.index + indx]};
1912  if (p.is_invalid_handle()) {
1913  throw VoidPointerError(std::string(s->name) + " wasn't made to point to anything");
1914  }
1915  return p;
1916  }
1917 }
1918 
1919 
1920 /* if you change this then change nrnpy_dprop as well */
1921 /* returns location of property symbol */
1923  auto* const m = nrn_mechanism_check(s->u.rng.type, sec, inode);
1924  try {
1926  } catch (const VoidPointerError& e) {
1927  hoc_execerror(e.what(), nullptr);
1928  }
1929 }
1930 
1931 /* return nullptr instead of hoc_execerror. */
1932 /* returns location of property symbol */
1934  int indx,
1935  Section* sec,
1936  short inode,
1937  int* err) {
1938  auto* const m = nrn_mechanism(s->u.rng.type, sec->pnode[inode]);
1939  if (!m) {
1940  *err = 1;
1941  return {};
1942  }
1943  try {
1944  return dprop_impl(m, s, indx, sec, inode);
1945  } catch (const VoidPointerError& e) {
1946  *err = 2;
1947  }
1948  return {};
1949 }
1950 
1951 static char* objectname(void) {
1952  static char buf[100];
1953  if (hoc_thisobject) {
1955  } else {
1956  buf[0] = '\0';
1957  }
1958  return buf;
1959 }
1960 
1961 #define relative(pc) (pc + (pc)->i)
1962 
1963 void forall_section(void) {
1964  /*statement pointed to by pc
1965  continuation pointed to by pc+1. template used is shortfor in code.cpp
1966  of hoc system.
1967  */
1968  /* if inside object then forall refers only to sections in the object */
1969 
1970  Inst* savepc = pc;
1971  Item *qsec, *first, *last;
1972  char buf[200];
1973  char** s;
1974  int istk;
1975 
1976  /* fast forall within an object asserts that the object sections
1977  are contiguous and secelm_ is the last.
1978  */
1979  if (hoc_thisobject) {
1980  qsec = hoc_thisobject->secelm_;
1981  if (qsec) {
1982  for (first = qsec;
1983  first->prev->itemtype &&
1984  hocSEC(first->prev)->prop->dparam[6].get<Object*>() == hoc_thisobject;
1985  first = first->prev) {
1986  }
1987  last = qsec->next;
1988  } else {
1989  first = (Item*) 0;
1990  last = (Item*) 0;
1991  }
1992  } else {
1993  first = section_list->next;
1994  last = section_list;
1995  }
1996  s = hoc_strpop();
1997  buf[0] = '\0';
1998  if (s) {
1999  Sprintf(buf, "%s.*%s.*", objectname(), *s);
2000  } else {
2001  char* o = objectname();
2002  if (o[0]) {
2003  Sprintf(buf, "%s.*", o);
2004  }
2005  }
2006  istk = nrn_isecstack();
2007  /* do the iteration safely. a possible command is to delete the section*/
2008  for (qsec = first; qsec != last;) {
2009  Section* sec = hocSEC(qsec);
2010  qsec = qsec->next;
2011  if (buf[0]) {
2012  std::regex pattern(escape_bracket(buf));
2013  if (!std::regex_match(secname(sec), pattern)) {
2014  continue;
2015  }
2016  }
2017  nrn_pushsec(sec);
2018  hoc_execute(relative(savepc));
2019  nrn_popsec();
2020  if (hoc_returning) {
2021  nrn_secstack(istk);
2022  }
2023  if (hoc_returning == 1 || hoc_returning == 4) {
2024  break;
2025  } else if (hoc_returning == 2) {
2026  hoc_returning = 0;
2027  break;
2028  } else {
2029  hoc_returning = 0;
2030  }
2031  }
2032  if (!hoc_returning)
2033  pc = relative(savepc + 1);
2034 }
2035 
2036 void hoc_ifsec(void) {
2037  Inst* savepc = pc;
2038  char buf[200];
2039  char** s;
2040  extern int hoc_returning;
2041 
2042  s = hoc_strpop();
2043  Sprintf(buf, ".*%s.*", *s);
2044  std::regex pattern(escape_bracket(buf));
2045  if (std::regex_match(secname(chk_access()), pattern)) {
2046  hoc_execute(relative(savepc));
2047  }
2048  if (!hoc_returning)
2049  pc = relative(savepc + 1);
2050 }
2051 
2052 void issection(void) { /* returns true if string is the access section */
2053  std::regex pattern(escape_bracket(gargstr(1)));
2054  if (std::regex_match(secname(chk_access()), pattern)) {
2055  hoc_retpushx(1.);
2056  } else {
2057  hoc_retpushx(0.);
2058  }
2059 }
2060 
2061 int has_membrane(char* mechanism_name, Section* sec) {
2062  /* return true if string is an inserted membrane in the
2063  section sec */
2064  Prop* p;
2065  for (p = sec->pnode[0]->prop; p; p = p->next) {
2066  if (strcmp(memb_func[p->_type].sym->name, mechanism_name) == 0) {
2067  return (1);
2068  }
2069  }
2070  return (0);
2071 }
2072 
2073 void ismembrane(void) { /* return true if string is an inserted membrane in the
2074  access section */
2075  char* str = gargstr(1);
2076  hoc_retpushx((double) has_membrane(str, chk_access()));
2077 }
2078 
2079 void sectionname(void) {
2080  char** cpp;
2081 
2082  cpp = hoc_pgargstr(1);
2083  if (ifarg(2) && chkarg(2, 0., 1.) == 0.) {
2085  } else {
2087  }
2088  hoc_retpushx(1.);
2089 }
2090 
2091 void hoc_secname(void) {
2092  static char* buf = (char*) 0;
2093  Section* sec = chk_access();
2094  if (!buf) {
2095  buf = static_cast<char*>(emalloc(256 * sizeof(char)));
2096  }
2097  if (ifarg(1) && chkarg(1, 0., 1.) == 0.) {
2098  strcpy(buf, secname(sec));
2099  } else {
2100  strcpy(buf, nrn_sec2pysecname(sec));
2101  }
2102  hoc_ret();
2103  hoc_pushstr(&buf);
2104 }
2105 
2106 static double chk_void2dbl(void* vp, const char* mes) {
2107  size_t n = (size_t) vp;
2108  if (sizeof(void*) == 8) {
2109  size_t maxvoid2dbl = ((size_t) 1) << 53;
2110 #if 0
2111  printf("sizeof void*, size_t, and double = %zd, %zd, %zd\n",
2112  sizeof(void*), sizeof(size_t), sizeof(double));
2113  printf("(double)((1<<53) - 1)=%.20g\n", (double)(maxvoid2dbl - 1));
2114  printf("(double)((1<<53) + 0)=%.20g\n", (double)(maxvoid2dbl));
2115  printf("(double)((1<<53) + 1)=%.20g\n", (double)(maxvoid2dbl + 1));
2116  printf("(size_t)(vp) = %zd\n", n);
2117 #endif
2118  if (n > maxvoid2dbl) {
2119  hoc_execerror(mes, "pointer too large to be represented by a double");
2120  }
2121  } else if (sizeof(void*) > 8) {
2122  hoc_execerror(mes, "not implemented for sizeof(void*) > 8");
2123  }
2124  return (double) n;
2125 }
2126 
2127 void this_section(void) {
2128  /* return section number of currently accessed section at
2129  arc length postition x */
2130 
2131  Section* sec;
2132  sec = chk_access();
2133  hoc_retpushx(chk_void2dbl(sec, "this_section"));
2134 }
2135 void this_node(void) {
2136  /* return node number of currently accessed section at
2137  arc length postition x */
2138 
2139  Section* sec;
2140  Node* nd;
2141  sec = chk_access();
2142  nd = node_exact(sec, *getarg(1));
2143  hoc_retpushx(chk_void2dbl(nd, "this_node"));
2144 }
2145 void parent_section(void) {
2146  /* return section number of currently accessed section at
2147  arc length postition x */
2148 
2149  Section* sec;
2150  sec = chk_access();
2151  hoc_retpushx(chk_void2dbl(sec->parentsec, "parent_section"));
2152 }
2153 void parent_connection(void) {
2154  Section* sec;
2155  sec = chk_access();
2157 }
2158 
2160  Section* sec;
2161  sec = chk_access();
2163 }
2164 
2165 void parent_node(void) {
2166  Section* sec;
2167  if (tree_changed) {
2168  setup_topology();
2169  }
2170  sec = chk_access();
2171  hoc_retpushx(chk_void2dbl(sec->parentnode, "parent_node"));
2172 }
2173 
2174 void pop_section(void) {
2176  if (skip_secstack_check < 0) {
2177  skip_secstack_check = 0;
2178  }
2179  nrn_popsec();
2180  hoc_retpushx(1.);
2181 }
2182 
2183 /* turn off section stack fixing (in case of return,continue,break in a section statement) between
2184  * exlicit user level push_section,etc and pop_section
2185  */
2186 
2189  nrn_pushsec(sec);
2190 }
2191 
2192 void push_section(void) {
2193  Section* sec = nullptr;
2194  if (hoc_is_str_arg(1)) {
2195  char* s;
2196  s = gargstr(1);
2197  for (Section* sec1: range_sec(section_list)) {
2198  if (strcmp(s, nrn_sec2pysecname(sec1)) == 0) {
2199  sec = sec1;
2200  break;
2201  }
2202  }
2203  if (!sec) {
2204  hoc_execerror("push_section: arg not a sectionname:", s);
2205  }
2206  } else {
2207  sec = (Section*) (size_t) (*getarg(1));
2208  }
2209  if (!sec || !sec->prop || !sec->prop->dparam || !sec->prop->dparam[8].get<hoc_Item*>() ||
2210  sec->prop->dparam[8].get<hoc_Item*>()->itemtype != SECTION) {
2211  hoc_execerror("Not a Section pointer", (char*) 0);
2212  }
2214  hoc_retpushx(1.0);
2215 }
2216 
2217 
2219  Section* sec = (Section*) 0;
2220  Symbol* sym = (Symbol*) 0;
2221  Object* obj = cell;
2222  Objectdata* obd;
2223  Item* itm;
2224  if (obj) {
2225  sym = hoc_table_lookup(name, obj->ctemplate->symtable);
2226  /* if external then back to top level */
2227  if (sym && sym->cpublic == 2) {
2228  sym = sym->u.sym;
2229  obj = nullptr;
2230  }
2231  } else {
2233  }
2234  if (sym) {
2235  if (sym->type == SECTION) {
2236  if (obj) {
2237  obd = obj->u.dataspace;
2238  } else {
2239  obd = hoc_top_level_data;
2240  }
2241  if (indx >= 0 && std::size_t(indx) < hoc_total_array_data(sym, obd)) {
2242  itm = *(obd[sym->u.oboff].psecitm + indx);
2243  if (itm) {
2244  sec = itm->element.sec;
2245  }
2246  }
2247  }
2248  }
2249  return sec;
2250 }
2251 
2252 void section_exists(void) {
2253  int iarg, indx;
2254  Section* sec;
2255  Object* obj;
2256  char *str, buf[100];
2257 
2258  obj = nullptr;
2259  sec = (Section*) 0;
2260  iarg = 1;
2261  str = gargstr(iarg++);
2262 
2263  indx = 0;
2264  if (ifarg(iarg) && hoc_is_double_arg(iarg)) {
2265  indx = (int) chkarg(iarg++, 0., 1e9);
2266  } else { /* if [integer] present, then extract the value and the basename */
2267  if (sscanf(str, "%[^[][%d", buf, &indx) == 2) {
2268  str = buf;
2269  }
2270  }
2271  if (ifarg(iarg)) {
2272  obj = *hoc_objgetarg(iarg);
2273  }
2274  sec = nrn_section_exists(str, indx, obj);
2275  hoc_retpushx((double) (sec && sec->prop));
2276 }
int diam_changed
Definition: cabcode.cpp:55
void rangevareval(void)
Definition: cabcode.cpp:1373
void section_exists(void)
Definition: cabcode.cpp:2252
Object *(* nrnpy_pysec_cell_p_)(Section *)
Definition: cabcode.cpp:61
int keep_nseg_parm_
Definition: cabcode.cpp:1474
int segment_limits(double *pdx)
Definition: cabcode.cpp:1784
double nrn_section_orientation(Section *sec)
Definition: cabcode.cpp:1556
Section * chk_access()
Definition: cabcode.cpp:449
void rangeobjeval(void)
Definition: cabcode.cpp:1388
const char * secname(Section *sec)
name of section (for use in error messages)
Definition: cabcode.cpp:1674
void parent_node(void)
Definition: cabcode.cpp:2165
void hoc_sec_internal_push(void)
Definition: cabcode.cpp:759
static double chk_void2dbl(void *vp, const char *mes)
Definition: cabcode.cpp:2106
void nrn_change_nseg(Section *sec, int n)
Definition: cabcode.cpp:1482
void delete_section(void)
Definition: cabcode.cpp:339
void nrn_secstack(int i)
Definition: cabcode.cpp:89
void cab_alloc(Prop *p)
Definition: cabcode.cpp:421
void oc_save_cabcode(int *a1, int *a2)
Definition: cabcode.cpp:117
neuron::container::generic_data_handle nrnpy_dprop(Symbol *s, int indx, Section *sec, short inode, int *err)
returns location of property symbol, return nullptr instead of hoc_execerror
Definition: cabcode.cpp:1933
static int range_vec_indx(Symbol *s)
Definition: cabcode.cpp:1026
void sectionname(void)
Definition: cabcode.cpp:2079
static void nrn_remove_sibling_list(Section *sec)
Definition: cabcode.cpp:502
void mech_uninsert1(Section *sec, Symbol *s)
Definition: cabcode.cpp:898
#define NSECSTACK
Definition: cabcode.cpp:73
static Section * secstack[NSECSTACK+1]
Definition: cabcode.cpp:74
static void nrn_add_sibling_list(Section *sec)
Definition: cabcode.cpp:528
double * nrn_vext_pd(Symbol *s, int indx, Node *nd)
Definition: cabcode.cpp:1860
void rangeobjevalmiddle(void)
Definition: cabcode.cpp:1400
int hoc_execerror_messages
Definition: hoc.cpp:607
static void connectsec_impl(Section *parent, Section *sec)
Definition: cabcode.cpp:615
void sec_access_pop(void)
Definition: cabcode.cpp:164
static int skip_secstack_check
Definition: cabcode.cpp:81
#define CAB_SIZE
int node_index_exact(Section *sec, double x)
return -1 if x at connection end, nnode-1 if at other end
Definition: cabcode.cpp:1426
void rangevarevalpointer()
Definition: cabcode.cpp:1339
static void nrn_rootnode_alloc(Section *sec)
Definition: cabcode.cpp:1565
Node * node_ptr(Section *sec, double x, double *parea)
Definition: cabcode.cpp:1828
void nrn_pushsec(Section *sec)
Definition: cabcode.cpp:130
void nrn_parent_info(Section *s)
Definition: cabcode.cpp:1589
double nrn_arc_position(Section *sec, Node *node)
Definition: cabcode.cpp:1755
void parent_connection(void)
Definition: cabcode.cpp:2153
Prop * hoc_getdata_range(int type)
Definition: cabcode.cpp:1065
int has_membrane(char *mechanism_name, Section *sec)
Definition: cabcode.cpp:2061
double cable_prop_eval(Symbol *sym)
Definition: cabcode.cpp:1447
Section * nrn_trueparent(Section *sec)
Definition: cabcode.cpp:1577
void mech_access(void)
Definition: cabcode.cpp:846
void simpleconnectsection(void)
Definition: cabcode.cpp:664
Prop * nrn_mechanism(int type, Node *nd)
Definition: cabcode.cpp:1038
void ismembrane(void)
Definition: cabcode.cpp:2073
void cable_prop_assign(Symbol *sym, double *pd, int op)
Definition: cabcode.cpp:1512
int nrn_shape_changed_
Definition: neuron.h:24
void setup_topology(void)
Definition: cabcode.cpp:1635
void range_const()
Definition: cabcode.cpp:1014
void range_interpolate(void)
Definition: cabcode.cpp:1138
void morph_alloc(Prop *p)
Definition: cabcode.cpp:438
void add_section(void)
Definition: cabcode.cpp:205
void forall_section(void)
Definition: cabcode.cpp:1963
void this_section(void)
Definition: cabcode.cpp:2127
double nrn_ra(Section *sec)
Definition: cabcode.cpp:417
static int isecstack
Definition: cabcode.cpp:75
int nrn_isecstack(void)
Definition: cabcode.cpp:85
void nrn_rangeconst(Section *sec, Symbol *s, neuron::container::data_handle< double > pd, int op)
Definition: cabcode.cpp:935
static Section * new_section(Object *ob, Symbol *sym, int i)
Definition: cabcode.cpp:278
double section_length(Section *sec)
Definition: cabcode.cpp:401
int node_index(Section *sec, double x)
returns nearest index to x
Definition: cabcode.cpp:1406
void mech_uninsert(void)
Definition: cabcode.cpp:892
neuron::container::generic_data_handle nrnpy_rangepointer(Section *sec, Symbol *s, double d, int *err, int idx)
return nullptr if failure instead of hoc_execerror and return pointer to the 0 element if an array
Definition: cabcode.cpp:1306
int nrn_sec2cell_equals(Section *sec, Object *obj)
Definition: cabcode.cpp:267
void connectsection(void)
Definition: cabcode.cpp:673
void sec_access(void)
Definition: cabcode.cpp:720
void hoc_secname(void)
Definition: cabcode.cpp:2091
double nrn_connection_position(Section *sec)
Definition: cabcode.cpp:1552
static char * escape_bracket(const char *s)
Definition: cabcode.cpp:18
int nrn_exists(Symbol *s, Node *node)
Definition: cabcode.cpp:1258
Section * nrn_noerr_access(void)
return 0 if no accessed section
Definition: cabcode.cpp:474
void connectpointer()
Definition: cabcode.cpp:1084
int(* nrnpy_pysec_cell_equals_p_)(Section *, Object *)
Definition: cabcode.cpp:62
static Section * Sec_access(void)
Definition: cabcode.cpp:681
void keep_nseg_parm(void)
Definition: cabcode.cpp:1475
static void reverse_sibling_list(Section *sec)
Definition: cabcode.cpp:551
neuron::container::data_handle< double > dprop(Symbol *s, int indx, Section *sec, short inode)
returns location of property symbol
Definition: cabcode.cpp:1922
void disconnect()
Definition: cabcode.cpp:568
void range_interpolate_single(void)
Definition: cabcode.cpp:1097
int arc0at0(Section *sec)
Definition: cabcode.cpp:413
void sec_access_push(void)
Definition: cabcode.cpp:749
void pop_section(void)
Definition: cabcode.cpp:2174
void sec_access_object(void)
Definition: cabcode.cpp:732
Section * nrn_sec_pop(void)
Definition: cabcode.cpp:753
static double ncp_abs(Section *sec)
Definition: cabcode.cpp:518
neuron::container::generic_data_handle dprop_impl(Prop *m, Symbol *s, int indx, Section *sec, short inode)
Definition: cabcode.cpp:1890
Object * nrn_sec2cell(Section *sec)
Definition: cabcode.cpp:252
int nrn_get_mechtype(const char *mechname)
Definition: cabcode.cpp:1842
void section_orientation(void)
Definition: cabcode.cpp:2159
#define relative(pc)
Definition: cabcode.cpp:1961
void this_node(void)
Definition: cabcode.cpp:2135
void hoc_ifsec(void)
Definition: cabcode.cpp:2036
void new_sections(Object *ob, Symbol *sym, Item **pitm, int size)
Definition: cabcode.cpp:304
int tree_changed
Definition: cabcode.cpp:51
Prop * nrn_mechanism_check(int type, Section *sec, int inode)
returns prop given mech type, section, and inode error if mech not at this position
Definition: cabcode.cpp:1050
double nrn_diameter(Node *nd)
Definition: cabcode.cpp:444
void hoc_level_pushsec(Section *sec)
turn off section stack fixing (in case of return, continue, break in a section statement) between exp...
Definition: cabcode.cpp:2187
const char * sec_and_position(Section *sec, Node *nd)
Definition: cabcode.cpp:1773
neuron::container::data_handle< double > nrn_rangepointer(Section *sec, Symbol *s, double d)
Definition: cabcode.cpp:1274
void nrn_initcode(void)
Definition: cabcode.cpp:107
void oc_restore_cabcode(int *a1, int *a2)
Definition: cabcode.cpp:122
void nrn_popsec(void)
Definition: cabcode.cpp:154
void ob_sec_access_push(hoc_Item *qsec)
Definition: cabcode.cpp:827
void ob_sec_access()
Definition: cabcode.cpp:834
char *(* nrnpy_pysec_name_p_)(Section *)
Definition: cabcode.cpp:60
void parent_section(void)
Definition: cabcode.cpp:2145
void nrn_disconnect(Section *sec)
Definition: cabcode.cpp:593
void push_section(void)
Definition: cabcode.cpp:2192
char * hoc_section_pathname(Section *sec)
Definition: cabcode.cpp:1728
Node * node_exact(Section *sec, double x)
like node_index but give proper node when x is 0 or 1 as well as in between
Definition: cabcode.cpp:1800
void mech_insert1(Section *sec, int type)
Definition: cabcode.cpp:852
#define symlist
Definition: cabcode.cpp:49
static char * objectname(void)
Definition: cabcode.cpp:1951
Section * section_new(Symbol *sym)
Creates a new section and registers with the global section list.
Definition: cabcode.cpp:323
static void reverse_nodes(Section *sec)
Definition: cabcode.cpp:580
double * cable_prop_eval_pointer(Symbol *sym)
Definition: cabcode.cpp:1461
static Datum * pdprop(Symbol *s, int indx, Section *sec, short inode)
Definition: cabcode.cpp:1075
Section * nrn_section_exists(char *name, int indx, Object *cell)
Definition: cabcode.cpp:2218
void rangepoint(void)
Definition: cabcode.cpp:1382
const char * nrn_sec2pysecname(Section *sec)
Definition: cabcode.cpp:1703
void section_owner(void)
Definition: cabcode.cpp:1719
int nrn_at_beginning(Section *sec)
Definition: cabcode.cpp:1560
void issection(void)
Definition: cabcode.cpp:2052
static void free_clamp(void)
Definition: clamp.cpp:143
static Node * pnd
Definition: clamp.cpp:33
Symbol * hoc_table_lookup(const char *, Symlist *)
Definition: symbol.cpp:48
char * gargstr(int narg)
Definition: code2.cpp:227
void clear_sectionlist(void)
#define v
Definition: md1redef.h:11
#define sec
Definition: md1redef.h:20
#define i
Definition: md1redef.h:19
#define prop
Definition: md1redef.h:38
Datum * nrn_prop_datum_alloc(int type, int count, Prop *p)
Definition: cxprop.cpp:33
int nrn_is_valid_section_ptr(void *v)
Definition: cxprop.cpp:101
static int indx
Definition: deriv.cpp:289
void extcell_2d_alloc(Section *sec)
Definition: extcelln.cpp:328
void extcell_node_create(Node *nd)
Definition: extcelln.cpp:302
double chkarg(int, double low, double high)
Definition: code2.cpp:626
static void free_stim(void)
Definition: fstim.cpp:124
#define NMODLRANDOM
Definition: modl.h:226
char buf[512]
Definition: init.cpp:13
char * hoc_object_pathname(Object *ob)
Definition: hoc_oop.cpp:1828
double hoc_xpop()
Definition: code.cpp:903
void hoc_pushstr(char **d)
Definition: code.cpp:800
void hoc_execerr_ext(const char *fmt,...)
printf style specification of hoc_execerror message.
Definition: fileio.cpp:828
Object * nrn_nmodlrandom_wrap(Prop *prop, Symbol *sym)
size_t hoc_total_array_data(const Symbol *s, Objectdata *obd)
Definition: hoc_oop.cpp:95
void hoc_ret()
int hoc_arayinfo_install(Symbol *sp, int nsub)
Definition: hoc.cpp:528
void hoc_pushpx(double *d)
Definition: code.cpp:834
void hoc_pushobj(Object **d)
Definition: code.cpp:784
void hoc_freearay(Symbol *sp)
Definition: hoc.cpp:567
void * hoc_sec_internal_name2ptr(const char *s, int eflag)
Definition: cabcode.cpp:764
int hoc_is_str_arg(int narg)
Definition: code.cpp:872
double * hoc_pxpop()
Definition: code.cpp:922
Objectdata * hoc_objectdata
Definition: hoc_oop.cpp:122
void hoc_assign_str(char **cpp, const char *buf)
Definition: code.cpp:2263
double hoc_opasgn(int op, double dest, double src)
Definition: code.cpp:1674
int hoc_is_double_arg(int narg)
Definition: code.cpp:864
void hoc_retpushx(double x)
Definition: hocusr.cpp:154
char * hoc_object_name(Object *ob)
Definition: hoc_oop.cpp:73
void * hoc_pysec_name2ptr(const char *s, int)
Definition: cabcode.cpp:806
void hoc_install_object_data_index(Symbol *sp)
Definition: hoc_oop.cpp:297
size_t hoc_total_array(Symbol *s)
Definition: hoc_oop.cpp:83
Symbol * hoc_lookup(const char *)
Definition: symbol.cpp:59
void hoc_nopop()
Definition: code.cpp:972
char * hoc_araystr(Symbol *sym, int index, Objectdata *obd)
Definition: code.cpp:2281
void hoc_push_object(Object *d)
Definition: code.cpp:793
void hoc_push(neuron::container::generic_data_handle handle)
Definition: code.cpp:850
char ** hoc_pgargstr(int narg)
Definition: code.cpp:1623
Objectdata * hoc_objectdata_restore(Objectdata *obdsav)
Definition: hoc_oop.cpp:142
Objectdata * hoc_objectdata_save(void)
Definition: hoc_oop.cpp:132
#define assert(ex)
Definition: hocassrt.h:24
#define getarg
Definition: hocdec.h:17
#define OPARINFO(sym)
Definition: hocdec.h:239
#define OPSECITM(sym)
Definition: hocdec.h:237
bool is_array(const Symbol &sym)
Definition: hocdec.h:136
#define hocSEC(q)
Definition: hoclist.h:87
constexpr auto range_sec(hoc_List *iterable)
Definition: hoclist.h:50
Object ** hoc_objgetarg(int)
Definition: code.cpp:1614
Symlist * hoc_top_level_symlist
Definition: code2.cpp:677
int hoc_araypt(Symbol *, int)
Definition: code.cpp:2340
Object * hoc_thisobject
Definition: hoc_oop.cpp:121
void hoc_pushx(double)
Definition: code.cpp:779
#define IMEMFAST
Definition: membfunc.h:114
#define NRNPOINTER
Definition: membfunc.hpp:83
#define CAP
Definition: membfunc.hpp:60
#define MORPHOLOGY
Definition: membfunc.hpp:59
#define CABLESECTION
Definition: membfunc.hpp:58
#define EXTRACELL
Definition: membfunc.hpp:61
#define VINDEX
Definition: membfunc.hpp:57
#define DEF_rallbranch
#define DEF_nseg
#define DEF_L
#define DEF_Ra
#define DEF_diam
#define SYMBOL
Definition: model.h:91
#define IGNORE(arg)
Definition: model.h:224
printf
Definition: extdef.h:5
const char * name
Definition: init.cpp:16
int state_discon_allowed_
int v_structure_change
Definition: nrnoc_aux.cpp:20
void hoc_execerror(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:39
static void * emalloc(size_t size)
Definition: mpispike.cpp:30
bool nrn_use_fast_imem
Definition: fast_imem.cpp:19
int nrn_is_ion(int)
void hoc_warning(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:44
constexpr do_not_search_t do_not_search
Definition: data_handle.hpp:11
std::size_t vext_pseudoindex()
Definition: membfunc.h:150
Model & model()
Access the global Model instance.
Definition: model_data.hpp:206
int Sprintf(char(&buf)[N], const char *fmt, Args &&... args)
Redirect sprintf to snprintf if the buffer size can be deduced.
Definition: wrap_sprintf.h:14
Prop * prop_alloc(Prop **, int, Node *)
Definition: treeset.cpp:671
void single_prop_free(Prop *)
Definition: treeset.cpp:718
static char * mechname
Definition: nocpout.cpp:137
void nrn_relocate_old_points(Section *oldsec, Node *oldnode, Section *sec, Node *node)
Definition: point.cpp:153
void nrn_area_ri(Section *sec)
Definition: treeset.cpp:752
void section_ref(Section *)
Definition: solve.cpp:520
int section_object_seen
Definition: hoc_oop.cpp:28
int can_change_morph(Section *)
Definition: treeset.cpp:1228
void section_unref(Section *)
Definition: solve.cpp:509
void section_order(void)
Definition: solve.cpp:729
void sec_free(hoc_Item *)
Definition: solve.cpp:467
void nrn_diam_change(Section *)
Definition: treeset.cpp:1185
void nrn_seg_or_x_arg(int iarg, Section **psec, double *px)
Definition: point.cpp:170
void nrn_length_change(Section *, double)
Definition: treeset.cpp:1205
static Node * node(Object *)
Definition: netcvode.cpp:291
int const size_t const size_t n
Definition: nrngsl.h:10
size_t p
size_t j
s
Definition: multisend.cpp:521
int ifarg(int)
Definition: code.cpp:1607
std::vector< Memb_func > memb_func
Definition: init.cpp:145
short type
Definition: cabvars.h:10
hoc_List * section_list
Definition: init.cpp:113
int nrn_global_ncell
Definition: init.cpp:114
char ** hoc_strpop()
Definition: code.cpp:962
Object ** hoc_objpop()
Pop pointer to object pointer and return top elem from stack.
Definition: code.cpp:943
Inst * hoc_pc
Definition: code.cpp:78
Symlist * hoc_symlist
Definition: symbol.cpp:34
Objectdata * hoc_top_level_data
Definition: hoc_oop.cpp:123
Item * lappendsec(List *list, Section *sec)
Definition: list.cpp:186
Item * insertsec(Item *item, Section *sec)
Definition: list.cpp:132
static double done(void *v)
Definition: ocbbs.cpp:251
static double cell(void *v)
Definition: ocbbs.cpp:540
void hoc_execute(Inst *)
Definition: code.cpp:2531
#define EXTRACELLULAR
Definition: options.h:16
static void pnode(Prop *)
Definition: psection.cpp:47
Section * nrnpy_pysecname2sec(const char *name)
int hoc_returning
Definition: code.cpp:81
void node_alloc(Section *, short)
Definition: solve.cpp:705
#define xpop
Definition: section.h:36
#define pc
Definition: section.h:37
#define PROP_PY_INDEX
Definition: section.h:230
#define execerror
Definition: section.h:39
#define NODEAREA(n)
Definition: section.h:101
Section * sec_alloc()
Allocate a new Section object.
Definition: solve.cpp:445
#define NODEV(n)
Definition: section_fwd.hpp:60
#define NULL
Definition: spdefs.h:105
double * v
Definition: section_fwd.hpp:40
Definition: model.h:8
struct Item * prev
Definition: model.h:13
void * element
Definition: model.h:11
short itemtype
Definition: model.h:9
struct Item * next
Definition: model.h:12
Definition: section.h:105
auto v_handle()
Definition: section.h:153
Section * sec
Definition: section.h:193
Extnode * extnode
Definition: section.h:199
auto & v()
Definition: section.h:141
auto sav_rhs_handle()
Definition: section.h:177
int sec_node_index_
Definition: section.h:213
Prop * prop
Definition: section.h:190
Definition: hocdec.h:173
Objectdata * dataspace
Definition: hocdec.h:177
int refcount
Definition: hocdec.h:174
cTemplate * ctemplate
Definition: hocdec.h:180
hoc_Item * secelm_
Definition: hocdec.h:184
union Object::@47 u
Definition: section.h:231
Datum * dparam
Definition: section.h:247
short _type
Definition: section.h:244
Object * ob
Definition: section.h:252
auto param_handle_legacy(int legacy_index)
Definition: section.h:355
Prop * next
Definition: section.h:243
Section * sibling
Definition: section.h:56
short recalc_area_
Definition: section.h:61
Section * child
Definition: section.h:54
Node * parentnode
Definition: section.h:58
short nnode
Definition: section.h:52
Section * parentsec
Definition: section.h:53
Node ** pnode
Definition: section.h:59
Definition: model.h:47
union Symbol::@28 u
short cpublic
Definition: hocdec.h:107
struct Symbol::@45::@46 rng
short type
Definition: model.h:48
Symbol * sym
Definition: hocdec.h:127
char * name
Definition: model.h:61
int oboff
Definition: hocdec.h:111
Definition: hocdec.h:75
Symlist * symtable
Definition: hocdec.h:148
Section * sec
Definition: hoclist.h:40
union hoc_Item::@48 element
short itemtype
Definition: hoclist.h:46
hoc_Item * next
Definition: hoclist.h:44
container::Node::storage & node_data()
Access the structure containing the data of all Nodes.
Definition: model_data.hpp:24
Non-template stable handle to a generic value.
void mark_as_unsorted()
Tell the container it is no longer sorted.
static void free_syn(void)
Definition: synapse.cpp:168
Definition: hocdec.h:42
hoc_Item ** psecitm
Definition: hocdec.h:167
double * pval
Definition: hocdec.h:164
int Fprintf(FILE *stream, const char *fmt, Args... args)
Definition: logger.hpp:8
int Printf(const char *fmt, Args... args)
Definition: logger.hpp:18