26 #include "cvodes_interface.hpp"
27 #include "casadi/core/casadi_misc.hpp"
29 #define THROWING(fcn, ...) \
30 cvodes_error(CASADI_STR(fcn), fcn(__VA_ARGS__))
35 int CASADI_INTEGRATOR_CVODES_EXPORT
38 plugin->name =
"cvodes";
40 plugin->version = CASADI_VERSION;
52 double t0,
const std::vector<double>& tout) :
SundialsInterface(name, dae, t0, tout) {
61 {{
"linear_multistep_method",
63 "Integrator scheme: BDF|adams"}},
64 {
"nonlinear_solver_iteration",
66 "Nonlinear solver type: NEWTON|functional"}},
69 "Min step size [default: 0/0.0]"}},
72 "Calculate all right hand sides of the sensitivity equations at once"}},
73 {
"always_recalculate_jacobian",
75 "Recalculate Jacobian before factorizations, even if Jacobian is current [default: true]"}}
86 std::string linear_multistep_method =
"bdf";
87 std::string nonlinear_solver_iteration =
"newton";
92 for (
auto&& op : opts) {
93 if (op.first==
"linear_multistep_method") {
94 linear_multistep_method = op.second.to_string();
95 }
else if (op.first==
"min_step_size") {
97 }
else if (op.first==
"nonlinear_solver_iteration") {
98 nonlinear_solver_iteration = op.second.to_string();
99 }
else if (op.first==
"always_recalculate_jacobian") {
105 casadi_assert(
nz_==0 &&
nrz_==0,
106 "CVODES does not support algebraic variables");
108 if (linear_multistep_method==
"adams") {
110 }
else if (linear_multistep_method==
"bdf") {
113 casadi_error(
"Unknown linear multistep method: " + linear_multistep_method);
116 if (nonlinear_solver_iteration==
"newton") {
118 }
else if (nonlinear_solver_iteration==
"functional") {
119 iter_ = CV_FUNCTIONAL;
121 casadi_error(
"Unknown nonlinear solver iteration: " + nonlinear_solver_iteration);
135 casadi_assert(m->mem!=
nullptr,
"CVodeCreate: Creation failed");
138 THROWING(CVodeSetErrHandlerFn, m->mem,
ehfun, m);
141 THROWING(CVodeSetUserData, m->mem, m);
145 THROWING(CVodeInit, m->mem,
rhsF, t0, m->v_xz);
149 THROWING(CVodeSVtolerances, m->mem,
reltol_, m->abstolv);
158 if (
step0_!=0) THROWING(CVodeSetInitStep, m->mem,
step0_);
175 CVodeMem cv_mem =
static_cast<CVodeMem
>(m->mem);
179 cv_mem->cv_setupNonNull = TRUE;
182 casadi_int pretype =
use_precon_ ? PREC_LEFT : PREC_NONE;
189 THROWING(CVSpilsSetJacTimesVecFn, m->mem,
jtimesF);
196 THROWING(CVodeQuadInit, m->mem,
rhsQF, m->v_q);
200 THROWING(CVodeSetQuadErrCon, m->mem,
true);
214 m->first_callB =
true;
220 casadi_assert_dev(user_data);
221 auto m =
to_mem(user_data);
223 if (s.calc_daeF(m, t, NV_DATA_S(x),
nullptr, NV_DATA_S(xdot),
nullptr))
return 1;
225 }
catch(std::exception& e) {
226 uerr() <<
"rhs failed: " << e.what() << std::endl;
240 if (first_call ||
ne_ > 0) {
242 THROWING(CVodeReInit, m->mem, m->t, m->v_xz);
246 THROWING(CVodeQuadReInit, m->mem, m->v_q);
254 THROWING(CVodeAdjReInit, m->mem);
265 if (m->t_stop >= m->tcur) {
266 THROWING(CVodeSetStopTime, m->mem, m->t_stop);
270 const double ttol = 1e-9;
271 if (fabs(m->t - m->t_next) >= ttol) {
276 THROWING(CVodeF, m->mem, m->t_next, m->v_xz, &tret, CV_NORMAL, &m->ncheck);
279 THROWING(CVode, m->mem, m->t_next, m->v_xz, &tret, CV_NORMAL);
284 THROWING(CVodeGetQuad, m->mem, &tret, m->v_q);
293 THROWING(CVodeGetIntegratorStats, m->mem, &m->nsteps, &m->nfevals, &m->nlinsetups,
294 &m->netfails, &m->qlast, &m->qcur, &m->hinused,
295 &m->hlast, &m->hcur, &m->tcur);
296 THROWING(CVodeGetNonlinSolvStats, m->mem, &m->nniters, &m->nncfails);
302 const double* adj_x,
const double* adj_z,
const double* adj_q)
const {
308 if (m->first_callB) {
310 THROWING(CVodeCreateB, m->mem,
lmm_,
iter_, &m->whichB);
311 THROWING(CVodeInitB, m->mem, m->whichB,
rhsB, m->t, m->v_adj_xz);
312 THROWING(CVodeSStolerancesB, m->mem, m->whichB,
reltol_,
abstol_);
313 THROWING(CVodeSetUserDataB, m->mem, m->whichB, m);
316 CVodeMem cv_mem =
static_cast<CVodeMem
>(m->mem);
317 CVadjMem ca_mem = cv_mem->cv_adj_mem;
318 CVodeBMem cvB_mem = ca_mem->cvB_mem;
319 cvB_mem->cv_lmem = m;
320 cvB_mem->cv_mem->cv_lmem = m;
321 cvB_mem->cv_mem->cv_lsetup =
lsetupB;
322 cvB_mem->cv_mem->cv_lsolve =
lsolveB;
323 cvB_mem->cv_mem->cv_setupNonNull = TRUE;
326 casadi_int pretype =
use_precon_ ? PREC_LEFT : PREC_NONE;
333 THROWING(CVSpilsSetJacTimesVecFnB, m->mem, m->whichB,
jtimesB);
338 THROWING(CVodeQuadInitB, m->mem, m->whichB,
rhsQB, m->v_adj_pu);
340 THROWING(CVodeSetQuadErrConB, m->mem, m->whichB,
true);
341 THROWING(CVodeQuadSStolerancesB, m->mem, m->whichB,
reltol_,
abstol_);
345 m->first_callB =
false;
351 THROWING(CVodeReInitB, m->mem, m->whichB, m->t, m->v_adj_xz);
352 THROWING(CVodeQuadReInitB, m->mem, m->whichB, m->v_adj_pu);
357 double* adj_x,
double* adj_p,
double* adj_u)
const {
364 if (m->t_next < m->t) {
365 THROWING(CVodeB, m->mem, m->t_next, CV_NORMAL);
367 THROWING(CVodeGetB, m->mem, m->whichB, &tret, m->v_adj_xz);
369 THROWING(CVodeGetQuadB, m->mem, m->whichB, &tret, m->v_adj_pu);
379 CVodeMem cv_mem =
static_cast<CVodeMem
>(m->mem);
380 CVadjMem ca_mem = cv_mem->cv_adj_mem;
381 CVodeBMem cvB_mem = ca_mem->cvB_mem;
382 THROWING(CVodeGetIntegratorStats, cvB_mem->cv_mem, &m->nstepsB,
383 &m->nfevalsB, &m->nlinsetupsB, &m->netfailsB, &m->qlastB,
384 &m->qcurB, &m->hinusedB, &m->hlastB, &m->hcurB, &m->tcurB);
385 THROWING(CVodeGetNonlinSolvStats, cvB_mem->cv_mem, &m->nnitersB, &m->nncfailsB);
393 if (flag>=CV_SUCCESS)
return;
395 char* flagname = CVodeGetReturnFlagName(flag);
396 std::stringstream ss;
397 ss << module <<
" returned \"" << flagname <<
"\". Consult CVODES documentation.";
399 casadi_error(ss.str());
403 char *msg,
void *user_data) {
405 casadi_assert_dev(user_data);
406 auto m =
to_mem(user_data);
408 if (!s.disable_internal_warnings_) {
409 uerr() << msg << std::endl;
411 }
catch(std::exception& e) {
412 uerr() <<
"ehfun failed: " << e.what() << std::endl;
418 auto m =
to_mem(user_data);
420 if (s.calc_quadF(m, t, NV_DATA_S(x),
nullptr, NV_DATA_S(qdot)))
return 1;
423 }
catch(std::exception& e) {
424 uerr() <<
"rhsQ failed: " << e.what() << std::endl;
431 casadi_assert_dev(user_data);
432 auto m =
to_mem(user_data);
434 if (s.calc_daeB(m, t, NV_DATA_S(x),
nullptr, NV_DATA_S(rx),
nullptr, m->adj_q,
435 NV_DATA_S(rxdot),
nullptr))
return 1;
439 }
catch(std::exception& e) {
440 uerr() <<
"rhsB failed: " << e.what() << std::endl;
447 casadi_assert_dev(user_data);
448 auto m =
to_mem(user_data);
450 if (s.calc_quadB(m, t, NV_DATA_S(x),
nullptr, NV_DATA_S(rx),
nullptr,
451 NV_DATA_S(ruqdot), NV_DATA_S(ruqdot) + s.nrq_))
return 1;
454 casadi_scal((s.nrq_ + s.nuq_), -1., NV_DATA_S(ruqdot));
457 }
catch(std::exception& e) {
458 uerr() <<
"rhsQB failed: " << e.what() << std::endl;
464 N_Vector xdot,
void *user_data, N_Vector tmp) {
466 auto m =
to_mem(user_data);
468 if (s.calc_jtimesF(m, t, NV_DATA_S(x),
nullptr, NV_DATA_S(v),
nullptr,
469 NV_DATA_S(Jv),
nullptr))
return 1;
471 }
catch(std::exception& e) {
472 uerr() <<
"jtimesF failed: " << e.what() << std::endl;
478 N_Vector rx, N_Vector rxdot,
void *user_data, N_Vector tmpB) {
480 auto m =
to_mem(user_data);
483 if (s.calc_daeB(m, t, NV_DATA_S(x),
nullptr, NV_DATA_S(v),
nullptr,
nullptr,
484 NV_DATA_S(Jv),
nullptr))
return 1;
486 }
catch(std::exception& e) {
487 uerr() <<
"jtimesB failed: " << e.what() << std::endl;
493 N_Vector z,
double gamma,
double delta,
int lr,
void *user_data, N_Vector tmp) {
495 auto m =
to_mem(user_data);
499 double* v = NV_DATA_S(r);
503 if (s.linsolF_.solve(m->jacF, m->tmp1, 1,
false, m->mem_linsolF))
return 1;
510 if (s.second_order_correction_) {
513 if (s.calc_jtimesF(m, t, NV_DATA_S(x),
nullptr, v,
nullptr, m->tmp2,
nullptr))
return 1;
516 casadi_axpy(s.nx_ - s.nx1_, m->gamma, m->tmp2 + s.nx1_, m->tmp1 + s.nx1_);
520 if (s.linsolF_.solve(m->jacF, m->tmp1 + s.nx1_, s.nfwd_,
false, m->mem_linsolF))
return 1;
523 casadi_copy(m->tmp1 + s.nx1_, s.nx_ - s.nx1_, v + s.nx1_);
527 }
catch(std::exception& e) {
528 uerr() <<
"psolve failed: " << e.what() << std::endl;
534 N_Vector zvecB,
double gammaB,
double deltaB,
int lr,
void *user_data, N_Vector tmpB) {
536 auto m =
to_mem(user_data);
540 double* v = NV_DATA_S(rvecB);
544 if (s.linsolF_.solve(m->jacF, m->tmp1, s.nadj_,
true, m->mem_linsolF))
return 1;
545 v = NV_DATA_S(zvecB);
551 if (s.second_order_correction_) {
553 casadi_clear(v + s.nrx1_ * s.nadj_, s.nrx_ - s.nrx1_ * s.nadj_);
554 if (s.calc_daeB(m, t, NV_DATA_S(x),
nullptr, v,
nullptr,
nullptr, m->tmp2,
nullptr))
557 casadi_axpy(s.nrx_ - s.nrx1_ * s.nadj_, -m->gammaB, m->tmp2 + s.nrx1_ * s.nadj_,
558 m->tmp1 + s.nrx1_ * s.nadj_);
562 if (s.linsolF_.solve(m->jacF, m->tmp1 + s.nx1_, s.nadj_ * s.nfwd_,
563 true, m->mem_linsolF))
return 1;
566 casadi_copy(m->tmp1 + s.nx1_, s.nx_ - s.nx1_, v + s.nx1_);
570 }
catch(std::exception& e) {
571 uerr() <<
"psolveB failed: " << e.what() << std::endl;
577 booleantype *jcurPtr,
double gamma,
void *user_data,
578 N_Vector tmp1, N_Vector tmp2, N_Vector tmp3) {
580 auto m =
to_mem(user_data);
586 const Sparsity& sp_jac_ode_x = s.get_function(
"jacF").sparsity_out(0);
587 const Sparsity& sp_jacF = s.linsolF_.sparsity();
590 if (s.always_recalculate_jacobian_ || !jcurPtr || *jcurPtr == 0) {
592 if (s.calc_jacF(m, t, NV_DATA_S(x),
nullptr,
593 m->jac_ode_x,
nullptr,
nullptr,
nullptr))
return 1;
596 if (jcurPtr) *jcurPtr = 1;
600 casadi_project(m->jac_ode_x, sp_jac_ode_x, m->jacF, sp_jacF, m->w);
603 const casadi_int *colind = sp_jacF.
colind(), *row = sp_jacF.
row();
604 for (casadi_int c = 0; c < sp_jacF.
size2(); ++c) {
605 for (casadi_int k = colind[c]; k < colind[c + 1]; ++k) {
606 casadi_int r = row[k];
608 m->jacF[k] *= -gamma;
610 if (r == c) m->jacF[k] += 1;
615 if (s.linsolF_.nfact(m->jacF, m->mem_linsolF))
return 1;
618 }
catch(std::exception& e) {
619 uerr() <<
"psetup failed: " << e.what() << std::endl;
625 booleantype jokB, booleantype *jcurPtrB,
double gammaB,
626 void *user_data, N_Vector tmp1B, N_Vector tmp2B, N_Vector tmp3B) {
628 auto m =
to_mem(user_data);
632 return psetupF(t, x,
nullptr, jokB, jcurPtrB, -gammaB, user_data, tmp1B, tmp2B, tmp3B);
634 }
catch(std::exception& e) {
635 uerr() <<
"psetupB failed: " << e.what() << std::endl;
641 booleantype *jcurPtr, N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3) {
643 auto m =
to_mem(cv_mem->cv_lmem);
646 return psetupF(cv_mem->cv_tn, x, xdot, FALSE, jcurPtr,
647 cv_mem->cv_gamma,
static_cast<void*
>(m), vtemp1, vtemp2, vtemp3);
649 }
catch(std::exception& e) {
650 uerr() <<
"lsetup failed: " << e.what() << std::endl;
656 booleantype *jcurPtr, N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3) {
658 auto m =
to_mem(cv_mem->cv_lmem);
663 double t = cv_mem->cv_tn;
664 double gamma = cv_mem->cv_gamma;
666 cv_mem =
static_cast<CVodeMem
>(cv_mem->cv_user_data);
667 ca_mem = cv_mem->cv_adj_mem;
671 int flag = ca_mem->ca_IMget(cv_mem, t, ca_mem->ca_ytmp,
nullptr);
672 if (flag != CV_SUCCESS) casadi_error(
"Could not interpolate forward states");
675 return psetupB(t, ca_mem->ca_ytmp, x, xdot, FALSE, jcurPtr,
676 gamma,
static_cast<void*
>(m), vtemp1, vtemp2, vtemp3);
678 }
catch(std::exception& e) {
679 uerr() <<
"lsetupB failed: " << e.what() << std::endl;
685 N_Vector x, N_Vector xdot) {
687 auto m =
to_mem(cv_mem->cv_lmem);
691 double t = cv_mem->cv_tn;
694 double gamma = cv_mem->cv_gamma;
703 return psolveF(t, x, xdot, b, b, gamma, delta, lr,
static_cast<void*
>(m),
nullptr);
705 }
catch(std::exception& e) {
706 uerr() <<
"lsolveF failed: " << e.what() << std::endl;
712 N_Vector x, N_Vector xdot) {
714 auto m =
to_mem(cv_mem->cv_lmem);
719 double t = cv_mem->cv_tn;
720 double gamma = cv_mem->cv_gamma;
722 cv_mem =
static_cast<CVodeMem
>(cv_mem->cv_user_data);
724 ca_mem = cv_mem->cv_adj_mem;
728 int flag = ca_mem->ca_IMget(cv_mem, t, ca_mem->ca_ytmp,
nullptr);
729 if (flag != CV_SUCCESS) casadi_error(
"Could not interpolate forward states");
738 return psolveB(t, ca_mem->ca_ytmp, x, xdot, b, b, gamma, delta, lr,
739 static_cast<void*
>(m),
nullptr);
741 }
catch(std::exception& e) {
742 uerr() <<
"lsolveB failed: " << e.what() << std::endl;
756 if (this->
mem) CVodeFree(&this->
mem);
760 int version = s.
version(
"CvodesInterface", 1, 3);
777 s.
version(
"CvodesInterface", 3);
779 s.
pack(
"CvodesInterface::lmm",
lmm_);
'cvodes' plugin for Integrator
static int lsolveB(CVodeMem cv_mem, N_Vector b, N_Vector weight, N_Vector x, N_Vector xdot)
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize into MX.
static int rhsF(double t, N_Vector x, N_Vector xdot, void *user_data)
static CvodesMemory * to_mem(void *mem)
Cast to memory object.
void retreat(IntegratorMemory *mem, const double *u, double *adj_x, double *adj_p, double *adj_u) const override
Retreat solution in time.
~CvodesInterface() override
Destructor.
static int psetupF(double t, N_Vector x, N_Vector xdot, booleantype jok, booleantype *jcurPtr, double gamma, void *user_data, N_Vector tmp1, N_Vector tmp2, N_Vector tmp3)
void reset(IntegratorMemory *mem, bool first_call) const override
Reset the forward solver at the start or after an event.
CvodesInterface(const std::string &name, const Function &dae, double t0, const std::vector< double > &tout)
Constructor.
static int rhsQB(double t, N_Vector x, N_Vector rx, N_Vector ruqdot, void *user_data)
int advance_noevent(IntegratorMemory *mem) const override
Advance solution in time.
static int lsetupF(CVodeMem cv_mem, int convfail, N_Vector x, N_Vector xdot, booleantype *jcurPtr, N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3)
static void cvodes_error(const char *module, int flag)
int init_mem(void *mem) const override
Initalize memory block.
static int psolveB(double t, N_Vector x, N_Vector xB, N_Vector xdotB, N_Vector rvecB, N_Vector zvecB, double gammaB, double deltaB, int lr, void *user_data, N_Vector tmpB)
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
void impulseB(IntegratorMemory *mem, const double *adj_x, const double *adj_z, const double *adj_q) const override
Introduce an impulse into the backwards integration at the current time.
static const std::string meta_doc
A documentation string.
static int lsetupB(CVodeMem cv_mem, int convfail, N_Vector x, N_Vector xdot, booleantype *jcurPtr, N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3)
static Integrator * creator(const std::string &name, const Function &dae, double t0, const std::vector< double > &tout)
Create a new integrator.
static const Options options_
Options.
void init(const Dict &opts) override
Initialize stage.
bool always_recalculate_jacobian_
Options.
static int jtimesF(N_Vector v, N_Vector Jv, double t, N_Vector x, N_Vector xdot, void *user_data, N_Vector tmp)
static void ehfun(int error_code, const char *module, const char *function, char *msg, void *user_data)
static int psolveF(double t, N_Vector x, N_Vector xdot, N_Vector r, N_Vector z, double gamma, double delta, int lr, void *user_data, N_Vector tmp)
static int rhsQF(double t, N_Vector x, N_Vector qdot, void *user_data)
static int lsolveF(CVodeMem cv_mem, N_Vector b, N_Vector weight, N_Vector x, N_Vector xdot)
static int rhsB(double t, N_Vector x, N_Vector xB, N_Vector xdotB, void *user_data)
static int psetupB(double t, N_Vector x, N_Vector xB, N_Vector xdotB, booleantype jokB, booleantype *jcurPtrB, double gammaB, void *user_data, N_Vector tmp1B, N_Vector tmp2B, N_Vector tmp3B)
static int jtimesB(N_Vector vB, N_Vector JvB, double t, N_Vector x, N_Vector xB, N_Vector xdotB, void *user_data, N_Vector tmpB)
double min_step_size_
Options.
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
void alloc_w(size_t sz_w, bool persistent=false)
Ensure required length of w field.
casadi_int nrx_
Number of states for the backward integration.
casadi_int nu_
Number of controls.
casadi_int nx_
Number of states for the forward integration.
casadi_int ne_
Number of of zero-crossing functions.
static void registerPlugin(const Plugin &plugin, bool needs_lock=true)
Register an integrator in the factory.
bool verbose_
Verbose printout.
void clear_mem()
Clear all memory (called from destructor)
Helper class for Serialization.
void version(const std::string &name, int v)
void pack(const Sparsity &e)
Serializes an object to the output stream.
casadi_int size2() const
Get the number of columns.
const casadi_int * row() const
Get a reference to row-vector,.
const casadi_int * colind() const
Get a reference to the colindex of all column element (see class description)
enum casadi::SundialsInterface::InterpType interp_
void impulseB(IntegratorMemory *mem, const double *adj_x, const double *adj_z, const double *adj_q) const override
Introduce an impulse into the backwards integration at the current time.
double nonlin_conv_coeff_
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
enum casadi::SundialsInterface::NewtonScheme newton_scheme_
void reset(IntegratorMemory *mem, bool first_call) const override
Reset the forward solver at the start or after an event.
int init_mem(void *mem) const override
Initalize memory block.
void add_offsets(SundialsMemory *m) const
Add stats offsets to stats.
casadi_int max_num_steps_
void init(const Dict &opts) override
Initialize.
void save_offsets(SundialsMemory *m) const
Save stats offsets before reset.
casadi_int steps_per_checkpoint_
static const Options options_
Options.
void casadi_project(const T1 *x, const casadi_int *sp_x, T1 *y, const casadi_int *sp_y, T1 *w)
Sparse copy: y <- x, w work vector (length >= number of rows)
void casadi_copy(const T1 *x, casadi_int n, T1 *y)
COPY: y <-x.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
void CASADI_INTEGRATOR_CVODES_EXPORT casadi_load_integrator_cvodes()
void casadi_scal(casadi_int n, T1 alpha, T1 *x)
SCAL: x <- alpha*x.
int CASADI_INTEGRATOR_CVODES_EXPORT casadi_register_integrator_cvodes(Integrator::Plugin *plugin)
void casadi_axpy(casadi_int n, T1 alpha, const T1 *x, T1 *y)
AXPY: y <- a*x + y.
void casadi_clear(T1 *x, casadi_int n)
CLEAR: x <- 0.
CvodesMemory(const CvodesInterface &s)
Constructor.
~CvodesMemory()
Destructor.
Options metadata for a class.
int mem_linsolF
Linear solver memory objects.
int ncheck
number of checkpoints stored so far