Merge pull request #3587 from bska/trigger-assign-from-actionx
Track Pending Assignments in UDQ Configuration Object
This commit is contained in:
@@ -101,6 +101,8 @@ namespace Opm {
|
||||
const std::vector<std::string>& expression,
|
||||
std::size_t report_step);
|
||||
|
||||
bool clear_pending_assignments();
|
||||
|
||||
void eval_assign(std::size_t report_step,
|
||||
const Schedule& sched,
|
||||
const WellMatcher& wm,
|
||||
@@ -147,6 +149,7 @@ namespace Opm {
|
||||
serializer(units);
|
||||
serializer(input_index);
|
||||
serializer(type_count);
|
||||
serializer(pending_assignments_);
|
||||
|
||||
// The UDQFunction table is constant up to udq_params, so we can
|
||||
// just construct a new instance here.
|
||||
@@ -174,12 +177,13 @@ namespace Opm {
|
||||
OrderedMap<UDQIndex> input_index;
|
||||
std::map<UDQVarType, std::size_t> type_count;
|
||||
|
||||
mutable std::vector<std::string> pending_assignments_{};
|
||||
|
||||
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,
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace Opm {
|
||||
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_assign(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;
|
||||
|
||||
@@ -53,8 +53,7 @@ public:
|
||||
double get_segment_var(const std::string& well, const std::string& var, const std::size_t segment) const;
|
||||
|
||||
void add_define(std::size_t report_step, const std::string& udq_key, const UDQSet& result);
|
||||
void add_assign(std::size_t report_step, const std::string& udq_key, const UDQSet& result);
|
||||
bool assign(std::size_t report_step, const std::string& udq_key) const;
|
||||
void add_assign(const std::string& udq_key, const UDQSet& result);
|
||||
bool define(const std::string& udq_key, const std::pair<UDQUpdate, std::size_t>& update_status) const;
|
||||
double undefined_value() const;
|
||||
|
||||
@@ -70,7 +69,6 @@ public:
|
||||
serializer(this->well_values);
|
||||
serializer(this->group_values);
|
||||
serializer(this->segment_values);
|
||||
serializer(this->assignments);
|
||||
serializer(this->defines);
|
||||
}
|
||||
|
||||
@@ -87,7 +85,6 @@ private:
|
||||
// [var][well][segment] -> double
|
||||
std::unordered_map<std::string, std::unordered_map<std::string, std::unordered_map<std::size_t, double>>> segment_values{};
|
||||
|
||||
std::unordered_map<std::string, std::size_t> assignments;
|
||||
std::unordered_map<std::string, std::size_t> defines;
|
||||
|
||||
void add(const std::string& udq_key, const UDQSet& result);
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
|
||||
#include <opm/input/eclipse/Schedule/Action/Actions.hpp>
|
||||
#include <opm/input/eclipse/Schedule/GasLiftOpt.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Group/GConSump.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Group/GConSale.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Group/GConSump.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Group/GroupEconProductionLimits.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Group/GuideRateConfig.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Network/Balance.hpp>
|
||||
@@ -31,39 +31,51 @@
|
||||
#include <opm/input/eclipse/Schedule/RPTConfig.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQActive.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp>
|
||||
#include <opm/input/eclipse/Schedule/VFPProdTable.hpp>
|
||||
#include <opm/input/eclipse/Schedule/VFPInjTable.hpp>
|
||||
#include <opm/input/eclipse/Schedule/VFPProdTable.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/WellMatcher.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/WellTestConfig.hpp>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <ctime>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace Opm {
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace {
|
||||
|
||||
/*
|
||||
This is to ensure that only time_points which can be represented with
|
||||
std::time_t are used. The reason for clamping to std::time_t resolution is
|
||||
that the serialization code in
|
||||
opm-simulators:opm/simulators/utils/ParallelRestart.cpp goes via std::time_t.
|
||||
*/
|
||||
time_point clamp_time(time_point t) {
|
||||
return TimeService::from_time_t( TimeService::to_time_t( t ) );
|
||||
}
|
||||
// This is to ensure that only time_points which can be represented with
|
||||
// std::time_t are used. The reason for clamping to std::time_t
|
||||
// resolution is that the serialization code in
|
||||
// opm-simulators:opm/simulators/utils/ParallelRestart.cpp goes via
|
||||
// std::time_t.
|
||||
Opm::time_point clamp_time(Opm::time_point t)
|
||||
{
|
||||
return Opm::TimeService::from_time_t(Opm::TimeService::to_time_t(t));
|
||||
}
|
||||
|
||||
std::pair<std::size_t, std::size_t> date_diff(const time_point& t2, const time_point& t1) {
|
||||
auto ts1 = TimeStampUTC(TimeService::to_time_t(t1));
|
||||
auto ts2 = TimeStampUTC(TimeService::to_time_t(t2));
|
||||
auto year_diff = ts2.year() - ts1.year();
|
||||
auto month_diff = year_diff*12 + ts2.month() - ts1.month();
|
||||
return { year_diff, month_diff };
|
||||
}
|
||||
std::pair<std::size_t, std::size_t>
|
||||
date_diff(const Opm::time_point& t2, const Opm::time_point& t1)
|
||||
{
|
||||
const auto ts1 = Opm::TimeStampUTC { Opm::TimeService::to_time_t(t1) };
|
||||
const auto ts2 = Opm::TimeStampUTC { Opm::TimeService::to_time_t(t2) };
|
||||
|
||||
}
|
||||
const auto year_diff = ts2.year() - ts1.year();
|
||||
const auto month_diff = year_diff*12 + ts2.month() - ts1.month();
|
||||
|
||||
return { year_diff, month_diff };
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
namespace Opm {
|
||||
|
||||
void ScheduleState::updateSAVE(bool save) {
|
||||
this->m_save_step = save;
|
||||
@@ -73,27 +85,23 @@ bool ScheduleState::save() const {
|
||||
return this->m_save_step;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ScheduleState::ScheduleState(const time_point& t1):
|
||||
m_start_time(clamp_time(t1)),
|
||||
m_first_in_month(true),
|
||||
m_first_in_year(true)
|
||||
ScheduleState::ScheduleState(const time_point& t1)
|
||||
: m_start_time(clamp_time(t1))
|
||||
, m_first_in_month(true)
|
||||
, m_first_in_year(true)
|
||||
{
|
||||
auto ts1 = TimeStampUTC(TimeService::to_time_t(this->m_start_time));
|
||||
this->m_month_num = ts1.month() - 1;
|
||||
}
|
||||
|
||||
ScheduleState::ScheduleState(const time_point& start_time, const time_point& end_time) :
|
||||
ScheduleState(start_time)
|
||||
ScheduleState::ScheduleState(const time_point& start_time, const time_point& end_time)
|
||||
: ScheduleState(start_time)
|
||||
{
|
||||
this->m_end_time = clamp_time(end_time);
|
||||
}
|
||||
|
||||
void ScheduleState::update_date(const time_point& prev_time) {
|
||||
void ScheduleState::update_date(const time_point& prev_time)
|
||||
{
|
||||
auto [year_diff, month_diff] = date_diff(this->m_start_time, prev_time);
|
||||
this->m_year_num += year_diff;
|
||||
this->m_first_in_month = (month_diff > 0);
|
||||
@@ -103,11 +111,8 @@ void ScheduleState::update_date(const time_point& prev_time) {
|
||||
this->m_month_num = ts1.month() - 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
ScheduleState::ScheduleState(const ScheduleState& src, const time_point& start_time) :
|
||||
ScheduleState(src)
|
||||
ScheduleState::ScheduleState(const ScheduleState& src, const time_point& start_time)
|
||||
: ScheduleState { src } // Copy constructor
|
||||
{
|
||||
this->m_start_time = clamp_time(start_time);
|
||||
this->m_end_time = std::nullopt;
|
||||
@@ -118,15 +123,22 @@ ScheduleState::ScheduleState(const ScheduleState& src, const time_point& start_t
|
||||
this->target_wellpi.clear();
|
||||
this->m_save_step = false;
|
||||
|
||||
auto next_rft = this->rft_config().next();
|
||||
if (next_rft.has_value())
|
||||
this->rft_config.update( std::move(*next_rft) );
|
||||
{
|
||||
auto next_rft = this->rft_config().next();
|
||||
|
||||
this->update_date(src.m_start_time);
|
||||
if (this->rst_config().save) {
|
||||
auto new_rst = this->rst_config();
|
||||
new_rst.save = false;
|
||||
this->rst_config.update( std::move(new_rst) );
|
||||
if (next_rft.has_value()) {
|
||||
this->rft_config.update(std::move(*next_rft));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
this->update_date(src.m_start_time);
|
||||
|
||||
if (this->rst_config().save) {
|
||||
auto new_rst = this->rst_config();
|
||||
new_rst.save = false;
|
||||
this->rst_config.update(std::move(new_rst));
|
||||
}
|
||||
}
|
||||
|
||||
if (this->next_tstep.has_value()) {
|
||||
@@ -136,16 +148,26 @@ ScheduleState::ScheduleState(const ScheduleState& src, const time_point& start_t
|
||||
// Need to signal an event also for the persistance to take effect
|
||||
this->events().addEvent(ScheduleEvents::TUNING_CHANGE);
|
||||
}
|
||||
|
||||
{
|
||||
auto new_udq = this->udq();
|
||||
|
||||
if (new_udq.clear_pending_assignments()) {
|
||||
// New report step. All ASSIGNments from previous report steps
|
||||
// have been performed.
|
||||
this->udq.update(std::move(new_udq));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ScheduleState::ScheduleState(const ScheduleState& src, const time_point& start_time, const time_point& end_time) :
|
||||
ScheduleState(src, start_time)
|
||||
ScheduleState::ScheduleState(const ScheduleState& src,
|
||||
const time_point& start_time,
|
||||
const time_point& end_time)
|
||||
: ScheduleState { src, start_time }
|
||||
{
|
||||
this->m_end_time = end_time;
|
||||
}
|
||||
|
||||
|
||||
time_point ScheduleState::start_time() const {
|
||||
return this->m_start_time;
|
||||
}
|
||||
|
||||
@@ -176,6 +176,7 @@ namespace Opm {
|
||||
result.units = {{"test3", "test4"}};
|
||||
result.input_index.insert({"test5", UDQIndex::serializationTestObject()});
|
||||
result.type_count = {{UDQVarType::SCALAR, 5}};
|
||||
result.pending_assignments_.push_back("test2");
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -219,6 +220,10 @@ namespace Opm {
|
||||
this->add_named_assign(quantity, selector, value, report_step);
|
||||
break;
|
||||
}
|
||||
|
||||
if (this->m_assignments.find(quantity) != this->m_assignments.end()) {
|
||||
this->pending_assignments_.push_back(quantity);
|
||||
}
|
||||
}
|
||||
|
||||
void UDQConfig::add_assign(const std::string& quantity,
|
||||
@@ -333,6 +338,14 @@ namespace Opm {
|
||||
}
|
||||
}
|
||||
|
||||
bool UDQConfig::clear_pending_assignments()
|
||||
{
|
||||
const auto update = ! this->pending_assignments_.empty();
|
||||
this->pending_assignments_.clear();
|
||||
|
||||
return update;
|
||||
}
|
||||
|
||||
const UDQAssign& UDQConfig::assign(const std::string& key) const
|
||||
{
|
||||
return this->m_assignments.at(key);
|
||||
@@ -522,14 +535,18 @@ namespace Opm {
|
||||
&& (this->units == data.units)
|
||||
&& (this->input_index == data.input_index)
|
||||
&& (this->type_count == data.type_count)
|
||||
&& (this->pending_assignments_ == data.pending_assignments_)
|
||||
;
|
||||
}
|
||||
|
||||
void UDQConfig::eval_assign(const std::size_t report_step,
|
||||
const Schedule& sched,
|
||||
UDQState& udq_state,
|
||||
UDQContext& context) const
|
||||
{
|
||||
if (this->pending_assignments_.empty()) {
|
||||
return; // Nothing to do
|
||||
}
|
||||
|
||||
const auto handlers = std::map<UDQVarType, EvalAssign> {
|
||||
{ UDQVarType::FIELD_VAR , EvalAssign::field() },
|
||||
{ UDQVarType::GROUP_VAR , EvalAssign::group(report_step, sched) },
|
||||
@@ -537,24 +554,30 @@ namespace Opm {
|
||||
{ UDQVarType::SEGMENT_VAR, EvalAssign::segment(context) },
|
||||
};
|
||||
|
||||
for (const auto& index_pair : this->input_index) {
|
||||
const auto& keyword = index_pair.first;
|
||||
auto asgn_pos = this->m_assignments.find(keyword);
|
||||
if ((asgn_pos == this->m_assignments.end()) ||
|
||||
! udq_state.assign(asgn_pos->second.report_step(), keyword))
|
||||
{
|
||||
// No such ASSIGN or ASSIGN not active
|
||||
// Recall: pending_assignments_ is mutable.
|
||||
auto pending = std::vector<std::string>{};
|
||||
this->pending_assignments_.swap(pending);
|
||||
|
||||
{
|
||||
std::sort(pending.begin(), pending.end());
|
||||
auto u = std::unique(pending.begin(), pending.end());
|
||||
pending.erase(u, pending.end());
|
||||
}
|
||||
|
||||
for (const auto& assignment : pending) {
|
||||
auto asgn_pos = this->m_assignments.find(assignment);
|
||||
if (asgn_pos == this->m_assignments.end()) {
|
||||
// No such ASSIGNment. Unexpected.
|
||||
continue;
|
||||
}
|
||||
|
||||
auto handler = handlers.find(asgn_pos->second.var_type());
|
||||
if (handler == handlers.end()) {
|
||||
// Unhandled variable type.
|
||||
// Unhandled/unsupported variable type.
|
||||
continue;
|
||||
}
|
||||
|
||||
context.update_assign(report_step, keyword,
|
||||
handler->second(asgn_pos->second));
|
||||
context.update_assign(assignment, handler->second(asgn_pos->second));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -607,7 +630,7 @@ namespace Opm {
|
||||
UDQContext context {
|
||||
this->function_table(), wm, std::move(create_segment_matcher), st, udq_state
|
||||
};
|
||||
this->eval_assign(report_step, sched, udq_state, context);
|
||||
this->eval_assign(report_step, sched, context);
|
||||
this->eval_define(report_step, udq_state, context);
|
||||
}
|
||||
|
||||
@@ -621,7 +644,7 @@ namespace Opm {
|
||||
UDQContext context {
|
||||
this->function_table(), wm, std::move(create_segment_matcher), st, udq_state
|
||||
};
|
||||
this->eval_assign(report_step, sched, udq_state, context);
|
||||
this->eval_assign(report_step, sched, context);
|
||||
}
|
||||
|
||||
void UDQConfig::required_summary(std::unordered_set<std::string>& summary_keys) const
|
||||
|
||||
@@ -218,11 +218,10 @@ namespace Opm {
|
||||
return this->udqft;
|
||||
}
|
||||
|
||||
void UDQContext::update_assign(const std::size_t report_step,
|
||||
const std::string& keyword,
|
||||
void UDQContext::update_assign(const std::string& keyword,
|
||||
const UDQSet& udq_result)
|
||||
{
|
||||
this->udq_state.add_assign(report_step, keyword, udq_result);
|
||||
this->udq_state.add_assign(keyword, udq_result);
|
||||
this->summary_state.update_udq(udq_result, this->udq_state.undefined_value());
|
||||
}
|
||||
|
||||
|
||||
@@ -291,9 +291,8 @@ void UDQState::add_define(std::size_t report_step, const std::string& udq_key, c
|
||||
this->add(udq_key, result);
|
||||
}
|
||||
|
||||
void UDQState::add_assign(std::size_t report_step, const std::string& udq_key, const UDQSet& result)
|
||||
void UDQState::add_assign(const std::string& udq_key, const UDQSet& result)
|
||||
{
|
||||
this->assignments[udq_key] = report_step;
|
||||
this->add(udq_key, result);
|
||||
}
|
||||
|
||||
@@ -364,7 +363,6 @@ bool UDQState::operator==(const UDQState& other) const
|
||||
&& (this->well_values == other.well_values)
|
||||
&& (this->group_values == other.group_values)
|
||||
&& (this->segment_values == other.segment_values)
|
||||
&& (this->assignments == other.assignments)
|
||||
&& (this->defines == other.defines);
|
||||
}
|
||||
|
||||
@@ -373,7 +371,6 @@ UDQState UDQState::serializationTestObject()
|
||||
UDQState st;
|
||||
st.undef_value = 78;
|
||||
st.scalar_values = {{"FU1", 100}, {"FU2", 200}};
|
||||
st.assignments = {{"GU1", 99}, {"GU2", 199}};
|
||||
st.defines = {{"DU1", 299}, {"DU2", 399}};
|
||||
|
||||
st.well_values.emplace("W1", std::unordered_map<std::string, double>{{"U1", 100}, {"U2", 200}});
|
||||
@@ -410,14 +407,6 @@ UDQState UDQState::serializationTestObject()
|
||||
return st;
|
||||
}
|
||||
|
||||
bool UDQState::assign(std::size_t report_step, const std::string& udq_key) const
|
||||
{
|
||||
auto assign_iter = this->assignments.find(udq_key);
|
||||
|
||||
return (assign_iter == this->assignments.end())
|
||||
|| (report_step > assign_iter->second);
|
||||
}
|
||||
|
||||
bool UDQState::define(const std::string& udq_key,
|
||||
const std::pair<UDQUpdate, std::size_t>& update_status) const
|
||||
{
|
||||
|
||||
@@ -2851,7 +2851,7 @@ UDQ
|
||||
const auto& udq = schedule.getUDQConfig(1);
|
||||
{
|
||||
const auto& ass = udq.assign("FUBHPP1");
|
||||
context.update_assign(1, "FUBHPP1", ass.eval());
|
||||
context.update_assign("FUBHPP1", ass.eval());
|
||||
}
|
||||
const auto& def = udq.define("WUDELTA");
|
||||
auto res = def.eval(context);
|
||||
|
||||
Reference in New Issue
Block a user