NEURON
noccout.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 
3 /* print the .c file from the lists */
4 #include "modl.h"
5 #include "parse1.hpp"
6 #include "symbol.h"
7 
8 extern const char* nmodl_version_;
9 
10 #define P(arg) fputs(arg, fcout)
12 /* firstlist gets statements that must go before anything else */
13 
15 extern List *currents, *set_ion_variables(int), *get_ion_variables(int);
16 extern List *begin_dion_stmt(), *end_dion_stmt(const char*);
17 extern List* conductance_;
18 static void conductance_cout();
19 
20 extern List* defs_list;
21 extern const char* saveindep;
22 char* modelline;
23 extern int brkpnt_exists;
24 extern int artificial_cell;
25 extern int net_receive_;
26 extern int debugging_;
27 extern int point_process;
28 extern int dtsav_for_nrn_state;
29 
32 extern List* state_discon_list_;
33 
34 /* VECTORIZE has not been optional for years. We leave the define there but */
35 /* we no longer update the #else clauses. */
36 extern int vectorize;
37 static List* vectorize_replacements; /* pairs of item pointer, strings */
38 extern int electrode_current; /* 1 means we should watch out for extracellular
39  and handle it correctly */
40 
41 #if SYSV
42 #define index strchr
43 #endif
44 
45 static void initstates();
46 static void funcdec();
47 
48 static void ext_vdef() {
49  if (artificial_cell) {
50  return;
51  }
52  if (electrode_current) {
53  P("#if EXTRACELLULAR\n");
54  P(" _nd = _ml_arg->_nodelist[_iml];\n");
55  P(" if (auto* const _extnode = _nrn_mechanism_access_extnode(_nd); _extnode) {\n");
56  P(" _v = NODEV(_nd) + _extnode->_v[0];\n");
57  P(" }else\n");
58  P("#endif\n");
59  P(" {\n");
60  P(" _v = _vec_v[_ni[_iml]];\n");
61  P(" }\n");
62  } else {
63  P(" _v = _vec_v[_ni[_iml]];\n");
64  }
65 }
66 
67 
68 /* when vectorize = 0 */
69 void c_out() {
70  Item* q;
71 
72  Fprintf(fcout, "/* Created by Language version: %s */\n", nmodl_version_);
73  Fflush(fcout);
74 
75  if (vectorize) {
77  kin_vect2(); /* heh, heh.. bet you can't guess what this is */
79  return;
80  }
81  P("/* NOT VECTORIZED */\n#define NRN_VECTORIZED 0\n");
82  Fflush(fcout);
83  /* things which must go first and most declarations */
84  P("#include <stdio.h>\n#include <stdlib.h>\n#include <math.h>\n#include \"mech_api.h\"\n");
85  P("#undef PI\n");
86  P("#define nil 0\n");
87  P("#define _pval pval\n"); // due to some old models using _pval
88  P("// clang-format off\n");
89  P("#include \"md1redef.h\"\n");
90  P("#include \"section_fwd.hpp\"\n");
91  P("#include \"nrniv_mf.h\"\n");
92  P("#include \"md2redef.h\"\n");
93  P("#include \"nrnconf.h\"\n");
94  P("// clang-format on\n");
95  P("#include \"neuron/cache/mechanism_range.hpp\"\n");
96  P("#include <vector>\n");
97 
98  /* avoid clashes with mech names */
99  P("using std::size_t;\n");
100  P("static auto& std_cerr_stream = std::cerr;\n");
101 
104  P("static int _reset;\n");
105  P("static ");
106  if (modelline) {
107  Fprintf(fcout, "const char *modelname = \"%s\";\n\n", modelline);
108  } else {
109  Fprintf(fcout, "const char *modelname = \"\";\n\n");
110  }
111  Fflush(fcout); /* on certain internal errors partial output
112  * is helpful */
113  P("static int error;\n");
114  P("static ");
115  P("int _ninits = 0;\n");
116  P("static int _match_recurse=1;\n");
117  P("static void ");
118  P("_modl_cleanup(){ _match_recurse=1;}\n");
119  /*
120  * many machinations are required to make the infinite number of
121  * definitions involving _p in defs.h to be invisible to the user
122  */
123  /*
124  * This one allows scop variables in functions which do not have the
125  * p array as an argument
126  */
127  funcdec();
128  Fflush(fcout);
129 
130  /*
131  * translations of named blocks into functions, procedures, etc. Also
132  * some special declarations used by some blocks
133  */
135  Fflush(fcout);
136 
137  /* Initialization function must always be present */
138  P("\nstatic void initmodel() {\n int _i; double _save;");
139  P("_ninits++;\n");
140  P(saveindep); /*see solve.c; blank if not a time dependent process*/
141  P("{\n");
142  initstates();
144  P("\n}\n}\n");
145  Fflush(fcout);
146 
147  /* generation of initmodel interface */
148  P("\nstatic void nrn_init(_nrn_model_sorted_token const& _sorted_token, NrnThread* _nt, "
149  "Memb_list* _ml_arg, int _type){\n");
150  P("Node *_nd; double _v; int* _ni; int _cntml;\n");
151  P("_nrn_mechanism_cache_range _lmr{_sorted_token, *_nt, *_ml_arg, _type};\n");
152  P("auto* const _vec_v = _nt->node_voltage_storage();\n");
153  P("_ml = &_lmr;\n"); // update global _ml
154  P("_ni = _ml_arg->_nodeindices;\n");
155  P("_cntml = _ml_arg->_nodecount;\n");
156  P("for (_iml = 0; _iml < _cntml; ++_iml) {\n"); // use global _iml
157  P(" _ppvar = _ml_arg->_pdata[_iml];\n");
158  if (debugging_ && net_receive_) {
159  P(" _tsav = -1e20;\n");
160  }
161  if (!artificial_cell) {
162  ext_vdef();
163  }
164  if (!artificial_cell) {
165  P(" v = _v;\n");
166  }
168  P(" initmodel();\n");
170  P("}}\n");
171 
172  /* standard modl EQUATION without solve computes current */
173  P("\nstatic double _nrn_current(double _v){double _current=0.;v=_v;");
175  fprintf(fcout, "if (cvode_active_) { %s(); }\n", cvode_nrn_current_solve_->name);
176  }
177  P("{");
178  if (currents->next != currents) {
180  }
181  ITERATE(q, currents) {
182  Sprintf(buf, " _current += %s;\n", SYM(q)->name);
183  P(buf);
184  }
185  P("\n} return _current;\n}\n");
186 
187  /* For the classic BREAKPOINT block, the neuron current also has to compute the dcurrent/dv as
188  well as make sure all currents accumulated properly (currents list) */
189 
190  if (brkpnt_exists) {
191  P("\nstatic void nrn_cur(_nrn_model_sorted_token const& _sorted_token, NrnThread* _nt, "
192  "Memb_list* _ml_arg, int _type){\n");
193  P("_nrn_mechanism_cache_range _lmr{_sorted_token, *_nt, *_ml_arg, _type};\n");
194  P("auto const _vec_rhs = _nt->node_rhs_storage();\n");
195  P("auto const _vec_sav_rhs = _nt->node_sav_rhs_storage();\n");
196  P("auto const _vec_v = _nt->node_voltage_storage();\n");
197  P("Node *_nd; int* _ni; double _rhs, _v; int _cntml;\n");
198  P("_ml = &_lmr;\n"); // update global _ml
199  P("_ni = _ml_arg->_nodeindices;\n");
200  P("_cntml = _ml_arg->_nodecount;\n");
201  P("for (_iml = 0; _iml < _cntml; ++_iml) {\n"); // global _iml
202  P(" _ppvar = _ml_arg->_pdata[_iml];\n");
203  ext_vdef();
204  if (currents->next != currents) {
206  cvode_rw_cur(buf);
207  P(buf);
208  }
209  if (cvode_nrn_cur_solve_) {
210  fprintf(fcout, "if (cvode_active_) { %s(); }\n", cvode_nrn_cur_solve_->name);
211  }
212  if (currents->next != currents) {
213  P(" auto const _g_local = _nrn_current(_v + .001);\n");
215  if (state_discon_list_) {
216  P(" state_discon_flag_ = 1; _rhs = _nrn_current(_v); state_discon_flag_ = 0;\n");
217  } else {
218  P(" _rhs = _nrn_current(_v);\n");
219  }
220  printlist(end_dion_stmt(".001"));
221  P(" _g = (_g_local - _rhs)/.001;\n");
222  /* set the ion variable values */
224  if (point_process) {
225  P(" _g *= 1.e2/(_nd_area);\n");
226  P(" _rhs *= 1.e2/(_nd_area);\n");
227  }
228  if (electrode_current) {
229  P(" _vec_rhs[_ni[_iml]] += _rhs;\n");
230  P(" if (_vec_sav_rhs) {\n");
231  P(" _vec_sav_rhs[_ni[_iml]] += _rhs;\n");
232  P(" }\n");
233  P("#if EXTRACELLULAR\n");
234  P(" if (auto* const _extnode = _nrn_mechanism_access_extnode(_nd); _extnode) {\n");
235  P(" *_extnode->_rhs[0] += _rhs;\n");
236  P(" }\n");
237  P("#endif\n");
238  } else {
239  P(" _vec_rhs[_ni[_iml]] -= _rhs;\n");
240  }
241  }
242  P(" \n}}\n");
243 
244  /* for the classic breakpoint block, nrn_cur computed the conductance, _g,
245  and now the jacobian calculation merely returns that */
246  P("\nstatic void nrn_jacob(_nrn_model_sorted_token const& _sorted_token, NrnThread* "
247  "_nt, Memb_list* _ml_arg, int _type) {\n");
248  P("_nrn_mechanism_cache_range _lmr{_sorted_token, *_nt, *_ml_arg, _type};\n");
249  P("auto const _vec_d = _nt->node_d_storage();\n");
250  P("auto const _vec_sav_d = _nt->node_sav_d_storage();\n");
251  P("auto* const _ml = &_lmr;\n");
252  P("Node *_nd; int* _ni; int _iml, _cntml;\n");
253  P("_ni = _ml_arg->_nodeindices;\n");
254  P("_cntml = _ml_arg->_nodecount;\n");
255  P("for (_iml = 0; _iml < _cntml; ++_iml) {\n");
256  if (electrode_current) {
257  P(" _nd = _ml_arg->_nodelist[_iml];\n");
258  P(" _vec_d[_ni[_iml]] -= _g;\n");
259  P(" if (_vec_sav_d) {\n");
260  P(" _vec_sav_d[_ni[_iml]] -= _g;\n");
261  P(" }\n");
262  P("#if EXTRACELLULAR\n");
263  P(" if (auto* const _extnode = _nrn_mechanism_access_extnode(_nd); _extnode) {\n");
264  P(" *_extnode->_d[0] += _g;\n");
265  P(" }\n");
266  P("#endif\n");
267  } else {
268  P(" _vec_d[_ni[_iml]] += _g;\n");
269  }
270  P(" \n}}\n");
271  }
272 
273  /* nrnstate list contains the EQUATION solve statement so this
274  advances states by dt */
275  P("\nstatic void nrn_state(_nrn_model_sorted_token const& _sorted_token, NrnThread* _nt, "
276  "Memb_list* _ml_arg, int _type){\n");
277  if (nrnstate || currents->next == currents) {
278  P("Node *_nd; double _v = 0.0; int* _ni; int _cntml;\n");
279  if (dtsav_for_nrn_state && nrnstate) {
280  P("double _dtsav = dt;\n"
281  "if (secondorder) { dt *= 0.5; }\n");
282  }
283  P("_nrn_mechanism_cache_range _lmr{_sorted_token, *_nt, *_ml_arg, _type};\n");
284  P("auto* const _vec_v = _nt->node_voltage_storage();\n");
285  P("_ml = &_lmr;\n"); // update global _ml
286  P("_ni = _ml_arg->_nodeindices;\n");
287  P("_cntml = _ml_arg->_nodecount;\n");
288  P("for (_iml = 0; _iml < _cntml; ++_iml) {\n"); // use the global _iml
289  P(" _ppvar = _ml_arg->_pdata[_iml];\n");
290  P(" _nd = _ml_arg->_nodelist[_iml];\n");
291  ext_vdef();
292  P(" v=_v;\n{\n");
294  if (nrnstate) {
296  }
297  if (currents->next == currents) {
299  }
301  P("}}\n");
302  if (dtsav_for_nrn_state && nrnstate) {
303  P(" dt = _dtsav;");
304  }
305  }
306  P("\n}\n");
307 
308  P("\nstatic void terminal(){}\n");
309 
310  /* initlists() is called once to setup slist and dlist pointers */
311  P("\nstatic void _initlists() {\n");
312  P(" int _i; static int _first = 1;\n");
313  P(" if (!_first) return;\n");
315  P("_first = 0;\n}\n");
316 }
317 
318 /*
319  * One of the things initmodel() must do is initialize all states to the
320  * value of state0. This generated code goes before any explicit initialize
321  * code written by the user.
322  */
323 static void initstates() {
324  int i;
325  Item* qs;
326  Symbol* s;
327 
328 
329  SYMITER_STAT {
330  /* ioni and iono should not have initialization lines */
331 #define IONCONC 010000
332  if (s->nrntype & IONCONC) {
333  continue;
334  }
335  Sprintf(buf, "%s0", s->name);
336  if (lookup(buf)) { /* if no constant associated
337  * with a state such as the
338  * ones automattically
339  * generated by SENS then
340  * there is no initialization
341  * line */
342  if (s->subtype & ARRAY) {
343  Fprintf(fcout,
344  " for (_i=0; _i<%d; _i++) %s[_i] = %s0;\n",
345  s->araydim,
346  s->name,
347  s->name);
348  } else {
349  Fprintf(fcout, " %s = %s0;\n", s->name, s->name);
350  }
351  }
352  }
353 }
354 
355 /*
356  * here is the only place as of 18-apr-89 where we don't explicitly know the
357  * type of a list element
358  */
359 
360 static int newline, indent;
361 
362 void printitem(Item* q) {
363  if (q->itemtype == SYMBOL) {
364  if (SYM(q)->type == SPECIAL) {
365  switch (SYM(q)->subtype) {
366  case SEMI:
367  newline = 1;
368  break;
369  case BEGINBLK:
370  newline = 1;
371  indent++;
372  break;
373  case ENDBLK:
374  newline = 1;
375  indent--;
376  break;
377  }
378  }
379  Fprintf(fcout, " %s", SYM(q)->name);
380  } else if (q->itemtype == VERBATIM) {
382  } else if (q->itemtype == ITEM) {
383  printitem(ITM(q));
384  } else {
385  Fprintf(fcout, " %s", STR(q));
386  }
387 }
388 
390  if (q->itemtype == SYMBOL) {
391  printf("SYM %s\n", SYM(q)->name);
392  } else if (q->itemtype == VERBATIM) {
393  printf("VERB %s\n", STR(q));
394  } else if (q->itemtype == ITEM) {
395  printf("ITM ");
396  debugprintitem(ITM(q));
397  } else {
398  printf("STR %s\n", STR(q));
399  }
400 }
401 
402 /* does not include q2 */
403 char* items_as_string(Item* q1, Item* q2) {
404  Item* q;
405  buf[0] = '\0';
406  for (q = q1; q != q2; q = q->next) {
407  if (buf[0] != '\0') {
408  strcat(buf, " ");
409  }
410  if (q->itemtype == SYMBOL) {
411  strcat(buf, SYM(q)->name);
412  } else if (q->itemtype == STRING) {
413  strcat(buf, STR(q));
414  } else {
415  assert(0);
416  }
417  }
418  return strdup(buf);
419 }
420 
421 void printlist(List* s) {
422  Item* q;
423  int i;
424  newline = 0, indent = 0;
425  /*
426  * most of this is merely to decide where newlines and indentation
427  * goes so that the .c file can be read if something goes wrong
428  */
429  if (!s) {
430  return;
431  }
432  ITERATE(q, s) {
433  printitem(q);
434  if (newline) {
435  newline = 0;
436  Fprintf(fcout, "\n");
437  for (i = 0; i < indent; i++) {
438  Fprintf(fcout, " ");
439  }
440  }
441  }
442 }
443 
444 static void funcdec() {
445  int i;
446  Symbol* s;
447  List* qs;
448  int j, narg, more;
449 
450  SYMITER(NAME) {
451  more = 0;
452  if (s->subtype & PROCED) {
453  Fprintf(fcout, "static int %s(", s->name);
454  more = 1;
455  }
456  if (more) {
457  narg = s->varnum;
458  if (vectorize) {
459  if (narg) {
460  Fprintf(fcout, "_internalthreadargsprotocomma_ ");
461  } else {
462  Fprintf(fcout, "_internalthreadargsproto_");
463  }
464  }
465  /*loop over argcount and add ,double */
466  if (narg > 0) {
467  Fprintf(fcout, "double");
468  }
469  for (j = 1; j < narg; ++j) {
470  Fprintf(fcout, ", double");
471  }
472  Fprintf(fcout, ");\n");
473  }
474  }
475 }
476 
477 /* when vectorize = 1 */
479  Item* q;
480 
481  /* things which must go first and most declarations */
482  P("/* VECTORIZED */\n#define NRN_VECTORIZED 1\n");
483  P("#include <stdio.h>\n#include <stdlib.h>\n#include <math.h>\n#include \"mech_api.h\"\n");
484  P("#undef PI\n");
485  P("#define nil 0\n");
486  P("#define _pval pval\n"); // due to some old models using _pval
487  P("// clang-format off\n");
488  P("#include \"md1redef.h\"\n");
489  P("#include \"section_fwd.hpp\"\n");
490  P("#include \"nrniv_mf.h\"\n");
491  P("#include \"md2redef.h\"\n");
492  P("#include \"nrnconf.h\"\n");
493  P("// clang-format on\n");
494  P("#include \"neuron/cache/mechanism_range.hpp\"\n");
497  P("static int _reset;\n");
498  if (modelline) {
499  Fprintf(fcout, "static const char *modelname = \"%s\";\n\n", modelline);
500  } else {
501  Fprintf(fcout, "static const char *modelname = \"\";\n\n");
502  }
503  Fflush(fcout); /* on certain internal errors partial output
504  * is helpful */
505  P("static int error;\n");
506  P("static int _ninits = 0;\n");
507  P("static int _match_recurse=1;\n");
508  P("static void _modl_cleanup(){ _match_recurse=1;}\n");
509 
510  funcdec();
511  Fflush(fcout);
512 
513  /*
514  * translations of named blocks into functions, procedures, etc. Also
515  * some special declarations used by some blocks
516  */
518  Fflush(fcout);
519 
520  /* Initialization function must always be present */
521 
522  P("\nstatic void initmodel(_internalthreadargsproto_) {\n int "
523  "_i; double _save;");
524  P("{\n");
525  initstates();
527  P("\n}\n}\n");
528  Fflush(fcout);
529 
530  /* generation of initmodel interface */
531  P("\nstatic void nrn_init(_nrn_model_sorted_token const& _sorted_token, NrnThread* _nt, "
532  "Memb_list* _ml_arg, int _type){\n");
533  P("_nrn_mechanism_cache_range _lmr{_sorted_token, *_nt, *_ml_arg, _type};\n");
534  P("auto* const _vec_v = _nt->node_voltage_storage();\n");
535  P("auto* const _ml = &_lmr;\n");
536  P("Datum* _ppvar; Datum* _thread;\n");
537  P("Node *_nd; double _v; int* _ni; int _iml, _cntml;\n");
538  P("_ni = _ml_arg->_nodeindices;\n");
539  P("_cntml = _ml_arg->_nodecount;\n");
540  P("_thread = _ml_arg->_thread;\n");
541  P("double* _globals = nullptr;\n");
542  P("if (gind != 0 && _thread != nullptr) { _globals = _thread[_gth].get<double*>(); }\n");
543  /*check_tables();*/
544  P("for (_iml = 0; _iml < _cntml; ++_iml) {\n");
545  P(" _ppvar = _ml_arg->_pdata[_iml];\n");
546  check_tables();
547  if (debugging_ && net_receive_) {
548  P(" _tsav = -1e20;\n");
549  }
550  if (!artificial_cell) {
551  ext_vdef();
552  }
553  if (!artificial_cell) {
554  P(" v = _v;\n");
555  }
557  P(" initmodel(_threadargs_);\n");
559  P("}\n");
560  P("}\n");
561 
562  /* standard modl EQUATION without solve computes current */
563  if (!conductance_) {
564  P("\nstatic double _nrn_current(_internalthreadargsprotocomma_ "
565  "double _v) {\n"
566  "double _current=0.; v=_v;\n");
568  fprintf(fcout,
569  "if (cvode_active_) { %s(_threadargs_); }\n",
571  }
572  P("{");
573  if (currents->next != currents) {
575  }
576  ITERATE(q, currents) {
577  if (SYM(q) != breakpoint_current(SYM(q))) {
578  diag(
579  "current can only be LOCAL in a BREAKPOINT if CONDUCTANCE statements are "
580  "used. ",
581  SYM(q)->name);
582  }
583  Sprintf(buf, " _current += %s;\n", SYM(q)->name);
584  P(buf);
585  }
586  P("\n} return _current;\n}\n");
587  }
588 
589  /* For the classic BREAKPOINT block, the neuron current also has to compute the dcurrent/dv as
590  well as make sure all currents accumulated properly (currents list) */
591 
592  if (brkpnt_exists) {
593  P("\nstatic void nrn_cur(_nrn_model_sorted_token const& _sorted_token, NrnThread* _nt, "
594  "Memb_list* _ml_arg, int _type) {\n");
595  P("_nrn_mechanism_cache_range _lmr{_sorted_token, *_nt, *_ml_arg, _type};\n");
596  P("auto const _vec_rhs = _nt->node_rhs_storage();\n");
597  P("auto const _vec_sav_rhs = _nt->node_sav_rhs_storage();\n");
598  P("auto const _vec_v = _nt->node_voltage_storage();\n");
599  P("auto* const _ml = &_lmr;\n");
600  P("Datum* _ppvar; Datum* _thread;\n");
601  P("Node *_nd; int* _ni; double _rhs, _v; int _iml, _cntml;\n");
602  P("_ni = _ml_arg->_nodeindices;\n");
603  P("_cntml = _ml_arg->_nodecount;\n");
604  P("_thread = _ml_arg->_thread;\n");
605  P("double* _globals = nullptr;\n");
606  P("if (gind != 0 && _thread != nullptr) { _globals = _thread[_gth].get<double*>(); }\n");
607  P("for (_iml = 0; _iml < _cntml; ++_iml) {\n");
608  P(" _ppvar = _ml_arg->_pdata[_iml];\n");
609  ext_vdef();
610  if (currents->next != currents) {
612  cvode_rw_cur(buf);
613  P(buf);
614  }
615  if (cvode_nrn_cur_solve_) {
616  fprintf(fcout,
617  "if (cvode_active_) { %s(_threadargs_); }\n",
619  }
620  if (currents->next != currents) {
621  if (conductance_) {
622  P(" {\n");
625  P(" }\n");
626  } else {
627  P(" auto const _g_local = _nrn_current(_threadargscomma_ _v + .001);\n");
629  if (state_discon_list_) {
630  P(" state_discon_flag_ = 1; _rhs = _nrn_current(_v); state_discon_flag_ = "
631  "0;\n");
632  } else {
633  P(" _rhs = _nrn_current(_threadargscomma_ _v);\n");
634  }
635  printlist(end_dion_stmt(".001"));
636  P(" _g = (_g_local - _rhs)/.001;\n");
637  /* set the ion variable values */
639  } /* end of not conductance */
640  if (point_process) {
641  P(" _g *= 1.e2/(_nd_area);\n");
642  P(" _rhs *= 1.e2/(_nd_area);\n");
643  }
644  if (electrode_current) {
645  P(" _vec_rhs[_ni[_iml]] += _rhs;\n");
646  P(" if (_vec_sav_rhs) {\n");
647  P(" _vec_sav_rhs[_ni[_iml]] += _rhs;\n");
648  P(" }\n");
649  P("#if EXTRACELLULAR\n");
650  P(" if (auto* const _extnode = _nrn_mechanism_access_extnode(_nd); _extnode) {\n");
651  P(" *_extnode->_rhs[0] += _rhs;\n");
652  P(" }\n");
653  P("#endif\n");
654  } else {
655  P(" _vec_rhs[_ni[_iml]] -= _rhs;\n");
656  }
657  }
658  P(" \n}\n");
659  P(" \n}\n");
660  /* for the classic breakpoint block, nrn_cur computed the conductance, _g,
661  and now the jacobian calculation merely returns that */
662  P("\nstatic void nrn_jacob(_nrn_model_sorted_token const& _sorted_token, NrnThread* "
663  "_nt, Memb_list* _ml_arg, int _type) {\n");
664  P("_nrn_mechanism_cache_range _lmr{_sorted_token, *_nt, *_ml_arg, _type};\n");
665  P("auto const _vec_d = _nt->node_d_storage();\n");
666  P("auto const _vec_sav_d = _nt->node_sav_d_storage();\n");
667  P("auto* const _ml = &_lmr;\n");
668  P("Datum* _ppvar; Datum* _thread;\n");
669  P("Node *_nd; int* _ni; int _iml, _cntml;\n");
670  P("_ni = _ml_arg->_nodeindices;\n");
671  P("_cntml = _ml_arg->_nodecount;\n");
672  P("_thread = _ml_arg->_thread;\n");
673  P("double* _globals = nullptr;\n");
674  P("if (gind != 0 && _thread != nullptr) { _globals = _thread[_gth].get<double*>(); }\n");
675  P("for (_iml = 0; _iml < _cntml; ++_iml) {\n");
676  if (electrode_current) {
677  P(" _nd = _ml_arg->_nodelist[_iml];\n");
678  P(" _vec_d[_ni[_iml]] -= _g;\n");
679  P(" if (_vec_sav_d) {\n");
680  P(" _vec_sav_d[_ni[_iml]] -= _g;\n");
681  P(" }\n");
682  P("#if EXTRACELLULAR\n");
683  P(" if (auto* const _extnode = _nrn_mechanism_access_extnode(_nd); _extnode) {\n");
684  P(" *_extnode->_d[0] += _g;\n");
685  P(" }\n");
686  P("#endif\n");
687  } else {
688  P(" _vec_d[_ni[_iml]] += _g;\n");
689  }
690  P(" \n}\n");
691  P(" \n}\n");
692  }
693 
694  /* nrnstate list contains the EQUATION solve statement so this
695  advances states by dt */
696  P("\nstatic void nrn_state(_nrn_model_sorted_token const& _sorted_token, NrnThread* _nt, "
697  "Memb_list* _ml_arg, int _type) {\n");
698  P("_nrn_mechanism_cache_range _lmr{_sorted_token, *_nt, *_ml_arg, _type};\n");
699  P("auto* const _vec_v = _nt->node_voltage_storage();\n");
700  P("auto* const _ml = &_lmr;\n");
701  if (nrnstate || currents->next == currents) {
702  P("Datum* _ppvar; Datum* _thread;\n");
703  P("Node *_nd; double _v = 0.0; int* _ni;\n");
704  if (dtsav_for_nrn_state && nrnstate) {
705  P("double _dtsav = dt;\n"
706  "if (secondorder) { dt *= 0.5; }\n");
707  }
708  P("_ni = _ml_arg->_nodeindices;\n");
709  P("size_t _cntml = _ml_arg->_nodecount;\n");
710  P("_thread = _ml_arg->_thread;\n");
711  P("double* _globals = nullptr;\n");
712  P("if (gind != 0 && _thread != nullptr) { _globals = _thread[_gth].get<double*>(); }\n");
713  P("for (size_t _iml = 0; _iml < _cntml; ++_iml) {\n");
714  P(" _ppvar = _ml_arg->_pdata[_iml];\n");
715  P(" _nd = _ml_arg->_nodelist[_iml];\n");
716  ext_vdef();
717  P(" v=_v;\n{\n");
719  if (nrnstate) {
721  }
722  if (currents->next == currents) {
724  }
726  P("}}\n");
727  if (dtsav_for_nrn_state && nrnstate) {
728  P(" dt = _dtsav;");
729  }
730  }
731  P("\n}\n");
732 
733  P("\nstatic void terminal(){}\n");
734 
735  /* vectorized: data must have own copies of slist and dlist
736  for now we don't vectorize if slist or dlist exists. Eventually
737  must separate initialization of static things from vectorized
738  things.
739  */
740  /* initlists() is called once to setup slist and dlist pointers */
741  P("\nstatic void _initlists(){\n");
742  P(" int _i; static int _first = 1;\n");
743  P(" if (!_first) return;\n");
745  P("_first = 0;\n}\n");
746 }
747 
748 void vectorize_substitute(Item* q, const char* str) {
749  if (!vectorize_replacements) {
751  }
754 }
755 
757  Item* q1;
760  if (ITM(q1) == q) {
761  return q1->next;
762  }
763  }
764  }
765  return (Item*) 0;
766 }
767 
769  Item *q, *q1;
772  q1 = ITM(q);
773  q = q->next;
774  replacstr(q1, STR(q));
775  }
776  }
777 }
778 
779 static void conductance_cout() {
780  int i = 0;
781  Item* q;
782  List* m;
783 
784  /* replace v with _v */
785  m = newlist();
786  ITERATE(q, modelfunc) {
787  if (q->itemtype == SYMBOL) {
788  if (strcmp(SYM(q)->name, "v") == 0) {
789  lappendstr(m, "_v");
790  } else {
791  lappendsym(m, SYM(q));
792  }
793  } else if (q->itemtype == STRING) {
794  lappendstr(m, STR(q));
795  } else {
796  diag("modelfunc contains item which is not a SYMBOL or STRING", (char*) 0);
797  }
798  }
799  /* eliminate first { */
800  ITERATE(q, m) {
801  if (q->itemtype == SYMBOL) {
802  if (strcmp(SYM(q)->name, "{") == 0) {
803  remove(q);
804  break;
805  }
806  }
807  }
808  /* eliminate last } */
809  for (q = m->prev; q != m; q = q->prev) {
810  if (q->itemtype == SYMBOL) {
811  if (strcmp(SYM(q)->name, "}") == 0) {
812  remove(q);
813  break;
814  }
815  }
816  }
817 
818  printlist(m);
819 
820  ITERATE(q, currents) {
821  if (i == 0) {
822  Sprintf(buf, " _rhs = %s", breakpoint_current(SYM(q))->name);
823  } else {
824  Sprintf(buf, " + %s", breakpoint_current(SYM(q))->name);
825  }
826  P(buf);
827  i += 1;
828  }
829  if (i > 0) {
830  P(";\n");
831  }
832 
833  i = 0;
835  if (i == 0) {
836  Sprintf(buf, " _g = %s", SYM(q)->name);
837  } else {
838  Sprintf(buf, " + %s", SYM(q)->name);
839  }
840  P(buf);
841  i += 1;
842  q = q->next;
843  }
844  if (i > 0) {
845  P(";\n");
846  }
847 
849  if (SYM(q->next)) {
850  Sprintf(buf, " _ion_di%sdv += %s", SYM(q->next)->name, SYM(q)->name);
851  P(buf);
852  if (point_process) {
853  P("* 1.e2/(_nd_area)");
854  }
855  P(";\n");
856  }
857  q = q->next;
858  }
859 }
#define STRING
Definition: bbslsrv.cpp:9
#define i
Definition: md1redef.h:19
void verbatim_adjust(char *q)
Definition: modl.cpp:261
void printlist(List *s)
Definition: noccout.cpp:421
char buf[512]
Definition: init.cpp:13
List * firstlist
Definition: noccout.cpp:11
#define assert(ex)
Definition: hocassrt.h:24
static int narg()
Definition: ivocvect.cpp:121
void kin_vect2()
Definition: kinetic.cpp:1244
FILE * fcout
Definition: model.cpp:36
#define STR(q)
Definition: model.h:76
#define ITERATE(itm, lst)
Definition: model.h:18
#define ENDBLK
Definition: model.h:113
#define SYMBOL
Definition: model.h:91
#define ITEM
Definition: model.h:92
#define Fflush
Definition: model.h:213
#define SPECIAL
Definition: model.h:89
#define ITM(q)
Definition: model.h:77
#define SYM(q)
Definition: model.h:75
#define BEGINBLK
Definition: model.h:112
#define SEMI
Definition: model.h:111
Symbol * lookup(const char *)
#define ARRAY
Definition: model.h:107
#define PROCED
Definition: model.h:109
printf
Definition: extdef.h:5
const char * name
Definition: init.cpp:16
long subtype
Definition: init.cpp:107
void replacstr(Item *q, const char *s)
Definition: list.cpp:219
Item * lappenditem(List *list, Item *item)
Definition: list.cpp:147
Item * lappendsym(List *list, Symbol *sym)
Definition: list.cpp:143
Item * lappendstr(List *list, const char *str)
Definition: list.cpp:135
#define SYMITER(arg1)
Definition: symbol.h:13
#define SYMITER_STAT
Definition: symbol.h:22
List * newlist()
The following routines support the concept of a list.
int Sprintf(char(&buf)[N], const char *fmt, Args &&... args)
Redirect sprintf to snprintf if the buffer size can be deduced.
Definition: wrap_sprintf.h:14
Symbol * breakpoint_current(Symbol *s)
Definition: nocpout.cpp:3286
void cvode_rw_cur(char(&b)[NRN_BUFSIZE])
Definition: nocpout.cpp:3014
void check_tables()
Definition: parsact.cpp:353
Item * vectorize_replacement_item(Item *q)
Definition: noccout.cpp:756
List * get_ion_variables(int)
Definition: nocpout.cpp:2307
static void funcdec()
Definition: noccout.cpp:444
List * initfunc
Definition: noccout.cpp:11
List * currents
Definition: nocpout.cpp:124
List * procfunc
Definition: noccout.cpp:11
List * nrnstate
Definition: noccout.cpp:14
void c_out_vectorize()
Definition: noccout.cpp:478
#define P(arg)
Definition: noccout.cpp:10
List * conductance_
Definition: nocpout.cpp:126
int vectorize
Definition: nocpout.cpp:78
void vectorize_do_substitute()
Definition: noccout.cpp:768
Symbol * cvode_nrn_current_solve_
Definition: solve.cpp:23
int brkpnt_exists
int electrode_current
Definition: nocpout.cpp:109
List * state_discon_list_
Definition: nocpout.cpp:160
List * begin_dion_stmt()
List * set_ion_variables(int)
Definition: nocpout.cpp:2236
#define IONCONC
Symbol * cvode_nrn_cur_solve_
Definition: solve.cpp:22
const char * nmodl_version_
Definition: nocpout.cpp:12
List * defs_list
Definition: nocpout.cpp:107
int debugging_
Definition: nocpout.cpp:166
void c_out()
Definition: noccout.cpp:69
List * end_dion_stmt(const char *)
Definition: nocpout.cpp:2589
const char * saveindep
Definition: solve.cpp:300
static void initstates()
Definition: noccout.cpp:323
static int newline
Definition: noccout.cpp:360
static void conductance_cout()
Definition: noccout.cpp:779
static int indent
Definition: noccout.cpp:360
void debugprintitem(Item *q)
Definition: noccout.cpp:389
List * initlist
Definition: noccout.cpp:11
int net_receive_
Definition: nocpout.cpp:167
int dtsav_for_nrn_state
Definition: deriv.cpp:17
List * termfunc
Definition: noccout.cpp:11
static List * vectorize_replacements
Definition: noccout.cpp:37
static void ext_vdef()
Definition: noccout.cpp:48
int point_process
Definition: nocpout.cpp:138
void vectorize_substitute(Item *q, const char *str)
Definition: noccout.cpp:748
char * items_as_string(Item *q1, Item *q2)
Definition: noccout.cpp:403
int artificial_cell
Definition: nocpout.cpp:139
char * modelline
Definition: noccout.cpp:22
void printitem(Item *q)
Definition: noccout.cpp:362
List * modelfunc
Definition: noccout.cpp:11
NMODL parser global flags / functions.
#define diag(s)
Definition: nonlin.cpp:19
size_t q
size_t j
s
Definition: multisend.cpp:521
short type
Definition: cabvars.h:10
static double remove(void *v)
Definition: ocdeck.cpp:205
Definition: model.h:8
struct Item * prev
Definition: model.h:13
struct Item * next
Definition: model.h:12
Definition: model.h:47
char * name
Definition: model.h:61
int Fprintf(FILE *stream, const char *fmt, Args... args)
Definition: logger.hpp:8