| Cantera 3.0.0

Loading...
Searching...
No Matches
CVodesIntegrator.cpp
Go to the documentation of this file.
1//! @file CVodesIntegrator.cpp
2
3// This file is part of Cantera. See License.txt in the top-level directory or
4// at https://cantera.org/license.txt for license and copyright information.
5
6#include "cantera/numerics/CVodesIntegrator.h"
7#include "cantera/base/stringUtils.h"
8
9#include <iostream>
10 using namespace std;
11
12#include "cantera/numerics/sundials_headers.h"
13
14 namespace {
15
16N_Vector newNVector(size_t N, Cantera::SundialsContext& context)
17{
18#if CT_SUNDIALS_VERSION >= 60
19 return N_VNew_Serial(static_cast<sd_size_t>(N), context.get());
20#else
21 return N_VNew_Serial(static_cast<sd_size_t>(N));
22#endif
23}
24
25} // end anonymous namespace
26
27 namespace Cantera
28{
29
30 extern "C" {
31 /**
32 * Function called by cvodes to evaluate ydot given y. The CVODE integrator
33 * allows passing in a void* pointer to access external data. This pointer
34 * is cast to a pointer to a instance of class FuncEval. The equations to be
35 * integrated should be specified by deriving a class from FuncEval that
36 * evaluates the desired equations.
37 * @ingroup odeGroup
38 */
39 static int cvodes_rhs(realtype t, N_Vector y, N_Vector ydot, void* f_data)
40 {
41 FuncEval* f = (FuncEval*) f_data;
42 return f->evalNoThrow(t, NV_DATA_S(y), NV_DATA_S(ydot));
43 }
44
45 //! Function called by CVodes when an error is encountered instead of
46 //! writing to stdout. Here, save the error message provided by CVodes so
47 //! that it can be included in the subsequently raised CanteraError.
48 static void cvodes_err(int error_code, const char* module,
49 const char* function, char* msg, void* eh_data)
50 {
51 CVodesIntegrator* integrator = (CVodesIntegrator*) eh_data;
52 integrator->m_error_message = msg;
53 integrator->m_error_message += "\n";
54 }
55
56 static int cvodes_prec_setup(realtype t, N_Vector y, N_Vector ydot, booleantype jok,
57 booleantype *jcurPtr, realtype gamma, void *f_data)
58 {
59 FuncEval* f = (FuncEval*) f_data;
60 if (!jok) {
61 *jcurPtr = true; // jacobian data was recomputed
62 return f->preconditioner_setup_nothrow(t, NV_DATA_S(y), gamma);
63 } else {
64 f->updatePreconditioner(gamma); // updates preconditioner with new gamma
65 *jcurPtr = false; // indicates that Jacobian data was not recomputed
66 return 0; // no error because not recomputed
67 }
68 }
69
70 static int cvodes_prec_solve(realtype t, N_Vector y, N_Vector ydot, N_Vector r,
71 N_Vector z, realtype gamma, realtype delta, int lr,
72 void* f_data)
73 {
74 FuncEval* f = (FuncEval*) f_data;
75 return f->preconditioner_solve_nothrow(NV_DATA_S(r),NV_DATA_S(z));
76 }
77}
78
79 CVodesIntegrator::CVodesIntegrator()
80 : m_itol(CV_SS)
81 , m_method(CV_BDF)
82{
83}
84
85CVodesIntegrator::~CVodesIntegrator()
86{
87 if (m_cvode_mem) {
88 if (m_np > 0) {
89 CVodeSensFree(m_cvode_mem);
90 }
91 CVodeFree(&m_cvode_mem);
92 }
93
94 SUNLinSolFree((SUNLinearSolver) m_linsol);
95 SUNMatDestroy((SUNMatrix) m_linsol_matrix);
96
97 if (m_y) {
98 N_VDestroy_Serial(m_y);
99 }
100 if (m_abstol) {
101 N_VDestroy_Serial(m_abstol);
102 }
103 if (m_dky) {
104 N_VDestroy_Serial(m_dky);
105 }
106 if (m_yS) {
107 #if CT_SUNDIALS_VERSION >= 60
108 N_VDestroyVectorArray(m_yS, static_cast<int>(m_np));
109 #else
110 N_VDestroyVectorArray_Serial(m_yS, static_cast<int>(m_np));
111 #endif
112 }
113}
114
115
116 double& CVodesIntegrator::solution(size_t k)
117{
118 return NV_Ith_S(m_y, k);
119}
120
121 double* CVodesIntegrator::solution()
122{
123 return NV_DATA_S(m_y);
124}
125
126 void CVodesIntegrator::setTolerances(double reltol, size_t n, double* abstol)
127{
128 m_itol = CV_SV;
129 m_nabs = n;
130 if (n != m_neq) {
131 if (m_abstol) {
132 N_VDestroy_Serial(m_abstol);
133 }
134 m_abstol = newNVector(n, m_sundials_ctx);
135 }
136 for (size_t i=0; i<n; i++) {
137 NV_Ith_S(m_abstol, i) = abstol[i];
138 }
139 m_reltol = reltol;
140}
141
142 void CVodesIntegrator::setTolerances(double reltol, double abstol)
143{
144 m_itol = CV_SS;
145 m_reltol = reltol;
146 m_abstols = abstol;
147}
148
149 void CVodesIntegrator::setSensitivityTolerances(double reltol, double abstol)
150{
151 m_reltolsens = reltol;
152 m_abstolsens = abstol;
153}
154
155 void CVodesIntegrator::setProblemType(int probtype)
156{
157 warn_deprecated("CVodesIntegrator::setProblemType()",
158 "To be removed. Set linear solver type with setLinearSolverType");
159 if (probtype == DIAG)
160 {
161 setLinearSolverType("DIAG");
162 } else if (probtype == DENSE + NOJAC) {
163 setLinearSolverType("DENSE");
164 } else if (probtype == BAND + NOJAC) {
165 setLinearSolverType("BAND");
166 } else if (probtype == GMRES) {
167 setLinearSolverType("GMRES");
168 } else {
169 setLinearSolverType("Invalid Option");
170 }
171}
172
173 void CVodesIntegrator::setMethod(MethodType t)
174{
175 if (t == BDF_Method) {
176 m_method = CV_BDF;
177 } else if (t == Adams_Method) {
178 m_method = CV_ADAMS;
179 } else {
180 throw CanteraError("CVodesIntegrator::setMethod", "unknown method");
181 }
182}
183
184 void CVodesIntegrator::setMaxStepSize(double hmax)
185{
186 m_hmax = hmax;
187 if (m_cvode_mem) {
188 CVodeSetMaxStep(m_cvode_mem, hmax);
189 }
190}
191
192 void CVodesIntegrator::setMinStepSize(double hmin)
193{
194 m_hmin = hmin;
195 if (m_cvode_mem) {
196 CVodeSetMinStep(m_cvode_mem, hmin);
197 }
198}
199
200 void CVodesIntegrator::setMaxSteps(int nmax)
201{
202 m_maxsteps = nmax;
203 if (m_cvode_mem) {
204 CVodeSetMaxNumSteps(m_cvode_mem, m_maxsteps);
205 }
206}
207
208 int CVodesIntegrator::maxSteps()
209{
210 return m_maxsteps;
211}
212
213 void CVodesIntegrator::setMaxErrTestFails(int n)
214{
215 m_maxErrTestFails = n;
216 if (m_cvode_mem) {
217 CVodeSetMaxErrTestFails(m_cvode_mem, n);
218 }
219}
220
221 void CVodesIntegrator::sensInit(double t0, FuncEval& func)
222{
223 m_np = func.nparams();
224 m_sens_ok = false;
225
226 N_Vector y = newNVector(func.neq(), m_sundials_ctx);
227 #if CT_SUNDIALS_VERSION >= 60
228 m_yS = N_VCloneVectorArray(static_cast<int>(m_np), y);
229 #else
230 m_yS = N_VCloneVectorArray_Serial(static_cast<int>(m_np), y);
231 #endif
232 for (size_t n = 0; n < m_np; n++) {
233 N_VConst(0.0, m_yS[n]);
234 }
235 N_VDestroy_Serial(y);
236
237 int flag = CVodeSensInit(m_cvode_mem, static_cast<int>(m_np),
238 CV_STAGGERED, CVSensRhsFn(0), m_yS);
239 checkError(flag, "sensInit", "CVodeSensInit");
240
241 vector<double> atol(m_np);
242 for (size_t n = 0; n < m_np; n++) {
243 // This scaling factor is tuned so that reaction and species enthalpy
244 // sensitivities can be computed simultaneously with the same abstol.
245 atol[n] = m_abstolsens / func.m_paramScales[n];
246 }
247 flag = CVodeSensSStolerances(m_cvode_mem, m_reltolsens, atol.data());
248 checkError(flag, "sensInit", "CVodeSensSStolerances");
249}
250
251 void CVodesIntegrator::initialize(double t0, FuncEval& func)
252{
253 m_neq = func.neq();
254 m_t0 = t0;
255 m_time = t0;
256 m_tInteg = t0;
257 m_func = &func;
258 func.clearErrors();
259 // Initialize preconditioner if applied
260 if (m_prec_side != PreconditionerSide::NO_PRECONDITION) {
261 m_preconditioner->initialize(m_neq);
262 }
263 if (m_y) {
264 N_VDestroy_Serial(m_y); // free solution vector if already allocated
265 }
266 m_y = newNVector(m_neq, m_sundials_ctx); // allocate solution vector
267 N_VConst(0.0, m_y);
268 if (m_dky) {
269 N_VDestroy_Serial(m_dky); // free derivative vector if already allocated
270 }
271 m_dky = newNVector(m_neq, m_sundials_ctx); // allocate derivative vector
272 N_VConst(0.0, m_dky);
273 // check abs tolerance array size
274 if (m_itol == CV_SV && m_nabs < m_neq) {
275 throw CanteraError("CVodesIntegrator::initialize",
276 "not enough absolute tolerance values specified.");
277 }
278
279 func.getState(NV_DATA_S(m_y));
280
281 if (m_cvode_mem) {
282 CVodeFree(&m_cvode_mem);
283 }
284
285 //! Specify the method and the iteration type. Cantera Defaults:
286 //! CV_BDF - Use BDF methods
287 //! CV_NEWTON - use Newton's method
288 #if CT_SUNDIALS_VERSION < 40
289 m_cvode_mem = CVodeCreate(m_method, CV_NEWTON);
290 #elif CT_SUNDIALS_VERSION < 60
291 m_cvode_mem = CVodeCreate(m_method);
292 #else
293 m_cvode_mem = CVodeCreate(m_method, m_sundials_ctx.get());
294 #endif
295 if (!m_cvode_mem) {
296 throw CanteraError("CVodesIntegrator::initialize",
297 "CVodeCreate failed.");
298 }
299
300 int flag = CVodeInit(m_cvode_mem, cvodes_rhs, m_t0, m_y);
301 if (flag != CV_SUCCESS) {
302 if (flag == CV_MEM_FAIL) {
303 throw CanteraError("CVodesIntegrator::initialize",
304 "Memory allocation failed.");
305 } else if (flag == CV_ILL_INPUT) {
306 throw CanteraError("CVodesIntegrator::initialize",
307 "Illegal value for CVodeInit input argument.");
308 } else {
309 throw CanteraError("CVodesIntegrator::initialize",
310 "CVodeInit failed.");
311 }
312 }
313 flag = CVodeSetErrHandlerFn(m_cvode_mem, &cvodes_err, this);
314
315 if (m_itol == CV_SV) {
316 flag = CVodeSVtolerances(m_cvode_mem, m_reltol, m_abstol);
317 checkError(flag, "initialize", "CVodeSVtolerances");
318 } else {
319 flag = CVodeSStolerances(m_cvode_mem, m_reltol, m_abstols);
320 checkError(flag, "initialize", "CVodeSStolerances");
321 }
322
323 flag = CVodeSetUserData(m_cvode_mem, &func);
324 checkError(flag, "initialize", "CVodeSetUserData");
325
326 if (func.nparams() > 0) {
327 sensInit(t0, func);
328 flag = CVodeSetSensParams(m_cvode_mem, func.m_sens_params.data(),
329 func.m_paramScales.data(), NULL);
330 checkError(flag, "initialize", "CVodeSetSensParams");
331 }
332 applyOptions();
333}
334
335 void CVodesIntegrator::reinitialize(double t0, FuncEval& func)
336{
337 m_t0 = t0;
338 m_time = t0;
339 m_tInteg = t0;
340 func.getState(NV_DATA_S(m_y));
341 m_func = &func;
342 func.clearErrors();
343 // reinitialize preconditioner if applied
344 if (m_prec_side != PreconditionerSide::NO_PRECONDITION) {
345 m_preconditioner->initialize(m_neq);
346 }
347 int result = CVodeReInit(m_cvode_mem, m_t0, m_y);
348 checkError(result, "reinitialize", "CVodeReInit");
349 applyOptions();
350}
351
352 void CVodesIntegrator::applyOptions()
353{
354 if (m_type == "DENSE") {
355 sd_size_t N = static_cast<sd_size_t>(m_neq);
356 SUNLinSolFree((SUNLinearSolver) m_linsol);
357 SUNMatDestroy((SUNMatrix) m_linsol_matrix);
358 #if CT_SUNDIALS_VERSION >= 60
359 m_linsol_matrix = SUNDenseMatrix(N, N, m_sundials_ctx.get());
360 #else
361 m_linsol_matrix = SUNDenseMatrix(N, N);
362 #endif
363 if (m_linsol_matrix == nullptr) {
364 throw CanteraError("CVodesIntegrator::applyOptions",
365 "Unable to create SUNDenseMatrix of size {0} x {0}", N);
366 }
367 int flag;
368 #if CT_SUNDIALS_VERSION >= 60
369 #if CT_SUNDIALS_USE_LAPACK
370 m_linsol = SUNLinSol_LapackDense(m_y, (SUNMatrix) m_linsol_matrix,
371 m_sundials_ctx.get());
372 #else
373 m_linsol = SUNLinSol_Dense(m_y, (SUNMatrix) m_linsol_matrix,
374 m_sundials_ctx.get());
375 #endif
376 flag = CVodeSetLinearSolver(m_cvode_mem, (SUNLinearSolver) m_linsol,
377 (SUNMatrix) m_linsol_matrix);
378 #else
379 #if CT_SUNDIALS_USE_LAPACK
380 m_linsol = SUNLapackDense(m_y, (SUNMatrix) m_linsol_matrix);
381 #else
382 m_linsol = SUNDenseLinearSolver(m_y, (SUNMatrix) m_linsol_matrix);
383 #endif
384 flag = CVDlsSetLinearSolver(m_cvode_mem, (SUNLinearSolver) m_linsol,
385 (SUNMatrix) m_linsol_matrix);
386 #endif
387 if (m_linsol == nullptr) {
388 throw CanteraError("CVodesIntegrator::applyOptions",
389 "Error creating Sundials dense linear solver object");
390 } else if (flag != CV_SUCCESS) {
391 throw CanteraError("CVodesIntegrator::applyOptions",
392 "Error connecting linear solver to CVODES. "
393 "Sundials error code: {}", flag);
394 }
395
396 // throw preconditioner error for DENSE + NOJAC
397 if (m_prec_side != PreconditionerSide::NO_PRECONDITION) {
398 throw CanteraError("CVodesIntegrator::applyOptions",
399 "Preconditioning is not available with the specified problem type.");
400 }
401 } else if (m_type == "DIAG") {
402 CVDiag(m_cvode_mem);
403 // throw preconditioner error for DIAG
404 if (m_prec_side != PreconditionerSide::NO_PRECONDITION) {
405 throw CanteraError("CVodesIntegrator::applyOptions",
406 "Preconditioning is not available with the specified problem type.");
407 }
408 } else if (m_type == "GMRES") {
409 #if CT_SUNDIALS_VERSION >= 60
410 m_linsol = SUNLinSol_SPGMR(m_y, PREC_NONE, 0, m_sundials_ctx.get());
411 CVodeSetLinearSolver(m_cvode_mem, (SUNLinearSolver) m_linsol, nullptr);
412 #elif CT_SUNDIALS_VERSION >= 40
413 m_linsol = SUNLinSol_SPGMR(m_y, PREC_NONE, 0);
414 CVSpilsSetLinearSolver(m_cvode_mem, (SUNLinearSolver) m_linsol);
415 # else
416 m_linsol = SUNSPGMR(m_y, PREC_NONE, 0);
417 CVSpilsSetLinearSolver(m_cvode_mem, (SUNLinearSolver) m_linsol);
418 #endif
419 // set preconditioner if used
420 #if CT_SUNDIALS_VERSION >= 40
421 if (m_prec_side != PreconditionerSide::NO_PRECONDITION) {
422 SUNLinSol_SPGMRSetPrecType((SUNLinearSolver) m_linsol,
423 static_cast<int>(m_prec_side));
424 CVodeSetPreconditioner(m_cvode_mem, cvodes_prec_setup,
425 cvodes_prec_solve);
426 }
427 #else
428 if (m_prec_side != PreconditionerSide::NO_PRECONDITION) {
429 SUNSPGMRSetPrecType((SUNLinearSolver) m_linsol,
430 static_cast<int>(m_prec_side));
431 CVSpilsSetPreconditioner(m_cvode_mem, cvodes_prec_setup,
432 cvodes_prec_solve);
433 }
434 #endif
435 } else if (m_type == "BAND") {
436 sd_size_t N = static_cast<sd_size_t>(m_neq);
437 sd_size_t nu = m_mupper;
438 sd_size_t nl = m_mlower;
439 SUNLinSolFree((SUNLinearSolver) m_linsol);
440 SUNMatDestroy((SUNMatrix) m_linsol_matrix);
441 #if CT_SUNDIALS_VERSION >= 60
442 m_linsol_matrix = SUNBandMatrix(N, nu, nl, m_sundials_ctx.get());
443 #elif CT_SUNDIALS_VERSION >= 40
444 m_linsol_matrix = SUNBandMatrix(N, nu, nl);
445 #else
446 m_linsol_matrix = SUNBandMatrix(N, nu, nl, nu+nl);
447 #endif
448 if (m_linsol_matrix == nullptr) {
449 throw CanteraError("CVodesIntegrator::applyOptions",
450 "Unable to create SUNBandMatrix of size {} with bandwidths "
451 "{} and {}", N, nu, nl);
452 }
453 #if CT_SUNDIALS_VERSION >= 60
454 #if CT_SUNDIALS_USE_LAPACK
455 m_linsol = SUNLinSol_LapackBand(m_y, (SUNMatrix) m_linsol_matrix,
456 m_sundials_ctx.get());
457 #else
458 m_linsol = SUNLinSol_Band(m_y, (SUNMatrix) m_linsol_matrix,
459 m_sundials_ctx.get());
460 #endif
461 CVodeSetLinearSolver(m_cvode_mem, (SUNLinearSolver) m_linsol,
462 (SUNMatrix) m_linsol_matrix);
463 #else
464 #if CT_SUNDIALS_USE_LAPACK
465 m_linsol = SUNLapackBand(m_y, (SUNMatrix) m_linsol_matrix);
466 #else
467 m_linsol = SUNBandLinearSolver(m_y, (SUNMatrix) m_linsol_matrix);
468 #endif
469 CVDlsSetLinearSolver(m_cvode_mem, (SUNLinearSolver) m_linsol,
470 (SUNMatrix) m_linsol_matrix);
471 #endif
472 } else {
473 throw CanteraError("CVodesIntegrator::applyOptions",
474 "unsupported linear solver flag '{}'", m_type);
475 }
476
477 if (m_maxord > 0) {
478 int flag = CVodeSetMaxOrd(m_cvode_mem, m_maxord);
479 checkError(flag, "applyOptions", "CVodeSetMaxOrd");
480 }
481 if (m_maxsteps > 0) {
482 CVodeSetMaxNumSteps(m_cvode_mem, m_maxsteps);
483 }
484 if (m_hmax > 0) {
485 CVodeSetMaxStep(m_cvode_mem, m_hmax);
486 }
487 if (m_hmin > 0) {
488 CVodeSetMinStep(m_cvode_mem, m_hmin);
489 }
490 if (m_maxErrTestFails > 0) {
491 CVodeSetMaxErrTestFails(m_cvode_mem, m_maxErrTestFails);
492 }
493}
494
495 void CVodesIntegrator::integrate(double tout)
496{
497 if (tout == m_time) {
498 return;
499 } else if (tout < m_time) {
500 throw CanteraError("CVodesIntegrator::integrate",
501 "Cannot integrate backwards in time.\n"
502 "Requested time {} < current time {}",
503 tout, m_time);
504 }
505 int nsteps = 0;
506 while (m_tInteg < tout) {
507 if (nsteps >= m_maxsteps) {
508 throw CanteraError("CVodesIntegrator::integrate",
509 "Maximum number of timesteps ({}) taken without reaching output "
510 "time ({}).\nCurrent integrator time: {}",
511 nsteps, tout, m_tInteg);
512 }
513 int flag = CVode(m_cvode_mem, tout, m_y, &m_tInteg, CV_ONE_STEP);
514 if (flag != CV_SUCCESS) {
515 string f_errs = m_func->getErrors();
516 if (!f_errs.empty()) {
517 f_errs = "Exceptions caught during RHS evaluation:\n" + f_errs;
518 }
519 throw CanteraError("CVodesIntegrator::integrate",
520 "CVodes error encountered. Error code: {}\n{}\n"
521 "{}"
522 "Components with largest weighted error estimates:\n{}",
523 flag, m_error_message, f_errs, getErrorInfo(10));
524 }
525 nsteps++;
526 }
527 int flag = CVodeGetDky(m_cvode_mem, tout, 0, m_y);
528 checkError(flag, "integrate", "CVodeGetDky");
529 m_time = tout;
530 m_sens_ok = false;
531}
532
533 double CVodesIntegrator::step(double tout)
534{
535 int flag = CVode(m_cvode_mem, tout, m_y, &m_tInteg, CV_ONE_STEP);
536 if (flag != CV_SUCCESS) {
537 string f_errs = m_func->getErrors();
538 if (!f_errs.empty()) {
539 f_errs = "Exceptions caught during RHS evaluation:\n" + f_errs;
540 }
541 throw CanteraError("CVodesIntegrator::step",
542 "CVodes error encountered. Error code: {}\n{}\n"
543 "{}"
544 "Components with largest weighted error estimates:\n{}",
545 flag, f_errs, m_error_message, getErrorInfo(10));
546
547 }
548 m_sens_ok = false;
549 m_time = m_tInteg;
550 return m_time;
551}
552
553 double* CVodesIntegrator::derivative(double tout, int n)
554{
555 int flag = CVodeGetDky(m_cvode_mem, tout, n, m_dky);
556 checkError(flag, "derivative", "CVodeGetDky");
557 return NV_DATA_S(m_dky);
558}
559
560 int CVodesIntegrator::lastOrder() const
561{
562 int ord;
563 CVodeGetLastOrder(m_cvode_mem, &ord);
564 return ord;
565}
566
567 int CVodesIntegrator::nEvals() const
568{
569 long int ne;
570 CVodeGetNumRhsEvals(m_cvode_mem, &ne);
571 return ne;
572}
573
574 AnyMap CVodesIntegrator::solverStats() const
575{
576 // AnyMap to return stats
577 AnyMap stats;
578
579 // long int linear solver stats provided by CVodes
580 long int steps = 0, rhsEvals = 0, errTestFails = 0, jacEvals = 0, linSetup = 0,
581 linRhsEvals = 0, linIters = 0, linConvFails = 0, precEvals = 0,
582 precSolves = 0, jtSetupEvals = 0, jTimesEvals = 0, nonlinIters = 0,
583 nonlinConvFails = 0, orderReductions = 0;
584 int lastOrder = 0;
585;
586 #if CT_SUNDIALS_VERSION >= 40
587 CVodeGetNumSteps(m_cvode_mem, &steps);
588 CVodeGetNumRhsEvals(m_cvode_mem, &rhsEvals);
589 CVodeGetNonlinSolvStats(m_cvode_mem, &nonlinIters, &nonlinConvFails);
590 CVodeGetNumErrTestFails(m_cvode_mem, &errTestFails);
591 CVodeGetLastOrder(m_cvode_mem, &lastOrder);
592 CVodeGetNumStabLimOrderReds(m_cvode_mem, &orderReductions);
593 CVodeGetNumJacEvals(m_cvode_mem, &jacEvals);
594 CVodeGetNumLinRhsEvals(m_cvode_mem, &linRhsEvals);
595 CVodeGetNumLinSolvSetups(m_cvode_mem, &linSetup);
596 CVodeGetNumLinIters(m_cvode_mem, &linIters);
597 CVodeGetNumLinConvFails(m_cvode_mem, &linConvFails);
598 CVodeGetNumPrecEvals(m_cvode_mem, &precEvals);
599 CVodeGetNumPrecSolves(m_cvode_mem, &precSolves);
600 CVodeGetNumJTSetupEvals(m_cvode_mem, &jtSetupEvals);
601 CVodeGetNumJtimesEvals(m_cvode_mem, &jTimesEvals);
602 #else
603 warn_user("CVodesIntegrator::solverStats", "Function not"
604 "supported with sundials versions less than 4.");
605 #endif
606
607 #if CT_SUNDIALS_VERION >= 60
608 long int stepSolveFails = 0;
609 CVodeGetNumStepSolveFails(m_cvode_mem, &stepSolveFails);
610 stats["step_solve_fails"] = stepSolveFails;
611 #endif
612
613 stats["steps"] = steps;
614 stats["rhs_evals"] = rhsEvals;
615 stats["nonlinear_iters"] = nonlinIters;
616 stats["nonlinear_conv_fails"] = nonlinConvFails;
617 stats["err_test_fails"] = errTestFails;
618 stats["last_order"] = lastOrder;
619 stats["stab_order_reductions"] = orderReductions;
620
621 stats["jac_evals"] = jacEvals;
622 stats["lin_solve_setups"] = linSetup;
623 stats["lin_rhs_evals"] = linRhsEvals;
624 stats["lin_iters"] = linIters;
625 stats["lin_conv_fails"] = linConvFails;
626 stats["prec_evals"] = precEvals;
627 stats["prec_solves"] = precSolves;
628 stats["jt_vec_setup_evals"] = jtSetupEvals;
629 stats["jt_vec_prod_evals"] = jTimesEvals;
630 return stats;
631}
632
633 double CVodesIntegrator::sensitivity(size_t k, size_t p)
634{
635 if (m_time == m_t0) {
636 // calls to CVodeGetSens are only allowed after a successful time step.
637 return 0.0;
638 }
639 if (!m_sens_ok && m_np) {
640 int flag = CVodeGetSensDky(m_cvode_mem, m_time, 0, m_yS);
641 checkError(flag, "sensitivity", "CVodeGetSens");
642 m_sens_ok = true;
643 }
644
645 if (k >= m_neq) {
646 throw CanteraError("CVodesIntegrator::sensitivity",
647 "sensitivity: k out of range ({})", k);
648 }
649 if (p >= m_np) {
650 throw CanteraError("CVodesIntegrator::sensitivity",
651 "sensitivity: p out of range ({})", p);
652 }
653 return NV_Ith_S(m_yS[p],k);
654}
655
656 string CVodesIntegrator::getErrorInfo(int N)
657{
658 N_Vector errs = newNVector(m_neq, m_sundials_ctx);
659 N_Vector errw = newNVector(m_neq, m_sundials_ctx);
660 CVodeGetErrWeights(m_cvode_mem, errw);
661 CVodeGetEstLocalErrors(m_cvode_mem, errs);
662
663 vector<tuple<double, double, size_t>> weightedErrors;
664 for (size_t i=0; i<m_neq; i++) {
665 double err = NV_Ith_S(errs, i) * NV_Ith_S(errw, i);
666 weightedErrors.emplace_back(-abs(err), err, i);
667 }
668 N_VDestroy(errs);
669 N_VDestroy(errw);
670
671 N = std::min(N, static_cast<int>(m_neq));
672 sort(weightedErrors.begin(), weightedErrors.end());
673 fmt::memory_buffer s;
674 for (int i=0; i<N; i++) {
675 fmt_append(s, "{}: {}\n",
676 get<2>(weightedErrors[i]), get<1>(weightedErrors[i]));
677 }
678 return to_string(s);
679}
680
681 void CVodesIntegrator::checkError(long flag, const string& ctMethod,
682 const string& cvodesMethod) const
683{
684 if (flag == CV_SUCCESS) {
685 return;
686 } else if (flag == CV_MEM_NULL) {
687 throw CanteraError("CVodesIntegrator::" + ctMethod,
688 "CVODES integrator is not initialized");
689 } else {
690 const char* flagname = CVodeGetReturnFlagName(flag);
691 throw CanteraError("CVodesIntegrator::" + ctMethod,
692 "{} returned error code {} ({}):\n{}",
693 cvodesMethod, flag, flagname, m_error_message);
694 }
695}
696
697}
CVodesIntegrator.h
Cantera::AnyMap
A map of string keys to values whose type can vary at runtime.
Definition AnyMap.h:427
Cantera::CVodesIntegrator
Wrapper class for 'cvodes' integrator from LLNL.
Definition CVodesIntegrator.h:27
Cantera::CVodesIntegrator::step
double step(double tout) override
Integrate the system of equations.
Definition CVodesIntegrator.cpp:533
Cantera::CVodesIntegrator::setMaxStepSize
void setMaxStepSize(double hmax) override
Set the maximum step size.
Definition CVodesIntegrator.cpp:184
Cantera::CVodesIntegrator::solution
double * solution() override
The current value of the solution of the system of equations.
Definition CVodesIntegrator.cpp:121
Cantera::CVodesIntegrator::setProblemType
void setProblemType(int probtype) override
Set the problem type.
Definition CVodesIntegrator.cpp:155
Cantera::CVodesIntegrator::m_y
N_Vector m_y
The system state at m_time.
Definition CVodesIntegrator.h:112
Cantera::CVodesIntegrator::m_linsol
void * m_linsol
Sundials linear solver object.
Definition CVodesIntegrator.h:100
Cantera::CVodesIntegrator::nEvals
int nEvals() const override
The number of function evaluations.
Definition CVodesIntegrator.cpp:567
Cantera::CVodesIntegrator::CVodesIntegrator
CVodesIntegrator()
Constructor.
Definition CVodesIntegrator.cpp:79
Cantera::CVodesIntegrator::m_time
double m_time
The current system time, corresponding to m_y.
Definition CVodesIntegrator.h:106
Cantera::CVodesIntegrator::m_sens_ok
bool m_sens_ok
Indicates whether the sensitivities stored in m_yS have been updated for at the current integrator ti...
Definition CVodesIntegrator.h:135
Cantera::CVodesIntegrator::maxSteps
int maxSteps() override
Returns the maximum number of time-steps the integrator can take before reaching the next output time...
Definition CVodesIntegrator.cpp:208
Cantera::CVodesIntegrator::m_sundials_ctx
SundialsContext m_sundials_ctx
SUNContext object for Sundials>=6.0.
Definition CVodesIntegrator.h:99
Cantera::CVodesIntegrator::setLinearSolverType
void setLinearSolverType(const string &linSolverType) override
Set the linear solver type.
Definition CVodesIntegrator.h:60
Cantera::CVodesIntegrator::checkError
void checkError(long flag, const string &ctMethod, const string &cvodesMethod) const
Check whether a CVODES method indicated an error.
Definition CVodesIntegrator.cpp:681
Cantera::CVodesIntegrator::setSensitivityTolerances
void setSensitivityTolerances(double reltol, double abstol) override
Set the sensitivity error tolerances.
Definition CVodesIntegrator.cpp:149
Cantera::CVodesIntegrator::applyOptions
void applyOptions()
Applies user-specified options to the underlying CVODES solver.
Definition CVodesIntegrator.cpp:352
Cantera::CVodesIntegrator::lastOrder
int lastOrder() const override
Order used during the last solution step.
Definition CVodesIntegrator.cpp:560
Cantera::CVodesIntegrator::setMinStepSize
void setMinStepSize(double hmin) override
Set the minimum step size.
Definition CVodesIntegrator.cpp:192
Cantera::CVodesIntegrator::integrate
void integrate(double tout) override
Integrate the system of equations.
Definition CVodesIntegrator.cpp:495
Cantera::CVodesIntegrator::setTolerances
void setTolerances(double reltol, size_t n, double *abstol) override
Set error tolerances.
Definition CVodesIntegrator.cpp:126
Cantera::CVodesIntegrator::derivative
double * derivative(double tout, int n) override
n-th derivative of the output function at time tout.
Definition CVodesIntegrator.cpp:553
Cantera::CVodesIntegrator::m_error_message
string m_error_message
Error message information provide by CVodes.
Definition CVodesIntegrator.h:83
Cantera::CVodesIntegrator::setMaxErrTestFails
void setMaxErrTestFails(int n) override
Set the maximum permissible number of error test failures.
Definition CVodesIntegrator.cpp:213
Cantera::CVodesIntegrator::setMaxSteps
void setMaxSteps(int nmax) override
Set the maximum number of time-steps the integrator can take before reaching the next output time.
Definition CVodesIntegrator.cpp:200
Cantera::CVodesIntegrator::solverStats
AnyMap solverStats() const override
Get solver stats from integrator.
Definition CVodesIntegrator.cpp:574
Cantera::CVodesIntegrator::m_linsol_matrix
void * m_linsol_matrix
matrix used by Sundials
Definition CVodesIntegrator.h:101
Cantera::CVodesIntegrator::m_tInteg
double m_tInteg
The latest time reached by the integrator. May be greater than m_time.
Definition CVodesIntegrator.h:109
Cantera::CVodesIntegrator::initialize
void initialize(double t0, FuncEval &func) override
Initialize the integrator for a new problem.
Definition CVodesIntegrator.cpp:251
Cantera::CVodesIntegrator::getErrorInfo
string getErrorInfo(int N)
Returns a string listing the weighted error estimates associated with each solution component.
Definition CVodesIntegrator.cpp:656
Cantera::CVodesIntegrator::setMethod
void setMethod(MethodType t) override
Set the solution method.
Definition CVodesIntegrator.cpp:173
Cantera::CanteraError
Base class for exceptions thrown by Cantera classes.
Definition ctexceptions.h:66
Cantera::FuncEval
Virtual base class for ODE/DAE right-hand-side function evaluators.
Definition FuncEval.h:32
Cantera::FuncEval::m_paramScales
vector< double > m_paramScales
Scaling factors for each sensitivity parameter.
Definition FuncEval.h:184
Cantera::FuncEval::clearErrors
void clearErrors()
Clear any previously-stored suppressed errors.
Definition FuncEval.h:174
Cantera::FuncEval::evalNoThrow
int evalNoThrow(double t, double *y, double *ydot)
Evaluate the right-hand side using return code to indicate status.
Definition FuncEval.cpp:7
Cantera::FuncEval::neq
virtual size_t neq() const =0
Number of equations.
Cantera::FuncEval::nparams
virtual size_t nparams() const
Number of sensitivity parameters.
Definition FuncEval.h:156
Cantera::FuncEval::getErrors
string getErrors() const
Return a string containing the text of any suppressed errors.
Definition FuncEval.cpp:71
Cantera::FuncEval::m_sens_params
vector< double > m_sens_params
Values for the problem parameters for which sensitivities are computed This is the array which is per...
Definition FuncEval.h:181
Cantera::FuncEval::getState
virtual void getState(double *y)
Fill in the vector y with the current state of the system.
Definition FuncEval.h:142
Cantera::Integrator::m_preconditioner
shared_ptr< PreconditionerBase > m_preconditioner
Pointer to preconditioner object used in integration which is set by setPreconditioner and initialize...
Definition Integrator.h:320
Cantera::Integrator::m_prec_side
PreconditionerSide m_prec_side
Type of preconditioning used in applyOptions.
Definition Integrator.h:322
Cantera::SundialsContext
A wrapper for managing a SUNContext object, need for Sundials >= 6.0.
Definition SundialsContext.h:20
fmt_append
void fmt_append(fmt::memory_buffer &b, Args... args)
Versions 6.2.0 and 6.2.1 of fmtlib do not include this define before they include windows....
Definition fmt.h:29
Cantera::cvodes_rhs
static int cvodes_rhs(realtype t, N_Vector y, N_Vector ydot, void *f_data)
Function called by cvodes to evaluate ydot given y.
Definition CVodesIntegrator.cpp:39
Cantera::warn_user
void warn_user(const string &method, const string &msg, const Args &... args)
Print a user warning raised from method as CanteraWarning.
Definition global.h:267
Cantera
Namespace for the Cantera kernel.
Definition AnyMap.cpp:564
Cantera::MethodType
MethodType
Specifies the method used to integrate the system of equations.
Definition Integrator.h:30
Cantera::BDF_Method
@ BDF_Method
Backward Differentiation.
Definition Integrator.h:31
Cantera::Adams_Method
@ Adams_Method
Adams.
Definition Integrator.h:32
Cantera::warn_deprecated
void warn_deprecated(const string &source, const AnyBase &node, const string &message)
A deprecation warning for syntax in an input file.
Definition AnyMap.cpp:1926
Cantera::cvodes_err
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.
Definition CVodesIntegrator.cpp:48
stringUtils.h
Contains declarations for string manipulation functions within Cantera.