diff --git a/ebos/eclbasevanguard.hh b/ebos/eclbasevanguard.hh index a2f97f8ca..ab62b5222 100644 --- a/ebos/eclbasevanguard.hh +++ b/ebos/eclbasevanguard.hh @@ -65,7 +65,7 @@ struct EnableOpmRstFile { using type = UndefinedProperty; }; template -struct EclStrictParsing { +struct ParsingStrictness { using type = UndefinedProperty; }; template @@ -134,8 +134,8 @@ struct EnableOpmRstFile { static constexpr bool value = false; }; template -struct EclStrictParsing { - static constexpr bool value = false; +struct ParsingStrictness { + static constexpr auto value = "normal"; }; template struct SchedRestart { @@ -231,8 +231,11 @@ public: "Include OPM-specific keywords in the ECL restart file to enable restart of OPM simulators from these files"); EWOMS_REGISTER_PARAM(TypeTag, std::string, IgnoreKeywords, "List of Eclipse keywords which should be ignored. As a ':' separated string."); - EWOMS_REGISTER_PARAM(TypeTag, bool, EclStrictParsing, - "Use strict mode for parsing - all errors are collected before the applicaton exists."); + EWOMS_REGISTER_PARAM(TypeTag, std::string, ParsingStrictness, + "Set strictness of parsing process. Available options are " + "normal (stop for critical errors), " + "high (stop for all errors) and " + "low (as normal, except do not stop due to unsupported keywords even if marked critical"); EWOMS_REGISTER_PARAM(TypeTag, bool, SchedRestart, "When restarting: should we try to initialize wells and groups from historical SCHEDULE section."); EWOMS_REGISTER_PARAM(TypeTag, int, EdgeWeightsMethod, @@ -290,7 +293,6 @@ public: #endif enableDistributedWells_ = EWOMS_GET_PARAM(TypeTag, bool, AllowDistributedWells); ignoredKeywords_ = EWOMS_GET_PARAM(TypeTag, std::string, IgnoreKeywords); - eclStrictParsing_ = EWOMS_GET_PARAM(TypeTag, bool, EclStrictParsing); int output_param = EWOMS_GET_PARAM(TypeTag, int, EclOutputInterval); if (output_param >= 0) outputInterval_ = output_param; diff --git a/ebos/eclgenericvanguard.cc b/ebos/eclgenericvanguard.cc index bb88829cd..d64b73e5d 100644 --- a/ebos/eclgenericvanguard.cc +++ b/ebos/eclgenericvanguard.cc @@ -133,7 +133,7 @@ void EclGenericVanguard::readDeck(const std::string& filename) modelParams_.actionState_, modelParams_.wtestState_, modelParams_.eclSummaryConfig_, - nullptr, false, false, false, {}); + nullptr, "normal", false, false, {}); modelParams_.setupTime_ = setupTimer.stop(); } diff --git a/ebos/eclgenericvanguard.hh b/ebos/eclgenericvanguard.hh index 3fdffd4ee..0f0edcb74 100644 --- a/ebos/eclgenericvanguard.hh +++ b/ebos/eclgenericvanguard.hh @@ -296,7 +296,6 @@ protected: #endif bool enableDistributedWells_; std::string ignoredKeywords_; - bool eclStrictParsing_; std::optional outputInterval_; bool useMultisegmentWell_; bool enableExperiments_; diff --git a/opm/simulators/flow/KeywordValidation.cpp b/opm/simulators/flow/KeywordValidation.cpp index d4d09297d..4fa3df6a3 100644 --- a/opm/simulators/flow/KeywordValidation.cpp +++ b/opm/simulators/flow/KeywordValidation.cpp @@ -27,10 +27,12 @@ #include +#include #include #include #include #include +#include #include #include @@ -43,7 +45,7 @@ namespace KeywordValidation { - std::string get_error_report(const std::vector& errors, const bool critical) + std::string get_error_report(const std::vector& errors, const bool include_noncritical, const bool include_critical) { const std::string keyword_format = " {keyword}: keyword not supported\n"; const std::string item_format1 = " {{keyword}}: invalid value '{}' for item {}\n"; @@ -52,7 +54,7 @@ namespace KeywordValidation std::string report; for (const ValidationError& err : errors) { - if (err.critical == critical) { + if ((err.critical && include_critical) || (!err.critical && include_noncritical)) { if (err.item_number && err.item_value) { std::string message; if (err.record_number == 0) { @@ -84,6 +86,7 @@ namespace KeywordValidation void KeywordValidator::validateDeck(const Deck& deck, const ParseContext& parse_context, + const bool treat_critical_as_noncritical, ErrorGuard& error_guard) const { // Make a vector with all problems encountered in the deck. @@ -98,18 +101,31 @@ namespace KeywordValidation } } - // First report non-critical problems as a warning. - auto warning_report = get_error_report(errors, false); - if (!warning_report.empty()) { - parse_context.handleError( - ParseContext::SIMULATOR_KEYWORD_NOT_SUPPORTED, warning_report, std::nullopt, error_guard); - } + if (treat_critical_as_noncritical) { + // Get both critical and noncritical errors. + auto warning_report = get_error_report(errors, true, true); + if (!warning_report.empty()) { + // Report all as warnings. + parse_context.handleError(ParseContext::SIMULATOR_KEYWORD_NOT_SUPPORTED, warning_report, std::nullopt, error_guard); + } + } else { + // First report non-critical problems as a warning. + auto warning_report = get_error_report(errors, true, false); + if (!warning_report.empty()) { + parse_context.handleError( + ParseContext::SIMULATOR_KEYWORD_NOT_SUPPORTED, warning_report, std::nullopt, error_guard); + } - // Then report critical problems as an error. - auto error_report = get_error_report(errors, true); - if (!error_report.empty()) { - parse_context.handleError( - ParseContext::SIMULATOR_KEYWORD_NOT_SUPPORTED_CRITICAL, error_report, std::nullopt, error_guard); + // Then report critical problems as an error. + auto error_report = get_error_report(errors, false, true); + if (!error_report.empty()) { + OpmLog::info("\nOPM Flow will terminate due to unsupported critical keywords.\n" + "These are keywords that would change the simulator results if supported.\n" + "If you need to override this behaviour, you can use the command line argument --parsing-strictness=low,\n" + "this will reduce the severity of this to a warning instead of an error."); + parse_context.handleError( + ParseContext::SIMULATOR_KEYWORD_NOT_SUPPORTED_CRITICAL, error_report, std::nullopt, error_guard); + } } } diff --git a/opm/simulators/flow/KeywordValidation.hpp b/opm/simulators/flow/KeywordValidation.hpp index 98d765eb1..e78df09ed 100644 --- a/opm/simulators/flow/KeywordValidation.hpp +++ b/opm/simulators/flow/KeywordValidation.hpp @@ -78,11 +78,12 @@ namespace KeywordValidation }; // Get a formatted error report from a vector of validation errors. Set - // critical to true if the report should contain only critical errors. If - // critical is false, only non-critical errors are reported. If not - // critical/non-critical errors are present, but the critical flag to reset - // them, the result will be an empty string. - std::string get_error_report(const std::vector& errors, const bool critical); + // include_noncritical to true if the report should include noncritical errors, and + // include_critical to true if the report should include critical errors. These may + // be set independently. If no errors are included the result will be an empty string. + std::string get_error_report(const std::vector& errors, + const bool include_noncritical, + const bool include_critical); @@ -109,9 +110,12 @@ namespace KeywordValidation // Validate a deck, reporting warnings and errors. If there are only // warnings, these will be reported. If there are errors, these are - // reported, and execution of the program is halted. + // reported, and execution of the program is halted, unless the argument + // treat_critical_as_noncritical is true, then these also will only be + // reported and not cause termination. void validateDeck(const Deck& deck, const ParseContext& parse_context, + const bool treat_critical_as_noncritical, ErrorGuard& error_guard) const; // Validate a single deck keyword. If a problem is encountered, add the diff --git a/opm/simulators/flow/Main.cpp b/opm/simulators/flow/Main.cpp index cf44e423d..347004851 100644 --- a/opm/simulators/flow/Main.cpp +++ b/opm/simulators/flow/Main.cpp @@ -171,7 +171,7 @@ void Main::readDeck(const std::string& deckFilename, const std::string& outputMode, const bool init_from_restart_file, const bool allRanksDbgPrtLog, - const bool strictParsing, + const std::string& parsingStrictness, const int mpiRank, const int output_param, const std::string& parameters, @@ -202,7 +202,7 @@ void Main::readDeck(const std::string& deckFilename, wtestState_, summaryConfig_, std::make_shared(), - strictParsing, + parsingStrictness, init_from_restart_file, outputCout_, outputInterval); diff --git a/opm/simulators/flow/Main.hpp b/opm/simulators/flow/Main.hpp index 498f44d43..dd1283f01 100644 --- a/opm/simulators/flow/Main.hpp +++ b/opm/simulators/flow/Main.hpp @@ -374,7 +374,7 @@ private: EWOMS_GET_PARAM(PreTypeTag, std::string, OutputMode), !EWOMS_GET_PARAM(PreTypeTag, bool, SchedRestart), EWOMS_GET_PARAM(PreTypeTag, bool, EnableLoggingFalloutWarning), - EWOMS_GET_PARAM(PreTypeTag, bool, EclStrictParsing), + EWOMS_GET_PARAM(PreTypeTag, std::string, ParsingStrictness), mpiRank, EWOMS_GET_PARAM(PreTypeTag, int, EclOutputInterval), cmdline_params, @@ -626,7 +626,7 @@ private: const std::string& outputMode, const bool init_from_restart_file, const bool allRanksDbgPrtLog, - const bool strictParsing, + const std::string& parsingStrictness, const int mpiRank, const int output_param, const std::string& parameters, diff --git a/opm/simulators/utils/readDeck.cpp b/opm/simulators/utils/readDeck.cpp index e9d0b5825..bf12d0059 100644 --- a/opm/simulators/utils/readDeck.cpp +++ b/opm/simulators/utils/readDeck.cpp @@ -191,6 +191,7 @@ namespace { const bool checkDeck, const Opm::Parser& parser, const Opm::ParseContext& parseContext, + const bool treatCriticalAsNonCritical, Opm::ErrorGuard& errorGuard) { Opm::Deck deck(parser.parseFile(deckFilename, parseContext, errorGuard)); @@ -203,7 +204,7 @@ namespace { Opm::KeywordValidation::specialValidation() }; - keyword_validator.validateDeck(deck, parseContext, errorGuard); + keyword_validator.validateDeck(deck, parseContext, treatCriticalAsNonCritical, errorGuard); if (checkDeck) { Opm::checkDeck(deck, parser, parseContext, errorGuard); @@ -235,6 +236,7 @@ namespace { std::shared_ptr python, const bool initFromRestart, const bool checkDeck, + const bool treatCriticalAsNonCritical, const std::optional& outputInterval, Opm::ErrorGuard& errorGuard) { @@ -248,7 +250,7 @@ namespace { auto parser = Opm::Parser{}; const auto deck = readDeckFile(deckFilename, checkDeck, parser, - *parseContext, errorGuard); + *parseContext, treatCriticalAsNonCritical, errorGuard); if (eclipseState == nullptr) { eclipseState = createEclipseState(comm, deck); @@ -490,7 +492,7 @@ void Opm::readDeck(Opm::Parallel::Communication comm, std::unique_ptr& wtestState, std::shared_ptr& summaryConfig, std::shared_ptr python, - const bool strictParsing, + const std::string& parsingStrictness, const bool initFromRestart, const bool checkDeck, const std::optional& outputInterval) @@ -500,13 +502,20 @@ void Opm::readDeck(Opm::Parallel::Communication comm, int parseSuccess = 1; // > 0 is success std::string failureMessage; + if (parsingStrictness != "high" && parsingStrictness != "normal" && parsingStrictness != "low") { + OPM_THROW(std::runtime_error, + fmt::format("Incorrect value {} for parameter ParsingStrictness, must be 'high', 'normal', or 'low'", parsingStrictness)); + } + if (comm.rank() == 0) { // Always true when !HAVE_MPI + const bool exitOnAllErrors = (parsingStrictness == "high"); + const bool treatCriticalAsNonCritical = (parsingStrictness == "low"); try { - auto parseContext = setupParseContext(strictParsing); + auto parseContext = setupParseContext(exitOnAllErrors); readOnIORank(comm, deckFilename, parseContext.get(), eclipseState, schedule, udqState, actionState, wtestState, summaryConfig, std::move(python), initFromRestart, - checkDeck, outputInterval, *errorGuard); + checkDeck, treatCriticalAsNonCritical, outputInterval, *errorGuard); } catch (const OpmInputError& input_error) { failureMessage = input_error.what(); diff --git a/opm/simulators/utils/readDeck.hpp b/opm/simulators/utils/readDeck.hpp index 189069fc8..3ee94d904 100644 --- a/opm/simulators/utils/readDeck.hpp +++ b/opm/simulators/utils/readDeck.hpp @@ -60,7 +60,7 @@ enum class FileOutputMode { void ensureOutputDirExists(const std::string& cmdline_output_dir); -std::unique_ptr setupParseContext(const bool strictParsing); +std::unique_ptr setupParseContext(const bool exitOnAllErrors); // Setup the OpmLog backends FileOutputMode @@ -85,7 +85,7 @@ void readDeck(Parallel::Communication comm, std::unique_ptr& wtestState, std::shared_ptr& summaryConfig, std::shared_ptr python, - bool strictParsing, + const std::string& parsingStrictness, bool initFromRestart, bool checkDeck, const std::optional& outputInterval); diff --git a/tests/test_keyword_validator.cpp b/tests/test_keyword_validator.cpp index dc6468a22..feeaa6b32 100644 --- a/tests/test_keyword_validator.cpp +++ b/tests/test_keyword_validator.cpp @@ -277,7 +277,7 @@ ECHO KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {}); std::vector errors; validator.validateDeckKeyword(test_keyword, errors); - const auto report = get_error_report(errors, false); + const auto report = get_error_report(errors, true, false); BOOST_CHECK(report == "Unsupported keywords or keyword items:\n\n" " ECHO: keyword not supported\n" @@ -296,7 +296,7 @@ ECHO KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {}); std::vector errors; validator.validateDeckKeyword(test_keyword, errors); - const auto report = get_error_report(errors, true); + const auto report = get_error_report(errors, false, true); BOOST_CHECK(report.empty()); } @@ -311,7 +311,7 @@ NOECHO KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {}); std::vector errors; validator.validateDeckKeyword(test_keyword, errors); - const auto report = get_error_report(errors, true); + const auto report = get_error_report(errors, false, true); BOOST_CHECK(report == "Unsupported keywords or keyword items:\n\n" " NOECHO: keyword not supported\n" @@ -329,7 +329,7 @@ NOECHO KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {}); std::vector errors; validator.validateDeckKeyword(test_keyword, errors); - const auto report = get_error_report(errors, false); + const auto report = get_error_report(errors, true, false); BOOST_CHECK(report.empty()); } @@ -345,7 +345,7 @@ PINCH KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {}); std::vector errors; validator.validateDeckKeyword(test_keyword, errors); - const auto report = get_error_report(errors, false); + const auto report = get_error_report(errors, true, false); BOOST_CHECK(report == "Unsupported keywords or keyword items:\n\n" " PINCH: invalid value 'FOO' for item 2\n" @@ -368,7 +368,7 @@ COMPDAT KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {}); std::vector errors; validator.validateDeckKeyword(test_keyword, errors); - const auto report = get_error_report(errors, false); + const auto report = get_error_report(errors, true, false); BOOST_CHECK(report == "Unsupported keywords or keyword items:\n\n" " COMPDAT: invalid value '0' in record 1 for item 2\n" @@ -389,7 +389,7 @@ PINCH KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {}); std::vector errors; validator.validateDeckKeyword(test_keyword, errors); - const auto report = get_error_report(errors, true); + const auto report = get_error_report(errors, false, true); BOOST_CHECK(report.empty()); } @@ -405,7 +405,7 @@ ENDSCALE KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {}); std::vector errors; validator.validateDeckKeyword(test_keyword, errors); - const auto report = get_error_report(errors, false); + const auto report = get_error_report(errors, true, false); BOOST_CHECK(report == "Unsupported keywords or keyword items:\n\n" " ENDSCALE: invalid value '0' for item 3\n" @@ -424,7 +424,7 @@ ENDSCALE KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {}); std::vector errors; validator.validateDeckKeyword(test_keyword, errors); - const auto report = get_error_report(errors, true); + const auto report = get_error_report(errors, false, true); BOOST_CHECK(report.empty()); } @@ -440,7 +440,7 @@ ENDSCALE KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {}); std::vector errors; validator.validateDeckKeyword(test_keyword, errors); - const auto report = get_error_report(errors, true); + const auto report = get_error_report(errors, false, true); BOOST_CHECK(report == "Unsupported keywords or keyword items:\n\n" " ENDSCALE: invalid value '0' for item 4\n" @@ -459,7 +459,7 @@ ENDSCALE KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {}); std::vector errors; validator.validateDeckKeyword(test_keyword, errors); - const auto report = get_error_report(errors, false); + const auto report = get_error_report(errors, true, false); BOOST_CHECK(report.empty()); } @@ -485,7 +485,7 @@ ENDSCALE validator.validateDeckKeyword(test_keyword2, errors); validator.validateDeckKeyword(test_keyword3, errors); validator.validateDeckKeyword(test_keyword4, errors); - const auto report = get_error_report(errors, false); + const auto report = get_error_report(errors, true, false); BOOST_CHECK(report == "Unsupported keywords or keyword items:\n\n" " ECHO: keyword not supported\n" @@ -516,7 +516,7 @@ ENDSCALE validator.validateDeckKeyword(test_keyword2, errors); validator.validateDeckKeyword(test_keyword3, errors); validator.validateDeckKeyword(test_keyword4, errors); - const auto report = get_error_report(errors, true); + const auto report = get_error_report(errors, false, true); BOOST_CHECK(report == "Unsupported keywords or keyword items:\n\n" " NOECHO: keyword not supported\n"