Add Protocol for Populating Saturation Function End Points per Cell

This commit introduces a set of callback functions, packaged in an
abstract base class SatfuncCheckPointInterface<Scalar>, for querying
and populating the saturation function end-points that get probed by
the individual consistency checks.  Member function

    SatfuncCheckPointInterface::pointID(cellIdx)

translates the active cell index 'cellIdx' into a point ID, assumed
to be unique on at least the current MPI rank.  This function will
return 'nullopt' if the 'cellIdx' is not eligible for this
particular end-point.  This typically happens for the region based
tabulated (unscaled) saturation function checks when the 'cellIdx'
happens to be in a region that's already been visited.  Member
function

    SatfuncCheckPointInterface::populateCheckPoint(cellIdx, endPoints)

fills in (assigns) all data members of the 'endPoints' structure
with the pertinent values for the active cell 'cellIdx'.

We implement this interface for the tabulated/unscaled end-points in
derived class UnscaledSatfuncCheckPoint<Scalar> and for the scaled
end-points in derived class ScaledSatfuncCheckPoint<Scalar>.  The
former keeps track of which saturation regions have been visited
and short-circuits its 'pointID()' member function based on that
information while the latter uses an instance of the former in order
initialise the 'endPoints' structure in its populateCheckPoint()
member function.
This commit is contained in:
Bård Skaflestad
2024-09-10 09:35:14 +02:00
parent eaa9e994d2
commit 257e5a2d2a
7 changed files with 1201 additions and 0 deletions

View File

@@ -222,7 +222,9 @@ if (HAVE_ECL_INPUT)
opm/simulators/utils/satfunc/OilPhaseConsistencyChecks.cpp
opm/simulators/utils/satfunc/PhaseCheckBase.cpp
opm/simulators/utils/satfunc/SatfuncConsistencyChecks.cpp
opm/simulators/utils/satfunc/ScaledSatfuncCheckPoint.cpp
opm/simulators/utils/satfunc/ThreePointHorizontalConsistencyChecks.cpp
opm/simulators/utils/satfunc/UnscaledSatfuncCheckPoint.cpp
opm/simulators/utils/satfunc/WaterPhaseConsistencyChecks.cpp
)
endif()
@@ -409,6 +411,7 @@ if (HAVE_ECL_INPUT)
tests/test_nonnc.cpp
tests/test_GasSatfuncConsistencyChecks.cpp
tests/test_OilSatfuncConsistencyChecks.cpp
tests/test_SatfuncCheckPoint.cpp
tests/test_SatfuncConsistencyChecks.cpp
tests/test_SatfuncConsistencyChecks_parallel.cpp
tests/test_ThreePointHorizontalSatfuncConsistencyChecks.cpp
@@ -1053,8 +1056,11 @@ if (HAVE_ECL_INPUT)
opm/simulators/utils/satfunc/GasPhaseConsistencyChecks.hpp
opm/simulators/utils/satfunc/OilPhaseConsistencyChecks.hpp
opm/simulators/utils/satfunc/PhaseCheckBase.hpp
opm/simulators/utils/satfunc/SatfuncCheckPointInterface.hpp
opm/simulators/utils/satfunc/SatfuncConsistencyChecks.hpp
opm/simulators/utils/satfunc/ScaledSatfuncCheckPoint.hpp
opm/simulators/utils/satfunc/ThreePointHorizontalConsistencyChecks.hpp
opm/simulators/utils/satfunc/UnscaledSatfuncCheckPoint.hpp
opm/simulators/utils/satfunc/WaterPhaseConsistencyChecks.hpp
)
endif()

View File

