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

[Kinetics] Fix issue 717, Add check for sticking coefficient more than 1 #1038

Merged
merged 1 commit into from
Dec 17, 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
3 changes: 3 additions & 0 deletions include/cantera/base/global.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@ void warn_user(const std::string& method, const std::string& msg,
//! @copydoc Application::make_deprecation_warnings_fatal
void make_deprecation_warnings_fatal();

//! @copydoc Application::make_warnings_fatal
void make_warnings_fatal();

//! @copydoc Application::suppress_thermo_warnings
void suppress_thermo_warnings(bool suppress=true);

Expand Down
5 changes: 5 additions & 0 deletions include/cantera/kinetics/Kinetics.h
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,11 @@ class Kinetics
m_root = root;
}

//! Calculate the reaction enthalpy of a reaction which
//! has not necessarily been added into the Kinetics object
virtual double reactionEnthalpy(const Composition& reactants,
const Composition& products);

protected:
//! Cache for saved calculations within each Kinetics object.
ValueCache m_cache;
Expand Down
14 changes: 13 additions & 1 deletion include/cantera/kinetics/Reaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ class Reaction
//! valid.
virtual void validate();
ischoegl marked this conversation as resolved.
Show resolved Hide resolved

//! Perform validation checks that need access to a complete Kinetics objects, for
// example to retrieve information about reactant / product species.
virtual void validate(Kinetics& kin) {}

//! Return the parameters such that an identical Reaction could be reconstructed
//! using the newReaction() function. Behavior specific to derived classes is
//! handled by the getParameters() method.
Expand Down Expand Up @@ -197,7 +201,9 @@ class ElementaryReaction2 : public Reaction
ElementaryReaction2();
ElementaryReaction2(const Composition& reactants, const Composition products,
const Arrhenius& rate);

virtual void validate();
using Reaction::validate;
virtual void getParameters(AnyMap& reactionNode) const;

virtual std::string type() const {
Expand Down Expand Up @@ -283,7 +289,9 @@ class FalloffReaction2 : public Reaction

virtual std::string reactantString() const;
virtual std::string productString() const;

virtual void validate();
using Reaction::validate;
virtual void calculateRateCoeffUnits(const Kinetics& kin);
virtual void getParameters(AnyMap& reactionNode) const;

Expand Down Expand Up @@ -347,6 +355,7 @@ class PlogReaction2 : public Reaction
}

virtual void validate();
using Reaction::validate;
virtual void getParameters(AnyMap& reactionNode) const;

Plog rate;
Expand Down Expand Up @@ -397,6 +406,9 @@ class InterfaceReaction : public ElementaryReaction2
virtual void calculateRateCoeffUnits(const Kinetics& kin);
virtual void getParameters(AnyMap& reactionNode) const;

virtual void validate(Kinetics& kin);
using Reaction::validate;

virtual std::string type() const {
return "interface";
}
Expand Down Expand Up @@ -450,6 +462,7 @@ class BlowersMaselInterfaceReaction : public Reaction
virtual void getParameters(AnyMap& reactionNode) const;
virtual void validate();
virtual void calculateRateCoeffUnits(const Kinetics& kin);
virtual void validate(Kinetics& kin);

virtual std::string type() const {
return "surface-Blowers-Masel";
Expand Down Expand Up @@ -717,5 +730,4 @@ void setupElectrochemicalReaction(ElectrochemicalReaction&,
void setupBlowersMaselInterfaceReaction(BlowersMaselInterfaceReaction&,
const AnyMap&, const Kinetics&);
}

#endif
1 change: 1 addition & 0 deletions interfaces/cython/cantera/_cantera.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ cdef extern from "cantera/base/global.h" namespace "Cantera":
cdef XML_Node* CxxGetXmlFile "Cantera::get_XML_File" (string) except +translate_exception
cdef XML_Node* CxxGetXmlFromString "Cantera::get_XML_from_string" (string) except +translate_exception
cdef void Cxx_make_deprecation_warnings_fatal "Cantera::make_deprecation_warnings_fatal" ()
cdef void Cxx_make_warnings_fatal "Cantera::make_warnings_fatal" ()
cdef void Cxx_suppress_deprecation_warnings "Cantera::suppress_deprecation_warnings" ()
cdef void Cxx_suppress_thermo_warnings "Cantera::suppress_thermo_warnings" (cbool)
cdef void Cxx_use_legacy_rate_constants "Cantera::use_legacy_rate_constants" (cbool)
Expand Down
17 changes: 17 additions & 0 deletions interfaces/cython/cantera/test/test_kinetics.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,23 @@ def test_pdep_err(self):
for msg in err_msg:
self.assertIn(msg, err_msg_list)

def test_sticking_coeff_err(self):
err_msg = ("Sticking coefficient is greater than 1 for reaction \'O2 \+ 2 PT\(S\) => 2 O\(S\)\'",
"at T = 200.0",
"at T = 500.0",
"at T = 1000.0",
"at T = 2000.0",
"at T = 5000.0",
"at T = 10000.0",
"Sticking coefficient is greater than 1 for reaction",
"CanteraError thrown by InterfaceReaction::validate:",
"CanteraError thrown by BlowersMaselInterfaceReaction::validate:"
)
ct.make_warnings_fatal()
for err in err_msg:
with self.assertRaisesRegex(ct.CanteraError, err):
gas = ct.Solution('sticking_coeff_check.yaml')
surface = ct.Interface('sticking_coeff_check.yaml', 'Pt_surf', [gas])

class TestUndeclared(utilities.CanteraTest):

Expand Down
3 changes: 3 additions & 0 deletions interfaces/cython/cantera/utils.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ def make_deprecation_warnings_fatal():
message='.*Cantera.*') # for warnings in Cython code
Cxx_make_deprecation_warnings_fatal()

def make_warnings_fatal():# for warnings in Cython code
Cxx_make_warnings_fatal()

