Skip to content

Commit

Permalink
Canonicalise Region Selectors in Action Conditions
Browse files Browse the repository at this point in the history
This commit translates ACTIONX condition region quantities of the
form

    RPR 1 RE3

i.e., including the region set name 'RE3' (FIPRE3) into the common
summary vector format

    RPR__RE3 1

which is expected elsewhere.  Doing so enables using the former
syntax in ACTIONX conditions like

    RPR 1 RE3 < 215 /

without incurring significant downstream changes in the vector
evaluation code.  Defaulted ('1*') or blank (' ') region set names
are treated as the default region set (FIPNUM).
  • Loading branch information
bska committed Jan 31, 2025
1 parent 09c7a4e commit 3053b04
Show file tree
Hide file tree
Showing 2 changed files with 264 additions and 2 deletions.
79 changes: 77 additions & 2 deletions opm/input/eclipse/Schedule/Action/ASTNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <opm/input/eclipse/Schedule/Well/WListManager.hpp>

#include <opm/common/utility/shmatch.hpp>
#include <opm/common/utility/String.hpp>

#include <algorithm>
#include <cmath>
Expand Down Expand Up @@ -65,6 +66,80 @@ namespace {

return strings;
}

bool isDefaultRegSet(const std::string& regSet)
{
const auto trimmedRegSet = Opm::trim_copy(strip_quotes(regSet));

return trimmedRegSet.empty()
|| (trimmedRegSet == "1*");
}

std::string
normaliseFunction(const Opm::Action::FuncType funcType,
std::string_view function,
const std::vector<std::string>& argListIn)
{
if ((funcType != Opm::Action::FuncType::region) ||
(argListIn.size() < 2))
{
return std::string { function };
}

if (argListIn.size() > 2) {
throw std::invalid_argument {
fmt::format(R"(Selection "{}" is not supported for region vector '{}')",
fmt::join(argListIn, " "), function)
};
}

if (isDefaultRegSet(argListIn.back())) {
// The input specification is something along the lines of
//
// RPR 42 1* or RPR 42 ' '
//
// This corresponds to the default 'FIPNUM' region set, so
// return
//
// RPR
return std::string { function };
}

// The input specification is something along the lines of
//
// RPR 42 RE4
//
// Normalise vector name to the common
//
// RPR__RE4
//
// as that's the expected region vector name format elsewhere.
return fmt::format("{:_<5}{}", function,
strip_quotes(argListIn.back())
.substr(0, 3));
}

std::vector<std::string>
normaliseArgList(const Opm::Action::FuncType funcType,
std::vector<std::string>&& argListIn)
{
if ((funcType != Opm::Action::FuncType::region) ||
(argListIn.size() < 2))
{
return std::move(argListIn);
}

// The input specification is something along the lines of
//
// RPR 42 RE4
//
// NormaliseFunction() creates the vector name
//
// RPR__RE4
//
// so we only need to return the "42" here (front of argument list).
return { std::move(argListIn.front()) };
}
} // Anonymous namespace

Opm::Action::ASTNode::ASTNode()
Expand All @@ -87,8 +162,8 @@ Opm::Action::ASTNode::ASTNode(const TokenType type_arg,
const std::vector<std::string>& arg_list_arg)
: type (type_arg)
, func_type(func_type_arg)
, func (func_arg)
, arg_list (strip_quotes(arg_list_arg))
, func (normaliseFunction(func_type, func_arg, arg_list_arg))
, arg_list (normaliseArgList(func_type, strip_quotes(arg_list_arg)))
{}

Opm::Action::ASTNode
Expand Down
187 changes: 187 additions & 0 deletions tests/parser/ACTIONX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1927,3 +1927,190 @@ BOOST_AUTO_TEST_CASE(ParseNestedExpression)
BOOST_CHECK_EQUAL_COLLECTIONS(sortedVectors.begin(), sortedVectors.end(),
expected .begin(), expected .end());
}

BOOST_AUTO_TEST_CASE(RegionVector_In_Condition)
{
using namespace std::string_literals;

/// RPR 1 RE3 < 215.0 /
const auto ast = Opm::Action::Parser::parseCondition(std::vector {
"RPR"s, "1"s, "RE3"s, "<"s, "215.0"s,
});

auto requisiteVectors = std::unordered_set<std::string>{};
ast->required_summary(requisiteVectors);

auto sortedVectors = std::vector<std::string> {
requisiteVectors.begin(), requisiteVectors.end()
};
std::sort(sortedVectors.begin(), sortedVectors.end());

const auto expected = std::vector {
"RPR__RE3"s,
};

BOOST_CHECK_EQUAL_COLLECTIONS(sortedVectors.begin(), sortedVectors.end(),
expected .begin(), expected .end());
}

BOOST_AUTO_TEST_CASE(RegionVector_In_Condition_Default_RegSet)
{
using namespace std::string_literals;

/// RPR 1 1* < 215.0 /
const auto ast = Opm::Action::Parser::parseCondition(std::vector {
"RPR"s, "1"s, "1*"s, "<"s, "215.0"s,
});

auto requisiteVectors = std::unordered_set<std::string>{};
ast->required_summary(requisiteVectors);

auto sortedVectors = std::vector<std::string> {
requisiteVectors.begin(), requisiteVectors.end()
};
std::sort(sortedVectors.begin(), sortedVectors.end());

const auto expected = std::vector {
"RPR"s,
};

BOOST_CHECK_EQUAL_COLLECTIONS(sortedVectors.begin(), sortedVectors.end(),
expected .begin(), expected .end());
}

