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