[Reactor] Always check that input/output are finite

This causes problems to be caught early, where they can at least sometimes be
handled as recoverable intergrator errors, rather than letting NaN values
propagate through the solution.
This commit is contained in:
Ray Speth 2015-08-24 12:27:07 -04:00
parent 86835a5eeb
commit 6e138d0ae4
5 changed files with 29 additions and 20 deletions

View file

@ -521,6 +521,15 @@ void deepStdVectorPointerCopy(const std::vector<D*> &fromVec, std::vector<D*> &t
//! Check to see that a number is finite (not NaN, +Inf or -Inf) //! Check to see that a number is finite (not NaN, +Inf or -Inf)
void checkFinite(const double tmp); void checkFinite(const double tmp);
//! Check to see that all elements in an array are finite
/*!
* Throws an exception if any element is NaN, +Inf, or -Inf
* @param name Name to be used in the exception message if the check fails
* @param values Array of *N* values to be checked
* @param N Number of elements in *values*
*/
void checkFinite(const std::string& name, double* values, size_t N);
//! Const accessor for a value in a std::map. //! Const accessor for a value in a std::map.
/*! /*!
* This is a const alternative to operator[]. Roughly equivalent to the 'at' * This is a const alternative to operator[]. Roughly equivalent to the 'at'

View file

@ -13,6 +13,8 @@
#include <stdexcept> #include <stdexcept>
#include <cstdio> #include <cstdio>
#include "cantera/base/stringUtils.h"
#include "cantera/base/ctexceptions.h"
// We expect that there will be special casing based on the computer // We expect that there will be special casing based on the computer
// system here // system here
@ -54,4 +56,20 @@ void checkFinite(const double tmp)
} }
} }
void checkFinite(const std::string& name, double* values, size_t N)
{
for (size_t i = 0; i < N; i++) {
if (!finite(values[i])) {
std::string message = name + " contains non-finite elements:\n\n";
for (size_t j = 0; j < N; j++) {
if (!finite(values[j])) {
message += name + "[" + int2str(j) + "] = " +
fp2str(values[j]) + "\n";
}
}
throw CanteraError("checkFinite", message);
}
}
}
} }

View file

@ -56,11 +56,6 @@ void IdealGasReactor::initialize(doublereal t0)
void IdealGasReactor::updateState(doublereal* y) void IdealGasReactor::updateState(doublereal* y)
{ {
for (size_t i = 0; i < m_nv; i++) {
AssertFinite(y[i], "IdealGasReactor::updateState",
"y[" + int2str(i) + "] is not finite");
}
// The components of y are [0] the total mass, [1] the total volume, // The components of y are [0] the total mass, [1] the total volume,
// [2] the temperature, [3...K+3] are the mass fractions of each species, // [2] the temperature, [3...K+3] are the mass fractions of each species,
// and [K+3...] are the coverages of surface species on each wall. // and [K+3...] are the coverages of surface species on each wall.
@ -142,11 +137,6 @@ void IdealGasReactor::evalEqs(doublereal time, doublereal* y,
ydot[2] = 0; ydot[2] = 0;
} }
for (size_t i = 0; i < m_nv; i++) {
AssertFinite(ydot[i], "IdealGasReactor::evalEqs",
"ydot[" + int2str(i) + "] is not finite");
}
resetSensitivity(params); resetSensitivity(params);
} }

View file

@ -128,11 +128,6 @@ void Reactor::syncState()
void Reactor::updateState(doublereal* y) void Reactor::updateState(doublereal* y)
{ {
for (size_t i = 0; i < m_nv; i++) {
AssertFinite(y[i], "Reactor::updateState",
"y[" + int2str(i) + "] is not finite");
}
// The components of y are [0] the total mass, [1] the total volume, // The components of y are [0] the total mass, [1] the total volume,
// [2] the total internal energy, [3...K+3] are the mass fractions of each // [2] the total internal energy, [3...K+3] are the mass fractions of each
// species, and [K+3...] are the coverages of surface species on each wall. // species, and [K+3...] are the coverages of surface species on each wall.
@ -267,11 +262,6 @@ void Reactor::evalEqs(doublereal time, doublereal* y,
} }
ydot[0] = dmdt; ydot[0] = dmdt;
for (size_t i = 0; i < m_nv; i++) {
AssertFinite(ydot[i], "Reactor::evalEqs",
"ydot[" + int2str(i) + "] is not finite");
}
resetSensitivity(params); resetSensitivity(params);
} }

View file

@ -156,6 +156,7 @@ void ReactorNet::eval(doublereal t, doublereal* y,
ydot + m_start[n], p + pstart); ydot + m_start[n], p + pstart);
pstart += m_nparams[n]; pstart += m_nparams[n];
} }
checkFinite("ydot", ydot, m_nv);
} }
void ReactorNet::evalJacobian(doublereal t, doublereal* y, void ReactorNet::evalJacobian(doublereal t, doublereal* y,
@ -186,6 +187,7 @@ void ReactorNet::evalJacobian(doublereal t, doublereal* y,
void ReactorNet::updateState(doublereal* y) void ReactorNet::updateState(doublereal* y)
{ {
checkFinite("y", y, m_nv);
for (size_t n = 0; n < m_reactors.size(); n++) { for (size_t n = 0; n < m_reactors.size(); n++) {
m_reactors[n]->updateState(y + m_start[n]); m_reactors[n]->updateState(y + m_start[n]);
} }