cantera/Cantera/src/kinetics/RxnRates.h
Harry Moffat 263aeb6b35 Added a new way to specify the kinetics reaction rate coefficient
when dealing with electron transfer surface reactions.
This way specifies an exchange current density reaction rate coefficient
in units of amps / m2.  This is slightly more informative for 
electrode reactions. 

The new also preserves the correct treatment of activity coefficients
for these reactions. 

A memo describing this new capability is in the works.
2010-03-01 18:14:07 +00:00

491 lines
12 KiB
C++

/**
* @file RxnRates.h
*
*/
/* $Author$
* $Revision$
* $Date$
*/
// Copyright 2001 California Institute of Technology
#ifndef CT_RXNRATES_H
#define CT_RXNRATES_H
#include "reaction_defs.h"
#include "ctexceptions.h"
namespace Cantera {
//! Arrhenius reaction rate type depends only on temperature
/**
* A reaction rate coefficient of the following form.
*
* \f[
* k_f = A T^b \exp (-E/RT)
* \f]
*
*/
class Arrhenius {
public:
//! return the rate coefficient type.
static int type() {
return ARRHENIUS_REACTION_RATECOEFF_TYPE;
}
//! Default constructor.
Arrhenius() :
m_logA(-1.0E300),
m_b (0.0),
m_E (0.0),
m_A(0.0) {}
//! Constructor with Arrhenius parameters specified with an array.
Arrhenius(int csize, const doublereal* c) :
m_b (c[1]),
m_E (c[2]),
m_A (c[0])
{
if (m_A <= 0.0) {
m_logA = -1.0E300;
} else {
m_logA = log(m_A);
}
}
/// Constructor.
/// @param A pre-exponential. The unit system is
/// (kmol, m, s). The actual units depend on the reaction
/// order and the dimensionality (surface or bulk).
/// @param b Temperature exponent. Non-dimensional.
/// @param E Activation energy in temperature units. Kelvin.
Arrhenius(doublereal A, doublereal b, doublereal E) :
m_b (b),
m_E (E),
m_A (A)
{
if (m_A <= 0.0) {
m_logA = -1.0E300;
} else {
m_logA = log(m_A);
}
}
//! Update concentration-dependent parts of the rate coefficient.
/*!
* For this class, there are no
* concentration-dependent parts, so this method does nothing.
*/
void update_C(const doublereal* c) {
}
/**
* Update the value of the logarithm of the rate constant.
*
* Note, this function should never be called for negative A values.
* If it does then it will produce a negative overflow result, and
* a zero net forwards reaction rate, instead of a negative reaction
* rate constant that is the expected result.
*/
doublereal update(doublereal logT, doublereal recipT) const {
return m_logA + m_b*logT - m_E*recipT;
}
/**
* Update the value the rate constant.
*
* This function returns the actual value of the rate constant.
* It can be safely called for negative values of the pre-exponential
* factor.
*/
doublereal updateRC(doublereal logT, doublereal recipT) const {
return m_A * exp(m_b*logT - m_E*recipT);
}
void writeUpdateRHS(std::ostream& s) const {
s << " exp(" << m_logA;
if (m_b != 0.0) s << " + " << m_b << " * tlog";
if (m_E != 0.0) s << " - " << m_E << " * rt";
s << ");" << std::endl;
}
doublereal activationEnergy_R() const {
return m_E;
}
static bool alwaysComputeRate() { return false;}
protected:
doublereal m_logA, m_b, m_E, m_A;
};
class ArrheniusSum {
public:
static int type() {
return ARRHENIUS_SUM_REACTION_RATECOEFF_TYPE;
}
ArrheniusSum() : m_nterms(0) {}
void addArrheniusTerm(doublereal A, doublereal b, doublereal E) {
if (A > 0.0) {
m_terms.push_back(Arrhenius(A, b, E));
m_sign.push_back(1);
}
else if (A < 0.0) {
m_terms.push_back(Arrhenius(-A, b, E));
m_sign.push_back(-1);
}
m_nterms++;
}
void update_C(const doublereal* c) {}
/**
* Update the value of the logarithm of the rate constant.
*
*/
doublereal update(doublereal logT, doublereal recipT) const {
int n;
doublereal f, fsum = 0.0;
for (n = 0; n < m_nterms; n++) {
f = m_terms[n].updateRC(logT, recipT);
fsum += m_sign[n]*f;
}
return log(fsum);
}
/**
* Update the value the rate constant.
*
* This function returns the actual value of the rate constant.
* It can be safely called for negative values of the pre-exponential
* factor.
*/
doublereal updateRC(doublereal logT, doublereal recipT) const {
int n;
doublereal f, fsum = 0.0;
for (n = 0; n < m_nterms; n++) {
f = m_terms[n].updateRC(logT, recipT);
fsum += m_sign[n]*f;
}
return fsum;
}
void writeUpdateRHS(std::ostream& s) const {
;
}
static bool alwaysComputeRate() { return false;}
protected:
std::vector<Arrhenius> m_terms;
vector_int m_sign;
int m_nterms;
};
/**
* An Arrhenius rate with coverage-dependent terms.
*/
class SurfaceArrhenius {
public:
static int type() {
return ARRHENIUS_REACTION_RATECOEFF_TYPE;
}
SurfaceArrhenius() :
m_logA(-1.0E300),
m_b (0.0),
m_E (0.0),
m_A(0.0),
m_acov(0.0),
m_ecov(0.0),
m_mcov(0.0),
m_ncov(0),
m_nmcov(0)
{
}
SurfaceArrhenius( int csize, const doublereal* c ) :
m_b (c[1]),
m_E (c[2]),
m_A (c[0]),
m_acov(0.0),
m_ecov(0.0),
m_mcov(0.0),
m_ncov(0),
m_nmcov(0)
{
if (m_A <= 0.0) {
m_logA = -1.0E300;
} else {
m_logA = log(c[0]);
}
if (csize >= 7) {
for (int n = 3; n < csize-3; n += 4) {
addCoverageDependence(int(c[n]),
c[n+1], c[n+2], c[n+3]);
}
}
}
void addCoverageDependence(int k, doublereal a,
doublereal m, doublereal e) {
m_ncov++;
m_sp.push_back(k);
m_ac.push_back(a);
m_ec.push_back(e);
if (m != 0.0) {
m_msp.push_back(k);
m_mc.push_back(m);
m_nmcov++;
}
}
void update_C(const doublereal* theta) {
m_acov = 0.0;
m_ecov = 0.0;
m_mcov = 0.0;
int n, k;
doublereal th;
for (n = 0; n < m_ncov; n++) {
k = m_sp[n];
m_acov += m_ac[n] * theta[k];
m_ecov += m_ec[n] * theta[k];
}
for (n = 0; n < m_nmcov; n++) {
k = m_msp[n];
// changed n to k, dgg 1/22/04
th = fmaxx(theta[k], Tiny);
// th = fmaxx(theta[n], Tiny);
m_mcov += m_mc[n]*log(th);
}
}
/**
* Update the value of the logarithm of the rate constant.
*
* This calculation is not safe for negative values of
* the preexponential.
*/
doublereal update(doublereal logT, doublereal recipT) const {
return m_logA + m_acov + m_b*logT
- (m_E + m_ecov)*recipT + m_mcov;
}
/**
* Update the value the rate constant.
*
* This function returns the actual value of the rate constant.
* It can be safely called for negative values of the pre-exponential
* factor.
*/
doublereal updateRC(doublereal logT, doublereal recipT) const {
return m_A * exp(m_acov + m_b*logT - (m_E + m_ecov)*recipT + m_mcov);
}
doublereal activationEnergy_R() const {
return m_E + m_ecov;
}
static bool alwaysComputeRate() { return true;}
protected:
doublereal m_logA, m_b, m_E, m_A;
doublereal m_acov, m_ecov, m_mcov;
vector_int m_sp, m_msp;
vector_fp m_ac, m_ec, m_mc;
int m_ncov, m_nmcov;
};
#ifdef INCL_TST
class TST {
public:
static int type(){ return TSTRATE; }
TST() {}
TST( const vector_fp& c ) {
m_b.resize(10);
copy(c.begin(), c.begin() + 10, m_b.begin());
m_k = int(c[10]);
}
void update_C(const vector_fp& c) {
doublereal ck = c[m_k];
delta_s0 = m_b[0] + m_b[1]*ck + m_b[2]*ck*ck;
delta_e0 = m_b[5] + m_b[6]*ck + m_b[7]*ck*ck;
}
doublereal update(doublereal logT, doublereal recipT) const {
doublereal delta_s = delta_s0*(1.0 + m_b[3]*logT + m_b[4]*recipT);
doublereal delta_E = delta_e0*(1.0 + m_b[8]*logT + m_b[9]*recipT);
return logBoltz_Planck + logT + delta_s - delta_E*recipT;
}
doublereal updateRC(doublereal logT, doublereal recipT) const {
doublereal lres = update(logT, recipT);
return exp(lres);
}
void writeUpdateRHS(std::ostream& s) const {}
protected:
doublereal delta_s0, delta_e0;
int m_k;
vector_fp m_b;
};
#endif
//! Arrhenius reaction rate type depends only on temperature
/**
* A reaction rate coefficient of the following form.
*
* \f[
* k_f = A T^b \exp (-E/RT)
* \f]
*
*/
class ExchangeCurrent {
public:
//! return the rate coefficient type.
static int type() {
return EXCHANGE_CURRENT_REACTION_RATECOEFF_TYPE;
}
//! Default constructor.
ExchangeCurrent() :
m_logA(-1.0E300),
m_b (0.0),
m_E (0.0),
m_A(0.0) {}
//! Constructor with Arrhenius parameters specified with an array.
ExchangeCurrent(int csize, const doublereal* c) :
m_b (c[1]),
m_E (c[2]),
m_A (c[0])
{
if (m_A <= 0.0) {
m_logA = -1.0E300;
} else {
m_logA = log(m_A);
}
}
/// Constructor.
/// @param A pre-exponential. The unit system is
/// (kmol, m, s). The actual units depend on the reaction
/// order and the dimensionality (surface or bulk).
/// @param b Temperature exponent. Non-dimensional.
/// @param E Activation energy in temperature units. Kelvin.
ExchangeCurrent(doublereal A, doublereal b, doublereal E) :
m_b (b),
m_E (E),
m_A (A)
{
if (m_A <= 0.0) {
m_logA = -1.0E300;
} else {
m_logA = log(m_A);
}
}
//! Update concentration-dependent parts of the rate coefficient.
/*!
* For this class, there are no
* concentration-dependent parts, so this method does nothing.
*/
void update_C(const doublereal* c) {
}
/**
* Update the value of the logarithm of the rate constant.
*
* Note, this function should never be called for negative A values.
* If it does then it will produce a negative overflow result, and
* a zero net forwards reaction rate, instead of a negative reaction
* rate constant that is the expected result.
*/
doublereal update(doublereal logT, doublereal recipT) const {
return m_logA + m_b*logT - m_E*recipT;
}
/**
* Update the value the rate constant.
*
* This function returns the actual value of the rate constant.
* It can be safely called for negative values of the pre-exponential
* factor.
*/
doublereal updateRC(doublereal logT, doublereal recipT) const {
return m_A * exp(m_b*logT - m_E*recipT);
}
void writeUpdateRHS(std::ostream& s) const {
s << " exp(" << m_logA;
if (m_b != 0.0) s << " + " << m_b << " * tlog";
if (m_E != 0.0) s << " - " << m_E << " * rt";
s << ");" << std::endl;
}
doublereal activationEnergy_R() const {
return m_E;
}
static bool alwaysComputeRate() { return false;}
protected:
doublereal m_logA, m_b, m_E, m_A;
};
// class LandauTeller {
// public:
// static int type(){ return LANDAUTELLER; }
// LandauTeller(){}
// LandauTeller( const vector_fp& c ) : m_c(c) { m_c[0] = log(c[0]); }
// doublereal update(doublereal logT, doublereal recipT) const {
// return m_c[0] + m_c[1]*tt[1] - m_c[2]*tt[2]
// + m_c[3]*tt[3] + m_c[4]*tt[4];
// }
// //void writeUpdateRHS(ostream& s) const {
// // s << exp(m_logA);
// // s << " * exp(";
// // if (m_b != 0.0) s << m_b << " * tlog";
// // if (m_E != 0.0) s << " - " << m_E << " * rt";
// // if (m_E != 0.0) s << " - " << m_E << " * rt";
// // s << ");" << endl;
// // }
// //}
// protected:
// doublereal m_logA, m_b, m_E;
// };
//}
}
#endif