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.
This commit is contained in:
parent
a8d3dff2a4
commit
adab33ac60
@ -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,
|
||||
|
@ -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<std::unique_ptr<SegmentMatcher>()> segmentMatcherFactory(std::size_t report_step) const;
|
||||
std::vector<std::string> wellNames(const std::string& pattern, std::size_t timeStep, const std::vector<std::string>& matching_wells = {}) const;
|
||||
std::vector<std::string> wellNames(const std::string& pattern) const;
|
||||
std::vector<std::string> wellNames(std::size_t timeStep) const;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -31,7 +31,9 @@
|
||||
#include <opm/input/eclipse/EclipseState/Util/IOrderSet.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
@ -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<std::unique_ptr<SegmentMatcher>()>;
|
||||
|
||||
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<std::string>& data);
|
||||
void add_assign(const std::string& quantity, const std::vector<std::string>& selector, double value, std::size_t report_step);
|
||||
void add_assign(const std::string& quantity, const std::unordered_set<std::string>& selector, double value, std::size_t report_step);
|
||||
void add_define(const std::string& quantity, const KeywordLocation& location, const std::vector<std::string>& 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<std::string>& data);
|
||||
|
||||
void add_assign(const std::string& quantity,
|
||||
const std::vector<std::string>& selector,
|
||||
double value,
|
||||
std::size_t report_step);
|
||||
|
||||
void add_assign(const std::string& quantity,
|
||||
const std::unordered_set<std::string>& selector,
|
||||
double value,
|
||||
std::size_t report_step);
|
||||
|
||||
void add_define(const std::string& quantity,
|
||||
const KeywordLocation& location,
|
||||
const std::vector<std::string>& 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<UDQDefine> definitions() const;
|
||||
std::vector<UDQDefine> definitions(UDQVarType var_type) const;
|
||||
std::vector<UDQInput> 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<UDQIndex> input_index;
|
||||
std::map<UDQVarType, std::size_t> type_count;
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
|
||||
#endif
|
||||
#endif // UDQINPUT_HPP_
|
||||
|
@ -17,49 +17,74 @@
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UDQ_CONTEXT_HPP
|
||||
#define UDQ_CONTEXT_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQParams.hpp>
|
||||
|
||||
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<std::unique_ptr<SegmentMatcher>()>;
|
||||
|
||||
UDQContext(const UDQFunctionTable& udqft,
|
||||
const WellMatcher& wm,
|
||||
SegmentMatcherFactory segment_matcher_factory,
|
||||
SummaryState& summary_state,
|
||||
UDQState& udq_state);
|
||||
|
||||
std::optional<double> get(const std::string& key) const;
|
||||
std::optional<double> get_well_var(const std::string& well, const std::string& var) const;
|
||||
std::optional<double> get_group_var(const std::string& group, const std::string& var) const;
|
||||
std::optional<double> 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<std::string> wells() const;
|
||||
std::vector<std::string> wells(const std::string& pattern) const;
|
||||
std::vector<std::string> groups() const;
|
||||
SegmentSet segments() const;
|
||||
SegmentSet segments(const std::vector<std::string>& set_descriptor) const;
|
||||
|
||||
private:
|
||||
const UDQFunctionTable& udqft;
|
||||
const WellMatcher& well_matcher;
|
||||
|
||||
SegmentMatcherFactory segment_matcher_factory;
|
||||
mutable std::unique_ptr<SegmentMatcher> segment_matcher;
|
||||
SummaryState& summary_state;
|
||||
UDQState& udq_state;
|
||||
|
||||
//std::unordered_map<std::string, UDQSet> udq_results;
|
||||
std::unordered_map<std::string, double> values;
|
||||
|
||||
void ensure_segment_matcher_exists() const;
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
|
||||
#endif
|
||||
#endif // UDQ_CONTEXT_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<double>& value) const;
|
||||
UDQSet scatter_scalar_group_value(const UDQContext& context, const std::optional<double>& value) const;
|
||||
UDQSet scatter_scalar_segment_value(const UDQContext& context, const std::optional<double>& value) const;
|
||||
};
|
||||
|
||||
} // Namespace Opm
|
||||
|
@ -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<EnumeratedWellItems>& segments);
|
||||
static UDQSet segments(const std::string& name,
|
||||
const std::vector<EnumeratedWellItems>& segments,
|
||||
const double scalar_value);
|
||||
|
||||
/// Assign value to every element of the UDQ set
|
||||
///
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include <opm/input/eclipse/Schedule/Group/GTNode.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Group/GuideRateConfig.hpp>
|
||||
#include <opm/input/eclipse/Schedule/GasLiftOpt.hpp>
|
||||
#include <opm/input/eclipse/Schedule/MSW/SegmentMatcher.hpp>
|
||||
#include <opm/input/eclipse/Schedule/MSW/SICD.hpp>
|
||||
#include <opm/input/eclipse/Schedule/MSW/Valve.hpp>
|
||||
#include <opm/input/eclipse/Schedule/MSW/WellSegments.hpp>
|
||||
@ -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<std::unique_ptr<SegmentMatcher>()>
|
||||
Schedule::segmentMatcherFactory(const std::size_t report_step) const
|
||||
{
|
||||
return {
|
||||
[report_step, this]() -> std::unique_ptr<SegmentMatcher>
|
||||
{
|
||||
const auto ix = (report_step < this->snapshots.size())
|
||||
? report_step
|
||||
: this->snapshots.size() - 1;
|
||||
|
||||
return std::make_unique<SegmentMatcher>(this->snapshots[ix]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<std::string> Schedule::wellNames(const std::string& pattern) const {
|
||||
return this->wellNames(pattern, this->size() - 1);
|
||||
|
@ -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));
|
||||
|
@ -19,9 +19,11 @@
|
||||
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Schedule/MSW/SegmentMatcher.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQFunction.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
@ -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<std::string> {
|
||||
"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<Opm::UDQSet::EnumeratedWellItems>
|
||||
make_segment_items(const Opm::SegmentSet& segSet)
|
||||
{
|
||||
const auto numWells = segSet.numWells();
|
||||
|
||||
auto items = std::vector<Opm::UDQSet::EnumeratedWellItems>(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<std::string>& summary_keys) const
|
||||
{
|
||||
if (this->type == UDQTokenType::ecl_expr) {
|
||||
if (std::holds_alternative<std::string>(this->value)) {
|
||||
const auto& keyword = std::get<std::string>(this->value);
|
||||
if (!is_udq(keyword)) {
|
||||
summary_keys.insert(keyword);
|
||||
}
|
||||
if ((this->type == UDQTokenType::ecl_expr) &&
|
||||
std::holds_alternative<std::string>(this->value))
|
||||
{
|
||||
if (const auto& keyword = std::get<std::string>(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);
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <opm/common/OpmLog/KeywordLocation.hpp>
|
||||
#include <opm/common/utility/OpmInputError.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Schedule/MSW/SegmentMatcher.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
||||
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
@ -16,45 +16,58 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQContext.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Schedule/MSW/SegmentMatcher.hpp>
|
||||
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQState.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/WellMatcher.hpp>
|
||||
|
||||
#include <opm/common/utility/TimeService.hpp>
|
||||
|
||||
namespace Opm {
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
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<double> UDQContext::get(const std::string& key) const {
|
||||
std::optional<double>
|
||||
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<double> UDQContext::get_well_var(const std::string& well, const std::string& var) const {
|
||||
std::optional<double>
|
||||
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<double> UDQContext::get_group_var(const std::string& group, const std::string& var) const {
|
||||
std::optional<double>
|
||||
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<std::string> UDQContext::wells() const {
|
||||
std::optional<double>
|
||||
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<std::string> UDQContext::wells() const
|
||||
{
|
||||
return this->well_matcher.wells();
|
||||
}
|
||||
|
||||
std::vector<std::string> UDQContext::wells(const std::string& pattern) const {
|
||||
std::vector<std::string> UDQContext::wells(const std::string& pattern) const
|
||||
{
|
||||
return this->well_matcher.wells(pattern);
|
||||
}
|
||||
|
||||
std::vector<std::string> UDQContext::groups() const {
|
||||
std::vector<std::string> 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<std::string>& 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<std::string>::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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <opm/common/OpmLog/OpmLog.hpp>
|
||||
#include <opm/common/utility/String.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Schedule/MSW/SegmentMatcher.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQToken.hpp>
|
||||
@ -217,6 +218,22 @@ bool dynamic_type_check(const Opm::UDQVarType lhs,
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<Opm::UDQSet::EnumeratedWellItems>
|
||||
make_segment_items(const Opm::SegmentSet& segSet)
|
||||
{
|
||||
const auto numWells = segSet.numWells();
|
||||
|
||||
auto items = std::vector<Opm::UDQSet::EnumeratedWellItems>(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<double>& 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
|
||||
|
@ -270,6 +270,20 @@ UDQSet UDQSet::groups(const std::string& name,
|
||||
return us;
|
||||
}
|
||||
|
||||
UDQSet UDQSet::segments(const std::string& name,
|
||||
const std::vector<EnumeratedWellItems>& segments)
|
||||
{
|
||||
return { name, UDQVarType::SEGMENT_VAR, segments };
|
||||
}
|
||||
|
||||
UDQSet UDQSet::segments(const std::string& name,
|
||||
const std::vector<EnumeratedWellItems>& 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
|
||||
{
|
||||
|
@ -30,7 +30,10 @@
|
||||
|
||||
#include <opm/input/eclipse/Python/Python.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Schedule/MSW/SegmentMatcher.hpp>
|
||||
#include <opm/input/eclipse/Schedule/MSW/WellSegments.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
||||
#include <opm/input/eclipse/Schedule/ScheduleState.hpp>
|
||||
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQActive.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQAssign.hpp>
|
||||
@ -42,6 +45,7 @@
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQState.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/NameOrder.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/WellMatcher.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Utility/Typetools.hpp>
|
||||
@ -54,34 +58,126 @@
|
||||
#include <opm/input/eclipse/Deck/Deck.hpp>
|
||||
#include <opm/input/eclipse/Deck/UDAValue.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace Opm;
|
||||
|
||||
namespace {
|
||||
Schedule make_schedule(const std::string& input) {
|
||||
Parser parser;
|
||||
auto python = std::make_shared<Python>();
|
||||
|
||||
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<Python>() };
|
||||
}
|
||||
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<Python>() };
|
||||
}
|
||||
}
|
||||
} // 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<Opm::WellSegments> makeSegments(const int numSegments)
|
||||
{
|
||||
auto segments = std::vector<Opm::Segment>{};
|
||||
segments.reserve(numSegments);
|
||||
|
||||
for (auto segment = 0; segment < numSegments; ++segment) {
|
||||
segments.push_back(makeSegment(segment + 1));
|
||||
}
|
||||
|
||||
return std::make_shared<Opm::WellSegments>
|
||||
(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(ScheduleState {}); };
|
||||
udq.eval(0, schedule, wm, segmentMatcherFactory, st, udq_state);
|
||||
|
||||
const auto required_keys = [&udq]()
|
||||
{
|
||||
std::unordered_set<std::string> 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<std::string>{};
|
||||
udq.required_summary(keys);
|
||||
|
||||
auto required = std::vector<std::string>{ keys.begin(), keys.end() };
|
||||
std::sort(required.begin(), required.end());
|
||||
|
||||
return required;
|
||||
}();
|
||||
|
||||
const auto expected_keys = std::vector<std::string> {
|
||||
"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<SegmentMatcher>(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<SegmentMatcher>(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<std::string> 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<std::string>{};
|
||||
udq.required_summary(keys);
|
||||
|
||||
auto required = std::vector<std::string>{ keys.begin(), keys.end() };
|
||||
std::sort(required.begin(), required.end());
|
||||
|
||||
return required;
|
||||
}();
|
||||
|
||||
const auto expected_keys = std::vector<std::string> {};
|
||||
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(required_keys.begin(), required_keys.end(),
|
||||
expected_keys.begin(), expected_keys.end());
|
||||
|
||||
auto segmentMatcherFactory = []() { return std::make_unique<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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<SegmentMatcher>(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);
|
||||
|
@ -2,97 +2,113 @@
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <opm/output/eclipse/AggregateUDQData.hpp>
|
||||
|
||||
#include <opm/output/eclipse/AggregateConnectionData.hpp>
|
||||
#include <opm/output/eclipse/AggregateGroupData.hpp>
|
||||
#include <opm/output/eclipse/AggregateWellData.hpp>
|
||||
#include <opm/output/eclipse/AggregateConnectionData.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
||||
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
|
||||
#include <opm/input/eclipse/Parser/Parser.hpp>
|
||||
#include <opm/input/eclipse/Deck/Deck.hpp>
|
||||
|
||||
#include <opm/output/eclipse/AggregateUDQData.hpp>
|
||||
#include <opm/output/eclipse/WriteRestartHelpers.hpp>
|
||||
|
||||
#include <opm/output/eclipse/DoubHEAD.hpp>
|
||||
#include <opm/output/eclipse/InteHEAD.hpp>
|
||||
#include <opm/output/eclipse/VectorItems/intehead.hpp>
|
||||
#include <opm/output/eclipse/DoubHEAD.hpp>
|
||||
#include <opm/output/eclipse/WriteRestartHelpers.hpp>
|
||||
|
||||
#include <opm/output/data/Wells.hpp>
|
||||
|
||||
#include <opm/io/eclipse/ERst.hpp>
|
||||
#include <opm/io/eclipse/OutputStream.hpp>
|
||||
#include <opm/io/eclipse/RestartFileView.hpp>
|
||||
#include <opm/io/eclipse/rst/state.hpp>
|
||||
|
||||
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Python/Python.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQInput.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Action/State.hpp>
|
||||
#include <opm/input/eclipse/Schedule/MSW/SegmentMatcher.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
||||
#include <opm/input/eclipse/Schedule/ScheduleState.hpp>
|
||||
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQActive.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQParams.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQState.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQInput.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQParams.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQState.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/WellMatcher.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/WellTestState.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Units/UnitSystem.hpp>
|
||||
#include <opm/input/eclipse/Units/Units.hpp>
|
||||
#include <opm/common/utility/TimeService.hpp>
|
||||
#include <opm/io/eclipse/ERst.hpp>
|
||||
#include <opm/io/eclipse/RestartFileView.hpp>
|
||||
#include <opm/io/eclipse/rst/state.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Action/State.hpp>
|
||||
#include <opm/output/data/Wells.hpp>
|
||||
|
||||
#include <opm/io/eclipse/OutputStream.hpp>
|
||||
#include <opm/common/utility/TimeService.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Parser/Parser.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Deck/Deck.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#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<std::string>& wgnames,
|
||||
const std::vector<double>& values)
|
||||
{
|
||||
Opm::UDQSet s(name, var_type, wgnames);
|
||||
|
||||
Opm::UDQSet make_udq_set(const std::string& name, Opm::UDQVarType var_type, const std::vector<std::string>& wgnames, const std::vector<double>& 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<Opm::Python>() }
|
||||
{}
|
||||
|
||||
//int main(int argc, char* argv[])
|
||||
struct SimulationCase
|
||||
{
|
||||
explicit SimulationCase(const Opm::Deck& deck)
|
||||
: es { deck }
|
||||
, grid { deck }
|
||||
, python { std::make_shared<Opm::Python>()}
|
||||
, 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<Opm::Python> python;
|
||||
Opm::Schedule sched;
|
||||
Opm::Parser parser;
|
||||
};
|
||||
bool udq_contains(const std::vector<Opm::UDQActive::RstRecord>& 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<std::string>() == udq);
|
||||
});
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Aggregate_UDQ)
|
||||
return find_iter != records.end();
|
||||
}
|
||||
|
||||
bool udq_contains(const std::vector<Opm::UDQActive::RstRecord>& 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<std::string>() == 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<std::pair<std::string, std::string>> expected = {{"WUOPRL", "SM3/DAY"},
|
||||
{"WULPRL", "SM3/DAY"},
|
||||
{"WUOPRU", "SM3/DAY"},
|
||||
{"GUOPRU", "SM3/DAY"},
|
||||
{"WULPRU", "SM3/DAY"},
|
||||
{"FULPR", "SM3/DAY"}};
|
||||
const auto expected = std::vector<std::pair<std::string, std::string>> {
|
||||
{"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<std::string>& wells = {"PROD1", "PROD2", "WINJ1", "WINJ2"};
|
||||
const auto wells = std::vector<std::string> {
|
||||
"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::SegmentMatcher>(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
|
||||
|
@ -22,26 +22,31 @@
|
||||
#define BOOST_TEST_MODULE EclipseIO
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <opm/output/data/Cells.hpp>
|
||||
#include <opm/output/data/Groups.hpp>
|
||||
#include <opm/output/data/Wells.hpp>
|
||||
#include <opm/output/eclipse/AggregateAquiferData.hpp>
|
||||
#include <opm/output/eclipse/EclipseIO.hpp>
|
||||
#include <opm/output/eclipse/RestartIO.hpp>
|
||||
#include <opm/output/eclipse/RestartValue.hpp>
|
||||
#include <opm/output/data/Cells.hpp>
|
||||
#include <opm/output/data/Wells.hpp>
|
||||
#include <opm/output/data/Groups.hpp>
|
||||
#include <opm/input/eclipse/Python/Python.hpp>
|
||||
|
||||
#include <opm/io/eclipse/ERst.hpp>
|
||||
#include <opm/io/eclipse/EclIOdata.hpp>
|
||||
#include <opm/io/eclipse/OutputStream.hpp>
|
||||
|
||||
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/Eqldims.hpp>
|
||||
#include <opm/input/eclipse/Deck/Deck.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/IOConfig/IOConfig.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/SummaryConfig/SummaryConfig.hpp>
|
||||
#include <opm/input/eclipse/Parser/Parser.hpp>
|
||||
#include <opm/input/eclipse/Utility/Functional.hpp>
|
||||
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/Eqldims.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Python/Python.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Schedule/Action/State.hpp>
|
||||
#include <opm/input/eclipse/Schedule/MSW/SegmentMatcher.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
||||
#include <opm/input/eclipse/Schedule/ScheduleState.hpp>
|
||||
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQState.hpp>
|
||||
@ -49,16 +54,17 @@
|
||||
#include <opm/input/eclipse/Schedule/Well/WellConnections.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/WellMatcher.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/WellTestState.hpp>
|
||||
#include <opm/input/eclipse/Utility/Functional.hpp>
|
||||
|
||||
#include <opm/io/eclipse/OutputStream.hpp>
|
||||
#include <opm/io/eclipse/EclIOdata.hpp>
|
||||
#include <opm/io/eclipse/ERst.hpp>
|
||||
#include <opm/input/eclipse/Parser/Parser.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Deck/Deck.hpp>
|
||||
|
||||
#include <opm/common/utility/TimeService.hpp>
|
||||
|
||||
#include <sstream>
|
||||
#include <tuple>
|
||||
|
||||
#include <opm/common/utility/TimeService.hpp>
|
||||
|
||||
#include <tests/WorkArea.hpp>
|
||||
|
||||
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> python;
|
||||
Schedule schedule;
|
||||
SummaryConfig summary_config;
|
||||
|
||||
Setup( const char* path) :
|
||||
deck( Parser().parseFile( path) ),
|
||||
es( deck),
|
||||
grid( es.getInputGrid( ) ),
|
||||
python( std::make_shared<Python>() ),
|
||||
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<Python>() )
|
||||
, 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<SegmentMatcher>(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<RestartKey>& solution_keys) {
|
||||
RestartValue
|
||||
second_sim(const Setup& setup,
|
||||
Action::State& action_state,
|
||||
SummaryState& summary_state,
|
||||
const std::vector<RestartKey>& 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<RestartKey>& solution_keys) {
|
||||
|
||||
void compare(const RestartValue& fst,
|
||||
const RestartValue& snd,
|
||||
const std::vector<RestartKey>& 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<RestartKey> 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<RestartKey>& keys) {
|
||||
|
||||
void compare_equal(const RestartValue& fst,
|
||||
const RestartValue& snd,
|
||||
const std::vector<RestartKey>& 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<RestartKey> 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 {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user