[Python] Implement Reaction constructors from YAML files/strings

This commit is contained in:
Ray Speth 2019-02-20 22:49:44 -05:00
parent 8037497dd3
commit 69371e5751
5 changed files with 87 additions and 3 deletions

View file

@ -284,6 +284,11 @@ unique_ptr<Reaction> newReaction(const AnyMap& rxn_node, const Kinetics& kin);
//! bulk (e.g. gas) phases
std::vector<shared_ptr<Reaction> > getReactions(const XML_Node& node);
//! Create Reaction objects for each item (an AnyMap) in `items`. The species
//! involved in these reactions must exist in the phases associated with the
//! Kinetics object `kinetics`.
std::vector<shared_ptr<Reaction>> getReactions(const AnyValue& items,
Kinetics& kinetics);
}
#endif

View file

@ -256,7 +256,9 @@ cdef extern from "cantera/thermo/SurfPhase.h":
cdef extern from "cantera/kinetics/Reaction.h" namespace "Cantera":
cdef shared_ptr[CxxReaction] CxxNewReaction "newReaction" (XML_Node&) except +translate_exception
cdef shared_ptr[CxxReaction] CxxNewReaction "newReaction" (CxxAnyMap&, CxxKinetics&) except +translate_exception
cdef vector[shared_ptr[CxxReaction]] CxxGetReactions "getReactions" (XML_Node&) except +translate_exception
cdef vector[shared_ptr[CxxReaction]] CxxGetReactions "getReactions" (CxxAnyValue&, CxxKinetics&) except +translate_exception
cdef cppclass CxxArrhenius "Cantera::Arrhenius":
CxxArrhenius()

View file

@ -79,10 +79,28 @@ cdef class Reaction:
return wrapReaction(cxx_reaction)
@staticmethod
def listFromFile(filename):
def fromYaml(text, Kinetics kinetics):
"""
Create a `Reaction` object from its YAML string representation.
:param text:
The YAML reaction string
:param kinetics:
A `Kinetics` object whose associated phase(s) contain the species
involved in the reaction.
"""
cxx_reaction = CxxNewReaction(AnyMapFromYamlString(stringify(text)),
deref(kinetics.kinetics))
return wrapReaction(cxx_reaction)
@staticmethod
def listFromFile(filename, Kinetics kinetics=None, section='reactions'):
"""
Create a list of Reaction objects from all of the reactions defined in a
CTI or XML file.
YAML, CTI, or XML file.
For YAML input files, a `Kinetics` object is required as the second
argument, and reactions from the section *section* will be returned.
Directories on Cantera's input file path will be searched for the
specified file.
@ -91,7 +109,14 @@ cdef class Reaction:
children of the ``<reactionsData>`` node in a document with a ``<ctml>``
root node, as in the XML files produced by conversion from CTI files.
"""
cxx_reactions = CxxGetReactions(deref(CxxGetXmlFile(stringify(filename))))
if filename.lower().split('.')[-1] in ('yml', 'yaml'):
if kinetics is None:
raise ValueError("A Kinetics object is required.")
root = AnyMapFromYamlFile(stringify(filename))
cxx_reactions = CxxGetReactions(root[stringify(section)],
deref(kinetics.kinetics))
else:
cxx_reactions = CxxGetReactions(deref(CxxGetXmlFile(stringify(filename))))
return [wrapReaction(r) for r in cxx_reactions]
@staticmethod
@ -116,6 +141,17 @@ cdef class Reaction:
cxx_reactions = CxxGetReactions(deref(CxxGetXmlFromString(stringify(text))))
return [wrapReaction(r) for r in cxx_reactions]
@staticmethod
def listFromYaml(text, Kinetics kinetics):
"""
Create a list of `Reaction` objects from all the reactions defined in a
YAML string.
"""
root = AnyMapFromYamlString(stringify(text))
cxx_reactions = CxxGetReactions(root[stringify("items")],
deref(kinetics.kinetics))
return [wrapReaction(r) for r in cxx_reactions]
property reactant_string:
"""
A string representing the reactants side of the chemical equation for

View file

@ -767,6 +767,23 @@ class TestReaction(utilities.CanteraTest):
self.assertEqual(r.efficiencies['H2O'], 15.4)
self.assertEqual(r.rate.temperature_exponent, -1.0)
def test_fromYaml(self):
r = ct.Reaction.fromYaml(
"{equation: 2 O + M <=> O2 + M,"
" type: three-body,"
" rate-constant: {A: 1.2e+11, b: -1.0, Ea: 0.0},"
" efficiencies: {H2: 2.4, H2O: 15.4, AR: 0.83}}",
self.gas)
self.assertTrue(isinstance(r, ct.ThreeBodyReaction))
self.assertEqual(r.reactants['O'], 2)
self.assertEqual(r.products['O2'], 1)
self.assertEqual(r.efficiencies['H2O'], 15.4)
self.assertEqual(r.rate.temperature_exponent, -1.0)
self.assertIn('O', r)
self.assertIn('O2', r)
self.assertNotIn('H2O', r)
def test_listFromFile(self):
R = ct.Reaction.listFromFile('h2o2.xml')
eq1 = [r.equation for r in R]
@ -789,6 +806,20 @@ class TestReaction(utilities.CanteraTest):
eq2 = [r.equation for r in self.gas.reactions()]
self.assertEqual(eq1, eq2)
def test_listFromYaml(self):
yaml = """
- equation: O + H2 <=> H + OH # Reaction 3
rate-constant: {A: 3.87e+04, b: 2.7, Ea: 6260.0}
- equation: O + HO2 <=> OH + O2 # Reaction 4
rate-constant: {A: 2.0e+13, b: 0.0, Ea: 0.0}
- equation: O + H2O2 <=> OH + HO2 # Reaction 5
rate-constant: {A: 9.63e+06, b: 2.0, Ea: 4000.0}
"""
R = ct.Reaction.listFromYaml(yaml, self.gas)
self.assertEqual(len(R), 3)
self.assertIn('HO2', R[2].products)
self.assertEqual(R[0].rate.temperature_exponent, 2.7)
def test_elementary(self):
r = ct.ElementaryReaction({'O':1, 'H2':1}, {'H':1, 'OH':1})
r.rate = ct.Arrhenius(3.87e1, 2.7, 6260*1000*4.184)

View file

@ -1080,4 +1080,14 @@ std::vector<shared_ptr<Reaction> > getReactions(const XML_Node& node)
return all_reactions;
}
std::vector<shared_ptr<Reaction>> getReactions(const AnyValue& items,
Kinetics& kinetics)
{
std::vector<shared_ptr<Reaction>> all_reactions;
for (const auto& node : items.asVector<AnyMap>()) {
all_reactions.emplace_back(newReaction(node, kinetics));
};
return all_reactions;
}
}