/* 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_Parallel #define BOOST_TEST_NO_MAIN #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 #include #include #include namespace { #if HAVE_MPI struct MPIError { MPIError(std::string_view errstr, const int ec) : errorstring { errstr } , errorcode { ec } {} std::string errorstring; int errorcode; }; void MPI_err_handler(MPI_Comm*, int* err_code, ...) { std::array err_string_vec{'\0'}; auto err_length = 0; MPI_Error_string(*err_code, err_string_vec.data(), &err_length); auto err_string = std::string_view { err_string_vec.data(), static_cast(err_length) }; std::cerr << "An MPI Error ocurred:\n -> " << err_string << '\n'; throw MPIError { err_string, *err_code }; } // Register a throwing error handler to allow for debugging with // // catch throw // // in GDB. void register_error_handler() { MPI_Errhandler handler{}; MPI_Comm_create_errhandler(MPI_err_handler, &handler); MPI_Comm_set_errhandler(MPI_COMM_WORLD, handler); } #else // !HAVE_MPI void register_error_handler() {} #endif // HAVE_MPI class NProc_Is { public: explicit NProc_Is(const int expectNP) : expectNP_ { expectNP } {} boost::test_tools::assertion_result operator()(boost::unit_test::test_unit_id) const { auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; if (comm.size() == this->expectNP_) { return true; } boost::test_tools::assertion_result response(false); response.message() << "Number of MPI processes (" << comm.size() << ") differs from expected " << this->expectNP_; return response; } private: int expectNP_{}; }; bool init_unit_test_func() { return true; } } // Anonymous namespace 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) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"Cell", 1}; checker.resetCheckSet(); checker.addCheck(std::make_unique()); checker.finaliseCheckSet(); checker.checkEndpoints(comm.rank(), makePoints()); checker.collectFailures(0, comm); BOOST_CHECK_MESSAGE(! checker.anyFailedStandardChecks(), "There must be no failed checks"); BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(), "There must be no failed critical checks"); auto rpt = std::string{}; if (comm.rank() == 0) { 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_SUITE(NProc_2, * boost::unit_test::precondition(NProc_Is{2})) BOOST_AUTO_TEST_CASE(Standard_Violation) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"Cell", 4}; checker.resetCheckSet(); checker.addCheck(std::make_unique()); checker.finaliseCheckSet(); checker.checkEndpoints(comm.rank() + 1, makePoints()); checker.collectFailures(0, comm); BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(), "There must be at least one failed check"); BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(), "There must be no failed critical checks"); if (comm.rank() == 0) { 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: 2 List of Violations +------+---------------+ | Cell | SWL | +------+---------------+ | 1 | 1.729000e+01 | | 2 | 1.729000e+01 | +------+---------------+ )"); } } BOOST_AUTO_TEST_CASE(Critical_Violation) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"PVTNUM", 4}; checker.resetCheckSet(); checker.addCheck(std::make_unique()); checker.finaliseCheckSet(); checker.checkEndpoints(42 * (comm.rank() + 1), makePoints()); checker.collectFailures(0, comm); BOOST_CHECK_MESSAGE(! checker.anyFailedStandardChecks(), "There must be no failed standard level checks"); BOOST_CHECK_MESSAGE(checker.anyFailedCriticalChecks(), "There must be at least one failed Critical check"); if (comm.rank() == 0) { 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: 2 List of Violations +--------+---------------+ | PVTNUM | PRESS | +--------+---------------+ | 42 | 3.141593e+02 | | 84 | 3.141593e+02 | +--------+---------------+ )"); } } BOOST_AUTO_TEST_SUITE_END() // NProc_2 // --------------------------------------------------------------------------- BOOST_AUTO_TEST_SUITE(NProc_3, * boost::unit_test::precondition(NProc_Is{3})) BOOST_AUTO_TEST_CASE(Standard_Violation) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"Cell", 4}; checker.resetCheckSet(); checker.addCheck(std::make_unique()); checker.finaliseCheckSet(); checker.checkEndpoints(comm.rank() + 1, makePoints()); checker.collectFailures(0, comm); BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(), "There must be at least one failed check"); BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(), "There must be no failed critical checks"); if (comm.rank() == 0) { 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: 3 List of Violations +------+---------------+ | Cell | SWL | +------+---------------+ | 1 | 1.729000e+01 | | 2 | 1.729000e+01 | | 3 | 1.729000e+01 | +------+---------------+ )"); } } BOOST_AUTO_TEST_CASE(Critical_Violation) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"PVTNUM", 4}; checker.resetCheckSet(); checker.addCheck(std::make_unique()); checker.finaliseCheckSet(); checker.checkEndpoints(42 * (comm.rank() + 1), makePoints()); checker.collectFailures(0, comm); BOOST_CHECK_MESSAGE(! checker.anyFailedStandardChecks(), "There must be no failed standard level checks"); BOOST_CHECK_MESSAGE(checker.anyFailedCriticalChecks(), "There must be at least one failed Critical check"); if (comm.rank() == 0) { 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: 3 List of Violations +--------+---------------+ | PVTNUM | PRESS | +--------+---------------+ | 42 | 3.141593e+02 | | 84 | 3.141593e+02 | | 126 | 3.141593e+02 | +--------+---------------+ )"); } } BOOST_AUTO_TEST_SUITE_END() // NProc_3 // --------------------------------------------------------------------------- BOOST_AUTO_TEST_SUITE(NProc_4, * boost::unit_test::precondition(NProc_Is{4})) BOOST_AUTO_TEST_CASE(Standard_Violation) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"Cell", 4}; checker.resetCheckSet(); checker.addCheck(std::make_unique()); checker.finaliseCheckSet(); checker.checkEndpoints(comm.rank() + 1, makePoints()); checker.collectFailures(0, comm); BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(), "There must be at least one failed check"); BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(), "There must be no failed critical checks"); if (comm.rank() == 0) { 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: 4 List of Violations +------+---------------+ | Cell | SWL | +------+---------------+ | 1 | 1.729000e+01 | | 2 | 1.729000e+01 | | 3 | 1.729000e+01 | | 4 | 1.729000e+01 | +------+---------------+ )"); } } BOOST_AUTO_TEST_CASE(Critical_Violation) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"PVTNUM", 4}; checker.resetCheckSet(); checker.addCheck(std::make_unique()); checker.finaliseCheckSet(); checker.checkEndpoints(42 * (comm.rank() + 1), makePoints()); checker.collectFailures(0, comm); BOOST_CHECK_MESSAGE(! checker.anyFailedStandardChecks(), "There must be no failed standard level checks"); BOOST_CHECK_MESSAGE(checker.anyFailedCriticalChecks(), "There must be at least one failed Critical check"); if (comm.rank() == 0) { 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: 4 List of Violations +--------+---------------+ | PVTNUM | PRESS | +--------+---------------+ | 42 | 3.141593e+02 | | 84 | 3.141593e+02 | | 126 | 3.141593e+02 | | 168 | 3.141593e+02 | +--------+---------------+ )"); } } BOOST_AUTO_TEST_SUITE_END() // NProc_4 // --------------------------------------------------------------------------- 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_SUITE(NProc_2, * boost::unit_test::precondition(NProc_Is{2})) BOOST_AUTO_TEST_CASE(Standard) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"Bucket", 4}; checker.resetCheckSet(); checker.addCheck(std::make_unique()); checker.finaliseCheckSet(); checker.checkEndpoints(comm.rank() + 1, makePoints()); checker.collectFailures(0, comm); BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(), "There must be at least one failed check"); BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(), "There must be no failed critical checks"); if (comm.rank() == 0) { 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: 2 List of Violations +--------+---------------+---------------+ | Bucket | a | a + 1/2 | +--------+---------------+---------------+ | 1 | 1.600000e+00 | 2.100000e+00 | | 2 | 1.600000e+00 | 2.100000e+00 | +--------+---------------+---------------+ )"); } } BOOST_AUTO_TEST_SUITE_END() // NProc_2 // --------------------------------------------------------------------------- BOOST_AUTO_TEST_SUITE(NProc_3, * boost::unit_test::precondition(NProc_Is{3})) BOOST_AUTO_TEST_CASE(Standard) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"Bucket", 4}; checker.resetCheckSet(); checker.addCheck(std::make_unique()); checker.finaliseCheckSet(); checker.checkEndpoints(comm.rank() + 1, makePoints()); checker.collectFailures(0, comm); BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(), "There must be at least one failed check"); BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(), "There must be no failed critical checks"); if (comm.rank() == 0) { 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: 3 List of Violations +--------+---------------+---------------+ | Bucket | a | a + 1/2 | +--------+---------------+---------------+ | 1 | 1.600000e+00 | 2.100000e+00 | | 2 | 1.600000e+00 | 2.100000e+00 | | 3 | 1.600000e+00 | 2.100000e+00 | +--------+---------------+---------------+ )"); } } BOOST_AUTO_TEST_SUITE_END() // NProc_3 // --------------------------------------------------------------------------- BOOST_AUTO_TEST_SUITE(NProc_4, * boost::unit_test::precondition(NProc_Is{4})) BOOST_AUTO_TEST_CASE(Standard) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"Bucket", 4}; checker.resetCheckSet(); checker.addCheck(std::make_unique()); checker.finaliseCheckSet(); checker.checkEndpoints(comm.rank() + 1, makePoints()); checker.collectFailures(0, comm); BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(), "There must be at least one failed check"); BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(), "There must be no failed critical checks"); if (comm.rank() == 0) { 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: 4 List of Violations +--------+---------------+---------------+ | Bucket | a | a + 1/2 | +--------+---------------+---------------+ | 1 | 1.600000e+00 | 2.100000e+00 | | 2 | 1.600000e+00 | 2.100000e+00 | | 3 | 1.600000e+00 | 2.100000e+00 | | 4 | 1.600000e+00 | 2.100000e+00 | +--------+---------------+---------------+ )"); } } BOOST_AUTO_TEST_SUITE_END() // NProc_3 // --------------------------------------------------------------------------- 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_SUITE(NProc_2, * boost::unit_test::precondition(NProc_Is{2})) BOOST_AUTO_TEST_CASE(Standard) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"Grid Block", 4}; checker.resetCheckSet(); checker.addCheck(std::make_unique()); checker.finaliseCheckSet(); checker.checkEndpoints(comm.rank() + 1, makePoints()); checker.collectFailures(0, comm); BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(), "There must be at least one failed check"); BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(), "There must be no failed critical checks"); if (comm.rank() == 0) { 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: 2 List of Violations +------------+---------------+---------------+---------------+---------------+---------------+ | Grid Block | SGL | SOWCR | SWCR | 1-SOWCR-SGL | SWU | +------------+---------------+---------------+---------------+---------------+---------------+ | 1 | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | 2 | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | +------------+---------------+---------------+---------------+---------------+---------------+ )"); } } BOOST_AUTO_TEST_CASE(Standard_Multiple_Failing_Points) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"Grid Block", 16}; checker.resetCheckSet(); checker.addCheck(std::make_unique()); checker.finaliseCheckSet(); const auto rankMultiplier = 100'000; checker.setPointIDFormatCallback([](const std::size_t pointID) { const auto rank = pointID / rankMultiplier; const auto pt = pointID % rankMultiplier; return fmt::format("({}, {})", rank, pt); }); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1234, makePoints()); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1729, makePoints()); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1618, makePoints()); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 31415, makePoints()); BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(), "There must be at least one failed check"); BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(), "There must be no failed critical checks"); checker.collectFailures(0, comm); if (comm.rank() == 0) { 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: 8 List of Violations +------------+---------------+---------------+---------------+---------------+---------------+ | Grid Block | SGL | SOWCR | SWCR | 1-SOWCR-SGL | SWU | +------------+---------------+---------------+---------------+---------------+---------------+ | (1, 1234) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (1, 1618) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (1, 1729) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (1, 31415) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (2, 1234) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (2, 1618) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (2, 1729) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (2, 31415) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | +------------+---------------+---------------+---------------+---------------+---------------+ )"); } } BOOST_AUTO_TEST_SUITE_END() // NProc_2 // --------------------------------------------------------------------------- BOOST_AUTO_TEST_SUITE(NProc_3, * boost::unit_test::precondition(NProc_Is{3})) BOOST_AUTO_TEST_CASE(Standard) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"Grid Block", 4}; checker.resetCheckSet(); checker.addCheck(std::make_unique()); checker.finaliseCheckSet(); checker.checkEndpoints(comm.rank() + 1, makePoints()); checker.collectFailures(0, comm); BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(), "There must be at least one failed check"); BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(), "There must be no failed critical checks"); if (comm.rank() == 0) { 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: 3 List of Violations +------------+---------------+---------------+---------------+---------------+---------------+ | Grid Block | SGL | SOWCR | SWCR | 1-SOWCR-SGL | SWU | +------------+---------------+---------------+---------------+---------------+---------------+ | 1 | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | 2 | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | 3 | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | +------------+---------------+---------------+---------------+---------------+---------------+ )"); } } BOOST_AUTO_TEST_CASE(Standard_Multiple_Failing_Points) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"Grid Block", 16}; checker.resetCheckSet(); checker.addCheck(std::make_unique()); checker.finaliseCheckSet(); const auto rankMultiplier = 100'000; checker.setPointIDFormatCallback([](const std::size_t pointID) { const auto rank = pointID / rankMultiplier; const auto pt = pointID % rankMultiplier; return fmt::format("({}, {})", rank, pt); }); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1234, makePoints()); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1729, makePoints()); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1618, makePoints()); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 31415, makePoints()); BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(), "There must be at least one failed check"); BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(), "There must be no failed critical checks"); checker.collectFailures(0, comm); if (comm.rank() == 0) { 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: 12 List of Violations +------------+---------------+---------------+---------------+---------------+---------------+ | Grid Block | SGL | SOWCR | SWCR | 1-SOWCR-SGL | SWU | +------------+---------------+---------------+---------------+---------------+---------------+ | (1, 1234) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (1, 1618) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (1, 1729) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (1, 31415) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (2, 1234) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (2, 1618) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (2, 1729) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (2, 31415) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (3, 1234) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (3, 1618) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (3, 1729) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (3, 31415) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | +------------+---------------+---------------+---------------+---------------+---------------+ )"); } } BOOST_AUTO_TEST_SUITE_END() // NProc_3 // --------------------------------------------------------------------------- BOOST_AUTO_TEST_SUITE(NProc_4, * boost::unit_test::precondition(NProc_Is{4})) BOOST_AUTO_TEST_CASE(Standard) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"Grid Block", 4}; checker.resetCheckSet(); checker.addCheck(std::make_unique()); checker.finaliseCheckSet(); checker.checkEndpoints(comm.rank() + 1, makePoints()); checker.collectFailures(0, comm); BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(), "There must be at least one failed check"); BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(), "There must be no failed critical checks"); if (comm.rank() == 0) { 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: 4 List of Violations +------------+---------------+---------------+---------------+---------------+---------------+ | Grid Block | SGL | SOWCR | SWCR | 1-SOWCR-SGL | SWU | +------------+---------------+---------------+---------------+---------------+---------------+ | 1 | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | 2 | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | 3 | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | 4 | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | +------------+---------------+---------------+---------------+---------------+---------------+ )"); } } BOOST_AUTO_TEST_CASE(Standard_Multiple_Failing_Points) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"Grid Block", 16}; checker.resetCheckSet(); checker.addCheck(std::make_unique()); checker.finaliseCheckSet(); const auto rankMultiplier = 100'000; checker.setPointIDFormatCallback([](const std::size_t pointID) { const auto rank = pointID / rankMultiplier; const auto pt = pointID % rankMultiplier; return fmt::format("({}, {})", rank, pt); }); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1234, makePoints()); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1729, makePoints()); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1618, makePoints()); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 31415, makePoints()); BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(), "There must be at least one failed check"); BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(), "There must be no failed critical checks"); checker.collectFailures(0, comm); if (comm.rank() == 0) { 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: 16 List of Violations +------------+---------------+---------------+---------------+---------------+---------------+ | Grid Block | SGL | SOWCR | SWCR | 1-SOWCR-SGL | SWU | +------------+---------------+---------------+---------------+---------------+---------------+ | (1, 1234) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (1, 1618) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (1, 1729) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (1, 31415) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (2, 1234) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (2, 1618) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (2, 1729) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (2, 31415) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (3, 1234) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (3, 1618) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (3, 1729) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (3, 31415) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (4, 1234) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (4, 1618) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (4, 1729) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | | (4, 31415) | 1.000000e-01 | 7.000000e-01 | 3.000000e-01 | 2.000000e-01 | 8.800000e-01 | +------------+---------------+---------------+---------------+---------------+---------------+ )"); } } BOOST_AUTO_TEST_SUITE_END() // NProc_3 // --------------------------------------------------------------------------- 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_SUITE(NProc_2, * boost::unit_test::precondition(NProc_Is{2})) BOOST_AUTO_TEST_CASE(Standard) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"Grid Block", 4}; 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(comm.rank() + 1, makePoints()); checker.collectFailures(0, comm); BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(), "There must be at least one failed check"); BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(), "There must be no failed critical checks"); if (comm.rank() == 0) { 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: 2 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SGL | SGCR | SGU | +------------+---------------+---------------+---------------+ | 1 | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | 2 | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | +------------+---------------+---------------+---------------+ Consistency Problem: Oil Phase Non-Negative Saturation (G/O) SWL + SGU <= 1 Total Violations: 2 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SWL | SGU | SWL + SGU | +------------+---------------+---------------+---------------+ | 1 | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | 2 | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | +------------+---------------+---------------+---------------+ Consistency Problem: Water Phase End-Point Monotonicity SWL <= SWCR < SWU Total Violations: 2 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SWL | SWCR | SWU | +------------+---------------+---------------+---------------+ | 1 | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | 2 | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | +------------+---------------+---------------+---------------+ Consistency Problem: Oil Phase Non-Negative Saturation (O/W) SGL + SWU <= 1 Total Violations: 2 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SGL | SWU | SGL + SWU | +------------+---------------+---------------+---------------+ | 1 | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | 2 | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | +------------+---------------+---------------+---------------+ )"); } } BOOST_AUTO_TEST_CASE(Standard_Multiple_Failing_Points) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"Grid Block", 16}; checker.resetCheckSet(); checker.addCheck(std::make_unique()); checker.addCheck(std::make_unique()); checker.addCheck(std::make_unique()); checker.addCheck(std::make_unique()); checker.finaliseCheckSet(); const auto rankMultiplier = 100'000; checker.setPointIDFormatCallback([](const std::size_t pointID) { const auto rank = pointID / rankMultiplier; const auto pt = pointID % rankMultiplier; return fmt::format("({}, {})", rank, pt); }); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1234, makePoints()); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1729, makePoints()); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1618, makePoints()); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 31415, makePoints()); checker.collectFailures(0, comm); BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(), "There must be at least one failed check"); BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(), "There must be no failed critical checks"); if (comm.rank() == 0) { 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: 8 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SGL | SGCR | SGU | +------------+---------------+---------------+---------------+ | (1, 1234) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (1, 1618) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (1, 1729) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (1, 31415) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (2, 1234) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (2, 1618) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (2, 1729) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (2, 31415) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | +------------+---------------+---------------+---------------+ Consistency Problem: Oil Phase Non-Negative Saturation (G/O) SWL + SGU <= 1 Total Violations: 8 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SWL | SGU | SWL + SGU | +------------+---------------+---------------+---------------+ | (1, 1234) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (1, 1618) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (1, 1729) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (1, 31415) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (2, 1234) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (2, 1618) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (2, 1729) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (2, 31415) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | +------------+---------------+---------------+---------------+ Consistency Problem: Water Phase End-Point Monotonicity SWL <= SWCR < SWU Total Violations: 8 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SWL | SWCR | SWU | +------------+---------------+---------------+---------------+ | (1, 1234) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (1, 1618) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (1, 1729) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (1, 31415) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (2, 1234) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (2, 1618) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (2, 1729) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (2, 31415) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | +------------+---------------+---------------+---------------+ Consistency Problem: Oil Phase Non-Negative Saturation (O/W) SGL + SWU <= 1 Total Violations: 8 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SGL | SWU | SGL + SWU | +------------+---------------+---------------+---------------+ | (1, 1234) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (1, 1618) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (1, 1729) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (1, 31415) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (2, 1234) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (2, 1618) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (2, 1729) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (2, 31415) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | +------------+---------------+---------------+---------------+ )"); } } BOOST_AUTO_TEST_SUITE_END() // NProc_2 // --------------------------------------------------------------------------- BOOST_AUTO_TEST_SUITE(NProc_3, * boost::unit_test::precondition(NProc_Is{3})) BOOST_AUTO_TEST_CASE(Standard) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"Grid Block", 4}; 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(comm.rank() + 1, makePoints()); checker.collectFailures(0, comm); BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(), "There must be at least one failed check"); BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(), "There must be no failed critical checks"); if (comm.rank() == 0) { 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: 3 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SGL | SGCR | SGU | +------------+---------------+---------------+---------------+ | 1 | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | 2 | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | 3 | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | +------------+---------------+---------------+---------------+ Consistency Problem: Oil Phase Non-Negative Saturation (G/O) SWL + SGU <= 1 Total Violations: 3 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SWL | SGU | SWL + SGU | +------------+---------------+---------------+---------------+ | 1 | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | 2 | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | 3 | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | +------------+---------------+---------------+---------------+ Consistency Problem: Water Phase End-Point Monotonicity SWL <= SWCR < SWU Total Violations: 3 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SWL | SWCR | SWU | +------------+---------------+---------------+---------------+ | 1 | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | 2 | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | 3 | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | +------------+---------------+---------------+---------------+ Consistency Problem: Oil Phase Non-Negative Saturation (O/W) SGL + SWU <= 1 Total Violations: 3 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SGL | SWU | SGL + SWU | +------------+---------------+---------------+---------------+ | 1 | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | 2 | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | 3 | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | +------------+---------------+---------------+---------------+ )"); } } BOOST_AUTO_TEST_CASE(Standard_Multiple_Failing_Points) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"Grid Block", 16}; checker.resetCheckSet(); checker.addCheck(std::make_unique()); checker.addCheck(std::make_unique()); checker.addCheck(std::make_unique()); checker.addCheck(std::make_unique()); checker.finaliseCheckSet(); const auto rankMultiplier = 100'000; checker.setPointIDFormatCallback([](const std::size_t pointID) { const auto rank = pointID / rankMultiplier; const auto pt = pointID % rankMultiplier; return fmt::format("({}, {})", rank, pt); }); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1234, makePoints()); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1729, makePoints()); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1618, makePoints()); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 31415, makePoints()); checker.collectFailures(0, comm); BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(), "There must be at least one failed check"); BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(), "There must be no failed critical checks"); if (comm.rank() == 0) { 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: 12 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SGL | SGCR | SGU | +------------+---------------+---------------+---------------+ | (1, 1234) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (1, 1618) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (1, 1729) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (1, 31415) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (2, 1234) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (2, 1618) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (2, 1729) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (2, 31415) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (3, 1234) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (3, 1618) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (3, 1729) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (3, 31415) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | +------------+---------------+---------------+---------------+ Consistency Problem: Oil Phase Non-Negative Saturation (G/O) SWL + SGU <= 1 Total Violations: 12 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SWL | SGU | SWL + SGU | +------------+---------------+---------------+---------------+ | (1, 1234) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (1, 1618) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (1, 1729) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (1, 31415) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (2, 1234) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (2, 1618) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (2, 1729) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (2, 31415) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (3, 1234) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (3, 1618) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (3, 1729) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (3, 31415) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | +------------+---------------+---------------+---------------+ Consistency Problem: Water Phase End-Point Monotonicity SWL <= SWCR < SWU Total Violations: 12 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SWL | SWCR | SWU | +------------+---------------+---------------+---------------+ | (1, 1234) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (1, 1618) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (1, 1729) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (1, 31415) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (2, 1234) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (2, 1618) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (2, 1729) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (2, 31415) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (3, 1234) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (3, 1618) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (3, 1729) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (3, 31415) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | +------------+---------------+---------------+---------------+ Consistency Problem: Oil Phase Non-Negative Saturation (O/W) SGL + SWU <= 1 Total Violations: 12 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SGL | SWU | SGL + SWU | +------------+---------------+---------------+---------------+ | (1, 1234) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (1, 1618) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (1, 1729) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (1, 31415) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (2, 1234) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (2, 1618) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (2, 1729) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (2, 31415) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (3, 1234) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (3, 1618) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (3, 1729) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (3, 31415) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | +------------+---------------+---------------+---------------+ )"); } } BOOST_AUTO_TEST_SUITE_END() // NProc_3 // --------------------------------------------------------------------------- BOOST_AUTO_TEST_SUITE(NProc_4, * boost::unit_test::precondition(NProc_Is{4})) BOOST_AUTO_TEST_CASE(Standard) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"Grid Block", 4}; 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(comm.rank() + 1, makePoints()); checker.collectFailures(0, comm); BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(), "There must be at least one failed check"); BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(), "There must be no failed critical checks"); if (comm.rank() == 0) { 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: 4 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SGL | SGCR | SGU | +------------+---------------+---------------+---------------+ | 1 | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | 2 | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | 3 | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | 4 | 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 | +------------+---------------+---------------+---------------+ | 1 | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | 2 | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | 3 | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | 4 | 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 | +------------+---------------+---------------+---------------+ | 1 | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | 2 | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | 3 | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | 4 | 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 | +------------+---------------+---------------+---------------+ | 1 | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | 2 | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | 3 | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | 4 | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | +------------+---------------+---------------+---------------+ )"); } } BOOST_AUTO_TEST_CASE(Standard_Multiple_Failing_Points) { const auto comm = Opm::Parallel::Communication { Dune::MPIHelper::getCommunicator() }; auto checker = Opm::SatfuncConsistencyChecks{"Grid Block", 16}; checker.resetCheckSet(); checker.addCheck(std::make_unique()); checker.addCheck(std::make_unique()); checker.addCheck(std::make_unique()); checker.addCheck(std::make_unique()); checker.finaliseCheckSet(); const auto rankMultiplier = 100'000; checker.setPointIDFormatCallback([](const std::size_t pointID) { const auto rank = pointID / rankMultiplier; const auto pt = pointID % rankMultiplier; return fmt::format("({}, {})", rank, pt); }); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1234, makePoints()); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1729, makePoints()); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 1618, makePoints()); checker.checkEndpoints(rankMultiplier*(comm.rank() + 1) + 31415, makePoints()); checker.collectFailures(0, comm); BOOST_CHECK_MESSAGE(checker.anyFailedStandardChecks(), "There must be at least one failed check"); BOOST_CHECK_MESSAGE(! checker.anyFailedCriticalChecks(), "There must be no failed critical checks"); if (comm.rank() == 0) { 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: 16 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SGL | SGCR | SGU | +------------+---------------+---------------+---------------+ | (1, 1234) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (1, 1618) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (1, 1729) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (1, 31415) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (2, 1234) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (2, 1618) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (2, 1729) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (2, 31415) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (3, 1234) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (3, 1618) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (3, 1729) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (3, 31415) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (4, 1234) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (4, 1618) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (4, 1729) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | | (4, 31415) | 0.000000e+00 | -1.000000e-01 | 8.000000e-01 | +------------+---------------+---------------+---------------+ Consistency Problem: Oil Phase Non-Negative Saturation (G/O) SWL + SGU <= 1 Total Violations: 16 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SWL | SGU | SWL + SGU | +------------+---------------+---------------+---------------+ | (1, 1234) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (1, 1618) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (1, 1729) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (1, 31415) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (2, 1234) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (2, 1618) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (2, 1729) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (2, 31415) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (3, 1234) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (3, 1618) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (3, 1729) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (3, 31415) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (4, 1234) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (4, 1618) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (4, 1729) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | | (4, 31415) | 2.500000e-01 | 8.000000e-01 | 1.050000e+00 | +------------+---------------+---------------+---------------+ Consistency Problem: Water Phase End-Point Monotonicity SWL <= SWCR < SWU Total Violations: 16 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SWL | SWCR | SWU | +------------+---------------+---------------+---------------+ | (1, 1234) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (1, 1618) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (1, 1729) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (1, 31415) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (2, 1234) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (2, 1618) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (2, 1729) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (2, 31415) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (3, 1234) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (3, 1618) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (3, 1729) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (3, 31415) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (4, 1234) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (4, 1618) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (4, 1729) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | | (4, 31415) | 1.000000e-01 | 3.000000e-01 | 3.000000e-01 | +------------+---------------+---------------+---------------+ Consistency Problem: Oil Phase Non-Negative Saturation (O/W) SGL + SWU <= 1 Total Violations: 16 List of Violations +------------+---------------+---------------+---------------+ | Grid Block | SGL | SWU | SGL + SWU | +------------+---------------+---------------+---------------+ | (1, 1234) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (1, 1618) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (1, 1729) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (1, 31415) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (2, 1234) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (2, 1618) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (2, 1729) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (2, 31415) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (3, 1234) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (3, 1618) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (3, 1729) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (3, 31415) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (4, 1234) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (4, 1618) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (4, 1729) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | | (4, 31415) | 1.000000e-01 | 1.000000e+00 | 1.100000e+00 | +------------+---------------+---------------+---------------+ )"); } } BOOST_AUTO_TEST_SUITE_END() // NProc_4 // --------------------------------------------------------------------------- BOOST_AUTO_TEST_SUITE_END() // Multiple_Failing_Tests // =========================================================================== int main(int argc, char** argv) { Dune::MPIHelper::instance(argc, argv); register_error_handler(); return boost::unit_test::unit_test_main(&init_unit_test_func, argc, argv); }