Cantera  3.2.0a2
Loading...
Searching...
No Matches
IdealGasMoleReactor.cpp
Go to the documentation of this file.
1//! @file IdealGasMoleReactor.cpp A constant volume zero-dimensional
2//! reactor with moles as the 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
15#include <limits>
16
17namespace Cantera
18{
19
21{
22 if (thermo.type() != "ideal-gas") {
23 throw CanteraError("IdealGasMoleReactor::setThermo",
24 "Incompatible phase type provided");
25 }
27}
28
30{
31 if (m_thermo == 0) {
32 throw CanteraError("IdealGasMoleReactor::getState",
33 "Error: reactor is empty.");
34 }
35 m_thermo->restoreState(m_state);
36
37 // get mass for calculations
38 m_mass = m_thermo->density() * m_vol;
39
40 // set the first component to the temperature
41 y[0] = m_thermo->temperature();
42
43 // set the second component to the volume
44 y[1] = m_vol;
45
46 // get moles of species in remaining state
47 getMoles(y + m_sidx);
48 // set the remaining components to the surface species moles on
49 // the walls
51}
52
53size_t IdealGasMoleReactor::componentIndex(const string& nm) const
54{
55 size_t k = speciesIndex(nm);
56 if (k != npos) {
57 return k + m_sidx;
58 } else if (nm == "temperature") {
59 return 0;
60 } else if (nm == "volume") {
61 return 1;
62 } else {
63 return npos;
64 }
65}
66
68{
69 if (k == 0) {
70 return "temperature";
71 } else {
73 }
74}
75
77{
79 m_uk.resize(m_nsp, 0.0);
80}
81
82double IdealGasMoleReactor::upperBound(size_t k) const {
83 if (k == 0) {
84 //@todo: Revise pending resolution of https://github.com/Cantera/enhancements/issues/229
85 return 1.5 * m_thermo->maxTemp();
86 } else {
88 }
89}
90
91double IdealGasMoleReactor::lowerBound(size_t k) const {
92 if (k == 0) {
93 //@todo: Revise pending resolution of https://github.com/Cantera/enhancements/issues/229
94 return 0.5 * m_thermo->minTemp();
95 } else {
97 }
98}
99
101{
102 if (nSurfs() != 0) {
103 throw CanteraError("IdealGasMoleReactor::steadyConstraints",
104 "Steady state solver cannot currently be used with IdealGasMoleReactor"
105 " when reactor surfaces are present.\n"
106 "See https://github.com/Cantera/enhancements/issues/234");
107 }
108 if (energyEnabled()) {
109 return {1}; // volume
110 } else {
111 return {0, 1}; // temperature and volume
112 }
113}
114
116{
117 // the components of y are: [0] the temperature, [1] the volume, [2...K+1) are the
118 // moles of each species, and [K+1...] are the moles of surface
119 // species on each wall.
121 m_vol = y[1];
122 // set state
123 m_thermo->setMolesNoTruncate(y + m_sidx);
124 m_thermo->setState_TD(y[0], m_mass / m_vol);
125 updateConnected(true);
127}
128
129void IdealGasMoleReactor::eval(double time, double* LHS, double* RHS)
130{
131 double& mcvdTdt = RHS[0]; // m * c_v * dT/dt
132 double* dndt = RHS + m_sidx; // kmol per s
133
134 evalWalls(time);
135
136 m_thermo->restoreState(m_state);
137
138 m_thermo->getPartialMolarIntEnergies(&m_uk[0]);
139 const vector<double>& imw = m_thermo->inverseMolecularWeights();
140
141 if (m_chem) {
142 m_kin->getNetProductionRates(&m_wdot[0]); // "omega dot"
143 }
144
145 // evaluate surfaces
146 evalSurfaces(LHS + m_nsp + m_sidx, RHS + m_nsp + m_sidx, m_sdot.data());
147
148 // external heat transfer and compression work
149 mcvdTdt += - m_pressure * m_vdot + m_Qdot;
150
151 for (size_t n = 0; n < m_nsp; n++) {
152 // heat release from gas phase and surface reactions
153 mcvdTdt -= m_wdot[n] * m_uk[n] * m_vol;
154 mcvdTdt -= m_sdot[n] * m_uk[n];
155 // production in gas phase and from surfaces
156 dndt[n] = (m_wdot[n] * m_vol + m_sdot[n]);
157 }
158
159 // add terms for outlets
160 for (auto outlet : m_outlet) {
161 for (size_t n = 0; n < m_nsp; n++) {
162 // flow of species into system and dilution by other species
163 dndt[n] -= outlet->outletSpeciesMassFlowRate(n) * imw[n];
164 }
165 double mdot = outlet->massFlowRate();
166 mcvdTdt -= mdot * m_pressure * m_vol / m_mass; // flow work
167 }
168
169 // add terms for inlets
170 for (auto inlet : m_inlet) {
171 double mdot = inlet->massFlowRate();
172 mcvdTdt += inlet->enthalpy_mass() * mdot;
173 for (size_t n = 0; n < m_nsp; n++) {
174 double mdot_spec = inlet->outletSpeciesMassFlowRate(n);
175 // flow of species into system and dilution by other species
176 dndt[n] += inlet->outletSpeciesMassFlowRate(n) * imw[n];
177 mcvdTdt -= m_uk[n] * imw[n] * mdot_spec;
178 }
179 }
180
181 RHS[1] = m_vdot;
182 if (m_energy) {
183 LHS[0] = m_mass * m_thermo->cv_mass();
184 } else {
185 RHS[0] = 0;
186 }
187}
188
189Eigen::SparseMatrix<double> IdealGasMoleReactor::jacobian()
190{
191 if (m_nv == 0) {
192 throw CanteraError("IdealGasMoleReactor::jacobian",
193 "Reactor must be initialized first.");
194 }
195 // clear former jacobian elements
196 m_jac_trips.clear();
197 // dnk_dnj represents d(dot(n_k)) / d (n_j) but is first assigned as
198 // d (dot(omega)) / d c_j, it is later transformed appropriately.
199 Eigen::SparseMatrix<double> dnk_dnj = m_kin->netProductionRates_ddCi();
200 // species size that accounts for surface species
201 size_t ssize = m_nv - m_sidx;
202 // map derivatives from the surface chemistry jacobian
203 // to the reactor jacobian
204 if (!m_surfaces.empty()) {
205 vector<Eigen::Triplet<double>> species_trips;
206 for (int k = 0; k < dnk_dnj.outerSize(); k++) {
207 for (Eigen::SparseMatrix<double>::InnerIterator it(dnk_dnj, k); it; ++it) {
208 species_trips.emplace_back(static_cast<int>(it.row()),
209 static_cast<int>(it.col()), it.value());
210 }
211 }
212 addSurfaceJacobian(species_trips);
213 dnk_dnj.resize(ssize, ssize);
214 dnk_dnj.setFromTriplets(species_trips.begin(), species_trips.end());
215 }
216 // add species to species derivatives elements to the jacobian
217 // calculate ROP derivatives, excluding the terms -n_i / (V * N) dc_i/dn_j
218 // as it substantially reduces matrix sparsity
219 for (int k = 0; k < dnk_dnj.outerSize(); k++) {
220 for (Eigen::SparseMatrix<double>::InnerIterator it(dnk_dnj, k); it; ++it) {
221 m_jac_trips.emplace_back(static_cast<int>(it.row() + m_sidx),
222 static_cast<int>(it.col() + m_sidx), it.value());
223 }
224 }
225 // Temperature Derivatives
226 if (m_energy) {
227 // getting perturbed state for finite difference
228 double deltaTemp = m_thermo->temperature()
229 * std::sqrt(std::numeric_limits<double>::epsilon());
230 // finite difference temperature derivatives
231 vector<double> lhsPerturbed(m_nv, 1.0), lhsCurrent(m_nv, 1.0);
232 vector<double> rhsPerturbed(m_nv, 0.0), rhsCurrent(m_nv, 0.0);
233 vector<double> yCurrent(m_nv);
234 getState(yCurrent.data());
235 vector<double> yPerturbed = yCurrent;
236 // perturb temperature
237 yPerturbed[0] += deltaTemp;
238 // getting perturbed state
239 updateState(yPerturbed.data());
240 double time = (m_net != nullptr) ? m_net->time() : 0.0;
241 eval(time, lhsPerturbed.data(), rhsPerturbed.data());
242 // reset and get original state
243 updateState(yCurrent.data());
244 eval(time, lhsCurrent.data(), rhsCurrent.data());
245 // d ydot_j/dT
246 for (size_t j = 0; j < m_nv; j++) {
247 double ydotPerturbed = rhsPerturbed[j] / lhsPerturbed[j];
248 double ydotCurrent = rhsCurrent[j] / lhsCurrent[j];
249 m_jac_trips.emplace_back(static_cast<int>(j), 0,
250 (ydotPerturbed - ydotCurrent) / deltaTemp);
251 }
252 // d T_dot/dnj
253 Eigen::VectorXd netProductionRates = Eigen::VectorXd::Zero(ssize);
254 Eigen::VectorXd internal_energy = Eigen::VectorXd::Zero(ssize);
255 Eigen::VectorXd specificHeat = Eigen::VectorXd::Zero(ssize);
256 // getting species data
257 m_thermo->getPartialMolarIntEnergies(internal_energy.data());
258 m_kin->getNetProductionRates(netProductionRates.data());
259 m_thermo->getPartialMolarCp(specificHeat.data());
260 // convert Cp to Cv for ideal gas as Cp - Cv = R
261 for (size_t i = 0; i < m_nsp; i++) {
262 specificHeat[i] -= GasConstant;
263 netProductionRates[i] *= m_vol;
264 }
265 // scale net production rates by volume to get molar rate
266 double qdot = internal_energy.dot(netProductionRates);
267 // find the sum of n_i and cp_i
268 double NCv = 0.0;
269 double* moles = yCurrent.data() + m_sidx;
270 for (size_t i = 0; i < ssize; i++) {
271 NCv += moles[i] * specificHeat[i];
272 }
273 // make denominator beforehand
274 double denom = 1 / (NCv * NCv);
275 Eigen::VectorXd uk_dnkdnj_sums = dnk_dnj.transpose() * internal_energy;
276 // add derivatives to jacobian
277 for (size_t j = 0; j < ssize; j++) {
278 m_jac_trips.emplace_back(0, static_cast<int>(j + m_sidx),
279 (specificHeat[j] * qdot - NCv * uk_dnkdnj_sums[j]) * denom);
280 }
281 }
282 // convert triplets to sparse matrix
283 Eigen::SparseMatrix<double> jac(m_nv, m_nv);
284 jac.setFromTriplets(m_jac_trips.begin(), m_jac_trips.end());
285 return jac;
286}
287
288}
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,...
Header file for class ThermoPhase, the base class for phases with thermodynamic properties,...
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:36
double upperBound(size_t k) const override
Get the upper bound on the k-th component of the local state vector.
vector< size_t > steadyConstraints() const override
Get the indices of equations that are algebraic constraints when solving the steady-state problem.
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.
Eigen::SparseMatrix< double > jacobian() override
Calculate an approximate Jacobian to accelerate preconditioned solvers.
vector< double > m_uk
Species molar internal energies.
void getState(double *y) override
Get the the current state of the reactor.
double lowerBound(size_t k) const override
Get the lower bound on the k-th component of the local state vector.
string componentName(size_t k) override
Return the name of the solution component with index i.
void setThermo(ThermoPhase &thermo) override
Specify the mixture contained in the reactor.
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.
virtual void getNetProductionRates(double *wdot)
Species net production rates [kmol/m^3/s or kmol/m^2/s].
Definition Kinetics.cpp:411
double upperBound(size_t k) const override
Get the upper bound on the k-th component of the local state vector.
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.
const size_t m_sidx
const value for the species start index
Definition MoleReactor.h:64
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...
double lowerBound(size_t k) const override
Get the lower bound on the k-th component of the local state vector.
string componentName(size_t k) override
Return the name of the solution component with index i.
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:260
void setState_TD(double t, double rho)
Set the internally stored temperature (K) and density (kg/m^3)
Definition Phase.cpp:377
double temperature() const
Temperature (K).
Definition Phase.h:563
const vector< double > & inverseMolecularWeights() const
Return a const reference to the internal vector of molecular weights.
Definition Phase.cpp:400
virtual double density() const
Density (kg/m^3).
Definition Phase.h:588
virtual void setMolesNoTruncate(const double *const N)
Set the state of the object with moles in [kmol].
Definition Phase.cpp:528
virtual void setThermo(ThermoPhase &thermo)
Specify the mixture contained in the reactor.
FlowDevice & outlet(size_t n=0)
Return a reference to the n-th outlet FlowDevice connected to this reactor.
double m_pressure
Current pressure in the reactor [Pa].
ReactorNet * m_net
The ReactorNet that this reactor is part of.
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.
double m_vol
Current volume of the reactor [m^3].
double m_mass
Current mass of the reactor [kg].
size_t m_nsp
Number of homogeneous species in the mixture.
double time()
Current value of the simulation time [s], for reactor networks that are solved in the time domain.
Kinetics * m_kin
Pointer to the homogeneous Kinetics object that handles the reactions.
Definition Reactor.h:290
vector< double > m_wdot
Species net molar production rates.
Definition Reactor.h:301
virtual void evalWalls(double t)
Evaluate terms related to Walls.
Definition Reactor.cpp:283
bool energyEnabled() const
Returns true if solution of the energy equation is enabled.
Definition Reactor.h:92
double m_Qdot
net heat transfer into the reactor, through walls [W]
Definition Reactor.h:294
vector< Eigen::Triplet< double > > m_jac_trips
Vector of triplets representing the jacobian.
Definition Reactor.h:311
vector< double > m_sdot
Production rates of gas phase species on surfaces [kmol/s].
Definition Reactor.h:299
double m_vdot
net rate of volume change from moving walls [m^3/s]
Definition Reactor.h:292
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:450
virtual void updateConnected(bool updatePressure)
Update the state information needed by connected reactors, flow devices, and reactor walls.
Definition Reactor.cpp:188
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 void getPartialMolarCp(double *cpbar) const
Return an array of partial molar heat capacities for the species in the mixture.
string type() const override
String indicating the thermodynamic model implemented.
virtual void getPartialMolarIntEnergies(double *ubar) const
Return an array of partial molar internal energies for the species in the mixture.
virtual double maxTemp(size_t k=npos) const
Maximum temperature for which the thermodynamic data for the species are valid.
double cv_mass() const
Specific heat at constant volume. Units: J/kg/K.
Eigen::SparseMatrix< double > netProductionRates_ddCi()
Calculate derivatives for species net production rates with respect to species concentration at const...
Definition Kinetics.cpp:563
const double GasConstant
Universal Gas Constant [J/kmol/K].
Definition ct_defs.h:120
Namespace for the Cantera kernel.
Definition AnyMap.cpp:595
const size_t npos
index returned by functions to indicate "no position"
Definition ct_defs.h:180
Various templated functions that carry out common vector and polynomial operations (see Templated Arr...