NEURON
sens.cpp
Go to the documentation of this file.
1 #include <../../nmodlconf.h>
2 /* /local/src/master/nrn/src/nmodl/sens.c,v 4.2 1997/11/28 15:11:43 hines Exp */
3 /*
4 sens.c,v
5  * Revision 4.2 1997/11/28 15:11:43 hines
6  * absolute tolerance for CVODE on a per state basis.
7  * Interface is a spec of absolute tolerance within a .mod file for the
8  * declaration of a STATE as in
9  * state (units) <tolerance>
10  * Within nrniv, one specifies tolerance via
11  * tol = cvode.abstol(&var, tolerance) where var is any variable whose address
12  * can be taken (although only STATEs make use of a tolerance).
13  * The address aspect of the above is misleading since tolerances are the
14  * same for any single name, eg cvode.abstol(&v(.5)) changes tolerances for
15  * ALL membrane potentials globally. The only purpose of the address is
16  * to unambiguously identify the Symbol for the name. Perhaps string spec
17  * such as "TrigKSyn.G" will be incorporated in the future.
18  * when an absolute tolerance is changed, cvode will re-initialize the
19  * tolerances next time Cvode.re_init is called. The tolerance actually
20  * used for a STATE is the minimum between the value specified in the second
21  * arg of cvode.accuracy and the tolerance stored in the Symbol.
22  *
23  * Revision 4.1 1997/08/30 20:45:34 hines
24  * cvs problem with branches. Latest nmodl stuff should now be a top level
25  *
26  * Revision 4.0.1.1 1997/08/08 17:24:01 hines
27  * nocmodl version 4.0.1
28  *
29  * Revision 4.0 1997/08/08 17:06:28 hines
30  * proper nocmodl version number
31  *
32  * Revision 1.2 1995/09/05 17:57:58 hines
33  * allow domain limit in parameter spec. the syntax is of the form
34  * name '=' number units '[' number ',' number ']'
35  * The brackets may be changed to <...> if the syntax for arrays is ambiguous
36  *
37  * Revision 1.1.1.1 1994/10/12 17:21:37 hines
38  * NEURON 3.0 distribution
39  *
40  * Revision 9.76 90/12/07 09:27:25 hines
41  * new list structure that uses unions instead of void *element
42  *
43  * Revision 9.58 90/11/20 17:24:17 hines
44  * CONSTANT changed to PARAMETER
45  * CONSTANT now refers to variables that don't get put in .var file
46  *
47  * Revision 9.45 90/10/30 13:56:56 hines
48  * derivative blocks (this impacts kinetic and sens as well) now return
49  * _reset which can be set with RESET statement. _reset is static in the
50  * file and set to 0 on entry to a derivative or kinetic block.
51  *
52  * Revision 9.32 90/10/08 14:12:55 hines
53  * index vector instead of pointer vector for slist and dlist
54  *
55  * Revision 8.2 90/02/07 10:23:23 mlh
56  * It is important that blocks for derivative and sensitivity also
57  * be declared static before their possible use as arguments to other
58  * functions and that their body also be static to avoid multiple
59  * declaration errors.
60  *
61  * Revision 8.1 90/01/16 11:06:16 mlh
62  * error checking and cleanup after error and call to abort_run()
63  *
64  * Revision 8.0 89/09/22 17:26:57 nfh
65  * Freezing
66  *
67  * Revision 7.0 89/08/30 13:32:33 nfh
68  * Rev 7 is now Experimental; Rev 6 is Testing
69  *
70  * Revision 6.0 89/08/14 16:27:13 nfh
71  * Rev 6.0 is latest of 4.x; now the Experimental version
72  *
73  * Revision 4.1 89/08/07 15:35:26 mlh
74  * freelist now takes pointer to list pointer and 0's the list pointer.
75  * Not doing this is a bug for multiple sens blocks, etc.
76  *
77  * Revision 4.0 89/07/24 17:03:43 nfh
78  * Freezing rev 3. Rev 4 is now Experimental
79  *
80  * Revision 3.2 89/07/18 11:55:19 mlh
81  * first_time removed and MODEL_LEVEL used for declaration precedence
82  *
83  * Revision 1.2 89/07/18 11:22:19 mlh
84  * eliminate first_time, etc.
85  *
86  * Revision 1.1 89/07/06 14:50:34 mlh
87  * Initial revision
88  *
89 */
90 
91 #include "modl.h"
92 #include "parse1.hpp"
93 
94 static List* sensinfo; /* list of pairs: first is the block symbol where
95  the SENS statement appeared. The second is
96  a list of statements which goes after the
97  SOLVE statement. Used for NONLINEAR blocks.
98  So far sensmassage gets control when
99  massageblock is almost finished
100  */
101 static List* statelist;
102 static List* parmlist;
103 extern Symbol* indepsym;
104 int sens_parm = 0;
105 
106 void sensparm(Item* qparm) {
107  if (!parmlist)
108  parmlist = newlist();
109  Lappendsym(parmlist, SYM(qparm));
110  sens_parm++;
111 }
112 
114  if (!statelist)
115  statelist = newlist();
116  Lappendsym(statelist, s);
117 }
118 
119 void sensmassage(int type, Item* qfun, int fn) {
120  /*qfun is the list symbol for the name of the derivative block. It has
121  a count of the number of state variables used. A copy of this symbol
122  is made but with the name S_name and qfun is made to point to the new symbol
123  The old function name is then the name of a new created function which
124  contains the calls to trajecsens followed by a call to S_name to compute the
125  Note that trajecsens itself contains calls to S_name.
126  qfun->sym->used is then multiplied by the (1 + #sens parms used) so that
127  the solve code doesn't need to be changed.
128 
129  The slist needs to be augmented and that is done here also. However
130  since it is declared in solve.c it is necessary to access the number
131  of parameters being used.
132  */
133 
134  /* extending to nonlinear blocks. Differences:
135  Number of states remains the same. Statements built here but saved for output
136  when SOLVE is translated. No derivative variables constructed.
137  However, the full dlist is constructed since we need the last part
138  for use by EM variables
139  This has gotten much more difficult to understand since the nonlinear method
140  is merged into the code to take advantage of common code. It would be
141  conceptually simpler to merely repeat the whole process in a separate file*/
142  /* extending to linear blocks. Same as nonlinear except that
143  there is a linearsens call and we must be sure to keep proper state order */
144  int nstate, i, j, newjac;
145  char sname[256], dname[257];
146  Item *q, *q1;
147  List* senstmt; /* nonlinear sens statements (saved in sensinfo) */
148  Symbol *oldfun, *newfun, *s;
149 
150  oldfun = SYM(qfun);
151  Sprintf(buf, "S_%s", oldfun->name);
152  if (lookup(buf)) {
153  diag(buf, "is user defined and cant be used for SENS");
154  }
155  /*this is a time bomb*/
156  newfun = install(buf, oldfun->type);
157  newfun->subtype = oldfun->subtype;
158  newfun->u.i = oldfun->u.i; /*the listnum*/
159  newfun->used = oldfun->used; /*number of states*/
160  nstate = oldfun->used;
161  if (type == DERIVATIVE) {
162  oldfun->used *= (1 + sens_parm);
163  }
164  /* even derivatives need sensinfo since envelope statements go after the
165  SOLVE for statement */
166  if (!sensinfo) {
167  sensinfo = newlist();
168  }
169  Lappendsym(sensinfo, oldfun); /* newton will call oldfun
170  which will merely call newfun */
171  q = lappendsym(sensinfo, SYM0); /* the second element is a list
172  of statements to be constructed below */
173  senstmt = newlist();
174  LST(q) = senstmt;
175 
176  SYM(qfun) = newfun; /* the derivative equations alone are now
177  called newfun->name; oldfun will contain
178  the trajecsens calls */
179 
180  /* build the oldfun function */
181  /* In the nonlinear case all statements except call to newfun get
182  sent to senstmt */
183  /* in the derivative case envelope statements get sent to senstmt */
184  Sprintf(buf, "\nstatic int %s() {\n", oldfun->name);
186  Sprintf(buf, "\nstatic int %s();\n", newfun->name);
188  newjac = 1;
189  i = 1;
190  ITERATE(q, parmlist) {
191  if (type == DERIVATIVE) {
192  Sprintf(buf,
193  "error=trajecsens(%d, _slist%d, _dlist%d,\
194 _p, &%s, %s, %s, %d, _slist%d+%d, _dlist%d+%d);\n if(error){abort_run(error);}\n",
195  nstate,
196  fn,
197  fn,
198  SYM(q)->name,
199  newfun->name,
200  indepsym->name,
201  newjac,
202  fn,
203  nstate * i,
204  fn,
205  nstate * i);
207  } else if (type == NONLINEAR) {
208  Sprintf(buf,
209  "error=steadysens(%d, _slist%d, _p, &%s, %s,\
210  _dlist%d, %d, _slist%d+%d);\n if(error){abort_run(error);}\n",
211  nstate,
212  fn,
213  SYM(q)->name,
214  newfun->name,
215  fn,
216  newjac,
217  fn,
218  nstate * i);
219  Lappendstr(senstmt, buf);
220  } else if (type == LINEAR) {
221  Sprintf(buf,
222  "error=linearsens(%d, _slist%d, _p, &%s, %s,\
223  _coef%d, %d, _slist%d+%d);\n if(error){abort_run(error);}\n",
224  nstate,
225  fn,
226  SYM(q)->name,
227  newfun->name,
228  fn,
229  newjac,
230  fn,
231  nstate * i);
232  Lappendstr(senstmt, buf);
233  }
234  newjac = 0;
235  /* define S_state_parm and DS_state_parm */
236  ITERATE(q1, statelist) {
237  j = SYM(q1)->varnum;
238  Sprintf(sname, "S_%s_%s", SYM(q1)->name, SYM(q)->name);
239  Sprintf(dname, "D%s", sname);
240  if ((s = lookup(sname)) == SYM0) {
241  s = install(sname, NAME);
242  }
243  if (SYM(q1)->subtype & ARRAY) {
244  depinstall(1, s, SYM(q1)->araydim, "0", "1", "", ITEM0, 0, "");
245  } else {
246  depinstall(1, s, 0, "0", "1", "", ITEM0, 0, "");
247  }
248  s->usage |= DEP;
249  if (type == DERIVATIVE) {
250  s = lookup(dname);
251  assert(s);
252  s->usage |= DEP;
253  /* initialize augmented _slist and _dlist */
254  if (SYM(q1)->subtype & ARRAY) {
255  Sprintf(buf,
256  "for (_i=0;_i<%d;_i++){\n _slist%d[%d+_i] = %s_columnindex + _i; "
257  "_dlist%d[%d+_i] = %s_columnindex + _i;}\n",
258  SYM(q1)->araydim,
259  fn,
260  j + nstate * i,
261  sname,
262  fn,
263  j + nstate * i,
264  dname);
265  } else {
266  Sprintf(buf,
267  "_slist%d[%d] = %s_columnindex; _dlist%d[%d] = %s_columnindex;\n",
268  fn,
269  j + nstate * i,
270  sname,
271  fn,
272  j + nstate * i,
273  dname);
274  }
275  } else if (type == NONLINEAR || type == LINEAR) {
276  if (SYM(q1)->subtype & ARRAY) {
277  Sprintf(buf,
278  "for (_i=0;_i<%d;_i++){\
279 _slist%d[%d+_i] = %s_columnindex + _i;}\n",
280  SYM(q1)->araydim,
281  fn,
282  j + nstate * i,
283  sname);
284  } else {
285  Sprintf(buf, "_slist%d[%d] = %s_columnindex;\n", fn, j + nstate * i, sname);
286  }
287  }
289  }
290  i++;
291  }
292 
293  /* addition of envelope calls by modifying copy of above code
294  create EP_state_parm, EM_state_parm using a new eplist and emlist
295  respectively. Also create U_parm with default value of .05 if it
296  doesn't already exist as a constant.
297  */
298 
299  Sprintf(buf,
300  "static int _eplist%d[%d], _emlist%d[%d];\n",
301  fn,
302  nstate * sens_parm,
303  fn,
304  nstate * sens_parm);
306  i = 0;
307  ITERATE(q, parmlist) {
308  Sprintf(buf,
309  "envelope(_p, _slist%d, %d, %s, U_%s,\
310 _slist%d+%d, _eplist%d + %d, _emlist%d + %d);\n",
311  fn,
312  nstate,
313  SYM(q)->name,
314  SYM(q)->name,
315  fn,
316  nstate * (1 + i),
317  fn,
318  nstate * i,
319  fn,
320  nstate * i);
321  Lappendstr(senstmt, buf);
322 
323  /* define the uncertainty variables */
324  Sprintf(buf, "U_%s", SYM(q)->name);
325  IGNORE(ifnew_parminstall(buf, "0.05", "", ""));
326  /* define EP_state_parm and EM_state_parm */
327  ITERATE(q1, statelist) {
328  j = SYM(q1)->varnum;
329  Sprintf(sname, "EP_%s_%s", SYM(q1)->name, SYM(q)->name);
330  Sprintf(dname, "EM_%s_%s", SYM(q1)->name, SYM(q)->name);
331  if ((s = lookup(sname)) == SYM0) {
332  s = install(sname, NAME);
333  }
334  if (SYM(q1)->subtype & ARRAY) {
335  depinstall(0, s, SYM(q1)->araydim, "0", "1", "", ITEM0, 0, "");
336  } else {
337  depinstall(0, s, 0, "0", "1", "", ITEM0, 0, "");
338  }
339  s->usage |= DEP;
340 
341  if ((s = lookup(dname)) == SYM0) {
342  s = install(dname, NAME);
343  }
344  if (SYM(q1)->subtype & ARRAY) {
345  depinstall(0, s, SYM(q1)->araydim, "0", "1", "", ITEM0, 0, "");
346  } else {
347  depinstall(0, s, 0, "0", "1", "", ITEM0, 0, "");
348  }
349  s->usage |= DEP;
350 
351  /* initialize augmented _slist and _dlist */
352  if (SYM(q1)->subtype & ARRAY) {
353  Sprintf(buf,
354  "for (_i=0;_i<%d;_i++){\
355 _eplist%d[%d+_i] = %s_columnindex + _i; _emlist%d[%d+_i] = %s_columnindex + _i;}\n",
356  SYM(q1)->araydim,
357  fn,
358  j + nstate * i,
359  sname,
360  fn,
361  j + nstate * i,
362  dname);
363  } else {
364  Sprintf(buf,
365  "_eplist%d[%d] = %s_columnindex; _emlist%d[%d] = %s_columnindex;\n",
366  fn,
367  j + nstate * i,
368  sname,
369  fn,
370  j + nstate * i,
371  dname);
372  }
374  }
375  i++;
376  }
377  if (type == DERIVATIVE) {
378  Sprintf(buf, "return %s();\n}\n", newfun->name);
379  } else {
380  Sprintf(buf, "%s();\n}\n", newfun->name);
381  }
383  freelist(&parmlist);
385  sens_parm = 0;
386 }
387 
388 void sens_nonlin_out(Item* q, Symbol* fun) {
389  /* find fun in the sensinfo list and insert its statements before q */
390 
391  Item *q1, *q2, *q3;
392 
393  if (!sensinfo)
394  return;
395  ITERATE(q1, sensinfo) {
396  q2 = q1->next;
397  if (SYM(q1) == fun) {
398  ITERATE(q3, LST(q2)) {
399  Insertstr(q, STR(q3));
400  }
401  }
402  q1 = q2;
403  }
404 }
short type
Definition: cabvars.h:9
#define diag(s)
Definition: fmenu.cpp:192
Symbol * ifnew_parminstall(char *name, char *num, char *units, char *limits)
Definition: parsact.cpp:174
char buf[512]
Definition: init.cpp:13
#define assert(ex)
Definition: hocassrt.h:32
#define i
Definition: md1redef.h:12
#define STR(q)
Definition: model.h:87
#define SYM0
Definition: model.h:74
#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 IGNORE(arg)
Definition: model.h:247
#define SYM(q)
Definition: model.h:86
#define Sprintf
Definition: model.h:233
#define LST(q)
Definition: model.h:90
#define Lappendsym
Definition: model.h:244
#define DEP
Definition: model.h:116
#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
long subtype
Definition: init.cpp:215
void freelist(List **plist)
Definition: list.cpp:57
List * newlist()
Definition: list.cpp:47
Item * lappendsym(List *list, Symbol *sym)
Definition: list.cpp:142
void depinstall(int type, Symbol *n, int index, char *from, char *to, char *units, Item *qs, int makeconst, char *abstol)
Definition: parsact.cpp:295
size_t q
size_t j
#define lookup
Definition: redef.h:90
#define install
Definition: redef.h:82
static List * sensinfo
Definition: sens.cpp:94
void sens_nonlin_out(Item *q, Symbol *fun)
Definition: sens.cpp:388
void sensparm(Item *qparm)
Definition: sens.cpp:106
static List * parmlist
Definition: sens.cpp:102
static List * statelist
Definition: sens.cpp:101
void add_sens_statelist(Symbol *s)
Definition: sens.cpp:113
int sens_parm
Definition: sens.cpp:104
Symbol * indepsym
Definition: declare.cpp:11
void sensmassage(int type, Item *qfun, int fn)
Definition: sens.cpp:119
static int nstate
Definition: simultan.cpp:221
Definition: model.h:15
struct Item * next
Definition: model.h:19
Definition: model.h:57
int i
Definition: model.h:62
int usage
Definition: model.h:66
short type
Definition: model.h:58
long subtype
Definition: model.h:59
union Symbol::@18 u
char * name
Definition: model.h:72
int used
Definition: model.h:65