Fix for negative pre-exponential factors producing NaN rates
of progress. This bug was reported in the Cantera newsgroup.
The fix consists of replacing
Rc = exp ( mlogA + blogT - Ea / RT)
with
Rc = A * exp (b logT - Ea/RT)
Therefore, the log of A never has to be taken.
Note, this also allows for a zero rate of progress for a reaction.
Consequences:
The permissible range of the rate constant values may be altered.
Numerical roundoff differences will occur, since the order of
operations in key rate constant evalulations has been changed.
Speed of the calculation may be affected. I have no idea which way.
The fix should be considered as provisional. There are different pathways
for fixing this. This is merely the simplest.
This commit is contained in:
parent
228ebc78b1
commit
71ef5ebfcc
2 changed files with 291 additions and 175 deletions
|
|
@ -22,7 +22,7 @@ namespace Cantera {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This rate coefficient manager supports one parameterization of
|
* This rate coefficient manager supports one parameterization of
|
||||||
* any type.
|
* the rate constant of any type.
|
||||||
*/
|
*/
|
||||||
template<class R>
|
template<class R>
|
||||||
class Rate1 {
|
class Rate1 {
|
||||||
|
|
@ -104,7 +104,8 @@ namespace Cantera {
|
||||||
doublereal recipT = 1.0/T;
|
doublereal recipT = 1.0/T;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (; b != e; ++b, ++i) {
|
for (; b != e; ++b, ++i) {
|
||||||
values[m_rxn[i]] = exp(b->update(logT, recipT));
|
// values[m_rxn[i]] = exp(b->update(logT, recipT));
|
||||||
|
values[m_rxn[i]] = b->updateRC(logT, recipT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,200 +20,315 @@
|
||||||
namespace Cantera {
|
namespace Cantera {
|
||||||
|
|
||||||
|
|
||||||
class Arrhenius {
|
class Arrhenius {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static int type(){ return ARRHENIUS; }
|
static int type(){ return ARRHENIUS; }
|
||||||
Arrhenius() : m_b (0.0), m_E (0.0) {}
|
Arrhenius() :
|
||||||
Arrhenius( int csize, const doublereal* c )
|
m_logA(-1.0E300),
|
||||||
: m_b (c[1]), m_E (c[2]) { m_logA = log(c[0]);}
|
m_b (0.0),
|
||||||
Arrhenius( doublereal A, doublereal b, doublereal E)
|
m_E (0.0),
|
||||||
: m_b (b), m_E (E) { m_logA = log(A);}
|
m_A(0.0)
|
||||||
|
{
|
||||||
void update_C(const doublereal* c) {}
|
}
|
||||||
|
Arrhenius(int csize, const doublereal* c) :
|
||||||
doublereal update(doublereal logT, doublereal recipT) const {
|
m_b (c[1]),
|
||||||
return m_logA + m_b*logT - m_E*recipT;
|
m_E (c[2]),
|
||||||
}
|
m_A (c[0])
|
||||||
|
{
|
||||||
/// no longer used
|
if (m_A <= 0.0) {
|
||||||
//doublereal update_dT(doublereal logT, doublereal recipT) const {
|
m_logA = -1.0E300;
|
||||||
// return recipT*(m_b + m_E*recipT);
|
} else {
|
||||||
//}
|
m_logA = log(m_A);
|
||||||
|
}
|
||||||
void writeUpdateRHS(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 << ");" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
doublereal activationEnergy_R() const {
|
|
||||||
return m_E;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool alwaysComputeRate() { return false;}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
doublereal m_logA, m_b, m_E;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class ArrheniusSum {
|
|
||||||
|
|
||||||
public:
|
|
||||||
static int type(){ return ARRHENIUS_SUM; }
|
|
||||||
ArrheniusSum() : m_nterms(0) {}
|
|
||||||
ArrheniusSum( int csize, const doublereal* c ) {
|
|
||||||
m_nterms = 0;
|
|
||||||
addArrheniusTerm(c[0], c[1], c[2]);
|
|
||||||
}
|
|
||||||
void addArrheniusTerm(doublereal A, doublereal b, doublereal E) {
|
|
||||||
m_terms.push_back(Arrhenius(A, b, E));
|
|
||||||
m_nterms++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void update_C(const doublereal* c) {}
|
|
||||||
|
|
||||||
doublereal update(doublereal logT, doublereal recipT) const {
|
|
||||||
int n;
|
|
||||||
doublereal f, fexp = 0.0;
|
|
||||||
for (n = 0; n < m_nterms; n++) {
|
|
||||||
f = m_terms[n].update(logT, recipT);
|
|
||||||
fexp += exp(f);
|
|
||||||
}
|
|
||||||
return log(fexp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// doublereal update_dT(doublereal logT, doublereal recipT) const {
|
|
||||||
// throw CanteraError("ArrheniusSum::update_dT","not implemented.");
|
|
||||||
//}
|
|
||||||
|
|
||||||
void writeUpdateRHS(ostream& s) const {
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
//doublereal activationEnergy_R() const {
|
|
||||||
// return m_E;
|
|
||||||
//}
|
|
||||||
|
|
||||||
static bool alwaysComputeRate() { return true;}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
vector<Arrhenius> m_terms;
|
|
||||||
int m_nterms;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_C(const doublereal* c) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An Arrhenius rate with coverage-dependent terms.
|
* 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.
|
||||||
*/
|
*/
|
||||||
class SurfaceArrhenius {
|
doublereal update(doublereal logT, doublereal recipT) const {
|
||||||
|
return m_logA + m_b*logT - m_E*recipT;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
/**
|
||||||
static int type(){ return ARRHENIUS; }
|
* Update the value the rate constant.
|
||||||
SurfaceArrhenius() : m_b (0.0), m_E (0.0),
|
*
|
||||||
m_acov(0.0), m_ecov(0.0),
|
* This function returns the actual value of the rate constant.
|
||||||
m_mcov(0.0), m_ncov(0), m_nmcov(0)
|
* It can be safely called for negative values of the pre-exponential
|
||||||
{}
|
* factor.
|
||||||
SurfaceArrhenius( int csize, const doublereal* c )
|
*/
|
||||||
: m_b (c[1]), m_E (c[2]),
|
doublereal updateRC(doublereal logT, doublereal recipT) const {
|
||||||
m_acov(0.0), m_ecov(0.0), m_mcov(0.0), m_ncov(0), m_nmcov(0)
|
return m_A * exp(m_b*logT - m_E*recipT);
|
||||||
{ 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) {
|
/// no longer used
|
||||||
m_acov = 0.0;
|
//doublereal update_dT(doublereal logT, doublereal recipT) const {
|
||||||
m_ecov = 0.0;
|
// return recipT*(m_b + m_E*recipT);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
doublereal update(doublereal logT, doublereal recipT) const {
|
void writeUpdateRHS(ostream& s) const {
|
||||||
return m_logA + m_acov + m_b*logT
|
s << " exp(" << m_logA;
|
||||||
- (m_E + m_ecov)*recipT + m_mcov;
|
if (m_b != 0.0) s << " + " << m_b << " * tlog";
|
||||||
}
|
if (m_E != 0.0) s << " - " << m_E << " * rt";
|
||||||
|
s << ");" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
doublereal activationEnergy_R() const {
|
doublereal activationEnergy_R() const {
|
||||||
return m_E + m_ecov;
|
return m_E;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool alwaysComputeRate() { return true;}
|
static bool alwaysComputeRate() { return false;}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
doublereal m_logA, m_b, m_E;
|
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;
|
class ArrheniusSum {
|
||||||
};
|
|
||||||
|
public:
|
||||||
|
static int type(){ return ARRHENIUS_SUM; }
|
||||||
|
ArrheniusSum() : m_nterms(0) {}
|
||||||
|
ArrheniusSum( int csize, const doublereal* c ) {
|
||||||
|
m_nterms = 0;
|
||||||
|
addArrheniusTerm(c[0], c[1], c[2]);
|
||||||
|
}
|
||||||
|
void addArrheniusTerm(doublereal A, doublereal b, doublereal E) {
|
||||||
|
m_terms.push_back(Arrhenius(A, b, E));
|
||||||
|
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 += f;
|
||||||
|
}
|
||||||
|
//if (fsum <= 0.0) {
|
||||||
|
// throw CanteraError("ArrheniusSum::update",
|
||||||
|
// "Error: negative total reaction rate");
|
||||||
|
//}
|
||||||
|
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 += f;
|
||||||
|
}
|
||||||
|
//if (fsum <= 0.0) {
|
||||||
|
// throw CanteraError("ArrheniusSum::update",
|
||||||
|
// "Error: negative total reaction rate");
|
||||||
|
//}
|
||||||
|
return fsum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// doublereal update_dT(doublereal logT, doublereal recipT) const {
|
||||||
|
// throw CanteraError("ArrheniusSum::update_dT","not implemented.");
|
||||||
|
//}
|
||||||
|
|
||||||
|
void writeUpdateRHS(ostream& s) const {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
//doublereal activationEnergy_R() const {
|
||||||
|
// return m_E;
|
||||||
|
//}
|
||||||
|
|
||||||
|
static bool alwaysComputeRate() { return true;}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
vector<Arrhenius> m_terms;
|
||||||
|
int m_nterms;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Arrhenius rate with coverage-dependent terms.
|
||||||
|
*/
|
||||||
|
class SurfaceArrhenius {
|
||||||
|
|
||||||
|
public:
|
||||||
|
static int type(){ return ARRHENIUS; }
|
||||||
|
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
|
#ifdef INCL_TST
|
||||||
|
|
||||||
class TST {
|
class TST {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static int type(){ return TSTRATE; }
|
static int type(){ return TSTRATE; }
|
||||||
TST() {}
|
TST() {}
|
||||||
TST( const vector_fp& c ) {
|
TST( const vector_fp& c ) {
|
||||||
m_b.resize(10);
|
m_b.resize(10);
|
||||||
copy(c.begin(), c.begin() + 10, m_b.begin());
|
copy(c.begin(), c.begin() + 10, m_b.begin());
|
||||||
m_k = int(c[10]);
|
m_k = int(c[10]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_C(const vector_fp& c) {
|
void update_C(const vector_fp& c) {
|
||||||
doublereal ck = c[m_k];
|
doublereal ck = c[m_k];
|
||||||
delta_s0 = m_b[0] + m_b[1]*ck + m_b[2]*ck*ck;
|
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;
|
delta_e0 = m_b[5] + m_b[6]*ck + m_b[7]*ck*ck;
|
||||||
}
|
}
|
||||||
|
|
||||||
doublereal update(doublereal logT, doublereal recipT) const {
|
doublereal update(doublereal logT, doublereal recipT) const {
|
||||||
doublereal delta_s = delta_s0*(1.0 + m_b[3]*logT + m_b[4]*recipT);
|
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);
|
doublereal delta_E = delta_e0*(1.0 + m_b[8]*logT + m_b[9]*recipT);
|
||||||
return logBoltz_Planck + logT + delta_s - delta_E*recipT;
|
return logBoltz_Planck + logT + delta_s - delta_E*recipT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeUpdateRHS(ostream& s) const {}
|
doublereal updateRC(doublereal logT, doublereal recipT) const {
|
||||||
|
double lres = update(logT, recipT);
|
||||||
|
return exp(lres);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
void writeUpdateRHS(ostream& s) const {}
|
||||||
doublereal delta_s0, delta_e0;
|
|
||||||
int m_k;
|
protected:
|
||||||
vector_fp m_b;
|
doublereal delta_s0, delta_e0;
|
||||||
};
|
int m_k;
|
||||||
|
vector_fp m_b;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue