2019-02-07 07:43:17 -06: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 09:45:06 -06:00
2019-02-07 07:43:17 -06:00
This file is part of the Open Porous Media project ( OPM ) .
2017-02-13 09:45:06 -06:00
2019-02-07 07:43:17 -06: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 .
OPM is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with OPM . If not , see < http : //www.gnu.org/licenses/>.
*/
2019-05-07 06:06:02 -05:00
# include <opm/simulators/utils/DeferredLoggingErrorHelpers.hpp>
2019-06-20 03:15:51 -05:00
# include <opm/simulators/wells/SimFIBODetails.hpp>
2019-11-25 03:34:50 -06:00
# include <opm/core/props/phaseUsageFromDeck.hpp>
2017-02-13 09:45:06 -06:00
namespace Opm {
2017-05-03 06:34:15 -05:00
template < typename TypeTag >
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2018-08-16 04:51:36 -05:00
BlackoilWellModel ( Simulator & ebosSimulator )
2017-11-08 06:57:36 -06:00
: ebosSimulator_ ( ebosSimulator )
, has_solvent_ ( GET_PROP_VALUE ( TypeTag , EnableSolvent ) )
, has_polymer_ ( GET_PROP_VALUE ( TypeTag , EnablePolymer ) )
2017-02-13 09:45:06 -06:00
{
2018-08-16 04:51:36 -05:00
terminal_output_ = false ;
if ( ebosSimulator . gridView ( ) . comm ( ) . rank ( ) = = 0 )
terminal_output_ = EWOMS_GET_PARAM ( TypeTag , bool , EnableTerminalOutput ) ;
2019-09-30 05:49:36 -05:00
// Create the guide rate container.
guideRate_ . reset ( new GuideRate ( ebosSimulator_ . vanguard ( ) . schedule ( ) ) ) ;
2019-10-23 02:09:45 -05:00
// calculate the number of elements of the compressed sequential grid. this needs
// to be done in two steps because the dune communicator expects a reference as
// argument for sum()
const auto & gridView = ebosSimulator_ . gridView ( ) ;
number_of_cells_ = gridView . size ( /*codim=*/ 0 ) ;
global_nc_ = gridView . comm ( ) . sum ( number_of_cells_ ) ;
// Set up cartesian mapping.
const auto & grid = ebosSimulator_ . vanguard ( ) . grid ( ) ;
const auto & cartDims = Opm : : UgGridHelpers : : cartDims ( grid ) ;
setupCartesianToCompressed_ ( Opm : : UgGridHelpers : : globalCell ( grid ) ,
cartDims [ 0 ] * cartDims [ 1 ] * cartDims [ 2 ] ) ;
2018-08-16 04:51:36 -05:00
}
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2019-04-03 10:26:57 -05:00
init ( )
2018-08-16 04:51:36 -05:00
{
2019-04-03 10:26:57 -05:00
const Opm : : EclipseState & eclState = ebosSimulator_ . vanguard ( ) . eclState ( ) ;
2018-08-16 04:51:36 -05:00
extractLegacyCellPvtRegionIndex_ ( ) ;
extractLegacyDepth_ ( ) ;
2017-11-08 06:57:36 -06:00
phase_usage_ = phaseUsageFromDeck ( eclState ) ;
gravity_ = ebosSimulator_ . problem ( ) . gravity ( ) [ 2 ] ;
2017-02-13 09:45:06 -06:00
2018-03-23 06:56:19 -05:00
initial_step_ = true ;
2018-08-16 04:51:36 -05:00
// add the eWoms auxiliary module for the wells to the list
ebosSimulator_ . model ( ) . addAuxiliaryModule ( this ) ;
2018-11-15 07:37:01 -06:00
is_cell_perforated_ . resize ( number_of_cells_ , false ) ;
2018-08-16 04:51:36 -05: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 16:16:11 -06:00
const auto & schedule_wells = schedule ( ) . getWellsatEnd ( ) ;
2018-08-16 04:51:36 -05:00
const auto & cartesianSize = Opm : : UgGridHelpers : : cartDims ( grid ( ) ) ;
// initialize the additional cell connections introduced by wells.
2019-05-02 05:51:25 -05:00
for ( const auto & well : schedule_wells )
2018-08-16 04:51:36 -05:00
{
std : : vector < int > wellCells ;
// All possible connections of the well
2019-05-02 05:51:25 -05:00
const auto & connectionSet = well . getConnections ( ) ;
2018-08-16 04:51:36 -05:00
wellCells . reserve ( connectionSet . size ( ) ) ;
for ( size_t c = 0 ; c < connectionSet . size ( ) ; c + + )
{
const auto & connection = connectionSet . get ( c ) ;
int i = connection . getI ( ) ;
int j = connection . getJ ( ) ;
int k = connection . getK ( ) ;
int cart_grid_idx = i + cartesianSize [ 0 ] * ( j + cartesianSize [ 1 ] * k ) ;
int compressed_idx = cartesian_to_compressed_ . at ( cart_grid_idx ) ;
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 05:48:29 -05:00
linearize ( SparseMatrixAdapter & jacobian , GlobalEqVector & res )
2018-08-16 04:51:36 -05:00
{
if ( ! localWellsActive ( ) )
return ;
2019-02-25 03:51:30 -06: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 04:51:36 -05:00
for ( const auto & well : well_container_ ) {
2019-10-02 05:48:29 -05:00
well - > addWellContributions ( jacobian ) ;
2018-08-16 04:51:36 -05:00
// applying the well residual to reservoir residuals
// r = r - duneC_^T * invDuneD_ * resWell_
well - > apply ( res ) ;
}
2017-11-08 06:57:36 -06:00
}
2017-02-13 09:45:06 -06:00
2018-11-22 04:01:58 -06:00
/// Return true if any well has a THP constraint.
template < typename TypeTag >
bool
BlackoilWellModel < TypeTag > : :
hasTHPConstraints ( ) const
{
2019-01-14 15:14:01 -06:00
int local_result = false ;
2019-08-07 07:13:11 -05:00
const auto & summaryState = ebosSimulator_ . vanguard ( ) . summaryState ( ) ;
2018-11-22 04:01:58 -06:00
for ( const auto & well : well_container_ ) {
2019-08-07 07:13:11 -05:00
if ( well - > wellHasTHPConstraints ( summaryState ) ) {
2019-01-14 15:14:01 -06:00
local_result = true ;
2018-11-22 04:01:58 -06:00
}
}
2019-01-14 15:14:01 -06:00
return grid ( ) . comm ( ) . max ( local_result ) ;
2018-11-22 04:01:58 -06:00
}
2018-12-03 06:24:34 -06:00
/// Return true if the well was found and shut.
2018-11-22 09:24:17 -06:00
template < typename TypeTag >
2018-12-03 06:24:34 -06:00
bool
2018-11-22 09:24:17 -06:00
BlackoilWellModel < TypeTag > : :
2018-11-23 05:51:13 -06:00
forceShutWellByNameIfPredictionMode ( const std : : string & wellname ,
const double simulation_time )
2018-11-22 09:24:17 -06:00
{
// Only add the well to the closed list on the
// process that owns it.
2018-12-03 06:24:34 -06:00
int well_was_shut = 0 ;
2018-11-22 09:24:17 -06:00
for ( const auto & well : well_container_ ) {
2019-08-07 07:13:11 -05:00
if ( well - > name ( ) = = wellname & & ! well - > wellIsStopped ( ) ) {
2019-06-26 02:50:56 -05:00
if ( well - > underPredictionMode ( ) ) {
2019-06-25 01:13:37 -05:00
wellTestState_ . closeWell ( wellname , WellTestConfig : : Reason : : PHYSICAL , simulation_time ) ;
2018-12-03 06:24:34 -06:00
well_was_shut = 1 ;
2018-11-23 05:51:13 -06:00
}
2018-11-22 09:24:17 -06:00
break ;
}
}
2018-12-03 06:24:34 -06:00
// Communicate across processes if a well was shut.
well_was_shut = ebosSimulator_ . vanguard ( ) . grid ( ) . comm ( ) . max ( well_was_shut ) ;
2018-11-22 09:24:17 -06:00
// Only log a message on the output rank.
2018-12-03 06:24:34 -06:00
if ( terminal_output_ & & well_was_shut ) {
2018-11-22 09:24:17 -06:00
const std : : string msg = " Well " + wellname
+ " will be shut because it cannot get converged. " ;
OpmLog : : info ( msg ) ;
}
2018-12-03 06:24:34 -06:00
return ( well_was_shut = = 1 ) ;
2018-11-22 09:24:17 -06:00
}
2017-05-03 06:34:15 -05:00
template < typename TypeTag >
2017-02-13 09:45:06 -06:00
void
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2017-11-08 06:57:36 -06:00
beginReportStep ( const int timeStepIdx )
2017-02-13 09:45:06 -06:00
{
2019-02-07 07:43:17 -06:00
Opm : : DeferredLogger local_deferredLogger ;
2020-01-29 01:41:41 -06:00
report_step_starts_ = true ;
2019-02-07 07:43:17 -06:00
2018-02-01 09:27:42 -06:00
const Grid & grid = ebosSimulator_ . vanguard ( ) . grid ( ) ;
2019-05-29 00:44:23 -05:00
const auto & summaryState = ebosSimulator_ . vanguard ( ) . summaryState ( ) ;
2019-12-12 02:22:37 -06:00
int globalNumWells = 0 ;
2019-10-23 02:09:45 -05:00
// Make wells_ecl_ contain only this partition's non-shut wells.
{
const auto & defunct_well_names = ebosSimulator_ . vanguard ( ) . defunctWellNames ( ) ;
auto is_shut_or_defunct = [ & defunct_well_names ] ( const Well & well ) {
return ( well . getStatus ( ) = = Well : : Status : : SHUT ) | | ( defunct_well_names . find ( well . name ( ) ) ! = defunct_well_names . end ( ) ) ;
} ;
auto w = schedule ( ) . getWells ( timeStepIdx ) ;
2019-12-12 02:22:37 -06:00
globalNumWells = w . size ( ) ;
2019-10-23 02:09:45 -05:00
w . erase ( std : : remove_if ( w . begin ( ) , w . end ( ) , is_shut_or_defunct ) , w . end ( ) ) ;
wells_ecl_ . swap ( w ) ;
}
initializeWellPerfData ( ) ;
2017-11-16 04:42:34 -06:00
2017-11-08 06:57:36 -06: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_ ) ;
// The well state initialize bhp with the cell pressure in the top cell.
// We must therefore provide it with updated cell pressures
2017-11-08 08:48:30 -06:00
size_t nc = number_of_cells_ ;
2017-11-08 06:57:36 -06:00
std : : vector < double > cellPressures ( nc , 0.0 ) ;
ElementContext elemCtx ( ebosSimulator_ ) ;
2018-02-01 09:27:42 -06:00
const auto & gridView = ebosSimulator_ . vanguard ( ) . gridView ( ) ;
2017-11-08 06:57:36 -06:00
const auto & elemEndIt = gridView . template end < /*codim=*/ 0 > ( ) ;
for ( auto elemIt = gridView . template begin < /*codim=*/ 0 > ( ) ;
elemIt ! = elemEndIt ;
+ + elemIt )
{
const auto & elem = * elemIt ;
if ( elem . partitionType ( ) ! = Dune : : InteriorEntity ) {
continue ;
}
elemCtx . updatePrimaryStencil ( elem ) ;
elemCtx . updatePrimaryIntensiveQuantities ( /*timeIdx=*/ 0 ) ;
2017-03-24 09:12:42 -05:00
2017-11-08 06:57:36 -06:00
const unsigned cellIdx = elemCtx . globalSpaceIndex ( /*spaceIdx=*/ 0 , /*timeIdx=*/ 0 ) ;
const auto & intQuants = elemCtx . intensiveQuantities ( /*spaceIdx=*/ 0 , /*timeIdx=*/ 0 ) ;
const auto & fs = intQuants . fluidState ( ) ;
2019-10-11 08:57:51 -05:00
// copy of get perfpressure in Standard well
// exept for value
double perf_pressure = 0.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 ( ) ;
}
}
2019-10-09 08:24:23 -05:00
cellPressures [ cellIdx ] = perf_pressure ;
2017-02-13 09:45:06 -06:00
}
2019-12-12 02:22:37 -06:00
well_state_ . init ( cellPressures , schedule ( ) , wells_ecl_ , timeStepIdx , & previous_well_state_ , phase_usage_ , well_perf_data_ , summaryState , globalNumWells ) ;
2017-11-08 06:57:36 -06:00
// handling MS well related
2019-10-23 02:09:45 -05:00
if ( param_ . use_multisegment_well_ & & anyMSWellOpenLocal ( ) ) { // if we use MultisegmentWell model
well_state_ . initWellStateMSWell ( wells_ecl_ , phase_usage_ , & previous_well_state_ ) ;
2017-06-07 02:29:31 -05:00
}
2019-10-23 02:09:45 -05:00
const int nw = wells_ecl_ . size ( ) ;
2019-08-07 07:13:11 -05:00
for ( int w = 0 ; w < nw ; + + w ) {
2019-10-23 02:09:45 -05:00
const auto & well = wells_ecl_ [ w ] ;
2019-08-07 07:13:11 -05:00
const uint64_t effective_events_mask = ScheduleEvents : : WELL_STATUS_CHANGE
+ ScheduleEvents : : PRODUCTION_UPDATE
+ ScheduleEvents : : INJECTION_UPDATE
+ ScheduleEvents : : NEW_WELL ;
2019-02-07 07:43:17 -06:00
2019-11-27 07:56:10 -06:00
if ( ! schedule ( ) . hasWellGroupEvent ( well . name ( ) , effective_events_mask , timeStepIdx ) )
2019-08-07 07:13:11 -05:00
continue ;
if ( well . isProducer ( ) ) {
const auto controls = well . productionControls ( summaryState ) ;
well_state_ . currentProductionControls ( ) [ w ] = controls . cmode ;
}
else {
const auto controls = well . injectionControls ( summaryState ) ;
well_state_ . currentInjectionControls ( ) [ w ] = controls . cmode ;
}
2019-02-07 07:43:17 -06:00
}
2019-11-13 16:16:11 -06:00
const Group & fieldGroup = schedule ( ) . getGroup ( " FIELD " , timeStepIdx ) ;
2019-08-07 07:13:11 -05:00
wellGroupHelpers : : setCmodeGroup ( fieldGroup , schedule ( ) , summaryState , timeStepIdx , well_state_ ) ;
// Compute reservoir volumes for RESV controls.
rateConverter_ . reset ( new RateConverterType ( phase_usage_ ,
2019-12-11 15:04:40 -06:00
std : : vector < int > ( number_of_cells_ , 0 ) ) ) ;
2019-08-07 07:13:11 -05:00
rateConverter_ - > template defineState < ElementContext > ( ebosSimulator_ ) ;
2017-11-08 06:57:36 -06:00
2018-06-06 08:17:59 -05:00
// update VFP properties
2018-11-13 03:45:02 -06:00
vfp_properties_ . reset ( new VFPProperties < VFPInjProperties , VFPProdProperties > (
2018-06-06 08:17:59 -05:00
schedule ( ) . getVFPInjTables ( timeStepIdx ) ,
schedule ( ) . getVFPProdTables ( timeStepIdx ) ) ) ;
2019-08-07 07:13:11 -05:00
// update the previous well state. This is used to restart failed steps.
previous_well_state_ = well_state_ ;
2018-06-06 08:17:59 -05:00
}
// called at the beginning of a time step
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2018-08-16 04:51:36 -05:00
beginTimeStep ( ) {
2019-02-07 07:43:17 -06:00
Opm : : DeferredLogger local_deferredLogger ;
2018-06-06 08:17:59 -05:00
well_state_ = previous_well_state_ ;
2018-08-16 04:51:36 -05:00
const int reportStepIdx = ebosSimulator_ . episodeIndex ( ) ;
const double simulationTime = ebosSimulator_ . time ( ) ;
2018-06-06 08:17:59 -05:00
2019-02-07 07:43:17 -06:00
int exception_thrown = 0 ;
try {
// test wells
wellTesting ( reportStepIdx , simulationTime , local_deferredLogger ) ;
2018-06-06 08:17:59 -05:00
2019-02-07 07:43:17 -06:00
// create the well container
2019-10-23 02:09:45 -05:00
well_container_ = createWellContainer ( reportStepIdx ) ;
2017-11-08 06:57:36 -06:00
2019-02-07 07:43:17 -06: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_ ) {
well - > init ( & phase_usage_ , depth_ , gravity_ , number_of_cells_ ) ;
}
2017-08-07 04:35:59 -05:00
2019-02-07 07:43:17 -06: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 07:37:01 -06:00
2019-02-07 07:43:17 -06:00
// calculate the efficiency factors for each well
2019-08-07 07:13:11 -05:00
calculateEfficiencyFactors ( reportStepIdx ) ;
2017-08-07 04:35:59 -05:00
2019-02-07 07:43:17 -06:00
if ( has_polymer_ )
{
const Grid & grid = ebosSimulator_ . vanguard ( ) . grid ( ) ;
if ( PolymerModule : : hasPlyshlog ( ) | | GET_PROP_VALUE ( TypeTag , EnablePolymerMW ) ) {
computeRepRadiusPerfLength ( grid , local_deferredLogger ) ;
}
2017-11-08 06:57:36 -06:00
}
2019-02-07 07:43:17 -06:00
} catch ( std : : exception & e ) {
exception_thrown = 1 ;
2017-08-07 07:50:03 -05:00
}
2017-08-07 04:35:59 -05:00
2019-02-07 07:43:17 -06:00
logAndCheckForExceptionsAndThrow ( local_deferredLogger , exception_thrown , " beginTimeStep() failed. " , terminal_output_ ) ;
2018-04-07 14:41:34 -05:00
for ( auto & well : well_container_ ) {
well - > setVFPProperties ( vfp_properties_ . get ( ) ) ;
2019-09-30 05:49:36 -05:00
well - > setGuideRate ( guideRate_ . get ( ) ) ;
2018-04-07 14:41:34 -05:00
}
2017-08-07 04:35:59 -05:00
2018-10-31 09:32:50 -05:00
// Close completions due to economical reasons
2018-06-06 08:17:59 -05:00
for ( auto & well : well_container_ ) {
2018-07-03 08:13:30 -05:00
well - > closeCompletions ( wellTestState_ ) ;
2018-06-06 08:17:59 -05:00
}
2019-09-30 05:49:36 -05: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 ) ;
}
//compute well guideRates
2019-12-12 02:22:37 -06:00
const auto & comm = ebosSimulator_ . vanguard ( ) . grid ( ) . comm ( ) ;
wellGroupHelpers : : updateGuideRatesForWells ( schedule ( ) , phase_usage_ , reportStepIdx , simulationTime , well_state_ , comm , guideRate_ . get ( ) ) ;
2017-08-10 08:27:05 -05:00
}
2017-11-08 08:48:30 -06:00
template < typename TypeTag >
void
2019-02-07 07:43:17 -06:00
BlackoilWellModel < TypeTag > : : wellTesting ( const int timeStepIdx , const double simulationTime , Opm : : DeferredLogger & deferred_logger ) {
2018-06-06 08:17:59 -05:00
const auto & wtest_config = schedule ( ) . wtestConfig ( timeStepIdx ) ;
2019-02-03 01:13:11 -06:00
if ( wtest_config . size ( ) ! = 0 ) { // there is a WTEST request
2018-10-31 08:56:56 -05:00
2019-02-03 01:13:11 -06:00
// average B factors are required for the convergence checking of well equations
// Note: this must be done on all processes, even those with
// no wells needing testing, otherwise we will have locking.
std : : vector < Scalar > B_avg ( numComponents ( ) , Scalar ( ) ) ;
computeAverageFormationFactor ( B_avg ) ;
2018-06-06 08:17:59 -05:00
2019-07-02 09:33:12 -05:00
const auto & wellsForTesting = wellTestState_ . updateWells ( wtest_config , wells_ecl_ , simulationTime ) ;
2019-02-03 01:13:11 -06:00
for ( const auto & testWell : wellsForTesting ) {
const std : : string & well_name = testWell . first ;
2017-08-10 08:27:05 -05:00
2019-02-03 01:13:11 -06:00
// this is the well we will test
2019-02-07 07:43:17 -06:00
WellInterfacePtr well = createWellForWellTest ( well_name , timeStepIdx , deferred_logger ) ;
2018-06-06 08:17:59 -05:00
2019-02-03 01:13:11 -06:00
// some preparation before the well can be used
well - > init ( & phase_usage_ , depth_ , gravity_ , number_of_cells_ ) ;
2019-11-13 16:16:11 -06:00
const Well & wellEcl = schedule ( ) . getWell ( well_name , timeStepIdx ) ;
2019-08-07 07:13:11 -05:00
double well_efficiency_factor = wellEcl . getEfficiencyFactor ( ) ;
2019-11-13 16:16:11 -06:00
wellGroupHelpers : : accumulateGroupEfficiencyFactor ( schedule ( ) . getGroup ( wellEcl . groupName ( ) , timeStepIdx ) , schedule ( ) , timeStepIdx , well_efficiency_factor ) ;
2019-02-03 01:13:11 -06:00
well - > setWellEfficiencyFactor ( well_efficiency_factor ) ;
well - > setVFPProperties ( vfp_properties_ . get ( ) ) ;
2019-09-30 05:49:36 -05:00
well - > setGuideRate ( guideRate_ . get ( ) ) ;
2017-11-08 08:48:30 -06:00
2019-02-03 01:13:11 -06:00
const WellTestConfig : : Reason testing_reason = testWell . second ;
2018-06-28 06:28:30 -05:00
2019-02-03 01:13:11 -06:00
well - > wellTesting ( ebosSimulator_ , B_avg , simulationTime , timeStepIdx ,
2019-02-07 07:43:17 -06:00
testing_reason , well_state_ , wellTestState_ , deferred_logger ) ;
2019-02-03 01:13:11 -06:00
}
2019-01-18 07:04:30 -06:00
}
2017-11-08 08:48:30 -06:00
}
// called at the end of a report step
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
endReportStep ( ) {
}
// called at the end of a report step
template < typename TypeTag >
const SimulatorReport &
BlackoilWellModel < TypeTag > : :
lastReport ( ) const { return last_report_ ; }
// called at the end of a time step
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2018-11-30 05:15:51 -06:00
timeStepSucceeded ( const double & simulationTime , const double dt ) {
2019-02-03 01:13:11 -06:00
2020-01-29 01:41:41 -06:00
// time step is finished and we are not any more at the beginning of an report step
report_step_starts_ = false ;
2019-02-03 01:13:11 -06:00
Opm : : DeferredLogger local_deferredLogger ;
2018-02-14 06:34:35 -06:00
for ( const auto & well : well_container_ ) {
2019-10-23 02:09:45 -05:00
if ( GET_PROP_VALUE ( TypeTag , EnablePolymerMW ) & & well - > isInjector ( ) ) {
2018-11-30 05:15:51 -06:00
well - > updateWaterThroughput ( dt , well_state_ ) ;
}
2018-02-14 06:34:35 -06:00
}
2018-06-28 06:47:10 -05:00
updateWellTestState ( simulationTime , wellTestState_ ) ;
2018-11-07 07:53:43 -06:00
2019-08-07 07:13:11 -05:00
// update the rate converter with current averages pressures etc in
rateConverter_ - > template defineState < ElementContext > ( ebosSimulator_ ) ;
// calculate the well potentials
2019-02-07 07:43:17 -06:00
try {
2018-11-07 07:53:43 -06:00
std : : vector < double > well_potentials ;
2019-09-23 08:15:55 -05:00
const int reportStepIdx = ebosSimulator_ . episodeIndex ( ) ;
2019-08-07 07:13:11 -05:00
computeWellPotentials ( well_potentials , reportStepIdx , local_deferredLogger ) ;
2019-02-07 07:43:17 -06:00
} catch ( std : : runtime_error & e ) {
2018-11-07 07:53:43 -06:00
const std : : string msg = " A zero well potential is returned for output purposes. " ;
2019-02-03 01:13:11 -06:00
local_deferredLogger . warning ( " WELL_POTENTIAL_CALCULATION_FAILED " , msg ) ;
2018-11-07 07:53:43 -06:00
}
2017-11-08 08:48:30 -06:00
previous_well_state_ = well_state_ ;
2019-02-03 01:13:11 -06:00
Opm : : DeferredLogger global_deferredLogger = gatherDeferredLogger ( local_deferredLogger ) ;
if ( terminal_output_ ) {
global_deferredLogger . logMessages ( ) ;
}
2017-11-08 08:48:30 -06:00
}
2017-08-10 08:27:05 -05:00
2018-08-16 04:51:36 -05: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 07:37:01 -06:00
if ( ! is_cell_perforated_ [ elemIdx ] )
return ;
2018-08-16 04:51:36 -05:00
for ( const auto & well : well_container_ )
well - > addCellRates ( rate , elemIdx ) ;
}
2018-11-14 06:18:48 -06: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 04:51:36 -05:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
initFromRestartFile ( const RestartValue & restartValues )
{
2019-03-22 03:41:29 -05: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 00:44:23 -05:00
const auto & summaryState = ebosSimulator_ . vanguard ( ) . summaryState ( ) ;
2019-12-12 02:22:37 -06:00
int globalNumWells = 0 ;
2019-10-23 02:09:45 -05:00
// Make wells_ecl_ contain only this partition's non-shut wells.
{
const auto & defunct_well_names = ebosSimulator_ . vanguard ( ) . defunctWellNames ( ) ;
auto is_shut_or_defunct = [ & defunct_well_names ] ( const Well & well ) {
return ( well . getStatus ( ) = = Well : : Status : : SHUT ) | | ( defunct_well_names . find ( well . name ( ) ) ! = defunct_well_names . end ( ) ) ;
} ;
auto w = schedule ( ) . getWells ( report_step ) ;
2019-12-12 02:22:37 -06:00
globalNumWells = w . size ( ) ;
2019-10-23 02:09:45 -05:00
w . erase ( std : : remove_if ( w . begin ( ) , w . end ( ) , is_shut_or_defunct ) , w . end ( ) ) ;
wells_ecl_ . swap ( w ) ;
}
2018-08-16 04:51:36 -05:00
2019-10-23 02:09:45 -05:00
initializeWellPerfData ( ) ;
2019-10-01 07:30:11 -05:00
2019-10-23 02:09:45 -05:00
const int nw = wells_ecl_ . size ( ) ;
2018-08-16 04:51:36 -05:00
if ( nw > 0 ) {
2018-11-12 07:57:13 -06:00
const auto phaseUsage = phaseUsageFromDeck ( eclState ( ) ) ;
const size_t numCells = Opm : : UgGridHelpers : : numCells ( grid ( ) ) ;
2019-10-23 02:09:45 -05:00
const bool handle_ms_well = ( param_ . use_multisegment_well_ & & anyMSWellOpenLocal ( ) ) ;
2019-12-12 02:22:37 -06:00
well_state_ . resize ( wells_ecl_ , schedule ( ) , handle_ms_well , numCells , phaseUsage , well_perf_data_ , summaryState , globalNumWells ) ; // Resize for restart step
2019-06-25 14:53:37 -05:00
wellsToState ( restartValues . wells , phaseUsage , handle_ms_well , well_state_ ) ;
2018-08-16 04:51:36 -05:00
}
2019-08-07 07:13:11 -05:00
// for ecl compatible restart the current controls are not written
const auto & ioCfg = eclState ( ) . getIOConfig ( ) ;
2019-12-12 02:22:37 -06:00
const auto ecl_compatible_rst = ioCfg . getEclCompatibleRST ( ) ;
2019-09-30 08:22:31 -05:00
if ( true | | ecl_compatible_rst ) { // always set the control from the schedule
2019-08-07 07:13:11 -05:00
for ( int w = 0 ; w < nw ; + + w ) {
2019-10-23 02:09:45 -05:00
const auto & well = wells_ecl_ [ w ] ;
2019-08-07 07:13:11 -05:00
if ( well . isProducer ( ) ) {
const auto controls = well . productionControls ( summaryState ) ;
well_state_ . currentProductionControls ( ) [ w ] = controls . cmode ;
}
else {
const auto controls = well . injectionControls ( summaryState ) ;
well_state_ . currentInjectionControls ( ) [ w ] = controls . cmode ;
}
}
}
previous_well_state_ = well_state_ ;
2018-08-16 04:51:36 -05:00
initial_step_ = false ;
}
2018-11-17 16:36:31 -06:00
2019-10-23 02:09:45 -05:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
initializeWellPerfData ( )
{
const auto & grid = ebosSimulator_ . vanguard ( ) . grid ( ) ;
const auto & cartDims = Opm : : UgGridHelpers : : cartDims ( grid ) ;
well_perf_data_ . resize ( wells_ecl_ . size ( ) ) ;
first_perf_index_ . clear ( ) ;
first_perf_index_ . resize ( wells_ecl_ . size ( ) + 1 , 0 ) ;
int well_index = 0 ;
for ( const auto & well : wells_ecl_ ) {
well_perf_data_ [ well_index ] . clear ( ) ;
well_perf_data_ [ well_index ] . reserve ( well . getConnections ( ) . size ( ) ) ;
for ( const auto & completion : well . getConnections ( ) ) {
if ( completion . state ( ) = = Connection : : State : : OPEN ) {
const int i = completion . getI ( ) ;
const int j = completion . getJ ( ) ;
const int k = completion . getK ( ) ;
const int cart_grid_indx = i + cartDims [ 0 ] * ( j + cartDims [ 1 ] * k ) ;
const int active_index = cartesian_to_compressed_ [ cart_grid_indx ] ;
if ( active_index < 0 ) {
const std : : string msg
= ( " Cell with i,j,k indices " + std : : to_string ( i ) + " " + std : : to_string ( j ) + " "
+ std : : to_string ( k ) + " not found in grid (well = " + well . name ( ) + " ). " ) ;
OPM_THROW ( std : : runtime_error , msg ) ;
} else {
PerforationData pd ;
pd . cell_index = active_index ;
pd . connection_transmissibility_factor = completion . CF ( ) * completion . wellPi ( ) ;
pd . satnum_id = completion . satTableId ( ) ;
well_perf_data_ [ well_index ] . push_back ( pd ) ;
}
} else {
if ( completion . state ( ) ! = Connection : : State : : SHUT ) {
OPM_THROW ( std : : runtime_error ,
" Completion state: " < < Connection : : State2String ( completion . state ( ) ) < < " not handled " ) ;
}
}
}
first_perf_index_ [ well_index + 1 ] = first_perf_index_ [ well_index ] + well_perf_data_ [ well_index ] . size ( ) ;
+ + well_index ;
}
}
2017-06-15 10:19:49 -05:00
template < typename TypeTag >
2017-09-26 03:52:05 -05:00
std : : vector < typename BlackoilWellModel < TypeTag > : : WellInterfacePtr >
BlackoilWellModel < TypeTag > : :
2019-10-23 02:09:45 -05:00
createWellContainer ( const int time_step )
2017-06-15 10:19:49 -05:00
{
2017-08-21 03:23:42 -05:00
std : : vector < WellInterfacePtr > well_container ;
2019-12-13 04:08:36 -06:00
Opm : : DeferredLogger local_deferredLogger ;
2019-11-01 09:11:21 -05:00
const int nw = numLocalWells ( ) ;
2017-06-15 10:19:49 -05:00
2017-08-21 03:23:42 -05:00
if ( nw > 0 ) {
well_container . reserve ( nw ) ;
2017-06-15 10:19:49 -05:00
for ( int w = 0 ; w < nw ; + + w ) {
2019-10-23 02:09:45 -05:00
const Well & well_ecl = wells_ecl_ [ w ] ;
const std : : string & well_name = well_ecl . name ( ) ;
2017-06-15 10:19:49 -05:00
2019-07-31 09:15:41 -05:00
// A new WCON keywords can re-open a well that was closed/shut due to Physical limit
if ( wellTestState_ . hasWellClosed ( well_name ) ) {
// TODO: more checking here, to make sure this standard more specific and complete
// maybe there is some WCON keywords will not open the well
if ( well_state_ . effectiveEventsOccurred ( w ) ) {
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.
well_state_ . setEffectiveEventsOccurred ( w , false ) ;
} else {
wellTestState_ . openWell ( well_name ) ;
2018-12-14 03:04:59 -06:00
}
2018-11-17 16:36:31 -06:00
}
2019-07-31 09:15:41 -05:00
}
2018-11-17 16:30:27 -06:00
2019-07-31 09:15:41 -05:00
// TODO: should we do this for all kinds of closing reasons?
// something like wellTestState_.hasWell(well_name)?
2019-08-07 07:13:11 -05:00
bool wellIsStopped = false ;
2019-07-31 09:15:41 -05:00
if ( wellTestState_ . hasWellClosed ( well_name , WellTestConfig : : Reason : : ECONOMIC ) | |
wellTestState_ . hasWellClosed ( well_name , WellTestConfig : : Reason : : PHYSICAL ) ) {
if ( well_ecl . getAutomaticShutIn ( ) ) {
// shut wells are not added to the well container
2019-12-03 09:29:20 -06:00
well_state_ . shutWell ( w ) ;
2019-07-31 09:15:41 -05:00
continue ;
} else {
2019-08-07 07:13:11 -05:00
// stopped wells are added to the container but marked as stopped
2019-10-03 09:44:44 -05:00
well_state_ . thp ( ) [ w ] = 0. ;
2019-08-07 07:13:11 -05:00
wellIsStopped = true ;
2018-06-06 08:17:59 -05:00
}
}
2019-12-06 06:12:36 -06:00
// Due to ACTIONX the well might have been closed 'behind our back'.
const auto well_status = schedule ( ) . getWell ( well_name , time_step ) . getStatus ( ) ;
if ( well_status = = Well : : Status : : SHUT ) {
well_state_ . shutWell ( w ) ;
continue ;
}
2019-12-13 04:08:36 -06: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 ( ) ;
auto prod_controls = well_ecl . productionControls ( summaryState ) ;
bool zero_rate_control = false ;
switch ( prod_controls . cmode ) {
case Well : : ProducerCMode : : ORAT :
zero_rate_control = ( prod_controls . oil_rate = = 0.0 ) ;
break ;
case Well : : ProducerCMode : : WRAT :
zero_rate_control = ( prod_controls . water_rate = = 0.0 ) ;
break ;
case Well : : ProducerCMode : : GRAT :
zero_rate_control = ( prod_controls . gas_rate = = 0.0 ) ;
break ;
case Well : : ProducerCMode : : LRAT :
zero_rate_control = ( prod_controls . liquid_rate = = 0.0 ) ;
break ;
case Well : : ProducerCMode : : RESV :
zero_rate_control = ( prod_controls . resv_rate = = 0.0 ) ;
break ;
default :
// Might still have zero rate controls, but is pressure controlled.
zero_rate_control = false ;
}
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 ( ) ) ;
well_state_ . shutWell ( w ) ;
continue ;
}
}
2019-12-06 06:12:36 -06:00
if ( well_status = = Well : : Status : : STOP ) {
well_state_ . thp ( ) [ w ] = 0. ;
wellIsStopped = true ;
}
2017-11-23 01:37:30 -06:00
// Use the pvtRegionIdx from the top cell
2019-10-23 02:09:45 -05:00
const int well_cell_top = well_perf_data_ [ w ] [ 0 ] . cell_index ;
2017-11-22 07:39:42 -06:00
const int pvtreg = pvt_region_idx_ [ well_cell_top ] ;
2019-10-23 02:09:45 -05:00
if ( ! well_ecl . isMultiSegment ( ) | | ! param_ . use_multisegment_well_ ) {
well_container . emplace_back ( new StandardWell < TypeTag > ( well_ecl ,
time_step ,
param_ ,
* rateConverter_ ,
pvtreg ,
numComponents ( ) ,
numPhases ( ) ,
w ,
first_perf_index_ [ w ] ,
well_perf_data_ [ w ] ) ) ;
2017-09-01 10:37:51 -05:00
} else {
2019-10-23 02:09:45 -05:00
well_container . emplace_back ( new MultisegmentWell < TypeTag > ( well_ecl ,
time_step ,
param_ ,
* rateConverter_ ,
pvtreg ,
numComponents ( ) ,
numPhases ( ) ,
w ,
first_perf_index_ [ w ] ,
well_perf_data_ [ w ] ) ) ;
2017-09-01 10:37:51 -05:00
}
2019-08-07 07:13:11 -05:00
if ( wellIsStopped )
well_container . back ( ) - > stopWell ( ) ;
2017-06-15 10:19:49 -05:00
}
}
2019-02-07 07:43:17 -06:00
2019-12-13 04:08:36 -06:00
// Collect log messages and print.
Opm : : DeferredLogger global_deferredLogger = gatherDeferredLogger ( local_deferredLogger ) ;
if ( terminal_output_ ) {
global_deferredLogger . logMessages ( ) ;
}
2017-08-21 03:23:42 -05:00
return well_container ;
2017-06-15 10:19:49 -05:00
}
2018-10-31 08:56:56 -05:00
template < typename TypeTag >
typename BlackoilWellModel < TypeTag > : : WellInterfacePtr
BlackoilWellModel < TypeTag > : :
createWellForWellTest ( const std : : string & well_name ,
2019-02-07 07:43:17 -06:00
const int report_step ,
Opm : : DeferredLogger & deferred_logger ) const
2018-10-31 08:56:56 -05: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 05:51:25 -05:00
if ( well_name = = wells_ecl_ [ index_well_ecl ] . name ( ) ) {
2018-10-31 08:56:56 -05:00
break ;
}
}
// It should be able to find in wells_ecl.
if ( index_well_ecl = = nw_wells_ecl ) {
2019-02-07 07:43:17 -06:00
OPM_DEFLOG_THROW ( std : : logic_error , " Could not find well " < < well_name < < " in wells_ecl " , deferred_logger ) ;
2018-10-31 08:56:56 -05:00
}
2019-11-13 16:16:11 -06:00
const Well & well_ecl = wells_ecl_ [ index_well_ecl ] ;
2018-10-31 08:56:56 -05:00
// Use the pvtRegionIdx from the top cell
2019-10-23 02:09:45 -05:00
const int well_cell_top = well_perf_data_ [ index_well_ecl ] [ 0 ] . cell_index ;
2018-10-31 08:56:56 -05:00
const int pvtreg = pvt_region_idx_ [ well_cell_top ] ;
2019-10-23 02:09:45 -05:00
if ( ! well_ecl . isMultiSegment ( ) | | ! param_ . use_multisegment_well_ ) {
return WellInterfacePtr ( new StandardWell < TypeTag > ( well_ecl ,
report_step ,
param_ ,
* rateConverter_ ,
pvtreg ,
numComponents ( ) ,
numPhases ( ) ,
index_well_ecl ,
first_perf_index_ [ index_well_ecl ] ,
well_perf_data_ [ index_well_ecl ] ) ) ;
2018-10-31 08:56:56 -05:00
} else {
2019-10-23 02:09:45 -05:00
return WellInterfacePtr ( new MultisegmentWell < TypeTag > ( well_ecl ,
report_step ,
param_ ,
* rateConverter_ ,
pvtreg ,
numComponents ( ) ,
numPhases ( ) ,
index_well_ecl ,
first_perf_index_ [ index_well_ecl ] ,
well_perf_data_ [ index_well_ecl ] ) ) ;
2018-10-31 08:56:56 -05:00
}
}
2017-05-03 06:34:15 -05:00
template < typename TypeTag >
2017-11-08 06:57:36 -06:00
void
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2017-11-08 06:57:36 -06:00
assemble ( const int iterationIdx ,
2018-06-29 02:12:14 -05:00
const double dt )
2017-02-13 09:45:06 -06:00
{
2017-11-08 06:57:36 -06:00
last_report_ = SimulatorReport ( ) ;
2017-11-08 08:48:30 -06:00
if ( ! wellsActive ( ) ) {
return ;
}
2019-02-03 01:13:11 -06:00
Opm : : DeferredLogger local_deferredLogger ;
2017-11-08 06:57:36 -06:00
updatePerforationIntensiveQuantities ( ) ;
2017-02-13 09:45:06 -06:00
2019-02-07 07:43:17 -06:00
int exception_thrown = 0 ;
try {
if ( iterationIdx = = 0 ) {
calculateExplicitQuantities ( local_deferredLogger ) ;
2019-05-24 09:45:27 -05:00
prepareTimeStep ( local_deferredLogger ) ;
2019-02-07 07:43:17 -06:00
}
2020-01-29 01:41:41 -06:00
// check the current group control in the beginning of an episode for the first two iterations. The first itertion is needed for changes in group/well controls and closing of wells etc.
2020-01-16 02:52:03 -06:00
// a second check is needed for REIN and VREP controls since they depend on results from other wells.
// This check can probably be made more sofisticated, but this simple rule seems to work
2020-01-29 01:41:41 -06:00
bool checkCurrentGroupControls = ( report_step_starts_ & & iterationIdx < 2 ) ;
2020-01-16 02:52:03 -06:00
updateWellControls ( local_deferredLogger , /*allow for switching to group controls*/ true , checkCurrentGroupControls ) ;
2019-11-06 09:16:19 -06:00
2019-02-07 07:43:17 -06:00
// Set the well primary variables based on the value of well solutions
initPrimaryVariablesEvaluation ( ) ;
2017-02-13 09:45:06 -06:00
2019-05-24 09:45:27 -05:00
std : : vector < Scalar > B_avg ( numComponents ( ) , Scalar ( ) ) ;
computeAverageFormationFactor ( B_avg ) ;
2019-02-07 07:43:17 -06:00
if ( param_ . solve_welleq_initially_ & & iterationIdx = = 0 ) {
// solve the well equations as a pre-processing step
2019-02-27 07:47:31 -06:00
last_report_ = solveWellEq ( B_avg , dt , local_deferredLogger ) ;
2018-06-06 08:17:59 -05:00
2019-02-07 07:43:17 -06:00
if ( initial_step_ ) {
// update the explicit quantities to get the initial fluid distribution in the well correct.
calculateExplicitQuantities ( local_deferredLogger ) ;
2019-05-24 09:45:27 -05:00
prepareTimeStep ( local_deferredLogger ) ;
2019-02-27 07:47:31 -06:00
last_report_ = solveWellEq ( B_avg , dt , local_deferredLogger ) ;
2019-02-07 07:43:17 -06:00
initial_step_ = false ;
}
// TODO: should we update the explicit related here again, or even prepareTimeStep().
// basically, this is a more updated state from the solveWellEq based on fixed
// reservoir state, will tihs be a better place to inialize the explict information?
2018-03-23 06:56:19 -05:00
}
2019-02-03 01:13:11 -06:00
2019-04-23 06:30:12 -05:00
assembleWellEq ( B_avg , dt , local_deferredLogger ) ;
2019-04-12 03:43:30 -05:00
2019-02-07 07:43:17 -06:00
} catch ( std : : exception & e ) {
exception_thrown = 1 ;
2019-02-03 01:13:11 -06:00
}
2019-02-07 07:43:17 -06:00
logAndCheckForExceptionsAndThrow ( local_deferredLogger , exception_thrown , " assemble() failed. " , terminal_output_ ) ;
2017-02-13 09:45:06 -06:00
2017-11-08 06:57:36 -06:00
last_report_ . converged = true ;
2017-02-13 09:45:06 -06:00
}
2017-05-03 06:34:15 -05:00
template < typename TypeTag >
2017-02-13 09:45:06 -06:00
void
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2019-03-04 04:24:52 -06:00
assembleWellEq ( const std : : vector < Scalar > & B_avg , const double dt , Opm : : DeferredLogger & deferred_logger )
2017-02-13 09:45:06 -06:00
{
2018-06-06 08:17:59 -05:00
for ( auto & well : well_container_ ) {
2019-03-04 04:24:52 -06:00
well - > assembleWellEq ( ebosSimulator_ , B_avg , dt , well_state_ , deferred_logger ) ;
2017-07-21 07:21:17 -05:00
}
2017-02-13 10:07:34 -06:00
}
2018-11-05 08:54:48 -06: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 10:07:34 -06:00
2017-07-21 07:21:17 -05:00
// Ax = A x - C D^-1 B x
2017-05-03 06:34:15 -05:00
template < typename TypeTag >
2017-02-13 10:07:34 -06:00
void
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2017-06-07 07:23:43 -05:00
apply ( const BVector & x , BVector & Ax ) const
2017-02-13 10:07:34 -06:00
{
2017-07-21 08:30:34 -05:00
// TODO: do we still need localWellsActive()?
2018-02-26 08:47:25 -06:00
if ( ! localWellsActive ( ) ) {
2017-02-13 10:07:34 -06:00
return ;
}
2017-07-21 07:21:17 -05:00
for ( auto & well : well_container_ ) {
2018-03-02 13:47:04 -06:00
well - > apply ( x , Ax ) ;
2017-07-21 07:21:17 -05:00
}
2017-02-13 10:07:34 -06:00
}
2017-07-21 07:21:17 -05:00
// Ax = Ax - alpha * C D^-1 B x
2017-05-03 06:34:15 -05:00
template < typename TypeTag >
2017-02-13 10:07:34 -06:00
void
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2017-06-07 07:23:43 -05:00
applyScaleAdd ( const Scalar alpha , const BVector & x , BVector & Ax ) const
2017-02-13 10:07:34 -06:00
{
2018-02-26 08:47:25 -06:00
if ( ! localWellsActive ( ) ) {
2017-02-13 10:07:34 -06:00
return ;
}
if ( scaleAddRes_ . size ( ) ! = Ax . size ( ) ) {
scaleAddRes_ . resize ( Ax . size ( ) ) ;
}
scaleAddRes_ = 0.0 ;
2017-07-21 07:21:17 -05:00
// scaleAddRes_ = - C D^-1 B x
2017-02-13 10:07:34 -06:00
apply ( x , scaleAddRes_ ) ;
2017-07-21 07:21:17 -05:00
// Ax = Ax + alpha * scaleAddRes_
2017-02-13 10:07:34 -06:00
Ax . axpy ( alpha , scaleAddRes_ ) ;
}
2017-05-03 06:34:15 -05:00
template < typename TypeTag >
2017-02-13 10:07:34 -06:00
void
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2017-11-08 06:57:36 -06:00
recoverWellSolutionAndUpdateWellState ( const BVector & x )
2017-02-13 10:07:34 -06:00
{
2019-02-07 07:43:17 -06:00
Opm : : DeferredLogger local_deferredLogger ;
2017-11-08 06:57:36 -06:00
2019-02-07 07:43:17 -06:00
int exception_thrown = 0 ;
try {
if ( localWellsActive ( ) ) {
for ( auto & well : well_container_ ) {
well - > recoverWellSolutionAndUpdateWellState ( x , well_state_ , local_deferredLogger ) ;
}
}
} catch ( std : : exception & e ) {
exception_thrown = 1 ;
2017-02-13 10:07:34 -06:00
}
2019-02-07 07:43:17 -06:00
logAndCheckForExceptionsAndThrow ( local_deferredLogger , exception_thrown , " recoverWellSolutionAndUpdateWellState() failed. " , terminal_output_ ) ;
2017-02-13 10:07:34 -06:00
}
2017-05-03 06:34:15 -05:00
template < typename TypeTag >
2017-02-13 10:07:34 -06:00
bool
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2017-02-13 10:07:34 -06:00
wellsActive ( ) const
{
return wells_active_ ;
}
2017-05-03 06:34:15 -05:00
template < typename TypeTag >
2017-02-13 10:07:34 -06:00
void
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2017-02-13 10:07:34 -06:00
setWellsActive ( const bool wells_active )
{
wells_active_ = wells_active ;
}
2017-05-03 06:34:15 -05:00
template < typename TypeTag >
2017-02-13 10:07:34 -06:00
bool
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2017-02-13 10:07:34 -06:00
localWellsActive ( ) const
{
2019-11-01 09:11:21 -05:00
return numLocalWells ( ) > 0 ;
2017-02-13 10:07:34 -06:00
}
2017-05-03 06:34:15 -05:00
template < typename TypeTag >
2017-02-13 10:07:34 -06:00
void
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2017-08-21 08:41:25 -05:00
initPrimaryVariablesEvaluation ( ) const
2017-02-13 10:07:34 -06:00
{
2017-07-25 03:15:27 -05:00
for ( auto & well : well_container_ ) {
2017-08-21 08:41:25 -05:00
well - > initPrimaryVariablesEvaluation ( ) ;
2017-06-19 05:43:08 -05:00
}
2017-02-13 10:07:34 -06:00
}
2017-02-14 08:06:57 -06:00
2017-05-03 06:34:15 -05:00
template < typename TypeTag >
2017-02-14 04:34:03 -06:00
SimulatorReport
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2019-03-04 04:24:52 -06:00
solveWellEq ( const std : : vector < Scalar > & B_avg , const double dt , Opm : : DeferredLogger & deferred_logger )
2017-02-14 04:34:03 -06:00
{
2017-11-08 06:57:36 -06:00
WellState well_state0 = well_state_ ;
2017-02-14 04:34:03 -06:00
2017-10-04 06:09:49 -05:00
const int max_iter = param_ . max_welleq_iter_ ;
2017-02-14 04:34:03 -06:00
int it = 0 ;
bool converged ;
2019-02-07 07:43:17 -06:00
int exception_thrown = 0 ;
2017-02-14 04:34:03 -06:00
do {
2019-02-07 07:43:17 -06:00
try {
2019-03-04 04:24:52 -06:00
assembleWellEq ( B_avg , dt , deferred_logger ) ;
2019-02-07 07:43:17 -06:00
} catch ( std : : exception & e ) {
exception_thrown = 1 ;
}
// We need to check on all processes, as getWellConvergence() below communicates on all processes.
logAndCheckForExceptionsAndThrow ( deferred_logger , exception_thrown , " solveWellEq() failed. " , terminal_output_ ) ;
2017-07-21 09:01:32 -05:00
2018-11-13 07:02:55 -06:00
const auto report = getWellConvergence ( B_avg ) ;
converged = report . converged ( ) ;
2017-02-14 04:34:03 -06:00
if ( converged ) {
break ;
}
2019-02-07 07:43:17 -06:00
try {
if ( localWellsActive ( ) )
{
for ( auto & well : well_container_ ) {
well - > solveEqAndUpdateWellState ( well_state_ , deferred_logger ) ;
}
2017-06-28 06:46:01 -05:00
}
2019-02-07 07:43:17 -06:00
// updateWellControls uses communication
// Therefore the following is executed if there
// are active wells anywhere in the global domain.
if ( wellsActive ( ) )
{
2020-01-16 02:52:03 -06:00
updateWellControls ( deferred_logger , /*don't switch group controls*/ false , /*don't check current group controls*/ false ) ;
2019-02-07 07:43:17 -06:00
initPrimaryVariablesEvaluation ( ) ;
}
} catch ( std : : exception & e ) {
exception_thrown = 1 ;
2017-04-12 10:37:34 -05:00
}
2019-02-07 07:43:17 -06:00
logAndCheckForExceptionsAndThrow ( deferred_logger , exception_thrown , " solveWellEq() failed. " , terminal_output_ ) ;
+ + it ;
2017-10-04 06:09:49 -05:00
} while ( it < max_iter ) ;
2017-02-14 04:34:03 -06:00
2019-02-07 07:43:17 -06:00
try {
if ( converged ) {
if ( terminal_output_ ) {
deferred_logger . debug ( " Well equation solution gets converged with " + std : : to_string ( it ) + " iterations " ) ;
}
} else {
if ( terminal_output_ ) {
deferred_logger . debug ( " Well equation solution failed in getting converged with " + std : : to_string ( it ) + " iterations " ) ;
}
well_state_ = well_state0 ;
updatePrimaryVariables ( deferred_logger ) ;
2017-03-08 07:02:00 -06:00
}
2019-02-07 07:43:17 -06:00
} catch ( std : : exception & e ) {
exception_thrown = 1 ;
2017-02-14 04:34:03 -06:00
}
2019-02-07 07:43:17 -06:00
logAndCheckForExceptionsAndThrow ( deferred_logger , exception_thrown , " solveWellEq() failed. " , terminal_output_ ) ;
2017-02-14 04:34:03 -06:00
SimulatorReport report ;
report . converged = converged ;
report . total_well_iterations = it ;
return report ;
}
2017-05-03 06:34:15 -05:00
template < typename TypeTag >
2018-11-13 07:02:55 -06:00
ConvergenceReport
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2017-11-08 06:57:36 -06:00
getWellConvergence ( const std : : vector < Scalar > & B_avg ) const
2017-02-14 04:34:03 -06:00
{
2019-02-07 07:43:17 -06:00
Opm : : DeferredLogger local_deferredLogger ;
2018-11-13 07:02:55 -06:00
// Get global (from all processes) convergence report.
ConvergenceReport local_report ;
2017-06-28 04:15:04 -05:00
for ( const auto & well : well_container_ ) {
2018-11-17 16:14:51 -06:00
if ( well - > isOperable ( ) ) {
2019-08-07 07:13:11 -05:00
local_report + = well - > getWellConvergence ( well_state_ , B_avg , local_deferredLogger ) ;
2018-11-17 16:14:51 -06:00
}
2017-08-22 07:49:30 -05:00
}
2019-02-07 07:43:17 -06:00
Opm : : DeferredLogger global_deferredLogger = gatherDeferredLogger ( local_deferredLogger ) ;
if ( terminal_output_ ) {
global_deferredLogger . logMessages ( ) ;
}
2018-11-13 07:02:55 -06:00
ConvergenceReport report = gatherConvergenceReport ( local_report ) ;
2017-08-22 07:49:30 -05:00
2018-11-13 07:02:55 -06:00
// Log debug messages for NaN or too large residuals.
2019-02-03 01:13:11 -06: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 06:12:06 -05:00
}
}
2018-11-13 07:02:55 -06:00
return report ;
2017-02-14 04:34:03 -06:00
}
2017-05-03 06:34:15 -05:00
template < typename TypeTag >
2017-02-14 04:34:03 -06:00
void
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2019-02-07 07:43:17 -06:00
calculateExplicitQuantities ( Opm : : DeferredLogger & deferred_logger ) const
2017-02-14 04:34:03 -06:00
{
2018-11-17 16:14:51 -06:00
// TODO: checking isOperable() ?
for ( auto & well : well_container_ ) {
2019-02-07 07:43:17 -06:00
well - > calculateExplicitQuantities ( ebosSimulator_ , well_state_ , deferred_logger ) ;
2018-11-17 16:14:51 -06:00
}
2017-02-14 04:34:03 -06:00
}
2017-05-03 06:34:15 -05:00
template < typename TypeTag >
2017-02-14 04:34:03 -06:00
void
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2020-01-16 02:52:03 -06:00
updateWellControls ( Opm : : DeferredLogger & deferred_logger , const bool checkGroupControl , const bool checkCurrentGroupControl )
2017-02-14 04:34:03 -06:00
{
2019-01-21 01:26:28 -06: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 10:37:34 -05:00
if ( ! wellsActive ( ) ) return ;
2017-02-14 04:34:03 -06:00
2019-11-22 05:29:47 -06:00
const int reportStepIdx = ebosSimulator_ . episodeIndex ( ) ;
const Group & fieldGroup = schedule ( ) . getGroup ( " FIELD " , reportStepIdx ) ;
2019-08-07 07:13:11 -05:00
// update group controls
if ( checkGroupControl ) {
2020-01-16 02:52:03 -06:00
checkGroupConstraints ( fieldGroup , checkCurrentGroupControl , deferred_logger ) ;
2019-08-07 07:13:11 -05:00
}
2017-06-28 04:15:04 -05:00
for ( const auto & well : well_container_ ) {
2019-05-24 09:45:27 -05:00
well - > updateWellControl ( ebosSimulator_ , well_state_ , deferred_logger ) ;
2019-01-18 07:04:30 -06:00
}
2019-11-22 05:29:47 -06:00
2019-12-17 01:49:47 -06:00
const int nupcol = schedule ( ) . getNupcol ( reportStepIdx ) ;
const int iterationIdx = ebosSimulator_ . model ( ) . newtonMethod ( ) . numIterations ( ) ;
if ( iterationIdx < nupcol ) {
well_state_nupcol_ = well_state_ ;
}
2019-11-22 05:29:47 -06:00
// the group target reduction rates needs to be update since wells may have swicthed to/from GRUP control
// Currently the group targer reduction does not honor NUPCOL
2019-12-12 02:22:37 -06:00
std : : vector < double > groupTargetReduction ( numPhases ( ) , 0.0 ) ;
2020-02-11 02:03:40 -06:00
wellGroupHelpers : : updateGroupTargetReduction ( fieldGroup , schedule ( ) , reportStepIdx , /*isInjector*/ false , phase_usage_ , well_state_nupcol_ , well_state_ , groupTargetReduction ) ;
2019-12-12 02:22:37 -06:00
std : : vector < double > groupTargetReductionInj ( numPhases ( ) , 0.0 ) ;
2020-02-11 02:03:40 -06:00
wellGroupHelpers : : updateGroupTargetReduction ( fieldGroup , schedule ( ) , reportStepIdx , /*isInjector*/ true , phase_usage_ , well_state_nupcol_ , well_state_ , groupTargetReductionInj ) ;
2019-12-12 02:22:37 -06:00
const auto & comm = ebosSimulator_ . vanguard ( ) . grid ( ) . comm ( ) ;
well_state_ . updateGlobalIsGrup ( schedule ( ) , reportStepIdx , comm ) ;
2019-12-16 06:48:48 -06:00
const double simulationTime = ebosSimulator_ . time ( ) ;
std : : vector < double > pot ( numPhases ( ) , 0.0 ) ;
2019-12-12 02:22:37 -06:00
wellGroupHelpers : : updateGuideRateForGroups ( fieldGroup , schedule ( ) , phase_usage_ , reportStepIdx , simulationTime , /*isInjector*/ false , well_state_ , comm , guideRate_ . get ( ) , pot ) ;
2019-12-16 06:48:48 -06:00
std : : vector < double > potInj ( numPhases ( ) , 0.0 ) ;
2019-12-12 02:22:37 -06:00
wellGroupHelpers : : updateGuideRateForGroups ( fieldGroup , schedule ( ) , phase_usage_ , reportStepIdx , simulationTime , /*isInjector*/ true , well_state_ , comm , guideRate_ . get ( ) , potInj ) ;
2019-12-17 01:49:47 -06:00
2019-12-12 02:22:37 -06:00
const auto & summaryState = ebosSimulator_ . vanguard ( ) . summaryState ( ) ;
2020-01-08 07:13:38 -06:00
wellGroupHelpers : : updateREINForGroups ( fieldGroup , schedule ( ) , reportStepIdx , phase_usage_ , summaryState , well_state_nupcol_ , well_state_ ) ;
wellGroupHelpers : : updateVREPForGroups ( fieldGroup , schedule ( ) , reportStepIdx , well_state_nupcol_ , well_state_ ) ;
2020-01-23 07:26:02 -06:00
wellGroupHelpers : : updateReservoirRatesInjectionGroups ( fieldGroup , schedule ( ) , reportStepIdx , well_state_nupcol_ , well_state_ ) ;
well_state_ . communicateGroupRates ( comm ) ;
2019-12-17 01:49:47 -06:00
// compute wsolvent fraction for REIN wells
updateWsolvent ( fieldGroup , schedule ( ) , reportStepIdx , well_state_nupcol_ ) ;
2017-02-14 04:34:03 -06:00
}
2017-02-14 06:39:53 -06:00
2017-05-03 06:34:15 -05:00
template < typename TypeTag >
2017-02-14 06:39:53 -06:00
void
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2018-06-28 06:47:10 -05:00
updateWellTestState ( const double & simulationTime , WellTestState & wellTestState ) const
2017-02-14 06:39:53 -06:00
{
2019-02-03 01:13:11 -06:00
Opm : : DeferredLogger local_deferredLogger ;
2017-07-26 04:01:26 -05:00
for ( const auto & well : well_container_ ) {
2019-02-03 01:13:11 -06:00
well - > updateWellTestState ( well_state_ , simulationTime , /*writeMessageToOPMLog=*/ true , wellTestState , local_deferredLogger ) ;
}
Opm : : DeferredLogger global_deferredLogger = gatherDeferredLogger ( local_deferredLogger ) ;
if ( terminal_output_ ) {
global_deferredLogger . logMessages ( ) ;
2017-07-26 04:01:26 -05:00
}
2017-02-14 06:39:53 -06:00
}
2017-05-03 06:34:15 -05:00
template < typename TypeTag >
2017-02-14 06:39:53 -06:00
void
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2019-08-07 07:13:11 -05:00
computeWellPotentials ( std : : vector < double > & well_potentials , const int reportStepIdx , Opm : : DeferredLogger & deferred_logger )
2017-02-14 06:39:53 -06:00
{
// number of wells and phases
2019-11-01 09:11:21 -05:00
const int nw = numLocalWells ( ) ;
2017-11-08 06:57:36 -06:00
const int np = numPhases ( ) ;
2017-03-23 05:36:49 -05:00
well_potentials . resize ( nw * np , 0.0 ) ;
2019-04-23 06:30:12 -05:00
auto well_state_copy = well_state_ ;
// average B factors are required for the convergence checking of well equations
// Note: this must be done on all processes, even those with
// no wells needing testing, otherwise we will have locking.
std : : vector < Scalar > B_avg ( numComponents ( ) , Scalar ( ) ) ;
computeAverageFormationFactor ( B_avg ) ;
2018-11-16 09:03:23 -06:00
const Opm : : SummaryConfig & summaryConfig = ebosSimulator_ . vanguard ( ) . summaryConfig ( ) ;
2019-08-05 05:58:14 -05:00
const bool write_restart_file = ebosSimulator_ . vanguard ( ) . eclState ( ) . getRestartConfig ( ) . getWriteRestartFile ( reportStepIdx ) ;
2019-02-07 07:43:17 -06:00
int exception_thrown = 0 ;
try {
2019-07-31 08:39:56 -05:00
for ( const auto & well : well_container_ ) {
2019-08-05 05:58:14 -05:00
const bool needed_for_summary = ( ( summaryConfig . hasSummaryKey ( " WWPI: " + well - > name ( ) ) | |
summaryConfig . hasSummaryKey ( " WOPI: " + well - > name ( ) ) | |
2019-10-23 02:09:45 -05:00
summaryConfig . hasSummaryKey ( " WGPI: " + well - > name ( ) ) ) & & well - > isInjector ( ) ) | |
2019-08-05 05:58:14 -05:00
( ( summaryConfig . hasSummaryKey ( " WWPP: " + well - > name ( ) ) | |
summaryConfig . hasSummaryKey ( " WOPP: " + well - > name ( ) ) | |
2019-10-23 02:09:45 -05:00
summaryConfig . hasSummaryKey ( " WGPP: " + well - > name ( ) ) ) & & well - > isProducer ( ) ) ;
2019-08-05 05:58:14 -05:00
2019-11-13 16:16:11 -06:00
const Well & eclWell = well - > wellEcl ( ) ;
bool needPotentialsForGuideRate = eclWell . getGuideRatePhase ( ) = = Well : : GuideRateTarget : : UNDEFINED ;
2019-08-07 07:13:11 -05:00
if ( write_restart_file | | needed_for_summary | | needPotentialsForGuideRate )
2019-02-07 07:43:17 -06:00
{
std : : vector < double > potentials ;
2019-04-23 06:30:12 -05:00
well - > computeWellPotentials ( ebosSimulator_ , B_avg , well_state_copy , potentials , deferred_logger ) ;
2019-02-07 07:43:17 -06: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 ] ) ;
}
2018-11-07 07:53:43 -06:00
}
2019-02-07 07:43:17 -06:00
} // end of for (int w = 0; w < nw; ++w)
} catch ( std : : exception & e ) {
exception_thrown = 1 ;
}
logAndCheckForExceptionsAndThrow ( deferred_logger , exception_thrown , " computeWellPotentials() failed. " , terminal_output_ ) ;
2018-11-07 07:53:43 -06:00
// Store it in the well state
well_state_ . wellPotentials ( ) = well_potentials ;
2017-02-14 08:06:57 -06:00
}
2017-05-03 06:34:15 -05:00
template < typename TypeTag >
2017-03-16 10:39:05 -05:00
void
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2019-05-24 09:45:27 -05:00
prepareTimeStep ( Opm : : DeferredLogger & deferred_logger )
2017-03-16 10:39:05 -05:00
{
2019-02-07 07:43:17 -06:00
int exception_thrown = 0 ;
try {
for ( const auto & well : well_container_ ) {
2019-05-24 09:45:27 -05:00
well - > checkWellOperability ( ebosSimulator_ , well_state_ , deferred_logger ) ;
2017-09-04 06:54:41 -05:00
}
2019-02-07 07:43:17 -06:00
// since the controls are all updated, we should update well_state accordingly
for ( const auto & well : well_container_ ) {
const int w = well - > indexOfWell ( ) ;
if ( ! well - > isOperable ( ) ) continue ;
2018-06-06 08:17:59 -05:00
2019-02-07 07:43:17 -06:00
if ( well_state_ . effectiveEventsOccurred ( w ) ) {
2019-08-07 07:13:11 -05:00
well - > updateWellStateWithTarget ( ebosSimulator_ , well_state_ , deferred_logger ) ;
2019-02-07 07:43:17 -06: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
// TODO: if we can know whether this is the first time step within the report step,
// we do not need to set it to false
// TODO: we should do this at the end of the time step in case we will need it within
// this time step somewhere
if ( well_state_ . effectiveEventsOccurred ( w ) ) {
well_state_ . setEffectiveEventsOccurred ( w , false ) ;
}
} // end of for (const auto& well : well_container_)
updatePrimaryVariables ( deferred_logger ) ;
} catch ( std : : exception & e ) {
exception_thrown = 1 ;
}
logAndCheckForExceptionsAndThrow ( deferred_logger , exception_thrown , " prepareTimestep() failed. " , terminal_output_ ) ;
2017-09-04 06:54:41 -05:00
}
2017-11-08 08:48:30 -06:00
template < typename TypeTag >
const typename BlackoilWellModel < TypeTag > : : WellState &
BlackoilWellModel < TypeTag > : :
wellState ( ) const { return well_state_ ; }
2017-02-14 08:06:57 -06:00
2017-11-08 08:48:30 -06:00
template < typename TypeTag >
const typename BlackoilWellModel < TypeTag > : : WellState &
BlackoilWellModel < TypeTag > : :
wellState ( const WellState & well_state OPM_UNUSED ) const { return wellState ( ) ; }
2017-02-14 08:06:57 -06:00
2017-05-03 06:34:15 -05:00
template < typename TypeTag >
2017-02-14 08:06:57 -06:00
void
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2019-08-07 07:13:11 -05:00
calculateEfficiencyFactors ( const int reportStepIdx )
2017-02-14 08:06:57 -06:00
{
if ( ! localWellsActive ( ) ) {
return ;
}
2018-06-06 08:17:59 -05:00
for ( auto & well : well_container_ ) {
2019-11-13 16:16:11 -06:00
const Well & wellEcl = well - > wellEcl ( ) ;
2019-08-07 07:13:11 -05:00
double well_efficiency_factor = wellEcl . getEfficiencyFactor ( ) ;
2019-11-13 16:16:11 -06:00
wellGroupHelpers : : accumulateGroupEfficiencyFactor ( schedule ( ) . getGroup ( wellEcl . groupName ( ) , reportStepIdx ) , schedule ( ) , reportStepIdx , well_efficiency_factor ) ;
2018-06-06 08:17:59 -05:00
well - > setWellEfficiencyFactor ( well_efficiency_factor ) ;
2017-02-14 08:06:57 -06:00
}
}
2017-06-07 02:29:31 -05:00
template < typename TypeTag >
void
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2018-08-16 04:51:36 -05:00
setupCartesianToCompressed_ ( const int * global_cell , int number_of_cartesian_cells )
2017-06-07 02:29:31 -05:00
{
2018-08-16 04:51:36 -05:00
cartesian_to_compressed_ . resize ( number_of_cartesian_cells , - 1 ) ;
2017-06-07 02:29:31 -05:00
if ( global_cell ) {
2018-08-16 04:51:36 -05:00
for ( unsigned i = 0 ; i < number_of_cells_ ; + + i ) {
cartesian_to_compressed_ [ global_cell [ i ] ] = i ;
2017-06-07 02:29:31 -05:00
}
}
else {
2018-08-16 04:51:36 -05:00
for ( unsigned i = 0 ; i < number_of_cells_ ; + + i ) {
cartesian_to_compressed_ [ i ] = i ;
2017-06-07 02:29:31 -05:00
}
}
}
template < typename TypeTag >
void
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2019-02-07 07:43:17 -06:00
computeRepRadiusPerfLength ( const Grid & grid , Opm : : DeferredLogger & deferred_logger )
2017-06-07 02:29:31 -05:00
{
2017-07-31 09:42:26 -05:00
for ( const auto & well : well_container_ ) {
2019-02-07 07:43:17 -06:00
well - > computeRepRadiusPerfLength ( grid , cartesian_to_compressed_ , deferred_logger ) ;
2017-06-07 02:29:31 -05:00
}
}
2017-05-09 01:21:51 -05:00
2017-06-23 05:24:50 -05:00
template < typename TypeTag >
void
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2019-02-27 07:47:31 -06:00
computeAverageFormationFactor ( std : : vector < Scalar > & B_avg ) const
2017-06-23 05:24:50 -05:00
{
2018-02-01 09:27:42 -06:00
const auto & grid = ebosSimulator_ . vanguard ( ) . grid ( ) ;
2017-06-23 05:24:50 -05:00
const auto & gridView = grid . leafGridView ( ) ;
2017-11-08 06:57:36 -06:00
ElementContext elemCtx ( ebosSimulator_ ) ;
2017-06-23 05:24:50 -05: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 02:14:08 -06:00
for ( unsigned phaseIdx = 0 ; phaseIdx < FluidSystem : : numPhases ; + + phaseIdx )
2017-06-23 05:24:50 -05:00
{
2017-12-04 02:14:08 -06:00
if ( ! FluidSystem : : phaseIsActive ( phaseIdx ) ) {
continue ;
}
const unsigned compIdx = Indices : : canonicalToActiveComponentIndex ( FluidSystem : : solventComponentIndex ( phaseIdx ) ) ;
auto & B = B_avg [ compIdx ] ;
2017-06-23 05:24:50 -05:00
2017-12-04 02:14:08 -06:00
B + = 1 / fs . invB ( phaseIdx ) . value ( ) ;
2017-06-23 05:24:50 -05:00
}
if ( has_solvent_ ) {
2017-06-27 08:16:22 -05:00
auto & B = B_avg [ solventSaturationIdx ] ;
2017-06-23 05:24:50 -05:00
B + = 1 / intQuants . solventInverseFormationVolumeFactor ( ) . value ( ) ;
}
}
// compute global average
grid . comm ( ) . sum ( B_avg . data ( ) , B_avg . size ( ) ) ;
for ( auto & bval : B_avg )
{
bval / = global_nc_ ;
}
}
2017-08-08 03:44:10 -05:00
template < typename TypeTag >
void
2017-09-26 03:52:05 -05:00
BlackoilWellModel < TypeTag > : :
2019-02-07 07:43:17 -06:00
updatePrimaryVariables ( Opm : : DeferredLogger & deferred_logger )
2017-08-08 03:44:10 -05:00
{
for ( const auto & well : well_container_ ) {
2019-02-07 07:43:17 -06:00
well - > updatePrimaryVariables ( well_state_ , deferred_logger ) ;
2017-11-08 06:57:36 -06:00
}
}
2017-11-08 08:48:30 -06:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : : extractLegacyCellPvtRegionIndex_ ( )
{
2018-02-01 09:27:42 -06:00
const auto & grid = ebosSimulator_ . vanguard ( ) . grid ( ) ;
2017-11-08 08:48:30 -06: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 08:58:10 -05:00
if ( wellsActive ( ) & & numPhases ( ) < 3 ) {
2019-10-09 08:24:23 -05:00
return numPhases ( ) ;
2017-11-08 08:48:30 -06:00
}
int numComp = FluidSystem : : numComponents ;
if ( has_solvent_ ) {
numComp + + ;
}
return numComp ;
}
template < typename TypeTag >
int
2019-11-01 09:11:21 -05:00
BlackoilWellModel < TypeTag > : : numLocalWells ( ) const
2017-11-08 08:48:30 -06:00
{
2019-10-23 02:09:45 -05:00
return wells_ecl_ . size ( ) ;
2017-11-08 08:48:30 -06:00
}
template < typename TypeTag >
int
2019-10-23 02:09:45 -05:00
BlackoilWellModel < TypeTag > : : numPhases ( ) const
2017-11-08 08:48:30 -06:00
{
2019-10-23 02:09:45 -05:00
return phase_usage_ . num_phases ;
2017-11-08 08:48:30 -06:00
}
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : : extractLegacyDepth_ ( )
{
2018-02-01 09:27:42 -06:00
const auto & grid = ebosSimulator_ . vanguard ( ) . grid ( ) ;
2017-11-08 08:48:30 -06:00
const unsigned numCells = grid . size ( /*codim=*/ 0 ) ;
depth_ . resize ( numCells ) ;
for ( unsigned cellIdx = 0 ; cellIdx < numCells ; + + cellIdx ) {
2019-12-11 15:04:40 -06:00
depth_ [ cellIdx ] = Opm : : UgGridHelpers : : cellCenterDepth ( grid , cellIdx ) ;
2017-11-08 08:48:30 -06: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 09:02:47 -06:00
2017-11-08 08:48:30 -06:00
elemCtx . updatePrimaryStencil ( * elemIt ) ;
2018-11-16 09:02:47 -06:00
int elemIdx = elemCtx . globalSpaceIndex ( 0 , 0 ) ;
if ( ! is_cell_perforated_ [ elemIdx ] ) {
continue ;
}
2017-11-08 08:48:30 -06:00
elemCtx . updatePrimaryIntensiveQuantities ( /*timeIdx=*/ 0 ) ;
}
}
2017-11-08 06:57:36 -06:00
2018-11-26 05:09:04 -06:00
// convert well data from opm-common to well state from opm-core
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
wellsToState ( const data : : Wells & wells ,
2019-03-22 03:41:29 -05:00
const PhaseUsage & phases ,
const bool handle_ms_well ,
2019-06-25 14:53:37 -05:00
WellStateFullyImplicitBlackoil & state ) const
2019-03-22 03:41:29 -05:00
{
2018-11-26 05:09:04 -06: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 ;
}
for ( const auto & wm : state . wellMap ( ) ) {
const auto well_index = wm . second [ 0 ] ;
const auto & well = wells . at ( wm . first ) ;
state . bhp ( ) [ well_index ] = well . bhp ;
state . temperature ( ) [ well_index ] = well . temperature ;
2019-08-07 07:13:11 -05:00
2019-11-13 16:16:11 -06:00
//state.currentInjectionControls()[ well_index ] = static_cast<Opm::Well::InjectorCMode>(well.injectionControl);
//state.currentProductionControls()[ well_index ] = static_cast<Well::ProducerCMode>(well.productionControl);
2019-08-07 07:13:11 -05:00
2018-11-26 05:09:04 -06:00
const auto wellrate_index = well_index * np ;
for ( size_t i = 0 ; i < phs . size ( ) ; + + i ) {
assert ( well . rates . has ( phs [ i ] ) ) ;
state . wellRates ( ) [ wellrate_index + i ] = well . rates . get ( phs [ i ] ) ;
}
2019-09-30 08:22:31 -05:00
const auto perforation_pressure = [ ] ( const data : : Connection & comp ) {
return comp . pressure ;
} ;
const auto perforation_reservoir_rate = [ ] ( const data : : Connection & comp ) {
return comp . reservoir_rate ;
} ;
std : : transform ( well . connections . begin ( ) ,
well . connections . end ( ) ,
state . perfPress ( ) . begin ( ) + wm . second [ 1 ] ,
perforation_pressure ) ;
std : : transform ( well . connections . begin ( ) ,
well . connections . end ( ) ,
state . perfRates ( ) . begin ( ) + wm . second [ 1 ] ,
perforation_reservoir_rate ) ;
int local_comp_index = 0 ;
for ( const data : : Connection & comp : well . connections ) {
const int global_comp_index = wm . second [ 1 ] + local_comp_index ;
for ( int phase_index = 0 ; phase_index < np ; + + phase_index ) {
state . perfPhaseRates ( ) [ global_comp_index * np + phase_index ] = comp . rates . get ( phs [ phase_index ] ) ;
}
+ + local_comp_index ;
}
2019-03-22 03:41:29 -05:00
if ( handle_ms_well & & ! well . segments . empty ( ) ) {
// we need the well_ecl_ information
const std : : string & well_name = wm . first ;
2019-11-13 16:16:11 -06:00
const Well & well_ecl = getWellEcl ( well_name ) ;
2019-03-22 03:41:29 -05:00
2019-05-02 05:51:25 -05:00
const WellSegments & segment_set = well_ecl . getSegments ( ) ;
2019-03-22 03:41:29 -05:00
const int top_segment_index = state . topSegmentIndex ( well_index ) ;
const auto & segments = well . segments ;
// \Note: eventually we need to hanlde the situations that some segments are shut
2019-04-30 03:01:38 -05:00
assert ( 0u + segment_set . size ( ) = = segments . size ( ) ) ;
2019-03-22 03:41:29 -05:00
for ( const auto & segment : segments ) {
const int segment_index = segment_set . segmentNumberToIndex ( segment . first ) ;
// recovering segment rates and pressure from the restart values
state . segPress ( ) [ top_segment_index + segment_index ] = segment . second . pressure ;
const auto & segment_rates = segment . second . rates ;
for ( int p = 0 ; p < np ; + + p ) {
state . segRates ( ) [ ( top_segment_index + segment_index ) * np + p ] = segment_rates . get ( phs [ p ] ) ;
}
}
}
}
}
template < typename TypeTag >
bool
BlackoilWellModel < TypeTag > : :
2019-10-23 02:09:45 -05:00
anyMSWellOpenLocal ( ) const
2019-03-22 03:41:29 -05:00
{
2019-10-23 02:09:45 -05:00
for ( const auto & well : wells_ecl_ ) {
if ( well . isMultiSegment ( ) ) {
return true ;
2019-03-22 03:41:29 -05:00
}
}
2019-10-23 02:09:45 -05:00
return false ;
2019-03-22 03:41:29 -05:00
}
template < typename TypeTag >
2019-11-13 16:16:11 -06:00
const Well &
2019-03-22 03:41:29 -05:00
BlackoilWellModel < TypeTag > : :
getWellEcl ( const std : : string & well_name ) const
{
2019-04-04 08:36:35 -05: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 16:16:11 -06:00
[ & well_name ] ( const Well & elem ) - > bool {
2019-05-02 05:51:25 -05:00
return elem . name ( ) = = well_name ;
2019-04-04 08:36:35 -05:00
} ) ;
2019-03-22 03:41:29 -05:00
2019-04-04 08:36:35 -05:00
assert ( well_ecl ! = wells_ecl_ . end ( ) ) ;
return * well_ecl ;
2018-11-26 05:09:04 -06:00
}
2019-09-23 08:15:55 -05: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 ;
}
2019-08-07 07:13:11 -05:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2020-01-16 02:52:03 -06:00
checkGroupConstraints ( const Group & group , const bool checkCurrentControl , Opm : : DeferredLogger & deferred_logger ) {
2019-08-07 07:13:11 -05:00
const int reportStepIdx = ebosSimulator_ . episodeIndex ( ) ;
const auto & summaryState = ebosSimulator_ . vanguard ( ) . summaryState ( ) ;
2019-12-12 02:22:37 -06:00
const auto & comm = ebosSimulator_ . vanguard ( ) . grid ( ) . comm ( ) ;
2020-01-23 02:05:37 -06:00
auto & well_state = well_state_ ;
2019-08-07 07:13:11 -05:00
if ( group . isInjectionGroup ( ) )
{
2020-01-23 02:05:37 -06:00
2020-01-23 04:20:06 -06:00
const Phase all [ ] = { Phase : : WATER , Phase : : OIL , Phase : : GAS } ;
for ( Phase phase : all ) {
if ( ! group . hasInjectionControl ( phase ) ) {
2020-02-11 02:03:40 -06:00
continue ;
2020-01-23 02:05:37 -06:00
}
2020-01-23 04:20:06 -06: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
continue ;
2020-01-23 02:05:37 -06:00
2020-01-23 04:20:06 -06:00
const auto & controls = group . injectionControls ( phase , summaryState ) ;
2020-02-11 02:03:40 -06:00
const Group : : InjectionCMode & currentControl = well_state . currentInjectionGroupControl ( phase , group . name ( ) ) ;
2020-01-23 02:05:37 -06:00
2020-02-11 02:03:40 -06:00
if ( controls . has_control ( Group : : InjectionCMode : : RATE ) )
2020-01-16 02:52:03 -06:00
{
2020-02-11 02:03:40 -06:00
if ( checkCurrentControl | | currentControl ! = Group : : InjectionCMode : : RATE )
{
double current_rate = 0.0 ;
current_rate + = wellGroupHelpers : : sumWellRates ( group , schedule ( ) , well_state , reportStepIdx , phasePos , /*isInjector*/ true ) ;
2019-12-12 02:22:37 -06:00
2020-02-11 02:03:40 -06:00
// sum over all nodes
current_rate = comm . sum ( current_rate ) ;
2019-12-12 02:22:37 -06:00
2020-02-11 02:03:40 -06:00
if ( controls . surface_max_rate < current_rate ) {
actionOnBrokenConstraints ( group , Group : : InjectionCMode : : RATE , phase , reportStepIdx , deferred_logger ) ;
}
2020-01-23 04:20:06 -06:00
}
2019-08-07 07:13:11 -05:00
}
2020-02-11 02:03:40 -06:00
if ( controls . has_control ( Group : : InjectionCMode : : RESV ) )
2020-01-16 02:52:03 -06:00
{
2020-02-11 02:03:40 -06:00
if ( checkCurrentControl | | currentControl ! = Group : : InjectionCMode : : RESV )
{
double current_rate = 0.0 ;
current_rate + = wellGroupHelpers : : sumWellResRates ( group , schedule ( ) , well_state , reportStepIdx , phasePos , /*isInjector*/ true ) ;
// sum over all nodes
current_rate = comm . sum ( current_rate ) ;
if ( controls . resv_max_rate < current_rate ) {
actionOnBrokenConstraints ( group , Group : : InjectionCMode : : RESV , phase , reportStepIdx , deferred_logger ) ;
}
}
}
2020-01-23 04:20:06 -06:00
if ( controls . has_control ( Group : : InjectionCMode : : REIN ) )
2020-01-16 02:52:03 -06:00
{
2020-02-11 02:03:40 -06:00
if ( checkCurrentControl | | currentControl ! = Group : : InjectionCMode : : REIN )
{
double production_Rate = 0.0 ;
const Group & groupRein = schedule ( ) . getGroup ( controls . reinj_group , reportStepIdx ) ;
production_Rate + = wellGroupHelpers : : sumWellRates ( groupRein , schedule ( ) , well_state , reportStepIdx , phasePos , /*isInjector*/ false ) ;
2019-08-07 07:13:11 -05:00
2020-02-11 02:03:40 -06:00
// sum over all nodes
production_Rate = comm . sum ( production_Rate ) ;
2019-12-12 02:22:37 -06:00
2020-02-11 02:03:40 -06:00
double current_rate = 0.0 ;
current_rate + = wellGroupHelpers : : sumWellRates ( group , schedule ( ) , well_state , reportStepIdx , phasePos , /*isInjector*/ true ) ;
2019-08-07 07:13:11 -05:00
2020-02-11 02:03:40 -06:00
// sum over all nodes
current_rate = comm . sum ( current_rate ) ;
2019-12-12 02:22:37 -06:00
2020-02-11 02:03:40 -06:00
if ( controls . target_reinj_fraction * production_Rate < current_rate ) {
actionOnBrokenConstraints ( group , Group : : InjectionCMode : : REIN , phase , reportStepIdx , deferred_logger ) ;
}
}
}
if ( controls . has_control ( Group : : InjectionCMode : : VREP ) )
2020-01-16 02:52:03 -06:00
{
2020-02-11 02:03:40 -06:00
if ( checkCurrentControl | | currentControl ! = Group : : InjectionCMode : : VREP )
{
double voidage_rate = 0.0 ;
const Group & groupVoidage = schedule ( ) . getGroup ( controls . voidage_group , reportStepIdx ) ;
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 ) ;
// sum over all nodes
voidage_rate = comm . sum ( voidage_rate ) ;
double total_rate = 0.0 ;
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 ) ;
// sum over all nodes
total_rate = comm . sum ( total_rate ) ;
if ( controls . target_void_fraction * voidage_rate < total_rate ) {
actionOnBrokenConstraints ( group , Group : : InjectionCMode : : VREP , phase , reportStepIdx , deferred_logger ) ;
}
2020-01-23 04:20:06 -06:00
}
2019-08-07 07:13:11 -05:00
}
2020-02-11 02:03:40 -06:00
// Handle GCONSALE
if ( schedule ( ) . gConSale ( reportStepIdx ) . has ( group . name ( ) ) ) {
2019-11-26 04:15:09 -06:00
2020-02-11 02:03:40 -06:00
if ( controls . phase ! = Phase : : GAS )
OPM_THROW ( std : : runtime_error , " Group " + group . name ( ) + " has GCONSALE control but is not a GAS group " ) ;
2019-11-26 04:15:09 -06:00
2020-02-11 02:03:40 -06:00
const auto & gconsale = schedule ( ) . gConSale ( reportStepIdx ) . get ( group . name ( ) , summaryState ) ;
2019-11-26 04:15:09 -06:00
2020-02-11 02:03:40 -06:00
double sales_rate = 0.0 ;
int gasPos = phase_usage_ . phase_pos [ BlackoilPhases : : Vapour ] ;
sales_rate + = wellGroupHelpers : : sumWellRates ( group , schedule ( ) , well_state , reportStepIdx , gasPos , /*isInjector*/ false ) ;
sales_rate - = wellGroupHelpers : : sumWellRates ( group , schedule ( ) , well_state , reportStepIdx , gasPos , /*isInjector*/ true ) ;
2019-11-26 04:15:09 -06:00
2020-02-11 02:03:40 -06:00
// sum over all nodes
sales_rate = comm . sum ( sales_rate ) ;
// add import rate and substract consumption rate for group for gas
if ( schedule ( ) . gConSump ( reportStepIdx ) . has ( group . name ( ) ) ) {
const auto & gconsump = schedule ( ) . gConSump ( reportStepIdx ) . get ( group . name ( ) , summaryState ) ;
if ( phase_usage_ . phase_used [ BlackoilPhases : : Vapour ] ) {
sales_rate + = gconsump . import_rate ;
sales_rate - = gconsump . consumption_rate ;
}
}
if ( sales_rate > gconsale . max_sales_rate ) {
OPM_THROW ( std : : runtime_error , " Group " + group . name ( ) + " has sale rate more then the maximum permitted value. Not implemented in Flow " ) ;
}
if ( sales_rate < gconsale . min_sales_rate ) {
OPM_THROW ( std : : runtime_error , " Group " + group . name ( ) + " has sale rate less then minimum permitted value. Not implemented in Flow " ) ;
}
if ( gconsale . sales_target < 0.0 ) {
OPM_THROW ( std : : runtime_error , " Group " + group . name ( ) + " has sale rate target less then zero. Not implemented in Flow " ) ;
2019-11-26 04:15:09 -06:00
}
}
2020-02-11 02:03:40 -06:00
}
2019-11-26 06:36:45 -06:00
}
if ( group . isProductionGroup ( ) ) {
2019-08-07 07:13:11 -05:00
const auto controls = group . productionControls ( summaryState ) ;
2020-01-16 02:52:03 -06:00
const Group : : ProductionCMode & currentControl = well_state . currentProductionGroupControl ( group . name ( ) ) ;
2019-08-07 07:13:11 -05:00
2019-11-13 16:16:11 -06:00
if ( group . has_control ( Group : : ProductionCMode : : ORAT ) )
2019-08-07 07:13:11 -05:00
{
2020-01-16 02:52:03 -06:00
if ( checkCurrentControl | | currentControl ! = Group : : ProductionCMode : : ORAT )
{
2020-02-11 02:03:40 -06:00
double current_rate = 0.0 ;
current_rate + = wellGroupHelpers : : sumWellRates ( group , schedule ( ) , well_state , reportStepIdx , phase_usage_ . phase_pos [ BlackoilPhases : : Liquid ] , false ) ;
2019-12-12 02:22:37 -06:00
2020-02-11 02:03:40 -06:00
// sum over all nodes
current_rate = comm . sum ( current_rate ) ;
2019-12-12 02:22:37 -06:00
2020-02-11 02:03:40 -06:00
if ( controls . oil_target < current_rate ) {
actionOnBrokenConstraints ( group , controls . exceed_action , Group : : ProductionCMode : : ORAT , reportStepIdx , deferred_logger ) ;
}
2020-01-16 02:52:03 -06:00
}
2019-08-07 07:13:11 -05:00
}
2019-11-13 16:16:11 -06:00
if ( group . has_control ( Group : : ProductionCMode : : WRAT ) )
2019-08-07 07:13:11 -05:00
{
2020-02-11 02:03:40 -06:00
if ( checkCurrentControl | | currentControl ! = Group : : ProductionCMode : : WRAT )
{
double current_rate = 0.0 ;
current_rate + = wellGroupHelpers : : sumWellRates ( group , schedule ( ) , well_state , reportStepIdx , phase_usage_ . phase_pos [ BlackoilPhases : : Aqua ] , false ) ;
2019-08-07 07:13:11 -05:00
2020-01-16 02:52:03 -06:00
// sum over all nodes
current_rate = comm . sum ( current_rate ) ;
2019-12-12 02:22:37 -06:00
2020-01-16 02:52:03 -06:00
if ( controls . water_target < current_rate ) {
actionOnBrokenConstraints ( group , controls . exceed_action , Group : : ProductionCMode : : WRAT , reportStepIdx , deferred_logger ) ;
}
2019-08-07 07:13:11 -05:00
}
}
2019-11-13 16:16:11 -06:00
if ( group . has_control ( Group : : ProductionCMode : : GRAT ) )
2019-08-07 07:13:11 -05:00
{
2020-01-16 02:52:03 -06:00
if ( checkCurrentControl | | currentControl ! = Group : : ProductionCMode : : GRAT )
{
double current_rate = 0.0 ;
current_rate + = wellGroupHelpers : : sumWellRates ( group , schedule ( ) , well_state , reportStepIdx , phase_usage_ . phase_pos [ BlackoilPhases : : Vapour ] , false ) ;
2019-12-12 02:22:37 -06:00
2020-01-16 02:52:03 -06:00
// sum over all nodes
current_rate = comm . sum ( current_rate ) ;
if ( controls . gas_target < current_rate ) {
actionOnBrokenConstraints ( group , controls . exceed_action , Group : : ProductionCMode : : GRAT , reportStepIdx , deferred_logger ) ;
}
2019-08-07 07:13:11 -05:00
}
}
2019-11-13 16:16:11 -06:00
if ( group . has_control ( Group : : ProductionCMode : : LRAT ) )
2019-08-07 07:13:11 -05:00
{
2020-01-16 02:52:03 -06:00
if ( checkCurrentControl | | currentControl ! = Group : : ProductionCMode : : LRAT )
{
double current_rate = 0.0 ;
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-12-12 02:22:37 -06:00
2020-01-16 02:52:03 -06:00
// sum over all nodes
current_rate = comm . sum ( current_rate ) ;
2019-12-12 02:22:37 -06:00
2020-01-16 02:52:03 -06:00
if ( controls . liquid_target < current_rate ) {
actionOnBrokenConstraints ( group , controls . exceed_action , Group : : ProductionCMode : : LRAT , reportStepIdx , deferred_logger ) ;
}
2019-08-07 07:13:11 -05:00
}
}
2019-11-13 16:16:11 -06:00
if ( group . has_control ( Group : : ProductionCMode : : CRAT ) )
2019-08-07 07:13:11 -05:00
{
OPM_DEFLOG_THROW ( std : : runtime_error , " Group " + group . name ( ) + " CRAT control for production groups not implemented " , deferred_logger ) ;
}
2019-11-13 16:16:11 -06:00
if ( group . has_control ( Group : : ProductionCMode : : RESV ) )
2019-08-07 07:13:11 -05:00
{
2020-01-16 02:52:03 -06:00
if ( checkCurrentControl | | currentControl ! = Group : : ProductionCMode : : RESV )
{
double current_rate = 0.0 ;
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-08-07 07:13:11 -05:00
2020-01-16 02:52:03 -06:00
// sum over all nodes
current_rate = comm . sum ( current_rate ) ;
2019-12-12 02:22:37 -06:00
2020-01-16 02:52:03 -06:00
if ( controls . resv_target < current_rate ) {
actionOnBrokenConstraints ( group , controls . exceed_action , Group : : ProductionCMode : : RESV , reportStepIdx , deferred_logger ) ;
}
2019-08-07 07:13:11 -05:00
}
}
2019-11-13 16:16:11 -06:00
if ( group . has_control ( Group : : ProductionCMode : : PRBL ) )
2019-08-07 07:13:11 -05:00
{
OPM_DEFLOG_THROW ( std : : runtime_error , " Group " + group . name ( ) + " PRBL control for production groups not implemented " , deferred_logger ) ;
}
2020-01-16 02:52:03 -06:00
2019-08-07 07:13:11 -05:00
} else {
//neither production or injecting group FIELD?
}
2019-12-16 06:53:03 -06:00
// call recursively down the group hiearchy
for ( const std : : string & groupName : group . groups ( ) ) {
2020-01-16 02:52:03 -06:00
checkGroupConstraints ( schedule ( ) . getGroup ( groupName , reportStepIdx ) , checkCurrentControl , deferred_logger ) ;
2019-12-16 06:53:03 -06:00
}
2019-08-07 07:13:11 -05:00
}
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2019-11-13 16:16:11 -06:00
actionOnBrokenConstraints ( const Group & group , const Group : : ExceedAction & exceed_action , const Group : : ProductionCMode & newControl , const int reportStepIdx , Opm : : DeferredLogger & deferred_logger ) {
2019-08-07 07:13:11 -05:00
2019-12-11 15:04:40 -06:00
auto & well_state = well_state_ ;
2019-11-13 16:16:11 -06:00
const Group : : ProductionCMode & oldControl = well_state . currentProductionGroupControl ( group . name ( ) ) ;
2019-08-07 07:13:11 -05:00
std : : ostringstream ss ;
2019-10-16 08:27:40 -05:00
2019-08-07 07:13:11 -05:00
switch ( exceed_action ) {
2019-11-13 16:16:11 -06:00
case Group : : ExceedAction : : NONE : {
2019-11-25 03:11:36 -06:00
if ( oldControl ! = newControl & & oldControl ! = Group : : ProductionCMode : : NONE ) {
ss < < " Group production exceed limit is NONE for group " + group . name ( ) + " . Nothing happens " ;
}
2019-08-07 07:13:11 -05:00
break ;
}
2019-11-13 16:16:11 -06:00
case Group : : ExceedAction : : CON : {
2019-08-07 07:13:11 -05:00
OPM_DEFLOG_THROW ( std : : runtime_error , " Group " + group . name ( ) + " GroupProductionExceedLimit CON not implemented " , deferred_logger ) ;
break ;
}
2019-11-13 16:16:11 -06:00
case Group : : ExceedAction : : CON_PLUS : {
2019-08-07 07:13:11 -05:00
OPM_DEFLOG_THROW ( std : : runtime_error , " Group " + group . name ( ) + " GroupProductionExceedLimit CON_PLUS not implemented " , deferred_logger ) ;
break ;
}
2019-11-13 16:16:11 -06:00
case Group : : ExceedAction : : WELL : {
2019-08-07 07:13:11 -05:00
OPM_DEFLOG_THROW ( std : : runtime_error , " Group " + group . name ( ) + " GroupProductionExceedLimit WELL not implemented " , deferred_logger ) ;
break ;
}
2019-11-13 16:16:11 -06:00
case Group : : ExceedAction : : PLUG : {
2019-08-07 07:13:11 -05:00
OPM_DEFLOG_THROW ( std : : runtime_error , " Group " + group . name ( ) + " GroupProductionExceedLimit PLUG not implemented " , deferred_logger ) ;
break ;
}
2019-11-13 16:16:11 -06:00
case Group : : ExceedAction : : RATE : {
2019-10-16 08:27:40 -05:00
if ( oldControl ! = newControl ) {
well_state . setCurrentProductionGroupControl ( group . name ( ) , newControl ) ;
2019-12-16 07:28:55 -06:00
ss < < " Switching control mode for group " < < group . name ( ) < < " to " < < Group : : ProductionCMode2String ( newControl ) ;
2019-10-16 08:27:40 -05:00
}
2020-01-20 02:14:19 -06:00
// Pass a dummy phase for producer groups. The topUpPhase is only relevant for injector groups
const Phase topUpPhase = Phase : : WATER ;
wellGroupHelpers : : setGroupControl ( group , schedule ( ) , topUpPhase , reportStepIdx , false , well_state , ss ) ;
2019-08-07 07:13:11 -05:00
break ;
}
default :
throw ( " Invalid procedure for maximum rate limit selected for group " + group . name ( ) ) ;
}
auto cc = Dune : : MPIHelper : : getCollectiveCommunication ( ) ;
if ( cc . size ( ) > 1 ) {
ss < < " on rank " < < cc . rank ( ) ;
}
2019-10-16 08:27:40 -05:00
if ( ! ss . str ( ) . empty ( ) )
deferred_logger . info ( ss . str ( ) ) ;
2019-08-07 07:13:11 -05:00
}
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2020-01-23 02:05:37 -06:00
actionOnBrokenConstraints ( const Group & group , const Group : : InjectionCMode & newControl , const Phase & controlPhase , const int reportStepIdx , Opm : : DeferredLogger & deferred_logger ) {
2019-08-07 07:13:11 -05:00
auto & well_state = well_state_ ;
2020-01-23 02:05:37 -06:00
const Group : : InjectionCMode & oldControl = well_state . currentInjectionGroupControl ( controlPhase , group . name ( ) ) ;
2019-10-16 08:27:40 -05:00
2019-08-07 07:13:11 -05:00
std : : ostringstream ss ;
2019-10-16 08:27:40 -05:00
if ( oldControl ! = newControl ) {
2019-11-13 16:16:11 -06:00
const std : : string from = Group : : InjectionCMode2String ( oldControl ) ;
2019-10-16 08:27:40 -05:00
ss < < " Group " < < group . name ( ) < < " exceeding "
< < from < < " limit \n " ;
2019-12-16 07:28:55 -06:00
ss < < " Switching control mode for group " < < group . name ( ) < < " to " < < Group : : InjectionCMode2String ( newControl ) ;
2019-10-16 08:27:40 -05:00
auto cc = Dune : : MPIHelper : : getCollectiveCommunication ( ) ;
if ( cc . size ( ) > 1 ) {
ss < < " on rank " < < cc . rank ( ) ;
}
2020-01-23 02:05:37 -06:00
well_state . setCurrentInjectionGroupControl ( controlPhase , group . name ( ) , newControl ) ;
2019-08-07 07:13:11 -05:00
}
2020-01-23 02:05:37 -06:00
wellGroupHelpers : : setGroupControl ( group , schedule ( ) , controlPhase , reportStepIdx , /*isInjector*/ true , well_state , ss ) ;
2019-10-16 08:27:40 -05:00
if ( ! ss . str ( ) . empty ( ) )
deferred_logger . info ( ss . str ( ) ) ;
2019-08-07 07:13:11 -05:00
}
2019-09-23 08:15:55 -05:00
template < typename TypeTag >
void
BlackoilWellModel < TypeTag > : :
2019-11-13 16:16:11 -06:00
updateWsolvent ( const Group & group , const Schedule & schedule , const int reportStepIdx , const WellStateFullyImplicitBlackoil & wellState ) {
2019-09-23 08:15:55 -05:00
for ( const std : : string & groupName : group . groups ( ) ) {
2019-11-13 16:16:11 -06:00
const Group & groupTmp = schedule . getGroup ( groupName , reportStepIdx ) ;
2019-09-23 08:15:55 -05:00
updateWsolvent ( groupTmp , schedule , reportStepIdx , wellState ) ;
}
if ( group . isProductionGroup ( ) )
return ;
2020-01-23 02:05:37 -06:00
const Group : : InjectionCMode & currentGroupControl = wellState . currentInjectionGroupControl ( Phase : : GAS , group . name ( ) ) ;
2019-11-13 16:16:11 -06:00
if ( currentGroupControl = = Group : : InjectionCMode : : REIN ) {
2019-09-23 08:15:55 -05:00
int gasPos = phase_usage_ . phase_pos [ BlackoilPhases : : Vapour ] ;
double gasProductionRate = wellGroupHelpers : : sumWellRates ( group , schedule , wellState , reportStepIdx , gasPos , /*isInjector*/ false ) ;
double solventProductionRate = wellGroupHelpers : : sumSolventRates ( group , schedule , wellState , reportStepIdx , /*isInjector*/ false ) ;
2019-12-12 02:22:37 -06:00
const auto & comm = ebosSimulator_ . vanguard ( ) . grid ( ) . comm ( ) ;
solventProductionRate = comm . sum ( solventProductionRate ) ;
gasProductionRate = comm . sum ( gasProductionRate ) ;
2019-09-23 08:15:55 -05: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 16:16:11 -06:00
setWsolvent ( const Group & group , const Schedule & schedule , const int reportStepIdx , double wsolvent ) {
2019-09-23 08:15:55 -05:00
for ( const std : : string & groupName : group . groups ( ) ) {
2019-11-13 16:16:11 -06:00
const Group & groupTmp = schedule . getGroup ( groupName , reportStepIdx ) ;
2019-09-23 08:15:55 -05:00
setWsolvent ( groupTmp , schedule , reportStepIdx , wsolvent ) ;
}
for ( const std : : string & wellName : group . wells ( ) ) {
2019-11-13 16:16:11 -06:00
const auto & wellTmp = schedule . getWell ( wellName , reportStepIdx ) ;
if ( wellTmp . getStatus ( ) = = Well : : Status : : SHUT )
2019-09-23 08:15:55 -05:00
continue ;
auto well = getWell ( wellName ) ;
well - > setWsolvent ( wsolvent ) ;
}
}
2018-11-26 05:09:04 -06:00
2017-02-13 09:45:06 -06:00
} // namespace Opm