From 1dd1b71095669478bd7d5e32251bd2a2a5b819f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Mon, 21 Sep 2020 15:00:24 +0200 Subject: [PATCH] PVTO: Switch to Using {fmt} Backend for Formatting This commit switches the custom diagnostic message formatting based on std::ostringstream to using a formatter implemented in terms of the fmt::format function. This removes the custom indentation from earlier. Note that we output at most four records to the console, including a message limit notification if applicable, and that this limit is currently not adjustable by the user. We do on the other hand output all flipped records to the .PRT file. New Example Diagnostic Output: * To the Console Warning: Non-Monotonic Oil Formation Volume Factor Detected in Keyword PVTO, PVTNUM=1 In /path/to/PVTO.INCL line 6 Record 9: FVF 1.234 at RS 123.456 is not greater than FVF 2.345 at RS 121.212 Record 10: FVF 1.233 at RS 123.457 is not greater than FVF 1.234 at RS 123.456 Record 11: FVF 1.233 at RS 123.460 is not greater than FVF 1.233 at RS 123.457 Report limit reached, see PRT-file for additional records. * In the PRT File (Unlimited Records) Warning: Non-Monotonic Oil Formation Volume Factor Detected in Keyword PVTO, PVTNUM=1 In /path/to/PVTO.INCL line 6 Record 9: FVF 1.234 at RS 123.456 is not greater than FVF 2.345 at RS 121.212 Record 10: FVF 1.233 at RS 123.457 is not greater than FVF 1.234 at RS 123.456 Record 11: FVF 1.233 at RS 123.460 is not greater than FVF 1.233 at RS 123.457 Record 12: FVF 1.233 at RS 123.461 is not greater than FVF 1.233 at RS 123.460 Record 13: FVF 1.233 at RS 123.470 is not greater than FVF 1.233 at RS 123.461 The length of each 'Record' line is 78 characters as of this change (assuming METRIC conventions, FIELD conventions not tested). The length of the 'In ...' line depends on the number of characters in the full filepath. --- .../EclipseState/Tables/TableManager.hpp | 4 + .../EclipseState/Tables/TableManager.cpp | 123 ++++++++++++++---- 2 files changed, 100 insertions(+), 27 deletions(-) diff --git a/opm/parser/eclipse/EclipseState/Tables/TableManager.hpp b/opm/parser/eclipse/EclipseState/Tables/TableManager.hpp index 2838dc02a..137c76bd9 100644 --- a/opm/parser/eclipse/EclipseState/Tables/TableManager.hpp +++ b/opm/parser/eclipse/EclipseState/Tables/TableManager.hpp @@ -493,6 +493,10 @@ namespace Opm { void checkPVTOMonotonicity(const Deck& deck) const; + void logPVTOMonotonicityFailure(const Deck& deck, + const std::size_t tableID, + const std::vector& flipped_Bo) const; + std::map m_simpleTables; std::vector m_pvtgTables; std::vector m_pvtgwTables; diff --git a/src/opm/parser/eclipse/EclipseState/Tables/TableManager.cpp b/src/opm/parser/eclipse/EclipseState/Tables/TableManager.cpp index a9d741066..65ad2fbe6 100644 --- a/src/opm/parser/eclipse/EclipseState/Tables/TableManager.cpp +++ b/src/opm/parser/eclipse/EclipseState/Tables/TableManager.cpp @@ -24,8 +24,12 @@ #include #include +#include + +#include #include #include +#include #include #include @@ -1206,43 +1210,110 @@ namespace Opm { void TableManager::checkPVTOMonotonicity(const Deck& deck) const { - const auto& usys = deck.getActiveUnitSystem(); - const auto& tables = this->getPvtoTables(); + auto tableID = std::size_t{0}; + for (const auto& pvto : this->getPvtoTables()) { + ++tableID; // One-based table ID + + const auto flipped_Bo = pvto.nonMonotonicSaturatedFVF(); + if (flipped_Bo.empty()) { + // Normal case. Bo strictly increasing as a function of Rs + // in saturated table. Nothing to do here. + continue; + } + + // Unexpected case. Bo is *not* strictly increasing as a + // function of Rs. Report condition to user. + this->logPVTOMonotonicityFailure(deck, tableID, flipped_Bo); + } + } + + void TableManager::logPVTOMonotonicityFailure(const Deck& deck, + const std::size_t tableID, + const std::vector& flipped_Bo) const + { + const auto& usys = deck.getActiveUnitSystem(); + const auto& pvtoLoc = deck.getKeyword(std::size_t{0}).location(); using M = UnitSystem::measure; + using namespace fmt::literals; - const auto nDigit = [](const std::size_t n) { + const auto nDigit = [](const std::size_t n) + { return 1 + static_cast(std::floor(std::log10(n))); }; - const auto nDigit_reg = nDigit(tables.size()); + const auto formatHeader = [&pvtoLoc](const std::size_t pvtnum) + { + return fmt::format("Non-Monotonic Oil Formation Volume Factor Detected in Keyword PVTO, PVTNUM={num}\n" + "In {file} line {line}", + "num"_a = pvtnum, + "file"_a = pvtoLoc.filename, + "line"_a = pvtoLoc.lineno); + }; - auto tableID = std::size_t{0}; - std::ostringstream os; - for (const auto& pvto : tables) { - ++tableID; // One-based table ID - const auto& flipped = pvto.nonMonotonicSaturatedFVF(); - if (flipped.empty()) { continue; } + const auto formatBoRecord = + [&usys](const std::size_t numDigitsRecordID, + const std::size_t floatPrecision, + const PvtoTable::FlippedFVF& flipped) + { + return fmt::format( + "Record {rec:{width}}: " + "FVF {BO_1:.{prec}f} at RS {RS_1:.{prec}f} " + "is not greater than " + "FVF {BO_0:.{prec}f} at RS {RS_0:.{prec}f}", + "rec"_a = flipped.i + 1, + "width"_a = numDigitsRecordID, + "prec"_a = floatPrecision, + "BO_1"_a = usys.from_si(M::oil_formation_volume_factor, flipped.Bo[1]), + "RS_1"_a = usys.from_si(M::gas_oil_ratio, flipped.Rs[1]), + "BO_0"_a = usys.from_si(M::oil_formation_volume_factor, flipped.Bo[0]), + "RS_0"_a = usys.from_si(M::gas_oil_ratio, flipped.Rs[0]) + ); + }; - const auto nDigit_rec = nDigit(flipped.back().i + 1); + std::ostringstream prt; + std::ostringstream console; - os << " * PVTO [PVTNUM = " << std::setw(nDigit_reg) << tableID << "]\n"; - for (const auto& f : flipped) { - os << " Record " << std::setw(nDigit_rec) << (f.i + 1) - << ": FVF " << std::setprecision(3) - << usys.from_si(M::oil_formation_volume_factor, f.Bo[1]) - << " at RS " - << usys.from_si(M::gas_oil_ratio, f.Rs[1]) - << " is not greater than FVF " - << usys.from_si(M::oil_formation_volume_factor, f.Bo[0]) - << " at RS " - << usys.from_si(M::gas_oil_ratio, f.Rs[0]) << '\n'; + { + const auto header = formatHeader(tableID); + prt << header << '\n'; + console << header << '\n'; + } + + // Append record to console message if either of the following conditions hold + // + // 1. Total number of flipped records does not exceed `consoleRecordLimit`. + // + // 2. Record is among `consoleRecordLimit - 1` first records. + // + // In the second case, also emit limiter message as `consoleRecordLimit`-th + // record. + // + // Print file gets all flipped records. + const std::size_t numDigitsRecordID = nDigit(flipped_Bo.back().i + 1); + const std::size_t numRecords = static_cast(flipped_Bo.size()); + const std::size_t consoleRecordLimit = 4; + const std::size_t floatPrecision = 3; + const bool consoleWriteAll = numRecords <= consoleRecordLimit; + for (auto recordIx = 0*numRecords; recordIx < numRecords; ++recordIx) { + const auto record = + formatBoRecord(numDigitsRecordID, floatPrecision, flipped_Bo[recordIx]); + + prt << record << '\n'; + + if (consoleWriteAll || (recordIx + 1 < consoleRecordLimit)) { + console << record << '\n'; + } + else if (recordIx + 1 == consoleRecordLimit) { + console << "Report limit reached, see PRT-file for additional records.\n"; } } - if (os.tellp() != std::streampos{0}) { - // There were non-monotonic FVFs in saturated table - OpmLog::warning("Non-Monotonic Oil Formation Volume Factor Detected\n" + os.str()); + if (auto prtLog = OpmLog::getBackend("ECLIPSEPRTLOG")) { + prtLog->addMessage(Log::MessageType::Warning, prt.str()); + } + if (auto consoleLog = OpmLog::getBackend("STDOUT_LOGGER")) { + consoleLog->addMessage(Log::MessageType::Warning, console.str()); } } @@ -1275,5 +1346,3 @@ namespace Opm { return result; } } - -