Add Interface class as a specialized version of Solution

This class provides access to the thermo and kinetics objects as the
correct derived types, i.e. SurfPhase and InterfaceKinetics, so
methods defined only for these derived types can be called easily.
This commit is contained in:
Ray Speth
2022-01-02 13:41:34 -05:00
committed by Ingmar Schoegl
parent eff534ff50
commit 7785d6cf0e
9 changed files with 220 additions and 49 deletions

View File

@@ -48,6 +48,7 @@ phases:
X: {CH4: 0.095, O2: 0.21, AR: 0.79}
- name: Pt_surf
thermo: ideal-surface
adjacent-phases: [gas]
elements: [Pt, H, O, C]
species: [PT(S), H(S), H2O(S), OH(S), CO(S), CO2(S), CH3(S), CH2(S)s,
CH(S), C(S), O(S)]

View File

@@ -0,0 +1,99 @@
//! @file Interface.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_INTERFACE_H
#define CT_INTERFACE_H
#include "cantera/base/Solution.h"
#include "cantera/thermo/SurfPhase.h"
#include "cantera/kinetics/InterfaceKinetics.h"
namespace Cantera
{
//! A container class holding managers for all pieces defining an interface
class Interface : public Solution
{
private:
Interface();
public:
~Interface() {}
Interface(const Interface&) = delete;
Interface& operator=(const Interface&) = delete;
//! Create an empty Interface object
static shared_ptr<Interface> create() {
return shared_ptr<Interface>(new Interface());
}
//! Set the reacting phase thermo object
void setThermo(shared_ptr<ThermoPhase> thermo) override;
//! Set the Kinetics object
void setKinetics(shared_ptr<Kinetics> kinetics) override;
//! Get the surface phase thermo object
shared_ptr<SurfPhase> thermo() {
return m_surf;
}
//! Get the surface phase Kinetics object
shared_ptr<InterfaceKinetics> kinetics() {
return m_surfkin;
}
protected:
shared_ptr<SurfPhase> m_surf; //!< Surface phase ThermoPhase manager
shared_ptr<InterfaceKinetics> m_surfkin; //!< Kinetics manager
};
//! Create and initialize a new Interface from an input file
/*!
* This constructor wraps newPhase() and newKinetics()
*
* @param infile name of the input file
* @param name name of the surface phase in the file.
* If this is blank, the first phase in the file is used.
* @param adjacent vector containing names of adjacent phases that participate in this
* phases kinetics. If empty, adjacent phases will be instantiated based
* on the phase definition.
* @returns an initialized Interface object.
*/
shared_ptr<Interface> newInterface(const std::string& infile,
const std::string& name="", const std::vector<std::string>& adjacent={});
//! Create and initialize a new Interface from an input file
/*!
* This constructor wraps newPhase() and newKinetics()
*
* @param infile name of the input file
* @param name name of the phase in the file. If this is the empty string, the first
* phase in the file is used.
* @param adjacent vector containing adjacent Solution objects. If empty, adjacent
* phases will be instantiated based on the phase definition.
* @returns an initialized Interface object.
*/
shared_ptr<Interface> newInterface(const std::string& infile,
const std::string& name, const std::vector<shared_ptr<Solution>>& adjacent);
//! Create and initialize a new Interface from AnyMap objects
/*!
* This constructor wraps newPhase() and newKinetics()
*
* @param phaseNode the node containing the phase definition (i.e. thermo model,
* list of species, and initial state)
* @param rootNode the root node of the tree containing the phase definition, which
* will be used as the default location from which to read species definitions.
* @param adjacent vector containing adjacent Solution objects. If empty, adjacent
* phases will be instantiated based on the phase definition.
* @returns an initialized Interface object.
*/
shared_ptr<Interface> newInterface(AnyMap& phaseNode, const AnyMap& rootNode=AnyMap(),
const std::vector<shared_ptr<Solution>>& adjacent={});
}
#endif

View File

