Support Outputting Preferred Phase PI to Summary File

This commit adds support for outputting the productivity index of
a well's preferred phase at the well and connection levels to the
summary file (keywords 'WPI' and 'CPI').

Update unit tests accordingly.
This commit is contained in:
Bård Skaflestad 2020-11-22 23:15:30 +01:00
parent a4e05aee47
commit a14c4184a9
3 changed files with 122 additions and 15 deletions

View File

@ -958,6 +958,69 @@ inline quantity potential_rate( const fn_args& args ) {
return { sum, rate_unit< phase >() };
}
inline quantity preferred_phase_productivty_index(const fn_args& args) {
if (args.schedule_wells.empty())
return potential_rate<rt::productivity_index_oil>(args);
switch (args.schedule_wells.front().getPreferredPhase()) {
case Opm::Phase::OIL:
return potential_rate<rt::productivity_index_oil>(args);
case Opm::Phase::GAS:
return potential_rate<rt::productivity_index_gas>(args);
case Opm::Phase::WATER:
return potential_rate<rt::productivity_index_water>(args);
}
throw std::invalid_argument {
"Unsupported \"preferred\" phase: " +
std::to_string(static_cast<int>(args.schedule_wells.front().getPreferredPhase()))
};
}
inline quantity connection_productivity_index(const fn_args& args) {
const quantity zero = { 0.0, rate_unit<rt::productivity_index_oil>() };
if (args.schedule_wells.empty())
return zero;
auto xwPos = args.wells.find(args.schedule_wells.front().name());
if (xwPos == args.wells.end())
return zero;
// The args.num value is the literal value which will go to the
// NUMS array in the eclipse SMSPEC file; the values in this array
// are offset 1 - whereas we need to use this index here to look
// up a completion with offset 0.
const auto global_index = static_cast<std::size_t>(args.num) - 1;
const auto& xcon = xwPos->second.connections;
const auto& completion =
std::find_if(xcon.begin(), xcon.end(),
[global_index](const Opm::data::Connection& c)
{
return c.index == global_index;
});
if (completion == xcon.end())
return zero;
switch (args.schedule_wells.front().getPreferredPhase()) {
case Opm::Phase::GAS:
return { completion->rates.get(rt::productivity_index_gas, 0.0),
rate_unit<rt::productivity_index_gas>() };
case Opm::Phase::WATER:
return { completion->rates.get(rt::productivity_index_water, 0.0),
rate_unit<rt::productivity_index_water>() };
default:
return { completion->rates.get(rt::productivity_index_oil, 0.0),
rate_unit<rt::productivity_index_oil>() };
}
}
template < bool isGroup, bool Producer, bool waterInjector, bool gasInjector>
inline quantity group_control( const fn_args& args ) {
@ -1444,6 +1507,7 @@ static const std::unordered_map< std::string, ofun > funs = {
{ "CSIT", mul( crate< rt::brine, injector >, duration ) },
{ "CSPT", mul( crate< rt::brine, producer >, duration ) },
{ "CTFAC", trans_factors },
{ "CPI", connection_productivity_index },
{ "FWPR", rate< rt::wat, producer > },
{ "FOPR", rate< rt::oil, producer > },
@ -1587,10 +1651,12 @@ static const std::unordered_map< std::string, ofun > funs = {
{ "SPRDF", segpress<Opm::data::SegmentPressures::Value::PDropFriction> },
{ "SPRDA", segpress<Opm::data::SegmentPressures::Value::PDropAccel> },
// Well productivity index
{ "WPI", preferred_phase_productivty_index },
{ "WPIW", potential_rate< rt::productivity_index_water >},
{ "WPIO", potential_rate< rt::productivity_index_oil >},
{ "WPIG", potential_rate< rt::productivity_index_gas >},
{ "WPIL", sum( potential_rate< rt::productivity_index_water >, potential_rate< rt::productivity_index_oil>)},
{ "WPIL", sum( potential_rate< rt::productivity_index_water, true, false >,
potential_rate< rt::productivity_index_oil, true, false >)},
// Well potential
{ "WWPP", potential_rate< rt::well_potential_water , true, false>},
{ "WOPP", potential_rate< rt::well_potential_oil , true, false>},

View File

@ -621,6 +621,14 @@ WTHPH
/
WPI
/
WPIO
/
WPIG
/
WPIW
/
WPIL
/
WBP
/
WBP4

View File

@ -48,6 +48,7 @@
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/Units/Units.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
#include <opm/io/eclipse/ESmry.hpp>
@ -92,6 +93,15 @@ namespace {
*/
static const int day = 24 * 60 * 60;
double liquid_PI_unit()
{
return UnitSystem::newMETRIC().to_si(UnitSystem::measure::liquid_productivity_index, 1.0);
}
double gas_PI_unit()
{
return UnitSystem::newMETRIC().to_si(UnitSystem::measure::gas_productivity_index, 1.0);
}
/*
This is quite misleading, because the values prepared in the test
@ -125,9 +135,9 @@ data::Wells result_wells(const bool w3_injector = true)
rates1.set( rt::reservoir_water, -10.6 / day );
rates1.set( rt::reservoir_oil, -10.7 / day );
rates1.set( rt::reservoir_gas, -10.8 / day );
rates1.set( rt::productivity_index_water, -10.9 / day );
rates1.set( rt::productivity_index_oil, -10.11 / day );
rates1.set( rt::productivity_index_gas, -10.12 / day );
rates1.set( rt::productivity_index_water, 10.9*liquid_PI_unit());
rates1.set( rt::productivity_index_oil, 10.11*liquid_PI_unit());
rates1.set( rt::productivity_index_gas, 10.12*gas_PI_unit());
rates1.set( rt::well_potential_water, -10.13 / day );
rates1.set( rt::well_potential_oil, -10.14 / day );
rates1.set( rt::well_potential_gas, -10.15 / day );
@ -144,9 +154,9 @@ data::Wells result_wells(const bool w3_injector = true)
rates2.set( rt::reservoir_water, -20.6 / day );
rates2.set( rt::reservoir_oil, -20.7 / day );
rates2.set( rt::reservoir_gas, -20.8 / day );
rates2.set( rt::productivity_index_water, -20.9 / day );
rates2.set( rt::productivity_index_oil, -20.11 / day );
rates2.set( rt::productivity_index_gas, -20.12 / day );
rates2.set( rt::productivity_index_water, 20.9*liquid_PI_unit());
rates2.set( rt::productivity_index_oil, 20.11*liquid_PI_unit());
rates2.set( rt::productivity_index_gas, 20.12*gas_PI_unit());
rates2.set( rt::well_potential_water, -20.13 / day );
rates2.set( rt::well_potential_oil, -20.14 / day );
rates2.set( rt::well_potential_gas, -20.15 / day );
@ -163,16 +173,15 @@ data::Wells result_wells(const bool w3_injector = true)
rates3.set( rt::reservoir_water, 30.6 / day );
rates3.set( rt::reservoir_oil, 30.7 / day );
rates3.set( rt::reservoir_gas, 30.8 / day );
rates3.set( rt::productivity_index_water, -30.9 / day );
rates3.set( rt::productivity_index_oil, -30.11 / day );
rates3.set( rt::productivity_index_gas, -30.12 / day );
rates3.set( rt::productivity_index_water, 30.9*liquid_PI_unit());
rates3.set( rt::productivity_index_oil, 30.11*liquid_PI_unit());
rates3.set( rt::productivity_index_gas, 30.12*gas_PI_unit());
rates3.set( rt::well_potential_water, 30.13 / day );
rates3.set( rt::well_potential_oil, 30.14 / day );
rates3.set( rt::well_potential_gas, 30.15 / day );
rates3.set( rt::polymer, 30.16 / day );
rates3.set( rt::brine, 30.17 / day );
data::Rates rates6;
rates6.set( rt::wat, 60.0 / day );
rates6.set( rt::oil, 60.1 / day );
@ -183,14 +192,15 @@ data::Wells result_wells(const bool w3_injector = true)
rates6.set( rt::reservoir_water, 60.6 / day );
rates6.set( rt::reservoir_oil, 60.7 / day );
rates6.set( rt::reservoir_gas, 60.8 / day );
rates6.set( rt::productivity_index_water, -60.9 / day );
rates6.set( rt::productivity_index_oil, -60.11 / day );
rates6.set( rt::productivity_index_gas, -60.12 / day );
rates6.set( rt::productivity_index_water, 60.9*liquid_PI_unit());
rates6.set( rt::productivity_index_oil, 60.11*liquid_PI_unit());
rates6.set( rt::productivity_index_gas, 60.12*gas_PI_unit());
rates6.set( rt::well_potential_water, 60.13 / day );
rates6.set( rt::well_potential_oil, 60.14 / day );
rates6.set( rt::well_potential_gas, 60.15 / day );
rates6.set( rt::polymer, 60.16 / day );
rates6.set( rt::brine, 60.17 / day );
/* completion rates */
data::Rates crates1;
crates1.set( rt::wat, -100.0 / day );
@ -388,12 +398,14 @@ double ecl_sum_get_general_var(const EclIO::ESmry* smry,
return smry->get(var)[timeIdx];
}
#if 0
bool ecl_sum_has_well_var( const EclIO::ESmry* smry,
const std::string& wellname,
const std::string& variable )
{
return smry->hasKey(variable + ':' + wellname);
}
#endif
double ecl_sum_get_well_var( const EclIO::ESmry* smry,
const int timeIdx,
@ -526,6 +538,28 @@ BOOST_AUTO_TEST_CASE(well_keywords) {
BOOST_CHECK_CLOSE( 30.13, ecl_sum_get_well_var( resp, 1, "W_3", "WWPI" ), 1e-5 );
BOOST_CHECK_CLOSE( 60.15, ecl_sum_get_well_var( resp, 1, "W_6", "WGPI" ), 1e-5 );
BOOST_CHECK_CLOSE( 10.9 , ecl_sum_get_well_var( resp, 1, "W_1", "WPIW" ), 1.0e-5 );
BOOST_CHECK_CLOSE( 10.11, ecl_sum_get_well_var( resp, 1, "W_1", "WPIO" ), 1.0e-5 );
BOOST_CHECK_CLOSE( 10.12, ecl_sum_get_well_var( resp, 1, "W_1", "WPIG" ), 1.0e-5 );
BOOST_CHECK_CLOSE( 10.11, ecl_sum_get_well_var( resp, 1, "W_1", "WPI" ), 1.0e-5 );
BOOST_CHECK_CLOSE( 21.01, ecl_sum_get_well_var( resp, 1, "W_1", "WPIL" ), 1.0e-5 );
BOOST_CHECK_CLOSE( 20.9 , ecl_sum_get_well_var( resp, 1, "W_2", "WPIW" ), 1.0e-5 );
BOOST_CHECK_CLOSE( 20.11, ecl_sum_get_well_var( resp, 1, "W_2", "WPIO" ), 1.0e-5 );
BOOST_CHECK_CLOSE( 20.12, ecl_sum_get_well_var( resp, 1, "W_2", "WPIG" ), 1.0e-5 );
BOOST_CHECK_CLOSE( 20.11, ecl_sum_get_well_var( resp, 1, "W_2", "WPI" ), 1.0e-5 );
BOOST_CHECK_CLOSE( 41.01, ecl_sum_get_well_var( resp, 1, "W_2", "WPIL" ), 1.0e-5 );
BOOST_CHECK_CLOSE( 30.9 , ecl_sum_get_well_var( resp, 1, "W_3", "WPIW" ), 1.0e-5 );
BOOST_CHECK_CLOSE( 30.11, ecl_sum_get_well_var( resp, 1, "W_3", "WPIO" ), 1.0e-5 );
BOOST_CHECK_CLOSE( 30.12, ecl_sum_get_well_var( resp, 1, "W_3", "WPIG" ), 1.0e-5 );
BOOST_CHECK_CLOSE( 30.9 , ecl_sum_get_well_var( resp, 1, "W_3", "WPI" ), 1.0e-5 );
BOOST_CHECK_CLOSE( 60.9 , ecl_sum_get_well_var( resp, 1, "W_6", "WPIW" ), 1.0e-5 );
BOOST_CHECK_CLOSE( 60.11, ecl_sum_get_well_var( resp, 1, "W_6", "WPIO" ), 1.0e-5 );
BOOST_CHECK_CLOSE( 60.12, ecl_sum_get_well_var( resp, 1, "W_6", "WPIG" ), 1.0e-5 );
BOOST_CHECK_CLOSE( 60.12, ecl_sum_get_well_var( resp, 1, "W_6", "WPI" ), 1.0e-5 );
BOOST_CHECK_CLOSE( 123.456, ecl_sum_get_well_var(resp, 1, "W_1", "WOPGR"), 1.0e-5);
BOOST_CHECK_CLOSE(2345.67 , ecl_sum_get_well_var(resp, 1, "W_1", "WGPGR"), 1.0e-5);
BOOST_CHECK_CLOSE( 654.321, ecl_sum_get_well_var(resp, 1, "W_2", "WWPGR"), 1.0e-5);
@ -1218,7 +1252,6 @@ BOOST_AUTO_TEST_CASE(skip_unknown_var) {
const auto* resp = res.get();
/* verify that some non-supported keywords aren't written to the file */
BOOST_CHECK( !ecl_sum_has_well_var( resp, "W_1", "WPI" ) );
BOOST_CHECK( !ecl_sum_has_field_var( resp, "FGST" ) );
}