Cantera  4.0.0a1
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
21MoleReactor::MoleReactor(shared_ptr<Solution> sol, const string& name)
22 : MoleReactor(sol, true, name)
23{
24}
25
26MoleReactor::MoleReactor(shared_ptr<Solution> sol, bool clone, const string& name)
27 : Reactor(sol, clone, name)
28{
29 m_nv = 2 + m_nsp; // internal energy, volume, and moles of each species
30}
31
32void MoleReactor::getMoles(double* y)
33{
34 // Use inverse molecular weights to convert to moles
35 const double* Y = m_thermo->massFractions();
36 const vector<double>& imw = m_thermo->inverseMolecularWeights();
37 for (size_t i = 0; i < m_nsp; i++) {
38 y[i] = m_mass * imw[i] * Y[i];
39 }
40}
41
42void MoleReactor::setMassFromMoles(double* y)
43{
44 const vector<double>& mw = m_thermo->molecularWeights();
45 // calculate mass from moles
46 m_mass = 0;
47 for (size_t i = 0; i < m_nsp; i++) {
48 m_mass += y[i] * mw[i];
49 }
50}
51
52void MoleReactor::getState(double* y)
53{
54 // set the first component to the internal energy
55 m_mass = m_thermo->density() * m_vol;
56 y[0] = m_thermo->intEnergy_mass() * m_mass;
57 // set the second component to the total volume
58 y[1] = m_vol;
59 // set components y+2 ... y+K+2 to the moles of each species
60 getMoles(y + m_sidx);
61}
62
63void MoleReactor::updateState(double* y)
64{
65 // The components of y are [0] total internal energy, [1] the total volume, and
66 // [2...K+3] are the moles of each species, and [K+3...] are the moles
67 // of surface species on each wall.
68 setMassFromMoles(y + m_sidx);
69 m_vol = y[1];
70 m_thermo->setMolesNoTruncate(y + m_sidx);
71 if (m_energy) {
72 double U = y[0];
73 // Residual function: error in internal energy as a function of T
74 auto u_err = [this, U](double T) {
75 m_thermo->setState_TD(T, m_mass / m_vol);
76 return m_thermo->intEnergy_mass() * m_mass - U;
77 };
78 double T = m_thermo->temperature();
79 boost::uintmax_t maxiter = 100;
80 pair<double, double> TT;
81 try {
82 TT = bmt::bracket_and_solve_root(
83 u_err, T, 1.2, true, bmt::eps_tolerance<double>(48), maxiter);
84 } catch (std::exception&) {
85 // Try full-range bisection if bracketing fails (for example, near
86 // temperature limits for the phase's equation of state)
87 try {
88 TT = bmt::bisect(u_err, m_thermo->minTemp(), m_thermo->maxTemp(),
89 bmt::eps_tolerance<double>(48), maxiter);
90 } catch (std::exception& err2) {
91 // Set m_thermo back to a reasonable state if root finding fails
92 m_thermo->setState_TD(T, m_mass / m_vol);
93 throw CanteraError("MoleReactor::updateState",
94 "{}\nat U = {}, rho = {}", err2.what(), U, m_mass / m_vol);
95 }
96 }
97 if (fabs(TT.first - TT.second) > 1e-7*TT.first) {
98 throw CanteraError("MoleReactor::updateState", "root finding failed");
99 }
100 m_thermo->setState_TD(TT.second, m_mass / m_vol);
101 } else {
102 m_thermo->setDensity(m_mass / m_vol);
103 }
104 updateConnected(true);
105}
106
107void MoleReactor::eval(double time, double* LHS, double* RHS)
108{
109 double* dndt = RHS + m_sidx; // moles per time
110
111 evalWalls(time);
112 updateSurfaceProductionRates();
113 // inverse molecular weights for conversion
114 const vector<double>& imw = m_thermo->inverseMolecularWeights();
115 // volume equation
116 RHS[1] = m_vdot;
117
118 if (m_chem) {
119 m_kin->getNetProductionRates(&m_wdot[0]); // "omega dot"
120 }
121
122 // Energy equation.
123 // @f[
124 // \dot U = -P\dot V + A \dot q + \dot m_{in} h_{in} - \dot m_{out} h.
125 // @f]
126 if (m_energy) {
127 RHS[0] = - m_thermo->pressure() * m_vdot + m_Qdot;
128 RHS[0] += m_thermo->intrinsicHeating() * m_vol;
129 } else {
130 RHS[0] = 0.0;
131 }
132
133 for (size_t k = 0; k < m_nsp; k++) {
134 // production in gas phase and from surfaces
135 dndt[k] = m_wdot[k] * m_vol + m_sdot[k];
136 }
137
138 // add terms for outlets
139 for (auto outlet : m_outlet) {
140 // flow of species into system and dilution by other species
141 for (size_t n = 0; n < m_nsp; n++) {
142 dndt[n] -= outlet->outletSpeciesMassFlowRate(n) * imw[n];
143 }
144 // energy update based on mass flow
145 double mdot = outlet->massFlowRate();
146 if (m_energy) {
147 RHS[0] -= mdot * m_enthalpy;
148 }
149 }
150
151 // add terms for inlets
152 for (auto inlet : m_inlet) {
153 double mdot = inlet->massFlowRate();
154 for (size_t n = 0; n < m_nsp; n++) {
155 // flow of species into system and dilution by other species
156 dndt[n] += inlet->outletSpeciesMassFlowRate(n) * imw[n];
157 }
158 if (m_energy) {
159 RHS[0] += mdot * inlet->enthalpy_mass();
160 }
161 }
162}
163
164
165size_t MoleReactor::componentIndex(const string& nm) const
166{
167 if (nm == "int_energy") {
168 return 0;
169 }
170 if (nm == "volume") {
171 return 1;
172 }
173 try {
174 return m_thermo->speciesIndex(nm) + m_sidx;
175 } catch (const CanteraError&) {
176 throw CanteraError("MoleReactor::componentIndex",
177 "Component '{}' not found", nm);
178 }
179}
180
181string MoleReactor::componentName(size_t k) {
182 if (k == 0) {
183 return "int_energy";
184 } else if (k == 1) {
185 return "volume";
186 } else if (k >= m_sidx && k < neq()) {
187 return m_thermo->speciesName(k - m_sidx);
188 }
189 throw IndexError("MoleReactor::componentName", "component", k, m_nv);
190}
191
192double MoleReactor::upperBound(size_t k) const {
193 // Component is either int_energy, volume, or moles of a bulk or surface species
194 return BigNumber;
195}
196
197double MoleReactor::lowerBound(size_t k) const {
198 if (k == 0) {
199 return -BigNumber; // int_energy
200 } else if (k == 1) {
201 return 0; // volume
202 } else if (k >= 2 && k < m_nv) {
203 return -Tiny; // moles of bulk or surface species
204 } else {
205 throw CanteraError("MoleReactor::lowerBound", "Index {} is out of bounds.", k);
206 }
207}
208
209void MoleReactor::resetBadValues(double* y) {
210 for (size_t k = m_sidx; k < m_nv; k++) {
211 y[k] = std::max(y[k], 0.0);
212 }
213}
214
215}
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.
An array index is out of range.
Namespace for the Cantera kernel.
Definition AnyMap.cpp:595
const double Tiny
Small number to compare differences of mole fractions against.
Definition ct_defs.h:175
const double BigNumber
largest number to compare to inf.
Definition ct_defs.h:162
Various templated functions that carry out common vector and polynomial operations (see Templated Arr...