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