Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix reactor mass flow rate #886

Merged
merged 3 commits into from
Jul 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion include/cantera/clib/ctreactor.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ extern "C" {
CANTERA_CAPI int flowdev_del(int i);
CANTERA_CAPI int flowdev_install(int i, int n, int m);
CANTERA_CAPI int flowdev_setMaster(int i, int n);
CANTERA_CAPI double flowdev_massFlowRate(int i, double time);
CANTERA_CAPI double flowdev_massFlowRate2(int i);
CANTERA_CAPI double flowdev_massFlowRate(int i, double time); //!< @deprecated To be changed after Cantera 2.5.
CANTERA_CAPI int flowdev_setMassFlowRate(int i, double mdot);
CANTERA_CAPI int flowdev_setParameters(int i, int n, const double* v); //!< @deprecated To be removed after Cantera 2.5.
CANTERA_CAPI int flowdev_setMassFlowCoeff(int i, double v);
Expand Down
14 changes: 13 additions & 1 deletion include/cantera/zeroD/FlowDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "cantera/base/ct_defs.h"
#include "cantera/base/global.h"
#include "cantera/base/stringUtils.h"
#include "cantera/base/ctexceptions.h"

namespace Cantera
{
Expand Down Expand Up @@ -54,11 +55,22 @@ class FlowDevice
}

//! Mass flow rate (kg/s).
//! @deprecated The 'time' argument will be removed after Cantera 2.5.
//! Evaluating the mass flow rate at times other than the current time
//! for the reactor network may lead to subtly incorrect results.
double massFlowRate(double time = -999.0) {
if (time != -999.0) {
warn_deprecated("FlowDevice::massFlowRate", "The 'time' argument"
" is deprecated and will be removed after Cantera 2.5.");
updateMassFlowRate(time);
}
return m_mdot;

if (m_mdot == Undef) {
throw CanteraError("FlowDevice::massFlowRate",
"Flow device is not ready. Try initializing the reactor network.");
} else {
return m_mdot;
}
}

//! Update the mass flow rate at time 'time'. This must be overloaded in
Expand Down
14 changes: 8 additions & 6 deletions include/cantera/zeroD/Reactor.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,6 @@ class Reactor : public ReactorBase
//! @param t the current time
virtual void evalWalls(double t);

//! Evaluate inlet and outlet mass flow rates. This is called in evalEqs()
//! before setting the state of #m_thermo, since calling the mass flow rate
//! functions may modify ThermoPhase objects that are shared with other
//! reactors.
virtual void evalFlowDevices(double t);

//! Evaluate terms related to surface reactions. Calculates #m_sdot and rate
//! of change in surface species coverages.
//! @param t the current time
Expand All @@ -200,6 +194,14 @@ class Reactor : public ReactorBase
//! Update the state of SurfPhase objects attached to this reactor
virtual void updateSurfaceState(double* y);

//! Update the state information needed by connected reactors and flow
//! devices. Called from updateState().
//! @param updatePressure Indicates whether to update #m_pressure. Should
//! `true` for reactors where the pressure is a dependent property,
//! calculated from the state, and `false` when the pressure is constant
//! or an independent variable.
virtual void updateConnected(bool updatePressure);

//! Get initial conditions for SurfPhase objects attached to this reactor
virtual void getSurfaceInitialConditions(double* y);

Expand Down
6 changes: 0 additions & 6 deletions include/cantera/zeroD/ReactorBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,12 +269,6 @@ class ReactorBase
vector_fp m_state;
std::vector<FlowDevice*> m_inlet, m_outlet;

//! Temporary storage for mass flow rates from each inlet FlowDevice
vector_fp m_mdot_in;

//! Temporary storage for mass flow rates from each outlet FlowDevice
vector_fp m_mdot_out;

std::vector<WallBase*> m_wall;
std::vector<ReactorSurface*> m_surfaces;
vector_int m_lr;
Expand Down
4 changes: 0 additions & 4 deletions include/cantera/zeroD/flowControllers.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@ class MassFlowController : public FlowDevice
return "MassFlowController";
}

virtual bool ready() {
return FlowDevice::ready() && m_mdot >= 0.0;
}

//! Set the fixed mass flow rate (kg/s) through the mass flow controller.
void setMassFlowRate(double mdot);

