NEURON
deriv.cpp
Go to the documentation of this file.
1 #include <../../nmodlconf.h>
2 
3 #include "modl.h"
4 #include "symbol.h"
5 #include "../oc/nrnassrt.h"
6 #include <ctype.h>
7 #undef METHOD
8 #include "parse1.hpp"
9 
10 static List* deriv_imp_list; /* list of derivative blocks that were
11  translated in form suitable for the derivimplicit method */
12 static char Derivimplicit[] = "derivimplicit";
13 
14 extern Symbol* indepsym;
15 extern List* indeplist;
16 extern int sens_parm, numlist;
18 void copylist(List*, Item*);
21 
22 /* SmallBuf size */
23 #undef SB
24 #define SB 256
25 
26 #if VECTORIZE
27 extern int vectorize;
28 extern int assert_threadsafe;
29 extern int thread_data_index;
32 #endif
33 
34 #if CVODE
35 extern char *cvode_deriv(), *cvode_eqnrhs();
36 extern Item* cvode_cnexp_solve;
37 void cvode_diffeq(Symbol* ds, Item* qbegin, Item* qend);
38 static List *cvode_diffeq_list, *cvode_eqn;
39 static int cvode_cnexp_possible;
40 #endif
41 
42 void solv_diffeq(Item* qsol,
43  Symbol* fun,
44  Symbol* method,
45  int numeqn,
46  int listnum,
47  int steadystate,
48  int btype) {
49  char *maxerr_str, dindepname[256];
50  char deriv1_advance[256], deriv2_advance[256];
51  char ssprefix[8];
52 
53  if (method && strcmp(method->name, "cnexp") == 0) {
54  sprintf(buf, " %s();\n", fun->name);
55  replacstr(qsol, buf);
56  sprintf(buf, " %s(_p, _ppvar, _thread, _nt);\n", fun->name);
58  return;
59  }
60  if (steadystate) {
61  Strcpy(ssprefix, "_ss_");
62  } else {
63  Strcpy(ssprefix, "");
64  }
65  Sprintf(dindepname, "d%s", indepsym->name);
66  if (fun->subtype & KINF) { /* translate the kinetic equations */
67  /* can be standard integrator, full matrix advancec, or
68  sparse matrix advance */
69  /* at this time only sparse and standard exists */
70  if (method->subtype & DERF) {
71  kinetic_intmethod(fun, method->name);
72  } else {
73  kinetic_implicit(fun, dindepname, method->name);
74  }
75  }
76  save_dt(qsol);
77  if (method->subtype & DERF) {
78  if (method->u.i == 1) { /* variable step method */
79  maxerr_str = ", maxerr";
80  IGNORE(ifnew_parminstall("maxerr", "1e-5", "", ""));
81  } else {
82  maxerr_str = "";
83  }
84 
85  if (deriv_imp_list) { /* make sure deriv block translation matches method */
86  Item* q;
87  int found = 0;
89  if (strcmp(STR(q), fun->name) == 0) {
90  found = 1;
91  }
92  }
93  if ((strcmp(method->name, Derivimplicit) == 0) ^ (found == 1)) {
94  diag(
95  "To use the derivimplicit method the SOLVE statement must precede the "
96  "DERIVATIVE block\n",
97  " and all SOLVEs using that block must use the derivimplicit method\n");
98  }
99  Sprintf(deriv1_advance, "_deriv%d_advance = 1;\n", listnum);
100  Sprintf(deriv2_advance, "_deriv%d_advance = 0;\n", listnum);
101  Sprintf(buf, "static int _deriv%d_advance = 0;\n", listnum);
102  q = linsertstr(procfunc, buf);
103  Sprintf(buf,
104  "\n#define _deriv%d_advance _thread[%d]._i\n"
105  "#define _dith%d %d\n"
106  "#define _recurse _thread[%d]._i\n"
107  "#define _newtonspace%d _thread[%d]._pvoid\n",
108  listnum,
110  listnum,
111  thread_data_index + 1,
112  thread_data_index + 2,
113  listnum,
114  thread_data_index + 3);
116  Sprintf(buf,
117  " _thread[_dith%d]._pval = (double*)ecalloc(%d, sizeof(double));\n",
118  listnum,
119  2 * numeqn);
121  Sprintf(buf, " _newtonspace%d = nrn_cons_newtonspace(%d);\n", listnum, numeqn);
123  Sprintf(buf, " free((void*)(_thread[_dith%d]._pval));\n", listnum);
125  Sprintf(buf, " nrn_destroy_newtonspace(_newtonspace%d);\n", listnum);
127  thread_data_index += 4;
128  } else {
129  Strcpy(deriv1_advance, "");
130  Strcpy(deriv2_advance, "");
131  }
132  Sprintf(buf,
133  "%s %s%s(_ninits, %d, _slist%d, _dlist%d, _p, &%s, %s, %s, &_temp%d%s);\n%s",
134  deriv1_advance,
135  ssprefix,
136  method->name,
137  numeqn,
138  listnum,
139  listnum,
140  indepsym->name,
141  dindepname,
142  fun->name,
143  listnum,
144  maxerr_str,
145  deriv2_advance);
146  } else {
147  Sprintf(buf,
148  "%s%s(&_sparseobj%d, %d, _slist%d, _dlist%d, _p, &%s, %s, %s\
149 ,&_coef%d, _linmat%d);\n",
150  ssprefix,
151  method->name,
152  listnum,
153  numeqn,
154  listnum,
155  listnum,
156  indepsym->name,
157  dindepname,
158  fun->name,
159  listnum,
160  listnum);
161  }
162  replacstr(qsol, buf);
163 #if VECTORIZE
164  if (method->subtype & DERF) { /* derivimplicit */
165  Sprintf(buf,
166  "%s %s%s_thread(%d, _slist%d, _dlist%d, _p, %s, _ppvar, _thread, _nt);\n%s",
167  deriv1_advance,
168  ssprefix,
169  method->name,
170  numeqn,
171  listnum,
172  listnum,
173  fun->name,
174  deriv2_advance);
175  vectorize_substitute(qsol, buf);
176  } else { /* kinetic */
177  if (vectorize) {
178  Sprintf(buf,
179  "%s%s_thread(&_thread[_spth%d]._pvoid, %d, _slist%d, _dlist%d, _p, &%s, %s, %s\
180 , _linmat%d, _ppvar, _thread, _nt);\n",
181  ssprefix,
182  method->name,
183  listnum,
184  numeqn,
185  listnum,
186  listnum,
187  indepsym->name,
188  dindepname,
189  fun->name,
190  listnum);
191  vectorize_substitute(qsol, buf);
192  }
193 #endif
194  }
197  " if (secondorder) {\n"
198  " int _i;\n"
199  " for (_i = 0; _i < %d; ++_i) {\n"
200  " _p[_slist%d[_i]] += dt*_p[_dlist%d[_i]];\n"
201  " }}\n",
202  numeqn,
203  listnum,
204  listnum);
205  insertstr(qsol->next, buf);
206 }
207 
208 /* addition of higher order derivatives
209  User appearance:
210 Higher order derivatives are now allowed in DERIVATIVE blocks.
211 The number of primes following a variable is the order of the derivative.
212 For example, y'''' is a 4th order derivative.
213 The highest derivative of a state
214 must appear on the left hand side of the equation. Lower order derivatives
215 of a state (including the state itself) may appear on the right hand
216 side within an arbitrary expression. It makes no sense, in general,
217 to have multiple equations involving the same state on the left hand side.
218 The most common usage will be equations of the form
219  y'' = f(y, y', t)
220 
221 Higher derivatives can be accessed in SCoP as
222 y' Dy
223 y'' D2y
224 y''' D3y
225 etc. Note that all derivatives except the highest derivative are themselves
226 states on an equal footing with y. E.G. they can be used within
227 a MATCH block, they can be explicitly declared within a STATE block (and
228 given START values), and they have associated initial value constants.
229 Initial values default to 0. Here is a complicated example which
230 shows off the syntax (I have no idea if the solution exists).
231  INDEPENDENT {t FROM 0 TO 1 WITH 1}
232  STATE {x y
233  y' START 1
234  x' START -10
235  }
236  DERIVATIVE d {
237  x''' = y + 3*x''*y' + sin(x') + exp(x)
238  y'' = cos(x'' + y) - y'
239  MATCH { y0 y(1)=1
240  x(1)=1 Dx0 x''(1)=0
241  }
242  EQUATION {SOLVE d}
243 Note that we had to use Dx0 since x'0 is illegal. Also Dx0 has a
244 value of -10.
245 
246 Implementation :
247  In parse1.ypp we see that asgn: varname '=' expr and that
248  varname gets marked if it is type PRIME. With respect to
249  higher order derivatives, therefore, only the highest order
250  actually used in the equations in that block
251  should be marked. Furthermore these highest primes may or may not be
252  dependent variables and the lesser primes must be created as states.
253  We use a special iterator FORALL which returns each lesser order
254  symbol given a dstate.
255 
256  The implicit equations of the form DD2y = D3y do not have to
257  be constructed and the dependent variables DD2y do not have to
258  be created since the slist and dlist links can carry this
259  information. Thus dlist[D2y] == slist[D3y] causes the integrators
260  to do the right thing without, in fact, doing any arithmetic.
261  We assume that the itegrators either save the *dlist values or
262  update *slist using a loop running from 0 to N. This is why
263  the FORALL interator returns states starting with the base state
264  (so that *slist[i+1] doesn't change until after *dlist[i] is used.
265  (they point to the same value). In the case of a second order
266  equation, the lists are:
267  slist[0] = &y dlist[0] = &Dy
268  slist[1] = &Dy dlist[1] = &D2y
269 
270  With respect to the MATCH process
271  the code which unmarks the PRIMES and marks the corresponding state
272  is inadequate since several states must be marked some of which
273  are PRIME. For this reason we distinguish using a -1 to mark states
274  for later counting.
275 
276  The array problem is solved by using lex to:
277  when a PRIME is seen, check against the base state. If the base
278  state doesn't exist don't worry. If the STATE is an array
279  Then make PRIME an array of the same dimension.
280 
281  depinstall automattically creates a Dstate for each state
282  passed to it as well as a state0 (optional). This is OK since
283  they dissappear if unused.
284 
285 
286 */
287 
288 #define FORALL(state, dstate) for (state = init_forderiv(dstate); state; state = next_forderiv())
289 /* This returns all states of lower order than dstate in the order of
290 base state first. Will install PRIME if necessary.
291 */
292 static Symbol* forderiv; /* base state */
293 static char base_units[256]; /*base state units */
294 static int indx, maxindx; /* current indx, and indx of dstate */
295 
296 static Symbol* init_forderiv(Symbol* prime) {
297  char name[256];
298  double d1, d2;
299 
300  assert(prime->type == PRIME);
301  /*extract maxindx and basename*/
302  if (isdigit(prime->name[1])) { /* higher than 1 */
303  if (sscanf(prime->name + 1, "%d%s", &maxindx, name) != 2) {
304  diag("internal error in init_forderiv in init.c", (char*) 0);
305  }
306  } else {
307  maxindx = 1;
308  Strcpy(name, prime->name + 1);
309  }
310  forderiv = lookup(name);
311  if (!forderiv || !(forderiv->subtype & STAT)) {
312  diag(name, "must be declared as a state variable");
313  }
314  if (forderiv->araydim != prime->araydim) {
315  Sprintf(buf, "%s and %s have different dimensions", forderiv->name, prime->name);
316  diag(buf, (char*) 0);
317  }
318  indx = 0;
319  decode_ustr(forderiv, &d1, &d2, base_units);
320  return forderiv;
321 }
322 
323 static char* name_forderiv(int i) {
324  static char name[256];
325 
326  assert(i > 0 && forderiv);
327  if (i > 1) {
328  Sprintf(name, "D%d%s", i, forderiv->name);
329  } else {
330  Sprintf(name, "D%s", forderiv->name);
331  }
332  return name;
333 }
334 
335 /* Scop can handle 's so we put the prime style names into the .var file.
336 We make use of the tools here to reconstruct the original prime name.
337 */
338 char* reprime(Symbol* sym) {
339  static char name[256];
340  int i;
341  char* cp;
342 
343  if (sym->type != PRIME) {
344  Strcpy(name, sym->name);
345  return name;
346  }
347 
348  IGNORE(init_forderiv(sym));
349 
351  cp = name + strlen(name);
352  for (i = 0; i < maxindx; i++) {
353  *cp++ = '\'';
354  }
355  *cp = '\0';
356  return name;
357 }
358 
360  char* name;
361  Symbol* s;
362  char units[SB];
363 
364  if (++indx >= maxindx) {
365  return SYM0;
366  }
368  if ((s = lookup(name)) == SYM0) {
369  s = install(name, PRIME);
370  nrn_assert(snprintf(units, SB, "%s/%s^%d", base_units, STR(indeplist->prev), indx) < SB);
371  depinstall(1, s, forderiv->araydim, "0", "1", units, ITEM0, 1, "");
372  s->usage |= DEP;
373  }
374  if (s->araydim != forderiv->araydim) {
375  diag(s->name, "must have same dimension as associated state");
376  }
377  if (!(s->subtype & STAT)) { /* Dstate changes to state */
378  nrn_assert(snprintf(units, SB, "%s/%s^%d", base_units, STR(indeplist->prev), indx) < SB);
379  s->subtype &= ~DEP;
380  depinstall(1, s, forderiv->araydim, "0", "1", units, ITEM0, 1, "");
381  depinstall(1, s, forderiv->araydim, "0", "1", units, ITEM0, 1, "");
382  s->usage |= DEP;
383  }
384  return s;
385 }
386 
387 /* mixed derivative and nonlinear equations */
388 /* Implementation:
389  The main requirement is to distinguish between the states which
390  have derivative specifications and the states which are solved
391  for by the nonlinear equations. We do this by having the
392  left hand side derivative saved in a list instead of marking the
393  variables in the used field. See deriv_used(). States seen in the
394  nonlinear equations are marked as usual. To leave only nonlinear
395  states marked we then cast out any lesser state which is marked.
396  (eg if y''=.. then y and y' cannot be states of the nonlinear equation).
397  The former version also made use of state->used = -1 for match
398  purposes. We replace this usage with a list of states of the
399  derivatives. This means that the derivative block with respect to
400  derivative equations no longer uses the used field.
401 
402  To avoid copying the block we (albeit resulting is somewhat poorer
403  efficiency) we allow the block to call newton and pass itself as
404  an argument. A flag tells the block if its call was by newton or by
405  an integrator. My guess is this will still work with match, sens, and
406  array states.
407 */
408 
409 /* derivative equations (and possibly some nonlinear equations) solved
410  with an implicit method */
411 /* Implementation:
412  Things are starting to get a little bit out of conceptual control.
413  We make use of the mixed case, except that the number of nonlinear
414  equations may be 0. The substantive change is that now the number
415  of equations is the sum of the derivatives and the nonlinears and the
416  extra equations added into the block are of the form
417  dlist2[++_counte] = Dstate - (state - statesave1[0])/dt;
418  The administrative needs are that newton is called with the total number
419  of equations and that we can match state and statesave. Notice that we
420  already have two sets of slists floating around and one dlist,
421  currently they are the
422  slist and dlist for the derivative state and state'
423  and the slist for the nonlinear states (the corresponding dlist is just
424  the rhs of the equations). Clearly, statesave should be associated
425  with the derivative slist and will be in that order, then the slist for
426  newton will be expanded by not resetting the used field.
427  The biggest conceptual problem is how to generate the code at the time
428  we handle the SOLVE since the actual numbers for the declarations
429  of the newton slists depend on the method.
430  Here, we assume a flag, deriv_implicit, which tells us which code to
431  generate. Whether this means that we must look through the .mod file
432  for all the SOLVE statements or whether all this stuff is saved for
433  calling from the solve handler as in the kinetic block is not specified
434  yet.
435  For now, we demand that the SOLVE statement be seen first if it
436  invokes the derivimplicit method. Otherwise modl generates an error
437  message.
438 */
439 
441  if (!deriv_imp_list) {
443  }
445 }
446 
447 static List* deriv_used_list; /* left hand side derivatives of diffeqs */
448 static List* deriv_state_list; /* states of the derivative equations */
449 
450 void deriv_used(Symbol* s, Item* q1, Item* q2) /* q1, q2 are begin and end tokens for expression */
451 {
452  if (!deriv_used_list) {
455  }
457 #if CVODE
458  if (!cvode_diffeq_list) {
459  cvode_diffeq_list = newlist();
460  }
461  lappendsym(cvode_diffeq_list, s);
462  lappenditem(cvode_diffeq_list, q1);
463  lappenditem(cvode_diffeq_list, q2);
464 #endif
465 }
466 
467 static int matchused = 0; /* set when MATCH seen */
468 /* args are --- derivblk: DERIVATIVE NAME stmtlist '}' */
469 void massagederiv(Item* q1, Item* q2, Item* q3, Item* q4, int sensused) {
470  int count = 0, deriv_implicit, solve_seen;
471  char units[SB];
472  Item *qs, *q, *mixed_eqns(Item * q2, Item * q3, Item * q4);
473  Symbol *s, *derfun, *state;
474 
475  /* to allow verification that definition after SOLVE */
476  if (!massage_list_) {
478  }
480 
481  /* all this junk is still in the intoken list */
482  Sprintf(buf, "static int %s(_threadargsproto_);\n", SYM(q2)->name);
484  replacstr(q1, "\nstatic int");
485  q = insertstr(q3, "() {_reset=0;\n");
486  derfun = SYM(q2);
488  "(double* _p, Datum* _ppvar, Datum* _thread, NrnThread* _nt) {int "
489  "_reset=0; int error = 0;\n");
490 
491  if (derfun->subtype & DERF && derfun->u.i) {
492  diag("DERIVATIVE merging not implemented", (char*) 0);
493  }
494 
495  /* check if we are to translate using derivimplicit method */
496  deriv_implicit = 0;
497  if (deriv_imp_list)
499  if (strcmp(derfun->name, STR(q)) == 0) {
500  deriv_implicit = 1;
501  break;
502  }
503  }
504  numlist++;
505  derfun->u.i = numlist;
506  derfun->subtype |= DERF;
507  if (!deriv_used_list) {
508  diag("No derivative equations in DERIVATIVE block", (char*) 0);
509  }
510  ITERATE(qs, deriv_used_list) {
511  s = SYM(qs);
512  if (!(s->subtype & DEP) && !(s->subtype & STAT)) {
513  IGNORE(init_forderiv(s));
514  nrn_assert(snprintf(units, SB, "%s/%s^%d", base_units, STR(indeplist->prev), maxindx) >
515  SB);
516  depinstall(0, s, s->araydim, "0", "1", units, ITEM0, 0, "");
517  }
518  /* high order: make sure
519  no lesser order is marked, and all lesser
520  orders exist as STAT */
521  FORALL(state, s) {
522  if (state->type == PRIME) {
523  ITERATE(q, deriv_used_list) if (state == SYM(q)) {
524  diag(state->name,
525  ": Since higher derivative is being used, this state \
526 is not allowed on the left hand side.");
527  }
528  }
530  if (sensused) {
531  add_sens_statelist(state);
532  state->varnum = count;
533  }
534 #if CVODE
535  slist_data(state, count, numlist);
536 #endif
537  if (s->subtype & ARRAY) {
538  int dim = s->araydim;
539  Sprintf(buf,
540  "for(_i=0;_i<%d;_i++){_slist%d[%d+_i] = %s_columnindex + _i;",
541  dim,
542  numlist,
543  count,
544  state->name);
546  Sprintf(buf,
547  " _dlist%d[%d+_i] = %s_columnindex + _i;}\n",
548  numlist,
549  count,
550  name_forderiv(indx + 1));
552  count += dim;
553  } else {
554  Sprintf(buf, "_slist%d[%d] = %s_columnindex;", numlist, count, state->name);
556  Sprintf(buf,
557  " _dlist%d[%d] = %s_columnindex;\n",
558  numlist,
559  count,
560  name_forderiv(indx + 1));
562  count++;
563  }
564  }
565  }
566  if (count == 0) {
567  diag("DERIVATIVE contains no derivatives", (char*) 0);
568  }
569  derfun->used = count;
570  Sprintf(buf,
571  "static int _slist%d[%d], _dlist%d[%d];\n",
572  numlist,
573  count * (1 + 2 * sens_parm),
574  numlist,
575  count * (1 + 2 * sens_parm));
577 
578 #if CVODE
579  Lappendstr(procfunc, "\n/*CVODE*/\n");
580  Sprintf(buf, "static int _ode_spec%d", numlist);
582  {
583  Item* qq = procfunc->prev;
584  copyitems(q1->next, q4, procfunc->prev);
586  qq->next,
587  "(double* _p, Datum* _ppvar, Datum* _thread, NrnThread* _nt) {int _reset = 0;");
589  }
590  lappendstr(procfunc, "return _reset;\n}\n");
591 
592  /* don't emit _ode_matsol if the user has defined cvodematsol */
593  if (!lookup("cvodematsol")) {
594  Item* qq;
595  Item* qextra = q1->next->next->next->next;
596  Sprintf(buf, "static int _ode_matsol%d", numlist);
599  "(double* _p, Datum* _ppvar, Datum* _thread, NrnThread* _nt) {\n");
600  qq = procfunc->next;
601  cvode_cnexp_possible = 1;
602  ITERATE(q, cvode_diffeq_list) {
603  Symbol* s;
604  Item *q1, *q2;
605  s = SYM(q);
606  q = q->next;
607  q1 = ITM(q);
608  q = q->next;
609  q2 = ITM(q);
610 #if 1
611  while (qextra != q1) { /* must first have any intervening statements */
612  switch (qextra->itemtype) {
613  case STRING:
614  Lappendstr(procfunc, STR(qextra));
615  break;
616  case SYMBOL:
617  Lappendsym(procfunc, SYM(qextra));
618  break;
619  }
620  qextra = qextra->next;
621  }
622 #endif
623  cvode_diffeq(s, q1, q2);
624  qextra = q2->next;
625  }
626 #if 1
627  /* if we are not at the end, there is more extra */
628  while (qextra != q4) {
629  switch (qextra->itemtype) {
630  case STRING:
631  Lappendstr(procfunc, STR(qextra));
632  break;
633  case SYMBOL:
634  Lappendsym(procfunc, SYM(qextra));
635  break;
636  }
637  qextra = qextra->next;
638  }
639 #endif
640  Lappendstr(procfunc, " return 0;\n}\n");
642  }
643 
644  Lappendstr(procfunc, "/*END CVODE*/\n");
645  if (cvode_cnexp_solve && cvode_cnexp_success(q1, q4)) {
648  return;
649  }
650 #endif
651  if (deriv_implicit) {
652  Sprintf(buf,
653  "static double _savstate%d[%d], *_temp%d = _savstate%d;\n",
654  numlist,
655  count * (1 + 2 * sens_parm),
656  numlist,
657  numlist);
658  q = linsertstr(procfunc, buf);
659  vectorize_substitute(q, "");
660  } else {
661  Sprintf(buf, "static double *_temp%d;\n", numlist);
663  }
664  movelist(q1, q4, procfunc);
665  Lappendstr(procfunc, "return _reset;}\n");
666  if (sensused)
667  sensmassage(DERIVATIVE, q2, numlist); /*among other things
668  the name of q2 is changed. ie a new item */
669  if (matchused) {
670  matchmassage(count);
671  }
672  /* reset used field for any states that may appear in
673  nonlinear equations which should not be solved for. */
675  SYM(q)->used = 0;
676  }
677  if (deriv_implicit) {
678  Symbol* sp;
680  SYM(q)->used = 1;
681  }
682  Sprintf(buf,
683  "{int _id; for(_id=0; _id < %d; _id++) {\n\
684 if (_deriv%d_advance) {\n",
685  count,
686  numlist);
687  Insertstr(q4, buf);
688  sp = install("D", STRING);
689  sp->araydim = count; /*this breaks SENS*/
690  q = insertsym(q4, sp);
691  eqnqueue(q);
692  Sprintf(buf,
693  "_p[_dlist%d[_id]] - (_p[_slist%d[_id]] - _savstate%d[_id])/d%s;\n",
694  numlist,
695  numlist,
696  numlist,
697  indepsym->name);
698  Insertstr(q4, buf);
699  Sprintf(buf,
700  "}else{\n_dlist%d[++_counte] = _p[_slist%d[_id]] - _savstate%d[_id];}}}\n",
701  numlist + 1,
702  numlist,
703  numlist);
704  Insertstr(q4, buf);
705  } else {
707  SYM(q)->used = 0;
708  }
709  }
710  /* if there are also nonlinear equations, put in the newton call,
711  create the proper lists and fill in the left hand side of each
712  equation. */
713  q = mixed_eqns(q2, q3, q4); /* numlist now incremented */
714  if (deriv_implicit) {
715  Sprintf(buf,
716  "{int _id; for(_id=0; _id < %d; _id++) { _savstate%d[_id] = _p[_slist%d[_id]];}}\n",
717  count,
718  derfun->u.i,
719  derfun->u.i);
720  Insertstr(q, buf);
721  }
722 
725 }
726 
727 static List* match_init; /* list of states for which initial values
728  are known. */
729 List* match_bound; /* list of triples or quadruples.
730  First is the state symbol.
731  Second is a string giving the matchtime
732  expression. Third is a string giving the
733  matchtarget expression
734  Fourth is the loop index string if the state
735  is an array*/
736 /* if non null then cout.c will put proper
737 call at end of initmodel() */
738 
739 /* note that the number of states in match_init plus the number of states
740 in match_bound must be equal to the number of differential equations */
741 /* we limit ourselves to one matched boundary problem per model */
742 
743 void matchinitial(Item* q1) /* name */
744 {
745  /* must be of form state0. Later we can check if state' is in fact
746  used. Save the state symbol in the initialvalue matchlist */
747  Symbol *s, *state;
748 
749  s = SYM(q1);
750  if ((s->subtype & (PARM | INDEP)) || !(s->subtype)) {
751  /* possibly used before declared */
752  if (s->name[strlen(s->name) - 1] == '0') {
753  Strcpy(buf, s->name);
754  buf[strlen(buf) - 1] = '\0';
755  state = lookup(buf);
756  if ((state && (state->subtype & STAT)) || (state->type == PRIME)) {
757  Lappendsym(match_init, state);
758  return;
759  }
760  }
761  }
762  diag(s->name, "must be an initial state parameter");
763  return;
764 }
765 
766 void matchbound(Item* q1, Item* q2, Item* q3, Item* q4, Item* q5, Symbol* sindex) /* q1name q2'('
767  q3')' '='
768  q4exprq5 */
769 {
770  /* q1 must be a state */
771  Symbol* state;
772  Item* q;
773  List* l;
774 
775  state = SYM(q1);
776  if (!(state->subtype & STAT) && state->type != PRIME) {
777  diag(state->name, "is not a state");
778  }
779  if ((state->subtype & ARRAY) && !sindex) {
780  diag(state->name, "must have an index for the implicit loop");
781  }
782  if (!(state->subtype & ARRAY) && sindex) {
783  diag(state->name, "is not an array");
784  }
785 
786  Lappendsym(match_bound, state);
787 
789  l = newlist();
790  movelist(q2, q3, l);
791  LST(q) = l;
792 
794  l = newlist();
795  movelist(q4, q5, l);
796  LST(q) = l;
797 
798  if (sindex) {
799  Lappendstr(match_bound, sindex->name);
800  }
801 }
802 
803 void checkmatch(int blocktype) {
804  if (blocktype != DERIVATIVE) {
805  diag("MATCH block can only be in DERIVATIVE block", (char*) 0);
806  }
807  matchused = 1; /*communicate with massagederiv*/
808  if (match_bound || match_init) {
809  diag("Only one MATCH block allowed", (char*) 0);
810  }
811  if (!indepsym) {
812  diag("INDEPENDENT variable must be declared before MATCH", "statement");
813  }
814  match_bound = newlist();
815  match_init = newlist();
816 }
817 
818 void matchmassage(int nderiv) {
819  int count, nunknown, j;
820  Item *q, *q1, *setup;
821  Symbol* s;
822  List *tmatch, *vmatch;
823  char* imatch;
824 
825  matchused = 0;
826  /* we have a list of states at which the initial values are known
827  and a list of information about state(time) = match with implicit loop
828  index if array.
829 
830  check that the total number of conditions = nderiv.
831  the number of unknown initial conditions is the complement of the
832  states which have known initial conditions ( the number of states
833  in the match_bound list. Note that the complement of match_init
834  states is NOT the list of states in match_bound.
835 
836  We create
837  1) array of doubles which will receive the values of
838  the found initial conditions. (_found_init)
839  2) array of doubles which receives the match times
840  3) array of doubles which receives the match values
841  4) array of state pointers(state_match). we solve
842  *statematch(matchtime) = matchvalue
843  5) array of state pointers(state_get). We initialize with
844  *state_get = _found_init
845  6) since 2, 3, 4 must be sorted according to match times we
846  create pointer arrays to 2 and 3 and pass those.
847  7) Spec of shoot requires the passing of pointer array to
848  found_init.
849 
850 
851  At this time I don't know how this can be restarted.
852 
853  Initmodel() calls _initmatch() which
854  1) if first=1 then sets first=0
855  sets up match times, match values, initializes
856  _found_init, calls shoot(), calls initmodel(),
857  sets first = 1 and exits.
858  2) if first=0 then put _found_init into states and exit.
859 
860  Call to _initmatch must be the last thing done in initmodel() in
861  case the user desires to give good starting initial values to
862  help shoot().
863  */
864 
865  count = 0;
866 
867  ITERATE(q, match_init) { /* these initializations are done
868  automatically by initmodel(), so just remove the state
869  from the deriv_state_list */
870  s = SYM(q);
872  if (SYM(q1) == s) {
873  remove(q1);
874  break;
875  }
876  }
877  if (!(s->subtype & STAT)) {
878  diag(s->name, "is not a state");
879  }
880  if (s->subtype & ARRAY) {
881  count += s->araydim;
882  } else {
883  count++;
884  }
885  }
886  nunknown = nderiv - count;
887  if (nunknown <= 0) {
888  diag("Nothing to match", (char*) 0);
889  }
890  /* the ones that are still marked are the ones to solve for */
891 
892  /* add the boilerplate for _initmatch and save the location
893  where model specific info goes.
894  */
895  Lappendstr(
896  procfunc,
897  "\n_init_match(_save) double _save;{ int _i;\nif (_match_recurse) {_match_recurse = 0;\n");
898  Sprintf(buf, "for (_i=0; _i<%d; _i++) _found_init[_i] = _p[_state_get[_i]];\n", nunknown);
899  setup = lappendstr(procfunc, buf);
900  Sprintf(buf,
901  "error=shoot(%d, &(%s) - _p, _pmatch_time, _pmatch_value, _state_match,\
902  _found_init, _p, &(d%s));\n if(error){abort_run(error);}; %s = _save;",
903  nunknown,
904  indepsym->name,
905  indepsym->name,
906  indepsym->name);
907  /*deltaindep may not be declared yet */
909  Lappendstr(procfunc, "\n initmodel(_p); _match_recurse = 1;\n}\n");
910  Sprintf(buf, "for (_i=0; _i<%d; _i++) _p[_state_get[_i]] = _found_init[_i];", nunknown);
912  Lappendstr(procfunc, "\n}\n\n");
913 
914  /* construct _state_get from the marked states */
915  j = 0;
916 
918  s = SYM(q);
919  if (s->subtype & ARRAY) {
920  Sprintf(buf,
921  "for (_i=0; _i<%d; _i++) {_state_get[%d+_i] = %s_columnindex + _i;}\n",
922  s->araydim,
923  j,
924  s->name);
925  j += s->araydim;
926  } else {
927  Sprintf(buf, "_state_get[%d] = %s_columnindex;\n", j, s->name);
928  j++;
929  }
931  }
932  /* declare the arrays */
933  Sprintf(buf,
934  "static int _state_get[%d], _state_match[%d];\n\
935 static double _match_time[%d], _match_value[%d], _found_init[%d];\n",
936  nunknown,
937  nunknown,
938  nunknown,
939  nunknown,
940  nunknown);
942  Sprintf(buf, "static double *_pmatch_time[%d], *_pmatch_value[%d];\n", nunknown, nunknown);
944 
945  /* create the _state_match stuff */
946  j = 0;
947  ITERATE(q, match_bound) {
948  s = SYM(q);
949  if (!(s->subtype & STAT)) {
950  diag(s->name, "is not a state");
951  }
952  tmatch = LST(q = q->next);
953  vmatch = LST(q = q->next);
954  if (s->subtype & ARRAY) {
955  imatch = STR(q = q->next);
956  Sprintf(buf,
957  "for (_i=0; _i<%d; _i++) {_state_match[%d+_i] = %s_columnindex + _i;}\n",
958  s->araydim,
959  j,
960  s->name);
962  Sprintf(buf,
963  "{int %s; for (%s=0; %s<%d; %s++) {\n",
964  imatch,
965  imatch,
966  imatch,
967  s->araydim,
968  imatch);
969  Insertstr(setup, buf);
970  Sprintf(buf, "_match_time[%s + %d] = ", imatch, j);
971  Insertstr(setup, buf);
972  copylist(tmatch, setup);
973  Sprintf(buf, ";\n _match_value[%s + %d] = ", imatch, j);
974  Insertstr(setup, buf);
975  copylist(vmatch, setup);
976  Insertstr(setup, ";\n}}\n");
977  j += s->araydim;
978  count += s->araydim;
979  } else {
980  Sprintf(buf, "_state_match[%d] = %s_columnindex;\n", j, s->name);
982  Sprintf(buf, "_match_time[%d] = ", j);
983  Insertstr(setup, buf);
984  copylist(tmatch, setup);
985  Sprintf(buf, ";\n _match_value[%d] = ", j);
986  Insertstr(setup, buf);
987  copylist(vmatch, setup);
988  Insertstr(setup, ";\n");
989  j++;
990  count++;
991  }
992  }
993  /* set up the trivial pointer arrays */
994  Sprintf(buf, "for(_i=0; _i<%d; _i++) { _pmatch_time[_i] = _match_time + _i;\n", nunknown);
996  Lappendstr(initlist, "_pmatch_value[_i] = _match_value + _i;\n }\n");
997  if (count != nderiv) {
998  Sprintf(buf, "%d equations != %d MATCH specs", nderiv, count);
999  diag(buf, (char*) 0);
1000  }
1001 }
1002 
1003 
1004 void copylist(List* l, Item* i) /* copy list l before item i */
1005 {
1006  Item* q;
1007 
1008  ITERATE(q, l) {
1009  switch (q->itemtype) {
1010  case STRING:
1011  Insertstr(i, STR(q));
1012  break;
1013  case SYMBOL:
1014  Insertsym(i, SYM(q));
1015  break;
1016  default:
1017  /*SUPPRESS 622*/
1018  assert(0);
1019  }
1020  }
1021 }
1022 
1023 void copyitems(Item* q1, Item* q2, Item* qdest) /* copy items before item */
1024 {
1025  Item* q;
1026  for (q = q2; q != q1; q = q->prev) {
1027  switch (q->itemtype) {
1028  case STRING:
1029  case VERBATIM:
1030  Linsertstr(qdest, STR(q));
1031  break;
1032  case SYMBOL:
1033  Linsertsym(qdest, SYM(q));
1034  break;
1035  default:
1036  /*SUPPRESS 622*/
1037  assert(0);
1038  }
1039  }
1040 }
1041 
1042 #if CVODE
1043 static int cvode_linear_diffeq(Symbol* ds, Symbol* s, Item* qbegin, Item* qend) {
1044  char* c;
1045  List* tlst;
1046  Item* q;
1047  tlst = newlist();
1048  for (q = qbegin; q != qend->next; q = q->next) {
1049  switch (q->itemtype) {
1050  case SYMBOL:
1051  lappendsym(tlst, SYM(q));
1052  break;
1053  case STRING:
1054  lappendstr(tlst, STR(q));
1055  break;
1056  default:
1057  cvode_cnexp_possible = 0;
1058  return 0;
1059  }
1060  }
1061  cvode_parse(s, tlst);
1062  freelist(&tlst);
1063  c = cvode_deriv();
1064  if (!cvode_eqn) {
1065  cvode_eqn = newlist();
1066  }
1067  lappendsym(cvode_eqn, s);
1068  lappendstr(cvode_eqn, cvode_deriv());
1069  lappendstr(cvode_eqn, cvode_eqnrhs());
1070  if (c) {
1071  lappendstr(procfunc, c);
1072  lappendstr(procfunc, "))");
1073  return 1;
1074  }
1075  cvode_cnexp_possible = 0;
1076  return 0;
1077 }
1078 
1079 /* DState symbol, begin, and end of expression */
1080 void cvode_diffeq(Symbol* ds, Item* qbegin, Item* qend) {
1081  /* try first the assumption of linear. If not, then use numerical diff*/
1082  Symbol* s;
1083  Item* q;
1084 
1085  /* get state symbol */
1086  sscanf(ds->name, "D%s", buf);
1087  s = lookup(buf);
1088  assert(s);
1089 
1090  /* ds/(1. - dt*( */
1091  Lappendsym(procfunc, ds);
1092  Lappendstr(procfunc, " / (1. - dt*(");
1093  if (cvode_linear_diffeq(ds, s, qbegin, qend)) {
1094  return;
1095  }
1096  /* ((expr(s+.001))-(expr))/.001; */
1097  Lappendstr(procfunc, "((");
1098  for (q = qbegin; q != qend->next; q = q->next) {
1099  switch (q->itemtype) {
1100  case STRING:
1101  Lappendstr(procfunc, STR(q));
1102  break;
1103  case SYMBOL:
1104  if (SYM(q) == s) {
1105  Lappendstr(procfunc, "(");
1106  Lappendsym(procfunc, s);
1107  Lappendstr(procfunc, " + .001)");
1108  } else {
1109  Lappendsym(procfunc, SYM(q));
1110  }
1111  break;
1112  default:
1113  assert(0);
1114  }
1115  }
1116  Lappendstr(procfunc, ") - (");
1117  for (q = qbegin; q != qend->next; q = q->next) {
1118  switch (q->itemtype) {
1119  case STRING:
1120  Lappendstr(procfunc, STR(q));
1121  break;
1122  case SYMBOL:
1123  Lappendsym(procfunc, SYM(q));
1124  break;
1125  default:
1126  assert(0);
1127  }
1128  }
1129  Lappendstr(procfunc, " )) / .001 ))");
1130 }
1131 
1132 /*
1133 the cnexp method was requested but the symbol in the solve queue was
1134 changed to derivimplicit and cvode_cnexp_solve holds a pointer to
1135 the solvq item (1st of three).
1136 The 0=f(state) equations have already been solved and the rhs for
1137 each has been saved. So we know if the translation is possible.
1138 */
1139 int cvode_cnexp_success(Item* q1, Item* q2) {
1140  Item *q, *q3, *q4, *qeq;
1141  if (cvode_cnexp_possible) {
1142  /* convert Method to nil and the type of the block to
1143  PROCEDURE */
1144  SYM(cvode_cnexp_solve->next)->name = stralloc("cnexp", 0);
1146 
1147  /* replace the Dstate = f(state) equations */
1148  qeq = cvode_eqn->next;
1149  ITERATE(q, cvode_diffeq_list) {
1150  Symbol* s;
1151  Item *q1, *q2;
1152  char *a, *b;
1153  s = SYM(qeq);
1154  qeq = qeq->next;
1155  a = STR(qeq);
1156  qeq = qeq->next;
1157  b = STR(qeq);
1158  qeq = qeq->next;
1159  q = q->next;
1160  q1 = ITM(q);
1161  q = q->next;
1162  q2 = ITM(q);
1163  if (!netrec_cnexp) {
1164  netrec_cnexp = newlist();
1165  }
1167  if (strcmp(a, "0.0") == 0) {
1168  assert(b[strlen(b) - 9] == '/');
1169  b[strlen(b) - 9] = '\0';
1170  sprintf(buf, " __primary -= 0.5*dt*( %s )", b);
1172  sprintf(buf, " %s = %s - dt*(%s)", s->name, s->name, b);
1173  } else {
1174  sprintf(buf,
1175  " __primary += ( 1. - exp( 0.5*dt*( %s ) ) )*( %s - __primary )",
1176  a,
1177  b);
1179  sprintf(buf,
1180  " %s = %s + (1. - exp(dt*(%s)))*(%s - %s)",
1181  s->name,
1182  s->name,
1183  a,
1184  b,
1185  s->name);
1186  }
1187  insertstr(q2->next, buf);
1188  q2 = q2->next;
1189  for (q3 = q1->prev->prev; q3 != q2; q3 = q4) {
1190  q4 = q3->next;
1191  remove(q3);
1192  }
1193  }
1194 
1195  lappendstr(procfunc, "static int");
1196  {
1197  Item* qq = procfunc->prev;
1198  copyitems(q1, q2, procfunc->prev);
1199  /* more or less redundant with massagederiv */
1201  "(double* _p, Datum* _ppvar, Datum* _thread, NrnThread* _nt) {");
1203  }
1204  lappendstr(procfunc, " return 0;\n}\n");
1205  return 1;
1206  }
1207  fprintf(stderr, "Could not translate using cnexp method; using derivimplicit\n");
1208  return 0;
1209 }
1210 #endif
insertstr(qsol->next, buf)
static int maxindx
Definition: deriv.cpp:294
#define FORALL(state, dstate)
Definition: deriv.cpp:288
static List * deriv_state_list
Definition: deriv.cpp:448
List * match_bound
Definition: deriv.cpp:729
static int matchused
Definition: deriv.cpp:467
void massagederiv(Item *q1, Item *q2, Item *q3, Item *q4, int sensused)
Definition: deriv.cpp:469
char * reprime(Symbol *sym)
Definition: deriv.cpp:338
void solv_diffeq(Item *qsol, Symbol *fun, Symbol *method, int numeqn, int listnum, int steadystate, int btype)
Definition: deriv.cpp:42
static List * deriv_imp_list
Definition: deriv.cpp:10
List * indeplist
Definition: parsact.cpp:15
int dtsav_for_nrn_state
Definition: deriv.cpp:17
void matchbound(Item *q1, Item *q2, Item *q3, Item *q4, Item *q5, Symbol *sindex)
Definition: deriv.cpp:766
#define SB
Definition: deriv.cpp:24
int numlist
Definition: deriv.cpp:16
void matchinitial(Item *q1)
Definition: deriv.cpp:743
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 List * match_init
Definition: deriv.cpp:727
List * massage_list_
Definition: deriv.cpp:19
static Symbol * forderiv
Definition: deriv.cpp:292
static char Derivimplicit[]
Definition: deriv.cpp:12
void copyitems(Item *q1, Item *q2, Item *qdest)
Definition: deriv.cpp:1023
static List * deriv_used_list
Definition: deriv.cpp:447
static int indx
Definition: deriv.cpp:294
static char base_units[256]
Definition: deriv.cpp:293
int sens_parm
Definition: sens.cpp:104
void add_deriv_imp_list(char *name)
Definition: deriv.cpp:440
void copylist(List *, Item *)
Definition: deriv.cpp:1004
static Symbol * next_forderiv()
Definition: deriv.cpp:359
void matchmassage(int nderiv)
Definition: deriv.cpp:818
List * netrec_cnexp
Definition: deriv.cpp:20
Symbol * indepsym
Definition: declare.cpp:11
void checkmatch(int blocktype)
Definition: deriv.cpp:803
static Symbol * init_forderiv(Symbol *prime)
Definition: deriv.cpp:296
void deriv_used(Symbol *s, Item *q1, Item *q2)
Definition: deriv.cpp:450
static char * name_forderiv(int i)
Definition: deriv.cpp:323
#define c
#define diag(s)
Definition: fmenu.cpp:192
#define PARM
Definition: modl.h:190
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
List * thread_cleanup_list
Definition: nocpout.cpp:127
int thread_data_index
Definition: nocpout.cpp:126
void kinetic_intmethod(Symbol *fun, char *meth)
Definition: kinetic.cpp:511
void kinetic_implicit(Symbol *fun, char *dt, char *mname)
Definition: kinetic.cpp:692
#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 STAT
Definition: model.h:117
#define ITERATE(itm, lst)
Definition: model.h:25
#define SYMBOL
Definition: model.h:102
#define Linsertsym
Definition: model.h:242
#define Linsertstr
Definition: model.h:243
#define INDEP
Definition: model.h:115
#define Lappendstr
Definition: model.h:245
#define ITEM0
Definition: model.h:22
#define Insertstr
Definition: model.h:240
#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 Insertsym
Definition: model.h:241
#define Lappendsym
Definition: model.h:244
#define DEP
Definition: model.h:116
#define Strcpy
Definition: model.h:238
#define ARRAY
Definition: model.h:118
NMODL parser global flags / functions.
List * procfunc
Definition: init.cpp:9
char * name
Definition: init.cpp:16
List * initlist
Definition: init.cpp:8
Item * lappendstr(List *list, char *str)
Definition: list.cpp:134
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
void replacstr(Item *q, char *s)
Definition: list.cpp:225
char * stralloc(char *buf, char *rel)
Definition: list.cpp:184
List * newlist()
Definition: list.cpp:47
Item * lappenditem(List *list, Item *item)
Definition: list.cpp:146
Item * insertsym(Item *item, Symbol *sym)
Definition: list.cpp:119
Item * lappendsym(List *list, Symbol *sym)
Definition: list.cpp:142
void units(unit *)
Definition: units.cpp:733
#define fprintf
Definition: mwprefix.h:30
int vectorize
void slist_data(Symbol *s, int indx, int findx)
void vectorize_substitute(Item *q, char *str)
void vectorize_scan_for_func(Item *q1, Item *q2)
Definition: parsact.cpp:381
void depinstall(int type, Symbol *n, int index, char *from, char *to, char *units, Item *qs, int makeconst, char *abstol)
Definition: parsact.cpp:295
int cvode_cnexp_success(Item *q1, Item *q2)
void cvode_parse(Symbol *s, List *e)
void save_dt(Item *)
Definition: solve.cpp:356
void decode_ustr(Symbol *sym, double *pg1, double *pg2, char *s)
Definition: nocpout.cpp:1577
void eqnqueue(Item *)
Definition: simultan.cpp:39
void add_sens_statelist(Symbol *)
Definition: sens.cpp:113
void sensmassage(int type, Item *qfun, int fn)
Definition: sens.cpp:119
List * thread_mem_init_list
Definition: nocpout.cpp:128
int assert_threadsafe
#define nrn_assert(ex)
Definition: nrnassrt.h:53
size_t q
size_t j
static double remove(void *v)
Definition: ocdeck.cpp:207
#define STRING
Definition: bbslsrv.cpp:9
#define lookup
Definition: redef.h:90
#define install
Definition: redef.h:82
Item * mixed_eqns(Item *q2, Item *q3, Item *q4)
Definition: simultan.cpp:165
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 i
Definition: model.h:62
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
int used
Definition: model.h:65
int varnum
Definition: model.h:69