Merge pull request #5592 from bska/top-level-sfunc-check-mgr

Add Top Level Container for Saturation Function Consistency Checks
This commit is contained in:
Atgeirr Flø Rasmussen 2024-10-16 12:02:55 +02:00 committed by GitHub
commit 585627295f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 2512 additions and 33 deletions

View File

@ -221,6 +221,7 @@ if (HAVE_ECL_INPUT)
opm/simulators/utils/satfunc/GasPhaseConsistencyChecks.cpp
opm/simulators/utils/satfunc/OilPhaseConsistencyChecks.cpp
opm/simulators/utils/satfunc/PhaseCheckBase.cpp
opm/simulators/utils/satfunc/SatfuncConsistencyCheckManager.cpp
opm/simulators/utils/satfunc/SatfuncConsistencyChecks.cpp
opm/simulators/utils/satfunc/ScaledSatfuncCheckPoint.cpp
opm/simulators/utils/satfunc/ThreePointHorizontalConsistencyChecks.cpp
@ -412,6 +413,7 @@ if (HAVE_ECL_INPUT)
tests/test_GasSatfuncConsistencyChecks.cpp
tests/test_OilSatfuncConsistencyChecks.cpp
tests/test_SatfuncCheckPoint.cpp
tests/test_SatfuncConsistencyCheckManager.cpp
tests/test_SatfuncConsistencyChecks.cpp
tests/test_SatfuncConsistencyChecks_parallel.cpp
tests/test_ThreePointHorizontalSatfuncConsistencyChecks.cpp
@ -1057,6 +1059,7 @@ if (HAVE_ECL_INPUT)
opm/simulators/utils/satfunc/OilPhaseConsistencyChecks.hpp
opm/simulators/utils/satfunc/PhaseCheckBase.hpp
opm/simulators/utils/satfunc/SatfuncCheckPointInterface.hpp
opm/simulators/utils/satfunc/SatfuncConsistencyCheckManager.hpp
opm/simulators/utils/satfunc/SatfuncConsistencyChecks.hpp
opm/simulators/utils/satfunc/ScaledSatfuncCheckPoint.hpp
opm/simulators/utils/satfunc/ThreePointHorizontalConsistencyChecks.hpp

View File

