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