diff --git a/src/opm/output/eclipse/Summary.cpp b/src/opm/output/eclipse/Summary.cpp index d6f4089b9..de911a84a 100644 --- a/src/opm/output/eclipse/Summary.cpp +++ b/src/opm/output/eclipse/Summary.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -2522,6 +2523,7 @@ private: SummaryOutputParameters outputParameters_{}; std::vector requiredRestartParameters_{}; + std::vector udq_parameters; std::vector valueKeys_{}; std::vector unwritten_{}; @@ -2538,6 +2540,8 @@ private: void configureRequiredRestartParameters(const SummaryConfig& sumcfg, const Schedule& sched); + void configureUDQ(const SummaryConfig& summary_config, const Schedule& sched); + MiniStep& getNextMiniStep(const int report_step); const MiniStep& lastUnwritten() const; @@ -2563,6 +2567,7 @@ SummaryImplementation(const EclipseState& es, this->configureTimeVectors(es, sumcfg); this->configureSummaryInput(es, sumcfg, grid, sched); this->configureRequiredRestartParameters(sumcfg, sched); + this->configureUDQ(sumcfg, sched); } void Opm::out::Summary::SummaryImplementation:: @@ -2611,6 +2616,9 @@ eval(const EclipseState& es, for (auto& evalPtr : this->requiredRestartParameters_) { evalPtr->update(sim_step, duration, input, simRes, st); } + + for (auto& eval_ptr : this->udq_parameters) + eval_ptr->update(sim_step, duration, input, simRes, st); } void Opm::out::Summary::SummaryImplementation::write() @@ -2759,6 +2767,105 @@ configureSummaryInput(const EclipseState& es, reportUnsupportedKeywords(std::move(unsuppkw)); } + +/* + These nodes are added to the summary evaluation list because they are + requested by the UDQ system. In the case of well and group variables the code + will all nodes for all wells / groups - irrespective of what has been + requested in the UDQ code. +*/ + +std::vector make_default_nodes(const std::string& keyword, const Opm::Schedule& sched) { + auto nodes = std::vector {}; + auto category = Opm::parseKeywordCategory(keyword); + auto type = Opm::parseKeywordType(keyword); + + switch (category) { + case Opm::EclIO::SummaryNode::Category::Field: + { + Opm::EclIO::SummaryNode node; + node.keyword = keyword; + node.category = category; + node.type = type; + + nodes.push_back(node); + } + break; + case Opm::EclIO::SummaryNode::Category::Miscellaneous: + { + Opm::EclIO::SummaryNode node; + node.keyword = keyword; + node.category = category; + node.type = type; + + nodes.push_back(node); + } + break; + case Opm::EclIO::SummaryNode::Category::Well: + { + for (const auto& well : sched.wellNames()) { + Opm::EclIO::SummaryNode node; + node.keyword = keyword; + node.category = category; + node.type = type; + node.wgname = well; + + nodes.push_back(node); + } + } + break; + case Opm::EclIO::SummaryNode::Category::Group: + { + for (const auto& group : sched.groupNames()) { + Opm::EclIO::SummaryNode node; + node.keyword = keyword; + node.category = category; + node.type = type; + node.wgname = group; + + nodes.push_back(node); + } + } + break; + default: + throw std::logic_error(fmt::format("make_default_nodes does not yet support: {}", keyword)); + } + + return nodes; +} + + + +void Opm::out::Summary::SummaryImplementation::configureUDQ(const SummaryConfig& summary_config, const Schedule& sched) { + auto nodes = std::vector {}; + std::unordered_set summary_keys; + for (const auto& udq_ptr : sched.udqConfigList()) + udq_ptr->required_summary(summary_keys); + + for (const auto& key : summary_keys) { + const auto& default_nodes = make_default_nodes(key, sched); + for (const auto& def_node : default_nodes) + nodes.push_back(def_node); + } + + for (const auto& node: nodes) { + if (summary_config.hasSummaryKey(node.unique_key())) + // Handler already exists. Don't add second evaluation. + continue; + + auto fun_pos = funs.find(node.keyword); + if (fun_pos != funs.end()) + this->udq_parameters.push_back( std::make_unique(node, fun_pos->second) ); + else { + auto unit = single_values_units.find(node.keyword); + if (unit == single_values_units.end()) + throw std::logic_error(fmt::format("Evaluation function for: {} not found ", node.keyword)); + + this->udq_parameters.push_back( std::make_unique(node, unit->second)); + } + } +} + void Opm::out::Summary::SummaryImplementation:: configureRequiredRestartParameters(const SummaryConfig& sumcfg, @@ -2771,8 +2878,8 @@ configureRequiredRestartParameters(const SummaryConfig& sumcfg, return; auto fcnPos = funs.find(node.keyword); - assert ((fcnPos != funs.end()) && - "Internal error creating required restart vectors"); + if (fcnPos == funs.end()) + throw std::logic_error(fmt::format("Evaluation function for:{} not found", node.keyword)); auto eval = std::make_unique< Evaluator::FunctionRelation>(node, fcnPos->second); diff --git a/tests/msim/test_msim_ACTIONX.cpp b/tests/msim/test_msim_ACTIONX.cpp index 3f530708a..bee5bf27c 100644 --- a/tests/msim/test_msim_ACTIONX.cpp +++ b/tests/msim/test_msim_ACTIONX.cpp @@ -83,6 +83,12 @@ double prod_opr(const EclipseState& es, const Schedule& /* sched */, const Summ return -units.to_si(UnitSystem::measure::rate, oil_rate); } +double prod_gpr(const EclipseState& es, const Schedule& /* sched */, const SummaryState&, const data::Solution& /* sol */, size_t /* report_step */, double /* seconds_elapsed */) { + const auto& units = es.getUnits(); + double gas_rate = 20.0; + return -units.to_si(UnitSystem::measure::rate, gas_rate); +} + double prod_opr_low(const EclipseState& es, const Schedule& /* sched */, const SummaryState&, const data::Solution& /* sol */, size_t /* report_step */, double /* seconds_elapsed */) { const auto& units = es.getUnits(); double oil_rate = 0.5; @@ -357,6 +363,11 @@ BOOST_AUTO_TEST_CASE(UDQ_IN_ACTIONX) { sim.well_rate("P3", data::Rates::opt::wat, prod_wpr_P3); sim.well_rate("P4", data::Rates::opt::wat, prod_wpr_P4); + sim.well_rate("P1", data::Rates::opt::gas, prod_gpr); + sim.well_rate("P2", data::Rates::opt::gas, prod_gpr); + sim.well_rate("P3", data::Rates::opt::gas, prod_gpr); + sim.well_rate("P4", data::Rates::opt::gas, prod_gpr); + { const auto& w1 = td.schedule.getWell("P1", 15); BOOST_CHECK(w1.getStatus() == Well::Status::OPEN ); @@ -381,8 +392,15 @@ BOOST_AUTO_TEST_CASE(UDQ_IN_ACTIONX) { BOOST_CHECK(udq2.has_keyword("FUPROD")); BOOST_CHECK(udq2.has_keyword("FUNEW")); } - } + const auto& base_name = td.state.getIOConfig().getBaseName(); + const EclIO::ESmry ecl_sum(base_name + ".SMSPEC"); + BOOST_CHECK( !ecl_sum.hasKey("FLPR") ); + BOOST_CHECK( ecl_sum.hasKey("FUGPR") ); + + BOOST_CHECK( !ecl_sum.hasKey("FGLIR") ); + BOOST_CHECK( ecl_sum.hasKey("FUGPR") ); + } } BOOST_AUTO_TEST_CASE(UDA) { diff --git a/tests/msim/udq_in_actionx.include b/tests/msim/udq_in_actionx.include index f128086d6..df0d83984 100644 --- a/tests/msim/udq_in_actionx.include +++ b/tests/msim/udq_in_actionx.include @@ -330,9 +330,6 @@ WGIT 'INJ' / -WGPR -/ - WGPT / @@ -360,7 +357,8 @@ WUWCT FOPR FUOPR - +FUGPR +FU_VAR2 SCHEDULE -- ------------------------------------------------------------------------- @@ -382,6 +380,7 @@ UDQ UNITS WUWCT '1' / DEFINE FUOPR SUM(WOPR) / UNITS FUOPR 'SM3/DAY' / + DEFINE FUGPR FLPR / / @@ -473,6 +472,12 @@ DATES -- 3 1 'MAR' 2015 / / +UDQ + DEFINE FU_VAR2 FGLIR / +/ + + + DATES -- 4 1 'APR' 2015 / / @@ -481,6 +486,10 @@ DATES -- 5 1 'MAI' 2015 / / +UDQ + DEFINE FU_VAR3 WGPR P1 / +/ + DATES 1 'JUN' 2015 / /