From 0c71d0701ccd17aa131d6892080acf89f80405ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Tue, 25 Jun 2024 18:57:09 +0200 Subject: [PATCH 1/2] Add MPI Support to Saturation Function Consistency Checks This commit adds a new public member function SatfuncConsistencyChecks<>::collectFailures(root, comm) which aggregates consistency check violations from all ranks in the MPI communication object 'comm' onto rank 'root' of 'comm'. This amounts to summing the total number of violations from all ranks and potentially resampling the failure points for reporting purposes. To this end, extract the body of function processViolation() into a general helper which performs reservoir sampling and records point IDs and which uses a call-back function to populate the check values associated to a single failed check. Re-implement the original function in terms of this helper by wrapping exportCheckValues() in a lambda function. Extract similar helpers for numPoints() and anyFailedChecks(), and add a new helper function SatfuncConsistencyChecks<>::incorporateRankViolations() which brings sampled points from an MPI rank into the 'root's internal data structures. One caveat applies here. Our current approach to collecting check failures implies that calling member function reportFailures() is safe only on the 'root' process in a parallel run. On the other hand functions anyFailedChecks() and anyFailedCriticalChecks() are safe, and guaranteed to return the same answer, on all MPI ranks. On a final note, the internal helper functions are at present mostly implemented in terms of non-owning pointers. I intend to switch to using 'std::span<>' once we enable C++20 mode. --- CMakeLists.txt | 39 + CMakeLists_files.cmake | 1 + .../satfunc/SatfuncConsistencyChecks.cpp | 179 +- .../satfunc/SatfuncConsistencyChecks.hpp | 116 + tests/test_SatfuncConsistencyChecks.cpp | 3 + ...test_SatfuncConsistencyChecks_parallel.cpp | 2127 +++++++++++++++++ 6 files changed, 2449 insertions(+), 16 deletions(-) create mode 100644 tests/test_SatfuncConsistencyChecks_parallel.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b8c0ed51..7950f5084 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -542,6 +542,45 @@ opm_add_test(test_parallel_region_phase_pvaverage_np4 4 ) +opm_add_test(test_parallel_satfunc_consistency_checks_np2 + EXE_NAME + test_SatfuncConsistencyChecks_parallel + CONDITION + MPI_FOUND AND Boost_UNIT_TEST_FRAMEWORK_FOUND + DRIVER_ARGS + -n 2 + -b ${PROJECT_BINARY_DIR} + NO_COMPILE + PROCESSORS + 2 +) + +opm_add_test(test_parallel_satfunc_consistency_checks_np3 + EXE_NAME + test_SatfuncConsistencyChecks_parallel + CONDITION + MPI_FOUND AND Boost_UNIT_TEST_FRAMEWORK_FOUND + DRIVER_ARGS + -n 3 + -b ${PROJECT_BINARY_DIR} + NO_COMPILE + PROCESSORS + 3 +) + +opm_add_test(test_parallel_satfunc_consistency_checks_np4 + EXE_NAME + test_SatfuncConsistencyChecks_parallel + CONDITION + MPI_FOUND AND Boost_UNIT_TEST_FRAMEWORK_FOUND + DRIVER_ARGS + -n 4 + -b ${PROJECT_BINARY_DIR} + NO_COMPILE + PROCESSORS + 4 +) + opm_add_test(test_broadcast DEPENDS "opmsimulators" LIBRARIES opmsimulators ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index ef349a98d..d50c32860 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -340,6 +340,7 @@ if (HAVE_ECL_INPUT) list(APPEND TEST_SOURCE_FILES tests/test_nonnc.cpp tests/test_SatfuncConsistencyChecks.cpp + tests/test_SatfuncConsistencyChecks_parallel.cpp ) endif() diff --git a/opm/simulators/utils/satfunc/SatfuncConsistencyChecks.cpp b/opm/simulators/utils/satfunc/SatfuncConsistencyChecks.cpp index 08c9d180d..86b19ea37 100644 --- a/opm/simulators/utils/satfunc/SatfuncConsistencyChecks.cpp +++ b/opm/simulators/utils/satfunc/SatfuncConsistencyChecks.cpp @@ -21,6 +21,10 @@ #include +#include + +#include + #include #include @@ -141,6 +145,22 @@ checkEndpoints(const std::size_t pointID, }); } +template +void Opm::SatfuncConsistencyChecks:: +collectFailures(const int root, + const Parallel::Communication& comm) +{ + if (comm.size() == 1) { + // Not a parallel run. Violation structure complete without + // exchanging additional information, so nothing to do. + return; + } + + for (auto& violation : this->violations_) { + this->collectFailures(root, comm, violation); + } +} + template bool Opm::SatfuncConsistencyChecks::anyFailedChecks() const { @@ -194,9 +214,77 @@ void Opm::SatfuncConsistencyChecks::ViolationSample::clear() // --------------------------------------------------------------------------- +namespace { + bool anyFailedChecks(const std::vector& count) + { + return std::any_of(count.begin(), count.end(), + [](const std::size_t n) { return n > 0; }); + } +} + template -void -Opm::SatfuncConsistencyChecks:: +void Opm::SatfuncConsistencyChecks:: +collectFailures(const int root, + const Parallel::Communication& comm, + ViolationSample& violation) +{ + // Count total number of violations of each check across all ranks. + // This should be the final number emitted in reportFailures() on the + // root process. + auto totalCount = violation.count; + comm.sum(totalCount.data(), violation.count.size()); + + if (! ::anyFailedChecks(totalCount)) { + // No failed checks on any rank for this severity level. + // + // No additional work needed, since every rank will have zero + // failure counts for all checks. + return; + } + + // CSR-like structures for the failure counts, sampled point IDs, and + // sampled check values from all ranks. One set of all-to-one messages + // for each quantity. If this stage becomes a bottleneck we must devise + // a better communication structure that reduces the number of messages. + const auto& [rankCount, startRankCount] = + gatherv(violation.count, comm, root); + + const auto& [rankPointID, startRankPointID] = + gatherv(violation.pointID, comm, root); + + const auto& [rankCheckValues, startRankCheckValues] = + gatherv(violation.checkValues, comm, root); + + if (comm.rank() == root) { + // Re-initialise this violation sample to prepare for incorporating + // contributions from all MPI ranks--including the current rank. + violation.clear(); + this->buildStructure(violation); + + const auto numRanks = comm.size(); + for (auto rank = 0*numRanks; rank < numRanks; ++rank) { + this->incorporateRankViolations + (rankCount.data() + startRankCount[rank], + rankPointID.data() + startRankPointID[rank], + rankCheckValues.data() + startRankCheckValues[rank], + violation); + } + } + + // The final violation counts for reporting purposes should be the sum + // of the per-rank counts. This ensures that all ranks give the same + // answer to the anyFailedChecks() predicate, although the particular + // sample points will differ across the ranks. + violation.count.swap(totalCount); + + // Ensure that all ranks are synchronised here before proceeding. We + // don't want to end up in a situation where the ranks have a different + // notion of what to send/receive. + comm.barrier(); +} + +template +void Opm::SatfuncConsistencyChecks:: buildStructure(ViolationSample& violation) { violation.count.assign(this->battery_.size(), 0); @@ -212,13 +300,13 @@ buildStructure(ViolationSample& violation) } template +template void Opm::SatfuncConsistencyChecks:: -processViolation(const ViolationLevel level, - const std::size_t checkIx, - const std::size_t pointID) +processViolation(ViolationSample& violation, + const std::size_t checkIx, + const std::size_t pointID, + PopulateCheckValues&& populateCheckValues) { - auto& violation = this->violations_[this->index(level)]; - const auto nViol = ++violation.count[checkIx]; // Special case handling for number of violations not exceeding number @@ -240,12 +328,59 @@ processViolation(const ViolationLevel level, // reported violations. Record the pointID and the corresponding check // values in their appropriate locations. - violation.pointID[checkIx*this->numSamplePoints_ + sampleIx] = pointID; + violation.pointID[this->violationPointIDStart(checkIx) + sampleIx] = pointID; - auto* exportedCheckValues = violation.checkValues.data() + auto* const checkValues = violation.checkValues.data() + this->violationValueStart(checkIx, sampleIx); - this->battery_[checkIx]->exportCheckValues(exportedCheckValues); + populateCheckValues(checkValues); +} + +template +void Opm::SatfuncConsistencyChecks:: +processViolation(const ViolationLevel level, + const std::size_t checkIx, + const std::size_t pointID) +{ + this->processViolation(this->violations_[this->index(level)], checkIx, pointID, + [this, checkIx](Scalar* const exportedCheckValues) + { + this->battery_[checkIx]->exportCheckValues(exportedCheckValues); + }); +} + +template +void Opm::SatfuncConsistencyChecks:: +incorporateRankViolations(const std::size_t* const count, + const std::size_t* const pointID, + const Scalar* const checkValues, + ViolationSample& violation) +{ + this->checkLoop([this, count, pointID, checkValues, &violation] + (const Check* currentCheck, + const std::size_t checkIx) + { + if (count[checkIx] == 0) { + // No violations of this check on this rank. Nothing to do. + return; + } + + const auto* const srcPointID = pointID + + this->violationPointIDStart(checkIx); + + const auto numCheckValues = currentCheck->numExportedCheckValues(); + const auto numSrcSamples = this->numPoints(count[checkIx]); + + for (auto srcSampleIx = 0*numSrcSamples; srcSampleIx < numSrcSamples; ++srcSampleIx) { + this->processViolation(violation, checkIx, srcPointID[srcSampleIx], + [numCheckValues, + srcCheckValues = checkValues + this->violationValueStart(checkIx, srcSampleIx)] + (Scalar* const destCheckValues) + { + std::copy_n(srcCheckValues, numCheckValues, destCheckValues); + }); + } + }); } namespace { @@ -471,8 +606,15 @@ Opm::SatfuncConsistencyChecks:: numPoints(const ViolationSample& violation, const std::size_t checkIx) const { - return std::min(this->numSamplePoints_, - violation.count[checkIx]); + return this->numPoints(violation.count[checkIx]); +} + +template +std::size_t +Opm::SatfuncConsistencyChecks:: +numPoints(const std::size_t violationCount) const +{ + return std::min(this->numSamplePoints_, violationCount); } template @@ -507,6 +649,14 @@ void Opm::SatfuncConsistencyChecks::ensureRandomBitGeneratorIsInitialise this->urbg_ = std::make_unique(seeds); } +template +std::vector::size_type +Opm::SatfuncConsistencyChecks:: +violationPointIDStart(const std::size_t checkIx) const +{ + return checkIx * this->numSamplePoints_; +} + template typename std::vector::size_type Opm::SatfuncConsistencyChecks:: @@ -522,10 +672,7 @@ bool Opm::SatfuncConsistencyChecks:: anyFailedChecks(const ViolationLevel level) const { - const auto& violation = this->violations_[this->index(level)]; - - return std::any_of(violation.count.begin(), violation.count.end(), - [](const std::size_t n) { return n > 0; }); + return ::anyFailedChecks(this->violations_[this->index(level)].count); } template diff --git a/opm/simulators/utils/satfunc/SatfuncConsistencyChecks.hpp b/opm/simulators/utils/satfunc/SatfuncConsistencyChecks.hpp index f009978a8..11303b292 100644 --- a/opm/simulators/utils/satfunc/SatfuncConsistencyChecks.hpp +++ b/opm/simulators/utils/satfunc/SatfuncConsistencyChecks.hpp @@ -20,6 +20,8 @@ #ifndef OPM_SATFUNC_CONSISTENCY_CHECK_MODULE_HPP #define OPM_SATFUNC_CONSISTENCY_CHECK_MODULE_HPP +#include + #include #include #include @@ -198,6 +200,19 @@ namespace Opm { void checkEndpoints(const std::size_t pointID, const EclEpsScalingPointsInfo& endPoints); + /// Collect consistency violations from all ranks in MPI communicator. + /// + /// Incorporates violation counts and sampled failure points into + /// the internal structures on each rank. Aggregate results useful + /// for subsequent call to reportFailures() on root process. + /// + /// \param[in] root MPI root process. This is the process onto + /// which the counts and samples will be collected. Typically + /// the index of the IO rank. + /// + /// \param[in] comm MPI communication object. + void collectFailures(int root, const Parallel::Communication& comm); + /// Whether or not any checks failed at the \c Standard level. bool anyFailedChecks() const; @@ -210,6 +225,10 @@ namespace Opm { /// Reports only those conditions/checks for which there is at least /// one violation. /// + /// In a parallel run it is only safe to call this function on the + /// MPI process to which the consistency check violations were + /// collected in a previous call to collectFailures(). + /// /// \param[in] level Report's severity level. /// /// \param[in] emitReportRecord Call-back function for outputting a @@ -299,6 +318,26 @@ namespace Opm { /// is a common case in production runs. std::unique_ptr urbg_{}; + /// Collect violations of single severity level from all ranks in + /// MPI communicator. + /// + /// Incorporates violation counts and sampled failure points into + /// the internal structures on each rank. Aggregate results useful + /// for subsequent call to reportFailures(). + /// + /// \param[in] root MPI root process. This is the process/rank onto + /// which the counts and samples will be collected. Typically + /// the index of the IO rank. + /// + /// \param[in] comm MPI communication object. + /// + /// \param[in, out] violation Current rank's violation structure for + /// a single severity level. Holds aggregate values across all + /// ranks, including updated sample points, on return. + void collectFailures(int root, + const Parallel::Communication& comm, + ViolationSample& violation); + /// Allocate and initialise backing storage for a single set of /// sampled consistency check violations. /// @@ -306,6 +345,44 @@ namespace Opm { /// violation sample of proper size. void buildStructure(ViolationSample& violation); + /// Internalise a single violation into internal data structures. + /// + /// Counts the violation and uses "reservoir sampling" + /// (https://en.wikipedia.org/wiki/Reservoir_sampling) to determine + /// whether or not to include the specific point into the reporting + /// sample. + /// + /// \tparam PopulateCheckValues Call-back function type + /// encapsulating block of code populate sequence of check values + /// for a single, failed consistency check. Expected to be a + /// callable type with a function call operator of the form + /// \code + /// void operator()(Scalar* checkValues) const + /// \endcode + /// in which the \c checkValues points the start of a sequence of + /// values associated to particular check. The call-back function + /// is expected to know how many values are in a valid sequence and + /// to fill in exactly this many values. + /// + /// \param[in, out] violation Current rank's violation sample at + /// particular severity level. + /// + /// \param[in] checkIx Numerical check index in the range + /// [0..battery_.size()). + /// + /// \param[in] pointID Numeric identifier for this particular set of + /// end-points. Typically a saturation region or a cell ID. + /// + /// \param[in] populateCheckValues Call-back function to populate a + /// sequence of values pertaining to specified check. Typically + /// \code Check::exportCheckValues() \endcode or a copy routine + /// to incorporate samples from multiple MPI ranks. + template + void processViolation(ViolationSample& violation, + const std::size_t checkIx, + const std::size_t pointID, + PopulateCheckValues&& populateCheckValues); + /// Internalise a single violation into internal data structures. /// /// Counts the violation and uses "reservoir sampling" @@ -324,6 +401,24 @@ namespace Opm { const std::size_t checkIx, const std::size_t pointID); + /// Incorporate single severity level's set of violations from + /// single MPI rank into current rank's internal data structures. + /// + /// \param[in] count Start of sequence of failure counts for all + /// checks from single MPI rank. + /// + /// \param[in] pointID Start of sequence of sampled point IDs for + /// all checks from a single MPI rank. + /// + /// \param[in] checkValues Start of sequence of sampled check values + /// for all checks from a single MPI rank. + /// + /// \param[in, out] violation + void incorporateRankViolations(const std::size_t* count, + const std::size_t* pointID, + const Scalar* checkValues, + ViolationSample& violation); + /// Generate random index in the sample size. /// /// \param[in] sampleSize Total number of violations of a particular @@ -337,6 +432,16 @@ namespace Opm { /// initialised. void ensureRandomBitGeneratorIsInitialised(); + /// Compute start offset into ViolationSample::pointID for + /// particular check. + /// + /// \param[in] checkIx Numerical check index in the range + /// [0..battery_.size()). + /// + /// \return Start offset into ViolationSample::pointID. + std::vector::size_type + violationPointIDStart(const std::size_t checkIx) const; + /// Compute start offset into ViolationSample::checkValues for /// particular check and sample index. /// @@ -442,6 +547,17 @@ namespace Opm { std::size_t numPoints(const ViolationSample& violation, const std::size_t checkIx) const; + /// Compute number of sample points for a single check's violations. + /// + /// Effectively the minimum of the number of violations of that + /// check and the maximum number of sample points (\code + /// this->numSamplePoints_ \endcode). + /// + /// \param[in] violationCount Total number of check violations. + /// + /// \return Number of active sample points. + std::size_t numPoints(const std::size_t violationCount) const; + /// Whether or not any checks failed at specified severity level. /// /// \param[in] level Violation severity level. diff --git a/tests/test_SatfuncConsistencyChecks.cpp b/tests/test_SatfuncConsistencyChecks.cpp index ac50317ec..269ad1587 100644 --- a/tests/test_SatfuncConsistencyChecks.cpp +++ b/tests/test_SatfuncConsistencyChecks.cpp @@ -259,6 +259,9 @@ BOOST_AUTO_TEST_CASE(Critical_Violation) 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"); diff --git a/tests/test_SatfuncConsistencyChecks_parallel.cpp b/tests/test_SatfuncConsistencyChecks_parallel.cpp new file mode 100644 index 000000000..23e8a03ef --- /dev/null +++ b/tests/test_SatfuncConsistencyChecks_parallel.cpp @@ -0,0 +1,2127 @@ +/* + 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.anyFailedChecks(), + "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.anyFailedChecks(), + "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.anyFailedChecks(), + "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.anyFailedChecks(), + "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.anyFailedChecks(), + "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.anyFailedChecks(), + "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.anyFailedChecks(), + "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.anyFailedChecks(), + "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.anyFailedChecks(), + "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.anyFailedChecks(), + "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.anyFailedChecks(), + "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([rankMultiplier](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.anyFailedChecks(), + "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.anyFailedChecks(), + "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([rankMultiplier](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.anyFailedChecks(), + "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.anyFailedChecks(), + "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([rankMultiplier](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.anyFailedChecks(), + "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.anyFailedChecks(), + "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([rankMultiplier](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.anyFailedChecks(), + "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.anyFailedChecks(), + "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([rankMultiplier](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.anyFailedChecks(), + "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.anyFailedChecks(), + "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([rankMultiplier](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.anyFailedChecks(), + "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); +} From 9895c15d7c8dd846d6e72101ce5ea9739a277d9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Fri, 28 Jun 2024 11:24:48 +0200 Subject: [PATCH 2/2] Simplify Generation of Processor Dependent MPI Tests Suggested by: [at]akva2. --- CMakeLists.txt | 164 +++++++++++++------------------------------------ 1 file changed, 44 insertions(+), 120 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7950f5084..7224e4c2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -418,44 +418,20 @@ opm_add_test(test_parallelwellinfo_mpi 4 ) -opm_add_test(test_parallel_wbp_sourcevalues_np2 - EXE_NAME - test_parallel_wbp_sourcevalues - CONDITION - MPI_FOUND AND Boost_UNIT_TEST_FRAMEWORK_FOUND - DRIVER_ARGS - -n 2 - -b ${PROJECT_BINARY_DIR} - NO_COMPILE - PROCESSORS - 2 -) - -opm_add_test(test_parallel_wbp_sourcevalues_np3 - EXE_NAME - test_parallel_wbp_sourcevalues - CONDITION - MPI_FOUND AND Boost_UNIT_TEST_FRAMEWORK_FOUND - DRIVER_ARGS - -n 3 - -b ${PROJECT_BINARY_DIR} - NO_COMPILE - PROCESSORS - 3 -) - -opm_add_test(test_parallel_wbp_sourcevalues_np4 - EXE_NAME - test_parallel_wbp_sourcevalues - CONDITION - MPI_FOUND AND Boost_UNIT_TEST_FRAMEWORK_FOUND - DRIVER_ARGS - -n 4 - -b ${PROJECT_BINARY_DIR} - NO_COMPILE - PROCESSORS - 4 -) +foreach(NPROC 2 3 4) + opm_add_test(test_parallel_wbp_sourcevalues_np${NPROC} + EXE_NAME + test_parallel_wbp_sourcevalues + CONDITION + MPI_FOUND AND Boost_UNIT_TEST_FRAMEWORK_FOUND + DRIVER_ARGS + -n ${NPROC} + -b ${PROJECT_BINARY_DIR} + NO_COMPILE + PROCESSORS + ${NPROC} + ) +endforeach() opm_add_test(test_parallel_wbp_calculation SOURCES @@ -497,89 +473,37 @@ opm_add_test(test_parallel_wbp_calculation_well_openconns 2 ) -opm_add_test(test_parallel_region_phase_pvaverage_np2 - EXE_NAME - test_region_phase_pvaverage - CONDITION - MPI_FOUND AND Boost_UNIT_TEST_FRAMEWORK_FOUND - DRIVER_ARGS - -n 2 - -b ${PROJECT_BINARY_DIR} - TEST_ARGS - --run_test=Parallel/* - NO_COMPILE - PROCESSORS - 2 -) +foreach(NPROC 2 3 4) + opm_add_test(test_parallel_region_phase_pvaverage_np${NPROC} + EXE_NAME + test_region_phase_pvaverage + CONDITION + MPI_FOUND AND Boost_UNIT_TEST_FRAMEWORK_FOUND + DRIVER_ARGS + -n ${NPROC} + -b ${PROJECT_BINARY_DIR} + TEST_ARGS + --run_test=Parallel/* + NO_COMPILE + PROCESSORS + ${NPROC} + ) +endforeach() -opm_add_test(test_parallel_region_phase_pvaverage_np3 - EXE_NAME - test_region_phase_pvaverage - CONDITION - MPI_FOUND AND Boost_UNIT_TEST_FRAMEWORK_FOUND - DRIVER_ARGS - -n 3 - -b ${PROJECT_BINARY_DIR} - TEST_ARGS - --run_test=Parallel/* - NO_COMPILE - PROCESSORS - 3 -) - -opm_add_test(test_parallel_region_phase_pvaverage_np4 - EXE_NAME - test_region_phase_pvaverage - CONDITION - MPI_FOUND AND Boost_UNIT_TEST_FRAMEWORK_FOUND - DRIVER_ARGS - -n 4 - -b ${PROJECT_BINARY_DIR} - TEST_ARGS - --run_test=Parallel/* - NO_COMPILE - PROCESSORS - 4 -) - -opm_add_test(test_parallel_satfunc_consistency_checks_np2 - EXE_NAME - test_SatfuncConsistencyChecks_parallel - CONDITION - MPI_FOUND AND Boost_UNIT_TEST_FRAMEWORK_FOUND - DRIVER_ARGS - -n 2 - -b ${PROJECT_BINARY_DIR} - NO_COMPILE - PROCESSORS - 2 -) - -opm_add_test(test_parallel_satfunc_consistency_checks_np3 - EXE_NAME - test_SatfuncConsistencyChecks_parallel - CONDITION - MPI_FOUND AND Boost_UNIT_TEST_FRAMEWORK_FOUND - DRIVER_ARGS - -n 3 - -b ${PROJECT_BINARY_DIR} - NO_COMPILE - PROCESSORS - 3 -) - -opm_add_test(test_parallel_satfunc_consistency_checks_np4 - EXE_NAME - test_SatfuncConsistencyChecks_parallel - CONDITION - MPI_FOUND AND Boost_UNIT_TEST_FRAMEWORK_FOUND - DRIVER_ARGS - -n 4 - -b ${PROJECT_BINARY_DIR} - NO_COMPILE - PROCESSORS - 4 -) +foreach(NPROC 2 3 4) + opm_add_test(test_parallel_satfunc_consistency_checks_np${NPROC} + EXE_NAME + test_SatfuncConsistencyChecks_parallel + CONDITION + MPI_FOUND AND Boost_UNIT_TEST_FRAMEWORK_FOUND + DRIVER_ARGS + -n ${NPROC} + -b ${PROJECT_BINARY_DIR} + NO_COMPILE + PROCESSORS + ${NPROC} + ) +endforeach() opm_add_test(test_broadcast DEPENDS "opmsimulators"