Cantera 2.6.0
Falloff.cpp
Go to the documentation of this file.
1/**
2 * @file Falloff.cpp Definitions for member functions of classes derived from
3 * Falloff
4 */
5
6// This file is part of Cantera. See License.txt in the top-level directory or
7// at https://cantera.org/license.txt for license and copyright information.
8
11#include "cantera/base/global.h"
12#include "cantera/base/AnyMap.h"
13#include "cantera/kinetics/Falloff.h"
16
17namespace Cantera
18{
19
20FalloffData::FalloffData()
21 : ready(false)
22 , molar_density(NAN)
23 , m_state_mf_number(-1)
24 , m_perturbed(false)
25{
26 conc_3b.resize(1, NAN);
27 m_conc_3b_buf.resize(1, NAN);
28}
29
30void FalloffData::update(double T)
31{
32 throw CanteraError("FalloffData::update",
33 "Missing state information: 'FalloffData' requires third-body concentration.");
34}
35
36void FalloffData::update(double T, double M)
37{
38 ReactionData::update(T);
39 conc_3b[0] = M;
40}
41
42bool FalloffData::update(const ThermoPhase& phase, const Kinetics& kin)
43{
44 double rho_m = phase.molarDensity();
45 int mf = phase.stateMFNumber();
46 double T = phase.temperature();
47 bool changed = false;
48 if (T != temperature) {
49 ReactionData::update(T);
50 changed = true;
51 }
52 if (rho_m != molar_density || mf != m_state_mf_number) {
53 molar_density = rho_m;
54 m_state_mf_number = mf;
55 conc_3b = kin.thirdBodyConcentrations();
56 changed = true;
57 }
58 return changed;
59}
60
61void FalloffData::perturbThirdBodies(double deltaM)
62{
63 if (m_perturbed) {
64 throw CanteraError("FalloffData::perturbThirdBodies",
65 "Cannot apply another perturbation as state is already perturbed.");
66 }
67 m_conc_3b_buf = conc_3b;
68 for (auto& c3b : conc_3b) {
69 c3b *= 1. + deltaM;
70 }
71 m_perturbed = true;
72}
73
74void FalloffData::restore()
75{
76 ReactionData::restore();
77 // only restore if there is a valid buffered value
78 if (!m_perturbed) {
79 return;
80 }
81 conc_3b = m_conc_3b_buf;
82 m_perturbed = false;
83}
84
85void FalloffRate::init(const vector_fp& c)
86{
87 setFalloffCoeffs(c);
88}
89
90void FalloffRate::setLowRate(const ArrheniusRate& low)
91{
92 ArrheniusRate _low = low;
93 _low.setAllowNegativePreExponentialFactor(m_negativeA_ok);
94 _low.check("", AnyMap());
95 if (_low.preExponentialFactor() * m_highRate.preExponentialFactor() < 0.) {
96 throw CanteraError("FalloffRate::setLowRate",
97 "Detected inconsistent rate definitions;\nhigh and low "
98 "rate pre-exponential factors must have the same sign.");
99 }
100 m_lowRate = std::move(_low);
101}
102
103void FalloffRate::setHighRate(const ArrheniusRate& high)
104{
105 ArrheniusRate _high = high;
106 _high.setAllowNegativePreExponentialFactor(m_negativeA_ok);
107 _high.check("", AnyMap());
108 if (m_lowRate.preExponentialFactor() * _high.preExponentialFactor() < 0.) {
109 throw CanteraError("FalloffRate::setHighRate",
110 "Detected inconsistent rate definitions;\nhigh and low "
111 "rate pre-exponential factors must have the same sign.");
112 }
113 m_highRate = std::move(_high);
114}
115
116void FalloffRate::setFalloffCoeffs(const vector_fp& c)
117{
118 if (c.size() != 0) {
119 throw CanteraError("FalloffRate::setFalloffCoeffs",
120 "Incorrect number of parameters. 0 required. Received {}.",
121 c.size());
122 }
123}
124
125void FalloffRate::getFalloffCoeffs(vector_fp& c) const
126{
127 c.clear();
128}
129
130void FalloffRate::setParameters(const AnyMap& node, const UnitStack& rate_units)
131{
132 if (node.empty()) {
133 return;
134 }
135
136 m_negativeA_ok = node.getBool("negative-A", false);
137 if (node["type"] == "chemically-activated") {
138 m_chemicallyActivated = true;
139 }
140
141 UnitStack low_rate_units = rate_units;
142 UnitStack high_rate_units = rate_units;
143 if (rate_units.size()) {
144 if (m_chemicallyActivated) {
145 low_rate_units.join(1);
146 high_rate_units.join(2);
147 } else {
148 high_rate_units.join(1);
149 }
150 }
151 if (node.hasKey("low-P-rate-constant")) {
152 m_lowRate = ArrheniusRate(
153 node["low-P-rate-constant"], node.units(), low_rate_units);
154 m_lowRate.setAllowNegativePreExponentialFactor(m_negativeA_ok);
155 }
156 if (node.hasKey("high-P-rate-constant")) {
157 m_highRate = ArrheniusRate(
158 node["high-P-rate-constant"], node.units(), high_rate_units);
159 m_highRate.setAllowNegativePreExponentialFactor(m_negativeA_ok);
160 }
161}
162
163void FalloffRate::getParameters(AnyMap& node) const
164{
165 if (m_chemicallyActivated) {
166 node["type"] = "chemically-activated";
167 } else {
168 node["type"] = "falloff";
169 }
170 if (m_negativeA_ok) {
171 node["negative-A"] = true;
172 }
173 AnyMap rNode;
174 m_lowRate.getRateParameters(rNode);
175 if (!rNode.empty()) {
176 node["low-P-rate-constant"] = std::move(rNode);
177 }
178 rNode.clear();
179 m_highRate.getRateParameters(rNode);
180 if (!rNode.empty()) {
181 node["high-P-rate-constant"] = std::move(rNode);
182 }
183}
184
185void FalloffRate::check(const std::string& equation, const AnyMap& node)
186{
187 m_lowRate.check(equation, node);
188 m_highRate.check(equation, node);
189
190 double lowA = m_lowRate.preExponentialFactor();
191 double highA = m_highRate.preExponentialFactor();
192 if (std::isnan(lowA) || std::isnan(highA)) {
193 // arrhenius rates are not initialized
194 return;
195 }
196 if (lowA * highA < 0) {
197 throw InputFileError("FalloffRate::check", node,
198 "Inconsistent rate definitions found in reaction '{}';\nhigh and low "
199 "rate pre-exponential factors must have the same sign.", equation);
200 }
201}
202
203void FalloffRate::validate(const std::string& equation, const Kinetics& kin)
204{
205 m_lowRate.validate(equation, kin);
206 m_highRate.validate(equation, kin);
207}
208
209void TroeRate::setFalloffCoeffs(const vector_fp& c)
210{
211 if (c.size() != 3 && c.size() != 4) {
212 throw CanteraError("TroeRate::setFalloffCoeffs",
213 "Incorrect number of coefficients. 3 or 4 required. Received {}.",
214 c.size());
215 }
216 m_a = c[0];
217 if (std::abs(c[1]) < SmallNumber) {
218 m_rt3 = std::numeric_limits<double>::infinity();
219 } else {
220 m_rt3 = 1.0 / c[1];
221 }
222
223 if (std::abs(c[2]) < SmallNumber) {
224 m_rt1 = std::numeric_limits<double>::infinity();
225 } else {
226 m_rt1 = 1.0 / c[2];
227 }
228
229 if (c.size() == 4) {
230 if (std::abs(c[3]) < SmallNumber) {
231 warn_user("TroeRate::setFalloffCoeffs",
232 "Unexpected parameter value T2=0. Omitting exp(T2/T) term from "
233 "falloff expression. To suppress this warning, remove value "
234 "for T2 from the input file. In the unlikely case that the "
235 "exp(T2/T) term should be included with T2 effectively equal "
236 "to 0, set T2 to a sufficiently small value "
237 "(for example, T2 < 1e-16).");
238 }
239 m_t2 = c[3];
240 } else {
241 m_t2 = 0.;
242 }
243}
244
245void TroeRate::getFalloffCoeffs(vector_fp& c) const
246{
247 c.resize(4, 0.);
248 getParameters(c.data());
249 if (std::abs(c[3]) < SmallNumber) {
250 c.resize(3);
251 }
252}
253
254void TroeRate::updateTemp(double T, double* work) const
255{
256 double Fcent = (1.0 - m_a) * exp(-T*m_rt3) + m_a * exp(-T*m_rt1);
257 if (m_t2) {
258 Fcent += exp(- m_t2 / T);
259 }
260 *work = log10(std::max(Fcent, SmallNumber));
261}
262
263double TroeRate::F(double pr, const double* work) const
264{
265 double lpr = log10(std::max(pr,SmallNumber));
266 double cc = -0.4 - 0.67 * (*work);
267 double nn = 0.75 - 1.27 * (*work);
268 double f1 = (lpr + cc)/ (nn - 0.14 * (lpr + cc));
269 double lgf = (*work) / (1.0 + f1 * f1);
270 return pow(10.0, lgf);
271}
272
273void TroeRate::setParameters(const AnyMap& node, const UnitStack& rate_units)
274{
275 if (node.empty()) {
276 return;
277 }
278
279 FalloffRate::setParameters(node, rate_units);
280 auto& f = node["Troe"].as<AnyMap>();
281 if (f.empty()) {
282 return;
283 }
284 vector_fp params{
285 f["A"].asDouble(),
286 f["T3"].asDouble(),
287 f["T1"].asDouble()
288 };
289 if (f.hasKey("T2")) {
290 params.push_back(f["T2"].asDouble());
291 }
292 setFalloffCoeffs(params);
293}
294
295void TroeRate::getParameters(double* params) const {
296 params[0] = m_a;
297 params[1] = 1.0/m_rt3;
298 params[2] = 1.0/m_rt1;
299 params[3] = m_t2;
300}
301
302void TroeRate::getParameters(AnyMap& node) const
303{
304 FalloffRate::getParameters(node);
305
306 AnyMap params;
307 if (std::isnan(m_a)) {
308 // pass
309 } else if (m_lowRate.rateUnits().factor() != 0.0) {
310 params["A"] = m_a;
311 params["T3"].setQuantity(1.0 / m_rt3, "K");
312 params["T1"].setQuantity(1.0 / m_rt1, "K");
313 if (std::abs(m_t2) > SmallNumber) {
314 params["T2"].setQuantity(m_t2, "K");
315 }
316 } else {
317 params["A"] = m_a;
318 params["T3"] = 1.0 / m_rt3;
319 params["T1"] = 1.0 / m_rt1;
320 if (std::abs(m_t2) > SmallNumber) {
321 params["T2"] = m_t2;
322 }
323 }
324 params.setFlowStyle();
325 node["Troe"] = std::move(params);
326}
327
328void SriRate::setFalloffCoeffs(const vector_fp& c)
329{
330 if (c.size() != 3 && c.size() != 5) {
331 throw CanteraError("SriRate::setFalloffCoeffs",
332 "Incorrect number of coefficients. 3 or 5 required. Received {}.",
333 c.size());
334 }
335
336 if (c[2] < 0.0) {
337 throw CanteraError("SriRate::setFalloffCoeffs()",
338 "m_c parameter is less than zero: {}", c[2]);
339 }
340 m_a = c[0];
341 m_b = c[1];
342 m_c = c[2];
343
344 if (c.size() == 5) {
345 if (c[3] < 0.0) {
346 throw CanteraError("SriRate::setFalloffCoeffs()",
347 "m_d parameter is less than zero: {}", c[3]);
348 }
349 m_d = c[3];
350 m_e = c[4];
351 } else {
352 m_d = 1.0;
353 m_e = 0.0;
354 }
355}
356
357void SriRate::getFalloffCoeffs(vector_fp& c) const
358{
359 c.resize(5, 0.);
360 getParameters(c.data());
361 if (m_e < SmallNumber && std::abs(m_e - 1.) < SmallNumber) {
362 c.resize(3);
363 }
364}
365
366void SriRate::updateTemp(double T, double* work) const
367{
368 *work = m_a * exp(- m_b / T);
369 if (m_c != 0.0) {
370 *work += exp(- T/m_c);
371 }
372 work[1] = m_d * pow(T,m_e);
373}
374
375double SriRate::F(double pr, const double* work) const
376{
377 double lpr = log10(std::max(pr,SmallNumber));
378 double xx = 1.0/(1.0 + lpr*lpr);
379 return pow(*work, xx) * work[1];
380}
381
382void SriRate::setParameters(const AnyMap& node, const UnitStack& rate_units)
383{
384 if (node.empty()) {
385 return;
386 }
387
388 FalloffRate::setParameters(node, rate_units);
389 auto& f = node["SRI"].as<AnyMap>();
390 if (f.empty()) {
391 return;
392 }
393 vector_fp params{
394 f["A"].asDouble(),
395 f["B"].asDouble(),
396 f["C"].asDouble()
397 };
398 if (f.hasKey("D")) {
399 params.push_back(f["D"].asDouble());
400 }
401 if (f.hasKey("E")) {
402 params.push_back(f["E"].asDouble());
403 }
404 setFalloffCoeffs(params);
405}
406
407void SriRate::getParameters(double* params) const
408{
409 params[0] = m_a;
410 params[1] = m_b;
411 params[2] = m_c;
412 params[3] = m_d;
413 params[4] = m_e;
414}
415
416void SriRate::getParameters(AnyMap& node) const
417{
418 FalloffRate::getParameters(node);
419
420 AnyMap params;
421 if (std::isnan(m_a)) {
422 // pass
423 } else if (m_lowRate.rateUnits().factor() != 0.0) {
424 params["A"] = m_a;
425 params["B"].setQuantity(m_b, "K");
426 params["C"].setQuantity(m_c, "K");
427 if (m_d != 1.0 || m_e != 0.0) {
428 params["D"] = m_d;
429 params["E"] = m_e;
430 }
431 } else {
432 params["A"] = m_a;
433 params["B"] = m_b;
434 params["C"] = m_c;
435 if (m_d != 1.0 || m_e != 0.0) {
436 params["D"] = m_d;
437 params["E"] = m_e;
438 }
439 }
440 params.setFlowStyle();
441 node["SRI"] = std::move(params);
442}
443
444void TsangRate::setFalloffCoeffs(const vector_fp& c)
445{
446 if (c.size() != 1 && c.size() != 2) {
447 throw CanteraError("TsangRate::init",
448 "Incorrect number of coefficients. 1 or 2 required. Received {}.",
449 c.size());
450 }
451 m_a = c[0];
452
453 if (c.size() == 2) {
454 m_b = c[1];
455 }
456 else {
457 m_b = 0.0;
458 }
459}
460
461void TsangRate::getFalloffCoeffs(vector_fp& c) const
462{
463 c.resize(2, 0.);
464 getParameters(c.data());
465 if (m_b < SmallNumber) {
466 c.resize(1);
467 }
468}
469
470void TsangRate::updateTemp(double T, double* work) const
471{
472 double Fcent = m_a + (m_b * T);
473 *work = log10(std::max(Fcent, SmallNumber));
474}
475
476double TsangRate::F(double pr, const double* work) const
477{ //identical to TroeRate::F
478 double lpr = log10(std::max(pr,SmallNumber));
479 double cc = -0.4 - 0.67 * (*work);
480 double nn = 0.75 - 1.27 * (*work);
481 double f1 = (lpr + cc)/ (nn - 0.14 * (lpr + cc));
482 double lgf = (*work) / (1.0 + f1 * f1);
483 return pow(10.0, lgf);
484}
485
486void TsangRate::setParameters(const AnyMap& node, const UnitStack& rate_units)
487{
488 if (node.empty()) {
489 return;
490 }
491
492 FalloffRate::setParameters(node, rate_units);
493 auto& f = node["Tsang"].as<AnyMap>();
494 if (f.empty()) {
495 return;
496 }
497 vector_fp params{
498 f["A"].asDouble(),
499 f["B"].asDouble()
500 };
501 setFalloffCoeffs(params);
502}
503
504void TsangRate::getParameters(double* params) const {
505 params[0] = m_a;
506 params[1] = m_b;
507}
508
509void TsangRate::getParameters(AnyMap& node) const
510{
511 FalloffRate::getParameters(node);
512
513 AnyMap params;
514 if (std::isnan(m_a)) {
515 // pass
516 } else {
517 // Parameters do not have unit system (yet)
518 params["A"] = m_a;
519 params["B"] = m_b;
520 }
521 params.setFlowStyle();
522 node["Tsang"] = std::move(params);
523}
524
525}
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:399
const UnitSystem & units() const
Return the default units that should be used to convert stored values.
Definition: AnyMap.h:598
bool empty() const
Return boolean indicating whether AnyMap is empty.
Definition: AnyMap.cpp:1401
bool getBool(const std::string &key, bool default_) const
If key exists, return it as a bool, otherwise return default_.
Definition: AnyMap.cpp:1487
void setFlowStyle(bool flow=true)
Use "flow" style when outputting this AnyMap to YAML.
Definition: AnyMap.cpp:1698
void clear()
Erase all items in the mapping.
Definition: AnyMap.cpp:1416
bool hasKey(const std::string &key) const
Returns true if the map contains an item named key.
Definition: AnyMap.cpp:1406
void setAllowNegativePreExponentialFactor(bool value)
Set flag indicating whether negative A values are permitted.
Definition: Arrhenius.h:158
virtual void check(const std::string &equation, const AnyMap &node) override
Check rate expression.
Definition: Arrhenius.cpp:139
virtual double preExponentialFactor() const
Return the pre-exponential factor A (in m, kmol, s to powers depending on the reaction order)
Definition: Arrhenius.h:108
Arrhenius reaction rate type depends only on temperature.
Definition: Arrhenius.h:192
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:61
Error thrown for problems processing information contained in an AnyMap or AnyValue.
Definition: AnyMap.h:702
Public interface for kinetics managers.
Definition: Kinetics.h:114
virtual const vector_fp & thirdBodyConcentrations() const
Provide direct access to current third-body concentration values.
Definition: Kinetics.h:532
double molarDensity() const
Molar density (kmol/m^3).
Definition: Phase.cpp:671
int stateMFNumber() const
Return the State Mole Fraction Number.
Definition: Phase.h:858
doublereal temperature() const
Temperature (K).
Definition: Phase.h:654
Base class for a phase with thermodynamic properties.
Definition: ThermoPhase.h:102
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...
This file contains definitions for utility functions and text for modules, inputfiles,...
Namespace for the Cantera kernel.
Definition: AnyMap.h:29
const double SmallNumber
smallest number to compare to zero.
Definition: ct_defs.h:153
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
Definition: ct_defs.h:184
void warn_user(const std::string &method, const std::string &msg, const Args &... args)
Print a user warning raised from method as CanteraWarning.
Definition: global.h:245
Contains declarations for string manipulation functions within Cantera.
Unit aggregation utility.
Definition: Units.h:99
size_t size() const
Size of UnitStack.
Definition: Units.h:110
void join(double exponent)
Join (update) exponent of standard units, where the updated exponent is the sum of the pre-existing e...
Definition: Units.cpp:363