Skip to content

Commit 4e04870

Browse files
committed
[Reactor] Implement ExtensibleReactorSurface
1 parent 3ff7887 commit 4e04870

File tree

12 files changed

+179
-44
lines changed

12 files changed

+179
-44
lines changed

doc/sphinx/python/zerodim.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,14 @@ ReactorSurface
123123
^^^^^^^^^^^^^^
124124
.. autoclass:: ReactorSurface(phase, r=None, clone=None, name="(none)", *, A=None)
125125

126+
ExtensibleReactorSurface
127+
^^^^^^^^^^^^^^^^^^^^^^^^
128+
.. autoclass:: ExtensibleReactorSurface(phase, r=None, clone=None, name="(none)", *, A=None)
129+
130+
ExtensibleMoleReactorSurface
131+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
132+
.. autoclass:: ExtensibleMoleReactorSurface(phase, r=None, clone=None, name="(none)", *, A=None)
133+
126134
Flow Controllers
127135
----------------
128136

include/cantera/zeroD/Reactor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ class Reactor : public ReactorBase
140140
//! Evaluate terms related to Walls. Calculates #m_vdot and #m_Qdot based on
141141
//! wall movement and heat transfer.
142142
//! @param t the current time
143-
virtual void evalWalls(double t);
143+
void evalWalls(double t) override;
144144

145145
//! Pointer to the homogeneous Kinetics object that handles the reactions
146146
Kinetics* m_kin = nullptr;

include/cantera/zeroD/ReactorBase.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,12 @@ class ReactorBase : public std::enable_shared_from_this<ReactorBase>
125125
"Area is undefined for reactors of type '{}'.", type());
126126
}
127127

128+
//! Evaluate contributions from walls connected to this reactor
129+
virtual void evalWalls(double t) {
130+
throw NotImplementedError("ReactorBase::evalWalls",
131+
"Wall evaluation is undefined for reactors of type '{}'.", type());
132+
}
133+
128134
//! Set an area associated with a reactor [m²].
129135
//! Examples: surface area of ReactorSurface or cross section area of FlowReactor.
130136
virtual void setArea(double a) {
@@ -213,6 +219,18 @@ class ReactorBase : public std::enable_shared_from_this<ReactorBase>
213219
return m_surfaces.size();
214220
}
215221

222+
//! Production rates on surfaces.
223+
//!
224+
//! For bulk reactors, this contains the total production rates [kmol/s] of bulk
225+
//! phase species due to reactions on all adjacent species.
226+
//!
227+
//! For surfaces, this contains the production rates [kmol/m²/s] of species on the
228+
//! surface and all adjacent phases, in the order defined by the InterfaceKinetics
229+
//! object.
230+
const vector<double>& surfaceProductionRates() const {
231+
return m_sdot;
232+
}
233+
216234
/**
217235
* Initialize the reactor. Called automatically by ReactorNet::initialize.
218236
*/
@@ -482,6 +500,7 @@ class ReactorBase : public std::enable_shared_from_this<ReactorBase>
482500

483501
vector<WallBase*> m_wall;
484502
vector<ReactorSurface*> m_surfaces;
503+
vector<double> m_sdot; //!< species production rates on surfaces
485504

486505
//! Vector of length nWalls(), indicating whether this reactor is on the left (0)
487506
//! or right (1) of each wall.

include/cantera/zeroD/ReactorDelegator.h

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ class ReactorAccessor
4444
//! by Reactor::eval, this method should be called in either a "replace" or "after"
4545
//! delegate for Reactor::evalWalls().
4646
virtual void setHeatRate(double q) = 0;
47+
48+
//! @copydoc ReactorBase::surfaceProductionRates
49+
virtual vector<double>& surfaceProductionRates() = 0;
4750
};
4851

