NEURON
nocpout.cpp
Go to the documentation of this file.
1 #include <../../nmodlconf.h>
2 /* /local/src/master/nrn/src/nmodl/nocpout.c,v 4.1 1997/08/30 20:45:28 hines Exp */
3 
4 /*
5 nrnversion is a string that is passed via the _mechanism structure
6 as the first arg. It will be interpreted within neuron to determine if
7 that version is compatible with this version.
8 For now try to use something of the form d.d
9 If this is changed then also change nrnoc/init.c
10 */
11 char* nmodl_version_ = "7.7.0";
12 
13 /* Point processes are now interfaced to nrnoc via objectvars.
14 Thus, p-array variables and functions accessible to hoc do not have
15 suffixes, and there is a constructor, destructor.
16 Also hoc interface functions always have a void* _vptr arg which is
17 always cast to (Point_process*) and the _p and _ppvar pointers set.
18 This makes the old setdata and create obsolete.
19 */
20 /* The strategy is to use as much of parout and hparout method as possible.
21 The bulk of the variables is in a p-array. The variables that don't belong
22 in this p-array are indicated by a flag with sym->subtype & NRNNOTP.
23 All other variables have values in that single array but not all those values
24 are available from HOC.
25 
26 Variables accessible to NEURON are variables that appear within
27 GLOBAL, SECTION, and RANGE statements.
28 SECTION variables are not currently implemented.
29 
30 Variables that do not appear in the p-array are:
31  1)externally declared variables such as celsius, t.
32  2)parameters and assigned not declared in the NEURON{RANGE list}
33  that are global with respect to sections.
34  3) variables static to this model, ie. v
35  4) read only variables like "diam"
36 States always are in the p-array.
37 
38 USEION variables in the p-array have connections to other places and
39 depending on the context may get their value from somewhere else, or
40 add their value to somewhere else, or place their value somewhere else.
41 The cases are:
42  NONSPECIFIC and USEION WRITE i... value added to proper ion current
43  and total current.
44  USEION READ entry value assigned to local copy.
45  USEION WRITE e.. ..o ..i exit value of local copy assigned to pointer..
46  It is an error for an ionic current or ionic variable
47  to be a STATE. Use another variable as the state, make the
48  ionic variable an ASSIGNED and just assign it at the
49  proper place.
50  Alternatively, if they are STATE's then they should not be READ
51  since their value comes from the p-array itself.
52 
53 POINTER variables are like USEION variables. Unfortunately, it is up to
54 the hoc user to make sure they point to the proper place with a connect
55 statement. At this time we only check for a null pointer. The pointers
56 are kept in the ppvar array.
57 
58 each model creates a setdata_suffix(x) (or setdata_suffix(i)) function
59 which sets up _p and _ppvar for use by functions in the model called
60 directly by hoc.
61 */
62 
63 /* FUNCTIONS are made external so they are callable from other models */
64 #define GLOBFUNCT 1
65 
66 #include "modl.h"
67 #include "parse1.hpp"
68 #include <stdlib.h>
69 #include <unistd.h>
70 #define GETWD(buf) getcwd(buf, NRN_BUFSIZE)
71 
72 #if VECTORIZE
73 int vectorize = 1;
74 /*
75 the idea is to put all variables into a vector of vectors so there
76 there is no static data. Every function has an implicit argument, underbar ix
77 which tells which set of data _p[ix][...] to use. There are going to have
78 to be limits on the kinds of scopmath functions called since many of them
79 need static data. We can have special versions of the most useful of these.
80 ie sparse.c.
81 Above is obsolete in detail , underbar ix is no longer used.
82 When vectorize = 1 then we believe the code is thread safe and most functions
83 pass around _p, _ppvar, _thread. When vectorize is 0 then we are definitely
84 not thread safe and _p and _ppvar are static.
85 */
86 
87 #endif
88 #define NRNEXTRN 01 /* t, dt, celsius, etc. */
89 #define NRNCURIN 02 /* input value used */
90 #define NRNCUROUT 04 /* added to output value */
91 #define NRNRANGE 010
92 #define NRNPRANGEIN 020
93 #define NRNPRANGEOUT 040
94 #define NRNGLOBAL 0100 /* same for all sections, defined here */
95 #define NRNSTATIC 0200 /* v */
96 #define NRNNOTP 0400 /* doesn't belong in p array */
97 #define NRNIONFLAG \
98  01000 /* temporary flag to allow READ and WRITE \
99  without declaring twice */
100 #define NRNSECTION 02000
101 #define NRNPOINTER 04000
102 #define IONCONC 010000
103 #define NRNBBCOREPOINTER 020000
104 
105 #define IONEREV 0 /* Parameter */
106 #define IONIN 1
107 #define IONOUT 2
108 #define IONCUR 3 /* assigned */
109 #define IONDCUR 4
110 
111 extern int assert_threadsafe;
112 extern int brkpnt_exists;
113 static char* brkpnt_str_;
114 extern Symbol* indepsym;
115 extern Symbol* scop_indep;
116 extern List* indeplist;
117 extern Symbol* stepsym;
118 extern char* reprime();
119 extern List* symlist[];
120 extern List* ldifuslist;
121 extern char* finname;
130 List* toplocal_;
131 extern int protect_;
132 extern int protect_include_;
133 extern List *set_ion_variables(int), *get_ion_variables(int);
134 extern int netrec_need_v;
135 
136 int decode_limits(Symbol* sym, double* pg1, double* pg2);
137 int decode_tolerance(Symbol* sym, double* pg1);
138 
139 
140 /* NEURON block information */
145 static List* rangeparm;
146 static List* rangedep;
147 static List* rangestate;
149 static List* uip; /* void _update_ion_pointer(Datum* _ppvar){...} text */
150 static char suffix[256];
151 static char* rsuffix; /* point process range and functions don't have suffix*/
152 static char* mechname;
153 int point_process; /* 1 if a point process model */
154 int artificial_cell; /* 1 if also explicitly declared an ARTIFICIAL_CELL */
155 static int diamdec = 0; /*1 if diam is declared*/
156 static int areadec = 0;
157 static int use_bbcorepointer = 0;
158 
159 void defs_h(Symbol*);
160 int iontype(char* s1, char* s2);
161 void nrndeclare();
162 void del_range(List*);
163 void declare_p();
164 int iondef(int*);
166 static int ppvar_cnt;
167 static List* ppvar_semantics_;
168 static void ppvar_semantics(int, const char*);
169 static int for_netcons_; /* number of FOR_NETCONS statements */
172 static int ba_index_; /* BEFORE AFTER blocks. See bablk */
173 static List* ba_list_;
174 
175 #if CVODE
176 List* state_discon_list_;
178 static int cvode_emit, cvode_ieq_index;
179 static int cond_index;
180 static int tqitem_index;
181 static int watch_index;
182 static int cvode_index;
183 static List* ion_synonym;
184 extern int singlechan_;
185 int debugging_;
186 int net_receive_;
187 int net_send_seen_;
188 int net_event_seen_;
189 int watch_seen_; /* number of WATCH statements + 1*/
190 extern List* watch_alloc;
191 static Item* net_send_delivered_; /* location for if flag is 1 then clear the
192  tqitem_ to allow an error message for net_move */
193 #endif
194 
195 #define SYMITER(arg) \
196  ITERATE(q, syminorder) { \
197  s = SYM(q); \
198  if (s->type == arg)
199 
200 #define SYMLISTITER \
201  for (i = 'A'; i <= 'z'; i++) \
202  ITERATE(q, symlist[i])
203 
204 #define IFTYPE(arg) if ((s->subtype & arg) && ((s->usage & EXPLICIT_DECL) != automatic))
205 
206 /* varcount holds the index into the .var file and is saved in s->used
207  parraycount holds the index into the p array and is saved in s->varnum
208  pvarcount indexes pointers to variables such as ena
209 */
210 static int varcount, parraycount;
211 
212 void nrninit() {
213  extern int using_default_indep;
214  currents = newlist();
215  rangeparm = newlist();
216  rangedep = newlist();
217  rangestate = newlist();
218  useion = newlist();
219  nrnpointers = newlist();
220  using_default_indep = 0;
221  indepinstall(install("t", NAME), "0", "1", "100", (Item*) 0, "ms", 0);
222  using_default_indep = 1;
223  debugging_ = 1;
226 }
227 
228 void parout() {
229  int i, j, ioncount, pointercount, gind, emit_check_table_thread;
230  Item *q, *q1;
231  Symbol *s, *sion;
232  double d1, d2;
233  extern char* modprefix;
234  char* modbase;
235 
236  defs_list = newlist(); /* relates hoc names to c-variables */
237  if (brkpnt_exists) {
238  brkpnt_str_ = "nrn_cur, nrn_jacob, nrn_state";
239  } else {
240  brkpnt_str_ = "0, 0, 0";
241 #if 1 || defined(__MINGW32__)
242  /* x86_64-w64-mingw32-gcc passed 0 without zeroing the high 32 bits */
243  /* also cygwin64 gcc 4.8.1, so cast to void* universally */
244  brkpnt_str_ = "(void*)0, (void*)0, (void*)0";
245 #endif
246  }
247 
248  for (modbase = modprefix + strlen(modprefix); modbase != modprefix; modbase--) {
249  if (*modbase == '\\' || *modbase == '/') {
250  modbase++;
251  break;
252  }
253  }
254  if (!mechname) {
255  sprintf(suffix, "_%s", modbase);
256  mechname = modbase;
257  } else if (strcmp(mechname, "nothing") == 0) {
258  vectorize = 0;
259  suffix[0] = '\0';
260  mechname = modbase;
261  nmodl_text = 0;
262  } else {
263  sprintf(suffix, "_%s", mechname);
264  }
266  fprintf(stderr,
267  "Notice: ARTIFICIAL_CELL models that would require thread specific data are not "
268  "thread safe.\n");
269  vectorize = 0;
270  }
271  if (point_process) {
272  rsuffix = "";
273  } else {
274  rsuffix = suffix;
275  }
276 
278  "\
279 \n#if METHOD3\nextern int _method3;\n#endif\n\
280 \n#if !NRNGPU\
281 \n#undef exp\
282 \n#define exp hoc_Exp\nextern double hoc_Exp(double);\
283 \n#endif\n\
284 ");
285  if (protect_include_) {
286  Lappendstr(defs_list, "\n#include \"nmodlmutex.h\"");
287  }
288 
289 #if 1
290  /* for easier profiling, give distinct names to otherwise reused static names */
291  sprintf(buf,
292  "\n\
293 #define nrn_init _nrn_init_%s\n\
294 #define _nrn_initial _nrn_initial_%s\n\
295 #define nrn_cur _nrn_cur_%s\n\
296 #define _nrn_current _nrn_current_%s\n\
297 #define nrn_jacob _nrn_jacob_%s\n\
298 #define nrn_state _nrn_state_%s\n\
299 #define _net_receive _net_receive_%s\
300 ",
301  suffix,
302  suffix,
303  suffix,
304  suffix,
305  suffix,
306  suffix,
307  suffix);
309  SYMLISTITER {
310  Symbol* s = SYM(q);
311  /* note that with GLOBFUNCT, FUNCT will be redefined anyway */
312  if (s->type == NAME && s->subtype & (PROCED | DERF | KINF)) {
313  sprintf(buf, "\n#define %s %s_%s", s->name, s->name, suffix);
315  }
316  }
317  Lappendstr(defs_list, "\n");
318 #endif /* distinct names for easier profiling */
319 
320  if (vectorize) {
322  "\n\
323 #define _threadargscomma_ _p, _ppvar, _thread, _nt,\n\
324 #define _threadargsprotocomma_ double* _p, Datum* _ppvar, Datum* _thread, NrnThread* _nt,\n\
325 #define _threadargs_ _p, _ppvar, _thread, _nt\n\
326 #define _threadargsproto_ double* _p, Datum* _ppvar, Datum* _thread, NrnThread* _nt\n\
327 ");
328  } else {
330  "\n\
331 #define _threadargscomma_ /**/\n\
332 #define _threadargsprotocomma_ /**/\n\
333 #define _threadargs_ /**/\n\
334 #define _threadargsproto_ /**/\n\
335 ");
336  }
338  "\
339  /*SUPPRESS 761*/\n\
340  /*SUPPRESS 762*/\n\
341  /*SUPPRESS 763*/\n\
342  /*SUPPRESS 765*/\n\
343  ");
344  Lappendstr(defs_list, "extern double *getarg();\n");
345 #if VECTORIZE
346  if (vectorize) {
347  Sprintf(buf, "/* Thread safe. No static _p or _ppvar. */\n");
348  } else
349 #endif
350  {
351  Sprintf(buf, "static double *_p; static Datum *_ppvar;\n");
352  }
354 
355  nrndeclare();
356  varcount = parraycount = 0;
357  declare_p();
358  ioncount = iondef(&pointercount); /* first is _nd_area if point process */
360  "\n#if MAC\n#if !defined(v)\n#define v _mlhv\n#endif\n#if !defined(h)\n#define h "
361  "_mlhh\n#endif\n#endif\n");
362  Lappendstr(defs_list, "\n#if defined(__cplusplus)\nextern \"C\" {\n#endif\n");
363  Lappendstr(defs_list, "static int hoc_nrnpointerindex = ");
364  if (pointercount) {
365  q = nrnpointers->next;
366  Sprintf(buf, "%d;\n", SYM(q)->used);
367  } else {
368  Sprintf(buf, "-1;\n");
369  }
371  /*above modified to also count and define pointers*/
372 
373  if (vectorize) {
374  Lappendstr(defs_list, "static Datum* _extcall_thread;\n static Prop* _extcall_prop;\n");
375  }
376 #if 0
377  Lappendstr(defs_list, "/* static variables special to NEURON */\n");
378  SYMLISTITER {
379  if (SYM(q)->nrntype & NRNSTATIC) {
380  Sprintf(buf, "static double %s;\n", SYM(q)->name);
382  }
383  }
384 #endif
385  Lappendstr(defs_list, "/* external NEURON variables */\n");
386  SYMLISTITER {
387  s = SYM(q);
388  if (s->nrntype & NRNEXTRN) {
389  if (strcmp(s->name, "dt") == 0) {
390  continue;
391  }
392  if (strcmp(s->name, "t") == 0) {
393  continue;
394  }
395  if (s->subtype & ARRAY) {
396  Sprintf(buf, "extern double* %s;\n", s->name);
397  } else {
398  Sprintf(buf, "extern double %s;\n", s->name);
399  }
401  }
402  }
403 
404  Lappendstr(defs_list, "/* declaration of user functions */\n");
405  SYMLISTITER {
406  s = SYM(q);
407  if (s->subtype & (FUNCT | PROCED) && s->name[0] != '_') {
408  if (point_process) {
409  Sprintf(buf, "static double _hoc_%s(void*);\n", s->name);
410  } else {
411  Sprintf(buf, "static void _hoc_%s(void);\n", s->name);
412  }
414  }
415  }
416 
418  "static int _mechtype;\n\
419 extern void _nrn_cacheloop_reg(int, int);\n\
420 extern void hoc_register_prop_size(int, int, int);\n\
421 extern void hoc_register_limits(int, HocParmLimits*);\n\
422 extern void hoc_register_units(int, HocParmUnits*);\n\
423 extern void nrn_promote(Prop*, int, int);\n\
424 extern Memb_func* memb_func;\n\
425 ");
426 
427  if (nmodl_text) {
429  "\n"
430  "#define NMODL_TEXT 1\n"
431  "#if NMODL_TEXT\n"
432  "static const char* nmodl_file_text;\n"
433  "static const char* nmodl_filename;\n"
434  "extern void hoc_reg_nmodl_text(int, const char*);\n"
435  "extern void hoc_reg_nmodl_filename(int, const char*);\n"
436  "#endif\n\n");
437  }
438 
439  /**** create special point process functions */
440  if (point_process) {
441  Lappendstr(defs_list, "extern Prop* nrn_point_prop_;\n");
442  Lappendstr(defs_list, "static int _pointtype;\n");
444  "static void* _hoc_create_pnt(Object* _ho) { void* create_point_process(int, "
445  "Object*);\n");
446  Lappendstr(defs_list, "return create_point_process(_pointtype, _ho);\n}\n");
447  Lappendstr(defs_list, "static void _hoc_destroy_pnt(void*);\n");
448  Lappendstr(
449  defs_list,
450  "static double _hoc_loc_pnt(void* _vptr) {double loc_point_process(int, void*);\n");
451  Lappendstr(defs_list, "return loc_point_process(_pointtype, _vptr);\n}\n");
453  "static double _hoc_has_loc(void* _vptr) {double has_loc_point(void*);\n");
454  Lappendstr(defs_list, "return has_loc_point(_vptr);\n}\n");
455  Lappendstr(defs_list, "static double _hoc_get_loc_pnt(void* _vptr) {\n");
456  Lappendstr(
457  defs_list,
458  "double get_loc_point_process(void*); return (get_loc_point_process(_vptr));\n}\n");
459  }
460  /* function to set up _p and _ppvar */
461  Lappendstr(defs_list, "extern void _nrn_setdata_reg(int, void(*)(Prop*));\n");
462  Lappendstr(defs_list, "static void _setdata(Prop* _prop) {\n");
463 #if VECTORIZE
464  if (vectorize) {
465  Lappendstr(defs_list, "_extcall_prop = _prop;\n");
466  } else
467 #endif
468  {
469  Lappendstr(defs_list, "_p = _prop->param; _ppvar = _prop->dparam;\n");
470  }
471  Lappendstr(defs_list, "}\n");
472 
473  if (point_process) {
474  Lappendstr(defs_list, "static void _hoc_setdata(void* _vptr) { Prop* _prop;\n");
475  Lappendstr(defs_list, "_prop = ((Point_process*)_vptr)->_prop;\n");
476  } else {
478  "static void _hoc_setdata() {\n Prop *_prop, *hoc_getdata_range(int);\n");
479  Sprintf(buf, "_prop = hoc_getdata_range(_mechtype);\n");
481  }
482  Lappendstr(defs_list, " _setdata(_prop);\n");
483  if (point_process) {
484  Lappendstr(defs_list, "}\n");
485  } else {
486  Lappendstr(defs_list, "hoc_retpushx(1.);\n}\n");
487  }
488 
489  /* functions */
490  Lappendstr(defs_list, "/* connect user functions to hoc names */\n");
491  Lappendstr(defs_list, "static VoidFunc hoc_intfunc[] = {\n");
492  if (point_process) {
493  Lappendstr(defs_list, "0,0\n};\n");
494  Lappendstr(defs_list, "static Member_func _member_func[] = {\n");
495  Sprintf(buf, "\"loc\", _hoc_loc_pnt,\n");
497  Sprintf(buf, "\"has_loc\", _hoc_has_loc,\n");
499  Sprintf(buf, "\"get_loc\", _hoc_get_loc_pnt,\n");
501  } else {
502  Sprintf(buf, "\"setdata_%s\", _hoc_setdata,\n", mechname);
504  }
505  SYMLISTITER {
506  s = SYM(q);
507  if ((s->subtype & (FUNCT | PROCED)) && s->name[0] != '_') {
508  Sprintf(buf, "\"%s%s\", _hoc_%s,\n", s->name, rsuffix, s->name);
510  }
511  }
512  Lappendstr(defs_list, "0, 0\n};\n");
513 
514 #if GLOBFUNCT
515  /* FUNCTION's are now global so callable from other models */
516  /* change name to namesuffix. This propagates everywhere except
517  to hoc_name*/
518  /* but don't do it if suffix is empty */
519  if (suffix[0])
520  SYMLISTITER {
521  s = SYM(q);
522  if ((s->subtype & FUNCT)) {
523  Sprintf(buf, "#define %s %s%s\n", s->name, s->name, suffix);
524  q1 = Lappendstr(defs_list, buf);
525  q1->itemtype = VERBATIM;
526  }
527  }
528  SYMLISTITER {
529  int j;
530  s = SYM(q);
531  if ((s->subtype & FUNCT)) {
532  Sprintf(buf, "extern double %s(", s->name);
534  if (vectorize && !s->no_threadargs) {
535  if (s->varnum) {
536  Lappendstr(defs_list, "_threadargsprotocomma_");
537  } else {
538  Lappendstr(defs_list, "_threadargsproto_");
539  }
540  }
541  for (j = 0; j < s->varnum; ++j) {
542  Lappendstr(defs_list, "double");
543  if (j + 1 < s->varnum) {
544  Lappendstr(defs_list, ",");
545  }
546  }
547  Lappendstr(defs_list, ");\n");
548  }
549  }
550 #endif
551 
552  emit_check_table_thread = 0;
554  emit_check_table_thread = 1;
555  }
556 
557  /* per thread top LOCAL */
558  /* except those that are marked assigned_to_ == 2 stay static double */
559  if (vectorize && toplocal_) {
560  int cnt;
561  cnt = 0;
562  ITERATE(q, toplocal_) {
563  if (SYM(q)->assigned_to_ != 2) {
564  if (SYM(q)->subtype & ARRAY) {
565  cnt += SYM(q)->araydim;
566  } else {
567  ++cnt;
568  }
569  }
570  }
571  sprintf(buf,
572  " _thread[%d]._pval = (double*)ecalloc(%d, sizeof(double));\n",
574  cnt);
576  sprintf(buf, " free((void*)(_thread[%d]._pval));\n", thread_data_index);
578  cnt = 0;
579  ITERATE(q, toplocal_) {
580  if (SYM(q)->assigned_to_ != 2) {
581  if (SYM(q)->subtype & ARRAY) {
582  sprintf(buf,
583  "#define %s (_thread[%d]._pval + %d)\n",
584  SYM(q)->name,
586  cnt);
587  cnt += SYM(q)->araydim;
588  } else {
589  sprintf(buf,
590  "#define %s _thread[%d]._pval[%d]\n",
591  SYM(q)->name,
593  cnt);
594  ++cnt;
595  }
596  } else { /* stay file static */
597  if (SYM(q)->subtype & ARRAY) {
598  sprintf(buf, "static double %s[%d];\n", SYM(q)->name, SYM(q)->araydim);
599  } else {
600  sprintf(buf, "static double %s;\n", SYM(q)->name);
601  }
602  }
604  }
606  }
607  /* per thread global data */
608  gind = 0;
609  if (vectorize)
610  SYMLISTITER {
611  s = SYM(q);
612  if (s->nrntype & (NRNGLOBAL) && s->assigned_to_ == 1) {
613  if (s->subtype & ARRAY) {
614  gind += s->araydim;
615  } else {
616  ++gind;
617  }
618  }
619  }
620  /* double scalars declared internally */
621  Lappendstr(defs_list, "/* declare global and static user variables */\n");
622  if (gind) {
623  sprintf(buf,
624  "static int _thread1data_inuse = 0;\nstatic double _thread1data[%d];\n#define _gth "
625  "%d\n",
626  gind,
629  sprintf(buf,
630  " if (_thread1data_inuse) {_thread[_gth]._pval = (double*)ecalloc(%d, "
631  "sizeof(double));\n }else{\n _thread[_gth]._pval = _thread1data; "
632  "_thread1data_inuse = 1;\n }\n",
633  gind);
636  " if (_thread[_gth]._pval == _thread1data) {\n _thread1data_inuse = 0;\n "
637  "}else{\n free((void*)_thread[_gth]._pval);\n }\n");
639  }
640  gind = 0;
641  SYMLISTITER { /* globals are now global with respect to C as well as hoc */
642  s = SYM(q);
643  if (s->nrntype & (NRNGLOBAL)) {
644  if (vectorize && s->assigned_to_ == 1) {
645  if (s->subtype & ARRAY) {
646  sprintf(buf,
647  "#define %s%s (_thread1data + %d)\n\
648 #define %s (_thread[_gth]._pval + %d)\n",
649  s->name,
650  suffix,
651  gind,
652  s->name,
653  gind);
654  } else {
655  sprintf(buf,
656  "#define %s%s _thread1data[%d]\n\
657 #define %s _thread[_gth]._pval[%d]\n",
658  s->name,
659  suffix,
660  gind,
661  s->name,
662  gind);
663  }
664  q1 = Lappendstr(defs_list, buf);
665  q1->itemtype = VERBATIM;
666  if (s->subtype & ARRAY) {
667  gind += s->araydim;
668  } else {
669  ++gind;
670  }
671  continue;
672  }
673  if (suffix[0]) {
674  Sprintf(buf, "#define %s %s%s\n", s->name, s->name, suffix);
675  q1 = Lappendstr(defs_list, buf);
676  q1->itemtype = VERBATIM;
677  }
678  decode_ustr(s, &d1, &d2, buf);
679  if (s->subtype & ARRAY) {
680  Sprintf(buf, "double %s[%d];\n", s->name, s->araydim);
681  } else {
682  Sprintf(buf, "double %s = %g;\n", s->name, d1);
683  }
685  }
686  }
687 
688  Lappendstr(defs_list, "/* some parameters have upper and lower limits */\n");
689  Lappendstr(defs_list, "static HocParmLimits _hoc_parm_limits[] = {\n");
690  SYMLISTITER {
691  s = SYM(q);
692  if (s->subtype & PARM) {
693  double d1 = 0., d2 = 0.;
694  if (decode_limits(s, &d1, &d2)) {
695  if (s->nrntype & NRNGLOBAL || !point_process) {
696  Sprintf(buf, "\"%s%s\", %g, %g,\n", s->name, suffix, d1, d2);
697  } else {
698  Sprintf(buf, "\"%s\", %g, %g,\n", s->name, d1, d2);
699  }
701  }
702  }
703  }
704  Lappendstr(defs_list, "0,0,0\n};\n");
705 
706  units_reg();
707 
708  SYMLISTITER {
709  s = SYM(q);
710  if (s->nrntype & (NRNSTATIC)) {
711 #if VECTORIZE && 0
712  if (vectorize) {
713  diag("No statics allowed for thread safe models:", s->name);
714  }
715 #endif
716  decode_ustr(s, &d1, &d2, buf);
717  if (s->subtype & ARRAY) {
718  Sprintf(buf, "static double %s[%d];\n", s->name, s->araydim);
719  } else {
720  Sprintf(buf, "static double %s = %g;\n", s->name, d1);
721  }
723  }
724  }
725  Lappendstr(defs_list, "/* connect global user variables to hoc */\n");
726  Lappendstr(defs_list, "static DoubScal hoc_scdoub[] = {\n");
727  ITERATE(q, syminorder) {
728  s = SYM(q);
729  if (s->nrntype & NRNGLOBAL && !(s->subtype & ARRAY)) {
730  Sprintf(buf, "\"%s%s\", &%s%s,\n", s->name, suffix, s->name, suffix);
732  }
733  }
734  Lappendstr(defs_list, "0,0\n};\n");
735 
736  /* double vectors */
737  Lappendstr(defs_list, "static DoubVec hoc_vdoub[] = {\n");
738  ITERATE(q, syminorder) {
739  s = SYM(q);
740  if (s->nrntype & NRNGLOBAL && (s->subtype & ARRAY)) {
741  Sprintf(buf, "\"%s%s\", %s%s, %d,\n", s->name, suffix, s->name, suffix, s->araydim);
743  }
744  }
745  Lappendstr(defs_list, "0,0,0\n};\n");
746  Lappendstr(defs_list, "static double _sav_indep;\n");
747  if (ba_index_ > 0) {
748  Lappendstr(
749  defs_list,
750  "static void _ba1(Node*_nd, double* _pp, Datum* _ppd, Datum* _thread, NrnThread* _nt)");
751  for (i = 2; i <= ba_index_; ++i) {
752  sprintf(buf,
753  ", _ba%d(Node*_nd, double* _pp, Datum* _ppd, Datum* _thread, NrnThread* _nt)",
754  i);
756  }
757  Lappendstr(defs_list, ";\n");
758  }
759 
760  /******** what normally goes into cabvars.h structures */
761 
762  /*declaration of the range variables names to HOC */
763  Lappendstr(
764  defs_list,
765  "static void nrn_alloc(Prop*);\nstatic void nrn_init(NrnThread*, _Memb_list*, int);\nstatic void nrn_state(NrnThread*, _Memb_list*, int);\n\
766 ");
767  if (brkpnt_exists) {
769  "static void nrn_cur(NrnThread*, _Memb_list*, int);\nstatic void "
770  "nrn_jacob(NrnThread*, _Memb_list*, int);\n");
771  }
772  /* count the number of pointers needed */
773  ppvar_cnt = ioncount + diamdec + pointercount + areadec;
774 #if CVODE
775  if (net_send_seen_) {
776  tqitem_index = ppvar_cnt;
777  ppvar_semantics(ppvar_cnt, "netsend");
778  ppvar_cnt++;
779  }
780  if (watch_seen_) {
781  watch_index = ppvar_cnt;
782  for (i = 0; i < watch_seen_; ++i) {
783  ppvar_semantics(i + ppvar_cnt, "watch");
784  }
785  ppvar_cnt += watch_seen_;
786  sprintf(buf, "\n#define _watch_array _ppvar + %d", watch_index);
788  Lappendstr(defs_list, "\n");
789  Lappendstr(defs_list, "static void _watch_alloc(Datum*);\n");
790  Lappendstr(defs_list, "extern void hoc_reg_watch_allocate(int, void(*)(Datum*));");
791  Lappendstr(watch_alloc, "}\n\n");
793  }
794  if (for_netcons_) {
795  sprintf(buf, "\n#define _fnc_index %d\n", ppvar_cnt);
797  ppvar_semantics(ppvar_cnt, "fornetcon");
798  ppvar_cnt += 1;
799  }
800  if (point_process) {
801  Lappendstr(defs_list, "static void _hoc_destroy_pnt(void* _vptr) {\n");
802  if (watch_seen_ || for_netcons_) {
803  Lappendstr(defs_list, " Prop* _prop = ((Point_process*)_vptr)->_prop;\n");
804  }
805  if (watch_seen_) {
806  sprintf(buf,
807  " if (_prop) { _nrn_free_watch(_prop->dparam, %d, %d);}\n",
808  watch_index,
809  watch_seen_);
811  }
812  if (for_netcons_) {
813  sprintf(buf,
814  " if (_prop) { _nrn_free_fornetcon(&(_prop->dparam[_fnc_index]._pvoid));}\n");
816  }
817  Lappendstr(defs_list, " destroy_point_process(_vptr);\n}\n");
818  }
819  if (cvode_emit) {
820  cvode_ieq_index = ppvar_cnt;
821  ppvar_semantics(ppvar_cnt, "cvodeieq");
822  ppvar_cnt++;
823  }
825 #endif
827  if (!point_process) {
828  diag("DESTRUCTOR only permitted for POINT_PROCESS", (char*) 0);
829  }
830  Lappendstr(defs_list, "static void _destructor(Prop*);\n");
831  }
832 
834  Lappendstr(defs_list, "static void _constructor(Prop*);\n");
835  }
836 
838  "/* connect range variables in _p that hoc is supposed to know about */\n");
840  "\
841 static const char *_mechanism[] = {\n\
842 ");
843  Sprintf(buf, "\"%s\",\n\"%s\",\n", nmodl_version_, mechname);
845  ITERATE(q, rangeparm) {
846  s = SYM(q);
847  if (s->subtype & ARRAY) {
848  Sprintf(buf, "\"%s%s[%d]\",\n", s->name, rsuffix, s->araydim);
849  } else {
850  Sprintf(buf, "\"%s%s\",\n", s->name, rsuffix);
851  }
853  }
854  Lappendstr(defs_list, "0,\n");
855  ITERATE(q, rangedep) {
856  s = SYM(q);
857  if (s->subtype & ARRAY) {
858  Sprintf(buf, "\"%s%s[%d]\",\n", s->name, rsuffix, s->araydim);
859  } else {
860  Sprintf(buf, "\"%s%s\",\n", s->name, rsuffix);
861  }
863  }
864  Lappendstr(defs_list, "0,\n");
865  ITERATE(q, rangestate) {
866  s = SYM(q);
867  if (s->subtype & ARRAY) {
868  Sprintf(buf, "\"%s%s[%d]\",\n", s->name, rsuffix, s->araydim);
869  } else {
870  Sprintf(buf, "\"%s%s\",\n", s->name, rsuffix);
871  }
873  }
874  Lappendstr(defs_list, "0,\n");
875 
876  /* pointer variable names */
877  ITERATE(q, nrnpointers) {
878  s = SYM(q);
879  if (s->subtype & ARRAY) {
880  Sprintf(buf, "\"%s%s[%d]\",\n", s->name, rsuffix, s->araydim);
881  } else {
882  Sprintf(buf, "\"%s%s\",\n", s->name, rsuffix);
883  }
885  }
886 
887  Lappendstr(defs_list, "0};\n");
888 
889  /*********Creation of the allocation function*/
890 
891  if (diamdec) {
892  Lappendstr(defs_list, "static Symbol* _morphology_sym;\n");
893  }
894  if (areadec) {
895  Lappendstr(defs_list, "extern Node* nrn_alloc_node_;\n");
896  }
897  ITERATE(q, useion) {
898  sion = SYM(q);
899  Sprintf(buf, "static Symbol* _%s_sym;\n", sion->name);
901  if (ldifuslist) {
902  sprintf(buf, "static int _type_i%s;\n", sion->name);
904  }
905  q = q->next->next->next;
906  }
907 
909  "\n\
910 extern Prop* need_memb(Symbol*);\n\n\
911 static void nrn_alloc(Prop* _prop) {\n\
912  Prop *prop_ion;\n\
913  double *_p; Datum *_ppvar;\n\
914 ");
915  if (point_process) {
917  " if (nrn_point_prop_) {\n\
918  _prop->_alloc_seq = nrn_point_prop_->_alloc_seq;\n\
919  _p = nrn_point_prop_->param;\n\
920  _ppvar = nrn_point_prop_->dparam;\n }else{\n");
921  }
922  Sprintf(buf, " _p = nrn_prop_data_alloc(_mechtype, %d, _prop);\n", parraycount);
924  Lappendstr(defs_list, " /*initialize range parameters*/\n");
925  ITERATE(q, rangeparm) {
926  s = SYM(q);
927  if (s->subtype & ARRAY) {
928  continue;
929  }
930  decode_ustr(s, &d1, &d2, buf);
931  Sprintf(buf, " %s = %g;\n", s->name, d1);
933  }
934  if (point_process) {
935  Lappendstr(defs_list, " }\n");
936  }
937  Lappendstr(defs_list, "\t_prop->param = _p;\n");
938  Sprintf(buf, "\t_prop->param_size = %d;\n", parraycount);
940  if (ppvar_cnt) {
941  if (point_process) {
942  Lappendstr(defs_list, " if (!nrn_point_prop_) {\n");
943  }
944  Sprintf(buf, " _ppvar = nrn_prop_datum_alloc(_mechtype, %d, _prop);\n", ppvar_cnt);
946  if (point_process) {
947  Lappendstr(defs_list, " }\n");
948  }
949  Lappendstr(defs_list, "\t_prop->dparam = _ppvar;\n");
950  Lappendstr(defs_list, "\t/*connect ionic variables to this model*/\n");
951  }
952  if (diamdec) {
953  Sprintf(buf, "prop_ion = need_memb(_morphology_sym);\n");
955  Sprintf(buf,
956  "\t_ppvar[%d]._pval = &prop_ion->param[0]; /* diam */\n",
957  ioncount + pointercount),
959  ppvar_semantics(ioncount + pointercount, "diam");
960  }
961  if (areadec) {
962  Sprintf(buf,
963  "\t_ppvar[%d]._pval = &nrn_alloc_node_->_area; /* diam */\n",
964  ioncount + pointercount + diamdec),
966  ppvar_semantics(ioncount + pointercount + diamdec, "area");
967  }
968 
969  if (point_process) {
970  ioncount = 2;
971  } else {
972  ioncount = 0;
973  }
974  ITERATE(q, useion) {
975  int dcurdef = 0;
976  int need_style = 0;
977  sion = SYM(q);
978  Sprintf(buf, "prop_ion = need_memb(_%s_sym);\n", sion->name);
980  if (ldifuslist) {
981  sprintf(buf, " _type_i%s = prop_ion->_type;\n", sion->name);
983  }
984  ion_promote(q);
985  q = q->next;
986  ITERATE(q1, LST(q)) {
987  SYM(q1)->nrntype |= NRNIONFLAG;
988  Sprintf(buf,
989  "\t_ppvar[%d]._pval = &prop_ion->param[%d]; /* %s */\n",
990  ioncount++,
991  iontype(SYM(q1)->name, sion->name),
992  SYM(q1)->name);
994  }
995  q = q->next;
996  ITERATE(q1, LST(q)) {
997  int itype = iontype(SYM(q1)->name, sion->name);
998 
999  if (SYM(q1)->nrntype & NRNIONFLAG) {
1000  SYM(q1)->nrntype &= ~NRNIONFLAG;
1001  } else {
1002  Sprintf(buf,
1003  "\t_ppvar[%d]._pval = &prop_ion->param[%d]; /* %s */\n",
1004  ioncount++,
1005  itype,
1006  SYM(q1)->name);
1008  }
1009  if (itype == IONCUR) {
1010  dcurdef = 1;
1011  Sprintf(buf,
1012  "\t_ppvar[%d]._pval = &prop_ion->param[%d]; /* _ion_di%sdv */\n",
1013  ioncount++,
1014  IONDCUR,
1015  sion->name);
1017  }
1018  if (itype == IONIN || itype == IONOUT) {
1019  need_style = 1;
1020  }
1021  }
1022  if (need_style) {
1023  Sprintf(
1024  buf,
1025  "\t_ppvar[%d]._pvoid = (void*)(&(prop_ion->dparam[0]._i)); /* iontype for %s */\n",
1026  ioncount++,
1027  sion->name);
1029  }
1030  q = q->next;
1031  if (!dcurdef && ldifuslist) {
1032  Sprintf(buf,
1033  "\t_ppvar[%d]._pval = &prop_ion->param[%d]; /* _ion_di%sdv */\n",
1034  ioncount++,
1035  IONDCUR,
1036  sion->name);
1038  }
1039  }
1040 
1042  Lappendstr(defs_list, "if (!nrn_point_prop_) {_constructor(_prop);}\n");
1043  if (vectorize) {
1045  "\n\
1046 static void _constructor(Prop* _prop) {\n\
1047  double* _p; Datum* _ppvar; Datum* _thread;\n\
1048  _thread = (Datum*)0;\n\
1049  _p = _prop->param; _ppvar = _prop->dparam;\n\
1050 {\n\
1051 ");
1052  } else {
1054  "\n\
1055 static void _constructor(Prop* _prop) {\n\
1056  _p = _prop->param; _ppvar = _prop->dparam;\n\
1057 {\n\
1058 ");
1059  }
1061  Lappendstr(procfunc, "\n}\n}\n");
1062  }
1063  Lappendstr(defs_list, "\n}\n");
1064 
1065  Lappendstr(defs_list, "static void _initlists();\n");
1066 #if CVODE
1067  if (cvode_emit) {
1068  Lappendstr(defs_list, " /* some states have an absolute tolerance */\n");
1069  Lappendstr(defs_list, "static Symbol** _atollist;\n");
1070  Lappendstr(defs_list, "static HocStateTolerance _hoc_state_tol[] = {\n");
1071  ITERATE(q, rangestate) {
1072  double d1;
1073  s = SYM(q);
1074  if (decode_tolerance(s, &d1)) {
1075  if (!point_process) {
1076  Sprintf(buf, "\"%s%s\", %g,\n", s->name, suffix, d1);
1077  } else {
1078  Sprintf(buf, "\"%s\", %g,\n", s->name, d1);
1079  }
1081  }
1082  }
1083  Lappendstr(defs_list, "0,0\n};\n");
1084  }
1085  if (singlechan_) {
1086  sprintf(buf, "static _singlechan_declare%d();\n", singlechan_);
1088  }
1089 #endif
1090 
1091 #if VECTORIZE
1092  if (net_send_seen_) {
1093  if (!net_receive_) {
1094  diag("can't use net_send if there is no NET_RECEIVE block", (char*) 0);
1095  }
1096  sprintf(buf, "\n#define _tqitem &(_ppvar[%d]._pvoid)\n", tqitem_index);
1098  if (net_send_delivered_) {
1099  insertstr(net_send_delivered_, " if (_lflag == 1. ) {*(_tqitem) = 0;}\n");
1100  }
1101  }
1102  if (net_receive_) {
1103  Lappendstr(defs_list, "static void _net_receive(Point_process*, double*, double);\n");
1104  if (for_netcons_) {
1105  Lappendstr(defs_list, "extern int _nrn_netcon_args(void*, double***);\n");
1106  }
1107  if (net_init_q1_) {
1108  Lappendstr(defs_list, "static void _net_init(Point_process*, double*, double);\n");
1109  }
1110  }
1112  Lappendstr(defs_list, "static void _thread_mem_init(Datum*);\n");
1113  }
1115  Lappendstr(defs_list, "static void _thread_cleanup(Datum*);\n");
1116  }
1117  if (uip) {
1118  lappendstr(defs_list, "static void _update_ion_pointer(Datum*);\n");
1119  }
1120  if (use_bbcorepointer) {
1122  "static void bbcore_write(double*, int*, int*, int*, _threadargsproto_);\n");
1124  "extern void hoc_reg_bbcore_write(int, void(*)(double*, int*, int*, int*, "
1125  "_threadargsproto_));\n");
1127  "static void bbcore_read(double*, int*, int*, int*, _threadargsproto_);\n");
1129  "extern void hoc_reg_bbcore_read(int, void(*)(double*, int*, int*, int*, "
1130  "_threadargsproto_));\n");
1131  }
1133  "\
1134 extern Symbol* hoc_lookup(const char*);\n\
1135 extern void _nrn_thread_reg(int, int, void(*)(Datum*));\n\
1136 extern void _nrn_thread_table_reg(int, void(*)(double*, Datum*, Datum*, NrnThread*, int));\n\
1137 extern void hoc_register_tolerance(int, HocStateTolerance*, Symbol***);\n\
1138 extern void _cvode_abstol( Symbol**, double*, int);\n\n\
1139 ");
1140  Sprintf(buf,
1141  "void _%s_reg() {\n\
1142  int _vectorized = %d;\n",
1143  modbase,
1144  vectorize);
1146  q = lappendstr(defs_list, "");
1147  Lappendstr(defs_list, "_initlists();\n");
1148 #else
1149  Sprintf(buf, "void _%s_reg() {\n _initlists();\n", modbase);
1151 #endif
1152 
1153  if (suffix[0]) { /* not "nothing" */
1154 
1155  ITERATE(q, useion) {
1156  Sprintf(buf, "\tion_reg(\"%s\", %s);\n", SYM(q)->name, STR(q->next->next->next));
1158  q = q->next->next->next;
1159  }
1160  if (diamdec) {
1161  Lappendstr(defs_list, "\t_morphology_sym = hoc_lookup(\"morphology\");\n");
1162  }
1163  ITERATE(q, useion) {
1164  Sprintf(buf, "\t_%s_sym = hoc_lookup(\"%s_ion\");\n", SYM(q)->name, SYM(q)->name);
1166  q = q->next->next->next;
1167  }
1168 #if VECTORIZE
1169  if (point_process) {
1170  sprintf(buf,
1171  "\
1172  _pointtype = point_register_mech(_mechanism,\n\
1173  nrn_alloc,%s, nrn_init,\n\
1174  hoc_nrnpointerindex, %d,\n\
1175  _hoc_create_pnt, _hoc_destroy_pnt, _member_func);\n",
1176  brkpnt_str_,
1177  vectorize ? 1 + thread_data_index : 0);
1180  Lappendstr(defs_list, " register_destructor(_destructor);\n");
1181  }
1182  } else {
1183  sprintf(buf,
1184  "\
1185  register_mech(_mechanism, nrn_alloc,%s, nrn_init, hoc_nrnpointerindex, %d);\n",
1186  brkpnt_str_,
1187  vectorize ? 1 + thread_data_index : 0);
1189  }
1190  if (vectorize && thread_data_index) {
1191  sprintf(buf,
1192  " _extcall_thread = (Datum*)ecalloc(%d, sizeof(Datum));\n",
1196  Lappendstr(defs_list, " _thread_mem_init(_extcall_thread);\n");
1197  if (gind) {
1198  Lappendstr(defs_list, " _thread1data_inuse = 0;\n");
1199  }
1200  }
1201  }
1202 #endif
1203  Lappendstr(defs_list, "_mechtype = nrn_get_mechtype(_mechanism[1]);\n");
1204  lappendstr(defs_list, " _nrn_setdata_reg(_mechtype, _setdata);\n");
1206  lappendstr(defs_list, " _nrn_thread_reg(_mechtype, 1, _thread_mem_init);\n");
1207  }
1209  lappendstr(defs_list, " _nrn_thread_reg(_mechtype, 0, _thread_cleanup);\n");
1210  }
1211  if (uip) {
1212  lappendstr(defs_list, " _nrn_thread_reg(_mechtype, 2, _update_ion_pointer);\n");
1213  }
1214  if (emit_check_table_thread) {
1215  lappendstr(defs_list, " _nrn_thread_table_reg(_mechtype, _check_table_thread);\n");
1216  }
1217  if (use_bbcorepointer) {
1218  lappendstr(defs_list, " hoc_reg_bbcore_write(_mechtype, bbcore_write);\n");
1219  lappendstr(defs_list, " hoc_reg_bbcore_read(_mechtype, bbcore_read);\n");
1220  }
1221  if (nmodl_text) {
1223  "#if NMODL_TEXT\n hoc_reg_nmodl_text(_mechtype, nmodl_file_text);\n "
1224  "hoc_reg_nmodl_filename(_mechtype, nmodl_filename);\n#endif\n");
1225  }
1226  sprintf(buf, " hoc_register_prop_size(_mechtype, %d, %d);\n", parraycount, ppvar_cnt);
1228  if (watch_seen_) {
1229  Lappendstr(defs_list, " hoc_reg_watch_allocate(_mechtype, _watch_alloc);\n");
1230  }
1231  if (ppvar_semantics_)
1233  sprintf(buf,
1234  " hoc_register_dparam_semantics(_mechtype, %d, \"%s\");\n",
1235  (int) q->itemtype,
1236  q->element.str);
1238  }
1239  /* Models that write concentration need their INITIAL blocks called
1240  before those that read the concentration or reversal potential. */
1241  i = 0;
1242  ITERATE(q, useion) {
1243  ITERATE(q1, LST(q->next->next)) {
1244  int type;
1245  type = iontype(SYM(q1)->name, SYM(q)->name);
1246  if (type == IONIN || type == IONOUT) {
1247  i += 1;
1248  }
1249  }
1250  q = q->next->next->next;
1251  }
1252  if (i) {
1253  Lappendstr(defs_list, "\tnrn_writes_conc(_mechtype, 0);\n");
1254  }
1255 
1256 #if CVODE
1257  if (cvode_emit) {
1259  "\
1260  hoc_register_cvode(_mechtype, _ode_count, _ode_map, _ode_spec, _ode_matsol);\n");
1262  "\
1263  hoc_register_tolerance(_mechtype, _hoc_state_tol, &_atollist);\n");
1264  if (ion_synonym) {
1265  Lappendstr(defs_list, " hoc_register_synonym(_mechtype, _ode_synonym);\n");
1266  }
1267  } else if (cvode_not_allowed) {
1269  "\
1270  hoc_register_cvode(_mechtype, _ode_count, 0, 0, 0);\n");
1271  }
1272  if (singlechan_) {
1273  sprintf(buf, "hoc_reg_singlechan(_mechtype, _singlechan_declare%d);\n", singlechan_);
1275  }
1276 #endif
1277  if (artificial_cell) {
1279  useion->next != useion) {
1280  printf(
1281  "Notice: ARTIFICIAL_CELL is a synonym for POINT_PROCESS which hints that it\n\
1282 only affects and is affected by discrete events. As such it is not\n\
1283 located in a section and is not associated with an integrator\n");
1284  }
1285  sprintf(buf, "add_nrn_artcell(_mechtype, %d);\n", tqitem_index);
1287  }
1288  if (net_event_seen_) {
1289  Lappendstr(defs_list, "add_nrn_has_net_event(_mechtype);\n");
1290  }
1291  if (net_receive_) {
1292  Lappendstr(defs_list, "pnt_receive[_mechtype] = _net_receive;\n");
1293  if (net_init_q1_) {
1294  Lappendstr(defs_list, "pnt_receive_init[_mechtype] = _net_init;\n");
1295  }
1296  sprintf(buf, "pnt_receive_size[_mechtype] = %d;\n", net_receive_);
1298  }
1299  if (for_netcons_) {
1300  sprintf(buf, "add_nrn_fornetcons(_mechtype, _fnc_index);\n");
1302  }
1303  q = ba_list_;
1304  for (i = 1; i <= ba_index_; ++i) {
1305  List* lst;
1306  q = q->next;
1307  if (electrode_current) {
1308  insertstr(ITM(q),
1309  " \
1310 #if EXTRACELLULAR\n\
1311 if (_nd->_extnode) {\n\
1312  v = NODEV(_nd) +_nd->_extnode->_v[0];\n\
1313 }else\n\
1314 #endif\n\
1315 {\n\
1316  v = NODEV(_nd);\n\
1317 }\n");
1318  } else {
1319  insertstr(ITM(q), " v = NODEV(_nd);\n");
1320  }
1321  lst = get_ion_variables(0);
1322  if (lst->next != lst->prev) {
1323  move(lst->next, lst->prev, ITM(q));
1324  freelist((List**) lst);
1325  }
1326  q = q->next;
1327  lst = set_ion_variables(0);
1328  if (lst->next != lst->prev) {
1329  move(lst->next, lst->prev, ITM(q));
1330  freelist((List**) lst);
1331  }
1332  q = q->next;
1333  sprintf(buf, "\thoc_reg_ba(_mechtype, _ba%d, %s);\n", i, STR(q));
1335  }
1336  if (ldifuslist) {
1337  Lappendstr(defs_list, "\thoc_register_ldifus1(_difusfunc);\n");
1338  Linsertstr(defs_list, "static void _difusfunc(ldifusfunc2_t, NrnThread*);\n");
1339  }
1340  } /* end of not "nothing" */
1342  "\
1343  hoc_register_var(hoc_scdoub, hoc_vdoub, hoc_intfunc);\n");
1344  {
1345  char buf1[NRN_BUFSIZE];
1346  char* pf{};
1347 #if HAVE_REALPATH && !defined(NRN_AVOID_ABSOLUTE_PATHS)
1348  pf = realpath(finname, NULL);
1349 #endif
1350  sprintf(buf1, "\tivoc_help(\"help ?1 %s %s\\n\");\n", mechname, pf ? pf : finname);
1351  if (pf) {
1352  free(pf);
1353  }
1354  Lappendstr(defs_list, buf1);
1355  }
1356  if (suffix[0]) {
1357  Lappendstr(defs_list, "hoc_register_limits(_mechtype, _hoc_parm_limits);\n");
1358  Lappendstr(defs_list, "hoc_register_units(_mechtype, _hoc_parm_units);\n");
1359  }
1360  Lappendstr(defs_list, "}\n"); /* end of _reg */
1362  Lappendstr(procfunc, "\nstatic void _thread_mem_init(Datum* _thread) {\n");
1364  Lappendstr(procfunc, "}\n");
1365  }
1367  Lappendstr(procfunc, "\nstatic void _thread_cleanup(Datum* _thread) {\n");
1369  Lappendstr(procfunc, "}\n");
1370  }
1371  if (uip) {
1372  move(uip->next, uip->prev, procfunc);
1373  }
1375  if (vectorize) {
1377  "\n\
1378 static void _destructor(Prop* _prop) {\n\
1379  double* _p; Datum* _ppvar; Datum* _thread;\n\
1380  _thread = (Datum*)0;\n\
1381  _p = _prop->param; _ppvar = _prop->dparam;\n\
1382 {\n\
1383 ");
1384  } else {
1386  "\n\
1387 static void _destructor(Prop* _prop) {\n\
1388  _p = _prop->param; _ppvar = _prop->dparam;\n\
1389 {\n\
1390 ");
1391  }
1393  Lappendstr(procfunc, "\n}\n}\n");
1394  }
1395  if (ldifuslist) {
1396  ldifusreg();
1397  }
1398  SYMLISTITER {
1399  s = SYM(q);
1400  if ((s->subtype & PARM)) {
1401  warn_ignore(s);
1402  }
1403  }
1404 }
1406 void warn_ignore(Symbol* s) {
1407  int b;
1408  double d1, d2;
1409  b = 0;
1410  if (s->nrntype & (NRNEXTRN | NRNPRANGEIN | NRNPRANGEOUT))
1411  b = 1;
1412  if (strcmp(s->name, "v") == 0)
1413  b = 1;
1414 
1415  decode_ustr(s, &d1, &d2, buf);
1416  if (d1 == 0.0)
1417  b = 0;
1418  if (b) {
1419  printf("Warning: Default %g of PARAMETER %s will be ignored and set by NEURON.\n",
1420  d1,
1421  s->name);
1422  }
1423 }
1425 void ldifusreg() {
1426  Item *q, *qdexp, *qb1, *qvexp, *qb2, *q1;
1427  char *cfindex, *dfdcur;
1428  Symbol *s, *d;
1429  int n;
1430 
1431  /* ldifuslist format: series of symbol qdexp qb1 svexp qb2
1432  indexforflux dflux/dconc */
1433  n = 0;
1434  ITERATE(q, ldifuslist) {
1435  s = SYM(q);
1436  q = q->next;
1437  qdexp = ITM(q);
1438  q = q->next;
1439  qb1 = ITM(q);
1440  q = q->next;
1441  qvexp = ITM(q);
1442  q = q->next;
1443  qb2 = ITM(q);
1444  q = q->next;
1445  cfindex = STR(q);
1446  q = q->next;
1447  dfdcur = STR(q);
1448  ++n;
1449  sprintf(buf,
1450  "static void* _difspace%d;\nextern double nrn_nernst_coef();\n\
1451 static double _difcoef%d(int _i, double* _p, Datum* _ppvar, double* _pdvol, double* _pdfcdc, Datum* _thread, NrnThread* _nt) {\n \
1452  *_pdvol = ",
1453  n,
1454  n);
1456  for (q1 = qvexp; q1 != qb2; q1 = q1->next) {
1457  lappenditem(procfunc, q1);
1458  }
1459  if (dfdcur[0]) {
1460  sprintf(buf,
1461  ";\n\
1462  if (_i == %s) {\n *_pdfcdc = %s;\n }else{ *_pdfcdc=0.;}\n",
1463  cfindex,
1464  dfdcur);
1465  } else {
1466  sprintf(buf, "; *_pdfcdc=0.;\n");
1467  }
1469  lappendstr(procfunc, " return");
1470  for (q1 = qdexp; q1 != qb1; q1 = q1->next) {
1471  lappenditem(procfunc, q1);
1472  }
1473  lappendstr(procfunc, ";\n}\n");
1474  }
1475  lappendstr(procfunc, "static void _difusfunc(ldifusfunc2_t _f, NrnThread* _nt) {int _i;\n");
1476  n = 0;
1477  ITERATE(q, ldifuslist) {
1478  s = SYM(q);
1479  q = q->next;
1480  qdexp = ITM(q);
1481  q = q->next;
1482  qb1 = ITM(q);
1483  q = q->next;
1484  qvexp = ITM(q);
1485  q = q->next;
1486  qb2 = ITM(q);
1487  q = q->next;
1488  cfindex = STR(q);
1489  q = q->next;
1490  dfdcur = STR(q);
1491  ++n;
1492 
1493  if (s->subtype & ARRAY) {
1494 #if MAC
1495  sprintf(buf,
1496  " for (_i=0; _i < %d; ++_i) mac_difusfunc(_f, _mechtype, _difcoef%d, "
1497  "&_difspace%d, _i, ",
1498  s->araydim,
1499  n,
1500  n);
1501 #else
1502  sprintf(buf,
1503  " for (_i=0; _i < %d; ++_i) (*_f)(_mechtype, _difcoef%d, &_difspace%d, _i, ",
1504  s->araydim,
1505  n,
1506  n);
1507 #endif
1508  } else {
1509 #if MAC
1510  sprintf(buf, " mac_difusfunc(_f,_mechtype, _difcoef%d, &_difspace%d, 0, ", n, n);
1511 #else
1512  sprintf(buf, " (*_f)(_mechtype, _difcoef%d, &_difspace%d, 0, ", n, n);
1513 #endif
1514  }
1516 
1517  sprintf(buf, "D%s", s->name);
1518  d = lookup(buf);
1519  assert(d);
1520  if (s->nrntype & IONCONC) {
1521  sprintf(buf, "%d, %d", -(s->ioncount_ + 1), d->varnum);
1522  } else {
1523  sprintf(buf, "%d, %d", s->varnum, d->varnum);
1524  }
1526  lappendstr(procfunc, ", _nt);\n");
1527  }
1528  lappendstr(procfunc, "}\n");
1529 }
1531 int decode_limits(Symbol* sym, double* pg1, double* pg2) {
1532  int i;
1533  double d1;
1534  if (sym->subtype & PARM) {
1535  char* cp;
1536  int n;
1537  assert(sym->u.str);
1538  for (n = 0, cp = sym->u.str; *cp; ++cp) {
1539  if (*cp == '\n') {
1540  ++n;
1541  if (n == 3) {
1542  ++cp;
1543  break;
1544  }
1545  }
1546  }
1547  i = sscanf(cp, "%lf %lf\n", pg1, pg2);
1548  if (i == 2) {
1549  return 1;
1550  }
1551  }
1552  return 0;
1553 }
1555 int decode_tolerance(Symbol* sym, double* pg1) {
1556  int i;
1557  double d1;
1558  if (sym->subtype & STAT) {
1559  char* cp;
1560  int n;
1561  for (n = 0, cp = sym->u.str; *cp; ++cp) {
1562  if (*cp == '\n') {
1563  ++n;
1564  if (n == 3) {
1565  ++cp;
1566  break;
1567  }
1568  }
1569  }
1570  i = sscanf(cp, "%lf\n", pg1);
1571  if (i == 1) {
1572  return 1;
1573  }
1574  }
1575  return 0;
1576 }
1578 void decode_ustr(Symbol* sym, double* pg1, double* pg2, char* s) /* decode sym->u.str */
1579 {
1580  int i, n;
1581  char *cp, *cp1;
1582 
1583  switch (sym->subtype & (INDEP | DEP | STAT | PARM)) {
1584  case INDEP: /* but doesnt get all info */
1585  case DEP:
1586  case STAT:
1587  assert(sym && sym->u.str);
1588  if (sym->subtype & ARRAY) { /* see parsact.c */
1589  i = sscanf(sym->u.str, "[%*d]\n%lf%*c%lf", pg1, pg2);
1590  } else {
1591  i = sscanf(sym->u.str, "%lf%*c%lf", pg1, pg2);
1592  }
1593  assert(i == 2);
1594  for (n = 0, cp = sym->u.str; n < 2;) {
1595  if (*cp++ == '\n') {
1596  n++;
1597  }
1598  }
1599  for (cp1 = s; *cp != '\n';) {
1600  *cp1++ = *cp++;
1601  }
1602  *cp1 = '\0';
1603  break;
1604 
1605  case PARM:
1606  assert(sym && sym->u.str);
1607  if (sym->subtype & ARRAY) { /* see parsact.c */
1608  i = sscanf(sym->u.str, "[%*d]\n%lf\n%s", pg1, s);
1609  } else {
1610  i = sscanf(sym->u.str, "%lf\n%s", pg1, s);
1611  }
1612  if (i == 1) {
1613  s[0] = '\0';
1614  i = 2;
1615  }
1616  assert(i == 2);
1617  break;
1618  default:
1619  diag(sym->name, " does not have a proper declaration");
1620  }
1621  if (s[0] == '0') {
1622  s[0] = '\0';
1623  }
1624 }
1626 void units_reg() {
1627  Symbol* s;
1628  Item* q;
1629  double d1, d2;
1630  char u[NRN_BUFSIZE];
1631 
1632  Lappendstr(defs_list, "static HocParmUnits _hoc_parm_units[] = {\n");
1633  ITERATE(q, syminorder) {
1634  s = SYM(q);
1635  if (s->nrntype & NRNGLOBAL) {
1636  decode_ustr(s, &d1, &d2, u);
1637  if (u[0]) {
1638  sprintf(buf, "\"%s%s\", \"%s\",\n", s->name, suffix, u);
1640  }
1641  }
1642  }
1643  ITERATE(q, rangeparm) {
1644  s = SYM(q);
1645  decode_ustr(s, &d1, &d2, u);
1646  if (u[0]) {
1647  sprintf(buf, "\"%s%s\", \"%s\",\n", s->name, rsuffix, u);
1649  }
1650  }
1651  ITERATE(q, rangestate) {
1652  s = SYM(q);
1653  decode_ustr(s, &d1, &d2, u);
1654  if (u[0]) {
1655  sprintf(buf, "\"%s%s\", \"%s\",\n", s->name, rsuffix, u);
1657  }
1658  }
1659  ITERATE(q, rangedep) {
1660  s = SYM(q);
1661  decode_ustr(s, &d1, &d2, u);
1662  if (u[0]) {
1663  sprintf(buf, "\"%s%s\", \"%s\",\n", s->name, rsuffix, u);
1665  }
1666  }
1667  ITERATE(q, nrnpointers) {
1668  s = SYM(q);
1669  decode_ustr(s, &d1, &d2, u);
1670  if (u[0]) {
1671  sprintf(buf, "\"%s%s\", \"%s\",\n", s->name, rsuffix, u);
1673  }
1674  }
1675  Lappendstr(defs_list, "0,0\n};\n");
1676 }
1678 static void var_count(Symbol* s) {
1679  defs_h(s);
1680  s->used = varcount++;
1681  s->varnum = parraycount;
1682  if (s->subtype & ARRAY) {
1683  parraycount += s->araydim;
1684  } else {
1685  parraycount++;
1686  }
1687 }
1689 void defs_h(Symbol* s) {
1690  Item* q;
1691 
1692  if (s->subtype & ARRAY) {
1693  Sprintf(buf,
1694  "#define %s (_p + %d)\n#define %s_columnindex %d\n",
1695  s->name,
1696  parraycount,
1697  s->name,
1698  parraycount);
1699  q = lappendstr(defs_list, buf);
1700  } else {
1701  Sprintf(buf,
1702  "#define %s _p[%d]\n#define %s_columnindex %d\n",
1703  s->name,
1704  parraycount,
1705  s->name,
1706  parraycount);
1707  q = lappendstr(defs_list, buf);
1708  }
1709  q->itemtype = VERBATIM;
1710 }
1712 void nrn_list(Item* q1, Item* q2) {
1713  List** plist = (List**) 0;
1714  Item* q;
1715 
1716  switch (SYM(q1)->type) {
1717  case RANGE:
1718  plist = (List**) 0;
1719  for (q = q1->next; q != q2->next; q = q->next) {
1720  SYM(q)->nrntype |= NRNRANGE;
1721  }
1722  break;
1723  case SUFFIX:
1724  plist = (List**) 0;
1725  mechname = SYM(q2)->name;
1726  if (strcmp(SYM(q1)->name, "POINT_PROCESS") == 0) {
1727  point_process = 1;
1728  } else if (strcmp(SYM(q1)->name, "ARTIFICIAL_CELL") == 0) {
1729  point_process = 1;
1730  artificial_cell = 1;
1731  }
1732  break;
1733  case ELECTRODE_CURRENT:
1734  electrode_current = 1;
1735  case NONSPECIFIC:
1736  plist = &currents;
1737  for (q = q1->next; q != q2->next; q = q->next) {
1738  SYM(q)->nrntype |= NRNRANGE;
1739  }
1740  break;
1741  case SECTION:
1742  diag("NEURON SECTION variables not implemented", (char*) 0);
1743  break;
1744  case GLOBAL:
1745  for (q = q1->next; q != q2->next; q = q->next) {
1746  SYM(q)->nrntype |= NRNGLOBAL | NRNNOTP;
1747  }
1748  plist = (List**) 0;
1749  break;
1750  case EXTERNAL:
1751 #if VECTORIZE
1752  threadsafe("Use of EXTERNAL is not thread safe.");
1753 #endif
1754  for (q = q1->next; q != q2->next; q = q->next) {
1755  SYM(q)->nrntype |= NRNEXTRN | NRNNOTP;
1756  }
1757  plist = (List**) 0;
1758  break;
1759  case POINTER:
1760  threadsafe("Use of POINTER is not thread safe.");
1761  plist = &nrnpointers;
1762  for (q = q1->next; q != q2->next; q = q->next) {
1763  SYM(q)->nrntype |= NRNNOTP | NRNPOINTER;
1764  }
1765  break;
1766  case BBCOREPOINTER:
1767  threadsafe("Use of BBCOREPOINTER is not thread safe.");
1768  plist = &nrnpointers;
1769  for (q = q1->next; q != q2->next; q = q->next) {
1770  SYM(q)->nrntype |= NRNNOTP | NRNBBCOREPOINTER;
1771  }
1772  use_bbcorepointer = 1;
1773  break;
1774  }
1775  if (plist) {
1776  if (!*plist) {
1777  *plist = newlist();
1778  }
1779  assert(q1 != q2);
1780  movelist(q1->next, q2, *plist);
1781  }
1782 }
1784 void bablk(int ba, int type, Item* q1, Item* q2) {
1785  Item *qb, *qv, *q;
1786  qb = insertstr(q1->prev->prev, "/*");
1787  insertstr(q1, "*/\n");
1788  if (!ba_list_) {
1789  ba_list_ = newlist();
1790  }
1791  sprintf(
1792  buf,
1793  "static void _ba%d(Node*_nd, double* _pp, Datum* _ppd, Datum* _thread, NrnThread* _nt) ",
1794  ++ba_index_);
1795  insertstr(q1, buf);
1796  q = q1->next;
1797  vectorize_substitute(insertstr(q, ""), "double* _p; Datum* _ppvar;");
1798  qv = insertstr(q, "_p = _pp; _ppvar = _ppd;\n");
1799  movelist(qb, q2, procfunc);
1800 
1801  ba = (ba == BEFORE) ? 10 : 20; /* BEFORE or AFTER */
1802  ba += (type == BREAKPOINT) ? 1 : 0;
1803  ba += (type == SOLVE) ? 2 : 0;
1804  ba += (type == INITIAL1) ? 3 : 0;
1805  ba += (type == STEP) ? 4 : 0;
1806  lappenditem(ba_list_, qv->next);
1807  lappenditem(ba_list_, q2);
1808  sprintf(buf, "%d", ba);
1810 }
1812 int ion_declared(Symbol* s) {
1813  Item* q;
1814  int used = 0;
1815  ITERATE(q, useion) {
1816  if (SYM(q) == s) {
1817  used = 1;
1818  }
1819  q = q->next->next->next;
1820  }
1821  return used;
1822 }
1824 void nrn_use(Item* q1, Item* q2, Item* q3, Item* q4) {
1825  int used, i;
1826  Item *q, *qr, *qw;
1827  List *readlist, *writelist;
1828  Symbol* ion;
1829 
1830  ion = SYM(q1);
1831  /* is it already used */
1832  used = ion_declared(SYM(q1));
1833  if (used) { /* READ gets promoted to WRITE */
1834  diag("mergeing of neuron models not supported yet", (char*) 0);
1835  } else { /* create all the ionic variables */
1836  Lappendsym(useion, ion);
1837  readlist = newlist();
1838  writelist = newlist();
1839  qr = lappendsym(useion, SYM0);
1840  qw = lappendsym(useion, SYM0);
1841  if (q4) {
1842  lappendstr(useion, STR(q4));
1843  } else {
1844  lappendstr(useion, "-10000.");
1845  }
1846  LST(qr) = readlist;
1847  LST(qw) = writelist;
1848  if (q2) {
1849  Item* qt = q2->next;
1850  move(q1->next->next, q2, readlist);
1851  if (q3) {
1852  move(qt->next, q3, writelist);
1853  }
1854  } else if (q3) {
1855  move(q1->next->next, q3, writelist);
1856  }
1857  ITERATE(q, readlist) {
1858  i = iontype(SYM(q)->name, ion->name);
1859  if (i == IONCUR) {
1860  SYM(q)->nrntype |= NRNCURIN;
1861  } else {
1862  SYM(q)->nrntype |= NRNPRANGEIN;
1863  if (i == IONIN || i == IONOUT) {
1864  SYM(q)->nrntype |= IONCONC;
1865  }
1866  }
1867  }
1868  ITERATE(q, writelist) {
1869  i = iontype(SYM(q)->name, ion->name);
1870  if (i == IONCUR) {
1871  if (!currents) {
1872  currents = newlist();
1873  }
1874  Lappendsym(currents, SYM(q));
1875  SYM(q)->nrntype |= NRNCUROUT;
1876  } else {
1877  SYM(q)->nrntype |= NRNPRANGEOUT;
1878  if (i == IONIN || i == IONOUT) {
1879  SYM(q)->nrntype |= IONCONC;
1880  }
1881  }
1882  }
1883  }
1884 }
1886 int iontype(char* s1, char* s2) /* returns index of variable in ion mechanism */
1887 {
1888  Sprintf(buf, "i%s", s2);
1889  if (strcmp(buf, s1) == 0) {
1890  return IONCUR;
1891  }
1892  Sprintf(buf, "e%s", s2);
1893  if (strcmp(buf, s1) == 0) {
1894  return IONEREV;
1895  }
1896  Sprintf(buf, "%si", s2);
1897  if (strcmp(buf, s1) == 0) {
1898  return IONIN;
1899  }
1900  Sprintf(buf, "%so", s2);
1901  if (strcmp(buf, s1) == 0) {
1902  return IONOUT;
1903  }
1904  Sprintf(buf, "%s is not a valid ionic variable for %s", s1, s2);
1905  diag(buf, (char*) 0);
1906  return -1;
1907 }
1909 static Symbol* ifnew_install(char* name) {
1910  Symbol* s;
1911 
1912  if ((s = lookup(name)) == SYM0) {
1913  s = install(name, NAME);
1914  parminstall(s, "0", "", "");
1915  }
1916  return s;
1917 }
1919 void nrndeclare() {
1920  Symbol* s;
1921  Item* q;
1922 
1923  s = lookup("diam");
1924  if (s) {
1925  if (s->nrntype & (NRNRANGE | NRNGLOBAL)) {
1926  diag(s->name, "cannot be a RANGE or GLOBAL variable for this mechanism");
1927  }
1928  s->nrntype |= NRNNOTP | NRNPRANGEIN;
1929  diamdec = 1;
1930  }
1931  s = lookup("area");
1932  if (s) {
1933  if (s->nrntype & (NRNRANGE | NRNGLOBAL)) {
1934  diag(s->name, "cannot be a RANGE or GLOBAL variable for this mechanism");
1935  }
1936  s->nrntype |= NRNNOTP | NRNPRANGEIN;
1937  areadec = 1;
1938  }
1939 #if VECTORIZE
1940  if (vectorize) {
1941  s = ifnew_install("v");
1942  s->nrntype = NRNNOTP; /* this is a lie, it goes in at end specially */
1943  } else
1944 #endif
1945  {
1946  s = ifnew_install("v");
1947  s->nrntype |= NRNSTATIC | NRNNOTP;
1948  }
1949  s = ifnew_install("t");
1950  s->nrntype |= NRNEXTRN | NRNNOTP;
1951  s = ifnew_install("dt");
1952  s->nrntype |= NRNEXTRN | NRNNOTP;
1954  "\n#define t nrn_threads->_t\n#define dt nrn_threads->_dt\n"),
1955  "\n#define t _nt->_t\n#define dt _nt->_dt\n");
1956 
1957  s = lookup("usetable");
1958  if (s) {
1959  s->nrntype |= NRNGLOBAL | NRNNOTP;
1960  }
1961  s = lookup("celsius");
1962  if (s) {
1963  s->nrntype |= NRNEXTRN | NRNNOTP;
1964  }
1965  s = lookup("celcius");
1966  if (s)
1967  diag("celcius should be spelled celsius", (char*) 0);
1968 
1969  ITERATE(q, syminorder) {
1970  s = SYM(q);
1971  if (s->type == NAME || s->type == PRIME) {
1972  if (s->subtype & PARM && s->nrntype & NRNRANGE) {
1973  Lappendsym(rangeparm, s);
1974  } else if (s->subtype & STAT) {
1975  s->nrntype |= NRNRANGE;
1976  Lappendsym(rangestate, s);
1977  } else if (s->subtype & DEP && s->nrntype & NRNRANGE) {
1978  Lappendsym(rangedep, s);
1979  }
1980  if (s != indepsym && !s->nrntype) {
1981  if (s->subtype & PARM) {
1982  if (s->usage & EXPLICIT_DECL) {
1983  s->nrntype |= NRNGLOBAL;
1984  s->nrntype |= NRNNOTP;
1985  } else {
1986  s->nrntype |= NRNSTATIC;
1987  s->nrntype |= NRNNOTP;
1988  }
1989  }
1990  }
1991  }
1992  }
1993  /* some ionic variables don't need duplicates known to hoc */
1997 }
1999 void del_range(List* range) {
2000  Item *q, *q1;
2001  Symbol* s;
2002 
2003  for (q = ((Item*) range)->next; q != (Item*) range; q = q1) {
2004  q1 = q->next;
2005  s = SYM(q);
2006  if (s->nrntype & (NRNPRANGEIN | NRNPRANGEOUT)) {
2007  remove(q);
2008  }
2009  }
2010 }
2011 
2013 void declare_p() {
2014  Item* q;
2015  Symbol* s;
2016 
2017  ITERATE(q, syminorder) {
2018  SYM(q)->used = -1;
2019  }
2020  ITERATE(q, rangeparm) {
2021  var_count(SYM(q));
2022  }
2023  ITERATE(q, rangedep) {
2024  var_count(SYM(q));
2025  }
2026  ITERATE(q, rangestate) {
2027  var_count(SYM(q));
2028  }
2029  ITERATE(q, syminorder) {
2030  if (!(SYM(q)->nrntype & NRNNOTP) && SYM(q)->used < 0) {
2031  var_count(SYM(q));
2032  }
2033  }
2034 #if VECTORIZE
2035  if (vectorize) {
2036  s = ifnew_install("v");
2037  var_count(s);
2038  }
2039 #endif
2040  if (brkpnt_exists) {
2041  s = ifnew_install("_g");
2042  var_count(s);
2043  }
2044  if (debugging_ && net_receive_) {
2045  s = ifnew_install("_tsav");
2046  var_count(s);
2047  }
2048 }
2050 List* set_ion_variables(int block)
2051 /* 0 means equation block , 2 means initial block */
2052 {
2053  /*ARGSUSED*/
2054  Item *q, *q1, *qconc;
2055  char* in;
2056  static List* l;
2057 
2058  l = newlist();
2059  ITERATE(q, useion) {
2060  in = SYM(q)->name;
2061  q = q->next;
2062  q = q->next;
2063  qconc = (Item*) 0;
2064  ITERATE(q1, LST(q)) {
2065  if (SYM(q1)->nrntype & NRNCUROUT) {
2066  if (block == 0) {
2067  Sprintf(buf,
2068  " _ion_%s += %s",
2069  SYM(q1)->name,
2070  breakpoint_current(SYM(q1))->name);
2071  Lappendstr(l, buf);
2072  if (point_process) {
2073  Sprintf(buf, "* 1.e2/ (_nd_area);\n");
2074  } else {
2075  Sprintf(buf, ";\n");
2076  }
2077  } else {
2078  buf[0] = '\0';
2079  }
2080  } else {
2081  if (iontype(SYM(q1)->name, in) != IONEREV) {
2082  qconc = q1;
2083  }
2084  Sprintf(buf, " _ion_%s = %s;\n", SYM(q1)->name, SYM(q1)->name);
2085  }
2086  Lappendstr(l, buf);
2087  }
2088  q = q->next;
2089  /* when INITIAL block is called, if it modifies the concentrations
2090  then the reversal potential should be recomputed in case
2091  other mechanisms need the true initial value. This would be
2092  rare since most initial blocks do not depend on erev. Instead
2093  the right value will be present due to fcurrent or cvode f(y).
2094  However, this fastidiousness cant hurt. It just makes ion_style
2095  in effect always at least for initialization.
2096  */
2097  /* sure enough, someone needed to demote the ion_style so
2098  that erev is decoupled from concentrations. So we need
2099  another variable pointing to the ionstyle
2100  */
2101  if (block == 2 && qconc) {
2102  int ic = iontype(SYM(qconc)->name, in);
2103  if (ic == IONIN) {
2104  ic = 1;
2105  } else if (ic == IONOUT) {
2106  ic = 2;
2107  } else {
2108  assert(0);
2109  }
2110  /* first arg is just for the charge, second is pointer to erev, third ard is the style*/
2111  Sprintf(buf,
2112  " nrn_wrote_conc(_%s_sym, (&(_ion_%s)) - %d, _style_%s);\n",
2113  in,
2114  SYM(qconc)->name,
2115  ic,
2116  in);
2117  Lappendstr(l, buf);
2118  }
2119  }
2120  return l;
2121 }
2123 List* get_ion_variables(int block)
2124 /* 0 means equation block */
2125 /* 2 means ode_spec and ode_matsol blocks */
2126 {
2127  /*ARGSUSED*/
2128  Item *q, *q1;
2129  static List* l;
2130 
2131  l = newlist();
2132  ITERATE(q, useion) {
2133  q = q->next;
2134  ITERATE(q1, LST(q)) {
2135  if (block == 2 && (SYM(q1)->nrntype & IONCONC) && (SYM(q1)->subtype & STAT)) {
2136  continue;
2137  }
2138  Sprintf(buf, " %s = _ion_%s;\n", SYM(q1)->name, SYM(q1)->name);
2139  Lappendstr(l, buf);
2140  if (point_process && (SYM(q1)->nrntype & NRNCURIN)) {
2141  Fprintf(stderr,
2142  "WARNING: Dimensions may be wrong for READ %s with POINT_PROCESS\n",
2143  SYM(q1)->name);
2144  }
2145  }
2146  q = q->next;
2147  ITERATE(q1, LST(q)) {
2148  if (block == 2 && (SYM(q1)->nrntype & IONCONC) && (SYM(q1)->subtype & STAT)) {
2149  continue;
2150  }
2151  if (SYM(q1)->nrntype & IONCONC) {
2152  Sprintf(buf, " %s = _ion_%s;\n", SYM(q1)->name, SYM(q1)->name);
2153  Lappendstr(l, buf);
2154  }
2155  if (SYM(q1)->subtype & STAT) {
2156  if (SYM(q1)->nrntype & NRNCUROUT) {
2157  Fprintf(stderr,
2158  "WARNING: WRITE %s with it a STATE may not be translated correctly\n",
2159  SYM(q1)->name);
2160  }
2161  }
2162  }
2163  q = q->next;
2164  }
2165  return l;
2166 }
2168 int iondef(int* p_pointercount) {
2169  int ioncount, it, need_style;
2170  Item *q, *q1, *q2;
2171  Symbol* sion;
2172  char ionname[256];
2173 
2174  ioncount = 0;
2175  if (point_process) {
2176  ioncount = 2;
2177  q = lappendstr(defs_list, "#define _nd_area *_ppvar[0]._pval\n");
2178  q->itemtype = VERBATIM;
2179  ppvar_semantics(0, "area");
2180  ppvar_semantics(1, "pntproc");
2181  }
2182  ITERATE(q, useion) {
2183  int dcurdef = 0;
2184  if (!uip) {
2185  uip = newlist();
2186  lappendstr(uip, "extern void nrn_update_ion_pointer(Symbol*, Datum*, int, int);\n");
2187  lappendstr(uip, "static void _update_ion_pointer(Datum* _ppvar) {\n");
2188  }
2189  need_style = 0;
2190  sion = SYM(q);
2191  sprintf(ionname, "%s_ion", sion->name);
2192  q = q->next;
2193  ITERATE(q1, LST(q)) {
2194  SYM(q1)->nrntype |= NRNIONFLAG;
2195  Sprintf(buf, "#define _ion_%s *_ppvar[%d]._pval\n", SYM(q1)->name, ioncount);
2196  q2 = lappendstr(defs_list, buf);
2197  q2->itemtype = VERBATIM;
2198  sprintf(buf,
2199  " nrn_update_ion_pointer(_%s_sym, _ppvar, %d, %d);\n",
2200  sion->name,
2201  ioncount,
2202  iontype(SYM(q1)->name, sion->name));
2203  lappendstr(uip, buf);
2204  SYM(q1)->ioncount_ = ioncount;
2205  ppvar_semantics(ioncount, ionname);
2206  ioncount++;
2207  }
2208  q = q->next;
2209  ITERATE(q1, LST(q)) {
2210  if (SYM(q1)->nrntype & NRNIONFLAG) {
2211  SYM(q1)->nrntype &= ~NRNIONFLAG;
2212  } else {
2213  Sprintf(buf, "#define _ion_%s *_ppvar[%d]._pval\n", SYM(q1)->name, ioncount);
2214  q2 = lappendstr(defs_list, buf);
2215  q2->itemtype = VERBATIM;
2216  sprintf(buf,
2217  " nrn_update_ion_pointer(_%s_sym, _ppvar, %d, %d);\n",
2218  sion->name,
2219  ioncount,
2220  iontype(SYM(q1)->name, sion->name));
2221  lappendstr(uip, buf);
2222  SYM(q1)->ioncount_ = ioncount;
2223  ppvar_semantics(ioncount, ionname);
2224  ioncount++;
2225  }
2226  it = iontype(SYM(q1)->name, sion->name);
2227  if (it == IONCUR) {
2228  dcurdef = 1;
2229  Sprintf(buf, "#define _ion_di%sdv\t*_ppvar[%d]._pval\n", sion->name, ioncount);
2230  q2 = lappendstr(defs_list, buf);
2231  q2->itemtype = VERBATIM;
2232  sprintf(buf,
2233  " nrn_update_ion_pointer(_%s_sym, _ppvar, %d, 4);\n",
2234  sion->name,
2235  ioncount);
2236  lappendstr(uip, buf);
2237  ppvar_semantics(ioncount, ionname);
2238  ioncount++;
2239  }
2240  if (it == IONIN || it == IONOUT) { /* would have wrote_ion_conc */
2241  need_style = 1;
2242  }
2243  }
2244  if (need_style) {
2245  Sprintf(buf, "#define _style_%s\t*((int*)_ppvar[%d]._pvoid)\n", sion->name, ioncount);
2246  q2 = lappendstr(defs_list, buf);
2247  q2->itemtype = VERBATIM;
2248  sprintf(buf, "#%s", ionname);
2249  ppvar_semantics(ioncount, buf);
2250  ioncount++;
2251  }
2252  q = q->next;
2253  if (!dcurdef && ldifuslist) {
2254  Sprintf(buf, "#define _ion_di%sdv\t*_ppvar[%d]._pval\n", sion->name, ioncount);
2255  q2 = lappendstr(defs_list, buf);
2256  q2->itemtype = VERBATIM;
2257  sprintf(buf,
2258  " nrn_update_ion_pointer(_%s_sym, _ppvar, %d, 4);\n",
2259  sion->name,
2260  ioncount);
2261  lappendstr(uip, buf);
2262  ppvar_semantics(ioncount, ionname);
2263  ioncount++;
2264  }
2265  }
2266  *p_pointercount = 0;
2267  ITERATE(q, nrnpointers) {
2268  sion = SYM(q);
2269  Sprintf(buf, "#define %s *_ppvar[%d]._pval\n", sion->name, ioncount + *p_pointercount);
2270  sion->used = ioncount + *p_pointercount;
2271  q2 = lappendstr(defs_list, buf);
2272  q2->itemtype = VERBATIM;
2273  Sprintf(buf, "#define _p_%s _ppvar[%d]._pval\n", sion->name, ioncount + *p_pointercount);
2274  sion->used = ioncount + *p_pointercount;
2275  q2 = lappendstr(defs_list, buf);
2276  q2->itemtype = VERBATIM;
2277  if (sion->nrntype & NRNPOINTER) {
2278  ppvar_semantics(ioncount + *p_pointercount, "pointer");
2279  } else {
2280  ppvar_semantics(ioncount + *p_pointercount, "bbcorepointer");
2281  }
2282  (*p_pointercount)++;
2283  }
2284 
2285  if (diamdec) { /* must be last */
2286  Sprintf(buf, "#define diam *_ppvar[%d]._pval\n", ioncount + *p_pointercount);
2287  q2 = lappendstr(defs_list, buf);
2288  q2->itemtype = VERBATIM;
2289  } /* notice that ioncount is not incremented */
2290  if (areadec) { /* must be last, if we add any more the administrative
2291  procedures must be redone */
2292  Sprintf(buf, "#define area *_ppvar[%d]._pval\n", ioncount + *p_pointercount + diamdec);
2293  q2 = lappendstr(defs_list, buf);
2294  q2->itemtype = VERBATIM;
2295  } /* notice that ioncount is not incremented */
2296  if (uip) {
2297  lappendstr(uip, "}\n");
2298  }
2299  return ioncount;
2300 }
2302 void ppvar_semantics(int i, const char* name) {
2303  Item* q;
2304  if (!ppvar_semantics_) {
2306  }
2307  q = Lappendstr(ppvar_semantics_, const_cast<char*>(name)); // TODO - ugly but ok for now
2308  q->itemtype = (short) i;
2309 }
2311 List* begin_dion_stmt() {
2312  Item *q, *q1, *qbrak;
2313  static List* l;
2314  char* strion;
2315 
2316  l = newlist();
2317  qbrak = lappendstr(l, "\t{");
2318  ITERATE(q, useion) {
2319  strion = SYM(q)->name;
2320  q = q->next;
2321  q = q->next;
2322  ITERATE(q1, LST(q)) {
2323  if (SYM(q1)->nrntype & NRNCUROUT) {
2324  Sprintf(buf, " _di%s = %s;\n", strion, SYM(q1)->name);
2325  Lappendstr(l, buf);
2326  Sprintf(buf, "double _di%s;\n", strion);
2327  Insertstr(qbrak->next, buf);
2328  }
2329  }
2330  q = q->next;
2331  }
2332  return l;
2333 }
2335 List* end_dion_stmt(char* strdel) {
2336  Item *q, *q1;
2337  static List* l;
2338  char* strion;
2339 
2340  l = newlist();
2341  ITERATE(q, useion) {
2342  strion = SYM(q)->name;
2343  q = q->next;
2344  q = q->next;
2345  ITERATE(q1, LST(q)) {
2346  if (SYM(q1)->nrntype & NRNCUROUT) {
2347  Sprintf(
2348  buf, " _ion_di%sdv += (_di%s - %s)/%s", strion, strion, SYM(q1)->name, strdel);
2349  Lappendstr(l, buf);
2350  if (point_process) {
2351  Lappendstr(l, "* 1.e2/ (_nd_area);\n");
2352  } else {
2353  Lappendstr(l, ";\n");
2354  }
2355  }
2356  }
2357  q = q->next;
2358  }
2359  Lappendstr(l, "\t}\n");
2360  return l;
2361 }
2363 void ion_promote(Item* qion) {
2364  Item* q;
2365  char* in;
2366  int conc, rev;
2367  int type;
2368  conc = 0;
2369  rev = 0;
2370  in = SYM(qion)->name;
2371  ITERATE(q, LST(qion->next)) { /* check READ */
2372  type = iontype(SYM(q)->name, in);
2373  if (type == IONIN || type == IONOUT) {
2374  conc = 1;
2375  }
2376  if (type == IONEREV) {
2377  rev = 1;
2378  }
2379  }
2380  ITERATE(q, LST(qion->next->next)) { /* promote if WRITE */
2381  type = iontype(SYM(q)->name, in);
2382  if (type == IONIN) {
2383  Lappendstr(defs_list, "nrn_check_conc_write(_prop, prop_ion, 1);\n");
2384  conc = 3;
2385  }
2386  if (type == IONOUT) {
2387  Lappendstr(defs_list, "nrn_check_conc_write(_prop, prop_ion, 0);\n");
2388  conc = 3;
2389  }
2390  if (type == IONEREV) {
2391  rev = 3;
2392  }
2393  }
2394  if (conc || rev) {
2395  Sprintf(buf, "nrn_promote(prop_ion, %d, %d);\n", conc, rev);
2397  }
2398 }
2400 #define NRNFIX(arg) \
2401  if (strcmp(n, arg) == 0) \
2402  e = 1;
2404 void nrn_var_assigned(Symbol* s) {
2405  int e;
2406  char* n;
2407  if (s->assigned_to_ == 0) {
2408  s->assigned_to_ = 1;
2409  }
2410  if (protect_) {
2411  s->assigned_to_ = 2;
2412  }
2413  e = 0;
2414  n = s->name;
2415  NRNFIX("area");
2416  NRNFIX("diam");
2417  NRNFIX("t");
2418  NRNFIX("dt");
2419  NRNFIX("celsius");
2420  if (e) {
2421  diag(s->name,
2422  "is a special NEURON variable that should not be\n assigned a value\
2423  in a model description file\n");
2424  }
2425 }
2426 
2427 #if CVODE
2428 
2429 static int cvode_valid_, using_cvode;
2430 static int cvode_num_, cvode_neq_;
2431 static Symbol* cvode_fun_;
2432 
2433 void slist_data(Symbol* s, int indx, int findx) {
2434  /* format: number of pairs, followed by findx, indx pairs */
2435  int* pi;
2436  int i, n;
2437  if (s->slist_info_) {
2438  /* i'd use realloc but to avoid portability problems */
2439  /* this probably will never get executed anyway */
2440  n = s->slist_info_[0] + 1;
2441  pi = (int*) emalloc((1 + 2 * n) * sizeof(int));
2442  for (i = 2 * (n - 1); i > 0; --i) {
2443  pi[i] = s->slist_info_[i];
2444  }
2445  free(s->slist_info_);
2446  s->slist_info_ = pi;
2447  pi[0] = n;
2448  pi[2 * n - 1] = findx;
2449  pi[2 * n] = indx;
2450  } else {
2451  s->slist_info_ = pi = (int*) emalloc(3 * sizeof(int));
2452  pi[0] = 1;
2453  pi[1] = findx;
2454  pi[2] = indx;
2455  }
2456 }
2457 
2458 int slist_search(int n, Symbol* s) {
2459  int i, *pi;
2460  pi = s->slist_info_;
2461  if (pi == (int*) 0) {
2462  diag(s->name, "not really a STATE; Ie. No differential equation for it.\n");
2463  }
2464  assert(pi);
2465  for (i = 0; i < pi[0]; ++i) {
2466  if (pi[1 + 2 * i] == n) {
2467  return pi[2 + 2 * i];
2468  }
2469  }
2470  assert(0);
2471  return 0;
2472 }
2473 
2474 static void cvode_conc_map() {
2475  /* pv index is slist index, ppd index is to the concentration
2476  pointer to the ion concentration is eg. &(ion_cai). Unfortunately
2477  the slist index has nothing to do with the _p array index.
2478  To recover the slist index, an slist_index list was made for
2479  every slist which consists of an slist ordered list of state symbols
2480  */
2481  /*
2482  also must handle case where user WRITE cai but cai is not a STATE
2483  since inefficiency occurs due to inability to set eca when
2484  states are predicted
2485  */
2486  Item *q, *q1, *q2, *q3;
2487  int sindex;
2488  ITERATE(q, useion) {
2489  q = q->next;
2490  q = q->next;
2491  ITERATE(q1, LST(q)) {
2492  if (SYM(q1)->nrntype & IONCONC) {
2493  if ((SYM(q1)->subtype & STAT)) {
2494  sindex = slist_search(cvode_num_, SYM(q1));
2495  sprintf(buf, "\t_pv[%d] = &(_ion_%s);\n", sindex, SYM(q1)->name);
2497  } else { /* not a STATE but WRITE it*/
2498  /*its got to have an assignment in a SOLVE block and that assignment
2499  better not depend on intermediate variables that depend on states
2500  because we will assign cai using only that statement prior to
2501  calling the nernst equation code.
2502  */
2503  int b = 0;
2504  if (!ion_synonym) {
2505  ion_synonym = newlist();
2506  }
2507  ITERATE(q2, procfunc) {
2508  if (q2->itemtype == SYMBOL && SYM(q2) == SYM(q1)) {
2509  q3 = q2->next;
2510  if (q3->itemtype == SYMBOL && strcmp(SYM(q3)->name, "=") == 0) {
2511  /*printf(" found reference to %s = ...\n", SYM(q2)->name);*/
2512  sprintf(buf, "_ion_%s = ", SYM(q2)->name);
2513  lappendstr(ion_synonym, buf);
2514  for (q3 = q3->next; q3 != procfunc->prev; q3 = q3->next) {
2515  lappenditem(ion_synonym, q3);
2516  if (q3->itemtype == SYMBOL && SYM(q3) == semi) {
2517 #if 0
2518  if (q3->itemtype == STRING && strchr(STR(q3), ';')) {
2519  char* e, *s = stralloc(STR(q3), (char*)0);
2520  e = strchr(s, ';');
2521  *e = '\0';
2522  sprintf(buf, "%s;\n", s);
2523 printf("|%s||%s||%s|\n",STR(q3), s, buf);
2524  lappendstr(ion_synonym, buf);
2525 #endif
2526  b = 1;
2527  break;
2528  }
2529  }
2530  break;
2531  }
2532  }
2533  }
2534  if (b == 0) {
2535  diag(SYM(q1)->name,
2536  "is WRITE but is not a STATE and has no assignment statement");
2537  }
2538  }
2539  }
2540  }
2541  q = q->next;
2542  }
2543 }
2544 
2545 void out_nt_ml_frag(List* p) {
2546  vectorize_substitute(lappendstr(p, " Datum* _thread;\n"),
2547  " double* _p; Datum* _ppvar; Datum* _thread;\n");
2548  Lappendstr(p,
2549  " Node* _nd; double _v; int _iml, _cntml;\n\
2550  _cntml = _ml->_nodecount;\n\
2551  _thread = _ml->_thread;\n\
2552  for (_iml = 0; _iml < _cntml; ++_iml) {\n\
2553  _p = _ml->_data[_iml]; _ppvar = _ml->_pdata[_iml];\n\
2554  _nd = _ml->_nodelist[_iml];\n\
2555  v = NODEV(_nd);\n\
2556 ");
2557 }
2558 
2559 void cvode_emit_interface() {
2560  List* lst;
2561  Item *q, *q1;
2562  if (cvode_not_allowed) {
2564  "\n\
2565 static int _ode_count(int);\n");
2566  sprintf(buf,
2567  "\n\
2568 static int _ode_count(int _type){ hoc_execerror(\"%s\", \"cannot be used with CVODE\"); return 0;}\n",
2569  mechname);
2571  } else if (cvode_emit) {
2573  "\n\
2574 static int _ode_count(int);\n\
2575 static void _ode_map(int, double**, double**, double*, Datum*, double*, int);\n\
2576 static void _ode_spec(NrnThread*, _Memb_list*, int);\n\
2577 static void _ode_matsol(NrnThread*, _Memb_list*, int);\n\
2578 ");
2579  sprintf(buf,
2580  "\n\
2581 static int _ode_count(int _type){ return %d;}\n",
2582  cvode_neq_);
2584  sprintf(buf, "\n#define _cvode_ieq _ppvar[%d]._i\n", cvode_ieq_index);
2586 
2587  if (cvode_fun_->subtype == PROCED) {
2589  } else {
2591  "\nstatic void _ode_spec(NrnThread* _nt, _Memb_list* _ml, int _type) {\n");
2593  lst = get_ion_variables(1);
2594  if (lst->next->itemtype)
2595  movelist(lst->next, lst->prev, procfunc);
2596  sprintf(buf, " _ode_spec%d", cvode_num_);
2598  vectorize_substitute(lappendstr(procfunc, "();\n"), "(_p, _ppvar, _thread, _nt);\n");
2599  lst = set_ion_variables(1);
2600  if (lst->next->itemtype)
2601  movelist(lst->next, lst->prev, procfunc);
2602  Lappendstr(procfunc, "}}\n");
2603 
2605  "\n\
2606 static void _ode_map(int _ieq, double** _pv, double** _pvdot, double* _pp, Datum* _ppd, double* _atol, int _type) {");
2608  "\n\
2609  double* _p; Datum* _ppvar;\n");
2610  sprintf(buf,
2611  "\
2612  int _i; _p = _pp; _ppvar = _ppd;\n\
2613  _cvode_ieq = _ieq;\n\
2614  for (_i=0; _i < %d; ++_i) {\n\
2615  _pv[_i] = _pp + _slist%d[_i]; _pvdot[_i] = _pp + _dlist%d[_i];\n\
2616  _cvode_abstol(_atollist, _atol, _i);\n\
2617  }\n",
2618  cvode_neq_,
2619  cvode_num_,
2620  cvode_num_);
2622  /* need to take care of case where a state is an ion concentration. Replace
2623  the _pp pointer with a pointer to the actual ion model's concentration */
2624  cvode_conc_map();
2625  Lappendstr(procfunc, "}\n");
2626  if (ion_synonym) {
2627  Lappendstr(defs_list, "static void _ode_synonym(int, double**, Datum**);\n");
2629  "\
2630 static void _ode_synonym(int _cnt, double** _pp, Datum** _ppd) {");
2632  "\n\
2633  double* _p; Datum* _ppvar;\n");
2635  "\
2636  int _i; \n\
2637  for (_i=0; _i < _cnt; ++_i) {_p = _pp[_i]; _ppvar = _ppd[_i];\n");
2638  movelist(ion_synonym->next, ion_synonym->prev, procfunc);
2639  Lappendstr(procfunc, "}}\n");
2640  }
2641 
2642  sprintf(buf, "static void _ode_matsol_instance%d(_threadargsproto_);\n", cvode_num_);
2644  sprintf(buf, "\nstatic void _ode_matsol_instance%d(_threadargsproto_) {\n", cvode_num_);
2646  if (cvode_fun_->subtype == KINF) {
2647  int i = cvode_num_;
2648  sprintf(
2649  buf,
2650  "_cvode_sparse(&_cvsparseobj%d, %d, _dlist%d, _p, _ode_matsol%d, &_coef%d);\n",
2651  i,
2652  cvode_neq_,
2653  i,
2654  i,
2655  i);
2657  sprintf(buf,
2658  "_cvode_sparse_thread(&_thread[_cvspth%d]._pvoid, %d, _dlist%d, _p, "
2659  "_ode_matsol%d, _ppvar, _thread, _nt);\n",
2660  i,
2661  cvode_neq_,
2662  i,
2663  i);
2665  } else {
2666  sprintf(buf, "_ode_matsol%d", cvode_num_);
2669  "(_p, _ppvar, _thread, _nt);\n");
2670  }
2671  Lappendstr(procfunc, "}\n");
2673  "\nstatic void _ode_matsol(NrnThread* _nt, _Memb_list* _ml, int _type) {\n");
2675  lst = get_ion_variables(1);
2676  if (lst->next->itemtype)
2677  movelist(lst->next, lst->prev, procfunc);
2678  sprintf(buf, "_ode_matsol_instance%d(_threadargs_);\n", cvode_num_);
2680  Lappendstr(procfunc, "}}\n");
2681  }
2682  /* handle the state_discontinuities (obsolete in NET_RECEIVE)*/
2683  if (state_discon_list_)
2684  ITERATE(q, state_discon_list_) {
2685  Symbol* s;
2686  int sindex;
2687  q1 = ITM(q);
2688  s = SYM(q1);
2689  if (q1->itemtype == SYMBOL && (s->subtype & STAT)) {
2690  sindex = slist_search(cvode_num_, s);
2691  sprintf(buf, "_cvode_ieq + %d, &", sindex);
2692  replacstr(q1->prev, buf);
2693  }
2694  }
2695  }
2696 }
2697 
2698 void cvode_proced_emit() {
2699  sprintf(buf,
2700  "\n\
2701 static void _ode_spec(Node* _nd, double* _pp, Datum* _ppd) {\n\
2702  _p = _pp; _ppvar = _ppd; v = NODEV(_nd);\n\
2703  %s();\n}\n",
2704  cvode_fun_->name);
2705 
2707  sprintf(buf,
2708  "\n\
2709 static void _ode_map(int _ieq, double** _pv, doubl** _pvdot, double* _pp){}\n");
2711 
2713  "\n\
2714 static void _ode_matsol(Node* _nd, double* _pp, Datum* _ppd){}\n");
2715 }
2716 
2717 void cvode_interface(Symbol* fun, int num, int neq) {
2718  /* if only one then allowed and emit */
2719  cvode_valid_ = 1;
2720  cvode_not_allowed = (using_cvode++) ? 1 : 0;
2721  cvode_emit = !cvode_not_allowed;
2722  cvode_num_ = num;
2723  cvode_neq_ = neq;
2724  cvode_fun_ = fun;
2725  if (cvode_fun_->subtype == PROCED) {
2726  cvode_emit = 0;
2727  return;
2728  }
2729  Sprintf(buf,
2730  "\n\
2731 static int _ode_spec%d(_threadargsproto_);\n\
2732 /*static int _ode_matsol%d(_threadargsproto_);*/\n\
2733 ",
2734  num,
2735  num);
2737 }
2738 
2739 void cvode_valid() {
2740  static int once;
2741  if (!cvode_valid_ && !once++) {
2742  Fprintf(stderr, "Notice: This mechanism cannot be used with CVODE\n");
2743  cvode_not_allowed = 1;
2744  }
2745  cvode_valid_ = 0;
2746 }
2747 
2748 void cvode_rw_cur(char* b) {
2749  /* if a current is READ and WRITE then call the correct _ode_spec
2750  since it may compute some aspect of the current */
2751  Item *q, *q1;
2752  int type;
2753  Symbol* sion;
2754  b[0] = '\0';
2755  ITERATE(q, useion) {
2756  sion = SYM(q);
2757  q = q->next;
2758  ITERATE(q1, LST(q)) {
2759  type = SYM(q1)->nrntype;
2760  if ((type & NRNCURIN) && (type & NRNCUROUT)) {
2761  if (!cvode_not_allowed && cvode_emit) {
2762  if (vectorize) {
2763  sprintf(b,
2764  "if (_nt->_vcv) { _ode_spec%d(_p, _ppvar, _thread, _nt); }\n",
2765  cvode_num_);
2766  } else {
2767  sprintf(b, "if (_nt->_vcv) { _ode_spec%d(); }\n", cvode_num_);
2768  }
2769  return;
2770  }
2771  }
2772  }
2773  q = q->next;
2774  q = q->next;
2775  }
2776 }
2777 #endif
2779 void net_receive(Item* qarg, Item* qp1, Item* qp2, Item* qstmt, Item* qend) {
2780  Item *q, *q1;
2781  Symbol* s;
2782  int i, b;
2783  char snew[256];
2784  if (net_receive_) {
2785  diag("Only one NET_RECEIVE block allowed", (char*) 0);
2786  }
2787  if (!point_process) {
2788  diag("NET_RECEIVE can only exist in a POINT_PROCESS", (char*) 0);
2789  }
2790  net_receive_ = 1;
2791  deltokens(qp1, qp2);
2792  insertstr(qstmt, "(Point_process* _pnt, double* _args, double _lflag)");
2793  i = 0;
2794  ITERATE(q1, qarg) if (q1->next != qarg) { /* skip last "flag" arg */
2795  s = SYM(q1);
2796  sprintf(snew, "_args[%d]", i);
2797  ++i;
2798  for (q = qstmt; q != qend; q = q->next) {
2799  if (q->itemtype == SYMBOL && SYM(q) == s) {
2800  replacstr(q, snew);
2801  }
2802  }
2803  }
2804  net_send_delivered_ = qstmt;
2805  q = insertstr(qstmt, "\n{");
2806  vectorize_substitute(q, "\n{ double* _p; Datum* _ppvar; Datum* _thread; NrnThread* _nt;\n");
2807  if (watch_seen_) {
2808  insertstr(qstmt, " int _watch_rm = 0;\n");
2809  }
2810  q = insertstr(qstmt, " _p = _pnt->_prop->param; _ppvar = _pnt->_prop->dparam;\n");
2811  vectorize_substitute(insertstr(q, ""), " _thread = (Datum*)0; _nt = (NrnThread*)_pnt->_vnt;");
2812  if (debugging_) {
2813  if (0) {
2814  insertstr(qstmt, " assert(_tsav <= t); _tsav = t;");
2815  } else {
2816  insertstr(qstmt,
2817  " if (_tsav > t){ extern char* hoc_object_name(); "
2818  "hoc_execerror(hoc_object_name(_pnt->ob), \":Event arrived out of order. "
2819  "Must call ParallelContext.set_maxstep AFTER assigning minimum "
2820  "NetCon.delay\");}\n _tsav = t;");
2821  }
2822  }
2823  insertstr(qend, "}");
2824  if (!artificial_cell) {
2825  Symbol* ions[10];
2826  int j, nion = 0;
2827  /* v can be changed in the NET_RECEIVE block since it is
2828  called between integrator steps and before a re_init
2829  But no need to do so if it is not used.
2830  */
2831  Symbol* vsym = lookup("v");
2832  netrec_need_v = 1;
2833  for (q = qstmt; q != qend; q = q->next) {
2834  if (q->itemtype == SYMBOL && SYM(q) == vsym) {
2835  insertstr(qstmt, " v = NODEV(_pnt->node);\n");
2836  insertstr(qend, "\n NODEV(_pnt->node) = v;\n");
2837  netrec_need_v = 0;
2838  break;
2839  }
2840  }
2841  /* if an ion concentration
2842  is mentioned then we need to get the relevant value
2843  on entry and possibly set a value on exit
2844  Do not allow mention of reversal potential or current
2845  */
2846  for (q = qstmt; q != qend; q = q->next) {
2847  if (q->itemtype == SYMBOL && SYM(q)->type == NAME) {
2848  s = SYM(q);
2849  if ((s->nrntype & (NRNPRANGEIN | NRNPRANGEOUT)) == 0) {
2850  continue;
2851  }
2852  if ((s->nrntype & IONCONC) == 0) {
2853  diag(s->name, ":only concentrations can be mentioned in a NET_RECEIVE block");
2854  }
2855  /* distinct only */
2856  for (j = 0; j < nion; ++j) {
2857  if (s == ions[j]) {
2858  break;
2859  }
2860  }
2861  if (j == nion) {
2862  if (nion >= 10) {
2863  diag("too many ions mentioned in NET_RECEIVE block (limit 10", (char*) 0);
2864  }
2865  ions[nion] = s;
2866  ++nion;
2867  }
2868  }
2869  }
2870  for (j = 0; j < nion; ++j) {
2871  sprintf(
2872  buf, "%s %s = _ion_%s;\n", (j == 0) ? "\n" : "", ions[j]->name, ions[j]->name);
2873  insertstr(qstmt, buf);
2874  }
2875  for (j = 0; j < nion; ++j) {
2876  if (ions[j]->subtype & STAT) {
2877  sprintf(buf,
2878  "%s _ion_%s = %s;\n",
2879  (j == 0) ? "\n" : "",
2880  ions[j]->name,
2881  ions[j]->name);
2882  insertstr(qend, buf);
2883  }
2884  }
2885  }
2886  if (i > 0) {
2887  net_receive_ = i;
2888  }
2889  if (net_init_q1_) {
2891  }
2892 }
2894 void net_init(Item* qinit, Item* qp2) {
2895  /* qinit=INITIAL { stmtlist qp2=} */
2896  replacstr(qinit, "\nstatic void _net_init(Point_process* _pnt, double* _args, double _lflag)");
2897  sprintf(buf, " _p = _pnt->_prop->param; _ppvar = _pnt->_prop->dparam;\n");
2899  "\
2900  double* _p = _pnt->_prop->param;\n\
2901  Datum* _ppvar = _pnt->_prop->dparam;\n\
2902  Datum* _thread = (Datum*)0;\n\
2903  NrnThread* _nt = (NrnThread*)_pnt->_vnt;\n\
2904 ");
2905  if (net_init_q1_) {
2906  diag("NET_RECEIVE block can contain only one INITIAL block", (char*) 0);
2907  }
2908  net_init_q1_ = qinit;
2909  net_init_q2_ = qp2;
2910 }
2912 void fornetcon(Item* keyword, Item* par1, Item* args, Item* par2, Item* stmt, Item* qend) {
2913  Item *q, *q1;
2914  Symbol* s;
2915  char snew[256];
2916  int i;
2917  /* follows net_receive pretty closely */
2918  ++for_netcons_;
2919  deltokens(par1, par2);
2920  i = for_netcons_;
2921  sprintf(buf,
2922  "{int _ifn%d, _nfn%d; double* _fnargs%d, **_fnargslist%d;\n\
2923 \t_nfn%d = _nrn_netcon_args(_ppvar[_fnc_index]._pvoid, &_fnargslist%d);\n\
2924 \tfor (_ifn%d = 0; _ifn%d < _nfn%d; ++_ifn%d) {\n",
2925  i,
2926  i,
2927  i,
2928  i,
2929  i,
2930  i,
2931  i,
2932  i,
2933  i,
2934  i);
2935  replacstr(keyword, buf);
2936  sprintf(buf, "\t _fnargs%d = _fnargslist%d[_ifn%d];\n", i, i, i);
2937  insertstr(keyword->next, buf);
2938  insertstr(qend->next, "\t}}\n");
2939  i = 0;
2940  ITERATE(q1, args) {
2941  s = SYM(q1);
2942  sprintf(snew, "_fnargs%d[%d]", for_netcons_, i);
2943  ++i;
2944  for (q = stmt; q != qend; q = q->next) {
2945  if (q->itemtype == SYMBOL && SYM(q) == s) {
2946  replacstr(q, snew);
2947  }
2948  }
2949  }
2950 }
2952 void chk_thread_safe() {
2953  Symbol* s;
2954  int i;
2955  Item* q;
2956  SYMLISTITER { /* globals are now global with respect to C as well as hoc */
2957  s = SYM(q);
2958  if (s->nrntype & (NRNGLOBAL) && s->assigned_to_ == 1) {
2959  sprintf(buf, "Assignment to the GLOBAL variable, \"%s\", is not thread safe", s->name);
2960  threadsafe(buf);
2961  }
2962  }
2963 }
2964 
2966 void chk_global_state() {
2967  int i;
2968  Item* q;
2969  SYMLISTITER {
2970  Symbol* s = SYM(q);
2971  if (s->nrntype & NRNGLOBAL && s->subtype & STAT) {
2972  diag(s->name, " is a STATE variable and hence cannot be declared as GLOBAL");
2973  }
2974  }
2975 }
2976 
2978 void threadsafe_seen(Item* q1, Item* q2) {
2979  Item* q;
2980  assert_threadsafe = 1;
2981  if (q2) {
2982  for (q = q1->next; q != q2->next; q = q->next) {
2983  SYM(q)->assigned_to_ = 2;
2984  }
2985  }
2986 }
2988 void conductance_hint(int blocktype, Item* q1, Item* q2) {
2989  Item* q;
2990  if (blocktype != BREAKPOINT) {
2991  diag("CONDUCTANCE can only appear in BREAKPOINT block", (char*) 0);
2992  }
2993  if (!conductance_) {
2994  conductance_ = newlist();
2995  }
2997  if (q2 != q1->next) {
2998  Symbol* s = SYM(q2);
2999  if (!ion_declared(s)) {
3000  diag(s->name, "not declared as USEION in NEURON block");
3001  }
3003  } else {
3005  }
3006  deltokens(q1, q2);
3007 }
3009 void possible_local_current(int blocktype, List* symlist) {
3010  Item* q;
3011  Item* q2;
3012  if (blocktype != BREAKPOINT) {
3013  return;
3014  }
3015  ITERATE(q, currents) {
3016  ITERATE(q2, symlist) {
3017  char* n = SYM(q2)->name + 2; /* start after the _l */
3018  if (strcmp(SYM(q)->name, n) == 0) {
3021  }
3024  }
3025  }
3026  }
3027 }
3031  Item* q;
3033  if (SYM(q) == s) {
3034  return SYM(q->next);
3035  }
3036  }
3037  }
3038  return s;
3039 }
short type
Definition: cabvars.h:9
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
#define diag(s)
Definition: fmenu.cpp:192
#define PARM
Definition: modl.h:190
char * finname
Definition: model.cpp:37
char * modprefix
Definition: modl.cpp:56
char buf[512]
Definition: init.cpp:13
Symbol * semi
Definition: init.cpp:11
int nmodl_text
Definition: modl.cpp:66
#define assert(ex)
Definition: hocassrt.h:32
#define i
Definition: md1redef.h:12
#define DERF
Definition: model.h:125
#define STR(q)
Definition: model.h:87
#define FUNCT
Definition: model.h:119
#define SYM0
Definition: model.h:74
#define STAT
Definition: model.h:117
#define ITERATE(itm, lst)
Definition: model.h:25
#define SYMBOL
Definition: model.h:102
#define EXPLICIT_DECL
Definition: model.h:137
#define Linsertstr
Definition: model.h:243
#define INDEP
Definition: model.h:115
#define Lappendstr
Definition: model.h:245
#define Insertstr
Definition: model.h:240
#define ITM(q)
Definition: model.h:88
#define SYM(q)
Definition: model.h:86
#define Sprintf
Definition: model.h:233
#define KINF
Definition: model.h:132
#define LST(q)
Definition: model.h:90
#define Lappendsym
Definition: model.h:244
#define DEP
Definition: model.h:116
#define NRN_BUFSIZE
Definition: model.h:13
#define ARRAY
Definition: model.h:118
#define PROCED
Definition: model.h:120
#define Fprintf
Definition: model.h:234
NMODL parser global flags / functions.
List * procfunc
Definition: init.cpp:9
char * name
Definition: init.cpp:16
long subtype
Definition: init.cpp:215
Item * lappendstr(List *list, char *str)
Definition: list.cpp:134
void movelist(Item *q1, Item *q2, List *s)
Definition: list.cpp:220
void freelist(List **plist)
Definition: list.cpp:57
Item * insertstr(Item *item, char *str)
Definition: list.cpp:98
void replacstr(Item *q, char *s)
Definition: list.cpp:225
char * emalloc(unsigned n)
Definition: list.cpp:166
char * stralloc(char *buf, char *rel)
Definition: list.cpp:184
Item * next(Item *item)
Definition: list.cpp:88
void deltokens(Item *q1, Item *q2)
Definition: list.cpp:195
List * newlist()
Definition: list.cpp:47
Item * lappenditem(List *list, Item *item)
Definition: list.cpp:146
Item * lappendsym(List *list, Symbol *sym)
Definition: list.cpp:142
#define SUFFIX
Definition: units.cpp:63
#define printf
Definition: mwprefix.h:26
#define fprintf
Definition: mwprefix.h:30
int vectorize
int cvode_not_allowed
List * destructorfunc
Definition: init.cpp:313
List * constructorfunc
Definition: init.cpp:313
void slist_data(Symbol *s, int indx, int findx)
void out_nt_ml_frag(List *)
void vectorize_substitute(Item *q, char *str)
int slist_search(int listnum, Symbol *s)
void cvode_valid()
void cvode_rw_cur(char *)
void threadsafe(char *)
Definition: parsact.cpp:1216
void parminstall(Symbol *n, char *num, char *units, char *limits)
Definition: parsact.cpp:159
void cvode_interface(Symbol *fun, int num, int neq)
void indepinstall(Symbol *n, char *from, char *to, char *with, Item *qstart, char *units, int scop)
Definition: parsact.cpp:232
void cvode_proced_emit()
void cvode_emit_interface()
int debugging_
int net_receive_
Symbol * stepsym
Definition: parsact.cpp:14
#define NRNCUROUT
Definition: nocpout.cpp:90
static char * rsuffix
Definition: nocpout.cpp:150
#define NRNGLOBAL
Definition: nocpout.cpp:94
static void var_count(Symbol *s)
Definition: nocpout.cpp:1677
void possible_local_current(int blocktype, List *symlist)
Definition: nocpout.cpp:3008
static Symbol * ifnew_install(char *name)
Definition: nocpout.cpp:1908
void ldifusreg()
Definition: nocpout.cpp:1424
void chk_thread_safe()
Definition: nocpout.cpp:2951
List * get_ion_variables(int)
Definition: nocpout.cpp:2122
#define IONCUR
Definition: nocpout.cpp:107
#define NRNPRANGEIN
Definition: nocpout.cpp:92
void ion_promote(Item *)
Definition: nocpout.cpp:2362
static int use_bbcorepointer
Definition: nocpout.cpp:156
void defs_h(Symbol *)
Definition: nocpout.cpp:1688
#define IONOUT
Definition: nocpout.cpp:106
static int ba_index_
Definition: nocpout.cpp:171
void del_range(List *)
Definition: nocpout.cpp:1998
List * currents
Definition: nocpout.cpp:140
#define NRNPRANGEOUT
Definition: nocpout.cpp:93
int decode_tolerance(Symbol *sym, double *pg1)
Definition: nocpout.cpp:1554
List * thread_cleanup_list
Definition: nocpout.cpp:127
int thread_data_index
Definition: nocpout.cpp:126
List * useion
Definition: nocpout.cpp:141
Symbol * breakpoint_current(Symbol *s)
Definition: nocpout.cpp:3028
#define NRNPOINTER
Definition: nocpout.cpp:100
int check_tables_threads(List *)
Definition: parsact.cpp:564
#define IONDCUR
Definition: nocpout.cpp:108
List * conductance_
Definition: nocpout.cpp:142
List * toplocal_
Definition: nocpout.cpp:129
void nrn_list(Item *q1, Item *q2)
Definition: nocpout.cpp:1711
void nrn_use(Item *q1, Item *q2, Item *q3, Item *q4)
Definition: nocpout.cpp:1823
#define IONEREV
Definition: nocpout.cpp:104
void chk_global_state()
Definition: nocpout.cpp:2965
int brkpnt_exists
void net_receive(Item *qarg, Item *qp1, Item *qp2, Item *qstmt, Item *qend)
Definition: nocpout.cpp:2778
void parout()
Definition: nocpout.cpp:227
static int for_netcons_
Definition: nocpout.cpp:168
int electrode_current
Definition: nocpout.cpp:125
int iontype(char *s1, char *s2)
Definition: nocpout.cpp:1885
static char * brkpnt_str_
Definition: nocpout.cpp:112
static List * rangestate
Definition: nocpout.cpp:146
static int varcount
Definition: nocpout.cpp:209
List * begin_dion_stmt()
Definition: nocpout.cpp:2310
List * set_ion_variables(int)
Definition: nocpout.cpp:2049
static int diamdec
Definition: nocpout.cpp:154
List * indeplist
Definition: parsact.cpp:15
static Item * net_init_q1_
Definition: nocpout.cpp:169
#define IONCONC
Definition: nocpout.cpp:101
List * thread_mem_init_list
Definition: nocpout.cpp:128
List * defs_list
Definition: nocpout.cpp:124
int protect_include_
Definition: parsact.cpp:28
static int parraycount
Definition: nocpout.cpp:209
int netrec_need_v
void net_init(Item *qinit, Item *qp2)
Definition: nocpout.cpp:2893
#define SYMLISTITER
Definition: nocpout.cpp:199
char * nmodl_version_
Definition: nocpout.cpp:11
int protect_
Definition: parsact.cpp:27
void threadsafe_seen(Item *q1, Item *q2)
Definition: nocpout.cpp:2977
static List * uip
Definition: nocpout.cpp:148
List * plotlist
Definition: nocpout.cpp:123
void bablk(int ba, int type, Item *q1, Item *q2)
Definition: nocpout.cpp:1783
#define NRNCURIN
Definition: nocpout.cpp:89
List * syminorder
Definition: nocpout.cpp:122
#define NRNIONFLAG
Definition: nocpout.cpp:97
static char suffix[256]
Definition: nocpout.cpp:149
#define NRNBBCOREPOINTER
Definition: nocpout.cpp:102
#define NRNRANGE
Definition: nocpout.cpp:91
#define NRNSTATIC
Definition: nocpout.cpp:95
int ion_declared(Symbol *s)
Definition: nocpout.cpp:1811
#define NRNEXTRN
Definition: nocpout.cpp:88
static int ppvar_cnt
Definition: nocpout.cpp:165
void nrn_var_assigned(Symbol *s)
Definition: nocpout.cpp:2403
#define IONIN
Definition: nocpout.cpp:105
void nrndeclare()
Definition: nocpout.cpp:1918
static Item * net_init_q2_
Definition: nocpout.cpp:170
static void ppvar_semantics(int, const char *)
Definition: nocpout.cpp:2301
int iondef(int *)
Definition: nocpout.cpp:2167
#define NRNFIX(arg)
Definition: nocpout.cpp:2399
static List * rangeparm
Definition: nocpout.cpp:144
List * end_dion_stmt(char *strdel)
Definition: nocpout.cpp:2334
List * symlist[]
Definition: symbol.cpp:8
static List * rangedep
Definition: nocpout.cpp:145
int assert_threadsafe
void conductance_hint(int blocktype, Item *q1, Item *q2)
Definition: nocpout.cpp:2987
static char * mechname
Definition: nocpout.cpp:151
int point_process
Definition: nocpout.cpp:152
void nrninit()
Definition: nocpout.cpp:211
static List * ppvar_semantics_
Definition: nocpout.cpp:166
void decode_ustr(Symbol *sym, double *pg1, double *pg2, char *s)
Definition: nocpout.cpp:1577
static List * ba_list_
Definition: nocpout.cpp:172
int decode_limits(Symbol *sym, double *pg1, double *pg2)
Definition: nocpout.cpp:1530
void units_reg()
Definition: nocpout.cpp:1625
#define NRNNOTP
Definition: nocpout.cpp:96
static int areadec
Definition: nocpout.cpp:155
static List * nrnpointers
Definition: nocpout.cpp:147
int artificial_cell
Definition: nocpout.cpp:153
Symbol * scop_indep
Definition: declare.cpp:12
char * reprime()
void fornetcon(Item *keyword, Item *par1, Item *args, Item *par2, Item *stmt, Item *qend)
Definition: nocpout.cpp:2911
Symbol * indepsym
Definition: declare.cpp:11
List * breakpoint_local_current_
Definition: nocpout.cpp:143
List * ldifuslist
Definition: kinetic.cpp:82
void declare_p()
Definition: nocpout.cpp:2012
void warn_ignore(Symbol *s)
Definition: nocpout.cpp:1405
int const size_t const size_t n
Definition: nrngsl.h:11
size_t q
size_t p
size_t j
static Symbol * vsym
Definition: occvode.cpp:49
static double remove(void *v)
Definition: ocdeck.cpp:207
virtual void move(const Event &e)
Definition: ocinput.h:26
#define STRING
Definition: bbslsrv.cpp:9
List * watch_alloc
Definition: parsact.cpp:16
#define e
Definition: passive0.cpp:22
#define lookup
Definition: redef.h:90
#define install
Definition: redef.h:82
#define cnt
Definition: spt2queue.cpp:19
#define NULL
Definition: sptree.h:16
Definition: model.h:15
struct Item * prev
Definition: model.h:20
short itemtype
Definition: model.h:16
struct Item * next
Definition: model.h:19
Definition: model.h:57
int usage
Definition: model.h:66
short type
Definition: model.h:58
int araydim
Definition: model.h:67
long subtype
Definition: model.h:59
union Symbol::@18 u
char * name
Definition: model.h:72
char * str
Definition: model.h:63
int used
Definition: model.h:65
int varnum
Definition: model.h:69