Cantera  4.0.0a1
Loading...
Searching...
No Matches
LinearBurkeRate.cpp
Go to the documentation of this file.
1//! @file LinearBurkeRate.cpp
2// This file is part of Cantera. See License.txt in the top-level directory or
3// at https://cantera.org/license.txt for license and copyright information.
4
8
9using std::get; // for std::variant
10
11namespace Cantera
12{
13
14LinearBurkeData::LinearBurkeData()
15{
16 moleFractions.resize(1, NAN);
17}
18
19bool LinearBurkeData::update(const ThermoPhase& phase, const Kinetics& kin)
20{
21 int X = phase.stateMFNumber();
22 double T = phase.temperature();
23 double P = phase.pressure();
24 if (moleFractions.empty()) {
25 moleFractions.resize(kin.nTotalSpecies());
26 }
27 if (P != pressure || T != temperature || X != mf_number) {
29 pressure = P;
30 logP = std::log(P);
31 mf_number = X;
32 phase.getMoleFractions(moleFractions);
33 return true;
34 }
35 return false;
36}
37
39{
40 if (m_pressure_buf > 0.) {
41 throw CanteraError("LinearBurkeData::perturbPressure",
42 "Cannot apply another perturbation as state is already perturbed.");
43 }
44 m_pressure_buf = pressure;
45 update(temperature, pressure * (1. + deltaP));
46}
47
49{
51 if (m_pressure_buf < 0.) {
52 return;
53 }
54 update(temperature, m_pressure_buf);
55 m_pressure_buf = -1.;
56}
57
59{
60 moleFractions.resize(kin.nTotalSpecies(), NAN);
61 ready = true;
62}
63
64
65LinearBurkeRate::LinearBurkeRate(const AnyMap& node, const UnitStack& rate_units)
66{
67 setParameters(node, rate_units);
68}
69
70void LinearBurkeRate::setParameters(const AnyMap& node, const UnitStack& rate_units)
71{
72 UnitStack eps_units{{Units(1.0), 1.0}};
73 ReactionRate::setParameters(node, rate_units);
74 if (!node.hasKey("colliders")) {
75 throw InputFileError("LinearBurkeRate::setParameters", m_input,
76 "'colliders' key missing");
77 }
78 auto colliders = node["colliders"].asVector<AnyMap>();
79 if (!colliders[0].hasKey("name")) {
80 throw InputFileError("LinearBurkeRate::setParameters", colliders[0],
81 "'name' key missing from collider entry");
82 } else if (colliders[0]["name"].asString() != "M") {
83 throw InputFileError("LinearBurkeRate::setParameters", colliders[0],
84 "The first collider must be 'M'. Found '{}'.", colliders[0]["name"].asString());
85 } else if (!colliders[0].hasKey("type")) {
86 throw InputFileError("LinearBurkeRate::setParameters", colliders[0],
87 "'type' key missing for 'M'. Must be either 'falloff'"
88 " (Troe format), 'pressure-dependent-Arrhenius', or 'Chebyshev'.");
89 } else if (colliders[0].hasKey("efficiency")) { //
90 if (colliders[0]["efficiency"]["A"] != 1 ||
91 colliders[0]["efficiency"]["b"] != 0 ||
92 colliders[0]["efficiency"]["Ea"] != 0) {
93 throw InputFileError("LinearBurkeRate::setParameters", colliders[0],
94 "It is not necessary to provide an 'efficiency' for 'M', "
95 "as it is always equal to 1, by definition. However, if it is "
96 "entered, then it must be: 'efficiency: {A: 1, b: 0, Ea: 0}'.");
97 }
98 }
99 if (colliders[0]["type"] == "pressure-dependent-Arrhenius") {
100 m_rateObj_M = PlogRate(colliders[0], rate_units);
102 } else if (colliders[0]["type"] == "falloff" && colliders[0].hasKey("Troe")) {
103 TroeRate troeRateObj = TroeRate(colliders[0], rate_units);
104 troeRateObj.setRateIndex(0);
105 m_rateObj_M = troeRateObj;
107 } else if (colliders[0]["type"] == "Chebyshev") {
108 m_rateObj_M = ChebyshevRate(colliders[0], rate_units);
110 } else {
111 throw InputFileError("LinearBurkeRate::setParameters", colliders[0],
112 "Collider 'M' must be specified in a pressure-dependent-Arrhenius (PLOG), "
113 "falloff (Troe form), or Chebyshev format.");
114 }
115 AnyMap params;
116 params["A"] = 1.0;
117 params["b"] = 0.0;
118 params["Ea"] = 0.0;
119 m_epsObj_M = ArrheniusRate(AnyValue(params), colliders[0].units(), eps_units);
120 string eig_eps_key, conflicting_key;
121 // If using eig0 for all colliders, then it is mandatory to specify an eig0 value
122 // for the reference collider
123 if (colliders[0].hasKey("eig0")) {
124 eig_eps_key = "eig0";
125 conflicting_key = "efficiency";
126 } else {
127 eig_eps_key = "efficiency";
128 conflicting_key = "eig0";
129 colliders[0][eig_eps_key] = params;
130 }
131 // Start at 1 because index 0 is for "M"
132 for (size_t i = 1; i < colliders.size(); i++) {
133 if (!colliders[i].hasKey("name")) {
134 throw InputFileError("LinearBurkeRate::setParameters", colliders[i],
135 "'name' key missing from collider entry");
136 }
137 auto nm = colliders[i]["name"].asString();
138 if (!colliders[i].hasKey(eig_eps_key)) {
139 throw InputFileError("LinearBurkeRate::setParameters", colliders[i],
140 "Collider '{}' lacks an '{}' key.", nm, eig_eps_key);
141 }
142 if (colliders[i].hasKey(conflicting_key)) {
143 throw InputFileError("LinearBurkeRate::setParameters", colliders[i],
144 "Collider '{}' cannot contain both 'efficiency' and 'eig0'. All "
145 "additional colliders must also make the same choice as that of 'M'.",
146 nm);
147 }
148 m_colliderNames.push_back(colliders[i]["name"].as<string>());
149
150 ArrheniusRate epsObj_i;
151 // eig0 and eps are ONLY interchangeable due to the requirement that eps_M have
152 // parameters {A: 1, b: 0, Ea: 0}
153 params["A"] = colliders[i][eig_eps_key]["A"].asDouble() /
154 colliders[0][eig_eps_key]["A"].asDouble();
155 params["b"] = colliders[i][eig_eps_key]["b"].asDouble() -
156 colliders[0][eig_eps_key]["b"].asDouble();
157 params["Ea"] = colliders[i][eig_eps_key]["Ea"].asDouble() -
158 colliders[0][eig_eps_key]["Ea"].asDouble();
159
160 if (params["A"].asDouble() < 0) {
161 throw InputFileError("LinearBurkeRate::setParameters", colliders[i],
162 "Invalid '{}' entry for collider '{}'.", eig_eps_key, nm);
163 }
164
165 epsObj_i = ArrheniusRate(AnyValue(params), colliders[i].units(), eps_units);
166 if (colliders[i].hasKey("type")) {
167 if (colliders[i]["type"] == "pressure-dependent-Arrhenius") {
168 m_rateObjs.push_back(PlogRate(colliders[i], rate_units));
169 m_dataObjs.push_back(PlogData());
170 m_epsObjs1.push_back(epsObj_i);
171 m_epsObjs2.push_back(epsObj_i);
172 } else if (colliders[i]["type"] == "falloff"
173 && colliders[i].hasKey("Troe"))
174 {
175 TroeRate troeRateObj = TroeRate(colliders[i], rate_units);
176 troeRateObj.setRateIndex(0);
177 m_rateObjs.push_back(troeRateObj);
178 m_dataObjs.push_back(FalloffData());
179 m_epsObjs1.push_back(epsObj_i);
180 m_epsObjs2.push_back(epsObj_i);
181 } else if (colliders[i]["type"] == "Chebyshev") {
182 m_rateObjs.push_back(ChebyshevRate(colliders[i], rate_units));
183 m_dataObjs.push_back(ChebyshevData());
184 m_epsObjs1.push_back(epsObj_i);
185 m_epsObjs2.push_back(epsObj_i);
186 } else {
187 throw InputFileError("LinearBurkeRate::setParameters", colliders[i],
188 "Collider '{}': '{}' rate parameterization is not supported. Must "
189 "be one of 'pressure-dependent-Arrhenius (PLOG), 'falloff' (Troe "
190 "form), or 'Chebyshev'.",
191 m_colliderNames[i-1], colliders[i]["type"].asString());
192 }
193 m_hasRateConstant.push_back(true);
194 } else {
195 // Collider has an 'efficiency' specified, but no other info is provided.
196 // Assign it the same rate and data objects as "M"
197 m_rateObjs.push_back(m_rateObj_M);
198 m_dataObjs.push_back(m_dataObj_M);
199 m_epsObjs1.push_back(epsObj_i);
200 m_epsObjs2.push_back(m_epsObj_M);
201 m_hasRateConstant.push_back(false);
202 }
203 }
204}
205
206void LinearBurkeRate::validate(const string& equation, const Kinetics& kin) {}
207
209{
210 m_colliderIndices.clear();
211 for (size_t i = 0; i<m_colliderNames.size(); i++) {
213 }
214}
215
217 DataTypes& dataObj, RateTypes& rateObj, double logPeff)
218{
219 PlogData& data = std::get<PlogData>(dataObj);
220 PlogRate& rate = std::get<PlogRate>(rateObj);
221 // Replace logP with log of the effective pressure with respect to eps
222 data.logP = logPeff;
223 data.logT = shared_data.logT;
224 data.recipT = shared_data.recipT;
225 rate.updateFromStruct(data);
226 return rate.evalFromStruct(data);
227}
228
230 DataTypes& dataObj, RateTypes& rateObj, double logPeff)
231{
232 FalloffData& data = get<FalloffData>(dataObj);
233 TroeRate& rate = get<TroeRate>(rateObj);
234 data.conc_3b = {exp(logPeff) / GasConstant / shared_data.temperature};
235 data.logT = shared_data.logT;
236 data.recipT = shared_data.recipT;
237 data.temperature = shared_data.temperature;
238 return rate.evalFromStruct(data);
239}
240
242 DataTypes& dataObj, RateTypes& rateObj, double logPeff)
243{
244 ChebyshevData& data = get<ChebyshevData>(dataObj);
245 ChebyshevRate& rate = get<ChebyshevRate>(rateObj);
246 data.log10P = log10(exp(logPeff));
247 data.logT = shared_data.logT;
248 data.recipT = shared_data.recipT;
249 rate.updateFromStruct(data);
250 return rate.evalFromStruct(data);
251}
252
253double LinearBurkeRate::evalFromStruct(const LinearBurkeData& shared_data)
254{
255 double sigmaX_M = 0.0;
256 // Test each species listed at the top of the YAML file
257 for (size_t i = 0; i < shared_data.moleFractions.size(); i++) {
258 // Total sum will be essentially 1, but perhaps not exactly due to Cantera's
259 // rounding conventions
260 sigmaX_M += shared_data.moleFractions[i];
261 }
262 double eps_mix = 0.0; // mole-fraction-weighted overall eps value of the mixtures
263 for (size_t j = 0; j < m_colliderIndices.size(); j++) {
264 size_t i = m_colliderIndices[j];
265 eps_mix += shared_data.moleFractions[i]
266 * m_epsObjs1[j].evalRate(shared_data.logT, shared_data.recipT);
267 sigmaX_M -= shared_data.moleFractions[i];
268 }
269 // Add all M colliders to eps_mix in a single step
270 eps_mix += sigmaX_M; // eps_mix += sigmaX_M * eps_M, but eps_M = 1 always
271 if (eps_mix == 0) {
272 throw InputFileError("LinearBurkeRate::evalFromStruct", m_input,
273 "eps_mix == 0 for some reason");
274 }
275 double k_LMR_ = 0.0;
276 double logPeff;
277 for (size_t j = 0; j < m_colliderIndices.size(); j++) {
278 size_t i = m_colliderIndices[j];
279 double eps1 = m_epsObjs1[j].evalRate(shared_data.logT, shared_data.recipT);
280 double eps2 = m_epsObjs2[j].evalRate(shared_data.logT, shared_data.recipT);
281 // eps2 equals either eps_M or eps_i, depending on the scenario
282 // effective pressure as a function of eps
283 logPeff = shared_data.logP + log(eps_mix) - log(eps2);
284 if (m_rateObjs[j].index() == 0) { // 0 means PlogRate
285 k_LMR_ += evalPlogRate(shared_data, m_dataObjs[j], m_rateObjs[j], logPeff)
286 * eps1 * shared_data.moleFractions[i] / eps_mix;
287 } else if (m_rateObjs[j].index() == 1) { // 1 means TroeRate
288 k_LMR_ += evalTroeRate(shared_data, m_dataObjs[j], m_rateObjs[j], logPeff)
289 * eps1 * shared_data.moleFractions[i] / eps_mix;
290 } else if (m_rateObjs[j].index() == 2) { // 2 means ChebyshevRate
291 k_LMR_ += evalChebyshevRate(shared_data, m_dataObjs[j], m_rateObjs[j], logPeff)
292 * eps1 * shared_data.moleFractions[i] / eps_mix;
293 } else {
294 throw InputFileError("LinearBurkeRate::evalFromStruct", m_input,
295 "Something went wrong...");
296 }
297 }
298 // We actually have
299 // logPeff = shared_data.logP + log(eps_mix) - log(eps_M)
300 // but log(eps_M)=0 always
301 logPeff = shared_data.logP + log(eps_mix);
302
303 // We actually have
304 // k_LMR_+=evalPlogRate(shared_data,m_dataObj_M,m_rateObj_M)*eps_M*sigmaX_M/eps_mix
305 // k_LMR_+=evalTroeRate(shared_data,m_dataObj_M,m_rateObj_M)*eps_M*sigmaX_M/eps_mix
306 // etc., but eps_M = 1 always
307 if (m_rateObj_M.index() == 0) { // 0 means PlogRate
308 k_LMR_ += evalPlogRate(shared_data, m_dataObj_M, m_rateObj_M, logPeff) *
309 sigmaX_M / eps_mix;
310 } else if (m_rateObj_M.index() == 1) { // 1 means TroeRate
311 k_LMR_ += evalTroeRate(shared_data, m_dataObj_M, m_rateObj_M, logPeff) *
312 sigmaX_M / eps_mix;
313 } else if (m_rateObj_M.index() == 2) { // 2 means ChebyshevRate
314 k_LMR_ += evalChebyshevRate(shared_data, m_dataObj_M, m_rateObj_M, logPeff) *
315 sigmaX_M / eps_mix;
316 }
317 return k_LMR_;
318}
319
321{
322 vector<AnyMap> topLevelList;
323 AnyMap M_node, M_params;
324 M_node["name"] = "M";
325 if (m_rateObj_M.index() == 0) {
326 auto& rate = get<PlogRate>(m_rateObj_M);
327 M_params = rate.parameters();
328 } else if (m_rateObj_M.index() == 1) {
329 auto& rate = get<TroeRate>(m_rateObj_M);
330 M_params = rate.parameters();
331 } else if (m_rateObj_M.index() == 2) {
332 auto& rate = get<ChebyshevRate>(m_rateObj_M);
333 M_params = rate.parameters();
334 }
335 M_node.update(M_params);
336 topLevelList.push_back(std::move(M_node));
337
338 for (size_t i = 0; i < m_colliderNames.size(); i++) {
339 AnyMap collider, efficiency, params;
340 collider["name"] = m_colliderNames[i];
341 m_epsObjs1[i].getRateParameters(efficiency);
342 collider["efficiency"] = std::move(efficiency);
343 if (m_hasRateConstant[i]) {
344 const auto& var_rate = m_rateObjs[i];
345 if (var_rate.index() == 0) {
346 auto& rate = get<PlogRate>(var_rate);
347 params = rate.parameters();
348 } else if (var_rate.index() == 1) {
349 auto& rate = get<TroeRate>(var_rate);
350 params = rate.parameters();
351 } else if (var_rate.index() == 2) {
352 auto& rate = get<ChebyshevRate>(var_rate);
353 params = rate.parameters();
354 }
355 collider.update(params);
356 }
357 topLevelList.push_back(std::move(collider));
358 }
359 rateNode["colliders"] = std::move(topLevelList);
360}
361
362}
Base class for kinetics managers and also contains the kineticsmgr module documentation (see Kinetics...
Header file for class ThermoPhase, the base class for phases with thermodynamic properties,...
A map of string keys to values whose type can vary at runtime.
Definition AnyMap.h:431
bool hasKey(const string &key) const
Returns true if the map contains an item named key.
Definition AnyMap.cpp:1477
void update(const AnyMap &other, bool keepExisting=true)
Add items from other to this AnyMap.
Definition AnyMap.cpp:1493
A wrapper for a variable whose type is determined at runtime.
Definition AnyMap.h:88
Arrhenius reaction rate type depends only on temperature.
Definition Arrhenius.h:170
Base class for exceptions thrown by Cantera classes.
Pressure-dependent rate expression where the rate coefficient is expressed as a bivariate Chebyshev p...
void updateFromStruct(const ChebyshevData &shared_data)
Update information specific to reaction.
double evalFromStruct(const ChebyshevData &shared_data)
Evaluate reaction rate.
double evalFromStruct(const FalloffData &shared_data)
Evaluate reaction rate.
Definition Falloff.h:154
Error thrown for problems processing information contained in an AnyMap or AnyValue.
Definition AnyMap.h:749
Public interface for kinetics managers.
Definition Kinetics.h:126
size_t kineticsSpeciesIndex(size_t k, size_t n) const
The location of species k of phase n in species arrays.
Definition Kinetics.h:273
size_t nTotalSpecies() const
The total number of species in all phases participating in the kinetics mechanism.
Definition Kinetics.h:251
void getParameters(AnyMap &rateNode) const override
Get parameters.
std::variant< PlogData, FalloffData, ChebyshevData > DataTypes
Type alias that refers to PlogData, FalloffData, and ChebyshevData.
double evalTroeRate(const LinearBurkeData &shared_data, DataTypes &dataObj, RateTypes &rateObj, double logPeff)
Evaluate overall reaction rate using Troe to evaluate pressure-dependent aspect of the reaction.
std::variant< PlogRate, TroeRate, ChebyshevRate > RateTypes
Type alias that refers to PlogRate, TroeRate, and ChebyshevRate.
void setContext(const Reaction &rxn, const Kinetics &kin) override
Set context of reaction rate evaluation.
vector< string > m_colliderNames
String name of each collider, appearing in the same order as that of the original reaction input.
void setParameters(const AnyMap &node, const UnitStack &rate_units) override
Perform object setup based on AnyMap node information.
vector< RateTypes > m_rateObjs
Stores rate objects corresponding to each non-M collider, which can be either PlogRate,...
LinearBurkeRate()=default
Default constructor.
DataTypes m_dataObj_M
Stores data objects corresponding to the reference collider M, which can be either PlogData,...
void validate(const string &equation, const Kinetics &kin) override
Validate the reaction rate expression.
double evalChebyshevRate(const LinearBurkeData &shared_data, DataTypes &dataObj, RateTypes &rateObj, double logPeff)
Evaluate overall reaction rate using Chebyshev to evaluate pressure-dependent aspect of the reaction.
ArrheniusRate m_epsObj_M
Third-body collision efficiency object for the reference collider M (eig0_M/eig0_M = 1 always)
vector< size_t > m_colliderIndices
Index of each collider in the kinetics object species list where the vector elements appear in the sa...
vector< ArrheniusRate > m_epsObjs1
Third-body collision efficiency object for k(T,P,X) and eig0_mix calculation.
double evalPlogRate(const LinearBurkeData &shared_data, DataTypes &dataObj, RateTypes &rateObj, double logPeff)
Evaluate overall reaction rate using PLOG to evaluate pressure-dependent aspect of the reaction.
vector< bool > m_hasRateConstant
Indicates which colliders have a distinct k(T,P) versus only an efficiency.
vector< ArrheniusRate > m_epsObjs2
Third-body collision efficiency object for logPeff calculation.
RateTypes m_rateObj_M
Stores rate objects corresponding the reference collider M, which can be either PlogRate,...
vector< DataTypes > m_dataObjs
Stores data objects corresponding to each non-M collider, which can be either PlogData,...
void getMoleFractions(span< double > x) const
Get the species mole fraction vector.
Definition Phase.cpp:441
double temperature() const
Temperature (K).
Definition Phase.h:585
int stateMFNumber() const
Return the State Mole Fraction Number.
Definition Phase.h:794
virtual double pressure() const
Return the thermodynamic pressure (Pa).
Definition Phase.h:603
Pressure-dependent reaction rate expressed by logarithmically interpolating between Arrhenius rate ex...
Definition PlogRate.h:77
void updateFromStruct(const PlogData &shared_data)
Update information specific to reaction.
Definition PlogRate.h:110
double evalFromStruct(const PlogData &shared_data)
Evaluate reaction rate.
Definition PlogRate.h:141
virtual void setParameters(const AnyMap &node, const UnitStack &units)
Set parameters.
void setRateIndex(size_t idx)
Set reaction rate index within kinetics evaluator.
AnyMap m_input
Input data used for specific models.
Abstract base class which stores data about a reaction and its rate parameterization so that it can b...
Definition Reaction.h:25
Base class for a phase with thermodynamic properties.
The 3- or 4-parameter Troe falloff parameterization.
Definition Falloff.h:311
A representation of the units associated with a dimensional quantity.
Definition Units.h:35
const double GasConstant
Universal Gas Constant [J/kmol/K].
Definition ct_defs.h:123
Namespace for the Cantera kernel.
Definition AnyMap.cpp:595
Data container holding shared data specific to ChebyshevRate.
double log10P
base 10 logarithm of pressure
Data container holding shared data specific to Falloff rates.
Definition Falloff.h:21
vector< double > conc_3b
vector of effective third-body concentrations
Definition Falloff.h:49
Data container holding shared data specific to LinearBurkeRate.
void perturbPressure(double deltaP)
Perturb pressure of data container.
double logP
Logarithm of pressure.
bool ready
Boolean indicating whether vectors are accessible.
void restore() override
Restore data container after a perturbation.
virtual void resize(Kinetics &kin) override
Update array sizes that depend on number of species, reactions and phases.
void update(double T, double P) override
Update data container based on temperature T and an extra parameter.
Data container holding shared data specific to PlogRate.
Definition PlogRate.h:20
double logP
logarithm of pressure
Definition PlogRate.h:50
double recipT
inverse of temperature
virtual void update(double T)
Update data container based on temperature T
double temperature
temperature
double logT
logarithm of temperature
virtual void restore()
Restore data container after a perturbation.
Unit aggregation utility.
Definition Units.h:105