18ReactorNet::ReactorNet() :
19 m_integ(newIntegrator(
"CVODE")),
20 m_time(0.0), m_init(false), m_integrator_init(false),
21 m_nv(0), m_rtol(1.0e-9), m_rtolsens(1.0e-4),
22 m_atols(1.0e-15), m_atolsens(1.0e-6),
23 m_maxstep(0.0), m_maxErrTestFails(0),
24 m_verbose(false), m_checked_eval_deprecation(false)
31 m_integ->setProblemType(DENSE + NOJAC);
34ReactorNet::~ReactorNet()
38void ReactorNet::setInitialTime(
double time)
41 m_integrator_init =
false;
44void ReactorNet::setMaxTimeStep(
double maxstep)
50void ReactorNet::setMaxErrTestFails(
int nmax)
52 m_maxErrTestFails = nmax;
56void ReactorNet::setTolerances(
double rtol,
double atol)
67void ReactorNet::setSensitivityTolerances(
double rtol,
double atol)
78void ReactorNet::initialize()
81 debuglog(
"Initializing reactor network.\n", m_verbose);
82 if (m_reactors.empty()) {
84 "no reactors in network!");
87 for (
size_t n = 0; n < m_reactors.size(); n++) {
92 m_start.push_back(m_nv);
95 writelog(
"Reactor {:d}: {:d} variables.\n", n, nv);
98 if (r.
type() ==
"FlowReactor" && m_reactors.size() > 1) {
100 "FlowReactors must be used alone.");
104 m_ydot.resize(m_nv,0.0);
105 m_yest.resize(m_nv,0.0);
106 m_advancelimits.resize(m_nv,-1.0);
107 m_atol.resize(neq());
108 fill(m_atol.begin(), m_atol.end(), m_atols);
109 m_integ->setTolerances(m_rtol, neq(), m_atol.data());
110 m_integ->setSensitivityTolerances(m_rtolsens, m_atolsens);
111 m_integ->setMaxStepSize(m_maxstep);
112 m_integ->setMaxErrTestFails(m_maxErrTestFails);
114 writelog(
"Number of equations: {:d}\n", neq());
115 writelog(
"Maximum time step: {:14.6g}\n", m_maxstep);
117 m_integ->initialize(m_time, *
this);
118 m_integrator_init =
true;
122void ReactorNet::reinitialize()
125 debuglog(
"Re-initializing reactor network.\n", m_verbose);
126 m_integ->reinitialize(m_time, *
this);
127 m_integrator_init =
true;
133void ReactorNet::setMaxSteps(
int nmax)
135 m_integ->setMaxSteps(nmax);
138int ReactorNet::maxSteps()
140 return m_integ->maxSteps();
143void ReactorNet::advance(doublereal time)
147 }
else if (!m_integrator_init) {
150 m_integ->integrate(time);
152 updateState(m_integ->solution());
155double ReactorNet::advance(
double time,
bool applylimit)
159 }
else if (!m_integrator_init) {
169 if (!hasAdvanceLimits()) {
175 getAdvanceLimits(m_advancelimits.data());
178 while (lastOrder() < 1) {
183 double t = time, delta;
184 double* y = m_integ->solution();
188 bool exceeded =
false;
189 getEstimate(t, k, &m_yest[0]);
190 for (
size_t j = 0; j < m_nv; j++) {
191 delta = abs(m_yest[j] - y[j]);
192 if ( (m_advancelimits[j] > 0.) && ( delta > m_advancelimits[j]) ) {
195 writelog(
" Limiting global state vector component {:d} (dt = {:9.4g}):"
196 "{:11.6g} > {:9.4g}\n",
197 j, t - m_time, delta, m_advancelimits[j]);
204 t = .5 * (m_time + t);
210double ReactorNet::step()
214 }
else if (!m_integrator_init) {
217 m_time = m_integ->step(m_time + 1.0);
218 updateState(m_integ->solution());
222void ReactorNet::getEstimate(
double time,
int k,
double* yest)
225 double* cvode_dky = m_integ->solution();
226 for (
size_t j = 0; j < m_nv; j++) {
227 yest[j] = cvode_dky[j];
232 double deltat = time - m_time;
233 for (
int n = 1; n <= k; n++) {
234 factor *= deltat / n;
235 cvode_dky = m_integ->derivative(m_time, n);
236 for (
size_t j = 0; j < m_nv; j++) {
237 yest[j] += factor * cvode_dky[j];
242int ReactorNet::lastOrder()
244 return m_integ->lastOrder();
250 m_reactors.push_back(&r);
253void ReactorNet::eval(doublereal t, doublereal* y,
254 doublereal* ydot, doublereal* p)
258 m_LHS.assign(m_nv, 1);
259 m_RHS.assign(m_nv, 0);
260 if (!m_checked_eval_deprecation) {
261 m_have_deprecated_eval.assign(m_reactors.size(),
false);
262 for (
size_t n = 0; n < m_reactors.size(); n++) {
263 m_reactors[n]->applySensitivity(p);
265 m_reactors[n]->evalEqs(t, y + m_start[n], ydot + m_start[n], p);
267 "::evalEqs(double t, double* y , double* ydot, double* params)",
268 "Reactor time derivative evaluation now uses signature "
269 "eval(double t, double* ydot)");
270 m_have_deprecated_eval[n] =
true;
272 m_reactors[n]->eval(t, m_LHS.data() + m_start[n], m_RHS.data() + m_start[n]);
274 if (n == m_reactors.size() - 1) {
277 yEnd = m_start[n + 1];
279 for (
size_t i = m_start[n]; i < yEnd; i++) {
280 ydot[i] = m_RHS[i] / m_LHS[i];
283 m_reactors[n]->resetSensitivity(p);
285 m_checked_eval_deprecation =
true;
287 for (
size_t n = 0; n < m_reactors.size(); n++) {
288 m_reactors[n]->applySensitivity(p);
289 if (m_have_deprecated_eval[n]) {
290 m_reactors[n]->evalEqs(t, y + m_start[n], ydot + m_start[n], p);
292 m_reactors[n]->eval(t, m_LHS.data() + m_start[n], m_RHS.data() + m_start[n]);
294 if (n == m_reactors.size() - 1) {
297 yEnd = m_start[n + 1];
299 for (
size_t i = m_start[n]; i < yEnd; i++) {
300 ydot[i] = m_RHS[i] / m_LHS[i];
303 m_reactors[n]->resetSensitivity(p);
309double ReactorNet::sensitivity(
size_t k,
size_t p)
314 if (p >= m_sens_params.size()) {
316 "m_sens_params", p, m_sens_params.size()-1);
318 double denom = m_integ->solution(k);
322 return m_integ->sensitivity(k, p) / denom;
325void ReactorNet::evalJacobian(doublereal t, doublereal* y,
326 doublereal* ydot, doublereal* p,
Array2D* j)
330 for (
size_t n = 0; n < m_nv; n++) {
333 double dy = m_atol[n] + fabs(ysave)*m_rtol;
338 eval(t, y, m_ydot.data(), p);
341 for (
size_t m = 0; m < m_nv; m++) {
342 j->
value(m,n) = (m_ydot[m] - ydot[m])/dy;
348void ReactorNet::updateState(doublereal* y)
351 for (
size_t n = 0; n < m_reactors.size(); n++) {
352 m_reactors[n]->updateState(y + m_start[n]);
356void ReactorNet::getState(
double* y)
358 for (
size_t n = 0; n < m_reactors.size(); n++) {
359 m_reactors[n]->getState(y + m_start[n]);
363void ReactorNet::getDerivative(
int k,
double* dky)
365 double* cvode_dky = m_integ->derivative(m_time, k);
366 for (
size_t j = 0; j < m_nv; j++) {
367 dky[j] = cvode_dky[j];
371void ReactorNet::setAdvanceLimits(
const double *limits)
376 for (
size_t n = 0; n < m_reactors.size(); n++) {
377 m_reactors[n]->setAdvanceLimits(limits + m_start[n]);
381bool ReactorNet::hasAdvanceLimits()
383 bool has_limit =
false;
384 for (
size_t n = 0; n < m_reactors.size(); n++) {
385 has_limit |= m_reactors[n]->hasAdvanceLimits();
390bool ReactorNet::getAdvanceLimits(
double *limits)
392 bool has_limit =
false;
393 for (
size_t n = 0; n < m_reactors.size(); n++) {
394 has_limit |= m_reactors[n]->getAdvanceLimits(limits + m_start[n]);
399size_t ReactorNet::globalComponentIndex(
const string& component,
size_t reactor)
404 return m_start[reactor] + m_reactors[reactor]->componentIndex(component);
407std::string ReactorNet::componentName(
size_t i)
const
409 for (
auto r : m_reactors) {
411 return r->name() +
": " + r->componentName(i);
416 throw CanteraError(
"ReactorNet::componentName",
"Index out of bounds");
419size_t ReactorNet::registerSensitivityParameter(
420 const std::string& name,
double value,
double scale)
422 if (m_integrator_init) {
423 throw CanteraError(
"ReactorNet::registerSensitivityParameter",
424 "Sensitivity parameters cannot be added after the"
425 "integrator has been initialized.");
427 m_paramNames.push_back(name);
428 m_sens_params.push_back(value);
429 m_paramScales.push_back(
scale);
430 return m_sens_params.size() - 1;
Header file for class Cantera::Array2D.
Header file for base class WallBase.
A class for 2D arrays stored in column-major (Fortran-compatible) form.
doublereal & value(size_t i, size_t j)
Returns a changeable reference to position in the matrix.
Base class for exceptions thrown by Cantera classes.
An array index is out of range.
An error indicating that an unimplemented function has been called.
void setNetwork(ReactorNet *net)
Set the ReactorNet that this reactor belongs to.
Class Reactor is a general-purpose class for stirred reactors.
size_t neq()
Number of equations (state variables) for this reactor.
virtual std::string type() const
String indicating the reactor model implemented.
virtual void initialize(doublereal t0=0.0)
Initialize the reactor.
virtual size_t nSensParams()
Number of sensitivity parameters associated with this reactor (including walls)
void writelog(const std::string &fmt, const Args &... args)
Write a formatted message to the screen.
Namespace for the Cantera kernel.
void checkFinite(const double tmp)
Check to see that a number is finite (not NaN, +Inf or -Inf)
@ BDF_Method
Backward Differentiation.
void warn_deprecated(const std::string &source, const AnyBase &node, const std::string &message)
A deprecation warning for syntax in an input file.
void debuglog(const std::string &msg, int loglevel)
Write a message to the log only if loglevel > 0.
const double SmallNumber
smallest number to compare to zero.
void scale(InputIter begin, InputIter end, OutputIter out, S scale_factor)
Multiply elements of an array by a scale factor.
Various templated functions that carry out common vector operations (see Templated Utility Functions)...