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>
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>
2021-01-30 14:51:55 +01:00
# include <fnmatch.h>
2020-09-27 23:25:16 +02:00
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
2021-04-23 15:50:22 +02:00
# include <opm/io/eclipse/rst/state.hpp>
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>
2021-04-23 11:34:58 +02:00
# include <opm/parser/eclipse/Parser/ParserKeywords/E.hpp>
2020-03-16 16:02:05 +01:00
# include <opm/parser/eclipse/Parser/ParserKeywords/P.hpp>
2021-09-09 11:48:21 +02:00
# include <opm/parser/eclipse/Parser/ParserKeywords/R.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>
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>
2021-01-12 18:29:27 +01:00
# include <opm/parser/eclipse/EclipseState/Schedule/Group/GConSump.hpp>
# include <opm/parser/eclipse/EclipseState/Schedule/Group/GConSale.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>
# 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>
2021-10-06 19:24:06 +02:00
# include <opm/parser/eclipse/EclipseState/Schedule/Well/WellMICPProperties.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
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 ) ;
}
2021-09-09 11:48:21 +02:00
double sumthin_summary_section ( const Opm : : SUMMARYSection & section ) {
const auto entries = section . getKeywordList < Opm : : ParserKeywords : : SUMTHIN > ( ) ;
// Care only about the last SUMTHIN entry in the SUMMARY
// section if keyword is present here at all.
return entries . empty ( )
? - 1.0 // (<= 0.0)
: entries . back ( ) - > getRecord ( 0 ) . getItem ( 0 ) . getSIDouble ( 0 ) ;
}
bool rptonly_summary_section ( const Opm : : SUMMARYSection & section ) {
auto rptonly = false ;
using On = Opm : : ParserKeywords : : RPTONLY ;
using Off = Opm : : ParserKeywords : : RPTONLYO ;
// Last on/off keyword entry "wins".
for ( const auto & keyword : section ) {
if ( keyword . name ( ) = = On : : keywordName )
rptonly = true ;
else if ( keyword . name ( ) = = Off : : keywordName )
rptonly = false ;
}
return rptonly ;
}
2019-07-07 08:46:17 +02:00
}
2021-09-09 11:48:21 +02:00
namespace Opm {
2021-04-23 15:50:22 +02:00
ScheduleStatic : : ScheduleStatic ( std : : shared_ptr < const Python > python_handle ,
2021-07-22 07:54:34 +02:00
const ScheduleRestartInfo & restart_info ,
2021-04-23 15:50:22 +02:00
const Deck & deck ,
const Runspec & runspec ,
const std : : optional < int > & output_interval_ ,
const ParseContext & parseContext ,
ErrorGuard & errors ) :
m_python_handle ( python_handle ) ,
m_input_path ( deck . getInputPath ( ) ) ,
2021-07-22 07:54:34 +02:00
rst_info ( restart_info ) ,
2021-04-23 15:50:22 +02:00
m_deck_message_limits ( deck ) ,
m_unit_system ( deck . getActiveUnitSystem ( ) ) ,
m_runspec ( runspec ) ,
rst_config ( SOLUTIONSection ( deck ) , parseContext , errors ) ,
2021-09-09 11:48:21 +02:00
output_interval ( output_interval_ ) ,
sumthin ( sumthin_summary_section ( SUMMARYSection { deck } ) ) ,
rptonly ( rptonly_summary_section ( SUMMARYSection { deck } ) )
2021-04-23 15:50:22 +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 ,
2021-07-22 07:02:33 +02:00
std : : shared_ptr < const Python > python ,
2021-03-08 17:39:37 +01:00
const std : : optional < int > & output_interval ,
2020-09-27 23:25:16 +02:00
const RestartIO : : RstState * rst )
try :
2021-07-22 07:54:34 +02:00
m_static ( python , ScheduleRestartInfo ( rst , deck ) , deck , runspec , output_interval , parseContext , errors ) ,
2021-09-19 11:22:14 +02:00
m_sched_deck ( runspec , deck , m_static . rst_info )
2016-05-02 17:46:20 +02:00
{
2021-07-06 17:42:24 +02:00
this - > restart_output . resize ( this - > m_sched_deck . size ( ) ) ;
this - > restart_output . clearRemainingEvents ( 0 ) ;
2021-01-13 13:41:10 +01:00
if ( rst ) {
2021-07-22 07:54:34 +02:00
auto restart_step = this - > m_static . rst_info . report_step ;
2021-09-01 15:44:25 +02:00
this - > iterateScheduleSection ( 0 , restart_step , parseContext , errors , nullptr , & grid , & fp , " " ) ;
2020-11-02 16:11:35 +01:00
this - > load_rst ( * rst , grid , fp ) ;
2021-07-06 17:42:24 +02:00
if ( ! this - > restart_output . writeRestartFile ( restart_step ) )
this - > restart_output . addRestartOutput ( restart_step ) ;
2021-09-01 15:44:25 +02:00
this - > iterateScheduleSection ( restart_step , this - > m_sched_deck . size ( ) , parseContext , errors , nullptr , & grid , & fp , " " ) ;
2021-01-13 13:41:10 +01:00
} else
2021-09-01 15:44:25 +02:00
this - > iterateScheduleSection ( 0 , this - > m_sched_deck . size ( ) , parseContext , errors , nullptr , & grid , & fp , " " ) ;
2013-11-14 16:08:10 +01:00
}
2020-09-27 23:25:16 +02:00
catch ( const OpmInputError & opm_error ) {
2021-07-22 06:55:39 +02:00
OpmLog : : error ( opm_error . what ( ) ) ;
2020-09-27 23:25:16 +02:00
throw ;
}
catch ( const std : : exception & std_error ) {
2021-06-11 15:31:00 +02:00
OpmLog : : error ( fmt : : format ( " An error occurred 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 ,
2021-03-08 17:39:37 +01:00
const std : : optional < int > & output_interval ,
2020-01-28 13:03:07 +01:00
const RestartIO : : RstState * rst ) :
2021-03-08 17:39:37 +01:00
Schedule ( deck , grid , fp , runspec , parseContext , errors , python , output_interval , 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 ,
2021-03-08 17:39:37 +01:00
const std : : optional < int > & output_interval ,
2020-01-28 13:03:07 +01:00
const RestartIO : : RstState * rst ) :
2021-03-08 17:39:37 +01:00
Schedule ( deck , grid , fp , runspec , ParseContext ( ) , ErrorGuard ( ) , python , output_interval , rst )
2019-01-03 18:05:19 +01:00
{ }
2021-03-08 17:39:37 +01:00
Schedule : : Schedule ( const Deck & deck , const EclipseState & es , const ParseContext & parse_context , ErrorGuard & errors , std : : shared_ptr < const Python > python , const std : : optional < int > & output_interval , 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 ,
2021-03-08 17:39:37 +01:00
output_interval ,
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 >
2021-03-08 17:39:37 +01:00
Schedule : : Schedule ( const Deck & deck , const EclipseState & es , const ParseContext & parse_context , T & & errors , std : : shared_ptr < const Python > python , const std : : optional < int > & output_interval , 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 ,
2021-03-08 17:39:37 +01:00
output_interval ,
2020-01-28 13:03:07 +01:00
rst )
2019-01-03 18:05:19 +01:00
{ }
2021-03-08 17:39:37 +01:00
Schedule : : Schedule ( const Deck & deck , const EclipseState & es , std : : shared_ptr < const Python > python , const std : : optional < int > & output_interval , const RestartIO : : RstState * rst ) :
Schedule ( deck , es , ParseContext ( ) , ErrorGuard ( ) , python , output_interval , rst )
{ }
2019-01-03 18:05:19 +01:00
2018-04-24 14:03:29 +02:00
2021-03-08 17:39:37 +01:00
Schedule : : Schedule ( const Deck & deck , const EclipseState & es , const std : : optional < int > & output_interval , const RestartIO : : RstState * rst ) :
Schedule ( deck , es , ParseContext ( ) , ErrorGuard ( ) , std : : make_shared < const Python > ( ) , output_interval , rst )
2020-03-26 15:31:21 +01:00
{ }
2021-01-13 09:13:24 +01:00
Schedule : : Schedule ( std : : shared_ptr < const Python > python_handle ) :
m_static ( python_handle )
{
}
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 ( )
{
2021-01-13 09:13:24 +01:00
Schedule result ;
2020-04-10 09:15:05 +02:00
2021-01-13 09:13:24 +01:00
result . m_static = ScheduleStatic : : serializeObject ( ) ;
2021-01-05 12:16:44 +01:00
result . snapshots = { ScheduleState : : serializeObject ( ) } ;
2021-04-21 09:32:06 +02:00
result . m_sched_deck = ScheduleDeck : : serializeObject ( ) ;
2021-07-06 17:42:24 +02:00
result . restart_output = WriteRestartFileEvents : : 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 {
2021-02-19 13:41:24 +01:00
return std : : chrono : : system_clock : : to_time_t ( this - > m_sched_deck [ 0 ] . start_time ( ) ) ;
2015-10-02 10:49:23 +02:00
}
2016-09-12 14:28:19 +02:00
time_t Schedule : : posixEndTime ( ) const {
2021-02-19 13:41:24 +01:00
// This should indeed access the start_time() property of the last
// snapshot.
return std : : chrono : : system_clock : : to_time_t ( this - > snapshots . back ( ) . start_time ( ) ) ;
2013-11-14 16:08:10 +01:00
}
2018-07-11 13:54:49 +02:00
2021-01-08 10:03:20 +01:00
void Schedule : : handleKeyword ( 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 ,
2021-01-19 10:27:37 +01:00
const EclipseGrid * grid ,
const FieldPropsManager * fp ,
2021-02-03 08:31:59 +01:00
const std : : vector < std : : string > & matching_wells ,
2021-09-01 15:44:25 +02:00
bool actionx_mode ,
2021-03-25 12:00:08 +01:00
std : : unordered_set < std : : string > * affected_wells ,
2021-02-18 08:37:23 +01:00
const std : : unordered_map < std : : string , double > * target_wellpi ) {
2018-04-06 15:48:27 +02:00
2021-01-08 10:55:46 +01:00
static const std : : unordered_set < std : : string > require_grid = {
" COMPDAT " ,
" COMPSEGS "
} ;
2018-05-14 04:18:07 +02:00
2021-01-08 10:55:46 +01:00
2021-09-01 15:44:25 +02:00
HandlerContext handlerContext { block , keyword , currentStep , matching_wells , actionx_mode , affected_wells , target_wellpi } ;
2021-01-08 10:55:46 +01:00
/*
The grid and fieldProps members create problems for reiterating the
Schedule section . We therefor single them out very clearly here .
*/
if ( require_grid . count ( keyword . name ( ) ) > 0 ) {
2021-01-19 10:27:37 +01:00
handlerContext . grid_ptr = grid ;
handlerContext . fp_ptr = fp ;
2021-01-08 10:55:46 +01:00
}
2020-09-21 19:22:11 +02:00
if ( handleNormalKeyword ( handlerContext , parseContext , errors ) )
return ;
2020-08-31 18:24:09 +02:00
2021-02-18 08:37:23 +01:00
if ( keyword . name ( ) = = " PYACTION " )
2021-01-13 10:25:06 +01:00
handlePYACTION ( keyword ) ;
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 :
2021-08-16 16:47:20 +02:00
ScheduleLogger ( bool restart_skip , const std : : string & prefix_ , const KeywordLocation & location )
: prefix ( prefix_ )
, current_file ( location . filename )
2020-10-10 08:59:38 +02:00
{
if ( restart_skip )
this - > log_function = & OpmLog : : note ;
else
this - > log_function = & OpmLog : : info ;
}
void operator ( ) ( const std : : string & msg ) {
2021-08-23 23:01:08 +02:00
this - > log_function ( this - > prefix + msg ) ;
2020-10-10 08:59:38 +02:00
}
void info ( const std : : string & msg ) {
2021-08-16 16:47:20 +02:00
OpmLog : : info ( this - > prefix + msg ) ;
2020-10-10 08:59:38 +02:00
}
2021-08-16 16:47:20 +02:00
void info ( const std : : vector < std : : string > & msg_list ) {
for ( const auto & msg : msg_list )
this - > info ( msg ) ;
}
void complete_step ( const std : : string & msg ) {
2020-10-10 08:59:38 +02:00
this - > step_count + = 1 ;
if ( this - > step_count = = this - > max_print ) {
2021-08-23 23:01:08 +02:00
this - > log_function ( this - > prefix + msg ) ;
2021-08-16 16:47:20 +02:00
this - > info ( std : : vector < std : : string > { " Report limit reached, see PRT-file for remaining Schedule initialization. " , " " } ) ;
2020-10-10 08:59:38 +02:00
this - > log_function = & OpmLog : : note ;
2021-08-16 16:47:20 +02:00
} else {
2021-08-23 23:01:08 +02:00
this - > log_function ( this - > prefix + msg ) ;
this - > log_function ( this - > prefix ) ;
2021-08-16 16:47:20 +02:00
}
2020-10-10 08:59:38 +02:00
} ;
void restart ( ) {
this - > step_count = 0 ;
this - > log_function = & OpmLog : : info ;
}
2021-08-16 16:47:20 +02:00
void location ( const KeywordLocation & location ) {
if ( this - > current_file = = location . filename )
return ;
this - > operator ( ) ( fmt : : format ( " Reading from: {} line {} " , location . filename , location . lineno ) ) ;
this - > current_file = location . filename ;
}
2020-10-10 08:59:38 +02:00
private :
std : : size_t step_count = 0 ;
std : : size_t max_print = 5 ;
2021-08-16 16:47:20 +02:00
std : : string prefix ;
std : : string current_file ;
2020-10-10 08:59:38 +02:00
void ( * log_function ) ( const std : : string & ) ;
} ;
}
2018-04-12 19:02:15 +02:00
2021-01-13 13:41:10 +01:00
void Schedule : : iterateScheduleSection ( std : : size_t load_start , std : : size_t load_end ,
2021-01-08 10:03:20 +01:00
const ParseContext & parseContext ,
ErrorGuard & errors ,
2021-02-12 12:56:28 +01:00
const std : : unordered_map < std : : string , double > * target_wellpi ,
2021-01-19 10:27:37 +01:00
const EclipseGrid * grid ,
2021-03-19 18:14:37 +01:00
const FieldPropsManager * fp ,
const std : : string & prefix ) {
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 ;
2021-01-13 09:13:24 +01:00
std : : string time_unit = this - > m_static . m_unit_system . name ( UnitSystem : : measure : : time ) ;
auto deck_time = [ this ] ( double seconds ) { return this - > m_static . m_unit_system . from_si ( UnitSystem : : measure : : time , seconds ) ; } ;
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
/*
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
2021-02-19 13:41:24 +01:00
we will have Schedule : : restart_offset ( ) = = 0.
2020-09-29 22:01:24 +02:00
[ 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
2021-07-22 07:54:34 +02:00
auto restart_skip = load_start < this - > m_static . rst_info . report_step ;
2021-08-16 16:47:20 +02:00
ScheduleLogger logger ( restart_skip , prefix , this - > m_sched_deck . location ( ) ) ;
2020-10-10 08:59:38 +02:00
{
2021-01-04 11:34:22 +01:00
const auto & location = this - > m_sched_deck . location ( ) ;
2021-08-16 16:47:20 +02:00
logger . info ( { " " , " Processing dynamic information from " , fmt : : format ( " {} line {} " , location . filename , location . lineno ) } ) ;
2021-07-22 07:54:34 +02:00
if ( restart_skip )
2021-08-16 16:47:20 +02:00
logger . info ( fmt : : format ( " This is a restarted run - skipping until report step {} at {} " , this - > m_static . rst_info . report_step , Schedule : : formatDate ( this - > m_static . rst_info . time ) ) ) ;
2021-07-22 07:54:34 +02:00
2021-08-16 16:47:20 +02:00
logger ( fmt : : format ( " Initializing report step {}/{} at {} {} {} line {} " ,
load_start ,
2021-02-28 16:50:49 +01:00
this - > m_sched_deck . size ( ) - 1 ,
2020-10-10 08:59:38 +02:00
Schedule : : formatDate ( this - > getStartTime ( ) ) ,
2021-02-28 16:50:49 +01:00
deck_time ( this - > m_sched_deck . seconds ( load_start ) ) ,
2020-10-10 08:59:38 +02:00
time_unit ,
location . lineno ) ) ;
}
2020-09-29 22:01:24 +02:00
2021-01-13 13:41:10 +01:00
for ( auto report_step = load_start ; report_step < load_end ; report_step + + ) {
2021-01-04 11:34:22 +01:00
std : : size_t keyword_index = 0 ;
2021-01-13 13:41:10 +01:00
auto & block = this - > m_sched_deck [ report_step ] ;
2021-01-04 11:34:22 +01:00
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-13 13:41:10 +01:00
const auto & days = deck_time ( this - > stepLength ( report_step - 1 ) ) ;
2021-02-28 17:04:35 +01:00
const auto & days_total = deck_time ( this - > seconds ( report_step - 1 ) ) ;
2021-08-16 16:47:20 +02:00
logger . complete_step ( fmt : : format ( " Complete report step {0} ({1} {2}) at {3} ({4} {2}) " ,
report_step ,
days ,
time_unit ,
start_date ,
days_total ) ) ;
if ( report_step < ( load_end - 1 ) ) {
logger . location ( block . location ( ) ) ;
logger ( fmt : : format ( " Initializing report step {}/{} at {} ({} {}) line {} " ,
2021-03-29 12:27:25 +02:00
report_step + 1 ,
this - > m_sched_deck . size ( ) - 1 ,
start_date ,
days_total ,
time_unit ,
block . location ( ) . lineno ) ) ;
2021-08-16 16:47:20 +02:00
}
2020-10-10 08:59:38 +02:00
}
2021-01-13 13:41:10 +01:00
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 ( ) ;
2021-08-16 16:47:20 +02:00
logger . location ( keyword . location ( ) ) ;
2020-09-29 22:01:24 +02:00
2021-01-04 11:34:22 +01:00
if ( keyword . name ( ) = = " ACTIONX " ) {
2021-09-18 18:46:12 +02:00
Action : : ActionX action ( keyword ,
this - > m_static . m_runspec . actdims ( ) ,
std : : chrono : : system_clock : : to_time_t ( this - > snapshots [ report_step ] . start_time ( ) ) ) ;
2021-01-04 11:34:22 +01:00
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-13 10:25:06 +01:00
this - > addACTIONX ( action ) ;
2021-01-04 11:34:22 +01:00
keyword_index + + ;
continue ;
2015-10-30 12:55:17 +01:00
}
2021-01-04 11:34:22 +01:00
2021-08-16 16:47:20 +02:00
logger ( fmt : : format ( " Processing keyword {} at line {} " , location . keyword , location . lineno ) ) ;
2021-01-13 13:41:10 +01:00
this - > handleKeyword ( report_step ,
2021-01-04 11:34:22 +01:00
block ,
keyword ,
parseContext ,
errors ,
grid ,
fp ,
2021-02-03 08:31:59 +01:00
{ } ,
2021-09-01 15:44:25 +02:00
false ,
2021-03-25 12:00:08 +01:00
nullptr ,
2021-02-18 08:37:23 +01:00
target_wellpi ) ;
2021-01-04 11:34:22 +01:00
keyword_index + + ;
2020-01-28 20:31:24 +01:00
}
2021-01-05 12:16:44 +01:00
2021-09-01 15:43:52 +02:00
this - > end_report ( report_step ) ;
2021-07-06 17:42:24 +02:00
if ( this - > must_write_rst_file ( report_step ) ) {
this - > restart_output . addRestartOutput ( report_step ) ;
}
2013-11-05 15:25:47 +01:00
}
}
2021-01-13 10:25:06 +01:00
void Schedule : : addACTIONX ( const Action : : ActionX & action ) {
2021-01-27 10:55:35 +01:00
auto new_actions = this - > snapshots . back ( ) . actions . get ( ) ;
2021-01-13 10:25:06 +01:00
new_actions . add ( action ) ;
2021-01-27 10:55:35 +01:00
this - > snapshots . back ( ) . actions . update ( std : : move ( new_actions ) ) ;
2019-08-29 18:17:37 +02:00
}
2021-01-13 10:25:06 +01:00
void Schedule : : handlePYACTION ( const DeckKeyword & keyword ) {
2021-01-13 09:13:24 +01:00
if ( ! this - > m_static . m_python_handle - > enabled ( ) ) {
2020-03-22 21:02:32 +01:00
//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 ;
2021-01-13 09:13:24 +01:00
if ( this - > m_static . m_input_path . empty ( ) )
2020-03-22 21:02:32 +01:00
module = module_arg ;
else
2021-01-13 09:13:24 +01:00
module = this - > m_static . m_input_path + " / " + module_arg ;
2020-03-16 16:02:05 +01:00
2021-01-13 09:13:24 +01:00
Action : : PyAction pyaction ( this - > m_static . m_python_handle , name , run_count , module ) ;
2021-01-27 10:55:35 +01:00
auto new_actions = this - > snapshots . back ( ) . actions . get ( ) ;
2021-01-13 10:25:06 +01:00
new_actions . add ( pyaction ) ;
2021-01-27 10:55:35 +01:00
this - > snapshots . back ( ) . actions . update ( std : : move ( new_actions ) ) ;
2020-03-16 16:02:05 +01:00
}
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 ) {
2021-02-03 10:43:56 +01:00
this - > updateWellStatus ( well_name , report_step , 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 ) {
2021-02-03 10:43:56 +01:00
this - > updateWellStatus ( well_name , report_step , 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 ) {
2021-02-03 10:43:56 +01:00
this - > updateWellStatus ( well_name , report_step , Well : : Status : : STOP ) ;
2020-01-08 10:17:52 +01: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
*/
2021-02-03 08:31:59 +01:00
bool Schedule : : updateWellStatus ( const std : : string & well_name , std : : size_t reportStep , Well : : Status status , std : : optional < KeywordLocation > location ) {
auto well2 = this - > snapshots [ reportStep ] . wells . get ( well_name ) ;
if ( well2 . getConnections ( ) . empty ( ) & & status = = Well : : Status : : OPEN ) {
2020-11-17 10:17:45 +01:00
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 ;
}
2021-02-03 08:31:59 +01:00
auto old_status = well2 . getStatus ( ) ;
2020-11-17 10:17:45 +01:00
bool update = false ;
2021-02-03 08:31:59 +01:00
if ( well2 . updateStatus ( status ) ) {
2021-02-18 08:37:23 +01:00
if ( status = = Well : : Status : : OPEN ) {
auto new_rft = this - > snapshots . back ( ) . rft_config ( ) . well_open ( well_name ) ;
if ( new_rft . has_value ( ) )
this - > snapshots . back ( ) . rft_config . update ( std : : move ( * new_rft ) ) ;
}
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 ) {
2021-01-11 14:17:53 +01:00
this - > snapshots . back ( ) . events ( ) . addEvent ( ScheduleEvents : : WELL_STATUS_CHANGE ) ;
2021-02-03 08:31:59 +01:00
this - > snapshots . back ( ) . wellgroup_events ( ) . addEvent ( well2 . name ( ) , ScheduleEvents : : WELL_STATUS_CHANGE ) ;
2020-12-04 16:04:40 +01:00
}
2021-02-03 08:31:59 +01:00
this - > snapshots [ reportStep ] . wells . update ( std : : move ( well2 ) ) ;
2020-12-04 16:04:40 +01:00
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 ) {
2021-02-03 08:31:59 +01:00
auto new_well = this - > snapshots [ report_step ] . wells . get ( wname ) ;
new_well . updateWPAVE ( pavg ) ;
this - > snapshots [ report_step ] . wells . update ( std : : move ( new_well ) ) ;
2020-11-11 11:11:44 +01:00
return true ;
}
return false ;
}
2019-01-28 16:52:28 +01:00
2021-03-25 12:00:08 +01:00
void Schedule : : applyWELOPEN ( const DeckKeyword & keyword ,
std : : size_t currentStep ,
const ParseContext & parseContext ,
ErrorGuard & errors ,
const std : : vector < std : : string > & matching_wells ,
std : : unordered_set < std : : string > * affected_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 ( ) ) {
2021-02-19 13:41:24 +01:00
auto elapsed = this - > snapshots [ currentStep ] . start_time ( ) - this - > snapshots [ 0 ] . start_time ( ) ;
auto days = std : : chrono : : duration_cast < std : : chrono : : hours > ( elapsed ) . count ( ) / 24 ;
2020-09-25 11:54:25 +02:00
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 ) ;
2021-03-25 12:00:08 +01:00
} else {
2021-02-03 10:43:56 +01:00
this - > updateWellStatus ( wname , currentStep , well_status ) ;
2021-03-25 12:00:08 +01:00
if ( affected_wells )
affected_wells - > insert ( wname ) ;
}
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 ) {
2021-09-01 15:44:25 +02:00
{
2021-02-03 08:31:59 +01:00
auto well = this - > snapshots [ currentStep ] . wells . get ( wname ) ;
this - > snapshots [ currentStep ] . wells . update ( std : : move ( well ) ) ;
2020-12-08 09:20:44 +01:00
}
const auto connection_status = Connection : : StateFromString ( status_str ) ;
2020-09-25 11:54:25 +02:00
{
2021-02-03 08:31:59 +01:00
auto well = this - > snapshots [ currentStep ] . wells . get ( wname ) ;
2021-09-01 15:44:25 +02:00
well . handleWELOPENConnections ( record , connection_status ) ;
2021-02-03 08:31:59 +01:00
this - > snapshots [ currentStep ] . wells . update ( std : : move ( well ) ) ;
2019-03-23 16:11:37 +01:00
}
2020-09-25 11:19:31 +02:00
2021-03-25 12:00:08 +01:00
if ( affected_wells )
affected_wells - > insert ( wname ) ;
2021-01-11 14:17:53 +01:00
this - > snapshots . back ( ) . events ( ) . addEvent ( ScheduleEvents : : COMPLETION_CHANGE ) ;
2015-03-25 08:20:22 +01:00
}
}
}
2015-02-06 14:54:03 +01:00
2021-02-18 08:37:23 +01:00
std : : optional < std : : size_t > Schedule : : first_RFT ( ) const {
for ( std : : size_t report_step = 0 ; report_step < this - > snapshots . size ( ) ; report_step + + ) {
if ( this - > snapshots [ report_step ] . rft_config ( ) . active ( ) )
return report_step ;
2015-02-06 14:54:03 +01:00
}
2021-02-18 08:37:23 +01:00
return { } ;
2019-04-03 18:47:02 +02:00
}
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
}
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
}
2021-02-10 09:19:39 +01:00
void Schedule : : addWell ( Well well ) {
2020-02-14 14:18:22 +01:00
const std : : string wname = well . name ( ) ;
2021-01-27 10:55:35 +01:00
auto & sched_state = this - > snapshots . back ( ) ;
2020-02-14 14:18:22 +01:00
2021-01-27 10:55:35 +01:00
sched_state . events ( ) . addEvent ( ScheduleEvents : : NEW_WELL ) ;
sched_state . wellgroup_events ( ) . addWell ( wname ) ;
{
auto wo = sched_state . well_order . get ( ) ;
wo . add ( wname ) ;
sched_state . well_order . update ( std : : move ( wo ) ) ;
}
2021-02-03 08:31:59 +01:00
well . setInsertIndex ( sched_state . wells . size ( ) ) ;
sched_state . wells . update ( std : : move ( well ) ) ;
2020-02-14 14:18:22 +01:00
}
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
2021-01-11 20:55:09 +01:00
const auto & sched_state = this - > operator [ ] ( timeStep ) ;
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 ) ,
2021-01-11 20:55:09 +01:00
sched_state . whistctl ( ) ,
2020-02-14 14:18:22 +01:00
wellConnectionOrder ,
2021-01-13 09:13:24 +01:00
this - > m_static . m_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
2021-02-10 09:19:39 +01:00
this - > addWell ( std : : move ( well ) ) ;
2020-11-11 11:11:44 +01:00
2021-01-05 12:16:44 +01:00
const auto & ts = this - > operator [ ] ( timeStep ) ;
2021-01-27 10:55:35 +01:00
this - > updateWPAVE ( wellName , timeStep , ts . pavg . get ( ) ) ;
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 {
2021-02-03 08:31:59 +01:00
return this - > snapshots . back ( ) . wells . 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 {
2021-02-03 08:31:59 +01:00
return this - > snapshots . back ( ) . wells . has ( wellName ) ;
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 {
2021-02-03 08:31:59 +01:00
return this - > snapshots [ timeStep ] . wells . has ( wellName ) ;
2017-07-25 19:50:06 +02:00
}
2021-02-02 15:59:56 +01:00
bool Schedule : : hasGroup ( const std : : string & groupName , std : : size_t timeStep ) const {
return this - > snapshots [ timeStep ] . groups . has ( groupName ) ;
}
2020-09-25 12:51:36 +02:00
std : : vector < const Group * > Schedule : : getChildGroups2 ( const std : : string & group_name , std : : size_t timeStep ) const {
2021-01-30 14:51:55 +01:00
const auto & sched_state = this - > snapshots [ timeStep ] ;
const auto & group = sched_state . groups . get ( group_name ) ;
2019-03-23 16:11:37 +01:00
2020-09-25 11:55:03 +02:00
std : : vector < const Group * > child_groups ;
2021-01-30 14:51:55 +01:00
for ( const auto & child_name : group . groups ( ) )
child_groups . push_back ( std : : addressof ( this - > getGroup ( child_name , timeStep ) ) ) ;
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 {
2021-01-30 14:51:55 +01:00
const auto & sched_state = this - > snapshots [ timeStep ] ;
const auto & group = sched_state . groups . get ( group_name ) ;
std : : vector < Well > wells ;
2019-08-06 22:40:14 +02:00
2021-01-30 14:51:55 +01:00
if ( group . groups ( ) . size ( ) ) {
for ( const auto & child_name : group . groups ( ) ) {
const auto & child_wells = this - > getChildWells2 ( child_name , timeStep ) ;
wells . insert ( wells . end ( ) , child_wells . begin ( ) , child_wells . end ( ) ) ;
}
2020-09-25 11:55:03 +02:00
} else {
2021-01-30 14:51:55 +01:00
for ( const auto & well_name : group . wells ( ) ) {
wells . push_back ( this - > getWell ( well_name , timeStep ) ) ;
}
2018-04-25 09:44:57 +02:00
}
2021-01-30 14:51:55 +01:00
return wells ;
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 ;
2021-02-03 08:31:59 +01:00
const auto & state = this - > snapshots [ report_step ] ;
const auto & all_wells = state . wells ( ) ;
if ( report_step = = 0 )
std : : transform ( all_wells . begin ( ) , all_wells . end ( ) , std : : back_inserter ( wells ) , [ ] ( const auto & well_ref ) { return well_ref . get ( ) . name ( ) ; } ) ;
else {
const auto & prev_state = this - > snapshots [ report_step - 1 ] ;
for ( const auto & well_ref : all_wells ) {
const auto & wname = well_ref . get ( ) . name ( ) ;
if ( prev_state . wells . has ( wname ) ) {
const auto & prev_well = prev_state . wells . get ( wname ) ;
if ( ! prev_well . cmp_structure ( well_ref . get ( ) ) )
wells . push_back ( wname ) ;
} else
wells . push_back ( wname ) ;
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 ;
2021-02-19 13:41:24 +01:00
if ( timeStep > = this - > snapshots . size ( ) )
2019-05-04 12:00:32 +02:00
throw std : : invalid_argument ( " timeStep argument beyond the length of the simulation " ) ;
2016-06-16 08:37:10 +02:00
2021-01-28 17:08:43 +01:00
const auto & well_order = this - > snapshots [ timeStep ] . well_order ( ) ;
2021-02-03 08:31:59 +01:00
for ( const auto & wname : well_order )
wells . push_back ( this - > snapshots [ timeStep ] . wells . get ( wname ) ) ;
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 {
2021-02-03 08:31:59 +01:00
return this - > getWells ( this - > snapshots . 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 {
2021-02-03 08:31:59 +01:00
return this - > getWell ( well_name , this - > snapshots . 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 {
2021-02-03 08:31:59 +01:00
return this - > snapshots [ timeStep ] . wells . get ( wellName ) ;
2019-03-23 16:11:37 +01:00
}
2015-05-28 14:55:09 +02:00
2021-02-10 09:09:21 +01:00
const Well & Schedule : : getWell ( std : : size_t well_index , std : : size_t timeStep ) const {
const auto find_pred = [ well_index ] ( const auto & well_pair ) - > bool
{
return well_pair . second - > seqIndex ( ) = = well_index ;
} ;
auto well_ptr = this - > snapshots [ timeStep ] . wells . find ( find_pred ) ;
if ( well_ptr = = nullptr )
throw std : : invalid_argument ( fmt : : format ( " There is no well with well_index:{} at report_step:{} " , well_index , timeStep ) ) ;
return * well_ptr ;
}
2020-09-25 12:51:36 +02:00
const Group & Schedule : : getGroup ( const std : : string & groupName , std : : size_t timeStep ) const {
2021-01-30 14:51:55 +01:00
return this - > snapshots [ timeStep ] . groups . get ( groupName ) ;
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 ) {
2021-02-03 08:31:59 +01:00
auto new_config = this - > snapshots [ report_step ] . guide_rate ( ) ;
if ( new_config . update_model ( new_model ) )
this - > snapshots [ report_step ] . guide_rate . update ( std : : move ( new_config ) ) ;
2020-10-13 08:10:36 +02:00
}
2019-03-14 09:23:03 +01:00
/*
There are many SCHEDULE keyword which take a wellname as argument . In
addition to giving a fully qualified name like ' W1 ' you can also specify
shell wildcard patterns like like ' W * ' , you can get all the wells in the
well - list ' * WL ' [ 1 ] and the wellname ' ? ' is used to get all the wells which
already have matched a condition in a ACTIONX keyword . This function
should be one - stop function to get all well names according to a input
pattern . The timestep argument is used to check that the wells have
2019-05-04 12:00:32 +02:00
indeed been defined at the point in time we are considering .
2019-03-14 09:23:03 +01:00
[ 1 ] : The leading ' * ' in a WLIST name should not be interpreted as a shell
wildcard !
*/
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 {
2021-01-25 06:52:02 +01:00
const ScheduleState * sched_state ;
2021-01-12 18:48:34 +01:00
if ( report_step < this - > snapshots . size ( ) )
2021-01-25 06:52:02 +01:00
sched_state = & this - > snapshots [ report_step ] ;
2021-01-12 18:48:34 +01:00
else
2021-01-25 06:52:02 +01:00
sched_state = & this - > snapshots . back ( ) ;
2021-01-27 10:55:35 +01:00
return WellMatcher ( sched_state - > well_order . get ( ) , sched_state - > wlist_manager . get ( ) ) ;
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 {
2021-01-28 17:08:43 +01:00
const auto & well_order = this - > snapshots [ timeStep ] . well_order ( ) ;
2021-01-28 18:02:35 +01:00
return well_order . names ( ) ;
2019-03-24 07:53:30 +01:00
}
std : : vector < std : : string > Schedule : : wellNames ( ) const {
2021-01-30 08:40:51 +01:00
const auto & well_order = this - > snapshots . back ( ) . well_order ( ) ;
return well_order . 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 { } ;
2021-01-30 10:15:53 +01:00
const auto & group_order = this - > snapshots [ timeStep ] . group_order ( ) ;
2019-07-07 08:46:17 +02:00
// Normal pattern matching
auto star_pos = pattern . find ( ' * ' ) ;
if ( star_pos ! = std : : string : : npos ) {
std : : vector < std : : string > names ;
2021-01-30 10:15:53 +01:00
for ( const auto & gname : group_order ) {
if ( name_match ( pattern , gname ) )
names . push_back ( gname ) ;
2019-07-07 08:46:17 +02:00
}
return names ;
}
// Normal group name without any special characters
2021-01-30 10:15:53 +01:00
if ( group_order . has ( pattern ) )
return { pattern } ;
2019-07-07 08:46:17 +02:00
return { } ;
}
2020-09-25 12:51:36 +02:00
std : : vector < std : : string > Schedule : : groupNames ( std : : size_t timeStep ) const {
2021-01-30 10:15:53 +01:00
const auto & group_order = this - > snapshots [ timeStep ] . group_order ( ) ;
return group_order . names ( ) ;
2019-07-07 08:46:17 +02:00
}
std : : vector < std : : string > Schedule : : groupNames ( const std : : string & pattern ) const {
2021-01-30 10:15:53 +01:00
return this - > groupNames ( pattern , this - > snapshots . size ( ) - 1 ) ;
2019-07-07 08:46:17 +02:00
}
std : : vector < std : : string > Schedule : : groupNames ( ) const {
2021-01-30 10:15:53 +01:00
const auto & group_order = this - > snapshots . back ( ) . group_order ( ) ;
return group_order . 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 {
2021-01-30 10:15:53 +01:00
const auto & restart_groups = this - > snapshots [ timeStep ] . group_order ( ) . restart_groups ( ) ;
std : : vector < const Group * > rst_groups ( restart_groups . size ( ) , nullptr ) ;
for ( std : : size_t restart_index = 0 ; restart_index < restart_groups . size ( ) ; restart_index + + ) {
const auto & group_name = restart_groups [ restart_index ] ;
if ( group_name . has_value ( ) )
rst_groups [ restart_index ] = & this - > getGroup ( group_name . value ( ) , timeStep ) ;
2020-06-23 16:50:30 +02:00
}
return rst_groups ;
}
2015-02-12 12:54:57 +01:00
2021-03-30 17:37:03 +02:00
void Schedule : : addGroup ( Group group ) {
std : : string group_name = group . name ( ) ;
2021-01-30 10:15:53 +01:00
auto & sched_state = this - > snapshots . back ( ) ;
2021-03-30 17:37:03 +02:00
sched_state . groups . update ( std : : move ( group ) ) ;
2021-01-30 10:15:53 +01:00
sched_state . events ( ) . addEvent ( ScheduleEvents : : NEW_GROUP ) ;
2021-03-30 17:37:03 +02:00
sched_state . wellgroup_events ( ) . addGroup ( group_name ) ;
2021-01-30 10:15:53 +01:00
{
auto go = sched_state . group_order . get ( ) ;
2021-03-30 17:37:03 +02:00
go . add ( group_name ) ;
2021-01-30 10:15:53 +01:00
sched_state . group_order . update ( std : : move ( go ) ) ;
}
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.
2021-03-30 17:37:03 +02:00
if ( group_name ! = " FIELD " )
this - > addGroupToGroup ( " FIELD " , group_name ) ;
}
void Schedule : : addGroup ( const std : : string & groupName , std : : size_t timeStep ) {
auto udq_undefined = this - > getUDQConfig ( timeStep ) . params ( ) . undefinedValue ( ) ;
const auto & sched_state = this - > snapshots . back ( ) ;
auto insert_index = sched_state . groups . size ( ) ;
this - > addGroup ( Group ( groupName , insert_index , udq_undefined , this - > m_static . m_unit_system ) ) ;
2013-11-18 13:11:49 +01:00
}
2020-10-05 14:04:25 +02:00
2021-06-17 13:18:26 +02:00
void Schedule : : addGroup ( const RestartIO : : RstGroup & rst_group , std : : size_t timeStep ) {
auto udq_undefined = this - > getUDQConfig ( timeStep ) . params ( ) . undefinedValue ( ) ;
const auto & sched_state = this - > snapshots . back ( ) ;
auto insert_index = sched_state . groups . size ( ) ;
this - > addGroup ( Group ( rst_group , insert_index , udq_undefined , this - > m_static . m_unit_system ) ) ;
}
2021-03-30 17:37:03 +02:00
void Schedule : : addGroupToGroup ( const std : : string & parent_name , const std : : string & child_name ) {
2021-01-30 14:51:55 +01:00
auto parent_group = this - > snapshots . back ( ) . groups . get ( parent_name ) ;
if ( parent_group . addGroup ( child_name ) )
this - > snapshots . back ( ) . groups . update ( std : : move ( parent_group ) ) ;
2019-07-25 11:46:15 +02:00
// Check and update backreference in child
2021-03-30 17:37:03 +02:00
const auto & child_group = this - > snapshots . back ( ) . groups . get ( child_name ) ;
2021-01-18 11:39:07 +01:00
if ( child_group . parent ( ) ! = parent_name ) {
2021-01-30 14:51:55 +01:00
auto old_parent = this - > snapshots . back ( ) . groups . get ( child_group . parent ( ) ) ;
old_parent . delGroup ( child_group . name ( ) ) ;
this - > snapshots . back ( ) . groups . update ( std : : move ( old_parent ) ) ;
2019-01-28 09:52:11 +01:00
2021-01-30 14:51:55 +01:00
auto new_child_group = Group { child_group } ;
new_child_group . updateParent ( parent_name ) ;
this - > snapshots . back ( ) . groups . update ( std : : move ( new_child_group ) ) ;
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 ) {
2021-02-03 08:31:59 +01:00
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 ) {
2021-02-03 08:31:59 +01:00
well . updateGroup ( group_name ) ;
this - > snapshots . back ( ) . wells . update ( std : : move ( well ) ) ;
this - > snapshots . back ( ) . wellgroup_events ( ) . addEvent ( well_name , ScheduleEvents : : WELL_WELSPECS_UPDATE ) ;
2019-07-25 11:46:15 +02:00
2019-08-06 22:40:14 +02:00
// Remove well child reference from previous group
2021-01-30 14:51:55 +01:00
auto group = this - > snapshots . back ( ) . groups . get ( old_gname ) ;
group . delWell ( well_name ) ;
this - > snapshots . back ( ) . groups . update ( std : : move ( group ) ) ;
2019-07-25 11:46:15 +02:00
}
2019-08-06 22:40:14 +02:00
// Add well child reference to new group
2021-01-30 14:51:55 +01:00
auto group = this - > snapshots . back ( ) . groups . get ( group_name ) ;
group . addWell ( well_name ) ;
this - > snapshots . back ( ) . groups . update ( std : : move ( group ) ) ;
2021-01-11 14:17:53 +01:00
this - > snapshots . back ( ) . events ( ) . addEvent ( ScheduleEvents : : GROUP_CHANGE ) ;
2020-09-25 10:49:47 +02:00
}
2014-12-05 12:59:53 +01:00
2015-04-17 18:51:42 +02:00
2018-04-12 19:02:15 +02:00
2021-01-11 20:55:09 +01:00
Well : : ProducerCMode Schedule : : getGlobalWhistctlMmode ( std : : size_t timestep ) const {
return this - > operator [ ] ( timestep ) . whistctl ( ) ;
2019-12-16 14:34:36 +01:00
}
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 ) {
2021-02-19 13:41:24 +01:00
auto elapsed = this - > snapshots [ timeStep ] . start_time ( ) - this - > snapshots [ 0 ] . start_time ( ) ;
auto days = std : : chrono : : duration_cast < std : : chrono : : hours > ( elapsed ) . count ( ) / 24.0 ;
auto msg = fmt : : format ( " All completions in well {} is shut at {} days \n "
" The well is therefore also shut " , well . name ( ) , days ) ;
2020-06-01 09:07:17 +02:00
OpmLog : : note ( msg ) ;
2021-02-03 10:43:56 +01:00
this - > updateWellStatus ( well . name ( ) , timeStep , 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
2021-09-01 15:44:25 +02:00
void Schedule : : end_report ( std : : size_t report_step ) {
this - > checkIfAllConnectionsIsShut ( report_step ) ;
}
2018-02-06 19:13:42 +01:00
2019-12-10 11:46:49 +01:00
void Schedule : : filterConnections ( const ActiveGridCells & grid ) {
2021-02-03 08:31:59 +01:00
for ( auto & sched_state : this - > snapshots ) {
for ( auto & well : sched_state . wells ( ) ) {
well . get ( ) . filterConnections ( grid ) ;
2019-05-04 12:00:32 +02:00
}
}
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 UDQConfig & Schedule : : getUDQConfig ( std : : size_t timeStep ) const {
2021-02-03 08:31:59 +01:00
return this - > snapshots [ timeStep ] . udq . get ( ) ;
2020-10-23 15:04:27 +02:00
}
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 {
2021-02-19 13:41:24 +01:00
return this - > snapshots . size ( ) ;
2018-10-12 08:25:40 +02:00
}
2018-10-17 12:08:54 +02:00
2021-02-19 13:41:24 +01:00
double Schedule : : seconds ( std : : size_t timeStep ) const {
if ( this - > snapshots . empty ( ) )
return 0 ;
2021-02-28 17:04:35 +01:00
if ( timeStep > = this - > snapshots . size ( ) )
throw std : : logic_error ( fmt : : format ( " seconds({}) - invalid timeStep. Valid range [0,{}> " , timeStep , this - > snapshots . size ( ) ) ) ;
2021-02-19 13:41:24 +01:00
auto elapsed = this - > snapshots [ timeStep ] . start_time ( ) - this - > snapshots [ 0 ] . start_time ( ) ;
return std : : chrono : : duration_cast < std : : chrono : : seconds > ( elapsed ) . count ( ) ;
2018-10-17 12:08:54 +02:00
}
2020-09-25 12:51:36 +02:00
time_t Schedule : : simTime ( std : : size_t timeStep ) const {
2021-02-19 13:41:24 +01:00
return std : : chrono : : system_clock : : to_time_t ( this - > snapshots [ timeStep ] . start_time ( ) ) ;
2019-01-22 17:04:54 +01:00
}
2018-10-09 17:42:37 +02:00
2020-09-25 12:51:36 +02:00
double Schedule : : stepLength ( std : : size_t timeStep ) const {
2021-02-19 13:41:24 +01:00
auto elapsed = this - > snapshots [ timeStep ] . end_time ( ) - this - > snapshots [ timeStep ] . start_time ( ) ;
return std : : chrono : : duration_cast < std : : chrono : : seconds > ( elapsed ) . count ( ) ;
2018-10-09 17:42:37 +02:00
}
2018-11-19 09:43:50 +01:00
2021-03-25 12:00:08 +01:00
std : : unordered_set < std : : string > Schedule : : applyAction ( std : : size_t reportStep , const time_point & , const Action : : ActionX & action , const Action : : Result & result , const std : : unordered_map < std : : string , double > & target_wellpi ) {
2021-03-19 18:14:37 +01:00
const std : : string prefix = " | " ;
2019-01-28 10:00:08 +01:00
ParseContext parseContext ;
ErrorGuard errors ;
2021-03-25 12:00:08 +01:00
std : : unordered_set < std : : string > affected_wells ;
2019-01-28 10:00:08 +01:00
2021-03-19 18:14:37 +01:00
OpmLog : : info ( " /---------------------------------------------------------------------- " ) ;
OpmLog : : info ( fmt : : format ( " {0}Action {1} evaluated to true. Will add action keywords and \n {0}rerun Schedule section. \n {0} " , prefix , action . name ( ) ) ) ;
2021-02-03 08:31:59 +01:00
this - > snapshots . resize ( reportStep + 1 ) ;
auto & input_block = this - > m_sched_deck [ reportStep ] ;
2019-01-28 10:00:08 +01:00
for ( const auto & keyword : action ) {
2021-02-03 08:31:59 +01:00
input_block . push_back ( keyword ) ;
2021-03-19 18:14:37 +01:00
const auto & location = keyword . location ( ) ;
OpmLog : : info ( fmt : : format ( " {}Processing keyword {} from {} line {} " , prefix , location . keyword , location . filename , location . lineno ) ) ;
2021-02-03 08:31:59 +01:00
this - > handleKeyword ( reportStep ,
input_block ,
keyword ,
parseContext ,
errors ,
nullptr ,
nullptr ,
result . wells ( ) ,
true ,
2021-03-25 12:00:08 +01:00
& affected_wells ,
2021-02-18 08:37:23 +01:00
& target_wellpi ) ;
2021-02-03 08:31:59 +01:00
}
2021-09-01 15:44:25 +02:00
this - > end_report ( reportStep ) ;
2021-05-21 15:55:39 +02:00
if ( ! affected_wells . empty ( ) ) {
this - > snapshots . back ( ) . events ( ) . addEvent ( ScheduleEvents : : ACTIONX_WELL_EVENT ) ;
for ( const auto & well : affected_wells )
this - > snapshots . back ( ) . wellgroup_events ( ) . addEvent ( well , ScheduleEvents : : ACTIONX_WELL_EVENT ) ;
}
2021-02-03 08:31:59 +01:00
if ( reportStep < this - > m_sched_deck . size ( ) - 1 )
2021-09-01 15:44:25 +02:00
iterateScheduleSection ( reportStep + 1 , this - > m_sched_deck . size ( ) , parseContext , errors , & target_wellpi , nullptr , nullptr , prefix ) ;
2021-03-19 18:14:37 +01:00
OpmLog : : info ( " \\ ---------------------------------------------------------------------- " ) ;
2021-03-25 12:00:08 +01:00
return affected_wells ;
2019-01-28 10:00:08 +01:00
}
2020-11-02 16:27:18 +01:00
2021-02-05 12:52:09 +01:00
void Schedule : : applyWellProdIndexScaling ( const std : : string & well_name , const std : : size_t reportStep , const double newWellPI ) {
2021-02-03 08:31:59 +01:00
if ( reportStep > = this - > snapshots . size ( ) )
2020-10-19 01:56:10 +02:00
return ;
2021-02-03 08:31:59 +01:00
if ( ! this - > snapshots [ reportStep ] . wells . has ( well_name ) )
2020-10-19 01:56:10 +02:00
return ;
2021-02-03 08:31:59 +01:00
std : : vector < Well * > unique_wells ;
for ( std : : size_t step = reportStep ; step < this - > snapshots . size ( ) ; step + + ) {
auto & well = this - > snapshots [ step ] . wells . get ( well_name ) ;
if ( unique_wells . empty ( ) | | ( ! ( * unique_wells . back ( ) = = well ) ) )
unique_wells . push_back ( & well ) ;
}
2020-10-19 01:56:10 +02:00
std : : vector < bool > scalingApplicable ;
2021-02-11 11:05:09 +01:00
const auto targetPI = this - > snapshots [ reportStep ] . target_wellpi . at ( well_name ) ;
2021-02-03 08:31:59 +01:00
auto prev_well = unique_wells [ 0 ] ;
2021-02-11 11:05:09 +01:00
auto scalingFactor = prev_well - > convertDeckPI ( targetPI ) / newWellPI ;
2021-02-03 08:31:59 +01:00
prev_well - > applyWellProdIndexScaling ( scalingFactor , scalingApplicable ) ;
2020-10-19 01:56:10 +02:00
2021-02-03 08:31:59 +01:00
for ( std : : size_t well_index = 1 ; well_index < unique_wells . size ( ) ; well_index + + ) {
auto wellPtr = unique_wells [ well_index ] ;
if ( ! wellPtr - > hasSameConnectionsPointers ( * prev_well ) ) {
2020-10-19 01:56:10 +02:00
wellPtr - > applyWellProdIndexScaling ( scalingFactor , scalingApplicable ) ;
2021-02-03 08:31:59 +01:00
prev_well = wellPtr ;
2020-10-19 01:56:10 +02:00
}
2021-02-03 08:31:59 +01:00
}
2020-10-19 01:56:10 +02:00
}
2021-07-06 17:42:24 +02:00
bool Schedule : : write_rst_file ( const std : : size_t report_step ) const
{
2021-09-08 14:52:21 +02:00
return this - > restart_output . writeRestartFile ( report_step ) | | this - > operator [ ] ( report_step ) . save ( ) ;
2021-07-06 17:42:24 +02:00
}
bool Schedule : : must_write_rst_file ( const std : : size_t report_step ) const
{
2021-03-26 07:44:42 +01:00
if ( this - > m_static . output_interval . has_value ( ) )
return this - > m_static . output_interval . value ( ) % report_step ;
2021-03-24 17:24:42 +01:00
if ( report_step = = 0 )
return this - > m_static . rst_config . write_rst_file . value ( ) ;
2020-02-16 20:00:16 +01:00
2021-07-06 17:42:24 +02:00
const auto previous_restart_output_step =
this - > restart_output . lastRestartEventBefore ( report_step ) ;
// Previous output event time or start of simulation if no previous
// event recorded
const auto previous_output = previous_restart_output_step . has_value ( )
? this - > snapshots [ previous_restart_output_step . value ( ) ] . start_time ( )
: this - > snapshots [ 0 ] . start_time ( ) ;
2021-03-24 17:24:42 +01:00
const auto & rst_config = this - > snapshots [ report_step - 1 ] . rst_config ( ) ;
2021-07-06 17:42:24 +02:00
return this - > snapshots [ report_step ] . rst_file ( rst_config , previous_output ) ;
2020-02-16 20:00:16 +01:00
}
2021-03-07 09:28:09 +01:00
2021-03-24 17:24:42 +01:00
const std : : map < std : : string , int > & Schedule : : rst_keywords ( size_t report_step ) const {
if ( report_step = = 0 )
return this - > m_static . rst_config . keywords ;
2021-03-07 09:28:09 +01:00
2021-03-24 17:24:42 +01:00
const auto & keywords = this - > snapshots [ report_step - 1 ] . rst_config ( ) . keywords ;
return keywords ;
2021-03-07 09:28:09 +01:00
}
2020-09-25 10:49:47 +02:00
bool Schedule : : operator = = ( const Schedule & data ) const {
2021-04-03 08:38:58 +02:00
return this - > m_static = = data . m_static & &
2021-04-03 08:44:22 +02:00
this - > m_sched_deck = = data . m_sched_deck & &
2021-07-06 17:42:24 +02:00
this - > snapshots = = data . snapshots & &
this - > restart_output = = data . restart_output ;
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 {
2021-01-13 09:13:24 +01:00
const double sim_time { this - > m_static . m_unit_system . from_si ( UnitSystem : : measure : : time , simTime ( currentStep ) ) } ;
return fmt : : format ( " {} {} " , sim_time , this - > m_static . m_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
{
const auto report_step = rst_state . header . report_step - 1 ;
2021-01-13 13:41:10 +01:00
double udq_undefined = 0 ;
2020-10-08 08:15:32 +02:00
for ( const auto & rst_group : rst_state . groups ) {
2021-06-17 13:18:26 +02:00
this - > addGroup ( rst_group , report_step ) ;
2021-01-30 14:51:55 +01:00
const auto & group = this - > snapshots . back ( ) . groups . get ( rst_group . name ) ;
2020-10-20 08:40:41 +02:00
if ( group . isProductionGroup ( ) ) {
2021-01-11 14:17:53 +01:00
// Was originally at report_step + 1
this - > snapshots . back ( ) . events ( ) . addEvent ( ScheduleEvents : : GROUP_PRODUCTION_UPDATE ) ;
this - > snapshots . back ( ) . wellgroup_events ( ) . addEvent ( rst_group . name , ScheduleEvents : : GROUP_PRODUCTION_UPDATE ) ;
2020-10-20 08:40:41 +02:00
}
if ( group . isInjectionGroup ( ) ) {
2021-01-11 14:17:53 +01:00
// Was originally at report_step + 1
this - > snapshots . back ( ) . events ( ) . addEvent ( ScheduleEvents : : GROUP_INJECTION_UPDATE ) ;
this - > snapshots . back ( ) . wellgroup_events ( ) . addEvent ( rst_group . name , ScheduleEvents : : GROUP_INJECTION_UPDATE ) ;
2020-10-20 08:40:41 +02:00
}
2021-08-16 16:04:35 +02:00
OpmLog : : info ( fmt : : format ( " Adding group {} from restart file " , rst_group . name ) ) ;
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 ] ;
2021-03-30 17:37:03 +02:00
this - > addGroupToGroup ( parent_group . name , rst_group . name ) ;
2020-10-07 16:45:19 +02:00
}
2021-10-20 17:08:08 +02:00
auto glo = this - > snapshots . back ( ) . glo ( ) ;
2020-09-25 10:49:47 +02:00
for ( const auto & rst_well : rst_state . wells ) {
2021-01-13 09:13:24 +01:00
Opm : : Well well ( rst_well , report_step , this - > m_static . m_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 ) ;
2021-02-03 11:40:38 +01:00
well . updateConnections ( std : : make_shared < WellConnections > ( std : : move ( connections ) ) , 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 ) ;
2021-02-03 11:40:38 +01:00
well . updateConnections ( std : : make_shared < WellConnections > ( std : : move ( connections ) ) , 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
}
2021-02-10 09:19:39 +01:00
this - > addWell ( well ) ;
2020-09-25 10:49:47 +02:00
this - > addWellToGroup ( well . groupName ( ) , well . name ( ) , report_step ) ;
2021-08-16 16:04:35 +02:00
OpmLog : : info ( fmt : : format ( " Adding well {} from restart file " , rst_well . name ) ) ;
2021-10-07 09:29:24 +02:00
2021-10-20 17:08:08 +02:00
if ( GasLiftOpt : : Well : : active ( rst_well ) )
glo . add_well ( GasLiftOpt : : Well ( rst_well ) ) ;
}
this - > snapshots . back ( ) . glo . update ( std : : move ( glo ) ) ;
2021-09-24 08:34:24 +02:00
this - > snapshots . back ( ) . update_tuning ( rst_state . tuning ) ;
2021-01-11 14:17:53 +01:00
this - > snapshots . back ( ) . events ( ) . addEvent ( ScheduleEvents : : TUNING_CHANGE ) ;
2020-03-13 07:36:45 +01:00
2020-10-20 08:38:13 +02:00
{
const auto & header = rst_state . header ;
2021-10-07 09:29:24 +02:00
if ( GuideRateModel : : rst_valid ( header . guide_rate_delay ,
2020-10-20 08:38:13 +02:00
header . guide_rate_a ,
header . guide_rate_b ,
header . guide_rate_c ,
header . guide_rate_d ,
header . guide_rate_e ,
header . guide_rate_f ,
2021-10-07 09:29:24 +02:00
header . guide_rate_damping ) )
{
const bool allow_increase = true ;
const bool use_free_gas = false ;
const auto guide_rate_model = GuideRateModel {
header . guide_rate_delay ,
GuideRateModel : : TargetFromRestart ( header . guide_rate_nominated_phase ) ,
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
} ;
2020-10-20 08:38:13 +02:00
this - > updateGuideRateModel ( guide_rate_model , report_step ) ;
}
}
2021-10-07 10:39:46 +02:00
for ( const auto & rst_group : rst_state . groups ) {
const auto & group = this - > snapshots . back ( ) . groups . get ( rst_group . name ) ;
if ( group . isProductionGroup ( ) ) {
auto new_config = this - > snapshots . back ( ) . guide_rate ( ) ;
new_config . update_production_group ( group ) ;
this - > snapshots . back ( ) . guide_rate . update ( std : : move ( new_config ) ) ;
}
}
2021-07-03 10:29:36 +02:00
this - > snapshots . back ( ) . udq . update ( UDQConfig ( this - > m_static . m_runspec . udqParams ( ) , rst_state ) ) ;
2021-08-25 15:04:45 +02:00
const auto & uda_records = UDQActive : : load_rst ( this - > m_static . m_unit_system , this - > snapshots . back ( ) . udq ( ) , rst_state , this - > wellNames ( report_step ) , this - > groupNames ( report_step ) ) ;
if ( ! uda_records . empty ( ) ) {
const auto & udq_config = this - > snapshots . back ( ) . udq ( ) ;
auto udq_active = this - > snapshots . back ( ) . udq_active ( ) ;
for ( const auto & [ control , value , wgname , ig_phase ] : uda_records ) {
if ( UDQ : : well_control ( control ) ) {
auto & well = this - > snapshots . back ( ) . wells . get ( wgname ) ;
if ( UDQ : : injection_control ( control ) ) {
auto injection_properties = std : : make_shared < Well : : WellInjectionProperties > ( well . getInjectionProperties ( ) ) ;
injection_properties - > update_uda ( udq_config , udq_active , control , value ) ;
well . updateInjection ( std : : move ( injection_properties ) ) ;
}
if ( UDQ : : production_control ( control ) ) {
auto production_properties = std : : make_shared < Well : : WellProductionProperties > ( well . getProductionProperties ( ) ) ;
production_properties - > update_uda ( udq_config , udq_active , control , value ) ;
well . updateProduction ( std : : move ( production_properties ) ) ;
}
} else {
auto & group = this - > snapshots . back ( ) . groups . get ( wgname ) ;
if ( UDQ : : injection_control ( control ) ) {
auto injection_properties = group . injectionProperties ( ig_phase . value ( ) ) ;
injection_properties . update_uda ( udq_config , udq_active , control , value ) ;
group . updateInjection ( injection_properties ) ;
}
if ( UDQ : : production_control ( control ) ) {
auto production_properties = group . productionProperties ( ) ;
production_properties . update_uda ( udq_config , udq_active , control , value ) ;
group . updateProduction ( production_properties ) ;
}
}
2021-08-19 18:21:50 +02:00
}
2021-08-25 15:04:45 +02:00
this - > snapshots . back ( ) . udq_active . update ( std : : move ( udq_active ) ) ;
2021-08-19 18:21:50 +02:00
}
2021-09-08 09:41:47 +02:00
if ( ! rst_state . actions . empty ( ) ) {
auto actions = this - > snapshots . back ( ) . actions ( ) ;
for ( const auto & rst_action : rst_state . actions )
actions . add ( Action : : ActionX ( rst_action ) ) ;
this - > snapshots . back ( ) . actions . update ( std : : move ( actions ) ) ;
}
2021-10-11 10:07:43 +02:00
this - > snapshots . back ( ) . wtest_config . update ( WellTestConfig { rst_state , report_step } ) ;
2021-10-14 21:00:56 +02:00
if ( ! rst_state . wlists . empty ( ) )
this - > snapshots . back ( ) . wlist_manager . update ( WListManager ( rst_state ) ) ;
2020-03-13 07:36:45 +01:00
}
2020-09-25 10:49:47 +02:00
std : : shared_ptr < const Python > Schedule : : python ( ) const
{
2021-01-13 09:13:24 +01:00
return this - > m_static . m_python_handle ;
2020-09-25 10:49:47 +02:00
}
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 {
2021-02-03 08:31:59 +01:00
return this - > snapshots [ report_step ] . glo ( ) ;
2020-09-25 10:49:47 +02:00
}
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
{
2021-02-19 13:41:24 +01:00
//if (sched1.size() != sched2.size())
// return false;
//for (std::size_t step=0; step < sched1.size(); step++) {
// auto start1 = sched1[step].start_time();
// auto start2 = sched2[step].start_time();
// if (start1 != start2)
// return false;
// if (step < sched1.size() - 1) {
// auto end1 = sched1[step].end_time();
// auto end2 = sched2[step].end_time();
// if (end1 != end2)
// return false;
// }
//}
2020-03-13 12:18:08 +01:00
}
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-13 10:25:06 +01:00
const ScheduleState & Schedule : : back ( ) const {
return this - > snapshots . back ( ) ;
}
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-02-28 17:04:35 +01:00
void Schedule : : create_first ( const time_point & start_time , const std : : optional < time_point > & end_time ) {
2021-01-07 08:22:08 +01:00
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 ( ) ;
2021-05-21 14:53:12 +02:00
sched_state . init_nupcol ( this - > m_static . m_runspec . nupcol ( ) ) ;
2021-01-26 11:02:19 +01:00
sched_state . update_oilvap ( OilVaporizationProperties ( this - > m_static . m_runspec . tabdims ( ) . getNumPVTTables ( ) ) ) ;
sched_state . update_message_limits ( this - > m_static . m_deck_message_limits ) ;
2021-01-27 10:55:35 +01:00
sched_state . pavg . update ( PAvg ( ) ) ;
sched_state . wtest_config . update ( WellTestConfig ( ) ) ;
sched_state . gconsale . update ( GConSale ( ) ) ;
sched_state . gconsump . update ( GConSump ( ) ) ;
sched_state . wlist_manager . update ( WListManager ( ) ) ;
sched_state . network . update ( Network : : ExtNetwork ( ) ) ;
sched_state . rpt_config . update ( RPTConfig ( ) ) ;
sched_state . actions . update ( Action : : Actions ( ) ) ;
sched_state . udq_active . update ( UDQActive ( ) ) ;
sched_state . well_order . update ( NameOrder ( ) ) ;
2021-01-30 08:36:40 +01:00
sched_state . group_order . update ( GroupOrder ( this - > m_static . m_runspec . wellDimensions ( ) . maxGroupsInField ( ) ) ) ;
2021-02-03 08:31:59 +01:00
sched_state . udq . update ( UDQConfig ( this - > m_static . m_runspec . udqParams ( ) ) ) ;
sched_state . glo . update ( GasLiftOpt ( ) ) ;
sched_state . guide_rate . update ( GuideRateConfig ( ) ) ;
2021-02-18 08:37:23 +01:00
sched_state . rft_config . update ( RFTConfig ( ) ) ;
2021-03-24 17:24:42 +01:00
sched_state . rst_config . update ( RSTConfig : : first ( this - > m_static . rst_config ) ) ;
2021-10-04 12:35:47 +02:00
sched_state . network_balance . update ( Network : : Balance ( ) ) ;
2021-09-09 11:48:21 +02:00
sched_state . update_sumthin ( this - > m_static . sumthin ) ;
sched_state . rptonly ( this - > m_static . rptonly ) ;
2021-03-24 17:24:42 +01:00
//sched_state.update_date( start_time );
2021-01-11 14:17:53 +01:00
this - > addGroup ( " FIELD " , 0 ) ;
2021-01-07 08:22:08 +01:00
}
2021-02-28 17:04:35 +01:00
void Schedule : : create_next ( const time_point & start_time , const std : : optional < 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
}