diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index b7188467f..90d7afc94 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -203,6 +203,7 @@ 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/ThreePointHorizontalConsistencyChecks.cpp opm/simulators/utils/satfunc/WaterPhaseConsistencyChecks.cpp ) endif() @@ -391,6 +392,7 @@ if (HAVE_ECL_INPUT) tests/test_OilSatfuncConsistencyChecks.cpp tests/test_SatfuncConsistencyChecks.cpp tests/test_SatfuncConsistencyChecks_parallel.cpp + tests/test_ThreePointHorizontalSatfuncConsistencyChecks.cpp tests/test_WaterSatfuncConsistencyChecks.cpp ) endif() @@ -999,6 +1001,7 @@ if (HAVE_ECL_INPUT) opm/simulators/utils/satfunc/OilPhaseConsistencyChecks.hpp opm/simulators/utils/satfunc/PhaseCheckBase.hpp opm/simulators/utils/satfunc/SatfuncConsistencyChecks.hpp + opm/simulators/utils/satfunc/ThreePointHorizontalConsistencyChecks.hpp opm/simulators/utils/satfunc/WaterPhaseConsistencyChecks.hpp ) endif() diff --git a/opm/simulators/utils/satfunc/ThreePointHorizontalConsistencyChecks.cpp b/opm/simulators/utils/satfunc/ThreePointHorizontalConsistencyChecks.cpp new file mode 100644 index 000000000..d86704c35 --- /dev/null +++ b/opm/simulators/utils/satfunc/ThreePointHorizontalConsistencyChecks.cpp @@ -0,0 +1,110 @@ +/* + 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 . +*/ + +#include + +#include + +#include + +#include + +// --------------------------------------------------------------------------- + +template +void Opm::Satfunc::PhaseChecks::ThreePointHorizontal::DisplacingOil_GO:: +testImpl(const EclEpsScalingPointsInfo& endPoints) +{ + // SGCR < 1-SOGCR-SWL < SGU + + this->swl_ = endPoints.Swl; + this->sogcr_ = endPoints.Sogcr; + this->sgcr_ = endPoints.Sgcr; + this->sgu_ = endPoints.Sgu; + + if (! std::isfinite(this->swl_) || + ! std::isfinite(this->sogcr_) || + ! std::isfinite(this->sgcr_) || + ! std::isfinite(this->sgu_)) + { + this->setViolated(); + this->setCritical(); + + return; + } + + const auto sr = Scalar{1} - (this->sogcr_ + this->swl_); + + const auto low = ! (this->swl_ < sr); + const auto high = ! (sr < this->sgu_); + + if (low || high) { + this->setViolated(); + this->setCritical(); + } +} + +// --------------------------------------------------------------------------- + +template +void Opm::Satfunc::PhaseChecks::ThreePointHorizontal::DisplacingOil_OW:: +testImpl(const EclEpsScalingPointsInfo& endPoints) +{ + // SWCR < 1-SOWCR-SGL < SWU + + this->sgl_ = endPoints.Sgl; + this->sowcr_ = endPoints.Sowcr; + this->swcr_ = endPoints.Swcr; + this->swu_ = endPoints.Swu; + + if (! std::isfinite(this->sgl_) || + ! std::isfinite(this->sowcr_) || + ! std::isfinite(this->swcr_) || + ! std::isfinite(this->swu_)) + { + this->setViolated(); + this->setCritical(); + + return; + } + + const auto sr = Scalar{1} - (this->sowcr_ + this->sgl_); + + const auto low = ! (this->sgl_ < sr); + const auto high = ! (sr < this->swu_); + + if (low || high) { + this->setViolated(); + this->setCritical(); + } +} + +// =========================================================================== +// Explicit Specialisations of Individual Check Templates +// +// No other code below this separator +// =========================================================================== + +template class Opm::Satfunc::PhaseChecks::ThreePointHorizontal::DisplacingOil_GO; +template class Opm::Satfunc::PhaseChecks::ThreePointHorizontal::DisplacingOil_GO; + +// --------------------------------------------------------------------------- + +template class Opm::Satfunc::PhaseChecks::ThreePointHorizontal::DisplacingOil_OW; +template class Opm::Satfunc::PhaseChecks::ThreePointHorizontal::DisplacingOil_OW; diff --git a/opm/simulators/utils/satfunc/ThreePointHorizontalConsistencyChecks.hpp b/opm/simulators/utils/satfunc/ThreePointHorizontalConsistencyChecks.hpp new file mode 100644 index 000000000..1261bb6b8 --- /dev/null +++ b/opm/simulators/utils/satfunc/ThreePointHorizontalConsistencyChecks.hpp @@ -0,0 +1,183 @@ +/* + 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 . +*/ + +#ifndef THREE_POINT_HORIZONTAL_CONSISTENCY_CHECKS_HPP_INCLUDED +#define THREE_POINT_HORIZONTAL_CONSISTENCY_CHECKS_HPP_INCLUDED + +#include +#include + +#include +#include + +namespace Opm::Satfunc::PhaseChecks::ThreePointHorizontal { + + /// Verify that critical saturation of displacing phase (oil/liquid) is + /// strictly between critical and maximum gas saturations for the + /// alternative (three point) horizontal scaling method (SCALECRS=YES) + /// in the gas/oil two-phase system. + /// + /// \tparam Scalar Element type. Typically \c float or \c double. + template + class DisplacingOil_GO : public PhaseCheckBase + { + public: + /// Number of \c Scalar values involved in the check. + std::size_t numExportedCheckValues() const override { return 5; }; + + /// Get a linearised copy of the \c Scalar values involved in the check. + /// + /// \param[in,out] exportedCheckValues Pointer to contiguous + /// sequence of at least numExportedCheckValues() \c Scalars. + void exportCheckValues(Scalar* exportedCheckValues) const override + { + exportedCheckValues[0] = this->swl_; + exportedCheckValues[1] = this->sogcr_; + exportedCheckValues[2] = this->sgcr_; + exportedCheckValues[3] = Scalar{1} - (this->sogcr_ + this->swl_); + exportedCheckValues[4] = this->sgu_; + } + + /// Descriptive textual summary of this check. + std::string description() const override + { + return { "Mobile displacing oil in three point " + "horizontally scaled gas/oil system" }; + } + + /// Textual representation of the consistency condition. + std::string condition() const override + { + return { "SGCR < 1-SOGCR-SWL < SGU" }; + } + + /// Retrieve names of the exported check values. + /// + /// \param[in,out] headers Pointer to contiguous sequence of at + /// least numExportedCheckValues() strings. + void columnNames(std::string* headers) const override + { + headers[0] = "SWL"; + headers[1] = "SOGCR"; + headers[2] = "SGCR"; + headers[3] = "1-SOGCR-SWL"; + headers[4] = "SGU"; + } + + private: + /// Minimum (connate) water saturation. + Scalar swl_; + + /// Critical oil saturation in two-phase gas/oil system. + Scalar sogcr_; + + /// Critical gas saturation. + Scalar sgcr_; + + /// Maximum gas saturation. + Scalar sgu_; + + /// Run check against a set of saturation function end-points. + /// + /// \param[in] endPoints Set of saturation function end-points. + /// Might for instance be the scaled end-points of the drainage + /// functions in a single grid block or the unscaled end-points + /// of the tabulated saturation functions in a single saturation + /// region. + void testImpl(const EclEpsScalingPointsInfo& endPoints) override; + }; + + /// Verify that critical saturation of displacing phase (oil) is + /// strictly between critical and maximum water saturations for the + /// alternative (three point) horizontal scaling method (SCALECRS=YES) + /// in the oil/water two-phase system. + /// + /// \tparam Scalar Element type. Typically \c float or \c double. + template + class DisplacingOil_OW : public PhaseCheckBase + { + public: + /// Number of \c Scalar values involved in the check. + std::size_t numExportedCheckValues() const override { return 5; }; + + /// Get a linearised copy of the \c Scalar values involved in the check. + /// + /// \param[in,out] exportedCheckValues Pointer to contiguous + /// sequence of at least numExportedCheckValues() \c Scalars. + void exportCheckValues(Scalar* exportedCheckValues) const override + { + exportedCheckValues[0] = this->sgl_; + exportedCheckValues[1] = this->sowcr_; + exportedCheckValues[2] = this->swcr_; + exportedCheckValues[3] = Scalar{1} - (this->sowcr_ + this->sgl_); + exportedCheckValues[4] = this->swu_; + } + + /// Descriptive textual summary of this check. + std::string description() const override + { + return { "Mobile displacing oil in three point " + "horizontally scaled oil/water system" }; + } + + /// Textual representation of the consistency condition. + std::string condition() const override + { + return { "SWCR < 1-SOWCR-SGL < SWU" }; + } + + /// Retrieve names of the exported check values. + /// + /// \param[in,out] headers Pointer to contiguous sequence of at + /// least numExportedCheckValues() strings. + void columnNames(std::string* headers) const override + { + headers[0] = "SGL"; + headers[1] = "SOWCR"; + headers[2] = "SWCR"; + headers[3] = "1-SOWCR-SGL"; + headers[4] = "SWU"; + } + + private: + /// Minimum gas saturation. + Scalar sgl_; + + /// Critical oil saturation in two-phase oil/water system. + Scalar sowcr_; + + /// Critical water saturation. + Scalar swcr_; + + /// Maximum water saturation. + Scalar swu_; + + /// Run check against a set of saturation function end-points. + /// + /// \param[in] endPoints Set of saturation function end-points. + /// Might for instance be the scaled end-points of the drainage + /// functions in a single grid block or the unscaled end-points + /// of the tabulated saturation functions in a single saturation + /// region. + void testImpl(const EclEpsScalingPointsInfo& endPoints) override; + }; + +} // namespace Opm::Satfunc::PhaseChecks::ThreePointHorizontal + +#endif // THREE_POINT_HORIZONTAL_CONSISTENCY_CHECKS_HPP_INCLUDED diff --git a/tests/test_ThreePointHorizontalSatfuncConsistencyChecks.cpp b/tests/test_ThreePointHorizontalSatfuncConsistencyChecks.cpp new file mode 100644 index 000000000..10c3ccaba --- /dev/null +++ b/tests/test_ThreePointHorizontalSatfuncConsistencyChecks.cpp @@ -0,0 +1,1687 @@ +/* + 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 . +*/ + +#include + +#define BOOST_TEST_MODULE TestThreePointHorizontalConsistencyChecks + +#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 + +#include + +#include + +#include +#include +#include + +// ########################################################################### + +namespace Checks = Opm::Satfunc::PhaseChecks::ThreePointHorizontal; + +// =========================================================================== + +BOOST_AUTO_TEST_SUITE(Displacing_Oil_in_Gas_Oil) + +BOOST_AUTO_TEST_CASE(All_Good) +{ + auto check = Checks::DisplacingOil_GO{}; + + constexpr auto expectNumExportedCheckValues = std::size_t{5}; + + BOOST_CHECK_EQUAL(check.numExportedCheckValues(), expectNumExportedCheckValues); + + { + auto columns = std::vector(expectNumExportedCheckValues); + check.columnNames(columns.data()); + + BOOST_CHECK_EQUAL(columns[0], "SWL"); + BOOST_CHECK_EQUAL(columns[1], "SOGCR"); + BOOST_CHECK_EQUAL(columns[2], "SGCR"); + BOOST_CHECK_EQUAL(columns[3], "1-SOGCR-SWL"); + BOOST_CHECK_EQUAL(columns[4], "SGU"); + } + + { + auto endPoints = Opm::EclEpsScalingPointsInfo{}; + endPoints.Swl = 0.25f; + endPoints.Sgcr = 0.15f; + endPoints.Sogcr = 0.3f; + endPoints.Sgu = 0.7; + + check.test(endPoints); + } + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[3], 0.45f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + } + + BOOST_CHECK_MESSAGE(! check.isViolated(), "Test must not be violated"); + BOOST_CHECK_MESSAGE(! check.isCritical(), "Test must not be violated at critical level"); +} + +BOOST_AUTO_TEST_CASE(Non_Finite) +{ + // NaN + if constexpr (std::numeric_limits::has_quiet_NaN) { + constexpr auto expectNumExportedCheckValues = std::size_t{5}; + + auto endPoints = Opm::EclEpsScalingPointsInfo{}; + endPoints.Swl = std::numeric_limits::quiet_NaN(); + endPoints.Sgcr = 0.15f; + endPoints.Sogcr = 0.3f; + endPoints.Sgu = 0.7; + + auto check = Checks::DisplacingOil_GO{}; + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isnan(values[0]), "Swl value must be NaN"); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sogcr-Swl value must be NaN"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = 0.25f; + endPoints.Sgcr = std::numeric_limits::quiet_NaN(); + endPoints.Sogcr = 0.3f; + endPoints.Sgu = 0.7; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[2]), "Sgcr value must be NaN"); + BOOST_CHECK_CLOSE(values[3], 0.45f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = 0.25f; + endPoints.Sgcr = 0.15f; + endPoints.Sogcr = std::numeric_limits::quiet_NaN(); + endPoints.Sgu = 0.7; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[1]), "Sogcr value must be NaN"); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sogcr-Swl value must be NaN"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = 0.25f; + endPoints.Sgcr = 0.15f; + endPoints.Sogcr = 0.3f; + endPoints.Sgu = std::numeric_limits::quiet_NaN(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[3], 0.45f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[4]), "Sgu value must be NaN"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = std::numeric_limits::quiet_NaN(); + endPoints.Sgcr = std::numeric_limits::quiet_NaN(); + endPoints.Sogcr = 0.3f; + endPoints.Sgu = 0.7; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isnan(values[0]), "Swl value must be NaN"); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[2]), "Sgcr value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sogcr-Swl value must be NaN"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = std::numeric_limits::quiet_NaN(); + endPoints.Sgcr = 0.15f; + endPoints.Sogcr = std::numeric_limits::quiet_NaN(); + endPoints.Sgu = 0.7; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isnan(values[0]), "Swl value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[1]), "Sogcr value must be NaN"); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sogcr-Swl value must be NaN"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = std::numeric_limits::quiet_NaN(); + endPoints.Sgcr = 0.15f; + endPoints.Sogcr = 0.3f; + endPoints.Sgu = std::numeric_limits::quiet_NaN(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isnan(values[0]), "Swl value must be NaN"); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sogcr-Swl value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[4]), "Sgu value must be NaN"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = 0.25f; + endPoints.Sgcr = std::numeric_limits::quiet_NaN(); + endPoints.Sogcr = std::numeric_limits::quiet_NaN(); + endPoints.Sgu = 0.7; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[1]), "Sgcr value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[2]), "Sogcr value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sogcr-Swl value must be NaN"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = 0.25f; + endPoints.Sgcr = std::numeric_limits::quiet_NaN(); + endPoints.Sogcr = 0.3f; + endPoints.Sgu = std::numeric_limits::quiet_NaN(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[2]), "Sgcr value must be NaN"); + BOOST_CHECK_CLOSE(values[3], 0.45f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[4]), "Sgu value must be NaN"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = 0.25f; + endPoints.Sgcr = 0.15f; + endPoints.Sogcr = std::numeric_limits::quiet_NaN(); + endPoints.Sgu = std::numeric_limits::quiet_NaN(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[1]), "Sogcr value must be NaN"); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sogcr-Swl value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[4]), "Sgu value must be NaN"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = std::numeric_limits::quiet_NaN(); + endPoints.Sgcr = std::numeric_limits::quiet_NaN(); + endPoints.Sogcr = std::numeric_limits::quiet_NaN(); + endPoints.Sgu = 0.7f; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isnan(values[0]), "Swl value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[1]), "Sogcr value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[2]), "Sgcr value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sogcr-Swl value must be NaN"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = std::numeric_limits::quiet_NaN(); + endPoints.Sgcr = 0.15f; + endPoints.Sogcr = std::numeric_limits::quiet_NaN(); + endPoints.Sgu = std::numeric_limits::quiet_NaN(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isnan(values[0]), "Swl value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[1]), "Sogcr value must be NaN"); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sogcr-Swl value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[4]), "Sgu value must be NaN"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = std::numeric_limits::quiet_NaN(); + endPoints.Sgcr = std::numeric_limits::quiet_NaN(); + endPoints.Sogcr = 0.3f; + endPoints.Sgu = std::numeric_limits::quiet_NaN(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isnan(values[0]), "Swl value must be NaN"); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[2]), "Sgcr value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sogcr-Swl value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[4]), "Sgu value must be NaN"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = 0.25f; + endPoints.Sgcr = std::numeric_limits::quiet_NaN(); + endPoints.Sogcr = std::numeric_limits::quiet_NaN(); + endPoints.Sgu = std::numeric_limits::quiet_NaN(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[1]), "Sogcr value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[2]), "Sgcr value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sogcr-Swl value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[4]), "Sgu value must be NaN"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = std::numeric_limits::quiet_NaN(); + endPoints.Sgcr = std::numeric_limits::quiet_NaN(); + endPoints.Sogcr = std::numeric_limits::quiet_NaN(); + endPoints.Sgu = std::numeric_limits::quiet_NaN(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isnan(values[0]), "Swl value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[1]), "Sogcr value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[2]), "Sgcr value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sogcr-Swl value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[4]), "Sgu value must be NaN"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + } + + // Inf + if constexpr (std::numeric_limits::has_infinity) { + constexpr auto expectNumExportedCheckValues = std::size_t{5}; + + auto endPoints = Opm::EclEpsScalingPointsInfo{}; + endPoints.Swl = std::numeric_limits::infinity(); + endPoints.Sgcr = 0.15f; + endPoints.Sogcr = 0.3f; + endPoints.Sgu = 0.7; + + auto check = Checks::DisplacingOil_GO{}; + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isinf(values[0]), "Swl value must be Inf"); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sogcr-Swl value must be Inf"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = 0.25f; + endPoints.Sgcr = std::numeric_limits::infinity(); + endPoints.Sogcr = 0.3f; + endPoints.Sgu = 0.7; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[2]), "Sgcr value must be Inf"); + BOOST_CHECK_CLOSE(values[3], 0.45f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = 0.25f; + endPoints.Sgcr = 0.15f; + endPoints.Sogcr = std::numeric_limits::infinity(); + endPoints.Sgu = 0.7; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[1]), "Sogcr value must be Inf"); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sogcr-Swl value must be Inf"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = 0.25f; + endPoints.Sgcr = 0.15f; + endPoints.Sogcr = 0.3f; + endPoints.Sgu = std::numeric_limits::infinity(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[3], 0.45f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[4]), "Sgu value must be Inf"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = std::numeric_limits::infinity(); + endPoints.Sgcr = std::numeric_limits::infinity(); + endPoints.Sogcr = 0.3f; + endPoints.Sgu = 0.7; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isinf(values[0]), "Swl value must be Inf"); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[2]), "Sgcr value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sogcr-Swl value must be Inf"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = std::numeric_limits::infinity(); + endPoints.Sgcr = 0.15f; + endPoints.Sogcr = std::numeric_limits::infinity(); + endPoints.Sgu = 0.7; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isinf(values[0]), "Swl value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[1]), "Sogcr value must be Inf"); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sogcr-Swl value must be Inf"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = std::numeric_limits::infinity(); + endPoints.Sgcr = 0.15f; + endPoints.Sogcr = 0.3f; + endPoints.Sgu = std::numeric_limits::infinity(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isinf(values[0]), "Swl value must be Inf"); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sogcr-Swl value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[4]), "Sgu value must be Inf"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = 0.25f; + endPoints.Sgcr = std::numeric_limits::infinity(); + endPoints.Sogcr = std::numeric_limits::infinity(); + endPoints.Sgu = 0.7; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[1]), "Sgcr value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[2]), "Sogcr value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sogcr-Swl value must be Inf"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = 0.25f; + endPoints.Sgcr = std::numeric_limits::infinity(); + endPoints.Sogcr = 0.3f; + endPoints.Sgu = std::numeric_limits::infinity(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[2]), "Sgcr value must be Inf"); + BOOST_CHECK_CLOSE(values[3], 0.45f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[4]), "Sgu value must be Inf"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = 0.25f; + endPoints.Sgcr = 0.15f; + endPoints.Sogcr = std::numeric_limits::infinity(); + endPoints.Sgu = std::numeric_limits::infinity(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[1]), "Sogcr value must be Inf"); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sogcr-Swl value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[4]), "Sgu value must be Inf"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = std::numeric_limits::infinity(); + endPoints.Sgcr = std::numeric_limits::infinity(); + endPoints.Sogcr = std::numeric_limits::infinity(); + endPoints.Sgu = 0.7f; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isinf(values[0]), "Swl value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[1]), "Sogcr value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[2]), "Sgcr value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sogcr-Swl value must be Inf"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = std::numeric_limits::infinity(); + endPoints.Sgcr = 0.15f; + endPoints.Sogcr = std::numeric_limits::infinity(); + endPoints.Sgu = std::numeric_limits::infinity(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isinf(values[0]), "Swl value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[1]), "Sogcr value must be Inf"); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sogcr-Swl value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[4]), "Sgu value must be Inf"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = std::numeric_limits::infinity(); + endPoints.Sgcr = std::numeric_limits::infinity(); + endPoints.Sogcr = 0.3f; + endPoints.Sgu = std::numeric_limits::infinity(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isinf(values[0]), "Swl value must be Inf"); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[2]), "Sgcr value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sogcr-Swl value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[4]), "Sgu value must be Inf"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = 0.25f; + endPoints.Sgcr = std::numeric_limits::infinity(); + endPoints.Sogcr = std::numeric_limits::infinity(); + endPoints.Sgu = std::numeric_limits::infinity(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[1]), "Sogcr value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[2]), "Sgcr value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sogcr-Swl value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[4]), "Sgu value must be Inf"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Swl = std::numeric_limits::infinity(); + endPoints.Sgcr = std::numeric_limits::infinity(); + endPoints.Sogcr = std::numeric_limits::infinity(); + endPoints.Sgu = std::numeric_limits::infinity(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isinf(values[0]), "Swl value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[1]), "Sogcr value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[2]), "Sgcr value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sogcr-Swl value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[4]), "Sgu value must be Inf"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + } +} + +BOOST_AUTO_TEST_CASE(Sr_TooSmall) +{ + auto check = Checks::DisplacingOil_GO{}; + + constexpr auto expectNumExportedCheckValues = std::size_t{5}; + + { + auto endPoints = Opm::EclEpsScalingPointsInfo{}; + endPoints.Swl = 0.55f; + endPoints.Sgcr = 0.15f; + endPoints.Sogcr = 0.35f; + endPoints.Sgu = 0.7; + + check.test(endPoints); + } + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.55f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.35f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[3], 0.1f, 3.0e-5f); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + } + + BOOST_CHECK_MESSAGE(check.isViolated(), "Test must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Test must be violated at critical level"); +} + +BOOST_AUTO_TEST_CASE(Sr_Is_Lower_Bound) +{ + auto check = Checks::DisplacingOil_GO{}; + + constexpr auto expectNumExportedCheckValues = std::size_t{5}; + + { + auto endPoints = Opm::EclEpsScalingPointsInfo{}; + endPoints.Swl = 0.50f; + endPoints.Sgcr = 0.15f; + endPoints.Sogcr = 0.35f; + endPoints.Sgu = 0.7; + + check.test(endPoints); + } + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.50f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.35f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[3], 0.15f, 2.0e-5f); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + } + + BOOST_CHECK_MESSAGE(check.isViolated(), "Test must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Test must be violated at critical level"); +} + +BOOST_AUTO_TEST_CASE(Sr_TooLarge) +{ + auto check = Checks::DisplacingOil_GO{}; + + constexpr auto expectNumExportedCheckValues = std::size_t{5}; + + { + auto endPoints = Opm::EclEpsScalingPointsInfo{}; + endPoints.Swl = 0.0f; + endPoints.Sgcr = 0.15f; + endPoints.Sogcr = 0.25f; + endPoints.Sgu = 0.7; + + check.test(endPoints); + } + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.0f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.25f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[3], 0.75f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + } + + BOOST_CHECK_MESSAGE(check.isViolated(), "Test must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Test must be violated at critical level"); +} + +BOOST_AUTO_TEST_CASE(Sr_Is_Upper_Bound) +{ + auto check = Checks::DisplacingOil_GO{}; + + constexpr auto expectNumExportedCheckValues = std::size_t{5}; + + { + auto endPoints = Opm::EclEpsScalingPointsInfo{}; + endPoints.Swl = 0.05f; + endPoints.Sgcr = 0.15f; + endPoints.Sogcr = 0.25f; + endPoints.Sgu = 0.7; + + check.test(endPoints); + } + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.05f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.25f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[3], 0.7f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + } + + BOOST_CHECK_MESSAGE(check.isViolated(), "Test must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Test must be violated at critical level"); +} + +BOOST_AUTO_TEST_SUITE_END() // Displacing_Oil_in_Gas_Oil + +// =========================================================================== + +BOOST_AUTO_TEST_SUITE(Displacing_Oil_in_Oil_Water) + +BOOST_AUTO_TEST_CASE(All_Good) +{ + auto check = Checks::DisplacingOil_OW{}; + + constexpr auto expectNumExportedCheckValues = std::size_t{5}; + + BOOST_CHECK_EQUAL(check.numExportedCheckValues(), expectNumExportedCheckValues); + + { + auto columns = std::vector(expectNumExportedCheckValues); + check.columnNames(columns.data()); + + BOOST_CHECK_EQUAL(columns[0], "SGL"); + BOOST_CHECK_EQUAL(columns[1], "SOWCR"); + BOOST_CHECK_EQUAL(columns[2], "SWCR"); + BOOST_CHECK_EQUAL(columns[3], "1-SOWCR-SGL"); + BOOST_CHECK_EQUAL(columns[4], "SWU"); + } + + { + auto endPoints = Opm::EclEpsScalingPointsInfo{}; + endPoints.Sgl = 0.25f; + endPoints.Swcr = 0.15f; + endPoints.Sowcr = 0.3f; + endPoints.Swu = 0.7; + + check.test(endPoints); + } + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[3], 0.45f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + } + + BOOST_CHECK_MESSAGE(! check.isViolated(), "Test must not be violated"); + BOOST_CHECK_MESSAGE(! check.isCritical(), "Test must not be violated at critical level"); +} + +BOOST_AUTO_TEST_CASE(Non_Finite) +{ + // NaN + if constexpr (std::numeric_limits::has_quiet_NaN) { + constexpr auto expectNumExportedCheckValues = std::size_t{5}; + + auto endPoints = Opm::EclEpsScalingPointsInfo{}; + endPoints.Sgl = std::numeric_limits::quiet_NaN(); + endPoints.Swcr = 0.15f; + endPoints.Sowcr = 0.3f; + endPoints.Swu = 0.7; + + auto check = Checks::DisplacingOil_OW{}; + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isnan(values[0]), "Sgl value must be NaN"); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sowcr-Sgl value must be NaN"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = 0.25f; + endPoints.Swcr = std::numeric_limits::quiet_NaN(); + endPoints.Sowcr = 0.3f; + endPoints.Swu = 0.7; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[2]), "Swcr value must be NaN"); + BOOST_CHECK_CLOSE(values[3], 0.45f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = 0.25f; + endPoints.Swcr = 0.15f; + endPoints.Sowcr = std::numeric_limits::quiet_NaN(); + endPoints.Swu = 0.7; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[1]), "Sowcr value must be NaN"); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sowcr-Sgl value must be NaN"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = 0.25f; + endPoints.Swcr = 0.15f; + endPoints.Sowcr = 0.3f; + endPoints.Swu = std::numeric_limits::quiet_NaN(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[3], 0.45f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[4]), "Swu value must be NaN"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = std::numeric_limits::quiet_NaN(); + endPoints.Swcr = std::numeric_limits::quiet_NaN(); + endPoints.Sowcr = 0.3f; + endPoints.Swu = 0.7; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isnan(values[0]), "Sgl value must be NaN"); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[2]), "Swcr value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sowcr-Sgl value must be NaN"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = std::numeric_limits::quiet_NaN(); + endPoints.Swcr = 0.15f; + endPoints.Sowcr = std::numeric_limits::quiet_NaN(); + endPoints.Swu = 0.7; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isnan(values[0]), "Sgl value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[1]), "Sowcr value must be NaN"); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sowcr-Sgl value must be NaN"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = std::numeric_limits::quiet_NaN(); + endPoints.Swcr = 0.15f; + endPoints.Sowcr = 0.3f; + endPoints.Swu = std::numeric_limits::quiet_NaN(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isnan(values[0]), "Sgl value must be NaN"); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sowcr-Sgl value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[4]), "Swu value must be NaN"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = 0.25f; + endPoints.Swcr = std::numeric_limits::quiet_NaN(); + endPoints.Sowcr = std::numeric_limits::quiet_NaN(); + endPoints.Swu = 0.7; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[1]), "Swcr value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[2]), "Sowcr value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sowcr-Sgl value must be NaN"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = 0.25f; + endPoints.Swcr = std::numeric_limits::quiet_NaN(); + endPoints.Sowcr = 0.3f; + endPoints.Swu = std::numeric_limits::quiet_NaN(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[2]), "Swcr value must be NaN"); + BOOST_CHECK_CLOSE(values[3], 0.45f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[4]), "Swu value must be NaN"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = 0.25f; + endPoints.Swcr = 0.15f; + endPoints.Sowcr = std::numeric_limits::quiet_NaN(); + endPoints.Swu = std::numeric_limits::quiet_NaN(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[1]), "Sowcr value must be NaN"); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sowcr-Sgl value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[4]), "Swu value must be NaN"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = std::numeric_limits::quiet_NaN(); + endPoints.Swcr = std::numeric_limits::quiet_NaN(); + endPoints.Sowcr = std::numeric_limits::quiet_NaN(); + endPoints.Swu = 0.7f; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isnan(values[0]), "Sgl value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[1]), "Sowcr value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[2]), "Swcr value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sowcr-Sgl value must be NaN"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = std::numeric_limits::quiet_NaN(); + endPoints.Swcr = 0.15f; + endPoints.Sowcr = std::numeric_limits::quiet_NaN(); + endPoints.Swu = std::numeric_limits::quiet_NaN(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isnan(values[0]), "Sgl value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[1]), "Sowcr value must be NaN"); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sowcr-Sgl value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[4]), "Swu value must be NaN"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = std::numeric_limits::quiet_NaN(); + endPoints.Swcr = std::numeric_limits::quiet_NaN(); + endPoints.Sowcr = 0.3f; + endPoints.Swu = std::numeric_limits::quiet_NaN(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isnan(values[0]), "Sgl value must be NaN"); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[2]), "Swcr value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sowcr-Sgl value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[4]), "Swu value must be NaN"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = 0.25f; + endPoints.Swcr = std::numeric_limits::quiet_NaN(); + endPoints.Sowcr = std::numeric_limits::quiet_NaN(); + endPoints.Swu = std::numeric_limits::quiet_NaN(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isnan(values[1]), "Sowcr value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[2]), "Swcr value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sowcr-Sgl value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[4]), "Swu value must be NaN"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = std::numeric_limits::quiet_NaN(); + endPoints.Swcr = std::numeric_limits::quiet_NaN(); + endPoints.Sowcr = std::numeric_limits::quiet_NaN(); + endPoints.Swu = std::numeric_limits::quiet_NaN(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isnan(values[0]), "Sgl value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[1]), "Sowcr value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[2]), "Swcr value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[3]), "1-Sowcr-Sgl value must be NaN"); + BOOST_CHECK_MESSAGE(std::isnan(values[4]), "Swu value must be NaN"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + } + + // Inf + if constexpr (std::numeric_limits::has_infinity) { + constexpr auto expectNumExportedCheckValues = std::size_t{5}; + + auto endPoints = Opm::EclEpsScalingPointsInfo{}; + endPoints.Sgl = std::numeric_limits::infinity(); + endPoints.Swcr = 0.15f; + endPoints.Sowcr = 0.3f; + endPoints.Swu = 0.7; + + auto check = Checks::DisplacingOil_OW{}; + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isinf(values[0]), "Sgl value must be Inf"); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sowcr-Sgl value must be Inf"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = 0.25f; + endPoints.Swcr = std::numeric_limits::infinity(); + endPoints.Sowcr = 0.3f; + endPoints.Swu = 0.7; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[2]), "Swcr value must be Inf"); + BOOST_CHECK_CLOSE(values[3], 0.45f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = 0.25f; + endPoints.Swcr = 0.15f; + endPoints.Sowcr = std::numeric_limits::infinity(); + endPoints.Swu = 0.7; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[1]), "Sowcr value must be Inf"); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sowcr-Sgl value must be Inf"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = 0.25f; + endPoints.Swcr = 0.15f; + endPoints.Sowcr = 0.3f; + endPoints.Swu = std::numeric_limits::infinity(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[3], 0.45f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[4]), "Swu value must be Inf"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = std::numeric_limits::infinity(); + endPoints.Swcr = std::numeric_limits::infinity(); + endPoints.Sowcr = 0.3f; + endPoints.Swu = 0.7; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isinf(values[0]), "Sgl value must be Inf"); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[2]), "Swcr value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sowcr-Sgl value must be Inf"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = std::numeric_limits::infinity(); + endPoints.Swcr = 0.15f; + endPoints.Sowcr = std::numeric_limits::infinity(); + endPoints.Swu = 0.7; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isinf(values[0]), "Sgl value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[1]), "Sowcr value must be Inf"); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sowcr-Sgl value must be Inf"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = std::numeric_limits::infinity(); + endPoints.Swcr = 0.15f; + endPoints.Sowcr = 0.3f; + endPoints.Swu = std::numeric_limits::infinity(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isinf(values[0]), "Sgl value must be Inf"); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sowcr-Sgl value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[4]), "Swu value must be Inf"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = 0.25f; + endPoints.Swcr = std::numeric_limits::infinity(); + endPoints.Sowcr = std::numeric_limits::infinity(); + endPoints.Swu = 0.7; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[1]), "Swcr value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[2]), "Sowcr value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sowcr-Sgl value must be Inf"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = 0.25f; + endPoints.Swcr = std::numeric_limits::infinity(); + endPoints.Sowcr = 0.3f; + endPoints.Swu = std::numeric_limits::infinity(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[2]), "Swcr value must be Inf"); + BOOST_CHECK_CLOSE(values[3], 0.45f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[4]), "Swu value must be Inf"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = 0.25f; + endPoints.Swcr = 0.15f; + endPoints.Sowcr = std::numeric_limits::infinity(); + endPoints.Swu = std::numeric_limits::infinity(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[1]), "Sowcr value must be Inf"); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sowcr-Sgl value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[4]), "Swu value must be Inf"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = std::numeric_limits::infinity(); + endPoints.Swcr = std::numeric_limits::infinity(); + endPoints.Sowcr = std::numeric_limits::infinity(); + endPoints.Swu = 0.7f; + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isinf(values[0]), "Sgl value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[1]), "Sowcr value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[2]), "Swcr value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sowcr-Sgl value must be Inf"); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = std::numeric_limits::infinity(); + endPoints.Swcr = 0.15f; + endPoints.Sowcr = std::numeric_limits::infinity(); + endPoints.Swu = std::numeric_limits::infinity(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isinf(values[0]), "Sgl value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[1]), "Sowcr value must be Inf"); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sowcr-Sgl value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[4]), "Swu value must be Inf"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = std::numeric_limits::infinity(); + endPoints.Swcr = std::numeric_limits::infinity(); + endPoints.Sowcr = 0.3f; + endPoints.Swu = std::numeric_limits::infinity(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isinf(values[0]), "Sgl value must be Inf"); + BOOST_CHECK_CLOSE(values[1], 0.3f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[2]), "Swcr value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sowcr-Sgl value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[4]), "Swu value must be Inf"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = 0.25f; + endPoints.Swcr = std::numeric_limits::infinity(); + endPoints.Sowcr = std::numeric_limits::infinity(); + endPoints.Swu = std::numeric_limits::infinity(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.25f, 1.0e-6f); + BOOST_CHECK_MESSAGE(std::isinf(values[1]), "Sowcr value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[2]), "Swcr value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sowcr-Sgl value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[4]), "Swu value must be Inf"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + + endPoints.Sgl = std::numeric_limits::infinity(); + endPoints.Swcr = std::numeric_limits::infinity(); + endPoints.Sowcr = std::numeric_limits::infinity(); + endPoints.Swu = std::numeric_limits::infinity(); + + check.test(endPoints); + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_MESSAGE(std::isinf(values[0]), "Sgl value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[1]), "Sowcr value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[2]), "Swcr value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[3]), "1-Sowcr-Sgl value must be Inf"); + BOOST_CHECK_MESSAGE(std::isinf(values[4]), "Swu value must be Inf"); + + BOOST_CHECK_MESSAGE(check.isViolated(), "Check must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Check must be violated at critical level"); + } + } +} + +BOOST_AUTO_TEST_CASE(Sr_TooSmall) +{ + auto check = Checks::DisplacingOil_OW{}; + + constexpr auto expectNumExportedCheckValues = std::size_t{5}; + + { + auto endPoints = Opm::EclEpsScalingPointsInfo{}; + endPoints.Sgl = 0.55f; + endPoints.Swcr = 0.15f; + endPoints.Sowcr = 0.35f; + endPoints.Swu = 0.7; + + check.test(endPoints); + } + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.55f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.35f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[3], 0.1f, 3.0e-5f); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + } + + BOOST_CHECK_MESSAGE(check.isViolated(), "Test must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Test must be violated at critical level"); +} + +BOOST_AUTO_TEST_CASE(Sr_Is_Lower_Bound) +{ + auto check = Checks::DisplacingOil_OW{}; + + constexpr auto expectNumExportedCheckValues = std::size_t{5}; + + { + auto endPoints = Opm::EclEpsScalingPointsInfo{}; + endPoints.Sgl = 0.50f; + endPoints.Swcr = 0.15f; + endPoints.Sowcr = 0.35f; + endPoints.Swu = 0.7; + + check.test(endPoints); + } + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.50f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.35f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[3], 0.15f, 2.0e-5f); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + } + + BOOST_CHECK_MESSAGE(check.isViolated(), "Test must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Test must be violated at critical level"); +} + +BOOST_AUTO_TEST_CASE(Sr_TooLarge) +{ + auto check = Checks::DisplacingOil_OW{}; + + constexpr auto expectNumExportedCheckValues = std::size_t{5}; + + { + auto endPoints = Opm::EclEpsScalingPointsInfo{}; + endPoints.Sgl = 0.0f; + endPoints.Swcr = 0.15f; + endPoints.Sowcr = 0.25f; + endPoints.Swu = 0.7; + + check.test(endPoints); + } + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.0f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.25f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[3], 0.75f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + } + + BOOST_CHECK_MESSAGE(check.isViolated(), "Test must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Test must be violated at critical level"); +} + +BOOST_AUTO_TEST_CASE(Sr_Is_Upper_Bound) +{ + auto check = Checks::DisplacingOil_OW{}; + + constexpr auto expectNumExportedCheckValues = std::size_t{5}; + + { + auto endPoints = Opm::EclEpsScalingPointsInfo{}; + endPoints.Sgl = 0.05f; + endPoints.Swcr = 0.15f; + endPoints.Sowcr = 0.25f; + endPoints.Swu = 0.7; + + check.test(endPoints); + } + + { + auto values = std::vector(expectNumExportedCheckValues); + check.exportCheckValues(values.data()); + + BOOST_CHECK_CLOSE(values[0], 0.05f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[1], 0.25f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[2], 0.15f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[3], 0.7f, 1.0e-6f); + BOOST_CHECK_CLOSE(values[4], 0.7f, 1.0e-6f); + } + + BOOST_CHECK_MESSAGE(check.isViolated(), "Test must be violated"); + BOOST_CHECK_MESSAGE(check.isCritical(), "Test must be violated at critical level"); +} + +BOOST_AUTO_TEST_SUITE_END() // Displacing_Oil_in_Oil_Water