NEURON
nrndaspk.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 // differential algebraic system solver interface to DDASPK
3 
4 // DDASPK is translated from fortran with f2c. Hence all args are
5 // call by reference
6 
7 #include <stdio.h>
8 #include <math.h>
9 #include "spmatrix.h"
10 #include "nrnoc2iv.h"
11 #include "cvodeobj.h"
12 #include "nrndaspk.h"
13 #include "netcvode.h"
14 #include "nrn_ansi.h"
15 #include "ida/ida.h"
16 #include "ida/ida_impl.h"
17 #include "mymath.h"
18 
19 // the state of the g - d2/dx2 matrix for voltages
20 #define INVALID 0
21 #define NO_CAP 1
22 #define SETUP 2
23 #define FACTORED 3
24 static int solve_state_;
25 
26 // prototypes
27 
28 double Daspk::dteps_;
29 
30 
31 extern void nrndae_dkres(double*, double*, double*);
32 extern void nrndae_dkpsol(double);
33 extern void nrn_solve(NrnThread*);
34 void nrn_daspk_init_step(double, double, int);
35 // this is private in ida.cpp but we want to check if our initialization
36 // is good. Unfortunately ewt is set on the first call to solve which
37 // is too late for us.
38 extern "C" {
39 extern booleantype IDAEwtSet(IDAMem IDA_mem, N_Vector ycur);
40 } // extern "C"
41 
42 // extern double t, dt;
43 #define nt_dt nrn_threads->_dt
44 #define nt_t nrn_threads->_t
45 
46 static void daspk_nrn_solve(NrnThread* nt) {
47  nrn_solve(nt);
48 }
49 
50 static int res_gvardt(realtype t, N_Vector y, N_Vector yp, N_Vector delta, void* rdata);
51 
52 static int minit(IDAMem);
53 
54 static int msetup(IDAMem mem,
55  N_Vector y,
56  N_Vector ydot,
57  N_Vector delta,
58  N_Vector tempv1,
59  N_Vector tempv2,
60  N_Vector tempv3);
61 
62 static int msolve(IDAMem mem, N_Vector b, N_Vector ycur, N_Vector ypcur, N_Vector deltacur);
63 
64 static int mfree(IDAMem);
65 
66 
67 // at least in DARWIN the following is already declared so avoid conflict
68 #define thread_t nrn_thread_t
69 
70 // residual
71 static N_Vector nvec_y;
72 static N_Vector nvec_yp;
73 static N_Vector nvec_delta;
74 static double thread_t;
75 static double thread_cj;
76 static int thread_ier;
77 static Cvode* thread_cv;
78 static void* res_thread(NrnThread* nt) {
79  int i = nt->id;
80  Cvode* cv = thread_cv;
81  int ier = cv->res(thread_t,
82  cv->n_vector_data(nvec_y, i),
83  cv->n_vector_data(nvec_yp, i),
85  nt);
86  if (ier != 0) {
87  thread_ier = ier;
88  }
89  return 0;
90 }
91 static int res_gvardt(realtype t, N_Vector y, N_Vector yp, N_Vector delta, void* rdata) {
92  thread_cv = (Cvode*) rdata;
93  nvec_y = y;
94  nvec_yp = yp;
95  nvec_delta = delta;
96  thread_t = t;
97  thread_ier = 0;
99  return thread_ier;
100 }
101 
102 // linear solver specific allocation and initialization
103 static int minit(IDAMem) {
104  return IDA_SUCCESS;
105 }
106 
107 // linear solver preparation for subsequent calls to msolve
108 // approximation to jacobian. Everything necessary for solving P*x = b
109 static int msetup(IDAMem mem, N_Vector y, N_Vector yp, N_Vector, N_Vector, N_Vector, N_Vector) {
110  Cvode* cv = (Cvode*) mem->ida_rdata;
111  ++cv->jac_calls_;
112  return 0;
113 }
114 
115 /* solve P*x = b */
116 static void* msolve_thread(NrnThread* nt) {
117  int i = nt->id;
118  Cvode* cv = thread_cv;
119  int ier = cv->psol(
121  if (ier != 0) {
122  thread_ier = ier;
123  }
124  return 0;
125 }
126 static int msolve(IDAMem mem, N_Vector b, N_Vector w, N_Vector ycur, N_Vector, N_Vector) {
127  thread_cv = (Cvode*) mem->ida_rdata;
128  thread_t = mem->ida_tn;
129  nvec_y = ycur;
130  nvec_yp = b;
131  thread_cj = mem->ida_cj;
133  return thread_ier;
134 }
135 
136 static int mfree(IDAMem) {
137  return IDA_SUCCESS;
138 }
139 
140 Daspk::Daspk(Cvode* cv, int neq) {
141  // printf("Daspk::Daspk\n");
142  cv_ = cv;
143  yp_ = cv->nvnew(neq);
144  delta_ = cv->nvnew(neq);
145  parasite_ = cv->nvnew(neq);
146  use_parasite_ = false;
147  spmat_ = nullptr;
148  mem_ = nullptr;
149 }
150 
152  // printf("Daspk::~Daspk\n");
153  N_VDestroy(delta_);
154  N_VDestroy(yp_);
155  if (mem_) {
156  IDAFree((IDAMem) mem_);
157  }
158 }
159 
161  int ier;
162  if (mem_) {
163  ier = IDAReInit(
164  mem_, res_gvardt, cv_->t_, cv_->y_, yp_, IDA_SV, &cv_->ncv_->rtol_, cv_->atolnvec_);
165  if (ier < 0) {
166  hoc_execerror("IDAReInit error", 0);
167  }
168  } else {
169  IDAMem mem = (IDAMem) IDACreate();
170  if (!mem) {
171  hoc_execerror("IDAMalloc error", 0);
172  }
173  IDASetRdata(mem, cv_);
174  ier = IDAMalloc(
175  mem, res_gvardt, cv_->t_, cv_->y_, yp_, IDA_SV, &cv_->ncv_->rtol_, cv_->atolnvec_);
176  mem->ida_linit = minit;
177  mem->ida_lsetup = msetup;
178  mem->ida_lsolve = msolve;
179  mem->ida_lfree = mfree;
180  mem->ida_setupNonNull = false;
181  mem_ = mem;
182  }
183 }
184 
185 void Daspk::info() {}
186 
187 
188 // last two bits, 0 error, 1 warning, 2 apply parasitic
189 // if init_failure_style & 010, then use the original method
193 
194 static void do_ode_thread(neuron::model_sorted_token const& sorted_token, NrnThread& ntr) {
195  auto* const nt = &ntr;
196  int i;
197  Cvode* cv = thread_cv;
198  nt->_t = cv->t_;
199  cv->do_ode(sorted_token, ntr);
200  CvodeThreadData& z = cv->ctd_[nt->id];
201  double* yp = cv->n_vector_data(nvec_yp, nt->id);
202  for (i = z.neq_v_; i < z.nvsize_; ++i) {
203  yp[i] = *(z.pvdot_[i]);
204  }
205 }
206 
207 #if 0
208 static double check(double t, Daspk* ida) {
209  res_gvardt(t, ida->cv_->y_, ida->yp_, ida->delta_, ida->cv_);
210  double norm = N_VWrmsNorm(ida->delta_, ((IDAMem) (ida->mem_))->ida_ewt);
211  Printf("ida check t=%.15g norm=%g\n", t, norm);
212 #if 0
213  for (int i=0; i < ida->cv_->neq_; ++i) {
214  printf(" %3d %22.15g %22.15g %22.15g\n", i,
215 N_VGetArrayPointer(ida->cv_->y_)[i],
216 N_VGetArrayPointer(ida->yp_)[i],
217 N_VGetArrayPointer(ida->delta_)[i]);
218  }
219 #endif
220  return norm;
221 }
222 #endif
223 
224 int Daspk::init() {
225  extern double t;
226 #if 0
227 printf("Daspk_init t_=%20.12g t-t_=%g t0_-t_=%g\n",
228 cv_->t_, t-cv_->t_, cv_->t0_-cv_->t_);
229 #endif
230  N_VConst(0., yp_);
231 
232  // the new initial condition is based on a dteps_ step backward euler
233  // linear solution with respect to the old state in order to
234  // start the following initial condition calculation with a "valid"
235  // (in a linear system sense) initial state.
236 
237  double tt = cv_->t_;
238  double dtinv = 1. / dteps_;
239  if (init_failure_style_ & 010) {
240  cv_->play_continuous(tt);
241  nrn_daspk_init_step(tt, dteps_, 1);
242  nrn_daspk_init_step(tt, dteps_, 1);
244  cv_->play_continuous(tt);
245  nrn_daspk_init_step(tt, dteps_, 1);
247  N_VLinearSum(dtinv, cv_->y_, -dtinv, yp_, yp_);
248  } else {
249 #if 0
250  cv_->play_continuous(tt);
251  nrn_daspk_init_step(tt, dteps_, 1);
253  tt = cv_->t_ + dteps_;
254  cv_->play_continuous(tt);
255  nrn_daspk_init_step(tt, dteps_, 1);
257  N_VLinearSum(dtinv, yp_, -dtinv, cv_->y_, yp_);
259 #else
260  cv_->play_continuous(tt);
261  nrn_daspk_init_step(tt, dteps_, 1); // first approx to y (and maybe good enough)
262  nrn_daspk_init_step(tt, dteps_, 1); // 2nd approx to y (trouble with 2sramp.hoc)
263 
265  tt = cv_->t_ + dteps_;
266  cv_->play_continuous(tt);
267  nrn_daspk_init_step(tt, dteps_, 0); // rhs contains delta y (for v, vext, linmod
268  cv_->gather_ydot(yp_);
269  N_VScale(dtinv, yp_, yp_);
270 #endif
271  }
272  thread_cv = cv_;
273  nvec_yp = yp_;
275  ida_init();
276  t = cv_->t_;
277 #if 1
278  // test
279  // printf("test\n");
280  if (!IDAEwtSet((IDAMem) mem_, cv_->y_)) {
281  hoc_execerror("Bad Ida error weight vector", 0);
282  }
283  use_parasite_ = false;
284  // check(cv_->t_, this);
286  double norm = N_VWrmsNorm(parasite_, ((IDAMem) mem_)->ida_ewt);
287  // printf("norm=%g at t=%g\n", norm, t);
288  if (norm > 1.) {
289  switch (init_failure_style_ & 03) {
290  case 0:
291  Printf("IDA initialization failure, weighted norm of residual=%g\n", norm);
292  return IDA_ERR_FAIL;
293  break;
294  case 1:
295  Printf("IDA initialization warning, weighted norm of residual=%g\n", norm);
296  break;
297  case 2:
298  Printf("IDA initialization warning, weighted norm of residual=%g\n", norm);
299  use_parasite_ = true;
300  t_parasite_ = nt_t;
301  Printf(" subtracting (for next 1e-6 ms): f(y', y, %g)*exp(-1e7*(t-%g))\n", nt_t, nt_t);
302  break;
303  }
304 #if 0
305 for (int i=0; i < cv_->neq_; ++i) {
306  printf(" %d %g %g %g %g\n", i, nt_t, N_VGetArrayPointer(cv_->y_)[i], N_VGetArrayPointer(yp_)[i], N_VGetArrayPointer(delta_)[i]);
307 }
308 #endif
309  if (init_try_again_ < 0) {
311  init_try_again_ += 1;
312  int err = init();
313  init_try_again_ = 0;
314  return err;
315  }
316  return 0;
317  }
318 #endif
319 
320  return 0;
321 }
322 
323 int Daspk::advance_tn(double tstop) {
324  // printf("Daspk::advance_tn(%g)\n", tstop);
325  double tn = cv_->tn_;
326  IDASetStopTime(mem_, tstop);
327  int ier = IDASolve(mem_, tstop, &cv_->t_, cv_->y_, yp_, IDA_ONE_STEP_TSTOP);
328  if (ier < 0) {
329  // printf("DASPK advance_tn error\n");
330  return ier;
331  }
332 #if 0
333  if (ier > 0 && t < cv_->t_) {
334  // interpolation to tstop does not call res. So we have to.
335  cv_->res(cv_->t_, N_VGetArrayPointer(cv_->y_), N_VGetArrayPointer(yp_), N_VGetArrayPointer(delta_));
337  }
338 #else
339  // this is very bad, performance-wise. However ida modifies its states
340  // after a call to fun with the proper t.
341  res_gvardt(cv_->t_, cv_->y_, yp_, delta_, cv_);
342 #endif
343  cv_->t0_ = tn;
344  cv_->tn_ = cv_->t_;
345  // printf("Daspk::advance_tn complete.\n");
346  return ier;
347 }
348 
349 int Daspk::interpolate(double tt) {
350  // printf("Daspk::interpolate %.15g\n", tt);
351  assert(tt >= cv_->t0_ && tt <= cv_->tn_);
352  int ier = IDAGetSolution(mem_, tt, cv_->y_, yp_);
353  if (ier < 0) {
354  Printf("DASPK interpolate error\n");
355  return ier;
356  }
357  cv_->t_ = tt;
358  // interpolation does not call res. So we have to.
359  res_gvardt(cv_->t_, cv_->y_, yp_, delta_, cv_);
360  // if(MyMath::eq(t, cv_->t_, NetCvode::eps(cv_->t_))) {
361  // printf("t=%.15g t_=%.15g\n", t, cv_->t_);
362  //}
363  // assert(MyMath::eq(t, cv_->t_, NetCvode::eps(cv_->t_)));
364  return ier;
365 }
366 
368 #if 0
369  printf("rwork size = %d\n", iwork_[18-1]);
370  printf("iwork size = %d\n", iwork_[17-1]);
371  printf("Number of time steps = %d\n", iwork_[11-1]);
372  printf("Number of residual evaluations = %d\n", iwork_[12-1]);
373  printf("Number of Jac evaluations = %d\n", iwork_[13-1]);
374  printf("Number of preconditioner solves = %d\n", iwork_[21-1]);
375  printf("Number of nonlinear iterations = %d\n", iwork_[19-1]);
376  printf("Number of linear iterations = %d\n", iwork_[20-1]);
377  double avlin = double(iwork_[20-1])/double(iwork_[19-1]);
378  printf("Average Krylov subspace dimension = %g\n", avlin);
379  printf("nonlinear conv. failures = %d\n", iwork_[15-1]);
380  printf("linear conv. failures = %d\n", iwork_[16-1]);
381 #endif
383  Printf(" %d First try Initialization failures\n", first_try_init_failures_);
384  }
385 }
386 
387 static void* daspk_scatter_thread(NrnThread* nt) {
389  return 0;
390 }
391 void Cvode::daspk_scatter_y(N_Vector y) {
392  thread_cv = this;
393  nvec_y = y;
395 }
396 void Cvode::daspk_scatter_y(double* y, int tid) {
397  // the dependent variables in daspk are vi,vx,etc
398  // whereas in the node structure we need vm, vx
399  // note that a corresponding transformation for gather_ydot is
400  // not needed since the matrix solve is already with respect to vi,vx
401  // in all cases. (i.e. the solution vector is in the right hand side
402  // and refers to vi, vx.
404  // transform the vm+vext to vm
405  CvodeThreadData& z = ctd_[tid];
406  if (z.cmlext_) {
407  assert(z.cmlext_->ml.size() == 1);
408  Memb_list* ml = &z.cmlext_->ml[0];
409  int i, n = ml->nodecount;
410  for (i = 0; i < n; ++i) {
411  Node* nd = ml->nodelist[i];
412  nd->v() -= nd->extnode->v[0];
413  }
414  }
415 }
416 static void* daspk_gather_thread(NrnThread* nt) {
418  return 0;
419 }
420 void Cvode::daspk_gather_y(N_Vector y) {
421  thread_cv = this;
422  nvec_y = y;
424 }
425 void Cvode::daspk_gather_y(double* y, int tid) {
426  gather_y(y, tid);
427  // transform vm to vm+vext
428  CvodeThreadData& z = ctd_[tid];
429  if (z.cmlext_) {
430  assert(z.cmlext_->ml.size() == 1);
431  Memb_list* ml = &z.cmlext_->ml[0];
432  int i, n = ml->nodecount;
433  for (i = 0; i < n; ++i) {
434  Node* nd = ml->nodelist[i];
435  int j = nd->eqn_index_;
436  y[j - 1] += y[j];
437  }
438  }
439 }
440 
441 // for res and psol the equations for c*yp = f(y) are
442 // cast in the form G(t,y,yp) = f(y) - c*yp
443 // So res calculates delta = f(y) - c*yp
444 // and psol solves (c*cj - df/dy)*x = -b
445 // Note that since cvode uses J = 1 - gam*df/dy and
446 // ida uses J = df/dy - cj*df/dyp that is the origin of the use of -b in our
447 // psol and also why all the non-voltage odes are scaled by dt at the
448 // end of it.
449 
450 int Cvode::res(double tt, double* y, double* yprime, double* delta, NrnThread* nt) {
451  CvodeThreadData& z = ctd_[nt->id];
452  ++f_calls_;
453  nt->_t = tt;
454 
455 #if 0
456 printf("Cvode::res enter tt=%g\n", tt);
457 for (int i=0; i < z.nvsize_; ++i) {
458  printf(" %d %g %g %g\n", i, y[i], yprime[i], delta[i]);
459 }
460 #endif
461  nt->_vcv = this; // some models may need to know this
462  daspk_scatter_y(y, nt->id); // vi, vext, channel states, linmod non-node y.
463  // rhs of cy' = f(y)
464  play_continuous_thread(tt, nt);
465  auto const sorted_token = nrn_ensure_model_data_are_sorted();
466  nrn_rhs(sorted_token, *nt);
467  do_ode(sorted_token, *nt);
468  // accumulate into delta
469  gather_ydot(delta, nt->id);
470 
471  // now calculate -c*yp. i.e.
472  // cm*vm' + c_linmod*vi' internal current balance
473  // cx*vx' + c_linmod*vx' external current balance
474  // c_linmod*y' non-node linmod states
475  // y' mechanism states
476 
477  // this can be accumulated into delta in several stages
478  // -cm*vm'and -cx*vx for current balance equation delta's
479  // -c_linmod*yp (but note that the node yp yp(vm)+yp(vx))
480  // subtract yp from mechanism state delta's
481 
482 #if 0
483  static int res_ = 0;
484  ++res_;
485  printf("Cvode::res after ode and gather_ydot into delta\n");
486  for (int i=0; i < z.nvsize_; ++i) {
487  printf(" %d %g %g %g\n", i, y[i], yprime[i], delta[i]);
488  }
489 #endif
490  // the cap nodes : see nrnoc/capac.cpp for location of cm, etc.
491  // these are not in same order as for cvode but are in
492  // spmatrix order mixed with nocap nodes and extracellular
493  // therefore we use the Node.eqn_index to calculate the delta index.
494  // assert(use_sparse13 == true && nlayer <= 1);
495  assert(use_sparse13 == true);
496  if (z.cmlcap_) {
497  assert(z.cmlcap_->ml.size() == 1);
498  Memb_list* ml = &z.cmlcap_->ml[0];
499  int n = ml->nodecount;
500  auto const vec_sav_rhs = nt->node_sav_rhs_storage();
501  for (int i = 0; i < n; ++i) {
502  Node* nd = ml->nodelist[i];
503  int j = nd->eqn_index_ - 1;
504  Extnode* nde = nd->extnode;
505  double cdvm;
506  if (nde) {
507  cdvm = 1e-3 * ml->data(i, 0) * (yprime[j] - yprime[j + 1]);
508  delta[j] -= cdvm;
509  delta[j + 1] += cdvm;
510  // i_cap
511  ml->data(i, 1) = cdvm;
512 #if I_MEMBRANE
513  // add i_cap to i_ion which is in sav_g
514  // this will be copied to i_membrane below
516 #endif
517  } else {
518  cdvm = 1e-3 * ml->data(i, 0) * yprime[j];
519  delta[j] -= cdvm;
520  ml->data(i, 1) = cdvm;
521  }
522  if (vec_sav_rhs) {
523  int j = nd->v_node_index;
524  vec_sav_rhs[j] += cdvm;
525  vec_sav_rhs[j] *= NODEAREA(nd) * 0.01;
526  }
527  }
528  }
529  // See nrnoc/excelln.cpp for location of cx.
530  if (z.cmlext_) {
531  assert(z.cmlext_->ml.size() == 1);
532  Memb_list* ml = &z.cmlext_->ml[0];
533  int n = ml->nodecount;
534  for (int i = 0; i < n; ++i) {
535  Node* nd = ml->nodelist[i];
536  int j = nd->eqn_index_;
537 #if EXTRACELLULAR
538 #if I_MEMBRANE
539  // i_membrane = sav_rhs --- even for zero area nodes
542 #endif /*I_MEMBRANE*/
543  if (nrn_nlayer_extracellular == 1) {
544  // only works for one layer
545  // otherwise loop over layer,
546  // xc is (pd + 2*(nlayer))[layer]
547  // and deal with yprime[i+layer]-yprime[i+layer+1]
548  delta[j] -= 1e-3 *
549  ml->data(i, neuron::extracellular::xc_index, 0 /* 0th/only layer */) *
550  yprime[j];
551  } else {
552  int k = nrn_nlayer_extracellular - 1;
553  int jj = j + k;
554  delta[jj] -= 1e-3 * ml->data(i, neuron::extracellular::xc_index, k) * (yprime[jj]);
555  for (k = nrn_nlayer_extracellular - 2; k >= 0; --k) {
556  // k=0 refers to stuff between layer 0 and 1
557  // j is for vext[0]
558  jj = j + k;
559  auto const x = 1e-3 * ml->data(i, neuron::extracellular::xc_index, k) *
560  (yprime[jj] - yprime[jj + 1]);
561  delta[jj] -= x;
562  delta[jj + 1] += x; // last one in iteration is nlayer-1
563  }
564  }
565 #endif /*EXTRACELLULAR*/
566  }
567  }
568 
569  nrndae_dkres(y, yprime, delta);
570 
571  // the ode's
572  for (int i = z.neq_v_; i < z.nvsize_; ++i) {
573  delta[i] -= yprime[i];
574  }
575 
576  for (int i = 0; i < z.nvsize_; ++i) {
577  delta[i] *= -1.;
578  }
579  if (daspk_->use_parasite_ && tt - daspk_->t_parasite_ < 1e-6) {
580  double fac = exp(1e7 * (daspk_->t_parasite_ - tt));
581  double* tps = n_vector_data(daspk_->parasite_, nt->id);
582  for (int i = 0; i < z.nvsize_; ++i) {
583  delta[i] -= tps[i] * fac;
584  }
585  }
586  before_after(sorted_token, z.after_solve_, nt);
587 #if 0
588 printf("Cvode::res exit res_=%d tt=%20.12g\n", res_, tt);
589 for (int i=0; i < z.nvsize_; ++i) {
590  printf(" %d %g %g %g\n", i, y[i], yprime[i], delta[i]);
591 }
592 #endif
593  nt->_vcv = 0;
594 #if 0
595 double e = 0;
596 for (int i=0; i < z.nvsize_; ++i) {
597  e += delta[i]*delta[i];
598 }
599 printf("Cvode::res %d e=%g t=%.15g\n", res_, e, tt);
600 #endif
601  return 0;
602 }
603 
604 int Cvode::psol(double tt, double* y, double* b, double cj, NrnThread* _nt) {
605  CvodeThreadData& z = ctd_[_nt->id];
606  ++mxb_calls_;
607  int i;
608  _nt->_t = tt;
609 
610 #if 0
611 printf("Cvode::psol tt=%g solvestate=%d \n", tt, solve_state_);
612 for (i=0; i < z.nvsize_; ++i) {
613 printf(" %g", b[i]);
614 }
615 printf("\n");
616 #endif
617 
618  _nt->cj = cj;
619  _nt->_dt = 1. / cj;
620 
621  _nt->_vcv = this;
622  daspk_scatter_y(y, _nt->id); // I'm not sure this is necessary.
623  if (solve_state_ == INVALID) {
625  *_nt); // designed to setup M*[dvm+dvext, dvext, dy] = ...
627  }
628  if (solve_state_ == SETUP) {
629  // if using sparse 13 then should factor
631  }
632  scatter_ydot(b, _nt->id);
633 #if 0
634 printf("before nrn_solve matrix cj=%g\n", cj);
635 spPrint(sp13mat_, 1,1,1);
636 printf("before nrn_solve actual_rhs=\n");
637 for (i=0; i < z.neq_v_; ++i) {
638  printf("%d %g\n", i+1, actual_rhs[i+1]);
639 }
640 #endif
641  daspk_nrn_solve(_nt); // not the cvode one
642 #if 0
643 //printf("after nrn_solve matrix\n");
644 //spPrint(sp13mat_, 1,1,1);
645 printf("after nrn_solve actual_rhs=\n");
646 for (i=0; i < neq_v_; ++i) {
647  printf("%d %g\n", i+1, actual_rhs[i+1]);
648 }
649 #endif
650  solve_state_ = INVALID; // but not if using sparse13
652  gather_ydot(b, _nt->id);
653  // the ode's of the form m' = (minf - m)/mtau in model descriptions compute
654  // b = b/(1 + dt*mtau) since cvode required J = 1 - gam*df/dy
655  // so we need to scale those results by 1/cj.
656  for (i = z.neq_v_; i < z.nvsize_; ++i) {
657  b[i] *= _nt->_dt;
658  }
659 #if 0
660 for (i=0; i < z.nvsize_; ++i) {
661 printf(" %g", b[i]);
662 }
663 printf("\n");
664 #endif
665  _nt->_vcv = 0;
666  return 0;
667 }
668 
669 N_Vector Daspk::ewtvec() {
670  return ((IDAMem) mem_)->ida_ewt;
671 }
672 
673 N_Vector Daspk::acorvec() {
674  return ((IDAMem) mem_)->ida_delta;
675 }
Definition: cvodeobj.h:97
int neq_
Definition: cvodeobj.h:245
void solvemem(neuron::model_sorted_token const &, NrnThread *)
Definition: occvode.cpp:697
double t_
Definition: cvodeobj.h:126
int mxb_calls_
Definition: cvodeobj.h:132
void play_continuous_thread(double t, NrnThread *)
Definition: occvode.cpp:1155
N_Vector atolnvec_
Definition: cvodeobj.h:232
int jac_calls_
Definition: cvodeobj.h:132
int psol(double, double *, double *, double, NrnThread *)
Definition: nrndaspk.cpp:604
CvodeThreadData * ctd_
Definition: cvodeobj.h:240
void daspk_scatter_y(N_Vector)
Definition: nrndaspk.cpp:391
void gather_y(N_Vector)
Definition: occvode.cpp:523
void play_continuous(double t)
Definition: occvode.cpp:1141
N_Vector y_
Definition: cvodeobj.h:231
Daspk * daspk_
Definition: cvodeobj.h:209
void before_after(neuron::model_sorted_token const &, BAMechList *, NrnThread *)
Definition: occvode.cpp:857
NetCvode * ncv_
Definition: cvodeobj.h:244
int res(double, double *, double *, double *, NrnThread *)
Definition: nrndaspk.cpp:450
double * n_vector_data(N_Vector, int)
Definition: occvode.cpp:485
void do_ode(neuron::model_sorted_token const &, NrnThread &)
Definition: occvode.cpp:985
void daspk_gather_y(N_Vector)
Definition: nrndaspk.cpp:420
void scatter_y(neuron::model_sorted_token const &, double *, int)
Definition: occvode.cpp:498
double t0_
Definition: cvodeobj.h:126
double tn_
Definition: cvodeobj.h:126
void scatter_ydot(double *, int)
Definition: occvode.cpp:541
N_Vector nvnew(long)
Definition: cvodeobj.cpp:788
void gather_ydot(N_Vector)
Definition: occvode.cpp:554
int f_calls_
Definition: cvodeobj.h:132
CvMembList * cmlext_
Definition: cvodeobj.h:64
BAMechList * after_solve_
Definition: cvodeobj.h:67
std::vector< double * > pvdot_
Definition: cvodeobj.h:87
CvMembList * cmlcap_
Definition: cvodeobj.h:63
Definition: nrndaspk.h:10
virtual ~Daspk()
Definition: nrndaspk.cpp:151
void statistics()
Definition: nrndaspk.cpp:367
double t_parasite_
Definition: nrndaspk.h:31
bool use_parasite_
Definition: nrndaspk.h:32
void ida_init()
Definition: nrndaspk.cpp:160
int init()
Definition: nrndaspk.cpp:224
static double dteps_
Definition: nrndaspk.h:35
static int init_try_again_
Definition: nrndaspk.h:36
int interpolate(double tout)
Definition: nrndaspk.cpp:349
static int first_try_init_failures_
Definition: nrndaspk.h:37
void info()
Definition: nrndaspk.cpp:185
N_Vector yp_
Definition: nrndaspk.h:28
N_Vector delta_
Definition: nrndaspk.h:29
void * mem_
Definition: nrndaspk.h:26
Cvode * cv_
Definition: nrndaspk.h:27
Daspk(Cvode *, int neq)
Definition: nrndaspk.cpp:140
int advance_tn(double tstop)
Definition: nrndaspk.cpp:323
N_Vector acorvec()
Definition: nrndaspk.cpp:673
char * spmat_
Definition: nrndaspk.h:33
N_Vector ewtvec()
Definition: nrndaspk.cpp:669
static int init_failure_style_
Definition: nrndaspk.h:34
N_Vector parasite_
Definition: nrndaspk.h:30
static bool eq(T x, T y, T e)
Definition: mymath.h:63
static double eps(double x)
Definition: netcvode.h:137
double rtol_
Definition: netcvode.h:158
#define i
Definition: md1redef.h:19
int nrn_nlayer_extracellular
Definition: extcelln.cpp:16
static RNG::key_type k
Definition: nrnran123.cpp:9
#define assert(ex)
Definition: hocassrt.h:24
printf
Definition: extdef.h:5
exp
Definition: extdef.h:5
double norm(const Point3D &p1)
Definition: lfp.hpp:22
static void nrn_lhs(NrnThread *_nt)
void hoc_execerror(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:39
static void nrn_rhs(NrnThread *_nt)
void nrn_multithread_job(F &&job, Args &&... args)
Definition: multicore.hpp:161
std::size_t sav_rhs_index_ext()
Definition: membfunc.h:146
static constexpr auto xc_index
Definition: membfunc.h:126
static constexpr auto sav_rhs_index
Definition: membfunc.h:130
static constexpr auto i_membrane_index
Definition: membfunc.h:128
static void check(VecTNode &)
Definition: cellorder1.cpp:401
neuron::model_sorted_token nrn_ensure_model_data_are_sorted()
Ensure neuron::container::* data are sorted.
Definition: treeset.cpp:2182
void nrndae_dkpsol(double)
static void do_ode_thread(neuron::model_sorted_token const &sorted_token, NrnThread &ntr)
Definition: nrndaspk.cpp:194
void nrndae_dkres(double *, double *, double *)
Definition: nrndae.cpp:98
#define FACTORED
Definition: nrndaspk.cpp:23
static int res_gvardt(realtype t, N_Vector y, N_Vector yp, N_Vector delta, void *rdata)
Definition: nrndaspk.cpp:91
static N_Vector nvec_yp
Definition: nrndaspk.cpp:72
static void daspk_nrn_solve(NrnThread *nt)
Definition: nrndaspk.cpp:46
#define thread_t
Definition: nrndaspk.cpp:68
void nrn_daspk_init_step(double, double, int)
Definition: fadvance.cpp:307
static N_Vector nvec_delta
Definition: nrndaspk.cpp:73
static void * msolve_thread(NrnThread *nt)
Definition: nrndaspk.cpp:116
static int solve_state_
Definition: nrndaspk.cpp:24
static double thread_cj
Definition: nrndaspk.cpp:75
void nrn_solve(NrnThread *)
Definition: solve.cpp:333
static int thread_ier
Definition: nrndaspk.cpp:76
static int msolve(IDAMem mem, N_Vector b, N_Vector ycur, N_Vector ypcur, N_Vector deltacur)
static N_Vector nvec_y
Definition: nrndaspk.cpp:71
static int mfree(IDAMem)
Definition: nrndaspk.cpp:136
booleantype IDAEwtSet(IDAMem IDA_mem, N_Vector ycur)
#define SETUP
Definition: nrndaspk.cpp:22
#define INVALID
Definition: nrndaspk.cpp:20
#define nt_t
Definition: nrndaspk.cpp:44
static void * daspk_gather_thread(NrnThread *nt)
Definition: nrndaspk.cpp:416
static void * daspk_scatter_thread(NrnThread *nt)
Definition: nrndaspk.cpp:387
static void * res_thread(NrnThread *nt)
Definition: nrndaspk.cpp:78
static int msetup(IDAMem mem, N_Vector y, N_Vector ydot, N_Vector delta, N_Vector tempv1, N_Vector tempv2, N_Vector tempv3)
Definition: nrndaspk.cpp:109
static int minit(IDAMem)
Definition: nrndaspk.cpp:103
static Cvode * thread_cv
Definition: nrndaspk.cpp:77
int const size_t const size_t n
Definition: nrngsl.h:10
size_t j
#define NODEAREA(n)
Definition: section.h:101
int use_sparse13
Definition: treeset.cpp:58
void spPrint(char *, int, int, int)
Definition: spoutput.cpp:126
std::vector< Memb_list > ml
Definition: cvodeobj.h:41
std::vector< neuron::container::data_handle< double > > param
Definition: section_fwd.hpp:33
double * v
Definition: section_fwd.hpp:40
A view into a set of mechanism instances.
Definition: nrnoc_ml.h:34
int nodecount
Definition: nrnoc_ml.h:78
Node ** nodelist
Definition: nrnoc_ml.h:68
std::vector< double * > data()
Get a vector of double* representing the model data.
Definition: memblist.cpp:64
Definition: section.h:105
int eqn_index_
Definition: section.h:187
int v_node_index
Definition: section.h:212
Extnode * extnode
Definition: section.h:199
auto & v()
Definition: section.h:141
Represent main neuron object computed by single thread.
Definition: multicore.h:58
double _dt
Definition: multicore.h:60
int id
Definition: multicore.h:66
double cj
Definition: multicore.h:61
double * node_sav_rhs_storage()
Definition: multicore.cpp:1088
void * _vcv
Definition: multicore.h:97
double _t
Definition: multicore.h:59
int Printf(const char *fmt, Args... args)
Definition: logger.hpp:18