NEURON
simultan.cpp
Go to the documentation of this file.
1 #include <../../nmodlconf.h>
2 #include "modl.h"
3 #include "parse1.hpp"
4 #include "symbol.h"
5 
6 extern int sens_parm;
7 extern int numlist;
8 static List *eqnq;
9 
10 int nonlin_common(Item*, int);
11 
12 void solv_nonlin(Item* qsol, Symbol* fun, Symbol* method, int numeqn, int listnum)
13 {
14  Sprintf(buf, "%s(%d,_slist%d, _p, %s, _dlist%d);\n",
15  method->name, numeqn, listnum, fun->name, listnum);
16  replacstr(qsol, buf);
17  /* if sens statement appeared in fun then the steadysens call list,
18  built during the massagenonlin phase
19  gets added after the call to newton */
20  sens_nonlin_out(qsol->next, fun);
21 }
22 
23 void solv_lineq(Item* qsol, Symbol* fun, Symbol* method, int numeqn, int listnum)
24 {
25  Sprintf(buf, " 0; %s();\n error = %s(%d, _coef%d, _p, _slist%d);\n",
26  fun->name, method->name, numeqn, listnum, listnum);
27  replacstr(qsol, buf);
28  sens_nonlin_out(qsol->next, fun);
29 }
30 
31 void eqnqueue(Item* q1)
32 {
33  Item *lq;
34 
35  if (!eqnq) {
36  eqnq = newlist();
37  }
38  lq = lappendsym(eqnq, SYM0);
39  ITM(lq) = q1;
40  return;
41 }
42 
43 static void freeqnqueue()
44 {
45  freelist(&eqnq);
46 }
47 
48 /* args are --- nonlinblk: NONLINEAR NAME stmtlist '}' */
49 void massagenonlin(Item* q1, Item* q2, Item* q3, Item* q4, int sensused)
50 {
51 /* declare a special _counte variable to number the equations.
52 before each equation we increment it by 1 during run time. This
53 gives us a current equation number */
54  Symbol *nonfun;
55 
56  /* all this junk is still in the intoken list */
57  Sprintf(buf, "static void %s();\n", SYM(q2)->name);
59  replacstr(q1, "\nstatic void"); Insertstr(q3, "()\n");
60  Insertstr(q3->next, " int _counte = -1;\n");
61  nonfun = SYM(q2);
62  if ((nonfun->subtype) & NLINF && nonfun->u.i) {
63  diag("NONLINEAR merging not implemented", (char *)0);
64  }
65  numlist++;
66  nonfun->subtype |= NLINF;
67  nonfun->u.i = numlist;
68  nonfun->used = nonlin_common(q4, sensused);
69  movelist(q1, q4, procfunc);
70  if (sensused) {
71  sensmassage(NONLINEAR, q2, numlist);
72  }
73 }
74 
75 int nonlin_common(Item* q4, int sensused) /* used by massagenonlin() and mixed_eqns() */
76 {
77  Item *lq, *qs, *q;
78  int i, counts = 0, counte = 0, using_array;
79  Symbol *s;
80 
81  using_array=0;
82  SYMITER_STAT {
83  if (s->used) {
84  s->varnum = counts;
85 #if CVODE
86  slist_data(s, counts, numlist);
87 #endif
88  if (s->subtype & ARRAY) {int dim = s->araydim;
89  using_array=1;
90  Sprintf(buf, "for(_i=0;_i<%d;_i++){_slist%d[%d+_i] = (%s + _i) - _p;}\n"
91  ,dim, numlist , counts, s->name);
92  counts += dim;
93  }else{
94  Sprintf(buf, "_slist%d[%d] = &(%s) - _p;\n",
95  numlist, counts, s->name);
96  counts++;
97  }
99  s->used = 0;
100  if (sensused) {
102  }
103  }
104  }
105 
106  ITERATE(lq, eqnq) {
107  char *eqtype = SYM(ITM(lq))->name;
108  if (strcmp(eqtype, "~+") == 0) { /* add equation to previous */
109  if (counte == -1) {
110  diag("no previous equation for adding terms", (char *)0);
111  }
112  Sprintf(buf, "_dlist%d[_counte] +=", numlist);
113  } else if (eqtype[0] == 'D') {
114  /* derivative equations using implicit method */
115  int count_deriv = SYM(ITM(lq))->araydim;
116  Sprintf(buf, "_dlist%d[++_counte] =", numlist);
117  counte += count_deriv;
118  }else{
119  Sprintf(buf, "_dlist%d[++_counte] =", numlist);
120  counte++;
121  }
122  replacstr(ITM(lq), buf);
123  }
124  if (!using_array) {
125  if(counte != counts) {
126 Sprintf(buf ,"Number of equations, %d, does not equal number, %d", counte, counts);
127  diag(buf, "of states used");
128  }
129  } else {
130 #if 1 /* can give message when running */
131 Sprintf(buf, "if(_counte != %d) printf( \"Number of equations, %%d,\
132  does not equal number of states, %d\", _counte + 1);\n",
133  counts-1, counts);
134  Insertstr(q4, buf);
135 #endif
136  }
137  if (counte == 0) {
138  diag("NONLINEAR contains no equations", (char *)0);
139  }
140  freeqnqueue();
141 Sprintf(buf, "static int _slist%d[%d]; static double _dlist%d[%d];\n",
142 numlist, counts*(1 + sens_parm), numlist, counts);
143  q = linsertstr(procfunc, buf);
144 Sprintf(buf, "static int _slist%d[%d];\n",
145 numlist, counts*(1 + sens_parm));
147  return counts;
148 }
149 
150 Item *mixed_eqns(Item* q2, Item* q3, Item* q4) /* name, '{', '}' */
151 {
152  int counts;
153  Item *qret;
154  Item* q;
155 
156  if (!eqnq) {
157  return ITEM0; /* no nonlinear algebraic equations */
158  }
159  /* makes use of old massagenonlin split into the guts and
160  the header stuff */
161  numlist++;
162  counts = nonlin_common(q4, 0);
163  Insertstr(q4, "}");
164  q = insertstr(q3, "{ static int _recurse = 0;\n int _counte = -1;\n");
165  sprintf(buf, "{ double* _savstate%d = _thread[_dith%d]._pval;\n\
166  double* _dlist%d = _thread[_dith%d]._pval + %d;\n int _counte = -1;\n",
167 numlist-1, numlist-1,
168 numlist, numlist-1, counts);
170  Insertstr(q3, "if (!_recurse) {\n _recurse = 1;\n");
171  Sprintf(buf, "error = newton(%d,_slist%d, _p, %s, _dlist%d);\n",
172  counts, numlist, SYM(q2)->name, numlist);
173  qret = insertstr(q3, buf);
174  Sprintf(buf, "error = nrn_newton_thread(_newtonspace%d, %d,_slist%d, _p, %s, _dlist%d, _ppvar, _thread, _nt);\n",
175  numlist-1, counts, numlist, SYM(q2)->name, numlist);
176  vectorize_substitute(qret, buf);
177  Insertstr(q3, "_recurse = 0; if(error) {abort_run(error);}}\n");
178  return qret;
179 }
180 
181 /* linear simultaneous equations */
182 /* declare a _counte variable to dynamically contain the current
183 equation number. This is necessary to allow use of state vectors.
184 It is no longer necessary to count equations here but we do it
185 anyway in case of future move to named equations.
186 It is this change which requires a varnum field in Symbols for states
187 since the arraydim field cannot be messed with anymore.
188 */
189 static int nlineq = -1; /* actually the current index of the equation */
190  /* is only good if there are no arrays */
191 static int using_array; /* 1 if vector state in equations */
192 static int nstate = 0;
193 static Symbol *linblk;
194 static Symbol *statsym;
195 
196 void init_linblk(Item* q) /* NAME */
197 {
198  using_array = 0;
199  nlineq = -1;
200  nstate = 0;
201  linblk = SYM(q);
202  numlist++;
203 }
204 
205 void init_lineq(Item* q1) /* the colon */
206 {
207  if (strcmp(SYM(q1)->name, "~+") == 0) {
208  replacstr(q1, "");
209  }else {
210  nlineq++; /* current index will start at 0 */
211  replacstr(q1, " ++_counte;\n");
212  }
213 }
214 
215 static char *indexstr; /* set in lin_state_term, used in linterm */
216 
217 void lin_state_term(Item* q1, Item* q2) /* term last*/
218 {
219  char *qconcat(Item*, Item*); /* but puts extra ) at end */
220 
221  statsym = SYM(q1);
222  replacstr(q1, "1.0");
223  if (statsym->subtype & ARRAY) {
224  indexstr = qconcat(q1->next->next, q2->prev);
225  deltokens(q1->next, q2->prev); /*can't erase lastok*/
226  replacstr(q2, "");
227  }
228  if (statsym->used == 1) {
229  statsym->varnum = nstate;
230  if (statsym->subtype & ARRAY) {int dim = statsym->araydim;
231  using_array=1;
232  Sprintf(buf, "for(_i=0;_i<%d;_i++){_slist%d[%d+_i] = (%s + _i) - _p;}\n"
233  ,dim, numlist , nstate, statsym->name);
234  nstate += dim;
235  }else{
236  Sprintf(buf, "_slist%d[%d] = &(%s) - _p;\n",
237  numlist, nstate, statsym->name);
238  nstate++;
239  }
241  }
242 }
243 
244 void linterm(Item* q1, Item* q2, int pstate, int sign) /*primary, last ,, */
245 {
246  char *signstr;
247 
248  if (pstate == 0) {
249  sign *= -1;
250  }
251  if (sign == -1) {
252  signstr = " -= ";
253  } else {
254  signstr = " += ";
255  }
256 
257  if (pstate == 1) {
258  if (statsym->subtype & ARRAY) {
259  Sprintf(buf, "_coef%d[_counte][%d + %s]%s",
260  numlist, statsym->varnum, indexstr, signstr);
261  } else {
262  Sprintf(buf, "_coef%d[_counte][%d]%s",
263  numlist, statsym->varnum, signstr);
264  }
265  Insertstr(q1, buf);
266  } else if (pstate == 0) {
267  Sprintf(buf, "_RHS%d(_counte)%s", numlist, signstr);
268  Insertstr(q1, buf);
269  }else{
270  diag("more than one state in preceding term", (char *)0);
271  }
272  Insertstr(q2->next, ";\n");
273 }
274 
275 void massage_linblk(Item* q1, Item* q2, Item* q3, Item* q4, int sensused) /* LINEAR NAME stmtlist '}' */
276 {
277  Item *qs;
278  Symbol *s;
279  int i;
280 
281 #if LINT
282 assert(q2);
283 #endif
284  if (++nlineq == 0) {
285  diag(linblk->name, "has no equations");
286  }
287  Sprintf(buf, "static void %s();\n", SYM(q2)->name);
289  replacstr(q1, "\nstatic void"); Insertstr(q3, "()\n");
290  Insertstr(q3->next, " int _counte = -1;\n");
291  linblk->subtype |= LINF;
292  linblk->u.i = numlist;
293  SYMITER(NAME){
294  if ((s->subtype &STAT) && s->used) {
295  if (sensused) {
297  }
298  s->used = 0;
299  }
300  }
301  if (!using_array) {
302  if (nlineq != nstate) {
303 Sprintf(buf,"Number states, %d, unequal to equations, %d in ", nstate, nlineq);
304  diag(buf, linblk->name);
305  }
306  } else {
307 #if 1 /* can give message when running */
308 Sprintf(buf, "if(_counte != %d) printf( \"Number of equations, %%d,\
309  does not equal number of states, %d\", _counte + 1);\n",
310  nstate-1, nstate);
311  Insertstr(q4, buf);
312 #endif
313  }
314  linblk->used = nstate;
315  Sprintf(buf, "static int _slist%d[%d];static double **_coef%d;\n",
316  numlist, nstate*(1 + sens_parm), numlist);
318  Sprintf(buf, "\n#define _RHS%d(arg) _coef%d[arg][%d]\n",
321  Sprintf(buf, "if (_first) _coef%d = makematrix(%d, %d);\n",
322  numlist, nstate, nstate+1);
324  Sprintf(buf, "zero_matrix(_coef%d, %d, %d);\n{\n",
325  numlist, nstate, nstate+1);
326  Insertstr(q3->next, buf);
327  Insertstr(q4, "\n}\n");
328  movelist(q1, q4, procfunc);
329  if (sensused) {
330  sensmassage(LINEAR, q2, numlist);
331  }
332  nstate = 0; nlineq = 0;
333 }
334 
335 
336 /* It is sometimes convenient to not use some states in solving equations.
337  We use the SOLVEFOR statement to list the states in LINEAR, NONLINEAR,
338  and KINETIC blocks that are to be treated as states in fact. States
339  not listed are treated in that block as assigned variables.
340  If the SOLVEFOR statement is absent all states are assumed to be in the
341  list.
342 
343  Syntax is:
344  blocktype blockname [SOLVEFOR name, name, ...] { statement }
345 
346  The implementation uses the varname: production that marks the state->used
347  record. The old if statement was
348  if (inequation && (SYM($1)->subtype & STAT)) { then mark states}
349  now we add && in_solvefor() to indicate that it Really should be marked.
350  The hope is that no further change to diagnostics for LINEAR or NONLINEAR
351  will be required. Some more work on KINETIC is required since the checking
352  on whether a name is a STAT is done much later.
353  The solveforlist is freed at the end of each block.
354 */
355 
357 
359 {
360  Item *q;
361 
362  if (!solveforlist) {
363  return 1;
364  }
365  ITERATE(q, solveforlist) {
366  if (s == SYM(q)) {
367  return 1;
368  }
369  }
370  return 0;
371 }
void deltokens(Item *q1, Item *q2)
Definition: list.cpp:219
#define assert(ex)
Definition: hocassrt.h:26
Item * mixed_eqns(Item *q2, Item *q3, Item *q4)
Definition: simultan.cpp:150
#define diag(s)
Definition: fmenu.cpp:188
int in_solvefor(Symbol *s)
Definition: simultan.cpp:358
#define ITERATE(itm, lst)
Definition: model.h:25
#define SYM(q)
Definition: model.h:86
#define SYMITER_STAT
Definition: symbol.h:14
#define ITEM0
Definition: model.h:22
Item * lappendsym(List *list, Symbol *sym)
Definition: list.cpp:161
void init_linblk(Item *q)
Definition: simultan.cpp:196
List * initlist
Definition: init.cpp:8
char * name
Definition: model.h:72
struct Item * prev
Definition: model.h:20
void sensmassage(int type, Item *qfun, int fn)
Definition: sens.cpp:121
struct Item * next
Definition: model.h:19
sprintf(buf," if (secondorder) {\ " int _i;\" " for(_i=0;_i< %d;++_i) {\" " _p[_slist%d[_i]]+=dt *_p[_dlist%d[_i]];\" " }}\", numeqn, listnum, listnum)
int i
Definition: model.h:62
void init_lineq(Item *q1)
Definition: simultan.cpp:205
static int nlineq
Definition: simultan.cpp:189
Definition: model.h:15
char * qconcat(Item *q1, Item *q2)
Definition: kinetic.cpp:125
#define Insertstr
Definition: model.h:255
int nonlin_common(Item *, int)
Definition: simultan.cpp:75
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
static Symbol * linblk
Definition: simultan.cpp:193
#define sign(x)
Definition: qrfactor.c:52
void solv_nonlin(Item *qsol, Symbol *fun, Symbol *method, int numeqn, int listnum)
Definition: simultan.cpp:12
List * procfunc
Definition: init.cpp:9
static Symbol * statsym
Definition: simultan.cpp:194
void vectorize_substitute(Item *q, char *str)
static int nstate
Definition: simultan.cpp:192
Item * linsertstr(List *list, char *str)
Definition: list.cpp:143
Definition: model.h:57
int numlist
Definition: solve.cpp:38
char * name
Definition: init.cpp:16
List * newlist()
Definition: list.cpp:50
void eqnqueue(Item *q1)
Definition: simultan.cpp:31
#define NLINF
Definition: model.h:127
#define Lappendstr
Definition: model.h:260
void massagenonlin(Item *q1, Item *q2, Item *q3, Item *q4, int sensused)
Definition: simultan.cpp:49
NMODL parser global flags / functions.
void solv_lineq(Item *qsol, Symbol *fun, Symbol *method, int numeqn, int listnum)
Definition: simultan.cpp:23
long subtype
Definition: model.h:59
static void freeqnqueue()
Definition: simultan.cpp:43
void sens_nonlin_out(Item *q, Symbol *fun)
Definition: sens.cpp:337
int used
Definition: model.h:65
Item * insertstr(Item *item, char *str)
Definition: list.cpp:108
int sens_parm
Definition: sens.cpp:104
int araydim
Definition: model.h:67
void freelist(List **plist)
Definition: list.cpp:61
#define LINF
Definition: model.h:126
#define i
Definition: md1redef.h:12
#define Linsertstr
Definition: model.h:258
char buf[512]
Definition: init.cpp:13
void lin_state_term(Item *q1, Item *q2)
Definition: simultan.cpp:217
#define STAT
Definition: model.h:117
void replacstr(Item *q, char *s)
Definition: list.cpp:250
void massage_linblk(Item *q1, Item *q2, Item *q3, Item *q4, int sensused)
Definition: simultan.cpp:275
#define Sprintf
Definition: model.h:248
union Symbol::@18 u
static List * eqnq
Definition: simultan.cpp:8
#define SYM0
Definition: model.h:74
size_t q
void slist_data(Symbol *s, int indx, int findx)
int varnum
Definition: model.h:69
void add_sens_statelist(Symbol *)
Definition: sens.cpp:114
void linterm(Item *q1, Item *q2, int pstate, int sign)
Definition: simultan.cpp:244
static int using_array
Definition: simultan.cpp:191
List * solveforlist
Definition: simultan.cpp:356
#define ITM(q)
Definition: model.h:88
#define SYMITER(arg1)
Definition: symbol.h:9
static char * indexstr
Definition: simultan.cpp:215