2019-08-07 14:13:11 +02:00
/*
Copyright 2019 Norce.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_WELLGROUPHELPERS_HEADER_INCLUDED
#define OPM_WELLGROUPHELPERS_HEADER_INCLUDED
#include <vector>
namespace Opm {
namespace wellGroupHelpers
{
2020-01-20 09:14:19 +01:00
inline void setGroupControl ( const Group & group , const Schedule & schedule , const Phase & topUpPhase , const int reportStepIdx , const bool injector , WellStateFullyImplicitBlackoil & wellState , std :: ostringstream & ss ) {
2019-08-07 14:13:11 +02:00
for ( const std :: string & groupName : group . groups ()) {
2019-11-13 23:16:11 +01:00
const Group & groupTmp = schedule . getGroup ( groupName , reportStepIdx );
2020-01-20 09:14:19 +01:00
setGroupControl ( groupTmp , schedule , topUpPhase , reportStepIdx , injector , wellState , ss );
2020-01-13 11:03:35 +01:00
if ( injector ) {
2020-01-20 09:14:19 +01:00
if ( groupTmp . injection_phase () == topUpPhase || wellState . currentInjectionGroupControl ( groupName ) == Group :: InjectionCMode :: NONE ) // only switch sub groups with same phase or NONE
2020-01-13 11:03:35 +01:00
wellState . setCurrentInjectionGroupControl ( groupName , Group :: InjectionCMode :: FLD );
} else {
2019-11-13 23:16:11 +01:00
wellState . setCurrentProductionGroupControl ( groupName , Group :: ProductionCMode :: FLD );
2020-01-13 11:03:35 +01:00
}
2019-08-07 14:13:11 +02:00
}
2019-09-30 12:49:36 +02:00
2019-08-07 14:13:11 +02:00
const auto & end = wellState . wellMap (). end ();
for ( const std :: string & wellName : group . wells ()) {
const auto & it = wellState . wellMap (). find ( wellName );
if ( it == end ) // the well is not found
continue ;
int well_index = it -> second [ 0 ];
2019-11-13 23:16:11 +01:00
const auto & wellEcl = schedule . getWell ( wellName , reportStepIdx );
2019-09-30 12:49:36 +02:00
2019-11-13 23:16:11 +01:00
if ( wellEcl . getStatus () == Well :: Status :: SHUT )
2019-08-07 14:13:11 +02:00
continue ;
2019-09-30 12:49:36 +02:00
if ( ! wellEcl . isAvailableForGroupControl ())
continue ;
2019-10-16 15:27:40 +02:00
if ( wellEcl . isProducer () && ! injector ) {
2019-11-13 23:16:11 +01:00
if ( wellState . currentProductionControls ()[ well_index ] != Well :: ProducerCMode :: GRUP ) {
wellState . currentProductionControls ()[ well_index ] = Well :: ProducerCMode :: GRUP ;
2019-10-16 15:27:40 +02:00
ss << " \n Producer " << wellName << " switches to GRUP control limit" ;
}
}
if ( wellEcl . isInjector () && injector ) {
2019-11-06 16:16:19 +01:00
// only switch if the well phase is the same as the group phase
2020-01-13 11:03:35 +01:00
// Get the current controls.
const Well :: InjectorType & injectorType = wellEcl . getInjectionProperties (). injectorType ;
2020-01-20 09:14:19 +01:00
if ( injectorType == Well :: InjectorType :: WATER && topUpPhase != Phase :: WATER )
2020-01-13 11:03:35 +01:00
continue ;
2020-01-20 09:14:19 +01:00
if ( injectorType == Well :: InjectorType :: OIL && topUpPhase != Phase :: OIL )
2019-11-06 16:16:19 +01:00
continue ;
2020-01-20 09:14:19 +01:00
if ( injectorType == Well :: InjectorType :: GAS && topUpPhase != Phase :: GAS )
2020-01-13 11:03:35 +01:00
continue ;
if ( injectorType == Well :: InjectorType :: MULTI )
throw ( "Expected WATER, OIL or GAS as type for injectors " + wellEcl . name ());
2019-11-13 23:16:11 +01:00
if ( wellState . currentInjectionControls ()[ well_index ] != Well :: InjectorCMode :: GRUP ) {
wellState . currentInjectionControls ()[ well_index ] = Well :: InjectorCMode :: GRUP ;
2019-10-16 15:27:40 +02:00
ss << " \n Injector " << wellName << " switches to GRUP control limit" ;
}
}
2019-08-07 14:13:11 +02:00
}
}
2019-11-26 11:15:09 +01:00
inline void setCmodeGroup ( const Group & group , const Schedule & schedule , const SummaryState & summaryState , const int reportStepIdx , WellStateFullyImplicitBlackoil & wellState ) {
for ( const std :: string & groupName : group . groups ()) {
setCmodeGroup ( schedule . getGroup ( groupName , reportStepIdx ), schedule , summaryState , reportStepIdx , wellState );
}
// use NONE as default control
if ( ! wellState . hasInjectionGroupControl ( group . name ())) {
wellState . setCurrentInjectionGroupControl ( group . name (), Group :: InjectionCMode :: NONE );
}
if ( ! wellState . hasProductionGroupControl ( group . name ())) {
wellState . setCurrentProductionGroupControl ( group . name (), Group :: ProductionCMode :: NONE );
}
2019-11-28 09:29:55 +01:00
if ( group . isInjectionGroup () && schedule . hasWellGroupEvent ( group . name (), ScheduleEvents :: GROUP_INJECTION_UPDATE , reportStepIdx )) {
2019-11-26 11:15:09 +01:00
const auto controls = group . injectionControls ( summaryState );
wellState . setCurrentInjectionGroupControl ( group . name (), controls . cmode );
}
2019-11-28 09:29:55 +01:00
if ( group . isProductionGroup () && schedule . hasWellGroupEvent ( group . name (), ScheduleEvents :: GROUP_PRODUCTION_UPDATE , reportStepIdx )) {
2019-11-26 11:15:09 +01:00
const auto controls = group . productionControls ( summaryState );
wellState . setCurrentProductionGroupControl ( group . name (), controls . cmode );
}
if ( schedule . gConSale ( reportStepIdx ). has ( group . name ())) {
wellState . setCurrentInjectionGroupControl ( group . name (), Group :: InjectionCMode :: SALE );
std :: ostringstream ss ;
2020-01-13 11:03:35 +01:00
setGroupControl ( group , schedule , Phase :: GAS , reportStepIdx , /*injector*/ true , wellState , ss );
2019-11-26 11:15:09 +01:00
}
}
inline void accumulateGroupEfficiencyFactor ( const Group & group , const Schedule & schedule , const int reportStepIdx , double & factor ) {
factor *= group . getGroupEfficiencyFactor ();
if ( group . parent () != "FIELD" )
accumulateGroupEfficiencyFactor ( schedule . getGroup ( group . parent (), reportStepIdx ), schedule , reportStepIdx , factor );
}
2019-08-07 14:13:11 +02:00
2019-11-13 23:16:11 +01:00
inline void computeGroupTargetReduction ( const Group & group , const WellStateFullyImplicitBlackoil & wellState , const Schedule & schedule , const int reportStepIdx , const int phasePos , const bool isInjector , double & groupTargetReduction )
2019-09-30 12:49:36 +02:00
{
2019-08-07 14:13:11 +02:00
for ( const std :: string & groupName : group . groups ()) {
2019-11-13 23:16:11 +01:00
const Group & groupTmp = schedule . getGroup ( groupName , reportStepIdx );
2019-09-30 12:49:36 +02:00
computeGroupTargetReduction ( groupTmp , wellState , schedule , reportStepIdx , phasePos , isInjector , groupTargetReduction );
2019-08-07 14:13:11 +02:00
}
for ( const std :: string & wellName : group . wells ()) {
2019-11-13 23:16:11 +01:00
const auto & wellTmp = schedule . getWell ( wellName , reportStepIdx );
2019-08-07 14:13:11 +02:00
2019-09-30 12:49:36 +02:00
if ( wellTmp . isProducer () && isInjector )
continue ;
2019-08-07 14:13:11 +02:00
2019-09-30 12:49:36 +02:00
if ( wellTmp . isInjector () && ! isInjector )
continue ;
2019-11-13 23:16:11 +01:00
if ( wellTmp . getStatus () == Well :: Status :: SHUT )
2019-08-07 14:13:11 +02:00
continue ;
2019-09-30 12:49:36 +02:00
const auto & end = wellState . wellMap (). end ();
const auto & it = wellState . wellMap (). find ( wellName );
if ( it == end ) // the well is not found
continue ;
2019-08-07 14:13:11 +02:00
2019-09-30 12:49:36 +02:00
int well_index = it -> second [ 0 ];
2019-08-07 14:13:11 +02:00
const auto wellrate_index = well_index * wellState . numPhases ();
2019-09-30 12:49:36 +02:00
// add contributino from wells not under group control
if ( isInjector ) {
2019-11-13 23:16:11 +01:00
if ( wellState . currentInjectionControls ()[ well_index ] != Well :: InjectorCMode :: GRUP )
2019-09-30 12:49:36 +02:00
groupTargetReduction += wellState . wellRates ()[ wellrate_index + phasePos ];
} else {
2019-11-13 23:16:11 +01:00
if ( wellState . currentProductionControls ()[ well_index ] != Well :: ProducerCMode :: GRUP )
2019-09-30 12:49:36 +02:00
groupTargetReduction -= wellState . wellRates ()[ wellrate_index + phasePos ];
}
2019-08-07 14:13:11 +02:00
}
}
2019-11-13 23:16:11 +01:00
inline double sumWellPhaseRates ( const std :: vector < double >& rates , const Group & group , const Schedule & schedule , const WellStateFullyImplicitBlackoil & wellState , const int reportStepIdx , const int phasePos ,
2019-09-30 12:49:36 +02:00
const bool injector ) {
double rate = 0.0 ;
2019-08-07 14:13:11 +02:00
for ( const std :: string & groupName : group . groups ()) {
2019-11-13 23:16:11 +01:00
const Group & groupTmp = schedule . getGroup ( groupName , reportStepIdx );
2019-09-30 12:49:36 +02:00
rate += groupTmp . getGroupEfficiencyFactor () * sumWellPhaseRates ( rates , groupTmp , schedule , wellState , reportStepIdx , phasePos , injector );
2019-08-07 14:13:11 +02:00
}
const auto & end = wellState . wellMap (). end ();
for ( const std :: string & wellName : group . wells ()) {
const auto & it = wellState . wellMap (). find ( wellName );
if ( it == end ) // the well is not found
continue ;
int well_index = it -> second [ 0 ];
2019-09-30 12:49:36 +02:00
2019-11-13 23:16:11 +01:00
const auto & wellEcl = schedule . getWell ( wellName , reportStepIdx );
2019-09-30 12:49:36 +02:00
//only count producers or injectors
if ( ( wellEcl . isProducer () && injector ) || ( wellEcl . isInjector () && ! injector ))
2019-08-07 14:13:11 +02:00
continue ;
2019-11-13 23:16:11 +01:00
if ( wellEcl . getStatus () == Well :: Status :: SHUT )
2019-09-30 12:49:36 +02:00
continue ;
double factor = wellEcl . getEfficiencyFactor ();
const auto wellrate_index = well_index * wellState . numPhases ();
if ( injector )
rate += factor * rates [ wellrate_index + phasePos ];
else
rate -= factor * rates [ wellrate_index + phasePos ];
2019-08-07 14:13:11 +02:00
}
2019-09-30 12:49:36 +02:00
return rate ;
2019-08-07 14:13:11 +02:00
}
2019-11-13 23:16:11 +01:00
inline double sumWellRates ( const Group & group , const Schedule & schedule , const WellStateFullyImplicitBlackoil & wellState , const int reportStepIdx , const int phasePos , const bool injector ) {
2019-09-30 12:49:36 +02:00
return sumWellPhaseRates ( wellState . wellRates (), group , schedule , wellState , reportStepIdx , phasePos , injector );
}
2019-08-07 14:13:11 +02:00
2019-11-13 23:16:11 +01:00
inline double sumWellResRates ( const Group & group , const Schedule & schedule , const WellStateFullyImplicitBlackoil & wellState , const int reportStepIdx , const int phasePos , const bool injector ) {
2019-09-30 12:49:36 +02:00
return sumWellPhaseRates ( wellState . wellReservoirRates (), group , schedule , wellState , reportStepIdx , phasePos , injector );
2019-08-07 14:13:11 +02:00
}
2019-11-13 23:16:11 +01:00
inline double sumSolventRates ( const Group & group , const Schedule & schedule , const WellStateFullyImplicitBlackoil & wellState , const int reportStepIdx , const bool injector ) {
2019-09-23 15:15:55 +02:00
double rate = 0.0 ;
for ( const std :: string & groupName : group . groups ()) {
2019-11-13 23:16:11 +01:00
const Group & groupTmp = schedule . getGroup ( groupName , reportStepIdx );
2019-09-23 15:15:55 +02:00
rate += groupTmp . getGroupEfficiencyFactor () * sumSolventRates ( groupTmp , schedule , wellState , reportStepIdx , injector );
}
const auto & end = wellState . wellMap (). end ();
for ( const std :: string & wellName : group . wells ()) {
const auto & it = wellState . wellMap (). find ( wellName );
if ( it == end ) // the well is not found
continue ;
int well_index = it -> second [ 0 ];
2019-11-13 23:16:11 +01:00
const auto & wellEcl = schedule . getWell ( wellName , reportStepIdx );
2019-09-23 15:15:55 +02:00
//only count producers or injectors
if ( ( wellEcl . isProducer () && injector ) || ( wellEcl . isInjector () && ! injector ))
continue ;
2019-11-13 23:16:11 +01:00
if ( wellEcl . getStatus () == Well :: Status :: SHUT )
2019-09-23 15:15:55 +02:00
continue ;
double factor = wellEcl . getEfficiencyFactor ();
if ( injector )
rate += factor * wellState . solventWellRate ( well_index );
else
rate -= factor * wellState . solventWellRate ( well_index );
}
return rate ;
}
2019-12-17 08:49:47 +01:00
inline void updateGroupTargetReduction ( const Group & group , const Schedule & schedule , const int reportStepIdx , const bool isInjector , const WellStateFullyImplicitBlackoil & wellStateNupcol , WellStateFullyImplicitBlackoil & wellState , std :: vector < double >& groupTargetReduction )
2019-11-05 15:12:01 +01:00
{
const int np = wellState . numPhases ();
for ( const std :: string & groupName : group . groups ()) {
std :: vector < double > thisGroupTargetReduction ( np , 0.0 );
2019-11-13 23:16:11 +01:00
const Group & groupTmp = schedule . getGroup ( groupName , reportStepIdx );
2019-12-17 08:49:47 +01:00
updateGroupTargetReduction ( groupTmp , schedule , reportStepIdx , isInjector , wellStateNupcol , wellState , thisGroupTargetReduction );
2019-11-05 15:12:01 +01:00
// accumulate group contribution from sub group
if ( isInjector ) {
2019-11-13 23:16:11 +01:00
const Group :: InjectionCMode & currentGroupControl = wellState . currentInjectionGroupControl ( groupName );
if ( currentGroupControl != Group :: InjectionCMode :: FLD ) {
2019-11-05 15:12:01 +01:00
for ( int phase = 0 ; phase < np ; phase ++ ) {
2019-12-17 08:49:47 +01:00
groupTargetReduction [ phase ] += sumWellRates ( groupTmp , schedule , wellStateNupcol , reportStepIdx , phase , isInjector );
2019-11-05 15:12:01 +01:00
}
continue ;
}
} else {
2019-11-13 23:16:11 +01:00
const Group :: ProductionCMode & currentGroupControl = wellState . currentProductionGroupControl ( groupName );
if ( currentGroupControl != Group :: ProductionCMode :: FLD ) {
2019-11-05 15:12:01 +01:00
for ( int phase = 0 ; phase < np ; phase ++ ) {
2019-12-17 08:49:47 +01:00
groupTargetReduction [ phase ] += sumWellRates ( groupTmp , schedule , wellStateNupcol , reportStepIdx , phase , isInjector );
2019-11-05 15:12:01 +01:00
}
continue ;
}
}
// or accumulate directly from the wells if controled from its parents
for ( int phase = 0 ; phase < np ; phase ++ ) {
groupTargetReduction [ phase ] += thisGroupTargetReduction [ phase ];
}
}
for ( const std :: string & wellName : group . wells ()) {
2019-11-13 23:16:11 +01:00
const auto & wellTmp = schedule . getWell ( wellName , reportStepIdx );
2019-11-05 15:12:01 +01:00
if ( wellTmp . isProducer () && isInjector )
continue ;
if ( wellTmp . isInjector () && ! isInjector )
continue ;
2019-11-13 23:16:11 +01:00
if ( wellTmp . getStatus () == Well :: Status :: SHUT )
2019-11-05 15:12:01 +01:00
continue ;
const auto & end = wellState . wellMap (). end ();
const auto & it = wellState . wellMap (). find ( wellName );
if ( it == end ) // the well is not found
continue ;
int well_index = it -> second [ 0 ];
const auto wellrate_index = well_index * wellState . numPhases ();
// add contributino from wells not under group control
if ( isInjector ) {
2019-11-13 23:16:11 +01:00
if ( wellState . currentInjectionControls ()[ well_index ] != Well :: InjectorCMode :: GRUP )
2019-11-05 15:12:01 +01:00
for ( int phase = 0 ; phase < np ; phase ++ ) {
2019-12-17 08:49:47 +01:00
groupTargetReduction [ phase ] += wellStateNupcol . wellRates ()[ wellrate_index + phase ];
2019-11-05 15:12:01 +01:00
}
} else {
2019-11-13 23:16:11 +01:00
if ( wellState . currentProductionControls ()[ well_index ] != Well :: ProducerCMode :: GRUP )
2019-11-05 15:12:01 +01:00
for ( int phase = 0 ; phase < np ; phase ++ ) {
2019-12-17 08:49:47 +01:00
groupTargetReduction [ phase ] -= wellStateNupcol . wellRates ()[ wellrate_index + phase ];
2019-11-05 15:12:01 +01:00
}
}
}
if ( isInjector )
wellState . setCurrentInjectionGroupReductionRates ( group . name (), groupTargetReduction );
else
wellState . setCurrentProductionGroupReductionRates ( group . name (), groupTargetReduction );
}
2019-12-12 09:22:37 +01:00
template < class Comm >
inline void updateGuideRateForGroups ( const Group & group , const Schedule & schedule , const PhaseUsage & pu , const int reportStepIdx , const double & simTime , const bool isInjector , WellStateFullyImplicitBlackoil & wellState , const Comm & comm , GuideRate * guideRate , std :: vector < double >& pot )
2019-12-16 13:48:48 +01:00
{
const int np = pu . num_phases ;
2019-08-07 14:13:11 +02:00
for ( const std :: string & groupName : group . groups ()) {
2019-12-16 13:48:48 +01:00
std :: vector < double > thisPot ( np , 0.0 );
2019-11-13 23:16:11 +01:00
const Group & groupTmp = schedule . getGroup ( groupName , reportStepIdx );
2019-12-12 09:22:37 +01:00
updateGuideRateForGroups ( groupTmp , schedule , pu , reportStepIdx , simTime , isInjector , wellState , comm , guideRate , thisPot );
2019-12-16 13:48:48 +01:00
// accumulate group contribution from sub group if FLD
if ( isInjector ) {
const Group :: InjectionCMode & currentGroupControl = wellState . currentInjectionGroupControl ( groupName );
if ( currentGroupControl != Group :: InjectionCMode :: FLD ) {
continue ;
}
} else {
const Group :: ProductionCMode & currentGroupControl = wellState . currentProductionGroupControl ( groupName );
if ( currentGroupControl != Group :: ProductionCMode :: FLD ) {
continue ;
}
}
for ( int phase = 0 ; phase < np ; phase ++ ) {
pot [ phase ] += thisPot [ phase ];
}
2019-08-07 14:13:11 +02:00
}
2019-12-16 13:48:48 +01:00
for ( const std :: string & wellName : group . wells ()) {
const auto & wellTmp = schedule . getWell ( wellName , reportStepIdx );
2019-09-30 12:49:36 +02:00
2019-12-16 13:48:48 +01:00
if ( wellTmp . isProducer () && isInjector )
continue ;
if ( wellTmp . isInjector () && ! isInjector )
continue ;
if ( wellTmp . getStatus () == Well :: Status :: SHUT )
continue ;
const auto & end = wellState . wellMap (). end ();
const auto & it = wellState . wellMap (). find ( wellName );
if ( it == end ) // the well is not found
continue ;
int well_index = it -> second [ 0 ];
const auto wellrate_index = well_index * wellState . numPhases ();
// add contribution from wells not under group control
if ( isInjector ) {
if ( wellState . currentInjectionControls ()[ well_index ] == Well :: InjectorCMode :: GRUP )
for ( int phase = 0 ; phase < np ; phase ++ ) {
pot [ phase ] += wellState . wellPotentials ()[ wellrate_index + phase ];
}
} else {
if ( wellState . currentProductionControls ()[ well_index ] == Well :: ProducerCMode :: GRUP )
for ( int phase = 0 ; phase < np ; phase ++ ) {
pot [ phase ] -= wellState . wellPotentials ()[ wellrate_index + phase ];
}
}
}
2019-09-30 12:49:36 +02:00
double oilPot = 0.0 ;
if ( pu . phase_used [ BlackoilPhases :: Liquid ])
2019-12-16 13:48:48 +01:00
oilPot = pot [ pu . phase_pos [ BlackoilPhases :: Liquid ]];
2019-12-12 09:22:37 +01:00
2019-09-30 12:49:36 +02:00
double gasPot = 0.0 ;
if ( pu . phase_used [ BlackoilPhases :: Vapour ])
2019-12-16 13:48:48 +01:00
gasPot = pot [ pu . phase_pos [ BlackoilPhases :: Vapour ]];
2019-09-30 12:49:36 +02:00
double waterPot = 0.0 ;
if ( pu . phase_used [ BlackoilPhases :: Aqua ])
2019-12-16 13:48:48 +01:00
waterPot = pot [ pu . phase_pos [ BlackoilPhases :: Aqua ]];
2019-09-30 12:49:36 +02:00
2019-12-12 09:22:37 +01:00
oilPot = comm . sum ( oilPot );
gasPot = comm . sum ( gasPot );
waterPot = comm . sum ( waterPot );
2019-12-16 13:48:48 +01:00
if ( isInjector ) {
wellState . setCurrentGroupInjectionPotentials ( group . name (), pot );
} else {
guideRate -> compute ( group . name (), reportStepIdx , simTime , oilPot , gasPot , waterPot );
}
2019-09-30 12:49:36 +02:00
}
2019-12-12 09:22:37 +01:00
template < class Comm >
inline void updateGuideRatesForWells ( const Schedule & schedule , const PhaseUsage & pu , const int reportStepIdx , const double & simTime , const WellStateFullyImplicitBlackoil & wellState , const Comm & comm , GuideRate * guideRate ) {
const auto & end = wellState . wellMap (). end ();
for ( const auto & well : schedule . getWells ( reportStepIdx )) {
double oilpot = 0.0 ;
double gaspot = 0.0 ;
double waterpot = 0.0 ;
const auto & it = wellState . wellMap (). find ( well . name ());
if ( it != end ) { // the well is found
int well_index = it -> second [ 0 ];
const auto wpot = wellState . wellPotentials (). data () + well_index * wellState . numPhases ();
if ( pu . phase_used [ BlackoilPhases :: Liquid ] > 0 )
oilpot = wpot [ pu . phase_pos [ BlackoilPhases :: Liquid ]];
if ( pu . phase_used [ BlackoilPhases :: Vapour ] > 0 )
gaspot = wpot [ pu . phase_pos [ BlackoilPhases :: Vapour ]];
if ( pu . phase_used [ BlackoilPhases :: Aqua ] > 0 )
waterpot = wpot [ pu . phase_pos [ BlackoilPhases :: Aqua ]];
}
oilpot = comm . sum ( oilpot );
gaspot = comm . sum ( gaspot );
waterpot = comm . sum ( waterpot );
guideRate -> compute ( well . name (), reportStepIdx , simTime , oilpot , gaspot , waterpot );
}
}
2020-01-08 14:13:38 +01:00
inline void updateVREPForGroups ( const Group & group , const Schedule & schedule , const int reportStepIdx , const WellStateFullyImplicitBlackoil & wellStateNupcol , WellStateFullyImplicitBlackoil & wellState ) {
2019-11-05 15:12:01 +01:00
for ( const std :: string & groupName : group . groups ()) {
2019-11-13 23:16:11 +01:00
const Group & groupTmp = schedule . getGroup ( groupName , reportStepIdx );
2020-01-08 14:13:38 +01:00
updateVREPForGroups ( groupTmp , schedule , reportStepIdx , wellStateNupcol , wellState );
2019-11-05 15:12:01 +01:00
}
const int np = wellState . numPhases ();
2020-01-08 14:13:38 +01:00
double resv = 0.0 ;
2019-11-05 15:12:01 +01:00
for ( int phase = 0 ; phase < np ; ++ phase ) {
2019-12-17 08:49:47 +01:00
resv += sumWellPhaseRates ( wellStateNupcol . wellReservoirRates (), group , schedule , wellState , reportStepIdx , phase , /*isInjector*/ false );
2019-11-05 15:12:01 +01:00
}
wellState . setCurrentInjectionVREPRates ( group . name (), resv );
}
2020-01-08 14:13:38 +01:00
inline void updateREINForGroups ( const Group & group , const Schedule & schedule , const int reportStepIdx , const PhaseUsage & pu , const SummaryState & st , const WellStateFullyImplicitBlackoil & wellStateNupcol , WellStateFullyImplicitBlackoil & wellState ) {
2019-11-05 15:12:01 +01:00
const int np = wellState . numPhases ();
for ( const std :: string & groupName : group . groups ()) {
2019-11-13 23:16:11 +01:00
const Group & groupTmp = schedule . getGroup ( groupName , reportStepIdx );
2020-01-08 14:13:38 +01:00
updateREINForGroups ( groupTmp , schedule , reportStepIdx , pu , st , wellStateNupcol , wellState );
2019-11-05 15:12:01 +01:00
}
2020-01-08 14:13:38 +01:00
std :: vector < double > rein ( np , 0.0 );
2019-11-05 15:12:01 +01:00
for ( int phase = 0 ; phase < np ; ++ phase ) {
2019-12-17 08:49:47 +01:00
rein [ phase ] = sumWellPhaseRates ( wellStateNupcol . wellRates (), group , schedule , wellState , reportStepIdx , phase , /*isInjector*/ false );
2019-11-05 15:12:01 +01:00
}
2019-11-25 11:10:11 +01:00
// add import rate and substract consumption rate for group for gas
if ( schedule . gConSump ( reportStepIdx ). has ( group . name ())) {
2019-11-26 11:15:09 +01:00
const auto & gconsump = schedule . gConSump ( reportStepIdx ). get ( group . name (), st );
2019-11-25 11:10:11 +01:00
if ( pu . phase_used [ BlackoilPhases :: Vapour ]) {
2019-11-26 11:15:09 +01:00
rein [ pu . phase_pos [ BlackoilPhases :: Vapour ]] += gconsump . import_rate ;
rein [ pu . phase_pos [ BlackoilPhases :: Vapour ]] -= gconsump . consumption_rate ;
2019-11-25 11:10:11 +01:00
}
}
2019-11-05 15:12:01 +01:00
wellState . setCurrentInjectionREINRates ( group . name (), rein );
}
2019-11-13 23:16:11 +01:00
inline double wellFractionFromGuideRates ( const Well & well , const Schedule & schedule , const WellStateFullyImplicitBlackoil & wellState , const int reportStepIdx , const GuideRate * guideRate , const Well :: GuideRateTarget & wellTarget , const bool isInjector ) {
2019-09-30 12:49:36 +02:00
double groupTotalGuideRate = 0.0 ;
2019-11-13 23:16:11 +01:00
const Group & groupTmp = schedule . getGroup ( well . groupName (), reportStepIdx );
2019-12-12 09:22:37 +01:00
int global_well_index = - 1 ;
2019-09-30 12:49:36 +02:00
for ( const std :: string & wellName : groupTmp . wells ()) {
2019-11-13 23:16:11 +01:00
const auto & wellTmp = schedule . getWell ( wellName , reportStepIdx );
2019-08-07 14:13:11 +02:00
2019-12-12 09:22:37 +01:00
global_well_index ++ ;
2019-08-07 14:13:11 +02:00
if ( wellTmp . isProducer () && isInjector )
continue ;
if ( wellTmp . isInjector () && ! isInjector )
continue ;
2019-11-13 23:16:11 +01:00
if ( wellTmp . getStatus () == Well :: Status :: SHUT )
2019-09-30 12:49:36 +02:00
continue ;
2019-08-07 14:13:11 +02:00
2019-10-17 12:40:14 +02:00
// only count wells under group control
if ( isInjector ) {
2019-12-12 09:22:37 +01:00
if ( ! wellState . isInjectionGrup ( wellName ))
2019-10-17 12:40:14 +02:00
continue ;
} else {
2019-12-12 09:22:37 +01:00
if ( ! wellState . isProductionGrup ( wellName ))
2019-10-17 12:40:14 +02:00
continue ;
}
2019-09-30 12:49:36 +02:00
groupTotalGuideRate += guideRate -> get ( wellName , wellTarget );
}
2019-09-30 15:26:47 +02:00
if ( groupTotalGuideRate == 0.0 )
return 0.0 ;
2019-09-30 12:49:36 +02:00
double wellGuideRate = guideRate -> get ( well . name (), wellTarget );
return wellGuideRate / groupTotalGuideRate ;
}
2019-12-16 13:48:48 +01:00
inline double groupFractionFromGuideRates ( const Group & group , const Schedule & schedule , const WellStateFullyImplicitBlackoil & wellState , const int reportStepIdx , const GuideRate * guideRate , const Group :: GuideRateTarget & groupTarget ) {
2019-09-30 12:49:36 +02:00
double groupTotalGuideRate = 0.0 ;
2019-11-13 23:16:11 +01:00
const Group & groupParent = schedule . getGroup ( group . parent (), reportStepIdx );
2019-09-30 12:49:36 +02:00
for ( const std :: string & groupName : groupParent . groups ()) {
2019-10-17 12:40:14 +02:00
// only count group under group control from its parent
2019-12-16 13:48:48 +01:00
const Group :: ProductionCMode & currentGroupControl = wellState . currentProductionGroupControl ( groupName );
if ( currentGroupControl != Group :: ProductionCMode :: FLD )
continue ;
2019-10-17 12:40:14 +02:00
2019-12-16 13:48:48 +01:00
groupTotalGuideRate += guideRate -> get ( groupName , groupTarget );
2019-08-07 14:13:11 +02:00
}
2019-09-30 15:26:47 +02:00
if ( groupTotalGuideRate == 0.0 )
2019-11-05 15:13:47 +01:00
return 1.0 ;
2019-09-30 15:26:47 +02:00
2019-09-30 12:49:36 +02:00
double groupGuideRate = guideRate -> get ( group . name (), groupTarget );
return groupGuideRate / groupTotalGuideRate ;
2019-08-07 14:13:11 +02:00
}
2019-12-16 13:48:48 +01:00
inline void accumulateGroupFractionsFromGuideRates ( const std :: string & groupName , const std :: string & controlGroupName , const Schedule & schedule , const WellStateFullyImplicitBlackoil & wellState , const int reportStepIdx , const GuideRate * guideRate , const Group :: GuideRateTarget & groupTarget , double & fraction ) {
2019-11-13 23:16:11 +01:00
const Group & group = schedule . getGroup ( groupName , reportStepIdx );
2019-09-30 12:49:36 +02:00
if ( groupName != controlGroupName ) {
2019-12-16 13:48:48 +01:00
fraction *= groupFractionFromGuideRates ( group , schedule , wellState , reportStepIdx , guideRate , groupTarget );
accumulateGroupFractionsFromGuideRates ( group . parent (), controlGroupName , schedule , wellState , reportStepIdx , guideRate , groupTarget , fraction );
2019-09-30 12:49:36 +02:00
}
2019-12-16 13:48:48 +01:00
return ;
}
inline double groupFractionFromInjectionPotentials ( const Group & group , const Schedule & schedule , const WellStateFullyImplicitBlackoil & wellState , const int reportStepIdx , const int phasePos ) {
double groupTotalGuideRate = 0.0 ;
const Group & groupParent = schedule . getGroup ( group . parent (), reportStepIdx );
for ( const std :: string & groupName : groupParent . groups ()) {
// only count group under group control from its parent
const Group :: InjectionCMode & currentGroupControl = wellState . currentInjectionGroupControl ( groupName );
if ( currentGroupControl != Group :: InjectionCMode :: FLD )
continue ;
groupTotalGuideRate += wellState . currentGroupInjectionPotentials ( groupName )[ phasePos ];
}
if ( groupTotalGuideRate == 0.0 )
return 1.0 ;
2019-09-30 12:49:36 +02:00
2019-12-16 13:48:48 +01:00
double groupGuideRate = wellState . currentGroupInjectionPotentials ( group . name ())[ phasePos ];
return groupGuideRate / groupTotalGuideRate ;
}
inline void accumulateGroupInjectionPotentialFractions ( const std :: string & groupName , const std :: string & controlGroupName , const Schedule & schedule , const WellStateFullyImplicitBlackoil & wellState , const int reportStepIdx , const int phasePos , double & fraction ) {
const Group & group = schedule . getGroup ( groupName , reportStepIdx );
if ( groupName != controlGroupName ) {
fraction *= groupFractionFromInjectionPotentials ( group , schedule , wellState , reportStepIdx , phasePos );
accumulateGroupInjectionPotentialFractions ( group . parent (), controlGroupName , schedule , wellState , reportStepIdx , phasePos , fraction );
}
2019-09-30 12:49:36 +02:00
return ;
}
2019-08-07 14:13:11 +02:00
} // namespace wellGroupHelpers
}
#endif