NEURON
deriv.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.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 numlist;
18 void copylist(List*, Item*);
21 
22 /* SmallBuf size */
23 #undef SB
24 #define SB 256
25 
26 extern int vectorize;
27 extern int assert_threadsafe;
28 extern int thread_data_index;
31 
32 extern char *cvode_deriv(), *cvode_eqnrhs();
33 extern Item* cvode_cnexp_solve;
34 void cvode_diffeq(Symbol* ds, Item* qbegin, Item* qend);
37 
38 void solv_diffeq(Item* qsol,
39  Symbol* fun,
40  Symbol* method,
41  int numeqn,
42  int listnum,
43  int steadystate,
44  int btype) {
45  const char* maxerr_str;
46  char dindepname[256];
47  char deriv1_advance[256], deriv2_advance[256];
48  char ssprefix[8];
49 
50  if (method && strcmp(method->name, "cnexp") == 0) {
51  Sprintf(buf, " %s();\n", fun->name);
52  replacstr(qsol, buf);
53  Sprintf(buf, " %s(_threadargs_);\n", fun->name);
55  return;
56  }
57  if (steadystate) {
58  Strcpy(ssprefix, "_ss_");
59  } else {
60  Strcpy(ssprefix, "");
61  }
62  Sprintf(dindepname, "d%s", indepsym->name);
63  if (fun->subtype & KINF) { /* translate the kinetic equations */
64  /* can be standard integrator, full matrix advancec, or
65  sparse matrix advance */
66  /* at this time only sparse and standard exists */
67  if (method->subtype & DERF) {
68  kinetic_intmethod(fun, method->name);
69  } else {
70  kinetic_implicit(fun, dindepname, method->name);
71  }
72  }
73  save_dt(qsol);
74  if (method->subtype & DERF) {
75  if (method->u.i == 1) { /* variable step method */
76  maxerr_str = ", maxerr";
77  IGNORE(ifnew_parminstall("maxerr", "1e-5", "", ""));
78  } else {
79  maxerr_str = "";
80  }
81 
82  if (deriv_imp_list) { /* make sure deriv block translation matches method */
83  Item* q;
84  int found = 0;
86  if (strcmp(STR(q), fun->name) == 0) {
87  found = 1;
88  }
89  }
90  if ((strcmp(method->name, Derivimplicit) == 0) ^ (found == 1)) {
91  diag(
92  "To use the derivimplicit method the SOLVE statement must precede the "
93  "DERIVATIVE block\n",
94  " and all SOLVEs using that block must use the derivimplicit method\n");
95  }
96  Sprintf(deriv1_advance, "_deriv%d_advance = 1;\n", listnum);
97  Sprintf(deriv2_advance, "_deriv%d_advance = 0;\n", listnum);
98  Sprintf(buf, "static int _deriv%d_advance = 0;\n", listnum);
100  Sprintf(buf,
101  "\n#define _deriv%d_advance _thread[%d].literal_value<int>()\n"
102  "#define _dith%d %d\n"
103  "#define _recurse _thread[%d].literal_value<int>()\n"
104  "#define _newtonspace%d _thread[%d].literal_value<NewtonSpace*>()\n",
105  listnum,
107  listnum,
108  thread_data_index + 1,
109  thread_data_index + 2,
110  listnum,
111  thread_data_index + 3);
113  Sprintf(buf, " _thread[_dith%d] = new double[%d]{};\n", listnum, 2 * numeqn);
115  Sprintf(buf, " _newtonspace%d = nrn_cons_newtonspace(%d);\n", listnum, numeqn);
117  Sprintf(buf, " delete[] _thread[_dith%d].get<double*>();\n", listnum);
119  Sprintf(buf, " nrn_destroy_newtonspace(_newtonspace%d);\n", listnum);
121  thread_data_index += 4;
122  } else {
123  Strcpy(deriv1_advance, "");
124  Strcpy(deriv2_advance, "");
125  }
126  Sprintf(buf,
127  "%s %s%s(_ninits, %d, _slist%d, _dlist%d, neuron::scopmath::row_view{_ml, _iml}, "
128  "&%s, %s, %s, &_temp%d%s);\n%s",
129  deriv1_advance,
130  ssprefix,
131  method->name,
132  numeqn,
133  listnum,
134  listnum,
135  indepsym->name,
136  dindepname,
137  fun->name,
138  listnum,
139  maxerr_str,
140  deriv2_advance);
141  } else {
142  // examples of ssprefix + method->name: sparse, _ss_sparse
143  Sprintf(buf,
144  "%s%s(&_sparseobj%d, %d, _slist%d, _dlist%d, "
145  "neuron::scopmath::row_view{_ml, _iml}, &%s, "
146  "%s, %s, &_coef%d, _linmat%d);\n",
147  ssprefix,
148  method->name,
149  listnum,
150  numeqn,
151  listnum,
152  listnum,
153  indepsym->name,
154  dindepname,
155  fun->name,
156  listnum,
157  listnum);
158  }
159  replacstr(qsol, buf);
160  if (method->subtype & DERF) { /* derivimplicit */
161  // derivimplicit_thread
162  Sprintf(buf,
163  "%s %s%s_thread(%d, _slist%d, _dlist%d, neuron::scopmath::row_view{_ml, _iml}, %s, "
164  "_ml, _iml, _ppvar, _thread, _globals, _nt);\n%s",
165  deriv1_advance,
166  ssprefix,
167  method->name,
168  numeqn,
169  listnum,
170  listnum,
171  fun->name,
172  deriv2_advance);
173  vectorize_substitute(qsol, buf);
174  } else { /* kinetic */
175  if (vectorize) {
176  // sparse_thread, _ss_sparse_thread
177  Sprintf(buf,
178  "%s%s_thread(&(_thread[_spth%d].literal_value<void*>()), %d, "
179  "_slist%d, _dlist%d, neuron::scopmath::row_view{_ml, _iml}, "
180  "&%s, %s, %s, _linmat%d, _threadargs_);\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  }
195  Sprintf(buf,
196  " if (secondorder) {\n"
197  " int _i;\n"
198  " for (_i = 0; _i < %d; ++_i) {\n"
199  " _ml->data(_iml, _slist%d[_i]) += dt*_ml->data(_iml, _dlist%d[_i]);\n"
200  " }}\n",
201  numeqn,
202  listnum,
203  listnum);
204  insertstr(qsol->next, buf);
205 }
206 
207 /* addition of higher order derivatives
208  User appearance:
209 Higher order derivatives are now allowed in DERIVATIVE blocks.
210 The number of primes following a variable is the order of the derivative.
211 For example, y'''' is a 4th order derivative.
212 The highest derivative of a state
213 must appear on the left hand side of the equation. Lower order derivatives
214 of a state (including the state itself) may appear on the right hand
215 side within an arbitrary expression. It makes no sense, in general,
216 to have multiple equations involving the same state on the left hand side.
217 The most common usage will be equations of the form
218  y'' = f(y, y', t)
219 
220 Higher derivatives can be accessed in SCoP as
221 y' Dy
222 y'' D2y
223 y''' D3y
224 etc. Note that all derivatives except the highest derivative are themselves
225 states on an equal footing with y. E.G. they can be explicitly declared within
226 a STATE block (and given START values), and they have associated initial value
227 constants. Initial values default to 0. Here is a complicated example which
228 shows off the syntax (I have no idea if the solution exists).
229  INDEPENDENT {t FROM 0 TO 1 WITH 1}
230  STATE {x y
231  y' START 1
232  x' START -10
233  }
234  DERIVATIVE d {
235  x''' = y + 3*x''*y' + sin(x') + exp(x)
236  y'' = cos(x'' + y) - y'
237  EQUATION {SOLVE d}
238 Note that we had to use Dx0 since x'0 is illegal. Also Dx0 has a
239 value of -10.
240 
241 Implementation :
242  In parse1.ypp we see that asgn: varname '=' expr and that
243  varname gets marked if it is type PRIME. With respect to
244  higher order derivatives, therefore, only the highest order
245  actually used in the equations in that block
246  should be marked. Furthermore these highest primes may or may not be
247  dependent variables and the lesser primes must be created as states.
248  We use a special iterator FORALL which returns each lesser order
249  symbol given a dstate.
250 
251  The implicit equations of the form DD2y = D3y do not have to
252  be constructed and the dependent variables DD2y do not have to
253  be created since the slist and dlist links can carry this
254  information. Thus dlist[D2y] == slist[D3y] causes the integrators
255  to do the right thing without, in fact, doing any arithmetic.
256  We assume that the itegrators either save the *dlist values or
257  update *slist using a loop running from 0 to N. This is why
258  the FORALL interator returns states starting with the base state
259  (so that *slist[i+1] doesn't change until after *dlist[i] is used.
260  (they point to the same value). In the case of a second order
261  equation, the lists are:
262  slist[0] = &y dlist[0] = &Dy
263  slist[1] = &Dy dlist[1] = &D2y
264 
265  Process
266  the code which unmarks the PRIMES and marks the corresponding state
267  is inadequate since several states must be marked some of which
268  are PRIME. For this reason we distinguish using a -1 to mark states
269  for later counting.
270 
271  The array problem is solved by using lex to:
272  when a PRIME is seen, check against the base state. If the base
273  state doesn't exist don't worry. If the STATE is an array
274  Then make PRIME an array of the same dimension.
275 
276  depinstall automattically creates a Dstate for each state
277  passed to it as well as a state0 (optional). This is OK since
278  they dissappear if unused.
279 
280 
281 */
282 
283 #define FORALL(state, dstate) for (state = init_forderiv(dstate); state; state = next_forderiv())
284 /* This returns all states of lower order than dstate in the order of
285 base state first. Will install PRIME if necessary.
286 */
287 static Symbol* forderiv; /* base state */
288 static char base_units[256]; /*base state units */
289 static int indx, maxindx; /* current indx, and indx of dstate */
290 
291 static Symbol* init_forderiv(Symbol* prime) {
292  char name[256];
293  double d1, d2;
294 
295  assert(prime->type == PRIME);
296  /*extract maxindx and basename*/
297  if (isdigit(prime->name[1])) { /* higher than 1 */
298  if (sscanf(prime->name + 1, "%d%s", &maxindx, name) != 2) {
299  diag("internal error in init_forderiv in init.c", (char*) 0);
300  }
301  } else {
302  maxindx = 1;
303  Strcpy(name, prime->name + 1);
304  }
305  forderiv = lookup(name);
306  if (!forderiv || !(forderiv->subtype & STAT)) {
307  diag(name, "must be declared as a state variable");
308  }
309  if (forderiv->araydim != prime->araydim) {
310  Sprintf(buf, "%s and %s have different dimensions", forderiv->name, prime->name);
311  diag(buf, (char*) 0);
312  }
313  indx = 0;
314  decode_ustr(forderiv, &d1, &d2, base_units);
315  return forderiv;
316 }
317 
318 static char* name_forderiv(int i) {
319  static char name[256];
320 
321  assert(i > 0 && forderiv);
322  if (i > 1) {
323  Sprintf(name, "D%d%s", i, forderiv->name);
324  } else {
325  Sprintf(name, "D%s", forderiv->name);
326  }
327  return name;
328 }
329 
330 /* Scop can handle 's so we put the prime style names into the .var file.
331 We make use of the tools here to reconstruct the original prime name.
332 */
333 char* reprime(Symbol* sym) {
334  static char name[256];
335  int i;
336  char* cp;
337 
338  if (sym->type != PRIME) {
339  Strcpy(name, sym->name);
340  return name;
341  }
342 
343  IGNORE(init_forderiv(sym));
344 
346  cp = name + strlen(name);
347  for (i = 0; i < maxindx; i++) {
348  *cp++ = '\'';
349  }
350  *cp = '\0';
351  return name;
352 }
353 
355  char* name;
356  Symbol* s;
357  char units[SB];
358 
359  if (++indx >= maxindx) {
360  return SYM0;
361  }
363  if ((s = lookup(name)) == SYM0) {
364  s = install(name, PRIME);
365  nrn_assert(snprintf(units, SB, "%s/%s^%d", base_units, STR(indeplist->prev), indx) < SB);
366  depinstall(1, s, forderiv->araydim, "0", "1", units, ITEM0, 1, "");
367  s->usage |= DEP;
368  }
369  if (s->araydim != forderiv->araydim) {
370  diag(s->name, "must have same dimension as associated state");
371  }
372  if (!(s->subtype & STAT)) { /* Dstate changes to state */
373  nrn_assert(snprintf(units, SB, "%s/%s^%d", base_units, STR(indeplist->prev), indx) < SB);
374  s->subtype &= ~DEP;
375  depinstall(1, s, forderiv->araydim, "0", "1", units, ITEM0, 1, "");
376  depinstall(1, s, forderiv->araydim, "0", "1", units, ITEM0, 1, "");
377  s->usage |= DEP;
378  }
379  return s;
380 }
381 
382 /* mixed derivative and nonlinear equations */
383 /* Implementation:
384  The main requirement is to distinguish between the states which
385  have derivative specifications and the states which are solved
386  for by the nonlinear equations. We do this by having the
387  left hand side derivative saved in a list instead of marking the
388  variables in the used field. See deriv_used(). States seen in the
389  nonlinear equations are marked as usual. To leave only nonlinear
390  states marked we then cast out any lesser state which is marked.
391  (eg if y''=.. then y and y' cannot be states of the nonlinear equation).
392  The former version also made use of state->used = -1 for match
393  purposes. We replace this usage with a list of states of the
394  derivatives. This means that the derivative block with respect to
395  derivative equations no longer uses the used field.
396 
397  To avoid copying the block we (albeit resulting is somewhat poorer
398  efficiency) we allow the block to call newton and pass itself as
399  an argument. A flag tells the block if its call was by newton or by
400  an integrator. My guess is this will still work with match, sens, and
401  array states.
402 */
403 
404 /* derivative equations (and possibly some nonlinear equations) solved
405  with an implicit method */
406 /* Implementation:
407  Things are starting to get a little bit out of conceptual control.
408  We make use of the mixed case, except that the number of nonlinear
409  equations may be 0. The substantive change is that now the number
410  of equations is the sum of the derivatives and the nonlinears and the
411  extra equations added into the block are of the form
412  dlist2[++_counte] = Dstate - (state - statesave1[0])/dt;
413  The administrative needs are that newton is called with the total number
414  of equations and that we can match state and statesave. Notice that we
415  already have two sets of slists floating around and one dlist,
416  currently they are the
417  slist and dlist for the derivative state and state'
418  and the slist for the nonlinear states (the corresponding dlist is just
419  the rhs of the equations). Clearly, statesave should be associated
420  with the derivative slist and will be in that order, then the slist for
421  newton will be expanded by not resetting the used field.
422  The biggest conceptual problem is how to generate the code at the time
423  we handle the SOLVE since the actual numbers for the declarations
424  of the newton slists depend on the method.
425  Here, we assume a flag, deriv_implicit, which tells us which code to
426  generate. Whether this means that we must look through the .mod file
427  for all the SOLVE statements or whether all this stuff is saved for
428  calling from the solve handler as in the kinetic block is not specified
429  yet.
430  For now, we demand that the SOLVE statement be seen first if it
431  invokes the derivimplicit method. Otherwise modl generates an error
432  message.
433 */
434 
436  if (!deriv_imp_list) {
438  }
440 }
441 
442 static List* deriv_used_list; /* left hand side derivatives of diffeqs */
443 static List* deriv_state_list; /* states of the derivative equations */
444 
445 void deriv_used(Symbol* s, Item* q1, Item* q2) /* q1, q2 are begin and end tokens for expression */
446 {
447  if (!deriv_used_list) {
450  }
452  if (!cvode_diffeq_list) {
454  }
458 }
459 
460 /* args are --- derivblk: DERIVATIVE NAME stmtlist '}' */
461 void massagederiv(Item* q1, Item* q2, Item* q3, Item* q4) {
462  int count = 0, deriv_implicit;
463  char units[SB];
464  Item *qs, *q, *mixed_eqns(Item * q2, Item * q3, Item * q4);
465  Symbol *s, *derfun, *state;
466 
467  /* to allow verification that definition after SOLVE */
468  if (!massage_list_) {
470  }
472 
473  /* all this junk is still in the intoken list */
474  Sprintf(buf, "static int %s(_internalthreadargsproto_);\n", SYM(q2)->name);
476  replacstr(q1, "\nstatic int");
477  q = insertstr(q3, "() {_reset=0;\n");
478  derfun = SYM(q2);
480  "(_internalthreadargsproto_) {\n"
481  " int _reset=0;\n"
482  " int error = 0;\n");
483 
484  if (derfun->subtype & DERF && derfun->u.i) {
485  diag("DERIVATIVE merging not implemented", (char*) 0);
486  }
487 
488  /* check if we are to translate using derivimplicit method */
489  deriv_implicit = 0;
490  if (deriv_imp_list)
492  if (strcmp(derfun->name, STR(q)) == 0) {
493  deriv_implicit = 1;
494  break;
495  }
496  }
497  numlist++;
498  derfun->u.i = numlist;
499  derfun->subtype |= DERF;
500  if (!deriv_used_list) {
501  diag("No derivative equations in DERIVATIVE block", (char*) 0);
502  }
503  ITERATE(qs, deriv_used_list) {
504  s = SYM(qs);
505  if (!(s->subtype & DEP) && !(s->subtype & STAT)) {
507  nrn_assert(snprintf(units, SB, "%s/%s^%d", base_units, STR(indeplist->prev), maxindx) >
508  SB);
509  depinstall(0, s, s->araydim, "0", "1", units, ITEM0, 0, "");
510  }
511  /* high order: make sure
512  no lesser order is marked, and all lesser
513  orders exist as STAT */
514  FORALL(state, s) {
515  if (state->type == PRIME) {
516  ITERATE(q, deriv_used_list) if (state == SYM(q)) {
517  diag(state->name,
518  ": Since higher derivative is being used, this state \
519 is not allowed on the left hand side.");
520  }
521  }
523  slist_data(state, count, numlist);
524  if (s->subtype & ARRAY) {
525  int dim = s->araydim;
526  Sprintf(buf,
527  "for(_i=0;_i<%d;_i++){_slist%d[%d+_i] = {%s_columnindex, _i};",
528  dim,
529  numlist,
530  count,
531  state->name);
533  Sprintf(buf,
534  " _dlist%d[%d+_i] = {%s_columnindex, _i};}\n",
535  numlist,
536  count,
537  name_forderiv(indx + 1));
539  count += dim;
540  } else {
541  Sprintf(buf, "_slist%d[%d] = {%s_columnindex, 0};", numlist, count, state->name);
543  Sprintf(buf,
544  " _dlist%d[%d] = {%s_columnindex, 0};\n",
545  numlist,
546  count,
547  name_forderiv(indx + 1));
549  count++;
550  }
551  }
552  }
553  if (count == 0) {
554  diag("DERIVATIVE contains no derivatives", (char*) 0);
555  }
556  derfun->used = count;
557  Sprintf(buf,
558  "static neuron::container::field_index _slist%d[%d], _dlist%d[%d];\n",
559  numlist,
560  count,
561  numlist,
562  count);
564 
565  Lappendstr(procfunc, "\n/*CVODE*/\n");
566  Sprintf(buf, "static int _ode_spec%d", numlist);
568  {
569  Item* qq = procfunc->prev;
570  copyitems(q1->next, q4, procfunc->prev);
571  vectorize_substitute(qq->next, "(_internalthreadargsproto_) {int _reset = 0;");
573  }
574  lappendstr(procfunc, "return _reset;\n}\n");
575 
576  /* don't emit _ode_matsol if the user has defined cvodematsol */
577  if (!lookup("cvodematsol")) {
578  Item* qq;
579  Item* qextra = q1->next->next->next->next;
580  Sprintf(buf, "static int _ode_matsol%d", numlist);
582  vectorize_substitute(lappendstr(procfunc, "() {\n"), "(_internalthreadargsproto_) {\n");
583  qq = procfunc->next;
586  Symbol* s;
587  Item *q1, *q2;
588  s = SYM(q);
589  q = q->next;
590  q1 = ITM(q);
591  q = q->next;
592  q2 = ITM(q);
593 #if 1
594  while (qextra != q1) { /* must first have any intervening statements */
595  switch (qextra->itemtype) {
596  case STRING:
597  Lappendstr(procfunc, STR(qextra));
598  break;
599  case SYMBOL:
600  Lappendsym(procfunc, SYM(qextra));
601  break;
602  }
603  qextra = qextra->next;
604  }
605 #endif
606  cvode_diffeq(s, q1, q2);
607  qextra = q2->next;
608  }
609 #if 1
610  /* if we are not at the end, there is more extra */
611  while (qextra != q4) {
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  Lappendstr(procfunc, " return 0;\n}\n");
625  }
626 
627  Lappendstr(procfunc, "/*END CVODE*/\n");
628  if (cvode_cnexp_solve && cvode_cnexp_success(q1, q4)) {
631  return;
632  }
633  if (deriv_implicit) {
634  Sprintf(buf,
635  "static double _savstate%d[%d], *_temp%d = _savstate%d;\n",
636  numlist,
637  count,
638  numlist,
639  numlist);
640  q = linsertstr(procfunc, buf);
641  vectorize_substitute(q, "");
642  } else {
643  Sprintf(buf, "static double *_temp%d;\n", numlist);
645  }
646  movelist(q1, q4, procfunc);
647  Lappendstr(procfunc, "return _reset;}\n");
648  /* reset used field for any states that may appear in
649  nonlinear equations which should not be solved for. */
651  SYM(q)->used = 0;
652  }
653  if (deriv_implicit) {
654  Symbol* sp;
656  SYM(q)->used = 1;
657  }
658  Sprintf(buf,
659  "{int _id; for(_id=0; _id < %d; _id++) {\n\
660 if (_deriv%d_advance) {\n",
661  count,
662  numlist);
663  Insertstr(q4, buf);
664  sp = install("D", STRING);
665  sp->araydim = count;
666  q = insertsym(q4, sp);
667  eqnqueue(q);
668  Sprintf(buf,
669  "_ml->data(_iml, _dlist%d[_id]) - (_ml->data(_iml, _slist%d[_id]) - "
670  "_savstate%d[_id])/d%s;\n",
671  numlist,
672  numlist,
673  numlist,
674  indepsym->name);
675  Insertstr(q4, buf);
676  Sprintf(
677  buf,
678  "}else{\n_dlist%d[++_counte] = _ml->data(_iml, _slist%d[_id]) - _savstate%d[_id];}}}\n",
679  numlist + 1,
680  numlist,
681  numlist);
682  Insertstr(q4, buf);
683  } else {
685  SYM(q)->used = 0;
686  }
687  }
688  /* if there are also nonlinear equations, put in the newton call,
689  create the proper lists and fill in the left hand side of each
690  equation. */
691  q = mixed_eqns(q2, q3, q4); /* numlist now incremented */
692  if (deriv_implicit) {
693  Sprintf(buf,
694  "for(int _id=0; _id < %d; _id++) {\n"
695  " _savstate%d[_id] = _ml->data(_iml, _slist%d[_id]);\n"
696  "}\n",
697  count,
698  derfun->u.i,
699  derfun->u.i);
700  Insertstr(q, buf);
701  }
702 
705 }
706 
707 
708 void copylist(List* l, Item* i) /* copy list l before item i */
709 {
710  Item* q;
711 
712  ITERATE(q, l) {
713  switch (q->itemtype) {
714  case STRING:
715  Insertstr(i, STR(q));
716  break;
717  case SYMBOL:
718  Insertsym(i, SYM(q));
719  break;
720  default:
721  /*SUPPRESS 622*/
722  assert(0);
723  }
724  }
725 }
726 
727 void copyitems(Item* q1, Item* q2, Item* qdest) /* copy items before item */
728 {
729  Item* q;
730  for (q = q2; q != q1; q = q->prev) {
731  switch (q->itemtype) {
732  case STRING:
733  case VERBATIM:
734  Linsertstr(qdest, STR(q));
735  break;
736  case SYMBOL:
737  Linsertsym(qdest, SYM(q));
738  break;
739  default:
740  /*SUPPRESS 622*/
741  assert(0);
742  }
743  }
744 }
745 
746 static int cvode_linear_diffeq(Symbol* ds, Symbol* s, Item* qbegin, Item* qend) {
747  char* c;
748  List* tlst;
749  Item* q;
750  tlst = newlist();
751  for (q = qbegin; q != qend->next; q = q->next) {
752  switch (q->itemtype) {
753  case SYMBOL:
754  lappendsym(tlst, SYM(q));
755  break;
756  case STRING:
757  lappendstr(tlst, STR(q));
758  break;
759  default:
761  return 0;
762  }
763  }
764  cvode_parse(s, tlst);
765  freelist(&tlst);
766  c = cvode_deriv();
767  if (!cvode_eqn) {
768  cvode_eqn = newlist();
769  }
773  if (c) {
775  lappendstr(procfunc, "))");
776  return 1;
777  }
779  return 0;
780 }
781 
782 /* DState symbol, begin, and end of expression */
783 void cvode_diffeq(Symbol* ds, Item* qbegin, Item* qend) {
784  /* try first the assumption of linear. If not, then use numerical diff*/
785  Symbol* s;
786  Item* q;
787 
788  /* get state symbol */
789  sscanf(ds->name, "D%s", buf);
790  s = lookup(buf);
791  assert(s);
792 
793  /* ds/(1. - dt*( */
794  Lappendsym(procfunc, ds);
795  Lappendstr(procfunc, " / (1. - dt*(");
796  if (cvode_linear_diffeq(ds, s, qbegin, qend)) {
797  return;
798  }
799  /* ((expr(s+.001))-(expr))/.001; */
800  Lappendstr(procfunc, "((");
801  for (q = qbegin; q != qend->next; q = q->next) {
802  switch (q->itemtype) {
803  case STRING:
805  break;
806  case SYMBOL:
807  if (SYM(q) == s) {
808  Lappendstr(procfunc, "(");
810  Lappendstr(procfunc, " + .001)");
811  } else {
813  }
814  break;
815  default:
816  assert(0);
817  }
818  }
819  Lappendstr(procfunc, ") - (");
820  for (q = qbegin; q != qend->next; q = q->next) {
821  switch (q->itemtype) {
822  case STRING:
824  break;
825  case SYMBOL:
827  break;
828  default:
829  assert(0);
830  }
831  }
832  Lappendstr(procfunc, " )) / .001 ))");
833 }
834 
835 /*
836 the cnexp method was requested but the symbol in the solve queue was
837 changed to derivimplicit and cvode_cnexp_solve holds a pointer to
838 the solvq item (1st of three).
839 The 0=f(state) equations have already been solved and the rhs for
840 each has been saved. So we know if the translation is possible.
841 */
843  Item *q, *q3, *q4, *qeq;
844  if (cvode_cnexp_possible) {
845  /* convert Method to nullptr and the type of the block to
846  PROCEDURE */
847  SYM(cvode_cnexp_solve->next)->name = stralloc("cnexp", 0);
849 
850  /* replace the Dstate = f(state) equations */
851  qeq = cvode_eqn->next;
853  Symbol* s;
854  Item *q1, *q2;
855  char *a, *b;
856  s = SYM(qeq);
857  qeq = qeq->next;
858  a = STR(qeq);
859  qeq = qeq->next;
860  b = STR(qeq);
861  qeq = qeq->next;
862  q = q->next;
863  q1 = ITM(q);
864  q = q->next;
865  q2 = ITM(q);
866  if (!netrec_cnexp) {
867  netrec_cnexp = newlist();
868  }
870  if (strcmp(a, "0.0") == 0) {
871  assert(b[strlen(b) - 9] == '/');
872  b[strlen(b) - 9] = '\0';
873  Sprintf(buf, " __primary -= 0.5*dt*( %s )", b);
875  Sprintf(buf, " %s = %s - dt*(%s)", s->name, s->name, b);
876  } else {
877  Sprintf(buf,
878  " __primary += ( 1. - exp( 0.5*dt*( %s ) ) )*( %s - __primary )",
879  a,
880  b);
882  Sprintf(buf,
883  " %s = %s + (1. - exp(dt*(%s)))*(%s - %s)",
884  s->name,
885  s->name,
886  a,
887  b,
888  s->name);
889  }
890  insertstr(q2->next, buf);
891  q2 = q2->next;
892  for (q3 = q1->prev->prev; q3 != q2; q3 = q4) {
893  q4 = q3->next;
894  remove(q3);
895  }
896  }
897 
898  lappendstr(procfunc, "static int");
899  {
900  Item* qq = procfunc->prev;
901  copyitems(q1, q2, procfunc->prev);
902  /* more or less redundant with massagederiv */
903  vectorize_substitute(qq->next->next, "(_internalthreadargsproto_) {");
905  }
906  lappendstr(procfunc, " return 0;\n}\n");
907  return 1;
908  }
909  fprintf(stderr, "Could not translate using cnexp method; using derivimplicit\n");
910  return 0;
911 }
#define STRING
Definition: bbslsrv.cpp:9
#define i
Definition: md1redef.h:19
static List * cvode_eqn
Definition: deriv.cpp:35
static int maxindx
Definition: deriv.cpp:289
#define FORALL(state, dstate)
Definition: deriv.cpp:283
List * thread_cleanup_list
Definition: nocpout.cpp:111
int thread_data_index
Definition: nocpout.cpp:110
static List * deriv_state_list
Definition: deriv.cpp:443
int vectorize
Definition: nocpout.cpp:78
char * reprime(Symbol *sym)
Definition: deriv.cpp:333
void solv_diffeq(Item *qsol, Symbol *fun, Symbol *method, int numeqn, int listnum, int steadystate, int btype)
Definition: deriv.cpp:38
static List * deriv_imp_list
Definition: deriv.cpp:10
Item * cvode_cnexp_solve
Definition: solve.cpp:21
List * indeplist
Definition: parsact.cpp:15
List * thread_mem_init_list
Definition: nocpout.cpp:112
#define SB
Definition: deriv.cpp:24
static List * cvode_diffeq_list
Definition: deriv.cpp:35
int numlist
Definition: solve.cpp:33
int cvode_cnexp_success(Item *q1, Item *q2)
Definition: deriv.cpp:842
void massagederiv(Item *q1, Item *q2, Item *q3, Item *q4)
Definition: deriv.cpp:461
List * massage_list_
Definition: deriv.cpp:19
static Symbol * forderiv
Definition: deriv.cpp:287
static int cvode_linear_diffeq(Symbol *ds, Symbol *s, Item *qbegin, Item *qend)
Definition: deriv.cpp:746
static char Derivimplicit[]
Definition: deriv.cpp:12
void copyitems(Item *q1, Item *q2, Item *qdest)
Definition: deriv.cpp:727
int dtsav_for_nrn_state
Definition: deriv.cpp:17
void cvode_diffeq(Symbol *ds, Item *qbegin, Item *qend)
Definition: deriv.cpp:783
static List * deriv_used_list
Definition: deriv.cpp:442
char * cvode_eqnrhs()
static int indx
Definition: deriv.cpp:289
int assert_threadsafe
char * cvode_deriv()
static char base_units[256]
Definition: deriv.cpp:288
void add_deriv_imp_list(char *name)
Definition: deriv.cpp:435
void copylist(List *, Item *)
Definition: deriv.cpp:708
static Symbol * next_forderiv()
Definition: deriv.cpp:354
List * netrec_cnexp
Definition: deriv.cpp:20
Symbol * indepsym
Definition: declare.cpp:8
static int cvode_cnexp_possible
Definition: deriv.cpp:36
static Symbol * init_forderiv(Symbol *prime)
Definition: deriv.cpp:291
void deriv_used(Symbol *s, Item *q1, Item *q2)
Definition: deriv.cpp:445
static char * name_forderiv(int i)
Definition: deriv.cpp:318
Symbol * ifnew_parminstall(const char *name, const char *num, const char *units, const char *limits)
Definition: parsact.cpp:71
char buf[512]
Definition: init.cpp:13
static int c
Definition: hoc.cpp:169
#define assert(ex)
Definition: hocassrt.h:24
void kinetic_intmethod(Symbol *fun, const char *meth)
Definition: kinetic.cpp:458
void kinetic_implicit(Symbol *fun, const char *dt, const char *mname)
Definition: kinetic.cpp:642
#define DEP
Definition: membfunc.hpp:64
#define DERF
Definition: model.h:114
#define STR(q)
Definition: model.h:76
#define SYM0
Definition: model.h:63
#define STAT
Definition: model.h:106
#define ITERATE(itm, lst)
Definition: model.h:18
#define SYMBOL
Definition: model.h:91
#define Linsertsym
Definition: model.h:219
#define Linsertstr
Definition: model.h:220
#define Lappendstr
Definition: model.h:222
#define ITEM0
Definition: model.h:15
#define Insertstr
Definition: model.h:217
#define ITM(q)
Definition: model.h:77
#define IGNORE(arg)
Definition: model.h:224
#define SYM(q)
Definition: model.h:75
#define KINF
Definition: model.h:120
#define Insertsym
Definition: model.h:218
#define Lappendsym
Definition: model.h:221
#define Strcpy
Definition: model.h:215
Symbol * lookup(const char *)
#define ARRAY
Definition: model.h:107
Symbol * install(const char *, int)
List * procfunc
Definition: init.cpp:9
const char * name
Definition: init.cpp:16
List * initlist
Definition: init.cpp:8
char * stralloc(const char *buf, char *rel)
Definition: list.cpp:178
void movelist(Item *q1, Item *q2, List *s)
Definition: list.cpp:214
Item * linsertstr(List *list, const char *str)
Definition: list.cpp:131
void replacstr(Item *q, const char *s)
Definition: list.cpp:219
Item * lappenditem(List *list, Item *item)
Definition: list.cpp:147
Item * insertsym(Item *item, Symbol *sym)
Definition: list.cpp:120
Item * insertstr(Item *item, const char *str)
Definition: list.cpp:99
Item * lappendsym(List *list, Symbol *sym)
Definition: list.cpp:143
Item * lappendstr(List *list, const char *str)
Definition: list.cpp:135
List * newlist()
The following routines support the concept of a list.
int Sprintf(char(&buf)[N], const char *fmt, Args &&... args)
Redirect sprintf to snprintf if the buffer size can be deduced.
Definition: wrap_sprintf.h:14
void depinstall(int type, Symbol *n, int index, const char *from, const char *to, const char *units, Item *qs, int makeconst, const char *abstol)
Definition: parsact.cpp:136
void slist_data(Symbol *s, int indx, int findx)
Definition: nocpout.cpp:2686
void vectorize_scan_for_func(Item *q1, Item *q2)
Definition: parsact.cpp:219
void cvode_parse(Symbol *s, List *e)
void save_dt(Item *)
Definition: solve.cpp:283
void decode_ustr(Symbol *sym, double *pg1, double *pg2, char *s)
Definition: nocpout.cpp:1718
void eqnqueue(Item *)
Definition: simultan.cpp:44
void vectorize_substitute(Item *q, const char *str)
Definition: noccout.cpp:748
NMODL parser global flags / functions.
#define diag(s)
Definition: nonlin.cpp:19
#define nrn_assert(x)
assert()-like macro, independent of NDEBUG status
Definition: nrn_assert.h:33
size_t q
s
Definition: multisend.cpp:521
static double remove(void *v)
Definition: ocdeck.cpp:205
Item * mixed_eqns(Item *q2, Item *q3, Item *q4)
Definition: simultan.cpp:166
void units(unit *)
Definition: units.cpp:641
Definition: model.h:8
struct Item * prev
Definition: model.h:13
short itemtype
Definition: model.h:9
struct Item * next
Definition: model.h:12
Definition: model.h:47
union Symbol::@28 u
int i
Definition: model.h:52
short type
Definition: model.h:48
int araydim
Definition: model.h:57
long subtype
Definition: model.h:49
char * name
Definition: model.h:61
int used
Definition: model.h:55