Skip to content

Commit

Permalink
Implements MoleReactor and ConstPressureMoleReactor
Browse files Browse the repository at this point in the history
This commit implements MoleReactor and ConstPressureMoleReactor classes,
it adds the appropriate python interfaces for them, it also adds a test
comparing surface chemistry of mole reactors to traditional reactors.
  • Loading branch information
anthony-walker committed Aug 11, 2022
1 parent 25c5174 commit f5bd6df
Show file tree
Hide file tree
Showing 12 changed files with 496 additions and 51 deletions.
45 changes: 45 additions & 0 deletions include/cantera/zeroD/ConstPressureMoleReactor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//! @file ConstPressureMoleReactor.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_CONSTPRESSMOLE_REACTOR_H
#define CT_CONSTPRESSMOLE_REACTOR_H

#include "cantera/zeroD/MoleReactor.h"

namespace Cantera
{

/*!
* ConstPressureMoleReactor is a class for constant-pressure reactors
* which use a state of moles.
*/
class ConstPressureMoleReactor : public MoleReactor
{
public:
ConstPressureMoleReactor() {}

virtual std::string type() const {
return "ConstPressureMoleReactor";
};

virtual size_t componentIndex(const std::string& nm) const;

virtual std::string componentName(size_t k);

virtual void getState(double* y);

virtual void initialize(double t0 = 0.0);

virtual void eval(double t, double* LHS, double* RHS);

virtual void updateState(double* y);

protected:
const size_t m_sidx = 1;
};

}

#endif
6 changes: 2 additions & 4 deletions include/cantera/zeroD/IdealGasConstPressureMoleReactor.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#ifndef CT_IDEALGASCONSTPRESSMOLE_REACTOR_H
#define CT_IDEALGASCONSTPRESSMOLE_REACTOR_H

#include "cantera/zeroD/MoleReactor.h"
#include "cantera/zeroD/ConstPressureMoleReactor.h"

namespace Cantera
{
Expand All @@ -15,7 +15,7 @@ namespace Cantera
* IdealGasConstPressureMoleReactor is a class for ideal gas constant-pressure reactors
* which use a state of moles.
*/
class IdealGasConstPressureMoleReactor : public MoleReactor
class IdealGasConstPressureMoleReactor : public ConstPressureMoleReactor
{
public:
IdealGasConstPressureMoleReactor() {}
Expand All @@ -42,8 +42,6 @@ class IdealGasConstPressureMoleReactor : public MoleReactor

protected:
vector_fp m_hk; //!< Species molar enthalpies

const size_t m_sidx = 1;
};

}
Expand Down
3 changes: 0 additions & 3 deletions include/cantera/zeroD/IdealGasMoleReactor.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ class IdealGasMoleReactor : public MoleReactor
virtual void updateState(double* y);

virtual Eigen::SparseMatrix<double> jacobian(double t, double* y);

protected:
vector_fp m_uk; //!< Species molar internal energies
};

}
Expand Down
27 changes: 16 additions & 11 deletions include/cantera/zeroD/MoleReactor.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ namespace Cantera