def suppress_deprecation_warnings():
warnings.filterwarnings('ignore', category=DeprecationWarning,
module='cantera') # for warnings in Python code
Expand Down
4 changes: 4 additions & 0 deletions src/base/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ Application::Application() :
m_suppress_deprecation_warnings(false),
m_fatal_deprecation_warnings(false),
m_suppress_thermo_warnings(false),
m_fatal_warnings(false),
#if CT_LEGACY_RATE_CONSTANTS
m_use_legacy_rate_constants(true)
#else
Expand Down Expand Up @@ -182,6 +183,9 @@ void Application::warn_deprecated(const std::string& method,
void Application::warn_user(const std::string& method,
const std::string& extra)
{
if (m_fatal_warnings) {
throw CanteraError(method, extra);
}
writelog(fmt::format("CanteraWarning: {}: {}", method, extra));
writelogendl();
}
Expand Down
7 changes: 7 additions & 0 deletions src/base/application.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,12 @@ class Application
//! information can be specified in *extra*.
void warn_user(const std::string& method, const std::string& extra="");

//! Turns Cantera warnings into exceptions. Activated within the test
//! suite to make sure that your warning message are being raised.
void make_warnings_fatal() {
m_fatal_warnings = true;
}

//! Globally disable printing of warnings about problematic thermo data,
//! e.g. NASA polynomials with discontinuities at the midpoint temperature.
void suppress_thermo_warnings(bool suppress=true) {
Expand Down Expand Up @@ -453,6 +459,7 @@ class Application
bool m_suppress_deprecation_warnings;
bool m_fatal_deprecation_warnings;
bool m_suppress_thermo_warnings;
bool m_fatal_warnings;
bool m_use_legacy_rate_constants;

ThreadMessages pMessenger;
Expand Down
5 changes: 5 additions & 0 deletions src/base/global.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ void make_deprecation_warnings_fatal()
app()->make_deprecation_warnings_fatal();
}

void make_warnings_fatal()
{
app()->make_warnings_fatal();
}

void suppress_thermo_warnings(bool suppress)
{
app()->suppress_thermo_warnings(suppress);
Expand Down
22 changes: 22 additions & 0 deletions src/kinetics/Kinetics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,8 @@ void Kinetics::resizeSpecies()
bool Kinetics::addReaction(shared_ptr<Reaction> r, bool resize)
{
r->validate();
r->validate(*this);

if (m_kk == 0) {
init();
}
Expand Down Expand Up @@ -647,4 +649,24 @@ shared_ptr<const Reaction> Kinetics::reaction(size_t i) const
return m_reactions[i];
}

double Kinetics::reactionEnthalpy(const Composition& reactants, const Composition& products)
{
vector_fp hk(nTotalSpecies());
for (size_t n = 0; n < nPhases(); n++) {
thermo(n).getPartialMolarEnthalpies(&hk[m_start[n]]);
}
double rxn_deltaH = 0;
for (const auto& product : products) {
size_t k = kineticsSpeciesIndex(product.first);
double stoich = product.second;
rxn_deltaH += hk[k] * stoich;
}
for (const auto& reactant : reactants) {
size_t k = kineticsSpeciesIndex(reactant.first);
double stoich = reactant.second;
rxn_deltaH -= hk[k] * stoich;
}
return rxn_deltaH;
Comment on lines +654 to +669
Copy link
Member

@ischoegl ischoegl Oct 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to use

/**
* Change in species properties. Given an array of molar species property
* values \f$ z_k, k = 1, \dots, K \f$, return the array of reaction values
* \f[
* \Delta Z_i = \sum_k \nu_{k,i} z_k, i = 1, \dots, I.
* \f]
* For example, if this method is called with the array of standard-state
* molar Gibbs free energies for the species, then the values returned in
* array \c deltaProperty would be the standard-state Gibbs free energies of
* reaction for each reaction.
*
* @param property Input vector of property value. Length: m_kk.
* @param deltaProperty Output vector of deltaRxn. Length: nReactions().
*/
virtual void getReactionDelta(const doublereal* property,
doublereal* deltaProperty);

here? I have recently used

bulk.getPartialMolarEnthalpies(m_grt.data());
getReactionDelta(m_grt.data(), dH.data());

(this used just one phase, with dH being a vector with the length of the number of reactions); I believe this may extend to multiple phases as long as the partial molar enthalpies are in the correct order. You mainly need to pick out the correct reaction index (while this calculates things for all reactions, it does not require lookup; it's a tradeoff, but as it is called during validation speed may not be as critical).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review, I think I have addressed all the comments except this one. I would rather not change this part if it is not going to significantly speed things up

Copy link
Member

@ischoegl ischoegl Oct 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@12Chao … no problem. I’ll leave the final approval to @speth. From my perspective, what you have here may be redundant code that could be avoided, as the same may be achieved with 5 lines of code within your validation functions. Another option would be to make this a local function within Reaction.cpp, as it is not being used elsewhere and I do not think that it is a good fit for Kinetics.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that the reason for adding the deltaEnthalpy function was because you need to be able to evaluate it for a reaction that isn't already part of the Kinetics object. Correct?

Copy link
Member

@ischoegl ischoegl Oct 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@speth … valid point: in this case getReactionDelta does not apply. It still doesn’t quite fit with Kinetics and I believe it would be better to have it as a helper function within Reaction. But it’s not a major sticking point for me.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, it does feel like an awkward addition to the Kinetics class. Given that it relies almost entirely on public member functions of Kinetics (and the one exception, the use of m_start, can be fixed), I can see it more naturally being a member of the Reaction class.

}

}
48 changes: 48 additions & 0 deletions src/kinetics/Reaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,26 @@ void InterfaceReaction::getParameters(AnyMap& reactionNode) const
}
}

void InterfaceReaction::validate(Kinetics& kin)
{
if (is_sticking_coefficient) {
fmt::memory_buffer err_reactions;
double T[] = {200.0, 500.0, 1000.0, 2000.0, 5000.0, 10000.0};
for (size_t i=0; i < 6; i++) {
double k = rate.updateRC(log(T[i]), 1/T[i]);
if (k > 1) {
fmt_append(err_reactions,
"\n Sticking coefficient is greater than 1 for reaction '{}'\n"
" at T = {:.1f}\n",
equation(), T[i]);
}
}
if (err_reactions.size()) {
warn_user("InterfaceReaction::validate", to_string(err_reactions));
}
}
}

