From 40ae5b5fb5a37588123b142ef2dadd3ec5d58b5e Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Sat, 26 Oct 2019 00:37:28 -0500 Subject: [PATCH] [Base] implement initialization of C++ Solution from input files - implement constructor that loads ThermoPhase, Kinetics, and Transport from input files (wrapping factory class methods) - logic for selection of transport manager follows Python object - add convenience methods to type-cast frequently used classes --- include/cantera/base/Solution.h | 46 ++++++++++++++++++++ include/cantera/kinetics/GasKinetics.h | 13 ++++++ include/cantera/kinetics/InterfaceKinetics.h | 14 ++++++ include/cantera/kinetics/Kinetics.h | 2 - include/cantera/thermo/IdealGasPhase.h | 14 ++++++ include/cantera/thermo/Phase.h | 3 +- include/cantera/thermo/SurfPhase.h | 14 ++++++ include/cantera/transport/TransportBase.h | 2 - include/cantera/zeroD/Reactor.h | 5 +++ include/cantera/zeroD/Reservoir.h | 4 ++ src/base/Solution.cpp | 25 +++++++++++ test/kinetics/kineticsFromYaml.cpp | 36 ++++++++------- test/thermo/nasapoly.cpp | 4 +- 13 files changed, 155 insertions(+), 27 deletions(-) diff --git a/include/cantera/base/Solution.h b/include/cantera/base/Solution.h index bf886a95d..d50b0762a 100644 --- a/include/cantera/base/Solution.h +++ b/include/cantera/base/Solution.h @@ -20,16 +20,38 @@ class Solution : public std::enable_shared_from_this { private: Solution(); + Solution(const std::string& infile, std::string name, std::string transport, + std::vector > adjacent); public: ~Solution() {} Solution(const Solution&) = delete; Solution& operator=(const Solution&) = delete; + //! Create an empty Solution object static shared_ptr create() { return shared_ptr( new Solution ); } + //! Create and initialize a Solution object from an input file + /*! + * This constructor wraps newPhase(), newKinetics() and + * newTransportMgr() routines for initialization. + * + * @param infile name of the input file + * @param name name of the phase in the file. + * If this is blank, the first phase in the file is used. + * @param transport name of the transport model. + * @param adjacent vector containing adjacent solution objects. + * @returns an initialized Solution object. + */ + static shared_ptr create(const std::string& infile, + std::string name="", + std::string transport="", + std::vector > adjacent={}) { + return shared_ptr( new Solution(infile, name, transport, adjacent) ); + } + //! Return the name of this Solution object std::string name() const; @@ -60,11 +82,35 @@ public: return *m_transport; } + //! Accessor for the ThermoPhase pointer + shared_ptr thermoPtr() { + return m_thermo; + } + + //! Accessor for the Kinetics pointer + shared_ptr kineticsPtr() { + return m_kinetics; + } + + //! Accessor for the Transport pointer + shared_ptr transportPtr() { + return m_transport; + } + protected: shared_ptr m_thermo; //!< ThermoPhase manager shared_ptr m_kinetics; //!< Kinetics manager shared_ptr m_transport; //!< Transport manager }; +/** + * Create a new solution manager. + */ +inline shared_ptr newSolution(const std::string& infile, std::string name="", + std::string transport="", + std::vector > adjacent={}) { + return Solution::create(infile, name, transport, adjacent); +} + } #endif diff --git a/include/cantera/kinetics/GasKinetics.h b/include/cantera/kinetics/GasKinetics.h index 3e9c41367..b3056d79d 100644 --- a/include/cantera/kinetics/GasKinetics.h +++ b/include/cantera/kinetics/GasKinetics.h @@ -119,6 +119,19 @@ protected: void updateKc(); }; +/** + * Return a pointer to an GasKinetics object contained in Solution. + */ +inline shared_ptr getGasKineticsPtr(shared_ptr sol) { + auto kin = sol->kineticsPtr(); + if (kin->kineticsType()=="Surf") { + return std::dynamic_pointer_cast(kin); + } else { + throw CanteraError("getGasKineticsPtr", + "Incompatible kinetics"); + } +} + } #endif diff --git a/include/cantera/kinetics/InterfaceKinetics.h b/include/cantera/kinetics/InterfaceKinetics.h index 1311e07f8..ac7a78244 100644 --- a/include/cantera/kinetics/InterfaceKinetics.h +++ b/include/cantera/kinetics/InterfaceKinetics.h @@ -678,6 +678,20 @@ protected: //! EdgeKinetics) size_t m_nDim; }; + +/** + * Return a pointer to an InterfaceKinetics object contained in Solution. + */ +inline shared_ptr getInterfaceKineticsPtr(shared_ptr sol) { + auto kin = sol->kineticsPtr(); + if (kin->kineticsType()=="Surf") { + return std::dynamic_pointer_cast(kin); + } else { + throw CanteraError("getInterfaceKineticsPtr", + "Incompatible kinetics"); + } +} + } #endif diff --git a/include/cantera/kinetics/Kinetics.h b/include/cantera/kinetics/Kinetics.h index 57b285395..ba903e6e2 100644 --- a/include/cantera/kinetics/Kinetics.h +++ b/include/cantera/kinetics/Kinetics.h @@ -19,8 +19,6 @@ namespace Cantera { -class Solution; - /** * @defgroup chemkinetics Chemical Kinetics */ diff --git a/include/cantera/thermo/IdealGasPhase.h b/include/cantera/thermo/IdealGasPhase.h index 5bd7a73cd..4e3437ea3 100644 --- a/include/cantera/thermo/IdealGasPhase.h +++ b/include/cantera/thermo/IdealGasPhase.h @@ -631,6 +631,20 @@ private: */ void _updateThermo() const; }; + +/** + * Return a pointer to an IdealGasPhase object contained in Solution. + */ +inline shared_ptr getIdealGasPhasePtr(shared_ptr sol) { + auto ph = sol->thermoPtr(); + if (ph->type()=="IdealGas") { + return std::dynamic_pointer_cast(ph); + } else { + throw CanteraError("getIdealGasPhasePtr", + "Incompatible phase"); + } +} + } #endif diff --git a/include/cantera/thermo/Phase.h b/include/cantera/thermo/Phase.h index 7f5c37fd7..0151da7b7 100644 --- a/include/cantera/thermo/Phase.h +++ b/include/cantera/thermo/Phase.h @@ -10,6 +10,7 @@ #define CT_PHASE_H #include "cantera/base/ctexceptions.h" +#include "cantera/base/Solution.h" #include "cantera/thermo/Elements.h" #include "cantera/thermo/Species.h" #include "cantera/base/ValueCache.h" @@ -29,8 +30,6 @@ namespace Cantera * support thermodynamic calculations (see \ref thermoprops). */ -class Solution; - //! Class Phase is the base class for phases of matter, managing the species and //! elements in a phase, as well as the independent variables of temperature, //! mass density, species mass/mole fraction, and other generalized forces and diff --git a/include/cantera/thermo/SurfPhase.h b/include/cantera/thermo/SurfPhase.h index 6316e0a4b..0319c9b96 100644 --- a/include/cantera/thermo/SurfPhase.h +++ b/include/cantera/thermo/SurfPhase.h @@ -447,6 +447,20 @@ private: */ void _updateThermo(bool force=false) const; }; + +/** + * Return a pointer to an SurfPhase object contained in Solution. + */ + inline shared_ptr getSurfPhasePtr(shared_ptr sol) { + auto ph = sol->thermoPtr(); + if (ph->type()=="Surf") { + return std::dynamic_pointer_cast(ph); + } else { + throw CanteraError("getSurfPhasePtr", + "Incompatible phase"); + } +} + } #endif diff --git a/include/cantera/transport/TransportBase.h b/include/cantera/transport/TransportBase.h index 664d47d2a..1726c2ea1 100644 --- a/include/cantera/transport/TransportBase.h +++ b/include/cantera/transport/TransportBase.h @@ -74,8 +74,6 @@ const VelocityBasis VB_SPECIES_2 = 2; const VelocityBasis VB_SPECIES_3 = 3; //@} -class Solution; - //! Base class for transport property managers. /*! * All classes that compute transport properties for a single phase derive from diff --git a/include/cantera/zeroD/Reactor.h b/include/cantera/zeroD/Reactor.h index 26e3825fa..83ba78460 100644 --- a/include/cantera/zeroD/Reactor.h +++ b/include/cantera/zeroD/Reactor.h @@ -64,6 +64,11 @@ public: setKineticsMgr(contents); } + void insert(shared_ptr sol) { + setThermoMgr(sol->thermo()); + setKineticsMgr(sol->kinetics()); + } + virtual void setKineticsMgr(Kinetics& kin); virtual void setChemistry(bool cflag = true) { diff --git a/include/cantera/zeroD/Reservoir.h b/include/cantera/zeroD/Reservoir.h index 427fa9380..2884cf288 100644 --- a/include/cantera/zeroD/Reservoir.h +++ b/include/cantera/zeroD/Reservoir.h @@ -35,6 +35,10 @@ public: void insert(ThermoPhase& contents) { setThermoMgr(contents); } + + void insert(shared_ptr sol) { + setThermoMgr(sol->thermo()); + } }; } diff --git a/src/base/Solution.cpp b/src/base/Solution.cpp index 85e0f1877..8c4f8b20a 100644 --- a/src/base/Solution.cpp +++ b/src/base/Solution.cpp @@ -8,14 +8,39 @@ #include "cantera/base/Solution.h" #include "cantera/thermo/ThermoPhase.h" +#include "cantera/thermo/ThermoFactory.h" #include "cantera/kinetics/Kinetics.h" +#include "cantera/kinetics/KineticsFactory.h" #include "cantera/transport/TransportBase.h" +#include "cantera/transport/TransportFactory.h" namespace Cantera { Solution::Solution() {} + Solution::Solution(const std::string& infile, std::string name, std::string transport, + std::vector > adjacent) { + + // thermo phase + m_thermo = shared_ptr(newPhase(infile, name)); + + // kinetics + std::vector phases; + for (auto & adj : adjacent) { + phases.push_back(adj->thermoPtr().get()); + } + phases.push_back(m_thermo.get()); + m_kinetics = std::move(newKinetics(phases, infile, name)); + + // transport + if (transport=="") { + m_transport = shared_ptr(newDefaultTransportMgr(m_thermo.get())); + } else if (transport!="None") { + m_transport = shared_ptr(newTransportMgr(transport, m_thermo.get())); + } +} + std::string Solution::name() const { if (m_thermo) { return m_thermo->name(); diff --git a/test/kinetics/kineticsFromYaml.cpp b/test/kinetics/kineticsFromYaml.cpp index bc0586edd..fe494341d 100644 --- a/test/kinetics/kineticsFromYaml.cpp +++ b/test/kinetics/kineticsFromYaml.cpp @@ -1,6 +1,6 @@ #include "gtest/gtest.h" #include "cantera/base/Units.h" -#include "cantera/IdealGasMix.h" +#include "cantera/kinetics/GasKinetics.h" #include "cantera/thermo/SurfPhase.h" #include "cantera/kinetics/KineticsFactory.h" #include "cantera/thermo/ThermoFactory.h" @@ -9,15 +9,13 @@ using namespace Cantera; TEST(Reaction, ElementaryFromYaml) { - // @TODO: Use of XML input files in these tests of the YAML format needs to - // be eliminated before we can deprecate the XML format. - IdealGasMix gas("gri30.xml"); + auto sol = newSolution("gri30.yaml"); AnyMap rxn = AnyMap::fromYamlString( "{equation: N + NO <=> N2 + O," " rate-constant: [-2.70000E+13 cm^3/mol/s, 0, 355 cal/mol]," " negative-A: true}"); - auto R = newReaction(rxn, gas); + auto R = newReaction(rxn, sol->kinetics()); EXPECT_EQ(R->reactants.at("NO"), 1); EXPECT_EQ(R->products.at("N2"), 1); EXPECT_EQ(R->reaction_type, ELEMENTARY_RXN); @@ -31,14 +29,14 @@ TEST(Reaction, ElementaryFromYaml) TEST(Reaction, ThreeBodyFromYaml1) { - IdealGasMix gas("gri30.xml"); + auto sol = newSolution("gri30.yaml"); AnyMap rxn = AnyMap::fromYamlString( "{equation: 2 O + M = O2 + M," " type: three-body," " rate-constant: [1.20000E+17 cm^6/mol^2/s, -1, 0]," " efficiencies: {AR: 0.83, H2O: 5}}"); - auto R = newReaction(rxn, gas); + auto R = newReaction(rxn, sol->kinetics()); EXPECT_EQ(R->reactants.count("M"), (size_t) 0); auto TBR = dynamic_cast(*R); @@ -49,18 +47,18 @@ TEST(Reaction, ThreeBodyFromYaml1) TEST(Reaction, ThreeBodyFromYaml2) { - IdealGasMix gas("gri30.xml"); + auto sol = newSolution("gri30.yaml"); AnyMap rxn = AnyMap::fromYamlString( "{equation: 2 O <=> O2," // Missing "M" on each side of the equation " type: three-body," " rate-constant: [1.20000E+17, -1, 0]}"); - EXPECT_THROW(newReaction(rxn, gas), CanteraError); + EXPECT_THROW(newReaction(rxn, sol->kinetics()), CanteraError); } TEST(Reaction, FalloffFromYaml1) { - IdealGasMix gas("gri30.xml"); + auto sol = newSolution("gri30.yaml"); AnyMap rxn = AnyMap::fromYamlString( "{equation: N2O (+M) = N2 + O (+ M)," " type: falloff," @@ -69,7 +67,7 @@ TEST(Reaction, FalloffFromYaml1) " SRI: {A: 1.1, B: 700.0, C: 1234.0, D: 56.0, E: 0.7}," " efficiencies: {AR: 0.625}}"); - auto R = newReaction(rxn, gas); + auto R = newReaction(rxn, sol->kinetics()); auto FR = dynamic_cast(*R); EXPECT_DOUBLE_EQ(FR.third_body.efficiency("AR"), 0.625); EXPECT_DOUBLE_EQ(FR.third_body.efficiency("N2"), 1.0); @@ -77,7 +75,7 @@ TEST(Reaction, FalloffFromYaml1) TEST(Reaction, FalloffFromYaml2) { - IdealGasMix gas("gri30.xml"); + auto sol = newSolution("gri30.yaml"); AnyMap rxn = AnyMap::fromYamlString( "{equation: H + CH2 (+ N2) <=> CH3 (+N2)," " type: falloff," @@ -86,7 +84,7 @@ TEST(Reaction, FalloffFromYaml2) " Troe: {A: 0.562, T3: 91, T1: 5836}," " source: somewhere}"); - auto R = newReaction(rxn, gas); + auto R = newReaction(rxn, sol->kinetics()); auto FR = dynamic_cast(*R); EXPECT_DOUBLE_EQ(FR.third_body.efficiency("N2"), 1.0); EXPECT_DOUBLE_EQ(FR.third_body.efficiency("H2O"), 0.0); @@ -103,7 +101,7 @@ TEST(Reaction, FalloffFromYaml2) TEST(Reaction, ChemicallyActivatedFromYaml) { - IdealGasMix gas("gri30.xml"); + auto sol = newSolution("gri30.yaml"); AnyMap rxn = AnyMap::fromYamlString( "{equation: CH3 + OH (+M) <=> CH2O + H2 (+M)," " units: {length: cm, quantity: mol}," @@ -111,7 +109,7 @@ TEST(Reaction, ChemicallyActivatedFromYaml) " high-P-rate-constant: [5.88E-14, 6.721, -3022.227]," " low-P-rate-constant: [282320.078, 1.46878, -3270.56495]}"); - auto R = newReaction(rxn, gas); + auto R = newReaction(rxn, sol->kinetics()); auto CAR = dynamic_cast(*R); EXPECT_DOUBLE_EQ(CAR.high_rate.preExponentialFactor(), 5.88e-14); EXPECT_DOUBLE_EQ(CAR.low_rate.preExponentialFactor(), 2.82320078e2); @@ -120,7 +118,7 @@ TEST(Reaction, ChemicallyActivatedFromYaml) TEST(Reaction, PlogFromYaml) { - IdealGasMix gas("gri30.xml"); + auto sol = newSolution("gri30.yaml"); AnyMap rxn = AnyMap::fromYamlString( "equation: 'H + CH4 <=> H2 + CH3'\n" "units: {pressure: atm}\n" @@ -131,7 +129,7 @@ TEST(Reaction, PlogFromYaml) "- {P: 1.0 atm, A: 1.230000e+04, b: 2.68, Ea: 6335.0}\n" "- {P: 1.01325 MPa, A: 1.680000e+16, b: -0.6, Ea: 14754.0}"); - auto R = newReaction(rxn, gas); + auto R = newReaction(rxn, sol->kinetics()); auto PR = dynamic_cast(*R); const auto& rates = PR.rate.rates(); EXPECT_EQ(rates.size(), (size_t) 4); @@ -145,7 +143,7 @@ TEST(Reaction, PlogFromYaml) TEST(Reaction, ChebyshevFromYaml) { - IdealGasMix gas("gri30.xml"); + auto sol = newSolution("gri30.yaml"); AnyMap rxn = AnyMap::fromYamlString( "equation: 'CH4 <=> CH3 + H'\n" "type: Chebyshev\n" @@ -158,7 +156,7 @@ TEST(Reaction, ChebyshevFromYaml) " [-2.26210e-01, 1.69190e-01, 4.85810e-03, -2.38030e-03],\n" " [-1.43220e-01, 7.71110e-02, 1.27080e-02, -6.41540e-04]]\n"); - auto R = newReaction(rxn, gas); + auto R = newReaction(rxn, sol->kinetics()); EXPECT_EQ(R->reactants.size(), (size_t) 1); auto CR = dynamic_cast(*R); double logP = std::log10(2e6); diff --git a/test/thermo/nasapoly.cpp b/test/thermo/nasapoly.cpp index 89c2f5bb3..119ebe596 100644 --- a/test/thermo/nasapoly.cpp +++ b/test/thermo/nasapoly.cpp @@ -1,6 +1,6 @@ #include "gtest/gtest.h" #include "cantera/thermo/NasaPoly1.h" -#include "cantera/IdealGasMix.h" +#include "cantera/thermo/IdealGasPhase.h" namespace Cantera { @@ -94,7 +94,7 @@ TEST_F(NasaPoly1Test, updatePropertiesTemp) TEST(Nasa9Test, Nasa9Thermo) { - IdealGasMix g("../data/gasNASA9.xml", "nasa9"); + IdealGasPhase g("gasNASA9.xml", "nasa9"); size_t nsp = g.nSpecies(); double pres = 1.0E5; vector_fp Xset(nsp, 0.0);