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 SUNDIALS_USE_LAPACK
18 #include "cvodes/cvodes_lapack.h"
20 #include "cvodes/cvodes_dense.h"
21 #include "cvodes/cvodes_band.h"
23 #include "cvodes/cvodes_diag.h"
24 #include "cvodes/cvodes_spgmr.h"
30 #if SUNDIALS_VERSION < 25
31 typedef int sd_size_t;
33 typedef long int sd_size_t;
44 FuncData(FuncEval* f,
size_t npar = 0) {
45 m_pars.resize(npar, 1.0);
48 virtual ~FuncData() {}
64 static int cvodes_rhs(realtype t, N_Vector y, N_Vector ydot,
68 double* ydata = NV_DATA_S(y);
69 double* ydotdata = NV_DATA_S(ydot);
70 Cantera::FuncData* d = (Cantera::FuncData*)f_data;
72 if (d->m_pars.size() == 0) {
73 f->
eval(t, ydata, ydotdata, NULL);
78 std::cerr << err.
what() << std::endl;
81 std::cerr <<
"cvodes_rhs: unhandled exception" << std::endl;
90 static void cvodes_err(
int error_code,
const char* module,
91 const char*
function,
char* msg,
void* eh_data)
99 CVodesIntegrator::CVodesIntegrator() :
112 m_reltolsens(1.0e-5),
113 m_abstolsens(1.0e-4),
118 m_maxErrTestFails(0),
121 m_mupper(0), m_mlower(0),
126 CVodesIntegrator::~CVodesIntegrator()
130 CVodeSensFree(m_cvode_mem);
132 CVodeFree(&m_cvode_mem);
135 N_VDestroy_Serial(m_y);
138 N_VDestroy_Serial(m_abstol);
145 return NV_Ith_S(m_y, k);
150 return NV_DATA_S(m_y);
159 N_VDestroy_Serial(m_abstol);
161 m_abstol = N_VNew_Serial(static_cast<sd_size_t>(n));
163 for (
size_t i=0; i<n; i++) {
164 NV_Ith_S(m_abstol, i) = abstol[i];
178 m_reltolsens = reltol;
179 m_abstolsens = abstol;
202 CVodeSetMaxStep(m_cvode_mem, hmax);
210 CVodeSetMinStep(m_cvode_mem, hmin);
214 void CVodesIntegrator::setMaxSteps(
int nmax)
218 CVodeSetMaxNumSteps(m_cvode_mem, m_maxsteps);
224 m_maxErrTestFails = n;
226 CVodeSetMaxErrTestFails(m_cvode_mem, n);
235 m_iter = CV_FUNCTIONAL;
241 void CVodesIntegrator::sensInit(
double t0,
FuncEval& func)
244 size_t nv = func.
neq();
249 y = N_VNew_Serial(static_cast<sd_size_t>(nv));
250 m_yS = N_VCloneVectorArray_Serial(static_cast<sd_size_t>(m_np), y);
251 for (
size_t n = 0; n < m_np; n++) {
252 data = NV_DATA_S(m_yS[n]);
253 for (
size_t j = 0; j < nv; j++) {
258 int flag = CVodeSensInit(m_cvode_mem, static_cast<sd_size_t>(m_np),
259 CV_STAGGERED, CVSensRhsFn(0), m_yS);
261 if (flag != CV_SUCCESS) {
262 throw CVodesErr(
"Error in CVodeSensMalloc");
265 double rtol = m_reltolsens;
266 flag = CVodeSensSStolerances(m_cvode_mem, rtol,
DATA_PTR(atol));
277 N_VDestroy_Serial(m_y);
279 m_y = N_VNew_Serial(static_cast<sd_size_t>(m_neq));
280 for (
size_t i = 0; i < m_neq; i++) {
281 NV_Ith_S(m_y, i) = 0.0;
284 if (m_itol == CV_SV && m_nabs < m_neq) {
285 throw CVodesErr(
"not enough absolute tolerance values specified.");
291 CVodeFree(&m_cvode_mem);
300 m_cvode_mem = CVodeCreate(m_method, m_iter);
305 int flag = CVodeInit(m_cvode_mem,
cvodes_rhs, m_t0, m_y);
306 if (flag != CV_SUCCESS) {
307 if (flag == CV_MEM_FAIL) {
308 throw CVodesErr(
"Memory allocation failed.");
309 }
else if (flag == CV_ILL_INPUT) {
310 throw CVodesErr(
"Illegal value for CVodeInit input argument.");
315 CVodeSetErrHandlerFn(m_cvode_mem, &
cvodes_err,
this);
317 if (m_itol == CV_SV) {
318 flag = CVodeSVtolerances(m_cvode_mem, m_reltol, m_abstol);
320 flag = CVodeSStolerances(m_cvode_mem, m_reltol, m_abstols);
322 if (flag != CV_SUCCESS) {
323 if (flag == CV_MEM_FAIL) {
324 throw CVodesErr(
"Memory allocation failed.");
325 }
else if (flag == CV_ILL_INPUT) {
326 throw CVodesErr(
"Illegal value for CVodeInit input argument.");
334 m_fdata =
new FuncData(&func, func.
nparams());
336 flag = CVodeSetUserData(m_cvode_mem, (
void*)m_fdata);
337 if (flag != CV_SUCCESS) {
338 throw CVodesErr(
"CVodeSetUserData failed.");
342 flag = CVodeSetSensParams(m_cvode_mem,
DATA_PTR(m_fdata->m_pars),
349 void CVodesIntegrator::reinitialize(
double t0,
FuncEval& func)
358 result = CVodeReInit(m_cvode_mem, m_t0, m_y);
359 if (result != CV_SUCCESS) {
367 if (m_type == DENSE + NOJAC) {
368 sd_size_t N =
static_cast<sd_size_t
>(m_neq);
369 #if SUNDIALS_USE_LAPACK
370 CVLapackDense(m_cvode_mem, N);
372 CVDense(m_cvode_mem, N);
374 }
else if (m_type == DIAG) {
376 }
else if (m_type == GMRES) {
377 CVSpgmr(m_cvode_mem, PREC_NONE, 0);
378 }
else if (m_type == BAND + NOJAC) {
379 sd_size_t N =
static_cast<sd_size_t
>(m_neq);
380 long int nu = m_mupper;
381 long int nl = m_mlower;
382 #if SUNDIALS_USE_LAPACK
383 CVLapackBand(m_cvode_mem, N, nu, nl);
385 CVBand(m_cvode_mem, N, nu, nl);
392 CVodeSetMaxOrd(m_cvode_mem, m_maxord);
394 if (m_maxsteps > 0) {
395 CVodeSetMaxNumSteps(m_cvode_mem, m_maxsteps);
398 CVodeSetMaxStep(m_cvode_mem, m_hmax);
401 CVodeSetMinStep(m_cvode_mem, m_hmin);
403 if (m_maxErrTestFails > 0) {
404 CVodeSetMaxErrTestFails(m_cvode_mem, m_maxErrTestFails);
410 int flag = CVode(m_cvode_mem, tout, m_y, &
m_time, CV_NORMAL);
411 if (flag != CV_SUCCESS) {
413 "\nComponents with largest weighted error estimates:\n" +
getErrorInfo(10));
420 int flag = CVode(m_cvode_mem, tout, m_y, &
m_time, CV_ONE_STEP);
421 if (flag != CV_SUCCESS) {
423 "\nComponents with largest weighted error estimates:\n" +
getErrorInfo(10));
433 CVodeGetNumRhsEvals(m_cvode_mem, &ne);
437 double CVodesIntegrator::sensitivity(
size_t k,
size_t p)
444 int flag = CVodeGetSens(m_cvode_mem, &
m_time, m_yS);
445 if (flag != CV_SUCCESS) {
446 throw CVodesErr(
"CVodeGetSens failed. Error code: " +
int2str(flag));
452 throw CVodesErr(
"sensitivity: k out of range ("+
int2str(p)+
")");
455 throw CVodesErr(
"sensitivity: p out of range ("+
int2str(p)+
")");
457 return NV_Ith_S(m_yS[p],k);
462 N_Vector errs = N_VNew_Serial(static_cast<sd_size_t>(m_neq));
463 N_Vector errw = N_VNew_Serial(static_cast<sd_size_t>(m_neq));
464 CVodeGetErrWeights(m_cvode_mem, errw);
465 CVodeGetEstLocalErrors(m_cvode_mem, errs);
467 vector<pair<pair<double, double>,
size_t> > weightedErrors;
468 for (
size_t i=0; i<m_neq; i++) {
469 double err = NV_Ith_S(errs, i) * NV_Ith_S(errw, i);
470 weightedErrors.push_back(make_pair(make_pair(-abs(err), err), i));
475 N = std::min(N, static_cast<int>(m_neq));
476 sort(weightedErrors.begin(), weightedErrors.end());
478 for (
int i=0; i<N; i++) {
479 s << weightedErrors[i].second <<
": "
480 << weightedErrors[i].first.second << endl;
Backward Differentiation.
virtual void setProblemType(int probtype)
Set the problem type.
void applyOptions()
Applies user-specified options to the underlying CVODES solver.
std::string int2str(const int n, const std::string &fmt)
Convert an int to a string using a format converter.
Wrapper class for 'cvodes' integrator from LLNL.
Exception thrown when a CVODES error is encountered.
virtual void eval(double t, double *y, double *ydot, double *p)=0
Evaluate the right-hand-side function.
virtual void setMaxStepSize(double hmax)
Set the maximum step size.
virtual void setMethod(MethodType t)
Set the solution method.
virtual void setMinStepSize(double hmin)
Set the minimum step size.
virtual void setIterator(IterType t)
Set the linear iterator.
virtual int nEvals() const
The number of function evaluations.
virtual double * solution()
The current value of the solution of the system of equations.
const char * what() const
Get a description of the error.
virtual size_t neq()=0
Number of equations.
virtual void integrate(double tout)
Integrate the system of equations.
virtual void setSensitivityTolerances(double reltol, double abstol)
Set the sensitivity error tolerances.
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 size_t nparams()
Number of sensitivity parameters.
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.
virtual void setTolerances(double reltol, size_t n, double *abstol)
Set or reset the number of equations.
virtual void setMaxErrTestFails(int n)
Set the maximum permissible number of error test failures.
bool m_sens_ok
Indicates whether the sensitivities stored in m_yS have been updated for at the current integrator ti...
static int cvodes_rhs(realtype t, N_Vector y, N_Vector ydot, void *f_data)
Function called by cvodes to evaluate ydot given y.
IterType
Specifies the method used for iteration.
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
virtual doublereal step(double tout)
Integrate the system of equations.
Contains declarations for string manipulation functions within Cantera.
std::string m_error_message
Error message information provide by CVodes.
#define DATA_PTR(vec)
Creates a pointer to the start of the raw data for a vector.
Virtual base class for ODE right-hand-side function evaluators.
MethodType
Specifies the method used to integrate the system of equations.
double m_time
The current integrator time.
virtual void getInitialConditions(double t0, size_t leny, double *y)=0
Fill the solution vector with the initial conditions at initial time t0.
virtual void initialize(double t0, FuncEval &func)
Initialize the integrator for a new problem.