2018-06-06 03:59:41 -05:00
/*
*/
# ifndef OPM_ADAPTIVE_TIME_STEPPING_EBOS_HPP
# define OPM_ADAPTIVE_TIME_STEPPING_EBOS_HPP
# include <iostream>
# include <utility>
2019-06-20 03:30:16 -05:00
# include <opm/simulators/timestepping/SimulatorReport.hpp>
2018-06-06 03:59:41 -05:00
# include <opm/grid/utility/StopWatch.hpp>
# include <opm/common/OpmLog/OpmLog.hpp>
# include <opm/common/ErrorMacros.hpp>
# include <opm/simulators/timestepping/SimulatorTimer.hpp>
# include <opm/simulators/timestepping/AdaptiveSimulatorTimer.hpp>
# include <opm/simulators/timestepping/TimeStepControlInterface.hpp>
# include <opm/simulators/timestepping/TimeStepControl.hpp>
2018-06-21 05:14:17 -05:00
# include <opm/core/props/phaseUsageFromDeck.hpp>
2021-12-14 01:30:15 -06:00
# include <opm/input/eclipse/Schedule/ScheduleState.hpp>
2020-09-21 10:43:09 -05:00
# include <opm/common/Exceptions.hpp>
2018-06-21 05:14:17 -05:00
2020-08-21 06:42:08 -05:00
namespace Opm : : Properties {
2018-06-21 05:14:17 -05:00
2020-08-27 03:30:29 -05:00
namespace TTag {
struct FlowTimeSteppingParameters { } ;
}
2018-06-21 05:14:17 -05:00
2020-08-27 04:38:38 -05:00
template < class TypeTag , class MyTypeTag >
struct SolverRestartFactor {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct SolverGrowthFactor {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct SolverMaxGrowth {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct SolverMaxTimeStepInDays {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct SolverMinTimeStep {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
2021-09-09 00:46:09 -05:00
struct SolverContinueOnConvergenceFailure {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
2020-08-27 04:38:38 -05:00
struct SolverMaxRestarts {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct SolverVerbosity {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct TimeStepVerbosity {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct InitialTimeStepInDays {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct FullTimeStepInitially {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct TimeStepAfterEventInDays {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct TimeStepControl {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct TimeStepControlTolerance {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct TimeStepControlTargetIterations {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct TimeStepControlTargetNewtonIterations {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct TimeStepControlDecayRate {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct TimeStepControlGrowthRate {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
2020-10-01 07:02:39 -05:00
struct TimeStepControlDecayDampingFactor {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct TimeStepControlGrowthDampingFactor {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
2020-08-27 04:38:38 -05:00
struct TimeStepControlFileName {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct MinTimeStepBeforeShuttingProblematicWellsInDays {
using type = UndefinedProperty ;
} ;
2021-02-17 04:30:57 -06:00
template < class TypeTag , class MyTypeTag >
struct MinTimeStepBasedOnNewtonIterations {
using type = UndefinedProperty ;
} ;
2018-08-06 08:59:35 -05:00
2020-08-27 04:38:38 -05:00
template < class TypeTag >
struct SolverRestartFactor < TypeTag , TTag : : FlowTimeSteppingParameters > {
using type = GetPropType < TypeTag , Scalar > ;
static constexpr type value = 0.33 ;
} ;
template < class TypeTag >
struct SolverGrowthFactor < TypeTag , TTag : : FlowTimeSteppingParameters > {
using type = GetPropType < TypeTag , Scalar > ;
static constexpr type value = 2.0 ;
} ;
template < class TypeTag >
struct SolverMaxGrowth < TypeTag , TTag : : FlowTimeSteppingParameters > {
using type = GetPropType < TypeTag , Scalar > ;
static constexpr type value = 3.0 ;
} ;
template < class TypeTag >
struct SolverMaxTimeStepInDays < TypeTag , TTag : : FlowTimeSteppingParameters > {
using type = GetPropType < TypeTag , Scalar > ;
static constexpr type value = 365.0 ;
} ;
template < class TypeTag >
struct SolverMinTimeStep < TypeTag , TTag : : FlowTimeSteppingParameters > {
using type = GetPropType < TypeTag , Scalar > ;
2021-03-18 03:23:48 -05:00
static constexpr type value = 1.0e-12 ;
2020-08-27 04:38:38 -05:00
} ;
2020-08-27 04:38:38 -05:00
template < class TypeTag >
2021-09-09 00:46:09 -05:00
struct SolverContinueOnConvergenceFailure < TypeTag , TTag : : FlowTimeSteppingParameters > {
static constexpr bool value = false ;
} ;
template < class TypeTag >
2020-08-27 04:38:38 -05:00
struct SolverMaxRestarts < TypeTag , TTag : : FlowTimeSteppingParameters > {
static constexpr int value = 10 ;
} ;
template < class TypeTag >
struct SolverVerbosity < TypeTag , TTag : : FlowTimeSteppingParameters > {
static constexpr int value = 1 ;
} ;
template < class TypeTag >
struct TimeStepVerbosity < TypeTag , TTag : : FlowTimeSteppingParameters > {
static constexpr int value = 1 ;
} ;
2020-08-27 04:38:38 -05:00
template < class TypeTag >
struct InitialTimeStepInDays < TypeTag , TTag : : FlowTimeSteppingParameters > {
using type = GetPropType < TypeTag , Scalar > ;
static constexpr type value = 1.0 ;
} ;
2020-08-27 04:38:38 -05:00
template < class TypeTag >
struct FullTimeStepInitially < TypeTag , TTag : : FlowTimeSteppingParameters > {
static constexpr bool value = false ;
} ;
2020-08-27 04:38:38 -05:00
template < class TypeTag >
struct TimeStepAfterEventInDays < TypeTag , TTag : : FlowTimeSteppingParameters > {
using type = GetPropType < TypeTag , Scalar > ;
static constexpr type value = - 1.0 ;
} ;
2020-08-27 04:38:38 -05:00
template < class TypeTag >
struct TimeStepControl < TypeTag , TTag : : FlowTimeSteppingParameters > {
2020-11-09 01:40:31 -06:00
static constexpr auto value = " pid+newtoniteration " ;
2020-08-27 04:38:38 -05:00
} ;
2020-08-27 04:38:38 -05:00
template < class TypeTag >
struct TimeStepControlTolerance < TypeTag , TTag : : FlowTimeSteppingParameters > {
using type = GetPropType < TypeTag , Scalar > ;
static constexpr type value = 1e-1 ;
} ;
2020-08-27 04:38:38 -05:00
template < class TypeTag >
struct TimeStepControlTargetIterations < TypeTag , TTag : : FlowTimeSteppingParameters > {
static constexpr int value = 30 ;
} ;
template < class TypeTag >
struct TimeStepControlTargetNewtonIterations < TypeTag , TTag : : FlowTimeSteppingParameters > {
static constexpr int value = 8 ;
} ;
2020-08-27 04:38:38 -05:00
template < class TypeTag >
struct TimeStepControlDecayRate < TypeTag , TTag : : FlowTimeSteppingParameters > {
using type = GetPropType < TypeTag , Scalar > ;
static constexpr type value = 0.75 ;
} ;
template < class TypeTag >
struct TimeStepControlGrowthRate < TypeTag , TTag : : FlowTimeSteppingParameters > {
using type = GetPropType < TypeTag , Scalar > ;
static constexpr type value = 1.25 ;
} ;
2020-08-27 04:38:38 -05:00
template < class TypeTag >
2020-10-01 07:02:39 -05:00
struct TimeStepControlDecayDampingFactor < TypeTag , TTag : : FlowTimeSteppingParameters > {
using type = GetPropType < TypeTag , Scalar > ;
static constexpr type value = 1.0 ;
} ;
template < class TypeTag >
struct TimeStepControlGrowthDampingFactor < TypeTag , TTag : : FlowTimeSteppingParameters > {
using type = GetPropType < TypeTag , Scalar > ;
2020-11-09 04:45:13 -06:00
static constexpr type value = 3.2 ;
2020-10-01 07:02:39 -05:00
} ;
template < class TypeTag >
2020-08-27 04:38:38 -05:00
struct TimeStepControlFileName < TypeTag , TTag : : FlowTimeSteppingParameters > {
static constexpr auto value = " timesteps " ;
} ;
2020-08-27 04:38:38 -05:00
template < class TypeTag >
struct MinTimeStepBeforeShuttingProblematicWellsInDays < TypeTag , TTag : : FlowTimeSteppingParameters > {
using type = GetPropType < TypeTag , Scalar > ;
2021-02-02 02:28:26 -06:00
static constexpr type value = 0.01 ;
2020-08-27 04:38:38 -05:00
} ;
2019-12-18 04:18:18 -06:00
2021-02-17 04:30:57 -06:00
template < class TypeTag >
struct MinTimeStepBasedOnNewtonIterations < TypeTag , TTag : : FlowTimeSteppingParameters > {
using type = GetPropType < TypeTag , Scalar > ;
static constexpr type value = 0.0 ;
} ;
2020-08-21 06:42:08 -05:00
} // namespace Opm::Properties
2018-06-06 03:59:41 -05:00
namespace Opm {
// AdaptiveTimeStepping
//---------------------
2021-06-08 08:36:56 -05:00
void logTimer ( const AdaptiveSimulatorTimer & substepTimer ) ;
2018-06-06 03:59:41 -05:00
2018-06-21 05:14:17 -05:00
template < class TypeTag >
2018-06-06 03:59:41 -05:00
class AdaptiveTimeSteppingEbos
{
template < class Solver >
class SolutionTimeErrorSolverWrapperEbos : public RelativeChangeInterface
{
const Solver & solver_ ;
public :
SolutionTimeErrorSolverWrapperEbos ( const Solver & solver )
: solver_ ( solver )
{ }
/// return || u^n+1 - u^n || / || u^n+1 ||
double relativeChange ( ) const
{ return solver_ . model ( ) . relativeChange ( ) ; }
} ;
template < class E >
void logException_ ( const E & exception , bool verbose )
{
if ( verbose ) {
std : : string message ;
message = " Caught Exception: " ;
message + = exception . what ( ) ;
OpmLog : : debug ( message ) ;
}
}
public :
//! \brief contructor taking parameter object
2021-02-17 04:30:57 -06:00
AdaptiveTimeSteppingEbos ( const UnitSystem & unitSystem ,
const bool terminalOutput = true )
2018-06-06 03:59:41 -05:00
: timeStepControl_ ( )
2018-08-06 08:59:35 -05:00
, restartFactor_ ( EWOMS_GET_PARAM ( TypeTag , double , SolverRestartFactor ) ) // 0.33
, growthFactor_ ( EWOMS_GET_PARAM ( TypeTag , double , SolverGrowthFactor ) ) // 2.0
, maxGrowth_ ( EWOMS_GET_PARAM ( TypeTag , double , SolverMaxGrowth ) ) // 3.0
, maxTimeStep_ ( EWOMS_GET_PARAM ( TypeTag , double , SolverMaxTimeStepInDays ) * 24 * 60 * 60 ) // 365.25
2021-03-18 03:23:48 -05:00
, minTimeStep_ ( unitSystem . to_si ( UnitSystem : : measure : : time , EWOMS_GET_PARAM ( TypeTag , double , SolverMinTimeStep ) ) ) // 1e-12;
2021-09-09 00:46:09 -05:00
, ignoreConvergenceFailure_ ( EWOMS_GET_PARAM ( TypeTag , bool , SolverContinueOnConvergenceFailure ) ) // false;
2018-08-06 08:59:35 -05:00
, solverRestartMax_ ( EWOMS_GET_PARAM ( TypeTag , int , SolverMaxRestarts ) ) // 10
, solverVerbose_ ( EWOMS_GET_PARAM ( TypeTag , int , SolverVerbosity ) > 0 & & terminalOutput ) // 2
, timestepVerbose_ ( EWOMS_GET_PARAM ( TypeTag , int , TimeStepVerbosity ) > 0 & & terminalOutput ) // 2
, suggestedNextTimestep_ ( EWOMS_GET_PARAM ( TypeTag , double , InitialTimeStepInDays ) * 24 * 60 * 60 ) // 1.0
, fullTimestepInitially_ ( EWOMS_GET_PARAM ( TypeTag , bool , FullTimeStepInitially ) ) // false
, timestepAfterEvent_ ( EWOMS_GET_PARAM ( TypeTag , double , TimeStepAfterEventInDays ) * 24 * 60 * 60 ) // 1e30
2018-06-06 03:59:41 -05:00
, useNewtonIteration_ ( false )
2019-12-18 04:18:18 -06:00
, minTimeStepBeforeShuttingProblematicWells_ ( EWOMS_GET_PARAM ( TypeTag , double , MinTimeStepBeforeShuttingProblematicWellsInDays ) * unit : : day )
2018-06-06 03:59:41 -05:00
{
2021-02-17 04:30:57 -06:00
init_ ( unitSystem ) ;
2018-06-06 03:59:41 -05:00
}
//! \brief contructor taking parameter object
//! \param tuning Pointer to ecl TUNING keyword
//! \param timeStep current report step
2021-10-18 04:52:33 -05:00
AdaptiveTimeSteppingEbos ( double max_next_tstep ,
const Tuning & tuning ,
2021-02-17 04:30:57 -06:00
const UnitSystem & unitSystem ,
2018-06-06 03:59:41 -05:00
const bool terminalOutput = true )
: timeStepControl_ ( )
2020-01-31 06:42:50 -06:00
, restartFactor_ ( tuning . TSFCNV )
, growthFactor_ ( tuning . TFDIFF )
, maxGrowth_ ( tuning . TSFMAX )
2020-05-14 14:31:18 -05:00
, maxTimeStep_ ( tuning . TSMAXZ ) // 365.25
2021-09-09 00:46:09 -05:00
, minTimeStep_ ( tuning . TSFMIN ) // 0.1;
, ignoreConvergenceFailure_ ( true )
2018-08-06 08:59:35 -05:00
, solverRestartMax_ ( EWOMS_GET_PARAM ( TypeTag , int , SolverMaxRestarts ) ) // 10
, solverVerbose_ ( EWOMS_GET_PARAM ( TypeTag , int , SolverVerbosity ) > 0 & & terminalOutput ) // 2
, timestepVerbose_ ( EWOMS_GET_PARAM ( TypeTag , int , TimeStepVerbosity ) > 0 & & terminalOutput ) // 2
2021-10-18 04:52:33 -05:00
, suggestedNextTimestep_ ( max_next_tstep ) // 1.0
2018-08-06 08:59:35 -05:00
, fullTimestepInitially_ ( EWOMS_GET_PARAM ( TypeTag , bool , FullTimeStepInitially ) ) // false
2020-05-14 14:31:18 -05:00
, timestepAfterEvent_ ( tuning . TMAXWC ) // 1e30
2018-06-06 03:59:41 -05:00
, useNewtonIteration_ ( false )
2019-12-18 04:18:18 -06:00
, minTimeStepBeforeShuttingProblematicWells_ ( EWOMS_GET_PARAM ( TypeTag , double , MinTimeStepBeforeShuttingProblematicWellsInDays ) * unit : : day )
2018-06-06 03:59:41 -05:00
{
2021-02-17 04:30:57 -06:00
init_ ( unitSystem ) ;
2018-06-21 05:14:17 -05:00
}
static void registerParameters ( )
{
// TODO: make sure the help messages are correct (and useful)
2018-08-06 08:59:35 -05:00
EWOMS_REGISTER_PARAM ( TypeTag , double , SolverRestartFactor ,
2018-06-21 05:14:17 -05:00
" The factor time steps are elongated after restarts " ) ;
2018-08-06 08:59:35 -05:00
EWOMS_REGISTER_PARAM ( TypeTag , double , SolverGrowthFactor ,
2018-06-21 05:14:17 -05:00
" The factor time steps are elongated after a successful substep " ) ;
2018-08-06 08:59:35 -05:00
EWOMS_REGISTER_PARAM ( TypeTag , double , SolverMaxGrowth ,
2018-06-21 05:14:17 -05:00
" The maximum factor time steps are elongated after a report step " ) ;
2018-08-06 08:59:35 -05:00
EWOMS_REGISTER_PARAM ( TypeTag , double , SolverMaxTimeStepInDays ,
2018-06-21 05:14:17 -05:00
" The maximum size of a time step in days " ) ;
2019-11-28 08:18:39 -06:00
EWOMS_REGISTER_PARAM ( TypeTag , double , SolverMinTimeStep ,
2021-03-18 03:23:48 -05:00
" The minimum size of a time step in days for field and metric and hours for lab. If a step cannot converge without getting cut below this step size the simulator will stop " ) ;
2021-09-09 00:46:09 -05:00
EWOMS_REGISTER_PARAM ( TypeTag , bool , SolverContinueOnConvergenceFailure ,
" Continue instead of stop when minimum solver time step is reached " ) ;
2018-08-06 08:59:35 -05:00
EWOMS_REGISTER_PARAM ( TypeTag , int , SolverMaxRestarts ,
2018-06-21 05:14:17 -05:00
" The maximum number of breakdowns before a substep is given up and the simulator is terminated " ) ;
2018-08-06 08:59:35 -05:00
EWOMS_REGISTER_PARAM ( TypeTag , int , SolverVerbosity ,
2018-06-21 05:14:17 -05:00
" Specify the \" chattiness \" of the non-linear solver itself " ) ;
2018-08-06 08:59:35 -05:00
EWOMS_REGISTER_PARAM ( TypeTag , int , TimeStepVerbosity ,
2018-06-21 05:14:17 -05:00
" Specify the \" chattiness \" during the time integration " ) ;
2018-08-06 08:59:35 -05:00
EWOMS_REGISTER_PARAM ( TypeTag , double , InitialTimeStepInDays ,
2018-06-21 05:14:17 -05:00
" The size of the initial time step in days " ) ;
2018-08-06 08:59:35 -05:00
EWOMS_REGISTER_PARAM ( TypeTag , bool , FullTimeStepInitially ,
2018-06-21 05:14:17 -05:00
" Always attempt to finish a report step using a single substep " ) ;
2018-08-06 08:59:35 -05:00
EWOMS_REGISTER_PARAM ( TypeTag , double , TimeStepAfterEventInDays ,
2018-06-21 05:14:17 -05:00
" Time step size of the first time step after an event occurs during the simulation in days " ) ;
2018-08-06 08:59:35 -05:00
EWOMS_REGISTER_PARAM ( TypeTag , std : : string , TimeStepControl ,
2020-10-01 07:02:39 -05:00
" The algorithm used to determine time-step sizes. valid options are: 'pid' (default), 'pid+iteration', 'pid+newtoniteration', 'iterationcount', 'newtoniterationcount' and 'hardcoded' " ) ;
2018-08-06 08:59:35 -05:00
EWOMS_REGISTER_PARAM ( TypeTag , double , TimeStepControlTolerance ,
2018-06-21 05:14:17 -05:00
" The tolerance used by the time step size control algorithm " ) ;
2018-08-06 08:59:35 -05:00
EWOMS_REGISTER_PARAM ( TypeTag , int , TimeStepControlTargetIterations ,
2018-06-21 05:14:17 -05:00
" The number of linear iterations which the time step control scheme should aim for (if applicable) " ) ;
2018-08-06 08:59:35 -05:00
EWOMS_REGISTER_PARAM ( TypeTag , int , TimeStepControlTargetNewtonIterations ,
2018-06-21 05:14:17 -05:00
" The number of Newton iterations which the time step control scheme should aim for (if applicable) " ) ;
2018-08-06 08:59:35 -05:00
EWOMS_REGISTER_PARAM ( TypeTag , double , TimeStepControlDecayRate ,
2018-06-21 05:14:17 -05:00
" The decay rate of the time step size of the number of target iterations is exceeded " ) ;
2018-08-06 08:59:35 -05:00
EWOMS_REGISTER_PARAM ( TypeTag , double , TimeStepControlGrowthRate ,
2018-06-21 05:14:17 -05:00
" The growth rate of the time step size of the number of target iterations is undercut " ) ;
2020-10-01 07:02:39 -05:00
EWOMS_REGISTER_PARAM ( TypeTag , double , TimeStepControlDecayDampingFactor ,
" The decay rate of the time step decrease when the target iterations is exceeded " ) ;
EWOMS_REGISTER_PARAM ( TypeTag , double , TimeStepControlGrowthDampingFactor ,
" The growth rate of the time step increase when the target iterations is undercut " ) ;
2018-08-06 08:59:35 -05:00
EWOMS_REGISTER_PARAM ( TypeTag , std : : string , TimeStepControlFileName ,
2018-06-21 05:14:17 -05:00
" The name of the file which contains the hardcoded time steps sizes " ) ;
2019-12-18 04:18:18 -06:00
EWOMS_REGISTER_PARAM ( TypeTag , double , MinTimeStepBeforeShuttingProblematicWellsInDays ,
" The minimum time step size in days for which problematic wells are not shut " ) ;
2021-02-17 04:30:57 -06:00
EWOMS_REGISTER_PARAM ( TypeTag , double , MinTimeStepBasedOnNewtonIterations ,
" The minimum time step size (in days for field and metric unit and hours for lab unit) can be reduced to based on newton iteration counts " ) ;
2018-06-06 03:59:41 -05:00
}
/** \brief step method that acts like the solver::step method
in a sub cycle of time steps
*/
2018-06-06 03:59:41 -05:00
template < class Solver >
2018-06-06 03:59:41 -05:00
SimulatorReport step ( const SimulatorTimer & simulatorTimer ,
2020-05-08 02:21:25 -05:00
Solver & solver ,
const bool isEvent ,
const std : : vector < int > * fipnum = nullptr )
2018-06-06 03:59:41 -05:00
{
SimulatorReport report ;
const double timestep = simulatorTimer . currentStepLength ( ) ;
// init last time step as a fraction of the given time step
if ( suggestedNextTimestep_ < 0 ) {
suggestedNextTimestep_ = restartFactor_ * timestep ;
}
if ( fullTimestepInitially_ ) {
suggestedNextTimestep_ = timestep ;
}
// use seperate time step after event
if ( isEvent & & timestepAfterEvent_ > 0 ) {
suggestedNextTimestep_ = timestepAfterEvent_ ;
}
2018-06-06 03:59:41 -05:00
auto & ebosSimulator = solver . model ( ) . ebosSimulator ( ) ;
auto & ebosProblem = ebosSimulator . problem ( ) ;
2018-06-06 03:59:41 -05:00
// create adaptive step timer with previously used sub step size
AdaptiveSimulatorTimer substepTimer ( simulatorTimer , suggestedNextTimestep_ , maxTimeStep_ ) ;
// counter for solver restarts
int restarts = 0 ;
// sub step time loop
while ( ! substepTimer . done ( ) ) {
// get current delta t
const double dt = substepTimer . currentStepLength ( ) ;
if ( timestepVerbose_ ) {
2021-06-08 08:36:56 -05:00
logTimer ( substepTimer ) ;
2018-06-06 03:59:41 -05:00
}
2020-05-07 09:13:39 -05:00
SimulatorReportSingle substepReport ;
2018-06-06 03:59:41 -05:00
std : : string causeOfFailure = " " ;
try {
substepReport = solver . step ( substepTimer ) ;
if ( solverVerbose_ ) {
// report number of linear iterations
OpmLog : : debug ( " Overall linear iterations used: " + std : : to_string ( substepReport . total_linear_iterations ) ) ;
}
}
2021-05-05 04:22:44 -05:00
catch ( const TooManyIterations & e ) {
2020-05-07 15:09:17 -05:00
substepReport = solver . failureReport ( ) ;
2018-06-06 03:59:41 -05:00
causeOfFailure = " Solver convergence failure - Iteration limit reached " ;
logException_ ( e , solverVerbose_ ) ;
// since linearIterations is < 0 this will restart the solver
}
2021-05-05 04:22:44 -05:00
catch ( const LinearSolverProblem & e ) {
2020-05-07 15:09:17 -05:00
substepReport = solver . failureReport ( ) ;
2018-06-06 03:59:41 -05:00
causeOfFailure = " Linear solver convergence failure " ;
logException_ ( e , solverVerbose_ ) ;
// since linearIterations is < 0 this will restart the solver
}
2021-05-05 04:22:44 -05:00
catch ( const NumericalIssue & e ) {
2020-05-07 15:09:17 -05:00
substepReport = solver . failureReport ( ) ;
2018-06-06 03:59:41 -05:00
causeOfFailure = " Solver convergence failure - Numerical problem encountered " ;
logException_ ( e , solverVerbose_ ) ;
// since linearIterations is < 0 this will restart the solver
}
catch ( const std : : runtime_error & e ) {
2020-05-07 15:09:17 -05:00
substepReport = solver . failureReport ( ) ;
2018-06-06 03:59:41 -05:00
logException_ ( e , solverVerbose_ ) ;
// also catch linear solver not converged
}
catch ( const Dune : : ISTLError & e ) {
2020-05-07 15:09:17 -05:00
substepReport = solver . failureReport ( ) ;
2018-06-06 03:59:41 -05:00
logException_ ( e , solverVerbose_ ) ;
// also catch errors in ISTL AMG that occur when time step is too large
}
catch ( const Dune : : MatrixBlockError & e ) {
2020-05-07 15:09:17 -05:00
substepReport = solver . failureReport ( ) ;
2018-06-06 03:59:41 -05:00
logException_ ( e , solverVerbose_ ) ;
// this can be thrown by ISTL's ILU0 in block mode, yet is not an ISTLError
}
2022-02-03 04:58:09 -06:00
//Pass substep to eclwriter for summary output
ebosSimulator . problem ( ) . setSubStepReport ( substepReport ) ;
2020-05-07 09:13:39 -05:00
report + = substepReport ;
2021-09-09 00:46:09 -05:00
bool continue_on_uncoverged_solution = ignoreConvergenceFailure_ & & ! substepReport . converged & & dt < = minTimeStep_ ;
if ( continue_on_uncoverged_solution ) {
const auto msg = std : : string ( " Solver failed to converge but timestep " )
+ std : : to_string ( dt ) + " is smaller or equal to "
+ std : : to_string ( minTimeStep_ ) + " \n which is the minimum threshold given "
+ " by option --solver-min-time-step= \n " ;
if ( solverVerbose_ ) {
OpmLog : : error ( msg ) ;
}
}
if ( substepReport . converged | | continue_on_uncoverged_solution ) {
2018-06-06 03:59:41 -05:00
// advance by current dt
+ + substepTimer ;
// create object to compute the time error, simply forwards the call to the model
SolutionTimeErrorSolverWrapperEbos < Solver > relativeChange ( solver ) ;
// compute new time step estimate
const int iterations = useNewtonIteration_ ? substepReport . total_newton_iterations
: substepReport . total_linear_iterations ;
double dtEstimate = timeStepControl_ - > computeTimeStepSize ( dt , iterations , relativeChange ,
substepTimer . simulationTimeElapsed ( ) ) ;
2019-10-11 08:57:51 -05:00
assert ( dtEstimate > 0 ) ;
2018-06-06 03:59:41 -05:00
// limit the growth of the timestep size by the growth factor
dtEstimate = std : : min ( dtEstimate , double ( maxGrowth_ * dt ) ) ;
2019-10-11 08:57:51 -05:00
assert ( dtEstimate > 0 ) ;
2018-06-06 03:59:41 -05:00
// further restrict time step size growth after convergence problems
if ( restarts > 0 ) {
dtEstimate = std : : min ( growthFactor_ * dt , dtEstimate ) ;
// solver converged, reset restarts counter
restarts = 0 ;
}
2018-11-22 09:24:52 -06:00
// Further restrict time step size if we are in
2018-11-22 04:01:58 -06:00
// prediction mode with THP constraints.
if ( solver . model ( ) . wellModel ( ) . hasTHPConstraints ( ) ) {
const double maxPredictionTHPTimestep = 16.0 * unit : : day ;
dtEstimate = std : : min ( dtEstimate , maxPredictionTHPTimestep ) ;
}
2019-10-11 08:57:51 -05:00
assert ( dtEstimate > 0 ) ;
2018-06-06 03:59:41 -05:00
if ( timestepVerbose_ ) {
std : : ostringstream ss ;
substepReport . reportStep ( ss ) ;
OpmLog : : info ( ss . str ( ) ) ;
}
// write data if outputWriter was provided
// if the time step is done we do not need
// to write it as this will be done by the simulator
// anyway.
if ( ! substepTimer . done ( ) ) {
if ( fipnum ) {
solver . computeFluidInPlace ( * fipnum ) ;
}
2021-05-05 04:22:44 -05:00
time : : StopWatch perfTimer ;
2018-06-06 03:59:41 -05:00
perfTimer . start ( ) ;
2018-06-06 03:59:41 -05:00
2019-05-13 05:49:43 -05:00
ebosProblem . writeOutput ( ) ;
2018-06-06 03:59:41 -05:00
2020-05-07 09:13:39 -05:00
report . success . output_write_time + = perfTimer . secsSinceStart ( ) ;
2018-06-06 03:59:41 -05:00
}
// set new time step length
substepTimer . provideTimeStepEstimate ( dtEstimate ) ;
2020-05-07 09:13:39 -05:00
report . success . converged = substepTimer . done ( ) ;
2018-06-06 03:59:41 -05:00
substepTimer . setLastStepFailed ( false ) ;
}
2018-12-03 06:25:19 -06:00
else { // in case of no convergence
2018-06-06 03:59:41 -05:00
substepTimer . setLastStepFailed ( true ) ;
2018-12-03 06:25:19 -06:00
// If we have restarted (i.e. cut the timestep) too
// many times, we have failed and throw an exception.
2018-06-06 03:59:41 -05:00
if ( restarts > = solverRestartMax_ ) {
const auto msg = std : : string ( " Solver failed to converge after cutting timestep " )
+ std : : to_string ( restarts ) + " times. " ;
if ( solverVerbose_ ) {
OpmLog : : error ( msg ) ;
}
2021-05-05 04:22:44 -05:00
OPM_THROW_NOLOG ( NumericalIssue , msg ) ;
2018-06-06 03:59:41 -05:00
}
2018-12-03 06:25:19 -06:00
// The new, chopped timestep.
2018-06-06 03:59:41 -05:00
const double newTimeStep = restartFactor_ * dt ;
2018-12-03 06:25:19 -06:00
2019-11-28 08:18:39 -06:00
// If we have restarted (i.e. cut the timestep) too
// much, we have failed and throw an exception.
if ( newTimeStep < minTimeStep_ ) {
const auto msg = std : : string ( " Solver failed to converge after cutting timestep to " )
+ std : : to_string ( minTimeStep_ ) + " \n which is the minimum threshold given "
+ " by option --solver-min-time-step= \n " ;
if ( solverVerbose_ ) {
OpmLog : : error ( msg ) ;
}
2021-05-05 04:22:44 -05:00
OPM_THROW_NOLOG ( NumericalIssue , msg ) ;
2019-11-28 08:18:39 -06:00
}
2018-12-03 06:25:19 -06:00
// Define utility function for chopping timestep.
auto chopTimestep = [ & ] ( ) {
2018-11-22 09:24:52 -06:00
substepTimer . provideTimeStepEstimate ( newTimeStep ) ;
if ( solverVerbose_ ) {
std : : string msg ;
msg = causeOfFailure + " \n Timestep chopped to "
+ std : : to_string ( unit : : convert : : to ( substepTimer . currentStepLength ( ) , unit : : day ) ) + " days \n " ;
OpmLog : : problem ( msg ) ;
}
+ + restarts ;
2018-12-03 06:25:19 -06:00
} ;
2019-12-18 04:18:18 -06:00
const double minimumChoppedTimestep = minTimeStepBeforeShuttingProblematicWells_ ;
2018-12-03 06:25:19 -06:00
if ( newTimeStep > minimumChoppedTimestep ) {
chopTimestep ( ) ;
2018-11-22 09:24:52 -06:00
} else {
// We are below the threshold, and will check if there are any
// wells we should close rather than chopping again.
std : : set < std : : string > failing_wells = consistentlyFailingWells ( solver . model ( ) . stepReports ( ) ) ;
if ( failing_wells . empty ( ) ) {
// Found no wells to close, chop the timestep as above.
2018-12-03 06:25:19 -06:00
chopTimestep ( ) ;
2018-11-22 09:24:52 -06:00
} else {
// Close all consistently failing wells.
2018-12-03 06:25:19 -06:00
int num_shut_wells = 0 ;
2018-11-22 09:24:52 -06:00
for ( const auto & well : failing_wells ) {
2021-10-14 06:14:38 -05:00
bool was_shut = solver . model ( ) . wellModel ( ) . forceShutWellByName ( well , substepTimer . simulationTimeElapsed ( ) ) ;
2018-12-03 06:25:19 -06:00
if ( was_shut ) {
+ + num_shut_wells ;
}
2018-11-22 09:24:52 -06:00
}
2018-12-03 06:25:19 -06:00
if ( num_shut_wells = = 0 ) {
2021-10-14 06:14:38 -05:00
// None of the problematic wells were shut.
// We must fall back to chopping again.
2018-12-03 06:25:19 -06:00
chopTimestep ( ) ;
} else {
substepTimer . provideTimeStepEstimate ( dt ) ;
if ( solverVerbose_ ) {
std : : string msg ;
msg = " \n Problematic well(s) were shut: " ;
for ( const auto & well : failing_wells ) {
msg + = well ;
msg + = " " ;
}
msg + = " (retrying timestep) \n " ;
OpmLog : : problem ( msg ) ;
2018-11-22 09:24:52 -06:00
}
}
}
}
2018-06-06 03:59:41 -05:00
}
2018-08-16 04:51:36 -05:00
ebosProblem . setNextTimeStepSize ( substepTimer . currentStepLength ( ) ) ;
2018-06-06 03:59:41 -05:00
}
// store estimated time step for next reportStep
suggestedNextTimestep_ = substepTimer . currentStepLength ( ) ;
if ( timestepVerbose_ ) {
std : : ostringstream ss ;
substepTimer . report ( ss ) ;
ss < < " Suggested next step size = " < < unit : : convert : : to ( suggestedNextTimestep_ , unit : : day ) < < " (days) " < < std : : endl ;
OpmLog : : debug ( ss . str ( ) ) ;
}
if ( ! std : : isfinite ( suggestedNextTimestep_ ) ) { // check for NaN
suggestedNextTimestep_ = timestep ;
}
return report ;
}
/** \brief Returns the simulator report for the failed substeps of the last
* report step .
*/
double suggestedNextStep ( ) const
{ return suggestedNextTimestep_ ; }
void setSuggestedNextStep ( const double x )
{ suggestedNextTimestep_ = x ; }
2021-10-18 04:52:33 -05:00
void updateTUNING ( double max_next_tstep , const Tuning & tuning )
2018-06-06 03:59:41 -05:00
{
2020-01-31 06:42:50 -06:00
restartFactor_ = tuning . TSFCNV ;
growthFactor_ = tuning . TFDIFF ;
maxGrowth_ = tuning . TSFMAX ;
maxTimeStep_ = tuning . TSMAXZ ;
2021-10-18 04:52:33 -05:00
suggestedNextTimestep_ = max_next_tstep ;
2020-01-31 06:42:50 -06:00
timestepAfterEvent_ = tuning . TMAXWC ;
2018-06-06 03:59:41 -05:00
}
protected :
2021-02-17 04:30:57 -06:00
void init_ ( const UnitSystem & unitSystem )
2018-06-06 03:59:41 -05:00
{
// valid are "pid" and "pid+iteration"
2018-08-06 08:59:35 -05:00
std : : string control = EWOMS_GET_PARAM ( TypeTag , std : : string , TimeStepControl ) ; // "pid"
2018-06-06 03:59:41 -05:00
2018-08-06 08:59:35 -05:00
const double tol = EWOMS_GET_PARAM ( TypeTag , double , TimeStepControlTolerance ) ; // 1e-1
2018-06-06 03:59:41 -05:00
if ( control = = " pid " ) {
timeStepControl_ = TimeStepControlType ( new PIDTimeStepControl ( tol ) ) ;
}
else if ( control = = " pid+iteration " ) {
2018-08-06 08:59:35 -05:00
const int iterations = EWOMS_GET_PARAM ( TypeTag , int , TimeStepControlTargetIterations ) ; // 30
2020-10-01 07:02:39 -05:00
const double decayDampingFactor = EWOMS_GET_PARAM ( TypeTag , double , TimeStepControlDecayDampingFactor ) ; // 1.0
2020-11-09 04:45:13 -06:00
const double growthDampingFactor = EWOMS_GET_PARAM ( TypeTag , double , TimeStepControlGrowthDampingFactor ) ; // 3.2
2020-10-01 07:02:39 -05:00
timeStepControl_ = TimeStepControlType ( new PIDAndIterationCountTimeStepControl ( iterations , decayDampingFactor , growthDampingFactor , tol ) ) ;
2018-06-06 03:59:41 -05:00
}
else if ( control = = " pid+newtoniteration " ) {
2018-08-06 08:59:35 -05:00
const int iterations = EWOMS_GET_PARAM ( TypeTag , int , TimeStepControlTargetNewtonIterations ) ; // 8
2020-10-01 07:02:39 -05:00
const double decayDampingFactor = EWOMS_GET_PARAM ( TypeTag , double , TimeStepControlDecayDampingFactor ) ; // 1.0
2020-11-09 04:45:13 -06:00
const double growthDampingFactor = EWOMS_GET_PARAM ( TypeTag , double , TimeStepControlGrowthDampingFactor ) ; // 3.2
2021-02-17 04:30:57 -06:00
const double nonDimensionalMinTimeStepIterations = EWOMS_GET_PARAM ( TypeTag , double , MinTimeStepBasedOnNewtonIterations ) ; // 0.0 by default
// the min time step can be reduced by the newton iteration numbers
2021-03-18 03:23:48 -05:00
double minTimeStepReducedByIterations = unitSystem . to_si ( UnitSystem : : measure : : time , nonDimensionalMinTimeStepIterations ) ;
2021-02-17 04:30:57 -06:00
timeStepControl_ = TimeStepControlType ( new PIDAndIterationCountTimeStepControl ( iterations , decayDampingFactor ,
growthDampingFactor , tol , minTimeStepReducedByIterations ) ) ;
2018-06-06 03:59:41 -05:00
useNewtonIteration_ = true ;
}
else if ( control = = " iterationcount " ) {
2018-08-06 08:59:35 -05:00
const int iterations = EWOMS_GET_PARAM ( TypeTag , int , TimeStepControlTargetIterations ) ; // 30
const double decayrate = EWOMS_GET_PARAM ( TypeTag , double , TimeStepControlDecayRate ) ; // 0.75
const double growthrate = EWOMS_GET_PARAM ( TypeTag , double , TimeStepControlGrowthRate ) ; // 1.25
2018-06-06 03:59:41 -05:00
timeStepControl_ = TimeStepControlType ( new SimpleIterationCountTimeStepControl ( iterations , decayrate , growthrate ) ) ;
}
2020-10-01 07:02:39 -05:00
else if ( control = = " newtoniterationcount " ) {
const int iterations = EWOMS_GET_PARAM ( TypeTag , int , TimeStepControlTargetNewtonIterations ) ; // 8
const double decayrate = EWOMS_GET_PARAM ( TypeTag , double , TimeStepControlDecayRate ) ; // 0.75
const double growthrate = EWOMS_GET_PARAM ( TypeTag , double , TimeStepControlGrowthRate ) ; // 1.25
timeStepControl_ = TimeStepControlType ( new SimpleIterationCountTimeStepControl ( iterations , decayrate , growthrate ) ) ;
useNewtonIteration_ = true ;
}
2018-06-06 03:59:41 -05:00
else if ( control = = " hardcoded " ) {
2018-08-06 08:59:35 -05:00
const std : : string filename = EWOMS_GET_PARAM ( TypeTag , std : : string , TimeStepControlFileName ) ; // "timesteps"
2018-06-06 03:59:41 -05:00
timeStepControl_ = TimeStepControlType ( new HardcodedTimeStepControl ( filename ) ) ;
}
else
OPM_THROW ( std : : runtime_error , " Unsupported time step control selected " < < control ) ;
// make sure growth factor is something reasonable
assert ( growthFactor_ > = 1.0 ) ;
}
2021-10-06 05:11:44 -05:00
template < class ProblemType >
std : : set < std : : string > consistentlyFailingWells ( const std : : vector < ProblemType > & sr )
2018-11-22 09:24:52 -06:00
{
// If there are wells that cause repeated failures, we
// close them, and restart the un-chopped timestep.
std : : ostringstream msg ;
msg < < " Excessive chopping detected in report step "
< < sr . back ( ) . report_step < < " , substep " < < sr . back ( ) . current_step < < " \n " ;
2019-06-03 01:48:21 -05:00
std : : set < std : : string > failing_wells ;
// return empty set if no report exists
// well failures in assembly is not yet registred
if ( sr . back ( ) . report . empty ( ) )
return failing_wells ;
2018-11-22 09:24:52 -06:00
const auto & wfs = sr . back ( ) . report . back ( ) . wellFailures ( ) ;
for ( const auto & wf : wfs ) {
msg < < " Well that failed: " < < wf . wellName ( ) < < " \n " ;
}
msg . flush ( ) ;
OpmLog : : debug ( msg . str ( ) ) ;
// Check the last few step reports.
const int num_steps = 3 ;
const int rep_step = sr . back ( ) . report_step ;
const int sub_step = sr . back ( ) . current_step ;
const int sr_size = sr . size ( ) ;
if ( sr_size > = num_steps ) {
2020-05-29 09:20:04 -05:00
for ( const auto & wf : wfs ) {
failing_wells . insert ( wf . wellName ( ) ) ;
}
2019-06-26 02:50:56 -05:00
for ( int s = 1 ; s < num_steps ; + + s ) {
const auto & srep = sr [ sr_size - 1 - s ] ;
2018-11-22 09:24:52 -06:00
// Report must be from same report step and substep, otherwise we have
// not chopped/retried enough times on this step.
if ( srep . report_step ! = rep_step | | srep . current_step ! = sub_step ) {
break ;
}
// Get the failing wells for this step, that also failed all other steps.
std : : set < std : : string > failing_wells_step ;
for ( const auto & wf : srep . report . back ( ) . wellFailures ( ) ) {
if ( failing_wells . count ( wf . wellName ( ) ) > 0 ) {
failing_wells_step . insert ( wf . wellName ( ) ) ;
}
}
failing_wells . swap ( failing_wells_step ) ;
}
}
return failing_wells ;
}
2018-06-06 03:59:41 -05:00
typedef std : : unique_ptr < TimeStepControlInterface > TimeStepControlType ;
TimeStepControlType timeStepControl_ ; //!< time step control object
double restartFactor_ ; //!< factor to multiply time step with when solver fails to converge
double growthFactor_ ; //!< factor to multiply time step when solver recovered from failed convergence
double maxGrowth_ ; //!< factor that limits the maximum growth of a time step
2019-11-28 08:18:39 -06:00
double maxTimeStep_ ; //!< maximal allowed time step size in days
double minTimeStep_ ; //!< minimal allowed time step size before throwing
2021-09-09 00:46:09 -05:00
bool ignoreConvergenceFailure_ ; //!< continue instead of stop when minimum time step is reached
2018-06-21 05:14:17 -05:00
int solverRestartMax_ ; //!< how many restart of solver are allowed
bool solverVerbose_ ; //!< solver verbosity
bool timestepVerbose_ ; //!< timestep verbosity
2018-06-06 03:59:41 -05:00
double suggestedNextTimestep_ ; //!< suggested size of next timestep
bool fullTimestepInitially_ ; //!< beginning with the size of the time step from data file
double timestepAfterEvent_ ; //!< suggested size of timestep after an event
bool useNewtonIteration_ ; //!< use newton iteration count for adaptive time step control
2019-12-18 04:18:18 -06:00
double minTimeStepBeforeShuttingProblematicWells_ ; //! < shut problematic wells when time step size in days are less than this
2018-06-06 03:59:41 -05:00
} ;
}
# endif // OPM_ADAPTIVE_TIME_STEPPING_EBOS_HPP