@@ -0,0 +1,73 @@
/*
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_CHECKPOINT_INTERFACE_HPP_INCLUDED
#define SATFUNC_CHECKPOINT_INTERFACE_HPP_INCLUDED
#include <cstddef>
#include <optional>
namespace Opm {
template <typename Scalar>
struct EclEpsScalingPointsInfo;
} // namespace Opm
namespace Opm::Satfunc::PhaseChecks {
/// Callback protocol for single saturation function consistency check point.
///
/// Intended to be used as a base class.
///
/// \tparam Scalar Element type. Typically \c float or \c double.
template <typename Scalar>
struct SatfuncCheckPointInterface
{
/// Virtual destructor for public inheritance
virtual ~SatfuncCheckPointInterface() = default;
/// Compute locally unique, i.e., per MPI rank, ID of this check for
/// a particular cell index.
///
/// Common examples include the drainage or imbibition region ID
/// (i.e., SATNUM or IMBNUM) or the Cartesian block index of a cell.
///
/// \param[in] cellIdx Active cell index on current rank.
///
/// \return Locally unique point ID for \p cellIdx. Nullopt if this
/// check point does not apply to \p cellIdx. A common cause of the
/// latter is running a region based check and the region already
/// having been visited.
virtual std::optional<std::size_t>
pointID(const int cellIdx) const = 0;
/// Populate check point values for a particular cell.
///
/// \param[in] cellIdx Active cell index on current rank.
///
/// \param[out] endPoints Set of saturation function end-points.
/// Member function populateCheckPoint() assigns all data members
/// and derived classes must abide by this requirement.
virtual void
populateCheckPoint(const int cellIdx,
EclEpsScalingPointsInfo<Scalar>& endPoints) const = 0;
};
} // namespace Opm::Satfunc::PhaseChecks
#endif // SATFUNC_CHECKPOINT_INTERFACE_HPP_INCLUDED

View File

@@ -0,0 +1,51 @@
/*
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/ScaledSatfuncCheckPoint.hpp>
#include <opm/input/eclipse/EclipseState/EclipseState.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/UnscaledSatfuncCheckPoint.hpp>
template <typename Scalar>
void
Opm::Satfunc::PhaseChecks::ScaledSatfuncCheckPoint<Scalar>::
populateCheckPoint(const int cellIdx,
EclEpsScalingPointsInfo<Scalar>& endPoints) const
{
this->unscaled_.populateCheckPoint(cellIdx, endPoints);
endPoints.extractScaled(*this->eclipseState_,
*this->epsGridProps_, cellIdx);
}
// ===========================================================================
// Explicit Specialisations
//
// No other code below this separator
// ===========================================================================
template class Opm::Satfunc::PhaseChecks::ScaledSatfuncCheckPoint<float>;
template class Opm::Satfunc::PhaseChecks::ScaledSatfuncCheckPoint<double>;

View File

@@ -0,0 +1,113 @@
/*
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 SCALED_SATFUNC_CHECKPOINT_HPP_INCLUDED
#define SCALED_SATFUNC_CHECKPOINT_HPP_INCLUDED
#include <opm/simulators/utils/satfunc/SatfuncCheckPointInterface.hpp>
#include <opm/simulators/utils/satfunc/UnscaledSatfuncCheckPoint.hpp>
#include <cstddef>
#include <functional>
#include <optional>
namespace Opm {
class EclipseState;
class EclEpsGridProperties;
template <typename Scalar>
struct EclEpsScalingPointsInfo;
} // namespace Opm
namespace Opm::Satfunc::PhaseChecks {
/// Callbacks for defining the scaled saturation function consistency
/// check point of a single active grid block.
///
/// \tparam Scalar Element type. Typically \c float or \c double.
template <typename Scalar>
class ScaledSatfuncCheckPoint : public SatfuncCheckPointInterface<Scalar>
{
public:
/// Callback for translating active cell index to globally unique
/// point ID.
using LocalToGlobal = std::function<std::size_t(const int)>;
/// Constructor
///
/// \param[in] unscaled Callbacks for inferring the end-points of
/// the underlying saturation region.
///
/// \param[in] eclipseState Container of static properties such as
/// the scaled saturation function end-points.
///
/// \param[in] epsGridProps Access interface for scaled saturation
/// function end-points.
///
/// \param[in] localToGlobal Callback for translating active cell
/// indices to globally unique point IDs.
explicit ScaledSatfuncCheckPoint(const UnscaledSatfuncCheckPoint<Scalar>& unscaled,
const EclipseState* eclipseState,
const EclEpsGridProperties* epsGridProps,
const LocalToGlobal& localToGlobal)
: unscaled_ { unscaled }
, eclipseState_ { eclipseState }
, epsGridProps_ { epsGridProps }
, localToGlobal_ { localToGlobal }
{}
/// Compute global unique, i.e., across all MPI ranks, ID of this
/// check for a particular cell index.
///
/// \param[in] cellIdx Active cell index on current rank.
///
/// \return Globally unique point ID for \p cellIdx
std::optional<std::size_t> pointID(const int cellIdx) const override
{
return { this->localToGlobal_(cellIdx) };
}
/// Populate check point values for a particular cell.
///
/// \param[in] cellIdx Active cell index on current rank.
///
/// \param[out] endPoints Set of saturation function end-points.
void populateCheckPoint(const int cellIdx,
EclEpsScalingPointsInfo<Scalar>& endPoints) const override;
private:
/// Callbacks for inferring the end-points of the underlying
/// saturation region.
UnscaledSatfuncCheckPoint<Scalar> unscaled_;
/// Container of static properties such as the scaled saturation
/// function end-points.
const EclipseState* eclipseState_{nullptr};
/// Access interface for scaled saturation function end-points.
const EclEpsGridProperties* epsGridProps_{nullptr};
/// Callback for translating active cell indices to globally unique
/// point IDs.
LocalToGlobal localToGlobal_{};
};
} // namespace Opm::Satfunc::PhaseChecks
#endif // SCALED_SATFUNC_CHECKPOINT_HPP_INCLUDED

View File

@@ -0,0 +1,68 @@
/*
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/UnscaledSatfuncCheckPoint.hpp>
#include <opm/input/eclipse/EclipseState/Grid/SatfuncPropertyInitializers.hpp>
#include <opm/material/fluidmatrixinteractions/EclEpsScalingPoints.hpp>
#include <opm/simulators/utils/satfunc/SatfuncCheckPointInterface.hpp>
#include <cstddef>
#include <optional>
#include <unordered_set>
#include <vector>
template <typename Scalar>
std::optional<std::size_t>
Opm::Satfunc::PhaseChecks::UnscaledSatfuncCheckPoint<Scalar>::
pointID(const int cellIdx) const
{
const auto& [regPos, inserted] =
this->seen_.insert((*this->region_)[cellIdx]);
// inserted == true => new/unseen region,
// == false => previously seen region.
return inserted
? std::optional { static_cast<std::size_t>(*regPos) }
: std::nullopt;
}
template <typename Scalar>
void
Opm::Satfunc::PhaseChecks::UnscaledSatfuncCheckPoint<Scalar>::
populateCheckPoint(const int cellIdx,
EclEpsScalingPointsInfo<Scalar>& endPoints) const
{
endPoints.extractUnscaled(*this->unscaledEndPoints_.rtep,
*this->unscaledEndPoints_.rfunc,
(*this->region_)[cellIdx] - this->regIdxOffset_);
}
// ===========================================================================
// Explicit Specialisations
//
// No other code below this separator
// ===========================================================================
template class Opm::Satfunc::PhaseChecks::UnscaledSatfuncCheckPoint<float>;
template class Opm::Satfunc::PhaseChecks::UnscaledSatfuncCheckPoint<double>;

View File

@@ -0,0 +1,122 @@
/*
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 UNSCALED_SATFUNC_CHECKPOINT_HPP_INCLUDED
#define UNSCALED_SATFUNC_CHECKPOINT_HPP_INCLUDED
#include <opm/simulators/utils/satfunc/SatfuncCheckPointInterface.hpp>
#include <cstddef>
#include <optional>
#include <unordered_set>
#include <vector>
namespace Opm {
template <typename Scalar>
struct EclEpsScalingPointsInfo;
} // namespace Opm
namespace Opm::satfunc {
struct RawTableEndPoints;
struct RawFunctionValues;
} // namespace Opm::satfunc
namespace Opm::Satfunc::PhaseChecks {
/// Callbacks for defining the consistency check point of a single region.
///
/// \tparam Scalar Element type. Typically \c float or \c double.
template <typename Scalar>
class UnscaledSatfuncCheckPoint : public SatfuncCheckPointInterface<Scalar>
{
public:
/// Collection of saturation function end-points and function values
/// extracted from tabulated saturation functions.
struct UnscaledEndPoints
{
/// Raw table end-points. Minimum, critical, and maximum
/// saturation points for each phase for all tabulated
/// saturation functions.
const satfunc::RawTableEndPoints* rtep{nullptr};
/// Raw saturation function values. Maximum function values for
/// all saturation functions in addition to relative
/// permeability values at critical saturation points.
const satfunc::RawFunctionValues* rfunc{nullptr};
};
/// Constructor
///
/// \param[in] region Region index for each active cell on rank.
///
/// \param[in] regIdxOffset Region index offset. Pass one (1) if \p
/// region contains one-based region indices.
///
/// \param[in] unscaledEndPoints Saturation function end-points for
/// all tabulated saturation functions. Lifetime of members must
/// exceed the \c UnscaledSatfuncCheckPoint object.
explicit UnscaledSatfuncCheckPoint(const std::vector<int>* region,
const int regIdxOffset,
const UnscaledEndPoints& unscaledEndPoints)
: unscaledEndPoints_ { unscaledEndPoints }
, regIdxOffset_ { regIdxOffset }
, region_ { region }
{}
/// Compute locally unique, i.e., per MPI rank, ID of this check for
/// a particular cell index.
///
/// Common examples include the drainage or imbibition region ID
/// (i.e., SATNUM or IMBNUM) or the Cartesian block index of a cell.
///
/// \param[in] cellIdx Active cell index on current rank.
///
/// \return Locally unique point ID for \p cellIdx. Nullopt if this
/// check point does not apply to \p cellIdx. Typically because the
/// underlying region of \p cellIdx has already been visited.
std::optional<std::size_t> pointID(const int cellIdx) const override;
/// Populate check point values for a particular cell.
///
/// \param[in] cellIdx Active cell index on current rank.
///
/// \param[out] endPoints Set of saturation function end-points.
void populateCheckPoint(const int cellIdx,
EclEpsScalingPointsInfo<Scalar>& endPoints) const override;
private:
/// Saturation function end-points for all tabulated saturation
/// functions. Lifetime of members must exceed the \c
/// UnscaledSatfuncCheckPoint object.
UnscaledEndPoints unscaledEndPoints_;
/// Region index offset. Should be one (1) if region_ contains
/// one-based region indices.
int regIdxOffset_{};
/// Region index for each active cell on rank.
const std::vector<int>* region_{nullptr};
/// Cache for visited ("seen") saturation regions.
mutable std::unordered_set<int> seen_{};
};
} // namespace Opm::Satfunc::PhaseChecks
#endif // UNSCALED_SATFUNC_CHECKPOINT_HPP_INCLUDED

View File

@@ -0,0 +1,768 @@
/*
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>
#define BOOST_TEST_MODULE TestSatfuncCheckPoint
#ifndef HAVE_MPI
// Suppress GCC diagnostics of the form
//
// warning: "HAVE_MPI" is not defined, evaluates to 0
//
// when compiling with "-Wundef".
#define HAVE_MPI 0
#endif // HAVE_MPI
#include <boost/test/unit_test.hpp>
#include <opm/simulators/utils/satfunc/ScaledSatfuncCheckPoint.hpp>
#include <opm/simulators/utils/satfunc/UnscaledSatfuncCheckPoint.hpp>
#include <opm/input/eclipse/EclipseState/Grid/SatfuncPropertyInitializers.hpp>
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
#include <opm/material/fluidmatrixinteractions/EclEpsGridProperties.hpp>
#include <opm/material/fluidmatrixinteractions/EclEpsScalingPoints.hpp>
#include <opm/input/eclipse/Deck/Deck.hpp>
#include <opm/input/eclipse/Parser/Parser.hpp>
#include <cstddef>
#include <initializer_list>
#include <vector>
// ###########################################################################
namespace {
Opm::satfunc::RawTableEndPoints exampleRTep()
{
auto rtep = Opm::satfunc::RawTableEndPoints{};
rtep.connate.gas .assign({ 0.0, 0.0, 0.0, 0.0 , });
rtep.connate.water.assign({ 0.2, 0.1, 0.0, 0.25, });
rtep.critical.oil_in_gas .assign({ 0.1 , 0.125, 0.02, 0.35, });
rtep.critical.oil_in_water.assign({ 0.2 , 0.225, 0.07, 0.5 , });
rtep.critical.gas .assign({ 0.15, 0.257, 0.12, 0.04, });
rtep.critical.water .assign({ 0.27, 0.325, 0.25, 0.42, });
rtep.maximum.gas .assign({ 0.8, 0.9, 1.0, 0.75, });
rtep.maximum.water.assign({ 1.0, 1.0, 1.0, 0.8 , });
return rtep;
}
Opm::satfunc::RawFunctionValues exampleRFunc()
{
auto rfunc = Opm::satfunc::RawFunctionValues{};
rfunc.kro.max.assign({ 0.75, 0.8, 0.85, 0.7, });
rfunc.kro.rg .assign({ 0.62, 0.6, 0.78, 0.7, });
rfunc.kro.rw .assign({ 0.53, 0.4, 0.82, 0.5, });
rfunc.krg.max.assign({ 1.0, 0.99, 0.98, 0.95, });
rfunc.krg.r .assign({ 0.8, 0.79, 0.87, 0.75, });
rfunc.krw.max.assign({ 0.7, 0.69, 0.68, 0.65, });
rfunc.krw.r .assign({ 0.5, 0.49, 0.48, 0.45, });
rfunc.pc.g.assign({ 0.0, 1.0, 2.0, 3.0, });
rfunc.pc.w.assign({ 10.0, 8.5, 7.0, 5.5, });
return rfunc;
}
} // Anonymous namespace
// ===========================================================================
BOOST_AUTO_TEST_SUITE(Unscaled_Curve)
BOOST_AUTO_TEST_CASE(All_Regions)
{
using CurvePt = Opm::Satfunc::PhaseChecks::UnscaledSatfuncCheckPoint<double>;
const auto satnum = std::vector { 1, 2, 3, 4, };
const auto rtep = exampleRTep();
const auto rfunc = exampleRFunc();
const auto curvePt = CurvePt {
&satnum, 1, CurvePt::UnscaledEndPoints { &rtep, &rfunc }
};
{
const auto id = curvePt.pointID(0);
BOOST_REQUIRE_MESSAGE(id.has_value(),
"pointID(0) must return a value on first call");
BOOST_CHECK_EQUAL(*id, std::size_t{1});
BOOST_CHECK_MESSAGE(! curvePt.pointID(0).has_value(),
"pointID(0) must NOT return a value on second call");
}
{
const auto id = curvePt.pointID(1);
BOOST_REQUIRE_MESSAGE(id.has_value(),
"pointID(1) must return a value on first call");
BOOST_CHECK_EQUAL(*id, std::size_t{2});
BOOST_CHECK_MESSAGE(! curvePt.pointID(1).has_value(),
"pointID(1) must NOT return a value on second call");
}
{
const auto id = curvePt.pointID(2);
BOOST_REQUIRE_MESSAGE(id.has_value(),
"pointID(2) must return a value on first call");
BOOST_CHECK_EQUAL(*id, std::size_t{3});
BOOST_CHECK_MESSAGE(! curvePt.pointID(0).has_value(),
"pointID(2) must NOT return a value on second call");
}
{
const auto id = curvePt.pointID(3);
BOOST_REQUIRE_MESSAGE(id.has_value(),
"pointID(3) must return a value on first call");
BOOST_CHECK_EQUAL(*id, std::size_t{4});
BOOST_CHECK_MESSAGE(! curvePt.pointID(0).has_value(),
"pointID(3) must NOT return a value on second call");
}
// Unscaled saturation function end-points in cell 0 (SATNUM = 1).
{
auto endPoints = Opm::EclEpsScalingPointsInfo<double>{};
curvePt.populateCheckPoint(0, endPoints);
BOOST_CHECK_CLOSE(endPoints.Swl, 0.2, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgl, 0.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Swcr, 0.27, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgcr, 0.15, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sowcr, 0.2 , 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sogcr, 0.1 , 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Swu, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgu, 0.8, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxPcow, 10.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxPcgo, 0.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.pcowLeverettFactor, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.pcgoLeverettFactor, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krwr, 0.5, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krgr, 0.8, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krorw, 0.53, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krorg, 0.62, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrw, 0.7, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrow, 0.75, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrog, 0.75, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrg, 1.0, 1.0e-8);
}
// Unscaled saturation function end-points in cell 0. Intentionally
// same as previous. Member function populateCheckPoint() should not
// care that we've called the function with the same arguments before.
{
auto endPoints = Opm::EclEpsScalingPointsInfo<double>{};
curvePt.populateCheckPoint(0, endPoints);
BOOST_CHECK_CLOSE(endPoints.Swl, 0.2, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgl, 0.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Swcr, 0.27, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgcr, 0.15, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sowcr, 0.2 , 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sogcr, 0.1 , 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Swu, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgu, 0.8, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxPcow, 10.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxPcgo, 0.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.pcowLeverettFactor, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.pcgoLeverettFactor, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krwr, 0.5, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krgr, 0.8, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krorw, 0.53, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krorg, 0.62, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrw, 0.7, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrow, 0.75, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrog, 0.75, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrg, 1.0, 1.0e-8);
}
// Unscaled saturation function end-points in cell 1 (SATNUM = 2).
{
auto endPoints = Opm::EclEpsScalingPointsInfo<double>{};
curvePt.populateCheckPoint(1, endPoints);
BOOST_CHECK_CLOSE(endPoints.Swl, 0.1, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgl, 0.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Swcr, 0.325, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgcr, 0.257, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sowcr, 0.225, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sogcr, 0.125, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Swu, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgu, 0.9, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxPcow, 8.5, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxPcgo, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.pcowLeverettFactor, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.pcgoLeverettFactor, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krwr, 0.49, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krgr, 0.79, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krorw, 0.4, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krorg, 0.6, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrw, 0.69, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrow, 0.8, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrog, 0.8, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrg, 0.99, 1.0e-8);
}
// Unscaled saturation function end-points in cell 2 (SATNUM = 3).
{
auto endPoints = Opm::EclEpsScalingPointsInfo<double>{};
curvePt.populateCheckPoint(2, endPoints);
BOOST_CHECK_CLOSE(endPoints.Swl, 0.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgl, 0.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Swcr, 0.25, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgcr, 0.12, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sowcr, 0.07, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sogcr, 0.02, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Swu, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgu, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxPcow, 7.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxPcgo, 2.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.pcowLeverettFactor, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.pcgoLeverettFactor, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krwr, 0.48, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krgr, 0.87, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krorw, 0.82, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krorg, 0.78, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrw, 0.68, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrow, 0.85, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrog, 0.85, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrg, 0.98, 1.0e-8);
}
// Unscaled saturation function end-points in cell 3 (SATNUM = 4).
{
auto endPoints = Opm::EclEpsScalingPointsInfo<double>{};
curvePt.populateCheckPoint(3, endPoints);
BOOST_CHECK_CLOSE(endPoints.Swl, 0.25, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgl, 0.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Swcr, 0.42, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgcr, 0.04, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sowcr, 0.5, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sogcr, 0.35, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Swu, 0.8, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgu, 0.75, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxPcow, 5.5, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxPcgo, 3.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.pcowLeverettFactor, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.pcgoLeverettFactor, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krwr, 0.45, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krgr, 0.75, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krorw, 0.5, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krorg, 0.7, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrw, 0.65, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrow, 0.7, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrog, 0.7, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrg, 0.95, 1.0e-8);
}
}
BOOST_AUTO_TEST_CASE(Same_Region)
{
using CurvePt = Opm::Satfunc::PhaseChecks::UnscaledSatfuncCheckPoint<double>;
const auto satnum = std::vector { 2, 2, 2, 2, };
const auto rtep = exampleRTep();
const auto rfunc = exampleRFunc();
const auto curvePt = CurvePt {
&satnum, 1, CurvePt::UnscaledEndPoints { &rtep, &rfunc }
};
{
const auto id = curvePt.pointID(0);
BOOST_REQUIRE_MESSAGE(id.has_value(),
"pointID(0) must return a value on first call");
BOOST_CHECK_EQUAL(*id, std::size_t{2});
BOOST_CHECK_MESSAGE(! curvePt.pointID(0).has_value(),
"pointID(0) must NOT return a value on second call");
}
BOOST_CHECK_MESSAGE(! curvePt.pointID(1).has_value(),
"pointID(1) must NOT return a value on first call");
BOOST_CHECK_MESSAGE(! curvePt.pointID(2).has_value(),
"pointID(2) must NOT return a value on first call");
BOOST_CHECK_MESSAGE(! curvePt.pointID(3).has_value(),
"pointID(3) must NOT return a value on first call");
// Unscaled saturation function end-points in cell 0 (SATNUM = 2).
{
auto endPoints = Opm::EclEpsScalingPointsInfo<double>{};
curvePt.populateCheckPoint(0, endPoints);
BOOST_CHECK_CLOSE(endPoints.Swl, 0.1, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgl, 0.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Swcr, 0.325, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgcr, 0.257, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sowcr, 0.225, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sogcr, 0.125, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Swu, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgu, 0.9, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxPcow, 8.5, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxPcgo, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.pcowLeverettFactor, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.pcgoLeverettFactor, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krwr, 0.49, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krgr, 0.79, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krorw, 0.4, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krorg, 0.6, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrw, 0.69, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrow, 0.8, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrog, 0.8, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrg, 0.99, 1.0e-8);
}
// Unscaled saturation function end-points in cell 1 (SATNUM = 2).
{
auto endPoints = Opm::EclEpsScalingPointsInfo<double>{};
curvePt.populateCheckPoint(1, endPoints);
BOOST_CHECK_CLOSE(endPoints.Swl, 0.1, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgl, 0.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Swcr, 0.325, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgcr, 0.257, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sowcr, 0.225, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sogcr, 0.125, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Swu, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgu, 0.9, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxPcow, 8.5, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxPcgo, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.pcowLeverettFactor, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.pcgoLeverettFactor, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krwr, 0.49, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krgr, 0.79, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krorw, 0.4, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krorg, 0.6, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrw, 0.69, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrow, 0.8, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrog, 0.8, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrg, 0.99, 1.0e-8);
}
// Unscaled saturation function end-points in cell 2 (SATNUM = 2).
{
auto endPoints = Opm::EclEpsScalingPointsInfo<double>{};
curvePt.populateCheckPoint(2, endPoints);
BOOST_CHECK_CLOSE(endPoints.Swl, 0.1, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgl, 0.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Swcr, 0.325, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgcr, 0.257, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sowcr, 0.225, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sogcr, 0.125, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Swu, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgu, 0.9, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxPcow, 8.5, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxPcgo, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.pcowLeverettFactor, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.pcgoLeverettFactor, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krwr, 0.49, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krgr, 0.79, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krorw, 0.4, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krorg, 0.6, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrw, 0.69, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrow, 0.8, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrog, 0.8, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrg, 0.99, 1.0e-8);
}
// Unscaled saturation function end-points in cell 3 (SATNUM = 2).
{
auto endPoints = Opm::EclEpsScalingPointsInfo<double>{};
curvePt.populateCheckPoint(3, endPoints);
BOOST_CHECK_CLOSE(endPoints.Swl, 0.1, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgl, 0.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Swcr, 0.325, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgcr, 0.257, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sowcr, 0.225, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sogcr, 0.125, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Swu, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Sgu, 0.9, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxPcow, 8.5, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxPcgo, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.pcowLeverettFactor, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.pcgoLeverettFactor, 1.0, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krwr, 0.49, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krgr, 0.79, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krorw, 0.4, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.Krorg, 0.6, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrw, 0.69, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrow, 0.8, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrog, 0.8, 1.0e-8);
BOOST_CHECK_CLOSE(endPoints.maxKrg, 0.99, 1.0e-8);
}
}
BOOST_AUTO_TEST_SUITE_END() // Unscaled_Curve
// ===========================================================================
BOOST_AUTO_TEST_SUITE(Scaled_Curve)
namespace {
Opm::EclipseState scaledEndpointProps()
{
return Opm::EclipseState {
Opm::Parser{}.parseString(R"(RUNSPEC
DIMENS
1 5 1 /
ENDSCALE
/
TABDIMS
3 /
OIL
GAS
WATER
GRID
DXV
100.0 /
DYV
5*20.0 /
DZV
5.0 /
DEPTHZ
12*2000.0 /
PORO
5*0.3 /
PROPS
SCALECRS
'YES' /
SWOF
0.0 0.0 1.0 0.0
1.0 1.0 0.0 0.0
/
/
/
SGOF
0.0 0.0 1.0 0.0
1.0 1.0 0.0 0.0
/
/
/
SWL
0.05 0.1 0.15 0.2 0.27 /
SWCR
0.06 0.11 0.16 0.21 0.3 /
SWU
0.98 0.97 0.96 0.95 0.94 /
SGL
0.01 0.02 0.03 0.04 0.05 /
SGCR
0.1 0.11 0.12 0.13 0.14 /
SGU
0.89 0.9 0.91 0.92 0.93 /
SOWCR
0.21 0.23 0.25 0.27 0.29 /
SOGCR
0.15 0.16 0.17 0.18 0.19 /
KRW
0.72 0.77 0.82 0.87 0.92 /
KRWR
0.6 0.63 0.66 0.71 0.65 /
KRG
0.85 0.84 0.86 0.83 0.87 /
KRGR
5*0.775 /
KRORW
0.55 0.65 0.65 0.7 0.6 /
-- No KRORG => use unscaled function values
REGIONS
SATNUM
1 3 2 2 1 /
END
)")
};
}
} // Anonymous namespace
BOOST_AUTO_TEST_CASE(All_Cells)
{
using UnscaledCurvePt = Opm::Satfunc::PhaseChecks::UnscaledSatfuncCheckPoint<float>;
using ScaledCurvePt = Opm::Satfunc::PhaseChecks::ScaledSatfuncCheckPoint<float>;
const auto es = scaledEndpointProps();
const auto* satnum = &es.fieldProps().get_int("SATNUM"); // {1, 3, 2, 2, 1}
const auto rtep = exampleRTep();
const auto rfunc = exampleRFunc();
const auto unscaledCurvePt = UnscaledCurvePt {
satnum, 1, UnscaledCurvePt::UnscaledEndPoints { &rtep, &rfunc }
};
const auto epsGridProps = Opm::EclEpsGridProperties { es, /* useImbibition = */ false };
const auto scaledCurvePt = ScaledCurvePt {
unscaledCurvePt, &es, &epsGridProps,
[](const auto& i) { return static_cast<std::size_t>(i); }
};
{
const auto id = scaledCurvePt.pointID(0);
BOOST_REQUIRE_MESSAGE(id.has_value(),
"pointID(0) must return a value on first call");
BOOST_CHECK_EQUAL(*id, std::size_t{0});
BOOST_CHECK_MESSAGE(scaledCurvePt.pointID(0).has_value(),
"pointID(0) must return a value on second call");
}
// Scaled saturation function end-points in cell 0 (SATNUM = 1).
{
auto endPoints = Opm::EclEpsScalingPointsInfo<float>{};
scaledCurvePt.populateCheckPoint(0, endPoints);
BOOST_CHECK_CLOSE(endPoints.Swl, 0.05f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sgl, 0.01f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Swcr, 0.06f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sgcr, 0.1f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sowcr, 0.21f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sogcr, 0.15f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Swu, 0.98f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sgu, 0.89f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxPcow, 10.0f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxPcgo, 0.0f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.pcowLeverettFactor, 1.0f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.pcgoLeverettFactor, 1.0f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Krwr, 0.6f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Krgr, 0.775f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Krorw, 0.55f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Krorg, 0.62f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxKrw, 0.72f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxKrow, 0.75f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxKrog, 0.75f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxKrg, 0.85f, 1.0e-6f);
}
// Scaled saturation function end-points in cell 1 (SATNUM = 3).
{
auto endPoints = Opm::EclEpsScalingPointsInfo<float>{};
scaledCurvePt.populateCheckPoint(1, endPoints);
BOOST_CHECK_CLOSE(endPoints.Swl, 0.1f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sgl, 0.02f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Swcr, 0.11f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sgcr, 0.11f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sowcr, 0.23f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sogcr, 0.16f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Swu, 0.97f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sgu, 0.9f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxPcow, 7.0f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxPcgo, 2.0f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.pcowLeverettFactor, 1.0f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.pcgoLeverettFactor, 1.0f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Krwr, 0.63f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Krgr, 0.775f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Krorw, 0.65f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Krorg, 0.78f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxKrw, 0.77f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxKrow, 0.85f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxKrog, 0.85f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxKrg, 0.84f, 1.0e-6f);
}
// Scaled saturation function end-points in cell 2 (SATNUM = 2).
{
auto endPoints = Opm::EclEpsScalingPointsInfo<float>{};
scaledCurvePt.populateCheckPoint(2, endPoints);
BOOST_CHECK_CLOSE(endPoints.Swl, 0.15f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sgl, 0.03f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Swcr, 0.16f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sgcr, 0.12f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sowcr, 0.25f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sogcr, 0.17f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Swu, 0.96f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sgu, 0.91f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxPcow, 8.5f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxPcgo, 1.0f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.pcowLeverettFactor, 1.0f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.pcgoLeverettFactor, 1.0f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Krwr, 0.66f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Krgr, 0.775f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Krorw, 0.65f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Krorg, 0.6f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxKrw, 0.82f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxKrow, 0.8f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxKrog, 0.8f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxKrg, 0.86f, 1.0e-6f);
}
// Scaled saturation function end-points in cell 3 (SATNUM = 2).
{
auto endPoints = Opm::EclEpsScalingPointsInfo<float>{};
scaledCurvePt.populateCheckPoint(3, endPoints);
BOOST_CHECK_CLOSE(endPoints.Swl, 0.2f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sgl, 0.04f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Swcr, 0.21f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sgcr, 0.13f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sowcr, 0.27f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sogcr, 0.18f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Swu, 0.95f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sgu, 0.92f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxPcow, 8.5f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxPcgo, 1.0f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.pcowLeverettFactor, 1.0f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.pcgoLeverettFactor, 1.0f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Krwr, 0.71f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Krgr, 0.775f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Krorw, 0.7f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Krorg, 0.6f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxKrw, 0.87f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxKrow, 0.8f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxKrog, 0.8f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxKrg, 0.83f, 1.0e-6f);
}
// Scaled saturation function end-points in cell 4 (SATNUM = 1).
{
auto endPoints = Opm::EclEpsScalingPointsInfo<float>{};
scaledCurvePt.populateCheckPoint(4, endPoints);
BOOST_CHECK_CLOSE(endPoints.Swl, 0.27f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sgl, 0.05f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Swcr, 0.3f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sgcr, 0.14f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sowcr, 0.29f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sogcr, 0.19f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Swu, 0.94f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Sgu, 0.93f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxPcow, 10.0f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxPcgo, 0.0f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.pcowLeverettFactor, 1.0f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.pcgoLeverettFactor, 1.0f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Krwr, 0.65f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Krgr, 0.775f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Krorw, 0.6f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.Krorg, 0.62f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxKrw, 0.92f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxKrow, 0.75f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxKrog, 0.75f, 1.0e-6f);
BOOST_CHECK_CLOSE(endPoints.maxKrg, 0.87f, 1.0e-6f);
}
}
BOOST_AUTO_TEST_SUITE_END() // Scaled_Curve