NEURON
solve.cpp
Go to the documentation of this file.
1 #include <../../nmodlconf.h>
2 /* /local/src/master/nrn/src/nmodl/solve.c,v 4.4 1998/08/20 21:07:34 hines Exp */
3 
4 #include "modl.h"
5 #include "parse1.hpp"
6 #include "symbol.h"
7 
8 /* make it an error if 2 solve statements are called on a single call to
9 model() */
10 extern List* indeplist;
12 extern Symbol* indepsym;
13 extern char* current_line();
14 extern List* massage_list_;
15 #if NMODL
16 extern List* nrnstate;
17 #if VECTORIZE
18 extern int vectorize;
19 extern char* cray_pragma();
20 extern int netrec_state_count;
21 extern int netrec_need_thread;
22 #endif
23 #endif
24 #if CVODE
25 Item* cvode_cnexp_solve;
26 Symbol* cvode_nrn_cur_solve_;
27 Symbol* cvode_nrn_current_solve_;
28 #endif
29 
30 void whileloop(Item*, long, int);
31 void check_ss_consist(Item*);
32 
33 /* Need list of solve statements. We impress the
34 general list structure to handle it. The element is a pointer to an
35 item which is the first item in the statement sequence in another list.
36 */
37 static List* solvq; /* list of the solve statement locations */
38 int numlist = 0; /* number of slist's */
39 
40 void solvequeue(Item* q1, Item* q2, int blocktype, Item* qerr) /*solve NAME=q1 [using METHOD=q2]*/
41 /* q2 = 0 means method wasn't there */
42 /* qerr in ITEM0 or else the closing
43  brace of an IFERROR stmt */
44 {
45  /* the solvq list is organized in groups of an item element
46  followed by the method symbol( null if default to be used) */
47  /* The itemtype field of the first is used to carry the blocktype*/
48  /* SOLVE and METHOD method are deleted */
49  /* The list now consists of triples in which the third element
50  is a list containing the complete IFERROR statement.
51  */
52  Item *lq, *qtemp;
53  List* errstmt;
54 
55  if (!solvq) {
56  solvq = newlist();
57  }
58 #if NMODL
59  /* if the blocktype is equation then move the solve statement to
60  the nrnstate function. Everything else stays in the
61  model function to be used as the nrncurrent function */
62  if (blocktype == BREAKPOINT) {
63  if (!nrnstate) {
64  nrnstate = newlist();
65  }
66  Lappendstr(nrnstate, "{");
67  if (qerr) {
68  movelist(q1->prev, qerr, nrnstate);
69  } else if (q2) {
70  movelist(q1->prev, q2, nrnstate);
71  } else {
72  movelist(q1->prev, q1, nrnstate);
73  }
74  Lappendstr(nrnstate, "}");
75  }
76  /* verify that the block defintion for this SOLVE has not yet been seen */
77  if (massage_list_)
78  ITERATE(lq, massage_list_) {
79  if (strcmp(SYM(lq)->name, SYM(q1)->name) == 0) {
80  diag("The SOLVE statement must be before the DERIVATIVE block for ", SYM(lq)->name);
81  }
82  }
83 #endif
84  lq = lappendsym(solvq, SYM0);
85  ITM(lq) = q1;
86  lq->itemtype = blocktype;
87  /* handle STEADYSTATE option */
88  if (q1->next->itemtype == SYMBOL && strcmp("STEADYSTATE", SYM(q1->next)->name) == 0) {
89  lq->itemtype = -blocktype; /* gets put back below */
90  }
91  if (q2) {
92  qtemp = q2->next; /* The IFERROR location */
93  Lappendsym(solvq, SYM(q2));
94  if (strcmp(SYM(q2)->name, "derivimplicit") == 0) {
96  }
97  if (strcmp(SYM(q2)->name, "cnexp") == 0) {
98  SYM(q2)->name = stralloc("derivimplicit", SYM(q2)->name);
100 #if CVODE
101  cvode_cnexp_solve = lq;
102 #endif
103  }
104  remove(q2->prev);
105  remove(q2);
106  } else {
107  qtemp = q1->next;
109  }
110  remove(q1->prev);
111 
112  /* handle the error statement */
113  /* put one in if it isn't already there */
114  if (qerr == ITEM0) {
115 #if NOCMODL
116  sprintf(buf,
117  "if(error){fprintf(stderr,\"%s\\n\"); nrn_complain(_p); abort_run(error);}\n",
118  current_line());
119  qtemp = qerr = insertstr(qtemp, buf);
120 #else
121  qtemp = qerr = insertstr(qtemp, "if(error){abort_run(error);}\n");
122 #endif
123  } else {
124  replacstr(qtemp, "if (error)");
125  }
126  errstmt = newlist();
127  lq = lappendsym(solvq, SYM0);
128  LST(lq) = errstmt;
129  movelist(qtemp, qerr, errstmt);
130 }
131 
132 /* go through the solvq list and construct the proper while loop and calls*/
133 void solvhandler() {
134  Item *lq, *qsol, *follow;
135  List* errstmt;
136  Symbol *fun, *method;
137  int numeqn, listnum, btype, steadystate;
138  int cvodemethod_;
139 
140  if (!solvq)
141  solvq = newlist();
142  init_disc_vars(); /*why not here?*/
143  ITERATE(lq, solvq) { /* remember it goes by 3's */
144  steadystate = 0;
145  btype = lq->itemtype;
146  if (btype < 0) {
147  btype = lq->itemtype = -btype;
148  steadystate = 1;
149  check_ss_consist(lq);
150  }
151  qsol = ITM(lq);
152  lq = lq->next;
153  method = SYM(lq);
154 #if CVODE
155  cvodemethod_ = 0;
156  if (method && strcmp(method->name, "after_cvode") == 0) {
157  method = (Symbol*) 0;
158  lq->element.sym = (Symbol*) 0;
159  cvodemethod_ = 1;
160  }
161  if (method && strcmp(method->name, "cvode_t") == 0) {
162  method = (Symbol*) 0;
163  lq->element.sym = (Symbol*) 0;
164  cvodemethod_ = 2;
165  }
166  if (method && strcmp(method->name, "cvode_v") == 0) {
167  method = (Symbol*) 0;
168  lq->element.sym = (Symbol*) 0;
169  cvodemethod_ = 3;
170  }
171 #endif
172  lq = lq->next;
173  errstmt = LST(lq);
174  /* err stmt handling assumes qsol->next is where it goes. */
175  fun = SYM(qsol);
176  numeqn = fun->used;
177  listnum = fun->u.i;
178  if (btype == BREAKPOINT && (fun->subtype == DERF || fun->subtype == KINF)) {
179  netrec_state_count = numeqn * 10 + listnum;
180  netrec_need_thread = 1;
181  }
182  follow = qsol->next; /* where p[0] gets updated */
183  /* Check consistency of method and block type */
184  if (method && !(method->subtype & fun->subtype)) {
185  Sprintf(buf, "Method %s can't be used with Block %s", method->name, fun->name);
186  diag(buf, (char*) 0);
187  }
188 
189  switch (fun->subtype) {
190  case DERF:
191  if (method == SYM0) {
192  method = lookup("adrunge");
193  }
194  if (btype == BREAKPOINT && !steadystate) {
195  /* derivatives recalculated after while loop */
196  if (strcmp(method->name, "cnexp") != 0 &&
197  strcmp(method->name, "derivimplicit") != 0 &&
198  strcmp(method->name, "euler") != 0) {
199  fprintf(stderr,
200  "Notice: %s is not thread safe. Complain to Hines\n",
201  method->name);
202  vectorize = 0;
203  Sprintf(buf, " %s();\n", fun->name);
204  Insertstr(follow, buf);
205  }
206  /* envelope calls go after the while loop */
207  sens_nonlin_out(follow, fun);
208 #if CVODE
209  cvode_interface(fun, listnum, numeqn);
210 #endif
211  }
212  if (btype == BREAKPOINT)
213  whileloop(qsol, (long) DERF, steadystate);
214  solv_diffeq(qsol, fun, method, numeqn, listnum, steadystate, btype);
215  break;
216  case KINF:
217  if (method == SYM0) {
218  method = lookup("_advance");
219  }
220  if (btype == BREAKPOINT && (method->subtype & DERF)) {
221 #if VECTORIZE
222  fprintf(
223  stderr,
224  "Notice: KINETIC is thread safe only with METHOD sparse. Complain to Hines\n");
225  vectorize = 0;
226 #endif
227  /* derivatives recalculated after while loop */
228  Sprintf(buf, " %s();\n", fun->name);
229  Insertstr(follow, buf);
230  /* envelope calls go after the while loop */
231  sens_nonlin_out(follow, fun);
232  }
233  if (btype == BREAKPOINT) {
234  whileloop(qsol, (long) DERF, steadystate);
235 #if CVODE
236  if (strcmp(method->name, "sparse") == 0) {
237  cvode_interface(fun, listnum, numeqn);
238  cvode_kinetic(qsol, fun, numeqn, listnum);
239  single_channel(qsol, fun, numeqn, listnum);
240  }
241 #endif
242  }
243  solv_diffeq(qsol, fun, method, numeqn, listnum, steadystate, btype);
244  break;
245  case NLINF:
246 #if VECTORIZE
247  fprintf(stderr, "Notice: NONLINEAR is not thread safe.\n");
248  vectorize = 0;
249 #endif
250  if (method == SYM0) {
251  method = lookup("newton");
252  }
253  solv_nonlin(qsol, fun, method, numeqn, listnum);
254  break;
255  case LINF:
256 #if VECTORIZE
257  fprintf(stderr, "Notice: LINEAR is not thread safe.\n");
258  vectorize = 0;
259 #endif
260  if (method == SYM0) {
261  method = lookup("simeq");
262  }
263  solv_lineq(qsol, fun, method, numeqn, listnum);
264  break;
265  case DISCF:
266 #if VECTORIZE
267  fprintf(stderr, "Notice: DISCRETE is not thread safe.\n");
268  vectorize = 0;
269 #endif
270  if (btype == BREAKPOINT)
271  whileloop(qsol, (long) DISCRETE, 0);
272  Sprintf(buf, "0; %s += d%s; %s();\n", indepsym->name, indepsym->name, fun->name);
273  replacstr(qsol, buf);
274  break;
275 #if 1 /* really wanted? */
276  case PROCED:
277  if (btype == BREAKPOINT) {
278  whileloop(qsol, (long) DERF, 0);
279 #if CVODE
280  if (cvodemethod_ == 1) { /*after_cvode*/
281  cvode_interface(fun, listnum, 0);
282  }
283  if (cvodemethod_ == 2) { /*cvode_t*/
284  cvode_interface(fun, listnum, 0);
285  insertstr(qsol, "if (!cvode_active_)");
286  cvode_nrn_cur_solve_ = fun;
287  linsertstr(procfunc, "extern int cvode_active_;\n");
288  }
289  if (cvodemethod_ == 3) { /*cvode_t_v*/
290  cvode_interface(fun, listnum, 0);
291  insertstr(qsol, "if (!cvode_active_)");
292  cvode_nrn_current_solve_ = fun;
293  linsertstr(procfunc, "extern int cvode_active_;\n");
294  }
295 #endif
296  }
297  Sprintf(buf, " %s();\n", fun->name);
298  replacstr(qsol, buf);
299 #if VECTORIZE
300  Sprintf(buf, "{ %s(_p, _ppvar, _thread, _nt); }\n", fun->name);
301  vectorize_substitute(qsol, buf);
302 #endif
303  break;
304 #endif
305  case PARF:
306 #if VECTORIZE
307  fprintf(stderr, "Notice: PARTIAL is not thread safe.\n");
308  vectorize = 0;
309 #endif
310  if (btype == BREAKPOINT)
311  whileloop(qsol, (long) DERF, 0);
312  solv_partial(qsol, fun);
313  break;
314  default:
315  diag("Illegal or unimplemented SOLVE type: ", fun->name);
316  break;
317  }
318 #if CVODE
319  if (btype == BREAKPOINT) {
320  cvode_valid();
321  }
322 #endif
323  /* add the error check */
324  Insertstr(qsol, "error =");
325  move(errstmt->next, errstmt->prev, qsol->next);
326 #if VECTORIZE
327  if (errstmt->next == errstmt->prev) {
328  vectorize_substitute(qsol->next, "");
329  vectorize_substitute(qsol->prev, "");
330  } else {
331  fprintf(stderr, "Notice: SOLVE with ERROR is not thread safe.\n");
332  vectorize = 0;
333  }
334 #endif
335  freelist(&errstmt);
336  /* under all circumstances, on return from model,
337  p[0] = current indepvar */
338  /* obviously ok if indepvar is original; if it has been changed
339  away from time
340  then _sav_indep will be reset to starting value of original when
341  initmodel is called on every call to model */
342 #if NMODL
343 #else
344  if (btype == BREAKPOINT) {
345 #if SIMSYS
346  Sprintf(buf, "_sav_indep = %s;\n", indepsym->name);
347 #else
348  Sprintf(buf, "_sav_indep = _p[_indepindex];\n");
349 #endif
350  Insertstr(follow, buf);
351  }
352 #endif
353  }
354 }
355 
356 void save_dt(Item* q) /* save and restore the value of indepvar */
357 {
358  /*ARGSUSED*/
359 #if 0 /* integrators no longer increment time */
360  static int first=1;
361 
362  if (first) {
363  first = 0;
364  Linsertstr(procfunc, "double _savlocal;\n");
365  }
366  Sprintf(buf, "_savlocal = %s;\n", indepsym->name);
367  Insertstr(q, buf);
368  Sprintf(buf, "%s = _savlocal;\n", indepsym->name);
369  Insertstr(q->next, buf);
370 #endif
371 }
372 
373 char* saveindep = "";
374 
375 void whileloop(Item* qsol, long type, int ss) {
376  /* no solve statement except this is allowed to
377  change the indepvar. Time passed to integrators
378  must therefore be saved and restored. */
379  /* Note that when the user changes the independent variable within Scop,
380  the while loop still uses the original independent variable. In this case
381  1) _break must be set to the entry value of the original independent variable
382  2) initmodel() must be called after each entry to model()
383  3) in initmodel() we are very careful not to destroy the entry value of
384  time-- on exit it has its original value. Note that _sav_indep gets
385  any value of time that is set within initmodel().
386  */
387  /* executing more that one for loop in a single call to model() is an error
388  which is trapped in scop */
389  static int called = 0, firstderf = 1;
390  char* cp = 0;
391 
392  switch (type) {
393  case DERF:
394  case DISCRETE:
395  if (firstderf) { /* time dependent process so create a deltastep */
396  double d[3];
397  int i;
398  Item* q;
399  char sval[256];
400  Sprintf(buf, "delta_%s", indepsym->name);
401  for (i = 0, q = indeplist->next; i < 3; i++, q = q->next) {
402  d[i] = atof(STR(q));
403  }
404  if (type == DERF) {
405  Sprintf(sval, "%g", (d[1] - d[0]) / d[2]);
406  } else if (type == DISCRETE) {
407  Sprintf(sval, "1.0");
408  }
409  deltaindep = ifnew_parminstall(buf, sval, "", "");
410  firstderf = 0;
411 #if NMODL
412 #else
413  Sprintf(buf, "_modl_set_dt(_dt) double _dt; { %s = _dt;}\n", deltaindep->name);
415 #endif
416  }
417  if (type == DERF) {
418  cp = "dt";
419  } else if (type == DISCRETE) {
420  cp = "0.0";
421  }
422  if (ss) {
423  return;
424  }
425  break;
426  default:
427  /*SUPPRESS 622*/
428  assert(0);
429  }
430 #if NMODL
431  if (strcmp(indepsym->name, "t") != 0) {
432  diag("The independent variable name must be `t'", (char*) 0);
433  }
434 #else
435  Sprintf(buf, "_save = _break = %s; %s = _sav_indep;\n", indepsym->name, indepsym->name);
436  Insertstr(qsol, buf);
437 #if !SIMSYS
438  Sprintf(buf,
439  "if (_p + _indepindex != &%s) {initmodel(_pp); %s = _sav_indep;}\n",
440  indepsym->name,
441  indepsym->name);
442  Insertstr(qsol, buf);
443 #endif
444 #endif
445 
446  if (called) {
447  Fprintf(stderr,
448  "Warning: More than one integrating SOLVE statement in an \
449 BREAKPOINT block.\nThe simulation will be incorrect if more than one is used \
450 at a time.\n");
451  }
452 #if NMODL
453 #else
454  Sprintf(buf, "if (%s < _break) {\n", indepsym->name);
455  Insertstr(qsol, buf);
456 
457  /* ensure that there are an integer number of steps / break */
458  if (type == DERF) {
459  Sprintf(buf,
460  " { int _nstep; double _dt, _y;\n\
461  _y = _break - %s; _dt = %s;\n",
462  indepsym->name,
463  "dt");
464  Insertstr(qsol, buf);
465  Insertstr(qsol, "_nstep = (int)(_y/_dt + .9);\n if (_nstep==0) _nstep = 1;\n");
466  Sprintf(buf, "%s = _y/((double)_nstep);\n", "dt");
467  Insertstr(qsol, buf);
468  Sprintf(buf, "\n }\n");
469  Insertstr(qsol, buf);
470  }
471 
472  if (type == DERF) {
473  Sprintf(buf, "_break -= .5* %s;\n", "dt");
474  Insertstr(qsol, buf);
475  }
476 #endif
477 #if NMODL
478  /* no longer a for loop */
479 #else
480  Sprintf(buf, "for (; %s < _break; %s += %s) {\n", indepsym->name, indepsym->name, cp);
481  Insertstr(qsol, buf);
482  /* close the while loop; note that integrators have been called */
483  if (type == DERF) {
484  Sprintf(buf, "\n}}\n %s = _save;\n", indepsym->name);
485  } else if (type == DISCRETE) {
486  Sprintf(buf, "\n}}\n");
487  }
488  Insertstr(qsol->next, buf);
489 #endif
490  if (!called) {
491  /* fix up initmodel as per 3) above.
492  In cout.c _save is declared */
493 #if NMODL
494  Sprintf(buf, " _save = %s;\n %s = 0.0;\n", indepsym->name, indepsym->name);
495  saveindep = stralloc(buf, (char*) 0);
496 #else
497  Sprintf(buf, "%s0", indepsym->name);
499  Sprintf(buf, " _save = %s;\n %s = %s0;\n", indepsym->name, indepsym->name, indepsym->name);
500  saveindep = stralloc(buf, (char*) 0);
501 #endif
502  /* Assert no more additions to initfunc involving
503  the value of time */
504  Sprintf(buf, " _sav_indep = %s; %s = _save;\n", indepsym->name, indepsym->name);
506 #if VECTORIZE
508 #endif
509  }
510  called++;
511 }
512 
513 /* steady state consistency means that KINETIC blocks whenever solved must
514 invoke same integrator (default is advance) and DERIVATIVE blocks whenever
515 solved must invoke the derivimplicit method.
516 */
517 void check_ss_consist(Item* qchk) {
518  Item* q;
519  Symbol *fun, *method;
520 
521  ITERATE(q, solvq) {
522  fun = SYM(ITM(q));
523  if (fun == SYM(qchk)) {
524  method = SYM(q->next);
525  switch (q->itemtype) {
526  case DERF:
527  if (!method || strcmp("derivimplicit", method->name) != 0) {
528  diag(
529  "STEADYSTATE requires all SOLVE's of this DERIVATIVE block to use the\n\
530 `derivimplicit' method:",
531  fun->name);
532  }
533  break;
534  case KINF:
535  if (SYM(qchk->next) != method || (method && strcmp("sparse", method->name) != 0)) {
536  diag(
537  "STEADYSTATE requires all SOLVE's of this KINETIC block to use the\n\
538 same method (`advance' or `sparse'). :",
539  fun->name);
540  }
541  break;
542  default:
543  diag("STEADYSTATE only valid for SOLVEing a KINETIC or DERIVATIVE block:",
544  fun->name);
545  break;
546  }
547  }
548  q = q->next->next;
549  }
550 }
short type
Definition: cabvars.h:9
void solv_diffeq(Item *qsol, Symbol *fun, Symbol *method, int numeqn, int listnum, int steadystate, int btype)
Definition: deriv.cpp:42
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)
void add_deriv_imp_list(char *name)
Definition: deriv.cpp:440
void init_disc_vars()
Definition: discrete.cpp:132
static int first
Definition: fmenu.cpp:190
#define diag(s)
Definition: fmenu.cpp:192
Symbol * ifnew_parminstall(char *name, char *num, char *units, char *limits)
Definition: parsact.cpp:174
char buf[512]
Definition: init.cpp:13
#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 SYM0
Definition: model.h:74
#define LINF
Definition: model.h:126
#define ITERATE(itm, lst)
Definition: model.h:25
#define DISCF
Definition: model.h:128
#define SYMBOL
Definition: model.h:102
#define Linsertstr
Definition: model.h:243
#define Lappendstr
Definition: model.h:245
#define ITEM0
Definition: model.h:22
#define Insertstr
Definition: model.h:240
#define PARF
Definition: model.h:130
#define ITM(q)
Definition: model.h:88
#define IGNORE(arg)
Definition: model.h:247
#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 NLINF
Definition: model.h:127
#define PROCED
Definition: model.h:120
#define Fprintf
Definition: model.h:234
NMODL parser global flags / functions.
List * initfunc
Definition: init.cpp:8
List * procfunc
Definition: init.cpp:9
char * name
Definition: init.cpp:16
Item * linsertstr(List *list, char *str)
Definition: list.cpp:130
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 * stralloc(char *buf, char *rel)
Definition: list.cpp:184
Item * next(Item *item)
Definition: list.cpp:88
List * newlist()
Definition: list.cpp:47
Item * lappendsym(List *list, Symbol *sym)
Definition: list.cpp:142
#define fprintf
Definition: mwprefix.h:30
int vectorize
int netrec_state_count
int netrec_need_thread
Symbol * deltaindep
Definition: solve.cpp:11
void save_dt(Item *q)
Definition: solve.cpp:356
void solvequeue(Item *q1, Item *q2, int blocktype, Item *qerr)
Definition: solve.cpp:40
char * current_line()
Definition: io.cpp:217
List * indeplist
Definition: parsact.cpp:15
int numlist
Definition: solve.cpp:38
void check_ss_consist(Item *)
Definition: solve.cpp:517
List * massage_list_
Definition: deriv.cpp:19
void solvhandler()
Definition: solve.cpp:133
void whileloop(Item *, long, int)
Definition: solve.cpp:375
char * saveindep
Definition: solve.cpp:373
static List * solvq
Definition: solve.cpp:37
Symbol * indepsym
Definition: declare.cpp:11
void solv_partial(Item *qsol, Symbol *fun)
Definition: partial.cpp:84
void single_channel(Item *qsol, Symbol *fun, int numeqn, int listnum)
void vectorize_substitute(Item *q, char *str)
void sens_nonlin_out(Item *q, Symbol *fun)
Definition: sens.cpp:388
void cvode_valid()
void cvode_kinetic(Item *qsol, Symbol *fun, int numeqn, int listnum)
void cvode_interface(Symbol *fun, int num, int neq)
void solv_lineq(Item *qsol, Symbol *fun, Symbol *method, int numeqn, int listnum)
Definition: simultan.cpp:27
void solv_nonlin(Item *qsol, Symbol *fun, Symbol *method, int numeqn, int listnum)
Definition: simultan.cpp:12
size_t q
static double remove(void *v)
Definition: ocdeck.cpp:207
virtual void move(const Event &e)
Definition: ocinput.h:26
#define lookup
Definition: redef.h:90
#define follow
Definition: redef.h:61
Definition: model.h:15
struct Item * prev
Definition: model.h:20
void * element
Definition: model.h:18
short itemtype
Definition: model.h:16
struct Item * next
Definition: model.h:19
Definition: model.h:57
int i
Definition: model.h:62
long subtype
Definition: model.h:59
union Symbol::@18 u
char * name
Definition: model.h:72
int used
Definition: model.h:65