NEURON
method3.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 /* /local/src/master/nrn/src/nrnoc/method3.cpp,v 1.5 1999/07/08 14:25:03 hines Exp */
3 /*
4 method3.cpp,v
5  * Revision 1.5 1999/07/08 14:25:03 hines
6  * Uniformly use section_length(sec) instead of sec->prop->dparam[2].val
7  * and make sure it never returns <= 0
8  * Also avoid recursive error when error due to shape updating.
9  *
10  * Revision 1.4 1998/02/19 20:20:03 hines
11  * several fields moved from memb_list to memb_func.
12  * This was more convenient for local variable time step method
13  *
14  * Revision 1.3 1997/04/07 19:47:26 hines
15  * PI now same everywhere
16  *
17  * Revision 1.2 1996/05/21 17:09:21 hines
18  * Section now holds list of node pointers instead of vector of nodes.
19  * This will be used later to allow changing nseg to not throw away node
20  * information. This has been checked up through the level of the nrn/examples
21  * files to verify that it produces the same results as the previous structure.
22  *
23  * Revision 1.1.1.1 1994/10/12 17:22:33 hines
24  * NEURON 3.0 distribution
25  *
26  * Revision 4.25 1993/04/20 08:58:42 hines
27  * rootsection no longer exists. section structure changed so
28  * sec->parentnode is a Node*. sec->parentsec no longer changed but
29  * kept the way user specified it. The function Section* nrn_trueparent(sec)
30  * returns the section that used to be in parentsec after setup_topology()
31  * was executed. no more inode_exact(Section** psec, double x)---has been
32  * replaced by Node* node_exact(Section* sec, double x)
33  * There is now a rootnode list. parentsec of a section which was not
34  * connect'ed to anything has a parentsec of nil. One can now disconnect
35  * and delete sections without otherwise changing user spec (except
36  * point processes at ends may be moved or changed -- will be fixed later)
37  *
38  * Revision 4.4 93/01/06 09:44:45 hines
39  * minor adjustments for cray c90
40  *
41  * Revision 3.43 92/12/16 14:24:33 hines
42  * Ra switched from global variable to section variable in which it can
43  * take on different values in different sections. Similar to L.
44  * No need to set diam_changed when Ra changed.
45  *
46  * Revision 3.35 92/10/27 12:09:50 hines
47  * list.cpp list.h moved from nrnoc to oc
48  *
49  * Revision 3.21 92/10/08 10:24:42 hines
50  * third order correct with _method3 = 3 and when more than 1 segment
51  * per section and interior segments do not have point processes.
52  * when not active then third order correct no matter what.
53  *
54  * Revision 3.17 92/09/30 16:52:59 hines
55  * strength of stimuli requires area=100 for _method3
56  *
57  * Revision 3.15 92/09/27 19:30:12 hines
58  * set up for testing with 1-d cables. only first node sees G' and E'
59  * dg and de set to 0 for all other nodes. Doesn't appear to be a difference
60  * whether G' and E' are second order correct or not for HH cables.
61  *
62  * Revision 3.13 92/09/27 17:45:11 hines
63  * non vectorized model descriptions with _method3 fill thisnode.GC,EC
64  * instead of d,rhs when models are channel densities.
65  * HH doesn't work too well with G' and E' as first order differences so
66  * now it is zeroed.
67  *
68  * Revision 3.12 92/09/25 18:03:22 hines
69  * for method3. now tested and working for transient passive cables.
70  * but perhaps the equations could be written with better roundoff
71  * error when dt is small
72  *
73  * Revision 3.11 92/09/24 17:03:42 hines
74  * METHOD3 option. use with spatial_method(i) with i=0-3
75  * 0 is the default and is the normal neuron method with zero area nodes
76  * at boundaries and branch points.
77  * 1 is the standard method with half area nodes at boundaries
78  * 2 is a modified second order method which weights by 2/12, 8/12, 2/12
79  * 3 is a third order correct method which weights by 1/12 10/12 1/12
80  * with the last three methods x = i/nnode with i=0 to nnode
81  * methods 1 and 2 are at present quite inefficient since they use the
82  * data structures of 3.
83  * Works in steady state. not tested with dynamic simulations
84  * At this time, discontinuities in parameters (except diameter) is
85  * not handled well across nodes and all parameters are assumed to
86  * be constant in interval between node and parent node.
87  * Good deal of difficulty remains in managing values that change discontinuously
88  *
89  * Revision 1.1 92/09/24 11:26:31 hines
90  * Initial revision
91  *
92 */
93 /* started from version 3.5 of treeset.cpp */
94 
95 
96 #include <stdio.h>
97 #include <errno.h>
98 #include "section.h"
99 
100 
101 #if METHOD3 && VECTORIZE
102 #include "membfunc.h"
103 #include "neuron.h"
104 #include "parse.hpp"
105 
106 extern int diam_changed;
107 extern int tree_changed;
108 extern double chkarg();
109 extern double nrn_ra();
110 
111 int _method3;
112 
113 int spatial_method() {
114  int new_method;
115 
116  if (ifarg(1)) {
117  new_method = (int) chkarg(1, 0., 3.);
118  if (_method3 == 0 && new_method) { /* don't use last node */
119  tree_changed = 1;
120  } else if (_method3 && new_method == 0) { /* need the last node */
121  tree_changed = 1;
122  }
123  if (_method3 != new_method) {
124  _method3 = new_method;
125  tree_changed = 1;
126  diam_changed = 1;
127  }
128  _method3 = new_method;
129  }
130  hoc_retpushx((double) _method3);
131 }
132 
133 /*
134 When properties are allocated to nodes or freed, v_structure_change is
135 set to 1. This means that the mechanism vectors need to be re-determined.
136 */
137 extern "C" int v_structure_change;
138 extern int v_node_count;
139 extern Node** v_node;
140 extern Node** v_parent;
141 
142 extern int section_count;
143 extern Section** secorder;
144 
145 method3_setup_tree_matrix() /* construct diagonal elements */
146 {
147  int i;
148  if (diam_changed) {
149  recalc_diam();
150  }
151 #if _CRAY
152 #pragma _CRI ivdep
153 #endif
154  for (i = 0; i < v_node_count; ++i) {
155  Node* nd = v_node[i];
156  NODED(nd) = 0.;
157  NODERHS(nd) = 0.;
158  nd->thisnode.GC = 0.;
159  nd->thisnode.EC = 0.;
160  }
161  for (i = 0; i < n_memb_func; ++i)
162  if (memb_func[i].current && memb_list[i].nodecount) {
163  if (memb_func[i].vectorized) {
166  memb_list[i].data,
167  memb_list[i].pdata);
168  } else {
169  int j, count;
170  Pfrd s = memb_func[i].current;
171  Memb_list* m = memb_list + i;
172  count = m->nodecount;
173  if (memb_func[i].is_point) {
174  for (j = 0; j < count; ++j) {
175  Node* nd = m->nodelist[j];
176  NODERHS(nd) -= (*s)(m->data[j], m->pdata[j], &NODED(nd), nd->v);
177  };
178  } else {
179  for (j = 0; j < count; ++j) {
180  Node* nd = m->nodelist[j];
181  nd->thisnode.EC -= (*s)(m->data[j], m->pdata[j], &nd->thisnode.GC, nd->v);
182  };
183  }
184  }
185  if (errno) {
186  if (nrn_errno_check(i)) {
187  hoc_warning("errno set during calculation of currents", (char*) 0);
188  }
189  }
190  }
191 #if 0 && _CRAY
192 #pragma _CRI ivdep
193 #endif
194  for (i = rootnodecount; i < v_node_count; ++i) {
195  Node* nd2;
196  Node* nd = v_node[i];
197  Node* pnd = v_parent[nd->v_node_index];
198  double dg, de, dgp, dep, fac;
199 
200 #if 0
201 if (i == rootnodecount) {
202  printf("v0 %g vn %g jstim %g jleft %g jright %g\n",
203  nd->v, pnd->v, nd->fromparent.current, nd->toparent.current,
204  nd[1].fromparent.current);
205 }
206 #endif
207 
208  /* dg and de must be second order when used */
209  if ((nd2 = nd->toparent.nd2) != (Node*) 0) {
210  dgp = -(3 * (pnd->thisnode.GC - pnd->thisnode.Cdt) -
211  4 * (nd->thisnode.GC - nd->thisnode.Cdt) +
212  (nd2->thisnode.GC - nd2->thisnode.Cdt)) /
213  2;
214  dep = -(3 * (pnd->thisnode.EC - pnd->thisnode.Cdt * pnd->v) -
215  4 * (nd->thisnode.EC - nd->thisnode.Cdt * nd->v) +
216  (nd2->thisnode.EC - nd2->thisnode.Cdt * nd2->v)) /
217  2;
218  } else {
219  dgp = 0.;
220  dep = 0.;
221  }
222 
223  if ((nd2 = pnd->fromparent.nd2) != (Node*) 0) {
224  dg = -(3 * (nd->thisnode.GC - nd->thisnode.Cdt) -
225  4 * (pnd->thisnode.GC - pnd->thisnode.Cdt) +
226  (nd2->thisnode.GC - nd2->thisnode.Cdt)) /
227  2;
228  de = -(3 * (nd->thisnode.EC - nd->thisnode.Cdt * nd->v) -
229  4 * (pnd->thisnode.EC - pnd->thisnode.Cdt * pnd->v) +
230  (nd2->thisnode.EC - nd2->thisnode.Cdt * nd2->v)) /
231  2;
232  } else {
233  dg = 0.;
234  de = 0.;
235  }
236 
237  fac = 1. + nd->toparent.coefjdot * nd->thisnode.GC;
238  nd->toparent.djdv0 = (nd->toparent.coefj + nd->toparent.coef0 * nd->thisnode.GC +
239  nd->toparent.coefdg * dg) /
240  fac;
241  NODED(nd) += nd->toparent.djdv0;
242  nd->toparent.current = (-nd->toparent.coef0 * nd->thisnode.EC -
243  nd->toparent.coefn * pnd->thisnode.EC +
244  nd->toparent.coefjdot * nd->thisnode.Cdt * nd->toparent.current -
245  nd->toparent.coefdg * de) /
246  fac;
247  NODERHS(nd) -= nd->toparent.current;
248  NODEB(nd) = (-nd->toparent.coefj + nd->toparent.coefn * pnd->thisnode.GC) / fac;
249 
250  /* this can break cray vectors */
251  fac = 1. + nd->fromparent.coefjdot * pnd->thisnode.GC;
252  nd->fromparent.djdv0 = (nd->fromparent.coefj + nd->fromparent.coef0 * pnd->thisnode.GC +
253  nd->fromparent.coefdg * dgp) /
254  fac;
255  pNODED(nd) += nd->fromparent.djdv0;
256  nd->fromparent.current =
257  (-nd->fromparent.coef0 * pnd->thisnode.EC - nd->fromparent.coefn * nd->thisnode.EC +
258  nd->fromparent.coefjdot * nd->thisnode.Cdt * nd->fromparent.current -
259  nd->fromparent.coefdg * dep) /
260  fac;
261  pNODERHS(nd) -= nd->fromparent.current;
262  NODEA(nd) = (-nd->fromparent.coefj + nd->fromparent.coefn * nd->thisnode.GC) / fac;
263  }
264  activstim();
265  activsynapse();
266  activclamp();
267 }
268 
269 method3_axial_current() {
270  int i;
271 #if _CRAY
272 #pragma _CRI ivdep
273 #endif
274  for (i = rootnodecount; i < v_node_count; ++i) {
275  Node* nd = v_node[i];
276  Node* pnd = v_parent[i];
277  nd->toparent.current += nd->toparent.djdv0 * nd->v + NODEB(nd) * pnd->v;
278 
279  nd->fromparent.current += nd->fromparent.djdv0 * pnd->v + NODEA(nd) * nd->v;
280  }
281 #if 0
282 printf("cur0 %g curleft %g curright %g\n",
283  v_node[rootnodecount]->fromparent.current,
284  v_node[rootnodecount]->toparent.current,
285  v_node[rootnodecount+1]->fromparent.current
286  );
287 #endif
288 }
289 
290 /* For now there is always one more node in a section than there are
291 segments */
292 /* except in section 0 in which all nodes serve as x=0 to connecting
293 sections */
294 /* the above is obsolete with method3 */
295 
296 #define PI 3.14159265358979323846
297 
298 method3_connection_coef() /* setup a and b */
299 {
300  int j;
301  double dx, diam, ra, coef;
302  hoc_Item* qsec;
303  Section* sec;
304  Node* nd;
305  Prop *p, *nrn_mechanism();
306  float r, s, t;
307 
308  if (tree_changed) {
309  setup_topology();
310  }
311  /* for now assume diameter between node and parent is constant and located at the node */
312 
313  /* r = 6 is standard method, 5 is third order, 4 is modified second order */
314  switch (_method3) {
315  case 1:
316  r = 6.;
317  break;
318  case 2:
319  r = 4.;
320  break;
321  case 3:
322  r = 5.;
323  break;
324  default:
325  hoc_execerror(" invalid spatial method", (char*) 0);
326  }
327  s = 6. - r;
328  if (r == 5.) {
329  t = 1.;
330  } else {
331  t = 0.;
332  }
333 
334  // ForAllSections(sec)
335  ITERATE(qsec, section_list) {
336  Section* sec = hocSEC(qsec);
337  dx = section_length(sec) / ((double) (sec->nnode));
338  for (j = 0; j < sec->nnode; ++j) {
339  nd = sec->pnode[j];
340  p = nrn_mechanism(MORPHOLOGY, nd);
341  assert(p);
342  diam = p->param[0];
343  /* dv/(ra*dx) is nanoamps */
344  ra = nrn_ra(sec) * 4.e-2 / (PI * diam * diam);
345  /* coef*dx* mA/cm^2 should be nanoamps */
346  coef = PI * 1e-2 * diam;
347 
348  nd->area = 100.;
349  sec->parentnode->area = 100.;
350 
351  nd->toparent.coef0 = coef * r * dx / 12.;
352  nd->fromparent.coef0 = coef * r * dx / 12.;
353  nd->toparent.coefn = coef * s * dx / 12.;
354  nd->fromparent.coefn = coef * s * dx / 12.;
355  nd->toparent.coefjdot = t * ra * coef * dx * dx / 12.;
356  nd->fromparent.coefjdot = t * ra * coef * dx * dx / 12.;
357  nd->toparent.coefdg = t * coef * dx / 12.;
358  nd->fromparent.coefdg = t * coef * dx / 12.;
359  nd->toparent.coefj = 1. / (ra * dx);
360  nd->fromparent.coefj = 1. / (ra * dx);
361  nd->toparent.nd2 = 0;
362  nd->fromparent.nd2 = 0;
363  }
364  if (sec->nnode > 1) {
365  sec->pnode[0]->toparent.nd2 = sec->pnode[1];
366  if (sec->nnode > 2) {
367  sec->pnode[sec->nnode - 2]->fromparent.nd2 = sec->pnode[sec->nnode - 3];
368  } else {
369  sec->pnode[sec->nnode - 2]->fromparent.nd2 =
370  sec->parentsec->pnode[sec->parentsec->nnode - 1];
371  }
372  }
373  }
374 }
375 
376 
377 #endif
Section ** secorder
Definition: solve.cpp:77
int section_count
Definition: solve.cpp:76
Prop * nrn_mechanism(int type, Node *nd)
Definition: cabcode.cpp:1079
double nrn_ra(Section *sec)
Definition: cabcode.cpp:403
double section_length(Section *sec)
Definition: cabcode.cpp:387
Memb_func * memb_func
Definition: init.cpp:123
static Node * pnd
Definition: clamp.cpp:33
int diam_changed
Definition: cabcode.cpp:23
double t
Definition: cvodeobj.cpp:59
int v_structure_change
Definition: cvodestb.cpp:99
int tree_changed
double chkarg(int, double low, double high)
Definition: code2.cpp:638
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:754
void hoc_warning(const char *, const char *)
void hoc_retpushx(double x)
Definition: hocusr.cpp:154
#define assert(ex)
Definition: hocassrt.h:32
double(* Pfrd)(void)
Definition: hocdec.h:41
#define hocSEC(q)
Definition: hoclist.h:66
int ifarg(int)
Definition: code.cpp:1581
#define PI
Definition: ivocvect.cpp:59
#define sec
Definition: md1redef.h:13
#define nodecount
Definition: md1redef.h:30
#define nodelist
Definition: md1redef.h:25
#define i
Definition: md1redef.h:12
#define pdata
Definition: md1redef.h:28
#define MORPHOLOGY
Definition: membfunc.h:63
#define ITERATE(itm, lst)
Definition: model.h:25
#define printf
Definition: mwprefix.h:26
void setup_topology()
int nrn_errno_check(int)
Definition: fadvance.cpp:837
size_t p
size_t j
hoc_List * section_list
Definition: init.cpp:102
Memb_list * memb_list
Definition: init.cpp:124
int n_memb_func
Definition: init.cpp:440
static List * current
Definition: nrnunit.cpp:12
void recalc_diam()
Definition: treeset.cpp:953
#define e
Definition: passive0.cpp:22
#define data
Definition: rbtqueue.cpp:49
#define NODEA(n)
Definition: section.h:124
#define NODEB(n)
Definition: section.h:125
#define NODERHS(n)
Definition: section.h:105
#define NODED(n)
Definition: section.h:104
Pvmi current
Definition: membfunc.h:33
int nodecount
Definition: nrnoc_ml.h:18
Node ** nodelist
Definition: nrnoc_ml.h:5
double ** data
Definition: nrnoc_ml.h:14
Datum ** pdata
Definition: nrnoc_ml.h:15
Definition: section.h:133
int v_node_index
Definition: section.h:175
Definition: section.h:214