Add summary configuration for WxxxL and CxxxL completion keywords
This commit is contained in:
parent
e625623e49
commit
b9b918defa
@ -274,6 +274,43 @@ namespace {
|
||||
return (keyword[0] == 'A') && (keyword != "ALL");
|
||||
}
|
||||
|
||||
bool is_connection_completion(const std::string& keyword)
|
||||
{
|
||||
if (keyword[0] != 'C')
|
||||
return false;
|
||||
|
||||
if (keyword.back() != 'L')
|
||||
return false;
|
||||
|
||||
if (is_udq(keyword))
|
||||
return false;
|
||||
|
||||
if (keyword.size() != 5)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_well_completion(const std::string& keyword)
|
||||
{
|
||||
if (keyword[0] != 'W')
|
||||
return false;
|
||||
|
||||
if (keyword.back() != 'L')
|
||||
return false;
|
||||
|
||||
if (is_liquid_phase(keyword))
|
||||
return false;
|
||||
|
||||
if (is_udq(keyword))
|
||||
return false;
|
||||
|
||||
if (keyword == "WMCTL")
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_node_keyword(const std::string& keyword)
|
||||
{
|
||||
static const auto nodekw = keyword_set {
|
||||
@ -395,6 +432,7 @@ inline void keywordAquifer( SummaryConfig::keyword_list& list,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline std::array< int, 3 > getijk( const DeckRecord& record ) {
|
||||
return {{
|
||||
record.getItem( "I" ).get< int >( 0 ) - 1,
|
||||
@ -403,6 +441,90 @@ inline std::array< int, 3 > getijk( const DeckRecord& record ) {
|
||||
}};
|
||||
}
|
||||
|
||||
|
||||
inline void keywordCL( SummaryConfig::keyword_list& list,
|
||||
const ParseContext& parseContext,
|
||||
ErrorGuard& errors,
|
||||
const DeckKeyword& keyword,
|
||||
const Schedule& schedule ,
|
||||
const GridDims& dims)
|
||||
{
|
||||
auto node = SummaryConfigNode{keyword.name(), SummaryConfigNode::Category::Connection, keyword.location()};
|
||||
node.parameterType( parseKeywordType(keyword.name()) );
|
||||
node.isUserDefined( is_udq(keyword.name()) );
|
||||
|
||||
for (const auto& record : keyword) {
|
||||
const auto& pattern = record.getItem(0).get<std::string>(0);
|
||||
auto well_names = schedule.wellNames( pattern, schedule.size() - 1 );
|
||||
|
||||
|
||||
if( well_names.empty() )
|
||||
handleMissingWell( parseContext, errors, keyword.location(), pattern );
|
||||
|
||||
const auto ijk_defaulted = record.getItem( 1 ).defaultApplied( 0 );
|
||||
for (const auto& wname : well_names) {
|
||||
const auto& well = schedule.getWellatEnd(wname);
|
||||
const auto& all_connections = well.getConnections();
|
||||
|
||||
node.namedEntity( wname );
|
||||
if (ijk_defaulted) {
|
||||
for (const auto& conn : all_connections)
|
||||
list.push_back( node.number( 1 + conn.global_index()));
|
||||
} else {
|
||||
const auto& ijk = getijk(record);
|
||||
auto global_index = dims.getGlobalIndex(ijk[0], ijk[1], ijk[2]);
|
||||
|
||||
if (all_connections.hasGlobalIndex(global_index)) {
|
||||
const auto& conn = all_connections.getFromGlobalIndex(global_index);
|
||||
list.push_back( node.number( 1 + conn.global_index()));
|
||||
} else {
|
||||
const auto& ijk = getijk(record);
|
||||
std::string msg = fmt::format("Problem with keyword {{keyword}}\n"
|
||||
"In {{file}} line {{line}}\n"
|
||||
"Connnection ({},{},{}) not defined for well {} ", ijk[0], ijk[1], ijk[2], wname);
|
||||
parseContext.handleError( ParseContext::SUMMARY_UNHANDLED_KEYWORD, msg, keyword.location(), errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void keywordWL( SummaryConfig::keyword_list& list,
|
||||
const ParseContext& parseContext,
|
||||
ErrorGuard& errors,
|
||||
const DeckKeyword& keyword,
|
||||
const Schedule& schedule )
|
||||
{
|
||||
for (const auto& record : keyword) {
|
||||
const auto& pattern = record.getItem(0).get<std::string>(0);
|
||||
const int completion = record.getItem(1).get<int>(0);
|
||||
auto well_names = schedule.wellNames( pattern, schedule.size() - 1 );
|
||||
|
||||
// We add the completion number both the extra field which contains
|
||||
// parsed data from the keywordname - i.e. WOPRL__8 and also to the
|
||||
// numeric member which will be written to the NUMS field.
|
||||
auto node = SummaryConfigNode{ fmt::format("{}{:_>3}", keyword.name(), completion), SummaryConfigNode::Category::Well, keyword.location()};
|
||||
node.parameterType( parseKeywordType(keyword.name()) );
|
||||
node.isUserDefined( is_udq(keyword.name()) );
|
||||
node.number(completion);
|
||||
|
||||
if( well_names.empty() )
|
||||
handleMissingWell( parseContext, errors, keyword.location(), pattern );
|
||||
|
||||
for (const auto& wname : well_names) {
|
||||
const auto& well = schedule.getWellatEnd(wname);
|
||||
if (well.hasCompletion(completion))
|
||||
list.push_back( node.namedEntity( wname ) );
|
||||
else {
|
||||
std::string msg = fmt::format("Problem with keyword {{keyword}}\n"
|
||||
"In {{file}} line {{line}}\n"
|
||||
"Completion number {} not defined for well {} ", completion, wname);
|
||||
parseContext.handleError( ParseContext::SUMMARY_UNHANDLED_KEYWORD, msg, keyword.location(), errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void keywordW( SummaryConfig::keyword_list& list,
|
||||
const std::string& keyword,
|
||||
KeywordLocation loc,
|
||||
@ -422,25 +544,8 @@ inline void keywordW( SummaryConfig::keyword_list& list,
|
||||
ErrorGuard& errors,
|
||||
const DeckKeyword& keyword,
|
||||
const Schedule& schedule ) {
|
||||
/*
|
||||
Two step check for whether to discard this keyword as unsupported:
|
||||
|
||||
1. Completion quantity keywords are currently not supported. These are
|
||||
well summary keywords, apart from "WMCTL" and "WPIL", that end in 'L'.
|
||||
|
||||
2. If the keyword is a UDQ keyword there is no convention enforced to
|
||||
the last character, and in that case it is treated as a normal well
|
||||
keyword anyways.
|
||||
*/
|
||||
if (keyword.name().back() == 'L') {
|
||||
if (! (is_control_mode(keyword.name()) || is_liquid_phase(keyword.name()) || is_udq(keyword.name()))) {
|
||||
const auto& location = keyword.location();
|
||||
std::string msg = "Unsupported summary output keyword {}\n"
|
||||
"In {file} line {line}";
|
||||
parseContext.handleError( ParseContext::SUMMARY_UNHANDLED_KEYWORD, msg, location, errors);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (is_well_completion(keyword.name()))
|
||||
return keywordWL(list, parseContext, errors, keyword, schedule);
|
||||
|
||||
auto param = SummaryConfigNode {
|
||||
keyword.name(), SummaryConfigNode::Category::Well, keyword.location()
|
||||
@ -681,6 +786,9 @@ inline void keywordMISC( SummaryConfig::keyword_list& list,
|
||||
const Schedule& schedule,
|
||||
const GridDims& dims) {
|
||||
|
||||
if (is_connection_completion(keyword.name()))
|
||||
return keywordCL(list, parseContext, errors, keyword, schedule, dims);
|
||||
|
||||
auto param = SummaryConfigNode {
|
||||
keyword.name(), SummaryConfigNode::Category::Connection, keyword.location()
|
||||
}
|
||||
@ -703,8 +811,8 @@ inline void keywordMISC( SummaryConfig::keyword_list& list,
|
||||
param.namedEntity(name);
|
||||
const auto& well = schedule.getWellatEnd(name);
|
||||
/*
|
||||
* we don't want to add completions that don't exist, so we iterate
|
||||
* over a well's completions regardless of the desired block is
|
||||
* we don't want to add connections that don't exist, so we iterate
|
||||
* over a well's connections regardless of the desired block is
|
||||
* defaulted or not
|
||||
*/
|
||||
for( const auto& connection : well.getConnections() ) {
|
||||
@ -1000,6 +1108,12 @@ inline void handleKW( SummaryConfig::keyword_list& list,
|
||||
// =====================================================================
|
||||
|
||||
SummaryConfigNode::Type parseKeywordType(std::string keyword) {
|
||||
if (is_well_completion(keyword))
|
||||
keyword.pop_back();
|
||||
|
||||
if (is_connection_completion(keyword))
|
||||
keyword.pop_back();
|
||||
|
||||
if (is_rate(keyword)) return SummaryConfigNode::Type::Rate;
|
||||
if (is_total(keyword)) return SummaryConfigNode::Type::Total;
|
||||
if (is_ratio(keyword)) return SummaryConfigNode::Type::Ratio;
|
||||
|
@ -666,21 +666,6 @@ BOOST_AUTO_TEST_CASE(FMWPA) {
|
||||
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( WOPRL ) {
|
||||
const std::string input = R"(
|
||||
WOPRL
|
||||
'W_1' 1 /
|
||||
'WX2' 2 /
|
||||
'W_3' 3 /
|
||||
/
|
||||
)";
|
||||
|
||||
ParseContext parseContext;
|
||||
parseContext.update(ParseContext::SUMMARY_UNHANDLED_KEYWORD, InputError::THROW_EXCEPTION);
|
||||
BOOST_CHECK_THROW(createSummary( input, parseContext ), OpmInputError);
|
||||
parseContext.update(ParseContext::SUMMARY_UNHANDLED_KEYWORD, InputError::IGNORE);
|
||||
BOOST_CHECK_NO_THROW( createSummary(input, parseContext ));
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( summary_require3DField ) {
|
||||
@ -1219,3 +1204,118 @@ ROPT_REG
|
||||
auto rpr = summary_config.keywords("RP*");
|
||||
BOOST_CHECK_EQUAL(rpr.size(), 3U);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( WOPRL ) {
|
||||
const std::string input1 = R"(
|
||||
WOPRL
|
||||
'W_1' 2 /
|
||||
'xxx' 2 /
|
||||
/
|
||||
)";
|
||||
|
||||
|
||||
const std::string input2 = R"(
|
||||
WOPRL
|
||||
'W_1' 2 /
|
||||
'W_1' 999 /
|
||||
/
|
||||
)";
|
||||
|
||||
ParseContext parseContext;
|
||||
// Invalid well
|
||||
parseContext.update(ParseContext::SUMMARY_UNKNOWN_WELL, InputError::THROW_EXCEPTION);
|
||||
BOOST_CHECK_THROW(createSummary( input1, parseContext ), OpmInputError);
|
||||
|
||||
// Invalid completion
|
||||
parseContext.update(ParseContext::SUMMARY_UNHANDLED_KEYWORD, InputError::THROW_EXCEPTION);
|
||||
BOOST_CHECK_THROW(createSummary( input2, parseContext ), OpmInputError);
|
||||
|
||||
|
||||
parseContext.update(ParseContext::SUMMARY_UNHANDLED_KEYWORD, InputError::IGNORE);
|
||||
parseContext.update(ParseContext::SUMMARY_UNKNOWN_WELL, InputError::IGNORE);
|
||||
const auto& summary_config1 = createSummary(input1, parseContext);
|
||||
BOOST_CHECK(summary_config1.hasKeyword("WOPRL__2"));
|
||||
BOOST_CHECK_EQUAL(summary_config1.size(), 1);
|
||||
|
||||
const auto& summary_config2 = createSummary(input2, parseContext );
|
||||
BOOST_CHECK(summary_config2.hasKeyword("WOPRL__2"));
|
||||
BOOST_CHECK(!summary_config2.hasKeyword("WOPRL999"));
|
||||
const auto& node = summary_config2[0];
|
||||
BOOST_CHECK_EQUAL( node.number(), 2 );
|
||||
BOOST_CHECK(node.type() == EclIO::SummaryNode::Type::Rate);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( COPRL ) {
|
||||
const std::string input1 = R"(
|
||||
COPRL
|
||||
'W_1' 3 7 2 /
|
||||
'xxx' 3 7 2 /
|
||||
/
|
||||
)";
|
||||
|
||||
|
||||
const std::string input2 = R"(
|
||||
COPRL
|
||||
'W_1' 3 7 2 /
|
||||
'W_1' 2 6 1 /
|
||||
/
|
||||
)";
|
||||
|
||||
const std::string input3 = R"(
|
||||
COPRL
|
||||
'W_1' /
|
||||
/
|
||||
)";
|
||||
|
||||
ParseContext parseContext;
|
||||
// Invalid well
|
||||
parseContext.update(ParseContext::SUMMARY_UNKNOWN_WELL, InputError::THROW_EXCEPTION);
|
||||
BOOST_CHECK_THROW(createSummary( input1, parseContext ), OpmInputError);
|
||||
|
||||
// Invalid connection
|
||||
parseContext.update(ParseContext::SUMMARY_UNHANDLED_KEYWORD, InputError::THROW_EXCEPTION);
|
||||
BOOST_CHECK_THROW(createSummary( input2, parseContext ), OpmInputError);
|
||||
|
||||
|
||||
parseContext.update(ParseContext::SUMMARY_UNHANDLED_KEYWORD, InputError::IGNORE);
|
||||
parseContext.update(ParseContext::SUMMARY_UNKNOWN_WELL, InputError::IGNORE);
|
||||
const auto& summary_config1 = createSummary(input1, parseContext);
|
||||
BOOST_CHECK(summary_config1.hasKeyword("COPRL"));
|
||||
BOOST_CHECK_EQUAL(summary_config1.size(), 1);
|
||||
|
||||
|
||||
EclipseGrid grid(10,10,10);
|
||||
const auto g1 = grid.getGlobalIndex(1,1,0) + 1;
|
||||
const auto g2 = grid.getGlobalIndex(1,1,1) + 1;
|
||||
const auto g3 = grid.getGlobalIndex(2,6,1) + 1;
|
||||
|
||||
const auto& summary_config2 = createSummary(input2, parseContext );
|
||||
BOOST_CHECK(summary_config2.hasKeyword("COPRL"));
|
||||
BOOST_CHECK_EQUAL( summary_config2.size(), 1);
|
||||
{
|
||||
const auto& node = summary_config2[0];
|
||||
BOOST_CHECK_EQUAL( node.number(), g3);
|
||||
BOOST_CHECK(node.type() == EclIO::SummaryNode::Type::Rate);
|
||||
}
|
||||
|
||||
|
||||
const auto& summary_config3 = createSummary(input3, parseContext );
|
||||
BOOST_CHECK(summary_config3.hasKeyword("COPRL"));
|
||||
BOOST_CHECK_EQUAL( summary_config3.size(), 3);
|
||||
{
|
||||
const auto& node = summary_config3[0];
|
||||
BOOST_CHECK_EQUAL( node.number(), g1);
|
||||
}
|
||||
{
|
||||
const auto& node = summary_config3[1];
|
||||
BOOST_CHECK_EQUAL( node.number(), g2);
|
||||
}
|
||||
{
|
||||
const auto& node = summary_config3[2];
|
||||
BOOST_CHECK_EQUAL( node.number(), g3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user