2019-02-07 14:43:17 +01:00
/*
2021-03-02 00:14:34 +01:00
Copyright 2016 - 2019 SINTEF Digital , Mathematics & Cybernetics .
Copyright 2016 - 2018 Equinor ASA .
Copyright 2017 Dr . Blatt - HPC - Simulation - Software & Services
Copyright 2016 - 2018 Norce AS
2017-02-13 16:45:06 +01:00
2021-03-02 00:14:34 +01:00
This file is part of the Open Porous Media project ( OPM ) .
2017-02-13 16:45:06 +01:00
2021-03-02 00:14:34 +01:00
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 .
2019-02-07 14:43:17 +01:00
2021-03-02 00:14:34 +01:00
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 .
2019-02-07 14:43:17 +01:00
2021-03-02 00:14:34 +01:00
You should have received a copy of the GNU General Public License
along with OPM . If not , see < http : //www.gnu.org/licenses/>.
2019-02-07 14:43:17 +01:00
*/
2019-05-07 13:06:02 +02:00
# include <opm/simulators/utils/DeferredLoggingErrorHelpers.hpp>
2019-11-25 10:34:50 +01:00
# include <opm/core/props/phaseUsageFromDeck.hpp>
2017-02-13 16:45:06 +01:00
2020-10-29 23:30:09 +01:00
# include <opm/parser/eclipse/Units/UnitSystem.hpp>
2020-09-22 14:12:15 +02:00
# include <algorithm>
2020-10-29 23:16:31 +01:00
# include <utility>
2021-03-02 00:14:34 +01:00
2020-10-01 18:27:57 +02:00
# include <fmt/format.h>
2020-07-20 21:38:30 +02:00
2017-02-13 16:45:06 +01:00
namespace Opm {
2017-05-03 13:34:15 +02:00
template < typename TypeTag >
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2021-04-25 20:47:31 +02:00
BlackoilWellModel ( Simulator & ebosSimulator , const PhaseUsage & phase_usage )
2021-03-02 00:14:34 +01:00
: ebosSimulator_ ( ebosSimulator )
, terminal_output_ ( ( ebosSimulator . gridView ( ) . comm ( ) . rank ( ) = = 0 ) & &
EWOMS_GET_PARAM ( TypeTag , bool , EnableTerminalOutput ) )
, phase_usage_ ( phase_usage )
, active_wgstate_ ( phase_usage )
, last_valid_wgstate_ ( phase_usage )
, nupcol_wgstate_ ( phase_usage )
2017-02-13 16:45:06 +01:00
{
2019-09-30 12:49:36 +02:00
// Create the guide rate container.
2021-03-02 00:14:34 +01:00
this - > guideRate_ =
std : : make_unique < GuideRate > ( ebosSimulator_ . vanguard ( ) . schedule ( ) ) ;
2019-10-23 09:09:45 +02:00
2020-10-05 20:02:13 +02:00
local_num_cells_ = ebosSimulator_ . gridView ( ) . size ( 0 ) ;
2021-03-02 00:14:34 +01:00
2020-10-05 12:43:55 +02:00
// Number of cells the global grid view
2020-10-05 20:02:13 +02:00
global_num_cells_ = ebosSimulator_ . vanguard ( ) . globalNumCells ( ) ;
2019-10-23 09:09:45 +02:00
// Set up cartesian mapping.
2021-03-02 00:14:34 +01:00
{
const auto & grid = this - > ebosSimulator_ . vanguard ( ) . grid ( ) ;
2021-05-05 11:22:44 +02:00
const auto & cartDims = UgGridHelpers : : cartDims ( grid ) ;
setupCartesianToCompressed_ ( UgGridHelpers : : globalCell ( grid ) ,
2021-03-02 00:14:34 +01:00
cartDims [ 0 ] * cartDims [ 1 ] * cartDims [ 2 ] ) ;
auto & parallel_wells = ebosSimulator . vanguard ( ) . parallelWells ( ) ;
this - > parallel_well_info_ . assign ( parallel_wells . begin ( ) ,
parallel_wells . end ( ) ) ;
}
const auto numProcs = ebosSimulator . gridView ( ) . comm ( ) . size ( ) ;
this - > not_on_process_ = [ this , numProcs ] ( const Well & well ) {
if ( numProcs = = decltype ( numProcs ) { 1 } )
return false ;
// Recall: false indicates NOT active!
const auto value = std : : make_pair ( well . name ( ) , true ) ;
auto candidate = std : : lower_bound ( this - > parallel_well_info_ . begin ( ) ,
this - > parallel_well_info_ . end ( ) ,
value ) ;
return ( candidate = = this - > parallel_well_info_ . end ( ) )
| | ( * candidate ! = value ) ;
} ;
this - > alternative_well_rate_init_ =
EWOMS_GET_PARAM ( TypeTag , bool , AlternativeWellRateInit ) ;
2018-08-16 11:51:36 +02:00
}
2021-04-25 20:47:31 +02:00
template < typename TypeTag >
BlackoilWellModel < TypeTag > : :
BlackoilWellModel ( Simulator & ebosSimulator ) :
BlackoilWellModel ( ebosSimulator , phaseUsageFromDeck ( ebosSimulator . vanguard ( ) . eclState ( ) ) )
{ }
2018-08-16 11:51:36 +02:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2019-04-03 17:26:57 +02:00
init ( )
2018-08-16 11:51:36 +02:00
{
extractLegacyCellPvtRegionIndex_ ( ) ;
extractLegacyDepth_ ( ) ;
2017-11-08 13:57:36 +01:00
gravity_ = ebosSimulator_ . problem ( ) . gravity ( ) [ 2 ] ;
2017-02-13 16:45:06 +01:00
2018-03-23 12:56:19 +01:00
initial_step_ = true ;
2018-08-16 11:51:36 +02:00
// add the eWoms auxiliary module for the wells to the list
ebosSimulator_ . model ( ) . addAuxiliaryModule ( this ) ;
2018-11-15 14:37:01 +01:00
2020-10-05 20:02:13 +02:00
is_cell_perforated_ . resize ( local_num_cells_ , false ) ;
2018-08-16 11:51:36 +02:00
}
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
addNeighbors ( std : : vector < NeighborSet > & neighbors ) const
{
if ( ! param_ . matrix_add_well_contributions_ ) {
return ;
}
// Create cartesian to compressed mapping
2019-11-13 23:16:11 +01:00
const auto & schedule_wells = schedule ( ) . getWellsatEnd ( ) ;
2018-08-16 11:51:36 +02:00
// initialize the additional cell connections introduced by wells.
2019-05-02 12:51:25 +02:00
for ( const auto & well : schedule_wells )
2018-08-16 11:51:36 +02:00
{
std : : vector < int > wellCells ;
// All possible connections of the well
2019-05-02 12:51:25 +02:00
const auto & connectionSet = well . getConnections ( ) ;
2018-08-16 11:51:36 +02:00
wellCells . reserve ( connectionSet . size ( ) ) ;
for ( size_t c = 0 ; c < connectionSet . size ( ) ; c + + )
{
const auto & connection = connectionSet . get ( c ) ;
2020-12-07 20:22:54 +01:00
int compressed_idx = cartesian_to_compressed_
. at ( connection . global_index ( ) ) ;
2018-08-16 11:51:36 +02:00
if ( compressed_idx > = 0 ) { // Ignore connections in inactive/remote cells.
wellCells . push_back ( compressed_idx ) ;
}
}
for ( int cellIdx : wellCells ) {
neighbors [ cellIdx ] . insert ( wellCells . begin ( ) ,
wellCells . end ( ) ) ;
}
}
}
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2019-10-02 12:48:29 +02:00
linearize ( SparseMatrixAdapter & jacobian , GlobalEqVector & res )
2018-08-16 11:51:36 +02:00
{
if ( ! localWellsActive ( ) )
return ;
2019-02-25 10:51:30 +01:00
if ( ! param_ . matrix_add_well_contributions_ ) {
// if the well contributions are not supposed to be included explicitly in
// the matrix, we only apply the vector part of the Schur complement here.
for ( const auto & well : well_container_ ) {
// r = r - duneC_^T * invDuneD_ * resWell_
well - > apply ( res ) ;
}
return ;
}
2018-08-16 11:51:36 +02:00
for ( const auto & well : well_container_ ) {
2019-10-02 12:48:29 +02:00
well - > addWellContributions ( jacobian ) ;
2018-08-16 11:51:36 +02:00
// applying the well residual to reservoir residuals
// r = r - duneC_^T * invDuneD_ * resWell_
well - > apply ( res ) ;
}
2017-11-08 13:57:36 +01:00
}
2017-02-13 16:45:06 +01:00
2018-11-22 11:01:58 +01:00
/// Return true if any well has a THP constraint.
template < typename TypeTag >
bool
BlackoilWellModel < TypeTag > : :
hasTHPConstraints ( ) const
{
2019-01-14 22:14:01 +01:00
int local_result = false ;
2019-08-07 14:13:11 +02:00
const auto & summaryState = ebosSimulator_ . vanguard ( ) . summaryState ( ) ;
2018-11-22 11:01:58 +01:00
for ( const auto & well : well_container_ ) {
2019-08-07 14:13:11 +02:00
if ( well - > wellHasTHPConstraints ( summaryState ) ) {
2019-01-14 22:14:01 +01:00
local_result = true ;
2018-11-22 11:01:58 +01:00
}
}
2019-01-14 22:14:01 +01:00
return grid ( ) . comm ( ) . max ( local_result ) ;
2018-11-22 11:01:58 +01:00
}
2018-12-03 13:24:34 +01:00
/// Return true if the well was found and shut.
2018-11-22 16:24:17 +01:00
template < typename TypeTag >
2018-12-03 13:24:34 +01:00
bool
2018-11-22 16:24:17 +01:00
BlackoilWellModel < TypeTag > : :
2018-11-23 12:51:13 +01:00
forceShutWellByNameIfPredictionMode ( const std : : string & wellname ,
const double simulation_time )
2018-11-22 16:24:17 +01:00
{
// Only add the well to the closed list on the
// process that owns it.
2018-12-03 13:24:34 +01:00
int well_was_shut = 0 ;
2018-11-22 16:24:17 +01:00
for ( const auto & well : well_container_ ) {
2019-08-07 14:13:11 +02:00
if ( well - > name ( ) = = wellname & & ! well - > wellIsStopped ( ) ) {
2019-06-26 09:50:56 +02:00
if ( well - > underPredictionMode ( ) ) {
2019-06-25 08:13:37 +02:00
wellTestState_ . closeWell ( wellname , WellTestConfig : : Reason : : PHYSICAL , simulation_time ) ;
2018-12-03 13:24:34 +01:00
well_was_shut = 1 ;
2018-11-23 12:51:13 +01:00
}
2018-11-22 16:24:17 +01:00
break ;
}
}
2018-12-03 13:24:34 +01:00
// Communicate across processes if a well was shut.
well_was_shut = ebosSimulator_ . vanguard ( ) . grid ( ) . comm ( ) . max ( well_was_shut ) ;
2018-11-22 16:24:17 +01:00
// Only log a message on the output rank.
2018-12-03 13:24:34 +01:00
if ( terminal_output_ & & well_was_shut ) {
2018-11-22 16:24:17 +01:00
const std : : string msg = " Well " + wellname
+ " will be shut because it cannot get converged. " ;
OpmLog : : info ( msg ) ;
}
2018-12-03 13:24:34 +01:00
return ( well_was_shut = = 1 ) ;
2018-11-22 16:24:17 +01:00
}
2020-10-09 15:09:28 +02:00
template < typename TypeTag >
std : : vector < Well >
BlackoilWellModel < TypeTag > : :
2021-04-28 10:22:29 +02:00
getLocalWells ( const int timeStepIdx ) const
2020-10-09 15:09:28 +02:00
{
auto w = schedule ( ) . getWells ( timeStepIdx ) ;
2020-12-09 11:02:04 +01:00
w . erase ( std : : remove_if ( w . begin ( ) , w . end ( ) , not_on_process_ ) , w . end ( ) ) ;
2020-12-04 10:06:14 +01:00
return w ;
}
template < typename TypeTag >
std : : vector < ParallelWellInfo * >
BlackoilWellModel < TypeTag > : : createLocalParallelWellInfo ( const std : : vector < Well > & wells )
{
std : : vector < ParallelWellInfo * > local_parallel_well_info ;
local_parallel_well_info . reserve ( wells . size ( ) ) ;
for ( const auto & well : wells )
2020-10-09 15:09:28 +02:00
{
auto wellPair = std : : make_pair ( well . name ( ) , true ) ;
auto pwell = std : : lower_bound ( parallel_well_info_ . begin ( ) ,
parallel_well_info_ . end ( ) ,
wellPair ) ;
assert ( pwell ! = parallel_well_info_ . end ( ) & &
* pwell = = wellPair ) ;
2020-12-04 10:06:14 +01:00
local_parallel_well_info . push_back ( & ( * pwell ) ) ;
2020-10-09 15:09:28 +02:00
}
2020-12-04 10:06:14 +01:00
return local_parallel_well_info ;
2020-10-09 15:09:28 +02:00
}
2018-11-22 16:24:17 +01:00
2017-05-03 13:34:15 +02:00
template < typename TypeTag >
2017-02-13 16:45:06 +01:00
void
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2017-11-08 13:57:36 +01:00
beginReportStep ( const int timeStepIdx )
2017-02-13 16:45:06 +01:00
{
2021-05-05 11:22:44 +02:00
DeferredLogger local_deferredLogger ;
2020-01-29 08:41:41 +01:00
report_step_starts_ = true ;
2019-02-07 14:43:17 +01:00
2018-02-01 16:27:42 +01:00
const Grid & grid = ebosSimulator_ . vanguard ( ) . grid ( ) ;
2019-05-29 07:44:23 +02:00
const auto & summaryState = ebosSimulator_ . vanguard ( ) . summaryState ( ) ;
2020-12-09 11:02:04 +01:00
// Make wells_ecl_ contain only this partition's wells.
2021-04-28 10:22:29 +02:00
wells_ecl_ = getLocalWells ( timeStepIdx ) ;
2020-12-04 10:06:14 +01:00
local_parallel_well_info_ = createLocalParallelWellInfo ( wells_ecl_ ) ;
2020-10-09 13:38:33 +02:00
2020-10-20 00:16:52 +02:00
// The well state initialize bhp with the cell pressure in the top cell.
// We must therefore provide it with updated cell pressures
this - > initializeWellPerfData ( ) ;
2021-04-28 10:22:29 +02:00
this - > initializeWellState ( timeStepIdx , summaryState ) ;
2017-11-16 11:42:34 +01:00
2017-11-08 13:57:36 +01:00
// Wells are active if they are active wells on at least
// one process.
wells_active_ = localWellsActive ( ) ? 1 : 0 ;
wells_active_ = grid . comm ( ) . max ( wells_active_ ) ;
// handling MS well related
2019-10-23 09:09:45 +02:00
if ( param_ . use_multisegment_well_ & & anyMSWellOpenLocal ( ) ) { // if we use MultisegmentWell model
2021-04-25 20:47:31 +02:00
this - > wellState ( ) . initWellStateMSWell ( wells_ecl_ , & this - > prevWellState ( ) ) ;
2017-06-07 09:29:31 +02:00
}
2019-11-13 23:16:11 +01:00
const Group & fieldGroup = schedule ( ) . getGroup ( " FIELD " , timeStepIdx ) ;
2021-04-22 17:31:21 +02:00
WellGroupHelpers : : setCmodeGroup ( fieldGroup , schedule ( ) , summaryState , timeStepIdx , this - > wellState ( ) , this - > groupState ( ) ) ;
2019-08-07 14:13:11 +02:00
// Compute reservoir volumes for RESV controls.
rateConverter_ . reset ( new RateConverterType ( phase_usage_ ,
2020-10-05 20:02:13 +02:00
std : : vector < int > ( local_num_cells_ , 0 ) ) ) ;
2019-08-07 14:13:11 +02:00
rateConverter_ - > template defineState < ElementContext > ( ebosSimulator_ ) ;
2017-11-08 13:57:36 +01:00
2021-01-14 19:22:34 +01:00
{
const auto & sched_state = this - > schedule ( ) [ timeStepIdx ] ;
// update VFP properties
vfp_properties_ . reset ( new VFPProperties ( sched_state . vfpinj ( ) , sched_state . vfpprod ( ) ) ) ;
this - > initializeWellProdIndCalculators ( ) ;
if ( sched_state . events ( ) . hasEvent ( ScheduleEvents : : Events : : WELL_PRODUCTIVITY_INDEX ) ) {
this - > runWellPIScaling ( timeStepIdx , local_deferredLogger ) ;
}
2020-10-29 23:30:09 +01:00
}
2021-03-26 22:10:16 +01:00
// Store the current well state, to be able to recover in the case of failed iterations
2021-04-22 17:31:21 +02:00
this - > commitWGState ( ) ;
2018-06-06 15:17:59 +02:00
}
// called at the beginning of a time step
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2021-03-01 15:17:52 +01:00
beginTimeStep ( )
{
2020-05-15 11:21:32 +02:00
updatePerforationIntensiveQuantities ( ) ;
2021-03-18 14:49:52 +01:00
updateAverageFormationFactor ( ) ;
2020-05-15 11:21:32 +02:00
2021-05-05 11:22:44 +02:00
DeferredLogger local_deferredLogger ;
2019-02-07 14:43:17 +01:00
2021-04-22 17:31:21 +02:00
this - > resetWGState ( ) ;
2021-03-19 11:09:14 +01:00
updateAndCommunicateGroupData ( ) ;
2021-03-30 17:10:09 +02:00
this - > wellState ( ) . gliftTimeStepInit ( ) ;
2018-08-16 11:51:36 +02:00
const int reportStepIdx = ebosSimulator_ . episodeIndex ( ) ;
const double simulationTime = ebosSimulator_ . time ( ) ;
2021-03-18 08:29:23 +01:00
std : : string exc_msg ;
auto exc_type = ExceptionType : : NONE ;
2019-02-07 14:43:17 +01:00
try {
// test wells
wellTesting ( reportStepIdx , simulationTime , local_deferredLogger ) ;
2018-06-06 15:17:59 +02:00
2019-02-07 14:43:17 +01:00
// create the well container
2019-10-23 09:09:45 +02:00
well_container_ = createWellContainer ( reportStepIdx ) ;
2017-11-08 13:57:36 +01:00
2019-02-07 14:43:17 +01:00
// do the initialization for all the wells
// TODO: to see whether we can postpone of the intialization of the well containers to
// optimize the usage of the following several member variables
for ( auto & well : well_container_ ) {
2021-03-18 14:49:52 +01:00
well - > init ( & phase_usage_ , depth_ , gravity_ , local_num_cells_ , B_avg_ ) ;
2019-02-07 14:43:17 +01:00
}
2017-08-07 11:35:59 +02:00
2019-02-07 14:43:17 +01:00
// update the updated cell flag
std : : fill ( is_cell_perforated_ . begin ( ) , is_cell_perforated_ . end ( ) , false ) ;
for ( auto & well : well_container_ ) {
well - > updatePerforatedCell ( is_cell_perforated_ ) ;
}
2018-11-15 14:37:01 +01:00
2019-02-07 14:43:17 +01:00
// calculate the efficiency factors for each well
2019-08-07 14:13:11 +02:00
calculateEfficiencyFactors ( reportStepIdx ) ;
2017-08-07 11:35:59 +02:00
2021-01-28 14:33:21 +01:00
if constexpr ( has_polymer_ )
2019-02-07 14:43:17 +01:00
{
2020-08-27 09:13:30 +02:00
if ( PolymerModule : : hasPlyshlog ( ) | | getPropValue < TypeTag , Properties : : EnablePolymerMW > ( ) ) {
2021-01-28 12:52:19 +01:00
setRepRadiusPerfLength ( ) ;
2019-02-07 14:43:17 +01:00
}
2017-11-08 13:57:36 +01:00
}
2021-03-18 08:29:23 +01:00
} catch ( const std : : runtime_error & e ) {
exc_type = ExceptionType : : RUNTIME_ERROR ;
exc_msg = e . what ( ) ;
} catch ( const std : : invalid_argument & e ) {
exc_type = ExceptionType : : INVALID_ARGUMENT ;
exc_msg = e . what ( ) ;
} catch ( const std : : logic_error & e ) {
exc_type = ExceptionType : : LOGIC_ERROR ;
exc_msg = e . what ( ) ;
} catch ( const std : : exception & e ) {
exc_type = ExceptionType : : DEFAULT ;
exc_msg = e . what ( ) ;
}
logAndCheckForExceptionsAndThrow ( local_deferredLogger , exc_type , " beginTimeStep() failed: " + exc_msg , terminal_output_ ) ;
2019-02-07 14:43:17 +01:00
2018-04-07 21:41:34 +02:00
for ( auto & well : well_container_ ) {
well - > setVFPProperties ( vfp_properties_ . get ( ) ) ;
2019-09-30 12:49:36 +02:00
well - > setGuideRate ( guideRate_ . get ( ) ) ;
2018-04-07 21:41:34 +02:00
}
2017-08-07 11:35:59 +02:00
2018-10-31 15:32:50 +01:00
// Close completions due to economical reasons
2018-06-06 15:17:59 +02:00
for ( auto & well : well_container_ ) {
2018-07-03 15:13:30 +02:00
well - > closeCompletions ( wellTestState_ ) ;
2018-06-06 15:17:59 +02:00
}
2019-09-30 12:49:36 +02:00
// calculate the well potentials
try {
std : : vector < double > well_potentials ;
computeWellPotentials ( well_potentials , reportStepIdx , local_deferredLogger ) ;
} catch ( std : : runtime_error & e ) {
const std : : string msg = " A zero well potential is returned for output purposes. " ;
local_deferredLogger . warning ( " WELL_POTENTIAL_CALCULATION_FAILED " , msg ) ;
}
2020-10-15 17:56:11 +02:00
if ( alternative_well_rate_init_ ) {
2020-12-07 10:05:46 +01:00
// Update the well rates of well_state_, if only single-phase rates, to
// have proper multi-phase rates proportional to rates at bhp zero.
// This is done only for producers, as injectors will only have a single
// nonzero phase anyway.
2020-10-15 17:56:11 +02:00
for ( auto & well : well_container_ ) {
2020-12-07 10:05:46 +01:00
if ( well - > isProducer ( ) ) {
2021-03-26 22:10:16 +01:00
well - > updateWellStateRates ( ebosSimulator_ , this - > wellState ( ) , local_deferredLogger ) ;
2020-12-07 10:05:46 +01:00
}
2020-10-15 17:56:11 +02:00
}
2020-05-15 11:21:32 +02:00
}
2021-03-19 11:09:14 +01:00
//update guide rates
2019-12-12 09:22:37 +01:00
const auto & comm = ebosSimulator_ . vanguard ( ) . grid ( ) . comm ( ) ;
2021-03-19 11:09:14 +01:00
const auto & summaryState = ebosSimulator_ . vanguard ( ) . summaryState ( ) ;
std : : vector < double > pot ( numPhases ( ) , 0.0 ) ;
const Group & fieldGroup = schedule ( ) . getGroup ( " FIELD " , reportStepIdx ) ;
2021-04-22 17:31:21 +02:00
WellGroupHelpers : : updateGuideRateForProductionGroups ( fieldGroup , schedule ( ) , phase_usage_ , reportStepIdx , simulationTime , this - > wellState ( ) , this - > groupState ( ) , comm , guideRate_ . get ( ) , pot ) ;
WellGroupHelpers : : updateGuideRatesForInjectionGroups ( fieldGroup , schedule ( ) , summaryState , phase_usage_ , reportStepIdx , this - > wellState ( ) , this - > groupState ( ) , guideRate_ . get ( ) , local_deferredLogger ) ;
2021-03-26 22:10:16 +01:00
WellGroupHelpers : : updateGuideRatesForWells ( schedule ( ) , phase_usage_ , reportStepIdx , simulationTime , this - > wellState ( ) , comm , guideRate_ . get ( ) ) ;
2021-03-19 11:09:14 +01:00
2021-01-19 14:43:32 +01:00
try {
2021-03-09 13:37:03 +01:00
// Compute initial well solution for new wells and injectors that change injection type i.e. WAG.
2021-01-19 14:43:32 +01:00
for ( auto & well : well_container_ ) {
const uint64_t effective_events_mask = ScheduleEvents : : WELL_STATUS_CHANGE
2021-03-09 13:37:03 +01:00
+ ScheduleEvents : : INJECTION_TYPE_CHANGED
2021-04-16 13:38:56 +02:00
+ ScheduleEvents : : WELL_SWITCHED_INJECTOR_PRODUCER
2021-03-09 13:37:03 +01:00
+ ScheduleEvents : : NEW_WELL ;
2021-01-19 14:43:32 +01:00
const auto & events = schedule ( ) [ reportStepIdx ] . wellgroup_events ( ) ;
const bool event = report_step_starts_ & & events . hasEvent ( well - > name ( ) , effective_events_mask ) ;
if ( event ) {
try {
2021-04-26 09:31:29 +02:00
well - > updateWellStateWithTarget ( ebosSimulator_ , this - > wellState ( ) , local_deferredLogger ) ;
2021-03-26 22:10:16 +01:00
well - > calculateExplicitQuantities ( ebosSimulator_ , this - > wellState ( ) , local_deferredLogger ) ;
2021-04-22 17:31:21 +02:00
well - > solveWellEquation ( ebosSimulator_ , this - > wellState ( ) , this - > groupState ( ) , local_deferredLogger ) ;
2021-03-18 08:29:23 +01:00
} catch ( const std : : exception & e ) {
2021-01-19 14:43:32 +01:00
const std : : string msg = " Compute initial well solution for new well " + well - > name ( ) + " failed. Continue with zero initial rates " ;
local_deferredLogger . warning ( " WELL_INITIAL_SOLVE_FAILED " , msg ) ;
}
}
2021-01-04 14:00:59 +01:00
}
2021-03-18 08:29:23 +01:00
} catch ( const std : : runtime_error & e ) {
exc_type = ExceptionType : : RUNTIME_ERROR ;
exc_msg = e . what ( ) ;
} catch ( const std : : invalid_argument & e ) {
exc_type = ExceptionType : : INVALID_ARGUMENT ;
exc_msg = e . what ( ) ;
} catch ( const std : : logic_error & e ) {
exc_type = ExceptionType : : LOGIC_ERROR ;
exc_msg = e . what ( ) ;
} catch ( const std : : exception & e ) {
exc_type = ExceptionType : : DEFAULT ;
exc_msg = e . what ( ) ;
}
if ( exc_type ! = ExceptionType : : NONE ) {
2021-01-19 14:43:32 +01:00
const std : : string msg = " Compute initial well solution for new wells failed. Continue with zero initial rates " ;
local_deferredLogger . warning ( " WELL_INITIAL_SOLVE_FAILED " , msg ) ;
2021-01-04 14:00:59 +01:00
}
2020-09-30 10:04:39 +02:00
logAndCheckForExceptionsAndThrow ( local_deferredLogger ,
2021-03-18 08:29:23 +01:00
exc_type , " beginTimeStep() failed: " + exc_msg , terminal_output_ ) ;
2020-09-30 10:04:39 +02:00
2017-08-10 15:27:05 +02:00
}
2020-09-30 10:04:39 +02:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : : gliftDebug (
2021-05-05 11:22:44 +02:00
const std : : string & msg , DeferredLogger & deferred_logger ) const
2020-09-30 10:04:39 +02:00
{
if ( this - > glift_debug ) {
2020-10-01 18:27:57 +02:00
const std : : string message = fmt : : format (
" GLIFT (DEBUG) : BlackoilWellModel : {} " , msg ) ;
deferred_logger . info ( message ) ;
2020-09-30 10:04:39 +02:00
}
}
2017-08-10 15:27:05 +02:00
2017-11-08 15:48:30 +01:00
template < typename TypeTag >
void
2021-03-01 15:17:52 +01:00
BlackoilWellModel < TypeTag > : : wellTesting ( const int timeStepIdx ,
const double simulationTime ,
2021-05-05 11:22:44 +02:00
DeferredLogger & deferred_logger )
2021-03-01 15:17:52 +01:00
{
2021-01-12 14:08:41 +01:00
const auto & wtest_config = schedule ( ) [ timeStepIdx ] . wtest_config ( ) ;
2019-02-03 08:13:11 +01:00
if ( wtest_config . size ( ) ! = 0 ) { // there is a WTEST request
2021-03-01 15:17:52 +01:00
const auto wellsForTesting = wellTestState_
. updateWells ( wtest_config , wells_ecl_ , simulationTime ) ;
2019-02-03 08:13:11 +01:00
for ( const auto & testWell : wellsForTesting ) {
const std : : string & well_name = testWell . first ;
2017-08-10 15:27:05 +02:00
2019-02-03 08:13:11 +01:00
// this is the well we will test
2019-02-07 14:43:17 +01:00
WellInterfacePtr well = createWellForWellTest ( well_name , timeStepIdx , deferred_logger ) ;
2018-06-06 15:17:59 +02:00
2019-02-03 08:13:11 +01:00
// some preparation before the well can be used
2021-03-18 14:49:52 +01:00
well - > init ( & phase_usage_ , depth_ , gravity_ , local_num_cells_ , B_avg_ ) ;
2019-11-13 23:16:11 +01:00
const Well & wellEcl = schedule ( ) . getWell ( well_name , timeStepIdx ) ;
2019-08-07 14:13:11 +02:00
double well_efficiency_factor = wellEcl . getEfficiencyFactor ( ) ;
2021-03-01 15:17:52 +01:00
WellGroupHelpers : : accumulateGroupEfficiencyFactor ( schedule ( ) . getGroup ( wellEcl . groupName ( ) , timeStepIdx ) ,
schedule ( ) , timeStepIdx , well_efficiency_factor ) ;
2019-02-03 08:13:11 +01:00
well - > setWellEfficiencyFactor ( well_efficiency_factor ) ;
well - > setVFPProperties ( vfp_properties_ . get ( ) ) ;
2019-09-30 12:49:36 +02:00
well - > setGuideRate ( guideRate_ . get ( ) ) ;
2017-11-08 15:48:30 +01:00
2019-02-03 08:13:11 +01:00
const WellTestConfig : : Reason testing_reason = testWell . second ;
2018-06-28 13:28:30 +02:00
2021-03-18 14:49:52 +01:00
well - > wellTesting ( ebosSimulator_ , simulationTime , timeStepIdx ,
2021-04-22 17:31:21 +02:00
testing_reason , this - > wellState ( ) , this - > groupState ( ) , wellTestState_ , deferred_logger ) ;
2019-02-03 08:13:11 +01:00
}
2019-01-18 14:04:30 +01:00
}
2017-11-08 15:48:30 +01:00
}
2021-03-01 15:17:52 +01:00
2017-11-08 15:48:30 +01:00
// called at the end of a report step
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2021-03-01 15:17:52 +01:00
endReportStep ( )
{
2020-11-27 18:26:59 +01:00
// Clear the communication data structures for above values.
2021-03-01 15:17:52 +01:00
for ( auto & & pinfo : local_parallel_well_info_ )
2020-11-27 18:26:59 +01:00
{
2020-12-14 16:35:30 +01:00
pinfo - > clear ( ) ;
2020-11-27 18:26:59 +01:00
}
2017-11-08 15:48:30 +01:00
}
2021-03-01 15:17:52 +01:00
2017-11-08 15:48:30 +01:00
// called at the end of a report step
template < typename TypeTag >
2020-05-07 16:13:39 +02:00
const SimulatorReportSingle &
2017-11-08 15:48:30 +01:00
BlackoilWellModel < TypeTag > : :
lastReport ( ) const { return last_report_ ; }
2021-03-01 15:17:52 +01:00
2017-11-08 15:48:30 +01:00
// called at the end of a time step
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2021-03-01 15:17:52 +01:00
timeStepSucceeded ( const double & simulationTime , const double dt )
{
2021-03-01 15:43:43 +01:00
this - > closed_this_step_ . clear ( ) ;
2019-02-03 08:13:11 +01:00
2020-01-29 08:41:41 +01:00
// time step is finished and we are not any more at the beginning of an report step
report_step_starts_ = false ;
2020-04-24 15:25:38 +02:00
const int reportStepIdx = ebosSimulator_ . episodeIndex ( ) ;
2020-01-29 08:41:41 +01:00
2021-05-05 11:22:44 +02:00
DeferredLogger local_deferredLogger ;
2018-02-14 13:34:35 +01:00
for ( const auto & well : well_container_ ) {
2020-08-27 09:13:30 +02:00
if ( getPropValue < TypeTag , Properties : : EnablePolymerMW > ( ) & & well - > isInjector ( ) ) {
2021-03-26 22:10:16 +01:00
well - > updateWaterThroughput ( dt , this - > wellState ( ) ) ;
2018-11-30 12:15:51 +01:00
}
2018-02-14 13:34:35 +01:00
}
2018-06-28 13:47:10 +02:00
updateWellTestState ( simulationTime , wellTestState_ ) ;
2018-11-07 14:53:43 +01:00
2019-08-07 14:13:11 +02:00
// update the rate converter with current averages pressures etc in
rateConverter_ - > template defineState < ElementContext > ( ebosSimulator_ ) ;
// calculate the well potentials
2019-02-07 14:43:17 +01:00
try {
2018-11-07 14:53:43 +01:00
std : : vector < double > well_potentials ;
2020-04-24 15:25:38 +02:00
2019-08-07 14:13:11 +02:00
computeWellPotentials ( well_potentials , reportStepIdx , local_deferredLogger ) ;
2019-02-07 14:43:17 +01:00
} catch ( std : : runtime_error & e ) {
2018-11-07 14:53:43 +01:00
const std : : string msg = " A zero well potential is returned for output purposes. " ;
2019-02-03 08:13:11 +01:00
local_deferredLogger . warning ( " WELL_POTENTIAL_CALCULATION_FAILED " , msg ) ;
2018-11-07 14:53:43 +01:00
}
2020-05-04 15:56:34 +02:00
// check group sales limits at the end of the timestep
const Group & fieldGroup = schedule ( ) . getGroup ( " FIELD " , reportStepIdx ) ;
2021-03-26 22:10:16 +01:00
checkGconsaleLimits ( fieldGroup , this - > wellState ( ) , local_deferredLogger ) ;
2020-05-04 15:56:34 +02:00
2020-10-09 13:38:33 +02:00
this - > calculateProductivityIndexValues ( local_deferredLogger ) ;
2021-04-22 17:31:21 +02:00
this - > commitWGState ( ) ;
2019-02-03 08:13:11 +01:00
2021-05-05 11:22:44 +02:00
DeferredLogger global_deferredLogger = gatherDeferredLogger ( local_deferredLogger ) ;
2019-02-03 08:13:11 +01:00
if ( terminal_output_ ) {
global_deferredLogger . logMessages ( ) ;
}
2021-03-08 15:11:50 +01:00
//reporting output temperatures
this - > computeWellTemperature ( ) ;
2017-11-08 15:48:30 +01:00
}
2017-08-10 15:27:05 +02:00
2018-08-16 11:51:36 +02:00
template < typename TypeTag >
template < class Context >
void
BlackoilWellModel < TypeTag > : :
computeTotalRatesForDof ( RateVector & rate ,
const Context & context ,
unsigned spaceIdx ,
unsigned timeIdx ) const
{
rate = 0 ;
int elemIdx = context . globalSpaceIndex ( spaceIdx , timeIdx ) ;
2018-11-15 14:37:01 +01:00
if ( ! is_cell_perforated_ [ elemIdx ] )
return ;
2018-08-16 11:51:36 +02:00
for ( const auto & well : well_container_ )
well - > addCellRates ( rate , elemIdx ) ;
}
2018-11-14 13:18:48 +01:00
template < typename TypeTag >
typename BlackoilWellModel < TypeTag > : : WellInterfacePtr
BlackoilWellModel < TypeTag > : :
well ( const std : : string & wellName ) const
{
for ( const auto & well : well_container_ ) {
if ( well - > name ( ) = = wellName ) {
return well ;
}
}
OPM_THROW ( std : : invalid_argument , " The well with name " + wellName + " is not in the well Container " ) ;
return nullptr ;
}
2018-08-16 11:51:36 +02:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
initFromRestartFile ( const RestartValue & restartValues )
{
2019-03-22 09:41:29 +01:00
// The restart step value is used to identify wells present at the given
// time step. Wells that are added at the same time step as RESTART is initiated
// will not be present in a restart file. Use the previous time step to retrieve
// wells that have information written to the restart file.
const int report_step = std : : max ( eclState ( ) . getInitConfig ( ) . getRestartStep ( ) - 1 , 0 ) ;
2019-05-29 07:44:23 +02:00
const auto & summaryState = ebosSimulator_ . vanguard ( ) . summaryState ( ) ;
2020-12-09 11:02:04 +01:00
// wells_ecl_ should only contain wells on this processor.
2021-04-28 10:22:29 +02:00
wells_ecl_ = getLocalWells ( report_step ) ;
2020-11-27 18:19:23 +01:00
local_parallel_well_info_ = createLocalParallelWellInfo ( wells_ecl_ ) ;
2018-08-16 11:51:36 +02:00
2020-10-09 13:38:33 +02:00
this - > initializeWellProdIndCalculators ( ) ;
2019-10-23 09:09:45 +02:00
initializeWellPerfData ( ) ;
2019-10-01 14:30:11 +02:00
2019-10-23 09:09:45 +02:00
const int nw = wells_ecl_ . size ( ) ;
2018-08-16 11:51:36 +02:00
if ( nw > 0 ) {
2018-11-12 14:57:13 +01:00
const auto phaseUsage = phaseUsageFromDeck ( eclState ( ) ) ;
2021-05-05 11:22:44 +02:00
const size_t numCells = UgGridHelpers : : numCells ( grid ( ) ) ;
2019-10-23 09:09:45 +02:00
const bool handle_ms_well = ( param_ . use_multisegment_well_ & & anyMSWellOpenLocal ( ) ) ;
2021-04-28 10:22:29 +02:00
this - > wellState ( ) . resize ( wells_ecl_ , local_parallel_well_info_ , schedule ( ) , handle_ms_well , numCells , well_perf_data_ , summaryState ) ; // Resize for restart step
2021-04-13 16:58:59 +02:00
loadRestartData ( restartValues . wells , restartValues . grp_nwrk , phaseUsage , handle_ms_well , this - > wellState ( ) ) ;
2018-08-16 11:51:36 +02:00
}
2019-08-07 14:13:11 +02:00
2021-04-22 17:31:21 +02:00
this - > commitWGState ( ) ;
2018-08-16 11:51:36 +02:00
initial_step_ = false ;
}
2018-11-17 23:36:31 +01:00
2020-10-09 13:38:33 +02:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
initializeWellProdIndCalculators ( )
{
this - > prod_index_calc_ . clear ( ) ;
this - > prod_index_calc_ . reserve ( this - > wells_ecl_ . size ( ) ) ;
for ( const auto & well : this - > wells_ecl_ ) {
this - > prod_index_calc_ . emplace_back ( well ) ;
}
}
2019-10-23 09:09:45 +02:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
initializeWellPerfData ( )
{
well_perf_data_ . resize ( wells_ecl_ . size ( ) ) ;
int well_index = 0 ;
for ( const auto & well : wells_ecl_ ) {
2020-11-27 18:26:59 +01:00
int completion_index = 0 ;
2020-12-14 16:19:48 +01:00
// INVALID_ECL_INDEX marks no above perf available
int completion_index_above = ParallelWellInfo : : INVALID_ECL_INDEX ;
2019-10-23 09:09:45 +02:00
well_perf_data_ [ well_index ] . clear ( ) ;
well_perf_data_ [ well_index ] . reserve ( well . getConnections ( ) . size ( ) ) ;
2020-11-27 18:19:23 +01:00
CheckDistributedWellConnections checker ( well , * local_parallel_well_info_ [ well_index ] ) ;
2020-11-27 18:22:23 +01:00
bool hasFirstPerforation = false ;
bool firstOpenCompletion = true ;
2020-11-27 18:26:59 +01:00
auto & parallelWellInfo = * local_parallel_well_info_ [ well_index ] ;
parallelWellInfo . beginReset ( ) ;
2020-11-27 18:19:23 +01:00
2019-10-23 09:09:45 +02:00
for ( const auto & completion : well . getConnections ( ) ) {
2020-12-07 20:22:54 +01:00
const int active_index =
cartesian_to_compressed_ [ completion . global_index ( ) ] ;
2019-10-23 09:09:45 +02:00
if ( completion . state ( ) = = Connection : : State : : OPEN ) {
2020-11-27 18:19:23 +01:00
if ( active_index > = 0 ) {
2020-11-27 18:22:23 +01:00
if ( firstOpenCompletion )
{
hasFirstPerforation = true ;
}
2020-11-27 18:19:23 +01:00
checker . connectionFound ( completion_index ) ;
2019-10-23 09:09:45 +02:00
PerforationData pd ;
pd . cell_index = active_index ;
2020-03-31 16:43:21 +02:00
pd . connection_transmissibility_factor = completion . CF ( ) ;
2019-10-23 09:09:45 +02:00
pd . satnum_id = completion . satTableId ( ) ;
2020-11-12 14:04:27 +01:00
pd . ecl_index = completion_index ;
2019-10-23 09:09:45 +02:00
well_perf_data_ [ well_index ] . push_back ( pd ) ;
2020-11-27 18:26:59 +01:00
parallelWellInfo . pushBackEclIndex ( completion_index_above ,
completion_index ) ;
2019-10-23 09:09:45 +02:00
}
2020-11-27 18:22:23 +01:00
firstOpenCompletion = false ;
2020-12-14 16:35:30 +01:00
// Next time this index is the one above as each open completion is
// is stored somehwere.
completion_index_above = completion_index ;
2019-10-23 09:09:45 +02:00
} else {
2020-11-27 18:19:23 +01:00
checker . connectionFound ( completion_index ) ;
2019-10-23 09:09:45 +02:00
if ( completion . state ( ) ! = Connection : : State : : SHUT ) {
OPM_THROW ( std : : runtime_error ,
" Completion state: " < < Connection : : State2String ( completion . state ( ) ) < < " not handled " ) ;
}
}
2020-11-27 18:26:59 +01:00
// Note: we rely on the connections being filtered! I.e. there are only connections
// to active cells in the global grid.
2020-11-12 14:04:27 +01:00
+ + completion_index ;
2019-10-23 09:09:45 +02:00
}
2020-11-27 18:26:59 +01:00
parallelWellInfo . endReset ( ) ;
2020-11-27 18:19:23 +01:00
checker . checkAllConnectionsFound ( ) ;
2020-11-27 18:26:59 +01:00
parallelWellInfo . communicateFirstPerforation ( hasFirstPerforation ) ;
2019-10-23 09:09:45 +02:00
+ + well_index ;
}
}
2020-10-20 00:16:52 +02:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
initializeWellState ( const int timeStepIdx ,
const SummaryState & summaryState )
{
std : : vector < double > cellPressures ( this - > local_num_cells_ , 0.0 ) ;
ElementContext elemCtx ( ebosSimulator_ ) ;
const auto & gridView = ebosSimulator_ . vanguard ( ) . gridView ( ) ;
const auto & elemEndIt = gridView . template end < /*codim=*/ 0 > ( ) ;
for ( auto elemIt = gridView . template begin < /*codim=*/ 0 > ( ) ;
elemIt ! = elemEndIt ;
+ + elemIt )
{
if ( elemIt - > partitionType ( ) ! = Dune : : InteriorEntity ) {
continue ;
}
elemCtx . updatePrimaryStencil ( * elemIt ) ;
elemCtx . updatePrimaryIntensiveQuantities ( /*timeIdx=*/ 0 ) ;
const auto & fs = elemCtx . intensiveQuantities ( /*spaceIdx=*/ 0 , /*timeIdx=*/ 0 ) . fluidState ( ) ;
// copy of get perfpressure in Standard well except for value
double & perf_pressure = cellPressures [ elemCtx . globalSpaceIndex ( /*spaceIdx=*/ 0 , /*timeIdx=*/ 0 ) ] ;
if ( Indices : : oilEnabled ) {
perf_pressure = fs . pressure ( FluidSystem : : oilPhaseIdx ) . value ( ) ;
} else if ( Indices : : waterEnabled ) {
perf_pressure = fs . pressure ( FluidSystem : : waterPhaseIdx ) . value ( ) ;
} else {
perf_pressure = fs . pressure ( FluidSystem : : gasPhaseIdx ) . value ( ) ;
}
}
2021-03-26 22:10:16 +01:00
this - > wellState ( ) . init ( cellPressures , schedule ( ) , wells_ecl_ , local_parallel_well_info_ , timeStepIdx ,
2021-04-25 20:47:31 +02:00
& this - > prevWellState ( ) , well_perf_data_ ,
2021-04-28 10:22:29 +02:00
summaryState ) ;
2020-10-20 00:16:52 +02:00
}
2017-06-15 17:19:49 +02:00
template < typename TypeTag >
2017-09-26 10:52:05 +02:00
std : : vector < typename BlackoilWellModel < TypeTag > : : WellInterfacePtr >
BlackoilWellModel < TypeTag > : :
2019-10-23 09:09:45 +02:00
createWellContainer ( const int time_step )
2017-06-15 17:19:49 +02:00
{
2017-08-21 10:23:42 +02:00
std : : vector < WellInterfacePtr > well_container ;
2021-05-05 11:22:44 +02:00
DeferredLogger local_deferredLogger ;
2019-12-13 11:08:36 +01:00
2019-11-01 15:11:21 +01:00
const int nw = numLocalWells ( ) ;
2017-06-15 17:19:49 +02:00
2017-08-21 10:23:42 +02:00
if ( nw > 0 ) {
well_container . reserve ( nw ) ;
2021-03-01 15:17:52 +01:00
2017-06-15 17:19:49 +02:00
for ( int w = 0 ; w < nw ; + + w ) {
2019-10-23 09:09:45 +02:00
const Well & well_ecl = wells_ecl_ [ w ] ;
const std : : string & well_name = well_ecl . name ( ) ;
2021-03-01 15:43:43 +01:00
const auto well_status = this - > schedule ( )
. getWell ( well_name , time_step ) . getStatus ( ) ;
if ( ( well_ecl . getStatus ( ) = = Well : : Status : : SHUT ) | |
( well_status = = Well : : Status : : SHUT ) )
{
// Due to ACTIONX the well might have been closed behind our back.
if ( well_ecl . getStatus ( ) ! = Well : : Status : : SHUT ) {
this - > closed_this_step_ . insert ( well_name ) ;
2021-03-26 22:10:16 +01:00
this - > wellState ( ) . shutWell ( w ) ;
2021-03-01 15:43:43 +01:00
}
continue ;
}
2017-06-15 17:19:49 +02:00
2019-07-31 16:15:41 +02:00
// A new WCON keywords can re-open a well that was closed/shut due to Physical limit
2021-03-01 15:17:52 +01:00
if ( this - > wellTestState_ . hasWellClosed ( well_name ) ) {
2019-07-31 16:15:41 +02:00
// TODO: more checking here, to make sure this standard more specific and complete
// maybe there is some WCON keywords will not open the well
2021-05-07 11:21:58 +02:00
auto & events = this - > wellState ( ) . events ( w ) ;
if ( events . hasEvent ( WellStateFullyImplicitBlackoil : : event_mask ) ) {
2019-07-31 16:15:41 +02:00
if ( wellTestState_ . lastTestTime ( well_name ) = = ebosSimulator_ . time ( ) ) {
// The well was shut this timestep, we are most likely retrying
// a timestep without the well in question, after it caused
// repeated timestep cuts. It should therefore not be opened,
// even if it was new or received new targets this report step.
2021-05-07 11:21:58 +02:00
events . clearEvent ( WellStateFullyImplicitBlackoil : : event_mask ) ;
2019-07-31 16:15:41 +02:00
} else {
wellTestState_ . openWell ( well_name ) ;
2018-12-14 10:04:59 +01:00
}
2018-11-17 23:36:31 +01:00
}
2019-07-31 16:15:41 +02:00
}
2018-11-17 23:30:27 +01:00
2019-07-31 16:15:41 +02:00
// TODO: should we do this for all kinds of closing reasons?
// something like wellTestState_.hasWell(well_name)?
2019-08-07 14:13:11 +02:00
bool wellIsStopped = false ;
2021-03-01 15:17:52 +01:00
if ( wellTestState_ . hasWellClosed ( well_name , WellTestConfig : : Reason : : ECONOMIC ) | |
wellTestState_ . hasWellClosed ( well_name , WellTestConfig : : Reason : : PHYSICAL ) )
{
if ( well_ecl . getAutomaticShutIn ( ) ) {
2019-07-31 16:15:41 +02:00
// shut wells are not added to the well container
2021-03-26 22:10:16 +01:00
this - > wellState ( ) . shutWell ( w ) ;
2019-07-31 16:15:41 +02:00
continue ;
} else {
2019-08-07 14:13:11 +02:00
// stopped wells are added to the container but marked as stopped
2021-03-26 22:10:16 +01:00
this - > wellState ( ) . stopWell ( w ) ;
2019-08-07 14:13:11 +02:00
wellIsStopped = true ;
2018-06-06 15:17:59 +02:00
}
}
2019-12-13 11:08:36 +01:00
// If a production well disallows crossflow and its
// (prediction type) rate control is zero, then it is effectively shut.
if ( ! well_ecl . getAllowCrossFlow ( ) & & well_ecl . isProducer ( ) & & well_ecl . predictionMode ( ) ) {
const auto & summaryState = ebosSimulator_ . vanguard ( ) . summaryState ( ) ;
2021-03-01 15:17:52 +01:00
const auto prod_controls = well_ecl . productionControls ( summaryState ) ;
auto is_zero = [ ] ( const double x )
{
return std : : isfinite ( x ) & & ! std : : isnormal ( x ) ;
} ;
2019-12-13 11:08:36 +01:00
bool zero_rate_control = false ;
switch ( prod_controls . cmode ) {
case Well : : ProducerCMode : : ORAT :
2021-03-01 15:17:52 +01:00
zero_rate_control = is_zero ( prod_controls . oil_rate ) ;
2019-12-13 11:08:36 +01:00
break ;
2021-03-01 15:17:52 +01:00
2019-12-13 11:08:36 +01:00
case Well : : ProducerCMode : : WRAT :
2021-03-01 15:17:52 +01:00
zero_rate_control = is_zero ( prod_controls . water_rate ) ;
2019-12-13 11:08:36 +01:00
break ;
2021-03-01 15:17:52 +01:00
2019-12-13 11:08:36 +01:00
case Well : : ProducerCMode : : GRAT :
2021-03-01 15:17:52 +01:00
zero_rate_control = is_zero ( prod_controls . gas_rate ) ;
2019-12-13 11:08:36 +01:00
break ;
2021-03-01 15:17:52 +01:00
2019-12-13 11:08:36 +01:00
case Well : : ProducerCMode : : LRAT :
2021-03-01 15:17:52 +01:00
zero_rate_control = is_zero ( prod_controls . liquid_rate ) ;
2019-12-13 11:08:36 +01:00
break ;
2021-03-01 15:17:52 +01:00
2019-12-13 11:08:36 +01:00
case Well : : ProducerCMode : : RESV :
2021-03-01 15:17:52 +01:00
zero_rate_control = is_zero ( prod_controls . resv_rate ) ;
2019-12-13 11:08:36 +01:00
break ;
2021-03-01 15:17:52 +01:00
2019-12-13 11:08:36 +01:00
default :
// Might still have zero rate controls, but is pressure controlled.
zero_rate_control = false ;
2021-03-01 15:17:52 +01:00
break ;
2019-12-13 11:08:36 +01:00
}
2021-03-01 15:17:52 +01:00
2019-12-13 11:08:36 +01:00
if ( zero_rate_control ) {
// Treat as shut, do not add to container.
local_deferredLogger . info ( " Well shut due to zero rate control and disallowing crossflow: " + well_ecl . name ( ) ) ;
2021-03-26 22:10:16 +01:00
this - > wellState ( ) . shutWell ( w ) ;
2019-12-13 11:08:36 +01:00
continue ;
}
}
2019-12-06 13:12:36 +01:00
if ( well_status = = Well : : Status : : STOP ) {
2021-03-26 22:10:16 +01:00
this - > wellState ( ) . stopWell ( w ) ;
2019-12-06 13:12:36 +01:00
wellIsStopped = true ;
}
2020-12-01 18:04:46 +01:00
well_container . emplace_back ( this - > createWellPointer ( w , time_step ) ) ;
2019-08-07 14:13:11 +02:00
if ( wellIsStopped )
well_container . back ( ) - > stopWell ( ) ;
2017-06-15 17:19:49 +02:00
}
}
2019-02-07 14:43:17 +01:00
2019-12-13 11:08:36 +01:00
// Collect log messages and print.
2021-05-05 11:22:44 +02:00
DeferredLogger global_deferredLogger = gatherDeferredLogger ( local_deferredLogger ) ;
2019-12-13 11:08:36 +01:00
if ( terminal_output_ ) {
global_deferredLogger . logMessages ( ) ;
}
2017-08-21 10:23:42 +02:00
return well_container ;
2017-06-15 17:19:49 +02:00
}
2021-03-02 01:11:19 +01:00
template < typename TypeTag >
void BlackoilWellModel < TypeTag > : :
inferLocalShutWells ( )
{
this - > local_shut_wells_ . clear ( ) ;
const auto nw = this - > numLocalWells ( ) ;
auto used = std : : vector < bool > ( nw , false ) ;
for ( const auto & wellPtr : this - > well_container_ ) {
used [ wellPtr - > indexOfWell ( ) ] = true ;
}
for ( auto wellID = 0 ; wellID < nw ; + + wellID ) {
if ( ! used [ wellID ] ) {
this - > local_shut_wells_ . push_back ( wellID ) ;
}
}
}
2020-12-01 18:04:46 +01:00
template < typename TypeTag >
typename BlackoilWellModel < TypeTag > : : WellInterfacePtr
BlackoilWellModel < TypeTag > : :
createWellPointer ( const int wellID , const int time_step ) const
{
const auto is_multiseg = this - > wells_ecl_ [ wellID ] . isMultiSegment ( ) ;
if ( ! ( this - > param_ . use_multisegment_well_ & & is_multiseg ) ) {
return this - > template createTypedWellPointer < StandardWell < TypeTag > > ( wellID , time_step ) ;
}
else {
return this - > template createTypedWellPointer < MultisegmentWell < TypeTag > > ( wellID , time_step ) ;
}
}
template < typename TypeTag >
template < typename WellType >
std : : unique_ptr < WellType >
BlackoilWellModel < TypeTag > : :
createTypedWellPointer ( const int wellID , const int time_step ) const
{
// Use the pvtRegionIdx from the top cell
const auto & perf_data = this - > well_perf_data_ [ wellID ] ;
2020-11-27 18:22:23 +01:00
// Cater for case where local part might have no perforations.
2021-03-01 15:17:52 +01:00
const auto pvtreg = perf_data . empty ( )
? 0 : pvt_region_idx_ [ perf_data . front ( ) . cell_index ] ;
2020-11-27 18:22:23 +01:00
const auto & parallel_well_info = * local_parallel_well_info_ [ wellID ] ;
2021-03-01 15:17:52 +01:00
const auto global_pvtreg = parallel_well_info . broadcastFirstPerforationValue ( pvtreg ) ;
2020-11-27 18:22:23 +01:00
2020-12-01 18:04:46 +01:00
return std : : make_unique < WellType > ( this - > wells_ecl_ [ wellID ] ,
2020-11-27 18:22:23 +01:00
parallel_well_info ,
2020-12-01 18:04:46 +01:00
time_step ,
this - > param_ ,
* this - > rateConverter_ ,
2020-11-27 18:22:23 +01:00
global_pvtreg ,
2020-12-01 18:04:46 +01:00
this - > numComponents ( ) ,
this - > numPhases ( ) ,
wellID ,
2021-03-26 22:10:16 +01:00
this - > wellState ( ) . firstPerfIndex ( ) [ wellID ] ,
2020-12-01 18:04:46 +01:00
perf_data ) ;
}
2018-10-31 14:56:56 +01:00
template < typename TypeTag >
typename BlackoilWellModel < TypeTag > : : WellInterfacePtr
BlackoilWellModel < TypeTag > : :
createWellForWellTest ( const std : : string & well_name ,
2019-02-07 14:43:17 +01:00
const int report_step ,
2021-05-05 11:22:44 +02:00
DeferredLogger & deferred_logger ) const
2018-10-31 14:56:56 +01:00
{
// Finding the location of the well in wells_ecl
const int nw_wells_ecl = wells_ecl_ . size ( ) ;
int index_well_ecl = 0 ;
for ( ; index_well_ecl < nw_wells_ecl ; + + index_well_ecl ) {
2019-05-02 12:51:25 +02:00
if ( well_name = = wells_ecl_ [ index_well_ecl ] . name ( ) ) {
2018-10-31 14:56:56 +01:00
break ;
}
}
// It should be able to find in wells_ecl.
if ( index_well_ecl = = nw_wells_ecl ) {
2019-02-07 14:43:17 +01:00
OPM_DEFLOG_THROW ( std : : logic_error , " Could not find well " < < well_name < < " in wells_ecl " , deferred_logger ) ;
2018-10-31 14:56:56 +01:00
}
2020-12-01 18:04:46 +01:00
return this - > createWellPointer ( index_well_ecl , report_step ) ;
2018-10-31 14:56:56 +01:00
}
2017-05-03 13:34:15 +02:00
template < typename TypeTag >
2017-11-08 13:57:36 +01:00
void
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2017-11-08 13:57:36 +01:00
assemble ( const int iterationIdx ,
2018-06-29 09:12:14 +02:00
const double dt )
2017-02-13 16:45:06 +01:00
{
2017-11-08 13:57:36 +01:00
2021-05-05 11:22:44 +02:00
DeferredLogger local_deferredLogger ;
2020-09-30 10:04:39 +02:00
if ( this - > glift_debug ) {
2020-10-01 18:27:57 +02:00
const std : : string msg = fmt : : format (
" assemble() : iteration {} " , iterationIdx ) ;
gliftDebug ( msg , local_deferredLogger ) ;
2020-09-30 10:04:39 +02:00
}
2020-05-07 16:13:39 +02:00
last_report_ = SimulatorReportSingle ( ) ;
2020-09-07 15:05:02 +02:00
Dune : : Timer perfTimer ;
perfTimer . start ( ) ;
2017-11-08 13:57:36 +01:00
2017-11-08 15:48:30 +01:00
if ( ! wellsActive ( ) ) {
return ;
}
2019-02-03 08:13:11 +01:00
2017-11-08 13:57:36 +01:00
updatePerforationIntensiveQuantities ( ) ;
2017-02-13 16:45:06 +01:00
2021-03-18 08:29:23 +01:00
auto exc_type = ExceptionType : : NONE ;
std : : string exc_msg ;
2019-02-07 14:43:17 +01:00
try {
if ( iterationIdx = = 0 ) {
calculateExplicitQuantities ( local_deferredLogger ) ;
2019-05-24 16:45:27 +02:00
prepareTimeStep ( local_deferredLogger ) ;
2019-02-07 14:43:17 +01:00
}
2020-02-10 15:16:09 +01:00
updateWellControls ( local_deferredLogger , /* check group controls */ true ) ;
2019-11-06 16:16:19 +01:00
2019-02-07 14:43:17 +01:00
// Set the well primary variables based on the value of well solutions
initPrimaryVariablesEvaluation ( ) ;
2017-02-13 16:45:06 +01:00
2021-03-03 13:59:26 +01:00
maybeDoGasLiftOptimize ( local_deferredLogger ) ;
2021-03-18 14:49:52 +01:00
assembleWellEq ( dt , local_deferredLogger ) ;
2021-03-18 08:29:23 +01:00
} catch ( const std : : runtime_error & e ) {
exc_type = ExceptionType : : RUNTIME_ERROR ;
exc_msg = e . what ( ) ;
} catch ( const std : : invalid_argument & e ) {
exc_type = ExceptionType : : INVALID_ARGUMENT ;
exc_msg = e . what ( ) ;
} catch ( const std : : logic_error & e ) {
exc_type = ExceptionType : : LOGIC_ERROR ;
exc_msg = e . what ( ) ;
} catch ( const std : : exception & e ) {
exc_type = ExceptionType : : DEFAULT ;
exc_msg = e . what ( ) ;
}
logAndCheckForExceptionsAndThrow ( local_deferredLogger , exc_type , " assemble() failed: " + exc_msg , terminal_output_ ) ;
2017-11-08 13:57:36 +01:00
last_report_ . converged = true ;
2020-09-07 15:05:02 +02:00
last_report_ . assemble_time_well + = perfTimer . stop ( ) ;
2017-02-13 16:45:06 +01:00
}
2021-03-25 22:40:12 +01:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2021-05-05 11:22:44 +02:00
maybeDoGasLiftOptimize ( DeferredLogger & deferred_logger )
2021-03-03 13:59:26 +01:00
{
2021-03-30 17:10:09 +02:00
this - > wellState ( ) . enableGliftOptimization ( ) ;
2021-03-03 13:59:26 +01:00
GLiftOptWells glift_wells ;
GLiftProdWells prod_wells ;
GLiftWellStateMap state_map ;
// Stage1: Optimize single wells not checking any group limits
for ( auto & well : well_container_ ) {
well - > gasLiftOptimizationStage1 (
2021-03-30 17:10:09 +02:00
this - > wellState ( ) , ebosSimulator_ , deferred_logger ,
2021-03-03 13:59:26 +01:00
prod_wells , glift_wells , state_map ) ;
}
gasLiftOptimizationStage2 ( deferred_logger , prod_wells , glift_wells , state_map ) ;
if ( this - > glift_debug ) gliftDebugShowALQ ( deferred_logger ) ;
2021-03-30 17:10:09 +02:00
this - > wellState ( ) . disableGliftOptimization ( ) ;
2021-03-03 13:59:26 +01:00
}
// If a group has any production rate constraints, and/or a limit
// on its total rate of lift gas supply, allocate lift gas
// preferentially to the wells that gain the most benefit from
// it. Lift gas increments are allocated in turn to the well that
// currently has the largest weighted incremental gradient. The
// procedure takes account of any limits on the group production
// rate or lift gas supply applied to any level of group.
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2021-05-05 11:22:44 +02:00
gasLiftOptimizationStage2 ( DeferredLogger & deferred_logger ,
2021-03-03 13:59:26 +01:00
GLiftProdWells & prod_wells , GLiftOptWells & glift_wells ,
GLiftWellStateMap & glift_well_state_map )
{
2021-03-30 17:10:09 +02:00
GasLiftStage2 glift { * this , ebosSimulator_ , deferred_logger , this - > wellState ( ) ,
2021-03-03 13:59:26 +01:00
prod_wells , glift_wells , glift_well_state_map } ;
glift . runOptimize ( ) ;
}
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2021-05-05 11:22:44 +02:00
gliftDebugShowALQ ( DeferredLogger & deferred_logger )
2021-03-03 13:59:26 +01:00
{
for ( auto & well : this - > well_container_ ) {
if ( well - > isProducer ( ) ) {
2021-03-30 17:10:09 +02:00
auto alq = this - > wellState ( ) . getALQ ( well - > name ( ) ) ;
2021-03-03 13:59:26 +01:00
const std : : string msg = fmt : : format ( " ALQ_REPORT : {} : {} " ,
well - > name ( ) , alq ) ;
gliftDebug ( msg , deferred_logger ) ;
}
}
}
2017-05-03 13:34:15 +02:00
template < typename TypeTag >
2017-02-13 16:45:06 +01:00
void
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2021-05-05 11:22:44 +02:00
assembleWellEq ( const double dt , DeferredLogger & deferred_logger )
2017-02-13 16:45:06 +01:00
{
2018-06-06 15:17:59 +02:00
for ( auto & well : well_container_ ) {
2021-04-22 17:31:21 +02:00
well - > assembleWellEq ( ebosSimulator_ , dt , this - > wellState ( ) , this - > groupState ( ) , deferred_logger ) ;
2017-07-21 14:21:17 +02:00
}
2017-02-13 17:07:34 +01:00
}
2018-11-05 15:54:48 +01:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
apply ( BVector & r ) const
{
if ( ! localWellsActive ( ) ) {
return ;
}
for ( auto & well : well_container_ ) {
well - > apply ( r ) ;
}
}
2017-02-13 17:07:34 +01:00
2017-07-21 14:21:17 +02:00
// Ax = A x - C D^-1 B x
2017-05-03 13:34:15 +02:00
template < typename TypeTag >
2017-02-13 17:07:34 +01:00
void
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2017-06-07 14:23:43 +02:00
apply ( const BVector & x , BVector & Ax ) const
2017-02-13 17:07:34 +01:00
{
2017-07-21 15:30:34 +02:00
// TODO: do we still need localWellsActive()?
2018-02-26 15:47:25 +01:00
if ( ! localWellsActive ( ) ) {
2017-02-13 17:07:34 +01:00
return ;
}
2017-07-21 14:21:17 +02:00
for ( auto & well : well_container_ ) {
2018-03-02 20:47:04 +01:00
well - > apply ( x , Ax ) ;
2017-07-21 14:21:17 +02:00
}
2017-02-13 17:07:34 +01:00
}
2020-06-25 18:44:49 +02:00
# if HAVE_CUDA || HAVE_OPENCL
2020-03-13 14:21:59 +01:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
getWellContributions ( WellContributions & wellContribs ) const
{
2020-05-15 16:00:09 +02:00
// prepare for StandardWells
2020-03-19 11:08:11 +01:00
wellContribs . setBlockSize ( StandardWell < TypeTag > : : numEq , StandardWell < TypeTag > : : numStaticWellEq ) ;
2020-09-24 16:34:46 -03:00
2020-03-13 14:21:59 +01:00
for ( unsigned int i = 0 ; i < well_container_ . size ( ) ; i + + ) {
auto & well = well_container_ [ i ] ;
std : : shared_ptr < StandardWell < TypeTag > > derived = std : : dynamic_pointer_cast < StandardWell < TypeTag > > ( well ) ;
2020-05-15 16:00:09 +02:00
if ( derived ) {
unsigned int numBlocks ;
derived - > getNumBlocks ( numBlocks ) ;
wellContribs . addNumBlocks ( numBlocks ) ;
}
2020-03-13 14:21:59 +01:00
}
2020-05-15 16:00:09 +02:00
// allocate memory for data from StandardWells
2020-03-18 15:08:48 +01:00
wellContribs . alloc ( ) ;
2020-05-15 16:00:09 +02:00
2020-03-13 14:21:59 +01:00
for ( unsigned int i = 0 ; i < well_container_ . size ( ) ; i + + ) {
auto & well = well_container_ [ i ] ;
2020-05-15 16:00:09 +02:00
// maybe WellInterface could implement addWellContribution()
auto derived_std = std : : dynamic_pointer_cast < StandardWell < TypeTag > > ( well ) ;
if ( derived_std ) {
derived_std - > addWellContribution ( wellContribs ) ;
2020-03-19 16:06:49 +01:00
} else {
2020-05-15 16:00:09 +02:00
auto derived_ms = std : : dynamic_pointer_cast < MultisegmentWell < TypeTag > > ( well ) ;
if ( derived_ms ) {
derived_ms - > addWellContribution ( wellContribs ) ;
} else {
OpmLog : : warning ( " Warning unknown type of well " ) ;
}
2020-03-19 16:06:49 +01:00
}
2020-03-13 14:21:59 +01:00
}
}
2020-03-18 17:48:28 +01:00
# endif
2017-02-13 17:07:34 +01:00
2017-07-21 14:21:17 +02:00
// Ax = Ax - alpha * C D^-1 B x
2017-05-03 13:34:15 +02:00
template < typename TypeTag >
2017-02-13 17:07:34 +01:00
void
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2017-06-07 14:23:43 +02:00
applyScaleAdd ( const Scalar alpha , const BVector & x , BVector & Ax ) const
2017-02-13 17:07:34 +01:00
{
2018-02-26 15:47:25 +01:00
if ( ! localWellsActive ( ) ) {
2017-02-13 17:07:34 +01:00
return ;
}
if ( scaleAddRes_ . size ( ) ! = Ax . size ( ) ) {
scaleAddRes_ . resize ( Ax . size ( ) ) ;
}
scaleAddRes_ = 0.0 ;
2017-07-21 14:21:17 +02:00
// scaleAddRes_ = - C D^-1 B x
2017-02-13 17:07:34 +01:00
apply ( x , scaleAddRes_ ) ;
2017-07-21 14:21:17 +02:00
// Ax = Ax + alpha * scaleAddRes_
2017-02-13 17:07:34 +01:00
Ax . axpy ( alpha , scaleAddRes_ ) ;
}
2017-05-03 13:34:15 +02:00
template < typename TypeTag >
2017-02-13 17:07:34 +01:00
void
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2017-11-08 13:57:36 +01:00
recoverWellSolutionAndUpdateWellState ( const BVector & x )
2017-02-13 17:07:34 +01:00
{
2021-05-05 11:22:44 +02:00
DeferredLogger local_deferredLogger ;
2021-03-18 08:29:23 +01:00
auto exc_type = ExceptionType : : NONE ;
std : : string exc_msg ;
2019-02-07 14:43:17 +01:00
try {
if ( localWellsActive ( ) ) {
for ( auto & well : well_container_ ) {
2021-03-26 22:10:16 +01:00
well - > recoverWellSolutionAndUpdateWellState ( x , this - > wellState ( ) , local_deferredLogger ) ;
2019-02-07 14:43:17 +01:00
}
}
2021-03-18 08:29:23 +01:00
} catch ( const std : : runtime_error & e ) {
exc_type = ExceptionType : : RUNTIME_ERROR ;
exc_msg = e . what ( ) ;
} catch ( const std : : invalid_argument & e ) {
exc_type = ExceptionType : : INVALID_ARGUMENT ;
exc_msg = e . what ( ) ;
} catch ( const std : : logic_error & e ) {
exc_type = ExceptionType : : LOGIC_ERROR ;
exc_msg = e . what ( ) ;
} catch ( const std : : exception & e ) {
exc_type = ExceptionType : : DEFAULT ;
exc_msg = e . what ( ) ;
}
logAndCheckForExceptionsAndThrow ( local_deferredLogger , exc_type , " recoverWellSolutionAndUpdateWellState() failed: " + exc_msg , terminal_output_ ) ;
2017-02-13 17:07:34 +01:00
}
2017-05-03 13:34:15 +02:00
template < typename TypeTag >
2017-02-13 17:07:34 +01:00
bool
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2017-02-13 17:07:34 +01:00
wellsActive ( ) const
{
return wells_active_ ;
}
2017-05-03 13:34:15 +02:00
template < typename TypeTag >
2017-02-13 17:07:34 +01:00
void
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2017-02-13 17:07:34 +01:00
setWellsActive ( const bool wells_active )
{
wells_active_ = wells_active ;
}
2017-05-03 13:34:15 +02:00
template < typename TypeTag >
2017-02-13 17:07:34 +01:00
bool
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2017-02-13 17:07:34 +01:00
localWellsActive ( ) const
{
2019-11-01 15:11:21 +01:00
return numLocalWells ( ) > 0 ;
2017-02-13 17:07:34 +01:00
}
2017-05-03 13:34:15 +02:00
template < typename TypeTag >
2017-02-13 17:07:34 +01:00
void
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2017-08-21 15:41:25 +02:00
initPrimaryVariablesEvaluation ( ) const
2017-02-13 17:07:34 +01:00
{
2017-07-25 10:15:27 +02:00
for ( auto & well : well_container_ ) {
2017-08-21 15:41:25 +02:00
well - > initPrimaryVariablesEvaluation ( ) ;
2017-06-19 12:43:08 +02:00
}
2017-02-13 17:07:34 +01:00
}
2017-02-14 15:06:57 +01:00
2017-02-14 11:34:03 +01:00
2017-05-03 13:34:15 +02:00
template < typename TypeTag >
2018-11-13 14:02:55 +01:00
ConvergenceReport
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2020-04-01 09:55:29 +02:00
getWellConvergence ( const std : : vector < Scalar > & B_avg , bool checkGroupConvergence ) const
2017-02-14 11:34:03 +01:00
{
2019-02-07 14:43:17 +01:00
2021-05-05 11:22:44 +02:00
DeferredLogger local_deferredLogger ;
2018-11-13 14:02:55 +01:00
// Get global (from all processes) convergence report.
ConvergenceReport local_report ;
2017-06-28 11:15:04 +02:00
for ( const auto & well : well_container_ ) {
2018-11-17 23:14:51 +01:00
if ( well - > isOperable ( ) ) {
2021-03-26 22:10:16 +01:00
local_report + = well - > getWellConvergence ( this - > wellState ( ) , B_avg , local_deferredLogger ) ;
2018-11-17 23:14:51 +01:00
}
2017-08-22 14:49:30 +02:00
}
2021-05-05 11:22:44 +02:00
DeferredLogger global_deferredLogger = gatherDeferredLogger ( local_deferredLogger ) ;
2019-02-07 14:43:17 +01:00
if ( terminal_output_ ) {
global_deferredLogger . logMessages ( ) ;
}
2018-11-13 14:02:55 +01:00
ConvergenceReport report = gatherConvergenceReport ( local_report ) ;
2017-08-22 14:49:30 +02:00
2018-11-13 14:02:55 +01:00
// Log debug messages for NaN or too large residuals.
2019-02-03 08:13:11 +01:00
if ( terminal_output_ ) {
for ( const auto & f : report . wellFailures ( ) ) {
if ( f . severity ( ) = = ConvergenceReport : : Severity : : NotANumber ) {
OpmLog : : debug ( " NaN residual found with phase " + std : : to_string ( f . phase ( ) ) + " for well " + f . wellName ( ) ) ;
} else if ( f . severity ( ) = = ConvergenceReport : : Severity : : TooLarge ) {
OpmLog : : debug ( " Too large residual found with phase " + std : : to_string ( f . phase ( ) ) + " for well " + f . wellName ( ) ) ;
}
2017-03-24 12:12:06 +01:00
}
}
2020-04-08 10:41:20 +02:00
2020-04-01 09:55:29 +02:00
if ( checkGroupConvergence ) {
const int reportStepIdx = ebosSimulator_ . episodeIndex ( ) ;
const Group & fieldGroup = schedule ( ) . getGroup ( " FIELD " , reportStepIdx ) ;
bool violated = checkGroupConstraints ( fieldGroup , global_deferredLogger ) ;
report . setGroupConverged ( ! violated ) ;
}
2018-11-13 14:02:55 +01:00
return report ;
2017-02-14 11:34:03 +01:00
}
2017-05-03 13:34:15 +02:00
template < typename TypeTag >
2017-02-14 11:34:03 +01:00
void
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2021-05-05 11:22:44 +02:00
calculateExplicitQuantities ( DeferredLogger & deferred_logger ) const
2017-02-14 11:34:03 +01:00
{
2018-11-17 23:14:51 +01:00
// TODO: checking isOperable() ?
for ( auto & well : well_container_ ) {
2021-03-26 22:10:16 +01:00
well - > calculateExplicitQuantities ( ebosSimulator_ , this - > wellState ( ) , deferred_logger ) ;
2018-11-17 23:14:51 +01:00
}
2017-02-14 11:34:03 +01:00
}
2017-05-03 13:34:15 +02:00
template < typename TypeTag >
2017-02-14 11:34:03 +01:00
void
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2021-05-05 11:22:44 +02:00
updateWellControls ( DeferredLogger & deferred_logger , const bool checkGroupControls )
2017-02-14 11:34:03 +01:00
{
2019-01-21 08:26:28 +01:00
// Even if there are no wells active locally, we cannot
// return as the DeferredLogger uses global communication.
// For no well active globally we simply return.
2017-04-12 17:37:34 +02:00
if ( ! wellsActive ( ) ) return ;
2017-02-14 11:34:03 +01:00
2021-03-19 11:09:14 +01:00
updateAndCommunicateGroupData ( ) ;
2020-02-10 15:16:09 +01:00
2020-05-15 11:21:32 +02:00
updateNetworkPressures ( ) ;
2020-02-10 15:16:09 +01:00
std : : set < std : : string > switched_wells ;
std : : set < std : : string > switched_groups ;
if ( checkGroupControls ) {
// Check group individual constraints.
updateGroupIndividualControls ( deferred_logger , switched_groups ) ;
// Check group's constraints from higher levels.
updateGroupHigherControls ( deferred_logger , switched_groups ) ;
2021-03-19 11:09:14 +01:00
updateAndCommunicateGroupData ( ) ;
2019-11-22 12:29:47 +01:00
2020-02-10 15:16:09 +01:00
// Check wells' group constraints and communicate.
for ( const auto & well : well_container_ ) {
const auto mode = WellInterface < TypeTag > : : IndividualOrGroup : : Group ;
2021-04-22 17:31:21 +02:00
const bool changed = well - > updateWellControl ( ebosSimulator_ , mode , this - > wellState ( ) , this - > groupState ( ) , deferred_logger ) ;
2020-02-10 15:16:09 +01:00
if ( changed ) {
switched_wells . insert ( well - > name ( ) ) ;
}
}
2021-03-19 11:09:14 +01:00
updateAndCommunicateGroupData ( ) ;
2019-08-07 14:13:11 +02:00
}
2020-02-10 15:16:09 +01:00
// Check individual well constraints and communicate.
2017-06-28 11:15:04 +02:00
for ( const auto & well : well_container_ ) {
2020-02-10 15:16:09 +01:00
if ( switched_wells . count ( well - > name ( ) ) ) {
continue ;
}
const auto mode = WellInterface < TypeTag > : : IndividualOrGroup : : Individual ;
2021-04-22 17:31:21 +02:00
well - > updateWellControl ( ebosSimulator_ , mode , this - > wellState ( ) , this - > groupState ( ) , deferred_logger ) ;
2019-01-18 14:04:30 +01:00
}
2021-03-19 11:09:14 +01:00
updateAndCommunicateGroupData ( ) ;
2019-11-22 12:29:47 +01:00
2020-02-10 15:16:09 +01:00
}
2020-05-15 11:21:32 +02:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
updateNetworkPressures ( )
{
// Get the network and return if inactive.
const int reportStepIdx = ebosSimulator_ . episodeIndex ( ) ;
2021-01-13 00:58:03 +01:00
const auto & network = schedule ( ) [ reportStepIdx ] . network ( ) ;
2020-05-15 11:21:32 +02:00
if ( ! network . active ( ) ) {
return ;
}
2021-04-22 17:31:21 +02:00
node_pressures_ = WellGroupHelpers : : computeNetworkPressures ( network , this - > wellState ( ) , this - > groupState ( ) , * ( vfp_properties_ - > getProd ( ) ) , schedule ( ) , reportStepIdx ) ;
2020-05-15 11:21:32 +02:00
2020-10-21 09:50:31 +02:00
// Set the thp limits of wells
2020-05-15 11:21:32 +02:00
for ( auto & well : well_container_ ) {
2020-10-21 09:50:31 +02:00
// Producers only, since we so far only support the
// "extended" network model (properties defined by
// BRANPROP and NODEPROP) which only applies to producers.
2020-05-15 11:21:32 +02:00
if ( well - > isProducer ( ) ) {
const auto it = node_pressures_ . find ( well - > wellEcl ( ) . groupName ( ) ) ;
if ( it ! = node_pressures_ . end ( ) ) {
// The well belongs to a group with has a network pressure constraint,
// set the dynamic THP constraint of the well accordingly.
well - > setDynamicThpLimit ( it - > second ) ;
}
}
}
}
2020-02-10 15:16:09 +01:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2021-03-19 11:09:14 +01:00
updateAndCommunicateGroupData ( )
2020-02-10 15:16:09 +01:00
{
const int reportStepIdx = ebosSimulator_ . episodeIndex ( ) ;
const Group & fieldGroup = schedule ( ) . getGroup ( " FIELD " , reportStepIdx ) ;
2021-01-06 15:10:05 +01:00
const int nupcol = schedule ( ) [ reportStepIdx ] . nupcol ( ) ;
2019-12-17 08:49:47 +01:00
const int iterationIdx = ebosSimulator_ . model ( ) . newtonMethod ( ) . numIterations ( ) ;
2020-02-10 15:16:09 +01:00
// This builds some necessary lookup structures, so it must be called
// before we copy to well_state_nupcol_.
const auto & comm = ebosSimulator_ . vanguard ( ) . grid ( ) . comm ( ) ;
2021-04-28 10:22:29 +02:00
this - > wellState ( ) . updateGlobalIsGrup ( comm ) ;
2020-02-10 15:16:09 +01:00
2019-12-17 08:49:47 +01:00
if ( iterationIdx < nupcol ) {
2021-04-22 17:31:21 +02:00
this - > updateNupcolWGState ( ) ;
2019-12-17 08:49:47 +01:00
}
2021-03-26 22:10:16 +01:00
auto & well_state = this - > wellState ( ) ;
const auto & well_state_nupcol = this - > nupcolWellState ( ) ;
2021-03-10 14:26:04 +01:00
const auto & summaryState = ebosSimulator_ . vanguard ( ) . summaryState ( ) ;
2019-11-22 12:29:47 +01:00
// the group target reduction rates needs to be update since wells may have swicthed to/from GRUP control
2020-02-10 15:16:09 +01:00
// Currently the group target reduction does not honor NUPCOL. TODO: is that true?
2019-12-12 09:22:37 +01:00
std : : vector < double > groupTargetReduction ( numPhases ( ) , 0.0 ) ;
2021-04-22 17:31:21 +02:00
WellGroupHelpers : : updateGroupTargetReduction ( fieldGroup , schedule ( ) , reportStepIdx , /*isInjector*/ false , phase_usage_ , * guideRate_ , well_state_nupcol , well_state , this - > groupState ( ) , groupTargetReduction ) ;
2019-12-12 09:22:37 +01:00
std : : vector < double > groupTargetReductionInj ( numPhases ( ) , 0.0 ) ;
2021-04-22 17:31:21 +02:00
WellGroupHelpers : : updateGroupTargetReduction ( fieldGroup , schedule ( ) , reportStepIdx , /*isInjector*/ true , phase_usage_ , * guideRate_ , well_state_nupcol , well_state , this - > groupState ( ) , groupTargetReductionInj ) ;
2019-12-12 09:22:37 +01:00
2021-04-22 17:31:21 +02:00
WellGroupHelpers : : updateREINForGroups ( fieldGroup , schedule ( ) , reportStepIdx , phase_usage_ , summaryState , well_state_nupcol , well_state , this - > groupState ( ) ) ;
WellGroupHelpers : : updateVREPForGroups ( fieldGroup , schedule ( ) , reportStepIdx , well_state_nupcol , well_state , this - > groupState ( ) ) ;
2020-01-23 14:26:02 +01:00
2021-04-22 17:31:21 +02:00
WellGroupHelpers : : updateReservoirRatesInjectionGroups ( fieldGroup , schedule ( ) , reportStepIdx , well_state_nupcol , well_state , this - > groupState ( ) ) ;
WellGroupHelpers : : updateGroupProductionRates ( fieldGroup , schedule ( ) , reportStepIdx , well_state_nupcol , well_state , this - > groupState ( ) ) ;
2020-06-24 09:38:18 +02:00
// We use the rates from the privious time-step to reduce oscilations
2021-03-26 22:10:16 +01:00
WellGroupHelpers : : updateWellRates ( fieldGroup , schedule ( ) , reportStepIdx , this - > prevWellState ( ) , well_state ) ;
2020-11-16 10:36:44 +01:00
// Set ALQ for off-process wells to zero
for ( const auto & wname : schedule ( ) . wellNames ( reportStepIdx ) ) {
const bool is_producer = schedule ( ) . getWell ( wname , reportStepIdx ) . isProducer ( ) ;
2021-03-26 22:10:16 +01:00
const bool not_on_this_process = well_state . wellMap ( ) . count ( wname ) = = 0 ;
2020-11-16 10:36:44 +01:00
if ( is_producer & & not_on_this_process ) {
2021-03-26 22:10:16 +01:00
well_state . setALQ ( wname , 0.0 ) ;
2020-11-16 10:36:44 +01:00
}
}
2021-03-26 22:10:16 +01:00
well_state . communicateGroupRates ( comm ) ;
2021-04-22 17:31:21 +02:00
this - > groupState ( ) . communicate_rates ( comm ) ;
2019-12-17 08:49:47 +01:00
// compute wsolvent fraction for REIN wells
2021-03-26 22:10:16 +01:00
updateWsolvent ( fieldGroup , schedule ( ) , reportStepIdx , well_state_nupcol ) ;
2019-12-17 08:49:47 +01:00
2017-02-14 11:34:03 +01:00
}
2017-02-14 13:39:53 +01:00
2017-05-03 13:34:15 +02:00
template < typename TypeTag >
2017-02-14 13:39:53 +01:00
void
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2018-06-28 13:47:10 +02:00
updateWellTestState ( const double & simulationTime , WellTestState & wellTestState ) const
2017-02-14 13:39:53 +01:00
{
2021-05-05 11:22:44 +02:00
DeferredLogger local_deferredLogger ;
2017-07-26 11:01:26 +02:00
for ( const auto & well : well_container_ ) {
2021-03-01 15:43:43 +01:00
const auto wasClosed = wellTestState . hasWellClosed ( well - > name ( ) ) ;
2021-03-26 22:10:16 +01:00
well - > updateWellTestState ( this - > wellState ( ) , simulationTime , /*writeMessageToOPMLog=*/ true , wellTestState , local_deferredLogger ) ;
2021-03-01 15:43:43 +01:00
if ( ! wasClosed & & wellTestState . hasWellClosed ( well - > name ( ) ) ) {
this - > closed_this_step_ . insert ( well - > name ( ) ) ;
}
2019-02-03 08:13:11 +01:00
}
2021-03-01 15:43:43 +01:00
2021-05-05 11:22:44 +02:00
DeferredLogger global_deferredLogger = gatherDeferredLogger ( local_deferredLogger ) ;
2019-02-03 08:13:11 +01:00
if ( terminal_output_ ) {
global_deferredLogger . logMessages ( ) ;
2017-07-26 11:01:26 +02:00
}
2017-02-14 13:39:53 +01:00
}
2017-05-03 13:34:15 +02:00
template < typename TypeTag >
2017-02-14 13:39:53 +01:00
void
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2021-05-05 11:22:44 +02:00
computeWellPotentials ( std : : vector < double > & well_potentials , const int reportStepIdx , DeferredLogger & deferred_logger )
2017-02-14 13:39:53 +01:00
{
// number of wells and phases
2019-11-01 15:11:21 +01:00
const int nw = numLocalWells ( ) ;
2017-11-08 13:57:36 +01:00
const int np = numPhases ( ) ;
2017-03-23 11:36:49 +01:00
well_potentials . resize ( nw * np , 0.0 ) ;
2021-03-26 22:10:16 +01:00
auto well_state = this - > wellState ( ) ;
2019-04-23 13:30:12 +02:00
2021-05-05 11:22:44 +02:00
const SummaryConfig & summaryConfig = ebosSimulator_ . vanguard ( ) . summaryConfig ( ) ;
2021-03-07 09:31:10 +01:00
const bool write_restart_file = ebosSimulator_ . vanguard ( ) . schedule ( ) . write_rst_file ( reportStepIdx ) ;
2021-03-18 08:29:23 +01:00
auto exc_type = ExceptionType : : NONE ;
std : : string exc_msg ;
2020-12-11 08:26:52 +01:00
for ( const auto & well : well_container_ ) {
const bool needed_for_summary = ( ( summaryConfig . hasSummaryKey ( " WWPI: " + well - > name ( ) ) | |
summaryConfig . hasSummaryKey ( " WOPI: " + well - > name ( ) ) | |
summaryConfig . hasSummaryKey ( " WGPI: " + well - > name ( ) ) ) & & well - > isInjector ( ) ) | |
( ( summaryConfig . hasSummaryKey ( " WWPP: " + well - > name ( ) ) | |
summaryConfig . hasSummaryKey ( " WOPP: " + well - > name ( ) ) | |
summaryConfig . hasSummaryKey ( " WGPP: " + well - > name ( ) ) ) & & well - > isProducer ( ) ) ;
bool needPotentialsForGuideRate = true ; //eclWell.getGuideRatePhase() == Well::GuideRateTarget::UNDEFINED;
if ( write_restart_file | | needed_for_summary | | needPotentialsForGuideRate )
{
try {
2019-02-07 14:43:17 +01:00
std : : vector < double > potentials ;
2021-03-26 22:10:16 +01:00
well - > computeWellPotentials ( ebosSimulator_ , well_state , potentials , deferred_logger ) ;
2019-02-07 14:43:17 +01:00
// putting the sucessfully calculated potentials to the well_potentials
for ( int p = 0 ; p < np ; + + p ) {
well_potentials [ well - > indexOfWell ( ) * np + p ] = std : : abs ( potentials [ p ] ) ;
}
2021-03-18 08:29:23 +01:00
} catch ( const std : : runtime_error & e ) {
exc_type = ExceptionType : : RUNTIME_ERROR ;
exc_msg = e . what ( ) ;
} catch ( const std : : invalid_argument & e ) {
exc_type = ExceptionType : : INVALID_ARGUMENT ;
exc_msg = e . what ( ) ;
} catch ( const std : : logic_error & e ) {
exc_type = ExceptionType : : LOGIC_ERROR ;
exc_msg = e . what ( ) ;
} catch ( const std : : exception & e ) {
exc_type = ExceptionType : : DEFAULT ;
exc_msg = e . what ( ) ;
2018-11-07 14:53:43 +01:00
}
2020-12-11 08:26:52 +01:00
}
2019-02-07 14:43:17 +01:00
}
2021-03-18 08:29:23 +01:00
logAndCheckForExceptionsAndThrow ( deferred_logger , exc_type ,
" computeWellPotentials() failed: " + exc_msg ,
2021-03-01 15:17:52 +01:00
terminal_output_ ) ;
2018-11-07 14:53:43 +01:00
// Store it in the well state
2021-03-26 22:10:16 +01:00
this - > wellState ( ) . wellPotentials ( ) = well_potentials ;
2017-02-14 15:06:57 +01:00
}
2020-10-09 13:38:33 +02:00
2021-03-02 01:11:19 +01:00
template < typename TypeTag >
2020-10-09 13:38:33 +02:00
void
BlackoilWellModel < TypeTag > : :
calculateProductivityIndexValues ( DeferredLogger & deferred_logger )
{
2021-03-02 01:11:19 +01:00
for ( const auto & wellPtr : this - > well_container_ ) {
this - > calculateProductivityIndexValues ( wellPtr . get ( ) , deferred_logger ) ;
2020-10-09 13:38:33 +02:00
}
2021-03-02 01:11:19 +01:00
}
2020-10-09 13:38:33 +02:00
2021-03-02 01:11:19 +01:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
calculateProductivityIndexValuesShutWells ( const int reportStepIdx ,
DeferredLogger & deferred_logger )
{
// For the purpose of computing PI/II values, it is sufficient to
// construct StandardWell instances only. We don't need to form
// well objects that honour the 'isMultisegment()' flag of the
// corresponding "this->wells_ecl_[shutWell]".
for ( const auto & shutWell : this - > local_shut_wells_ ) {
auto wellPtr = this - > template createTypedWellPointer
< StandardWell < TypeTag > > ( shutWell , reportStepIdx ) ;
wellPtr - > init ( & this - > phase_usage_ , this - > depth_ , this - > gravity_ ,
this - > local_num_cells_ , this - > B_avg_ ) ;
this - > calculateProductivityIndexValues ( wellPtr . get ( ) , deferred_logger ) ;
2020-10-09 13:38:33 +02:00
}
}
2021-03-02 01:11:19 +01:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
calculateProductivityIndexValues ( const WellInterface < TypeTag > * wellPtr ,
DeferredLogger & deferred_logger )
{
wellPtr - > updateProductivityIndex ( this - > ebosSimulator_ ,
this - > prod_index_calc_ [ wellPtr - > indexOfWell ( ) ] ,
this - > wellState ( ) ,
deferred_logger ) ;
}
2017-05-03 13:34:15 +02:00
template < typename TypeTag >
2017-03-16 16:39:05 +01:00
void
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2021-05-05 11:22:44 +02:00
prepareTimeStep ( DeferredLogger & deferred_logger )
2017-03-16 16:39:05 +01:00
{
2021-03-18 08:29:23 +01:00
auto exc_type = ExceptionType : : NONE ;
std : : string exc_msg ;
2019-02-07 14:43:17 +01:00
try {
for ( const auto & well : well_container_ ) {
2021-03-26 22:10:16 +01:00
well - > checkWellOperability ( ebosSimulator_ , this - > wellState ( ) , deferred_logger ) ;
2021-04-23 08:40:14 +02:00
2019-02-07 14:43:17 +01:00
if ( ! well - > isOperable ( ) ) continue ;
2018-06-06 15:17:59 +02:00
2021-05-11 08:10:49 +02:00
auto & events = this - > wellState ( ) . events ( well - > indexOfWell ( ) ) ;
2021-05-07 11:21:58 +02:00
if ( events . hasEvent ( WellStateFullyImplicitBlackoil : : event_mask ) ) {
2021-03-26 22:10:16 +01:00
well - > updateWellStateWithTarget ( ebosSimulator_ , this - > wellState ( ) , deferred_logger ) ;
2021-05-05 14:07:52 +02:00
// There is no new well control change input within a report step,
// so next time step, the well does not consider to have effective events anymore.
2021-05-07 11:21:58 +02:00
events . clearEvent ( WellStateFullyImplicitBlackoil : : event_mask ) ;
2019-02-07 14:43:17 +01:00
}
2021-04-23 08:40:14 +02:00
// solve the well equation initially to improve the initial solution of the well model
if ( param_ . solve_welleq_initially_ ) {
well - > solveWellEquation ( ebosSimulator_ , this - > wellState ( ) , this - > groupState ( ) , deferred_logger ) ;
}
} // end of for (const auto& well : well_container_)
2019-02-07 14:43:17 +01:00
updatePrimaryVariables ( deferred_logger ) ;
2021-03-18 08:29:23 +01:00
} catch ( const std : : runtime_error & e ) {
exc_type = ExceptionType : : RUNTIME_ERROR ;
exc_msg = e . what ( ) ;
} catch ( const std : : invalid_argument & e ) {
exc_type = ExceptionType : : INVALID_ARGUMENT ;
exc_msg = e . what ( ) ;
} catch ( const std : : logic_error & e ) {
exc_type = ExceptionType : : LOGIC_ERROR ;
exc_msg = e . what ( ) ;
} catch ( const std : : exception & e ) {
exc_type = ExceptionType : : DEFAULT ;
exc_msg = e . what ( ) ;
}
logAndCheckForExceptionsAndThrow ( deferred_logger , exc_type , " prepareTimestep() failed: " + exc_msg , terminal_output_ ) ;
2017-09-04 13:54:41 +02:00
}
2017-05-03 13:34:15 +02:00
template < typename TypeTag >
2017-02-14 15:06:57 +01:00
void
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2019-08-07 14:13:11 +02:00
calculateEfficiencyFactors ( const int reportStepIdx )
2017-02-14 15:06:57 +01:00
{
if ( ! localWellsActive ( ) ) {
return ;
}
2018-06-06 15:17:59 +02:00
for ( auto & well : well_container_ ) {
2019-11-13 23:16:11 +01:00
const Well & wellEcl = well - > wellEcl ( ) ;
2019-08-07 14:13:11 +02:00
double well_efficiency_factor = wellEcl . getEfficiencyFactor ( ) ;
2020-03-27 13:27:45 +01:00
WellGroupHelpers : : accumulateGroupEfficiencyFactor ( schedule ( ) . getGroup ( wellEcl . groupName ( ) , reportStepIdx ) , schedule ( ) , reportStepIdx , well_efficiency_factor ) ;
2018-06-06 15:17:59 +02:00
well - > setWellEfficiencyFactor ( well_efficiency_factor ) ;
2017-02-14 15:06:57 +01:00
}
}
2017-06-07 09:29:31 +02:00
template < typename TypeTag >
void
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2018-08-16 11:51:36 +02:00
setupCartesianToCompressed_ ( const int * global_cell , int number_of_cartesian_cells )
2017-06-07 09:29:31 +02:00
{
2018-08-16 11:51:36 +02:00
cartesian_to_compressed_ . resize ( number_of_cartesian_cells , - 1 ) ;
2017-06-07 09:29:31 +02:00
if ( global_cell ) {
2020-11-10 11:54:19 +01:00
auto elemIt = ebosSimulator_ . gridView ( ) . template begin < /*codim=*/ 0 > ( ) ;
2020-10-05 20:02:13 +02:00
for ( unsigned i = 0 ; i < local_num_cells_ ; + + i ) {
2020-11-10 11:54:19 +01:00
// Skip perforations in the overlap/ghost for distributed wells.
if ( elemIt - > partitionType ( ) = = Dune : : InteriorEntity )
{
assert ( ebosSimulator_ . gridView ( ) . indexSet ( ) . index ( * elemIt ) = = static_cast < int > ( i ) ) ;
cartesian_to_compressed_ [ global_cell [ i ] ] = i ;
}
+ + elemIt ;
2017-06-07 09:29:31 +02:00
}
}
else {
2020-10-05 20:02:13 +02:00
for ( unsigned i = 0 ; i < local_num_cells_ ; + + i ) {
2018-08-16 11:51:36 +02:00
cartesian_to_compressed_ [ i ] = i ;
2017-06-07 09:29:31 +02:00
}
}
}
template < typename TypeTag >
void
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2021-01-28 12:52:19 +01:00
setRepRadiusPerfLength ( )
2017-06-07 09:29:31 +02:00
{
2017-07-31 16:42:26 +02:00
for ( const auto & well : well_container_ ) {
2021-01-28 12:52:19 +01:00
well - > setRepRadiusPerfLength ( cartesian_to_compressed_ ) ;
2017-06-07 09:29:31 +02:00
}
}
2017-05-09 08:21:51 +02:00
2017-06-23 12:24:50 +02:00
template < typename TypeTag >
void
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2021-03-18 14:49:52 +01:00
updateAverageFormationFactor ( )
2017-06-23 12:24:50 +02:00
{
2021-03-18 14:49:52 +01:00
std : : vector < Scalar > B_avg ( numComponents ( ) , Scalar ( ) ) ;
2018-02-01 16:27:42 +01:00
const auto & grid = ebosSimulator_ . vanguard ( ) . grid ( ) ;
2017-06-23 12:24:50 +02:00
const auto & gridView = grid . leafGridView ( ) ;
2017-11-08 13:57:36 +01:00
ElementContext elemCtx ( ebosSimulator_ ) ;
2017-06-23 12:24:50 +02:00
const auto & elemEndIt = gridView . template end < /*codim=*/ 0 , Dune : : Interior_Partition > ( ) ;
for ( auto elemIt = gridView . template begin < /*codim=*/ 0 , Dune : : Interior_Partition > ( ) ;
elemIt ! = elemEndIt ; + + elemIt )
{
elemCtx . updatePrimaryStencil ( * elemIt ) ;
elemCtx . updatePrimaryIntensiveQuantities ( /*timeIdx=*/ 0 ) ;
const auto & intQuants = elemCtx . intensiveQuantities ( /*spaceIdx=*/ 0 , /*timeIdx=*/ 0 ) ;
const auto & fs = intQuants . fluidState ( ) ;
2017-12-04 09:14:08 +01:00
for ( unsigned phaseIdx = 0 ; phaseIdx < FluidSystem : : numPhases ; + + phaseIdx )
2017-06-23 12:24:50 +02:00
{
2017-12-04 09:14:08 +01:00
if ( ! FluidSystem : : phaseIsActive ( phaseIdx ) ) {
continue ;
}
const unsigned compIdx = Indices : : canonicalToActiveComponentIndex ( FluidSystem : : solventComponentIndex ( phaseIdx ) ) ;
auto & B = B_avg [ compIdx ] ;
2017-06-23 12:24:50 +02:00
2017-12-04 09:14:08 +01:00
B + = 1 / fs . invB ( phaseIdx ) . value ( ) ;
2017-06-23 12:24:50 +02:00
}
2021-01-28 14:33:21 +01:00
if constexpr ( has_solvent_ ) {
2017-06-27 15:16:22 +02:00
auto & B = B_avg [ solventSaturationIdx ] ;
2017-06-23 12:24:50 +02:00
B + = 1 / intQuants . solventInverseFormationVolumeFactor ( ) . value ( ) ;
}
}
// compute global average
grid . comm ( ) . sum ( B_avg . data ( ) , B_avg . size ( ) ) ;
for ( auto & bval : B_avg )
{
2020-10-05 20:02:13 +02:00
bval / = global_num_cells_ ;
2017-06-23 12:24:50 +02:00
}
2021-03-18 14:49:52 +01:00
B_avg_ = B_avg ;
2017-06-23 12:24:50 +02:00
}
2017-08-08 10:44:10 +02:00
template < typename TypeTag >
void
2017-09-26 10:52:05 +02:00
BlackoilWellModel < TypeTag > : :
2021-05-05 11:22:44 +02:00
updatePrimaryVariables ( DeferredLogger & deferred_logger )
2017-08-08 10:44:10 +02:00
{
for ( const auto & well : well_container_ ) {
2021-03-26 22:10:16 +01:00
well - > updatePrimaryVariables ( this - > wellState ( ) , deferred_logger ) ;
2017-11-08 13:57:36 +01:00
}
}
2017-11-08 15:48:30 +01:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : : extractLegacyCellPvtRegionIndex_ ( )
{
2018-02-01 16:27:42 +01:00
const auto & grid = ebosSimulator_ . vanguard ( ) . grid ( ) ;
2017-11-08 15:48:30 +01:00
const auto & eclProblem = ebosSimulator_ . problem ( ) ;
const unsigned numCells = grid . size ( /*codim=*/ 0 ) ;
pvt_region_idx_ . resize ( numCells ) ;
for ( unsigned cellIdx = 0 ; cellIdx < numCells ; + + cellIdx ) {
pvt_region_idx_ [ cellIdx ] =
eclProblem . pvtRegionIndex ( cellIdx ) ;
}
}
// The number of components in the model.
template < typename TypeTag >
int
BlackoilWellModel < TypeTag > : : numComponents ( ) const
{
2019-11-01 14:58:10 +01:00
if ( wellsActive ( ) & & numPhases ( ) < 3 ) {
2019-10-09 15:24:23 +02:00
return numPhases ( ) ;
2017-11-08 15:48:30 +01:00
}
int numComp = FluidSystem : : numComponents ;
2021-01-28 14:33:21 +01:00
if constexpr ( has_solvent_ ) {
2017-11-08 15:48:30 +01:00
numComp + + ;
}
return numComp ;
}
template < typename TypeTag >
int
2019-11-01 15:11:21 +01:00
BlackoilWellModel < TypeTag > : : numLocalWells ( ) const
2017-11-08 15:48:30 +01:00
{
2019-10-23 09:09:45 +02:00
return wells_ecl_ . size ( ) ;
2017-11-08 15:48:30 +01:00
}
template < typename TypeTag >
int
2019-10-23 09:09:45 +02:00
BlackoilWellModel < TypeTag > : : numPhases ( ) const
2017-11-08 15:48:30 +01:00
{
2019-10-23 09:09:45 +02:00
return phase_usage_ . num_phases ;
2017-11-08 15:48:30 +01:00
}
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : : extractLegacyDepth_ ( )
{
2018-02-01 16:27:42 +01:00
const auto & grid = ebosSimulator_ . vanguard ( ) . grid ( ) ;
2017-11-08 15:48:30 +01:00
const unsigned numCells = grid . size ( /*codim=*/ 0 ) ;
depth_ . resize ( numCells ) ;
for ( unsigned cellIdx = 0 ; cellIdx < numCells ; + + cellIdx ) {
2021-05-05 11:22:44 +02:00
depth_ [ cellIdx ] = UgGridHelpers : : cellCenterDepth ( grid , cellIdx ) ;
2017-11-08 15:48:30 +01:00
}
}
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
updatePerforationIntensiveQuantities ( ) {
ElementContext elemCtx ( ebosSimulator_ ) ;
const auto & gridView = ebosSimulator_ . gridView ( ) ;
const auto & elemEndIt = gridView . template end < /*codim=*/ 0 , Dune : : Interior_Partition > ( ) ;
for ( auto elemIt = gridView . template begin < /*codim=*/ 0 , Dune : : Interior_Partition > ( ) ;
elemIt ! = elemEndIt ;
+ + elemIt )
{
2018-11-16 16:02:47 +01:00
2017-11-08 15:48:30 +01:00
elemCtx . updatePrimaryStencil ( * elemIt ) ;
2018-11-16 16:02:47 +01:00
int elemIdx = elemCtx . globalSpaceIndex ( 0 , 0 ) ;
if ( ! is_cell_perforated_ [ elemIdx ] ) {
continue ;
}
2017-11-08 15:48:30 +01:00
elemCtx . updatePrimaryIntensiveQuantities ( /*timeIdx=*/ 0 ) ;
}
}
2017-11-08 13:57:36 +01:00
2021-02-12 11:26:14 +01:00
template < typename TypeTag >
bool
BlackoilWellModel < TypeTag > : :
hasWell ( const std : : string & wname ) {
auto iter = std : : find_if ( this - > wells_ecl_ . begin ( ) , this - > wells_ecl_ . end ( ) , [ & wname ] ( const Well & well ) { return well . name ( ) = = wname ; } ) ;
return ( iter ! = this - > wells_ecl_ . end ( ) ) ;
}
2018-11-26 12:09:04 +01:00
// convert well data from opm-common to well state from opm-core
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2021-04-13 21:32:09 +02:00
loadRestartData ( const data : : Wells & rst_wells ,
2021-04-13 16:58:59 +02:00
const data : : GroupAndNetworkValues & grpNwrkValues ,
const PhaseUsage & phases ,
const bool handle_ms_well ,
2021-04-22 17:31:21 +02:00
WellStateFullyImplicitBlackoil & well_state )
2019-03-22 09:41:29 +01:00
{
2020-08-28 08:41:48 +02:00
using GPMode = Group : : ProductionCMode ;
using GIMode = Group : : InjectionCMode ;
2018-11-26 12:09:04 +01:00
using rt = data : : Rates : : opt ;
const auto np = phases . num_phases ;
std : : vector < rt > phs ( np ) ;
if ( phases . phase_used [ BlackoilPhases : : Aqua ] ) {
phs . at ( phases . phase_pos [ BlackoilPhases : : Aqua ] ) = rt : : wat ;
}
if ( phases . phase_used [ BlackoilPhases : : Liquid ] ) {
phs . at ( phases . phase_pos [ BlackoilPhases : : Liquid ] ) = rt : : oil ;
}
if ( phases . phase_used [ BlackoilPhases : : Vapour ] ) {
phs . at ( phases . phase_pos [ BlackoilPhases : : Vapour ] ) = rt : : gas ;
}
2021-04-22 17:31:21 +02:00
for ( const auto & wm : well_state . wellMap ( ) ) {
2018-11-26 12:09:04 +01:00
const auto well_index = wm . second [ 0 ] ;
2021-04-13 21:32:09 +02:00
const auto & rst_well = rst_wells . at ( wm . first ) ;
2021-05-14 08:00:52 +02:00
well_state . update_bhp ( well_index , rst_well . bhp ) ;
2021-05-14 08:23:46 +02:00
well_state . update_temperature ( well_index , rst_well . temperature ) ;
2019-08-07 14:13:11 +02:00
2021-04-13 21:32:09 +02:00
if ( rst_well . current_control . isProducer ) {
2021-04-22 17:31:21 +02:00
well_state . currentProductionControls ( ) [ well_index ] = rst_well . current_control . prod ;
2020-02-07 19:08:14 +01:00
}
else {
2021-04-22 17:31:21 +02:00
well_state . currentInjectionControls ( ) [ well_index ] = rst_well . current_control . inj ;
2020-02-07 19:08:14 +01:00
}
2019-08-07 14:13:11 +02:00
2018-11-26 12:09:04 +01:00
const auto wellrate_index = well_index * np ;
for ( size_t i = 0 ; i < phs . size ( ) ; + + i ) {
2021-04-13 21:32:09 +02:00
assert ( rst_well . rates . has ( phs [ i ] ) ) ;
2021-04-22 17:31:21 +02:00
well_state . wellRates ( ) [ wellrate_index + i ] = rst_well . rates . get ( phs [ i ] ) ;
2018-11-26 12:09:04 +01:00
}
2021-04-22 17:31:21 +02:00
auto * perf_pressure = well_state . perfPress ( ) . data ( ) + wm . second [ 1 ] ;
auto * perf_rates = well_state . perfRates ( ) . data ( ) + wm . second [ 1 ] ;
2021-05-07 11:14:57 +02:00
auto * perf_phase_rates = well_state . mutable_perfPhaseRates ( ) . data ( ) + wm . second [ 1 ] * np ;
2021-04-13 21:32:09 +02:00
const auto & perf_data = this - > well_perf_data_ [ well_index ] ;
for ( std : : size_t perf_index = 0 ; perf_index < perf_data . size ( ) ; perf_index + + ) {
const auto & pd = perf_data [ perf_index ] ;
const auto & rst_connection = rst_well . connections [ pd . ecl_index ] ;
perf_pressure [ perf_index ] = rst_connection . pressure ;
perf_rates [ perf_index ] = rst_connection . reservoir_rate ;
for ( int phase_index = 0 ; phase_index < np ; + + phase_index )
perf_phase_rates [ perf_index * np + phase_index ] = rst_connection . rates . get ( phs [ phase_index ] ) ;
2019-09-30 15:22:31 +02:00
}
2019-03-22 09:41:29 +01:00
2021-04-13 21:32:09 +02:00
if ( handle_ms_well & & ! rst_well . segments . empty ( ) ) {
2019-03-22 09:41:29 +01:00
// we need the well_ecl_ information
const std : : string & well_name = wm . first ;
2019-11-13 23:16:11 +01:00
const Well & well_ecl = getWellEcl ( well_name ) ;
2019-03-22 09:41:29 +01:00
2019-05-02 12:51:25 +02:00
const WellSegments & segment_set = well_ecl . getSegments ( ) ;
2019-03-22 09:41:29 +01:00
2021-04-22 17:31:21 +02:00
const int top_segment_index = well_state . topSegmentIndex ( well_index ) ;
2021-04-13 21:32:09 +02:00
const auto & segments = rst_well . segments ;
2019-03-22 09:41:29 +01:00
// \Note: eventually we need to hanlde the situations that some segments are shut
2019-04-30 10:01:38 +02:00
assert ( 0u + segment_set . size ( ) = = segments . size ( ) ) ;
2019-03-22 09:41:29 +01:00
for ( const auto & segment : segments ) {
const int segment_index = segment_set . segmentNumberToIndex ( segment . first ) ;
// recovering segment rates and pressure from the restart values
2021-05-05 11:22:44 +02:00
const auto pres_idx = data : : SegmentPressures : : Value : : Pressure ;
2021-04-22 17:31:21 +02:00
well_state . segPress ( ) [ top_segment_index + segment_index ] = segment . second . pressures [ pres_idx ] ;
2019-03-22 09:41:29 +01:00
const auto & segment_rates = segment . second . rates ;
for ( int p = 0 ; p < np ; + + p ) {
2021-04-22 17:31:21 +02:00
well_state . segRates ( ) [ ( top_segment_index + segment_index ) * np + p ] = segment_rates . get ( phs [ p ] ) ;
2019-03-22 09:41:29 +01:00
}
}
}
}
2020-08-28 08:41:48 +02:00
2020-09-20 22:16:07 +02:00
for ( const auto & [ group , value ] : grpNwrkValues . groupData ) {
2020-08-28 08:41:48 +02:00
const auto cpc = value . currentControl . currentProdConstraint ;
const auto cgi = value . currentControl . currentGasInjectionConstraint ;
const auto cwi = value . currentControl . currentWaterInjectionConstraint ;
if ( cpc ! = GPMode : : NONE ) {
2021-04-22 17:31:21 +02:00
this - > groupState ( ) . production_control ( group , cpc ) ;
2020-08-28 08:41:48 +02:00
}
if ( cgi ! = GIMode : : NONE ) {
2021-04-22 17:31:21 +02:00
this - > groupState ( ) . injection_control ( group , Phase : : GAS , cgi ) ;
2020-08-28 08:41:48 +02:00
}
if ( cwi ! = GIMode : : NONE ) {
2021-04-22 17:31:21 +02:00
this - > groupState ( ) . injection_control ( group , Phase : : WATER , cwi ) ;
2020-08-28 08:41:48 +02:00
}
}
2019-03-22 09:41:29 +01:00
}
template < typename TypeTag >
bool
BlackoilWellModel < TypeTag > : :
2019-10-23 09:09:45 +02:00
anyMSWellOpenLocal ( ) const
2019-03-22 09:41:29 +01:00
{
2019-10-23 09:09:45 +02:00
for ( const auto & well : wells_ecl_ ) {
if ( well . isMultiSegment ( ) ) {
return true ;
2019-03-22 09:41:29 +01:00
}
}
2019-10-23 09:09:45 +02:00
return false ;
2019-03-22 09:41:29 +01:00
}
template < typename TypeTag >
2019-11-13 23:16:11 +01:00
const Well &
2019-03-22 09:41:29 +01:00
BlackoilWellModel < TypeTag > : :
getWellEcl ( const std : : string & well_name ) const
{
2019-04-04 15:36:35 +02:00
// finding the iterator of the well in wells_ecl
auto well_ecl = std : : find_if ( wells_ecl_ . begin ( ) ,
wells_ecl_ . end ( ) ,
2019-11-13 23:16:11 +01:00
[ & well_name ] ( const Well & elem ) - > bool {
2019-05-02 12:51:25 +02:00
return elem . name ( ) = = well_name ;
2019-04-04 15:36:35 +02:00
} ) ;
2019-03-22 09:41:29 +01:00
2019-04-04 15:36:35 +02:00
assert ( well_ecl ! = wells_ecl_ . end ( ) ) ;
return * well_ecl ;
2018-11-26 12:09:04 +01:00
}
2019-09-23 15:15:55 +02:00
template < typename TypeTag >
typename BlackoilWellModel < TypeTag > : : WellInterfacePtr
BlackoilWellModel < TypeTag > : :
getWell ( const std : : string & well_name ) const
{
// finding the iterator of the well in wells_ecl
auto well = std : : find_if ( well_container_ . begin ( ) ,
well_container_ . end ( ) ,
[ & well_name ] ( const WellInterfacePtr & elem ) - > bool {
return elem - > name ( ) = = well_name ;
} ) ;
assert ( well ! = well_container_ . end ( ) ) ;
return * well ;
}
2020-02-10 15:16:09 +01:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2021-05-05 11:22:44 +02:00
updateGroupIndividualControls ( DeferredLogger & deferred_logger , std : : set < std : : string > & switched_groups )
2020-02-10 15:16:09 +01:00
{
const int reportStepIdx = ebosSimulator_ . episodeIndex ( ) ;
2020-04-27 10:28:24 +02:00
2021-01-06 15:10:05 +01:00
const int nupcol = schedule ( ) [ reportStepIdx ] . nupcol ( ) ;
2020-04-27 10:28:24 +02:00
const int iterationIdx = ebosSimulator_ . model ( ) . newtonMethod ( ) . numIterations ( ) ;
// don't switch group control when iterationIdx > nupcol
// to avoid oscilations between group controls
if ( iterationIdx > nupcol )
return ;
2020-02-10 15:16:09 +01:00
const Group & fieldGroup = schedule ( ) . getGroup ( " FIELD " , reportStepIdx ) ;
2020-03-24 09:24:45 +01:00
updateGroupIndividualControl ( fieldGroup , deferred_logger , switched_groups ) ;
2020-02-10 15:16:09 +01:00
}
2019-08-07 14:13:11 +02:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2021-05-05 11:22:44 +02:00
updateGroupIndividualControl ( const Group & group , DeferredLogger & deferred_logger , std : : set < std : : string > & switched_groups ) {
2019-08-07 14:13:11 +02:00
const int reportStepIdx = ebosSimulator_ . episodeIndex ( ) ;
2020-02-10 15:16:09 +01:00
const bool skip = switched_groups . count ( group . name ( ) ) ;
if ( ! skip & & group . isInjectionGroup ( ) )
2019-08-07 14:13:11 +02:00
{
2020-01-23 11:20:06 +01:00
const Phase all [ ] = { Phase : : WATER , Phase : : OIL , Phase : : GAS } ;
for ( Phase phase : all ) {
if ( ! group . hasInjectionControl ( phase ) ) {
2020-02-11 09:03:40 +01:00
continue ;
2020-01-23 09:05:37 +01:00
}
2020-04-08 10:41:20 +02:00
Group : : InjectionCMode newControl = checkGroupInjectionConstraints ( group , phase ) ;
2020-03-24 09:24:45 +01:00
if ( newControl ! = Group : : InjectionCMode : : NONE )
2020-01-16 09:52:03 +01:00
{
2020-03-24 09:24:45 +01:00
switched_groups . insert ( group . name ( ) ) ;
2020-04-08 10:41:20 +02:00
actionOnBrokenConstraints ( group , newControl , phase , deferred_logger ) ;
2020-02-11 09:03:40 +01:00
}
2020-03-24 09:24:45 +01:00
}
2020-04-08 10:41:20 +02:00
}
if ( ! skip & & group . isProductionGroup ( ) ) {
2020-03-24 09:24:45 +01:00
Group : : ProductionCMode newControl = checkGroupProductionConstraints ( group , deferred_logger ) ;
const auto & summaryState = ebosSimulator_ . vanguard ( ) . summaryState ( ) ;
const auto controls = group . productionControls ( summaryState ) ;
if ( newControl ! = Group : : ProductionCMode : : NONE )
{
switched_groups . insert ( group . name ( ) ) ;
2020-04-08 10:41:20 +02:00
actionOnBrokenConstraints ( group , controls . exceed_action , newControl , deferred_logger ) ;
2020-03-24 09:24:45 +01:00
}
}
2019-12-12 09:22:37 +01:00
2020-03-24 09:24:45 +01:00
// call recursively down the group hiearchy
for ( const std : : string & groupName : group . groups ( ) ) {
updateGroupIndividualControl ( schedule ( ) . getGroup ( groupName , reportStepIdx ) , deferred_logger , switched_groups ) ;
}
}
2019-08-07 14:13:11 +02:00
2020-03-24 09:24:45 +01:00
template < typename TypeTag >
bool
BlackoilWellModel < TypeTag > : :
2021-05-05 11:22:44 +02:00
checkGroupConstraints ( const Group & group , DeferredLogger & deferred_logger ) const {
2019-12-12 09:22:37 +01:00
2020-03-24 09:24:45 +01:00
const int reportStepIdx = ebosSimulator_ . episodeIndex ( ) ;
2020-04-08 10:41:20 +02:00
if ( group . isInjectionGroup ( ) ) {
2020-03-24 09:24:45 +01:00
const Phase all [ ] = { Phase : : WATER , Phase : : OIL , Phase : : GAS } ;
for ( Phase phase : all ) {
if ( ! group . hasInjectionControl ( phase ) ) {
continue ;
2020-02-11 09:03:40 +01:00
}
2020-04-08 10:41:20 +02:00
Group : : InjectionCMode newControl = checkGroupInjectionConstraints ( group , phase ) ;
if ( newControl ! = Group : : InjectionCMode : : NONE ) {
2020-03-24 09:24:45 +01:00
return true ;
2019-08-07 14:13:11 +02:00
}
2020-03-24 09:24:45 +01:00
}
2020-04-08 10:41:20 +02:00
}
if ( group . isProductionGroup ( ) ) {
2020-03-24 09:24:45 +01:00
Group : : ProductionCMode newControl = checkGroupProductionConstraints ( group , deferred_logger ) ;
if ( newControl ! = Group : : ProductionCMode : : NONE )
{
return true ;
}
}
2019-11-26 11:15:09 +01:00
2020-03-24 09:24:45 +01:00
// call recursively down the group hiearchy
bool violated = false ;
for ( const std : : string & groupName : group . groups ( ) ) {
violated = violated | | checkGroupConstraints ( schedule ( ) . getGroup ( groupName , reportStepIdx ) , deferred_logger ) ;
}
return violated ;
}
2020-04-08 10:41:20 +02:00
2020-03-24 09:24:45 +01:00
template < typename TypeTag >
Group : : ProductionCMode
BlackoilWellModel < TypeTag > : :
2021-05-05 11:22:44 +02:00
checkGroupProductionConstraints ( const Group & group , DeferredLogger & deferred_logger ) const {
2019-11-26 11:15:09 +01:00
2020-03-24 09:24:45 +01:00
const int reportStepIdx = ebosSimulator_ . episodeIndex ( ) ;
const auto & summaryState = ebosSimulator_ . vanguard ( ) . summaryState ( ) ;
const auto & comm = ebosSimulator_ . vanguard ( ) . grid ( ) . comm ( ) ;
2021-03-26 22:10:16 +01:00
const auto & well_state = this - > wellState ( ) ;
2019-11-26 11:15:09 +01:00
2020-03-24 09:24:45 +01:00
const auto controls = group . productionControls ( summaryState ) ;
2021-04-22 17:31:21 +02:00
const Group : : ProductionCMode & currentControl = this - > groupState ( ) . production_control ( group . name ( ) ) ;
2019-11-26 11:15:09 +01:00
2020-03-24 09:24:45 +01:00
if ( group . has_control ( Group : : ProductionCMode : : ORAT ) )
{
if ( currentControl ! = Group : : ProductionCMode : : ORAT )
{
double current_rate = 0.0 ;
2020-03-27 13:27:45 +01:00
current_rate + = WellGroupHelpers : : sumWellRates ( group , schedule ( ) , well_state , reportStepIdx , phase_usage_ . phase_pos [ BlackoilPhases : : Liquid ] , false ) ;
2020-02-11 09:03:40 +01:00
2020-03-24 09:24:45 +01:00
// sum over all nodes
current_rate = comm . sum ( current_rate ) ;
2019-11-26 11:15:09 +01:00
2020-03-24 09:24:45 +01:00
if ( controls . oil_target < current_rate ) {
return Group : : ProductionCMode : : ORAT ;
}
2020-02-11 09:03:40 +01:00
}
2019-11-26 13:36:45 +01:00
}
2020-03-24 09:24:45 +01:00
if ( group . has_control ( Group : : ProductionCMode : : WRAT ) )
{
if ( currentControl ! = Group : : ProductionCMode : : WRAT )
2019-08-07 14:13:11 +02:00
{
2019-12-12 09:22:37 +01:00
2020-03-24 09:24:45 +01:00
double current_rate = 0.0 ;
2020-03-27 13:27:45 +01:00
current_rate + = WellGroupHelpers : : sumWellRates ( group , schedule ( ) , well_state , reportStepIdx , phase_usage_ . phase_pos [ BlackoilPhases : : Aqua ] , false ) ;
2019-12-12 09:22:37 +01:00
2020-03-24 09:24:45 +01:00
// sum over all nodes
current_rate = comm . sum ( current_rate ) ;
if ( controls . water_target < current_rate ) {
return Group : : ProductionCMode : : WRAT ;
2020-01-16 09:52:03 +01:00
}
2019-08-07 14:13:11 +02:00
}
2020-03-24 09:24:45 +01:00
}
if ( group . has_control ( Group : : ProductionCMode : : GRAT ) )
{
if ( currentControl ! = Group : : ProductionCMode : : GRAT )
2019-08-07 14:13:11 +02:00
{
2020-03-24 09:24:45 +01:00
double current_rate = 0.0 ;
2020-03-27 13:27:45 +01:00
current_rate + = WellGroupHelpers : : sumWellRates ( group , schedule ( ) , well_state , reportStepIdx , phase_usage_ . phase_pos [ BlackoilPhases : : Vapour ] , false ) ;
2020-02-11 09:03:40 +01:00
2020-03-24 09:24:45 +01:00
// sum over all nodes
current_rate = comm . sum ( current_rate ) ;
if ( controls . gas_target < current_rate ) {
return Group : : ProductionCMode : : GRAT ;
}
}
}
if ( group . has_control ( Group : : ProductionCMode : : LRAT ) )
{
if ( currentControl ! = Group : : ProductionCMode : : LRAT )
{
double current_rate = 0.0 ;
2020-03-27 13:27:45 +01:00
current_rate + = WellGroupHelpers : : sumWellRates ( group , schedule ( ) , well_state , reportStepIdx , phase_usage_ . phase_pos [ BlackoilPhases : : Liquid ] , false ) ;
current_rate + = WellGroupHelpers : : sumWellRates ( group , schedule ( ) , well_state , reportStepIdx , phase_usage_ . phase_pos [ BlackoilPhases : : Aqua ] , false ) ;
2019-08-07 14:13:11 +02:00
2020-03-24 09:24:45 +01:00
// sum over all nodes
current_rate = comm . sum ( current_rate ) ;
2019-12-12 09:22:37 +01:00
2020-03-24 09:24:45 +01:00
if ( controls . liquid_target < current_rate ) {
return Group : : ProductionCMode : : LRAT ;
2019-08-07 14:13:11 +02:00
}
}
2020-03-24 09:24:45 +01:00
}
if ( group . has_control ( Group : : ProductionCMode : : CRAT ) )
{
OPM_DEFLOG_THROW ( std : : runtime_error , " Group " + group . name ( ) + " CRAT control for production groups not implemented " , deferred_logger ) ;
}
if ( group . has_control ( Group : : ProductionCMode : : RESV ) )
{
if ( currentControl ! = Group : : ProductionCMode : : RESV )
2019-08-07 14:13:11 +02:00
{
2020-03-24 09:24:45 +01:00
double current_rate = 0.0 ;
2020-03-27 13:27:45 +01:00
current_rate + = WellGroupHelpers : : sumWellResRates ( group , schedule ( ) , well_state , reportStepIdx , phase_usage_ . phase_pos [ BlackoilPhases : : Aqua ] , true ) ;
current_rate + = WellGroupHelpers : : sumWellResRates ( group , schedule ( ) , well_state , reportStepIdx , phase_usage_ . phase_pos [ BlackoilPhases : : Liquid ] , true ) ;
current_rate + = WellGroupHelpers : : sumWellResRates ( group , schedule ( ) , well_state , reportStepIdx , phase_usage_ . phase_pos [ BlackoilPhases : : Vapour ] , true ) ;
2019-12-12 09:22:37 +01:00
2020-03-24 09:24:45 +01:00
// sum over all nodes
current_rate = comm . sum ( current_rate ) ;
if ( controls . resv_target < current_rate ) {
return Group : : ProductionCMode : : RESV ;
2019-08-07 14:13:11 +02:00
}
}
2020-03-24 09:24:45 +01:00
}
if ( group . has_control ( Group : : ProductionCMode : : PRBL ) )
{
OPM_DEFLOG_THROW ( std : : runtime_error , " Group " + group . name ( ) + " PRBL control for production groups not implemented " , deferred_logger ) ;
2020-04-08 10:41:20 +02:00
}
2020-03-24 09:24:45 +01:00
return Group : : ProductionCMode : : NONE ;
}
2020-04-08 10:41:20 +02:00
2020-03-24 09:24:45 +01:00
template < typename TypeTag >
Group : : InjectionCMode
BlackoilWellModel < TypeTag > : :
2020-04-08 10:41:20 +02:00
checkGroupInjectionConstraints ( const Group & group , const Phase & phase ) const {
2020-03-24 09:24:45 +01:00
const int reportStepIdx = ebosSimulator_ . episodeIndex ( ) ;
const auto & summaryState = ebosSimulator_ . vanguard ( ) . summaryState ( ) ;
const auto & comm = ebosSimulator_ . vanguard ( ) . grid ( ) . comm ( ) ;
2021-03-26 22:10:16 +01:00
const auto & well_state = this - > wellState ( ) ;
2020-03-24 09:24:45 +01:00
int phasePos ;
if ( phase = = Phase : : GAS & & phase_usage_ . phase_used [ BlackoilPhases : : Vapour ] )
phasePos = phase_usage_ . phase_pos [ BlackoilPhases : : Vapour ] ;
else if ( phase = = Phase : : OIL & & phase_usage_ . phase_used [ BlackoilPhases : : Liquid ] )
phasePos = phase_usage_ . phase_pos [ BlackoilPhases : : Liquid ] ;
else if ( phase = = Phase : : WATER & & phase_usage_ . phase_used [ BlackoilPhases : : Aqua ] )
phasePos = phase_usage_ . phase_pos [ BlackoilPhases : : Aqua ] ;
else
OPM_THROW ( std : : runtime_error , " Unknown phase " ) ;
const auto & controls = group . injectionControls ( phase , summaryState ) ;
2021-04-22 17:31:21 +02:00
auto currentControl = this - > groupState ( ) . injection_control ( group . name ( ) , phase ) ;
2020-03-24 09:24:45 +01:00
if ( controls . has_control ( Group : : InjectionCMode : : RATE ) )
{
if ( currentControl ! = Group : : InjectionCMode : : RATE )
2019-08-07 14:13:11 +02:00
{
2020-03-24 09:24:45 +01:00
double current_rate = 0.0 ;
2020-03-27 13:27:45 +01:00
current_rate + = WellGroupHelpers : : sumWellRates ( group , schedule ( ) , well_state , reportStepIdx , phasePos , /*isInjector*/ true ) ;
2019-12-12 09:22:37 +01:00
2020-03-24 09:24:45 +01:00
// sum over all nodes
current_rate = comm . sum ( current_rate ) ;
2019-12-12 09:22:37 +01:00
2020-03-24 09:24:45 +01:00
if ( controls . surface_max_rate < current_rate ) {
return Group : : InjectionCMode : : RATE ;
2019-08-07 14:13:11 +02:00
}
}
2020-03-24 09:24:45 +01:00
}
if ( controls . has_control ( Group : : InjectionCMode : : RESV ) )
{
if ( currentControl ! = Group : : InjectionCMode : : RESV )
2019-08-07 14:13:11 +02:00
{
2020-03-24 09:24:45 +01:00
double current_rate = 0.0 ;
2020-03-27 13:27:45 +01:00
current_rate + = WellGroupHelpers : : sumWellResRates ( group , schedule ( ) , well_state , reportStepIdx , phasePos , /*isInjector*/ true ) ;
2020-03-24 09:24:45 +01:00
// sum over all nodes
current_rate = comm . sum ( current_rate ) ;
2019-08-07 14:13:11 +02:00
2020-03-24 09:24:45 +01:00
if ( controls . resv_max_rate < current_rate ) {
return Group : : InjectionCMode : : RESV ;
}
2019-08-07 14:13:11 +02:00
}
2020-03-24 09:24:45 +01:00
}
if ( controls . has_control ( Group : : InjectionCMode : : REIN ) )
{
if ( currentControl ! = Group : : InjectionCMode : : REIN )
2019-08-07 14:13:11 +02:00
{
2020-03-24 09:24:45 +01:00
double production_Rate = 0.0 ;
const Group & groupRein = schedule ( ) . getGroup ( controls . reinj_group , reportStepIdx ) ;
2020-03-27 13:27:45 +01:00
production_Rate + = WellGroupHelpers : : sumWellRates ( groupRein , schedule ( ) , well_state , reportStepIdx , phasePos , /*isInjector*/ false ) ;
2019-08-07 14:13:11 +02:00
2020-03-24 09:24:45 +01:00
// sum over all nodes
production_Rate = comm . sum ( production_Rate ) ;
2019-12-12 09:22:37 +01:00
2020-03-24 09:24:45 +01:00
double current_rate = 0.0 ;
2020-03-27 13:27:45 +01:00
current_rate + = WellGroupHelpers : : sumWellRates ( group , schedule ( ) , well_state , reportStepIdx , phasePos , /*isInjector*/ true ) ;
2020-03-24 09:24:45 +01:00
// sum over all nodes
current_rate = comm . sum ( current_rate ) ;
2019-08-07 14:13:11 +02:00
2020-03-24 09:24:45 +01:00
if ( controls . target_reinj_fraction * production_Rate < current_rate ) {
return Group : : InjectionCMode : : REIN ;
}
2019-08-07 14:13:11 +02:00
}
2020-03-24 09:24:45 +01:00
}
if ( controls . has_control ( Group : : InjectionCMode : : VREP ) )
{
if ( currentControl ! = Group : : InjectionCMode : : VREP )
2019-08-07 14:13:11 +02:00
{
2020-03-24 09:24:45 +01:00
double voidage_rate = 0.0 ;
const Group & groupVoidage = schedule ( ) . getGroup ( controls . voidage_group , reportStepIdx ) ;
2020-03-27 13:27:45 +01:00
voidage_rate + = WellGroupHelpers : : sumWellResRates ( groupVoidage , schedule ( ) , well_state , reportStepIdx , phase_usage_ . phase_pos [ BlackoilPhases : : Aqua ] , false ) ;
voidage_rate + = WellGroupHelpers : : sumWellResRates ( groupVoidage , schedule ( ) , well_state , reportStepIdx , phase_usage_ . phase_pos [ BlackoilPhases : : Liquid ] , false ) ;
voidage_rate + = WellGroupHelpers : : sumWellResRates ( groupVoidage , schedule ( ) , well_state , reportStepIdx , phase_usage_ . phase_pos [ BlackoilPhases : : Vapour ] , false ) ;
2020-01-16 09:52:03 +01:00
2020-03-24 09:24:45 +01:00
// sum over all nodes
voidage_rate = comm . sum ( voidage_rate ) ;
2019-08-07 14:13:11 +02:00
2020-03-24 09:24:45 +01:00
double total_rate = 0.0 ;
2020-03-27 13:27:45 +01:00
total_rate + = WellGroupHelpers : : sumWellResRates ( group , schedule ( ) , well_state , reportStepIdx , phase_usage_ . phase_pos [ BlackoilPhases : : Aqua ] , true ) ;
total_rate + = WellGroupHelpers : : sumWellResRates ( group , schedule ( ) , well_state , reportStepIdx , phase_usage_ . phase_pos [ BlackoilPhases : : Liquid ] , true ) ;
total_rate + = WellGroupHelpers : : sumWellResRates ( group , schedule ( ) , well_state , reportStepIdx , phase_usage_ . phase_pos [ BlackoilPhases : : Vapour ] , true ) ;
2019-08-07 14:13:11 +02:00
2020-03-24 09:24:45 +01:00
// sum over all nodes
total_rate = comm . sum ( total_rate ) ;
if ( controls . target_void_fraction * voidage_rate < total_rate ) {
return Group : : InjectionCMode : : VREP ;
}
}
2019-12-16 13:53:03 +01:00
}
2020-04-24 15:25:38 +02:00
return Group : : InjectionCMode : : NONE ;
}
2019-08-07 14:13:11 +02:00
2020-04-24 15:25:38 +02:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2021-05-05 11:22:44 +02:00
checkGconsaleLimits ( const Group & group , WellState & well_state , DeferredLogger & deferred_logger )
2020-04-24 15:25:38 +02:00
{
const int reportStepIdx = ebosSimulator_ . episodeIndex ( ) ;
// call recursively down the group hiearchy
for ( const std : : string & groupName : group . groups ( ) ) {
2020-05-04 15:56:34 +02:00
checkGconsaleLimits ( schedule ( ) . getGroup ( groupName , reportStepIdx ) , well_state , deferred_logger ) ;
2020-04-24 15:25:38 +02:00
}
2019-08-07 14:13:11 +02:00
2020-04-24 15:25:38 +02:00
// only for groups with gas injection controls
if ( ! group . hasInjectionControl ( Phase : : GAS ) ) {
return ;
}
2020-03-24 09:24:45 +01:00
2020-04-24 15:25:38 +02:00
// check if gconsale is used for this group
2021-01-12 18:29:59 +01:00
if ( ! schedule ( ) [ reportStepIdx ] . gconsale ( ) . has ( group . name ( ) ) )
2020-04-24 15:25:38 +02:00
return ;
2020-03-24 09:24:45 +01:00
2020-05-04 15:56:34 +02:00
std : : ostringstream ss ;
2020-04-24 15:25:38 +02:00
const auto & summaryState = ebosSimulator_ . vanguard ( ) . summaryState ( ) ;
const auto & comm = ebosSimulator_ . vanguard ( ) . grid ( ) . comm ( ) ;
2020-03-24 09:24:45 +01:00
2021-01-12 18:29:59 +01:00
const auto & gconsale = schedule ( ) [ reportStepIdx ] . gconsale ( ) . get ( group . name ( ) , summaryState ) ;
2021-04-22 17:31:21 +02:00
const Group : : ProductionCMode & oldProductionControl = this - > groupState ( ) . production_control ( group . name ( ) ) ;
2020-05-04 15:56:34 +02:00
2020-04-24 15:25:38 +02:00
int gasPos = phase_usage_ . phase_pos [ BlackoilPhases : : Vapour ] ;
2020-05-04 15:56:34 +02:00
double production_rate = WellGroupHelpers : : sumWellRates ( group , schedule ( ) , well_state , reportStepIdx , gasPos , /*isInjector*/ false ) ;
double injection_rate = WellGroupHelpers : : sumWellRates ( group , schedule ( ) , well_state , reportStepIdx , gasPos , /*isInjector*/ true ) ;
2020-04-08 10:41:20 +02:00
2020-04-24 15:25:38 +02:00
// sum over all nodes
2020-05-04 15:56:34 +02:00
injection_rate = comm . sum ( injection_rate ) ;
production_rate = comm . sum ( production_rate ) ;
double sales_rate = production_rate - injection_rate ;
double production_target = gconsale . sales_target + injection_rate ;
2020-04-24 15:25:38 +02:00
// add import rate and substract consumption rate for group for gas
2021-01-12 18:29:59 +01:00
if ( schedule ( ) [ reportStepIdx ] . gconsump ( ) . has ( group . name ( ) ) ) {
const auto & gconsump = schedule ( ) [ reportStepIdx ] . gconsump ( ) . get ( group . name ( ) , summaryState ) ;
2020-04-24 15:25:38 +02:00
if ( phase_usage_ . phase_used [ BlackoilPhases : : Vapour ] ) {
sales_rate + = gconsump . import_rate ;
sales_rate - = gconsump . consumption_rate ;
2020-05-04 15:56:34 +02:00
production_target - = gconsump . import_rate ;
production_target + = gconsump . consumption_rate ;
2020-04-24 15:25:38 +02:00
}
2020-03-24 09:24:45 +01:00
}
2020-04-24 15:25:38 +02:00
if ( sales_rate > gconsale . max_sales_rate ) {
2020-05-04 15:56:34 +02:00
switch ( gconsale . max_proc ) {
case GConSale : : MaxProcedure : : NONE : {
if ( oldProductionControl ! = Group : : ProductionCMode : : GRAT & & oldProductionControl ! = Group : : ProductionCMode : : NONE ) {
ss < < " Group sales exceed maximum limit, but the action is NONE for " + group . name ( ) + " . Nothing happens " ;
}
break ;
}
case GConSale : : MaxProcedure : : CON : {
OPM_DEFLOG_THROW ( std : : runtime_error , " Group " + group . name ( ) + " GCONSALE exceed limit CON not implemented " , deferred_logger ) ;
break ;
}
case GConSale : : MaxProcedure : : CON_P : {
OPM_DEFLOG_THROW ( std : : runtime_error , " Group " + group . name ( ) + " GCONSALE exceed limit CON_P not implemented " , deferred_logger ) ;
break ;
}
case GConSale : : MaxProcedure : : WELL : {
OPM_DEFLOG_THROW ( std : : runtime_error , " Group " + group . name ( ) + " GCONSALE exceed limit WELL not implemented " , deferred_logger ) ;
break ;
}
case GConSale : : MaxProcedure : : PLUG : {
OPM_DEFLOG_THROW ( std : : runtime_error , " Group " + group . name ( ) + " GCONSALE exceed limit PLUG not implemented " , deferred_logger ) ;
break ;
}
case GConSale : : MaxProcedure : : MAXR : {
OPM_DEFLOG_THROW ( std : : runtime_error , " Group " + group . name ( ) + " GCONSALE exceed limit MAXR not implemented " , deferred_logger ) ;
break ;
}
case GConSale : : MaxProcedure : : END : {
OPM_DEFLOG_THROW ( std : : runtime_error , " Group " + group . name ( ) + " GCONSALE exceed limit END not implemented " , deferred_logger ) ;
break ;
}
case GConSale : : MaxProcedure : : RATE : {
2021-04-22 17:31:21 +02:00
this - > groupState ( ) . production_control ( group . name ( ) , Group : : ProductionCMode : : GRAT ) ;
ss < < " Maximum GCONSALE limit violated for " < < group . name ( ) < < " . The group is switched from " ;
ss < < Group : : ProductionCMode2String ( oldProductionControl ) < < " to " < < Group : : ProductionCMode2String ( Group : : ProductionCMode : : GRAT ) ;
ss < < " and limited by the maximum sales rate after consumption and import are considered " ;
this - > groupState ( ) . update_grat_sales_target ( group . name ( ) , production_target ) ;
2020-05-04 15:56:34 +02:00
break ;
}
default :
throw ( " Invalid procedure for maximum rate limit selected for group " + group . name ( ) ) ;
}
2020-04-24 15:25:38 +02:00
}
if ( sales_rate < gconsale . min_sales_rate ) {
2021-04-22 17:31:21 +02:00
const Group : : ProductionCMode & currentProductionControl = this - > groupState ( ) . production_control ( group . name ( ) ) ;
2020-05-04 15:56:34 +02:00
if ( currentProductionControl = = Group : : ProductionCMode : : GRAT ) {
ss < < " Group " + group . name ( ) + " has sale rate less then minimum permitted value and is under GRAT control. \n " ;
ss < < " The GRAT is increased to meet the sales minimum rate. \n " ;
2021-04-22 17:31:21 +02:00
this - > groupState ( ) . update_grat_sales_target ( group . name ( ) , production_target ) ;
2020-05-04 15:56:34 +02:00
//} else if () {//TODO add action for WGASPROD
//} else if () {//TODO add action for drilling queue
} else {
ss < < " Group " + group . name ( ) + " has sale rate less then minimum permitted value but cannot increase the group production rate \n " ;
ss < < " or adjust gas production using WGASPROD or drill new wells to meet the sales target. \n " ;
ss < < " Note that WGASPROD and drilling queues are not implemented in Flow. No action is taken. \n " ;
}
2020-04-24 15:25:38 +02:00
}
if ( gconsale . sales_target < 0.0 ) {
2020-05-04 15:56:34 +02:00
OPM_DEFLOG_THROW ( std : : runtime_error , " Group " + group . name ( ) + " has sale rate target less then zero. Not implemented in Flow " , deferred_logger ) ;
}
auto cc = Dune : : MPIHelper : : getCollectiveCommunication ( ) ;
2021-02-26 14:16:38 +01:00
if ( ! ss . str ( ) . empty ( ) & & cc . rank ( ) = = 0 )
2020-05-04 15:56:34 +02:00
deferred_logger . info ( ss . str ( ) ) ;
2020-04-24 15:25:38 +02:00
2019-08-07 14:13:11 +02:00
}
2020-04-24 15:25:38 +02:00
2019-08-07 14:13:11 +02:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2021-05-05 11:22:44 +02:00
actionOnBrokenConstraints ( const Group & group , const Group : : ExceedAction & exceed_action , const Group : : ProductionCMode & newControl , DeferredLogger & deferred_logger ) {
2019-08-07 14:13:11 +02:00
2021-04-22 17:31:21 +02:00
const Group : : ProductionCMode oldControl = this - > groupState ( ) . production_control ( group . name ( ) ) ;
2019-08-07 14:13:11 +02:00
std : : ostringstream ss ;
2019-10-16 15:27:40 +02:00
2019-08-07 14:13:11 +02:00
switch ( exceed_action ) {
2019-11-13 23:16:11 +01:00
case Group : : ExceedAction : : NONE : {
2019-11-25 10:11:36 +01:00
if ( oldControl ! = newControl & & oldControl ! = Group : : ProductionCMode : : NONE ) {
2020-05-14 17:22:52 +02:00
ss < < " Group production exceed action is NONE for group " + group . name ( ) + " . Nothing happens. " ;
2019-11-25 10:11:36 +01:00
}
2019-08-07 14:13:11 +02:00
break ;
}
2019-11-13 23:16:11 +01:00
case Group : : ExceedAction : : CON : {
2019-08-07 14:13:11 +02:00
OPM_DEFLOG_THROW ( std : : runtime_error , " Group " + group . name ( ) + " GroupProductionExceedLimit CON not implemented " , deferred_logger ) ;
break ;
}
2019-11-13 23:16:11 +01:00
case Group : : ExceedAction : : CON_PLUS : {
2019-08-07 14:13:11 +02:00
OPM_DEFLOG_THROW ( std : : runtime_error , " Group " + group . name ( ) + " GroupProductionExceedLimit CON_PLUS not implemented " , deferred_logger ) ;
break ;
}
2019-11-13 23:16:11 +01:00
case Group : : ExceedAction : : WELL : {
2019-08-07 14:13:11 +02:00
OPM_DEFLOG_THROW ( std : : runtime_error , " Group " + group . name ( ) + " GroupProductionExceedLimit WELL not implemented " , deferred_logger ) ;
break ;
}
2019-11-13 23:16:11 +01:00
case Group : : ExceedAction : : PLUG : {
2019-08-07 14:13:11 +02:00
OPM_DEFLOG_THROW ( std : : runtime_error , " Group " + group . name ( ) + " GroupProductionExceedLimit PLUG not implemented " , deferred_logger ) ;
break ;
}
2019-11-13 23:16:11 +01:00
case Group : : ExceedAction : : RATE : {
2019-10-16 15:27:40 +02:00
if ( oldControl ! = newControl ) {
2021-04-22 17:31:21 +02:00
this - > groupState ( ) . production_control ( group . name ( ) , newControl ) ;
2020-05-14 17:22:52 +02:00
ss < < " Switching production control mode for group " < < group . name ( )
< < " from " < < Group : : ProductionCMode2String ( oldControl )
< < " to " < < Group : : ProductionCMode2String ( newControl ) ;
2019-10-16 15:27:40 +02:00
}
2019-08-07 14:13:11 +02:00
break ;
}
default :
throw ( " Invalid procedure for maximum rate limit selected for group " + group . name ( ) ) ;
}
auto cc = Dune : : MPIHelper : : getCollectiveCommunication ( ) ;
2021-02-26 14:16:38 +01:00
if ( ! ss . str ( ) . empty ( ) & & cc . rank ( ) = = 0 )
2019-10-16 15:27:40 +02:00
deferred_logger . info ( ss . str ( ) ) ;
2019-08-07 14:13:11 +02:00
}
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2021-05-05 11:22:44 +02:00
actionOnBrokenConstraints ( const Group & group , const Group : : InjectionCMode & newControl , const Phase & controlPhase , DeferredLogger & deferred_logger ) {
2021-04-22 17:31:21 +02:00
auto oldControl = this - > groupState ( ) . injection_control ( group . name ( ) , controlPhase ) ;
2019-10-16 15:27:40 +02:00
2019-08-07 14:13:11 +02:00
std : : ostringstream ss ;
2019-10-16 15:27:40 +02:00
if ( oldControl ! = newControl ) {
2019-11-13 23:16:11 +01:00
const std : : string from = Group : : InjectionCMode2String ( oldControl ) ;
2020-05-14 17:22:52 +02:00
ss < < " Switching injection control mode for group " < < group . name ( )
< < " from " < < Group : : InjectionCMode2String ( oldControl )
< < " to " < < Group : : InjectionCMode2String ( newControl ) ;
2021-04-22 17:31:21 +02:00
this - > groupState ( ) . injection_control ( group . name ( ) , controlPhase , newControl ) ;
2019-08-07 14:13:11 +02:00
}
2021-02-26 14:16:38 +01:00
auto cc = Dune : : MPIHelper : : getCollectiveCommunication ( ) ;
if ( ! ss . str ( ) . empty ( ) & & cc . rank ( ) = = 0 )
2019-10-16 15:27:40 +02:00
deferred_logger . info ( ss . str ( ) ) ;
2019-08-07 14:13:11 +02:00
}
2020-02-10 15:16:09 +01:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2021-05-05 11:22:44 +02:00
updateGroupHigherControls ( DeferredLogger & deferred_logger , std : : set < std : : string > & switched_groups )
2020-02-10 15:16:09 +01:00
{
const int reportStepIdx = ebosSimulator_ . episodeIndex ( ) ;
const Group & fieldGroup = schedule ( ) . getGroup ( " FIELD " , reportStepIdx ) ;
checkGroupHigherConstraints ( fieldGroup , deferred_logger , switched_groups ) ;
}
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2021-05-05 11:22:44 +02:00
checkGroupHigherConstraints ( const Group & group , DeferredLogger & deferred_logger , std : : set < std : : string > & switched_groups )
2020-02-10 15:16:09 +01:00
{
2020-03-27 13:27:45 +01:00
// Set up coefficients for RESV <-> surface rate conversion.
2020-02-10 15:16:09 +01:00
// Use the pvtRegionIdx from the top cell of the first well.
// TODO fix this!
// This is only used for converting RESV rates.
// What is the proper approach?
2020-11-17 11:47:51 +01:00
const auto & comm = ebosSimulator_ . vanguard ( ) . grid ( ) . comm ( ) ;
2020-03-27 13:27:45 +01:00
const int fipnum = 0 ;
2020-11-17 17:07:58 +01:00
int pvtreg = well_perf_data_ . empty ( ) | | well_perf_data_ [ 0 ] . empty ( )
2020-02-10 15:16:09 +01:00
? pvt_region_idx_ [ 0 ]
: pvt_region_idx_ [ well_perf_data_ [ 0 ] [ 0 ] . cell_index ] ;
2020-11-17 11:47:51 +01:00
if ( comm . size ( ) > 1 )
{
// Just like in the sequential case the pvtregion is determined
// by the first cell of the first well. What is the first well
// is decided by the order in the Schedule using Well::seqIndex()
int firstWellIndex = well_perf_data_ . empty ( ) ?
std : : numeric_limits < int > : : max ( ) : wells_ecl_ [ 0 ] . seqIndex ( ) ;
auto regIndexPair = std : : make_pair ( pvtreg , firstWellIndex ) ;
std : : vector < decltype ( regIndexPair ) > pairs ( comm . size ( ) ) ;
comm . allgather ( & regIndexPair , 1 , pairs . data ( ) ) ;
pvtreg = std : : min_element ( pairs . begin ( ) , pairs . end ( ) ,
[ ] ( const auto & p1 , const auto & p2 ) { return p1 . second < p2 . second ; } )
- > first ;
}
2020-03-27 13:27:45 +01:00
std : : vector < double > resv_coeff ( phase_usage_ . num_phases , 0.0 ) ;
rateConverter_ - > calcCoeff ( fipnum , pvtreg , resv_coeff ) ;
2020-02-10 15:16:09 +01:00
const int reportStepIdx = ebosSimulator_ . episodeIndex ( ) ;
const auto & summaryState = ebosSimulator_ . vanguard ( ) . summaryState ( ) ;
std : : vector < double > rates ( phase_usage_ . num_phases , 0.0 ) ;
2020-03-24 19:51:11 +01:00
const bool skip = switched_groups . count ( group . name ( ) ) | | group . name ( ) = = " FIELD " ;
2020-02-10 15:16:09 +01:00
if ( ! skip & & group . isInjectionGroup ( ) ) {
// Obtain rates for group.
for ( int phasePos = 0 ; phasePos < phase_usage_ . num_phases ; + + phasePos ) {
2021-03-26 22:10:16 +01:00
const double local_current_rate = WellGroupHelpers : : sumWellRates ( group , schedule ( ) , this - > wellState ( ) , reportStepIdx , phasePos , /* isInjector */ true ) ;
2020-02-10 15:16:09 +01:00
// Sum over all processes
rates [ phasePos ] = comm . sum ( local_current_rate ) ;
}
const Phase all [ ] = { Phase : : WATER , Phase : : OIL , Phase : : GAS } ;
for ( Phase phase : all ) {
// Check higher up only if under individual (not FLD) control.
2021-04-22 17:31:21 +02:00
auto currentControl = this - > groupState ( ) . injection_control ( group . name ( ) , phase ) ;
2021-04-19 14:34:38 +02:00
if ( currentControl ! = Group : : InjectionCMode : : FLD & & group . injectionGroupControlAvailable ( phase ) ) {
2020-02-10 15:16:09 +01:00
const Group & parentGroup = schedule ( ) . getGroup ( group . parent ( ) , reportStepIdx ) ;
2020-03-27 13:27:45 +01:00
const std : : pair < bool , double > changed = WellGroupHelpers : : checkGroupConstraintsInj (
2020-02-10 15:16:09 +01:00
group . name ( ) ,
group . parent ( ) ,
parentGroup ,
2021-03-26 22:10:16 +01:00
this - > wellState ( ) ,
2021-04-22 17:31:21 +02:00
this - > groupState ( ) ,
2020-02-10 15:16:09 +01:00
reportStepIdx ,
guideRate_ . get ( ) ,
rates . data ( ) ,
phase ,
phase_usage_ ,
group . getGroupEfficiencyFactor ( ) ,
schedule ( ) ,
summaryState ,
2020-03-27 13:27:45 +01:00
resv_coeff ,
2020-02-10 15:16:09 +01:00
deferred_logger ) ;
2020-03-24 09:24:45 +01:00
if ( changed . first ) {
2020-02-10 15:16:09 +01:00
switched_groups . insert ( group . name ( ) ) ;
2020-04-08 10:41:20 +02:00
actionOnBrokenConstraints ( group , Group : : InjectionCMode : : FLD , phase , deferred_logger ) ;
2020-02-10 15:16:09 +01:00
}
}
}
}
if ( ! skip & & group . isProductionGroup ( ) ) {
// Obtain rates for group.
for ( int phasePos = 0 ; phasePos < phase_usage_ . num_phases ; + + phasePos ) {
2021-03-26 22:10:16 +01:00
const double local_current_rate = WellGroupHelpers : : sumWellRates ( group , schedule ( ) , this - > wellState ( ) , reportStepIdx , phasePos , /* isInjector */ false ) ;
2020-02-10 15:16:09 +01:00
// Sum over all processes
rates [ phasePos ] = - comm . sum ( local_current_rate ) ;
}
// Check higher up only if under individual (not FLD) control.
2021-04-22 17:31:21 +02:00
const Group : : ProductionCMode & currentControl = this - > groupState ( ) . production_control ( group . name ( ) ) ;
2021-04-19 14:34:38 +02:00
if ( currentControl ! = Group : : ProductionCMode : : FLD & & group . productionGroupControlAvailable ( ) ) {
2020-02-10 15:16:09 +01:00
const Group & parentGroup = schedule ( ) . getGroup ( group . parent ( ) , reportStepIdx ) ;
2020-03-27 13:27:45 +01:00
const std : : pair < bool , double > changed = WellGroupHelpers : : checkGroupConstraintsProd (
2020-02-10 15:16:09 +01:00
group . name ( ) ,
group . parent ( ) ,
parentGroup ,
2021-03-26 22:10:16 +01:00
this - > wellState ( ) ,
2021-04-22 17:31:21 +02:00
this - > groupState ( ) ,
2020-02-10 15:16:09 +01:00
reportStepIdx ,
guideRate_ . get ( ) ,
rates . data ( ) ,
phase_usage_ ,
group . getGroupEfficiencyFactor ( ) ,
schedule ( ) ,
summaryState ,
2020-03-27 13:27:45 +01:00
resv_coeff ,
2020-02-10 15:16:09 +01:00
deferred_logger ) ;
2020-03-24 09:24:45 +01:00
if ( changed . first ) {
2020-02-10 15:16:09 +01:00
switched_groups . insert ( group . name ( ) ) ;
const auto exceed_action = group . productionControls ( summaryState ) . exceed_action ;
2020-04-08 10:41:20 +02:00
actionOnBrokenConstraints ( group , exceed_action , Group : : ProductionCMode : : FLD , deferred_logger ) ;
2020-02-10 15:16:09 +01:00
}
}
}
// call recursively down the group hiearchy
for ( const std : : string & groupName : group . groups ( ) ) {
checkGroupHigherConstraints ( schedule ( ) . getGroup ( groupName , reportStepIdx ) , deferred_logger , switched_groups ) ;
}
}
2020-10-29 23:30:09 +01:00
2021-03-01 15:17:52 +01:00
2021-02-12 12:35:53 +01:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2021-03-25 14:46:35 +01:00
updateEclWells ( const int timeStepIdx , const std : : unordered_set < std : : string > & wells ) {
const auto & schedule = this - > ebosSimulator_ . vanguard ( ) . schedule ( ) ;
for ( const auto & wname : wells ) {
auto well_iter = std : : find_if ( this - > wells_ecl_ . begin ( ) , this - > wells_ecl_ . end ( ) , [ wname ] ( const auto & well ) - > bool { return well . name ( ) = = wname ; } ) ;
if ( well_iter ! = this - > wells_ecl_ . end ( ) ) {
auto well_index = std : : distance ( this - > wells_ecl_ . begin ( ) , well_iter ) ;
this - > wells_ecl_ [ well_index ] = schedule . getWell ( wname , timeStepIdx ) ;
const auto & well = this - > wells_ecl_ [ well_index ] ;
auto & pd = this - > well_perf_data_ [ well_index ] ;
auto pdIter = pd . begin ( ) ;
for ( const auto & conn : well . getConnections ( ) ) {
if ( conn . state ( ) ! = Connection : : State : : SHUT ) {
pdIter - > connection_transmissibility_factor = conn . CF ( ) ;
+ + pdIter ;
}
}
this - > wellState ( ) . updateStatus ( well_index , well . getStatus ( ) ) ;
this - > wellState ( ) . resetConnectionTransFactors ( well_index , pd ) ;
this - > prod_index_calc_ [ well_index ] . reInit ( well ) ;
}
2021-03-01 15:17:52 +01:00
}
2021-02-12 12:35:53 +01:00
}
2021-02-10 14:58:13 +01:00
2021-03-01 15:17:52 +01:00
2021-02-12 11:45:37 +01:00
template < typename TypeTag >
double
BlackoilWellModel < TypeTag > : :
2021-03-01 15:17:52 +01:00
wellPI ( const int well_index ) const
2021-02-12 11:45:37 +01:00
{
const auto & pu = this - > phase_usage_ ;
const auto np = this - > numPhases ( ) ;
2021-03-26 22:10:16 +01:00
const auto * pi = & this - > wellState ( ) . productivityIndex ( ) [ np * well_index + 0 ] ;
2021-02-12 11:45:37 +01:00
const auto preferred = this - > wells_ecl_ [ well_index ] . getPreferredPhase ( ) ;
switch ( preferred ) { // Should really have LIQUID = OIL + WATER here too...
case Phase : : WATER :
return pu . phase_used [ BlackoilPhases : : PhaseIndex : : Aqua ]
? pi [ pu . phase_pos [ BlackoilPhases : : PhaseIndex : : Aqua ] ]
: 0.0 ;
case Phase : : OIL :
return pu . phase_used [ BlackoilPhases : : PhaseIndex : : Liquid ]
? pi [ pu . phase_pos [ BlackoilPhases : : PhaseIndex : : Liquid ] ]
: 0.0 ;
case Phase : : GAS :
return pu . phase_used [ BlackoilPhases : : PhaseIndex : : Vapour ]
? pi [ pu . phase_pos [ BlackoilPhases : : PhaseIndex : : Vapour ] ]
: 0.0 ;
default :
throw std : : invalid_argument {
" Unsupported preferred phase " +
2021-03-01 15:17:52 +01:00
std : : to_string ( static_cast < int > ( preferred ) )
} ;
2021-02-12 11:45:37 +01:00
}
}
2021-03-01 15:17:52 +01:00
2021-02-12 12:35:53 +01:00
template < typename TypeTag >
double
BlackoilWellModel < TypeTag > : :
wellPI ( const std : : string & well_name ) const
{
2021-03-01 15:17:52 +01:00
auto well_iter = std : : find_if ( this - > wells_ecl_ . begin ( ) , this - > wells_ecl_ . end ( ) ,
[ & well_name ] ( const Well & well )
{
return well . name ( ) = = well_name ;
} ) ;
if ( well_iter = = this - > wells_ecl_ . end ( ) ) {
throw std : : logic_error { " Could not find well: " + well_name } ;
}
2021-02-12 12:35:53 +01:00
2021-03-01 15:17:52 +01:00
auto well_index = std : : distance ( this - > wells_ecl_ . begin ( ) , well_iter ) ;
2021-02-12 12:35:53 +01:00
return this - > wellPI ( well_index ) ;
}
2021-02-10 14:58:13 +01:00
2021-03-01 15:43:43 +01:00
template < typename TypeTag >
int
BlackoilWellModel < TypeTag > : :
reportStepIndex ( ) const
{
return std : : max ( this - > ebosSimulator_ . episodeIndex ( ) , 0 ) ;
}
2020-10-29 23:30:09 +01:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
runWellPIScaling ( const int timeStepIdx , DeferredLogger & local_deferredLogger )
{
if ( this - > last_run_wellpi_ . has_value ( ) & & ( * this - > last_run_wellpi_ = = timeStepIdx ) ) {
// We've already run WELPI scaling for this report step. Most
// common for the very first report step. Don't redo WELPI scaling.
return ;
}
auto hasWellPIEvent = [ this , timeStepIdx ] ( const int well_index ) - > bool
{
2021-03-01 15:17:52 +01:00
return this - > schedule ( ) [ timeStepIdx ] . wellgroup_events ( )
. hasEvent ( this - > wells_ecl_ [ well_index ] . name ( ) ,
ScheduleEvents : : Events : : WELL_PRODUCTIVITY_INDEX ) ;
2020-10-29 23:30:09 +01:00
} ;
2021-03-25 14:42:03 +01:00
auto updateEclWell = [ this , timeStepIdx ] ( const int well_index ) - > void
{
const auto & schedule = this - > schedule ( ) ;
const auto & wname = this - > wells_ecl_ [ well_index ] . name ( ) ;
this - > wells_ecl_ [ well_index ] = schedule . getWell ( wname , timeStepIdx ) ;
const auto & well = this - > wells_ecl_ [ well_index ] ;
auto & pd = this - > well_perf_data_ [ well_index ] ;
auto pdIter = pd . begin ( ) ;
for ( const auto & conn : well . getConnections ( ) ) {
if ( conn . state ( ) ! = Connection : : State : : SHUT ) {
pdIter - > connection_transmissibility_factor = conn . CF ( ) ;
+ + pdIter ;
}
}
2021-03-25 14:46:35 +01:00
this - > wellState ( ) . resetConnectionTransFactors ( well_index , pd ) ;
2021-03-25 14:42:03 +01:00
this - > prod_index_calc_ [ well_index ] . reInit ( well ) ;
} ;
2020-10-29 23:30:09 +01:00
auto rescaleWellPI =
[ this , timeStepIdx ] ( const int well_index ,
2021-02-05 12:53:00 +01:00
const double newWellPI ) - > void
2020-10-29 23:30:09 +01:00
{
2021-03-01 15:17:52 +01:00
const auto & wname = this - > wells_ecl_ [ well_index ] . name ( ) ;
auto & schedule = this - > ebosSimulator_ . vanguard ( ) . schedule ( ) ; // Mutable
schedule . applyWellProdIndexScaling ( wname , timeStepIdx , newWellPI ) ;
2020-10-29 23:30:09 +01:00
} ;
// Minimal well setup to compute PI/II values
{
2021-04-22 17:31:21 +02:00
auto saved_previous_wgstate = this - > prevWGState ( ) ;
this - > commitWGState ( ) ;
2020-10-29 23:30:09 +01:00
2021-03-02 01:11:19 +01:00
this - > well_container_ = this - > createWellContainer ( timeStepIdx ) ;
this - > inferLocalShutWells ( ) ;
2020-10-29 23:30:09 +01:00
2021-03-02 01:11:19 +01:00
for ( auto & wellPtr : this - > well_container_ ) {
wellPtr - > init ( & this - > phase_usage_ , this - > depth_ , this - > gravity_ ,
this - > local_num_cells_ , this - > B_avg_ ) ;
2020-10-29 23:30:09 +01:00
}
this - > calculateProductivityIndexValues ( local_deferredLogger ) ;
2021-03-02 01:11:19 +01:00
this - > calculateProductivityIndexValuesShutWells ( timeStepIdx , local_deferredLogger ) ;
2021-04-22 17:31:21 +02:00
this - > commitWGState ( std : : move ( saved_previous_wgstate ) ) ;
2020-10-29 23:30:09 +01:00
}
const auto nw = this - > numLocalWells ( ) ;
for ( auto wellID = 0 * nw ; wellID < nw ; + + wellID ) {
if ( hasWellPIEvent ( wellID ) ) {
2021-03-01 15:17:52 +01:00
rescaleWellPI ( wellID , this - > wellPI ( wellID ) ) ;
2021-03-25 14:42:03 +01:00
updateEclWell ( wellID ) ;
2020-10-29 23:30:09 +01:00
}
}
this - > last_run_wellpi_ = timeStepIdx ;
}
2021-03-01 15:43:43 +01:00
template < typename TypeTag >
bool
BlackoilWellModel < TypeTag > : :
wasDynamicallyShutThisTimeStep ( const int well_index ) const
{
return this - > closed_this_step_ . find ( this - > wells_ecl_ [ well_index ] . name ( ) )
! = this - > closed_this_step_ . end ( ) ;
}
2019-09-23 15:15:55 +02:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2019-11-13 23:16:11 +01:00
updateWsolvent ( const Group & group , const Schedule & schedule , const int reportStepIdx , const WellStateFullyImplicitBlackoil & wellState ) {
2019-09-23 15:15:55 +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-23 15:15:55 +02:00
updateWsolvent ( groupTmp , schedule , reportStepIdx , wellState ) ;
}
if ( group . isProductionGroup ( ) )
return ;
2021-04-22 17:31:21 +02:00
auto currentGroupControl = this - > groupState ( ) . injection_control ( group . name ( ) , Phase : : GAS ) ;
2019-11-13 23:16:11 +01:00
if ( currentGroupControl = = Group : : InjectionCMode : : REIN ) {
2019-09-23 15:15:55 +02:00
int gasPos = phase_usage_ . phase_pos [ BlackoilPhases : : Vapour ] ;
2020-05-04 09:16:42 +02:00
const auto & summaryState = ebosSimulator_ . vanguard ( ) . summaryState ( ) ;
const auto & controls = group . injectionControls ( Phase : : GAS , summaryState ) ;
const Group & groupRein = schedule . getGroup ( controls . reinj_group , reportStepIdx ) ;
double gasProductionRate = WellGroupHelpers : : sumWellRates ( groupRein , schedule , wellState , reportStepIdx , gasPos , /*isInjector*/ false ) ;
double solventProductionRate = WellGroupHelpers : : sumSolventRates ( groupRein , schedule , wellState , reportStepIdx , /*isInjector*/ false ) ;
2019-09-23 15:15:55 +02:00
2019-12-12 09:22:37 +01:00
const auto & comm = ebosSimulator_ . vanguard ( ) . grid ( ) . comm ( ) ;
solventProductionRate = comm . sum ( solventProductionRate ) ;
gasProductionRate = comm . sum ( gasProductionRate ) ;
2019-09-23 15:15:55 +02:00
double wsolvent = 0.0 ;
if ( std : : abs ( gasProductionRate ) > 1e-6 )
wsolvent = solventProductionRate / gasProductionRate ;
setWsolvent ( group , schedule , reportStepIdx , wsolvent ) ;
}
}
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2019-11-13 23:16:11 +01:00
setWsolvent ( const Group & group , const Schedule & schedule , const int reportStepIdx , double wsolvent ) {
2019-09-23 15:15:55 +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-23 15:15:55 +02:00
setWsolvent ( groupTmp , schedule , reportStepIdx , wsolvent ) ;
}
for ( const std : : string & wellName : group . wells ( ) ) {
2019-11-13 23:16:11 +01:00
const auto & wellTmp = schedule . getWell ( wellName , reportStepIdx ) ;
if ( wellTmp . getStatus ( ) = = Well : : Status : : SHUT )
2019-09-23 15:15:55 +02:00
continue ;
auto well = getWell ( wellName ) ;
well - > setWsolvent ( wsolvent ) ;
}
}
2020-10-20 00:10:27 +02:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
assignWellGuideRates ( data : : Wells & wsrpt ) const
{
for ( const auto & well : this - > wells_ecl_ ) {
auto xwPos = wsrpt . find ( well . name ( ) ) ;
if ( xwPos = = wsrpt . end ( ) ) { // No well results. Unexpected.
continue ;
}
xwPos - > second . guide_rates = this - > getGuideRateValues ( well ) ;
}
}
2020-10-29 23:16:31 +01:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
assignShutConnections ( data : : Wells & wsrpt ) const
{
2021-03-01 15:43:43 +01:00
auto wellID = 0 ;
2020-10-29 23:16:31 +01:00
for ( const auto & well : this - > wells_ecl_ ) {
2021-03-01 15:43:43 +01:00
auto & xwel = wsrpt [ well . name ( ) ] ; // data::Wells is a std::map<>
xwel . dynamicStatus = this - > schedule ( )
. getWell ( well . name ( ) , this - > reportStepIndex ( ) ) . getStatus ( ) ;
const auto wellIsOpen = xwel . dynamicStatus = = Well : : Status : : OPEN ;
auto skip = [ wellIsOpen ] ( const Connection & conn )
{
return wellIsOpen & & ( conn . state ( ) ! = Connection : : State : : SHUT ) ;
} ;
if ( this - > wellTestState_ . hasWellClosed ( well . name ( ) ) & &
! this - > wasDynamicallyShutThisTimeStep ( wellID ) )
{
xwel . dynamicStatus = well . getAutomaticShutIn ( )
? Well : : Status : : SHUT : Well : : Status : : STOP ;
2020-10-29 23:16:31 +01:00
}
2021-03-01 15:43:43 +01:00
auto & xcon = xwel . connections ;
2020-10-29 23:16:31 +01:00
for ( const auto & conn : well . getConnections ( ) ) {
2021-03-01 15:43:43 +01:00
if ( skip ( conn ) ) {
2020-10-29 23:16:31 +01:00
continue ;
}
auto & xc = xcon . emplace_back ( ) ;
xc . index = conn . global_index ( ) ;
xc . pressure = xc . reservoir_rate = 0.0 ;
xc . effective_Kh = conn . Kh ( ) ;
xc . trans_factor = conn . CF ( ) ;
}
2021-03-01 15:43:43 +01:00
+ + wellID ;
2020-10-29 23:16:31 +01:00
}
}
2020-09-20 22:16:07 +02:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
assignGroupValues ( const int reportStepIdx ,
const Schedule & sched ,
std : : map < std : : string , data : : GroupData > & gvalues ) const
{
const auto groupGuideRates =
this - > calculateAllGroupGuiderates ( reportStepIdx , sched ) ;
for ( const auto & gname : sched . groupNames ( reportStepIdx ) ) {
const auto & grup = sched . getGroup ( gname , reportStepIdx ) ;
auto & gdata = gvalues [ gname ] ;
this - > assignGroupControl ( grup , gdata ) ;
this - > assignGroupGuideRates ( grup , groupGuideRates , gdata ) ;
}
}
2020-05-15 11:21:32 +02:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2020-10-21 13:32:12 +02:00
assignNodeValues ( std : : map < std : : string , data : : NodeData > & nodevalues ) const
2020-05-15 11:21:32 +02:00
{
nodevalues . clear ( ) ;
for ( const auto & [ node , pressure ] : node_pressures_ ) {
nodevalues . emplace ( node , data : : NodeData { pressure } ) ;
}
}
2020-07-20 21:38:30 +02:00
template < typename TypeTag >
std : : unordered_map < std : : string , data : : GroupGuideRates >
BlackoilWellModel < TypeTag > : :
calculateAllGroupGuiderates ( const int reportStepIdx , const Schedule & sched ) const
{
auto gr = std : : unordered_map < std : : string , data : : GroupGuideRates > { } ;
auto up = std : : vector < std : : string > { } ;
// Start at well level, accumulate contributions towards root of
// group tree (FIELD group).
for ( const auto & wname : sched . wellNames ( reportStepIdx ) ) {
2021-03-26 22:10:16 +01:00
if ( ! ( this - > wellState ( ) . hasWellRates ( wname ) & &
2020-07-20 21:38:30 +02:00
this - > guideRate_ - > has ( wname ) ) )
{
continue ;
}
const auto & well = sched . getWell ( wname , reportStepIdx ) ;
const auto & parent = well . groupName ( ) ;
if ( parent = = " FIELD " ) {
// Well parented directly to "FIELD". Inadvisable and
// unexpected, but nothing to do about that here. Just skip
// this guide rate contribution.
continue ;
}
auto & grval = well . isInjector ( )
? gr [ parent ] . injection
: gr [ parent ] . production ;
grval + = this - > getGuideRateValues ( well ) ;
up . push_back ( parent ) ;
}
// Propagate accumulated guide rates up towards root of group tree.
// Override accumulation if there is a GUIDERAT specification that
// applies to a group.
std : : sort ( up . begin ( ) , up . end ( ) ) ;
auto start = 0 * up . size ( ) ;
auto u = std : : unique ( up . begin ( ) , up . end ( ) ) ;
auto nu = std : : distance ( up . begin ( ) , u ) ;
while ( nu > 0 ) {
const auto ntot = up . size ( ) ;
for ( auto gi = 0 * nu ; gi < nu ; + + gi ) {
const auto & gname = up [ start + gi ] ;
const auto & group = sched . getGroup ( gname , reportStepIdx ) ;
if ( this - > guideRate_ - > has ( gname ) ) {
gr [ gname ] . production = this - > getGuideRateValues ( group ) ;
}
2021-05-05 11:22:44 +02:00
if ( this - > guideRate_ - > has ( gname , Phase : : WATER )
| | this - > guideRate_ - > has ( gname , Phase : : GAS ) ) {
2021-03-10 14:26:04 +01:00
gr [ gname ] . injection = this - > getGuideRateInjectionGroupValues ( group ) ;
}
2020-07-20 21:38:30 +02:00
const auto parent = group . parent ( ) ;
if ( parent = = " FIELD " ) { continue ; }
gr [ parent ] . injection + = gr [ gname ] . injection ;
gr [ parent ] . production + = gr [ gname ] . production ;
up . push_back ( parent ) ;
}
start = ntot ;
auto begin = up . begin ( ) + ntot ;
std : : sort ( begin , up . end ( ) ) ;
u = std : : unique ( begin , up . end ( ) ) ;
nu = std : : distance ( begin , u ) ;
}
return gr ;
}
2020-07-01 13:52:02 +02:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
assignGroupControl ( const Group & group , data : : GroupData & gdata ) const
{
const auto & gname = group . name ( ) ;
const auto grup_type = group . getGroupType ( ) ;
auto & cgc = gdata . currentControl ;
cgc . currentProdConstraint =
: : Opm : : Group : : ProductionCMode : : NONE ;
cgc . currentGasInjectionConstraint =
cgc . currentWaterInjectionConstraint =
: : Opm : : Group : : InjectionCMode : : NONE ;
2021-04-22 17:31:21 +02:00
if ( this - > groupState ( ) . has_production_control ( gname ) ) {
cgc . currentProdConstraint = this - > groupState ( ) . production_control ( gname ) ;
2020-07-01 13:52:02 +02:00
}
if ( ( grup_type = = : : Opm : : Group : : GroupType : : INJECTION ) | |
( grup_type = = : : Opm : : Group : : GroupType : : MIXED ) )
{
2021-04-22 17:31:21 +02:00
if ( this - > groupState ( ) . has_injection_control ( gname , : : Opm : : Phase : : WATER ) ) {
cgc . currentWaterInjectionConstraint = this - > groupState ( ) . injection_control ( gname , Phase : : WATER ) ;
2020-07-01 13:52:02 +02:00
}
2021-04-22 17:31:21 +02:00
if ( this - > groupState ( ) . has_injection_control ( gname , : : Opm : : Phase : : GAS ) ) {
cgc . currentGasInjectionConstraint = this - > groupState ( ) . injection_control ( gname , Phase : : GAS ) ;
2020-07-01 13:52:02 +02:00
}
}
}
2018-11-26 12:09:04 +01:00
2020-07-20 21:38:30 +02:00
template < typename TypeTag >
data : : GuideRateValue
BlackoilWellModel < TypeTag > : :
getGuideRateValues ( const Well & well ) const
{
auto grval = data : : GuideRateValue { } ;
assert ( this - > guideRate_ ! = nullptr ) ;
const auto & wname = well . name ( ) ;
2021-03-26 22:10:16 +01:00
if ( ! this - > wellState ( ) . hasWellRates ( wname ) ) {
2020-07-20 21:38:30 +02:00
// No flow rates for 'wname' -- might be before well comes
// online (e.g., for the initial condition before simulation
// starts).
return grval ;
}
if ( ! this - > guideRate_ - > has ( wname ) ) {
// No guiderates exist for 'wname'.
return grval ;
}
const auto qs = WellGroupHelpers : :
2021-03-26 22:10:16 +01:00
getWellRateVector ( this - > wellState ( ) , this - > phase_usage_ , wname ) ;
2020-07-20 21:38:30 +02:00
this - > getGuideRateValues ( qs , well . isInjector ( ) , wname , grval ) ;
return grval ;
}
2021-03-10 14:26:04 +01:00
template < typename TypeTag >
data : : GuideRateValue
BlackoilWellModel < TypeTag > : :
getGuideRateInjectionGroupValues ( const Group & group ) const
{
auto grval = data : : GuideRateValue { } ;
assert ( this - > guideRate_ ! = nullptr ) ;
const auto & gname = group . name ( ) ;
2021-05-05 11:22:44 +02:00
if ( this - > guideRate_ - > has ( gname , Phase : : GAS ) ) {
2021-03-10 14:26:04 +01:00
grval . set ( data : : GuideRateValue : : Item : : Gas ,
2021-05-05 11:22:44 +02:00
this - > guideRate_ - > get ( gname , Phase : : GAS ) ) ;
2021-03-10 14:26:04 +01:00
}
2021-05-05 11:22:44 +02:00
if ( this - > guideRate_ - > has ( gname , Phase : : WATER ) ) {
2021-03-10 14:26:04 +01:00
grval . set ( data : : GuideRateValue : : Item : : Water ,
2021-05-05 11:22:44 +02:00
this - > guideRate_ - > get ( gname , Phase : : WATER ) ) ;
2021-03-10 14:26:04 +01:00
}
return grval ;
}
2020-07-20 21:38:30 +02:00
template < typename TypeTag >
data : : GuideRateValue
BlackoilWellModel < TypeTag > : :
getGuideRateValues ( const Group & group ) const
{
auto grval = data : : GuideRateValue { } ;
assert ( this - > guideRate_ ! = nullptr ) ;
const auto & gname = group . name ( ) ;
2021-03-10 14:26:04 +01:00
2021-04-22 17:31:21 +02:00
if ( ! this - > groupState ( ) . has_production_rates ( gname ) ) {
2021-03-10 14:26:04 +01:00
// No flow rates for production group 'gname' -- might be before group comes
2020-07-20 21:38:30 +02:00
// online (e.g., for the initial condition before simulation
// starts).
return grval ;
}
if ( ! this - > guideRate_ - > has ( gname ) ) {
// No guiderates exist for 'gname'.
return grval ;
}
2021-04-22 17:31:21 +02:00
const auto qs = WellGroupHelpers : : getProductionGroupRateVector ( this - > groupState ( ) , this - > phase_usage_ , gname ) ;
2020-07-20 21:38:30 +02:00
const auto is_inj = false ; // This procedure only applies to G*PGR.
this - > getGuideRateValues ( qs , is_inj , gname , grval ) ;
return grval ;
}
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
getGuideRateValues ( const GuideRate : : RateVector & qs ,
const bool is_inj ,
const std : : string & wgname ,
data : : GuideRateValue & grval ) const
{
auto getGR = [ this , & wgname , & qs ] ( const GuideRateModel : : Target t )
{
return this - > guideRate_ - > get ( wgname , t , qs ) ;
} ;
// Note: GuideRate does currently (2020-07-20) not support Target::RES.
grval . set ( data : : GuideRateValue : : Item : : Gas ,
getGR ( GuideRateModel : : Target : : GAS ) ) ;
grval . set ( data : : GuideRateValue : : Item : : Water ,
getGR ( GuideRateModel : : Target : : WAT ) ) ;
if ( ! is_inj ) {
// Producer. Extract "all" guiderate values.
grval . set ( data : : GuideRateValue : : Item : : Oil ,
getGR ( GuideRateModel : : Target : : OIL ) ) ;
}
}
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
assignGroupGuideRates ( const Group & group ,
const std : : unordered_map < std : : string , data : : GroupGuideRates > & groupGuideRates ,
data : : GroupData & gdata ) const
{
auto & prod = gdata . guideRates . production ; prod . clear ( ) ;
auto & inj = gdata . guideRates . injection ; inj . clear ( ) ;
auto xgrPos = groupGuideRates . find ( group . name ( ) ) ;
if ( ( xgrPos = = groupGuideRates . end ( ) ) | |
! this - > guideRate_ - > has ( group . name ( ) ) )
{
// No guiderates defined for this group.
return ;
}
const auto & xgr = xgrPos - > second ;
prod = xgr . production ;
inj = xgr . injection ;
}
2021-03-08 15:11:50 +01:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
computeWellTemperature ( )
{
if ( ! has_energy_ )
return ;
int np = numPhases ( ) ;
double cellInternalEnergy ;
double cellBinv ;
double cellDensity ;
double perfPhaseRate ;
const int nw = numLocalWells ( ) ;
for ( auto wellID = 0 * nw ; wellID < nw ; + + wellID ) {
const Well & well = wells_ecl_ [ wellID ] ;
if ( well . isInjector ( ) )
continue ;
int connpos = 0 ;
for ( int i = 0 ; i < wellID ; + + i ) {
connpos + = well_perf_data_ [ i ] . size ( ) ;
}
connpos * = np ;
double weighted_temperature = 0.0 ;
double total_weight = 0.0 ;
auto & well_info = * local_parallel_well_info_ [ wellID ] ;
const int num_perf_this_well = well_info . communication ( ) . sum ( well_perf_data_ [ wellID ] . size ( ) ) ;
for ( int perf = 0 ; perf < num_perf_this_well ; + + perf ) {
const int cell_idx = well_perf_data_ [ wellID ] [ perf ] . cell_index ;
const auto & intQuants = * ( ebosSimulator_ . model ( ) . cachedIntensiveQuantities ( cell_idx , /*timeIdx=*/ 0 ) ) ;
const auto & fs = intQuants . fluidState ( ) ;
double cellTemperatures = fs . temperature ( /*phaseIdx*/ 0 ) . value ( ) ;
double weight_factor = 0.0 ;
for ( int phaseIdx = 0 ; phaseIdx < np ; + + phaseIdx ) {
cellInternalEnergy = fs . enthalpy ( phaseIdx ) . value ( ) - fs . pressure ( phaseIdx ) . value ( ) / fs . density ( phaseIdx ) . value ( ) ;
cellBinv = fs . invB ( phaseIdx ) . value ( ) ;
cellDensity = fs . density ( phaseIdx ) . value ( ) ;
2021-03-26 22:10:16 +01:00
perfPhaseRate = this - > wellState ( ) . perfPhaseRates ( ) [ connpos + perf * np + phaseIdx ] ;
2021-03-08 15:11:50 +01:00
weight_factor + = cellDensity * perfPhaseRate / cellBinv * cellInternalEnergy / cellTemperatures ;
}
total_weight + = weight_factor ;
weighted_temperature + = weight_factor * cellTemperatures ;
}
weighted_temperature = well_info . communication ( ) . sum ( weighted_temperature ) ;
total_weight = well_info . communication ( ) . sum ( total_weight ) ;
2021-05-14 08:23:46 +02:00
this - > wellState ( ) . update_temperature ( wellID , weighted_temperature / total_weight ) ;
2021-03-08 15:11:50 +01:00
}
}
2017-02-13 16:45:06 +01:00
} // namespace Opm