Expand Down
1 change: 1 addition & 0 deletions interfaces/cython/cantera/_cantera.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,7 @@ cdef extern from "cantera/zerodim.h" namespace "Cantera":
cdef cppclass CxxFlowDevice "Cantera::FlowDevice":
CxxFlowDevice()
string typeStr()
double massFlowRate() except +translate_exception
double massFlowRate(double) except +translate_exception
cbool install(CxxReactorBase&, CxxReactorBase&) except +translate_exception
void setPressureFunction(CxxFunc1*) except +translate_exception
Expand Down
4 changes: 2 additions & 2 deletions interfaces/cython/cantera/examples/reactors/ic_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,8 @@ def piston_speed(t):
states.append(cyl.thermo.state,
t=sim.time, ca=crank_angle(sim.time),
V=cyl.volume, m=cyl.mass,
mdot_in=inlet_valve.mdot(sim.time),
mdot_out=outlet_valve.mdot(sim.time),
mdot_in=inlet_valve.mass_flow_rate,
mdot_out=outlet_valve.mass_flow_rate,
dWv_dt=dWv_dt)


Expand Down
24 changes: 22 additions & 2 deletions interfaces/cython/cantera/reactor.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -707,10 +707,26 @@ cdef class FlowDevice:
self._upstream = upstream
self._downstream = downstream

def mdot(self, double t):
property mass_flow_rate:
def __get__(self):
"""
The mass flow rate [kg/s] through this device at the current reactor
network time.
"""
return self.dev.massFlowRate()

def mdot(self, double t=-999):
"""
The mass flow rate [kg/s] through this device at time *t* [s].

.. deprecated:: 2.5

To be removed after Cantera 2.5. Replaced with the
`mass_flow_rate` property.
"""
warnings.warn("To be removed after Cantera 2.5. "
"Replaced by property 'mass_flow_rate'", DeprecationWarning)

return self.dev.massFlowRate(t)

def set_pressure_function(self, k):
Expand Down Expand Up @@ -799,14 +815,18 @@ cdef class MassFlowController(FlowDevice):
property mass_flow_rate:
r"""
Set the mass flow rate [kg/s] through this controller to be either
a constant or an arbitrary function of time. See `Func1`.
a constant or an arbitrary function of time. See `Func1`, or get its
current value.

Note that depending on the argument type, this method either changes
the property `mass_flow_coeff` or calls the `set_time_function` method.

>>> mfc.mass_flow_rate = 0.3
>>> mfc.mass_flow_rate = lambda t: 2.5 * exp(-10 * (t - 0.5)**2)
"""
def __get__(self):
return self.dev.massFlowRate()

def __set__(self, m):
if isinstance(m, _numbers.Real):
(<CxxMassFlowController*>self.dev).setMassFlowRate(m)
Expand Down
52 changes: 31 additions & 21 deletions interfaces/cython/cantera/test/test_reactor.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,13 +468,18 @@ def test_mass_flow_controller(self):
ma = self.r1.volume * self.r1.density
Ya = self.r1.Y

self.assertNear(mfc.mdot(0.1), 0.)
self.assertNear(mfc.mdot(0.2), 0.1)
self.assertNear(mfc.mdot(1.1), 0.1)
self.assertNear(mfc.mdot(1.2), 0.)

self.net.rtol = 1e-11
self.net.max_time_step = 0.05

self.net.advance(0.1)
self.assertNear(mfc.mass_flow_rate, 0.)
self.net.advance(0.2)
self.assertNear(mfc.mass_flow_rate, 0.1)
self.net.advance(1.1)
self.assertNear(mfc.mass_flow_rate, 0.1)
self.net.advance(1.2)
self.assertNear(mfc.mass_flow_rate, 0.)

self.net.advance(2.5)

mb = self.r1.volume * self.r1.density
Expand Down Expand Up @@ -506,8 +511,9 @@ def test_valve1(self):
self.assertEqual(valve.valve_coeff, k)
self.assertTrue(self.r1.energy_enabled)
self.assertTrue(self.r2.energy_enabled)
self.net.initialize()
self.assertNear((self.r1.thermo.P - self.r2.thermo.P) * k,
valve.mdot(0))
valve.mass_flow_rate)

m1a = self.r1.thermo.density * self.r1.volume
m2a = self.r2.thermo.density * self.r2.volume
Expand All @@ -520,7 +526,7 @@ def test_valve1(self):
m2b = self.r2.thermo.density * self.r2.volume

