PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/nmodl/sens.c

https://bitbucket.org/nrnhines/nrn
C | 359 lines | 201 code | 19 blank | 139 comment | 35 complexity | 4347f2f5c964c04c374544bac0a6bba8 MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0
  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. #include "modl.h"
  91. #include "parse1.h"
  92. static List *sensinfo; /* list of pairs: first is the block symbol where
  93. the SENS statement appeared. The second is
  94. a list of statements which goes after the
  95. SOLVE statement. Used for NONLINEAR blocks.
  96. So far sensmassage gets control when
  97. massageblock is almost finished
  98. */
  99. static List *statelist;
  100. static List *parmlist;
  101. extern Symbol *indepsym;
  102. int sens_parm = 0;
  103. void sensparm(qparm)
  104. Item *qparm;
  105. {
  106. if (!parmlist)
  107. parmlist = newlist();
  108. Lappendsym(parmlist, SYM(qparm));
  109. sens_parm++;
  110. }
  111. void add_sens_statelist(s)
  112. Symbol *s;
  113. {
  114. if (!statelist)
  115. statelist = newlist();
  116. Lappendsym(statelist, s);
  117. }
  118. void sensmassage(type, qfun, fn)
  119. int type;
  120. Item *qfun;
  121. {
  122. /*qfun is the list symbol for the name of the derivative block. It has
  123. a count of the number of state variables used. A copy of this symbol
  124. is made but with the name S_name and qfun is made to point to the new symbol
  125. The old function name is then the name of a new created function which
  126. contains the calls to trajecsens followed by a call to S_name to compute the
  127. Note that trajecsens itself contains calls to S_name.
  128. qfun->sym->used is then multiplied by the (1 + #sens parms used) so that
  129. the solve code doesn't need to be changed.
  130. The slist needs to be augmented and that is done here also. However
  131. since it is declared in solve.c it is necessary to access the number
  132. of parameters being used.
  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[100], dname[100];
  146. Item *q, *q1;
  147. List *senstmt; /* nonlinear sens statements (saved in sensinfo) */
  148. Symbol *oldfun, *newfun, *s;
  149. oldfun = SYM(qfun);
  150. Sprintf(buf, "S_%s", oldfun->name);
  151. if (lookup(buf)) {
  152. diag(buf, " is user defined and cant be used for SENS");
  153. }
  154. /*this is a time bomb*/
  155. newfun = install(buf, oldfun->type);
  156. newfun->subtype = oldfun->subtype;
  157. newfun->u.i = oldfun->u.i; /*the listnum*/
  158. newfun->used = oldfun->used; /*number of states*/
  159. nstate = oldfun->used;
  160. if (type == DERIVATIVE) {
  161. oldfun->used *= (1 + sens_parm);
  162. }
  163. /* even derivatives need sensinfo since envelope statements go after the
  164. SOLVE for statement */
  165. if (!sensinfo) {
  166. sensinfo = newlist();
  167. }
  168. Lappendsym(sensinfo, oldfun); /* newton will call oldfun
  169. which will merely call newfun */
  170. q = lappendsym(sensinfo, SYM0); /* the second element is a list
  171. of statements to be constructed below */
  172. senstmt = newlist();
  173. LST(q) = senstmt;
  174. SYM(qfun) = newfun; /* the derivative equations alone are now
  175. called newfun->name; oldfun will contain
  176. the trajecsens calls */
  177. /* build the oldfun function */
  178. /* In the nonlinear case all statements except call to newfun get
  179. sent to senstmt */
  180. /* in the derivative case envelope statements get sent to senstmt */
  181. Sprintf(buf, "\nstatic int %s() {\n", oldfun->name);
  182. Lappendstr(procfunc, buf);
  183. Sprintf(buf, "\nstatic int %s();\n", newfun->name);
  184. Linsertstr(procfunc, buf);
  185. newjac = 1;
  186. i=1;
  187. ITERATE(q, parmlist) {
  188. if (type == DERIVATIVE) {
  189. Sprintf(buf, "error=trajecsens(%d, _slist%d, _dlist%d,\
  190. _p, &%s, %s, %s, %d, _slist%d+%d, _dlist%d+%d);\n if(error){abort_run(error);}\n",
  191. nstate,
  192. fn, fn,
  193. SYM(q)->name, newfun->name, indepsym->name, newjac,
  194. fn, nstate*i,
  195. fn, nstate*i);
  196. Lappendstr(procfunc, buf);
  197. }else if (type == NONLINEAR) {
  198. Sprintf(buf, "error=steadysens(%d, _slist%d, _p, &%s, %s,\
  199. _dlist%d, %d, _slist%d+%d);\n if(error){abort_run(error);}\n",
  200. nstate,
  201. fn,
  202. SYM(q)->name, newfun->name, fn, newjac,
  203. fn, nstate*i);
  204. Lappendstr(senstmt, buf);
  205. }else if (type == LINEAR) {
  206. Sprintf(buf, "error=linearsens(%d, _slist%d, _p, &%s, %s,\
  207. _coef%d, %d, _slist%d+%d);\n if(error){abort_run(error);}\n",
  208. nstate,
  209. fn,
  210. SYM(q)->name, newfun->name, fn, newjac,
  211. fn, nstate*i);
  212. Lappendstr(senstmt, buf);
  213. }
  214. newjac = 0;
  215. /* define S_state_parm and DS_state_parm */
  216. ITERATE(q1, statelist) {
  217. j = SYM(q1)->varnum;
  218. Sprintf(sname, "S_%s_%s", SYM(q1)->name, SYM(q)->name);
  219. Sprintf(dname, "D%s", sname);
  220. if ((s = lookup(sname)) == SYM0) {
  221. s = install(sname, NAME);
  222. }
  223. if (SYM(q1)->subtype & ARRAY) {
  224. depinstall(1, s, SYM(q1)->araydim, "0", "1", "", ITEM0, 0, "");
  225. }else{
  226. depinstall(1, s, 0, "0", "1", "", ITEM0, 0, "");
  227. }
  228. s->usage |= DEP;
  229. if (type == DERIVATIVE) {
  230. s = lookup(dname);
  231. assert (s);
  232. s->usage |= DEP;
  233. /* initialize augmented _slist and _dlist */
  234. if (SYM(q1)->subtype & ARRAY) {
  235. Sprintf(buf, "for (_i=0;_i<%d;_i++){\
  236. _slist%d[%d+_i] = (%s + _i) - _p; _dlist%d[%d+_i] = (%s + _i) - _p;}\n", SYM(q1)->araydim,
  237. fn, j + nstate*i, sname, fn, j + nstate*i, dname);
  238. }else{
  239. Sprintf(buf, "_slist%d[%d] = &(%s) - _p; _dlist%d[%d] = &(%s) - _p;\n",
  240. fn, j + nstate*i, sname, fn, j + nstate*i, dname);
  241. }
  242. }else if (type == NONLINEAR || type == LINEAR) {
  243. if (SYM(q1)->subtype & ARRAY) {
  244. Sprintf(buf, "for (_i=0;_i<%d;_i++){\
  245. _slist%d[%d+_i] = (%s + _i) - _p;}\n", SYM(q1)->araydim,
  246. fn, j + nstate*i, sname);
  247. }else{
  248. Sprintf(buf, "_slist%d[%d] = &(%s) - _p;\n",
  249. fn, j + nstate*i, sname);
  250. }
  251. }
  252. Lappendstr(initlist, buf);
  253. }
  254. i++;
  255. }
  256. /* addition of envelope calls by modifying copy of above code
  257. create EP_state_parm, EM_state_parm using a new eplist and emlist
  258. respectively. Also create U_parm with default value of .05 if it
  259. doesn't already exist as a constant.
  260. */
  261. Sprintf(buf, "static int _eplist%d[%d], _emlist%d[%d];\n",
  262. fn, nstate*sens_parm, fn, nstate*sens_parm);
  263. Linsertstr(procfunc, buf);
  264. i = 0;
  265. ITERATE(q, parmlist) {
  266. Sprintf(buf, "envelope(_p, _slist%d, %d, %s, U_%s,\
  267. _slist%d+%d, _eplist%d + %d, _emlist%d + %d);\n",
  268. fn, nstate,
  269. SYM(q)->name, SYM(q)->name,
  270. fn, nstate*(1 + i),
  271. fn, nstate*i,
  272. fn, nstate*i);
  273. Lappendstr(senstmt, buf);
  274. /* define the uncertainty variables */
  275. Sprintf(buf, "U_%s", SYM(q)->name);
  276. IGNORE(ifnew_parminstall(buf, "0.05", "", ""));
  277. /* define EP_state_parm and EM_state_parm */
  278. ITERATE(q1, statelist) {
  279. j = SYM(q1)->varnum;
  280. Sprintf(sname, "EP_%s_%s", SYM(q1)->name, SYM(q)->name);
  281. Sprintf(dname, "EM_%s_%s", SYM(q1)->name, SYM(q)->name);
  282. if ((s = lookup(sname)) == SYM0) {
  283. s = install(sname, NAME);
  284. }
  285. if (SYM(q1)->subtype & ARRAY) {
  286. depinstall(0, s, SYM(q1)->araydim, "0", "1", "", ITEM0, 0, "");
  287. }else{
  288. depinstall(0, s, 0, "0", "1", "", ITEM0, 0, "");
  289. }
  290. s->usage |= DEP;
  291. if ((s = lookup(dname)) == SYM0) {
  292. s = install(dname, NAME);
  293. }
  294. if (SYM(q1)->subtype & ARRAY) {
  295. depinstall(0, s, SYM(q1)->araydim, "0", "1", "", ITEM0, 0, "");
  296. }else{
  297. depinstall(0, s, 0, "0", "1", "", ITEM0, 0, "");
  298. }
  299. s->usage |= DEP;
  300. /* initialize augmented _slist and _dlist */
  301. if (SYM(q1)->subtype & ARRAY) {
  302. Sprintf(buf, "for (_i=0;_i<%d;_i++){\
  303. _eplist%d[%d+_i] = (%s + _i) - _p; _emlist%d[%d+_i] = (%s + _i) - _p;}\n", SYM(q1)->araydim,
  304. fn, j + nstate*i, sname, fn, j + nstate*i, dname);
  305. }else{
  306. Sprintf(buf, "_eplist%d[%d] = &(%s) - _p; _emlist%d[%d] = &(%s) - _p;\n",
  307. fn, j + nstate*i, sname, fn, j + nstate*i, dname);
  308. }
  309. Lappendstr(initlist, buf);
  310. }
  311. i++;
  312. }
  313. if (type == DERIVATIVE) {
  314. Sprintf(buf, "return %s();\n}\n", newfun->name);
  315. }else{
  316. Sprintf(buf, "%s();\n}\n", newfun->name);
  317. }
  318. Lappendstr(procfunc, buf);
  319. freelist(&parmlist);
  320. freelist(&statelist);
  321. sens_parm = 0;
  322. }
  323. void sens_nonlin_out(q, fun)
  324. Item *q;
  325. Symbol *fun;
  326. {
  327. /* find fun in the sensinfo list and insert its statements before q */
  328. Item *q1, *q2, *q3;
  329. if (!sensinfo) return;
  330. ITERATE(q1, sensinfo) {
  331. q2 = q1->next;
  332. if (SYM(q1) == fun) {
  333. ITERATE(q3, LST(q2)) {
  334. Insertstr(q, STR(q3));
  335. }
  336. }
  337. q1 = q2;
  338. }
  339. }