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