[Reactor] Eliminate re-ordering of sensitivity parameters

Passing the full parameter vector to evalEqs for each reactor and wall
eliminates the need to re-order the parameter vector. Instead, each reactor and
wall just needs to know the indices of its sensitivity parameters, which are now
returned by ReactorNet::registerSensitivityReaction.
This commit is contained in:
Ray Speth 2016-05-01 19:34:49 -04:00
parent e13faa1071
commit c7a1a57fbd
8 changed files with 63 additions and 176 deletions

View file

@ -126,19 +126,6 @@ public:
//! (in the homogeneous phase).
virtual void addSensitivityReaction(size_t rxn);
//! Return a vector specifying the ordering of objects to use when
//! determining sensitivity parameter indices.
/*!
* Used to construct ReactorNet::m_sensOrder.
*
* @return A vector of pairs where the first element of each pair is a
* pointer to either a Reactor object or a Wall object and the second
* element is either 0 (in the case of a Reactor) or in the case of a
* Wall indicates that the sensitivity parameters are associated with
* surface chemistry on the left (0) or right (1) side of the wall.
*/
std::vector<std::pair<void*, int> > getSensitivityOrder() const;
//! Return the index in the solution vector for this reactor of the
//! component named *nm*. Possible values for *nm* are "mass", "volume",
//! "int_energy", the name of a homogeneous phase species, or the name of a
@ -193,10 +180,8 @@ protected:
bool m_energy;
size_t m_nv;
size_t m_nsens;
std::vector<size_t> m_pnum;
std::vector<size_t> m_nsens_wall;
vector_fp m_mult_save;
// Data associated each sensitivity parameter
std::vector<SensitivityParameter> m_sensParams;
};
}

View file