self.assertNear((self.r1.thermo.P - self.r2.thermo.P) * k,
valve.mdot(0.1))
valve.mass_flow_rate)
self.assertNear(m1a+m2a, m1b+m2b)
Y1b = self.r1.thermo.Y
Y2b = self.r2.thermo.Y
Expand Down Expand Up @@ -586,7 +592,7 @@ def speciesMass(k):
t = self.net.step()
p1 = self.r1.thermo.P
p2 = self.r2.thermo.P
self.assertNear(mdot(p1-p2), valve.mdot(t))
self.assertNear(mdot(p1-p2), valve.mass_flow_rate)
self.assertArrayNear(Y1, self.r1.Y)
self.assertNear(speciesMass(kAr), mAr)
self.assertNear(speciesMass(kO2), mO2)
Expand All @@ -600,11 +606,15 @@ def test_valve_timing(self):
valve.valve_coeff = k
valve.set_time_function(lambda t: t>.01)

mdot = valve.valve_coeff * (self.r1.thermo.P - self.r2.thermo.P)
self.assertTrue(valve.mdot(0.0)==0.)
self.assertTrue(valve.mdot(0.01)==0.)
self.assertTrue(valve.mdot(0.01 + 1e-9)==mdot)
self.assertTrue(valve.mdot(0.02)==mdot)
mdot = lambda: valve.valve_coeff * (self.r1.thermo.P - self.r2.thermo.P)
self.net.initialize()
self.assertEqual(valve.mass_flow_rate, 0.0)
self.net.advance(0.01)
self.assertEqual(valve.mass_flow_rate, 0.0)
self.net.advance(0.01 + 1e-9)
self.assertNear(valve.mass_flow_rate, mdot())
self.net.advance(0.02)
self.assertNear(valve.mass_flow_rate, mdot())

def test_valve_deprecations(self):
# Make sure Python deprecation warnings actually get displayed
Expand Down Expand Up @@ -669,9 +679,9 @@ def test_pressure_controller1(self):
t = 0
while t < 1.0:
t = self.net.step()
self.assertNear(mdot(t), mfc.mdot(t))
self.assertNear(mdot(t), mfc.mass_flow_rate)
dP = self.r1.thermo.P - outlet_reservoir.thermo.P
self.assertNear(mdot(t) + 1e-5 * dP, pc.mdot(t))
self.assertNear(mdot(t) + 1e-5 * dP, pc.mass_flow_rate)

def test_pressure_controller2(self):
self.make_reactors(n_reactors=1)
Expand All @@ -695,9 +705,9 @@ def test_pressure_controller2(self):
t = 0
while t < 1.0:
t = self.net.step()
self.assertNear(mdot(t), mfc.mdot(t))
self.assertNear(mdot(t), mfc.mass_flow_rate)
dP = self.r1.thermo.P - outlet_reservoir.thermo.P
self.assertNear(mdot(t) + pfunc(dP), pc.mdot(t))
self.assertNear(mdot(t) + pfunc(dP), pc.mass_flow_rate)

def test_pressure_controller_deprecations(self):
# Make sure Python deprecation warnings actually get displayed
Expand Down Expand Up @@ -726,13 +736,13 @@ def test_pressure_controller_errors(self):

p = ct.PressureController(self.r1, self.r2, master=mfc, K=0.5)

with self.assertRaisesRegex(ct.CanteraError, 'Device is not ready'):
with self.assertRaisesRegex(ct.CanteraError, 'is not ready'):
p = ct.PressureController(self.r1, self.r2, K=0.5)
p.mdot(0.0)
p.mass_flow_rate

with self.assertRaisesRegex(ct.CanteraError, 'Device is not ready'):
with self.assertRaisesRegex(ct.CanteraError, 'is not ready'):
p = ct.PressureController(self.r1, self.r2)
p.mdot(0.0)
p.mass_flow_rate

with self.assertRaisesRegex(ct.CanteraError, 'NotImplementedError'):
p = ct.PressureController(self.r1, self.r2)
Expand Down
8 changes: 7 additions & 1 deletion interfaces/matlab/toolbox/@FlowDevice/massFlowRate.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,10 @@
% The mass flow rate through the :mat:func:`FlowDevice` at the given time
%

