[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
This commit is contained in:
Ingmar Schoegl 2019-10-26 00:37:28 -05:00 committed by Ray Speth
parent 43d02e95e3
commit 40ae5b5fb5
13 changed files with 155 additions and 27 deletions

View file

@ -20,16 +20,38 @@ class Solution : public std::enable_shared_from_this<Solution>
{
private:
Solution();
Solution(const std::string& infile, std::string name, std::string transport,
std::vector<shared_ptr<Solution> > adjacent);
public:
~Solution() {}
Solution(const Solution&) = delete;
Solution& operator=(const Solution&) = delete;
//! Create an empty Solution object
static shared_ptr<Solution> create() {
return shared_ptr<Solution>( 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<Solution> create(const std::string& infile,
std::string name="",
std::string transport="",
std::vector<shared_ptr<Solution> > adjacent={}) {
return shared_ptr<Solution>( 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<ThermoPhase> thermoPtr() {
return m_thermo;
}
//! Accessor for the Kinetics pointer
shared_ptr<Kinetics> kineticsPtr() {
return m_kinetics;
}
//! Accessor for the Transport pointer
shared_ptr<Transport> transportPtr() {
return m_transport;
}
protected:
shared_ptr<ThermoPhase> m_thermo; //!< ThermoPhase manager
shared_ptr<Kinetics> m_kinetics; //!< Kinetics manager
shared_ptr<Transport> m_transport; //!< Transport manager
};
/**
* Create a new solution manager.
*/
inline shared_ptr<Solution> newSolution(const std::string& infile, std::string name="",
std::string transport="",
std::vector<shared_ptr<Solution> > adjacent={}) {
return Solution::create(infile, name, transport, adjacent);
}
}
#endif

View file

@ -119,6 +119,19 @@ protected:
void updateKc();
};
/**
* Return a pointer to an GasKinetics object contained in Solution.
*/
inline shared_ptr<GasKinetics> getGasKineticsPtr(shared_ptr<Solution> sol) {
auto kin = sol->kineticsPtr();
if (kin->kineticsType()=="Surf") {
return std::dynamic_pointer_cast<GasKinetics>(kin);
} else {
throw CanteraError("getGasKineticsPtr",
"Incompatible kinetics");
}
}
}
#endif

View file

@ -678,6 +678,20 @@ protected:
//! EdgeKinetics)
size_t m_nDim;
};
/**
* Return a pointer to an InterfaceKinetics object contained in Solution.
*/
inline shared_ptr<InterfaceKinetics> getInterfaceKineticsPtr(shared_ptr<Solution> sol) {
auto kin = sol->kineticsPtr();
if (kin->kineticsType()=="Surf") {
return std::dynamic_pointer_cast<InterfaceKinetics>(kin);
} else {
throw CanteraError("getInterfaceKineticsPtr",
"Incompatible kinetics");
}
}
}
#endif

View file

@ -19,8 +19,6 @@
namespace Cantera
{
class Solution;
/**
* @defgroup chemkinetics Chemical Kinetics
*/

View file

@ -631,6 +631,20 @@ private:
*/
void _updateThermo() const;
};
/**
* Return a pointer to an IdealGasPhase object contained in Solution.
*/
inline shared_ptr<IdealGasPhase> getIdealGasPhasePtr(shared_ptr<Solution> sol) {
auto ph = sol->thermoPtr();
if (ph->type()=="IdealGas") {
return std::dynamic_pointer_cast<IdealGasPhase>(ph);
} else {
throw CanteraError("getIdealGasPhasePtr",
"Incompatible phase");
}
}
}
#endif

View file

@ -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

View file

@ -447,6 +447,20 @@ private:
*/
void _updateThermo(bool force=false) const;
};
/**
* Return a pointer to an SurfPhase object contained in Solution.
*/
inline shared_ptr<SurfPhase> getSurfPhasePtr(shared_ptr<Solution> sol) {
auto ph = sol->thermoPtr();
if (ph->type()=="Surf") {
return std::dynamic_pointer_cast<SurfPhase>(ph);
} else {
throw CanteraError("getSurfPhasePtr",
"Incompatible phase");
}
}
}
#endif

View file

@ -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

View file

@ -64,6 +64,11 @@ public:
setKineticsMgr(contents);
}
void insert(shared_ptr<Solution> sol) {
setThermoMgr(sol->thermo());
setKineticsMgr(sol->kinetics());
}
virtual void setKineticsMgr(Kinetics& kin);
virtual void setChemistry(bool cflag = true) {

View file

@ -35,6 +35,10 @@ public:
void insert(ThermoPhase& contents) {
setThermoMgr(contents);
}
void insert(shared_ptr<Solution> sol) {
setThermoMgr(sol->thermo());
}
};
}

View file

@ -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<shared_ptr<Solution> > adjacent) {
// thermo phase
m_thermo = shared_ptr<ThermoPhase>(newPhase(infile, name));
// kinetics
std::vector<ThermoPhase*> 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<Transport>(newDefaultTransportMgr(m_thermo.get()));
} else if (transport!="None") {
m_transport = shared_ptr<Transport>(newTransportMgr(transport, m_thermo.get()));
}
}
std::string Solution::name() const {
if (m_thermo) {
return m_thermo->name();

View file

@ -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<ThreeBodyReaction&>(*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<FalloffReaction&>(*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<FalloffReaction&>(*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<ChemicallyActivatedReaction&>(*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<PlogReaction&>(*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<ChebyshevReaction&>(*R);
double logP = std::log10(2e6);

View file

@ -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);