Merge pull request #2929 from bska/internalise-interreg-smry-nodes

Make SummaryConfig Nodes for Inter-Region Flows
This commit is contained in:
Joakim Hove 2022-01-20 17:17:20 +01:00 committed by GitHub
commit 49c10378bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 347 additions and 92 deletions

View File

@ -37,6 +37,17 @@ namespace Opm { namespace EclIO {
bool isFormatted(const std::string& filename); bool isFormatted(const std::string& filename);
bool is_number(const std::string& numstr); bool is_number(const std::string& numstr);
/// Compute the linearly combined summary vector ID number from two
/// constituents.
///
/// Constituents are *typically* one-based region IDs, but at least one
/// of the two could be a component ID too.
int combineSummaryNumbers(const int n1, const int n2);
/// Split a combined summary vector ID ('NUMS' entry) into its original
/// two constituent IDs.
std::tuple<int,int> splitSummaryNumber(const int n);
std::tuple<int, int> block_size_data_binary(eclArrType arrType); std::tuple<int, int> block_size_data_binary(eclArrType arrType);
std::tuple<int, int, int> block_size_data_formatted(eclArrType arrType); std::tuple<int, int, int> block_size_data_formatted(eclArrType arrType);

View File

@ -344,7 +344,7 @@ public:
case FieldProps::GetStatus::MISSING_KEYWORD: case FieldProps::GetStatus::MISSING_KEYWORD:
throw std::out_of_range("No such keyword in deck: " + keyword); throw std::out_of_range("No such keyword in deck: " + keyword);
case FieldProps::GetStatus::NOT_SUPPPORTED_KEYWORD: case FieldProps::GetStatus::NOT_SUPPPORTED_KEYWORD:
throw std::logic_error("The kewyord " + keyword + " is not supported"); throw std::logic_error("The keyword " + keyword + " is not supported");
} }
} }

View File

