NEURON
kinetic.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 
3 #define Glass 1
4 
5 #if Glass
6 /*
7 We have found and corrected an MODL bug.
8 
9 The problem is that if any directive other than a CONSERVE or ~
10 is used within a KINETIC block the resultant C code is not in the correct
11 order. Here is the C code from a kinetic block:
12 */
13 #endif
14 
15 /* Sets up derivative form and implicit form*/
16 
17 #include <stdlib.h>
18 #include "modl.h"
19 #include "parse1.hpp"
20 #include "symbol.h"
21 extern int numlist;
22 extern int thread_data_index;
24 extern int vectorize;
25 
26 static int cvode_flag;
27 static void cvode_kin_remove();
29 static List* kin_items_;
30 #define CVODE_FLAG if (cvode_flag)
31 #define NOT_CVODE_FLAG if (!cvode_flag)
32 
33 typedef struct Rterm {
34  struct Rterm* rnext;
36  char* str;
37  int num;
38  short isstate; /* 1 if to be solved for */
40 static Rterm *rterm = (Rterm*) 0, *lterm; /*list of reaction terms for a side*/
41 
42 typedef struct Reaction {
44  Rterm* rterm[2]; /* rterm[0] = null if flux*/
45  char* krate[2]; /* one of these is null if flux */
48 static Reaction* reactlist = (Reaction*) 0;
49 static Reaction* conslist = (Reaction*) 0;
50 static List* done_list; /* list of already translated blocks */
51 static List* done_list1; /* do not emit definitions more than once */
52 typedef struct Rlist {
54  Symbol* sym; /* the kinetic block symbol */
55  Item* position; /* where we can initialize lists */
56  Item* endbrace; /* can insert after all statements */
57  Symbol** symorder; /* state symbols in varnum order */
58  const char** capacity; /* compartment size expessions in varnum order */
59  int nsym; /* number of symbols in above vector */
60  int ncons; /* and the diagonals for conservation are first */
61  struct Rlist* rlistnext;
64 static Rlist* rlist = (Rlist*) 0;
65 static Rlist* clist = (Rlist*) 0;
66 
67 static List* compartlist; /* list of triples with point to info in
68  COMPARTMENT statement. The info is qexpr q'{' q'}' and points
69  to items safely enclosed in a C comment.
70  see massagecompart() and massagekinetic() */
71 
72 List* ldifuslist; /* analogous to compartment. Specifies diffusion constant
73  times the relevant cross sectional area. The volume/length
74  must be specified in the COMPARTMENT statement */
75 
76 int genconservterms(int eqnum, Reaction* r, int fn, Rlist* rlst);
77 int number_states(Symbol* fun, Rlist** prlst, Rlist** pclst);
78 void kinlist(Symbol* fun, Rlist* rlst);
79 void genderivterms(Reaction* r, int type, int n);
80 void genmatterms(Reaction* r, int fn);
81 
82 #define MAXKINBLK 20
83 static int nstate_[MAXKINBLK];
84 
85 char* qconcat(Item* q1, Item* q2) /* return names as single string */
86 {
87  char *cp, *ovrfl, *cs, *n;
88  cp = buf;
89  ovrfl = buf + 400;
90  while (q1 != q2->next) {
91  assert(cp < ovrfl);
92  *cp++ = ' ';
93  if (q1->itemtype == SYMBOL) {
94  /* dont prepend *( to ARRAYS anymore */
95 #if 0
96  if (SYM(q1)->type == NAME && (SYM(q1)->subtype & ARRAY)) {
97  *cp++ = '*';
98  *cp++ = '(';
99  }
100 #endif
101  n = SYM(q1)->name;
102  } else {
103  n = STR(q1);
104  }
105  for (cs = n; *cs; cs++) {
106  *cp++ = *cs;
107  }
108  q1 = q1->next;
109  }
110  *cp = '\0';
111  return stralloc(buf, (char*) 0);
112 }
113 
114 void reactname(Item* q1, Item* lastok, Item* q2) /* NAME [] INTEGER q2 may be null*/
115 { /* put on right hand side */
116  Symbol *s, *s1;
117  Rterm* rnext;
118 
119  rnext = rterm;
120  rterm = (Rterm*) emalloc(sizeof(Rterm));
121  rterm->rnext = rnext;
122  rterm->isstate = 0;
123  s = SYM(q1);
124  if ((s->subtype & STAT) && in_solvefor(s)) {
125  Sprintf(buf, "D%s", s->name);
126  s1 = lookup(buf);
127  s1->usage |= DEP;
128  s->used++;
129  rterm->isstate = 1;
130  } else if (!(s->subtype & (DEP | nmodlCONST | PARM | INDEP | STAT))) {
131  diag(s->name, "must be a STATE, CONSTANT, ASSIGNED, or INDEPENDENT");
132  }
133  if (q2) {
134  rterm->num = atoi(STR(q2));
135  } else {
136  rterm->num = 1;
137  }
138  if (q1 != lastok) {
139  if (!(s->subtype & ARRAY)) {
140  diag("REACTION: MUST be scalar or array", (char*) 0);
141  }
142  rterm->str = qconcat(q1->next->next, lastok->prev);
143  /* one too many parentheses since normally a *( is prepended to the name
144  during output in cout.c. Therefore when used to construct a MATELM or RHS
145  extra parentheses must be prepended as in MATELM((...,(....
146  */ /* this no longer holds, no parentheses are to be prepended */
147  } else {
148  rterm->str = (char*) 0;
149  }
150  rterm->sym = s;
151 }
152 
153 void leftreact() /* current reaction list is for left hand side */
154 {
155  /* put whole list on left hand side and initialize right hand side */
156  lterm = rterm;
157  rterm = (Rterm*) 0;
158 }
159 
160 void massagereaction(Item* qREACTION, Item* qREACT1, Item* qlpar, Item* qcomma, Item* qrpar) {
161  Reaction* r1;
162 
163  /*ARGSUSED*/
164  r1 = reactlist;
165  reactlist = (Reaction*) emalloc(sizeof(Reaction));
166  reactlist->reactnext = r1;
167  reactlist->rterm[1] = rterm;
168  reactlist->rterm[0] = lterm;
169  reactlist->krate[0] = qconcat(qlpar->next, qcomma->prev);
170  reactlist->krate[1] = qconcat(qcomma->next, qrpar->prev);
171  reactlist->position = qrpar;
172  /*SUPPRESS 440*/
173  replacstr(qREACTION, "/* ~");
174  /*SUPPRESS 440*/
175  Insertstr(qrpar, ")*/\n");
176  /*SUPPRESS 440*/
177  replacstr(qrpar, "/*REACTION*/\n");
178  rterm = (Rterm*) 0;
179 }
180 
181 void flux(Item* qREACTION, Item* qdir, Item* qlast) {
182  Reaction* r1;
183 
184  r1 = reactlist;
185  reactlist = (Reaction*) emalloc(sizeof(Reaction));
186  reactlist->reactnext = r1;
187  reactlist->rterm[0] = rterm;
188  reactlist->rterm[1] = (Rterm*) 0;
189  /*SUPPRESS 440*/
190  replacstr(qREACTION, "/* ~");
191  reactlist->position = qlast;
192  if (SYM(qdir)->name[0] == '-') {
193  reactlist->krate[0] = qconcat(qdir->next->next, qlast);
194  reactlist->krate[1] = (char*) 0;
195  /*SUPPRESS 440*/
196  replacstr(qlast, "/*REACTION*/\n");
197  } else {
198  if (rterm->rnext || (rterm->num != 1)) {
199  diag("flux equations involve only one state", (char*) 0);
200  }
201  reactlist->krate[0] = (char*) 0;
202  reactlist->krate[1] = qconcat(qdir->next->next, qlast);
203  if (ldifuslist) { /* function of current ? */
204  Item* q;
205  for (q = qdir->next->next; q != qlast; q = q->next) {
206  Symbol* s;
207  if (q->itemtype == SYMBOL) {
208  s = SYM(q);
209  if (s->nrntype & 02 /*NRNCURIN*/) {
210  Symbol* sr;
211  Item* q1;
212  char *c1, *c2;
213  /* associate dflux/dcur with proper state */
214  ITERATE(q1, ldifuslist) {
215  sr = SYM(q1);
216  q1 = q1->next->next->next->next->next;
217  if (sr == rterm->sym) {
218  c1 = qconcat(qdir->next->next, q->prev);
219  c2 = qconcat(q->next, qlast);
220  Sprintf(buf,
221  "nrn_nernst_coef(_type_%s)*(%s _ion_d%sdv %s)",
222  s->name,
223  c1,
224  s->name,
225  c2); /* dflux/dv */
226  if (rterm->str) {
227  replacstr(q1, rterm->str);
228  }
229  if (*STR(q1->next) == '\0') {
230  replacstr(q1->next, buf);
231  } else {
232  diag(sr->name, "gets a flux from more than one current");
233  }
234  }
235  q1 = q1->next;
236  }
237  }
238  }
239  }
240  }
241  /*SUPPRESS 440*/
242  replacstr(qlast, "/*FLUX*/\n");
243  }
244  /*SUPPRESS 440*/
245  Insertstr(qlast, ")*/\n");
246  /*SUPPRESS 440*/
247  rterm = (Rterm*) 0;
248 }
249 
250 /* set up derivative form for use with integration methods */
251 
252 /* a bunch of states may be marked used but not be in the solveforlist
253  we therefore loop through all the rterms and mark only those
254 */
255 
256 void massagekinetic(Item* q1, Item* q2, Item* q3, Item* q4) /*KINETIC NAME stmtlist
257  '}'*/
258 {
259  int count = 0, i, order, ncons;
260  Item *q, *qs, *afterbrace;
261  Item* qv;
262  Symbol *s, *fun;
263  Reaction* r1;
264  Rterm* rt;
265  Rlist* r;
266 
267  fun = SYM(q2);
268  if ((fun->subtype & (DERF | KINF)) && fun->u.i) {
269  diag("Merging kinetic blocks not implemented", (char*) 0);
270  }
271  fun->subtype |= KINF;
272  numlist++;
273  fun->u.i = numlist;
274 
276  "(void* _so, double* _rhs, _internalthreadargsproto_);\n");
277  Sprintf(buf, "static int %s", SYM(q2)->name);
279 
280  replacstr(q1, "\nstatic int");
281  qv = insertstr(q3, "()\n");
282  if (vectorize) {
283  kin_vect1(q1, q2, q4);
284  vectorize_substitute(qv, "(void* _so, double* _rhs, _internalthreadargsproto_)\n");
285  }
286  qv = insertstr(q3, "{_reset=0;\n");
287  Sprintf(buf, "{int _reset=0;\n");
289  afterbrace = q3->next;
290 #if Glass
291  /* Make sure that if the next statement was LOCAL xxx, we skip
292  past it to do any of the other declarations. DRB */
293  if (afterbrace->itemtype == STRING && !strcmp(afterbrace->element.str, "double")) {
294  for (afterbrace = afterbrace->next;
295  afterbrace->itemtype != STRING || strcmp(afterbrace->element.str, ";\n");
296  afterbrace = afterbrace->next)
297  ;
298  if (afterbrace->itemtype == STRING && !strcmp(afterbrace->element.str, ";\n"))
299  afterbrace = afterbrace->next;
300  }
301 
302 #endif
303  qv = insertstr(afterbrace, "double b_flux, f_flux, _term; int _i;\n");
304  /* also after these declarations will go initilization statements */
305 
306  order = 0;
307  /* the varnum and order of the states is such that diagonals of
308  conservation equations must be first. This is done by setting
309  s->used=-1 for all states and then numbering first with respect
310  to the conslist and then the remaining that are still -1
311  */
312  /* mark only the isstate states */
313  SYMITER(NAME) {
314  if ((s->subtype & STAT) && s->used) {
315  s->used = 0;
316  }
317  }
318  for (r1 = conslist; r1; r1 = r1->reactnext) {
319  for (rt = r1->rterm[0]; rt; rt = rt->rnext) {
320  if (rt->isstate) {
321  rt->sym->used = -1;
322  }
323  }
324  }
325  for (r1 = reactlist; r1; r1 = r1->reactnext) {
326  for (rt = r1->rterm[0]; rt; rt = rt->rnext) {
327  if (rt->isstate) {
328  rt->sym->used = -1;
329  }
330  }
331  for (rt = r1->rterm[1]; rt; rt = rt->rnext) {
332  if (rt->isstate) {
333  rt->sym->used = -1;
334  }
335  }
336  }
337 
338  /* diagonals of the conservation relations are first */
339  for (r1 = conslist; r1; r1 = r1->reactnext) {
340  for (rt = r1->rterm[0]; rt; rt = rt->rnext) {
341  if ((rt->sym->used == -1) && !(rt->sym->subtype & ARRAY)) {
342  rt->sym->varnum = count++;
343  rt->sym->used = ++order; /*first is 1*/
344  break;
345  }
346  }
347  if (!rt) {
348  diag("Failed to diagonalize the Kinetic matrix", (char*) 0);
349  }
350  }
351  ncons = count; /* can't use array as conservation diagonal */
352  /* others can be in any order */
353  SYMITER(NAME) {
354  if ((s->subtype & STAT) && s->used == -1) {
355  s->varnum = count;
356  s->used = ++order; /* count and order distinct states */
357  if (s->subtype & ARRAY) {
358  int dim = s->araydim;
359  count += dim;
360  } else {
361  count++;
362  }
363  }
364  }
365  if (count == 0) {
366  diag("KINETIC contains no reactions", (char*) 0);
367  }
368  fun->used = count;
369  Sprintf(buf,
370  "static neuron::container::field_index _slist%d[%d], _dlist%d[%d]; static double "
371  "*_temp%d;\n",
372  numlist,
373  count,
374  numlist,
375  count,
376  numlist);
378  insertstr(q4, " } return _reset;\n");
379  movelist(q1, q4, procfunc);
380 
381  r = (Rlist*) emalloc(sizeof(Rlist));
382  r->reaction = reactlist;
383  reactlist = (Reaction*) 0;
384  r->symorder = (Symbol**) emalloc((unsigned) order * sizeof(Symbol*));
385  r->slist_decl = 0;
386  /*the reason that we can't just keep this info in s->varnum is that
387  more than one block can have the same state with a different varnum */
388  SYMITER(NAME) {
389  if ((s->subtype & STAT) && s->used) {
390  r->symorder[s->used - 1] = s;
391  }
392  }
393  r->nsym = order;
394  r->ncons = ncons;
395  r->position = afterbrace;
396  r->endbrace = q4->prev; /* needed for Dstate with COMPARTMENT */
397  r->sym = fun;
398  r->rlistnext = rlist;
399  rlist = r;
400  r = (Rlist*) emalloc(sizeof(Rlist));
401  r->reaction = conslist;
402  conslist = (Reaction*) 0;
403  r->sym = fun;
404  r->rlistnext = clist;
405  clist = r;
406 
407  /* handle compartlist if any */
408  rlist->capacity = (const char**) emalloc((unsigned) order * sizeof(char*));
409  for (i = 0; i < order; i++) {
410  rlist->capacity[i] = "";
411  }
412  if (compartlist) {
413  char buf1[NRN_BUFSIZE];
414  Item *q, *qexp, *qb, *qend, *q1;
415  ITERATE(q, compartlist) {
416  qexp = ITM(q);
417  q = q->next;
418  qb = ITM(q);
419  q = q->next;
420  qend = ITM(q);
421  for (q1 = qb->next; q1 != qend; q1 = q1->next) {
422  // if a state compartment variable is not used in
423  // the kinetic block then skip it
424  if (!SYM(q1)->used) {
425  continue;
426  }
427  Sprintf(buf1, "(%s)", qconcat(qexp, qb->prev));
428  rlist->capacity[SYM(q1)->used - 1] = stralloc(buf1, (char*) 0);
429  }
430  }
432  }
433 
434  SYMITER(NAME) {
435  if ((s->subtype & STAT) && s->used) {
436  s->used = 0;
437  }
438  }
439  cvode_sbegin = q3;
440  cvode_send = q4;
441  kin_items_ = newlist();
442  for (q = cvode_sbegin; q != cvode_send->next; q = q->next) {
444  }
445 }
446 
447 #if Glass
448 void fixrlst(Rlist* rlst) {
449  if (rlst->position->prev->itemtype == STRING &&
450  !strcmp(rlst->position->prev->element.str, "error =")) {
451  rlst->position = rlst->position->prev;
452  }
453 }
454 #endif
455 
456 static int ncons; /* the number of conservation equations */
457 
458 void kinetic_intmethod(Symbol* fun, const char* meth) {
459  /*derivative form*/
460  Reaction* r1;
461  Rlist *rlst, *clst;
462  int i, nstate;
463 
465  nstate = number_states(fun, &rlst, &clst);
466  if (ncons) {
467  Fprintf(stderr, "%s method ignores conservation\n", meth);
468  }
469  ncons = 0;
470  Sprintf(buf,
471  "{int _i; for(_i=0;_i<%d;_i++) _ml->data(_iml, _dlist%d[_i]) = 0.0;}\n",
472  nstate,
473  fun->u.i);
474  /*goes near beginning of block*/
475 #if Glass
476  fixrlst(rlst);
477 #endif
478  Insertstr(rlst->position, buf);
479  for (r1 = rlst->reaction; r1; r1 = r1->reactnext) {
480  genderivterms(r1, 0, 0);
481  }
482  for (i = 0; i < rlst->nsym; i++) {
483  if (rlst->capacity[i][0]) {
484  if (rlst->symorder[i]->subtype & ARRAY) {
485  Sprintf(buf,
486  "for (_i=0; _i < %d; _i++) { _ml->data(_iml, _dlist%d[_i + %d]) /= %s;}\n",
487  rlst->symorder[i]->araydim,
488  fun->u.i,
489  rlst->symorder[i]->varnum,
490  rlst->capacity[i]);
491  Insertstr(rlst->endbrace, buf);
492  } else {
493  Sprintf(buf,
494  "_ml->data(_iml, _dlist%d[%d]) /= %s;\n",
495  fun->u.i,
496  rlst->symorder[i]->varnum,
497  rlst->capacity[i]);
498  Insertstr(rlst->endbrace, buf);
499  }
500  }
501  }
502  kinlist(fun, rlst);
503 }
504 
505 void genderivterms(Reaction* r, int type, int n) {
506  Symbol* s;
507  Item* q;
508  Rterm* rt;
509  int i, j;
510 
511  if (r->rterm[1] == (Rterm*) 0 && r->krate[1]) {
512  genfluxterm(r, type, n);
513  return;
514  }
515  q = r->position;
516  for (j = 0; j < 2; j++) {
517  if (j == 0) {
518  Insertstr(q, "f_flux =");
519  } else {
520  Insertstr(q, ";\n b_flux =");
521  }
522  if (r->krate[j]) {
523  Insertstr(q, r->krate[j]);
524  } else {
525  Insertstr(q, "0.");
526  }
527  for (rt = r->rterm[j]; rt; rt = rt->rnext) {
528  for (i = 0; i < rt->num; i++) {
529  Insertstr(q, "*");
530  Insertsym(q, rt->sym);
531  if (rt->str) {
532  Sprintf(buf, "[%s]", rt->str);
533  Insertstr(q, buf);
534  }
535  }
536  }
537  }
538  Insertstr(q, ";\n");
539  for (j = 0; j < 2; j++) {
540  for (rt = r->rterm[j]; rt; rt = rt->rnext) {
541  if (!(rt->isstate)) {
542  continue;
543  }
544  Sprintf(buf, "D%s", rt->sym->name);
545  s = lookup(buf);
546  s->usage |= DEP;
547  if (rt->sym->varnum < ncons)
548  continue; /* equation reserved for conservation*/
549  if (type) {
550  Sprintf(buf, "_RHS%d(", n);
551  Insertstr(q, buf);
552  if (rt->str) {
553  Sprintf(buf, "%d + %s)", rt->sym->varnum, rt->str);
554  } else {
555  Sprintf(buf, "%d)", rt->sym->varnum);
556  }
557  Insertstr(q, buf);
558  } else {
559  Insertsym(q, s); /*needs processing in cout*/
560  if (rt->str) {
561  Sprintf(buf, "[%s]", rt->str);
562  Insertstr(q, buf);
563  }
564  }
565  if (j == 0) {
566  Insertstr(q, "-=");
567  } else {
568  Insertstr(q, "+=");
569  }
570  if (rt->num > 1) {
571  Sprintf(buf, "%d.0 *", rt->num);
572  Insertstr(q, buf);
573  }
574  Insertstr(q, "(f_flux - b_flux);\n");
575  }
576  }
577  Insertstr(q, "\n"); /* REACTION comment left in */
578 }
579 
580 void genfluxterm(Reaction* r, int type, int n) {
581  Symbol* s;
582  Rterm* rt;
583  Item* q;
584 
585  q = r->position;
586  rt = r->rterm[0];
587  if (!(rt->isstate)) {
588  diag(rt->sym->name, "must be (solved) STATE in flux reaction");
589  }
590  Sprintf(buf, "D%s", rt->sym->name);
591  s = lookup(buf);
592  if (rt->sym->varnum < ncons)
593  diag(rt->sym->name, "is conserved and has a flux");
594  /* the right hand side */
595  Insertstr(q, "f_flux = b_flux = 0.;\n");
596  if (type) {
597  Sprintf(buf, "_RHS%d(", n);
598  Insertstr(q, buf);
599  if (rt->str) {
600  Sprintf(buf, "%d + %s)", rt->sym->varnum, rt->str);
601  } else {
602  Sprintf(buf, "%d)", rt->sym->varnum);
603  }
604  Insertstr(q, buf);
605  } else {
606  Insertsym(q, s); /*needs processing in cout*/
607  if (rt->str) {
608  Sprintf(buf, "[%s]", rt->str);
609  Insertstr(q, buf);
610  }
611  }
612  if (r->krate[0]) {
613  Sprintf(buf, " -= (f_flux = (%s) * ", r->krate[0]);
614  Insertstr(q, buf);
615  Insertsym(q, rt->sym);
616  if (rt->str) {
617  Sprintf(buf, "[%s]", rt->str);
618  Insertstr(q, buf);
619  }
620  } else {
621  Insertstr(q, "+= (b_flux = ");
622  Insertstr(q, r->krate[1]);
623  }
624  Insertstr(q, ");\n");
625 
626  /* the matrix coefficient */
627  if (type && r->krate[0]) {
628  Sprintf(buf, " _MATELM%d(", n);
629  Insertstr(q, buf);
630  if (rt->str) {
631  Sprintf(buf, "%d + %s, %d + %s", rt->sym->varnum, rt->str, rt->sym->varnum, rt->str);
632  } else {
633  Sprintf(buf, "%d, %d)", rt->sym->varnum, rt->sym->varnum);
634  }
635  Insertstr(q, buf);
636  Sprintf(buf, "+= %s;\n", r->krate[0]);
637  Insertstr(q, buf);
638  }
639 }
640 
641 static int linmat; /* 1 if linear */
642 void kinetic_implicit(Symbol* fun, const char* dt, const char* mname) {
643  /*implicit equations _slist are state(t+dt) _dlist are Dstate(t)*/
644  Item* q;
645  Item* qv;
646  Reaction* r1;
647  Rlist *rlst, *clst;
648  int i, nstate, flag, firsttrans, firsttrans1;
649 
650  firsttrans = 0; /* general declarations done only for NOT_CVODE_FLAG */
651  firsttrans1 = 0;
653 
654  nstate = number_states(fun, &rlst, &clst);
655 
656  CVODE_FLAG {
657  ncons = 0;
658  Sprintf(buf, "static void* _cvsparseobj%d;\n", fun->u.i);
659  q = linsertstr(procfunc, buf);
660  Sprintf(buf, "static int _cvspth%d = %d;\n", fun->u.i, thread_data_index++);
662  Sprintf(buf,
663  " "
664  "_nrn_destroy_sparseobj_thread(static_cast<SparseObj*>(_thread[_cvspth%d].get<void*"
665  ">()));\n",
666  fun->u.i);
668  }
669  else {
670  if (!done_list) {
671  done_list = newlist();
672  done_list1 = newlist();
673  }
674  firsttrans = 1; /* declare the sparseobj and linflag*/
675  firsttrans1 = 1;
676  ITERATE(q, done_list) {
677  if (SYM(q) == fun) {
678  firsttrans = 0; /* already declared */
679  }
680  }
681  ITERATE(q, done_list1) {
682  if (SYM(q) == fun) {
683  firsttrans1 = 0; /* already declared */
684  }
685  }
686  if (firsttrans1) {
687  Lappendsym(done_list, fun);
688  Lappendsym(done_list1, fun);
689  Sprintf(buf, "static void* _sparseobj%d;\n", fun->u.i);
690  q = linsertstr(procfunc, buf);
691  Sprintf(buf, "static int _spth%d = %d;\n", fun->u.i, thread_data_index++);
693  Sprintf(buf,
694  " "
695  "_nrn_destroy_sparseobj_thread(static_cast<SparseObj*>(_thread[_spth%d].get<"
696  "void*>()));\n",
697  fun->u.i);
699  }
700  }
701  /*goes near beginning of block. Before first reaction is not
702  adequate since the first reaction may be within a while loop */
703 #if Glass
704  fixrlst(rlst);
705 #endif
706  CVODE_FLAG {
707  Insertstr(rlst->position, " b_flux = f_flux = 0.;\n");
708  }
709  Sprintf(buf,
710  "{int _i; double _dt1 = 1.0/%s;\n\
711 for(_i=%d;_i<%d;_i++){\n",
712  dt,
713  ncons,
714  nstate);
715  Insertstr(rlst->position, buf);
716 
717  qv = insertstr(rlst->position, "");
718 
720  Sprintf(buf,
721  "\
722  _RHS%d(_i) = -_dt1*(_ml->data(_iml, _slist%d[_i]) - _ml->data(_iml, _dlist%d[_i]));\n\
723  _MATELM%d(_i, _i) = _dt1;\n",
724  fun->u.i,
725  fun->u.i,
726  fun->u.i,
727  fun->u.i);
728  qv = insertstr(rlst->position, buf);
729  }
730  CVODE_FLAG {
731  Sprintf(buf,
732  "\
733  _RHS%d(_i) = _dt1*(_ml->data(_iml, _dlist%d[_i]));\n\
734  _MATELM%d(_i, _i) = _dt1;\n",
735  fun->u.i,
736  fun->u.i,
737  fun->u.i);
738  qv = insertstr(rlst->position, buf);
739  }
740  qv = insertstr(rlst->position, "");
741  Sprintf(buf, " \n}");
742  Insertstr(rlst->position, buf);
743  /* Modify to take into account compartment sizes */
744  /* separate into scalars and vectors */
745 
746  flag = 0;
747  for (i = ncons; i < rlst->nsym; i++) {
748  if (rlst->capacity[i][0]) {
749  if (!(rlst->symorder[i]->subtype & ARRAY)) {
750  if (!flag) {
751  flag = 1;
752  qv = insertstr(rlst->position, "");
753  }
754  Sprintf(buf,
755  "\n_RHS%d(%d) *= %s",
756  fun->u.i,
757  rlst->symorder[i]->varnum,
758  rlst->capacity[i]);
759  Insertstr(rlst->position, buf);
760  Sprintf(buf,
761  ";\n_MATELM%d(%d, %d) *= %s;",
762  fun->u.i,
763  rlst->symorder[i]->varnum,
764  rlst->symorder[i]->varnum,
765  rlst->capacity[i]);
766  Insertstr(rlst->position, buf);
767  }
768  }
769  }
770  if (flag) {
771  qv = insertstr(rlst->position, "");
772  }
773 
774  for (i = ncons; i < rlst->nsym; i++) {
775  if (rlst->capacity[i][0]) {
776  if (rlst->symorder[i]->subtype & ARRAY) {
777  Sprintf(buf, "\nfor (_i=0; _i < %d; _i++) {\n", rlst->symorder[i]->araydim);
778  Insertstr(rlst->position, buf);
779  qv = insertstr(rlst->position, "");
780 
781  Sprintf(buf,
782  " _RHS%d(_i + %d) *= %s",
783  fun->u.i,
784  rlst->symorder[i]->varnum,
785  rlst->capacity[i]);
786  Insertstr(rlst->position, buf);
787  Sprintf(buf,
788  ";\n_MATELM%d(_i + %d, _i + %d) *= %s;",
789  fun->u.i,
790  rlst->symorder[i]->varnum,
791  rlst->symorder[i]->varnum,
792  rlst->capacity[i]);
793  Insertstr(rlst->position, buf);
794  qv = insertstr(rlst->position, "");
795 
796  Insertstr(rlst->position, "}");
797  }
798  }
799  }
800 
801  /*----------*/
802  Insertstr(rlst->position, "}\n");
803  linmat = 1;
804  for (r1 = rlst->reaction; r1; r1 = r1->reactnext) {
806  genderivterms(r1, 1, fun->u.i);
807  }
808  genmatterms(r1, fun->u.i);
809  }
810  NOT_CVODE_FLAG { /* to end of function */
811  for (i = 0, r1 = clst->reaction; r1; r1 = r1->reactnext) {
812  i = genconservterms(i, r1, fun->u.i, rlst);
813  }
814  if (firsttrans1) {
815  Sprintf(buf, "\n#define _linmat%d %d\n", fun->u.i, linmat);
817  }
818  if (firsttrans) {
819  kinlist(fun, rlst);
820 
821 
822  if (strcmp(mname, "_advance") == 0) { /* use for simeq */
823  Sprintf(
824  buf, "\n#define _RHS%d(arg) _coef%d[arg][%d]\n", fun->u.i, fun->u.i, nstate);
826  Sprintf(buf,
827  "\n#define _MATELM%d(arg1,arg2) _coef%d[arg1][arg2]\n",
828  fun->u.i,
829  fun->u.i);
831  Sprintf(buf, "static double **_coef%d;\n", fun->u.i);
833 
834  } else { /*for sparse matrix solver*/
835  /* boilerplate for using sparse matrix solver */
836  {
837  static int first = 1;
838  if (first) {
839  first = 0;
840  Sprintf(buf, "static double *_coef%d;\n", fun->u.i);
841  qv = linsertstr(procfunc, buf);
842  vectorize_substitute(qv, "");
843  }
844  }
845  Sprintf(buf, "\n#define _RHS%d(_arg) _coef%d[_arg + 1]\n", fun->u.i, fun->u.i);
846  qv = linsertstr(procfunc, buf);
847  Sprintf(buf, "\n#define _RHS%d(_arg) _rhs[_arg+1]\n", fun->u.i);
849  Sprintf(buf,
850  "\n#define _MATELM%d(_row,_col)\
851  *(_getelm(_row + 1, _col + 1))\n",
852  fun->u.i);
853  qv = linsertstr(procfunc, buf);
854  Sprintf(buf,
855  "\n#define _MATELM%d(_row,_col) "
856  "*(_nrn_thread_getelm(static_cast<SparseObj*>(_so), _row + 1, _col + 1))\n",
857  fun->u.i);
859  }
860  }
861  } /* end of NOT_CVODE_FLAG */
862 }
863 
864 void genmatterms(Reaction* r, int fn) {
865  Symbol *s, *s1;
866  Item* q;
867  Rterm *rt, *rt1;
868  int i, j, j1, n;
869 
870  if (r->rterm[1] == (Rterm*) 0 && r->krate[1]) {
871  return; /* no fluxes go into matrix */
872  }
873 
874  q = r->position;
875  for (j = 0; j < 2; j++)
876  for (rt = r->rterm[j]; rt; rt = rt->rnext) { /*d/dstate*/
877  s = rt->sym;
878  if (!(rt->isstate)) {
879  continue;
880  }
881  /* construct the term */
882  Sprintf(buf, "_term = %s", r->krate[j]);
883  Insertstr(q, buf);
884  if (rt->num != 1) {
885  Sprintf(buf, "* %d", rt->num);
886  Insertstr(q, buf);
887  }
888  for (rt1 = r->rterm[j]; rt1; rt1 = rt1->rnext) {
889  n = rt1->num;
890  if (rt == rt1) {
891  n--;
892  }
893  for (i = 0; i < n; i++) {
894  linmat = 0;
895  Insertstr(q, "*");
896  Insertsym(q, rt1->sym);
897  if (rt1->str) {
898  Sprintf(buf, "[%s]", rt1->str);
899  Insertstr(q, buf);
900  }
901  }
902  }
903  Insertstr(q, ";\n");
904  /* put in each equation (row) */
905  for (j1 = 0; j1 < 2; j1++)
906  for (rt1 = r->rterm[j1]; rt1; rt1 = rt1->rnext) {
907  s1 = rt1->sym;
908  if (!(rt1->isstate)) {
909  continue;
910  }
911  if (s1->varnum < ncons)
912  continue;
913  Sprintf(buf, "_MATELM%d(", fn);
914  Insertstr(q, buf);
915  if (rt1->str) {
916  Sprintf(buf, "%d + %s", s1->varnum, rt1->str);
917  Insertstr(q, buf);
918  } else {
919  Sprintf(buf, "%d", s1->varnum);
920  Insertstr(q, buf);
921  }
922  if (rt->str) {
923  Sprintf(buf, ",%d + %s)", s->varnum, rt->str);
924  Insertstr(q, buf);
925  } else {
926  Sprintf(buf, ",%d)", s->varnum);
927  Insertstr(q, buf);
928  }
929  if (j == j1) {
930  Insertstr(q, " +=");
931  } else {
932  Insertstr(q, " -=");
933  }
934  if (rt1->num != 1) {
935  Sprintf(buf, "%d * ", rt1->num);
936  Insertstr(q, buf);
937  }
938  Insertstr(q, "_term;\n");
939  }
940  }
941  /* REACTION comment left in */
942 }
943 
944 void massageconserve(Item* q1, Item* q3, Item* q5) /* CONSERVE react '=' expr */
945 {
946  /* the list of states is in rterm at this time with the first at the end */
947  Reaction* r1;
948 
949  r1 = conslist;
950  conslist = (Reaction*) emalloc(sizeof(Reaction));
951  conslist->reactnext = r1;
952  conslist->rterm[0] = rterm;
953  conslist->rterm[1] = (Rterm*) 0;
954  conslist->krate[0] = qconcat(q3->next, q5);
955  conslist->krate[1] = (char*) 0;
956  /*SUPPRESS 440*/
957  replacstr(q1, "/*");
958  insertstr(q1, "");
959  /*SUPPRESS 440*/
960  Insertstr(q5->next, "*/\n");
961  /*SUPPRESS 440*/
962  conslist->position = insertstr(q5->next->next, "/*CONSERVATION*/\n");
963  rterm = (Rterm*) 0;
964 }
965 
966 int genconservterms(int eqnum, Reaction* r, int fn, Rlist* rlst) {
967  Item* q;
968  Rterm *rt, *rtdiag;
969  char eqstr[NRN_BUFSIZE];
970 
971  q = r->position;
972  /* find the term used for the equation number (important if array)*/
973  for (rtdiag = (Rterm*) 0, rt = r->rterm[0]; rt; rt = rt->rnext) {
974  if (eqnum == rt->sym->varnum) {
975  rtdiag = rt;
976  break;
977  }
978  }
979  assert(rtdiag);
980  if (rtdiag->str) {
981  Sprintf(eqstr, "%d(%d + %s", fn, eqnum, rtdiag->str);
982  eqnum += rtdiag->sym->araydim;
983  /*SUPPRESS 622*/
984  assert(0); /*could ever work only in specialized circumstances
985  when same conservation eqn used for all elements*/
986  } else {
987  Sprintf(eqstr, "%d(%d", fn, eqnum);
988  eqnum++;
989  }
990  SprintfAsrt(buf, "_RHS%s) = %s;\n", eqstr, r->krate[0]);
991  Insertstr(q, buf);
992  for (rt = r->rterm[0]; rt; rt = rt->rnext) {
993  char buf1[NRN_BUFSIZE];
994  if (rlst->capacity[rt->sym->used][0]) {
995  Sprintf(buf1, " * %s", rlst->capacity[rt->sym->used]);
996  } else {
997  buf1[0] = '\0';
998  }
999  if (!(rt->isstate)) {
1000  diag(rt->sym->name, ": only (solved) STATE are allowed in CONSERVE equations.");
1001  }
1002  if (rt->str) {
1003  if (rlst->capacity[rt->sym->used][0]) {
1004  Sprintf(buf, "_i = %s;\n", rt->str);
1005  Insertstr(q, buf);
1006  }
1007  SprintfAsrt(buf,
1008  "_MATELM%s, %d + %s) = %d%s;\n",
1009  eqstr,
1010  rt->sym->varnum,
1011  rt->str,
1012  rt->num,
1013  buf1);
1014  Insertstr(q, buf);
1015  SprintfAsrt(buf, "_RHS%s) -= %s[%s]%s", eqstr, rt->sym->name, rt->str, buf1);
1016  } else {
1017  SprintfAsrt(buf, "_MATELM%s, %d) = %d%s;\n", eqstr, rt->sym->varnum, rt->num, buf1);
1018  Insertstr(q, buf);
1019  SprintfAsrt(buf, "_RHS%s) -= %s%s", eqstr, rt->sym->name, buf1);
1020  }
1021  Insertstr(q, buf);
1022  if (rt->num != 1) {
1023  Sprintf(buf, " * %d;\n", rt->num);
1024  Insertstr(q, buf);
1025  } else {
1026  Insertstr(q, ";\n");
1027  }
1028  }
1029  return eqnum;
1030 }
1031 
1032 int number_states(Symbol* fun, Rlist** prlst, Rlist** pclst) {
1033  /* reaction list has the symorder and this info is put back in sym->varnum*/
1034  /* also index of symorder goes into sym->used */
1035  Rlist *rlst, *clst;
1036  Symbol* s;
1037  int i, istate;
1038 
1039  /*match fun with proper reaction list*/
1040  clst = clist;
1041  for (rlst = rlist; rlst && (rlst->sym != fun); rlst = rlst->rlistnext)
1042  clst = clst->rlistnext;
1043  if (rlst == (Rlist*) 0) {
1044  diag(fun->name, "doesn't exist");
1045  }
1046  *prlst = rlst;
1047  *pclst = clst;
1048  /* Number the states. */
1049  for (i = 0, istate = 0; i < rlst->nsym; i++) {
1050  s = rlst->symorder[i];
1051  s->varnum = istate;
1052  s->used = i; /* set back to 0 in kinlist */
1053  if (s->subtype & ARRAY) {
1054  istate += s->araydim;
1055  } else {
1056  istate++;
1057  }
1058  }
1059  ncons = rlst->ncons;
1060  if (fun->u.i >= MAXKINBLK) {
1061  diag("too many solve blocks", (char*) 0);
1062  }
1063  nstate_[fun->u.i] = istate;
1064  return istate;
1065 }
1066 
1067 void kinlist(Symbol* fun, Rlist* rlst) {
1068  int i;
1069  Symbol* s;
1070 
1071  if (rlst->slist_decl) {
1072  return;
1073  }
1074  rlst->slist_decl = 1;
1075  /* put slist and dlist in initlist */
1076  for (i = 0; i < rlst->nsym; i++) {
1077  s = rlst->symorder[i];
1078  slist_data(s, s->varnum, fun->u.i);
1079  if (s->subtype & ARRAY) {
1080  int dim = s->araydim;
1081  Sprintf(buf,
1082  "for(_i=0;_i<%d;_i++){_slist%d[%d+_i] = {%s_columnindex, _i};",
1083  dim,
1084  fun->u.i,
1085  s->varnum,
1086  s->name);
1088  Sprintf(
1089  buf, " _dlist%d[%d+_i] = {D%s_columnindex, _i};}\n", fun->u.i, s->varnum, s->name);
1091  } else {
1092  Sprintf(buf, "_slist%d[%d] = {%s_columnindex, 0};", fun->u.i, s->varnum, s->name);
1094  Sprintf(buf, " _dlist%d[%d] = {D%s_columnindex, 0};\n", fun->u.i, s->varnum, s->name);
1096  }
1097  s->used = 0;
1098  }
1099 }
1100 
1101 /* for now we only check CONSERVE and COMPARTMENT */
1102 void check_block(int standard, int actual, const char* mes) {
1103  if (standard != actual) {
1104  diag(mes, "not allowed in this kind of block");
1105  }
1106 }
1107 
1108 /* Syntax to take into account compartment size
1109 compart: COMPARTMENT NAME ',' expr '{' namelist '}'
1110  {massagecompart($4, $5, $7, SYM($2));}
1111  | COMPARTMENT expr '{' namelist '}'
1112  {massagecompart($2, $3, $5, SYM0);}
1113  | COMPARTMENT error {myerr("Correct syntax is: \
1114 COMPARTMENT index, expr { vectorstates }\n\
1115  COMPARTMENT expr { scalarstates }");}
1116  ;
1117 */
1118 /* implementation
1119  We save enough info here so that the rlist built in massagekinetic
1120  can point to compartment size expressions which are later used
1121  analogously to c*dv/dt and also affect the conservation equations.
1122  see Item ** Rlist->capacity[2]
1123 
1124  any index is replaced by _i.
1125  the name list is checked to make sure they are states
1126 
1127  compartlist is a list of triples of item pointers which
1128  holds the info for massagekinetic.
1129 */
1130 void massagecompart(Item* qexp, Item* qb1, Item* qb2, Symbol* indx) {
1131  Item *q, *qs;
1132 
1133  /* surround the statement with comments so that the expession
1134  will benignly exist for later use */
1135  /*SUPPRESS 440*/
1136  Insertstr(qb2->next, "*/\n");
1137 
1138  if (indx) {
1139  for (q = qexp; q != qb1; q = q->next) {
1140  if (q->itemtype == SYMBOL && SYM(q) == indx) {
1141  replacstr(q, "_i");
1142  }
1143  }
1144  /*SUPPRESS 440*/
1145  Insertstr(qexp->prev->prev->prev, "/*");
1146  } else {
1147  /*SUPPRESS 440*/
1148  Insertstr(qexp->prev, "/*");
1149  }
1150  for (q = qb1->next; q != qb2; q = qs) {
1151  qs = q->next;
1152  if (!(SYM(q)->subtype & STAT) && in_solvefor(SYM(q))) {
1153  remove(q);
1154 #if 0
1155 diag(SYM(q)->name, "must be a (solved) STATE in a COMPARTMENT statement");
1156 #endif
1157  }
1158  }
1159  if (!compartlist) {
1160  compartlist = newlist();
1161  }
1162  Lappenditem(compartlist, qexp);
1163  Lappenditem(compartlist, qb1);
1164  Lappenditem(compartlist, qb2);
1165 }
1166 
1167 void massageldifus(Item* qexp, Item* qb1, Item* qb2, Symbol* indx) {
1168  Item *q, *qs, *q1;
1169  Symbol *s, *s2;
1170 
1171  /* surround the statement with comments so that the expession
1172  will benignly exist for later use */
1173  /*SUPPRESS 440*/
1174  Insertstr(qb2->next, "*/\n");
1175 
1176  if (indx) {
1177  for (q = qexp; q != qb1; q = q->next) {
1178  if (q->itemtype == SYMBOL && SYM(q) == indx) {
1179  replacstr(q, "_i");
1180  }
1181  }
1182  /*SUPPRESS 440*/
1183  Insertstr(qexp->prev->prev->prev, "/*");
1184  } else {
1185  /*SUPPRESS 440*/
1186  Insertstr(qexp->prev, "/*");
1187  }
1188  if (!ldifuslist) {
1189  ldifuslist = newlist();
1190  }
1191  for (q = qb1->next; q != qb2; q = qs) {
1192  qs = q->next;
1193  s = SYM(q);
1194  s2 = SYM0;
1195  if (!(s->subtype & STAT) && in_solvefor(s)) {
1196  remove(q);
1197  diag(SYM(q)->name, "must be a (solved) STATE in a LONGITUDINAL_DIFFUSION statement");
1198  }
1200  Lappenditem(ldifuslist, qexp);
1201  Lappenditem(ldifuslist, qb1);
1202  /* store the COMPARTMENT volume expression for this sym */
1203  q1 = compartlist;
1204  if (q1)
1205  ITERATE(q1, compartlist) {
1206  Item *qexp, *qb1, *qb2, *q;
1207  qexp = ITM(q1);
1208  q1 = q1->next;
1209  qb1 = ITM(q1);
1210  q1 = q1->next;
1211  qb2 = ITM(q1);
1212  for (q = qb1; q != qb2; q = q->next) {
1213  if (q->itemtype == SYMBOL) {
1214  s2 = SYM(q);
1215  if (s == s2)
1216  break;
1217  }
1218  }
1219  if (s == s2) {
1220  lappenditem(ldifuslist, qexp);
1221  lappenditem(ldifuslist, qb1);
1222  break;
1223  }
1224  }
1225  if (s != s2) {
1226  diag(SYM(q)->name, "must be declared in COMPARTMENT");
1227  }
1228  lappendstr(ldifuslist, "0"); /* will be flux conc index if any */
1229  lappendstr(ldifuslist, ""); /* will be dflux/dconc if any */
1230  }
1231 }
1232 
1233 static List* kvect;
1234 
1235 void kin_vect1(Item* q1, Item* q2, Item* q4) {
1236  if (!kvect) {
1237  kvect = newlist();
1238  }
1239  Lappenditem(kvect, q1); /* static .. */
1240  Lappenditem(kvect, q2); /* sym */
1241  Lappenditem(kvect, q4); /* } */
1242 }
1243 
1244 void kin_vect2() {
1245  Item *q, *q1, *q2, *q4;
1246  return;
1247  if (kvect) {
1248  ITERATE(q, kvect) {
1249  q1 = ITM(q);
1250  q = q->next;
1251  q2 = ITM(q);
1252  q = q->next;
1253  q4 = ITM(q);
1254  kin_vect3(q1, q2, q4);
1255  }
1256  }
1257 }
1258 
1259 void kin_vect3(Item* q1, Item* q2, Item* q4) {
1260  Symbol* fun;
1261  Item *q, *first, *last, *insertitem(Item * item, Item * itm);
1262  fun = SYM(q2);
1263  last = insertstr(q4->next, "\n");
1264  first = insertstr(last, "\n/*copy of previous function */\n");
1265  for (q = q1; q != q4->next; q = q->next) {
1266  if (q == q2) {
1267  Sprintf(buf, "_vector_%s", fun->name);
1268  insertstr(last, buf);
1269  } else {
1270  insertitem(last, q);
1271  }
1272  }
1273  Sprintf(buf,
1274  "\n#undef WANT_PRAGMA\n#define WANT_PRAGMA 1\
1275 \n#undef _INSTANCE_LOOP\n#define _INSTANCE_LOOP \
1276 for (_ix = _base; _ix < _bound; ++_ix) ");
1277  insertstr(first, buf);
1278  Sprintf(buf,
1279  "\n#undef _RHS%d\n#define _RHS%d(arg) \
1280 _coef%d[arg][_ix]\n",
1281  fun->u.i,
1282  fun->u.i,
1283  fun->u.i);
1284  insertstr(first, buf);
1285  Sprintf(buf,
1286  "\n#undef _MATELM%d\n#define _MATELM%d(row,col) \
1287 _jacob%d[(row)*%d + (col)][_ix]\n",
1288  fun->u.i,
1289  fun->u.i,
1290  fun->u.i,
1291  nstate_[fun->u.i]);
1292  insertstr(first, buf);
1293 }
1294 
1295 
1296 static void cvode_kin_remove() {
1297  Item *q, *q2;
1298 #if 0
1301 #endif
1302  q2 = cvode_sbegin;
1303  ITERATE(q, kin_items_) {
1304  while (ITM(q) != q2) {
1305  assert(q2 != cvode_send); /* past the list */
1306  q2 = q2->next;
1307  remove(q2->prev);
1308  }
1309  q2 = q2->next;
1310  }
1311 }
1312 
1313 void prn(Item* q1, Item* q2) {
1314  Item *qq, *q;
1315  for (qq = q1; qq != q2; qq = qq->next) {
1316  if (qq->itemtype == ITEM) {
1317  fprintf(stderr, "itm ");
1318  q = ITM(qq);
1319  } else {
1320  q = qq;
1321  }
1322  switch (q->itemtype) {
1323  case STRING:
1324  fprintf(stderr, "%p STRING |%s|\n", q, STR(q));
1325  break;
1326  case SYMBOL:
1327  fprintf(stderr, "%p SYMBOL |%s|\n", q, SYM(q)->name);
1328  break;
1329  case ITEM:
1330  fprintf(stderr, "%p ITEM\n", q);
1331  break;
1332  default:
1333  fprintf(stderr, "%p type %d\n", q, q->itemtype);
1334  break;
1335  }
1336  }
1337 }
1338 
1339 void cvode_kinetic(Item* qsol, Symbol* fun, int numeqn, int listnum) {
1340 #if 1
1341  Item* qn;
1342  int out;
1343  Item *q, *pbeg, *pend, *qnext;
1344  /* get a list of the original items so we can keep removing
1345  the added ones to get back to the original list.
1346  */
1347  if (done_list)
1348  for (q = done_list->next; q != done_list; q = qn) {
1349  qn = q->next;
1350  if (SYM(q) == fun) {
1351  remove(q);
1352  }
1353  }
1354  kinetic_intmethod(fun, "NEURON's CVode");
1355  Lappendstr(procfunc, "\n/*CVODE ode begin*/\n");
1356  Sprintf(buf, "static int _ode_spec%d() {_reset=0;{\n", fun->u.i);
1358  Sprintf(buf,
1359  "static int _ode_spec%d(_internalthreadargsproto_) {\n"
1360  " int _reset=0;\n"
1361  " {\n",
1362  fun->u.i);
1365 
1366  Lappendstr(procfunc, "\n/*CVODE matsol*/\n");
1367  Sprintf(buf, "static int _ode_matsol%d() {_reset=0;{\n", fun->u.i);
1369  Sprintf(buf,
1370  "static int _ode_matsol%d(void* _so, double* _rhs, _internalthreadargsproto_) {int "
1371  "_reset=0;{\n",
1372  fun->u.i);
1374  cvode_flag = 1;
1375  kinetic_implicit(fun, "dt", "ZZZ");
1376  cvode_flag = 0;
1377  pbeg = procfunc->prev;
1379  pend = procfunc->prev;
1380 #if 1
1381  /* remove statements containing f_flux or b_flux */
1382  for (q = pbeg; q != pend; q = qnext) {
1383  qnext = q->next;
1384  if (q->itemtype == SYMBOL &&
1385  (strcmp(SYM(q)->name, "f_flux") == 0 || strcmp(SYM(q)->name, "b_flux") == 0)) {
1386  /* find the beginning of the statement */
1387  out = 0;
1388  for (;;) {
1389  switch (q->itemtype) {
1390  case STRING:
1391  if (strchr(STR(q), ';')) {
1392  out = 1;
1393  }
1394  break;
1395  case SYMBOL:
1396  if (SYM(q)->name[0] == ';') {
1397  out = 1;
1398  }
1399  break;
1400  }
1401  if (out) {
1402  break;
1403  }
1404  q = q->prev;
1405  }
1406  q = q->next;
1407  /* delete the statement */
1408  while (q->itemtype != SYMBOL || SYM(q)->name[0] != ';') {
1409  qnext = q->next;
1410  remove(q);
1411  q = qnext;
1412  }
1413  qnext = q->next;
1414  remove(q);
1415  }
1416  }
1417 #endif
1418  Lappendstr(procfunc, "\n/*CVODE end*/\n");
1419 
1420 #endif
1421 }
#define STRING
Definition: bbslsrv.cpp:9
#define i
Definition: md1redef.h:19
static double order(void *v)
Definition: cvodeobj.cpp:218
void copyitems(Item *q1, Item *q2, Item *qdest)
Definition: deriv.cpp:727
static int indx
Definition: deriv.cpp:289
#define PARM
Definition: modl.h:183
char buf[512]
Definition: init.cpp:13
#define nmodlCONST
Definition: modl.h:203
#define assert(ex)
Definition: hocassrt.h:24
void check_block(int standard, int actual, const char *mes)
Definition: kinetic.cpp:1102
struct Reaction Reaction
static int ncons
Definition: kinetic.cpp:456
void massagekinetic(Item *q1, Item *q2, Item *q3, Item *q4)
Definition: kinetic.cpp:256
void massagecompart(Item *qexp, Item *qb1, Item *qb2, Symbol *indx)
Definition: kinetic.cpp:1130
void reactname(Item *q1, Item *lastok, Item *q2)
Definition: kinetic.cpp:114
static List * kvect
Definition: kinetic.cpp:1233
static int nstate_[MAXKINBLK]
Definition: kinetic.cpp:83
static List * kin_items_
Definition: kinetic.cpp:29
#define MAXKINBLK
Definition: kinetic.cpp:82
#define NOT_CVODE_FLAG
Definition: kinetic.cpp:31
List * thread_cleanup_list
Definition: nocpout.cpp:111
int thread_data_index
Definition: nocpout.cpp:110
static Rterm * rterm
Definition: kinetic.cpp:40
void prn(Item *q1, Item *q2)
Definition: kinetic.cpp:1313
void massageconserve(Item *q1, Item *q3, Item *q5)
Definition: kinetic.cpp:944
int number_states(Symbol *fun, Rlist **prlst, Rlist **pclst)
Definition: kinetic.cpp:1032
static Rlist * rlist
Definition: kinetic.cpp:64
int vectorize
Definition: nocpout.cpp:78
static Reaction * reactlist
Definition: kinetic.cpp:48
void genfluxterm(Reaction *r, int type, int n)
Definition: kinetic.cpp:580
static Item * cvode_send
Definition: kinetic.cpp:28
static Item * cvode_sbegin
Definition: kinetic.cpp:28
static void cvode_kin_remove()
Definition: kinetic.cpp:1296
char * qconcat(Item *q1, Item *q2)
Definition: kinetic.cpp:85
void leftreact()
Definition: kinetic.cpp:153
static List * done_list1
Definition: kinetic.cpp:51
void massageldifus(Item *qexp, Item *qb1, Item *qb2, Symbol *indx)
Definition: kinetic.cpp:1167
static List * done_list
Definition: kinetic.cpp:50
void flux(Item *qREACTION, Item *qdir, Item *qlast)
Definition: kinetic.cpp:181
int numlist
Definition: solve.cpp:33
struct Rterm Rterm
void cvode_kinetic(Item *qsol, Symbol *fun, int numeqn, int listnum)
Definition: kinetic.cpp:1339
void kinlist(Symbol *fun, Rlist *rlst)
Definition: kinetic.cpp:1067
static Rterm * lterm
Definition: kinetic.cpp:40
struct Rlist Rlist
void massagereaction(Item *qREACTION, Item *qREACT1, Item *qlpar, Item *qcomma, Item *qrpar)
Definition: kinetic.cpp:160
static Rlist * clist
Definition: kinetic.cpp:65
void genderivterms(Reaction *r, int type, int n)
Definition: kinetic.cpp:505
int genconservterms(int eqnum, Reaction *r, int fn, Rlist *rlst)
Definition: kinetic.cpp:966
static Reaction * conslist
Definition: kinetic.cpp:49
void kin_vect1(Item *q1, Item *q2, Item *q4)
Definition: kinetic.cpp:1235
static int cvode_flag
Definition: kinetic.cpp:26
void kinetic_intmethod(Symbol *fun, const char *meth)
Definition: kinetic.cpp:458
void fixrlst(Rlist *rlst)
Definition: kinetic.cpp:448
#define CVODE_FLAG
Definition: kinetic.cpp:30
void kin_vect3(Item *q1, Item *q2, Item *q4)
Definition: kinetic.cpp:1259
void kin_vect2()
Definition: kinetic.cpp:1244
static int linmat
Definition: kinetic.cpp:641
void kinetic_implicit(Symbol *fun, const char *dt, const char *mname)
Definition: kinetic.cpp:642
void genmatterms(Reaction *r, int fn)
Definition: kinetic.cpp:864
static List * compartlist
Definition: kinetic.cpp:67
List * ldifuslist
Definition: kinetic.cpp:72
#define DEP
Definition: membfunc.hpp:64
#define DERF
Definition: model.h:114
#define STR(q)
Definition: model.h:76
#define Lappenditem
Definition: model.h:223
#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 ITEM
Definition: model.h:92
#define Linsertstr
Definition: model.h:220
#define INDEP
Definition: model.h:104
#define Lappendstr
Definition: model.h:222
#define Insertstr
Definition: model.h:217
#define ITM(q)
Definition: model.h:77
#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
Symbol * lookup(const char *)
#define NRN_BUFSIZE
Definition: model.h:6
#define ARRAY
Definition: model.h:107
List * procfunc
Definition: init.cpp:9
const char * name
Definition: init.cpp:16
List * initlist
Definition: init.cpp:8
long subtype
Definition: init.cpp:107
Item * lastok
Definition: io.cpp:11
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 * insertitem(Item *item, Item *itm)
Definition: list.cpp:110
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
#define SYMITER(arg1)
Definition: symbol.h:13
List * newlist()
The following routines support the concept of a list.
static void * emalloc(size_t size)
Definition: mpispike.cpp:30
void SprintfAsrt(char(&buf)[N], const char *fmt, Args &&... args)
assert if the Sprintf format data does not fit into buf
Definition: wrap_sprintf.h:27
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
if(ncell==0)
Definition: cellorder.cpp:785
void slist_data(Symbol *s, int indx, int findx)
Definition: nocpout.cpp:2686
int in_solvefor(Symbol *)
Definition: simultan.cpp:394
void vectorize_substitute(Item *q, const char *str)
Definition: noccout.cpp:748
NMODL parser global flags / functions.
#define diag(s)
Definition: nonlin.cpp:19
int const size_t const size_t n
Definition: nrngsl.h:10
size_t q
size_t j
s
Definition: multisend.cpp:521
short type
Definition: cabvars.h:10
static double remove(void *v)
Definition: ocdeck.cpp:205
static int nstate
Definition: simultan.cpp:226
Definition: model.h:8
struct Item * prev
Definition: model.h:13
void * element
Definition: model.h:11
short itemtype
Definition: model.h:9
struct Item * next
Definition: model.h:12
char * krate[2]
Definition: kinetic.cpp:45
Rterm * rterm[2]
Definition: kinetic.cpp:44
struct Reaction * reactnext
Definition: kinetic.cpp:43
Item * position
Definition: kinetic.cpp:46
Item * endbrace
Definition: kinetic.cpp:56
Item * position
Definition: kinetic.cpp:55
int ncons
Definition: kinetic.cpp:60
const char ** capacity
Definition: kinetic.cpp:58
Symbol ** symorder
Definition: kinetic.cpp:57
int slist_decl
Definition: kinetic.cpp:62
Reaction * reaction
Definition: kinetic.cpp:53
int nsym
Definition: kinetic.cpp:59
Symbol * sym
Definition: kinetic.cpp:54
struct Rlist * rlistnext
Definition: kinetic.cpp:61
short isstate
Definition: kinetic.cpp:38
int num
Definition: kinetic.cpp:37
struct Rterm * rnext
Definition: kinetic.cpp:34
char * str
Definition: kinetic.cpp:36
Symbol * sym
Definition: kinetic.cpp:35
Definition: model.h:47
union Symbol::@28 u
int i
Definition: model.h:52
int usage
Definition: model.h:56
int araydim
Definition: model.h:57
long subtype
Definition: model.h:49
char * name
Definition: model.h:61
int used
Definition: model.h:55
int varnum
Definition: model.h:59
int Fprintf(FILE *stream, const char *fmt, Args... args)
Definition: logger.hpp:8