mirror of
https://github.com/Cantera/cantera.git
synced 2025-02-25 18:55:29 -06:00
Use 'if constexpr' to simplify MultiRate specialization
This commit is contained in:
parent
56c3a077f7
commit
184f4ddccf
@ -187,17 +187,13 @@ const U& getValue(const std::map<T, U>& m, const T& key, const U& default_val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! A macro for generating member function detectors, which can then be used in
|
//! A macro for generating member function detectors, which can then be used in
|
||||||
//! combination with `std::enable_if` to allow selection of a particular template
|
//! combination with `if constexpr` to condition behavior on the availability of that
|
||||||
//! specialization based on the presence of that member function. See MultiRate for
|
//! member function. See MultiRate for examples of use.
|
||||||
//! examples of use.
|
#define CT_DEFINE_HAS_MEMBER(detector_name, func_name) \
|
||||||
#define CT_DEFINE_HAS_MEMBER(detector_name, func_name) \
|
template<class T, class=void> \
|
||||||
template <typename T> \
|
struct detector_name : std::false_type {}; \
|
||||||
struct detector_name { \
|
template<class T> \
|
||||||
typedef char (& yes)[1], (& no)[2]; \
|
struct detector_name<T, std::void_t<decltype(&T::func_name)>> : std::true_type {};
|
||||||
template <typename C> static yes check(decltype(&C::func_name)); \
|
|
||||||
template <typename> static no check(...); \
|
|
||||||
static bool const value = sizeof(check<T>(0)) == sizeof(yes); \
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,7 +402,9 @@ public:
|
|||||||
//! Update reaction rate parameters
|
//! Update reaction rate parameters
|
||||||
//! @param shared_data data shared by all reactions of a given type
|
//! @param shared_data data shared by all reactions of a given type
|
||||||
void updateFromStruct(const DataType& shared_data) {
|
void updateFromStruct(const DataType& shared_data) {
|
||||||
_update(shared_data);
|
if constexpr (has_update<RateType>::value) {
|
||||||
|
RateType::updateFromStruct(shared_data);
|
||||||
|
}
|
||||||
InterfaceRateBase::updateFromStruct(shared_data);
|
InterfaceRateBase::updateFromStruct(shared_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,22 +434,6 @@ public:
|
|||||||
virtual double activationEnergy() const override {
|
virtual double activationEnergy() const override {
|
||||||
return RateType::activationEnergy() + m_ecov * GasConstant;
|
return RateType::activationEnergy() + m_ecov * GasConstant;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
|
||||||
//! Helper function to process updates for rate types that implement the
|
|
||||||
//! `updateFromStruct` method.
|
|
||||||
template <typename T=RateType,
|
|
||||||
typename std::enable_if<has_update<T>::value, bool>::type = true>
|
|
||||||
void _update(const DataType& shared_data) {
|
|
||||||
T::updateFromStruct(shared_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Helper function for rate types that do not implement `updateFromStruct`.
|
|
||||||
//! Does nothing, but exists to allow generic implementations of update().
|
|
||||||
template <typename T=RateType,
|
|
||||||
typename std::enable_if<!has_update<T>::value, bool>::type = true>
|
|
||||||
void _update(const DataType& shared_data) {
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using InterfaceArrheniusRate = InterfaceRate<ArrheniusRate, InterfaceData>;
|
using InterfaceArrheniusRate = InterfaceRate<ArrheniusRate, InterfaceData>;
|
||||||
@ -539,7 +525,9 @@ public:
|
|||||||
//! Update reaction rate parameters
|
//! Update reaction rate parameters
|
||||||
//! @param shared_data data shared by all reactions of a given type
|
//! @param shared_data data shared by all reactions of a given type
|
||||||
void updateFromStruct(const DataType& shared_data) {
|
void updateFromStruct(const DataType& shared_data) {
|
||||||
_update(shared_data);
|
if constexpr (has_update<RateType>::value) {
|
||||||
|
RateType::updateFromStruct(shared_data);
|
||||||
|
}
|
||||||
InterfaceRateBase::updateFromStruct(shared_data);
|
InterfaceRateBase::updateFromStruct(shared_data);
|
||||||
m_factor = pow(m_siteDensity, -m_surfaceOrder);
|
m_factor = pow(m_siteDensity, -m_surfaceOrder);
|
||||||
}
|
}
|
||||||
@ -575,22 +563,6 @@ public:
|
|||||||
virtual double activationEnergy() const override {
|
virtual double activationEnergy() const override {
|
||||||
return RateType::activationEnergy() + m_ecov * GasConstant;
|
return RateType::activationEnergy() + m_ecov * GasConstant;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
|
||||||
//! Helper function to process updates for rate types that implement the
|
|
||||||
//! `updateFromStruct` method.
|
|
||||||
template <typename T=RateType,
|
|
||||||
typename std::enable_if<has_update<T>::value, bool>::type = true>
|
|
||||||
void _update(const DataType& shared_data) {
|
|
||||||
T::updateFromStruct(shared_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Helper function for rate types that do not implement `updateFromStruct`.
|
|
||||||
//! Does nothing, but exists to allow generic implementations of update().
|
|
||||||
template <typename T=RateType,
|
|
||||||
typename std::enable_if<!has_update<T>::value, bool>::type = true>
|
|
||||||
void _update(const DataType& shared_data) {
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using StickingArrheniusRate = StickingRate<ArrheniusRate, InterfaceData>;
|
using StickingArrheniusRate = StickingRate<ArrheniusRate, InterfaceData>;
|
||||||
|
@ -74,18 +74,54 @@ public:
|
|||||||
const double* kf,
|
const double* kf,
|
||||||
double deltaT) override
|
double deltaT) override
|
||||||
{
|
{
|
||||||
// call helper function: implementation of derivative depends on whether
|
if constexpr (has_ddT<RateType>::value) {
|
||||||
// ReactionRate::ddTFromStruct is defined
|
for (const auto& [iRxn, rate] : m_rxn_rates) {
|
||||||
_process_ddT(rop, kf, deltaT);
|
rop[iRxn] *= rate.ddTScaledFromStruct(m_shared);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// perturb conditions
|
||||||
|
double dTinv = 1. / (m_shared.temperature * deltaT);
|
||||||
|
m_shared.perturbTemperature(deltaT);
|
||||||
|
_update();
|
||||||
|
|
||||||
|
// apply numerical derivative
|
||||||
|
for (auto& [iRxn, rate] : m_rxn_rates) {
|
||||||
|
if (kf[iRxn] != 0.) {
|
||||||
|
double k1 = rate.evalFromStruct(m_shared);
|
||||||
|
rop[iRxn] *= dTinv * (k1 / kf[iRxn] - 1.);
|
||||||
|
} // else not needed: derivative is already zero
|
||||||
|
}
|
||||||
|
|
||||||
|
// revert changes
|
||||||
|
m_shared.restore();
|
||||||
|
_update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void processRateConstants_ddP(double* rop,
|
virtual void processRateConstants_ddP(double* rop,
|
||||||
const double* kf,
|
const double* kf,
|
||||||
double deltaP) override
|
double deltaP) override
|
||||||
{
|
{
|
||||||
// call helper function: implementation of derivative depends on whether
|
if constexpr (has_ddP<DataType>::value) {
|
||||||
// ReactionData::perturbPressure is defined
|
double dPinv = 1. / (m_shared.pressure * deltaP);
|
||||||
_process_ddP(rop, kf, deltaP);
|
m_shared.perturbPressure(deltaP);
|
||||||
|
_update();
|
||||||
|
|
||||||
|
for (auto& [iRxn, rate] : m_rxn_rates) {
|
||||||
|
if (kf[iRxn] != 0.) {
|
||||||
|
double k1 = rate.evalFromStruct(m_shared);
|
||||||
|
rop[iRxn] *= dPinv * (k1 / kf[iRxn] - 1.);
|
||||||
|
} // else not needed: derivative is already zero
|
||||||
|
}
|
||||||
|
|
||||||
|
// revert changes
|
||||||
|
m_shared.restore();
|
||||||
|
_update();
|
||||||
|
} else {
|
||||||
|
for (const auto& [iRxn, rate] : m_rxn_rates) {
|
||||||
|
rop[iRxn] = 0.;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void processRateConstants_ddM(double* rop,
|
virtual void processRateConstants_ddM(double* rop,
|
||||||
@ -93,9 +129,33 @@ public:
|
|||||||
double deltaM,
|
double deltaM,
|
||||||
bool overwrite=true) override
|
bool overwrite=true) override
|
||||||
{
|
{
|
||||||
// call helper function: implementation of derivative depends on whether
|
if constexpr (has_ddM<DataType>::value) {
|
||||||
// ReactionRate::thirdBodyConcentration is defined
|
double dMinv = 1. / deltaM;
|
||||||
_process_ddM(rop, kf, deltaM, overwrite);
|
m_shared.perturbThirdBodies(deltaM);
|
||||||
|
_update();
|
||||||
|
|
||||||
|
for (auto& [iRxn, rate] : m_rxn_rates) {
|
||||||
|
if (kf[iRxn] != 0. && m_shared.conc_3b[iRxn] > 0.) {
|
||||||
|
double k1 = rate.evalFromStruct(m_shared);
|
||||||
|
rop[iRxn] *= dMinv * (k1 / kf[iRxn] - 1.);
|
||||||
|
rop[iRxn] /= m_shared.conc_3b[iRxn];
|
||||||
|
} else {
|
||||||
|
rop[iRxn] = 0.;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// revert changes
|
||||||
|
m_shared.restore();
|
||||||
|
_update();
|
||||||
|
} else {
|
||||||
|
if (!overwrite) {
|
||||||
|
// do not overwrite existing entries
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const auto& [iRxn, rate] : m_rxn_rates) {
|
||||||
|
rop[iRxn] = 0.;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void update(double T) override {
|
virtual void update(double T) override {
|
||||||
@ -125,7 +185,9 @@ public:
|
|||||||
|
|
||||||
virtual double evalSingle(ReactionRate& rate) override {
|
virtual double evalSingle(ReactionRate& rate) override {
|
||||||
RateType& R = static_cast<RateType&>(rate);
|
RateType& R = static_cast<RateType&>(rate);
|
||||||
_updateRate(R);
|
if constexpr (has_update<RateType>::value) {
|
||||||
|
R.updateFromStruct(m_shared);
|
||||||
|
}
|
||||||
return R.evalFromStruct(m_shared);
|
return R.evalFromStruct(m_shared);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,135 +198,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Helper function to process updates for rate types that implement the
|
//! Helper function to process updates
|
||||||
//! `updateFromStruct` method.
|
|
||||||
template <typename T=RateType,
|
|
||||||
typename std::enable_if<has_update<T>::value, bool>::type = true>
|
|
||||||
void _update() {
|
void _update() {
|
||||||
for (auto& rxn : m_rxn_rates) {
|
if constexpr (has_update<RateType>::value) {
|
||||||
rxn.second.updateFromStruct(m_shared);
|
for (auto& [i, rxn] : m_rxn_rates) {
|
||||||
}
|
rxn.updateFromStruct(m_shared);
|
||||||
}
|
|
||||||
|
|
||||||
//! Helper function for rate types that do not implement `updateFromStruct`.
|
|
||||||
//! Does nothing, but exists to allow generic implementations of update().
|
|
||||||
template <typename T=RateType,
|
|
||||||
typename std::enable_if<!has_update<T>::value, bool>::type = true>
|
|
||||||
void _update() {
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Helper function to update a single rate that has an `updateFromStruct` method`.
|
|
||||||
template <typename T=RateType,
|
|
||||||
typename std::enable_if<has_update<T>::value, bool>::type = true>
|
|
||||||
void _updateRate(RateType& rate) {
|
|
||||||
rate.updateFromStruct(m_shared);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Helper function for single rate that does not implement `updateFromStruct`.
|
|
||||||
//! Exists to allow generic implementations of `evalSingle` and `ddTSingle`.
|
|
||||||
template <typename T=RateType,
|
|
||||||
typename std::enable_if<!has_update<T>::value, bool>::type = true>
|
|
||||||
void _updateRate(RateType& rate) {
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Helper function to process temperature derivatives for rate types that
|
|
||||||
//! implement the `ddTScaledFromStruct` method.
|
|
||||||
template <typename T=RateType,
|
|
||||||
typename std::enable_if<has_ddT<T>::value, bool>::type = true>
|
|
||||||
void _process_ddT(double* rop, const double* kf, double deltaT) {
|
|
||||||
for (const auto& [iRxn, rate] : m_rxn_rates) {
|
|
||||||
rop[iRxn] *= rate.ddTScaledFromStruct(m_shared);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Helper function for rate types that do not implement `ddTScaledFromStruct`
|
|
||||||
template <typename T=RateType,
|
|
||||||
typename std::enable_if<!has_ddT<T>::value, bool>::type = true>
|
|
||||||
void _process_ddT(double* rop, const double* kf, double deltaT) {
|
|
||||||
|
|
||||||
// perturb conditions
|
|
||||||
double dTinv = 1. / (m_shared.temperature * deltaT);
|
|
||||||
m_shared.perturbTemperature(deltaT);
|
|
||||||
_update();
|
|
||||||
|
|
||||||
// apply numerical derivative
|
|
||||||
for (auto& [iRxn, rate] : m_rxn_rates) {
|
|
||||||
if (kf[iRxn] != 0.) {
|
|
||||||
double k1 = rate.evalFromStruct(m_shared);
|
|
||||||
rop[iRxn] *= dTinv * (k1 / kf[iRxn] - 1.);
|
|
||||||
} // else not needed: derivative is already zero
|
|
||||||
}
|
|
||||||
|
|
||||||
// revert changes
|
|
||||||
m_shared.restore();
|
|
||||||
_update();
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Helper function to process third-body derivatives for rate data that
|
|
||||||
//! implement the `perturbThirdBodies` method.
|
|
||||||
template <typename T=RateType, typename D=DataType,
|
|
||||||
typename std::enable_if<has_ddM<D>::value, bool>::type = true>
|
|
||||||
void _process_ddM(double* rop, const double* kf, double deltaM, bool overwrite) {
|
|
||||||
double dMinv = 1. / deltaM;
|
|
||||||
m_shared.perturbThirdBodies(deltaM);
|
|
||||||
_update();
|
|
||||||
|
|
||||||
for (auto& [iRxn, rate] : m_rxn_rates) {
|
|
||||||
if (kf[iRxn] != 0. && m_shared.conc_3b[iRxn] > 0.) {
|
|
||||||
double k1 = rate.evalFromStruct(m_shared);
|
|
||||||
rop[iRxn] *= dMinv * (k1 / kf[iRxn] - 1.);
|
|
||||||
rop[iRxn] /= m_shared.conc_3b[iRxn];
|
|
||||||
} else {
|
|
||||||
rop[iRxn] = 0.;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// revert changes
|
|
||||||
m_shared.restore();
|
|
||||||
_update();
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Helper function for rate data that do not implement `perturbThirdBodies`
|
|
||||||
template <typename T=RateType, typename D=DataType,
|
|
||||||
typename std::enable_if<!has_ddM<D>::value, bool>::type = true>
|
|
||||||
void _process_ddM(double* rop, const double* kf, double deltaM, bool overwrite) {
|
|
||||||
if (!overwrite) {
|
|
||||||
// do not overwrite existing entries
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (const auto& [iRxn, rate] : m_rxn_rates) {
|
|
||||||
rop[iRxn] = 0.;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Helper function to process pressure derivatives for rate data that
|
|
||||||
//! implement the `perturbPressure` method.
|
|
||||||
template <typename T=RateType, typename D=DataType,
|
|
||||||
typename std::enable_if<has_ddP<D>::value, bool>::type = true>
|
|
||||||
void _process_ddP(double* rop, const double* kf, double deltaP) {
|
|
||||||
double dPinv = 1. / (m_shared.pressure * deltaP);
|
|
||||||
m_shared.perturbPressure(deltaP);
|
|
||||||
_update();
|
|
||||||
|
|
||||||
for (auto& [iRxn, rate] : m_rxn_rates) {
|
|
||||||
if (kf[iRxn] != 0.) {
|
|
||||||
double k1 = rate.evalFromStruct(m_shared);
|
|
||||||
rop[iRxn] *= dPinv * (k1 / kf[iRxn] - 1.);
|
|
||||||
} // else not needed: derivative is already zero
|
|
||||||
}
|
|
||||||
|
|
||||||
// revert changes
|
|
||||||
m_shared.restore();
|
|
||||||
_update();
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Helper function for rate data that do not implement `perturbPressure`
|
|
||||||
template <typename T=RateType, typename D=DataType,
|
|
||||||
typename std::enable_if<!has_ddP<D>::value, bool>::type = true>
|
|
||||||
void _process_ddP(double* rop, const double* kf, double deltaP) {
|
|
||||||
for (const auto& [iRxn, rate] : m_rxn_rates) {
|
|
||||||
rop[iRxn] = 0.;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Vector of pairs of reaction rates indices and reaction rates
|
//! Vector of pairs of reaction rates indices and reaction rates
|
||||||
|
Loading…
Reference in New Issue
Block a user