@ -21,6 +21,13 @@ const int ConstPressureReactorType = 4;
const int IdealGasReactorType = 5;
const int IdealGasConstPressureReactorType = 6;
struct SensitivityParameter
{
size_t local; //!< local parameter index
size_t global; //!< global parameter index
double value; //!< nominal value of the parameter
};
/**
* Base class for stirred reactors. Allows using any substance model, with
* arbitrary inflow, outflow, heat loss/gain, surface chemistry, and volume

View file

@ -162,7 +162,7 @@ public:
virtual void getState(doublereal* y);
virtual size_t nparams() {
return m_ntotpar;
return m_sens_params.size();
}
//! Return the index corresponding to the component named *component* in the
@ -173,8 +173,9 @@ public:
//! Used by Reactor and Wall objects to register the addition of
//! sensitivity reactions so that the ReactorNet can keep track of the
//! order in which sensitivity parameters are added.
void registerSensitivityReaction(void* reactor, size_t reactionIndex,
const std::string& name, int leftright=0);
//! @returns the index of this parameter in the vector of sensitivity
//! parameters (global across all reactors)
size_t registerSensitivityReaction(const std::string& name);
//! The name of the p-th sensitivity parameter added to this ReactorNet.
const std::string& sensitivityParameterName(size_t p) {
@ -217,21 +218,10 @@ protected:
int m_maxErrTestFails;
bool m_verbose;
size_t m_ntotpar;
std::vector<size_t> m_nparams;
//! Names corresponding to each sensitivity parameter
std::vector<std::string> m_paramNames;
//! Structure used to determine the order of sensitivity parameters
//! m_sensOrder[Reactor or Wall, leftright][reaction number] = parameter
//! index
std::map<std::pair<void*, int>, std::map<size_t, size_t> > m_sensOrder;
//! Mapping from the order in which sensitivity parameters were added to the
//! ReactorNet to the order in which they occur in the integrator output.
std::vector<size_t> m_sensIndex;
vector_fp m_ydot;
};
}

View file

@ -7,12 +7,11 @@
#include "cantera/base/ctexceptions.h"
#include "cantera/numerics/Func1.h"
#include "cantera/zeroD/ReactorBase.h"
namespace Cantera
{
// forward references
class ReactorBase;
class Kinetics;
class SurfPhase;
@ -122,7 +121,7 @@ public:
bool install(ReactorBase& leftReactor, ReactorBase& rightReactor);
//! Called just before the start of integration
virtual void initialize();
virtual void initialize() {}
//! True if the wall is correctly configured and ready to use.
virtual bool ready() {
@ -186,8 +185,8 @@ public:
}
}
void addSensitivityReaction(int leftright, size_t rxn);
void setSensitivityParameters(int lr, double* params);
void resetSensitivityParameters(int lr);
void setSensitivityParameters(double* params);
void resetSensitivityParameters();
protected:
ReactorBase* m_left;
@ -201,7 +200,7 @@ protected:
Func1* m_qf;
vector_fp m_leftcov, m_rightcov;
std::vector<size_t> m_pleft, m_pright;
std::vector<SensitivityParameter> m_pleft, m_pright;
vector_fp m_leftmult_save, m_rightmult_save;
};

View file

@ -76,18 +76,7 @@ void FlowReactor::evalEqs(doublereal time, doublereal* y,
doublereal* ydot, doublereal* params)
{
m_thermo->restoreState(m_state);
double mult;
size_t n, npar;
// process sensitivity parameters
if (params) {
npar = nSensParams();
for (n = 0; n < npar; n++) {
mult = m_kin->multiplier(m_pnum[n]);
m_kin->setMultiplier(m_pnum[n], mult*params[n]);
}
}
applySensitivity(params);
// distance equation
ydot[0] = m_speed;
@ -104,18 +93,10 @@ void FlowReactor::evalEqs(doublereal time, doublereal* y,
fill(ydot + 2, ydot + 2 + m_nsp, 0.0);
}
doublereal rrho = 1.0/m_thermo->density();
for (n = 0; n < m_nsp; n++) {
for (size_t n = 0; n < m_nsp; n++) {
ydot[n+2] *= mw[n]*rrho;
}
// reset sensitivity parameters
if (params) {
npar = nSensParams();
for (n = 0; n < npar; n++) {
mult = m_kin->multiplier(m_pnum[n]);
m_kin->setMultiplier(m_pnum[n], mult/params[n]);
}
}
resetSensitivity(params);
}
size_t FlowReactor::componentIndex(const string& nm) const

View file

@ -21,8 +21,7 @@ Reactor::Reactor() :
m_mass(0.0),
m_chem(false),
m_energy(true),
m_nv(0),
m_nsens(npos)
m_nv(0)
{}
void Reactor::setKineticsMgr(Kinetics& kin)
@ -117,22 +116,15 @@ void Reactor::initialize(doublereal t0)
}
}
m_work.resize(maxnt);
std::sort(m_pnum.begin(), m_pnum.end());
}
size_t Reactor::nSensParams()
{
if (m_nsens == npos) {
// determine the number of sensitivity parameters
size_t m, ns;
m_nsens = m_pnum.size();
for (m = 0; m < m_wall.size(); m++) {
ns = m_wall[m]->nSensParams(m_lr[m]);
m_nsens_wall.push_back(ns);
m_nsens += ns;
size_t ns = m_sensParams.size();
for (size_t m = 0; m < m_wall.size(); m++) {
ns += m_wall[m]->nSensParams(m_lr[m]);
}
}
return m_nsens;
return ns;
}
void Reactor::syncState()
@ -328,22 +320,8 @@ void Reactor::addSensitivityReaction(size_t rxn)
"Reaction number out of range ({})", rxn);
}
network().registerSensitivityReaction(this, rxn,
name()+": "+m_kin->reactionString(rxn));
m_pnum.push_back(rxn);
m_mult_save.push_back(1.0);
}
std::vector<std::pair<void*, int> > Reactor::getSensitivityOrder() const
{
std::vector<std::pair<void*, int> > order;
order.emplace_back(const_cast<Reactor*>(this), 0);
for (size_t n = 0; n < m_wall.size(); n++) {
if (m_nsens_wall[n]) {
order.emplace_back(m_wall[n], m_lr[n]);
}
}
return order;
size_t p = network().registerSensitivityReaction(name()+": "+m_kin->reactionString(rxn));
m_sensParams.emplace_back(SensitivityParameter{rxn, p, 1.0});
}
size_t Reactor::speciesIndex(const string& nm) const
@ -408,19 +386,14 @@ void Reactor::applySensitivity(double* params)
if (!params) {
return;
}
size_t npar = m_pnum.size();
for (size_t n = 0; n < npar; n++) {
double mult = m_kin->multiplier(m_pnum[n]);
m_kin->setMultiplier(m_pnum[n], mult*params[n]);
for (auto& p : m_sensParams) {
p.value = m_kin->multiplier(p.local);
m_kin->setMultiplier(p.local, p.value*params[p.global]);
}
size_t ploc = npar;
for (size_t m = 0; m < m_wall.size(); m++) {
if (m_nsens_wall[m] > 0) {
m_wall[m]->setSensitivityParameters(m_lr[m], params + ploc);
ploc += m_nsens_wall[m];
m_wall[m]->setSensitivityParameters(params);
}
}
m_kin->invalidateCache();
}
void Reactor::resetSensitivity(double* params)
@ -428,17 +401,11 @@ void Reactor::resetSensitivity(double* params)
if (!params) {
return;
}
size_t npar = m_pnum.size();
for (size_t n = 0; n < npar; n++) {
double mult = m_kin->multiplier(m_pnum[n]);
m_kin->setMultiplier(m_pnum[n], mult/params[n]);
for (auto& p : m_sensParams) {
m_kin->setMultiplier(p.local, p.value);
}
size_t ploc = npar;
for (size_t m = 0; m < m_wall.size(); m++) {
if (m_nsens_wall[m] > 0) {
m_wall[m]->resetSensitivityParameters(m_lr[m]);
ploc += m_nsens_wall[m];
}
m_wall[m]->resetSensitivityParameters();
}
}

View file

@ -15,7 +15,7 @@ ReactorNet::ReactorNet() :
m_nv(0), m_rtol(1.0e-9), m_rtolsens(1.0e-4),
m_atols(1.0e-15), m_atolsens(1.0e-4),
m_maxstep(0.0), m_maxErrTestFails(0),
m_verbose(false), m_ntotpar(0)
m_verbose(false)
{
m_integ = newIntegrator("CVODE");
@ -80,19 +80,11 @@ void ReactorNet::initialize()
throw CanteraError("ReactorNet::initialize",
"no reactors in network!");
}
size_t sensParamNumber = 0;
m_start.assign(1, 0);
for (n = 0; n < m_reactors.size(); n++) {
Reactor& r = *m_reactors[n];
r.initialize(m_time);
nv = r.neq();
m_nparams.push_back(r.nSensParams());
for (const auto& sens_obj : r.getSensitivityOrder()) {
for (const auto& order : m_sensOrder[sens_obj]) {
m_sensIndex.resize(std::max(order.second + 1, m_sensIndex.size()));
m_sensIndex[order.second] = sensParamNumber++;
}
}
m_nv += nv;
m_start.push_back(m_nv);
@ -171,12 +163,9 @@ void ReactorNet::eval(doublereal t, doublereal* y,
doublereal* ydot, doublereal* p)
{
size_t n;
size_t pstart = 0;
updateState(y);
for (n = 0; n < m_reactors.size(); n++) {
m_reactors[n]->evalEqs(t, y + m_start[n],
ydot + m_start[n], p + pstart);
pstart += m_nparams[n];
m_reactors[n]->evalEqs(t, y + m_start[n], ydot + m_start[n], p);
}
checkFinite("ydot", ydot, m_nv);
}
@ -186,11 +175,11 @@ double ReactorNet::sensitivity(size_t k, size_t p)
if (!m_init) {
initialize();
}
if (p >= m_sensIndex.size()) {
if (p >= m_sens_params.size()) {
throw IndexError("ReactorNet::sensitivity",
"m_sensIndex", p, m_sensIndex.size()-1);
"m_sens_params", p, m_sens_params.size()-1);
}
return m_integ->sensitivity(k, m_sensIndex[p])/m_integ->solution(k);
return m_integ->sensitivity(k, p) / m_integ->solution(k);
}
void ReactorNet::evalJacobian(doublereal t, doublereal* y,
@ -249,24 +238,16 @@ size_t ReactorNet::globalComponentIndex(const string& component, size_t reactor)
return m_start[reactor] + m_reactors[reactor]->componentIndex(component);
}
void ReactorNet::registerSensitivityReaction(void* reactor,
size_t reactionIndex, const std::string& name, int leftright)
size_t ReactorNet::registerSensitivityReaction(const std::string& name)
{
if (m_integrator_init) {
throw CanteraError("ReactorNet::registerSensitivityReaction",
"Sensitivity reactions cannot be added after the"
"integrator has been initialized.");
}
std::pair<void*, int> R = {reactor, leftright};
if (m_sensOrder.count(R) &&
m_sensOrder[R].count(reactionIndex)) {
throw CanteraError("ReactorNet::registerSensitivityReaction",
"Attempted to register duplicate sensitivity reaction");
}
m_paramNames.push_back(name);
m_sensOrder[R][reactionIndex] = m_ntotpar;
m_ntotpar++;
m_sens_params.push_back(1.0);
return m_sens_params.size() - 1;
}
}

View file

@ -31,12 +31,6 @@ bool Wall::install(ReactorBase& rleft, ReactorBase& rright)
return true;
}
void Wall::initialize()
{
std::sort(m_pleft.begin(), m_pleft.end());
std::sort(m_pright.begin(), m_pright.end());
}
void Wall::setKinetics(Kinetics* left, Kinetics* right)
{
m_chem[0] = left;
@ -146,53 +140,36 @@ void Wall::addSensitivityReaction(int leftright, size_t rxn)
"Reaction number out of range ({})", rxn);
}
if (leftright == 0) {
m_left->network().registerSensitivityReaction(this, rxn,
m_chem[0]->reactionString(rxn), leftright);
m_pleft.push_back(rxn);
m_leftmult_save.push_back(1.0);
size_t p = m_left->network().registerSensitivityReaction(
m_chem[0]->reactionString(rxn));
m_pleft.emplace_back(SensitivityParameter{rxn, p, 1.0});
} else {
m_right->network().registerSensitivityReaction(this, rxn,
m_chem[1]->reactionString(rxn), leftright);
m_pright.push_back(rxn);
m_rightmult_save.push_back(1.0);
size_t p = m_right->network().registerSensitivityReaction(
m_chem[1]->reactionString(rxn));
m_pright.emplace_back(SensitivityParameter{rxn, p, 1.0});
}
}
void Wall::setSensitivityParameters(int lr, double* params)
void Wall::setSensitivityParameters(double* params)
{
// process sensitivity parameters
size_t n, npar;
if (lr == 0) {
npar = m_pleft.size();
for (n = 0; n < npar; n++) {
m_leftmult_save[n] = m_chem[0]->multiplier(m_pleft[n]);
m_chem[0]->setMultiplier(m_pleft[n],
m_leftmult_save[n]*params[n]);
}
} else {
npar = m_pright.size();
for (n = 0; n < npar; n++) {
m_rightmult_save[n] = m_chem[1]->multiplier(m_pright[n]);
m_chem[1]->setMultiplier(m_pright[n],
m_rightmult_save[n]*params[n]);
for (auto& p : m_pleft) {
p.value = m_chem[0]->multiplier(p.local);
m_chem[0]->setMultiplier(p.local, p.value*params[p.global]);
}
for (auto& p : m_pright) {
p.value = m_chem[1]->multiplier(p.local);
m_chem[1]->setMultiplier(p.local, p.value*params[p.global]);
}
}
void Wall::resetSensitivityParameters(int lr)
void Wall::resetSensitivityParameters()
{
size_t n, npar;
if (lr == 0) {
npar = m_pleft.size();
for (n = 0; n < npar; n++) {
m_chem[0]->setMultiplier(m_pleft[n], m_leftmult_save[n]);
}
} else {
npar = m_pright.size();
for (n = 0; n < npar; n++) {
m_chem[1]->setMultiplier(m_pright[n],
m_rightmult_save[n]);
for (auto& p : m_pleft) {
m_chem[0]->setMultiplier(p.local, p.value);
}
for (auto& p : m_pright) {
m_chem[1]->setMultiplier(p.local, p.value);
}
}
}