2013-10-25 17:28:56 +02:00
/*
Copyright 2013 Statoil ASA .
This file is part of the Open Porous Media project ( OPM ) .
OPM is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
OPM is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with OPM . If not , see < http : //www.gnu.org/licenses/>.
2013-11-08 15:55:11 +01:00
*/
2013-10-25 17:28:56 +02:00
2019-03-14 09:23:03 +01:00
# include <fnmatch.h>
2020-03-30 10:38:15 +02:00
# include <iostream>
2020-04-25 19:15:17 +02:00
# include <optional>
2020-03-30 10:38:15 +02:00
# include <stdexcept>
2014-12-12 20:56:34 +01:00
# include <string>
2020-03-30 10:38:15 +02:00
# include <unordered_set>
2014-12-12 20:56:34 +01:00
# include <vector>
2018-03-22 11:07:14 +01:00
# include <opm/common/OpmLog/LogUtil.hpp>
2020-03-13 07:36:17 +01:00
# include <opm/common/utility/numeric/cmp.hpp>
2020-04-03 17:16:02 +02:00
# include <opm/common/utility/String.hpp>
2018-03-22 11:07:14 +01:00
2020-03-16 16:02:05 +01:00
# include <opm/parser/eclipse/Python/Python.hpp>
2016-01-24 21:49:39 +01:00
# include <opm/parser/eclipse/Deck/DeckItem.hpp>
# include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
# include <opm/parser/eclipse/Deck/DeckRecord.hpp>
2019-12-29 07:21:37 +01:00
# include <opm/parser/eclipse/Deck/DeckSection.hpp>
2020-02-16 20:00:16 +01:00
# include <opm/parser/eclipse/Parser/ErrorGuard.hpp>
2016-03-16 17:15:09 +08:00
# include <opm/parser/eclipse/Parser/ParseContext.hpp>
2020-03-16 16:02:05 +01:00
# include <opm/parser/eclipse/Parser/ParserKeywords/P.hpp>
2016-01-18 17:51:15 +01:00
# include <opm/parser/eclipse/Parser/ParserKeywords/W.hpp>
2014-12-12 20:56:34 +01:00
2016-01-15 08:42:57 +01:00
# include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
2019-01-17 11:22:49 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/Action/ActionX.hpp>
2019-07-01 08:27:07 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/Action/ActionResult.hpp>
2016-01-15 08:42:57 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/DynamicState.hpp>
# include <opm/parser/eclipse/EclipseState/Schedule/DynamicVector.hpp>
2020-05-28 09:27:03 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/MSW/SICD.hpp>
2019-12-16 14:46:04 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/MSW/Valve.hpp>
# include <opm/parser/eclipse/EclipseState/Schedule/MSW/WellSegments.hpp>
2016-09-12 14:28:19 +02:00
2016-01-15 08:42:57 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/OilVaporizationProperties.hpp>
2019-07-26 17:17:06 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQConfig.hpp>
2019-06-19 13:40:27 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQActive.hpp>
2020-04-01 13:01:45 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/RPTConfig.hpp>
2016-01-15 08:42:57 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
2013-10-25 17:28:56 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp>
2016-01-15 08:42:57 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/Tuning.hpp>
2020-04-25 19:15:17 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/Network/Node.hpp>
2019-03-08 07:12:07 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WList.hpp>
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WListManager.hpp>
2019-07-03 10:04:20 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WellFoamProperties.hpp>
2019-08-13 11:56:17 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WellInjectionProperties.hpp>
2019-03-08 07:12:07 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WellPolymerProperties.hpp>
2019-08-13 11:56:17 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WellProductionProperties.hpp>
2019-11-27 13:26:28 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WellBrineProperties.hpp>
2019-03-08 07:12:07 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WellConnections.hpp>
2018-11-19 09:43:50 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/SummaryState.hpp>
2016-01-24 21:49:39 +01:00
# include <opm/parser/eclipse/Units/Dimension.hpp>
2016-01-15 08:42:57 +01:00
# include <opm/parser/eclipse/Units/UnitSystem.hpp>
2018-12-18 14:42:25 +01:00
# include <opm/parser/eclipse/Units/Units.hpp>
2015-01-14 11:41:13 +01:00
2019-06-20 11:23:06 +02:00
# include "Well/injection.hpp"
2020-06-06 08:54:04 +02:00
# include "MSW/Compsegs.hpp"
2019-03-25 10:03:16 +01:00
2013-11-08 15:55:11 +01:00
namespace Opm {
2018-10-26 09:13:26 +02:00
2019-07-07 08:46:17 +02:00
namespace {
bool name_match ( const std : : string & pattern , const std : : string & name ) {
int flags = 0 ;
return ( fnmatch ( pattern . c_str ( ) , name . c_str ( ) , flags ) = = 0 ) ;
}
2020-09-21 19:22:11 +02:00
std : : pair < std : : time_t , std : : size_t > restart_info ( const RestartIO : : RstState * rst ) {
if ( ! rst )
return std : : make_pair ( std : : time_t { 0 } , std : : size_t { 0 } ) ;
else
return rst - > header . restart_info ( ) ;
}
2019-07-07 08:46:17 +02:00
}
2017-09-27 16:34:38 +02:00
Schedule : : Schedule ( const Deck & deck ,
2016-09-08 19:42:45 +02:00
const EclipseGrid & grid ,
2019-11-21 11:44:06 +01:00
const FieldPropsManager & fp ,
2018-10-17 13:35:25 +02:00
const Runspec & runspec ,
2019-01-03 11:53:32 +01:00
const ParseContext & parseContext ,
2020-01-28 13:03:07 +01:00
ErrorGuard & errors ,
2020-03-31 10:26:55 +02:00
[[maybe_unused]] std : : shared_ptr < const Python > python ,
2020-01-28 13:03:07 +01:00
const RestartIO : : RstState * rst ) :
2020-03-22 21:02:32 +01:00
python_handle ( python ) ,
2020-01-28 13:14:32 +01:00
m_timeMap ( deck , restart_info ( rst ) ) ,
2018-10-17 13:35:25 +02:00
m_oilvaporizationproperties ( this - > m_timeMap , OilVaporizationProperties ( runspec . tabdims ( ) . getNumPVTTables ( ) ) ) ,
2016-11-08 18:29:52 +01:00
m_events ( this - > m_timeMap ) ,
2016-11-09 09:07:57 +01:00
m_modifierDeck ( this - > m_timeMap , Deck { } ) ,
2020-01-31 13:40:44 +01:00
m_tuning ( this - > m_timeMap , Tuning ( ) ) ,
2016-11-08 18:29:52 +01:00
m_messageLimits ( this - > m_timeMap ) ,
2018-10-17 13:35:25 +02:00
m_runspec ( runspec ) ,
2019-01-14 12:09:07 +01:00
wtest_config ( this - > m_timeMap , std : : make_shared < WellTestConfig > ( ) ) ,
2019-01-28 16:52:28 +01:00
wlist_manager ( this - > m_timeMap , std : : make_shared < WListManager > ( ) ) ,
2019-07-26 17:17:06 +02:00
udq_config ( this - > m_timeMap , std : : make_shared < UDQConfig > ( deck ) ) ,
2019-06-19 13:40:27 +02:00
udq_active ( this - > m_timeMap , std : : make_shared < UDQActive > ( ) ) ,
2019-09-06 07:56:42 +02:00
guide_rate_config ( this - > m_timeMap , std : : make_shared < GuideRateConfig > ( ) ) ,
2019-11-05 10:46:17 +01:00
gconsale ( this - > m_timeMap , std : : make_shared < GConSale > ( ) ) ,
2019-11-06 11:33:32 +01:00
gconsump ( this - > m_timeMap , std : : make_shared < GConSump > ( ) ) ,
2019-11-12 08:29:28 +01:00
global_whistctl_mode ( this - > m_timeMap , Well : : ProducerCMode : : CMODE_UNDEFINED ) ,
2019-08-29 18:17:37 +02:00
m_actions ( this - > m_timeMap , std : : make_shared < Action : : Actions > ( ) ) ,
2020-04-25 19:15:17 +02:00
m_network ( this - > m_timeMap , std : : make_shared < Network : : ExtNetwork > ( ) ) ,
2020-05-06 11:35:22 +02:00
m_glo ( this - > m_timeMap , std : : make_shared < GasLiftOpt > ( ) ) ,
2019-08-30 12:56:49 +02:00
rft_config ( this - > m_timeMap ) ,
2020-06-10 14:55:20 +02:00
m_nupcol ( this - > m_timeMap , runspec . nupcol ( ) ) ,
2020-04-01 11:56:07 +02:00
restart_config ( m_timeMap , deck , parseContext , errors ) ,
rpt_config ( this - > m_timeMap , std : : make_shared < RPTConfig > ( ) )
2016-05-02 17:46:20 +02:00
{
2019-08-05 18:37:01 +02:00
addGroup ( " FIELD " , 0 , deck . getActiveUnitSystem ( ) ) ;
2020-03-13 07:36:45 +01:00
if ( rst )
this - > load_rst ( * rst , grid , fp , deck . getActiveUnitSystem ( ) ) ;
2015-07-26 23:13:49 +02:00
2016-10-21 16:38:39 +02:00
/*
We can have the MESSAGES keyword anywhere in the deck , we
must therefor also scan the part of the deck prior to the
SCHEDULE section to initialize valid MessageLimits object .
*/
for ( size_t keywordIdx = 0 ; keywordIdx < deck . size ( ) ; + + keywordIdx ) {
const auto & keyword = deck . getKeyword ( keywordIdx ) ;
if ( keyword . name ( ) = = " SCHEDULE " )
break ;
if ( keyword . name ( ) = = " MESSAGES " )
2020-09-21 19:22:11 +02:00
applyMESSAGES ( keyword , 0 ) ;
2016-10-21 16:38:39 +02:00
}
2019-12-29 07:21:37 +01:00
if ( DeckSection : : hasSCHEDULE ( deck ) )
2020-03-22 21:02:32 +01:00
iterateScheduleSection ( python , deck . getInputPath ( ) , parseContext , errors , SCHEDULESection ( deck ) , grid , fp ) ;
2013-11-14 16:08:10 +01:00
}
2017-12-03 09:00:56 +01:00
2019-01-03 18:05:19 +01:00
template < typename T >
Schedule : : Schedule ( const Deck & deck ,
const EclipseGrid & grid ,
2019-11-21 11:44:06 +01:00
const FieldPropsManager & fp ,
2019-01-03 18:05:19 +01:00
const Runspec & runspec ,
const ParseContext & parseContext ,
2020-01-28 13:03:07 +01:00
T & & errors ,
2020-03-31 10:26:55 +02:00
std : : shared_ptr < const Python > python ,
2020-01-28 13:03:07 +01:00
const RestartIO : : RstState * rst ) :
2020-03-26 15:31:21 +01:00
Schedule ( deck , grid , fp , runspec , parseContext , errors , python , rst )
2019-01-03 18:05:19 +01:00
{ }
Schedule : : Schedule ( const Deck & deck ,
const EclipseGrid & grid ,
2019-11-21 11:44:06 +01:00
const FieldPropsManager & fp ,
2020-01-28 13:03:07 +01:00
const Runspec & runspec ,
2020-03-31 10:26:55 +02:00
std : : shared_ptr < const Python > python ,
2020-01-28 13:03:07 +01:00
const RestartIO : : RstState * rst ) :
2020-03-26 15:31:21 +01:00
Schedule ( deck , grid , fp , runspec , ParseContext ( ) , ErrorGuard ( ) , python , rst )
2019-01-03 18:05:19 +01:00
{ }
2020-03-31 10:26:55 +02:00
Schedule : : Schedule ( const Deck & deck , const EclipseState & es , const ParseContext & parse_context , ErrorGuard & errors , std : : shared_ptr < const Python > python , const RestartIO : : RstState * rst ) :
2017-12-03 09:00:56 +01:00
Schedule ( deck ,
es . getInputGrid ( ) ,
2019-11-21 11:44:06 +01:00
es . fieldProps ( ) ,
2018-10-17 13:35:25 +02:00
es . runspec ( ) ,
2019-01-03 11:53:32 +01:00
parse_context ,
2020-01-28 13:03:07 +01:00
errors ,
2020-03-26 15:31:21 +01:00
python ,
2020-01-28 13:03:07 +01:00
rst )
2017-12-03 09:00:56 +01:00
{ }
2018-04-24 14:03:29 +02:00
2019-01-03 18:05:19 +01:00
template < typename T >
2020-03-31 10:26:55 +02:00
Schedule : : Schedule ( const Deck & deck , const EclipseState & es , const ParseContext & parse_context , T & & errors , std : : shared_ptr < const Python > python , const RestartIO : : RstState * rst ) :
2019-01-03 18:05:19 +01:00
Schedule ( deck ,
es . getInputGrid ( ) ,
2019-11-21 11:44:06 +01:00
es . fieldProps ( ) ,
2019-01-03 18:05:19 +01:00
es . runspec ( ) ,
parse_context ,
2020-01-28 13:03:07 +01:00
errors ,
2020-03-26 15:31:21 +01:00
python ,
2020-01-28 13:03:07 +01:00
rst )
2019-01-03 18:05:19 +01:00
{ }
2020-03-31 10:26:55 +02:00
Schedule : : Schedule ( const Deck & deck , const EclipseState & es , std : : shared_ptr < const Python > python , const RestartIO : : RstState * rst ) :
2020-03-26 15:31:21 +01:00
Schedule ( deck , es , ParseContext ( ) , ErrorGuard ( ) , python , rst )
2019-01-03 18:05:19 +01:00
{ }
2018-04-24 14:03:29 +02:00
2020-03-26 15:31:21 +01:00
Schedule : : Schedule ( const Deck & deck , const EclipseState & es , const RestartIO : : RstState * rst ) :
2020-03-31 10:26:55 +02:00
Schedule ( deck , es , ParseContext ( ) , ErrorGuard ( ) , std : : make_shared < const Python > ( ) , rst )
2020-03-26 15:31:21 +01:00
{ }
2020-04-10 09:15:05 +02:00
/*
In general the serializeObject ( ) instances are used as targets for
deserialization , i . e . the serialized buffer is unpacked into this
instance . However the Schedule object is a top level object , and the
simulator will instantiate and manage a Schedule object to unpack into , so
the instance created here is only for testing .
*/
2020-03-19 15:21:20 +01:00
Schedule Schedule : : serializeObject ( )
{
2020-04-10 09:15:05 +02:00
auto python = std : : make_shared < Python > ( Python : : Enable : : OFF ) ;
Schedule result ( python ) ;
2020-03-19 15:21:20 +01:00
result . m_timeMap = TimeMap : : serializeObject ( ) ;
result . wells_static . insert ( { " test1 " , { { std : : make_shared < Opm : : Well > ( Opm : : Well : : serializeObject ( ) ) } , 1 } } ) ;
result . groups . insert ( { " test2 " , { { std : : make_shared < Opm : : Group > ( Opm : : Group : : serializeObject ( ) ) } , 1 } } ) ;
result . m_oilvaporizationproperties = { { Opm : : OilVaporizationProperties : : serializeObject ( ) } , 1 } ;
result . m_events = Events : : serializeObject ( ) ;
result . m_modifierDeck = DynamicVector < Deck > ( { Deck : : serializeObject ( ) } ) ;
result . m_tuning = { { Tuning : : serializeObject ( ) } , 1 } ;
result . m_messageLimits = MessageLimits : : serializeObject ( ) ;
result . m_runspec = Runspec : : serializeObject ( ) ;
result . vfpprod_tables = { { 1 , { { std : : make_shared < VFPProdTable > ( VFPProdTable : : serializeObject ( ) ) } , 1 } } } ;
result . vfpinj_tables = { { 2 , { { std : : make_shared < VFPInjTable > ( VFPInjTable : : serializeObject ( ) ) } , 1 } } } ;
result . wtest_config = { { std : : make_shared < WellTestConfig > ( WellTestConfig : : serializeObject ( ) ) } , 1 } ;
result . wlist_manager = { { std : : make_shared < WListManager > ( WListManager : : serializeObject ( ) ) } , 1 } ;
result . udq_config = { { std : : make_shared < UDQConfig > ( UDQConfig : : serializeObject ( ) ) } , 1 } ;
2020-05-06 21:10:52 +02:00
result . m_network = { { std : : make_shared < Network : : ExtNetwork > ( Network : : ExtNetwork : : serializeObject ( ) ) } , 1 } ;
2020-05-06 11:35:22 +02:00
result . m_glo = { { std : : make_shared < GasLiftOpt > ( GasLiftOpt : : serializeObject ( ) ) } , 1 } ;
2020-03-19 15:21:20 +01:00
result . udq_active = { { std : : make_shared < UDQActive > ( UDQActive : : serializeObject ( ) ) } , 1 } ;
result . guide_rate_config = { { std : : make_shared < GuideRateConfig > ( GuideRateConfig : : serializeObject ( ) ) } , 1 } ;
result . gconsale = { { std : : make_shared < GConSale > ( GConSale : : serializeObject ( ) ) } , 1 } ;
result . gconsump = { { std : : make_shared < GConSump > ( GConSump : : serializeObject ( ) ) } , 1 } ;
result . global_whistctl_mode = { { Well : : ProducerCMode : : CRAT } , 1 } ;
result . m_actions = { { std : : make_shared < Action : : Actions > ( Action : : Actions : : serializeObject ( ) ) } , 1 } ;
result . rft_config = RFTConfig : : serializeObject ( ) ;
result . m_nupcol = { { 1 } , 1 } ;
result . restart_config = RestartConfig : : serializeObject ( ) ;
result . wellgroup_events = { { " test " , Events : : serializeObject ( ) } } ;
return result ;
}
2019-12-16 14:27:16 +01:00
2017-06-19 09:45:43 +02:00
std : : time_t Schedule : : getStartTime ( ) const {
return this - > posixStartTime ( ) ;
2016-05-24 16:55:32 +02:00
}
time_t Schedule : : posixStartTime ( ) const {
2017-06-19 09:45:43 +02:00
return m_timeMap . getStartTime ( 0 ) ;
2015-10-02 10:49:23 +02:00
}
2016-09-12 14:28:19 +02:00
time_t Schedule : : posixEndTime ( ) const {
2017-06-19 09:45:43 +02:00
return this - > m_timeMap . getEndTime ( ) ;
2013-11-14 16:08:10 +01:00
}
2018-07-11 13:54:49 +02:00
2020-03-22 21:02:32 +01:00
void Schedule : : handleKeyword ( std : : shared_ptr < const Python > python ,
const std : : string & input_path ,
2020-03-16 16:02:05 +01:00
size_t currentStep ,
2018-07-11 13:54:49 +02:00
const SCHEDULESection & section ,
size_t keywordIdx ,
const DeckKeyword & keyword ,
const ParseContext & parseContext ,
2019-01-03 11:53:32 +01:00
ErrorGuard & errors ,
2018-07-11 13:54:49 +02:00
const EclipseGrid & grid ,
2019-11-21 11:44:06 +01:00
const FieldPropsManager & fp ,
2018-07-11 13:54:49 +02:00
std : : vector < std : : pair < const DeckKeyword * , size_t > > & rftProperties ) {
2018-04-06 15:48:27 +02:00
2020-09-21 19:22:11 +02:00
const HandlerContext handlerContext { section , keyword , keywordIdx , currentStep , grid , fp } ;
2018-05-14 04:18:07 +02:00
2020-09-21 19:22:11 +02:00
if ( handleNormalKeyword ( handlerContext , parseContext , errors ) )
return ;
2020-08-31 18:24:09 +02:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WRFT " )
rftProperties . push_back ( std : : make_pair ( & keyword , currentStep ) ) ;
2016-01-20 14:58:32 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WRFTPLT " )
rftProperties . push_back ( std : : make_pair ( & keyword , currentStep ) ) ;
2015-04-17 18:51:42 +02:00
2020-03-16 16:02:05 +01:00
else if ( keyword . name ( ) = = " PYACTION " )
2020-03-22 21:02:32 +01:00
handlePYACTION ( python , input_path , keyword , currentStep ) ;
2018-07-11 13:54:49 +02:00
}
2017-11-21 09:55:07 +01:00
2018-04-12 19:02:15 +02:00
2020-03-22 21:02:32 +01:00
void Schedule : : iterateScheduleSection ( std : : shared_ptr < const Opm : : Python > python , const std : : string & input_path , const ParseContext & parseContext , ErrorGuard & errors , const SCHEDULESection & section , const EclipseGrid & grid ,
2020-01-13 15:46:06 +01:00
const FieldPropsManager & fp ) {
2018-07-11 13:54:49 +02:00
std : : vector < std : : pair < const DeckKeyword * , size_t > > rftProperties ;
size_t keywordIdx = 0 ;
2020-03-30 10:38:15 +02:00
/*
The keywords in the skiprest_whitelist set are loaded from the
SCHEDULE section even though the SKIPREST keyword is in action . The
full list includes some additional keywords which we do not support at
all .
*/
std : : unordered_set < std : : string > skiprest_whitelist = { " VFPPROD " , " VFPINJ " , " RPTSCHED " , " RPTRST " , " TUNING " , " MESSAGES " } ;
2018-04-12 19:02:15 +02:00
2020-03-13 07:36:45 +01:00
size_t currentStep ;
if ( this - > m_timeMap . skiprest ( ) )
currentStep = 0 ;
else
currentStep = this - > m_timeMap . restart_offset ( ) ;
2018-07-11 13:54:49 +02:00
while ( true ) {
const auto & keyword = section . getKeyword ( keywordIdx ) ;
if ( keyword . name ( ) = = " ACTIONX " ) {
2020-05-04 16:01:57 +02:00
Action : : ActionX action ( keyword , this - > m_timeMap . getStartTime ( currentStep ) ) ;
2018-07-11 13:54:49 +02:00
while ( true ) {
keywordIdx + + ;
if ( keywordIdx = = section . size ( ) )
throw std : : invalid_argument ( " Invalid ACTIONX section - missing ENDACTIO " ) ;
const auto & action_keyword = section . getKeyword ( keywordIdx ) ;
if ( action_keyword . name ( ) = = " ENDACTIO " )
break ;
2019-07-01 08:27:07 +02:00
if ( Action : : ActionX : : valid_keyword ( action_keyword . name ( ) ) )
2019-02-03 18:07:04 +01:00
action . addKeyword ( action_keyword ) ;
else {
2018-10-26 09:13:26 +02:00
std : : string msg = " The keyword " + action_keyword . name ( ) + " is not supported in a ACTIONX block. " ;
2019-01-03 11:53:32 +01:00
parseContext . handleError ( ParseContext : : ACTIONX_ILLEGAL_KEYWORD , msg , errors ) ;
2019-02-03 18:07:04 +01:00
}
2015-10-30 12:55:17 +01:00
}
2019-08-29 18:17:37 +02:00
this - > addACTIONX ( action , currentStep ) ;
2020-01-28 20:31:24 +01:00
}
else if ( keyword . name ( ) = = " DATES " ) {
checkIfAllConnectionsIsShut ( currentStep ) ;
currentStep + = keyword . size ( ) ;
}
else if ( keyword . name ( ) = = " TSTEP " ) {
checkIfAllConnectionsIsShut ( currentStep ) ;
currentStep + = keyword . getRecord ( 0 ) . getItem ( 0 ) . data_size ( ) ;
}
else {
2020-03-30 10:38:15 +02:00
if ( currentStep > = this - > m_timeMap . restart_offset ( ) | | skiprest_whitelist . count ( keyword . name ( ) ) )
2020-09-21 19:22:11 +02:00
this - > handleKeyword ( python , input_path , currentStep , section , keywordIdx , keyword , parseContext , errors , grid , fp , rftProperties ) ;
2020-01-28 20:31:24 +01:00
else
OpmLog : : info ( " Skipping keyword: " + keyword . name ( ) + " while loading SCHEDULE section " ) ;
}
2018-07-11 13:54:49 +02:00
keywordIdx + + ;
if ( keywordIdx = = section . size ( ) )
break ;
2013-11-05 15:25:47 +01:00
}
2017-09-26 09:32:29 +02:00
2018-07-11 13:54:49 +02:00
checkIfAllConnectionsIsShut ( currentStep ) ;
2015-01-16 14:51:57 +01:00
2015-02-12 08:38:26 +01:00
for ( auto rftPair = rftProperties . begin ( ) ; rftPair ! = rftProperties . end ( ) ; + + rftPair ) {
2016-02-09 12:09:40 +01:00
const DeckKeyword & keyword = * rftPair - > first ;
2015-02-12 08:38:26 +01:00
size_t timeStep = rftPair - > second ;
2019-04-03 18:47:02 +02:00
if ( keyword . name ( ) = = " WRFT " )
2020-09-21 19:22:11 +02:00
applyWRFT ( keyword , timeStep ) ;
2015-02-06 14:54:03 +01:00
2019-04-03 18:47:02 +02:00
if ( keyword . name ( ) = = " WRFTPLT " )
2020-09-21 19:22:11 +02:00
applyWRFTPLT ( keyword , timeStep ) ;
2015-02-06 14:54:03 +01:00
}
2015-01-16 14:51:57 +01:00
2015-07-26 23:13:49 +02:00
checkUnhandledKeywords ( section ) ;
2013-11-05 15:25:47 +01:00
}
2019-08-29 18:17:37 +02:00
void Schedule : : addACTIONX ( const Action : : ActionX & action , std : : size_t currentStep ) {
auto new_actions = std : : make_shared < Action : : Actions > ( this - > actions ( currentStep ) ) ;
new_actions - > add ( action ) ;
this - > m_actions . update ( currentStep , new_actions ) ;
}
2020-09-21 19:22:11 +02:00
void Schedule : : checkUnhandledKeywords ( const SCHEDULESection & /*section*/ ) const {
2015-08-07 15:13:52 +02:00
}
2020-09-21 19:22:11 +02:00
void Schedule : : handlePYACTION ( std : : shared_ptr < const Python > python , const std : : string & input_path , const DeckKeyword & keyword , std : : size_t currentStep ) {
2020-03-22 21:02:32 +01:00
if ( ! python - > enabled ( ) ) {
//Must have a real Python instance here - to ensure that IMPORT works
2020-03-16 16:02:05 +01:00
const auto & loc = keyword . location ( ) ;
OpmLog : : warning ( " This version of flow is built without support for Python. Keyword PYACTION in file: " + loc . filename + " line: " + std : : to_string ( loc . lineno ) + " is ignored. " ) ;
return ;
}
2020-09-25 10:26:17 +02:00
const auto & name = keyword . getRecord ( 0 ) . getItem < ParserKeywords : : PYACTION : : NAME > ( ) . get < std : : string > ( 0 ) ;
const auto & run_count = Action : : PyAction : : from_string ( keyword . getRecord ( 0 ) . getItem < ParserKeywords : : PYACTION : : RUN_COUNT > ( ) . get < std : : string > ( 0 ) ) ;
const auto & module_arg = keyword . getRecord ( 1 ) . getItem < ParserKeywords : : PYACTION : : FILENAME > ( ) . get < std : : string > ( 0 ) ;
2020-03-22 21:02:32 +01:00
std : : string module ;
if ( input_path . empty ( ) )
module = module_arg ;
else
module = input_path + " / " + module_arg ;
2020-03-16 16:02:05 +01:00
2020-03-22 21:02:32 +01:00
Action : : PyAction pyaction ( python , name , run_count , module ) ;
2020-03-16 16:02:05 +01:00
auto new_actions = std : : make_shared < Action : : Actions > ( this - > actions ( currentStep ) ) ;
new_actions - > add ( pyaction ) ;
this - > m_actions . update ( currentStep , new_actions ) ;
}
2020-09-25 10:12:55 +02:00
void Schedule : : applyEXIT ( const DeckKeyword & keyword , std : : size_t report_step ) {
2020-09-25 10:26:17 +02:00
int status = keyword . getRecord ( 0 ) . getItem < ParserKeywords : : EXIT : : STATUS_CODE > ( ) . get < int > ( 0 ) ;
2020-04-12 09:30:23 +02:00
OpmLog : : info ( " Simulation exit with status: " + std : : to_string ( status ) + " requested as part of ACTIONX at report_step: " + std : : to_string ( report_step ) ) ;
this - > exit_status = status ;
}
2020-01-08 10:17:52 +01:00
void Schedule : : shut_well ( const std : : string & well_name , std : : size_t report_step ) {
2020-01-08 10:18:31 +01:00
this - > updateWellStatus ( well_name , report_step , Well : : Status : : SHUT , true ) ;
2020-01-08 10:17:52 +01:00
}
void Schedule : : open_well ( const std : : string & well_name , std : : size_t report_step ) {
2020-01-08 10:18:31 +01:00
this - > updateWellStatus ( well_name , report_step , Well : : Status : : OPEN , true ) ;
2020-01-08 10:17:52 +01:00
}
void Schedule : : stop_well ( const std : : string & well_name , std : : size_t report_step ) {
2020-01-08 10:18:31 +01:00
this - > updateWellStatus ( well_name , report_step , Well : : Status : : STOP , true ) ;
2020-01-08 10:17:52 +01:00
}
2019-11-12 08:29:28 +01:00
void Schedule : : updateWell ( std : : shared_ptr < Well > well , size_t reportStep ) {
2019-03-23 16:11:37 +01:00
auto & dynamic_state = this - > wells_static . at ( well - > name ( ) ) ;
2020-01-13 15:46:06 +01:00
dynamic_state . update ( reportStep , std : : move ( well ) ) ;
2015-06-23 14:20:31 +02:00
}
2019-03-23 16:11:37 +01:00
/*
Function is quite dangerous - because if this is called while holding a
2019-11-12 08:29:28 +01:00
Well pointer that will go stale and needs to be refreshed .
2019-03-23 16:11:37 +01:00
*/
2020-01-08 10:18:31 +01:00
bool Schedule : : updateWellStatus ( const std : : string & well_name , size_t reportStep , Well : : Status status , bool update_connections ) {
2019-03-23 16:11:37 +01:00
bool update = false ;
2020-01-08 10:18:31 +01:00
auto & dynamic_state = this - > wells_static . at ( well_name ) ;
auto well2 = std : : make_shared < Well > ( * dynamic_state [ reportStep ] ) ;
if ( well2 - > updateStatus ( status , update_connections ) ) {
m_events . addEvent ( ScheduleEvents : : WELL_STATUS_CHANGE , reportStep ) ;
this - > addWellGroupEvent ( well2 - > name ( ) , ScheduleEvents : : WELL_STATUS_CHANGE , reportStep ) ;
this - > updateWell ( well2 , reportStep ) ;
update = true ;
if ( status = = Well : : Status : : OPEN )
this - > rft_config . addWellOpen ( well_name , reportStep ) ;
2019-03-23 16:11:37 +01:00
}
return update ;
2013-11-08 15:55:11 +01:00
}
2020-09-16 16:06:02 +02:00
/*
This routine is called when UDQ keywords is added in an ACTIONX block .
*/
void Schedule : : updateUDQ ( const DeckKeyword & keyword , std : : size_t current_step ) {
const auto & current = * this - > udq_config . get ( current_step ) ;
std : : shared_ptr < UDQConfig > new_udq = std : : make_shared < UDQConfig > ( current ) ;
for ( const auto & record : keyword )
new_udq - > add_record ( record , current_step ) ;
auto next_index = this - > udq_config . update_equal ( current_step , new_udq ) ;
if ( next_index ) {
for ( const auto & [ report_step , udq_ptr ] : this - > udq_config . unique ( ) ) {
if ( report_step > current_step ) {
for ( const auto & record : keyword )
udq_ptr - > add_record ( record , current_step ) ;
}
}
}
}
2019-01-28 16:52:28 +01:00
2020-09-21 19:22:11 +02:00
void Schedule : : applyWELOPEN ( const DeckKeyword & keyword , std : : size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors , const std : : vector < std : : string > & matching_wells ) {
2015-06-02 13:26:37 +02:00
2019-04-03 18:47:02 +02:00
auto conn_defaulted = [ ] ( const DeckRecord & rec ) {
2016-12-01 13:44:38 +01:00
auto defaulted = [ ] ( const DeckItem & item ) {
return item . defaultApplied ( 0 ) ;
} ;
2015-01-13 15:06:06 +01:00
2016-12-01 13:44:38 +01:00
return std : : all_of ( rec . begin ( ) + 2 , rec . end ( ) , defaulted ) ;
} ;
2015-06-23 14:20:31 +02:00
2019-11-12 08:29:28 +01:00
constexpr auto open = Well : : Status : : OPEN ;
2019-12-02 11:12:17 +01:00
bool action_mode = ! matching_wells . empty ( ) ;
2015-01-16 17:49:28 +01:00
2016-12-01 13:44:38 +01:00
for ( const auto & record : keyword ) {
2018-05-03 09:18:53 +02:00
const auto & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
2016-12-01 13:44:38 +01:00
const auto & status_str = record . getItem ( " STATUS " ) . getTrimmedString ( 0 ) ;
2019-03-23 16:11:37 +01:00
const auto well_names = this - > wellNames ( wellNamePattern , currentStep , matching_wells ) ;
2019-03-23 16:51:32 +01:00
if ( well_names . empty ( ) )
2020-02-14 15:06:28 +01:00
invalidNamePattern ( wellNamePattern , currentStep , parseContext , errors , keyword ) ;
2018-05-03 09:18:53 +02:00
2016-12-01 13:44:38 +01:00
/* if all records are defaulted or just the status is set, only
* well status is updated
*/
2019-04-03 18:47:02 +02:00
if ( conn_defaulted ( record ) ) {
2019-11-12 08:29:28 +01:00
const auto well_status = Well : : StatusFromString ( status_str ) ;
2019-03-23 16:11:37 +01:00
for ( const auto & wname : well_names ) {
{
2019-11-12 08:29:28 +01:00
const auto & well = this - > getWell ( wname , currentStep ) ;
2019-05-04 12:00:32 +02:00
if ( well_status = = open & & ! well . canOpen ( ) ) {
2019-03-23 16:11:37 +01:00
auto days = m_timeMap . getTimePassedUntil ( currentStep ) / ( 60 * 60 * 24 ) ;
std : : string msg = " Well " + wname
+ " where crossflow is banned has zero total rate. "
+ " This well is prevented from opening at "
+ std : : to_string ( days ) + " days " ;
OpmLog : : note ( msg ) ;
} else {
2020-01-08 10:18:31 +01:00
this - > updateWellStatus ( wname , currentStep , well_status , false ) ;
2019-03-23 16:11:37 +01:00
if ( well_status = = open )
this - > rft_config . addWellOpen ( wname , currentStep ) ;
2019-11-29 18:11:45 +01:00
OpmLog : : info ( Well : : Status2String ( well_status ) + " well: " + wname + " at report step: " + std : : to_string ( currentStep ) ) ;
2019-03-23 16:11:37 +01:00
}
2015-11-05 14:37:47 +01:00
}
2015-01-13 11:25:28 +01:00
}
2016-12-01 13:44:38 +01:00
continue ;
}
2019-03-23 16:11:37 +01:00
for ( const auto & wname : well_names ) {
2019-08-27 23:14:32 +02:00
const auto comp_status = Connection : : StateFromString ( status_str ) ;
2019-03-23 16:11:37 +01:00
{
auto & dynamic_state = this - > wells_static . at ( wname ) ;
2019-11-12 08:29:28 +01:00
auto well_ptr = std : : make_shared < Well > ( * dynamic_state [ currentStep ] ) ;
2019-12-02 11:12:17 +01:00
if ( well_ptr - > handleWELOPEN ( record , comp_status , action_mode ) ) {
2019-03-23 16:11:37 +01:00
// The updateWell call breaks test at line 825 and 831 in ScheduleTests
this - > updateWell ( well_ptr , currentStep ) ;
2019-11-29 18:11:45 +01:00
const auto well_status = Well : : StatusFromString ( status_str ) ;
OpmLog : : info ( Well : : Status2String ( well_status ) + " well: " + wname + " at report step: " + std : : to_string ( currentStep ) ) ;
}
2019-03-23 16:11:37 +01:00
}
2016-12-01 13:44:38 +01:00
m_events . addEvent ( ScheduleEvents : : COMPLETION_CHANGE , currentStep ) ;
2015-03-25 08:20:22 +01:00
}
}
}
2020-09-21 19:22:11 +02:00
void Schedule : : applyMESSAGES ( const DeckKeyword & keyword , std : : size_t currentStep ) {
2016-10-14 10:06:35 +08:00
const auto & record = keyword . getRecord ( 0 ) ;
2016-10-21 16:38:39 +02:00
using set_limit_fptr = decltype ( std : : mem_fn ( & MessageLimits : : setMessagePrintLimit ) ) ;
2016-10-24 17:06:50 +02:00
static const std : : pair < std : : string , set_limit_fptr > setters [ ] = {
2020-09-21 19:22:11 +02:00
{ " MESSAGE_PRINT_LIMIT " , std : : mem_fn ( & MessageLimits : : setMessagePrintLimit ) } ,
{ " COMMENT_PRINT_LIMIT " , std : : mem_fn ( & MessageLimits : : setCommentPrintLimit ) } ,
{ " WARNING_PRINT_LIMIT " , std : : mem_fn ( & MessageLimits : : setWarningPrintLimit ) } ,
{ " PROBLEM_PRINT_LIMIT " , std : : mem_fn ( & MessageLimits : : setProblemPrintLimit ) } ,
{ " ERROR_PRINT_LIMIT " , std : : mem_fn ( & MessageLimits : : setErrorPrintLimit ) } ,
{ " BUG_PRINT_LIMIT " , std : : mem_fn ( & MessageLimits : : setBugPrintLimit ) } ,
{ " MESSAGE_STOP_LIMIT " , std : : mem_fn ( & MessageLimits : : setMessageStopLimit ) } ,
{ " COMMENT_STOP_LIMIT " , std : : mem_fn ( & MessageLimits : : setCommentStopLimit ) } ,
{ " WARNING_STOP_LIMIT " , std : : mem_fn ( & MessageLimits : : setWarningStopLimit ) } ,
{ " PROBLEM_STOP_LIMIT " , std : : mem_fn ( & MessageLimits : : setProblemStopLimit ) } ,
{ " ERROR_STOP_LIMIT " , std : : mem_fn ( & MessageLimits : : setErrorStopLimit ) } ,
{ " BUG_STOP_LIMIT " , std : : mem_fn ( & MessageLimits : : setBugStopLimit ) } ,
} ;
2016-10-21 16:38:39 +02:00
for ( const auto & pair : setters ) {
const auto & item = record . getItem ( pair . first ) ;
if ( ! item . defaultApplied ( 0 ) ) {
2016-10-24 17:06:50 +02:00
const set_limit_fptr & fptr = pair . second ;
2016-10-21 16:38:39 +02:00
int value = item . get < int > ( 0 ) ;
fptr ( this - > m_messageLimits , currentStep , value ) ;
}
}
2016-10-14 10:06:35 +08:00
}
2020-09-21 19:22:11 +02:00
void Schedule : : applyWRFT ( const DeckKeyword & keyword , std : : size_t currentStep ) {
2015-02-12 08:38:26 +01:00
/* Rule for handling RFT: Request current RFT data output for specified wells, plus output when
* any well is subsequently opened
*/
2015-02-06 14:54:03 +01:00
2016-02-09 12:09:40 +01:00
for ( const auto & record : keyword ) {
2015-02-06 14:54:03 +01:00
2016-02-09 12:09:40 +01:00
const std : : string & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
2019-03-23 16:51:32 +01:00
const auto well_names = wellNames ( wellNamePattern , currentStep ) ;
2019-04-10 07:44:45 +02:00
for ( const auto & well_name : well_names )
2019-08-31 09:44:31 +02:00
this - > rft_config . updateRFT ( well_name , currentStep , RFTConfig : : RFT : : YES ) ;
2019-04-10 07:44:45 +02:00
2015-02-06 14:54:03 +01:00
}
2019-04-03 18:47:02 +02:00
this - > rft_config . setWellOpenRFT ( currentStep ) ;
2015-02-06 14:54:03 +01:00
}
2020-09-21 19:22:11 +02:00
void Schedule : : applyWRFTPLT ( const DeckKeyword & keyword , std : : size_t currentStep ) {
2016-02-09 12:09:40 +01:00
for ( const auto & record : keyword ) {
const std : : string & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
2015-02-06 14:54:03 +01:00
2019-08-31 09:44:31 +02:00
RFTConfig : : RFT RFTKey = RFTConfig : : RFTFromString ( record . getItem ( " OUTPUT_RFT " ) . getTrimmedString ( 0 ) ) ;
RFTConfig : : PLT PLTKey = RFTConfig : : PLTFromString ( record . getItem ( " OUTPUT_PLT " ) . getTrimmedString ( 0 ) ) ;
2019-03-23 16:51:32 +01:00
const auto well_names = wellNames ( wellNamePattern , currentStep ) ;
for ( const auto & well_name : well_names ) {
2019-04-03 18:47:02 +02:00
this - > rft_config . updateRFT ( well_name , currentStep , RFTKey ) ;
this - > rft_config . updatePLT ( well_name , currentStep , PLTKey ) ;
2015-02-06 14:54:03 +01:00
}
}
}
2013-11-14 16:08:10 +01:00
2019-04-03 18:47:02 +02:00
const RFTConfig & Schedule : : rftConfig ( ) const {
return this - > rft_config ;
}
2020-09-21 19:22:11 +02:00
void Schedule : : invalidNamePattern ( const std : : string & namePattern , std : : size_t report_step , const ParseContext & parseContext , ErrorGuard & errors , const DeckKeyword & keyword ) const {
std : : string msg = " Error when handling " + keyword . name ( ) + " at step: " + std : : to_string ( report_step ) + " . No names match " + namePattern ;
2019-01-03 11:53:32 +01:00
parseContext . handleError ( ParseContext : : SCHEDULE_INVALID_NAME , msg , errors ) ;
2018-04-22 10:25:17 +02:00
}
2016-10-12 12:26:14 +02:00
const TimeMap & Schedule : : getTimeMap ( ) const {
2016-11-08 18:29:52 +01:00
return this - > m_timeMap ;
2013-10-25 17:28:56 +02:00
}
2020-05-07 17:25:11 +02:00
GTNode Schedule : : groupTree ( const std : : string & root_node , std : : size_t report_step , std : : size_t level , const std : : optional < std : : string > & parent_name ) const {
2019-11-12 08:29:28 +01:00
auto root_group = this - > getGroup ( root_node , report_step ) ;
2020-05-07 17:25:11 +02:00
GTNode tree ( root_group , level , parent_name ) ;
2019-07-25 11:46:15 +02:00
for ( const auto & wname : root_group . wells ( ) ) {
2019-11-12 08:29:28 +01:00
const auto & well = this - > getWell ( wname , report_step ) ;
2019-07-25 11:46:15 +02:00
tree . add_well ( well ) ;
}
for ( const auto & gname : root_group . groups ( ) ) {
2020-05-07 17:25:11 +02:00
auto child_group = this - > groupTree ( gname , report_step , level + 1 , root_node ) ;
2019-07-25 11:46:15 +02:00
tree . add_group ( child_group ) ;
}
return tree ;
}
GTNode Schedule : : groupTree ( const std : : string & root_node , std : : size_t report_step ) const {
2020-05-07 17:25:11 +02:00
return this - > groupTree ( root_node , report_step , 0 , { } ) ;
2019-07-25 11:46:15 +02:00
}
GTNode Schedule : : groupTree ( std : : size_t report_step ) const {
return this - > groupTree ( " FIELD " , report_step ) ;
}
2019-06-08 12:25:29 +02:00
void Schedule : : addWell ( const std : : string & wellName ,
const DeckRecord & record ,
size_t timeStep ,
2019-08-28 07:06:58 +02:00
Connection : : Order wellConnectionOrder ,
2020-01-30 10:37:57 +01:00
const UnitSystem & unit_system )
{
2014-01-29 11:48:02 +01:00
// We change from eclipse's 1 - n, to a 0 - n-1 solution
2016-02-09 12:09:40 +01:00
int headI = record . getItem ( " HEAD_I " ) . get < int > ( 0 ) - 1 ;
int headJ = record . getItem ( " HEAD_J " ) . get < int > ( 0 ) - 1 ;
2018-12-20 12:10:14 +01:00
Phase preferredPhase ;
2020-01-30 10:37:57 +01:00
{
const std : : string phaseStr = record . getItem ( " PHASE " ) . getTrimmedString ( 0 ) ;
if ( phaseStr = = " LIQ " ) {
// We need a workaround in case the preferred phase is "LIQ",
// which is not proper phase and will cause the get_phase()
// function to throw. In that case we choose to treat it as OIL.
preferredPhase = Phase : : OIL ;
OpmLog : : warning ( " LIQ_PREFERRED_PHASE " ,
" LIQ preferred phase not supported for well " + wellName + " , using OIL instead " ) ;
} else
preferredPhase = get_phase ( phaseStr ) ;
2018-12-20 12:10:14 +01:00
}
2016-02-09 12:09:40 +01:00
const auto & refDepthItem = record . getItem ( " REF_DEPTH " ) ;
2016-11-22 13:18:43 +01:00
double refDepth = refDepthItem . hasValue ( 0 )
2020-01-30 10:37:57 +01:00
? refDepthItem . getSIDouble ( 0 )
: - 1.0 ;
2014-08-25 11:20:54 +02:00
2018-11-02 15:21:28 +01:00
double drainageRadius = record . getItem ( " D_RADIUS " ) . getSIDouble ( 0 ) ;
2015-10-06 15:47:07 +02:00
bool allowCrossFlow = true ;
2016-02-09 12:09:40 +01:00
const std : : string & allowCrossFlowStr = record . getItem < ParserKeywords : : WELSPECS : : CROSSFLOW > ( ) . getTrimmedString ( 0 ) ;
2015-10-06 15:47:07 +02:00
if ( allowCrossFlowStr = = " NO " )
allowCrossFlow = false ;
2016-06-29 14:11:11 +02:00
bool automaticShutIn = true ;
const std : : string & automaticShutInStr = record . getItem < ParserKeywords : : WELSPECS : : AUTO_SHUTIN > ( ) . getTrimmedString ( 0 ) ;
if ( automaticShutInStr = = " STOP " ) {
automaticShutIn = false ;
}
2020-01-30 10:37:57 +01:00
const std : : string & group = record . getItem < ParserKeywords : : WELSPECS : : GROUP > ( ) . getTrimmedString ( 0 ) ;
2020-09-25 10:26:17 +02:00
auto pvt_table = record . getItem < ParserKeywords : : WELSPECS : : P_TABLE > ( ) . get < int > ( 0 ) ;
auto gas_inflow = Well : : GasInflowEquationFromString ( record . getItem < ParserKeywords : : WELSPECS : : INFLOW_EQ > ( ) . get < std : : string > ( 0 ) ) ;
2020-01-30 10:37:57 +01:00
this - > addWell ( wellName ,
group ,
headI ,
headJ ,
preferredPhase ,
refDepth ,
drainageRadius ,
allowCrossFlow ,
automaticShutIn ,
2020-04-15 10:45:32 +02:00
pvt_table ,
2020-04-19 08:37:48 +02:00
gas_inflow ,
2020-01-30 10:37:57 +01:00
timeStep ,
wellConnectionOrder ,
unit_system ) ;
}
2020-02-14 14:18:22 +01:00
void Schedule : : addWell ( Well well , size_t report_step ) {
const std : : string wname = well . name ( ) ;
m_events . addEvent ( ScheduleEvents : : NEW_WELL , report_step ) ;
wellgroup_events . insert ( std : : make_pair ( wname , Events ( this - > m_timeMap ) ) ) ;
this - > addWellGroupEvent ( wname , ScheduleEvents : : NEW_WELL , report_step ) ;
well . setInsertIndex ( this - > wells_static . size ( ) ) ;
this - > wells_static . insert ( std : : make_pair ( wname , DynamicState < std : : shared_ptr < Well > > ( m_timeMap , nullptr ) ) ) ;
auto & dynamic_well_state = this - > wells_static . at ( wname ) ;
dynamic_well_state . update ( report_step , std : : make_shared < Well > ( std : : move ( well ) ) ) ;
}
2020-01-30 10:37:57 +01:00
void Schedule : : addWell ( const std : : string & wellName ,
const std : : string & group ,
int headI ,
int headJ ,
Phase preferredPhase ,
double refDepth ,
double drainageRadius ,
bool allowCrossFlow ,
bool automaticShutIn ,
2020-04-15 10:45:32 +02:00
int pvt_table ,
2020-04-19 08:37:48 +02:00
Well : : GasInflowEquation gas_inflow ,
2020-01-30 10:37:57 +01:00
size_t timeStep ,
Connection : : Order wellConnectionOrder ,
const UnitSystem & unit_system ) {
2020-02-14 14:18:22 +01:00
Well well ( wellName ,
group ,
timeStep ,
0 ,
headI , headJ ,
refDepth ,
2020-03-03 10:52:08 +01:00
WellType ( preferredPhase ) ,
2020-02-14 14:18:22 +01:00
this - > global_whistctl_mode [ timeStep ] ,
wellConnectionOrder ,
unit_system ,
this - > getUDQConfig ( timeStep ) . params ( ) . undefinedValue ( ) ,
drainageRadius ,
allowCrossFlow ,
2020-04-15 10:45:32 +02:00
automaticShutIn ,
2020-04-19 08:37:48 +02:00
pvt_table ,
gas_inflow ) ;
2020-02-14 14:18:22 +01:00
this - > addWell ( std : : move ( well ) , timeStep ) ;
2013-11-05 17:58:57 +01:00
}
2020-01-30 10:37:57 +01:00
2013-11-05 15:25:47 +01:00
size_t Schedule : : numWells ( ) const {
2019-05-04 12:00:32 +02:00
return wells_static . size ( ) ;
2013-11-05 15:25:47 +01:00
}
2015-02-12 12:54:57 +01:00
size_t Schedule : : numWells ( size_t timestep ) const {
2019-03-23 16:11:37 +01:00
auto well_names = this - > wellNames ( timestep ) ;
return well_names . size ( ) ;
2014-12-05 12:59:53 +01:00
}
2013-11-05 15:25:47 +01:00
bool Schedule : : hasWell ( const std : : string & wellName ) const {
2019-05-04 12:00:32 +02:00
return wells_static . count ( wellName ) > 0 ;
2015-02-12 12:54:57 +01:00
}
2019-05-04 12:00:32 +02:00
bool Schedule : : hasWell ( const std : : string & wellName , std : : size_t timeStep ) const {
if ( this - > wells_static . count ( wellName ) = = 0 )
return false ;
2017-07-25 19:50:06 +02:00
2019-11-12 08:29:28 +01:00
const auto & well = this - > getWellatEnd ( wellName ) ;
2019-05-04 12:00:32 +02:00
return well . hasBeenDefined ( timeStep ) ;
2017-07-25 19:50:06 +02:00
}
2019-11-12 08:29:28 +01:00
std : : vector < const Group * > Schedule : : getChildGroups2 ( const std : : string & group_name , size_t timeStep ) const {
2019-03-23 16:11:37 +01:00
if ( ! hasGroup ( group_name ) )
2019-07-25 11:46:15 +02:00
throw std : : invalid_argument ( " No such group: ' " + group_name + " ' " ) ;
2019-03-23 16:11:37 +01:00
{
2019-11-12 08:29:28 +01:00
const auto & group = getGroup ( group_name , timeStep ) ;
std : : vector < const Group * > child_groups ;
2019-03-23 16:11:37 +01:00
2019-08-06 22:40:14 +02:00
if ( group . defined ( timeStep ) ) {
for ( const auto & child_name : group . groups ( ) )
2019-11-12 08:29:28 +01:00
child_groups . push_back ( std : : addressof ( this - > getGroup ( child_name , timeStep ) ) ) ;
2019-03-23 16:11:37 +01:00
}
2019-08-06 22:40:14 +02:00
return child_groups ;
2019-03-23 16:11:37 +01:00
}
}
2019-05-04 12:00:32 +02:00
2019-11-12 08:29:28 +01:00
std : : vector < Well > Schedule : : getChildWells2 ( const std : : string & group_name , size_t timeStep ) const {
2018-04-25 09:44:57 +02:00
if ( ! hasGroup ( group_name ) )
2019-07-25 11:46:15 +02:00
throw std : : invalid_argument ( " No such group: ' " + group_name + " ' " ) ;
2018-04-25 09:44:57 +02:00
{
2019-08-06 22:40:14 +02:00
const auto & dynamic_state = this - > groups . at ( group_name ) ;
const auto & group_ptr = dynamic_state . get ( timeStep ) ;
if ( group_ptr ) {
2019-11-12 08:29:28 +01:00
std : : vector < Well > wells ;
2019-08-06 22:40:14 +02:00
2019-09-01 07:57:48 +02:00
if ( group_ptr - > groups ( ) . size ( ) ) {
2019-08-06 22:40:14 +02:00
for ( const auto & child_name : group_ptr - > groups ( ) ) {
2019-09-01 07:57:48 +02:00
const auto & child_wells = getChildWells2 ( child_name , timeStep ) ;
2019-08-06 22:40:14 +02:00
wells . insert ( wells . end ( ) , child_wells . begin ( ) , child_wells . end ( ) ) ;
}
} else {
for ( const auto & well_name : group_ptr - > wells ( ) )
2019-11-12 08:29:28 +01:00
wells . push_back ( this - > getWell ( well_name , timeStep ) ) ;
2018-04-25 09:44:57 +02:00
}
2019-08-06 22:40:14 +02:00
return wells ;
} else
return { } ;
2018-04-25 09:44:57 +02:00
}
}
2020-04-21 10:40:34 +02:00
/*
This function will return a list of wells which have changed
* structurally * in the last report_step ; wells where only production
settings have changed will not be included .
*/
std : : vector < std : : string > Schedule : : changed_wells ( std : : size_t report_step ) const {
std : : vector < std : : string > wells ;
for ( const auto & dynamic_pair : this - > wells_static ) {
const auto & well_ptr = dynamic_pair . second . get ( report_step ) ;
if ( well_ptr ) {
if ( report_step > 0 ) {
const auto & prev = dynamic_pair . second . get ( report_step - 1 ) ;
if ( prev ) {
if ( ! well_ptr - > cmp_structure ( * prev ) )
wells . push_back ( well_ptr - > name ( ) ) ;
} else
wells . push_back ( well_ptr - > name ( ) ) ;
} else
wells . push_back ( well_ptr - > name ( ) ) ;
}
}
return wells ;
}
2019-01-28 09:52:11 +01:00
2019-08-06 22:40:14 +02:00
2019-11-12 08:29:28 +01:00
std : : vector < Well > Schedule : : getWells ( size_t timeStep ) const {
std : : vector < Well > wells ;
2019-05-04 12:00:32 +02:00
if ( timeStep > = this - > m_timeMap . size ( ) )
throw std : : invalid_argument ( " timeStep argument beyond the length of the simulation " ) ;
2016-06-16 08:37:10 +02:00
2019-05-04 12:00:32 +02:00
for ( const auto & dynamic_pair : this - > wells_static ) {
auto & well_ptr = dynamic_pair . second . get ( timeStep ) ;
if ( well_ptr )
wells . push_back ( * well_ptr . get ( ) ) ;
2015-02-12 12:54:57 +01:00
}
2016-06-16 08:37:10 +02:00
return wells ;
2015-02-12 15:36:39 +01:00
}
2019-11-12 08:29:28 +01:00
std : : vector < Well > Schedule : : getWellsatEnd ( ) const {
return this - > getWells ( this - > m_timeMap . size ( ) - 1 ) ;
2019-05-04 12:00:32 +02:00
}
2019-11-12 08:29:28 +01:00
const Well & Schedule : : getWellatEnd ( const std : : string & well_name ) const {
return this - > getWell ( well_name , this - > m_timeMap . size ( ) - 1 ) ;
2016-03-29 14:13:54 +02:00
}
2019-11-12 08:29:28 +01:00
const Well & Schedule : : getWell ( const std : : string & wellName , size_t timeStep ) const {
2019-03-23 16:11:37 +01:00
if ( this - > wells_static . count ( wellName ) = = 0 )
throw std : : invalid_argument ( " No such well: " + wellName ) ;
const auto & dynamic_state = this - > wells_static . at ( wellName ) ;
auto & well_ptr = dynamic_state . get ( timeStep ) ;
if ( ! well_ptr )
throw std : : invalid_argument ( " Well: " + wellName + " not yet defined at step: " + std : : to_string ( timeStep ) ) ;
return * well_ptr ;
}
2015-05-28 14:55:09 +02:00
2019-11-12 08:29:28 +01:00
const Group & Schedule : : getGroup ( const std : : string & groupName , size_t timeStep ) const {
2019-07-24 08:38:39 +02:00
if ( this - > groups . count ( groupName ) = = 0 )
2019-07-25 11:46:15 +02:00
throw std : : invalid_argument ( " No such group: ' " + groupName + " ' " ) ;
2019-07-24 08:38:39 +02:00
const auto & dynamic_state = this - > groups . at ( groupName ) ;
auto & group_ptr = dynamic_state . get ( timeStep ) ;
if ( ! group_ptr )
throw std : : invalid_argument ( " Group: " + groupName + " not yet defined at step: " + std : : to_string ( timeStep ) ) ;
return * group_ptr ;
}
2019-11-12 08:29:28 +01:00
void Schedule : : updateGroup ( std : : shared_ptr < Group > group , size_t reportStep ) {
2019-07-24 08:38:39 +02:00
auto & dynamic_state = this - > groups . at ( group - > name ( ) ) ;
2019-07-30 17:47:19 +02:00
dynamic_state . update ( reportStep , std : : move ( group ) ) ;
2019-07-24 08:38:39 +02:00
}
2019-03-14 09:23:03 +01:00
/*
There are many SCHEDULE keyword which take a wellname as argument . In
addition to giving a fully qualified name like ' W1 ' you can also specify
shell wildcard patterns like like ' W * ' , you can get all the wells in the
well - list ' * WL ' [ 1 ] and the wellname ' ? ' is used to get all the wells which
already have matched a condition in a ACTIONX keyword . This function
should be one - stop function to get all well names according to a input
pattern . The timestep argument is used to check that the wells have
2019-05-04 12:00:32 +02:00
indeed been defined at the point in time we are considering .
2019-03-14 09:23:03 +01:00
[ 1 ] : The leading ' * ' in a WLIST name should not be interpreted as a shell
wildcard !
*/
std : : vector < std : : string > Schedule : : wellNames ( const std : : string & pattern , size_t timeStep , const std : : vector < std : : string > & matching_wells ) const {
2019-03-18 10:44:11 +01:00
if ( pattern . size ( ) = = 0 )
return { } ;
2019-03-14 09:23:03 +01:00
// WLIST
2019-03-18 10:44:11 +01:00
if ( pattern [ 0 ] = = ' * ' & & pattern . size ( ) > 1 ) {
2019-03-14 09:23:03 +01:00
const auto & wlm = this - > getWListManager ( timeStep ) ;
2020-07-09 13:25:02 +02:00
return wlm . wells ( pattern ) ;
2019-03-14 09:23:03 +01:00
}
// Normal pattern matching
auto star_pos = pattern . find ( ' * ' ) ;
if ( star_pos ! = std : : string : : npos ) {
std : : vector < std : : string > names ;
2019-03-23 16:11:37 +01:00
for ( const auto & well_pair : this - > wells_static ) {
2019-07-07 08:46:17 +02:00
if ( name_match ( pattern , well_pair . first ) ) {
2019-03-23 16:11:37 +01:00
const auto & dynamic_state = well_pair . second ;
if ( dynamic_state . get ( timeStep ) )
2019-03-14 09:23:03 +01:00
names . push_back ( well_pair . first ) ;
}
}
return names ;
}
// ACTIONX handler
2019-05-04 12:00:32 +02:00
if ( pattern = = " ? " )
2019-03-14 09:23:03 +01:00
return { matching_wells . begin ( ) , matching_wells . end ( ) } ;
// Normal well name without any special characters
if ( this - > hasWell ( pattern ) ) {
2019-03-23 16:11:37 +01:00
const auto & dynamic_state = this - > wells_static . at ( pattern ) ;
if ( dynamic_state . get ( timeStep ) )
2019-03-14 09:23:03 +01:00
return { pattern } ;
}
return { } ;
}
2019-03-24 07:53:30 +01:00
std : : vector < std : : string > Schedule : : wellNames ( const std : : string & pattern ) const {
return this - > wellNames ( pattern , this - > size ( ) - 1 ) ;
}
std : : vector < std : : string > Schedule : : wellNames ( std : : size_t timeStep ) const {
std : : vector < std : : string > names ;
2019-05-04 12:00:32 +02:00
for ( const auto & well_pair : this - > wells_static ) {
const auto & well_name = well_pair . first ;
const auto & dynamic_state = well_pair . second ;
2020-09-16 11:59:03 +02:00
auto open_step = dynamic_state . find_not ( nullptr ) ;
if ( open_step . value ( ) < = timeStep )
2019-05-04 12:00:32 +02:00
names . push_back ( well_name ) ;
2019-03-24 07:53:30 +01:00
}
return names ;
}
std : : vector < std : : string > Schedule : : wellNames ( ) const {
std : : vector < std : : string > names ;
2019-05-04 12:00:32 +02:00
for ( const auto & well_pair : this - > wells_static )
2019-03-24 07:53:30 +01:00
names . push_back ( well_pair . first ) ;
2019-05-04 12:00:32 +02:00
2019-03-24 07:53:30 +01:00
return names ;
2019-07-07 08:46:17 +02:00
}
std : : vector < std : : string > Schedule : : groupNames ( const std : : string & pattern , size_t timeStep ) const {
if ( pattern . size ( ) = = 0 )
return { } ;
// Normal pattern matching
auto star_pos = pattern . find ( ' * ' ) ;
if ( star_pos ! = std : : string : : npos ) {
std : : vector < std : : string > names ;
2019-08-06 22:40:14 +02:00
for ( const auto & group_pair : this - > groups ) {
2019-07-07 08:46:17 +02:00
if ( name_match ( pattern , group_pair . first ) ) {
2019-08-06 22:40:14 +02:00
const auto & dynamic_state = group_pair . second ;
const auto & group_ptr = dynamic_state . get ( timeStep ) ;
if ( group_ptr )
2019-07-07 08:46:17 +02:00
names . push_back ( group_pair . first ) ;
}
}
return names ;
}
// Normal group name without any special characters
if ( this - > hasGroup ( pattern ) ) {
2019-08-06 22:40:14 +02:00
const auto & dynamic_state = this - > groups . at ( pattern ) ;
const auto & group_ptr = dynamic_state . get ( timeStep ) ;
if ( group_ptr )
2019-07-07 08:46:17 +02:00
return { pattern } ;
}
return { } ;
}
std : : vector < std : : string > Schedule : : groupNames ( size_t timeStep ) const {
std : : vector < std : : string > names ;
2019-08-06 22:40:14 +02:00
for ( const auto & group_pair : this - > groups ) {
const auto & dynamic_state = group_pair . second ;
const auto & group_ptr = dynamic_state . get ( timeStep ) ;
if ( group_ptr )
names . push_back ( group_pair . first ) ;
2019-07-07 08:46:17 +02:00
}
return names ;
}
std : : vector < std : : string > Schedule : : groupNames ( const std : : string & pattern ) const {
if ( pattern . size ( ) = = 0 )
return { } ;
// Normal pattern matching
auto star_pos = pattern . find ( ' * ' ) ;
if ( star_pos ! = std : : string : : npos ) {
int flags = 0 ;
std : : vector < std : : string > names ;
2019-08-06 22:40:14 +02:00
for ( const auto & group_pair : this - > groups ) {
2019-07-07 08:46:17 +02:00
if ( fnmatch ( pattern . c_str ( ) , group_pair . first . c_str ( ) , flags ) = = 0 )
names . push_back ( group_pair . first ) ;
}
return names ;
}
// Normal group name without any special characters
if ( this - > hasGroup ( pattern ) )
return { pattern } ;
return { } ;
}
std : : vector < std : : string > Schedule : : groupNames ( ) const {
std : : vector < std : : string > names ;
2019-08-06 22:40:14 +02:00
for ( const auto & group_pair : this - > groups )
2019-07-07 08:46:17 +02:00
names . push_back ( group_pair . first ) ;
return names ;
2019-03-24 07:53:30 +01:00
}
2019-03-14 09:23:03 +01:00
2020-06-23 16:50:30 +02:00
std : : vector < const Group * > Schedule : : restart_groups ( std : : size_t timeStep ) const {
2020-06-24 15:38:44 +02:00
std : : size_t wdmax = this - > m_runspec . wellDimensions ( ) . maxGroupsInField ( ) ;
std : : vector < const Group * > rst_groups ( wdmax + 1 , nullptr ) ;
2020-06-23 16:50:30 +02:00
for ( const auto & group_name : this - > groupNames ( timeStep ) ) {
const auto & group = this - > getGroup ( group_name , timeStep ) ;
if ( group . name ( ) = = " FIELD " )
rst_groups . back ( ) = & group ;
else
rst_groups [ group . insert_index ( ) - 1 ] = & group ;
}
return rst_groups ;
}
2015-02-12 12:54:57 +01:00
2019-08-05 18:37:01 +02:00
void Schedule : : addGroup ( const std : : string & groupName , size_t timeStep , const UnitSystem & unit_system ) {
2019-08-06 22:40:14 +02:00
const size_t gseqIndex = this - > groups . size ( ) ;
2019-07-24 08:38:39 +02:00
2019-11-12 08:29:28 +01:00
groups . insert ( std : : make_pair ( groupName , DynamicState < std : : shared_ptr < Group > > ( this - > m_timeMap , nullptr ) ) ) ;
auto group_ptr = std : : make_shared < Group > ( groupName , gseqIndex , timeStep , this - > getUDQConfig ( timeStep ) . params ( ) . undefinedValue ( ) , unit_system ) ;
2019-07-24 08:38:39 +02:00
auto & dynamic_state = this - > groups . at ( groupName ) ;
dynamic_state . update ( timeStep , group_ptr ) ;
2016-10-05 10:09:45 +02:00
m_events . addEvent ( ScheduleEvents : : NEW_GROUP , timeStep ) ;
2019-11-27 08:58:57 +01:00
wellgroup_events . insert ( std : : make_pair ( groupName , Events ( this - > m_timeMap ) ) ) ;
this - > addWellGroupEvent ( groupName , ScheduleEvents : : NEW_GROUP , timeStep ) ;
2019-07-25 11:46:15 +02:00
// All newly created groups are attached to the field group,
// can then be relocated with the GRUPTREE keyword.
if ( groupName ! = " FIELD " )
this - > addGroupToGroup ( " FIELD " , * group_ptr , timeStep ) ;
2013-11-18 13:11:49 +01:00
}
size_t Schedule : : numGroups ( ) const {
2019-08-06 22:40:14 +02:00
return groups . size ( ) ;
2013-11-18 13:11:49 +01:00
}
2019-07-07 10:29:24 +02:00
2018-04-24 14:03:29 +02:00
size_t Schedule : : numGroups ( size_t timeStep ) const {
2019-07-07 10:29:24 +02:00
const auto group_names = this - > groupNames ( timeStep ) ;
return group_names . size ( ) ;
2018-04-24 14:03:29 +02:00
}
2013-11-18 13:11:49 +01:00
bool Schedule : : hasGroup ( const std : : string & groupName ) const {
2019-08-06 22:40:14 +02:00
return groups . count ( groupName ) > 0 ;
2013-11-18 13:11:49 +01:00
}
2019-09-19 23:50:41 +02:00
bool Schedule : : hasGroup ( const std : : string & groupName , std : : size_t timeStep ) const {
if ( timeStep > = this - > size ( ) )
return false ;
auto grpMap = this - > groups . find ( groupName ) ;
return ( grpMap ! = this - > groups . end ( ) )
& & grpMap - > second . at ( timeStep ) ;
}
2019-07-07 10:29:24 +02:00
2019-11-12 08:29:28 +01:00
void Schedule : : addGroupToGroup ( const std : : string & parent_group , const Group & child_group , size_t timeStep ) {
2019-07-25 11:46:15 +02:00
// Add to new parent
auto & dynamic_state = this - > groups . at ( parent_group ) ;
2019-11-12 08:29:28 +01:00
auto parent_ptr = std : : make_shared < Group > ( * dynamic_state [ timeStep ] ) ;
2019-07-25 11:46:15 +02:00
if ( parent_ptr - > addGroup ( child_group . name ( ) ) )
2019-07-30 17:47:19 +02:00
this - > updateGroup ( std : : move ( parent_ptr ) , timeStep ) ;
2019-07-25 11:46:15 +02:00
// Check and update backreference in child
if ( child_group . parent ( ) ! = parent_group ) {
2019-11-12 08:29:28 +01:00
auto old_parent = std : : make_shared < Group > ( this - > getGroup ( child_group . parent ( ) , timeStep ) ) ;
2019-07-25 11:46:15 +02:00
old_parent - > delGroup ( child_group . name ( ) ) ;
2019-07-30 17:47:19 +02:00
this - > updateGroup ( std : : move ( old_parent ) , timeStep ) ;
2019-01-28 09:52:11 +01:00
2019-11-12 08:29:28 +01:00
auto child_ptr = std : : make_shared < Group > ( child_group ) ;
2019-07-25 11:46:15 +02:00
child_ptr - > updateParent ( parent_group ) ;
2019-07-30 17:47:19 +02:00
this - > updateGroup ( std : : move ( child_ptr ) , timeStep ) ;
2013-11-18 13:11:49 +01:00
2019-07-25 11:46:15 +02:00
}
}
void Schedule : : addGroupToGroup ( const std : : string & parent_group , const std : : string & child_group , size_t timeStep ) {
2019-11-12 08:29:28 +01:00
this - > addGroupToGroup ( parent_group , this - > getGroup ( child_group , timeStep ) , timeStep ) ;
2019-07-25 11:46:15 +02:00
}
void Schedule : : addWellToGroup ( const std : : string & group_name , const std : : string & well_name , size_t timeStep ) {
2019-11-12 08:29:28 +01:00
const auto & well = this - > getWell ( well_name , timeStep ) ;
2019-07-25 11:46:15 +02:00
const auto old_gname = well . groupName ( ) ;
2019-08-06 22:40:14 +02:00
if ( old_gname ! = group_name ) {
2019-11-12 08:29:28 +01:00
auto well_ptr = std : : make_shared < Well > ( well ) ;
2019-07-25 11:46:15 +02:00
well_ptr - > updateGroup ( group_name ) ;
this - > updateWell ( well_ptr , timeStep ) ;
2019-11-27 08:58:57 +01:00
this - > addWellGroupEvent ( well_ptr - > name ( ) , ScheduleEvents : : WELL_WELSPECS_UPDATE , timeStep ) ;
2019-07-25 11:46:15 +02:00
2019-08-06 22:40:14 +02:00
// Remove well child reference from previous group
2019-11-12 08:29:28 +01:00
auto group = std : : make_shared < Group > ( this - > getGroup ( old_gname , timeStep ) ) ;
2019-08-06 22:40:14 +02:00
group - > delWell ( well_name ) ;
2019-07-30 17:47:19 +02:00
this - > updateGroup ( std : : move ( group ) , timeStep ) ;
2019-07-25 11:46:15 +02:00
}
2019-08-06 22:40:14 +02:00
// Add well child reference to new group
2019-11-12 08:29:28 +01:00
auto group_ptr = std : : make_shared < Group > ( this - > getGroup ( group_name , timeStep ) ) ;
2019-08-06 22:40:14 +02:00
group_ptr - > addWell ( well_name ) ;
this - > updateGroup ( group_ptr , timeStep ) ;
this - > m_events . addEvent ( ScheduleEvents : : GROUP_CHANGE , timeStep ) ;
2019-05-04 12:00:32 +02:00
}
2015-01-28 09:39:13 +01:00
2014-12-05 12:59:53 +01:00
2015-04-17 18:51:42 +02:00
2020-01-31 13:40:44 +01:00
const Tuning & Schedule : : getTuning ( size_t timeStep ) const {
return this - > m_tuning . get ( timeStep ) ;
}
2016-11-09 09:07:57 +01:00
const Deck & Schedule : : getModifierDeck ( size_t timeStep ) const {
2016-10-05 10:12:46 +02:00
return m_modifierDeck . iget ( timeStep ) ;
2015-10-30 15:33:53 +01:00
}
2016-10-17 10:41:17 +08:00
const MessageLimits & Schedule : : getMessageLimits ( ) const {
return m_messageLimits ;
2016-10-14 10:06:35 +08:00
}
2015-10-30 15:33:53 +01:00
2018-04-12 19:02:15 +02:00
2019-11-27 08:58:57 +01:00
const Events & Schedule : : getWellGroupEvents ( const std : : string & wellGroup ) const {
if ( this - > wellgroup_events . count ( wellGroup ) > 0 )
return this - > wellgroup_events . at ( wellGroup ) ;
2019-03-21 08:49:27 +01:00
else
2019-11-27 08:58:57 +01:00
throw std : : invalid_argument ( " No such well og group " + wellGroup ) ;
2019-03-21 08:49:27 +01:00
}
2016-04-14 09:39:28 +08:00
2019-11-27 08:58:57 +01:00
void Schedule : : addWellGroupEvent ( const std : : string & wellGroup , ScheduleEvents : : Events event , size_t reportStep ) {
auto & events = this - > wellgroup_events . at ( wellGroup ) ;
2019-03-21 08:49:27 +01:00
events . addEvent ( event , reportStep ) ;
}
2019-11-27 08:58:57 +01:00
bool Schedule : : hasWellGroupEvent ( const std : : string & wellGroup , uint64_t event_mask , size_t reportStep ) const {
const auto & events = this - > getWellGroupEvents ( wellGroup ) ;
2019-11-25 09:55:32 +01:00
return events . hasEvent ( event_mask , reportStep ) ;
}
2015-06-23 14:20:31 +02:00
const Events & Schedule : : getEvents ( ) const {
2016-10-05 10:09:45 +02:00
return this - > m_events ;
2015-10-02 10:49:23 +02:00
}
2016-12-22 15:11:02 +01:00
const OilVaporizationProperties & Schedule : : getOilVaporizationProperties ( size_t timestep ) const {
2016-10-05 10:23:42 +02:00
return m_oilvaporizationproperties . get ( timestep ) ;
2015-10-02 10:49:23 +02:00
}
2019-12-16 14:27:16 +01:00
2019-12-16 14:34:36 +01:00
const Well : : ProducerCMode & Schedule : : getGlobalWhistctlMmode ( size_t timestep ) const {
return global_whistctl_mode . get ( timestep ) ;
}
2015-10-02 10:49:23 +02:00
2016-11-30 12:49:19 +01:00
bool Schedule : : hasOilVaporizationProperties ( ) const {
2016-11-30 12:59:16 +01:00
for ( size_t i = 0 ; i < this - > m_timeMap . size ( ) ; + + i )
2016-11-30 12:49:19 +01:00
if ( m_oilvaporizationproperties . at ( i ) . defined ( ) ) return true ;
return false ;
2015-10-02 10:49:23 +02:00
}
2017-09-26 09:32:29 +02:00
2019-05-04 12:00:32 +02:00
void Schedule : : checkIfAllConnectionsIsShut ( size_t timeStep ) {
const auto & well_names = this - > wellNames ( timeStep ) ;
for ( const auto & wname : well_names ) {
2019-11-12 08:29:28 +01:00
const auto & well = this - > getWell ( wname , timeStep ) ;
2019-05-04 12:00:32 +02:00
const auto & connections = well . getConnections ( ) ;
2020-06-01 09:07:17 +02:00
if ( connections . allConnectionsShut ( ) & & well . getStatus ( ) ! = Well : : Status : : SHUT ) {
std : : string msg =
" All completions in well " + well . name ( ) + " is shut at " + std : : to_string ( m_timeMap . getTimePassedUntil ( timeStep ) / ( 60 * 60 * 24 ) ) + " days. \n " +
" The well is therefore also shut. " ;
OpmLog : : note ( msg ) ;
2020-06-04 13:15:18 +02:00
this - > updateWellStatus ( well . name ( ) , timeStep , Well : : Status : : SHUT , false ) ;
2020-06-01 09:07:17 +02:00
}
2017-09-26 09:32:29 +02:00
}
}
2018-02-06 19:13:42 +01:00
2019-12-10 11:46:49 +01:00
void Schedule : : filterConnections ( const ActiveGridCells & grid ) {
2019-05-04 12:00:32 +02:00
for ( auto & dynamic_pair : this - > wells_static ) {
auto & dynamic_state = dynamic_pair . second ;
for ( auto & well_pair : dynamic_state . unique ( ) ) {
if ( well_pair . second )
well_pair . second - > filterConnections ( grid ) ;
}
}
for ( auto & dynamic_pair : this - > wells_static ) {
auto & dynamic_state = dynamic_pair . second ;
for ( auto & well_pair : dynamic_state . unique ( ) ) {
if ( well_pair . second )
well_pair . second - > filterConnections ( grid ) ;
}
2019-03-08 09:00:36 +01:00
}
2019-03-23 16:11:37 +01:00
for ( auto & dynamic_pair : this - > wells_static ) {
auto & dynamic_state = dynamic_pair . second ;
for ( auto & well_pair : dynamic_state . unique ( ) ) {
if ( well_pair . second )
well_pair . second - > filterConnections ( grid ) ;
}
}
2018-02-06 19:13:42 +01:00
}
2018-04-06 12:12:30 +02:00
2018-04-12 19:02:15 +02:00
const VFPProdTable & Schedule : : getVFPProdTable ( int table_id , size_t timeStep ) const {
const auto pair = vfpprod_tables . find ( table_id ) ;
if ( pair = = vfpprod_tables . end ( ) )
throw std : : invalid_argument ( " No such table id: " + std : : to_string ( table_id ) ) ;
auto table_ptr = pair - > second . get ( timeStep ) ;
if ( ! table_ptr )
throw std : : invalid_argument ( " Table not yet defined at timeStep: " + std : : to_string ( timeStep ) ) ;
return * table_ptr ;
2018-04-06 12:12:30 +02:00
}
2018-04-12 19:02:15 +02:00
const VFPInjTable & Schedule : : getVFPInjTable ( int table_id , size_t timeStep ) const {
const auto pair = vfpinj_tables . find ( table_id ) ;
if ( pair = = vfpinj_tables . end ( ) )
throw std : : invalid_argument ( " No such table id: " + std : : to_string ( table_id ) ) ;
auto table_ptr = pair - > second . get ( timeStep ) ;
if ( ! table_ptr )
throw std : : invalid_argument ( " Table not yet defined at timeStep: " + std : : to_string ( timeStep ) ) ;
return * table_ptr ;
}
2018-04-20 11:27:26 +02:00
std : : map < int , std : : shared_ptr < const VFPInjTable > > Schedule : : getVFPInjTables ( size_t timeStep ) const {
std : : map < int , std : : shared_ptr < const VFPInjTable > > tables ;
2018-04-12 19:02:15 +02:00
for ( const auto & pair : this - > vfpinj_tables ) {
if ( pair . second . get ( timeStep ) ) {
2018-04-20 11:27:26 +02:00
tables . insert ( std : : make_pair ( pair . first , pair . second . get ( timeStep ) ) ) ;
2018-04-12 19:02:15 +02:00
}
}
return tables ;
}
2018-04-20 11:27:26 +02:00
std : : map < int , std : : shared_ptr < const VFPProdTable > > Schedule : : getVFPProdTables ( size_t timeStep ) const {
std : : map < int , std : : shared_ptr < const VFPProdTable > > tables ;
2018-04-12 19:02:15 +02:00
for ( const auto & pair : this - > vfpprod_tables ) {
if ( pair . second . get ( timeStep ) ) {
2018-04-20 11:27:26 +02:00
tables . insert ( std : : make_pair ( pair . first , pair . second . get ( timeStep ) ) ) ;
2018-04-12 19:02:15 +02:00
}
}
return tables ;
2018-04-06 12:12:30 +02:00
}
2019-06-19 13:40:27 +02:00
const UDQActive & Schedule : : udqActive ( size_t timeStep ) const {
return * this - > udq_active [ timeStep ] ;
}
void Schedule : : updateUDQActive ( size_t timeStep , std : : shared_ptr < UDQActive > udq ) {
this - > udq_active . update ( timeStep , udq ) ;
}
2018-05-14 04:18:07 +02:00
const WellTestConfig & Schedule : : wtestConfig ( size_t timeStep ) const {
const auto & ptr = this - > wtest_config . get ( timeStep ) ;
return * ptr ;
}
2018-10-12 08:25:40 +02:00
2019-10-31 15:18:42 +01:00
const GConSale & Schedule : : gConSale ( size_t timeStep ) const {
const auto & ptr = this - > gconsale . get ( timeStep ) ;
return * ptr ;
}
2019-11-06 11:33:32 +01:00
const GConSump & Schedule : : gConSump ( size_t timeStep ) const {
const auto & ptr = this - > gconsump . get ( timeStep ) ;
return * ptr ;
}
2019-01-14 12:09:07 +01:00
const WListManager & Schedule : : getWListManager ( size_t timeStep ) const {
const auto & ptr = this - > wlist_manager . get ( timeStep ) ;
return * ptr ;
}
2018-10-27 15:58:02 +02:00
2019-07-26 17:17:06 +02:00
const UDQConfig & Schedule : : getUDQConfig ( size_t timeStep ) const {
2019-01-28 16:52:28 +01:00
const auto & ptr = this - > udq_config . get ( timeStep ) ;
return * ptr ;
}
2019-09-06 07:56:42 +02:00
const GuideRateConfig & Schedule : : guideRateConfig ( size_t timeStep ) const {
const auto & ptr = this - > guide_rate_config . get ( timeStep ) ;
2019-08-22 17:55:10 +02:00
return * ptr ;
}
2020-04-01 11:56:07 +02:00
const RPTConfig & Schedule : : report_config ( size_t timeStep ) const {
const auto & ptr = this - > rpt_config . get ( timeStep ) ;
return * ptr ;
}
2020-04-12 09:30:23 +02:00
std : : optional < int > Schedule : : exitStatus ( ) const {
return this - > exit_status ;
}
2018-10-27 15:58:02 +02:00
2018-10-12 08:25:40 +02:00
size_t Schedule : : size ( ) const {
return this - > m_timeMap . size ( ) ;
}
2018-10-17 12:08:54 +02:00
2018-11-19 09:43:50 +01:00
double Schedule : : seconds ( size_t timeStep ) const {
2018-10-17 12:08:54 +02:00
return this - > m_timeMap . seconds ( timeStep ) ;
}
2019-01-22 17:04:54 +01:00
time_t Schedule : : simTime ( size_t timeStep ) const {
return this - > m_timeMap [ timeStep ] ;
}
2018-10-09 17:42:37 +02:00
double Schedule : : stepLength ( size_t timeStep ) const {
return this - > m_timeMap . getTimeStepLength ( timeStep ) ;
}
2018-11-19 09:43:50 +01:00
2019-08-29 18:17:37 +02:00
const Action : : Actions & Schedule : : actions ( std : : size_t timeStep ) const {
const auto & ptr = this - > m_actions . get ( timeStep ) ;
return * ptr ;
2018-11-19 09:43:50 +01:00
}
2019-07-01 08:27:07 +02:00
void Schedule : : applyAction ( size_t reportStep , const Action : : ActionX & action , const Action : : Result & result ) {
2019-01-28 10:00:08 +01:00
ParseContext parseContext ;
ErrorGuard errors ;
for ( const auto & keyword : action ) {
2019-07-01 08:27:07 +02:00
if ( ! Action : : ActionX : : valid_keyword ( keyword . name ( ) ) )
2019-01-28 10:00:08 +01:00
throw std : : invalid_argument ( " The keyword: " + keyword . name ( ) + " can not be handled in the ACTION body " ) ;
if ( keyword . name ( ) = = " WELOPEN " )
2020-09-21 19:22:11 +02:00
this - > applyWELOPEN ( keyword , reportStep , parseContext , errors , result . wells ( ) ) ;
2020-04-12 09:30:23 +02:00
if ( keyword . name ( ) = = " EXIT " )
2020-09-25 10:12:55 +02:00
this - > applyEXIT ( keyword , reportStep ) ;
2019-01-28 10:00:08 +01:00
2020-09-16 16:06:02 +02:00
if ( keyword . name ( ) = = " UDQ " )
this - > updateUDQ ( keyword , reportStep ) ;
}
2019-01-28 10:00:08 +01:00
}
2020-02-16 20:00:16 +01:00
RestartConfig & Schedule : : restart ( ) {
return this - > restart_config ;
}
const RestartConfig & Schedule : : restart ( ) const {
return this - > restart_config ;
}
2019-08-30 12:56:49 +02:00
int Schedule : : getNupcol ( size_t reportStep ) const {
return this - > m_nupcol . get ( reportStep ) ;
}
2019-12-16 14:27:16 +01:00
bool Schedule : : operator = = ( const Schedule & data ) const {
auto & & comparePtr = [ ] ( const auto & t1 , const auto & t2 ) {
if ( ( t1 & & ! t2 ) | | ( ! t1 & & t2 ) )
return false ;
if ( ! t1 )
return true ;
return * t1 = = * t2 ;
} ;
auto & & compareDynState = [ comparePtr ] ( const auto & state1 , const auto & state2 ) {
if ( state1 . data ( ) . size ( ) ! = state2 . data ( ) . size ( ) )
return false ;
return std : : equal ( state1 . data ( ) . begin ( ) , state1 . data ( ) . end ( ) ,
state2 . data ( ) . begin ( ) , comparePtr ) ;
} ;
2020-01-13 10:07:33 +01:00
auto & & compareMap = [ compareDynState ] ( const auto & map1 , const auto & map2 ) {
2019-12-16 14:27:16 +01:00
if ( map1 . size ( ) ! = map2 . size ( ) )
return false ;
auto it2 = map2 . begin ( ) ;
for ( const auto & it : map1 ) {
if ( it . first ! = it2 - > first )
return false ;
if ( ! compareDynState ( it . second , it2 - > second ) )
return false ;
+ + it2 ;
}
return true ;
} ;
2019-08-30 12:56:49 +02:00
2020-03-12 12:10:32 +01:00
return this - > m_timeMap = = data . m_timeMap & &
compareMap ( this - > wells_static , data . wells_static ) & &
compareMap ( this - > groups , data . groups ) & &
this - > m_oilvaporizationproperties = = data . m_oilvaporizationproperties & &
this - > m_events = = data . m_events & &
this - > m_modifierDeck = = data . m_modifierDeck & &
this - > m_tuning = = data . m_tuning & &
this - > m_messageLimits = = data . m_messageLimits & &
this - > m_runspec = = data . m_runspec & &
compareMap ( this - > vfpprod_tables , data . vfpprod_tables ) & &
compareMap ( this - > vfpinj_tables , data . vfpinj_tables ) & &
2020-05-06 21:10:52 +02:00
compareDynState ( this - > m_network , data . m_network ) & &
2020-05-06 11:35:22 +02:00
compareDynState ( this - > m_glo , data . m_glo ) & &
2020-03-12 12:10:32 +01:00
compareDynState ( this - > wtest_config , data . wtest_config ) & &
compareDynState ( this - > wlist_manager , data . wlist_manager ) & &
compareDynState ( this - > udq_config , data . udq_config ) & &
compareDynState ( this - > udq_active , data . udq_active ) & &
compareDynState ( this - > guide_rate_config , data . guide_rate_config ) & &
compareDynState ( this - > gconsale , data . gconsale ) & &
compareDynState ( this - > gconsump , data . gconsump ) & &
this - > global_whistctl_mode = = data . global_whistctl_mode & &
compareDynState ( this - > m_actions , data . m_actions ) & &
2020-04-01 11:56:07 +02:00
compareDynState ( this - > rpt_config , data . rpt_config ) & &
2020-03-12 12:10:32 +01:00
rft_config = = data . rft_config & &
this - > m_nupcol = = data . m_nupcol & &
this - > restart_config = = data . restart_config & &
this - > wellgroup_events = = data . wellgroup_events ;
2019-12-16 14:27:16 +01:00
}
2020-06-06 08:54:04 +02:00
2020-03-18 13:56:26 +01:00
namespace {
// Duplicated from Well.cpp
Connection : : Order order_from_int ( int int_value ) {
switch ( int_value ) {
case 0 :
return Connection : : Order : : TRACK ;
case 1 :
return Connection : : Order : : DEPTH ;
case 2 :
return Connection : : Order : : INPUT ;
default :
throw std : : invalid_argument ( " Invalid integer value: " + std : : to_string ( int_value ) + " encountered when determining connection ordering " ) ;
}
}
}
2020-03-13 07:36:45 +01:00
void Schedule : : load_rst ( const RestartIO : : RstState & rst_state , const EclipseGrid & grid , const FieldPropsManager & fp , const UnitSystem & unit_system )
2020-01-30 11:08:20 +01:00
{
2020-03-13 07:36:45 +01:00
double udq_undefined = 0 ;
const auto report_step = rst_state . header . report_step - 1 ;
for ( const auto & rst_group : rst_state . groups )
this - > addGroup ( rst_group . name , report_step , unit_system ) ;
for ( const auto & rst_well : rst_state . wells ) {
Opm : : Well well ( rst_well , report_step , unit_system , udq_undefined ) ;
2020-06-06 08:54:04 +02:00
std : : vector < Opm : : Connection > rst_connections ;
2020-03-13 07:36:45 +01:00
for ( const auto & rst_conn : rst_well . connections )
2020-06-06 08:54:04 +02:00
rst_connections . emplace_back ( rst_conn , grid , fp ) ;
if ( rst_well . segments . empty ( ) ) {
Opm : : WellConnections connections ( order_from_int ( rst_well . completion_ordering ) ,
rst_well . ij [ 0 ] ,
rst_well . ij [ 1 ] ,
rst_connections ) ;
well . updateConnections ( std : : make_shared < WellConnections > ( std : : move ( connections ) ) , grid , fp . get_int ( " PVTNUM " ) ) ;
} else {
std : : unordered_map < int , Opm : : Segment > rst_segments ;
for ( const auto & rst_segment : rst_well . segments ) {
Opm : : Segment segment ( rst_segment ) ;
rst_segments . insert ( std : : make_pair ( rst_segment . segment , std : : move ( segment ) ) ) ;
}
auto [ connections , segments ] = Compsegs : : rstUpdate ( rst_well , rst_connections , rst_segments ) ;
well . updateConnections ( std : : make_shared < WellConnections > ( std : : move ( connections ) ) , grid , fp . get_int ( " PVTNUM " ) ) ;
well . updateSegments ( std : : make_shared < WellSegments > ( std : : move ( segments ) ) ) ;
2020-03-13 07:36:45 +01:00
}
this - > addWell ( well , report_step ) ;
this - > addWellToGroup ( well . groupName ( ) , well . name ( ) , report_step ) ;
}
m_tuning . update ( report_step , rst_state . tuning ) ;
m_events . addEvent ( ScheduleEvents : : TUNING_CHANGE , report_step ) ;
2020-01-30 11:08:20 +01:00
}
2020-03-22 21:02:32 +01:00
std : : shared_ptr < const Python > Schedule : : python ( ) const
{
return this - > python_handle ;
}
2020-04-25 19:15:17 +02:00
void Schedule : : updateNetwork ( std : : shared_ptr < Network : : ExtNetwork > network , std : : size_t report_step ) {
this - > m_network . update ( report_step , std : : move ( network ) ) ;
}
const Network : : ExtNetwork & Schedule : : network ( std : : size_t report_step ) const {
return * this - > m_network [ report_step ] ;
}
2020-05-06 11:35:22 +02:00
const GasLiftOpt & Schedule : : glo ( std : : size_t report_step ) const {
return * this - > m_glo [ report_step ] ;
}
2020-04-25 19:15:17 +02:00
2020-03-13 07:36:17 +01:00
namespace {
/*
The insane trickery here ( thank you Stackoverflow ! ) is to be able to provide a
simple templated comparison function
template < typename T >
int not_equal ( const T & arg1 , const T & arg2 , const std : : string & msg ) ;
which will print arg1 and arg2 on stderr * if * T supports operator < < , otherwise
it will just print the typename of T .
*/
template < typename T , typename = int >
struct cmpx
{
int neq ( const T & arg1 , const T & arg2 , const std : : string & msg ) {
if ( arg1 = = arg2 )
return 0 ;
std : : cerr < < " Error when comparing < " < < typeid ( arg1 ) . name ( ) < < " >: " < < msg < < std : : endl ;
return 1 ;
}
} ;
template < typename T >
struct cmpx < T , decltype ( std : : cout < < T ( ) , 0 ) >
{
int neq ( const T & arg1 , const T & arg2 , const std : : string & msg ) {
if ( arg1 = = arg2 )
return 0 ;
std : : cerr < < " Error when comparing: " < < msg < < " " < < arg1 < < " != " < < arg2 < < std : : endl ;
return 1 ;
}
} ;
template < typename T >
int not_equal ( const T & arg1 , const T & arg2 , const std : : string & msg ) {
return cmpx < T > ( ) . neq ( arg1 , arg2 , msg ) ;
}
template < >
int not_equal ( const double & arg1 , const double & arg2 , const std : : string & msg ) {
if ( Opm : : cmp : : scalar_equal ( arg1 , arg2 ) )
return 0 ;
std : : cerr < < " Error when comparing: " < < msg < < " " < < arg1 < < " != " < < arg2 < < std : : endl ;
return 1 ;
}
template < >
int not_equal ( const UDAValue & arg1 , const UDAValue & arg2 , const std : : string & msg ) {
if ( arg1 . is < double > ( ) )
return not_equal ( arg1 . get < double > ( ) , arg2 . get < double > ( ) , msg ) ;
else
return not_equal ( arg1 . get < std : : string > ( ) , arg2 . get < std : : string > ( ) , msg ) ;
}
std : : string well_msg ( const std : : string & well , const std : : string & msg ) {
return " Well: " + well + " " + msg ;
}
2020-03-26 19:45:32 +01:00
std : : string well_segment_msg ( const std : : string & well , int segment_number , const std : : string & msg ) {
return " Well: " + well + " Segment: " + std : : to_string ( segment_number ) + " " + msg ;
}
2020-03-13 07:36:17 +01:00
2020-03-27 10:18:38 +01:00
std : : string well_connection_msg ( const std : : string & well , const Connection & conn , const std : : string & msg ) {
return " Well: " + well + " Connection: " + std : : to_string ( conn . getI ( ) ) + " , " + std : : to_string ( conn . getJ ( ) ) + " , " + std : : to_string ( conn . getK ( ) ) + " " + msg ;
}
2020-03-13 07:36:17 +01:00
}
bool Schedule : : cmp ( const Schedule & sched1 , const Schedule & sched2 , std : : size_t report_step ) {
int count = not_equal ( sched1 . wellNames ( report_step ) , sched2 . wellNames ( report_step ) , " Wellnames " ) ;
if ( count ! = 0 )
return false ;
2020-03-13 12:18:08 +01:00
{
const auto & tm1 = sched1 . getTimeMap ( ) ;
const auto & tm2 = sched2 . getTimeMap ( ) ;
if ( not_equal ( tm1 . size ( ) , tm2 . size ( ) , " TimeMap: size() " ) )
count + = 1 ;
for ( auto & step_index = report_step ; step_index < std : : min ( tm1 . size ( ) , tm2 . size ( ) ) - 1 ; step_index + + ) {
if ( not_equal ( tm1 [ step_index ] , tm2 [ step_index ] , " TimePoint[ " + std : : to_string ( step_index ) + " ] " ) )
count + = 1 ;
}
}
2020-03-13 07:36:17 +01:00
for ( const auto & wname : sched1 . wellNames ( report_step ) ) {
const auto & well1 = sched1 . getWell ( wname , report_step ) ;
const auto & well2 = sched2 . getWell ( wname , report_step ) ;
int well_count = 0 ;
{
const auto & connections2 = well2 . getConnections ( ) ;
const auto & connections1 = well1 . getConnections ( ) ;
2020-03-18 13:56:26 +01:00
well_count + = not_equal ( connections1 . ordering ( ) , connections2 . ordering ( ) , well_msg ( well1 . name ( ) , " Connection: ordering " ) ) ;
2020-03-13 07:36:17 +01:00
for ( std : : size_t icon = 0 ; icon < connections1 . size ( ) ; icon + + ) {
const auto & conn1 = connections1 [ icon ] ;
const auto & conn2 = connections2 [ icon ] ;
2020-03-27 10:18:38 +01:00
well_count + = not_equal ( conn1 . getI ( ) , conn2 . getI ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " I " ) ) ;
well_count + = not_equal ( conn1 . getJ ( ) , conn2 . getJ ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " J " ) ) ;
well_count + = not_equal ( conn1 . getK ( ) , conn2 . getK ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " K " ) ) ;
well_count + = not_equal ( conn1 . state ( ) , conn2 . state ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " State " ) ) ;
well_count + = not_equal ( conn1 . dir ( ) , conn2 . dir ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " dir " ) ) ;
well_count + = not_equal ( conn1 . complnum ( ) , conn2 . complnum ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " complnum " ) ) ;
well_count + = not_equal ( conn1 . segment ( ) , conn2 . segment ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " segment " ) ) ;
well_count + = not_equal ( conn1 . kind ( ) , conn2 . kind ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " CFKind " ) ) ;
well_count + = not_equal ( conn1 . sort_value ( ) , conn2 . sort_value ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " sort_value " ) ) ;
well_count + = not_equal ( conn1 . CF ( ) , conn2 . CF ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " CF " ) ) ;
well_count + = not_equal ( conn1 . Kh ( ) , conn2 . Kh ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " Kh " ) ) ;
well_count + = not_equal ( conn1 . rw ( ) , conn2 . rw ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " rw " ) ) ;
well_count + = not_equal ( conn1 . depth ( ) , conn2 . depth ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " depth " ) ) ;
//well_count += not_equal( conn1.r0(), conn2.r0(), well_connection_msg(well1.name(), conn1, "r0"));
well_count + = not_equal ( conn1 . skinFactor ( ) , conn2 . skinFactor ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " skinFactor " ) ) ;
2020-03-13 07:36:17 +01:00
}
}
if ( not_equal ( well1 . isMultiSegment ( ) , well2 . isMultiSegment ( ) , well_msg ( well1 . name ( ) , " Is MSW " ) ) )
return false ;
if ( well1 . isMultiSegment ( ) ) {
const auto & segments1 = well1 . getSegments ( ) ;
const auto & segments2 = well2 . getSegments ( ) ;
if ( not_equal ( segments1 . size ( ) , segments2 . size ( ) , " Segments: size " ) )
return false ;
for ( std : : size_t iseg = 0 ; iseg < segments1 . size ( ) ; iseg + + ) {
const auto & segment1 = segments1 [ iseg ] ;
const auto & segment2 = segments2 [ iseg ] ;
2020-03-26 19:45:32 +01:00
//const auto& segment2 = segments2.getFromSegmentNumber(segment1.segmentNumber());
well_count + = not_equal ( segment1 . segmentNumber ( ) , segment2 . segmentNumber ( ) , well_segment_msg ( well1 . name ( ) , segment1 . segmentNumber ( ) , " segmentNumber " ) ) ;
well_count + = not_equal ( segment1 . branchNumber ( ) , segment2 . branchNumber ( ) , well_segment_msg ( well1 . name ( ) , segment1 . segmentNumber ( ) , " branchNumber " ) ) ;
well_count + = not_equal ( segment1 . outletSegment ( ) , segment2 . outletSegment ( ) , well_segment_msg ( well1 . name ( ) , segment1 . segmentNumber ( ) , " outletSegment " ) ) ;
well_count + = not_equal ( segment1 . totalLength ( ) , segment2 . totalLength ( ) , well_segment_msg ( well1 . name ( ) , segment1 . segmentNumber ( ) , " totalLength " ) ) ;
well_count + = not_equal ( segment1 . depth ( ) , segment2 . depth ( ) , well_segment_msg ( well1 . name ( ) , segment1 . segmentNumber ( ) , " depth " ) ) ;
well_count + = not_equal ( segment1 . internalDiameter ( ) , segment2 . internalDiameter ( ) , well_segment_msg ( well1 . name ( ) , segment1 . segmentNumber ( ) , " internalDiameter " ) ) ;
well_count + = not_equal ( segment1 . roughness ( ) , segment2 . roughness ( ) , well_segment_msg ( well1 . name ( ) , segment1 . segmentNumber ( ) , " roughness " ) ) ;
well_count + = not_equal ( segment1 . crossArea ( ) , segment2 . crossArea ( ) , well_segment_msg ( well1 . name ( ) , segment1 . segmentNumber ( ) , " crossArea " ) ) ;
well_count + = not_equal ( segment1 . volume ( ) , segment2 . volume ( ) , well_segment_msg ( well1 . name ( ) , segment1 . segmentNumber ( ) , " volume " ) ) ;
2020-03-13 07:36:17 +01:00
}
}
2020-03-30 16:02:40 +02:00
well_count + = not_equal ( well1 . getStatus ( ) , well2 . getStatus ( ) , well_msg ( well1 . name ( ) , " status " ) ) ;
2020-03-13 07:36:17 +01:00
{
const auto & prod1 = well1 . getProductionProperties ( ) ;
const auto & prod2 = well2 . getProductionProperties ( ) ;
well_count + = not_equal ( prod1 . name , prod2 . name , well_msg ( well1 . name ( ) , " Prod: name " ) ) ;
well_count + = not_equal ( prod1 . OilRate , prod2 . OilRate , well_msg ( well1 . name ( ) , " Prod: OilRate " ) ) ;
well_count + = not_equal ( prod1 . GasRate , prod2 . GasRate , well_msg ( well1 . name ( ) , " Prod: GasRate " ) ) ;
well_count + = not_equal ( prod1 . WaterRate , prod2 . WaterRate , well_msg ( well1 . name ( ) , " Prod: WaterRate " ) ) ;
well_count + = not_equal ( prod1 . LiquidRate , prod2 . LiquidRate , well_msg ( well1 . name ( ) , " Prod: LiquidRate " ) ) ;
well_count + = not_equal ( prod1 . ResVRate , prod2 . ResVRate , well_msg ( well1 . name ( ) , " Prod: ResVRate " ) ) ;
well_count + = not_equal ( prod1 . BHPTarget , prod2 . BHPTarget , well_msg ( well1 . name ( ) , " Prod: BHPTarget " ) ) ;
well_count + = not_equal ( prod1 . THPTarget , prod2 . THPTarget , well_msg ( well1 . name ( ) , " Prod: THPTarget " ) ) ;
2020-03-30 16:02:40 +02:00
well_count + = not_equal ( prod1 . VFPTableNumber , prod2 . VFPTableNumber , well_msg ( well1 . name ( ) , " Prod: VFPTableNumber " ) ) ;
well_count + = not_equal ( prod1 . ALQValue , prod2 . ALQValue , well_msg ( well1 . name ( ) , " Prod: ALQValue " ) ) ;
2020-03-27 12:40:47 +01:00
well_count + = not_equal ( prod1 . predictionMode , prod2 . predictionMode , well_msg ( well1 . name ( ) , " Prod: predictionMode " ) ) ;
if ( ! prod1 . predictionMode ) {
well_count + = not_equal ( prod1 . bhp_hist_limit , prod2 . bhp_hist_limit , well_msg ( well1 . name ( ) , " Prod: bhp_hist_limit " ) ) ;
well_count + = not_equal ( prod1 . thp_hist_limit , prod2 . thp_hist_limit , well_msg ( well1 . name ( ) , " Prod: thp_hist_limit " ) ) ;
well_count + = not_equal ( prod1 . BHPH , prod2 . BHPH , well_msg ( well1 . name ( ) , " Prod: BHPH " ) ) ;
well_count + = not_equal ( prod1 . THPH , prod2 . THPH , well_msg ( well1 . name ( ) , " Prod: THPH " ) ) ;
}
2020-03-13 07:36:17 +01:00
well_count + = not_equal ( prod1 . productionControls ( ) , prod2 . productionControls ( ) , well_msg ( well1 . name ( ) , " Prod: productionControls " ) ) ;
2020-03-30 16:02:40 +02:00
if ( well1 . getStatus ( ) = = Well : : Status : : OPEN )
well_count + = not_equal ( prod1 . controlMode , prod2 . controlMode , well_msg ( well1 . name ( ) , " Prod: controlMode " ) ) ;
2020-03-13 07:36:17 +01:00
well_count + = not_equal ( prod1 . whistctl_cmode , prod2 . whistctl_cmode , well_msg ( well1 . name ( ) , " Prod: whistctl_cmode " ) ) ;
}
{
const auto & inj1 = well1 . getInjectionProperties ( ) ;
const auto & inj2 = well2 . getInjectionProperties ( ) ;
well_count + = not_equal ( inj1 . name , inj2 . name , well_msg ( well1 . name ( ) , " Well::Inj: name " ) ) ;
well_count + = not_equal ( inj1 . surfaceInjectionRate , inj2 . surfaceInjectionRate , well_msg ( well1 . name ( ) , " Well::Inj: surfaceInjectionRate " ) ) ;
well_count + = not_equal ( inj1 . reservoirInjectionRate , inj2 . reservoirInjectionRate , well_msg ( well1 . name ( ) , " Well::Inj: reservoirInjectionRate " ) ) ;
well_count + = not_equal ( inj1 . BHPTarget , inj2 . BHPTarget , well_msg ( well1 . name ( ) , " Well::Inj: BHPTarget " ) ) ;
well_count + = not_equal ( inj1 . THPTarget , inj2 . THPTarget , well_msg ( well1 . name ( ) , " Well::Inj: THPTarget " ) ) ;
well_count + = not_equal ( inj1 . bhp_hist_limit , inj2 . bhp_hist_limit , well_msg ( well1 . name ( ) , " Well::Inj: bhp_hist_limit " ) ) ;
well_count + = not_equal ( inj1 . thp_hist_limit , inj2 . thp_hist_limit , well_msg ( well1 . name ( ) , " Well::Inj: thp_hist_limit " ) ) ;
well_count + = not_equal ( inj1 . BHPH , inj2 . BHPH , well_msg ( well1 . name ( ) , " Well::Inj: BHPH " ) ) ;
well_count + = not_equal ( inj1 . THPH , inj2 . THPH , well_msg ( well1 . name ( ) , " Well::Inj: THPH " ) ) ;
well_count + = not_equal ( inj1 . VFPTableNumber , inj2 . VFPTableNumber , well_msg ( well1 . name ( ) , " Well::Inj: VFPTableNumber " ) ) ;
well_count + = not_equal ( inj1 . predictionMode , inj2 . predictionMode , well_msg ( well1 . name ( ) , " Well::Inj: predictionMode " ) ) ;
well_count + = not_equal ( inj1 . injectionControls , inj2 . injectionControls , well_msg ( well1 . name ( ) , " Well::Inj: injectionControls " ) ) ;
well_count + = not_equal ( inj1 . injectorType , inj2 . injectorType , well_msg ( well1 . name ( ) , " Well::Inj: injectorType " ) ) ;
well_count + = not_equal ( inj1 . controlMode , inj2 . controlMode , well_msg ( well1 . name ( ) , " Well::Inj: controlMode " ) ) ;
}
{
well_count + = well2 . firstTimeStep ( ) > report_step ;
well_count + = not_equal ( well1 . groupName ( ) , well2 . groupName ( ) , well_msg ( well1 . name ( ) , " Well: groupName " ) ) ;
well_count + = not_equal ( well1 . getHeadI ( ) , well2 . getHeadI ( ) , well_msg ( well1 . name ( ) , " Well: getHeadI " ) ) ;
well_count + = not_equal ( well1 . getHeadJ ( ) , well2 . getHeadJ ( ) , well_msg ( well1 . name ( ) , " Well: getHeadJ " ) ) ;
well_count + = not_equal ( well1 . getRefDepth ( ) , well2 . getRefDepth ( ) , well_msg ( well1 . name ( ) , " Well: getRefDepth " ) ) ;
well_count + = not_equal ( well1 . isMultiSegment ( ) , well2 . isMultiSegment ( ) , well_msg ( well1 . name ( ) , " Well: isMultiSegment " ) ) ;
well_count + = not_equal ( well1 . isAvailableForGroupControl ( ) , well2 . isAvailableForGroupControl ( ) , well_msg ( well1 . name ( ) , " Well: isAvailableForGroupControl " ) ) ;
well_count + = not_equal ( well1 . getGuideRate ( ) , well2 . getGuideRate ( ) , well_msg ( well1 . name ( ) , " Well: getGuideRate " ) ) ;
well_count + = not_equal ( well1 . getGuideRatePhase ( ) , well2 . getGuideRatePhase ( ) , well_msg ( well1 . name ( ) , " Well: getGuideRatePhase " ) ) ;
well_count + = not_equal ( well1 . getGuideRateScalingFactor ( ) , well2 . getGuideRateScalingFactor ( ) , well_msg ( well1 . name ( ) , " Well: getGuideRateScalingFactor " ) ) ;
well_count + = not_equal ( well1 . predictionMode ( ) , well2 . predictionMode ( ) , well_msg ( well1 . name ( ) , " Well: predictionMode " ) ) ;
well_count + = not_equal ( well1 . canOpen ( ) , well2 . canOpen ( ) , well_msg ( well1 . name ( ) , " Well: canOpen " ) ) ;
well_count + = not_equal ( well1 . isProducer ( ) , well2 . isProducer ( ) , well_msg ( well1 . name ( ) , " Well: isProducer " ) ) ;
well_count + = not_equal ( well1 . isInjector ( ) , well2 . isInjector ( ) , well_msg ( well1 . name ( ) , " Well: isInjector " ) ) ;
if ( well1 . isInjector ( ) )
well_count + = not_equal ( well1 . injectorType ( ) , well2 . injectorType ( ) , well_msg ( well1 . name ( ) , " Well1: injectorType " ) ) ;
well_count + = not_equal ( well1 . seqIndex ( ) , well2 . seqIndex ( ) , well_msg ( well1 . name ( ) , " Well: seqIndex " ) ) ;
well_count + = not_equal ( well1 . getAutomaticShutIn ( ) , well2 . getAutomaticShutIn ( ) , well_msg ( well1 . name ( ) , " Well: getAutomaticShutIn " ) ) ;
well_count + = not_equal ( well1 . getAllowCrossFlow ( ) , well2 . getAllowCrossFlow ( ) , well_msg ( well1 . name ( ) , " Well: getAllowCrossFlow " ) ) ;
well_count + = not_equal ( well1 . getSolventFraction ( ) , well2 . getSolventFraction ( ) , well_msg ( well1 . name ( ) , " Well: getSolventFraction " ) ) ;
well_count + = not_equal ( well1 . getStatus ( ) , well2 . getStatus ( ) , well_msg ( well1 . name ( ) , " Well: getStatus " ) ) ;
//well_count += not_equal( well1.getInjectionProperties(), well2.getInjectionProperties(), "Well: getInjectionProperties");
if ( well1 . isProducer ( ) )
well_count + = not_equal ( well1 . getPreferredPhase ( ) , well2 . getPreferredPhase ( ) , well_msg ( well1 . name ( ) , " Well: getPreferredPhase " ) ) ;
well_count + = not_equal ( well1 . getDrainageRadius ( ) , well2 . getDrainageRadius ( ) , well_msg ( well1 . name ( ) , " Well: getDrainageRadius " ) ) ;
well_count + = not_equal ( well1 . getEfficiencyFactor ( ) , well2 . getEfficiencyFactor ( ) , well_msg ( well1 . name ( ) , " Well: getEfficiencyFactor " ) ) ;
}
count + = well_count ;
if ( well_count > 0 )
std : : cerr < < std : : endl ;
}
return ( count = = 0 ) ;
}
2019-07-24 10:20:38 +02:00
}