diff --git a/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQInput.hpp b/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQInput.hpp index d21bc8974..faa6bfca5 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQInput.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQInput.hpp @@ -21,8 +21,9 @@ #ifndef UDQINPUT_HPP_ #define UDQINPUT_HPP_ -#include #include +#include +#include #include #include @@ -37,6 +38,8 @@ namespace Opm { void add_record(const DeckRecord& record); const std::vector& expressions() const noexcept; const std::string& unit(const std::string& key) const; + bool has_unit(const std::string& keyword) const; + bool has_keyword(const std::string& keyword) const; void assign_unit(const std::string& keyword, const std::string& unit); const std::vector& assignments() const; std::vector assignments(UDQVarType var_type) const; @@ -44,6 +47,7 @@ namespace Opm { std::vector m_expressions; std::vector m_assignments; std::unordered_map units; + std::unordered_set keywords; }; } diff --git a/opm/parser/eclipse/Parser/ParseContext.hpp b/opm/parser/eclipse/Parser/ParseContext.hpp index e403b3dd9..de5b5453e 100644 --- a/opm/parser/eclipse/Parser/ParseContext.hpp +++ b/opm/parser/eclipse/Parser/ParseContext.hpp @@ -107,9 +107,9 @@ namespace Opm { */ void addKey(const std::string& key, InputError::Action default_action); /* - The PARSE_EXTRA_RECORDS field regulates how the parser - responds to keywords whose size has been defined in the - previous keyword. + The PARSE_EXTRA_RECORDS field regulates how the parser + responds to keywords whose size has been defined in the + previous keyword. Example: EQLDIMS 2 100 20 1 1 / @@ -117,11 +117,11 @@ namespace Opm { 2469 382.4 1705.0 0.0 500 0.0 1 1 20 / 2469 382.4 1705.0 0.0 500 0.0 1 1 20 / 2470 382.4 1705.0 0.0 500 0.0 1 1 20 / - EQLDIMS's first entry is 2 and defines the record size of the - EQUIL keyword. Since there are 3 records in EQUIL, this results - in an error that needs to be handled by the parser. By default, - an exception is thrown, or it may be specified in the - PARSE_EXTRA_RECORDS field that this error is to be ignored. + EQLDIMS's first entry is 2 and defines the record size of the + EQUIL keyword. Since there are 3 records in EQUIL, this results + in an error that needs to be handled by the parser. By default, + an exception is thrown, or it may be specified in the + PARSE_EXTRA_RECORDS field that this error is to be ignored. */ const static std::string PARSE_EXTRA_RECORDS; /* @@ -271,6 +271,8 @@ namespace Opm { const static std::string SUMMARY_UNKNOWN_WELL; const static std::string SUMMARY_UNKNOWN_GROUP; const static std::string SUMMARY_UNHANDLED_KEYWORD; + const static std::string SUMMARY_UNDEFINED_UDQ; + const static std::string SUMMARY_UDQ_MISSING_UNIT; /* A well must be specified (e.g. WELSPECS) and have completions diff --git a/src/opm/output/eclipse/Summary.cpp b/src/opm/output/eclipse/Summary.cpp index 27fe287c8..1768fa909 100644 --- a/src/opm/output/eclipse/Summary.cpp +++ b/src/opm/output/eclipse/Summary.cpp @@ -1274,12 +1274,15 @@ Summary::Summary( const EclipseState& st, auto * nodeptr = ecl_smspec_add_node( smspec, keyword.c_str(), node.wgname().c_str(), node.num(), st.getUnits().name( val.unit ), 0 ); this->handlers->handlers.emplace_back( nodeptr, handle ); } else if (is_udq(keyword)) { - const auto& unit = udq.unit(keyword); + std::string udq_unit = "?????"; const auto& udq_params = st.runspec().udqParams(); - ecl_smspec_add_node(smspec, keyword.c_str(), node.wgname().c_str(), node.num(), unit.c_str(), udq_params.undefinedValue()); - } else { + + if (udq.has_unit(keyword)) + udq_unit = udq.unit(keyword); + + ecl_smspec_add_node(smspec, keyword.c_str(), node.wgname().c_str(), node.num(), udq_unit.c_str(), udq_params.undefinedValue()); + } else unsupported_keywords.insert(keyword); - } } for ( const auto& keyword : unsupported_keywords ) { Opm::OpmLog::info("Keyword " + std::string(keyword) + " is unhandled"); diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQInput.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQInput.cpp index 1b4e7bd3d..79e3f6855 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQInput.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQInput.cpp @@ -49,6 +49,8 @@ namespace Opm { this->m_assignments.emplace_back( quantity, selector, value ); } else this->m_expressions.emplace_back(action, quantity, data); + + this->keywords.insert(quantity); } @@ -94,4 +96,13 @@ namespace Opm { } this->units[keyword] = unit; } + + bool UDQInput::has_unit(const std::string& keyword) const { + return (this->units.count(keyword) > 0); + } + + bool UDQInput::has_keyword(const std::string& keyword) const { + return (this->keywords.count(keyword) > 0); + } + } diff --git a/src/opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.cpp b/src/opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.cpp index bdd4f40b3..dc2727bde 100644 --- a/src/opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.cpp +++ b/src/opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -124,6 +125,9 @@ namespace { {"SGAS" , {"BSGAS"}} }; + bool is_udq(const std::string& keyword) { + return (keyword.size() > 1 && keyword[1] == 'U'); + } void handleMissingWell( const ParseContext& parseContext, ErrorGuard& errors, const std::string& keyword, const std::string& well) { @@ -534,6 +538,21 @@ inline void keywordMISC( SummaryConfig::keyword_list& list, ErrorGuard& errors, const GridDims& dims) { const auto var_type = ecl_smspec_identify_var_type( keyword.name().c_str() ); + const auto& name = keyword.name(); + if (is_udq(name)) { + const auto& udq = schedule.getUDQConfig(schedule.size() - 1); + + if (!udq.has_keyword(name)) { + std::string msg{"Summary output has been requested for UDQ keyword: " + name + " but it has not been configured"}; + parseContext.handleError(ParseContext::SUMMARY_UNDEFINED_UDQ, msg, errors); + return; + } + + if (!udq.has_unit(name)) { + std::string msg{"Summary output has been requested for UDQ keyword: " + name + " but no unit has not been configured"}; + parseContext.handleError(ParseContext::SUMMARY_UDQ_MISSING_UNIT, msg, errors); + } + } switch( var_type ) { case ECL_SMSPEC_WELL_VAR: return keywordW( list, parseContext, errors, keyword, schedule ); diff --git a/src/opm/parser/eclipse/Parser/ParseContext.cpp b/src/opm/parser/eclipse/Parser/ParseContext.cpp index a39f2ff11..072e0994e 100644 --- a/src/opm/parser/eclipse/Parser/ParseContext.cpp +++ b/src/opm/parser/eclipse/Parser/ParseContext.cpp @@ -17,11 +17,11 @@ along with OPM. If not, see . */ -#include #include #include #include +#include #include #include @@ -94,6 +94,8 @@ namespace Opm { addKey(SUMMARY_UNKNOWN_WELL, InputError::THROW_EXCEPTION); addKey(SUMMARY_UNKNOWN_GROUP, InputError::THROW_EXCEPTION); addKey(SUMMARY_UNHANDLED_KEYWORD, InputError::WARN); + addKey(SUMMARY_UNDEFINED_UDQ, InputError::WARN); + addKey(SUMMARY_UDQ_MISSING_UNIT, InputError::WARN); addKey(SCHEDULE_INVALID_NAME, InputError::THROW_EXCEPTION); addKey(ACTIONX_ILLEGAL_KEYWORD, InputError::THROW_EXCEPTION); @@ -321,6 +323,8 @@ namespace Opm { const std::string ParseContext::SUMMARY_UNKNOWN_WELL = "SUMMARY_UNKNOWN_WELL"; const std::string ParseContext::SUMMARY_UNKNOWN_GROUP = "SUMMARY_UNKNOWN_GROUP"; const std::string ParseContext::SUMMARY_UNHANDLED_KEYWORD = "SUMMARY_UNHANDLED_KEYWORD"; + const std::string ParseContext::SUMMARY_UNDEFINED_UDQ = "SUMMARY_UNDEFINED_UDQ"; + const std::string ParseContext::SUMMARY_UDQ_MISSING_UNIT = "SUMMARY_UDQ_MISSING_UNIT"; const std::string ParseContext::RPT_MIXED_STYLE = "RPT_MIXED_STYLE"; const std::string ParseContext::RPT_UNKNOWN_MNEMONIC = "RPT_UNKNOWN_MNEMONIC"; diff --git a/tests/parser/SummaryConfigTests.cpp b/tests/parser/SummaryConfigTests.cpp index db886aeb6..16fa1eed5 100644 --- a/tests/parser/SummaryConfigTests.cpp +++ b/tests/parser/SummaryConfigTests.cpp @@ -432,6 +432,19 @@ BOOST_AUTO_TEST_CASE(INVALID_WELL2) { BOOST_CHECK_NO_THROW( createSummary( input , parseContext )); } +BOOST_AUTO_TEST_CASE(UNDEFINED_UDQ_WELL) { + ParseContext parseContext; + const auto input = "WUWCT\n" + "/\n"; + parseContext.updateKey( ParseContext::SUMMARY_UNDEFINED_UDQ, InputError::THROW_EXCEPTION ); + BOOST_CHECK_THROW( createSummary( input , parseContext ) , std::invalid_argument); + + parseContext.updateKey( ParseContext::SUMMARY_UNDEFINED_UDQ, InputError::IGNORE ); + BOOST_CHECK_NO_THROW( createSummary( input , parseContext )); +} + + + BOOST_AUTO_TEST_CASE(INVALID_GROUP) { ParseContext parseContext; diff --git a/tests/parser/UDQTests.cpp b/tests/parser/UDQTests.cpp index 0921c5cf0..12fb5945a 100644 --- a/tests/parser/UDQTests.cpp +++ b/tests/parser/UDQTests.cpp @@ -153,6 +153,7 @@ UDQ ASSIGN WUBHP 0.0 / UNITS WUBHP 'BARSA' / DEFINE FUOPR AVEG(WOPR) + 1/ + ASSIGN WUXUNIT 0.0 / / DATES @@ -172,6 +173,10 @@ UDQ BOOST_CHECK_THROW( udq.unit("NO_SUCH_KEY"), std::invalid_argument ); BOOST_CHECK_EQUAL( udq.unit("WUBHP"), "BARSA"); + BOOST_CHECK( udq.has_keyword("WUBHP") ); + BOOST_CHECK( !udq.has_keyword("NO_SUCH_KEY") ); + BOOST_CHECK( !udq.has_unit("WUXUNIT")); + BOOST_CHECK( udq.has_unit("WUBHP")); Parser parser; auto deck = parser.parseString(input);