20 #ifndef OPM_ADAPTIVE_TIME_STEPPING_IMPL_HPP 21 #define OPM_ADAPTIVE_TIME_STEPPING_IMPL_HPP 24 #ifndef OPM_ADAPTIVE_TIME_STEPPING_HPP 26 #include <opm/simulators/timestepping/AdaptiveTimeStepping.hpp> 27 #include <opm/simulators/timestepping/AdaptiveSimulatorTimer.hpp> 30 #include <dune/common/timer.hh> 31 #include <dune/istl/istlexception.hh> 33 #include <opm/common/Exceptions.hpp> 34 #include <opm/common/ErrorMacros.hpp> 35 #include <opm/common/OpmLog/OpmLog.hpp> 37 #include <opm/grid/utility/StopWatch.hpp> 39 #include <opm/input/eclipse/Schedule/Tuning.hpp> 41 #include <opm/input/eclipse/Units/Units.hpp> 42 #include <opm/input/eclipse/Units/UnitSystem.hpp> 46 #include <opm/simulators/timestepping/EclTimeSteppingParams.hpp> 54 #include <boost/date_time/posix_time/posix_time.hpp> 55 #include <fmt/format.h> 56 #include <fmt/ranges.h> 64 template<
class TypeTag>
65 AdaptiveTimeStepping<TypeTag>::
66 AdaptiveTimeStepping(
const UnitSystem& unit_system,
68 const double max_next_tstep,
69 const bool terminal_output
71 : time_step_control_{}
72 , restart_factor_{Parameters::Get<Parameters::SolverRestartFactor<Scalar>>()}
73 , growth_factor_{Parameters::Get<Parameters::SolverGrowthFactor<Scalar>>()}
74 , max_growth_{Parameters::Get<Parameters::SolverMaxGrowth<Scalar>>()}
76 Parameters::Get<Parameters::SolverMaxTimeStepInDays<Scalar>>() * 24 * 60 * 60}
78 unit_system.to_si(UnitSystem::measure::time,
79 Parameters::Get<Parameters::SolverMinTimeStep<Scalar>>())}
80 , ignore_convergence_failure_{
81 Parameters::Get<Parameters::SolverContinueOnConvergenceFailure>()}
82 , solver_restart_max_{Parameters::Get<Parameters::SolverMaxRestarts>()}
83 , solver_verbose_{Parameters::Get<Parameters::SolverVerbosity>() > 0 && terminal_output}
84 , timestep_verbose_{Parameters::Get<Parameters::TimeStepVerbosity>() > 0 && terminal_output}
85 , suggested_next_timestep_{
86 (max_next_tstep <= 0 ? Parameters::Get<Parameters::InitialTimeStepInDays>()
87 : max_next_tstep) * 24 * 60 * 60}
88 , full_timestep_initially_{Parameters::Get<Parameters::FullTimeStepInitially>()}
89 , timestep_after_event_{
90 Parameters::Get<Parameters::TimeStepAfterEventInDays<Scalar>>() * 24 * 60 * 60}
91 , use_newton_iteration_{
false}
92 , min_time_step_before_shutting_problematic_wells_{
93 Parameters::Get<Parameters::MinTimeStepBeforeShuttingProblematicWellsInDays>() * unit::day}
105 template<
class TypeTag>
106 AdaptiveTimeStepping<TypeTag>::
107 AdaptiveTimeStepping(
double max_next_tstep,
108 const Tuning& tuning,
109 const UnitSystem& unit_system,
111 const bool terminal_output
113 : time_step_control_{}
114 , restart_factor_{tuning.TSFCNV}
115 , growth_factor_{tuning.TFDIFF}
116 , max_growth_{tuning.TSFMAX}
117 , max_time_step_{tuning.TSMAXZ}
118 , min_time_step_{tuning.TSMINZ}
119 , ignore_convergence_failure_{
true}
120 , solver_restart_max_{Parameters::Get<Parameters::SolverMaxRestarts>()}
121 , solver_verbose_{Parameters::Get<Parameters::SolverVerbosity>() > 0 && terminal_output}
122 , timestep_verbose_{Parameters::Get<Parameters::TimeStepVerbosity>() > 0 && terminal_output}
123 , suggested_next_timestep_{
124 max_next_tstep <= 0 ? Parameters::Get<Parameters::InitialTimeStepInDays>() * 24 * 60 * 60
126 , full_timestep_initially_{Parameters::Get<Parameters::FullTimeStepInitially>()}
127 , timestep_after_event_{tuning.TMAXWC}
128 , use_newton_iteration_{
false}
129 , min_time_step_before_shutting_problematic_wells_{
130 Parameters::Get<Parameters::MinTimeStepBeforeShuttingProblematicWellsInDays>() * unit::day}
136 template<
class TypeTag>
138 AdaptiveTimeStepping<TypeTag>::
139 operator==(
const AdaptiveTimeStepping<TypeTag>& rhs)
const 141 if (this->time_step_control_type_ != rhs.time_step_control_type_ ||
142 (this->time_step_control_ && !rhs.time_step_control_) ||
143 (!this->time_step_control_ && rhs.time_step_control_)) {
148 switch (this->time_step_control_type_) {
149 case TimeStepControlType::HardCodedTimeStep:
150 result = castAndComp<HardcodedTimeStepControl>(rhs);
152 case TimeStepControlType::PIDAndIterationCount:
153 result = castAndComp<PIDAndIterationCountTimeStepControl>(rhs);
155 case TimeStepControlType::SimpleIterationCount:
156 result = castAndComp<SimpleIterationCountTimeStepControl>(rhs);
158 case TimeStepControlType::PID:
159 result = castAndComp<PIDTimeStepControl>(rhs);
161 case TimeStepControlType::General3rdOrder:
162 result = castAndComp<General3rdOrderController>(rhs);
167 this->restart_factor_ == rhs.restart_factor_ &&
168 this->growth_factor_ == rhs.growth_factor_ &&
169 this->max_growth_ == rhs.max_growth_ &&
170 this->max_time_step_ == rhs.max_time_step_ &&
171 this->min_time_step_ == rhs.min_time_step_ &&
172 this->ignore_convergence_failure_ == rhs.ignore_convergence_failure_ &&
173 this->solver_restart_max_== rhs.solver_restart_max_ &&
174 this->solver_verbose_ == rhs.solver_verbose_ &&
175 this->full_timestep_initially_ == rhs.full_timestep_initially_ &&
176 this->timestep_after_event_ == rhs.timestep_after_event_ &&
177 this->use_newton_iteration_ == rhs.use_newton_iteration_ &&
178 this->min_time_step_before_shutting_problematic_wells_ ==
179 rhs.min_time_step_before_shutting_problematic_wells_;
182 template<
class TypeTag>
184 AdaptiveTimeStepping<TypeTag>::
187 registerEclTimeSteppingParameters<Scalar>();
188 detail::registerAdaptiveParameters();
192 template<
class TypeTag>
193 template <
class Solver>
201 SubStepper<Solver> sub_stepper{
202 *
this, simulator_timer, solver, is_event, tuning_updater,
204 return sub_stepper.run();
207 template<
class TypeTag>
208 template<
class Serializer>
213 serializer(this->time_step_control_type_);
214 switch (this->time_step_control_type_) {
215 case TimeStepControlType::HardCodedTimeStep:
216 allocAndSerialize<HardcodedTimeStepControl>(serializer);
218 case TimeStepControlType::PIDAndIterationCount:
219 allocAndSerialize<PIDAndIterationCountTimeStepControl>(serializer);
221 case TimeStepControlType::SimpleIterationCount:
222 allocAndSerialize<SimpleIterationCountTimeStepControl>(serializer);
224 case TimeStepControlType::PID:
225 allocAndSerialize<PIDTimeStepControl>(serializer);
227 case TimeStepControlType::General3rdOrder:
228 allocAndSerialize<General3rdOrderController>(serializer);
231 serializer(this->restart_factor_);
232 serializer(this->growth_factor_);
233 serializer(this->max_growth_);
234 serializer(this->max_time_step_);
235 serializer(this->min_time_step_);
236 serializer(this->ignore_convergence_failure_);
237 serializer(this->solver_restart_max_);
238 serializer(this->solver_verbose_);
239 serializer(this->timestep_verbose_);
240 serializer(this->suggested_next_timestep_);
241 serializer(this->full_timestep_initially_);
242 serializer(this->timestep_after_event_);
243 serializer(this->use_newton_iteration_);
244 serializer(this->min_time_step_before_shutting_problematic_wells_);
247 template<
class TypeTag>
249 AdaptiveTimeStepping<TypeTag>::
255 template<
class TypeTag>
256 AdaptiveTimeStepping<TypeTag>
257 AdaptiveTimeStepping<TypeTag>::
258 serializationTestObjectHardcoded()
260 return serializationTestObject_<HardcodedTimeStepControl>();
263 template<
class TypeTag>
264 AdaptiveTimeStepping<TypeTag>
265 AdaptiveTimeStepping<TypeTag>::
266 serializationTestObjectPID()
268 return serializationTestObject_<PIDTimeStepControl>();
271 template<
class TypeTag>
272 AdaptiveTimeStepping<TypeTag>
273 AdaptiveTimeStepping<TypeTag>::
274 serializationTestObjectPIDIt()
276 return serializationTestObject_<PIDAndIterationCountTimeStepControl>();
279 template<
class TypeTag>
280 AdaptiveTimeStepping<TypeTag>
281 AdaptiveTimeStepping<TypeTag>::
282 serializationTestObjectSimple()
284 return serializationTestObject_<SimpleIterationCountTimeStepControl>();
287 template<
class TypeTag>
288 AdaptiveTimeStepping<TypeTag>
289 AdaptiveTimeStepping<TypeTag>::
290 serializationTestObject3rdOrder()
292 return serializationTestObject_<General3rdOrderController>();
296 template<
class TypeTag>
301 this->suggested_next_timestep_ = x;
304 template<
class TypeTag>
309 return this->suggested_next_timestep_;
312 template<
class TypeTag>
317 return *this->time_step_control_;
321 template<
class TypeTag>
328 if (max_next_tstep > 0) {
329 this->suggested_next_timestep_ = max_next_tstep;
333 template<
class TypeTag>
338 this->restart_factor_ = tuning.TSFCNV;
339 this->growth_factor_ = tuning.TFDIFF;
340 this->max_growth_ = tuning.TSFMAX;
341 this->max_time_step_ = tuning.TSMAXZ;
342 updateNEXTSTEP(max_next_tstep);
343 this->timestep_after_event_ = tuning.TMAXWC;
350 template<
class TypeTag>
351 template<
class T,
class Serializer>
356 if (!serializer.isSerializing()) {
357 this->time_step_control_ = std::make_unique<T>();
359 serializer(*static_cast<T*>(this->time_step_control_.get()));
362 template<
class TypeTag>
365 AdaptiveTimeStepping<TypeTag>::
366 castAndComp(
const AdaptiveTimeStepping<TypeTag>& Rhs)
const 368 const T* lhs =
static_cast<const T*
>(this->time_step_control_.get());
369 const T* rhs =
static_cast<const T*
>(Rhs.time_step_control_.get());
373 template<
class TypeTag>
375 AdaptiveTimeStepping<TypeTag>::
376 maybeModifySuggestedTimeStepAtBeginningOfReportStep_(
const double original_time_step,
380 if (this->suggested_next_timestep_ < 0) {
381 this->suggested_next_timestep_ = this->restart_factor_ * original_time_step;
384 if (this->full_timestep_initially_) {
385 this->suggested_next_timestep_ = original_time_step;
389 if (is_event && this->timestep_after_event_ > 0) {
390 this->suggested_next_timestep_ = this->timestep_after_event_;
394 template<
class TypeTag>
395 template<
class Controller>
396 AdaptiveTimeStepping<TypeTag>
397 AdaptiveTimeStepping<TypeTag>::
398 serializationTestObject_()
400 AdaptiveTimeStepping<TypeTag> result;
402 result.restart_factor_ = 1.0;
403 result.growth_factor_ = 2.0;
404 result.max_growth_ = 3.0;
405 result.max_time_step_ = 4.0;
406 result.min_time_step_ = 5.0;
407 result.ignore_convergence_failure_ =
true;
408 result.solver_restart_max_ = 6;
409 result.solver_verbose_ =
true;
410 result.timestep_verbose_ =
true;
411 result.suggested_next_timestep_ = 7.0;
412 result.full_timestep_initially_ =
true;
413 result.use_newton_iteration_ =
true;
414 result.min_time_step_before_shutting_problematic_wells_ = 9.0;
415 result.time_step_control_type_ = Controller::Type;
416 result.time_step_control_ =
417 std::make_unique<Controller>(Controller::serializationTestObject());
426 template<
class TypeTag>
427 void AdaptiveTimeStepping<TypeTag>::
428 init_(
const UnitSystem& unitSystem)
430 std::tie(time_step_control_type_,
432 use_newton_iteration_) = detail::createController(unitSystem);
434 if (this->growth_factor_ < 1.0) {
435 OPM_THROW(std::runtime_error,
436 "Growth factor cannot be less than 1.");
446 template<
class TypeTag>
447 template<
class Solver>
448 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
449 SubStepper(AdaptiveTimeStepping<TypeTag>& adaptive_time_stepping,
450 const SimulatorTimer& simulator_timer,
453 const TuningUpdateCallback& tuning_updater)
454 : adaptive_time_stepping_{adaptive_time_stepping}
455 , simulator_timer_{simulator_timer}
457 , is_event_{is_event}
458 , tuning_updater_{tuning_updater}
462 template<
class TypeTag>
463 template<
class Solver>
464 AdaptiveTimeStepping<TypeTag>&
465 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
466 getAdaptiveTimerStepper()
468 return adaptive_time_stepping_;
471 template<
class TypeTag>
472 template<
class Solver>
474 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
477 #ifdef RESERVOIR_COUPLING_ENABLED 478 if (isReservoirCouplingSlave_() && reservoirCouplingSlave_().activated()) {
479 return runStepReservoirCouplingSlave_();
481 else if (isReservoirCouplingMaster_() && reservoirCouplingMaster_().activated()) {
482 return runStepReservoirCouplingMaster_();
485 return runStepOriginal_();
488 return runStepOriginal_();
496 #ifdef RESERVOIR_COUPLING_ENABLED 497 template<
class TypeTag>
498 template<
class Solver>
500 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
501 isReservoirCouplingMaster_()
const 503 return this->solver_.model().simulator().reservoirCouplingMaster() !=
nullptr;
506 template<
class TypeTag>
507 template<
class Solver>
509 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
510 isReservoirCouplingSlave_()
const 512 return this->solver_.model().simulator().reservoirCouplingSlave() !=
nullptr;
516 template<
class TypeTag>
517 template<
class Solver>
519 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
520 maybeModifySuggestedTimeStepAtBeginningOfReportStep_(
const double original_time_step)
522 this->adaptive_time_stepping_.maybeModifySuggestedTimeStepAtBeginningOfReportStep_(
523 original_time_step, this->is_event_
530 template<
class TypeTag>
531 template<
class Solver>
533 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
534 maybeUpdateTuning_(
double elapsed,
double substep_length,
int sub_step_number)
const 536 return this->tuning_updater_(elapsed, substep_length, sub_step_number);
539 template<
class TypeTag>
540 template<
class Solver>
542 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
545 return this->adaptive_time_stepping_.max_time_step_;
548 template <
class TypeTag>
549 template <
class Solver>
551 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
554 const auto elapsed = this->simulator_timer_.simulationTimeElapsed();
555 const auto original_time_step = this->simulator_timer_.currentStepLength();
556 const auto report_step = this->simulator_timer_.reportStepNum();
557 maybeUpdateTuning_(elapsed, suggestedNextTimestep_(), 0);
558 maybeModifySuggestedTimeStepAtBeginningOfReportStep_(original_time_step);
560 AdaptiveSimulatorTimer substep_timer{
561 this->simulator_timer_.startDateTime(),
564 suggestedNextTimestep_(),
568 SubStepIteration<Solver> substepIteration{*
this, substep_timer, original_time_step,
true};
569 return substepIteration.run();
572 #ifdef RESERVOIR_COUPLING_ENABLED 573 template <
class TypeTag>
574 template <
class Solver>
575 ReservoirCouplingMaster<typename AdaptiveTimeStepping<TypeTag>::Scalar>&
576 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
577 reservoirCouplingMaster_()
579 return *(this->solver_.model().simulator().reservoirCouplingMaster());
583 #ifdef RESERVOIR_COUPLING_ENABLED 584 template <
class TypeTag>
585 template <
class Solver>
586 ReservoirCouplingSlave<typename AdaptiveTimeStepping<TypeTag>::Scalar>&
587 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
588 reservoirCouplingSlave_()
590 return *(this->solver_.model().simulator().reservoirCouplingSlave());
594 #ifdef RESERVOIR_COUPLING_ENABLED 625 template <
class TypeTag>
626 template <
class Solver>
628 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
629 runStepReservoirCouplingMaster_()
632 const double original_time_step = this->simulator_timer_.currentStepLength();
633 double current_time{this->simulator_timer_.simulationTimeElapsed()};
634 double step_end_time = current_time + original_time_step;
635 auto current_step_length = original_time_step;
636 auto report_step_idx = this->simulator_timer_.currentStepNum();
637 if (report_step_idx == 0 && iteration == 0) {
638 reservoirCouplingMaster_().initTimeStepping();
640 SimulatorReport report;
642 reservoirCouplingMaster_().maybeReceiveActivationHandshakeFromSlaves(current_time);
644 reservoirCouplingMaster_().sendDontTerminateSignalToSlaves();
645 reservoirCouplingMaster_().receiveNextReportDateFromSlaves();
646 bool start_of_report_step = (iteration == 0);
647 if (start_of_report_step) {
648 reservoirCouplingMaster_().initStartOfReportStep(report_step_idx);
650 current_step_length = reservoirCouplingMaster_().maybeChopSubStep(
651 current_step_length, current_time);
652 auto num_active = reservoirCouplingMaster_().numActivatedSlaves();
653 OpmLog::info(fmt::format(
654 "\nChoosing next sync time between master and {} active slave {}: {:.2f} days",
655 num_active, (num_active == 1 ?
"process" :
"processes"),
656 current_step_length / unit::day
658 reservoirCouplingMaster_().sendNextTimeStepToSlaves(current_step_length);
659 if (start_of_report_step) {
660 maybeUpdateTuning_(current_time, suggestedNextTimestep_(), 0);
661 maybeModifySuggestedTimeStepAtBeginningOfReportStep_(current_step_length);
663 AdaptiveSimulatorTimer substep_timer{
664 this->simulator_timer_.startDateTime(),
667 suggestedNextTimestep_(),
668 this->simulator_timer_.reportStepNum(),
672 current_time + current_step_length, step_end_time
677 reservoirCouplingMaster_().setFirstSubstepOfSyncTimestep(
true);
681 reservoirCouplingMaster_().setNeedsSlaveDataReceive(
true);
682 SubStepIteration<Solver> substepIteration{*
this, substep_timer, current_step_length, final_step};
683 const auto sub_steps_report = substepIteration.run();
684 report += sub_steps_report;
685 current_time += current_step_length;
695 #ifdef RESERVOIR_COUPLING_ENABLED 696 template <
class TypeTag>
697 template <
class Solver>
699 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
700 runStepReservoirCouplingSlave_()
703 const double original_time_step = this->simulator_timer_.currentStepLength();
704 double current_time{this->simulator_timer_.simulationTimeElapsed()};
705 double step_end_time = current_time + original_time_step;
706 SimulatorReport report;
707 auto report_step_idx = this->simulator_timer_.currentStepNum();
708 if (report_step_idx == 0 && iteration == 0) {
709 reservoirCouplingSlave_().initTimeStepping();
712 bool start_of_report_step = (iteration == 0);
713 if (reservoirCouplingSlave_().maybeReceiveTerminateSignalFromMaster()) {
717 reservoirCouplingSlave_().sendNextReportDateToMasterProcess();
718 const auto timestep = reservoirCouplingSlave_().receiveNextTimeStepFromMaster();
719 if (start_of_report_step) {
720 maybeUpdateTuning_(current_time, suggestedNextTimestep_(), 0);
721 maybeModifySuggestedTimeStepAtBeginningOfReportStep_(timestep);
723 AdaptiveSimulatorTimer substep_timer{
724 this->simulator_timer_.startDateTime(),
727 suggestedNextTimestep_(),
728 this->simulator_timer_.reportStepNum(),
732 current_time + timestep, step_end_time
737 reservoirCouplingSlave_().setFirstSubstepOfSyncTimestep(
true);
738 SubStepIteration<Solver> substepIteration{*
this, substep_timer, timestep, final_step};
739 const auto sub_steps_report = substepIteration.run();
740 report += sub_steps_report;
741 current_time += timestep;
752 template <
class TypeTag>
753 template <
class Solver>
755 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
756 suggestedNextTimestep_()
const 758 return this->adaptive_time_stepping_.suggestedNextStep();
767 template<
class TypeTag>
768 template<
class Solver>
769 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
770 SubStepIteration(SubStepper<Solver>& substepper,
771 AdaptiveSimulatorTimer& substep_timer,
772 const double original_time_step,
774 : substepper_{substepper}
775 , substep_timer_{substep_timer}
776 , original_time_step_{original_time_step}
777 , final_step_{final_step}
778 , adaptive_time_stepping_{substepper.getAdaptiveTimerStepper()}
782 template <
class TypeTag>
783 template <
class Solver>
785 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
788 auto& simulator = solver_().model().simulator();
789 auto& problem = simulator.problem();
792 SimulatorReport report;
795 while (!this->substep_timer_.done()) {
799 maybeUpdateTuningAndTimeStep_();
801 const double dt = this->substep_timer_.currentStepLength();
802 if (timeStepVerbose_()) {
803 detail::logTimer(this->substep_timer_);
806 maybeUpdateLastSubstepOfSyncTimestep_(dt);
807 auto substep_report = runSubStep_();
808 markFirstSubStepAsFinished_();
810 if (substep_report.converged || checkContinueOnUnconvergedSolution_(dt)) {
811 Dune::Timer perfTimer;
814 problem.setSubStepReport(substep_report);
815 auto& full_report = adaptive_time_stepping_.report();
816 full_report += substep_report;
817 problem.setSimulationReport(full_report);
818 problem.endTimeStep();
819 substep_report.pre_post_time += perfTimer.stop();
821 report += substep_report;
823 ++this->substep_timer_;
825 const int iterations = getNumIterations_(substep_report);
826 auto dt_estimate = timeStepControlComputeEstimate_(
827 dt, iterations, this->substep_timer_);
829 assert(dt_estimate > 0);
830 dt_estimate = maybeRestrictTimeStepGrowth_(dt, dt_estimate, restarts);
833 maybeReportSubStep_(substep_report);
834 if (this->final_step_ && this->substep_timer_.done()) {
839 report.success.output_write_time += writeOutput_();
843 setTimeStep_(dt_estimate);
845 report.success.converged = this->substep_timer_.done();
846 this->substep_timer_.setLastStepFailed(
false);
849 report += substep_report;
850 this->substep_timer_.setLastStepFailed(
true);
851 checkTimeStepMaxRestartLimit_(restarts);
853 double new_time_step = restartFactor_() * dt;
854 if (substep_report.time_step_rejected) {
855 const double tol = Parameters::Get<Parameters::TimeStepControlTolerance>();
856 const double safetyFactor = Parameters::Get<Parameters::TimeStepControlSafetyFactor>();
857 const double temp_time_step = std::sqrt(safetyFactor * tol / solver_().model().relativeChange()) * dt;
858 if (temp_time_step < dt) {
859 new_time_step = temp_time_step;
862 checkTimeStepMinLimit_(new_time_step);
863 bool wells_shut =
false;
864 if (new_time_step > minTimeStepBeforeClosingWells_()) {
865 chopTimeStep_(new_time_step);
867 wells_shut = chopTimeStepOrCloseFailingWells_(new_time_step);
876 problem.setNextTimeStepSize(this->substep_timer_.currentStepLength());
878 updateSuggestedNextStep_();
888 template<
class TypeTag>
889 template<
class Solver>
891 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
892 checkContinueOnUnconvergedSolution_(
double dt)
const 894 const bool continue_on_uncoverged_solution = ignoreConvergenceFailure_() && dt <= minTimeStep_();
895 if (continue_on_uncoverged_solution && solverVerbose_()) {
897 const auto msg = fmt::format(
898 "Solver failed to converge but timestep {} is smaller or equal to {}\n" 899 "which is the minimum threshold given by option --solver-min-time-step\n",
902 OpmLog::problem(msg);
904 return continue_on_uncoverged_solution;
907 template<
class TypeTag>
908 template<
class Solver>
910 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
911 checkTimeStepMaxRestartLimit_(
const int restarts)
const 915 if (restarts >= solverRestartMax_()) {
916 const auto msg = fmt::format(
917 fmt::runtime(
"Solver failed to converge after cutting timestep {} times."), restarts
919 if (solverVerbose_()) {
923 throw TimeSteppingBreakdown{msg};
927 template<
class TypeTag>
928 template<
class Solver>
930 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
931 checkTimeStepMinLimit_(
const double new_time_step)
const 933 using Meas = UnitSystem::measure;
936 if (new_time_step < minTimeStep_()) {
937 std::string msg =
"Solver failed to converge after cutting timestep to ";
938 if (Parameters::Get<Parameters::EnableTuning>()) {
939 const UnitSystem& unit_system = solver_().model().simulator().vanguard().eclState().getDeckUnitSystem();
941 "{:.3E} {}\nwhich is the minimum threshold given by the TUNING keyword\n",
942 unit_system.from_si(Meas::time, minTimeStep_()),
943 unit_system.name(Meas::time)
948 "{:.3E} DAYS\nwhich is the minimum threshold given by option --solver-min-time-step\n",
949 minTimeStep_() / 86400.0
952 if (solverVerbose_()) {
956 throw TimeSteppingBreakdown{msg};
960 template<
class TypeTag>
961 template<
class Solver>
963 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
964 chopTimeStep_(
const double new_time_step)
966 setTimeStep_(new_time_step);
967 if (solverVerbose_()) {
968 const auto msg = fmt::format(fmt::runtime(
"{}\nTimestep chopped to {} days\n"),
969 this->cause_of_failure_,
970 unit::convert::to(this->substep_timer_.currentStepLength(), unit::day));
971 OpmLog::problem(msg);
975 template<
class TypeTag>
976 template<
class Solver>
978 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
979 chopTimeStepOrCloseFailingWells_(
const double new_time_step)
981 bool wells_shut =
false;
988 const bool requireRepeatedFailures =
989 new_time_step > (minTimeStepBeforeClosingWells_() * restartFactor_() * restartFactor_());
990 const std::set<std::string> failing_wells =
991 detail::consistentlyFailingWells(solver_().model().stepReports(), requireRepeatedFailures);
993 if (failing_wells.empty()) {
995 chopTimeStep_(new_time_step);
998 std::vector<std::string> shut_wells;
999 for (
const auto& well : failing_wells) {
1000 const bool was_shut =
1001 solver_().model().wellModel().forceShutWellByName(well,
1002 this->substep_timer_.simulationTimeElapsed(),
1005 shut_wells.push_back(well);
1009 if (shut_wells.empty()) {
1010 for (
const auto& well : failing_wells) {
1011 const bool was_shut =
1012 solver_().model().wellModel().forceShutWellByName(well,
1013 this->substep_timer_.simulationTimeElapsed(),
1016 shut_wells.push_back(well);
1021 if (shut_wells.empty()) {
1022 chopTimeStep_(new_time_step);
1025 if (solverVerbose_()) {
1026 const std::string msg =
1027 fmt::format(fmt::runtime(
"\nProblematic well(s) were shut: {}" 1028 "(retrying timestep)\n"),
1029 fmt::join(shut_wells,
" "));
1030 OpmLog::problem(msg);
1037 template<
class TypeTag>
1038 template<
class Solver>
1039 boost::posix_time::ptime
1040 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1041 currentDateTime_()
const 1043 return simulatorTimer_().currentDateTime();
1046 template<
class TypeTag>
1047 template<
class Solver>
1049 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1050 getNumIterations_(
const SimulatorReportSingle &substep_report)
const 1052 if (useNewtonIteration_()) {
1053 return substep_report.total_newton_iterations;
1056 return substep_report.total_linear_iterations;
1060 template<
class TypeTag>
1061 template<
class Solver>
1063 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1064 growthFactor_()
const 1066 return this->adaptive_time_stepping_.growth_factor_;
1069 template<
class TypeTag>
1070 template<
class Solver>
1072 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1073 ignoreConvergenceFailure_()
const 1075 return adaptive_time_stepping_.ignore_convergence_failure_;
1078 template<
class TypeTag>
1079 template<
class Solver>
1081 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1082 isReservoirCouplingMaster_()
const 1084 return this->substepper_.isReservoirCouplingMaster_();
1087 template<
class TypeTag>
1088 template<
class Solver>
1090 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1091 isReservoirCouplingSlave_()
const 1093 return this->substepper_.isReservoirCouplingSlave_();
1096 template<
class TypeTag>
1097 template<
class Solver>
1099 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1100 markFirstSubStepAsFinished_()
const 1102 #ifdef RESERVOIR_COUPLING_ENABLED 1106 if (isReservoirCouplingMaster_()) {
1107 reservoirCouplingMaster_().setFirstSubstepOfSyncTimestep(
false);
1109 else if (isReservoirCouplingSlave_()) {
1110 reservoirCouplingSlave_().setFirstSubstepOfSyncTimestep(
false);
1116 template<
class TypeTag>
1117 template<
class Solver>
1119 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1122 return this->adaptive_time_stepping_.max_growth_;
1125 template<
class TypeTag>
1126 template<
class Solver>
1128 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1129 maybeReportSubStep_(SimulatorReportSingle substep_report)
const 1131 if (timeStepVerbose_()) {
1132 std::ostringstream ss;
1133 substep_report.reportStep(ss);
1134 OpmLog::info(ss.str());
1138 template<
class TypeTag>
1139 template<
class Solver>
1141 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1142 maybeRestrictTimeStepGrowth_(
const double dt,
double dt_estimate,
const int restarts)
const 1145 dt_estimate = std::min(dt_estimate,
double(maxGrowth_() * dt));
1146 assert(dt_estimate > 0);
1149 dt_estimate = std::min(growthFactor_() * dt, dt_estimate);
1156 template<
class TypeTag>
1157 template<
class Solver>
1159 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1160 maybeUpdateLastSubstepOfSyncTimestep_([[maybe_unused]]
const double dt)
1162 #ifdef RESERVOIR_COUPLING_ENABLED 1167 if (isReservoirCouplingSlave_()) {
1169 this->substep_timer_.simulationTimeElapsed() + dt,
1170 this->substep_timer_.totalTime()
1172 reservoirCouplingSlave_().setLastSubstepOfSyncTimestep(is_last);
1180 template<
class TypeTag>
1181 template<
class Solver>
1183 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1184 maybeUpdateTuningAndTimeStep_()
1192 const auto old_value = suggestedNextTimestep_();
1193 if (this->substepper_.maybeUpdateTuning_(this->substep_timer_.simulationTimeElapsed(),
1194 this->substep_timer_.currentStepLength(),
1195 this->substep_timer_.currentStepNum()))
1202 setTimeStep_(suggestedNextTimestep_());
1203 setSuggestedNextStep_(old_value);
1207 template<
class TypeTag>
1208 template<
class Solver>
1210 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1211 minTimeStepBeforeClosingWells_()
const 1213 return this->adaptive_time_stepping_.min_time_step_before_shutting_problematic_wells_;
1216 template<
class TypeTag>
1217 template<
class Solver>
1219 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1220 minTimeStep_()
const 1222 return this->adaptive_time_stepping_.min_time_step_;
1225 #ifdef RESERVOIR_COUPLING_ENABLED 1226 template<
class TypeTag>
1227 template<
class Solver>
1228 ReservoirCouplingMaster<typename AdaptiveTimeStepping<TypeTag>::Scalar>&
1229 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1230 reservoirCouplingMaster_()
const 1232 return this->substepper_.reservoirCouplingMaster_();
1235 template<
class TypeTag>
1236 template<
class Solver>
1237 ReservoirCouplingSlave<typename AdaptiveTimeStepping<TypeTag>::Scalar>&
1238 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1239 reservoirCouplingSlave_()
const 1241 return this->substepper_.reservoirCouplingSlave_();
1245 template<
class TypeTag>
1246 template<
class Solver>
1248 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1249 restartFactor_()
const 1251 return this->adaptive_time_stepping_.restart_factor_;
1254 template<
class TypeTag>
1255 template<
class Solver>
1256 SimulatorReportSingle
1257 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1260 SimulatorReportSingle substep_report;
1262 auto handleFailure = [
this, &substep_report]
1263 (
const std::string& failure_reason,
const std::exception& e,
bool log_exception =
true)
1265 substep_report = solver_().failureReport();
1266 this->cause_of_failure_ = failure_reason;
1267 if (log_exception && solverVerbose_()) {
1268 OpmLog::debug(std::string(
"Caught Exception: ") + e.what());
1273 substep_report = solver_().step(this->substep_timer_, &this->adaptive_time_stepping_.timeStepControl());
1274 if (solverVerbose_()) {
1276 OpmLog::debug(
"Overall linear iterations used: " 1277 + std::to_string(substep_report.total_linear_iterations));
1280 catch (
const TooManyIterations& e) {
1281 handleFailure(
"Solver convergence failure - Iteration limit reached", e);
1283 catch (
const TimeSteppingBreakdown& e) {
1284 handleFailure(e.what(), e);
1286 catch (
const ConvergenceMonitorFailure& e) {
1287 handleFailure(
"Convergence monitor failure", e,
false);
1289 catch (
const LinearSolverProblem& e) {
1290 handleFailure(
"Linear solver convergence failure", e);
1292 catch (
const NumericalProblem& e) {
1293 handleFailure(
"Solver convergence failure - Numerical problem encountered", e);
1295 catch (
const std::runtime_error& e) {
1296 handleFailure(
"Runtime error encountered", e);
1298 catch (
const Dune::ISTLError& e) {
1299 handleFailure(
"ISTL error - Time step too large", e);
1301 catch (
const Dune::MatrixBlockError& e) {
1302 handleFailure(
"Matrix block error", e);
1305 return substep_report;
1308 template<
class TypeTag>
1309 template<
class Solver>
1311 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1312 setTimeStep_(
double dt_estimate)
1314 this->substep_timer_.provideTimeStepEstimate(dt_estimate);
1317 template<
class TypeTag>
1318 template<
class Solver>
1320 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1323 return this->substepper_.solver_;
1327 template<
class TypeTag>
1328 template<
class Solver>
1330 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1331 solverRestartMax_()
const 1333 return this->adaptive_time_stepping_.solver_restart_max_;
1336 template<
class TypeTag>
1337 template<
class Solver>
1339 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1340 setSuggestedNextStep_(
double step)
1342 this->adaptive_time_stepping_.setSuggestedNextStep(step);
1345 template <
class TypeTag>
1346 template <
class Solver>
1347 const SimulatorTimer&
1348 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1349 simulatorTimer_()
const 1351 return this->substepper_.simulator_timer_;
1354 template <
class TypeTag>
1355 template <
class Solver>
1357 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1358 solverVerbose_()
const 1360 return this->adaptive_time_stepping_.solver_verbose_;
1363 template<
class TypeTag>
1364 template<
class Solver>
1365 boost::posix_time::ptime
1366 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1367 startDateTime_()
const 1369 return simulatorTimer_().startDateTime();
1372 template <
class TypeTag>
1373 template <
class Solver>
1375 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1376 suggestedNextTimestep_()
const 1378 return this->adaptive_time_stepping_.suggestedNextStep();
1381 template <
class TypeTag>
1382 template <
class Solver>
1384 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1385 timeStepControlComputeEstimate_(
const double dt,
const int iterations,
1386 const AdaptiveSimulatorTimer& substepTimer)
const 1389 const SolutionTimeErrorSolverWrapper<Solver> relative_change{solver_()};
1390 return this->adaptive_time_stepping_.time_step_control_->computeTimeStepSize(
1391 dt, iterations, relative_change, substepTimer);
1394 template <
class TypeTag>
1395 template <
class Solver>
1397 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1398 timeStepVerbose_()
const 1400 return this->adaptive_time_stepping_.timestep_verbose_;
1410 template <
class TypeTag>
1411 template <
class Solver>
1413 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1414 updateSuggestedNextStep_()
1416 auto suggested_next_step = this->substep_timer_.currentStepLength();
1417 if (! std::isfinite(suggested_next_step)) {
1418 suggested_next_step = this->original_time_step_;
1420 if (timeStepVerbose_()) {
1421 std::ostringstream ss;
1422 this->substep_timer_.report(ss);
1423 ss <<
"Suggested next step size = " 1424 << unit::convert::to(suggested_next_step, unit::day) <<
" (days)" << std::endl;
1425 OpmLog::debug(ss.str());
1427 setSuggestedNextStep_(suggested_next_step);
1430 template <
class TypeTag>
1431 template <
class Solver>
1433 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1434 useNewtonIteration_()
const 1436 return this->adaptive_time_stepping_.use_newton_iteration_;
1439 template <
class TypeTag>
1440 template <
class Solver>
1442 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1443 writeOutput_()
const 1445 time::StopWatch perf_timer;
1447 auto& problem = solver_().model().simulator().problem();
1448 problem.writeOutput(
true);
1449 return perf_timer.secsSinceStart();
1456 template<
class TypeTag>
1457 template<
class Solver>
1458 AdaptiveTimeStepping<TypeTag>::
1459 SolutionTimeErrorSolverWrapper<Solver>::
1460 SolutionTimeErrorSolverWrapper(
const Solver& solver)
1464 template<
class TypeTag>
1465 template<
class Solver>
1466 double AdaptiveTimeStepping<TypeTag>::SolutionTimeErrorSolverWrapper<Solver>::relativeChange()
const 1469 return solver_.model().relativeChange();
1474 #endif // OPM_ADAPTIVE_TIME_STEPPING_IMPL_HPP This file provides the infrastructure to retrieve run-time parameters.
void setSuggestedNextStep(const double x)
Set the suggested length for the next substep [s].
Definition: AdaptiveTimeStepping_impl.hpp:299
Adaptive time-stepping coordinator for the black-oil simulator.
Definition: AdaptiveTimeStepping.hpp:92
This file contains a set of helper functions used by VFPProd / VFPInj.
Definition: blackoilbioeffectsmodules.hh:45
void updateNEXTSTEP(double max_next_tstep)
Set suggested_next_timestep_ to max_next_tstep iff max_next_tstep > 0.
Definition: AdaptiveTimeStepping_impl.hpp:324
SimulatorReport step(const SimulatorTimer &simulator_timer, Solver &solver, const bool is_event, const TuningUpdateCallback &tuning_updater)
Run one report step by orchestrating adaptive substepping.
Definition: AdaptiveTimeStepping_impl.hpp:196
void updateTUNING(double max_next_tstep, const Tuning &tuning)
Apply TUNING keyword parameters.
Definition: AdaptiveTimeStepping_impl.hpp:336
TimeStepControlInterface.
Definition: TimeStepControlInterface.hpp:50
double suggestedNextStep() const
Current suggested length for the next substep [s].
Definition: AdaptiveTimeStepping_impl.hpp:307
Definition: SimulatorReport.hpp:121
Definition: SimulatorTimer.hpp:38
std::function< bool(double elapsed, double substep_length, int sub_step_number)> TuningUpdateCallback
Callback invoked at the start of each substep to apply TUNING, NEXTSTEP (via ACTIONX), and WCYCLE updates.
Definition: AdaptiveTimeStepping.hpp:119
static bool compare_gt_or_eq(double a, double b)
Determines if a is greater than b within the specified tolerance.
Definition: ReservoirCoupling.cpp:179