ElectrochemicalReaction::ElectrochemicalReaction()
: beta(0.5)
, exchange_current_density_formulation(false)
Expand Down Expand Up @@ -898,6 +918,33 @@ void BlowersMaselInterfaceReaction::validate()
throw InputFileError("BlowersMaselInterfaceReaction::validate", input,
"Undeclared negative pre-exponential factor found in reaction '"
+ equation() + "'");
}
}

void BlowersMaselInterfaceReaction::validate(Kinetics& kin)
{
if (is_sticking_coefficient) {
double original_T = kin.thermo().temperature();
double original_P = kin.thermo().pressure();
fmt::memory_buffer err_reactions;
double T[] = {200.0, 500.0, 1000.0, 2000.0, 5000.0, 10000.0};
size_t length_T = sizeof(T) / sizeof(T[0]);
for (size_t i=0; i < length_T; i++) {
kin.thermo().setState_TP(T[i], original_P);
double rxn_deltaH = kin.reactionEnthalpy(reactants, products);
double k = rate.updateRC(log(T[i]), 1/T[i], rxn_deltaH);
if (k > 1) {
fmt_append(err_reactions,
"\n Sticking coefficient is bigger than 1 for reaction '{}'\n"
" at T = {:.1f}\n",
equation(), T[i]);
}

}
kin.thermo().setState_TP(original_T, original_P);
if (err_reactions.size()) {
warn_user("BlowersMaselInterfaceReaction::validate", to_string(err_reactions));
}
}
}

Expand Down Expand Up @@ -2003,6 +2050,7 @@ std::vector<shared_ptr<Reaction>> getReactions(const AnyValue& items,
for (const auto& node : items.asVector<AnyMap>()) {
shared_ptr<Reaction> R(newReaction(node, kinetics));
R->validate();
R->validate(kinetics);
if (R->valid() && R->checkSpecies(kinetics)) {
all_reactions.emplace_back(R);
}
Expand Down
56 changes: 56 additions & 0 deletions test/data/sticking_coeff_check.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
units: {length: cm, quantity: mol, activation-energy: J/mol}

phases:
- name: gas
thermo: ideal-gas
elements: [O, H, C, N, Ar]
species:
- gri30.yaml/species: [ O2, OH]
skip-undeclared-elements: true
kinetics: gas
reactions:
- gri30.yaml/reactions: declared-species
transport: mixture-averaged
- name: Pt_surf
thermo: ideal-surface
elements: [Pt, H, O, C]
species: [{Pt-surf-species: all}]
kinetics: surface
reactions: [Pt-reactions]

Pt-surf-species:
- name: PT(S)
composition: {Pt: 1}
thermo:
model: NASA7
temperature-ranges: [300.0, 1000.0, 3000.0]
data:
- [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
- [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
- name: OH(S)
composition: {O: 1, H: 1, Pt: 1}
thermo:
model: NASA7
temperature-ranges: [300.0, 1000.0, 3000.0]
data:
- [-2.0340881, 9.3662683e-03, 6.6275214e-07, -5.2074887e-09, 1.7088735e-12,
-2.5319949e+04, 8.9863186]
- [1.8249973, 3.2501565e-03, -3.1197541e-07, -3.4603206e-10, 7.9171472e-14,
-2.6685492e+04, -12.280891]
- name: O(S)
composition: {O: 1, Pt: 1}
thermo:
model: NASA7
temperature-ranges: [300.0, 1000.0, 3000.0]
data:
- [-0.94986904, 7.4042305e-03, -1.0451424e-06, -6.112042e-09, 3.3787992e-12,
-1.3209912e+04, 3.6137905]
- [1.945418, 9.1761647e-04, -1.1226719e-07, -9.9099624e-11, 2.4307699e-14,
-1.4005187e+04, -11.531663]

Pt-reactions:
- equation: O2 + 2 PT(S) => 2 O(S) # Reaction 1
sticking-coefficient: {A: 2.0, b: 0, Ea: 0}
- equation: OH + PT(S) => OH(S) # Reaction 2
type: Blowers-Masel
sticking-coefficient: {A: 2.0, b: 0, Ea0: 0, w: 100000}