@ -17,6 +17,34 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>. along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <opm/input/eclipse/EclipseState/SummaryConfig/SummaryConfig.hpp>
#include <opm/io/eclipse/EclUtil.hpp>
#include <opm/common/utility/OpmInputError.hpp>
#include <opm/common/utility/shmatch.hpp>
#include <opm/input/eclipse/EclipseState/Aquifer/AquiferConfig.hpp>
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
#include <opm/input/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/input/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
#include <opm/input/eclipse/EclipseState/Grid/GridDims.hpp>
#include <opm/input/eclipse/Schedule/Group/Group.hpp>
#include <opm/input/eclipse/Schedule/Network/ExtNetwork.hpp>
#include <opm/input/eclipse/Schedule/Schedule.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp>
#include <opm/input/eclipse/Schedule/Well/Connection.hpp>
#include <opm/input/eclipse/Schedule/Well/WellConnections.hpp>
#include <opm/input/eclipse/Parser/ErrorGuard.hpp>
#include <opm/input/eclipse/Parser/ParseContext.hpp>
#include <opm/input/eclipse/Deck/Deck.hpp>
#include <opm/input/eclipse/Deck/DeckItem.hpp>
#include <opm/input/eclipse/Deck/DeckKeyword.hpp>
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
#include <opm/input/eclipse/Deck/DeckSection.hpp>
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <iostream> #include <iostream>
@ -25,37 +53,14 @@
#include <set> #include <set>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <tuple>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <utility>
#include <vector> #include <vector>
#include <fmt/format.h> #include <fmt/format.h>
#include <opm/input/eclipse/Parser/ParseContext.hpp>
#include <opm/input/eclipse/Parser/ErrorGuard.hpp>
#include <opm/common/utility/OpmInputError.hpp>
#include <opm/common/utility/shmatch.hpp>
#include <opm/input/eclipse/Deck/Deck.hpp>
#include <opm/input/eclipse/Deck/DeckItem.hpp>
#include <opm/input/eclipse/Deck/DeckKeyword.hpp>
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
#include <opm/input/eclipse/Deck/DeckSection.hpp>
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
#include <opm/input/eclipse/EclipseState/Aquifer/AquiferConfig.hpp>
#include <opm/input/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/input/eclipse/EclipseState/Grid/GridDims.hpp>
#include <opm/input/eclipse/Schedule/Group/Group.hpp>
#include <opm/input/eclipse/Schedule/Network/ExtNetwork.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp>
#include <opm/input/eclipse/Schedule/Schedule.hpp>
#include <opm/input/eclipse/Schedule/Well/Connection.hpp>
#include <opm/input/eclipse/Schedule/Well/WellConnections.hpp>
#include <opm/input/eclipse/EclipseState/SummaryConfig/SummaryConfig.hpp>
#include <opm/input/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
namespace Opm { namespace Opm {
namespace { namespace {
@ -218,6 +223,11 @@ struct SummaryConfigContext {
bool is_rate(const std::string& keyword) { bool is_rate(const std::string& keyword) {
static const keyword_set ratekw { static const keyword_set ratekw {
"OPR", "GPR", "WPR", "GLIR", "LPR", "NPR", "CPR", "VPR", "TPR", "TPC", "OPR", "GPR", "WPR", "GLIR", "LPR", "NPR", "CPR", "VPR", "TPR", "TPC",
"OFR", "OFR+", "OFR-",
"GFR", "GFR+", "GFR-",
"WFR", "WFR+", "WFR-",
"OPGR", "GPGR", "WPGR", "VPGR", "OPGR", "GPGR", "WPGR", "VPGR",
"OPRH", "GPRH", "WPRH", "LPRH", "OPRH", "GPRH", "WPRH", "LPRH",
"OVPR", "GVPR", "WVPR", "OVPR", "GVPR", "WVPR",
@ -233,7 +243,10 @@ struct SummaryConfigContext {
"AQR", "AQRG", "NQR", "AQR", "AQRG", "NQR",
}; };
return is_in_set(ratekw, keyword.substr(1)) || (keyword.length() > 4 && is_in_set({"TPR","TPC","TIR","TIC"}, keyword.substr(1,3)));; return is_in_set(ratekw, keyword.substr(1))
|| ((keyword.length() > 4) &&
is_in_set({ "TPR", "TPC", "TIR", "TIC" },
keyword.substr(1, 3)));
} }
bool is_ratio(const std::string& keyword) { bool is_ratio(const std::string& keyword) {
@ -252,13 +265,20 @@ struct SummaryConfigContext {
"WPTH", "OPTH", "GPTH", "LPTH", "WPTH", "OPTH", "GPTH", "LPTH",
"GPTS", "OPTS", "GPTF", "OPTF", "GPTS", "OPTS", "GPTF", "OPTF",
"OFT", "OFT+", "OFT-", "OFTL", "OFTG",
"GFT", "GFT+", "GFT-", "GFTL", "GFTG",
"WFT", "WFT+", "WFT-",
"WIT", "OIT", "GIT", "LIT", "NIT", "CIT", "VIT", "TIT", "WIT", "OIT", "GIT", "LIT", "NIT", "CIT", "VIT", "TIT",
"WITH", "OITH", "GITH", "WVIT", "OVIT", "GVIT", "WITH", "OITH", "GITH", "WVIT", "OVIT", "GVIT",
"AQT", "AQTG", "NQT", "AQT", "AQTG", "NQT",
}; };
return is_in_set(totalkw, keyword.substr(1)) || (keyword.length() > 4 && is_in_set({"TPT","TIT"}, keyword.substr(1,3))); return is_in_set(totalkw, keyword.substr(1))
|| ((keyword.length() > 4) &&
is_in_set({ "TPT", "TIT" },
keyword.substr(1, 3)));
} }
bool is_count(const std::string& keyword) { bool is_count(const std::string& keyword) {
@ -293,15 +313,27 @@ struct SummaryConfigContext {
return keyword == "WPIL"; return keyword == "WPIL";
} }
bool is_region_to_region(const std::string& keyword) bool is_supported_region_to_region(const std::string& keyword)
{ {
static const auto rate = std::regex { R"(R[OGWEK]F[RT][-+GL]?)" }; static const auto supported_kw = std::regex { R"(R[OGW]F[RT][-+GL]?)" };
static const auto ngl = std::regex { R"(RNLF[RT][-+]?)" };
// R[OGW]F[RT][-+GL]? (e.g., "ROFTG", "RGFR+", or "RWFT") // R[OGW]F[RT][-+GL]? (e.g., "ROFTG", "RGFR+", or "RWFT")
// RNLF[RT].? (e.g., "RNLFR-" or "RNLFT") return std::regex_match(keyword, supported_kw);
return std::regex_match(keyword, rate) }
|| std::regex_match(keyword, ngl);
bool is_unsupported_region_to_region(const std::string& keyword)
{
static const auto unsupported_kw = std::regex { R"(R([EK]|NL)F[RT][-+]?)" };
// R[EK]F[RT][-+]? (e.g., "REFT" or "RKFR+")
// RNLF[RT][-+]? (e.g., "RNLFR-" or "RNLFT")
return std::regex_match(keyword, unsupported_kw);
}
bool is_region_to_region(const std::string& keyword)
{
return is_supported_region_to_region (keyword)
|| is_unsupported_region_to_region(keyword);
} }
bool is_aquifer(const std::string& keyword) bool is_aquifer(const std::string& keyword)
@ -799,52 +831,129 @@ inline void keywordB( SummaryConfig::keyword_list& list,
} }
} }
inline void keywordR2R( SummaryConfig::keyword_list& /* list */, inline std::optional<std::string>
const ParseContext& parseContext, establishRegionContext(const DeckKeyword& keyword,
ErrorGuard& errors, const FieldPropsManager& field_props,
const DeckKeyword& keyword) const ParseContext& parseContext,
ErrorGuard& errors,
SummaryConfigContext& context)
{ {
const auto& location = keyword.location(); auto region_name = std::string { "FIPNUM" };
std::string msg_fmt = "Region to region summary keyword {keyword} is ignored\n"
"In {file} line {line}"; if (keyword.name().size() > 5) {
parseContext.handleError(ParseContext::SUMMARY_UNHANDLED_KEYWORD, msg_fmt, location, errors); region_name = "FIP" + keyword.name().substr(5, 3);
if (! field_props.has_int(region_name)) {
const auto msg_fmt =
fmt::format("Problem with summary keyword {{keyword}}\n"
"In {{file}} line {{line}}\n"
"FIP region {} not defined in "
"REGIONS section - {{keyword}} ignored", region_name);
parseContext.handleError(ParseContext::SUMMARY_INVALID_FIPNUM,
msg_fmt, keyword.location(), errors);
return std::nullopt;
}
}
if (context.regions.count(region_name) == 0) {
const auto& fipnum = field_props.get_int(region_name);
context.regions.emplace(std::piecewise_construct,
std::forward_as_tuple(region_name),
std::forward_as_tuple(fipnum.begin(), fipnum.end()));
}
return { region_name };
}
inline void keywordR2R_unsupported(const DeckKeyword& keyword,
const ParseContext& parseContext,
ErrorGuard& errors)
{
const auto msg_fmt = std::string {
"Region to region summary keyword {keyword} is ignored\n"
"In {file} line {line}"
};
parseContext.handleError(ParseContext::SUMMARY_UNHANDLED_KEYWORD,
msg_fmt, keyword.location(), errors);
}
inline void keywordR2R(const DeckKeyword& keyword,
const FieldPropsManager& field_props,
const ParseContext& parseContext,
ErrorGuard& errors,
SummaryConfigContext& context,
SummaryConfig::keyword_list& list)
{
if (is_unsupported_region_to_region(keyword.name())) {
keywordR2R_unsupported(keyword, parseContext, errors);
}
if (is_udq(keyword.name())) {
throw std::invalid_argument {
"Inter-Region quantity '"
+ keyword.name() + "' "
+ "cannot be a user-defined quantity"
};
}
const auto region_name = establishRegionContext(keyword, field_props,
parseContext, errors,
context);
if (! region_name.has_value()) {
return;
}
auto param = SummaryConfigNode {
keyword.name(), SummaryConfigNode::Category::Region, keyword.location()
}
.parameterType(parseKeywordType(keyword.name()))
.fip_region(region_name.value())
.isUserDefined(false);
// Expected format:
//
// ROFT
// 1 2 /
// 1 4 /
// /
for (const auto& record : keyword) {
// We *intentionally* record/use one-based region IDs here.
const auto r1 = record.getItem("REGION1").get<int>(0);
const auto r2 = record.getItem("REGION2").get<int>(0);
list.push_back(param.number(EclIO::combineSummaryNumbers(r1, r2)));
}
} }
inline void keywordR( SummaryConfig::keyword_list& list, inline void keywordR(SummaryConfig::keyword_list& list,
SummaryConfigContext& context, SummaryConfigContext& context,
const DeckKeyword& deck_keyword, const DeckKeyword& deck_keyword,
const Schedule& schedule, const Schedule& schedule,
const FieldPropsManager& field_props, const FieldPropsManager& field_props,
const ParseContext& parseContext, const ParseContext& parseContext,
ErrorGuard& errors ) { ErrorGuard& errors)
{
auto keyword = deck_keyword.name(); const auto keyword = deck_keyword.name();
if( is_region_to_region(keyword) ) { if (is_region_to_region(keyword)) {
keywordR2R( list, parseContext, errors, deck_keyword ); keywordR2R(deck_keyword, field_props, parseContext, errors, context, list);
return; return;
} }
std::string region_name = "FIPNUM";
if (keyword.size() > 5) { const auto region_name = establishRegionContext(deck_keyword, field_props,
region_name = "FIP" + keyword.substr(5,3); parseContext, errors,
if (!field_props.has_int(region_name)) { context);
std::string msg_fmt = fmt::format("Problem with summary keyword {{keyword}}\n"
"In {{file}} line {{line}}\n" if (! region_name.has_value()) {
"FIP region {} not defined in REGIONS section - {{keyword}} ignored", region_name); return;
parseContext.handleError(ParseContext::SUMMARY_INVALID_FIPNUM, msg_fmt, deck_keyword.location(), errors);
return;
}
}
if (context.regions.count(region_name) == 0) {
const auto& fipnum = field_props.get_int(region_name);
context.regions.emplace( region_name, std::set<int>{ fipnum.begin(), fipnum.end()});
} }
const auto& item = deck_keyword.getDataRecord().getDataItem(); const auto& item = deck_keyword.getDataRecord().getDataItem();
std::vector<int> regions; std::vector<int> regions;
/* /*
Assume that the FIPNUM array contains the values {1,2,4}; i.e. the maximum Assume that the FIPNUM array contains the values {1,2,4}; i.e. the maximum
value is 4 and the value 3 is missing. Values which are too large, i.e. > value is 4 and the value 3 is missing. Values which are too large, i.e. >
@ -863,12 +972,12 @@ inline void keywordR( SummaryConfig::keyword_list& list,
if (item.data_size() > 0) { if (item.data_size() > 0) {
for (const auto& region_id : item.getData<int>()) { for (const auto& region_id : item.getData<int>()) {
const auto& region_set = context.regions.at(region_name); const auto& region_set = context.regions.at(region_name.value());
auto max_iter = region_set.rbegin(); auto max_iter = region_set.rbegin();
if (region_id > *max_iter) { if (region_id > *max_iter) {
std::string msg_fmt = fmt::format("Problem with summary keyword {{keyword}}\n" std::string msg_fmt = fmt::format("Problem with summary keyword {{keyword}}\n"
"In {{file}} line {{line}}\n" "In {{file}} line {{line}}\n"
"FIP region {} not present in {} - ignored", region_id, region_name); "FIP region {} not present in {} - ignored", region_id, region_name.value());
parseContext.handleError(ParseContext::SUMMARY_REGION_TOO_LARGE, msg_fmt, deck_keyword.location(), errors); parseContext.handleError(ParseContext::SUMMARY_REGION_TOO_LARGE, msg_fmt, deck_keyword.location(), errors);
continue; continue;
} }
@ -876,14 +985,15 @@ inline void keywordR( SummaryConfig::keyword_list& list,
if (region_set.count(region_id) == 0) { if (region_set.count(region_id) == 0) {
std::string msg_fmt = fmt::format("Problem with summary keyword {{keyword}}\n" std::string msg_fmt = fmt::format("Problem with summary keyword {{keyword}}\n"
"In {{file}} line {{line}}\n" "In {{file}} line {{line}}\n"
"FIP region {} not present in {} - will use 0", region_id, region_name); "FIP region {} not present in {} - will use 0", region_id, region_name.value());
parseContext.handleError(ParseContext::SUMMARY_EMPTY_REGION, msg_fmt, deck_keyword.location(), errors); parseContext.handleError(ParseContext::SUMMARY_EMPTY_REGION, msg_fmt, deck_keyword.location(), errors);
} }
regions.push_back( region_id ); regions.push_back( region_id );
} }
} else { }
for (const auto& region_id : context.regions.at(region_name)) else {
for (const auto& region_id : context.regions.at(region_name.value()))
regions.push_back( region_id ); regions.push_back( region_id );
} }
@ -899,17 +1009,16 @@ inline void keywordR( SummaryConfig::keyword_list& list,
list.push_back( copt_node ); list.push_back( copt_node );
} }
} }
} }
auto param = SummaryConfigNode { auto param = SummaryConfigNode {
keyword, SummaryConfigNode::Category::Region, deck_keyword.location() keyword, SummaryConfigNode::Category::Region, deck_keyword.location()
} }
.fip_region( region_name ) .parameterType(parseKeywordType(keyword))
.fip_region( region_name.value() )
.isUserDefined( is_udq(keyword) ); .isUserDefined( is_udq(keyword) );
for( const auto& region : regions ) for (const auto& region : regions)
list.push_back( param.number( region ) ); list.push_back( param.number( region ) );
} }

View File

@ -31,10 +31,15 @@ namespace Opm{
namespace { namespace {
bool is_total(const std::string& key) { bool is_total(const std::string& key) {
static const std::vector<std::string> totals = {"OPT" , "GPT" , "WPT" , "GIT", "WIT", "OPTF" , "OPTS" , "OIT" , "OVPT" , "OVIT" , "MWT" , static const std::vector<std::string> totals = {
"WVPT" , "WVIT" , "GMT" , "GPTF" , "SGT" , "GST" , "FGT" , "GCT" , "GIMT" , "OPT" , "GPT" , "WPT" , "GIT", "WIT", "OPTF" , "OPTS" , "OIT" , "OVPT" , "OVIT" , "MWT" ,
"WGPT" , "WGIT" , "EGT" , "EXGT" , "GVPT" , "GVIT" , "LPT" , "VPT" , "VIT" , "NPT" , "NIT", "WVPT" , "WVIT" , "GMT" , "GPTF" , "SGT" , "GST" , "FGT" , "GCT" , "GIMT" ,
"TPT", "TIT", "CPT", "CIT", "SPT", "SIT", "EPT", "EIT", "TPTHEA", "TITHEA"}; "WGPT" , "WGIT" , "EGT" , "EXGT" , "GVPT" , "GVIT" , "LPT" , "VPT" , "VIT" , "NPT" , "NIT",
"TPT", "TIT", "CPT", "CIT", "SPT", "SIT", "EPT", "EIT", "TPTHEA", "TITHEA",
"OFT", "OFT+", "OFT-", "OFTG", "OFTL",
"GFT", "GFT+", "GFT-", "GFTG", "GFTL",
"WFT", "WFT+", "WFT-",
};
auto sep_pos = key.find(':'); auto sep_pos = key.find(':');

View File

@ -1220,8 +1220,7 @@ std::string ESmry::makeKeyString(const std::string& keywordArg, const std::strin
if ((str34 == "FR") || (str34 == "FT") || (str45 == "FR") || (str45 == "FT")) { if ((str34 == "FR") || (str34 == "FT") || (str45 == "FR") || (str45 == "FT")) {
// NUMS = R1 + 32768*(R2 + 10) // NUMS = R1 + 32768*(R2 + 10)
const auto r1 = num % (1UL << 15); const auto& [r1, r2] = splitSummaryNumber(num);
const auto r2 = (num / (1UL << 15)) - 10;
return fmt::format("{}:{}-{}", keywordArg, r1, r2); return fmt::format("{}:{}-{}", keywordArg, r1, r2);
} }

View File

@ -103,6 +103,18 @@ bool Opm::EclIO::isEOF(std::fstream* fileH)
} }
} }
int Opm::EclIO::combineSummaryNumbers(const int n1, const int n2)
{
return n1 + (1 << 15)*(n2 + 10);
}
std::tuple<int, int> Opm::EclIO::splitSummaryNumber(const int n)
{
const auto n1 = n % (1 << 15);
const auto n2 = (n / (1 << 15)) - 10;
return { n1, n2 };
}
std::tuple<int, int> Opm::EclIO::block_size_data_binary(eclArrType arrType) std::tuple<int, int> Opm::EclIO::block_size_data_binary(eclArrType arrType)
{ {

View File

@ -388,6 +388,7 @@ ROFTL
ROFTG ROFTG
1 2/ 1 2/
3 4/ 3 4/
1 3/
/ /
RGFT RGFT
5 6/ 5 6/
@ -441,17 +442,118 @@ RWFR-
/ /
RWIP RWIP
/ /
)" };
ParseContext parseContext;
const auto summary = createSummary(input, parseContext);
{
const auto expect_kw = std::vector<std::string> {
"ROFT", "ROFT+", "ROFT-", "ROFR", "ROFR+", "ROFR-", "ROFTL", "ROFTG",
"RGFT", "RGFT+", "RGFT-", "RGFR", "RGFR+", "RGFR-", "RGFTL", "RGFTG",
"RGFT", "RGFT+", "RGFT-", "RGFR", "RGFR+", "RGFR-",
};
for (const auto& kw : expect_kw) {
BOOST_CHECK_MESSAGE(summary.hasKeyword(kw),
"SummaryConfig MUST have keyword '" << kw << "'");
}
}
{
const auto kw = summary.keywords("ROFT");
BOOST_CHECK_EQUAL(kw.size(), 2);
BOOST_CHECK_MESSAGE(kw[1].namedEntity().empty(),
"ROFT vector must NOT have an associated named entity");
BOOST_CHECK_MESSAGE(kw[0].type() == SummaryConfigNode::Type::Total,
"ROFT must be a Cumulative Total");
BOOST_CHECK_MESSAGE(kw[1].category() == SummaryConfigNode::Category::Region,
"ROFT must be a Region vector");
const auto expect_number = std::vector<int> {
393'217, // 1 2
458'755, // 3 4
};
const auto n1 = kw[0].number();
const auto n2 = kw[1].number();
BOOST_CHECK_MESSAGE(((n1 == expect_number[0]) && (n2 == expect_number[1])) ||
((n2 == expect_number[0]) && (n1 == expect_number[1])),
R"(ROFT 'NUMS' must match expected set)");
}
{
const auto kw = summary.keywords("RGFR-");
BOOST_CHECK_EQUAL(kw.size(), 2);
BOOST_CHECK_MESSAGE(kw[1].namedEntity().empty(),
"RGFR- vector must NOT have an associated named entity");
BOOST_CHECK_MESSAGE(kw[0].type() == SummaryConfigNode::Type::Rate,
"RGFR- must be a Rate");
BOOST_CHECK_MESSAGE(kw[1].category() == SummaryConfigNode::Category::Region,
"RGFR- must be a Region vector");
const auto expect_number = std::vector<int> {
524'293, // 5 6
589'831, // 7 8
};
const auto n1 = kw[0].number();
const auto n2 = kw[1].number();
BOOST_CHECK_MESSAGE(((n1 == expect_number[0]) && (n2 == expect_number[1])) ||
((n2 == expect_number[0]) && (n1 == expect_number[1])),
R"(RGFR- 'NUMS' must match expected set)");
}
{
const auto kw = summary.keywords("ROFTG");
BOOST_CHECK_EQUAL(kw.size(), 3);
BOOST_CHECK_MESSAGE(kw[1].namedEntity().empty(),
"ROFTG vector must NOT have an associated named entity");
BOOST_CHECK_MESSAGE(kw[0].type() == SummaryConfigNode::Type::Total,
"ROFTG must be a Cumulative Total");
BOOST_CHECK_MESSAGE(kw[1].category() == SummaryConfigNode::Category::Region,
"ROFTG must be a Region vector");
const auto expect_number = std::vector<int> {
393'217, // 1 2
458'755, // 3 4
425'985, // 1 3
};
const auto actual = std::vector<int> {
kw[0].number(),
kw[1].number(),
kw[2].number(),
};
BOOST_CHECK_MESSAGE(std::is_permutation(actual .begin(), actual .end(),
expect_number.begin(), expect_number.end()),
R"(ROFTG 'NUMS' must match expected set)");
}
}
BOOST_AUTO_TEST_CASE(region2region_unsupported) {
const auto input = std::string { R"(REFR-
2 3 /
/
RKFT
2 3 /
/
)" }; )" };
ParseContext parseContext; ParseContext parseContext;
parseContext.update(ParseContext::SUMMARY_UNHANDLED_KEYWORD, InputError::IGNORE);
const auto summary = createSummary( input, parseContext );
const auto keywords = { "RWIP", "RWIP", "RWIP" };
const auto names = sorted_keywords( summary );
BOOST_CHECK_EQUAL_COLLECTIONS(keywords.begin(), keywords.end(),
names.begin(), names.end() );
parseContext.update(ParseContext::SUMMARY_UNHANDLED_KEYWORD, InputError::THROW_EXCEPTION); parseContext.update(ParseContext::SUMMARY_UNHANDLED_KEYWORD, InputError::THROW_EXCEPTION);
BOOST_CHECK_THROW( createSummary(input, parseContext), OpmInputError); BOOST_CHECK_THROW( createSummary(input, parseContext), OpmInputError);

View File

@ -530,3 +530,20 @@ BOOST_AUTO_TEST_CASE(TestEcl_Write_CHAR) {
BOOST_CHECK(std::get<1>(arrayList[0]) == Opm::EclIO::C0NN); BOOST_CHECK(std::get<1>(arrayList[0]) == Opm::EclIO::C0NN);
} }
} }
BOOST_AUTO_TEST_CASE(CombinedVectorID) {
BOOST_CHECK_EQUAL(combineSummaryNumbers(1, 2), 393'217);
BOOST_CHECK_EQUAL(combineSummaryNumbers(10, 1), 360'458);
{
const auto [n1, n2] = splitSummaryNumber(393'217);
BOOST_CHECK_EQUAL(n1, 1);
BOOST_CHECK_EQUAL(n2, 2);
}
{
const auto [n1, n2] = splitSummaryNumber(360'458);
BOOST_CHECK_EQUAL(n1, 10);
BOOST_CHECK_EQUAL(n2, 1);
}
}