Cantera  3.2.0a2
Loading...
Searching...
No Matches
ReactorNet.cpp
Go to the documentation of this file.
1//! @file ReactorNet.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
11#include "cantera/base/Array.h"
18
19#include <cstdio>
20
21namespace Cantera
22{
23
24ReactorNet::ReactorNet()
25{
26 suppressErrors(true);
27}
28
29ReactorNet::ReactorNet(shared_ptr<ReactorBase> reactor)
30{
31 suppressErrors(true);
33}
34
35ReactorNet::ReactorNet(vector<shared_ptr<ReactorBase>>& reactors)
36{
37 suppressErrors(true);
38 for (auto& reactor : reactors) {
40 }
41}
42
43ReactorNet::~ReactorNet()
44{
45}
46
48{
49 m_time = time;
51 m_integrator_init = false;
52}
53
54void ReactorNet::setMaxTimeStep(double maxstep)
55{
56 m_maxstep = maxstep;
58}
59
61{
63}
64
65void ReactorNet::setTolerances(double rtol, double atol)
66{
67 if (rtol >= 0.0) {
68 m_rtol = rtol;
69 }
70 if (atol >= 0.0) {
71 m_atols = atol;
72 }
73 m_init = false;
74}
75
76void ReactorNet::setSensitivityTolerances(double rtol, double atol)
77{
78 if (rtol >= 0.0) {
79 m_rtolsens = rtol;
80 }
81 if (atol >= 0.0) {
82 m_atolsens = atol;
83 }
84 m_init = false;
85}
86
89 return m_time;
90 } else {
91 throw CanteraError("ReactorNet::time", "Time is not the independent variable"
92 " for this reactor network.");
93 }
94}
95
98 return m_time;
99 } else {
100 throw CanteraError("ReactorNet::distance", "Distance is not the independent"
101 " variable for this reactor network.");
102 }
103}
104
106{
107 m_nv = 0;
108 debuglog("Initializing reactor network.\n", m_verbose);
109 if (m_reactors.empty()) {
110 throw CanteraError("ReactorNet::initialize",
111 "no reactors in network!");
112 }
113 m_start.assign(1, 0);
114 for (size_t n = 0; n < m_reactors.size(); n++) {
115 Reactor& r = *m_reactors[n];
117 size_t nv = r.neq();
118 m_nv += nv;
119 m_start.push_back(m_nv);
120
121 if (m_verbose) {
122 writelog("Reactor {:d}: {:d} variables.\n", n, nv);
123 writelog(" {:d} sensitivity params.\n", r.nSensParams());
124 }
125 if (r.type() == "FlowReactor" && m_reactors.size() > 1) {
126 throw CanteraError("ReactorNet::initialize",
127 "FlowReactors must be used alone.");
128 }
129 }
130
131 m_ydot.resize(m_nv,0.0);
132 m_yest.resize(m_nv,0.0);
133 m_advancelimits.resize(m_nv,-1.0);
134 m_atol.resize(neq());
135 fill(m_atol.begin(), m_atol.end(), m_atols);
136 m_integ->setTolerances(m_rtol, neq(), m_atol.data());
137 m_integ->setSensitivityTolerances(m_rtolsens, m_atolsens);
138 if (!m_linearSolverType.empty()) {
139 m_integ->setLinearSolverType(m_linearSolverType);
140 }
141 if (m_precon) {
142 m_integ->setPreconditioner(m_precon);
143 }
144 m_integ->initialize(m_time, *this);
145 if (m_verbose) {
146 writelog("Number of equations: {:d}\n", neq());
147 writelog("Maximum time step: {:14.6g}\n", m_maxstep);
148 }
149 if (m_integ->preconditionerSide() != PreconditionerSide::NO_PRECONDITION) {
151 }
152 m_integrator_init = true;
153 m_init = true;
154}
155
157{
158 if (m_init) {
159 debuglog("Re-initializing reactor network.\n", m_verbose);
160 m_integ->reinitialize(m_time, *this);
161 if (m_integ->preconditionerSide() != PreconditionerSide::NO_PRECONDITION) {
163 }
164 m_integrator_init = true;
165 } else {
166 initialize();
167 }
168}
169
170void ReactorNet::setLinearSolverType(const string& linSolverType)
171{
172 m_linearSolverType = linSolverType;
173 m_integrator_init = false;
174}
175
176void ReactorNet::setPreconditioner(shared_ptr<SystemJacobian> preconditioner)
177{
178 m_precon = preconditioner;
179 m_integrator_init = false;
180}
181
183{
184 integrator().setMaxSteps(nmax);
185}
186
188{
189 return integrator().maxSteps();
190}
191
192void ReactorNet::advance(double time)
193{
194 if (!m_init) {
195 initialize();
196 } else if (!m_integrator_init) {
197 reinitialize();
198 }
199 m_integ->integrate(time);
200 m_time = time;
201 updateState(m_integ->solution());
202}
203
204double ReactorNet::advance(double time, bool applylimit)
205{
206 if (!m_init) {
207 initialize();
208 } else if (!m_integrator_init) {
209 reinitialize();
210 }
211
212 if (!applylimit) {
213 // take full step
214 advance(time);
215 return time;
216 }
217
218 if (!hasAdvanceLimits()) {
219 // take full step
220 advance(time);
221 return time;
222 }
223
224 getAdvanceLimits(m_advancelimits.data());
225
226 // ensure that gradient is available
227 while (lastOrder() < 1) {
228 step();
229 }
230
231 int k = lastOrder();
232 double t = time, delta;
233 double* y = m_integ->solution();
234
235 // reduce time step if limits are exceeded
236 while (true) {
237 bool exceeded = false;
238 getEstimate(t, k, &m_yest[0]);
239 for (size_t j = 0; j < m_nv; j++) {
240 delta = abs(m_yest[j] - y[j]);
241 if ( (m_advancelimits[j] > 0.) && ( delta > m_advancelimits[j]) ) {
242 exceeded = true;
243 if (m_verbose) {
244 writelog(" Limiting global state vector component {:d} (dt = {:9.4g}):"
245 "{:11.6g} > {:9.4g}\n",
246 j, t - m_time, delta, m_advancelimits[j]);
247 }
248 }
249 }
250 if (!exceeded) {
251 break;
252 }
253 t = .5 * (m_time + t);
254 }
255 advance(t);
256 return t;
257}
258
260{
261 if (!m_init) {
262 initialize();
263 } else if (!m_integrator_init) {
264 reinitialize();
265 }
266 m_time = m_integ->step(m_time + 1.0);
267 updateState(m_integ->solution());
268 return m_time;
269}
270
271void ReactorNet::solveSteady(int loglevel)
272{
273 if (!m_init) {
274 initialize();
275 } else if (!m_integrator_init) {
276 reinitialize();
277 }
278 vector<double> y(neq());
279 getState(y.data());
280 SteadyReactorSolver solver(this, y.data());
282 solver.solve(loglevel);
283 solver.getState(y.data());
284 updateState(y.data());
285}
286
287Eigen::SparseMatrix<double> ReactorNet::steadyJacobian(double rdt)
288{
289 if (!m_init) {
290 initialize();
291 } else if (!m_integrator_init) {
292 reinitialize();
293 }
294 vector<double> y0(neq());
295 vector<double> y1(neq());
296 getState(y0.data());
297 SteadyReactorSolver solver(this, y0.data());
298 solver.evalJacobian(y0.data());
299 if (rdt) {
300 solver.linearSolver()->updateTransient(rdt, solver.transientMask().data());
301 }
302 return std::dynamic_pointer_cast<EigenSparseJacobian>(solver.linearSolver())->jacobian();
303}
304
305void ReactorNet::getEstimate(double time, int k, double* yest)
306{
307 if (!m_init) {
308 initialize();
309 }
310 // initialize
311 double* cvode_dky = m_integ->solution();
312 for (size_t j = 0; j < m_nv; j++) {
313 yest[j] = cvode_dky[j];
314 }
315
316 // Taylor expansion
317 double factor = 1.;
318 double deltat = time - m_time;
319 for (int n = 1; n <= k; n++) {
320 factor *= deltat / n;
321 cvode_dky = m_integ->derivative(m_time, n);
322 for (size_t j = 0; j < m_nv; j++) {
323 yest[j] += factor * cvode_dky[j];
324 }
325 }
326}
327
329{
330 if (m_integ) {
331 return m_integ->lastOrder();
332 } else {
333 return 0;
334 }
335}
336
338{
339 warn_deprecated("ReactorNet::addReactor",
340 "To be removed after Cantera 3.2. Replaceable by reactor net "
341 "instantiation with contents.");
342 for (auto current : m_reactors) {
343 if (current->isOde() != r.isOde()) {
344 throw CanteraError("ReactorNet::addReactor",
345 "Cannot mix Reactor types using both ODEs and DAEs ({} and {})",
346 current->type(), r.type());
347 }
348 if (current->timeIsIndependent() != r.timeIsIndependent()) {
349 throw CanteraError("ReactorNet::addReactor",
350 "Cannot mix Reactor types using time and space as independent variables"
351 "\n({} and {})", current->type(), r.type());
352 }
353 }
355 r.setNetwork(this);
356 m_reactors.push_back(&r);
357 if (!m_integ) {
358 m_integ.reset(newIntegrator(r.isOde() ? "CVODE" : "IDA"));
359 // use backward differencing, with a full Jacobian computed
360 // numerically, and use a Newton linear iterator
361 m_integ->setMethod(BDF_Method);
362 m_integ->setLinearSolverType("DENSE");
363 }
364 updateNames(r);
365}
366
367void ReactorNet::addReactor(shared_ptr<ReactorBase> reactor)
368{
369 auto r = std::dynamic_pointer_cast<Reactor>(reactor);
370 if (!r) {
371 throw CanteraError("ReactorNet::addReactor",
372 "Reactor with type '{}' cannot be added to network.",
373 reactor->type());
374 }
375
376 for (auto current : m_reactors) {
377 if (current->isOde() != r->isOde()) {
378 throw CanteraError("ReactorNet::addReactor",
379 "Cannot mix Reactor types using both ODEs and DAEs ({} and {})",
380 current->type(), r->type());
381 }
382 if (current->timeIsIndependent() != r->timeIsIndependent()) {
383 throw CanteraError("ReactorNet::addReactor",
384 "Cannot mix Reactor types using time and space as independent variables"
385 "\n({} and {})", current->type(), r->type());
386 }
387 }
388 m_timeIsIndependent = r->timeIsIndependent();
389 r->setNetwork(this);
390 m_reactors.push_back(r.get());
391 if (!m_integ) {
392 m_integ.reset(newIntegrator(r->isOde() ? "CVODE" : "IDA"));
393 // use backward differencing, with a full Jacobian computed
394 // numerically, and use a Newton linear iterator
395 m_integ->setMethod(BDF_Method);
396 m_integ->setLinearSolverType("DENSE");
397 }
398 updateNames(*r);
399}
400
402{
403 // ensure that reactors and components have reproducible names
405
406 for (size_t i=0; i<r.nWalls(); i++) {
407 auto& w = r.wall(i);
409 if (w.left().type() == "Reservoir") {
410 w.left().setDefaultName(m_counts);
411 }
412 if (w.right().type() == "Reservoir") {
413 w.right().setDefaultName(m_counts);
414 }
415 }
416
417 for (size_t i=0; i<r.nInlets(); i++) {
418 auto& in = r.inlet(i);
420 if (in.in().type() == "Reservoir") {
421 in.in().setDefaultName(m_counts);
422 }
423 }
424
425 for (size_t i=0; i<r.nOutlets(); i++) {
426 auto& out = r.outlet(i);
428 if (out.out().type() == "Reservoir") {
429 out.out().setDefaultName(m_counts);
430 }
431 }
432
433 for (size_t i=0; i<r.nSurfs(); i++) {
435 }
436}
437
439 if (m_integ == nullptr) {
440 throw CanteraError("ReactorNet::integrator",
441 "Integrator has not been instantiated. Add one or more reactors first.");
442 }
443 return *m_integ;
444}
445
446void ReactorNet::eval(double t, double* y, double* ydot, double* p)
447{
448 m_time = t;
449 updateState(y);
450 m_LHS.assign(m_nv, 1);
451 m_RHS.assign(m_nv, 0);
452 for (size_t n = 0; n < m_reactors.size(); n++) {
453 m_reactors[n]->applySensitivity(p);
454 m_reactors[n]->eval(t, m_LHS.data() + m_start[n], m_RHS.data() + m_start[n]);
455 size_t yEnd = 0;
456 if (n == m_reactors.size() - 1) {
457 yEnd = m_RHS.size();
458 } else {
459 yEnd = m_start[n + 1];
460 }
461 for (size_t i = m_start[n]; i < yEnd; i++) {
462 ydot[i] = m_RHS[i] / m_LHS[i];
463 }
464 m_reactors[n]->resetSensitivity(p);
465 }
466 checkFinite("ydot", ydot, m_nv);
467}
468
469void ReactorNet::evalDae(double t, double* y, double* ydot, double* p, double* residual)
470{
471 m_time = t;
472 updateState(y);
473 for (size_t n = 0; n < m_reactors.size(); n++) {
474 m_reactors[n]->applySensitivity(p);
475 m_reactors[n]->evalDae(t, y, ydot, residual);
476 m_reactors[n]->resetSensitivity(p);
477 }
478 checkFinite("ydot", ydot, m_nv);
479}
480
481void ReactorNet::getConstraints(double* constraints)
482{
483 for (size_t n = 0; n < m_reactors.size(); n++) {
484 m_reactors[n]->getConstraints(constraints + m_start[n]);
485 }
486}
487
488double ReactorNet::sensitivity(size_t k, size_t p)
489{
490 if (!m_init) {
491 initialize();
492 }
493 if (p >= m_sens_params.size()) {
494 throw IndexError("ReactorNet::sensitivity",
495 "m_sens_params", p, m_sens_params.size());
496 }
497 double denom = m_integ->solution(k);
498 if (denom == 0.0) {
499 denom = SmallNumber;
500 }
501 return m_integ->sensitivity(k, p) / denom;
502}
503
504void ReactorNet::evalJacobian(double t, double* y, double* ydot, double* p, Array2D* j)
505{
506 //evaluate the unperturbed ydot
507 eval(t, y, ydot, p);
508 for (size_t n = 0; n < m_nv; n++) {
509 // perturb x(n)
510 double ysave = y[n];
511 double dy = m_atol[n] + fabs(ysave)*m_rtol;
512 y[n] = ysave + dy;
513 dy = y[n] - ysave;
514
515 // calculate perturbed residual
516 eval(t, y, m_ydot.data(), p);
517
518 // compute nth column of Jacobian
519 for (size_t m = 0; m < m_nv; m++) {
520 j->value(m,n) = (m_ydot[m] - ydot[m])/dy;
521 }
522 y[n] = ysave;
523 }
524}
525
527{
528 checkFinite("y", y, m_nv);
529 for (size_t n = 0; n < m_reactors.size(); n++) {
530 m_reactors[n]->updateState(y + m_start[n]);
531 }
532}
533
534void ReactorNet::getDerivative(int k, double* dky)
535{
536 if (!m_init) {
537 initialize();
538 }
539 double* cvode_dky = m_integ->derivative(m_time, k);
540 for (size_t j = 0; j < m_nv; j++) {
541 dky[j] = cvode_dky[j];
542 }
543}
544
545void ReactorNet::setAdvanceLimits(const double *limits)
546{
547 if (!m_init) {
548 initialize();
549 }
550 for (size_t n = 0; n < m_reactors.size(); n++) {
551 m_reactors[n]->setAdvanceLimits(limits + m_start[n]);
552 }
553}
554
556{
557 bool has_limit = false;
558 for (size_t n = 0; n < m_reactors.size(); n++) {
559 has_limit |= m_reactors[n]->hasAdvanceLimits();
560 }
561 return has_limit;
562}
563
564bool ReactorNet::getAdvanceLimits(double *limits) const
565{
566 bool has_limit = false;
567 for (size_t n = 0; n < m_reactors.size(); n++) {
568 has_limit |= m_reactors[n]->getAdvanceLimits(limits + m_start[n]);
569 }
570 return has_limit;
571}
572
573void ReactorNet::getState(double* y)
574{
575 for (size_t n = 0; n < m_reactors.size(); n++) {
576 m_reactors[n]->getState(y + m_start[n]);
577 }
578}
579
580void ReactorNet::getStateDae(double* y, double* ydot)
581{
582 for (size_t n = 0; n < m_reactors.size(); n++) {
583 m_reactors[n]->getStateDae(y + m_start[n], ydot + m_start[n]);
584 }
585}
586
587size_t ReactorNet::globalComponentIndex(const string& component, size_t reactor)
588{
589 if (!m_init) {
590 initialize();
591 }
592 return m_start[reactor] + m_reactors[reactor]->componentIndex(component);
593}
594
595string ReactorNet::componentName(size_t i) const
596{
597 for (auto r : m_reactors) {
598 if (i < r->neq()) {
599 return r->name() + ": " + r->componentName(i);
600 } else {
601 i -= r->neq();
602 }
603 }
604 throw CanteraError("ReactorNet::componentName", "Index out of bounds");
605}
606
607double ReactorNet::upperBound(size_t i) const
608{
609 size_t i0 = i;
610 for (auto r : m_reactors) {
611 if (i < r->neq()) {
612 return r->upperBound(i);
613 } else {
614 i -= r->neq();
615 }
616 }
617 throw CanteraError("ReactorNet::upperBound", "Index {} out of bounds", i0);
618}
619
620double ReactorNet::lowerBound(size_t i) const
621{
622 size_t i0 = i;
623 for (auto r : m_reactors) {
624 if (i < r->neq()) {
625 return r->lowerBound(i);
626 } else {
627 i -= r->neq();
628 }
629 }
630 throw CanteraError("ReactorNet::lowerBound", "Index {} out of bounds", i0);
631}
632
634 size_t i = 0;
635 for (auto r : m_reactors) {
636 r->resetBadValues(y + m_start[i++]);
637 }
638}
639
641 const string& name, double value, double scale)
642{
643 if (m_integrator_init) {
644 throw CanteraError("ReactorNet::registerSensitivityParameter",
645 "Sensitivity parameters cannot be added after the"
646 "integrator has been initialized.");
647 }
648 m_paramNames.push_back(name);
649 m_sens_params.push_back(value);
650 m_paramScales.push_back(scale);
651 return m_sens_params.size() - 1;
652}
653
655{
656 // Apply given settings to all reactors
657 for (size_t i = 0; i < m_reactors.size(); i++) {
658 m_reactors[i]->setDerivativeSettings(settings);
659 }
660}
661
663{
664 if (m_integ) {
665 return m_integ->solverStats();
666 } else {
667 return AnyMap();
668 }
669}
670
672{
673 if (m_integ) {
674 return m_integ->linearSolverType();
675 } else {
676 return "";
677 }
678}
679
680void ReactorNet::preconditionerSolve(double* rhs, double* output)
681{
682 if (!m_integ) {
683 throw CanteraError("ReactorNet::preconditionerSolve",
684 "Must only be called after ReactorNet is initialized.");
685 }
686 m_integ->preconditionerSolve(m_nv, rhs, output);
687}
688
689void ReactorNet::preconditionerSetup(double t, double* y, double gamma)
690{
691 // ensure state is up to date.
692 updateState(y);
693 // get the preconditioner
694 auto precon = m_integ->preconditioner();
695 // Reset preconditioner
696 precon->reset();
697 // Set gamma value for M =I - gamma*J
698 precon->setGamma(gamma);
699 // Make a copy of state to adjust it for preconditioner
700 vector<double> yCopy(m_nv);
701 // Get state of reactor
702 getState(yCopy.data());
703 // transform state based on preconditioner rules
704 precon->stateAdjustment(yCopy);
705 // update network with adjusted state
706 updateState(yCopy.data());
707 // Get jacobians and give elements to preconditioners
708 for (size_t i = 0; i < m_reactors.size(); i++) {
709 Eigen::SparseMatrix<double> rJac = m_reactors[i]->jacobian();
710 for (int k=0; k<rJac.outerSize(); ++k) {
711 for (Eigen::SparseMatrix<double>::InnerIterator it(rJac, k); it; ++it) {
712 precon->setValue(it.row() + m_start[i], it.col() + m_start[i],
713 it.value());
714 }
715 }
716 }
717 // post reactor setup operations
718 precon->updatePreconditioner();
719}
720
722{
723 if (!m_integ) {
724 throw CanteraError("ReactorNet::updatePreconditioner",
725 "Must only be called after ReactorNet is initialized.");
726 }
727 auto precon = m_integ->preconditioner();
728 precon->setGamma(gamma);
729 precon->updatePreconditioner();
730}
731
733 // check for non-mole-based reactors and throw an error otherwise
734 for (auto reactor : m_reactors) {
736 throw CanteraError("ReactorNet::checkPreconditionerSupported",
737 "Preconditioning is only supported for type *MoleReactor,\n"
738 "Reactor type given: '{}'.",
739 reactor->type());
740 }
741 }
742}
743
744SteadyReactorSolver::SteadyReactorSolver(ReactorNet* net, double* x0)
745 : m_net(net)
746{
747 m_size = m_net->neq();
748 m_jac = newSystemJacobian("eigen-sparse-direct");
750 m_initialState.assign(x0, x0 + m_size);
751 setInitialGuess(x0);
752 m_mask.assign(m_size, 1);
753 size_t start = 0;
754 for (size_t i = 0; i < net->nReactors(); i++) {
755 auto& R = net->reactor(i);
756 for (auto& m : R.steadyConstraints()) {
757 m_algebraic.push_back(start + m);
758 }
759 start += R.neq();
760 }
761 for (auto& n : m_algebraic) {
762 m_mask[n] = 0;
763 }
764}
765
766void SteadyReactorSolver::eval(double* x, double* r, double rdt, int count)
767{
768 if (rdt < 0.0) {
769 rdt = m_rdt;
770 }
771 vector<double> xv(x, x + size());
772 m_net->eval(0.0, x, r, nullptr);
773 for (size_t i = 0; i < size(); i++) {
774 r[i] -= (x[i] - m_initialState[i]) * rdt;
775 }
776 // Hold algebraic constraints fixed
777 for (auto& n : m_algebraic) {
778 r[n] = x[n] - m_initialState[n];
779 }
780}
781
782void SteadyReactorSolver::initTimeInteg(double dt, double* x)
783{
785 m_initialState.assign(x, x + size());
786}
787
789{
790 m_jac->reset();
791 clock_t t0 = clock();
792 m_work1.resize(size());
793 m_work2.resize(size());
794 eval(x0, m_work1.data(), 0.0, 0);
795 for (size_t j = 0; j < size(); j++) {
796 // perturb x(n); preserve sign(x(n))
797 double xsave = x0[j];
798 double dx = fabs(xsave) * m_jacobianRelPerturb + m_jacobianAbsPerturb;
799 if (xsave < 0) {
800 dx = -dx;
801 }
802 x0[j] = xsave + dx;
803 double rdx = 1.0 / (x0[j] - xsave);
804
805 // calculate perturbed residual
806 eval(x0, m_work2.data(), 0.0, 0);
807
808 // compute nth column of Jacobian
809 for (size_t i = 0; i < size(); i++) {
810 double delta = m_work2[i] - m_work1[i];
811 if (std::abs(delta) > m_jacobianThreshold || i == j) {
812 m_jac->setValue(i, j, delta * rdx);
813 }
814 }
815 x0[j] = xsave;
816 }
817
818 m_jac->updateElapsed(double(clock() - t0) / CLOCKS_PER_SEC);
819 m_jac->incrementEvals();
820 m_jac->setAge(0);
821}
822
823double SteadyReactorSolver::weightedNorm(const double* step) const
824{
825 double sum = 0.0;
826 const double* x = m_state->data();
827 for (size_t i = 0; i < size(); i++) {
828 double ewt = m_net->rtol()*x[i] + m_net->atol();
829 double f = step[i] / ewt;
830 sum += f*f;
831 }
832 return sqrt(sum / size());
833}
834
836{
837 return m_net->componentName(i);
838}
839
841{
842 return m_net->upperBound(i);
843}
844
846{
847 return m_net->lowerBound(i);
848}
849
851{
852 m_net->resetBadValues(x);
853}
854
855void SteadyReactorSolver::writeDebugInfo(const string& header_suffix,
856 const string& message, int loglevel, int attempt_counter)
857{
858 if (loglevel >= 6 && !m_state->empty()) {
859 const auto& state = *m_state;
860 writelog("Current state ({}):\n[", header_suffix);
861 for (size_t i = 0; i < state.size() - 1; i++) {
862 writelog("{}, ", state[i]);
863 }
864 writelog("{}]\n", state.back());
865 }
866 if (loglevel >= 7 && !m_xnew.empty()) {
867 writelog("Current residual ({}):\n[", header_suffix);
868 for (size_t i = 0; i < m_xnew.size() - 1; i++) {
869 writelog("{}, ", m_xnew[i]);
870 }
871 writelog("{}]\n", m_xnew.back());
872 }
873}
874
875shared_ptr<ReactorNet> newReactorNet(vector<shared_ptr<ReactorBase>>& reactors)
876{
877 return make_shared<ReactorNet>(reactors);
878}
879
880}
Header file for class Cantera::Array2D.
Header file for class ReactorSurface.
Header file for base class WallBase.
A map of string keys to values whose type can vary at runtime.
Definition AnyMap.h:431
A class for 2D arrays stored in column-major (Fortran-compatible) form.
Definition Array.h:32
double & value(size_t i, size_t j)
Returns a changeable reference to position in the matrix.
Definition Array.h:160
Base class for exceptions thrown by Cantera classes.
void setDefaultName(map< string, int > &counts)
Set the default name of a connector. Returns false if it was previously set.
vector< double > m_paramScales
Scaling factors for each sensitivity parameter.
Definition FuncEval.h:184
bool suppressErrors() const
Get current state of error suppression.
Definition FuncEval.h:166
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
An array index is out of range.
Abstract base class for ODE system integrators.
Definition Integrator.h:44
virtual void setMaxStepSize(double hmax)
Set the maximum step size.
Definition Integrator.h:221
virtual void setMaxSteps(int nmax)
Set the maximum number of time-steps the integrator can take before reaching the next output time.
Definition Integrator.h:239
virtual int maxSteps()
Returns the maximum number of time-steps the integrator can take before reaching the next output time...
Definition Integrator.h:245
virtual void setMaxErrTestFails(int n)
Set the maximum permissible number of error test failures.
Definition Integrator.h:231
FlowDevice & outlet(size_t n=0)
Return a reference to the n-th outlet FlowDevice connected to this reactor.
size_t nWalls()
Return the number of Wall objects connected to this reactor.
WallBase & wall(size_t n)
Return a reference to the n-th Wall connected to this reactor.
void setNetwork(ReactorNet *net)
Set the ReactorNet that this reactor belongs to.
bool setDefaultName(map< string, int > &counts)
Set the default name of a reactor. Returns false if it was previously set.
virtual size_t nSurfs() const
Return the number of surfaces in a reactor.
FlowDevice & inlet(size_t n=0)
Return a reference to the n-th inlet FlowDevice connected to this reactor.
size_t nOutlets()
Return the number of outlet FlowDevice objects connected to this reactor.
size_t nInlets()
Return the number of inlet FlowDevice objects connected to this reactor.
ReactorSurface * surface(size_t n)
Return a reference to the n-th ReactorSurface connected to this reactor.
A class representing a network of connected reactors.
Definition ReactorNet.h:30
void setLinearSolverType(const string &linSolverType="DENSE")
Set the type of linear solver used in the integration.
void preconditionerSetup(double t, double *y, double gamma) override
Evaluate the setup processes for the Jacobian preconditioner.
double step()
Advance the state of all reactors with respect to the independent variable (time or space).
virtual int lastOrder() const
Returns the order used for last solution step of the ODE integrator The function is intended for inte...
void eval(double t, double *y, double *ydot, double *p) override
Evaluate the right-hand-side ODE function.
void initialize()
Initialize the reactor network.
void advance(double t)
Advance the state of all reactors in the independent variable (time or space).
size_t neq() const override
Number of equations.
Definition ReactorNet.h:258
vector< size_t > m_start
m_start[n] is the starting point in the state vector for reactor n
Definition ReactorNet.h:405
vector< double > m_LHS
m_LHS is a vector representing the coefficients on the "left hand side" of each governing equation
Definition ReactorNet.h:431
double m_initial_time
The initial value of the independent variable in the system.
Definition ReactorNet.h:398
void evalJacobian(double t, double *y, double *ydot, double *p, Array2D *j)
Evaluate the Jacobian matrix for the reactor network.
double time()
Current value of the simulation time [s], for reactor networks that are solved in the time domain.
void getConstraints(double *constraints) override
Given a vector of length neq(), mark which variables should be considered algebraic constraints.
double m_time
The independent variable in the system.
Definition ReactorNet.h:395
AnyMap solverStats() const
Get solver stats from integrator.
Reactor & reactor(int n)
Return a reference to the n-th reactor in this network.
Definition ReactorNet.h:194
map< string, int > m_counts
Map used for default name generation.
Definition ReactorNet.h:390
double upperBound(size_t i) const
Get the upper bound on the i-th component of the global state vector.
virtual void setMaxSteps(int nmax)
Set the maximum number of internal integration steps the integrator will take before reaching the nex...
string componentName(size_t i) const
Return the name of the i-th component of the global state vector.
void addReactor(Reactor &r)
Add the reactor r to this reactor network.
void getStateDae(double *y, double *ydot) override
Fill in the vectors y and ydot with the current state of the system.
void setInitialTime(double time)
Set the initial value of the independent variable (typically time).
virtual void getDerivative(int k, double *dky)
Return k-th derivative at the current state of the system.
void setMaxErrTestFails(int nmax)
Set the maximum number of error test failures permitted by the CVODES integrator in a single step.
size_t registerSensitivityParameter(const string &name, double value, double scale)
Used by Reactor and Wall objects to register the addition of sensitivity parameters so that the React...
double m_maxstep
Maximum integrator internal timestep. Default of 0.0 means infinity.
Definition ReactorNet.h:416
double distance()
Current position [m] along the length of the reactor network, for reactors that are solved as a funct...
void setSensitivityTolerances(double rtol, double atol)
Set the relative and absolute tolerances for integrating the sensitivity equations.
int maxSteps()
Returns the maximum number of internal integration steps the integrator will take before reaching the...
virtual void setDerivativeSettings(AnyMap &settings)
Set derivative settings of all reactors.
double sensitivity(size_t k, size_t p)
Return the sensitivity of the k-th solution component with respect to the p-th sensitivity parameter.
void updateNames(Reactor &r)
Create reproducible names for reactors and walls/connectors.
void updateState(double *y)
Update the state of all the reactors in the network to correspond to the values in the solution vecto...
void getState(double *y) override
Fill in the vector y with the current state of the system.
void setAdvanceLimits(const double *limits)
Set absolute step size limits during advance.
double rtol()
Relative tolerance.
Definition ReactorNet.h:96
size_t globalComponentIndex(const string &component, size_t reactor=0)
Return the index corresponding to the component named component in the reactor with index reactor in ...
void solveSteady(int loglevel=0)
Solve directly for the steady-state solution.
bool m_timeIsIndependent
Indicates whether time or space is the independent variable.
Definition ReactorNet.h:421
double atol()
Absolute integration tolerance.
Definition ReactorNet.h:101
bool hasAdvanceLimits() const
Check whether ReactorNet object uses advance limits.
void setMaxTimeStep(double maxstep)
Set the maximum integrator step.
double lowerBound(size_t i) const
Get the lower bound on the i-th component of the global state vector.
void evalDae(double t, double *y, double *ydot, double *p, double *residual) override
eval coupling for IDA / DAEs
virtual void checkPreconditionerSupported() const
Check that preconditioning is supported by all reactors in the network.
bool m_integrator_init
True if integrator initialization is current.
Definition ReactorNet.h:401
void reinitialize()
Reinitialize the integrator.
Integrator & integrator()
Return a reference to the integrator.
bool getAdvanceLimits(double *limits) const
Retrieve absolute step size limits during advance.
Eigen::SparseMatrix< double > steadyJacobian(double rdt=0.0)
Get the Jacobian used by the steady-state solver.
string linearSolverType() const
Problem type of integrator.
void updatePreconditioner(double gamma) override
Update the preconditioner based on already computed jacobian values.
void setPreconditioner(shared_ptr< SystemJacobian > preconditioner)
Set preconditioner used by the linear solver.
void preconditionerSolve(double *rhs, double *output) override
Evaluate the linear system Ax=b where A is the preconditioner.
vector< string > m_paramNames
Names corresponding to each sensitivity parameter.
Definition ReactorNet.h:424
void resetBadValues(double *y)
Reset physically or mathematically problematic values, such as negative species concentrations.
void setTolerances(double rtol, double atol)
Set the relative and absolute tolerances for the integrator.
virtual void getEstimate(double time, int k, double *yest)
Estimate a future state based on current derivatives.
Class Reactor is a general-purpose class for stirred reactors.
Definition Reactor.h:47
size_t neq()
Number of equations (state variables) for this reactor.
Definition Reactor.h:97
size_t nSensParams() const override
Number of sensitivity parameters associated with this reactor.
Definition Reactor.cpp:122
string type() const override
String indicating the reactor model implemented.
Definition Reactor.h:52
void initialize(double t0=0.0) override
Initialize the reactor.
Definition Reactor.cpp:94
virtual bool preconditionerSupported() const
Return a false if preconditioning is not supported or true otherwise.
Definition Reactor.h:247
virtual bool isOde() const
Indicate whether the governing equations for this reactor type are a system of ODEs or DAEs.
Definition Reactor.h:59
virtual bool timeIsIndependent() const
Indicates whether the governing equations for this reactor are functions of time or a spatial variabl...
Definition Reactor.h:65
Adapter class to enable using the SteadyStateSystem solver with ReactorNet.
Definition ReactorNet.h:441
double weightedNorm(const double *step) const override
Compute the weighted norm of step.
vector< double > m_initialState
Initial value of each state variable.
Definition ReactorNet.h:459
string componentName(size_t i) const override
Get the name of the i-th component of the state vector.
double upperBound(size_t i) const override
Get the upper bound for global component i in the state vector.
vector< size_t > m_algebraic
Indices of variables that are held constant in the time-stepping mode of the steady-state solver.
Definition ReactorNet.h:463
void evalJacobian(double *x0) override
Evaluates the Jacobian at x0 using finite differences.
void resetBadValues(double *x) override
Reset values such as negative species concentrations.
void writeDebugInfo(const string &header_suffix, const string &message, int loglevel, int attempt_counter) override
Write solver debugging based on the specified log level.
void eval(double *x, double *r, double rdt=-1.0, int count=1) override
Evaluate the residual function.
void initTimeInteg(double dt, double *x) override
Prepare for time stepping beginning with solution x and timestep dt.
double lowerBound(size_t i) const override
Get the lower bound for global component i in the state vector.
int solve(double *x0, double *x1, int loglevel)
Solve , where is the residual function.
virtual void resize()
Call to set the size of internal data structures after first defining the system or if the problem si...
shared_ptr< SystemJacobian > linearSolver() const
Get the the linear solver being used to hold the Jacobian matrix and solve linear systems as part of ...
vector< double > m_xnew
Work array used to hold the residual or the new solution.
double m_jacobianAbsPerturb
Absolute perturbation of each component in finite difference Jacobian.
size_t size() const
Total solution vector length;.
vector< int > & transientMask()
Access the vector indicating which equations contain a transient term.
double rdt() const
Reciprocal of the time step.
virtual void initTimeInteg(double dt, double *x)
Prepare for time stepping beginning with solution x and timestep dt.
double m_rdt
Reciprocal of time step.
double m_jacobianThreshold
Threshold for ignoring small elements in Jacobian.
shared_ptr< SystemJacobian > m_jac
Jacobian evaluator.
shared_ptr< vector< double > > m_state
Solution vector.
void setMaxTimeStepCount(int nmax)
Set the maximum number of timeteps allowed before successful steady-state solve.
void getState(double *x) const
Get the converged steady-state solution after calling solve().
double m_jacobianRelPerturb
Relative perturbation of each component in finite difference Jacobian.
vector< double > m_work1
Work arrays used during Jacobian evaluation.
void debuglog(const string &msg, int loglevel)
Write a message to the log only if loglevel > 0.
Definition global.h:154
void writelog(const string &fmt, const Args &... args)
Write a formatted message to the screen.
Definition global.h:171
void scale(InputIter begin, InputIter end, OutputIter out, S scale_factor)
Multiply elements of an array by a scale factor.
Definition utilities.h:104
Integrator * newIntegrator(const string &itype)
Create new Integrator object.
Namespace for the Cantera kernel.
Definition AnyMap.cpp:595
void checkFinite(const double tmp)
Check to see that a number is finite (not NaN, +Inf or -Inf)
@ BDF_Method
Backward Differentiation.
Definition Integrator.h:24
shared_ptr< SystemJacobian > newSystemJacobian(const string &type)
Create a SystemJacobian object of the specified type.
const double SmallNumber
smallest number to compare to zero.
Definition ct_defs.h:158
shared_ptr< ReactorNet > newReactorNet(vector< shared_ptr< ReactorBase > > &reactors)
Create a reactor network containing one or more coupled reactors.
void warn_deprecated(const string &source, const AnyBase &node, const string &message)
A deprecation warning for syntax in an input file.
Definition AnyMap.cpp:1997
Various templated functions that carry out common vector and polynomial operations (see Templated Arr...