Cantera  3.0.0
Loading...
Searching...
No Matches
MoleReactor.cpp
Go to the documentation of this file.
1//! @file MoleReactor.cpp A zero-dimensional reactor with a moles as the
2//! state
3
4// This file is part of Cantera. See License.txt in the top-level directory or
5// at https://cantera.org/license.txt for license and copyright information.
6
13#include <boost/math/tools/roots.hpp>
14
15using namespace std;
16namespace bmt = boost::math::tools;
17
18namespace Cantera
19{
20
22{
23 size_t loc = 0;
24 for (auto& S : m_surfaces) {
25 double area = S->area();
26 auto currPhase = S->thermo();
27 size_t tempLoc = currPhase->nSpecies();
28 double surfDensity = currPhase->siteDensity();
29 S->getCoverages(y + loc);
30 // convert coverages to moles
31 for (size_t i = 0; i < tempLoc; i++) {
32 y[i + loc] = y[i + loc] * area * surfDensity / currPhase->size(i);
33 }
34 loc += tempLoc;
35 }
36}
37
39{
41 m_nv -= 1; // moles gives the state one fewer variables
42}
43
45{
46 size_t loc = 0;
47 vector<double> coverages(m_nv_surf, 0.0);
48 for (auto& S : m_surfaces) {
49 auto surf = S->thermo();
50 double invArea = 1/S->area();
51 double invSurfDensity = 1/surf->siteDensity();
52 size_t tempLoc = surf->nSpecies();
53 for (size_t i = 0; i < tempLoc; i++) {
54 coverages[i + loc] = y[i + loc] * invArea * surf->size(i) * invSurfDensity;
55 }
56 S->setCoverages(coverages.data()+loc);
57 loc += tempLoc;
58 }
59}
60
61void MoleReactor::evalSurfaces(double* LHS, double* RHS, double* sdot)
62{
63 fill(sdot, sdot + m_nsp, 0.0);
64 size_t loc = 0; // offset into ydot
65 for (auto S : m_surfaces) {
66 Kinetics* kin = S->kinetics();
67 SurfPhase* surf = S->thermo();
68 double wallarea = S->area();
69 size_t nk = surf->nSpecies();
70 S->syncState();
71 kin->getNetProductionRates(&m_work[0]);
72 size_t ns = kin->reactionPhaseIndex();
73 size_t surfloc = kin->kineticsSpeciesIndex(0,ns);
74 for (size_t k = 0; k < nk; k++) {
75 RHS[loc + k] = m_work[surfloc + k] * wallarea / surf->size(k);
76 }
77 loc += nk;
78
79 size_t bulkloc = kin->kineticsSpeciesIndex(m_thermo->speciesName(0));
80
81 for (size_t k = 0; k < m_nsp; k++) {
82 sdot[k] += m_work[bulkloc + k] * wallarea;
83 }
84 }
85}
86
87void MoleReactor::addSurfaceJacobian(vector<Eigen::Triplet<double>> &triplets)
88{
89 size_t offset = m_nsp;
90 for (auto& S : m_surfaces) {
91 S->syncState();
92 double A = S->area();
93 auto kin = S->kinetics();
94 size_t nk = S->thermo()->nSpecies();
95 // index of gas and surface phases to check if the species is in gas or surface
96 size_t spi = kin->reactionPhaseIndex();
97 size_t gpi = kin->speciesPhaseIndex(kin->kineticsSpeciesIndex(
98 m_thermo->speciesName(0)));
99 // get surface jacobian in concentration units
100 Eigen::SparseMatrix<double> surfJac = kin->netProductionRates_ddCi();
101 // loop through surface specific jacobian and add elements to triplets vector
102 // accordingly
103 for (int k=0; k<surfJac.outerSize(); ++k) {
104 for (Eigen::SparseMatrix<double>::InnerIterator it(surfJac, k); it; ++it) {
105 size_t row = it.row();
106 size_t col = it.col();
107 auto& rowPhase = kin->speciesPhase(row);
108 auto& colPhase = kin->speciesPhase(col);
109 size_t rpi = kin->phaseIndex(rowPhase.name());
110 size_t cpi = kin->phaseIndex(colPhase.name());
111 // check if the reactor kinetics object contains both phases to avoid
112 // any solid phases which may be included then use phases to map surf
113 // kinetics indicies to reactor kinetic indices
114 if ((rpi == spi || rpi == gpi) && (cpi == spi || cpi == gpi) ) {
115 // subtract start of phase
116 row -= kin->kineticsSpeciesIndex(0, rpi);
117 col -= kin->kineticsSpeciesIndex(0, cpi);
118 // since the gas phase is the first phase in the reactor state
119 // vector add the offset only if it is a surf species index to
120 // both row and col
121 row = (rpi != spi) ? row : row + offset;
122 // determine appropriate scalar to account for dimensionality
123 // gas phase species indices will be less than m_nsp
124 // so use volume if that is the case or area otherwise
125 double scalar = A;
126 if (cpi == spi) {
127 col += offset;
128 scalar /= A;
129 } else {
130 scalar /= m_vol;
131 }
132 // push back scaled value triplet
133 triplets.emplace_back(static_cast<int>(row), static_cast<int>(col),
134 scalar * it.value());
135 }
136 }
137 }
138 // add species in this surface to the offset
139 offset += nk;
140 }
141}
142
144{
145 // Use inverse molecular weights to convert to moles
146 const double* Y = m_thermo->massFractions();
147 const vector<double>& imw = m_thermo->inverseMolecularWeights();
148 for (size_t i = 0; i < m_nsp; i++) {
149 y[i] = m_mass * imw[i] * Y[i];
150 }
151}
152
154{
155 const vector<double>& mw = m_thermo->molecularWeights();
156 // calculate mass from moles
157 m_mass = 0;
158 for (size_t i = 0; i < m_nsp; i++) {
159 m_mass += y[i] * mw[i];
160 }
161}
162
164{
165 if (m_thermo == 0) {
166 throw CanteraError("MoleReactor::getState",
167 "Error: reactor is empty.");
168 }
169 m_thermo->restoreState(m_state);
170 // set the first component to the internal energy
171 m_mass = m_thermo->density() * m_vol;
172 y[0] = m_thermo->intEnergy_mass() * m_mass;
173 // set the second component to the total volume
174 y[1] = m_vol;
175 // set components y+2 ... y+K+2 to the moles of each species
176 getMoles(y + m_sidx);
177 // set the remaining components to the surface species
178 // moles on walls
180}
181
183{
184 // The components of y are [0] total internal energy, [1] the total volume, and
185 // [2...K+3] are the moles of each species, and [K+3...] are the moles
186 // of surface species on each wall.
188 m_vol = y[1];
189 m_thermo->setMolesNoTruncate(y + m_sidx);
190 if (m_energy) {
191 double U = y[0];
192 // Residual function: error in internal energy as a function of T
193 auto u_err = [this, U](double T) {
194 m_thermo->setState_TD(T, m_mass / m_vol);
195 return m_thermo->intEnergy_mass() * m_mass - U;
196 };
197 double T = m_thermo->temperature();
198 boost::uintmax_t maxiter = 100;
199 pair<double, double> TT;
200 try {
201 TT = bmt::bracket_and_solve_root(
202 u_err, T, 1.2, true, bmt::eps_tolerance<double>(48), maxiter);
203 } catch (std::exception&) {
204 // Try full-range bisection if bracketing fails (for example, near
205 // temperature limits for the phase's equation of state)
206 try {
207 TT = bmt::bisect(u_err, m_thermo->minTemp(), m_thermo->maxTemp(),
208 bmt::eps_tolerance<double>(48), maxiter);
209 } catch (std::exception& err2) {
210 // Set m_thermo back to a reasonable state if root finding fails
211 m_thermo->setState_TD(T, m_mass / m_vol);
212 throw CanteraError("MoleReactor::updateState",
213 "{}\nat U = {}, rho = {}", err2.what(), U, m_mass / m_vol);
214 }
215 }
216 if (fabs(TT.first - TT.second) > 1e-7*TT.first) {
217 throw CanteraError("MoleReactor::updateState", "root finding failed");
218 }
219 m_thermo->setState_TD(TT.second, m_mass / m_vol);
220 } else {
221 m_thermo->setDensity(m_mass / m_vol);
222 }
223 updateConnected(true);
225}
226
227void MoleReactor::eval(double time, double* LHS, double* RHS)
228{
229 double* dndt = RHS + m_sidx; // moles per time
230
231 evalWalls(time);
232 m_thermo->restoreState(m_state);
233
234 evalSurfaces(LHS + m_nsp + m_sidx, RHS + m_nsp + m_sidx, m_sdot.data());
235 // inverse molecular weights for conversion
236 const vector<double>& imw = m_thermo->inverseMolecularWeights();
237 // volume equation
238 RHS[1] = m_vdot;
239
240 if (m_chem) {
241 m_kin->getNetProductionRates(&m_wdot[0]); // "omega dot"
242 }
243
244 // Energy equation.
245 // @f[
246 // \dot U = -P\dot V + A \dot q + \dot m_{in} h_{in} - \dot m_{out} h.
247 // @f]
248 if (m_energy) {
249 RHS[0] = - m_thermo->pressure() * m_vdot + m_Qdot;
250 } else {
251 RHS[0] = 0.0;
252 }
253
254 for (size_t k = 0; k < m_nsp; k++) {
255 // production in gas phase and from surfaces
256 dndt[k] = m_wdot[k] * m_vol + m_sdot[k];
257 }
258
259 // add terms for outlets
260 for (auto outlet : m_outlet) {
261 // flow of species into system and dilution by other species
262 for (size_t n = 0; n < m_nsp; n++) {
263 dndt[n] -= outlet->outletSpeciesMassFlowRate(n) * imw[n];
264 }
265 // energy update based on mass flow
266 double mdot = outlet->massFlowRate();
267 if (m_energy) {
268 RHS[0] -= mdot * m_enthalpy;
269 }
270 }
271
272 // add terms for inlets
273 for (auto inlet : m_inlet) {
274 double mdot = inlet->massFlowRate();
275 for (size_t n = 0; n < m_nsp; n++) {
276 // flow of species into system and dilution by other species
277 dndt[n] += inlet->outletSpeciesMassFlowRate(n) * imw[n];
278 }
279 if (m_energy) {
280 RHS[0] += mdot * inlet->enthalpy_mass();
281 }
282 }
283}
284
285
286size_t MoleReactor::componentIndex(const string& nm) const
287{
288 size_t k = speciesIndex(nm);
289 if (k != npos) {
290 return k + m_sidx;
291 } else if (nm == "int_energy") {
292 return 0;
293 } else if (nm == "volume") {
294 return 1;
295 } else {
296 return npos;
297 }
298}
299
301 if (k == 0) {
302 return "int_energy";
303 } else if (k == 1) {
304 return "volume";
305 } else if (k >= m_sidx && k < neq()) {
306 k -= m_sidx;
307 if (k < m_thermo->nSpecies()) {
308 return m_thermo->speciesName(k);
309 } else {
310 k -= m_thermo->nSpecies();
311 }
312 for (auto& S : m_surfaces) {
313 ThermoPhase* th = S->thermo();
314 if (k < th->nSpecies()) {
315 return th->speciesName(k);
316 } else {
317 k -= th->nSpecies();
318 }
319 }
320 }
321 throw CanteraError("MoleReactor::componentName", "Index is out of bounds.");
322}
323
324}
Base class for kinetics managers and also contains the kineticsmgr module documentation (see Kinetics...
Header file for class ReactorSurface.
Header for a simple thermodynamics model of a surface phase derived from ThermoPhase,...
Base class for exceptions thrown by Cantera classes.
double outletSpeciesMassFlowRate(size_t k)
Mass flow rate (kg/s) of outlet species k.
double enthalpy_mass()
specific enthalpy
double massFlowRate()
Mass flow rate (kg/s).
Definition FlowDevice.h:39
Public interface for kinetics managers.
Definition Kinetics.h:126
size_t reactionPhaseIndex() const
Phase where the reactions occur.
Definition Kinetics.h:235
size_t kineticsSpeciesIndex(size_t k, size_t n) const
The location of species k of phase n in species arrays.
Definition Kinetics.h:288
virtual void getNetProductionRates(double *wdot)
Species net production rates [kmol/m^3/s or kmol/m^2/s].
Definition Kinetics.cpp:435
void evalSurfaces(double *LHS, double *RHS, double *sdot) override
Evaluate terms related to surface reactions.
void getSurfaceInitialConditions(double *y) override
Get initial conditions for SurfPhase objects attached to this reactor.
void getMoles(double *y)
Get moles of the system from mass fractions stored by thermo object.
void eval(double t, double *LHS, double *RHS) override
Evaluate the reactor governing equations.
size_t componentIndex(const string &nm) const override
Return the index in the solution vector for this reactor of the component named nm.
const size_t m_sidx
const value for the species start index
Definition MoleReactor.h:62
void setMassFromMoles(double *y)
Set internal mass variable based on moles given.
virtual void addSurfaceJacobian(vector< Eigen::Triplet< double > > &triplets)
For each surface in the reactor, update vector of triplets with all relevant surface jacobian derivat...
void getState(double *y) override
Get the the current state of the reactor.
string componentName(size_t k) override
Return the name of the solution component with index i.
void updateState(double *y) override
Set the state of the reactor to correspond to the state vector y.
void initialize(double t0=0.0) override
Initialize the reactor.
void updateSurfaceState(double *y) override
Update the state of SurfPhase objects attached to this reactor.
void restoreState(const vector< double > &state)
Restore a state saved on a previous call to saveState.
Definition Phase.cpp:275
size_t nSpecies() const
Returns the number of species in the phase.
Definition Phase.h:245
void setState_TD(double t, double rho)
Set the internally stored temperature (K) and density (kg/m^3)
Definition Phase.cpp:444
double temperature() const
Temperature (K).
Definition Phase.h:662
string speciesName(size_t k) const
Name of the species with index k.
Definition Phase.cpp:151
virtual void setDensity(const double density_)
Set the internally stored density (kg/m^3) of the phase.
Definition Phase.cpp:707
const vector< double > & inverseMolecularWeights() const
Return a const reference to the internal vector of molecular weights.
Definition Phase.cpp:506
const double * massFractions() const
Return a const pointer to the mass fraction array.
Definition Phase.h:535
const vector< double > & molecularWeights() const
Return a const reference to the internal vector of molecular weights.
Definition Phase.cpp:501
virtual double density() const
Density (kg/m^3).
Definition Phase.h:687
virtual void setMolesNoTruncate(const double *const N)
Set the state of the object with moles in [kmol].
Definition Phase.cpp:641
virtual double pressure() const
Return the thermodynamic pressure (Pa).
Definition Phase.h:680
FlowDevice & outlet(size_t n=0)
Return a reference to the n-th outlet FlowDevice connected to this reactor.
FlowDevice & inlet(size_t n=0)
Return a reference to the n-th inlet FlowDevice connected to this reactor.
double m_vol
Current volume of the reactor [m^3].
size_t m_nsp
Number of homogeneous species in the mixture.
double m_enthalpy
Current specific enthalpy of the reactor [J/kg].
Kinetics * m_kin
Pointer to the homogeneous Kinetics object that handles the reactions.
Definition Reactor.h:277
vector< double > m_wdot
Species net molar production rates.
Definition Reactor.h:289
virtual void evalWalls(double t)
Evaluate terms related to Walls.
Definition Reactor.cpp:275
size_t neq()
Number of equations (state variables) for this reactor.
Definition Reactor.h:103
double m_Qdot
net heat transfer into the reactor, through walls [W]
Definition Reactor.h:281
double m_mass
total mass
Definition Reactor.h:283
vector< double > m_sdot
Production rates of gas phase species on surfaces [kmol/s].
Definition Reactor.h:287
double m_vdot
net rate of volume change from moving walls [m^3/s]
Definition Reactor.h:279
void initialize(double t0=0.0) override
Initialize the reactor.
Definition Reactor.cpp:84
virtual size_t speciesIndex(const string &nm) const
Return the index in the solution vector for this reactor of the species named nm, in either the homog...
Definition Reactor.cpp:430
virtual void updateConnected(bool updatePressure)
Update the state information needed by connected reactors, flow devices, and reactor walls.
Definition Reactor.cpp:184
A simple thermodynamic model for a surface phase, assuming an ideal solution model.
Definition SurfPhase.h:98
double size(size_t k) const
Returns the number of sites occupied by one molecule of species k.
Definition SurfPhase.h:226
Base class for a phase with thermodynamic properties.
virtual double minTemp(size_t k=npos) const
Minimum temperature for which the thermodynamic data for the species or phase are valid.
virtual double maxTemp(size_t k=npos) const
Maximum temperature for which the thermodynamic data for the species are valid.
double intEnergy_mass() const
Specific internal energy. Units: J/kg.
Namespace for the Cantera kernel.
Definition AnyMap.cpp:564
const size_t npos
index returned by functions to indicate "no position"
Definition ct_defs.h:195
offset
Offsets of solution components in the 1D solution array.
Definition StFlow.h:24
Various templated functions that carry out common vector and polynomial operations (see Templated Arr...