Skip to content

Commit

Permalink
[Thermo] ensure that SolutionArray wraps Solution setters/getters
Browse files Browse the repository at this point in the history
  • Loading branch information
Ingmar Schoegl committed Nov 3, 2019
1 parent 2050c61 commit 8058130
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 9 deletions.
2 changes: 2 additions & 0 deletions interfaces/cython/cantera/_cantera.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ cdef extern from "cantera/thermo/ThermoPhase.h" namespace "Cantera":
# miscellaneous
string type()
string report(cbool, double) except +translate_exception
cbool isStoichPhase()
cbool isIncompressible()
vector[string] defaultState()
vector[string] fullStates()
vector[string] partialStates()
Expand Down
8 changes: 8 additions & 0 deletions interfaces/cython/cantera/composite.py
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,13 @@ class SolutionArray:
'transport_model',
]

_all_states = [
# all setter/getter combos defined by the ThermoPhase base class
'TD', 'TDX', 'TDY', 'TP', 'TPX', 'TPY', 'UV', 'UVX', 'UVY',
'DP', 'DPX', 'DPY', 'HP', 'HPX', 'HPY', 'SP', 'SPX', 'SPY',
'SV', 'SVX', 'SVY'
]

_interface_passthrough = ['site_density']
_interface_n_species = ['coverages']

Expand Down Expand Up @@ -531,6 +538,7 @@ def __init__(self, phase, shape=(0,), states=None, extra=None):

# add properties dynamically
state_sets = set(phase._full_states.values()) | set(phase._partial_states.values())
state_sets = state_sets | set(self._all_states)
for name in state_sets:
ph = type(phase)
if len(name) == 2:
Expand Down
26 changes: 18 additions & 8 deletions interfaces/cython/cantera/test/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ def test_load_thermo_models(self):
# (converted to errors in test suite)
if 'Deprecated' not in str(inst):

msg = "Error in processing of phase with type '{}'"
raise TypeError(msg.format(ph['thermo'])) from inst
msg = "Error in processing of phase '{}' with type '{}'"
msg = msg.format(ph['name'], ph['thermo'])
raise TypeError(msg) from inst

def test_restore_thermo_models(self):

Expand All @@ -75,18 +76,26 @@ def check(a, b):

try:
sol = ct.Solution(yml_file, ph_name)

a = ct.SolutionArray(sol, 10)

# assign some state
T = 373.15 + 100*np.random.rand(10)
P = a.P * (1 + np.random.rand(10))
X = a.X
if sol.n_species > 1:
X = a.X
X[:, 1] = .01
X = np.diag(X.sum(axis=1)).dot(X)
a.TPX = T, np.linspace(1., 2., 10), X
self.assertFalse(sol._is_stoich_phase)
self.assertIn('TPX', sol._full_states.values())
a.TPX = T, P, X
else:
a.TP = T, np.linspace(1., 2., 10)
a.TP = T, P
if sol._is_stoich_phase:
# filter out thermo phases with ambigious definitions
# (single species, but not defined as stoich substance)
self.assertNotIn('TPX', sol._full_states.values())
with self.assertRaises(AttributeError):
a.TPX = T, P, X

# default columns
data, labels = a.collect_data()
Expand All @@ -101,8 +110,9 @@ def check(a, b):
# (converted to errors in test suite)
if 'Deprecated' not in str(inst):

msg = "Error in processing of phase with type '{}'"
raise TypeError(msg.format(ph['thermo'])) from inst
msg = "Error in processing of phase '{}' with type '{}'"
msg = msg.format(ph['name'], ph['thermo'])
raise TypeError(msg) from inst


class TestRestoreIdealGas(utilities.CanteraTest):
Expand Down
16 changes: 15 additions & 1 deletion interfaces/cython/cantera/thermo.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,20 @@ cdef class ThermoPhase(_SolutionBase):
def __call__(self, *args, **kwargs):
print(self.report(*args, **kwargs))

property _is_stoich_phase:
"""
Phase represents a stoichiometric (fixed composition) substance
"""
def __get__(self):
return self.thermo.isStoichPhase()

property _is_incompressible:
"""
Phase represents an incompressible substance
"""
def __get__(self):
return self.thermo.isIncompressible()

property _default_state:
"""
Default properties defining a state
Expand Down Expand Up @@ -316,7 +330,7 @@ cdef class ThermoPhase(_SolutionBase):
Check whether *prop* represents a settable (partial) thermodynamic state
"""
valid = any([prop in self._full_states.values(),
prop in self._partial_states.values()])
prop in self._partial_states.values()])
if not valid:
raise AttributeError("Setter '{}' is not available "
"for phase '{}'".format(prop, self.name))
Expand Down

0 comments on commit 8058130

Please sign in to comment.