BOOST_AUTO_TEST_CASE(RegionVector_In_Condition_Default_RegSet_2)
{
using namespace std::string_literals;

/// RPR 1 ' ' < 215.0 /
const auto ast = Opm::Action::Parser::parseCondition(std::vector {
"RPR"s, "1"s, " "s, "<"s, "215.0"s,
});

auto requisiteVectors = std::unordered_set<std::string>{};
ast->required_summary(requisiteVectors);

auto sortedVectors = std::vector<std::string> {
requisiteVectors.begin(), requisiteVectors.end()
};
std::sort(sortedVectors.begin(), sortedVectors.end());

const auto expected = std::vector {
"RPR"s,
};

BOOST_CHECK_EQUAL_COLLECTIONS(sortedVectors.begin(), sortedVectors.end(),
expected .begin(), expected .end());
}

BOOST_AUTO_TEST_CASE(Eval_RegionVector_In_Condition)
{
using namespace std::string_literals;

/// RPR 1 RE3 < 215.0 /
const auto actCond = Action::AST { std::vector {
"RPR"s, "1"s, "RE3"s, "<"s, "215.0"s,
}};

auto st = SummaryState { TimeService::now(), 0.0 };

st.update_region_var("RE3", "RPR", 1, 225.0); // > 215
st.update_region_var("RE3", "RPR", 2, 217.5); // > 215
st.update_region_var("RE3", "RPR", 3, 210.0); // < 215

auto wlm = WListManager{};

auto context = Action::Context {st, wlm};

{
const auto result = actCond.eval(context);
BOOST_CHECK_MESSAGE(! result.conditionSatisfied(),
"Condition must NOT be satisfied");
}

st.update_region_var("RE3", "RPR", 1, 205.0); // < 215

{
const auto result = actCond.eval(context);
BOOST_CHECK_MESSAGE(result.conditionSatisfied(),
"Condition must be satisfied");
}
}

BOOST_AUTO_TEST_CASE(Eval_RegionVector_In_Condition_Default_RegSet)
{
using namespace std::string_literals;

/// RPR 1 1* < 215.0 / -- RegSet = 1* => FIPNUM
const auto actCond = Action::AST { std::vector {
"RPR"s, "1"s, "1*"s, "<"s, "215.0"s,
}};

auto st = SummaryState { TimeService::now(), 0.0 };

st.update_region_var("RE3", "RPR", 1, 225.0); // > 215
st.update_region_var("RE3", "RPR", 2, 217.5); // > 215
st.update_region_var("RE3", "RPR", 3, 210.0); // < 215

st.update_region_var("NUM", "RPR", 1, 225.0); // > 215
st.update_region_var("NUM", "RPR", 2, 217.5); // > 215
st.update_region_var("NUM", "RPR", 3, 210.0); // < 215

auto wlm = WListManager{};

auto context = Action::Context {st, wlm};

{
const auto result = actCond.eval(context);
BOOST_CHECK_MESSAGE(! result.conditionSatisfied(),
"Condition must NOT be satisfied");
}

st.update_region_var("RE3", "RPR", 1, 205.0); // < 215
st.update_region_var("NUM", "RPR", 1, 205.0); // < 215

{
const auto result = actCond.eval(context);
BOOST_CHECK_MESSAGE(result.conditionSatisfied(),
"Condition must be satisfied");
}
}

BOOST_AUTO_TEST_CASE(Eval_RegionVector_In_Condition_Default_RegSet_2)
{
using namespace std::string_literals;

/// RPR 1 ' ' < 215.0 / -- RegSet = ' ' => FIPNUM
const auto actCond = Action::AST { std::vector {
"RPR"s, "1"s, " "s, "<"s, "215.0"s,
}};

auto st = SummaryState { TimeService::now(), 0.0 };

st.update_region_var("RE3", "RPR", 1, 225.0); // > 215
st.update_region_var("RE3", "RPR", 2, 217.5); // > 215
st.update_region_var("RE3", "RPR", 3, 210.0); // < 215

st.update_region_var("NUM", "RPR", 1, 225.0); // > 215
st.update_region_var("NUM", "RPR", 2, 217.5); // > 215
st.update_region_var("NUM", "RPR", 3, 210.0); // < 215

auto wlm = WListManager{};

auto context = Action::Context {st, wlm};

{
const auto result = actCond.eval(context);
BOOST_CHECK_MESSAGE(! result.conditionSatisfied(),
"Condition must NOT be satisfied");
}

st.update_region_var("RE3", "RPR", 1, 205.0); // < 215
st.update_region_var("NUM", "RPR", 1, 205.0); // < 215

{
const auto result = actCond.eval(context);
BOOST_CHECK_MESSAGE(result.conditionSatisfied(),
"Condition must be satisfied");
}
}

0 comments on commit 3053b04

Please sign in to comment.