From 37652e88c71937440d9850073b59673fc71757cb Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Wed, 14 Aug 2019 15:16:07 -0500 Subject: [PATCH 1/6] [Reactor] YAML summary of ReactorNet * recreate ReactorNet structure * list ReactorBase, WallBase, FlowDevice and ReactorSurface objects * create of unique names based on * implementation for Phase list is partial, Kinetics is missing * names only available for ReactorBase --- include/cantera/zeroD/FlowDevice.h | 5 +- include/cantera/zeroD/ReactorBase.h | 8 + include/cantera/zeroD/ReactorNet.h | 4 + include/cantera/zeroD/ReactorSurface.h | 3 + include/cantera/zeroD/Wall.h | 5 +- interfaces/cython/cantera/_cantera.pxd | 5 + .../cantera/examples/reactors/ic_engine.py | 10 +- interfaces/cython/cantera/reactor.pyx | 20 +++ src/zeroD/FlowDevice.cpp | 20 +++ src/zeroD/ReactorBase.cpp | 20 +++ src/zeroD/ReactorNet.cpp | 165 ++++++++++++++++++ src/zeroD/ReactorSurface.cpp | 20 +++ src/zeroD/Wall.cpp | 20 +++ 13 files changed, 298 insertions(+), 7 deletions(-) diff --git a/include/cantera/zeroD/FlowDevice.h b/include/cantera/zeroD/FlowDevice.h index 46902db7706..e10d9a1ea4b 100644 --- a/include/cantera/zeroD/FlowDevice.h +++ b/include/cantera/zeroD/FlowDevice.h @@ -54,6 +54,9 @@ class FlowDevice return m_type; } + //! Generate self-documenting YAML string. + virtual std::string toYAML() const; + //! Mass flow rate (kg/s). //! @deprecated The 'time' argument will be removed after Cantera 2.5. //! Evaluating the mass flow rate at times other than the current time @@ -101,7 +104,7 @@ class FlowDevice } //! Return a const reference to the downstream reactor. - const ReactorBase& out() const { + ReactorBase& out() const { return *m_out; } diff --git a/include/cantera/zeroD/ReactorBase.h b/include/cantera/zeroD/ReactorBase.h index 9ac35a5398e..b1af0d69c2e 100644 --- a/include/cantera/zeroD/ReactorBase.h +++ b/include/cantera/zeroD/ReactorBase.h @@ -101,6 +101,9 @@ class ReactorBase throw NotImplementedError("ReactorBase::setChemistry"); } + //! Generate self-documenting YAML string. + virtual std::string toYAML() const; + //! Set the energy equation on or off. virtual void setEnergy(int eflag = 1) { throw NotImplementedError("ReactorBase::setEnergy"); @@ -136,6 +139,11 @@ class ReactorBase return m_wall.size(); } + //! Return the number of ReactorSurface objects connected to this reactor. + size_t nSurfaces() { + return m_surfaces.size(); + } + //! Insert a Wall between this reactor and another reactor. /*! * `lr` = 0 if this reactor is to the left of the wall and `lr` = 1 if diff --git a/include/cantera/zeroD/ReactorNet.h b/include/cantera/zeroD/ReactorNet.h index af656e07311..3b48140e32f 100644 --- a/include/cantera/zeroD/ReactorNet.h +++ b/include/cantera/zeroD/ReactorNet.h @@ -31,6 +31,7 @@ class ReactorNet : public FuncEval //! @name Methods to set up a simulation. //@{ + //! Set initial time. Default = 0.0 s. Restarts integration from this time //! using the current mixture state as the initial condition. void setInitialTime(double time); @@ -102,6 +103,9 @@ class ReactorNet : public FuncEval //@} + //! Generate self-documenting YAML string. + std::string toYAML() const; + //! Add the reactor *r* to this reactor network. void addReactor(Reactor& r); diff --git a/include/cantera/zeroD/ReactorSurface.h b/include/cantera/zeroD/ReactorSurface.h index e3a4d3d2994..cabb9155e63 100644 --- a/include/cantera/zeroD/ReactorSurface.h +++ b/include/cantera/zeroD/ReactorSurface.h @@ -22,6 +22,9 @@ class ReactorSurface ReactorSurface(const ReactorSurface&) = delete; ReactorSurface& operator=(const ReactorSurface&) = delete; + //! Generate self-documenting YAML string. + virtual std::string toYAML() const; + //! Returns the surface area [m^2] double area() const; diff --git a/include/cantera/zeroD/Wall.h b/include/cantera/zeroD/Wall.h index ff7fe0a4690..41e3bdef0bd 100644 --- a/include/cantera/zeroD/Wall.h +++ b/include/cantera/zeroD/Wall.h @@ -40,6 +40,9 @@ class WallBase return "WallBase"; } + //! Generate self-documenting YAML string. + virtual std::string toYAML() const; + //! Rate of volume change (m^3/s) for the adjacent reactors. /*! * This method is called by Reactor::evalWalls(). Base class method @@ -95,7 +98,7 @@ class WallBase } //! Return a reference to the Reactor or Reservoir to the right of the wall. - const ReactorBase& right() { + ReactorBase& right() const { return *m_right; } diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 26ff56dcd3c..3607964a856 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -546,6 +546,7 @@ cdef extern from "cantera/zerodim.h" namespace "Cantera": cdef cppclass CxxReactorBase "Cantera::ReactorBase": CxxReactorBase() string typeStr() + string toYAML() void setThermoMgr(CxxThermoPhase&) except +translate_exception void restoreState() except +translate_exception void syncState() except +translate_exception @@ -582,6 +583,7 @@ cdef extern from "cantera/zerodim.h" namespace "Cantera": cdef cppclass CxxWallBase "Cantera::WallBase": CxxWallBase() string type() + string toYAML() cbool install(CxxReactorBase&, CxxReactorBase&) double area() void setArea(double) @@ -610,6 +612,7 @@ cdef extern from "cantera/zerodim.h" namespace "Cantera": cdef cppclass CxxReactorSurface "Cantera::ReactorSurface": CxxReactorSurface() + string toYAML() double area() void setArea(double) void setKinetics(CxxKinetics*) @@ -625,6 +628,7 @@ cdef extern from "cantera/zerodim.h" namespace "Cantera": CxxFlowDevice() string typeStr() double massFlowRate() except +translate_exception + string toYAML() double massFlowRate(double) except +translate_exception cbool install(CxxReactorBase&, CxxReactorBase&) except +translate_exception void setPressureFunction(CxxFunc1*) except +translate_exception @@ -652,6 +656,7 @@ cdef extern from "cantera/zerodim.h" namespace "Cantera": cdef cppclass CxxReactorNet "Cantera::ReactorNet": CxxReactorNet() void addReactor(CxxReactor&) + string toYAML() double advance(double, cbool) except +translate_exception double step() except +translate_exception void initialize() except +translate_exception diff --git a/interfaces/cython/cantera/examples/reactors/ic_engine.py b/interfaces/cython/cantera/examples/reactors/ic_engine.py index c1260cfd0ee..f65c5190351 100644 --- a/interfaces/cython/cantera/examples/reactors/ic_engine.py +++ b/interfaces/cython/cantera/examples/reactors/ic_engine.py @@ -97,12 +97,12 @@ def piston_speed(t): # define initial state and set up reactor gas.TPX = T_inlet, p_inlet, comp_inlet -cyl = ct.IdealGasReactor(gas) +cyl = ct.IdealGasReactor(gas, name='Cylinder') cyl.volume = V_oT # define inlet state gas.TPX = T_inlet, p_inlet, comp_inlet -inlet = ct.Reservoir(gas) +inlet = ct.Reservoir(gas, name='Inlet') # inlet valve inlet_valve = ct.Valve(inlet, cyl) @@ -113,7 +113,7 @@ def piston_speed(t): # define injector state (gaseous!) gas.TPX = T_injector, p_injector, comp_injector -injector = ct.Reservoir(gas) +injector = ct.Reservoir(gas, name='Fuel') # injector is modeled as a mass flow controller injector_mfc = ct.MassFlowController(injector, cyl) @@ -125,7 +125,7 @@ def piston_speed(t): # define outlet pressure (temperature and composition don't matter) gas.TPX = T_ambient, p_outlet, comp_ambient -outlet = ct.Reservoir(gas) +outlet = ct.Reservoir(gas, name='Outlet') # outlet valve outlet_valve = ct.Valve(cyl, outlet) @@ -136,7 +136,7 @@ def piston_speed(t): # define ambient pressure (temperature and composition don't matter) gas.TPX = T_ambient, p_ambient, comp_ambient -ambient_air = ct.Reservoir(gas) +ambient_air = ct.Reservoir(ct.Solution('air.cti'), name='Ambient') # piston is modeled as a moving wall piston = ct.Wall(ambient_air, cyl) diff --git a/interfaces/cython/cantera/reactor.pyx b/interfaces/cython/cantera/reactor.pyx index 2bde1067d72..d1bae5d5786 100644 --- a/interfaces/cython/cantera/reactor.pyx +++ b/interfaces/cython/cantera/reactor.pyx @@ -63,6 +63,10 @@ cdef class ReactorBase: def __set__(self, name): self.rbase.setName(stringify(name)) + def to_yaml(self): + """Return a YAML representation of the Reactor setup.""" + return pystr(self.rbase.toYAML()) + def syncState(self): """ Set the state of the Reactor to match that of the associated @@ -414,6 +418,10 @@ cdef class ReactorSurface: if A is not None: self.area = A + def to_yaml(self): + """Return a YAML representation of the ReactorSurface setup.""" + return pystr(self.surface.toYAML()) + def install(self, Reactor r): r.reactor.addSurface(self.surface) @@ -542,6 +550,10 @@ cdef class WallBase: def __get__(self): return pystr(self.wall.type()) + def to_yaml(self): + """Return a YAML representation of the WallBase setup.""" + return pystr(self.wall.toYAML()) + property left: """ The left surface of this wall. """ def __get__(self): @@ -695,6 +707,10 @@ cdef class FlowDevice: def __get__(self): return pystr(self.dev.typeStr()) + def to_yaml(self): + """Return a YAML representation of the FlowDevice setup.""" + return pystr(self.dev.toYAML()) + def _install(self, ReactorBase upstream, ReactorBase downstream): """ Install the device between the *upstream* (source) and *downstream* @@ -1045,6 +1061,10 @@ cdef class ReactorNet: self._reactors.append(r) self.net.addReactor(deref(r.reactor)) + def to_yaml(self): + """Return a YAML representation of the ReactorNet setup.""" + return pystr(self.net.toYAML()) + def advance(self, double t, pybool apply_limit=True): """ Advance the state of the reactor network in time from the current time diff --git a/src/zeroD/FlowDevice.cpp b/src/zeroD/FlowDevice.cpp index 11ed774d19e..a7ddaf2d28f 100644 --- a/src/zeroD/FlowDevice.cpp +++ b/src/zeroD/FlowDevice.cpp @@ -6,6 +6,7 @@ #include "cantera/zeroD/FlowDevice.h" #include "cantera/zeroD/ReactorBase.h" #include "cantera/numerics/Func1.h" +#include "cantera/base/yaml.h" namespace Cantera { @@ -46,6 +47,25 @@ bool FlowDevice::install(ReactorBase& in, ReactorBase& out) return true; } +std::string FlowDevice::toYAML() const +{ + YAML::Emitter yml; + std::stringstream out; + + // object is not aware of its unique identifier + yml << YAML::BeginMap; + yml << YAML::Key << "type"; + yml << YAML::Value << typeStr(); + yml << YAML::Key << "in"; + yml << YAML::Value << m_in->name(); + yml << YAML::Key << "out"; + yml << YAML::Value << m_out->name(); + yml << YAML::EndMap; + + out << yml.c_str(); + return out.str(); +} + void FlowDevice::setPressureFunction(Func1* f) { m_pfunc = f; diff --git a/src/zeroD/ReactorBase.cpp b/src/zeroD/ReactorBase.cpp index edcb7e1532c..ed9e0f334e6 100644 --- a/src/zeroD/ReactorBase.cpp +++ b/src/zeroD/ReactorBase.cpp @@ -7,6 +7,7 @@ #include "cantera/zeroD/FlowDevice.h" #include "cantera/zeroD/ReactorNet.h" #include "cantera/zeroD/ReactorSurface.h" +#include "cantera/base/yaml.h" using namespace std; namespace Cantera @@ -44,6 +45,25 @@ void ReactorBase::syncState() } } +std::string ReactorBase::toYAML() const +{ + YAML::Emitter yml; + std::stringstream out; + + yml << YAML::BeginMap; + yml << YAML::Key << name(); + yml << YAML::BeginMap; + yml << YAML::Key << "type"; + yml << YAML::Value << typeStr(); + yml << YAML::Key << "thermo"; + yml << YAML::Value << m_thermo->name(); + yml << YAML::EndMap; + yml << YAML::EndMap; + + out << yml.c_str(); + return out.str(); +} + void ReactorBase::addInlet(FlowDevice& inlet) { m_inlet.push_back(&inlet); diff --git a/src/zeroD/ReactorNet.cpp b/src/zeroD/ReactorNet.cpp index e51627c7121..2edbc1c4a2a 100644 --- a/src/zeroD/ReactorNet.cpp +++ b/src/zeroD/ReactorNet.cpp @@ -6,6 +6,7 @@ #include "cantera/zeroD/ReactorNet.h" #include "cantera/zeroD/FlowDevice.h" #include "cantera/zeroD/Wall.h" +#include "cantera/base/yaml.h" #include @@ -30,6 +31,170 @@ ReactorNet::ReactorNet() : m_integ->setProblemType(DENSE + NOJAC); } +std::string uniqueName(void const *ptr) { + // use pointer address as unique name + std::ostringstream address; + address << ptr; + return address.str(); +} + +std::string ReactorNet::toYAML() const +{ + YAML::Emitter yml; + yml.SetIndent(1); + std::string name; + std::stringstream out; + + // components: using generic pointers + std::map reactors; + std::map phases; + std::map kinetics; // <-- needed + std::map walls; + std::map devices; + std::map surfaces; + + // construct complete maps + for (auto r=m_reactors.begin(); r!=m_reactors.end(); r++) { + + // insert reactor (emplace ensures that it remains unique) + ReactorBase* rb = *r; + reactors.emplace(uniqueName((void const *)rb), rb); + + // walls + for (size_t i=0; inWalls(); i++) { + + // wall has reactor to left and right + WallBase& wall = rb->wall(i); + walls.emplace(uniqueName((void const *)(&wall)), &wall); + + ReactorBase& rl = wall.left(); + reactors.emplace(uniqueName((void const *)(&rl)), &rl); + + ReactorBase& rr = wall.right(); + reactors.emplace(uniqueName((void const *)(&rr)), &rr); + } + + // inlets + for (size_t i=0; inInlets(); i++) { + + // flow devices at inlet have inlets + FlowDevice& inlet = rb->inlet(i); + devices.emplace(uniqueName((void const *)(&inlet)), &inlet); + + ReactorBase& in = inlet.in(); + reactors.emplace(uniqueName((void const *)(&in)), &in); + } + + // outlets + for (size_t i=0; inOutlets(); i++) { + + // flow devices at outlet have outlets + FlowDevice& outlet = rb->outlet(i); + devices.emplace(uniqueName((void const *)(&outlet)), &outlet); + + ReactorBase& out = outlet.out(); + reactors.emplace(uniqueName((void const *)(&out)), &out); + } + + // surfaces + for (size_t i=0; inSurfaces(); i++) { + + ReactorSurface* surface = rb->surface(i); + surfaces.emplace(uniqueName((void const *)surface), surface); + + // missing: surface phase & kinetics + } + } + + // gas phases + for (const auto& r : reactors) { + + // missing: kinetics + thermo_t& contents = r.second->contents(); + phases.emplace(uniqueName((void const *)(&contents)), &contents); + } + + // // surface phases + // for (const auto& s : surfaces) { + + // missing: kinetics + // SurfPhase* thermo = s.second->thermo(); + // phases.emplace(uniqueName((void const *)thermo), thermo); + // } + + // header + yml << YAML::BeginMap; + yml << YAML::Key << "ReactorNet"; + yml << YAML::BeginMap; + + // emit list of thermo phases + yml << YAML::Key << "t_thermo"; + yml << YAML::Value << YAML::BeginSeq; + for (const auto& p : phases) { + yml << YAML::BeginMap; + yml << YAML::Key << p.first; + yml << YAML::BeginMap; + yml << YAML::Key << "type"; + yml << YAML::Value << p.second->type(); + yml << YAML::EndMap; + yml << YAML::EndMap; + } + yml << YAML::EndSeq; + + // emit list of reactors + yml << YAML::Key << "ReactorBase"; + yml << YAML::Value << YAML::BeginSeq; + for (const auto& r : reactors) { + yml << YAML::Load(r.second->toYAML()); + } + yml << YAML::EndSeq; + + // emit list of walls + if (walls.size()) { + yml << YAML::Key << "WallBase"; + yml << YAML::Value << YAML::BeginSeq; + for (const auto& w : walls) { + yml << YAML::BeginMap; + yml << YAML::Key << w.first; + yml << YAML::Load(w.second->toYAML()); + yml << YAML::EndMap; + } + yml << YAML::EndSeq; + } + + // emit list of flow devices + if (devices.size()) { + yml << YAML::Key << "FlowDevice"; + yml << YAML::Value << YAML::BeginSeq; + for (const auto& d : devices) { + yml << YAML::BeginMap; + yml << YAML::Key << d.first; + yml << YAML::Load(d.second->toYAML()); + yml << YAML::EndMap; + } + yml << YAML::EndSeq; + } + + // emit list of reactor surfaces + if (surfaces.size()) { + yml << YAML::Key << "ReactorSurface"; + yml << YAML::Value << YAML::BeginSeq; + for (const auto& s : surfaces) { + yml << YAML::BeginMap; + yml << YAML::Key << s.first; + yml << YAML::Load(s.second->toYAML()); + yml << YAML::EndMap; + } + yml << YAML::EndSeq; + } + + // close out + yml << YAML::EndMap; + yml << YAML::EndMap; + out << yml.c_str(); + return out.str(); +} + void ReactorNet::setInitialTime(double time) { m_time = time; diff --git a/src/zeroD/ReactorSurface.cpp b/src/zeroD/ReactorSurface.cpp index 88a446ecaf7..9e1f2ebbef7 100644 --- a/src/zeroD/ReactorSurface.cpp +++ b/src/zeroD/ReactorSurface.cpp @@ -7,6 +7,7 @@ #include "cantera/zeroD/ReactorNet.h" #include "cantera/thermo/SurfPhase.h" #include "cantera/kinetics/Kinetics.h" +#include "cantera/base/yaml.h" namespace Cantera { @@ -19,6 +20,25 @@ ReactorSurface::ReactorSurface() { } +std::string ReactorSurface::toYAML() const +{ + YAML::Emitter yml; + std::stringstream out; + + // yml << YAML::BeginMap; + // yml << YAML::Key << name(); + yml << YAML::BeginMap; + // yml << YAML::Key << "type"; + // yml << YAML::Value << typeStr(); + yml << YAML::Key << "thermo"; + yml << YAML::Value << m_thermo->name(); + yml << YAML::EndMap; + //yml << YAML::EndMap; + + out << yml.c_str(); + return out.str(); +} + double ReactorSurface::area() const { return m_area; diff --git a/src/zeroD/Wall.cpp b/src/zeroD/Wall.cpp index 6132186cd84..27aed12578d 100644 --- a/src/zeroD/Wall.cpp +++ b/src/zeroD/Wall.cpp @@ -7,6 +7,7 @@ #include "cantera/numerics/Func1.h" #include "cantera/zeroD/Wall.h" #include "cantera/thermo/SurfPhase.h" +#include "cantera/base/yaml.h" namespace Cantera { @@ -28,6 +29,25 @@ bool WallBase::install(ReactorBase& rleft, ReactorBase& rright) return true; } +std::string WallBase::toYAML() const +{ + YAML::Emitter yml; + std::stringstream out; + + // object is not aware of its unique identifier + yml << YAML::BeginMap; + yml << YAML::Key << "type"; + yml << YAML::Value << type(); + yml << YAML::Key << "left"; + yml << YAML::Value << m_left->name(); + yml << YAML::Key << "right"; + yml << YAML::Value << m_right->name(); + yml << YAML::EndMap; + + out << yml.c_str(); + return out.str(); +} + void WallBase::setArea(double a) { m_area = a; m_surf[0].setArea(a); From a75bb769385c62c5b58e0109753be18147a0a64e Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Thu, 15 Aug 2019 00:21:21 -0500 Subject: [PATCH 2/6] [Reactor] streamline/update naming of zeroD objects * pass name attributes from Cython to C++ layer for FlowDevice and WallBase objects * create name and type attributes for ReactorSurface objects --- include/cantera/zeroD/FlowDevice.h | 14 +++++- include/cantera/zeroD/Reactor.h | 3 -- include/cantera/zeroD/ReactorBase.h | 4 ++ include/cantera/zeroD/ReactorSurface.h | 20 +++++++- include/cantera/zeroD/Wall.h | 14 +++++- interfaces/cython/cantera/_cantera.pxd | 11 +++-- .../cantera/examples/reactors/ic_engine.py | 8 ++-- interfaces/cython/cantera/reactor.pyx | 46 ++++++++++++++++-- src/zeroD/FlowDevice.cpp | 26 +++++----- src/zeroD/Reactor.cpp | 1 - src/zeroD/ReactorBase.cpp | 16 +++++-- src/zeroD/ReactorNet.cpp | 47 +------------------ src/zeroD/ReactorSurface.cpp | 26 +++++----- src/zeroD/Wall.cpp | 19 ++++---- 14 files changed, 157 insertions(+), 98 deletions(-) diff --git a/include/cantera/zeroD/FlowDevice.h b/include/cantera/zeroD/FlowDevice.h index e10d9a1ea4b..ff9e7e3d9c7 100644 --- a/include/cantera/zeroD/FlowDevice.h +++ b/include/cantera/zeroD/FlowDevice.h @@ -30,7 +30,7 @@ const int Valve_Type = 3; class FlowDevice { public: - FlowDevice(); + FlowDevice(const std::string& name = "(none)"); virtual ~FlowDevice() {} FlowDevice(const FlowDevice&) = delete; @@ -54,6 +54,16 @@ class FlowDevice return m_type; } + //! Return the name of this flow device + std::string name() const { + return m_name; + } + + //! Set the name of this flow device + void setName(const std::string& name) { + m_name = name; + } + //! Generate self-documenting YAML string. virtual std::string toYAML() const; @@ -169,6 +179,8 @@ class FlowDevice int m_type; //!< @deprecated To be removed after Cantera 2.5. + std::string m_name; //! flow device name + private: size_t m_nspin, m_nspout; ReactorBase* m_in; diff --git a/include/cantera/zeroD/Reactor.h b/include/cantera/zeroD/Reactor.h index 41528862b28..93c75c5f0f0 100644 --- a/include/cantera/zeroD/Reactor.h +++ b/include/cantera/zeroD/Reactor.h @@ -205,9 +205,6 @@ class Reactor : public ReactorBase //! Get initial conditions for SurfPhase objects attached to this reactor virtual void getSurfaceInitialConditions(double* y); - //! Pointer to the homogeneous Kinetics object that handles the reactions - Kinetics* m_kin; - doublereal m_vdot; //!< net rate of volume change from moving walls [m^3/s] doublereal m_Q; //!< net heat transfer through walls [W] doublereal m_mass; //!< total mass diff --git a/include/cantera/zeroD/ReactorBase.h b/include/cantera/zeroD/ReactorBase.h index b1af0d69c2e..885c734326b 100644 --- a/include/cantera/zeroD/ReactorBase.h +++ b/include/cantera/zeroD/ReactorBase.h @@ -270,6 +270,10 @@ class ReactorBase size_t m_nsp; thermo_t* m_thermo; + + //! Pointer to the homogeneous Kinetics object that handles the reactions + Kinetics* m_kin; + doublereal m_vol; doublereal m_enthalpy; doublereal m_intEnergy; diff --git a/include/cantera/zeroD/ReactorSurface.h b/include/cantera/zeroD/ReactorSurface.h index cabb9155e63..b3b903817ad 100644 --- a/include/cantera/zeroD/ReactorSurface.h +++ b/include/cantera/zeroD/ReactorSurface.h @@ -17,11 +17,27 @@ class SurfPhase; class ReactorSurface { public: - ReactorSurface(); + ReactorSurface(const std::string& name = "(none)"); virtual ~ReactorSurface() {} ReactorSurface(const ReactorSurface&) = delete; ReactorSurface& operator=(const ReactorSurface&) = delete; + //! String indicating the wall model implemented. Usually + //! corresponds to the name of the derived class. + virtual std::string type() const { + return "ReactorSurface"; + } + + //! Return the name of this surface + std::string name() const { + return m_name; + } + + //! Set the name of this surface + void setName(const std::string& name) { + m_name = name; + } + //! Generate self-documenting YAML string. virtual std::string toYAML() const; @@ -93,6 +109,8 @@ class ReactorSurface ReactorBase* m_reactor; vector_fp m_cov; std::vector m_params; + + std::string m_name; //! reactor surface name }; } diff --git a/include/cantera/zeroD/Wall.h b/include/cantera/zeroD/Wall.h index 41e3bdef0bd..2be60b12d8f 100644 --- a/include/cantera/zeroD/Wall.h +++ b/include/cantera/zeroD/Wall.h @@ -28,7 +28,7 @@ const int WallType = 1; class WallBase { public: - WallBase(); + WallBase(const std::string& name = "(none)"); virtual ~WallBase() {} WallBase(const WallBase&) = delete; @@ -40,6 +40,16 @@ class WallBase return "WallBase"; } + //! Return the name of this wall + std::string name() const { + return m_name; + } + + //! Set the name of this wall + void setName(const std::string& name) { + m_name = name; + } + //! Generate self-documenting YAML string. virtual std::string toYAML() const; @@ -109,6 +119,8 @@ class WallBase std::vector m_surf; double m_area; + + std::string m_name; //! wall name }; //! Represents a wall between between two ReactorBase objects. diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 3607964a856..1eefa9d9a3a 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -583,6 +583,8 @@ cdef extern from "cantera/zerodim.h" namespace "Cantera": cdef cppclass CxxWallBase "Cantera::WallBase": CxxWallBase() string type() + string name() + void setName(string) string toYAML() cbool install(CxxReactorBase&, CxxReactorBase&) double area() @@ -612,6 +614,9 @@ cdef extern from "cantera/zerodim.h" namespace "Cantera": cdef cppclass CxxReactorSurface "Cantera::ReactorSurface": CxxReactorSurface() + string type() + string name() + void setName(string) string toYAML() double area() void setArea(double) @@ -627,8 +632,10 @@ cdef extern from "cantera/zerodim.h" namespace "Cantera": cdef cppclass CxxFlowDevice "Cantera::FlowDevice": CxxFlowDevice() string typeStr() - double massFlowRate() except +translate_exception + string name() + void setName(string) string toYAML() + double massFlowRate() except +translate_exception double massFlowRate(double) except +translate_exception cbool install(CxxReactorBase&, CxxReactorBase&) except +translate_exception void setPressureFunction(CxxFunc1*) except +translate_exception @@ -1093,7 +1100,6 @@ cdef class WallBase: cdef object _heat_flux_func cdef ReactorBase _left_reactor cdef ReactorBase _right_reactor - cdef str name cdef class Wall(WallBase): pass @@ -1102,7 +1108,6 @@ cdef class FlowDevice: cdef CxxFlowDevice* dev cdef Func1 _rate_func cdef Func1 _time_func - cdef str name cdef ReactorBase _upstream cdef ReactorBase _downstream diff --git a/interfaces/cython/cantera/examples/reactors/ic_engine.py b/interfaces/cython/cantera/examples/reactors/ic_engine.py index f65c5190351..f02d19b4312 100644 --- a/interfaces/cython/cantera/examples/reactors/ic_engine.py +++ b/interfaces/cython/cantera/examples/reactors/ic_engine.py @@ -105,7 +105,7 @@ def piston_speed(t): inlet = ct.Reservoir(gas, name='Inlet') # inlet valve -inlet_valve = ct.Valve(inlet, cyl) +inlet_valve = ct.Valve(inlet, cyl, name='InletValve') inlet_delta = np.mod(inlet_close - inlet_open, 4 * np.pi) inlet_valve.valve_coeff = inlet_valve_coeff inlet_valve.set_time_function( @@ -116,7 +116,7 @@ def piston_speed(t): injector = ct.Reservoir(gas, name='Fuel') # injector is modeled as a mass flow controller -injector_mfc = ct.MassFlowController(injector, cyl) +injector_mfc = ct.MassFlowController(injector, cyl, name='Injector') injector_delta = np.mod(injector_close - injector_open, 4 * np.pi) injector_t_open = (injector_close - injector_open) / 2. / np.pi / f injector_mfc.mass_flow_coeff = injector_mass / injector_t_open @@ -128,7 +128,7 @@ def piston_speed(t): outlet = ct.Reservoir(gas, name='Outlet') # outlet valve -outlet_valve = ct.Valve(cyl, outlet) +outlet_valve = ct.Valve(cyl, outlet, name='OutletValve') outlet_delta = np.mod(outlet_close - outlet_open, 4 * np.pi) outlet_valve.valve_coeff = outlet_valve_coeff outlet_valve.set_time_function( @@ -139,7 +139,7 @@ def piston_speed(t): ambient_air = ct.Reservoir(ct.Solution('air.cti'), name='Ambient') # piston is modeled as a moving wall -piston = ct.Wall(ambient_air, cyl) +piston = ct.Wall(ambient_air, cyl, name='Piston') piston.area = A_piston piston.set_velocity(piston_speed) diff --git a/interfaces/cython/cantera/reactor.pyx b/interfaces/cython/cantera/reactor.pyx index d1bae5d5786..6695ee5bec8 100644 --- a/interfaces/cython/cantera/reactor.pyx +++ b/interfaces/cython/cantera/reactor.pyx @@ -410,7 +410,8 @@ cdef class ReactorSurface: def __dealloc__(self): del self.surface - def __init__(self, kin=None, Reactor r=None, *, A=None): + def __init__(self, kin=None, Reactor r=None, *, name=None, A=None): + if kin is not None: self.kinetics = kin if r is not None: @@ -418,6 +419,26 @@ cdef class ReactorSurface: if A is not None: self.area = A + 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) + + property type: + """The type of the reactor.""" + def __get__(self): + return pystr(self.surface.type()) + + property name: + """The name of the reactor.""" + def __get__(self): + return pystr(self.surface.name()) + + def __set__(self, name): + self.surface.setName(stringify(name)) + def to_yaml(self): """Return a YAML representation of the ReactorSurface setup.""" return pystr(self.surface.toYAML()) @@ -515,12 +536,13 @@ 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) + _reactor_counts[self.__class__.__name__] += 1 + n = _reactor_counts[self.__class__.__name__] + self.name = '{0}_{1}'.format(self.__class__.__name__, n) if A is not None: self.area = A @@ -550,6 +572,14 @@ cdef class WallBase: def __get__(self): return pystr(self.wall.type()) + property name: + """The name of the reactor.""" + def __get__(self): + return pystr(self.wall.name()) + + def __set__(self, name): + self.wall.setName(stringify(name)) + def to_yaml(self): """Return a YAML representation of the WallBase setup.""" return pystr(self.wall.toYAML()) @@ -707,6 +737,14 @@ cdef class FlowDevice: def __get__(self): return pystr(self.dev.typeStr()) + property name: + """The name of the reactor.""" + def __get__(self): + return pystr(self.dev.name()) + + def __set__(self, name): + self.dev.setName(stringify(name)) + def to_yaml(self): """Return a YAML representation of the FlowDevice setup.""" return pystr(self.dev.toYAML()) diff --git a/src/zeroD/FlowDevice.cpp b/src/zeroD/FlowDevice.cpp index a7ddaf2d28f..83ee3b18d99 100644 --- a/src/zeroD/FlowDevice.cpp +++ b/src/zeroD/FlowDevice.cpp @@ -11,10 +11,15 @@ namespace Cantera { -FlowDevice::FlowDevice() : m_mdot(Undef), m_pfunc(0), m_tfunc(0), - m_coeff(1.0), m_type(0), - m_nspin(0), m_nspout(0), - m_in(0), m_out(0) {} +FlowDevice::FlowDevice(const std::string& name) : + m_mdot(Undef), + m_pfunc(0), m_tfunc(0), + m_coeff(1.0), m_type(0), + m_nspin(0), m_nspout(0), + m_in(0), m_out(0) +{ + m_name = name; +} bool FlowDevice::install(ReactorBase& in, ReactorBase& out) { @@ -52,14 +57,13 @@ std::string FlowDevice::toYAML() const YAML::Emitter yml; std::stringstream out; - // object is not aware of its unique identifier yml << YAML::BeginMap; - yml << YAML::Key << "type"; - yml << YAML::Value << typeStr(); - yml << YAML::Key << "in"; - yml << YAML::Value << m_in->name(); - yml << YAML::Key << "out"; - yml << YAML::Value << m_out->name(); + yml << YAML::Key << name(); + yml << YAML::BeginMap; + yml << YAML::Key << "type" << YAML::Value << typeStr(); + yml << YAML::Key << "in" << YAML::Value << m_in->name(); + yml << YAML::Key << "out" << YAML::Value << m_out->name(); + yml << YAML::EndMap; yml << YAML::EndMap; out << yml.c_str(); diff --git a/src/zeroD/Reactor.cpp b/src/zeroD/Reactor.cpp index da3f985312b..36af26216ff 100644 --- a/src/zeroD/Reactor.cpp +++ b/src/zeroD/Reactor.cpp @@ -18,7 +18,6 @@ namespace bmt = boost::math::tools; namespace Cantera { Reactor::Reactor() : - m_kin(0), m_vdot(0.0), m_Q(0.0), m_mass(0.0), diff --git a/src/zeroD/ReactorBase.cpp b/src/zeroD/ReactorBase.cpp index ed9e0f334e6..815830a837a 100644 --- a/src/zeroD/ReactorBase.cpp +++ b/src/zeroD/ReactorBase.cpp @@ -13,8 +13,10 @@ using namespace std; namespace Cantera { -ReactorBase::ReactorBase(const string& name) : m_nsp(0), +ReactorBase::ReactorBase(const string& name) : + m_nsp(0), m_thermo(0), + m_kin(0), m_vol(1.0), m_enthalpy(0.0), m_intEnergy(0.0), @@ -55,8 +57,16 @@ std::string ReactorBase::toYAML() const yml << YAML::BeginMap; yml << YAML::Key << "type"; yml << YAML::Value << typeStr(); - yml << YAML::Key << "thermo"; - yml << YAML::Value << m_thermo->name(); + if (m_thermo) { + yml << YAML::Key << "phase"; + yml << YAML::Value << m_thermo->name(); + yml << YAML::Key << "thermo.type"; + yml << YAML::Value << m_thermo->type(); + } + if (m_kin) { + yml << YAML::Key << "kinetics.type"; + yml << YAML::Value << m_kin->kineticsType(); + } yml << YAML::EndMap; yml << YAML::EndMap; diff --git a/src/zeroD/ReactorNet.cpp b/src/zeroD/ReactorNet.cpp index 2edbc1c4a2a..8a40f06503f 100644 --- a/src/zeroD/ReactorNet.cpp +++ b/src/zeroD/ReactorNet.cpp @@ -41,14 +41,10 @@ std::string uniqueName(void const *ptr) { std::string ReactorNet::toYAML() const { YAML::Emitter yml; - yml.SetIndent(1); - std::string name; std::stringstream out; - // components: using generic pointers + // components: maps use generic pointers std::map reactors; - std::map phases; - std::map kinetics; // <-- needed std::map walls; std::map devices; std::map surfaces; @@ -101,46 +97,14 @@ std::string ReactorNet::toYAML() const ReactorSurface* surface = rb->surface(i); surfaces.emplace(uniqueName((void const *)surface), surface); - - // missing: surface phase & kinetics } } - // gas phases - for (const auto& r : reactors) { - - // missing: kinetics - thermo_t& contents = r.second->contents(); - phases.emplace(uniqueName((void const *)(&contents)), &contents); - } - - // // surface phases - // for (const auto& s : surfaces) { - - // missing: kinetics - // SurfPhase* thermo = s.second->thermo(); - // phases.emplace(uniqueName((void const *)thermo), thermo); - // } - // header yml << YAML::BeginMap; yml << YAML::Key << "ReactorNet"; yml << YAML::BeginMap; - // emit list of thermo phases - yml << YAML::Key << "t_thermo"; - yml << YAML::Value << YAML::BeginSeq; - for (const auto& p : phases) { - yml << YAML::BeginMap; - yml << YAML::Key << p.first; - yml << YAML::BeginMap; - yml << YAML::Key << "type"; - yml << YAML::Value << p.second->type(); - yml << YAML::EndMap; - yml << YAML::EndMap; - } - yml << YAML::EndSeq; - // emit list of reactors yml << YAML::Key << "ReactorBase"; yml << YAML::Value << YAML::BeginSeq; @@ -154,10 +118,7 @@ std::string ReactorNet::toYAML() const yml << YAML::Key << "WallBase"; yml << YAML::Value << YAML::BeginSeq; for (const auto& w : walls) { - yml << YAML::BeginMap; - yml << YAML::Key << w.first; yml << YAML::Load(w.second->toYAML()); - yml << YAML::EndMap; } yml << YAML::EndSeq; } @@ -167,10 +128,7 @@ std::string ReactorNet::toYAML() const yml << YAML::Key << "FlowDevice"; yml << YAML::Value << YAML::BeginSeq; for (const auto& d : devices) { - yml << YAML::BeginMap; - yml << YAML::Key << d.first; yml << YAML::Load(d.second->toYAML()); - yml << YAML::EndMap; } yml << YAML::EndSeq; } @@ -180,10 +138,7 @@ std::string ReactorNet::toYAML() const yml << YAML::Key << "ReactorSurface"; yml << YAML::Value << YAML::BeginSeq; for (const auto& s : surfaces) { - yml << YAML::BeginMap; - yml << YAML::Key << s.first; yml << YAML::Load(s.second->toYAML()); - yml << YAML::EndMap; } yml << YAML::EndSeq; } diff --git a/src/zeroD/ReactorSurface.cpp b/src/zeroD/ReactorSurface.cpp index 9e1f2ebbef7..5122d30886c 100644 --- a/src/zeroD/ReactorSurface.cpp +++ b/src/zeroD/ReactorSurface.cpp @@ -12,12 +12,13 @@ namespace Cantera { -ReactorSurface::ReactorSurface() - : m_area(1.0) - , m_thermo(nullptr) - , m_kinetics(nullptr) - , m_reactor(nullptr) +ReactorSurface::ReactorSurface(const std::string& name) : + m_area(1.0), + m_thermo(nullptr), + m_kinetics(nullptr), + m_reactor(nullptr) { + m_name = name; } std::string ReactorSurface::toYAML() const @@ -25,15 +26,16 @@ std::string ReactorSurface::toYAML() const YAML::Emitter yml; std::stringstream out; - // yml << YAML::BeginMap; - // yml << YAML::Key << name(); yml << YAML::BeginMap; - // yml << YAML::Key << "type"; - // yml << YAML::Value << typeStr(); - yml << YAML::Key << "thermo"; - yml << YAML::Value << m_thermo->name(); + yml << YAML::Key << name(); + yml << YAML::BeginMap; + yml << YAML::Key << "type" << YAML::Value << type(); + yml << YAML::Key << "reactor" << YAML::Value << m_reactor->name(); + yml << YAML::Key << "phase" << YAML::Value << m_thermo->name(); + yml << YAML::Key << "thermo.type" << YAML::Value << m_thermo->type(); + yml << YAML::Key << "kinetics.type" << YAML::Value << m_kinetics->kineticsType(); + yml << YAML::EndMap; yml << YAML::EndMap; - //yml << YAML::EndMap; out << yml.c_str(); return out.str(); diff --git a/src/zeroD/Wall.cpp b/src/zeroD/Wall.cpp index 27aed12578d..9aa5bd8fb8b 100644 --- a/src/zeroD/Wall.cpp +++ b/src/zeroD/Wall.cpp @@ -12,7 +12,11 @@ namespace Cantera { -WallBase::WallBase() : m_left(0), m_right(0), m_surf(2), m_area(1.0) {} +WallBase::WallBase(const std::string& name) : + m_left(0), m_right(0), m_surf(2), m_area(1.0) +{ + m_name = name; +} bool WallBase::install(ReactorBase& rleft, ReactorBase& rright) { @@ -34,14 +38,13 @@ std::string WallBase::toYAML() const YAML::Emitter yml; std::stringstream out; - // object is not aware of its unique identifier yml << YAML::BeginMap; - yml << YAML::Key << "type"; - yml << YAML::Value << type(); - yml << YAML::Key << "left"; - yml << YAML::Value << m_left->name(); - yml << YAML::Key << "right"; - yml << YAML::Value << m_right->name(); + yml << YAML::Key << name(); + yml << YAML::BeginMap; + yml << YAML::Key << "type" << YAML::Value << type(); + yml << YAML::Key << "left" << YAML::Value << m_left->name(); + yml << YAML::Key << "right" << YAML::Value << m_right->name(); + yml << YAML::EndMap; yml << YAML::EndMap; out << yml.c_str(); From 74053a925be657b3e1d082333de305e568090fe6 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Thu, 15 Aug 2019 10:41:47 -0500 Subject: [PATCH 3/6] [Reactor] finalize and add unit tests --- include/cantera/zeroD/ReactorNet.h | 1 - interfaces/cython/cantera/_cantera.pxd | 2 +- interfaces/cython/cantera/reactor.pyx | 52 ++++++++++--------- .../cython/cantera/test/test_reactor.py | 38 ++++++++++++++ src/zeroD/ReactorNet.cpp | 24 +++++++++ 5 files changed, 90 insertions(+), 27 deletions(-) diff --git a/include/cantera/zeroD/ReactorNet.h b/include/cantera/zeroD/ReactorNet.h index 3b48140e32f..739357a9452 100644 --- a/include/cantera/zeroD/ReactorNet.h +++ b/include/cantera/zeroD/ReactorNet.h @@ -31,7 +31,6 @@ class ReactorNet : public FuncEval //! @name Methods to set up a simulation. //@{ - //! Set initial time. Default = 0.0 s. Restarts integration from this time //! using the current mixture state as the initial condition. void setInitialTime(double time); diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 1eefa9d9a3a..439101e1045 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -663,7 +663,7 @@ cdef extern from "cantera/zerodim.h" namespace "Cantera": cdef cppclass CxxReactorNet "Cantera::ReactorNet": CxxReactorNet() void addReactor(CxxReactor&) - string toYAML() + string toYAML() except +translate_exception double advance(double, cbool) except +translate_exception double step() except +translate_exception void initialize() except +translate_exception diff --git a/interfaces/cython/cantera/reactor.pyx b/interfaces/cython/cantera/reactor.pyx index 6695ee5bec8..80a36949080 100644 --- a/interfaces/cython/cantera/reactor.pyx +++ b/interfaces/cython/cantera/reactor.pyx @@ -7,6 +7,18 @@ import numbers as _numbers _reactor_counts = _defaultdict(int) + +def _unique_name(name, class_type): + """Generate a unique name.""" + + if name is not None: + return name + else: + _reactor_counts[class_type] += 1 + n = _reactor_counts[class_type] + return '{0}_{1}'.format(class_type, n) + + # Need a pure-python class to store weakrefs to class _WeakrefProxy: pass @@ -28,12 +40,7 @@ cdef class ReactorBase: if isinstance(contents, ThermoPhase): self.insert(contents) - if name is not None: - self.name = name - else: - _reactor_counts[self.reactor_type] += 1 - n = _reactor_counts[self.reactor_type] - self.name = '{0}_{1}'.format(self.reactor_type, n) + self.name = _unique_name(name, self.type) if volume is not None: self.volume = volume @@ -419,12 +426,7 @@ cdef class ReactorSurface: if A is not None: self.area = A - 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.name = _unique_name(name, self.type) property type: """The type of the reactor.""" @@ -537,12 +539,7 @@ cdef class WallBase: self._install(left, right) - 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.name = _unique_name(name, self.type) if A is not None: self.area = A @@ -720,12 +717,7 @@ cdef class FlowDevice: 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.name = _unique_name(name, self.type) self._install(upstream, downstream) @@ -1100,9 +1092,19 @@ cdef class ReactorNet: self.net.addReactor(deref(r.reactor)) def to_yaml(self): - """Return a YAML representation of the ReactorNet setup.""" + """ + Return a YAML representation of the ReactorNet structure. To + print the structure to the terminal, simply call the ReactorNet object. + The following two statements are equivalent for the sim object:: + + >>> sim() + >>> print(sim.to_yaml()) + """ return pystr(self.net.toYAML()) + def __call__(self): + print(self.to_yaml()) + def advance(self, double t, pybool apply_limit=True): """ Advance the state of the reactor network in time from the current time diff --git a/interfaces/cython/cantera/test/test_reactor.py b/interfaces/cython/cantera/test/test_reactor.py index 7747c1ddab9..06dd072e575 100644 --- a/interfaces/cython/cantera/test/test_reactor.py +++ b/interfaces/cython/cantera/test/test_reactor.py @@ -5,6 +5,7 @@ import numpy as np from .utilities import unittest +from ruamel.yaml import YAML import cantera as ct from . import utilities @@ -396,6 +397,43 @@ def v(t): self.assertNear(self.r1.volume, V1 + 1.0 * A, 1e-7) self.assertNear(self.r2.volume, V2 - 1.0 * A, 1e-7) + def test_yaml(self, **kwargs): + self.make_reactors() + self.add_wall() + reservoir = ct.Reservoir(self.gas1) + mfc = ct.MassFlowController(reservoir, self.r1) + + self.assertTrue(isinstance(self.net.to_yaml(), str)) + self.assertTrue(isinstance(self.r1.to_yaml(), str)) + self.assertTrue(isinstance(self.r2.to_yaml(), str)) + self.assertTrue(isinstance(self.w.to_yaml(), str)) + self.assertTrue(isinstance(reservoir.to_yaml(), str)) + self.assertTrue(isinstance(mfc.to_yaml(), str)) + + yaml = YAML() + yml = yaml.load(self.net.to_yaml()) + self.assertTrue('ReactorNet' in yml) + net = yml['ReactorNet'] + + self.assertTrue('ReactorBase' in net) + reactors = [tuple(n)[0] for n in net['ReactorBase']] + self.assertTrue(self.r1.name in reactors) + self.assertTrue(self.r2.name in reactors) + self.assertTrue(reservoir.name in reactors) + + self.assertTrue('WallBase' in net) + walls = [tuple(n)[0] for n in net['WallBase']] + self.assertTrue(self.w.name in walls) + + self.assertTrue('FlowDevice' in net) + devices = [tuple(n)[0] for n in net['FlowDevice']] + self.assertTrue(mfc.name in devices) + + self.r2.name = self.r1.name + with self.assertRaisesRegex(ct.CanteraError, 'names are not unique'): + # reactor names need to be unique + self.net.to_yaml() + def test_disable_energy(self): self.make_reactors(T1=500) self.r1.energy_enabled = False diff --git a/src/zeroD/ReactorNet.cpp b/src/zeroD/ReactorNet.cpp index 8a40f06503f..039b9c1f583 100644 --- a/src/zeroD/ReactorNet.cpp +++ b/src/zeroD/ReactorNet.cpp @@ -42,6 +42,7 @@ std::string ReactorNet::toYAML() const { YAML::Emitter yml; std::stringstream out; + std::map names; // components: maps use generic pointers std::map reactors; @@ -109,39 +110,62 @@ std::string ReactorNet::toYAML() const yml << YAML::Key << "ReactorBase"; yml << YAML::Value << YAML::BeginSeq; for (const auto& r : reactors) { + names.emplace(r.second->name(), r.first); yml << YAML::Load(r.second->toYAML()); } yml << YAML::EndSeq; + if (names.size()!=reactors.size()) { + // this should raise a warning, but an applicable warning system is not in place + throw CanteraError("ReactorNet::toYAML", "ReactorBase names are not unique."); + } // emit list of walls + names.clear(); if (walls.size()) { yml << YAML::Key << "WallBase"; yml << YAML::Value << YAML::BeginSeq; for (const auto& w : walls) { + names.emplace(w.second->name(), w.first); yml << YAML::Load(w.second->toYAML()); } yml << YAML::EndSeq; } + if (names.size()!=walls.size()) { + // this should raise a warning, but an applicable warning system is not in place + throw CanteraError("ReactorNet::toYAML", "Wall names are not unique."); + } // emit list of flow devices + names.clear(); if (devices.size()) { yml << YAML::Key << "FlowDevice"; yml << YAML::Value << YAML::BeginSeq; for (const auto& d : devices) { + names.emplace(d.second->name(), d.first); yml << YAML::Load(d.second->toYAML()); } yml << YAML::EndSeq; } + if (names.size()!=devices.size()) { + // this should raise a warning, but an applicable warning system is not in place + throw CanteraError("ReactorNet::toYAML", "FlowDevice names are not unique."); + } // emit list of reactor surfaces + names.clear(); if (surfaces.size()) { yml << YAML::Key << "ReactorSurface"; yml << YAML::Value << YAML::BeginSeq; for (const auto& s : surfaces) { + names.emplace(s.second->name(), s.first); yml << YAML::Load(s.second->toYAML()); } yml << YAML::EndSeq; } + if (names.size()!=surfaces.size()) { + // this should raise a warning, but an applicable warning system is not in place + throw CanteraError("ReactorNet::toYAML", "ReactorSurface names are not unique."); + } // close out yml << YAML::EndMap; From 9d54e9a196d0d904be88ef1335faf49e142ac7af Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Thu, 15 Aug 2019 12:27:59 -0500 Subject: [PATCH 4/6] Fix ruamel_yaml for Travis CI on osx --- interfaces/cython/cantera/test/test_reactor.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interfaces/cython/cantera/test/test_reactor.py b/interfaces/cython/cantera/test/test_reactor.py index 06dd072e575..ffbf040c368 100644 --- a/interfaces/cython/cantera/test/test_reactor.py +++ b/interfaces/cython/cantera/test/test_reactor.py @@ -5,7 +5,10 @@ import numpy as np from .utilities import unittest -from ruamel.yaml import YAML +try: + from ruamel.yaml import YAML +except: + from ruamel_yaml import YAML import cantera as ct from . import utilities From 34a5f9fa8c28afb56d5e5d328f4c6d2a5435cf82 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Thu, 15 Aug 2019 17:38:57 -0500 Subject: [PATCH 5/6] Replace thermo_t by ThermoPhase in ReactorBase --- include/cantera/zeroD/ReactorBase.h | 8 ++++---- src/zeroD/ReactorBase.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/cantera/zeroD/ReactorBase.h b/include/cantera/zeroD/ReactorBase.h index 885c734326b..b80d29bf59b 100644 --- a/include/cantera/zeroD/ReactorBase.h +++ b/include/cantera/zeroD/ReactorBase.h @@ -89,7 +89,7 @@ class ReactorBase //! Specify the mixture contained in the reactor. Note that a pointer to //! this substance is stored, and as the integration proceeds, the state of //! the substance is modified. - virtual void setThermoMgr(thermo_t& thermo); + virtual void setThermoMgr(ThermoPhase& thermo); //! Specify chemical kinetics governing the reactor. virtual void setKineticsMgr(Kinetics& kin) { @@ -185,7 +185,7 @@ class ReactorBase virtual void syncState(); //! return a reference to the contents. - thermo_t& contents() { + ThermoPhase& contents() { if (!m_thermo) { throw CanteraError("ReactorBase::contents", "Reactor contents not defined."); @@ -193,7 +193,7 @@ class ReactorBase return *m_thermo; } - const thermo_t& contents() const { + const ThermoPhase& contents() const { if (!m_thermo) { throw CanteraError("ReactorBase::contents", "Reactor contents not defined."); @@ -269,7 +269,7 @@ class ReactorBase //! Number of homogeneous species in the mixture size_t m_nsp; - thermo_t* m_thermo; + ThermoPhase* m_thermo; //! Pointer to the homogeneous Kinetics object that handles the reactions Kinetics* m_kin; diff --git a/src/zeroD/ReactorBase.cpp b/src/zeroD/ReactorBase.cpp index 815830a837a..2636a890b88 100644 --- a/src/zeroD/ReactorBase.cpp +++ b/src/zeroD/ReactorBase.cpp @@ -26,7 +26,7 @@ ReactorBase::ReactorBase(const string& name) : m_name = name; } -void ReactorBase::setThermoMgr(thermo_t& thermo) +void ReactorBase::setThermoMgr(ThermoPhase& thermo) { m_thermo = &thermo; m_nsp = m_thermo->nSpecies(); From bf2eb073f071befb904729b325f115049882df9f Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Sun, 18 Aug 2019 06:35:18 -0500 Subject: [PATCH 6/6] Revise structure of yaml output --- .../cython/cantera/test/test_reactor.py | 16 +++--- src/zeroD/FlowDevice.cpp | 4 +- src/zeroD/ReactorBase.cpp | 17 +++---- src/zeroD/ReactorNet.cpp | 50 +++++++++---------- src/zeroD/Wall.cpp | 4 +- 5 files changed, 45 insertions(+), 46 deletions(-) diff --git a/interfaces/cython/cantera/test/test_reactor.py b/interfaces/cython/cantera/test/test_reactor.py index ffbf040c368..496347a70e2 100644 --- a/interfaces/cython/cantera/test/test_reactor.py +++ b/interfaces/cython/cantera/test/test_reactor.py @@ -415,21 +415,21 @@ def test_yaml(self, **kwargs): yaml = YAML() yml = yaml.load(self.net.to_yaml()) - self.assertTrue('ReactorNet' in yml) - net = yml['ReactorNet'] + self.assertTrue('reactor-network' in yml) + net = yml['reactor-network'] - self.assertTrue('ReactorBase' in net) - reactors = [tuple(n)[0] for n in net['ReactorBase']] + self.assertTrue('reactors' in net) + reactors = [tuple(n)[0] for n in net['reactors']] self.assertTrue(self.r1.name in reactors) self.assertTrue(self.r2.name in reactors) self.assertTrue(reservoir.name in reactors) - self.assertTrue('WallBase' in net) - walls = [tuple(n)[0] for n in net['WallBase']] + self.assertTrue('walls' in net) + walls = [tuple(n)[0] for n in net['walls']] self.assertTrue(self.w.name in walls) - self.assertTrue('FlowDevice' in net) - devices = [tuple(n)[0] for n in net['FlowDevice']] + self.assertTrue('flow-devices' in net) + devices = [tuple(n)[0] for n in net['flow-devices']] self.assertTrue(mfc.name in devices) self.r2.name = self.r1.name diff --git a/src/zeroD/FlowDevice.cpp b/src/zeroD/FlowDevice.cpp index 83ee3b18d99..ce534cedee9 100644 --- a/src/zeroD/FlowDevice.cpp +++ b/src/zeroD/FlowDevice.cpp @@ -61,8 +61,8 @@ std::string FlowDevice::toYAML() const yml << YAML::Key << name(); yml << YAML::BeginMap; yml << YAML::Key << "type" << YAML::Value << typeStr(); - yml << YAML::Key << "in" << YAML::Value << m_in->name(); - yml << YAML::Key << "out" << YAML::Value << m_out->name(); + yml << YAML::Key << "reactors" << YAML::Flow; + yml << YAML::BeginSeq << m_in->name() << m_out->name() << YAML::EndSeq; yml << YAML::EndMap; yml << YAML::EndMap; diff --git a/src/zeroD/ReactorBase.cpp b/src/zeroD/ReactorBase.cpp index 2636a890b88..1df46a38c9b 100644 --- a/src/zeroD/ReactorBase.cpp +++ b/src/zeroD/ReactorBase.cpp @@ -1,3 +1,4 @@ + //! @file ReactorBase.cpp // This file is part of Cantera. See License.txt in the top-level directory or @@ -7,6 +8,7 @@ #include "cantera/zeroD/FlowDevice.h" #include "cantera/zeroD/ReactorNet.h" #include "cantera/zeroD/ReactorSurface.h" +#include "cantera/thermo/SurfPhase.h" #include "cantera/base/yaml.h" using namespace std; @@ -57,16 +59,13 @@ std::string ReactorBase::toYAML() const yml << YAML::BeginMap; yml << YAML::Key << "type"; yml << YAML::Value << typeStr(); - if (m_thermo) { - yml << YAML::Key << "phase"; - yml << YAML::Value << m_thermo->name(); - yml << YAML::Key << "thermo.type"; - yml << YAML::Value << m_thermo->type(); - } - if (m_kin) { - yml << YAML::Key << "kinetics.type"; - yml << YAML::Value << m_kin->kineticsType(); + yml << YAML::Key << "phases" << YAML::Flow; + yml << YAML::BeginSeq; + yml << m_thermo->name(); + for (const auto& s : m_surfaces) { + yml << s->thermo()->name(); } + yml << YAML::EndSeq; yml << YAML::EndMap; yml << YAML::EndMap; diff --git a/src/zeroD/ReactorNet.cpp b/src/zeroD/ReactorNet.cpp index 039b9c1f583..9d811c18b2a 100644 --- a/src/zeroD/ReactorNet.cpp +++ b/src/zeroD/ReactorNet.cpp @@ -48,7 +48,7 @@ std::string ReactorNet::toYAML() const std::map reactors; std::map walls; std::map devices; - std::map surfaces; + // std::map surfaces; // construct complete maps for (auto r=m_reactors.begin(); r!=m_reactors.end(); r++) { @@ -93,21 +93,21 @@ std::string ReactorNet::toYAML() const reactors.emplace(uniqueName((void const *)(&out)), &out); } - // surfaces - for (size_t i=0; inSurfaces(); i++) { + // // surfaces + // for (size_t i=0; inSurfaces(); i++) { - ReactorSurface* surface = rb->surface(i); - surfaces.emplace(uniqueName((void const *)surface), surface); - } + // ReactorSurface* surface = rb->surface(i); + // surfaces.emplace(uniqueName((void const *)surface), surface); + // } } // header yml << YAML::BeginMap; - yml << YAML::Key << "ReactorNet"; + yml << YAML::Key << "reactor-network"; yml << YAML::BeginMap; // emit list of reactors - yml << YAML::Key << "ReactorBase"; + yml << YAML::Key << "reactors"; yml << YAML::Value << YAML::BeginSeq; for (const auto& r : reactors) { names.emplace(r.second->name(), r.first); @@ -122,7 +122,7 @@ std::string ReactorNet::toYAML() const // emit list of walls names.clear(); if (walls.size()) { - yml << YAML::Key << "WallBase"; + yml << YAML::Key << "walls"; yml << YAML::Value << YAML::BeginSeq; for (const auto& w : walls) { names.emplace(w.second->name(), w.first); @@ -138,7 +138,7 @@ std::string ReactorNet::toYAML() const // emit list of flow devices names.clear(); if (devices.size()) { - yml << YAML::Key << "FlowDevice"; + yml << YAML::Key << "flow-devices"; yml << YAML::Value << YAML::BeginSeq; for (const auto& d : devices) { names.emplace(d.second->name(), d.first); @@ -151,21 +151,21 @@ std::string ReactorNet::toYAML() const throw CanteraError("ReactorNet::toYAML", "FlowDevice names are not unique."); } - // emit list of reactor surfaces - names.clear(); - if (surfaces.size()) { - yml << YAML::Key << "ReactorSurface"; - yml << YAML::Value << YAML::BeginSeq; - for (const auto& s : surfaces) { - names.emplace(s.second->name(), s.first); - yml << YAML::Load(s.second->toYAML()); - } - yml << YAML::EndSeq; - } - if (names.size()!=surfaces.size()) { - // this should raise a warning, but an applicable warning system is not in place - throw CanteraError("ReactorNet::toYAML", "ReactorSurface names are not unique."); - } + // // emit list of reactor surfaces + // names.clear(); + // if (surfaces.size()) { + // yml << YAML::Key << "ReactorSurface"; + // yml << YAML::Value << YAML::BeginSeq; + // for (const auto& s : surfaces) { + // names.emplace(s.second->name(), s.first); + // yml << YAML::Load(s.second->toYAML()); + // } + // yml << YAML::EndSeq; + // } + // if (names.size()!=surfaces.size()) { + // // this should raise a warning, but an applicable warning system is not in place + // throw CanteraError("ReactorNet::toYAML", "ReactorSurface names are not unique."); + // } // close out yml << YAML::EndMap; diff --git a/src/zeroD/Wall.cpp b/src/zeroD/Wall.cpp index 9aa5bd8fb8b..667142c14b4 100644 --- a/src/zeroD/Wall.cpp +++ b/src/zeroD/Wall.cpp @@ -42,8 +42,8 @@ std::string WallBase::toYAML() const yml << YAML::Key << name(); yml << YAML::BeginMap; yml << YAML::Key << "type" << YAML::Value << type(); - yml << YAML::Key << "left" << YAML::Value << m_left->name(); - yml << YAML::Key << "right" << YAML::Value << m_right->name(); + yml << YAML::Key << "reactors" << YAML::Flow; + yml << YAML::BeginSeq << m_left->name() << m_right->name() << YAML::EndSeq; yml << YAML::EndMap; yml << YAML::EndMap;