4952
//! Delegate methods of the Reactor class to external functions
@@ -52,8 +55,9 @@ template <class R>
5255
class ReactorDelegator : public Delegator, public R, public ReactorAccessor
5356
{
5457
public:
55-
ReactorDelegator(shared_ptr<Solution> phase, bool clone, const string& name="(none)")
56-
: R(phase, clone, name)
58+
template <class... Args>
59+
ReactorDelegator(Args&&... args)
60+
: R(std::forward<Args>(args)...)
5761
{
5862
install("initialize", m_initialize, [this](double t0) { R::initialize(t0); });
5963
install("getState", m_getState,
@@ -67,7 +71,9 @@ class ReactorDelegator : public Delegator, public R, public ReactorAccessor
6771
R::eval(t, LHS, RHS);
6872
}
6973
);
70-
install("evalWalls", m_evalWalls, [this](double t) { R::evalWalls(t); });
74+
if constexpr (std::is_base_of<Reactor, R>::value) {
75+
install("evalWalls", m_evalWalls, [this](double t) { R::evalWalls(t); });
76+
}
7177
install("componentName", m_componentName,
7278
[this](size_t k) { return R::componentName(k); });
7379
install("componentIndex", m_componentIndex,
@@ -104,7 +110,11 @@ class ReactorDelegator : public Delegator, public R, public ReactorAccessor
104110
}
105111

106112
void evalWalls(double t) override {
107-
m_evalWalls(t);
113+
if constexpr (std::is_base_of<Reactor, R>::value) {
114+
m_evalWalls(t);
115+
} else {
116+
ReactorBase::evalWalls(t);
117+
}
108118
}
109119

110120
string componentName(size_t k) override {
@@ -122,19 +132,43 @@ class ReactorDelegator : public Delegator, public R, public ReactorAccessor
122132
}
123133

124134
double expansionRate() const override {
125-
return R::m_vdot;
135+
if constexpr (std::is_base_of<Reactor, R>::value) {
136+
return R::m_vdot;
137+
} else {
138+
throw NotImplementedError("ReactorDelegator::expansionRate",
139+
"Expansion rate is undefined for reactors of type '{}'.", type());
140+
}
126141
}
127142

128143
void setExpansionRate(double v) override {
129-
R::m_vdot = v;
144+
if constexpr (std::is_base_of<Reactor, R>::value) {
145+
R::m_vdot = v;
146+
} else {
147+
throw NotImplementedError("ReactorDelegator::setExpansionRate",
148+
"Expansion rate is undefined for reactors of type '{}'.", type());
149+
}
130150
}
131151

132152
double heatRate() const override {
133-
return R::m_Qdot;
153+
if constexpr (std::is_base_of<Reactor, R>::value) {
154+
return R::m_Qdot;
155+
} else {
156+
throw NotImplementedError("ReactorDelegator::heatRate",
157+
"Heat rate is undefined for reactors of type '{}'.", type());
158+
}
134159
}
135160

136161
void setHeatRate(double q) override {
137-
R::m_Qdot = q;
162+
if constexpr (std::is_base_of<Reactor, R>::value) {
163+
R::m_Qdot = q;
164+
} else {
165+
throw NotImplementedError("ReactorDelegator::setHeatRate",
166+
"Heat rate is undefined for reactors of type '{}'.", type());
167+
}
168+
}
169+
170+
vector<double>& surfaceProductionRates() override {
171+
return R::m_sdot;
138172
}
139173

140174
private:

include/cantera/zeroD/ReactorSurface.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,6 @@ class ReactorSurface : public ReactorBase
9191
//! number of surface species.
9292
void getCoverages(double* cov) const;
9393

94-
const vector<double>& netProductionRates() const {
95-
return m_sdot;
96-
}
97-
9894
void getState(double* y) override;
9995
void initialize(double t0=0.0) override;
10096
void updateState(double* y) override;
@@ -120,7 +116,6 @@ class ReactorSurface : public ReactorBase
120116
shared_ptr<SurfPhase> m_surf;
121117
shared_ptr<InterfaceKinetics> m_kinetics;
122118
vector<ReactorBase*> m_reactors;
123-
vector<double> m_sdot; //!< species production rates for all phases
124119
};
125120

126121
//! A surface where the state variables are the total number of moles of each species.

