12#include "sundials/sundials_types.h"
13#include "sundials/sundials_math.h"
14#include "sundials/sundials_nvector.h"
15#include "nvector/nvector_serial.h"
16#include "cvodes/cvodes.h"
17#if CT_SUNDIALS_VERSION >= 30
18 #if CT_SUNDIALS_USE_LAPACK
19 #include "sunlinsol/sunlinsol_lapackdense.h"
20 #include "sunlinsol/sunlinsol_lapackband.h"
22 #include "sunlinsol/sunlinsol_dense.h"
23 #include "sunlinsol/sunlinsol_band.h"
25 #include "sunlinsol/sunlinsol_spgmr.h"
26 #include "cvodes/cvodes_direct.h"
27 #include "cvodes/cvodes_diag.h"
28 #include "cvodes/cvodes_spils.h"
30 #if CT_SUNDIALS_USE_LAPACK
31 #include "cvodes/cvodes_lapack.h"
33 #include "cvodes/cvodes_dense.h"
34 #include "cvodes/cvodes_band.h"
36 #include "cvodes/cvodes_diag.h"
37 #include "cvodes/cvodes_spgmr.h"
43#if CT_SUNDIALS_VERSION < 25
46typedef long int sd_size_t;
53#if CT_SUNDIALS_VERSION >= 60
54 return N_VNew_Serial(
static_cast<sd_size_t
>(N), context.get());
56 return N_VNew_Serial(
static_cast<sd_size_t
>(N));
74 static int cvodes_rhs(realtype t, N_Vector y, N_Vector ydot,
void* f_data)
77 return f->
eval_nothrow(t, NV_DATA_S(y), NV_DATA_S(ydot));
83 static void cvodes_err(
int error_code,
const char* module,
84 const char*
function,
char* msg,
void* eh_data)
108 m_reltolsens(1.0e-5),
109 m_abstolsens(1.0e-4),
114 m_maxErrTestFails(0),
117 m_mupper(0), m_mlower(0),
122CVodesIntegrator::~CVodesIntegrator()
126 CVodeSensFree(m_cvode_mem);
128 CVodeFree(&m_cvode_mem);
131 #if CT_SUNDIALS_VERSION >= 30
132 SUNLinSolFree((SUNLinearSolver)
m_linsol);
137 N_VDestroy_Serial(m_y);
140 N_VDestroy_Serial(m_abstol);
143 N_VDestroy_Serial(m_dky);
146 #if CT_SUNDIALS_VERSION >= 60
147 N_VDestroyVectorArray(m_yS,
static_cast<sd_size_t
>(m_np));
149 N_VDestroyVectorArray_Serial(m_yS,
static_cast<sd_size_t
>(m_np));
157 return NV_Ith_S(m_y, k);
162 return NV_DATA_S(m_y);
171 N_VDestroy_Serial(m_abstol);
175 for (
size_t i=0; i<n; i++) {
176 NV_Ith_S(m_abstol, i) = abstol[i];
190 m_reltolsens = reltol;
191 m_abstolsens = abstol;
206 throw CanteraError(
"CVodesIntegrator::setMethod",
"unknown method");
214 CVodeSetMaxStep(m_cvode_mem, hmax);
222 CVodeSetMinStep(m_cvode_mem, hmin);
230 CVodeSetMaxNumSteps(m_cvode_mem, m_maxsteps);
241 m_maxErrTestFails = n;
243 CVodeSetMaxErrTestFails(m_cvode_mem, n);
247void CVodesIntegrator::sensInit(
double t0,
FuncEval& func)
253 #if CT_SUNDIALS_VERSION >= 60
254 m_yS = N_VCloneVectorArray(
static_cast<sd_size_t
>(m_np), y);
256 m_yS = N_VCloneVectorArray_Serial(
static_cast<sd_size_t
>(m_np), y);
258 for (
size_t n = 0; n < m_np; n++) {
259 N_VConst(0.0, m_yS[n]);
261 N_VDestroy_Serial(y);
263 int flag = CVodeSensInit(m_cvode_mem,
static_cast<sd_size_t
>(m_np),
264 CV_STAGGERED, CVSensRhsFn(0), m_yS);
266 if (flag != CV_SUCCESS) {
267 throw CanteraError(
"CVodesIntegrator::sensInit",
"Error in CVodeSensInit");
270 for (
size_t n = 0; n < m_np; n++) {
275 flag = CVodeSensSStolerances(m_cvode_mem, m_reltolsens, atol.data());
287 N_VDestroy_Serial(m_y);
292 N_VDestroy_Serial(m_dky);
295 N_VConst(0.0, m_dky);
297 if (m_itol == CV_SV && m_nabs < m_neq) {
299 "not enough absolute tolerance values specified.");
305 CVodeFree(&m_cvode_mem);
311 #if CT_SUNDIALS_VERSION < 40
312 m_cvode_mem = CVodeCreate(m_method, CV_NEWTON);
313 #elif CT_SUNDIALS_VERSION < 60
314 m_cvode_mem = CVodeCreate(m_method);
320 "CVodeCreate failed.");
323 int flag = CVodeInit(m_cvode_mem,
cvodes_rhs, m_t0, m_y);
324 if (flag != CV_SUCCESS) {
325 if (flag == CV_MEM_FAIL) {
327 "Memory allocation failed.");
328 }
else if (flag == CV_ILL_INPUT) {
330 "Illegal value for CVodeInit input argument.");
333 "CVodeInit failed.");
336 CVodeSetErrHandlerFn(m_cvode_mem, &
cvodes_err,
this);
338 if (m_itol == CV_SV) {
339 flag = CVodeSVtolerances(m_cvode_mem, m_reltol, m_abstol);
341 flag = CVodeSStolerances(m_cvode_mem, m_reltol, m_abstols);
343 if (flag != CV_SUCCESS) {
344 if (flag == CV_MEM_FAIL) {
346 "Memory allocation failed.");
347 }
else if (flag == CV_ILL_INPUT) {
349 "Illegal value for CVodeInit input argument.");
352 "CVodeInit failed.");
356 flag = CVodeSetUserData(m_cvode_mem, &func);
357 if (flag != CV_SUCCESS) {
359 "CVodeSetUserData failed.");
363 flag = CVodeSetSensParams(m_cvode_mem, func.
m_sens_params.data(),
365 if (flag != CV_SUCCESS) {
367 "CVodeSetSensParams failed.");
373void CVodesIntegrator::reinitialize(
double t0,
FuncEval& func)
381 int result = CVodeReInit(m_cvode_mem, m_t0, m_y);
382 if (result != CV_SUCCESS) {
384 "CVodeReInit failed. result = {}", result);
391 if (m_type == DENSE + NOJAC) {
392 sd_size_t N =
static_cast<sd_size_t
>(m_neq);
393 #if CT_SUNDIALS_VERSION >= 30
394 SUNLinSolFree((SUNLinearSolver)
m_linsol);
396 #if CT_SUNDIALS_VERSION >= 60
403 "Unable to create SUNDenseMatrix of size {0} x {0}", N);
406 #if CT_SUNDIALS_VERSION >= 60
407 #if CT_SUNDIALS_USE_LAPACK
414 flag = CVodeSetLinearSolver(m_cvode_mem, (SUNLinearSolver)
m_linsol,
417 #if CT_SUNDIALS_USE_LAPACK
422 flag = CVDlsSetLinearSolver(m_cvode_mem, (SUNLinearSolver)
m_linsol,
427 "Error creating Sundials dense linear solver object");
428 }
else if (flag != CV_SUCCESS) {
430 "Error connecting linear solver to CVODES. "
431 "Sundials error code: {}", flag);
434 #if CT_SUNDIALS_USE_LAPACK
435 CVLapackDense(m_cvode_mem, N);
437 CVDense(m_cvode_mem, N);
441 }
else if (m_type == DIAG) {
443 }
else if (m_type == GMRES) {
444 #if CT_SUNDIALS_VERSION >= 30
445 #if CT_SUNDIALS_VERSION >= 60
447 CVodeSetLinearSolver(m_cvode_mem, (SUNLinearSolver)
m_linsol,
nullptr);
448 #elif CT_SUNDIALS_VERSION >= 40
449 m_linsol = SUNLinSol_SPGMR(m_y, PREC_NONE, 0);
450 CVSpilsSetLinearSolver(m_cvode_mem, (SUNLinearSolver)
m_linsol);
452 m_linsol = SUNSPGMR(m_y, PREC_NONE, 0);
453 CVSpilsSetLinearSolver(m_cvode_mem, (SUNLinearSolver)
m_linsol);
457 CVSpgmr(m_cvode_mem, PREC_NONE, 0);
459 }
else if (m_type == BAND + NOJAC) {
460 sd_size_t N =
static_cast<sd_size_t
>(m_neq);
461 long int nu = m_mupper;
462 long int nl = m_mlower;
463 #if CT_SUNDIALS_VERSION >= 30
464 SUNLinSolFree((SUNLinearSolver)
m_linsol);
466 #if CT_SUNDIALS_VERSION >= 60
468 #elif CT_SUNDIALS_VERSION >= 40
475 "Unable to create SUNBandMatrix of size {} with bandwidths "
476 "{} and {}", N, nu, nl);
478 #if CT_SUNDIALS_VERSION >= 60
479 #if CT_SUNDIALS_USE_LAPACK
486 CVodeSetLinearSolver(m_cvode_mem, (SUNLinearSolver)
m_linsol,
489 #if CT_SUNDIALS_USE_LAPACK
494 CVDlsSetLinearSolver(m_cvode_mem, (SUNLinearSolver)
m_linsol,
498 #if CT_SUNDIALS_USE_LAPACK
499 CVLapackBand(m_cvode_mem, N, nu, nl);
501 CVBand(m_cvode_mem, N, nu, nl);
506 "unsupported option");
510 CVodeSetMaxOrd(m_cvode_mem, m_maxord);
512 if (m_maxsteps > 0) {
513 CVodeSetMaxNumSteps(m_cvode_mem, m_maxsteps);
516 CVodeSetMaxStep(m_cvode_mem, m_hmax);
519 CVodeSetMinStep(m_cvode_mem, m_hmin);
521 if (m_maxErrTestFails > 0) {
522 CVodeSetMaxErrTestFails(m_cvode_mem, m_maxErrTestFails);
531 int flag = CVode(m_cvode_mem, tout, m_y, &
m_time, CV_NORMAL);
532 if (flag != CV_SUCCESS) {
534 if (!f_errs.empty()) {
535 f_errs =
"Exceptions caught during RHS evaluation:\n" + f_errs;
538 "CVodes error encountered. Error code: {}\n{}\n"
540 "Components with largest weighted error estimates:\n{}",
548 int flag = CVode(m_cvode_mem, tout, m_y, &
m_time, CV_ONE_STEP);
549 if (flag != CV_SUCCESS) {
551 if (!f_errs.empty()) {
552 f_errs =
"Exceptions caught during RHS evaluation:\n" + f_errs;
555 "CVodes error encountered. Error code: {}\n{}\n"
557 "Components with largest weighted error estimates:\n{}",
567 int flag = CVodeGetDky(m_cvode_mem, tout, n, m_dky);
568 if (flag != CV_SUCCESS) {
570 if (!f_errs.empty()) {
571 f_errs =
"Exceptions caught evaluating derivative:\n" + f_errs;
574 "CVodes error encountered. Error code: {}\n{}\n"
578 return NV_DATA_S(m_dky);
584 CVodeGetLastOrder(m_cvode_mem, &ord);
591 CVodeGetNumRhsEvals(m_cvode_mem, &ne);
595double CVodesIntegrator::sensitivity(
size_t k,
size_t p)
602 int flag = CVodeGetSens(m_cvode_mem, &
m_time, m_yS);
603 if (flag != CV_SUCCESS) {
604 throw CanteraError(
"CVodesIntegrator::sensitivity",
605 "CVodeGetSens failed. Error code: {}", flag);
611 throw CanteraError(
"CVodesIntegrator::sensitivity",
612 "sensitivity: k out of range ({})", k);
615 throw CanteraError(
"CVodesIntegrator::sensitivity",
616 "sensitivity: p out of range ({})", p);
618 return NV_Ith_S(m_yS[p],k);
625 CVodeGetErrWeights(m_cvode_mem, errw);
626 CVodeGetEstLocalErrors(m_cvode_mem, errs);
628 vector<tuple<double, double, size_t> > weightedErrors;
629 for (
size_t i=0; i<m_neq; i++) {
630 double err = NV_Ith_S(errs, i) * NV_Ith_S(errw, i);
631 weightedErrors.emplace_back(-abs(err), err, i);
636 N = std::min(N,
static_cast<int>(m_neq));
637 sort(weightedErrors.begin(), weightedErrors.end());
638 fmt::memory_buffer s;
639 for (
int i=0; i<N; i++) {
640 fmt_append(s,
"{}: {}\n",
641 get<2>(weightedErrors[i]), get<1>(weightedErrors[i]));
Wrapper class for 'cvodes' integrator from LLNL.
virtual int nEvals() const
The number of function evaluations.
virtual int lastOrder() const
Order used during the last solution step.
virtual void setMinStepSize(double hmin)
Set the minimum step size.
void * m_linsol
Sundials linear solver object.
std::string m_error_message
Error message information provide by CVodes.
CVodesIntegrator()
Constructor.
double m_time
The current integrator time.
bool m_sens_ok
Indicates whether the sensitivities stored in m_yS have been updated for at the current integrator ti...
virtual void initialize(double t0, FuncEval &func)
Initialize the integrator for a new problem.
SundialsContext m_sundials_ctx
SUNContext object for Sundials>=6.0.
virtual void integrate(double tout)
Integrate the system of equations.
virtual void setMaxSteps(int nmax)
Set the maximum number of time-steps the integrator can take before reaching the next output time.
virtual doublereal step(double tout)
Integrate the system of equations.
virtual void setSensitivityTolerances(double reltol, double abstol)
Set the sensitivity error tolerances.
virtual double * solution()
The current value of the solution of the system of equations.
virtual void setTolerances(double reltol, size_t n, double *abstol)
Set error tolerances.
virtual int maxSteps()
Returns the maximum number of time-steps the integrator can take before reaching the next output time...
virtual void setMaxStepSize(double hmax)
Set the maximum step size.
void applyOptions()
Applies user-specified options to the underlying CVODES solver.
virtual double * derivative(double tout, int n)
n-th derivative of the output function at time tout.
virtual void setProblemType(int probtype)
Set the problem type.
virtual void setMethod(MethodType t)
Set the solution method.
void * m_linsol_matrix
matrix used by Sundials
virtual void setMaxErrTestFails(int n)
Set the maximum permissible number of error test failures.
virtual std::string getErrorInfo(int N)
Returns a string listing the weighted error estimates associated with each solution component.
Base class for exceptions thrown by Cantera classes.
Virtual base class for ODE right-hand-side function evaluators.
virtual size_t nparams()
Number of sensitivity parameters.
vector_fp m_sens_params
Values for the problem parameters for which sensitivities are computed This is the array which is per...
void clearErrors()
Clear any previously-stored suppressed errors.
virtual size_t neq()=0
Number of equations.
std::string getErrors() const
Return a string containing the text of any suppressed errors.
int eval_nothrow(double t, double *y, double *ydot)
Evaluate the right-hand side using return code to indicate status.
vector_fp m_paramScales
Scaling factors for each sensitivity parameter.
virtual void getState(double *y)
Fill in the vector y with the current state of the system.
A wrapper for managing a SUNContext object, need for Sundials >= 6.0.
static int cvodes_rhs(realtype t, N_Vector y, N_Vector ydot, void *f_data)
Function called by cvodes to evaluate ydot given y.
Namespace for the Cantera kernel.
MethodType
Specifies the method used to integrate the system of equations.
@ BDF_Method
Backward Differentiation.
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
static void cvodes_err(int error_code, const char *module, const char *function, char *msg, void *eh_data)
Function called by CVodes when an error is encountered instead of writing to stdout.
Contains declarations for string manipulation functions within Cantera.