diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index a302b6d67..b443e59e4 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -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 + diff --git a/interfaces/cython/cantera/base.pyx b/interfaces/cython/cantera/base.pyx index af30bb4cc..a254c58ad 100644 --- a/interfaces/cython/cantera/base.pyx +++ b/interfaces/cython/cantera/base.pyx @@ -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) diff --git a/interfaces/cython/cantera/test/test_thermo.py b/interfaces/cython/cantera/test/test_thermo.py index c4b6fbd9c..3c47061cf 100644 --- a/interfaces/cython/cantera/test/test_thermo.py +++ b/interfaces/cython/cantera/test/test_thermo.py @@ -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):