[Python] Implement Species constructors from YAML files/strings

This commit is contained in:
Ray Speth 2019-02-19 00:04:56 -05:00
parent 040ffe4711
commit 8037497dd3
6 changed files with 78 additions and 12 deletions

View file

@ -79,6 +79,9 @@ unique_ptr<Species> newSpecies(const AnyMap& node);
//! respectively, where the string or file is formatted as either CTI or XML.
std::vector<shared_ptr<Species> > getSpecies(const XML_Node& node);
//! Generate Species objects for each item (an AnyMap) in `items`.
std::vector<shared_ptr<Species>> getSpecies(const AnyValue& items);
}
#endif

View file

@ -116,6 +116,8 @@ cdef extern from "cantera/thermo/Species.h" namespace "Cantera":
cdef shared_ptr[CxxSpecies] CxxNewSpecies "newSpecies" (XML_Node&)
cdef vector[shared_ptr[CxxSpecies]] CxxGetSpecies "getSpecies" (XML_Node&)
cdef shared_ptr[CxxSpecies] CxxNewSpecies "newSpecies" (CxxAnyMap&) except +translate_exception
cdef vector[shared_ptr[CxxSpecies]] CxxGetSpecies "getSpecies" (CxxAnyValue&) except +translate_exception
cdef extern from "cantera/thermo/ThermoPhase.h" namespace "Cantera":
cdef cppclass CxxThermoPhase "Cantera::ThermoPhase":

View file

@ -1022,6 +1022,10 @@ class TestSpecies(utilities.CanteraTest):
self.assertEqual({sp.name for sp in S},
set(self.gas.species_names))
def test_listfromFile_yaml(self):
S = ct.Species.listFromFile('ideal-gas.yaml')
self.assertEqual(S[0].name, 'O2')
def test_listFromCti(self):
p = os.path.dirname(__file__)
with open(pjoin(p, '..', 'data', 'h2o2.cti')) as f:
@ -1030,6 +1034,20 @@ class TestSpecies(utilities.CanteraTest):
self.assertEqual({sp.name for sp in S},
set(self.gas.species_names))
def test_listFomYaml(self):
yaml = '''
- name: H2O
composition: {H: 2, O: 1}
thermo: {model: constant-cp, h0: 100}
- name: HO2
composition: {H: 1, O: 2}
thermo: {model: constant-cp, h0: 200}
'''
species = ct.Species.listFromYaml(yaml)
self.assertEqual(species[0].name, 'H2O')
self.assertEqual(species[1].composition, {'H': 1, 'O': 2})
self.assertNear(species[0].thermo.h(300), 100)
def test_listFromXml(self):
p = os.path.dirname(__file__)
with open(pjoin(p, '..', 'data', 'h2o2.xml')) as f:

View file

@ -37,15 +37,14 @@ cdef class Species:
ch4.transport = tran
gas = ct.Solution(thermo='IdealGas', species=[ch4])
The static methods `fromCti`, `fromXml`, `listFromFile`, `listFromCti`, and
`listFromXml` can be used to create `Species` objects from existing
definitions in the CTI or XML formats. All of the following will produce a
list of 53 `Species` objects containing the species defined in the GRI 3.0
mechanism::
The static methods `fromYaml`, `fromCti`, `fromXml`, `listFromFile`,
`listFromYaml`, `listFromCti`, and `listFromXml` can be used to create
`Species` objects from existing definitions in the CTI or XML formats.
Either of the following will produce a list of 53 `Species` objects
containing the species defined in the GRI 3.0 mechanism::
S = ct.Species.listFromFile('gri30.cti')
S = ct.Species.listFromCti(open('path/to/gri30.cti').read())
S = ct.Species.listFromXml(open('path/to/gri30.xml').read())
S = ct.Species.listFromFile('gri30.yaml')
S = ct.Species.listFromYaml(open('path/to/gri30.yaml').read())
"""
def __cinit__(self, *args, init=True, **kwargs):
@ -96,10 +95,21 @@ cdef class Species:
return species
@staticmethod
def listFromFile(filename):
def fromYaml(text):
"""
Create a Species object from its YAML string representation.
"""
cxx_species = CxxNewSpecies(AnyMapFromYamlString(stringify(text)))
species = Species(init=False)
species._assign(cxx_species)
return species
@staticmethod
def listFromFile(filename, section='species'):
"""
Create a list of Species objects from all of the species defined in a
CTI or XML file.
YAML, CTI or XML file. For YAML files, return species from the section
*section*.
Directories on Cantera's input file path will be searched for the
specified file.
@ -108,7 +118,12 @@ cdef class Species:
children of the ``<speciesData>`` node in a document with a ``<ctml>``
root node, as in the XML files produced by conversion from CTI files.
"""
cxx_species = CxxGetSpecies(deref(CxxGetXmlFile(stringify(filename))))
if filename.lower().split('.')[-1] in ('yml', 'yaml'):
root = AnyMapFromYamlFile(stringify(filename))
cxx_species = CxxGetSpecies(root[stringify(section)])
else:
cxx_species = CxxGetSpecies(deref(CxxGetXmlFile(stringify(filename))))
species = []
for a in cxx_species:
b = Species(init=False)
@ -148,6 +163,21 @@ cdef class Species:
species.append(b)
return species
@staticmethod
def listFromYaml(text):
"""
Create a list of Species objects from all the species defined in a YAML
string.
"""
root = AnyMapFromYamlString(stringify(text))
cxx_species = CxxGetSpecies(root[stringify("items")])
species = []
for a in cxx_species:
b = Species(init=False)
b._assign(a)
species.append(b)
return species
property name:
""" The name of the species. """
def __get__(self):

View file

@ -149,7 +149,11 @@ struct convert<Cantera::AnyMap> {
}
static bool decode(const Node& node, Cantera::AnyMap& target) {
target.setLoc(node.Mark().line, node.Mark().column);
if (!node.IsMap()) {
if (node.IsSequence()) {
// Convert a top-level list to a map with the key "items"
target["items"] = node.as<AnyValue>();
return true;
} else if (!node.IsMap()) {
std::string text = YAML::Dump(node);
if (text.size() > 300) {
text.resize(300);

View file

@ -127,4 +127,13 @@ std::vector<shared_ptr<Species> > getSpecies(const XML_Node& node)
return all_species;
}
std::vector<shared_ptr<Species>> getSpecies(const AnyValue& items)
{
std::vector<shared_ptr<Species> > all_species;
for (const auto& node : items.asVector<AnyMap>()) {
all_species.emplace_back(newSpecies(node));
}
return all_species;
}
}