/*
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 TestSatfuncConsistencyChecks
#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
#include
#include
BOOST_AUTO_TEST_SUITE(NoFailures)
namespace {
class Standard : public Opm::SatfuncConsistencyChecks::Check
{
public:
void test(const Opm::EclEpsScalingPointsInfo&) override {}
bool isViolated() const override { return false; }
bool isCritical() const override { return false; }
std::size_t numExportedCheckValues() const override { return 1; }
void exportCheckValues(double* exportedCheckValues) const override
{
*exportedCheckValues = 17.29;
}
std::string description() const override
{
return "Water Phase End-Point";
}
std::string condition() const override
{
return "0 <= SWL < 1";
}
void columnNames(std::string* headers) const override
{
*headers = "SWL";
}
};
Opm::EclEpsScalingPointsInfo makePoints() { return {}; }
} // Anonymous namespace
BOOST_AUTO_TEST_CASE(All_Good)
{
auto checker = Opm::SatfuncConsistencyChecks{"Cell", 1};
checker.resetCheckSet();
checker.addCheck(std::make_unique());
checker.finaliseCheckSet();
checker.checkEndpoints(1234, makePoints());
BOOST_CHECK_MESSAGE(! checker.anyFailedChecks(),
"There must be no failed checks");
BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(),
"There must be no failed critical checks");
auto rpt = std::string{};
checker.reportFailures(Opm::SatfuncConsistencyChecks::ViolationLevel::Standard,
[&rpt](std::string_view record)
{
rpt += fmt::format("{}\n", record);
});
BOOST_CHECK_MESSAGE(rpt.empty(), "There must be no output from reportFailures()");
}
BOOST_AUTO_TEST_SUITE_END()
// ===========================================================================
BOOST_AUTO_TEST_SUITE(Single_Exported_Value)
namespace {
class StandardViolation : public Opm::SatfuncConsistencyChecks::Check
{
public:
void test(const Opm::EclEpsScalingPointsInfo&) override {}
bool isViolated() const override { return true; }
bool isCritical() const override { return false; }
std::size_t numExportedCheckValues() const override { return 1; }
void exportCheckValues(double* exportedCheckValues) const override
{
*exportedCheckValues = 17.29;
}
std::string description() const override
{
return "Water Phase End-Point";
}
std::string condition() const override
{
return "0 <= SWL < 1";
}
void columnNames(std::string* headers) const override
{
*headers = "SWL";
}
};
class CriticalViolation : public Opm::SatfuncConsistencyChecks::Check
{
public:
void test(const Opm::EclEpsScalingPointsInfo&) override {}
bool isViolated() const override { return true; }
bool isCritical() const override { return true; }
std::size_t numExportedCheckValues() const override { return 1; }
void exportCheckValues(double* exportedCheckValues) const override
{
*exportedCheckValues = 314.15926;
}
std::string description() const override
{
return "Minimum Pressure";
}
std::string condition() const override
{
return "PRESS > 350";
}
void columnNames(std::string* headers) const override
{
*headers = "PRESS";
}
};
Opm::EclEpsScalingPointsInfo makePoints() { return {}; }
} // Anonymous namespace
BOOST_AUTO_TEST_CASE(Standard_Violation)
{
auto checker = Opm::SatfuncConsistencyChecks{"Cell", 1};
checker.resetCheckSet();
checker.addCheck(std::make_unique());
checker.finaliseCheckSet();
checker.checkEndpoints(1234, makePoints());
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
"There must be at least one failed check");
auto rpt = std::string{};
checker.reportFailures(Opm::SatfuncConsistencyChecks::ViolationLevel::Standard,
[&rpt](std::string_view record)
{
rpt += fmt::format("{}\n", record);
});
BOOST_CHECK_EQUAL(rpt, R"(Consistency Problem:
Water Phase End-Point
0 <= SWL < 1
Total Violations: 1
List of Violations
+------+---------------+
| Cell | SWL |
+------+---------------+
| 1234 | 1.729000e+01 |
+------+---------------+
)");
}
BOOST_AUTO_TEST_CASE(Standard_Violation_ReportIJK)
{
auto checker = Opm::SatfuncConsistencyChecks{"Cell", 1};
checker.resetCheckSet();
checker.addCheck(std::make_unique());
checker.finaliseCheckSet();
checker.setPointIDFormatCallback([](const std::size_t)
{
return std::string { "(11, 22, 33)" };
});
checker.checkEndpoints(1234, makePoints());
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
"There must be at least one failed check");
auto rpt = std::string{};
checker.reportFailures(Opm::SatfuncConsistencyChecks::ViolationLevel::Standard,
[&rpt](std::string_view record)
{
rpt += fmt::format("{}\n", record);
});
BOOST_CHECK_EQUAL(rpt, R"(Consistency Problem:
Water Phase End-Point
0 <= SWL < 1
Total Violations: 1
List of Violations
+--------------+---------------+
| Cell | SWL |
+--------------+---------------+
| (11, 22, 33) | 1.729000e+01 |
+--------------+---------------+
)");
}
BOOST_AUTO_TEST_CASE(Critical_Violation)
{
auto checker = Opm::SatfuncConsistencyChecks{"PVTNUM", 1};
checker.resetCheckSet();
checker.addCheck(std::make_unique());
checker.finaliseCheckSet();
checker.checkEndpoints(42, makePoints());
BOOST_CHECK_MESSAGE(! checker.anyFailedChecks(),
"There must be no failed standard level checks");
BOOST_CHECK_MESSAGE(checker.anyFailedCriticalChecks(),
"There must be at least one failed Critical check");
auto rpt = std::string{};
checker.reportFailures(Opm::SatfuncConsistencyChecks::ViolationLevel::Critical,
[&rpt](std::string_view record)
{
rpt += fmt::format("{}\n", record);
});
BOOST_CHECK_EQUAL(rpt, R"(Consistency Problem:
Minimum Pressure
PRESS > 350
Total Violations: 1
List of Violations
+--------+---------------+
| PVTNUM | PRESS |
+--------+---------------+
| 42 | 3.141593e+02 |
+--------+---------------+
)");
}
BOOST_AUTO_TEST_SUITE_END() // Single_Exported_Value
// ===========================================================================
BOOST_AUTO_TEST_SUITE(Two_Exported_Values)
namespace {
class Violation : public Opm::SatfuncConsistencyChecks::Check
{
void test(const Opm::EclEpsScalingPointsInfo&) override {}
bool isViolated() const override { return true; }
bool isCritical() const override { return false; }
std::size_t numExportedCheckValues() const override { return 2; }
void exportCheckValues(float* exportedCheckValues) const override
{
exportedCheckValues[0] = 1.6f;
exportedCheckValues[1] = 1.6f + 0.5f;
}
std::string description() const override
{
return "Sum";
}
std::string condition() const override
{
return "a + 1/2 < 2";
}
void columnNames(std::string* headers) const override
{
headers[0] = "a";
headers[1] = "a + 1/2";
}
};
Opm::EclEpsScalingPointsInfo makePoints() { return {}; }
} // Anonymous namespace
BOOST_AUTO_TEST_CASE(Standard)
{
auto checker = Opm::SatfuncConsistencyChecks{"Bucket", 1};
checker.resetCheckSet();
checker.addCheck(std::make_unique());
checker.finaliseCheckSet();
checker.checkEndpoints(1234, makePoints());
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
"There must be at least one failed check");
auto rpt = std::string{};
checker.reportFailures(Opm::SatfuncConsistencyChecks::ViolationLevel::Standard,
[&rpt](std::string_view record)
{
rpt += fmt::format("{}\n", record);
});
BOOST_CHECK_EQUAL(rpt, R"(Consistency Problem:
Sum
a + 1/2 < 2
Total Violations: 1
List of Violations
+--------+---------------+---------------+
| Bucket | a | a + 1/2 |
+--------+---------------+---------------+
| 1234 | 1.600000e+00 | 2.100000e+00 |
+--------+---------------+---------------+
)");
}
BOOST_AUTO_TEST_SUITE_END() // Two_Exported_Values
// ===========================================================================
BOOST_AUTO_TEST_SUITE(Five_Exported_Values)
namespace {
class Violation : public Opm::SatfuncConsistencyChecks::Check
{
void test(const Opm::EclEpsScalingPointsInfo&) override {}
bool isViolated() const override { return true; }
bool isCritical() const override { return false; }
std::size_t numExportedCheckValues() const override { return 5; }
void exportCheckValues(float* exportedCheckValues) const override
{
exportedCheckValues[0] = 0.1f;
exportedCheckValues[1] = 0.7f;
exportedCheckValues[2] = 0.3f;
exportedCheckValues[3] = 0.2f;
exportedCheckValues[4] = 0.88f;
}
std::string description() const override
{
return "Water Phase End-Point Displacing Saturation";
}
std::string condition() const override
{
return "SWCR < 1-SOWCR-SGL < SWU";
}
void columnNames(std::string* headers) const override
{
headers[0] = "SGL";
headers[1] = "SOWCR";
headers[2] = "SWCR";
headers[3] = "1-SOWCR-SGL";
headers[4] = "SWU";
}
};
Opm::EclEpsScalingPointsInfo makePoints() { return {}; }
} // Anonymous namespace
BOOST_AUTO_TEST_CASE(Standard)
{
auto checker = Opm::SatfuncConsistencyChecks{"Grid Block", 1};
checker.resetCheckSet();
checker.addCheck(std::make_unique());
checker.finaliseCheckSet();
checker.setPointIDFormatCallback([](const std::size_t)
{
return std::string { "(121, 323, 42)" };
});
checker.checkEndpoints(1234, makePoints());
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
"There must be at least one failed check");
auto rpt = std::string{};
checker.reportFailures(Opm::SatfuncConsistencyChecks::ViolationLevel::Standard,
[&rpt](std::string_view record)
{
rpt += fmt::format("{}\n", record);
});
BOOST_CHECK_EQUAL(rpt, R"(Consistency Problem:
Water Phase End-Point Displacing Saturation
SWCR < 1-SOWCR-SGL < SWU
Total Violations: 1
List of Violations
+----------------+---------------+---------------+---------------+---------------+---------------+
| Grid Block | SGL | SOWCR | SWCR | 1-SOWCR-SGL | SWU |
+----------------+---------------+---------------+---------------+---------------+---------------+
| (121, 323, 42) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 |
+----------------+---------------+---------------+---------------+---------------+---------------+
)");
}
BOOST_AUTO_TEST_CASE(Standard_Multiple_Failing_Points)
{
auto checker = Opm::SatfuncConsistencyChecks{"Grid Block", 5};
checker.resetCheckSet();
checker.addCheck(std::make_unique());
checker.finaliseCheckSet();
checker.checkEndpoints( 1234, makePoints());
checker.checkEndpoints( 1729, makePoints());
checker.checkEndpoints( 1618, makePoints());
checker.checkEndpoints(31415, makePoints());
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
"There must be at least one failed check");
auto rpt = std::string{};
checker.reportFailures(Opm::SatfuncConsistencyChecks::ViolationLevel::Standard,
[&rpt](std::string_view record)
{
rpt += fmt::format("{}\n", record);
});
// Note that grid blocks are reported in sorted order rather in the
// order of insertion.
BOOST_CHECK_EQUAL(rpt, R"(Consistency Problem:
Water Phase End-Point Displacing Saturation
SWCR < 1-SOWCR-SGL < SWU
Total Violations: 4
List of Violations
+------------+---------------+---------------+---------------+---------------+---------------+
| Grid Block | SGL | SOWCR | SWCR | 1-SOWCR-SGL | SWU |
+------------+---------------+---------------+---------------+---------------+---------------+
| 1234 | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 |
| 1618 | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 |
| 1729 | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 |
| 31415 | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 |
+------------+---------------+---------------+---------------+---------------+---------------+
)");
}
BOOST_AUTO_TEST_SUITE_END() // Five_Exported_Values
// ===========================================================================
BOOST_AUTO_TEST_SUITE(Multiple_Failing_Tests)
namespace {
class MonotoneWater : public Opm::SatfuncConsistencyChecks::Check
{
void test(const Opm::EclEpsScalingPointsInfo&) override {}
bool isViolated() const override { return true; }
bool isCritical() const override { return false; }
std::size_t numExportedCheckValues() const override { return 3; }
void exportCheckValues(float* exportedCheckValues) const override
{
exportedCheckValues[0] = 0.1f;
exportedCheckValues[1] = 0.3f;
exportedCheckValues[2] = 0.3f;
}
std::string description() const override
{
return "Water Phase End-Point Monotonicity";
}
std::string condition() const override
{
return "SWL <= SWCR < SWU";
}
void columnNames(std::string* headers) const override
{
headers[0] = "SWL";
headers[1] = "SWCR";
headers[2] = "SWU";
}
};
class MonotoneGas : public Opm::SatfuncConsistencyChecks::Check
{
void test(const Opm::EclEpsScalingPointsInfo&) override {}
bool isViolated() const override { return true; }
bool isCritical() const override { return false; }
std::size_t numExportedCheckValues() const override { return 3; }
void exportCheckValues(float* exportedCheckValues) const override
{
exportedCheckValues[0] = 0.0f;
exportedCheckValues[1] = -0.1f;
exportedCheckValues[2] = 0.8f;
}
std::string description() const override
{
return "Gas Phase End-Point Monotonicity";
}
std::string condition() const override
{
return "SGL <= SGCR < SGU";
}
void columnNames(std::string* headers) const override
{
headers[0] = "SGL";
headers[1] = "SGCR";
headers[2] = "SGU";
}
};
class NonNegOSAT_OW : public Opm::SatfuncConsistencyChecks::Check
{
void test(const Opm::EclEpsScalingPointsInfo&) override {}
bool isViolated() const override { return true; }
bool isCritical() const override { return false; }
std::size_t numExportedCheckValues() const override { return 3; }
void exportCheckValues(float* exportedCheckValues) const override
{
exportedCheckValues[0] = 0.1f;
exportedCheckValues[1] = 1.0f;
exportedCheckValues[2] = 1.1f;
}
std::string description() const override
{
return "Oil Phase Non-Negative Saturation (O/W)";
}
std::string condition() const override
{
return "SGL + SWU <= 1";
}
void columnNames(std::string* headers) const override
{
headers[0] = "SGL";
headers[1] = "SWU";
headers[2] = "SGL + SWU";
}
};
class NonNegOSAT_GO : public Opm::SatfuncConsistencyChecks::Check
{
void test(const Opm::EclEpsScalingPointsInfo&) override {}
bool isViolated() const override { return true; }
bool isCritical() const override { return false; }
std::size_t numExportedCheckValues() const override { return 3; }
void exportCheckValues(float* exportedCheckValues) const override
{
exportedCheckValues[0] = 0.25f;
exportedCheckValues[1] = 0.8f;
exportedCheckValues[2] = 1.05f;
}
std::string description() const override
{
return "Oil Phase Non-Negative Saturation (G/O)";
}
std::string condition() const override
{
return "SWL + SGU <= 1";
}
void columnNames(std::string* headers) const override
{
headers[0] = "SWL";
headers[1] = "SGU";
headers[2] = "SWL + SGU";
}
};
Opm::EclEpsScalingPointsInfo makePoints() { return {}; }
} // Anonymous namespace
BOOST_AUTO_TEST_CASE(Standard)
{
auto checker = Opm::SatfuncConsistencyChecks{"Grid Block", 1};
checker.resetCheckSet();
checker.addCheck(std::make_unique());
checker.addCheck(std::make_unique());
checker.addCheck(std::make_unique());
checker.addCheck(std::make_unique());
checker.finaliseCheckSet();
checker.setPointIDFormatCallback([](const std::size_t)
{
return std::string { "(121, 323, 42)" };
});
checker.checkEndpoints(1234, makePoints());
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
"There must be at least one failed check");
auto rpt = std::string{};
checker.reportFailures(Opm::SatfuncConsistencyChecks::ViolationLevel::Standard,
[&rpt](std::string_view record)
{
rpt += fmt::format("{}\n", record);
});
BOOST_CHECK_EQUAL(rpt, R"(Consistency Problem:
Gas Phase End-Point Monotonicity
SGL <= SGCR < SGU
Total Violations: 1
List of Violations
+----------------+---------------+---------------+---------------+
| Grid Block | SGL | SGCR | SGU |
+----------------+---------------+---------------+---------------+
| (121, 323, 42) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 |
+----------------+---------------+---------------+---------------+
Consistency Problem:
Oil Phase Non-Negative Saturation (G/O)
SWL + SGU <= 1
Total Violations: 1
List of Violations
+----------------+---------------+---------------+---------------+
| Grid Block | SWL | SGU | SWL + SGU |
+----------------+---------------+---------------+---------------+
| (121, 323, 42) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 |
+----------------+---------------+---------------+---------------+
Consistency Problem:
Water Phase End-Point Monotonicity
SWL <= SWCR < SWU
Total Violations: 1
List of Violations
+----------------+---------------+---------------+---------------+
| Grid Block | SWL | SWCR | SWU |
+----------------+---------------+---------------+---------------+
| (121, 323, 42) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 |
+----------------+---------------+---------------+---------------+
Consistency Problem:
Oil Phase Non-Negative Saturation (O/W)
SGL + SWU <= 1
Total Violations: 1
List of Violations
+----------------+---------------+---------------+---------------+
| Grid Block | SGL | SWU | SGL + SWU |
+----------------+---------------+---------------+---------------+
| (121, 323, 42) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 |
+----------------+---------------+---------------+---------------+
)");
}
BOOST_AUTO_TEST_CASE(Standard_Multiple_Failing_Points)
{
auto checker = Opm::SatfuncConsistencyChecks{"Grid Block", 5};
checker.resetCheckSet();
checker.addCheck(std::make_unique());
checker.addCheck(std::make_unique());
checker.addCheck(std::make_unique());
checker.addCheck(std::make_unique());
checker.finaliseCheckSet();
checker.checkEndpoints( 1234, makePoints());
checker.checkEndpoints( 1729, makePoints());
checker.checkEndpoints( 1618, makePoints());
checker.checkEndpoints(31415, makePoints());
BOOST_CHECK_MESSAGE(checker.anyFailedChecks(),
"There must be at least one failed check");
auto rpt = std::string{};
checker.reportFailures(Opm::SatfuncConsistencyChecks::ViolationLevel::Standard,
[&rpt](std::string_view record)
{
rpt += fmt::format("{}\n", record);
});
// Note that grid blocks are reported in sorted order rather in the
// order of insertion.
BOOST_CHECK_EQUAL(rpt, R"(Consistency Problem:
Gas Phase End-Point Monotonicity
SGL <= SGCR < SGU
Total Violations: 4
List of Violations
+------------+---------------+---------------+---------------+
| Grid Block | SGL | SGCR | SGU |
+------------+---------------+---------------+---------------+
| 1234 | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 |
| 1618 | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 |
| 1729 | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 |
| 31415 | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 |
+------------+---------------+---------------+---------------+
Consistency Problem:
Oil Phase Non-Negative Saturation (G/O)
SWL + SGU <= 1
Total Violations: 4
List of Violations
+------------+---------------+---------------+---------------+
| Grid Block | SWL | SGU | SWL + SGU |
+------------+---------------+---------------+---------------+
| 1234 | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 |
| 1618 | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 |
| 1729 | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 |
| 31415 | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 |
+------------+---------------+---------------+---------------+
Consistency Problem:
Water Phase End-Point Monotonicity
SWL <= SWCR < SWU
Total Violations: 4
List of Violations
+------------+---------------+---------------+---------------+
| Grid Block | SWL | SWCR | SWU |
+------------+---------------+---------------+---------------+
| 1234 | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 |
| 1618 | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 |
| 1729 | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 |
| 31415 | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 |
+------------+---------------+---------------+---------------+
Consistency Problem:
Oil Phase Non-Negative Saturation (O/W)
SGL + SWU <= 1
Total Violations: 4
List of Violations
+------------+---------------+---------------+---------------+
| Grid Block | SGL | SWU | SGL + SWU |
+------------+---------------+---------------+---------------+
| 1234 | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 |
| 1618 | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 |
| 1729 | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 |
| 31415 | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 |
+------------+---------------+---------------+---------------+
)");
}
BOOST_AUTO_TEST_SUITE_END() // Multiple_Failing_Tests