2012-03-29 11:34:51 -05:00
/*
2013-01-29 06:42:24 -06:00
Copyright 2011 SINTEF ICT , Applied Mathematics .
2012-03-29 11:34:51 -05:00
2013-01-29 06:42:24 -06:00
This file is part of the Open Porous Media project ( OPM ) .
2012-03-29 11:34:51 -05:00
2013-01-29 06:42:24 -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 .
2012-03-29 11:34:51 -05:00
2013-01-29 06:42:24 -06:00
OPM is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2012-03-29 11:34:51 -05:00
2013-01-29 06:42:24 -06:00
You should have received a copy of the GNU General Public License
along with OPM . If not , see < http : //www.gnu.org/licenses/>.
*/
2012-03-29 11:34:51 -05:00
2013-04-10 05:56:14 -05:00
# include "config.h"
2012-06-05 08:42:49 -05:00
# include <opm/core/wells/WellCollection.hpp>
2014-02-12 08:39:57 -06:00
# include <opm/parser/eclipse/EclipseState/Schedule/Well.hpp>
# include <opm/parser/eclipse/EclipseState/Schedule/Group.hpp>
2014-02-14 06:43:25 -06:00
# include <boost/lexical_cast.hpp>
2013-08-08 05:32:01 -05:00
# include <memory>
2012-03-29 11:34:51 -05:00
namespace Opm
{
2016-10-05 08:24:14 -05:00
void WellCollection : : addField ( const Group & fieldGroup , size_t timeStep , const PhaseUsage & phaseUsage ) {
WellsGroupInterface * fieldNode = findNode ( fieldGroup . name ( ) ) ;
2014-02-13 09:00:39 -06:00
if ( fieldNode ) {
OPM_THROW ( std : : runtime_error , " Trying to add FIELD node, but this already exists. Can only have one FIELD node. " ) ;
}
roots_ . push_back ( createGroupWellsGroup ( fieldGroup , timeStep , phaseUsage ) ) ;
}
2016-10-05 08:24:14 -05:00
void WellCollection : : addGroup ( const Group & groupChild , std : : string parent_name ,
2014-02-12 08:39:57 -06:00
size_t timeStep , const PhaseUsage & phaseUsage ) {
2014-02-13 09:00:39 -06:00
WellsGroupInterface * parent = findNode ( parent_name ) ;
2014-02-12 08:39:57 -06:00
if ( ! parent ) {
2014-02-14 06:43:25 -06:00
OPM_THROW ( std : : runtime_error , " Trying to add child group to group named " < < parent_name < < " , but this does not exist in the WellCollection. " ) ;
2014-02-12 08:39:57 -06:00
}
2016-10-05 08:24:14 -05:00
if ( findNode ( groupChild . name ( ) ) ) {
OPM_THROW ( std : : runtime_error , " Trying to add child group named " < < groupChild . name ( ) < < " , but this group is already in the WellCollection. " ) ;
2014-02-12 08:39:57 -06:00
}
2014-02-13 09:00:39 -06:00
std : : shared_ptr < WellsGroupInterface > child = createGroupWellsGroup ( groupChild , timeStep , phaseUsage ) ;
2016-10-21 10:39:31 -05:00
if ( child - > injSpec ( ) . control_mode_ = = InjectionSpecification : : VREP ) {
having_vrep_groups_ = true ;
}
2014-02-12 08:39:57 -06:00
WellsGroup * parent_as_group = static_cast < WellsGroup * > ( parent ) ;
if ( ! parent_as_group ) {
2014-02-14 06:43:25 -06:00
OPM_THROW ( std : : runtime_error , " Trying to add child group to group named " < < parent - > name ( ) < < " , but it's not a group. " ) ;
2014-02-12 08:39:57 -06:00
}
parent_as_group - > addChild ( child ) ;
child - > setParent ( parent ) ;
}
2016-06-16 02:33:43 -05:00
void WellCollection : : addWell ( const Well * wellChild , size_t timeStep , const PhaseUsage & phaseUsage ) {
2016-04-08 08:47:49 -05:00
if ( wellChild - > getStatus ( timeStep ) = = WellCommon : : SHUT ) {
//SHUT wells are not added to the well collection
return ;
}
2014-02-13 09:00:39 -06:00
WellsGroupInterface * parent = findNode ( wellChild - > getGroupName ( timeStep ) ) ;
2014-02-12 08:39:57 -06:00
if ( ! parent ) {
2014-02-14 06:43:25 -06:00
OPM_THROW ( std : : runtime_error , " Trying to add well " < < wellChild - > name ( ) < < " Step: " < < boost : : lexical_cast < std : : string > ( timeStep ) < < " to group named " < < wellChild - > getGroupName ( timeStep ) < < " , but this group does not exist in the WellCollection. " ) ;
2014-02-12 08:39:57 -06:00
}
2014-02-13 09:00:39 -06:00
std : : shared_ptr < WellsGroupInterface > child = createWellWellsGroup ( wellChild , timeStep , phaseUsage ) ;
2014-02-12 08:39:57 -06:00
WellsGroup * parent_as_group = static_cast < WellsGroup * > ( parent ) ;
if ( ! parent_as_group ) {
2014-02-14 06:43:25 -06:00
OPM_THROW ( std : : runtime_error , " Trying to add well to group named " < < wellChild - > getGroupName ( timeStep ) < < " , but it's not a group. " ) ;
2014-02-12 08:39:57 -06:00
}
parent_as_group - > addChild ( child ) ;
2014-02-13 09:00:39 -06:00
leaf_nodes_ . push_back ( static_cast < WellNode * > ( child . get ( ) ) ) ;
2014-02-12 08:39:57 -06:00
child - > setParent ( parent ) ;
}
2012-04-25 07:19:47 -05:00
const std : : vector < WellNode * > & WellCollection : : getLeafNodes ( ) const {
2012-03-30 03:51:31 -05:00
return leaf_nodes_ ;
2012-03-29 11:34:51 -05:00
}
2012-04-25 09:42:55 -05:00
WellsGroupInterface * WellCollection : : findNode ( const std : : string & name )
2012-03-29 11:34:51 -05:00
{
2012-04-10 08:01:52 -05:00
for ( size_t i = 0 ; i < roots_ . size ( ) ; i + + ) {
2012-03-29 11:34:51 -05:00
WellsGroupInterface * result = roots_ [ i ] - > findGroup ( name ) ;
if ( result ) {
return result ;
}
}
return NULL ;
}
2013-07-28 06:34:13 -05:00
2012-04-25 09:42:55 -05:00
const WellsGroupInterface * WellCollection : : findNode ( const std : : string & name ) const
2012-04-23 06:24:47 -05:00
{
for ( size_t i = 0 ; i < roots_ . size ( ) ; i + + ) {
WellsGroupInterface * result = roots_ [ i ] - > findGroup ( name ) ;
if ( result ) {
return result ;
}
}
return NULL ;
}
2012-05-14 09:10:37 -05:00
2016-11-03 07:12:12 -05:00
WellNode * WellCollection : : findWellNode ( const std : : string & name ) const
{
auto well_node = std : : find_if ( leaf_nodes_ . begin ( ) , leaf_nodes_ . end ( ) ,
[ & ] ( WellNode * w ) {
return w - > name ( ) = = name ;
} ) ;
if ( well_node ! = leaf_nodes_ . end ( ) ) {
return * well_node ;
} else {
return nullptr ;
}
}
2012-05-14 09:10:37 -05:00
/// Adds the child to the collection
/// and appends it to parent's children.
/// \param[in] child the child node
/// \param[in] parent name of parent node
2013-08-08 05:32:01 -05:00
void WellCollection : : addChild ( std : : shared_ptr < WellsGroupInterface > & child_node ,
2012-05-14 09:10:37 -05:00
const std : : string & parent_name )
{
WellsGroupInterface * parent = findNode ( parent_name ) ;
if ( parent = = NULL ) {
2013-08-28 06:59:03 -05:00
OPM_THROW ( std : : runtime_error , " Parent with name = " < < parent_name < < " not found. " ) ;
2012-05-14 09:10:37 -05:00
}
2013-08-28 07:00:35 -05:00
assert ( ! parent - > isLeafNode ( ) ) ;
2012-05-14 09:10:37 -05:00
static_cast < WellsGroup * > ( parent ) - > addChild ( child_node ) ;
if ( child_node - > isLeafNode ( ) ) {
leaf_nodes_ . push_back ( static_cast < WellNode * > ( child_node . get ( ) ) ) ;
}
}
/// Adds the node to the collection (as a root node)
2013-08-08 05:32:01 -05:00
void WellCollection : : addChild ( std : : shared_ptr < WellsGroupInterface > & child_node )
2012-05-14 09:10:37 -05:00
{
roots_ . push_back ( child_node ) ;
if ( child_node - > isLeafNode ( ) ) {
leaf_nodes_ . push_back ( static_cast < WellNode * > ( child_node . get ( ) ) ) ;
}
}
2013-07-28 06:34:13 -05:00
2012-04-25 09:14:40 -05:00
bool WellCollection : : conditionsMet ( const std : : vector < double > & well_bhp ,
2012-05-02 06:02:59 -05:00
const std : : vector < double > & well_reservoirrates_phase ,
const std : : vector < double > & well_surfacerates_phase )
2012-04-25 07:03:57 -05:00
{
2012-04-25 09:14:40 -05:00
for ( size_t i = 0 ; i < roots_ . size ( ) ; i + + ) {
WellPhasesSummed phases ;
2012-05-02 06:02:59 -05:00
if ( ! roots_ [ i ] - > conditionsMet ( well_bhp ,
well_reservoirrates_phase ,
well_surfacerates_phase ,
phases ) ) {
2012-04-25 09:14:40 -05:00
return false ;
}
}
return true ;
2012-04-12 07:25:39 -05:00
}
2013-07-28 06:34:13 -05:00
2012-04-25 09:14:40 -05:00
void WellCollection : : setWellsPointer ( Wells * wells ) {
2012-04-25 07:19:47 -05:00
for ( size_t i = 0 ; i < leaf_nodes_ . size ( ) ; i + + ) {
leaf_nodes_ [ i ] - > setWellsPointer ( wells , i ) ;
}
}
2013-07-28 06:34:13 -05:00
2012-05-02 06:02:59 -05:00
void WellCollection : : applyGroupControls ( )
{
for ( size_t i = 0 ; i < roots_ . size ( ) ; + + i ) {
roots_ [ i ] - > applyProdGroupControls ( ) ;
roots_ [ i ] - > applyInjGroupControls ( ) ;
}
}
2012-05-09 06:03:37 -05:00
/// Applies explicit reinjection controls. This must be called at each timestep to be correct.
/// \param[in] well_reservoirrates_phase
/// A vector containing reservoir rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
/// \param[in] well_surfacerates_phase
/// A vector containing surface rates by phase for each well.
/// Is assumed to be ordered the same way as the related Wells-struct,
/// with all phase rates of a single well adjacent in the array.
void WellCollection : : applyExplicitReinjectionControls ( const std : : vector < double > & well_reservoirrates_phase ,
const std : : vector < double > & well_surfacerates_phase )
{
for ( size_t i = 0 ; i < roots_ . size ( ) ; + + i ) {
roots_ [ i ] - > applyExplicitReinjectionControls ( well_reservoirrates_phase , well_surfacerates_phase ) ;
}
}
2016-09-30 10:54:49 -05:00
2016-10-21 10:39:31 -05:00
void WellCollection : : applyVREPGroupControls ( const std : : vector < double > & well_voidage_rates ,
const std : : vector < double > & conversion_coeffs )
{
for ( size_t i = 0 ; i < roots_ . size ( ) ; + + i ) {
roots_ [ i ] - > applyVREPGroupControls ( well_voidage_rates , conversion_coeffs ) ;
}
}
2016-11-02 07:53:30 -05:00
// TODO: later, it should be extended to update group targets
2016-09-30 10:54:49 -05:00
bool WellCollection : : needUpdateWellTargets ( ) const
2016-10-07 07:54:53 -05:00
{
return needUpdateInjectionTargets ( ) | | needUpdateProductionTargets ( ) ;
}
bool WellCollection : : needUpdateInjectionTargets ( ) const
2016-09-30 10:54:49 -05:00
{
2016-11-02 07:53:30 -05:00
// TODO: it should based on individual group
// With current approach, it will potentially result in more update,
// thus more iterations, while it will not cause result wrong.
2016-11-04 07:37:50 -05:00
// If the group control and individual control is mixed, then it need to
// update the well targets
2016-10-06 11:00:08 -05:00
bool any_group_control_node = false ;
2016-11-04 07:37:50 -05:00
bool any_individual_control_node = false ;
2016-10-07 07:54:53 -05:00
2016-09-30 10:54:49 -05:00
for ( size_t i = 0 ; i < leaf_nodes_ . size ( ) ; + + i ) {
2016-10-07 07:54:53 -05:00
if ( leaf_nodes_ [ i ] - > isInjector ( ) ) {
2016-11-04 07:37:50 -05:00
if ( leaf_nodes_ [ i ] - > individualControl ( ) ) {
any_individual_control_node = true ;
} else {
2016-10-07 07:54:53 -05:00
any_group_control_node = true ;
}
2016-10-06 11:00:08 -05:00
}
2016-10-07 07:54:53 -05:00
}
2016-11-04 07:37:50 -05:00
return ( any_group_control_node & & any_individual_control_node ) ;
2016-10-07 07:54:53 -05:00
}
2016-11-04 07:37:50 -05:00
// These two functions should be made one
2016-10-10 07:47:19 -05:00
bool WellCollection : : needUpdateProductionTargets ( ) const
{
2016-11-02 07:53:30 -05:00
// TODO: it should based on individual group
// With current approach, it will potentially result in more update,
// thus more iterations, while it will not cause result wrong.
2016-11-04 07:37:50 -05:00
// If the group control and individual control is mixed, then it need to
// update the well targets
2016-10-07 07:54:53 -05:00
bool any_group_control_node = false ;
2016-11-04 07:37:50 -05:00
bool any_individual_control_node = false ;
2016-10-07 07:54:53 -05:00
for ( size_t i = 0 ; i < leaf_nodes_ . size ( ) ; + + i ) {
if ( leaf_nodes_ [ i ] - > isProducer ( ) ) {
2016-11-04 07:37:50 -05:00
if ( leaf_nodes_ [ i ] - > individualControl ( ) ) {
any_individual_control_node = true ;
} else {
2016-10-07 07:54:53 -05:00
any_group_control_node = true ;
}
2016-09-30 10:54:49 -05:00
}
}
2016-10-07 07:54:53 -05:00
2016-11-04 07:37:50 -05:00
return ( any_group_control_node & & any_individual_control_node ) ;
2016-09-30 10:54:49 -05:00
}
2016-11-16 02:51:06 -06:00
void WellCollection : : updateWellTargets ( const std : : vector < double > & well_rates )
2016-10-10 07:47:19 -05:00
{
2016-11-15 06:56:49 -06:00
if ( ! needUpdateWellTargets ( ) ) {
return ;
}
2016-11-15 07:36:19 -06:00
// set the target_updated to be false
for ( WellNode * well_node : leaf_nodes_ ) {
well_node - > setTargetUpdated ( false ) ;
}
2016-10-10 07:47:19 -05:00
// TODO: currently, we only handle the level of the well groups for the moment, i.e. the level just above wells
// We believe the relations between groups are similar to the relations between different wells inside the same group.
// While there will be somre more complication invloved for sure.
for ( size_t i = 0 ; i < leaf_nodes_ . size ( ) ; + + i ) {
// find a node needs to update targets, then update targets for all the wellls inside the group.
// if (leaf_nodes_[i]->shouldUpdateWellTargets() && !leaf_nodes_[i]->individualControl()) {
2016-11-15 07:36:19 -06:00
if ( ! leaf_nodes_ [ i ] - > individualControl ( ) & & ! leaf_nodes_ [ i ] - > targetUpdated ( ) ) {
2016-10-10 08:30:15 -05:00
WellsGroupInterface * parent_node = leaf_nodes_ [ i ] - > getParent ( ) ;
2016-10-10 07:47:19 -05:00
// update the target within this group.
if ( leaf_nodes_ [ i ] - > isProducer ( ) ) {
parent_node - > updateWellProductionTargets ( well_rates ) ;
}
if ( leaf_nodes_ [ i ] - > isInjector ( ) ) {
parent_node - > updateWellInjectionTargets ( well_rates ) ;
}
}
}
}
2016-11-16 04:40:10 -06:00
2016-10-21 10:39:31 -05:00
bool WellCollection : : havingVREPGroups ( ) const {
return having_vrep_groups_ ;
}
2012-04-25 07:03:57 -05:00
}