1 /**
2  * @file ReactionRate.h
3  *
4  * @warning This file is an experimental part of the %Cantera API and
5  *    may be changed or removed without notice.
6  */
7 
8 // This file is part of Cantera. See License.txt in the top-level directory or
9 // at https://cantera.org/license.txt for license and copyright information.
10 
11 #ifndef CT_REACTIONRATE_H
12 #define CT_REACTIONRATE_H
13 
14 #include "cantera/base/AnyMap.h"
15 #include "cantera/base/Units.h"
16 #include "cantera/kinetics/RxnRates.h"
17 #include "cantera/kinetics/ReactionData.h"
18 #include "cantera/base/ctexceptions.h"
19 
20 namespace Cantera
21 {
22 
23 class Func1;
24 class MultiRateBase;
25 
26 //! Abstract base class for reaction rate definitions
27 /**
28  * Because this class has no template parameters, derived objects can be
29  * accessed via `shared_ptr<ReactionRateBase>`. For performance reasons
30  * it is essential that derived classes use the keyword `final` to
31  * de-virtualize `virtual` methods.
32  *
33  * Methods defined for the abstract base class are not aware of specialized
34  * data handlers defined by the template class `ReactionRate<DataType>`
35  * and thus can be exposed to the API.
36  */
37 class ReactionRateBase
38 {
39 public:
ReactionRateBase()40     ReactionRateBase() : units(0.) {}
~ReactionRateBase()41     virtual ~ReactionRateBase() {}
42 
43 public:
44     //! Identifier of reaction type
45     virtual std::string type() const = 0;
46 
47     //! Create multi-rate evaluator
48     virtual unique_ptr<MultiRateBase> newMultiRate() const = 0;
49 
50     //! Update reaction rate data based on temperature
51     //! @param T  temperature [K]
52     virtual void update(double T) = 0;
53 
54     //! Update reaction rate data based on temperature and pressure
55     //! @param T  temperature [K]
56     //! @param P  pressure [Pa]
57     //! @param concm  third-body concentration (if applicable)
58     virtual void update(double T, double P, double concm=0.) = 0;
59 
60     //! Update reaction rate data based on bulk phase
61     //! @param bulk  object representing bulk phase
62     //! @param concm  third-body concentration (if applicable)
63     virtual void update(const ThermoPhase& bulk, double concm=0.) = 0;
64 
65     //! Evaluate reaction rate based on temperature
66     //! @param T  temperature [K]
67     virtual double eval(double T) const = 0;
68 
69     //! Evaluate reaction rate based on temperature and pressure
70     //! @param T  temperature [K]
71     //! @param P  pressure [Pa]
72     //! @param concm  third-body concentration (if applicable)
73     virtual double eval(double T, double P, double concm=0.) const = 0;
74 
75     //! Evaluate reaction rate based on bulk phase
76     //! @param bulk  object representing bulk phase
77     //! @param concm  third-body concentration (if applicable)
78     virtual double eval(const ThermoPhase& bulk, double concm=0.) const = 0;
79 
80     //! Evaluate reaction rate derivative based on temperature
81     //! @param T  temperature [K]
82     virtual double ddT(double T) const = 0;
83 
84     //! Evaluate reaction rate derivative based on temperature and pressure
85     //! @param T  temperature [K]
86     //! @param P  pressure [Pa]
87     virtual double ddT(double T, double P) const = 0;
88 
89     //! Evaluate reaction rate derivative based on bulk phase
90     //! @param bulk  object representing bulk phase
91     //! @param concm  third-body concentration (if applicable)
92     virtual double ddT(const ThermoPhase& bulk, double concm=0.) const = 0;
93 
94     //! Validate the reaction rate expression
95     virtual void validate(const std::string& equation) = 0;
96 
97     //! Return the parameters such that an identical Reaction could be reconstructed
98     //! using the newReaction() function. Behavior specific to derived classes is
99     //! handled by the getParameters() method.
100     //! @param rate_units  units used for rate parameters
101     AnyMap parameters(const Units& rate_units) const;
102 
103     //! Return parameters using original unit system
104     AnyMap parameters() const;
105 
106     //! Set parameters
107     //! @param node  AnyMap object containing reaction rate specification
108     //! @param rate_units  Description of units used for rate parameters
109     virtual void setParameters(const AnyMap& node, const Units& rate_units);
110 
111     //! Set rate units
112     //! @param rate_units  Description of units used for rate parameters
113     virtual void setUnits(const Units& rate_units);
114 
115 protected:
116     //! Get parameters
117     //! Store the parameters of a ReactionRate needed to reconstruct an identical
118     //! object. Does not include user-defined fields available in the #input map.
getParameters(AnyMap & rateNode,const Units & rate_units)119     virtual void getParameters(AnyMap& rateNode, const Units& rate_units) const {
120         throw CanteraError("ReactionRate::getParameters",
121                            "Not implemented by derived ReactionRate object.");
122     }
123 
124     //! Input data used for specific models
125     AnyMap input;
126 
127     //! The units of the rate constant. These are determined by the units of the
128     //! standard concentration of the reactant species' phases of the phase
129     //! where the reaction occurs.
130     Units units;
131 };
132 
133 
134 //! Class template for reaction rate definitions with specialized DataType
135 /**
136  * This class template ensures that derived objects are aware of specialized
137  * data types, which are passed by MultiRateBase evaluators.
138  */
139 template <class DataType>
140 class ReactionRate : public ReactionRateBase
141 {
142 public:
143     ReactionRate() = default;
144 
145     //! Update information specific to reaction
146     //! @param shared_data  data shared by all reactions of a given type
147     virtual void update(const DataType& shared_data,
148                         double concm=0.) {}
149 
update(double T)150     virtual void update(double T) override {
151         DataType data;
152         data.update(T);
153         update(data);
154     }
155 
156     virtual void update(double T, double P, double concm=0.) override {
157         DataType data;
158         data.update(T, P);
159         update(data, concm);
160     }
161 
162     virtual void update(const ThermoPhase& bulk, double concm=0.) override {
163         DataType data;
164         data.update(bulk);
165         update(data);
166     }
167 
168     //! Evaluate reaction rate
169     //! @param shared_data  data shared by all reactions of a given type
170     //! @param concm  third-body concentration (if applicable)
171     virtual double eval(const DataType& shared_data, double concm=0.) const = 0;
172 
eval(double T)173     virtual double eval(double T) const override {
174         DataType data;
175         data.update(T);
176         return eval(data);
177     }
178 
179     virtual double eval(double T, double P, double concm=0.) const override {
180         DataType data;
181         data.update(T, P);
182         return eval(data, concm);
183     }
184 
185     virtual double eval(const ThermoPhase& bulk, double concm=0.) const override {
186         DataType data;
187         data.update(bulk);
188         return eval(data, concm);
189     }
190 
191     //! Evaluate derivative of reaction rate with respect to temperature
192     //! @param shared_data  data shared by all reactions of a given type
193     virtual double ddT(const DataType& shared_data, double concm=0.) const {
194         throw CanteraError("ReactionRate::ddT",
195                            "Not implemented by derived ReactionRate object.");
196     }
197 
ddT(double T)198     virtual double ddT(double T) const override {
199         DataType data;
200         data.update(T);
201         return ddT(data);
202     }
203 
ddT(double T,double P)204     virtual double ddT(double T, double P) const override {
205         DataType data;
206         data.update(T, P);
207         return ddT(data);
208     }
209 
210     virtual double ddT(const ThermoPhase& bulk, double concm=0.) const override {
211         DataType data;
212         data.update(bulk);
213         return ddT(data, concm);
214     }
215 };
216 
217 
218 //! The ArrheniusRate reaction rate type depends only on temperature
219 /**
220  *  A reaction rate coefficient of the following form.
221  *
222  *   \f[
223  *        k_f =  A T^b \exp (-E/RT)
224  *   \f]
225  *
226  * Note: ArrheniusRate acts as a wrapper for the Arrhenius class.
227  */
228 class ArrheniusRate final : public ReactionRate<ArrheniusData>, public Arrhenius
229 {
230 public:
231     //! Default constructor.
232     ArrheniusRate();
233 
234     //! Constructor.
235     //! @param A  pre-exponential. The unit system is
236     //!     (kmol, m, s). The actual units depend on the reaction
237     //!     order and the dimensionality (surface or bulk).
238     //! @param b  Temperature exponent. Non-dimensional.
239     //! @param E  Activation energy. J/kmol.
240     ArrheniusRate(double A, double b, double E);
241 
242     //! Constructor using AnyMap content
243     //! @param node  AnyMap containing rate information
244     //! @param rate_units  unit definitions used for rate information
245     ArrheniusRate(const AnyMap& node, const Units& rate_units);
246 
247     //! Constructor using AnyMap content
248     //! @param node  AnyMap containing rate information
249     ArrheniusRate(const AnyMap& node);
250 
251     //! Constructor based on Arrhenius object
252     //! @param arr  Arrhenius object
253     //! @param allow_negative_A  allow negative pre-exponential factor
254     //!      (optional, default is false)
255     ArrheniusRate(const Arrhenius& arr, bool allow_negative_A=false);
256 
257     virtual void setParameters(const AnyMap& node, const Units& rate_units) override;
258     virtual void getParameters(AnyMap& rateNode,
259                                const Units& rate_units) const override;
260 
type()261     virtual std::string type() const override { return "Arrhenius"; }
262 
263     virtual unique_ptr<MultiRateBase> newMultiRate() const override;
264 
265     //! Update information specific to reaction
usesUpdate()266     static bool usesUpdate() { return false; }
267 
268     virtual double eval(const ArrheniusData& shared_data,
269                         double concm=0.) const override {
270         return updateRC(shared_data.m_logT, shared_data.m_recipT);
271     }
272 
273     virtual double ddT(const ArrheniusData& shared_data,
274                        double concm=0.) const override {
275         return updateRC(shared_data.m_logT, shared_data.m_recipT) *
276             (m_b + m_E * shared_data.m_recipT) * shared_data.m_recipT;
277     }
278 
279     //! Return the activation energy [J/kmol]
activationEnergy()280     double activationEnergy() const {
281         return m_E * GasConstant;
282     }
283 
284     virtual void validate(const std::string& equation) override;
285 
286     bool allow_negative_pre_exponential_factor;
287 };
288 
289 
290 //! Pressure-dependent reaction rate expressed by logarithmically interpolating
291 //! between Arrhenius rate expressions at various pressures.
292 /*!
293  * Given two rate expressions at two specific pressures:
294  *
295  *   * \f$ P_1: k_1(T) = A_1 T^{b_1} e^{-E_1 / RT} \f$
296  *   * \f$ P_2: k_2(T) = A_2 T^{b_2} e^{-E_2 / RT} \f$
297  *
298  * The rate at an intermediate pressure \f$ P_1 < P < P_2 \f$ is computed as
299  * \f[
300  *  \log k(T,P) = \log k_1(T) + \bigl(\log k_2(T) - \log k_1(T)\bigr)
301  *      \frac{\log P - \log P_1}{\log P_2 - \log P_1}
302  * \f]
303  * Multiple rate expressions may be given at the same pressure, in which case
304  * the rate used in the interpolation formula is the sum of all the rates given
305  * at that pressure. For pressures outside the given range, the rate expression
306  * at the nearest pressure is used.
307  */
308 class PlogRate final : public ReactionRate<PlogData>, public Plog
309 {
310 public:
PlogRate()311     PlogRate() {}
312 
313     //! Constructor from Arrhenius rate expressions at a set of pressures
314     explicit PlogRate(const std::multimap<double, Arrhenius>& rates);
315 
316     //! Constructor using AnyMap content
317     //! @param node  AnyMap containing rate information
318     //! @param rate_units  unit definitions used for rate information
319     PlogRate(const AnyMap& node, const Units& rate_units);
320 
321     //! Constructor using AnyMap content
322     //! @param node  AnyMap containing rate information
323     PlogRate(const AnyMap& node);
324 
type()325     virtual std::string type() const override
326     {
327         return "pressure-dependent-Arrhenius";
328     }
329 
330     virtual unique_ptr<MultiRateBase> newMultiRate() const override;
331 
332     virtual void setParameters(const AnyMap& node, const Units& rate_units) override;
333     virtual void getParameters(AnyMap& rateNode,
334                                const Units& rate_units) const override;
335 
336     //! Update information specific to reaction
usesUpdate()337     static bool usesUpdate() { return true; }
338 
339     virtual void update(const PlogData& shared_data, double concm=0.) override {
340         update_C(&shared_data.m_logP);
341     }
342 
343     virtual double eval(const PlogData& shared_data,
344                         double concm=0.) const override {
345         return updateRC(shared_data.m_logT, shared_data.m_recipT);
346     }
347 
validate(const std::string & equation)348     virtual void validate(const std::string& equation) override {
349         Plog::validate(equation);
350     }
351 };
352 
353 
354 //! Pressure-dependent rate expression where the rate coefficient is expressed
355 //! as a bivariate Chebyshev polynomial in temperature and pressure.
356 /*!
357  * The rate constant can be written as:
358  * \f[
359  *     \log k(T,P) = \sum_{t=1}^{N_T} \sum_{p=1}^{N_P} \alpha_{tp}
360  *                       \phi_t(\tilde{T}) \phi_p(\tilde{P})
361  * \f]
362  * where \f$\alpha_{tp}\f$ are the constants defining the rate, \f$\phi_n(x)\f$
363  * is the Chebyshev polynomial of the first kind of degree *n* evaluated at
364  * *x*, and
365  * \f[
366  *  \tilde{T} \equiv \frac{2T^{-1} - T_\mathrm{min}^{-1} - T_\mathrm{max}^{-1}}
367  *                        {T_\mathrm{max}^{-1} - T_\mathrm{min}^{-1}}
368  * \f]
369  * \f[
370  *  \tilde{P} \equiv \frac{2 \log P - \log P_\mathrm{min} - \log P_\mathrm{max}}
371  *                        {\log P_\mathrm{max} - \log P_\mathrm{min}}
372  * \f]
373  * are reduced temperature and reduced pressures which map the ranges
374  * \f$ (T_\mathrm{min}, T_\mathrm{max}) \f$ and
375  * \f$ (P_\mathrm{min}, P_\mathrm{max}) \f$ to (-1, 1).
376  *
377  * A Chebyshev rate expression is specified in terms of the coefficient matrix
378  * \f$ \alpha \f$ and the temperature and pressure ranges. Note that the
379  * Chebyshev polynomials are not defined outside the interval (-1,1), and
380  * therefore extrapolation of rates outside the range of temperatures and
381  * pressures for which they are defined is strongly discouraged.
382  *
383  * @TODO  rename to ChebyshevRate when the legacy ChebyshevRate class is removed
384  *      from RxnRates.h after Cantera 2.6.
385  */
386 class ChebyshevRate3 final : public ReactionRate<ChebyshevData>, public Chebyshev
387 {
388 public:
389     //! Default constructor.
ChebyshevRate3()390     ChebyshevRate3() {}
391 
392     //! Constructor using coefficient array
393     /*
394      *  @param Tmin    Minimum temperature [K]
395      *  @param Tmax    Maximum temperature [K]
396      *  @param Pmin    Minimum pressure [Pa]
397      *  @param Pmax    Maximum pressure [Pa]
398      *  @param coeffs  Coefficient array dimensioned `nT` by `nP` where `nT` and
399      *      `nP` are the number of temperatures and pressures used in the fit,
400      *      respectively.
401      */
402     ChebyshevRate3(double Tmin, double Tmax, double Pmin, double Pmax,
403                    const Array2D& coeffs);
404 
405     //! Constructor using AnyMap content
406     //! @param node  AnyMap containing rate information
407     //! @param rate_units  unit definitions used for rate information
408     ChebyshevRate3(const AnyMap& node, const Units& rate_units);
409 
410     //! Constructor using AnyMap content
411     //! @param node  AnyMap containing rate information
412     ChebyshevRate3(const AnyMap& node);
413 
type()414     virtual std::string type() const override { return "Chebyshev"; }
415 
416     virtual unique_ptr<MultiRateBase> newMultiRate() const override;
417 
418     virtual void setParameters(const AnyMap& node, const Units& rate_units) override;
419     virtual void getParameters(AnyMap& rateNode,
420                                const Units& rate_units) const override;
421 
422     //! Update information specific to reaction
usesUpdate()423     static bool usesUpdate() { return true; }
424 
425     virtual void update(const ChebyshevData& shared_data, double concm=0.) override {
426         update_C(&shared_data.m_log10P);
427     }
428 
429     virtual double eval(const ChebyshevData& shared_data,
430                         double concm=0.) const override {
431         return updateRC(0., shared_data.m_recipT);
432     }
433 
434     virtual void validate(const std::string& equation) override;
435 };
436 
437 
438 //! Custom reaction rate depending only on temperature
439 /**
440  * The rate expression is provided by a `Func1` object taking a single
441  * argument (temperature) and does not use a formalized parameterization.
442  *
443  * @warning This class is an experimental part of the %Cantera API and
444  *    may be changed or removed without notice.
445  */
446 class CustomFunc1Rate final : public ReactionRate<CustomFunc1Data>
447 {
448 public:
449     CustomFunc1Rate();
450 
451     //! Constructor does nothing, as there is no formalized parameterization
452     //! @param node  AnyMap object containing reaction rate specification
453     //! @param rate_units  Description of units used for rate parameters
CustomFunc1Rate(const AnyMap & rate,const Units & rate_units)454     CustomFunc1Rate(const AnyMap& rate, const Units& rate_units) {}
455 
type()456     virtual std::string type() const override { return "custom-rate-function"; }
457 
458     virtual unique_ptr<MultiRateBase> newMultiRate() const override;
459 
setParameters(const AnyMap & node,const Units & rate_units)460     virtual void setParameters(const AnyMap& node, const Units& rate_units) override {
461         units = rate_units;
462     }
463 
464     //! Update information specific to reaction
usesUpdate()465     static bool usesUpdate() { return false; }
466 
467     //! Set custom rate
468     /**
469      * The call to the Func1 object takes a single argument (temperature) and
470      * does not depend on parameters handled in C++.
471      */
472     void setRateFunction(shared_ptr<Func1> f);
473 
474     virtual double eval(const CustomFunc1Data& shared_data,
475                         double concm=0.) const override;
476 
validate(const std::string & equation)477     virtual void validate(const std::string& equation) override {}
478 
479 protected:
480     shared_ptr<Func1> m_ratefunc;
481 };
482 
483 }
484 
485 #endif
486