1#ifndef STAN_MATH_PRIM_FUNCTOR_ARKODE_INTEGRATOR_HPP
2#define STAN_MATH_PRIM_FUNCTOR_ARKODE_INTEGRATOR_HPP
11#include <sundials/sundials_context.h>
12#include <arkode/arkode_erkstep.h>
13#include <nvector/nvector_serial.h>
42template <ARKODE_ERKTableID Table,
bool DenseOutput,
typename F,
typename T_y0,
43 typename T_t0,
typename T_ts,
typename... Args>
51 const Eigen::Matrix<T_y0_t0, Eigen::Dynamic, 1>
y0_;
53 const std::vector<T_ts>&
ts_;
62 std::vector<double>
z_;
67 static realtype
max_norm(N_Vector x, N_Vector w) {
68 Eigen::Map<const Eigen::ArrayXd> x_map(NV_DATA_S(x), NV_LENGTH_S(x));
69 Eigen::Map<const Eigen::ArrayXd> w_map(NV_DATA_S(w), NV_LENGTH_S(w));
70 return (x_map * w_map).abs().maxCoeff();
73 static int erk_rhs(realtype t, N_Vector y, N_Vector ydot,
void* user_data) {
75 integrator->
rhs(t, NV_DATA_S(y), NV_DATA_S(ydot));
79 inline void rhs(
double t,
const double y[],
double dy_dt[]) {
105 T_t0 t0,
const std::vector<T_ts>& ts,
106 double relative_tolerance,
double absolute_tolerance,
107 long int max_num_steps,
108 std::ostream* msgs,
const Args&... args)
127 [&](
const auto&... args_ref) {
128 (
check_finite(function_name,
"ode parameters and data", args_ref),
158 std::vector<Eigen::Matrix<T_Return, Eigen::Dynamic, 1>>
operator()() {
159 std::vector<Eigen::Matrix<T_Return, Eigen::Dynamic, 1>> y;
160 y.reserve(
ts_.size());
162 auto free_mem = [](
void* mem) { ERKStepFree(&mem); };
163 std::unique_ptr<void,
decltype(free_mem)> mem_ptr(
167 void* arkode_mem = mem_ptr.get();
168 if (arkode_mem ==
nullptr) {
169 throw std::runtime_error(
"ERKStepCreate failed to allocate memory");
173 ERKStepSetUserData(arkode_mem,
reinterpret_cast<void*
>(
this)));
180 realtype adapt_params[3] = {1.0, 0.0, 0.0};
190 ERKStepSetFixedStepBounds(arkode_mem, 0.9, 0.9 * std::pow(0.5, -0.2)));
194 ERKStepSetInterpolantType(arkode_mem, ARK_INTERP_LAGRANGE));
198 for (
size_t n = 0; n <
ts_.size(); ++n) {
201 if (t_final != t_init) {
205 int flag = ERKStepEvolve(arkode_mem, t_final,
nv_state_, &t_init,
207 if (flag == ARK_TOO_MUCH_WORK) {
209 "Failed to integrate to next output time (",
210 ") in less than max_num_steps steps");
216 [&](
const auto&... args_ref) {
#define CHECK_ARKODE_CALL(call)
const Eigen::Matrix< T_y0_t0, Eigen::Dynamic, 1 > y0_
static int erk_rhs(realtype t, N_Vector y, N_Vector ydot, void *user_data)
double relative_tolerance_
coupled_ode_system< F, T_y0_t0, Args... > coupled_system_
return_type_t< T_y0, T_t0, T_ts, Args... > T_Return
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,...
sundials::Context sundials_context_
std::tuple< const Args &... > args_tuple_
const char * function_name_
return_type_t< T_y0, T_t0 > T_y0_t0
std::vector< double > coupled_state_
double absolute_tolerance_
static realtype max_norm(N_Vector x, N_Vector w)
const std::vector< T_ts > & ts_
std::vector< double > dz_dt_
arkode_integrator(const char *function_name, const F &f, const T_y0 &y0, T_t0 t0, const std::vector< T_ts > &ts, double relative_tolerance, double absolute_tolerance, long int max_num_steps, std::ostream *msgs, const Args &... args)
Construct arkode_integrator object.
void rhs(double t, const double y[], double dy_dt[])
Integrator interface for ARKODE's ERKStep explicit adaptive Runge-Kutta solver, using one of ERKStep'...
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.
T value_of(const fvar< T > &v)
Return the value of the specified variable.
void arkode_check(int flag, const char *func_name)
void throw_domain_error(const char *function, const char *name, const T &y, const char *msg1, const char *msg2)
Throw a domain error with a consistently formatted message.
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_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 ...