From a83c4ca490425e9dadf7fc3a6e3ee0e4a263d706 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Thu, 19 Aug 2021 21:01:10 -0500 Subject: [PATCH 01/28] [SCons] Update docstring 'scons help' reports setting values in terms of 'yes' and 'no' rather than boolean flags that are otherwise used internally. This commit ensures that documentation for the newly added flag 'legacy-rate-constants' is consistent with this convention; accordingly, the setting is either enabled or disabled. --- SConstruct | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/SConstruct b/SConstruct index 66aed1f90c..51838deb76 100644 --- a/SConstruct +++ b/SConstruct @@ -680,12 +680,13 @@ config_options = [ False), BoolVariable( "legacy_rate_constants", - """If set to 'false', rate constant calculations will will no longer include - third-body concentrations for ThreeBodyReaction objects. For Cantera 2.6, the - default is set to 'true' (no change of previous behavior). After Cantera 2.6, - the default will be changed to 'false', and rate constant calculations will be - consistent with conventional definitions (see Eq. 9.75 in Kee, Coltrin and - Glarborg, 'Chemically Reacting Flow', Wiley Interscience, 2003).""", + """If enabled, rate constant calculations include third-body concentrations + for three-body reactions, which corresponds to the legacy implementation. + For Cantera 2.6, the option remains enabled (no change compared to past + behavior). After Cantera 2.6, the default will be to disable this option, + and rate constant calculations will be consistent with conventional + definitions (see Eq. 9.75 in Kee, Coltrin and Glarborg, 'Chemically Reacting + Flow', Wiley Interscience, 2003).""", True), ] From b9a7eb846362ca85ad0751142ef33801b2053d68 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Wed, 4 Aug 2021 10:21:21 -0500 Subject: [PATCH 02/28] [UnitTest] Fix true_divide RuntimeWarning in test_kinetics.py --- interfaces/cython/cantera/test/test_kinetics.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/interfaces/cython/cantera/test/test_kinetics.py b/interfaces/cython/cantera/test/test_kinetics.py index 748ce6c691..359e5ecc56 100644 --- a/interfaces/cython/cantera/test/test_kinetics.py +++ b/interfaces/cython/cantera/test/test_kinetics.py @@ -143,8 +143,10 @@ def test_heat_release(self): def test_rate_constants(self): self.assertEqual(len(self.phase.forward_rate_constants), self.phase.n_reactions) - self.assertArrayNear(self.phase.forward_rate_constants / self.phase.reverse_rate_constants, - self.phase.equilibrium_constants) + ix = self.phase.reverse_rate_constants != 0. + self.assertArrayNear( + self.phase.forward_rate_constants[ix] / self.phase.reverse_rate_constants[ix], + self.phase.equilibrium_constants[ix]) def test_species_rates(self): nu_p = self.phase.product_stoich_coeffs() From 20915363aa25243ba81ba64b02c60e33b78a8663 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Mon, 16 Aug 2021 19:09:13 -0500 Subject: [PATCH 03/28] Allow for custom NotImplementedError messages --- include/cantera/base/ctexceptions.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/cantera/base/ctexceptions.h b/include/cantera/base/ctexceptions.h index 0b121f7ca3..605e4c2c11 100644 --- a/include/cantera/base/ctexceptions.h +++ b/include/cantera/base/ctexceptions.h @@ -191,6 +191,12 @@ class NotImplementedError : public CanteraError NotImplementedError(const std::string& func) : CanteraError(func, "Not implemented.") {} + //! Alternative constructor taking same arguments as @see CanteraError + template + NotImplementedError(const std::string& func, const std::string& msg, + const Args&... args) : + CanteraError(func, msg, args...) {} + virtual std::string getClass() const { return "NotImplementedError"; } From 5e94f54032763147aecd2c4aee76f5d83e763246 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Thu, 19 Aug 2021 21:08:45 -0500 Subject: [PATCH 04/28] [Thermo] Fix compilation warning in MixtureFugacityTP.cpp Compilation with GNU g++ currently raises the following warning. warning: 'nSolnValues' may be used uninitialized in this function [-Wmaybe-uninitialized] The warning is resolved by providing an (invalid) initial value; the value is overwritten by a subsequent (pre-existing) if-else tree. --- src/thermo/MixtureFugacityTP.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thermo/MixtureFugacityTP.cpp b/src/thermo/MixtureFugacityTP.cpp index a52c23d96f..b248998578 100644 --- a/src/thermo/MixtureFugacityTP.cpp +++ b/src/thermo/MixtureFugacityTP.cpp @@ -875,7 +875,7 @@ int MixtureFugacityTP::solveCubic(double T, double pres, double a, double b, } } - int nSolnValues; // Represents number of solutions to the cubic equation + int nSolnValues = -1; // Represents number of solutions to the cubic equation double h2 = 4. * an * an * delta2 * delta2 * delta2; // h^2 if (delta2 > 0.0) { delta = sqrt(delta2); From 3d0316461315131b71fc63462f214697278d2378 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Thu, 19 Aug 2021 21:30:24 -0500 Subject: [PATCH 05/28] [Unittests] Resolve unused variable warning in test-surfSolver2 Resolve GNU g++ warning: warning: unused variable 'p' [-Wunused-variable] --- test_problems/surfSolverTest/surfaceSolver2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_problems/surfSolverTest/surfaceSolver2.cpp b/test_problems/surfSolverTest/surfaceSolver2.cpp index 8accd34cba..6d0f830920 100644 --- a/test_problems/surfSolverTest/surfaceSolver2.cpp +++ b/test_problems/surfSolverTest/surfaceSolver2.cpp @@ -174,7 +174,7 @@ int main(int argc, char** argv) nr = iKin_ptr->nReactions(); cout << "Number of reactions = " << nr << endl; - double x[MSSIZE], p = OneAtm; + double x[MSSIZE]; /* * Set-up the Surface Problem From d6afa44cb2deba37307068bf896fa195522096e0 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Sun, 1 Aug 2021 22:44:47 -0500 Subject: [PATCH 06/28] [Numerics] Update eigen_dense.h and introduce eigen_sparse.h --- include/cantera/numerics/eigen_dense.h | 23 ++++++++++++++++++----- include/cantera/numerics/eigen_sparse.h | 19 +++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 include/cantera/numerics/eigen_sparse.h diff --git a/include/cantera/numerics/eigen_dense.h b/include/cantera/numerics/eigen_dense.h index 17de99157d..9df430be54 100644 --- a/include/cantera/numerics/eigen_dense.h +++ b/include/cantera/numerics/eigen_dense.h @@ -1,12 +1,25 @@ -#include "cantera/base/ct_defs.h" +// This file is part of Cantera. See License.txt in the top-level directory or +// at https://cantera.org/license.txt for license and copyright information. + +#ifndef CT_EIGEN_DENSE_H +#define CT_EIGEN_DENSE_H + +#include "cantera/base/config.h" #if CT_USE_SYSTEM_EIGEN #include #else #include "cantera/ext/Eigen/Dense" #endif -namespace Cantera { - typedef Eigen::Map MappedMatrix; - typedef Eigen::Map MappedVector; - typedef Eigen::Map ConstMappedVector; +namespace Cantera +{ + +typedef Eigen::Map MappedMatrix; +typedef Eigen::Map ConstMappedMatrix; +typedef Eigen::Map MappedVector; +typedef Eigen::Map ConstMappedVector; +typedef Eigen::Map MappedRowVector; +typedef Eigen::Map ConstMappedRowVector; } + +#endif diff --git a/include/cantera/numerics/eigen_sparse.h b/include/cantera/numerics/eigen_sparse.h new file mode 100644 index 0000000000..8ed144b8ff --- /dev/null +++ b/include/cantera/numerics/eigen_sparse.h @@ -0,0 +1,19 @@ +// This file is part of Cantera. See License.txt in the top-level directory or +// at https://cantera.org/license.txt for license and copyright information. + +#ifndef CT_EIGEN_SPARSE_H +#define CT_EIGEN_SPARSE_H + +#include "cantera/base/config.h" +#if CT_USE_SYSTEM_EIGEN +#include +#else +#include "cantera/ext/Eigen/Sparse" +#endif + +namespace Cantera +{ +typedef std::vector> SparseTriplets; +} + +#endif From 3fcbc1387720be5d279f99e5c59011cf29c1eb44 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Fri, 20 Aug 2021 07:42:51 -0500 Subject: [PATCH 07/28] [Kinetics] Update ChebyshevRate interface * Use consistent interface based on Array2D * Use column-major consistently in internal calculations * Deprecate Chebyshev::coeffs and Chebyshev::setup --- include/cantera/kinetics/ReactionRate.h | 6 ++ include/cantera/kinetics/RxnRates.h | 33 +++++-- interfaces/cython/cantera/_cantera.pxd | 5 +- interfaces/cython/cantera/reaction.pyx | 22 +++-- .../cython/cantera/test/test_reaction.py | 4 + src/kinetics/ReactionRate.cpp | 11 +++ src/kinetics/RxnRates.cpp | 86 +++++++++++-------- 7 files changed, 111 insertions(+), 56 deletions(-) diff --git a/include/cantera/kinetics/ReactionRate.h b/include/cantera/kinetics/ReactionRate.h index 13034dac97..5f9c1c9475 100644 --- a/include/cantera/kinetics/ReactionRate.h +++ b/include/cantera/kinetics/ReactionRate.h @@ -428,6 +428,12 @@ class ChebyshevRate3 final : public ReactionRate, public Chebyshe return updateRC(0., shared_data.m_recipT); } + //! Access the Chebyshev coefficients as 2-dimensional array. + const Array2D& coeffs() const; + + //! Set the Chebyshev coefficients as 2-dimensional array. + void setCoeffs(const Array2D& coeffs); + virtual void validate(const std::string& equation) override; }; diff --git a/include/cantera/kinetics/RxnRates.h b/include/cantera/kinetics/RxnRates.h index 2edc6dbe7a..efad007fb6 100644 --- a/include/cantera/kinetics/RxnRates.h +++ b/include/cantera/kinetics/RxnRates.h @@ -12,6 +12,7 @@ #define CT_RXNRATES_H #include "cantera/kinetics/reaction_defs.h" +#include "cantera/base/Array.h" #include "cantera/base/ctexceptions.h" namespace Cantera @@ -490,9 +491,16 @@ class Chebyshev void getParameters(AnyMap& rateNode, const Units& rate_units) const; //! Set up Chebyshev object + /*! + * @deprecated Deprecated in Cantera 2.6. Replaceable with + * @see setLimits() and @see setCoeffs(). + */ void setup(double Tmin, double Tmax, double Pmin, double Pmax, const Array2D& coeffs); + //! Set limits for Chebyshev object + void setLimits(double Tmin, double Tmax, double Pmin, double Pmax); + //! Update concentration-dependent parts of the rate coefficient. //! @param c base-10 logarithm of the pressure in Pa void update_C(const double* c) { @@ -500,13 +508,13 @@ class Chebyshev double Cnm1 = Pr; double Cn = 1; double Cnp1; - for (size_t j = 0; j < nT_; j++) { - dotProd_[j] = chebCoeffs_[nP_*j]; + for (size_t i = 0; i < nT_; i++) { + dotProd_[i] = m_coeffs(i, 0); } - for (size_t i = 1; i < nP_; i++) { + for (size_t j = 1; j < nP_; j++) { Cnp1 = 2 * Pr * Cn - Cnm1; - for (size_t j = 0; j < nT_; j++) { - dotProd_[j] += Cnp1 * chebCoeffs_[nP_*j + i]; + for (size_t i = 0; i < nT_; i++) { + dotProd_[i] += Cnp1 * m_coeffs(i, j); } Cnm1 = Cn; Cn = Cnp1; @@ -567,17 +575,28 @@ class Chebyshev /*! * \f$ \alpha_{t,p} = \mathrm{coeffs}[N_P*t + p] \f$ where * \f$ 0 <= t < N_T \f$ and \f$ 0 <= p < N_P \f$. + * + * @deprecated Behavior to change after Cantera 2.6. For new + * behavior @see getCoeffs(). */ - const vector_fp& coeffs() const { - return chebCoeffs_; + const vector_fp& coeffs() const; + + //! Access Chebyshev coefficients as 2-dimensional array. + const Array2D& getCoeffs() const + { + return m_coeffs; } + //! Set the Chebyshev coefficients as 2-dimensional array. + void setCoeffs(const Array2D& coeffs); + protected: double Tmin_, Tmax_; //!< valid temperature range double Pmin_, Pmax_; //!< valid pressure range double TrNum_, TrDen_; //!< terms appearing in the reduced temperature double PrNum_, PrDen_; //!< terms appearing in the reduced pressure + Array2D m_coeffs; //!<< coefficient array size_t nP_; //!< number of points in the pressure direction size_t nT_; //!< number of points in the temperature direction vector_fp chebCoeffs_; //!< Chebyshev coefficients, length nP * nT diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index aeea393444..9f3b59368e 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -126,6 +126,9 @@ cdef extern from "cantera/base/Array.h" namespace "Cantera": CxxArray2D(size_t, size_t) void resize(size_t, size_t) double operator()(size_t, size_t) + vector[double]& data() + size_t nRows() + size_t nColumns() cdef extern from "cantera/thermo/SpeciesThermoInterpType.h": cdef cppclass CxxSpeciesThermo "Cantera::SpeciesThermoInterpType": @@ -394,7 +397,7 @@ cdef extern from "cantera/kinetics/Reaction.h" namespace "Cantera": double Pmax() size_t nPressure() size_t nTemperature() - vector[double]& coeffs() + CxxArray2D& coeffs() cdef cppclass CxxCustomFunc1Rate "Cantera::CustomFunc1Rate" (CxxReactionRateBase): CxxCustomFunc1Rate() diff --git a/interfaces/cython/cantera/reaction.pyx b/interfaces/cython/cantera/reaction.pyx index 2112a32190..53badbbdef 100644 --- a/interfaces/cython/cantera/reaction.pyx +++ b/interfaces/cython/cantera/reaction.pyx @@ -262,8 +262,8 @@ cdef class ChebyshevRate(ReactionRate): if isinstance(input_data, dict): self._rate.reset(new CxxChebyshevRate3(dict_to_anymap(input_data))) elif all([arg is not None for arg in [Tmin, Tmax, Pmin, Pmax, data]]): - self._setup(Tmin, Tmax, Pmin, Pmax, data) - return + self._rate.reset(new CxxChebyshevRate3(Tmin, Tmax, Pmin, Pmax, + self._cxxarray2d(data))) elif all([arg is None for arg in [Tmin, Tmax, Pmin, Pmax, data, input_data]]): self._rate.reset(new CxxChebyshevRate3(dict_to_anymap({}))) @@ -273,12 +273,11 @@ cdef class ChebyshevRate(ReactionRate): raise TypeError("Invalid parameters") self.rate = self._rate.get() - def _setup(self, Tmin, Tmax, Pmin, Pmax, coeffs): - """ - Simultaneously set values for `Tmin`, `Tmax`, `Pmin`, `Pmax`, and - `coeffs`. - """ + cdef CxxArray2D _cxxarray2d(self, coeffs): + """ Internal function to assign coefficient matrix values """ cdef CxxArray2D data + if isinstance(coeffs, np.ndarray): + coeffs = coeffs.tolist() data.resize(len(coeffs), len(coeffs[0])) cdef double value cdef int i @@ -287,8 +286,7 @@ cdef class ChebyshevRate(ReactionRate): for j,value in enumerate(row): CxxArray2D_set(data, i, j, value) - self._rate.reset(new CxxChebyshevRate3(Tmin, Tmax, Pmin, Pmax, data)) - self.rate = self._rate.get() + return data cdef CxxChebyshevRate3* cxx_object(self): return self.rate @@ -328,9 +326,9 @@ cdef class ChebyshevRate(ReactionRate): 2D array of Chebyshev coefficients of size `(n_temperature, n_pressure)`. """ def __get__(self): - c = np.fromiter(self.cxx_object().coeffs(), np.double) - return c.reshape( - (self.cxx_object().nTemperature(), self.cxx_object().nPressure())) + cdef CxxArray2D cxxcoeffs = self.cxx_object().coeffs() + c = np.fromiter(cxxcoeffs.data(), np.double) + return c.reshape(cxxcoeffs.nRows(), cxxcoeffs.nColumns(), order="F") cdef class CustomRate(ReactionRate): diff --git a/interfaces/cython/cantera/test/test_reaction.py b/interfaces/cython/cantera/test/test_reaction.py index 612725e7b9..d7d79c5538 100644 --- a/interfaces/cython/cantera/test/test_reaction.py +++ b/interfaces/cython/cantera/test/test_reaction.py @@ -525,6 +525,8 @@ def test_deprecated_getters(self): if self._yaml is None: return + ct.suppress_deprecation_warnings() # disable fatal deprecation warnings + rxn = ct.Reaction.from_yaml(self._yaml, kinetics=self.gas) for attr, default in self._deprecated_getters.items(): if self._legacy: @@ -533,6 +535,8 @@ def test_deprecated_getters(self): with self.assertWarnsRegex(DeprecationWarning, "property is moved"): self.check_equal(getattr(rxn, attr), default) + ct.make_deprecation_warnings_fatal() # re-enable fatal deprecation warnings + def test_deprecated_setters(self): # check property setters deprecated in new framework if self._yaml is None: diff --git a/src/kinetics/ReactionRate.cpp b/src/kinetics/ReactionRate.cpp index 21b5ea1e70..c490829411 100644 --- a/src/kinetics/ReactionRate.cpp +++ b/src/kinetics/ReactionRate.cpp @@ -5,6 +5,7 @@ #include "cantera/kinetics/ReactionRate.h" #include "cantera/kinetics/MultiRate.h" +#include "cantera/base/Array.h" #include "cantera/numerics/Func1.h" namespace Cantera @@ -190,6 +191,16 @@ void ChebyshevRate3::getParameters(AnyMap& rateNode, rateNode["type"] = type(); } +const Array2D& ChebyshevRate3::coeffs() const +{ + return ChebyshevRate3::getCoeffs(); +} + +void ChebyshevRate3::setCoeffs(const Array2D& coeffs) +{ + Chebyshev::setCoeffs(coeffs); +} + void ChebyshevRate3::validate(const std::string& equation) { } diff --git a/src/kinetics/RxnRates.cpp b/src/kinetics/RxnRates.cpp index c54fc8c2fa..cb62676359 100644 --- a/src/kinetics/RxnRates.cpp +++ b/src/kinetics/RxnRates.cpp @@ -4,7 +4,6 @@ // at https://cantera.org/license.txt for license and copyright information. #include "cantera/kinetics/RxnRates.h" -#include "cantera/base/Array.h" #include "cantera/base/AnyMap.h" #include "cantera/base/global.h" @@ -277,16 +276,9 @@ std::vector > Plog::rates() const Chebyshev::Chebyshev(double Tmin, double Tmax, double Pmin, double Pmax, const Array2D& coeffs) - : Tmin_(Tmin) - , Tmax_(Tmax) - , Pmin_(Pmin) - , Pmax_(Pmax) - , nP_(coeffs.nColumns()) - , nT_(coeffs.nRows()) - , chebCoeffs_(coeffs.nColumns() * coeffs.nRows(), 0.0) - , dotProd_(coeffs.nRows()) { - setup(Tmin, Tmax, Pmin, Pmax, coeffs); + setLimits(Tmin, Tmax, Pmin, Pmax); + setCoeffs(coeffs); } void Chebyshev::setParameters(const AnyMap& node, @@ -307,33 +299,32 @@ void Chebyshev::setParameters(const AnyMap& node, coeffs(i, j) = vcoeffs[i][j]; } } - coeffs(0, 0) += std::log10(units.convertTo(1.0, rate_units)); - - Tmin_ = units.convert(T_range[0], "K"); - Tmax_ = units.convert(T_range[1], "K"); - Pmin_ = units.convert(P_range[0], "Pa"); - Pmax_ = units.convert(P_range[1], "Pa"); - nP_ = coeffs.nColumns(); - nT_ = coeffs.nRows(); + if (rate_units.factor()) { + coeffs(0, 0) += std::log10(units.convertTo(1.0, rate_units)); + } + setLimits( + units.convert(T_range[0], "K"), units.convert(T_range[1], "K"), + units.convert(P_range[0], "Pa"), units.convert(P_range[1], "Pa")); } else { // ensure that reaction rate can be evaluated (but returns NaN) coeffs = Array2D(1, 1); coeffs(0, 0) = NAN; - Tmin_ = 290.; - Tmax_ = 3000.; - Pmin_ = 1.e-7; - Pmax_ = 1.e14; - nP_ = 1; - nT_ = 1; + setLimits(290., 3000., 1.e-7, 1.e14); } - chebCoeffs_.resize(nP_ * nT_); - dotProd_.resize(nT_); - setup(Tmin_, Tmax_, Pmin_, Pmax_, coeffs); + setCoeffs(coeffs); } void Chebyshev::setup(double Tmin, double Tmax, double Pmin, double Pmax, const Array2D& coeffs) +{ + warn_deprecated("Chebyshev::setup", "Deprecated in Cantera 2.6; " + "replaceable with setLimits() and setCoeffs()."); + setLimits(Tmin, Tmax, Pmin, Pmax); + setCoeffs(coeffs); +} + +void Chebyshev::setLimits(double Tmin, double Tmax, double Pmin, double Pmax) { double logPmin = std::log10(Pmin); double logPmax = std::log10(Pmax); @@ -345,29 +336,52 @@ void Chebyshev::setup(double Tmin, double Tmax, double Pmin, double Pmax, PrNum_ = - logPmin - logPmax; PrDen_ = 1.0 / (logPmax - logPmin); - for (size_t t = 0; t < nT_; t++) { - for (size_t p = 0; p < nP_; p++) { - chebCoeffs_[nP_*t + p] = coeffs(t,p); + Tmin_ = Tmin; + Tmax_ = Tmax; + Pmin_ = Pmin; + Pmax_ = Pmax; +} + +const vector_fp& Chebyshev::coeffs() const +{ + warn_deprecated("Chebyshev::coeffs", "Behavior to change after Cantera 2.6; " + "for new behavior, use getCoeffs()."); + return chebCoeffs_; +} + +void Chebyshev::setCoeffs(const Array2D& coeffs) +{ + m_coeffs = Array2D(coeffs); + nP_ = coeffs.nColumns(); + nT_ = coeffs.nRows(); + dotProd_.resize(nT_); + + // convert to row major for legacy output + // note: chebCoeffs_ is not used internally + size_t rows = nT_; + size_t cols = nP_; + chebCoeffs_.resize(rows * cols); + for (size_t i = 0; i < rows; i++) { + for (size_t j = 0; j < cols; j++) { + chebCoeffs_[cols * i + j] = m_coeffs(i, j); } } } void Chebyshev::getParameters(AnyMap& rateNode, const Units& rate_units) const { - double A = chebCoeffs_[0]; - if (std::isnan(A)) { + if (std::isnan(m_coeffs(0, 0))) { // Return empty/unmodified AnyMap return; } rateNode["temperature-range"].setQuantity({Tmin(), Tmax()}, "K"); rateNode["pressure-range"].setQuantity({Pmin(), Pmax()}, "Pa"); - const auto& coeffs1d = coeffs(); - size_t nT = nTemperature(); - size_t nP = nPressure(); + size_t nT = m_coeffs.nRows(); + size_t nP = m_coeffs.nColumns(); std::vector coeffs2d(nT, vector_fp(nP)); for (size_t i = 0; i < nT; i++) { for (size_t j = 0; j < nP; j++) { - coeffs2d[i][j] = coeffs1d[nP*i + j]; + coeffs2d[i][j] = m_coeffs(i, j); } } // Unit conversions must take place later, after the destination unit system From ef7c81b99e271bcee4fe868b5b931a4512112be6 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Sun, 22 Aug 2021 13:59:13 -0500 Subject: [PATCH 08/28] [Kinetics] Remove unused functions from internal StoichManager.h classes Several internal methods defined for C1, C2, C3, and C_AnyN are unused; as there are no simple accessor methods defined in StoichManagerN, deprecation appears not to be required. --- include/cantera/kinetics/StoichManager.h | 83 ++---------------------- 1 file changed, 4 insertions(+), 79 deletions(-) diff --git a/include/cantera/kinetics/StoichManager.h b/include/cantera/kinetics/StoichManager.h index e011edfea9..bbe4fa7ee9 100644 --- a/include/cantera/kinetics/StoichManager.h +++ b/include/cantera/kinetics/StoichManager.h @@ -16,11 +16,8 @@ namespace Cantera /** * @defgroup Stoichiometry Stoichiometry * - * Note: these classes are designed for internal use in class - * ReactionStoichManager. - * * The classes defined here implement simple operations that are used by class - * ReactionStoichManager to compute things like rates of progress, species + * Kinetics to compute things like rates of progress, species * production rates, etc. In general, a reaction mechanism may involve many * species and many reactions, but any given reaction typically only involves * a few species as reactants, and a few as products. Therefore, the matrix of @@ -62,17 +59,17 @@ namespace Cantera * They are designed to explicitly unroll loops over species or reactions for * operations on reactions that require knowing the reaction stoichiometry. * - * This module consists of class StoichManager, and classes C1, C2, and C3. + * This module consists of class StoichManagerN, and classes C1, C2, and C3. * Classes C1, C2, and C3 handle operations involving one, two, or three * species, respectively, in a reaction. Instances are instantiated with a * reaction number, and n species numbers (n = 1 for C1, etc.). All three * classes have the same interface. * - * These classes are designed for use by StoichManager, and the operations + * These classes are designed for use by StoichManagerN, and the operations * implemented are those needed to efficiently compute quantities such as * rates of progress, species production rates, reaction thermochemistry, etc. * The compiler will inline these methods into the body of the corresponding - * StoichManager method, and so there is no performance penalty (unless + * StoichManagerN method, and so there is no performance penalty (unless * inlining is turned off). * * To describe the methods, consider class C3 and suppose an instance is @@ -81,9 +78,6 @@ namespace Cantera * - multiply(in, out) : out[irxn] is multiplied by * in[k0] * in[k1] * in[k2] * - * - power(in, out) : out[irxn] is multiplied by - * (in[k0]^order0) * (in[k1]^order1) * (in[k2]^order2) - * * - incrementReaction(in, out) : out[irxn] is incremented by * in[k0] + in[k1] + in[k2] * @@ -133,12 +127,6 @@ class C1 m_ic0(ic0) { } - size_t data(std::vector& ic) { - ic.resize(1); - ic[0] = m_ic0; - return m_rxn; - } - void incrementSpecies(const doublereal* R, doublereal* S) const { S[m_ic0] += R[m_rxn]; } @@ -159,16 +147,6 @@ class C1 R[m_rxn] -= S[m_ic0]; } - size_t rxnNumber() const { - return m_rxn; - } - size_t speciesIndex(size_t n) const { - return m_ic0; - } - size_t nSpecies() { - return 1; - } - private: //! Reaction number size_t m_rxn; @@ -187,13 +165,6 @@ class C2 C2(size_t rxn = 0, size_t ic0 = 0, size_t ic1 = 0) : m_rxn(rxn), m_ic0(ic0), m_ic1(ic1) {} - size_t data(std::vector& ic) { - ic.resize(2); - ic[0] = m_ic0; - ic[1] = m_ic1; - return m_rxn; - } - void incrementSpecies(const doublereal* R, doublereal* S) const { S[m_ic0] += R[m_rxn]; S[m_ic1] += R[m_rxn]; @@ -220,16 +191,6 @@ class C2 R[m_rxn] -= (S[m_ic0] + S[m_ic1]); } - size_t rxnNumber() const { - return m_rxn; - } - size_t speciesIndex(size_t n) const { - return (n == 0 ? m_ic0 : m_ic1); - } - size_t nSpecies() { - return 2; - } - private: //! Reaction index -> index into the ROP vector size_t m_rxn; @@ -249,14 +210,6 @@ class C3 C3(size_t rxn = 0, size_t ic0 = 0, size_t ic1 = 0, size_t ic2 = 0) : m_rxn(rxn), m_ic0(ic0), m_ic1(ic1), m_ic2(ic2) {} - size_t data(std::vector& ic) { - ic.resize(3); - ic[0] = m_ic0; - ic[1] = m_ic1; - ic[2] = m_ic2; - return m_rxn; - } - void incrementSpecies(const doublereal* R, doublereal* S) const { S[m_ic0] += R[m_rxn]; S[m_ic1] += R[m_rxn]; @@ -286,16 +239,6 @@ class C3 R[m_rxn] -= (S[m_ic0] + S[m_ic1] + S[m_ic2]); } - size_t rxnNumber() const { - return m_rxn; - } - size_t speciesIndex(size_t n) const { - return (n == 0 ? m_ic0 : (n == 1 ? m_ic1 : m_ic2)); - } - size_t nSpecies() { - return 3; - } - private: size_t m_rxn; size_t m_ic0; @@ -331,24 +274,6 @@ class C_AnyN } } - size_t data(std::vector& ic) { - ic.resize(m_n); - for (size_t n = 0; n < m_n; n++) { - ic[n] = m_ic[n]; - } - return m_rxn; - } - - doublereal order(size_t n) const { - return m_order[n]; - } - doublereal stoich(size_t n) const { - return m_stoich[n]; - } - size_t speciesIndex(size_t n) const { - return m_ic[n]; - } - void multiply(const doublereal* input, doublereal* output) const { for (size_t n = 0; n < m_n; n++) { double order = m_order[n]; From c409e25f5c67cd05607158277dca9c27cbf64872 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Sun, 22 Aug 2021 20:28:26 -0500 Subject: [PATCH 09/28] [Kinetics] Add sparse stoichiometric coefficients in StoichManager.h --- include/cantera/kinetics/StoichManager.h | 41 ++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/include/cantera/kinetics/StoichManager.h b/include/cantera/kinetics/StoichManager.h index bbe4fa7ee9..834a809fa2 100644 --- a/include/cantera/kinetics/StoichManager.h +++ b/include/cantera/kinetics/StoichManager.h @@ -8,6 +8,7 @@ #ifndef CT_STOICH_MGR_H #define CT_STOICH_MGR_H +#include "cantera/numerics/eigen_sparse.h" #include "cantera/base/ctexceptions.h" namespace Cantera @@ -458,7 +459,23 @@ class StoichManagerN * DGG - the problem is that the number of reactions and species are not * known initially. */ - StoichManagerN() { + StoichManagerN() : m_finalized(false) { + m_stoichCoeffs.setZero(); + m_stoichCoeffs.resize(0, 0); + } + + //! finalize the sparse coefficient matrix setup + void finalizeSetup(size_t nSpc, size_t nRxn) + { + size_t nCoeffs = m_coeffList.size(); + + // Stoichiometric coefficient matrix + m_stoichCoeffs.setZero(); + m_stoichCoeffs.resize(nSpc, nRxn); + m_stoichCoeffs.reserve(nCoeffs); + m_stoichCoeffs.setFromTriplets(m_coeffList.begin(), m_coeffList.end()); + + m_finalized = true; } /** @@ -505,9 +522,9 @@ class StoichManagerN } bool frac = false; for (size_t n = 0; n < stoich.size(); n++) { + m_coeffList.push_back(Eigen::Triplet(k[n], rxn, stoich[n])); if (fmod(stoich[n], 1.0) || stoich[n] != order[n]) { frac = true; - break; } } if (frac || k.size() > 3) { @@ -538,6 +555,7 @@ class StoichManagerN m_cn_list.emplace_back(rxn, k, order, stoich); } } + m_finalized = false; } void multiply(const doublereal* input, doublereal* output) const { @@ -575,11 +593,30 @@ class StoichManagerN _decrementReactions(m_cn_list.begin(), m_cn_list.end(), input, output); } + //! Return matrix containing stoichiometric coefficients + const Eigen::SparseMatrix& stoichCoeffs() const + { + if (!m_finalized) { + // This can happen if a user overrides default behavior: + // Kinetics::finalizeSetup is not called after adding reactions via + // Kinetics::addReaction with the 'finalize' flag set to 'false' + throw CanteraError("StoichManagerN::stoichCoeffs", + "The object is not fully configured; make sure to call finalizeSetup."); + } + return m_stoichCoeffs; + } + private: + bool m_finalized; //!< Boolean flag indicating whether setup is finalized + std::vector m_c1_list; std::vector m_c2_list; std::vector m_c3_list; std::vector m_cn_list; + + //! Sparse matrices for stoichiometric coefficients + std::vector> m_coeffList; + Eigen::SparseMatrix m_stoichCoeffs; }; } From b9a4eea0f5be3e131b0f5d5cf74618f05ffcb2d1 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Sun, 22 Aug 2021 20:57:44 -0500 Subject: [PATCH 10/28] [Kinetics] Implement mechanism for Kinetics::finalizeSetup The 'Kinetics::finalizeSetup' method executes code after all reactions have been added. The new flag 'finalize' is added to 'Kinetics::addReaction' which determines whether 'finalizeSetup' is executed. While the default is 'true', imports within 'KineticsManager' use 'addReaction' with the flag set to 'false'. --- include/cantera/kinetics/BulkKinetics.h | 2 +- include/cantera/kinetics/GasKinetics.h | 2 +- include/cantera/kinetics/InterfaceKinetics.h | 2 +- include/cantera/kinetics/Kinetics.h | 9 +++++++- include/cantera/kinetics/StoichManager.h | 2 +- interfaces/cython/cantera/_cantera.pxd | 2 ++ interfaces/cython/cantera/base.pyx | 3 ++- src/kinetics/BulkKinetics.cpp | 4 ++-- src/kinetics/GasKinetics.cpp | 4 ++-- src/kinetics/InterfaceKinetics.cpp | 4 ++-- src/kinetics/Kinetics.cpp | 22 +++++++++++++++++++- src/kinetics/KineticsFactory.cpp | 6 ++++-- src/kinetics/importKinetics.cpp | 6 ++++-- 13 files changed, 51 insertions(+), 17 deletions(-) diff --git a/include/cantera/kinetics/BulkKinetics.h b/include/cantera/kinetics/BulkKinetics.h index 2767840739..ef7594578e 100644 --- a/include/cantera/kinetics/BulkKinetics.h +++ b/include/cantera/kinetics/BulkKinetics.h @@ -38,7 +38,7 @@ class BulkKinetics : public Kinetics virtual void getRevRateConstants(double* krev, bool doIrreversible = false); - virtual bool addReaction(shared_ptr r); + virtual bool addReaction(shared_ptr r, bool finalize=true); virtual void modifyReaction(size_t i, shared_ptr rNew); virtual void resizeSpecies(); diff --git a/include/cantera/kinetics/GasKinetics.h b/include/cantera/kinetics/GasKinetics.h index 8a1cda8c44..b97b5aeb5c 100644 --- a/include/cantera/kinetics/GasKinetics.h +++ b/include/cantera/kinetics/GasKinetics.h @@ -49,7 +49,7 @@ class GasKinetics : public BulkKinetics //! @name Reaction Mechanism Setup Routines //! @{ virtual void init(); - virtual bool addReaction(shared_ptr r); + virtual bool addReaction(shared_ptr r, bool finalize=true); virtual void modifyReaction(size_t i, shared_ptr rNew); virtual void invalidateCache(); //@} diff --git a/include/cantera/kinetics/InterfaceKinetics.h b/include/cantera/kinetics/InterfaceKinetics.h index fe74ed3948..7c7e9664e1 100644 --- a/include/cantera/kinetics/InterfaceKinetics.h +++ b/include/cantera/kinetics/InterfaceKinetics.h @@ -199,7 +199,7 @@ class InterfaceKinetics : public Kinetics virtual void init(); virtual void resizeSpecies(); - virtual bool addReaction(shared_ptr r); + virtual bool addReaction(shared_ptr r, bool finalize=true); virtual void modifyReaction(size_t i, shared_ptr rNew); //! @} diff --git a/include/cantera/kinetics/Kinetics.h b/include/cantera/kinetics/Kinetics.h index 036d4ec8c3..e73afaa90d 100644 --- a/include/cantera/kinetics/Kinetics.h +++ b/include/cantera/kinetics/Kinetics.h @@ -135,6 +135,9 @@ class Kinetics return "Kinetics"; } + //! Finalize Kinetics object and associated objects + virtual void finalizeSetup(); + //! Number of reactions in the reaction mechanism. size_t nReactions() const { return m_reactions.size(); @@ -738,9 +741,10 @@ class Kinetics * base class method in addition to handling their own specialized behavior. * * @param r Pointer to the Reaction object to be added. + * @param finalize If `true`, finalize Kinetics object. * @return `true` if the reaction is added or `false` if it was skipped */ - virtual bool addReaction(shared_ptr r); + virtual bool addReaction(shared_ptr r, bool finalize=true); /** * Modify the rate expression associated with a reaction. The @@ -899,6 +903,9 @@ class Kinetics StoichManagerN m_irrevProductStoich; //@} + //! Boolean indicating whether Kinetics object setup is finalized + bool m_finalized; + //! The number of species in all of the phases //! that participate in this kinetics mechanism. size_t m_kk; diff --git a/include/cantera/kinetics/StoichManager.h b/include/cantera/kinetics/StoichManager.h index 834a809fa2..5a1645b058 100644 --- a/include/cantera/kinetics/StoichManager.h +++ b/include/cantera/kinetics/StoichManager.h @@ -459,7 +459,7 @@ class StoichManagerN * DGG - the problem is that the number of reactions and species are not * known initially. */ - StoichManagerN() : m_finalized(false) { + StoichManagerN() : m_finalized(true) { m_stoichCoeffs.setZero(); m_stoichCoeffs.resize(0, 0); } diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 9f3b59368e..11f34166fc 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -562,8 +562,10 @@ cdef extern from "cantera/kinetics/Kinetics.h" namespace "Cantera": void init() except +translate_exception void skipUndeclaredThirdBodies(cbool) void addReaction(shared_ptr[CxxReaction]) except +translate_exception + void addReaction(shared_ptr[CxxReaction], cbool) except +translate_exception void modifyReaction(int, shared_ptr[CxxReaction]) except +translate_exception void invalidateCache() except +translate_exception + void finalizeSetup() shared_ptr[CxxReaction] reaction(size_t) except +translate_exception cbool isReversible(int) except +translate_exception diff --git a/interfaces/cython/cantera/base.pyx b/interfaces/cython/cantera/base.pyx index 20bdfd5532..4952e242c9 100644 --- a/interfaces/cython/cantera/base.pyx +++ b/interfaces/cython/cantera/base.pyx @@ -224,7 +224,8 @@ cdef class _SolutionBase: self.kinetics.init() self.kinetics.skipUndeclaredThirdBodies(True) for reaction in reactions: - self.kinetics.addReaction(reaction._reaction) + self.kinetics.addReaction(reaction._reaction, False) + self.kinetics.finalizeSetup() property input_data: """ diff --git a/src/kinetics/BulkKinetics.cpp b/src/kinetics/BulkKinetics.cpp index 9cafa138b3..c847558849 100644 --- a/src/kinetics/BulkKinetics.cpp +++ b/src/kinetics/BulkKinetics.cpp @@ -99,9 +99,9 @@ void BulkKinetics::getRevRateConstants(double* krev, bool doIrreversible) } } -bool BulkKinetics::addReaction(shared_ptr r) +bool BulkKinetics::addReaction(shared_ptr r, bool finalize) { - bool added = Kinetics::addReaction(r); + bool added = Kinetics::addReaction(r, finalize); if (!added) { // undeclared species, etc. return false; diff --git a/src/kinetics/GasKinetics.cpp b/src/kinetics/GasKinetics.cpp index f7e8069901..2aa3fe29d1 100644 --- a/src/kinetics/GasKinetics.cpp +++ b/src/kinetics/GasKinetics.cpp @@ -264,10 +264,10 @@ void GasKinetics::getFwdRateConstants(double* kfwd) } } -bool GasKinetics::addReaction(shared_ptr r) +bool GasKinetics::addReaction(shared_ptr r, bool finalize) { // operations common to all reaction types - bool added = BulkKinetics::addReaction(r); + bool added = BulkKinetics::addReaction(r, finalize); if (!added) { return false; } else if (!(r->usesLegacy())) { diff --git a/src/kinetics/InterfaceKinetics.cpp b/src/kinetics/InterfaceKinetics.cpp index 0679bf4233..850072aace 100644 --- a/src/kinetics/InterfaceKinetics.cpp +++ b/src/kinetics/InterfaceKinetics.cpp @@ -477,7 +477,7 @@ void InterfaceKinetics::getDeltaSSEntropy(doublereal* deltaS) getReactionDelta(m_grt.data(), deltaS); } -bool InterfaceKinetics::addReaction(shared_ptr r_base) +bool InterfaceKinetics::addReaction(shared_ptr r_base, bool finalize) { if (!m_surf) { init(); @@ -505,7 +505,7 @@ bool InterfaceKinetics::addReaction(shared_ptr r_base) } size_t i = nReactions(); - bool added = Kinetics::addReaction(r_base); + bool added = Kinetics::addReaction(r_base, finalize); if (!added) { return false; } diff --git a/src/kinetics/Kinetics.cpp b/src/kinetics/Kinetics.cpp index 92b13370e2..fcf8115244 100644 --- a/src/kinetics/Kinetics.cpp +++ b/src/kinetics/Kinetics.cpp @@ -24,6 +24,7 @@ using namespace std; namespace Cantera { Kinetics::Kinetics() : + m_finalized(false), m_kk(0), m_thermo(0), m_surfphase(npos), @@ -44,6 +45,18 @@ void Kinetics::checkReactionIndex(size_t i) const } } +void Kinetics::finalizeSetup() +{ + size_t nRxn = nReactions(); + + // Stoichiometry managers + m_reactantStoich.finalizeSetup(m_kk, nRxn); + m_revProductStoich.finalizeSetup(m_kk, nRxn); + m_irrevProductStoich.finalizeSetup(m_kk, nRxn); + + m_finalized = true; +} + void Kinetics::checkReactionArraySize(size_t ii) const { if (nReactions() > ii) { @@ -501,7 +514,7 @@ void Kinetics::resizeSpecies() invalidateCache(); } -bool Kinetics::addReaction(shared_ptr r) +bool Kinetics::addReaction(shared_ptr r, bool finalize) { r->validate(); if (m_kk == 0) { @@ -577,6 +590,13 @@ bool Kinetics::addReaction(shared_ptr r) m_ropnet.push_back(0.0); m_perturb.push_back(1.0); m_dH.push_back(0.0); + + if (finalize) { + finalizeSetup(); + } else { + m_finalized = false; + } + return true; } diff --git a/src/kinetics/KineticsFactory.cpp b/src/kinetics/KineticsFactory.cpp index fd15c8a6df..905580d4a6 100644 --- a/src/kinetics/KineticsFactory.cpp +++ b/src/kinetics/KineticsFactory.cpp @@ -175,7 +175,7 @@ void addReactions(Kinetics& kin, const AnyMap& phaseNode, const AnyMap& rootNode rootNode.getString("__file__", "")); for (const auto& R : reactions[node].asVector()) { try { - kin.addReaction(newReaction(R, kin)); + kin.addReaction(newReaction(R, kin), false); } catch (CanteraError& err) { format_to(add_rxn_err, "{}", err.what()); } @@ -184,7 +184,7 @@ void addReactions(Kinetics& kin, const AnyMap& phaseNode, const AnyMap& rootNode // specified section is in the current file for (const auto& R : rootNode.at(sections[i]).asVector()) { try { - kin.addReaction(newReaction(R, kin)); + kin.addReaction(newReaction(R, kin), false); } catch (CanteraError& err) { format_to(add_rxn_err, "{}", err.what()); } @@ -196,6 +196,8 @@ void addReactions(Kinetics& kin, const AnyMap& phaseNode, const AnyMap& rootNode if (add_rxn_err.size()) { throw CanteraError("addReactions", to_string(add_rxn_err)); } + + kin.finalizeSetup(); } } diff --git a/src/kinetics/importKinetics.cpp b/src/kinetics/importKinetics.cpp index 3164ead2b1..cb7e26dd53 100644 --- a/src/kinetics/importKinetics.cpp +++ b/src/kinetics/importKinetics.cpp @@ -82,7 +82,7 @@ bool installReactionArrays(const XML_Node& p, Kinetics& kin, if (incl.empty()) { for (size_t i = 0; i < allrxns.size(); i++) { checkElectrochemReaction(p,kin,*allrxns[i]); - kin.addReaction(newReaction(*allrxns[i])); + kin.addReaction(newReaction(*allrxns[i]), false); ++itot; } } else { @@ -114,7 +114,7 @@ bool installReactionArrays(const XML_Node& p, Kinetics& kin, // has surprising results. if ((rxid >= imin) && (rxid <= imax)) { checkElectrochemReaction(p,kin,*r); - kin.addReaction(newReaction(*r)); + kin.addReaction(newReaction(*r), false); ++itot; } } @@ -127,6 +127,8 @@ bool installReactionArrays(const XML_Node& p, Kinetics& kin, kin.checkDuplicates(); } + kin.finalizeSetup(); + return true; } From 3f2dc1e58fa6918afced82b9bba00ccf2bc0942b Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Mon, 23 Aug 2021 08:40:54 -0500 Subject: [PATCH 11/28] [Kinetics] Merge irreversible and reversible product StoichManagerN as Kinetics::m_irrevProductManager is only used in conjunction with Kinetics::m_revProductManager, a new Kinetics::m_productManager provides for simpler code. --- include/cantera/kinetics/Kinetics.h | 6 +++--- src/kinetics/Kinetics.cpp | 14 +++++--------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/include/cantera/kinetics/Kinetics.h b/include/cantera/kinetics/Kinetics.h index e73afaa90d..474ab4c1d8 100644 --- a/include/cantera/kinetics/Kinetics.h +++ b/include/cantera/kinetics/Kinetics.h @@ -896,11 +896,11 @@ class Kinetics //! Stoichiometry manager for the reactants for each reaction StoichManagerN m_reactantStoich; + //! Stoichiometry manager for the products for each reaction + StoichManagerN m_productStoich; + //! Stoichiometry manager for the products of reversible reactions StoichManagerN m_revProductStoich; - - //! Stoichiometry manager for the products of irreversible reactions - StoichManagerN m_irrevProductStoich; //@} //! Boolean indicating whether Kinetics object setup is finalized diff --git a/src/kinetics/Kinetics.cpp b/src/kinetics/Kinetics.cpp index fcf8115244..241ec9074d 100644 --- a/src/kinetics/Kinetics.cpp +++ b/src/kinetics/Kinetics.cpp @@ -51,8 +51,8 @@ void Kinetics::finalizeSetup() // Stoichiometry managers m_reactantStoich.finalizeSetup(m_kk, nRxn); + m_productStoich.finalizeSetup(m_kk, nRxn); m_revProductStoich.finalizeSetup(m_kk, nRxn); - m_irrevProductStoich.finalizeSetup(m_kk, nRxn); m_finalized = true; } @@ -417,8 +417,7 @@ void Kinetics::getReactionDelta(const double* prop, double* deltaProp) { fill(deltaProp, deltaProp + nReactions(), 0.0); // products add - m_revProductStoich.incrementReactions(prop, deltaProp); - m_irrevProductStoich.incrementReactions(prop, deltaProp); + m_productStoich.incrementReactions(prop, deltaProp); // reactants subtract m_reactantStoich.decrementReactions(prop, deltaProp); } @@ -440,8 +439,7 @@ void Kinetics::getCreationRates(double* cdot) fill(cdot, cdot + m_kk, 0.0); // the forward direction creates product species - m_revProductStoich.incrementSpecies(m_ropf.data(), cdot); - m_irrevProductStoich.incrementSpecies(m_ropf.data(), cdot); + m_productStoich.incrementSpecies(m_ropf.data(), cdot); // the reverse direction creates reactant species m_reactantStoich.incrementSpecies(m_ropr.data(), cdot); @@ -464,8 +462,7 @@ void Kinetics::getNetProductionRates(doublereal* net) fill(net, net + m_kk, 0.0); // products are created for positive net rate of progress - m_revProductStoich.incrementSpecies(m_ropnet.data(), net); - m_irrevProductStoich.incrementSpecies(m_ropnet.data(), net); + m_productStoich.incrementSpecies(m_ropnet.data(), net); // reactants are destroyed for positive net rate of progress m_reactantStoich.decrementSpecies(m_ropnet.data(), net); } @@ -576,10 +573,9 @@ bool Kinetics::addReaction(shared_ptr r, bool finalize) m_reactantStoich.add(irxn, rk, rorder, rstoich); // product orders = product stoichiometric coefficients + m_productStoich.add(irxn, pk, pstoich, pstoich); if (r->reversible) { m_revProductStoich.add(irxn, pk, pstoich, pstoich); - } else { - m_irrevProductStoich.add(irxn, pk, pstoich, pstoich); } m_reactions.push_back(r); From 9e31a125b4f9152f891ebac787554ba9b2f22a19 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Mon, 23 Aug 2021 09:58:01 -0500 Subject: [PATCH 12/28] [Kinetics] Use sparse stoichcoeff matrices for internal calculations --- include/cantera/kinetics/Kinetics.h | 25 +++++++++++++++++++++++++ src/kinetics/Kinetics.cpp | 6 ++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/include/cantera/kinetics/Kinetics.h b/include/cantera/kinetics/Kinetics.h index 474ab4c1d8..023d413e96 100644 --- a/include/cantera/kinetics/Kinetics.h +++ b/include/cantera/kinetics/Kinetics.h @@ -558,6 +558,15 @@ class Kinetics * @param i reaction index */ virtual double reactantStoichCoeff(size_t k, size_t i) const; + + /** + * Stoichiometric coefficient matrix for reactants. + */ + Eigen::SparseMatrix reactantStoichCoeffs() const + { + return m_reactantStoich.stoichCoeffs(); + } + /** * Stoichiometric coefficient of species k as a product in reaction i. * @@ -566,6 +575,22 @@ class Kinetics */ virtual double productStoichCoeff(size_t k, size_t i) const; + /** + * Stoichiometric coefficient matrix for products. + */ + Eigen::SparseMatrix productStoichCoeffs() const + { + return m_productStoich.stoichCoeffs(); + } + + /** + * Stoichiometric coefficient matrix for products of reversible reactions. + */ + Eigen::SparseMatrix revProductStoichCoeffs() const + { + return m_revProductStoich.stoichCoeffs(); + } + //! Reactant order of species k in reaction i. /*! * This is the nominal order of the activity concentration in diff --git a/src/kinetics/Kinetics.cpp b/src/kinetics/Kinetics.cpp index 241ec9074d..2d0041472f 100644 --- a/src/kinetics/Kinetics.cpp +++ b/src/kinetics/Kinetics.cpp @@ -356,14 +356,12 @@ size_t Kinetics::speciesPhaseIndex(size_t k) const double Kinetics::reactantStoichCoeff(size_t kSpec, size_t irxn) const { - return getValue(m_reactions[irxn]->reactants, kineticsSpeciesName(kSpec), - 0.0); + return m_reactantStoich.stoichCoeffs().coeff(kSpec, irxn); } double Kinetics::productStoichCoeff(size_t kSpec, size_t irxn) const { - return getValue(m_reactions[irxn]->products, kineticsSpeciesName(kSpec), - 0.0); + return m_productStoich.stoichCoeffs().coeff(kSpec, irxn); } int Kinetics::reactionType(size_t i) const { From de3158b87951464f40241123959e3e85e56ace65 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Mon, 23 Aug 2021 18:10:15 -0500 Subject: [PATCH 13/28] [Python] Enable optional scipy.sparse output --- interfaces/cython/cantera/utils.pyx | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/interfaces/cython/cantera/utils.pyx b/interfaces/cython/cantera/utils.pyx index 3e07c4c446..20d3503ae5 100644 --- a/interfaces/cython/cantera/utils.pyx +++ b/interfaces/cython/cantera/utils.pyx @@ -6,6 +6,15 @@ import os import warnings from cpython.ref cimport PyObject import numbers +import pkg_resources + +# avoid explicit dependence of cantera on scipy +try: + pkg_resources.get_distribution('scipy') +except pkg_resources.DistributionNotFound: + _scipy_sparse = ImportError('Method requires a working scipy installation.') +else: + from scipy import sparse as _scipy_sparse cdef CxxPythonLogger* _logger = new CxxPythonLogger() CxxSetLogger(_logger) @@ -35,10 +44,22 @@ __version__ = pystr(get_cantera_version()) __git_commit__ = pystr(CxxGitCommit()) +__use_sparse__ = False + def appdelete(): """ Delete all global Cantera C++ objects """ CxxAppdelete() +def use_sparse(sparse=True): + """ + Enable sparse output using `scipy.sparse`. Sparse output requires a working + `scipy` installation. Use pip or conda to install `scipy` to enable this method. + """ + global __use_sparse__ + if sparse and isinstance(_scipy_sparse, ImportError): + raise _scipy_sparse + __use_sparse__ = sparse + def make_deprecation_warnings_fatal(): warnings.filterwarnings('error', category=DeprecationWarning, module='cantera') # for warnings in Python code From 31b08de17ca7030b8babc1e098890adef2f3346c Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Mon, 23 Aug 2021 17:43:32 -0500 Subject: [PATCH 14/28] [Python] Create sparse stoichCoeff API --- include/cantera/cython/wrappers.h | 34 ++++++++++++++++++++++++++ interfaces/cython/cantera/_cantera.pxd | 7 ++++++ interfaces/cython/cantera/kinetics.pyx | 25 +++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/include/cantera/cython/wrappers.h b/include/cantera/cython/wrappers.h index 65225289a6..bbf6621d49 100644 --- a/include/cantera/cython/wrappers.h +++ b/include/cantera/cython/wrappers.h @@ -2,6 +2,7 @@ // at https://cantera.org/license.txt for license and copyright information. #include "cantera/base/logger.h" +#include "cantera/numerics/eigen_sparse.h" #include "cantera/thermo/ThermoPhase.h" #include "cantera/transport/TransportBase.h" #include "cantera/kinetics/Kinetics.h" @@ -49,6 +50,35 @@ void CxxArray2D_set(Cantera::Array2D& array, size_t i, size_t j, double value) array(i,j) = value; } +// Service function to pass components describing sparse matrix +size_t sparseComponents(const Eigen::SparseMatrix& mat, + int* rows, int* cols, double* data, size_t length) +{ + size_t count = 0; + for (int i = 0; i < mat.outerSize(); i++) { + for (Eigen::SparseMatrix::InnerIterator it(mat, i); it; ++it) { + if (count < length) { + rows[count] = it.row(); + cols[count] = it.col(); + data[count] = it.value(); + } + count++; + } + } + if (count > length) { + throw Cantera::CanteraError("sparseComponents", + "Output arrays have insufficient length. Required size is {}, " + "while provided length is {}.", count, length); + } + return count; +} + +// Function which passes sparse matrix components to a set of 1D arrays +#define SPARSE_FUNC(PREFIX, CLASS_NAME, FUNC_NAME) \ + size_t PREFIX ## _ ## FUNC_NAME(Cantera::CLASS_NAME* object, \ + int* rows, int* cols, double* data, size_t length) \ + { return sparseComponents(object->FUNC_NAME(), rows, cols, data, length); } + // Function which populates a 1D array #define ARRAY_FUNC(PREFIX, CLASS_NAME, FUNC_NAME) \ void PREFIX ## _ ## FUNC_NAME(Cantera::CLASS_NAME* object, double* data) \ @@ -62,6 +92,7 @@ void CxxArray2D_set(Cantera::Array2D& array, size_t i, size_t j, double value) #define THERMO_1D(FUNC_NAME) ARRAY_FUNC(thermo, ThermoPhase, FUNC_NAME) #define KIN_1D(FUNC_NAME) ARRAY_FUNC(kin, Kinetics, FUNC_NAME) +#define KIN_SPARSE(FUNC_NAME) SPARSE_FUNC(kin, Kinetics, FUNC_NAME) #define TRANSPORT_1D(FUNC_NAME) ARRAY_FUNC(tran, Transport, FUNC_NAME) #define TRANSPORT_2D(FUNC_NAME) ARRAY_FUNC2(tran, Transport, FUNC_NAME) @@ -89,6 +120,9 @@ THERMO_1D(getCp_R) THERMO_1D(getActivities) THERMO_1D(getActivityCoefficients) +KIN_SPARSE(reactantStoichCoeffs) +KIN_SPARSE(productStoichCoeffs) + KIN_1D(getFwdRatesOfProgress) KIN_1D(getRevRatesOfProgress) KIN_1D(getNetRatesOfProgress) diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 11f34166fc..d9bb3ba800 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -1095,6 +1095,10 @@ cdef extern from "cantera/cython/wrappers.h": cdef void kin_getDestructionRates(CxxKinetics*, double*) except +translate_exception cdef void kin_getNetProductionRates(CxxKinetics*, double*) except +translate_exception + # Kinetics sparse matrices + cdef size_t kin_reactantStoichCoeffs(CxxKinetics*, int*, int*, double*, size_t) except +translate_exception + cdef size_t kin_productStoichCoeffs(CxxKinetics*, int*, int*, double*, size_t) except +translate_exception + # Transport properties cdef void tran_getMixDiffCoeffs(CxxTransport*, double*) except +translate_exception cdef void tran_getMixDiffCoeffsMass(CxxTransport*, double*) except +translate_exception @@ -1111,6 +1115,7 @@ ctypedef void (*thermoMethod1d)(CxxThermoPhase*, double*) except +translate_exce ctypedef void (*transportMethod1d)(CxxTransport*, double*) except +translate_exception ctypedef void (*transportMethod2d)(CxxTransport*, size_t, double*) except +translate_exception ctypedef void (*kineticsMethod1d)(CxxKinetics*, double*) except +translate_exception +ctypedef size_t (*kineticsMethodSparse)(CxxKinetics*, int*, int*, double*, size_t) except +translate_exception # classes cdef class SpeciesThermo: @@ -1358,6 +1363,8 @@ cdef string stringify(x) except * cdef pystr(string x) cdef np.ndarray get_species_array(Kinetics kin, kineticsMethod1d method) cdef np.ndarray get_reaction_array(Kinetics kin, kineticsMethod1d method) +cdef np.ndarray get_dense(Kinetics kin, kineticsMethodSparse method, size_t dim, tuple shape) +cdef tuple get_sparse(Kinetics kin, kineticsMethodSparse method, size_t dim) cdef np.ndarray get_transport_1d(Transport tran, transportMethod1d method) cdef np.ndarray get_transport_2d(Transport tran, transportMethod2d method) cdef CxxIdealGasPhase* getIdealGasPhase(ThermoPhase phase) except * diff --git a/interfaces/cython/cantera/kinetics.pyx b/interfaces/cython/cantera/kinetics.pyx index eabc5ad665..e7f53f030c 100644 --- a/interfaces/cython/cantera/kinetics.pyx +++ b/interfaces/cython/cantera/kinetics.pyx @@ -1,6 +1,8 @@ # This file is part of Cantera. See License.txt in the top-level directory or # at https://cantera.org/license.txt for license and copyright information. +from ctypes import c_int + # NOTE: These cdef functions cannot be members of Kinetics because they would # cause "layout conflicts" when creating derived classes with multiple bases, # e.g. class Solution. [Cython 0.16] @@ -18,6 +20,29 @@ cdef np.ndarray get_reaction_array(Kinetics kin, kineticsMethod1d method): method(kin.kinetics, &data[0]) return data +cdef np.ndarray get_dense(Kinetics kin, kineticsMethodSparse method, + size_t max_dim, tuple shape): + cdef vector[int] rows + cdef vector[int] cols + cdef vector[double] data + cdef size_t size + rows.resize(max_dim) + cols.resize(max_dim) + data.resize(max_dim) + size = method(kin.kinetics, &rows[0], &cols[0], &data[0], max_dim) + + out = np.zeros(shape) + for i in xrange(size): + out[rows[i], cols[i]] = data[i] + return out + +cdef tuple get_sparse(Kinetics kin, kineticsMethodSparse method, size_t max_dim): + cdef np.ndarray[int, ndim=1, mode="c"] rows = np.empty(max_dim, dtype=c_int) + cdef np.ndarray[int, ndim=1, mode="c"] cols = np.empty(max_dim, dtype=c_int) + cdef np.ndarray[np.double_t, ndim=1] data = np.empty(max_dim) + size = method(kin.kinetics, &rows[0], &cols[0], &data[0], max_dim) + return data[:size], tuple([rows[:size], cols[:size]]) + cdef class Kinetics(_SolutionBase): """ From 67cd2e35ae6e73bec37ad77c0106de9a6b80a510 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Mon, 23 Aug 2021 20:08:09 -0500 Subject: [PATCH 15/28] [GH] Add scipy to coverage tests --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ed54007ce9..073515ad72 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -115,7 +115,7 @@ jobs: - name: Upgrade pip run: python3 -m pip install -U pip setuptools wheel - name: Install Python dependencies - run: python3 -m pip install ruamel.yaml scons numpy cython h5py pandas pytest + run: python3 -m pip install ruamel.yaml scons numpy cython h5py pandas scipy pytest pytest-github-actions-annotate-failures - name: Build Cantera run: | From 6cd9e311a0fe44f48003b4a266297cbb10f6bfbd Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Fri, 27 Aug 2021 09:09:35 -0500 Subject: [PATCH 16/28] [Unittest] Skip some tests if h5py is not installed --- interfaces/cython/cantera/test/test_composite.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interfaces/cython/cantera/test/test_composite.py b/interfaces/cython/cantera/test/test_composite.py index 721c20cbf8..c8f839aa27 100644 --- a/interfaces/cython/cantera/test/test_composite.py +++ b/interfaces/cython/cantera/test/test_composite.py @@ -154,6 +154,7 @@ def test_append_no_norm_data(self): self.assertEqual(states[0].P, gas.P) self.assertArrayNear(states[0].Y, gas.Y) + @utilities.unittest.skipIf(isinstance(_h5py, ImportError), "h5py is not installed") def test_import_no_norm_data(self): outfile = self.test_work_path / "solutionarray.h5" # In Python >= 3.8, this can be replaced by the missing_ok argument @@ -469,6 +470,7 @@ def check(a, b): b.restore_data(data) check(a, b) + @utilities.unittest.skipIf(isinstance(_h5py, ImportError), "h5py is not installed") def test_import_no_norm_water(self): outfile = self.test_work_path / "solutionarray.h5" # In Python >= 3.8, this can be replaced by the missing_ok argument From b4924347709f15d76730dbf3d8afc003be0deb05 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Sat, 4 Sep 2021 13:12:53 -0500 Subject: [PATCH 17/28] [Kinetics] Streamline Chebyshev interface Deprecate Tmin/Tmax, Pmin/Pmax as well as constructors to use std::pair input/output --- include/cantera/kinetics/ReactionRate.h | 21 ++-- include/cantera/kinetics/RxnRates.h | 128 ++++++++++++++++---- interfaces/cython/cantera/_cantera.pxd | 21 ++-- interfaces/cython/cantera/reaction.pyx | 154 +++++++++++++----------- src/kinetics/Reaction.cpp | 20 +-- src/kinetics/ReactionRate.cpp | 7 +- src/kinetics/RxnRates.cpp | 65 +++++----- 7 files changed, 258 insertions(+), 158 deletions(-) diff --git a/include/cantera/kinetics/ReactionRate.h b/include/cantera/kinetics/ReactionRate.h index 5f9c1c9475..75b2b45011 100644 --- a/include/cantera/kinetics/ReactionRate.h +++ b/include/cantera/kinetics/ReactionRate.h @@ -379,6 +379,9 @@ class PlogRate final : public ReactionRate, public Plog * Chebyshev polynomials are not defined outside the interval (-1,1), and * therefore extrapolation of rates outside the range of temperatures and * pressures for which they are defined is strongly discouraged. + * + * @TODO rename to ChebyshevRate when the legacy ChebyshevRate class is removed + * from RxnRates.h after Cantera 2.6. */ class ChebyshevRate3 final : public ReactionRate, public Chebyshev { @@ -386,18 +389,18 @@ class ChebyshevRate3 final : public ReactionRate, public Chebyshe //! Default constructor. ChebyshevRate3() {} - //! Constructor directly from coefficient array - /* - * @param Tmin Minimum temperature [K] - * @param Tmax Maximum temperature [K] - * @param Pmin Minimum pressure [Pa] - * @param Pmax Maximum pressure [Pa] - * @param coeffs Coefficient array dimensioned `nT` by `nP` where `nT` and + //! Constructor using coefficient array + /*! + * @param Trange Valid temperature range (min, max) [K] + * @param Prange Valid pressure range (min, max) [Pa] + * @param coeffs Coefficient array dimensioned `nT` by `nP` where `nT` and * `nP` are the number of temperatures and pressures used in the fit, * respectively. */ - ChebyshevRate3(double Tmin, double Tmax, double Pmin, double Pmax, - const Array2D& coeffs); + ChebyshevRate3( + const std::pair Trange, + const std::pair Prange, + const Array2D& coeffs); //! Constructor using AnyMap content //! @param node AnyMap containing rate information diff --git a/include/cantera/kinetics/RxnRates.h b/include/cantera/kinetics/RxnRates.h index efad007fb6..542872e531 100644 --- a/include/cantera/kinetics/RxnRates.h +++ b/include/cantera/kinetics/RxnRates.h @@ -14,6 +14,7 @@ #include "cantera/kinetics/reaction_defs.h" #include "cantera/base/Array.h" #include "cantera/base/ctexceptions.h" +#include "cantera/base/global.h" namespace Cantera { @@ -467,10 +468,23 @@ class Chebyshev { public: //! Default constructor. - Chebyshev() : nP_(0), nT_(0) {} + Chebyshev() {} //! Constructor directly from coefficient array - /* + /*! + * @param Trange Valid temperature range (min, max) [K] + * @param Prange Valid pressure range (min, max) [Pa] + * @param coeffs Coefficient array dimensioned `nT` by `nP` where `nT` and + * `nP` are the number of temperatures and pressures used in the fit, + * respectively. + */ + Chebyshev( + const std::pair Trange, + const std::pair Prange, + const Array2D& coeffs); + + //! Constructor directly from coefficient array + /*! * @param Tmin Minimum temperature [K] * @param Tmax Maximum temperature [K] * @param Pmin Minimum pressure [Pa] @@ -478,6 +492,9 @@ class Chebyshev * @param coeffs Coefficient array dimensioned `nT` by `nP` where `nT` and * `nP` are the number of temperatures and pressures used in the fit, * respectively. + * + * @deprecated Deprecated in Cantera 2.6. + * Use constructor using pairs for range input. */ Chebyshev(double Tmin, double Tmax, double Pmin, double Pmax, const Array2D& coeffs); @@ -499,7 +516,13 @@ class Chebyshev const Array2D& coeffs); //! Set limits for Chebyshev object - void setLimits(double Tmin, double Tmax, double Pmin, double Pmax); + /*! + * @param Trange Temperature range (min, max) [K] + * @param Prange Pressure range (min, max) [Pa] + */ + void setLimits( + const std::pair Trange, + const std::pair Prange); //! Update concentration-dependent parts of the rate coefficient. //! @param c base-10 logarithm of the pressure in Pa @@ -508,12 +531,12 @@ class Chebyshev double Cnm1 = Pr; double Cn = 1; double Cnp1; - for (size_t i = 0; i < nT_; i++) { + for (size_t i = 0; i < m_coeffs.nRows(); i++) { dotProd_[i] = m_coeffs(i, 0); } - for (size_t j = 1; j < nP_; j++) { + for (size_t j = 1; j < m_coeffs.nColumns(); j++) { Cnp1 = 2 * Pr * Cn - Cnm1; - for (size_t i = 0; i < nT_; i++) { + for (size_t i = 0; i < m_coeffs.nRows(); i++) { dotProd_[i] += Cnp1 * m_coeffs(i, j); } Cnm1 = Cn; @@ -532,7 +555,7 @@ class Chebyshev double Cn = 1; double Cnp1; double logk = dotProd_[0]; - for (size_t i = 1; i < nT_; i++) { + for (size_t i = 1; i < m_coeffs.nRows(); i++) { Cnp1 = 2 * Tr * Cn - Cnm1; logk += Cnp1 * dotProd_[i]; Cnm1 = Cn; @@ -542,33 +565,87 @@ class Chebyshev } //! Minimum valid temperature [K] - double Tmin() const { - return Tmin_; + /*! + * @deprecated Deprecated in Cantera 2.6. + * Replaceable with @see temperatureRange() + */ + double Tmin() const + { + warn_deprecated("Chebyshev::Tmin", "Deprecated in Cantera 2.6; " + "replaceable with temperatureRange."); + return m_Trange.first; } //! Maximum valid temperature [K] - double Tmax() const { - return Tmax_; + /*! + * @deprecated Deprecated in Cantera 2.6. + * Replaceable with @see temperatureRange() + */ + double Tmax() const + { + warn_deprecated("Chebyshev::Tmax", "Deprecated in Cantera 2.6; " + "replaceable with temperatureRange."); + return m_Trange.second; + } + + // Range of valid temperatures (min, max) [K] + const std::pair& temperatureRange() const + { + return m_Trange; } //! Minimum valid pressure [Pa] - double Pmin() const { - return Pmin_; + /*! + * @deprecated Deprecated in Cantera 2.6. + * Replaceable with @see pressureRange() + */ + double Pmin() const + { + warn_deprecated("Chebyshev::Pmin", "Deprecated in Cantera 2.6; " + "replaceable with pressureRange."); + return m_Prange.first; } //! Maximum valid pressure [Pa] - double Pmax() const { - return Pmax_; + /*! + * @deprecated Deprecated in Cantera 2.6. + * Replaceable with @see pressureRange() + */ + double Pmax() const + { + warn_deprecated("Chebyshev::Pmax", "Deprecated in Cantera 2.6; " + "replaceable with pressureRange."); + return m_Prange.second; + } + + // Range of valid pressures (min, max) [Pa] + const std::pair& pressureRange() const + { + return m_Prange; } //! Number of points in the pressure direction - size_t nPressure() const { - return nP_; + /*! + * @deprecated Deprecated in Cantera 2.6. + * Accessible as number of columns of the coefficient matrix + */ + size_t nPressure() const + { + warn_deprecated("Chebyshev::nPressure", "Deprecated in Cantera 2.6; " + "accessible as number of colums of the coefficient matrix."); + return m_coeffs.nColumns(); } //! Number of points in the temperature direction - size_t nTemperature() const { - return nT_; + /*! + * @deprecated Deprecated in Cantera 2.6. + * Accessible as number of rows of the coefficient matrix + */ + size_t nTemperature() const + { + warn_deprecated("Chebyshev::nTemperature", "Deprecated in Cantera 2.6; " + "accessible as number of rows of the coefficient matrix."); + return m_coeffs.nRows(); } //! Access the Chebyshev coefficients. @@ -579,7 +656,12 @@ class Chebyshev * @deprecated Behavior to change after Cantera 2.6. For new * behavior @see getCoeffs(). */ - const vector_fp& coeffs() const; + const vector_fp& coeffs() const + { + warn_deprecated("Chebyshev::coeffs", "Behavior to change after Cantera 2.6; " + "for new behavior, use getCoeffs()."); + return chebCoeffs_; + } //! Access Chebyshev coefficients as 2-dimensional array. const Array2D& getCoeffs() const @@ -591,14 +673,12 @@ class Chebyshev void setCoeffs(const Array2D& coeffs); protected: - double Tmin_, Tmax_; //!< valid temperature range - double Pmin_, Pmax_; //!< valid pressure range + std::pair m_Trange; //!< valid temperature range + std::pair m_Prange; //!< valid pressure range double TrNum_, TrDen_; //!< terms appearing in the reduced temperature double PrNum_, PrDen_; //!< terms appearing in the reduced pressure Array2D m_coeffs; //!<< coefficient array - size_t nP_; //!< number of points in the pressure direction - size_t nT_; //!< number of points in the temperature direction vector_fp chebCoeffs_; //!< Chebyshev coefficients, length nP * nT vector_fp dotProd_; //!< dot product of chebCoeffs with the reduced pressure polynomial }; diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index d9bb3ba800..f2047c579c 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -390,13 +390,9 @@ cdef extern from "cantera/kinetics/Reaction.h" namespace "Cantera": cdef cppclass CxxChebyshevRate3 "Cantera::ChebyshevRate3" (CxxReactionRateBase): CxxChebyshevRate3() CxxChebyshevRate3(CxxAnyMap) except +translate_exception - CxxChebyshevRate3(double, double, double, double, CxxArray2D) - double Tmin() - double Tmax() - double Pmin() - double Pmax() - size_t nPressure() - size_t nTemperature() + CxxChebyshevRate3(pair[double, double], pair[double, double], CxxArray2D) + pair[double, double] temperatureRange() + pair[double, double] pressureRange() CxxArray2D& coeffs() cdef cppclass CxxCustomFunc1Rate "Cantera::CustomFunc1Rate" (CxxReactionRateBase): @@ -472,14 +468,11 @@ cdef extern from "cantera/kinetics/Reaction.h" namespace "Cantera": CxxPlog rate cdef cppclass CxxChebyshev "Cantera::Chebyshev": - CxxChebyshev(double, double, double, double, CxxArray2D) - double Tmin() - double Tmax() - double Pmin() - double Pmax() - size_t nPressure() - size_t nTemperature() + CxxChebyshev(pair[double, double], pair[double, double], CxxArray2D) + pair[double, double] temperatureRange() + pair[double, double] pressureRange() vector[double]& coeffs() + CxxArray2D& getCoeffs() void update_C(double*) double updateRC(double, double) diff --git a/interfaces/cython/cantera/reaction.pyx b/interfaces/cython/cantera/reaction.pyx index 53badbbdef..6ef6bb0594 100644 --- a/interfaces/cython/cantera/reaction.pyx +++ b/interfaces/cython/cantera/reaction.pyx @@ -255,17 +255,24 @@ cdef class ChebyshevRate(ReactionRate): """ _reaction_rate_type = "Chebyshev" - def __cinit__(self, Tmin=None, Tmax=None, Pmin=None, Pmax=None, data=None, + def __cinit__(self, temperature_range=None, pressure_range=None, data=None, input_data=None, init=True): + cdef pair[double,double] Trange + cdef pair[double,double] Prange if init: if isinstance(input_data, dict): self._rate.reset(new CxxChebyshevRate3(dict_to_anymap(input_data))) - elif all([arg is not None for arg in [Tmin, Tmax, Pmin, Pmax, data]]): - self._rate.reset(new CxxChebyshevRate3(Tmin, Tmax, Pmin, Pmax, - self._cxxarray2d(data))) + elif all([arg is not None + for arg in [temperature_range, pressure_range, data]]): + Trange.first = temperature_range[0] + Trange.second = temperature_range[1] + Prange.first = pressure_range[0] + Prange.second = pressure_range[1] + self._rate.reset( + new CxxChebyshevRate3(Trange, Prange, self._cxxarray2d(data))) elif all([arg is None - for arg in [Tmin, Tmax, Pmin, Pmax, data, input_data]]): + for arg in [temperature_range, pressure_range, data, input_data]]): self._rate.reset(new CxxChebyshevRate3(dict_to_anymap({}))) elif input_data: raise TypeError("Invalid parameter 'input_data'") @@ -291,35 +298,17 @@ cdef class ChebyshevRate(ReactionRate): cdef CxxChebyshevRate3* cxx_object(self): return self.rate - property Tmin: - """ Minimum temperature [K] for the Chebyshev fit """ + property temperature_range: + """ Valid temperature range [K] for the Chebyshev fit """ def __get__(self): - return self.cxx_object().Tmin() + cdef pair[double,double] limits = self.cxx_object().temperatureRange() + return limits.first, limits.second - property Tmax: - """ Maximum temperature [K] for the Chebyshev fit """ - def __get__(self): - return self.cxx_object().Tmax() - - property Pmin: - """ Minimum pressure [Pa] for the Chebyshev fit """ + property pressure_range: + """ Valid pressure range [Pa] for the Chebyshev fit """ def __get__(self): - return self.cxx_object().Pmin() - - property Pmax: - """ Maximum pressure [Pa] for the Chebyshev fit """ - def __get__(self): - return self.cxx_object().Pmax() - - property n_pressure: - """ Number of pressures over which the Chebyshev fit is computed """ - def __get__(self): - return self.cxx_object().nPressure() - - property n_temperature: - """ Number of temperatures over which the Chebyshev fit is computed """ - def __get__(self): - return self.cxx_object().nTemperature() + cdef pair[double,double] limits = self.cxx_object().pressureRange() + return limits.first, limits.second property coeffs: """ @@ -811,10 +800,14 @@ cdef class Reaction: def __str__(self): return self.equation - def _deprecation_warning(self, attr, what="property"): - return ("\n{} '{}' to be removed after Cantera 2.6.\nThis {} is moved to " - "the {} object accessed via the 'rate' property." - ).format(what.capitalize(), attr, what, type(self.rate).__name__) + def _deprecation_warning(self, attr, what="property", new=None): + if new: + return (f"\n{what.capitalize()} '{attr}' to be removed after Cantera 2.6.\n" + f"This {what} is moved to the {type(self.rate).__name__} object " + f"accessed via the 'rate' property as '{new}'.") + return (f"\n{what.capitalize()} '{attr}' to be removed after Cantera 2.6.\n" + f"This {what} is moved to the {type(self.rate).__name__} object accessed " + "via the 'rate' property.") property uses_legacy: """Indicate whether reaction uses a legacy implementation""" @@ -1447,8 +1440,8 @@ cdef class ChebyshevReaction(Reaction): rxn = ChebyshevReaction( equation="HO2 <=> OH + O", - rate={"Tmin": 290.0, "Tmax": 3000.0, - "Pmin": 1e3, "Pmax": 1e8, + rate={"temperature-range": [290.0, 3000.0], + "pressure-range": [1e3, 1e8], "data": [[8.2883, -1.1397, -0.12059, 0.016034], [1.9764, 1.0037, 7.2865e-03, -0.030432], [0.3177, 0.26889, 0.094806, -7.6385e-03]]}, @@ -1489,9 +1482,8 @@ cdef class ChebyshevReaction(Reaction): rxn_type += "-legacy" spec = {"equation": equation, "type": rxn_type} if isinstance(rate, dict): - spec["temperature-range"] = [rate["Tmin"], rate["Tmax"]] - spec["pressure-range"] = [rate["Pmin"], rate["Pmax"]] - spec["data"] = rate["data"] + for key, value in rate.items(): + spec[key.replace("_", "-")] = value elif not legacy and (isinstance(rate, ChebyshevRate) or rate is None): pass else: @@ -1521,14 +1513,17 @@ cdef class ChebyshevReaction(Reaction): .. deprecated:: 2.6 To be deprecated with version 2.6, and removed thereafter. - Replaced by property `ChebyshevRate.Tmin`. + Replaced by property `ChebyshevRate.temperature_range[0]`. """ def __get__(self): if self.uses_legacy: - return self.cxx_object2().rate.Tmin() + return self.cxx_object2().rate.temperatureRange().first - warnings.warn(self._deprecation_warning("Tmin"), DeprecationWarning) - return self.rate.Tmin + warnings.warn( + self._deprecation_warning( + "Tmin", new="ChebyshevRate.temperature_range[0]"), + DeprecationWarning) + return self.rate.temperature_range[0] property Tmax: """ @@ -1536,14 +1531,17 @@ cdef class ChebyshevReaction(Reaction): .. deprecated:: 2.6 To be deprecated with version 2.6, and removed thereafter. - Replaced by property `ChebyshevRate.Tmax`. + Replaced by property `ChebyshevRate.temperature_range[1]`. """ def __get__(self): if self.uses_legacy: - return self.cxx_object2().rate.Tmax() + return self.cxx_object2().rate.temperatureRange().second - warnings.warn(self._deprecation_warning("Tmax"), DeprecationWarning) - return self.rate.Tmax + warnings.warn( + self._deprecation_warning( + "Tmax", new="ChebyshevRate.temperature_range[1]"), + DeprecationWarning) + return self.rate.temperature_range[1] property Pmin: """ @@ -1551,28 +1549,34 @@ cdef class ChebyshevReaction(Reaction): .. deprecated:: 2.6 To be deprecated with version 2.6, and removed thereafter. - Replaced by property `ChebyshevRate.Pmin`. + Replaced by property `ChebyshevRate.pressure_range[0]`. """ def __get__(self): if self.uses_legacy: - return self.cxx_object2().rate.Pmin() + return self.cxx_object2().rate.pressureRange().first - warnings.warn(self._deprecation_warning("Pmin"), DeprecationWarning) - return self.rate.Pmin + warnings.warn( + self._deprecation_warning( + "Pmin", new="ChebyshevRate.pressure_range[0]"), + DeprecationWarning) + return self.rate.pressure_range[0] property Pmax: """ Maximum pressure [Pa] for the Chebyshev fit .. deprecated:: 2.6 To be deprecated with version 2.6, and removed thereafter. - Replaced by property `ChebyshevRate.Pmax`. + Replaced by property `ChebyshevRate.pressure_range[1]`. """ def __get__(self): if self.uses_legacy: - return self.cxx_object2().rate.Pmax() + return self.cxx_object2().rate.pressureRange().second - warnings.warn(self._deprecation_warning("Pmax"), DeprecationWarning) - return self.rate.Pmax + warnings.warn( + self._deprecation_warning( + "Pmax", new="ChebyshevRate.pressure_range[0]"), + DeprecationWarning) + return self.rate.pressure_range[1] property nPressure: """ @@ -1580,14 +1584,17 @@ cdef class ChebyshevReaction(Reaction): .. deprecated:: 2.6 To be deprecated with version 2.6, and removed thereafter. - Replaced by property `ChebyshevRate.nPressure`. + Accessible as number of columns of `ChebyshevRate.coeffs`. """ def __get__(self): if self.uses_legacy: - return self.cxx_object2().rate.nPressure() + return self.cxx_object2().rate.getCoeffs().nColumns() - warnings.warn(self._deprecation_warning("nPressure"), DeprecationWarning) - return self.rate.n_pressure + warnings.warn( + self._deprecation_warning( + "nPressure", new="ChebyshevRate.coeffs.shape[1]"), + DeprecationWarning) + return self.rate.coeffs.shape[1] property nTemperature: """ @@ -1595,20 +1602,23 @@ cdef class ChebyshevReaction(Reaction): .. deprecated:: 2.6 To be deprecated with version 2.6, and removed thereafter. - Replaced by property `ChebyshevRate.nTemperature`. + Accessible as number of rows of `ChebyshevRate.coeffs`. """ def __get__(self): if self.uses_legacy: - return self.cxx_object2().rate.nTemperature() + return self.cxx_object2().rate.getCoeffs().nRows() warnings.warn( - self._deprecation_warning("nTemperature"), DeprecationWarning) - return self.rate.n_temperature + self._deprecation_warning( + "nTemperature", new="ChebyshevRate.coeffs.shape[0]"), + DeprecationWarning) + return self.rate.coeffs.shape[0] cdef _legacy_get_coeffs(self): cdef CxxChebyshevReaction2* r = self.cxx_object2() - c = np.fromiter(r.rate.coeffs(), np.double) - return c.reshape((r.rate.nTemperature(), r.rate.nPressure())) + cdef CxxArray2D cxxcoeffs = r.rate.getCoeffs() + c = np.fromiter(cxxcoeffs.data(), np.double) + return c.reshape(cxxcoeffs.nRows(), cxxcoeffs.nColumns(), order="F") property coeffs: """ @@ -1637,7 +1647,11 @@ cdef class ChebyshevReaction(Reaction): for j, value in enumerate(row): CxxArray2D_set(data, i, j, value) - r.rate = CxxChebyshev(Tmin, Tmax, Pmin, Pmax, data) + cdef pair[double,double] Trange + Trange.first, Trange.second = Tmin, Tmax + cdef pair[double,double] Prange + Prange.first, Prange.second = Pmin, Pmax + r.rate = CxxChebyshev(Trange, Prange, data) def set_parameters(self, Tmin, Tmax, Pmin, Pmax, coeffs): """ @@ -1654,7 +1668,11 @@ cdef class ChebyshevReaction(Reaction): warnings.warn("Method 'set_parameters' to be removed after Cantera 2.6. " "Method is replaceable by assigning a new 'ChebyshevRate' object to the " "rate property.", DeprecationWarning) - self.rate = ChebyshevRate(Tmin, Tmax, Pmin, Pmax, coeffs) + cdef pair[double,double] Trange + Trange.first, Trange.second = Tmin, Tmax + cdef pair[double,double] Prange + Prange.first, Prange.second = Pmin, Pmax + self.rate = ChebyshevRate(Trange, Prange, coeffs) cdef _legacy_call(self, float T, float P): cdef CxxChebyshevReaction2* r = self.cxx_object2() diff --git a/src/kinetics/Reaction.cpp b/src/kinetics/Reaction.cpp index 2a9f1c30ce..d862adfff1 100644 --- a/src/kinetics/Reaction.cpp +++ b/src/kinetics/Reaction.cpp @@ -1627,11 +1627,10 @@ void setupChebyshevReaction(ChebyshevReaction2& R, const XML_Node& rxn_node) coeffs(t,p) = coeffs_flat[nP*t + p]; } } - R.rate = Chebyshev(getFloat(rc, "Tmin", "toSI"), - getFloat(rc, "Tmax", "toSI"), - getFloat(rc, "Pmin", "toSI"), - getFloat(rc, "Pmax", "toSI"), - coeffs); + R.rate = Chebyshev( + std::make_pair(getFloat(rc, "Tmin", "toSI"), getFloat(rc, "Tmax", "toSI")), + std::make_pair(getFloat(rc, "Pmin", "toSI"), getFloat(rc, "Pmax", "toSI")), + coeffs); setupReaction(R, rxn_node); } @@ -1656,11 +1655,12 @@ void setupChebyshevReaction(ChebyshevReaction2&R, const AnyMap& node, } const UnitSystem& units = node.units(); coeffs(0, 0) += std::log10(units.convertTo(1.0, R.rate_units)); - R.rate = Chebyshev(units.convert(T_range[0], "K"), - units.convert(T_range[1], "K"), - units.convert(P_range[0], "Pa"), - units.convert(P_range[1], "Pa"), - coeffs); + R.rate = Chebyshev( + std::make_pair( + units.convert(T_range[0], "K"), units.convert(T_range[1], "K")), + std::make_pair( + units.convert(P_range[0], "Pa"), units.convert(P_range[1], "Pa")), + coeffs); } void setupInterfaceReaction(InterfaceReaction& R, const XML_Node& rxn_node) diff --git a/src/kinetics/ReactionRate.cpp b/src/kinetics/ReactionRate.cpp index c490829411..99778a0239 100644 --- a/src/kinetics/ReactionRate.cpp +++ b/src/kinetics/ReactionRate.cpp @@ -148,9 +148,10 @@ void PlogRate::getParameters(AnyMap& rateNode, const Units& rate_units) const rateNode["type"] = type(); } -ChebyshevRate3::ChebyshevRate3(double Tmin, double Tmax, double Pmin, double Pmax, - const Array2D& coeffs) - : Chebyshev(Tmin, Tmax, Pmin, Pmax, coeffs) +ChebyshevRate3::ChebyshevRate3( + const std::pair Trange, + const std::pair Prange, + const Array2D& coeffs) : Chebyshev(Trange, Prange, coeffs) { } diff --git a/src/kinetics/RxnRates.cpp b/src/kinetics/RxnRates.cpp index cb62676359..c7c8abdb32 100644 --- a/src/kinetics/RxnRates.cpp +++ b/src/kinetics/RxnRates.cpp @@ -5,7 +5,6 @@ #include "cantera/kinetics/RxnRates.h" #include "cantera/base/AnyMap.h" -#include "cantera/base/global.h" namespace Cantera { @@ -274,10 +273,21 @@ std::vector > Plog::rates() const return R; } +Chebyshev::Chebyshev( + const std::pair Trange, + const std::pair Prange, + const Array2D& coeffs) +{ + setLimits(Trange, Prange); + setCoeffs(coeffs); +} + Chebyshev::Chebyshev(double Tmin, double Tmax, double Pmin, double Pmax, const Array2D& coeffs) { - setLimits(Tmin, Tmax, Pmin, Pmax); + warn_deprecated("Chebyshev", "Deprecated in Cantera 2.6; " + "replaceable with constructor using pairs for range input."); + setLimits(std::make_pair(Tmin, Tmax), std::make_pair(Pmin, Pmax)); setCoeffs(coeffs); } @@ -303,13 +313,15 @@ void Chebyshev::setParameters(const AnyMap& node, coeffs(0, 0) += std::log10(units.convertTo(1.0, rate_units)); } setLimits( - units.convert(T_range[0], "K"), units.convert(T_range[1], "K"), - units.convert(P_range[0], "Pa"), units.convert(P_range[1], "Pa")); + std::make_pair( + units.convert(T_range[0], "K"), units.convert(T_range[1], "K")), + std::make_pair( + units.convert(P_range[0], "Pa"), units.convert(P_range[1], "Pa"))); } else { // ensure that reaction rate can be evaluated (but returns NaN) coeffs = Array2D(1, 1); coeffs(0, 0) = NAN; - setLimits(290., 3000., 1.e-7, 1.e14); + setLimits(std::make_pair(290., 3000.), std::make_pair(1.e-7, 1.e14)); } setCoeffs(coeffs); @@ -320,46 +332,37 @@ void Chebyshev::setup(double Tmin, double Tmax, double Pmin, double Pmax, { warn_deprecated("Chebyshev::setup", "Deprecated in Cantera 2.6; " "replaceable with setLimits() and setCoeffs()."); - setLimits(Tmin, Tmax, Pmin, Pmax); + setLimits(std::make_pair(Tmin, Tmax), std::make_pair(Pmin, Pmax)); setCoeffs(coeffs); } -void Chebyshev::setLimits(double Tmin, double Tmax, double Pmin, double Pmax) +void Chebyshev::setLimits( + const std::pair Trange, + const std::pair Prange) { - double logPmin = std::log10(Pmin); - double logPmax = std::log10(Pmax); - double TminInv = 1.0 / Tmin; - double TmaxInv = 1.0 / Tmax; + double logPmin = std::log10(Prange.first); + double logPmax = std::log10(Prange.second); + double TminInv = 1.0 / Trange.first; + double TmaxInv = 1.0 / Trange.second; TrNum_ = - TminInv - TmaxInv; TrDen_ = 1.0 / (TmaxInv - TminInv); PrNum_ = - logPmin - logPmax; PrDen_ = 1.0 / (logPmax - logPmin); - Tmin_ = Tmin; - Tmax_ = Tmax; - Pmin_ = Pmin; - Pmax_ = Pmax; -} - -const vector_fp& Chebyshev::coeffs() const -{ - warn_deprecated("Chebyshev::coeffs", "Behavior to change after Cantera 2.6; " - "for new behavior, use getCoeffs()."); - return chebCoeffs_; + m_Trange = Trange; + m_Prange = Prange; } void Chebyshev::setCoeffs(const Array2D& coeffs) { - m_coeffs = Array2D(coeffs); - nP_ = coeffs.nColumns(); - nT_ = coeffs.nRows(); - dotProd_.resize(nT_); + m_coeffs = coeffs; + dotProd_.resize(coeffs.nRows()); // convert to row major for legacy output // note: chebCoeffs_ is not used internally - size_t rows = nT_; - size_t cols = nP_; + size_t rows = m_coeffs.nRows(); + size_t cols = m_coeffs.nColumns(); chebCoeffs_.resize(rows * cols); for (size_t i = 0; i < rows; i++) { for (size_t j = 0; j < cols; j++) { @@ -374,8 +377,10 @@ void Chebyshev::getParameters(AnyMap& rateNode, const Units& rate_units) const // Return empty/unmodified AnyMap return; } - rateNode["temperature-range"].setQuantity({Tmin(), Tmax()}, "K"); - rateNode["pressure-range"].setQuantity({Pmin(), Pmax()}, "Pa"); + rateNode["temperature-range"].setQuantity( + {temperatureRange().first, temperatureRange().second}, "K"); + rateNode["pressure-range"].setQuantity( + {pressureRange().first, pressureRange().second}, "Pa"); size_t nT = m_coeffs.nRows(); size_t nP = m_coeffs.nColumns(); std::vector coeffs2d(nT, vector_fp(nP)); From 2ac8e8ce1fe71591a9002a9ed8aa6b3b319e754c Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Sat, 4 Sep 2021 14:08:15 -0500 Subject: [PATCH 18/28] [Unittest] Update Chebyshev tests --- .../cython/cantera/test/test_kinetics.py | 16 +++++++++----- .../cython/cantera/test/test_reaction.py | 21 +++++++++---------- test/kinetics/kineticsFromScratch.cpp | 3 ++- test/kinetics/kineticsFromScratch3.cpp | 3 ++- test/kinetics/kineticsFromYaml.cpp | 11 +++++----- 5 files changed, 31 insertions(+), 23 deletions(-) diff --git a/interfaces/cython/cantera/test/test_kinetics.py b/interfaces/cython/cantera/test/test_kinetics.py index 359e5ecc56..82b3682e6d 100644 --- a/interfaces/cython/cantera/test/test_kinetics.py +++ b/interfaces/cython/cantera/test/test_kinetics.py @@ -1131,7 +1131,9 @@ def test_chebyshev(self): r = ct.ChebyshevReaction() r.reactants = 'R5:1, H:1' r.products = 'P5A:1, P5B:1' - r.rate = ct.ChebyshevRate(Tmin=300.0, Tmax=2000.0, Pmin=1000, Pmax=10000000, + r.rate = ct.ChebyshevRate( + temperature_range=(300.0, 2000.0), + pressure_range=(1000, 10000000), data=[[ 5.28830e+00, -1.13970e+00, -1.20590e-01, 1.60340e-02], [ 1.97640e+00, 1.00370e+00, 7.28650e-03, -3.04320e-02], [ 3.17700e-01, 2.68890e-01, 9.48060e-02, -7.63850e-03], @@ -1154,7 +1156,9 @@ def test_chebyshev_single_P(self): r = ct.ChebyshevReaction() r.reactants = 'R5:1, H:1' r.products = 'P5A:1, P5B:1' - r.rate = ct.ChebyshevRate(Tmin=300.0, Tmax=2000.0, Pmin=1000, Pmax=10000000, + r.rate = ct.ChebyshevRate( + temperature_range=(300.0, 2000.0), + pressure_range=(1000, 10000000), data=[[ 5.28830e+00], [ 1.97640e+00], [ 3.17700e-01], @@ -1176,7 +1180,9 @@ def test_chebyshev_single_T(self): r = ct.ChebyshevReaction() r.reactants = 'R5:1, H:1' r.products = 'P5A:1, P5B:1' - r.rate = ct.ChebyshevRate(Tmin=300.0, Tmax=2000.0, Pmin=1000, Pmax=10000000, + r.rate = ct.ChebyshevRate( + temperature_range=(300.0, 2000.0), + pressure_range=(1000, 10000000), data=[[ 5.28830e+00, -1.13970e+00, -1.20590e-01, 1.60340e-02]]) gas = ct.Solution(thermo='IdealGas', kinetics='GasKinetics', @@ -1451,8 +1457,8 @@ def test_modify_chebyshev(self): r1 = gas.reaction(4) r2 = gas.reaction(5) - r1.rate = ct.ChebyshevRate(r2.rate.Tmin, r2.rate.Tmax, - r2.rate.Pmin, r2.rate.Pmax, r2.rate.coeffs) + r1.rate = ct.ChebyshevRate( + r2.rate.temperature_range, r2.rate.pressure_range, r2.rate.coeffs) # rates should be different before calling 'modify_reaction' kf = gas.forward_rate_constants diff --git a/interfaces/cython/cantera/test/test_reaction.py b/interfaces/cython/cantera/test/test_reaction.py index d7d79c5538..2a071a1294 100644 --- a/interfaces/cython/cantera/test/test_reaction.py +++ b/interfaces/cython/cantera/test/test_reaction.py @@ -330,19 +330,17 @@ class TestChebyshevRate(ReactionRateTests, utilities.CanteraTest): """ def setUp(self): - self.Tmin = self.gas.reaction(self._index).rate.Tmin - self.Tmax = self.gas.reaction(self._index).rate.Tmax - self.Pmin = self.gas.reaction(self._index).rate.Pmin - self.Pmax = self.gas.reaction(self._index).rate.Pmax + self.Trange = self.gas.reaction(self._index).rate.temperature_range + self.Prange = self.gas.reaction(self._index).rate.pressure_range self.coeffs = self.gas.reaction(self._index).rate.coeffs - self.rate = ct.ChebyshevRate(self.Tmin, self.Tmax, self.Pmin, self.Pmax, self.coeffs) + self.rate = ct.ChebyshevRate(self.Trange, self.Prange, self.coeffs) def test_parameters(self): # test getters for rate properties - self.assertEqual(self.Tmin, self.rate.Tmin) - self.assertEqual(self.Tmax, self.rate.Tmax) - self.assertEqual(self.Pmin, self.rate.Pmin) - self.assertEqual(self.Pmax, self.rate.Pmax) + self.assertEqual(self.Trange[0], self.rate.temperature_range[0]) + self.assertEqual(self.Trange[1], self.rate.temperature_range[1]) + self.assertEqual(self.Prange[0], self.rate.pressure_range[0]) + self.assertEqual(self.Prange[1], self.rate.pressure_range[1]) self.assertTrue(np.all(self.coeffs == self.rate.coeffs)) @@ -786,7 +784,7 @@ class TestChebyshev(ReactionTests, utilities.CanteraTest): _cls = ct.ChebyshevReaction _type = "Chebyshev" _equation = "HO2 <=> OH + O" - _rate = {"Tmin": 290., "Tmax": 3000., "Pmin": 1000., "Pmax": 10000000.0, + _rate = {"temperature_range": (290., 3000.), "pressure_range": (1000., 10000000.0), "data": [[ 8.2883e+00, -1.1397e+00, -1.2059e-01, 1.6034e-02], [ 1.9764e+00, 1.0037e+00, 7.2865e-03, -3.0432e-02], [ 3.1770e-01, 2.6889e-01, 9.4806e-02, -7.6385e-03]]} @@ -811,7 +809,8 @@ def setUpClass(cls): cls._rate_obj = ct.ChebyshevRate(**cls._rate) cls._deprecated_getters.update({"coeffs": np.array(cls._rate["data"])}) cls._deprecated_getters.update( - {k: v for k, v in cls._rate.items() if k != "data"}) + {k: v for k, v in cls._rate.items() + if k not in ["data", "temperature_range", "pressure_range"]}) class TestChebyshev2(TestChebyshev): diff --git a/test/kinetics/kineticsFromScratch.cpp b/test/kinetics/kineticsFromScratch.cpp index 767a1d672d..f9a6eb1cfc 100644 --- a/test/kinetics/kineticsFromScratch.cpp +++ b/test/kinetics/kineticsFromScratch.cpp @@ -187,7 +187,8 @@ TEST_F(KineticsFromScratch, add_chebyshev_reaction) coeffs(2,1) = 2.6889e-01; coeffs(2,2) = 9.4806e-02; coeffs(2,3) = -7.6385e-03; - Chebyshev rate(290, 3000, 1000.0, 10000000.0, coeffs); + Chebyshev rate( + std::make_pair(290., 3000.), std::make_pair(1000.0, 10000000.0), coeffs); auto R = make_shared(reac, prod, rate); kin.addReaction(R); diff --git a/test/kinetics/kineticsFromScratch3.cpp b/test/kinetics/kineticsFromScratch3.cpp index 603a2d2414..29f75e4d1e 100644 --- a/test/kinetics/kineticsFromScratch3.cpp +++ b/test/kinetics/kineticsFromScratch3.cpp @@ -167,7 +167,8 @@ TEST_F(KineticsFromScratch3, add_chebyshev_reaction) coeffs(2,1) = 2.6889e-01; coeffs(2,2) = 9.4806e-02; coeffs(2,3) = -7.6385e-03; - ChebyshevRate3 rate(290, 3000, 1000.0, 10000000.0, coeffs); + ChebyshevRate3 rate( + std::make_pair(290., 3000.), std::make_pair(1000.0, 10000000.0), coeffs); auto R = make_shared(reac, prod, rate); kin.addReaction(R); diff --git a/test/kinetics/kineticsFromYaml.cpp b/test/kinetics/kineticsFromYaml.cpp index 7f889396a8..777c95ccd4 100644 --- a/test/kinetics/kineticsFromYaml.cpp +++ b/test/kinetics/kineticsFromYaml.cpp @@ -249,10 +249,10 @@ TEST(Reaction, ChebyshevFromYaml) double logP = std::log10(2e6); double T = 1800; rate->update_C(&logP); - EXPECT_EQ(rate->nTemperature(), (size_t) 6); - EXPECT_EQ(rate->nPressure(), (size_t) 4); - EXPECT_DOUBLE_EQ(rate->Tmax(), 3000); - EXPECT_DOUBLE_EQ(rate->Pmin(), 1000); + EXPECT_EQ(rate->coeffs().nRows(), (size_t) 6); + EXPECT_EQ(rate->coeffs().nColumns(), (size_t) 4); + EXPECT_DOUBLE_EQ(rate->temperatureRange().second, 3000); + EXPECT_DOUBLE_EQ(rate->pressureRange().first, 1000); EXPECT_NEAR(rate->updateRC(std::log(T), 1.0/T), 130512.2773948636, 1e-9); } @@ -627,7 +627,8 @@ TEST_F(ReactionToYaml, unconvertible2) Array2D coeffs(2, 2, 1.0); ChebyshevReaction2 R({{"H2", 1}, {"OH", 1}}, {{"H2O", 1}, {"H", 1}}, - Chebyshev(273, 3000, 1e2, 1e7, coeffs)); + Chebyshev(std::make_pair(273., 3000.), + std::make_pair(1.e2, 1.e7), coeffs)); UnitSystem U{"g", "cm", "mol"}; AnyMap params = R.parameters(); params.setUnits(U); From d9a446b7c9dcc9764c0684a53a8b28609196a6a0 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Mon, 23 Aug 2021 18:41:10 -0500 Subject: [PATCH 19/28] [Python] Make sparse API more efficient and deprecate *stoich methods Deprecate Kinetics.*_stoich_coeffs() method in favor of property: Behavior will change after Cantera 2.6; for new behavior, new properties Kinetics.*_stoich_coefficients are implemented --- include/cantera/cython/wrappers.h | 16 +-- interfaces/cython/cantera/_cantera.pxd | 20 ++- interfaces/cython/cantera/kinetics.pyx | 126 +++++++++++++----- .../cython/cantera/test/test_convert.py | 14 +- .../cython/cantera/test/test_kinetics.py | 24 ++-- 5 files changed, 131 insertions(+), 69 deletions(-) diff --git a/include/cantera/cython/wrappers.h b/include/cantera/cython/wrappers.h index bbf6621d49..8290de5f88 100644 --- a/include/cantera/cython/wrappers.h +++ b/include/cantera/cython/wrappers.h @@ -73,11 +73,10 @@ size_t sparseComponents(const Eigen::SparseMatrix& mat, return count; } -// Function which passes sparse matrix components to a set of 1D arrays -#define SPARSE_FUNC(PREFIX, CLASS_NAME, FUNC_NAME) \ - size_t PREFIX ## _ ## FUNC_NAME(Cantera::CLASS_NAME* object, \ - int* rows, int* cols, double* data, size_t length) \ - { return sparseComponents(object->FUNC_NAME(), rows, cols, data, length); } +// Function which passes sparse matrix +#define SPARSE_MATRIX(PREFIX, CLASS_NAME, FUNC_NAME) \ + Eigen::SparseMatrix PREFIX ## _ ## FUNC_NAME(Cantera::CLASS_NAME* object) \ + { return object->FUNC_NAME(); } // Function which populates a 1D array #define ARRAY_FUNC(PREFIX, CLASS_NAME, FUNC_NAME) \ @@ -92,7 +91,7 @@ size_t sparseComponents(const Eigen::SparseMatrix& mat, #define THERMO_1D(FUNC_NAME) ARRAY_FUNC(thermo, ThermoPhase, FUNC_NAME) #define KIN_1D(FUNC_NAME) ARRAY_FUNC(kin, Kinetics, FUNC_NAME) -#define KIN_SPARSE(FUNC_NAME) SPARSE_FUNC(kin, Kinetics, FUNC_NAME) +#define KIN_SPARSE_MATRIX(FUNC_NAME) SPARSE_MATRIX(kin, Kinetics, FUNC_NAME) #define TRANSPORT_1D(FUNC_NAME) ARRAY_FUNC(tran, Transport, FUNC_NAME) #define TRANSPORT_2D(FUNC_NAME) ARRAY_FUNC2(tran, Transport, FUNC_NAME) @@ -120,8 +119,9 @@ THERMO_1D(getCp_R) THERMO_1D(getActivities) THERMO_1D(getActivityCoefficients) -KIN_SPARSE(reactantStoichCoeffs) -KIN_SPARSE(productStoichCoeffs) +KIN_SPARSE_MATRIX(reactantStoichCoeffs) +KIN_SPARSE_MATRIX(productStoichCoeffs) +KIN_SPARSE_MATRIX(revProductStoichCoeffs) KIN_1D(getFwdRatesOfProgress) KIN_1D(getRevRatesOfProgress) diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index f2047c579c..de2d637d6b 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -43,6 +43,13 @@ cdef extern from "cantera/numerics/Func1.h": CxxTabulated1(int, double*, double*, string) except +translate_exception double eval(double) except +translate_exception +cdef extern from "cantera/numerics/eigen_sparse.h" namespace "Eigen": + cdef cppclass CxxSparseMatrix "Eigen::SparseMatrix": + CxxSparseMatrix() + size_t nonZeros() + size_t rows() + size_t cols() + cdef extern from "cantera/base/xml.h" namespace "Cantera": cdef cppclass XML_Node: XML_Node* findByName(string) @@ -1034,6 +1041,8 @@ cdef extern from "cantera/cython/wrappers.h": cdef void CxxSetLogger "setLogger" (CxxPythonLogger*) + cdef size_t CxxSparseComponents "sparseComponents" (CxxSparseMatrix, int*, int*, double*, size_t) except +translate_exception + # workaround for Cython assignment limitations cdef void CxxArray2D_set(CxxArray2D, size_t, size_t, double) @@ -1089,8 +1098,9 @@ cdef extern from "cantera/cython/wrappers.h": cdef void kin_getNetProductionRates(CxxKinetics*, double*) except +translate_exception # Kinetics sparse matrices - cdef size_t kin_reactantStoichCoeffs(CxxKinetics*, int*, int*, double*, size_t) except +translate_exception - cdef size_t kin_productStoichCoeffs(CxxKinetics*, int*, int*, double*, size_t) except +translate_exception + cdef CxxSparseMatrix kin_reactantStoichCoeffs(CxxKinetics*) except +translate_exception + cdef CxxSparseMatrix kin_productStoichCoeffs(CxxKinetics*) except +translate_exception + cdef CxxSparseMatrix kin_revProductStoichCoeffs(CxxKinetics*) except +translate_exception # Transport properties cdef void tran_getMixDiffCoeffs(CxxTransport*, double*) except +translate_exception @@ -1108,7 +1118,7 @@ ctypedef void (*thermoMethod1d)(CxxThermoPhase*, double*) except +translate_exce ctypedef void (*transportMethod1d)(CxxTransport*, double*) except +translate_exception ctypedef void (*transportMethod2d)(CxxTransport*, size_t, double*) except +translate_exception ctypedef void (*kineticsMethod1d)(CxxKinetics*, double*) except +translate_exception -ctypedef size_t (*kineticsMethodSparse)(CxxKinetics*, int*, int*, double*, size_t) except +translate_exception +ctypedef CxxSparseMatrix (*kineticsMethodSparse)(CxxKinetics*) except +translate_exception # classes cdef class SpeciesThermo: @@ -1356,8 +1366,8 @@ cdef string stringify(x) except * cdef pystr(string x) cdef np.ndarray get_species_array(Kinetics kin, kineticsMethod1d method) cdef np.ndarray get_reaction_array(Kinetics kin, kineticsMethod1d method) -cdef np.ndarray get_dense(Kinetics kin, kineticsMethodSparse method, size_t dim, tuple shape) -cdef tuple get_sparse(Kinetics kin, kineticsMethodSparse method, size_t dim) +cdef np.ndarray get_dense(Kinetics kin, kineticsMethodSparse method) +cdef tuple get_sparse(Kinetics kin, kineticsMethodSparse method) cdef np.ndarray get_transport_1d(Transport tran, transportMethod1d method) cdef np.ndarray get_transport_2d(Transport tran, transportMethod2d method) cdef CxxIdealGasPhase* getIdealGasPhase(ThermoPhase phase) except * diff --git a/interfaces/cython/cantera/kinetics.pyx b/interfaces/cython/cantera/kinetics.pyx index e7f53f030c..bcc4a8fde6 100644 --- a/interfaces/cython/cantera/kinetics.pyx +++ b/interfaces/cython/cantera/kinetics.pyx @@ -20,28 +20,33 @@ cdef np.ndarray get_reaction_array(Kinetics kin, kineticsMethod1d method): method(kin.kinetics, &data[0]) return data -cdef np.ndarray get_dense(Kinetics kin, kineticsMethodSparse method, - size_t max_dim, tuple shape): - cdef vector[int] rows - cdef vector[int] cols - cdef vector[double] data - cdef size_t size - rows.resize(max_dim) - cols.resize(max_dim) - data.resize(max_dim) - size = method(kin.kinetics, &rows[0], &cols[0], &data[0], max_dim) - - out = np.zeros(shape) - for i in xrange(size): +cdef np.ndarray get_dense(Kinetics kin, kineticsMethodSparse method): + cdef CxxSparseMatrix smat = method(kin.kinetics) + cdef size_t length = smat.nonZeros() + if length == 0: + return np.zeros((kin.n_reactions, 0)) + + cdef np.ndarray[int, ndim=1, mode="c"] rows = np.empty(length, dtype=c_int) + cdef np.ndarray[int, ndim=1, mode="c"] cols = np.empty(length, dtype=c_int) + cdef np.ndarray[np.double_t, ndim=1] data = np.empty(length) + + size = CxxSparseComponents(smat, &rows[0], &cols[0], &data[0], length) + out = np.zeros((smat.rows(), smat.cols())) + for i in xrange(length): out[rows[i], cols[i]] = data[i] return out -cdef tuple get_sparse(Kinetics kin, kineticsMethodSparse method, size_t max_dim): - cdef np.ndarray[int, ndim=1, mode="c"] rows = np.empty(max_dim, dtype=c_int) - cdef np.ndarray[int, ndim=1, mode="c"] cols = np.empty(max_dim, dtype=c_int) - cdef np.ndarray[np.double_t, ndim=1] data = np.empty(max_dim) - size = method(kin.kinetics, &rows[0], &cols[0], &data[0], max_dim) - return data[:size], tuple([rows[:size], cols[:size]]) +cdef tuple get_sparse(Kinetics kin, kineticsMethodSparse method): + cdef CxxSparseMatrix smat = method(kin.kinetics) + cdef size_t length = smat.nonZeros() + + cdef np.ndarray[int, ndim=1, mode="c"] rows = np.empty(length, dtype=c_int) + cdef np.ndarray[int, ndim=1, mode="c"] cols = np.empty(length, dtype=c_int) + cdef np.ndarray[np.double_t, ndim=1] data = np.empty(length) + + if length > 0: + size = CxxSparseComponents(smat, &rows[0], &cols[0], &data[0], length) + return data, tuple([rows, cols]) cdef class Kinetics(_SolutionBase): @@ -235,8 +240,8 @@ cdef class Kinetics(_SolutionBase): def reactant_stoich_coeff(self, k_spec, int i_reaction): """ - The stoichiometric coefficient of species *k_spec* as a reactant in - reaction *i_reaction*. + The stoichiometric coefficient of species ``k_spec`` as a reactant in + reaction ``i_reaction``. """ cdef int k if isinstance(k_spec, (str, bytes)): @@ -250,8 +255,8 @@ cdef class Kinetics(_SolutionBase): def product_stoich_coeff(self, k_spec, int i_reaction): """ - The stoichiometric coefficient of species *k_spec* as a product in - reaction *i_reaction*. + The stoichiometric coefficient of species ``k_spec`` as a product in + reaction ``i_reaction``. """ cdef int k if isinstance(k_spec, (str, bytes)): @@ -268,28 +273,75 @@ cdef class Kinetics(_SolutionBase): The array of reactant stoichiometric coefficients. Element *[k,i]* of this array is the reactant stoichiometric coefficient of species *k* in reaction *i*. + + .. deprecated:: 2.6 + + Behavior to change after Cantera 2.6; for new behavior, see property + `Kinetics.reactant_stoich_coeffs3`. """ - cdef np.ndarray[np.double_t, ndim=2] data = np.empty((self.n_total_species, - self.n_reactions)) - cdef int i,k - for i in range(self.n_reactions): - for k in range(self.n_total_species): - data[k,i] = self.kinetics.reactantStoichCoeff(k,i) - return data + warnings.warn("Behavior to change after Cantera 2.6; for new behavior, see " + "property 'reactant_stoich_coeffs3'.", DeprecationWarning) + return self.reactant_stoich_coeffs3 + + property reactant_stoich_coeffs3: + """ + The array of reactant stoichiometric coefficients. Element ``[k,i]`` of + this array is the reactant stoichiometric coefficient of species ``k`` in + reaction ``i``. + + For sparse output, set ``ct.use_sparse(True)``. + """ + def __get__(self): + if __use_sparse__: + data, ix_ij = get_sparse(self, kin_reactantStoichCoeffs) + shape = self.n_total_species, self.n_reactions + return _scipy_sparse.coo_matrix((data, ix_ij), shape=shape) + return get_dense(self, kin_reactantStoichCoeffs) def product_stoich_coeffs(self): """ The array of product stoichiometric coefficients. Element *[k,i]* of this array is the product stoichiometric coefficient of species *k* in reaction *i*. + + .. deprecated:: 2.6 + + Behavior to change after Cantera 2.6; for new behavior, see property + `Kinetics.reactant_stoich_coeffs3`. """ - cdef np.ndarray[np.double_t, ndim=2] data = np.empty((self.n_total_species, - self.n_reactions)) - cdef int i,k - for i in range(self.n_reactions): - for k in range(self.n_total_species): - data[k,i] = self.kinetics.productStoichCoeff(k,i) - return data + warnings.warn("Behavior to change after Cantera 2.6; for new behavior, see " + "property 'product_stoich_coeffs3'.", DeprecationWarning) + return self.product_stoich_coeffs3 + + property product_stoich_coeffs3: + """ + The array of product stoichiometric coefficients. Element ``[k,i]`` of + this array is the product stoichiometric coefficient of species ``k`` in + reaction ``i``. + + For sparse output, set ``ct.use_sparse(True)``. + """ + def __get__(self): + if __use_sparse__: + data, ix_ij = get_sparse(self, kin_productStoichCoeffs) + shape = self.n_total_species, self.n_reactions + return _scipy_sparse.coo_matrix((data, ix_ij), shape=shape) + return get_dense(self, kin_productStoichCoeffs) + + property product_stoich_coeffs_reversible: + """ + The array of product stoichiometric coefficients of reversible reactions. + Element ``[k,i]`` of this array is the product stoichiometric coefficient + of species ``k`` in reaction ``i``. + + For sparse output, set ``ct.use_sparse(True)``. + """ + def __get__(self): + if __use_sparse__: + data, ix_ij = get_sparse(self, kin_revProductStoichCoeffs) + shape = self.n_total_species, self.n_reactions + return _scipy_sparse.coo_matrix((data, ix_ij), shape=shape) + return get_dense(self, kin_revProductStoichCoeffs) property forward_rates_of_progress: """ diff --git a/interfaces/cython/cantera/test/test_convert.py b/interfaces/cython/cantera/test/test_convert.py index 7ae4c87101..95432b8fbe 100644 --- a/interfaces/cython/cantera/test/test_convert.py +++ b/interfaces/cython/cantera/test/test_convert.py @@ -39,8 +39,8 @@ def checkConversion(self, refFile, testFile): self.assertEqual(ref.element_names, gas.element_names) self.assertEqual(ref.species_names, gas.species_names) - coeffs_ref = ref.reactant_stoich_coeffs() - coeffs_gas = gas.reactant_stoich_coeffs() + coeffs_ref = ref.reactant_stoich_coefficients + coeffs_gas = gas.reactant_stoich_coefficients self.assertEqual(coeffs_gas.shape, coeffs_ref.shape) self.assertTrue((coeffs_gas == coeffs_ref).all()) @@ -154,7 +154,7 @@ def test_pathologicalSpeciesNames(self): self.assertEqual(gas.species_name(8), 'co') self.assertEqual(gas.n_reactions, 12) - nu = gas.product_stoich_coeffs() - gas.reactant_stoich_coeffs() + nu = gas.product_stoich_coefficients - gas.reactant_stoich_coefficients self.assertEqual(list(nu[:,0]), [-1, -1, 0, 2, 0, 0, 0, 0, 0]) self.assertEqual(list(nu[:,1]), [-2, 3, 0, -1, 0, 0, 0, 0, 0]) self.assertEqual(list(nu[:,2]), [-1, 0, 0, 0, 1, 0, 0, 0, 0]) @@ -233,8 +233,8 @@ def test_explicit_reverse_rate(self): self.assertEqual(Rr[2], 0.0) self.assertEqual(Rr[3], 0.0) self.assertEqual(Rr[4], 0.0) - Rstoich = gas.reactant_stoich_coeffs() - Pstoich = gas.product_stoich_coeffs() + Rstoich = gas.reactant_stoich_coefficients + Pstoich = gas.product_stoich_coefficients self.assertEqual(list(Rstoich[:, 0]), list(Pstoich[:, 1])) self.assertEqual(list(Rstoich[:, 1]), list(Pstoich[:, 0])) self.assertEqual(list(Rstoich[:, 2]), list(Pstoich[:, 3])) @@ -289,8 +289,8 @@ def test_float_stoich_coeffs(self): output = self.convert('float-stoich.inp', thermo='dummy-thermo.dat') gas = ct.Solution(output) - R = gas.reactant_stoich_coeffs() - P = gas.product_stoich_coeffs() + R = gas.reactant_stoich_coefficients + P = gas.product_stoich_coefficients self.assertArrayNear(R[:,0], [0, 1.5, 0.5, 0]) self.assertArrayNear(P[:,0], [1, 0, 0, 1]) self.assertArrayNear(R[:,1], [1, 0, 0, 1]) diff --git a/interfaces/cython/cantera/test/test_kinetics.py b/interfaces/cython/cantera/test/test_kinetics.py index 82b3682e6d..a49c76e009 100644 --- a/interfaces/cython/cantera/test/test_kinetics.py +++ b/interfaces/cython/cantera/test/test_kinetics.py @@ -98,8 +98,8 @@ def test_reactants_products(self): self.assertIn(self.phase.species_name(k), P) def test_stoich_coeffs(self): - nu_r = self.phase.reactant_stoich_coeffs() - nu_p = self.phase.product_stoich_coeffs() + nu_r = self.phase.reactant_stoich_coefficients + nu_p = self.phase.product_stoich_coefficients def check_reactant(s, i, value): k = self.phase.kinetics_species_index(s) @@ -149,8 +149,8 @@ def test_rate_constants(self): self.phase.equilibrium_constants[ix]) def test_species_rates(self): - nu_p = self.phase.product_stoich_coeffs() - nu_r = self.phase.reactant_stoich_coeffs() + nu_p = self.phase.product_stoich_coefficients + nu_r = self.phase.reactant_stoich_coefficients creation = (np.dot(nu_p, self.phase.forward_rates_of_progress) + np.dot(nu_r, self.phase.reverse_rates_of_progress)) destruction = (np.dot(nu_r, self.phase.forward_rates_of_progress) + @@ -187,10 +187,10 @@ def test_idealgas(self): gas1.TPY = 800, 2*ct.one_atm, 'H2:0.3, O2:0.7, OH:2e-4, O:1e-3, H:5e-5' gas2.TPY = gas1.TPY - self.assertTrue((gas1.reactant_stoich_coeffs() == - gas2.reactant_stoich_coeffs()).all()) - self.assertTrue((gas1.product_stoich_coeffs() == - gas2.product_stoich_coeffs()).all()) + self.assertTrue((gas1.reactant_stoich_coefficients == + gas2.reactant_stoich_coefficients).all()) + self.assertTrue((gas1.product_stoich_coefficients == + gas2.product_stoich_coefficients).all()) self.assertArrayNear(gas1.delta_gibbs, gas2.delta_gibbs) @@ -265,10 +265,10 @@ def test_add_reaction(self): self.assertEqual(gas1.n_reactions, gas2.n_reactions) - self.assertTrue((gas1.reactant_stoich_coeffs() == - gas2.reactant_stoich_coeffs()).all()) - self.assertTrue((gas1.product_stoich_coeffs() == - gas2.product_stoich_coeffs()).all()) + self.assertTrue((gas1.reactant_stoich_coefficients == + gas2.reactant_stoich_coefficients).all()) + self.assertTrue((gas1.product_stoich_coefficients == + gas2.product_stoich_coefficients).all()) self.assertArrayNear(gas1.delta_gibbs, gas2.delta_gibbs) From 5ff68c3ee114d359d276c470ba32004d9fd5ea69 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Mon, 23 Aug 2021 20:05:58 -0500 Subject: [PATCH 20/28] [Unittest] Add test for sparse matrix output --- .../cython/cantera/test/test_convert.py | 14 +++--- .../cython/cantera/test/test_kinetics.py | 47 ++++++++++++++----- 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/interfaces/cython/cantera/test/test_convert.py b/interfaces/cython/cantera/test/test_convert.py index 95432b8fbe..61fd2a25fd 100644 --- a/interfaces/cython/cantera/test/test_convert.py +++ b/interfaces/cython/cantera/test/test_convert.py @@ -39,8 +39,8 @@ def checkConversion(self, refFile, testFile): self.assertEqual(ref.element_names, gas.element_names) self.assertEqual(ref.species_names, gas.species_names) - coeffs_ref = ref.reactant_stoich_coefficients - coeffs_gas = gas.reactant_stoich_coefficients + coeffs_ref = ref.reactant_stoich_coeffs3 + coeffs_gas = gas.reactant_stoich_coeffs3 self.assertEqual(coeffs_gas.shape, coeffs_ref.shape) self.assertTrue((coeffs_gas == coeffs_ref).all()) @@ -154,7 +154,7 @@ def test_pathologicalSpeciesNames(self): self.assertEqual(gas.species_name(8), 'co') self.assertEqual(gas.n_reactions, 12) - nu = gas.product_stoich_coefficients - gas.reactant_stoich_coefficients + nu = gas.product_stoich_coeffs3 - gas.reactant_stoich_coeffs3 self.assertEqual(list(nu[:,0]), [-1, -1, 0, 2, 0, 0, 0, 0, 0]) self.assertEqual(list(nu[:,1]), [-2, 3, 0, -1, 0, 0, 0, 0, 0]) self.assertEqual(list(nu[:,2]), [-1, 0, 0, 0, 1, 0, 0, 0, 0]) @@ -233,8 +233,8 @@ def test_explicit_reverse_rate(self): self.assertEqual(Rr[2], 0.0) self.assertEqual(Rr[3], 0.0) self.assertEqual(Rr[4], 0.0) - Rstoich = gas.reactant_stoich_coefficients - Pstoich = gas.product_stoich_coefficients + Rstoich = gas.reactant_stoich_coeffs3 + Pstoich = gas.product_stoich_coeffs3 self.assertEqual(list(Rstoich[:, 0]), list(Pstoich[:, 1])) self.assertEqual(list(Rstoich[:, 1]), list(Pstoich[:, 0])) self.assertEqual(list(Rstoich[:, 2]), list(Pstoich[:, 3])) @@ -289,8 +289,8 @@ def test_float_stoich_coeffs(self): output = self.convert('float-stoich.inp', thermo='dummy-thermo.dat') gas = ct.Solution(output) - R = gas.reactant_stoich_coefficients - P = gas.product_stoich_coefficients + R = gas.reactant_stoich_coeffs3 + P = gas.product_stoich_coeffs3 self.assertArrayNear(R[:,0], [0, 1.5, 0.5, 0]) self.assertArrayNear(P[:,0], [1, 0, 0, 1]) self.assertArrayNear(R[:,1], [1, 0, 0, 1]) diff --git a/interfaces/cython/cantera/test/test_kinetics.py b/interfaces/cython/cantera/test/test_kinetics.py index a49c76e009..9057b59c63 100644 --- a/interfaces/cython/cantera/test/test_kinetics.py +++ b/interfaces/cython/cantera/test/test_kinetics.py @@ -1,10 +1,19 @@ import numpy as np import re import itertools +import pkg_resources import cantera as ct from . import utilities +# avoid explicit dependence of cantera on scipy +try: + pkg_resources.get_distribution('scipy') +except pkg_resources.DistributionNotFound: + _scipy_sparse = ImportError('Method requires a working scipy installation.') +else: + from scipy import sparse as _scipy_sparse + class TestKinetics(utilities.CanteraTest): def setUp(self): @@ -98,8 +107,8 @@ def test_reactants_products(self): self.assertIn(self.phase.species_name(k), P) def test_stoich_coeffs(self): - nu_r = self.phase.reactant_stoich_coefficients - nu_p = self.phase.product_stoich_coefficients + nu_r = self.phase.reactant_stoich_coeffs3 + nu_p = self.phase.product_stoich_coeffs3 def check_reactant(s, i, value): k = self.phase.kinetics_species_index(s) @@ -130,6 +139,20 @@ def check_product(s, i, value): check_product('O', 0, 0) check_product('O2', 0, 1) + @utilities.unittest.skipIf(isinstance(_scipy_sparse, ImportError), "scipy is not installed") + def test_stoich_coeffs_sparse(self): + nu_r_dense = self.phase.reactant_stoich_coeffs3 + nu_p_dense = self.phase.product_stoich_coeffs3 + + ct.use_sparse(True) + nu_r_sparse = self.phase.reactant_stoich_coeffs3 + nu_p_sparse = self.phase.product_stoich_coeffs3 + + self.assertTrue((nu_r_sparse.toarray() == nu_r_dense).all()) + self.assertTrue((nu_p_sparse.toarray() == nu_p_dense).all()) + + ct.use_sparse(False) + def test_rates_of_progress(self): self.assertEqual(len(self.phase.net_rates_of_progress), self.phase.n_reactions) @@ -149,8 +172,8 @@ def test_rate_constants(self): self.phase.equilibrium_constants[ix]) def test_species_rates(self): - nu_p = self.phase.product_stoich_coefficients - nu_r = self.phase.reactant_stoich_coefficients + nu_p = self.phase.product_stoich_coeffs3 + nu_r = self.phase.reactant_stoich_coeffs3 creation = (np.dot(nu_p, self.phase.forward_rates_of_progress) + np.dot(nu_r, self.phase.reverse_rates_of_progress)) destruction = (np.dot(nu_r, self.phase.forward_rates_of_progress) + @@ -187,10 +210,10 @@ def test_idealgas(self): gas1.TPY = 800, 2*ct.one_atm, 'H2:0.3, O2:0.7, OH:2e-4, O:1e-3, H:5e-5' gas2.TPY = gas1.TPY - self.assertTrue((gas1.reactant_stoich_coefficients == - gas2.reactant_stoich_coefficients).all()) - self.assertTrue((gas1.product_stoich_coefficients == - gas2.product_stoich_coefficients).all()) + self.assertTrue((gas1.reactant_stoich_coeffs3 == + gas2.reactant_stoich_coeffs3).all()) + self.assertTrue((gas1.product_stoich_coeffs3 == + gas2.product_stoich_coeffs3).all()) self.assertArrayNear(gas1.delta_gibbs, gas2.delta_gibbs) @@ -265,10 +288,10 @@ def test_add_reaction(self): self.assertEqual(gas1.n_reactions, gas2.n_reactions) - self.assertTrue((gas1.reactant_stoich_coefficients == - gas2.reactant_stoich_coefficients).all()) - self.assertTrue((gas1.product_stoich_coefficients == - gas2.product_stoich_coefficients).all()) + self.assertTrue((gas1.reactant_stoich_coeffs3 == + gas2.reactant_stoich_coeffs3).all()) + self.assertTrue((gas1.product_stoich_coeffs3 == + gas2.product_stoich_coeffs3).all()) self.assertArrayNear(gas1.delta_gibbs, gas2.delta_gibbs) From 79e62d8519111325e801bdf146b79252d8eee7dd Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Sun, 5 Sep 2021 09:46:08 -0500 Subject: [PATCH 21/28] [Kinetics] Standardize Plog rates access This commit unifies parameter handling of Plog rate setters and getters to use std::multimap<...>. --- include/cantera/kinetics/RxnRates.h | 13 ++++++++++ interfaces/cython/cantera/_cantera.pxd | 4 +-- interfaces/cython/cantera/reaction.pyx | 6 ++--- src/kinetics/RxnRates.cpp | 35 ++++++++++++++++++-------- test/kinetics/kineticsFromYaml.cpp | 3 ++- 5 files changed, 44 insertions(+), 17 deletions(-) diff --git a/include/cantera/kinetics/RxnRates.h b/include/cantera/kinetics/RxnRates.h index 542872e531..d832c57c8d 100644 --- a/include/cantera/kinetics/RxnRates.h +++ b/include/cantera/kinetics/RxnRates.h @@ -347,8 +347,14 @@ class Plog void getParameters(AnyMap& rateNode, const Units& rate_units) const; //! Set up Plog object + /*! + * @deprecated Deprecated in Cantera 2.6. Renamed to setRates. + */ void setup(const std::multimap& rates); + //! Set up Plog object + void setRates(const std::multimap& rates); + //! Update concentration-dependent parts of the rate coefficient. //! @param c natural log of the pressure in Pa void update_C(const doublereal* c) { @@ -414,8 +420,15 @@ class Plog //! Return the pressures and Arrhenius expressions which comprise this //! reaction. + /*! + * @deprecated To be removed after Cantera 2.6. Replaceable by getRates. + */ std::vector > rates() const; + //! Return the pressures and Arrhenius expressions which comprise this + //! reaction. + std::multimap getRates() const; + protected: //! log(p) to (index range) in the rates_ vector std::map > pressures_; diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index de2d637d6b..bb750edcdc 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -392,7 +392,7 @@ cdef extern from "cantera/kinetics/Reaction.h" namespace "Cantera": CxxPlogRate() CxxPlogRate(CxxAnyMap) except +translate_exception CxxPlogRate(multimap[double, CxxArrhenius]) - vector[pair[double, CxxArrhenius]] rates() + multimap[double, CxxArrhenius] getRates() cdef cppclass CxxChebyshevRate3 "Cantera::ChebyshevRate3" (CxxReactionRateBase): CxxChebyshevRate3() @@ -467,7 +467,7 @@ cdef extern from "cantera/kinetics/Reaction.h" namespace "Cantera": cdef cppclass CxxPlog "Cantera::Plog": CxxPlog(multimap[double,CxxArrhenius]) - vector[pair[double,CxxArrhenius]] rates() + multimap[double, CxxArrhenius] getRates() void update_C(double*) double updateRC(double, double) diff --git a/interfaces/cython/cantera/reaction.pyx b/interfaces/cython/cantera/reaction.pyx index 6ef6bb0594..6599590273 100644 --- a/interfaces/cython/cantera/reaction.pyx +++ b/interfaces/cython/cantera/reaction.pyx @@ -228,9 +228,9 @@ cdef class PlogRate(ReactionRate): """ def __get__(self): rates = [] - cdef vector[pair[double, CxxArrhenius]] cxxrates + cdef multimap[double, CxxArrhenius] cxxrates cdef pair[double, CxxArrhenius] p_rate - cxxrates = self.cxx_object().rates() + cxxrates = self.cxx_object().getRates() for p_rate in cxxrates: rates.append((p_rate.first, copyArrhenius(&p_rate.second))) return rates @@ -1361,7 +1361,7 @@ cdef class PlogReaction(Reaction): cdef list _legacy_get_rates(self): cdef CxxPlogReaction2* r = self.cxx_object2() - cdef vector[pair[double,CxxArrhenius]] cxxrates = r.rate.rates() + cdef multimap[double,CxxArrhenius] cxxrates = r.rate.getRates() cdef pair[double,CxxArrhenius] p_rate rates = [] for p_rate in cxxrates: diff --git a/src/kinetics/RxnRates.cpp b/src/kinetics/RxnRates.cpp index c7c8abdb32..010c4d4d39 100644 --- a/src/kinetics/RxnRates.cpp +++ b/src/kinetics/RxnRates.cpp @@ -171,7 +171,7 @@ Plog::Plog() Plog::Plog(const std::multimap& rates) : Plog() { - setup(rates); + setRates(rates); } void Plog::setParameters(const std::vector& rates, @@ -188,7 +188,7 @@ void Plog::setParameters(const std::vector& rates, multi_rates.insert({1.e-7, Arrhenius(NAN, NAN, NAN)}); multi_rates.insert({1.e14, Arrhenius(NAN, NAN, NAN)}); } - setup(multi_rates); + setRates(multi_rates); } void Plog::getParameters(AnyMap& rateNode, const Units& rate_units) const @@ -199,7 +199,7 @@ void Plog::getParameters(AnyMap& rateNode, const Units& rate_units) const // Return empty/unmodified AnyMap return; } - for (const auto& r : rates()) { + for (const auto& r : getRates()) { AnyMap rateNode_; rateNode_["P"].setQuantity(r.first, "Pa"); r.second.getParameters(rateNode_, rate_units); @@ -209,6 +209,13 @@ void Plog::getParameters(AnyMap& rateNode, const Units& rate_units) const } void Plog::setup(const std::multimap& rates) +{ + warn_deprecated("Plog::setup", "Deprecated in Cantera 2.6; " + "renamed to setRates."); + setRates(rates); +} + +void Plog::setRates(const std::multimap& rates) { size_t j = 0; rates_.reserve(rates.size()); @@ -259,18 +266,24 @@ void Plog::validate(const std::string& equation) std::vector > Plog::rates() const { - std::vector > R; + warn_deprecated("Plog::rates", "To be removed after Cantera 2.6; " + "replaceable by getRates()."); + auto rateMap = getRates(); + return std::vector>(rateMap.begin(), rateMap.end()); +} + +std::multimap Plog::getRates() const +{ + std::multimap rateMap; // initial preincrement to skip rate for P --> 0 for (auto iter = ++pressures_.begin(); - iter->first < 1000; // skip rates for (P --> infinity) - ++iter) { - for (size_t i = iter->second.first; - i < iter->second.second; - i++) { - R.emplace_back(std::exp(iter->first), rates_[i]); + iter->first < 1000; // skip rates for (P --> infinity) + ++iter) { + for (size_t i = iter->second.first; i < iter->second.second; i++) { + rateMap.insert({std::exp(iter->first), rates_[i]}); } } - return R; + return rateMap; } Chebyshev::Chebyshev( diff --git a/test/kinetics/kineticsFromYaml.cpp b/test/kinetics/kineticsFromYaml.cpp index 777c95ccd4..98746b57db 100644 --- a/test/kinetics/kineticsFromYaml.cpp +++ b/test/kinetics/kineticsFromYaml.cpp @@ -218,7 +218,8 @@ TEST(Reaction, PlogFromYaml) "- {P: 1.01325 MPa, A: 1.680000e+16, b: -0.6, Ea: 14754.0}"); auto R = newReaction(rxn, *(sol->kinetics())); - const auto& rates = std::dynamic_pointer_cast(R->rate())->rates(); + const auto& rateMap = std::dynamic_pointer_cast(R->rate())->getRates(); + std::vector> rates(rateMap.begin(), rateMap.end()); EXPECT_EQ(rates.size(), (size_t) 4); EXPECT_NEAR(rates[0].first, 0.039474 * OneAtm, 1e-6); EXPECT_NEAR(rates[2].first, OneAtm, 1e-6); From 463598a614bbe94bdadaf796b0b0a341b2dfceb0 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Sun, 5 Sep 2021 11:01:28 -0500 Subject: [PATCH 22/28] [Kinetics] Access Chebyshev coefficients as 'data' --- include/cantera/kinetics/ReactionRate.h | 6 ---- include/cantera/kinetics/RxnRates.h | 14 ++++---- interfaces/cython/cantera/_cantera.pxd | 5 ++- interfaces/cython/cantera/reaction.pyx | 34 +++++++++++-------- .../cython/cantera/test/test_kinetics.py | 2 +- .../cython/cantera/test/test_reaction.py | 12 ++++--- src/kinetics/ReactionRate.cpp | 10 ------ src/kinetics/RxnRates.cpp | 14 ++++---- test/kinetics/kineticsFromYaml.cpp | 4 +-- 9 files changed, 46 insertions(+), 55 deletions(-) diff --git a/include/cantera/kinetics/ReactionRate.h b/include/cantera/kinetics/ReactionRate.h index 75b2b45011..0847a8620f 100644 --- a/include/cantera/kinetics/ReactionRate.h +++ b/include/cantera/kinetics/ReactionRate.h @@ -431,12 +431,6 @@ class ChebyshevRate3 final : public ReactionRate, public Chebyshe return updateRC(0., shared_data.m_recipT); } - //! Access the Chebyshev coefficients as 2-dimensional array. - const Array2D& coeffs() const; - - //! Set the Chebyshev coefficients as 2-dimensional array. - void setCoeffs(const Array2D& coeffs); - virtual void validate(const std::string& equation) override; }; diff --git a/include/cantera/kinetics/RxnRates.h b/include/cantera/kinetics/RxnRates.h index d832c57c8d..17640d5f1d 100644 --- a/include/cantera/kinetics/RxnRates.h +++ b/include/cantera/kinetics/RxnRates.h @@ -666,24 +666,24 @@ class Chebyshev * \f$ \alpha_{t,p} = \mathrm{coeffs}[N_P*t + p] \f$ where * \f$ 0 <= t < N_T \f$ and \f$ 0 <= p < N_P \f$. * - * @deprecated Behavior to change after Cantera 2.6. For new - * behavior @see getCoeffs(). + * @deprecated To be removed after Cantera 2.6. Replaceable by @see data(). */ const vector_fp& coeffs() const { - warn_deprecated("Chebyshev::coeffs", "Behavior to change after Cantera 2.6; " - "for new behavior, use getCoeffs()."); + warn_deprecated("Chebyshev::coeffs", "Deprecated in Cantera 2.6 " + "and to be removed thereafter; replaceable by data()."); return chebCoeffs_; } - //! Access Chebyshev coefficients as 2-dimensional array. - const Array2D& getCoeffs() const + //! Access Chebyshev coefficients as 2-dimensional array with temperature and + //! pressure dimensions corresponding to rows and columns, respecitively. + const Array2D& data() const { return m_coeffs; } //! Set the Chebyshev coefficients as 2-dimensional array. - void setCoeffs(const Array2D& coeffs); + void setData(const Array2D& coeffs); protected: std::pair m_Trange; //!< valid temperature range diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index bb750edcdc..a48d7b24b8 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -400,7 +400,7 @@ cdef extern from "cantera/kinetics/Reaction.h" namespace "Cantera": CxxChebyshevRate3(pair[double, double], pair[double, double], CxxArray2D) pair[double, double] temperatureRange() pair[double, double] pressureRange() - CxxArray2D& coeffs() + CxxArray2D& data() cdef cppclass CxxCustomFunc1Rate "Cantera::CustomFunc1Rate" (CxxReactionRateBase): CxxCustomFunc1Rate() @@ -478,8 +478,7 @@ cdef extern from "cantera/kinetics/Reaction.h" namespace "Cantera": CxxChebyshev(pair[double, double], pair[double, double], CxxArray2D) pair[double, double] temperatureRange() pair[double, double] pressureRange() - vector[double]& coeffs() - CxxArray2D& getCoeffs() + CxxArray2D& data() void update_C(double*) double updateRC(double, double) diff --git a/interfaces/cython/cantera/reaction.pyx b/interfaces/cython/cantera/reaction.pyx index 6599590273..f056f7cba1 100644 --- a/interfaces/cython/cantera/reaction.pyx +++ b/interfaces/cython/cantera/reaction.pyx @@ -310,12 +310,13 @@ cdef class ChebyshevRate(ReactionRate): cdef pair[double,double] limits = self.cxx_object().pressureRange() return limits.first, limits.second - property coeffs: + property data: """ - 2D array of Chebyshev coefficients of size `(n_temperature, n_pressure)`. + 2D array of Chebyshev coefficients where rows and columns correspond to + temperature and pressure dimensions over which the Chebyshev fit is computed. """ def __get__(self): - cdef CxxArray2D cxxcoeffs = self.cxx_object().coeffs() + cdef CxxArray2D cxxcoeffs = self.cxx_object().data() c = np.fromiter(cxxcoeffs.data(), np.double) return c.reshape(cxxcoeffs.nRows(), cxxcoeffs.nColumns(), order="F") @@ -1584,17 +1585,17 @@ cdef class ChebyshevReaction(Reaction): .. deprecated:: 2.6 To be deprecated with version 2.6, and removed thereafter. - Accessible as number of columns of `ChebyshevRate.coeffs`. + Accessible as number of columns of `ChebyshevRate.data`. """ def __get__(self): if self.uses_legacy: - return self.cxx_object2().rate.getCoeffs().nColumns() + return self.cxx_object2().rate.data().nColumns() warnings.warn( self._deprecation_warning( - "nPressure", new="ChebyshevRate.coeffs.shape[1]"), + "nPressure", new="ChebyshevRate.data.shape[1]"), DeprecationWarning) - return self.rate.coeffs.shape[1] + return self.rate.data.shape[1] property nTemperature: """ @@ -1602,21 +1603,21 @@ cdef class ChebyshevReaction(Reaction): .. deprecated:: 2.6 To be deprecated with version 2.6, and removed thereafter. - Accessible as number of rows of `ChebyshevRate.coeffs`. + Accessible as number of rows of `ChebyshevRate.data`. """ def __get__(self): if self.uses_legacy: - return self.cxx_object2().rate.getCoeffs().nRows() + return self.cxx_object2().rate.data().nRows() warnings.warn( self._deprecation_warning( - "nTemperature", new="ChebyshevRate.coeffs.shape[0]"), + "nTemperature", new="ChebyshevRate.data.shape[0]"), DeprecationWarning) - return self.rate.coeffs.shape[0] + return self.rate.data.shape[0] cdef _legacy_get_coeffs(self): cdef CxxChebyshevReaction2* r = self.cxx_object2() - cdef CxxArray2D cxxcoeffs = r.rate.getCoeffs() + cdef CxxArray2D cxxcoeffs = r.rate.data() c = np.fromiter(cxxcoeffs.data(), np.double) return c.reshape(cxxcoeffs.nRows(), cxxcoeffs.nColumns(), order="F") @@ -1626,14 +1627,17 @@ cdef class ChebyshevReaction(Reaction): .. deprecated:: 2.6 To be deprecated with version 2.6, and removed thereafter. - Replaced by property `ChebyshevRate.coeffs`. + Replaced by property `ChebyshevRate.data`. """ def __get__(self): if self.uses_legacy: return self._legacy_get_coeffs() - warnings.warn(self._deprecation_warning("coeffs"), DeprecationWarning) - return self.rate.coeffs + warnings.warn( + self._deprecation_warning( + "coeffs", new="ChebyshevRate.data"), + DeprecationWarning) + return self.rate.data cdef _legacy_set_parameters(self, Tmin, Tmax, Pmin, Pmax, coeffs): cdef CxxChebyshevReaction2* r = self.cxx_object2() diff --git a/interfaces/cython/cantera/test/test_kinetics.py b/interfaces/cython/cantera/test/test_kinetics.py index 9057b59c63..4328a80e3a 100644 --- a/interfaces/cython/cantera/test/test_kinetics.py +++ b/interfaces/cython/cantera/test/test_kinetics.py @@ -1481,7 +1481,7 @@ def test_modify_chebyshev(self): r1 = gas.reaction(4) r2 = gas.reaction(5) r1.rate = ct.ChebyshevRate( - r2.rate.temperature_range, r2.rate.pressure_range, r2.rate.coeffs) + r2.rate.temperature_range, r2.rate.pressure_range, r2.rate.data) # rates should be different before calling 'modify_reaction' kf = gas.forward_rate_constants diff --git a/interfaces/cython/cantera/test/test_reaction.py b/interfaces/cython/cantera/test/test_reaction.py index 2a071a1294..1f13e1d6cb 100644 --- a/interfaces/cython/cantera/test/test_reaction.py +++ b/interfaces/cython/cantera/test/test_reaction.py @@ -332,8 +332,8 @@ class TestChebyshevRate(ReactionRateTests, utilities.CanteraTest): def setUp(self): self.Trange = self.gas.reaction(self._index).rate.temperature_range self.Prange = self.gas.reaction(self._index).rate.pressure_range - self.coeffs = self.gas.reaction(self._index).rate.coeffs - self.rate = ct.ChebyshevRate(self.Trange, self.Prange, self.coeffs) + self.data = self.gas.reaction(self._index).rate.data + self.rate = ct.ChebyshevRate(self.Trange, self.Prange, self.data) def test_parameters(self): # test getters for rate properties @@ -341,7 +341,7 @@ def test_parameters(self): self.assertEqual(self.Trange[1], self.rate.temperature_range[1]) self.assertEqual(self.Prange[0], self.rate.pressure_range[0]) self.assertEqual(self.Prange[1], self.rate.pressure_range[1]) - self.assertTrue(np.all(self.coeffs == self.rate.coeffs)) + self.assertTrue(np.all(self.data == self.rate.data)) class ReactionTests: @@ -531,7 +531,11 @@ def test_deprecated_getters(self): self.check_equal(getattr(rxn, attr), default) else: with self.assertWarnsRegex(DeprecationWarning, "property is moved"): - self.check_equal(getattr(rxn, attr), default) + try: + self.check_equal(getattr(rxn, attr), default) + except Exception as err: + print(f"Exception raised when testing getter for '{attr}'") + raise err ct.make_deprecation_warnings_fatal() # re-enable fatal deprecation warnings diff --git a/src/kinetics/ReactionRate.cpp b/src/kinetics/ReactionRate.cpp index 99778a0239..6d09c42d45 100644 --- a/src/kinetics/ReactionRate.cpp +++ b/src/kinetics/ReactionRate.cpp @@ -192,16 +192,6 @@ void ChebyshevRate3::getParameters(AnyMap& rateNode, rateNode["type"] = type(); } -const Array2D& ChebyshevRate3::coeffs() const -{ - return ChebyshevRate3::getCoeffs(); -} - -void ChebyshevRate3::setCoeffs(const Array2D& coeffs) -{ - Chebyshev::setCoeffs(coeffs); -} - void ChebyshevRate3::validate(const std::string& equation) { } diff --git a/src/kinetics/RxnRates.cpp b/src/kinetics/RxnRates.cpp index 010c4d4d39..55ef0da936 100644 --- a/src/kinetics/RxnRates.cpp +++ b/src/kinetics/RxnRates.cpp @@ -292,7 +292,7 @@ Chebyshev::Chebyshev( const Array2D& coeffs) { setLimits(Trange, Prange); - setCoeffs(coeffs); + setData(coeffs); } Chebyshev::Chebyshev(double Tmin, double Tmax, double Pmin, double Pmax, @@ -301,7 +301,7 @@ Chebyshev::Chebyshev(double Tmin, double Tmax, double Pmin, double Pmax, warn_deprecated("Chebyshev", "Deprecated in Cantera 2.6; " "replaceable with constructor using pairs for range input."); setLimits(std::make_pair(Tmin, Tmax), std::make_pair(Pmin, Pmax)); - setCoeffs(coeffs); + setData(coeffs); } void Chebyshev::setParameters(const AnyMap& node, @@ -337,16 +337,16 @@ void Chebyshev::setParameters(const AnyMap& node, setLimits(std::make_pair(290., 3000.), std::make_pair(1.e-7, 1.e14)); } - setCoeffs(coeffs); + setData(coeffs); } void Chebyshev::setup(double Tmin, double Tmax, double Pmin, double Pmax, const Array2D& coeffs) { warn_deprecated("Chebyshev::setup", "Deprecated in Cantera 2.6; " - "replaceable with setLimits() and setCoeffs()."); + "replaceable with setLimits() and setData()."); setLimits(std::make_pair(Tmin, Tmax), std::make_pair(Pmin, Pmax)); - setCoeffs(coeffs); + setData(coeffs); } void Chebyshev::setLimits( @@ -367,13 +367,13 @@ void Chebyshev::setLimits( m_Prange = Prange; } -void Chebyshev::setCoeffs(const Array2D& coeffs) +void Chebyshev::setData(const Array2D& coeffs) { m_coeffs = coeffs; dotProd_.resize(coeffs.nRows()); // convert to row major for legacy output - // note: chebCoeffs_ is not used internally + // note: chebCoeffs_ is not used internally (@TODO: remove after Cantera 2.6) size_t rows = m_coeffs.nRows(); size_t cols = m_coeffs.nColumns(); chebCoeffs_.resize(rows * cols); diff --git a/test/kinetics/kineticsFromYaml.cpp b/test/kinetics/kineticsFromYaml.cpp index 98746b57db..77b12166bb 100644 --- a/test/kinetics/kineticsFromYaml.cpp +++ b/test/kinetics/kineticsFromYaml.cpp @@ -250,8 +250,8 @@ TEST(Reaction, ChebyshevFromYaml) double logP = std::log10(2e6); double T = 1800; rate->update_C(&logP); - EXPECT_EQ(rate->coeffs().nRows(), (size_t) 6); - EXPECT_EQ(rate->coeffs().nColumns(), (size_t) 4); + EXPECT_EQ(rate->data().nRows(), (size_t) 6); + EXPECT_EQ(rate->data().nColumns(), (size_t) 4); EXPECT_DOUBLE_EQ(rate->temperatureRange().second, 3000); EXPECT_DOUBLE_EQ(rate->pressureRange().first, 1000); EXPECT_NEAR(rate->updateRC(std::log(T), 1.0/T), 130512.2773948636, 1e-9); From 031a7e920c388a72e5f961d27a8616f9b21e1fbb Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Tue, 14 Sep 2021 13:48:11 -0500 Subject: [PATCH 23/28] [Kinetics] Use compressed sparse matrix format --- include/cantera/kinetics/StoichManager.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/cantera/kinetics/StoichManager.h b/include/cantera/kinetics/StoichManager.h index 5a1645b058..f9b7872b53 100644 --- a/include/cantera/kinetics/StoichManager.h +++ b/include/cantera/kinetics/StoichManager.h @@ -474,6 +474,7 @@ class StoichManagerN m_stoichCoeffs.resize(nSpc, nRxn); m_stoichCoeffs.reserve(nCoeffs); m_stoichCoeffs.setFromTriplets(m_coeffList.begin(), m_coeffList.end()); + m_stoichCoeffs.makeCompressed(); m_finalized = true; } From 53945402c0553466a22b28a63cbffbc000d50a67 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Tue, 14 Sep 2021 13:48:41 -0500 Subject: [PATCH 24/28] [Python] Switch sparse matrix output to CSC (from COO) format This change leverages the default internal storage format in Eigen (CSC) --- include/cantera/cython/wrappers.h | 30 +++++++++++++++++++++++-- interfaces/cython/cantera/_cantera.pxd | 8 ++++++- interfaces/cython/cantera/kinetics.pyx | 31 +++++++++++++++----------- 3 files changed, 53 insertions(+), 16 deletions(-) diff --git a/include/cantera/cython/wrappers.h b/include/cantera/cython/wrappers.h index 8290de5f88..5429502723 100644 --- a/include/cantera/cython/wrappers.h +++ b/include/cantera/cython/wrappers.h @@ -50,8 +50,8 @@ void CxxArray2D_set(Cantera::Array2D& array, size_t i, size_t j, double value) array(i,j) = value; } -// Service function to pass components describing sparse matrix -size_t sparseComponents(const Eigen::SparseMatrix& mat, +// Service function to pass index/value triplets describing sparse matrix +size_t sparseTriplets(const Eigen::SparseMatrix& mat, int* rows, int* cols, double* data, size_t length) { size_t count = 0; @@ -73,6 +73,32 @@ size_t sparseComponents(const Eigen::SparseMatrix& mat, return count; } +// Service function to pass CSC data describing sparse matrix +void sparseCscData(const Eigen::SparseMatrix& mat, + double* value, int* inner, int* outer) +{ + if (!mat.isCompressed()) { + throw Cantera::CanteraError("sparseCscData", + "Invalid input: Eigen matrix is not compressed."); + } + if (mat.IsRowMajor) { + throw Cantera::CanteraError("sparseCscData", + "Invalid input: Eigen matrix is not in column major format."); + } + + const double* valuePtr = mat.valuePtr(); + const int* innerPtr = mat.innerIndexPtr(); + for (size_t i = 0; i < mat.nonZeros(); ++i) { + value[i] = valuePtr[i]; + inner[i] = innerPtr[i]; + } + + const int* outerPtr = mat.outerIndexPtr(); + for (size_t i = 0; i < mat.outerSize() + 1; ++i) { + outer[i] = outerPtr[i]; + } +} + // Function which passes sparse matrix #define SPARSE_MATRIX(PREFIX, CLASS_NAME, FUNC_NAME) \ Eigen::SparseMatrix PREFIX ## _ ## FUNC_NAME(Cantera::CLASS_NAME* object) \ diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index a48d7b24b8..e4711fdba2 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -49,6 +49,11 @@ cdef extern from "cantera/numerics/eigen_sparse.h" namespace "Eigen": size_t nonZeros() size_t rows() size_t cols() + size_t innerSize() + size_t outerSize() + int* outerIndexPtr() + int* innerIndexPtr() + double* valuePtr() cdef extern from "cantera/base/xml.h" namespace "Cantera": cdef cppclass XML_Node: @@ -1040,7 +1045,8 @@ cdef extern from "cantera/cython/wrappers.h": cdef void CxxSetLogger "setLogger" (CxxPythonLogger*) - cdef size_t CxxSparseComponents "sparseComponents" (CxxSparseMatrix, int*, int*, double*, size_t) except +translate_exception + cdef size_t CxxSparseTriplets "sparseTriplets" (CxxSparseMatrix, int*, int*, double*, size_t) except +translate_exception + cdef void CxxSparseCscData "sparseCscData" (CxxSparseMatrix, double*, int*, int*) except +translate_exception # workaround for Cython assignment limitations cdef void CxxArray2D_set(CxxArray2D, size_t, size_t, double) diff --git a/interfaces/cython/cantera/kinetics.pyx b/interfaces/cython/cantera/kinetics.pyx index bcc4a8fde6..569e759c74 100644 --- a/interfaces/cython/cantera/kinetics.pyx +++ b/interfaces/cython/cantera/kinetics.pyx @@ -26,27 +26,32 @@ cdef np.ndarray get_dense(Kinetics kin, kineticsMethodSparse method): if length == 0: return np.zeros((kin.n_reactions, 0)) + # index/value triplets cdef np.ndarray[int, ndim=1, mode="c"] rows = np.empty(length, dtype=c_int) cdef np.ndarray[int, ndim=1, mode="c"] cols = np.empty(length, dtype=c_int) cdef np.ndarray[np.double_t, ndim=1] data = np.empty(length) - size = CxxSparseComponents(smat, &rows[0], &cols[0], &data[0], length) + size = CxxSparseTriplets(smat, &rows[0], &cols[0], &data[0], length) out = np.zeros((smat.rows(), smat.cols())) for i in xrange(length): out[rows[i], cols[i]] = data[i] return out cdef tuple get_sparse(Kinetics kin, kineticsMethodSparse method): + # retrieve sparse matrix cdef CxxSparseMatrix smat = method(kin.kinetics) + + # pointers to values and inner indices of CSC storage cdef size_t length = smat.nonZeros() + cdef np.ndarray[np.double_t, ndim=1] value = np.empty(length) + cdef np.ndarray[int, ndim=1, mode="c"] inner = np.empty(length, dtype=c_int) - cdef np.ndarray[int, ndim=1, mode="c"] rows = np.empty(length, dtype=c_int) - cdef np.ndarray[int, ndim=1, mode="c"] cols = np.empty(length, dtype=c_int) - cdef np.ndarray[np.double_t, ndim=1] data = np.empty(length) + # pointers outer indices of CSC storage + cdef size_t ncols = smat.outerSize() + cdef np.ndarray[int, ndim=1, mode="c"] outer = np.empty(ncols + 1, dtype=c_int) - if length > 0: - size = CxxSparseComponents(smat, &rows[0], &cols[0], &data[0], length) - return data, tuple([rows, cols]) + CxxSparseCscData(smat, &value[0], &inner[0], &outer[0]) + return value, inner, outer cdef class Kinetics(_SolutionBase): @@ -293,9 +298,9 @@ cdef class Kinetics(_SolutionBase): """ def __get__(self): if __use_sparse__: - data, ix_ij = get_sparse(self, kin_reactantStoichCoeffs) + tup = get_sparse(self, kin_reactantStoichCoeffs) shape = self.n_total_species, self.n_reactions - return _scipy_sparse.coo_matrix((data, ix_ij), shape=shape) + return _scipy_sparse.csc_matrix(tup, shape=shape) return get_dense(self, kin_reactantStoichCoeffs) def product_stoich_coeffs(self): @@ -323,9 +328,9 @@ cdef class Kinetics(_SolutionBase): """ def __get__(self): if __use_sparse__: - data, ix_ij = get_sparse(self, kin_productStoichCoeffs) + tup = get_sparse(self, kin_productStoichCoeffs) shape = self.n_total_species, self.n_reactions - return _scipy_sparse.coo_matrix((data, ix_ij), shape=shape) + return _scipy_sparse.csc_matrix(tup, shape=shape) return get_dense(self, kin_productStoichCoeffs) property product_stoich_coeffs_reversible: @@ -338,9 +343,9 @@ cdef class Kinetics(_SolutionBase): """ def __get__(self): if __use_sparse__: - data, ix_ij = get_sparse(self, kin_revProductStoichCoeffs) + tup = get_sparse(self, kin_revProductStoichCoeffs) shape = self.n_total_species, self.n_reactions - return _scipy_sparse.coo_matrix((data, ix_ij), shape=shape) + return _scipy_sparse.csc_matrix(tup, shape=shape) return get_dense(self, kin_revProductStoichCoeffs) property forward_rates_of_progress: From a9901f54d1016424c5567566c38a53e1cbcbf21b Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Thu, 16 Sep 2021 14:35:48 -0500 Subject: [PATCH 25/28] Update formatting --- include/cantera/cython/wrappers.h | 4 ---- include/cantera/kinetics/Kinetics.h | 9 +++------ include/cantera/kinetics/RxnRates.h | 2 +- include/cantera/kinetics/StoichManager.h | 8 +++----- interfaces/cython/cantera/_cantera.pxd | 4 ---- src/kinetics/RxnRates.cpp | 4 ++-- 6 files changed, 9 insertions(+), 22 deletions(-) diff --git a/include/cantera/cython/wrappers.h b/include/cantera/cython/wrappers.h index 5429502723..3011bb7105 100644 --- a/include/cantera/cython/wrappers.h +++ b/include/cantera/cython/wrappers.h @@ -81,10 +81,6 @@ void sparseCscData(const Eigen::SparseMatrix& mat, throw Cantera::CanteraError("sparseCscData", "Invalid input: Eigen matrix is not compressed."); } - if (mat.IsRowMajor) { - throw Cantera::CanteraError("sparseCscData", - "Invalid input: Eigen matrix is not in column major format."); - } const double* valuePtr = mat.valuePtr(); const int* innerPtr = mat.innerIndexPtr(); diff --git a/include/cantera/kinetics/Kinetics.h b/include/cantera/kinetics/Kinetics.h index 023d413e96..0227eacc8e 100644 --- a/include/cantera/kinetics/Kinetics.h +++ b/include/cantera/kinetics/Kinetics.h @@ -562,8 +562,7 @@ class Kinetics /** * Stoichiometric coefficient matrix for reactants. */ - Eigen::SparseMatrix reactantStoichCoeffs() const - { + Eigen::SparseMatrix reactantStoichCoeffs() const { return m_reactantStoich.stoichCoeffs(); } @@ -578,16 +577,14 @@ class Kinetics /** * Stoichiometric coefficient matrix for products. */ - Eigen::SparseMatrix productStoichCoeffs() const - { + Eigen::SparseMatrix productStoichCoeffs() const { return m_productStoich.stoichCoeffs(); } /** * Stoichiometric coefficient matrix for products of reversible reactions. */ - Eigen::SparseMatrix revProductStoichCoeffs() const - { + Eigen::SparseMatrix revProductStoichCoeffs() const { return m_revProductStoich.stoichCoeffs(); } diff --git a/include/cantera/kinetics/RxnRates.h b/include/cantera/kinetics/RxnRates.h index 17640d5f1d..fd23b4c8aa 100644 --- a/include/cantera/kinetics/RxnRates.h +++ b/include/cantera/kinetics/RxnRates.h @@ -676,7 +676,7 @@ class Chebyshev } //! Access Chebyshev coefficients as 2-dimensional array with temperature and - //! pressure dimensions corresponding to rows and columns, respecitively. + //! pressure dimensions corresponding to rows and columns, respectively. const Array2D& data() const { return m_coeffs; diff --git a/include/cantera/kinetics/StoichManager.h b/include/cantera/kinetics/StoichManager.h index f9b7872b53..2a8b57e8ef 100644 --- a/include/cantera/kinetics/StoichManager.h +++ b/include/cantera/kinetics/StoichManager.h @@ -470,11 +470,9 @@ class StoichManagerN size_t nCoeffs = m_coeffList.size(); // Stoichiometric coefficient matrix - m_stoichCoeffs.setZero(); m_stoichCoeffs.resize(nSpc, nRxn); m_stoichCoeffs.reserve(nCoeffs); m_stoichCoeffs.setFromTriplets(m_coeffList.begin(), m_coeffList.end()); - m_stoichCoeffs.makeCompressed(); m_finalized = true; } @@ -523,7 +521,7 @@ class StoichManagerN } bool frac = false; for (size_t n = 0; n < stoich.size(); n++) { - m_coeffList.push_back(Eigen::Triplet(k[n], rxn, stoich[n])); + m_coeffList.emplace_back(k[n], rxn, stoich[n]); if (fmod(stoich[n], 1.0) || stoich[n] != order[n]) { frac = true; } @@ -608,7 +606,7 @@ class StoichManagerN } private: - bool m_finalized; //!< Boolean flag indicating whether setup is finalized + bool m_finalized; //!< Boolean flag indicating whether object setup is finalized std::vector m_c1_list; std::vector m_c2_list; @@ -616,7 +614,7 @@ class StoichManagerN std::vector m_cn_list; //! Sparse matrices for stoichiometric coefficients - std::vector> m_coeffList; + SparseTriplets m_coeffList; Eigen::SparseMatrix m_stoichCoeffs; }; diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index e4711fdba2..6163c282fb 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -49,11 +49,7 @@ cdef extern from "cantera/numerics/eigen_sparse.h" namespace "Eigen": size_t nonZeros() size_t rows() size_t cols() - size_t innerSize() size_t outerSize() - int* outerIndexPtr() - int* innerIndexPtr() - double* valuePtr() cdef extern from "cantera/base/xml.h" namespace "Cantera": cdef cppclass XML_Node: diff --git a/src/kinetics/RxnRates.cpp b/src/kinetics/RxnRates.cpp index 55ef0da936..8a66b2b4fe 100644 --- a/src/kinetics/RxnRates.cpp +++ b/src/kinetics/RxnRates.cpp @@ -266,8 +266,8 @@ void Plog::validate(const std::string& equation) std::vector > Plog::rates() const { - warn_deprecated("Plog::rates", "To be removed after Cantera 2.6; " - "replaceable by getRates()."); + warn_deprecated("Plog::rates", "Behavior to change after Cantera 2.6; " + "see getRates() for new behavior."); auto rateMap = getRates(); return std::vector>(rateMap.begin(), rateMap.end()); } From 202c2bf71a4ec43805110f02ed00f2a6fe04ef63 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Thu, 16 Sep 2021 15:52:51 -0500 Subject: [PATCH 26/28] [Kinetics] Partially roll back changes to Chebyshev --- include/cantera/kinetics/ReactionRate.h | 16 ++-- include/cantera/kinetics/RxnRates.h | 115 +++++------------------- interfaces/cython/cantera/_cantera.pxd | 20 +++-- interfaces/cython/cantera/reaction.pyx | 60 +++++++------ src/kinetics/Reaction.cpp | 20 ++--- src/kinetics/ReactionRate.cpp | 7 +- src/kinetics/RxnRates.cpp | 47 ++++------ test/kinetics/kineticsFromScratch.cpp | 3 +- test/kinetics/kineticsFromScratch3.cpp | 3 +- test/kinetics/kineticsFromYaml.cpp | 7 +- 10 files changed, 111 insertions(+), 187 deletions(-) diff --git a/include/cantera/kinetics/ReactionRate.h b/include/cantera/kinetics/ReactionRate.h index 0847a8620f..7ccd45990e 100644 --- a/include/cantera/kinetics/ReactionRate.h +++ b/include/cantera/kinetics/ReactionRate.h @@ -390,17 +390,17 @@ class ChebyshevRate3 final : public ReactionRate, public Chebyshe ChebyshevRate3() {} //! Constructor using coefficient array - /*! - * @param Trange Valid temperature range (min, max) [K] - * @param Prange Valid pressure range (min, max) [Pa] - * @param coeffs Coefficient array dimensioned `nT` by `nP` where `nT` and + /* + * @param Tmin Minimum temperature [K] + * @param Tmax Maximum temperature [K] + * @param Pmin Minimum pressure [Pa] + * @param Pmax Maximum pressure [Pa] + * @param coeffs Coefficient array dimensioned `nT` by `nP` where `nT` and * `nP` are the number of temperatures and pressures used in the fit, * respectively. */ - ChebyshevRate3( - const std::pair Trange, - const std::pair Prange, - const Array2D& coeffs); + ChebyshevRate3(double Tmin, double Tmax, double Pmin, double Pmax, + const Array2D& coeffs); //! Constructor using AnyMap content //! @param node AnyMap containing rate information diff --git a/include/cantera/kinetics/RxnRates.h b/include/cantera/kinetics/RxnRates.h index fd23b4c8aa..32b0ccfae9 100644 --- a/include/cantera/kinetics/RxnRates.h +++ b/include/cantera/kinetics/RxnRates.h @@ -24,8 +24,6 @@ class AnyValue; class AnyMap; class UnitSystem; class Units; -class AnyMap; -class Units; //! Arrhenius reaction rate type depends only on temperature /** @@ -421,7 +419,8 @@ class Plog //! Return the pressures and Arrhenius expressions which comprise this //! reaction. /*! - * @deprecated To be removed after Cantera 2.6. Replaceable by getRates. + * @deprecated Behavior to change after Cantera 2.6. + * @see getRates for new behavior. */ std::vector > rates() const; @@ -483,19 +482,6 @@ class Chebyshev //! Default constructor. Chebyshev() {} - //! Constructor directly from coefficient array - /*! - * @param Trange Valid temperature range (min, max) [K] - * @param Prange Valid pressure range (min, max) [Pa] - * @param coeffs Coefficient array dimensioned `nT` by `nP` where `nT` and - * `nP` are the number of temperatures and pressures used in the fit, - * respectively. - */ - Chebyshev( - const std::pair Trange, - const std::pair Prange, - const Array2D& coeffs); - //! Constructor directly from coefficient array /*! * @param Tmin Minimum temperature [K] @@ -505,9 +491,6 @@ class Chebyshev * @param coeffs Coefficient array dimensioned `nT` by `nP` where `nT` and * `nP` are the number of temperatures and pressures used in the fit, * respectively. - * - * @deprecated Deprecated in Cantera 2.6. - * Use constructor using pairs for range input. */ Chebyshev(double Tmin, double Tmax, double Pmin, double Pmax, const Array2D& coeffs); @@ -530,12 +513,12 @@ class Chebyshev //! Set limits for Chebyshev object /*! - * @param Trange Temperature range (min, max) [K] - * @param Prange Pressure range (min, max) [Pa] + * @param Tmin Minimum temperature [K] + * @param Tmax Maximum temperature [K] + * @param Pmin Minimum pressure [Pa] + * @param Pmax Maximum pressure [Pa] */ - void setLimits( - const std::pair Trange, - const std::pair Prange); + void setLimits(double Tmin, double Tmax, double Pmin, double Pmax); //! Update concentration-dependent parts of the rate coefficient. //! @param c base-10 logarithm of the pressure in Pa @@ -578,86 +561,32 @@ class Chebyshev } //! Minimum valid temperature [K] - /*! - * @deprecated Deprecated in Cantera 2.6. - * Replaceable with @see temperatureRange() - */ - double Tmin() const - { - warn_deprecated("Chebyshev::Tmin", "Deprecated in Cantera 2.6; " - "replaceable with temperatureRange."); - return m_Trange.first; + double Tmin() const { + return Tmin_; } //! Maximum valid temperature [K] - /*! - * @deprecated Deprecated in Cantera 2.6. - * Replaceable with @see temperatureRange() - */ - double Tmax() const - { - warn_deprecated("Chebyshev::Tmax", "Deprecated in Cantera 2.6; " - "replaceable with temperatureRange."); - return m_Trange.second; - } - - // Range of valid temperatures (min, max) [K] - const std::pair& temperatureRange() const - { - return m_Trange; + double Tmax() const { + return Tmax_; } //! Minimum valid pressure [Pa] - /*! - * @deprecated Deprecated in Cantera 2.6. - * Replaceable with @see pressureRange() - */ - double Pmin() const - { - warn_deprecated("Chebyshev::Pmin", "Deprecated in Cantera 2.6; " - "replaceable with pressureRange."); - return m_Prange.first; + double Pmin() const { + return Pmin_; } //! Maximum valid pressure [Pa] - /*! - * @deprecated Deprecated in Cantera 2.6. - * Replaceable with @see pressureRange() - */ - double Pmax() const - { - warn_deprecated("Chebyshev::Pmax", "Deprecated in Cantera 2.6; " - "replaceable with pressureRange."); - return m_Prange.second; - } - - // Range of valid pressures (min, max) [Pa] - const std::pair& pressureRange() const - { - return m_Prange; + double Pmax() const { + return Pmax_; } //! Number of points in the pressure direction - /*! - * @deprecated Deprecated in Cantera 2.6. - * Accessible as number of columns of the coefficient matrix - */ - size_t nPressure() const - { - warn_deprecated("Chebyshev::nPressure", "Deprecated in Cantera 2.6; " - "accessible as number of colums of the coefficient matrix."); + size_t nPressure() const { return m_coeffs.nColumns(); } //! Number of points in the temperature direction - /*! - * @deprecated Deprecated in Cantera 2.6. - * Accessible as number of rows of the coefficient matrix - */ - size_t nTemperature() const - { - warn_deprecated("Chebyshev::nTemperature", "Deprecated in Cantera 2.6; " - "accessible as number of rows of the coefficient matrix."); + size_t nTemperature() const { return m_coeffs.nRows(); } @@ -668,8 +597,7 @@ class Chebyshev * * @deprecated To be removed after Cantera 2.6. Replaceable by @see data(). */ - const vector_fp& coeffs() const - { + const vector_fp& coeffs() const { warn_deprecated("Chebyshev::coeffs", "Deprecated in Cantera 2.6 " "and to be removed thereafter; replaceable by data()."); return chebCoeffs_; @@ -677,8 +605,7 @@ class Chebyshev //! Access Chebyshev coefficients as 2-dimensional array with temperature and //! pressure dimensions corresponding to rows and columns, respectively. - const Array2D& data() const - { + const Array2D& data() const { return m_coeffs; } @@ -686,8 +613,8 @@ class Chebyshev void setData(const Array2D& coeffs); protected: - std::pair m_Trange; //!< valid temperature range - std::pair m_Prange; //!< valid pressure range + double Tmin_, Tmax_; //!< valid temperature range + double Pmin_, Pmax_; //!< valid pressure range double TrNum_, TrDen_; //!< terms appearing in the reduced temperature double PrNum_, PrDen_; //!< terms appearing in the reduced pressure diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 6163c282fb..4e2f023bc3 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -398,9 +398,13 @@ cdef extern from "cantera/kinetics/Reaction.h" namespace "Cantera": cdef cppclass CxxChebyshevRate3 "Cantera::ChebyshevRate3" (CxxReactionRateBase): CxxChebyshevRate3() CxxChebyshevRate3(CxxAnyMap) except +translate_exception - CxxChebyshevRate3(pair[double, double], pair[double, double], CxxArray2D) - pair[double, double] temperatureRange() - pair[double, double] pressureRange() + CxxChebyshevRate3(double, double, double, double, CxxArray2D) + double Tmin() + double Tmax() + double Pmin() + double Pmax() + size_t nTemperature() + size_t nPressure() CxxArray2D& data() cdef cppclass CxxCustomFunc1Rate "Cantera::CustomFunc1Rate" (CxxReactionRateBase): @@ -476,9 +480,13 @@ cdef extern from "cantera/kinetics/Reaction.h" namespace "Cantera": CxxPlog rate cdef cppclass CxxChebyshev "Cantera::Chebyshev": - CxxChebyshev(pair[double, double], pair[double, double], CxxArray2D) - pair[double, double] temperatureRange() - pair[double, double] pressureRange() + CxxChebyshev(double, double, double, double, CxxArray2D) + double Tmin() + double Tmax() + double Pmin() + double Pmax() + size_t nTemperature() + size_t nPressure() CxxArray2D& data() void update_C(double*) double updateRC(double, double) diff --git a/interfaces/cython/cantera/reaction.pyx b/interfaces/cython/cantera/reaction.pyx index f056f7cba1..31ff0c203a 100644 --- a/interfaces/cython/cantera/reaction.pyx +++ b/interfaces/cython/cantera/reaction.pyx @@ -258,19 +258,17 @@ cdef class ChebyshevRate(ReactionRate): def __cinit__(self, temperature_range=None, pressure_range=None, data=None, input_data=None, init=True): - cdef pair[double,double] Trange - cdef pair[double,double] Prange if init: if isinstance(input_data, dict): self._rate.reset(new CxxChebyshevRate3(dict_to_anymap(input_data))) elif all([arg is not None for arg in [temperature_range, pressure_range, data]]): - Trange.first = temperature_range[0] - Trange.second = temperature_range[1] - Prange.first = pressure_range[0] - Prange.second = pressure_range[1] + Tmin = temperature_range[0] + Tmax = temperature_range[1] + Pmin = pressure_range[0] + Pmax = pressure_range[1] self._rate.reset( - new CxxChebyshevRate3(Trange, Prange, self._cxxarray2d(data))) + new CxxChebyshevRate3(Tmin, Tmax, Pmin, Pmax, self._cxxarray2d(data))) elif all([arg is None for arg in [temperature_range, pressure_range, data, input_data]]): self._rate.reset(new CxxChebyshevRate3(dict_to_anymap({}))) @@ -301,14 +299,28 @@ cdef class ChebyshevRate(ReactionRate): property temperature_range: """ Valid temperature range [K] for the Chebyshev fit """ def __get__(self): - cdef pair[double,double] limits = self.cxx_object().temperatureRange() - return limits.first, limits.second + return self.cxx_object().Tmin(), self.cxx_object().Tmax() property pressure_range: """ Valid pressure range [Pa] for the Chebyshev fit """ def __get__(self): - cdef pair[double,double] limits = self.cxx_object().pressureRange() - return limits.first, limits.second + return self.cxx_object().Pmin(), self.cxx_object().Pmax() + + property n_temperature: + """ + Number of temperatures over which the Chebyshev fit is computed. + (same as number of rows of `data` property). + """ + def __get__(self): + return self.cxx_object().Pmin(), self.cxx_object().nTemperature() + + property n_pressure: + """ + Number of pressures over which the Chebyshev fit is computed + (same as number of columns of `data` property). + """ + def __get__(self): + return self.cxx_object().Pmin(), self.cxx_object().nPressure() property data: """ @@ -1518,7 +1530,7 @@ cdef class ChebyshevReaction(Reaction): """ def __get__(self): if self.uses_legacy: - return self.cxx_object2().rate.temperatureRange().first + return self.cxx_object2().rate.Tmin() warnings.warn( self._deprecation_warning( @@ -1536,7 +1548,7 @@ cdef class ChebyshevReaction(Reaction): """ def __get__(self): if self.uses_legacy: - return self.cxx_object2().rate.temperatureRange().second + return self.cxx_object2().rate.Tmax() warnings.warn( self._deprecation_warning( @@ -1554,7 +1566,7 @@ cdef class ChebyshevReaction(Reaction): """ def __get__(self): if self.uses_legacy: - return self.cxx_object2().rate.pressureRange().first + return self.cxx_object2().rate.Pmin() warnings.warn( self._deprecation_warning( @@ -1571,7 +1583,7 @@ cdef class ChebyshevReaction(Reaction): """ def __get__(self): if self.uses_legacy: - return self.cxx_object2().rate.pressureRange().second + return self.cxx_object2().rate.Pmax() warnings.warn( self._deprecation_warning( @@ -1585,15 +1597,15 @@ cdef class ChebyshevReaction(Reaction): .. deprecated:: 2.6 To be deprecated with version 2.6, and removed thereafter. - Accessible as number of columns of `ChebyshevRate.data`. + Replaced by property `ChebyshevRate.n_pressure`. """ def __get__(self): if self.uses_legacy: - return self.cxx_object2().rate.data().nColumns() + return self.cxx_object2().rate.nPressure() warnings.warn( self._deprecation_warning( - "nPressure", new="ChebyshevRate.data.shape[1]"), + "nPressure", new="ChebyshevRate.data.n_pressure"), DeprecationWarning) return self.rate.data.shape[1] @@ -1603,15 +1615,15 @@ cdef class ChebyshevReaction(Reaction): .. deprecated:: 2.6 To be deprecated with version 2.6, and removed thereafter. - Accessible as number of rows of `ChebyshevRate.data`. + Replaced by property `ChebyshevRate.n_temperature`. """ def __get__(self): if self.uses_legacy: - return self.cxx_object2().rate.data().nRows() + return self.cxx_object2().rate.nTemperature() warnings.warn( self._deprecation_warning( - "nTemperature", new="ChebyshevRate.data.shape[0]"), + "nTemperature", new="ChebyshevRate.data.n_temperature"), DeprecationWarning) return self.rate.data.shape[0] @@ -1651,11 +1663,7 @@ cdef class ChebyshevReaction(Reaction): for j, value in enumerate(row): CxxArray2D_set(data, i, j, value) - cdef pair[double,double] Trange - Trange.first, Trange.second = Tmin, Tmax - cdef pair[double,double] Prange - Prange.first, Prange.second = Pmin, Pmax - r.rate = CxxChebyshev(Trange, Prange, data) + r.rate = CxxChebyshev(Tmin, Tmax, Pmin, Pmax, data) def set_parameters(self, Tmin, Tmax, Pmin, Pmax, coeffs): """ diff --git a/src/kinetics/Reaction.cpp b/src/kinetics/Reaction.cpp index d862adfff1..2a9f1c30ce 100644 --- a/src/kinetics/Reaction.cpp +++ b/src/kinetics/Reaction.cpp @@ -1627,10 +1627,11 @@ void setupChebyshevReaction(ChebyshevReaction2& R, const XML_Node& rxn_node) coeffs(t,p) = coeffs_flat[nP*t + p]; } } - R.rate = Chebyshev( - std::make_pair(getFloat(rc, "Tmin", "toSI"), getFloat(rc, "Tmax", "toSI")), - std::make_pair(getFloat(rc, "Pmin", "toSI"), getFloat(rc, "Pmax", "toSI")), - coeffs); + R.rate = Chebyshev(getFloat(rc, "Tmin", "toSI"), + getFloat(rc, "Tmax", "toSI"), + getFloat(rc, "Pmin", "toSI"), + getFloat(rc, "Pmax", "toSI"), + coeffs); setupReaction(R, rxn_node); } @@ -1655,12 +1656,11 @@ void setupChebyshevReaction(ChebyshevReaction2&R, const AnyMap& node, } const UnitSystem& units = node.units(); coeffs(0, 0) += std::log10(units.convertTo(1.0, R.rate_units)); - R.rate = Chebyshev( - std::make_pair( - units.convert(T_range[0], "K"), units.convert(T_range[1], "K")), - std::make_pair( - units.convert(P_range[0], "Pa"), units.convert(P_range[1], "Pa")), - coeffs); + R.rate = Chebyshev(units.convert(T_range[0], "K"), + units.convert(T_range[1], "K"), + units.convert(P_range[0], "Pa"), + units.convert(P_range[1], "Pa"), + coeffs); } void setupInterfaceReaction(InterfaceReaction& R, const XML_Node& rxn_node) diff --git a/src/kinetics/ReactionRate.cpp b/src/kinetics/ReactionRate.cpp index 6d09c42d45..28e80879fe 100644 --- a/src/kinetics/ReactionRate.cpp +++ b/src/kinetics/ReactionRate.cpp @@ -148,10 +148,9 @@ void PlogRate::getParameters(AnyMap& rateNode, const Units& rate_units) const rateNode["type"] = type(); } -ChebyshevRate3::ChebyshevRate3( - const std::pair Trange, - const std::pair Prange, - const Array2D& coeffs) : Chebyshev(Trange, Prange, coeffs) +ChebyshevRate3::ChebyshevRate3(double Tmin, double Tmax, double Pmin, double Pmax, + const Array2D& coeffs) + : Chebyshev(Tmin, Tmax, Pmin, Pmax, coeffs) { } diff --git a/src/kinetics/RxnRates.cpp b/src/kinetics/RxnRates.cpp index 8a66b2b4fe..c62913c695 100644 --- a/src/kinetics/RxnRates.cpp +++ b/src/kinetics/RxnRates.cpp @@ -286,21 +286,10 @@ std::multimap Plog::getRates() const return rateMap; } -Chebyshev::Chebyshev( - const std::pair Trange, - const std::pair Prange, - const Array2D& coeffs) -{ - setLimits(Trange, Prange); - setData(coeffs); -} - Chebyshev::Chebyshev(double Tmin, double Tmax, double Pmin, double Pmax, const Array2D& coeffs) { - warn_deprecated("Chebyshev", "Deprecated in Cantera 2.6; " - "replaceable with constructor using pairs for range input."); - setLimits(std::make_pair(Tmin, Tmax), std::make_pair(Pmin, Pmax)); + setLimits(Tmin, Tmax, Pmin, Pmax); setData(coeffs); } @@ -326,15 +315,13 @@ void Chebyshev::setParameters(const AnyMap& node, coeffs(0, 0) += std::log10(units.convertTo(1.0, rate_units)); } setLimits( - std::make_pair( - units.convert(T_range[0], "K"), units.convert(T_range[1], "K")), - std::make_pair( - units.convert(P_range[0], "Pa"), units.convert(P_range[1], "Pa"))); + units.convert(T_range[0], "K"), units.convert(T_range[1], "K"), + units.convert(P_range[0], "Pa"), units.convert(P_range[1], "Pa")); } else { // ensure that reaction rate can be evaluated (but returns NaN) coeffs = Array2D(1, 1); coeffs(0, 0) = NAN; - setLimits(std::make_pair(290., 3000.), std::make_pair(1.e-7, 1.e14)); + setLimits(290., 3000., 1.e-7, 1.e14); } setData(coeffs); @@ -345,26 +332,26 @@ void Chebyshev::setup(double Tmin, double Tmax, double Pmin, double Pmax, { warn_deprecated("Chebyshev::setup", "Deprecated in Cantera 2.6; " "replaceable with setLimits() and setData()."); - setLimits(std::make_pair(Tmin, Tmax), std::make_pair(Pmin, Pmax)); + setLimits(Tmin, Tmax, Pmin, Pmax); setData(coeffs); } -void Chebyshev::setLimits( - const std::pair Trange, - const std::pair Prange) +void Chebyshev::setLimits(double Tmin, double Tmax, double Pmin, double Pmax) { - double logPmin = std::log10(Prange.first); - double logPmax = std::log10(Prange.second); - double TminInv = 1.0 / Trange.first; - double TmaxInv = 1.0 / Trange.second; + double logPmin = std::log10(Pmin); + double logPmax = std::log10(Pmax); + double TminInv = 1.0 / Tmin; + double TmaxInv = 1.0 / Tmax; TrNum_ = - TminInv - TmaxInv; TrDen_ = 1.0 / (TmaxInv - TminInv); PrNum_ = - logPmin - logPmax; PrDen_ = 1.0 / (logPmax - logPmin); - m_Trange = Trange; - m_Prange = Prange; + Tmin_ = Tmin; + Tmax_ = Tmax; + Pmin_ = Pmin; + Pmax_ = Pmax; } void Chebyshev::setData(const Array2D& coeffs) @@ -390,10 +377,8 @@ void Chebyshev::getParameters(AnyMap& rateNode, const Units& rate_units) const // Return empty/unmodified AnyMap return; } - rateNode["temperature-range"].setQuantity( - {temperatureRange().first, temperatureRange().second}, "K"); - rateNode["pressure-range"].setQuantity( - {pressureRange().first, pressureRange().second}, "Pa"); + rateNode["temperature-range"].setQuantity({Tmin(), Tmax()}, "K"); + rateNode["pressure-range"].setQuantity({Pmin(), Pmax()}, "Pa"); size_t nT = m_coeffs.nRows(); size_t nP = m_coeffs.nColumns(); std::vector coeffs2d(nT, vector_fp(nP)); diff --git a/test/kinetics/kineticsFromScratch.cpp b/test/kinetics/kineticsFromScratch.cpp index f9a6eb1cfc..969628d154 100644 --- a/test/kinetics/kineticsFromScratch.cpp +++ b/test/kinetics/kineticsFromScratch.cpp @@ -187,8 +187,7 @@ TEST_F(KineticsFromScratch, add_chebyshev_reaction) coeffs(2,1) = 2.6889e-01; coeffs(2,2) = 9.4806e-02; coeffs(2,3) = -7.6385e-03; - Chebyshev rate( - std::make_pair(290., 3000.), std::make_pair(1000.0, 10000000.0), coeffs); + Chebyshev rate(290., 3000., 1000.0, 10000000.0, coeffs); auto R = make_shared(reac, prod, rate); kin.addReaction(R); diff --git a/test/kinetics/kineticsFromScratch3.cpp b/test/kinetics/kineticsFromScratch3.cpp index 29f75e4d1e..5617e765f2 100644 --- a/test/kinetics/kineticsFromScratch3.cpp +++ b/test/kinetics/kineticsFromScratch3.cpp @@ -167,8 +167,7 @@ TEST_F(KineticsFromScratch3, add_chebyshev_reaction) coeffs(2,1) = 2.6889e-01; coeffs(2,2) = 9.4806e-02; coeffs(2,3) = -7.6385e-03; - ChebyshevRate3 rate( - std::make_pair(290., 3000.), std::make_pair(1000.0, 10000000.0), coeffs); + ChebyshevRate3 rate(290., 3000., 1000.0, 10000000.0, coeffs); auto R = make_shared(reac, prod, rate); kin.addReaction(R); diff --git a/test/kinetics/kineticsFromYaml.cpp b/test/kinetics/kineticsFromYaml.cpp index 77b12166bb..db9ed11e3a 100644 --- a/test/kinetics/kineticsFromYaml.cpp +++ b/test/kinetics/kineticsFromYaml.cpp @@ -252,8 +252,8 @@ TEST(Reaction, ChebyshevFromYaml) rate->update_C(&logP); EXPECT_EQ(rate->data().nRows(), (size_t) 6); EXPECT_EQ(rate->data().nColumns(), (size_t) 4); - EXPECT_DOUBLE_EQ(rate->temperatureRange().second, 3000); - EXPECT_DOUBLE_EQ(rate->pressureRange().first, 1000); + EXPECT_DOUBLE_EQ(rate->Tmax(), 3000); + EXPECT_DOUBLE_EQ(rate->Pmin(), 1000); EXPECT_NEAR(rate->updateRC(std::log(T), 1.0/T), 130512.2773948636, 1e-9); } @@ -628,8 +628,7 @@ TEST_F(ReactionToYaml, unconvertible2) Array2D coeffs(2, 2, 1.0); ChebyshevReaction2 R({{"H2", 1}, {"OH", 1}}, {{"H2O", 1}, {"H", 1}}, - Chebyshev(std::make_pair(273., 3000.), - std::make_pair(1.e2, 1.e7), coeffs)); + Chebyshev(273., 3000., 1.e2, 1.e7, coeffs)); UnitSystem U{"g", "cm", "mol"}; AnyMap params = R.parameters(); params.setUnits(U); From 5a2999f0c0c1bc4369477569d87e98315450997e Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Thu, 16 Sep 2021 16:14:53 -0500 Subject: [PATCH 27/28] [Kinetics] Ensure member variables are reset when calling Plog::setRates --- src/kinetics/RxnRates.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/kinetics/RxnRates.cpp b/src/kinetics/RxnRates.cpp index c62913c695..863bbca7c6 100644 --- a/src/kinetics/RxnRates.cpp +++ b/src/kinetics/RxnRates.cpp @@ -218,6 +218,8 @@ void Plog::setup(const std::multimap& rates) void Plog::setRates(const std::multimap& rates) { size_t j = 0; + rates_.clear(); + pressures_.clear(); rates_.reserve(rates.size()); // Insert intermediate pressures for (const auto& rate : rates) { From c4e4a7b7690be31ae891ff56315b01b1cc0b98a3 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Thu, 16 Sep 2021 21:59:15 -0500 Subject: [PATCH 28/28] [Kinetics] Improve nomenclature for final step of Kinetics setup Update nomenclature for previously introduced finalizeSetup method; new names are Kinetics::resizeReactions and StoichManagerN::resizeCoeffs --- include/cantera/kinetics/BulkKinetics.h | 2 +- include/cantera/kinetics/GasKinetics.h | 2 +- include/cantera/kinetics/InterfaceKinetics.h | 2 +- include/cantera/kinetics/Kinetics.h | 12 +++++------ include/cantera/kinetics/StoichManager.h | 22 ++++++++++---------- interfaces/cython/cantera/_cantera.pxd | 2 +- interfaces/cython/cantera/base.pyx | 2 +- src/kinetics/BulkKinetics.cpp | 4 ++-- src/kinetics/GasKinetics.cpp | 4 ++-- src/kinetics/InterfaceKinetics.cpp | 4 ++-- src/kinetics/Kinetics.cpp | 20 +++++++++--------- src/kinetics/KineticsFactory.cpp | 2 +- src/kinetics/importKinetics.cpp | 2 +- 13 files changed, 40 insertions(+), 40 deletions(-) diff --git a/include/cantera/kinetics/BulkKinetics.h b/include/cantera/kinetics/BulkKinetics.h index ef7594578e..acd0c48f35 100644 --- a/include/cantera/kinetics/BulkKinetics.h +++ b/include/cantera/kinetics/BulkKinetics.h @@ -38,7 +38,7 @@ class BulkKinetics : public Kinetics virtual void getRevRateConstants(double* krev, bool doIrreversible = false); - virtual bool addReaction(shared_ptr r, bool finalize=true); + virtual bool addReaction(shared_ptr r, bool resize=true); virtual void modifyReaction(size_t i, shared_ptr rNew); virtual void resizeSpecies(); diff --git a/include/cantera/kinetics/GasKinetics.h b/include/cantera/kinetics/GasKinetics.h index b97b5aeb5c..7ad39b50fe 100644 --- a/include/cantera/kinetics/GasKinetics.h +++ b/include/cantera/kinetics/GasKinetics.h @@ -49,7 +49,7 @@ class GasKinetics : public BulkKinetics //! @name Reaction Mechanism Setup Routines //! @{ virtual void init(); - virtual bool addReaction(shared_ptr r, bool finalize=true); + virtual bool addReaction(shared_ptr r, bool resize=true); virtual void modifyReaction(size_t i, shared_ptr rNew); virtual void invalidateCache(); //@} diff --git a/include/cantera/kinetics/InterfaceKinetics.h b/include/cantera/kinetics/InterfaceKinetics.h index 7c7e9664e1..822aab099c 100644 --- a/include/cantera/kinetics/InterfaceKinetics.h +++ b/include/cantera/kinetics/InterfaceKinetics.h @@ -199,7 +199,7 @@ class InterfaceKinetics : public Kinetics virtual void init(); virtual void resizeSpecies(); - virtual bool addReaction(shared_ptr r, bool finalize=true); + virtual bool addReaction(shared_ptr r, bool resize=true); virtual void modifyReaction(size_t i, shared_ptr rNew); //! @} diff --git a/include/cantera/kinetics/Kinetics.h b/include/cantera/kinetics/Kinetics.h index 0227eacc8e..336dbe0076 100644 --- a/include/cantera/kinetics/Kinetics.h +++ b/include/cantera/kinetics/Kinetics.h @@ -136,7 +136,7 @@ class Kinetics } //! Finalize Kinetics object and associated objects - virtual void finalizeSetup(); + virtual void resizeReactions(); //! Number of reactions in the reaction mechanism. size_t nReactions() const { @@ -762,11 +762,11 @@ class Kinetics * Add a single reaction to the mechanism. Derived classes should call the * base class method in addition to handling their own specialized behavior. * - * @param r Pointer to the Reaction object to be added. - * @param finalize If `true`, finalize Kinetics object. + * @param r Pointer to the Reaction object to be added. + * @param resize If `true`, resizeReactions is called after reaction is added. * @return `true` if the reaction is added or `false` if it was skipped */ - virtual bool addReaction(shared_ptr r, bool finalize=true); + virtual bool addReaction(shared_ptr r, bool resize=true); /** * Modify the rate expression associated with a reaction. The @@ -925,8 +925,8 @@ class Kinetics StoichManagerN m_revProductStoich; //@} - //! Boolean indicating whether Kinetics object setup is finalized - bool m_finalized; + //! Boolean indicating whether Kinetics object is fully configured + bool m_ready; //! The number of species in all of the phases //! that participate in this kinetics mechanism. diff --git a/include/cantera/kinetics/StoichManager.h b/include/cantera/kinetics/StoichManager.h index 2a8b57e8ef..ad672f530f 100644 --- a/include/cantera/kinetics/StoichManager.h +++ b/include/cantera/kinetics/StoichManager.h @@ -459,13 +459,13 @@ class StoichManagerN * DGG - the problem is that the number of reactions and species are not * known initially. */ - StoichManagerN() : m_finalized(true) { + StoichManagerN() : m_ready(true) { m_stoichCoeffs.setZero(); m_stoichCoeffs.resize(0, 0); } - //! finalize the sparse coefficient matrix setup - void finalizeSetup(size_t nSpc, size_t nRxn) + //! Resize the sparse coefficient matrix) + void resizeCoeffs(size_t nSpc, size_t nRxn) { size_t nCoeffs = m_coeffList.size(); @@ -474,7 +474,7 @@ class StoichManagerN m_stoichCoeffs.reserve(nCoeffs); m_stoichCoeffs.setFromTriplets(m_coeffList.begin(), m_coeffList.end()); - m_finalized = true; + m_ready = true; } /** @@ -554,7 +554,7 @@ class StoichManagerN m_cn_list.emplace_back(rxn, k, order, stoich); } } - m_finalized = false; + m_ready = false; } void multiply(const doublereal* input, doublereal* output) const { @@ -595,18 +595,18 @@ class StoichManagerN //! Return matrix containing stoichiometric coefficients const Eigen::SparseMatrix& stoichCoeffs() const { - if (!m_finalized) { + if (!m_ready) { // This can happen if a user overrides default behavior: - // Kinetics::finalizeSetup is not called after adding reactions via - // Kinetics::addReaction with the 'finalize' flag set to 'false' - throw CanteraError("StoichManagerN::stoichCoeffs", - "The object is not fully configured; make sure to call finalizeSetup."); + // Kinetics::resizeReactions is not called after adding reactions via + // Kinetics::addReaction with the 'resize' flag set to 'false' + throw CanteraError("StoichManagerN::stoichCoeffs", "The object " + "is not fully configured; make sure to call resizeCoeffs()."); } return m_stoichCoeffs; } private: - bool m_finalized; //!< Boolean flag indicating whether object setup is finalized + bool m_ready; //!< Boolean flag indicating whether object is fully configured std::vector m_c1_list; std::vector m_c2_list; diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 4e2f023bc3..0826ebb60b 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -573,7 +573,7 @@ cdef extern from "cantera/kinetics/Kinetics.h" namespace "Cantera": void addReaction(shared_ptr[CxxReaction], cbool) except +translate_exception void modifyReaction(int, shared_ptr[CxxReaction]) except +translate_exception void invalidateCache() except +translate_exception - void finalizeSetup() + void resizeReactions() shared_ptr[CxxReaction] reaction(size_t) except +translate_exception cbool isReversible(int) except +translate_exception diff --git a/interfaces/cython/cantera/base.pyx b/interfaces/cython/cantera/base.pyx index 4952e242c9..997e907c1f 100644 --- a/interfaces/cython/cantera/base.pyx +++ b/interfaces/cython/cantera/base.pyx @@ -225,7 +225,7 @@ cdef class _SolutionBase: self.kinetics.skipUndeclaredThirdBodies(True) for reaction in reactions: self.kinetics.addReaction(reaction._reaction, False) - self.kinetics.finalizeSetup() + self.kinetics.resizeReactions() property input_data: """ diff --git a/src/kinetics/BulkKinetics.cpp b/src/kinetics/BulkKinetics.cpp index c847558849..faf5dfc636 100644 --- a/src/kinetics/BulkKinetics.cpp +++ b/src/kinetics/BulkKinetics.cpp @@ -99,9 +99,9 @@ void BulkKinetics::getRevRateConstants(double* krev, bool doIrreversible) } } -bool BulkKinetics::addReaction(shared_ptr r, bool finalize) +bool BulkKinetics::addReaction(shared_ptr r, bool resize) { - bool added = Kinetics::addReaction(r, finalize); + bool added = Kinetics::addReaction(r, resize); if (!added) { // undeclared species, etc. return false; diff --git a/src/kinetics/GasKinetics.cpp b/src/kinetics/GasKinetics.cpp index 2aa3fe29d1..3d8042e299 100644 --- a/src/kinetics/GasKinetics.cpp +++ b/src/kinetics/GasKinetics.cpp @@ -264,10 +264,10 @@ void GasKinetics::getFwdRateConstants(double* kfwd) } } -bool GasKinetics::addReaction(shared_ptr r, bool finalize) +bool GasKinetics::addReaction(shared_ptr r, bool resize) { // operations common to all reaction types - bool added = BulkKinetics::addReaction(r, finalize); + bool added = BulkKinetics::addReaction(r, resize); if (!added) { return false; } else if (!(r->usesLegacy())) { diff --git a/src/kinetics/InterfaceKinetics.cpp b/src/kinetics/InterfaceKinetics.cpp index 850072aace..c12c44a6f4 100644 --- a/src/kinetics/InterfaceKinetics.cpp +++ b/src/kinetics/InterfaceKinetics.cpp @@ -477,7 +477,7 @@ void InterfaceKinetics::getDeltaSSEntropy(doublereal* deltaS) getReactionDelta(m_grt.data(), deltaS); } -bool InterfaceKinetics::addReaction(shared_ptr r_base, bool finalize) +bool InterfaceKinetics::addReaction(shared_ptr r_base, bool resize) { if (!m_surf) { init(); @@ -505,7 +505,7 @@ bool InterfaceKinetics::addReaction(shared_ptr r_base, bool finalize) } size_t i = nReactions(); - bool added = Kinetics::addReaction(r_base, finalize); + bool added = Kinetics::addReaction(r_base, resize); if (!added) { return false; } diff --git a/src/kinetics/Kinetics.cpp b/src/kinetics/Kinetics.cpp index 2d0041472f..62db1fadab 100644 --- a/src/kinetics/Kinetics.cpp +++ b/src/kinetics/Kinetics.cpp @@ -24,7 +24,7 @@ using namespace std; namespace Cantera { Kinetics::Kinetics() : - m_finalized(false), + m_ready(false), m_kk(0), m_thermo(0), m_surfphase(npos), @@ -45,16 +45,16 @@ void Kinetics::checkReactionIndex(size_t i) const } } -void Kinetics::finalizeSetup() +void Kinetics::resizeReactions() { size_t nRxn = nReactions(); // Stoichiometry managers - m_reactantStoich.finalizeSetup(m_kk, nRxn); - m_productStoich.finalizeSetup(m_kk, nRxn); - m_revProductStoich.finalizeSetup(m_kk, nRxn); + m_reactantStoich.resizeCoeffs(m_kk, nRxn); + m_productStoich.resizeCoeffs(m_kk, nRxn); + m_revProductStoich.resizeCoeffs(m_kk, nRxn); - m_finalized = true; + m_ready = true; } void Kinetics::checkReactionArraySize(size_t ii) const @@ -509,7 +509,7 @@ void Kinetics::resizeSpecies() invalidateCache(); } -bool Kinetics::addReaction(shared_ptr r, bool finalize) +bool Kinetics::addReaction(shared_ptr r, bool resize) { r->validate(); if (m_kk == 0) { @@ -585,10 +585,10 @@ bool Kinetics::addReaction(shared_ptr r, bool finalize) m_perturb.push_back(1.0); m_dH.push_back(0.0); - if (finalize) { - finalizeSetup(); + if (resize) { + resizeReactions(); } else { - m_finalized = false; + m_ready = false; } return true; diff --git a/src/kinetics/KineticsFactory.cpp b/src/kinetics/KineticsFactory.cpp index 905580d4a6..af192158c3 100644 --- a/src/kinetics/KineticsFactory.cpp +++ b/src/kinetics/KineticsFactory.cpp @@ -197,7 +197,7 @@ void addReactions(Kinetics& kin, const AnyMap& phaseNode, const AnyMap& rootNode throw CanteraError("addReactions", to_string(add_rxn_err)); } - kin.finalizeSetup(); + kin.resizeReactions(); } } diff --git a/src/kinetics/importKinetics.cpp b/src/kinetics/importKinetics.cpp index cb7e26dd53..219567f0b6 100644 --- a/src/kinetics/importKinetics.cpp +++ b/src/kinetics/importKinetics.cpp @@ -127,7 +127,7 @@ bool installReactionArrays(const XML_Node& p, Kinetics& kin, kin.checkDuplicates(); } - kin.finalizeSetup(); + kin.resizeReactions(); return true; }