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) if (memb_func[i].current && memb_list[i].nodecount) {
162  if (memb_func[i].vectorized) {
164  memb_list[i].nodecount,
165  memb_list[i].nodelist,
166  memb_list[i].data,
167  memb_list[i].pdata
168  );
169  }else{
170  int j, count;
171  Pfrd s = memb_func[i].current;
172  Memb_list* m = memb_list + i;
173  count = m->nodecount;
174  if (memb_func[i].is_point) {
175  for (j = 0; j < count; ++j) {
176  Node* nd = m->nodelist[j];
177  NODERHS(nd) -= (*s)(m->data[j], m->pdata[j],
178  &NODED(nd),nd->v);
179  };
180  }else{
181  for (j = 0; j < count; ++j) {
182  Node* nd = m->nodelist[j];
183  nd->thisnode.EC -= (*s)(m->data[j], m->pdata[j],
184  &nd->thisnode.GC,nd->v);
185  };
186  }
187  }
188  if (errno) {
189  if (nrn_errno_check(i)) {
190 hoc_warning("errno set during calculation of currents", (char*)0);
191  }
192  }
193  }
194 #if 0 && _CRAY
195 #pragma _CRI ivdep
196 #endif
197  for (i=rootnodecount; i < v_node_count; ++i) {
198  Node* nd2;
199  Node* nd = v_node[i];
200  Node* pnd = v_parent[nd->v_node_index];
201  double dg, de, dgp, dep, fac;
202 
203 #if 0
204 if (i == rootnodecount) {
205  printf("v0 %g vn %g jstim %g jleft %g jright %g\n",
206  nd->v, pnd->v, nd->fromparent.current, nd->toparent.current,
207  nd[1].fromparent.current);
208 }
209 #endif
210 
211  /* dg and de must be second order when used */
212  if ((nd2 = nd->toparent.nd2) != (Node*)0) {
213  dgp = -(3*(pnd->thisnode.GC - pnd->thisnode.Cdt)
214  - 4*(nd->thisnode.GC - nd->thisnode.Cdt)
215  +(nd2->thisnode.GC - nd2->thisnode.Cdt))/2
216  ;
217  dep = -(3*(pnd->thisnode.EC - pnd->thisnode.Cdt * pnd->v)
218  - 4*(nd->thisnode.EC - nd->thisnode.Cdt * nd->v)
219  +(nd2->thisnode.EC - nd2->thisnode.Cdt * nd2->v))/2
220  ;
221  }else{
222  dgp = 0.;
223  dep = 0.;
224  }
225 
226  if ((nd2 = pnd->fromparent.nd2) != (Node*)0) {
227  dg = -(3*(nd->thisnode.GC - nd->thisnode.Cdt)
228  - 4*(pnd->thisnode.GC - pnd->thisnode.Cdt)
229  +(nd2->thisnode.GC - nd2->thisnode.Cdt))/2
230  ;
231  de = -(3*(nd->thisnode.EC - nd->thisnode.Cdt * nd->v)
232  - 4*(pnd->thisnode.EC - pnd->thisnode.Cdt * pnd->v)
233  +(nd2->thisnode.EC - nd2->thisnode.Cdt * nd2->v))/2
234  ;
235  }else{
236  dg = 0.;
237  de = 0.;
238  }
239 
240  fac = 1. + nd->toparent.coefjdot * nd->thisnode.GC;
241  nd->toparent.djdv0 = (
242  nd->toparent.coefj
243  + nd->toparent.coef0 * nd->thisnode.GC
244  + nd->toparent.coefdg * dg
245  )/fac;
246  NODED(nd) += nd->toparent.djdv0;
247  nd->toparent.current = (
248  - nd->toparent.coef0 * nd->thisnode.EC
249  - nd->toparent.coefn * pnd->thisnode.EC
250  + nd->toparent.coefjdot *
251  nd->thisnode.Cdt * nd->toparent.current
252  - nd->toparent.coefdg * de
253  )/fac;
254  NODERHS(nd) -= nd->toparent.current;
255  NODEB(nd) = (
256  - nd->toparent.coefj
257  + nd->toparent.coefn * pnd->thisnode.GC
258  )/fac;
259 
260  /* this can break cray vectors */
261  fac = 1. + nd->fromparent.coefjdot * pnd->thisnode.GC;
262  nd->fromparent.djdv0 = (
263  nd->fromparent.coefj
264  + nd->fromparent.coef0 * pnd->thisnode.GC
265  + nd->fromparent.coefdg * dgp
266  )/fac;
267  pNODED(nd) += nd->fromparent.djdv0;
268  nd->fromparent.current = (
269  - nd->fromparent.coef0 * pnd->thisnode.EC
270  - nd->fromparent.coefn * nd->thisnode.EC
271  + nd->fromparent.coefjdot *
272  nd->thisnode.Cdt * nd->fromparent.current
273  - nd->fromparent.coefdg * dep
274  )/fac;
275  pNODERHS(nd) -= nd->fromparent.current;
276  NODEA(nd) = (
277  - nd->fromparent.coefj
278  + nd->fromparent.coefn * nd->thisnode.GC
279  )/fac;
280  }
281  activstim();
282  activsynapse();
283  activclamp();
284 }
285 
286 method3_axial_current() {
287  int i;
288 #if _CRAY
289 #pragma _CRI ivdep
290 #endif
291  for (i=rootnodecount; i < v_node_count; ++ i) {
292  Node* nd = v_node[i];
293  Node* pnd = v_parent[i];
294  nd->toparent.current +=
295  nd->toparent.djdv0 * nd->v
296  + NODEB(nd) * pnd->v;
297 
298  nd->fromparent.current +=
299  nd->fromparent.djdv0 * pnd->v
300  + NODEA(nd) * nd->v;
301 
302  }
303 #if 0
304 printf("cur0 %g curleft %g curright %g\n",
305  v_node[rootnodecount]->fromparent.current,
306  v_node[rootnodecount]->toparent.current,
307  v_node[rootnodecount+1]->fromparent.current
308  );
309 #endif
310 }
311 
312 /* For now there is always one more node in a section than there are
313 segments */
314 /* except in section 0 in which all nodes serve as x=0 to connecting
315 sections */
316 /* the above is obsolete with method3 */
317 
318 #define PI 3.14159265358979323846
319 
320 method3_connection_coef() /* setup a and b */
321 {
322  int j;
323  double dx, diam, ra, coef;
324  hoc_Item* qsec;
325  Section* sec;
326  Node *nd;
327  Prop *p, *nrn_mechanism();
328  float r, s, t;
329 
330  if (tree_changed) {
331  setup_topology();
332  }
333 /* for now assume diameter between node and parent is constant and located at the node */
334 
335  /* r = 6 is standard method, 5 is third order, 4 is modified second order */
336  switch (_method3) {
337  case 1:
338  r = 6.;
339  break;
340  case 2:
341  r = 4.;
342  break;
343  case 3:
344  r = 5.;
345  break;
346  default:
347  hoc_execerror(" invalid spatial method", (char*)0);
348  }
349  s = 6. - r;
350  if (r == 5.) {
351  t = 1.;
352  }else{
353  t = 0.;
354  }
355 
356  ForAllSections(sec)
357  dx = section_length(sec)/((double)(sec->nnode));
358  for (j = 0; j < sec->nnode; ++j) {
359  nd = sec->pnode[j];
360  p = nrn_mechanism(MORPHOLOGY, nd);
361  assert(p);
362  diam = p->param[0];
363  /* dv/(ra*dx) is nanoamps */
364  ra = nrn_ra(sec)*4.e-2/(PI * diam*diam);
365  /* coef*dx* mA/cm^2 should be nanoamps */
366  coef = PI *1e-2* diam;
367 
368  nd->area = 100.;
369  sec->parentnode->area = 100.;
370 
371  nd->toparent.coef0 = coef*r*dx/12.;
372  nd->fromparent.coef0 = coef*r*dx/12.;
373  nd->toparent.coefn = coef*s*dx/12.;
374  nd->fromparent.coefn = coef*s*dx/12.;
375  nd->toparent.coefjdot = t*ra*coef*dx*dx/12.;
376  nd->fromparent.coefjdot = t*ra*coef*dx*dx/12.;
377  nd->toparent.coefdg = t*coef*dx/12.;
378  nd->fromparent.coefdg = t*coef*dx/12.;
379  nd->toparent.coefj = 1./(ra*dx);
380  nd->fromparent.coefj = 1./(ra*dx);
381  nd->toparent.nd2 = 0;
382  nd->fromparent.nd2 = 0;
383  }
384  if (sec->nnode > 1) {
385  sec->pnode[0]->toparent.nd2 = sec->pnode[1];
386  if (sec->nnode > 2) {
387  sec->pnode[sec->nnode - 2]->fromparent.nd2 =
388  sec->pnode[sec->nnode - 3];
389  }else{
390  sec->pnode[sec->nnode - 2]->fromparent.nd2 =
391  sec->parentsec->pnode[sec->parentsec->nnode - 1];
392  }
393  }
394  }
395 }
396 
397 
398 #endif
399 
#define data
Definition: rbtqueue.cpp:49
double * param
Definition: section.h:218
#define assert(ex)
Definition: hocassrt.h:26
int tree_changed
Definition: cabcode.cpp:19
short nnode
Definition: section.h:41
struct Node * parentnode
Definition: section.h:50
struct Section * parentsec
Definition: section.h:42
#define NODED(n)
Definition: section.h:103
Pvmi current
Definition: membfunc.h:33
size_t p
void setup_topology()
int diam_changed
Definition: cabcode.cpp:23
Memb_func * memb_func
Definition: init.cpp:161
nd
Definition: treeset.cpp:893
double ** data
Definition: nrnoc_ml.h:14
#define MORPHOLOGY
Definition: membfunc.h:63
#define e
Definition: passive0.cpp:24
double(* Pfrd)(void)
Definition: hocdec.h:41
int nodecount
Definition: nrnoc_ml.h:18
_CONST char * s
Definition: system.cpp:74
#define NODEA(n)
Definition: section.h:123
#define nodelist
Definition: md1redef.h:25
Section ** secorder
Definition: solve.cpp:77
Memb_list * memb_list
Definition: init.cpp:162
#define printf
Definition: mwprefix.h:26
int
Definition: nrnmusic.cpp:71
void hoc_warning(const char *, const char *)
static Node * pnd
Definition: clamp.cpp:33
int n_memb_func
Definition: init.cpp:471
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:741
#define ForAllSections(sec)
Definition: section.h:317
errno
Definition: system.cpp:98
hoc_retpushx(1.0)
size_t j
Datum ** pdata
Definition: nrnoc_ml.h:15
int section_count
Definition: solve.cpp:76
int v_structure_change
Definition: cvodestb.cpp:99
double nrn_ra(Section *sec)
Definition: cabcode.cpp:392
Definition: section.h:213
Prop * nrn_mechanism(int type, Node *nd)
Definition: cabcode.cpp:1079
#define NODEB(n)
Definition: section.h:124
double section_length(Section *sec)
Definition: cabcode.cpp:375
int ifarg(int)
Definition: code.cpp:1562
#define NODERHS(n)
Definition: section.h:104
static List * current
Definition: nrnunit.cpp:12
Node ** nodelist
Definition: nrnoc_ml.h:5
int v_node_index
Definition: section.h:174
#define nodecount
Definition: md1redef.h:30
#define i
Definition: md1redef.h:12
#define PI
Definition: ivocvect.cpp:59
void recalc_diam()
Definition: treeset.cpp:940
sec
Definition: solve.cpp:885
struct Node ** pnode
Definition: section.h:51
int nrn_errno_check(int)
Definition: fadvance.cpp:784
double t
Definition: init.cpp:123
Definition: section.h:132
double chkarg(int, double low, double high)
Definition: code2.cpp:608
#define pdata
Definition: md1redef.h:28