NEURON
treeset.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 /* /local/src/master/nrn/src/nrnoc/treeset.cpp,v 1.39 1999/07/08 14:25:07 hines Exp */
3 
4 #include <stdio.h>
5 #if HAVE_STDLIB_H
6 #include <stdlib.h>
7 #endif
8 #include <errno.h>
9 #include <math.h>
10 #include <string>
11 #include "section.h"
12 #include "membfunc.h"
13 #include "neuron.h"
14 #include "parse.hpp"
15 #include "nrnmpi.h"
16 #include "multisplit.h"
17 #include "spmatrix.h"
18 #include "nonvintblock.h"
19 #include "nrndae_c.h"
21 
22 extern spREAL *spGetElement(char*, int ,int);
23 
24 #if CVODE
25 extern int cvode_active_;
26 #endif
27 
28 int nrn_shape_changed_; /* for notifying Shape class in nrniv */
30 
31 extern int diam_changed;
32 extern int tree_changed;
33 extern double chkarg(int, double low, double high);
34 extern double nrn_ra(Section*);
35 #if !defined(NRNMPI) || NRNMPI == 0
36 extern double nrnmpi_wtime();
37 #endif
39 extern int* nrn_prop_dparam_size_;
40 extern int* nrn_dparam_ptr_start_;
41 extern int* nrn_dparam_ptr_end_;
42 extern void nrn_define_shape();
43 extern void nrn_partrans_update_ptrs();
44 
45 #if 1 || PARANEURON
47 #endif
48 
49 #if CACHEVEC
50 
51 
52 
53 /* a, b, d and rhs are, from now on, all stored in extra arrays, to improve
54  * cache efficiency in nrn_lhs() and nrn_rhs(). Formerly, three levels of
55  * indirection were necessary for accessing these elements, leading to lots
56  * of L2 misses. 2006-07-05/Hubert Eichner */
57 /* these are now thread instance arrays */
58 static void nrn_recalc_node_ptrs();
59 #define UPDATE_VEC_AREA(nd) if (nd->_nt && nd->_nt->_actual_area) { nd->_nt->_actual_area[(nd)->v_node_index] = NODEAREA(nd);}
60 #endif /* CACHEVEC */
62 
63 /*
64 Do not use unless necessary (loops in tree structure) since overhead
65 (for gaussian elimination) is
66 about a factor of 3 in space and 2 in time even for a tree.
67 */
69 int use_sparse13 = 0;
71 
72 #if VECTORIZE
73 /*
74 When properties are allocated to nodes or freed, v_structure_change is
75 set to 1. This means that the mechanism vectors need to be re-determined.
76 */
77 extern "C" {
81 } // extern "C"
83 
84 #endif
85 extern int section_count;
86 extern Section** secorder;
87 #if 1 /* if 0 then handled directly to save space : see finitialize*/
88 extern short* nrn_is_artificial_;
90 #endif
91 
92 /*
93 (2002-04-06)
94 One reason for going into the following in depth is to allow
95 comparison of the fixed step implicit method
96 with the implementation of the corresponding
97 cvode (vext not allowed) and daspk (vext allowed) versions.
98 
99 In the fixed step method the result of a setup is a linear matrix
100 equation of the form
101  G*(vinew,vxnew) = i(vm,vx)
102 which is solved and followed by an update step
103  vx=vxnew
104  vm = vinew - vxnew
105 
106 When cvode was added, as much as possible of the existing setup was re-used
107 through the addition of flags. Cvode solves a system of the form
108  dy/dt = f(y)
109 and this is not obtainable in the presence of extracellular or LinearMechanism
110 instances. And even in the cases it can handle, it
111 required a good deal of manipulation to remove the zero area compartments
112 from the state vector and compute the algebraic equations separately.
113 In fact, as of 2002-04-06, the CONSERVE statement for kinetic schemes
114 in model descriptions is still ignored.
115 At any rate, the issues involved are
116 1) How to compute f(y). Any algebraic equations are solved inside f(y)
117 so that the algebraic states are consistent with y.
118 2) How to setup the jacobian (I - gamma*df/dy)*y = b
119 
120 When daspk was added which solves the form
121  0 = f(y, y')
122 having one implementation serving the setup for
123 three very distinct methods became too cumbersome. Therefore setup_tree_matrix
124 was copied twice and modified separately so that each method
125 had its own setup code derived from this file.
126 
127 The issues that have
128 arisen with daspk are
129 1) How to actually implement a residual function res = f(y, y')
130 2) How to actually implement a preconditioner setup of the form
131  (df/dy + cj*df/dy')*y = b
132 3) how to initialize so that 0 = f(y(0), y'(0))
133 when it is not possible to know which are the algebraic and which
134 are the differential equations. Also, it is often the case that
135 a linear combination
136 of apparently differential equations yields an algebraic equation and we
137 don't know the linearly dependent subsets.
138 DASPK itself will only handle initialization if one can mark some states
139 as differential and the remaining states as algebraic.
140 
141 With that, here's what is going on in this file with respect to setup of
142  G*(vinew, vxnew) = i(vm,vx)
143 
144 The current balance equations are sum of outward currents = sum of inward currents
145 For an internal node
146  cm*dvm/dt + i(vm) = is(vi) + ai_j*(vi_j - vi)
147 For an external node (one layer)
148  cx*dvx/dt + gx*(vx - ex) = cm*dvm/dt + i(vm) + ax_j*(vx_j - vx)
149 where vm = vi - vx
150 and every term has the dimensions mA/cm2
151 (the last terms in each equation represent the second derivative cable properties)
152 The chosen convention that determines the side of the terms and their sign
153 is that
154 positive membrane current is outward but electrode stimulus
155 currents are toward the node. We place the terms involving
156 currents leaving a node on the left, and currents entering a node
157 on the right. i.e.
158  |is
159  ia `.'
160  ---> <---
161  |im
162  ie `.'
163  ---> <---
164  |gx*vx
165  `.'
166  ---
167  \ /
168  -
169 
170 At the hoc level, v refers to vm and vext refers to vx.
171 It should also be realized that LinearMechanism instances overlay equations of
172 the form
173 c*dy/dt + g*y = b
174 onto the current balance equation set thus adding new states,
175 equations, and terms to the above equations. However,
176 note that when y refers to a voltage of a segment in those equations
177 it always means vi or vx and never vm.
178 
179 At this point it is up to us whether we setup and solve the form
180 G*(vm,vx) = i or G*(vi,vx) = i
181 since any particular choice is resolved back to (vm,vx) in the update step.
182 At present, particularly for the implicit fixed step method whose setup
183 implementation resides in this file, we've chosen G*(vi,vx) = i,
184 because there are fewer operations in setting up second derivatives and it
185 makes life easy for the LinearMechanism. i.e. on setup each element of the
186 linear mechanism gets added to only one element of the complete matrix equations
187 and on update we merely copy the
188 vi solution to the proper LinearMechanism states and update v=vi-vext
189 for the compartment membrane potentials.
190 
191 The implicit linear form for the compartment internal node is
192 cm/dt*(vmnew - vmold) + (di/dvm*(vmnew - vmold) + i(vmold))
193  = (dis/dvi*(vinew - viold) + is(viold)) + ai_j*(vinew_j - vinew)
194 and for the compartment external node is
195 cx/dt*(vxnew - vxold) - gx(vxnew - ex)
196  = cm/dt*(vmnew - vmold) + (di/dvm*(vmnew - vmold) + i(vmold))
197  + ax_j*(vxnew_j - vxnew) = 0
198 
199 and this forms the matrix equation row (for an internal node)
200  (cm/dt + di/dvm - dis/dvi + ai_j)*vinew
201  - ai_j*vinew_j
202  -(cm/dt + di/dvm)*vxnew
203  =
204  cm/dt*vmold + di/dvm*vmold - i(vmold) - dis/dvi*viold + is(viold)
205 
206 where old is present value of vm, vi, or vx and new will be found by solving
207 this matrix equation (which is of the form G*v = rhs)
208 The matrix equation row for the extracellular node is
209  (cx/dt + gx + ax_j + cm/dt + di/dvm)*vext
210  -ax_j*vxnew_j
211  -(cm/dt + di/dvm)*vinew
212  = cx/dt*vxold - (cm/dt*vmold + di/dv*vmold - i(vmold)) - gx*ex
213 
214 Node.v is always interpreted as membrane potential and it is important to
215 distinguish this from internal potential (Node.v + Node.extnode.v)
216 when the extracellular mechanism is present.
217 
218 In dealing with these current balance equations, all three methods
219 use the same mechanism calls to calculate di/dvm, i(vm), dis/dvi, is(vi)
220 and add them to the matrix equation.
221 Thus the passive channel, i=g*(v - e), is a transmembrane current
222 (convention is positive outward) and the mechanism adds g to the
223 diagonal element of the matrix and subtracts i - g*v from the right hand side.
224 (see nrn_cur of passive.cpp) It does NOT add anything to the extracellular
225 current balance row.
226 
227 An electrode current (convention positive current increases the internal potential)
228 such as a voltage clamp with small resistance, is=g*(vc - (v+vext))
229 (see nrn_cur of svclmp.cpp)
230 subtracts -g from the matrix diagonal (since dis/dvi = -g)
231 and adds i - g*(v+vext) to the
232 right hand side. In the presence of an extracellular mechanism, such electrode
233 mechanisms add the dis/dvi term to the extracellular equation diagonal and also add
234 is - dis/dvi*(viold) to the extracellular equation right hand side.
235 
236 This is where a trick comes in. Note that in the equations it is the
237 membrane currents that appear in both rows whereas the stimulus appears
238 in the internal row only. But the membrane mechanisms add membrane currents
239 only to the internal row and stimuli to both rows. Perhaps the additional
240 confusion was not worth the mechanism efficiency gain ( since there are many
241 more membrane (and synaptic) currents than stimulus currents) but at any rate
242 the matrix filling is ordered so that membrane mechanisms are done before
243 the axial currents. This means that only membrane and stimulus currents are present
244 on the internal diagonal and right hand side. However, only stimulus current
245 is present on the external diagonal and right hand side. The difference
246 of course is the membrane current elements by themselves and the extracellular
247 code fills the elements appropriately.
248 So, in the code below, the order for doing the extracellular setup is very
249 important with respect to filling the matrix and mechanisms must be first,
250 then the obsolete activsynapse, then the extracellular setup, then
251 linear models and the obsolete activstim and activclamp. I.e it is crucial
252 to realize that before extracellular has been called that the internal
253 current balance matrix rows are with respect to vm whereas (except for special
254 handling of stimulus terms by keeping separate track of those currents)
255 and after extracellular has been called the current balance matrix rows are
256 with respect to vi and vext.
257 Finally at the end it is possible to add the internal axial terms.
258 */
259 
260 /*
261 2002-04-06
262 General comments toward a reorganization of the implementation to
263 promote code sharing of the fixed, cvode, and daspk methods and with
264 regard to the efficiency of cvode and daspk.
265 
266 The existing fixed step setup stategy is almost identical to that needed
267 by the current balance portion jacobian solvers for cvode and daspk.
268 However it is wasteful to calculate the right hand side since that is
269 thrown away because those solvers demand a calculation of M*x=b where b
270 is provided and the answer ends up in b. Also, for the function evaluation
271 portion of those solvers, the reuse of the setup is wastful because
272 after setting up the matrix, we essentially calculate rhs - M*x
273 and then throw away M.
274 
275 So, without reducing the efficiency of the fixed step it would be best
276 to re-implement the setup functions to separate the calculation of M
277 from that of b. Those pieces could then be used by all three methods as
278 needed. Also at this level of strategy we can properly take into
279 account cvode's and daspk's requirement of separating the dy/dt terms
280 from the y dependent terms. Note that the problem we are dealing with
281 is entirely confined to the current balance equations and little or
282 no change is required for the mechanism ode's.
283 
284 One other detail must be considered.
285 The computation that memb_func[i].current presently
286 performs can be split into two parts only if the jacabian calculation is done
287 first. This is because the first BREAKPOINT evaluation is for
288 v+.001 and the second is for v. We can't turn that around. The best that
289 can be done (apart from analytic calculation of g) is to make use
290 of the simultaneous calculation of g for the fixed step, store it for
291 use when the jacobian is evalulated and eventually
292 have faster version of current only for use by cvode and daspk.
293 
294 A further remark. LinearMechanisms allow much greater generality in
295 the structure of the current balance equations, especially with regard
296 to extracellular coupling and nonlinear gap junctions. In both these
297 cases, the extracellular equivalent circuit apparatus is entirely
298 superfluous and only the idea of a floating extracellular node is
299 needed. Perhaps this, as well as the elimination of axial resistors
300 for single segment sections will be forthcoming. Therefore it
301 is also useful to keep a clear separation between the computation of
302 membrane currents intra- and extracellular contribution
303 and the calculation of intracellular axial and extracellular currents.
304 
305 
306 The most reusable fixed step strategy I can think of is to compute
307 M*(dvi,dvx) = i on the basis of
308 cm*dvm/dt = -i(vm) + is(vi) + ai_j*(vi_j - vi)
309 cx*dvx/dt - cm*dvm/dt = -gx*(vx - ex) + i(vm) + ax_j*(vx_j - vx)
310 It has advantage of not adding capacitance terms to the
311 right hand side but requires the calculation of axial currents
312 for addition to the right hand side, which would have to be done anyway
313 for cvode and daspk. The choice is re-usability. Note that the dvm/dt term
314 in the external equation is why cvode can't work with the extracellular
315 mechanism. Also the axial coupling terms are linear so both the matrix
316 and righthand side are easy to setup separately without much loss of
317 efficiency.
318 
319 1)Put -i(vm)+is(vi) into right hand side for internal node and,
320 if an extracellular node exists, store is(vi) as well so that we
321 can later carry out the trick of putting i(vm) into the external right
322 hand side. This is common also for cvode and daspk.
323 2)For extracellular nodes perform the trick and deal with gx*ex and
324 add the extracellular axial terms to the right hand side.
325 Common to daspk and cvode.
326 3) Add the internal axial terms to the right hand side. Common to
327 daspk and cvode
328 The above accomplishes a function evaluation for cvode. For daspk it would
329 remain only to use y' to calculate the residual from the derivative terms.
330 
331 4)Start setting up the matrix by calculating di/dvm from the mechanisms
332 and put it directly into the rhs. For stimulus currents, store dis/dvi
333 for later use of the trick. Common also for cvode and daspk
334 5) For extracellular nodes perform the trick and deal with gx and extracellular
335 axial terms to the matrix. Common to cvode and daspk
336 6) Add the internal axial terms to the matrix.Commond to cvode and daspk.
337 
338 At this point the detailed handling of capacitance may be different for the
339 three methods. For the fixed step, what is required is
340 7) add cm/dt to the internal diagonal
341 8) for external nodes fill in the cv/dt and cx/dt contributions.
342 This completes the setup of the matrix equations.
343 We then solve for dvi and dvx and update using (for implicit method)
344 vx += dvx
345 vm += dvi-dvx
346 
347 */
348 
349 /* calculate right hand side of
350 cm*dvm/dt = -i(vm) + is(vi) + ai_j*(vi_j - vi)
351 cx*dvx/dt - cm*dvm/dt = -gx*(vx - ex) + i(vm) + ax_j*(vx_j - vx)
352 This is a common operation for fixed step, cvode, and daspk methods
353 */
354 
355 void nrn_rhs(NrnThread* _nt) {
356  int i, i1, i2, i3;
357  double w;
358  int measure = 0;
359  NrnThreadMembList* tml;
360 
361  i1 = 0;
362  i2 = i1 + _nt->ncell;
363  i3 = _nt->end;
364  if (_nt->id == 0 && nrn_mech_wtime_) { measure = 1; }
365 
366  if (diam_changed) {
367  nrn_thread_error("need recalc_diam()");
368  recalc_diam();
369  }
370  if (use_sparse13) {
371  int i, neqn;
372  nrn_thread_error("nrn_rhs use_sparse13");
373  neqn = spGetSize(_nt->_sp13mat, 0);
374  for (i=1; i <= neqn; ++i) {
375  _nt->_actual_rhs[i] = 0.;
376  }
377  }else{
378 #if CACHEVEC
379  if (use_cachevec) {
380  for (i = i1; i < i3; ++i) {
381  VEC_RHS(i) = 0.;
382  }
383  }else
384 #endif /* CACHEVEC */
385  {
386  for (i = i1; i < i3; ++i) {
387  NODERHS(_nt->_v_node[i]) = 0.;
388  }
389  }
390  }
391  if (_nt->_nrn_fast_imem) {
392  for (i = i1; i < i3; ++i) {
393  _nt->_nrn_fast_imem->_nrn_sav_rhs[i] = 0.;
394  }
395  }
396 
398  /* note that CAP has no current */
399  for (tml = _nt->tml; tml; tml = tml->next) if (memb_func[tml->index].current) {
400  Pvmi s = memb_func[tml->index].current;
401  std::string mechname("cur-");
402  mechname += memb_func[tml->index].sym->name;
403  if (measure) {
404  w = nrnmpi_wtime();
405  }
406  nrn::Instrumentor::phase_begin(mechname.c_str());
407  (*s)(_nt, tml->ml, tml->index);
408  nrn::Instrumentor::phase_end(mechname.c_str());
409  if (measure) { nrn_mech_wtime_[tml->index] += nrnmpi_wtime() - w; }
410  if (errno) {
411  if (nrn_errno_check(tml->index)) {
412 hoc_warning("errno set during calculation of currents", (char*)0);
413  }
414  }
415  }
417 
418  if (_nt->_nrn_fast_imem) {
419  /* _nrn_save_rhs has only the contribution of electrode current
420  so here we transform so it only has membrane current contribution
421  */
422  double* p = _nt->_nrn_fast_imem->_nrn_sav_rhs;
423  if (use_cachevec) {
424  for (i = i1; i < i3; ++i) {
425  p[i] -= VEC_RHS(i);
426  }
427  }else{
428  for (i = i1; i < i3; ++i) {
429  Node* nd = _nt->_v_node[i];
430  p[i] -= NODERHS(nd);
431  }
432  }
433  }
434 #if EXTRACELLULAR
435  /* Cannot have any axial terms yet so that i(vm) can be calculated from
436  i(vm)+is(vi) and is(vi) which are stored in rhs vector. */
437  nrn_rhs_ext(_nt);
438  /* nrn_rhs_ext has also computed the the internal axial current
439  for those nodes containing the extracellular mechanism
440  */
441 #endif
442  if (use_sparse13) {
443  /* must be after nrn_rhs_ext so that whatever is put in
444  nd->_rhs does not get added to nde->rhs */
445  nrndae_rhs();
446  }
447 
448  activstim_rhs();
449  activclamp_rhs();
450  /* now the internal axial currents.
451  The extracellular mechanism contribution is already done.
452  rhs += ai_j*(vi_j - vi)
453  */
454 #if CACHEVEC
455  if (use_cachevec) {
456  for (i = i2; i < i3; ++i) {
457  double dv = VEC_V(_nt->_v_parent_index[i]) - VEC_V(i);
458  /* our connection coefficients are negative so */
459  VEC_RHS(i) -= VEC_B(i)*dv;
460  VEC_RHS(_nt->_v_parent_index[i]) += VEC_A(i)*dv;
461  }
462  }else
463 #endif /* CACHEVEC */
464  {
465  for (i = i2; i < i3; ++i) {
466  Node* nd = _nt->_v_node[i];
467  Node* pnd = _nt->_v_parent[i];
468  double dv = NODEV(pnd) - NODEV(nd);
469  /* our connection coefficients are negative so */
470  NODERHS(nd) -= NODEB(nd)*dv;
471  NODERHS(pnd) += NODEA(nd)*dv;
472  }
473  }
474 }
475 
476 /* calculate left hand side of
477 cm*dvm/dt = -i(vm) + is(vi) + ai_j*(vi_j - vi)
478 cx*dvx/dt - cm*dvm/dt = -gx*(vx - ex) + i(vm) + ax_j*(vx_j - vx)
479 with a matrix so that the solution is of the form [dvm+dvx,dvx] on the right
480 hand side after solving.
481 This is a common operation for fixed step, cvode, and daspk methods
482 */
483 
484 void nrn_lhs(NrnThread* _nt) {
485  int i, i1, i2, i3;
486  NrnThreadMembList* tml;
487 
488  i1 = 0;
489  i2 = i1 + _nt->ncell;
490  i3 = _nt->end;
491 
492  if (diam_changed) {
493  nrn_thread_error("need recalc_diam()");
494  }
495 
496  if (use_sparse13) {
497  int i, neqn;
498  neqn = spGetSize(_nt->_sp13mat, 0);
499  spClear(_nt->_sp13mat);
500  }else{
501 #if CACHEVEC
502  if (use_cachevec) {
503  for (i = i1; i < i3; ++i) {
504  VEC_D(i) = 0.;
505  }
506  }else
507 #endif /* CACHEVEC */
508  {
509  for (i = i1; i < i3; ++i) {
510  NODED(_nt->_v_node[i]) = 0.;
511  }
512  }
513  }
514 
515  if (_nt->_nrn_fast_imem) {
516  for (i = i1; i < i3; ++i) {
517  _nt->_nrn_fast_imem->_nrn_sav_d[i] = 0.;
518  }
519  }
520 
521  /* note that CAP has no jacob */
522  for (tml = _nt->tml; tml; tml = tml->next) if (memb_func[tml->index].jacob) {
523  Pvmi s = memb_func[tml->index].jacob;
524  std::string mechname("cur-");
525  mechname += memb_func[tml->index].sym->name;
526  nrn::Instrumentor::phase_begin(mechname.c_str());
527  (*s)(_nt, tml->ml, tml->index);
528  nrn::Instrumentor::phase_end(mechname.c_str());
529  if (errno) {
530  if (nrn_errno_check(tml->index)) {
531 hoc_warning("errno set during calculation of jacobian", (char*)0);
532  }
533  }
534  }
535 /* now the cap current can be computed because any change to cm by another model
536 has taken effect
537 */
538  /* note, the first is CAP */
539  if (_nt->tml) {
540  assert(_nt->tml->index == CAP);
541  nrn_cap_jacob(_nt, _nt->tml->ml);
542  }
543 
545 
546 
547  if (_nt->_nrn_fast_imem) {
548  /* _nrn_save_d has only the contribution of electrode current
549  so here we transform so it only has membrane current contribution
550  */
551  double* p = _nt->_nrn_fast_imem->_nrn_sav_d;
552  if (use_sparse13) {
553  for (i = i1; i < i3; ++i) {
554  Node* nd = _nt->_v_node[i];
555  p[i] += NODED(nd);
556  }
557  }else if (use_cachevec) {
558  for (i = i1; i < i3; ++i) {
559  p[i] += VEC_D(i);
560  }
561  }else{
562  for (i = i1; i < i3; ++i) {
563  Node* nd = _nt->_v_node[i];
564  p[i] += NODED(nd);
565  }
566  }
567  }
568 #if EXTRACELLULAR
569  /* nde->_d[0] contains the -ELECTRODE_CURRENT contribution to nd->_d */
570  nrn_setup_ext(_nt);
571 #endif
572  if (use_sparse13) {
573  /* must be after nrn_setup_ext so that whatever is put in
574  nd->_d does not get added to nde->d */
575  nrndae_lhs();
576  }
577 
578  activclamp_lhs();
579 
580  /* at this point d contains all the membrane conductances */
581 
582 
583  /* now add the axial currents */
584 
585  if (use_sparse13) {
586  for (i = i2; i < i3; ++i) {
587  Node* nd = _nt->_v_node[i];
588  *(nd->_a_matelm) += NODEA(nd);
589  *(nd->_b_matelm) += NODEB(nd); /* b may have value from lincir */
590  NODED(nd) -= NODEB(nd);
591  }
592  for (i=i2; i < i3; ++i) {
593  NODED(_nt->_v_parent[i]) -= NODEA(_nt->_v_node[i]);
594  }
595  } else {
596 #if CACHEVEC
597  if (use_cachevec) {
598  for (i=i2; i < i3; ++i) {
599  VEC_D(i) -= VEC_B(i);
600  VEC_D(_nt->_v_parent_index[i]) -= VEC_A(i);
601  }
602  }else
603 #endif /* CACHEVEC */
604  {
605  for (i=i2; i < i3; ++i) {
606  NODED(_nt->_v_node[i]) -= NODEB(_nt->_v_node[i]);
607  NODED(_nt->_v_parent[i]) -= NODEA(_nt->_v_node[i]);
608  }
609  }
610  }
611 }
612 
613 /* for the fixed step method */
615  nrn::Instrumentor::phase p_setup_tree_matrix("setup-tree-matrix");
616  nrn_rhs(_nt);
617  nrn_lhs(_nt);
618  nrn_nonvint_block_current(_nt->end, _nt->_actual_rhs, _nt->id);
619  nrn_nonvint_block_conductance(_nt->end, _nt->_actual_d, _nt->id);
620  return nullptr;
621 }
622 
623 /* membrane mechanisms needed by other mechanisms (such as Eion by HH)
624 may require that the needed mechanism appear before it in the list.
625 (because ina must be initialized before it is incremented by HH)
626 With current implementation, a chain of "needs" may not be in list order.
627 */
628 static Prop **current_prop_list; /* the one prop_alloc is working on
629  when need_memb is called */
630 static int disallow_needmemb = 0; /* point processes cannot use need_memb
631  when inserted at locations 0 or 1 */
632 
634 
635 extern Prop *prop_alloc(Prop **, int, Node *);
636 
637 
638 extern "C" Prop* need_memb(Symbol* sym)
639 {
640  int type;
641  Prop *mprev, *m;
642  if (disallow_needmemb) {
643  fprintf(stderr, "You can not locate a point process at\n\
644  position 0 or 1 if it needs an ion\n");
645  hoc_execerror(sym->name, "can't be inserted in this node");
646  }
647  type = sym->subtype;
648  mprev = (Prop *)0; /* may need to relink m */
649  for (m = *current_prop_list; m; mprev = m, m = m->next) {
650  if (m->type == type) {
651  break;
652  }
653  }
654  if (m) {
655  /* a chain of "needs" will not be in list order
656  so it is important that order only important for Eion */
657  if (mprev) {
658  mprev->next = m->next;
659  m->next = *current_prop_list;
660  }
661  *current_prop_list = m;
662  } else if (nrn_pnt_sec_for_need_) {
663  /* The caller was a POINT_PROCESS and we need to make sure
664  that all segments of this section have the ion in order to
665  prevent the possibility of multiple instances of this ion
666  if a density mechanism that needs it is subsequently inserted
667  or if the ion mechanism itself is inserted. Any earlier
668  insertions of the latter or locating this kind of POINT_PROCESS
669  in this section will mean that we no longer get to this arm
670  of the if statement because m above is not nil.
671  */
673  Prop** cpl = current_prop_list;
674  nrn_pnt_sec_for_need_ = (Section*)0;
675  mech_insert1(sec, type);
676  current_prop_list = cpl;
677  m = need_memb(sym);
678  }else{
679  m = prop_alloc(current_prop_list, type, (Node*)0);
680  }
681  return m;
682 }
683 
684 
685 
686 Node* nrn_alloc_node_; /* needed by models that use area */
687 
688 Prop *prop_alloc(Prop **pp, int type, Node *nd) {
689 /* link in new property at head of list */
690 /* returning *Prop because allocation may */
691 /* cause other properties to be linked ahead */
692 /* some models need the node (to find area) */
693  Prop *p;
694 
695  if (nd) {
696  nrn_alloc_node_ = nd;
697  }
698 #if VECTORIZE
699  v_structure_change = 1;
700 #endif
701  current_prop_list = pp;
702  p = (Prop *) emalloc(sizeof(Prop));
703  p->type = type;
704  p->next = *pp;
705  p->ob = nullptr;
706  p->_alloc_seq = -1;
707  *pp = p;
708  assert(memb_func[type].alloc);
709  p->dparam = (Datum *) 0;
710  p->param = (double *) 0;
711  p->param_size = 0;
712  (memb_func[type].alloc)(p);
713  return p;
714 }
715 
717  Prop *p;
718  disallow_needmemb = 1;
719  p = prop_alloc(pp, type, nd);
720  disallow_needmemb = 0;
721  return p;
722 }
723 
724 void prop_free(Prop **pp) /* free an entire property list */
725 {
726  Prop *p, *pn;
727  p = *pp;
728  *pp = (Prop *) 0;
729  while (p) {
730  pn = p->next;
731  single_prop_free(p);
732  p = pn;
733  }
734 }
735 
737  extern char *pnt_map;
738 #if VECTORIZE
739  v_structure_change = 1;
740 #endif
741  if (pnt_map[p->type]) {
743  return;
744  }
745  if (p->param) {
747  nrn_prop_data_free(p->type, p->param);
748  }
749  if (p->dparam) {
750  if (p->type == CABLESECTION) {
751  notify_freed_val_array(&p->dparam[2].val, 6);
752  }
754  }
755  if (p->ob) {
756  hoc_obj_unref(p->ob);
757  }
758  free((char *) p);
759 }
760 
761 
762 /* For now there is always one more node in a section than there are
763 segments */
764 /* except in section 0 in which all nodes serve as x=0 to connecting
765 sections */
766 
767 #undef PI
768 #define PI 3.14159265358979323846
769 
770 static double diam_from_list(Section* sec, int inode, Prop* p, double rparent);
771 
774  int j;
775  double ra, dx, diam, rright, rleft;
776  Prop* p;
777  Node* nd;
779 #if DIAMLIST
780  if (sec->npt3d) {
781  sec->prop->dparam[2].val = sec->pt3d[sec->npt3d - 1].arc;
782  }
783 #endif
784  ra = nrn_ra(sec);
785  dx = section_length(sec)/((double)(sec->nnode - 1));
786  rright = 0.;
787  for (j = 0; j < sec->nnode-1; j++) {
788  nd = sec->pnode[j];
789  for (p = nd->prop; p; p = p->next) {
790  if (p->type == MORPHOLOGY) {
791  break;
792  }
793  }
794  assert(p);
795 #if DIAMLIST
796  if (sec->npt3d > 1) {
797  /* trapezoidal integration of diam, area, and resistance useing pt3d
798  the integration is over the span of the segment j.
799  and NODEAREA and NODERINV are filled in. The right half of the segment
800  resistance (MOhm) is returned.
801  */
802  rright = diam_from_list(sec, j, p, rright);
803  }else
804 #endif
805  {
806  /* area for right circular cylinders. Ri as right half of parent + left half
807  of this
808  */
809  diam = p->param[0];
810  if (diam <= 0.) {
811  p->param[0] = 1e-6;
812 hoc_execerror(secname(sec), "diameter diam = 0. Setting to 1e-6");
813  }
814  NODEAREA(nd) = PI*diam*dx; /* um^2 */
815  UPDATE_VEC_AREA(nd);
816  rleft = 1e-2*ra*(dx/2)/(PI*diam*diam/4.); /*left half segment Megohms*/
817  NODERINV(nd) = 1./(rleft + rright); /*uS*/
818  rright = rleft;
819  }
820  }
821  /* last segment has 0 length. area is 1e2
822  in dimensionless units */
823  NODEAREA(sec->pnode[j]) = 1.e2;
824  UPDATE_VEC_AREA(sec->pnode[j]);
825  NODERINV(sec->pnode[j]) = 1./rright;
826  sec->recalc_area_ = 0;
827  diam_changed = 1;
828 }
829 
831  return nd->_classical_parent;
832 }
833 
834 void connection_coef(void) /* setup a and b */
835 {
836  int j;
837  double dx, diam, area, ra;
838  hoc_Item* qsec;
839  Node *nd;
840  Prop *p;
841 #if RA_WARNING
842  extern int nrn_ra_set;
843 #endif
844 
845 #if 1
846  /* now only called from recalc_diam */
848 #else
849  if (tree_changed) {
850  setup_topology();
851  }
852 #endif
853 
854 #if RA_WARNING
855  if (nrn_ra_set > 0 && nrn_ra_set < section_count - 1) {
856  hoc_warning("Don't forget to set Ra in every section",
857  "eg. forall Ra=35.4");
858  }
859 #endif
863  nrn_area_ri(sec);
864  }
866  /* assume that if only one connection at x=1, then they butte
867  together, if several connections at x=1
868  then last point is at x=1, has 0 area and other points are at
869  centers of nnode-1 segments.
870  If interior connection then child half
871  section connects straight to the point*/
872  /* for the near future we always have a last node at x=1 with
873  no properties */
875 #if 1 /* unnecessary because they are unused, but help when looking at fmatrix */
876  if (!sec->parentsec) {
877  if (nrn_classicalNodeA(sec->parentnode)) {
878  ClassicalNODEA(sec->parentnode) = 0.0;
879  }
880  if (nrn_classicalNodeB(sec->parentnode)) {
881  ClassicalNODEB(sec->parentnode) = 0.0;
882  }
883  }
884 #endif
885  /* convert to siemens/cm^2 for all nodes except last
886  and microsiemens for last. This means that a*V = mamps/cm2
887  and a*v in last node = nanoamps. Note that last node
888  has no membrane properties and no area. It may perhaps receive
889  current stimulus later */
890  /* first the effect of node on parent equation. Note That
891  last nodes have area = 1.e2 in dimensionless units so that
892  last nodes have units of microsiemens */
893  nd = sec->pnode[0];
894  area = NODEAREA(sec->parentnode);
895  /* dparam[4] is rall_branch */
896  ClassicalNODEA(nd) = -1.e2*sec->prop->dparam[4].val * NODERINV(nd) / area;
897  for (j = 1; j < sec->nnode; j++) {
898  nd = sec->pnode[j];
899  area = NODEAREA(sec->pnode[j - 1]);
900  ClassicalNODEA(nd) = -1.e2 * NODERINV(nd) / area;
901  }
902  }
903  /* now the effect of parent on node equation. */
905  for (j=0; j < sec->nnode; j++) {
906  nd = sec->pnode[j];
907  ClassicalNODEB(nd) = -1.e2 * NODERINV(nd) / NODEAREA(nd);
908  }
909  }
910 #if EXTRACELLULAR
911  ext_con_coef();
912 #endif
913 }
914 
915 extern "C" void nrn_shape_update_always(void) {
916  static int updating;
917  if (!updating || updating != diam_change_cnt) {
918  updating = diam_change_cnt;
919  if (tree_changed) {
920  setup_topology();
921  }
922  if (v_structure_change) {
923  v_setup_vectors();
924  }
925  if (diam_changed) {
926  recalc_diam();
927  }
928  updating = 0;
929  }
930 }
931 
932 extern "C" void nrn_shape_update(void) {
933  if (section_list->next != section_list) {
935  }
936 }
937 
938 static void nrn_matrix_node_alloc(void);
939 
940 void recalc_diam(void) {
941  v_setup_vectors();
943  connection_coef();
944  diam_changed = 0;
945  ++diam_change_cnt;
946  stim_prepare();
947  synapse_prepare();
948  clamp_prepare();
949 }
950 
951 
952 void area(void) { /* returns area (um^2) of segment containing x */
953  double x;
954  Section *sec;
955  x = *getarg(1);
956  if (x == 0. || x == 1.) {
957  hoc_retpushx(0.);
958  }else{
959  sec = chk_access();
960  if (sec->recalc_area_) {
961  nrn_area_ri(sec);
962  }
963  hoc_retpushx(NODEAREA(sec->pnode[node_index(sec, x)]));
964  }
965 }
966 
967 
968 void ri(void) { /* returns resistance (Mohm) between center of segment containing x
969  and the center of the parent segment */
970  double area;
971  Node *np;
972  np = node_ptr(chk_access(), *getarg(1), &area);
973  if (NODERINV(np)) {
974  hoc_retpushx(1./NODERINV(np)); /* Megohms */
975  }else{
976  hoc_retpushx(1.e30);
977  }
978 }
979 
980 
981 #if DIAMLIST
982 
983 static int pt3dconst_;
984 
985 void pt3dconst(void) {
986  int i = pt3dconst_;
987  if (ifarg(1)) {
988  pt3dconst_ = (int)chkarg(1, 0., 1.);
989  }
990  hoc_retpushx((double)i);
991 }
992 
994  if (sec->logical_connection) {
995  free(sec->logical_connection);
996  sec->logical_connection = (Pt3d*)0;
998  diam_changed = 1;
999  }
1000 }
1001 
1002 void nrn_pt3dstyle1(Section* sec, double x, double y, double z) {
1003  Pt3d* p = sec->logical_connection;
1004  if (!p) {
1005  p = sec->logical_connection = (Pt3d*)ecalloc(1, sizeof(Pt3d));
1006  }
1007  p->x = x;
1008  p->y = y;
1009  p->z = z;
1011  diam_changed = 1;
1012 }
1013 
1014 void pt3dstyle(void) {
1015  Section* sec = chk_access();
1016  if (ifarg(1)) {
1017  /* Classical, Logical connection */
1018  /*
1019  Logical connection is used to turn off snapping to the
1020  centroid of the parent which sometimes ruins
1021  the 3-d shape rendering due to branches connected to a
1022  large diameter soma getting translated to the middle of
1023  the soma. Of course, the question then arises of what
1024  to do when the soma is moved to a new location or
1025  an ancestor branch length is changed (i.e. exactly what
1026  snapping to the parent deals with automatically)
1027  Our answer is that a pt3dstyle==1 branch gets translated
1028  exactly by the amount of the parent translation
1029  instead of snapping to a specific absolute x,y,z position.
1030  */
1031  if ((int)chkarg(1, 0., 1.) == 1) {
1032  if (hoc_is_pdouble_arg(2)) {
1033  Pt3d* p = sec->logical_connection;
1034  if (p) {
1035  double* px;
1036  px = hoc_pgetarg(2); *px = p->x;
1037  px = hoc_pgetarg(3); *px = p->y;
1038  px = hoc_pgetarg(4); *px = p->z;
1039  }
1040  }else{
1041  nrn_pt3dstyle1(sec, *getarg(2), *getarg(3), *getarg(4));
1042  }
1043  }else{
1044  nrn_pt3dstyle0(sec);
1045  }
1046  }
1047  hoc_retpushx((double)(sec->logical_connection ? 1 : 0));
1048 }
1049 
1050 void pt3dclear(void) { /*destroys space in current section for 3d points.*/
1051  Section* sec = chk_access();
1052  int req;
1053  if (ifarg(1)) {
1054  req = chkarg(1, 0., 30000.);
1055  } else {
1056  req = 0;
1057  }
1058  nrn_pt3dclear(sec, req);
1059  hoc_retpushx((double)sec->pt3d_bsize);
1060 }
1061 
1062 static void nrn_pt3dbufchk(Section* sec, int n) {
1063  if (n > sec->pt3d_bsize) {
1064  sec->pt3d_bsize = n;
1065  if ((sec->pt3d =
1066  (Pt3d *)hoc_Erealloc((char *)sec->pt3d, n*sizeof(Pt3d)))
1067  == (Pt3d *)0) {
1068  sec->npt3d = 0;
1069  sec->pt3d_bsize = 0;
1070  hoc_malchk();
1071  }
1072  }
1073 }
1074 
1075 static void nrn_pt3dmodified(Section* sec, int i0) {
1076  int n, i;
1077 
1079  diam_changed = 1;
1080  sec->recalc_area_ = 1;
1081  n = sec->npt3d;
1082 #if NTS_SPINE
1083 #else
1084  if (sec->pt3d[i0].d < 0.) {
1085  hoc_execerror("Diameter less than 0", (char *)0);
1086  }
1087 #endif
1088  if (i0 == 0) {
1089  sec->pt3d[0].arc = 0.;
1090  i0 = 1;
1091  }
1092  for (i = i0; i < n; ++i) {
1093  Pt3d* p = sec->pt3d + i - 1;
1094  double t1,t2,t3;
1095  t1 = sec->pt3d[i].x - p->x;
1096  t2 = sec->pt3d[i].y - p->y;
1097  t3 = sec->pt3d[i].z - p->z;
1098  sec->pt3d[i].arc = p->arc + sqrt(t1*t1 + t2*t2 + t3*t3);
1099  }
1100  sec->prop->dparam[2].val = sec->pt3d[n-1].arc;
1101 }
1102 
1103 void nrn_pt3dclear(Section* sec, int req) {
1105  if (req != sec->pt3d_bsize) {
1106  if (sec->pt3d) {
1107  free((char *)(sec->pt3d));
1108  sec->pt3d = (Pt3d *)0;
1109  sec->pt3d_bsize = 0;
1110  }
1111  if (req > 0) {
1112  sec->pt3d = (Pt3d*)ecalloc(req, sizeof(Pt3d));
1113  sec->pt3d_bsize = req;
1114  }
1115  }
1116  sec->npt3d = 0;
1117 }
1118 
1119 
1120 void nrn_pt3dinsert(Section* sec, int i0, double x, double y, double z, double d) {
1121  int i, n;
1122  n = sec->npt3d;
1123  nrn_pt3dbufchk(sec, n+1);
1124  ++sec->npt3d;
1125  for (i = n-1; i >= i0; --i) {
1126  Pt3d* p = sec->pt3d + i + 1;
1127  p->x = sec->pt3d[i].x;
1128  p->y = sec->pt3d[i].y;
1129  p->z = sec->pt3d[i].z;
1130  p->d = sec->pt3d[i].d;
1131  }
1132  sec->pt3d[i0].x = x;
1133  sec->pt3d[i0].y = y;
1134  sec->pt3d[i0].z = z;
1135  sec->pt3d[i0].d = d;
1136  nrn_pt3dmodified(sec,i0);
1137 }
1138 
1139 void pt3dinsert(void) {
1140  Section* sec;
1141  int i, n, i0;
1142  sec = chk_access();
1143  n = sec->npt3d;
1144  i0 = (int)chkarg(1, 0., (double)(n));
1145  nrn_pt3dinsert(sec, i0, *getarg(2), *getarg(3), *getarg(4), *getarg(5));
1146  hoc_retpushx(0.);
1147 }
1148 
1149 void nrn_pt3dchange1(Section* sec, int i, double d) {
1150  sec->pt3d[i].d = d;
1152  diam_changed = 1;
1153  sec->recalc_area_ = 1;
1154 }
1155 
1156 void nrn_pt3dchange2(Section* sec, int i, double x, double y, double z, double diam) {
1157  sec->pt3d[i].x = x;
1158  sec->pt3d[i].y = y;
1159  sec->pt3d[i].z = z;
1160  sec->pt3d[i].d = diam;
1161  nrn_pt3dmodified(sec, i);
1162 }
1163 
1164 void pt3dchange(void) {
1165  int i, n;
1166  Section* sec = chk_access();
1167  n = sec->npt3d;
1168  i = (int)chkarg(1, 0., (double)(n-1));
1169  if (ifarg(5)) {
1170  nrn_pt3dchange2(sec, i, *getarg(2), *getarg(3), *getarg(4), *getarg(5));
1171  }else{
1172  nrn_pt3dchange1(sec, i, *getarg(2));
1173  }
1174  hoc_retpushx(0.);
1175 }
1176 
1177 void nrn_pt3dremove(Section* sec, int i0) {
1178  int i, n;
1179  n = sec->npt3d;
1180  for (i=i0+1; i < n; ++i) {
1181  Pt3d* p = sec->pt3d + i - 1;
1182  p->x = sec->pt3d[i].x;
1183  p->y = sec->pt3d[i].y;
1184  p->z = sec->pt3d[i].z;
1185  p->d = sec->pt3d[i].d;
1186  }
1187  --sec->npt3d;
1188  nrn_pt3dmodified(sec, i0);
1189 }
1190 
1191 void pt3dremove(void) {
1192  int i, i0, n;
1193  Section* sec = chk_access();
1194  n = sec->npt3d;
1195  i0 = (int)chkarg(1, 0., (double)(n-1));
1196  nrn_pt3dremove(sec, i0);
1197 
1198  hoc_retpushx(0.);
1199 }
1200 
1202 {
1203  if (!pt3dconst_ && sec->npt3d) { /* fill 3dpoints as though constant diam segments */
1204  int i;
1205  double x, L;
1206  L = section_length(sec);
1207  if (fabs(L - sec->pt3d[sec->npt3d - 1].arc) > .001) {
1208  nrn_length_change(sec, L);
1209  }
1210  for (i=0; i < sec->npt3d; ++i) {
1211  x = sec->pt3d[i].arc/L;
1212  if (x > 1.0) {x = 1.0;}
1213  node_index(sec, x);
1214 sec->pt3d[i].d = nrn_diameter(sec->pnode[node_index(sec, x)]);
1215  }
1217  }
1218 }
1219 
1221 {
1222  if (!pt3dconst_ && sec->npt3d) {
1223  int i;
1224  double x0,y0,z0;
1225  double fac;
1226  double l;
1227  x0 = sec->pt3d[0].x;
1228  y0 = sec->pt3d[0].y;
1229  z0 = sec->pt3d[0].z;
1230  l = sec->pt3d[sec->npt3d-1].arc;
1231  fac = d/l;
1232 /*if (fac != 1) { printf("nrn_length_change from %g to %g\n", l, d);}*/
1233  for (i=0; i < sec->npt3d; ++i) {
1234  sec->pt3d[i].arc = sec->pt3d[i].arc *fac;
1235  sec->pt3d[i].x = x0 + (sec->pt3d[i].x - x0)*fac;
1236  sec->pt3d[i].y = y0 + (sec->pt3d[i].y - y0)*fac;
1237  sec->pt3d[i].z = z0 + (sec->pt3d[i].z - z0)*fac;
1238 
1239  }
1241  }
1242 }
1243 
1244 /*ARGSUSED*/
1246 {
1247  return pt3dconst_ == 0;
1248 }
1249 
1250 static void stor_pt3d_vec(Section* sec, IvocVect* xv, IvocVect* yv, IvocVect* zv, IvocVect* dv) {
1251  int i;
1252  int n = vector_capacity(xv);
1253  double* x = vector_vec(xv);
1254  double* y = vector_vec(yv);
1255  double* z = vector_vec(zv);
1256  double* d = vector_vec(dv);
1257  nrn_pt3dbufchk(sec, n);
1258  sec->npt3d = n;
1259  for (i=0; i < n; i++) {
1260  sec->pt3d[i].x = x[i];
1261  sec->pt3d[i].y = y[i];
1262  sec->pt3d[i].z = z[i];
1263  sec->pt3d[i].d = d[i];
1264  }
1265  nrn_pt3dmodified(sec, 0);
1266 }
1267 
1268 void pt3dadd(void) {
1269  /*pt3add(x,y,z, d) stores 3d point at end of current pt3d list.
1270  first point assumed to be at arc length position 0. Last point
1271  at 1. arc length increases monotonically.
1272  */
1273  if (hoc_is_object_arg(1)) {
1275  vector_arg(3), vector_arg(4));
1276  }else{
1277  stor_pt3d(chk_access(), *getarg(1), *getarg(2),
1278  *getarg(3), *getarg(4));
1279  }
1280  hoc_retpushx(1.);
1281 }
1282 
1283 
1284 void n3d(void) { /* returns number of 3d points in section */
1285  Section* sec;
1286  sec = chk_access();
1287  hoc_retpushx ((double)sec->npt3d);
1288 }
1289 
1290 void x3d(void) { /* returns x value at index of 3d list */
1291  Section* sec;
1292  int n, i;
1293  sec = chk_access();
1294  n = sec->npt3d - 1;
1295  i = chkarg(1, 0., (double)n);
1296  hoc_retpushx((double)sec->pt3d[i].x);
1297 }
1298 
1299 void y3d(void) { /* returns x value at index of 3d list */
1300  Section* sec;
1301  int n, i;
1302  sec = chk_access();
1303  n = sec->npt3d - 1;
1304  i = chkarg(1, 0., (double)n);
1305  hoc_retpushx((double)sec->pt3d[i].y);
1306 }
1307 
1308 void z3d(void) { /* returns x value at index of 3d list */
1309  Section* sec;
1310  int n, i;
1311  sec = chk_access();
1312  n = sec->npt3d - 1;
1313  i = chkarg(1, 0., (double)n);
1314  hoc_retpushx((double)sec->pt3d[i].z);
1315 }
1316 
1317 void arc3d(void) { /* returns x value at index of 3d list */
1318  Section* sec;
1319  int n, i;
1320  sec = chk_access();
1321  n = sec->npt3d - 1;
1322  i = chkarg(1, 0., (double)n);
1323  hoc_retpushx((double)sec->pt3d[i].arc);
1324 }
1325 
1326 void diam3d(void) { /* returns x value at index of 3d list */
1327  Section* sec;
1328  double d;
1329  int n, i;
1330  sec = chk_access();
1331  n = sec->npt3d - 1;
1332  i = chkarg(1, 0., (double)n);
1333  d = (double)sec->pt3d[i].d;
1334  hoc_retpushx(fabs(d));
1335 }
1336 
1337 void spine3d(void) { /* returns x value at index of 3d list */
1338  Section* sec;
1339  int n, i;
1340  double d;
1341  sec = chk_access();
1342  n = sec->npt3d - 1;
1343  i = chkarg(1, 0., (double)n);
1344  d = (double)sec->pt3d[i].d;
1345  if (d < 0) {
1346  hoc_retpushx(1.);
1347  }else{
1348  hoc_retpushx(0.);
1349  }
1350 }
1351 
1352 void stor_pt3d(Section* sec, double x, double y, double z, double d)
1353 {
1354  int n;
1355 
1356  n = sec->npt3d;
1357  nrn_pt3dbufchk(sec, n+1);
1358  sec->npt3d++;
1359  sec->pt3d[n].x = x;
1360  sec->pt3d[n].y = y;
1361  sec->pt3d[n].z = z;
1362  sec->pt3d[n].d = d;
1363  nrn_pt3dmodified(sec, n);
1364 }
1365 
1366 static double spinearea=0.;
1367 
1368 void setSpineArea(void) {
1369  spinearea = *getarg(1);
1370  diam_changed = 1;
1372 }
1373 
1374 void getSpineArea(void) {
1376 }
1377 
1378 void define_shape(void) {
1379  nrn_define_shape();
1380  hoc_retpushx(1.);
1381 }
1382 
1383 static void nrn_translate_shape(Section* sec, float x, float y, float z)
1384 {
1385  int i;
1386  float dx, dy, dz;
1387  if (pt3dconst_) {
1388  return;
1389  }
1390  if (sec->logical_connection) { /* args are relative not absolute */
1391  Pt3d* p = sec->logical_connection;
1392  dx = x - p->x;
1393  dy = y - p->y;
1394  dz = z - p->z;
1395  p->x = x;
1396  p->y = y;
1397  p->z = z;
1398  }else{
1399  dx = x - sec->pt3d[0].x;
1400  dy = y - sec->pt3d[0].y;
1401  dz = z - sec->pt3d[0].z;
1402  }
1403 /* if (dx*dx + dy*dy + dz*dz < 10.)*/
1404  for (i=0; i < sec->npt3d; ++i) {
1405  sec->pt3d[i].x += dx;
1406  sec->pt3d[i].y += dy;
1407  sec->pt3d[i].z += dz;
1408  }
1409 }
1410 
1411 void nrn_define_shape(void) {
1412  static int changed_;
1413  int i, j;
1414  Section* sec, *psec, *ch;
1415  float x, y, z, dz, x1, y1;
1416  float nch, ich=0.0, angle;
1417  double arc, len;
1418  if (changed_ == nrn_shape_changed_ && !diam_changed && !tree_changed) {
1419  return;
1420  }
1421  recalc_diam();
1422  dz = 100.;
1423  for (i=0; i < section_count; ++i) {
1424  sec = secorder[i];
1425  arc = nrn_connection_position(sec);
1426  if ((psec = sec->parentsec) == (Section*)0) {
1427  /* section has no parent */
1428  x = 0;
1429  y = 0;
1430  z = i * dz;
1431  x1 = 1;
1432  y1 = 0;
1433  }else{
1434  double arc1 = arc;
1435  x1 = psec->pt3d[psec->npt3d-1].x - psec->pt3d[0].x;
1436  y1 = psec->pt3d[psec->npt3d-1].y - psec->pt3d[0].y;
1437  if (!arc0at0(psec)) {
1438  arc1 = 1. - arc;
1439  }
1440  if (arc1 < .5) {
1441  x1 = -x1;
1442  y1 = -y1;
1443  }
1444 x = psec->pt3d[psec->npt3d-1].x*arc1 + psec->pt3d[0].x*(1-arc1);
1445 y = psec->pt3d[psec->npt3d-1].y*arc1 + psec->pt3d[0].y*(1-arc1);
1446 z = psec->pt3d[psec->npt3d-1].z*arc1 + psec->pt3d[0].z*(1-arc1);
1447  }
1448  if (sec->npt3d) {
1449  if (psec) {
1450  nrn_translate_shape(sec, x, y, z);
1451  }
1452  continue;
1453  }
1454  if (fabs(y1) < 1e-6 && fabs(x1) < 1e-6) {
1455 Printf("nrn_define_shape: %s first and last 3-d point at same (x,y)\n", secname(psec));
1456  angle = 0.;
1457  }else{
1458  angle = atan2(y1, x1);
1459  }
1460  if (arc > 0. && arc < 1.) {
1461  angle += 3.14159265358979323846/2.;
1462  }
1463  nch = 0.;
1464  if (psec) for (ch=psec->child; ch; ch = ch->sibling) {
1465  if (ch == sec) {
1466  ich = nch;
1467  }
1468  if (arc == nrn_connection_position(ch)) {
1469  ++nch;
1470  }
1471  }
1472  if (nch > 1) {
1473  angle += ich/(nch - 1.) * .8 - .4;
1474  }
1475  len = section_length(sec);
1476  x1 = x + len*cos(angle);
1477  y1 = y + len*sin(angle);
1478  stor_pt3d(sec, x, y, z, nrn_diameter(sec->pnode[0]));
1479  for (j = 0; j < sec->nnode-1; ++j) {
1480  double frac = ((double)j+.5)/(double)(sec->nnode-1);
1481  stor_pt3d(sec,
1482  x*(1-frac)+x1*frac,
1483  y*(1-frac)+y1*frac,
1484  z,
1485  nrn_diameter(sec->pnode[j])
1486  );
1487  }
1488  stor_pt3d(sec, x1, y1, z, nrn_diameter(sec->pnode[sec->nnode-2]));
1489  /* don't let above change length due to round-off errors*/
1490  sec->pt3d[sec->npt3d-1].arc = len;
1491  sec->prop->dparam[2].val = len;
1492  }
1493  changed_ = nrn_shape_changed_;
1494 }
1495 
1496 static double diam_from_list(Section* sec, int inode, Prop* p, double rparent)
1497  /* p->param[0] is diam of inode in sec.*/
1498  /* rparent right half resistance of the parent segment*/
1499 {
1500  /* Basic algorithm assumes a set of monotonic points on which a
1501  function is defined. The extension is the piecewise continuous
1502  function. y(x) for 0<=x<=x[n] (extrapolate for x>x[n]).
1503  The problem is to form the integral of f(y(s)) over intervals
1504  s[i] <= s <= s[i+1]. Note the intervals don't have to be equal.
1505  This implementation is specific to a call to this function for
1506  each interval in order.
1507  */
1508  /* computes diam as average, area, and ri. Slightly weirder since
1509  interval spit in two to compute right and left half values of ri
1510  */
1511  /* fills NODEAREA and NODERINV and returns the right half resistance
1512  (MOhms) of the segment.
1513  */
1514  static int j;
1515  static double x1, y1, ds;
1516  int ihalf;
1517  double si, sip;
1518  double diam, delta, temp, ri, area, ra, rleft=0.0;
1519  int npt, nspine;
1520 
1521  if (inode == 0) {
1522  j = 0;
1523  si = 0.;
1524  x1 = sec->pt3d[j].arc;
1525  y1 = fabs(sec->pt3d[j].d);
1526  ds = sec->pt3d[sec->npt3d - 1].arc / ((double)(sec->nnode - 1));
1527  }
1528  si = (double)inode*ds;
1529  npt = sec->npt3d;
1530  diam = 0.;
1531  area = 0.;
1532  nspine = 0;
1533  ra = nrn_ra(sec);
1534  for (ihalf = 0; ihalf < 2; ihalf++) {
1535  ri = 0.;
1536  sip = si + ds/2.;
1537  for (;;) {
1538  int jp, jnext;
1539  double x2, y2, xj, xjp;
1540  jp = j + 1;
1541  xj = sec->pt3d[j].arc;
1542 #if NTS_SPINE
1543  if (sec->pt3d[j].d < 0 && xj >= si && xj < sip) {
1544  nspine++;
1545  }
1546 #endif
1547  xjp = sec->pt3d[jp].arc;
1548  if (xjp > sip || jp == npt - 1) {
1549  double frac;
1550  if (fabs(xjp - xj) < 1e-10) {
1551  frac = 1;
1552  }else{
1553  frac = (sip - xj)/(xjp - xj);
1554  }
1555  x2 = sip;
1556  y2 = (1. - frac)*fabs(sec->pt3d[j].d) + frac*fabs(sec->pt3d[jp].d);
1557  jnext = j;
1558  }else{
1559  x2 = xjp;
1560  y2 = fabs(sec->pt3d[jp].d);
1561  jnext = jp;
1562  }
1563 
1564  /* f += integrate(x1,y1, x2, y2) */
1565  delta = (x2 - x1);
1566  diam += (y2 + y1)*delta;
1567  if (delta < 1e-15) {
1568  delta = 1e-15;
1569  }
1570  if ((temp = y2*y1/delta) == 0) {
1571  temp = 1e-15;
1572  }
1573  ri += 1/temp;
1574 #if 1 /*taper is very seldom taken into account*/
1575  temp = .5*(y2 - y1);
1576  temp = sqrt(delta*delta + temp*temp);
1577 #else
1578  temp = delta;
1579 #endif
1580 
1581  area += (y2 + y1)*temp;
1582  /* end of integration */
1583 
1584  x1 = x2;
1585  y1 = y2;
1586  if (j == jnext) {
1587  break;
1588  }
1589  j = jnext;
1590  }
1591  if (ihalf == 0) {
1592  rleft = ri*ra/PI*(4.*.01); /*left seg resistance*/
1593  }else{
1594  ri = ri*ra/PI*(4.*.01); /* MegOhms */
1595  /* above is right half segment resistance */
1596  }
1597  si = sip;
1598  }
1599  /* answer for inode is here */
1600  NODERINV(sec->pnode[inode]) = 1./(rparent + rleft);
1601  diam *= .5/ds;
1602  if (fabs(diam - p->param[0]) > 1e-9 || diam < 1e-5) {
1603  p->param[0] = diam; /* microns */
1604  }
1605  NODEAREA(sec->pnode[inode]) = area*.5*PI;/* microns^2 */
1606  UPDATE_VEC_AREA(sec->pnode[inode]);
1607 #if NTS_SPINE
1608  /* if last point has a spine then increment spine count for last node */
1609  if (inode == sec->nnode-2 && sec->pt3d[npt-1].d < 0.) {
1610  nspine += 1;
1611  }
1612  NODEAREA(sec->pnode[inode]) += nspine*spinearea;
1613  UPDATE_VEC_AREA(sec->pnode[inode]);
1614 #endif
1615  return ri;
1616 }
1617 
1618 #endif /*DIAMLIST*/
1619 
1620 #include "multicore.cpp"
1621 
1622 #if VECTORIZE
1623 void v_setup_vectors(void) {
1624  int inode, i;
1625  int isec;
1626  Section* sec;
1627  Node* nd;
1628  Prop* p;
1629  NrnThread* _nt;
1630 
1631  if (tree_changed) {
1632  setup_topology(); /* now classical secorder */
1633  v_structure_change = 1;
1635  }
1636  /* get rid of the old */
1637  if (!v_structure_change) {
1638  return;
1639  }
1640 
1641  nrn_threads_free();
1642 
1643  for (i=0; i < n_memb_func; ++i)
1644  if (nrn_is_artificial_[i] && memb_func[i].initialize) {
1645  if (memb_list[i].nodecount) {
1646  memb_list[i].nodecount = 0;
1647  free(memb_list[i].nodelist);
1648 #if CACHEVEC
1649  free((void *)memb_list[i].nodeindices);
1650 #endif /* CACHEVEC */
1651  if (memb_func[i].hoc_mech) {
1652  free(memb_list[i].prop);
1653  }else{
1654  free(memb_list[i].data);
1655  free(memb_list[i].pdata);
1656  }
1657  }
1658  }
1659 
1660 #if 1 /* see finitialize */
1661  /* and count the artificial cells */
1662  for (i=0; i < n_memb_func; ++i) if (nrn_is_artificial_[i] && memb_func[i].initialize) {
1663  cTemplate* tmp = nrn_pnt_template_[i];
1664  memb_list[i].nodecount = tmp->count;
1665  }
1666 #endif
1667 
1668  /* allocate it*/
1669 
1670  for (i=0; i < n_memb_func; ++i)
1671  if (nrn_is_artificial_[i] && memb_func[i].initialize) {
1672  if (memb_list[i].nodecount) {
1673  memb_list[i].nodelist = (Node**) emalloc(memb_list[i].nodecount * sizeof(Node*));
1674 #if CACHEVEC
1675  memb_list[i].nodeindices = (int *) emalloc(memb_list[i].nodecount * sizeof(int));
1676 #endif /* CACHEVEC */
1677  if (memb_func[i].hoc_mech) {
1678  memb_list[i].prop = (Prop**) emalloc(memb_list[i].nodecount * sizeof(Prop*));
1679  }else{
1680  memb_list[i].data = (double**) emalloc(memb_list[i].nodecount * sizeof(double*));
1681  memb_list[i].pdata = (Datum**) emalloc(memb_list[i].nodecount * sizeof(Datum*));
1682  }
1683  memb_list[i].nodecount = 0; /* counted again below */
1684  }
1685  }
1686 
1687 #if MULTICORE
1688  if (!nrn_user_partition()) {
1689  /* does not depend on memb_list */
1690  int ith, j;
1691  NrnThread* _nt;
1692  section_order(); /* could be already reordered */
1693  /* round robin distribution */
1694  for (ith=0; ith < nrn_nthread; ++ith) {
1695  _nt = nrn_threads + ith;
1696  _nt->roots = hoc_l_newlist();
1697  _nt->ncell = 0;
1698  }
1699  j = 0;
1700  for (ith=0; ith < nrn_nthread; ++ith) {
1701  _nt = nrn_threads + ith;
1702  for (i=ith; i < nrn_global_ncell; i += nrn_nthread) {
1703  hoc_l_lappendsec(_nt->roots, secorder[j]);
1704  ++_nt->ncell;
1705  ++j;
1706  }
1707  }
1708  }
1709  /* reorder. also fill NrnThread node indices, v_node, and v_parent */
1710  reorder_secorder();
1711 #endif
1712 
1713 #if CACHEVEC
1714  FOR_THREADS(_nt) {
1715  for (inode=0; inode < _nt->end; inode++) {
1716  if (_nt->_v_parent[inode]!=NULL) {
1718  }
1719  }
1720  }
1721 
1722 #endif /* CACHEVEC */
1723 
1725 
1726 #if 1 /* see finitialize */
1727  /* fill in artificial cell info */
1728  for (i=0; i < n_memb_func; ++i) if (nrn_is_artificial_[i] && memb_func[i].initialize) {
1729  hoc_Item* q;
1730  hoc_List* list;
1731  int j, nti;
1732  cTemplate* tmp = nrn_pnt_template_[i];
1733  memb_list[i].nodecount = tmp->count;
1734  nti = 0;
1735  j = 0;
1736  list = tmp->olist;
1737 #if 0
1738  if (memb_func[i].vectorized == 0 && list->next != list) {
1739 hoc_execerror(memb_func[i].sym->name, "is not thread safe");
1740  }
1741 #endif
1742  ITERATE(q, list) {
1743  Object* obj = OBJ(q);
1744  Point_process* pnt = (Point_process*)obj->u.this_pointer;
1745  p = pnt->prop;
1746  memb_list[i].nodelist[j] = (Node*)0;
1747  memb_list[i].data[j] = p->param;
1748  memb_list[i].pdata[j] = p->dparam;
1749 /* for now, round robin all the artificial cells */
1750 /* but put the non-threadsafe ones in thread 0 */
1751 /*
1752  Note that artficial cells are assumed not to need a thread specific
1753  Memb_list. But this implies that they do not have thread specific
1754  data. For this reason, for now, an otherwise thread-safe artificial
1755  cell model is declared by nmodl as thread-unsafe.
1756 */
1757 
1758  if (memb_func[i].vectorized == 0) {
1759  pnt->_vnt = (void*)(nrn_threads);
1760  }else{
1761  pnt->_vnt = (void*)(nrn_threads + nti);
1762  nti = (nti + 1)%nrn_nthread;
1763  }
1764  ++j;
1765  }
1766  }
1767 #endif
1769  v_structure_change = 0;
1770  nrn_update_ps2nt();
1774  diam_changed = 1;
1775 }
1776 
1777 #endif /*VECTORIZE*/
1778 
1779 #define NODE_DATA 0
1780 #if NODE_DATA
1781 static FILE* fnd;
1782 
1783 #undef P
1784 #undef Pn
1785 #undef Pd
1786 #undef Pg
1787 
1788 #define P fprintf(fnd,
1789 #define Pn P "\n")
1790 #define Pd(arg) P "%d\n", arg)
1791 #define Pg(arg) P "%g\n", arg)
1792 
1793 void node_data_scaffolding(void) {
1794  int i;
1795  Pd(n_memb_func);
1796 /* P "Mechanism names (first two are nil) beginning with memb_func[2]\n");*/
1797  for (i=2; i < n_memb_func; ++ i){
1798  P "%s", memb_func[i].sym->name); Pn;
1799  }
1800 }
1801 
1802 void node_data_structure(void) {
1803  int i, j;
1804  nrn_thread_error("node_data_structure");
1805  Pd(v_node_count);
1806 
1807  Pd(nrn_global_ncell);
1808 /* P "Indices of node parents\n");*/
1809  for (i=0; i < v_node_count; ++i) {
1810  Pd(v_parent[i]->v_node_index);
1811  }
1812 /* P "node lists for the membrane mechanisms\n");*/
1813  for (i=2; i < n_memb_func; ++ i){
1814 /* P "count, node list for mechanism %s\n", memb_func[i].sym->name);*/
1815  Pd(memb_list[i].nodecount);
1816  for (j=0; j < memb_list[i].nodecount; ++j) {
1817  Pd(memb_list[i].nodelist[j]->v_node_index);
1818  }
1819  }
1820 }
1821 
1822 void node_data_values(void) {
1823  int i, j, k;
1824 /* P "data for nodes then for all mechanisms in order of the above structure\n"); */
1825  for (i=0; i < v_node_count; ++ i) {
1826  Pg(NODEV(v_node[i]));
1827  Pg(NODEA(v_node[i]));
1828  Pg(NODEB(v_node[i]));
1829  Pg(NODEAREA(v_node[i]));
1830  }
1831  for (i=2; i < n_memb_func; ++ i){
1832  Prop* prop, *nrn_mechanism();
1833  int cnt;
1834  double* pd;
1835  if (memb_list[i].nodecount) {
1836  assert(!memb_func[i].hoc_mech);
1837  prop = nrn_mechanism(i, memb_list[i].nodelist[0]);
1838  cnt = prop->param_size;
1839  Pd(cnt);
1840  }
1841  for (j=0; j < memb_list[i].nodecount; ++j) {
1842  pd = memb_list[i].data[j];
1843  for (k = 0; k < cnt; ++k) {
1844  Pg(pd[k]);
1845  }
1846  }
1847  }
1848 }
1849 
1850 void node_data(void) {
1851  fnd = fopen(gargstr(1), "w");
1852  if (!fnd) {
1853  hoc_execerror("node_data: can't open", gargstr(1));
1854  }
1855  if (tree_changed) {
1856  setup_topology();
1857  }
1858  if (v_structure_change) {
1859  v_setup_vectors();
1860  }
1861  if (diam_changed) {
1862  recalc_diam();
1863  }
1864  node_data_scaffolding();
1865  node_data_structure();
1866  node_data_values();
1867  fclose(fnd);
1868  hoc_retpushx(1.);
1869 }
1870 
1871 #else
1872 void node_data(void) {
1873  Printf("recalc_diam=%d nrn_area_ri=%d\n", recalc_diam_count_, nrn_area_ri_count_);
1874  hoc_retpushx(0.);
1875 }
1876 
1877 #endif
1878 
1879 extern "C" void nrn_complain(double* pp) {
1880  /* print location for this param on the standard error */
1881  Node* nd;
1882  hoc_Item* qsec;
1883  int j;
1884  Prop* p;
1886  for (j = 0; j < sec->nnode; ++j) {
1887  nd = sec->pnode[j];
1888  for (p = nd->prop; p; p = p->next) {
1889  if (p->param == pp) {
1890 
1891 fprintf(stderr, "Error at section location %s(%g)\n", secname(sec),
1892  nrn_arc_position(sec, nd));
1893  return;
1894  }
1895  }
1896  }
1897  }
1898  fprintf(stderr, "Don't know the location of params at %p\n", pp);
1899 }
1900 
1902  NrnThread* nt;
1903  FOR_THREADS(nt) {
1904  if (nt->_actual_rhs) {
1905  free(nt->_actual_rhs);
1906  nt->_actual_rhs = (double*)0;
1907  }
1908  if (nt->_actual_d) {
1909  free(nt->_actual_d);
1910  nt->_actual_d = (double*)0;
1911  }
1912 #if CACHEVEC
1913  if (nt->_actual_a) {
1914  free(nt->_actual_a);
1915  nt->_actual_a = (double*)0;
1916  }
1917  if (nt->_actual_b) {
1918  free(nt->_actual_b);
1919  nt->_actual_b = (double*)0;
1920  }
1921  /* because actual_v and actual_area have pointers to them from many
1922  places, defer the freeing until nrn_recalc_node_ptrs is called
1923  */
1924 #endif /* CACHEVEC */
1925  if (nt->_sp13mat) {
1926  spDestroy(nt->_sp13mat);
1927  nt->_sp13mat = (char*)0;
1928  }
1929  }
1930  diam_changed = 1;
1931 }
1932 
1933 /* 0 means no model, 1 means ODE, 2 means DAE */
1934 int nrn_modeltype(void) {
1935  NrnThread* nt;
1936  static cTemplate* lm = (cTemplate*)0;
1937  int type;
1938  v_setup_vectors();
1939 
1940  if (!nrndae_list_is_empty()) {
1941  return 2;
1942  }
1943 
1944  type = 0;
1945  if (nrn_global_ncell > 0) {
1946  type = 1;
1947  FOR_THREADS(nt) if (nt->_ecell_memb_list) {
1948  type = 2;
1949  }
1950  }
1951  if (type == 0 && nrn_nonvint_block_ode_count(0, 0)) { type = 1; }
1952  return type;
1953 }
1954 
1955 /*
1956 minimally update flags consistent with the model type and cvode_active_
1957 return true if any flags changed.
1958 If DAE then variable step method requires daspk
1959 If DAE then must be sparse13
1960 If daspk then must be sparse13
1961 If cvode then must be classic tree method
1962 */
1963 
1965  int consist;
1966  int type;
1967  consist = 0;
1968  type = nrn_modeltype();
1969  if (cvode_active_) {
1970  if (type == 2) {
1971  if (nrn_use_daspk_ == 0) {
1972  nrn_use_daspk(1);
1973  consist = 1;
1974  }
1975  }
1976  if (nrn_use_daspk_ != use_sparse13) {
1978  consist = 1;
1979  }
1980  }else if (type == 2 && use_sparse13 == 0) {
1981  use_sparse13 = 1;
1982  consist = 1;
1983  }
1984  if (use_sparse13 != 0) {
1985  nrn_cachevec(0);
1986  }
1987  return consist;
1988 }
1989 
1990 
1991 /*
1992 sparse13 uses the mathematical index scheme in which the rows and columns
1993 range from 1...size instead of 0...size-1. Thus the calls to
1994 spGetElement(i,j) have args that are 1 greater than a normal c style.
1995 Also the actual_rhs_ uses this style, 1-neqn, when sparse13 is activated
1996 and therefore is passed to spSolve as actual_rhs intead of actual_rhs-1.
1997 */
1998 
1999 static void nrn_matrix_node_alloc(void) {
2000  int i, b;
2001  Node* nd;
2002  NrnThread* nt;
2003 
2005  nt = nrn_threads;
2006 /*printf("use_sparse13=%d sp13mat=%lx rhs=%lx\n", use_sparse13, (long)nt->_sp13mat, (long)nt->_actual_rhs);*/
2007  if (use_sparse13) {
2008  if (nt->_sp13mat) {
2009  return;
2010  }else{
2012  }
2013  }else{
2014  if (nt->_sp13mat) {
2015  v_structure_change = 1;
2016  v_setup_vectors();
2017  return;
2018  }else{
2019  if (nt->_actual_rhs != (double*)0) {
2020  return;
2021  }
2022  }
2023  }
2024 /*printf("nrn_matrix_node_alloc does its work\n");*/
2025 #if CACHEVEC
2026  FOR_THREADS(nt) {
2027  nt->_actual_a = (double*)ecalloc(nt->end, sizeof(double));
2028  nt->_actual_b = (double*)ecalloc(nt->end, sizeof(double));
2029  }
2031 #endif /* CACHEVEC */
2032 
2033 #if 0
2034 printf("nrn_matrix_node_alloc use_sparse13=%d cvode_active_=%d nrn_use_daspk_=%d\n", use_sparse13, cvode_active_, nrn_use_daspk_);
2035 #endif
2036  ++nrn_matrix_cnt_;
2037  if (use_sparse13) {
2038  int in, err, extn, neqn, j;
2039  nt = nrn_threads;
2040  neqn = nt->end + nrndae_extra_eqn_count();
2041  extn = 0;
2042  if (nt->_ecell_memb_list) {
2043  extn = nt->_ecell_memb_list->nodecount * nlayer;
2044  }
2045 /*printf(" %d extracellular nodes\n", extn);*/
2046  neqn += extn;
2047  nt->_actual_rhs = (double*)ecalloc(neqn+1, sizeof(double));
2048  nt->_sp13mat = spCreate(neqn, 0, &err);
2049  if (err != spOKAY) {
2050  hoc_execerror("Couldn't create sparse matrix", (char*)0);
2051  }
2052  for (in=0, i=1; in < nt->end; ++in, ++i) {
2053  nt->_v_node[in]->eqn_index_ = i;
2054  if (nt->_v_node[in]->extnode) {
2055  i += nlayer;
2056  }
2057  }
2058  for (in = 0; in < nt->end; ++in) {
2059  int ie, k;
2060  Node* nd, *pnd;
2061  Extnode* nde;
2062  nd = nt->_v_node[in];
2063  nde = nd->extnode;
2064  pnd = nt->_v_parent[in];
2065  i = nd->eqn_index_;
2066  nd->_rhs = nt->_actual_rhs + i;
2067  nd->_d = spGetElement(nt->_sp13mat, i, i);
2068  if (nde) {
2069  for (ie = 0; ie < nlayer; ++ie) {
2070  k = i + ie + 1;
2071  nde->_d[ie] = spGetElement(nt->_sp13mat, k, k);
2072  nde->_rhs[ie] = nt->_actual_rhs + k;
2073  nde->_x21[ie] = spGetElement(nt->_sp13mat, k, k-1);
2074  nde->_x12[ie] = spGetElement(nt->_sp13mat, k-1, k);
2075  }
2076  }
2077  if (pnd) {
2078  j = pnd->eqn_index_;
2079  nd->_a_matelm = spGetElement(nt->_sp13mat, j, i);
2080  nd->_b_matelm = spGetElement(nt->_sp13mat, i, j);
2081  if (nde && pnd->extnode) for (ie = 0; ie < nlayer; ++ie) {
2082  int kp = j + ie + 1;
2083  k = i + ie + 1;
2084  nde->_a_matelm[ie] = spGetElement(nt->_sp13mat, kp, k);
2085  nde->_b_matelm[ie] = spGetElement(nt->_sp13mat, k, kp);
2086  }
2087  }else{ /* not needed if index starts at 1 */
2088  nd->_a_matelm = (double*)0;
2089  nd->_b_matelm = (double*)0;
2090  }
2091  }
2092  nrndae_alloc();
2093  }else{
2094  FOR_THREADS(nt) {
2097  nt->_actual_d = (double*)ecalloc(nt->end, sizeof(double));
2098  nt->_actual_rhs = (double*)ecalloc(nt->end, sizeof(double));
2099  for (i = 0; i < nt->end; ++i) {
2100  Node* nd = nt->_v_node[i];
2101  nd->_d = nt->_actual_d + i;
2102  nd->_rhs = nt->_actual_rhs + i;
2103  }
2104  }
2105  }
2106 }
2107 
2108 void nrn_cachevec(int b) {
2109  if (use_sparse13) {
2110  use_cachevec = 0;
2111  }else{
2112  if (b && use_cachevec == 0) {
2113  tree_changed = 1;
2114  }
2115  use_cachevec = b;
2116  }
2117 }
2118 
2119 #if CACHEVEC
2120 /*
2121 Pointers that need to be updated are:
2122 All Point process area pointers.
2123 All mechanism POINTER variables that point to v.
2124 All Graph addvar pointers that plot v.
2125 All Vector record and play pointers that deal with v.
2126 All PreSyn threshold detectors that watch v.
2127 */
2128 
2130 static void (*recalc_ptr_callback[20])();
2131 static int recalc_cnt_;
2133 static int n_old_thread_;
2135 static double** old_actual_v_;
2136 static double** old_actual_area_;
2137 
2138 /* defer freeing a few things which may have pointers to them
2139 until ready to update those pointers */
2141  int i;
2142  int n = nrn_nthread;
2143  if (old_actual_v_){return;} /* one is already outstanding */
2144  n_old_thread_ = n;
2145  old_actual_v_size_ = (int*)ecalloc(n, sizeof(int));
2146  old_actual_v_ = (double**)ecalloc(n, sizeof(double*));
2147  old_actual_area_ = (double**)ecalloc(n, sizeof(double*));
2148  for (i=0; i < n; ++i) {
2149  NrnThread* nt = nrn_threads + i;
2150  old_actual_v_size_[i] = nt->end;
2151  old_actual_v_[i] = nt->_actual_v;
2153  }
2154 }
2155 
2156 static double* (*recalc_ptr_)(double*);
2157 
2158 extern "C" double* nrn_recalc_ptr(double* old) {
2159  if (recalc_ptr_) { return (*recalc_ptr_)(old); }
2160  if (!recalc_ptr_old_vp_) { return old; }
2161  if (nrn_isdouble(old, 0.0, (double)recalc_cnt_)) {
2162  int k = (int)(*old);
2163  if (old == recalc_ptr_old_vp_[k]) {
2164  return recalc_ptr_new_vp_[k];
2165  }
2166  }
2167  return old;
2168 }
2169 
2171  if (n_recalc_ptr_callback >= 20) {
2172  Printf("More than 20 recalc_ptr_callback functions\n");
2173  exit(1);
2174  }
2176 }
2177 
2178 void nrn_recalc_ptrs(double*(*r)(double*)) {
2179  int i;
2180 
2181  recalc_ptr_ = r;
2182 
2183  /* update pointers managed by c++ */
2185 
2186  /* user callbacks to update pointers */
2187  for (i=0; i < n_recalc_ptr_callback; ++i) {
2188  (*recalc_ptr_callback[i])();
2189  }
2190  recalc_ptr_ = nullptr;
2191 }
2192 
2194  int i, ii, j, k;
2195  NrnThread* nt;
2196  if (use_cachevec == 0) { return; }
2197 /*printf("nrn_recalc_node_ptrs\n");*/
2198  recalc_cnt_ = 0;
2199  FOR_THREADS(nt) { recalc_cnt_ += nt->end; }
2200  recalc_ptr_new_vp_ = (double**)ecalloc(recalc_cnt_, sizeof(double*));
2201  recalc_ptr_old_vp_ = (double**)ecalloc(recalc_cnt_, sizeof(double*));
2202  /* first update the pointers without messing with the old NODEV,NODEAREA */
2203  /* to prepare for the update, copy all the v and area values into the */
2204  /* new arrays are replace the old values by index value. */
2205  /* a pointer dereference value of i allows us to easily check */
2206  /* if the pointer points to what v_node[i]->_v points to. */
2207  ii = 0;
2208  FOR_THREADS(nt) {
2209  nt->_actual_v = (double*)ecalloc(nt->end, sizeof(double));
2210  nt->_actual_area = (double*)ecalloc(nt->end, sizeof(double));
2211  }
2212  FOR_THREADS(nt) for (i = 0; i < nt->end; ++i) {
2213  Node* nd = nt->_v_node[i];
2214  nt->_actual_v[i] = *nd->_v;
2215  recalc_ptr_new_vp_[ii] = nt->_actual_v + i;
2216  recalc_ptr_old_vp_[ii] = nd->_v;
2217  nt->_actual_area[i] = nd->_area;
2218  *nd->_v = (double)ii;
2219  ++ii;
2220  }
2221  /* update POINT_PROCESS pointers to NODEAREA */
2222  /* and relevant POINTER pointers to NODEV */
2223  FOR_THREADS(nt) for (i=0; i < nt->end; ++i) {
2224  Node* nd = nt->_v_node[i];
2225  Prop* p;
2226  Datum* d;
2227  int dpend;
2228  for (p = nd->prop; p; p = p->next) {
2229  if (memb_func[p->type].is_point && !nrn_is_artificial_[p->type]) {
2230  p->dparam[0].pval = nt->_actual_area + i;
2231  }
2232  dpend = nrn_dparam_ptr_end_[p->type];
2233  for (j=nrn_dparam_ptr_start_[p->type]; j < dpend; ++j) {
2234  double* pval = p->dparam[j].pval;
2235  if (nrn_isdouble(pval, 0., (double)recalc_cnt_)) {
2236  /* possible pointer to v */
2237  k = (int)(*pval);
2238  if (pval == recalc_ptr_old_vp_[k]) {
2239  p->dparam[j].pval = recalc_ptr_new_vp_[k];
2240  }
2241  }
2242  }
2243  }
2244  }
2245 
2246  nrn_recalc_ptrs(nullptr);
2247 
2248  /* now that all the pointers are updated we update the NODEV */
2249  ii = 0;
2250  FOR_THREADS(nt) for (i = 0; i < nt->end; ++i) {
2251  Node* nd = nt->_v_node[i];
2252  nd->_v = recalc_ptr_new_vp_[ii];
2253  ++ii;
2254  }
2255  free(recalc_ptr_old_vp_);
2256  free(recalc_ptr_new_vp_);
2257  recalc_ptr_old_vp_ = (double**)0;
2258  recalc_ptr_new_vp_ = (double**)0;
2259  /* and free the old thread arrays if new ones were allocated */
2260  for (i = 0; i < n_old_thread_; ++i) {
2262  if (old_actual_area_[i]) free(old_actual_area_[i]);
2263  }
2264  free(old_actual_v_size_);
2265  free(old_actual_v_);
2266  free(old_actual_area_);
2267  old_actual_v_size_ = 0;
2268  old_actual_v_ = 0;
2269  old_actual_area_ = 0;
2270  n_old_thread_ = 0;
2271 
2276 }
2277 
2278 #endif /* CACHEVEC */
2279 
void define_shape(void)
Definition: treeset.cpp:1378
#define data
Definition: rbtqueue.cpp:49
void nrn_pt3dinsert(Section *sec, int i0, double x, double y, double z, double d)
Definition: treeset.cpp:1120
Definition: hocdec.h:84
int nrn_shape_changed_
Definition: treeset.cpp:28
#define Printf
Definition: model.h:252
FOR_THREADS(_nt)
Definition: multicore.cpp:887
double * _actual_d
Definition: multicore.h:71
void activclamp_rhs(void)
Definition: clamp.cpp:162
#define nrn_nonvint_block_conductance(size, d, tid)
Definition: nonvintblock.h:47
int param_size
Definition: section.h:217
void * ecalloc(size_t n, size_t size)
Definition: symbol.cpp:221
Section ** secorder
Definition: solve.cpp:77
hoc_List * hoc_l_newlist()
Prop * need_memb(Symbol *sym)
Definition: treeset.cpp:638
double * param
Definition: section.h:218
spREAL * spGetElement(char *, int, int)
Definition: spbuild.c:195
struct Prop * prop
Definition: section.h:62
double nrnmpi_wtime()
Definition: nrnmpi.cpp:171
#define assert(ex)
Definition: hocassrt.h:26
float z
Definition: section.h:67
void long_difus_solve(int, NrnThread *)
Definition: ldifus.cpp:98
short type
Definition: cabvars.h:10
short nnode
Definition: section.h:41
void nrn_prop_data_free(int type, double *pd)
Definition: cxprop.cpp:287
void * _vnt
Definition: section.h:269
void clear_point_process_struct(Prop *p)
Definition: point.cpp:376
void clamp_prepare()
Definition: clamp.cpp:144
#define prop
Definition: md1redef.h:29
static void stor_pt3d_vec(Section *sec, IvocVect *xv, IvocVect *yv, IvocVect *zv, IvocVect *dv)
Definition: treeset.cpp:1250
Prop * prop_alloc_disallow(Prop **pp, short type, Node *nd)
Definition: treeset.cpp:716
void z3d(void)
Definition: treeset.cpp:1308
void nrn_pt3dclear(Section *sec, int req)
Definition: treeset.cpp:1103
void nrn_ba(NrnThread *, int)
Definition: fadvance.cpp:1041
ClassicalNODEB(nd)
void nrn_old_thread_save(void)
Definition: treeset.cpp:2140
#define NODEV(n)
Definition: section.h:114
static double ** old_actual_area_
Definition: treeset.cpp:2136
struct NrnThreadMembList * next
Definition: multicore.h:34
if(status)
void nrn_recalc_ptrs(double *(*r)(double *))
Definition: treeset.cpp:2178
struct Section * parentsec
Definition: section.h:42
#define NODED(n)
Definition: section.h:103
double nrn_ra(Section *)
Definition: cabcode.cpp:392
double * nrn_classicalNodeA(Node *nd)
double * _nrn_sav_d
Definition: multicore.h:47
void pt3dremove(void)
Definition: treeset.cpp:1191
static int n_recalc_ptr_callback
Definition: treeset.cpp:2129
int use_cachevec
Definition: treeset.cpp:61
struct Section * sibling
Definition: section.h:46
#define ITERATE(itm, lst)
Definition: model.h:25
double * pval
Definition: hocdec.h:180
void pt3dinsert(void)
Definition: treeset.cpp:1139
short * nrn_is_artificial_
Definition: init.cpp:231
double ** _x21
Definition: section.h:203
Definition: section.h:66
double nrn_arc_position(Section *sec, Node *node)
Definition: cabcode.cpp:1880
short npt3d
Definition: section.h:57
int nrndae_list_is_empty()
Definition: nrndae.cpp:23
#define spClear
Definition: cspredef.h:5
void
int * _v_parent_index
Definition: multicore.h:76
section_order()
Definition: solve.cpp:835
double ** _b_matelm
Definition: section.h:201
void * this_pointer
Definition: hocdec.h:231
Node ** _v_parent
Definition: multicore.h:78
Pvmi current
Definition: membfunc.h:33
size_t p
Represent main neuron object computed by single thread.
Definition: multicore.h:58
void notify_freed_val_array(double *p, size_t size)
Definition: ivoc.cpp:104
double * _actual_rhs
Definition: multicore.h:70
void setup_topology()
void diam3d(void)
Definition: treeset.cpp:1326
double ** _d
Definition: section.h:198
char * name
Definition: model.h:72
cos
Definition: extdef.h:3
Object * ob
Definition: section.h:224
void nrn_thread_error(const char *)
Definition: multicore.cpp:453
Memb_func * memb_func
Definition: init.cpp:161
int nrn_area_ri_count_
Definition: treeset.cpp:772
nd
Definition: treeset.cpp:893
#define spOKAY
Definition: spmatrix.h:97
float x
Definition: section.h:67
struct Node * _classical_parent
Definition: section.h:156
long _alloc_seq
Definition: section.h:223
void activclamp_lhs(void)
Definition: clamp.cpp:180
double ** data
Definition: nrnoc_ml.h:14
void activstim_rhs(void)
Definition: fstim.cpp:159
Section * nrn_pnt_sec_for_need_
Definition: treeset.cpp:633
void nrn_register_recalc_ptr_callback(Pfrv f)
Definition: treeset.cpp:2170
void nrndae_rhs()
Definition: nrndae.cpp:74
double * nrn_mech_wtime_
Definition: treeset.cpp:29
static void nrn_thread_memblist_setup()
Definition: multicore.cpp:855
ext_con_coef()
Definition: extcelln.cpp:507
#define P(arg)
Definition: cout.cpp:220
#define nodeindices
Definition: md1redef.h:26
int structure_change_cnt
Definition: treeset.cpp:79
void hoc_free_val_array(double *, size_t)
Definition: symbol.cpp:382
static philox4x32_key_t k
Definition: nrnran123.cpp:11
sin
Definition: extdef.h:3
Prop ** prop
Definition: nrnoc_ml.h:16
#define UPDATE_VEC_AREA(nd)
Definition: treeset.cpp:59
inode
Definition: multicore.cpp:985
#define MORPHOLOGY
Definition: membfunc.h:63
int arc0at0(Section *sec)
Definition: cabcode.cpp:387
void nrn_cap_jacob(NrnThread *_nt, Memb_list *ml)
Definition: capac.cpp:32
static void nrn_recalc_node_ptrs()
Definition: treeset.cpp:2193
hoc_List * olist
Definition: hocdec.h:203
#define e
Definition: passive0.cpp:24
_nrn_Fast_Imem * _nrn_fast_imem
Definition: multicore.h:82
#define gargstr
Definition: hocdec.h:14
void y3d(void)
Definition: treeset.cpp:1299
struct Pt3d * logical_connection
Definition: section.h:60
void nrn_pt3dchange1(Section *sec, int i, double d)
Definition: treeset.cpp:1149
j< sec-> nnode
Definition: treeset.cpp:905
double * hoc_pgetarg(int narg)
Definition: code.cpp:1604
void nrn_shape_update(void)
Definition: treeset.cpp:932
short type
Definition: section.h:215
void nrniv_recalc_ptrs()
Definition: cachevec.cpp:35
int nrn_method_consistent(void)
Definition: treeset.cpp:1964
double * nrn_recalc_ptr(double *old)
Definition: treeset.cpp:2158
void stim_prepare(void)
Definition: fstim.cpp:151
void stor_pt3d(Section *sec, double x, double y, double z, double d)
Definition: treeset.cpp:1352
int nrn_area_ri_nocount_
Definition: treeset.cpp:772
int id
Definition: multicore.h:66
void nrn_pt3dchange2(Section *sec, int i, double x, double y, double z, double diam)
Definition: treeset.cpp:1156
float y
Definition: section.h:67
int ncell
Definition: multicore.h:64
void nrndae_alloc()
Definition: nrndae.cpp:50
struct Pt3d * pt3d
Definition: section.h:59
void nrn_complain(double *pp)
Definition: treeset.cpp:1879
Symbol * sym
Definition: membfunc.h:38
int hoc_is_pdouble_arg(int narg)
Definition: code.cpp:737
void nrn_pt3dstyle0(Section *sec)
Definition: treeset.cpp:993
int nrn_nthread
Definition: multicore.cpp:44
Node ** _v_node
Definition: multicore.h:77
Symlist * hoc_built_in_symlist
Definition: symbol.cpp:39
atan2
Definition: extdef.h:3
#define VEC_A(i)
Definition: section.h:117
int const size_t const size_t n
Definition: nrngsl.h:12
Memb_list * ml
Definition: multicore.h:35
Memb_list * _ecell_memb_list
Definition: multicore.h:80
int nodecount
Definition: nrnoc_ml.h:18
static double diam_from_list(Section *sec, int inode, Prop *p, double rparent)
Definition: treeset.cpp:1496
void recalc_diam(void)
Definition: treeset.cpp:940
_CONST char * s
Definition: system.cpp:74
int nrn_modeltype(void)
Definition: treeset.cpp:1934
Node * nrn_alloc_node_
Definition: treeset.cpp:686
int nrn_user_partition()
Definition: multicore.cpp:1162
hoc_List * roots
Definition: multicore.h:90
NrnThread * nrn_threads
Definition: multicore.cpp:45
double ** _x12
Definition: section.h:202
#define NODEA(n)
Definition: section.h:123
double * _nrn_sav_rhs
Definition: multicore.h:46
#define nodelist
Definition: md1redef.h:25
cTemplate ** nrn_pnt_template_
Definition: init.cpp:169
void hoc_obj_unref(Object *obj)
Definition: hoc_oop.cpp:1998
void nrn_partrans_update_ptrs()
Definition: partrans.cpp:345
double arc
Definition: section.h:68
Memb_list * memb_list
Definition: init.cpp:162
static double ** old_actual_v_
Definition: treeset.cpp:2135
double nrn_connection_position(Section *sec)
Definition: cabcode.cpp:1645
Prop * prop
Definition: section.h:264
#define printf
Definition: mwprefix.h:26
int nrn_use_daspk_
Definition: treeset.cpp:70
void(* Pvmi)(struct NrnThread *, Memb_list *, int)
Definition: membfunc.h:18
static int n_old_thread_
Definition: treeset.cpp:2133
void nrn_prop_datum_free(int type, Datum *ppd)
Definition: cxprop.cpp:294
int
Definition: nrnmusic.cpp:71
void nrn_rhs(NrnThread *_nt)
Definition: treeset.cpp:355
void ri(void)
Definition: treeset.cpp:968
const char * secname(Section *sec)
Definition: cabcode.cpp:1787
static double ** recalc_ptr_old_vp_
Definition: treeset.cpp:2132
void hoc_warning(const char *, const char *)
Pvmp alloc
Definition: membfunc.h:32
void single_prop_free(Prop *p)
Definition: treeset.cpp:736
static Node * pnd
Definition: clamp.cpp:33
#define NODERINV(n)
Definition: section.h:116
static double ** recalc_ptr_new_vp_
Definition: treeset.cpp:2132
double * nrn_classicalNodeB(Node *nd)
int n_memb_func
Definition: init.cpp:471
double * _b_matelm
Definition: section.h:147
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:741
#define VEC_B(i)
Definition: section.h:118
#define cnt
Definition: spt2queue.cpp:19
int nrn_isdouble(double *, double, double)
Definition: isoc99.cpp:12
char * pnt_map
Definition: init.cpp:166
void activsynapse_rhs(void)
Definition: synapse.cpp:204
void prop_free(Prop **pp)
Definition: treeset.cpp:724
int tree_changed
Definition: cabcode.cpp:19
errno
Definition: system.cpp:98
double * _a_matelm
Definition: section.h:146
int nrn_node_ptr_change_cnt_
Definition: treeset.cpp:82
hoc_retpushx(1.0)
static void nrn_matrix_node_alloc(void)
Definition: treeset.cpp:1999
char * _sp13mat
Definition: multicore.h:79
void pt3dchange(void)
Definition: treeset.cpp:1164
void nrn_recalc_ptrvector()
Definition: cachevec.cpp:98
hoc_List * section_list
Definition: init.cpp:126
Datum ** pdata
Definition: nrnoc_ml.h:15
fprintf(stderr, "Don't know the location of params at %p\, pp)
int node_index(Section *, double)
Definition: cabcode.cpp:1470
Definition: model.h:57
#define spGetSize
Definition: cspredef.h:23
Definition: section.h:213
void nrn_matrix_node_free(void)
Definition: treeset.cpp:1901
void(* nrn_multisplit_setup_)()
Definition: treeset.cpp:46
void x3d(void)
Definition: treeset.cpp:1290
int diam_change_cnt
Definition: treeset.cpp:80
Prop * nrn_mechanism(int type, Node *nd)
Definition: cabcode.cpp:1079
void getSpineArea(void)
Definition: treeset.cpp:1374
#define NODEB(n)
Definition: section.h:124
int v_structure_change
Definition: treeset.cpp:78
void setSpineArea(void)
Definition: treeset.cpp:1368
char * emalloc(unsigned n)
Definition: list.cpp:189
#define spREAL
Definition: spmatrix.h:127
int * nrn_dparam_ptr_start_
Definition: init.cpp:180
#define CAP
Definition: membfunc.h:64
int can_change_morph(Section *sec)
Definition: treeset.cpp:1245
void nrn_update_ps2nt()
Definition: netcvode.cpp:4850
void nrn_lhs(NrnThread *_nt)
Definition: treeset.cpp:484
#define nlayer
Definition: section.h:187
double * _actual_a
Definition: multicore.h:72
double section_length(Section *sec)
Definition: cabcode.cpp:375
int * nrn_dparam_ptr_end_
Definition: init.cpp:181
int ifarg(int)
Definition: code.cpp:1562
#define VEC_V(i)
Definition: section.h:121
for(j=1;j< sec->nnode;j++)
Definition: treeset.cpp:897
struct Section * child
Definition: section.h:43
int end
Definition: multicore.h:65
Datum * dparam
Definition: section.h:219
ForAllSections(sec) if(!sec -> parentsec)
Definition: treeset.cpp:874
long subtype
Definition: model.h:59
static int * old_actual_v_size_
Definition: treeset.cpp:2134
void synapse_prepare(void)
Definition: synapse.cpp:196
static double spinearea
Definition: treeset.cpp:1366
void arc3d(void)
Definition: treeset.cpp:1317
static int disallow_needmemb
Definition: treeset.cpp:630
#define NODERHS(n)
Definition: section.h:104
void mech_insert1(Section *, int)
Definition: cabcode.cpp:845
#define OBJ(q)
Definition: hoclist.h:67
void * hoc_Erealloc(void *buf, size_t size)
Definition: symbol.cpp:253
Node ** nodelist
Definition: nrnoc_ml.h:5
int section_count
Definition: solve.cpp:76
Vect * vector_arg(int i)
Definition: ivocvect.cpp:332
int vector_capacity(Vect *v)
Definition: ivocvect.cpp:268
static void phase_end(const char *name)
Pvmi jacob
Definition: membfunc.h:34
int diam_changed
Definition: cabcode.cpp:23
static char * mechname
Definition: nocpout.cpp:151
void pt3dconst(void)
Definition: treeset.cpp:985
void nrn_cache_prop_realloc()
Definition: cxprop.cpp:572
int v_node_index
Definition: section.h:174
sqrt
Definition: extdef.h:3
void hoc_malchk()
Definition: symbol.cpp:187
static int recalc_cnt_
Definition: treeset.cpp:2131
struct hoc_Item * next
Definition: hoclist.h:50
static void phase_begin(const char *name)
Definition: hocdec.h:226
void nrn_length_change(Section *sec, double d)
Definition: treeset.cpp:1220
#define getarg
Definition: hocdec.h:15
#define nrn_nonvint_block_setup()
Definition: nonvintblock.h:36
double * _d
Definition: section.h:144
#define nodecount
Definition: md1redef.h:30
#define i
Definition: md1redef.h:12
void spine3d(void)
Definition: treeset.cpp:1337
int is_point
Definition: membfunc.h:53
void pt3dclear(void)
Definition: treeset.cpp:1050
#define PI
Definition: treeset.cpp:768
j
Definition: treeset.cpp:905
void connection_coef(void)
Definition: treeset.cpp:834
static void nrn_pt3dmodified(Section *sec, int i0)
Definition: treeset.cpp:1075
#define neqn
Definition: lineq.h:3
double * vector_vec(Vect *v)
Definition: ivocvect.cpp:271
void * setup_tree_matrix(NrnThread *_nt)
Definition: treeset.cpp:614
static void nrn_pt3dbufchk(Section *sec, int n)
Definition: treeset.cpp:1062
double _area
Definition: section.h:140
double nrn_diameter(Node *nd)
Definition: cabcode.cpp:423
void(* Pfrv)(void)
Definition: hocdec.h:40
struct Prop * next
Definition: section.h:214
void nrndae_lhs()
Definition: nrndae.cpp:80
sec
Definition: solve.cpp:885
void nrn_pt3dstyle1(Section *sec, double x, double y, double z)
Definition: treeset.cpp:1002
void pt3dadd(void)
Definition: treeset.cpp:1268
fabs
Definition: extdef.h:3
static void(* recalc_ptr_callback[20])()
Definition: treeset.cpp:2130
double * _actual_area
Definition: multicore.h:75
double * _rhs
Definition: section.h:145
short pt3d_bsize
Definition: section.h:58
struct Node ** pnode
Definition: section.h:51
void activsynapse_lhs(void)
Definition: synapse.cpp:214
#define CABLESECTION
Definition: membfunc.h:62
#define nrn_nonvint_block_ode_count(offset, tid)
Definition: nonvintblock.h:54
Prop * prop_alloc(Prop **, int, Node *)
Definition: treeset.cpp:688
int nrn_errno_check(int)
Definition: fadvance.cpp:784
int hoc_is_object_arg(int narg)
Definition: code.cpp:745
#define VEC_D(i)
Definition: section.h:119
NrnThreadMembList * tml
Definition: multicore.h:62
static double *(* recalc_ptr_)(double *)
Definition: treeset.cpp:2156
double ** _a_matelm
Definition: section.h:200
void nrn_use_daspk(int)
Definition: netcvode.cpp:309
static int pt3dconst_
Definition: treeset.cpp:983
#define spCreate
Definition: cspredef.h:7
int nrn_matrix_cnt_
Definition: treeset.cpp:68
void node_data(void)
Definition: treeset.cpp:1872
double ** _rhs
Definition: section.h:199
int use_sparse13
Definition: treeset.cpp:69
#define spDestroy
Definition: cspredef.h:9
int recalc_diam_count_
Definition: treeset.cpp:772
Node * node_ptr(Section *sec, double x, double *parea)
Definition: cabcode.cpp:2003
void pt3dstyle(void)
Definition: treeset.cpp:1014
union Object::@54 u
void nrn_diam_change(Section *sec)
Definition: treeset.cpp:1201
void nrn_area_ri(Section *sec)
Definition: treeset.cpp:773
Definition: section.h:132
void nrn_setup_ext(NrnThread *_nt)
Definition: extcelln.cpp:438
int count
Definition: hocdec.h:202
size_t q
Definition: hocdec.h:176
void nrn_define_shape()
Definition: treeset.cpp:1411
int eqn_index_
Definition: section.h:148
ClassicalNODEA(nd)
#define VEC_RHS(i)
Definition: section.h:120
double val
Definition: hocdec.h:177
FILE * fopen()
#define pval
Definition: md1redef.h:32
Section * chk_access(void)
Definition: cabcode.cpp:437
#define BEFORE_BREAKPOINT
Definition: membfunc.h:75
double * _actual_b
Definition: multicore.h:73
void nrn_cachevec(int b)
Definition: treeset.cpp:2108
void nrn_threads_free()
Definition: multicore.cpp:626
void nrn_rhs_ext(NrnThread *_nt)
Definition: extcelln.cpp:360
return NULL
Definition: cabcode.cpp:461
static Prop ** current_prop_list
Definition: treeset.cpp:628
Node * nrn_parent_node(Node *nd)
Definition: treeset.cpp:830
void nrn_shape_update_always(void)
Definition: treeset.cpp:915
hoc_Item * hoc_l_lappendsec(hoc_List *, struct Section *)
#define pdata
Definition: md1redef.h:28
void v_setup_vectors(void)
Definition: treeset.cpp:1623
double chkarg(int, double low, double high)
Definition: code2.cpp:608
double * _actual_v
Definition: multicore.h:74
static void nrn_translate_shape(Section *sec, float x, float y, float z)
Definition: treeset.cpp:1383
void nrn_pt3dremove(Section *sec, int i0)
Definition: treeset.cpp:1177
struct Extnode * extnode
Definition: section.h:160
area
Definition: treeset.cpp:894
static void reorder_secorder()
Definition: multicore.cpp:875
void n3d(void)
Definition: treeset.cpp:1284
#define nrn_nonvint_block_current(size, rhs, tid)
Definition: nonvintblock.h:42
int nrn_global_ncell
Definition: init.cpp:127
#define NODEAREA(n)
Definition: section.h:115
short recalc_area_
Definition: section.h:53
int * nrn_prop_dparam_size_
Definition: init.cpp:179
struct Prop * prop
Definition: section.h:151
int nrndae_extra_eqn_count()
Definition: nrndae.cpp:36
float d
Definition: section.h:67
double * _v
Definition: section.h:139
int cvode_active_
Definition: fadvance.cpp:158