From adab33ac60d0be53a6f19ef407aa6d7d14e0f594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Thu, 19 Jan 2023 13:20:52 +0100 Subject: [PATCH] Compute Segment Level UDQ Values This commit adds support for calculating UDQs at the segment level, i.e., UDQs named 'SU*'. This necessitates an API change for the UDQ context constructor and, transitively, every function that forms UDQ context objects. We pass a factory function that will create segment matcher objects on demand, and provide a default implementation of this factory function in the Schedule class. --- msim/src/msim.cpp | 7 +- opm/input/eclipse/Schedule/Schedule.hpp | 2 + opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp | 3 + opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp | 80 ++++- opm/input/eclipse/Schedule/UDQ/UDQContext.hpp | 43 ++- opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp | 1 + opm/input/eclipse/Schedule/UDQ/UDQSet.hpp | 5 + src/opm/input/eclipse/Schedule/Schedule.cpp | 15 + .../input/eclipse/Schedule/SummaryState.cpp | 8 + .../input/eclipse/Schedule/UDQ/UDQASTNode.cpp | 116 ++++++- .../input/eclipse/Schedule/UDQ/UDQConfig.cpp | 32 +- .../input/eclipse/Schedule/UDQ/UDQContext.cpp | 198 ++++++++--- .../input/eclipse/Schedule/UDQ/UDQDefine.cpp | 31 ++ src/opm/input/eclipse/Schedule/UDQ/UDQSet.cpp | 14 + tests/parser/UDQTests.cpp | 322 ++++++++++++++---- tests/test_AggregateUDQData.cpp | 246 +++++++------ tests/test_Restart.cpp | 169 +++++---- 17 files changed, 933 insertions(+), 359 deletions(-) diff --git a/msim/src/msim.cpp b/msim/src/msim.cpp index b2bb50cd4..dac66686c 100644 --- a/msim/src/msim.cpp +++ b/msim/src/msim.cpp @@ -128,7 +128,12 @@ void msim::run_step(WellTestState& wtest_state, UDQState& udq_state, data::Solut /* inplace = */ {}); this->schedule.getUDQConfig(report_step - 1) - .eval(report_step, this->schedule, schedule.wellMatcher(report_step), this->st, udq_state); + .eval(report_step, + this->schedule, + this->schedule.wellMatcher(report_step), + this->schedule.segmentMatcherFactory(report_step), + this->st, + udq_state); this->output(wtest_state, udq_state, diff --git a/opm/input/eclipse/Schedule/Schedule.hpp b/opm/input/eclipse/Schedule/Schedule.hpp index 42c01d56b..b2d14bd23 100644 --- a/opm/input/eclipse/Schedule/Schedule.hpp +++ b/opm/input/eclipse/Schedule/Schedule.hpp @@ -65,6 +65,7 @@ namespace Opm class Python; class RPTConfig; class SCHEDULESection; + class SegmentMatcher; struct SimulatorUpdate; class SummaryState; class TracerConfig; @@ -237,6 +238,7 @@ namespace Opm bool hasWell(const std::string& wellName, std::size_t timeStep) const; WellMatcher wellMatcher(std::size_t report_step) const; + std::function()> segmentMatcherFactory(std::size_t report_step) const; std::vector wellNames(const std::string& pattern, std::size_t timeStep, const std::vector& matching_wells = {}) const; std::vector wellNames(const std::string& pattern) const; std::vector wellNames(std::size_t timeStep) const; diff --git a/opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp b/opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp index e8f998aac..4f62a05f9 100644 --- a/opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp +++ b/opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp @@ -91,6 +91,9 @@ private: UDQSet eval_group_expression(const std::string& string_value, const UDQContext& context) const; + UDQSet eval_segment_expression(const std::string& string_value, + const UDQContext& context) const; + UDQSet eval_scalar_function(const UDQVarType target_type, const UDQContext& context) const; diff --git a/opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp b/opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp index ab579e438..d7770425f 100644 --- a/opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp +++ b/opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp @@ -31,7 +31,9 @@ #include #include +#include #include +#include #include #include #include @@ -42,6 +44,7 @@ namespace Opm { class DeckRecord; class KeywordLocation; class Schedule; + class SegmentMatcher; class SummaryState; class UDQState; class WellMatcher; @@ -57,6 +60,8 @@ namespace Opm { class UDQConfig { public: + using SegmentMatcherFactory = std::function()>; + UDQConfig() = default; explicit UDQConfig(const UDQParams& params); UDQConfig(const UDQParams& params, const RestartIO::RstState& rst_state); @@ -66,18 +71,51 @@ namespace Opm { 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 add_record(const DeckRecord& record, const KeywordLocation& location, std::size_t report_step); - void add_unit(const std::string& keyword, const std::string& unit); - void add_update(const std::string& keyword, std::size_t report_step, const KeywordLocation& location, const std::vector& data); - void add_assign(const std::string& quantity, const std::vector& selector, double value, std::size_t report_step); - void add_assign(const std::string& quantity, const std::unordered_set& selector, double value, std::size_t report_step); - void add_define(const std::string& quantity, const KeywordLocation& location, const std::vector& expression, std::size_t report_step); + void add_record(const DeckRecord& record, + const KeywordLocation& location, + std::size_t report_step); + + void add_unit(const std::string& keyword, + const std::string& unit); + + void add_update(const std::string& keyword, + std::size_t report_step, + const KeywordLocation& location, + const std::vector& data); + + void add_assign(const std::string& quantity, + const std::vector& selector, + double value, + std::size_t report_step); + + void add_assign(const std::string& quantity, + const std::unordered_set& selector, + double value, + std::size_t report_step); + + void add_define(const std::string& quantity, + const KeywordLocation& location, + const std::vector& expression, + std::size_t report_step); + + void eval_assign(std::size_t report_step, + const Schedule& sched, + const WellMatcher& wm, + SegmentMatcherFactory segment_matcher_factory, + SummaryState& st, + UDQState& udq_state) const; + + void eval(std::size_t report_step, + const Schedule& sched, + const WellMatcher& wm, + SegmentMatcherFactory segment_matcher_factory, + SummaryState& st, + UDQState& udq_state) const; - void eval_assign(std::size_t report_step, const Schedule& sched, const WellMatcher& wm, SummaryState& st, UDQState& udq_state) const; - void eval(std::size_t report_step, const Schedule& sched, const WellMatcher& wm, SummaryState& st, UDQState& udq_state) const; const UDQDefine& define(const std::string& key) const; const UDQAssign& assign(const std::string& key) const; + std::vector definitions() const; std::vector definitions(UDQVarType var_type) const; std::vector input() const; @@ -85,7 +123,7 @@ namespace Opm { // The size() method will return the number of active DEFINE and ASSIGN // statements; this will correspond to the length of the vector returned // from input(). - size_t size() const; + std::size_t size() const; UDQInput operator[](const std::string& keyword) const; UDQInput operator[](std::size_t insert_index) const; @@ -107,17 +145,26 @@ namespace Opm { serializer(units); serializer(input_index); serializer(type_count); - // The UDQFunction table is constant up to udq_params. - // So we can just construct a new instance here. - if (!serializer.isSerializing()) + + // The UDQFunction table is constant up to udq_params, so we can + // just construct a new instance here. + if (!serializer.isSerializing()) { udqft = UDQFunctionTable(udq_params); + } } private: void add_node(const std::string& quantity, UDQAction action); UDQAction action_type(const std::string& udq_key) const; - void eval_assign(std::size_t report_step, const Schedule& sched, UDQState& udq_state, UDQContext& context) const; - void eval_define(std::size_t report_step, UDQState& udq_state, UDQContext& context) const; + + void eval_assign(std::size_t report_step, + const Schedule& sched, + UDQState& udq_state, + UDQContext& context) const; + + void eval_define(std::size_t report_step, + UDQState& udq_state, + UDQContext& context) const; UDQParams udq_params; UDQFunctionTable udqft; @@ -137,8 +184,7 @@ namespace Opm { OrderedMap input_index; std::map type_count; }; -} +} // namespace Opm - -#endif +#endif // UDQINPUT_HPP_ diff --git a/opm/input/eclipse/Schedule/UDQ/UDQContext.hpp b/opm/input/eclipse/Schedule/UDQ/UDQContext.hpp index 9158d4d35..768d75395 100644 --- a/opm/input/eclipse/Schedule/UDQ/UDQContext.hpp +++ b/opm/input/eclipse/Schedule/UDQ/UDQContext.hpp @@ -17,49 +17,74 @@ along with OPM. If not, see . */ - #ifndef UDQ_CONTEXT_HPP #define UDQ_CONTEXT_HPP +#include +#include +#include #include #include #include #include - -#include - namespace Opm { + class SegmentMatcher; + class SegmentSet; class SummaryState; class UDQFunctionTable; class UDQSet; class UDQState; class WellMatcher; - class UDQContext { +} // namespace Opm + +namespace Opm { + + class UDQContext + { public: - UDQContext(const UDQFunctionTable& udqft, const WellMatcher& wm, SummaryState& summary_state, UDQState& udq_state); + using SegmentMatcherFactory = std::function()>; + + UDQContext(const UDQFunctionTable& udqft, + const WellMatcher& wm, + SegmentMatcherFactory segment_matcher_factory, + SummaryState& summary_state, + UDQState& udq_state); + std::optional get(const std::string& key) const; std::optional get_well_var(const std::string& well, const std::string& var) const; std::optional get_group_var(const std::string& group, const std::string& var) const; + std::optional get_segment_var(const std::string& well, const std::string& var, std::size_t segment) const; + void add(const std::string& key, double value); void update_assign(std::size_t report_step, const std::string& keyword, const UDQSet& udq_result); void update_define(std::size_t report_step, const std::string& keyword, const UDQSet& udq_result); + const UDQFunctionTable& function_table() const; + std::vector wells() const; std::vector wells(const std::string& pattern) const; std::vector groups() const; + SegmentSet segments() const; + SegmentSet segments(const std::vector& set_descriptor) const; + private: const UDQFunctionTable& udqft; const WellMatcher& well_matcher; + + SegmentMatcherFactory segment_matcher_factory; + mutable std::unique_ptr segment_matcher; SummaryState& summary_state; UDQState& udq_state; + //std::unordered_map udq_results; std::unordered_map values; + + void ensure_segment_matcher_exists() const; }; -} +} // namespace Opm - -#endif +#endif // UDQ_CONTEXT_HPP diff --git a/opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp b/opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp index 1b0c7b110..f3bde7273 100644 --- a/opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp +++ b/opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp @@ -116,6 +116,7 @@ private: UDQSet scatter_scalar_value(UDQSet&& res, const UDQContext& context) const; UDQSet scatter_scalar_well_value(const UDQContext& context, const std::optional& value) const; UDQSet scatter_scalar_group_value(const UDQContext& context, const std::optional& value) const; + UDQSet scatter_scalar_segment_value(const UDQContext& context, const std::optional& value) const; }; } // Namespace Opm diff --git a/opm/input/eclipse/Schedule/UDQ/UDQSet.hpp b/opm/input/eclipse/Schedule/UDQ/UDQSet.hpp index 6c445f7c9..ed250e4c3 100644 --- a/opm/input/eclipse/Schedule/UDQ/UDQSet.hpp +++ b/opm/input/eclipse/Schedule/UDQ/UDQSet.hpp @@ -304,6 +304,11 @@ public: /// this UDQ set. Non-finite value leaves the UDQ set element /// undefined. static UDQSet field(const std::string& name, double scalar_value); + static UDQSet segments(const std::string& name, + const std::vector& segments); + static UDQSet segments(const std::string& name, + const std::vector& segments, + const double scalar_value); /// Assign value to every element of the UDQ set /// diff --git a/src/opm/input/eclipse/Schedule/Schedule.cpp b/src/opm/input/eclipse/Schedule/Schedule.cpp index c35787a67..d69f55447 100644 --- a/src/opm/input/eclipse/Schedule/Schedule.cpp +++ b/src/opm/input/eclipse/Schedule/Schedule.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -1243,6 +1244,20 @@ File {} line {}.)", pattern, location.keyword, location.filename, location.linen return WellMatcher(sched_state->well_order.get(), sched_state->wlist_manager.get()); } + std::function()> + Schedule::segmentMatcherFactory(const std::size_t report_step) const + { + return { + [report_step, this]() -> std::unique_ptr + { + const auto ix = (report_step < this->snapshots.size()) + ? report_step + : this->snapshots.size() - 1; + + return std::make_unique(this->snapshots[ix]); + } + }; + } std::vector Schedule::wellNames(const std::string& pattern) const { return this->wellNames(pattern, this->size() - 1); diff --git a/src/opm/input/eclipse/Schedule/SummaryState.cpp b/src/opm/input/eclipse/Schedule/SummaryState.cpp index 6babc8ea1..5950c84c6 100644 --- a/src/opm/input/eclipse/Schedule/SummaryState.cpp +++ b/src/opm/input/eclipse/Schedule/SummaryState.cpp @@ -266,6 +266,14 @@ namespace Opm this->update_group_var(group, udq_set.name(), udq_value.value_or(undefined_value)); } } + else if (var_type == UDQVarType::SEGMENT_VAR) { + for (const auto& udq_value : udq_set) { + this->update_segment_var(udq_value.wgname(), + udq_set.name(), + udq_value.number(), + udq_value.value().value_or(undefined_value)); + } + } else { const auto& udq_var = udq_set[0].value(); this->update(udq_set.name(), udq_var.value_or(undefined_value)); diff --git a/src/opm/input/eclipse/Schedule/UDQ/UDQASTNode.cpp b/src/opm/input/eclipse/Schedule/UDQ/UDQASTNode.cpp index 361fb6267..8483d8808 100644 --- a/src/opm/input/eclipse/Schedule/UDQ/UDQASTNode.cpp +++ b/src/opm/input/eclipse/Schedule/UDQ/UDQASTNode.cpp @@ -19,9 +19,11 @@ #include +#include #include #include #include +#include #include #include @@ -34,25 +36,54 @@ namespace { -bool is_udq(const std::string& key) +bool is_udq_blacklist(const std::string& keyword) { - return (key.size() >= std::string::size_type{2}) - && (key[1] == 'U'); + static const auto udq_blacklistkw = std::unordered_set { + "SUMTHIN", "SUMMARY", "RUNSUM", + }; + + return udq_blacklistkw.find(keyword) != udq_blacklistkw.end(); +} + +bool is_udq(const std::string& keyword) +{ + // Does 'keyword' match one of the patterns + // AU*, BU*, CU*, FU*, GU*, RU*, SU*, or WU*? + using sz_t = std::string::size_type; + + return (keyword.size() > sz_t{1}) + && (keyword[1] == 'U') + && ! is_udq_blacklist(keyword) + && (keyword.find_first_of("WGFCRBSA") == sz_t{0}); } Opm::UDQVarType init_type(const Opm::UDQTokenType token_type) { - if (token_type == Opm::UDQTokenType::number) { - return Opm::UDQVarType::SCALAR; - } - - if (Opm::UDQ::scalarFunc(token_type)) { + if ((token_type == Opm::UDQTokenType::number) || + Opm::UDQ::scalarFunc(token_type)) + { return Opm::UDQVarType::SCALAR; } return Opm::UDQVarType::NONE; } +std::vector +make_segment_items(const Opm::SegmentSet& segSet) +{ + const auto numWells = segSet.numWells(); + + auto items = std::vector(numWells); + for (auto wellID = 0*numWells; wellID < numWells; ++wellID) { + auto segRange = segSet.segments(wellID); + + items[wellID].well = segRange.well(); + items[wellID].numbers.assign(segRange.begin(), segRange.end()); + } + + return items; +} + } // Anonymous namespace namespace Opm { @@ -132,7 +163,6 @@ UDQASTNode::UDQASTNode(const UDQTokenType type_arg, if ((this->var_type == UDQVarType::CONNECTION_VAR) || (this->var_type == UDQVarType::REGION_VAR) || - (this->var_type == UDQVarType::SEGMENT_VAR) || (this->var_type == UDQVarType::AQUIFER_VAR) || (this->var_type == UDQVarType::BLOCK_VAR)) { @@ -267,12 +297,13 @@ bool UDQASTNode::operator==(const UDQASTNode& data) const void UDQASTNode::required_summary(std::unordered_set& summary_keys) const { - if (this->type == UDQTokenType::ecl_expr) { - if (std::holds_alternative(this->value)) { - const auto& keyword = std::get(this->value); - if (!is_udq(keyword)) { - summary_keys.insert(keyword); - } + if ((this->type == UDQTokenType::ecl_expr) && + std::holds_alternative(this->value)) + { + if (const auto& keyword = std::get(this->value); + !is_udq(keyword)) + { + summary_keys.insert(keyword); } } @@ -299,6 +330,10 @@ UDQASTNode::eval_expression(const UDQContext& context) const return this->eval_group_expression(string_value, context); } + if (data_type == UDQVarType::SEGMENT_VAR) { + return this->eval_segment_expression(string_value, context); + } + if (data_type == UDQVarType::FIELD_VAR) { return UDQSet::scalar(string_value, context.get(string_value)); } @@ -376,6 +411,54 @@ UDQASTNode::eval_group_expression(const std::string& string_value, return res; } +UDQSet +UDQASTNode::eval_segment_expression(const std::string& string_value, + const UDQContext& context) const +{ + const auto all_msw_segments = make_segment_items(context.segments()); + if (this->selector.empty()) { + auto res = UDQSet::segments(string_value, all_msw_segments); + + auto index = std::size_t{0}; + for (const auto& ms_well : all_msw_segments) { + for (const auto& segment : ms_well.numbers) { + res.assign(index++, context.get_segment_var(ms_well.well, string_value, segment)); + } + } + + return res; + } + + const auto selected_segments = context.segments(this->selector); + if (selected_segments.empty()) { + // No matching segments. Could be because the 'selector' only + // applies to MS wells that are no yet online, or because the + // segments don't yet exist. + return UDQSet::empty(string_value); + } + else if (selected_segments.isScalar()) { + // Selector matches a single segment in a single MS well. + const auto segSet = selected_segments.segments(0); + const auto well = std::string { segSet.well() }; + return UDQSet::scalar(string_value, context.get_segment_var(well, string_value, *segSet.begin())); + } + + // If we get here, the selector matches at least one segment in at least + // one MS well. + auto res = UDQSet::segments(string_value, all_msw_segments); + + const auto numWells = selected_segments.numWells(); + for (auto wellID = 0*numWells; wellID < numWells; ++wellID) { + const auto segSet = selected_segments.segments(wellID); + const auto well = std::string { segSet.well() }; + for (const auto& segment : segSet) { + res.assign(well, segment, context.get_segment_var(well, string_value, segment)); + } + } + + return res; +} + UDQSet UDQASTNode::eval_scalar_function(const UDQVarType target_type, const UDQContext& context) const @@ -429,6 +512,9 @@ UDQASTNode::eval_number(const UDQVarType target_type, case UDQVarType::GROUP_VAR: return UDQSet::groups(dummy_name, context.groups(), numeric_value); + case UDQVarType::SEGMENT_VAR: + return UDQSet::segments(dummy_name, make_segment_items(context.segments()), numeric_value); + case UDQVarType::SCALAR: return UDQSet::scalar(dummy_name, numeric_value); diff --git a/src/opm/input/eclipse/Schedule/UDQ/UDQConfig.cpp b/src/opm/input/eclipse/Schedule/UDQ/UDQConfig.cpp index db3960efa..4b3e2d32d 100644 --- a/src/opm/input/eclipse/Schedule/UDQ/UDQConfig.cpp +++ b/src/opm/input/eclipse/Schedule/UDQ/UDQConfig.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -483,6 +484,7 @@ namespace Opm { select_var_type |= var_type_bit(UDQVarType::WELL_VAR); select_var_type |= var_type_bit(UDQVarType::GROUP_VAR); select_var_type |= var_type_bit(UDQVarType::FIELD_VAR); + select_var_type |= var_type_bit(UDQVarType::SEGMENT_VAR); for (const auto& [keyword, index] : this->input_index) { if (index.action != UDQAction::DEFINE) { @@ -508,24 +510,30 @@ namespace Opm { } } - void UDQConfig::eval(const std::size_t report_step, - const Schedule& sched, - const WellMatcher& wm, - SummaryState& st, - UDQState& udq_state) const + void UDQConfig::eval(const std::size_t report_step, + const Schedule& sched, + const WellMatcher& wm, + SegmentMatcherFactory segment_matcher_factory, + SummaryState& st, + UDQState& udq_state) const { - UDQContext context(this->function_table(), wm, st, udq_state); + UDQContext context { + this->function_table(), wm, std::move(segment_matcher_factory), st, udq_state + }; this->eval_assign(report_step, sched, udq_state, context); this->eval_define(report_step, udq_state, context); } - void UDQConfig::eval_assign(const std::size_t report_step, - const Schedule& sched, - const WellMatcher& wm, - SummaryState& st, - UDQState& udq_state) const + void UDQConfig::eval_assign(const std::size_t report_step, + const Schedule& sched, + const WellMatcher& wm, + SegmentMatcherFactory segment_matcher_factory, + SummaryState& st, + UDQState& udq_state) const { - UDQContext context(this->function_table(), wm, st, udq_state); + UDQContext context { + this->function_table(), wm, std::move(segment_matcher_factory), st, udq_state + }; this->eval_assign(report_step, sched, udq_state, context); } diff --git a/src/opm/input/eclipse/Schedule/UDQ/UDQContext.cpp b/src/opm/input/eclipse/Schedule/UDQ/UDQContext.cpp index 7a53b3dad..765fa194c 100644 --- a/src/opm/input/eclipse/Schedule/UDQ/UDQContext.cpp +++ b/src/opm/input/eclipse/Schedule/UDQ/UDQContext.cpp @@ -16,45 +16,58 @@ You should have received a copy of the GNU General Public License along with OPM. If not, see . */ -#include -#include #include + +#include +#include #include #include + #include -namespace Opm { +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include namespace { -bool is_udq(const std::string& key) { - if (key.size() < 2) - return false; - - if (key[1] != 'U') - return false; - - return true; +bool is_udq(const std::string& key) +{ + return (key.size() >= std::string::size_type{2}) + && (key[1] == 'U'); } -} +} // Anonymous namespace +namespace Opm { - UDQContext::UDQContext(const UDQFunctionTable& udqft_arg, const WellMatcher& wm, SummaryState& summary_state_arg, UDQState& udq_state_arg) : - udqft(udqft_arg), - well_matcher(wm), - summary_state(summary_state_arg), - udq_state(udq_state_arg) + UDQContext::UDQContext(const UDQFunctionTable& udqft_arg, + const WellMatcher& wm, + SegmentMatcherFactory segment_matcher_factory_arg, + SummaryState& summary_state_arg, + UDQState& udq_state_arg) + : udqft (udqft_arg) + , well_matcher (wm) + , segment_matcher_factory(std::move(segment_matcher_factory_arg)) + , summary_state (summary_state_arg) + , udq_state (udq_state_arg) { - for (const auto& pair : TimeService::eclipseMonthIndices()) - this->add(pair.first, pair.second); + for (const auto& [month, index] : TimeService::eclipseMonthIndices()) { + this->add(month, index); + } - /* - Simulator performance keywords which are expected to be available for - UDQ keywords; probably better to guarantee that they are present in - the underlying summary state object. - */ + // Simulator performance keywords which are expected to be available + // for UDQ keywords; probably better to guarantee that they are + // present in the underlying summary state object. this->add("MSUMLINS", 0.0); this->add("MSUMNEWT", 0.0); @@ -62,82 +75,169 @@ bool is_udq(const std::string& key) { this->add("TCPU", 0.0); } - - void UDQContext::add(const std::string& key, double value) { - this->values[key] = value; + void UDQContext::add(const std::string& key, double value) + { + this->values.insert_or_assign(key, value); } - std::optional UDQContext::get(const std::string& key) const { + std::optional + UDQContext::get(const std::string& key) const + { if (is_udq(key)) { - if (this->udq_state.has(key)) + if (this->udq_state.has(key)) { return this->udq_state.get(key); + } return std::nullopt; } - const auto& pair_ptr = this->values.find(key); - if (pair_ptr != this->values.end()) + auto pair_ptr = this->values.find(key); + if (pair_ptr != this->values.end()) { return pair_ptr->second; + } return this->summary_state.get(key); } - std::optional UDQContext::get_well_var(const std::string& well, const std::string& var) const { + std::optional + UDQContext::get_well_var(const std::string& well, + const std::string& var) const + { if (is_udq(var)) { - if (this->udq_state.has_well_var(well, var)) + if (this->udq_state.has_well_var(well, var)) { return this->udq_state.get_well_var(well, var); + } return std::nullopt; } + if (this->summary_state.has_well_var(var)) { - if (this->summary_state.has_well_var(well, var)) + if (this->summary_state.has_well_var(well, var)) { return this->summary_state.get_well_var(well, var); - else - return std::nullopt; + } + + return std::nullopt; } - throw std::logic_error(fmt::format("Summary well variable: {} not registered", var)); + + throw std::logic_error { + fmt::format("Summary well variable: {} not registered", var) + }; } - std::optional UDQContext::get_group_var(const std::string& group, const std::string& var) const { + std::optional + UDQContext::get_group_var(const std::string& group, + const std::string& var) const + { if (is_udq(var)) { - if (this->udq_state.has_group_var(group, var)) + if (this->udq_state.has_group_var(group, var)) { return this->udq_state.get_group_var(group, var); + } return std::nullopt; } if (this->summary_state.has_group_var(var)) { - if (this->summary_state.has_group_var(group, var)) + if (this->summary_state.has_group_var(group, var)) { return this->summary_state.get_group_var(group, var); - else - return std::nullopt; + } + + return std::nullopt; } - throw std::logic_error(fmt::format("Summary group variable: {} not registered", var)); + + throw std::logic_error { + fmt::format("Summary group variable: {} not registered", var) + }; } - std::vector UDQContext::wells() const { + std::optional + UDQContext::get_segment_var(const std::string& well, + const std::string& var, + std::size_t segment) const + { + if (is_udq(var)) { + if (this->udq_state.has_segment_var(well, var, segment)) { + return this->udq_state.get_segment_var(well, var, segment); + } + + return std::nullopt; + } + + if (this->summary_state.has_segment_var(well, var, segment)) { + return this->summary_state.get_segment_var(well, var, segment); + } + + throw std::logic_error { + fmt::format("Segment summary variable {} not " + "registered for segment {} in well {}", + var, segment, well) + }; + } + + std::vector UDQContext::wells() const + { return this->well_matcher.wells(); } - std::vector UDQContext::wells(const std::string& pattern) const { + std::vector UDQContext::wells(const std::string& pattern) const + { return this->well_matcher.wells(pattern); } - std::vector UDQContext::groups() const { + std::vector UDQContext::groups() const + { return this->summary_state.groups(); } - const UDQFunctionTable& UDQContext::function_table() const { + SegmentSet UDQContext::segments() const + { + // Empty descriptor matches all segments in all existing MS wells. + + this->ensure_segment_matcher_exists(); + return this->segment_matcher->findSegments(SegmentMatcher::SetDescriptor{}); + } + + SegmentSet UDQContext::segments(const std::vector& set_descriptor) const + { + assert (! set_descriptor.empty() && + "Internal error passing empty segment set " + "descriptor to filtered segment set query"); + + auto desc = SegmentMatcher::SetDescriptor{} + .wellNames(set_descriptor.front()); + + if (set_descriptor.size() > std::vector::size_type{1}) { + desc.segmentNumber(set_descriptor[1]); + } + + this->ensure_segment_matcher_exists(); + return this->segment_matcher->findSegments(desc); + } + + const UDQFunctionTable& UDQContext::function_table() const + { return this->udqft; } - void UDQContext::update_assign(std::size_t report_step, const std::string& keyword, const UDQSet& udq_result) { + void UDQContext::update_assign(const std::size_t report_step, + const std::string& keyword, + const UDQSet& udq_result) + { this->udq_state.add_assign(report_step, keyword, udq_result); this->summary_state.update_udq(udq_result, this->udq_state.undefined_value()); } - void UDQContext::update_define(std::size_t report_step, const std::string& keyword, const UDQSet& udq_result) { + void UDQContext::update_define(const std::size_t report_step, + const std::string& keyword, + const UDQSet& udq_result) + { this->udq_state.add_define(report_step, keyword, udq_result); this->summary_state.update_udq(udq_result, this->udq_state.undefined_value()); } + + void UDQContext::ensure_segment_matcher_exists() const + { + if (this->segment_matcher == nullptr) { + this->segment_matcher = this->segment_matcher_factory(); + } + } } diff --git a/src/opm/input/eclipse/Schedule/UDQ/UDQDefine.cpp b/src/opm/input/eclipse/Schedule/UDQ/UDQDefine.cpp index 01bc19e5e..c6d90b71b 100644 --- a/src/opm/input/eclipse/Schedule/UDQ/UDQDefine.cpp +++ b/src/opm/input/eclipse/Schedule/UDQ/UDQDefine.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -217,6 +218,22 @@ bool dynamic_type_check(const Opm::UDQVarType lhs, return true; } +std::vector +make_segment_items(const Opm::SegmentSet& segSet) +{ + const auto numWells = segSet.numWells(); + + auto items = std::vector(numWells); + for (auto wellID = 0*numWells; wellID < numWells; ++wellID) { + auto segRange = segSet.segments(wellID); + + items[wellID].well = segRange.well(); + items[wellID].numbers.assign(segRange.begin(), segRange.end()); + } + + return items; +} + } // Anonymous namespace namespace Opm { @@ -439,6 +456,10 @@ UDQSet UDQDefine::scatter_scalar_value(UDQSet&& res, const UDQContext& context) return this->scatter_scalar_group_value(context, res[0].value()); } + if (this->var_type() == UDQVarType::SEGMENT_VAR) { + return this->scatter_scalar_segment_value(context, res[0].value()); + } + return std::move(res); } @@ -462,4 +483,14 @@ UDQSet UDQDefine::scatter_scalar_group_value(const UDQContext& contex return UDQSet::groups(this->m_keyword, context.groups(), *value); } +UDQSet UDQDefine::scatter_scalar_segment_value(const UDQContext& context, + const std::optional& value) const +{ + if (! value.has_value()) { + return UDQSet::segments(this->m_keyword, make_segment_items(context.segments())); + } + + return UDQSet::segments(this->m_keyword, make_segment_items(context.segments()), *value); +} + } // namespace Opm diff --git a/src/opm/input/eclipse/Schedule/UDQ/UDQSet.cpp b/src/opm/input/eclipse/Schedule/UDQ/UDQSet.cpp index 455e29be9..56cf82e9c 100644 --- a/src/opm/input/eclipse/Schedule/UDQ/UDQSet.cpp +++ b/src/opm/input/eclipse/Schedule/UDQ/UDQSet.cpp @@ -270,6 +270,20 @@ UDQSet UDQSet::groups(const std::string& name, return us; } +UDQSet UDQSet::segments(const std::string& name, + const std::vector& segments) +{ + return { name, UDQVarType::SEGMENT_VAR, segments }; +} + +UDQSet UDQSet::segments(const std::string& name, + const std::vector& segments, + const double scalar_value) +{ + auto us = UDQSet::segments(name, segments); + us.assign(scalar_value); + return us; +} bool UDQSet::has(const std::string& name) const { diff --git a/tests/parser/UDQTests.cpp b/tests/parser/UDQTests.cpp index 19080f6a7..e412fa308 100644 --- a/tests/parser/UDQTests.cpp +++ b/tests/parser/UDQTests.cpp @@ -30,7 +30,10 @@ #include +#include +#include #include +#include #include #include #include @@ -42,6 +45,7 @@ #include #include #include +#include #include #include @@ -54,34 +58,126 @@ #include #include +#include #include #include #include #include #include #include +#include #include using namespace Opm; namespace { - Schedule make_schedule(const std::string& input) { - Parser parser; - auto python = std::make_shared(); - - auto deck = parser.parseString(input); + Schedule make_schedule(const std::string& input) + { + auto deck = Parser{}.parseString(input); if (deck.hasKeyword("DIMENS")) { EclipseState es(deck); - return Schedule(deck, es, python); - } else { + return { deck, es, std::make_shared() }; + } + else { EclipseGrid grid(10,10,10); - TableManager table ( deck ); - FieldPropsManager fp( deck, Phases{true, true, true}, grid, table); - Runspec runspec (deck); - return Schedule(deck, grid , fp, runspec, python); + TableManager table(deck); + FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); + Runspec runspec(deck); + + return { deck, grid, fp, runspec, std::make_shared() }; } } -} // namespace anonymous + + Opm::Segment makeSegment(const int segmentNumber) + { + return { segmentNumber, 1, 1, 1.0, 0.0, 0.5, 0.01, 0.25, 1.23, true, 0.0, 0.0 }; + } + + std::shared_ptr makeSegments(const int numSegments) + { + auto segments = std::vector{}; + segments.reserve(numSegments); + + for (auto segment = 0; segment < numSegments; ++segment) { + segments.push_back(makeSegment(segment + 1)); + } + + return std::make_shared + (Opm::WellSegments::CompPressureDrop::HFA, segments); + } + + Opm::Well makeProducerWell(const std::string& wname, + const std::size_t insert, + const int numSegments) + { + auto w = Opm::Well { + wname, "G", 0, insert, 1, 2, {}, + Opm::WellType { true, Opm::Phase::OIL }, // Oil producer + Opm::Well::ProducerCMode::ORAT, + Opm::Connection::Order::INPUT, + Opm::UnitSystem::newMETRIC(), + -3.0e+20, // UDQ undefined + 0.0, true, true, 0, + Opm::Well::GasInflowEquation::STD + }; + + if (numSegments > 0) { + w.updateSegments(makeSegments(numSegments)); + } + + return w; + } + + Opm::Well makeInjectionWell(const std::string& wname, + const std::size_t insert, + const int numSegments) + { + auto w = Opm::Well { + wname, "G", 0, insert, 1, 2, {}, + Opm::WellType { false, Opm::Phase::GAS }, // Gas injector + Opm::Well::ProducerCMode::ORAT, + Opm::Connection::Order::INPUT, + Opm::UnitSystem::newMETRIC(), + -3.0e+20, // UDQ undefined + 0.0, true, true, 0, + Opm::Well::GasInflowEquation::STD + }; + + if (numSegments > 0) { + w.updateSegments(makeSegments(numSegments)); + } + + return w; + } + + // Collection of wells + // OP-01: Producer, MSW, 20 segments (1 .. 20) + // OP-02: Producer, MSW, 5 segments (1 .. 5) + // OP-06: Producer, Standard well + // OPROD: Producer, MSW, 2 segments (1 .. 2) + // + // GI-01: Injector, MSW, 10 segments (1 .. 10) + // GI-08: Injector, Standard well + // I-45: Injector, MSW, 1 segment (1) + Opm::ScheduleState dynamicInputData() + { + auto block = Opm::ScheduleState { Opm::TimeService::now() }; + + block.wells.update(makeProducerWell("OP-01", 0, 20)); + block.wells.update(makeProducerWell("OP-02", 1, 5)); + block.wells.update(makeProducerWell("OP-06", 2, 0)); + block.wells.update(makeProducerWell("OPROD", 3, 2)); + block.wells.update(makeInjectionWell("GI-01", 4, 10)); + block.wells.update(makeInjectionWell("GI-08", 5, 0)); + block.wells.update(makeInjectionWell("I-45", 6, 1)); + + block.well_order.update(Opm::NameOrder { + "OP-01", "OP-02", "OP-06", "OPROD", "GI-01", "GI-08", "I-45", + }); + + return block; + } +} // Anonymous namespace BOOST_AUTO_TEST_CASE(TYPE_COERCION) { BOOST_CHECK( UDQVarType::SCALAR == UDQ::coerce(UDQVarType::SCALAR, UDQVarType::SCALAR) ); @@ -104,7 +200,8 @@ BOOST_AUTO_TEST_CASE(GROUP_VARIABLES) UDQDefine def_group(udqp, "GUOPRL", 0, location, {"(", "5000", "-", "GOPR", "LOWER", "*", "0.13", "-", "GOPR", "UPPER", "*", "0.15", ")" , "*", "0.89"}); SummaryState st(TimeService::now()); UDQState udq_state(udqp.undefinedValue()); - UDQContext context(udqft, {}, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, {}, segmentMatcherFactory, st, udq_state); double gopr_lower = 1234; double gopr_upper = 4321; @@ -120,7 +217,39 @@ BOOST_AUTO_TEST_CASE(GROUP_VARIABLES) BOOST_CHECK(!empty_value); } +BOOST_AUTO_TEST_CASE(SINGLE_SEGMENT_VARIABLES) +{ + const auto location = KeywordLocation{}; + const auto udqp = UDQParams{}; + const auto udqft = UDQFunctionTable{}; + const auto def_seg = UDQDefine { + udqp, "SU_OFR", 0, location, + { "(", "5000", "-", "SOFR", "'OP-*'", "3", "*", "0.13", ")" , "*", "0.89" } + }; + + auto st = SummaryState { TimeService::now() }; + auto udq_state = UDQState { udqp.undefinedValue() }; + + auto segmentMatcherFactory = [sched_state = dynamicInputData()]() + { + return std::make_unique(sched_state); + }; + + auto context = UDQContext { + udqft, {}, segmentMatcherFactory, st, udq_state + }; + + const auto sofr_p1_3 = 1234.0; + const auto sofr_p2_3 = 4321.0; + + st.update_segment_var("OP-01", "SOFR", 3, sofr_p1_3); + st.update_segment_var("OP-02", "SOFR", 3, sofr_p2_3); + + const auto res_seg = def_seg.eval(context); + BOOST_CHECK_EQUAL(res_seg("OP-01", 3).get(), (5000.0 - sofr_p1_3*0.13) * 0.89); + BOOST_CHECK_EQUAL(res_seg("OP-02", 3).get(), (5000.0 - sofr_p2_3*0.13) * 0.89); +} BOOST_AUTO_TEST_CASE(SUBTRACT) { @@ -133,7 +262,8 @@ BOOST_AUTO_TEST_CASE(SUBTRACT) SummaryState st(TimeService::now()); UDQState udq_state(udqp.undefinedValue()); WellMatcher wm(NameOrder({"P1"})); - UDQContext context(udqft, wm, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, wm, segmentMatcherFactory, st, udq_state); st.update_well_var("P1", "WOPR", 4); auto res = def.eval(context); @@ -156,7 +286,8 @@ BOOST_AUTO_TEST_CASE(TEST) SummaryState st(TimeService::now()); UDQState udq_state(udqp.undefinedValue()); WellMatcher wm(NameOrder({"P1", "P2"})); - UDQContext context(udqft, wm, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, wm, segmentMatcherFactory, st, udq_state); st.update_group_var("MAU", "GOPR", 4); st.update_group_var("XXX", "GOPR", 5); @@ -197,7 +328,8 @@ BOOST_AUTO_TEST_CASE(MIX_SCALAR) { SummaryState st(TimeService::now()); UDQState udq_state(udqp.undefinedValue()); WellMatcher wm(NameOrder({"P1"})); - UDQContext context(udqft, wm, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, wm, segmentMatcherFactory, st, udq_state); st.update_well_var("P1", "WOPR", 1); @@ -219,7 +351,8 @@ BOOST_AUTO_TEST_CASE(UDQFieldSetTest) { SummaryState st(TimeService::now()); UDQState udq_state(udqp.undefinedValue()); WellMatcher wm(NameOrder({"P1", "P2", "P3", "P4"})); - UDQContext context(udqft, wm, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, wm, segmentMatcherFactory, st, udq_state); st.update_well_var("P1", "WOPR", 1.0); st.update_well_var("P2", "WOPR", 2.0); @@ -321,7 +454,8 @@ BOOST_AUTO_TEST_CASE(UDQ_GROUP_TEST) { UDQDefine def_fopr(udqp, "FUOPR",0, location, {"SUM", "(", "GOPR", ")"}); SummaryState st(TimeService::now()); UDQState udq_state(udqp.undefinedValue()); - UDQContext context(udqft, {}, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, {}, segmentMatcherFactory, st, udq_state); st.update_group_var("G1", "GOPR", 1.0); st.update_group_var("G2", "GOPR", 2.0); @@ -343,7 +477,8 @@ BOOST_AUTO_TEST_CASE(UDQ_DEFINETEST) { SummaryState st(TimeService::now()); UDQState udq_state(udqp.undefinedValue()); WellMatcher wm(NameOrder({"W1", "W2", "W3"})); - UDQContext context(udqft, wm, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, wm, segmentMatcherFactory, st, udq_state); st.update_well_var("W1", "WBHP", 11); st.update_well_var("W2", "WBHP", 2); @@ -363,8 +498,8 @@ BOOST_AUTO_TEST_CASE(UDQ_DEFINETEST) { SummaryState st(TimeService::now()); UDQState udq_state(udqp.undefinedValue()); WellMatcher wm(NameOrder({"I1", "I2", "P1", "P2"})); - UDQContext context(udqft, wm, st, udq_state); - + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, wm, segmentMatcherFactory, st, udq_state); st.update_well_var("P1", "WBHP", 1); st.update_well_var("P2", "WBHP", 2); @@ -382,7 +517,8 @@ BOOST_AUTO_TEST_CASE(UDQ_DEFINETEST) { SummaryState st(TimeService::now()); UDQState udq_state(udqp.undefinedValue()); WellMatcher wm(NameOrder({"P1", "P2", "I1", "I2"})); - UDQContext context(udqft, wm, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, wm, segmentMatcherFactory, st, udq_state); st.update_well_var("P1", "WBHP", 4); st.update_well_var("P2", "WBHP", 3); st.update_well_var("I1", "WBHP", 2); @@ -579,15 +715,13 @@ ASSIGN WU2 8.0 / BOOST_CHECK_EQUAL( w2["P2"].get(), 8.0 ); } - - - BOOST_AUTO_TEST_CASE(UDQ_CONTEXT) { SummaryState st(TimeService::now()); UDQFunctionTable func_table; UDQParams udqp; UDQState udq_state(udqp.undefinedValue()); - UDQContext ctx(func_table, {}, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext ctx(func_table, {}, segmentMatcherFactory, st, udq_state); BOOST_CHECK_EQUAL(*ctx.get("JAN"), 1.0); BOOST_CHECK_THROW(ctx.get("NO_SUCH_KEY"), std::out_of_range); @@ -1044,7 +1178,8 @@ BOOST_AUTO_TEST_CASE(UDQ_POW_TEST) { UDQState udq_state(udqp.undefinedValue()); NameOrder wo; wo.add("P1"); WellMatcher wm(wo); - UDQContext context(udqft, wm, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, wm, segmentMatcherFactory, st, udq_state); st.update_well_var("P1", "WOPR", 1); st.update_well_var("P1", "WWPR", 2); @@ -1066,7 +1201,8 @@ BOOST_AUTO_TEST_CASE(UDQ_CMP_TEST) { SummaryState st(TimeService::now()); UDQState udq_state(udqp.undefinedValue()); WellMatcher wm(NameOrder({"P1", "P2"})); - UDQContext context(udqft, wm, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, wm, segmentMatcherFactory, st, udq_state); st.update_well_var("P1", "WOPR", 0); st.update_well_var("P1", "WWPR", 10); @@ -1097,7 +1233,8 @@ BOOST_AUTO_TEST_CASE(UDQ_SCALAR_SET) { SummaryState st(TimeService::now()); UDQState udq_state(udqp.undefinedValue()); WellMatcher wm(NameOrder({"PA1", "PB2", "PC3", "PD4"})); - UDQContext context(udqft, wm, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, wm, segmentMatcherFactory, st, udq_state); st.update_well_var("PA1", "WOPR", 1); st.update_well_var("PB2", "WOPR", 2); @@ -1168,7 +1305,8 @@ BOOST_AUTO_TEST_CASE(UDQ_SORTD_NAN) { SummaryState st(TimeService::now()); UDQState udq_state(udqp.undefinedValue()); WellMatcher wm(NameOrder({"OP1", "OP2", "OP3", "OP4"})); - UDQContext context(udqft, wm, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, wm, segmentMatcherFactory, st, udq_state); st.update_well_var("OP1", "WWIR", 1.0); st.update_well_var("OP2", "WWIR", 2.0); @@ -1213,7 +1351,8 @@ BOOST_AUTO_TEST_CASE(UDQ_SORTA) { SummaryState st(TimeService::now()); UDQState udq_state(udqp.undefinedValue()); WellMatcher wm(NameOrder({"OPL01", "OPL02", "OPU01", "OPU02"})); - UDQContext context(udqft, wm, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, wm, segmentMatcherFactory, st, udq_state); st.update_well_var("OPL01", "WWCT", 0.7); st.update_well_var("OPL02", "WWCT", 0.8); @@ -1242,7 +1381,8 @@ BOOST_AUTO_TEST_CASE(UDQ_BASIC_MATH_TEST) { SummaryState st(TimeService::now()); UDQState udq_state(udqp.undefinedValue()); WellMatcher wm(NameOrder({"P1", "P2", "P3", "P4"})); - UDQContext context(udqft, wm, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, wm, segmentMatcherFactory, st, udq_state); st.update_well_var("P1", "WOPR", 1); st.update_well_var("P2", "WOPR", 2); @@ -1305,7 +1445,8 @@ BOOST_AUTO_TEST_CASE(DECK_TEST) { SummaryState st(TimeService::now()); UDQState udq_state(udqp.undefinedValue()); WellMatcher wm(NameOrder({"OP1", "OP2", "OP3"})); - UDQContext context(udqft, wm, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, wm, segmentMatcherFactory, st, udq_state); st.update_well_var("OP1", "WOPR", 300); st.update_well_var("OP2", "WOPR", 3000); @@ -1360,7 +1501,8 @@ BOOST_AUTO_TEST_CASE(UDQ_PARSE_ERROR) { UDQFunctionTable udqft(udqp); UDQState udq_state(udqp.undefinedValue()); WellMatcher wm(NameOrder({"P1"})); - UDQContext context(udqft, wm, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, wm, segmentMatcherFactory, st, udq_state); st.update_well_var("P1", "WBHP", 1); auto res = def1.eval(context); @@ -1387,7 +1529,8 @@ BOOST_AUTO_TEST_CASE(UDQ_TYPE_ERROR) { UDQFunctionTable udqft(udqp); UDQState udq_state(udqp.undefinedValue()); WellMatcher wm(NameOrder({"P1", "P2"})); - UDQContext context(udqft, wm, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, wm, segmentMatcherFactory, st, udq_state); st.update_well_var("P1", "WBHP", 1); st.update_well_var("P2", "WBHP", 2); @@ -1843,7 +1986,8 @@ UDQ SummaryState st(TimeService::now()); UDQFunctionTable udqft(udqp); UDQState udq_state(udqp.undefinedValue()); - UDQContext context(udqft, {}, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, {}, segmentMatcherFactory, st, udq_state); auto res0 = def0.eval(context); BOOST_CHECK_CLOSE( res0[0].get(), -0.00125*3, 1e-6); @@ -1868,7 +2012,8 @@ UDQ SummaryState st(TimeService::now()); UDQFunctionTable udqft(udqp); UDQState udq_state(udqp.undefinedValue()); - UDQContext context(udqft, {}, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, {}, segmentMatcherFactory, st, udq_state); const double fwpr = 7; const double fopr = 4; const double fgpr = 7; @@ -1911,7 +2056,8 @@ UDQ UDQFunctionTable udqft(udqp); UDQState udq_state(udqp.undefinedValue()); WellMatcher wm(NameOrder({"W1", "W2", "W3"})); - UDQContext context(udqft, wm, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, wm, segmentMatcherFactory, st, udq_state); st.update_well_var("W1", "WOPR", 1); st.update_well_var("W2", "WOPR", 2); st.update_well_var("W3", "WOPR", 3); @@ -1949,7 +2095,8 @@ UDQ SummaryState st(TimeService::now()); auto undefined_value = udq.params().undefinedValue(); UDQState udq_state(undefined_value); - udq.eval(0, schedule, {}, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + udq.eval(0, schedule, {}, segmentMatcherFactory, st, udq_state); BOOST_CHECK_EQUAL( st.get("FU_UADD"), 12); // 10 + 2 @@ -1975,7 +2122,8 @@ DEFINE FU_PAR2 FU_PAR3 / auto undefined_value = udq.params().undefinedValue(); UDQState udq_state(undefined_value); st.update("FMWPR", 100); - udq.eval(0, schedule, {}, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + udq.eval(0, schedule, {}, segmentMatcherFactory, st, udq_state); BOOST_CHECK_EQUAL(st.get("FU_PAR2"), 100); } @@ -1993,7 +2141,8 @@ DEFINE FU_PAR3 FU_PAR2 + 1/ SummaryState st(TimeService::now()); auto undefined_value = udq.params().undefinedValue(); UDQState udq_state(undefined_value); - udq.eval(0, schedule, {}, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + udq.eval(0, schedule, {}, segmentMatcherFactory, st, udq_state); BOOST_CHECK_EQUAL(st.get("FU_PAR2"), undefined_value); BOOST_CHECK_EQUAL(st.get("FU_PAR3"), undefined_value); @@ -2103,19 +2252,32 @@ DEFINE WUGASRA 750000 - WGLIR '*' / NameOrder wo({"W1", "W2", "W3"}); WellMatcher wm(wo); - udq.eval(0, schedule, wm, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + udq.eval(0, schedule, wm, segmentMatcherFactory, st, udq_state); + + const auto required_keys = [&udq]() { - std::unordered_set required_keys; - udq.required_summary(required_keys); - BOOST_CHECK_EQUAL( required_keys.size(), 7); - BOOST_CHECK_EQUAL( required_keys.count("TIMESTEP"), 1); - BOOST_CHECK_EQUAL( required_keys.count("FMWPR"), 1); - BOOST_CHECK_EQUAL( required_keys.count("WGLIR"), 1); - BOOST_CHECK_EQUAL( required_keys.count("FOPR"), 1); - BOOST_CHECK_EQUAL( required_keys.count("FMWIN"), 1); - BOOST_CHECK_EQUAL( required_keys.count("FMWPA"), 1); - BOOST_CHECK_EQUAL( required_keys.count("FMWIA"), 1); - } + auto keys = std::unordered_set{}; + udq.required_summary(keys); + + auto required = std::vector{ keys.begin(), keys.end() }; + std::sort(required.begin(), required.end()); + + return required; + }(); + + const auto expected_keys = std::vector { + "FMWIA", + "FMWIN", + "FMWPA", + "FMWPR", + "FOPR", + "TIMESTEP", + "WGLIR", + }; + + BOOST_CHECK_EQUAL_COLLECTIONS(required_keys.begin(), required_keys.end(), + expected_keys.begin(), expected_keys.end()); } BOOST_AUTO_TEST_CASE(UDQ_UNDEFINED) { @@ -2307,7 +2469,8 @@ DEFINE FU_VAR91 GOPR TEST / st.update_well_var("W3", "WGLIR", 3); st.update_group_var("TEST", "GOPR", 1); - udq.eval(0, schedule, {}, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + udq.eval(0, schedule, {}, segmentMatcherFactory, st, udq_state); } BOOST_AUTO_TEST_CASE(UDQ_KEY_ERROR) { @@ -2326,7 +2489,8 @@ UDQ UDQState udq_state(undefined_value); SummaryState st(TimeService::now()); - BOOST_CHECK_THROW(udq.eval(0, schedule, {}, st, udq_state), std::exception); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + BOOST_CHECK_THROW(udq.eval(0, schedule, {}, segmentMatcherFactory, st, udq_state), std::exception); } BOOST_AUTO_TEST_CASE(UDQ_ASSIGN) { @@ -2345,13 +2509,25 @@ UDQ auto undefined_value = udq.params().undefinedValue(); UDQState udq_state(undefined_value); SummaryState st(TimeService::now()); - { - std::unordered_set required_keys; - udq.required_summary(required_keys); - BOOST_CHECK(required_keys.empty()); - } - udq.eval(0, schedule, {}, st, udq_state); + const auto required_keys = [&udq]() + { + auto keys = std::unordered_set{}; + udq.required_summary(keys); + + auto required = std::vector{ keys.begin(), keys.end() }; + std::sort(required.begin(), required.end()); + + return required; + }(); + + const auto expected_keys = std::vector {}; + + BOOST_CHECK_EQUAL_COLLECTIONS(required_keys.begin(), required_keys.end(), + expected_keys.begin(), expected_keys.end()); + + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + udq.eval(0, schedule, {}, segmentMatcherFactory, st, udq_state); BOOST_CHECK_EQUAL(st.get("FU_VAR1"), 10); } @@ -2392,7 +2568,8 @@ TSTEP // Counting: 1,2,3,4,5 for (std::size_t report_step = 0; report_step < 5; report_step++) { const auto& udq = schedule.getUDQConfig(report_step); - udq.eval(report_step, schedule, schedule.wellMatcher(report_step), st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + udq.eval(report_step, schedule, schedule.wellMatcher(report_step), segmentMatcherFactory, st, udq_state); auto fu_var1 = st.get("FU_VAR1"); BOOST_CHECK_EQUAL(fu_var1, report_step + 1); } @@ -2400,7 +2577,8 @@ TSTEP // Reset to zero and count: 1,2,3,4,5 for (std::size_t report_step = 5; report_step < 10; report_step++) { const auto& udq = schedule.getUDQConfig(report_step); - udq.eval(report_step, schedule, schedule.wellMatcher(report_step), st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + udq.eval(report_step, schedule, schedule.wellMatcher(report_step), segmentMatcherFactory, st, udq_state); auto fu_var1 = st.get("FU_VAR1"); BOOST_CHECK_EQUAL(fu_var1, report_step - 4); } @@ -2408,7 +2586,8 @@ TSTEP // Reset to zero and stay there. for (std::size_t report_step = 10; report_step < 15; report_step++) { const auto& udq = schedule.getUDQConfig(report_step); - udq.eval(report_step, schedule, schedule.wellMatcher(report_step),st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + udq.eval(report_step, schedule, schedule.wellMatcher(report_step), segmentMatcherFactory, st, udq_state); auto fu_var1 = st.get("FU_VAR1"); BOOST_CHECK_EQUAL(fu_var1, 0); } @@ -2432,7 +2611,8 @@ BOOST_AUTO_TEST_CASE(UDQ_DIV_TEST) { UDQDefine def_div(udqp, "FU",0, location, {"128", "/", "2", "/", "4", "/", "8"}); SummaryState st(TimeService::now()); UDQState udq_state(udqp.undefinedValue()); - UDQContext context(udqft, {}, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, {}, segmentMatcherFactory, st, udq_state); auto res_div = def_div.eval(context); BOOST_CHECK_EQUAL( res_div[0].get() , 2.0); @@ -2459,7 +2639,8 @@ UDQ SummaryState st(TimeService::now()); const auto& udq = schedule.getUDQConfig(0); - udq.eval(0, schedule, {}, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + udq.eval(0, schedule, {}, segmentMatcherFactory, st, udq_state); auto fu_var1 = st.get("FU_VAR1"); auto fu_var2 = st.get("FU_VAR2"); auto fu_var3 = st.get("FU_VAR3"); @@ -2504,7 +2685,8 @@ UDQ st.update_well_var("P3", "WOPR", 3); st.update_well_var("P4", "WOPR", 4); - udq.eval(0, schedule, schedule.wellMatcher(0), st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + udq.eval(0, schedule, schedule.wellMatcher(0), segmentMatcherFactory, st, udq_state); auto fu_var1 = st.get("FU_VAR1"); auto fu_var2 = st.get("FU_VAR2"); auto fu_var3 = st.get("FU_VAR3"); @@ -2530,7 +2712,8 @@ UDQ UDQState udq_state(0); SummaryState st(TimeService::now()); const auto& udq = schedule.getUDQConfig(0); - udq.eval(0, schedule, schedule.wellMatcher(0), st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + udq.eval(0, schedule, schedule.wellMatcher(0), segmentMatcherFactory, st, udq_state); auto fu_var1 = st.get("FU_VAR1"); auto fu_var2 = st.get("FU_VAR2"); @@ -2658,7 +2841,8 @@ UDQ SummaryState st(TimeService::now()); UDQFunctionTable udqft; WellMatcher wm(NameOrder({"W1", "W2", "W3"})); - UDQContext context(udqft, wm, st, udq_state); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState {}); }; + UDQContext context(udqft, wm, segmentMatcherFactory, st, udq_state); st.update_well_var("W1", "WBHP", 400); st.update_well_var("W2", "WBHP", 300); st.update_well_var("W3", "WBHP", 200); diff --git a/tests/test_AggregateUDQData.cpp b/tests/test_AggregateUDQData.cpp index 58f76a4de..543f3b453 100644 --- a/tests/test_AggregateUDQData.cpp +++ b/tests/test_AggregateUDQData.cpp @@ -2,97 +2,113 @@ #include +#include + +#include #include #include -#include -#include -#include -#include -#include -#include - -#include -#include - +#include #include #include -#include +#include + +#include + +#include +#include +#include +#include + +#include + #include -#include +#include +#include +#include +#include +#include #include #include -#include -#include -#include #include +#include +#include +#include +#include #include #include #include #include -#include -#include -#include -#include -#include -#include -#include +#include + +#include + +#include #include -#include -#include +#include #include -#include +#include +#include #include +#include #include #include "tests/WorkArea.hpp" namespace { - Opm::Deck first_sim(std::string fname) { + Opm::Deck first_sim(const std::string& fname) + { return Opm::Parser{}.parseFile(fname); } - /* - Opm::UDQActive udq_active() { - int update_count = 0; - // construct record data for udq_active - Opm::UDQParams params; - Opm::UDQConfig conf(params); - Opm::UDQActive udq_act; - Opm::UDAValue uda1("WUOPRL"); - update_count += udq_act.update(conf, uda1, "PROD1", Opm::UDAControl::WCONPROD_ORAT); - Opm::UDAValue uda2("WULPRL"); - update_count += udq_act.update(conf, uda2, "PROD1", Opm::UDAControl::WCONPROD_LRAT); - Opm::UDAValue uda3("WUOPRU"); - update_count += udq_act.update(conf, uda3, "PROD2", Opm::UDAControl::WCONPROD_ORAT); - Opm::UDAValue uda4("WULPRU"); - update_count += udq_act.update(conf, uda4, "PROD2", Opm::UDAControl::WCONPROD_LRAT); +#if 0 + Opm::UDQActive udq_active() + { + int update_count = 0; + // construct record data for udq_active + Opm::UDQParams params; + Opm::UDQConfig conf(params); + Opm::UDQActive udq_act; + Opm::UDAValue uda1("WUOPRL"); + update_count += udq_act.update(conf, uda1, "PROD1", Opm::UDAControl::WCONPROD_ORAT); - for (std::size_t index=0; index < udq_act.IUAD_size(); index++) - { - const auto & record = udq_act[index]; - auto ind = record.input_index; - auto udq_key = record.udq; - auto name = record.wgname; - auto ctrl_type = record.control; - } - return udq_act; + Opm::UDAValue uda2("WULPRL"); + update_count += udq_act.update(conf, uda2, "PROD1", Opm::UDAControl::WCONPROD_LRAT); + Opm::UDAValue uda3("WUOPRU"); + update_count += udq_act.update(conf, uda3, "PROD2", Opm::UDAControl::WCONPROD_ORAT); + Opm::UDAValue uda4("WULPRU"); + update_count += udq_act.update(conf, uda4, "PROD2", Opm::UDAControl::WCONPROD_LRAT); + + for (std::size_t index = 0; index < udq_act.IUAD_size(); ++index) { + const auto & record = udq_act[index]; + auto ind = record.input_index; + auto udq_key = record.udq; + auto name = record.wgname; + auto ctrl_type = record.control; + } + + return udq_act; } - */ -} +#endif + Opm::UDQSet + make_udq_set(const std::string& name, + const Opm::UDQVarType var_type, + const std::vector& wgnames, + const std::vector& values) + { + Opm::UDQSet s(name, var_type, wgnames); -Opm::UDQSet make_udq_set(const std::string& name, Opm::UDQVarType var_type, const std::vector& wgnames, const std::vector& values) { - Opm::UDQSet s(name, var_type, wgnames); - for (std::size_t i=0; i < values.size(); i++) - s.assign(i , values[i]); + for (std::size_t i = 0; i < values.size(); ++i) { + s.assign(i, values[i]); + } - return s; -} + return s; + } Opm::UDQState make_udq_state() { @@ -170,38 +186,42 @@ Opm::UDQSet make_udq_set(const std::string& name, Opm::UDQVarType var_type, cons return state; } + struct SimulationCase + { + explicit SimulationCase(const Opm::Deck& deck) + : es { deck } + , grid { deck } + , sched{ deck, es, std::make_shared() } + {} -//int main(int argc, char* argv[]) -struct SimulationCase -{ - explicit SimulationCase(const Opm::Deck& deck) - : es { deck } - , grid { deck } - , python { std::make_shared()} - , sched{ deck, es, python } - {} + // Order requirement: 'es' must be declared/initialised before 'sched'. + Opm::EclipseState es; + Opm::EclipseGrid grid; + Opm::Schedule sched; + Opm::Parser parser; + }; - // Order requirement: 'es' must be declared/initialised before 'sched'. - Opm::EclipseState es; - Opm::EclipseGrid grid; - std::shared_ptr python; - Opm::Schedule sched; - Opm::Parser parser; -}; + bool udq_contains(const std::vector& records, + const Opm::UDAControl control, + const std::string& udq, + const std::string& wgname) + { + auto find_iter = std::find_if(records.begin(), records.end(), + [&control, &udq, &wgname](const Opm::UDQActive::RstRecord& record) + { + return (record.control == control) + && (record.wgname == wgname) + && (record.value.get() == udq); + }); -BOOST_AUTO_TEST_SUITE(Aggregate_UDQ) + return find_iter != records.end(); + } -bool udq_contains(const std::vector& records, Opm::UDAControl control, const std::string& udq, const std::string wgname) { - auto find_iter = std::find_if(records.begin(), - records.end(), - [&control, &udq, &wgname] (const Opm::UDQActive::RstRecord& record) { - return record.control == control && - record.wgname == wgname && - record.value.get() == udq; - }); - return find_iter != records.end(); } +// --------------------------------------------------------------------------- + +BOOST_AUTO_TEST_SUITE(Aggregate_UDQ) // test constructed UDQ restart data BOOST_AUTO_TEST_CASE (Declared_UDQ_data) @@ -219,11 +239,10 @@ BOOST_AUTO_TEST_CASE (Declared_UDQ_data) // Report Step 1: 2008-10-10 --> 2011-01-20 const auto rptStep = std::size_t{1}; - double secs_elapsed = 3.1536E07; const auto ih = Opm::RestartIO::Helpers:: createInteHead(es, grid, sched, secs_elapsed, - rptStep, rptStep, rptStep-1); + rptStep, rptStep, rptStep - 1); //set dummy value for next_step_size const double next_step_size= 0.1; @@ -234,10 +253,11 @@ BOOST_AUTO_TEST_CASE (Declared_UDQ_data) const auto udqDims = Opm::RestartIO::Helpers::createUdqDims(sched, rptStep-1, ih); auto udqData = Opm::RestartIO::Helpers::AggregateUDQData(udqDims); - udqData.captureDeclaredUDQData(sched, rptStep-1, udq_state, ih); + udqData.captureDeclaredUDQData(sched, rptStep - 1, udq_state, ih); { WorkArea work; + { std::string outputDir = "./"; std::string baseName = "TEST_UDQRST"; @@ -309,7 +329,6 @@ BOOST_AUTO_TEST_CASE (Declared_UDQ_data) BOOST_CHECK_EQUAL(dh[214], 1.0E-4); } - { /* IUDQ @@ -731,7 +750,6 @@ BOOST_AUTO_TEST_CASE (Declared_UDQ_data) BOOST_CHECK_EQUAL(zUdn[start + 1].c_str(), "SM3/DAY "); // udq NO. 6 } - { /* ZUDL: @@ -772,7 +790,6 @@ BOOST_AUTO_TEST_CASE (Declared_UDQ_data) BOOST_CHECK_EQUAL(zUdl[start + 3].c_str(), " "); // udq NO. 1 } - { /* 'DUDW ' 24 'DOUB' @@ -816,7 +833,6 @@ BOOST_AUTO_TEST_CASE (Declared_UDQ_data) BOOST_CHECK_EQUAL(dUdg[start + 4], -0.3E+21); // duDg NO. 1 } - { /* 'DUDG ' 1 'DOUB' @@ -841,12 +857,14 @@ BOOST_AUTO_TEST_CASE (Declared_UDQ_data) BOOST_CHECK_EQUAL(rst_state.header.num_udq(), 44); BOOST_CHECK_EQUAL(rst_state.udqs.size(), 44); - std::vector> expected = {{"WUOPRL", "SM3/DAY"}, - {"WULPRL", "SM3/DAY"}, - {"WUOPRU", "SM3/DAY"}, - {"GUOPRU", "SM3/DAY"}, - {"WULPRU", "SM3/DAY"}, - {"FULPR", "SM3/DAY"}}; + const auto expected = std::vector> { + {"WUOPRL", "SM3/DAY"}, + {"WULPRL", "SM3/DAY"}, + {"WUOPRU", "SM3/DAY"}, + {"GUOPRU", "SM3/DAY"}, + {"WULPRU", "SM3/DAY"}, + {"FULPR" , "SM3/DAY"}, + }; std::size_t iudq = 0; for (const auto& [name, unit] : expected) { @@ -855,7 +873,6 @@ BOOST_AUTO_TEST_CASE (Declared_UDQ_data) iudq += 1; } - const std::size_t report_step = 1; const auto& udq_params = es.runspec().udqParams(); const auto& input_config = sched[report_step].udq(); @@ -863,12 +880,20 @@ BOOST_AUTO_TEST_CASE (Declared_UDQ_data) BOOST_CHECK_EQUAL(input_config.size(), rst_config.size()); BOOST_CHECK_EQUAL(input_config.definitions().size(), rst_config.definitions().size()); - const std::vector& wells = {"PROD1", "PROD2", "WINJ1", "WINJ2"}; + const auto wells = std::vector { + "PROD1", "PROD2", "WINJ1", "WINJ2", + }; Opm::UDQState rst_udq_state(udq_params.undefinedValue()); Opm::UDQFunctionTable udqft(udq_params); auto wm = Opm::WellMatcher(wells); - Opm::UDQContext input_context(udqft, wm, st, udq_state); - Opm::UDQContext rst_context(udqft, wm, st, rst_udq_state); + + auto segmentMatcherFactory = []() + { + return std::make_unique(Opm::ScheduleState{}); + }; + + Opm::UDQContext input_context(udqft, wm, segmentMatcherFactory, st, udq_state); + Opm::UDQContext rst_context(udqft, wm, segmentMatcherFactory, st, rst_udq_state); rst_udq_state.load_rst(rst_state); for (const auto& input_def : input_config.definitions()) { @@ -888,9 +913,10 @@ BOOST_AUTO_TEST_CASE (Declared_UDQ_data) BOOST_CHECK(input_eval == rst_eval); } - - const auto& uda_records = Opm::UDQActive::load_rst( - es.getUnits(), input_config, rst_state, sched.wellNames(report_step), sched.groupNames(report_step)); + const auto uda_records = + Opm::UDQActive::load_rst(es.getUnits(), input_config, rst_state, + sched.wellNames(report_step), + sched.groupNames(report_step)); BOOST_CHECK_EQUAL(uda_records.size(), 4); BOOST_CHECK(udq_contains(uda_records, Opm::UDAControl::WCONPROD_ORAT, "WUOPRU", "PROD1")); @@ -916,7 +942,6 @@ BOOST_AUTO_TEST_CASE (Declared_UDQ_data_2) auto rptStep = std::size_t{1}; auto simStep = rptStep - 1; - double secs_elapsed = 3.1536E07; auto ih = Opm::RestartIO::Helpers:: createInteHead(es, grid, sched, secs_elapsed, @@ -925,15 +950,14 @@ BOOST_AUTO_TEST_CASE (Declared_UDQ_data_2) //set dummy value for next_step_size double next_step_size= 0.1; auto dh = Opm::RestartIO::Helpers::createDoubHead(es, sched, simStep, simStep+1, - secs_elapsed, next_step_size); + secs_elapsed, next_step_size); auto lh = Opm::RestartIO::Helpers::createLogiHead(es); auto udqDims = Opm::RestartIO::Helpers::createUdqDims(sched, simStep, ih); - auto udqData = Opm::RestartIO::Helpers::AggregateUDQData(udqDims); + auto udqData = Opm::RestartIO::Helpers::AggregateUDQData(udqDims); udqData.captureDeclaredUDQData(sched, simStep, udq_state, ih); - { const auto& iGph = udqData.getIGPH(); @@ -952,7 +976,7 @@ BOOST_AUTO_TEST_CASE (Declared_UDQ_data_2) //set dummy value for next_step_size next_step_size= 0.1; dh = Opm::RestartIO::Helpers::createDoubHead(es, sched, simStep, simStep+1, - secs_elapsed, next_step_size); + secs_elapsed, next_step_size); lh = Opm::RestartIO::Helpers::createLogiHead(es); @@ -960,14 +984,12 @@ BOOST_AUTO_TEST_CASE (Declared_UDQ_data_2) udqData = Opm::RestartIO::Helpers::AggregateUDQData(udqDims); udqData.captureDeclaredUDQData(sched, simStep, udq_state, ih); - { const auto& iGph = udqData.getIGPH(); auto start = 0*udqDims[1]; BOOST_CHECK_EQUAL(iGph[start + 0] , 2); // (2 - water injection) } - } -BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() // Aggregate_UDQ diff --git a/tests/test_Restart.cpp b/tests/test_Restart.cpp index 329aad590..39b367340 100644 --- a/tests/test_Restart.cpp +++ b/tests/test_Restart.cpp @@ -22,26 +22,31 @@ #define BOOST_TEST_MODULE EclipseIO #include +#include +#include +#include #include #include #include #include -#include -#include -#include -#include + +#include +#include +#include #include -#include -#include #include #include -#include #include -#include -#include -#include +#include + +#include + #include +#include +#include +#include +#include #include #include #include @@ -49,16 +54,17 @@ #include #include #include +#include -#include -#include -#include +#include + +#include + +#include #include #include -#include - #include using namespace Opm; @@ -95,16 +101,14 @@ namespace { { return std::get<1>(vec); } -} +} // Anonymous namespace namespace Opm { namespace data { -/* - * Some test specific equivalence definitions and pretty-printing. Not fit as a - * general purpose implementation, but does its job for testing and - * pretty-pringing for debugging purposes. - */ +// Some test specific equivalence definitions and pretty-printing. Not fit +// as a general purpose implementation, but does its job for testing and +// pretty-pringing for debugging purposes. std::ostream& operator<<( std::ostream& stream, const Rates& r ) { return stream << "{ " @@ -141,7 +145,9 @@ std::ostream& operator<<( std::ostream& stream, return stream; } -} +} // namespace data + +namespace { data::GroupAndNetworkValues mkGroups() { return {}; @@ -382,49 +388,54 @@ Opm::SummaryState sim_state(const Opm::Schedule& sched) return state; } -struct Setup { +struct Setup +{ Deck deck; EclipseState es; const EclipseGrid& grid; - std::shared_ptr python; Schedule schedule; SummaryConfig summary_config; - Setup( const char* path) : - deck( Parser().parseFile( path) ), - es( deck), - grid( es.getInputGrid( ) ), - python( std::make_shared() ), - schedule( deck, es, python ), - summary_config( deck, schedule, es.fieldProps(), es.aquifer() ) + Setup(const char* path) + : deck ( Parser().parseFile( path) ) + , es ( deck) + , grid ( es.getInputGrid( ) ) + , schedule ( deck, es, std::make_shared() ) + , summary_config( deck, schedule, es.fieldProps(), es.aquifer() ) { auto& io_config = es.getIOConfig(); io_config.setEclCompatibleRST(false); } - }; - - -RestartValue first_sim(const Setup& setup, Action::State& action_state, SummaryState& st, UDQState& udq_state, bool write_double) { +RestartValue +first_sim(const Setup& setup, + Action::State& action_state, + SummaryState& st, + UDQState& udq_state, + bool write_double) +{ WellTestState wtest_state; EclipseIO eclWriter( setup.es, setup.grid, setup.schedule, setup.summary_config); - auto num_cells = setup.grid.getNumActive( ); - int report_step = 1; - auto start_time = setup.schedule.getStartTime(); - auto first_step = setup.schedule.simTime(report_step); - auto sol = mkSolution( num_cells ); - auto wells = mkWells(); - auto groups = mkGroups(); + const auto num_cells = setup.grid.getNumActive( ); + const int report_step = 1; + const auto start_time = setup.schedule.getStartTime(); + const auto first_step = setup.schedule.simTime(report_step); + + const auto sol = mkSolution(num_cells); + const auto wells = mkWells(); + const auto groups = mkGroups(); const auto& udq = setup.schedule.getUDQConfig(report_step); - RestartValue restart_value(sol, wells, groups, {}); + auto segmentMatcherFactory = []() { return std::make_unique(ScheduleState{}); }; udq.eval(report_step, setup.schedule, setup.schedule.wellMatcher(report_step), + segmentMatcherFactory, st, udq_state); + RestartValue restart_value(sol, wells, groups, {}); eclWriter.writeTimeStep( action_state, wtest_state, st, @@ -438,32 +449,39 @@ RestartValue first_sim(const Setup& setup, Action::State& action_state, SummaryS return restart_value; } -RestartValue second_sim(const Setup& setup, Action::State& action_state, SummaryState& summary_state, const std::vector& solution_keys) { +RestartValue +second_sim(const Setup& setup, + Action::State& action_state, + SummaryState& summary_state, + const std::vector& solution_keys) +{ EclipseIO writer(setup.es, setup.grid, setup.schedule, setup.summary_config); return writer.loadRestart( action_state, summary_state, solution_keys ); } -void compare( const RestartValue& fst, - const RestartValue& snd, - const std::vector& solution_keys) { - +void compare(const RestartValue& fst, + const RestartValue& snd, + const std::vector& solution_keys) +{ for (const auto& value : solution_keys) { - double tol = 0.00001; - const std::string& key = value.key; - auto first = fst.solution.data( key ).begin(); - auto second = snd.solution.data( key ).begin(); + auto tol = 0.00001; + const auto& key = value.key; - if (key == "TEMP") - tol *= 10; + if (key == "TEMP") { + tol *= 10.0; + } - for( ; first != fst.solution.data( key).end(); ++first, ++second ) - BOOST_CHECK_CLOSE( *first, *second, tol ); + auto first = fst.solution.data(key).begin(); + auto second = snd.solution.data(key).begin(); + + for (; first != fst.solution.data( key).end(); ++first, ++second) { + BOOST_CHECK_CLOSE(*first, *second, tol); + } } } - - +} // Anonymous namespace BOOST_AUTO_TEST_CASE(EclipseReadWriteWellStateData) { std::vector keys {{"PRESSURE" , UnitSystem::measure::pressure}, @@ -488,7 +506,6 @@ BOOST_AUTO_TEST_CASE(EclipseReadWriteWellStateData) { BOOST_CHECK_THROW( second_sim( restart_setup, action_state, st, {{"SOIL", UnitSystem::measure::pressure, true}}) , std::runtime_error ); } - BOOST_AUTO_TEST_CASE(ECL_FORMATTED) { namespace OS = ::Opm::EclIO::OutputStream; @@ -583,24 +600,25 @@ BOOST_AUTO_TEST_CASE(ECL_FORMATTED) { } } +namespace { - - - -void compare_equal( const RestartValue& fst, - const RestartValue& snd , - const std::vector& keys) { - +void compare_equal(const RestartValue& fst, + const RestartValue& snd, + const std::vector& keys) +{ for (const auto& value : keys) { const std::string& key = value.key; auto first = fst.solution.data( key ).begin(); auto second = snd.solution.data( key ).begin(); - for( ; first != fst.solution.data( key ).end(); ++first, ++second ) - BOOST_CHECK_EQUAL( *first, *second); + for (; first != fst.solution.data(key).end(); ++first, ++second) { + BOOST_CHECK_EQUAL(*first, *second); + } } } +} // Anonymous namespace + BOOST_AUTO_TEST_CASE(EclipseReadWriteWellStateData_double) { /* Observe that the purpose of this test is to verify that with @@ -628,7 +646,6 @@ BOOST_AUTO_TEST_CASE(EclipseReadWriteWellStateData_double) { compare_equal( state1 , state2 , solution_keys); } - BOOST_AUTO_TEST_CASE(WriteWrongSOlutionSize) { namespace OS = ::Opm::EclIO::OutputStream; @@ -668,7 +685,6 @@ BOOST_AUTO_TEST_CASE(WriteWrongSOlutionSize) { } } - BOOST_AUTO_TEST_CASE(ExtraData_KEYS) { Setup setup("BASE_SIM.DATA"); auto num_cells = setup.grid.getNumActive( ); @@ -776,7 +792,6 @@ BOOST_AUTO_TEST_CASE(ExtraData_content) { } } - BOOST_AUTO_TEST_CASE(STORE_THPRES) { namespace OS = ::Opm::EclIO::OutputStream; @@ -886,8 +901,6 @@ BOOST_AUTO_TEST_CASE(STORE_THPRES) { } } - - BOOST_AUTO_TEST_CASE(Restore_Cumulatives) { WorkArea wa{"test_Restart"}; @@ -1046,7 +1059,10 @@ BOOST_AUTO_TEST_CASE(Restore_Cumulatives) BOOST_CHECK_CLOSE(rstSumState.get("FGITH"), 90123.45, 1.0e-10); } -void init_st(SummaryState& st) { +namespace { + +void init_st(SummaryState& st) +{ st.update_well_var("PROD1", "WOPR", 100); st.update_well_var("PROD1", "WLPR", 100); st.update_well_var("PROD2", "WOPR", 100); @@ -1062,6 +1078,8 @@ void init_st(SummaryState& st) { st.update("FLPR", 100); } +} // Anonymous namespace + BOOST_AUTO_TEST_CASE(UDQ_RESTART) { std::vector keys {{"PRESSURE" , UnitSystem::measure::pressure}, {"SWAT" , UnitSystem::measure::identity}, @@ -1134,7 +1152,8 @@ BOOST_AUTO_TEST_CASE(UDQ_RESTART) { BOOST_CHECK_EQUAL(st1.get(kw), st2.get(kw)); } } -} + +} // namespace Opm namespace {