From c447fb224f122f32fc2587b7f7131974a632a4e6 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Wed, 7 Aug 2024 21:18:53 -0500 Subject: [PATCH 1/9] [zeroD] Add names to zeroD objects --- include/cantera/zeroD/FlowDevice.h | 19 +++++++++- include/cantera/zeroD/FlowDeviceFactory.h | 10 ++--- include/cantera/zeroD/ReactorBase.h | 4 +- include/cantera/zeroD/ReactorDelegator.h | 3 +- include/cantera/zeroD/ReactorFactory.h | 2 +- include/cantera/zeroD/ReactorSurface.h | 19 +++++++++- include/cantera/zeroD/Wall.h | 16 +++++++- include/cantera/zeroD/WallFactory.h | 10 ++--- include/cantera/zeroD/flowControllers.h | 6 +-- src/zeroD/FlowDeviceFactory.cpp | 18 ++++++--- src/zeroD/ReactorBase.cpp | 3 +- src/zeroD/ReactorFactory.cpp | 45 +++++++++++------------ src/zeroD/WallFactory.cpp | 8 ++-- 13 files changed, 109 insertions(+), 54 deletions(-) diff --git a/include/cantera/zeroD/FlowDevice.h b/include/cantera/zeroD/FlowDevice.h index 463cdb7a9c..a1d2dae225 100644 --- a/include/cantera/zeroD/FlowDevice.h +++ b/include/cantera/zeroD/FlowDevice.h @@ -23,7 +23,7 @@ class ReactorBase; class FlowDevice { public: - FlowDevice() = default; + FlowDevice(const string& name="(none)") : m_name(name) {} virtual ~FlowDevice() = default; FlowDevice(const FlowDevice&) = delete; @@ -35,6 +35,16 @@ class FlowDevice return "FlowDevice"; } + //! Retrieve flow device name. + string name() const { + return m_name; + } + + //! Set flow device name. + void setName(const string& name) { + m_name = name; + } + //! Mass flow rate (kg/s). double massFlowRate() { if (m_mdot == Undef) { @@ -77,6 +87,11 @@ class FlowDevice return *m_out; } + //! Return a mutable reference to the downstream reactor. + ReactorBase& out() { + return *m_out; + } + //! Return current value of the pressure function. /*! * The mass flow rate [kg/s] is calculated given the pressure drop [Pa] and a @@ -115,6 +130,8 @@ class FlowDevice } protected: + string m_name; //!< Flow device name. + double m_mdot = Undef; //! Function set by setPressureFunction; used by updateMassFlowRate diff --git a/include/cantera/zeroD/FlowDeviceFactory.h b/include/cantera/zeroD/FlowDeviceFactory.h index f32ac1773d..a11ef4a976 100644 --- a/include/cantera/zeroD/FlowDeviceFactory.h +++ b/include/cantera/zeroD/FlowDeviceFactory.h @@ -19,7 +19,7 @@ namespace Cantera //! ```cpp //! shared_ptr mfc = newFlowDevice("MassFlowController"); //! ``` -class FlowDeviceFactory : public Factory +class FlowDeviceFactory : public Factory { public: static FlowDeviceFactory* factory(); @@ -34,22 +34,22 @@ class FlowDeviceFactory : public Factory //! @defgroup flowDeviceGroup Flow Devices //! Flow device objects connect zero-dimensional reactors. -//! FlowDevice objects should be instantiated via the newFlowDevice() function, for +//! FlowDevice objects should be instantiated via the newFlowDevice function, for //! example: //! //! ```cpp -//! shared_ptr mfc = newFlowDevice("MassFlowController"); +//! shared_ptr mfc = newFlowDevice("MassFlowController", "my_mfc"); //! ``` //! @ingroup zerodGroup //! @{ //! Create a FlowDevice object of the specified type //! @since Starting in %Cantera 3.1, this method returns a `shared_ptr` -shared_ptr newFlowDevice(const string& model); +shared_ptr newFlowDevice(const string& model, const string& name="(none)"); //! Create a FlowDevice object of the specified type //! @since New in %Cantera 3.0. -//! @deprecated Transitional method. Use newFlowDevice() instead. +//! @deprecated Replaced by newFlowDevice. To be removed after %Cantera 3.1. shared_ptr newFlowDevice3(const string& model); //! @} diff --git a/include/cantera/zeroD/ReactorBase.h b/include/cantera/zeroD/ReactorBase.h index 08c1e978e4..c8b896bd4b 100644 --- a/include/cantera/zeroD/ReactorBase.h +++ b/include/cantera/zeroD/ReactorBase.h @@ -50,12 +50,12 @@ struct SensitivityParameter class ReactorBase { public: - explicit ReactorBase(const string& name = "(none)"); + explicit ReactorBase(const string& name="(none)"); //! Instantiate a ReactorBase object with Solution contents. //! @param sol Solution object to be set. //! @param name Name of the reactor. //! @since New in %Cantera 3.1. - ReactorBase(shared_ptr sol, const string& name = "(none)"); + ReactorBase(shared_ptr sol, const string& name="(none)"); virtual ~ReactorBase(); ReactorBase(const ReactorBase&) = delete; ReactorBase& operator=(const ReactorBase&) = delete; diff --git a/include/cantera/zeroD/ReactorDelegator.h b/include/cantera/zeroD/ReactorDelegator.h index 40c5f40870..b21c130d8a 100644 --- a/include/cantera/zeroD/ReactorDelegator.h +++ b/include/cantera/zeroD/ReactorDelegator.h @@ -59,7 +59,7 @@ template class ReactorDelegator : public Delegator, public R, public ReactorAccessor { public: - ReactorDelegator() { + ReactorDelegator(const string& name="") : m_name(name) { install("initialize", m_initialize, [this](double t0) { R::initialize(t0); }); install("syncState", m_syncState, [this]() { R::syncState(); }); install("getState", m_getState, @@ -185,6 +185,7 @@ class ReactorDelegator : public Delegator, public R, public ReactorAccessor } private: + string m_name; function m_initialize; function m_syncState; function, double*)> m_getState; diff --git a/include/cantera/zeroD/ReactorFactory.h b/include/cantera/zeroD/ReactorFactory.h index b6b9572431..802234ca6c 100644 --- a/include/cantera/zeroD/ReactorFactory.h +++ b/include/cantera/zeroD/ReactorFactory.h @@ -19,7 +19,7 @@ namespace Cantera //! ```cpp //! shared_ptr r1 = newReactor("IdealGasReactor"); //! ``` -class ReactorFactory : public Factory +class ReactorFactory : public Factory { public: static ReactorFactory* factory(); diff --git a/include/cantera/zeroD/ReactorSurface.h b/include/cantera/zeroD/ReactorSurface.h index 828ddaa549..747e864bc1 100644 --- a/include/cantera/zeroD/ReactorSurface.h +++ b/include/cantera/zeroD/ReactorSurface.h @@ -20,11 +20,26 @@ class SurfPhase; class ReactorSurface { public: - ReactorSurface() = default; + ReactorSurface(const string& name="(none)") : m_name(name) {} virtual ~ReactorSurface() = default; ReactorSurface(const ReactorSurface&) = delete; ReactorSurface& operator=(const ReactorSurface&) = delete; + //! String indicating the wall model implemented. + virtual string type() const { + return "ReactorSurface"; + } + + //! Retrieve reactor surface name. + string name() const { + return m_name; + } + + //! Set reactor surface name. + void setName(const string& name) { + m_name = name; + } + //! Returns the surface area [m^2] double area() const; @@ -87,6 +102,8 @@ class ReactorSurface void resetSensitivityParameters(); protected: + string m_name; //!< Reactor surface name. + double m_area = 1.0; SurfPhase* m_thermo = nullptr; diff --git a/include/cantera/zeroD/Wall.h b/include/cantera/zeroD/Wall.h index bcb495990c..efcd379ea0 100644 --- a/include/cantera/zeroD/Wall.h +++ b/include/cantera/zeroD/Wall.h @@ -21,7 +21,7 @@ class Func1; class WallBase { public: - WallBase() = default; + WallBase(const string& name="(none)") : m_name(name) {} virtual ~WallBase() {} WallBase(const WallBase&) = delete; @@ -33,6 +33,16 @@ class WallBase return "WallBase"; } + //! Retrieve wall name. + string name() const { + return m_name; + } + + //! Set wall name. + void setName(const string& name) { + m_name = name; + } + //! Rate of volume change (m^3/s) for the adjacent reactors at current reactor //! network time. /*! @@ -92,6 +102,8 @@ class WallBase } protected: + string m_name; //!< Wall name. + ReactorBase* m_left = nullptr; ReactorBase* m_right = nullptr; @@ -110,7 +122,7 @@ class WallBase class Wall : public WallBase { public: - Wall() = default; + using WallBase::WallBase; // inherit constructors //! String indicating the wall model implemented. Usually //! corresponds to the name of the derived class. diff --git a/include/cantera/zeroD/WallFactory.h b/include/cantera/zeroD/WallFactory.h index 3854b3e9c0..79850266c1 100644 --- a/include/cantera/zeroD/WallFactory.h +++ b/include/cantera/zeroD/WallFactory.h @@ -19,7 +19,7 @@ namespace Cantera //! ```cpp //! shared_ptr piston = newWall("Wall"); //! ``` -class WallFactory : public Factory +class WallFactory : public Factory { public: static WallFactory* factory(); @@ -34,22 +34,22 @@ class WallFactory : public Factory //! @defgroup wallGroup Walls //! Zero-dimensional objects adjacent to reactors. -//! Wall objects should be instantiated via the newWall() function, for +//! Wall objects should be instantiated via the newWall function, for //! example: //! //! ```cpp -//! shared_ptr piston = newWall("Wall"); +//! shared_ptr piston = newWall("Wall", "my_piston"); //! ``` //! @ingroup zerodGroup //! @{ //! Create a WallBase object of the specified type //! @since Starting in %Cantera 3.1, this method returns a `shared_ptr` -shared_ptr newWall(const string& model); +shared_ptr newWall(const string& model, const string& name="(none)"); //! Create a WallBase object of the specified type //! @since New in %Cantera 3.0. -//! @deprecated Transitional method. Use newWall() instead. +//! @deprecated Replaced by newWall. To be removed after %Cantera 3.1. shared_ptr newWall3(const string& model); //! @} diff --git a/include/cantera/zeroD/flowControllers.h b/include/cantera/zeroD/flowControllers.h index fa22b47f44..16c4d42313 100644 --- a/include/cantera/zeroD/flowControllers.h +++ b/include/cantera/zeroD/flowControllers.h @@ -20,7 +20,7 @@ namespace Cantera class MassFlowController : public FlowDevice { public: - MassFlowController() = default; + using FlowDevice::FlowDevice; // inherit constructors string type() const override { return "MassFlowController"; @@ -65,7 +65,7 @@ class MassFlowController : public FlowDevice class PressureController : public FlowDevice { public: - PressureController() = default; + using FlowDevice::FlowDevice; // inherit constructors string type() const override { return "PressureController"; @@ -123,7 +123,7 @@ class PressureController : public FlowDevice class Valve : public FlowDevice { public: - Valve() = default; + using FlowDevice::FlowDevice; // inherit constructors string type() const override { return "Valve"; diff --git a/src/zeroD/FlowDeviceFactory.cpp b/src/zeroD/FlowDeviceFactory.cpp index a18f24e575..013178a21f 100644 --- a/src/zeroD/FlowDeviceFactory.cpp +++ b/src/zeroD/FlowDeviceFactory.cpp @@ -14,9 +14,15 @@ std::mutex FlowDeviceFactory::flowDevice_mutex; FlowDeviceFactory::FlowDeviceFactory() { - reg("MassFlowController", []() { return new MassFlowController(); }); - reg("PressureController", []() { return new PressureController(); }); - reg("Valve", []() { return new Valve(); }); + reg("MassFlowController", [](const string& name) { + return new MassFlowController(name); + }); + reg("PressureController", [](const string& name) { + return new PressureController(name); + }); + reg("Valve", [](const string& name) { + return new Valve(name); + }); } FlowDeviceFactory* FlowDeviceFactory::factory() { @@ -33,13 +39,15 @@ void FlowDeviceFactory::deleteFactory() { s_factory = 0; } -shared_ptr newFlowDevice(const string& model) +shared_ptr newFlowDevice(const string& model, const string& name) { - return shared_ptr(FlowDeviceFactory::factory()->create(model)); + return shared_ptr(FlowDeviceFactory::factory()->create(model, name)); } shared_ptr newFlowDevice3(const string& model) { + warn_deprecated("newFlowDevice3", + "Use newFlowDevice instead; to be removed after Cantera 3.1."); return newFlowDevice(model); } diff --git a/src/zeroD/ReactorBase.cpp b/src/zeroD/ReactorBase.cpp index 99b33688d6..aa989f1b76 100644 --- a/src/zeroD/ReactorBase.cpp +++ b/src/zeroD/ReactorBase.cpp @@ -13,9 +13,8 @@ namespace Cantera { -ReactorBase::ReactorBase(const string& name) +ReactorBase::ReactorBase(const string& name) : m_name(name) { - m_name = name; } ReactorBase::ReactorBase(shared_ptr sol, const string& name) diff --git a/src/zeroD/ReactorFactory.cpp b/src/zeroD/ReactorFactory.cpp index 360f975bd3..134ed343a0 100644 --- a/src/zeroD/ReactorFactory.cpp +++ b/src/zeroD/ReactorFactory.cpp @@ -24,32 +24,32 @@ std::mutex ReactorFactory::reactor_mutex; ReactorFactory::ReactorFactory() { - reg("Reservoir", []() { return new Reservoir(); }); - reg("Reactor", []() { return new Reactor(); }); - reg("ConstPressureReactor", []() { return new ConstPressureReactor(); }); - reg("FlowReactor", []() { return new FlowReactor(); }); - reg("IdealGasReactor", []() { return new IdealGasReactor(); }); - reg("IdealGasConstPressureReactor", []() { return new IdealGasConstPressureReactor(); }); - reg("ExtensibleReactor", []() { return new ReactorDelegator(); }); + reg("Reservoir", [](const string& name) { return new Reservoir(name); }); + reg("Reactor", [](const string& name) { return new Reactor(name); }); + reg("ConstPressureReactor", [](const string& name) { return new ConstPressureReactor(name); }); + reg("FlowReactor", [](const string& name) { return new FlowReactor(name); }); + reg("IdealGasReactor", [](const string& name) { return new IdealGasReactor(name); }); + reg("IdealGasConstPressureReactor", [](const string& name) { return new IdealGasConstPressureReactor(name); }); + reg("ExtensibleReactor", [](const string& name) { return new ReactorDelegator(name); }); reg("ExtensibleIdealGasReactor", - []() { return new ReactorDelegator(); }); + [](const string& name) { return new ReactorDelegator(name); }); reg("ExtensibleConstPressureReactor", - []() { return new ReactorDelegator(); }); + [](const string& name) { return new ReactorDelegator(name); }); reg("ExtensibleIdealGasConstPressureReactor", - []() { return new ReactorDelegator(); }); + [](const string& name) { return new ReactorDelegator(name); }); reg("ExtensibleMoleReactor", - []() { return new ReactorDelegator(); }); + [](const string& name) { return new ReactorDelegator(name); }); reg("ExtensibleConstPressureMoleReactor", - []() { return new ReactorDelegator(); }); + [](const string& name) { return new ReactorDelegator(name); }); reg("ExtensibleIdealGasMoleReactor", - []() { return new ReactorDelegator(); }); + [](const string& name) { return new ReactorDelegator(name); }); reg("ExtensibleIdealGasConstPressureMoleReactor", - []() { return new ReactorDelegator(); }); - reg("IdealGasConstPressureMoleReactor", []() { return new - IdealGasConstPressureMoleReactor(); }); - reg("IdealGasMoleReactor", []() { return new IdealGasMoleReactor(); }); - reg("ConstPressureMoleReactor", []() { return new ConstPressureMoleReactor(); }); - reg("MoleReactor", []() { return new MoleReactor(); }); + [](const string& name) { return new ReactorDelegator(name); }); + reg("IdealGasConstPressureMoleReactor", + [](const string& name) { return new IdealGasConstPressureMoleReactor(name); }); + reg("IdealGasMoleReactor", [](const string& name) { return new IdealGasMoleReactor(name); }); + reg("ConstPressureMoleReactor", [](const string& name) { return new ConstPressureMoleReactor(name); }); + reg("MoleReactor", [](const string& name) { return new MoleReactor(name); }); } ReactorFactory* ReactorFactory::factory() { @@ -71,17 +71,16 @@ shared_ptr newReactor(const string& model) warn_deprecated("newReactor", "Creation of empty reactor objects is deprecated in Cantera 3.1 and will be \n" "removed thereafter; reactor contents should be provided in the constructor."); - return shared_ptr(ReactorFactory::factory()->create(model)); + return shared_ptr(ReactorFactory::factory()->create(model, "")); } shared_ptr newReactor( const string& model, shared_ptr contents, const string& name) { // once empty reactors are no longer supported, the create factory method should - // support passing a Solution object and a name - auto ret = shared_ptr(ReactorFactory::factory()->create(model)); + // support passing a Solution object + auto ret = shared_ptr(ReactorFactory::factory()->create(model, name)); ret->setSolution(contents); - ret->setName(name); return ret; } diff --git a/src/zeroD/WallFactory.cpp b/src/zeroD/WallFactory.cpp index 403f29b7ac..4acf2c0578 100644 --- a/src/zeroD/WallFactory.cpp +++ b/src/zeroD/WallFactory.cpp @@ -14,7 +14,7 @@ std::mutex WallFactory::wall_mutex; WallFactory::WallFactory() { - reg("Wall", []() { return new Wall(); }); + reg("Wall", [](const string& name) { return new Wall(name); }); } WallFactory* WallFactory::factory() { @@ -31,13 +31,15 @@ void WallFactory::deleteFactory() { s_factory = 0; } -shared_ptr newWall(const string& model) +shared_ptr newWall(const string& model, const string& name) { - return shared_ptr(WallFactory::factory()->create(model)); + return shared_ptr(WallFactory::factory()->create(model, name)); } shared_ptr newWall3(const string& model) { + warn_deprecated("newWall3", + "Use newWall instead; to be removed after Cantera 3.1."); return newWall(model); } From 9ad89f3de59cfb99bdf20091e7d476cb60af8204 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Wed, 7 Aug 2024 22:27:04 -0500 Subject: [PATCH 2/9] [Python] Push zeroD names to C++ layer --- interfaces/cython/cantera/reactor.pxd | 13 +++-- interfaces/cython/cantera/reactor.pyx | 71 +++++++++++++++------------ 2 files changed, 49 insertions(+), 35 deletions(-) diff --git a/interfaces/cython/cantera/reactor.pxd b/interfaces/cython/cantera/reactor.pxd index 8bb589e53d..c06a9e0b8c 100644 --- a/interfaces/cython/cantera/reactor.pxd +++ b/interfaces/cython/cantera/reactor.pxd @@ -32,8 +32,8 @@ cdef extern from "cantera/zerodim.h" namespace "Cantera": # factories cdef shared_ptr[CxxReactorBase] newReactor(string) except +translate_exception cdef shared_ptr[CxxReactorBase] newReactor(string, shared_ptr[CxxSolution], string) except +translate_exception - cdef shared_ptr[CxxFlowDevice] newFlowDevice(string) except +translate_exception - cdef shared_ptr[CxxWallBase] newWall(string) except +translate_exception + cdef shared_ptr[CxxFlowDevice] newFlowDevice(string, string) except +translate_exception + cdef shared_ptr[CxxWallBase] newWall(string, string) except +translate_exception # reactors cdef cppclass CxxReactorBase "Cantera::ReactorBase": @@ -86,6 +86,8 @@ cdef extern from "cantera/zerodim.h" namespace "Cantera": cdef cppclass CxxWallBase "Cantera::WallBase": CxxWallBase() string type() + string name() + void setName(string) except +translate_exception cbool install(CxxReactorBase&, CxxReactorBase&) double area() void setArea(double) @@ -117,7 +119,10 @@ cdef extern from "cantera/zerodim.h" namespace "Cantera": # reactor surface cdef cppclass CxxReactorSurface "Cantera::ReactorSurface": - CxxReactorSurface() + CxxReactorSurface(string) except +translate_exception + string type() + string name() + void setName(string) except +translate_exception double area() void setArea(double) void setKinetics(CxxKinetics*) @@ -132,6 +137,8 @@ cdef extern from "cantera/zerodim.h" namespace "Cantera": cdef cppclass CxxFlowDevice "Cantera::FlowDevice": CxxFlowDevice() string type() + string name() + void setName(string) except +translate_exception double massFlowRate() except +translate_exception double massFlowRate(double) except +translate_exception cbool install(CxxReactorBase&, CxxReactorBase&) except +translate_exception diff --git a/interfaces/cython/cantera/reactor.pyx b/interfaces/cython/cantera/reactor.pyx index 4af9158c14..1ae1e22986 100644 --- a/interfaces/cython/cantera/reactor.pyx +++ b/interfaces/cython/cantera/reactor.pyx @@ -2,7 +2,6 @@ # at https://cantera.org/license.txt for license and copyright information. import warnings -from collections import defaultdict as _defaultdict import numbers as _numbers from cython.operator cimport dereference as deref @@ -12,27 +11,19 @@ from ._utils import * from .delegator cimport * from .drawnetwork import * -_reactor_counts = _defaultdict(int) - cdef class ReactorBase: """ Common base class for reactors and reservoirs. """ reactor_type = "none" def __cinit__(self, _SolutionBase contents=None, name=None, *, **kwargs): - def reactor_name(name): - if name is not None: - return name - _reactor_counts[self.reactor_type] += 1 - return f"{self.reactor_type}_{_reactor_counts[self.reactor_type]}" - if isinstance(contents, _SolutionBase): self._reactor = newReactor(stringify(self.reactor_type), - contents._base, stringify(reactor_name(name))) + contents._base, stringify(name)) else: # deprecated: will raise warnings in C++ layer self._reactor = newReactor(stringify(self.reactor_type)) - self._reactor.get().setName(stringify(reactor_name(name))) + self._reactor.get().setName(stringify(name)) self.rbase = self._reactor.get() def __init__(self, _SolutionBase contents=None, name=None, *, volume=None, @@ -66,7 +57,6 @@ cdef class ReactorBase: """The name of the reactor.""" def __get__(self): return pystr(self.rbase.name()) - def __set__(self, name): self.rbase.setName(stringify(name)) @@ -796,6 +786,9 @@ cdef class ReactorSurface: """ Represents a surface in contact with the contents of a reactor. + :param name: + Name string. If omitted, the name is ``'ReactorSurface_n'``, where ``'n'`` + is an integer assigned in the order reactor surfaces are created. :param kin: The `Kinetics` or `Interface` object representing reactions on this surface. @@ -810,13 +803,14 @@ cdef class ReactorSurface: .. versionadded:: 3.1 Added the ``node_attr`` parameter. """ - def __cinit__(self): - self.surface = new CxxReactorSurface() + def __cinit__(self, *args, **kwargs): + name = kwargs.get("name") + self.surface = new CxxReactorSurface(stringify(name)) def __dealloc__(self): del self.surface - def __init__(self, kin=None, Reactor r=None, *, A=None, node_attr=None): + def __init__(self, kin=None, Reactor r=None, *, name=None, A=None, node_attr=None): if kin is not None: self.kinetics = kin if r is not None: @@ -833,6 +827,18 @@ cdef class ReactorSurface: r.reactor.addSurface(self.surface) self._reactor = r + property type: + """The type of the reactor surface.""" + def __get__(self): + return pystr(self.surface.type()) + + property name: + """The name of the reactor surface.""" + def __get__(self): + return pystr(self.surface.name()) + def __set__(self, name): + self.surface.setName(stringify(name)) + property area: """ Area on which reactions can occur [m^2] """ def __get__(self): @@ -941,7 +947,8 @@ cdef class WallBase: """ wall_type = "none" def __cinit__(self, *args, **kwargs): - self._wall = newWall(stringify(self.wall_type)) + name = kwargs.get("name") + self._wall = newWall(stringify(self.wall_type), stringify(name)) self.wall = self._wall.get() def __init__(self, left, right, *, name=None, A=None, K=None, U=None, @@ -979,12 +986,6 @@ cdef class WallBase: self._heat_flux_func = None self._install(left, right) - if name is not None: - self.name = name - else: - _reactor_counts['Wall'] += 1 - n = _reactor_counts['Wall'] - self.name = 'Wall_{0}'.format(n) if A is not None: self.area = A @@ -1015,6 +1016,13 @@ cdef class WallBase: def __get__(self): return pystr(self.wall.type()) + property name: + """The name of the wall.""" + def __get__(self): + return pystr(self.wall.name()) + def __set__(self, name): + self.wall.setName(stringify(name)) + property area: """ The wall area [m^2]. """ def __get__(self): @@ -1212,22 +1220,14 @@ cdef class FlowDevice: """ flowdevice_type = "none" def __cinit__(self, *args, **kwargs): - self._dev = newFlowDevice(stringify(self.flowdevice_type)) + name = kwargs.get("name") + self._dev = newFlowDevice(stringify(self.flowdevice_type), stringify(name)) self.dev = self._dev.get() def __init__(self, upstream, downstream, *, name=None, edge_attr=None): assert self.dev != NULL self._rate_func = None - - if name is not None: - self.name = name - else: - _reactor_counts[self.__class__.__name__] += 1 - n = _reactor_counts[self.__class__.__name__] - self.name = '{0}_{1}'.format(self.__class__.__name__, n) - self.edge_attr = edge_attr or {} - self._install(upstream, downstream) property type: @@ -1235,6 +1235,13 @@ cdef class FlowDevice: def __get__(self): return pystr(self.dev.type()) + property name: + """The name of the flow device.""" + def __get__(self): + return pystr(self.dev.name()) + def __set__(self, name): + self.dev.setName(stringify(name)) + def _install(self, ReactorBase upstream, ReactorBase downstream): """ Install the device between the ``upstream`` (source) and ``downstream`` From 14b9317c061f57620a0f1ea7cecc037a4f1b26f2 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Wed, 7 Aug 2024 23:33:16 -0500 Subject: [PATCH 3/9] [zeroD] Change factory constructors --- include/cantera/zeroD/Reactor.h | 2 +- include/cantera/zeroD/ReactorDelegator.h | 9 ++- include/cantera/zeroD/ReactorFactory.h | 2 +- src/zeroD/Reactor.cpp | 9 ++- src/zeroD/ReactorBase.cpp | 9 ++- src/zeroD/ReactorFactory.cpp | 77 +++++++++++++++--------- 6 files changed, 75 insertions(+), 33 deletions(-) diff --git a/include/cantera/zeroD/Reactor.h b/include/cantera/zeroD/Reactor.h index 8996be6d7b..5703431f6e 100644 --- a/include/cantera/zeroD/Reactor.h +++ b/include/cantera/zeroD/Reactor.h @@ -46,7 +46,7 @@ class AnyMap; class Reactor : public ReactorBase { public: - Reactor(shared_ptr sol, const string& name = "(none)"); + Reactor(shared_ptr sol, const string& name="(none)"); using ReactorBase::ReactorBase; // inherit constructors string type() const override { diff --git a/include/cantera/zeroD/ReactorDelegator.h b/include/cantera/zeroD/ReactorDelegator.h index b21c130d8a..1a30e79f71 100644 --- a/include/cantera/zeroD/ReactorDelegator.h +++ b/include/cantera/zeroD/ReactorDelegator.h @@ -59,7 +59,9 @@ template class ReactorDelegator : public Delegator, public R, public ReactorAccessor { public: - ReactorDelegator(const string& name="") : m_name(name) { + ReactorDelegator(shared_ptr contents, const string& name="(none)") + : R(contents, name) + { install("initialize", m_initialize, [this](double t0) { R::initialize(t0); }); install("syncState", m_syncState, [this]() { R::syncState(); }); install("getState", m_getState, @@ -96,6 +98,10 @@ class ReactorDelegator : public Delegator, public R, public ReactorAccessor // Overrides of Reactor methods + string type() const override { + return fmt::format("Extensible{}", R::type()); + } + void initialize(double t0) override { m_initialize(t0); } @@ -185,7 +191,6 @@ class ReactorDelegator : public Delegator, public R, public ReactorAccessor } private: - string m_name; function m_initialize; function m_syncState; function, double*)> m_getState; diff --git a/include/cantera/zeroD/ReactorFactory.h b/include/cantera/zeroD/ReactorFactory.h index 802234ca6c..56c17bf67c 100644 --- a/include/cantera/zeroD/ReactorFactory.h +++ b/include/cantera/zeroD/ReactorFactory.h @@ -19,7 +19,7 @@ namespace Cantera //! ```cpp //! shared_ptr r1 = newReactor("IdealGasReactor"); //! ``` -class ReactorFactory : public Factory +class ReactorFactory : public Factory, const string&> { public: static ReactorFactory* factory(); diff --git a/src/zeroD/Reactor.cpp b/src/zeroD/Reactor.cpp index 0201222d63..28f4ce7f8b 100644 --- a/src/zeroD/Reactor.cpp +++ b/src/zeroD/Reactor.cpp @@ -23,9 +23,16 @@ namespace Cantera { Reactor::Reactor(shared_ptr sol, const string& name) + : ReactorBase(name) { + if (!sol || !(sol->thermo())) { + warn_deprecated("Reactor::Reactor", + "Creation of empty reactor objects is deprecated in Cantera 3.1 and will " + "raise\nexceptions thereafter; reactor contents should be provided in the " + "constructor."); + return; + } setSolution(sol); - m_name = name; setThermo(*sol->thermo()); setKinetics(*sol->kinetics()); } diff --git a/src/zeroD/ReactorBase.cpp b/src/zeroD/ReactorBase.cpp index aa989f1b76..f68f49b59d 100644 --- a/src/zeroD/ReactorBase.cpp +++ b/src/zeroD/ReactorBase.cpp @@ -18,8 +18,15 @@ ReactorBase::ReactorBase(const string& name) : m_name(name) } ReactorBase::ReactorBase(shared_ptr sol, const string& name) + : ReactorBase(name) { - m_name = name; + if (!sol || !(sol->thermo())) { + warn_deprecated("ReactorBase::ReactorBase", + "Creation of empty reactor objects is deprecated in Cantera 3.1 and will " + "raise\nexceptions thereafter; reactor contents should be provided in the " + "constructor."); + return; + } setSolution(sol); } diff --git a/src/zeroD/ReactorFactory.cpp b/src/zeroD/ReactorFactory.cpp index 134ed343a0..4642e22009 100644 --- a/src/zeroD/ReactorFactory.cpp +++ b/src/zeroD/ReactorFactory.cpp @@ -24,32 +24,60 @@ std::mutex ReactorFactory::reactor_mutex; ReactorFactory::ReactorFactory() { - reg("Reservoir", [](const string& name) { return new Reservoir(name); }); - reg("Reactor", [](const string& name) { return new Reactor(name); }); - reg("ConstPressureReactor", [](const string& name) { return new ConstPressureReactor(name); }); - reg("FlowReactor", [](const string& name) { return new FlowReactor(name); }); - reg("IdealGasReactor", [](const string& name) { return new IdealGasReactor(name); }); - reg("IdealGasConstPressureReactor", [](const string& name) { return new IdealGasConstPressureReactor(name); }); - reg("ExtensibleReactor", [](const string& name) { return new ReactorDelegator(name); }); + reg("Reservoir", + [](shared_ptr sol, const string& name) + { return new Reservoir(sol, name); }); + reg("Reactor", + [](shared_ptr sol, const string& name) + { return new Reactor(sol, name); }); + reg("ConstPressureReactor", + [](shared_ptr sol, const string& name) + { return new ConstPressureReactor(sol, name); }); + reg("FlowReactor", + [](shared_ptr sol, const string& name) + { return new FlowReactor(sol, name); }); + reg("IdealGasReactor", + [](shared_ptr sol, const string& name) + { return new IdealGasReactor(sol, name); }); + reg("IdealGasConstPressureReactor", + [](shared_ptr sol, const string& name) + { return new IdealGasConstPressureReactor(sol, name); }); + reg("ExtensibleReactor", + [](shared_ptr sol, const string& name) + { return new ReactorDelegator(sol, name); }); reg("ExtensibleIdealGasReactor", - [](const string& name) { return new ReactorDelegator(name); }); + [](shared_ptr sol, const string& name) + { return new ReactorDelegator(sol, name); }); reg("ExtensibleConstPressureReactor", - [](const string& name) { return new ReactorDelegator(name); }); + [](shared_ptr sol, const string& name) + { return new ReactorDelegator(sol, name); }); reg("ExtensibleIdealGasConstPressureReactor", - [](const string& name) { return new ReactorDelegator(name); }); + [](shared_ptr sol, const string& name) + { return new ReactorDelegator(sol, name); }); reg("ExtensibleMoleReactor", - [](const string& name) { return new ReactorDelegator(name); }); + [](shared_ptr sol, const string& name) + { return new ReactorDelegator(sol, name); }); reg("ExtensibleConstPressureMoleReactor", - [](const string& name) { return new ReactorDelegator(name); }); + [](shared_ptr sol, const string& name) + { return new ReactorDelegator(sol, name); }); reg("ExtensibleIdealGasMoleReactor", - [](const string& name) { return new ReactorDelegator(name); }); + [](shared_ptr sol, const string& name) + { return new ReactorDelegator(sol, name); }); reg("ExtensibleIdealGasConstPressureMoleReactor", - [](const string& name) { return new ReactorDelegator(name); }); + [](shared_ptr sol, const string& name) + { return new ReactorDelegator(sol, name); }); reg("IdealGasConstPressureMoleReactor", - [](const string& name) { return new IdealGasConstPressureMoleReactor(name); }); - reg("IdealGasMoleReactor", [](const string& name) { return new IdealGasMoleReactor(name); }); - reg("ConstPressureMoleReactor", [](const string& name) { return new ConstPressureMoleReactor(name); }); - reg("MoleReactor", [](const string& name) { return new MoleReactor(name); }); + [](shared_ptr sol, const string& name) + { return new IdealGasConstPressureMoleReactor(sol, name); }); + reg("IdealGasMoleReactor", + [](shared_ptr sol, const string& name) + { return new IdealGasMoleReactor(sol, name); }); + reg("ConstPressureMoleReactor", + [](shared_ptr sol, const string& name) + { return new ConstPressureMoleReactor(sol, name); }); + reg("MoleReactor", + [](shared_ptr sol, const string& name) + { return new MoleReactor(sol, name); }); } ReactorFactory* ReactorFactory::factory() { @@ -68,20 +96,15 @@ void ReactorFactory::deleteFactory() { shared_ptr newReactor(const string& model) { - warn_deprecated("newReactor", - "Creation of empty reactor objects is deprecated in Cantera 3.1 and will be \n" - "removed thereafter; reactor contents should be provided in the constructor."); - return shared_ptr(ReactorFactory::factory()->create(model, "")); + return shared_ptr( + ReactorFactory::factory()->create(model, nullptr, "")); } shared_ptr newReactor( const string& model, shared_ptr contents, const string& name) { - // once empty reactors are no longer supported, the create factory method should - // support passing a Solution object - auto ret = shared_ptr(ReactorFactory::factory()->create(model, name)); - ret->setSolution(contents); - return ret; + return shared_ptr( + ReactorFactory::factory()->create(model, contents, name)); } shared_ptr newReactor3(const string& model) From 3e97125411e0328be73002978fee8c85fc8e1ddc Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Thu, 8 Aug 2024 10:52:50 -0500 Subject: [PATCH 4/9] [zeroD] Implement default names in ReactorNet Names of reactors and walls/connectors should be reproducible for a given reactor network. --- include/cantera/zeroD/FlowDevice.h | 4 +++ include/cantera/zeroD/ReactorBase.h | 6 +++- include/cantera/zeroD/ReactorNet.h | 4 +++ include/cantera/zeroD/ReactorSurface.h | 4 +++ include/cantera/zeroD/Wall.h | 6 +++- src/zeroD/FlowDevice.cpp | 14 +++++++++ src/zeroD/ReactorBase.cpp | 13 +++++++++ src/zeroD/ReactorNet.cpp | 39 ++++++++++++++++++++++++++ src/zeroD/ReactorSurface.cpp | 13 +++++++++ src/zeroD/Wall.cpp | 13 +++++++++ 10 files changed, 114 insertions(+), 2 deletions(-) diff --git a/include/cantera/zeroD/FlowDevice.h b/include/cantera/zeroD/FlowDevice.h index a1d2dae225..00e622b2ba 100644 --- a/include/cantera/zeroD/FlowDevice.h +++ b/include/cantera/zeroD/FlowDevice.h @@ -45,6 +45,9 @@ class FlowDevice m_name = name; } + //! Set the default name of a flow device. Returns `false` if it was previously set. + bool setDefaultName(map& counts); + //! Mass flow rate (kg/s). double massFlowRate() { if (m_mdot == Undef) { @@ -131,6 +134,7 @@ class FlowDevice protected: string m_name; //!< Flow device name. + bool m_defaultNameSet = false; //!< `true` if default name has been previously set. double m_mdot = Undef; diff --git a/include/cantera/zeroD/ReactorBase.h b/include/cantera/zeroD/ReactorBase.h index c8b896bd4b..0d11cd3a2f 100644 --- a/include/cantera/zeroD/ReactorBase.h +++ b/include/cantera/zeroD/ReactorBase.h @@ -76,6 +76,9 @@ class ReactorBase m_name = name; } + //! Set the default name of a reactor. Returns `false` if it was previously set. + bool setDefaultName(map& counts); + //! Set the Solution specifying the ReactorBase content. //! @param sol Solution object to be set. //! @since New in %Cantera 3.1. @@ -307,7 +310,8 @@ class ReactorBase //! Vector of length nWalls(), indicating whether this reactor is on the left (0) //! or right (1) of each wall. vector m_lr; - string m_name; + string m_name; //!< Reactor name. + bool m_defaultNameSet = false; //!< `true` if default name has been previously set. //! The ReactorNet that this reactor is part of ReactorNet* m_net = nullptr; diff --git a/include/cantera/zeroD/ReactorNet.h b/include/cantera/zeroD/ReactorNet.h index e32bca81d9..f1ffe5b249 100644 --- a/include/cantera/zeroD/ReactorNet.h +++ b/include/cantera/zeroD/ReactorNet.h @@ -305,6 +305,9 @@ class ReactorNet : public FuncEval void updatePreconditioner(double gamma) override; + //! Create reproducible names for reactors and walls/connectors. + void updateNames(Reactor& r); + //! Estimate a future state based on current derivatives. //! The function is intended for internal use by ReactorNet::advance //! and deliberately not exposed in external interfaces. @@ -316,6 +319,7 @@ class ReactorNet : public FuncEval virtual int lastOrder() const; vector m_reactors; + map m_counts; //!< Map used for default name generation unique_ptr m_integ; //! The independent variable in the system. May be either time or space depending diff --git a/include/cantera/zeroD/ReactorSurface.h b/include/cantera/zeroD/ReactorSurface.h index 747e864bc1..676c4637ea 100644 --- a/include/cantera/zeroD/ReactorSurface.h +++ b/include/cantera/zeroD/ReactorSurface.h @@ -40,6 +40,9 @@ class ReactorSurface m_name = name; } + //! Set the default name of a wall. Returns `false` if it was previously set. + bool setDefaultName(map& counts); + //! Returns the surface area [m^2] double area() const; @@ -103,6 +106,7 @@ class ReactorSurface protected: string m_name; //!< Reactor surface name. + bool m_defaultNameSet = false; //!< `true` if default name has been previously set. double m_area = 1.0; diff --git a/include/cantera/zeroD/Wall.h b/include/cantera/zeroD/Wall.h index efcd379ea0..14b9dbd034 100644 --- a/include/cantera/zeroD/Wall.h +++ b/include/cantera/zeroD/Wall.h @@ -43,6 +43,9 @@ class WallBase m_name = name; } + //! Set the default name of a wall. Returns `false` if it was previously set. + bool setDefaultName(map& counts); + //! Rate of volume change (m^3/s) for the adjacent reactors at current reactor //! network time. /*! @@ -89,7 +92,7 @@ class WallBase } //! Return a reference to the Reactor or Reservoir to the right of the wall. - const ReactorBase& right() { + ReactorBase& right() { return *m_right; } @@ -103,6 +106,7 @@ class WallBase protected: string m_name; //!< Wall name. + bool m_defaultNameSet = false; //!< `true` if default name has been previously set. ReactorBase* m_left = nullptr; ReactorBase* m_right = nullptr; diff --git a/src/zeroD/FlowDevice.cpp b/src/zeroD/FlowDevice.cpp index d298a933cc..225d19a44d 100644 --- a/src/zeroD/FlowDevice.cpp +++ b/src/zeroD/FlowDevice.cpp @@ -11,6 +11,20 @@ namespace Cantera { +bool FlowDevice::setDefaultName(map& counts) +{ + if (m_defaultNameSet) { + return false; + } + m_defaultNameSet = true; + string typ(type()); + if (m_name == "(none)" || m_name == "") { + m_name = fmt::format("{}_{}", type(), counts[type()]); + } + counts[type()]++; + return true; +} + bool FlowDevice::install(ReactorBase& in, ReactorBase& out) { if (m_in || m_out) { diff --git a/src/zeroD/ReactorBase.cpp b/src/zeroD/ReactorBase.cpp index f68f49b59d..4c5ced8393 100644 --- a/src/zeroD/ReactorBase.cpp +++ b/src/zeroD/ReactorBase.cpp @@ -37,6 +37,19 @@ ReactorBase::~ReactorBase() } } +bool ReactorBase::setDefaultName(map& counts) +{ + if (m_defaultNameSet) { + return false; + } + m_defaultNameSet = true; + if (m_name == "(none)" || m_name == "") { + m_name = fmt::format("{}_{}", type(), counts[type()]); + } + counts[type()]++; + return true; +} + void ReactorBase::setSolution(shared_ptr sol) { if (!sol || !(sol->thermo())) { throw CanteraError("ReactorBase::setSolution", diff --git a/src/zeroD/ReactorNet.cpp b/src/zeroD/ReactorNet.cpp index ae1e8128d4..3d1c4f2635 100644 --- a/src/zeroD/ReactorNet.cpp +++ b/src/zeroD/ReactorNet.cpp @@ -5,6 +5,7 @@ #include "cantera/zeroD/ReactorNet.h" #include "cantera/zeroD/FlowDevice.h" +#include "cantera/zeroD/ReactorSurface.h" #include "cantera/zeroD/Wall.h" #include "cantera/base/utilities.h" #include "cantera/base/Array.h" @@ -305,6 +306,44 @@ void ReactorNet::addReactor(Reactor& r) m_integ->setMethod(BDF_Method); m_integ->setLinearSolverType("DENSE"); } + updateNames(r); +} + +void ReactorNet::updateNames(Reactor& r) +{ + // ensure that reactors and components have reproducible names + r.setDefaultName(m_counts); + + for (size_t i=0; isetDefaultName(m_counts); + } } Integrator& ReactorNet::integrator() { diff --git a/src/zeroD/ReactorSurface.cpp b/src/zeroD/ReactorSurface.cpp index 5e98f3d292..f811eb4f76 100644 --- a/src/zeroD/ReactorSurface.cpp +++ b/src/zeroD/ReactorSurface.cpp @@ -12,6 +12,19 @@ namespace Cantera { +bool ReactorSurface::setDefaultName(map& counts) +{ + if (m_defaultNameSet) { + return false; + } + m_defaultNameSet = true; + if (m_name == "(none)" || m_name == "") { + m_name = fmt::format("{}_{}", type(), counts[type()]); + } + counts[type()]++; + return true; +} + double ReactorSurface::area() const { return m_area; diff --git a/src/zeroD/Wall.cpp b/src/zeroD/Wall.cpp index 519e80f85d..2d1d61a819 100644 --- a/src/zeroD/Wall.cpp +++ b/src/zeroD/Wall.cpp @@ -10,6 +10,19 @@ namespace Cantera { +bool WallBase::setDefaultName(map& counts) +{ + if (m_defaultNameSet) { + return false; + } + m_defaultNameSet = true; + if (m_name == "(none)" || m_name == "") { + m_name = fmt::format("{}_{}", type(), counts[type()]); + } + counts[type()]++; + return true; +} + bool WallBase::install(ReactorBase& rleft, ReactorBase& rright) { // check if wall is already installed From 80f5fcb837044350099605fedf442d10c93adb6c Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Thu, 8 Aug 2024 08:00:02 -0500 Subject: [PATCH 5/9] [CI] Test zeroD object names --- test/python/test_reactor.py | 75 ++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/test/python/test_reactor.py b/test/python/test_reactor.py index 1f90f6b5c5..ae3b8c396a 100644 --- a/test/python/test_reactor.py +++ b/test/python/test_reactor.py @@ -236,10 +236,34 @@ def test_maxsteps(self): self.assertLessEqual(self.net.time, max_steps * max_step_size) self.assertEqual(self.net.max_steps, max_steps) - def test_wall_type(self): + def test_wall_type1(self): self.make_reactors(P1=101325, P2=300000) self.add_wall(K=0.1, A=1.0) - self.assertEqual(self.w.type, "Wall") + net = ct.ReactorNet([self.r1, self.r2]) # assigns default names + assert self.r1.name.startswith(f"{self.r1.type}_") # default name + assert self.r2.name.startswith(f"{self.r2.type}_") # default name + assert self.w.type == "Wall" + assert self.w.name.startswith("Wall_") # default name + self.w.name = "name-of-wall" + assert self.w.name == "name-of-wall" + + def test_wall_type2(self): + self.make_reactors(n_reactors=1) + res = ct.Reservoir(self.gas1) + w = ct.Wall(self.r1, res) + net = ct.ReactorNet([self.r1]) # assigns default names + assert self.r1.name.startswith(f"{self.r1.type}_") # default name + assert w.type == "Wall" + assert w.name.startswith("Wall_") # default name + + def test_wall_type3(self): + self.make_reactors(n_reactors=1) + res = ct.Reservoir(self.gas1) + w = ct.Wall(res, self.r1) + net = ct.ReactorNet([self.r1]) # assigns default names + assert self.r1.name.startswith(f"{self.r1.type}_") # default name + assert w.type == "Wall" + assert w.name.startswith("Wall_") # default name def test_equalize_pressure(self): self.make_reactors(P1=101325, P2=300000) @@ -555,6 +579,15 @@ def mdot(t): self.assertNear(ma + 0.1, mb) self.assertArrayNear(ma * Ya + 0.1 * gas2.Y, mb * Yb) + def test_mass_flow_controller_type(self): + self.make_reactors(n_reactors=2) + mfc = ct.MassFlowController(self.r1, self.r2) + net = ct.ReactorNet([self.r1, self.r2]) # assigns default names + assert mfc.type == "MassFlowController" + assert mfc.name.startswith("MassFlowController_") # default name + mfc.name = "name-of-mfc" + assert mfc.name == "name-of-mfc" + def test_mass_flow_controller_errors(self): # Make sure Python error message actually gets displayed self.make_reactors(n_reactors=2) @@ -692,6 +725,26 @@ def test_valve_timing(self): assert valve.pressure_function == approx(delta_p()) assert valve.mass_flow_rate == approx(mdot()) + def test_valve_type1(self): + self.make_reactors() + res = ct.Reservoir(self.gas1) + v = ct.Valve(self.r1, res) + ct.ReactorNet([self.r1]) # assigns default names + assert self.r1.name.startswith(f"{self.r1.type}_") # default name + assert res.name.startswith(f"{res.type}_") # default name + assert v.type == "Valve" + assert v.name.startswith("Valve_") # default name + v.name = "name-of-valve" + assert v.name == "name-of-valve" + + def test_valve_type2(self): + self.make_reactors() + res = ct.Reservoir(self.gas1) + ct.Valve(res, self.r1) + ct.ReactorNet([self.r1]) # assigns default names + assert self.r1.name.startswith(f"{self.r1.type}_") # default name + assert res.name.startswith(f"{res.type}_") # default name + @pytest.mark.usefixtures("allow_deprecated") def test_valve_errors(self): self.make_reactors() @@ -757,6 +810,17 @@ def test_pressure_controller2(self): dP = self.r1.thermo.P - outlet_reservoir.thermo.P self.assertNear(mdot(t) + pfunc(dP), pc.mass_flow_rate) + def test_pressure_controller_type(self): + self.make_reactors() + res = ct.Reservoir(self.gas1) + mfc = ct.MassFlowController(res, self.r1, mdot=0.6) + p = ct.PressureController(self.r1, self.r2, primary=mfc, K=0.5) + net = ct.ReactorNet([self.r1, self.r2]) # assigns default names + assert p.type == "PressureController" + assert p.name.startswith("PressureController_") # default name + p.name = "name-of-pressure-controller" + assert p.name == "name-of-pressure-controller" + def test_pressure_controller_errors(self): self.make_reactors() res = ct.Reservoir(self.gas1) @@ -1294,6 +1358,13 @@ def create_reactors(self, add_Q=False, add_mdot=False, add_surf=False): self.net2.max_time_step = 0.05 self.net2.max_err_test_fails = 10 + def test_reactor_surface_type(self): + self.create_reactors(add_surf=True) + assert self.surf1.type == "ReactorSurface" + assert self.surf1.name.startswith("ReactorSurface_") # default name + self.surf1.name = "name-of-reactor-surface" + assert self.surf1.name == "name-of-reactor-surface" + def test_component_index(self): self.create_reactors(add_surf=True) for (gas,net,iface,r) in ((self.gas1, self.net1, self.interface1, self.r1), From e856a3f11c37b775cc27064b6900fe9b3babf3f2 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Thu, 8 Aug 2024 08:46:12 -0500 Subject: [PATCH 6/9] [clib/MATLAB] Expose zeroD object names --- include/cantera/clib/ctreactor.h | 14 ++- .../matlab_experimental/Reactor/FlowDevice.m | 17 +++- .../matlab_experimental/Reactor/Reactor.m | 10 ++ interfaces/matlab_experimental/Reactor/Wall.m | 17 +++- src/clib/ctreactor.cpp | 93 +++++++++++++++++-- test/clib/test_ctreactor.cpp | 9 ++ 6 files changed, 147 insertions(+), 13 deletions(-) diff --git a/include/cantera/clib/ctreactor.h b/include/cantera/clib/ctreactor.h index 263f445af7..a874b3255c 100644 --- a/include/cantera/clib/ctreactor.h +++ b/include/cantera/clib/ctreactor.h @@ -19,6 +19,8 @@ extern "C" { CANTERA_CAPI int reactor_new(const char* type, int n, const char* name); CANTERA_CAPI int reactor_del(int i); + CANTERA_CAPI int reactor_name(int i, int len, char* nbuf); + CANTERA_CAPI int reactor_setName(int i, const char* name); CANTERA_CAPI int reactor_setInitialVolume(int i, double v); CANTERA_CAPI int reactor_setChemistry(int i, int cflag); CANTERA_CAPI int reactor_setEnergy(int i, int eflag); @@ -49,8 +51,10 @@ extern "C" { CANTERA_CAPI double reactornet_atol(int i); CANTERA_CAPI double reactornet_sensitivity(int i, const char* v, int p, int r); - CANTERA_CAPI int flowdev_new(const char* type); + CANTERA_CAPI int flowdev_new(const char* type, const char* name); CANTERA_CAPI int flowdev_del(int i); + CANTERA_CAPI int flowdev_name(int i, int len, char* nbuf); + CANTERA_CAPI int flowdev_setName(int i, const char* name); CANTERA_CAPI int flowdev_install(int i, int n, int m); CANTERA_CAPI int flowdev_setPrimary(int i, int n); CANTERA_CAPI double flowdev_massFlowRate(int i); @@ -60,8 +64,10 @@ extern "C" { CANTERA_CAPI int flowdev_setPressureFunction(int i, int n); CANTERA_CAPI int flowdev_setTimeFunction(int i, int n); - CANTERA_CAPI int wall_new(const char* type); + CANTERA_CAPI int wall_new(const char* type, const char* name); CANTERA_CAPI int wall_del(int i); + CANTERA_CAPI int wall_name(int i, int len, char* nbuf); + CANTERA_CAPI int wall_setName(int i, const char* name); CANTERA_CAPI int wall_install(int i, int n, int m); CANTERA_CAPI double wall_expansionRate(int i); CANTERA_CAPI double wall_heatRate(int i); @@ -75,8 +81,10 @@ extern "C" { CANTERA_CAPI int wall_setEmissivity(int i, double epsilon); CANTERA_CAPI int wall_ready(int i); - CANTERA_CAPI int reactorsurface_new(int type); + CANTERA_CAPI int reactorsurface_new(const char* name); CANTERA_CAPI int reactorsurface_del(int i); + CANTERA_CAPI int reactorsurface_name(int i, int len, char* nbuf); + CANTERA_CAPI int reactorsurface_setName(int i, const char* name); CANTERA_CAPI int reactorsurface_install(int i, int n); CANTERA_CAPI int reactorsurface_setkinetics(int i, int n); CANTERA_CAPI double reactorsurface_area(int i); diff --git a/interfaces/matlab_experimental/Reactor/FlowDevice.m b/interfaces/matlab_experimental/Reactor/FlowDevice.m index fcd645ad53..0069902a17 100644 --- a/interfaces/matlab_experimental/Reactor/FlowDevice.m +++ b/interfaces/matlab_experimental/Reactor/FlowDevice.m @@ -30,6 +30,8 @@ properties (SetAccess = public) + name % name of flow device. + % Upstream object of type :mat:class:`Reactor` or :mat:class:`Reservoir`. upstream @@ -56,7 +58,7 @@ methods %% FlowDevice Class Constructor - function x = FlowDevice(typ) + function x = FlowDevice(typ, name) % Create a :mat:class:`FlowDevice` object. ctIsLoaded; @@ -64,9 +66,12 @@ if nargin == 0 error('please specify the type of flow device to be created'); end + if nargin < 2 + name = '(none)'; + end x.type = typ; - x.id = ctFunc('flowdev_new', typ); + x.id = ctFunc('flowdev_new', typ, name); x.upstream = -1; x.downstream = -1; end @@ -112,12 +117,20 @@ function install(f, upstream, downstream) %% FlowDevice Get Methods + function name = get.name(f) + name = ctString('flowdev_name', f.id); + end + function mdot = get.massFlowRate(f) mdot = ctFunc('flowdev_massFlowRate2', f.id); end %% FlowDevice Set Methods + function set.name(f, name) + ctFunc('flowdev_setName', f.id, name); + end + function set.massFlowRate(f, mdot) if strcmp(f.type, 'MassFlowController') diff --git a/interfaces/matlab_experimental/Reactor/Reactor.m b/interfaces/matlab_experimental/Reactor/Reactor.m index 8f7b3d1511..1404386894 100644 --- a/interfaces/matlab_experimental/Reactor/Reactor.m +++ b/interfaces/matlab_experimental/Reactor/Reactor.m @@ -9,6 +9,8 @@ properties (SetAccess = public) + name % Name of reactor. + contents % Density of the reactor contents at the end of the last call to @@ -158,6 +160,10 @@ function addSensitivityReaction(r, m) %% Reactor Get Methods + function name = get.name(r) + name = ctString('reactor_name', r.id); + end + function temperature = get.T(r) temperature = ctFunc('reactor_temperature', r.id); end @@ -213,6 +219,10 @@ function addSensitivityReaction(r, m) %% Reactor set methods + function set.name(r, name) + ctFunc('reactor_setName', r.id, name); + end + function set.V(r, v0) ctFunc('reactor_setInitialVolume', r.id, v0); diff --git a/interfaces/matlab_experimental/Reactor/Wall.m b/interfaces/matlab_experimental/Reactor/Wall.m index 05721aaddb..4712dc1e2d 100644 --- a/interfaces/matlab_experimental/Reactor/Wall.m +++ b/interfaces/matlab_experimental/Reactor/Wall.m @@ -52,6 +52,8 @@ properties (SetAccess = protected) + name % Name of wall. + left % Reactor on the left. right % Reactor on the right. @@ -87,15 +89,18 @@ methods %% Wall Class Constructor - function w = Wall(l, r) + function w = Wall(l, r, name) % Create a :mat:class:`Wall` object. ctIsLoaded; % At the moment, only one wall type is implemented typ = 'Wall'; + if nargin < 3 + name = '(none)'; + end w.type = char(typ); - w.id = ctFunc('wall_new', w.type); + w.id = ctFunc('wall_new', w.type, name); % Install the wall between left and right reactors w.left = l; @@ -127,6 +132,10 @@ function delete(w) %% ReactorNet get methods + function name = get.name(w) + name = ctString('wall_name', w.id); + end + function a = get.area(w) a = ctFunc('wall_area', w.id); end @@ -141,6 +150,10 @@ function delete(w) %% ReactorNet set methods + function set.name(w, name) + ctFunc('wall_setName', w.id, name); + end + function set.area(w, a) ctFunc('wall_setArea', w.id, a); end diff --git a/src/clib/ctreactor.cpp b/src/clib/ctreactor.cpp index c3eea3f78a..2b066fd51d 100644 --- a/src/clib/ctreactor.cpp +++ b/src/clib/ctreactor.cpp @@ -12,6 +12,7 @@ #include "cantera/thermo/ThermoPhase.h" #include "cantera/kinetics/Kinetics.h" #include "cantera/zerodim.h" +#include "cantera/base/stringUtils.h" #include "clib_utils.h" using namespace Cantera; @@ -59,6 +60,26 @@ extern "C" { } } + int reactor_name(int i, int len, char* nbuf) + { + try { + return static_cast( + copyString(ReactorCabinet::at(i)->name(), nbuf, len)); + } catch (...) { + return handleAllExceptions(-1, ERR); + } + } + + int reactor_setName(int i, const char* name) + { + try { + ReactorCabinet::at(i)->setName(name); + return 0; + } catch (...) { + return handleAllExceptions(-1, ERR); + } + } + int reactor_setInitialVolume(int i, double v) { try { @@ -349,10 +370,10 @@ extern "C" { // flow devices - int flowdev_new(const char* type) + int flowdev_new(const char* type, const char* name) { try { - return FlowDeviceCabinet::add(newFlowDevice(type)); + return FlowDeviceCabinet::add(newFlowDevice(type, name)); } catch (...) { return handleAllExceptions(-1, ERR); } @@ -368,6 +389,26 @@ extern "C" { } } + int flowdev_name(int i, int len, char* nbuf) + { + try { + return static_cast( + copyString(FlowDeviceCabinet::at(i)->name(), nbuf, len)); + } catch (...) { + return handleAllExceptions(-1, ERR); + } + } + + int flowdev_setName(int i, const char* name) + { + try { + FlowDeviceCabinet::at(i)->setName(name); + return 0; + } catch (...) { + return handleAllExceptions(-1, ERR); + } + } + int flowdev_install(int i, int n, int m) { try { @@ -455,10 +496,10 @@ extern "C" { ///////////// Walls /////////////////////// - int wall_new(const char* type) + int wall_new(const char* type, const char* name) { try { - return WallCabinet::add(newWall(type)); + return WallCabinet::add(newWall(type, name)); } catch (...) { return handleAllExceptions(-1, ERR); } @@ -474,6 +515,26 @@ extern "C" { } } + int wall_name(int i, int len, char* nbuf) + { + try { + return static_cast( + copyString(WallCabinet::at(i)->name(), nbuf, len)); + } catch (...) { + return handleAllExceptions(-1, ERR); + } + } + + int wall_setName(int i, const char* name) + { + try { + WallCabinet::at(i)->setName(name); + return 0; + } catch (...) { + return handleAllExceptions(-1, ERR); + } + } + int wall_install(int i, int n, int m) { try { @@ -593,10 +654,10 @@ extern "C" { // ReactorSurface - int reactorsurface_new(int type) + int reactorsurface_new(const char* name) { try { - return ReactorSurfaceCabinet::add(make_shared()); + return ReactorSurfaceCabinet::add(make_shared(name)); } catch (...) { return handleAllExceptions(-1, ERR); } @@ -612,6 +673,26 @@ extern "C" { } } + int reactorsurface_name(int i, int len, char* nbuf) + { + try { + return static_cast( + copyString(ReactorSurfaceCabinet::at(i)->name(), nbuf, len)); + } catch (...) { + return handleAllExceptions(-1, ERR); + } + } + + int reactorsurface_setName(int i, const char* name) + { + try { + ReactorSurfaceCabinet::at(i)->setName(name); + return 0; + } catch (...) { + return handleAllExceptions(-1, ERR); + } + } + int reactorsurface_install(int i, int n) { try { diff --git a/test/clib/test_ctreactor.cpp b/test/clib/test_ctreactor.cpp index 179f0326d3..cd84174383 100644 --- a/test/clib/test_ctreactor.cpp +++ b/test/clib/test_ctreactor.cpp @@ -13,6 +13,15 @@ TEST(ctreactor, reactor_soln) int sol = soln_newSolution("gri30.yaml", "gri30", "none"); int reactor = reactor_new("IdealGasReactor", sol, "test"); ASSERT_EQ(reactor, 0); + + int ret = reactor_setName(reactor, "spam"); + ASSERT_EQ(ret, 0); + int buflen = reactor_name(reactor, 0, 0); + char* buf = new char[buflen]; + reactor_name(reactor, buflen, buf); + string rName = buf; + ASSERT_EQ(rName, "spam"); + delete[] buf; } vector T_ctreactor = { From 186b9a8fb9bf96c68d6cbdcdca25e9fe7692cb3d Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Thu, 8 Aug 2024 12:06:24 -0500 Subject: [PATCH 7/9] [MATLAB] Update API & docstrings --- .../Reactor/ConstPressureReactor.m | 13 ++-- .../matlab_experimental/Reactor/FlowDevice.m | 6 +- .../matlab_experimental/Reactor/FlowReactor.m | 13 ++-- .../Reactor/IdealGasConstPressureReactor.m | 13 ++-- .../Reactor/IdealGasReactor.m | 13 ++-- .../Reactor/MassFlowController.m | 14 ++-- .../Reactor/ReactorSurface.m | 64 ++++++------------- .../matlab_experimental/Reactor/Reservoir.m | 13 ++-- .../matlab_experimental/Reactor/Valve.m | 14 ++-- interfaces/matlab_experimental/Reactor/Wall.m | 8 +-- samples/matlab_experimental/surf_reactor.m | 3 +- 11 files changed, 82 insertions(+), 92 deletions(-) diff --git a/interfaces/matlab_experimental/Reactor/ConstPressureReactor.m b/interfaces/matlab_experimental/Reactor/ConstPressureReactor.m index 0b45ee3aaa..dede06b3e6 100644 --- a/interfaces/matlab_experimental/Reactor/ConstPressureReactor.m +++ b/interfaces/matlab_experimental/Reactor/ConstPressureReactor.m @@ -1,7 +1,7 @@ classdef ConstPressureReactor < Reactor % Create a constant pressure reactor object. :: % - % >> r = ConstPressureReactor(contents) + % >> r = ConstPressureReactor(contents, name) % % A :mat:class:`ConstPressureReactor` is an instance of class % :mat:class:`Reactor` where the pressure is held constant. The volume @@ -10,26 +10,27 @@ % % .. code-block:: matlab % - % r1 = ConstPressureReactor % an empty reactor % r2 = ConstPressureReactor(contents) % a reactor containing contents % % See also: :mat:class:`Reactor` % % :param contents: % Cantera :mat:class:`Solution` to be set as the contents of the reactor. + % :param name: + % Reactor name (optional; default is ``(none)``). % :return: % Instance of class :mat:class:`ConstPressureReactor`. methods - function r = ConstPressureReactor(contents) + function r = ConstPressureReactor(contents, name) % Constructor - if nargin == 0 - contents = 0; + if nargin < 2 + name = '(none)' end - r@Reactor(contents, 'ConstPressureReactor'); + r@Reactor(contents, 'ConstPressureReactor', name); end end diff --git a/interfaces/matlab_experimental/Reactor/FlowDevice.m b/interfaces/matlab_experimental/Reactor/FlowDevice.m index 0069902a17..4dfd8438bc 100644 --- a/interfaces/matlab_experimental/Reactor/FlowDevice.m +++ b/interfaces/matlab_experimental/Reactor/FlowDevice.m @@ -1,7 +1,7 @@ classdef FlowDevice < handle % FlowDevice Class :: % - % >> x = FlowDevice(typ) + % >> x = FlowDevice(typ, name) % % Base class for devices that allow flow between reactors. % :mat:class:`FlowDevice` objects are assumed to be adiabatic, @@ -18,6 +18,8 @@ % Type of :mat:class:`FlowDevice` to be created. ``typ='MassFlowController'`` % for :mat:class:`MassFlowController`, ``typ='PressureController'`` for % :mat:class:`PressureController`, and ``typ='Valve'`` for :mat:class:`Valve`. + % :param name: + % Reactor name (optional; default is ``(none)``). % :return: % Instance of class :mat:class:`FlowDevice`. @@ -30,7 +32,7 @@ properties (SetAccess = public) - name % name of flow device. + name % Name of flow device. % Upstream object of type :mat:class:`Reactor` or :mat:class:`Reservoir`. upstream diff --git a/interfaces/matlab_experimental/Reactor/FlowReactor.m b/interfaces/matlab_experimental/Reactor/FlowReactor.m index 60652cb567..8b9eeff5ac 100644 --- a/interfaces/matlab_experimental/Reactor/FlowReactor.m +++ b/interfaces/matlab_experimental/Reactor/FlowReactor.m @@ -1,33 +1,34 @@ classdef FlowReactor < Reactor % Create a flow reactor object. :: % - % >> r = FlowReactor(contents) + % >> r = FlowReactor(contents, name) % % A reactor representing adiabatic plug flow in a constant-area % duct. Examples: % % .. code-block:: matlab % - % r1 = FlowReactor % an empty reactor % r2 = FlowReactor(gas) % a reactor containing a gas % % See also: :mat:class:`Reactor` % % :param contents: % Cantera :mat:class:`Solution` to be set as the contents of the reactor. + % :param name: + % Reactor name (optional; default is ``(none)``). % :return: % Instance of class :mat:class:`FlowReactor`. methods - function r = FlowReactor(contents) + function r = FlowReactor(contents, name) % Constructor - if nargin == 0 - contents = 0; + if nargin < 2 + name = '(none)' end - r@Reactor(contents, 'FlowReactor'); + r@Reactor(contents, 'FlowReactor', name); end end diff --git a/interfaces/matlab_experimental/Reactor/IdealGasConstPressureReactor.m b/interfaces/matlab_experimental/Reactor/IdealGasConstPressureReactor.m index fdbb703fdf..2faa02acae 100644 --- a/interfaces/matlab_experimental/Reactor/IdealGasConstPressureReactor.m +++ b/interfaces/matlab_experimental/Reactor/IdealGasConstPressureReactor.m @@ -1,7 +1,7 @@ classdef IdealGasConstPressureReactor < Reactor % Create a constant pressure reactor with an ideal gas. :: % - % >> r = IdealGasConstPressureReactor(contents) + % >> r = IdealGasConstPressureReactor(contents, name) % % An :mat:class:`IdealGasConstPressureReactor` is an instance of % :mat:class:`Reactor` where the pressure is held constant. @@ -13,26 +13,27 @@ % % .. code-block:: matlab % - % r1 = IdealGasConstPressureReactor % an empty reactor % r2 = IdealGasConstPressureReactor(gas) % a reactor containing a gas % % See also: :mat:class:`Reactor` % % :param contents: % Cantera :mat:class:`Solution` to be set as the contents of the reactor. + % :param name: + % Reactor name (optional; default is ``(none)``). % :return: % Instance of class :mat:class:`IdealGasConstPressureReactor`. methods - function r = IdealGasConstPressureReactor(contents) + function r = IdealGasConstPressureReactor(contents, name) % Constructor - if nargin == 0 - contents = 0; + if nargin < 2 + name = '(none)'; end - r@Reactor(contents, 'IdealGasConstPressureReactor'); + r@Reactor(contents, 'IdealGasConstPressureReactor', name); end end diff --git a/interfaces/matlab_experimental/Reactor/IdealGasReactor.m b/interfaces/matlab_experimental/Reactor/IdealGasReactor.m index 1ba96fdf2c..8049cadd13 100644 --- a/interfaces/matlab_experimental/Reactor/IdealGasReactor.m +++ b/interfaces/matlab_experimental/Reactor/IdealGasReactor.m @@ -1,7 +1,7 @@ classdef IdealGasReactor < Reactor % Create a reactor with an ideal gas. :: % - % >> r = IdealGasReactor(contents) + % >> r = IdealGasReactor(contents, name) % % An :mat:class:`IdealGasReactor` is an instance of :mat:class:`Reactor` where % the governing equations are specialized for the ideal gas equation of state @@ -9,26 +9,27 @@ % % .. code-block:: matlab % - % r1 = IdealGasReactor % an empty reactor % r2 = IdealGasReactor(gas) % a reactor containing a gas % % See also: :mat:class:`Reactor` % % :param contents: % Cantera :mat:class:`Solution` to be set as the contents of the reactor. + % :param name: + % Reactor name (optional; default is ``(none)``). % :return: % Instance of class :mat:class:`IdealGasReactor`. methods - function r = IdealGasReactor(contents) + function r = IdealGasReactor(contents, name) % Constructor - if nargin == 0 - contents = 0; + if nargin < 2 + name = '(none)'; end - r@Reactor(contents, 'IdealGasReactor'); + r@Reactor(contents, 'IdealGasReactor', name); end end diff --git a/interfaces/matlab_experimental/Reactor/MassFlowController.m b/interfaces/matlab_experimental/Reactor/MassFlowController.m index c6f9f0c243..fe8d9a134e 100644 --- a/interfaces/matlab_experimental/Reactor/MassFlowController.m +++ b/interfaces/matlab_experimental/Reactor/MassFlowController.m @@ -1,7 +1,7 @@ classdef MassFlowController < FlowDevice % Create a mass flow controller. :: % - % >> m = MassFlowController(upstream, downstream) + % >> m = MassFlowController(upstream, downstream, name) % % Creates an instance of class :mat:class:`FlowDevice` configured to % simulate a mass flow controller that maintains a constant mass flow @@ -17,20 +17,22 @@ % Upstream :mat:class:`Reactor` or :mat:class:`Reservoir`. % :param downstream: % Downstream :mat:class:`Reactor` or :mat:class:`Reservoir`. + % :param name: + % Flow device name (optional; default is ``(none)``). % :return: % Instance of class :mat:class:`FlowDevice`. methods - function m = MassFlowController(upstream, downstream) + function m = MassFlowController(upstream, downstream, name) % Constructor - m@FlowDevice('MassFlowController'); - - if nargin == 2 - m.install(upstream, downstream) + if nargin < 3 + name = '(none)'; end + m@FlowDevice('MassFlowController', name); + m.install(upstream, downstream) end end diff --git a/interfaces/matlab_experimental/Reactor/ReactorSurface.m b/interfaces/matlab_experimental/Reactor/ReactorSurface.m index 6af6b71c1d..a0793c0519 100644 --- a/interfaces/matlab_experimental/Reactor/ReactorSurface.m +++ b/interfaces/matlab_experimental/Reactor/ReactorSurface.m @@ -1,7 +1,7 @@ classdef ReactorSurface < handle % ReactorSurface Class :: % - % >> s = ReactorSurface(surf, reactor, area) + % >> s = ReactorSurface(surf, reactor, name) % % A surface on which heterogeneous reactions take place. The % mechanism object (typically an instance of :mat:class:`Interface`) @@ -10,18 +10,14 @@ % temperature on each side is taken to be equal to the % temperature of the reactor. % - % Note: all of the arguments are optional and can be activated - % after initial construction by using the various methods of - % the :mat:class:`ReactorSurface` class. - % % :param surf: % Surface reaction mechanisms for the left-facing surface. % This must bean instance of class :mat:class:`Kinetics`, or of a class % derived from Kinetics, such as :mat:class:`Interface`. % :param reactor: % Instance of class 'Reactor' to be used as the adjacent bulk phase. - % :param area: - % The area of the surface in m^2. Defaults to 1.0 m^2 if not specified. + % :param name: + % Reactor surface name (optional; default is ``(none)``). % :return: % Instance of class :mat:class:`ReactorSurface`. @@ -29,56 +25,30 @@ surfID end - properties (SetAccess = protected) - reactor - end - properties (SetAccess = public) + name % Name of reactor surface. + area % Area of the reactor surface in m^2. end methods %% ReactorSurface Class Constructor - function s = ReactorSurface(surf, reactor, area) + function s = ReactorSurface(surf, reactor, name) % Create a :mat:class:`ReactorSurface` object. ctIsLoaded; - s.surfID = ctFunc('reactorsurface_new', 0); - s.reactor = -1; - - if nargin >= 1 - ikin = 0; - - if isa(surf, 'Kinetics') - ikin = surf.kinID; - end - - ctFunc('reactorsurface_setkinetics', s.surfID, ikin); - end - - if nargin >= 2 - - if isa(reactor, 'Reactor') - s.reactor = reactor; - ctFunc('reactorsurface_install', s.surfID, reactor.id); - else - warning('Reactor was not installed due to incorrect type'); - end - + if ~isa(surf, 'Kinetics') || ~isa(reactor, 'Reactor') + error('Invalid parameters.') end - - if nargin >= 3 - - if isnumeric(area) - s.area = area; - else - warning('Area was not a number and was not set'); - end - + if nargin < 3 + name = '(none)'; end + s.surfID = ctFunc('reactorsurface_new', name); + ctFunc('reactorsurface_setkinetics', s.surfID, surf.kinID); + ctFunc('reactorsurface_install', s.surfID, reactor.id); end %% ReactorSurface Class Destructor @@ -106,12 +76,20 @@ function addSensitivityReaction(s, m) %% ReactorSurface Get Methods + function name = get.name(s) + name = ctString('reactorsurface_name', s.surfID); + end + function a = get.area(s) a = ctFunc('reactorsurface_area', s.surfID); end %% ReactorSurface Set Methods + function set.name(s, name) + ctFunc('reactorsurface_setName', s.surfID, name); + end + function set.area(s, a) ctFunc('reactorsurface_setArea', s.surfID, a); end diff --git a/interfaces/matlab_experimental/Reactor/Reservoir.m b/interfaces/matlab_experimental/Reactor/Reservoir.m index 8097fe3fd7..ac281b189c 100644 --- a/interfaces/matlab_experimental/Reactor/Reservoir.m +++ b/interfaces/matlab_experimental/Reactor/Reservoir.m @@ -1,7 +1,7 @@ classdef Reservoir < Reactor % Create a :mat:class:`Reservoir` object. :: % - % >> r = Reservoir(contents) + % >> r = Reservoir(contents, name) % % A :mat:class:`Reservoir` is an instance of class :mat:class:`Reactor` % configured so that its intensive state is constant in time. A reservoir @@ -14,26 +14,27 @@ % % .. code-block:: matlab % - % r1 = Reservoir % an empty reservoir % r2 = Reservoir(gas) % a reservoir containing a gas % % See also: :mat:class:`Reactor` % % :param contents: % Cantera :mat:class:`Solution` to be set as the contents of the reactor. + % :param name: + % Reservoir name (optional; default is ``(none)``). % :return: % Instance of class :mat:class:`Reactor`. methods - function r = Reservoir(contents) + function r = Reservoir(contents, name) % Constructor - if nargin == 0 - contents = 0; + if nargin < 2 + name = '(none)'; end - r@Reactor(contents, 'Reservoir'); + r@Reactor(contents, 'Reservoir', name); end end diff --git a/interfaces/matlab_experimental/Reactor/Valve.m b/interfaces/matlab_experimental/Reactor/Valve.m index 2a9bef3d2a..36ca248f87 100644 --- a/interfaces/matlab_experimental/Reactor/Valve.m +++ b/interfaces/matlab_experimental/Reactor/Valve.m @@ -1,7 +1,7 @@ classdef Valve < FlowDevice % Create a valve. :: % - % >> v = Valve(upstream, downstream) + % >> v = Valve(upstream, downstream, name) % % Create an instance of class :mat:class:`FlowDevice` configured to % simulate a valve that produces a flow rate proportional to the @@ -26,20 +26,22 @@ % Upstream reactor or reservoir. % :param downstream: % Downstream Reactor or reservoir. + % :param name: + % Valve name (optional; default is ``(none)``). % :return: % Instance of class :mat:class:`FlowDevice`. methods - function v = Valve(upstream, downstream) + function v = Valve(upstream, downstream, name) % Constructor - v@FlowDevice('Valve'); - - if nargin == 2 - v.install(upstream, downstream) + if nargin < 3 + name = '(none)'; end + v@FlowDevice('Valve', name); + v.install(upstream, downstream) end end diff --git a/interfaces/matlab_experimental/Reactor/Wall.m b/interfaces/matlab_experimental/Reactor/Wall.m index 4712dc1e2d..3557a81a82 100644 --- a/interfaces/matlab_experimental/Reactor/Wall.m +++ b/interfaces/matlab_experimental/Reactor/Wall.m @@ -1,7 +1,7 @@ classdef Wall < handle % Wall Class :: % - % >> x = Wall(l, r) + % >> x = Wall(l, r, name) % % A Wall separates two reactors, or a reactor and a reservoir. % A Wall has a finite area, may conduct heat between the two @@ -40,6 +40,8 @@ % :param r: % Instance of class :mat:class:`Reactor` to be used as the bulk phase % on the right side of the wall. + % :param name: + % Wall name (optional; default is ``(none)``). % :return: % Instance of class :mat:class:`Wall`. @@ -114,9 +116,7 @@ % Check whether the wall is ready. ok = ctFunc('wall_ready', w.id); - if ok - disp('The wall object is ready.'); - else + if ~ok error('The wall object is not ready.'); end diff --git a/samples/matlab_experimental/surf_reactor.m b/samples/matlab_experimental/surf_reactor.m index a7ead24530..fe33289c1e 100644 --- a/samples/matlab_experimental/surf_reactor.m +++ b/samples/matlab_experimental/surf_reactor.m @@ -46,7 +46,8 @@ A = 1e-4; % Wall area % Add a reacting surface, with an area matching that of the wall -rsurf = ReactorSurface(surf, r, A); +rsurf = ReactorSurface(surf, r); +rsurf.area = A; % set the wall area and heat transfer coefficient. w.area = A; From 64ac7f33c96641eb9c6c715cd74190759de9777d Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Sat, 10 Aug 2024 07:29:28 -0500 Subject: [PATCH 8/9] [Python] Make reactor 'name' arguments consistent --- interfaces/cython/cantera/reactor.pyx | 62 +++++++++++++-------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/interfaces/cython/cantera/reactor.pyx b/interfaces/cython/cantera/reactor.pyx index 1ae1e22986..552e84c263 100644 --- a/interfaces/cython/cantera/reactor.pyx +++ b/interfaces/cython/cantera/reactor.pyx @@ -16,7 +16,7 @@ cdef class ReactorBase: Common base class for reactors and reservoirs. """ reactor_type = "none" - def __cinit__(self, _SolutionBase contents=None, name=None, *, **kwargs): + def __cinit__(self, _SolutionBase contents=None, *, name="(none)", **kwargs): if isinstance(contents, _SolutionBase): self._reactor = newReactor(stringify(self.reactor_type), contents._base, stringify(name)) @@ -26,8 +26,8 @@ cdef class ReactorBase: self._reactor.get().setName(stringify(name)) self.rbase = self._reactor.get() - def __init__(self, _SolutionBase contents=None, name=None, *, volume=None, - node_attr=None): + def __init__(self, _SolutionBase contents=None, *, + name="(none)", volume=None, node_attr=None): self._inlets = [] self._outlets = [] self._walls = [] @@ -198,16 +198,19 @@ cdef class Reactor(ReactorBase): def __cinit__(self, *args, **kwargs): self.reactor = (self.rbase) - def __init__(self, contents=None, *, name=None, energy='on', group_name="", **kwargs): + def __init__(self, contents=None, *, + name="(none)", energy='on', group_name="", **kwargs): """ :param contents: Reactor contents. If not specified, the reactor is initially empty. In this case, call `insert` to specify the contents. Providing valid contents will become mandatory after Cantera 3.1. :param name: - Used only to identify this reactor in output. If not specified, - defaults to ``'Reactor_n'``, where *n* is an integer assigned in - the order `Reactor` objects are created. + Name string. If not specified, the name initially defaults to ``'(none)'`` + and changes to ``'_n'`` when `Reactor` objects are installed + within a `ReactorNet`. For the latter, ```` is the type of + the reactor and *n* is an integer assigned in the order reactors are + installed. :param energy: Set to ``'on'`` or ``'off'``. If set to ``'off'``, the energy equation is not solved, and the temperature is held at its @@ -234,7 +237,7 @@ cdef class Reactor(ReactorBase): >>> r3 = Reactor(name='adiabatic_reactor', contents=gas) """ - super().__init__(contents, name, **kwargs) + super().__init__(contents, name=name, **kwargs) if energy == 'off': self.energy_enabled = False @@ -787,8 +790,10 @@ cdef class ReactorSurface: Represents a surface in contact with the contents of a reactor. :param name: - Name string. If omitted, the name is ``'ReactorSurface_n'``, where ``'n'`` - is an integer assigned in the order reactor surfaces are created. + Name string. If not specified, the name initially defaults to ``'(none)'`` and + changes to ``'ReactorSurface_n'`` when when associated `Reactor` objects are + installed within a `ReactorNet`. For the latter, *n* is an integer assigned in + the order reactor surfaces are detected. :param kin: The `Kinetics` or `Interface` object representing reactions on this surface. @@ -803,14 +808,14 @@ cdef class ReactorSurface: .. versionadded:: 3.1 Added the ``node_attr`` parameter. """ - def __cinit__(self, *args, **kwargs): - name = kwargs.get("name") + def __cinit__(self, *args, name="(none)", **kwargs): self.surface = new CxxReactorSurface(stringify(name)) def __dealloc__(self): del self.surface - def __init__(self, kin=None, Reactor r=None, *, name=None, A=None, node_attr=None): + def __init__(self, kin=None, Reactor r=None, *, + name="(none)", A=None, node_attr=None): if kin is not None: self.kinetics = kin if r is not None: @@ -946,12 +951,11 @@ cdef class WallBase: Common base class for walls. """ wall_type = "none" - def __cinit__(self, *args, **kwargs): - name = kwargs.get("name") + def __cinit__(self, *args, name="(none)", **kwargs): self._wall = newWall(stringify(self.wall_type), stringify(name)) self.wall = self._wall.get() - def __init__(self, left, right, *, name=None, A=None, K=None, U=None, + def __init__(self, left, right, *, name="(none)", A=None, K=None, U=None, Q=None, velocity=None, edge_attr=None): """ :param left: @@ -959,8 +963,11 @@ cdef class WallBase: :param right: Reactor or reservoir on the right. Required. :param name: - Name string. If omitted, the name is ``'Wall_n'``, where ``'n'`` - is an integer assigned in the order walls are created. + Name string. If not specified, the name initially defaults to ``'(none)'`` + and changes to ``'_n'`` when when associated `Reactor` objects + are installed within a `ReactorNet`. For the latter, ```` is + the type of the wall and *n* is an integer assigned in the order walls are + detected. :param A: Wall area [m^2]. Defaults to 1.0 m^2. :param K: @@ -1219,12 +1226,11 @@ cdef class FlowDevice: pressure between the upstream and downstream reactors. """ flowdevice_type = "none" - def __cinit__(self, *args, **kwargs): - name = kwargs.get("name") + def __cinit__(self, *args, name="(none)", **kwargs): self._dev = newFlowDevice(stringify(self.flowdevice_type), stringify(name)) self.dev = self._dev.get() - def __init__(self, upstream, downstream, *, name=None, edge_attr=None): + def __init__(self, upstream, downstream, *, name="(none)", edge_attr=None): assert self.dev != NULL self._rate_func = None self.edge_attr = edge_attr or {} @@ -1390,7 +1396,7 @@ cdef class MassFlowController(FlowDevice): """ flowdevice_type = "MassFlowController" - def __init__(self, upstream, downstream, *, name=None, mdot=1., **kwargs): + def __init__(self, upstream, downstream, *, name="(none)", mdot=1., **kwargs): super().__init__(upstream, downstream, name=name, **kwargs) self.mass_flow_rate = mdot @@ -1464,7 +1470,7 @@ cdef class Valve(FlowDevice): """ flowdevice_type = "Valve" - def __init__(self, upstream, downstream, *, name=None, K=1., **kwargs): + def __init__(self, upstream, downstream, *, name="(none)", K=1., **kwargs): super().__init__(upstream, downstream, name=name, **kwargs) if isinstance(K, _numbers.Real): self.valve_coeff = K @@ -1507,14 +1513,8 @@ cdef class PressureController(FlowDevice): """ flowdevice_type = "PressureController" - def __init__(self, upstream, downstream, *, - name=None, primary=None, K=1., **kwargs): - if "master" in kwargs: - warnings.warn( - "PressureController: The 'master' keyword argument is deprecated; " - "use 'primary' instead.", DeprecationWarning) - primary = kwargs["master"] - super().__init__(upstream, downstream, name=name, **kwargs) + def __init__(self, upstream, downstream, *, name="(none)", primary=None, K=1.): + super().__init__(upstream, downstream, name=name) if primary is not None: self.primary = primary if isinstance(K, _numbers.Real): From afed40f9b4d48aa985a6958e8565d1518f13d1e1 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Mon, 19 Aug 2024 06:14:52 -0500 Subject: [PATCH 9/9] [googletest] Simplify char* handling --- test/clib/test_clib.cpp | 48 +++++++++++++++--------------------- test/clib/test_ctfunc.cpp | 14 +++++------ test/clib/test_ctonedim.cpp | 36 ++++++++++++--------------- test/clib/test_ctreactor.cpp | 7 +++--- 4 files changed, 45 insertions(+), 60 deletions(-) diff --git a/test/clib/test_clib.cpp b/test/clib/test_clib.cpp index a2b5128581..65f4dc869c 100644 --- a/test/clib/test_clib.cpp +++ b/test/clib/test_clib.cpp @@ -10,14 +10,11 @@ using ::testing::HasSubstr; string reportError() { - int buflen = 0; - char* output_buf = 0; - buflen = ct_getCanteraError(buflen, output_buf) + 1; - output_buf = new char[buflen]; - ct_getCanteraError(buflen, output_buf); - string err = output_buf; - delete[] output_buf; - return err; + vector output_buf; + int buflen = ct_getCanteraError(0, output_buf.data()) + 1; + output_buf.resize(buflen); + ct_getCanteraError(buflen, output_buf.data()); + return string(output_buf.data()); } TEST(ct, cabinet_exceptions) @@ -62,11 +59,10 @@ TEST(ct, new_solution) int thermo = soln_thermo(ref); ASSERT_EQ(thermo_parent(thermo), ref); - char* buf = new char[buflen]; - soln_name(ref, buflen, buf); - string solName = buf; + vector buf(buflen); + soln_name(ref, buflen, buf.data()); + string solName(buf.data()); ASSERT_EQ(solName, name); - delete[] buf; } TEST(ct, soln_objects) @@ -142,19 +138,17 @@ TEST(ct, new_interface) int ph_surf = soln_thermo(surf); int buflen = soln_name(ph_surf, 0, 0) + 1; // include \0 - char* buf = new char[buflen]; - soln_name(ph_surf, buflen, buf); - string solName = buf; + vector buf(buflen); + soln_name(ph_surf, buflen, buf.data()); + string solName(buf.data()); ASSERT_EQ(solName, "Pt_surf"); - delete[] buf; int kin_surf = soln_kinetics(surf); buflen = kin_getType(kin_surf, 0, 0) + 1; // include \0 - buf = new char[buflen]; - kin_getType(ph_surf, buflen, buf); - string kinType = buf; + buf.resize(buflen); + kin_getType(ph_surf, buflen, buf.data()); + string kinType(buf.data()); ASSERT_EQ(kinType, "surface"); - delete[] buf; } TEST(ct, new_interface_auto) @@ -170,18 +164,16 @@ TEST(ct, new_interface_auto) ASSERT_EQ(gas, 1); int buflen = soln_name(gas, 0, 0) + 1; // include \0 - char* buf = new char[buflen]; - soln_name(gas, buflen, buf); - string solName = buf; + vector buf(buflen); + soln_name(gas, buflen, buf.data()); + string solName(buf.data()); ASSERT_EQ(solName, "gas"); - delete[] buf; buflen = soln_adjacentName(surf, 0, 0, 0) + 1; - char* buf2 = new char[buflen]; - soln_adjacentName(surf, 0, buflen, buf2); - solName = buf2; + buf.resize(buflen); + soln_adjacentName(surf, 0, buflen, buf.data()); + solName = buf.data(); ASSERT_EQ(solName, "gas"); - delete[] buf2; } TEST(ct, thermo) diff --git a/test/clib/test_ctfunc.cpp b/test/clib/test_ctfunc.cpp index 80332d3c84..bacc31d97d 100644 --- a/test/clib/test_ctfunc.cpp +++ b/test/clib/test_ctfunc.cpp @@ -27,11 +27,10 @@ TEST(ctfunc, sin) EXPECT_DOUBLE_EQ(func_value(dfcn, 0.5), omega * cos(omega * 0.5)); int buflen = func_write(fcn, "x", 0, 0); - char* buf = new char[buflen]; - func_write(fcn, "x", buflen, buf); - string rep = buf; + vector buf(buflen); + func_write(fcn, "x", buflen, buf.data()); + string rep(buf.data()); ASSERT_EQ(rep, "\\sin(2.1x)"); - delete[] buf; } TEST(ctfunc, cos) @@ -123,11 +122,10 @@ TEST(ctfunc, poly) params = {1, 0, -2.2, 3.1}; fcn = func_new_advanced("polynomial3", params.size(), params.data()); int buflen = func_write(fcn, "x", 0, 0); - char* buf = new char[buflen]; - func_write(fcn, "x", buflen, buf); - string rep = buf; + vector buf(buflen); + func_write(fcn, "x", buflen, buf.data()); + string rep(buf.data()); ASSERT_EQ(rep, "x^3 - 2.2x + 3.1"); - delete[] buf; } TEST(ctfunc, Fourier) diff --git a/test/clib/test_ctonedim.cpp b/test/clib/test_ctonedim.cpp index 6325835b91..3e4f45d20b 100644 --- a/test/clib/test_ctonedim.cpp +++ b/test/clib/test_ctonedim.cpp @@ -29,11 +29,10 @@ TEST(ctonedim, freeflow) ASSERT_NEAR(flow1D_pressure(flow), P, 1e-5); int buflen = domain_type(flow, 0, 0); - char* buf = new char[buflen]; - domain_type(flow, buflen, buf); - string domType = buf; + vector buf(buflen); + domain_type(flow, buflen, buf.data()); + string domType(buf.data()); ASSERT_EQ(domType, "free-flow"); - delete[] buf; } TEST(ctonedim, inlet) @@ -43,11 +42,10 @@ TEST(ctonedim, inlet) ASSERT_GE(inlet, 0); int buflen = domain_type(inlet, 0, 0); - char* buf = new char[buflen]; - domain_type(inlet, buflen, buf); - string domType = buf; + vector buf(buflen); + domain_type(inlet, buflen, buf.data()); + string domType(buf.data()); ASSERT_EQ(domType, "inlet"); - delete[] buf; } TEST(ctonedim, outlet) @@ -57,11 +55,10 @@ TEST(ctonedim, outlet) ASSERT_GE(outlet, 0); int buflen = domain_type(outlet, 0, 0); - char* buf = new char[buflen]; - domain_type(outlet, buflen, buf); - string domType = buf; + vector buf(buflen); + domain_type(outlet, buflen, buf.data()); + string domType(buf.data()); ASSERT_EQ(domType, "outlet"); - delete[] buf; } TEST(ctonedim, reacting_surface) @@ -71,11 +68,10 @@ TEST(ctonedim, reacting_surface) ASSERT_GE(surf, 0); int buflen = domain_type(surf, 0, 0); - char* buf = new char[buflen]; - domain_type(surf, buflen, buf); - string domType = buf; + vector buf(buflen); + domain_type(surf, buflen, buf.data()); + string domType(buf.data()); ASSERT_EQ(domType, "reacting-surface"); - delete[] buf; } TEST(ctonedim, catcomb) @@ -170,11 +166,11 @@ TEST(ctonedim, freeflame) for (size_t i = 0; i < nsp; i++) { value = {yin[i], yin[i], yout[i], yout[i]}; int buflen = thermo_getSpeciesName(ph, i, 0, 0) + 1; // include \0 - char* buf = new char[buflen]; - thermo_getSpeciesName(ph, i, buflen, buf); - string name = buf; + vector buf(buflen); + thermo_getSpeciesName(ph, i, buflen, buf.data()); + string name(buf.data()); ASSERT_EQ(name, gas->speciesName(i)); - comp = static_cast(domain_componentIndex(flow, buf)); + comp = static_cast(domain_componentIndex(flow, buf.data())); sim1D_setProfile(flame, dom, comp, 4, locs.data(), 4, value.data()); } diff --git a/test/clib/test_ctreactor.cpp b/test/clib/test_ctreactor.cpp index cd84174383..bda8ba4d29 100644 --- a/test/clib/test_ctreactor.cpp +++ b/test/clib/test_ctreactor.cpp @@ -17,11 +17,10 @@ TEST(ctreactor, reactor_soln) int ret = reactor_setName(reactor, "spam"); ASSERT_EQ(ret, 0); int buflen = reactor_name(reactor, 0, 0); - char* buf = new char[buflen]; - reactor_name(reactor, buflen, buf); - string rName = buf; + vector buf(buflen); + reactor_name(reactor, buflen, buf.data()); + string rName(buf.data()); ASSERT_EQ(rName, "spam"); - delete[] buf; } vector T_ctreactor = {