1#ifndef STAN_MATH_REV_FUNCTOR_INTEGRATE_ODE_CVODES_HPP
2#define STAN_MATH_REV_FUNCTOR_INTEGRATE_ODE_CVODES_HPP
11#include <sundials/sundials_context.h>
12#include <cvodes/cvodes.h>
13#include <nvector/nvector_serial.h>
14#include <sunlinsol/sunlinsol_dense.h>
33template <
int Lmm,
typename F,
typename T_y0,
typename T_t0,
typename T_ts,
42 const Eigen::Matrix<T_y0_t0, Eigen::Dynamic, 1>
y0_;
44 const std::vector<T_ts>&
ts_;
46 std::tuple<plain_type_t<decltype(value_of(std::declval<const T_Args&>()))>...>
69 static int cv_rhs(realtype t, N_Vector y, N_Vector ydot,
void* user_data) {
71 integrator->
rhs(t, NV_DATA_S(y), NV_DATA_S(ydot));
79 static int cv_rhs_sens(
int Ns, realtype t, N_Vector y, N_Vector ydot,
80 N_Vector* yS, N_Vector* ySdot,
void* user_data,
81 N_Vector tmp1, N_Vector tmp2) {
83 integrator->
rhs_sens(t, NV_DATA_S(y), yS, ySdot);
94 SUNMatrix J,
void* user_data, N_Vector tmp1,
95 N_Vector tmp2, N_Vector tmp3) {
105 inline void rhs(
double t,
const double y[],
double dy_dt[])
const {
106 const Eigen::VectorXd y_vec = Eigen::Map<const Eigen::VectorXd>(y,
N_);
109 [&](
auto&&... args) {
return f_(t, y_vec,
msgs_, args...); },
115 std::copy(dy_dt_vec.data(), dy_dt_vec.data() + dy_dt_vec.size(), dy_dt);
126 auto f_wrapped = [&](
const Eigen::Matrix<var, Eigen::Dynamic, 1>& y) {
128 [&](
auto&&... args) {
return f_(t, y,
msgs_, args...); },
132 jacobian(f_wrapped, Eigen::Map<const Eigen::VectorXd>(y,
N_), fy, Jfy);
134 for (
size_t j = 0; j < Jfy.cols(); ++j) {
135 for (
size_t i = 0; i < Jfy.rows(); ++i) {
136 SM_ELEMENT_D(J, i, j) = Jfy(i, j);
147 inline void rhs_sens(
double t,
const double y[], N_Vector* yS,
150 std::vector<double> dz_dt;
151 std::copy(y, y +
N_, z.data());
153 std::copy(NV_DATA_S(yS[s]), NV_DATA_S(yS[s]) +
N_,
154 z.data() + (s + 1) *
N_);
158 std::move(dz_dt.data() + (s + 1) *
N_, dz_dt.data() + (s + 2) *
N_,
159 NV_DATA_S(ySdot[s]));
190 template <require_eigen_col_vector_t<T_y0>* =
nullptr>
192 const T_t0& t0,
const std::vector<T_ts>& ts,
193 double relative_tolerance,
double absolute_tolerance,
194 long int max_num_steps,
195 std::ostream* msgs,
const T_Args&... args)
220 [&](
auto&&... args) {
221 std::vector<int> unused_temp{
222 0, (
check_finite(function_name,
"ode parameters and data", args),
268 std::vector<Eigen::Matrix<T_Return, Eigen::Dynamic, 1>>
operator()() {
269 std::vector<Eigen::Matrix<T_Return, Eigen::Dynamic, 1>> y;
272 if (cvodes_mem ==
nullptr) {
273 throw std::runtime_error(
"CVodeCreate failed to allocate memory");
282 CVodeSetUserData(cvodes_mem,
reinterpret_cast<void*
>(
this)));
305 for (
size_t n = 0; n <
ts_.size(); ++n) {
308 if (t_final != t_init) {
310 CVode(cvodes_mem, t_final,
nv_state_, &t_init, CV_NORMAL));
319 [&](
auto&&... args) {
327 }
catch (
const std::exception&
e) {
328 CVodeFree(&cvodes_mem);
332 CVodeFree(&cvodes_mem);
#define CHECK_CVODES_CALL(call)
std::tuple< plain_type_t< decltype(value_of(std::declval< const T_Args & >()))> value_of_args_tuple_
sundials::Context sundials_context_
const char * function_name_
void rhs(double t, const double y[], double dy_dt[]) const
Calculates the ODE RHS, dy_dt, using the user-supplied functor at the given time t and state y.
static int cv_rhs(realtype t, N_Vector y, N_Vector ydot, void *user_data)
Implements the function of type CVRhsFn which is the user-defined ODE RHS passed to CVODES.
cvodes_integrator(const char *function_name, const F &f, const T_y0 &y0, const T_t0 &t0, const std::vector< T_ts > &ts, double relative_tolerance, double absolute_tolerance, long int max_num_steps, std::ostream *msgs, const T_Args &... args)
Construct cvodes_integrator object.
double absolute_tolerance_
static int cv_rhs_sens(int Ns, realtype t, N_Vector y, N_Vector ydot, N_Vector *yS, N_Vector *ySdot, void *user_data, N_Vector tmp1, N_Vector tmp2)
Implements the function of type CVSensRhsFn which is the RHS of the sensitivity ODE system.
static int cv_jacobian_states(realtype t, N_Vector y, N_Vector fy, SUNMatrix J, void *user_data, N_Vector tmp1, N_Vector tmp2, N_Vector tmp3)
Implements the function of type CVDlsJacFn which is the user-defined callback for CVODES to calculate...
std::vector< double > coupled_state_
const std::vector< T_ts > & ts_
const size_t num_args_vars_
void rhs_sens(double t, const double y[], N_Vector *yS, N_Vector *ySdot)
Calculates the RHS of the sensitivity ODE system which corresponds to the coupled ode system from whi...
return_type_t< T_y0, T_t0 > T_y0_t0
double relative_tolerance_
const size_t num_y0_vars_
return_type_t< T_y0, T_t0, T_ts, T_Args... > T_Return
const Eigen::Matrix< T_y0_t0, Eigen::Dynamic, 1 > y0_
coupled_ode_system< F, T_y0_t0, T_Args... > coupled_ode_
N_Vector * nv_state_sens_
void jacobian_states(double t, const double y[], SUNMatrix J) const
Calculates the jacobian of the ODE RHS wrt to its states y at the given time-point t and state y.
std::tuple< const T_Args &... > args_tuple_
std::vector< Eigen::Matrix< T_Return, Eigen::Dynamic, 1 > > operator()()
Solve the ODE initial value problem y' = f(t, y), y(t0) = y0 at a set of times, { t1,...
Integrator interface for CVODES' ODE solvers (Adams & BDF methods).
auto cast(T &&a)
Typecast a kernel generator expression scalar.
typename return_type< Ts... >::type return_type_t
Convenience type for the return type of the specified template parameters.
int64_t size(const T &m)
Returns the size (number of the elements) of a matrix_cl or var_value<matrix_cl<T>>.
void jacobian(const F &f, const Eigen::Matrix< T, Eigen::Dynamic, 1 > &x, Eigen::Matrix< T, Eigen::Dynamic, 1 > &fx, Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &J)
static constexpr double e()
Return the base of the natural logarithm.
void cvodes_set_options(void *cvodes_mem, long int max_num_steps)
T value_of(const fvar< T > &v)
Return the value of the specified variable.
size_t count_vars(Pargs &&... args)
Count the number of vars in the input argument list.
void check_finite(const char *function, const char *name, const T_y &y)
Return true if all values in y are finite.
Eigen::VectorXd ode_store_sensitivities(const F &f, const std::vector< double > &coupled_state, const Eigen::Matrix< T_y0_t0, Eigen::Dynamic, 1 > &y0, T_t0 t0, T_t t, std::ostream *msgs, const Args &... args)
When all arguments are arithmetic, there are no sensitivities to store, so the function just returns ...
void check_nonzero_size(const char *function, const char *name, const T_y &y)
Check if the specified matrix/vector is of non-zero size.
void check_positive(const char *function, const char *name, const T_y &y)
Check if y is positive.
void check_sorted(const char *function, const char *name, const EigVec &y)
Check if the specified vector is sorted into increasing order (repeated values are okay).
void check_size_match(const char *function, const char *name_i, T_size1 i, const char *name_j, T_size2 j)
Check if the provided sizes match.
void check_less(const char *function, const char *name, const T_y &y, const T_high &high, Idxs... idxs)
Throw an exception if y is not strictly less than high.
constexpr decltype(auto) apply(F &&f, Tuple &&t, PreArgs &&... pre_args)
void check_positive_finite(const char *function, const char *name, const T_y &y)
Check if y is positive and finite.
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...