This commit is contained in:
Ingmar Schoegl 2025-02-16 11:59:25 -05:00 committed by GitHub
commit 74e10f9989
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
35 changed files with 790 additions and 672 deletions

View File

@ -19,12 +19,12 @@ extern "C" {
CANTERA_CAPI int reactor_new(const char* type, int n, const char* name); CANTERA_CAPI int reactor_new(const char* type, int n, const char* name);
CANTERA_CAPI int reactor_del(int i); CANTERA_CAPI int reactor_del(int i);
CANTERA_CAPI int reactor_type(int i, int len, char* nbuf);
CANTERA_CAPI int reactor_name(int i, int len, char* nbuf); 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_setName(int i, const char* name);
CANTERA_CAPI int reactor_setInitialVolume(int i, double v); CANTERA_CAPI int reactor_setInitialVolume(int i, double v);
CANTERA_CAPI int reactor_setChemistry(int i, int cflag); CANTERA_CAPI int reactor_setChemistry(int i, int cflag);
CANTERA_CAPI int reactor_setEnergy(int i, int eflag); CANTERA_CAPI int reactor_setEnergy(int i, int eflag);
CANTERA_CAPI int reactor_setSolution(int i, int n);
CANTERA_CAPI double reactor_mass(int i); CANTERA_CAPI double reactor_mass(int i);
CANTERA_CAPI double reactor_volume(int i); CANTERA_CAPI double reactor_volume(int i);
CANTERA_CAPI double reactor_density(int i); CANTERA_CAPI double reactor_density(int i);
@ -51,11 +51,12 @@ extern "C" {
CANTERA_CAPI double reactornet_atol(int i); CANTERA_CAPI double reactornet_atol(int i);
CANTERA_CAPI double reactornet_sensitivity(int i, const char* v, int p, int r); CANTERA_CAPI double reactornet_sensitivity(int i, const char* v, int p, int r);
CANTERA_CAPI int flowdev_new(const char* type, const char* name); CANTERA_CAPI int connector_new(const char* type, int r0, int r1, const char* name);
CANTERA_CAPI int flowdev_del(int i); CANTERA_CAPI int connector_del(int i);
CANTERA_CAPI int flowdev_name(int i, int len, char* nbuf); CANTERA_CAPI int connector_type(int i, int len, char* nbuf);
CANTERA_CAPI int flowdev_setName(int i, const char* name); CANTERA_CAPI int connector_name(int i, int len, char* nbuf);
CANTERA_CAPI int flowdev_install(int i, int n, int m); CANTERA_CAPI int connector_setName(int i, const char* name);
CANTERA_CAPI int flowdev_setPrimary(int i, int n); CANTERA_CAPI int flowdev_setPrimary(int i, int n);
CANTERA_CAPI double flowdev_massFlowRate(int i); CANTERA_CAPI double flowdev_massFlowRate(int i);
CANTERA_CAPI int flowdev_setMassFlowCoeff(int i, double v); CANTERA_CAPI int flowdev_setMassFlowCoeff(int i, double v);
@ -64,11 +65,6 @@ extern "C" {
CANTERA_CAPI int flowdev_setPressureFunction(int i, int n); CANTERA_CAPI int flowdev_setPressureFunction(int i, int n);
CANTERA_CAPI int flowdev_setTimeFunction(int i, int n); CANTERA_CAPI int flowdev_setTimeFunction(int i, int n);
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_expansionRate(int i);
CANTERA_CAPI double wall_heatRate(int i); CANTERA_CAPI double wall_heatRate(int i);
CANTERA_CAPI double wall_area(int i); CANTERA_CAPI double wall_area(int i);
@ -79,7 +75,6 @@ extern "C" {
CANTERA_CAPI int wall_setExpansionRateCoeff(int i, double k); CANTERA_CAPI int wall_setExpansionRateCoeff(int i, double k);
CANTERA_CAPI int wall_setVelocity(int i, int n); CANTERA_CAPI int wall_setVelocity(int i, int n);
CANTERA_CAPI int wall_setEmissivity(int i, double epsilon); CANTERA_CAPI int wall_setEmissivity(int i, double epsilon);
CANTERA_CAPI int wall_ready(int i);
CANTERA_CAPI int reactorsurface_new(const char* name); CANTERA_CAPI int reactorsurface_new(const char* name);
CANTERA_CAPI int reactorsurface_del(int i); CANTERA_CAPI int reactorsurface_del(int i);

View File

@ -0,0 +1,98 @@
//! @file ConnectorFactory.h
// This file is part of Cantera. See License.txt in the top-level directory or
// at https://cantera.org/license.txt for license and copyright information.
#ifndef CONNECTOR_FACTORY_H
#define CONNECTOR_FACTORY_H
#include "cantera/base/FactoryBase.h"
#include "cantera/zeroD/ConnectorNode.h"
namespace Cantera
{
class FlowDevice;
class WallBase;
//! Factory class to create ConnectorNode objects.
//!
//! This class is mainly used via the newConnectorNode() function, for example:
//!
//! ```cpp
//! shared_ptr<ConnectorNode> valve = newConnectorNode("Valve", r0, r1, "my_valve");
//! ```
//!
//! where `r0` and `r1` are reactor objects.
class ConnectorFactory :
public Factory<ConnectorNode,
shared_ptr<ReactorBase>, shared_ptr<ReactorBase>, const string&>
{
public:
static ConnectorFactory* factory();
void deleteFactory() override;
private:
static ConnectorFactory* s_factory;
static std::mutex connector_mutex;
ConnectorFactory();
};
//! @defgroup connectorGroup Connectors
//! %ConnectorNode objects connect zero-dimensional reactors.
//! ConnectorNode objects should be instantiated via the newConnectorNode() function,
//! for example:
//!
//! ```cpp
//! shared_ptr<ConnectorNode> valve = newConnectorNode("Valve", r0, r1, "my_valve");
//! ```
//!
//! where `r0` and `r1` are reactor objects.
//!
//! @since New in %Cantera 3.2.
//!
//! @ingroup zerodGroup
//! @{
//! Create a ConnectorNode object of the specified type
//! @param model String specifying reactor type.
//! @param r0 First reactor.
//! @param r1 Second reactor.
//! @param name Name of the connector.
//! @since New in %Cantera 3.2.
shared_ptr<ConnectorNode> newConnectorNode(const string& model,
shared_ptr<ReactorBase> r0,
shared_ptr<ReactorBase> r1,
const string& name="(none)");
//! Create a FlowDevice object of the specified type
//! @since Starting in %Cantera 3.1, this method returns a `shared_ptr<FlowDevice>`
//! @deprecated To be removed after %Cantera 3.2. Use version that provides reactors
//! as parameter instead.
shared_ptr<FlowDevice> newFlowDevice(const string& model, const string& name="(none)");
//! Create a FlowDevice object of the specified type.
//! @copydetails newConnectorNode
shared_ptr<FlowDevice> newFlowDevice(const string& model,
shared_ptr<ReactorBase> r0,
shared_ptr<ReactorBase> r1,
const string& name="(none)");
//! Create a WallBase object of the specified type
//! @since Starting in %Cantera 3.1, this method returns a `shared_ptr<WallBase>`
//! @deprecated To be removed after %Cantera 3.2. Use version that provides reactors
//! as parameter instead.
shared_ptr<WallBase> newWall(const string& model, const string& name="(none)");
//! Create a WallBase object of the specified type.
//! @copydetails newConnectorNode
shared_ptr<WallBase> newWall(const string& model,
shared_ptr<ReactorBase> r0,
shared_ptr<ReactorBase> r1,
const string& name="(none)");
//! @}
}
#endif

View File

@ -0,0 +1,74 @@
//! @file ConnectorNode.h
// This file is part of Cantera. See License.txt in the top-level directory or
// at https://cantera.org/license.txt for license and copyright information.
#ifndef CT_CONNECTOR_H
#define CT_CONNECTOR_H
#include "cantera/base/ct_defs.h"
#include "cantera/base/global.h"
namespace Cantera
{
class ReactorBase;
/**
* Base class for walls and flow devices connecting reactors.
* In a reactor network, walls and flow devices (e.g., valves, pressure regulators)
* represent nodes in a directed bipartite graph - a graph whose vertices can be
* divided into two disjoint sets such that no two vertices within the same set are
* adjacent - with reactors forming the second set of nodes.
*
* @since New in %Cantera 3.2.
*
* @ingroup connectorGroup
*/
class ConnectorNode
{
public:
//! Transitional constructor.
//! @todo Implement deprecation warning.
ConnectorNode(const string& name="(none)") : m_name(name) {}
//! Instantiate a ConnectorNode object with associated ReactorBase objects.
//! @param r0 First reactor.
//! @param r1 Second reactor.
//! @param name Name of the connector.
ConnectorNode(shared_ptr<ReactorBase> r0, shared_ptr<ReactorBase> r1,
const string& name="(none)") : m_nodes({r0, r1}), m_name(name) {}
virtual ~ConnectorNode() = default;
ConnectorNode(const ConnectorNode&) = delete;
ConnectorNode& operator=(const ConnectorNode&) = delete;
//! String indicating the connector implemented. Usually
//! corresponds to the name of the derived class.
virtual string type() const {
return "ConnectorNode";
}
//! Retrieve connector name.
string name() const {
return m_name;
}
//! Set connector name.
void setName(const string& name) {
m_name = name;
}
//! Set the default name of a connector. Returns `false` if it was previously set.
void setDefaultName(map<string, int>& counts);
protected:
//! Pair of reactors forming end points of the connector.
pair<shared_ptr<ReactorBase>, shared_ptr<ReactorBase>> m_nodes;
string m_name; //!< ConnectorNode name.
bool m_defaultNameSet = false; //!< `true` if default name has been previously set.
};
}
#endif

View File

@ -9,6 +9,7 @@
#include "cantera/base/ct_defs.h" #include "cantera/base/ct_defs.h"
#include "cantera/base/global.h" #include "cantera/base/global.h"
#include "cantera/base/ctexceptions.h" #include "cantera/base/ctexceptions.h"
#include "ConnectorNode.h"
namespace Cantera namespace Cantera
{ {
@ -18,36 +19,19 @@ class ReactorBase;
/** /**
* Base class for 'flow devices' (valves, pressure regulators, etc.) * Base class for 'flow devices' (valves, pressure regulators, etc.)
* connecting reactors. * connecting reactors.
* @ingroup flowDeviceGroup * @ingroup connectorGroup
*/ */
class FlowDevice class FlowDevice : public ConnectorNode
{ {
public: public:
FlowDevice(const string& name="(none)") : m_name(name) {} FlowDevice(shared_ptr<ReactorBase> r0, shared_ptr<ReactorBase> r1,
const string& name="(none)");
using ConnectorNode::ConnectorNode; // inherit constructors
virtual ~FlowDevice() = default; string type() const override {
FlowDevice(const FlowDevice&) = delete;
FlowDevice& operator=(const FlowDevice&) = delete;
//! String indicating the flow device implemented. Usually
//! corresponds to the name of the derived class.
virtual string type() const {
return "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;
}
//! Set the default name of a flow device. Returns `false` if it was previously set.
bool setDefaultName(map<string, int>& counts);
//! Mass flow rate (kg/s). //! Mass flow rate (kg/s).
double massFlowRate() { double massFlowRate() {
if (m_mdot == Undef) { if (m_mdot == Undef) {
@ -73,6 +57,8 @@ public:
/*! /*!
* @param in Upstream reactor. * @param in Upstream reactor.
* @param out Downstream reactor. * @param out Downstream reactor.
* @deprecated To be removed after %Cantera 3.2. Reactors should be provided to
* constructor instead.
*/ */
bool install(ReactorBase& in, ReactorBase& out); bool install(ReactorBase& in, ReactorBase& out);
@ -133,9 +119,6 @@ public:
} }
protected: protected:
string m_name; //!< Flow device name.
bool m_defaultNameSet = false; //!< `true` if default name has been previously set.
double m_mdot = Undef; double m_mdot = Undef;
//! Function set by setPressureFunction; used by updateMassFlowRate //! Function set by setPressureFunction; used by updateMassFlowRate

View File

@ -6,48 +6,9 @@
#ifndef FLOWDEVICE_FACTORY_H #ifndef FLOWDEVICE_FACTORY_H
#define FLOWDEVICE_FACTORY_H #define FLOWDEVICE_FACTORY_H
#include "cantera/base/FactoryBase.h" #pragma message("warning: FlowDeviceFactory.h is deprecated and will be removed " \
#include "cantera/zeroD/FlowDevice.h" "after Cantera 3.2. Use ConnectorFactory.h instead.")
namespace Cantera #include "ConnectorFactory.h"
{
//! Factory class to create FlowDevice objects.
//!
//! This class is mainly used via the newFlowDevice() function, for example:
//!
//! ```cpp
//! shared_ptr<FlowDevice> mfc = newFlowDevice("MassFlowController");
//! ```
class FlowDeviceFactory : public Factory<FlowDevice, const string&>
{
public:
static FlowDeviceFactory* factory();
void deleteFactory() override;
private:
static FlowDeviceFactory* s_factory;
static std::mutex flowDevice_mutex;
FlowDeviceFactory();
};
//! @defgroup flowDeviceGroup Flow Devices
//! Flow device objects connect zero-dimensional reactors.
//! FlowDevice objects should be instantiated via the newFlowDevice function, for
//! example:
//!
//! ```cpp
//! shared_ptr<FlowDevice> 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<FlowDevice>`
shared_ptr<FlowDevice> newFlowDevice(const string& model, const string& name="(none)");
//! @}
}
#endif #endif

View File

@ -80,6 +80,8 @@ public:
//! Set the Solution specifying the ReactorBase content. //! Set the Solution specifying the ReactorBase content.
//! @param sol Solution object to be set. //! @param sol Solution object to be set.
//! @since New in %Cantera 3.1. //! @since New in %Cantera 3.1.
//! @deprecated To be removed after %Cantera 3.2. Superseded by instantiation of
//! ReactorBase with Solution object.
void setSolution(shared_ptr<Solution> sol); void setSolution(shared_ptr<Solution> sol);
//! @name Methods to set up a simulation //! @name Methods to set up a simulation

View File

@ -16,7 +16,6 @@ class SurfPhase;
//! A surface where reactions can occur that is in contact with the bulk fluid of a //! A surface where reactions can occur that is in contact with the bulk fluid of a
//! Reactor. //! Reactor.
//! @ingroup wallGroup
class ReactorSurface class ReactorSurface
{ {
public: public:

View File

@ -8,6 +8,7 @@
#include "cantera/base/ctexceptions.h" #include "cantera/base/ctexceptions.h"
#include "cantera/zeroD/ReactorBase.h" #include "cantera/zeroD/ReactorBase.h"
#include "ConnectorNode.h"
namespace Cantera namespace Cantera
{ {
@ -16,36 +17,19 @@ class Func1;
/** /**
* Base class for 'walls' (walls, pistons, etc.) connecting reactors. * Base class for 'walls' (walls, pistons, etc.) connecting reactors.
* @ingroup wallGroup * @ingroup connectorGroup
*/ */
class WallBase class WallBase : public ConnectorNode
{ {
public: public:
WallBase(const string& name="(none)") : m_name(name) {} WallBase(shared_ptr<ReactorBase> r0, shared_ptr<ReactorBase> r1,
const string& name="(none)");
using ConnectorNode::ConnectorNode; // inherit constructors
virtual ~WallBase() {} string type() const override {
WallBase(const WallBase&) = delete;
WallBase& operator=(const WallBase&) = delete;
//! String indicating the wall model implemented. Usually
//! corresponds to the name of the derived class.
virtual string type() const {
return "WallBase"; return "WallBase";
} }
//! Retrieve wall name.
string name() const {
return m_name;
}
//! Set wall name.
void setName(const string& name) {
m_name = name;
}
//! Set the default name of a wall. Returns `false` if it was previously set.
bool setDefaultName(map<string, int>& counts);
//! Rate of volume change (m^3/s) for the adjacent reactors at current reactor //! Rate of volume change (m^3/s) for the adjacent reactors at current reactor
//! network time. //! network time.
/*! /*!
@ -76,6 +60,8 @@ public:
virtual void setArea(double a); virtual void setArea(double a);
//! Install the wall between two reactors or reservoirs //! Install the wall between two reactors or reservoirs
//! @deprecated To be removed after %Cantera 3.2. Reactors should be provided to
//! constructor instead.
bool install(ReactorBase& leftReactor, ReactorBase& rightReactor); bool install(ReactorBase& leftReactor, ReactorBase& rightReactor);
//! Called just before the start of integration //! Called just before the start of integration
@ -105,9 +91,6 @@ public:
} }
protected: protected:
string m_name; //!< Wall name.
bool m_defaultNameSet = false; //!< `true` if default name has been previously set.
ReactorBase* m_left = nullptr; ReactorBase* m_left = nullptr;
ReactorBase* m_right = nullptr; ReactorBase* m_right = nullptr;
@ -121,7 +104,7 @@ protected:
/*! /*!
* Walls can move (changing the volume of the adjacent reactors) and allow heat * Walls can move (changing the volume of the adjacent reactors) and allow heat
* transfer between reactors. * transfer between reactors.
* @ingroup wallGroup * @ingroup connectorGroup
*/ */
class Wall : public WallBase class Wall : public WallBase
{ {

View File

@ -6,49 +6,9 @@
#ifndef WALL_FACTORY_H #ifndef WALL_FACTORY_H
#define WALL_FACTORY_H #define WALL_FACTORY_H
#include "cantera/base/FactoryBase.h" #pragma message("warning: WallFactory.h is deprecated and will be removed " \
#include "cantera/zeroD/Wall.h" "after Cantera 3.2. Use ConnectorFactory.h instead.")
namespace Cantera #include "ConnectorFactory.h"
{
//! Factory class to create WallBase objects
//!
//! This class is mainly used via the newWall() function, for example:
//!
//! ```cpp
//! shared_ptr<WallBase> piston = newWall("Wall");
//! ```
class WallFactory : public Factory<WallBase, const string&>
{
public:
static WallFactory* factory();
void deleteFactory() override;
private:
static WallFactory* s_factory;
static std::mutex wall_mutex;
WallFactory();
};
//! @defgroup wallGroup Walls
//! Zero-dimensional objects adjacent to reactors.
//! Wall objects should be instantiated via the newWall function, for
//! example:
//!
//! ```cpp
//! shared_ptr<WallBase> 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<WallBase>`
shared_ptr<WallBase> newWall(const string& model, const string& name="(none)");
//! @}
}
#endif #endif

View File

@ -15,7 +15,7 @@ namespace Cantera
/** /**
* A class for mass flow controllers. The mass flow rate is constant or * A class for mass flow controllers. The mass flow rate is constant or
* specified as a function of time. * specified as a function of time.
* @ingroup flowDeviceGroup * @ingroup connectorGroup
*/ */
class MassFlowController : public FlowDevice class MassFlowController : public FlowDevice
{ {
@ -60,7 +60,7 @@ public:
* A class for flow controllers where the flow rate is equal to the flow rate * A class for flow controllers where the flow rate is equal to the flow rate
* of a primary mass flow controller plus a correction proportional to the * of a primary mass flow controller plus a correction proportional to the
* pressure difference between the inlet and outlet. * pressure difference between the inlet and outlet.
* @ingroup flowDeviceGroup * @ingroup connectorGroup
*/ */
class PressureController : public FlowDevice class PressureController : public FlowDevice
{ {
@ -118,7 +118,7 @@ protected:
* The default behavior is a linearly proportional to the pressure difference. * The default behavior is a linearly proportional to the pressure difference.
* Note that real valves do not have this behavior, so this class does not * Note that real valves do not have this behavior, so this class does not
* model real, physical valves. * model real, physical valves.
* @ingroup flowDeviceGroup * @ingroup connectorGroup
*/ */
class Valve : public FlowDevice class Valve : public FlowDevice
{ {

View File

@ -33,8 +33,7 @@
// factories // factories
#include "cantera/zeroD/ReactorFactory.h" #include "cantera/zeroD/ReactorFactory.h"
#include "cantera/zeroD/FlowDeviceFactory.h" #include "cantera/zeroD/ConnectorFactory.h"
#include "cantera/zeroD/WallFactory.h"
// func1 // func1
#include "cantera/numerics/Func1.h" #include "cantera/numerics/Func1.h"

View File

@ -32,12 +32,11 @@ cdef extern from "cantera/zerodim.h" namespace "Cantera":
# factories # factories
cdef shared_ptr[CxxReactorBase] newReactor(string) except +translate_exception 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[CxxReactorBase] newReactor(string, shared_ptr[CxxSolution], string) except +translate_exception
cdef shared_ptr[CxxFlowDevice] newFlowDevice(string, string) except +translate_exception cdef shared_ptr[CxxConnectorNode] newConnectorNode(string, shared_ptr[CxxReactorBase], shared_ptr[CxxReactorBase], string) except +translate_exception
cdef shared_ptr[CxxWallBase] newWall(string, string) except +translate_exception
# reactors # reactors
cdef cppclass CxxReactorBase "Cantera::ReactorBase": cdef cppclass CxxReactorBase "Cantera::ReactorBase":
CxxReactorBase() CxxReactorBase() except +translate_exception
string type() string type()
void setSolution(shared_ptr[CxxSolution]) except +translate_exception void setSolution(shared_ptr[CxxSolution]) except +translate_exception
void restoreState() except +translate_exception void restoreState() except +translate_exception
@ -48,7 +47,7 @@ cdef extern from "cantera/zerodim.h" namespace "Cantera":
void setInitialVolume(double) void setInitialVolume(double)
cdef cppclass CxxReactor "Cantera::Reactor" (CxxReactorBase): cdef cppclass CxxReactor "Cantera::Reactor" (CxxReactorBase):
CxxReactor() CxxReactor() except +translate_exception
void setChemistry(cbool) void setChemistry(cbool)
cbool chemistryEnabled() cbool chemistryEnabled()
void setEnergy(int) void setEnergy(int)
@ -59,7 +58,7 @@ cdef extern from "cantera/zerodim.h" namespace "Cantera":
void getState(double*) except +translate_exception void getState(double*) except +translate_exception
CxxSparseMatrix jacobian() except +translate_exception CxxSparseMatrix jacobian() except +translate_exception
CxxSparseMatrix finiteDifferenceJacobian() except +translate_exception CxxSparseMatrix finiteDifferenceJacobian() except +translate_exception
void addSurface(CxxReactorSurface*) void addSurface(CxxReactorSurface*) except +translate_exception
void setAdvanceLimit(string&, double) except +translate_exception void setAdvanceLimit(string&, double) except +translate_exception
void addSensitivityReaction(size_t) except +translate_exception void addSensitivityReaction(size_t) except +translate_exception
void addSensitivitySpeciesEnthalpy(size_t) except +translate_exception void addSensitivitySpeciesEnthalpy(size_t) except +translate_exception
@ -82,40 +81,6 @@ cdef extern from "cantera/zerodim.h" namespace "Cantera":
int inletSurfaceMaxErrorFailures() int inletSurfaceMaxErrorFailures()
void setInletSurfaceMaxErrorFailures(int) except +translate_exception void setInletSurfaceMaxErrorFailures(int) except +translate_exception
# walls
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)
void setKinetics(CxxKinetics*, CxxKinetics*)
void setCoverages(int, double*)
void setCoverages(int, Composition&) except +translate_exception
void syncCoverages(int)
double expansionRate() except +translate_exception
double vdot(double) except +translate_exception
double heatRate() except +translate_exception
double Q(double) except +translate_exception
void addSensitivityReaction(int, size_t) except +translate_exception
size_t nSensParams(int)
cdef cppclass CxxWall "Cantera::Wall" (CxxWallBase):
CxxWall()
void setExpansionRateCoeff(double)
double getExpansionRateCoeff()
void setHeatTransferCoeff(double)
double getHeatTransferCoeff()
void setEmissivity(double) except +translate_exception
double getEmissivity()
double velocity()
void setVelocity(CxxFunc1*)
double heatFlux()
void setHeatFlux(CxxFunc1*)
# reactor surface # reactor surface
cdef cppclass CxxReactorSurface "Cantera::ReactorSurface": cdef cppclass CxxReactorSurface "Cantera::ReactorSurface":
@ -132,25 +97,59 @@ cdef extern from "cantera/zerodim.h" namespace "Cantera":
void addSensitivityReaction(size_t) except +translate_exception void addSensitivityReaction(size_t) except +translate_exception
size_t nSensParams() size_t nSensParams()
# flow devices # connectors
cdef cppclass CxxFlowDevice "Cantera::FlowDevice": cdef cppclass CxxConnectorNode "Cantera::ConnectorNode":
CxxFlowDevice() CxxConnectorNode() except +translate_exception
string type() string type()
string name() string name()
void setName(string) except +translate_exception void setName(string) except +translate_exception
# walls
cdef cppclass CxxWallBase "Cantera::WallBase" (CxxConnectorNode ):
CxxWallBase() except +translate_exception
double area()
void setArea(double)
void setKinetics(CxxKinetics*, CxxKinetics*)
void setCoverages(int, double*)
void setCoverages(int, Composition&) except +translate_exception
void syncCoverages(int)
double expansionRate() except +translate_exception
double vdot(double) except +translate_exception
double heatRate() except +translate_exception
double Q(double) except +translate_exception
void addSensitivityReaction(int, size_t) except +translate_exception
size_t nSensParams(int)
cdef cppclass CxxWall "Cantera::Wall" (CxxWallBase):
CxxWall() except +translate_exception
void setExpansionRateCoeff(double)
double getExpansionRateCoeff()
void setHeatTransferCoeff(double)
double getHeatTransferCoeff()
void setEmissivity(double) except +translate_exception
double getEmissivity()
double velocity()
void setVelocity(CxxFunc1*)
double heatFlux()
void setHeatFlux(CxxFunc1*)
# flow devices
cdef cppclass CxxFlowDevice "Cantera::FlowDevice" (CxxConnectorNode):
CxxFlowDevice() except +translate_exception
double massFlowRate() except +translate_exception double massFlowRate() except +translate_exception
double massFlowRate(double) except +translate_exception double massFlowRate(double) except +translate_exception
cbool install(CxxReactorBase&, CxxReactorBase&) except +translate_exception
double evalPressureFunction() except +translate_exception double evalPressureFunction() except +translate_exception
void setPressureFunction(CxxFunc1*) except +translate_exception void setPressureFunction(CxxFunc1*) except +translate_exception
double evalTimeFunction() except +translate_exception double evalTimeFunction() except +translate_exception
void setTimeFunction(CxxFunc1*) except +translate_exception void setTimeFunction(CxxFunc1*) except +translate_exception
cdef cppclass CxxMassFlowController "Cantera::MassFlowController" (CxxFlowDevice): cdef cppclass CxxMassFlowController "Cantera::MassFlowController" (CxxFlowDevice):
CxxMassFlowController() CxxMassFlowController() except +translate_exception
void setMassFlowRate(double) void setMassFlowRate(double) except +translate_exception
void setMassFlowCoeff(double) void setMassFlowCoeff(double) except +translate_exception
double getMassFlowCoeff() double getMassFlowCoeff()
cdef cppclass CxxValve "Cantera::Valve" (CxxFlowDevice): cdef cppclass CxxValve "Cantera::Valve" (CxxFlowDevice):
@ -225,7 +224,7 @@ ctypedef CxxReactorAccessor* CxxReactorAccessorPtr
cdef class ReactorBase: cdef class ReactorBase:
cdef shared_ptr[CxxReactorBase] _reactor cdef shared_ptr[CxxReactorBase] _reactor
cdef CxxReactorBase* rbase cdef CxxReactorBase* rbase
cdef object _thermo cdef object _contents
cdef list _inlets cdef list _inlets
cdef list _outlets cdef list _outlets
cdef list _walls cdef list _walls
@ -241,7 +240,6 @@ cdef class ReactorBase:
cdef class Reactor(ReactorBase): cdef class Reactor(ReactorBase):
cdef CxxReactor* reactor cdef CxxReactor* reactor
cdef object _kinetics
cdef public str group_name cdef public str group_name
""" """
Optional name of a grouping of reactors that will be drawn as a cluster in the Optional name of a grouping of reactors that will be drawn as a cluster in the
@ -289,14 +287,9 @@ cdef class ReactorSurface:
.. versionadded:: 3.1 .. versionadded:: 3.1
""" """
cdef class WallBase: cdef class ConnectorNode:
cdef shared_ptr[CxxWallBase] _wall cdef shared_ptr[CxxConnectorNode] _node
cdef CxxWallBase* wall cdef CxxConnectorNode* node
cdef object _velocity_func
cdef object _heat_flux_func
cdef ReactorBase _left_reactor
cdef ReactorBase _right_reactor
cdef str name
cdef public dict edge_attr cdef public dict edge_attr
""" """
A dictionary containing draw attributes for the representation of the `WallBase` as A dictionary containing draw attributes for the representation of the `WallBase` as
@ -306,25 +299,24 @@ cdef class WallBase:
.. versionadded:: 3.1 .. versionadded:: 3.1
""" """
cdef class WallBase(ConnectorNode):
# cdef shared_ptr[CxxWallBase] _wall
cdef CxxWallBase* wall
cdef object _velocity_func
cdef object _heat_flux_func
cdef ReactorBase _left_reactor
cdef ReactorBase _right_reactor
cdef class Wall(WallBase): cdef class Wall(WallBase):
pass pass
cdef class FlowDevice: cdef class FlowDevice(ConnectorNode):
cdef shared_ptr[CxxFlowDevice] _dev # cdef shared_ptr[CxxFlowDevice] _dev
cdef CxxFlowDevice* dev cdef CxxFlowDevice* dev
cdef Func1 _rate_func cdef Func1 _rate_func
cdef Func1 _time_func cdef Func1 _time_func
cdef str name
cdef ReactorBase _upstream cdef ReactorBase _upstream
cdef ReactorBase _downstream cdef ReactorBase _downstream
cdef public dict edge_attr
"""
A dictionary containing draw attributes for the representation of the `FlowDevice`
as a graphviz edge.See https://graphviz.org/docs/edges/ for a list of all usable
attributes.
.. versionadded:: 3.1
"""
cdef class MassFlowController(FlowDevice): cdef class MassFlowController(FlowDevice):
pass pass

View File

@ -28,7 +28,7 @@ cdef class ReactorBase:
self._walls = [] self._walls = []
self._surfaces = [] self._surfaces = []
if isinstance(contents, _SolutionBase): if isinstance(contents, _SolutionBase):
self.insert(contents) # leave insert for the time being self._contents = contents
if volume is not None: if volume is not None:
self.volume = volume self.volume = volume
@ -39,9 +39,14 @@ cdef class ReactorBase:
""" """
Set ``solution`` to be the object used to compute thermodynamic Set ``solution`` to be the object used to compute thermodynamic
properties and kinetic rates for this reactor. properties and kinetic rates for this reactor.
.. deprecated:: 3.2
After Cantera 3.2, a change of reactor contents after instantiation
will be disabled and this method will be removed.
""" """
self._thermo = solution self.rbase.setSolution(solution._base) # raises warning in C++ core
self.rbase.setSolution(solution._base) self._contents = solution
property type: property type:
"""The type of the reactor.""" """The type of the reactor."""
@ -64,10 +69,12 @@ cdef class ReactorBase:
self.rbase.syncState() self.rbase.syncState()
property thermo: property thermo:
"""The `ThermoPhase` object representing the reactor's contents.""" """
The `ThermoPhase` object representing the reactor's contents.
"""
def __get__(self): def __get__(self):
self.rbase.restoreState() self.rbase.restoreState()
return self._thermo return self._contents
property volume: property volume:
"""The volume [m^3] of the reactor.""" """The volume [m^3] of the reactor."""
@ -239,14 +246,6 @@ cdef class Reactor(ReactorBase):
self.group_name = group_name self.group_name = group_name
def insert(self, _SolutionBase solution):
"""
Set ``solution`` to be the object used to compute thermodynamic
properties and kinetic rates for this reactor.
"""
ReactorBase.insert(self, solution)
self._kinetics = solution
property kinetics: property kinetics:
""" """
The `Kinetics` object used for calculating kinetic rates in The `Kinetics` object used for calculating kinetic rates in
@ -254,7 +253,7 @@ cdef class Reactor(ReactorBase):
""" """
def __get__(self): def __get__(self):
self.rbase.restoreState() self.rbase.restoreState()
return self._kinetics return self._contents
property chemistry_enabled: property chemistry_enabled:
""" """
@ -939,14 +938,52 @@ cdef class ReactorSurface:
self.surface.addSensitivityReaction(m) self.surface.addSensitivityReaction(m)
cdef class WallBase: cdef class ConnectorNode:
"""
Common base class for walls and flow devices.
"""
node_type = "none"
def __cinit__(self, ReactorBase left=None, ReactorBase right=None, *,
ReactorBase upstream=None, ReactorBase downstream=None,
name="(none)", **kwargs):
# ensure that both naming conventions (Wall and FlowDevice) are covered
cdef ReactorBase r0 = left or upstream
cdef ReactorBase r1 = right or downstream
if isinstance(r0, ReactorBase) and isinstance(r1, ReactorBase):
self._node = newConnectorNode(stringify(self.node_type),
r0._reactor, r1._reactor, stringify(name))
self.node = self._node.get()
return
raise TypeError(f"Invalid reactor types: {r0} and {r1}.")
@property
def type(self):
"""The type of the connector."""
return pystr(self.node.type())
@property
def name(self):
"""The name of the connector."""
return pystr(self.node.name())
@name.setter
def name(self, name):
self.node.setName(stringify(name))
def __reduce__(self):
raise NotImplementedError('Reactor object is not picklable')
def __copy__(self):
raise NotImplementedError('Reactor object is not copyable')
cdef class WallBase(ConnectorNode):
""" """
Common base class for walls. Common base class for walls.
""" """
wall_type = "none" def __cinit__(self, *args, **kwargs):
def __cinit__(self, *args, name="(none)", **kwargs): self.wall = <CxxWall*>(self.node)
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): Q=None, velocity=None, edge_attr=None):
@ -985,8 +1022,6 @@ cdef class WallBase:
self._velocity_func = None self._velocity_func = None
self._heat_flux_func = None self._heat_flux_func = None
self._install(left, right)
if A is not None: if A is not None:
self.area = A self.area = A
if K is not None: if K is not None:
@ -999,30 +1034,12 @@ cdef class WallBase:
self.velocity = velocity self.velocity = velocity
self.edge_attr = edge_attr or {} self.edge_attr = edge_attr or {}
def _install(self, ReactorBase left, ReactorBase right):
"""
Install this Wall between two `Reactor` objects or between a
`Reactor` and a `Reservoir`.
"""
left._add_wall(self) left._add_wall(self)
right._add_wall(self) right._add_wall(self)
self.wall.install(deref(left.rbase), deref(right.rbase))
# Keep references to prevent premature garbage collection # Keep references to prevent premature garbage collection
self._left_reactor = left self._left_reactor = left
self._right_reactor = right self._right_reactor = right
property type:
"""The type of the wall."""
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: property area:
""" The wall area [m^2]. """ """ The wall area [m^2]. """
def __get__(self): def __get__(self):
@ -1138,7 +1155,7 @@ cdef class Wall(WallBase):
:math:`q_0(t)` is a specified function of time. The heat flux is positive :math:`q_0(t)` is a specified function of time. The heat flux is positive
when heat flows from the reactor on the left to the reactor on the right. when heat flows from the reactor on the left to the reactor on the right.
""" """
wall_type = "Wall" node_type = "Wall"
property expansion_rate_coeff: property expansion_rate_coeff:
""" """
@ -1207,7 +1224,7 @@ cdef class Wall(WallBase):
(<CxxWall*>self.wall).setHeatFlux(f.func) (<CxxWall*>self.wall).setHeatFlux(f.func)
cdef class FlowDevice: cdef class FlowDevice(ConnectorNode):
""" """
Base class for devices that allow flow between reactors. Base class for devices that allow flow between reactors.
@ -1218,37 +1235,15 @@ cdef class FlowDevice:
across a FlowDevice, and the pressure difference equals the difference in across a FlowDevice, and the pressure difference equals the difference in
pressure between the upstream and downstream reactors. pressure between the upstream and downstream reactors.
""" """
flowdevice_type = "none" def __cinit__(self, *args, **kwargs):
def __cinit__(self, *args, name="(none)", **kwargs): self.dev = <CxxFlowDevice*>(self.node)
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 assert self.dev != NULL
self._rate_func = None self._rate_func = None
self.edge_attr = edge_attr or {} self.edge_attr = edge_attr or {}
self._install(upstream, downstream)
property type:
"""The type of the flow device."""
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``
(destination) reactors or reservoirs.
"""
upstream._add_outlet(self) upstream._add_outlet(self)
downstream._add_inlet(self) downstream._add_inlet(self)
self.dev.install(deref(upstream.rbase), deref(downstream.rbase))
# Keep references to prevent premature garbage collection # Keep references to prevent premature garbage collection
self._upstream = upstream self._upstream = upstream
self._downstream = downstream self._downstream = downstream
@ -1387,10 +1382,10 @@ cdef class MassFlowController(FlowDevice):
that this capability should be used with caution, since no account is that this capability should be used with caution, since no account is
taken of the work required to do this. taken of the work required to do this.
""" """
flowdevice_type = "MassFlowController" node_type = "MassFlowController"
def __init__(self, upstream, downstream, *, name="(none)", mdot=1., **kwargs): def __init__(self, upstream, downstream, *, name="(none)", mdot=1., edge_attr=None):
super().__init__(upstream, downstream, name=name, **kwargs) super().__init__(upstream, downstream, name=name, edge_attr=edge_attr)
self.mass_flow_rate = mdot self.mass_flow_rate = mdot
property mass_flow_coeff: property mass_flow_coeff:
@ -1461,10 +1456,10 @@ cdef class Valve(FlowDevice):
value, very small pressure differences will result in flow between the value, very small pressure differences will result in flow between the
reactors that counteracts the pressure difference. reactors that counteracts the pressure difference.
""" """
flowdevice_type = "Valve" node_type = "Valve"
def __init__(self, upstream, downstream, *, name="(none)", K=1., **kwargs): def __init__(self, upstream, downstream, *, name="(none)", K=1., edge_attr=None):
super().__init__(upstream, downstream, name=name, **kwargs) super().__init__(upstream, downstream, name=name, edge_attr=edge_attr)
if isinstance(K, _numbers.Real): if isinstance(K, _numbers.Real):
self.valve_coeff = K self.valve_coeff = K
else: else:
@ -1504,10 +1499,11 @@ cdef class PressureController(FlowDevice):
where :math:`f` is the arbitrary function of a single argument. where :math:`f` is the arbitrary function of a single argument.
""" """
flowdevice_type = "PressureController" node_type = "PressureController"
def __init__(self, upstream, downstream, *, name="(none)", primary=None, K=1.): def __init__(self, upstream, downstream, *,
super().__init__(upstream, downstream, name=name) name="(none)", primary=None, K=1., edge_attr=None):
super().__init__(upstream, downstream, name=name, edge_attr=edge_attr)
if primary is not None: if primary is not None:
self.primary = primary self.primary = primary
if isinstance(K, _numbers.Real): if isinstance(K, _numbers.Real):

View File

@ -1,4 +1,4 @@
classdef Interface < handle & ThermoPhase & Kinetics classdef Interface < Solution
% Interface Class :: % Interface Class ::
% %
% >> s = Interface(src, name, p1, p2) % >> s = Interface(src, name, p1, p2)
@ -13,11 +13,6 @@ classdef Interface < handle & ThermoPhase & Kinetics
% :return: % :return:
% Instance of class :mat:class:`Interface`. % Instance of class :mat:class:`Interface`.
properties (SetAccess = immutable)
solnID % ID of the interface.
interfaceName % Name of the interface.
end
properties (SetAccess = public) properties (SetAccess = public)
% Surface coverages of the species on an interface. % Surface coverages of the species on an interface.
@ -50,11 +45,8 @@ classdef Interface < handle & ThermoPhase & Kinetics
ID = ctFunc('soln_newInterface', src, name, na, adj); ID = ctFunc('soln_newInterface', src, name, na, adj);
% Inherit methods and properties from ThermoPhase and Kinetics % Inherit methods and properties from Solution
s@ThermoPhase(ID); s@Solution(ID);
s@Kinetics(ID);
s.solnID = ID;
s.interfaceName = name;
s.nAdjacent = ctFunc('soln_nAdjacent', ID); s.nAdjacent = ctFunc('soln_nAdjacent', ID);
s.adjacentNames = {}; s.adjacentNames = {};
for i = 1:s.nAdjacent for i = 1:s.nAdjacent
@ -62,13 +54,6 @@ classdef Interface < handle & ThermoPhase & Kinetics
end end
end end
%% Interface Class Destructor
function delete(s)
% Delete :mat:class:`Interface` object.
ctFunc('soln_del', s.solnID);
end
%% Interface Get Methods %% Interface Get Methods
function adj = adjacent(s, name) function adj = adjacent(s, name)

View File

@ -0,0 +1,84 @@
classdef Connector < handle
% Connector Class ::
%
% >> c = Connector(typ, r1, r2, name)
%
% Base class for walls and flow devices.
%
% See also: :mat:class:`FlowDevice`, :mat:class:`Wall`
%
% :param typ:
% Type of connector.
% :param r1:
% Reactor one.
% :param r2:
% Reactor two.
% :param name:
% Connector name (optional; default is ``(none)``).
% :return:
% Instance of class :mat:class:`Connector`.
properties (SetAccess = immutable)
id % ID of Connector object.
end
properties (SetAccess = public)
type % Name of connector.
name % Name of connector.
end
methods
%% Connector Class Constructor
function c = Connector(typ, r1, r2, name)
% Create a :mat:class:`Connector` object.
ctIsLoaded;
if nargin < 3
error('please specify type and reactors');
end
if nargin < 4
name = '(none)';
end
if ~isa(r1, 'Reactor') || ~isa(r1, 'Reactor')
error(['Connectors can only be installed between', ...
'reactors or reservoirs']);
end
c.id = ctFunc('connector_new', typ, r1.id, r2.id, name);
end
%% Connector Class Destructor
function delete(c)
% Delete the :mat:class:`Connector` object.
ctFunc('connector_del', c.id);
end
%% Connector Get Methods
function typ = get.type(c)
typ = ctString('connector_type', c.id);
end
function name = get.name(c)
name = ctString('connector_name', c.id);
end
%% Connector Set Methods
function set.name(c, name)
ctFunc('connector_setName', c.id, name);
end
end
end

View File

@ -1,4 +1,4 @@
classdef FlowDevice < handle classdef FlowDevice < Connector
% FlowDevice Class :: % FlowDevice Class ::
% %
% >> x = FlowDevice(typ, name) % >> x = FlowDevice(typ, name)
@ -25,21 +25,16 @@ classdef FlowDevice < handle
properties (SetAccess = immutable) properties (SetAccess = immutable)
type % Type of flow device.
id % ID of FlowDevice object.
end
properties (SetAccess = public)
name % Name of flow device.
% Upstream object of type :mat:class:`Reactor` or :mat:class:`Reservoir`. % Upstream object of type :mat:class:`Reactor` or :mat:class:`Reservoir`.
upstream upstream
% Downstream object of type :mat:class:`Reactor` or :mat:class:`Reservoir`. % Downstream object of type :mat:class:`Reactor` or :mat:class:`Reservoir`.
downstream downstream
end
properties (SetAccess = public)
% The mass flow rate through the :mat:class:`FlowDevice` at the current time. % The mass flow rate through the :mat:class:`FlowDevice` at the current time.
% %
% The setter method can either take a double value or a function represented by % The setter method can either take a double value or a function represented by
@ -60,79 +55,28 @@ classdef FlowDevice < handle
methods methods
%% FlowDevice Class Constructor %% FlowDevice Class Constructor
function x = FlowDevice(typ, name) function x = FlowDevice(typ, upstream, downstream, name)
% Create a :mat:class:`FlowDevice` object. % Create a :mat:class:`FlowDevice` object.
ctIsLoaded; ctIsLoaded;
if nargin == 0 if nargin < 4
error('please specify the type of flow device to be created');
end
if nargin < 2
name = '(none)'; name = '(none)';
end end
x.type = typ; x@Connector(typ, upstream, downstream, name)
x.id = ctFunc('flowdev_new', typ, name); x.upstream = upstream;
x.upstream = -1; x.downstream = downstream;
x.downstream = -1;
end
%% FlowDevice Class Destructor
function delete(f)
% Delete the :mat:class:`FlowDevice` object.
ctFunc('flowdev_del', f.id);
end
%% Utility Methods
function install(f, upstream, downstream)
% Install a flow device between reactors or reservoirs. ::
%
% >> f.install(upstream, downstream)
%
% :param f:
% Instance of class :mat:class:`FlowDevice` to install.
% :param upstream:
% Upstream :mat:class:`Reactor` or :mat:class:`Reservoir`.
% :param downstream:
% Downstream :mat:class:`Reactor` or :mat:class:`Reservoir`.
% :return:
% Instance of class :mat:class:`FlowDevice`.
if nargin == 3
if ~isa(upstream, 'Reactor') || ~isa(downstream, 'Reactor')
error(['Flow devices can only be installed between', ...
'reactors or reservoirs']);
end
i = upstream.id;
j = downstream.id;
ctFunc('flowdev_install', f.id, i, j);
else error('install requires 3 arguments');
end
end end
%% FlowDevice Get Methods %% FlowDevice Get Methods
function name = get.name(f)
name = ctString('flowdev_name', f.id);
end
function mdot = get.massFlowRate(f) function mdot = get.massFlowRate(f)
mdot = ctFunc('flowdev_massFlowRate2', f.id); mdot = ctFunc('flowdev_massFlowRate2', f.id);
end end
%% FlowDevice Set Methods %% FlowDevice Set Methods
function set.name(f, name)
ctFunc('flowdev_setName', f.id, name);
end
function set.massFlowRate(f, mdot) function set.massFlowRate(f, mdot)
if strcmp(f.type, 'MassFlowController') if strcmp(f.type, 'MassFlowController')

View File

@ -31,8 +31,7 @@ classdef MassFlowController < FlowDevice
name = '(none)'; name = '(none)';
end end
m@FlowDevice('MassFlowController', name); m@FlowDevice('MassFlowController', upstream, downstream, name);
m.install(upstream, downstream)
end end
end end

View File

@ -2,13 +2,14 @@ classdef Reactor < handle
properties (SetAccess = immutable) properties (SetAccess = immutable)
type % Type of Reactor.
id % ID of Reactor. id % ID of Reactor.
end end
properties (SetAccess = public) properties (SetAccess = public)
type % Reactor type.
name % Name of reactor. name % Name of reactor.
contents contents
@ -131,8 +132,8 @@ classdef Reactor < handle
error('Reactor contents must be an object of type "Solution"'); error('Reactor contents must be an object of type "Solution"');
end end
r.type = char(typ);
r.id = ctFunc('reactor_new', typ, content.solnID, name); r.id = ctFunc('reactor_new', typ, content.solnID, name);
r.contents = content;
end end
%% Reactor Class Destructor %% Reactor Class Destructor
@ -160,6 +161,10 @@ classdef Reactor < handle
%% Reactor Get Methods %% Reactor Get Methods
function typ = get.type(r)
typ = ctString('reactor_type', r.id);
end
function name = get.name(r) function name = get.name(r)
name = ctString('reactor_name', r.id); name = ctString('reactor_name', r.id);
end end

View File

@ -40,8 +40,7 @@ classdef Valve < FlowDevice
name = '(none)'; name = '(none)';
end end
v@FlowDevice('Valve', name); v@FlowDevice('Valve', upstream, downstream, name);
v.install(upstream, downstream)
end end
end end

View File

@ -1,4 +1,4 @@
classdef Wall < handle classdef Wall < Connector
% Wall Class :: % Wall Class ::
% %
% >> x = Wall(l, r, name) % >> x = Wall(l, r, name)
@ -47,15 +47,6 @@ classdef Wall < handle
properties (SetAccess = immutable) properties (SetAccess = immutable)
id
type
end
properties (SetAccess = protected)
name % Name of wall.
left % Reactor on the left. left % Reactor on the left.
right % Reactor on the right. right % Reactor on the right.
@ -93,49 +84,26 @@ classdef Wall < handle
function w = Wall(l, r, name) function w = Wall(l, r, name)
% Create a :mat:class:`Wall` object. % Create a :mat:class:`Wall` object.
ctIsLoaded;
% At the moment, only one wall type is implemented % At the moment, only one wall type is implemented
typ = 'Wall';
if nargin < 3 if nargin < 3
name = '(none)'; name = '(none)';
end end
w.type = char(typ);
w.id = ctFunc('wall_new', w.type, name);
% Install the wall between left and right reactors % Install the wall between left and right reactors
w@Connector('Wall', l, r, name)
w.left = l; w.left = l;
w.right = r; w.right = r;
ctFunc('wall_install', w.id, l.id, r.id);
% Set default values. % Set default values.
w.area = 1.0; w.area = 1.0;
w.expansionRateCoeff = 0.0; w.expansionRateCoeff = 0.0;
w.heatTransferCoeff = 0.0; w.heatTransferCoeff = 0.0;
% Check whether the wall is ready.
ok = ctFunc('wall_ready', w.id);
if ~ok
error('The wall object is not ready.');
end
end
%% Wall Class Destructor
function delete(w)
% Clear the :mat:class:`Wall` object.
ctFunc('wall_del', w.id);
end end
%% ReactorNet get methods %% ReactorNet get methods
function name = get.name(w)
name = ctString('wall_name', w.id);
end
function a = get.area(w) function a = get.area(w)
a = ctFunc('wall_area', w.id); a = ctFunc('wall_area', w.id);
end end
@ -150,10 +118,6 @@ classdef Wall < handle
%% ReactorNet set methods %% ReactorNet set methods
function set.name(w, name)
ctFunc('wall_setName', w.id, name);
end
function set.area(w, a) function set.area(w, a)
ctFunc('wall_setArea', w.id, a); ctFunc('wall_setArea', w.id, a);
end end

View File

@ -24,6 +24,7 @@ class_crosswalk:
trans: Transport trans: Transport
wall: Wall wall: Wall
func: Func1 func: Func1
connector: Connector
# Provides information on instance methods that return instances # Provides information on instance methods that return instances
# of other C# classes. # of other C# classes.
@ -42,6 +43,8 @@ class_accessors:
# Derived: Base # Derived: Base
derived_handles: derived_handles:
SurfaceHandle: ThermoPhaseHandle SurfaceHandle: ThermoPhaseHandle
WallHandle: ConnectorHandle
FlowDeviceHandle: ConnectorHandle
# Provides info for scaffolding higher-level idiomatic C# classes # Provides info for scaffolding higher-level idiomatic C# classes
# At this stage, we can scaffold simple properties that follow the # At this stage, we can scaffold simple properties that follow the

View File

@ -73,8 +73,7 @@ function periodic_cstr
sccm = 1.25; sccm = 1.25;
vdot = sccm * 1.0e-6/60.0 * ((OneAtm / gas.P) * (gas.T / 273.15)); % m^3/s vdot = sccm * 1.0e-6/60.0 * ((OneAtm / gas.P) * (gas.T / 273.15)); % m^3/s
mdot = gas.D * vdot; % kg/s mdot = gas.D * vdot; % kg/s
mfc = MassFlowController; mfc = MassFlowController(upstream, cstr);
mfc.install(upstream, cstr);
mfc.massFlowRate = mdot; mfc.massFlowRate = mdot;
% now create a downstream reservoir to exhaust into. % now create a downstream reservoir to exhaust into.
@ -83,8 +82,7 @@ function periodic_cstr
% connect the reactor to the downstream reservoir with a valve, and % connect the reactor to the downstream reservoir with a valve, and
% set the coefficient sufficiently large to keep the reactor pressure % set the coefficient sufficiently large to keep the reactor pressure
% close to the downstream pressure of 60 Torr. % close to the downstream pressure of 60 Torr.
v = Valve; v = Valve(cstr, downstream);
v.install(cstr, downstream);
v.valveCoeff = 1.0e-9; v.valveCoeff = 1.0e-9;
% create the network % create the network

View File

@ -131,7 +131,7 @@ class SolidProperties:
def effectiveConductivitySiC(Ts): # for silicon carbide def effectiveConductivitySiC(Ts): # for silicon carbide
return (1 - 0.84) * 1857.0 * Ts**(-0.5332) return (1 - 0.84) * 1857.0 * Ts**(-0.5332)
# YZA: Thermal conductivity of zirconiaalumina composites, N.P. Bansal, D. Zhu, # YZA: Thermal conductivity of zirconiaalumina composites, N.P. Bansal, D. Zhu,
# Ceramics International, 31(7), pp 911-916 (2015) # Ceramics International, 31(7), pp 911-916 (2015)
def effectiveConductivityYZA(Ts): # for yittria-stabilized zirconia alumina def effectiveConductivityYZA(Ts): # for yittria-stabilized zirconia alumina
return 0.3 return 0.3
@ -409,3 +409,4 @@ plt.legend()
plt.xlabel("x (m)") plt.xlabel("x (m)")
plt.ylabel("T (K)") plt.ylabel("T (K)")
plt.savefig("T.png") plt.savefig("T.png")
plt.show()

View File

@ -162,6 +162,7 @@ plt.figure()
plt.semilogx(time_history.t, time_history("CO").X, "-o") plt.semilogx(time_history.t, time_history("CO").X, "-o")
plt.xlabel("Time (s)") plt.xlabel("Time (s)")
plt.ylabel("Mole Fraction : $X_{CO}$") plt.ylabel("Mole Fraction : $X_{CO}$")
plt.show()
# %% # %%
# Illustration : Modeling experimental data # Illustration : Modeling experimental data
@ -288,6 +289,7 @@ plt.ylabel(r"Mole Fractions")
plt.xlim([650, 1100]) plt.xlim([650, 1100])
plt.legend(loc=1) plt.legend(loc=1)
plt.show()
# %% # %%
# References # References

View File

@ -19,8 +19,7 @@ using namespace Cantera;
typedef Cabinet<ReactorBase> ReactorCabinet; typedef Cabinet<ReactorBase> ReactorCabinet;
typedef Cabinet<ReactorNet> NetworkCabinet; typedef Cabinet<ReactorNet> NetworkCabinet;
typedef Cabinet<FlowDevice> FlowDeviceCabinet; typedef Cabinet<ConnectorNode> ConnectorCabinet;
typedef Cabinet<WallBase> WallCabinet;
typedef Cabinet<Func1> FuncCabinet; typedef Cabinet<Func1> FuncCabinet;
typedef Cabinet<ThermoPhase> ThermoCabinet; typedef Cabinet<ThermoPhase> ThermoCabinet;
typedef Cabinet<Kinetics> KineticsCabinet; typedef Cabinet<Kinetics> KineticsCabinet;
@ -29,8 +28,7 @@ typedef Cabinet<ReactorSurface> ReactorSurfaceCabinet;
template<> ReactorCabinet* ReactorCabinet::s_storage = 0; template<> ReactorCabinet* ReactorCabinet::s_storage = 0;
template<> NetworkCabinet* NetworkCabinet::s_storage = 0; template<> NetworkCabinet* NetworkCabinet::s_storage = 0;
template<> FlowDeviceCabinet* FlowDeviceCabinet::s_storage = 0; template<> ConnectorCabinet* ConnectorCabinet::s_storage = 0;
template<> WallCabinet* WallCabinet::s_storage = 0;
template<> ReactorSurfaceCabinet* ReactorSurfaceCabinet::s_storage = 0; template<> ReactorSurfaceCabinet* ReactorSurfaceCabinet::s_storage = 0;
template<> FuncCabinet* FuncCabinet::s_storage; // defined in ctfunc.cpp template<> FuncCabinet* FuncCabinet::s_storage; // defined in ctfunc.cpp
template<> ThermoCabinet* ThermoCabinet::s_storage; // defined in ct.cpp template<> ThermoCabinet* ThermoCabinet::s_storage; // defined in ct.cpp
@ -44,7 +42,8 @@ extern "C" {
int reactor_new(const char* type, int n, const char* name) int reactor_new(const char* type, int n, const char* name)
{ {
try { try {
return ReactorCabinet::add(newReactor(type, SolutionCabinet::at(n), name)); return ReactorCabinet::add(
newReactor(type, SolutionCabinet::at(n), name));
} catch (...) { } catch (...) {
return handleAllExceptions(-1, ERR); return handleAllExceptions(-1, ERR);
} }
@ -60,6 +59,16 @@ extern "C" {
} }
} }
int reactor_type(int i, int len, char* nbuf)
{
try {
return static_cast<int>(
copyString(ReactorCabinet::at(i)->type(), nbuf, len));
} catch (...) {
return handleAllExceptions(-1, ERR);
}
}
int reactor_name(int i, int len, char* nbuf) int reactor_name(int i, int len, char* nbuf)
{ {
try { try {
@ -90,16 +99,6 @@ extern "C" {
} }
} }
int reactor_setSolution(int i, int n)
{
try {
ReactorCabinet::as<Reactor>(i)->setSolution(SolutionCabinet::at(n));
return 0;
} catch (...) {
return handleAllExceptions(-1, ERR);
}
}
double reactor_mass(int i) double reactor_mass(int i)
{ {
try { try {
@ -348,67 +347,67 @@ extern "C" {
} }
} }
// flow devices // connectors
int flowdev_new(const char* type, const char* name) int connector_new(const char* type, int n, int m, const char* name)
{ {
try { try {
return FlowDeviceCabinet::add(newFlowDevice(type, name));
return ConnectorCabinet::add(
newConnectorNode(type,
ReactorCabinet::at(n), ReactorCabinet::at(m), name));
} catch (...) { } catch (...) {
return handleAllExceptions(-1, ERR); return handleAllExceptions(-1, ERR);
} }
} }
int flowdev_del(int i) int connector_del(int i)
{ {
try { try {
FlowDeviceCabinet::del(i); ConnectorCabinet::del(i);
return 0; return 0;
} catch (...) { } catch (...) {
return handleAllExceptions(-1, ERR); return handleAllExceptions(-1, ERR);
} }
} }
int flowdev_name(int i, int len, char* nbuf) int connector_type(int i, int len, char* nbuf)
{ {
try { try {
return static_cast<int>( return static_cast<int>(
copyString(FlowDeviceCabinet::at(i)->name(), nbuf, len)); copyString(ConnectorCabinet::at(i)->type(), nbuf, len));
} catch (...) { } catch (...) {
return handleAllExceptions(-1, ERR); return handleAllExceptions(-1, ERR);
} }
} }
int flowdev_setName(int i, const char* name) int connector_name(int i, int len, char* nbuf)
{ {
try { try {
FlowDeviceCabinet::at(i)->setName(name); return static_cast<int>(
copyString(ConnectorCabinet::at(i)->name(), nbuf, len));
} catch (...) {
return handleAllExceptions(-1, ERR);
}
}
int connector_setName(int i, const char* name)
{
try {
ConnectorCabinet::at(i)->setName(name);
return 0; return 0;
} catch (...) { } catch (...) {
return handleAllExceptions(-1, ERR); return handleAllExceptions(-1, ERR);
} }
} }
int flowdev_install(int i, int n, int m) // flow devices
{
try {
bool ok = FlowDeviceCabinet::at(i)->install(*ReactorCabinet::at(n),
*ReactorCabinet::at(m));
if (!ok) {
throw CanteraError("flowdev_install",
"Could not install flow device.");
}
return 0;
} catch (...) {
return handleAllExceptions(-1, ERR);
}
}
int flowdev_setPrimary(int i, int n) int flowdev_setPrimary(int i, int n)
{ {
try { try {
FlowDeviceCabinet::as<PressureController>(i)->setPrimary( ConnectorCabinet::as<PressureController>(i)->setPrimary(
FlowDeviceCabinet::at(n).get()); ConnectorCabinet::as<FlowDevice>(n).get());
return 0; return 0;
} catch (...) { } catch (...) {
return handleAllExceptions(-1, ERR); return handleAllExceptions(-1, ERR);
@ -418,7 +417,7 @@ extern "C" {
double flowdev_massFlowRate(int i) double flowdev_massFlowRate(int i)
{ {
try { try {
return FlowDeviceCabinet::at(i)->massFlowRate(); return ConnectorCabinet::as<FlowDevice>(i)->massFlowRate();
} catch (...) { } catch (...) {
return handleAllExceptions(DERR, DERR); return handleAllExceptions(DERR, DERR);
} }
@ -427,7 +426,7 @@ extern "C" {
int flowdev_setMassFlowCoeff(int i, double v) int flowdev_setMassFlowCoeff(int i, double v)
{ {
try { try {
FlowDeviceCabinet::as<MassFlowController>(i)->setMassFlowCoeff(v); ConnectorCabinet::as<MassFlowController>(i)->setMassFlowCoeff(v);
return 0; return 0;
} catch (...) { } catch (...) {
return handleAllExceptions(-1, ERR); return handleAllExceptions(-1, ERR);
@ -437,7 +436,7 @@ extern "C" {
int flowdev_setValveCoeff(int i, double v) int flowdev_setValveCoeff(int i, double v)
{ {
try { try {
FlowDeviceCabinet::as<Valve>(i)->setValveCoeff(v); ConnectorCabinet::as<Valve>(i)->setValveCoeff(v);
return 0; return 0;
} catch (...) { } catch (...) {
return handleAllExceptions(-1, ERR); return handleAllExceptions(-1, ERR);
@ -447,7 +446,7 @@ extern "C" {
int flowdev_setPressureCoeff(int i, double v) int flowdev_setPressureCoeff(int i, double v)
{ {
try { try {
FlowDeviceCabinet::as<PressureController>(i)->setPressureCoeff(v); ConnectorCabinet::as<PressureController>(i)->setPressureCoeff(v);
return 0; return 0;
} catch (...) { } catch (...) {
return handleAllExceptions(-1, ERR); return handleAllExceptions(-1, ERR);
@ -457,7 +456,8 @@ extern "C" {
int flowdev_setPressureFunction(int i, int n) int flowdev_setPressureFunction(int i, int n)
{ {
try { try {
FlowDeviceCabinet::at(i)->setPressureFunction(FuncCabinet::at(n).get()); ConnectorCabinet::as<FlowDevice>(i)->setPressureFunction(
FuncCabinet::at(n).get());
return 0; return 0;
} catch (...) { } catch (...) {
return handleAllExceptions(-1, ERR); return handleAllExceptions(-1, ERR);
@ -467,7 +467,8 @@ extern "C" {
int flowdev_setTimeFunction(int i, int n) int flowdev_setTimeFunction(int i, int n)
{ {
try { try {
FlowDeviceCabinet::at(i)->setTimeFunction(FuncCabinet::at(n).get()); ConnectorCabinet::as<FlowDevice>(i)->setTimeFunction(
FuncCabinet::at(n).get());
return 0; return 0;
} catch (...) { } catch (...) {
return handleAllExceptions(-1, ERR); return handleAllExceptions(-1, ERR);
@ -476,60 +477,10 @@ extern "C" {
///////////// Walls /////////////////////// ///////////// Walls ///////////////////////
int wall_new(const char* type, const char* name)
{
try {
return WallCabinet::add(newWall(type, name));
} catch (...) {
return handleAllExceptions(-1, ERR);
}
}
int wall_del(int i)
{
try {
WallCabinet::del(i);
return 0;
} catch (...) {
return handleAllExceptions(-1, ERR);
}
}
int wall_name(int i, int len, char* nbuf)
{
try {
return static_cast<int>(
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 {
WallCabinet::at(i)->install(*ReactorCabinet::at(n),
*ReactorCabinet::at(m));
return 0;
} catch (...) {
return handleAllExceptions(-1, ERR);
}
}
double wall_expansionRate(int i) double wall_expansionRate(int i)
{ {
try { try {
return WallCabinet::at(i)->expansionRate(); return ConnectorCabinet::as<Wall>(i)->expansionRate();
} catch (...) { } catch (...) {
return handleAllExceptions(DERR, DERR); return handleAllExceptions(DERR, DERR);
} }
@ -538,7 +489,7 @@ extern "C" {
double wall_heatRate(int i) double wall_heatRate(int i)
{ {
try { try {
return WallCabinet::at(i)->heatRate(); return ConnectorCabinet::as<Wall>(i)->heatRate();
} catch (...) { } catch (...) {
return handleAllExceptions(DERR, DERR); return handleAllExceptions(DERR, DERR);
} }
@ -547,7 +498,7 @@ extern "C" {
double wall_area(int i) double wall_area(int i)
{ {
try { try {
return WallCabinet::at(i)->area(); return ConnectorCabinet::as<Wall>(i)->area();
} catch (...) { } catch (...) {
return handleAllExceptions(DERR, DERR); return handleAllExceptions(DERR, DERR);
} }
@ -556,7 +507,7 @@ extern "C" {
int wall_setArea(int i, double v) int wall_setArea(int i, double v)
{ {
try { try {
WallCabinet::at(i)->setArea(v); ConnectorCabinet::as<Wall>(i)->setArea(v);
return 0; return 0;
} catch (...) { } catch (...) {
return handleAllExceptions(-1, ERR); return handleAllExceptions(-1, ERR);
@ -566,7 +517,7 @@ extern "C" {
int wall_setThermalResistance(int i, double rth) int wall_setThermalResistance(int i, double rth)
{ {
try { try {
WallCabinet::as<Wall>(i)->setThermalResistance(rth); ConnectorCabinet::as<Wall>(i)->setThermalResistance(rth);
return 0; return 0;
} catch (...) { } catch (...) {
return handleAllExceptions(-1, ERR); return handleAllExceptions(-1, ERR);
@ -576,7 +527,7 @@ extern "C" {
int wall_setHeatTransferCoeff(int i, double u) int wall_setHeatTransferCoeff(int i, double u)
{ {
try { try {
WallCabinet::as<Wall>(i)->setHeatTransferCoeff(u); ConnectorCabinet::as<Wall>(i)->setHeatTransferCoeff(u);
return 0; return 0;
} catch (...) { } catch (...) {
return handleAllExceptions(-1, ERR); return handleAllExceptions(-1, ERR);
@ -586,7 +537,7 @@ extern "C" {
int wall_setHeatFlux(int i, int n) int wall_setHeatFlux(int i, int n)
{ {
try { try {
WallCabinet::as<Wall>(i)->setHeatFlux(FuncCabinet::at(n).get()); ConnectorCabinet::as<Wall>(i)->setHeatFlux(FuncCabinet::at(n).get());
return 0; return 0;
} catch (...) { } catch (...) {
return handleAllExceptions(-1, ERR); return handleAllExceptions(-1, ERR);
@ -596,7 +547,7 @@ extern "C" {
int wall_setExpansionRateCoeff(int i, double k) int wall_setExpansionRateCoeff(int i, double k)
{ {
try { try {
WallCabinet::as<Wall>(i)->setExpansionRateCoeff(k); ConnectorCabinet::as<Wall>(i)->setExpansionRateCoeff(k);
return 0; return 0;
} catch (...) { } catch (...) {
return handleAllExceptions(-1, ERR); return handleAllExceptions(-1, ERR);
@ -606,7 +557,7 @@ extern "C" {
int wall_setVelocity(int i, int n) int wall_setVelocity(int i, int n)
{ {
try { try {
WallCabinet::as<Wall>(i)->setVelocity(FuncCabinet::at(n).get()); ConnectorCabinet::as<Wall>(i)->setVelocity(FuncCabinet::at(n).get());
return 0; return 0;
} catch (...) { } catch (...) {
return handleAllExceptions(-1, ERR); return handleAllExceptions(-1, ERR);
@ -616,22 +567,13 @@ extern "C" {
int wall_setEmissivity(int i, double epsilon) int wall_setEmissivity(int i, double epsilon)
{ {
try { try {
WallCabinet::as<Wall>(i)->setEmissivity(epsilon); ConnectorCabinet::as<Wall>(i)->setEmissivity(epsilon);
return 0; return 0;
} catch (...) { } catch (...) {
return handleAllExceptions(-1, ERR); return handleAllExceptions(-1, ERR);
} }
} }
int wall_ready(int i)
{
try {
return int(WallCabinet::at(i)->ready());
} catch (...) {
return handleAllExceptions(-1, ERR);
}
}
// ReactorSurface // ReactorSurface
int reactorsurface_new(const char* name) int reactorsurface_new(const char* name)
@ -727,8 +669,7 @@ extern "C" {
try { try {
ReactorCabinet::clear(); ReactorCabinet::clear();
NetworkCabinet::clear(); NetworkCabinet::clear();
FlowDeviceCabinet::clear(); ConnectorCabinet::clear();
WallCabinet::clear();
ReactorSurfaceCabinet::clear(); ReactorSurfaceCabinet::clear();
return 0; return 0;
} catch (...) { } catch (...) {

View File

@ -0,0 +1,95 @@
//! @file ConnectorFactory.cpp
// This file is part of Cantera. See License.txt in the top-level directory or
// at https://cantera.org/license.txt for license and copyright information.
#include "cantera/zeroD/ConnectorFactory.h"
#include "cantera/zeroD/FlowDevice.h"
#include "cantera/zeroD/flowControllers.h"
#include "cantera/zeroD/Wall.h"
namespace Cantera
{
ConnectorFactory* ConnectorFactory::s_factory = 0;
std::mutex ConnectorFactory::connector_mutex;
ConnectorFactory::ConnectorFactory()
{
reg("MassFlowController",
[](shared_ptr<ReactorBase> r0, shared_ptr<ReactorBase> r1, const string& name)
{ return new MassFlowController(r0, r1, name); });
reg("PressureController",
[](shared_ptr<ReactorBase> r0, shared_ptr<ReactorBase> r1, const string& name)
{ return new PressureController(r0, r1, name); });
reg("Valve",
[](shared_ptr<ReactorBase> r0, shared_ptr<ReactorBase> r1, const string& name)
{ return new Valve(r0, r1, name); });
reg("Wall",
[](shared_ptr<ReactorBase> r0, shared_ptr<ReactorBase> r1, const string& name)
{ return new Wall(r0, r1, name); });
}
ConnectorFactory* ConnectorFactory::factory() {
std::unique_lock<std::mutex> lock(connector_mutex);
if (!s_factory) {
s_factory = new ConnectorFactory;
}
return s_factory;
}
void ConnectorFactory::deleteFactory() {
std::unique_lock<std::mutex> lock(connector_mutex);
delete s_factory;
s_factory = 0;
}
shared_ptr<ConnectorNode> newConnectorNode(
const string& model,
shared_ptr<ReactorBase> r0, shared_ptr<ReactorBase> r1, const string& name)
{
return shared_ptr<ConnectorNode>(
ConnectorFactory::factory()->create(model, r0, r1, name));
}
shared_ptr<FlowDevice> newFlowDevice(
const string& model,
shared_ptr<ReactorBase> r0, shared_ptr<ReactorBase> r1, const string& name)
{
auto dev = std::dynamic_pointer_cast<FlowDevice>(
newConnectorNode(model, r0, r1, name));
if (!dev) {
throw CanteraError("newFlowDevice",
"Detected incompatible ConnectorNode type '{}'", model);
}
return dev;
}
shared_ptr<FlowDevice> newFlowDevice(const string& model, const string& name)
{
warn_deprecated("newFlowDevice",
"After Cantera 3.1, Reactors must be provided as parameters.");
return newFlowDevice(model, nullptr, nullptr, name);
}
shared_ptr<WallBase> newWall(
const string& model,
shared_ptr<ReactorBase> r0, shared_ptr<ReactorBase> r1, const string& name)
{
auto wall = std::dynamic_pointer_cast<WallBase>(
newConnectorNode(model, r0, r1, name));
if (!wall) {
throw CanteraError("newWall",
"Detected incompatible ConnectorNode type '{}'", model);
}
return wall;
}
shared_ptr<WallBase> newWall(const string& model, const string& name)
{
warn_deprecated("newWall",
"After Cantera 3.1, Reactors must be provided as parameters.");
return newWall(model, nullptr, nullptr, name);
}
}

View File

@ -0,0 +1,25 @@
//! @file ConnectorNode.cpp
// This file is part of Cantera. See License.txt in the top-level directory or
// at https://cantera.org/license.txt for license and copyright information.
#include "cantera/zeroD/ConnectorNode.h"
#include "cantera/zeroD/ReactorBase.h"
namespace Cantera
{
void ConnectorNode::setDefaultName(map<string, int>& counts)
{
if (m_defaultNameSet) {
return;
}
m_defaultNameSet = true;
string typ(type());
if (m_name == "(none)" || m_name == "") {
m_name = fmt::format("{}_{}", type(), counts[type()]);
}
counts[type()]++;
}
}

View File

@ -11,22 +11,45 @@
namespace Cantera namespace Cantera
{ {
bool FlowDevice::setDefaultName(map<string, int>& counts) FlowDevice::FlowDevice(shared_ptr<ReactorBase> r0, shared_ptr<ReactorBase> r1,
const string& name) : ConnectorNode(r0, r1, name)
{ {
if (m_defaultNameSet) { if (!m_nodes.first || !m_nodes.second) {
return false; warn_deprecated("FlowDevice::FlowDevice",
"After Cantera 3.1, Reactors must be provided to a FlowDevice "
"constructor.");
return;
} }
m_defaultNameSet = true; m_in = r0.get();
string typ(type()); m_out = r1.get();
if (m_name == "(none)" || m_name == "") { m_in->addOutlet(*this);
m_name = fmt::format("{}_{}", type(), counts[type()]); m_out->addInlet(*this);
// construct adapters between inlet and outlet species
const ThermoPhase& mixin = m_in->contents();
const ThermoPhase& mixout = m_out->contents();
m_nspin = mixin.nSpecies();
m_nspout = mixout.nSpecies();
string nm;
size_t ki, ko;
for (ki = 0; ki < m_nspin; ki++) {
nm = mixin.speciesName(ki);
ko = mixout.speciesIndex(nm);
m_in2out.push_back(ko);
}
for (ko = 0; ko < m_nspout; ko++) {
nm = mixout.speciesName(ko);
ki = mixin.speciesIndex(nm);
m_out2in.push_back(ki);
} }
counts[type()]++;
return true;
} }
bool FlowDevice::install(ReactorBase& in, ReactorBase& out) bool FlowDevice::install(ReactorBase& in, ReactorBase& out)
{ {
warn_deprecated("FlowDevice::install",
"To be removed after Cantera 3.1. Reactors should be provided to constructor "
"instead.");
if (m_in || m_out) { if (m_in || m_out) {
throw CanteraError("FlowDevice::install", "Already installed"); throw CanteraError("FlowDevice::install", "Already installed");
} }

View File

@ -1,47 +0,0 @@
//! @file FlowDeviceFactory.cpp
// This file is part of Cantera. See License.txt in the top-level directory or
// at https://cantera.org/license.txt for license and copyright information.
#include "cantera/zeroD/FlowDeviceFactory.h"
#include "cantera/zeroD/flowControllers.h"
namespace Cantera
{
FlowDeviceFactory* FlowDeviceFactory::s_factory = 0;
std::mutex FlowDeviceFactory::flowDevice_mutex;
FlowDeviceFactory::FlowDeviceFactory()
{
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() {
std::unique_lock<std::mutex> lock(flowDevice_mutex);
if (!s_factory) {
s_factory = new FlowDeviceFactory;
}
return s_factory;
}
void FlowDeviceFactory::deleteFactory() {
std::unique_lock<std::mutex> lock(flowDevice_mutex);
delete s_factory;
s_factory = 0;
}
shared_ptr<FlowDevice> newFlowDevice(const string& model, const string& name)
{
return shared_ptr<FlowDevice>(FlowDeviceFactory::factory()->create(model, name));
}
}

View File

@ -23,14 +23,8 @@ namespace Cantera
{ {
Reactor::Reactor(shared_ptr<Solution> sol, const string& name) Reactor::Reactor(shared_ptr<Solution> sol, const string& name)
: ReactorBase(name) : ReactorBase(sol, name)
{ {
if (!sol || !(sol->thermo())) {
throw CanteraError("Reactor::Reactor",
"Reactor contents must be provided as constructor arguments");
}
setSolution(sol);
setThermo(*sol->thermo());
setKinetics(*sol->kinetics()); setKinetics(*sol->kinetics());
} }

View File

@ -24,7 +24,14 @@ ReactorBase::ReactorBase(shared_ptr<Solution> sol, const string& name)
throw CanteraError("ReactorBase::ReactorBase", throw CanteraError("ReactorBase::ReactorBase",
"Missing or incomplete Solution object."); "Missing or incomplete Solution object.");
} }
setSolution(sol); m_solution = sol;
setThermo(*sol->thermo());
try {
setKinetics(*sol->kinetics());
} catch (NotImplementedError&) {
// kinetics not used (example: Reservoir)
}
m_solution->thermo()->addSpeciesLock();
} }
ReactorBase::~ReactorBase() ReactorBase::~ReactorBase()
@ -47,7 +54,11 @@ bool ReactorBase::setDefaultName(map<string, int>& counts)
return true; return true;
} }
void ReactorBase::setSolution(shared_ptr<Solution> sol) { void ReactorBase::setSolution(shared_ptr<Solution> sol)
{
warn_deprecated("ReactorBase::setSolution",
"After Cantera 3.2, a change of reactor contents after instantiation "
"will be disabled.");
if (!sol || !(sol->thermo())) { if (!sol || !(sol->thermo())) {
throw CanteraError("ReactorBase::setSolution", throw CanteraError("ReactorBase::setSolution",
"Missing or incomplete Solution object."); "Missing or incomplete Solution object.");

View File

@ -10,21 +10,26 @@
namespace Cantera namespace Cantera
{ {
bool WallBase::setDefaultName(map<string, int>& counts) WallBase::WallBase(shared_ptr<ReactorBase> r0, shared_ptr<ReactorBase> r1,
const string& name) : ConnectorNode(r0, r1, name)
{ {
if (m_defaultNameSet) { if (!m_nodes.first || !m_nodes.second) {
return false; warn_deprecated("FlowDevice::FlowDevice",
"After Cantera 3.2, Reactors must be provided to a FlowDevice "
"constructor.");
return;
} }
m_defaultNameSet = true; m_left = r0.get();
if (m_name == "(none)" || m_name == "") { m_right = r1.get();
m_name = fmt::format("{}_{}", type(), counts[type()]); m_left->addWall(*this, 0);
} m_right->addWall(*this, 1);
counts[type()]++;
return true;
} }
bool WallBase::install(ReactorBase& rleft, ReactorBase& rright) bool WallBase::install(ReactorBase& rleft, ReactorBase& rright)
{ {
warn_deprecated("WallBase::install",
"To be removed after Cantera 3.2. Reactors should be provided to constructor "
"instead.");
// check if wall is already installed // check if wall is already installed
if (m_left || m_right) { if (m_left || m_right) {
return false; return false;

View File

@ -1,39 +0,0 @@
//! @file WallFactory.cpp
// This file is part of Cantera. See License.txt in the top-level directory or
// at https://cantera.org/license.txt for license and copyright information.
#include "cantera/zeroD/WallFactory.h"
#include "cantera/zeroD/Wall.h"
namespace Cantera
{
WallFactory* WallFactory::s_factory = 0;
std::mutex WallFactory::wall_mutex;
WallFactory::WallFactory()
{
reg("Wall", [](const string& name) { return new Wall(name); });
}
WallFactory* WallFactory::factory() {
std::unique_lock<std::mutex> lock(wall_mutex);
if (!s_factory) {
s_factory = new WallFactory;
}
return s_factory;
}
void WallFactory::deleteFactory() {
std::unique_lock<std::mutex> lock(wall_mutex);
delete s_factory;
s_factory = 0;
}
shared_ptr<WallBase> newWall(const string& model, const string& name)
{
return shared_ptr<WallBase>(WallFactory::factory()->create(model, name));
}
}

View File

@ -728,13 +728,6 @@ class TestReactor:
assert self.r1.name.startswith(f"{self.r1.type}_") # default name assert self.r1.name.startswith(f"{self.r1.type}_") # default name
assert res.name.startswith(f"{res.type}_") # default name assert res.name.startswith(f"{res.type}_") # default name
def test_valve_errors(self):
self.make_reactors()
v = ct.Valve(self.r1, self.r2)
with pytest.raises(ct.CanteraError, match='Already installed'):
# inlet and outlet cannot be reassigned
v._install(self.r2, self.r1)
def test_pressure_controller1(self): def test_pressure_controller1(self):
self.make_reactors(n_reactors=1) self.make_reactors(n_reactors=1)
g = ct.Solution('h2o2.yaml', transport_model=None) g = ct.Solution('h2o2.yaml', transport_model=None)

View File

@ -19,16 +19,16 @@ TEST(zerodim, simple)
auto sol = newSolution("gri30.yaml", "gri30", "none"); auto sol = newSolution("gri30.yaml", "gri30", "none");
sol->thermo()->setState_TPX(T, P, X); sol->thermo()->setState_TPX(T, P, X);
auto cppReactor = newReactor("IdealGasReactor", sol, "simple"); auto reactor = newReactor("IdealGasReactor", sol, "simple");
ASSERT_EQ(cppReactor->name(), "simple"); ASSERT_EQ(reactor->name(), "simple");
cppReactor->initialize(); reactor->initialize();
ReactorNet network; ReactorNet network;
network.addReactor(dynamic_cast<IdealGasReactor&>(*cppReactor)); network.addReactor(dynamic_cast<IdealGasReactor&>(*reactor));
network.initialize(); network.initialize();
double t = 0.0; double t = 0.0;
while (t < 0.1) { while (t < 0.1) {
ASSERT_GE(cppReactor->temperature(), T); ASSERT_GE(reactor->temperature(), T);
t = network.time() + 5e-3; t = network.time() + 5e-3;
network.advance(t); network.advance(t);
} }
@ -56,6 +56,97 @@ TEST(zerodim, test_guards)
EXPECT_THROW(Valve().updateMassFlowRate(0.), CanteraError); EXPECT_THROW(Valve().updateMassFlowRate(0.), CanteraError);
} }
TEST(zerodim, flowdevice)
{
auto gas = newSolution("gri30.yaml", "gri30", "none");
auto node0 = newReactor("IdealGasReactor", gas, "upstream");
auto node1 = newReactor("IdealGasReactor", gas, "downstream");
auto valve = newFlowDevice("Valve", node0, node1, "valve");
ASSERT_EQ(valve->name(), "valve");
ASSERT_EQ(valve->in().name(), "upstream");
ASSERT_EQ(valve->out().name(), "downstream");
ASSERT_EQ(node0->nInlets(), 0);
ASSERT_EQ(node0->nOutlets(), 1);
ASSERT_EQ(node1->nInlets(), 1);
ASSERT_EQ(node1->nOutlets(), 0);
}
TEST(zerodim, wall)
{
auto gas = newSolution("gri30.yaml", "gri30", "none");
auto node0 = newReactor("IdealGasReactor", gas, "left");
auto node1 = newReactor("IdealGasReactor", gas, "right");
auto wall = newWall("Wall", node0, node1, "wall");
ASSERT_EQ(wall->name(), "wall");
ASSERT_EQ(wall->left().name(), "left");
ASSERT_EQ(wall->right().name(), "right");
ASSERT_EQ(node0->nWalls(), 1);
ASSERT_EQ(node1->nWalls(), 1);
}
TEST(zerodim, mole_reactor)
{
// simplified version of continuous_reactor.py
auto gas = newSolution("h2o2.yaml", "ohmech", "none");
auto tank = make_shared<Reservoir>(gas, "fuel-air-tank");
auto exhaust = make_shared<Reservoir>(gas, "exhaust");
auto stirred = make_shared<IdealGasMoleReactor>(gas, "stirred-reactor");
stirred->setEnergy(0);
stirred->setInitialVolume(30.5 * 1e-6);
auto mfc = make_shared<MassFlowController>(tank, stirred, "mass-flow-controller");
double residenceTime = 2.;
double mass = stirred->mass();
mfc->setMassFlowRate(mass/residenceTime);
auto preg = make_shared<PressureController>(stirred, exhaust, "pressure-regulator");
preg->setPrimary(mfc.get());
preg->setPressureCoeff(1e-3);
auto net = ReactorNet();
net.addReactor(*stirred);
net.initialize();
}
TEST(zerodim, mole_reactor_2)
{
// simplified version of continuous_reactor.py
auto gas = newSolution("h2o2.yaml", "ohmech", "none");
auto tank = std::dynamic_pointer_cast<Reservoir>(
newReactor("Reservoir", gas, "fuel-air-tank"));
auto exhaust = std::dynamic_pointer_cast<Reservoir>(
newReactor("Reservoir", gas, "exhaust"));
auto stirred = std::dynamic_pointer_cast<IdealGasMoleReactor>(
newReactor("IdealGasMoleReactor", gas, "stirred-reactor"));
stirred->setEnergy(0);
stirred->setInitialVolume(30.5 * 1e-6);
auto mfc = std::dynamic_pointer_cast<MassFlowController>(
newConnectorNode("MassFlowController", tank, stirred, "mass-flow-controller"));
double residenceTime = 2.;
double mass = stirred->mass();
mfc->setMassFlowRate(mass/residenceTime);
auto preg = std::dynamic_pointer_cast<PressureController>(
newConnectorNode("PressureController", stirred, exhaust, "pressure-regulator"));
preg->setPrimary(mfc.get());
preg->setPressureCoeff(1e-3);
auto net = ReactorNet();
net.addReactor(*stirred);
net.initialize();
}
// This test ensures that prior reactor initialization of a reactor does // This test ensures that prior reactor initialization of a reactor does
// not affect later integration within a network. This example was // not affect later integration within a network. This example was
// adapted from test_reactor.py::test_equilibrium_HP. // adapted from test_reactor.py::test_equilibrium_HP.