@@ -19,11 +19,11 @@ class Transport;
//! A container class holding managers for all pieces defining a phase
class Solution
{
private:
protected:
Solution();
public:
~Solution() {}
virtual ~Solution() {}
Solution(const Solution&) = delete;
Solution& operator=(const Solution&) = delete;
@@ -39,13 +39,13 @@ public:
void setName(const std::string& name);
//! Set the ThermoPhase object
void setThermo(shared_ptr<ThermoPhase> thermo);
virtual void setThermo(shared_ptr<ThermoPhase> thermo);
//! Set the Kinetics object
void setKinetics(shared_ptr<Kinetics> kinetics);
virtual void setKinetics(shared_ptr<Kinetics> kinetics);
//! Set the Transport object
void setTransport(shared_ptr<Transport> transport);
virtual void setTransport(shared_ptr<Transport> transport);
//! Accessor for the ThermoPhase pointer
shared_ptr<ThermoPhase> thermo() {

74
src/base/Interface.cpp Normal file
View File

@@ -0,0 +1,74 @@
//! @file Interface.cpp
// 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.
#include "cantera/base/Interface.h"
#include "cantera/thermo/ThermoFactory.h"
#include "cantera/kinetics/KineticsFactory.h"
namespace Cantera
{
using std::string;
using std::vector;
Interface::Interface() {}
void Interface::setThermo(shared_ptr<ThermoPhase> thermo) {
Solution::setThermo(thermo);
auto surf = std::dynamic_pointer_cast<SurfPhase>(thermo);
if (!surf) {
throw CanteraError("Interface::setThermo",
"Thermo object of type '{}' does not descend from SurfPhase.",
thermo->type());
}
m_surf = surf;
}
void Interface::setKinetics(shared_ptr<Kinetics> kinetics) {
Solution::setKinetics(kinetics);
auto surfkin = std::dynamic_pointer_cast<InterfaceKinetics>(kinetics);
if (!surfkin) {
throw CanteraError("Interface::setKinetics",
"Kinetics object of type '{}' does not descend from InterfaceKinetics.",
kinetics->kineticsType());
}
m_surfkin = surfkin;
}
shared_ptr<Interface> newInterface(const std::string& infile,
const std::string& name, const std::vector<std::string>& adjacent)
{
auto sol = newSolution(infile, name, "", adjacent);
auto iface = std::dynamic_pointer_cast<Interface>(sol);
if (!iface) {
auto rootNode = AnyMap::fromYamlFile(infile);
AnyMap& phaseNode = rootNode["phases"].getMapWhere("name", name);
throw InputFileError("newInterface", phaseNode,
"Phase definition does not define a surface phase");
}
return iface;
}
shared_ptr<Interface> newInterface(const std::string& infile,
const std::string& name, const std::vector<shared_ptr<Solution>>& adjacent)
{
auto rootNode = AnyMap::fromYamlFile(infile);
AnyMap& phaseNode = rootNode["phases"].getMapWhere("name", name);
return newInterface(phaseNode, rootNode, adjacent);
}
shared_ptr<Interface> newInterface(AnyMap& phaseNode, const AnyMap& rootNode,
const std::vector<shared_ptr<Solution>>& adjacent)
{
auto sol = newSolution(phaseNode, rootNode, "", adjacent);
auto iface = std::dynamic_pointer_cast<Interface>(sol);
if (!iface) {
throw InputFileError("newInterface", phaseNode,
"Phase definition does not define a surface phase");
}
return iface;
}
} // end namespace Cantera

View File

@@ -7,6 +7,7 @@
// at https://cantera.org/license.txt for license and copyright information.
#include "cantera/base/Solution.h"
#include "cantera/base/Interface.h"
#include "cantera/thermo/ThermoPhase.h"
#include "cantera/thermo/ThermoFactory.h"
#include "cantera/kinetics/Kinetics.h"
@@ -193,12 +194,20 @@ shared_ptr<Solution> newSolution(const AnyMap& phaseNode,
const std::string& transport,
const std::vector<shared_ptr<Solution>>& adjacent)
{
// instantiate Solution object
auto sol = Solution::create();
sol->setSource("custom YAML");
// thermo phase
sol->setThermo(shared_ptr<ThermoPhase>(newPhase(phaseNode, rootNode)));
auto thermo = shared_ptr<ThermoPhase>(newPhase(phaseNode, rootNode));
// instantiate Solution object of the correct derived type
shared_ptr<Solution> sol;
switch (thermo->nDim()) {
case 2:
sol = Interface::create();
break;
default:
sol = Solution::create();
}
sol->setSource("custom YAML");
sol->setThermo(thermo);
// Add explicitly-specified adjacent phases
for (auto& adj : adjacent) {

View File

@@ -2,9 +2,9 @@
#include "cantera/thermo.h"
#include "cantera/kinetics.h"
#include "cantera/thermo/IdealGasPhase.h"
#include "cantera/thermo/SurfPhase.h"
#include "cantera/kinetics/GasKinetics.h"
#include "cantera/base/Solution.h"
#include "cantera/base/Interface.h"
namespace Cantera
{
@@ -202,16 +202,14 @@ TEST_F(NegativePreexponentialFactor, fromYaml)
}
TEST(InterfaceReaction, CoverageDependency) {
IdealGasPhase gas("ptcombust.yaml", "gas");
SurfPhase surf("ptcombust.yaml", "Pt_surf");
shared_ptr<Kinetics> kin(newKinetics({&surf, &gas}, "ptcombust.yaml", "Pt_surf"));
ASSERT_EQ(kin->nReactions(), (size_t) 24);
auto iface = newInterface("ptcombust.yaml", "Pt_surf");
ASSERT_EQ(iface->kinetics()->nReactions(), (size_t) 24);
double T = 500;
surf.setState_TP(T, 101325);
surf.setCoveragesByName("PT(S):0.7, H(S):0.3");
vector_fp kf(kin->nReactions());
kin->getFwdRateConstants(&kf[0]);
iface->thermo()->setState_TP(T, 101325);
iface->thermo()->setCoveragesByName("PT(S):0.7, H(S):0.3");
vector_fp kf(iface->kinetics()->nReactions());
iface->kinetics()->getFwdRateConstants(&kf[0]);
EXPECT_NEAR(kf[0], 4.4579e7 * pow(T, 0.5), 1e-14*kf[0]);
// Energies in XML file are converted from J/mol to J/kmol
EXPECT_NEAR(kf[1], 3.7e20 * exp(-(67.4e6-6e6*0.3)/(GasConstant*T)), 1e-14*kf[1]);

View File

@@ -22,6 +22,7 @@ phases:
species: [CB-CB3]
- name: soot_interface
thermo: ideal-surface
adjacent-phases: [gas, soot]
elements: [H, C]
species: [Csoot-*, Csoot-H]
kinetics: surface

View File

@@ -1,6 +1,6 @@
Gas Temperature = 1.4e+03
Gas Pressure = 1.01e+05
Gas Phase: gas (0)
Gas Phase: gas (2)
Name Conc MoleF SrcRate
(kmol/m^3) (kmol/m^2/s)
0 H 8.7e-05 0.00999 -2.366e-03
@@ -15,7 +15,7 @@ Gas Phase: gas (0)
9 O2 8.7e-06 0.000999 -9.061e-07
Sum of gas mole fractions= 1
Bulk Phase: soot (10)
Bulk Phase: soot (12)
Bulk Temperature = 1.4e+03
Bulk Pressure = 1.01e+05
Name Conc MoleF SrcRate
@@ -28,7 +28,7 @@ Density of bulk phase = 3.52e+03 kg / m^3
= 3.52 gm / cm^3
Sum of bulk mole fractions= 1
Surface Phase: soot_interface (11)
Surface Phase: soot_interface (0)
Surface Temperature = 1.4e+03
Surface Pressure = 1.01e+05
Name Coverage SrcRate
@@ -37,7 +37,7 @@ Surface Pressure = 1.01e+05
Sum of coverages = 1
Gas Temperature = 1.4e+03
Gas Pressure = 1.01e+05
Gas Phase: gas (0)
Gas Phase: gas (2)
Name Conc MoleF SrcRate
(kmol/m^3) (kmol/m^2/s)
0 H 0.000113 0.013 -3.122e-03
@@ -52,7 +52,7 @@ Gas Phase: gas (0)
9 O2 8.7e-06 0.000999 -9.129e-07
Sum of gas mole fractions= 1
Bulk Phase: soot (10)
Bulk Phase: soot (12)
Bulk Temperature = 1.4e+03
Bulk Pressure = 1.01e+05
Name Conc MoleF SrcRate
@@ -65,7 +65,7 @@ Density of bulk phase = 3.52e+03 kg / m^3
= 3.52 gm / cm^3
Sum of bulk mole fractions= 1
Surface Phase: soot_interface (11)
Surface Phase: soot_interface (0)
Surface Temperature = 1.4e+03
Surface Pressure = 1.01e+05
Name Coverage SrcRate
@@ -74,7 +74,7 @@ Surface Pressure = 1.01e+05
Sum of coverages = 1
Gas Temperature = 1.5e+03
Gas Pressure = 1.01e+05
Gas Phase: gas (0)
Gas Phase: gas (2)
Name Conc MoleF SrcRate
(kmol/m^3) (kmol/m^2/s)
0 H 0.000106 0.013 -3.833e-03
@@ -89,7 +89,7 @@ Gas Phase: gas (0)
9 O2 8.14e-06 0.000999 -1.324e-06
Sum of gas mole fractions= 1
Bulk Phase: soot (10)
Bulk Phase: soot (12)
Bulk Temperature = 1.5e+03
Bulk Pressure = 1.01e+05
Name Conc MoleF SrcRate
@@ -102,7 +102,7 @@ Density of bulk phase = 3.52e+03 kg / m^3
= 3.52 gm / cm^3
Sum of bulk mole fractions= 1
Surface Phase: soot_interface (11)
Surface Phase: soot_interface (0)
Surface Temperature = 1.5e+03
Surface Pressure = 1.01e+05
Name Coverage SrcRate
@@ -111,7 +111,7 @@ Surface Pressure = 1.01e+05
Sum of coverages = 1
Gas Temperature = 1.5e+03
Gas Pressure = 1.01e+05
Gas Phase: gas (0)
Gas Phase: gas (2)
Name Conc MoleF SrcRate
(kmol/m^3) (kmol/m^2/s)
0 H 0.000106 0.013 -3.833e-03
@@ -126,7 +126,7 @@ Gas Phase: gas (0)
9 O2 8.14e-06 0.000999 -1.324e-06
Sum of gas mole fractions= 1
Bulk Phase: soot (10)
Bulk Phase: soot (12)
Bulk Temperature = 1.5e+03
Bulk Pressure = 1.01e+05
Name Conc MoleF SrcRate
@@ -139,7 +139,7 @@ Density of bulk phase = 3.52e+03 kg / m^3
= 3.52 gm / cm^3
Sum of bulk mole fractions= 1
Surface Phase: soot_interface (11)
Surface Phase: soot_interface (0)
Surface Temperature = 1.5e+03
Surface Pressure = 1.01e+05
Name Coverage SrcRate

View File

@@ -6,7 +6,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.
#include "cantera/thermo/ThermoFactory.h"
#include "cantera/base/Interface.h"
#include "cantera/thermo/SurfPhase.h"
#include "cantera/kinetics.h"
#include "cantera/kinetics/ImplicitSurfChem.h"
#include "cantera/kinetics/InterfaceKinetics.h"
@@ -141,27 +142,22 @@ int main(int argc, char** argv)
int ioflag = 1;
try {
/*************************************************************/
/************************************************************/
ThermoPhase* gasTP = newPhase(infile, gasPhaseName);
auto iface = newInterface(infile, surfParticlePhaseName);
ThermoPhase* gasTP = iface->adjacent(gasPhaseName)->thermo().get();
size_t nspGas = gasTP->nSpecies();
cout << "Number of species = " << nspGas << endl;
ThermoPhase* bulkPhaseTP = newPhase(infile, bulkParticlePhaseName);
ThermoPhase* bulkPhaseTP = iface->adjacent(bulkParticlePhaseName)->thermo().get();
size_t nspBulk = bulkPhaseTP->nSpecies();
cout << "Number of species in bulk phase named " <<
bulkParticlePhaseName << " = " << nspBulk << endl;
ThermoPhase* surfPhaseTP = newPhase(infile, surfParticlePhaseName);
ThermoPhase* surfPhaseTP = iface->thermo().get();
size_t nsp_d100 = surfPhaseTP->nSpecies();
cout << "Number of species in surface phase, " << surfParticlePhaseName
<< " = " << nsp_d100 << endl;
auto kin = newKinetics({gasTP, bulkPhaseTP, surfPhaseTP},
infile, surfParticlePhaseName);
InterfaceKinetics* iKin_ptr = dynamic_cast<InterfaceKinetics*>(kin.get());
InterfaceKinetics* iKin_ptr = iface->kinetics().get();
size_t nr = iKin_ptr->nReactions();
cout << "Number of reactions = " << nr << endl;
@@ -248,13 +244,6 @@ int main(int argc, char** argv)
printGas(ofile, gasTP, iKin_ptr, src);
printBulk(ofile, bulkPhaseTP, iKin_ptr, src);
printSurf(ofile, surfPhaseTP, iKin_ptr, src) ;
delete gasTP;
gasTP = 0;
delete bulkPhaseTP;
bulkPhaseTP = 0;
delete surfPhaseTP;
surfPhaseTP = 0;
appdelete();
} catch (CanteraError& err) {
std::cout << err.what() << std::endl;