[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:
parent
370ba39a8c
commit
bcbdd25101
3 changed files with 62 additions and 19 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue