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

Conditional rate updates for MultiRate reactions #1151

Merged
merged 2 commits into from
Dec 4, 2021
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
12 changes: 9 additions & 3 deletions include/cantera/kinetics/MultiRate.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class MultiBulkRate final : public MultiRateBase
virtual void add(const size_t rxn_index, ReactionRate& rate) override {
m_indices[rxn_index] = m_rxn_rates.size();
m_rxn_rates.emplace_back(rxn_index, dynamic_cast<RateType&>(rate));
m_shared.invalidateCache();
}

virtual bool replace(const size_t rxn_index, ReactionRate& rate) override {
Expand All @@ -48,6 +49,7 @@ class MultiBulkRate final : public MultiRateBase
"Invalid operation: cannot replace rate object of type '{}' "
"with a new rate of type '{}'.", type(), rate.type());
}
m_shared.invalidateCache();
if (m_indices.find(rxn_index) != m_indices.end()) {
size_t j = m_indices[rxn_index];
m_rxn_rates.at(j).second = dynamic_cast<RateType&>(rate);
Expand All @@ -58,6 +60,7 @@ class MultiBulkRate final : public MultiRateBase

virtual void resize(size_t n_species, size_t n_reactions) override {
m_shared.resize(n_species, n_reactions);
m_shared.invalidateCache();
}

virtual void getRateConstants(double* kf) override {
Expand All @@ -78,10 +81,13 @@ class MultiBulkRate final : public MultiRateBase
_updateRates();
}

virtual void update(const ThermoPhase& bulk, const Kinetics& kin) override {
virtual bool update(const ThermoPhase& bulk, const Kinetics& kin) override {
// update common data once for each reaction type
m_shared.update(bulk, kin);
_updateRates();
std::pair<bool, bool> changed = m_shared.update(bulk, kin);
if (changed.first) {
_updateRates();
}
return changed.second;
}

virtual double evalSingle(ReactionRate& rate) override
Expand Down
3 changes: 2 additions & 1 deletion include/cantera/kinetics/MultiRateBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ class MultiRateBase
//! Update data common to reaction rates of a specific type
//! @param bulk object representing bulk phase
//! @param kin object representing kinetics
virtual void update(const ThermoPhase& bulk, const Kinetics& kin) = 0;
//! @returns flag indicating reaction rates need to be re-evaluated
virtual bool update(const ThermoPhase& bulk, const Kinetics& kin) = 0;

//! Get the rate for a single reaction. Used to implement ReactionRate::eval.
virtual double evalSingle(ReactionRate& rate) = 0;
Expand Down
65 changes: 54 additions & 11 deletions include/cantera/kinetics/ReactionData.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,23 @@ struct ArrheniusData
void update(double T, double P) { update(T); }

//! Update data container based on *bulk* phase state
void update(const ThermoPhase& bulk, const Kinetics& kin);
//! @returns A pair where the first element indicates whether the `updateFromStruct`
//! function for individual reactions needs to be called, and the second
//! element indicates whether the `evalFromStruct` method needs to be called
//! (assuming previously-calculated values were cached)
std::pair<bool, bool> update(const ThermoPhase& bulk, const Kinetics& kin);

//! Update number of species and reactions; unused
void resize(size_t n_species, size_t n_reactions) {}

//! Force shared data and reaction rates to be updated next time. This is called by
//! functions that change quantities affecting rate calculations that are normally
//! assumed to be constant, like the reaction rate parameters or the number of
//! reactions.
void invalidateCache() {
temperature = NAN;
}

double temperature; //!< temperature
double logT; //!< logarithm of temperature
double recipT; //!< inverse of temperature
Expand All @@ -55,8 +67,7 @@ struct ArrheniusData
*/
struct BlowersMaselData
{
BlowersMaselData()
: temperature(1.), logT(0.), recipT(1.), finalized(false) {}
BlowersMaselData();

//! Update data container based on temperature *T*
void update(double T);
Expand All @@ -67,7 +78,7 @@ struct BlowersMaselData
}

//! Update data container based on *bulk* phase state and *kin* kinetics
void update(const ThermoPhase& bulk, const Kinetics& kin);
std::pair<bool, bool> update(const ThermoPhase& bulk, const Kinetics& kin);

//! Finalize setup
void resize(size_t n_species, size_t n_reactions) {
Expand All @@ -76,9 +87,16 @@ struct BlowersMaselData
finalized = true;
}

void invalidateCache() {
temperature = NAN;
}

double temperature; //!< temperature
double logT; //!< logarithm of temperature
double recipT; //!< inverse of temperature
double density; //!< used to determine if updates are needed
int state_mf_number; //!< integer that is incremented when composition changes


bool finalized; //!< boolean indicating whether vectors are accessible
vector_fp dH; //!< enthalpy change for each reaction
Expand All @@ -95,10 +113,10 @@ struct BlowersMaselData
*/
struct FalloffData : public ArrheniusData
{
FalloffData() : finalized(false) {}
FalloffData() : finalized(false), molar_density(NAN), state_mf_number(-1) {}

//! Update data container based on *bulk* phase state and *kin* kinetics
void update(const ThermoPhase& bulk, const Kinetics& kin);
std::pair<bool, bool> update(const ThermoPhase& bulk, const Kinetics& kin);
using ArrheniusData::update;

//! Finalize setup
Expand All @@ -107,8 +125,15 @@ struct FalloffData : public ArrheniusData
finalized = true;
}

void invalidateCache() {
ArrheniusData::invalidateCache();
molar_density = NAN;
}

bool finalized; //!< boolean indicating whether vectors are accessible
vector_fp conc_3b; //!< vector of effective third-body concentrations
double molar_density; //!< used to determine if updates are needed
int state_mf_number; //!< integer that is incremented when composition changes
};


Expand All @@ -119,7 +144,7 @@ struct FalloffData : public ArrheniusData
*/
struct PlogData
{
PlogData() : temperature(1.), logT(0.), recipT(1.), logP(0.) {}
PlogData() : temperature(1.), logT(0.), recipT(1.), pressure(NAN), logP(0.) {}

//! Update data container based on temperature *T* (raises exception)
void update(double T);
Expand All @@ -129,18 +154,25 @@ struct PlogData
temperature = T;
logT = std::log(T);
recipT = 1./T;
pressure = P;
logP = std::log(P);
}

//! Update data container based on *bulk* phase state
void update(const ThermoPhase& bulk, const Kinetics& kin);
std::pair<bool, bool> update(const ThermoPhase& bulk, const Kinetics& kin);

//! Update number of species and reactions; unused
void resize(size_t n_species, size_t n_reactions) {}

void invalidateCache() {
temperature = NAN;
pressure = NAN;
}

double temperature; //!< temperature
double logT; //!< logarithm of temperature
double recipT; //!< inverse of temperature
double pressure; //!< Pressure [Pa]
double logP; //!< logarithm of pressure
};

Expand All @@ -152,7 +184,7 @@ struct PlogData
*/
struct ChebyshevData
{
ChebyshevData() : temperature(1.), recipT(1.), log10P(0.) {}
ChebyshevData() : temperature(1.), recipT(1.), pressure(NAN), log10P(0.) {}

//! Update data container based on temperature *T* (raises exception)
void update(double T);
Expand All @@ -162,17 +194,24 @@ struct ChebyshevData
{
temperature = T;
recipT = 1./T;
pressure = P;
log10P = std::log10(P);
}

//! Update data container based on *bulk* phase state
void update(const ThermoPhase& bulk, const Kinetics& kin);
std::pair<bool, bool> update(const ThermoPhase& bulk, const Kinetics& kin);

//! Update number of species and reactions; unused
void resize(size_t n_species, size_t n_reactions) {}

void invalidateCache() {
temperature = NAN;
pressure = NAN;
}

double temperature; //!< temperature
double recipT; //!< inverse of temperature
double pressure; //!< Pressure [Pa]
double log10P; //!< base 10 logarithm of pressure
};

Expand All @@ -189,11 +228,15 @@ struct CustomFunc1Data
void update(double T, double P) { update(T); }

//! Update data container based on *bulk* phase state
void update(const ThermoPhase& bulk, const Kinetics& kin);
std::pair<bool, bool> update(const ThermoPhase& bulk, const Kinetics& kin);

//! Update number of species and reactions; unused
void resize(size_t n_species, size_t n_reactions) {}

void invalidateCache() {
temperature = NAN;
}

double temperature; //!< temperature
};

Expand Down
17 changes: 7 additions & 10 deletions src/kinetics/GasKinetics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,15 @@ void GasKinetics::update_rates_T()
m_ROP_ok = false;
}