interfaces/cython/cantera/reactor.pxd

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ cdef extern from "cantera/zeroD/ReactorDelegator.h" namespace "Cantera":
216216
void setExpansionRate(double)
217217
double heatRate()
218218
void setHeatRate(double)
219+
vector[double]& surfaceProductionRates()
219220

220221

221222
ctypedef CxxReactorAccessor* CxxReactorAccessorPtr
@@ -272,6 +273,11 @@ cdef class FlowReactor(Reactor):
272273
cdef class ExtensibleReactor(Reactor):
273274
cdef public _delegates
274275
cdef CxxReactorAccessor* accessor
276+
cdef public double[:] surface_production_rates
277+
"""
278+
An array containing the total production rates [kmol/s] of bulk species on
279+
surfaces. Updated from adjacent surfaces as part of ``Reactor.eval``.
280+
"""
275281

276282
cdef class ReactorSurface(ReactorBase):
277283
cdef CxxReactorSurface* surface
@@ -280,6 +286,15 @@ cdef class ReactorSurface(ReactorBase):
280286
cdef class FlowReactorSurface(ReactorSurface):
281287
pass
282288

289+
cdef class ExtensibleReactorSurface(ReactorSurface):
290+
cdef public _delegates
291+
cdef public double[:] surface_production_rates
292+
"""
293+
An array containing the net production rates [kmol/m²/s] of surface and bulk species
294+
on the surface, with the order corresponding to the `InterfaceKinetics` object.
295+
Updated as part of ``ReactorSurface.update_state``.
296+
"""
297+
283298
cdef class ConnectorNode:
284299
cdef shared_ptr[CxxConnectorNode] _node
285300
cdef CxxConnectorNode* node

interfaces/cython/cantera/reactor.pyx

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,9 @@ cdef class ExtensibleReactor(Reactor):
567567

568568
def __cinit__(self, *args, **kwargs):
569569
self.accessor = dynamic_cast[CxxReactorAccessorPtr](self.rbase)
570+
cdef vector[double]* sdot = \
571+
&dynamic_cast[CxxReactorAccessorPtr](self.rbase).surfaceProductionRates()
572+
self.surface_production_rates = <double[:sdot.size()]> sdot.data()
570573

571574
def __init__(self, *args, **kwargs):
572575
assign_delegates(self, dynamic_cast[CxxDelegatorPtr](self.rbase))
@@ -728,6 +731,9 @@ cdef class ReactorSurface(ReactorBase):
728731
raise TypeError("Parameter 'r' should be a ReactorBase object or a list "
729732
"of ReactorBase objects.")
730733

734+
if kind is None and self.reactor_type != "ReactorSurface":
735+
kind = self.reactor_type
736+
731737
if kind is not None:
732738
self._rbase = CxxNewReactorSurface(stringify(kind), phase._base, cxx_adj,
733739
clone, stringify(name))
@@ -893,6 +899,58 @@ cdef class FlowReactorSurface(ReactorSurface):
893899
(<CxxFlowReactorSurface*>self.surface).setInitialMaxErrorFailures(nsteps)
894900

895901