/*!
* MoleReactor is meant to serve the same purpose as the reactor class but with a state
* vector composed of moles. It is currently not functional and only serves as a base
* class for other reactors.
* vector composed of moles. It also serves as the base class for other mole reactors.
*/
class MoleReactor : public Reactor
{
Expand All @@ -27,19 +26,25 @@ class MoleReactor : public Reactor

virtual void initialize(double t0 = 0.0);

virtual void eval(double t, double* LHS, double* RHS) {
throw NotImplementedError("MoleReactor::eval()");
}
virtual void getState(double* y);

size_t componentIndex(const std::string& nm) const {
throw NotImplementedError("MoleReactor::componentIndex");
}
virtual void updateState(double* y);

std::string componentName(size_t k) {
throw NotImplementedError("MoleReactor::componentName");
}
virtual void eval(double t, double* LHS, double* RHS);

size_t componentIndex(const std::string& nm) const;

std::string componentName(size_t k);

protected:
//! Get moles of the system from mass fractions stored by thermo object
//! @param y[out] vector for system moles to be put into
virtual void getMoles(double* y);

//! Set internal mass variable based on moles given
//! @param y[in] vector of moles of the system
virtual void setMassFromMoles(double* y);

virtual void evalSurfaces(double* LHS, double* RHS, double* sdot);

virtual void updateSurfaceState(double* y);
Expand Down
6 changes: 6 additions & 0 deletions interfaces/cython/cantera/reactor.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,18 @@ cdef class Reactor(ReactorBase):
cdef CxxReactor* reactor
cdef object _kinetics

cdef class MoleReactor(Reactor):
pass

cdef class Reservoir(ReactorBase):
pass

cdef class ConstPressureReactor(Reactor):
pass

cdef class ConstPressureMoleReactor(Reactor):
pass

cdef class IdealGasReactor(Reactor):
pass

Expand Down
13 changes: 13 additions & 0 deletions interfaces/cython/cantera/reactor.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,12 @@ cdef class Reactor(ReactorBase):
limit = -1.
self.reactor.setAdvanceLimit(stringify(name), limit)

cdef class MoleReactor(Reactor):
"""A homogeneous, constant pressure, zero-dimensional reactor. The volume
of the reactor changes as a function of time in order to keep the
pressure constant.
"""
reactor_type = "MoleReactor"

cdef class Reservoir(ReactorBase):
"""
Expand All @@ -361,6 +367,13 @@ cdef class ConstPressureReactor(Reactor):
"""
reactor_type = "ConstPressureReactor"

cdef class ConstPressureMoleReactor(Reactor):
"""A homogeneous, constant pressure, zero-dimensional reactor. The volume
of the reactor changes as a function of time in order to keep the
pressure constant.
"""
reactor_type = "ConstPressureMoleReactor"


cdef class IdealGasReactor(Reactor):
""" A constant volume, zero-dimensional reactor for ideal gas mixtures. """
Expand Down
146 changes: 146 additions & 0 deletions src/zeroD/ConstPressureMoleReactor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
//! @file ConstPressureMoleReactor.cpp A constant pressure
//! zero-dimensional reactor with moles as the state

// 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/Wall.h"
#include "cantera/zeroD/FlowDevice.h"
#include "cantera/zeroD/ConstPressureMoleReactor.h"
#include "cantera/base/utilities.h"
#include "cantera/thermo/SurfPhase.h"
#include "cantera/kinetics/Kinetics.h"

using namespace std;

namespace Cantera
{

void ConstPressureMoleReactor::getState(double* y)
{
if (m_thermo == 0) {
throw CanteraError("ConstPressureMoleReactor::getState",
"Error: reactor is empty.");
}
m_thermo->restoreState(m_state);
// get mass for calculations
m_mass = m_thermo->density() * m_vol;
// set the first component to the temperature
y[0] = m_thermo->enthalpy_mass() * m_thermo->density() * m_vol;
// get moles of species in remaining state
getMoles(y+m_sidx);
// set the remaining components to the surface species moles on the walls
getSurfaceInitialConditions(y+m_nsp+m_sidx);
}

void ConstPressureMoleReactor::initialize(double t0)
{
MoleReactor::initialize(t0);
m_nv -= 1; // const pressure system loses 1 more variable from MoleReactor
}

void ConstPressureMoleReactor::updateState(double* y)
{
// the components of y are: [0] the enthalpy, [1...K+1) are the
// moles of each species, and [K+1...] are the moles of surface
// species on each wall.
setMassFromMoles(y+m_sidx);
m_thermo->setMolesNoTruncate(y + m_sidx);
if (m_energy) {
m_thermo->setState_HP(y[0]/m_mass, m_pressure);
} else {
m_thermo->setPressure(m_pressure);
}
m_vol = m_mass / m_thermo->density();
updateConnected(false);
updateSurfaceState(y + m_nsp + m_sidx);
}

void ConstPressureMoleReactor::eval(double time, double* LHS, double* RHS)
{
double* dndt = RHS + m_sidx; // kmol per s

evalWalls(time);

m_thermo->restoreState(m_state);

const vector_fp& imw = m_thermo->inverseMolecularWeights();

if (m_chem) {
m_kin->getNetProductionRates(&m_wdot[0]); // "omega dot"
}

// evaluate reactor surfaces
evalSurfaces(LHS + m_nsp + m_sidx, RHS + m_nsp + m_sidx, m_sdot.data());

// external heat transfer
double dHdt = m_Qdot;

for (size_t n = 0; n < m_nsp; n++) {
// production in gas phase and from surfaces
dndt[n] = m_wdot[n] * m_vol + m_sdot[n];
}

// add terms for outlets
for (auto outlet : m_outlet) {
// determine enthalpy contribution
dHdt -= outlet->massFlowRate() * m_enthalpy;
// flow of species into system and dilution by other species
for (size_t n = 0; n < m_nsp; n++) {
dndt[n] -= outlet->outletSpeciesMassFlowRate(n) * imw[n];
}
}

// add terms for inlets
for (auto inlet : m_inlet) {
// enthalpy contribution from inlets
dHdt += inlet->enthalpy_mass() * inlet->massFlowRate();
// flow of species into system and dilution by other species
for (size_t n = 0; n < m_nsp; n++) {
dndt[n] += inlet->outletSpeciesMassFlowRate(n) * imw[n];
}
}

if (m_energy) {
RHS[0] = dHdt;
} else {
RHS[0] = 0.0;
}
}

size_t ConstPressureMoleReactor::componentIndex(const string& nm) const
{
size_t k = speciesIndex(nm);
if (k != npos) {
return k + m_sidx;
} else if (nm == "enthalpy") {
return 0;
} else {
return npos;
}
}

std::string ConstPressureMoleReactor::componentName(size_t k) {
if (k == 0) {
return "enthalpy";
} else if (k >= m_sidx && k < neq()) {
k -= m_sidx;
if (k < m_thermo->nSpecies()) {
return m_thermo->speciesName(k);
} else {
k -= m_thermo->nSpecies();
}
for (auto& S : m_surfaces) {
ThermoPhase* th = S->thermo();
if (k < th->nSpecies()) {
return th->speciesName(k);
} else {
k -= th->nSpecies();
}
}
}
throw CanteraError("ConstPressureMoleReactor::componentName",
"Index is out of bounds.");
}

}
21 changes: 5 additions & 16 deletions src/zeroD/IdealGasConstPressureMoleReactor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ void IdealGasConstPressureMoleReactor::setThermoMgr(ThermoPhase& thermo)
throw CanteraError("IdealGasConstPressureMoleReactor::setThermoMgr",
"Incompatible phase type provided");
}
MoleReactor::setThermoMgr(thermo);
ConstPressureMoleReactor::setThermoMgr(thermo);
}

