Apply efficiency factors
Efficiency factors are multiplied when specified at multiple levels of the well/group hierarchy. The factors are included as follows: * Well Rate - No efficiency factor * Well Total - WEFAC & GEFAC (whole hierarchy) * Group Rate - WEFAC & GEFAC (only subgroups) * Group Total - WEFAC & GEFAC (whole hierarchy) * Field Rate - WEFAC & GEFAC (whole hierarchy) * Field Total - WEFAC & GEFAC (whole hierarchy) * Region Rate - WEFAC & GEFAC (whole hierarchy) * Region Total - WEFAC & GEFAC (whole hierarchy) * Completion Rate - No efficiency factor * Completion Total - WEFAC & GEFAC (whole hierarchy) Authored by Sveinung Rundhovde and Lars Petter Hauge
This commit is contained in:
parent
22ebda2ea7
commit
fdb06aa77f
@ -156,6 +156,7 @@ struct fn_args {
|
|||||||
const data::Wells& wells;
|
const data::Wells& wells;
|
||||||
const out::RegionCache& regionCache;
|
const out::RegionCache& regionCache;
|
||||||
const EclipseGrid& grid;
|
const EclipseGrid& grid;
|
||||||
|
const std::vector< std::pair< std::string, double > > eff_factors;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Since there are several enums in opm scattered about more-or-less
|
/* Since there are several enums in opm scattered about more-or-less
|
||||||
@ -185,6 +186,15 @@ measure rate_unit< rt::reservoir_oil >() { return measure::rate; }
|
|||||||
template<> constexpr
|
template<> constexpr
|
||||||
measure rate_unit< rt::reservoir_gas >() { return measure::rate; }
|
measure rate_unit< rt::reservoir_gas >() { return measure::rate; }
|
||||||
|
|
||||||
|
double efac( const std::vector<std::pair<std::string,double>>& eff_factors, const std::string& name ) {
|
||||||
|
auto it = std::find_if( eff_factors.begin(), eff_factors.end(),
|
||||||
|
[&] ( const std::pair< std::string, double > elem )
|
||||||
|
{ return elem.first == name; }
|
||||||
|
);
|
||||||
|
|
||||||
|
return (it != eff_factors.end()) ? it->second : 1;
|
||||||
|
}
|
||||||
|
|
||||||
template< rt phase, bool injection = true >
|
template< rt phase, bool injection = true >
|
||||||
inline quantity rate( const fn_args& args ) {
|
inline quantity rate( const fn_args& args ) {
|
||||||
double sum = 0.0;
|
double sum = 0.0;
|
||||||
@ -192,7 +202,11 @@ inline quantity rate( const fn_args& args ) {
|
|||||||
for( const auto* sched_well : args.schedule_wells ) {
|
for( const auto* sched_well : args.schedule_wells ) {
|
||||||
const auto& name = sched_well->name();
|
const auto& name = sched_well->name();
|
||||||
if( args.wells.count( name ) == 0 ) continue;
|
if( args.wells.count( name ) == 0 ) continue;
|
||||||
const auto v = args.wells.at( name ).rates.get( phase, 0.0 );
|
|
||||||
|
double eff_fac = efac( args.eff_factors, name );
|
||||||
|
|
||||||
|
const auto v = args.wells.at(name).rates.get(phase, 0.0) * eff_fac;
|
||||||
|
|
||||||
if( ( v > 0 ) == injection )
|
if( ( v > 0 ) == injection )
|
||||||
sum += v;
|
sum += v;
|
||||||
}
|
}
|
||||||
@ -239,7 +253,10 @@ inline quantity crate( const fn_args& args ) {
|
|||||||
} );
|
} );
|
||||||
|
|
||||||
if( completion == well.completions.end() ) return zero;
|
if( completion == well.completions.end() ) return zero;
|
||||||
const auto v = completion->rates.get( phase, 0.0 );
|
|
||||||
|
double eff_fac = efac( args.eff_factors, name );
|
||||||
|
|
||||||
|
const auto v = completion->rates.get( phase, 0.0 ) * eff_fac;
|
||||||
if( ( v > 0 ) != injection ) return zero;
|
if( ( v > 0 ) != injection ) return zero;
|
||||||
|
|
||||||
if( !injection ) return { -v, rate_unit< phase >() };
|
if( !injection ) return { -v, rate_unit< phase >() };
|
||||||
@ -376,8 +393,12 @@ template<rt phase , bool injection>
|
|||||||
quantity region_rate( const fn_args& args ) {
|
quantity region_rate( const fn_args& args ) {
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
const auto& well_completions = args.regionCache.completions( args.num );
|
const auto& well_completions = args.regionCache.completions( args.num );
|
||||||
|
|
||||||
for (const auto& pair : well_completions) {
|
for (const auto& pair : well_completions) {
|
||||||
double rate = args.wells.get( pair.first , pair.second , phase );
|
|
||||||
|
double eff_fac = efac( args.eff_factors, pair.first );
|
||||||
|
|
||||||
|
double rate = args.wells.get( pair.first , pair.second , phase ) * eff_fac;
|
||||||
|
|
||||||
// We are asking for the production rate in an injector - or
|
// We are asking for the production rate in an injector - or
|
||||||
// opposite. We just clamp to zero.
|
// opposite. We just clamp to zero.
|
||||||
@ -945,6 +966,66 @@ Summary::Summary( const EclipseState& st,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The well efficiency factor will not impact the well rate itself, but is
|
||||||
|
* rather applied for accumulated values.The WEFAC can be considered to shut
|
||||||
|
* and open the well for short intervals within the same timestep, and the well
|
||||||
|
* is therefore solved at full speed.
|
||||||
|
*
|
||||||
|
* Groups are treated similarly as wells. The group's GEFAC is not applied for
|
||||||
|
* rates, only for accumulated volumes. When GEFAC is set for a group, it is
|
||||||
|
* considered that all wells are taken down simultaneously, and GEFAC is
|
||||||
|
* therefore not applied to the group's rate. However, any efficiency factors
|
||||||
|
* applied to the group's wells or sub-groups must be included.
|
||||||
|
*
|
||||||
|
* Regions and fields will have the well and group efficiency applied for both
|
||||||
|
* rates and accumulated values.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
std::vector< std::pair< std::string, double > >
|
||||||
|
well_efficiency_factors( const smspec_node_type* type,
|
||||||
|
const Schedule& schedule,
|
||||||
|
const std::vector< const Well* >& schedule_wells,
|
||||||
|
size_t timestep ) {
|
||||||
|
std::vector< std::pair< std::string, double > > efac;
|
||||||
|
|
||||||
|
if( smspec_node_get_var_type(type) != ECL_SMSPEC_GROUP_VAR
|
||||||
|
&& smspec_node_get_var_type(type) != ECL_SMSPEC_FIELD_VAR
|
||||||
|
&& smspec_node_get_var_type(type) != ECL_SMSPEC_REGION_VAR
|
||||||
|
&& !smspec_node_is_total( type ) ) {
|
||||||
|
return efac;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool is_group = smspec_node_get_var_type(type) == ECL_SMSPEC_GROUP_VAR;
|
||||||
|
const bool is_rate = !smspec_node_is_total( type );
|
||||||
|
const auto &groupTree = schedule.getGroupTree(timestep);
|
||||||
|
|
||||||
|
for( const auto* well : schedule_wells ) {
|
||||||
|
double eff_factor = well->getEfficiencyFactor(timestep);
|
||||||
|
|
||||||
|
if ( !well->hasBeenDefined( timestep ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto* node = &schedule.getGroup(well->getGroupName(timestep));
|
||||||
|
|
||||||
|
while(true){
|
||||||
|
if(( is_group
|
||||||
|
&& is_rate
|
||||||
|
&& node->name() == smspec_node_get_wgname(type) ))
|
||||||
|
break;
|
||||||
|
eff_factor *= node->getGroupEfficiencyFactor( timestep );
|
||||||
|
|
||||||
|
const auto& parent = groupTree.parent( node->name() );
|
||||||
|
if( !schedule.hasGroup( parent ) )
|
||||||
|
break;
|
||||||
|
node = &schedule.getGroup( parent );
|
||||||
|
}
|
||||||
|
efac.emplace_back( well->name(), eff_factor );
|
||||||
|
}
|
||||||
|
|
||||||
|
return efac;
|
||||||
|
}
|
||||||
|
|
||||||
void Summary::add_timestep( int report_step,
|
void Summary::add_timestep( int report_step,
|
||||||
double secs_elapsed,
|
double secs_elapsed,
|
||||||
const EclipseState& es,
|
const EclipseState& es,
|
||||||
@ -963,13 +1044,16 @@ void Summary::add_timestep( int report_step,
|
|||||||
const auto* genkey = smspec_node_get_gen_key1( f.first );
|
const auto* genkey = smspec_node_get_gen_key1( f.first );
|
||||||
|
|
||||||
const auto schedule_wells = find_wells( schedule, f.first, timestep, this->regionCache );
|
const auto schedule_wells = find_wells( schedule, f.first, timestep, this->regionCache );
|
||||||
|
auto eff_factors = well_efficiency_factors( f.first, schedule, schedule_wells, timestep );
|
||||||
|
|
||||||
const auto val = f.second( { schedule_wells,
|
const auto val = f.second( { schedule_wells,
|
||||||
duration,
|
duration,
|
||||||
timestep,
|
timestep,
|
||||||
num,
|
num,
|
||||||
wells,
|
wells,
|
||||||
this->regionCache,
|
this->regionCache,
|
||||||
this->grid});
|
this->grid,
|
||||||
|
eff_factors});
|
||||||
|
|
||||||
const auto unit_applied_val = es.getUnits().from_si( val.unit, val.value );
|
const auto unit_applied_val = es.getUnits().from_si( val.unit, val.value );
|
||||||
const auto res = smspec_node_is_total( f.first ) && prev_tstep
|
const auto res = smspec_node_is_total( f.first ) && prev_tstep
|
||||||
|
138
tests/SUMMARY_EFF_FAC.DATA
Normal file
138
tests/SUMMARY_EFF_FAC.DATA
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
START
|
||||||
|
10 MAI 2007 /
|
||||||
|
RUNSPEC
|
||||||
|
|
||||||
|
TITLE
|
||||||
|
SUMMARYTESTS
|
||||||
|
|
||||||
|
-- A simple 10x10x10 cube. Simple to reason about, large enough for all tests
|
||||||
|
DIMENS
|
||||||
|
10 10 10 /
|
||||||
|
|
||||||
|
REGDIMS
|
||||||
|
10 /
|
||||||
|
|
||||||
|
OIL
|
||||||
|
GAS
|
||||||
|
WATER
|
||||||
|
|
||||||
|
GRID
|
||||||
|
|
||||||
|
DX
|
||||||
|
1000*1 /
|
||||||
|
DY
|
||||||
|
1000*1 /
|
||||||
|
DZ
|
||||||
|
1000*1 /
|
||||||
|
TOPS
|
||||||
|
100*1 /
|
||||||
|
|
||||||
|
|
||||||
|
PORO
|
||||||
|
1000*0.2 /
|
||||||
|
|
||||||
|
REGIONS
|
||||||
|
|
||||||
|
FIPNUM
|
||||||
|
1*2
|
||||||
|
/
|
||||||
|
|
||||||
|
SUMMARY
|
||||||
|
DATE
|
||||||
|
|
||||||
|
ROPR
|
||||||
|
/
|
||||||
|
|
||||||
|
RWIR
|
||||||
|
/
|
||||||
|
|
||||||
|
WOPR
|
||||||
|
/
|
||||||
|
WOPT
|
||||||
|
/
|
||||||
|
WOIR
|
||||||
|
/
|
||||||
|
WOIT
|
||||||
|
/
|
||||||
|
|
||||||
|
GOPR
|
||||||
|
/
|
||||||
|
GOPT
|
||||||
|
/
|
||||||
|
GOIR
|
||||||
|
/
|
||||||
|
GOIT
|
||||||
|
/
|
||||||
|
GWCT
|
||||||
|
/
|
||||||
|
GGOR
|
||||||
|
/
|
||||||
|
|
||||||
|
FOPR
|
||||||
|
|
||||||
|
FOPT
|
||||||
|
|
||||||
|
FOIR
|
||||||
|
|
||||||
|
FOIT
|
||||||
|
|
||||||
|
COPR
|
||||||
|
'W_2' /
|
||||||
|
/
|
||||||
|
|
||||||
|
COPT
|
||||||
|
'W_2' /
|
||||||
|
/
|
||||||
|
|
||||||
|
SCHEDULE
|
||||||
|
|
||||||
|
GRUPTREE
|
||||||
|
'G_1' 'G' /
|
||||||
|
'G_2' 'G' /
|
||||||
|
'G_3' 'G_4' /
|
||||||
|
/
|
||||||
|
|
||||||
|
|
||||||
|
WELSPECS
|
||||||
|
'W_1' 'G_1' 1 1 3.33 'OIL' 7* /
|
||||||
|
'W_2' 'G_2' 2 1 3.33 'OIL' 7* /
|
||||||
|
'W_3' 'G_3' 2 1 3.33 'OIL' 7* /
|
||||||
|
/
|
||||||
|
|
||||||
|
WEFAC
|
||||||
|
'W_2' 0.2 /
|
||||||
|
'W_3' 0.3 /
|
||||||
|
/
|
||||||
|
|
||||||
|
GEFAC
|
||||||
|
G_2 0.01 /
|
||||||
|
G_3 0.02 /
|
||||||
|
G_4 0.03 /
|
||||||
|
/
|
||||||
|
|
||||||
|
WCONPROD
|
||||||
|
W_1 'OPEN' ORAT 10.1 /
|
||||||
|
W_2 'OPEN' ORAT 10.1 /
|
||||||
|
W_3 'OPEN' ORAT 10.1 /
|
||||||
|
/
|
||||||
|
|
||||||
|
-- Completion data.
|
||||||
|
COMPDAT
|
||||||
|
-- 'Well' I J K1 K2
|
||||||
|
-- Passing 0 to I/J means they'll get the well head I/J
|
||||||
|
W_1 0 0 1 1 / -- Active index: 0
|
||||||
|
W_2 0 0 1 1 / -- Active index: 1
|
||||||
|
W_2 0 0 2 2 / -- Active index: 101
|
||||||
|
W_3 0 0 1 1 / -- Active index: 2
|
||||||
|
/
|
||||||
|
|
||||||
|
TSTEP
|
||||||
|
-- register time steps (in days). This allows us to write *two* report steps (1
|
||||||
|
-- and 2. Without this, totals/accumulations would fail (segfault) when looking
|
||||||
|
-- up historical rates and volumes. These volumes however don't change, i.e.
|
||||||
|
-- every time step has the same set of values
|
||||||
|
10 10 /
|
||||||
|
|
||||||
|
|
||||||
|
TSTEP
|
||||||
|
10 10 /
|
@ -1150,3 +1150,75 @@ BOOST_AUTO_TEST_CASE(READ_WRITE_WELLDATA) {
|
|||||||
BOOST_CHECK_CLOSE( wellRatesCopy.get( "W_2" , 101 , rt::wat) , wellRates.get( "W_2" , 101 , rt::wat), 1e-16);
|
BOOST_CHECK_CLOSE( wellRatesCopy.get( "W_2" , 101 , rt::wat) , wellRates.get( "W_2" , 101 , rt::wat), 1e-16);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(efficiency_factor) {
|
||||||
|
setup cfg( "test_efficiency_factor", "SUMMARY_EFF_FAC.DATA" );
|
||||||
|
|
||||||
|
out::Summary writer( cfg.es, cfg.config, cfg.grid, cfg.schedule, cfg.name );
|
||||||
|
writer.add_timestep( 0, 0 * day, cfg.es, cfg.schedule, cfg.wells, {});
|
||||||
|
writer.add_timestep( 1, 1 * day, cfg.es, cfg.schedule, cfg.wells, {});
|
||||||
|
writer.add_timestep( 2, 2 * day, cfg.es, cfg.schedule, cfg.wells, {});
|
||||||
|
writer.write();
|
||||||
|
auto res = readsum( cfg.name );
|
||||||
|
const auto* resp = res.get();
|
||||||
|
|
||||||
|
/* No WEFAC assigned to W_1 */
|
||||||
|
BOOST_CHECK_CLOSE( 10.1, ecl_sum_get_well_var( resp, 1, "W_1", "WOPR" ), 1e-5 );
|
||||||
|
BOOST_CHECK_CLOSE( 10.1, ecl_sum_get_well_var( resp, 1, "W_1", "WOPT" ), 1e-5 );
|
||||||
|
BOOST_CHECK_CLOSE( 2 * 10.1, ecl_sum_get_well_var( resp, 2, "W_1", "WOPT" ), 1e-5 );
|
||||||
|
|
||||||
|
/* WEFAC 0.2 assigned to W_2.
|
||||||
|
* W_2 assigned to group G2. GEFAC G2 = 0.01 */
|
||||||
|
BOOST_CHECK_CLOSE( 20.1, ecl_sum_get_well_var( resp, 1, "W_2", "WOPR" ), 1e-5 );
|
||||||
|
BOOST_CHECK_CLOSE( 20.1 * 0.2 * 0.01, ecl_sum_get_well_var( resp, 1, "W_2", "WOPT" ), 1e-5 );
|
||||||
|
BOOST_CHECK_CLOSE( 2 * 20.1 * 0.2 * 0.01, ecl_sum_get_well_var( resp, 2, "W_2", "WOPT" ), 1e-5 );
|
||||||
|
|
||||||
|
/* WEFAC 0.3 assigned to W_3.
|
||||||
|
* W_3 assigned to group G3. GEFAC G_3 = 0.02
|
||||||
|
* G_3 assigned to group G4. GEFAC G_4 = 0.03*/
|
||||||
|
BOOST_CHECK_CLOSE( 30.1, ecl_sum_get_well_var( resp, 1, "W_3", "WOIR" ), 1e-5 );
|
||||||
|
BOOST_CHECK_CLOSE( 30.1 * 0.3 * 0.02 * 0.03, ecl_sum_get_well_var( resp, 1, "W_3", "WOIT" ), 1e-5 );
|
||||||
|
BOOST_CHECK_CLOSE( 2 * 30.1 * 0.3 * 0.02 * 0.03, ecl_sum_get_well_var( resp, 2, "W_3", "WOIT" ), 1e-5 );
|
||||||
|
|
||||||
|
/* WEFAC 0.2 assigned to W_2.
|
||||||
|
* W_2 assigned to group G2. GEFAC G2 = 0.01 */
|
||||||
|
BOOST_CHECK_CLOSE( 20.1 * 0.2, ecl_sum_get_group_var( resp, 1, "G_2", "GOPR" ), 1e-5 );
|
||||||
|
BOOST_CHECK_CLOSE( 20.1 * 0.2 * 0.01, ecl_sum_get_group_var( resp, 1, "G_2", "GOPT" ), 1e-5 );
|
||||||
|
BOOST_CHECK_CLOSE( 2 * 20.1 * 0.2 * 0.01, ecl_sum_get_group_var( resp, 2, "G_2", "GOPT" ), 1e-5 );
|
||||||
|
|
||||||
|
/* WEFAC 0.3 assigned to W_3.
|
||||||
|
* W_3 assigned to group G3. GEFAC G_3 = 0.02
|
||||||
|
* G_3 assigned to group G4. GEFAC G_4 = 0.03*/
|
||||||
|
BOOST_CHECK_CLOSE( 30.1 * 0.3, ecl_sum_get_group_var( resp, 1, "G_3", "GOIR" ), 1e-5 );
|
||||||
|
BOOST_CHECK_CLOSE( 30.1 * 0.3 * 0.02 * 0.03, ecl_sum_get_group_var( resp, 1, "G_3", "GOIT" ), 1e-5 );
|
||||||
|
BOOST_CHECK_CLOSE( 2 * 30.1 * 0.3 * 0.02 * 0.03, ecl_sum_get_group_var( resp, 2, "G_3", "GOIT" ), 1e-5 );
|
||||||
|
|
||||||
|
/* WEFAC 0.3 assigned to W_3.
|
||||||
|
* W_3 assigned to group G3. GEFAC G_3 = 0.02
|
||||||
|
* G_3 assigned to group G4. GEFAC G_4 = 0.03
|
||||||
|
* The rate for a group is calculated including WEFAC and GEFAC for subgroups */
|
||||||
|
BOOST_CHECK_CLOSE( 30.1 * 0.3 * 0.02, ecl_sum_get_group_var( resp, 1, "G_4", "GOIR" ), 1e-5 );
|
||||||
|
BOOST_CHECK_CLOSE( 30.1 * 0.3 * 0.02 * 0.03, ecl_sum_get_group_var( resp, 1, "G_4", "GOIT" ), 1e-5 );
|
||||||
|
BOOST_CHECK_CLOSE( 2 * 30.1 * 0.3 * 0.02 * 0.03, ecl_sum_get_group_var( resp, 2, "G_4", "GOIT" ), 1e-5 );
|
||||||
|
|
||||||
|
BOOST_CHECK_CLOSE( 10.1 + 20.1 * 0.2 * 0.01, ecl_sum_get_field_var( resp, 1, "FOPR" ), 1e-5 );
|
||||||
|
BOOST_CHECK_CLOSE( 10.1 + 20.1 * 0.2 * 0.01, ecl_sum_get_field_var( resp, 1, "FOPT" ), 1e-5 );
|
||||||
|
BOOST_CHECK_CLOSE( 2 * (10.1 + 20.1 * 0.2 * 0.01), ecl_sum_get_field_var( resp, 2, "FOPT" ), 1e-5 );
|
||||||
|
|
||||||
|
BOOST_CHECK_CLOSE( 30.1 * 0.3 * 0.02 * 0.03, ecl_sum_get_field_var( resp, 1, "FOIR" ), 1e-5 );
|
||||||
|
BOOST_CHECK_CLOSE( 30.1 * 0.3 * 0.02 * 0.03, ecl_sum_get_field_var( resp, 1, "FOIT" ), 1e-5 );
|
||||||
|
BOOST_CHECK_CLOSE( 2 * 30.1 * 0.3 * 0.02 * 0.03, ecl_sum_get_field_var( resp, 2, "FOIT" ), 1e-5 );
|
||||||
|
|
||||||
|
BOOST_CHECK_CLOSE( 30.1 * 0.3 * 0.02 * 0.03, ecl_sum_get_field_var( resp, 1, "FOIR" ), 1e-5 );
|
||||||
|
BOOST_CHECK_CLOSE( 30.1 * 0.3 * 0.02 * 0.03, ecl_sum_get_field_var( resp, 1, "FOIT" ), 1e-5 );
|
||||||
|
BOOST_CHECK_CLOSE( 2 * 30.1 * 0.3 * 0.02 * 0.03, ecl_sum_get_field_var( resp, 2, "FOIT" ), 1e-5 );
|
||||||
|
|
||||||
|
BOOST_CHECK_CLOSE( 200.1 * 0.2 * 0.01, ecl_sum_get_general_var( resp , 1 , "ROPR:1" ) , 1e-5);
|
||||||
|
|
||||||
|
BOOST_CHECK_CLOSE( 100.1, ecl_sum_get_general_var( resp , 1 , "ROPR:2" ) , 1e-5);
|
||||||
|
|
||||||
|
BOOST_CHECK_CLOSE( 300 * 0.2 * 0.01, ecl_sum_get_general_var( resp , 1 , "RWIR:1" ) , 1e-5);
|
||||||
|
|
||||||
|
BOOST_CHECK_CLOSE( 200.1, ecl_sum_get_well_completion_var( resp, 1, "W_2", "COPR", 2 ), 1e-5 );
|
||||||
|
BOOST_CHECK_CLOSE( 200.1 * 0.2 * 0.01, ecl_sum_get_well_completion_var( resp, 1, "W_2", "COPT", 2 ), 1e-5 );
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user