Recognise Numbers as Part of UDQ Set Selector

Needed in order to support segment sets which, potentially, have
both a well name pattern and a segment number.

This change also means that we now support *parsing* block (cell)
UDQ sets like

    BPR 11 22 33

and that, in turn, means we detect unsupported UDQ types later than
we used to.  That also means that the error detection exception type
changes, so update affected unit tests accordingly.
This commit is contained in:
Bård Skaflestad
2023-01-11 11:21:32 +01:00
parent bd7de87ac2
commit 2109552335
3 changed files with 99 additions and 16 deletions

View File

@@ -166,8 +166,10 @@ make_udq_tokens(const std::vector<std::string>& string_tokens)
break;
}
auto next_type = Opm::UDQ::tokenType(string_tokens[token_index]);
if (next_type == Opm::UDQTokenType::ecl_expr) {
if (auto next_token_type = Opm::UDQ::tokenType(string_tokens[token_index]);
(next_token_type == Opm::UDQTokenType::ecl_expr) ||
(next_token_type == Opm::UDQTokenType::number))
{
const auto& select_token = string_tokens[token_index];
if (Opm::RawConsts::is_quote()(select_token[0])) {
selector.push_back(select_token.substr(1, select_token.size() - 2));

View File

@@ -21,15 +21,43 @@
#include <opm/common/utility/String.hpp>
#include <charconv>
#include <map>
#include <optional>
#include <regex>
#include <set>
#include <stdexcept>
#include <string>
#include <string_view>
#include <system_error>
#include <unordered_map>
#include <vector>
namespace {
std::string_view dequote(std::string_view s)
{
const auto b = s.find('\'');
if (b == std::string_view::npos) {
return s;
}
const auto e = s.find('\'', b + 1);
if (e == std::string_view::npos) {
throw std::invalid_argument {
"Invalid quoted string |" + std::string{s} + '|'
};
}
return { s.begin() + b + 1, e - b - 1 };
}
bool is_asterisk(std::string_view s)
{
const auto ast = std::regex { R"(\s*\*\s*)" };
return std::regex_match(s.begin(), s.end(), ast);
}
bool is_no_mix(const Opm::UDQVarType t)
{
return (t == Opm::UDQVarType::CONNECTION_VAR)
@@ -51,6 +79,48 @@ namespace {
;
}
bool is_wgname_set(const std::vector<std::string>& selector)
{
return selector.empty()
|| (selector.front().find("*") != std::string::npos);
}
bool is_single_segment_number(std::string_view segNum0)
{
auto segNum = dequote(segNum0);
if (segNum.empty()) {
// Not specified
return false;
}
auto result = 0;
auto [ptr, ec] { std::from_chars(segNum.data(), segNum.data() + segNum.size(), result) };
if ((ec == std::errc{}) && (ptr == segNum.data() + segNum.size())) {
// Segment number is "123", or "'-1'", or something similar.
return result > 0;
}
else if ((ec == std::errc::invalid_argument) && is_asterisk(segNum)) {
// Segment number is '*'. Treat as all segments.
return false;
}
else {
// Segment number is some unrecognized number string other than '*'.
throw std::invalid_argument {
"Invalid segment number string |" + std::string{segNum0} + '|'
};
}
}
bool is_segment_set(const std::vector<std::string>& selector)
{
return (selector.size() < std::vector<std::string>::size_type{2})
|| ! is_single_segment_number(selector[1])
|| selector.front().empty()
|| (selector.front().find("*") != std::string::npos);
}
const auto cmp_func = std::set<Opm::UDQTokenType> {
Opm::UDQTokenType::binary_cmp_eq,
Opm::UDQTokenType::binary_cmp_ne,
@@ -190,13 +260,28 @@ UDQVarType targetType(const std::string& keyword,
const std::vector<std::string>& selector)
{
const auto tt = targetType(keyword);
if ((tt == UDQVarType::WELL_VAR) || (tt == UDQVarType::GROUP_VAR)) {
if (selector.empty() || (selector.front().find("*") != std::string::npos)) {
return tt;
}
if ((tt == UDQVarType::NONE) || (tt == UDQVarType::FIELD_VAR)) {
// Field variables and "none" (e.g., TIME) are treated as scalar.
return UDQVarType::SCALAR;
}
return UDQVarType::SCALAR;
if (((tt == UDQVarType::WELL_VAR) || (tt == UDQVarType::GROUP_VAR))
&& !is_wgname_set(selector))
{
// Well/group variables that apply to a single well/group are
// treated as scalar.
return UDQVarType::SCALAR;
}
if ((tt == UDQVarType::SEGMENT_VAR) && !is_segment_set(selector)) {
// Segment variables that apply to a single segment in a single MS
// well are treated as scalar.
return UDQVarType::SCALAR;
}
// All other targets keep the type inferred from the keyword.
return tt;
}
UDQVarType varType(const std::string& keyword)

View File

@@ -181,16 +181,12 @@ BOOST_AUTO_TEST_CASE(TEST)
BOOST_CHECK_EQUAL( res4["P1"].get(), 1.00 );
BOOST_CHECK_EQUAL( res4["P2"].get(), 1.00 );
/*
This expression has a well set as target type, and involves group with
wildcard that is not supported by flow.
*/
BOOST_CHECK_THROW( UDQDefine(udqp, "WUWI2",0, location, {"GOPR", "G*", "*", "2.0"}), OpmInputError);
// This expression has a well set as target type, and involves group
// with wildcard that is not supported by flow.
BOOST_CHECK_THROW( UDQDefine(udqp, "GUPR2",0, location, {"GOPR", "G*", "*", "2.0"}), OpmInputError);
/*
UDQVarType == BLOCK is not yet supported.
*/
BOOST_CHECK_THROW( UDQDefine(udqp, "WUWI2",0, location, {"BPR", "1","1", "1", "*", "2.0"}), OpmInputError);
// UDQVarType == BLOCK is not yet supported.
BOOST_CHECK_THROW( UDQDefine(udqp, "BUPR2",0, location, {"BPR", "1","1", "1", "*", "2.0"}), std::invalid_argument);
}
BOOST_AUTO_TEST_CASE(MIX_SCALAR) {