NEURON
solve.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 /* /local/src/master/nrn/src/nrnoc/solve.cpp,v 1.15 1999/07/12 14:34:13 hines Exp */
3 
4 /* solve.cpp 15-Dec-88 */
5 
6 /* The data structures in section.h were developed primarily for the needs of
7  solving and setting up the matrix equations reasonably efficiently in
8  space and time. I am hypothesizing that they will also be convenient
9  for accessing parameters.
10  Important properties of the structures used here are:
11  Each section must have at least one node. There may be 0 sections.
12  The order for back substitution is given by section[i]->order.
13  The order of last node to first node is used in triangularization.
14  First node to last is used in back substitution.
15 */
16 /* An equation is associated with each node. d and rhs are the diagonal and
17  right hand side respectively. a is the effect of this node on the parent
18  node's equation. b is the effect of the parent node on this node's
19  equation.
20  d is assumed to be non-zero.
21 */
22 
23 /* We have seen that it is best to have nodes generally denote the
24  centers of segments because most properties are most easily defined
25  at those points. The old problem then arises again of 2nd order correct
26  demands that a point be exactly at any branches. For this reason we
27  always allocate one extra node at the end with 0 length. Sections
28  that connect at x=1 connect to this node. Sections that connect
29  from 0<x<1 connect to nodes 0 to nnode-2 directly to the point
30  (no parent resistance, only a half segment resistance). It was an error
31  to try to connect a section to position 0. Now we are going to allow
32  that by the following artifice.
33 
34  Section 0 is always special. Its nodes act as roots to the independent
35  trees. They do not connect to each other. It has no properties.
36 */
37 
38 #if EXTRACELLULAR
39 /* Two users (Padjen and Shrager) require that the extracellular potential
40 be simulated. To do this we introduce a new node structure into the
41 section called extnode. This points to a vector of extnodes containing
42 the extracellular potential, the Node vector
43 is interpreted as the internal potential. Thus the membrane potential is
44 node[i].v - extnode[i].v[0]
45 */
46 /*
47 With vectorization, node.v is the membrane potential and node.rhs
48 after solving is the internal potential. Thus internal potential is
49 node.v + extnode.v[0]
50 */
51 
52 #endif
53 
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <math.h>
57 #include <nrnmpiuse.h>
58 #include "section.h"
59 #include "membdef.h"
60 #include "membfunc.h"
61 #include "spmatrix.h"
62 
63 extern int tree_changed;
64 static void node_free();
65 static void triang(NrnThread*), bksub(NrnThread*);
66 
67 #if PARANEURON
68 void (*nrnmpi_splitcell_compute_)();
69 #endif
70 
72 extern void (*nrnpy_o2loc_p_)(Object*, Section**, double*);
73 extern void (*nrnpy_o2loc2_p_)(Object*, Section**, double*);
74 
75 /* used for vectorization and distance calculations */
78 
79 /* nrn_solve() solves the matrix equations represented in "section"
80  rhs is replaced by the solution (delta v's).
81  d is destroyed.
82 */
83 /* Section *sec_alloc(nsec) allocates a vector of nsec sections and returns a
84  pointer to the first one in the list. No nodes are allocated.
85  The usage is normally "section = sec_alloc(nsection)"
86  After allocation one must allocate nodes for each section with
87  node_alloc(sec, n).
88  After all this connect sections together using section indices.
89  Finally order the sections with section_order(section, nsec).
90  When the section vector is no longer needed (and before creating another
91  one) free the space with sec_free(section, nsection);
92 */
93 
94 #if DEBUGSOLVE
95 double debugsolve(void) /* returns solution error */
96 {
97  short inode;
98  int i;
99  Section *sec, *psec, *ch;
100  Node *nd, *pnd, **ndP;
101  double err, sum;
102 
103  /* save parts of matrix that will be destroyed */
104  assert(0)
105  /* need to save the rootnodes too */
106  // ForAllSections(sec)
107  ITERATE(qsec, section_list) {
108  Section* sec = hocSEC(qsec);
109  assert(sec->pnode && sec->nnode);
110  for (inode = sec->nnode - 1; inode >= 0; inode--) {
111  nd = sec->pnode[inode];
112  nd->savd = NODED(nd);
113  nd->savrhs = NODERHS(nd);
114  }
115  }
116 
119 
120  err = 0.;
121  /* need to check the rootnodes too */
122  // ForAllSections(sec)
123  ITERATE(qsec, section_list) {
124  Section* sec = hocSEC(qsec);
125  for (inode = sec->nnode - 1; inode >= 0; inode--) {
126  ndP = sec->pnode + inode;
127  nd = sec->pnode[inode];
128  /* a single internal current equation */
129  sum = nd->savd * NODERHS(nd);
130  if (inode > 0) {
131  sum += NODEB(nd) * NODERHS(nd - 1);
132  } else {
133  pnd = sec->parentnode;
134  sum += NODEB(nd) * NODERHS(pnd);
135  }
136  if (inode < sec->nnode - 1) {
137  sum += NODEA(ndP[1]) * NODERHS(ndP[1]);
138  }
139  for (ch = nd->child; ch; ch = ch->sibling) {
140  psec = ch;
141  pnd = psec->pnode[0];
142  assert(pnd && psec->nnode);
143  sum += NODEA(pnd) * NODERHS(pnd);
144  }
145  sum -= nd->savrhs;
146  err += fabs(sum);
147  }
148  }
149 
150  return err;
151 }
152 #endif /*DEBUGSOLVE*/
153 
154 
156  int inode;
157  double ratio;
158 
159  if (!sec || sec->parentnode == node) {
160  return 0.;
161  } else if ((inode = node->sec_node_index_) == sec->nnode - 1) {
162  ratio = 1.;
163  } else {
164  ratio = ((double) inode + .5) / ((double) sec->nnode - 1.);
165  }
166  return section_length(sec) * ratio;
167 }
168 
169 double topol_distance(Section* sec1,
170  Node* node1,
171  Section* sec2,
172  Node* node2,
173  Section** prootsec,
174  Node** prootnode) { /* returns the distance between the two nodes
175  Ie the sum of the appropriate length portions
176  of those sections connecting these two
177  nodes.
178  */
179  double d, x1, x2;
180 
181  d = 0;
182  if (tree_changed) {
183  setup_topology();
184  }
185  /* keep moving toward a common node */
186  while (sec1 != sec2) {
187  if (!sec1) {
188  d += node_dist(sec2, node2);
189  node2 = sec2->parentnode;
190  sec2 = sec2->parentsec;
191  } else if (!sec2) {
192  d += node_dist(sec1, node1);
193  node1 = sec1->parentnode;
194  sec1 = sec1->parentsec;
195  } else if (sec1->order > sec2->order) {
196  d += node_dist(sec1, node1);
197  node1 = sec1->parentnode;
198  sec1 = sec1->parentsec;
199  } else {
200  d += node_dist(sec2, node2);
201  node2 = sec2->parentnode;
202  sec2 = sec2->parentsec;
203  }
204  }
205  if (!sec1) {
206  if (node1 != node2) {
207  sec1 = 0;
208  d = 1e20;
209  node1 = (Node*) 0;
210  }
211  } else if (node1 != node2) {
212  x1 = node_dist(sec1, node1);
213  x2 = node_dist(sec2, node2);
214  if (x1 < x2) {
215  d += x2 - x1;
216  } else {
217  node1 = node2;
218  d += x1 - x2;
219  }
220  }
221  *prootsec = sec1;
222  *prootnode = node1;
223  return d;
224 }
225 
227 
228 void distance(void) {
229  double d, d_origin;
230  int mode;
231  Node* node;
232  Section* sec;
233  static Node* origin_node;
234  Node* my_origin_node;
235  Section* my_origin_sec;
236 
237  if (tree_changed) {
238  setup_topology();
239  }
240 
241  if (ifarg(2)) {
242  nrn_seg_or_x_arg2(2, &sec, &d);
243  if (hoc_is_double_arg(1)) {
244  mode = (int) chkarg(1, 0., 1.);
245  } else {
246  mode = 2;
247  Object* o = *hoc_objgetarg(1);
248  my_origin_sec = (Section*) 0;
249  if (nrnpy_o2loc2_p_) {
250  (*nrnpy_o2loc2_p_)(o, &my_origin_sec, &d_origin);
251  }
252  if (!my_origin_sec) {
253  hoc_execerror("Distance origin not valid.",
254  "If first argument is an Object, it needs to be a Python Segment "
255  "object, a rxd.node object, or something with a segment property.");
256  }
257  my_origin_node = node_exact(my_origin_sec, d_origin);
258  }
259  } else if (ifarg(1)) {
260  nrn_seg_or_x_arg2(1, &sec, &d);
261  mode = 1;
262  } else {
263  sec = chk_access();
264  d = 0.;
265  mode = 0;
266  }
267  node = node_exact(sec, d);
268  if (mode == 0) {
269  origin_node = node;
270  origin_sec = sec;
271  } else {
272  if (mode != 2 && (!origin_sec || !origin_sec->prop)) {
273  hoc_execerror("Distance origin not valid.",
274  "Need to initialize origin with distance()");
275  }
276  if (mode == 1) {
277  my_origin_sec = origin_sec;
278  my_origin_node = origin_node;
279  }
280  d = topol_distance(my_origin_sec, my_origin_node, sec, node, &sec, &node);
281  }
282  hoc_retpushx(d);
283 }
284 
285 static void dashes(Section* sec, int offset, int first);
286 
287 void nrnhoc_topology(void) /* print the topology of the branched cable */
288 {
289  hoc_Item* q;
290 
291  v_setup_vectors();
292  Printf("\n");
294  Section* sec = (Section*) VOIDITM(q);
295  if (sec->parentsec == (Section*) 0) {
296  Printf("|");
297  dashes(sec, 0, '-');
298  }
299  }
300  Printf("\n");
301  hoc_retpushx(1.);
302 }
303 
304 static void dashes(Section* sec, int offset, int first) {
305  int i, scnt;
306  Section* ch;
307  char direc[30];
308 
309  i = (int) nrn_section_orientation(sec);
310  sprintf(direc, "(%d-%d)", i, 1 - i);
311  for (i = 0; i < offset; i++)
312  Printf(" ");
313  Printf("%c", first);
314  for (i = 2; i < sec->nnode; i++)
315  Printf("-");
316  if (sec->prop->dparam[4].val == 1) {
317  Printf("| %s%s\n", secname(sec), direc);
318  } else {
319  Printf("| %s%s with %g rall branches\n",
320  secname(sec),
321  direc,
322  sec->prop->dparam[4].val);
323  }
324  /* navigate the sibling list backwards */
325  /* note that the sibling list is organized monotonically by
326  increasing distance from parent */
327  for (scnt = 0, ch = sec->child; ch; ++scnt, ch = ch->sibling) {
328  hoc_pushobj((Object**) ch);
329  }
330  while (scnt--) {
331  ch = (Section*) hoc_objpop();
333  Printf(" ");
334  dashes(ch, i + offset + 1, 0140); /* the ` char*/
335  }
336 }
337 
338 /* solve the matrix equation */
339 void nrn_solve(NrnThread* _nt) {
340 #if 0
341  printf("\nnrn_solve enter %lx\n", (long)_nt);
342  nrn_print_matrix(_nt);
343 #endif
344 #if PARANEURON
345  if (nrn_multisplit_solve_) {
346  nrn_thread_error("nrn_multisplit_solve");
347  (*nrn_multisplit_solve_)();
348  return;
349  }
350 #endif
351 
352 #if DEBUGSOLVE
353  {
354  double err;
355  nrn_thread_error("debugsolve");
356  err = debugsolve();
357  if (err > 1.e-10) {
358  Fprintf(stderr, "solve error = %g\n", err);
359  }
360  }
361 #else
362  if (use_sparse13) {
363  int e;
364  nrn_thread_error("solve use_sparse13");
365  e = spFactor(_nt->_sp13mat);
366  if (e != spOKAY) {
367  switch (e) {
368  case spZERO_DIAG:
369  hoc_execerror("spFactor error:", "Zero Diagonal");
370  case spNO_MEMORY:
371  hoc_execerror("spFactor error:", "No Memory");
372  case spSINGULAR:
373  hoc_execerror("spFactor error:", "Singular");
374  }
375  }
376  spSolve(_nt->_sp13mat, _nt->_actual_rhs, _nt->_actual_rhs);
377  } else {
378  triang(_nt);
379 #if PARANEURON
380  if (nrnmpi_splitcell_compute_) {
381  nrn_thread_error("nrnmpi_splitcell_compute");
382  (*nrnmpi_splitcell_compute_)();
383  }
384 #endif
385  bksub(_nt);
386  }
387 #endif
388 #if 0
389  printf("\nnrn_solve leave %lx\n", (long)_nt);
390  nrn_print_matrix(_nt);
391 #endif
392 }
393 
394 #if VECTORIZE && _CRAY
395 extern Node*** v_node_depth_lists;
396 extern Node*** v_parent_depth_lists; /* parents must be unique in each list */
397 extern int* v_node_depth_count;
398 extern int v_node_depth; /* so depth may be more than twice what you'd expect */
399 #endif
400 
401 /* triangularization of the matrix equations */
402 void triang(NrnThread* _nt) {
403  Node *nd, *pnd;
404  double p;
405  int i, i2, i3;
406  i2 = _nt->ncell;
407  i3 = _nt->end;
408 #if CACHEVEC
409  if (use_cachevec) {
410  for (i = i3 - 1; i >= i2; --i) {
411  p = VEC_A(i) / VEC_D(i);
412  VEC_D(_nt->_v_parent_index[i]) -= p * VEC_B(i);
413  VEC_RHS(_nt->_v_parent_index[i]) -= p * VEC_RHS(i);
414  }
415  } else
416 #endif /* CACHEVEC */
417  {
418  for (i = i3 - 1; i >= i2; --i) {
419  nd = _nt->_v_node[i];
420  pnd = _nt->_v_parent[i];
421  p = NODEA(nd) / NODED(nd);
422  NODED(pnd) -= p * NODEB(nd);
423  NODERHS(pnd) -= p * NODERHS(nd);
424  }
425  }
426 }
427 
428 /* back substitution to finish solving the matrix equations */
429 void bksub(NrnThread* _nt) {
430  Node *nd, *cnd;
431  int i, i1, i2, i3;
432  i1 = 0;
433  i2 = i1 + _nt->ncell;
434  i3 = _nt->end;
435 #if CACHEVEC
436  if (use_cachevec) {
437  for (i = i1; i < i2; ++i) {
438  VEC_RHS(i) /= VEC_D(i);
439  }
440  for (i = i2; i < i3; ++i) {
441  VEC_RHS(i) -= VEC_B(i) * VEC_RHS(_nt->_v_parent_index[i]);
442  VEC_RHS(i) /= VEC_D(i);
443  }
444  } else
445 #endif /* CACHEVEC */
446  {
447  for (i = i1; i < i2; ++i) {
448  NODERHS(_nt->_v_node[i]) /= NODED(_nt->_v_node[i]);
449  }
450  for (i = i2; i < i3; ++i) {
451  cnd = _nt->_v_node[i];
452  nd = _nt->_v_parent[i];
453  NODERHS(cnd) -= NODEB(cnd) * NODERHS(nd);
454  NODERHS(cnd) /= NODED(cnd);
455  }
456  }
457 }
458 
459 void nrn_clear_mark(void) {
460  hoc_Item* qsec;
461  // ForAllSections(sec)
462  ITERATE(qsec, section_list) {
463  Section* sec = hocSEC(qsec);
464  sec->volatile_mark = 0;
465  }
466 }
468  return sec->volatile_mark++;
469 }
471  return sec->volatile_mark;
472 }
473 
474 /* allocate space for sections (but no nodes) */
475 /* returns pointer to Section */
477  Section* sec;
478 
479  /* changed from emalloc to allocation from a SectionPool in order
480  to allow safe checking of whether a void* is a possible Section*
481  without the possibility of invalid memory read errors.
482  Note that freeing sections must be done
483  with nrn_section_free(Section*)
484  */
486  sec->refcount = 0;
487  sec->nnode = 0;
488  sec->parentsec = sec->sibling = sec->child = (Section*) 0;
489  sec->parentnode = (Node*) 0;
490  sec->pnode = (Node**) 0;
491 #if DIAMLIST
492  sec->npt3d = 0;
493  sec->pt3d_bsize = 0;
494  sec->pt3d = (Pt3d*) 0;
495  sec->logical_connection = (Pt3d*) 0;
496 #endif
497  sec->prop = (Prop*) 0;
498  sec->recalc_area_ = 0;
499 
500  return sec;
501 }
502 
503 /* free a node vector for one section */
504 static void node_free(Section* sec) {
505  Node** pnd;
506 
507  pnd = sec->pnode;
508  if (!pnd) {
509  sec->nnode = 0;
510  }
511  if (sec->nnode == 0) {
512  return;
513  }
514  node_destruct(sec->pnode, sec->nnode);
515  sec->pnode = (Node**) 0;
516  sec->nnode = 0;
517 }
518 
519 static void section_unlink(Section* sec);
520 /* free everything about sections */
521 void sec_free(hoc_Item* secitem) {
522  Section* sec;
523 
524  if (!secitem) {
525  return;
526  }
527  sec = hocSEC(secitem);
528  assert(sec);
529  /*printf("sec_free %s\n", secname(sec));*/
531  {
532  Object* ob = sec->prop->dparam[6].obj;
533  if (ob && ob->secelm_ == secitem) { /* it is the last */
534  hoc_Item* q = secitem->prev;
535  if (q->itemtype && hocSEC(q)->prop && hocSEC(q)->prop->dparam[6].obj == ob) {
536  ob->secelm_ = q;
537  } else {
538  ob->secelm_ = (hoc_Item*) 0;
539  }
540  }
541  }
542  hoc_l_delete(secitem);
543  prop_free(&(sec->prop));
544  node_free(sec);
545  if (!sec->parentsec && sec->parentnode) {
546  nrn_node_destruct1(sec->parentnode);
547  }
548 #if DIAMLIST
549  if (sec->pt3d) {
550  free((char*) sec->pt3d);
551  sec->pt3d = (Pt3d*) 0;
552  sec->npt3d = 0;
553  sec->pt3d_bsize = 0;
554  }
555  if (sec->logical_connection) {
556  free(sec->logical_connection);
557  sec->logical_connection = (Pt3d*) 0;
558  }
559 #endif
561 }
562 
563 
564 /* can't actually release the space till the refcount goes to 0 */
566  /*printf("section_unref %lx %d\n", (long)sec, sec->refcount-1);*/
567  if (--sec->refcount <= 0) {
568 #if 0
569 printf("section_unref: freed\n");
570 #endif
571  assert(!sec->parentsec);
573  }
574 }
576  /*printf("section_ref %lx %d\n", (long)sec,sec->refcount+1);*/
577  ++sec->refcount;
578 }
579 
580 void nrn_sec_ref(Section** psec, Section* sec) {
581  Section* s = *psec;
582  if (sec) {
583  section_ref(sec);
584  }
585  *psec = sec;
586  if (s) {
587  section_unref(s);
588  }
589 }
590 
591 static void section_unlink(Section* sec) /* other sections no longer reference this one */
592 {
593  /* only sections that are explicitly connected to this are disconnected */
594  Section* child;
595  tree_changed = 1;
596  /* disconnect the sections connected to this at the parent end */
597  for (child = sec->child; child; child = child->sibling) {
598  nrn_disconnect(child);
599  }
601 }
602 
604  Node *nd, **pnode;
605  int i;
606 
607  pnode = (Node**) ecalloc((unsigned) n, sizeof(Node*));
608  for (i = n - 1; i >= 0; i--) {
609  nd = (Node*) ecalloc(1, sizeof(Node));
610 #if CACHEVEC
611  nd->_v = &nd->_v_temp;
612  nd->_area = 100.;
613  nd->_rinv = 0.;
614 #endif
615  nd->sec_node_index_ = i;
616  pnode[i] = nd;
617  nd->prop = (Prop*) 0;
618  NODEV(nd) = DEF_vrest;
619 #if EXTRACELLULAR
620  nd->extnode = (Extnode*) 0;
621 #endif
622 #if EXTRAEQN
623  nd->eqnblock = (Eqnblock*) 0;
624 #endif
625  }
626  return pnode;
627 }
628 
630  Node* nd;
631  Node** ndp;
632  ndp = node_construct(1);
633  nd = ndp[0];
634  free(ndp);
635  return nd;
636 }
637 
639  if (!nd) {
640  return;
641  }
642  prop_free(&(nd->prop));
643 #if CACHEVEC
644  notify_freed_val_array(&NODEV(nd), 1);
646 #else
647  notify_freed_val_array(&NODEV(nd), 2);
648 #endif
649 #if EXTRACELLULAR
650  if (nd->extnode) {
652  }
653 #endif
654 #if EXTRAEQN
655  {
656  Eqnblock *e, *e1;
657  for (e = nd->eqnblock; e; e = e1) {
658  e1 = e->eqnblock_next;
659  free((char*) e);
660  }
661  }
662 #endif
663 #if EXTRACELLULAR
664  if (nd->extnode) {
666  free((char*) nd->extnode);
667  }
668 #endif
669  free(nd);
670 }
671 
672 void node_destruct(Node** pnode, int n) {
673  int i;
674  Node* nd;
675 
676  for (i = n - 1; i >= 0; i--) {
677  if (pnode[i]) {
679  }
680  }
681  free((char*) pnode);
682 }
683 
684 #if KEEP_NSEG_PARM
685 
686 extern int keep_nseg_parm_;
687 
688 static Node* node_clone(Node* nd1) {
689  Node* nd2;
690  Prop *p1, *p2;
691  extern Prop* prop_alloc(Prop**, int, Node*);
692  int i, imax;
693  nd2 = (Node*) ecalloc(1, sizeof(Node));
694 #if CACHEVEC
695  nd2->_v = &nd2->_v_temp;
696 #endif
697  NODEV(nd2) = NODEV(nd1);
698  for (p1 = nd1->prop; p1; p1 = p1->next) {
699  if (!memb_func[p1->type].is_point) {
700  p2 = prop_alloc(&(nd2->prop), p1->type, nd2);
701  if (p2->ob) {
702  Symbol *s, *ps;
703  double *px, *py;
704  int j, jmax;
705  s = memb_func[p1->type].sym;
706  jmax = s->s_varn;
707  for (j = 0; j < jmax; ++j) {
708  ps = s->u.ppsym[j];
709  px = p2->ob->u.dataspace[ps->u.rng.index].pval;
710  py = p1->ob->u.dataspace[ps->u.rng.index].pval;
711  imax = hoc_total_array_data(ps, 0);
712  for (i = 0; i < imax; ++i) {
713  px[i] = py[i];
714  }
715  }
716  } else {
717  for (i = 0; i < p1->param_size; ++i) {
718  p2->param[i] = p1->param[i];
719  }
720  }
721  }
722  }
723  /* in case the user defined an explicit ion_style, make sure
724  the new node has the same style for all ions. */
725  for (p1 = nd1->prop; p1; p1 = p1->next) {
726  if (nrn_is_ion(p1->type)) {
727  p2 = nd2->prop;
728  while (p2 && p2->type != p1->type) {
729  p2 = p2->next;
730  }
731  assert(p2 && p1->type == p2->type);
732  p2->dparam[0].i = p1->dparam[0].i;
733  }
734  }
735 
736  return nd2;
737 }
738 
739 static Node* node_interp(Node* nd1, Node* nd2, double frac) {
740  Node* nd;
741  if (frac > .5) {
742  nd = node_clone(nd2);
743  } else {
744  nd = node_clone(nd1);
745  }
746  return nd;
747 }
748 
749 static void node_realloc(Section* sec, short nseg) {
750  Node **pn1, **pn2;
751  int n1, n2, i1, i2, i;
752  double x;
753  pn1 = sec->pnode;
754  n1 = sec->nnode;
755  pn2 = (Node**) ecalloc((unsigned) nseg, sizeof(Node*));
756  n2 = nseg;
757  sec->pnode = pn2;
758  sec->nnode = n2;
759 
760  n1--;
761  n2--; /* number of non-zero area segments */
762  pn2[n2] = pn1[n1]; /* 0 area node at end of section */
763  pn1[n1] = (Node*) 0;
764 
765  /* sprinkle nodes from pn1 to pn2 */
766  if (n1 < n2) {
767  /* the ones that are reused */
768  for (i1 = 0; i1 < n1; ++i1) {
769  x = (i1 + .5) / (double) n1;
770  i2 = (int) (n2 * x); /* because we want to round to n2*x-.5 */
771  pn2[i2] = pn1[i1];
772  }
773  /* the ones that are cloned */
774  for (i2 = 0; i2 < n2; ++i2)
775  if (pn2[i2] == NULL) {
776  x = (i2 + 0.5) / (double) n2;
777  i1 = (int) (n1 * x);
778  pn2[i2] = node_clone(pn1[i1]);
779  }
780  for (i1 = 0; i1 < n1; ++i1) {
781  pn1[i1] = (Node*) 0;
782  }
783  } else {
784  for (i2 = 0; i2 < n2; ++i2) {
785  x = (i2 + .5) / (double) n2;
786  i1 = (int) (n1 * x);
787  pn2[i2] = pn1[i1];
788  pn1[i1] = (Node*) 0;
789  }
790  /* do not lose any point processes */
791  i1 = 0;
792  for (i2 = 0; i2 < n2; ++i2) {
793  double x1, x2;
794  x2 = (i2 + 1.) / (double) n2; /* far end of new segment */
795  for (; i1 < n1; ++i1) {
796  x1 = (i1 + .5) / (double) n1;
797  if (x1 > x2) {
798  break;
799  }
800  if (pn1[i1] == (Node*) 0) {
801  continue;
802  }
803 #if 0
804 printf("moving point processes from pn1[%d] to pn2[%d]\n", i1, i2);
805 printf("i.e. x1=%g in the range %g to %g\n", x1, x2-1./n2, x2);
806 #endif
807  nrn_relocate_old_points(sec, pn1[i1], sec, pn2[i2]);
808  }
809  }
810  /* Some of the pn1 were not used */
811  }
812  node_destruct(pn1, n1 + 1);
813  for (i2 = 0; i2 < nseg; ++i2) {
814  pn2[i2]->sec_node_index_ = i2;
815  }
816 #if EXTRACELLULAR
817  if (sec->pnode[sec->nnode - 1]->extnode) {
819  }
820 #endif
821 }
822 
823 #endif
824 
825 /* allocate node vectors for a section list */
826 void node_alloc(Section* sec, short nseg) {
827  int i;
828 #if KEEP_NSEG_PARM
829  if (keep_nseg_parm_ && (nseg > 0) && sec->pnode) {
830  node_realloc(sec, nseg);
831  } else
832 #endif
833  {
834  node_free(sec);
835  if (nseg == 0) {
836  return;
837  }
838  sec->pnode = node_construct(nseg);
839  sec->nnode = nseg;
840  }
841  for (i = 0; i < nseg; ++i) {
842  sec->pnode[i]->sec = sec;
843  }
844 }
845 
846 void section_order(void) /* create a section order consistent */
847  /* with connection info */
848 {
849  int order, isec;
850  Section* ch;
851  Section* sec;
852  hoc_Item* qsec;
853 
854  /* count the sections */
855  section_count = 0;
856  /*SUPPRESS 765*/
857  // ForAllSections(sec)
858  ITERATE(qsec, section_list) {
859  Section* sec = hocSEC(qsec);
860  sec->order = -1;
861  ++section_count;
862  }
863 
864  if (secorder) {
865  free((char*) secorder);
866  secorder = (Section**) 0;
867  }
868  if (section_count) {
869  secorder = (Section**) emalloc(section_count * sizeof(Section*));
870  }
871  order = 0;
872  // ForAllSections(sec) /* all the roots first */
873  ITERATE(qsec, section_list) {
874  Section* sec = hocSEC(qsec);
875  if (!sec->parentsec) {
876  secorder[order] = sec;
877  sec->order = order;
878  ++order;
879  }
880  }
881 
882  for (isec = 0; isec < section_count; isec++) {
883  if (isec >= order) {
884  // Sections form a loop.
885  // ForAllSections(sec)
886  ITERATE(qsec, section_list) {
887  Section* sec = hocSEC(qsec);
888  Section *psec, *s = sec;
889  for (psec = sec->parentsec; psec; s = psec, psec = psec->parentsec) {
890  if (!psec || s->order >= 0) {
891  break;
892  } else if (psec == sec) {
893  fprintf(stderr, "A loop exists consisting of:\n %s", secname(sec));
894  for (s = sec->parentsec; s != sec; s = s->parentsec) {
895  fprintf(stderr, " %s", secname(s));
896  }
897  fprintf(stderr,
898  " %s\nUse <section> disconnect() to break the loop\n ",
899  secname(sec));
900  hoc_execerror("A loop exists involving section", secname(sec));
901  }
902  }
903  }
904  }
905  sec = secorder[isec];
906  for (ch = sec->child; ch; ch = ch->sibling) {
907  secorder[order] = ch;
908  ch->order = order;
909  ++order;
910  }
911  }
913 }
double nrn_section_orientation(Section *sec)
Definition: cabcode.cpp:1644
const char * secname(Section *sec)
Definition: cabcode.cpp:1776
int node_index_exact(Section *sec, double x)
Definition: cabcode.cpp:1497
double section_length(Section *sec)
Definition: cabcode.cpp:387
double nrn_connection_position(Section *sec)
Definition: cabcode.cpp:1639
Section * chk_access(void)
Definition: cabcode.cpp:444
void nrn_disconnect(Section *sec)
Definition: cabcode.cpp:594
Node * node_exact(Section *sec, double x)
Definition: cabcode.cpp:1940
Memb_func * memb_func
Definition: init.cpp:123
static Node * pnd
Definition: clamp.cpp:33
#define spSolve
Definition: cspredef.h:39
#define spFactor
Definition: cspredef.h:13
static double order(void *v)
Definition: cvodeobj.cpp:239
int use_cachevec
Definition: treeset.cpp:63
int nrn_is_ion(int)
Definition: eion.cpp:51
Section * nrn_section_alloc()
Definition: cxprop.cpp:324
void nrn_section_free(Section *s)
Definition: cxprop.cpp:331
sprintf(buf, " if (secondorder) {\n" " int _i;\n" " for (_i = 0; _i < %d; ++_i) {\n" " _p[_slist%d[_i]] += dt*_p[_dlist%d[_i]];\n" " }}\n", numeqn, listnum, listnum)
double chkarg(int, double low, double high)
Definition: code2.cpp:638
void extcell_2d_alloc(Section *sec)
Definition: extcelln.cpp:348
void extnode_free_elements(Extnode *nde)
Definition: extcelln.cpp:214
void nrn_print_matrix(NrnThread *_nt)
Definition: fadvance.cpp:717
static int first
Definition: fmenu.cpp:190
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:754
size_t hoc_total_array_data(Symbol *s, Objectdata *obd)
Definition: hoc_oop.cpp:94
void hoc_pushobj(Object **d)
Definition: code.cpp:663
void notify_freed_val_array(double *p, size_t size)
Definition: ivoc.cpp:101
int hoc_is_double_arg(int narg)
Definition: code.cpp:744
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
#define VOIDITM(q)
Definition: hoclist.h:68
void hoc_l_delete(hoc_Item *)
Object ** hoc_objgetarg(int)
Definition: code.cpp:1587
void
int ifarg(int)
Definition: code.cpp:1581
#define sec
Definition: md1redef.h:13
#define i
Definition: md1redef.h:12
#define prop
Definition: md1redef.h:29
#define DEF_vrest
Definition: membdef.h:13
#define ITERATE(itm, lst)
Definition: model.h:25
#define Printf
Definition: model.h:237
#define Fprintf
Definition: model.h:234
fabs
Definition: extdef.h:3
char * emalloc(unsigned n)
Definition: list.cpp:166
void nrn_thread_error(const char *)
Definition: multicore.cpp:467
NrnThread * nrn_threads
Definition: multicore.cpp:47
#define printf
Definition: mwprefix.h:26
#define fprintf
Definition: mwprefix.h:30
Prop * prop_alloc(Prop **, int, Node *)
Definition: treeset.cpp:694
static Node * node(Object *)
Definition: netcvode.cpp:340
void setup_topology()
void v_setup_vectors()
Definition: treeset.cpp:1631
void nrn_seg_or_x_arg2(int iarg, Section **psec, double *px)
Definition: point.cpp:201
void nrn_relocate_old_points(Section *oldsec, Node *oldnode, Section *sec, Node *node)
Definition: point.cpp:158
void prop_free(Prop **)
Definition: treeset.cpp:730
int const size_t const size_t n
Definition: nrngsl.h:11
size_t q
size_t p
size_t j
hoc_List * section_list
Definition: init.cpp:102
int keep_nseg_parm_
Definition: cabcode.cpp:1549
Section ** secorder
Definition: solve.cpp:77
void distance(void)
Definition: solve.cpp:228
void nrn_clear_mark(void)
Definition: solve.cpp:459
static void triang(NrnThread *)
Definition: solve.cpp:402
static Section * origin_sec
Definition: solve.cpp:226
void(* nrnpy_o2loc2_p_)(Object *, Section **, double *)
Definition: point.cpp:30
void nrn_sec_ref(Section **psec, Section *sec)
Definition: solve.cpp:580
void sec_free(hoc_Item *secitem)
Definition: solve.cpp:521
short nrn_value_mark(Section *sec)
Definition: solve.cpp:470
void(* nrn_multisplit_solve_)()
Definition: solve.cpp:71
static void node_realloc(Section *sec, short nseg)
Definition: solve.cpp:749
Node ** node_construct(int n)
Definition: solve.cpp:603
double node_dist(Section *sec, Node *node)
Definition: solve.cpp:155
Section * sec_alloc(void)
Definition: solve.cpp:476
void nrnhoc_topology(void)
Definition: solve.cpp:287
static void node_free()
void(* nrnpy_o2loc_p_)(Object *, Section **, double *)
Definition: point.cpp:29
static Node * node_interp(Node *nd1, Node *nd2, double frac)
Definition: solve.cpp:739
static Node * node_clone(Node *nd1)
Definition: solve.cpp:688
int section_count
Definition: solve.cpp:76
void nrn_node_destruct1(Node *nd)
Definition: solve.cpp:638
void section_unref(Section *sec)
Definition: solve.cpp:565
int tree_changed
double topol_distance(Section *sec1, Node *node1, Section *sec2, Node *node2, Section **prootsec, Node **prootnode)
Definition: solve.cpp:169
short nrn_increment_mark(Section *sec)
Definition: solve.cpp:467
void section_order(void)
Definition: solve.cpp:846
void node_destruct(Node **pnode, int n)
Definition: solve.cpp:672
void nrn_solve(NrnThread *_nt)
Definition: solve.cpp:339
void node_alloc(Section *sec, short nseg)
Definition: solve.cpp:826
void section_ref(Section *sec)
Definition: solve.cpp:575
static void section_unlink(Section *sec)
Definition: solve.cpp:591
static void dashes(Section *sec, int offset, int first)
Definition: solve.cpp:304
static void bksub(NrnThread *)
Definition: solve.cpp:429
Node * nrn_node_construct1(void)
Definition: solve.cpp:629
Object ** hoc_objpop()
Definition: code.cpp:860
#define e
Definition: passive0.cpp:22
static void pnode(Prop *)
Definition: psection.cpp:45
o
Definition: seclist.cpp:175
#define NODEA(n)
Definition: section.h:124
#define NODEB(n)
Definition: section.h:125
#define VEC_D(i)
Definition: section.h:120
#define VEC_B(i)
Definition: section.h:119
int use_sparse13
Definition: treeset.cpp:71
#define VEC_RHS(i)
Definition: section.h:121
#define VEC_A(i)
Definition: section.h:118
#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 spNO_MEMORY
Definition: spmatrix.h:101
#define spZERO_DIAG
Definition: spmatrix.h:99
#define spSINGULAR
Definition: spmatrix.h:100
#define spOKAY
Definition: spmatrix.h:97
#define NULL
Definition: sptree.h:16
double * v
Definition: section.h:196
int is_point
Definition: membfunc.h:53
Symbol * sym
Definition: membfunc.h:38
Definition: section.h:133
double * _v
Definition: section.h:140
struct Extnode * extnode
Definition: section.h:161
double _v_temp
Definition: section.h:143
double _area
Definition: section.h:141
struct Prop * prop
Definition: section.h:152
Section * child
Definition: section.h:153
double _rinv
Definition: section.h:142
int sec_node_index_
Definition: section.h:177
Represent main neuron object computed by single thread.
Definition: multicore.h:58
int * _v_parent_index
Definition: multicore.h:76
int ncell
Definition: multicore.h:64
char * _sp13mat
Definition: multicore.h:79
int end
Definition: multicore.h:65
Node ** _v_parent
Definition: multicore.h:78
double * _actual_rhs
Definition: multicore.h:70
Node ** _v_node
Definition: multicore.h:77
Definition: hocdec.h:227
Objectdata * dataspace
Definition: hocdec.h:231
HocStruct hoc_Item * secelm_
Definition: hocdec.h:242
union Object::@39 u
Definition: section.h:214
Datum * dparam
Definition: section.h:220
double * param
Definition: section.h:219
Object * ob
Definition: section.h:225
int param_size
Definition: section.h:218
short type
Definition: section.h:216
struct Prop * next
Definition: section.h:215
Definition: section.h:67
int order
Definition: section.h:52
struct Node ** pnode
Definition: section.h:51
struct Node * parentnode
Definition: section.h:50
struct Prop * prop
Definition: section.h:63
struct Section * parentsec
Definition: section.h:42
struct Section * sibling
Definition: section.h:46
short nnode
Definition: section.h:41
Definition: model.h:57
HocStruct Symbol ** ppsym
Definition: hocdec.h:150
struct Symbol::@37::@38 rng
union Symbol::@18 u
unsigned s_varn
Definition: hocdec.h:158
struct hoc_Item * prev
Definition: hoclist.h:51
int i
Definition: hocdec.h:180
double * pval
Definition: hocdec.h:218