From ef1fa9904f7cdd0ccff03d4802164f6c5a31e8c4 Mon Sep 17 00:00:00 2001 From: "Bryan W. Weber" Date: Mon, 6 Jul 2020 13:30:45 -0400 Subject: [PATCH] [Thermo] Append to SolutionArray all at once Move append of extra values to the end of SolutionArray.append(). If the append is done at the beginning of the function, the append can happen even if the state is invalid. This would cause the length of the arrays to become out of sync. --- interfaces/cython/cantera/composite.py | 16 ++++++++++++++++ interfaces/cython/cantera/test/test_thermo.py | 12 ++++++++++++ 2 files changed, 28 insertions(+) diff --git a/interfaces/cython/cantera/composite.py b/interfaces/cython/cantera/composite.py index a8d11ec6507..060d2f29efc 100644 --- a/interfaces/cython/cantera/composite.py +++ b/interfaces/cython/cantera/composite.py @@ -631,6 +631,16 @@ def append(self, state=None, **kwargs): "'{}'".format(", ".join(missing_extra_kwargs)) ) + # For the checks of the state below, the kwargs dictionary can + # only contain keywords that match properties of the state. Here + # we pop any kwargs that have to do with the extra items so they + # aren't included in that check. They are put into a temporary + # storage so that appending can be done at the end of the function + # all at once. + extra_temp = {} + for name in self._extra: + extra_temp[name] = kwargs.pop(name) + if state is not None: self._phase.state = state @@ -654,6 +664,12 @@ def append(self, state=None, **kwargs): self._states.append(self._phase.state) self._indices.append(len(self._indices)) + for name, value in self._extra.items(): + # Casting to a list before appending is ~5x faster than using + # np.append when appending a single item. + v = value.tolist() + v.append(extra_temp.pop(name)) + self._extra[name] = np.array(v) self._shape = (len(self._indices),) @property diff --git a/interfaces/cython/cantera/test/test_thermo.py b/interfaces/cython/cantera/test/test_thermo.py index b8bd10854f8..d463c9f8a39 100644 --- a/interfaces/cython/cantera/test/test_thermo.py +++ b/interfaces/cython/cantera/test/test_thermo.py @@ -1740,6 +1740,18 @@ def test_append(self): self.assertNear(states.P[-1], 1e4) self.assertNear(states.T[-1], 300) + def test_append_with_extra(self): + states = ct.SolutionArray(self.gas, 5, extra={"prop": "value"}) + states.TPX = np.linspace(500, 1000, 5), 2e5, 'H2:0.5, O2:0.4' + self.assertEqual(states._shape, (5,)) + states.append(T=1100, P=3e5, X="AR:1.0", prop="value2") + self.assertEqual(states.prop[-1], "value2") + self.assertEqual(states.prop.shape, (6,)) + states.append(T=1100, P=3e5, X="AR:1.0", prop=100) + # NumPy converts to the existing type of the array + self.assertEqual(states.prop[-1], "100") + self.assertEqual(states.prop.shape, (7,)) + def test_append_failures(self): states = ct.SolutionArray(self.gas, 5, extra={"prop": "value"}) states.TPX = np.linspace(500, 1000, 5), 2e5, 'H2:0.5, O2:0.4'