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