@ -0,0 +1,506 @@
/*
Copyright 2024 Equinor AS
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <opm/simulators/utils/satfunc/SatfuncConsistencyCheckManager.hpp>
#include <opm/common/OpmLog/OpmLog.hpp>
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
#include <opm/input/eclipse/EclipseState/EndpointScaling.hpp>
#include <opm/input/eclipse/EclipseState/Grid/FieldProps.hpp>
#include <opm/input/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
#include <opm/input/eclipse/EclipseState/Grid/SatfuncPropertyInitializers.hpp>
#include <opm/input/eclipse/EclipseState/Phase.hpp>
#include <opm/input/eclipse/EclipseState/Runspec.hpp>
#include <opm/material/fluidmatrixinteractions/EclEpsGridProperties.hpp>
#include <opm/material/fluidmatrixinteractions/EclEpsScalingPoints.hpp>
#include <opm/simulators/utils/satfunc/SatfuncCheckPointInterface.hpp>
#include <opm/simulators/utils/satfunc/SatfuncConsistencyChecks.hpp>
#include <opm/simulators/utils/satfunc/ScaledSatfuncCheckPoint.hpp>
#include <opm/simulators/utils/satfunc/UnscaledSatfuncCheckPoint.hpp>
#include <opm/simulators/utils/satfunc/GasPhaseConsistencyChecks.hpp>
#include <opm/simulators/utils/satfunc/OilPhaseConsistencyChecks.hpp>
#include <opm/simulators/utils/satfunc/ThreePointHorizontalConsistencyChecks.hpp>
#include <opm/simulators/utils/satfunc/WaterPhaseConsistencyChecks.hpp>
#include <algorithm>
#include <array>
#include <cstddef>
#include <functional>
#include <initializer_list>
#include <memory>
#include <stdexcept>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include <fmt/format.h>
namespace {
Opm::satfunc::RawTableEndPoints
rawTableEndpoints(const Opm::EclipseState& eclipseState)
{
const auto& rspec = eclipseState.runspec();
return Opm::satfunc::getRawTableEndpoints
(eclipseState.getTableManager(),
rspec.phases(),
rspec.saturationFunctionControls()
.minimumRelpermMobilityThreshold());
}
Opm::satfunc::RawFunctionValues
rawFunctionValues(const Opm::EclipseState& eclipseState,
const Opm::satfunc::RawTableEndPoints& rtep)
{
return Opm::satfunc::getRawFunctionValues
(eclipseState.getTableManager(),
eclipseState.runspec().phases(), rtep);
}
} // Anonymous namespace
// ---------------------------------------------------------------------------
template <typename Scalar>
Opm::Satfunc::PhaseChecks::SatfuncConsistencyCheckManager<Scalar>::
SatfuncConsistencyCheckManager(const std::size_t numSamplePoints,
const EclipseState& eclipseState,
const LocalToGlobal& localToGlobal)
: eclipseState_ { std::cref(eclipseState) }
, localToGlobal_ { localToGlobal }
, rtep_ { rawTableEndpoints(eclipseState) }
, rfunc_ { rawFunctionValues(eclipseState, rtep_) }
{
// Note: This setup is limited to
// 1. Drainage only--no hysteresis
// 2. Non-directional relative permeability
// 3. Relative permeability only--no capillary pressure
this->configureCurveChecks(numSamplePoints);
this->addChecks();
}
template <typename Scalar>
bool Opm::Satfunc::PhaseChecks::SatfuncConsistencyCheckManager<Scalar>::
anyFailedStandardChecks() const
{
return std::any_of(this->curves_.begin(), this->curves_.end(),
[](const auto& curve)
{ return curve.checks.anyFailedStandardChecks(); });
}
template <typename Scalar>
bool Opm::Satfunc::PhaseChecks::SatfuncConsistencyCheckManager<Scalar>::
anyFailedCriticalChecks() const
{
return std::any_of(this->curves_.begin(), this->curves_.end(),
[](const auto& curve)
{ return curve.checks.anyFailedCriticalChecks(); });
}
template <typename Scalar>
void Opm::Satfunc::PhaseChecks::SatfuncConsistencyCheckManager<Scalar>::
reportFailures(const ViolationLevel level,
const ReportRecordOutput& emitReportRecord) const
{
if (! this->isRoot_) {
return;
}
this->curveLoop([level, &emitReportRecord](const auto& curve)
{
curve.checks.reportFailures(level, emitReportRecord);
});
}
// ===========================================================================
// Private member functions for SatfuncConsistencyCheckManager template
// ===========================================================================
template <typename Scalar>
Opm::Satfunc::PhaseChecks::SatfuncConsistencyCheckManager<Scalar>::
CurveCollection::CurveCollection(std::unique_ptr<SatfuncCheckPointInterface<Scalar>> point_arg,
std::string_view pointName,
const std::size_t numSamplePoints)
: point { std::move(point_arg) }
, checks { pointName, numSamplePoints }
{}
// ---------------------------------------------------------------------------
template <typename Scalar>
void Opm::Satfunc::PhaseChecks::SatfuncConsistencyCheckManager<Scalar>::
warnIfDirectionalOrIrreversibleEPS() const
{
if (! this->isRoot_) { return; }
if (const auto& eps = this->eclipseState_.get().runspec().endpointScaling(); !eps) {
// End-point scaling not active in run. Don't need to check
// anything else.
return;
}
else if (eps.directional() || eps.irreversible()) {
OpmLog::warning("Directional and/or irreversible end-point "
"scaling is currently not included in the "
"saturation function consistency checks");
}
}
template <typename Scalar>
void Opm::Satfunc::PhaseChecks::SatfuncConsistencyCheckManager<Scalar>::
runCellChecks(const int cellIdx)
{
this->curveLoop([cellIdx, endPoints = EclEpsScalingPointsInfo<Scalar>{}]
(auto& curve) mutable
{
const auto pointID = curve.point->pointID(cellIdx);
if (! pointID.has_value()) {
// Check does not apply to this cell for 'curve'. Might be
// because it's a region based check and we already ran the
// checks for this particular underlying region.
return;
}
curve.point->populateCheckPoint(cellIdx, endPoints);
curve.checks.checkEndpoints(*pointID, endPoints);
});
}
template <typename Scalar>
void Opm::Satfunc::PhaseChecks::SatfuncConsistencyCheckManager<Scalar>::
configureCurveChecks(const std::size_t numSamplePoints)
{
const auto unscaledChecks =
this->configureUnscaledCurveChecks("SATNUM", numSamplePoints);
if (unscaledChecks == nullptr) {
// SATNUM array does not exist (unexpected), or end-point scaling is
// not active in the current run. There's no need to configure
// consistency checks for the scaled curves.
return;
}
const auto useImbibition = false;
this->configureScaledCurveChecks(*unscaledChecks,
useImbibition,
numSamplePoints);
}
template <typename Scalar>
std::unique_ptr<Opm::Satfunc::PhaseChecks::UnscaledSatfuncCheckPoint<Scalar>>
Opm::Satfunc::PhaseChecks::SatfuncConsistencyCheckManager<Scalar>::
configureUnscaledCurveChecks(const std::string& regionName,
const std::size_t numSamplePoints)
{
const auto& fp = this->eclipseState_.get().fieldProps();
if (! fp.has_int(regionName)) {
// Region property array (SATNUM, IMBNUM, &c) not available.
// Nothing to do.
return {};
}
using UEP = typename UnscaledSatfuncCheckPoint<Scalar>::UnscaledEndPoints;
const auto regIdxOffset = 1; // regIdx contains one-based region indices.
auto unscaledChecks = std::make_unique<UnscaledSatfuncCheckPoint<Scalar>>
(&fp.get_int(regionName), regIdxOffset, UEP { &this->rtep_, &this->rfunc_ });
if (! this->eclipseState_.get().runspec().endpointScaling()) {
// Include consistency checks for the unscaled/input/tabulated
// saturation functions only if end-point scaling is NOT enabled.
this->curves_.emplace_back
(std::move(unscaledChecks), regionName, numSamplePoints);
// Return nullptr because there are no scaled curves in this run and
// we therefore do not need to configure consistency checks for such
// curves.
return {};
}
// If we get here then the run includes end-point scaling. Return
// sampling points on the unscaled curve as the fall-back points for the
// scaled curve. Returning a non-null pointer here also lets the caller
// know that we need to configure the associate consistency checks for
// the scaled curves.
return unscaledChecks;
}
template <typename Scalar>
void Opm::Satfunc::PhaseChecks::SatfuncConsistencyCheckManager<Scalar>::
configureScaledCurveChecks(const UnscaledSatfuncCheckPoint<Scalar>& unscaledChecks,
const bool useImbibition,
const std::size_t numSamplePoints)
{
this->gridProps_.emplace_back(this->eclipseState_, useImbibition);
const auto& gdims = this->eclipseState_.get().gridDims();
auto& curve = this->curves_.emplace_back
(std::make_unique<ScaledSatfuncCheckPoint<Scalar>>
(unscaledChecks, &this->eclipseState_.get(),
&this->gridProps_.back(), this->localToGlobal_),
"Grid Block", numSamplePoints);
const auto nchar = std::max({
fmt::formatted_size("{}", gdims.getNX()),
fmt::formatted_size("{}", gdims.getNY()),
fmt::formatted_size("{}", gdims.getNZ()),
});
curve.checks.setPointIDFormatCallback([nchar, gdims](const std::size_t globalCell)
{
const auto ijk = gdims.getIJK(globalCell);
return fmt::format("({1:>{0}}, {2:>{0}}, {3:>{0}})", nchar,
ijk[0] + 1, ijk[1] + 1, ijk[2] + 1);
});
}
namespace {
/// Factory for creating individual end-point checks.
///
/// \tparam Scalar Element type. Typically \c float or \c double.
template <typename Scalar>
class CheckCreationFactory
{
public:
/// Constructor
///
/// \param[in] phases Run's active phases. Needed to determine
/// which end-point checks to include in the test set.
///
/// \param[in] threePointScaling Whether or not run uses the
/// alternative, three-point method for horizontal saturation
/// function end-point scaling ("SCALECRS = YES").
explicit CheckCreationFactory(const Opm::Phases& phases,
const bool threePointScaling);
/// Start of sequence of end-point check creation functions.
auto begin() const { return this->creationFunctions_.begin(); }
/// End of sequence of end-point check creation functions.
auto end() const { return this->creationFunctions_.end(); }
private:
/// Convenience type alias for individual checks.
using Check = typename Opm::SatfuncConsistencyChecks<Scalar>::Check;
/// Type alias for a check creation function.
using CreationFunction = std::function<std::unique_ptr<Check>()>;
/// Collection of pertinent test creation functions.
std::vector<CreationFunction> creationFunctions_{};
/// Incorporate end-point checks for an active oil phase.
///
/// \param[in] phases Run's active phases. Needed to determine
/// which of the two-phase G/O and/or O/W end-point checks to
/// include in the test set.
void addOilChecks(const Opm::Phases& phases);
/// Incorporate end-point checks for the two-phase G/O system.
void addGasOilChecks();
/// Incorporate end-point checks for the two-phase O/W system.
void addOilWaterChecks();
/// Incorporate end-point checks for an active gas phase.
void addGasChecks();
/// Incorporate end-point checks for an active water phase.
void addWaterChecks();
/// Incorporate end-point checks for the alternative, three-point
/// scaling method ("SCALECRS = YES").
///
/// \param[in] phases Run's active phases. Needed to determine
/// which of the two-phase G/O and/or O/W end-point checks to
/// include in the test set.
void addThreePointChecks(const Opm::Phases& phases);
};
template <typename Scalar>
CheckCreationFactory<Scalar>::CheckCreationFactory(const Opm::Phases& phases,
const bool threePointScaling)
{
if (phases.active(Opm::Phase::OIL)) {
this->addOilChecks(phases);
}
if (phases.active(Opm::Phase::GAS)) {
this->addGasChecks();
}
if (phases.active(Opm::Phase::WATER)) {
this->addWaterChecks();
}
if (threePointScaling && phases.active(Opm::Phase::OIL)) {
this->addThreePointChecks(phases);
}
}
template <typename Scalar>
void CheckCreationFactory<Scalar>::addOilChecks(const Opm::Phases& phases)
{
if (phases.active(Opm::Phase::GAS)) {
this->addGasOilChecks();
}
if (phases.active(Opm::Phase::WATER)) {
this->addOilWaterChecks();
}
}
template <typename Scalar>
void CheckCreationFactory<Scalar>::addGasOilChecks()
{
namespace OChecks = Opm::Satfunc::PhaseChecks::Oil;
this->creationFunctions_.insert(this->creationFunctions_.end(), {
CreationFunction { []() { return std::make_unique<OChecks::SOcr_GO<Scalar>>(); } },
CreationFunction { []() { return std::make_unique<OChecks::SOmin_GO<Scalar>>(); } },
CreationFunction { []() { return std::make_unique<OChecks::MobileOil_GO_SGmin<Scalar>>(); } },
CreationFunction { []() { return std::make_unique<OChecks::MobileOil_GO_SGcr<Scalar>>(); } },
});
}
template <typename Scalar>
void CheckCreationFactory<Scalar>::addOilWaterChecks()
{
namespace OChecks = Opm::Satfunc::PhaseChecks::Oil;
this->creationFunctions_.insert(this->creationFunctions_.end(), {
CreationFunction { []() { return std::make_unique<OChecks::SOcr_OW<Scalar>>(); } },
CreationFunction { []() { return std::make_unique<OChecks::SOmin_OW<Scalar>>(); } },
CreationFunction { []() { return std::make_unique<OChecks::MobileOil_OW_SWmin<Scalar>>(); } },
CreationFunction { []() { return std::make_unique<OChecks::MobileOil_OW_SWcr<Scalar>>(); } },
});
}
template <typename Scalar>
void CheckCreationFactory<Scalar>::addGasChecks()
{
namespace GChecks = Opm::Satfunc::PhaseChecks::Gas;
this->creationFunctions_.insert(this->creationFunctions_.end(), {
CreationFunction { []() { return std::make_unique<GChecks::SGmin<Scalar>>(); } },
CreationFunction { []() { return std::make_unique<GChecks::SGmax<Scalar>>(); } },
CreationFunction { []() { return std::make_unique<GChecks::SGcr <Scalar>>(); } },
});
}
template <typename Scalar>
void CheckCreationFactory<Scalar>::addWaterChecks()
{
namespace WChecks = Opm::Satfunc::PhaseChecks::Water;
this->creationFunctions_.insert(this->creationFunctions_.end(), {
CreationFunction { []() { return std::make_unique<WChecks::SWmin<Scalar>>(); } },
CreationFunction { []() { return std::make_unique<WChecks::SWmax<Scalar>>(); } },
CreationFunction { []() { return std::make_unique<WChecks::SWcr <Scalar>>(); } },
});
}
template <typename Scalar>
void CheckCreationFactory<Scalar>::addThreePointChecks(const Opm::Phases& phases)
{
namespace TChecks = Opm::Satfunc::PhaseChecks::ThreePointHorizontal;
if (phases.active(Opm::Phase::GAS)) {
this->creationFunctions_.emplace_back
([]() { return std::make_unique<TChecks::DisplacingOil_GO<Scalar>>(); });
}
if (phases.active(Opm::Phase::WATER)) {
this->creationFunctions_.emplace_back
([]() { return std::make_unique<TChecks::DisplacingOil_OW<Scalar>>(); });
}
}
} // Anonymous namespace
template <typename Scalar>
void Opm::Satfunc::PhaseChecks::SatfuncConsistencyCheckManager<Scalar>::addChecks()
{
const auto& rspec = this->eclipseState_.get().runspec();
const auto checkCreationFactory = CheckCreationFactory<Scalar> {
rspec.phases(),
[&eps = rspec.endpointScaling()]() {
return eps && eps.threepoint();
}()
};
this->curveLoop([&checkCreationFactory](auto& curve)
{
curve.checks.resetCheckSet();
for (const auto& makeCheck : checkCreationFactory) {
curve.checks.addCheck(makeCheck());
}
curve.checks.finaliseCheckSet();
});
}
template <typename Scalar>
void Opm::Satfunc::PhaseChecks::SatfuncConsistencyCheckManager<Scalar>::
collectFailures(const Parallel::Communication& comm)
{
this->curveLoop([root = this->root_, comm](auto& curve)
{
curve.checks.collectFailures(root, comm);
});
}
template <typename Scalar>
template <typename Body>
void Opm::Satfunc::PhaseChecks::SatfuncConsistencyCheckManager<Scalar>::
curveLoop(Body&& body)
{
std::for_each(this->curves_.begin(), this->curves_.end(),
std::forward<Body>(body));
}
template <typename Scalar>
template <typename Body>
void Opm::Satfunc::PhaseChecks::SatfuncConsistencyCheckManager<Scalar>::
curveLoop(Body&& body) const
{
std::for_each(this->curves_.begin(), this->curves_.end(),
std::forward<Body>(body));
}
// ===========================================================================
// Explicit Specialisations
//
// No other code below this separator
// ===========================================================================
template class Opm::Satfunc::PhaseChecks::SatfuncConsistencyCheckManager<float>;
template class Opm::Satfunc::PhaseChecks::SatfuncConsistencyCheckManager<double>;

View File

@ -0,0 +1,353 @@
/*
Copyright 2024 Equinor AS
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SATFUNC_CONSISTENCY_CHECK_MANAGER_HPP_INCLUDED
#define SATFUNC_CONSISTENCY_CHECK_MANAGER_HPP_INCLUDED
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
#include <opm/input/eclipse/EclipseState/Grid/SatfuncPropertyInitializers.hpp>
#include <opm/material/fluidmatrixinteractions/EclEpsGridProperties.hpp>
#include <opm/simulators/utils/ParallelCommunication.hpp>
#include <opm/simulators/utils/satfunc/SatfuncCheckPointInterface.hpp>
#include <opm/simulators/utils/satfunc/SatfuncConsistencyChecks.hpp>
#include <dune/grid/common/partitionset.hh>
#include <dune/grid/common/rangegenerators.hh>
#include <cstddef>
#include <functional>
#include <memory>
#include <string>
#include <string_view>
#include <type_traits>
#include <vector>
namespace Opm::Satfunc::PhaseChecks {
template <typename Scalar>
class UnscaledSatfuncCheckPoint;
} // namespace Opm::Satfunc::PhaseChecks
namespace Opm::Satfunc::PhaseChecks {
/// Define and execute saturation function consistency checks for all
/// cells in model.
///
/// \tparam Scalar Element type. Typically \c float or \c double.
template <typename Scalar>
class SatfuncConsistencyCheckManager
{
public:
/// Callback for translating active cell index to globally unique
/// point ID.
using LocalToGlobal = std::function<std::size_t(int)>;
/// Call-back function type for outputting a single record of a
/// consistency condition violation report.
using ReportRecordOutput = typename
SatfuncConsistencyChecks<Scalar>::ReportRecordOutput;
/// Severity level for consistency condition violation.
using ViolationLevel = typename
SatfuncConsistencyChecks<Scalar>::ViolationLevel;
/// Constructor
///
/// Creates a collection of saturation function checks based on the
/// characteristics of the simulation model, e.g., whether or not
/// end-point scaling is active or whether or not the run uses the
/// alternative (three-point) scaling method.
///
/// \param[in] numSamplePoints Upper bound on the number of
/// end-point check violations to preserve for reporting purposes.
/// Should normally be a small number like 5 or 10.
///
/// \param[in] eclipseState Container of static properties such as
/// the scaled saturation function end-points.
///
/// \param[in] localToGlobal Callback for translating active cell
/// indices to globally unique point IDs.
explicit SatfuncConsistencyCheckManager(const std::size_t numSamplePoints,
const EclipseState& eclipseState,
const LocalToGlobal& localToGlobal);
/// Set rank to which failure reports should be collected
///
/// \param[in] root Failure report destination rank. Should
/// normally be the run's I/O rank.
///
/// \return \code *this \endcode
SatfuncConsistencyCheckManager& collectFailuresTo(const int root)
{
this->root_ = root;
return *this;
}
/// Execute collection of saturation function consistency checks for
/// all cells in simulation model.
///
/// \tparam GridView Dune grid view type.
///
/// \tparam GetCellIndex Callback function type for translating an
/// active cell object into a numeric index. Assumed to support a
/// function call operator of the form
/// \code
/// int operator()(const Element& e)
/// \endcode
/// in which \c Element is the type representing a co-dimension zero
/// entity in the grid view.
///
/// \param[in] gv Grid view for which to analyse the saturation
/// function consistency. Each MPI rank will analyse its interior
/// cells only, and any failure reports will be subsequently
/// gathered on the root process defined by collectFailuresTo().
///
/// \param[in] getCellIndex Callback function for computing a
/// numeric lookup index associated to each interior element of the
/// grid view.
template <typename GridView, typename GetCellIndex>
void run(const GridView& gv, GetCellIndex&& getCellIndex)
{
this->isRoot_ = gv.comm().rank() == this->root_;
this->warnIfDirectionalOrIrreversibleEPS();
for (const auto& elem : elements(gv, Dune::Partitions::interior)) {
this->runCellChecks(getCellIndex(elem));
}
gv.comm().barrier();
this->collectFailures(gv.comm());
}
/// Whether or not any checks failed at the \c Standard level.
bool anyFailedStandardChecks() const;
/// Whether or not any checks failed at the \c Critical level.
bool anyFailedCriticalChecks() const;
/// Generate textual summary output of all failed consistency checks
/// at specific level.
///
/// Reports only those conditions/checks for which there is at least
/// one violation.
///
/// In a parallel run it is only safe to call this function on the
/// root process defined by collectFailuresTo().
///
/// \param[in] level Report's severity level.
///
/// \param[in] emitReportRecord Call-back function for outputting a
/// single record/line of a violation report. Typically a wrapper
/// of \code OpmLog::info() \endcode. It is the responsibility of
/// emitReportRecord() to properly display the text lines to end
/// users.
void reportFailures(const ViolationLevel level,
const ReportRecordOutput& emitReportRecord) const;
private:
/// Association between points on a specific saturation function
/// curves and the saturation function consistency checks to run on
/// those points.
struct CurveCollection
{
/// Constructor
///
/// Convenience only, as this enables constructing objects using
/// vector<>::emplace_back().
///
/// \param[in] point Callback protocol for defining and
/// populating saturation function end-points on a single
/// saturation function curve. Typically represents either a
/// collection of per-region, tabulated and unscaled saturation
/// functions or a collection of per-cell scaled saturation
/// functions.
///
/// \param[in] pointName Name/category of the points in this set
/// of checks. Might for instance be "Grid block" or
/// "Saturation region". Will be forwarded as a constructor
/// argument to \c SatfuncConsistencyChecks from whence it will
/// be used as a column header.
///
/// \param[in] numSamplePoints Upper bound on the number of
/// end-point check violations to preserve for reporting
/// purposes. Will be forwarded as a constructor argument to \c
/// SatfuncConsistencyChecks.
explicit CurveCollection(std::unique_ptr<SatfuncCheckPointInterface<Scalar>> point,
std::string_view pointName,
const std::size_t numSamplePoints);
/// Callback protocol for defining and populating saturation
/// function end-points on a single saturation function curve.
/// Typically represents either a collection of per-region,
/// tabulated and unscaled saturation functions or a collection
/// of per-cell scaled saturation functions.
std::unique_ptr<SatfuncCheckPointInterface<Scalar>> point;
/// Set of consistency checks to run against \c point.
SatfuncConsistencyChecks<Scalar> checks;
};
/// Container of static properties such as the scaled saturation
/// function end-points.
///
/// Also used to query if and which end-point scaling behaviour is
/// active in the run.
std::reference_wrapper<const EclipseState> eclipseState_;
/// Callback for translating active cell indices to globally unique
/// point IDs.
///
/// Mostly stored for convenience. Could arguably be forwarded to
/// the per-cell checks instead.
LocalToGlobal localToGlobal_;
/// Raw table end-points.
///
/// Minimum, critical, and maximum saturation points for each phase
/// for all tabulated saturation functions.
satfunc::RawTableEndPoints rtep_{};
/// Raw saturation function values.
///
/// Maximum function values for all saturation functions in addition
/// to relative permeability values at critical saturation points.
satfunc::RawFunctionValues rfunc_{};
/// Access interface for scaled saturation function end-points.
///
/// Represented as a vector in order to support expansion to
/// hysteretic cases and/or directionally dependent end-point
/// scaling.
std::vector<EclEpsGridProperties> gridProps_{};
/// All saturation function checks that will be run for all interior
/// cells in a grid view.
std::vector<CurveCollection> curves_{};
/// Rank to which failure reports should be collected.
int root_{0};
/// Whether or not the current rank coincides with \c root_ in the
/// grid view's communicator.
bool isRoot_{false};
/// Issue a warning on the \c root_ rank if the run uses directional
/// or irreversible end-point scaling.
///
/// Those scaled curves are currently not included in the saturation
/// function consistency analysis.
void warnIfDirectionalOrIrreversibleEPS() const;
/// Run all configured saturation function checks for a single
/// active cell.
///
/// \param[in] cellIdx Numeric lookup index associated to an
/// interior element/cell of a grid view.
void runCellChecks(const int cellIdx);
/// Configure all pertinent saturation function consistency checks.
///
/// \param[in] numSamplePoints Upper bound on the number of
/// end-point check violations to preserve for reporting purposes.
void configureCurveChecks(const std::size_t numSamplePoints);
/// Configure saturation function consistency checks for per-region,
/// unscaled saturation functions.
///
/// \param[in] regionName Region set for which to configure
/// consistency checks. Typically a well-known saturation function
/// region property name like SATNUM or IMBNUM.
///
/// \param[in] numSamplePoints Upper bound on the number of
/// end-point check violations to preserve for reporting purposes.
///
/// \return Callbacks for inferring the unscaled end-points of the
/// saturation region \p regionName. Nullptr if the region index
/// property array does not exist. This should, arguably, be an
/// optional<> instead to better reflect the intended semantics, but
/// then we would also need to include the header for class template
/// UnscaledSatfuncCheckPoint<> here.
std::unique_ptr<UnscaledSatfuncCheckPoint<Scalar>>
configureUnscaledCurveChecks(const std::string& regionName,
const std::size_t numSamplePoints);
/// Configure saturation function consistency checks for per-cell,
/// scaled saturation functions.
///
/// \param[in] unscaledChecks Callbacks for inferring the unscaled
/// end-points of the underlying saturation region. Typically the
/// return value from a previous call to member function
/// configureUnscaledCurveChecks().
///
/// \param[in] useImbibition Whether or not to configure consistency
/// checks for the imbibition curves.
///
/// \param[in] numSamplePoints Upper bound on the number of
/// end-point check violations to preserve for reporting purposes.
void configureScaledCurveChecks(const UnscaledSatfuncCheckPoint<Scalar>& unscaledChecks,
const bool useImbibition,
const std::size_t numSamplePoints);
/// Add set of particular end-point checks to each configured curve
void addChecks();
/// Collect consistency violations from all ranks in MPI communicator.
///
/// Incorporates violation counts and sampled failure points into
/// the internal structures on each rank. Aggregate results useful
/// for subsequent call to reportFailures() on root process.
///
/// \param[in] comm MPI communication object.
void collectFailures(const Parallel::Communication& comm);
/// Run a function for each configured curve.
///
/// Mutable version.
///
/// \tparam Body Callback function type representing a block of code
/// to run for each configured curve. Typically a class generated
/// by a lambda expression.
///
/// \param[in] body Block of code to run for each configured curve.
/// May mutate curves in place.
template <typename Body>
void curveLoop(Body&& body);
/// Run a function for each configured curve.
///
/// Immutable version.
///
/// \tparam Body Callback function type representing a block of code
/// to run for each configured curve. Typically a class generated
/// by a lambda expression.
///
/// \param[in] body Block of code to run for each configured curve.
/// May not mutate curves in place.
template <typename Body>
void curveLoop(Body&& body) const;
};
} // namespace Opm::Satfunc::PhaseChecks
#endif // SATFUNC_CONSISTENCY_CHECK_MANAGER_HPP_INCLUDED

View File

@ -162,7 +162,7 @@ collectFailures(const int root,
}
template <typename Scalar>
bool Opm::SatfuncConsistencyChecks<Scalar>::anyFailedChecks() const
bool Opm::SatfuncConsistencyChecks<Scalar>::anyFailedStandardChecks() const
{
return this->anyFailedChecks(ViolationLevel::Standard);
}

View File

@ -217,7 +217,7 @@ namespace Opm {
void collectFailures(int root, const Parallel::Communication& comm);
/// Whether or not any checks failed at the \c Standard level.
bool anyFailedChecks() const;
bool anyFailedStandardChecks() const;
/// Whether or not any checks failed at the \c Critical level.
bool anyFailedCriticalChecks() const;

File diff suppressed because it is too large Load Diff

View File

@ -88,7 +88,7 @@ BOOST_AUTO_TEST_CASE(All_Good)
checker.checkEndpoints(1234, makePoints());
BOOST_CHECK_MESSAGE(! checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(! checker.anyFailedStandardChecks(),
"There must be no failed checks");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),
@ -182,7 +182,7 @@ BOOST_AUTO_TEST_CASE(Standard_Violation)
checker.checkEndpoints(1234, makePoints());
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
auto rpt = std::string{};
@ -223,7 +223,7 @@ BOOST_AUTO_TEST_CASE(Standard_Violation_ReportIJK)
checker.checkEndpoints(1234, makePoints());
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
auto rpt = std::string{};
@ -259,7 +259,7 @@ BOOST_AUTO_TEST_CASE(Critical_Violation)
checker.checkEndpoints(42, makePoints());
BOOST_CHECK_MESSAGE(! checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(! checker.anyFailedStandardChecks(),
"There must be no failed standard level checks");
BOOST_CHECK_MESSAGE(checker.anyFailedCriticalChecks(),
@ -338,7 +338,7 @@ BOOST_AUTO_TEST_CASE(Standard)
checker.checkEndpoints(1234, makePoints());
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
auto rpt = std::string{};
@ -425,7 +425,7 @@ BOOST_AUTO_TEST_CASE(Standard)
checker.checkEndpoints(1234, makePoints());
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
auto rpt = std::string{};
@ -464,7 +464,7 @@ BOOST_AUTO_TEST_CASE(Standard_Multiple_Failing_Points)
checker.checkEndpoints( 1618, makePoints());
checker.checkEndpoints(31415, makePoints());
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
auto rpt = std::string{};
@ -651,7 +651,7 @@ BOOST_AUTO_TEST_CASE(Standard)
checker.checkEndpoints(1234, makePoints());
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
auto rpt = std::string{};
@ -732,7 +732,7 @@ BOOST_AUTO_TEST_CASE(Standard_Multiple_Failing_Points)
checker.checkEndpoints( 1618, makePoints());
checker.checkEndpoints(31415, makePoints());
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
auto rpt = std::string{};

View File

@ -189,7 +189,7 @@ BOOST_AUTO_TEST_CASE(All_Good)
checker.collectFailures(0, comm);
BOOST_CHECK_MESSAGE(! checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(! checker.anyFailedStandardChecks(),
"There must be no failed checks");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),
@ -293,7 +293,7 @@ BOOST_AUTO_TEST_CASE(Standard_Violation)
checker.collectFailures(0, comm);
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),
@ -341,7 +341,7 @@ BOOST_AUTO_TEST_CASE(Critical_Violation)
checker.collectFailures(0, comm);
BOOST_CHECK_MESSAGE(! checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(! checker.anyFailedStandardChecks(),
"There must be no failed standard level checks");
BOOST_CHECK_MESSAGE(checker.anyFailedCriticalChecks(),
@ -395,7 +395,7 @@ BOOST_AUTO_TEST_CASE(Standard_Violation)
checker.collectFailures(0, comm);
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),
@ -444,7 +444,7 @@ BOOST_AUTO_TEST_CASE(Critical_Violation)
checker.collectFailures(0, comm);
BOOST_CHECK_MESSAGE(! checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(! checker.anyFailedStandardChecks(),
"There must be no failed standard level checks");
BOOST_CHECK_MESSAGE(checker.anyFailedCriticalChecks(),
@ -499,7 +499,7 @@ BOOST_AUTO_TEST_CASE(Standard_Violation)
checker.collectFailures(0, comm);
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),
@ -549,7 +549,7 @@ BOOST_AUTO_TEST_CASE(Critical_Violation)
checker.collectFailures(0, comm);
BOOST_CHECK_MESSAGE(! checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(! checker.anyFailedStandardChecks(),
"There must be no failed standard level checks");
BOOST_CHECK_MESSAGE(checker.anyFailedCriticalChecks(),
@ -645,7 +645,7 @@ BOOST_AUTO_TEST_CASE(Standard)
checker.collectFailures(0, comm);
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),
@ -699,7 +699,7 @@ BOOST_AUTO_TEST_CASE(Standard)
checker.collectFailures(0, comm);
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),
@ -754,7 +754,7 @@ BOOST_AUTO_TEST_CASE(Standard)
checker.collectFailures(0, comm);
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),
@ -856,7 +856,7 @@ BOOST_AUTO_TEST_CASE(Standard)
checker.collectFailures(0, comm);
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),
@ -915,7 +915,7 @@ BOOST_AUTO_TEST_CASE(Standard_Multiple_Failing_Points)
checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1618, makePoints());
checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 31415, makePoints());
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),
@ -979,7 +979,7 @@ BOOST_AUTO_TEST_CASE(Standard)
checker.collectFailures(0, comm);
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),
@ -1039,7 +1039,7 @@ BOOST_AUTO_TEST_CASE(Standard_Multiple_Failing_Points)
checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1618, makePoints());
checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 31415, makePoints());
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),
@ -1107,7 +1107,7 @@ BOOST_AUTO_TEST_CASE(Standard)
checker.collectFailures(0, comm);
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),
@ -1168,7 +1168,7 @@ BOOST_AUTO_TEST_CASE(Standard_Multiple_Failing_Points)
checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1618, makePoints());
checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 31415, makePoints());
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),
@ -1381,7 +1381,7 @@ BOOST_AUTO_TEST_CASE(Standard)
checker.collectFailures(0, comm);
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),
@ -1487,7 +1487,7 @@ BOOST_AUTO_TEST_CASE(Standard_Multiple_Failing_Points)
checker.collectFailures(0, comm);
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),
@ -1612,7 +1612,7 @@ BOOST_AUTO_TEST_CASE(Standard)
checker.collectFailures(0, comm);
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),
@ -1722,7 +1722,7 @@ BOOST_AUTO_TEST_CASE(Standard_Multiple_Failing_Points)
checker.collectFailures(0, comm);
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),
@ -1863,7 +1863,7 @@ BOOST_AUTO_TEST_CASE(Standard)
checker.collectFailures(0, comm);
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),
@ -1977,7 +1977,7 @@ BOOST_AUTO_TEST_CASE(Standard_Multiple_Failing_Points)
checker.collectFailures(0, comm);
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(),
"There must be at least one failed check");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),