diff --git a/src/opm/input/eclipse/EclipseState/SummaryConfig/SummaryConfig.cpp b/src/opm/input/eclipse/EclipseState/SummaryConfig/SummaryConfig.cpp index fcf658246..b8c584b60 100644 --- a/src/opm/input/eclipse/EclipseState/SummaryConfig/SummaryConfig.cpp +++ b/src/opm/input/eclipse/EclipseState/SummaryConfig/SummaryConfig.cpp @@ -225,8 +225,8 @@ struct SummaryConfigContext { static const keyword_set ratekw { "OPR", "GPR", "WPR", "GLIR", "LPR", "NPR", "CPR", "VPR", "TPR", "TPC", - "OFR", "OFR+", "OFR-", - "GFR", "GFR+", "GFR-", + "OFR", "OFRF", "OFRS", "OFR+", "OFR-", + "GFR", "GFRF", "GFRS", "GFR+", "GFR-", "WFR", "WFR+", "WFR-", "OPGR", "GPGR", "WPGR", "VPGR", @@ -252,8 +252,8 @@ struct SummaryConfigContext { bool is_ratio(const std::string& keyword) { static const keyword_set ratiokw { - "GLR", "GOR", "WCT", - "GLRH", "GORH", "WCTH", + "GLR" , "GOR" , "OGR", "WCT" , "WGR", + "GLRH", "GORH", "WCTH", }; return is_in_set(ratiokw, keyword.substr(1)); @@ -1099,63 +1099,67 @@ inline void keywordMISC( SummaryConfig::keyword_list& list, { const auto& kw = keyword.name(); - if (kw.size() > 5) { + if (kw.size() > std::string::size_type{5}) { // Easy check first--handles SUMMARY and SUMTHIN &c. return false; } const auto kw_whitelist = std::vector { - "SOFR", "SGFR", "SWFR", "SWCT", - "SPR", "SPRD", "SPRDH", "SPRDF", "SPRDA", + "SOFR" , "SOFRF", "SOFRS", + "SGFR" , "SGFRF", "SGFRS", + "SWFR" , + "SGOR" , "SOGR" , "SWCT" , "SWGR" , + "SPR" , "SPRD" , "SPRDH", "SPRDF", "SPRDA", }; return std::any_of(kw_whitelist.begin(), kw_whitelist.end(), - [&kw](const char* known) -> bool - { - return kw == known; - }); + [&kw](const char* known) + { + return kw == known; + }); } - int maxNumWellSegments(const std::size_t /* last_timestep */, - const Well& well) + int maxNumWellSegments(const Well& well) { return well.isMultiSegment() ? well.getSegments().size() : 0; } - void makeSegmentNodes(const std::size_t last_timestep, - const int segID, + void makeSegmentNodes(const int segID, const DeckKeyword& keyword, const Well& well, SummaryConfig::keyword_list& list) { - if (!well.isMultiSegment()) + if (!well.isMultiSegment()) { // Not an MSW. Don't create summary vectors for segments. return; + } auto param = SummaryConfigNode { keyword.name(), SummaryConfigNode::Category::Segment, keyword.location() } - .namedEntity( well.name() ) - .isUserDefined( is_udq(keyword.name()) ); + .namedEntity(well.name()) + .parameterType(parseKeywordType(keyword.name())) + .isUserDefined(is_udq(keyword.name())); if (segID < 1) { - // Segment number defaulted. Allocate a summary - // vector for each segment. - const auto nSeg = maxNumWellSegments(last_timestep, well); + // Segment number defaulted. Allocate a summary vector for each + // segment. + const auto nSeg = maxNumWellSegments(well); - for (auto segNumber = 0*nSeg; segNumber < nSeg; ++segNumber) - list.push_back( param.number(segNumber + 1) ); + for (auto segNumber = 0*nSeg; segNumber < nSeg; ++segNumber) { + list.push_back(param.number(segNumber + 1)); + } + } + else { + // Segment number specified. Allocate single summary vector for + // that segment number. + list.push_back(param.number(segID)); } - else - // Segment number specified. Allocate single - // summary vector for that segment number. - list.push_back( param.number(segID) ); } - void keywordSNoRecords(const std::size_t last_timestep, - const DeckKeyword& keyword, + void keywordSNoRecords(const DeckKeyword& keyword, const Schedule& schedule, SummaryConfig::keyword_list& list) { @@ -1169,13 +1173,12 @@ inline void keywordMISC( SummaryConfig::keyword_list& list, const auto segID = -1; - for (const auto& well : schedule.getWellsatEnd()) - makeSegmentNodes(last_timestep, segID, keyword, - well, list); + for (const auto& well : schedule.getWellsatEnd()) { + makeSegmentNodes(segID, keyword, well, list); + } } - void keywordSWithRecords(const std::size_t last_timestep, - const ParseContext& parseContext, + void keywordSWithRecords(const ParseContext& parseContext, ErrorGuard& errors, const DeckKeyword& keyword, const Schedule& schedule, @@ -1203,17 +1206,19 @@ inline void keywordMISC( SummaryConfig::keyword_list& list, ? schedule.wellNames() : schedule.wellNames(wellitem.getTrimmedString(0)); - if (well_names.empty()) + if (well_names.empty()) { handleMissingWell(parseContext, errors, keyword.location(), wellitem.getTrimmedString(0)); + } // Negative 1 (< 0) if segment ID defaulted. Defaulted // segment number in record implies all segments. const auto segID = record.getItem(1).defaultApplied(0) ? -1 : record.getItem(1).get(0); - for (const auto& well_name : well_names) - makeSegmentNodes(last_timestep, segID, keyword, schedule.getWellatEnd(well_name), list); + for (const auto& well_name : well_names) { + makeSegmentNodes(segID, keyword, schedule.getWellatEnd(well_name), list); + } } } @@ -1244,18 +1249,16 @@ inline void keywordMISC( SummaryConfig::keyword_list& list, return; } - const auto last_timestep = schedule.size() - 1; - if (! keyword.empty()) { - // Keyword with explicit records. - // Handle as alternatives SOFR and SPR above - keywordSWithRecords(last_timestep, parseContext, errors, + // Keyword with explicit records. Handle as alternatives SOFR + // and SPR above + keywordSWithRecords(parseContext, errors, keyword, schedule, list); } else { - // Keyword with no explicit records. - // Handle as alternative SGFR above. - keywordSNoRecords(last_timestep, keyword, schedule, list); + // Keyword with no explicit records. Handle as alternative SGFR + // above. + keywordSNoRecords(keyword, schedule, list); } } diff --git a/src/opm/input/eclipse/share/keywords/000_Eclipse100/S/SEGMENT_PROBE b/src/opm/input/eclipse/share/keywords/000_Eclipse100/S/SEGMENT_PROBE index d08fc8f38..9e80e3a93 100644 --- a/src/opm/input/eclipse/share/keywords/000_Eclipse100/S/SEGMENT_PROBE +++ b/src/opm/input/eclipse/share/keywords/000_Eclipse100/S/SEGMENT_PROBE @@ -5,10 +5,17 @@ ], "deck_names": [ "SGFR", + "SGFRF", + "SGFRS", + "SGOR", "SOFR", + "SOFRF", + "SOFRS", + "SOGR", "SPR", "SWFR", "SWCT", + "SWGR", "SPRD", "SPRDF", "SPRDH", diff --git a/src/opm/output/eclipse/Summary.cpp b/src/opm/output/eclipse/Summary.cpp index 24372a87f..3f64a6fff 100644 --- a/src/opm/output/eclipse/Summary.cpp +++ b/src/opm/output/eclipse/Summary.cpp @@ -999,13 +999,10 @@ quantity crate_resv( const fn_args& args ) { return { v, rate_unit() }; } -template< rt phase> -inline quantity srate( const fn_args& args ) { - const quantity zero = { 0, rate_unit< phase >() }; - // The args.num value is the literal value which will go to the - // NUMS array in the eclispe SMSPEC file; the values in this array - // are offset 1 - whereas we need to use this index here to look - // up a connection with offset 0. +template +inline quantity srate(const fn_args& args) +{ + const quantity zero = { 0, rate_unit() }; if (args.schedule_wells.empty()) { return zero; } @@ -1020,22 +1017,22 @@ inline quantity srate( const fn_args& args ) { const auto& well_data = xwPos->second; - const size_t segNumber = args.num; - const auto& segment = well_data.segments.find(segNumber); - - if (segment == well_data.segments.end()) + const auto segNumber = static_cast(args.num); + auto segPos = well_data.segments.find(segNumber); + if (segPos == well_data.segments.end()) { return zero; + } - const double eff_fac = efac(args.eff_factors, name); - auto v = segment->second.rates.get( phase, 0.0 ) * eff_fac; + const auto eff_fac = efac(args.eff_factors, name); - //switch sign of rate - opposite convention in flow vs eclipse - v *= -1; + // Switch sign of rate--opposite convention in Flow vs ECLIPSE. + const auto v = -segPos->second.rates.get(phase, 0.0) * eff_fac; - if (phase == rt::polymer || phase == rt::brine) + if ((phase == rt::polymer) || (phase == rt::brine)) { return { v, measure::mass_rate }; + } - return { v, rate_unit< phase >() }; + return { v, rate_unit() }; } inline quantity trans_factors ( const fn_args& args ) { @@ -2156,16 +2153,25 @@ static const std::unordered_map< std::string, ofun > funs = { { "RGPT" , mul( region_rate< rt::gas, producer >, duration ) }, { "RWPT" , mul( region_rate< rt::wat, producer >, duration ) }, { "RHPV" , rhpv }, - //Multisegment well segment data - { "SOFR", srate< rt::oil > }, - { "SWFR", srate< rt::wat > }, - { "SGFR", srate< rt::gas > }, - { "SWCT", div(srate, sum(srate, srate)) }, - { "SPR", segpress }, - { "SPRD", segpress }, + + // Segment summary vectors for multi-segmented wells. + { "SOFR" , srate }, + { "SOFRF", sub(srate, srate) }, // Free oil flow + { "SOFRS", srate }, // Solution oil flow + { "SGFR" , srate }, + { "SGFRF", sub(srate, srate) }, // Free gas flow + { "SGFRS", srate }, // Solution gas flow + { "SWFR" , srate }, + { "SGOR" , div(srate, srate) }, + { "SOGR" , div(srate, srate) }, + { "SWCT" , div(srate, sum(srate, srate)) }, + { "SWGR" , div(srate, srate) }, + { "SPR" , segpress }, + { "SPRD" , segpress }, { "SPRDH", segpress }, { "SPRDF", segpress }, { "SPRDA", segpress }, + // Well productivity index { "WPI", preferred_phase_productivty_index }, { "WPIW", potential_rate< rt::productivity_index_water >}, diff --git a/tests/SOFR_TEST.DATA b/tests/SOFR_TEST.DATA index 92ce79cff..2762f8214 100644 --- a/tests/SOFR_TEST.DATA +++ b/tests/SOFR_TEST.DATA @@ -111,10 +111,39 @@ SOFR 'PROD01' 21 / / +SOFRF + 'PROD01' 1 / + 'PROD01' 10 / + 'PROD01' 21 / +/ + +SOFRS + 'PROD01' 1 / + 'PROD01' 10 / + 'PROD01' 21 / +/ + +SOGR + 'PROD01' 5 / + 'PROD01' 7 / +/ + SGFR 'PROD01' / / +SGFRF + 'PROD01' 2 / +/ + +SGFRS + 'PROD01' 3 / +/ + +SGOR + 1* 10 / +/ + SPR 1* 10 / / @@ -122,6 +151,10 @@ SPR SWFR / +SWGR + 1* 3 / +/ + SPRD / diff --git a/tests/parser/SummaryConfigTests.cpp b/tests/parser/SummaryConfigTests.cpp index 84d5d26d9..5b6ae9f77 100644 --- a/tests/parser/SummaryConfigTests.cpp +++ b/tests/parser/SummaryConfigTests.cpp @@ -1091,9 +1091,174 @@ BOOST_AUTO_TEST_CASE(Summary_Segment) BOOST_CHECK_MESSAGE(sofr->category() == SummaryConfigNode::Category::Segment, R"("SOFR" keyword category must be "Segment")" ); + + BOOST_CHECK_MESSAGE(sofr->type() == SummaryConfigNode::Type::Rate, + R"("SOFR" keyword type must be "Rate")" + ); + BOOST_CHECK_EQUAL(sofr->namedEntity(), "PROD01"); } + // SOFRF PROD01 segments 1, 10, 21. + BOOST_CHECK(deck.hasKeyword("SOFRF")); + BOOST_CHECK(summary.hasKeyword("SOFRF")); + BOOST_CHECK(summary.hasSummaryKey("SOFRF:PROD01:1")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:2")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:3")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:4")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:5")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:6")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:7")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:8")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:9")); + BOOST_CHECK(summary.hasSummaryKey("SOFRF:PROD01:10")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:11")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:12")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:13")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:14")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:15")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:16")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:17")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:18")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:19")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:20")); + BOOST_CHECK(summary.hasSummaryKey("SOFRF:PROD01:21")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:22")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:23")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:24")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:25")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:26")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:PROD01:27")); + + BOOST_CHECK(!summary.hasSummaryKey("SOFRF:INJE01:1")); + + { + auto sofrf = std::find_if(summary.begin(), summary.end(), + [](const SummaryConfigNode& node) + { + return node.keyword() == "SOFRF"; + }); + + BOOST_REQUIRE(sofrf != summary.end()); + + BOOST_CHECK_MESSAGE(sofrf->category() == SummaryConfigNode::Category::Segment, + R"("SOFRF" keyword category must be "Segment")" + ); + + BOOST_CHECK_MESSAGE(sofrf->type() == SummaryConfigNode::Type::Rate, + R"("SOFRF" keyword type must be "Rate")" + ); + + BOOST_CHECK_EQUAL(sofrf->namedEntity(), "PROD01"); + } + + // SOFRS PROD01 segments 1, 10, 21. + BOOST_CHECK(deck.hasKeyword("SOFRS")); + BOOST_CHECK(summary.hasKeyword("SOFRS")); + BOOST_CHECK(summary.hasSummaryKey("SOFRS:PROD01:1")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:2")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:3")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:4")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:5")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:6")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:7")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:8")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:9")); + BOOST_CHECK(summary.hasSummaryKey("SOFRS:PROD01:10")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:11")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:12")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:13")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:14")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:15")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:16")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:17")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:18")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:19")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:20")); + BOOST_CHECK(summary.hasSummaryKey("SOFRS:PROD01:21")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:22")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:23")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:24")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:25")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:26")); + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:PROD01:27")); + + BOOST_CHECK(!summary.hasSummaryKey("SOFRS:INJE01:1")); + + { + auto sofrs = std::find_if(summary.begin(), summary.end(), + [](const SummaryConfigNode& node) + { + return node.keyword() == "SOFRS"; + }); + + BOOST_REQUIRE(sofrs != summary.end()); + + BOOST_CHECK_MESSAGE(sofrs->category() == SummaryConfigNode::Category::Segment, + R"("SOFRS" keyword category must be "Segment")" + ); + + BOOST_CHECK_MESSAGE(sofrs->type() == SummaryConfigNode::Type::Rate, + R"("SOFRS" keyword type must be "Rate")" + ); + + BOOST_CHECK_EQUAL(sofrs->namedEntity(), "PROD01"); + } + + // SOGR PROD01 segments 5 and 7. + BOOST_CHECK(deck.hasKeyword("SOGR")); + BOOST_CHECK(summary.hasKeyword("SOGR")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:1")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:2")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:3")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:4")); + BOOST_CHECK(summary.hasSummaryKey("SOGR:PROD01:5")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:6")); + BOOST_CHECK(summary.hasSummaryKey("SOGR:PROD01:7")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:8")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:9")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:10")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:11")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:12")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:13")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:14")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:15")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:16")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:17")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:18")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:19")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:20")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:21")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:22")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:23")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:24")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:25")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:26")); + BOOST_CHECK(!summary.hasSummaryKey("SOGR:PROD01:27")); + + BOOST_CHECK(!summary.hasSummaryKey("SOGR:INJE01:1")); + + { + auto sogr = std::find_if(summary.begin(), summary.end(), + [](const SummaryConfigNode& node) + { + return node.keyword() == "SOGR"; + }); + + BOOST_REQUIRE(sogr != summary.end()); + + BOOST_CHECK_MESSAGE(sogr->category() == SummaryConfigNode::Category::Segment, + R"("SOGR" keyword category must be "Segment")" + ); + + BOOST_CHECK_MESSAGE(sogr->type() == SummaryConfigNode::Type::Ratio, + R"("SOGR" keyword type must be "Ratio")" + ); + + BOOST_CHECK_EQUAL(sogr->namedEntity(), "PROD01"); + } + + // SGFR in all segments of PROD01 BOOST_CHECK(deck.hasKeyword("SGFR")); BOOST_CHECK(summary.hasKeyword("SGFR")); BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:1")); @@ -1124,6 +1289,180 @@ BOOST_AUTO_TEST_CASE(Summary_Segment) BOOST_CHECK(summary.hasSummaryKey("SGFR:PROD01:26")); BOOST_CHECK(!summary.hasSummaryKey("SGFR:PROD01:27")); // No such segment. + { + auto sgfr = std::find_if(summary.begin(), summary.end(), + [](const SummaryConfigNode& node) + { + return node.keyword() == "SGFR"; + }); + + BOOST_REQUIRE(sgfr != summary.end()); + + BOOST_CHECK_MESSAGE(sgfr->category() == SummaryConfigNode::Category::Segment, + R"("SGFR" keyword category must be "Segment")" + ); + + BOOST_CHECK_MESSAGE(sgfr->type() == SummaryConfigNode::Type::Rate, + R"("SGFR" keyword type must be "Rate")" + ); + + BOOST_CHECK_EQUAL(sgfr->namedEntity(), "PROD01"); + } + + // SGFRF in segment 2 of PROD01 + BOOST_CHECK(deck.hasKeyword("SGFRF")); + BOOST_CHECK(summary.hasKeyword("SGFRF")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:1")); + BOOST_CHECK(summary.hasSummaryKey("SGFRF:PROD01:2")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:3")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:4")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:5")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:6")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:7")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:8")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:9")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:10")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:11")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:12")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:13")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:14")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:15")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:16")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:17")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:18")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:19")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:20")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:21")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:22")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:23")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:24")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:25")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:26")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRF:PROD01:27")); // No such segment. + + { + auto sgfrf = std::find_if(summary.begin(), summary.end(), + [](const SummaryConfigNode& node) + { + return node.keyword() == "SGFRF"; + }); + + BOOST_REQUIRE(sgfrf != summary.end()); + + BOOST_CHECK_MESSAGE(sgfrf->category() == SummaryConfigNode::Category::Segment, + R"("SGFRF" keyword category must be "Segment")" + ); + + BOOST_CHECK_MESSAGE(sgfrf->type() == SummaryConfigNode::Type::Rate, + R"("SGFRF" keyword type must be "Rate")" + ); + + BOOST_CHECK_EQUAL(sgfrf->namedEntity(), "PROD01"); + } + + // SGFRF in segment 3 of PROD01 + BOOST_CHECK(deck.hasKeyword("SGFRS")); + BOOST_CHECK(summary.hasKeyword("SGFRS")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:1")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:2")); + BOOST_CHECK(summary.hasSummaryKey("SGFRS:PROD01:3")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:4")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:5")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:6")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:7")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:8")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:9")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:10")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:11")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:12")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:13")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:14")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:15")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:16")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:17")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:18")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:19")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:20")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:21")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:22")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:23")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:24")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:25")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:26")); + BOOST_CHECK(!summary.hasSummaryKey("SGFRS:PROD01:27")); // No such segment. + + { + auto sgfrs = std::find_if(summary.begin(), summary.end(), + [](const SummaryConfigNode& node) + { + return node.keyword() == "SGFRS"; + }); + + BOOST_REQUIRE(sgfrs != summary.end()); + + BOOST_CHECK_MESSAGE(sgfrs->category() == SummaryConfigNode::Category::Segment, + R"("SGFRS" keyword category must be "Segment")" + ); + + BOOST_CHECK_MESSAGE(sgfrs->type() == SummaryConfigNode::Type::Rate, + R"("SGFRS" keyword type must be "Rate")" + ); + + BOOST_CHECK_EQUAL(sgfrs->namedEntity(), "PROD01"); + } + + // SGOR PROD01 segment 10 only. + BOOST_CHECK(deck.hasKeyword("SGOR")); + BOOST_CHECK(summary.hasKeyword("SGOR")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:1")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:2")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:3")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:4")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:5")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:6")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:7")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:8")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:9")); + BOOST_CHECK(summary.hasSummaryKey("SGOR:PROD01:10")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:11")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:12")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:13")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:14")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:15")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:16")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:17")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:18")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:19")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:20")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:21")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:22")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:23")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:24")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:25")); + BOOST_CHECK(!summary.hasSummaryKey("SGOR:PROD01:26")); + + BOOST_CHECK(!summary.hasSummaryKey("SGOR:INJE01:10")); + + { + auto sgor = std::find_if(summary.begin(), summary.end(), + [](const SummaryConfigNode& node) + { + return node.keyword() == "SGOR"; + }); + + BOOST_REQUIRE(sgor != summary.end()); + + BOOST_CHECK_MESSAGE(sgor->category() == SummaryConfigNode::Category::Segment, + R"("SGOR" keyword category must be "Segment")" + ); + + BOOST_CHECK_MESSAGE(sgor->type() == SummaryConfigNode::Type::Ratio, + R"("SGOR" keyword type must be "Ratio")" + ); + + BOOST_CHECK_EQUAL(sgor->namedEntity(), "PROD01"); + } + // SPR PROD01 segment 10 only. BOOST_CHECK(deck.hasKeyword("SPR")); BOOST_CHECK(summary.hasKeyword("SPR")); @@ -1156,6 +1495,26 @@ BOOST_AUTO_TEST_CASE(Summary_Segment) BOOST_CHECK(!summary.hasSummaryKey("SPR:INJE01:10")); + { + auto spr = std::find_if(summary.begin(), summary.end(), + [](const SummaryConfigNode& node) + { + return node.keyword() == "SPR"; + }); + + BOOST_REQUIRE(spr != summary.end()); + + BOOST_CHECK_MESSAGE(spr->category() == SummaryConfigNode::Category::Segment, + R"("SPR" keyword category must be "Segment")" + ); + + BOOST_CHECK_MESSAGE(spr->type() == SummaryConfigNode::Type::Pressure, + R"("SPR" keyword type must be "Pressure")" + ); + + BOOST_CHECK_EQUAL(spr->namedEntity(), "PROD01"); + } + // SWFR for all segments in all MS wells. BOOST_CHECK(deck.hasKeyword("SWFR")); BOOST_CHECK(summary.hasKeyword("SWFR")); @@ -1188,6 +1547,78 @@ BOOST_AUTO_TEST_CASE(Summary_Segment) BOOST_CHECK(!summary.hasSummaryKey("SWFR:INJE01:1")); + { + auto swfr = std::find_if(summary.begin(), summary.end(), + [](const SummaryConfigNode& node) + { + return node.keyword() == "SWFR"; + }); + + BOOST_REQUIRE(swfr != summary.end()); + + BOOST_CHECK_MESSAGE(swfr->category() == SummaryConfigNode::Category::Segment, + R"("SWFR" keyword category must be "Segment")" + ); + + BOOST_CHECK_MESSAGE(swfr->type() == SummaryConfigNode::Type::Rate, + R"("SWFR" keyword type must be "Rate")" + ); + + BOOST_CHECK_EQUAL(swfr->namedEntity(), "PROD01"); + } + + // SWGR for segment 3 in all MS wells. + BOOST_CHECK(deck.hasKeyword("SWGR")); + BOOST_CHECK(summary.hasKeyword("SWGR")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:1")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:2")); + BOOST_CHECK(summary.hasSummaryKey("SWGR:PROD01:3")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:4")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:5")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:6")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:7")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:8")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:9")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:10")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:11")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:12")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:13")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:14")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:15")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:16")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:17")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:18")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:19")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:20")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:21")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:22")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:23")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:24")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:25")); + BOOST_CHECK(!summary.hasSummaryKey("SWGR:PROD01:26")); + + BOOST_CHECK(!summary.hasSummaryKey("SWGR:INJE01:1")); + + { + auto swgr = std::find_if(summary.begin(), summary.end(), + [](const SummaryConfigNode& node) + { + return node.keyword() == "SWGR"; + }); + + BOOST_REQUIRE(swgr != summary.end()); + + BOOST_CHECK_MESSAGE(swgr->category() == SummaryConfigNode::Category::Segment, + R"("SWGR" keyword category must be "Segment")" + ); + + BOOST_CHECK_MESSAGE(swgr->type() == SummaryConfigNode::Type::Ratio, + R"("SWGR" keyword type must be "Ratio")" + ); + + BOOST_CHECK_EQUAL(swgr->namedEntity(), "PROD01"); + } + // SPRD for all segments in all MS wells. BOOST_CHECK(deck.hasKeyword("SPRD")); BOOST_CHECK(summary.hasKeyword("SPRD")); @@ -1220,6 +1651,26 @@ BOOST_AUTO_TEST_CASE(Summary_Segment) BOOST_CHECK(!summary.hasSummaryKey("SPRD:INJE01:1")); + { + auto sprd = std::find_if(summary.begin(), summary.end(), + [](const SummaryConfigNode& node) + { + return node.keyword() == "SPRD"; + }); + + BOOST_REQUIRE(sprd != summary.end()); + + BOOST_CHECK_MESSAGE(sprd->category() == SummaryConfigNode::Category::Segment, + R"("SPRD" keyword category must be "Segment")" + ); + + BOOST_CHECK_MESSAGE(sprd->type() == SummaryConfigNode::Type::Pressure, + R"("SPRD" keyword type must be "Pressure")" + ); + + BOOST_CHECK_EQUAL(sprd->namedEntity(), "PROD01"); + } + // SPRDH for all segments of MS well PROD01. BOOST_CHECK(deck.hasKeyword("SPRDH")); BOOST_CHECK(summary.hasKeyword("SPRDH")); @@ -1252,6 +1703,26 @@ BOOST_AUTO_TEST_CASE(Summary_Segment) BOOST_CHECK(!summary.hasSummaryKey("SPRDH:INJE01:1")); + { + auto sprdh = std::find_if(summary.begin(), summary.end(), + [](const SummaryConfigNode& node) + { + return node.keyword() == "SPRDH"; + }); + + BOOST_REQUIRE(sprdh != summary.end()); + + BOOST_CHECK_MESSAGE(sprdh->category() == SummaryConfigNode::Category::Segment, + R"("SPRDH" keyword category must be "Segment")" + ); + + BOOST_CHECK_MESSAGE(sprdh->type() == SummaryConfigNode::Type::Pressure, + R"("SPRDH" keyword type must be "Pressure")" + ); + + BOOST_CHECK_EQUAL(sprdh->namedEntity(), "PROD01"); + } + // SPRDF for segments 10 and 16 of MS well PROD01. BOOST_CHECK(deck.hasKeyword("SPRDF")); BOOST_CHECK(summary.hasKeyword("SPRDF")); @@ -1284,6 +1755,26 @@ BOOST_AUTO_TEST_CASE(Summary_Segment) BOOST_CHECK(!summary.hasSummaryKey("SPRDF:INJE01:1")); + { + auto sprdf = std::find_if(summary.begin(), summary.end(), + [](const SummaryConfigNode& node) + { + return node.keyword() == "SPRDF"; + }); + + BOOST_REQUIRE(sprdf != summary.end()); + + BOOST_CHECK_MESSAGE(sprdf->category() == SummaryConfigNode::Category::Segment, + R"("SPRDF" keyword category must be "Segment")" + ); + + BOOST_CHECK_MESSAGE(sprdf->type() == SummaryConfigNode::Type::Pressure, + R"("SPRDF" keyword type must be "Pressure")" + ); + + BOOST_CHECK_EQUAL(sprdf->namedEntity(), "PROD01"); + } + // SPRDA for segments 10 and 16 of all MS wells BOOST_CHECK(deck.hasKeyword("SPRDA")); BOOST_CHECK(summary.hasKeyword("SPRDA")); @@ -1317,6 +1808,26 @@ BOOST_AUTO_TEST_CASE(Summary_Segment) BOOST_CHECK(!summary.hasSummaryKey("SPRDA:INJE01:1")); BOOST_CHECK(!summary.hasSummaryKey("SPRDA:INJE01:10")); BOOST_CHECK(!summary.hasSummaryKey("SPRDA:INJE01:16")); + + { + auto sprda = std::find_if(summary.begin(), summary.end(), + [](const SummaryConfigNode& node) + { + return node.keyword() == "SPRDA"; + }); + + BOOST_REQUIRE(sprda != summary.end()); + + BOOST_CHECK_MESSAGE(sprda->category() == SummaryConfigNode::Category::Segment, + R"("SPRDA" keyword category must be "Segment")" + ); + + BOOST_CHECK_MESSAGE(sprda->type() == SummaryConfigNode::Type::Pressure, + R"("SPRDA" keyword type must be "Pressure")" + ); + + BOOST_CHECK_EQUAL(sprda->namedEntity(), "PROD01"); + } } BOOST_AUTO_TEST_CASE(Summary_Network) {