Merge pull request #3587 from bska/trigger-assign-from-actionx

Track Pending Assignments in UDQ Configuration Object
This commit is contained in:
Markus Blatt
2023-10-10 12:41:33 +02:00
committed by GitHub
8 changed files with 120 additions and 86 deletions

View File

@@ -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,

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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());
}

View File

@@ -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
{

View File

@@ -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);