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