libpspm
lsoda.tpp
Go to the documentation of this file.
1 #include <iostream>
2 #include <cassert>
3 
4 
5 template <class Functor>
7  const size_t neq, std::vector<double> &y, Functor &derivs, void *_data)
8 {
9  (void)neq;
10 
11  size_t i = 0, ier = 0, j = 0;
12  double fac = 0.0, hl0 = 0.0, r = 0.0, r0 = 0.0, yj = 0.0;
13  /*
14  prja is called by stoda to compute and process the matrix
15  P = I - h_ * el[1] * J, where J is an approximation to the Jacobian.
16  Here J is computed by finite differencing.
17  J, scaled by -h_ * el[1], is stored in wm_. Then the norm of J ( the
18  matrix norm consistent with the weighted max-norm on vectors given
19  by vmnorm ) is computed, and J is overwritten by P. P is then
20  subjected to LU decomposition in preparation for later solution
21  of linear systems with p as coefficient matrix. This is done
22  by dgefa if miter = 2, and by dgbfa if miter = 5.
23  */
24  nje++;
25  ierpj = 0;
26  jcur = 1;
27  hl0 = h_ * el0;
28  /*
29  If miter = 2, make n calls to f to approximate J.
30  */
31  if(miter != 2) {
32  fprintf(stderr, "[prja] miter != 2\n");
33  return;
34  }
35  if(miter == 2) {
36  fac = vmnorm(n, savf, ewt);
37  r0 = 1000. * fabs(h_) * ETA * ((double)n) * fac;
38  if(r0 == 0.)
39  r0 = 1.;
40  for(j = 1; j <= n; j++) {
41  yj = y[j];
42  r = std::max(sqrteta * fabs(yj), r0 / ewt[j]);
43  y[j] += r;
44  fac = -hl0 / r;
45  derivs(tn_, ++y.begin(), ++acor.begin(), _data);
46  for(i = 1; i <= n; i++)
47  wm_[i][j] = (acor[i] - savf[i]) * fac;
48  y[j] = yj;
49  }
50  nfe += n;
51  /*
52  Compute norm of Jacobian.
53  */
54  pdnorm = fnorm(n, wm_, ewt) / fabs(hl0);
55  /*
56  Add identity matrix.
57  */
58  for(i = 1; i <= n; i++)
59  wm_[i][i] += 1.;
60  /*
61  Do LU decomposition on P.
62  */
63  dgefa(wm_, n, ipvt, &ier);
64  if(ier != 0)
65  ierpj = 1;
66  return;
67  }
68 } /* end prja */
69 
70 
71 
72 /*
73  *corflag = 0 : corrector converged,
74 1 : step size to be reduced, redo prediction,
75 2 : corrector cannot converge, failure flag.
76 */
77 template <class Functor>
78 void LSODA::correction(const size_t neq, std::vector<double> &y, Functor &derivs,
79  size_t *corflag, double pnorm, double *del, double *delp, double *told, size_t *ncf,
80  double *rh, size_t *m, void *_data)
81 {
82  double rm = 0.0, rate = 0.0, dcon = 0.0;
83 
84  /*
85  Up to maxcor corrector iterations are taken. A convergence test is
86  made on the r.m.s. norm of each correction, weighted by the error
87  weight vector ewt. The sum of the corrections is accumulated in the
88  vector acor[i]. The yh_ array is not altered in the corrector loop.
89  */
90 
91  *m = 0;
92  *corflag = 0;
93  *del = 0.;
94 
95  for(size_t i = 1; i <= n; i++)
96  y[i] = yh_[1][i];
97 
98  derivs(tn_, ++y.begin(), ++savf.begin(), _data);
99 
100  nfe++;
101  /*
102  If indicated, the matrix P = I - h_ * el[1] * J is reevaluated and
103  preprocessed before starting the corrector iteration. ipup is set
104  to 0 as an indicator that this has been done.
105  */
106  while(1) {
107  if(*m == 0) {
108  if(ipup > 0) {
109  prja(neq, y, derivs, _data);
110  ipup = 0;
111  rc = 1.;
112  nslp = nst;
113  crate = 0.7;
114  if(ierpj != 0) {
115  corfailure(told, rh, ncf, corflag);
116  return;
117  }
118  }
119  for(size_t i = 1; i <= n; i++)
120  acor[i] = 0.;
121  } /* end if ( *m == 0 ) */
122  if(miter == 0) {
123  /*
124  In case of functional iteration, update y directly from
125  the result of the last function evaluation.
126  */
127  for(size_t i = 1; i <= n; i++) {
128  savf[i] = h_ * savf[i] - yh_[2][i];
129  y[i] = savf[i] - acor[i];
130  }
131  *del = vmnorm(n, y, ewt);
132  for(size_t i = 1; i <= n; i++) {
133  y[i] = yh_[1][i] + el[1] * savf[i];
134  acor[i] = savf[i];
135  }
136  }
137  /* end functional iteration */
138  /*
139  In the case of the chord method, compute the corrector error,
140  and solve the linear system with that as right-hand side and
141  P as coefficient matrix.
142  */
143  else {
144  for(size_t i = 1; i <= n; i++)
145  y[i] = h_ * savf[i] - (yh_[2][i] + acor[i]);
146 
147  solsy(y);
148  *del = vmnorm(n, y, ewt);
149 
150  for(size_t i = 1; i <= n; i++) {
151  acor[i] += y[i];
152  y[i] = yh_[1][i] + el[1] * acor[i];
153  }
154  } /* end chord method */
155  /*
156  Test for convergence. If *m > 0, an estimate of the convergence
157  rate constant is stored in crate, and this is used in the test.
158 
159  We first check for a change of iterates that is the size of
160  roundoff error. If this occurs, the iteration has converged, and a
161  new rate estimate is not formed.
162  In all other cases, force at least two iterations to estimate a
163  local Lipschitz constant estimate for Adams method.
164  On convergence, form pdest = local maximum Lipschitz constant
165  estimate. pdlast is the most recent nonzero estimate.
166  */
167  if(*del <= 100. * pnorm * ETA)
168  break;
169  if(*m != 0 || meth_ != 1) {
170  if(*m != 0) {
171  rm = 1024.0;
172  if(*del <= (1024. * *delp))
173  rm = *del / *delp;
174  rate = std::max(rate, rm);
175  crate = std::max(0.2 * crate, rm);
176  }
177  dcon = *del * std::min(1., 1.5 * crate) / (tesco[nq][2] * conit);
178  if(dcon <= 1.) {
179  pdest = std::max(pdest, rate / fabs(h_ * el[1]));
180  if(pdest != 0.)
181  pdlast = pdest;
182  break;
183  }
184  }
185  /*
186  The corrector iteration failed to converge.
187  If miter != 0 and the Jacobian is out of date, prja is called for
188  the next try. Otherwise the yh_ array is retracted to its values
189  before prediction, and h_ is reduced, if possible. If h_ cannot be
190  reduced or mxncf failures have occured, exit with corflag = 2.
191  */
192  (*m)++;
193  if(*m == maxcor || (*m >= 2 && *del > 2. * *delp)) {
194  if(miter == 0 || jcur == 1) {
195  corfailure(told, rh, ncf, corflag);
196  return;
197  }
198  ipup = miter;
199  /*
200  Restart corrector if Jacobian is recomputed.
201  */
202  *m = 0;
203  rate = 0.;
204  *del = 0.;
205  for(size_t i = 1; i <= n; i++)
206  y[i] = yh_[1][i];
207 
208  derivs(tn_, ++y.begin(), ++savf.begin(), _data);
209 
210  nfe++;
211  }
212  /*
213  Iterate corrector.
214  */
215  else {
216  *delp = *del;
217  derivs(tn_, ++y.begin(), ++savf.begin(), _data);
218  nfe++;
219  }
220  } /* end while */
221 } /* end correction */
222 
223 
224 template <class Functor>
226  const size_t neq, std::vector<double> &y, Functor &derivs, void *_data)
227 {
228  assert(neq + 1 == y.size());
229 
230  size_t corflag = 0, orderflag = 0;
231  size_t i = 0, i1 = 0, j = 0, m = 0, ncf = 0;
232  double del = 0.0, delp = 0.0, dsm = 0.0, dup = 0.0, exup = 0.0, r = 0.0, rh = 0.0,
233  rhup = 0.0, told = 0.0;
234  double pdh = 0.0, pnorm = 0.0;
235 
236  /*
237  stoda performs one step of the integration of an initial value
238  problem for a system of ordinary differential equations.
239  Note.. stoda is independent of the value of the iteration method
240  indicator miter, when this is != 0, and hence is independent
241  of the type of chord method used, or the Jacobian structure.
242  Communication with stoda is done with the following variables:
243 
244  jstart = an integer used for input only, with the following
245  values and meanings:
246 
247  0 perform the first step,
248  > 0 take a new step continuing from the last,
249  -1 take the next step with a new value of h_,
250  n, meth_, miter, and/or matrix parameters.
251  -2 take the next step with a new value of h_,
252  but with other inputs unchanged.
253 
254  kflag = a completion code with the following meanings:
255 
256  0 the step was successful,
257  -1 the requested error could not be achieved,
258  -2 corrector convergence could not be achieved,
259  -3 fatal error in prja or solsy.
260 
261  miter = corrector iteration method:
262 
263  0 functional iteration,
264  >0 a chord method corresponding to jacobian type jt.
265 
266  */
267  kflag = 0;
268  told = tn_;
269  ncf = 0;
270  ierpj = 0;
271  iersl = 0;
272  jcur = 0;
273  delp = 0.;
274 
275  /*
276  On the first call, the order is set to 1, and other variables are
277  initialized. rmax is the maximum ratio by which h_ can be increased
278  in a single step. It is initially 1.e4 to compensate for the small
279  initial h_, but then is normally equal to 10. If a filure occurs
280  (in corrector convergence or error test), rmax is set at 2 for
281  the next increase.
282  cfode is called to get the needed coefficients for both methods.
283  */
284  if(jstart == 0) {
285  lmax = maxord + 1;
286  nq = 1;
287  l = 2;
288  ialth = 2;
289  rmax = 10000.;
290  rc = 0.;
291  el0 = 1.;
292  crate = 0.7;
293  hold = h_;
294  nslp = 0;
295  ipup = miter;
296  /*
297  Initialize switching parameters. meth_ = 1 is assumed initially.
298  */
299  icount = 20;
300  irflag = 0;
301  pdest = 0.;
302  pdlast = 0.;
303  ratio = 5.;
304  cfode(2);
305  for(i = 1; i <= 5; i++)
306  cm2[i] = tesco[i][2] * elco[i][i + 1];
307  cfode(1);
308  for(i = 1; i <= 12; i++)
309  cm1[i] = tesco[i][2] * elco[i][i + 1];
310  resetcoeff();
311  } /* end if ( jstart == 0 ) */
312  /*
313  The following block handles preliminaries needed when jstart = -1.
314  ipup is set to miter to force a matrix update.
315  If an order increase is about to be considered ( ialth = 1 ),
316  ialth is reset to 2 to postpone consideration one more step.
317  If the caller has changed meth_, cfode is called to reset
318  the coefficients of the method.
319  If h_ is to be changed, yh_ must be rescaled.
320  If h_ or meth_ is being changed, ialth is reset to l = nq + 1
321  to prevent further changes in h_ for that many steps.
322  */
323  if(jstart == -1) {
324  ipup = miter;
325  lmax = maxord + 1;
326  if(ialth == 1)
327  ialth = 2;
328  if(meth_ != mused) {
329  cfode(meth_);
330  ialth = l;
331  resetcoeff();
332  }
333  if(h_ != hold) {
334  rh = h_ / hold;
335  h_ = hold;
336  scaleh(&rh, &pdh);
337  }
338  } /* if ( jstart == -1 ) */
339  if(jstart == -2) {
340  if(h_ != hold) {
341  rh = h_ / hold;
342  h_ = hold;
343  scaleh(&rh, &pdh);
344  }
345  } /* if ( jstart == -2 ) */
346 
347  /*
348  Prediction.
349  This section computes the predicted values by effectively
350  multiplying the yh_ array by the pascal triangle matrix.
351  rc is the ratio of new to old values of the coefficient h_ * el[1].
352  When rc differs from 1 by more than ccmax, ipup is set to miter
353  to force pjac to be called, if a jacobian is involved.
354  In any case, prja is called at least every msbp steps.
355  */
356  while(1) {
357  while(1) {
358  if(fabs(rc - 1.) > ccmax)
359  ipup = miter;
360  if(nst >= nslp + msbp)
361  ipup = miter;
362  tn_ += h_;
363  for(size_t j = nq; j >= 1; j--)
364  for(size_t i1 = j; i1 <= nq; i1++)
365  for(i = 1; i <= n; i++)
366  yh_[i1][i] += yh_[i1 + 1][i];
367 
368  pnorm = vmnorm(n, yh_[1], ewt);
369  correction(
370  neq, y, derivs, &corflag, pnorm, &del, &delp, &told, &ncf, &rh, &m, _data);
371  if(corflag == 0)
372  break;
373  if(corflag == 1) {
374  rh = std::max(rh, hmin / fabs(h_));
375  scaleh(&rh, &pdh);
376  continue;
377  }
378  if(corflag == 2) {
379  kflag = -2;
380  hold = h_;
381  jstart = 1;
382  return;
383  }
384  } /* end inner while ( corrector loop ) */
385 
386  /*
387  The corrector has converged. jcur is set to 0
388  to signal that the Jacobian involved may need updating later.
389  The local error test is done now.
390  */
391  jcur = 0;
392  if(m == 0)
393  dsm = del / tesco[nq][2];
394  if(m > 0)
395  dsm = vmnorm(n, acor, ewt) / tesco[nq][2];
396 
397  if(dsm <= 1.) {
398  /*
399  After a successful step, update the yh_ array.
400  Decrease icount by 1, and if it is -1, consider switching methods.
401  If a method switch is made, reset various parameters,
402  rescale the yh_ array, and exit. If there is no switch,
403  consider changing h_ if ialth = 1. Otherwise decrease ialth by 1.
404  If ialth is then 1 and nq < maxord, then acor is saved for
405  use in a possible order increase on the next step.
406  If a change in h_ is considered, an increase or decrease in order
407  by one is considered also. A change in h_ is made only if it is by
408  a factor of at least 1.1. If not, ialth is set to 3 to prevent
409  testing for that many steps.
410  */
411  kflag = 0;
412  nst++;
413  hu = h_;
414  nqu = nq;
415  mused = meth_;
416  for(size_t j = 1; j <= l; j++) {
417  r = el[j];
418  for(i = 1; i <= n; i++)
419  yh_[j][i] += r * acor[i];
420  }
421  icount--;
422  if(icount < 0) {
423  methodswitch(dsm, pnorm, &pdh, &rh);
424  if(meth_ != mused) {
425  rh = std::max(rh, hmin / fabs(h_));
426  scaleh(&rh, &pdh);
427  rmax = 10.;
428  endstoda();
429  break;
430  }
431  }
432  /*
433  No method switch is being made. Do the usual step/order selection.
434  */
435  ialth--;
436  if(ialth == 0) {
437  rhup = 0.;
438  if(l != lmax) {
439  for(i = 1; i <= n; i++)
440  savf[i] = acor[i] - yh_[lmax][i];
441  dup = vmnorm(n, savf, ewt) / tesco[nq][3];
442  exup = 1. / (double)(l + 1);
443  rhup = 1. / (1.4 * pow(dup, exup) + 0.0000014);
444  }
445 
446  orderswitch(&rhup, dsm, &pdh, &rh, &orderflag);
447 
448  /*
449  No change in h_ or nq.
450  */
451  if(orderflag == 0) {
452  endstoda();
453  break;
454  }
455  /*
456  h_ is changed, but not nq.
457  */
458  if(orderflag == 1) {
459  rh = std::max(rh, hmin / fabs(h_));
460  scaleh(&rh, &pdh);
461  rmax = 10.;
462  endstoda();
463  break;
464  }
465  /*
466  both nq and h_ are changed.
467  */
468  if(orderflag == 2) {
469  resetcoeff();
470  rh = std::max(rh, hmin / fabs(h_));
471  scaleh(&rh, &pdh);
472  rmax = 10.;
473  endstoda();
474  break;
475  }
476  } /* end if ( ialth == 0 ) */
477  if(ialth > 1 || l == lmax) {
478  endstoda();
479  break;
480  }
481 
482  for(size_t i = 1; i <= n; i++)
483  yh_[lmax][i] = acor[i];
484 
485  endstoda();
486  break;
487  }
488  /* end if ( dsm <= 1. ) */
489  /*
490  The error test failed. kflag keeps track of multiple failures.
491  Restore tn_ and the yh_ array to their previous values, and prepare
492  to try the step again. Compute the optimum step size for this or
493  one lower. After 2 or more failures, h_ is forced to decrease
494  by a factor of 0.2 or less.
495  */
496  else {
497  kflag--;
498  tn_ = told;
499  for(j = nq; j >= 1; j--) {
500  for(i1 = j; i1 <= nq; i1++)
501  for(i = 1; i <= n; i++)
502  yh_[i1][i] -= yh_[i1 + 1][i];
503  }
504  rmax = 2.;
505  if(fabs(h_) <= hmin * 1.00001) {
506  kflag = -1;
507  hold = h_;
508  jstart = 1;
509  break;
510  }
511  if(kflag > -3) {
512  rhup = 0.;
513  orderswitch(&rhup, dsm, &pdh, &rh, &orderflag);
514  if(orderflag == 1 || orderflag == 0) {
515  if(orderflag == 0)
516  rh = std::min(rh, 0.2);
517  rh = std::max(rh, hmin / fabs(h_));
518  scaleh(&rh, &pdh);
519  }
520  if(orderflag == 2) {
521  resetcoeff();
522  rh = std::max(rh, hmin / fabs(h_));
523  scaleh(&rh, &pdh);
524  }
525  continue;
526  }
527  /* if ( kflag > -3 ) */
528  /*
529  Control reaches this section if 3 or more failures have occurred.
530  If 10 failures have occurred, exit with kflag = -1.
531  It is assumed that the derivatives that have accumulated in the
532  yh_ array have errors of the wrong order. Hence the first
533  derivative is recomputed, and the order is set to 1. Then
534  h_ is reduced by a factor of 10, and the step is retried,
535  until it succeeds or h_ reaches hmin.
536  */
537  else {
538  if(kflag == -10) {
539  kflag = -1;
540  hold = h_;
541  jstart = 1;
542  break;
543  }
544  else {
545  rh = 0.1;
546  rh = std::max(hmin / fabs(h_), rh);
547  h_ *= rh;
548  for(i = 1; i <= n; i++)
549  y[i] = yh_[1][i];
550  derivs(tn_, ++y.begin(), ++savf.begin(), _data);
551  nfe++;
552  for(i = 1; i <= n; i++)
553  yh_[2][i] = h_ * savf[i];
554  ipup = miter;
555  ialth = 5;
556  if(nq == 1)
557  continue;
558  nq = 1;
559  l = 2;
560  resetcoeff();
561  continue;
562  }
563  } /* end else -- kflag <= -3 */
564  } /* end error failure handling */
565  } /* end outer while */
566 
567 } /* end stoda */
568 
569 
570 /*
571  The following block handles all successful returns from lsoda.
572  If itask != 1, y is loaded from yh_ and t is set accordingly.
573  *Istate is set to 2, the illegal input counter is zeroed, and the
574  optional outputs are loaded into the work arrays before returning.
575 */
576 
577 template<class AfterStep>
578 void LSODA::successreturn(AfterStep &after_step,
579  std::vector<double> &y, double *t, int itask, int ihit, double tcrit, int *istate)
580 {
581  for(size_t i = 1; i <= n; i++)
582  y[i] = yh_[1][i];
583  *t = tn_;
584  if(itask == 4 || itask == 5)
585  if(ihit)
586  *t = tcrit;
587  *istate = 2;
588  illin = 0;
589 
590  after_step(*t, ++y.begin());
591 }
592 
593 
594 
595 /*
596 c references..
597 c 1. alan c. hindmarsh, odepack, a systematized collection of ode
598 c solvers, in scientific computing, r. s. stepleman et al. (eds.),
599 c north-holland, amsterdam, 1983, pp. 55-64.
600 c 2. linda r. petzold, automatic selection of methods for solving
601 c stiff and nonstiff systems of ordinary differential equations,
602 c siam j. sci. stat. comput. 4 (1983), pp. 136-148.
603 c-----------------------------------------------------------------------
604 */
605 template <class Functor, class AfterStep>
606 void LSODA::lsoda(Functor &derivs, AfterStep &after_step, const size_t neq, std::vector<double> &y, double *t,
607  double tout, int itask, int *istate, int iopt, int jt, std::array<int, 7> &iworks,
608  std::array<double, 4> &rworks, void *_data)
609 {
610  assert(tout > *t);
611 
612  int mxstp0 = 500, mxhnl0 = 10;
613 
614  int iflag = 0, lenyh = 0, ihit = 0;
615 
616  double atoli = 0, ayi = 0, big = 0, h0 = 0, hmax = 0, hmx = 0, rh = 0, rtoli = 0,
617  tcrit = 0, tdist = 0, tnext = 0, tol = 0, tolsf = 0, tp = 0, size = 0, sum = 0,
618  w0 = 0;
619 
620  /*
621  Block a.
622  This code block is executed on every call.
623  It tests *istate and itask for legality and branches appropriately.
624  If *istate > 1 but the flag init shows that initialization has not
625  yet been done, an error return occurs.
626  If *istate = 1 and tout = t, return immediately.
627  */
628 
629  if(*istate < 1 || *istate > 3) {
630  // fprintf(stderr, "[lsoda] illegal istate = %d\n", *istate);
631  std::cerr << "[lsoda] illegal istate = " << *istate << std::endl;
632  terminate(istate);
633  return;
634  }
635  if(itask < 1 || itask > 5) {
636  fprintf(stderr, "[lsoda] illegal itask = %d\n", itask);
637  terminate(istate);
638  return;
639  }
640  if(init == 0 && (*istate == 2 || *istate == 3)) {
641  fprintf(stderr, "[lsoda] istate > 1 but lsoda not initialized\n");
642  terminate(istate);
643  return;
644  }
645 
646  /*
647  Block b.
648  The next code block is executed for the initial call ( *istate = 1 ),
649  or for a continuation call with parameter changes ( *istate = 3 ).
650  It contains checking of all inputs and various initializations.
651 
652  First check legality of the non-optional inputs neq, itol, iopt,
653  jt, ml, and mu.
654  */
655 
656  if(*istate == 1 || *istate == 3) {
657  ntrep = 0;
658  if(neq <= 0) {
659  std::cerr << "[lsoda] neq = " << neq << " is less than 1." << std::endl;
660  terminate(istate);
661  return;
662  }
663  if(*istate == 3 && neq > n) {
664  std::cerr << "[lsoda] istate = 3 and neq increased" << std::endl;
665  terminate(istate);
666  return;
667  }
668  n = neq;
669  if(itol_ < 1 || itol_ > 4) {
670  std::cerr << "[lsoda] itol = " << itol_ << " illegal" << std::endl;
671  terminate(istate);
672  return;
673  }
674  if(iopt < 0 || iopt > 1) {
675  std::cerr << "[lsoda] iopt = " << iopt << " illegal" << std::endl;
676  terminate(istate);
677  return;
678  }
679  if(jt == 3 || jt < 1 || jt > 5) {
680  std::cerr << "[lsoda] jt = " << jt << " illegal" << std::endl;
681  terminate(istate);
682  return;
683  }
684  jtyp = jt;
685  if(jt > 2) {
686  ml = iworks[0];
687  mu = iworks[1];
688  if(ml >= n) {
689  std::cerr << "[lsoda] ml = " << ml << " not between 1 and neq" << std::endl;
690  terminate(istate);
691  return;
692  }
693  if(mu >= n) {
694  std::cerr << "[lsoda] mu = " << mu << " not between 1 and neq" << std::endl;
695  terminate(istate);
696  return;
697  }
698  }
699 
700  /* Next process and check the optional inpus. */
701  /* Default options. */
702  if(iopt == 0) {
703  ixpr = 0;
704  mxstep = mxstp0;
705  mxhnil = mxhnl0;
706  hmxi = 0.;
707  hmin = 0.;
708  if(*istate == 1) {
709  h0 = 0.;
710  mxordn = mord[0];
711  mxords = mord[1];
712  }
713  }
714  /* end if ( iopt == 0 ) */
715  /* Optional inputs. */
716  else /* if ( iopt = 1 ) */
717  {
718  ixpr = iworks[2];
719  if(ixpr > 1) {
720  std::cerr << "[lsoda] ixpr = " << ixpr << " is illegal" << std::endl;
721  terminate(istate);
722  return;
723  }
724 
725  mxstep = iworks[3];
726  if(mxstep == 0)
727  mxstep = mxstp0;
728  mxhnil = iworks[4];
729 
730  if(*istate == 1) {
731  h0 = rworks[1];
732  mxordn = iworks[5];
733 
734  if(mxordn == 0)
735  mxordn = 100;
736 
737  mxordn = std::min(mxordn, mord[0]);
738  mxords = iworks[6];
739 
740  // if mxords is not given use 100.
741  if(mxords == 0)
742  mxords = 100;
743 
744  mxords = std::min(mxords, mord[1]);
745 
746  if((tout - *t) * h0 < 0.) {
747  std::cerr << "[lsoda] tout = " << tout << " behind t = " << *t
748  << ". integration direction is given by " << h0 << std::endl;
749  terminate(istate);
750  return;
751  }
752  } /* end if ( *istate == 1 ) */
753  hmax = rworks[2];
754  if(hmax < 0.) {
755  std::cerr << "[lsoda] hmax < 0." << std::endl;
756  terminate(istate);
757  return;
758  }
759  hmxi = 0.;
760  if(hmax > 0)
761  hmxi = 1. / hmax;
762 
763  hmin = rworks[3];
764  if(hmin < 0.) {
765  std::cerr << "[lsoda] hmin < 0." << std::endl;
766  terminate(istate);
767  return;
768  }
769  } /* end else */ /* end iopt = 1 */
770  } /* end if ( *istate == 1 || *istate == 3 ) */
771  /*
772  If *istate = 1, meth_ is initialized to 1.
773 
774  Also allocate memory for yh_, wm_, ewt, savf, acor, ipvt.
775  */
776  if(*istate == 1) {
777  /*
778  If memory were not freed, *istate = 3 need not reallocate memory.
779  Hence this section is not executed by *istate = 3.
780  */
781  sqrteta = sqrt(ETA);
782  meth_ = 1;
783 
784  nyh = n;
785  lenyh = 1 + std::max(mxordn, mxords);
786  resize_system(nyh, lenyh);
787 
789  //yh_.clear(); yh_.resize(lenyh + 1, std::vector<double>(nyh + 1, 0.0));
790  //wm_.clear(); wm_.resize(nyh + 1, std::vector<double>(nyh + 1, 0.0));
791  //ewt.resize(1 + nyh, 0);
792  //savf.resize(1 + nyh, 0);
793  //acor.resize(nyh + 1, 0.0);
794  //ipvt.resize(nyh + 1, 0.0);
795  }
796  /*
797  Check rtol and atol for legality.
798  */
799  if(*istate == 1 || *istate == 3) {
800  rtoli = rtol_[1];
801  atoli = atol_[1];
802  for(size_t i = 1; i <= n; i++) {
803  if(itol_ >= 3)
804  rtoli = rtol_[i];
805  if(itol_ == 2 || itol_ == 4)
806  atoli = atol_[i];
807  if(rtoli < 0.) {
808  fprintf(stderr, "[lsoda] rtol = %g is less than 0.\n", rtoli);
809  terminate(istate);
810  return;
811  }
812  if(atoli < 0.) {
813  fprintf(stderr, "[lsoda] atol = %g is less than 0.\n", atoli);
814  terminate(istate);
815  return;
816  }
817  } /* end for */
818  } /* end if ( *istate == 1 || *istate == 3 ) */
819 
820  /* If *istate = 3, set flag to signal parameter changes to stoda. */
821  if(*istate == 3) {
822  jstart = -1;
823  }
824  /*
825  Block c.
826  The next block is for the initial call only ( *istate = 1 ).
827  It contains all remaining initializations, the initial call to f,
828  and the calculation of the initial step size.
829  The error weights in ewt are inverted after being loaded.
830  */
831  if(*istate == 1) {
832  tn_ = *t;
833  tsw = *t;
834  maxord = mxordn;
835  if(itask == 4 || itask == 5) {
836  tcrit = rworks[0];
837  if((tcrit - tout) * (tout - *t) < 0.) {
838  fprintf(stderr, "[lsoda] itask = 4 or 5 and tcrit behind tout\n");
839  terminate(istate);
840  return;
841  }
842  if(h0 != 0. && (*t + h0 - tcrit) * h0 > 0.)
843  h0 = tcrit - *t;
844  }
845 
846  jstart = 0;
847  nhnil = 0;
848  nst = 0;
849  nje = 0;
850  nslast = 0;
851  hu = 0.;
852  nqu = 0;
853  mused = 0;
854  miter = 0;
855  ccmax = 0.3;
856  maxcor = 3;
857  msbp = 20;
858  mxncf = 10;
859 
860  /* Initial call to f. */
861  assert((int)yh_.size() == lenyh + 1);
862  assert(yh_[0].size() == nyh + 1);
863 
864  derivs(*t, ++y.begin(), ++yh_[2].begin(), _data);
865  nfe = 1;
866 
867  /* Load the initial value vector in yh_. */
868  for(size_t i = 1; i <= n; i++)
869  yh_[1][i] = y[i];
870 
871  /* Load and invert the ewt array. ( h_ is temporarily set to 1. ) */
872  nq = 1;
873  h_ = 1.;
874  ewset(y);
875  for(size_t i = 1; i <= n; i++) {
876  if(ewt[i] <= 0.) {
877  std::cerr << "[lsoda] ewt[" << i << "] = " << ewt[i] << " <= 0.\n" << std::endl;
878  terminate2(y, t);
879  return;
880  }
881  ewt[i] = 1. / ewt[i];
882  }
883 
884  /*
885  The coding below computes the step size, h0, to be attempted on the
886  first step, unless the user has supplied a value for this.
887  First check that tout - *t differs significantly from zero.
888  A scalar tolerance quantity tol is computed, as max(rtol[i])
889  if this is positive, or max(atol[i]/fabs(y[i])) otherwise, adjusted
890  so as to be between 100*ETA and 0.001.
891  Then the computed value h0 is given by
892 
893  h0^(-2) = 1. / ( tol * w0^2 ) + tol * ( norm(f) )^2
894 
895  where w0 = max( fabs(*t), fabs(tout) ),
896  f = the initial value of the vector f(t,y), and
897  norm() = the weighted vector norm used throughout, given by
898  the vmnorm function routine, and weighted by the
899  tolerances initially loaded into the ewt array.
900 
901  The sign of h0 is inferred from the initial values of tout and *t.
902  fabs(h0) is made < fabs(tout-*t) in any case.
903  */
904  if(h0 == 0.) {
905  tdist = fabs(tout - *t);
906  w0 = std::max(fabs(*t), fabs(tout));
907  if(tdist < 2. * ETA * w0) {
908  fprintf(stderr, "[lsoda] tout too close to t to start integration\n ");
909  terminate(istate);
910  return;
911  }
912  tol = rtol_[1];
913  if(itol_ > 2) {
914  for(size_t i = 2; i <= n; i++)
915  tol = std::max(tol, rtol_[i]);
916  }
917  if(tol <= 0.) {
918  atoli = atol_[1];
919  for(size_t i = 1; i <= n; i++) {
920  if(itol_ == 2 || itol_ == 4)
921  atoli = atol_[i];
922  ayi = fabs(y[i]);
923  if(ayi != 0.)
924  tol = std::max(tol, atoli / ayi);
925  }
926  }
927  tol = std::max(tol, 100. * ETA);
928  tol = std::min(tol, 0.001);
929  sum = vmnorm(n, yh_[2], ewt);
930  sum = 1. / (tol * w0 * w0) + tol * sum * sum;
931  h0 = 1. / sqrt(sum);
932  h0 = std::min(h0, tdist);
933  h0 = h0 * ((tout - *t >= 0.) ? 1. : -1.);
934  } /* end if ( h0 == 0. ) */
935  /*
936  Adjust h0 if necessary to meet hmax bound.
937  */
938  rh = fabs(h0) * hmxi;
939  if(rh > 1.)
940  h0 /= rh;
941 
942  /*
943  Load h_ with h0 and scale yh_[2] by h0.
944  */
945  h_ = h0;
946  for(size_t i = 1; i <= n; i++)
947  yh_[2][i] *= h0;
948  } /* if ( *istate == 1 ) */
949  /*
950  Block d.
951  The next code block is for continuation calls only ( *istate = 2 or 3 )
952  and is to check stop conditions before taking a step.
953  */
954  if(*istate == 2 || *istate == 3) {
955  nslast = nst;
956  switch(itask) {
957  case 1:
958  if((tn_ - tout) * h_ >= 0.) {
959  intdy(tout, 0, y, &iflag);
960  if(iflag != 0) {
961  fprintf(stderr,
962  "[lsoda] trouble from intdy, itask = %d, tout = %g\n", itask,
963  tout);
964  terminate(istate);
965  return;
966  }
967  *t = tout;
968  *istate = 2;
969  illin = 0;
970  return;
971  }
972  break;
973  case 2:
974  break;
975  case 3:
976  tp = tn_ - hu * (1. + 100. * ETA);
977  if((tp - tout) * h_ > 0.) {
978  fprintf(
979  stderr, "[lsoda] itask = %d and tout behind tcur - hu\n", itask);
980  terminate(istate);
981  return;
982  }
983  if((tn_ - tout) * h_ < 0.)
984  break;
985  successreturn(after_step, y, t, itask, ihit, tcrit, istate);
986  return;
987  case 4:
988  tcrit = rworks[0];
989  if((tn_ - tcrit) * h_ > 0.) {
990  fprintf(stderr, "[lsoda] itask = 4 or 5 and tcrit behind tcur\n");
991  terminate(istate);
992  return;
993  }
994  if((tcrit - tout) * h_ < 0.) {
995  fprintf(stderr, "[lsoda] itask = 4 or 5 and tcrit behind tout\n");
996  terminate(istate);
997  return;
998  }
999  if((tn_ - tout) * h_ >= 0.) {
1000  intdy(tout, 0, y, &iflag);
1001  if(iflag != 0) {
1002  fprintf(stderr,
1003  "[lsoda] trouble from intdy, itask = %d, tout = %g\n", itask,
1004  tout);
1005  terminate(istate);
1006  return;
1007  }
1008  *t = tout;
1009  *istate = 2;
1010  illin = 0;
1011  after_step(*t, ++y.begin());
1012  return;
1013  }
1014  break;
1015  case 5:
1016  if(itask == 5) {
1017  tcrit = rworks[0];
1018  if((tn_ - tcrit) * h_ > 0.) {
1019  fprintf(stderr, "[lsoda] itask = 4 or 5 and tcrit behind tcur\n");
1020  terminate(istate);
1021  return;
1022  }
1023  }
1024  hmx = fabs(tn_) + fabs(h_);
1025  ihit = fabs(tn_ - tcrit) <= (100. * ETA * hmx);
1026  if(ihit) {
1027  *t = tcrit;
1028  successreturn(after_step, y, t, itask, ihit, tcrit, istate);
1029  return;
1030  }
1031  tnext = tn_ + h_ * (1. + 4. * ETA);
1032  if((tnext - tcrit) * h_ <= 0.)
1033  break;
1034  h_ = (tcrit - tn_) * (1. - 4. * ETA);
1035  if(*istate == 2)
1036  jstart = -2;
1037  break;
1038  } /* end switch */
1039  } /* end if ( *istate == 2 || *istate == 3 ) */
1040  /*
1041  Block e.
1042  The next block is normally executed for all calls and contains
1043  the call to the one-step core integrator stoda.
1044 
1045  This is a looping point for the integration steps.
1046 
1047  First check for too many steps being taken, update ewt ( if not at
1048  start of problem). Check for too much accuracy being requested, and
1049  check for h_ below the roundoff level in *t.
1050  */
1051  while(1) {
1052  if(*istate != 1 || nst != 0) {
1053  if((nst - nslast) >= mxstep) {
1054  std::cerr << "[lsoda] " << mxstep << " steps taken before reaching tout"
1055  << std::endl;
1056  *istate = -1;
1057  terminate2(y, t);
1058  return;
1059  }
1060 
1061  ewset(yh_[1]);
1062  for(size_t i = 1; i <= n; i++) {
1063  if(ewt[i] <= 0.) {
1064  std::cerr << "[lsoda] ewt[" << i << "] = " << ewt[i] << " <= 0." << std::endl;
1065  *istate = -6;
1066  terminate2(y, t);
1067  return;
1068  }
1069  ewt[i] = 1. / ewt[i];
1070  }
1071  }
1072  tolsf = ETA * vmnorm(n, yh_[1], ewt);
1073  if(tolsf > 0.01) {
1074  tolsf = tolsf * 200.;
1075  if(nst == 0) {
1076  fprintf(stderr, "lsoda -- at start of problem, too much accuracy\n");
1077  fprintf(stderr, " requested for precision of machine,\n");
1078  fprintf(stderr, " suggested scaling factor = %g\n", tolsf);
1079  terminate(istate);
1080  return;
1081  }
1082  fprintf(stderr, "lsoda -- at t = %g, too much accuracy requested\n", *t);
1083  fprintf(stderr, " for precision of machine, suggested\n");
1084  fprintf(stderr, " scaling factor = %g\n", tolsf);
1085  *istate = -2;
1086  terminate2(y, t);
1087  return;
1088  }
1089 
1090  if((tn_ + h_) == tn_) {
1091  nhnil++;
1092  if(nhnil <= mxhnil) {
1093  fprintf(stderr, "lsoda -- warning..internal t = %g and h_ = %g are\n",
1094  tn_, h_);
1095  fprintf(stderr,
1096  " such that in the machine, t + h_ = t on the next step\n");
1097  fprintf(stderr, " solver will continue anyway.\n");
1098  if(nhnil == mxhnil) {
1099  std::cerr << "lsoda -- above warning has been issued " << nhnil
1100  << " times, " << std::endl
1101  << " it will not be issued again for this problem" << std::endl;
1102  }
1103  }
1104  }
1105 
1106  /* Call stoda */
1107  stoda(neq, y, derivs, _data);
1108  if(kflag == 0) {
1109  /*
1110  Block f.
1111  The following block handles the case of a successful return from the
1112  core integrator ( kflag = 0 ).
1113  If a method switch was just made, record tsw, reset maxord,
1114  set jstart to -1 to signal stoda to complete the switch,
1115  and do extra printing of data if ixpr = 1.
1116  Then, in any case, check for stop conditions.
1117  */
1118  if (tn_ < tout) after_step(tn_, ++y.begin());
1119 
1120  init = 1;
1121  if(meth_ != mused) {
1122  tsw = tn_;
1123  maxord = mxordn;
1124  if(meth_ == 2)
1125  maxord = mxords;
1126  jstart = -1;
1127  if(ixpr) {
1128  if(meth_ == 2)
1129  std::cerr << "[lsoda] a switch to the stiff method has occurred "
1130  << std::endl;
1131  if(meth_ == 1)
1132  std::cerr << "[lsoda] a switch to the nonstiff method has occurred"
1133  << std::endl;
1134  }
1135  } /* end if ( meth_ != mused ) */
1136  /*
1137  itask = 1.
1138  If tout has been reached, interpolate.
1139  */
1140  if(1 == itask) {
1141  if((tn_ - tout) * h_ < 0.)
1142  continue;
1143 
1144  intdy(tout, 0, y, &iflag);
1145  *t = tout;
1146  *istate = 2;
1147  illin = 0;
1148  after_step(*t, ++y.begin());
1149  return;
1150  }
1151  /*
1152  itask = 2.
1153  */
1154  if(itask == 2) {
1155  successreturn(after_step, y, t, itask, ihit, tcrit, istate);
1156  return;
1157  }
1158  /*
1159  itask = 3.
1160  Jump to exit if tout was reached.
1161  */
1162  if(itask == 3) {
1163  if((tn_ - tout) * h_ >= 0.) {
1164  successreturn(after_step, y, t, itask, ihit, tcrit, istate);
1165  return;
1166  }
1167  continue;
1168  }
1169  /*
1170  itask = 4.
1171  See if tout or tcrit was reached. Adjust h_ if necessary.
1172  */
1173  if(itask == 4) {
1174  if((tn_ - tout) * h_ >= 0.) {
1175  intdy(tout, 0, y, &iflag);
1176  *t = tout;
1177  *istate = 2;
1178  illin = 0;
1179  after_step(*t, ++y.begin());
1180  return;
1181  }
1182  else {
1183  hmx = fabs(tn_) + fabs(h_);
1184  ihit = fabs(tn_ - tcrit) <= (100. * ETA * hmx);
1185  if(ihit) {
1186  successreturn(after_step, y, t, itask, ihit, tcrit, istate);
1187  return;
1188  }
1189  tnext = tn_ + h_ * (1. + 4. * ETA);
1190  if((tnext - tcrit) * h_ <= 0.)
1191  continue;
1192  h_ = (tcrit - tn_) * (1. - 4. * ETA);
1193  jstart = -2;
1194  continue;
1195  }
1196  } /* end if ( itask == 4 ) */
1197  /*
1198  itask = 5.
1199  See if tcrit was reached and jump to exit.
1200  */
1201  if(itask == 5) {
1202  hmx = fabs(tn_) + fabs(h_);
1203  ihit = fabs(tn_ - tcrit) <= (100. * ETA * hmx);
1204  successreturn(after_step, y, t, itask, ihit, tcrit, istate);
1205  return;
1206  }
1207 
1208  } /* end if ( kflag == 0 ) */
1209  /*
1210  kflag = -1, error test failed repeatedly or with fabs(h_) = hmin.
1211  kflag = -2, convergence failed repeatedly or with fabs(h_) = hmin.
1212  */
1213  if(kflag == -1 || kflag == -2) {
1214  fprintf(stderr, "lsoda -- at t = %g and step size h_ = %g, the\n", tn_, h_);
1215  if(kflag == -1) {
1216  fprintf(stderr, " error test failed repeatedly or\n");
1217  fprintf(stderr, " with fabs(h_) = hmin\n");
1218  *istate = -4;
1219  }
1220  if(kflag == -2) {
1221  fprintf(stderr, " corrector convergence failed repeatedly or\n");
1222  fprintf(stderr, " with fabs(h_) = hmin\n");
1223  *istate = -5;
1224  }
1225  big = 0.;
1226  imxer = 1;
1227  for(size_t i = 1; i <= n; i++) {
1228  size = fabs(acor[i]) * ewt[i];
1229  if(big < size) {
1230  big = size;
1231  imxer = i;
1232  }
1233  }
1234  terminate2(y, t);
1235  return;
1236  } /* end if ( kflag == -1 || kflag == -2 ) */
1237  } /* end while */
1238 } /* end lsoda */
1239 
1240 
1241 /* --------------------------------------------------------------------------*/
1255 /* ----------------------------------------------------------------------------*/
1256 template <class Functor, class AfterStep>
1257 void LSODA::lsoda_update(Functor &derivs, AfterStep &after_step, const size_t neq, std::vector<double> &y,
1258  /*std::vector<double> &yout_notused,*/ double *t, const double tout, /*int *istate,*/ void *_data,
1259  double rtol, double atol)
1260 {
1261  std::array<int, 7> iworks = {{0}};
1262  std::array<double, 4> rworks = {{0.0}};
1263 
1264  int itask, iopt, jt;
1265 
1266  // cout << "Debug : rtol " << rtol << ". atol " << atol << std::endl;
1267 
1268  itask = 1;
1269  iopt = 0;
1270  jt = 2;
1271 
1272  yout.resize(neq + 1);
1273 
1274  // Set the tolerance. We should do it only once.
1275  rtol_.resize(neq + 1, rtol);
1276  atol_.resize(neq + 1, atol);
1277  rtol_[0] = 0;
1278  atol_[0] = 0;
1279 
1280  // Fill-in values.
1281  for(size_t i = 1; i <= neq; i++)
1282  yout[i] = y[i - 1];
1283 
1284  lsoda(derivs, after_step, neq, yout, t, tout, itask, &iState, iopt, jt, iworks, rworks, _data);
1285 
1286  for (int i=0; i<y.size(); ++i) y[i] = yout[i+1];
1287 }
1288 
1289 
1290 
size_t nje
Definition: lsoda.h:137
size_t nyh
Definition: lsoda.h:139
void orderswitch(double *rhup, double dsm, double *pdh, double *rh, size_t *orderflag)
Definition: lsoda.cpp:716
size_t mxstep
Definition: lsoda.h:138
double hu
Definition: lsoda.h:142
size_t nst
Definition: lsoda.h:137
double ETA
Definition: lsoda.h:112
int iState
Definition: lsoda.h:165
double pdlast
Definition: lsoda.h:148
size_t mu
Definition: lsoda.h:114
double ratio
Definition: lsoda.h:148
std::vector< double > savf
Definition: lsoda.h:152
size_t ipup
Definition: lsoda.h:146
std::array< std::array< double, 14 >, 13 > elco
Definition: lsoda.h:127
void prja(const size_t neq, std::vector< double > &y, Functor &derivs, void *_data)
Definition: lsoda.tpp:6
double crate
Definition: lsoda.h:144
double rc
Definition: lsoda.h:142
size_t miter
Definition: lsoda.h:130
void terminate(int *istate)
Definition: lsoda.cpp:217
std::vector< std::vector< double > > yh_
Definition: lsoda.h:154
size_t jcur
Definition: lsoda.h:130
double el0
Definition: lsoda.h:141
double ccmax
Definition: lsoda.h:141
std::vector< std::vector< double > > wm_
Definition: lsoda.h:155
double conit
Definition: lsoda.h:144
double tn_
Definition: lsoda.h:142
void ewset(const std::vector< double > &ycur)
Definition: lsoda.cpp:241
void scaleh(double *rh, double *pdh)
Definition: lsoda.cpp:458
size_t meth_
Definition: lsoda.h:135
double hmin
Definition: lsoda.h:142
size_t ierpj
Definition: lsoda.h:130
size_t iersl
Definition: lsoda.h:130
size_t nfe
Definition: lsoda.h:137
void correction(const size_t neq, std::vector< double > &y, Functor &derivs, size_t *corflag, double pnorm, double *del, double *delp, double *told, size_t *ncf, double *rh, size_t *m, void *_data)
Definition: lsoda.tpp:78
void solsy(std::vector< double > &y)
Definition: lsoda.cpp:560
std::vector< double > ewt
Definition: lsoda.h:151
size_t nqu
Definition: lsoda.h:137
size_t n
Definition: lsoda.h:137
double vmnorm(const size_t n, const std::vector< double > &v, const std::vector< double > &w)
Definition: lsoda.cpp:501
void lsoda_update(Functor &derivs, AfterStep &after_step, const size_t neq, std::vector< double > &y, double *t, const double tout, void *const _data, double rtol=1e-6, double atol=1e-6)
Definition: lsoda.tpp:1257
int irflag
Definition: lsoda.h:149
double pdest
Definition: lsoda.h:148
size_t ml
Definition: lsoda.h:114
size_t ialth
Definition: lsoda.h:146
double fnorm(int n, const std::vector< std::vector< double >> &a, const std::vector< double > &w)
Definition: lsoda.cpp:509
void successreturn(AfterStep &after_step, std::vector< double > &y, double *t, int itask, int ihit, double tcrit, int *istate)
Definition: lsoda.tpp:578
int icount
Definition: lsoda.h:149
std::array< std::array< double, 4 >, 13 > tesco
Definition: lsoda.h:128
std::array< size_t, 3 > mord
Definition: lsoda.h:120
std::array< double, 13 > cm1
Definition: lsoda.h:124
int itol_
Definition: lsoda.h:160
size_t ntrep
Definition: lsoda.h:139
size_t mused
Definition: lsoda.h:134
int jstart
Definition: lsoda.h:132
size_t nslp
Definition: lsoda.h:147
void cfode(int meth_)
Definition: lsoda.cpp:331
size_t illin
Definition: lsoda.h:130
size_t ixpr
Definition: lsoda.h:134
int kflag
Definition: lsoda.h:132
double h_
Definition: lsoda.h:141
size_t nslast
Definition: lsoda.h:139
double pdnorm
Definition: lsoda.h:143
size_t nq
Definition: lsoda.h:137
void terminate2(std::vector< double > &y, double *t)
Definition: lsoda.cpp:230
void intdy(double t, int k, std::vector< double > &dky, int *iflag)
Definition: lsoda.cpp:286
void corfailure(double *told, double *rh, size_t *ncf, size_t *corflag)
Definition: lsoda.cpp:532
void endstoda(void)
Definition: lsoda.cpp:694
size_t maxcor
Definition: lsoda.h:130
std::vector< double > acor
Definition: lsoda.h:153
size_t mxhnil
Definition: lsoda.h:138
double tsw
Definition: lsoda.h:143
double sqrteta
Definition: lsoda.h:115
double hmxi
Definition: lsoda.h:142
size_t mxordn
Definition: lsoda.h:134
size_t init
Definition: lsoda.h:130
void resetcoeff(void)
Definition: lsoda.cpp:815
void resize_system(int nyh, int lenyh)
Definition: lsoda.cpp:837
void methodswitch(double dsm, double pnorm, double *pdh, double *rh)
Definition: lsoda.cpp:572
size_t lmax
Definition: lsoda.h:146
size_t nhnil
Definition: lsoda.h:139
size_t msbp
Definition: lsoda.h:130
void lsoda(Functor &derivs, AfterStep &after_step, const size_t neq, std::vector< double > &y, double *t, double tout, int itask, int *istate, int iopt, int jt, std::array< int, 7 > &iworks, std::array< double, 4 > &rworks, void *_data)
Definition: lsoda.tpp:606
std::vector< double > atol_
Definition: lsoda.h:162
double hold
Definition: lsoda.h:144
size_t l
Definition: lsoda.h:130
void dgefa(std::vector< std::vector< double >> &a, const size_t n, std::vector< int > &ipvt, size_t *const info)
Definition: lsoda.cpp:161
std::vector< int > ipvt
Definition: lsoda.h:157
void stoda(const size_t neq, std::vector< double > &y, Functor &derivs, void *_data)
Definition: lsoda.tpp:225
size_t maxord
Definition: lsoda.h:130
std::vector< double > yout
Definition: lsoda.h:167
size_t mxncf
Definition: lsoda.h:130
size_t imxer
Definition: lsoda.h:114
size_t mxords
Definition: lsoda.h:134
std::array< double, 6 > cm2
Definition: lsoda.h:125
size_t jtyp
Definition: lsoda.h:134
std::vector< double > rtol_
Definition: lsoda.h:161
std::array< double, 14 > el
Definition: lsoda.h:123
double rmax
Definition: lsoda.h:144