[Python] Add ability to create ThermoPhase objects from Species

This makes it possible to create a phase without ever generating a CTI
or XML description. Does not yet work with phase types that require
additional parameters.
This commit is contained in:
Ray Speth 2015-04-20 21:55:42 -04:00
parent 9fdf7c0c59
commit dc3af8a58d
3 changed files with 56 additions and 11 deletions

View file

@ -84,6 +84,11 @@ cdef extern from "cantera/thermo/ThermoPhase.h" namespace "Cantera":
cbool getElementPotentials(double*) except +
void equilibrate(string, string, double, int, int, int, int) except +
# initialization
void addUndefinedElements() except +
cbool addSpecies(shared_ptr[CxxSpecies]) except +
void initThermo() except +
# basic thermodynamic properties
double temperature() except +
double pressure() except +
@ -387,9 +392,11 @@ cdef extern from "cantera/zeroD/ReactorNet.h":
cdef extern from "cantera/thermo/ThermoFactory.h" namespace "Cantera":
cdef CxxThermoPhase* newPhase(string, string) except +
cdef CxxThermoPhase* newPhase(XML_Node&) except +
cdef CxxThermoPhase* newThermoPhase(string) except +
cdef extern from "cantera/kinetics/KineticsFactory.h" namespace "Cantera":
cdef CxxKinetics* newKineticsMgr(XML_Node&, vector[CxxThermoPhase*]) except +
cdef CxxKinetics* CxxNewKinetics "Cantera::newKineticsMgr" (string) except +
cdef extern from "cantera/transport/TransportFactory.h" namespace "Cantera":
cdef CxxTransport* newDefaultTransportMgr(CxxThermoPhase*) except +

View file

@ -1,6 +1,6 @@
cdef class _SolutionBase:
def __cinit__(self, infile='', phaseid='', phases=(), origin=None,
source=None, **kwargs):
source=None, thermo=None, species=(), **kwargs):
# Shallow copy of an existing Solution (for slicing support)
cdef _SolutionBase other
if origin is not None:
@ -18,13 +18,31 @@ cdef class _SolutionBase:
self._selected_species = other._selected_species.copy()
return
# Instantiate a set of new Cantera C++ objects
if infile or source:
self._init_cti_xml(infile, phaseid, phases, source)
elif thermo and species:
self._init_parts(thermo, species)
else:
raise ValueError("Arguments are insufficient to define a phase")
# Initialization of transport is deferred to Transport.__init__
self.transport = NULL
self._selected_species = np.ndarray(0, dtype=np.integer)
def __init__(self, *args, **kwargs):
if isinstance(self, Transport):
assert self.transport is not NULL
def _init_cti_xml(self, infile, phaseid, phases, source):
"""
Instantiate a set of new Cantera C++ objects from a CTI or XML
phase definition
"""
if infile:
rootNode = CxxGetXmlFile(stringify(infile))
elif source:
rootNode = CxxGetXmlFromString(stringify(source))
else:
raise ValueError('No phase definition provided')
# Get XML data
cdef XML_Node* phaseNode
@ -54,14 +72,21 @@ cdef class _SolutionBase:
else:
self.kinetics = NULL
# Initialization of transport is deferred to Transport.__init__
self.transport = NULL
def _init_parts(self, thermo, species):
"""
Instantiate a set of new Cantera C++ objects based on a string defining
the model type and a list of Species objects.
"""
self.thermo = newThermoPhase(stringify(thermo))
self.thermo.addUndefinedElements()
cdef Species S
for S in species:
self.thermo.addSpecies(S._species)
self.thermo.initThermo()
self._selected_species = np.ndarray(0, dtype=np.integer)
def __init__(self, *args, **kwargs):
if isinstance(self, Transport):
assert self.transport is not NULL
if isinstance(self, Kinetics):
# Not yet implemented
self.kinetics = CxxNewKinetics(stringify("none"))
def __getitem__(self, selection):
copy = self.__class__(origin=self)

View file

@ -620,6 +620,19 @@ ideal_gas(name='spam', elements='O H',
gas = ct.Solution(source=xml_def)
self.check(gas, 'spam', 350, 2e6, 2, 1)
def test_import_from_species(self):
gas1 = ct.Solution('h2o2.xml')
gas1.TPX = 350, 101325, 'H2:0.3, O2:0.7'
gas1.equilibrate('HP')
species = ct.Species.listFromFile('h2o2.xml')
gas2 = ct.ThermoPhase(thermo='IdealGas', species=species)
gas2.TPX = 350, 101325, 'H2:0.3, O2:0.7'
gas2.equilibrate('HP')
self.assertEqual(gas1.n_elements, gas2.n_elements)
self.assertEqual(gas1.species_names, gas2.species_names)
self.assertNear(gas1.T, gas2.T)
self.assertArrayNear(gas1.X, gas2.X)
def test_checkReactionBalance(self):
with self.assertRaises(Exception):