From 69177fc0d87fdf895602099ecf6e2b278f338131 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Sun, 3 Nov 2019 09:33:20 -0600 Subject: [PATCH] [Thermo] ensure that SolutionArray wraps Solution setters/getters --- interfaces/cython/cantera/_cantera.pxd | 2 ++ interfaces/cython/cantera/composite.py | 8 ++++++ interfaces/cython/cantera/test/test_models.py | 26 +++++++++++++------ interfaces/cython/cantera/thermo.pyx | 14 ++++++++++ 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 5a082885e..0ae88642d 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -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() diff --git a/interfaces/cython/cantera/composite.py b/interfaces/cython/cantera/composite.py index e5fd793e1..278d7af26 100644 --- a/interfaces/cython/cantera/composite.py +++ b/interfaces/cython/cantera/composite.py @@ -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'] @@ -531,6 +538,7 @@ class SolutionArray: # 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: diff --git a/interfaces/cython/cantera/test/test_models.py b/interfaces/cython/cantera/test/test_models.py index 62e7a5fe7..9bf73e8b8 100644 --- a/interfaces/cython/cantera/test/test_models.py +++ b/interfaces/cython/cantera/test/test_models.py @@ -50,8 +50,9 @@ class TestModels(utilities.CanteraTest): # (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): @@ -75,18 +76,26 @@ class TestModels(utilities.CanteraTest): 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() @@ -101,8 +110,9 @@ class TestModels(utilities.CanteraTest): # (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): diff --git a/interfaces/cython/cantera/thermo.pyx b/interfaces/cython/cantera/thermo.pyx index e54d8c058..2555cf83e 100644 --- a/interfaces/cython/cantera/thermo.pyx +++ b/interfaces/cython/cantera/thermo.pyx @@ -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