902+
cdef class ExtensibleReactorSurface(ReactorSurface):
903+
"""
904+
A base class for a reactor surface with delegated methods where the base
905+
functionality corresponds to the `ReactorSurface` class.
906+
907+
Methods of the base class can be modified in the same way as in class
908+
`ExtensibleReactor`. The methods that can be modified are::
909+
910+
- ``initialize(self, t0: double) -> None``
911+
- ``get_state(self, y : double[:]) -> None``
912+
- ``update_state(self, y : double[:]) -> None``
913+
- ``eval(self, t : double, LHS : double[:], RHS : double[:]) -> None``
914+
- ``component_name(i : int) -> string``
915+
- ``component_index(name: string) -> int``
916+
"""
917+
918+
reactor_type = "ExtensibleReactorSurface"
919+
920+
delegatable_methods = {
921+
'initialize': ('initialize', 'void(double)'),
922+
'get_state': ('getState', 'void(double*)'),
923+
'update_state': ('updateState', 'void(double*)'),
924+
'eval': ('eval', 'void(double, double*, double*)'),
925+
'component_name': ('componentName', 'string(size_t)'),
926+
'component_index': ('componentIndex', 'size_t(string)'),
927+
}
928+
929+
def __init__(self, *args, **kwargs):
930+
assign_delegates(self, dynamic_cast[CxxDelegatorPtr](self.rbase))
931+
cdef vector[double]* sdot = \
932+
&dynamic_cast[CxxReactorAccessorPtr](self.rbase).surfaceProductionRates()
933+
self.surface_production_rates = <double[:sdot.size()]> sdot.data()
934+
super().__init__(*args, **kwargs)
935+
936+
property n_vars:
937+
"""
938+
Get/Set the number of state variables in the reactor.
939+
"""
940+
def __get__(self):
941+
return self.reactor.neq()
942+
def __set__(self, n):
943+
dynamic_cast[CxxReactorAccessorPtr](self.rbase).setNEq(n)
944+
945+
946+
cdef class ExtensibleMoleReactorSurface(ExtensibleReactorSurface):
947+
"""
948+
A variant of `ExtensibleReactorSurface` where the base behavior corresponds to the
949+
:ct:`MoleReactorSurface` class.
950+
"""
951+
reactor_type = "ExtensibleMoleReactorSurface"
952+
953+
896954
cdef class ConnectorNode:
897955
"""
898956
Common base class for walls and flow devices.

src/zeroD/IdealGasConstPressureMoleReactor.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,6 @@ void IdealGasConstPressureMoleReactor::getJacobianElements(
120120
// double molarVol = m_thermo->molarVolume();
121121
for (int k = 0; k < dnk_dnj.outerSize(); k++) {
122122
for (Eigen::SparseMatrix<double>::InnerIterator it(dnk_dnj, k); it; ++it) {
123-
// gas phase species need the addition of V / N * omega_dot
124-
// if (static_cast<size_t>(it.row()) < m_nsp) {
125-
// it.valueRef() = it.value() + netProductionRates[it.row()] * molarVol;
126-
// }
127123
trips.emplace_back(it.row() + offset, it.col() + offset, it.value());
128124
}
129125
}

src/zeroD/Reactor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ void Reactor::updateSurfaceProductionRates()
293293
{
294294
m_sdot.assign(m_nsp, 0.0);
295295
for (auto& S : m_surfaces) {
296-
const auto& sdot = S->netProductionRates();
296+
const auto& sdot = S->surfaceProductionRates();
297297
size_t offset = S->kinetics()->kineticsSpeciesIndex(m_thermo->speciesName(0));
298298
for (size_t k = 0; k < m_nsp; k++) {
299299
m_sdot[k] += sdot[offset + k] * S->area();

src/zeroD/ReactorFactory.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,18 @@ ReactorSurfaceFactory::ReactorSurfaceFactory()
127127
[](shared_ptr<Solution> surf, const vector<shared_ptr<ReactorBase>>& reactors,
128128
bool clone, const string& name)
129129
{ return new FlowReactorSurface(surf, reactors, clone, name); });
130+
reg("ExtensibleReactorSurface",
131+
[](shared_ptr<Solution> surf, const vector<shared_ptr<ReactorBase>>& reactors,
132+
bool clone, const string& name)
133+
{ return new ReactorDelegator<ReactorSurface>(surf, reactors, clone, name); });
134+
reg("ExtensibleMoleReactorSurface",
135+
[](shared_ptr<Solution> surf, const vector<shared_ptr<ReactorBase>>& reactors,
136+
bool clone, const string& name)
137+
{ return new ReactorDelegator<MoleReactorSurface>(surf, reactors, clone, name); });
138+
reg("ExtensibleFlowReactorSurface",
139+
[](shared_ptr<Solution> surf, const vector<shared_ptr<ReactorBase>>& reactors,
140+
bool clone, const string& name)
141+
{ return new ReactorDelegator<FlowReactorSurface>(surf, reactors, clone, name); });
130142
}
131143

132144
// ---------- free functions ----------

0 commit comments

Comments
 (0)