NEURON
extcelln.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 /* /local/src/master/nrn/src/nrnoc/extcell.cpp,v 1.4 1996/05/21 17:09:19 hines Exp */
3 
4 #include <stdio.h>
5 #include <math.h>
6 #include "section.h"
7 #include "nrniv_mf.h"
8 #include "hocassrt.h"
9 #include "parse.hpp"
10 
11 
12 extern int cvode_active_;
13 extern int nrn_use_daspk_;
14 extern void nrn_delete_prop_pool(int type);
15 
16 #if EXTRACELLULAR
17 
19 
20 /* the N index is a keyword in the following. See init.cpp for implementation.*/
21 /* if nlayer is changed the symbol table arayinfo->sub[0] must be updated
22  for xraxial, xg, xc, and vext */
23 static const char* mechanism[] = {
24  "0",
25  "extracellular",
26  "xraxial[N]",
27  "xg[N]",
28  "xc[N]",
29  "e_extracellular",
30  0,
31 #if I_MEMBRANE
32  "i_membrane",
33 #endif
34  0,
35  "vext[N]",
36  0,
37 };
38 static HocParmLimits limits[] = {"xraxial", 1e-9, 1e15, "xg", 0., 1e15, "xc", 0., 1e15, 0, 0., 0.};
39 
40 static HocParmUnits units[] = {"xraxial",
41  "MOhm/cm",
42  "xg",
43  "S/cm2",
44  "xc",
45  "uF/cm2",
46  "e_extracellular",
47  "mV",
48  "vext",
49  "mV",
50  "i_membrane",
51  "mA/cm2",
52  0,
53  0};
54 
55 static void extcell_alloc(Prop*);
56 static void extcell_init(NrnThread* nt, Memb_list* ml, int type);
57 #if 0
58 static void printnode(const char* s);
59 #endif
60 
61 static int _ode_count(int type) {
62  /* hoc_execerror("extracellular", "cannot be used with CVODE");*/
63  /* but can be used with daspk. However everything is handled
64  in analogy with intracellular nodes instead of in analogy with a
65  membrane mechanism.
66  Thus the count really comes from the size of sp13mat.
67 */
68  return 0;
69 }
70 
71 
72 extern "C" void extracell_reg_(void) {
73  int i;
76  hoc_register_cvode(i, _ode_count, 0, 0, 0);
79 }
80 
81 
82 /* solving is done with sparse13 */
83 
84 /* interface between hoc and extcell */
85 #define xraxial pd /* From Eion */
86 #define xg (pd + (nlayer))
87 #define xc (pd + 2 * (nlayer))
88 #define e_extracellular pd[3 * (nlayer)]
89 #if I_MEMBRANE
90 #define i_membrane pd[1 + 3 * (nlayer)]
91 #define sav_g pd[2 + 3 * (nlayer)]
92 #define sav_rhs pd[3 + 3 * (nlayer)]
93 #endif
94 
95 /* based on update() in fadvance.cpp */
96 /* update has already been called so modify nd->v based on dvi
97 we only need to update extracellular
98 nodes and base the corresponding nd->v on dvm (dvm = dvi - dvx)
99 */
101  int i, cnt, il;
102  extern int secondorder;
103  Node *nd, **ndlist;
104  Extnode* nde;
105  double* pd;
106  double cfac;
107  Memb_list* ml = nt->_ecell_memb_list;
108  if (!ml) {
109  return;
110  }
111  cfac = .001 * nt->cj;
112  cnt = ml->nodecount;
113  ndlist = ml->nodelist;
114 
115  for (i = 0; i < cnt; ++i) {
116  nd = ndlist[i];
117  nde = nd->extnode;
118  for (il = 0; il < nlayer; ++il) {
119  nde->v[il] += *nde->_rhs[il];
120  }
121  NODEV(nd) -= *nde->_rhs[0];
122  }
123 
124 #if I_MEMBRANE
125  for (i = 0; i < cnt; ++i) {
126  pd = ml->data[i];
127  nd = ndlist[i];
128  NODERHS(nd) -= *nd->extnode->_rhs[0];
129  i_membrane = sav_g * (NODERHS(nd)) + sav_rhs;
130 #if 1
131  /* i_membrane is a current density (mA/cm2). However
132  it contains contributions from Non-ELECTRODE_CURRENT
133  point processes. i_membrane(0) and i_membrane(1) will
134  return the membrane current density at the points
135  .5/nseg and 1-.5/nseg respectively. This can cause
136  confusion if non-ELECTRODE_CURRENT point processes
137  are located at these 0-area nodes since 1) not only
138  is the true current density infinite, but 2) the
139  correct absolute current is being computed here
140  at the x=1 point but is not available, and 3) the
141  correct absolute current at x=0 is not computed
142  if the parent is a rootnode or there is no
143  extracellular mechanism for the parent of this
144  section. Thus, if non-ELECTRODE_CURRENT point processesm,
145  eg synapses, are being used it is not a good idea to
146  insert them at the points x=0 or x=1
147  */
148 #else
149  i_membrane *= NODEAREA(nd);
150  /* i_membrane is nA for every segment. This is different
151  from all other continuous mechanism currents and
152  same as PointProcess currents since it contains
153  non-ELECTRODE_CURRENT point processes and may
154  be non-zero for the zero area nodes.
155  */
156 #endif
157  }
158 #endif
159 }
160 
161 static int nparm() { /* number of doubles for property data */
162  /* 3 are the nlayer size arrays xg, xc, xraxial */
163 #if I_MEMBRANE
164  /* 4 is for e_extracellular, i_membrane, sav_g, and sav_rhs */
165  return 3 * (nlayer) + 4;
166 #else
167  /* 1 is for e_extracellular */
168  return 3 * (nlayer) + 1;
169 #endif
170 }
171 
172 static void extcell_alloc(Prop* p) {
173  double* pd;
174  int i;
175 
176  pd = nrn_prop_data_alloc(EXTRACELL, nparm(), p);
177  p->param_size = nparm();
178 
179  for (i = 0; i < nlayer; ++i) {
180  xraxial[i] = 1.e9;
181  xg[i] = 1.e9;
182  xc[i] = 0.;
183  }
184  e_extracellular = 0.;
185 #if 0
186  i_membrane = 0.;
187  sav_g = 0.;
188  sav_rhs = 0.;
189 #endif
190  p->param = pd;
191 }
192 
193 /*ARGSUSED*/
194 static void extcell_init(NrnThread* nt, Memb_list* ml, int type) {
195  int ndcount = ml->nodecount;
196  Node** ndlist = ml->nodelist;
197  double** data = ml->data;
198  int i, j;
199  double* pd;
200  if ((cvode_active_ > 0) && (nrn_use_daspk_ == 0)) {
201  hoc_execerror("Extracellular mechanism only works with fixed step methods and daspk", 0);
202  }
203  for (i = 0; i < ndcount; ++i) {
204  for (j = 0; j < nlayer; ++j) {
205  ndlist[i]->extnode->v[j] = 0.;
206  }
207 #if I_MEMBRANE
208  pd = data[i];
209  i_membrane = 0.;
210 #endif
211  }
212 }
213 
215  if (nde->v) {
216  free(nde->v); /* along with _a and _b */
217  free(nde->_d); /* along with _rhs, _a_matelm, _b_matelm, _x12, and _x21 */
218  nde->v = NULL;
219  nde->_a = NULL;
220  nde->_b = NULL;
221  nde->_d = NULL;
222  nde->_rhs = NULL;
223  nde->_a_matelm = NULL;
224  nde->_b_matelm = NULL;
225  nde->_x12 = NULL;
226  nde->_x21 = NULL;
227  }
228 }
229 
231  hoc_Item* qsec;
232  ITERATE(qsec, section_list) {
233  Section* sec = hocSEC(qsec);
234  if (sec->pnode[0]->extnode) {
235  hoc_execerror("Cannot change nlayer_extracellular when instances exist", NULL);
236  }
237  }
238 }
239 
240 static void update_existing_extnode(int old_nlayer) {
241  /*
242  This is a placeholder for a later extension to allow change
243  of nlayer even if the extracellular mechanism has been instantiated
244  in some sections. It is deferred for later because it is not clear
245  that handling pointer updates to vext is straightforward.
246  Hence the check_if_extracellular_in_use() function, which will
247  be eliminated when this is filled in.
248  */
249 }
250 
251 static void update_extracellular_reg(int old_nlayer) {
252  /* update hoc_symlist for arayinfo->sub[0] and u.rng.index. */
253  int i, ix;
254  Symbol* ecell = hoc_table_lookup("extracellular", hoc_built_in_symlist);
255  assert(ecell);
256  assert(ecell->type == MECHANISM);
257  ix = 0;
258  for (i = 0; i < ecell->s_varn; ++i) {
259  Symbol* s = ecell->u.ppsym[i];
260  if (s->type == RANGEVAR) {
261  Arrayinfo* a = s->arayinfo;
262  s->u.rng.index = ix;
263  if (a && a->nsub == 1) {
264  assert(a->sub[0] == old_nlayer);
265  a->sub[0] = nlayer;
266  ix += nlayer;
267  } else {
268  ix += 1;
269  }
270  }
271  }
272 }
273 
275  if (ifarg(1)) {
276  /* Note in section.h: #define nlayer (nrn_nlayer_extracellular) */
277  int old = nlayer;
278  nrn_nlayer_extracellular = (int) chkarg(1, 1., 1000.);
279  if (nrn_nlayer_extracellular == old) {
280  return;
281  }
282 
284  nrn_delete_prop_pool(EXTRACELL);
285  /*global nlayer is the new value. Following needs to know the previous */
288  }
289  hoc_retpushx((double) nlayer);
290 }
291 
292 static void extnode_alloc_elements(Extnode* nde) {
294  if (nlayer > 0) {
295  nde->v = (double*) ecalloc(nlayer * 3, sizeof(double));
296  nde->_a = nde->v + nlayer;
297  nde->_b = nde->_a + nlayer;
298 
299  nde->_d = (double**) ecalloc(nlayer * 6, sizeof(double*));
300  nde->_rhs = nde->_d + nlayer;
301  nde->_a_matelm = nde->_rhs + nlayer;
302  nde->_b_matelm = nde->_a_matelm + nlayer;
303  nde->_x12 = nde->_b_matelm + nlayer;
304  nde->_x21 = nde->_x12 + nlayer;
305  }
306 }
307 
309  int i, j;
310  Extnode* nde;
311  Prop* p;
312  /* may be a nnode increase so some may already be allocated */
313  if (!nd->extnode) {
314  nde = (Extnode*) ecalloc(1, sizeof(Extnode));
316  nd->extnode = nde;
317  for (j = 0; j < nlayer; ++j) {
318  nde->v[j] = 0.;
319  }
320  nde->param = (double*) 0;
321  for (p = nd->prop; p; p = p->next) {
322  if (p->type == EXTRACELL) {
323  nde->param = p->param;
324  break;
325  }
326  }
327  assert(p && p->type == EXTRACELL);
328  }
329 }
330 
332  int i;
333  NrnThread* nt;
334  FOR_THREADS(nt) {
335  Memb_list* ml = nt->_ecell_memb_list;
336  if (ml) {
337  int cnt = ml->nodecount;
338  Node** ndlist = ml->nodelist;
339  for (i = 0; i < cnt; ++i) {
340  Node* nd = ndlist[i];
341  assert(nd->extnode);
342  nd->extnode->param = ml->data[i];
343  }
344  }
345  }
346 }
347 
349  int i, j;
350  Node* nd;
351  Extnode* nde;
352  Prop* p;
353  /* may be a nnode increase so some may already be allocated */
354  for (i = sec->nnode - 1; i >= 0; i--) {
355  extcell_node_create(sec->pnode[i]);
356  }
357  /* if the rootnode is owned by this section then it gets extnode also*/
358  if (!sec->parentsec && sec->parentnode) { /* last "if" clause unnecessary*/
359  extcell_node_create(sec->parentnode);
360  }
361 }
362 
363 /* from treesetup.cpp */
364 void nrn_rhs_ext(NrnThread* _nt) {
365  int i, j, cnt;
366  Node *nd, *pnd, **ndlist;
367  double* pd;
368  Extnode *nde, *pnde;
369  Memb_list* ml = _nt->_ecell_memb_list;
370  if (!ml) {
371  return;
372  }
373  cnt = ml->nodecount;
374  ndlist = ml->nodelist;
375 
376  /* nd rhs contains -membrane current + stim current */
377  /* nde rhs contains stim current */
378  for (i = 0; i < cnt; ++i) {
379  nd = ndlist[i];
380  nde = nd->extnode;
381  *nde->_rhs[0] -= NODERHS(nd);
382 #if I_MEMBRANE
383  pd = ml->data[i];
384  sav_rhs = *nde->_rhs[0];
385  /* and for daspk this is the ionic current which can be
386  combined later with i_cap before return from solve. */
387 #endif
388  }
389  for (i = 0; i < cnt; ++i) {
390  nd = ndlist[i];
391  nde = nd->extnode;
392  pnd = _nt->_v_parent[nd->v_node_index];
393  if (pnd) {
394  pnde = pnd->extnode;
395  pd = nde->param;
396  /* axial contributions */
397  if (pnde) { /* parent sec may not be extracellular */
398  for (j = 0; j < nlayer; ++j) {
399  double dv = pnde->v[j] - nde->v[j];
400  *nde->_rhs[j] -= nde->_b[j] * dv;
401  *pnde->_rhs[j] += nde->_a[j] * dv;
402  /* for the internal balance equation
403  take care of vi = vm + vx */
404  if (j == 0) {
405  NODERHS(nd) -= NODEB(nd) * dv;
406  NODERHS(pnd) += NODEA(nd) * dv;
407  }
408  }
409  } else { /* no extracellular in parent but still need
410  to take care of vi = vm + vx in this node.
411  Note that we are NOT grounding the parent
412  side of xraxial so equivalent to sealed.
413  Also note that when children of this node
414  do not have extracellular, we deal with
415  that, at end of this function. */
416  double dv = -nde->v[0];
417  NODERHS(nd) -= NODEB(nd) * dv;
418  NODERHS(pnd) += NODEA(nd) * dv;
419  }
420 
421  /* series resistance and battery to ground */
422  /* between nlayer-1 and ground */
423  j = nlayer - 1;
424  *nde->_rhs[j] -= xg[j] * (nde->v[j] - e_extracellular);
425  for (--j; j >= 0; --j) { /* between j and j+1 layer */
426  double x = xg[j] * (nde->v[j] - nde->v[j + 1]);
427  *nde->_rhs[j] -= x;
428  *nde->_rhs[j + 1] += x;
429  }
430  }
431  }
432  cnt = _nt->_ecell_child_cnt;
433  for (i = 0; i < cnt; ++i) {
434  double dv;
435  nd = _nt->_ecell_children[i];
436  pnd = _nt->_v_parent[nd->v_node_index];
437  dv = pnd->extnode->v[0];
438  NODERHS(nd) -= NODEB(nd) * dv;
439  NODERHS(pnd) += NODEA(nd) * dv;
440  }
441 }
442 
444  int i, j, cnt;
445  Node *nd, *pnd, **ndlist;
446  double* pd;
447  double d, cfac, mfac;
448  Extnode *nde, *pnde;
449  Memb_list* ml = _nt->_ecell_memb_list;
450  if (!ml) {
451  return;
452  }
453  /*printnode("begin setup");*/
454  cnt = ml->nodecount;
455  ndlist = ml->nodelist;
456  cfac = .001 * _nt->cj;
457 
458  /* d contains all the membrane conductances (and capacitance) */
459  /* i.e. (cm/dt + di/dvm - dis/dvi)*[dvi] and
460  (dis/dvi)*[dvx] */
461  for (i = 0; i < cnt; ++i) {
462  nd = ndlist[i];
463  nde = nd->extnode;
464  d = NODED(nd);
465  /* nde->_d only has -ELECTRODE_CURRENT contribution */
466  d = (*nde->_d[0] += NODED(nd));
467  /* now d is only the membrane current contribution */
468  /* i.e. d = cm/dt + di/dvm */
469  *nde->_x12[0] -= d;
470  *nde->_x21[0] -= d;
471 #if I_MEMBRANE
472  pd = ml->data[i];
473  sav_g = d;
474 #endif
475  }
476  /* series resistance, capacitance, and axial terms. */
477  for (i = 0; i < cnt; ++i) {
478  nd = ndlist[i];
479  nde = nd->extnode;
480  pnd = _nt->_v_parent[nd->v_node_index];
481  if (pnd) {
482  pd = nde->param;
483  /* series resistance and capacitance to ground */
484  j = 0;
485  for (;;) { /* between j and j+1 layer */
486  mfac = (xg[j] + xc[j] * cfac);
487  *nde->_d[j] += mfac;
488  ++j;
489  if (j == nlayer) {
490  break;
491  }
492  *nde->_d[j] += mfac;
493  *nde->_x12[j] -= mfac;
494  *nde->_x21[j] -= mfac;
495  }
496  pnde = pnd->extnode;
497  /* axial connections */
498  if (pnde) { /* parent sec may not be extracellular */
499  for (j = 0; j < nlayer; ++j) {
500  *nde->_d[j] -= nde->_b[j];
501  *pnde->_d[j] -= nde->_a[j];
502  ;
503  *nde->_a_matelm[j] += nde->_a[j];
504  *nde->_b_matelm[j] += nde->_b[j];
505  ;
506  }
507  }
508  }
509  }
510  /*printnode("end setup_lhs");*/
511 }
512 
513 /* based on treeset.cpp */
514 void ext_con_coef(void) /* setup a and b */
515 {
516  int j, k;
517  double dx, area;
518  hoc_Item* qsec;
519  Node *nd, **pnd;
520  Extnode* nde;
521  double* pd;
522 
523  /* temporarily store half segment resistances in rhs */
524  // ForAllSections(sec)
525  ITERATE(qsec, section_list) {
526  Section* sec = hocSEC(qsec);
527  if (sec->pnode[0]->extnode) {
528  dx = section_length(sec) / ((double) (sec->nnode - 1));
529  for (j = 0; j < sec->nnode - 1; j++) {
530  nde = sec->pnode[j]->extnode;
531  pd = nde->param;
532  for (k = 0; k < nlayer; ++k) {
533  *nde->_rhs[k] = 1e-4 * xraxial[k] * (dx / 2.); /*Megohms*/
534  }
535  }
536  /* last segment has 0 length. */
537  nde = sec->pnode[j]->extnode;
538  pd = nde->param;
539  for (k = 0; k < nlayer; ++k) {
540  *nde->_rhs[k] = 0.;
541  xc[k] = 0.;
542  xg[k] = 0.;
543  }
544  /* if owns a rootnode */
545  if (!sec->parentsec) {
546  nde = sec->parentnode->extnode;
547  pd = nde->param;
548  for (k = 0; k < nlayer; ++k) {
549  *nde->_rhs[k] = 0.;
550  xc[k] = 0.;
551  xg[k] = 0.;
552  }
553  }
554  }
555  }
556  /* assume that if only one connection at x=1, then they butte
557  together, if several connections at x=1
558  then last point is at x=1, has 0 area and other points are at
559  centers of nnode-1 segments.
560  If interior connection then child half
561  section connects straight to the point*/
562  /* for the near future we always have a last node at x=1 with
563  no properties */
564  // ForAllSections(sec)
565  ITERATE(qsec, section_list) {
566  Section* sec = hocSEC(qsec);
567  if (sec->pnode[0]->extnode) {
568  /* node half resistances in general get added to the
569  node and to the node's "child node in the same section".
570  child nodes in different sections don't involve parent
571  node's resistance */
572  nde = sec->pnode[0]->extnode;
573  for (k = 0; k < nlayer; ++k) {
574  nde->_b[k] = *nde->_rhs[k];
575  }
576  for (j = 1; j < sec->nnode; j++) {
577  nde = sec->pnode[j]->extnode;
578  for (k = 0; k < nlayer; ++k) {
579  nde->_b[k] = *nde->_rhs[k] + *(sec->pnode[j - 1]->extnode->_rhs[k]); /*megohms*/
580  }
581  }
582  }
583  }
584  // ForAllSections(sec)
585  ITERATE(qsec, section_list) {
586  Section* sec = hocSEC(qsec);
587  if (sec->pnode[0]->extnode) {
588  /* convert to siemens/cm^2 for all nodes except last
589  and microsiemens for last. This means that a*V = mamps/cm2
590  and a*v in last node = nanoamps. Note that last node
591  has no membrane properties and no area. It may perhaps recieve
592  current stimulus later */
593  /* first the effect of node on parent equation. Note That
594  last nodes have area = 1.e2 in dimensionless units so that
595  last nodes have units of microsiemens's */
596  pnd = sec->pnode;
597  nde = pnd[0]->extnode;
598  area = NODEAREA(sec->parentnode);
599  /* param[4] is rall_branch */
600  for (k = 0; k < nlayer; ++k) {
601  nde->_a[k] = -1.e2 * sec->prop->dparam[4].val / (nde->_b[k] * area);
602  }
603  for (j = 1; j < sec->nnode; j++) {
604  nde = pnd[j]->extnode;
605  area = NODEAREA(pnd[j - 1]);
606  for (k = 0; k < nlayer; ++k) {
607  nde->_a[k] = -1.e2 / (nde->_b[k] * area);
608  }
609  }
610  }
611  }
612  /* now the effect of parent on node equation. */
613  // ForAllSections(sec)
614  ITERATE(qsec, section_list) {
615  Section* sec = hocSEC(qsec);
616  if (sec->pnode[0]->extnode) {
617  for (j = 0; j < sec->nnode; j++) {
618  nd = sec->pnode[j];
619  nde = nd->extnode;
620  for (k = 0; k < nlayer; ++k) {
621  nde->_b[k] = -1.e2 / (nde->_b[k] * NODEAREA(nd));
622  }
623  }
624  }
625  }
626 }
627 
628 #if 0
629 /* needs to be fixed to deal with rootnodes having this property */
630 
631 static void printnode(const char* s) {
632  int in, i, j, k;
633  hoc_Item* qsec;
634  Section* sec;
635  Node* nd;
636  Extnode* nde;
637  double *pd;
638  NrnThread* _nt;
639  FOR_THREADS(_nt) for (in=0; in < _nt->end; ++in) {
640  nd = _nt->_v_node[in];
641  if (nd->extnode) {
642  sec = nd->sec;
643  j = nd->sec_node_index_;
644  nde = nd->extnode;
645  pd = nde->param;
646  for (k=0; k < nlayer; ++k) {
647 printf("%s %s nd%d layer%d v=%g rhs=%g:\n", s, secname(sec), j, k, nde->v[k], *nde->_rhs[k]);
648 printf("xraxial=%g xg=%g xc=%g e=%g\n", xraxial[k], xg[k], xc[k], e_extracellular);
649  }
650  }
651  }
652 }
653 #if 0
654 static int cntndsave;
655 static Extnode* ndesave;
656 
657 void save2mat(void) {
658  int i, j, k, im, ipm;
659  register Node *nd, *pnd;
660  register Extnode *nde, *pnde;
661 
662  if (cntndsave < v_node_count) {
663  if (ndesave) {
664  free(ndesave);
665  }
666  cntndsave = v_node_count;
667  ndesave = (Extnode*)ecalloc(cntndsave, sizeof(Extnode));
668  }
669  for (i=0; i < v_node_count; ++i) {
670  nd = v_node[i];
671  nde = nd->extnode;
672  if (nde) {
673  for (j=0; j < nlayer; ++j) {
674  ndesave[i].v[j] = nde->v[j];
675  ndesave[i].rhs[j] = nde->_rhs[j];
676  for (k=0; k < 2*(nlayer)+1; ++k) {
677  ndesave[i].m[j][k] = nde->_m[j][k];
678  }
679  if (!v_parent[i]->extnode && j > 0) {
680  ndesave[i].m[j][0] = 0.;
681  ndesave[i].m[j][2*(nlayer)] = 0.;
682  }
683  }
684  }else{
685  for (j=0; j < nlayer; ++j) {
686  ndesave[i].m[j][nlayer] = 1;
687  }
688  ndesave[i].v[0] = nd->v;
689  ndesave[i].m[0][nlayer] = NODED(nd);
690  ndesave[i].rhs[0] = NODERHS(nd);
691  ndesave[i].m[0][0] = NODEB(nd);
692  ndesave[i].m[0][2*(nlayer)] = NODEA(nd);
693  }
694  }
695 }
696 
697 #if 0
698 #define DBG printf
699 #else
700 DBG() {}
701 #endif
702 
703 void check2mat(void) {
704  int i, j, k, im, ip;
705  Node* nd;
706  Extnode* nde;
707  double sum;
708 
709  /* copy solved v to saved v */
710  for (i=0; i < v_node_count; ++ i) {
711  nd = v_node[i];
712  nde = nd->extnode;
713  if (nde) {
714  for (j=0; j < (nlayer); ++j) {
715  ndesave[i].v[j] = nde->_rhs[j];
716  }
717  }else{
718  ndesave[i].v[0] = NODERHS(nd);
719  }
720  }
721 
722 #if 0
723  printf("mat\n");
724  for (i=0; i < v_node_count; ++i) {
725  printf("node %d\n", i);
726  for (j=0; j < (nlayer); ++j) {
727  printf("%d %d ", j, i);
728  for (k=0; k <= 2*(nlayer); ++k) {
729  printf(" %-8.3g", ndesave[i].m[j][k]);
730  }
731  printf(" %g %g\n", ndesave[i].v[j], ndesave[i].rhs[j]);
732  }
733  }
734 #endif
735 
736  /* rhs - M*V accomplished by subtracting every term from rhs */
737  for (i=0; i < v_node_count; ++i) {
738 DBG("work on node %d\n", i);
739  if (v_parent[i]) {
740  ip = v_parent[i]->v_node_index;
741  /* effect of parent on node */
742 DBG(" effect of parent %d on node %d\n", ip, i);
743  for (j=0; j < nlayer; ++j) {
744 DBG(" work on layer %d\n", j);
745  for (k=j; k < nlayer; ++k) {
746 DBG(" nde[%d].rhs[%d] -= nde[%d].v[%d]*nde[%d].m[%d][%d]\n", i,j,ip,k,i,j,k-j);
747 DBG(" %g * %g\n",ndesave[ip].v[k],ndesave[i].m[j][k-j]);
748 ndesave[i].rhs[j] -= ndesave[ip].v[k]*ndesave[i].m[j][k-j];
749  }
750  }
751  /* effect of node on parent */
752 DBG(" effect of node %d on parent %d\n", i, ip);
753  for (j=0; j < nlayer; ++j) {
754 DBG(" work on layer %d\n", j);
755  for (k=0; k <= j; ++k) {
756 DBG(" nde[%d].rhs[%d] -= nde[%d].v[%d]*nde[%d].m[%d][%d]\n", ip,j,i,k,i,j,2*(nlayer)-j+k);
757 DBG(" %g * %g\n",ndesave[i].v[k],ndesave[i].m[j][2*(nlayer)-j+k]);
758 ndesave[ip].rhs[j] -= ndesave[i].v[k]*ndesave[i].m[j][2*(nlayer)-j+k];
759  }
760  }
761  }
762  /* effect of node on node */
763 DBG(" effect of node %d on node %d\n", i, i);
764  for (j=0; j < nlayer; ++j) {
765 DBG(" work on layer %d\n", j);
766  for (k=0; k < nlayer; ++k) {
767 DBG(" nde[%d].rhs[%d] -= nde[%d].v[%d]*nde[%d].m[%d][%d]\n", i,j,i,k,i,j,(nlayer)+k-j);
768 DBG(" %g * %g\n",ndesave[i].v[k],ndesave[i].m[j][(nlayer)+k-j]);
769 ndesave[i].rhs[j] -= ndesave[i].v[k]*ndesave[i].m[j][(nlayer)+k-j];
770  }
771  }
772  }
773 
774  for (i=0; i < v_node_count; ++i) {
775  for (j=0; j < (nlayer); ++j) {
776  if (fabs(ndesave[i].rhs[j]) > 1e-5) {
777  printf("bad soln of eq %d,%d rhs-M*V=%g\n",
778  i,j, ndesave[i].rhs[j]);
779  }
780  }
781  }
782 }
783 #endif
784 #endif
785 
786 
787 #endif /*EXTRACELLULAR*/
const char * secname(Section *sec)
Definition: cabcode.cpp:1776
double section_length(Section *sec)
Definition: cabcode.cpp:387
int nrn_get_mechtype(const char *mechname)
Definition: cabcode.cpp:2000
short type
Definition: cabvars.h:9
static Node * pnd
Definition: clamp.cpp:33
Symbol * hoc_table_lookup(const char *, Symlist *)
Definition: symbol.cpp:61
int secondorder
Definition: init.cpp:96
double * nrn_prop_data_alloc(int type, int count, Prop *p)
Definition: cxprop.cpp:277
double chkarg(int, double low, double high)
Definition: code2.cpp:638
void register_mech(const char **, Pvmp, Pvmi, Pvmi, Pvmi, Pvmi, int, int)
Definition: init.cpp:674
static int _ode_count(int type)
Definition: extcelln.cpp:61
static HocParmUnits units[]
Definition: extcelln.cpp:40
void nrn_update_2d(NrnThread *nt)
Definition: extcelln.cpp:100
static HocParmLimits limits[]
Definition: extcelln.cpp:38
static void extcell_init(NrnThread *nt, Memb_list *ml, int type)
Definition: extcelln.cpp:194
int nrn_nlayer_extracellular
Definition: extcelln.cpp:18
#define xraxial
Definition: extcelln.cpp:85
void extracell_reg_(void)
Definition: extcelln.cpp:72
#define sav_g
Definition: extcelln.cpp:91
void ext_con_coef(void)
Definition: extcelln.cpp:514
void nlayer_extracellular()
Definition: extcelln.cpp:274
#define xc
Definition: extcelln.cpp:87
#define sav_rhs
Definition: extcelln.cpp:92
void nrn_extcell_update_param(void)
Definition: extcelln.cpp:331
int cvode_active_
Definition: fadvance.cpp:163
static void extnode_alloc_elements(Extnode *nde)
Definition: extcelln.cpp:292
static void extcell_alloc(Prop *)
Definition: extcelln.cpp:172
static void check_if_extracellular_in_use()
Definition: extcelln.cpp:230
static int nparm()
Definition: extcelln.cpp:161
void nrn_rhs_ext(NrnThread *_nt)
Definition: extcelln.cpp:364
void extcell_2d_alloc(Section *sec)
Definition: extcelln.cpp:348
int nrn_use_daspk_
Definition: treeset.cpp:72
#define e_extracellular
Definition: extcelln.cpp:88
static void update_extracellular_reg(int old_nlayer)
Definition: extcelln.cpp:251
void nrn_delete_prop_pool(int type)
Definition: cxprop.cpp:257
void extcell_node_create(Node *nd)
Definition: extcelln.cpp:308
static const char * mechanism[]
Definition: extcelln.cpp:23
#define xg
Definition: extcelln.cpp:86
#define i_membrane
Definition: extcelln.cpp:90
static void update_existing_extnode(int old_nlayer)
Definition: extcelln.cpp:240
void nrn_setup_ext(NrnThread *_nt)
Definition: extcelln.cpp:443
void extnode_free_elements(Extnode *nde)
Definition: extcelln.cpp:214
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:754
void hoc_retpushx(double x)
Definition: hocusr.cpp:154
#define assert(ex)
Definition: hocassrt.h:32
void * ecalloc(size_t n, size_t size)
Definition: symbol.cpp:215
#define hocSEC(q)
Definition: hoclist.h:66
Symlist * hoc_built_in_symlist
Definition: ivocmac.cpp:76
int ifarg(int)
Definition: code.cpp:1581
#define rhs
Definition: lineq.h:6
#define area
Definition: md1redef.h:5
#define v
Definition: md1redef.h:4
#define extnode
Definition: md1redef.h:9
#define sec
Definition: md1redef.h:13
#define i
Definition: md1redef.h:12
void(* Pvmi)(struct NrnThread *, Memb_list *, int)
Definition: membfunc.h:18
#define ITERATE(itm, lst)
Definition: model.h:25
fabs
Definition: extdef.h:3
#define FOR_THREADS(nt)
Definition: multicore.h:104
#define printf
Definition: mwprefix.h:26
size_t p
size_t j
void hoc_register_limits(int type, HocParmLimits *limits)
Definition: init.cpp:874
hoc_List * section_list
Definition: init.cpp:102
void hoc_register_units(int type, HocParmUnits *units)
Definition: init.cpp:891
void hoc_register_cvode(int i, nrn_ode_count_t cnt, nrn_ode_map_t map, Pvmi spec, Pvmi matsol)
Definition: init.cpp:767
static philox4x32_key_t k
Definition: nrnran123.cpp:11
#define EXTRACELLULAR
Definition: options.h:19
#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 NODEV(n)
Definition: section.h:115
#define NODEAREA(n)
Definition: section.h:116
#define NODERHS(n)
Definition: section.h:105
#define nlayer
Definition: section.h:188
#define NODED(n)
Definition: section.h:104
#define cnt
Definition: spt2queue.cpp:19
#define NULL
Definition: sptree.h:16
int nsub
Definition: hocdec.h:70
int sub[1]
Definition: hocdec.h:72
double ** _a_matelm
Definition: section.h:201
double ** _b_matelm
Definition: section.h:202
double * _b
Definition: section.h:198
double ** _x21
Definition: section.h:204
double ** _x12
Definition: section.h:203
double * _a
Definition: section.h:197
double * param
Definition: section.h:190
double * v
Definition: section.h:196
double ** _d
Definition: section.h:199
double ** _rhs
Definition: section.h:200
int nodecount
Definition: nrnoc_ml.h:18
Node ** nodelist
Definition: nrnoc_ml.h:5
double ** data
Definition: nrnoc_ml.h:14
Definition: section.h:133
struct Extnode * extnode
Definition: section.h:161
Section * sec
Definition: section.h:155
int v_node_index
Definition: section.h:175
struct Prop * prop
Definition: section.h:152
int sec_node_index_
Definition: section.h:177
Represent main neuron object computed by single thread.
Definition: multicore.h:58
double cj
Definition: multicore.h:61
int end
Definition: multicore.h:65
int _ecell_child_cnt
Definition: multicore.h:68
Node ** _v_parent
Definition: multicore.h:78
Node ** _ecell_children
Definition: multicore.h:81
Memb_list * _ecell_memb_list
Definition: multicore.h:80
Node ** _v_node
Definition: multicore.h:77
Definition: section.h:214
Definition: model.h:57
HocStruct Symbol ** ppsym
Definition: hocdec.h:150
short type
Definition: model.h:58
struct Symbol::@37::@38 rng
union Symbol::@18 u
unsigned s_varn
Definition: hocdec.h:158
Arrayinfo * arayinfo
Definition: hocdec.h:159