diff --git a/opm/simulators/flow/SimulatorFullyImplicitBlackoil.hpp b/opm/simulators/flow/SimulatorFullyImplicitBlackoil.hpp index 6c003897e..c1af0fce8 100644 --- a/opm/simulators/flow/SimulatorFullyImplicitBlackoil.hpp +++ b/opm/simulators/flow/SimulatorFullyImplicitBlackoil.hpp @@ -378,29 +378,40 @@ public: // \Note: The report steps are met in any case // \Note: The sub stepping will require a copy of the state variables if (adaptiveTimeStepping_) { - const auto& events = schedule()[timer.currentStepNum()].events(); - if (events.hasEvent(ScheduleEvents::TUNING_CHANGE)) { - const auto& sched_state = schedule()[timer.currentStepNum()]; - const auto& max_next_tstep = sched_state.max_next_tstep(enableTUNING); - if (enableTUNING) { - const auto& tuning = sched_state.tuning(); - adaptiveTimeStepping_->updateTUNING(max_next_tstep, tuning); - // \Note: Assumes TUNING is only used with adaptive time-stepping - // \Note: Need to update both solver (model) and simulator since solver is re-created each report step. - solver_->model().updateTUNING(tuning); - this->updateTUNING(tuning); - } else { - adaptiveTimeStepping_->updateNEXTSTEP(max_next_tstep); - } - } + auto tuningUpdater = [enableTUNING, this, reportStep = timer.currentStepNum()]() + { + auto& schedule = this->ebosSimulator_.vanguard().schedule(); + auto& events = this->schedule()[reportStep].events(); + if (events.hasEvent(ScheduleEvents::TUNING_CHANGE)) { + // Unset the event to not trigger it again on the next sub step + schedule.clear_event(ScheduleEvents::TUNING_CHANGE, reportStep); + const auto& sched_state = schedule[reportStep]; + const auto& max_next_tstep = sched_state.max_next_tstep(enableTUNING); + const auto& tuning = sched_state.tuning(); + + if (enableTUNING) { + adaptiveTimeStepping_->updateTUNING(max_next_tstep, tuning); + // \Note: Assumes TUNING is only used with adaptive time-stepping + // \Note: Need to update both solver (model) and simulator since solver is re-created each report step. + solver_->model().updateTUNING(tuning); + this->updateTUNING(tuning); + } else { + this->adaptiveTimeStepping_->updateNEXTSTEP(max_next_tstep); + } + return max_next_tstep >0; + } + return false; + }; + tuningUpdater(); + const auto& events = schedule()[timer.currentStepNum()].events(); bool event = events.hasEvent(ScheduleEvents::NEW_WELL) || events.hasEvent(ScheduleEvents::INJECTION_TYPE_CHANGED) || events.hasEvent(ScheduleEvents::WELL_SWITCHED_INJECTOR_PRODUCER) || events.hasEvent(ScheduleEvents::PRODUCTION_UPDATE) || events.hasEvent(ScheduleEvents::INJECTION_UPDATE) || events.hasEvent(ScheduleEvents::WELL_STATUS_CHANGE); - auto stepReport = adaptiveTimeStepping_->step(timer, *solver_, event, nullptr); + auto stepReport = adaptiveTimeStepping_->step(timer, *solver_, event, nullptr, tuningUpdater); report_ += stepReport; //Pass simulation report to eclwriter for summary output ebosSimulator_.problem().setSimulationReport(report_); diff --git a/opm/simulators/timestepping/AdaptiveSimulatorTimer.cpp b/opm/simulators/timestepping/AdaptiveSimulatorTimer.cpp index db575bebd..2c36efcf5 100644 --- a/opm/simulators/timestepping/AdaptiveSimulatorTimer.cpp +++ b/opm/simulators/timestepping/AdaptiveSimulatorTimer.cpp @@ -62,7 +62,7 @@ namespace Opm return ( report_step_ == 0 ) && ( current_step_ == 0 ); } -AdaptiveSimulatorTimer& AdaptiveSimulatorTimer::operator++ () + AdaptiveSimulatorTimer& AdaptiveSimulatorTimer::operator++ () { ++current_step_; current_time_ += dt_; @@ -115,6 +115,12 @@ AdaptiveSimulatorTimer& AdaptiveSimulatorTimer::operator++ () return dt_; } + void AdaptiveSimulatorTimer::setCurrentStepLength(double dt) + { + assert(dt > 0); + dt_ = dt; + } + double AdaptiveSimulatorTimer::stepLengthTaken() const { assert( ! steps_.empty() ); diff --git a/opm/simulators/timestepping/AdaptiveSimulatorTimer.hpp b/opm/simulators/timestepping/AdaptiveSimulatorTimer.hpp index e02dc4684..3dffd4908 100644 --- a/opm/simulators/timestepping/AdaptiveSimulatorTimer.hpp +++ b/opm/simulators/timestepping/AdaptiveSimulatorTimer.hpp @@ -69,6 +69,9 @@ namespace Opm /// \brief \copydoc SimulationTimer::currentStepLength double currentStepLength () const; + // \brief Set next step length + void setCurrentStepLength(double dt); + /// \brief \copydoc SimulationTimer::totalTime double totalTime() const; diff --git a/opm/simulators/timestepping/AdaptiveTimeStepping.hpp b/opm/simulators/timestepping/AdaptiveTimeStepping.hpp index a3fa7df13..ed5be969e 100644 --- a/opm/simulators/timestepping/AdaptiveTimeStepping.hpp +++ b/opm/simulators/timestepping/AdaptiveTimeStepping.hpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -342,13 +343,18 @@ std::set consistentlyFailingWells(const std::vector& sr /** \brief step method that acts like the solver::step method in a sub cycle of time steps + \param tuningUpdater Function used to update TUNING parameters before each + time step. ACTIONX might change tuning. */ template SimulatorReport step(const SimulatorTimer& simulatorTimer, Solver& solver, const bool isEvent, - const std::vector* fipnum = nullptr) + const std::vector* fipnum = nullptr, + const std::function tuningUpdater = [](){return false;}) { + // Maybe update tuning + tuningUpdater(); SimulatorReport report; const double timestep = simulatorTimer.currentStepLength(); @@ -377,8 +383,14 @@ std::set consistentlyFailingWells(const std::vector& sr // sub step time loop while (!substepTimer.done()) { + // Maybe update tuning // get current delta t - const double dt = substepTimer.currentStepLength() ; + auto oldValue = suggestedNextTimestep_; + if (tuningUpdater()) { + substepTimer.setCurrentStepLength(suggestedNextTimestep_); + suggestedNextTimestep_ = oldValue; + } + const double dt = substepTimer.currentStepLength(); if (timestepVerbose_) { detail::logTimer(substepTimer); }