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