13 #include <boost/math/tools/roots.hpp>
16 namespace bmt = boost::math::tools;
21 void MoleReactor::getSurfaceInitialConditions(
double* y)
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);
31 for (
size_t i = 0; i < tempLoc; i++) {
32 y[i + loc] = y[i + loc] * area * surfDensity / currPhase->size(i);
38 void MoleReactor::initialize(
double t0)
40 Reactor::initialize(t0);
44 void MoleReactor::updateSurfaceState(
double* y)
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;
56 S->setCoverages(coverages.data()+loc);
61 void MoleReactor::evalSurfaces(
double* LHS,
double* RHS,
double* sdot)
63 fill(sdot, sdot + m_nsp, 0.0);
65 for (
auto S : m_surfaces) {
68 double wallarea = S->area();
72 for (
size_t k = 0; k < nk; k++) {
73 RHS[loc + k] = m_work[k] * wallarea / surf->
size(k);
79 for (
size_t k = 0; k < m_nsp; k++) {
80 sdot[k] += m_work[bulkloc + k] * wallarea;
85 void MoleReactor::addSurfaceJacobian(vector<Eigen::Triplet<double>> &triplets)
88 for (
auto& S : m_surfaces) {
91 auto kin = S->kinetics();
92 size_t nk = S->thermo()->nSpecies();
95 size_t gpi = kin->speciesPhaseIndex(kin->kineticsSpeciesIndex(
96 m_thermo->speciesName(0)));
98 Eigen::SparseMatrix<double> surfJac = kin->netProductionRates_ddCi();
101 for (
int k=0; k<surfJac.outerSize(); ++k) {
102 for (Eigen::SparseMatrix<double>::InnerIterator it(surfJac, k); it; ++it) {
103 size_t row = it.row();
104 size_t col = it.col();
105 auto& rowPhase = kin->speciesPhase(row);
106 auto& colPhase = kin->speciesPhase(col);
107 size_t rpi = kin->phaseIndex(rowPhase.name());
108 size_t cpi = kin->phaseIndex(colPhase.name());
112 if ((rpi == spi || rpi == gpi) && (cpi == spi || cpi == gpi) ) {
114 row -= kin->kineticsSpeciesIndex(0, rpi);
115 col -= kin->kineticsSpeciesIndex(0, cpi);
119 row = (rpi != spi) ? row : row +
offset;
131 triplets.emplace_back(
static_cast<int>(row),
static_cast<int>(col),
132 scalar * it.value());
141 void MoleReactor::getMoles(
double* y)
144 const double* Y = m_thermo->massFractions();
145 const vector<double>& imw = m_thermo->inverseMolecularWeights();
146 for (
size_t i = 0; i < m_nsp; i++) {
147 y[i] = m_mass * imw[i] * Y[i];
151 void MoleReactor::setMassFromMoles(
double* y)
153 const vector<double>& mw = m_thermo->molecularWeights();
156 for (
size_t i = 0; i < m_nsp; i++) {
157 m_mass += y[i] * mw[i];
161 void MoleReactor::getState(
double* y)
165 "Error: reactor is empty.");
167 m_thermo->restoreState(m_state);
169 m_mass = m_thermo->density() * m_vol;
170 y[0] = m_thermo->intEnergy_mass() * m_mass;
174 getMoles(y + m_sidx);
177 getSurfaceInitialConditions(y+m_nsp+m_sidx);
180 void MoleReactor::updateState(
double* y)
185 setMassFromMoles(y + m_sidx);
187 m_thermo->setMolesNoTruncate(y + m_sidx);
191 auto u_err = [
this, U](
double T) {
192 m_thermo->setState_TD(T, m_mass / m_vol);
193 return m_thermo->intEnergy_mass() * m_mass - U;
195 double T = m_thermo->temperature();
196 boost::uintmax_t maxiter = 100;
197 pair<double, double> TT;
199 TT = bmt::bracket_and_solve_root(
200 u_err, T, 1.2,
true, bmt::eps_tolerance<double>(48), maxiter);
201 }
catch (std::exception&) {
205 TT = bmt::bisect(u_err, m_thermo->minTemp(), m_thermo->maxTemp(),
206 bmt::eps_tolerance<double>(48), maxiter);
207 }
catch (std::exception& err2) {
209 m_thermo->setState_TD(T, m_mass / m_vol);
211 "{}\nat U = {}, rho = {}", err2.what(), U, m_mass / m_vol);
214 if (fabs(TT.first - TT.second) > 1e-7*TT.first) {
215 throw CanteraError(
"MoleReactor::updateState",
"root finding failed");
217 m_thermo->setState_TD(TT.second, m_mass / m_vol);
219 m_thermo->setDensity(m_mass / m_vol);
221 updateConnected(
true);
222 updateSurfaceState(y + m_nsp + m_sidx);
225 void MoleReactor::eval(
double time,
double* LHS,
double* RHS)
227 double* dndt = RHS + m_sidx;
230 m_thermo->restoreState(m_state);
232 evalSurfaces(LHS + m_nsp + m_sidx, RHS + m_nsp + m_sidx, m_sdot.data());
234 const vector<double>& imw = m_thermo->inverseMolecularWeights();
239 m_kin->getNetProductionRates(&m_wdot[0]);
247 RHS[0] = - m_thermo->pressure() * m_vdot + m_Qdot;
252 for (
size_t k = 0; k < m_nsp; k++) {
254 dndt[k] = m_wdot[k] * m_vol + m_sdot[k];
258 for (
auto outlet : m_outlet) {
260 for (
size_t n = 0; n < m_nsp; n++) {
261 dndt[n] -= outlet->outletSpeciesMassFlowRate(n) * imw[n];
264 double mdot = outlet->massFlowRate();
266 RHS[0] -= mdot * m_enthalpy;
271 for (
auto inlet : m_inlet) {
272 double mdot = inlet->massFlowRate();
273 for (
size_t n = 0; n < m_nsp; n++) {
275 dndt[n] += inlet->outletSpeciesMassFlowRate(n) * imw[n];
278 RHS[0] += mdot * inlet->enthalpy_mass();
284 size_t MoleReactor::componentIndex(
const string& nm)
const
286 size_t k = speciesIndex(nm);
289 }
else if (nm ==
"int_energy") {
291 }
else if (nm ==
"volume") {
298 string MoleReactor::componentName(
size_t k) {
303 }
else if (k >= m_sidx && k < neq()) {
305 if (k < m_thermo->nSpecies()) {
306 return m_thermo->speciesName(k);
308 k -= m_thermo->nSpecies();
310 for (
auto& S : m_surfaces) {
312 if (k < th->nSpecies()) {
319 throw CanteraError(
"MoleReactor::componentName",
"Index is out of bounds.");
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.
Public interface for kinetics managers.
size_t kineticsSpeciesIndex(size_t k, size_t n) const
The location of species k of phase n in species arrays.
virtual void getNetProductionRates(double *wdot)
Species net production rates [kmol/m^3/s or kmol/m^2/s].
size_t nSpecies() const
Returns the number of species in the phase.
string speciesName(size_t k) const
Name of the species with index k.
A simple thermodynamic model for a surface phase, assuming an ideal solution model.
double size(size_t k) const
Returns the number of sites occupied by one molecule of species k.
Base class for a phase with thermodynamic properties.
Namespace for the Cantera kernel.
const size_t npos
index returned by functions to indicate "no position"
offset
Offsets of solution components in the 1D solution array.
Various templated functions that carry out common vector and polynomial operations (see Templated Arr...