diff --git a/opm/autodiff/SimulatorBase_impl.hpp b/opm/autodiff/SimulatorBase_impl.hpp index 4eceb058c..03ad38f0d 100644 --- a/opm/autodiff/SimulatorBase_impl.hpp +++ b/opm/autodiff/SimulatorBase_impl.hpp @@ -105,9 +105,9 @@ namespace Opm std::ofstream tstep_os(tstep_filename.c_str()); const auto& schedule = eclipse_state_->getSchedule(); - const auto& events = schedule.getEvents(); // adaptive time stepping + const auto& events = schedule.getEvents(); std::unique_ptr< AdaptiveTimeStepping > adaptiveTimeStepping; if( param_.getDefault("timestep.adaptive", true ) ) { @@ -234,8 +234,12 @@ namespace Opm // // \Note: The report steps are met in any case // \Note: The sub stepping will require a copy of the state variables - if( adaptiveTimeStepping ) { - report += adaptiveTimeStepping->step( timer, *solver, state, well_state, output_writer_, + if( adaptiveTimeStepping ) { + bool event = events.hasEvent(ScheduleEvents::NEW_WELL, timer.currentStepNum()) || + events.hasEvent(ScheduleEvents::PRODUCTION_UPDATE, timer.currentStepNum()) || + events.hasEvent(ScheduleEvents::INJECTION_UPDATE, timer.currentStepNum()) || + events.hasEvent(ScheduleEvents::WELL_STATUS_CHANGE, timer.currentStepNum()); + report += adaptiveTimeStepping->step( timer, *solver, state, well_state, event, output_writer_, output_writer_.requireFIPNUM() ? &fipnum : nullptr ); } else { diff --git a/opm/autodiff/SimulatorFullyImplicitBlackoilEbos.hpp b/opm/autodiff/SimulatorFullyImplicitBlackoilEbos.hpp index 3ece9e051..0e584eaf5 100644 --- a/opm/autodiff/SimulatorFullyImplicitBlackoilEbos.hpp +++ b/opm/autodiff/SimulatorFullyImplicitBlackoilEbos.hpp @@ -162,6 +162,7 @@ public: const auto& schedule = eclState().getSchedule(); // adaptive time stepping + const auto& events = schedule.getEvents(); std::unique_ptr< AdaptiveTimeStepping > adaptiveTimeStepping; if( param_.getDefault("timestep.adaptive", true ) ) { @@ -306,7 +307,11 @@ public: // \Note: The report steps are met in any case // \Note: The sub stepping will require a copy of the state variables if( adaptiveTimeStepping ) { - report += adaptiveTimeStepping->step( timer, *solver, state, well_state, output_writer_, + bool event = events.hasEvent(ScheduleEvents::NEW_WELL, timer.currentStepNum()) || + events.hasEvent(ScheduleEvents::PRODUCTION_UPDATE, timer.currentStepNum()) || + events.hasEvent(ScheduleEvents::INJECTION_UPDATE, timer.currentStepNum()) || + events.hasEvent(ScheduleEvents::WELL_STATUS_CHANGE, timer.currentStepNum()); + report += adaptiveTimeStepping->step( timer, *solver, state, well_state, event, output_writer_, output_writer_.requireFIPNUM() ? &fipnum : nullptr ); } else { diff --git a/opm/autodiff/SimulatorFullyImplicitBlackoilMultiSegment_impl.hpp b/opm/autodiff/SimulatorFullyImplicitBlackoilMultiSegment_impl.hpp index 79cd39cb4..7fc3c88df 100644 --- a/opm/autodiff/SimulatorFullyImplicitBlackoilMultiSegment_impl.hpp +++ b/opm/autodiff/SimulatorFullyImplicitBlackoilMultiSegment_impl.hpp @@ -66,6 +66,7 @@ namespace Opm std::ofstream tstep_os(tstep_filename.c_str()); // adaptive time stepping + const auto& events = eclipse_state_->getSchedule().getEvents(); std::unique_ptr< AdaptiveTimeStepping > adaptiveTimeStepping; if( param_.getDefault("timestep.adaptive", true ) ) { @@ -173,7 +174,11 @@ namespace Opm // \Note: The report steps are met in any case // \Note: The sub stepping will require a copy of the state variables if( adaptiveTimeStepping ) { - adaptiveTimeStepping->step( timer, *solver, state, well_state, output_writer_ ); + bool event = events.hasEvent(ScheduleEvents::NEW_WELL, timer.currentStepNum()) || + events.hasEvent(ScheduleEvents::PRODUCTION_UPDATE, timer.currentStepNum()) || + events.hasEvent(ScheduleEvents::INJECTION_UPDATE, timer.currentStepNum()) || + events.hasEvent(ScheduleEvents::WELL_STATUS_CHANGE, timer.currentStepNum()); + adaptiveTimeStepping->step( timer, *solver, state, well_state, event, output_writer_); } else { // solve for complete report step diff --git a/opm/simulators/timestepping/AdaptiveTimeStepping.hpp b/opm/simulators/timestepping/AdaptiveTimeStepping.hpp index a1ebb3777..6ecc32ce4 100644 --- a/opm/simulators/timestepping/AdaptiveTimeStepping.hpp +++ b/opm/simulators/timestepping/AdaptiveTimeStepping.hpp @@ -63,10 +63,12 @@ namespace Opm { \param solver solver object that must implement a method step( dt, state, well_state ) \param state current state of the solution variables \param well_state additional well state object + \param event event status for possible tuning */ template SimulatorReport step( const SimulatorTimer& timer, - Solver& solver, State& state, WellState& well_state ); + Solver& solver, State& state, WellState& well_state, + const bool event); /** \brief step method that acts like the solver::step method in a sub cycle of time steps @@ -76,11 +78,13 @@ namespace Opm { \param solver solver object that must implement a method step( dt, state, well_state ) \param state current state of the solution variables \param well_state additional well state object + \param event event status for possible tuning \param outputWriter writer object to write sub steps */ template SimulatorReport step( const SimulatorTimer& timer, Solver& solver, State& state, WellState& well_state, + const bool event, Output& outputWriter, const std::vector* fipnum = nullptr); @@ -92,6 +96,7 @@ namespace Opm { template SimulatorReport stepImpl( const SimulatorTimer& timer, Solver& solver, State& state, WellState& well_state, + const bool event, Output* outputWriter, const std::vector* fipnum); @@ -109,6 +114,8 @@ namespace Opm { const bool timestep_verbose_; //!< timestep verbosity double suggested_next_timestep_; //!< suggested size of next timestep bool full_timestep_initially_; //!< beginning with the size of the time step from data file + const double timestep_after_event_; //!< suggested size of timestep after an event + bool use_newton_iteration_; //!< use newton iteration count for adaptive time step control }; } diff --git a/opm/simulators/timestepping/AdaptiveTimeStepping_impl.hpp b/opm/simulators/timestepping/AdaptiveTimeStepping_impl.hpp index 51dd28559..b398c8621 100644 --- a/opm/simulators/timestepping/AdaptiveTimeStepping_impl.hpp +++ b/opm/simulators/timestepping/AdaptiveTimeStepping_impl.hpp @@ -89,6 +89,8 @@ namespace Opm { , timestep_verbose_( param.getDefault("timestep.verbose", bool(true) ) && terminal_output ) , suggested_next_timestep_( tuning.getTSINIT(time_step) ) , full_timestep_initially_( param.getDefault("full_timestep_initially", bool(false) ) ) + , timestep_after_event_( tuning.getTMAXWC(time_step)) + , use_newton_iteration_(false) { init(param); @@ -107,6 +109,8 @@ namespace Opm { , timestep_verbose_( param.getDefault("timestep.verbose", bool(true) ) && terminal_output ) , suggested_next_timestep_( unit::convert::from(param.getDefault("timestep.initial_timestep_in_days", -1.0 ), unit::day) ) , full_timestep_initially_( param.getDefault("full_timestep_initially", bool(false) ) ) + , timestep_after_event_( unit::convert::from(param.getDefault("timestep.timestep_in_days_after_event", -1.0 ), unit::day)) + , use_newton_iteration_(false) { init(param); } @@ -118,6 +122,7 @@ namespace Opm { std::string control = param.getDefault("timestep.control", std::string("pid") ); // iterations is the accumulation of all linear iterations over all newton steops per time step const int defaultTargetIterations = 30; + const int defaultTargetNewtonIterations = 8; const double tol = param.getDefault("timestep.control.tol", double(1e-1) ); if( control == "pid" ) { @@ -128,6 +133,12 @@ namespace Opm { const int iterations = param.getDefault("timestep.control.targetiteration", defaultTargetIterations ); timeStepControl_ = TimeStepControlType( new PIDAndIterationCountTimeStepControl( iterations, tol ) ); } + else if ( control == "pid+newtoniteration" ) + { + const int iterations = param.getDefault("timestep.control.targetiteration", defaultTargetNewtonIterations ); + timeStepControl_ = TimeStepControlType( new PIDAndIterationCountTimeStepControl( iterations, tol ) ); + use_newton_iteration_ = true; + } else if ( control == "iterationcount" ) { const int iterations = param.getDefault("timestep.control.targetiteration", defaultTargetIterations ); @@ -150,19 +161,20 @@ namespace Opm { template SimulatorReport AdaptiveTimeStepping:: - step( const SimulatorTimer& simulatorTimer, Solver& solver, State& state, WellState& well_state ) + step( const SimulatorTimer& simulatorTimer, Solver& solver, State& state, WellState& well_state, const bool event ) { - return stepImpl( simulatorTimer, solver, state, well_state, nullptr, nullptr ); + return stepImpl( simulatorTimer, solver, state, well_state, event, nullptr, nullptr ); } template SimulatorReport AdaptiveTimeStepping:: step( const SimulatorTimer& simulatorTimer, Solver& solver, State& state, WellState& well_state, + const bool event, Output& outputWriter, const std::vector* fipnum) { - return stepImpl( simulatorTimer, solver, state, well_state, &outputWriter, fipnum ); + return stepImpl( simulatorTimer, solver, state, well_state, event, &outputWriter, fipnum ); } @@ -171,6 +183,7 @@ namespace Opm { SimulatorReport AdaptiveTimeStepping:: stepImpl( const SimulatorTimer& simulatorTimer, Solver& solver, State& state, WState& well_state, + const bool event, Output* outputWriter, const std::vector* fipnum) { @@ -186,8 +199,10 @@ namespace Opm { suggested_next_timestep_ = timestep; } - // TODO - // take change in well state into account + // use seperate time step after event + if (event && timestep_after_event_ > 0) { + suggested_next_timestep_ = timestep_after_event_; + } // create adaptive step timer with previously used sub step size AdaptiveSimulatorTimer substepTimer( simulatorTimer, suggested_next_timestep_, max_time_step_ ); @@ -249,8 +264,10 @@ namespace Opm { relativeChange( solver, last_state, state ); // compute new time step estimate - double dtEstimate = - timeStepControl_->computeTimeStepSize( dt, substepReport.total_linear_iterations, relativeChange, substepTimer.simulationTimeElapsed()); + const int iterations = use_newton_iteration_ ? substepReport.total_newton_iterations + : substepReport.total_linear_iterations; + double dtEstimate = timeStepControl_->computeTimeStepSize( dt, iterations, relativeChange, + substepTimer.simulationTimeElapsed()); // limit the growth of the timestep size by the growth factor dtEstimate = std::min( dtEstimate, double(max_growth_ * dt) ); diff --git a/opm/simulators/timestepping/TimeStepControl.cpp b/opm/simulators/timestepping/TimeStepControl.cpp index ebbfaa428..ff3521a83 100644 --- a/opm/simulators/timestepping/TimeStepControl.cpp +++ b/opm/simulators/timestepping/TimeStepControl.cpp @@ -177,16 +177,20 @@ namespace Opm double PIDAndIterationCountTimeStepControl:: computeTimeStepSize( const double dt, const int iterations, const RelativeChangeInterface& relChange, const double simulationTimeElapsed ) const { - double dtEstimate = BaseType :: computeTimeStepSize( dt, iterations, relChange, simulationTimeElapsed); + double dtEstimatePID = BaseType :: computeTimeStepSize( dt, iterations, relChange, simulationTimeElapsed); - // further reduce step size if to many iterations were used - if( iterations > target_iterations_ ) - { - // if iterations was the same or dts were the same, do some magic - dtEstimate *= double( target_iterations_ ) / double(iterations); + // adjust timesteps based on target iteration + double dtEstimateIter; + if (iterations > target_iterations_) { + double off_target_fraction = double(iterations - target_iterations_) / target_iterations_; + dtEstimateIter = dt / (1.0 + off_target_fraction); + } else { + double off_target_fraction = double(target_iterations_ - iterations) / target_iterations_; + // Be a bit more careful when increasing. The 1.2 factor is from ebos. + dtEstimateIter = dt * (1.0 + off_target_fraction / 1.2); } - return dtEstimate; + return std::min(dtEstimatePID, dtEstimateIter); } } // end namespace Opm