detecting the NAN and INF values during VFP calculation

and give warning messages when they happen, since they can be the
culprits of the termination of simulation later.

For ADB related, I did not find a good way to do the detection, so there
is no warning message given.
This commit is contained in:
Kai Bao 2018-11-13 15:30:18 +01:00
parent 32b00b61f8
commit afcdbcf202
3 changed files with 34 additions and 18 deletions

View File

@ -365,7 +365,7 @@ spdiag(const AutoDiffBlock<double>::V& d)
public:
typedef AutoDiffBlock<Scalar> ADB;
enum CriterionForLeftElement { GreaterEqualZero, GreaterZero, Zero, NotEqualZero, LessZero, LessEqualZero, NotNaN };
enum CriterionForLeftElement { GreaterEqualZero, GreaterZero, Zero, NotEqualZero, LessZero, LessEqualZero, NotNaN, NotNaNInf };
Selector(const typename ADB::V& selection_basis,
CriterionForLeftElement crit = GreaterEqualZero)
@ -400,6 +400,9 @@ spdiag(const AutoDiffBlock<double>::V& d)
case NotNaN:
chooseleft = !isnan(selection_basis[i]);
break;
case NotNaNInf:
chooseleft = !isnan(selection_basis[i]) && !std::isinf(selection_basis[i]);
break;
default:
OPM_THROW(std::logic_error, "No such criterion: " << crit);
}

View File

@ -21,6 +21,7 @@
#ifndef OPM_AUTODIFF_VFPHELPERS_HPP_
#define OPM_AUTODIFF_VFPHELPERS_HPP_
#include <opm/common/OpmLog/OpmLog.hpp>
#include <cmath>
#include <opm/common/ErrorMacros.hpp>
@ -37,19 +38,31 @@ namespace detail {
/**
* Returns zero if input value is NaN
* Returns zero if input value is NaN of INF
*/
inline double zeroIfNan(const double& value) {
return (std::isnan(value)) ? 0.0 : value;
inline double zeroIfNanInf(const double& value) {
const bool nan_or_inf = std::isnan(value) || std::isinf(value);
if (nan_or_inf) {
OpmLog::warning("NAN_OR_INF_VFP", "NAN or INF value encountered during VFP calculation, the value is set to zero");
}
return nan_or_inf ? 0.0 : value;
}
/**
* Returns zero if input value is NaN
* Returns zero if input value is NaN or INF
*/
template <class EvalWell>
inline EvalWell zeroIfNan(const EvalWell& value) {
return (std::isnan(value.value())) ? 0.0 : value;
inline EvalWell zeroIfNanInf(const EvalWell& value) {
const bool nan_or_inf = std::isnan(value.value()) || std::isinf(value.value());
if (nan_or_inf) {
OpmLog::warning("NAN_OR_INF_VFP_EVAL", "NAN or INF Evalution encountered during VFP calculation, the Evalution is set to zero");
}
return nan_or_inf ? 0.0 : value;
}
@ -120,14 +133,14 @@ static T getWFR(const T& aqua, const T& liquid, const T& vapour,
case VFPProdTable::WFR_WOR: {
//Water-oil ratio = water / oil
T wor = aqua / liquid;
return zeroIfNan(wor);
return zeroIfNanInf(wor);
}
case VFPProdTable::WFR_WCT:
//Water cut = water / (water + oil)
return zeroIfNan(aqua / (aqua + liquid));
return zeroIfNanInf(aqua / (aqua + liquid));
case VFPProdTable::WFR_WGR:
//Water-gas ratio = water / gas
return zeroIfNan(aqua / vapour);
return zeroIfNanInf(aqua / vapour);
case VFPProdTable::WFR_INVALID: //Intentional fall-through
default:
OPM_THROW(std::logic_error, "Invalid WFR_TYPE: '" << type << "'");
@ -149,13 +162,13 @@ static T getGFR(const T& aqua, const T& liquid, const T& vapour,
switch(type) {
case VFPProdTable::GFR_GOR:
// Gas-oil ratio = gas / oil
return zeroIfNan(vapour / liquid);
return zeroIfNanInf(vapour / liquid);
case VFPProdTable::GFR_GLR:
// Gas-liquid ratio = gas / (oil + water)
return zeroIfNan(vapour / (liquid + aqua));
return zeroIfNanInf(vapour / (liquid + aqua));
case VFPProdTable::GFR_OGR:
// Oil-gas ratio = oil / gas
return zeroIfNan(liquid / vapour);
return zeroIfNanInf(liquid / vapour);
case VFPProdTable::GFR_INVALID: //Intentional fall-through
default:
OPM_THROW(std::logic_error, "Invalid GFR_TYPE: '" << type << "'");

View File

@ -37,15 +37,15 @@ typedef AutoDiffBlock<double> ADB;
/**
* Returns zero for every entry in the ADB which is NaN
*/
inline ADB zeroIfNan(const ADB& values) {
Selector<ADB::V::Scalar> not_nan_selector(values.value(), Selector<ADB::V::Scalar>::NotNaN);
* * Returns zero for every entry in the ADB which is NaN or INF
* */
inline ADB zeroIfNanInf(const ADB& values) {
Selector<ADB::V::Scalar> not_nan_inf_selector(values.value(), Selector<ADB::V::Scalar>::NotNaNInf);
const ADB::V z = ADB::V::Zero(values.size());
const ADB zero = ADB::constant(z, values.blockPattern());
ADB retval = not_nan_selector.select(values, zero);
ADB retval = not_nan_inf_selector.select(values, zero);
return retval;
}