Skip to content

Commit

Permalink
[Python] Add Solution.state to allow faster iteration over states
Browse files Browse the repository at this point in the history
  • Loading branch information
speth committed Jul 9, 2016
1 parent 78d275b commit 21a1be8
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 29 deletions.
2 changes: 2 additions & 0 deletions interfaces/cython/cantera/_cantera.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ cdef extern from "cantera/thermo/ThermoPhase.h" namespace "Cantera":
double refPressure() except +
cbool getElementPotentials(double*) except +
void equilibrate(string, string, double, int, int, int, int) except +
void saveState(size_t, double*)
void restoreState(size_t, double*)

# initialization
void addUndefinedElements() except +
Expand Down
50 changes: 21 additions & 29 deletions interfaces/cython/cantera/composite.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ def setter(self, value):
return property(getter, setter, doc=getattr(Solution, attr).__doc__)

for _attr in dir(Solution):
if _attr.startswith('_') or _attr in Quantity.__dict__:
if _attr.startswith('_') or _attr in Quantity.__dict__ or _attr == 'state':
continue
else:
setattr(Quantity, _attr, _prop(_attr))
Expand All @@ -205,37 +205,22 @@ def __init__(self, phase, shape, states=None):
else:
self._shape = shape
S = np.empty(shape + (2+self._phase.n_species,))
S[...,0], S[...,1], S[...,2:] = self._phase.TDY
S[:] = self._phase.state
self._states = S

self._indices = list(np.ndindex(self._shape))

def __iter__(self):
"""
Iterate over states, with the phase object set to the corresponding
state.
"""
for index in self._indices:
state = self._states[index]
self._phase.TDY = state[0], state[1], state[2:]
yield index

def items(self):
for index in self._indices:
state = self._states[index]
self._phase.TDY = state[0], state[1], state[2:]
yield index, state

def __getitem__(self, index):
states = self._states[index]
shape = states.shape[:-1]
return SolutionArray(self._phase, shape, states)

def equilibrate(self, *args, **kwargs):
""" See `ThermoPhase.equilibrate` """
for index, state in self.items():
for index in self._indices:
self._phase.state = self._states[index]
self._phase.equilibrate(*args, **kwargs)
state[0], state[1], state[2:] = self._phase.TDY
self._states[index][:] = self._phase.state


def _make_functions():
Expand Down Expand Up @@ -270,16 +255,18 @@ def state2_prop(name):
def getter(self):
a = np.empty(self._shape)
b = np.empty(self._shape)
for index in self:
for index in self._indices:
self._phase.state = self._states[index]
a[index], b[index] = getattr(self._phase, name)
return a, b

def setter(self, AB):
assert len(AB) == 2, "Expected 2 elements, got {}".format(len(AB))
A, B, _ = np.broadcast_arrays(AB[0], AB[1], self._states[...,0])
for index, state in self.items():
for index in self._indices:
self._phase.state = self._states[index]
setattr(self._phase, name, (A[index], B[index]))
state[0], state[1], state[2:] = self._phase.TDY
self._states[index][:] = self._phase.state

return property(getter, setter, doc=getattr(Solution, name).__doc__)

Expand All @@ -293,17 +280,19 @@ def getter(self):
a = np.empty(self._shape)
b = np.empty(self._shape)
c = np.empty(self._shape + (self._phase.n_species,))
for index in self:
for index in self._indices:
self._phase.state = self._states[index]
a[index], b[index], c[index] = getattr(self._phase, name)
return a, b, c

def setter(self, ABC):
assert len(ABC) == 3, "Expected 3 elements, got {}".format(len(ABC))
A, B, C, _ = np.broadcast_arrays(ABC[0], ABC[1], ABC[2],
self._states[...,0])
for index, state in self.items():
for index in self._indices:
self._phase.state = self._states[index]
setattr(self._phase, name, (A[index], B[index], C[index]))
state[0], state[1], state[2:] = self._phase.TDY
self._states[index][:] = self._phase.state

return property(getter, setter, doc=getattr(Solution, name).__doc__)

Expand All @@ -313,7 +302,8 @@ def setter(self, ABC):
def scalar_prop(name):
def getter(self):
v = np.empty(self._shape)
for index in self:
for index in self._indices:
self._phase.state = self._states[index]
v[index] = getattr(self._phase, name)
return v
return property(getter, doc=getattr(Solution, name).__doc__)
Expand All @@ -324,7 +314,8 @@ def getter(self):
def species_prop(name):
def getter(self):
v = np.empty(self._shape + (self._phase.n_species,))
for index in self:
for index in self._indices:
self._phase.state = self._states[index]
v[index] = getattr(self._phase, name)
return v
return property(getter, doc=getattr(Solution, name).__doc__)
Expand All @@ -336,7 +327,8 @@ def getter(self):
def caller(name):
def wrapper(self, *args, **kwargs):
v = np.empty(self._shape)
for index in self:
for index in self._indices:
self._phase.state = self._states[index]
v[index] = getattr(self._phase, name)(*args, **kwargs)
return v
return wrapper
Expand Down
16 changes: 16 additions & 0 deletions interfaces/cython/cantera/thermo.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,22 @@ cdef class ThermoPhase(_SolutionBase):

######## Methods to get/set the complete thermodynamic state ########

property state:
"""
Get/Set the full thermodynamic state as a single array, arranged as
[temperature, density, mass fractions] for most phases. Useful mainly
in cases where it is desired to store many states in a multidimensional
array.
"""
def __get__(self):
cdef np.ndarray[np.double_t, ndim=1] state = np.empty(self.n_species + 2)
self.thermo.saveState(len(state), &state[0])
return state

def __set__(self, state):
cdef np.ndarray[np.double_t, ndim=1] cstate = np.asarray(state)
self.thermo.restoreState(len(state), &cstate[0])

property TD:
"""Get/Set temperature [K] and density [kg/m^3 or kmol/m^3]."""
def __get__(self):
Expand Down

0 comments on commit 21a1be8

Please sign in to comment.