2013-10-25 17:28:56 +02:00
/*
Copyright 2013 Statoil ASA .
This file is part of the Open Porous Media project ( OPM ) .
OPM is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
OPM is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with OPM . If not , see < http : //www.gnu.org/licenses/>.
2013-11-08 15:55:11 +01:00
*/
2013-10-25 17:28:56 +02:00
2019-03-14 09:23:03 +01:00
# include <fnmatch.h>
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>
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>
2019-01-17 11:22:49 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/Action/ActionX.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>
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>
2019-02-21 11:49:33 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQInput.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>
2019-03-08 07:12:07 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WList.hpp>
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WListManager.hpp>
2019-07-03 10:04:20 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WellFoamProperties.hpp>
2019-03-08 07:12:07 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WellPolymerProperties.hpp>
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WellConnections.hpp>
2018-11-19 09:43:50 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/SummaryState.hpp>
2016-01-24 21:49:39 +01:00
# include <opm/parser/eclipse/Units/Dimension.hpp>
2016-01-15 08:42:57 +01:00
# include <opm/parser/eclipse/Units/UnitSystem.hpp>
2018-12-18 14:42:25 +01:00
# include <opm/parser/eclipse/Units/Units.hpp>
2015-01-14 11:41:13 +01:00
2019-06-20 11:23:06 +02:00
# include "Well/injection.hpp"
2019-05-19 15:39:03 +02:00
# include "Well/WellProductionProperties.hpp"
# include "Well/WellInjectionProperties.hpp"
2019-03-25 10:03:16 +01:00
2013-11-08 15:55:11 +01:00
namespace Opm {
2018-10-26 09:13:26 +02:00
2019-07-07 08:46:17 +02:00
namespace {
bool name_match ( const std : : string & pattern , const std : : string & name ) {
int flags = 0 ;
return ( fnmatch ( pattern . c_str ( ) , name . c_str ( ) , flags ) = = 0 ) ;
}
}
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 ) ,
2019-01-14 12:09:07 +01:00
wtest_config ( this - > m_timeMap , std : : make_shared < WellTestConfig > ( ) ) ,
2019-01-28 16:52:28 +01:00
wlist_manager ( this - > m_timeMap , std : : make_shared < WListManager > ( ) ) ,
2019-04-03 18:47:02 +02:00
udq_config ( this - > m_timeMap , std : : make_shared < UDQInput > ( deck ) ) ,
2019-05-02 15:08:44 +02:00
global_whistctl_mode ( this - > m_timeMap , WellProducer : : CMODE_UNDEFINED ) ,
2019-04-03 18:47:02 +02:00
rft_config ( this - > m_timeMap )
2016-05-02 17:46:20 +02:00
{
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 ) ;
2019-07-24 10:20:38 +02:00
checkGroups ( parseContext , errors ) ;
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
2019-01-28 16:52:28 +01:00
else if ( keyword . name ( ) = = " UDQ " )
handleUDQ ( keyword , currentStep ) ;
2019-01-14 12:09:07 +01:00
else if ( keyword . name ( ) = = " WLIST " )
handleWLIST ( keyword , currentStep ) ;
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WELSPECS " )
2019-06-08 12:25:29 +02:00
handleWELSPECS ( section , keywordIdx , currentStep , unit_system ) ;
2013-11-05 15:25:47 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WHISTCTL " )
2019-04-08 09:18:32 +02:00
handleWHISTCTL ( keyword , currentStep , parseContext , errors ) ;
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-06-26 07:46:40 +02:00
handleWCONINJE ( keyword , currentStep , parseContext , errors ) ;
2013-11-08 15:55:11 +01:00
2019-07-03 10:04:20 +02:00
else if ( keyword . name ( ) = = " WFOAM " )
handleWFOAM ( keyword , currentStep , parseContext , errors ) ;
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-06-26 07:46:40 +02:00
handleWCONINJH ( 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 " )
2019-05-23 13:13:36 +02:00
handleCOMPSEGS ( keyword , currentStep , grid , parseContext , errors ) ;
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 ;
2019-02-03 18:07:04 +01:00
if ( ActionX : : valid_keyword ( action_keyword . name ( ) ) )
action . addKeyword ( action_keyword ) ;
else {
2018-10-26 09:13:26 +02:00
std : : string msg = " The keyword " + action_keyword . name ( ) + " is not supported in a ACTIONX block. " ;
2019-01-03 11:53:32 +01:00
parseContext . handleError ( ParseContext : : ACTIONX_ILLEGAL_KEYWORD , msg , errors ) ;
2019-02-03 18:07:04 +01:00
}
2015-10-30 12:55:17 +01:00
}
2019-01-22 16:33:17 +01:00
this - > m_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 ;
2019-04-03 18:47:02 +02:00
if ( keyword . name ( ) = = " WRFT " )
2015-02-12 08:38:26 +01:00
handleWRFT ( keyword , timeStep ) ;
2015-02-06 14:54:03 +01:00
2019-04-03 18:47:02 +02: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
}
2018-07-04 12:47:30 +02:00
2019-04-08 09:18:32 +02:00
void Schedule : : handleWHISTCTL ( const DeckKeyword & keyword , std : : size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
const auto & record = keyword . getRecord ( 0 ) ;
const std : : string & cmodeString = record . getItem ( " CMODE " ) . getTrimmedString ( 0 ) ;
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 ) ;
2019-05-02 15:08:44 +02:00
} else
this - > global_whistctl_mode . update ( currentStep , controlMode ) ;
2019-04-08 09:18:32 +02:00
}
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 " ;
OpmLog : : error ( msg ) ;
parseContext . handleError ( ParseContext : : UNSUPPORTED_TERMINATE_IF_BHP , msg , errors ) ;
}
2016-09-22 09:28:43 +02:00
2019-04-08 09:18:32 +02:00
2019-05-04 12:00:32 +02:00
for ( auto & well_pair : this - > wells_static ) {
auto & dynamic_state = well_pair . second ;
auto well2 = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
auto prop = std : : make_shared < WellProductionProperties > ( well2 - > getProductionProperties ( ) ) ;
if ( prop - > whistctl_cmode ! = controlMode ) {
prop - > whistctl_cmode = controlMode ;
well2 - > updateProduction ( prop ) ;
this - > updateWell ( well2 , currentStep ) ;
}
}
for ( auto & well_pair : this - > wells_static ) {
auto & dynamic_state = well_pair . second ;
auto well2 = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
auto prop = std : : make_shared < WellProductionProperties > ( well2 - > getProductionProperties ( ) ) ;
if ( prop - > whistctl_cmode ! = controlMode ) {
prop - > whistctl_cmode = controlMode ;
well2 - > updateProduction ( prop ) ;
this - > updateWell ( well2 , currentStep ) ;
2019-04-08 09:18:32 +02:00
}
2016-09-22 09:28:43 +02:00
}
2019-03-23 16:11:37 +01:00
for ( auto & well_pair : this - > wells_static ) {
auto & dynamic_state = well_pair . second ;
auto well2 = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
auto prop = std : : make_shared < WellProductionProperties > ( well2 - > getProductionProperties ( ) ) ;
if ( prop - > whistctl_cmode ! = controlMode ) {
prop - > whistctl_cmode = controlMode ;
well2 - > updateProduction ( prop ) ;
this - > updateWell ( well2 , currentStep ) ;
}
}
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 ,
2019-06-08 12:25:29 +02:00
size_t currentStep ,
const UnitSystem & unit_system ) {
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 ) ;
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 ) ;
2019-05-04 12:00:32 +02:00
if ( Well2 : : 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
}
}
}
2019-06-08 12:25:29 +02:00
this - > addWell ( wellName , record , currentStep , wellConnectionOrder , unit_system ) ;
2019-07-25 11:46:15 +02:00
this - > addWellToGroup ( groupName , wellName , currentStep ) ;
2019-03-23 16:11:37 +01:00
} else {
const auto headI = record . getItem ( " HEAD_I " ) . get < int > ( 0 ) - 1 ;
const auto headJ = record . getItem ( " HEAD_J " ) . get < int > ( 0 ) - 1 ;
const auto & refDepthItem = record . getItem ( " REF_DEPTH " ) ;
double drainageRadius = record . getItem ( " D_RADIUS " ) . getSIDouble ( 0 ) ;
double refDepth = refDepthItem . hasValue ( 0 )
? refDepthItem . getSIDouble ( 0 )
: - 1.0 ;
{
bool update = false ;
auto well2 = std : : shared_ptr < Well2 > ( new Well2 ( this - > getWell2 ( wellName , currentStep ) ) ) ;
update = well2 - > updateHead ( headI , headJ ) ;
update | = well2 - > updateRefDepth ( refDepth ) ;
update | = well2 - > updateDrainageRadius ( drainageRadius ) ;
2019-05-04 12:00:32 +02:00
if ( well2 - > groupName ( ) ! = groupName ) {
auto & old_group = this - > m_groups . at ( well2 - > groupName ( ) ) ;
auto & new_group = this - > m_groups . at ( groupName ) ;
old_group . delWell ( currentStep , well2 - > name ( ) ) ;
new_group . addWell ( currentStep , well2 - > name ( ) ) ;
update = true ;
}
if ( update ) {
2019-03-23 16:11:37 +01:00
this - > updateWell ( well2 , currentStep ) ;
2019-05-04 12:00:32 +02:00
this - > addWellEvent ( well2 - > name ( ) , ScheduleEvents : : WELL_WELSPECS_UPDATE , currentStep ) ;
}
2019-03-23 16:11:37 +01:00
}
2016-11-22 11:34:46 +01:00
}
2014-01-20 14:52:30 +01:00
2015-06-23 14:20:31 +02:00
if ( handleGroupFromWELSPECS ( groupName , newTree ) )
needNewTree = true ;
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-03-23 16:11:37 +01:00
void Schedule : : handleWCONHIST ( const DeckKeyword & keyword , size_t currentStep , 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
2019-03-23 16:51:32 +01:00
auto well_names = this - > wellNames ( wellNamePattern , currentStep ) ;
if ( well_names . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2014-06-27 00:17:56 +02:00
2019-03-23 16:51:32 +01:00
for ( const auto & well_name : well_names ) {
2019-03-23 16:11:37 +01:00
updateWellStatus ( well_name , currentStep , status ) ;
{
auto & dynamic_state = this - > wells_static . at ( well_name ) ;
auto well2 = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
bool switching_from_injector = ! well2 - > isProducer ( ) ;
auto properties = std : : make_shared < WellProductionProperties > ( well2 - > getProductionProperties ( ) ) ;
2019-05-20 16:13:20 +02:00
bool update_well = false ;
2019-03-23 16:11:37 +01:00
properties - > handleWCONHIST ( record ) ;
if ( switching_from_injector ) {
properties - > resetDefaultBHPLimit ( ) ;
well2 - > updateProducer ( true ) ;
2019-05-04 12:00:32 +02:00
auto inj_props = std : : make_shared < WellInjectionProperties > ( well2 - > getInjectionProperties ( ) ) ;
inj_props - > setBHPLimit ( 0 ) ;
well2 - > updateInjection ( inj_props ) ;
2019-03-23 16:11:37 +01:00
}
2019-05-20 16:13:20 +02:00
if ( well2 - > updateProducer ( true ) )
update_well = true ;
if ( well2 - > updateProduction ( properties ) )
update_well = true ;
if ( well2 - > updatePrediction ( false ) )
update_well = true ;
if ( update_well ) {
2019-03-23 16:11:37 +01:00
m_events . addEvent ( ScheduleEvents : : PRODUCTION_UPDATE , currentStep ) ;
this - > addWellEvent ( well2 - > name ( ) , ScheduleEvents : : PRODUCTION_UPDATE , currentStep ) ;
this - > updateWell ( well2 , currentStep ) ;
}
2019-06-24 09:34:11 +02:00
if ( ! well2 - > getAllowCrossFlow ( ) ) {
// The numerical content of the rate UDAValues is accessed unconditionally;
// since this is in history mode use of UDA values is not allowed anyway.
const auto & oil_rate = properties - > OilRate ;
const auto & water_rate = properties - > WaterRate ;
const auto & gas_rate = properties - > GasRate ;
if ( ( oil_rate . get < double > ( ) + water_rate . get < double > ( ) + gas_rate . get < double > ( ) ) = = 0 ) {
std : : string msg =
" Well " + well2 - > name ( ) + " is a history matched well 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_name , currentStep , WellCommon : : StatusEnum : : SHUT ) ;
}
2019-03-23 16:11:37 +01:00
}
}
}
}
}
void Schedule : : handleWCONPROD ( const DeckKeyword & keyword , size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
for ( const auto & record : keyword ) {
const std : : string & wellNamePattern =
record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
const WellCommon : : StatusEnum status =
WellCommon : : StatusFromString ( record . getItem ( " STATUS " ) . getTrimmedString ( 0 ) ) ;
auto well_names = this - > wellNames ( wellNamePattern , currentStep ) ;
if ( well_names . empty ( ) )
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
for ( const auto & well_name : well_names ) {
updateWellStatus ( well_name , currentStep , status ) ;
{
auto & dynamic_state = this - > wells_static . at ( well_name ) ;
auto well2 = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
bool switching_from_injector = ! well2 - > isProducer ( ) ;
auto properties = std : : make_shared < WellProductionProperties > ( well2 - > getProductionProperties ( ) ) ;
2019-05-20 16:13:20 +02:00
bool update_well = switching_from_injector ;
2019-05-11 13:11:54 +02:00
properties - > clearControls ( ) ;
2019-03-23 16:11:37 +01:00
if ( well2 - > isAvailableForGroupControl ( ) )
properties - > addProductionControl ( WellProducer : : GRUP ) ;
2019-04-08 09:18:32 +02:00
2019-03-23 16:11:37 +01:00
properties - > handleWCONPROD ( record ) ;
if ( switching_from_injector )
properties - > resetDefaultBHPLimit ( ) ;
2019-05-20 16:13:20 +02:00
if ( well2 - > updateProducer ( true ) )
update_well = true ;
if ( well2 - > updateProduction ( properties ) )
update_well = true ;
if ( well2 - > updatePrediction ( true ) )
update_well = true ;
if ( update_well ) {
2019-03-23 16:11:37 +01:00
m_events . addEvent ( ScheduleEvents : : PRODUCTION_UPDATE , currentStep ) ;
this - > addWellEvent ( well2 - > name ( ) , ScheduleEvents : : PRODUCTION_UPDATE , currentStep ) ;
this - > updateWell ( well2 , currentStep ) ;
2019-04-08 09:18:32 +02:00
}
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
}
2019-03-23 16:11:37 +01:00
void Schedule : : updateWell ( std : : shared_ptr < Well2 > well , size_t reportStep ) {
auto & dynamic_state = this - > wells_static . at ( well - > name ( ) ) ;
dynamic_state . update ( reportStep , well ) ;
2015-06-23 14:20:31 +02:00
}
2019-03-23 16:11:37 +01:00
/*
Function is quite dangerous - because if this is called while holding a
Well2 pointer that will go stale and needs to be refreshed .
*/
bool Schedule : : updateWellStatus ( const std : : string & well_name , size_t reportStep , WellCommon : : StatusEnum status ) {
bool update = false ;
{
auto & dynamic_state = this - > wells_static . at ( well_name ) ;
auto well2 = std : : make_shared < Well2 > ( * dynamic_state [ reportStep ] ) ;
if ( well2 - > updateStatus ( status ) ) {
m_events . addEvent ( ScheduleEvents : : WELL_STATUS_CHANGE , reportStep ) ;
this - > addWellEvent ( well2 - > name ( ) , ScheduleEvents : : WELL_STATUS_CHANGE , reportStep ) ;
this - > updateWell ( well2 , reportStep ) ;
update = true ;
}
}
return update ;
2013-11-08 15:55:11 +01:00
}
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 ) ;
2019-03-23 16:11:37 +01:00
const auto & well_names = this - > wellNames ( wellNamePattern , currentStep ) ;
for ( const auto & wname : well_names ) {
{
auto & dynamic_state = this - > wells_static . at ( wname ) ;
auto well_ptr = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
if ( well_ptr - > handleWPIMULT ( record ) )
this - > updateWell ( well_ptr , currentStep ) ;
}
2019-03-23 16:51:32 +01:00
}
2015-06-02 09:30:08 +02:00
}
}
2018-06-25 19:16:52 +02:00
2019-06-26 07:46:40 +02:00
void Schedule : : handleWCONINJE ( 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
2019-03-23 16:11:37 +01:00
auto well_names = wellNames ( wellNamePattern , currentStep ) ;
2019-03-23 16:51:32 +01:00
if ( well_names . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-04-26 10:39:54 +02:00
2019-03-23 16:11:37 +01:00
for ( const auto & well_name : well_names ) {
WellCommon : : StatusEnum status = WellCommon : : StatusFromString ( record . getItem ( " STATUS " ) . getTrimmedString ( 0 ) ) ;
updateWellStatus ( well_name , currentStep , status ) ;
{
bool update_well = false ;
auto & dynamic_state = this - > wells_static . at ( well_name ) ;
auto well2 = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
auto injection = std : : make_shared < WellInjectionProperties > ( well2 - > getInjectionProperties ( ) ) ;
2019-06-26 07:46:40 +02:00
injection - > handleWCONINJE ( record , well2 - > isAvailableForGroupControl ( ) , well_name ) ;
2019-03-23 16:11:37 +01:00
2019-05-20 16:13:20 +02:00
if ( well2 - > updateProducer ( false ) )
update_well = true ;
if ( well2 - > updateInjection ( injection ) )
update_well = true ;
if ( well2 - > updatePrediction ( true ) )
update_well = true ;
2019-03-23 16:11:37 +01:00
if ( update_well ) {
this - > updateWell ( well2 , currentStep ) ;
m_events . addEvent ( ScheduleEvents : : INJECTION_UPDATE , currentStep ) ;
this - > addWellEvent ( well_name , ScheduleEvents : : INJECTION_UPDATE , currentStep ) ;
}
// if the well has zero surface rate limit or reservior rate limit, while does not allow crossflow,
// it should be turned off.
2019-06-24 09:34:11 +02:00
if ( ! well2 - > getAllowCrossFlow ( ) ) {
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 " ;
if ( injection - > surfaceInjectionRate . is < double > ( ) ) {
if ( injection - > hasInjectionControl ( WellInjector : : RATE ) & & injection - > surfaceInjectionRate . get < double > ( ) = = 0 ) {
OpmLog : : note ( msg ) ;
updateWellStatus ( well_name , currentStep , WellCommon : : StatusEnum : : SHUT ) ;
}
}
if ( injection - > reservoirInjectionRate . is < double > ( ) ) {
if ( injection - > hasInjectionControl ( WellInjector : : RESV ) & & injection - > reservoirInjectionRate . get < double > ( ) = = 0 ) {
OpmLog : : note ( msg ) ;
updateWellStatus ( well_name , currentStep , WellCommon : : StatusEnum : : SHUT ) ;
}
}
2019-03-23 16:11:37 +01:00
}
2015-10-08 12:17:29 +02:00
}
2014-03-03 15:00:42 +01:00
}
2013-11-11 17:06:22 +01:00
}
}
2019-06-26 07:46:40 +02:00
void Schedule : : handleWCONINJH ( const DeckKeyword & keyword , size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
2019-03-23 16:11:37 +01:00
for ( const auto & record : keyword ) {
const std : : string & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
WellCommon : : StatusEnum status = WellCommon : : StatusFromString ( record . getItem ( " STATUS " ) . getTrimmedString ( 0 ) ) ;
const auto well_names = wellNames ( wellNamePattern , currentStep ) ;
if ( well_names . empty ( ) )
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
for ( const auto & well_name : well_names ) {
updateWellStatus ( well_name , currentStep , status ) ;
{
bool update_well = false ;
auto & dynamic_state = this - > wells_static . at ( well_name ) ;
auto well2 = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
auto injection = std : : make_shared < WellInjectionProperties > ( well2 - > getInjectionProperties ( ) ) ;
2019-06-26 07:46:40 +02:00
injection - > handleWCONINJH ( record , well2 - > isProducer ( ) , well_name ) ;
2019-03-23 16:11:37 +01:00
2019-05-20 16:13:20 +02:00
if ( well2 - > updateProducer ( false ) )
update_well = true ;
if ( well2 - > updateInjection ( injection ) )
update_well = true ;
if ( well2 - > updatePrediction ( false ) )
update_well = true ;
2019-03-23 16:11:37 +01:00
if ( update_well ) {
this - > updateWell ( well2 , currentStep ) ;
m_events . addEvent ( ScheduleEvents : : INJECTION_UPDATE , currentStep ) ;
this - > addWellEvent ( well_name , ScheduleEvents : : INJECTION_UPDATE , currentStep ) ;
}
2019-06-24 09:34:11 +02:00
if ( ! well2 - > getAllowCrossFlow ( ) & & ( injection - > surfaceInjectionRate . get < double > ( ) = = 0 ) ) {
2019-03-23 16:11:37 +01:00
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_name , currentStep , WellCommon : : StatusEnum : : SHUT ) ;
}
}
}
}
}
2014-03-03 15:00:42 +01:00
2019-07-03 10:04:20 +02:00
void Schedule : : handleWFOAM ( const DeckKeyword & keyword , size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors ) {
for ( const auto & record : keyword ) {
const std : : string & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
const auto well_names = wellNames ( wellNamePattern , currentStep ) ;
if ( well_names . empty ( ) )
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
for ( const auto & well_name : well_names ) {
2019-07-04 09:08:54 +02:00
const auto & dynamic_state = this - > wells_static . at ( well_name ) ;
2019-07-03 10:04:20 +02:00
auto well2 = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
auto foam_properties = std : : make_shared < WellFoamProperties > ( well2 - > getFoamProperties ( ) ) ;
foam_properties - > handleWFOAM ( record ) ;
if ( well2 - > updateFoamProperties ( foam_properties ) )
this - > updateWell ( well2 , currentStep ) ;
}
}
}
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 ) ;
2019-03-23 16:51:32 +01:00
const auto well_names = wellNames ( wellNamePattern , currentStep ) ;
2014-11-20 16:20:54 +08:00
2019-03-23 16:51:32 +01:00
if ( well_names . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-05-02 11:01:21 +02:00
2019-03-23 16:51:32 +01:00
for ( const auto & well_name : well_names ) {
2019-03-23 16:11:37 +01:00
{
2019-07-04 09:08:54 +02:00
const auto & dynamic_state = this - > wells_static . at ( well_name ) ;
2019-03-23 16:11:37 +01:00
auto well2 = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
auto polymer_properties = std : : make_shared < WellPolymerProperties > ( well2 - > getPolymerProperties ( ) ) ;
polymer_properties - > handleWPOLYMER ( record ) ;
if ( well2 - > updatePolymerProperties ( polymer_properties ) )
this - > updateWell ( well2 , currentStep ) ;
2014-11-20 17:23:12 +08:00
}
2014-11-20 16:20:54 +08:00
}
}
}
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 ) ;
2019-03-23 16:11:37 +01:00
const auto well_names = wellNames ( wellNamePattern , currentStep ) ;
2018-06-04 12:04:17 +02:00
2019-03-23 16:51:32 +01:00
if ( well_names . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-06-04 12:04:17 +02:00
2019-03-23 16:51:32 +01:00
for ( const auto & well_name : well_names ) {
2019-03-23 16:11:37 +01:00
{
auto & dynamic_state = this - > wells_static . at ( well_name ) ;
auto well2 = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
auto polymer_properties = std : : make_shared < WellPolymerProperties > ( well2 - > getPolymerProperties ( ) ) ;
polymer_properties - > handleWPMITAB ( record ) ;
if ( well2 - > updatePolymerProperties ( polymer_properties ) )
this - > updateWell ( well2 , currentStep ) ;
2018-10-09 12:48:11 +02:00
}
2018-04-06 15:48:27 +02:00
}
}
}
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 ) ;
2019-03-23 16:51:32 +01:00
const auto well_names = wellNames ( wellNamePattern , currentStep ) ;
2018-06-04 12:04:17 +02:00
2019-03-23 16:51:32 +01:00
if ( well_names . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-06-04 12:04:17 +02:00
2019-03-23 16:51:32 +01:00
for ( const auto & well_name : well_names ) {
2019-03-23 16:11:37 +01:00
{
auto & dynamic_state = this - > wells_static . at ( well_name ) ;
auto well2 = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
auto polymer_properties = std : : make_shared < WellPolymerProperties > ( well2 - > getPolymerProperties ( ) ) ;
polymer_properties - > handleWSKPTAB ( record ) ;
if ( well2 - > updatePolymerProperties ( polymer_properties ) )
this - > updateWell ( well2 , currentStep ) ;
}
2018-04-12 15:39:45 +02:00
}
}
}
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 ) ;
2019-03-23 16:51:32 +01:00
const auto well_names = wellNames ( wellNamePattern , currentStep ) ;
2016-06-23 13:44:03 +02:00
2019-03-23 16:51:32 +01:00
if ( well_names . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-05-03 09:34:54 +02:00
2019-03-23 16:51:32 +01:00
for ( const auto & well_name : well_names ) {
2019-03-23 16:11:37 +01:00
{
auto & dynamic_state = this - > wells_static . at ( well_name ) ;
auto well2 = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
auto econ_limits = std : : make_shared < WellEconProductionLimits > ( record ) ;
if ( well2 - > updateEconLimits ( econ_limits ) )
this - > updateWell ( well2 , currentStep ) ;
}
2016-06-23 13:44:03 +02:00
}
}
}
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 ) ;
2019-03-23 16:51:32 +01:00
const auto well_names = wellNames ( wellNamePattern , currentStep ) ;
2017-11-21 09:55:07 +01:00
2019-03-23 16:51:32 +01:00
if ( well_names . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-05-03 09:34:54 +02:00
2019-03-23 16:51:32 +01:00
for ( const auto & well_name : well_names ) {
2019-03-23 16:11:37 +01:00
{
auto & dynamic_state = this - > wells_static . at ( well_name ) ;
auto well2 = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
if ( well2 - > updateEfficiencyFactor ( efficiencyFactor ) )
this - > updateWell ( well2 , currentStep ) ;
}
2017-11-21 09:55:07 +01:00
}
}
}
2016-06-23 13:44:03 +02:00
2019-01-14 12:09:07 +01:00
void Schedule : : handleWLIST ( const DeckKeyword & keyword , size_t currentStep ) {
const std : : string legal_actions = " NEW:ADD:DEL:MOV " ;
const auto & current = * this - > wlist_manager . get ( currentStep ) ;
std : : shared_ptr < WListManager > new_wlm ( new WListManager ( current ) ) ;
for ( const auto & record : keyword ) {
const std : : string & name = record . getItem ( " NAME " ) . getTrimmedString ( 0 ) ;
const std : : string & action = record . getItem ( " ACTION " ) . getTrimmedString ( 0 ) ;
const std : : vector < std : : string > & wells = record . getItem ( " WELLS " ) . getData < std : : string > ( ) ;
if ( legal_actions . find ( action ) = = std : : string : : npos )
throw std : : invalid_argument ( " The action: " + action + " is not recognized. " ) ;
for ( const auto & well : wells ) {
if ( ! this - > hasWell ( well ) )
throw std : : invalid_argument ( " The well: " + well + " has not been defined in the WELSPECS " ) ;
}
if ( name [ 0 ] ! = ' * ' )
throw std : : invalid_argument ( " The list name in WLIST must start with a '*' " ) ;
if ( action = = " NEW " )
new_wlm - > newList ( name ) ;
if ( ! new_wlm - > hasList ( name ) )
throw std : : invalid_argument ( " Invalid well list: " + name ) ;
auto & wlist = new_wlm - > getList ( name ) ;
if ( action = = " MOV " ) {
for ( const auto & well : wells )
new_wlm - > delWell ( well ) ;
}
if ( action = = " DEL " ) {
for ( const auto & well : wells )
wlist . del ( well ) ;
} else {
for ( const auto & well : wells )
wlist . add ( well ) ;
}
}
this - > wlist_manager . update ( currentStep , new_wlm ) ;
}
2019-01-28 16:52:28 +01:00
void Schedule : : handleUDQ ( const DeckKeyword & keyword , size_t currentStep ) {
const auto & current = * this - > udq_config . get ( currentStep ) ;
2019-02-21 11:49:33 +01:00
std : : shared_ptr < UDQInput > new_udq = std : : make_shared < UDQInput > ( current ) ;
2019-01-28 16:52:28 +01:00
for ( const auto & record : keyword )
new_udq - > add_record ( record ) ;
this - > udq_config . update ( currentStep , new_udq ) ;
}
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 ) ;
2019-03-23 16:51:32 +01:00
const auto well_names = wellNames ( wellNamePattern , currentStep ) ;
if ( well_names . 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 ) ;
2019-06-26 14:48:46 +02:00
const std : : string & reasons = record . getItem ( " REASON " ) . get < std : : string > ( 0 ) ;
2018-05-14 04:18:07 +02:00
int num_test = record . getItem ( " TEST_NUM " ) . get < int > ( 0 ) ;
double startup_time = record . getItem ( " START_TIME " ) . getSIDouble ( 0 ) ;
2019-03-23 16:51:32 +01:00
for ( const auto & well_name : well_names ) {
2019-06-26 14:48:46 +02:00
if ( reasons . empty ( ) )
2019-05-04 12:00:32 +02:00
new_config - > drop_well ( well_name ) ;
2018-05-14 04:18:07 +02:00
else
2019-06-26 14:48:46 +02:00
new_config - > add_well ( well_name , reasons , test_interval , num_test , startup_time , currentStep ) ;
2018-05-14 04:18:07 +02:00
}
}
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 ) ;
2019-03-23 16:51:32 +01:00
const auto well_names = wellNames ( wellNamePattern , currentStep ) ;
2019-06-20 12:11:57 +02:00
double fraction = record . getItem ( " SOLVENT_FRACTION " ) . get < UDAValue > ( 0 ) . get < double > ( ) ;
2015-08-04 13:55:16 +02:00
2019-03-23 16:51:32 +01:00
if ( well_names . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-05-02 11:01:21 +02:00
2019-03-23 16:51:32 +01:00
for ( const auto & well_name : well_names ) {
2019-03-23 16:11:37 +01:00
{
const auto & well = this - > getWell2 ( well_name , currentStep ) ;
const auto & inj = well . getInjectionProperties ( ) ;
if ( ! well . isProducer ( ) & & inj . injectorType = = WellInjector : : GAS ) {
if ( well . getSolventFraction ( ) ! = fraction ) {
auto new_well = std : : make_shared < Well2 > ( well ) ;
new_well - > updateSolventFraction ( fraction ) ;
this - > updateWell ( new_well , currentStep ) ;
}
} else
throw std : : invalid_argument ( " The WSOLVENT keyword can only be applied to gas injectors " ) ;
2015-08-05 08:30:25 +02:00
}
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 ) ;
2019-03-23 16:51:32 +01:00
const auto well_names = wellNames ( wellNamePattern , currentStep ) ;
2018-11-12 09:05:01 +01:00
2019-03-23 16:51:32 +01:00
if ( well_names . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-11-12 09:05:01 +01:00
2019-03-23 16:51:32 +01:00
for ( const auto & well_name : well_names ) {
2019-06-20 12:11:17 +02:00
double tracerConcentration = record . getItem ( " CONCENTRATION " ) . get < UDAValue > ( 0 ) . get < double > ( ) ;
2018-11-12 09:05:01 +01:00
const std : : string & tracerName = record . getItem ( " TRACER " ) . getTrimmedString ( 0 ) ;
2019-03-23 16:11:37 +01:00
{
auto well = std : : make_shared < Well2 > ( this - > getWell2 ( well_name , currentStep ) ) ;
auto wellTracerProperties = std : : make_shared < WellTracerProperties > ( well - > getTracerProperties ( ) ) ;
wellTracerProperties - > setConcentration ( tracerName , tracerConcentration ) ;
if ( well - > updateTracer ( wellTracerProperties ) )
this - > updateWell ( well , currentStep ) ;
}
2018-11-12 09:05:01 +01:00
}
}
}
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 ) ;
2019-03-23 16:51:32 +01:00
const auto well_names = wellNames ( wellNamePattern , currentStep ) ;
2019-03-23 16:11:37 +01:00
double temp = record . getItem ( " TEMP " ) . getSIDouble ( 0 ) ;
2019-03-23 16:51:32 +01:00
if ( well_names . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-04-26 14:41:39 +02:00
2019-03-23 16:51:32 +01:00
for ( const auto & well_name : well_names ) {
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.
2019-03-23 16:11:37 +01:00
{
const auto & well = this - > getWell2 ( well_name , currentStep ) ;
double current_temp = well . getInjectionProperties ( ) . temperature ;
if ( current_temp ! = temp & & ! well . isProducer ( ) ) {
auto & dynamic_state = this - > wells_static . at ( well_name ) ;
auto well_ptr = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
auto inj = std : : make_shared < WellInjectionProperties > ( well_ptr - > getInjectionProperties ( ) ) ;
inj - > temperature = temp ;
well_ptr - > updateInjection ( inj ) ;
this - > updateWell ( well_ptr , currentStep ) ;
}
2018-04-10 14:56:11 +02:00
}
}
}
}
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 ) ;
2019-03-23 16:51:32 +01:00
auto well_names = wellNames ( wellNamePattern , currentStep ) ;
2019-03-23 16:11:37 +01:00
double temp = record . getItem ( " TEMPERATURE " ) . getSIDouble ( 0 ) ;
2018-04-26 14:41:39 +02:00
2019-03-23 16:51:32 +01:00
if ( well_names . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-04-10 14:56:11 +02:00
2019-03-23 16:51:32 +01:00
for ( const auto & well_name : well_names ) {
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.
2019-03-23 16:11:37 +01:00
{
const auto & well = this - > getWell2 ( well_name , currentStep ) ;
double current_temp = well . getInjectionProperties ( ) . temperature ;
if ( current_temp ! = temp & & ! well . isProducer ( ) ) {
auto & dynamic_state = this - > wells_static . at ( well_name ) ;
auto well_ptr = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
auto inj = std : : make_shared < WellInjectionProperties > ( well_ptr - > getInjectionProperties ( ) ) ;
inj - > temperature = temp ;
well_ptr - > updateInjection ( inj ) ;
this - > updateWell ( well_ptr , currentStep ) ;
}
2018-04-26 10:39:54 +02:00
}
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 ) {
2019-03-23 16:11:37 +01:00
const std : : string & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
const auto well_names = this - > wellNames ( wellNamePattern , timestep ) ;
for ( const auto & wname : well_names ) {
{
auto & dynamic_state = this - > wells_static . at ( wname ) ;
auto well_ptr = std : : make_shared < Well2 > ( * dynamic_state [ timestep ] ) ;
if ( well_ptr - > handleCOMPLUMP ( record ) )
this - > updateWell ( well_ptr , timestep ) ;
}
}
2016-11-29 15:46:55 +01:00
}
}
2019-01-28 10:00:08 +01:00
void Schedule : : handleWELOPEN ( const DeckKeyword & keyword , size_t currentStep , const ParseContext & parseContext , ErrorGuard & errors , const std : : vector < std : : string > & matching_wells ) {
2015-06-02 13:26:37 +02:00
2019-04-03 18:47:02 +02:00
auto conn_defaulted = [ ] ( const DeckRecord & rec ) {
2016-12-01 13:44:38 +01:00
auto defaulted = [ ] ( const DeckItem & item ) {
return item . defaultApplied ( 0 ) ;
} ;
2015-01-13 15:06:06 +01:00
2016-12-01 13:44:38 +01:00
return std : : all_of ( rec . begin ( ) + 2 , rec . end ( ) , defaulted ) ;
} ;
2015-06-23 14:20:31 +02:00
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 ) ;
2019-03-23 16:11:37 +01:00
const auto well_names = this - > wellNames ( wellNamePattern , currentStep , matching_wells ) ;
2018-05-03 09:18:53 +02:00
2019-03-23 16:51:32 +01:00
if ( well_names . 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
*/
2019-04-03 18:47:02 +02:00
if ( conn_defaulted ( record ) ) {
2018-06-25 18:45:01 +02:00
const auto well_status = WellCommon : : StatusFromString ( status_str ) ;
2019-03-23 16:11:37 +01:00
for ( const auto & wname : well_names ) {
{
2019-05-04 12:00:32 +02:00
const auto & well = this - > getWell2 ( wname , currentStep ) ;
if ( well_status = = open & & ! well . canOpen ( ) ) {
2019-03-23 16:11:37 +01:00
auto days = m_timeMap . getTimePassedUntil ( currentStep ) / ( 60 * 60 * 24 ) ;
std : : string msg = " Well " + wname
+ " where crossflow is banned has zero total rate. "
+ " This well is prevented from opening at "
+ std : : to_string ( days ) + " days " ;
OpmLog : : note ( msg ) ;
} else {
this - > updateWellStatus ( wname , currentStep , well_status ) ;
if ( well_status = = open )
this - > rft_config . addWellOpen ( wname , currentStep ) ;
}
2015-11-05 14:37:47 +01:00
}
2015-01-13 11:25:28 +01:00
}
2016-12-01 13:44:38 +01:00
continue ;
}
2019-03-23 16:11:37 +01:00
for ( const auto & wname : well_names ) {
2018-06-25 18:45:01 +02:00
const auto comp_status = WellCompletion : : StateEnumFromString ( status_str ) ;
2019-03-23 16:11:37 +01:00
{
auto & dynamic_state = this - > wells_static . at ( wname ) ;
auto well_ptr = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
if ( well_ptr - > handleWELOPEN ( record , comp_status ) )
// The updateWell call breaks test at line 825 and 831 in ScheduleTests
this - > updateWell ( well_ptr , currentStep ) ;
}
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 ) ;
2019-04-10 07:44:45 +02:00
const auto cmode = WellTarget : : ControlModeFromString ( record . getItem ( " CMODE " ) . getTrimmedString ( 0 ) ) ;
2016-02-09 12:09:40 +01:00
double newValue = record . getItem ( " NEW_VALUE " ) . get < double > ( 0 ) ;
2015-03-25 08:20:22 +01:00
2019-03-23 16:51:32 +01:00
const auto well_names = wellNames ( wellNamePattern , currentStep ) ;
2016-07-15 14:37:18 +02:00
2019-03-23 16:51:32 +01:00
if ( well_names . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2016-07-15 14:37:18 +02:00
2019-03-23 16:51:32 +01:00
for ( const auto & well_name : well_names ) {
2019-03-23 16:11:37 +01:00
{
auto & dynamic_state = this - > wells_static . at ( well_name ) ;
auto well2 = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
bool update = false ;
if ( well2 - > isProducer ( ) ) {
auto prop = std : : make_shared < WellProductionProperties > ( well2 - > getProductionProperties ( ) ) ;
prop - > handleWELTARG ( cmode , newValue , siFactorG , siFactorL , siFactorP ) ;
update = well2 - > updateProduction ( prop ) ;
if ( cmode = = WellTarget : : GUID )
update | = well2 - > updateWellGuideRate ( newValue ) ;
} else {
auto inj = std : : make_shared < WellInjectionProperties > ( well2 - > getInjectionProperties ( ) ) ;
inj - > handleWELTARG ( cmode , newValue , siFactorG , siFactorL , siFactorP ) ;
update = well2 - > updateInjection ( inj ) ;
if ( cmode = = WellTarget : : GUID )
update | = well2 - > updateWellGuideRate ( newValue ) ;
}
if ( update )
this - > updateWell ( well2 , currentStep ) ;
2015-03-25 08:20:22 +01: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 ) ;
2019-07-07 10:29:24 +02:00
const auto group_names = this - > groupNames ( groupNamePattern ) ;
2013-11-18 16:06:50 +01:00
2019-07-07 10:29:24 +02:00
if ( group_names . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( groupNamePattern , parseContext , errors , keyword ) ;
2018-05-03 14:04:19 +02:00
2019-07-07 10:29:24 +02:00
for ( const auto & group_name : group_names ) {
2019-07-24 08:38:39 +02:00
GroupInjection : : ControlEnum controlMode = GroupInjection : : ControlEnumFromString ( record . getItem ( " CONTROL_MODE " ) . getTrimmedString ( 0 ) ) ;
Phase phase = get_phase ( record . getItem ( " PHASE " ) . getTrimmedString ( 0 ) ) ;
double surfaceInjectionRate = record . getItem ( " SURFACE_TARGET " ) . get < UDAValue > ( 0 ) . get < double > ( ) ;
double reservoirInjectionRate = record . getItem ( " RESV_TARGET " ) . get < UDAValue > ( 0 ) . get < double > ( ) ;
double reinj_target = record . getItem ( " REINJ_TARGET " ) . get < UDAValue > ( 0 ) . get < double > ( ) ;
double voidage_target = record . getItem ( " VOIDAGE_TARGET " ) . get < UDAValue > ( 0 ) . get < double > ( ) ;
surfaceInjectionRate = injection : : rateToSI ( surfaceInjectionRate , phase , section . unitSystem ( ) ) ;
2018-05-03 13:20:04 +02:00
{
2019-07-24 08:38:39 +02:00
auto & group = this - > getGroup ( group_name ) ;
2019-07-07 10:29:24 +02:00
group . setInjectionPhase ( currentStep , phase ) ;
2019-07-24 08:38:39 +02:00
group . setInjectionControlMode ( currentStep , controlMode ) ;
group . setSurfaceMaxRate ( currentStep , surfaceInjectionRate ) ;
group . setReservoirMaxRate ( currentStep , reservoirInjectionRate ) ;
group . setTargetReinjectFraction ( currentStep , reinj_target ) ;
group . setTargetVoidReplacementFraction ( currentStep , voidage_target ) ;
group . setInjectionGroup ( currentStep ) ;
2018-05-03 13:20:04 +02:00
}
{
2019-07-24 08:38:39 +02:00
auto group_ptr = std : : make_shared < Group2 > ( this - > getGroup2 ( group_name , currentStep ) ) ;
Group2 : : GroupInjectionProperties injection ;
injection . phase = phase ;
injection . cmode = controlMode ;
injection . surface_max_rate = surfaceInjectionRate ;
injection . resv_max_rate = reservoirInjectionRate ;
injection . target_reinj_fraction = reinj_target ;
injection . target_void_fraction = voidage_target ;
if ( group_ptr - > updateInjection ( injection ) )
2019-07-30 17:47:19 +02:00
this - > updateGroup ( std : : move ( group_ptr ) , currentStep ) ;
2018-05-03 13:20:04 +02:00
}
}
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 ) ;
2019-07-07 10:29:24 +02:00
const auto group_names = this - > groupNames ( groupNamePattern ) ;
2014-12-08 16:34:28 +01:00
2019-07-07 10:29:24 +02:00
if ( group_names . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( groupNamePattern , parseContext , errors , keyword ) ;
2018-05-03 14:04:19 +02:00
2019-07-07 10:29:24 +02:00
for ( const auto & group_name : group_names ) {
2019-07-24 08:38:39 +02:00
GroupProduction : : ControlEnum controlMode = GroupProduction : : ControlEnumFromString ( record . getItem ( " CONTROL_MODE " ) . getTrimmedString ( 0 ) ) ;
GroupProductionExceedLimit : : ActionEnum exceedAction = GroupProductionExceedLimit : : ActionEnumFromString ( record . getItem ( " EXCEED_PROC " ) . getTrimmedString ( 0 ) ) ;
auto oil_target = record . getItem ( " OIL_TARGET " ) . get < UDAValue > ( 0 ) . get < double > ( ) ;
auto gas_target = record . getItem ( " GAS_TARGET " ) . get < UDAValue > ( 0 ) . get < double > ( ) ;
auto water_target = record . getItem ( " WATER_TARGET " ) . get < UDAValue > ( 0 ) . get < double > ( ) ;
auto liquid_target = record . getItem ( " LIQUID_TARGET " ) . get < UDAValue > ( 0 ) . get < double > ( ) ;
auto resv_target = record . getItem ( " RESERVOIR_FLUID_TARGET " ) . getSIDouble ( 0 ) ;
2018-05-03 13:20:04 +02:00
{
2019-07-24 08:38:39 +02:00
auto & group = this - > getGroup ( group_name ) ;
2019-07-07 10:29:24 +02:00
group . setProductionControlMode ( currentStep , controlMode ) ;
2019-07-24 08:38:39 +02:00
group . setOilTargetRate ( currentStep , oil_target ) ;
group . setGasTargetRate ( currentStep , gas_target ) ;
group . setWaterTargetRate ( currentStep , water_target ) ;
group . setLiquidTargetRate ( currentStep , liquid_target ) ;
group . setReservoirVolumeTargetRate ( currentStep , resv_target ) ;
group . setProductionExceedLimitAction ( currentStep , exceedAction ) ;
group . setProductionGroup ( currentStep ) ;
2018-05-03 13:20:04 +02:00
}
{
2019-07-24 08:38:39 +02:00
auto group_ptr = std : : make_shared < Group2 > ( this - > getGroup2 ( group_name , currentStep ) ) ;
Group2 : : GroupProductionProperties production ;
production . cmode = controlMode ;
production . oil_target = oil_target ;
production . gas_target = gas_target ;
production . water_target = water_target ;
production . liquid_target = liquid_target ;
production . resv_target = resv_target ;
production . exceed_action = exceedAction ;
if ( group_ptr - > updateProduction ( production ) )
2019-07-30 17:47:19 +02:00
this - > updateGroup ( std : : move ( group_ptr ) , currentStep ) ;
2018-05-03 13:20:04 +02:00
}
}
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 ) ;
2019-07-07 10:29:24 +02:00
const auto group_names = this - > groupNames ( groupNamePattern ) ;
2016-01-20 14:58:32 +01:00
2019-07-07 10:29:24 +02:00
if ( group_names . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( groupNamePattern , parseContext , errors , keyword ) ;
2018-05-03 14:04:19 +02:00
2019-07-07 10:29:24 +02:00
for ( const auto & group_name : group_names ) {
2019-07-24 08:38:39 +02:00
bool transfer = DeckItem : : to_bool ( record . getItem ( " TRANSFER_EXT_NET " ) . getTrimmedString ( 0 ) ) ;
auto gefac = record . getItem ( " EFFICIENCY_FACTOR " ) . get < double > ( 0 ) ;
{
auto & group = this - > getGroup ( group_name ) ;
2019-07-07 10:29:24 +02:00
2019-07-24 08:38:39 +02:00
group . setGroupEfficiencyFactor ( currentStep , gefac ) ;
group . setTransferGroupEfficiencyFactor ( currentStep , transfer ) ;
}
{
auto group_ptr = std : : make_shared < Group2 > ( this - > getGroup2 ( group_name , currentStep ) ) ;
if ( group_ptr - > update_gefac ( gefac , transfer ) )
2019-07-30 17:47:19 +02:00
this - > updateGroup ( std : : move ( group_ptr ) , currentStep ) ;
2019-07-24 08:38:39 +02:00
}
2018-05-03 13:20:04 +02:00
}
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 ) ;
2019-03-23 16:11:37 +01:00
auto wellnames = this - > wellNames ( wellNamePattern , currentStep ) ;
if ( wellnames . empty ( ) )
2019-01-03 11:53:32 +01:00
invalidNamePattern ( wellNamePattern , parseContext , errors , keyword ) ;
2018-06-25 13:50:58 +02:00
2019-03-23 16:11:37 +01:00
for ( const auto & name : wellnames ) {
{
auto well2 = std : : shared_ptr < Well2 > ( new Well2 ( this - > getWell2 ( name , currentStep ) ) ) ;
auto connections = std : : shared_ptr < WellConnections > ( new WellConnections ( well2 - > getConnections ( ) ) ) ;
connections - > loadCOMPDAT ( record , grid , eclipseProperties ) ;
/*
This block implements the following dubious logic .
1. All competions are shut .
2. A new open completion is added .
3. A currently SHUT well is opened .
This code assumes that the reason the well is initially
shut is due to all the shut completions , if the well was
explicitly shut for another reason the explicit opening of
the well might be in error ?
*/
/*if (all_shut0) {
if ( ! connections - > allConnectionsShut ( ) ) {
if ( well2 - > getStatus ( ) = = WellCommon : : StatusEnum : : SHUT ) {
printf ( " Running all_shut inner loop \n " ) ;
if ( this - > updateWellStatus ( well2 - > name ( ) , currentStep , WellCommon : : StatusEnum : : OPEN ) )
// Refresh pointer if the status has updated current slot. Ugly
well2 = std : : shared_ptr < Well2 > ( new Well2 ( this - > getWell2 ( name , currentStep ) ) ) ;
}
}
}
*/
if ( well2 - > updateConnections ( connections ) )
this - > updateWell ( well2 , currentStep ) ;
if ( well2 - > getStatus ( ) = = WellCommon : : StatusEnum : : SHUT ) {
std : : string msg =
" All completions in well " + well2 - > name ( ) + " is shut at " + std : : to_string ( m_timeMap . getTimePassedUntil ( currentStep ) / ( 60 * 60 * 24 ) ) + " days. \n " +
" The well is therefore also shut. " ;
OpmLog : : note ( msg ) ;
}
2018-06-25 13:50:58 +02:00
2019-07-30 17:47:19 +02:00
if ( well2 - > updateConnections ( connections ) )
this - > updateWell ( well2 , currentStep ) ;
2018-06-25 13:50:58 +02:00
}
2019-03-23 16:11:37 +01:00
this - > addWellEvent ( name , ScheduleEvents : : COMPLETION_CHANGE , currentStep ) ;
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 ) ;
2019-03-23 16:11:37 +01:00
const auto & wname = record1 . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
{
auto & dynamic_state = this - > wells_static . at ( wname ) ;
auto well_ptr = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
if ( well_ptr - > handleWELSEGS ( keyword ) )
this - > updateWell ( well_ptr , currentStep ) ;
}
2015-10-26 12:51:09 +01:00
}
2019-05-23 13:13:36 +02:00
void Schedule : : handleCOMPSEGS ( const DeckKeyword & keyword , size_t currentStep , const EclipseGrid & grid ,
const ParseContext & parseContext , ErrorGuard & errors ) {
2016-02-09 12:09:40 +01:00
const auto & record1 = keyword . getRecord ( 0 ) ;
const std : : string & well_name = record1 . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
2019-03-23 16:11:37 +01:00
{
auto & dynamic_state = this - > wells_static . at ( well_name ) ;
auto well_ptr = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
2019-05-23 13:13:36 +02:00
if ( well_ptr - > handleCOMPSEGS ( keyword , grid , parseContext , errors ) )
2019-03-23 16:11:37 +01:00
this - > updateWell ( well_ptr , 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 ) {
2019-03-23 16:11:37 +01:00
const auto well_names = this - > wellNames ( record . getItem ( " WELL " ) . getTrimmedString ( 0 ) , currentStep ) ;
for ( const auto & well_name : well_names ) {
bool availableForGroupControl = DeckItem : : to_bool ( record . getItem ( " GROUP_CONTROLLED " ) . getTrimmedString ( 0 ) ) ;
double guide_rate = record . getItem ( " GUIDE_RATE " ) . get < double > ( 0 ) ;
double scaling_factor = record . getItem ( " SCALING_FACTOR " ) . get < double > ( 0 ) ;
GuideRate : : GuideRatePhaseEnum phase = GuideRate : : UNDEFINED ;
if ( ! record . getItem ( " PHASE " ) . defaultApplied ( 0 ) ) {
std : : string guideRatePhase = record . getItem ( " PHASE " ) . getTrimmedString ( 0 ) ;
phase = GuideRate : : GuideRatePhaseEnumFromString ( guideRatePhase ) ;
}
2014-02-21 12:48:36 +01:00
2019-03-23 16:11:37 +01:00
{
auto & dynamic_state = this - > wells_static . at ( well_name ) ;
auto well_ptr = std : : make_shared < Well2 > ( * dynamic_state [ currentStep ] ) ;
if ( well_ptr - > updateWellGuideRate ( availableForGroupControl , guide_rate , phase , scaling_factor ) )
this - > updateWell ( well_ptr , currentStep ) ;
}
}
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 ) ;
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 ) ;
2019-07-25 11:46:15 +02:00
this - > addGroupToGroup ( parentName , 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
2019-07-24 08:38:39 +02: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 ) ;
int table = record . getItem ( " VFP_TABLE " ) . get < int > ( 0 ) ;
2019-07-24 08:38:39 +02:00
{
auto & group = this - > m_groups . at ( groupName ) ;
group . setGroupNetVFPTable ( currentStep , table ) ;
}
{
auto group_ptr = std : : make_shared < Group2 > ( this - > getGroup2 ( groupName , currentStep ) ) ;
if ( group_ptr - > updateNetVFPTable ( table ) )
2019-07-30 17:47:19 +02:00
this - > updateGroup ( std : : move ( group_ptr ) , currentStep ) ;
2019-07-24 08:38:39 +02:00
}
2017-12-04 16:24:07 +01:00
}
}
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 ) ;
2019-03-23 16:51:32 +01:00
const auto well_names = wellNames ( wellNamePattern , currentStep ) ;
2019-04-10 07:44:45 +02:00
for ( const auto & well_name : well_names )
2019-04-03 18:47:02 +02:00
this - > rft_config . updateRFT ( well_name , currentStep , RFTConnections : : RFTEnum : : YES ) ;
2019-04-10 07:44:45 +02:00
2015-02-06 14:54:03 +01:00
}
2019-04-03 18:47:02 +02:00
this - > rft_config . setWellOpenRFT ( currentStep ) ;
2015-02-06 14:54:03 +01:00
}
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 ) ) ;
2019-03-23 16:51:32 +01:00
const auto well_names = wellNames ( wellNamePattern , currentStep ) ;
for ( const auto & well_name : well_names ) {
2019-04-03 18:47:02 +02:00
this - > rft_config . updateRFT ( well_name , currentStep , RFTKey ) ;
this - > rft_config . updatePLT ( well_name , currentStep , PLTKey ) ;
2015-02-06 14:54:03 +01:00
}
}
}
2013-11-14 16:08:10 +01:00
2019-04-03 18:47:02 +02:00
const RFTConfig & Schedule : : rftConfig ( ) const {
return this - > rft_config ;
}
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
}
2019-07-25 11:46:15 +02:00
GTNode Schedule : : groupTree ( const std : : string & root_node , std : : size_t report_step , const GTNode * parent ) const {
auto root_group = this - > getGroup2 ( root_node , report_step ) ;
GTNode tree ( root_group , parent ) ;
for ( const auto & wname : root_group . wells ( ) ) {
const auto & well = this - > getWell2 ( wname , report_step ) ;
tree . add_well ( well ) ;
}
for ( const auto & gname : root_group . groups ( ) ) {
auto child_group = this - > groupTree ( gname , report_step , std : : addressof ( tree ) ) ;
tree . add_group ( child_group ) ;
}
return tree ;
}
GTNode Schedule : : groupTree ( const std : : string & root_node , std : : size_t report_step ) const {
return this - > groupTree ( root_node , report_step , nullptr ) ;
}
GTNode Schedule : : groupTree ( std : : size_t report_step ) const {
return this - > groupTree ( " FIELD " , report_step ) ;
}
2019-06-08 12:25:29 +02:00
void Schedule : : addWell ( const std : : string & wellName ,
const DeckRecord & record ,
size_t timeStep ,
WellCompletion : : CompletionOrderEnum wellConnectionOrder ,
const UnitSystem & unit_system ) {
2014-01-29 11:48:02 +01:00
// We change from eclipse's 1 - n, to a 0 - n-1 solution
2016-02-09 12:09:40 +01:00
int headI = record . getItem ( " HEAD_I " ) . get < int > ( 0 ) - 1 ;
int headJ = record . getItem ( " HEAD_J " ) . get < int > ( 0 ) - 1 ;
2018-12-20 12:10:14 +01:00
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 ;
}
2019-03-23 16:11:37 +01:00
{
wells_static . insert ( std : : make_pair ( wellName , DynamicState < std : : shared_ptr < Well2 > > ( m_timeMap , nullptr ) ) ) ;
auto & dynamic_state = wells_static . at ( wellName ) ;
const std : : string & group = record . getItem < ParserKeywords : : WELSPECS : : GROUP > ( ) . getTrimmedString ( 0 ) ;
std : : size_t insert_index = this - > wells_static . size ( ) - 1 ;
2019-06-08 12:25:29 +02:00
auto well_ptr = std : : make_shared < Well2 > ( wellName ,
group ,
timeStep ,
insert_index ,
headI , headJ ,
refDepth ,
preferredPhase ,
this - > global_whistctl_mode [ timeStep ] ,
wellConnectionOrder ,
2019-06-19 13:24:21 +02:00
unit_system ,
this - > getUDQConfig ( timeStep ) . params ( ) . undefinedValue ( ) ) ;
2019-03-23 16:11:37 +01:00
well_ptr - > updateCrossFlow ( allowCrossFlow ) ;
well_ptr - > updateAutoShutin ( automaticShutIn ) ;
well_ptr - > updateDrainageRadius ( drainageRadius ) ;
dynamic_state . update ( timeStep , well_ptr ) ;
}
2016-10-05 10:09:45 +02:00
m_events . addEvent ( ScheduleEvents : : NEW_WELL , timeStep ) ;
2019-03-21 08:49:27 +01:00
well_events . insert ( std : : make_pair ( wellName , Events ( this - > m_timeMap ) ) ) ;
this - > addWellEvent ( wellName , 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 {
2019-05-04 12:00:32 +02:00
return wells_static . size ( ) ;
2013-11-05 15:25:47 +01:00
}
2015-02-12 12:54:57 +01:00
size_t Schedule : : numWells ( size_t timestep ) const {
2019-03-23 16:11:37 +01:00
auto well_names = this - > wellNames ( timestep ) ;
return well_names . size ( ) ;
2014-12-05 12:59:53 +01:00
}
2013-11-05 15:25:47 +01:00
bool Schedule : : hasWell ( const std : : string & wellName ) const {
2019-05-04 12:00:32 +02:00
return wells_static . count ( wellName ) > 0 ;
2015-02-12 12:54:57 +01:00
}
2019-05-04 12:00:32 +02:00
bool Schedule : : hasWell ( const std : : string & wellName , std : : size_t timeStep ) const {
if ( this - > wells_static . count ( wellName ) = = 0 )
return false ;
2017-07-25 19:50:06 +02:00
2019-05-04 12:00:32 +02:00
const auto & well = this - > getWell2atEnd ( wellName ) ;
return well . hasBeenDefined ( timeStep ) ;
2017-07-25 19:50:06 +02:00
}
2019-05-04 12:00:32 +02:00
std : : vector < Well2 > Schedule : : getChildWells2 ( const std : : string & group_name , size_t timeStep , GroupWellQueryMode query_mode ) const {
2019-03-23 16:11:37 +01:00
if ( ! hasGroup ( group_name ) )
2019-07-25 11:46:15 +02:00
throw std : : invalid_argument ( " No such group: ' " + group_name + " ' " ) ;
2019-03-23 16:11:37 +01:00
{
const auto & group = getGroup ( group_name ) ;
2019-05-04 12:00:32 +02:00
std : : vector < Well2 > wells ;
2019-03-23 16:11:37 +01:00
if ( group . hasBeenDefined ( timeStep ) ) {
const GroupTree & group_tree = getGroupTree ( timeStep ) ;
const auto & child_groups = group_tree . children ( group_name ) ;
if ( child_groups . size ( ) & & query_mode = = GroupWellQueryMode : : Recursive ) {
for ( const auto & child : child_groups ) {
const auto & child_wells = getChildWells2 ( child , timeStep , query_mode ) ;
wells . insert ( wells . end ( ) , child_wells . begin ( ) , child_wells . end ( ) ) ;
}
} else {
for ( const auto & well_name : group . getWells ( timeStep ) )
2019-05-04 12:00:32 +02:00
wells . push_back ( this - > getWell2 ( well_name , timeStep ) ) ;
2019-03-23 16:11:37 +01:00
}
}
return wells ;
}
}
2019-05-04 12:00:32 +02:00
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 ) )
2019-07-25 11:46:15 +02:00
throw std : : invalid_argument ( " No such group: ' " + group_name + " ' " ) ;
2018-04-25 09:44:57 +02:00
{
const auto & group = getGroup ( group_name ) ;
2019-04-17 08:58:00 +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 ) ;
2019-04-17 08:58:00 +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-25 09:44:57 +02:00
}
}
2019-04-17 08:58:00 +02:00
return child_groups ;
2018-04-25 09:44:57 +02:00
}
}
2019-01-28 09:52:11 +01:00
2019-05-04 12:00:32 +02:00
std : : vector < Well2 > Schedule : : getWells2 ( size_t timeStep ) const {
std : : vector < Well2 > wells ;
if ( timeStep > = this - > m_timeMap . size ( ) )
throw std : : invalid_argument ( " timeStep argument beyond the length of the simulation " ) ;
2016-06-16 08:37:10 +02:00
2019-05-04 12:00:32 +02:00
for ( const auto & dynamic_pair : this - > wells_static ) {
auto & well_ptr = dynamic_pair . second . get ( timeStep ) ;
if ( well_ptr )
wells . push_back ( * well_ptr . get ( ) ) ;
2015-02-12 12:54:57 +01:00
}
2016-06-16 08:37:10 +02:00
return wells ;
2015-02-12 15:36:39 +01:00
}
2019-05-04 12:00:32 +02:00
std : : vector < Well2 > Schedule : : getWells2atEnd ( ) const {
return this - > getWells2 ( this - > m_timeMap . size ( ) - 1 ) ;
}
const Well2 & Schedule : : getWell2atEnd ( const std : : string & well_name ) const {
return this - > getWell2 ( well_name , this - > m_timeMap . size ( ) - 1 ) ;
2016-03-29 14:13:54 +02:00
}
2019-03-23 16:11:37 +01:00
const Well2 & Schedule : : getWell2 ( const std : : string & wellName , size_t timeStep ) const {
if ( this - > wells_static . count ( wellName ) = = 0 )
throw std : : invalid_argument ( " No such well: " + wellName ) ;
const auto & dynamic_state = this - > wells_static . at ( wellName ) ;
auto & well_ptr = dynamic_state . get ( timeStep ) ;
if ( ! well_ptr )
throw std : : invalid_argument ( " Well: " + wellName + " not yet defined at step: " + std : : to_string ( timeStep ) ) ;
return * well_ptr ;
}
2015-05-28 14:55:09 +02:00
2019-07-24 08:38:39 +02:00
const Group2 & Schedule : : getGroup2 ( const std : : string & groupName , size_t timeStep ) const {
if ( this - > groups . count ( groupName ) = = 0 )
2019-07-25 11:46:15 +02:00
throw std : : invalid_argument ( " No such group: ' " + groupName + " ' " ) ;
2019-07-24 08:38:39 +02:00
const auto & dynamic_state = this - > groups . at ( groupName ) ;
auto & group_ptr = dynamic_state . get ( timeStep ) ;
if ( ! group_ptr )
throw std : : invalid_argument ( " Group: " + groupName + " not yet defined at step: " + std : : to_string ( timeStep ) ) ;
return * group_ptr ;
}
void Schedule : : updateGroup ( std : : shared_ptr < Group2 > group , size_t reportStep ) {
auto & dynamic_state = this - > groups . at ( group - > name ( ) ) ;
2019-07-30 17:47:19 +02:00
dynamic_state . update ( reportStep , std : : move ( group ) ) ;
2019-07-24 08:38:39 +02:00
}
2019-03-14 09:23:03 +01:00
/*
There are many SCHEDULE keyword which take a wellname as argument . In
addition to giving a fully qualified name like ' W1 ' you can also specify
shell wildcard patterns like like ' W * ' , you can get all the wells in the
well - list ' * WL ' [ 1 ] and the wellname ' ? ' is used to get all the wells which
already have matched a condition in a ACTIONX keyword . This function
should be one - stop function to get all well names according to a input
pattern . The timestep argument is used to check that the wells have
2019-05-04 12:00:32 +02:00
indeed been defined at the point in time we are considering .
2019-03-14 09:23:03 +01:00
[ 1 ] : The leading ' * ' in a WLIST name should not be interpreted as a shell
wildcard !
*/
std : : vector < std : : string > Schedule : : wellNames ( const std : : string & pattern , size_t timeStep , const std : : vector < std : : string > & matching_wells ) const {
2019-03-18 10:44:11 +01:00
if ( pattern . size ( ) = = 0 )
return { } ;
2019-03-14 09:23:03 +01:00
// WLIST
2019-03-18 10:44:11 +01:00
if ( pattern [ 0 ] = = ' * ' & & pattern . size ( ) > 1 ) {
2019-03-14 09:23:03 +01:00
const auto & wlm = this - > getWListManager ( timeStep ) ;
if ( wlm . hasList ( pattern ) ) {
const auto & wlist = wlm . getList ( pattern ) ;
return { wlist . begin ( ) , wlist . end ( ) } ;
} else
return { } ;
}
// Normal pattern matching
auto star_pos = pattern . find ( ' * ' ) ;
if ( star_pos ! = std : : string : : npos ) {
std : : vector < std : : string > names ;
2019-03-23 16:11:37 +01:00
for ( const auto & well_pair : this - > wells_static ) {
2019-07-07 08:46:17 +02:00
if ( name_match ( pattern , well_pair . first ) ) {
2019-03-23 16:11:37 +01:00
const auto & dynamic_state = well_pair . second ;
if ( dynamic_state . get ( timeStep ) )
2019-03-14 09:23:03 +01:00
names . push_back ( well_pair . first ) ;
}
}
return names ;
}
// ACTIONX handler
2019-05-04 12:00:32 +02:00
if ( pattern = = " ? " )
2019-03-14 09:23:03 +01:00
return { matching_wells . begin ( ) , matching_wells . end ( ) } ;
// Normal well name without any special characters
if ( this - > hasWell ( pattern ) ) {
2019-03-23 16:11:37 +01:00
const auto & dynamic_state = this - > wells_static . at ( pattern ) ;
if ( dynamic_state . get ( timeStep ) )
2019-03-14 09:23:03 +01:00
return { pattern } ;
}
return { } ;
}
2019-03-24 07:53:30 +01:00
std : : vector < std : : string > Schedule : : wellNames ( const std : : string & pattern ) const {
return this - > wellNames ( pattern , this - > size ( ) - 1 ) ;
}
std : : vector < std : : string > Schedule : : wellNames ( std : : size_t timeStep ) const {
std : : vector < std : : string > names ;
2019-05-04 12:00:32 +02:00
for ( const auto & well_pair : this - > wells_static ) {
const auto & well_name = well_pair . first ;
const auto & dynamic_state = well_pair . second ;
auto open_step = static_cast < std : : size_t > ( dynamic_state . find_not ( nullptr ) ) ;
if ( open_step < = timeStep )
names . push_back ( well_name ) ;
2019-03-24 07:53:30 +01:00
}
return names ;
}
std : : vector < std : : string > Schedule : : wellNames ( ) const {
std : : vector < std : : string > names ;
2019-05-04 12:00:32 +02:00
for ( const auto & well_pair : this - > wells_static )
2019-03-24 07:53:30 +01:00
names . push_back ( well_pair . first ) ;
2019-05-04 12:00:32 +02:00
2019-03-24 07:53:30 +01:00
return names ;
2019-07-07 08:46:17 +02:00
}
std : : vector < std : : string > Schedule : : groupNames ( const std : : string & pattern , size_t timeStep ) const {
if ( pattern . size ( ) = = 0 )
return { } ;
// Normal pattern matching
auto star_pos = pattern . find ( ' * ' ) ;
if ( star_pos ! = std : : string : : npos ) {
std : : vector < std : : string > names ;
for ( const auto & group_pair : this - > m_groups ) {
if ( name_match ( pattern , group_pair . first ) ) {
const auto & group = group_pair . second ;
if ( group . hasBeenDefined ( timeStep ) )
names . push_back ( group_pair . first ) ;
}
}
return names ;
}
// Normal group name without any special characters
if ( this - > hasGroup ( pattern ) ) {
const auto & group = this - > m_groups . at ( pattern ) ;
if ( group . hasBeenDefined ( timeStep ) )
return { pattern } ;
}
return { } ;
}
std : : vector < std : : string > Schedule : : groupNames ( size_t timeStep ) const {
std : : vector < std : : string > names ;
for ( const auto & group_pair : this - > m_groups ) {
const auto & group = group_pair . second ;
if ( group . hasBeenDefined ( timeStep ) )
names . push_back ( group . name ( ) ) ;
}
return names ;
}
std : : vector < std : : string > Schedule : : groupNames ( const std : : string & pattern ) const {
if ( pattern . size ( ) = = 0 )
return { } ;
// Normal pattern matching
auto star_pos = pattern . find ( ' * ' ) ;
if ( star_pos ! = std : : string : : npos ) {
int flags = 0 ;
std : : vector < std : : string > names ;
for ( const auto & group_pair : this - > m_groups ) {
if ( fnmatch ( pattern . c_str ( ) , group_pair . first . c_str ( ) , flags ) = = 0 )
names . push_back ( group_pair . first ) ;
}
return names ;
}
// Normal group name without any special characters
if ( this - > hasGroup ( pattern ) )
return { pattern } ;
return { } ;
}
std : : vector < std : : string > Schedule : : groupNames ( ) const {
std : : vector < std : : string > names ;
for ( const auto & group_pair : this - > m_groups )
names . push_back ( group_pair . first ) ;
return names ;
2019-03-24 07:53:30 +01:00
}
2019-03-14 09:23:03 +01:00
2015-02-12 12:54:57 +01:00
2013-11-25 16:31:44 +01:00
void Schedule : : addGroup ( const std : : string & groupName , size_t timeStep ) {
2019-03-23 16:11:37 +01:00
const size_t gseqIndex = m_groups . size ( ) ;
2019-07-24 08:38:39 +02:00
// Old group
2019-03-23 16:11:37 +01:00
m_groups . insert ( std : : make_pair ( groupName , Group { groupName , gseqIndex , m_timeMap , timeStep } ) ) ;
2019-07-24 08:38:39 +02:00
// New group
groups . insert ( std : : make_pair ( groupName , DynamicState < std : : shared_ptr < Group2 > > ( this - > m_timeMap , nullptr ) ) ) ;
auto group_ptr = std : : make_shared < Group2 > ( groupName , gseqIndex , timeStep ) ;
auto & dynamic_state = this - > groups . at ( groupName ) ;
dynamic_state . update ( timeStep , group_ptr ) ;
2016-10-05 10:09:45 +02:00
m_events . addEvent ( ScheduleEvents : : NEW_GROUP , timeStep ) ;
2019-07-25 11:46:15 +02:00
// All newly created groups are attached to the field group,
// can then be relocated with the GRUPTREE keyword.
if ( groupName ! = " FIELD " )
this - > addGroupToGroup ( " FIELD " , * group_ptr , timeStep ) ;
2013-11-18 13:11:49 +01:00
}
size_t Schedule : : numGroups ( ) const {
return m_groups . size ( ) ;
}
2019-07-07 10:29:24 +02:00
2018-04-24 14:03:29 +02:00
size_t Schedule : : numGroups ( size_t timeStep ) const {
2019-07-07 10:29:24 +02:00
const auto group_names = this - > groupNames ( timeStep ) ;
return group_names . size ( ) ;
2018-04-24 14:03:29 +02:00
}
2013-11-18 13:11:49 +01:00
bool Schedule : : hasGroup ( const std : : string & groupName ) const {
2019-03-08 09:00:36 +01:00
return m_groups . count ( groupName ) > 0 ;
2013-11-18 13:11:49 +01: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 " ) ;
}
2019-07-07 10:29:24 +02:00
Group & Schedule : : getGroup ( const std : : string & groupName ) {
if ( hasGroup ( groupName ) ) {
return m_groups . at ( groupName ) ;
} else
throw std : : invalid_argument ( " Group: " + groupName + " does not exist " ) ;
}
2019-07-25 11:46:15 +02:00
void Schedule : : addGroupToGroup ( const std : : string & parent_group , const Group2 & child_group , size_t timeStep ) {
// Add to new parent
auto & dynamic_state = this - > groups . at ( parent_group ) ;
auto parent_ptr = std : : make_shared < Group2 > ( * dynamic_state [ timeStep ] ) ;
if ( parent_ptr - > addGroup ( child_group . name ( ) ) )
2019-07-30 17:47:19 +02:00
this - > updateGroup ( std : : move ( parent_ptr ) , timeStep ) ;
2019-07-25 11:46:15 +02:00
// Check and update backreference in child
if ( child_group . parent ( ) ! = parent_group ) {
auto old_parent = std : : make_shared < Group2 > ( this - > getGroup2 ( child_group . parent ( ) , timeStep ) ) ;
old_parent - > delGroup ( child_group . name ( ) ) ;
2019-07-30 17:47:19 +02:00
this - > updateGroup ( std : : move ( old_parent ) , timeStep ) ;
2019-01-28 09:52:11 +01:00
2019-07-25 11:46:15 +02:00
auto child_ptr = std : : make_shared < Group2 > ( child_group ) ;
child_ptr - > updateParent ( parent_group ) ;
2019-07-30 17:47:19 +02:00
this - > updateGroup ( std : : move ( child_ptr ) , timeStep ) ;
2013-11-18 13:11:49 +01:00
2019-07-25 11:46:15 +02:00
}
}
void Schedule : : addGroupToGroup ( const std : : string & parent_group , const std : : string & child_group , size_t timeStep ) {
this - > addGroupToGroup ( parent_group , this - > getGroup2 ( child_group , timeStep ) , timeStep ) ;
}
void Schedule : : addWellToGroup ( const std : : string & group_name , const std : : string & well_name , size_t timeStep ) {
const auto & well = this - > getWell2 ( well_name , timeStep ) ;
const auto old_gname = well . groupName ( ) ;
{
auto well_ptr = std : : make_shared < Well2 > ( well ) ;
well_ptr - > updateGroup ( group_name ) ;
this - > updateWell ( well_ptr , timeStep ) ;
}
// Remove well child reference from previous group
// Old Group implementation
if ( old_gname ! = group_name ) {
{
auto & group = this - > m_groups . at ( old_gname ) ;
group . delWell ( timeStep , well_name ) ;
}
// New Group2 implementation
{
auto group = std : : make_shared < Group2 > ( this - > getGroup2 ( old_gname , timeStep ) ) ;
group - > delWell ( well_name ) ;
2019-07-30 17:47:19 +02:00
this - > updateGroup ( std : : move ( group ) , timeStep ) ;
2019-07-25 11:46:15 +02:00
}
}
// Add well child reference to new parent group
{
auto & group = this - > m_groups . at ( group_name ) ;
group . addWell ( timeStep , well_name ) ;
}
{
auto group = std : : make_shared < Group2 > ( this - > getGroup2 ( group_name , timeStep ) ) ;
group - > addWell ( well_name ) ;
2019-07-30 17:47:19 +02:00
this - > updateGroup ( std : : move ( group ) , timeStep ) ;
2019-07-25 11:46:15 +02:00
}
2019-05-04 12:00:32 +02:00
}
2015-01-28 09:39:13 +01:00
2014-12-05 12:59:53 +01:00
2015-04-17 18:51:42 +02:00
2016-10-05 10:04:22 +02:00
const Tuning & Schedule : : getTuning ( ) const {
2019-05-04 12:00:32 +02:00
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
2019-03-21 08:49:27 +01:00
const Events & Schedule : : getWellEvents ( const std : : string & well ) const {
if ( this - > well_events . count ( well ) > 0 )
return this - > well_events . at ( well ) ;
else
throw std : : invalid_argument ( " No such well " + well ) ;
}
2016-04-14 09:39:28 +08:00
2019-03-21 08:49:27 +01:00
void Schedule : : addWellEvent ( const std : : string & well , ScheduleEvents : : Events event , size_t reportStep ) {
auto & events = this - > well_events . at ( well ) ;
events . addEvent ( event , reportStep ) ;
}
bool Schedule : : hasWellEvent ( const std : : string & well , uint64_t event_mask , size_t reportStep ) const {
const auto & events = this - > getWellEvents ( well ) ;
return events . hasEvent ( event_mask , reportStep ) ;
}
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
2019-05-04 12:00:32 +02:00
void Schedule : : checkIfAllConnectionsIsShut ( size_t timeStep ) {
const auto & well_names = this - > wellNames ( timeStep ) ;
for ( const auto & wname : well_names ) {
const auto & well = this - > getWell2 ( wname , timeStep ) ;
const auto & connections = well . getConnections ( ) ;
if ( connections . allConnectionsShut ( ) )
this - > updateWellStatus ( well . name ( ) , timeStep , WellCommon : : StatusEnum : : SHUT ) ;
2017-09-26 09:32:29 +02:00
}
}
2018-02-06 19:13:42 +01:00
2018-06-10 20:54:34 +02:00
void Schedule : : filterConnections ( const EclipseGrid & grid ) {
2019-05-04 12:00:32 +02:00
for ( auto & dynamic_pair : this - > wells_static ) {
auto & dynamic_state = dynamic_pair . second ;
for ( auto & well_pair : dynamic_state . unique ( ) ) {
if ( well_pair . second )
well_pair . second - > filterConnections ( grid ) ;
}
}
for ( auto & dynamic_pair : this - > wells_static ) {
auto & dynamic_state = dynamic_pair . second ;
for ( auto & well_pair : dynamic_state . unique ( ) ) {
if ( well_pair . second )
well_pair . second - > filterConnections ( grid ) ;
}
2019-03-08 09:00:36 +01:00
}
2019-03-23 16:11:37 +01:00
for ( auto & dynamic_pair : this - > wells_static ) {
auto & dynamic_state = dynamic_pair . second ;
for ( auto & well_pair : dynamic_state . unique ( ) ) {
if ( well_pair . second )
well_pair . second - > filterConnections ( grid ) ;
}
}
2018-02-06 19:13:42 +01:00
}
2018-04-06 12:12:30 +02:00
2018-04-12 19:02:15 +02:00
const VFPProdTable & Schedule : : getVFPProdTable ( int table_id , size_t timeStep ) const {
const auto pair = vfpprod_tables . find ( table_id ) ;
if ( pair = = vfpprod_tables . end ( ) )
throw std : : invalid_argument ( " No such table id: " + std : : to_string ( table_id ) ) ;
auto table_ptr = pair - > second . get ( timeStep ) ;
if ( ! table_ptr )
throw std : : invalid_argument ( " Table not yet defined at timeStep: " + std : : to_string ( timeStep ) ) ;
return * table_ptr ;
2018-04-06 12:12:30 +02:00
}
2018-04-12 19:02:15 +02:00
const VFPInjTable & Schedule : : getVFPInjTable ( int table_id , size_t timeStep ) const {
const auto pair = vfpinj_tables . find ( table_id ) ;
if ( pair = = vfpinj_tables . end ( ) )
throw std : : invalid_argument ( " No such table id: " + std : : to_string ( table_id ) ) ;
auto table_ptr = pair - > second . get ( timeStep ) ;
if ( ! table_ptr )
throw std : : invalid_argument ( " Table not yet defined at timeStep: " + std : : to_string ( timeStep ) ) ;
return * table_ptr ;
}
2018-04-20 11:27:26 +02:00
std : : map < int , std : : shared_ptr < const VFPInjTable > > Schedule : : getVFPInjTables ( size_t timeStep ) const {
std : : map < int , std : : shared_ptr < const VFPInjTable > > tables ;
2018-04-12 19:02:15 +02:00
for ( const auto & pair : this - > vfpinj_tables ) {
if ( pair . second . get ( timeStep ) ) {
2018-04-20 11:27:26 +02:00
tables . insert ( std : : make_pair ( pair . first , pair . second . get ( timeStep ) ) ) ;
2018-04-12 19:02:15 +02:00
}
}
return tables ;
}
2018-04-20 11:27:26 +02:00
std : : map < int , std : : shared_ptr < const VFPProdTable > > Schedule : : getVFPProdTables ( size_t timeStep ) const {
std : : map < int , std : : shared_ptr < const VFPProdTable > > tables ;
2018-04-12 19:02:15 +02:00
for ( const auto & pair : this - > vfpprod_tables ) {
if ( pair . second . get ( timeStep ) ) {
2018-04-20 11:27:26 +02:00
tables . insert ( std : : make_pair ( pair . first , pair . second . get ( timeStep ) ) ) ;
2018-04-12 19:02:15 +02:00
}
}
return tables ;
2018-04-06 12:12:30 +02:00
}
2018-05-14 04:18:07 +02:00
const WellTestConfig & Schedule : : wtestConfig ( size_t timeStep ) const {
const auto & ptr = this - > wtest_config . get ( timeStep ) ;
return * ptr ;
}
2018-10-12 08:25:40 +02:00
2019-01-14 12:09:07 +01:00
const WListManager & Schedule : : getWListManager ( size_t timeStep ) const {
const auto & ptr = this - > wlist_manager . get ( timeStep ) ;
return * ptr ;
}
2018-10-27 15:58:02 +02:00
2019-02-21 11:49:33 +01:00
const UDQInput & Schedule : : getUDQConfig ( size_t timeStep ) const {
2019-01-28 16:52:28 +01:00
const auto & ptr = this - > udq_config . get ( timeStep ) ;
return * ptr ;
}
2018-10-27 15:58:02 +02:00
2018-10-12 08:25:40 +02:00
size_t Schedule : : size ( ) const {
return this - > m_timeMap . size ( ) ;
}
2018-10-17 12:08:54 +02:00
2018-11-19 09:43:50 +01:00
double Schedule : : seconds ( size_t timeStep ) const {
2018-10-17 12:08:54 +02:00
return this - > m_timeMap . seconds ( timeStep ) ;
}
2019-01-22 17:04:54 +01:00
time_t Schedule : : simTime ( size_t timeStep ) const {
return this - > m_timeMap [ timeStep ] ;
}
2018-10-09 17:42:37 +02:00
double Schedule : : stepLength ( size_t timeStep ) const {
return this - > m_timeMap . getTimeStepLength ( timeStep ) ;
}
2018-11-19 09:43:50 +01:00
2019-01-22 16:33:17 +01:00
const Actions & Schedule : : actions ( ) const {
return this - > m_actions ;
2018-11-19 09:43:50 +01:00
}
2019-01-28 10:00:08 +01:00
void Schedule : : applyAction ( size_t reportStep , const ActionX & action , const std : : vector < std : : string > & matching_wells ) {
ParseContext parseContext ;
ErrorGuard errors ;
for ( const auto & keyword : action ) {
2019-02-03 18:07:04 +01:00
if ( ! ActionX : : valid_keyword ( keyword . name ( ) ) )
2019-01-28 10:00:08 +01:00
throw std : : invalid_argument ( " The keyword: " + keyword . name ( ) + " can not be handled in the ACTION body " ) ;
if ( keyword . name ( ) = = " WELOPEN " )
this - > handleWELOPEN ( keyword , reportStep , parseContext , errors , matching_wells ) ;
}
}
2019-05-04 12:00:32 +02:00
2019-07-24 10:20:38 +02:00
# ifdef GROUP_TEST
bool Schedule : : checkGroups ( const ParseContext & parseContext , ErrorGuard & errors ) {
if ( this - > m_groups . size ( ) ! = this - > groups . size ( ) )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " Group count mismatch " , errors ) ;
// Check group names
for ( const auto & group_pair : this - > m_groups ) {
if ( this - > groups . count ( group_pair . second . name ( ) ) = = 0 )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " Group missing named group " , errors ) ;
}
// Insert index and defined()
for ( const auto & group_pair : this - > m_groups ) {
const auto & group = group_pair . second ;
const auto & dynamic_state = this - > groups . at ( group . name ( ) ) ;
if ( group . seqIndex ( ) ! = dynamic_state . back ( ) - > insert_index ( ) )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " Group - seq index error " , errors ) ;
for ( std : : size_t index = 0 ; index < dynamic_state . size ( ) ; index + + ) {
const auto & group2_ptr = dynamic_state [ index ] ;
if ( group2_ptr = = nullptr ) {
if ( group . hasBeenDefined ( index ) )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " Group defined error " , errors ) ;
} else {
if ( ! group . hasBeenDefined ( index ) )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " Group defined error " , errors ) ;
if ( group . hasBeenDefined ( index ) ! = group2_ptr - > defined ( index ) )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " Group defined error " , errors ) ;
}
}
}
// GCONINJE
for ( const auto & group_pair : this - > m_groups ) {
const auto & group = group_pair . second ;
const auto & dynamic_state = this - > groups . at ( group . name ( ) ) ;
for ( std : : size_t index = 0 ; index < dynamic_state . size ( ) ; index + + ) {
const auto & group_ptr = dynamic_state [ index ] ;
if ( group_ptr = = nullptr ) {
if ( group . getSurfaceMaxRate ( index ) ! = 0 )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " Group rate error 2 " , errors ) ;
if ( group . getReservoirMaxRate ( index ) ! = 0 )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " Group rate error 3 " , errors ) ;
if ( group . getTargetReinjectFraction ( index ) ! = 0 )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " Group rate error 4 " , errors ) ;
if ( group . getTargetVoidReplacementFraction ( index ) ! = 0 )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " Group rate error 5 " , errors ) ;
} else {
if ( group_ptr - > isInjectionGroup ( ) ) {
const auto & injection = group_ptr - > injectionProperties ( ) ;
if ( group . getReservoirMaxRate ( index ) ! = injection . resv_max_rate )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " Group rate error 6 " , errors ) ;
if ( group . getSurfaceMaxRate ( index ) ! = injection . surface_max_rate )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " Group rate error 7 " , errors ) ;
if ( group . getTargetReinjectFraction ( index ) ! = injection . target_reinj_fraction )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " Group rate error 9 " , errors ) ;
if ( group . getTargetVoidReplacementFraction ( index ) ! = injection . target_void_fraction )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " Group rate error 10 " , errors ) ;
if ( group . getInjectionControlMode ( index ) ! = injection . cmode )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " Group rate error 11 " , errors ) ;
if ( group . getInjectionPhase ( index ) ! = injection . phase )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " Group rate error 12 " , errors ) ;
if ( group . isProductionGroup ( index ) ! = group_ptr - > isProductionGroup ( ) )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " Group rate error 13 " , errors ) ;
}
}
}
}
// GCONPROD && GEFAC
for ( const auto & group_pair : this - > m_groups ) {
const auto & group = group_pair . second ;
const auto & dynamic_state = this - > groups . at ( group . name ( ) ) ;
for ( std : : size_t index = 0 ; index < dynamic_state . size ( ) ; index + + ) {
const auto & group_ptr = dynamic_state [ index ] ;
if ( group_ptr = = nullptr ) {
if ( group . getOilTargetRate ( index ) ! = 0 ) {
printf ( " Looking at group: %s step:%ld orat:%lg \n " , group . name ( ) . c_str ( ) , index , group . getOilTargetRate ( index ) ) ;
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " PRODGroup rate error 2 " , errors ) ;
}
if ( group . getGasTargetRate ( index ) ! = 0 )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " PRODGroup rate error 3 " , errors ) ;
if ( group . getWaterTargetRate ( index ) ! = 0 )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " PRODGroup rate error 4 " , errors ) ;
if ( group . getLiquidTargetRate ( index ) ! = 0 )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " PRODGroup rate error 5 " , errors ) ;
if ( group . getReservoirVolumeTargetRate ( index ) ! = 0 )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " PRODGroup rate error 6 " , errors ) ;
} else {
if ( group_ptr - > isProductionGroup ( ) ) {
const auto & production = group_ptr - > productionProperties ( ) ;
if ( group . getOilTargetRate ( index ) ! = production . oil_target )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " PRODGroup rate error 7 " , errors ) ;
if ( group . getGasTargetRate ( index ) ! = production . gas_target )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " PRODGroup rate error 8 " , errors ) ;
if ( group . getWaterTargetRate ( index ) ! = production . water_target )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " PRODGroup rate error 9 " , errors ) ;
if ( group . getLiquidTargetRate ( index ) ! = production . liquid_target )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " PRODGroup rate error 10 " , errors ) ;
if ( group . getReservoirVolumeTargetRate ( index ) ! = production . resv_target )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " PRODGroup rate error 11 " , errors ) ;
if ( group . getProductionControlMode ( index ) ! = production . cmode ) {
printf ( " Looking at group: %s step:%ld cmode:%d != %d \n " , group . name ( ) . c_str ( ) , index , static_cast < int > ( group . getProductionControlMode ( index ) ) , static_cast < int > ( production . cmode ) ) ;
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " PRODGroup rate error 12 " , errors ) ;
}
if ( group . getProductionExceedLimitAction ( index ) ! = production . exceed_action )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " PRODGroup rate error 13 " , errors ) ;
if ( group . isProductionGroup ( index ) ! = group_ptr - > isProductionGroup ( ) )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " PRODGroup rate error 14 " , errors ) ;
}
if ( group . getGroupEfficiencyFactor ( index ) ! = group_ptr - > getGroupEfficiencyFactor ( ) )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " GEFAC error " , errors ) ;
if ( group . getTransferGroupEfficiencyFactor ( index ) ! = group_ptr - > getTransferGroupEfficiencyFactor ( ) )
parseContext . handleError ( ParseContext : : SCHEDULE_GROUP_ERROR , " GEFAC error " , errors ) ;
}
}
}
return true ;
}
# else
bool Schedule : : checkGroups ( const ParseContext & parseContext , ErrorGuard & errors ) {
return true ;
}
# endif
}