[Python] Added "slicing" support to Solution

Slicing a Solution object (with the [] operator) creates a view where all
species-specific properties are returned for the specified subset of the
species.
This commit is contained in:
Ray Speth 2012-09-06 19:57:53 +00:00
parent 370ba39a8c
commit bcbdd25101
3 changed files with 62 additions and 19 deletions

View file

@ -1,6 +1,10 @@
from libcpp.vector cimport vector
from libcpp.string cimport string
from libcpp cimport bool as cbool
from cpython cimport bool as pybool
import numpy as np
cimport numpy as np
cdef extern from "cantera/base/xml.h" namespace "Cantera":
cdef cppclass XML_Node:
@ -271,6 +275,8 @@ cdef class _SolutionBase:
cdef CxxKinetics* kinetics
cdef CxxTransport* transport
cdef int thermoBasis
cdef np.ndarray _selectedSpecies
cdef object parent
cdef class Mixture:
cdef CxxMultiPhase* mix

View file

@ -1,5 +1,23 @@
cdef class _SolutionBase:
def __cinit__(self, infile, phaseid='', phases=()):
def __cinit__(self, infile='', phaseid='', phases=(), source=None):
# Shallow copy of an existing Solution (for slicing support)
cdef _SolutionBase other
if source is not None:
other = <_SolutionBase?>source
# keep a reference to the parent to prevent the underlying
# C++ objects from being deleted
self.parent = other
self.thermo = other.thermo
self.kinetics = other.kinetics
self.transport = other.transport
self.thermoBasis = other.thermoBasis
self._selectedSpecies = other._selectedSpecies.copy()
return
# Instantiate a set of new Cantera C++ objects
rootNode = getCtmlTree(stringify(infile))
# Get XML data
@ -33,11 +51,34 @@ cdef class _SolutionBase:
# Initialization of transport is deferred to Transport.__init__
self.transport = NULL
self._selectedSpecies = np.ndarray(0, dtype=np.integer)
def __init__(self, *args, **kwargs):
if isinstance(self, Transport):
assert self.transport is not NULL
def __getitem__(self, selection):
copy = self.__class__(source=self)
if isinstance(selection, slice):
selection = range(selection.start or 0,
selection.stop or self.nSpecies,
selection.step or 1)
copy.selectedSpecies = selection
return copy
property selectedSpecies:
def __get__(self):
return list(self._selectedSpecies)
def __set__(self, species):
if isinstance(species, (str, int)):
species = (species,)
self._selectedSpecies.resize(len(species))
for i,spec in enumerate(species):
self._selectedSpecies[i] = self.speciesIndex(spec)
def __dealloc__(self):
del self.thermo
del self.kinetics
del self.transport
# only delete the C++ objects if this is the parent object
if self.parent is None:
del self.thermo
del self.kinetics
del self.transport

View file

@ -7,7 +7,8 @@ ctypedef void (*thermoMethod1d)(CxxThermoPhase*, double*) except +
cdef class ThermoPhase(_SolutionBase):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.thermoBasis = massBasis
if 'source' not in kwargs:
self.thermoBasis = massBasis
def report(self, show_thermo=True):
return pystr(self.thermo.report(bool(show_thermo)))
@ -85,7 +86,11 @@ cdef class ThermoPhase(_SolutionBase):
property speciesNames:
def __get__(self):
return [self.speciesName(k) for k in range(self.nSpecies)]
if self._selectedSpecies.size:
indices = self._selectedSpecies
else:
indices = range(self.nSpecies)
return [self.speciesName(k) for k in indices]
cpdef int speciesIndex(self, species) except *:
if isinstance(species, str):
@ -107,7 +112,10 @@ cdef class ThermoPhase(_SolutionBase):
cdef np.ndarray _getArray1(self, thermoMethod1d method):
cdef np.ndarray[np.double_t, ndim=1] data = np.empty(self.nSpecies)
method(self.thermo, &data[0])
return data
if self._selectedSpecies.size:
return data[self._selectedSpecies]
else:
return data
cdef void _setArray1(self, thermoMethod1d method, values) except *:
if len(values) != self.nSpecies:
@ -121,9 +129,6 @@ cdef class ThermoPhase(_SolutionBase):
def __get__(self):
return self._getArray1(thermo_getMolecularWeights)
def molecularWeight(self, species):
return self.thermo.molecularWeight(self.speciesIndex(species))
property meanMolecularWeight:
def __get__(self):
return self.thermo.meanMolecularWeight()
@ -137,9 +142,6 @@ cdef class ThermoPhase(_SolutionBase):
else:
self._setArray1(thermo_setMassFractions, Y)
def massFraction(self, species):
return self.thermo.massFraction(self.speciesIndex(species))
property X:
def __get__(self):
return self._getArray1(thermo_getMoleFractions)
@ -149,18 +151,12 @@ cdef class ThermoPhase(_SolutionBase):
else:
self._setArray1(thermo_setMoleFractions, X)
def moleFraction(self, species):
return self.thermo.moleFraction(self.speciesIndex(species))
property concentrations:
def __get__(self):
return self._getArray1(thermo_getConcentrations)
def __set__(self, C):
self._setArray1(thermo_setConcentrations, C)
def concentration(self, species):
return self.thermo.concentration(self.speciesIndex(species))
######## Read-only thermodynamic properties ########
property P: