Skip to content
8 changes: 6 additions & 2 deletions msim/include/opm/msim/msim.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,12 @@ class msim {

void well_rate(const std::string& well, data::Rates::opt rate, std::function<well_rate_function> func);
void solution(const std::string& field, std::function<solution_function> func);
void run(EclipseIO& io, bool report_only);
void post_step(data::Solution& sol, data::Wells& well_data, data::GroupAndNetworkValues& group_nwrk_data, size_t report_step, const time_point& sim_time);
/// \brief Mimick runnung all steps of the simulation
/// \return True if any ACTIONX was applied.
bool run(EclipseIO& io, bool report_only);
/// \brief Mimick postprocessing after a simulation step
/// \return True if any ACTIONX was applied.
bool post_step(data::Solution& sol, data::Wells& well_data, data::GroupAndNetworkValues& group_nwrk_data, size_t report_step, const time_point& sim_time);

private:
void run_step(const WellTestState& wtest_state,
Expand Down
16 changes: 11 additions & 5 deletions msim/src/msim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,9 @@ msim::msim(const EclipseState& state_arg, const Schedule& schedule_arg)
{}


void msim::run(EclipseIO& io, bool report_only)
bool msim::run(EclipseIO& io, bool report_only)
{
bool any_actions_applied = false;
const double week = 7 * 86400;

data::Solution sol;
Expand All @@ -107,13 +108,15 @@ void msim::run(EclipseIO& io, bool report_only)
}

const auto sim_time = TimeService::from_time_t(schedule.simTime(report_step));
post_step(sol, well_data, group_nwrk_data, report_step, sim_time);
auto action_applied = post_step(sol, well_data, group_nwrk_data, report_step, sim_time);
any_actions_applied = any_actions_applied || action_applied;

const auto& exit_status = schedule.exitStatus();
if (exit_status.has_value()) {
return;
return any_actions_applied;
}
}
return any_actions_applied;
}


Expand All @@ -123,15 +126,16 @@ UDAValue msim::uda_val()
}


void msim::post_step(data::Solution& /* sol */,
bool msim::post_step(data::Solution& /* sol */,
data::Wells& /* well_data */,
data::GroupAndNetworkValues& /* grp_nwrk_data */,
const size_t report_step,
const time_point& sim_time)
{
bool action_applied = false;
const auto& actions = this->schedule[report_step].actions.get();
if (actions.empty()) {
return;
return action_applied;
}

const auto context = Action::Context {
Expand All @@ -143,13 +147,15 @@ void msim::post_step(data::Solution& /* sol */,
if (result.conditionSatisfied()) {
this->schedule.applyAction(report_step, *action, result.matches(),
std::unordered_map<std::string,double>{}, true);
action_applied = true;
}
}

for (const auto& pyaction : actions.pending_python(this->action_state)) {
this->schedule.runPyAction(report_step, *pyaction,
this->action_state, this->state, this->st);
}
return action_applied;
}


Expand Down
25 changes: 24 additions & 1 deletion opm/input/eclipse/Schedule/Action/ActionParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <cstdlib> // std::strtod()
#include <cstring> // std::strlen()
#include <memory>
#include <regex>
#include <stdexcept>
#include <string>
#include <utility>
Expand Down Expand Up @@ -64,6 +65,11 @@ Opm::Action::FuncType functionType(const std::string& arg)
case Cat::Region: return FuncType::region;
case Cat::Block: return FuncType::block;
case Cat::Segment: return FuncType::well_segment;
// ACTIONX does not support conditions on well completions
// with a special syntax like for connections and wells.
// But it can have conditions on Quanttties defined for completions
// (e.g. WWCTL__3) and then this will change wells
case Cat::Completion: return FuncType::well;
default: return FuncType::none;
}
}
Expand Down Expand Up @@ -366,8 +372,25 @@ Opm::Action::ASTNode ActionParser::parse_left()

// Note: Func must be an independent object here--i.e., not a
// reference--since we update 'curr' in the loop below.
const auto func = curr.value;
auto func = curr.value;
const auto func_type = functionType(curr.value);
if(func_type == Opm::Action::FuncType::well && func.size() > 2 && func[2] == 'C' ) {
// Normalize number to have 3 digits if this is actually a completion
// function mimicking as a well. We fill up missing digits at the front with _
static const auto num_kw_regex = std::regex {
R"((W[A-Z]C[A-Z+-]*)(_[0-9]+))"
};
std::smatch matched;
if (std::regex_match(func, matched, num_kw_regex)) {
auto numchars = matched.length(2);
if (numchars < 3) {
const auto prefix = "___";
func = fmt::format("{}{}{}", matched[1].str(),
std::string_view(prefix, 3 - numchars),
matched[2].str());
}
}
}

auto arg_list = std::vector<std::string>{};

Expand Down
37 changes: 37 additions & 0 deletions opm/input/eclipse/Schedule/SummaryState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@
#include <opm/io/eclipse/SummaryNode.hpp>

#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <limits>
#include <ostream>
#include <regex>
#include <set>
#include <stdexcept>
#include <string>
Expand Down Expand Up @@ -84,6 +86,19 @@ namespace {
&& (keyword.compare(0, 2, "SU") == 0);
}

bool is_encoded_well_completion_quantity(std::string_view keyword)
{
// Does 'keyword' match the pattern
// W?C*:
using sz_t = std::string_view::size_type;

return keyword.size() > sz_t{6}
&& keyword.find(':') != std::string::npos
&& keyword.compare(0, 1, "W") == 0
&& keyword.compare(2, 1, "C") == 0;
}


bool is_total(const std::string& key)
{
static const std::vector<std::string> totals = {
Expand Down Expand Up @@ -169,6 +184,20 @@ namespace {
return l;
}

std::string normalise_encoded_well_completion_quantity(const std::string& keyword)
{
// Does 'keyword' match the pattern W?C*:
static const auto comp_kw_regex = std::regex {
R"((W[A-Z]C[A-Z+-]*)_*([0-9]+):(.+))"
};
std::smatch matched;
if (!std::regex_match(keyword, matched, comp_kw_regex)) {
return std::string(keyword);
} else {
return fmt::format("{}:{}:{}", matched[1].str(), matched[3].str(), matched[2].str());
}
}

std::string normalise_region_set_name(const std::string& regSet)
{
if (regSet.empty()) {
Expand Down Expand Up @@ -490,6 +519,14 @@ namespace Opm
return this->udq_undefined;
}

if (is_encoded_well_completion_quantity(key)) {
auto key1 = normalise_encoded_well_completion_quantity(key);
auto iter1 = this->values.find(key1);
if (iter1 != this->values.end()) {
return iter1->second;
}
}

throw std::out_of_range {
fmt::format("Summary vector {} is unknown", key)
};
Expand Down
Loading