mdot = flowdevicemethods(21, f.index, time);
if nargin == 1
mdot = flowdevicemethods(21, f.index);
else
warning(['"time" argument to massFlowRate is deprecated and will be' ...
' removed after Cantera 2.5.'])
mdot = flowdevicemethods(21, f.index, time);
end
12 changes: 12 additions & 0 deletions src/clib/ctreactor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -413,12 +413,24 @@ extern "C" {
double flowdev_massFlowRate(int i, double time)
{
try {
warn_deprecated("flowdev_massFlowRate(int i, double time)",
"To be changed after Cantera 2.5. 'time' argument will be "
"removed. Use flowdev_massFlowRate2(int i) during transition.");
return FlowDeviceCabinet::item(i).massFlowRate(time);
} catch (...) {
return handleAllExceptions(DERR, DERR);
}
}

double flowdev_massFlowRate2(int i)
{
try {
return FlowDeviceCabinet::item(i).massFlowRate();
} catch (...) {
return handleAllExceptions(DERR, DERR);
}
}

int flowdev_setMassFlowRate(int i, double mdot)
{
/* @deprecated To be removed after Cantera 2.5. */
Expand Down
6 changes: 5 additions & 1 deletion src/matlab/flowdevicemethods.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,11 @@ void flowdevicemethods(int nlhs, mxArray* plhs[],
// options that return a value of type 'double'
switch (job) {
case 21:
r = flowdev_massFlowRate(i, v);
if (v == Undef) {
r = flowdev_massFlowRate2(i);
} else {
r = flowdev_massFlowRate(i, v);
}
break;
default:
mexErrMsgTxt("unknown job parameter");
Expand Down
25 changes: 11 additions & 14 deletions src/zeroD/ConstPressureReactor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,7 @@ void ConstPressureReactor::updateState(doublereal* y)
}
m_vol = m_mass / m_thermo->density();
updateSurfaceState(y + m_nsp + 2);

// save parameters needed by other connected reactors
m_enthalpy = m_thermo->enthalpy_mass();
m_intEnergy = m_thermo->intEnergy_mass();
m_thermo->saveState(m_state);
updateConnected(false);
}

void ConstPressureReactor::evalEqs(doublereal time, doublereal* y,
Expand All @@ -68,7 +64,6 @@ void ConstPressureReactor::evalEqs(doublereal time, doublereal* y,
double dmdt = 0.0; // dm/dt (gas phase)
double* dYdt = ydot + 2;

evalFlowDevices(time);
evalWalls(time);
applySensitivity(params);

Expand All @@ -94,20 +89,22 @@ void ConstPressureReactor::evalEqs(doublereal time, doublereal* y,
double dHdt = - m_Q;

// add terms for outlets
for (size_t i = 0; i < m_outlet.size(); i++) {
dmdt -= m_mdot_out[i];
dHdt -= m_mdot_out[i] * m_enthalpy;
for (auto outlet : m_outlet) {
double mdot = outlet->massFlowRate();
dmdt -= mdot;
dHdt -= mdot * m_enthalpy;
}

// add terms for inlets
for (size_t i = 0; i < m_inlet.size(); i++) {
dmdt += m_mdot_in[i]; // mass flow into system
for (auto inlet : m_inlet) {
double mdot = inlet->massFlowRate();
dmdt += mdot; // mass flow into system
for (size_t n = 0; n < m_nsp; n++) {
double mdot_spec = m_inlet[i]->outletSpeciesMassFlowRate(n);
double mdot_spec = inlet->outletSpeciesMassFlowRate(n);
// flow of species into system and dilution by other species
dYdt[n] += (mdot_spec - m_mdot_in[i] * Y[n]) / m_mass;
dYdt[n] += (mdot_spec - mdot * Y[n]) / m_mass;
}
dHdt += m_mdot_in[i] * m_inlet[i]->enthalpy_mass();
dHdt += mdot * inlet->enthalpy_mass();
}

ydot[0] = dmdt;
Expand Down
2 changes: 1 addition & 1 deletion src/zeroD/FlowDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
namespace Cantera
{

FlowDevice::FlowDevice() : m_mdot(0.0), m_pfunc(0), m_tfunc(0),
FlowDevice::FlowDevice() : m_mdot(Undef), m_pfunc(0), m_tfunc(0),
m_coeff(1.0), m_type(0),
m_nspin(0), m_nspout(0),
m_in(0), m_out(0) {}
Expand Down
Loading