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
2014-12-12 20:56:34 +01:00
# include <string>
# include <vector>
2015-09-04 13:42:10 +02:00
# include <stdexcept>
2018-06-12 13:56:44 +02:00
# include <iostream>
2018-10-26 09:13:26 +02:00
# include <set>
2014-12-12 20:56:34 +01:00
# include <boost/algorithm/string.hpp>
2016-01-15 08:42:57 +01:00
# include <boost/date_time/posix_time/posix_time.hpp>
2015-08-07 16:30:38 +02:00
2018-03-22 11:07:14 +01:00
# include <opm/common/OpmLog/LogUtil.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>
2014-12-12 20:56:34 +01:00
# include <opm/parser/eclipse/Deck/Section.hpp>
2016-03-16 17:15:09 +08:00
# include <opm/parser/eclipse/Parser/ParseContext.hpp>
2016-01-18 17:51:15 +01:00
# include <opm/parser/eclipse/Parser/ParserKeywords/C.hpp>
2018-04-06 12:12:30 +02:00
# include <opm/parser/eclipse/Parser/ParserKeywords/V.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>
2018-07-11 13:54:49 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/ActionX.hpp>
2018-06-20 11:35:11 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/WellConnections.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>
# include <opm/parser/eclipse/EclipseState/Schedule/Events.hpp>
# include <opm/parser/eclipse/EclipseState/Schedule/Group.hpp>
# include <opm/parser/eclipse/EclipseState/Schedule/GroupTree.hpp>
2018-06-20 11:36:50 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/MSW/WellSegments.hpp>
2018-06-10 20:54:34 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/MSW/updatingConnectionsWithSegments.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>
2015-08-28 16:20:39 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.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>
# include <opm/parser/eclipse/EclipseState/Schedule/Well.hpp>
2014-10-13 19:24:02 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/WellInjectionProperties.hpp>
2014-11-20 16:20:54 +08:00
# include <opm/parser/eclipse/EclipseState/Schedule/WellPolymerProperties.hpp>
2016-01-15 08:42:57 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/WellProductionProperties.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
2013-11-08 15:55:11 +01:00
namespace Opm {
2018-10-26 09:13:26 +02:00
static std : : set < std : : string > actionx_whitelist = { " WELSPECS " , " WELOPEN " } ;
2017-09-27 16:34:38 +02:00
Schedule : : Schedule ( const Deck & deck ,
2016-09-08 19:42:45 +02:00
const EclipseGrid & grid ,
2017-02-15 11:13:29 +01:00
const Eclipse3DProperties & eclipseProperties ,
2018-10-17 13:35:25 +02:00
const Runspec & runspec ,
2019-01-03 11:53:32 +01:00
const ParseContext & parseContext ,
ErrorGuard & errors ) :
2016-11-08 18:29:52 +01:00
m_timeMap ( deck ) ,
m_rootGroupTree ( this - > m_timeMap , GroupTree { } ) ,
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 { } ) ,
2016-11-08 18:29:52 +01:00
m_tuning ( this - > m_timeMap ) ,
m_messageLimits ( this - > m_timeMap ) ,
2018-10-17 13:35:25 +02:00
m_runspec ( runspec ) ,
2018-05-14 04:18:07 +02:00
wtest_config ( this - > m_timeMap , std : : make_shared < WellTestConfig > ( ) )
2016-05-02 17:46:20 +02:00
{
2016-09-22 09:28:43 +02:00
m_controlModeWHISTCTL = WellProducer : : CMODE_UNDEFINED ;
2013-12-02 11:47:14 +01:00
addGroup ( " FIELD " , 0 ) ;
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 " )
handleMESSAGES ( keyword , 0 ) ;
}
2018-04-12 19:02:15 +02:00
if ( Section : : hasSCHEDULE ( deck ) )
2019-01-03 11:53:32 +01:00
iterateScheduleSection ( parseContext , errors , SCHEDULESection ( deck ) , grid , eclipseProperties ) ;
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 ,
const Eclipse3DProperties & eclipseProperties ,
const Runspec & runspec ,
const ParseContext & parseContext ,
T & & errors ) :
Schedule ( deck , grid , eclipseProperties , runspec , parseContext , errors )
{ }
Schedule : : Schedule ( const Deck & deck ,
const EclipseGrid & grid ,
const Eclipse3DProperties & eclipseProperties ,
const Runspec & runspec ) :
Schedule ( deck , grid , eclipseProperties , runspec , ParseContext ( ) , ErrorGuard ( ) )
{ }
2019-01-03 11:53:32 +01:00
Schedule : : Schedule ( const Deck & deck , const EclipseState & es , const ParseContext & parse_context , ErrorGuard & errors ) :
2017-12-03 09:00:56 +01:00
Schedule ( deck ,
es . getInputGrid ( ) ,
es . get3DProperties ( ) ,
2018-10-17 13:35:25 +02:00
es . runspec ( ) ,
2019-01-03 11:53:32 +01:00
parse_context ,
errors )
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 >
Schedule : : Schedule ( const Deck & deck , const EclipseState & es , const ParseContext & parse_context , T & & errors ) :
Schedule ( deck ,
es . getInputGrid ( ) ,
es . get3DProperties ( ) ,
es . runspec ( ) ,
parse_context ,
errors )
{ }
Schedule : : Schedule ( const Deck & deck , const EclipseState & es ) :
Schedule ( deck , es , ParseContext ( ) , ErrorGuard ( ) )
{ }
2018-04-24 14:03:29 +02: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
void Schedule : : handleKeyword ( size_t & currentStep ,
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 ,
const Eclipse3DProperties & eclipseProperties ,
const UnitSystem & unit_system ,
std : : vector < std : : pair < const DeckKeyword * , size_t > > & rftProperties ) {
/*
geoModifiers is a list of geo modifiers which can be found in the schedule
section . This is only partly supported , support is indicated by the bool
value . The keywords which are supported will be assembled in a per - timestep
' minideck ' , whereas ParseContext : : UNSUPPORTED_SCHEDULE_GEO_MODIFIER will be
consulted for the others .
*/
2015-10-30 15:33:53 +01:00
2015-10-30 12:55:17 +01:00
const std : : map < std : : string , bool > geoModifiers = { { " MULTFLT " , true } ,
2015-10-30 15:33:53 +01:00
{ " MULTPV " , false } ,
{ " MULTX " , false } ,
{ " MULTX- " , false } ,
{ " MULTY " , false } ,
{ " MULTY- " , false } ,
{ " MULTZ " , false } ,
{ " MULTZ- " , false } ,
{ " MULTREGT " , false } ,
{ " MULTR " , false } ,
{ " MULTR- " , false } ,
{ " MULTSIG " , false } ,
{ " MULTSIGV " , false } ,
{ " MULTTHT " , false } ,
{ " MULTTHT- " , false } } ;
2015-07-26 23:13:49 +02:00
2018-07-11 13:54:49 +02:00
if ( keyword . name ( ) = = " DATES " ) {
checkIfAllConnectionsIsShut ( currentStep ) ;
currentStep + = keyword . size ( ) ;
}
2015-02-06 14:54:03 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " TSTEP " ) {
checkIfAllConnectionsIsShut ( currentStep ) ;
currentStep + = keyword . getRecord ( 0 ) . getItem ( 0 ) . size ( ) ; // This is a bit weird API.
}
2013-11-08 15:55:11 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WELSPECS " )
handleWELSPECS ( section , keywordIdx , currentStep ) ;
2013-11-05 15:25:47 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WHISTCTL " )
2019-01-03 11:53:32 +01:00
handleWHISTCTL ( parseContext , errors , keyword ) ;
2013-11-08 15:55:11 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WCONHIST " )
2019-01-03 11:53:32 +01:00
handleWCONHIST ( keyword , currentStep , parseContext , errors ) ;
2013-11-08 15:55:11 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WCONPROD " )
2019-01-03 11:53:32 +01:00
handleWCONPROD ( keyword , currentStep , parseContext , errors ) ;
2016-09-22 09:28:43 +02:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WCONINJE " )
2019-01-03 11:53:32 +01:00
handleWCONINJE ( section , keyword , currentStep , parseContext , errors ) ;
2013-11-08 15:55:11 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WPOLYMER " )
2019-01-03 11:53:32 +01:00
handleWPOLYMER ( keyword , currentStep , parseContext , errors ) ;
2013-11-08 15:55:11 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WSOLVENT " )
2019-01-03 11:53:32 +01:00
handleWSOLVENT ( keyword , currentStep , parseContext , errors ) ;
2013-11-11 17:06:22 +01:00
2018-11-12 09:05:01 +01:00
else if ( keyword . name ( ) = = " WTRACER " )
2019-01-03 11:53:32 +01:00
handleWTRACER ( keyword , currentStep , parseContext , errors ) ;
2018-11-12 09:05:01 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WTEST " )
2019-01-03 11:53:32 +01:00
handleWTEST ( keyword , currentStep , parseContext , errors ) ;
2014-11-20 16:20:54 +08:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WTEMP " )
2019-01-03 11:53:32 +01:00
handleWTEMP ( keyword , currentStep , parseContext , errors ) ;
2015-08-04 13:55:16 +02:00
2018-06-04 12:04:17 +02:00
else if ( keyword . name ( ) = = " WPMITAB " )
2019-01-03 11:53:32 +01:00
handleWPMITAB ( keyword , currentStep , parseContext , errors ) ;
2018-04-06 15:48:27 +02:00
2018-06-04 12:04:17 +02:00
else if ( keyword . name ( ) = = " WSKPTAB " )
2019-01-03 11:53:32 +01:00
handleWSKPTAB ( keyword , currentStep , parseContext , errors ) ;
2018-04-06 15:48:27 +02:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WINJTEMP " )
2019-01-03 11:53:32 +01:00
handleWINJTEMP ( keyword , currentStep , parseContext , errors ) ;
2018-05-14 04:18:07 +02:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WCONINJH " )
2019-01-03 11:53:32 +01:00
handleWCONINJH ( section , keyword , currentStep , parseContext , errors ) ;
2017-11-23 13:18:33 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WGRUPCON " )
handleWGRUPCON ( keyword , currentStep ) ;
2018-04-10 14:56:11 +02:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " COMPDAT " )
2019-01-03 11:53:32 +01:00
handleCOMPDAT ( keyword , currentStep , grid , eclipseProperties , parseContext , errors ) ;
2013-11-05 15:25:47 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WELSEGS " )
handleWELSEGS ( keyword , currentStep ) ;
2014-02-17 16:10:31 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " COMPSEGS " )
2018-08-27 17:16:19 +02:00
handleCOMPSEGS ( keyword , currentStep , grid ) ;
2013-11-14 16:08:10 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WELOPEN " )
2019-01-03 11:53:32 +01:00
handleWELOPEN ( keyword , currentStep , parseContext , errors ) ;
2015-10-26 12:51:09 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WELTARG " )
2019-01-03 11:53:32 +01:00
handleWELTARG ( section , keyword , currentStep , parseContext , errors ) ;
2015-11-10 09:53:38 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " GRUPTREE " )
handleGRUPTREE ( keyword , currentStep ) ;
2013-11-14 16:08:10 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " GRUPNET " )
handleGRUPNET ( keyword , currentStep ) ;
2015-03-25 08:20:22 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " GCONINJE " )
2019-01-03 11:53:32 +01:00
handleGCONINJE ( section , keyword , currentStep , parseContext , errors ) ;
2013-11-09 13:17:42 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " GCONPROD " )
2019-01-03 11:53:32 +01:00
handleGCONPROD ( keyword , currentStep , parseContext , errors ) ;
2017-12-04 16:24:07 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " GEFAC " )
2019-01-03 11:53:32 +01:00
handleGEFAC ( keyword , currentStep , parseContext , errors ) ;
2013-11-18 16:06:50 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " TUNING " )
handleTUNING ( keyword , currentStep ) ;
2015-02-06 14:54:03 +01: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
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WPIMULT " )
handleWPIMULT ( keyword , currentStep ) ;
2015-02-06 14:54:03 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " COMPORD " )
2019-01-03 11:53:32 +01:00
handleCOMPORD ( parseContext , errors , keyword , currentStep ) ;
2015-02-12 15:32:31 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " COMPLUMP " )
handleCOMPLUMP ( keyword , currentStep ) ;
2015-06-02 09:30:08 +02:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " DRSDT " )
handleDRSDT ( keyword , currentStep ) ;
2015-10-30 12:55:17 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " DRVDT " )
handleDRVDT ( keyword , currentStep ) ;
2016-11-29 15:46:55 +01:00
2018-10-17 13:35:25 +02:00
else if ( keyword . name ( ) = = " DRSDTR " )
handleDRSDTR ( keyword , currentStep ) ;
else if ( keyword . name ( ) = = " DRVDTR " )
handleDRVDTR ( keyword , currentStep ) ;
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " VAPPARS " )
handleVAPPARS ( keyword , currentStep ) ;
2015-10-02 10:49:23 +02:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WECON " )
2019-01-03 11:53:32 +01:00
handleWECON ( keyword , currentStep , parseContext , errors ) ;
2015-10-02 10:49:23 +02:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " MESSAGES " )
handleMESSAGES ( keyword , currentStep ) ;
2015-08-07 15:13:52 +02:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WEFAC " )
2019-01-03 11:53:32 +01:00
handleWEFAC ( keyword , currentStep , parseContext , errors ) ;
2016-06-23 13:44:03 +02:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " VFPINJ " )
handleVFPINJ ( keyword , unit_system , currentStep ) ;
2016-10-14 10:06:35 +08:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " VFPPROD " )
handleVFPPROD ( keyword , unit_system , currentStep ) ;
else if ( geoModifiers . find ( keyword . name ( ) ) ! = geoModifiers . end ( ) ) {
bool supported = geoModifiers . at ( keyword . name ( ) ) ;
if ( supported ) {
this - > m_modifierDeck [ currentStep ] . addKeyword ( keyword ) ;
m_events . addEvent ( ScheduleEvents : : GEO_MODIFIER , currentStep ) ;
} else {
std : : string msg = " OPM does not support grid property modifier " + keyword . name ( ) + " in the Schedule section. Error at report: " + std : : to_string ( currentStep ) ;
2019-01-03 11:53:32 +01:00
parseContext . handleError ( ParseContext : : UNSUPPORTED_SCHEDULE_GEO_MODIFIER , msg , errors ) ;
2018-07-11 13:54:49 +02:00
}
}
}
2017-11-21 09:55:07 +01:00
2018-04-12 19:02:15 +02:00
2019-01-03 11:53:32 +01:00
void Schedule : : iterateScheduleSection ( const ParseContext & parseContext , ErrorGuard & errors , const SCHEDULESection & section , const EclipseGrid & grid ,
2018-07-11 13:54:49 +02:00
const Eclipse3DProperties & eclipseProperties ) {
size_t currentStep = 0 ;
const auto & unit_system = section . unitSystem ( ) ;
std : : vector < std : : pair < const DeckKeyword * , size_t > > rftProperties ;
size_t keywordIdx = 0 ;
2018-04-12 19:02:15 +02:00
2018-07-11 13:54:49 +02:00
while ( true ) {
const auto & keyword = section . getKeyword ( keywordIdx ) ;
if ( keyword . name ( ) = = " ACTIONX " ) {
2018-10-27 15:58:02 +02:00
ActionX action ( keyword , this - > m_timeMap . getStartTime ( currentStep + 1 ) ) ;
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 ;
2018-10-26 09:13:26 +02:00
if ( actionx_whitelist . find ( action_keyword . name ( ) ) = = actionx_whitelist . end ( ) ) {
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 ) ;
2018-10-26 09:13:26 +02:00
} else
action . addKeyword ( action_keyword ) ;
2015-10-30 12:55:17 +01:00
}
2018-10-27 15:58:02 +02:00
this - > actions . add ( action ) ;
2018-07-11 13:54:49 +02:00
} else
2019-01-03 11:53:32 +01:00
this - > handleKeyword ( currentStep , section , keywordIdx , keyword , parseContext , errors , grid , eclipseProperties , unit_system , rftProperties ) ;
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 ;
2016-02-09 12:09:40 +01:00
if ( keyword . name ( ) = = " WRFT " ) {
2015-02-12 08:38:26 +01:00
handleWRFT ( keyword , timeStep ) ;
2015-02-06 14:54:03 +01:00
}
2016-02-09 12:09:40 +01:00
if ( keyword . name ( ) = = " WRFTPLT " ) {
2015-02-12 08:38:26 +01:00
handleWRFTPLT ( 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
}
2018-07-11 13:54:49 +02:00
2016-02-09 12:09:40 +01:00
void Schedule : : checkUnhandledKeywords ( const SCHEDULESection & /*section*/ ) const
2015-08-07 15:13:52 +02:00
{
}
2016-10-05 10:34:58 +02:00
bool Schedule : : handleGroupFromWELSPECS ( const std : : string & groupName , GroupTree & newTree ) const {
2016-11-07 14:25:00 +01:00
if ( newTree . exists ( groupName ) ) return false ;
newTree . update ( groupName ) ;
return true ;
2013-11-18 15:28:58 +01:00
}
2019-01-03 11:53:32 +01:00
void Schedule : : handleWHISTCTL ( const ParseContext & parseContext , ErrorGuard & errors , const DeckKeyword & keyword ) {
2016-09-22 09:28:43 +02:00
for ( const auto & record : keyword ) {
const std : : string & cmodeString = record . getItem ( " CMODE " ) . getTrimmedString ( 0 ) ;
2018-07-04 12:47:30 +02:00
const WellProducer : : ControlModeEnum controlMode = WellProducer : : ControlModeFromString ( cmodeString ) ;
if ( controlMode ! = WellProducer : : NONE ) {
if ( ! WellProductionProperties : : effectiveHistoryProductionControl ( controlMode ) ) {
std : : string msg = " The WHISTCTL keyword specifies an un-supported control mode " + cmodeString
+ " , which makes WHISTCTL keyword not affect the simulation at all " ;
OpmLog : : warning ( msg ) ;
}
}
2016-09-22 09:28:43 +02:00
m_controlModeWHISTCTL = controlMode ;
const std : : string bhp_terminate = record . getItem ( " BPH_TERMINATE " ) . getTrimmedString ( 0 ) ;
if ( bhp_terminate = = " YES " ) {
std : : string msg = " The WHISTCTL keyword does not handle 'YES'. i.e. to terminate the run " ;
2018-03-22 11:07:14 +01:00
OpmLog : : error ( msg ) ;
2019-01-03 11:53:32 +01:00
parseContext . handleError ( ParseContext : : UNSUPPORTED_TERMINATE_IF_BHP , msg , errors ) ;
2016-09-22 09:28:43 +02:00
}
}
}
2015-08-07 15:13:52 +02:00
2019-01-03 11:53:32 +01:00
void Schedule : : handleCOMPORD ( const ParseContext & parseContext , ErrorGuard & errors , const DeckKeyword & compordKeyword , size_t /* currentStep */ ) {
2016-02-09 12:09:40 +01:00
for ( const auto & record : compordKeyword ) {
const auto & methodItem = record . getItem < ParserKeywords : : COMPORD : : ORDER_TYPE > ( ) ;
if ( ( methodItem . get < std : : string > ( 0 ) ! = " TRACK " ) & & ( methodItem . get < std : : string > ( 0 ) ! = " INPUT " ) ) {
2015-08-28 16:20:39 +02:00
std : : string msg = " The COMPORD keyword only handles 'TRACK' or 'INPUT' order. " ;
2018-03-22 11:07:14 +01:00
OpmLog : : error ( msg ) ;
2019-01-03 11:53:32 +01:00
parseContext . handleError ( ParseContext : : UNSUPPORTED_COMPORD_TYPE , msg , errors ) ;
2015-08-07 15:13:52 +02:00
}
}
}
2018-04-12 19:02:15 +02:00
void Schedule : : handleVFPINJ ( const DeckKeyword & vfpinjKeyword , const UnitSystem & unit_system , size_t currentStep ) {
std : : shared_ptr < VFPInjTable > table = std : : make_shared < VFPInjTable > ( vfpinjKeyword , unit_system ) ;
int table_id = table - > getTableNum ( ) ;
const auto iter = vfpinj_tables . find ( table_id ) ;
if ( iter = = vfpinj_tables . end ( ) ) {
std : : pair < int , DynamicState < std : : shared_ptr < VFPInjTable > > > pair = std : : make_pair ( table_id , DynamicState < std : : shared_ptr < VFPInjTable > > ( this - > m_timeMap , nullptr ) ) ;
vfpinj_tables . insert ( pair ) ;
}
auto & table_state = vfpinj_tables . at ( table_id ) ;
table_state . update ( currentStep , table ) ;
this - > m_events . addEvent ( ScheduleEvents : : VFPINJ_UPDATE , currentStep ) ;
}
void Schedule : : handleVFPPROD ( const DeckKeyword & vfpprodKeyword , const UnitSystem & unit_system , size_t currentStep ) {
std : : shared_ptr < VFPProdTable > table = std : : make_shared < VFPProdTable > ( vfpprodKeyword , unit_system ) ;
int table_id = table - > getTableNum ( ) ;
const auto iter = vfpprod_tables . find ( table_id ) ;
if ( iter = = vfpprod_tables . end ( ) ) {
std : : pair < int , DynamicState < std : : shared_ptr < VFPProdTable > > > pair = std : : make_pair ( table_id , DynamicState < std : : shared_ptr < VFPProdTable > > ( this - > m_timeMap , nullptr ) ) ;
vfpprod_tables . insert ( pair ) ;
}
auto & table_state = vfpprod_tables . at ( table_id ) ;
table_state . update ( currentStep , table ) ;
this - > m_events . addEvent ( ScheduleEvents : : VFPPROD_UPDATE , currentStep ) ;
}
2016-08-05 15:28:29 +02:00
void Schedule : : handleWELSPECS ( const SCHEDULESection & section ,
size_t index ,
size_t currentStep ) {
2013-11-18 15:28:58 +01:00
bool needNewTree = false ;
2016-10-05 10:34:58 +02:00
auto newTree = m_rootGroupTree . get ( currentStep ) ;
2013-11-18 15:28:58 +01:00
2016-08-05 15:28:29 +02:00
const auto COMPORD_in_timestep = [ & ] ( ) - > const DeckKeyword * {
auto itr = section . begin ( ) + index ;
for ( ; itr ! = section . end ( ) ; + + itr ) {
if ( itr - > name ( ) = = " DATES " ) return nullptr ;
if ( itr - > name ( ) = = " TSTEP " ) return nullptr ;
if ( itr - > name ( ) = = " COMPORD " ) return std : : addressof ( * itr ) ;
}
return nullptr ;
} ;
const auto & keyword = section . getKeyword ( index ) ;
2016-02-09 12:09:40 +01:00
for ( size_t recordNr = 0 ; recordNr < keyword . size ( ) ; recordNr + + ) {
const auto & record = keyword . getRecord ( recordNr ) ;
const std : : string & wellName = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
const std : : string & groupName = record . getItem ( " GROUP " ) . getTrimmedString ( 0 ) ;
2017-04-05 14:43:25 +02:00
bool new_well = false ;
2013-11-18 16:06:50 +01:00
2015-06-23 14:20:31 +02:00
if ( ! hasGroup ( groupName ) )
2013-11-25 16:31:44 +01:00
addGroup ( groupName , currentStep ) ;
2013-11-08 15:55:11 +01:00
2015-08-28 16:20:39 +02:00
if ( ! hasWell ( wellName ) ) {
2018-06-10 20:54:34 +02:00
WellCompletion : : CompletionOrderEnum wellConnectionOrder = WellCompletion : : TRACK ;
2015-08-28 16:20:39 +02:00
2016-08-05 15:28:29 +02:00
if ( const auto * compordp = COMPORD_in_timestep ( ) ) {
const auto & compord = * compordp ;
2015-08-28 16:20:39 +02:00
2016-02-09 12:09:40 +01:00
for ( size_t compordRecordNr = 0 ; compordRecordNr < compord . size ( ) ; compordRecordNr + + ) {
const auto & compordRecord = compord . getRecord ( compordRecordNr ) ;
2015-08-28 16:20:39 +02:00
2016-02-09 12:09:40 +01:00
const std : : string & wellNamePattern = compordRecord . getItem ( 0 ) . getTrimmedString ( 0 ) ;
2015-08-28 16:20:39 +02:00
if ( Well : : wellNameInWellNamePattern ( wellName , wellNamePattern ) ) {
2016-02-09 12:09:40 +01:00
const std : : string & compordString = compordRecord . getItem ( 1 ) . getTrimmedString ( 0 ) ;
2018-06-10 20:54:34 +02:00
wellConnectionOrder = WellCompletion : : CompletionOrderEnumFromString ( compordString ) ;
2015-08-28 16:20:39 +02:00
}
}
}
2018-06-10 20:54:34 +02:00
addWell ( wellName , record , currentStep , wellConnectionOrder ) ;
2017-04-05 14:43:25 +02:00
new_well = true ;
2015-08-28 16:20:39 +02:00
}
2013-11-18 15:28:58 +01:00
2016-11-22 11:34:46 +01:00
auto & currentWell = this - > m_wells . get ( wellName ) ;
const auto headI = record . getItem ( " HEAD_I " ) . get < int > ( 0 ) - 1 ;
const auto headJ = record . getItem ( " HEAD_J " ) . get < int > ( 0 ) - 1 ;
2017-04-05 14:43:25 +02:00
if ( ! new_well )
currentWell . addEvent ( ScheduleEvents : : WELL_WELSPECS_UPDATE , currentStep ) ;
2016-11-22 11:34:46 +01:00
2016-11-08 18:42:29 +01:00
if ( currentWell . getHeadI ( ) ! = headI ) {
std : : string msg = " HEAD_I changed for well " + currentWell . name ( ) ;
2018-03-22 11:07:14 +01:00
OpmLog : : info ( Log : : fileMessage ( keyword . getFileName ( ) , keyword . getLineNumber ( ) , msg ) ) ;
2016-11-08 18:42:29 +01:00
currentWell . setHeadI ( currentStep , headI ) ;
2016-11-22 11:34:46 +01:00
}
2016-11-08 18:42:29 +01:00
if ( currentWell . getHeadJ ( ) ! = headJ ) {
std : : string msg = " HEAD_J changed for well " + currentWell . name ( ) ;
2018-03-22 11:07:14 +01:00
OpmLog : : info ( Log : : fileMessage ( keyword . getFileName ( ) , keyword . getLineNumber ( ) , msg ) ) ;
2016-11-08 18:42:29 +01:00
currentWell . setHeadJ ( currentStep , headJ ) ;
2016-11-22 11:34:46 +01:00
}
2014-01-20 14:52:30 +01:00
2016-11-22 13:18:43 +01:00
const auto & refDepthItem = record . getItem ( " REF_DEPTH " ) ;
double refDepth = refDepthItem . hasValue ( 0 )
? refDepthItem . getSIDouble ( 0 )
: - 1.0 ;
2016-11-08 18:42:29 +01:00
currentWell . setRefDepth ( currentStep , refDepth ) ;
2016-11-22 13:18:43 +01:00
2018-11-02 15:21:28 +01:00
double drainageRadius = record . getItem ( " D_RADIUS " ) . getSIDouble ( 0 ) ;
currentWell . setDrainageRadius ( currentStep , drainageRadius ) ;
2016-11-08 18:42:29 +01:00
addWellToGroup ( this - > m_groups . at ( groupName ) , this - > m_wells . get ( wellName ) , currentStep ) ;
2015-06-23 14:20:31 +02:00
if ( handleGroupFromWELSPECS ( groupName , newTree ) )
needNewTree = true ;
2016-06-08 13:46:34 +02:00
2013-11-18 15:28:58 +01:00
}
2015-06-23 14:20:31 +02:00
2013-11-18 15:28:58 +01:00
if ( needNewTree ) {
2016-10-05 10:34:58 +02:00
m_rootGroupTree . update ( currentStep , newTree ) ;
2016-10-05 10:09:45 +02:00
m_events . addEvent ( ScheduleEvents : : GROUP_CHANGE , currentStep ) ;
2013-11-05 15:25:47 +01:00
}
}
2015-10-27 14:12:28 +01:00
2016-02-09 12:09:40 +01:00
void Schedule : : handleVAPPARS ( const DeckKeyword & keyword , size_t currentStep ) {
2018-10-17 13:35:25 +02:00
size_t numPvtRegions = m_runspec . tabdims ( ) . getNumPVTTables ( ) ;
std : : vector < double > vap ( numPvtRegions ) ;
std : : vector < double > density ( numPvtRegions ) ;
2016-02-09 12:09:40 +01:00
for ( const auto & record : keyword ) {
2018-10-17 13:35:25 +02:00
std : : fill ( vap . begin ( ) , vap . end ( ) , record . getItem ( " OIL_VAP_PROPENSITY " ) . get < double > ( 0 ) ) ;
std : : fill ( density . begin ( ) , density . end ( ) , record . getItem ( " OIL_DENSITY_PROPENSITY " ) . get < double > ( 0 ) ) ;
OilVaporizationProperties ovp = this - > m_oilvaporizationproperties . get ( currentStep ) ;
OilVaporizationProperties : : updateVAPPARS ( ovp , vap , density ) ;
this - > m_oilvaporizationproperties . update ( currentStep , ovp ) ;
2015-10-02 10:49:23 +02:00
}
}
2016-02-09 12:09:40 +01:00
void Schedule : : handleDRVDT ( const DeckKeyword & keyword , size_t currentStep ) {
2018-10-17 13:35:25 +02:00
size_t numPvtRegions = m_runspec . tabdims ( ) . getNumPVTTables ( ) ;
std : : vector < double > max ( numPvtRegions ) ;
2016-02-09 12:09:40 +01:00
for ( const auto & record : keyword ) {
2018-10-17 13:35:25 +02:00
std : : fill ( max . begin ( ) , max . end ( ) , record . getItem ( " DRVDT_MAX " ) . getSIDouble ( 0 ) ) ;
OilVaporizationProperties ovp = this - > m_oilvaporizationproperties . get ( currentStep ) ;
OilVaporizationProperties : : updateDRVDT ( ovp , max ) ;
this - > m_oilvaporizationproperties . update ( currentStep , ovp ) ;
2015-10-02 10:49:23 +02:00
}
}
2016-02-09 12:09:40 +01:00
void Schedule : : handleDRSDT ( const DeckKeyword & keyword , size_t currentStep ) {
2018-10-17 13:35:25 +02:00
size_t numPvtRegions = m_runspec . tabdims ( ) . getNumPVTTables ( ) ;
std : : vector < double > max ( numPvtRegions ) ;
std : : vector < std : : string > options ( numPvtRegions ) ;
2016-02-09 12:09:40 +01:00
for ( const auto & record : keyword ) {
2018-10-17 13:35:25 +02:00
std : : fill ( max . begin ( ) , max . end ( ) , record . getItem ( " DRSDT_MAX " ) . getSIDouble ( 0 ) ) ;
std : : fill ( options . begin ( ) , options . end ( ) , record . getItem ( " Option " ) . get < std : : string > ( 0 ) ) ;
OilVaporizationProperties ovp = this - > m_oilvaporizationproperties . get ( currentStep ) ;
OilVaporizationProperties : : updateDRSDT ( ovp , max , options ) ;
this - > m_oilvaporizationproperties . update ( currentStep , ovp ) ;
2015-10-02 10:49:23 +02:00
}
}
2015-05-28 14:55:09 +02:00
2018-10-17 13:35:25 +02:00
void Schedule : : handleDRSDTR ( const DeckKeyword & keyword , size_t currentStep ) {
size_t numPvtRegions = m_runspec . tabdims ( ) . getNumPVTTables ( ) ;
std : : vector < double > max ( numPvtRegions ) ;
std : : vector < std : : string > options ( numPvtRegions ) ;
size_t pvtRegionIdx = 0 ;
for ( const auto & record : keyword ) {
max [ pvtRegionIdx ] = record . getItem ( " DRSDT_MAX " ) . getSIDouble ( 0 ) ;
options [ pvtRegionIdx ] = record . getItem ( " Option " ) . get < std : : string > ( 0 ) ;
pvtRegionIdx + + ;
}
OilVaporizationProperties ovp = this - > m_oilvaporizationproperties . get ( currentStep ) ;
OilVaporizationProperties : : updateDRSDT ( ovp , max , options ) ;
this - > m_oilvaporizationproperties . update ( currentStep , ovp ) ;
}
void Schedule : : handleDRVDTR ( const DeckKeyword & keyword , size_t currentStep ) {
size_t numPvtRegions = m_runspec . tabdims ( ) . getNumPVTTables ( ) ;
size_t pvtRegionIdx = 0 ;
std : : vector < double > max ( numPvtRegions ) ;
for ( const auto & record : keyword ) {
max [ pvtRegionIdx ] = record . getItem ( " DRVDT_MAX " ) . getSIDouble ( 0 ) ;
pvtRegionIdx + + ;
}
OilVaporizationProperties ovp = this - > m_oilvaporizationproperties . get ( currentStep ) ;
OilVaporizationProperties : : updateDRVDT ( ovp , max ) ;
this - > m_oilvaporizationproperties . update ( currentStep , ovp ) ;
}
2019-01-03 11:53:32 +01:00
void Schedule : : handleWCONProducer ( const DeckKeyword & keyword , size_t currentStep , bool isPredictionMode , const ParseContext & parseContext , ErrorGuard & errors ) {
2016-02-09 12:09:40 +01:00
for ( const auto & record : keyword ) {
2014-06-27 00:17:56 +02:00
const std : : string & wellNamePattern =
2016-02-09 12:09:40 +01:00
record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
2014-06-27 00:17:56 +02:00
const WellCommon : : StatusEnum status =
2016-02-09 12:09:40 +01:00
WellCommon : : StatusFromString ( record . getItem ( " STATUS " ) . getTrimmedString ( 0 ) ) ;
2014-03-17 15:30:41 +01:00
2016-06-16 08:37:10 +02:00
auto wells = getWells ( wellNamePattern ) ;
2018-04-23 12:45:57 +02:00
if ( wells . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2014-06-27 00:17:56 +02:00
2018-04-23 12:45:57 +02:00
for ( auto * well : wells ) {
2015-10-27 14:12:28 +01:00
WellProductionProperties properties ;
2016-01-19 13:35:07 +01:00
2016-02-10 12:46:20 +01:00
if ( isPredictionMode ) {
auto addGrupProductionControl = well - > isAvailableForGroupControl ( currentStep ) ;
2016-01-19 13:35:07 +01:00
properties = WellProductionProperties : : prediction ( record , addGrupProductionControl ) ;
2016-11-02 13:29:00 +01:00
} else {
2015-10-27 14:12:28 +01:00
const WellProductionProperties & prev_properties = well - > getProductionProperties ( currentStep ) ;
2018-12-19 15:37:10 +01:00
const bool switching_from_injector = ! well - > isProducer ( currentStep ) ;
properties = WellProductionProperties : : history ( prev_properties , record , m_controlModeWHISTCTL , switching_from_injector ) ;
2014-07-07 15:33:05 +02:00
}
2016-06-15 14:34:28 +02:00
updateWellStatus ( * well , currentStep , status ) ;
2015-06-23 14:20:31 +02:00
if ( well - > setProductionProperties ( currentStep , properties ) )
2016-10-05 10:09:45 +02:00
m_events . addEvent ( ScheduleEvents : : PRODUCTION_UPDATE , currentStep ) ;
2017-04-05 14:43:25 +02:00
2015-10-08 12:17:29 +02:00
if ( ! well - > getAllowCrossFlow ( ) & & ! isPredictionMode & & ( properties . OilRate + properties . WaterRate + properties . GasRate ) = = 0 ) {
std : : string msg =
" Well " + well - > name ( ) + " is a history matched well with zero rate where crossflow is banned. " +
2016-11-08 18:29:52 +01:00
" This well will be closed at " + std : : to_string ( m_timeMap . getTimePassedUntil ( currentStep ) / ( 60 * 60 * 24 ) ) + " days " ;
2018-03-22 11:07:14 +01:00
OpmLog : : note ( msg ) ;
2016-06-15 14:34:28 +02:00
updateWellStatus ( * well , currentStep , WellCommon : : StatusEnum : : SHUT ) ;
2015-10-08 12:17:29 +02:00
}
2014-05-06 09:54:37 +02:00
}
2013-11-05 15:25:47 +01:00
}
2013-10-25 17:28:56 +02:00
}
2016-06-15 14:34:28 +02:00
void Schedule : : updateWellStatus ( Well & well , size_t reportStep , WellCommon : : StatusEnum status ) {
if ( well . setStatus ( reportStep , status ) )
2016-10-05 10:09:45 +02:00
m_events . addEvent ( ScheduleEvents : : WELL_STATUS_CHANGE , reportStep ) ;
2015-06-23 14:20:31 +02:00
}
2019-01-03 11:53:32 +01:00
void Schedule : : handleWCONHIST ( const DeckKeyword & keyword , size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
handleWCONProducer ( keyword , currentStep , false , parseContext , errors ) ;
2013-11-08 15:55:11 +01:00
}
2019-01-03 11:53:32 +01:00
void Schedule : : handleWCONPROD ( const DeckKeyword & keyword , size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
handleWCONProducer ( keyword , currentStep , true , parseContext , errors ) ;
2013-11-11 17:06:22 +01:00
}
2016-02-09 12:09:40 +01:00
void Schedule : : handleWPIMULT ( const DeckKeyword & keyword , size_t currentStep ) {
for ( const auto & record : keyword ) {
const std : : string & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
2015-06-02 13:26:37 +02:00
2018-06-25 19:16:52 +02:00
for ( auto * well : getWells ( wellNamePattern ) )
well - > handleWPIMULT ( record , currentStep ) ;
2015-06-02 09:30:08 +02:00
}
}
2018-06-25 19:16:52 +02:00
2019-01-03 11:53:32 +01:00
void Schedule : : handleWCONINJE ( const SCHEDULESection & section , const DeckKeyword & keyword , size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
2016-02-09 12:09:40 +01:00
for ( const auto & record : keyword ) {
const std : : string & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
2014-05-06 09:54:37 +02:00
2018-04-26 10:39:54 +02:00
auto wells = getWells ( wellNamePattern ) ;
if ( wells . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-04-26 10:39:54 +02:00
for ( auto * well : wells ) {
2016-02-09 12:09:40 +01:00
WellInjector : : TypeEnum injectorType = WellInjector : : TypeFromString ( record . getItem ( " TYPE " ) . getTrimmedString ( 0 ) ) ;
WellCommon : : StatusEnum status = WellCommon : : StatusFromString ( record . getItem ( " STATUS " ) . getTrimmedString ( 0 ) ) ;
2014-05-06 09:54:37 +02:00
2016-06-15 14:34:28 +02:00
updateWellStatus ( * well , currentStep , status ) ;
2014-05-06 09:54:37 +02:00
WellInjectionProperties properties ( well - > getInjectionPropertiesCopy ( currentStep ) ) ;
2014-08-25 11:56:17 +02:00
2014-05-06 09:54:37 +02:00
properties . injectorType = injectorType ;
properties . predictionMode = true ;
2014-12-08 16:34:28 +01:00
2016-02-09 12:09:40 +01:00
if ( ! record . getItem ( " RATE " ) . defaultApplied ( 0 ) ) {
2016-08-05 15:28:29 +02:00
properties . surfaceInjectionRate = convertInjectionRateToSI ( record . getItem ( " RATE " ) . get < double > ( 0 ) , injectorType , section . unitSystem ( ) ) ;
2014-05-06 09:54:37 +02:00
properties . addInjectionControl ( WellInjector : : RATE ) ;
2014-08-25 11:56:17 +02:00
} else
2014-08-25 11:20:54 +02:00
properties . dropInjectionControl ( WellInjector : : RATE ) ;
2014-05-06 09:54:37 +02:00
2016-02-09 12:09:40 +01:00
if ( ! record . getItem ( " RESV " ) . defaultApplied ( 0 ) ) {
properties . reservoirInjectionRate = record . getItem ( " RESV " ) . getSIDouble ( 0 ) ;
2014-08-25 11:20:54 +02:00
properties . addInjectionControl ( WellInjector : : RESV ) ;
2014-08-25 11:56:17 +02:00
} else
2014-08-25 11:20:54 +02:00
properties . dropInjectionControl ( WellInjector : : RESV ) ;
2014-05-06 09:54:37 +02:00
2014-08-25 11:20:54 +02:00
2016-02-09 12:09:40 +01:00
if ( ! record . getItem ( " THP " ) . defaultApplied ( 0 ) ) {
properties . THPLimit = record . getItem ( " THP " ) . getSIDouble ( 0 ) ;
2014-08-25 11:20:54 +02:00
properties . addInjectionControl ( WellInjector : : THP ) ;
2014-08-25 11:56:17 +02:00
} else
2014-12-08 16:34:28 +01:00
properties . dropInjectionControl ( WellInjector : : THP ) ;
2014-08-25 11:20:54 +02:00
2018-05-30 11:45:00 +02:00
properties . VFPTableNumber = record . getItem ( " VFP_TABLE " ) . get < int > ( 0 ) ;
2014-08-25 11:56:17 +02:00
/*
2016-10-28 16:32:11 +02:00
There is a sensible default BHP limit defined , so the BHPLimit can be
safely set unconditionally , and we make BHP limit as a constraint based
on that default value . It is not easy to infer from the manual , while the
current behavoir agrees with the behovir of Eclipse when BHPLimit is not
specified while employed during group control .
2014-08-25 11:56:17 +02:00
*/
2019-01-10 14:18:54 +01:00
properties . setBHPLimit ( record . getItem ( " BHP " ) . getSIDouble ( 0 ) ) ;
2016-10-28 16:32:11 +02:00
// BHP control should always be there.
properties . addInjectionControl ( WellInjector : : BHP ) ;
2014-07-07 15:33:05 +02:00
if ( well - > isAvailableForGroupControl ( currentStep ) )
properties . addInjectionControl ( WellInjector : : GRUP ) ;
else
properties . dropInjectionControl ( WellInjector : : GRUP ) ;
2014-05-06 09:54:37 +02:00
{
2016-02-09 12:09:40 +01:00
const std : : string & cmodeString = record . getItem ( " CMODE " ) . getTrimmedString ( 0 ) ;
2014-05-06 09:54:37 +02:00
WellInjector : : ControlModeEnum controlMode = WellInjector : : ControlModeFromString ( cmodeString ) ;
if ( properties . hasInjectionControl ( controlMode ) )
properties . controlMode = controlMode ;
else {
throw std : : invalid_argument ( " Tried to set invalid control: " + cmodeString + " for well: " + wellNamePattern ) ;
}
2014-03-03 15:00:42 +01:00
}
2015-10-08 12:17:29 +02:00
2015-06-23 14:20:31 +02:00
if ( well - > setInjectionProperties ( currentStep , properties ) )
2016-10-05 10:09:45 +02:00
m_events . addEvent ( ScheduleEvents : : INJECTION_UPDATE , currentStep ) ;
2015-10-08 12:17:29 +02:00
2018-02-08 17:00:58 +01:00
// if the well has zero surface rate limit or reservior rate limit, while does not allow crossflow,
// it should be turned off.
if ( ! well - > getAllowCrossFlow ( )
& & ( ( properties . hasInjectionControl ( WellInjector : : RATE ) & & properties . surfaceInjectionRate = = 0 )
| | ( properties . hasInjectionControl ( WellInjector : : RESV ) & & properties . reservoirInjectionRate = = 0 ) ) ) {
2015-10-08 12:17:29 +02:00
std : : string msg =
" Well " + well - > name ( ) + " is an injector with zero rate where crossflow is banned. " +
2016-11-08 18:29:52 +01:00
" This well will be closed at " + std : : to_string ( m_timeMap . getTimePassedUntil ( currentStep ) / ( 60 * 60 * 24 ) ) + " days " ;
2018-03-22 11:07:14 +01:00
OpmLog : : note ( msg ) ;
2016-06-15 14:34:28 +02:00
updateWellStatus ( * well , currentStep , WellCommon : : StatusEnum : : SHUT ) ;
2015-10-08 12:17:29 +02:00
}
2014-03-03 15:00:42 +01:00
}
2013-11-11 17:06:22 +01:00
}
}
2014-03-03 15:00:42 +01:00
2019-01-03 11:53:32 +01:00
void Schedule : : handleWPOLYMER ( const DeckKeyword & keyword , size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
2016-02-09 12:09:40 +01:00
for ( const auto & record : keyword ) {
const std : : string & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
2018-05-02 11:01:21 +02:00
const auto wells = getWells ( wellNamePattern ) ;
2014-11-20 16:20:54 +08:00
2018-05-02 11:01:21 +02:00
if ( wells . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-05-02 11:01:21 +02:00
for ( auto * well : wells ) {
2014-11-20 16:20:54 +08:00
WellPolymerProperties properties ( well - > getPolymerPropertiesCopy ( currentStep ) ) ;
2014-12-08 16:34:28 +01:00
2016-02-09 12:09:40 +01:00
properties . m_polymerConcentration = record . getItem ( " POLYMER_CONCENTRATION " ) . getSIDouble ( 0 ) ;
properties . m_saltConcentration = record . getItem ( " SALT_CONCENTRATION " ) . getSIDouble ( 0 ) ;
2014-11-20 17:23:12 +08:00
2016-02-09 12:09:40 +01:00
const auto & group_polymer_item = record . getItem ( " GROUP_POLYMER_CONCENTRATION " ) ;
const auto & group_salt_item = record . getItem ( " GROUP_SALT_CONCENTRATION " ) ;
2014-11-20 17:23:12 +08:00
2016-02-09 12:09:40 +01:00
if ( ! group_polymer_item . defaultApplied ( 0 ) ) {
2014-12-08 15:55:20 +01:00
throw std : : logic_error ( " Sorry explicit setting of \' GROUP_POLYMER_CONCENTRATION \' is not supported! " ) ;
2014-11-20 16:20:54 +08:00
}
2016-02-09 12:09:40 +01:00
if ( ! group_salt_item . defaultApplied ( 0 ) ) {
2014-12-08 15:55:20 +01:00
throw std : : logic_error ( " Sorry explicit setting of \' GROUP_SALT_CONCENTRATION \' is not supported! " ) ;
2014-11-20 17:23:12 +08:00
}
2014-11-20 16:20:54 +08:00
well - > setPolymerProperties ( currentStep , properties ) ;
}
}
}
2016-06-23 13:44:03 +02:00
2019-01-03 11:53:32 +01:00
void Schedule : : handleWPMITAB ( const DeckKeyword & keyword , const size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
2018-06-04 12:04:17 +02:00
2018-04-06 15:48:27 +02:00
for ( const auto & record : keyword ) {
2018-06-04 12:04:17 +02:00
2018-04-06 15:48:27 +02:00
const std : : string & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
2018-06-04 12:04:17 +02:00
const auto wells = getWells ( wellNamePattern ) ;
if ( wells . empty ( ) ) {
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-06-04 12:04:17 +02:00
}
for ( auto * well : wells ) {
2018-10-09 12:48:11 +02:00
if ( well - > isProducer ( currentStep ) ) {
throw std : : logic_error ( " WPMITAB keyword can not be applied to production well " + well - > name ( ) ) ;
}
2018-04-06 15:48:27 +02:00
WellPolymerProperties properties ( well - > getPolymerProperties ( currentStep ) ) ;
properties . m_plymwinjtable = record . getItem ( " TABLE_NUMBER " ) . get < int > ( 0 ) ;
well - > setPolymerProperties ( currentStep , properties ) ;
}
}
}
2016-06-23 13:44:03 +02:00
2019-01-03 11:53:32 +01:00
void Schedule : : handleWSKPTAB ( const DeckKeyword & keyword , const size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
2018-06-04 12:04:17 +02:00
2018-04-12 15:39:45 +02:00
for ( const auto & record : keyword ) {
const std : : string & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
2018-06-04 12:04:17 +02:00
const auto wells = getWells ( wellNamePattern ) ;
if ( wells . empty ( ) ) {
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-06-04 12:04:17 +02:00
}
for ( auto * well : wells ) {
2018-10-09 12:48:11 +02:00
if ( well - > isProducer ( currentStep ) ) {
throw std : : logic_error ( " WSKPTAB can not be applied to production well " + well - > name ( ) ) ;
}
2018-04-12 15:39:45 +02:00
WellPolymerProperties properties ( well - > getPolymerProperties ( currentStep ) ) ;
properties . m_skprwattable = record . getItem ( " TABLE_NUMBER_WATER " ) . get < int > ( 0 ) ;
properties . m_skprpolytable = record . getItem ( " TABLE_NUMBER_POLYMER " ) . get < int > ( 0 ) ;
well - > setPolymerProperties ( currentStep , properties ) ;
}
}
}
2016-06-23 13:44:03 +02:00
2019-01-03 11:53:32 +01:00
void Schedule : : handleWECON ( const DeckKeyword & keyword , size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
2016-06-23 13:44:03 +02:00
for ( const auto & record : keyword ) {
const std : : string & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
WellEconProductionLimits econ_production_limits ( record ) ;
2018-05-03 09:34:54 +02:00
const auto wells = getWells ( wellNamePattern ) ;
2016-06-23 13:44:03 +02:00
2018-05-03 09:34:54 +02:00
if ( wells . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-05-03 09:34:54 +02:00
for ( auto * well : wells ) {
2016-06-23 13:44:03 +02:00
well - > setEconProductionLimits ( currentStep , econ_production_limits ) ;
}
}
}
2019-01-03 11:53:32 +01:00
void Schedule : : handleWEFAC ( const DeckKeyword & keyword , size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
2017-11-21 09:55:07 +01:00
for ( const auto & record : keyword ) {
const std : : string & wellNamePattern = record . getItem ( " WELLNAME " ) . getTrimmedString ( 0 ) ;
const double & efficiencyFactor = record . getItem ( " EFFICIENCY_FACTOR " ) . get < double > ( 0 ) ;
2018-05-03 09:34:54 +02:00
const auto wells = getWells ( wellNamePattern ) ;
2017-11-21 09:55:07 +01:00
2018-05-03 09:34:54 +02:00
if ( wells . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-05-03 09:34:54 +02:00
for ( auto * well : wells ) {
2017-11-21 09:55:07 +01:00
well - > setEfficiencyFactor ( currentStep , efficiencyFactor ) ;
}
}
}
2016-06-23 13:44:03 +02:00
2019-01-03 11:53:32 +01:00
void Schedule : : handleWTEST ( const DeckKeyword & keyword , size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
2018-05-14 04:18:07 +02:00
const auto & current = * this - > wtest_config . get ( currentStep ) ;
std : : shared_ptr < WellTestConfig > new_config ( new WellTestConfig ( current ) ) ;
for ( const auto & record : keyword ) {
const std : : string & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
const auto wells = getWells ( wellNamePattern ) ;
if ( wells . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-05-14 04:18:07 +02:00
double test_interval = record . getItem ( " INTERVAL " ) . getSIDouble ( 0 ) ;
const std : : string & reason = record . getItem ( " REASON " ) . get < std : : string > ( 0 ) ;
int num_test = record . getItem ( " TEST_NUM " ) . get < int > ( 0 ) ;
double startup_time = record . getItem ( " START_TIME " ) . getSIDouble ( 0 ) ;
for ( auto * well : wells ) {
if ( reason . size ( ) = = 0 )
new_config - > drop_well ( well - > name ( ) ) ;
else
new_config - > add_well ( well - > name ( ) , reason , test_interval , num_test , startup_time ) ;
}
}
this - > wtest_config . update ( currentStep , new_config ) ;
}
2019-01-03 11:53:32 +01:00
void Schedule : : handleWSOLVENT ( const DeckKeyword & keyword , size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
2015-08-05 08:30:25 +02:00
2016-02-09 12:09:40 +01:00
for ( const auto & record : keyword ) {
const std : : string & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
2018-05-02 11:01:21 +02:00
const auto wells = getWells ( wellNamePattern ) ;
2015-08-04 13:55:16 +02:00
2018-05-02 11:01:21 +02:00
if ( wells . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-05-02 11:01:21 +02:00
for ( auto * well : wells ) {
2015-08-05 08:30:25 +02:00
WellInjectionProperties injectionProperties = well - > getInjectionProperties ( currentStep ) ;
if ( well - > isInjector ( currentStep ) & & injectionProperties . injectorType = = WellInjector : : GAS ) {
2016-02-09 12:09:40 +01:00
double fraction = record . getItem ( " SOLVENT_FRACTION " ) . get < double > ( 0 ) ;
2015-08-05 08:30:25 +02:00
well - > setSolventFraction ( currentStep , fraction ) ;
} else {
throw std : : invalid_argument ( " WSOLVENT keyword can only be applied to Gas injectors " ) ;
}
2015-08-04 13:55:16 +02:00
}
}
}
2019-01-03 11:53:32 +01:00
void Schedule : : handleWTRACER ( const DeckKeyword & keyword , size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
2018-11-12 09:05:01 +01:00
for ( const auto & record : keyword ) {
const std : : string & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
const auto wells = getWells ( wellNamePattern ) ;
if ( wells . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-11-12 09:05:01 +01:00
for ( auto * well : wells ) {
WellTracerProperties wellTracerProperties = well - > getTracerProperties ( currentStep ) ;
double tracerConcentration = record . getItem ( " CONCENTRATION " ) . get < double > ( 0 ) ;
const std : : string & tracerName = record . getItem ( " TRACER " ) . getTrimmedString ( 0 ) ;
wellTracerProperties . setConcentration ( tracerName , tracerConcentration ) ;
well - > setTracerProperties ( currentStep , wellTracerProperties ) ;
}
}
}
2015-08-04 13:55:16 +02:00
2019-01-03 11:53:32 +01:00
void Schedule : : handleWTEMP ( const DeckKeyword & keyword , size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
2017-11-23 13:18:33 +01:00
for ( const auto & record : keyword ) {
const std : : string & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
2018-04-26 14:41:39 +02:00
auto wells = getWells ( wellNamePattern ) ;
2017-11-23 13:18:33 +01:00
2018-04-26 14:41:39 +02:00
if ( wells . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-04-26 14:41:39 +02:00
for ( auto * well : wells ) {
2018-04-10 14:56:11 +02:00
// TODO: Is this the right approach? Setting the well temperature only
// has an effect on injectors, but specifying it for producers won't hurt
// and wells can also switch their injector/producer status. Note that
2017-11-23 13:18:33 +01:00
// modifying the injector properties for producer wells currently leads
// to a very weird segmentation fault downstream. For now, let's take the
// water route.
if ( well - > isInjector ( currentStep ) ) {
WellInjectionProperties injectionProperties = well - > getInjectionProperties ( currentStep ) ;
injectionProperties . temperature = record . getItem ( " TEMP " ) . getSIDouble ( 0 ) ;
2018-04-10 14:56:11 +02:00
well - > setInjectionProperties ( currentStep , injectionProperties ) ;
}
}
}
}
2019-01-03 11:53:32 +01:00
void Schedule : : handleWINJTEMP ( const DeckKeyword & keyword , size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
2018-04-10 14:56:11 +02:00
// we do not support the "enthalpy" field yet. how to do this is a more difficult
// question.
for ( const auto & record : keyword ) {
const std : : string & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
2018-04-26 14:41:39 +02:00
auto wells = getWells ( wellNamePattern ) ;
if ( wells . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-04-10 14:56:11 +02:00
2018-04-26 14:41:39 +02:00
for ( auto * well : wells ) {
2018-04-10 14:56:11 +02:00
// TODO: Is this the right approach? Setting the well temperature only
// has an effect on injectors, but specifying it for producers won't hurt
// and wells can also switch their injector/producer status. Note that
// modifying the injector properties for producer wells currently leads
// to a very weird segmentation fault downstream. For now, let's take the
// water route.
if ( well - > isInjector ( currentStep ) ) {
WellInjectionProperties injectionProperties = well - > getInjectionProperties ( currentStep ) ;
injectionProperties . temperature = record . getItem ( " TEMPERATURE " ) . getSIDouble ( 0 ) ;
2017-11-23 13:18:33 +01:00
well - > setInjectionProperties ( currentStep , injectionProperties ) ;
}
}
}
}
2019-01-03 11:53:32 +01:00
void Schedule : : handleWCONINJH ( const SCHEDULESection & section , const DeckKeyword & keyword , size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
2016-02-09 12:09:40 +01:00
for ( const auto & record : keyword ) {
2018-04-26 10:39:54 +02:00
const std : : string & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
2014-02-07 17:19:37 +01:00
2014-02-10 16:15:22 +01:00
// convert injection rates to SI
2019-01-03 13:16:15 +01:00
const auto & typeItem = record . getItem ( " TYPE " ) ;
if ( typeItem . defaultApplied ( 0 ) ) {
const std : : string msg = " Injection type can not be defaulted for keyword WCONINJH " ;
throw std : : invalid_argument ( msg ) ;
}
const WellInjector : : TypeEnum injectorType = WellInjector : : TypeFromString ( typeItem . getTrimmedString ( 0 ) ) ;
2016-02-09 12:09:40 +01:00
double injectionRate = record . getItem ( " RATE " ) . get < double > ( 0 ) ;
2016-08-05 15:28:29 +02:00
injectionRate = convertInjectionRateToSI ( injectionRate , injectorType , section . unitSystem ( ) ) ;
2014-02-07 17:19:37 +01:00
2016-02-09 12:09:40 +01:00
WellCommon : : StatusEnum status = WellCommon : : StatusFromString ( record . getItem ( " STATUS " ) . getTrimmedString ( 0 ) ) ;
2014-02-10 16:15:22 +01:00
2018-04-26 10:39:54 +02:00
auto wells = getWells ( wellNamePattern ) ;
2014-09-19 17:40:40 +02:00
2018-04-26 10:39:54 +02:00
if ( wells . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2014-09-22 10:11:46 +02:00
2018-04-26 10:39:54 +02:00
for ( auto * well : wells ) {
updateWellStatus ( * well , currentStep , status ) ;
WellInjectionProperties properties ( well - > getInjectionPropertiesCopy ( currentStep ) ) ;
properties . injectorType = injectorType ;
if ( ! record . getItem ( " RATE " ) . defaultApplied ( 0 ) ) {
properties . surfaceInjectionRate = injectionRate ;
}
if ( record . getItem ( " BHP " ) . hasValue ( 0 ) )
properties . BHPH = record . getItem ( " BHP " ) . getSIDouble ( 0 ) ;
if ( record . getItem ( " THP " ) . hasValue ( 0 ) )
properties . THPH = record . getItem ( " THP " ) . getSIDouble ( 0 ) ;
2018-12-18 14:42:25 +01:00
const std : : string & cmodeString = record . getItem ( " CMODE " ) . getTrimmedString ( 0 ) ;
2019-01-03 13:16:15 +01:00
const WellInjector : : ControlModeEnum controlMode = WellInjector : : ControlModeFromString ( cmodeString ) ;
if ( ! ( controlMode = = WellInjector : : RATE | | controlMode = = WellInjector : : BHP ) ) {
const std : : string msg = " Only RATE and BHP control are allowed for WCONINJH for well " + well - > name ( ) ;
throw std : : invalid_argument ( msg ) ;
}
// when well is under BHP control, we use its historical BHP value as BHP limit
if ( controlMode = = WellInjector : : BHP ) {
2019-01-10 14:18:54 +01:00
properties . setBHPLimit ( properties . BHPH ) ;
2019-01-03 13:16:15 +01:00
} else {
const bool switching_from_producer = well - > isProducer ( currentStep ) ;
const bool switching_from_prediction = properties . predictionMode ;
2019-01-10 14:18:54 +01:00
const bool switching_from_BHP_control = ( properties . controlMode = = WellInjector : : BHP ) ;
2019-01-03 13:16:15 +01:00
if ( switching_from_prediction | |
switching_from_BHP_control | |
switching_from_producer ) {
2019-01-10 14:18:54 +01:00
properties . resetDefaultHistoricalBHPLimit ( ) ;
2019-01-03 13:16:15 +01:00
}
// otherwise, we keep its previous BHP limit
2018-12-18 14:42:25 +01:00
}
2018-12-19 15:37:10 +01:00
2018-12-18 14:42:25 +01:00
properties . addInjectionControl ( WellInjector : : BHP ) ;
properties . addInjectionControl ( controlMode ) ;
properties . controlMode = controlMode ;
properties . predictionMode = false ;
2018-05-30 12:58:44 +02:00
const int VFPTableNumber = record . getItem ( " VFP_TABLE " ) . get < int > ( 0 ) ;
if ( VFPTableNumber > 0 ) {
properties . VFPTableNumber = VFPTableNumber ;
}
2018-04-26 10:39:54 +02:00
if ( well - > setInjectionProperties ( currentStep , properties ) )
m_events . addEvent ( ScheduleEvents : : INJECTION_UPDATE , currentStep ) ;
if ( ! well - > getAllowCrossFlow ( ) & & ( injectionRate = = 0 ) ) {
std : : string msg =
" Well " + well - > name ( ) + " is an injector with zero rate where crossflow is banned. " +
" This well will be closed at " + std : : to_string ( m_timeMap . getTimePassedUntil ( currentStep ) / ( 60 * 60 * 24 ) ) + " days " ;
OpmLog : : note ( msg ) ;
updateWellStatus ( * well , currentStep , WellCommon : : StatusEnum : : SHUT ) ;
}
2015-10-08 12:17:29 +02:00
}
2013-11-11 17:06:22 +01:00
}
2013-11-08 15:55:11 +01:00
}
2016-11-29 15:46:55 +01:00
void Schedule : : handleCOMPLUMP ( const DeckKeyword & keyword ,
size_t timestep ) {
for ( const auto & record : keyword ) {
2018-06-25 18:17:55 +02:00
const std : : string & well_name = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
auto & well = this - > m_wells . get ( well_name ) ;
well . handleCOMPLUMP ( record , timestep ) ;
2016-11-29 15:46:55 +01:00
}
}
2019-01-03 11:53:32 +01:00
void Schedule : : handleWELOPEN ( const DeckKeyword & keyword , size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
2015-06-02 13:26:37 +02:00
2016-12-01 13:44:38 +01:00
auto all_defaulted = [ ] ( const DeckRecord & rec ) {
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
2016-12-01 13:44:38 +01:00
constexpr auto open = WellCommon : : StatusEnum : : OPEN ;
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 ) ;
2018-05-03 09:18:53 +02:00
auto wells = getWells ( wellNamePattern ) ;
if ( wells . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , 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
*/
if ( all_defaulted ( record ) ) {
2018-06-25 18:45:01 +02:00
const auto well_status = WellCommon : : StatusFromString ( status_str ) ;
2018-05-03 09:18:53 +02:00
for ( auto * well : wells ) {
2018-06-25 18:45:01 +02:00
if ( well_status = = open & & ! well - > canOpen ( currentStep ) ) {
2016-12-01 13:44:38 +01:00
auto days = m_timeMap . getTimePassedUntil ( currentStep ) / ( 60 * 60 * 24 ) ;
std : : string msg = " Well " + well - > name ( )
+ " where crossflow is banned has zero total rate. "
+ " This well is prevented from opening at "
+ std : : to_string ( days ) + " days " ;
2018-03-22 11:07:14 +01:00
OpmLog : : note ( msg ) ;
2016-12-01 13:44:38 +01:00
} else {
2018-06-25 18:45:01 +02:00
this - > updateWellStatus ( * well , currentStep , well_status ) ;
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 ;
}
2018-05-03 09:18:53 +02:00
for ( auto * well : wells ) {
2018-06-25 18:45:01 +02:00
const auto comp_status = WellCompletion : : StateEnumFromString ( status_str ) ;
well - > handleWELOPEN ( record , currentStep , comp_status ) ;
2016-12-01 13:44:38 +01:00
m_events . addEvent ( ScheduleEvents : : COMPLETION_CHANGE , currentStep ) ;
2015-03-25 08:20:22 +01:00
}
}
}
2015-04-07 08:02:06 +02:00
/*
2015-07-26 23:13:49 +02:00
The documentation for the WELTARG keyword says that the well
must have been fully specified and initialized using one of the
WCONxxxx keywords prior to modifying the well using the WELTARG
keyword .
The following implementation of handling the WELTARG keyword
does not check or enforce in any way that this is done ( i . e . it
is not checked or verified that the well is initialized with any
WCONxxxx keyword ) .
2015-04-07 08:02:06 +02:00
*/
2015-07-26 23:13:49 +02:00
2018-05-03 09:18:53 +02:00
void Schedule : : handleWELTARG ( const SCHEDULESection & section ,
const DeckKeyword & keyword ,
size_t currentStep ,
2019-01-03 11:53:32 +01:00
const ParseContext & parseContext , ErrorGuard & errors ) {
2016-08-05 15:28:29 +02:00
Opm : : UnitSystem unitSystem = section . unitSystem ( ) ;
2016-10-07 16:55:04 +02:00
double siFactorL = unitSystem . parse ( " LiquidSurfaceVolume/Time " ) . getSIScaling ( ) ;
double siFactorG = unitSystem . parse ( " GasSurfaceVolume/Time " ) . getSIScaling ( ) ;
double siFactorP = unitSystem . parse ( " Pressure " ) . getSIScaling ( ) ;
2015-04-07 08:02:06 +02:00
2016-02-09 12:09:40 +01:00
for ( const auto & record : keyword ) {
2015-01-13 11:25:28 +01:00
2016-02-09 12:09:40 +01:00
const std : : string & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
const std : : string & cMode = record . getItem ( " CMODE " ) . getTrimmedString ( 0 ) ;
double newValue = record . getItem ( " NEW_VALUE " ) . get < double > ( 0 ) ;
2015-03-25 08:20:22 +01:00
2016-07-15 14:37:18 +02:00
const auto wells = getWells ( wellNamePattern ) ;
if ( wells . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2016-07-15 14:37:18 +02:00
for ( auto * well : wells ) {
2015-09-04 13:42:10 +02:00
if ( well - > isProducer ( currentStep ) ) {
WellProductionProperties prop = well - > getProductionPropertiesCopy ( currentStep ) ;
2015-01-16 17:49:28 +01:00
2015-09-04 13:42:10 +02:00
if ( cMode = = " ORAT " ) {
prop . OilRate = newValue * siFactorL ;
}
else if ( cMode = = " WRAT " ) {
prop . WaterRate = newValue * siFactorL ;
}
else if ( cMode = = " GRAT " ) {
prop . GasRate = newValue * siFactorG ;
}
else if ( cMode = = " LRAT " ) {
prop . LiquidRate = newValue * siFactorL ;
}
else if ( cMode = = " RESV " ) {
prop . ResVRate = newValue * siFactorL ;
}
else if ( cMode = = " BHP " ) {
prop . BHPLimit = newValue * siFactorP ;
}
else if ( cMode = = " THP " ) {
prop . THPLimit = newValue * siFactorP ;
}
else if ( cMode = = " VFP " ) {
prop . VFPTableNumber = static_cast < int > ( newValue ) ;
}
else if ( cMode = = " GUID " ) {
well - > setGuideRate ( currentStep , newValue ) ;
}
else {
throw std : : invalid_argument ( " Invalid keyword (MODE) supplied " ) ;
}
well - > setProductionProperties ( currentStep , prop ) ;
} else {
WellInjectionProperties prop = well - > getInjectionPropertiesCopy ( currentStep ) ;
if ( cMode = = " BHP " ) {
prop . BHPLimit = newValue * siFactorP ;
}
else if ( cMode = = " ORAT " ) {
if ( prop . injectorType = = WellInjector : : TypeEnum : : OIL ) {
prop . surfaceInjectionRate = newValue * siFactorL ;
} else {
2015-09-07 12:19:55 +02:00
std : : invalid_argument ( " Well type must be OIL to set the oil rate " ) ;
2015-09-04 13:42:10 +02:00
}
}
else if ( cMode = = " WRAT " ) {
if ( prop . injectorType = = WellInjector : : TypeEnum : : WATER ) {
prop . surfaceInjectionRate = newValue * siFactorL ;
} else {
2015-09-07 12:19:55 +02:00
std : : invalid_argument ( " Well type must be WATER to set the water rate " ) ;
2015-09-04 13:42:10 +02:00
}
}
else if ( cMode = = " GRAT " ) {
if ( prop . injectorType = = WellInjector : : TypeEnum : : GAS ) {
2015-09-04 13:46:23 +02:00
prop . surfaceInjectionRate = newValue * siFactorG ;
2015-09-04 13:42:10 +02:00
} else {
2015-09-07 12:19:55 +02:00
std : : invalid_argument ( " Well type must be GAS to set the gas rate " ) ;
2015-09-04 13:42:10 +02:00
}
}
else if ( cMode = = " THP " ) {
prop . THPLimit = newValue * siFactorP ;
}
else if ( cMode = = " VFP " ) {
prop . VFPTableNumber = static_cast < int > ( newValue ) ;
}
else if ( cMode = = " GUID " ) {
well - > setGuideRate ( currentStep , newValue ) ;
}
else if ( cMode = = " RESV " ) {
prop . reservoirInjectionRate = newValue * siFactorL ;
}
else {
throw std : : invalid_argument ( " Invalid keyword (MODE) supplied " ) ;
}
well - > setInjectionProperties ( currentStep , prop ) ;
2015-03-25 08:20:22 +01:00
}
2015-09-04 13:42:10 +02:00
2015-01-13 11:25:28 +01:00
}
2014-02-04 16:12:49 +01:00
}
}
2019-01-03 11:53:32 +01:00
void Schedule : : handleGCONINJE ( const SCHEDULESection & section , const DeckKeyword & keyword , size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
2016-02-09 12:09:40 +01:00
for ( const auto & record : keyword ) {
2018-05-03 13:20:04 +02:00
const std : : string & groupNamePattern = record . getItem ( " GROUP " ) . getTrimmedString ( 0 ) ;
auto groups = getGroups ( groupNamePattern ) ;
2013-11-18 16:06:50 +01:00
2018-05-03 14:04:19 +02:00
if ( groups . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( groupNamePattern , parseContext , errors , keyword ) ;
2018-05-03 14:04:19 +02:00
2018-05-03 13:20:04 +02:00
for ( auto * group : groups ) {
{
Phase phase = get_phase ( record . getItem ( " PHASE " ) . getTrimmedString ( 0 ) ) ;
group - > setInjectionPhase ( currentStep , phase ) ;
}
{
GroupInjection : : ControlEnum controlMode = GroupInjection : : ControlEnumFromString ( record . getItem ( " CONTROL_MODE " ) . getTrimmedString ( 0 ) ) ;
group - > setInjectionControlMode ( currentStep , controlMode ) ;
}
2014-02-10 16:15:22 +01:00
2018-05-03 13:20:04 +02:00
Phase wellPhase = get_phase ( record . getItem ( " PHASE " ) . getTrimmedString ( 0 ) ) ;
2014-02-10 16:15:22 +01:00
2018-05-03 13:20:04 +02:00
// calculate SI injection rates for the group
double surfaceInjectionRate = record . getItem ( " SURFACE_TARGET " ) . get < double > ( 0 ) ;
surfaceInjectionRate = convertInjectionRateToSI ( surfaceInjectionRate , wellPhase , section . unitSystem ( ) ) ;
double reservoirInjectionRate = record . getItem ( " RESV_TARGET " ) . getSIDouble ( 0 ) ;
2014-02-10 16:15:22 +01:00
2018-05-03 13:20:04 +02:00
group - > setSurfaceMaxRate ( currentStep , surfaceInjectionRate ) ;
group - > setReservoirMaxRate ( currentStep , reservoirInjectionRate ) ;
group - > setTargetReinjectFraction ( currentStep , record . getItem ( " REINJ_TARGET " ) . getSIDouble ( 0 ) ) ;
group - > setTargetVoidReplacementFraction ( currentStep , record . getItem ( " VOIDAGE_TARGET " ) . getSIDouble ( 0 ) ) ;
2014-02-10 15:29:59 +01:00
2018-05-03 13:20:04 +02:00
group - > setInjectionGroup ( currentStep , true ) ;
}
2013-11-18 16:06:50 +01:00
}
}
2019-01-03 11:53:32 +01:00
void Schedule : : handleGCONPROD ( const DeckKeyword & keyword , size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
2016-02-09 12:09:40 +01:00
for ( const auto & record : keyword ) {
2018-05-03 13:20:04 +02:00
const std : : string & groupNamePattern = record . getItem ( " GROUP " ) . getTrimmedString ( 0 ) ;
auto groups = getGroups ( groupNamePattern ) ;
2014-12-08 16:34:28 +01:00
2018-05-03 14:04:19 +02:00
if ( groups . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( groupNamePattern , parseContext , errors , keyword ) ;
2018-05-03 14:04:19 +02:00
2018-05-03 13:20:04 +02:00
for ( auto * group : groups ) {
{
GroupProduction : : ControlEnum controlMode = GroupProduction : : ControlEnumFromString ( record . getItem ( " CONTROL_MODE " ) . getTrimmedString ( 0 ) ) ;
group - > setProductionControlMode ( currentStep , controlMode ) ;
}
group - > setOilTargetRate ( currentStep , record . getItem ( " OIL_TARGET " ) . getSIDouble ( 0 ) ) ;
group - > setGasTargetRate ( currentStep , record . getItem ( " GAS_TARGET " ) . getSIDouble ( 0 ) ) ;
group - > setWaterTargetRate ( currentStep , record . getItem ( " WATER_TARGET " ) . getSIDouble ( 0 ) ) ;
group - > setLiquidTargetRate ( currentStep , record . getItem ( " LIQUID_TARGET " ) . getSIDouble ( 0 ) ) ;
group - > setReservoirVolumeTargetRate ( currentStep , record . getItem ( " RESERVOIR_FLUID_TARGET " ) . getSIDouble ( 0 ) ) ;
{
GroupProductionExceedLimit : : ActionEnum exceedAction = GroupProductionExceedLimit : : ActionEnumFromString ( record . getItem ( " EXCEED_PROC " ) . getTrimmedString ( 0 ) ) ;
group - > setProductionExceedLimitAction ( currentStep , exceedAction ) ;
}
group - > setProductionGroup ( currentStep , true ) ;
}
2013-11-20 17:07:49 +01:00
}
}
2016-01-20 14:58:32 +01:00
2019-01-03 11:53:32 +01:00
void Schedule : : handleGEFAC ( const DeckKeyword & keyword , size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
2016-02-09 12:09:40 +01:00
for ( const auto & record : keyword ) {
2018-05-03 13:20:04 +02:00
const std : : string & groupNamePattern = record . getItem ( " GROUP " ) . getTrimmedString ( 0 ) ;
auto groups = getGroups ( groupNamePattern ) ;
2016-01-20 14:58:32 +01:00
2018-05-03 14:04:19 +02:00
if ( groups . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( groupNamePattern , parseContext , errors , keyword ) ;
2018-05-03 14:04:19 +02:00
2018-05-03 13:20:04 +02:00
for ( auto * group : groups ) {
group - > setGroupEfficiencyFactor ( currentStep , record . getItem ( " EFFICIENCY_FACTOR " ) . get < double > ( 0 ) ) ;
2016-01-20 14:58:32 +01:00
2018-05-03 13:20:04 +02:00
const std : : string & transfer_str = record . getItem ( " TRANSFER_EXT_NET " ) . getTrimmedString ( 0 ) ;
bool transfer = ( transfer_str = = " YES " ) ? true : false ;
group - > setTransferGroupEfficiencyFactor ( currentStep , transfer ) ;
}
2016-01-20 14:58:32 +01:00
}
}
2016-02-09 12:09:40 +01:00
void Schedule : : handleTUNING ( const DeckKeyword & keyword , size_t currentStep ) {
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
int numrecords = keyword . size ( ) ;
2015-04-17 18:51:42 +02:00
if ( numrecords > 0 ) {
2016-02-09 12:09:40 +01:00
const auto & record1 = keyword . getRecord ( 0 ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double TSINIT = record1 . getItem ( " TSINIT " ) . getSIDouble ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setTSINIT ( currentStep , TSINIT ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double TSMAXZ = record1 . getItem ( " TSMAXZ " ) . getSIDouble ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setTSMAXZ ( currentStep , TSMAXZ ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double TSMINZ = record1 . getItem ( " TSMINZ " ) . getSIDouble ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setTSMINZ ( currentStep , TSMINZ ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double TSMCHP = record1 . getItem ( " TSMCHP " ) . getSIDouble ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setTSMCHP ( currentStep , TSMCHP ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double TSFMAX = record1 . getItem ( " TSFMAX " ) . get < double > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setTSFMAX ( currentStep , TSFMAX ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double TSFMIN = record1 . getItem ( " TSFMIN " ) . get < double > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setTSFMIN ( currentStep , TSFMIN ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double TSFCNV = record1 . getItem ( " TSFCNV " ) . get < double > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setTSFCNV ( currentStep , TSFCNV ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double TFDIFF = record1 . getItem ( " TFDIFF " ) . get < double > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setTFDIFF ( currentStep , TFDIFF ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double THRUPT = record1 . getItem ( " THRUPT " ) . get < double > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setTHRUPT ( currentStep , THRUPT ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
const auto & TMAXWCdeckItem = record1 . getItem ( " TMAXWC " ) ;
if ( TMAXWCdeckItem . hasValue ( 0 ) ) {
double TMAXWC = TMAXWCdeckItem . getSIDouble ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setTMAXWC ( currentStep , TMAXWC ) ;
2015-04-17 18:51:42 +02:00
}
}
if ( numrecords > 1 ) {
2016-02-09 12:09:40 +01:00
const auto & record2 = keyword . getRecord ( 1 ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double TRGTTE = record2 . getItem ( " TRGTTE " ) . get < double > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setTRGTTE ( currentStep , TRGTTE ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double TRGCNV = record2 . getItem ( " TRGCNV " ) . get < double > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setTRGCNV ( currentStep , TRGCNV ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double TRGMBE = record2 . getItem ( " TRGMBE " ) . get < double > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setTRGMBE ( currentStep , TRGMBE ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double TRGLCV = record2 . getItem ( " TRGLCV " ) . get < double > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setTRGLCV ( currentStep , TRGLCV ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double XXXTTE = record2 . getItem ( " XXXTTE " ) . get < double > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setXXXTTE ( currentStep , XXXTTE ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double XXXCNV = record2 . getItem ( " XXXCNV " ) . get < double > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setXXXCNV ( currentStep , XXXCNV ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double XXXMBE = record2 . getItem ( " XXXMBE " ) . get < double > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setXXXMBE ( currentStep , XXXMBE ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double XXXLCV = record2 . getItem ( " XXXLCV " ) . get < double > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setXXXLCV ( currentStep , XXXLCV ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double XXXWFL = record2 . getItem ( " XXXWFL " ) . get < double > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setXXXWFL ( currentStep , XXXWFL ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double TRGFIP = record2 . getItem ( " TRGFIP " ) . get < double > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setTRGFIP ( currentStep , TRGFIP ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
const auto & TRGSFTdeckItem = record2 . getItem ( " TRGSFT " ) ;
if ( TRGSFTdeckItem . hasValue ( 0 ) ) {
double TRGSFT = TRGSFTdeckItem . get < double > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setTRGSFT ( currentStep , TRGSFT ) ;
2015-04-17 18:51:42 +02:00
}
2016-02-09 12:09:40 +01:00
double THIONX = record2 . getItem ( " THIONX " ) . get < double > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setTHIONX ( currentStep , THIONX ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
int TRWGHT = record2 . getItem ( " TRWGHT " ) . get < int > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setTRWGHT ( currentStep , TRWGHT ) ;
2015-04-17 18:51:42 +02:00
}
if ( numrecords > 2 ) {
2016-02-09 12:09:40 +01:00
const auto & record3 = keyword . getRecord ( 2 ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
int NEWTMX = record3 . getItem ( " NEWTMX " ) . get < int > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setNEWTMX ( currentStep , NEWTMX ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
int NEWTMN = record3 . getItem ( " NEWTMN " ) . get < int > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setNEWTMN ( currentStep , NEWTMN ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
int LITMAX = record3 . getItem ( " LITMAX " ) . get < int > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setLITMAX ( currentStep , LITMAX ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
int LITMIN = record3 . getItem ( " LITMIN " ) . get < int > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setLITMIN ( currentStep , LITMIN ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
int MXWSIT = record3 . getItem ( " MXWSIT " ) . get < int > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setMXWSIT ( currentStep , MXWSIT ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
int MXWPIT = record3 . getItem ( " MXWPIT " ) . get < int > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setMXWPIT ( currentStep , MXWPIT ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double DDPLIM = record3 . getItem ( " DDPLIM " ) . getSIDouble ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setDDPLIM ( currentStep , DDPLIM ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double DDSLIM = record3 . getItem ( " DDSLIM " ) . get < double > ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setDDSLIM ( currentStep , DDSLIM ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
double TRGDPR = record3 . getItem ( " TRGDPR " ) . getSIDouble ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setTRGDPR ( currentStep , TRGDPR ) ;
2015-04-17 18:51:42 +02:00
2016-02-09 12:09:40 +01:00
const auto & XXXDPRdeckItem = record3 . getItem ( " XXXDPR " ) ;
if ( XXXDPRdeckItem . hasValue ( 0 ) ) {
double XXXDPR = XXXDPRdeckItem . getSIDouble ( 0 ) ;
2016-10-05 10:04:22 +02:00
this - > m_tuning . setXXXDPR ( currentStep , XXXDPR ) ;
2015-04-17 18:51:42 +02:00
}
}
2017-11-23 13:20:32 +01:00
m_events . addEvent ( ScheduleEvents : : TUNING_CHANGE , currentStep ) ;
2015-04-17 18:51:42 +02:00
}
2016-10-14 10:06:35 +08:00
void Schedule : : handleMESSAGES ( const DeckKeyword & keyword , size_t currentStep ) {
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 [ ] = {
{ " 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
}
2019-01-03 11:53:32 +01:00
void Schedule : : handleCOMPDAT ( const DeckKeyword & keyword , size_t currentStep , const EclipseGrid & grid , const Eclipse3DProperties & eclipseProperties , const ParseContext & parseContext , ErrorGuard & errors ) {
2018-06-25 13:50:58 +02:00
for ( const auto & record : keyword ) {
const std : : string & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
auto wells = getWells ( wellNamePattern ) ;
if ( wells . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-06-25 13:50:58 +02:00
for ( auto * well : wells ) {
well - > handleCOMPDAT ( currentStep , record , grid , eclipseProperties ) ;
if ( well - > getConnections ( currentStep ) . allConnectionsShut ( ) ) {
std : : string msg =
" All completions in well " + well - > name ( ) + " is shut at " + std : : to_string ( m_timeMap . getTimePassedUntil ( currentStep ) / ( 60 * 60 * 24 ) ) + " days. \n " +
2016-08-09 10:30:31 +02:00
" The well is therefore also shut. " ;
2018-06-25 13:50:58 +02:00
OpmLog : : note ( msg ) ;
updateWellStatus ( * well , currentStep , WellCommon : : StatusEnum : : SHUT ) ;
}
2016-08-09 10:30:31 +02:00
}
}
2016-10-05 10:09:45 +02:00
m_events . addEvent ( ScheduleEvents : : COMPLETION_CHANGE , currentStep ) ;
2013-11-09 13:17:42 +01:00
}
2018-06-25 13:50:58 +02:00
2016-02-09 12:09:40 +01:00
void Schedule : : handleWELSEGS ( const DeckKeyword & keyword , size_t currentStep ) {
2018-06-25 23:05:56 +02:00
const auto & record1 = keyword . getRecord ( 0 ) ;
auto & well = this - > m_wells . get ( record1 . getItem ( " WELL " ) . getTrimmedString ( 0 ) ) ;
well . handleWELSEGS ( keyword , currentStep ) ; WellSegments newSegmentset ;
2015-10-26 12:51:09 +01:00
}
2018-08-27 17:16:19 +02:00
void Schedule : : handleCOMPSEGS ( const DeckKeyword & keyword , size_t currentStep , const EclipseGrid & grid ) {
2016-02-09 12:09:40 +01:00
const auto & record1 = keyword . getRecord ( 0 ) ;
const std : : string & well_name = record1 . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
2016-11-08 18:42:29 +01:00
auto & well = this - > m_wells . get ( well_name ) ;
2018-08-27 17:16:19 +02:00
well . handleCOMPSEGS ( keyword , grid , currentStep ) ;
2015-11-10 09:53:38 +01:00
}
2016-02-09 12:09:40 +01:00
void Schedule : : handleWGRUPCON ( const DeckKeyword & keyword , size_t currentStep ) {
for ( const auto & record : keyword ) {
const std : : string & wellName = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
2016-11-08 18:42:29 +01:00
auto & well = this - > m_wells . get ( wellName ) ;
2014-02-19 15:43:42 +01:00
2016-02-09 12:09:40 +01:00
bool availableForGroupControl = convertEclipseStringToBool ( record . getItem ( " GROUP_CONTROLLED " ) . getTrimmedString ( 0 ) ) ;
2016-06-16 08:37:10 +02:00
well . setAvailableForGroupControl ( currentStep , availableForGroupControl ) ;
2014-02-19 15:43:42 +01:00
2016-06-16 08:37:10 +02:00
well . setGuideRate ( currentStep , record . getItem ( " GUIDE_RATE " ) . get < double > ( 0 ) ) ;
2014-02-21 12:48:36 +01:00
2016-02-09 12:09:40 +01:00
if ( ! record . getItem ( " PHASE " ) . defaultApplied ( 0 ) ) {
std : : string guideRatePhase = record . getItem ( " PHASE " ) . getTrimmedString ( 0 ) ;
2016-06-16 08:37:10 +02:00
well . setGuideRatePhase ( currentStep , GuideRate : : GuideRatePhaseEnumFromString ( guideRatePhase ) ) ;
2014-12-08 16:34:28 +01:00
} else
2016-06-16 08:37:10 +02:00
well . setGuideRatePhase ( currentStep , GuideRate : : UNDEFINED ) ;
2014-02-21 12:48:36 +01:00
2016-06-16 08:37:10 +02:00
well . setGuideRateScalingFactor ( currentStep , record . getItem ( " SCALING_FACTOR " ) . get < double > ( 0 ) ) ;
2014-02-17 16:10:31 +01:00
}
}
2016-02-09 12:09:40 +01:00
void Schedule : : handleGRUPTREE ( const DeckKeyword & keyword , size_t currentStep ) {
2016-10-05 10:34:58 +02:00
const auto & currentTree = m_rootGroupTree . get ( currentStep ) ;
auto newTree = currentTree ;
2016-02-09 12:09:40 +01:00
for ( const auto & record : keyword ) {
const std : : string & childName = record . getItem ( " CHILD_GROUP " ) . getTrimmedString ( 0 ) ;
const std : : string & parentName = record . getItem ( " PARENT_GROUP " ) . getTrimmedString ( 0 ) ;
2016-11-07 14:25:00 +01:00
newTree . update ( childName , parentName ) ;
2018-06-12 13:56:44 +02:00
newTree . updateSeqIndex ( childName , parentName ) ;
2014-03-03 13:29:02 +01:00
if ( ! hasGroup ( parentName ) )
addGroup ( parentName , currentStep ) ;
2014-12-08 16:34:28 +01:00
2014-03-03 13:29:02 +01:00
if ( ! hasGroup ( childName ) )
addGroup ( childName , currentStep ) ;
2013-11-14 16:08:10 +01:00
}
2016-10-05 10:34:58 +02:00
m_rootGroupTree . update ( currentStep , newTree ) ;
2013-11-14 16:08:10 +01:00
}
2015-02-06 14:57:24 +01:00
2017-12-04 16:24:07 +01:00
void Schedule : : handleGRUPNET ( const DeckKeyword & keyword , size_t currentStep ) {
for ( const auto & record : keyword ) {
const auto & groupName = record . getItem ( " NAME " ) . getTrimmedString ( 0 ) ;
if ( ! hasGroup ( groupName ) )
addGroup ( groupName , currentStep ) ;
auto & group = this - > m_groups . at ( groupName ) ;
int table = record . getItem ( " VFP_TABLE " ) . get < int > ( 0 ) ;
group . setGroupNetVFPTable ( currentStep , table ) ;
}
}
2016-02-09 12:09:40 +01:00
void Schedule : : handleWRFT ( const DeckKeyword & keyword , 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 ) ;
2015-02-06 14:54:03 +01:00
2017-09-08 22:25:55 +02:00
for ( auto * well : getWells ( wellNamePattern ) )
well - > updateRFTActive ( currentStep , RFTConnections : : RFTEnum : : YES ) ;
2015-02-06 14:54:03 +01:00
}
2017-09-08 22:25:55 +02:00
for ( auto & well : this - > m_wells )
well . setRFTForWellWhenFirstOpen ( currentStep ) ;
2015-02-06 14:54:03 +01:00
}
2016-02-09 12:09:40 +01:00
void Schedule : : handleWRFTPLT ( const DeckKeyword & keyword , size_t currentStep ) {
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 ) ;
2015-02-06 14:54:03 +01:00
2016-02-09 12:09:40 +01:00
RFTConnections : : RFTEnum RFTKey = RFTConnections : : RFTEnumFromString ( record . getItem ( " OUTPUT_RFT " ) . getTrimmedString ( 0 ) ) ;
PLTConnections : : PLTEnum PLTKey = PLTConnections : : PLTEnumFromString ( record . getItem ( " OUTPUT_PLT " ) . getTrimmedString ( 0 ) ) ;
2015-02-06 14:54:03 +01:00
2016-06-16 08:37:10 +02:00
for ( auto * well : getWells ( wellNamePattern ) ) {
2017-09-08 22:25:55 +02:00
well - > updateRFTActive ( currentStep , RFTKey ) ;
well - > updatePLTActive ( currentStep , PLTKey ) ;
2015-02-06 14:54:03 +01:00
}
}
}
2013-11-14 16:08:10 +01:00
2019-01-03 11:53:32 +01:00
void Schedule : : invalidNamePattern ( const std : : string & namePattern , const ParseContext & parseContext , ErrorGuard & errors , const DeckKeyword & keyword ) const {
2018-05-03 13:20:04 +02:00
std : : string msg = " Error when handling " + keyword . name ( ) + " . 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
}
2016-10-05 10:34:58 +02:00
const GroupTree & Schedule : : getGroupTree ( size_t timeStep ) const {
return m_rootGroupTree . get ( timeStep ) ;
2013-11-14 16:08:10 +01:00
}
2018-06-10 20:54:34 +02:00
void Schedule : : addWell ( const std : : string & wellName , const DeckRecord & record , size_t timeStep , WellCompletion : : CompletionOrderEnum wellConnectionOrder ) {
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
const std : : string phaseStr = record . getItem ( " PHASE " ) . getTrimmedString ( 0 ) ;
Phase preferredPhase ;
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 {
// Normal case.
preferredPhase = get_phase ( phaseStr ) ;
}
2016-02-09 12:09:40 +01:00
const auto & refDepthItem = record . getItem ( " REF_DEPTH " ) ;
2014-08-25 11:20:54 +02:00
2016-11-22 13:18:43 +01:00
double refDepth = refDepthItem . hasValue ( 0 )
? 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 ;
}
2018-04-30 16:53:33 +02:00
const size_t wseqIndex = m_wells . size ( ) ;
Well well ( wellName , wseqIndex ,
2018-11-02 15:21:28 +01:00
headI , headJ , refDepth , drainageRadius ,
2016-11-08 18:42:29 +01:00
preferredPhase , m_timeMap ,
timeStep ,
2018-06-10 20:54:34 +02:00
wellConnectionOrder , allowCrossFlow , automaticShutIn ) ;
2016-11-08 18:42:29 +01:00
m_wells . insert ( wellName , well ) ;
2016-10-05 10:09:45 +02:00
m_events . addEvent ( ScheduleEvents : : NEW_WELL , timeStep ) ;
2013-11-05 17:58:57 +01:00
}
2013-11-05 15:25:47 +01:00
size_t Schedule : : numWells ( ) const {
return m_wells . size ( ) ;
}
2015-02-12 12:54:57 +01:00
size_t Schedule : : numWells ( size_t timestep ) const {
2016-06-16 08:37:10 +02:00
return this - > getWells ( timestep ) . 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 {
2014-04-30 14:45:37 +02:00
return m_wells . hasKey ( wellName ) ;
2013-11-05 15:25:47 +01:00
}
2016-06-16 08:37:10 +02:00
std : : vector < const Well * > Schedule : : getWells ( ) const {
2016-11-08 18:29:52 +01:00
return getWells ( m_timeMap . size ( ) - 1 ) ;
2015-02-12 12:54:57 +01:00
}
2017-07-25 19:50:06 +02:00
/*
This will recursively go all the way down through the group tree
until the well leaf - nodes are encountered .
*/
std : : vector < const Well * > Schedule : : getWells ( const std : : string & group_name , size_t timeStep ) const {
if ( ! hasGroup ( group_name ) )
throw std : : invalid_argument ( " No such group: " + group_name ) ;
{
const auto & group = getGroup ( group_name ) ;
std : : vector < const Well * > wells ;
if ( group . hasBeenDefined ( timeStep ) ) {
const GroupTree & group_tree = getGroupTree ( timeStep ) ;
const auto & child_groups = group_tree . children ( group_name ) ;
if ( child_groups . size ( ) ) {
for ( const auto & child : child_groups ) {
const auto & child_wells = getWells ( child , timeStep ) ;
wells . insert ( wells . end ( ) , child_wells . begin ( ) , child_wells . end ( ) ) ;
}
} else {
for ( const auto & well_name : group . getWells ( timeStep ) ) {
wells . push_back ( getWell ( well_name ) ) ;
}
}
}
return wells ;
}
}
2018-04-30 16:53:33 +02:00
std : : vector < const Group * > Schedule : : getChildGroups ( const std : : string & group_name , size_t timeStep ) const {
2018-04-25 09:44:57 +02:00
if ( ! hasGroup ( group_name ) )
throw std : : invalid_argument ( " No such group: " + group_name ) ;
{
const auto & group = getGroup ( group_name ) ;
2018-04-30 16:53:33 +02:00
std : : vector < const Group * > child_groups ;
2018-04-25 09:44:57 +02:00
if ( group . hasBeenDefined ( timeStep ) ) {
const GroupTree & group_tree = getGroupTree ( timeStep ) ;
2018-04-26 13:29:08 +02:00
const auto & ch_grps = group_tree . children ( group_name ) ;
2018-05-18 13:04:49 +02:00
//for (const std::string& group_name : ch_grps) {
for ( auto it = ch_grps . begin ( ) ; it ! = ch_grps . end ( ) ; it + + ) {
child_groups . push_back ( & getGroup ( * it ) ) ;
2018-04-26 13:29:08 +02:00
}
}
return child_groups ;
}
2018-04-25 09:44:57 +02:00
}
std : : vector < const Well * > Schedule : : getChildWells ( const std : : string & group_name , size_t timeStep ) const {
if ( ! hasGroup ( group_name ) )
throw std : : invalid_argument ( " No such group: " + group_name ) ;
{
const auto & group = getGroup ( group_name ) ;
std : : vector < const Well * > wells ;
if ( group . hasBeenDefined ( timeStep ) ) {
const GroupTree & group_tree = getGroupTree ( timeStep ) ;
const auto & child_groups = group_tree . children ( group_name ) ;
if ( ! child_groups . size ( ) ) {
2018-05-18 13:04:49 +02:00
//for (const auto& well_name : group.getWells( timeStep )) {
const auto & ch_wells = group . getWells ( timeStep ) ;
for ( auto it = ch_wells . begin ( ) ; it ! = ch_wells . end ( ) ; it + + ) {
wells . push_back ( getWell ( * it ) ) ;
2018-04-25 09:44:57 +02:00
}
}
}
return wells ;
}
}
2016-06-16 08:37:10 +02:00
std : : vector < const Well * > Schedule : : getWells ( size_t timeStep ) const {
2016-11-08 18:29:52 +01:00
if ( timeStep > = m_timeMap . size ( ) ) {
2015-02-12 12:54:57 +01:00
throw std : : invalid_argument ( " Timestep to large " ) ;
}
2016-11-08 18:42:29 +01:00
auto defined = [ = ] ( const Well & w ) {
return w . hasBeenDefined ( timeStep ) ;
2016-06-16 08:37:10 +02:00
} ;
std : : vector < const Well * > wells ;
2016-11-08 18:42:29 +01:00
for ( const auto & well : m_wells ) {
if ( ! defined ( well ) ) continue ;
wells . push_back ( std : : addressof ( well ) ) ;
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
}
2016-06-16 08:37:10 +02:00
const Well * Schedule : : getWell ( const std : : string & wellName ) const {
2016-11-08 18:42:29 +01:00
return std : : addressof ( m_wells . get ( wellName ) ) ;
2016-03-29 14:13:54 +02:00
}
2015-05-28 14:55:09 +02:00
/*
Observe that this method only returns wells which have state = =
OPEN ; it does not include wells in state AUTO which might have
been opened by the simulator .
*/
2016-06-16 08:37:10 +02:00
std : : vector < const Well * > Schedule : : getOpenWells ( size_t timeStep ) const {
2016-11-08 18:42:29 +01:00
auto open = [ = ] ( const Well & w ) {
return w . getStatus ( timeStep ) = = WellCommon : : OPEN ;
2016-06-16 08:37:10 +02:00
} ;
std : : vector < const Well * > wells ;
2016-11-08 18:42:29 +01:00
for ( const auto & well : m_wells ) {
if ( ! open ( well ) ) continue ;
wells . push_back ( std : : addressof ( well ) ) ;
2015-05-28 14:55:09 +02:00
}
2016-06-16 08:37:10 +02:00
2015-05-28 14:55:09 +02:00
return wells ;
}
2016-06-16 08:37:10 +02:00
std : : vector < const Well * > Schedule : : getWellsMatching ( const std : : string & wellNamePattern ) const {
auto tmp = const_cast < Schedule * > ( this ) - > getWells ( wellNamePattern ) ;
return { tmp . begin ( ) , tmp . end ( ) } ;
}
2015-05-28 14:55:09 +02:00
2016-06-16 08:37:10 +02:00
std : : vector < Well * > Schedule : : getWells ( const std : : string & wellNamePattern ) {
2015-02-12 12:54:57 +01:00
size_t wildcard_pos = wellNamePattern . find ( " * " ) ;
2016-07-15 14:37:18 +02:00
if ( wildcard_pos ! = wellNamePattern . length ( ) - 1 ) {
if ( ! m_wells . hasKey ( wellNamePattern ) ) return { } ;
2016-11-08 18:42:29 +01:00
return { std : : addressof ( m_wells . get ( wellNamePattern ) ) } ;
2015-02-12 12:54:57 +01:00
}
2016-07-15 14:37:18 +02:00
std : : vector < Well * > wells ;
2016-11-08 18:42:29 +01:00
for ( auto & well : this - > m_wells ) {
if ( Well : : wellNameInWellNamePattern ( well . name ( ) , wellNamePattern ) ) {
wells . push_back ( std : : addressof ( well ) ) ;
2016-07-15 14:37:18 +02:00
}
2015-02-12 12:54:57 +01:00
}
2016-07-15 14:37:18 +02:00
2015-02-12 12:54:57 +01:00
return wells ;
}
2013-11-25 16:31:44 +01:00
void Schedule : : addGroup ( const std : : string & groupName , size_t timeStep ) {
2018-04-30 16:53:33 +02:00
const size_t gseqIndex = m_groups . size ( ) ;
m_groups . insert ( groupName , Group { groupName , gseqIndex , m_timeMap , timeStep } ) ;
2016-10-05 10:09:45 +02:00
m_events . addEvent ( ScheduleEvents : : NEW_GROUP , timeStep ) ;
2013-11-18 13:11:49 +01:00
}
size_t Schedule : : numGroups ( ) const {
return m_groups . size ( ) ;
}
2018-04-24 14:03:29 +02:00
size_t Schedule : : numGroups ( size_t timeStep ) const {
return this - > getGroups ( timeStep ) . size ( ) ;
}
2013-11-18 13:11:49 +01:00
bool Schedule : : hasGroup ( const std : : string & groupName ) const {
2018-03-18 19:33:58 +01:00
return m_groups . hasKey ( groupName ) ;
2013-11-18 13:11:49 +01:00
}
2015-04-08 08:54:10 +02:00
2016-10-05 14:39:01 +02:00
const Group & Schedule : : getGroup ( const std : : string & groupName ) const {
2013-11-18 13:11:49 +01:00
if ( hasGroup ( groupName ) ) {
2016-10-05 14:39:01 +02:00
return m_groups . at ( groupName ) ;
2013-11-18 13:11:49 +01:00
} else
throw std : : invalid_argument ( " Group: " + groupName + " does not exist " ) ;
}
2016-02-01 14:16:07 +01:00
std : : vector < const Group * > Schedule : : getGroups ( ) const {
std : : vector < const Group * > groups ;
2018-03-18 19:33:58 +01:00
for ( const auto & group : m_groups )
groups . push_back ( & group ) ;
2016-02-01 14:16:07 +01:00
return groups ;
}
2015-04-17 18:51:42 +02:00
2018-05-03 13:20:04 +02:00
std : : vector < Group * > Schedule : : getGroups ( const std : : string & groupNamePattern ) {
size_t wildcard_pos = groupNamePattern . find ( " * " ) ;
if ( wildcard_pos ! = groupNamePattern . length ( ) - 1 ) {
if ( ! m_groups . hasKey ( groupNamePattern ) ) return { } ;
return { std : : addressof ( m_groups . get ( groupNamePattern ) ) } ;
}
std : : vector < Group * > groups ;
for ( auto & group : this - > m_groups ) {
if ( Group : : groupNameInGroupNamePattern ( group . name ( ) , groupNamePattern ) ) {
groups . push_back ( std : : addressof ( group ) ) ;
}
}
return groups ;
}
2018-04-24 14:03:29 +02:00
std : : vector < const Group * > Schedule : : getGroups ( size_t timeStep ) const {
if ( timeStep > = m_timeMap . size ( ) ) {
throw std : : invalid_argument ( " Timestep to large " ) ;
}
auto defined = [ = ] ( const Group & g ) {
return g . hasBeenDefined ( timeStep ) ;
} ;
2018-04-24 14:03:29 +02:00
std : : vector < const Group * > groups ;
for ( const auto & group : m_groups ) {
if ( ! defined ( group ) ) continue ;
groups . push_back ( & group ) ;
}
return groups ;
}
2016-06-16 08:37:10 +02:00
void Schedule : : addWellToGroup ( Group & newGroup , Well & well , size_t timeStep ) {
const std : : string currentGroupName = well . getGroupName ( timeStep ) ;
2013-11-26 12:48:20 +01:00
if ( currentGroupName ! = " " ) {
2016-10-05 14:39:01 +02:00
m_groups . at ( currentGroupName ) . delWell ( timeStep , well . name ( ) ) ;
2013-11-26 12:48:20 +01:00
}
2016-06-16 08:37:10 +02:00
well . setGroupName ( timeStep , newGroup . name ( ) ) ;
newGroup . addWell ( timeStep , & well ) ;
2013-11-26 12:48:20 +01:00
}
2013-11-18 13:11:49 +01:00
2015-01-28 09:39:13 +01:00
2015-01-28 09:30:07 +01:00
double Schedule : : convertInjectionRateToSI ( double rawRate , WellInjector : : TypeEnum wellType , const Opm : : UnitSystem & unitSystem ) {
2014-02-10 16:15:22 +01:00
switch ( wellType ) {
case WellInjector : : MULTI :
// multi-phase controlled injectors are a really funny
// construct in Eclipse: the quantity controlled for is
// not physically meaningful, i.e. Eclipse adds up
// MCFT/day and STB/day.
throw std : : logic_error ( " There is no generic way to handle multi-phase injectors at this level! " ) ;
case WellInjector : : OIL :
case WellInjector : : WATER :
2016-08-05 13:24:30 +02:00
return unitSystem . to_si ( UnitSystem : : measure : : liquid_surface_rate , rawRate ) ;
2014-02-10 16:15:22 +01:00
case WellInjector : : GAS :
2016-08-05 13:24:30 +02:00
return unitSystem . to_si ( UnitSystem : : measure : : gas_surface_rate , rawRate ) ;
2014-02-10 16:15:22 +01:00
default :
throw std : : logic_error ( " Unknown injector type " ) ;
}
}
2016-10-31 16:47:59 +01:00
double Schedule : : convertInjectionRateToSI ( double rawRate , Phase wellPhase , const Opm : : UnitSystem & unitSystem ) {
2014-02-10 16:15:22 +01:00
switch ( wellPhase ) {
case Phase : : OIL :
case Phase : : WATER :
2016-08-05 13:24:30 +02:00
return unitSystem . to_si ( UnitSystem : : measure : : liquid_surface_rate , rawRate ) ;
2014-02-10 16:15:22 +01:00
case Phase : : GAS :
2016-08-05 13:24:30 +02:00
return unitSystem . to_si ( UnitSystem : : measure : : gas_surface_rate , rawRate ) ;
2014-02-10 16:15:22 +01:00
default :
throw std : : logic_error ( " Unknown injection phase " ) ;
}
}
2014-12-08 16:34:28 +01:00
2014-02-19 15:43:42 +01:00
bool Schedule : : convertEclipseStringToBool ( const std : : string & eclipseString ) {
std : : string lowerTrimmed = boost : : algorithm : : to_lower_copy ( eclipseString ) ;
boost : : algorithm : : trim ( lowerTrimmed ) ;
if ( lowerTrimmed = = " y " | | lowerTrimmed = = " yes " ) {
return true ;
}
else if ( lowerTrimmed = = " n " | | lowerTrimmed = = " no " ) {
return false ;
}
else throw std : : invalid_argument ( " String " + eclipseString + " not recognized as a boolean-convertible string. " ) ;
}
2014-12-05 12:59:53 +01:00
2018-06-10 20:54:34 +02:00
size_t Schedule : : getMaxNumConnectionsForWells ( size_t timestep ) const {
2014-12-05 12:59:53 +01:00
size_t ncwmax = 0 ;
2016-06-16 08:37:10 +02:00
for ( const auto * wellPtr : getWells ( ) ) {
2018-06-10 20:54:34 +02:00
const auto & completions = wellPtr - > getConnections ( timestep ) ;
2014-12-05 12:59:53 +01:00
2016-10-12 16:30:06 +02:00
if ( completions . size ( ) > ncwmax )
ncwmax = completions . size ( ) ;
2014-12-05 12:59:53 +01:00
}
return ncwmax ;
}
2015-04-17 18:51:42 +02:00
2016-10-05 10:04:22 +02:00
const Tuning & Schedule : : getTuning ( ) const {
return this - > m_tuning ;
2015-04-17 18:51:42 +02:00
}
2015-06-23 14:20:31 +02:00
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
2016-04-14 09:39:28 +08:00
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
}
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
void Schedule : : checkIfAllConnectionsIsShut ( size_t timestep ) {
for ( auto & well : this - > m_wells ) {
2018-06-10 20:54:34 +02:00
const auto & completions = well . getConnections ( timestep ) ;
if ( completions . allConnectionsShut ( ) )
2017-09-26 09:32:29 +02:00
this - > updateWellStatus ( well , timestep , WellCommon : : StatusEnum : : SHUT ) ;
}
}
2018-02-06 19:13:42 +01:00
2018-06-10 20:54:34 +02:00
void Schedule : : filterConnections ( const EclipseGrid & grid ) {
2018-02-06 19:13:42 +01:00
for ( auto & well : this - > m_wells )
2018-06-10 20:54:34 +02:00
well . 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
}
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
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 ) ;
}
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
2018-12-10 16:08:44 +01:00
void Schedule : : evalAction ( const SummaryState & /* st */ , size_t /* timeStep */ ) {
2018-11-19 09:43:50 +01:00
if ( this - > actions . empty ( ) )
return ;
}
2013-10-25 17:28:56 +02:00
}
2018-02-06 19:13:42 +01:00