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