void IdealGasConstPressureMoleReactor::getState(double* y)
Expand All @@ -39,21 +39,15 @@ void IdealGasConstPressureMoleReactor::getState(double* y)
m_mass = m_thermo->density() * m_vol;
// set the first component to the temperature
y[0] = m_thermo->temperature();
// Use inverse molecular weights
const double* Y = m_thermo->massFractions();
const vector_fp& imw = m_thermo->inverseMolecularWeights();
double *ys = y + m_sidx;
for (size_t i = 0; i < m_nsp; i++) {
ys[i] = m_mass * imw[i] * Y[i];
}
// get moles of species in remaining state
getMoles(y + m_sidx);
// set the remaining components to the surface species moles on the walls
getSurfaceInitialConditions(y + m_nsp + m_sidx);
}

void IdealGasConstPressureMoleReactor::initialize(double t0)
{
MoleReactor::initialize(t0);
m_nv -= 1; // const pressure system loses 1 more variable from MoleReactor
ConstPressureMoleReactor::initialize(t0);
m_hk.resize(m_nsp, 0.0);
}

Expand All @@ -62,14 +56,9 @@ void IdealGasConstPressureMoleReactor::updateState(double* y)
// the components of y are: [0] the temperature, [1...K+1) are the
// moles of each species, and [K+1...] are the moles of surface
// species on each wall.
setMassFromMoles(y+m_sidx);
m_thermo->setMolesNoTruncate(y + m_sidx);
m_thermo->setState_TP(y[0], m_pressure);
// calculate mass from moles
const vector_fp& mw = m_thermo->molecularWeights();
m_mass = 0;
for (size_t i = 0; i < m_nsp; i++) {
m_mass += y[i + m_sidx] * mw[i];
}
m_vol = m_mass / m_thermo->density();
updateConnected(false);
updateSurfaceState(y + m_nsp + m_sidx);
Expand Down
Loading

0 comments on commit f5bd6df

Please sign in to comment.