Cantera  3.1.0
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.data());
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
58LinearBurkeRate::LinearBurkeRate(const AnyMap& node, const UnitStack& rate_units)
59{
60 setParameters(node, rate_units);
61}
62
63void LinearBurkeRate::setParameters(const AnyMap& node, const UnitStack& rate_units)
64{
65 UnitStack eps_units{{Units(1.0), 1.0}};
66 ReactionRate::setParameters(node, rate_units);
67 if (!node.hasKey("colliders")) {
68 throw InputFileError("LinearBurkeRate::setParameters", m_input,
69 "'colliders' key missing");
70 }
71 auto colliders = node["colliders"].asVector<AnyMap>();
72 if (!colliders[0].hasKey("name")) {
73 throw InputFileError("LinearBurkeRate::setParameters", colliders[0],
74 "'name' key missing from collider entry");
75 } else if (colliders[0]["name"].asString() != "M") {
76 throw InputFileError("LinearBurkeRate::setParameters", colliders[0],
77 "The first collider must be 'M'. Found '{}'.", colliders[0]["name"].asString());
78 } else if (!colliders[0].hasKey("type")) {
79 throw InputFileError("LinearBurkeRate::setParameters", colliders[0],
80 "'type' key missing for 'M'. Must be either 'falloff'"
81 " (Troe format), 'pressure-dependent-Arrhenius', or 'Chebyshev'.");
82 } else if (colliders[0].hasKey("efficiency")) { //
83 if (colliders[0]["efficiency"]["A"] != 1 ||
84 colliders[0]["efficiency"]["b"] != 0 ||
85 colliders[0]["efficiency"]["Ea"] != 0) {
86 throw InputFileError("LinearBurkeRate::setParameters", colliders[0],
87 "It is not necessary to provide an 'efficiency' for 'M', "
88 "as it is always equal to 1, by definition. However, if it is "
89 "entered, then it must be: 'efficiency: {A: 1, b: 0, Ea: 0}'.");
90 }
91 }
92 if (colliders[0]["type"] == "pressure-dependent-Arrhenius") {
93 m_rateObj_M = PlogRate(colliders[0], rate_units);
95 } else if (colliders[0]["type"] == "falloff" && colliders[0].hasKey("Troe")) {
96 TroeRate troeRateObj = TroeRate(colliders[0], rate_units);
97 troeRateObj.setRateIndex(0);
98 m_rateObj_M = troeRateObj;
100 } else if (colliders[0]["type"] == "Chebyshev") {
101 m_rateObj_M = ChebyshevRate(colliders[0], rate_units);
103 } else {
104 throw InputFileError("LinearBurkeRate::setParameters", colliders[0],
105 "Collider 'M' must be specified in a pressure-dependent-Arrhenius (PLOG), "
106 "falloff (Troe form), or Chebyshev format.");
107 }
108 AnyMap params;
109 params["A"] = 1.0;
110 params["b"] = 0.0;
111 params["Ea"] = 0.0;
112 m_epsObj_M = ArrheniusRate(AnyValue(params), colliders[0].units(), eps_units);
113 string eig_eps_key, conflicting_key;
114 // If using eig0 for all colliders, then it is mandatory to specify an eig0 value
115 // for the reference collider
116 if (colliders[0].hasKey("eig0")) {
117 eig_eps_key = "eig0";
118 conflicting_key = "efficiency";
119 } else {
120 eig_eps_key = "efficiency";
121 conflicting_key = "eig0";
122 colliders[0][eig_eps_key] = params;
123 }
124 // Start at 1 because index 0 is for "M"
125 for (size_t i = 1; i < colliders.size(); i++) {
126 if (!colliders[i].hasKey("name")) {
127 throw InputFileError("LinearBurkeRate::setParameters", colliders[i],
128 "'name' key missing from collider entry");
129 }
130 auto nm = colliders[i]["name"].asString();
131 if (!colliders[i].hasKey(eig_eps_key)) {
132 throw InputFileError("LinearBurkeRate::setParameters", colliders[i],
133 "Collider '{}' lacks an '{}' key.", nm, eig_eps_key);
134 }
135 if (colliders[i].hasKey(conflicting_key)) {
136 throw InputFileError("LinearBurkeRate::setParameters", colliders[i],
137 "Collider '{}' cannot contain both 'efficiency' and 'eig0'. All "
138 "additional colliders must also make the same choice as that of 'M'.",
139 nm);
140 }
141 m_colliderNames.push_back(colliders[i]["name"].as<string>());
142
143 ArrheniusRate epsObj_i;
144 // eig0 and eps are ONLY interchangeable due to the requirement that eps_M have
145 // parameters {A: 1, b: 0, Ea: 0}
146 params["A"] = colliders[i][eig_eps_key]["A"].asDouble() /
147 colliders[0][eig_eps_key]["A"].asDouble();
148 params["b"] = colliders[i][eig_eps_key]["b"].asDouble() -
149 colliders[0][eig_eps_key]["b"].asDouble();
150 params["Ea"] = colliders[i][eig_eps_key]["Ea"].asDouble() -
151 colliders[0][eig_eps_key]["Ea"].asDouble();
152
153 if (params["A"].asDouble() < 0) {
154 throw InputFileError("LinearBurkeRate::setParameters", colliders[i],
155 "Invalid '{}' entry for collider '{}'.", eig_eps_key, nm);
156 }
157
158 epsObj_i = ArrheniusRate(AnyValue(params), colliders[i].units(), eps_units);
159 if (colliders[i].hasKey("type")) {
160 if (colliders[i]["type"] == "pressure-dependent-Arrhenius") {
161 m_rateObjs.push_back(PlogRate(colliders[i], rate_units));
162 m_dataObjs.push_back(PlogData());
163 m_epsObjs1.push_back(epsObj_i);
164 m_epsObjs2.push_back(epsObj_i);
165 } else if (colliders[i]["type"] == "falloff"
166 && colliders[i].hasKey("Troe"))
167 {
168 TroeRate troeRateObj = TroeRate(colliders[i], rate_units);
169 troeRateObj.setRateIndex(0);
170 m_rateObjs.push_back(troeRateObj);
171 m_dataObjs.push_back(FalloffData());
172 m_epsObjs1.push_back(epsObj_i);
173 m_epsObjs2.push_back(epsObj_i);
174 } else if (colliders[i]["type"] == "Chebyshev") {
175 m_rateObjs.push_back(ChebyshevRate(colliders[i], rate_units));
176 m_dataObjs.push_back(ChebyshevData());
177 m_epsObjs1.push_back(epsObj_i);
178 m_epsObjs2.push_back(epsObj_i);
179 } else {
180 throw InputFileError("LinearBurkeRate::setParameters", colliders[i],
181 "Collider '{}': '{}' rate parameterization is not supported. Must "
182 "be one of 'pressure-dependent-Arrhenius (PLOG), 'falloff' (Troe "
183 "form), or 'Chebyshev'.",
184 m_colliderNames[i-1], colliders[i]["type"].asString());
185 }
186 m_hasRateConstant.push_back(true);
187 } else {
188 // Collider has an 'efficiency' specified, but no other info is provided.
189 // Assign it the same rate and data objects as "M"
190 m_rateObjs.push_back(m_rateObj_M);
191 m_dataObjs.push_back(m_dataObj_M);
192 m_epsObjs1.push_back(epsObj_i);
193 m_epsObjs2.push_back(m_epsObj_M);
194 m_hasRateConstant.push_back(false);
195 }
196 }
197}
198
199void LinearBurkeRate::validate(const string& equation, const Kinetics& kin) {}
200
202{
203 m_colliderIndices.clear();
204 for (size_t i = 0; i<m_colliderNames.size(); i++) {
206 }
207}
208
210 DataTypes& dataObj, RateTypes& rateObj, double logPeff)
211{
212 PlogData& data = std::get<PlogData>(dataObj);
213 PlogRate& rate = std::get<PlogRate>(rateObj);
214 // Replace logP with log of the effective pressure with respect to eps
215 data.logP = logPeff;
216 data.logT = shared_data.logT;
217 data.recipT = shared_data.recipT;
218 rate.updateFromStruct(data);
219 return rate.evalFromStruct(data);
220}
221
223 DataTypes& dataObj, RateTypes& rateObj, double logPeff)
224{
225 FalloffData& data = get<FalloffData>(dataObj);
226 TroeRate& rate = get<TroeRate>(rateObj);
227 data.conc_3b = {exp(logPeff) / GasConstant / shared_data.temperature};
228 data.logT = shared_data.logT;
229 data.recipT = shared_data.recipT;
230 data.temperature = shared_data.temperature;
231 return rate.evalFromStruct(data);
232}
233
235 DataTypes& dataObj, RateTypes& rateObj, double logPeff)
236{
237 ChebyshevData& data = get<ChebyshevData>(dataObj);
238 ChebyshevRate& rate = get<ChebyshevRate>(rateObj);
239 data.log10P = log10(exp(logPeff));
240 data.logT = shared_data.logT;
241 data.recipT = shared_data.recipT;
242 rate.updateFromStruct(data);
243 return rate.evalFromStruct(data);
244}
245
246double LinearBurkeRate::evalFromStruct(const LinearBurkeData& shared_data)
247{
248 double sigmaX_M = 0.0;
249 // Test each species listed at the top of the YAML file
250 for (size_t i = 0; i < shared_data.moleFractions.size(); i++) {
251 // Total sum will be essentially 1, but perhaps not exactly due to Cantera's
252 // rounding conventions
253 sigmaX_M += shared_data.moleFractions[i];
254 }
255 double eps_mix = 0.0; // mole-fraction-weighted overall eps value of the mixtures
256 for (size_t j = 0; j < m_colliderIndices.size(); j++) {
257 size_t i = m_colliderIndices[j];
258 eps_mix += shared_data.moleFractions[i]
259 * m_epsObjs1[j].evalRate(shared_data.logT, shared_data.recipT);
260 sigmaX_M -= shared_data.moleFractions[i];
261 }
262 // Add all M colliders to eps_mix in a single step
263 eps_mix += sigmaX_M; // eps_mix += sigmaX_M * eps_M, but eps_M = 1 always
264 if (eps_mix == 0) {
265 throw InputFileError("LinearBurkeRate::evalFromStruct", m_input,
266 "eps_mix == 0 for some reason");
267 }
268 double k_LMR_ = 0.0;
269 double logPeff;
270 for (size_t j = 0; j < m_colliderIndices.size(); j++) {
271 size_t i = m_colliderIndices[j];
272 double eps1 = m_epsObjs1[j].evalRate(shared_data.logT, shared_data.recipT);
273 double eps2 = m_epsObjs2[j].evalRate(shared_data.logT, shared_data.recipT);
274 // eps2 equals either eps_M or eps_i, depending on the scenario
275 // effective pressure as a function of eps
276 logPeff = shared_data.logP + log(eps_mix) - log(eps2);
277 if (m_rateObjs[j].index() == 0) { // 0 means PlogRate
278 k_LMR_ += evalPlogRate(shared_data, m_dataObjs[j], m_rateObjs[j], logPeff)
279 * eps1 * shared_data.moleFractions[i] / eps_mix;
280 } else if (m_rateObjs[j].index() == 1) { // 1 means TroeRate
281 k_LMR_ += evalTroeRate(shared_data, m_dataObjs[j], m_rateObjs[j], logPeff)
282 * eps1 * shared_data.moleFractions[i] / eps_mix;
283 } else if (m_rateObjs[j].index() == 2) { // 2 means ChebyshevRate
284 k_LMR_ += evalChebyshevRate(shared_data, m_dataObjs[j], m_rateObjs[j], logPeff)
285 * eps1 * shared_data.moleFractions[i] / eps_mix;
286 } else {
287 throw InputFileError("LinearBurkeRate::evalFromStruct", m_input,
288 "Something went wrong...");
289 }
290 }
291 // We actually have
292 // logPeff = shared_data.logP + log(eps_mix) - log(eps_M)
293 // but log(eps_M)=0 always
294 logPeff = shared_data.logP + log(eps_mix);
295
296 // We actually have
297 // k_LMR_+=evalPlogRate(shared_data,m_dataObj_M,m_rateObj_M)*eps_M*sigmaX_M/eps_mix
298 // k_LMR_+=evalTroeRate(shared_data,m_dataObj_M,m_rateObj_M)*eps_M*sigmaX_M/eps_mix
299 // etc., but eps_M = 1 always
300 if (m_rateObj_M.index() == 0) { // 0 means PlogRate
301 k_LMR_ += evalPlogRate(shared_data, m_dataObj_M, m_rateObj_M, logPeff) *
302 sigmaX_M / eps_mix;
303 } else if (m_rateObj_M.index() == 1) { // 1 means TroeRate
304 k_LMR_ += evalTroeRate(shared_data, m_dataObj_M, m_rateObj_M, logPeff) *
305 sigmaX_M / eps_mix;
306 } else if (m_rateObj_M.index() == 2) { // 2 means ChebyshevRate
307 k_LMR_ += evalChebyshevRate(shared_data, m_dataObj_M, m_rateObj_M, logPeff) *
308 sigmaX_M / eps_mix;
309 }
310 return k_LMR_;
311}
312
314{
315 vector<AnyMap> topLevelList;
316 AnyMap M_node, M_params;
317 M_node["name"] = "M";
318 if (m_rateObj_M.index() == 0) {
319 auto& rate = get<PlogRate>(m_rateObj_M);
320 M_params = rate.parameters();
321 } else if (m_rateObj_M.index() == 1) {
322 auto& rate = get<TroeRate>(m_rateObj_M);
323 M_params = rate.parameters();
324 } else if (m_rateObj_M.index() == 2) {
325 auto& rate = get<ChebyshevRate>(m_rateObj_M);
326 M_params = rate.parameters();
327 }
328 M_node.update(M_params);
329 topLevelList.push_back(std::move(M_node));
330
331 for (size_t i = 0; i < m_colliderNames.size(); i++) {
332 AnyMap collider, efficiency, params;
333 collider["name"] = m_colliderNames[i];
334 m_epsObjs1[i].getRateParameters(efficiency);
335 collider["efficiency"] = std::move(efficiency);
336 if (m_hasRateConstant[i]) {
337 const auto& var_rate = m_rateObjs[i];
338 if (var_rate.index() == 0) {
339 auto& rate = get<PlogRate>(var_rate);
340 params = rate.parameters();
341 } else if (var_rate.index() == 1) {
342 auto& rate = get<TroeRate>(var_rate);
343 params = rate.parameters();
344 } else if (var_rate.index() == 2) {
345 auto& rate = get<ChebyshevRate>(var_rate);
346 params = rate.parameters();
347 }
348 collider.update(params);
349 }
350 topLevelList.push_back(std::move(collider));
351 }
352 rateNode["colliders"] = std::move(topLevelList);
353}
354
355}
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:87
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:157
Error thrown for problems processing information contained in an AnyMap or AnyValue.
Definition AnyMap.h:749
Public interface for kinetics managers.
Definition Kinetics.h:125
size_t kineticsSpeciesIndex(size_t k, size_t n) const
The location of species k of phase n in species arrays.
Definition Kinetics.h:276
size_t nTotalSpecies() const
The total number of species in all phases participating in the kinetics mechanism.
Definition Kinetics.h:254
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,...
double temperature() const
Temperature (K).
Definition Phase.h:562
void getMoleFractions(double *const x) const
Get the species mole fraction vector.
Definition Phase.cpp:434
int stateMFNumber() const
Return the State Mole Fraction Number.
Definition Phase.h:773
virtual double pressure() const
Return the thermodynamic pressure (Pa).
Definition Phase.h:580
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:304
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:120
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:54
Data container holding shared data specific to LinearBurkeRate.
void perturbPressure(double deltaP)
Perturb pressure of data container.
double logP
Logarithm of pressure.
void restore() override
Restore data container after a perturbation.
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