NEURON
nonlin.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 #include <stdlib.h>
3 #include <math.h>
4 #include "parse.hpp"
5 #include "hocparse.h"
6 #include "equation.h"
7 #include "lineq.h"
8 #include "code.h"
9 
10 
11 int hoc_do_equation; /* switch for determining access to dep vars */
12 int* hoc_access; /* links to next accessed variables */
13 int hoc_var_access; /* variable number as pointer into access array */
14 
15 
16 static double** varble; /* pointer to symbol values */
17 typedef struct elm* Elm;
18 
19 #define diag(s) hoc_execerror(s, (char*) 0);
20 
21 void hoc_dep_make(void) /* tag the variable as dependent with a variable number */
22 {
23 #if !OCSMALL
24  Symbol* sym;
25  unsigned* numpt = 0;
26 
27  sym = hoc_spop();
28  switch (sym->type) {
29  case UNDEF:
30  hoc_execerror(sym->name, "undefined in dep_make");
31  sym->type = VAR;
32  OPVAL(sym) = (double*) emalloc(sizeof(double));
33  *(OPVAL(sym)) = 0.;
34  case VAR:
35  if (sym->subtype != NOTUSER) {
36  hoc_execerror(sym->name, "can't be a dependent variable");
37  }
38  if (!is_array(*sym)) {
39  numpt = &(sym->s_varn);
40  } else {
41  Arrayinfo* aray = OPARINFO(sym);
42  if (sym->s_varn == 0) /* allocate varnum array */
43  {
44  int total = 1;
45  int i;
46  for (i = 0; i < aray->nsub; i++)
47  total *= (aray->sub)[i];
48  aray->a_varn = (unsigned*) ecalloc((unsigned) total, sizeof(unsigned));
49  sym->s_varn = (unsigned) total; /* set_varble() uses this */
50  }
51  numpt = &((aray->a_varn)[hoc_araypt(sym, OBJECTVAR)]);
52  }
53  break;
54 
55  default:
56  hoc_execerror(sym->name, "can't be a dependent variable");
57  }
58  if (*numpt > 0)
59  hoc_execerror(sym->name, "made dependent twice");
60  *numpt = ++neqn;
61 #endif
62 }
63 
64 
65 void init_access(void) /* zero the access array */
66 {
67 #if !OCSMALL
68  if (hoc_access != (int*) 0)
69  free((char*) hoc_access);
70  hoc_access = (int*) ecalloc((neqn + 1), sizeof(int));
71  hoc_var_access = -1;
72 #endif
73 }
74 
75 static void eqn_space(void); /* reallocate space for matrix */
76 static void set_varble(void); /* set up varble array by searching for tags */
77 static void eqn_side(int lhs);
78 static unsigned row;
79 static unsigned maxeqn;
80 
81 void hoc_eqn_name(void) /* save row number for lhs and/or rhs */
82 {
83 #if !OCSMALL
84 
85  if (maxeqn != neqn) /* discard equations and reallocate space */
86  {
87  eqn_space();
88  set_varble();
89  }
90  init_access();
91  hoc_do_equation = 1;
92  hoc_eval();
93  hoc_do_equation = 0;
94  if (hoc_var_access < 1)
95  hoc_execerror("illegal equation name", (hoc_pc - 2)->sym->name);
97  hoc_nopop();
98 #endif
99 }
100 
101 static void set_varble(void) { /* set up varble array by searching for tags */
102 #if !OCSMALL
103  Symbol* sp;
104 
105  for (sp = hoc_symlist->first; sp != (Symbol*) 0; sp = sp->next) {
106  if (sp->s_varn != 0) {
107  if (sp->type == VAR) {
108  if (!is_array(*sp)) {
109  varble[sp->s_varn] = OPVAL(sp);
110  } else {
111  int i;
112  Arrayinfo* aray = OPARINFO(sp);
113  for (i = 0; i < sp->s_varn; i++)
114  if ((aray->a_varn)[i] > 0)
115  varble[(aray->a_varn)[i]] = OPVAL(sp) + i;
116  }
117  }
118  }
119  }
120 #endif
121 }
122 
123 static double Delta = .001; /* variable variation */
124 
125 void hoc_eqinit(void) /* built in function to initialize equation solver */
126 {
127 #if !OCSMALL
128  Symbol* sp;
129 
130  if (ifarg(1))
131  Delta = *getarg(1);
132  for (sp = hoc_symlist->first; sp != (Symbol*) 0; sp = sp->next) {
133  if (sp->s_varn != 0) {
134  if (is_array(*sp)) {
135  if (OPARINFO(sp)->a_varn != (unsigned*) 0)
136  free((char*) (OPARINFO(sp)->a_varn));
137  }
138  sp->s_varn = 0;
139  }
140  }
141  neqn = 0;
142  eqn_space();
143 #endif
144  hoc_ret();
145  hoc_pushx(0.);
146 }
147 
148 void hoc_eqn_init(void) /* initialize equation row */
149 {
150 #if !OCSMALL
151  struct elm* el;
152 
153  for (el = rowst[row]; el != (struct elm*) 0; el = el->c_right)
154  el->value = 0.;
155  rhs[row] = 0.;
156 #endif
157 }
158 
159 void hoc_eqn_lhs(void) /* add terms to left hand side */
160 {
161  eqn_side(1);
162 }
163 
164 void hoc_eqn_rhs(void) /* add terms to right hand side */
165 {
166  eqn_side(0);
167 }
168 
169 
170 static void eqn_side(int lhs) {
171 #if !OCSMALL
172  int i;
173  struct elm* el;
174  double f0, f1;
175  Inst* savepc = hoc_pc;
176 
177  init_access();
178  hoc_do_equation = 1;
179  hoc_execute(savepc);
180  hoc_do_equation = 0;
181 
182  if (lhs) {
183  f0 = hoc_xpop();
184  } else {
185  f0 = -hoc_xpop();
186  }
187 
188  rhs[row] -= f0;
189  for (i = hoc_var_access; i > 0; i = hoc_access[i]) {
190  *varble[i] += Delta;
191  hoc_execute(savepc);
192  *varble[i] -= Delta;
193  if (lhs) {
194  f1 = hoc_xpop();
195  } else {
196  f1 = -hoc_xpop();
197  }
198  el = getelm((struct elm*) 0, row, (unsigned) i);
199  el->value += (f1 - f0) / Delta;
200  }
201  hoc_pc++;
202 #endif
203 }
204 
205 static void eqn_space(void) { /* reallocate space for matrix */
206 #if !OCSMALL
207  int i;
208  struct elm* el;
209 
210  if (maxeqn > 0 && rowst == (Elm*) 0)
211  diag("matrix coefficients cannot be released");
212  for (i = 1; i <= maxeqn; i++)
213  for (el = rowst[i]; el; el = el->c_right)
214  free((char*) el);
215  maxeqn = neqn;
216  if (varble)
217  free((char*) varble);
218  if (rowst)
219  free((char*) rowst);
220  if (colst)
221  free((char*) colst);
222  if (eqord)
223  free((char*) eqord);
224  if (varord)
225  free((char*) varord);
226  if (rhs)
227  free((char*) rhs);
228  varble = (double**) 0;
229  rowst = colst = (Elm*) 0;
230  eqord = varord = (unsigned*) 0;
231  rhs = (double*) 0;
232  rowst = (Elm*) ecalloc((maxeqn + 1), sizeof(struct elm*));
233  varble = (double**) emalloc((maxeqn + 1) * sizeof(double*));
234  colst = (Elm*) ecalloc((maxeqn + 1), sizeof(struct elm*));
235  eqord = (unsigned*) emalloc((maxeqn + 1) * sizeof(unsigned));
236  varord = (unsigned*) emalloc((maxeqn + 1) * sizeof(unsigned));
237  rhs = (double*) emalloc((maxeqn + 1) * sizeof(double));
238  for (i = 1; i <= maxeqn; i++) {
239  eqord[i] = i;
240  varord[i] = i;
241  }
242 #endif
243 }
244 
245 void hoc_Prmat(void) {
246 #if !OCSMALL
247  prmat();
248 #endif
249  hoc_ret();
250  hoc_pushx(1.);
251 }
252 
253 void hoc_solve(void) {
254 #if !OCSMALL
255  /* Sum is a measure of the dependent variable accuracy
256  and how well the equations are solved */
257 
258  int i;
259  double sum;
260  struct elm* el;
261 
262  sum = 0.;
263  for (i = 1; i <= neqn; i++)
264  sum += fabs(rhs[i]);
265  if (!matsol())
266  diag("indeterminate system");
267  for (i = 1; i <= neqn; i++) {
268  *varble[varord[i]] += rhs[eqord[i]];
269  sum += fabs(rhs[i]);
270  }
271  /* free all elements */
272  for (i = 1; i <= neqn; i++) {
273  struct elm* el2;
274  for (el = rowst[i]; el != (struct elm*) 0; el = el2) {
275  el2 = el->c_right;
276  free(el);
277  }
278  rowst[i] = colst[i] = (struct elm*) 0;
279  }
280 #else
281  double sum = 0;
282 #endif
283  hoc_ret();
284  hoc_pushx(sum);
285 }
void hoc_eval(void)
Definition: code.cpp:1827
#define i
Definition: md1redef.h:19
double hoc_xpop()
Definition: code.cpp:903
void hoc_ret()
Symbol * hoc_spop()
Definition: code.cpp:928
void hoc_nopop()
Definition: code.cpp:972
#define NOTUSER
Definition: hocdec.h:82
#define getarg
Definition: hocdec.h:17
#define OPARINFO(sym)
Definition: hocdec.h:239
bool is_array(const Symbol &sym)
Definition: hocdec.h:136
#define OPVAL(sym)
Definition: hocdec.h:234
int hoc_araypt(Symbol *, int)
Definition: code.cpp:2340
void hoc_pushx(double)
Definition: code.cpp:779
int matsol(void)
Definition: lineq.cpp:15
#define colst
Definition: lineq.h:2
#define rhs
Definition: lineq.h:6
#define getelm
Definition: lineq.h:8
#define varord
Definition: lineq.h:5
#define eqord
Definition: lineq.h:4
#define neqn
Definition: lineq.h:3
#define rowst
Definition: lineq.h:1
fabs
Definition: extdef.h:3
void hoc_execerror(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:39
void * ecalloc(size_t n, size_t size)
Definition: nrnoc_aux.cpp:85
static void * emalloc(size_t size)
Definition: mpispike.cpp:30
void hoc_eqinit(void)
Definition: nonlin.cpp:125
static void eqn_side(int lhs)
Definition: nonlin.cpp:170
void init_access(void)
Definition: nonlin.cpp:65
static unsigned row
Definition: nonlin.cpp:78
void hoc_dep_make(void)
Definition: nonlin.cpp:21
void hoc_eqn_init(void)
Definition: nonlin.cpp:148
void hoc_eqn_name(void)
Definition: nonlin.cpp:81
int hoc_var_access
Definition: nonlin.cpp:13
int * hoc_access
Definition: nonlin.cpp:12
static void eqn_space(void)
Definition: nonlin.cpp:205
static unsigned maxeqn
Definition: nonlin.cpp:79
int hoc_do_equation
Definition: nonlin.cpp:11
void hoc_solve(void)
Definition: nonlin.cpp:253
void hoc_eqn_lhs(void)
Definition: nonlin.cpp:159
static double Delta
Definition: nonlin.cpp:123
void hoc_eqn_rhs(void)
Definition: nonlin.cpp:164
struct elm * Elm
Definition: nonlin.cpp:17
void hoc_Prmat(void)
Definition: nonlin.cpp:245
#define diag(s)
Definition: nonlin.cpp:19
static void set_varble(void)
Definition: nonlin.cpp:101
static double ** varble
Definition: nonlin.cpp:16
int ifarg(int)
Definition: code.cpp:1607
Inst * hoc_pc
Definition: code.cpp:78
Symlist * hoc_symlist
Definition: symbol.cpp:34
void hoc_execute(Inst *)
Definition: code.cpp:2531
void prmat(void)
Definition: prmat.cpp:10
unsigned * a_varn
Definition: hocdec.h:60
int nsub
Definition: hocdec.h:61
int sub[1]
Definition: hocdec.h:63
Definition: model.h:47
Symbol * next
Definition: hocdec.h:133
short type
Definition: model.h:48
long subtype
Definition: model.h:49
unsigned s_varn
Definition: hocdec.h:129
char * name
Definition: model.h:61
Symbol * first
Definition: hocdec.h:76
Definition: lineq.h:17
double value
Definition: lineq.h:20
struct elm * c_right
Definition: lineq.h:24
Definition: hocdec.h:42