Cantera  4.0.0a1
Loading...
Searching...
No Matches
ReactorSurface.cpp
Go to the documentation of this file.
1//! @file ReactorSurface.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
12#include <numeric>
13
14namespace Cantera
15{
16
17ReactorSurface::ReactorSurface(shared_ptr<Solution> soln,
18 span<shared_ptr<ReactorBase>> reactors,
19 bool clone,
20 const string& name)
21 : ReactorBase(name)
22{
23 if (reactors.empty()) {
24 throw CanteraError("ReactorSurface::ReactorSurface",
25 "Surface requires at least one adjacent reactor.");
26 }
27 vector<shared_ptr<Solution>> adjacent;
28 for (auto R : reactors) {
29 adjacent.push_back(R->phase());
30 m_reactors.push_back(R);
31 R->addSurface(this);
32 }
33 if (clone) {
34 m_solution = soln->clone(adjacent, true, false);
35 } else {
36 m_solution = soln;
37 }
38 m_solution->thermo()->addSpeciesLock();
39 m_surf = std::dynamic_pointer_cast<SurfPhase>(m_solution->thermo());
40 if (!m_surf) {
41 throw CanteraError("ReactorSurface::ReactorSurface",
42 "Solution object must have a SurfPhase object as the thermo manager.");
43 }
44
45 if (!soln->kinetics() ) {
46 throw CanteraError("ReactorSurface::ReactorSurface",
47 "Solution object must have kinetics manager.");
48 } else if (!std::dynamic_pointer_cast<InterfaceKinetics>(soln->kinetics())) {
49 throw CanteraError("ReactorSurface::ReactorSurface",
50 "Kinetics manager must be an InterfaceKinetics object.");
51 }
52 m_kinetics = std::dynamic_pointer_cast<InterfaceKinetics>(m_solution->kinetics());
53 m_thermo = m_surf.get();
54 m_nsp = m_nv = m_surf->nSpecies();
55 m_sdot.resize(m_kinetics->nTotalSpecies(), 0.0);
56}
57
59{
60 return m_area;
61}
62
64{
65 m_area = a;
66}
67
68void ReactorSurface::setCoverages(span<const double> cov)
69{
70 m_surf->setCoveragesNoNorm(cov);
71}
72
74{
75 m_surf->setCoveragesByName(cov);
76}
77
78void ReactorSurface::setCoverages(const string& cov)
79{
80 m_surf->setCoveragesByName(cov);
81}
82
83void ReactorSurface::getCoverages(span<double> cov) const
84{
85 m_surf->getCoverages(cov);
86}
87
88void ReactorSurface::getState(span<double> y)
89{
90 m_surf->getCoverages(y);
91}
92
94{
95 // Sync the surface temperature and pressure to that of the first adjacent reactor
96 m_thermo->setState_TP(m_reactors[0]->temperature(), m_reactors[0]->pressure());
97}
98
100{
101 return {0}; // sum of coverages constraint
102}
103
104void ReactorSurface::updateState(span<const double> y)
105{
106 m_surf->setCoveragesNoNorm(y);
107 m_thermo->setState_TP(m_reactors[0]->temperature(), m_reactors[0]->pressure());
108 m_kinetics->getNetProductionRates(m_sdot);
109}
110
111void ReactorSurface::eval(double t, span<double> LHS, span<double> RHS)
112{
113 size_t nsp = m_surf->nSpecies();
114 double rs0 = 1.0 / m_surf->siteDensity();
115 double sum = 0.0;
116 for (size_t k = 1; k < nsp; k++) {
117 RHS[k] = m_sdot[k] * rs0 * m_surf->size(k);
118 sum -= RHS[k];
119 }
120 RHS[0] = sum;
121}
122
123void ReactorSurface::evalSteady(double t, span<double> LHS, span<double> RHS)
124{
125 eval(t, LHS, RHS);
126 vector<double> cov(m_nsp);
127 m_surf->getCoverages(cov);
128 double sum = 0.0;
129 for (size_t k = 0; k < m_nsp; k++) {
130 sum += cov[k];
131 }
132 RHS[0] = 1.0 - sum;
133}
134
135void ReactorSurface::applySensitivity(span<const double> params)
136{
137 if (params.empty()) {
138 return;
139 }
140 for (auto& p : m_sensParams) {
141 if (p.type == SensParameterType::reaction) {
142 p.value = m_kinetics->multiplier(p.local);
143 m_kinetics->setMultiplier(p.local, p.value*params[p.global]);
144 } else if (p.type == SensParameterType::enthalpy) {
145 m_thermo->modifyOneHf298SS(p.local, p.value + params[p.global]);
146 }
147 }
148 m_thermo->invalidateCache();
149 m_kinetics->invalidateCache();
150}
151
152void ReactorSurface::resetSensitivity(span<const double> params)
153{
154 if (params.empty()) {
155 return;
156 }
157 for (auto& p : m_sensParams) {
158 if (p.type == SensParameterType::reaction) {
159 m_kinetics->setMultiplier(p.local, p.value);
160 } else if (p.type == SensParameterType::enthalpy) {
161 m_thermo->resetHf298(p.local);
162 }
163 }
164 m_thermo->invalidateCache();
165 m_kinetics->invalidateCache();
166}
167
169{
170 if (rxn >= m_kinetics->nReactions()) {
171 throw CanteraError("ReactorSurface::addSensitivityReaction",
172 "Reaction number out of range ({})", rxn);
173 }
174 size_t p = m_reactors[0]->network().registerSensitivityParameter(
175 m_kinetics->reaction(rxn)->equation(), 1.0, 1.0);
176 m_sensParams.emplace_back(
177 SensitivityParameter{rxn, p, 1.0, SensParameterType::reaction});
178}
179
180size_t ReactorSurface::componentIndex(const string& nm) const
181{
182 return m_surf->speciesIndex(nm);
183}
184
186{
187 return m_surf->speciesName(k);
188}
189
190double ReactorSurface::upperBound(size_t k) const
191{
192 return 1.0;
193}
194
195double ReactorSurface::lowerBound(size_t k) const
196{
197 return -Tiny;
198}
199
201{
202 for (size_t k = 0; k < m_nsp; k++) {
203 y[k] = std::max(y[k], 0.0);
204 }
205 m_surf->setCoverages(y);
206 m_surf->getCoverages(y);
207}
208
209// ------ MoleReactorSurface methods ------
210
212{
214 m_cov_tmp.resize(m_nsp);
215 m_f_energy.resize(m_kinetics->nTotalSpecies(), 0.0);
216 m_f_species.resize(m_kinetics->nTotalSpecies(), 0.0);
217 m_kin2net.resize(m_kinetics->nTotalSpecies(), -1);
218 m_kin2reactor.resize(m_kinetics->nTotalSpecies(), nullptr);
219
220 for (size_t k = 0; k < m_nsp; k++) {
221 m_kin2net[k] = static_cast<int>(m_offset + k);
222 }
223 for (auto R : m_reactors) {
224 size_t nsp = R->phase()->thermo()->nSpecies();
225 size_t k0 = m_kinetics->speciesOffset(*R->phase()->thermo());
226 int offset = static_cast<int>(R->offset() + R->speciesOffset());
227 for (size_t k = 0; k < nsp; k++) {
228 m_kin2net[k + k0] = offset + k;
229 m_kin2reactor[k + k0] = R.get();
230 }
231 }
232}
233
235{
236 m_surf->getCoverages(y);
237 double totalSites = m_surf->siteDensity() * m_area;
238 for (size_t k = 0; k < m_nsp; k++) {
239 y[k] *= totalSites / m_surf->size(k);
240 }
241}
242
243void MoleReactorSurface::updateDefaultTolerances(span<double> atol, double baseAtol)
244{
245 vector<double> y(neq());
246 getState(y);
247 double totalMoles = std::accumulate(y.begin(), y.end(), 0.0);
248 if (totalMoles <= 0.0) {
249 return;
250 }
251 std::fill(atol.begin(), atol.end(), baseAtol * totalMoles);
252}
253
254void MoleReactorSurface::updateState(span<const double> y)
255{
256 std::copy(y.begin(), y.end(), m_cov_tmp.begin());
257 double totalSites = m_surf->siteDensity() * m_area;
258 for (size_t k = 0; k < m_nsp; k++) {
259 m_cov_tmp[k] *= m_surf->size(k) / totalSites;
260 }
261 m_surf->setCoveragesNoNorm(m_cov_tmp);
262 m_thermo->setState_TP(m_reactors[0]->temperature(), m_reactors[0]->pressure());
263 m_kinetics->getNetProductionRates(m_sdot);
264}
265
266void MoleReactorSurface::eval(double t, span<double> LHS, span<double> RHS)
267{
268 for (size_t k = 0; k < m_nsp; k++) {
269 RHS[k] = m_sdot[k] * m_area;
270 }
271}
272
273void MoleReactorSurface::evalSteady(double t, span<double> LHS, span<double> RHS)
274{
275 eval(t, LHS, RHS);
276 double cov_sum = 0.0;
277 for (size_t k = 0; k < m_nsp; k++) {
278 cov_sum += m_cov_tmp[k];
279 }
280 RHS[0] = 1.0 - cov_sum;
281}
282
283double MoleReactorSurface::upperBound(size_t k) const
284{
285 return BigNumber;
286}
287
288double MoleReactorSurface::lowerBound(size_t k) const
289{
290 return -Tiny;
291}
292
294{
295 for (size_t k = 0; k < m_nsp; k++) {
296 y[k] = std::max(y[k], 0.0);
297 }
298}
299
300void MoleReactorSurface::getJacobianElements(vector<Eigen::Triplet<double>>& trips)
301{
302 auto sdot_ddC = m_kinetics->netProductionRates_ddCi();
303 for (auto R : m_reactors) {
304 double f_species;
305 size_t nsp_R = R->phase()->thermo()->nSpecies();
306 size_t k0 = m_kinetics->speciesOffset(*R->phase()->thermo());
307 R->getJacobianScalingFactors(f_species, span<double>(&m_f_energy[k0], nsp_R));
308 std::fill(&m_f_species[k0], &m_f_species[k0 + nsp_R], m_area * f_species);
309 }
310 std::fill(&m_f_species[0], &m_f_species[m_nsp], 1.0); // surface species
311 for (int k = 0; k < sdot_ddC.outerSize(); k++) {
312 int col = m_kin2net[k];
313 if (col == -1) {
314 continue;
315 }
316 for (Eigen::SparseMatrix<double>::InnerIterator it(sdot_ddC, k); it; ++it) {
317 int row = m_kin2net[it.row()];
318 if (row == -1 || it.value() == 0.0) {
319 continue;
320 }
321 ReactorBase* R = m_kin2reactor[it.row()];
322 trips.emplace_back(row, col, it.value() * m_f_species[k]);
323 if (m_f_energy[it.row()] != 0.0) {
324 trips.emplace_back(R->offset(), col,
325 it.value() * m_f_energy[it.row()] * m_f_species[k]);
326 }
327 }
328 }
329}
330
331// ------ FlowReactorSurface methods ------
332
334 span<shared_ptr<ReactorBase>> reactors,
335 bool clone,
336 const string& name)
337 : ReactorSurface(soln, reactors, clone, name)
338{
339 m_area = -1.0; // default to perimeter of cylindrical reactor
340}
341
343 if (m_area > 0) {
344 return m_area;
345 }
346
347 // Assuming a cylindrical cross section, P = 2 * pi * r and A = pi * r^2, so
348 // P(A) = 2 * sqrt(pi * A)
349 return 2.0 * sqrt(Pi * m_reactors[0]->area());
350}
351
352void FlowReactorSurface::evalDae(double t, span<const double> y,
353 span<const double> ydot, span<double> residual)
354{
355 size_t nsp = m_surf->nSpecies();
356 double sum = y[0];
357 for (size_t k = 1; k < nsp; k++) {
358 residual[k] = m_sdot[k];
359 sum += y[k];
360 }
361 residual[0] = sum - 1.0;
362}
363
364void FlowReactorSurface::getStateDae(span<double> y, span<double> ydot)
365{
366 // Advance the surface to steady state to get consistent initial coverages
367 m_kinetics->advanceCoverages(100.0, m_ss_rtol, m_ss_atol, 0, m_max_ss_steps,
369 getCoverages(y);
370 // Update the values in m_sdot that are needed by the adjacent FlowReactor
371 updateState(y);
372}
373
374void FlowReactorSurface::getConstraints(span<double> constraints)
375{
376 // The species coverages are algebraic constraints
377 std::fill(constraints.begin(), constraints.end(), 1.0);
378}
379
380}
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.
FlowReactorSurface(shared_ptr< Solution > soln, span< shared_ptr< ReactorBase > > reactors, bool clone, const string &name="(none)")
Create a new ReactorSurface.
double area() const override
Surface area per unit length [m].
double m_ss_rtol
steady-state relative tolerance, used to determine initial surface coverages
int m_max_ss_error_fails
maximum number of steady-state integrator error test failures
void getConstraints(span< double > constraints) override
Given a vector of length neq(), mark which variables should be considered algebraic constraints.
int m_max_ss_steps
maximum number of steady-state coverage integrator-steps
void evalDae(double t, span< const double > y, span< const double > ydot, span< double > residual) override
Evaluate the reactor governing equations.
double m_ss_atol
steady-state absolute tolerance, used to determine initial surface coverages
void getStateDae(span< double > y, span< double > ydot) override
Get the current state and derivative vector of the reactor for a DAE solver.
double upperBound(size_t k) const override
Get the upper bound on the k-th component of the local state vector.
void resetBadValues(span< double > y) override
Reset physically or mathematically problematic values, such as negative species concentrations.
vector< double > m_f_energy
Temporary storage for d(energy)/d(moles) scaling factors.
void eval(double t, span< double > LHS, span< double > RHS) override
Evaluate the reactor governing equations.
vector< Eigen::SparseMatrix< double >::StorageIndex > m_kin2net
Mapping from InterfaceKinetics species index to ReactorNet state vector index.
void evalSteady(double t, span< double > LHS, span< double > RHS) override
Evaluate the governing equations with modifications for the steady-state solver.
vector< double > m_f_species
Temporary storage for d(moles)/d(moles) scaling factor.
vector< ReactorBase * > m_kin2reactor
Mapping from InterfaceKinetics species index to the corresponding reactor.
void getJacobianElements(vector< Eigen::Triplet< double > > &trips) override
Get Jacobian elements for this reactor within the full reactor network.
double lowerBound(size_t k) const override
Get the lower bound on the k-th component of the local state vector.
void initialize(double t0=0.0) override
Initialize the reactor.
void updateState(span< const double > y) override
Set the state of the reactor to correspond to the state vector y.
vector< double > m_cov_tmp
Temporary storage for coverages.
void updateDefaultTolerances(span< double > atol, double baseAtol) override
Update default absolute tolerances based on this reactor's state variables.
void getState(span< double > y) override
Get the current state of the reactor.
Base class for reactor objects.
Definition ReactorBase.h:51
shared_ptr< Solution > m_solution
Composite thermo/kinetics/transport handler.
double pressure() const
Returns the current pressure (Pa) of the reactor.
size_t neq()
Number of equations (state variables) for this reactor.
size_t m_nv
Number of state variables for this reactor.
double temperature() const
Returns the current temperature (K) of the reactor's contents.
size_t m_offset
Offset into global ReactorNet state vector.
vector< double > m_sdot
species production rates on surfaces
size_t m_nsp
Number of homogeneous species in the mixture.
size_t offset() const
Get the starting offset for this reactor's state variables within the global state vector of the Reac...
A surface where reactions can occur that is in contact with the bulk fluid of a Reactor.
double upperBound(size_t k) const override
Get the upper bound on the k-th component of the local state vector.
void resetBadValues(span< double > y) override
Reset physically or mathematically problematic values, such as negative species concentrations.
void eval(double t, span< double > LHS, span< double > RHS) override
Evaluate the reactor governing equations.
double area() const override
Returns the surface area [m²].
void evalSteady(double t, span< double > LHS, span< double > RHS) override
Evaluate the governing equations with modifications for the steady-state solver.
ReactorSurface(shared_ptr< Solution > soln, span< shared_ptr< ReactorBase > > reactors, bool clone, const string &name="(none)")
Create a new ReactorSurface.
void setArea(double a) override
Set the surface area [m²].
size_t componentIndex(const string &nm) const override
Return the index in the solution vector for this reactor of the component named nm.
void setCoverages(span< const double > cov)
Set the surface coverages.
void resetSensitivity(span< const double > params) override
Reset the reaction rate multipliers.
void applySensitivity(span< const double > params) override
Set reaction rate multipliers based on the sensitivity variables in params.
vector< size_t > initializeSteady() override
Initialize the reactor before solving a steady-state problem.
void addSensitivityReaction(size_t rxn) override
Add a sensitivity parameter associated with the reaction number rxn
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.
shared_ptr< ReactorBase > adjacent(size_t n)
Access an adjacent Reactor or Reservoir.
void getCoverages(span< double > cov) const
Get the surface coverages.
void initialize(double t0=0.0) override
Initialize the reactor.
void updateState(span< const double > y) override
Set the state of the reactor to correspond to the state vector y.
void getState(span< double > y) override
Get the current state of the reactor.
virtual void setState_TP(double t, double p)
Set the temperature (K) and pressure (Pa)
virtual void modifyOneHf298SS(const size_t k, const double Hf298New)
Modify the value of the 298 K Heat of Formation of one species in the phase (J kmol-1)
void invalidateCache() override
Invalidate any cached values which are normally updated only when a change in state is detected.
virtual void resetHf298(const size_t k=npos)
Restore the original heat of formation of one or more species.
const double Pi
Pi.
Definition ct_defs.h:71
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:176
offset
Offsets of solution components in the 1D solution array.
Definition Flow1D.h:25
const double BigNumber
largest number to compare to inf.
Definition ct_defs.h:163
map< string, double > Composition
Map from string names to doubles.
Definition ct_defs.h:180