diff --git a/opm/input/eclipse/EclipseState/Grid/FieldProps.hpp b/opm/input/eclipse/EclipseState/Grid/FieldProps.hpp index 87a5bc0b9..72938acfc 100644 --- a/opm/input/eclipse/EclipseState/Grid/FieldProps.hpp +++ b/opm/input/eclipse/EclipseState/Grid/FieldProps.hpp @@ -294,6 +294,7 @@ static const std::unordered_map> int_keywords = { template keyword_info global_kw_info(const std::string& name, bool allow_unsupported = false); +bool is_oper_keyword(const std::string& name); } // end namespace keywords } // end namespace FieldProps diff --git a/src/opm/input/eclipse/EclipseState/Grid/FieldProps.cpp b/src/opm/input/eclipse/EclipseState/Grid/FieldProps.cpp index 9e3f6b8e4..bde6d0f87 100644 --- a/src/opm/input/eclipse/EclipseState/Grid/FieldProps.cpp +++ b/src/opm/input/eclipse/EclipseState/Grid/FieldProps.cpp @@ -84,6 +84,12 @@ static const std::set region_oper_keywords = {"MULTIREG", "ADDREG", static const std::set box_keywords = {"BOX", "ENDBOX"}; +bool is_oper_keyword(const std::string& name) +{ + return (oper_keywords.find(name) != oper_keywords.end() + || region_oper_keywords.find(name) != region_oper_keywords.end()); +} + std::string get_keyword_from_alias(const std::string& name) { if (ALIAS::aliased_keywords.count(name)) return ALIAS::aliased_keywords.at(name); diff --git a/src/opm/input/eclipse/Parser/Parser.cpp b/src/opm/input/eclipse/Parser/Parser.cpp index a87d018aa..2c6959769 100644 --- a/src/opm/input/eclipse/Parser/Parser.cpp +++ b/src/opm/input/eclipse/Parser/Parser.cpp @@ -43,6 +43,7 @@ #include #include +#include #include @@ -1584,13 +1585,40 @@ std::vector Parser::getAllDeckNames () const { // ignore unknown keywords for now (i.e. they can appear in any section) continue; - const auto& parserKeyword = parser.getParserKeywordFromDeckName( curKeywordName ); - if (ensureKeywordSectionAffiliation && !parserKeyword.isValidSection(curSectionName)) { - std::string msg = - "The keyword '"+curKeywordName+"' is located in the '"+curSectionName - +"' section where it is invalid"; - errorGuard.addError(errorKey, Log::fileMessage(curKeyword.location(), msg) ); - deckValid = false; + const bool isOperateKeyword = + Fieldprops::keywords::is_oper_keyword(curKeywordName); + + auto checker = [&errorGuard, &deckValid, &parser, curSectionName, + ensureKeywordSectionAffiliation, errorKey] + (const std::string& curKeywordName, const KeywordLocation& location) + { + const auto& parserKeyword = + parser.getParserKeywordFromDeckName( curKeywordName ); + if (ensureKeywordSectionAffiliation && !parserKeyword.isValidSection(curSectionName)) { + std::string msg = + "The keyword '{}' is located in the '{}' section where it is invalid"; + errorGuard.addError(errorKey, + Log::fileMessage(location, + fmt::format(msg, + curKeywordName, + curSectionName) + ) ); + deckValid = false; + } + }; + + if (isOperateKeyword) { + for (const auto& record : curKeyword) { + const auto& operName = record.getItem(0).getTrimmedString(0); + if (!parser.isRecognizedKeyword(operName)) { + // ignore unknown keywords + continue; + } + checker(operName, curKeyword.location()); + } + } + else { + checker(curKeyword.name(), curKeyword.location()); } continue; diff --git a/tests/parser/integration/CheckDeckValidity.cpp b/tests/parser/integration/CheckDeckValidity.cpp index ad36b7740..f4d1c39fc 100644 --- a/tests/parser/integration/CheckDeckValidity.cpp +++ b/tests/parser/integration/CheckDeckValidity.cpp @@ -31,9 +31,9 @@ BOOST_AUTO_TEST_CASE( KeywordInCorrectSection ) { Opm::Parser parser; Opm::ParseContext parseContext; - Opm::ErrorGuard errorGuard; { + Opm::ErrorGuard errorGuard; const char *correctDeckString = "RUNSPEC\n" "DIMENS\n" @@ -55,9 +55,13 @@ BOOST_AUTO_TEST_CASE( KeywordInCorrectSection ) { auto deck = parser.parseString(correctDeckString); BOOST_CHECK(Opm::checkDeck(deck, parser, parseContext, errorGuard)); + // prevent std::exit(1) in ErrorGuard's destructor! + errorGuard.dump(); + errorGuard.clear(); } { + Opm::ErrorGuard errorGuard; // wrong section ordering const char *correctDeckString = "GRID\n" @@ -69,9 +73,13 @@ BOOST_AUTO_TEST_CASE( KeywordInCorrectSection ) { auto deck = parser.parseString(correctDeckString); BOOST_CHECK(!Opm::checkDeck(deck, parser, parseContext, errorGuard)); BOOST_CHECK(Opm::checkDeck(deck, parser, parseContext, errorGuard, ~Opm::SectionTopology)); + // prevent std::exit(1) in ErrorGuard's destructor! + errorGuard.dump(); + errorGuard.clear(); } { + Opm::ErrorGuard errorGuard; // the BOX keyword is in a section where it's not supposed to be const char *incorrectDeckString = "RUNSPEC\n" @@ -101,8 +109,46 @@ BOOST_AUTO_TEST_CASE( KeywordInCorrectSection ) { // this fails because of the incorrect BOX keyword BOOST_CHECK(!Opm::checkDeck(deck, parser, parseContext, errorGuard, Opm::SectionTopology | Opm::KeywordSection)); + // prevent std::exit(1) in ErrorGuard's destructor! + errorGuard.dump(); + errorGuard.clear(); + } + + { + Opm::ErrorGuard errorGuard; + // the MULTIPLY TRANX is in a section where it's not supposed to be + const char *incorrectDeckString = + "RUNSPEC\n" + "DIMENS\n" + "3 3 3 /\n" + "GRID\n" + "DXV\n" + "1 1 1 /\n" + "DYV\n" + "1 1 1 /\n" + "DZV\n" + "1 1 1 /\n" + "TOPS\n" + "9*100 /\n" + "MULTIPLY\n" + "'TRANX' 20.0 /\n" + "'TRANY' 20.0 /\n" + "/\n" + "PROPS\n" + "SOLUTION\n" + "SCHEDULE\n"; + + auto deck = parser.parseString(incorrectDeckString); + BOOST_CHECK(!Opm::checkDeck(deck, parser, parseContext, errorGuard)); + + // this is supposed to succeed as we don't ensure that all keywords are in the + // correct section + BOOST_CHECK(Opm::checkDeck(deck, parser, parseContext, errorGuard, Opm::SectionTopology)); + + // this fails because of the incorrect TRANX keyword + BOOST_CHECK(!Opm::checkDeck(deck, parser, parseContext, errorGuard, Opm::SectionTopology | Opm::KeywordSection)); + // prevent std::exit(1) in ErrorGuard's destructor! + errorGuard.dump(); + errorGuard.clear(); } - // prevent std::exit(1) in ErrorGuard's destructor! - errorGuard.dump(); - errorGuard.clear(); }