From dbac2fc79ceb7194862bc895ef4e44f4edfaf224 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Sat, 17 Aug 2019 10:01:54 -0500 Subject: [PATCH] [Base] replace Solution property `ID` by `phase` in Python * Clarifies the meaning of ID * Creates a PEP8 compliant attribute that does not conflict with a built-in function name that is also consistent with the YAML entry. * Change associated member function names in C++ SolutionBase * Deprecate `ID` in Python (to be removed after Cantera 2.5) --- include/cantera/base/Base.h | 26 ++++++++--------- interfaces/cython/cantera/_cantera.pxd | 4 +-- interfaces/cython/cantera/base.pyx | 27 ++++++++++++++++-- .../cython/cantera/test/test_reactor.py | 4 +-- interfaces/cython/cantera/test/test_thermo.py | 28 +++++++++++++++---- src/base/Base.cpp | 6 ++-- 6 files changed, 67 insertions(+), 28 deletions(-) diff --git a/include/cantera/base/Base.h b/include/cantera/base/Base.h index a73c35113..a22e1580e 100644 --- a/include/cantera/base/Base.h +++ b/include/cantera/base/Base.h @@ -36,28 +36,28 @@ public: //! Set the type of this SolutionBase object void setType(const std::string& type); - /*! Name and ID + /*! Name and phase * Class SolutionBase references two strings that identify a SolutionBase. - * The ID is the value of the ID attribute of the XML/YAML node that is used - * to initialize a phase when it is read. The name field is also initialized - * to the value of the ID attribute of the XML/YAML node. + * The phase is the value of the phase name in YAML (or ID attribute + * of the XML node) that is used to initialize a phase when it is read. + * The name field is also initialized to the value of the phase name + * read from the XML/YAML node. * * However, the name field may be changed to another value during the course * of a calculation. For example, if a SolutionBase is located in two places, - * but has the same constitutive input, the IDs of the two SolutionBases - * will be the same, but the names of the two SOlutionBases may be different. + * but has the same constitutive input, the phase of the two SolutionBases + * will be the same, but the names of the two SolutionBases need to differ. * * It is an error to have two phases in a single problem with the same name - * and ID (or the name from one phase being the same as the id of another - * SolutionBase). Thus, it is expected that there is a 1-1 correspondence - * between names and unique SolutionBase objects within a Cantera problem. + * attribute. Thus, it is expected that there is a 1-1 correspondence between + * names and unique SolutionBase objects within a Cantera problem. */ - //! Return the string id for the SolutionBase. - std::string id() const; + //! Return the phase string of this SolutionBase. + std::string phase() const; - //! Set the string id for the SolutionBase. - void setID(const std::string& id); + //! Set the phase string of this SolutionBase. + void setPhase(const std::string& id); //! Return the name of this SolutionBase object std::string name() const; diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index db4d7957e..94f232b83 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -126,8 +126,8 @@ cdef extern from "cantera/base/Base.h" namespace "Cantera": CxxSolutionBase() string type() string setType(string) - string id() - void setID(string) + string phase() + void setPhase(string) string name() void setName(string) void setThermoPhase(shared_ptr[CxxThermoPhase]) diff --git a/interfaces/cython/cantera/base.pyx b/interfaces/cython/cantera/base.pyx index 7ef88c8d6..a5be061bf 100644 --- a/interfaces/cython/cantera/base.pyx +++ b/interfaces/cython/cantera/base.pyx @@ -60,7 +60,7 @@ cdef class _SolutionBase: else: raise ValueError('Missing required keyword `base_type`.') - phase_name = pystr(self.base.id()) + phase_name = pystr(self.base.phase()) name = kwargs.get('name', None) if name is not None: self.name = name @@ -80,15 +80,36 @@ cdef class _SolutionBase: def __get__(self): return pystr(self.base.type()) + property phase: + """ + The ID of the SolutionBase object. The phase corresponds to the + CTI/XML/YAML input file entry. + """ + def __get__(self): + return pystr(self.base.phase()) + def __set__(self, phase_name): + # may consider removing/deprecating, but resetting of the phase name + # is required to associate surface kinetics (with phase name being 'gas') + self.base.setPhase(stringify(phase_name)) + property ID: """ The ID of the SolutionBase object. The default is taken from the CTI/XML/YAML input file. + + .. deprecated:: 2.5 + + To be deprecated with version 2.5, and removed thereafter. + Renamed to `phase`. """ def __get__(self): - return pystr(self.base.id()) + warnings.warn("To be removed after Cantera 2.5. " + "Use `phase` attribute instead", DeprecationWarning) + return pystr(self.base.phase()) def __set__(self, id_): - self.base.setID(stringify(id_)) + warnings.warn("To be removed after Cantera 2.5. " + "Use `phase` attribute instead", DeprecationWarning) + self.base.setPhase(stringify(id_)) property name: """ diff --git a/interfaces/cython/cantera/test/test_reactor.py b/interfaces/cython/cantera/test/test_reactor.py index 9e788cb5b..7d084bc7d 100644 --- a/interfaces/cython/cantera/test/test_reactor.py +++ b/interfaces/cython/cantera/test/test_reactor.py @@ -929,9 +929,9 @@ class TestConstPressureReactor(utilities.CanteraTest): self.gas.TPX = 900, 25*ct.one_atm, 'CO:0.5, H2O:0.2' self.gas1 = ct.Solution('gri30.xml') - self.gas1.ID = 'gas' + self.gas1.phase = 'gas' self.gas2 = ct.Solution('gri30.xml') - self.gas2.ID = 'gas' + self.gas2.phase = 'gas' resGas = ct.Solution('gri30.xml') solid = ct.Solution('diamond.xml', 'diamond') diff --git a/interfaces/cython/cantera/test/test_thermo.py b/interfaces/cython/cantera/test/test_thermo.py index ddce98b28..9f70649be 100644 --- a/interfaces/cython/cantera/test/test_thermo.py +++ b/interfaces/cython/cantera/test/test_thermo.py @@ -8,6 +8,8 @@ import warnings import cantera as ct from . import utilities +import warnings + class TestThermoPhase(utilities.CanteraTest): def setUp(self): @@ -322,10 +324,24 @@ class TestThermoPhase(utilities.CanteraTest): self.assertEqual(self.phase.name, 'something') self.assertIn('something', self.phase.report()) - def test_ID(self): - self.assertEqual(self.phase.ID, 'ohmech') - self.phase.ID = 'something' - self.assertEqual(self.phase.ID, 'something') + def test_phase(self): + self.assertEqual(self.phase.phase, 'ohmech') + warnings.simplefilter("always") + + with warnings.catch_warnings(record=True) as w: + self.assertEqual(self.phase.ID, 'ohmech') + self.assertTrue(len(w) == 1) + self.assertTrue(issubclass(w[-1].category, DeprecationWarning)) + self.assertTrue("To be removed after Cantera 2.5. " + in str(w[-1].message)) + + with warnings.catch_warnings(record=True) as w: + self.phase.ID = 'something' + self.assertEqual(self.phase.phase, 'something') + self.assertTrue(len(w) == 1) + self.assertTrue(issubclass(w[-1].category, DeprecationWarning)) + self.assertTrue("To be removed after Cantera 2.5. " + in str(w[-1].message)) def test_badLength(self): X = np.zeros(5) @@ -859,8 +875,8 @@ class ImportTest(utilities.CanteraTest): """ Test the various ways of creating a Solution object """ - def check(self, gas, name, T, P, nSpec, nElem): - self.assertEqual(gas.ID, name) + def check(self, gas, phase, T, P, nSpec, nElem): + self.assertEqual(gas.phase, phase) self.assertNear(gas.T, T) self.assertNear(gas.P, P) self.assertEqual(gas.n_species, nSpec) diff --git a/src/base/Base.cpp b/src/base/Base.cpp index 29043517e..258ee953e 100644 --- a/src/base/Base.cpp +++ b/src/base/Base.cpp @@ -34,7 +34,7 @@ void SolutionBase::setType(const std::string& type){ m_type = type; } -std::string SolutionBase::id() const { +std::string SolutionBase::phase() const { // currently managed by ThermoPhase if (m_thermo) { return m_thermo->id(); @@ -43,8 +43,10 @@ std::string SolutionBase::id() const { } } -void SolutionBase::setID(const std::string& id) { +void SolutionBase::setPhase(const std::string& id) { // currently managed by ThermoPhase + // note: may consider removing (but needed for association of surface + // kinetics which require the phase name "gas") if (m_thermo) { return m_thermo->setID(id); } else {