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
2020-10-19 01:56:10 +02:00
# include <algorithm>
2020-09-28 14:21:35 +02:00
# include <ctime>
2019-03-14 09:23:03 +01:00
# include <fnmatch.h>
2020-10-19 01:56:10 +02:00
# include <functional>
2020-03-30 10:38:15 +02:00
# include <iostream>
2020-04-25 19:15:17 +02:00
# include <optional>
2020-03-30 10:38:15 +02:00
# include <stdexcept>
2014-12-12 20:56:34 +01:00
# include <string>
2020-03-30 10:38:15 +02:00
# include <unordered_set>
2020-10-19 01:56:10 +02:00
# include <utility>
2014-12-12 20:56:34 +01:00
# include <vector>
2020-09-27 23:25:16 +02:00
# include <fmt/format.h>
2018-03-22 11:07:14 +01:00
# include <opm/common/OpmLog/LogUtil.hpp>
2020-10-10 08:59:38 +02:00
# include <opm/common/OpmLog/OpmLog.hpp>
2020-03-13 07:36:17 +01:00
# include <opm/common/utility/numeric/cmp.hpp>
2020-04-03 17:16:02 +02:00
# include <opm/common/utility/String.hpp>
2020-09-27 23:25:16 +02:00
# include <opm/common/utility/OpmInputError.hpp>
2018-03-22 11:07:14 +01:00
2020-03-16 16:02:05 +01:00
# include <opm/parser/eclipse/Python/Python.hpp>
2016-01-24 21:49:39 +01:00
# include <opm/parser/eclipse/Deck/DeckItem.hpp>
# include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
# include <opm/parser/eclipse/Deck/DeckRecord.hpp>
2019-12-29 07:21:37 +01:00
# include <opm/parser/eclipse/Deck/DeckSection.hpp>
2020-02-16 20:00:16 +01:00
# include <opm/parser/eclipse/Parser/ErrorGuard.hpp>
2016-03-16 17:15:09 +08:00
# include <opm/parser/eclipse/Parser/ParseContext.hpp>
2020-03-16 16:02:05 +01:00
# include <opm/parser/eclipse/Parser/ParserKeywords/P.hpp>
2020-10-10 08:59:38 +02:00
# include <opm/parser/eclipse/Parser/ParserKeywords/S.hpp>
2016-01-18 17:51:15 +01:00
# include <opm/parser/eclipse/Parser/ParserKeywords/W.hpp>
2014-12-12 20:56:34 +01:00
2016-01-15 08:42:57 +01:00
# include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
2019-01-17 11:22:49 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/Action/ActionX.hpp>
2019-07-01 08:27:07 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/Action/ActionResult.hpp>
2016-01-15 08:42:57 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/DynamicState.hpp>
# include <opm/parser/eclipse/EclipseState/Schedule/DynamicVector.hpp>
2020-05-28 09:27:03 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/MSW/SICD.hpp>
2019-12-16 14:46:04 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/MSW/Valve.hpp>
# include <opm/parser/eclipse/EclipseState/Schedule/MSW/WellSegments.hpp>
2016-09-12 14:28:19 +02:00
2016-01-15 08:42:57 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/OilVaporizationProperties.hpp>
2019-07-26 17:17:06 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQConfig.hpp>
2019-06-19 13:40:27 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQActive.hpp>
2020-04-01 13:01:45 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/RPTConfig.hpp>
2016-01-15 08:42:57 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
2013-10-25 17:28:56 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp>
2016-01-15 08:42:57 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/Tuning.hpp>
2020-04-25 19:15:17 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/Network/Node.hpp>
2019-03-08 07:12:07 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WList.hpp>
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WListManager.hpp>
2019-07-03 10:04:20 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WellFoamProperties.hpp>
2019-08-13 11:56:17 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WellInjectionProperties.hpp>
2019-03-08 07:12:07 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WellPolymerProperties.hpp>
2019-08-13 11:56:17 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WellProductionProperties.hpp>
2019-11-27 13:26:28 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WellBrineProperties.hpp>
2019-03-08 07:12:07 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WellConnections.hpp>
2018-11-19 09:43:50 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/SummaryState.hpp>
2016-01-24 21:49:39 +01:00
# include <opm/parser/eclipse/Units/Dimension.hpp>
2016-01-15 08:42:57 +01:00
# include <opm/parser/eclipse/Units/UnitSystem.hpp>
2018-12-18 14:42:25 +01:00
# include <opm/parser/eclipse/Units/Units.hpp>
2015-01-14 11:41:13 +01:00
2019-06-20 11:23:06 +02:00
# include "Well/injection.hpp"
2020-06-06 08:54:04 +02:00
# include "MSW/Compsegs.hpp"
2019-03-25 10:03:16 +01:00
2013-11-08 15:55:11 +01:00
namespace Opm {
2018-10-26 09:13:26 +02:00
2019-07-07 08:46:17 +02:00
namespace {
bool name_match ( const std : : string & pattern , const std : : string & name ) {
int flags = 0 ;
return ( fnmatch ( pattern . c_str ( ) , name . c_str ( ) , flags ) = = 0 ) ;
}
2020-09-21 19:22:11 +02:00
std : : pair < std : : time_t , std : : size_t > restart_info ( const RestartIO : : RstState * rst ) {
if ( ! rst )
return std : : make_pair ( std : : time_t { 0 } , std : : size_t { 0 } ) ;
else
return rst - > header . restart_info ( ) ;
}
2019-07-07 08:46:17 +02:00
}
2017-09-27 16:34:38 +02:00
Schedule : : Schedule ( const Deck & deck ,
2016-09-08 19:42:45 +02:00
const EclipseGrid & grid ,
2019-11-21 11:44:06 +01:00
const FieldPropsManager & fp ,
2018-10-17 13:35:25 +02:00
const Runspec & runspec ,
2019-01-03 11:53:32 +01:00
const ParseContext & parseContext ,
2020-01-28 13:03:07 +01:00
ErrorGuard & errors ,
2020-03-31 10:26:55 +02:00
[[maybe_unused]] std : : shared_ptr < const Python > python ,
2020-09-27 23:25:16 +02:00
const RestartIO : : RstState * rst )
try :
2020-03-22 21:02:32 +01:00
python_handle ( python ) ,
2021-01-04 11:34:22 +01:00
m_sched_deck ( deck , restart_info ( rst ) ) ,
2020-01-28 13:14:32 +01:00
m_timeMap ( deck , restart_info ( rst ) ) ,
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_messageLimits ( this - > m_timeMap ) ,
2018-10-17 13:35:25 +02:00
m_runspec ( runspec ) ,
2019-01-14 12:09:07 +01:00
wtest_config ( this - > m_timeMap , std : : make_shared < WellTestConfig > ( ) ) ,
2019-01-28 16:52:28 +01:00
wlist_manager ( this - > m_timeMap , std : : make_shared < WListManager > ( ) ) ,
2019-07-26 17:17:06 +02:00
udq_config ( this - > m_timeMap , std : : make_shared < UDQConfig > ( deck ) ) ,
2019-06-19 13:40:27 +02:00
udq_active ( this - > m_timeMap , std : : make_shared < UDQActive > ( ) ) ,
2019-09-06 07:56:42 +02:00
guide_rate_config ( this - > m_timeMap , std : : make_shared < GuideRateConfig > ( ) ) ,
2019-11-05 10:46:17 +01:00
gconsale ( this - > m_timeMap , std : : make_shared < GConSale > ( ) ) ,
2019-11-06 11:33:32 +01:00
gconsump ( this - > m_timeMap , std : : make_shared < GConSump > ( ) ) ,
2019-11-12 08:29:28 +01:00
global_whistctl_mode ( this - > m_timeMap , Well : : ProducerCMode : : CMODE_UNDEFINED ) ,
2019-08-29 18:17:37 +02:00
m_actions ( this - > m_timeMap , std : : make_shared < Action : : Actions > ( ) ) ,
2020-04-25 19:15:17 +02:00
m_network ( this - > m_timeMap , std : : make_shared < Network : : ExtNetwork > ( ) ) ,
2020-05-06 11:35:22 +02:00
m_glo ( this - > m_timeMap , std : : make_shared < GasLiftOpt > ( ) ) ,
2019-08-30 12:56:49 +02:00
rft_config ( this - > m_timeMap ) ,
2020-04-01 11:56:07 +02:00
restart_config ( m_timeMap , deck , parseContext , errors ) ,
2020-11-02 16:11:35 +01:00
unit_system ( deck . getActiveUnitSystem ( ) ) ,
2020-04-01 11:56:07 +02:00
rpt_config ( this - > m_timeMap , std : : make_shared < RPTConfig > ( ) )
2016-05-02 17:46:20 +02:00
{
2020-11-02 16:11:35 +01:00
addGroup ( " FIELD " , 0 ) ;
2020-03-13 07:36:45 +01:00
if ( rst )
2020-11-02 16:11:35 +01:00
this - > load_rst ( * rst , grid , fp ) ;
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 .
*/
2020-09-25 12:51:36 +02:00
for ( std : : size_t keywordIdx = 0 ; keywordIdx < deck . size ( ) ; + + keywordIdx ) {
2016-10-21 16:38:39 +02:00
const auto & keyword = deck . getKeyword ( keywordIdx ) ;
if ( keyword . name ( ) = = " SCHEDULE " )
break ;
if ( keyword . name ( ) = = " MESSAGES " )
2020-09-21 19:22:11 +02:00
applyMESSAGES ( keyword , 0 ) ;
2016-10-21 16:38:39 +02:00
}
2021-01-04 11:34:22 +01:00
this - > iterateScheduleSection ( python , deck . getInputPath ( ) , parseContext , errors , grid , fp ) ;
2021-01-05 12:16:44 +01:00
/*
This is temporary " integration test " for the time arguments in the
Schedule class .
*/
if ( this - > size ( ) > 0 ) {
for ( std : : size_t report_step = 0 ; report_step < this - > size ( ) - 1 ; report_step + + ) {
const auto & this_block = this - > m_sched_deck [ report_step ] ;
if ( this_block . start_time ( ) ! = std : : chrono : : system_clock : : from_time_t ( this - > m_timeMap [ report_step ] ) ) {
auto msg = fmt : : format ( " Block: Bug in start_time for report_step: {} " , report_step ) ;
throw std : : logic_error ( msg ) ;
}
const auto & next_block = this - > m_sched_deck [ report_step + 1 ] ;
if ( this_block . end_time ( ) ! = next_block . start_time ( ) )
throw std : : logic_error ( " Block: Internal bug in sched_block start / end inconsistent " ) ;
const auto & this_step = this - > operator [ ] ( report_step ) ;
if ( this_step . start_time ( ) ! = std : : chrono : : system_clock : : from_time_t ( this - > m_timeMap [ report_step ] ) ) {
auto msg = fmt : : format ( " Bug in start_time for report_step: {} " , report_step ) ;
throw std : : logic_error ( msg ) ;
}
const auto & next_step = this - > operator [ ] ( report_step + 1 ) ;
if ( this_step . end_time ( ) ! = next_step . start_time ( ) )
2021-01-07 09:36:15 +01:00
throw std : : logic_error ( fmt : : format ( " Internal bug in sched_step start / end inconsistent report:{} " , report_step ) ) ;
2021-01-05 12:16:44 +01:00
}
}
2013-11-14 16:08:10 +01:00
}
2020-09-27 23:25:16 +02:00
catch ( const OpmInputError & opm_error ) {
throw ;
}
catch ( const std : : exception & std_error ) {
2020-10-09 11:23:41 +02:00
OpmLog : : error ( fmt : : format ( " An error occured while creating the reservoir schedule \n "
2020-09-27 23:25:16 +02:00
" Internal error: {} " , std_error . what ( ) ) ) ;
throw ;
}
2013-11-14 16:08:10 +01:00
2017-12-03 09:00:56 +01:00
2019-01-03 18:05:19 +01:00
template < typename T >
Schedule : : Schedule ( const Deck & deck ,
const EclipseGrid & grid ,
2019-11-21 11:44:06 +01:00
const FieldPropsManager & fp ,
2019-01-03 18:05:19 +01:00
const Runspec & runspec ,
const ParseContext & parseContext ,
2020-01-28 13:03:07 +01:00
T & & errors ,
2020-03-31 10:26:55 +02:00
std : : shared_ptr < const Python > python ,
2020-01-28 13:03:07 +01:00
const RestartIO : : RstState * rst ) :
2020-03-26 15:31:21 +01:00
Schedule ( deck , grid , fp , runspec , parseContext , errors , python , rst )
2019-01-03 18:05:19 +01:00
{ }
Schedule : : Schedule ( const Deck & deck ,
const EclipseGrid & grid ,
2019-11-21 11:44:06 +01:00
const FieldPropsManager & fp ,
2020-01-28 13:03:07 +01:00
const Runspec & runspec ,
2020-03-31 10:26:55 +02:00
std : : shared_ptr < const Python > python ,
2020-01-28 13:03:07 +01:00
const RestartIO : : RstState * rst ) :
2020-03-26 15:31:21 +01:00
Schedule ( deck , grid , fp , runspec , ParseContext ( ) , ErrorGuard ( ) , python , rst )
2019-01-03 18:05:19 +01:00
{ }
2020-09-25 10:49:47 +02:00
Schedule : : Schedule ( const Deck & deck , const EclipseState & es , const ParseContext & parse_context , ErrorGuard & errors , std : : shared_ptr < const Python > python , const RestartIO : : RstState * rst ) :
2017-12-03 09:00:56 +01:00
Schedule ( deck ,
es . getInputGrid ( ) ,
2019-11-21 11:44:06 +01:00
es . fieldProps ( ) ,
2018-10-17 13:35:25 +02:00
es . runspec ( ) ,
2019-01-03 11:53:32 +01:00
parse_context ,
2020-01-28 13:03:07 +01:00
errors ,
2020-03-26 15:31:21 +01:00
python ,
2020-01-28 13:03:07 +01:00
rst )
2017-12-03 09:00:56 +01:00
{ }
2019-01-03 18:05:19 +01:00
template < typename T >
2020-03-31 10:26:55 +02:00
Schedule : : Schedule ( const Deck & deck , const EclipseState & es , const ParseContext & parse_context , T & & errors , std : : shared_ptr < const Python > python , const RestartIO : : RstState * rst ) :
2019-01-03 18:05:19 +01:00
Schedule ( deck ,
es . getInputGrid ( ) ,
2019-11-21 11:44:06 +01:00
es . fieldProps ( ) ,
2019-01-03 18:05:19 +01:00
es . runspec ( ) ,
parse_context ,
2020-01-28 13:03:07 +01:00
errors ,
2020-03-26 15:31:21 +01:00
python ,
2020-01-28 13:03:07 +01:00
rst )
2019-01-03 18:05:19 +01:00
{ }
2020-03-31 10:26:55 +02:00
Schedule : : Schedule ( const Deck & deck , const EclipseState & es , std : : shared_ptr < const Python > python , const RestartIO : : RstState * rst ) :
2020-03-26 15:31:21 +01:00
Schedule ( deck , es , ParseContext ( ) , ErrorGuard ( ) , python , rst )
2019-01-03 18:05:19 +01:00
{ }
2018-04-24 14:03:29 +02:00
2020-03-26 15:31:21 +01:00
Schedule : : Schedule ( const Deck & deck , const EclipseState & es , const RestartIO : : RstState * rst ) :
2020-03-31 10:26:55 +02:00
Schedule ( deck , es , ParseContext ( ) , ErrorGuard ( ) , std : : make_shared < const Python > ( ) , rst )
2020-03-26 15:31:21 +01:00
{ }
2020-04-10 09:15:05 +02:00
/*
In general the serializeObject ( ) instances are used as targets for
deserialization , i . e . the serialized buffer is unpacked into this
instance . However the Schedule object is a top level object , and the
simulator will instantiate and manage a Schedule object to unpack into , so
the instance created here is only for testing .
*/
2020-03-19 15:21:20 +01:00
Schedule Schedule : : serializeObject ( )
{
2020-04-10 09:15:05 +02:00
auto python = std : : make_shared < Python > ( Python : : Enable : : OFF ) ;
Schedule result ( python ) ;
2020-03-19 15:21:20 +01:00
result . m_timeMap = TimeMap : : serializeObject ( ) ;
result . wells_static . insert ( { " test1 " , { { std : : make_shared < Opm : : Well > ( Opm : : Well : : serializeObject ( ) ) } , 1 } } ) ;
result . groups . insert ( { " test2 " , { { std : : make_shared < Opm : : Group > ( Opm : : Group : : serializeObject ( ) ) } , 1 } } ) ;
result . m_events = Events : : serializeObject ( ) ;
result . m_modifierDeck = DynamicVector < Deck > ( { Deck : : serializeObject ( ) } ) ;
result . m_messageLimits = MessageLimits : : serializeObject ( ) ;
result . m_runspec = Runspec : : serializeObject ( ) ;
result . vfpprod_tables = { { 1 , { { std : : make_shared < VFPProdTable > ( VFPProdTable : : serializeObject ( ) ) } , 1 } } } ;
result . vfpinj_tables = { { 2 , { { std : : make_shared < VFPInjTable > ( VFPInjTable : : serializeObject ( ) ) } , 1 } } } ;
result . wtest_config = { { std : : make_shared < WellTestConfig > ( WellTestConfig : : serializeObject ( ) ) } , 1 } ;
result . wlist_manager = { { std : : make_shared < WListManager > ( WListManager : : serializeObject ( ) ) } , 1 } ;
result . udq_config = { { std : : make_shared < UDQConfig > ( UDQConfig : : serializeObject ( ) ) } , 1 } ;
2020-05-06 21:10:52 +02:00
result . m_network = { { std : : make_shared < Network : : ExtNetwork > ( Network : : ExtNetwork : : serializeObject ( ) ) } , 1 } ;
2020-05-06 11:35:22 +02:00
result . m_glo = { { std : : make_shared < GasLiftOpt > ( GasLiftOpt : : serializeObject ( ) ) } , 1 } ;
2020-03-19 15:21:20 +01:00
result . udq_active = { { std : : make_shared < UDQActive > ( UDQActive : : serializeObject ( ) ) } , 1 } ;
result . guide_rate_config = { { std : : make_shared < GuideRateConfig > ( GuideRateConfig : : serializeObject ( ) ) } , 1 } ;
result . gconsale = { { std : : make_shared < GConSale > ( GConSale : : serializeObject ( ) ) } , 1 } ;
result . gconsump = { { std : : make_shared < GConSump > ( GConSump : : serializeObject ( ) ) } , 1 } ;
result . global_whistctl_mode = { { Well : : ProducerCMode : : CRAT } , 1 } ;
result . m_actions = { { std : : make_shared < Action : : Actions > ( Action : : Actions : : serializeObject ( ) ) } , 1 } ;
result . rft_config = RFTConfig : : serializeObject ( ) ;
result . restart_config = RestartConfig : : serializeObject ( ) ;
result . wellgroup_events = { { " test " , Events : : serializeObject ( ) } } ;
2020-11-02 16:11:35 +01:00
result . unit_system = UnitSystem : : newFIELD ( ) ;
2021-01-05 12:16:44 +01:00
result . snapshots = { ScheduleState : : serializeObject ( ) } ;
2020-03-19 15:21:20 +01:00
return result ;
}
2019-12-16 14:27:16 +01:00
2017-06-19 09:45:43 +02:00
std : : time_t Schedule : : getStartTime ( ) const {
return this - > posixStartTime ( ) ;
2016-05-24 16:55:32 +02:00
}
time_t Schedule : : posixStartTime ( ) const {
2017-06-19 09:45:43 +02:00
return m_timeMap . getStartTime ( 0 ) ;
2015-10-02 10:49:23 +02:00
}
2016-09-12 14:28:19 +02:00
time_t Schedule : : posixEndTime ( ) const {
2017-06-19 09:45:43 +02:00
return this - > m_timeMap . getEndTime ( ) ;
2013-11-14 16:08:10 +01:00
}
2018-07-11 13:54:49 +02:00
2020-03-22 21:02:32 +01:00
void Schedule : : handleKeyword ( std : : shared_ptr < const Python > python ,
const std : : string & input_path ,
2020-09-25 12:51:36 +02:00
std : : size_t currentStep ,
2021-01-04 11:34:22 +01:00
const ScheduleBlock & block ,
2018-07-11 13:54:49 +02:00
const DeckKeyword & keyword ,
const ParseContext & parseContext ,
2019-01-03 11:53:32 +01:00
ErrorGuard & errors ,
2018-07-11 13:54:49 +02:00
const EclipseGrid & grid ,
2019-11-21 11:44:06 +01:00
const FieldPropsManager & fp ,
2020-09-25 12:51:36 +02:00
std : : vector < std : : pair < const DeckKeyword * , std : : size_t > > & rftProperties ) {
2018-04-06 15:48:27 +02:00
2021-01-07 09:36:15 +01:00
HandlerContext handlerContext { block , keyword , currentStep , grid , fp } ;
2018-05-14 04:18:07 +02:00
2020-09-21 19:22:11 +02:00
if ( handleNormalKeyword ( handlerContext , parseContext , errors ) )
return ;
2020-08-31 18:24:09 +02:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WRFT " )
rftProperties . push_back ( std : : make_pair ( & keyword , currentStep ) ) ;
2016-01-20 14:58:32 +01:00
2018-07-11 13:54:49 +02:00
else if ( keyword . name ( ) = = " WRFTPLT " )
rftProperties . push_back ( std : : make_pair ( & keyword , currentStep ) ) ;
2015-04-17 18:51:42 +02:00
2020-03-16 16:02:05 +01:00
else if ( keyword . name ( ) = = " PYACTION " )
2020-03-22 21:02:32 +01:00
handlePYACTION ( python , input_path , keyword , currentStep ) ;
2018-07-11 13:54:49 +02:00
}
2017-11-21 09:55:07 +01:00
2020-10-10 08:59:38 +02:00
namespace {
class ScheduleLogger {
public :
explicit ScheduleLogger ( bool restart_skip )
{
if ( restart_skip )
this - > log_function = & OpmLog : : note ;
else
this - > log_function = & OpmLog : : info ;
}
void operator ( ) ( const std : : string & msg ) {
this - > log_function ( msg ) ;
}
void info ( const std : : string & msg ) {
OpmLog : : info ( msg ) ;
}
void complete_step ( const std : : string & msg ) {
this - > step_count + = 1 ;
if ( this - > step_count = = this - > max_print ) {
this - > log_function ( msg ) ;
OpmLog : : info ( " Report limit reached, see PRT-file for remaining Schedule initialization. \n " ) ;
this - > log_function = & OpmLog : : note ;
} else
this - > log_function ( msg + " \n " ) ;
} ;
void restart ( ) {
this - > step_count = 0 ;
this - > log_function = & OpmLog : : info ;
}
private :
std : : size_t step_count = 0 ;
std : : size_t max_print = 5 ;
void ( * log_function ) ( const std : : string & ) ;
} ;
}
2018-04-12 19:02:15 +02:00
2021-01-04 11:34:22 +01:00
void Schedule : : iterateScheduleSection ( std : : shared_ptr < const Opm : : Python > python ,
const std : : string & input_path ,
const ParseContext & parseContext ,
ErrorGuard & errors ,
const EclipseGrid & grid ,
2020-01-13 15:46:06 +01:00
const FieldPropsManager & fp ) {
2020-10-10 08:59:38 +02:00
2020-09-25 12:51:36 +02:00
std : : vector < std : : pair < const DeckKeyword * , std : : size_t > > rftProperties ;
2020-11-02 16:11:35 +01:00
std : : string time_unit = this - > unit_system . name ( UnitSystem : : measure : : time ) ;
2021-01-05 12:16:44 +01:00
auto deck_time = [ this ] ( double seconds ) { return this - > unit_system . from_si ( UnitSystem : : measure : : time , seconds ) ; } ;
2020-10-10 08:59:38 +02:00
std : : string current_file ;
const auto & time_map = this - > m_timeMap ;
2020-03-30 10:38:15 +02:00
/*
The keywords in the skiprest_whitelist set are loaded from the
SCHEDULE section even though the SKIPREST keyword is in action . The
full list includes some additional keywords which we do not support at
all .
*/
std : : unordered_set < std : : string > skiprest_whitelist = { " VFPPROD " , " VFPINJ " , " RPTSCHED " , " RPTRST " , " TUNING " , " MESSAGES " } ;
2020-09-29 22:01:24 +02:00
std : : size_t currentStep = 0 ;
/*
The behavior of variable restart_skip is more lenient than the
SKIPREST keyword . If this is a restarted [ 1 ] run the loop iterating
over keywords will skip the all keywords [ 2 ] until DATES keyword with
the restart date is encountered - irrespective of whether the SKIPREST
keyword is present in the deck or not .
[ 1 ] : opm / flow can restart in a mode where all the keywords from the
historical part of the Schedule section is internalized , and only
the solution fields are read from the restart file . In this case
we will have TimeMap : : restart_offset ( ) = = 0.
[ 2 ] : With the exception of the keywords in the skiprest_whitelist ;
these keywords will be assigned to report step 0.
*/
2020-03-13 07:36:45 +01:00
2020-09-29 22:59:03 +02:00
auto restart_skip = currentStep < this - > m_timeMap . restart_offset ( ) ;
2020-10-10 08:59:38 +02:00
ScheduleLogger logger ( restart_skip ) ;
{
2021-01-04 11:34:22 +01:00
const auto & location = this - > m_sched_deck . location ( ) ;
2020-10-10 08:59:38 +02:00
current_file = location . filename ;
2020-11-02 13:43:13 +01:00
logger . info ( fmt : : format ( " \n Processing dynamic information from \n {} line {} " , current_file , location . lineno ) ) ;
2020-10-10 08:59:38 +02:00
if ( restart_skip )
logger . info ( fmt : : format ( " This is a restarted run - skipping until report step {} at {} " , time_map . restart_offset ( ) , Schedule : : formatDate ( time_map . restart_time ( ) ) ) ) ;
logger ( fmt : : format ( " Initializing report step {}/{} at {} {} {} line {} " ,
currentStep + 1 ,
this - > size ( ) ,
Schedule : : formatDate ( this - > getStartTime ( ) ) ,
2021-01-05 12:16:44 +01:00
deck_time ( time_map . getTimePassedUntil ( currentStep ) ) ,
2020-10-10 08:59:38 +02:00
time_unit ,
location . lineno ) ) ;
}
2020-09-29 22:01:24 +02:00
2021-01-04 11:34:22 +01:00
for ( const auto & block : this - > m_sched_deck ) {
std : : size_t keyword_index = 0 ;
auto time_type = block . time_type ( ) ;
if ( time_type = = ScheduleTimeType : : DATES | | time_type = = ScheduleTimeType : : TSTEP ) {
const auto & start_date = Schedule : : formatDate ( std : : chrono : : system_clock : : to_time_t ( block . start_time ( ) ) ) ;
2021-01-05 12:16:44 +01:00
const auto & days = deck_time ( this - > stepLength ( currentStep - 1 ) ) ;
const auto & days_total = deck_time ( time_map . getTimePassedUntil ( currentStep ) ) ;
2021-01-04 11:34:22 +01:00
logger . complete_step ( fmt : : format ( " Complete report step {0} ({1} {2}) at {3} ({4} {2}) " ,
currentStep ,
days ,
time_unit ,
start_date ,
days_total ) ) ;
logger ( fmt : : format ( " Initializing report step {}/{} at {} ({} {}) - line {} " ,
currentStep + 1 ,
this - > size ( ) ,
start_date ,
days_total ,
time_unit ,
block . location ( ) . lineno ) ) ;
2020-10-10 08:59:38 +02:00
}
2021-01-06 18:11:05 +01:00
if ( time_type ! = ScheduleTimeType : : RESTART )
this - > create_next ( block ) ;
2020-10-10 08:59:38 +02:00
2021-01-04 11:34:22 +01:00
while ( true ) {
if ( keyword_index = = block . size ( ) )
break ;
2020-09-29 22:01:24 +02:00
2021-01-04 11:34:22 +01:00
const auto & keyword = block [ keyword_index ] ;
const auto & location = keyword . location ( ) ;
if ( location . filename ! = current_file ) {
logger ( fmt : : format ( " Reading from: {} line {} " , location . filename , location . lineno ) ) ;
current_file = location . filename ;
2020-09-29 22:59:03 +02:00
}
2020-09-29 22:01:24 +02:00
2021-01-04 11:34:22 +01:00
if ( keyword . name ( ) = = " ACTIONX " ) {
Action : : ActionX action ( keyword , this - > m_timeMap . getStartTime ( currentStep ) ) ;
while ( true ) {
keyword_index + + ;
if ( keyword_index = = block . size ( ) )
throw OpmInputError ( " Missing keyword ENDACTIO " , keyword . location ( ) ) ;
const auto & action_keyword = block [ keyword_index ] ;
if ( action_keyword . name ( ) = = " ENDACTIO " )
break ;
if ( Action : : ActionX : : valid_keyword ( action_keyword . name ( ) ) )
action . addKeyword ( action_keyword ) ;
else {
std : : string msg_fmt = " The keyword {keyword} is not supported in the ACTIONX block \n "
" In {file} line {line}. " ;
parseContext . handleError ( ParseContext : : ACTIONX_ILLEGAL_KEYWORD , msg_fmt , action_keyword . location ( ) , errors ) ;
}
2019-02-03 18:07:04 +01:00
}
2021-01-04 11:34:22 +01:00
this - > addACTIONX ( action , currentStep ) ;
keyword_index + + ;
continue ;
2015-10-30 12:55:17 +01:00
}
2021-01-04 11:34:22 +01:00
logger ( fmt : : format ( " Processing keyword {} at line {} " , location . keyword , location . lineno ) ) ;
this - > handleKeyword ( python ,
input_path ,
currentStep ,
block ,
keyword ,
parseContext ,
errors ,
grid ,
fp ,
rftProperties ) ;
keyword_index + + ;
2020-01-28 20:31:24 +01:00
}
2021-01-05 12:16:44 +01:00
2021-01-04 11:34:22 +01:00
checkIfAllConnectionsIsShut ( currentStep ) ;
currentStep + = 1 ;
2013-11-05 15:25:47 +01:00
}
2015-01-16 14:51:57 +01:00
2020-09-29 22:01:24 +02: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 ;
2020-09-25 12:51:36 +02:00
std : : size_t timeStep = rftPair - > second ;
2019-04-03 18:47:02 +02:00
if ( keyword . name ( ) = = " WRFT " )
2020-09-21 19:22:11 +02:00
applyWRFT ( keyword , timeStep ) ;
2015-02-06 14:54:03 +01:00
2019-04-03 18:47:02 +02:00
if ( keyword . name ( ) = = " WRFTPLT " )
2020-09-21 19:22:11 +02:00
applyWRFTPLT ( keyword , timeStep ) ;
2015-02-06 14:54:03 +01:00
}
2013-11-05 15:25:47 +01:00
}
2019-08-29 18:17:37 +02:00
void Schedule : : addACTIONX ( const Action : : ActionX & action , std : : size_t currentStep ) {
auto new_actions = std : : make_shared < Action : : Actions > ( this - > actions ( currentStep ) ) ;
new_actions - > add ( action ) ;
this - > m_actions . update ( currentStep , new_actions ) ;
}
2020-09-21 19:22:11 +02:00
void Schedule : : handlePYACTION ( std : : shared_ptr < const Python > python , const std : : string & input_path , const DeckKeyword & keyword , std : : size_t currentStep ) {
2020-03-22 21:02:32 +01:00
if ( ! python - > enabled ( ) ) {
//Must have a real Python instance here - to ensure that IMPORT works
2020-03-16 16:02:05 +01:00
const auto & loc = keyword . location ( ) ;
OpmLog : : warning ( " This version of flow is built without support for Python. Keyword PYACTION in file: " + loc . filename + " line: " + std : : to_string ( loc . lineno ) + " is ignored. " ) ;
return ;
}
2020-09-25 10:26:17 +02:00
const auto & name = keyword . getRecord ( 0 ) . getItem < ParserKeywords : : PYACTION : : NAME > ( ) . get < std : : string > ( 0 ) ;
const auto & run_count = Action : : PyAction : : from_string ( keyword . getRecord ( 0 ) . getItem < ParserKeywords : : PYACTION : : RUN_COUNT > ( ) . get < std : : string > ( 0 ) ) ;
const auto & module_arg = keyword . getRecord ( 1 ) . getItem < ParserKeywords : : PYACTION : : FILENAME > ( ) . get < std : : string > ( 0 ) ;
2020-03-22 21:02:32 +01:00
std : : string module ;
if ( input_path . empty ( ) )
module = module_arg ;
else
module = input_path + " / " + module_arg ;
2020-03-16 16:02:05 +01:00
2020-03-22 21:02:32 +01:00
Action : : PyAction pyaction ( python , name , run_count , module ) ;
2020-03-16 16:02:05 +01:00
auto new_actions = std : : make_shared < Action : : Actions > ( this - > actions ( currentStep ) ) ;
new_actions - > add ( pyaction ) ;
this - > m_actions . update ( currentStep , new_actions ) ;
}
2020-09-25 10:12:55 +02:00
void Schedule : : applyEXIT ( const DeckKeyword & keyword , std : : size_t report_step ) {
2020-09-25 10:26:17 +02:00
int status = keyword . getRecord ( 0 ) . getItem < ParserKeywords : : EXIT : : STATUS_CODE > ( ) . get < int > ( 0 ) ;
2020-04-12 09:30:23 +02:00
OpmLog : : info ( " Simulation exit with status: " + std : : to_string ( status ) + " requested as part of ACTIONX at report_step: " + std : : to_string ( report_step ) ) ;
this - > exit_status = status ;
}
2020-01-08 10:17:52 +01:00
void Schedule : : shut_well ( const std : : string & well_name , std : : size_t report_step ) {
2020-12-08 09:20:44 +01:00
this - > updateWellStatus ( well_name , report_step , true , Well : : Status : : SHUT ) ;
2020-01-08 10:17:52 +01:00
}
void Schedule : : open_well ( const std : : string & well_name , std : : size_t report_step ) {
2020-12-08 09:20:44 +01:00
this - > updateWellStatus ( well_name , report_step , true , Well : : Status : : OPEN ) ;
2020-01-08 10:17:52 +01:00
}
void Schedule : : stop_well ( const std : : string & well_name , std : : size_t report_step ) {
2020-12-08 09:20:44 +01:00
this - > updateWellStatus ( well_name , report_step , true , Well : : Status : : STOP ) ;
2020-01-08 10:17:52 +01:00
}
2020-09-25 12:51:36 +02:00
void Schedule : : updateWell ( std : : shared_ptr < Well > well , std : : size_t reportStep ) {
2019-03-23 16:11:37 +01:00
auto & dynamic_state = this - > wells_static . at ( well - > name ( ) ) ;
2020-12-04 16:04:40 +01:00
dynamic_state . update_equal ( reportStep , std : : move ( well ) ) ;
2015-06-23 14:20:31 +02:00
}
2019-03-23 16:11:37 +01:00
/*
Function is quite dangerous - because if this is called while holding a
2019-11-12 08:29:28 +01:00
Well pointer that will go stale and needs to be refreshed .
2019-03-23 16:11:37 +01:00
*/
2020-12-08 09:20:44 +01:00
bool Schedule : : updateWellStatus ( const std : : string & well_name , std : : size_t reportStep , bool runtime , Well : : Status status , std : : optional < KeywordLocation > location ) {
2020-01-08 10:18:31 +01:00
auto & dynamic_state = this - > wells_static . at ( well_name ) ;
auto well2 = std : : make_shared < Well > ( * dynamic_state [ reportStep ] ) ;
2020-11-17 10:17:45 +01:00
if ( well2 - > getConnections ( ) . empty ( ) & & status = = Well : : Status : : OPEN ) {
if ( location ) {
auto msg = fmt : : format ( " Problem with{} \n " ,
" In {} line{} \n "
" Well {} has no connections to grid and will remain SHUT " , location - > keyword , location - > filename , location - > lineno , well_name ) ;
OpmLog : : warning ( msg ) ;
} else
OpmLog : : warning ( fmt : : format ( " Well {} has no connections to grid and will remain SHUT " , well_name ) ) ;
return false ;
}
2020-12-04 16:04:40 +01:00
auto old_status = well2 - > getStatus ( ) ;
2020-11-17 10:17:45 +01:00
bool update = false ;
2020-12-08 09:20:44 +01:00
if ( well2 - > updateStatus ( status , reportStep , runtime ) ) {
2020-01-08 10:18:31 +01:00
this - > updateWell ( well2 , reportStep ) ;
if ( status = = Well : : Status : : OPEN )
this - > rft_config . addWellOpen ( well_name , reportStep ) ;
2020-12-04 16:04:40 +01:00
/*
The Well : : updateStatus ( ) will always return true because a new
WellStatus object should be created . But the new object might have
the same value as the previous object ; therefor we need to check
for an actual status change before we emit a WELL_STATUS_CHANGE
event .
*/
if ( old_status ! = status ) {
this - > m_events . addEvent ( ScheduleEvents : : WELL_STATUS_CHANGE , reportStep ) ;
this - > addWellGroupEvent ( well2 - > name ( ) , ScheduleEvents : : WELL_STATUS_CHANGE , reportStep ) ;
}
update = true ;
2019-03-23 16:11:37 +01:00
}
return update ;
2013-11-08 15:55:11 +01:00
}
2020-11-11 11:11:44 +01:00
bool Schedule : : updateWPAVE ( const std : : string & wname , std : : size_t report_step , const PAvg & pavg ) {
const auto & well = this - > getWell ( wname , report_step ) ;
if ( well . pavg ( ) ! = pavg ) {
auto & dynamic_state = this - > wells_static . at ( wname ) ;
auto new_well = std : : make_shared < Well > ( * dynamic_state [ report_step ] ) ;
new_well - > updateWPAVE ( pavg ) ;
this - > updateWell ( new_well , report_step ) ;
return true ;
}
return false ;
}
2020-09-16 16:06:02 +02:00
/*
This routine is called when UDQ keywords is added in an ACTIONX block .
*/
void Schedule : : updateUDQ ( const DeckKeyword & keyword , std : : size_t current_step ) {
const auto & current = * this - > udq_config . get ( current_step ) ;
std : : shared_ptr < UDQConfig > new_udq = std : : make_shared < UDQConfig > ( current ) ;
for ( const auto & record : keyword )
2020-09-24 07:59:19 +02:00
new_udq - > add_record ( record , keyword . location ( ) , current_step ) ;
2020-09-16 16:06:02 +02:00
auto next_index = this - > udq_config . update_equal ( current_step , new_udq ) ;
if ( next_index ) {
for ( const auto & [ report_step , udq_ptr ] : this - > udq_config . unique ( ) ) {
if ( report_step > current_step ) {
for ( const auto & record : keyword )
2020-09-24 07:59:19 +02:00
udq_ptr - > add_record ( record , keyword . location ( ) , current_step ) ;
2020-09-16 16:06:02 +02:00
}
}
}
}
2019-01-28 16:52:28 +01:00
2020-12-04 16:04:40 +01:00
void Schedule : : applyWELOPEN ( const DeckKeyword & keyword , std : : size_t currentStep , bool runtime , const ParseContext & parseContext , ErrorGuard & errors , const std : : vector < std : : string > & matching_wells ) {
2015-06-02 13:26:37 +02:00
2019-04-03 18:47:02 +02:00
auto conn_defaulted = [ ] ( const DeckRecord & rec ) {
2016-12-01 13:44:38 +01:00
auto defaulted = [ ] ( const DeckItem & item ) {
return item . defaultApplied ( 0 ) ;
} ;
2015-01-13 15:06:06 +01:00
2016-12-01 13:44:38 +01:00
return std : : all_of ( rec . begin ( ) + 2 , rec . end ( ) , defaulted ) ;
} ;
2015-06-23 14:20:31 +02:00
2019-11-12 08:29:28 +01:00
constexpr auto open = Well : : Status : : OPEN ;
2015-01-16 17:49:28 +01:00
2020-09-25 11:29:13 +02:00
for ( const auto & record : keyword ) {
2018-05-03 09:18:53 +02:00
const auto & wellNamePattern = record . getItem ( " WELL " ) . getTrimmedString ( 0 ) ;
2016-12-01 13:44:38 +01:00
const auto & status_str = record . getItem ( " STATUS " ) . getTrimmedString ( 0 ) ;
2019-03-23 16:11:37 +01:00
const auto well_names = this - > wellNames ( wellNamePattern , currentStep , matching_wells ) ;
2019-03-23 16:51:32 +01:00
if ( well_names . empty ( ) )
2020-02-14 15:06:28 +01:00
invalidNamePattern ( wellNamePattern , currentStep , parseContext , errors , keyword ) ;
2018-05-03 09:18:53 +02:00
2016-12-01 13:44:38 +01:00
/* if all records are defaulted or just the status is set, only
* well status is updated
*/
2020-09-25 11:29:13 +02:00
if ( conn_defaulted ( record ) ) {
2019-11-12 08:29:28 +01:00
const auto well_status = Well : : StatusFromString ( status_str ) ;
2019-03-23 16:11:37 +01:00
for ( const auto & wname : well_names ) {
2020-09-25 11:54:25 +02:00
{
const auto & well = this - > getWell ( wname , currentStep ) ;
if ( well_status = = open & & ! well . canOpen ( ) ) {
auto days = m_timeMap . getTimePassedUntil ( currentStep ) / ( 60 * 60 * 24 ) ;
std : : string msg = " Well " + wname
+ " where crossflow is banned has zero total rate. "
+ " This well is prevented from opening at "
+ std : : to_string ( days ) + " days " ;
OpmLog : : note ( msg ) ;
} else {
2020-12-08 09:20:44 +01:00
this - > updateWellStatus ( wname , currentStep , runtime , well_status ) ;
2020-09-25 11:54:25 +02:00
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 ;
}
2020-12-08 09:20:44 +01:00
/*
Some of the connection information has been entered , in this case
we * only * update the status of the connections , and not the well
itself . Unless all connections are shut - then the well is also
shut .
*/
2019-03-23 16:11:37 +01:00
for ( const auto & wname : well_names ) {
2020-12-08 09:20:44 +01:00
if ( ! runtime ) {
auto & dynamic_state = this - > wells_static . at ( wname ) ;
auto well_ptr = std : : make_shared < Well > ( * dynamic_state [ currentStep ] ) ;
well_ptr - > commitStatus ( currentStep ) ;
this - > updateWell ( well_ptr , currentStep ) ;
}
const auto connection_status = Connection : : StateFromString ( status_str ) ;
2020-09-25 11:54:25 +02:00
{
auto & dynamic_state = this - > wells_static . at ( wname ) ;
auto well_ptr = std : : make_shared < Well > ( * dynamic_state [ currentStep ] ) ;
2020-12-08 09:20:44 +01:00
if ( well_ptr - > handleWELOPENConnections ( record , currentStep , connection_status , runtime ) ) {
auto [ first_step , last_step ] = well_ptr - > statusRange ( ) ;
if ( last_step )
dynamic_state . update_range ( first_step , * last_step , std : : move ( well_ptr ) ) ;
else
dynamic_state . update ( first_step , std : : move ( well_ptr ) ) ;
}
2019-03-23 16:11:37 +01:00
}
2020-09-25 11:19:31 +02:00
2016-12-01 13:44:38 +01:00
m_events . addEvent ( ScheduleEvents : : COMPLETION_CHANGE , currentStep ) ;
2015-03-25 08:20:22 +01:00
}
}
}
2020-09-21 19:22:11 +02:00
void Schedule : : applyMESSAGES ( const DeckKeyword & keyword , std : : size_t currentStep ) {
2016-10-14 10:06:35 +08:00
const auto & record = keyword . getRecord ( 0 ) ;
2016-10-21 16:38:39 +02:00
using set_limit_fptr = decltype ( std : : mem_fn ( & MessageLimits : : setMessagePrintLimit ) ) ;
2016-10-24 17:06:50 +02:00
static const std : : pair < std : : string , set_limit_fptr > setters [ ] = {
2020-09-21 19:22:11 +02:00
{ " MESSAGE_PRINT_LIMIT " , std : : mem_fn ( & MessageLimits : : setMessagePrintLimit ) } ,
{ " COMMENT_PRINT_LIMIT " , std : : mem_fn ( & MessageLimits : : setCommentPrintLimit ) } ,
{ " WARNING_PRINT_LIMIT " , std : : mem_fn ( & MessageLimits : : setWarningPrintLimit ) } ,
{ " PROBLEM_PRINT_LIMIT " , std : : mem_fn ( & MessageLimits : : setProblemPrintLimit ) } ,
{ " ERROR_PRINT_LIMIT " , std : : mem_fn ( & MessageLimits : : setErrorPrintLimit ) } ,
{ " BUG_PRINT_LIMIT " , std : : mem_fn ( & MessageLimits : : setBugPrintLimit ) } ,
{ " MESSAGE_STOP_LIMIT " , std : : mem_fn ( & MessageLimits : : setMessageStopLimit ) } ,
{ " COMMENT_STOP_LIMIT " , std : : mem_fn ( & MessageLimits : : setCommentStopLimit ) } ,
{ " WARNING_STOP_LIMIT " , std : : mem_fn ( & MessageLimits : : setWarningStopLimit ) } ,
{ " PROBLEM_STOP_LIMIT " , std : : mem_fn ( & MessageLimits : : setProblemStopLimit ) } ,
{ " ERROR_STOP_LIMIT " , std : : mem_fn ( & MessageLimits : : setErrorStopLimit ) } ,
{ " BUG_STOP_LIMIT " , std : : mem_fn ( & MessageLimits : : setBugStopLimit ) } ,
} ;
2016-10-21 16:38:39 +02:00
for ( const auto & pair : setters ) {
const auto & item = record . getItem ( pair . first ) ;
if ( ! item . defaultApplied ( 0 ) ) {
2016-10-24 17:06:50 +02:00
const set_limit_fptr & fptr = pair . second ;
2016-10-21 16:38:39 +02:00
int value = item . get < int > ( 0 ) ;
fptr ( this - > m_messageLimits , currentStep , value ) ;
}
}
2016-10-14 10:06:35 +08:00
}
2020-09-21 19:22:11 +02:00
void Schedule : : applyWRFT ( const DeckKeyword & keyword , std : : size_t currentStep ) {
2015-02-12 08:38:26 +01:00
/* Rule for handling RFT: Request current RFT data output for specified wells, plus output when
* any well is subsequently opened
*/
2015-02-06 14:54:03 +01:00
2020-09-25 11:29:13 +02: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 ) ;
2020-09-25 11:29:13 +02:00
for ( const auto & well_name : well_names )
2019-08-31 09:44:31 +02:00
this - > rft_config . updateRFT ( well_name , currentStep , RFTConfig : : RFT : : YES ) ;
2019-04-10 07:44:45 +02:00
2015-02-06 14:54:03 +01:00
}
2019-04-03 18:47:02 +02:00
this - > rft_config . setWellOpenRFT ( currentStep ) ;
2015-02-06 14:54:03 +01:00
}
2020-09-21 19:22:11 +02:00
void Schedule : : applyWRFTPLT ( const DeckKeyword & keyword , std : : size_t currentStep ) {
2020-09-25 11:29:13 +02:00
for ( const auto & record : keyword ) {
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
2019-08-31 09:44:31 +02:00
RFTConfig : : RFT RFTKey = RFTConfig : : RFTFromString ( record . getItem ( " OUTPUT_RFT " ) . getTrimmedString ( 0 ) ) ;
RFTConfig : : PLT PLTKey = RFTConfig : : PLTFromString ( record . getItem ( " OUTPUT_PLT " ) . getTrimmedString ( 0 ) ) ;
2019-03-23 16:51:32 +01:00
const auto well_names = wellNames ( wellNamePattern , currentStep ) ;
2020-09-25 11:29:13 +02:00
for ( const auto & well_name : well_names ) {
2019-04-03 18:47:02 +02:00
this - > rft_config . updateRFT ( well_name , currentStep , RFTKey ) ;
this - > rft_config . updatePLT ( well_name , currentStep , PLTKey ) ;
2015-02-06 14:54:03 +01:00
}
}
}
2013-11-14 16:08:10 +01:00
2019-04-03 18:47:02 +02:00
const RFTConfig & Schedule : : rftConfig ( ) const {
return this - > rft_config ;
}
2020-09-27 22:13:30 +02:00
2020-10-14 08:15:07 +02:00
void Schedule : : invalidNamePattern ( const std : : string & namePattern , std : : size_t , const ParseContext & parseContext , ErrorGuard & errors , const DeckKeyword & keyword ) const {
std : : string msg_fmt = fmt : : format ( " No wells/groups match the pattern: \' {} \' " , namePattern ) ;
2020-09-27 22:13:30 +02:00
parseContext . handleError ( ParseContext : : SCHEDULE_INVALID_NAME , msg_fmt , keyword . location ( ) , errors ) ;
2018-04-22 10:25:17 +02:00
}
2016-10-12 12:26:14 +02:00
const TimeMap & Schedule : : getTimeMap ( ) const {
2016-11-08 18:29:52 +01:00
return this - > m_timeMap ;
2013-10-25 17:28:56 +02:00
}
2020-05-07 17:25:11 +02:00
GTNode Schedule : : groupTree ( const std : : string & root_node , std : : size_t report_step , std : : size_t level , const std : : optional < std : : string > & parent_name ) const {
2019-11-12 08:29:28 +01:00
auto root_group = this - > getGroup ( root_node , report_step ) ;
2020-05-07 17:25:11 +02:00
GTNode tree ( root_group , level , parent_name ) ;
2019-07-25 11:46:15 +02:00
for ( const auto & wname : root_group . wells ( ) ) {
2019-11-12 08:29:28 +01:00
const auto & well = this - > getWell ( wname , report_step ) ;
2019-07-25 11:46:15 +02:00
tree . add_well ( well ) ;
}
for ( const auto & gname : root_group . groups ( ) ) {
2020-05-07 17:25:11 +02:00
auto child_group = this - > groupTree ( gname , report_step , level + 1 , root_node ) ;
2019-07-25 11:46:15 +02:00
tree . add_group ( child_group ) ;
}
return tree ;
}
GTNode Schedule : : groupTree ( const std : : string & root_node , std : : size_t report_step ) const {
2020-05-07 17:25:11 +02:00
return this - > groupTree ( root_node , report_step , 0 , { } ) ;
2019-07-25 11:46:15 +02:00
}
GTNode Schedule : : groupTree ( std : : size_t report_step ) const {
return this - > groupTree ( " FIELD " , report_step ) ;
}
2019-06-08 12:25:29 +02:00
void Schedule : : addWell ( const std : : string & wellName ,
const DeckRecord & record ,
2020-09-25 12:51:36 +02:00
std : : size_t timeStep ,
2020-11-02 16:11:35 +01:00
Connection : : Order wellConnectionOrder )
2020-01-30 10:37:57 +01:00
{
2014-01-29 11:48:02 +01:00
// We change from eclipse's 1 - n, to a 0 - n-1 solution
2016-02-09 12:09:40 +01:00
int headI = record . getItem ( " HEAD_I " ) . get < int > ( 0 ) - 1 ;
int headJ = record . getItem ( " HEAD_J " ) . get < int > ( 0 ) - 1 ;
2018-12-20 12:10:14 +01:00
Phase preferredPhase ;
2020-01-30 10:37:57 +01:00
{
const std : : string phaseStr = record . getItem ( " PHASE " ) . getTrimmedString ( 0 ) ;
if ( phaseStr = = " LIQ " ) {
// We need a workaround in case the preferred phase is "LIQ",
// which is not proper phase and will cause the get_phase()
// function to throw. In that case we choose to treat it as OIL.
preferredPhase = Phase : : OIL ;
OpmLog : : warning ( " LIQ_PREFERRED_PHASE " ,
" LIQ preferred phase not supported for well " + wellName + " , using OIL instead " ) ;
2020-09-25 15:10:23 +02:00
} else {
2020-01-30 10:37:57 +01:00
preferredPhase = get_phase ( phaseStr ) ;
2020-09-25 15:10:23 +02:00
}
2018-12-20 12:10:14 +01:00
}
2016-02-09 12:09:40 +01:00
const auto & refDepthItem = record . getItem ( " REF_DEPTH " ) ;
2020-10-22 17:04:40 +02:00
std : : optional < double > ref_depth ;
if ( refDepthItem . hasValue ( 0 ) )
ref_depth = refDepthItem . getSIDouble ( 0 ) ;
2014-08-25 11:20:54 +02:00
2018-11-02 15:21:28 +01:00
double drainageRadius = record . getItem ( " D_RADIUS " ) . getSIDouble ( 0 ) ;
2015-10-06 15:47:07 +02:00
bool allowCrossFlow = true ;
2016-02-09 12:09:40 +01:00
const std : : string & allowCrossFlowStr = record . getItem < ParserKeywords : : WELSPECS : : CROSSFLOW > ( ) . getTrimmedString ( 0 ) ;
2015-10-06 15:47:07 +02:00
if ( allowCrossFlowStr = = " NO " )
allowCrossFlow = false ;
2016-06-29 14:11:11 +02:00
bool automaticShutIn = true ;
const std : : string & automaticShutInStr = record . getItem < ParserKeywords : : WELSPECS : : AUTO_SHUTIN > ( ) . getTrimmedString ( 0 ) ;
if ( automaticShutInStr = = " STOP " ) {
automaticShutIn = false ;
}
2020-01-30 10:37:57 +01:00
const std : : string & group = record . getItem < ParserKeywords : : WELSPECS : : GROUP > ( ) . getTrimmedString ( 0 ) ;
2020-09-25 10:26:17 +02:00
auto pvt_table = record . getItem < ParserKeywords : : WELSPECS : : P_TABLE > ( ) . get < int > ( 0 ) ;
auto gas_inflow = Well : : GasInflowEquationFromString ( record . getItem < ParserKeywords : : WELSPECS : : INFLOW_EQ > ( ) . get < std : : string > ( 0 ) ) ;
2020-01-30 10:37:57 +01:00
this - > addWell ( wellName ,
group ,
headI ,
headJ ,
preferredPhase ,
2020-10-22 17:04:40 +02:00
ref_depth ,
2020-01-30 10:37:57 +01:00
drainageRadius ,
allowCrossFlow ,
automaticShutIn ,
2020-04-15 10:45:32 +02:00
pvt_table ,
2020-04-19 08:37:48 +02:00
gas_inflow ,
2020-01-30 10:37:57 +01:00
timeStep ,
2020-11-02 16:11:35 +01:00
wellConnectionOrder ) ;
2020-01-30 10:37:57 +01:00
}
2020-09-25 12:51:36 +02:00
void Schedule : : addWell ( Well well , std : : size_t report_step ) {
2020-02-14 14:18:22 +01:00
const std : : string wname = well . name ( ) ;
m_events . addEvent ( ScheduleEvents : : NEW_WELL , report_step ) ;
2020-12-04 16:04:40 +01:00
this - > wellgroup_events . insert ( std : : make_pair ( wname , Events ( this - > m_timeMap ) ) ) ;
2020-02-14 14:18:22 +01:00
this - > addWellGroupEvent ( wname , ScheduleEvents : : NEW_WELL , report_step ) ;
well . setInsertIndex ( this - > wells_static . size ( ) ) ;
this - > wells_static . insert ( std : : make_pair ( wname , DynamicState < std : : shared_ptr < Well > > ( m_timeMap , nullptr ) ) ) ;
auto & dynamic_well_state = this - > wells_static . at ( wname ) ;
dynamic_well_state . update ( report_step , std : : make_shared < Well > ( std : : move ( well ) ) ) ;
}
2020-01-30 10:37:57 +01:00
void Schedule : : addWell ( const std : : string & wellName ,
const std : : string & group ,
int headI ,
int headJ ,
Phase preferredPhase ,
2020-10-22 17:04:40 +02:00
const std : : optional < double > & ref_depth ,
2020-01-30 10:37:57 +01:00
double drainageRadius ,
bool allowCrossFlow ,
bool automaticShutIn ,
2020-04-15 10:45:32 +02:00
int pvt_table ,
2020-04-19 08:37:48 +02:00
Well : : GasInflowEquation gas_inflow ,
2020-09-25 12:51:36 +02:00
std : : size_t timeStep ,
2020-11-02 16:11:35 +01:00
Connection : : Order wellConnectionOrder ) {
2020-01-30 10:37:57 +01:00
2020-02-14 14:18:22 +01:00
Well well ( wellName ,
group ,
timeStep ,
0 ,
headI , headJ ,
2020-10-22 17:04:40 +02:00
ref_depth ,
2020-03-03 10:52:08 +01:00
WellType ( preferredPhase ) ,
2020-02-14 14:18:22 +01:00
this - > global_whistctl_mode [ timeStep ] ,
wellConnectionOrder ,
2020-11-02 16:11:35 +01:00
this - > unit_system ,
2020-02-14 14:18:22 +01:00
this - > getUDQConfig ( timeStep ) . params ( ) . undefinedValue ( ) ,
drainageRadius ,
allowCrossFlow ,
2020-04-15 10:45:32 +02:00
automaticShutIn ,
2020-04-19 08:37:48 +02:00
pvt_table ,
gas_inflow ) ;
2020-02-14 14:18:22 +01:00
this - > addWell ( std : : move ( well ) , timeStep ) ;
2020-11-11 11:11:44 +01:00
2021-01-05 12:16:44 +01:00
const auto & ts = this - > operator [ ] ( timeStep ) ;
this - > updateWPAVE ( wellName , timeStep , ts . pavg ( ) ) ;
2013-11-05 17:58:57 +01:00
}
2020-01-30 10:37:57 +01:00
2020-09-25 12:51:36 +02:00
std : : 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
}
2020-09-25 12:51:36 +02:00
std : : size_t Schedule : : numWells ( std : : size_t timestep ) const {
2019-03-23 16:11:37 +01:00
auto well_names = this - > wellNames ( timestep ) ;
return well_names . size ( ) ;
2014-12-05 12:59:53 +01:00
}
2013-11-05 15:25:47 +01:00
bool Schedule : : hasWell ( const std : : string & wellName ) const {
2019-05-04 12:00:32 +02:00
return wells_static . count ( wellName ) > 0 ;
2015-02-12 12:54:57 +01:00
}
2019-05-04 12:00:32 +02:00
bool Schedule : : hasWell ( const std : : string & wellName , std : : size_t timeStep ) const {
if ( this - > wells_static . count ( wellName ) = = 0 )
return false ;
2017-07-25 19:50:06 +02:00
2019-11-12 08:29:28 +01:00
const auto & well = this - > getWellatEnd ( wellName ) ;
2019-05-04 12:00:32 +02:00
return well . hasBeenDefined ( timeStep ) ;
2017-07-25 19:50:06 +02:00
}
2020-09-25 12:51:36 +02:00
std : : vector < const Group * > Schedule : : getChildGroups2 ( const std : : string & group_name , std : : size_t timeStep ) const {
2019-03-23 16:11:37 +01:00
if ( ! hasGroup ( group_name ) )
2019-07-25 11:46:15 +02:00
throw std : : invalid_argument ( " No such group: ' " + group_name + " ' " ) ;
2019-03-23 16:11:37 +01:00
2020-09-25 11:55:03 +02:00
const auto & group = getGroup ( group_name , timeStep ) ;
std : : vector < const Group * > child_groups ;
if ( group . defined ( timeStep ) ) {
for ( const auto & child_name : group . groups ( ) ) {
child_groups . push_back ( std : : addressof ( this - > getGroup ( child_name , timeStep ) ) ) ;
2019-03-23 16:11:37 +01:00
}
}
2020-09-25 11:55:03 +02:00
return child_groups ;
2019-03-23 16:11:37 +01:00
}
2020-09-25 12:51:36 +02:00
std : : vector < Well > Schedule : : getChildWells2 ( const std : : string & group_name , std : : 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 + " ' " ) ;
2020-09-25 11:55:03 +02:00
const auto & dynamic_state = this - > groups . at ( group_name ) ;
const auto & group_ptr = dynamic_state . get ( timeStep ) ;
if ( group_ptr ) {
std : : vector < Well > wells ;
if ( group_ptr - > groups ( ) . size ( ) ) {
for ( const auto & child_name : group_ptr - > groups ( ) ) {
const auto & child_wells = getChildWells2 ( child_name , timeStep ) ;
wells . insert ( wells . end ( ) , child_wells . begin ( ) , child_wells . end ( ) ) ;
}
} else {
for ( const auto & well_name : group_ptr - > wells ( ) ) {
wells . push_back ( this - > getWell ( well_name , timeStep ) ) ;
2018-04-25 09:44:57 +02:00
}
2020-09-25 11:55:03 +02:00
}
2019-08-06 22:40:14 +02:00
2020-09-25 11:55:03 +02:00
return wells ;
} else {
return { } ;
2018-04-25 09:44:57 +02:00
}
}
2020-04-21 10:40:34 +02:00
/*
This function will return a list of wells which have changed
* structurally * in the last report_step ; wells where only production
settings have changed will not be included .
*/
std : : vector < std : : string > Schedule : : changed_wells ( std : : size_t report_step ) const {
std : : vector < std : : string > wells ;
for ( const auto & dynamic_pair : this - > wells_static ) {
const auto & well_ptr = dynamic_pair . second . get ( report_step ) ;
if ( well_ptr ) {
if ( report_step > 0 ) {
const auto & prev = dynamic_pair . second . get ( report_step - 1 ) ;
if ( prev ) {
if ( ! well_ptr - > cmp_structure ( * prev ) )
wells . push_back ( well_ptr - > name ( ) ) ;
2020-09-25 15:10:23 +02:00
} else {
2020-04-21 10:40:34 +02:00
wells . push_back ( well_ptr - > name ( ) ) ;
2020-09-25 15:10:23 +02:00
}
} else {
2020-04-21 10:40:34 +02:00
wells . push_back ( well_ptr - > name ( ) ) ;
2020-09-25 15:10:23 +02:00
}
2020-04-21 10:40:34 +02:00
}
}
return wells ;
}
2019-01-28 09:52:11 +01:00
2019-08-06 22:40:14 +02:00
2020-09-25 12:51:36 +02:00
std : : vector < Well > Schedule : : getWells ( std : : size_t timeStep ) const {
2019-11-12 08:29:28 +01:00
std : : vector < Well > wells ;
2019-05-04 12:00:32 +02:00
if ( timeStep > = this - > m_timeMap . size ( ) )
throw std : : invalid_argument ( " timeStep argument beyond the length of the simulation " ) ;
2016-06-16 08:37:10 +02:00
2019-05-04 12:00:32 +02:00
for ( const auto & dynamic_pair : this - > wells_static ) {
auto & well_ptr = dynamic_pair . second . get ( timeStep ) ;
if ( well_ptr )
wells . push_back ( * well_ptr . get ( ) ) ;
2015-02-12 12:54:57 +01:00
}
2016-06-16 08:37:10 +02:00
return wells ;
2015-02-12 15:36:39 +01:00
}
2019-11-12 08:29:28 +01:00
std : : vector < Well > Schedule : : getWellsatEnd ( ) const {
return this - > getWells ( this - > m_timeMap . size ( ) - 1 ) ;
2019-05-04 12:00:32 +02:00
}
2019-11-12 08:29:28 +01:00
const Well & Schedule : : getWellatEnd ( const std : : string & well_name ) const {
return this - > getWell ( well_name , this - > m_timeMap . size ( ) - 1 ) ;
2016-03-29 14:13:54 +02:00
}
2020-09-25 12:51:36 +02:00
const Well & Schedule : : getWell ( const std : : string & wellName , std : : size_t timeStep ) const {
2019-03-23 16:11:37 +01:00
if ( this - > wells_static . count ( wellName ) = = 0 )
throw std : : invalid_argument ( " No such well: " + wellName ) ;
const auto & dynamic_state = this - > wells_static . at ( wellName ) ;
auto & well_ptr = dynamic_state . get ( timeStep ) ;
if ( ! well_ptr )
throw std : : invalid_argument ( " Well: " + wellName + " not yet defined at step: " + std : : to_string ( timeStep ) ) ;
return * well_ptr ;
}
2015-05-28 14:55:09 +02:00
2020-09-25 12:51:36 +02:00
const Group & Schedule : : getGroup ( const std : : string & groupName , std : : size_t timeStep ) const {
2019-07-24 08:38:39 +02:00
if ( this - > groups . count ( groupName ) = = 0 )
2019-07-25 11:46:15 +02:00
throw std : : invalid_argument ( " No such group: ' " + groupName + " ' " ) ;
2019-07-24 08:38:39 +02:00
const auto & dynamic_state = this - > groups . at ( groupName ) ;
auto & group_ptr = dynamic_state . get ( timeStep ) ;
if ( ! group_ptr )
throw std : : invalid_argument ( " Group: " + groupName + " not yet defined at step: " + std : : to_string ( timeStep ) ) ;
return * group_ptr ;
}
2020-09-25 12:51:36 +02:00
void Schedule : : updateGroup ( std : : shared_ptr < Group > group , std : : size_t reportStep ) {
2019-07-24 08:38:39 +02:00
auto & dynamic_state = this - > groups . at ( group - > name ( ) ) ;
2019-07-30 17:47:19 +02:00
dynamic_state . update ( reportStep , std : : move ( group ) ) ;
2019-07-24 08:38:39 +02:00
}
2019-03-14 09:23:03 +01:00
2020-10-13 08:10:36 +02:00
void Schedule : : updateGuideRateModel ( const GuideRateModel & new_model , std : : size_t report_step ) {
auto new_config = std : : make_shared < GuideRateConfig > ( this - > guideRateConfig ( report_step ) ) ;
if ( new_config - > update_model ( new_model ) )
this - > guide_rate_config . update ( report_step , new_config ) ;
}
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 !
*/
2020-09-25 12:51:36 +02:00
std : : vector < std : : string > Schedule : : wellNames ( const std : : string & pattern , std : : size_t timeStep , const std : : vector < std : : string > & matching_wells ) const {
2019-03-14 09:23:03 +01:00
// 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 ( ) } ;
2020-10-30 22:17:28 +01:00
auto wm = this - > wellMatcher ( timeStep ) ;
return wm . wells ( pattern ) ;
2019-03-14 09:23:03 +01:00
}
2020-10-30 13:36:41 +01:00
WellMatcher Schedule : : wellMatcher ( std : : size_t report_step ) const {
std : : vector < std : : string > wnames ;
for ( const auto & well_pair : this - > wells_static ) {
const auto & dynamic_state = well_pair . second ;
if ( dynamic_state . get ( report_step ) )
wnames . push_back ( well_pair . first ) ;
2019-03-14 09:23:03 +01:00
}
2020-10-30 13:36:41 +01:00
return WellMatcher ( wnames , this - > getWListManager ( report_step ) ) ;
2019-03-14 09:23:03 +01:00
}
2020-10-30 13:36:41 +01:00
2019-03-24 07:53:30 +01:00
std : : vector < std : : string > Schedule : : wellNames ( const std : : string & pattern ) const {
return this - > wellNames ( pattern , this - > size ( ) - 1 ) ;
}
std : : vector < std : : string > Schedule : : wellNames ( std : : size_t timeStep ) const {
std : : vector < std : : string > names ;
2019-05-04 12:00:32 +02:00
for ( const auto & well_pair : this - > wells_static ) {
const auto & well_name = well_pair . first ;
const auto & dynamic_state = well_pair . second ;
2020-09-16 11:59:03 +02:00
auto open_step = dynamic_state . find_not ( nullptr ) ;
if ( open_step . value ( ) < = timeStep )
2019-05-04 12:00:32 +02:00
names . push_back ( well_name ) ;
2019-03-24 07:53:30 +01:00
}
return names ;
}
std : : vector < std : : string > Schedule : : wellNames ( ) const {
std : : vector < std : : string > names ;
2019-05-04 12:00:32 +02:00
for ( const auto & well_pair : this - > wells_static )
2019-03-24 07:53:30 +01:00
names . push_back ( well_pair . first ) ;
2019-05-04 12:00:32 +02:00
2019-03-24 07:53:30 +01:00
return names ;
2019-07-07 08:46:17 +02:00
}
2020-09-25 12:51:36 +02:00
std : : vector < std : : string > Schedule : : groupNames ( const std : : string & pattern , std : : size_t timeStep ) const {
2019-07-07 08:46:17 +02:00
if ( pattern . size ( ) = = 0 )
return { } ;
// Normal pattern matching
auto star_pos = pattern . find ( ' * ' ) ;
if ( star_pos ! = std : : string : : npos ) {
std : : vector < std : : string > names ;
2019-08-06 22:40:14 +02:00
for ( const auto & group_pair : this - > groups ) {
2019-07-07 08:46:17 +02:00
if ( name_match ( pattern , group_pair . first ) ) {
2019-08-06 22:40:14 +02:00
const auto & dynamic_state = group_pair . second ;
const auto & group_ptr = dynamic_state . get ( timeStep ) ;
if ( group_ptr )
2019-07-07 08:46:17 +02:00
names . push_back ( group_pair . first ) ;
}
}
return names ;
}
// Normal group name without any special characters
if ( this - > hasGroup ( pattern ) ) {
2019-08-06 22:40:14 +02:00
const auto & dynamic_state = this - > groups . at ( pattern ) ;
const auto & group_ptr = dynamic_state . get ( timeStep ) ;
if ( group_ptr )
2019-07-07 08:46:17 +02:00
return { pattern } ;
}
return { } ;
}
2020-09-25 12:51:36 +02:00
std : : vector < std : : string > Schedule : : groupNames ( std : : size_t timeStep ) const {
2019-07-07 08:46:17 +02:00
std : : vector < std : : string > names ;
2019-08-06 22:40:14 +02:00
for ( const auto & group_pair : this - > groups ) {
const auto & dynamic_state = group_pair . second ;
const auto & group_ptr = dynamic_state . get ( timeStep ) ;
if ( group_ptr )
names . push_back ( group_pair . first ) ;
2019-07-07 08:46:17 +02:00
}
return names ;
}
std : : vector < std : : string > Schedule : : groupNames ( const std : : string & pattern ) const {
if ( pattern . size ( ) = = 0 )
return { } ;
// Normal pattern matching
auto star_pos = pattern . find ( ' * ' ) ;
if ( star_pos ! = std : : string : : npos ) {
int flags = 0 ;
std : : vector < std : : string > names ;
2019-08-06 22:40:14 +02:00
for ( const auto & group_pair : this - > groups ) {
2019-07-07 08:46:17 +02:00
if ( fnmatch ( pattern . c_str ( ) , group_pair . first . c_str ( ) , flags ) = = 0 )
names . push_back ( group_pair . first ) ;
}
return names ;
}
// Normal group name without any special characters
if ( this - > hasGroup ( pattern ) )
return { pattern } ;
return { } ;
}
std : : vector < std : : string > Schedule : : groupNames ( ) const {
std : : vector < std : : string > names ;
2019-08-06 22:40:14 +02:00
for ( const auto & group_pair : this - > groups )
2019-07-07 08:46:17 +02:00
names . push_back ( group_pair . first ) ;
return names ;
2019-03-24 07:53:30 +01:00
}
2019-03-14 09:23:03 +01:00
2020-06-23 16:50:30 +02:00
std : : vector < const Group * > Schedule : : restart_groups ( std : : size_t timeStep ) const {
2020-06-24 15:38:44 +02:00
std : : size_t wdmax = this - > m_runspec . wellDimensions ( ) . maxGroupsInField ( ) ;
std : : vector < const Group * > rst_groups ( wdmax + 1 , nullptr ) ;
2020-06-23 16:50:30 +02:00
for ( const auto & group_name : this - > groupNames ( timeStep ) ) {
const auto & group = this - > getGroup ( group_name , timeStep ) ;
if ( group . name ( ) = = " FIELD " )
rst_groups . back ( ) = & group ;
else
rst_groups [ group . insert_index ( ) - 1 ] = & group ;
}
return rst_groups ;
}
2015-02-12 12:54:57 +01:00
2020-10-05 14:04:25 +02:00
void Schedule : : addGroup ( const Group & group , std : : size_t timeStep ) {
this - > groups . insert ( std : : make_pair ( group . name ( ) , DynamicState < std : : shared_ptr < Group > > ( this - > m_timeMap , nullptr ) ) ) ;
auto group_ptr = std : : make_shared < Group > ( group ) ;
auto & dynamic_state = this - > groups . at ( group . name ( ) ) ;
2019-07-24 08:38:39 +02:00
dynamic_state . update ( timeStep , group_ptr ) ;
2020-10-05 14:04:25 +02:00
this - > m_events . addEvent ( ScheduleEvents : : NEW_GROUP , timeStep ) ;
this - > wellgroup_events . insert ( std : : make_pair ( group . name ( ) , Events ( this - > m_timeMap ) ) ) ;
this - > addWellGroupEvent ( group . name ( ) , 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.
2020-10-05 14:04:25 +02:00
if ( group . name ( ) ! = " FIELD " )
2019-07-25 11:46:15 +02:00
this - > addGroupToGroup ( " FIELD " , * group_ptr , timeStep ) ;
2013-11-18 13:11:49 +01:00
}
2020-10-05 14:04:25 +02:00
2020-11-02 16:11:35 +01:00
void Schedule : : addGroup ( const std : : string & groupName , std : : size_t timeStep ) {
2020-10-05 14:04:25 +02:00
const std : : size_t insert_index = this - > groups . size ( ) ;
auto udq_undefined = this - > getUDQConfig ( timeStep ) . params ( ) . undefinedValue ( ) ;
2020-11-02 16:11:35 +01:00
auto group = Group { groupName , insert_index , timeStep , udq_undefined , this - > unit_system } ;
2020-10-05 14:04:25 +02:00
this - > addGroup ( group , timeStep ) ;
}
2020-09-25 12:51:36 +02:00
std : : size_t Schedule : : numGroups ( ) const {
2019-08-06 22:40:14 +02:00
return groups . size ( ) ;
2013-11-18 13:11:49 +01:00
}
2019-07-07 10:29:24 +02:00
2020-09-25 12:51:36 +02:00
std : : size_t Schedule : : numGroups ( std : : size_t timeStep ) const {
2019-07-07 10:29:24 +02:00
const auto group_names = this - > groupNames ( timeStep ) ;
return group_names . size ( ) ;
2018-04-24 14:03:29 +02:00
}
2013-11-18 13:11:49 +01:00
bool Schedule : : hasGroup ( const std : : string & groupName ) const {
2019-08-06 22:40:14 +02:00
return groups . count ( groupName ) > 0 ;
2013-11-18 13:11:49 +01:00
}
2019-09-19 23:50:41 +02:00
bool Schedule : : hasGroup ( const std : : string & groupName , std : : size_t timeStep ) const {
if ( timeStep > = this - > size ( ) )
return false ;
auto grpMap = this - > groups . find ( groupName ) ;
return ( grpMap ! = this - > groups . end ( ) )
& & grpMap - > second . at ( timeStep ) ;
}
2019-07-07 10:29:24 +02:00
2020-09-25 12:51:36 +02:00
void Schedule : : addGroupToGroup ( const std : : string & parent_group , const Group & child_group , std : : size_t timeStep ) {
2019-07-25 11:46:15 +02:00
// Add to new parent
auto & dynamic_state = this - > groups . at ( parent_group ) ;
2019-11-12 08:29:28 +01:00
auto parent_ptr = std : : make_shared < Group > ( * dynamic_state [ timeStep ] ) ;
2019-07-25 11:46:15 +02:00
if ( parent_ptr - > addGroup ( child_group . name ( ) ) )
2019-07-30 17:47:19 +02:00
this - > updateGroup ( std : : move ( parent_ptr ) , timeStep ) ;
2019-07-25 11:46:15 +02:00
// Check and update backreference in child
if ( child_group . parent ( ) ! = parent_group ) {
2019-11-12 08:29:28 +01:00
auto old_parent = std : : make_shared < Group > ( this - > getGroup ( child_group . parent ( ) , timeStep ) ) ;
2019-07-25 11:46:15 +02:00
old_parent - > delGroup ( child_group . name ( ) ) ;
2019-07-30 17:47:19 +02:00
this - > updateGroup ( std : : move ( old_parent ) , timeStep ) ;
2019-01-28 09:52:11 +01:00
2019-11-12 08:29:28 +01:00
auto child_ptr = std : : make_shared < Group > ( child_group ) ;
2019-07-25 11:46:15 +02:00
child_ptr - > updateParent ( parent_group ) ;
2019-07-30 17:47:19 +02:00
this - > updateGroup ( std : : move ( child_ptr ) , timeStep ) ;
2013-11-18 13:11:49 +01:00
2019-07-25 11:46:15 +02:00
}
}
2020-09-25 12:51:36 +02:00
void Schedule : : addGroupToGroup ( const std : : string & parent_group , const std : : string & child_group , std : : size_t timeStep ) {
2019-11-12 08:29:28 +01:00
this - > addGroupToGroup ( parent_group , this - > getGroup ( child_group , timeStep ) , timeStep ) ;
2019-07-25 11:46:15 +02:00
}
2020-09-25 12:51:36 +02:00
void Schedule : : addWellToGroup ( const std : : string & group_name , const std : : string & well_name , std : : size_t timeStep ) {
2019-11-12 08:29:28 +01:00
const auto & well = this - > getWell ( well_name , timeStep ) ;
2019-07-25 11:46:15 +02:00
const auto old_gname = well . groupName ( ) ;
2019-08-06 22:40:14 +02:00
if ( old_gname ! = group_name ) {
2019-11-12 08:29:28 +01:00
auto well_ptr = std : : make_shared < Well > ( well ) ;
2019-07-25 11:46:15 +02:00
well_ptr - > updateGroup ( group_name ) ;
this - > updateWell ( well_ptr , timeStep ) ;
2019-11-27 08:58:57 +01:00
this - > addWellGroupEvent ( well_ptr - > name ( ) , ScheduleEvents : : WELL_WELSPECS_UPDATE , timeStep ) ;
2019-07-25 11:46:15 +02:00
2019-08-06 22:40:14 +02:00
// Remove well child reference from previous group
2019-11-12 08:29:28 +01:00
auto group = std : : make_shared < Group > ( this - > getGroup ( old_gname , timeStep ) ) ;
2019-08-06 22:40:14 +02:00
group - > delWell ( well_name ) ;
2019-07-30 17:47:19 +02:00
this - > updateGroup ( std : : move ( group ) , timeStep ) ;
2019-07-25 11:46:15 +02:00
}
2019-08-06 22:40:14 +02:00
// Add well child reference to new group
2019-11-12 08:29:28 +01:00
auto group_ptr = std : : make_shared < Group > ( this - > getGroup ( group_name , timeStep ) ) ;
2019-08-06 22:40:14 +02:00
group_ptr - > addWell ( well_name ) ;
this - > updateGroup ( group_ptr , timeStep ) ;
this - > m_events . addEvent ( ScheduleEvents : : GROUP_CHANGE , timeStep ) ;
2020-09-25 10:49:47 +02:00
}
2014-12-05 12:59:53 +01:00
2015-04-17 18:51:42 +02:00
2020-09-25 12:51:36 +02:00
const Deck & Schedule : : getModifierDeck ( std : : size_t timeStep ) const {
2016-10-05 10:12:46 +02:00
return m_modifierDeck . iget ( timeStep ) ;
2015-10-30 15:33:53 +01:00
}
2016-10-17 10:41:17 +08:00
const MessageLimits & Schedule : : getMessageLimits ( ) const {
return m_messageLimits ;
2016-10-14 10:06:35 +08:00
}
2015-10-30 15:33:53 +01:00
2018-04-12 19:02:15 +02:00
2019-11-27 08:58:57 +01:00
const Events & Schedule : : getWellGroupEvents ( const std : : string & wellGroup ) const {
if ( this - > wellgroup_events . count ( wellGroup ) > 0 )
return this - > wellgroup_events . at ( wellGroup ) ;
2019-03-21 08:49:27 +01:00
else
2019-11-27 08:58:57 +01:00
throw std : : invalid_argument ( " No such well og group " + wellGroup ) ;
2019-03-21 08:49:27 +01:00
}
2016-04-14 09:39:28 +08:00
2020-09-25 12:51:36 +02:00
void Schedule : : addWellGroupEvent ( const std : : string & wellGroup , ScheduleEvents : : Events event , std : : size_t reportStep ) {
2019-11-27 08:58:57 +01:00
auto & events = this - > wellgroup_events . at ( wellGroup ) ;
2019-03-21 08:49:27 +01:00
events . addEvent ( event , reportStep ) ;
}
2020-09-25 12:51:36 +02:00
bool Schedule : : hasWellGroupEvent ( const std : : string & wellGroup , uint64_t event_mask , std : : size_t reportStep ) const {
2019-11-27 08:58:57 +01:00
const auto & events = this - > getWellGroupEvents ( wellGroup ) ;
2019-11-25 09:55:32 +01:00
return events . hasEvent ( event_mask , reportStep ) ;
}
2015-06-23 14:20:31 +02:00
const Events & Schedule : : getEvents ( ) const {
2016-10-05 10:09:45 +02:00
return this - > m_events ;
2015-10-02 10:49:23 +02:00
}
2020-09-25 12:51:36 +02:00
const Well : : ProducerCMode & Schedule : : getGlobalWhistctlMmode ( std : : size_t timestep ) const {
2019-12-16 14:34:36 +01:00
return global_whistctl_mode . get ( timestep ) ;
}
2015-10-02 10:49:23 +02:00
2017-09-26 09:32:29 +02:00
2020-09-25 12:51:36 +02:00
void Schedule : : checkIfAllConnectionsIsShut ( std : : size_t timeStep ) {
2019-05-04 12:00:32 +02:00
const auto & well_names = this - > wellNames ( timeStep ) ;
for ( const auto & wname : well_names ) {
2019-11-12 08:29:28 +01:00
const auto & well = this - > getWell ( wname , timeStep ) ;
2019-05-04 12:00:32 +02:00
const auto & connections = well . getConnections ( ) ;
2020-06-01 09:07:17 +02:00
if ( connections . allConnectionsShut ( ) & & well . getStatus ( ) ! = Well : : Status : : SHUT ) {
std : : string msg =
" All completions in well " + well . name ( ) + " is shut at " + std : : to_string ( m_timeMap . getTimePassedUntil ( timeStep ) / ( 60 * 60 * 24 ) ) + " days. \n " +
" The well is therefore also shut. " ;
OpmLog : : note ( msg ) ;
2020-12-08 09:20:44 +01:00
this - > updateWellStatus ( well . name ( ) , timeStep , false , Well : : Status : : SHUT ) ;
2020-06-01 09:07:17 +02:00
}
2017-09-26 09:32:29 +02:00
}
}
2018-02-06 19:13:42 +01:00
2019-12-10 11:46:49 +01:00
void Schedule : : filterConnections ( const ActiveGridCells & grid ) {
2019-05-04 12:00:32 +02:00
for ( auto & dynamic_pair : this - > wells_static ) {
auto & dynamic_state = dynamic_pair . second ;
for ( auto & well_pair : dynamic_state . unique ( ) ) {
if ( well_pair . second )
well_pair . second - > filterConnections ( grid ) ;
}
}
2018-02-06 19:13:42 +01:00
}
2018-04-06 12:12:30 +02:00
2020-09-25 12:51:36 +02:00
const VFPProdTable & Schedule : : getVFPProdTable ( int table_id , std : : size_t timeStep ) const {
2018-04-12 19:02:15 +02:00
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
}
2020-09-25 12:51:36 +02:00
const VFPInjTable & Schedule : : getVFPInjTable ( int table_id , std : : size_t timeStep ) const {
2018-04-12 19:02:15 +02:00
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 ;
}
2020-09-25 12:51:36 +02:00
std : : map < int , std : : shared_ptr < const VFPInjTable > > Schedule : : getVFPInjTables ( std : : size_t timeStep ) const {
2018-04-20 11:27:26 +02:00
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 ;
}
2020-09-25 12:51:36 +02:00
std : : map < int , std : : shared_ptr < const VFPProdTable > > Schedule : : getVFPProdTables ( std : : size_t timeStep ) const {
2018-04-20 11:27:26 +02:00
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
}
2020-09-25 12:51:36 +02:00
const UDQActive & Schedule : : udqActive ( std : : size_t timeStep ) const {
2019-06-19 13:40:27 +02:00
return * this - > udq_active [ timeStep ] ;
}
2020-09-25 12:51:36 +02:00
void Schedule : : updateUDQActive ( std : : size_t timeStep , std : : shared_ptr < UDQActive > udq ) {
2019-06-19 13:40:27 +02:00
this - > udq_active . update ( timeStep , udq ) ;
}
2018-05-14 04:18:07 +02:00
2020-09-25 12:51:36 +02:00
const WellTestConfig & Schedule : : wtestConfig ( std : : size_t timeStep ) const {
2018-05-14 04:18:07 +02:00
const auto & ptr = this - > wtest_config . get ( timeStep ) ;
return * ptr ;
}
2018-10-12 08:25:40 +02:00
2020-09-25 12:51:36 +02:00
const GConSale & Schedule : : gConSale ( std : : size_t timeStep ) const {
2019-10-31 15:18:42 +01:00
const auto & ptr = this - > gconsale . get ( timeStep ) ;
return * ptr ;
}
2020-09-25 12:51:36 +02:00
const GConSump & Schedule : : gConSump ( std : : size_t timeStep ) const {
2019-11-06 11:33:32 +01:00
const auto & ptr = this - > gconsump . get ( timeStep ) ;
return * ptr ;
}
2020-09-25 12:51:36 +02:00
const WListManager & Schedule : : getWListManager ( std : : size_t timeStep ) const {
2019-01-14 12:09:07 +01:00
const auto & ptr = this - > wlist_manager . get ( timeStep ) ;
return * ptr ;
}
2018-10-27 15:58:02 +02:00
2020-09-25 12:51:36 +02:00
const UDQConfig & Schedule : : getUDQConfig ( std : : size_t timeStep ) const {
2019-01-28 16:52:28 +01:00
const auto & ptr = this - > udq_config . get ( timeStep ) ;
return * ptr ;
}
2020-10-23 15:04:27 +02:00
std : : vector < const UDQConfig * > Schedule : : udqConfigList ( ) const {
std : : vector < const UDQConfig * > udq_list ;
for ( const auto & udq_pair : this - > udq_config . unique ( ) )
udq_list . push_back ( udq_pair . second . get ( ) ) ;
return udq_list ;
}
2020-09-25 12:51:36 +02:00
const GuideRateConfig & Schedule : : guideRateConfig ( std : : size_t timeStep ) const {
2019-09-06 07:56:42 +02:00
const auto & ptr = this - > guide_rate_config . get ( timeStep ) ;
2019-08-22 17:55:10 +02:00
return * ptr ;
}
2020-09-25 12:51:36 +02:00
const RPTConfig & Schedule : : report_config ( std : : size_t timeStep ) const {
2020-04-01 11:56:07 +02:00
const auto & ptr = this - > rpt_config . get ( timeStep ) ;
return * ptr ;
}
2020-04-12 09:30:23 +02:00
std : : optional < int > Schedule : : exitStatus ( ) const {
return this - > exit_status ;
}
2018-10-27 15:58:02 +02:00
2020-09-25 12:51:36 +02:00
std : : size_t Schedule : : size ( ) const {
2018-10-12 08:25:40 +02:00
return this - > m_timeMap . size ( ) ;
}
2018-10-17 12:08:54 +02:00
2020-09-25 12:51:36 +02:00
double Schedule : : seconds ( std : : size_t timeStep ) const {
2018-10-17 12:08:54 +02:00
return this - > m_timeMap . seconds ( timeStep ) ;
}
2020-09-25 12:51:36 +02:00
time_t Schedule : : simTime ( std : : size_t timeStep ) const {
2019-01-22 17:04:54 +01:00
return this - > m_timeMap [ timeStep ] ;
}
2018-10-09 17:42:37 +02:00
2020-09-25 12:51:36 +02:00
double Schedule : : stepLength ( std : : size_t timeStep ) const {
2018-10-09 17:42:37 +02:00
return this - > m_timeMap . getTimeStepLength ( timeStep ) ;
}
2018-11-19 09:43:50 +01:00
2019-08-29 18:17:37 +02:00
const Action : : Actions & Schedule : : actions ( std : : size_t timeStep ) const {
const auto & ptr = this - > m_actions . get ( timeStep ) ;
return * ptr ;
2018-11-19 09:43:50 +01:00
}
2020-09-25 12:51:36 +02:00
void Schedule : : applyAction ( std : : size_t reportStep , const Action : : ActionX & action , const Action : : Result & result ) {
2019-01-28 10:00:08 +01:00
ParseContext parseContext ;
ErrorGuard errors ;
for ( const auto & keyword : action ) {
2019-07-01 08:27:07 +02:00
if ( ! Action : : ActionX : : valid_keyword ( keyword . name ( ) ) )
2019-01-28 10:00:08 +01:00
throw std : : invalid_argument ( " The keyword: " + keyword . name ( ) + " can not be handled in the ACTION body " ) ;
2020-04-12 09:30:23 +02:00
if ( keyword . name ( ) = = " EXIT " )
2020-09-25 10:12:55 +02:00
this - > applyEXIT ( keyword , reportStep ) ;
2019-01-28 10:00:08 +01:00
2020-11-13 08:48:11 +01:00
if ( keyword . name ( ) = = " GCONINJE " )
this - > handleGCONINJE ( keyword , reportStep , parseContext , errors ) ;
2020-11-02 16:27:18 +01:00
if ( keyword . name ( ) = = " GCONPROD " )
this - > handleGCONPROD ( keyword , reportStep , parseContext , errors ) ;
2020-11-03 08:45:14 +01:00
if ( keyword . name ( ) = = " GLIFTOPT " )
this - > handleGLIFTOPT ( keyword , reportStep , parseContext , errors ) ;
2020-11-13 17:46:29 +01:00
if ( keyword . name ( ) = = " UDQ " )
this - > updateUDQ ( keyword , reportStep ) ;
if ( keyword . name ( ) = = " WELOPEN " )
2020-12-04 16:04:40 +01:00
this - > applyWELOPEN ( keyword , reportStep , true , parseContext , errors , result . wells ( ) ) ;
2020-11-13 17:46:29 +01:00
2020-12-03 22:42:48 +01:00
/*
The WELPI functionality is implemented as a two - step process
involving both code here in opm - common and opm - simulator . The
update process goes like this :
1. The scalar factor from the WELPI keyword is internalized in
the WellConnections objects . And the event
WELL_PRODUCTIVITY_INDEX is emitted to signal that a PI
recalculation is required .
2. In opm - simulators the run loop will detect
WELL_PRODUCTIVITY_INDEX event and perform the actual PI
recalculation .
In the simulator the WELL_PRODUCTIVITY_INDEX event is checked at
the start of a new report step . That implies that if an ACTIONX is
evaluated to true while processing report step N , this can only be
acted upon in the simulator at the start of the following step
N + 1 , this is special cased in the handleWELPI function when it is
called with actionx_mode = = true . If the interaction between
opm - common and the simulator changes in the future this might
change .
*/
2020-11-13 17:46:29 +01:00
if ( keyword . name ( ) = = " WELPI " )
2020-12-03 22:42:48 +01:00
this - > handleWELPI ( keyword , reportStep , parseContext , errors , true , result . wells ( ) ) ;
2020-09-16 16:06:02 +02:00
}
2019-01-28 10:00:08 +01:00
}
2020-11-02 16:27:18 +01:00
2020-10-19 01:56:10 +02:00
void Schedule : : applyWellProdIndexScaling ( const std : : string & well_name , const std : : size_t reportStep , const double scalingFactor ) {
auto wstat = this - > wells_static . find ( well_name ) ;
if ( wstat = = this - > wells_static . end ( ) )
return ;
2020-10-20 11:14:03 +02:00
auto unique_well_instances = wstat - > second . unique ( ) ;
auto end = unique_well_instances . end ( ) ;
auto start = std : : lower_bound ( unique_well_instances . begin ( ) , end , reportStep ,
2020-10-19 01:56:10 +02:00
[ ] ( const auto & time_well_pair , const auto lookup ) - > bool
{
// time < reportStep
return time_well_pair . first < lookup ;
} ) ;
if ( start = = end )
// Report step after last?
return ;
// Relies on wells_static being OrderedMap<string, DynamicState<shared_ptr<>>>
2020-10-20 11:14:03 +02:00
// which means unique_well_instances is a vector<pair<report_step, shared_ptr<>>>
2020-10-19 01:56:10 +02:00
std : : vector < bool > scalingApplicable ;
auto wellPtr = start - > second ;
wellPtr - > applyWellProdIndexScaling ( scalingFactor , scalingApplicable ) ;
for ( ; start ! = end ; + + start )
if ( ! wellPtr - > hasSameConnectionsPointers ( * start - > second ) ) {
wellPtr = start - > second ;
wellPtr - > applyWellProdIndexScaling ( scalingFactor , scalingApplicable ) ;
}
}
2020-02-16 20:00:16 +01:00
RestartConfig & Schedule : : restart ( ) {
return this - > restart_config ;
}
const RestartConfig & Schedule : : restart ( ) const {
return this - > restart_config ;
}
2020-09-25 10:49:47 +02:00
bool Schedule : : operator = = ( const Schedule & data ) const {
2019-12-16 14:27:16 +01:00
auto & & comparePtr = [ ] ( const auto & t1 , const auto & t2 ) {
if ( ( t1 & & ! t2 ) | | ( ! t1 & & t2 ) )
return false ;
if ( ! t1 )
return true ;
return * t1 = = * t2 ;
} ;
auto & & compareDynState = [ comparePtr ] ( const auto & state1 , const auto & state2 ) {
if ( state1 . data ( ) . size ( ) ! = state2 . data ( ) . size ( ) )
return false ;
return std : : equal ( state1 . data ( ) . begin ( ) , state1 . data ( ) . end ( ) ,
state2 . data ( ) . begin ( ) , comparePtr ) ;
} ;
2020-01-13 10:07:33 +01:00
auto & & compareMap = [ compareDynState ] ( const auto & map1 , const auto & map2 ) {
2019-12-16 14:27:16 +01:00
if ( map1 . size ( ) ! = map2 . size ( ) )
return false ;
auto it2 = map2 . begin ( ) ;
for ( const auto & it : map1 ) {
if ( it . first ! = it2 - > first )
return false ;
if ( ! compareDynState ( it . second , it2 - > second ) )
return false ;
+ + it2 ;
}
return true ;
} ;
2019-08-30 12:56:49 +02:00
2020-03-12 12:10:32 +01:00
return this - > m_timeMap = = data . m_timeMap & &
compareMap ( this - > wells_static , data . wells_static ) & &
compareMap ( this - > groups , data . groups ) & &
this - > m_events = = data . m_events & &
this - > m_modifierDeck = = data . m_modifierDeck & &
this - > m_messageLimits = = data . m_messageLimits & &
this - > m_runspec = = data . m_runspec & &
compareMap ( this - > vfpprod_tables , data . vfpprod_tables ) & &
compareMap ( this - > vfpinj_tables , data . vfpinj_tables ) & &
2020-05-06 21:10:52 +02:00
compareDynState ( this - > m_network , data . m_network ) & &
2020-05-06 11:35:22 +02:00
compareDynState ( this - > m_glo , data . m_glo ) & &
2020-03-12 12:10:32 +01:00
compareDynState ( this - > wtest_config , data . wtest_config ) & &
compareDynState ( this - > wlist_manager , data . wlist_manager ) & &
compareDynState ( this - > udq_config , data . udq_config ) & &
compareDynState ( this - > udq_active , data . udq_active ) & &
compareDynState ( this - > guide_rate_config , data . guide_rate_config ) & &
compareDynState ( this - > gconsale , data . gconsale ) & &
compareDynState ( this - > gconsump , data . gconsump ) & &
this - > global_whistctl_mode = = data . global_whistctl_mode & &
compareDynState ( this - > m_actions , data . m_actions ) & &
2020-04-01 11:56:07 +02:00
compareDynState ( this - > rpt_config , data . rpt_config ) & &
2020-03-12 12:10:32 +01:00
rft_config = = data . rft_config & &
this - > restart_config = = data . restart_config & &
2020-11-02 16:11:35 +01:00
this - > unit_system = = data . unit_system & &
2020-03-12 12:10:32 +01:00
this - > wellgroup_events = = data . wellgroup_events ;
2019-12-16 14:27:16 +01:00
}
2020-06-06 08:54:04 +02:00
2020-09-29 22:59:03 +02:00
std : : string Schedule : : formatDate ( std : : time_t t ) {
const auto ts { TimeStampUTC ( t ) } ;
2020-09-28 14:21:35 +02:00
return fmt : : format ( " {:04d}-{:02d}-{:02d} " , ts . year ( ) , ts . month ( ) , ts . day ( ) ) ;
}
2020-11-02 16:11:35 +01:00
std : : string Schedule : : simulationDays ( std : : size_t currentStep ) const {
const double sim_time { this - > unit_system . from_si ( UnitSystem : : measure : : time , simTime ( currentStep ) ) } ;
return fmt : : format ( " {} {} " , sim_time , this - > unit_system . name ( UnitSystem : : measure : : time ) ) ;
2020-09-28 14:21:35 +02:00
}
2020-03-18 13:56:26 +01:00
namespace {
2020-09-25 10:49:47 +02:00
// Duplicated from Well.cpp
Connection : : Order order_from_int ( int int_value ) {
switch ( int_value ) {
case 0 :
return Connection : : Order : : TRACK ;
case 1 :
return Connection : : Order : : DEPTH ;
case 2 :
return Connection : : Order : : INPUT ;
default :
throw std : : invalid_argument ( " Invalid integer value: " + std : : to_string ( int_value ) + " encountered when determining connection ordering " ) ;
}
2020-03-18 13:56:26 +01:00
}
}
2020-03-13 07:36:45 +01:00
2020-11-02 16:11:35 +01:00
void Schedule : : load_rst ( const RestartIO : : RstState & rst_state , const EclipseGrid & grid , const FieldPropsManager & fp )
2020-09-25 10:49:47 +02:00
{
double udq_undefined = 0 ;
const auto report_step = rst_state . header . report_step - 1 ;
2021-01-06 18:11:05 +01:00
auto start_time = std : : chrono : : system_clock : : from_time_t ( this - > getStartTime ( ) ) ;
2021-01-07 09:36:15 +01:00
for ( int step = 0 ; step < report_step ; step + + )
this - > create_next ( start_time , start_time ) ;
2021-01-06 18:11:05 +01:00
{
auto restart_time = std : : chrono : : system_clock : : from_time_t ( rst_state . header . restart_info ( ) . first ) ;
2021-01-07 09:36:15 +01:00
this - > create_next ( start_time , restart_time ) ;
2021-01-06 18:11:05 +01:00
}
2020-09-25 10:49:47 +02:00
2020-10-08 08:15:32 +02:00
for ( const auto & rst_group : rst_state . groups ) {
2020-11-02 16:11:35 +01:00
auto group = Group { rst_group , this - > groups . size ( ) , static_cast < std : : size_t > ( report_step ) , udq_undefined , this - > unit_system } ;
2020-10-08 08:15:32 +02:00
this - > addGroup ( group , report_step ) ;
2020-10-20 08:40:41 +02:00
if ( group . isProductionGroup ( ) ) {
this - > m_events . addEvent ( ScheduleEvents : : GROUP_PRODUCTION_UPDATE , report_step + 1 ) ;
this - > addWellGroupEvent ( rst_group . name , ScheduleEvents : : GROUP_PRODUCTION_UPDATE , report_step + 1 ) ;
}
if ( group . isInjectionGroup ( ) ) {
this - > m_events . addEvent ( ScheduleEvents : : GROUP_INJECTION_UPDATE , report_step + 1 ) ;
this - > addWellGroupEvent ( rst_group . name , ScheduleEvents : : GROUP_INJECTION_UPDATE , report_step + 1 ) ;
}
2020-10-08 08:15:32 +02:00
}
2020-09-25 10:49:47 +02:00
2020-10-07 16:45:19 +02:00
for ( std : : size_t group_index = 0 ; group_index < rst_state . groups . size ( ) ; group_index + + ) {
const auto & rst_group = rst_state . groups [ group_index ] ;
if ( rst_group . parent_group = = 0 )
continue ;
if ( rst_group . parent_group = = rst_state . header . max_groups_in_field )
continue ;
const auto & parent_group = rst_state . groups [ rst_group . parent_group - 1 ] ;
this - > addGroupToGroup ( parent_group . name , rst_group . name , report_step ) ;
}
2020-09-25 10:49:47 +02:00
for ( const auto & rst_well : rst_state . wells ) {
2020-11-02 16:11:35 +01:00
Opm : : Well well ( rst_well , report_step , this - > unit_system , udq_undefined ) ;
2020-09-25 10:49:47 +02:00
std : : vector < Opm : : Connection > rst_connections ;
for ( const auto & rst_conn : rst_well . connections )
rst_connections . emplace_back ( rst_conn , grid , fp ) ;
if ( rst_well . segments . empty ( ) ) {
Opm : : WellConnections connections ( order_from_int ( rst_well . completion_ordering ) ,
rst_well . ij [ 0 ] ,
rst_well . ij [ 1 ] ,
rst_connections ) ;
2020-12-08 09:20:44 +01:00
well . updateConnections ( std : : make_shared < WellConnections > ( std : : move ( connections ) ) , report_step , grid , fp . get_int ( " PVTNUM " ) ) ;
2020-09-25 10:49:47 +02:00
} else {
std : : unordered_map < int , Opm : : Segment > rst_segments ;
for ( const auto & rst_segment : rst_well . segments ) {
Opm : : Segment segment ( rst_segment ) ;
rst_segments . insert ( std : : make_pair ( rst_segment . segment , std : : move ( segment ) ) ) ;
}
auto [ connections , segments ] = Compsegs : : rstUpdate ( rst_well , rst_connections , rst_segments ) ;
2020-12-08 09:20:44 +01:00
well . updateConnections ( std : : make_shared < WellConnections > ( std : : move ( connections ) ) , report_step , grid , fp . get_int ( " PVTNUM " ) ) ;
2020-09-25 10:49:47 +02:00
well . updateSegments ( std : : make_shared < WellSegments > ( std : : move ( segments ) ) ) ;
2020-06-06 08:54:04 +02:00
}
2020-09-25 10:49:47 +02:00
this - > addWell ( well , report_step ) ;
this - > addWellToGroup ( well . groupName ( ) , well . name ( ) , report_step ) ;
2020-03-13 07:36:45 +01:00
}
2021-01-06 18:11:05 +01:00
this - > snapshots [ report_step + 1 ] . tuning ( rst_state . tuning ) ;
2020-11-03 19:34:34 +01:00
m_events . addEvent ( ScheduleEvents : : TUNING_CHANGE , report_step + 1 ) ;
2020-03-13 07:36:45 +01:00
2020-10-20 08:38:13 +02:00
{
const auto & header = rst_state . header ;
bool time_interval = 0 ;
GuideRateModel : : Target target = GuideRateModel : : Target : : OIL ;
bool allow_increase = true ;
bool use_free_gas = false ;
if ( GuideRateModel : : rst_valid ( time_interval ,
header . guide_rate_a ,
header . guide_rate_b ,
header . guide_rate_c ,
header . guide_rate_d ,
header . guide_rate_e ,
header . guide_rate_f ,
header . guide_rate_damping ) ) {
auto guide_rate_model = GuideRateModel ( time_interval ,
target ,
header . guide_rate_a ,
header . guide_rate_b ,
header . guide_rate_c ,
header . guide_rate_d ,
header . guide_rate_e ,
header . guide_rate_f ,
allow_increase ,
header . guide_rate_damping ,
use_free_gas ) ;
this - > updateGuideRateModel ( guide_rate_model , report_step ) ;
}
}
2020-03-13 07:36:45 +01:00
}
2020-09-25 10:49:47 +02:00
std : : shared_ptr < const Python > Schedule : : python ( ) const
{
return this - > python_handle ;
}
2020-04-25 19:15:17 +02:00
2020-09-25 10:49:47 +02:00
void Schedule : : updateNetwork ( std : : shared_ptr < Network : : ExtNetwork > network , std : : size_t report_step ) {
this - > m_network . update ( report_step , std : : move ( network ) ) ;
}
2020-05-06 11:35:22 +02:00
2020-09-25 10:49:47 +02:00
const Network : : ExtNetwork & Schedule : : network ( std : : size_t report_step ) const {
return * this - > m_network [ report_step ] ;
}
2020-04-25 19:15:17 +02:00
2020-09-25 10:49:47 +02:00
const GasLiftOpt & Schedule : : glo ( std : : size_t report_step ) const {
return * this - > m_glo [ report_step ] ;
}
2020-04-25 19:15:17 +02:00
2020-03-13 07:36:17 +01:00
namespace {
/*
The insane trickery here ( thank you Stackoverflow ! ) is to be able to provide a
simple templated comparison function
template < typename T >
int not_equal ( const T & arg1 , const T & arg2 , const std : : string & msg ) ;
which will print arg1 and arg2 on stderr * if * T supports operator < < , otherwise
it will just print the typename of T .
*/
template < typename T , typename = int >
struct cmpx
{
int neq ( const T & arg1 , const T & arg2 , const std : : string & msg ) {
if ( arg1 = = arg2 )
return 0 ;
std : : cerr < < " Error when comparing < " < < typeid ( arg1 ) . name ( ) < < " >: " < < msg < < std : : endl ;
return 1 ;
}
} ;
template < typename T >
struct cmpx < T , decltype ( std : : cout < < T ( ) , 0 ) >
{
int neq ( const T & arg1 , const T & arg2 , const std : : string & msg ) {
if ( arg1 = = arg2 )
return 0 ;
std : : cerr < < " Error when comparing: " < < msg < < " " < < arg1 < < " != " < < arg2 < < std : : endl ;
return 1 ;
}
} ;
template < typename T >
int not_equal ( const T & arg1 , const T & arg2 , const std : : string & msg ) {
return cmpx < T > ( ) . neq ( arg1 , arg2 , msg ) ;
}
template < >
int not_equal ( const double & arg1 , const double & arg2 , const std : : string & msg ) {
if ( Opm : : cmp : : scalar_equal ( arg1 , arg2 ) )
return 0 ;
std : : cerr < < " Error when comparing: " < < msg < < " " < < arg1 < < " != " < < arg2 < < std : : endl ;
return 1 ;
}
template < >
int not_equal ( const UDAValue & arg1 , const UDAValue & arg2 , const std : : string & msg ) {
if ( arg1 . is < double > ( ) )
return not_equal ( arg1 . get < double > ( ) , arg2 . get < double > ( ) , msg ) ;
else
return not_equal ( arg1 . get < std : : string > ( ) , arg2 . get < std : : string > ( ) , msg ) ;
}
std : : string well_msg ( const std : : string & well , const std : : string & msg ) {
return " Well: " + well + " " + msg ;
}
2020-03-26 19:45:32 +01:00
std : : string well_segment_msg ( const std : : string & well , int segment_number , const std : : string & msg ) {
return " Well: " + well + " Segment: " + std : : to_string ( segment_number ) + " " + msg ;
}
2020-03-13 07:36:17 +01:00
2020-03-27 10:18:38 +01:00
std : : string well_connection_msg ( const std : : string & well , const Connection & conn , const std : : string & msg ) {
return " Well: " + well + " Connection: " + std : : to_string ( conn . getI ( ) ) + " , " + std : : to_string ( conn . getJ ( ) ) + " , " + std : : to_string ( conn . getK ( ) ) + " " + msg ;
}
2020-03-13 07:36:17 +01:00
}
bool Schedule : : cmp ( const Schedule & sched1 , const Schedule & sched2 , std : : size_t report_step ) {
int count = not_equal ( sched1 . wellNames ( report_step ) , sched2 . wellNames ( report_step ) , " Wellnames " ) ;
if ( count ! = 0 )
return false ;
2020-03-13 12:18:08 +01:00
{
const auto & tm1 = sched1 . getTimeMap ( ) ;
const auto & tm2 = sched2 . getTimeMap ( ) ;
if ( not_equal ( tm1 . size ( ) , tm2 . size ( ) , " TimeMap: size() " ) )
count + = 1 ;
for ( auto & step_index = report_step ; step_index < std : : min ( tm1 . size ( ) , tm2 . size ( ) ) - 1 ; step_index + + ) {
if ( not_equal ( tm1 [ step_index ] , tm2 [ step_index ] , " TimePoint[ " + std : : to_string ( step_index ) + " ] " ) )
count + = 1 ;
}
}
2020-03-13 07:36:17 +01:00
for ( const auto & wname : sched1 . wellNames ( report_step ) ) {
const auto & well1 = sched1 . getWell ( wname , report_step ) ;
const auto & well2 = sched2 . getWell ( wname , report_step ) ;
int well_count = 0 ;
{
const auto & connections2 = well2 . getConnections ( ) ;
const auto & connections1 = well1 . getConnections ( ) ;
2020-03-18 13:56:26 +01:00
well_count + = not_equal ( connections1 . ordering ( ) , connections2 . ordering ( ) , well_msg ( well1 . name ( ) , " Connection: ordering " ) ) ;
2020-03-13 07:36:17 +01:00
for ( std : : size_t icon = 0 ; icon < connections1 . size ( ) ; icon + + ) {
const auto & conn1 = connections1 [ icon ] ;
const auto & conn2 = connections2 [ icon ] ;
2020-03-27 10:18:38 +01:00
well_count + = not_equal ( conn1 . getI ( ) , conn2 . getI ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " I " ) ) ;
well_count + = not_equal ( conn1 . getJ ( ) , conn2 . getJ ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " J " ) ) ;
well_count + = not_equal ( conn1 . getK ( ) , conn2 . getK ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " K " ) ) ;
well_count + = not_equal ( conn1 . state ( ) , conn2 . state ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " State " ) ) ;
well_count + = not_equal ( conn1 . dir ( ) , conn2 . dir ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " dir " ) ) ;
well_count + = not_equal ( conn1 . complnum ( ) , conn2 . complnum ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " complnum " ) ) ;
well_count + = not_equal ( conn1 . segment ( ) , conn2 . segment ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " segment " ) ) ;
well_count + = not_equal ( conn1 . kind ( ) , conn2 . kind ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " CFKind " ) ) ;
well_count + = not_equal ( conn1 . sort_value ( ) , conn2 . sort_value ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " sort_value " ) ) ;
well_count + = not_equal ( conn1 . CF ( ) , conn2 . CF ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " CF " ) ) ;
well_count + = not_equal ( conn1 . Kh ( ) , conn2 . Kh ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " Kh " ) ) ;
well_count + = not_equal ( conn1 . rw ( ) , conn2 . rw ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " rw " ) ) ;
well_count + = not_equal ( conn1 . depth ( ) , conn2 . depth ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " depth " ) ) ;
//well_count += not_equal( conn1.r0(), conn2.r0(), well_connection_msg(well1.name(), conn1, "r0"));
well_count + = not_equal ( conn1 . skinFactor ( ) , conn2 . skinFactor ( ) , well_connection_msg ( well1 . name ( ) , conn1 , " skinFactor " ) ) ;
2020-03-13 07:36:17 +01:00
}
}
if ( not_equal ( well1 . isMultiSegment ( ) , well2 . isMultiSegment ( ) , well_msg ( well1 . name ( ) , " Is MSW " ) ) )
return false ;
if ( well1 . isMultiSegment ( ) ) {
const auto & segments1 = well1 . getSegments ( ) ;
const auto & segments2 = well2 . getSegments ( ) ;
if ( not_equal ( segments1 . size ( ) , segments2 . size ( ) , " Segments: size " ) )
return false ;
for ( std : : size_t iseg = 0 ; iseg < segments1 . size ( ) ; iseg + + ) {
const auto & segment1 = segments1 [ iseg ] ;
const auto & segment2 = segments2 [ iseg ] ;
2020-03-26 19:45:32 +01:00
//const auto& segment2 = segments2.getFromSegmentNumber(segment1.segmentNumber());
well_count + = not_equal ( segment1 . segmentNumber ( ) , segment2 . segmentNumber ( ) , well_segment_msg ( well1 . name ( ) , segment1 . segmentNumber ( ) , " segmentNumber " ) ) ;
well_count + = not_equal ( segment1 . branchNumber ( ) , segment2 . branchNumber ( ) , well_segment_msg ( well1 . name ( ) , segment1 . segmentNumber ( ) , " branchNumber " ) ) ;
well_count + = not_equal ( segment1 . outletSegment ( ) , segment2 . outletSegment ( ) , well_segment_msg ( well1 . name ( ) , segment1 . segmentNumber ( ) , " outletSegment " ) ) ;
well_count + = not_equal ( segment1 . totalLength ( ) , segment2 . totalLength ( ) , well_segment_msg ( well1 . name ( ) , segment1 . segmentNumber ( ) , " totalLength " ) ) ;
well_count + = not_equal ( segment1 . depth ( ) , segment2 . depth ( ) , well_segment_msg ( well1 . name ( ) , segment1 . segmentNumber ( ) , " depth " ) ) ;
well_count + = not_equal ( segment1 . internalDiameter ( ) , segment2 . internalDiameter ( ) , well_segment_msg ( well1 . name ( ) , segment1 . segmentNumber ( ) , " internalDiameter " ) ) ;
well_count + = not_equal ( segment1 . roughness ( ) , segment2 . roughness ( ) , well_segment_msg ( well1 . name ( ) , segment1 . segmentNumber ( ) , " roughness " ) ) ;
well_count + = not_equal ( segment1 . crossArea ( ) , segment2 . crossArea ( ) , well_segment_msg ( well1 . name ( ) , segment1 . segmentNumber ( ) , " crossArea " ) ) ;
well_count + = not_equal ( segment1 . volume ( ) , segment2 . volume ( ) , well_segment_msg ( well1 . name ( ) , segment1 . segmentNumber ( ) , " volume " ) ) ;
2020-03-13 07:36:17 +01:00
}
}
2020-03-30 16:02:40 +02:00
well_count + = not_equal ( well1 . getStatus ( ) , well2 . getStatus ( ) , well_msg ( well1 . name ( ) , " status " ) ) ;
2020-03-13 07:36:17 +01:00
{
const auto & prod1 = well1 . getProductionProperties ( ) ;
const auto & prod2 = well2 . getProductionProperties ( ) ;
well_count + = not_equal ( prod1 . name , prod2 . name , well_msg ( well1 . name ( ) , " Prod: name " ) ) ;
well_count + = not_equal ( prod1 . OilRate , prod2 . OilRate , well_msg ( well1 . name ( ) , " Prod: OilRate " ) ) ;
well_count + = not_equal ( prod1 . GasRate , prod2 . GasRate , well_msg ( well1 . name ( ) , " Prod: GasRate " ) ) ;
well_count + = not_equal ( prod1 . WaterRate , prod2 . WaterRate , well_msg ( well1 . name ( ) , " Prod: WaterRate " ) ) ;
well_count + = not_equal ( prod1 . LiquidRate , prod2 . LiquidRate , well_msg ( well1 . name ( ) , " Prod: LiquidRate " ) ) ;
well_count + = not_equal ( prod1 . ResVRate , prod2 . ResVRate , well_msg ( well1 . name ( ) , " Prod: ResVRate " ) ) ;
well_count + = not_equal ( prod1 . BHPTarget , prod2 . BHPTarget , well_msg ( well1 . name ( ) , " Prod: BHPTarget " ) ) ;
well_count + = not_equal ( prod1 . THPTarget , prod2 . THPTarget , well_msg ( well1 . name ( ) , " Prod: THPTarget " ) ) ;
2020-03-30 16:02:40 +02:00
well_count + = not_equal ( prod1 . VFPTableNumber , prod2 . VFPTableNumber , well_msg ( well1 . name ( ) , " Prod: VFPTableNumber " ) ) ;
well_count + = not_equal ( prod1 . ALQValue , prod2 . ALQValue , well_msg ( well1 . name ( ) , " Prod: ALQValue " ) ) ;
2020-03-27 12:40:47 +01:00
well_count + = not_equal ( prod1 . predictionMode , prod2 . predictionMode , well_msg ( well1 . name ( ) , " Prod: predictionMode " ) ) ;
if ( ! prod1 . predictionMode ) {
well_count + = not_equal ( prod1 . bhp_hist_limit , prod2 . bhp_hist_limit , well_msg ( well1 . name ( ) , " Prod: bhp_hist_limit " ) ) ;
well_count + = not_equal ( prod1 . thp_hist_limit , prod2 . thp_hist_limit , well_msg ( well1 . name ( ) , " Prod: thp_hist_limit " ) ) ;
well_count + = not_equal ( prod1 . BHPH , prod2 . BHPH , well_msg ( well1 . name ( ) , " Prod: BHPH " ) ) ;
well_count + = not_equal ( prod1 . THPH , prod2 . THPH , well_msg ( well1 . name ( ) , " Prod: THPH " ) ) ;
}
2020-03-13 07:36:17 +01:00
well_count + = not_equal ( prod1 . productionControls ( ) , prod2 . productionControls ( ) , well_msg ( well1 . name ( ) , " Prod: productionControls " ) ) ;
2020-03-30 16:02:40 +02:00
if ( well1 . getStatus ( ) = = Well : : Status : : OPEN )
well_count + = not_equal ( prod1 . controlMode , prod2 . controlMode , well_msg ( well1 . name ( ) , " Prod: controlMode " ) ) ;
2020-03-13 07:36:17 +01:00
well_count + = not_equal ( prod1 . whistctl_cmode , prod2 . whistctl_cmode , well_msg ( well1 . name ( ) , " Prod: whistctl_cmode " ) ) ;
}
{
const auto & inj1 = well1 . getInjectionProperties ( ) ;
const auto & inj2 = well2 . getInjectionProperties ( ) ;
well_count + = not_equal ( inj1 . name , inj2 . name , well_msg ( well1 . name ( ) , " Well::Inj: name " ) ) ;
well_count + = not_equal ( inj1 . surfaceInjectionRate , inj2 . surfaceInjectionRate , well_msg ( well1 . name ( ) , " Well::Inj: surfaceInjectionRate " ) ) ;
well_count + = not_equal ( inj1 . reservoirInjectionRate , inj2 . reservoirInjectionRate , well_msg ( well1 . name ( ) , " Well::Inj: reservoirInjectionRate " ) ) ;
well_count + = not_equal ( inj1 . BHPTarget , inj2 . BHPTarget , well_msg ( well1 . name ( ) , " Well::Inj: BHPTarget " ) ) ;
well_count + = not_equal ( inj1 . THPTarget , inj2 . THPTarget , well_msg ( well1 . name ( ) , " Well::Inj: THPTarget " ) ) ;
well_count + = not_equal ( inj1 . bhp_hist_limit , inj2 . bhp_hist_limit , well_msg ( well1 . name ( ) , " Well::Inj: bhp_hist_limit " ) ) ;
well_count + = not_equal ( inj1 . thp_hist_limit , inj2 . thp_hist_limit , well_msg ( well1 . name ( ) , " Well::Inj: thp_hist_limit " ) ) ;
well_count + = not_equal ( inj1 . BHPH , inj2 . BHPH , well_msg ( well1 . name ( ) , " Well::Inj: BHPH " ) ) ;
well_count + = not_equal ( inj1 . THPH , inj2 . THPH , well_msg ( well1 . name ( ) , " Well::Inj: THPH " ) ) ;
well_count + = not_equal ( inj1 . VFPTableNumber , inj2 . VFPTableNumber , well_msg ( well1 . name ( ) , " Well::Inj: VFPTableNumber " ) ) ;
well_count + = not_equal ( inj1 . predictionMode , inj2 . predictionMode , well_msg ( well1 . name ( ) , " Well::Inj: predictionMode " ) ) ;
well_count + = not_equal ( inj1 . injectionControls , inj2 . injectionControls , well_msg ( well1 . name ( ) , " Well::Inj: injectionControls " ) ) ;
well_count + = not_equal ( inj1 . injectorType , inj2 . injectorType , well_msg ( well1 . name ( ) , " Well::Inj: injectorType " ) ) ;
well_count + = not_equal ( inj1 . controlMode , inj2 . controlMode , well_msg ( well1 . name ( ) , " Well::Inj: controlMode " ) ) ;
}
{
well_count + = well2 . firstTimeStep ( ) > report_step ;
well_count + = not_equal ( well1 . groupName ( ) , well2 . groupName ( ) , well_msg ( well1 . name ( ) , " Well: groupName " ) ) ;
well_count + = not_equal ( well1 . getHeadI ( ) , well2 . getHeadI ( ) , well_msg ( well1 . name ( ) , " Well: getHeadI " ) ) ;
well_count + = not_equal ( well1 . getHeadJ ( ) , well2 . getHeadJ ( ) , well_msg ( well1 . name ( ) , " Well: getHeadJ " ) ) ;
well_count + = not_equal ( well1 . getRefDepth ( ) , well2 . getRefDepth ( ) , well_msg ( well1 . name ( ) , " Well: getRefDepth " ) ) ;
well_count + = not_equal ( well1 . isMultiSegment ( ) , well2 . isMultiSegment ( ) , well_msg ( well1 . name ( ) , " Well: isMultiSegment " ) ) ;
well_count + = not_equal ( well1 . isAvailableForGroupControl ( ) , well2 . isAvailableForGroupControl ( ) , well_msg ( well1 . name ( ) , " Well: isAvailableForGroupControl " ) ) ;
well_count + = not_equal ( well1 . getGuideRate ( ) , well2 . getGuideRate ( ) , well_msg ( well1 . name ( ) , " Well: getGuideRate " ) ) ;
well_count + = not_equal ( well1 . getGuideRatePhase ( ) , well2 . getGuideRatePhase ( ) , well_msg ( well1 . name ( ) , " Well: getGuideRatePhase " ) ) ;
well_count + = not_equal ( well1 . getGuideRateScalingFactor ( ) , well2 . getGuideRateScalingFactor ( ) , well_msg ( well1 . name ( ) , " Well: getGuideRateScalingFactor " ) ) ;
well_count + = not_equal ( well1 . predictionMode ( ) , well2 . predictionMode ( ) , well_msg ( well1 . name ( ) , " Well: predictionMode " ) ) ;
well_count + = not_equal ( well1 . canOpen ( ) , well2 . canOpen ( ) , well_msg ( well1 . name ( ) , " Well: canOpen " ) ) ;
well_count + = not_equal ( well1 . isProducer ( ) , well2 . isProducer ( ) , well_msg ( well1 . name ( ) , " Well: isProducer " ) ) ;
well_count + = not_equal ( well1 . isInjector ( ) , well2 . isInjector ( ) , well_msg ( well1 . name ( ) , " Well: isInjector " ) ) ;
if ( well1 . isInjector ( ) )
well_count + = not_equal ( well1 . injectorType ( ) , well2 . injectorType ( ) , well_msg ( well1 . name ( ) , " Well1: injectorType " ) ) ;
well_count + = not_equal ( well1 . seqIndex ( ) , well2 . seqIndex ( ) , well_msg ( well1 . name ( ) , " Well: seqIndex " ) ) ;
well_count + = not_equal ( well1 . getAutomaticShutIn ( ) , well2 . getAutomaticShutIn ( ) , well_msg ( well1 . name ( ) , " Well: getAutomaticShutIn " ) ) ;
well_count + = not_equal ( well1 . getAllowCrossFlow ( ) , well2 . getAllowCrossFlow ( ) , well_msg ( well1 . name ( ) , " Well: getAllowCrossFlow " ) ) ;
well_count + = not_equal ( well1 . getSolventFraction ( ) , well2 . getSolventFraction ( ) , well_msg ( well1 . name ( ) , " Well: getSolventFraction " ) ) ;
well_count + = not_equal ( well1 . getStatus ( ) , well2 . getStatus ( ) , well_msg ( well1 . name ( ) , " Well: getStatus " ) ) ;
//well_count += not_equal( well1.getInjectionProperties(), well2.getInjectionProperties(), "Well: getInjectionProperties");
if ( well1 . isProducer ( ) )
well_count + = not_equal ( well1 . getPreferredPhase ( ) , well2 . getPreferredPhase ( ) , well_msg ( well1 . name ( ) , " Well: getPreferredPhase " ) ) ;
well_count + = not_equal ( well1 . getDrainageRadius ( ) , well2 . getDrainageRadius ( ) , well_msg ( well1 . name ( ) , " Well: getDrainageRadius " ) ) ;
well_count + = not_equal ( well1 . getEfficiencyFactor ( ) , well2 . getEfficiencyFactor ( ) , well_msg ( well1 . name ( ) , " Well: getEfficiencyFactor " ) ) ;
}
count + = well_count ;
if ( well_count > 0 )
std : : cerr < < std : : endl ;
}
return ( count = = 0 ) ;
}
2020-11-11 11:11:44 +01:00
2021-01-05 12:16:44 +01:00
const ScheduleState & Schedule : : operator [ ] ( std : : size_t index ) const {
return this - > snapshots . at ( index ) ;
}
std : : vector < ScheduleState > : : const_iterator Schedule : : begin ( ) const {
return this - > snapshots . begin ( ) ;
}
std : : vector < ScheduleState > : : const_iterator Schedule : : end ( ) const {
return this - > snapshots . end ( ) ;
}
2021-01-07 08:22:08 +01:00
void Schedule : : create_first ( const std : : chrono : : system_clock : : time_point & start_time , const std : : optional < std : : chrono : : system_clock : : time_point > & end_time ) {
if ( end_time . has_value ( ) )
this - > snapshots . emplace_back ( start_time , end_time . value ( ) ) ;
else
this - > snapshots . emplace_back ( start_time ) ;
auto & sched_state = snapshots . back ( ) ;
sched_state . nupcol ( this - > m_runspec . nupcol ( ) ) ;
2021-01-07 09:36:15 +01:00
sched_state . oilvap ( OilVaporizationProperties ( this - > m_runspec . tabdims ( ) . getNumPVTTables ( ) ) ) ;
2021-01-07 08:22:08 +01:00
}
2021-01-07 09:36:15 +01:00
void Schedule : : create_next ( const std : : chrono : : system_clock : : time_point & start_time , const std : : optional < std : : chrono : : system_clock : : time_point > & end_time ) {
2021-01-07 08:22:08 +01:00
if ( this - > snapshots . empty ( ) )
this - > create_first ( start_time , end_time ) ;
else {
2021-01-05 12:16:44 +01:00
const auto & last = this - > snapshots . back ( ) ;
if ( end_time . has_value ( ) )
this - > snapshots . emplace_back ( last , start_time , end_time . value ( ) ) ;
else
this - > snapshots . emplace_back ( last , start_time ) ;
}
}
2020-11-11 11:11:44 +01:00
2021-01-07 09:36:15 +01:00
void Schedule : : create_next ( const ScheduleBlock & block ) {
const auto & start_time = block . start_time ( ) ;
const auto & end_time = block . end_time ( ) ;
this - > create_next ( start_time , end_time ) ;
}
2019-07-24 10:20:38 +02:00
}