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