if (T != m_temp || P != m_pres) {

// loop over MultiBulkRates evaluators
// @todo ... address/reassess logic as this update can fail
// (see tests/kinetics/KineticsFromScratch.cpp:
// KineticsAddSpecies - add_species_sequential)
// a work-around is to call GasKinetics::invalidateCache()
for (auto& rates : m_bulk_rates) {
rates->update(thermo(), *this);
// loop over MultiBulkRate evaluators for each reaction type
for (auto& rates : m_bulk_rates) {
bool changed = rates->update(thermo(), *this);
if (changed) {
rates->getRateConstants(m_rfn.data());
m_ROP_ok = false;
}

}
if (T != m_temp || P != m_pres) {
// P-log reactions (legacy)
if (m_plog_rates.nReactions()) {
m_plog_rates.update(T, logT, m_rfn.data());
Expand Down
76 changes: 61 additions & 15 deletions src/kinetics/ReactionData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@
namespace Cantera
{

void ArrheniusData::update(const ThermoPhase& bulk, const Kinetics& kin)
std::pair<bool, bool> ArrheniusData::update(const ThermoPhase& bulk,
const Kinetics& kin)
{
update(bulk.temperature());
double T = bulk.temperature();
std::pair<bool, bool> changed{ false, T != temperature };
update(T);
return changed;
}

void BlowersMaselData::update(double T)
Expand All @@ -23,17 +27,48 @@ void BlowersMaselData::update(double T)
recipT = 1./T;
}

void BlowersMaselData::update(const ThermoPhase& bulk, const Kinetics& kin)
BlowersMaselData::BlowersMaselData()
: temperature(1.)
, logT(0.)
, recipT(1.)
, density(NAN)
, state_mf_number(-1)
, finalized(false)
{
update(bulk.temperature());
bulk.getPartialMolarEnthalpies(m_grt.data());
kin.getReactionDelta(m_grt.data(), dH.data());
}

void FalloffData::update(const ThermoPhase& bulk, const Kinetics& kin)
std::pair<bool, bool> BlowersMaselData::update(const ThermoPhase& bulk,
const Kinetics& kin)
{
update(bulk.temperature());
kin.getThirdBodyConcentrations(conc_3b.data());
double rho = bulk.density();
int mf = bulk.stateMFNumber();
double T = bulk.temperature();
std::pair<bool, bool> changed { false, T != temperature };
if (T != temperature || rho != density || mf != state_mf_number) {
density = rho;
state_mf_number = mf;
bulk.getPartialMolarEnthalpies(m_grt.data());
kin.getReactionDelta(m_grt.data(), dH.data());
changed.first = changed.second = true;
}
update(T);
return changed;
}

std::pair<bool, bool> FalloffData::update(const ThermoPhase& bulk, const Kinetics& kin)
{
double rho_m = bulk.molarDensity();
int mf = bulk.stateMFNumber();
double T = bulk.temperature();
std::pair<bool, bool> changed { false, T != temperature };
if (rho_m != molar_density || mf != state_mf_number) {
molar_density = rho_m;
state_mf_number = mf;
kin.getThirdBodyConcentrations(conc_3b.data());
changed.first = changed.second = true;
}
update(T);
return changed;
}

void PlogData::update(double T)
Expand All @@ -42,9 +77,13 @@ void PlogData::update(double T)
"Missing state information: reaction type requires pressure.");
}

void PlogData::update(const ThermoPhase& bulk, const Kinetics& kin)
std::pair<bool, bool> PlogData::update(const ThermoPhase& bulk, const Kinetics& kin)
{
update(bulk.temperature(), bulk.pressure());
double T = bulk.temperature();
double P = bulk.pressure();
std::pair<bool, bool> changed{ P != pressure, P != pressure || T != temperature };
update(T, P);
return changed;
}

void ChebyshevData::update(double T)
Expand All @@ -53,14 +92,21 @@ void ChebyshevData::update(double T)
"Missing state information: reaction type requires pressure.");
}

void ChebyshevData::update(const ThermoPhase& bulk, const Kinetics& kin)
std::pair<bool, bool> ChebyshevData::update(const ThermoPhase& bulk, const Kinetics& kin)
{
update(bulk.temperature(), bulk.pressure());
double T = bulk.temperature();
double P = bulk.pressure();
std::pair<bool, bool> changed{ P != pressure, P != pressure || T != temperature };
update(T, P);
return changed;
}

void CustomFunc1Data::update(const ThermoPhase& bulk, const Kinetics& kin)
std::pair<bool, bool> CustomFunc1Data::update(const ThermoPhase& bulk, const Kinetics& kin)
{
temperature = bulk.temperature();
double T = bulk.temperature();
std::pair<bool, bool> changed { false, T != temperature };
temperature = T;
return changed;
}

}
1 change: 1 addition & 0 deletions src/thermo/Phase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,7 @@ bool Phase::ready() const
}

void Phase::invalidateCache() {
m_stateNum++;
m_cache.clear();
}

Expand Down
3 changes: 0 additions & 3 deletions test/kinetics/kineticsFromScratch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -427,9 +427,6 @@ class KineticsAddSpecies : public testing::Test
p.setState_TPX(1200, 5*OneAtm, X);
p_ref.setState_TPX(1200, 5*OneAtm, X);

// need to invalidate cache to force update
kin_ref->invalidateCache();

vector_fp k(kin.nReactions()), k_ref(kin_ref->nReactions());
vector_fp w(kin.nTotalSpecies()), w_ref(kin_ref->nTotalSpecies());

Expand Down