20#ifndef OPM_ADAPTIVE_TIME_STEPPING_IMPL_HPP
21#define OPM_ADAPTIVE_TIME_STEPPING_IMPL_HPP
24#ifndef OPM_ADAPTIVE_TIME_STEPPING_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>
36#include <opm/common/TimingMacros.hpp>
38#include <opm/grid/utility/StopWatch.hpp>
40#include <opm/input/eclipse/Schedule/Tuning.hpp>
42#include <opm/input/eclipse/Units/Units.hpp>
43#include <opm/input/eclipse/Units/UnitSystem.hpp>
56#include <boost/date_time/posix_time/posix_time.hpp>
57#include <fmt/format.h>
58#include <fmt/ranges.h>
66template<
class TypeTag>
70 const double max_next_tstep,
71 const bool terminal_output
73 : time_step_control_{}
74 , restart_factor_{Parameters::
Get<Parameters::SolverRestartFactor<Scalar>>()}
75 , growth_factor_{Parameters::
Get<Parameters::SolverGrowthFactor<Scalar>>()}
76 , max_growth_{Parameters::
Get<Parameters::SolverMaxGrowth<Scalar>>()}
78 Parameters::
Get<Parameters::SolverMaxTimeStepInDays<Scalar>>() * 24 * 60 * 60}
80 unit_system.to_si(UnitSystem::measure::time,
81 Parameters::
Get<Parameters::SolverMinTimeStep<Scalar>>())}
82 , ignore_convergence_failure_{
83 Parameters::
Get<Parameters::SolverContinueOnConvergenceFailure>()}
84 , solver_restart_max_{Parameters::
Get<Parameters::SolverMaxRestarts>()}
85 , solver_verbose_{Parameters::
Get<Parameters::SolverVerbosity>() > 0 && terminal_output}
86 , timestep_verbose_{Parameters::
Get<Parameters::TimeStepVerbosity>() > 0 && terminal_output}
87 , suggested_next_timestep_{
88 (max_next_tstep <= 0 ? Parameters::
Get<Parameters::InitialTimeStepInDays>()
89 : max_next_tstep) * 24 * 60 * 60}
90 , full_timestep_initially_{Parameters::
Get<Parameters::FullTimeStepInitially>()}
91 , timestep_after_event_{
92 Parameters::
Get<Parameters::TimeStepAfterEventInDays<Scalar>>() * 24 * 60 * 60}
93 , use_newton_iteration_{false}
94 , min_time_step_before_shutting_problematic_wells_{
95 Parameters::
Get<Parameters::MinTimeStepBeforeShuttingProblematicWellsInDays>() * unit::day}
107template<
class TypeTag>
110 const Tuning& tuning,
111 const UnitSystem& unit_system,
113 const bool terminal_output
115 : time_step_control_{}
116 , restart_factor_{tuning.TSFCNV}
117 , growth_factor_{tuning.TFDIFF}
118 , max_growth_{tuning.TSFMAX}
119 , max_time_step_{tuning.TSMAXZ}
120 , min_time_step_{tuning.TSMINZ}
121 , ignore_convergence_failure_{true}
122 , solver_restart_max_{Parameters::
Get<Parameters::SolverMaxRestarts>()}
123 , solver_verbose_{Parameters::
Get<Parameters::SolverVerbosity>() > 0 && terminal_output}
124 , timestep_verbose_{Parameters::
Get<Parameters::TimeStepVerbosity>() > 0 && terminal_output}
125 , suggested_next_timestep_{
126 max_next_tstep <= 0 ? Parameters::
Get<Parameters::InitialTimeStepInDays>() * 24 * 60 * 60
128 , full_timestep_initially_{Parameters::
Get<Parameters::FullTimeStepInitially>()}
129 , timestep_after_event_{tuning.TMAXWC}
130 , use_newton_iteration_{false}
131 , min_time_step_before_shutting_problematic_wells_{
132 Parameters::
Get<Parameters::MinTimeStepBeforeShuttingProblematicWellsInDays>() * unit::day}
138template<
class TypeTag>
150 switch (this->time_step_control_type_) {
152 result = castAndComp<HardcodedTimeStepControl>(rhs);
155 result = castAndComp<PIDAndIterationCountTimeStepControl>(rhs);
158 result = castAndComp<SimpleIterationCountTimeStepControl>(rhs);
161 result = castAndComp<PIDTimeStepControl>(rhs);
164 result = castAndComp<General3rdOrderController>(rhs);
180 this->min_time_step_before_shutting_problematic_wells_ ==
184template<
class TypeTag>
189 registerEclTimeSteppingParameters<Scalar>();
194template<
class TypeTag>
195template <
class Solver>
203 SubStepper<Solver> sub_stepper{
204 *
this, simulator_timer, solver, is_event, tuning_updater,
206 return sub_stepper.run();
209template<
class TypeTag>
210template<
class Serializer>
215 serializer(this->time_step_control_type_);
216 switch (this->time_step_control_type_) {
218 allocAndSerialize<HardcodedTimeStepControl>(serializer);
221 allocAndSerialize<PIDAndIterationCountTimeStepControl>(serializer);
224 allocAndSerialize<SimpleIterationCountTimeStepControl>(serializer);
227 allocAndSerialize<PIDTimeStepControl>(serializer);
230 allocAndSerialize<General3rdOrderController>(serializer);
233 serializer(this->restart_factor_);
234 serializer(this->growth_factor_);
235 serializer(this->max_growth_);
236 serializer(this->max_time_step_);
237 serializer(this->min_time_step_);
238 serializer(this->ignore_convergence_failure_);
239 serializer(this->solver_restart_max_);
240 serializer(this->solver_verbose_);
241 serializer(this->timestep_verbose_);
242 serializer(this->suggested_next_timestep_);
243 serializer(this->full_timestep_initially_);
244 serializer(this->timestep_after_event_);
245 serializer(this->use_newton_iteration_);
246 serializer(this->min_time_step_before_shutting_problematic_wells_);
249template<
class TypeTag>
257template<
class TypeTag>
262 return serializationTestObject_<HardcodedTimeStepControl>();
265template<
class TypeTag>
270 return serializationTestObject_<PIDTimeStepControl>();
273template<
class TypeTag>
278 return serializationTestObject_<PIDAndIterationCountTimeStepControl>();
281template<
class TypeTag>
286 return serializationTestObject_<SimpleIterationCountTimeStepControl>();
289template<
class TypeTag>
294 return serializationTestObject_<General3rdOrderController>();
298template<
class TypeTag>
303 this->suggested_next_timestep_ = x;
306template<
class TypeTag>
311 return this->suggested_next_timestep_;
314template<
class TypeTag>
319 return *this->time_step_control_;
323template<
class TypeTag>
330 if (max_next_tstep > 0) {
331 this->suggested_next_timestep_ = max_next_tstep;
335template<
class TypeTag>
338updateTUNING(
double max_next_tstep,
const Tuning& tuning)
340 this->restart_factor_ = tuning.TSFCNV;
341 this->growth_factor_ = tuning.TFDIFF;
342 this->max_growth_ = tuning.TSFMAX;
343 this->max_time_step_ = tuning.TSMAXZ;
344 updateNEXTSTEP(max_next_tstep);
345 this->timestep_after_event_ = tuning.TMAXWC;
352template<
class TypeTag>
353template<
class T,
class Serializer>
358 if (!serializer.isSerializing()) {
359 this->time_step_control_ = std::make_unique<T>();
361 serializer(*
static_cast<T*
>(this->time_step_control_.get()));
364template<
class TypeTag>
367AdaptiveTimeStepping<TypeTag>::
368castAndComp(
const AdaptiveTimeStepping<TypeTag>& Rhs)
const
370 const T* lhs =
static_cast<const T*
>(this->time_step_control_.get());
371 const T* rhs =
static_cast<const T*
>(Rhs.time_step_control_.get());
375template<
class TypeTag>
377AdaptiveTimeStepping<TypeTag>::
378maybeModifySuggestedTimeStepAtBeginningOfReportStep_(
const double original_time_step,
382 if (this->suggested_next_timestep_ < 0) {
383 this->suggested_next_timestep_ = this->restart_factor_ * original_time_step;
386 if (this->full_timestep_initially_) {
387 this->suggested_next_timestep_ = original_time_step;
391 if (is_event && this->timestep_after_event_ > 0) {
392 this->suggested_next_timestep_ = this->timestep_after_event_;
396template<
class TypeTag>
397template<
class Controller>
398AdaptiveTimeStepping<TypeTag>
399AdaptiveTimeStepping<TypeTag>::
400serializationTestObject_()
402 AdaptiveTimeStepping<TypeTag> result;
404 result.restart_factor_ = 1.0;
405 result.growth_factor_ = 2.0;
406 result.max_growth_ = 3.0;
407 result.max_time_step_ = 4.0;
408 result.min_time_step_ = 5.0;
409 result.ignore_convergence_failure_ =
true;
410 result.solver_restart_max_ = 6;
411 result.solver_verbose_ =
true;
412 result.timestep_verbose_ =
true;
413 result.suggested_next_timestep_ = 7.0;
414 result.full_timestep_initially_ =
true;
415 result.use_newton_iteration_ =
true;
416 result.min_time_step_before_shutting_problematic_wells_ = 9.0;
417 result.time_step_control_type_ = Controller::Type;
418 result.time_step_control_ =
419 std::make_unique<Controller>(Controller::serializationTestObject());
428template<
class TypeTag>
430init_(
const UnitSystem& unitSystem)
432 std::tie(time_step_control_type_,
436 if (this->growth_factor_ < 1.0) {
437 OPM_THROW(std::runtime_error,
438 "Growth factor cannot be less than 1.");
448template<
class TypeTag>
449template<
class Solver>
455 const TuningUpdateCallback& tuning_updater)
456 : adaptive_time_stepping_{adaptive_time_stepping}
457 , simulator_timer_{simulator_timer}
459 , is_event_{is_event}
460 , tuning_updater_{tuning_updater}
464template<
class TypeTag>
465template<
class Solver>
466AdaptiveTimeStepping<TypeTag>&
467AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
468getAdaptiveTimerStepper()
470 return adaptive_time_stepping_;
473template<
class TypeTag>
474template<
class Solver>
476AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
479#ifdef RESERVOIR_COUPLING_ENABLED
480 if (isReservoirCouplingSlave_() && reservoirCouplingSlave_().activated()) {
481 return runStepReservoirCouplingSlave_();
483 else if (isReservoirCouplingMaster_() && reservoirCouplingMaster_().activated()) {
484 return runStepReservoirCouplingMaster_();
487 return runStepOriginal_();
490 return runStepOriginal_();
498#ifdef RESERVOIR_COUPLING_ENABLED
499template<
class TypeTag>
500template<
class Solver>
502AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
503isReservoirCouplingMaster_()
const
505 return this->solver_.model().simulator().reservoirCouplingMaster() !=
nullptr;
508template<
class TypeTag>
509template<
class Solver>
511AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
512isReservoirCouplingSlave_()
const
514 return this->solver_.model().simulator().reservoirCouplingSlave() !=
nullptr;
518template<
class TypeTag>
519template<
class Solver>
521AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
522maybeModifySuggestedTimeStepAtBeginningOfReportStep_(
const double original_time_step)
524 this->adaptive_time_stepping_.maybeModifySuggestedTimeStepAtBeginningOfReportStep_(
525 original_time_step, this->is_event_
532 struct ZeroRelativeChange final : RelativeChangeInterface {
533 double relativeChange()
const override {
return 0.0; }
534 } zero_relative_change;
536 const auto* hardcoded_control =
static_cast<const HardcodedTimeStepControl*
>(
537 this->adaptive_time_stepping_.time_step_control_.get());
538 AdaptiveSimulatorTimer report_step_timer{
539 this->simulator_timer_.startDateTime(),
541 this->simulator_timer_.simulationTimeElapsed(),
543 this->simulator_timer_.reportStepNum(),
547 const double hardcoded_initial_step = hardcoded_control->computeTimeStepSize(
550 zero_relative_change,
552 if (std::isfinite(hardcoded_initial_step) && hardcoded_initial_step > 0.0) {
553 this->adaptive_time_stepping_.setSuggestedNextStep(hardcoded_initial_step);
560template<
class TypeTag>
561template<
class Solver>
563AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
564maybeUpdateTuning_(
double elapsed,
double substep_length,
int sub_step_number)
const
566 return this->tuning_updater_(elapsed, substep_length, sub_step_number);
569template<
class TypeTag>
570template<
class Solver>
572AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
575 return this->adaptive_time_stepping_.max_time_step_;
578template <
class TypeTag>
579template <
class Solver>
581AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
584 const auto elapsed = this->simulator_timer_.simulationTimeElapsed();
585 const auto original_time_step = this->simulator_timer_.currentStepLength();
586 const auto report_step = this->simulator_timer_.reportStepNum();
587 maybeUpdateTuning_(elapsed, suggestedNextTimestep_(), 0);
588 maybeModifySuggestedTimeStepAtBeginningOfReportStep_(original_time_step);
590 AdaptiveSimulatorTimer substep_timer{
591 this->simulator_timer_.startDateTime(),
594 suggestedNextTimestep_(),
598 SubStepIteration<Solver> substepIteration{*
this, substep_timer, original_time_step,
true};
599 return substepIteration.run();
602template <
class TypeTag>
603template <
class Solver>
605AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
606suggestedNextTimestep_()
const
608 return this->adaptive_time_stepping_.suggestedNextStep();
612#ifdef RESERVOIR_COUPLING_ENABLED
618template <
class TypeTag>
619template <
class Solver>
621AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
622checkIfSlaveIsTerminated_()
624 if (reservoirCouplingSlave_().terminated()) {
625 OPM_THROW(ReservoirCouplingError,
626 "Internal error: attempt to run a coupled substep loop after the slave "
627 "has been terminated by the master process");
646template <
class TypeTag>
647template <
class Solver>
649AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
650getRcMasterSyncStepLength_(
double prev_step,
652 double step_end_time)
654 const bool sync_at_report_steps = reservoirCouplingMaster_().syncAtReportSteps();
655 double current_step_length;
656 std::string flow_limited_by;
657 if (sync_at_report_steps) {
658 current_step_length = prev_step;
660 const double remaining = step_end_time - current_time;
662 const double flow_limit = reservoirCouplingMaster_().flowChangeTimeStepLimit();
663 current_step_length = std::min({suggestedNextTimestep_(), maxTimeStep_(), remaining});
664 if (flow_limit < current_step_length) {
665 current_step_length = flow_limit;
666 const auto& [group, change, fraction] = reservoirCouplingMaster_().flowChangeLimitingGroup();
667 flow_limited_by = group;
668 OpmLog::debug(fmt::format(
669 "Sync step limited by GRUPMAST item 4: flow rate of master group {} changed by {:.3g} "
670 "(limit {:.3g}) in the previous sync step",
671 group, change, fraction));
675 const double to_slave_report = reservoirCouplingMaster_().maybeChopSubStep(remaining, current_time);
676 if (current_step_length < to_slave_report && 1.5 * current_step_length > to_slave_report) {
677 current_step_length = 0.5 * to_slave_report;
693 const double chopped_step_length =
694 reservoirCouplingMaster_().maybeChopSubStep(current_step_length, current_time);
695 if (chopped_step_length < current_step_length) {
696 flow_limited_by.clear();
698 current_step_length = chopped_step_length;
699 auto num_active = reservoirCouplingMaster_().numCoupledSlaves();
700 OpmLog::info(fmt::format(
701 "\nChoosing next sync time{} between master and {} active slave {}: {:.2f} days{}",
702 sync_at_report_steps ?
" (RSYNC)" :
"",
703 num_active, (num_active == 1 ?
"process" :
"processes"),
704 current_step_length / unit::day,
705 flow_limited_by.empty() ?
"" : fmt::format(
" (limited by GRUPMAST item 4 for group {})", flow_limited_by)
707 return current_step_length;
710template <
class TypeTag>
711template <
class Solver>
712ReservoirCouplingMaster<typename AdaptiveTimeStepping<TypeTag>::Scalar>&
713AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
714reservoirCouplingMaster_()
716 return *(this->solver_.model().simulator().reservoirCouplingMaster());
719template <
class TypeTag>
720template <
class Solver>
721ReservoirCouplingSlave<typename AdaptiveTimeStepping<TypeTag>::Scalar>&
722AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
723reservoirCouplingSlave_()
725 return *(this->solver_.model().simulator().reservoirCouplingSlave());
783template <
class TypeTag>
784template <
class Solver>
786AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
787runStepReservoirCouplingMaster_()
790 const double original_time_step = this->simulator_timer_.currentStepLength();
791 double current_time{this->simulator_timer_.simulationTimeElapsed()};
792 double step_end_time = current_time + original_time_step;
793 const double report_step_start_time = current_time;
794 int report_step_substep_offset = 0;
801 auto current_step_length = original_time_step;
802 auto report_step_idx = this->simulator_timer_.currentStepNum();
803 if (report_step_idx == 0 && iteration == 0) {
804 reservoirCouplingMaster_().initTimeStepping();
806 SimulatorReport report;
808 reservoirCouplingMaster_().maybeReceiveActivationHandshakeFromSlaves(current_time);
810 reservoirCouplingMaster_().sendDontTerminateSignalToSlaves();
811 reservoirCouplingMaster_().receiveNextReportDateFromSlaves();
812 const bool start_of_report_step = (iteration == 0);
813 if (start_of_report_step) {
814 reservoirCouplingMaster_().initStartOfReportStep(report_step_idx);
815 maybeUpdateTuning_(current_time, suggestedNextTimestep_(), 0);
816 maybeModifySuggestedTimeStepAtBeginningOfReportStep_(original_time_step);
818 current_step_length = getRcMasterSyncStepLength_(
819 current_step_length, current_time, step_end_time);
820 reservoirCouplingMaster_().sendNextTimeStepToSlaves(current_step_length);
821 AdaptiveSimulatorTimer substep_timer{
822 this->simulator_timer_.startDateTime(),
825 suggestedNextTimestep_(),
826 this->simulator_timer_.reportStepNum(),
832 substep_timer.setReportStepStartTime(report_step_start_time);
833 substep_timer.setReportStepTotalTime(step_end_time);
834 substep_timer.setReportStepSubstepOffset(report_step_substep_offset);
836 current_time + current_step_length, step_end_time
841 reservoirCouplingMaster_().setFirstSubstepOfSyncTimestep(
true);
845 reservoirCouplingMaster_().setNeedsSlaveDataReceive(
true);
846 SubStepIteration<Solver> substepIteration{*
this, substep_timer, current_step_length, final_step};
847 const auto sub_steps_report = substepIteration.run();
848 report += sub_steps_report;
849 report_step_substep_offset += substep_timer.currentStepNum();
850 current_time += current_step_length;
859template <
class TypeTag>
860template <
class Solver>
862AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
863runStepReservoirCouplingSlave_()
865 checkIfSlaveIsTerminated_();
867 const double original_time_step = this->simulator_timer_.currentStepLength();
868 double current_time{this->simulator_timer_.simulationTimeElapsed()};
869 double step_end_time = current_time + original_time_step;
870 const double report_step_start_time = current_time;
871 int report_step_substep_offset = 0;
872 SimulatorReport report;
873 auto report_step_idx = this->simulator_timer_.currentStepNum();
874 if (report_step_idx == 0 && iteration == 0) {
875 reservoirCouplingSlave_().initTimeStepping();
878 bool start_of_report_step = (iteration == 0);
879 if (reservoirCouplingSlave_().maybeReceiveTerminateSignalFromMaster()) {
883 reservoirCouplingSlave_().sendNextReportDateToMasterProcess();
884 const auto timestep = reservoirCouplingSlave_().receiveNextTimeStepFromMaster();
885 if (start_of_report_step) {
886 maybeUpdateTuning_(current_time, suggestedNextTimestep_(), 0);
887 maybeModifySuggestedTimeStepAtBeginningOfReportStep_(timestep);
889 AdaptiveSimulatorTimer substep_timer{
890 this->simulator_timer_.startDateTime(),
893 suggestedNextTimestep_(),
894 this->simulator_timer_.reportStepNum(),
900 substep_timer.setReportStepStartTime(report_step_start_time);
901 substep_timer.setReportStepTotalTime(step_end_time);
902 substep_timer.setReportStepSubstepOffset(report_step_substep_offset);
904 current_time + timestep, step_end_time
909 reservoirCouplingSlave_().setFirstSubstepOfSyncTimestep(
true);
910 SubStepIteration<Solver> substepIteration{*
this, substep_timer, timestep, final_step};
911 const auto sub_steps_report = substepIteration.run();
912 report += sub_steps_report;
913 report_step_substep_offset += substep_timer.currentStepNum();
914 current_time += timestep;
929template<
class TypeTag>
930template<
class Solver>
931AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
932SubStepIteration(SubStepper<Solver>& substepper,
933 AdaptiveSimulatorTimer& substep_timer,
934 const double original_time_step,
936 : substepper_{substepper}
937 , substep_timer_{substep_timer}
938 , original_time_step_{original_time_step}
939 , final_step_{final_step}
940 , adaptive_time_stepping_{substepper.getAdaptiveTimerStepper()}
944template <
class TypeTag>
945template <
class Solver>
947AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
950 auto& simulator = solver_().model().simulator();
951 auto& problem = simulator.problem();
952 const bool truncateTimeStepToFloat = Parameters::Get<Parameters::TruncateTimeStepToFloat>();
955 SimulatorReport report;
958 while (!this->substep_timer_.done()) {
962 maybeUpdateTuningAndTimeStep_();
964 const double dt = this->substep_timer_.currentStepLength();
965 if (timeStepVerbose_()) {
969 maybeUpdateLastSubstepOfSyncTimestep_(dt);
970 auto substep_report = runSubStep_();
971 markFirstSubStepAsFinished_();
973 if (substep_report.converged || checkContinueOnUnconvergedSolution_(dt)) {
974 Dune::Timer perfTimer;
977 problem.setSubStepReport(substep_report);
978 auto& full_report = adaptive_time_stepping_.report();
979 full_report += substep_report;
980 problem.setSimulationReport(full_report);
981 problem.endTimeStep();
982 substep_report.pre_post_time += perfTimer.stop();
984 report += substep_report;
986 OPM_TIMEBLOCK(convergenceSucceeded);
993 double dt_taken = dt;
994 if (truncateTimeStepToFloat) {
995 const double model_dt = simulator.timeStepSize();
996 const double remaining = this->substep_timer_.totalTime()
997 - this->substep_timer_.simulationTimeElapsed();
998 if (model_dt > 0.0 && dt < remaining) {
999 this->substep_timer_.setCurrentStepLength(model_dt);
1000 dt_taken = model_dt;
1003 ++this->substep_timer_;
1005 const int iterations = getNumIterations_(substep_report);
1006 auto dt_estimate = timeStepControlComputeEstimate_(
1007 dt_taken, iterations, this->substep_timer_);
1009 assert(dt_estimate > 0);
1010 dt_estimate = maybeRestrictTimeStepGrowth_(dt_taken, dt_estimate, restarts);
1013 maybeReportSubStep_(substep_report);
1014 if (this->final_step_ && this->substep_timer_.done()) {
1019 report.success.output_write_time += writeOutput_();
1023 checkTimeStepCanAdvance_(dt_taken, dt_estimate);
1024 setTimeStep_(dt_estimate);
1026 report.success.converged = this->substep_timer_.done();
1027 this->substep_timer_.setLastStepFailed(
false);
1030 OPM_TIMEBLOCK(convergenceFailed);
1031 report += substep_report;
1032 this->substep_timer_.setLastStepFailed(
true);
1033 checkTimeStepMaxRestartLimit_(restarts);
1035 double new_time_step = restartFactor_() * dt;
1036 if (substep_report.time_step_rejected) {
1037 const double tol = Parameters::Get<Parameters::TimeStepControlTolerance>();
1038 const double safetyFactor = Parameters::Get<Parameters::TimeStepControlSafetyFactor>();
1039 const double temp_time_step = std::sqrt(safetyFactor * tol / solver_().model().relativeChange()) * dt;
1040 if (temp_time_step < dt) {
1041 new_time_step = temp_time_step;
1044 checkTimeStepMinLimit_(new_time_step);
1045 bool wells_shut =
false;
1046 if (new_time_step > minTimeStepBeforeClosingWells_()) {
1047 chopTimeStep_(new_time_step);
1049 wells_shut = chopTimeStepOrCloseFailingWells_(new_time_step);
1058 problem.setNextTimeStepSize(this->substep_timer_.currentStepLength());
1060 updateSuggestedNextStep_();
1070template<
class TypeTag>
1071template<
class Solver>
1073AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1074checkContinueOnUnconvergedSolution_(
double dt)
const
1076 const bool continue_on_uncoverged_solution = ignoreConvergenceFailure_() && dt <= minTimeStep_();
1077 if (continue_on_uncoverged_solution && solverVerbose_()) {
1079 const auto msg = fmt::format(
1080 "Solver failed to converge but timestep {} is smaller or equal to {}\n"
1081 "which is the minimum threshold given by option --solver-min-time-step\n",
1084 OpmLog::problem(msg);
1086 return continue_on_uncoverged_solution;
1089template<
class TypeTag>
1090template<
class Solver>
1092AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1093checkTimeStepMaxRestartLimit_(
const int restarts)
const
1097 if (restarts >= solverRestartMax_()) {
1098 const auto msg = fmt::format(
1099 fmt::runtime(
"Solver failed to converge after cutting timestep {} times."), restarts
1101 if (solverVerbose_()) {
1105 throw TimeSteppingBreakdown{msg};
1109template<
class TypeTag>
1110template<
class Solver>
1112AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1113checkTimeStepCanAdvance_(
const double current_time_step,
1114 const double new_time_step)
const
1121 if (new_time_step >= minTimeStep_()) {
1129 if (this->substep_timer_.done() || new_time_step >= current_time_step) {
1134 fmt::format(
"Time step control proposed a step of {:.3E} DAYS, below the "
1135 "minimum of {:.3E} DAYS, while every substep converges. The "
1136 "run is not advancing past {:.6E} DAYS.",
1137 new_time_step / 86400.0,
1138 minTimeStep_() / 86400.0,
1139 this->substep_timer_.simulationTimeElapsed() / 86400.0);
1141 if (solverVerbose_()) {
1146 throw TimeSteppingBreakdown{msg};
1149template<
class TypeTag>
1150template<
class Solver>
1152AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1153checkTimeStepMinLimit_(
const double new_time_step)
const
1155 using Meas = UnitSystem::measure;
1158 if (new_time_step < minTimeStep_()) {
1159 std::string msg =
"Solver failed to converge after cutting timestep to ";
1160 if (Parameters::Get<Parameters::EnableTuning>()) {
1161 const UnitSystem& unit_system = solver_().model().simulator().vanguard().eclState().getDeckUnitSystem();
1163 "{:.3E} {}\nwhich is the minimum threshold given by the TUNING keyword\n",
1164 unit_system.from_si(Meas::time, minTimeStep_()),
1165 unit_system.name(Meas::time)
1170 "{:.3E} DAYS\nwhich is the minimum threshold given by option --solver-min-time-step\n",
1171 minTimeStep_() / 86400.0
1174 if (solverVerbose_()) {
1178 throw TimeSteppingBreakdown{msg};
1182template<
class TypeTag>
1183template<
class Solver>
1185AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1186chopTimeStep_(
const double new_time_step)
1188 setTimeStep_(new_time_step);
1189 if (solverVerbose_()) {
1190 const auto msg = fmt::format(fmt::runtime(
"{}\nTimestep chopped to {} days\n"),
1191 this->cause_of_failure_,
1192 unit::convert::to(this->substep_timer_.currentStepLength(), unit::day));
1193 OpmLog::problem(msg);
1197template<
class TypeTag>
1198template<
class Solver>
1200AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1201chopTimeStepOrCloseFailingWells_(
const double new_time_step)
1203 bool wells_shut =
false;
1210 const bool requireRepeatedFailures =
1211 new_time_step > (minTimeStepBeforeClosingWells_() * restartFactor_() * restartFactor_());
1212 const std::set<std::string> failing_wells =
1215 if (failing_wells.empty()) {
1217 chopTimeStep_(new_time_step);
1220 std::vector<std::string> shut_wells;
1221 for (
const auto& well : failing_wells) {
1222 const bool was_shut =
1223 solver_().model().wellModel().forceShutWellByName(well,
1224 this->substep_timer_.simulationTimeElapsed(),
1227 shut_wells.push_back(well);
1231 if (shut_wells.empty()) {
1232 for (
const auto& well : failing_wells) {
1233 const bool was_shut =
1234 solver_().model().wellModel().forceShutWellByName(well,
1235 this->substep_timer_.simulationTimeElapsed(),
1238 shut_wells.push_back(well);
1243 if (shut_wells.empty()) {
1244 chopTimeStep_(new_time_step);
1247 if (solverVerbose_()) {
1248 const std::string msg =
1249 fmt::format(fmt::runtime(
"\nProblematic well(s) were shut: {}"
1250 "(retrying timestep)\n"),
1251 fmt::join(shut_wells,
" "));
1252 OpmLog::problem(msg);
1259template<
class TypeTag>
1260template<
class Solver>
1261boost::posix_time::ptime
1262AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1263currentDateTime_()
const
1265 return simulatorTimer_().currentDateTime();
1268template<
class TypeTag>
1269template<
class Solver>
1271AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1272getNumIterations_(
const SimulatorReportSingle &substep_report)
const
1274 if (useNewtonIteration_()) {
1275 return substep_report.total_newton_iterations;
1278 return substep_report.total_linear_iterations;
1282template<
class TypeTag>
1283template<
class Solver>
1285AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1286growthFactor_()
const
1288 return this->adaptive_time_stepping_.growth_factor_;
1291template<
class TypeTag>
1292template<
class Solver>
1294AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1295ignoreConvergenceFailure_()
const
1297 return adaptive_time_stepping_.ignore_convergence_failure_;
1300template<
class TypeTag>
1301template<
class Solver>
1303AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1304isReservoirCouplingMaster_()
const
1306 return this->substepper_.isReservoirCouplingMaster_();
1309template<
class TypeTag>
1310template<
class Solver>
1312AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1313isReservoirCouplingSlave_()
const
1315 return this->substepper_.isReservoirCouplingSlave_();
1318template<
class TypeTag>
1319template<
class Solver>
1321AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1322markFirstSubStepAsFinished_()
const
1324#ifdef RESERVOIR_COUPLING_ENABLED
1328 if (isReservoirCouplingMaster_()) {
1329 reservoirCouplingMaster_().setFirstSubstepOfSyncTimestep(
false);
1331 else if (isReservoirCouplingSlave_()) {
1332 reservoirCouplingSlave_().setFirstSubstepOfSyncTimestep(
false);
1338template<
class TypeTag>
1339template<
class Solver>
1341AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1344 return this->adaptive_time_stepping_.max_growth_;
1347template<
class TypeTag>
1348template<
class Solver>
1350AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1351maybeReportSubStep_(SimulatorReportSingle substep_report)
const
1353 if (timeStepVerbose_()) {
1354 std::ostringstream ss;
1355 substep_report.reportStep(ss);
1356 OpmLog::info(ss.str());
1360template<
class TypeTag>
1361template<
class Solver>
1363AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1364maybeRestrictTimeStepGrowth_(
const double dt,
double dt_estimate,
const int restarts)
const
1367 dt_estimate = std::min(dt_estimate,
double(maxGrowth_() * dt));
1368 assert(dt_estimate > 0);
1371 dt_estimate = std::min(growthFactor_() * dt, dt_estimate);
1378template<
class TypeTag>
1379template<
class Solver>
1381AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1382maybeUpdateLastSubstepOfSyncTimestep_([[maybe_unused]]
const double dt)
1384#ifdef RESERVOIR_COUPLING_ENABLED
1389 if (isReservoirCouplingSlave_()) {
1391 this->substep_timer_.simulationTimeElapsed() + dt,
1392 this->substep_timer_.totalTime()
1394 reservoirCouplingSlave_().setLastSubstepOfSyncTimestep(is_last);
1402template<
class TypeTag>
1403template<
class Solver>
1405AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1406maybeUpdateTuningAndTimeStep_()
1414 const auto old_value = suggestedNextTimestep_();
1415 if (this->substepper_.maybeUpdateTuning_(this->substep_timer_.simulationTimeElapsed(),
1416 this->substep_timer_.currentStepLength(),
1417 this->substep_timer_.currentStepNum()))
1424 setTimeStep_(suggestedNextTimestep_());
1425 setSuggestedNextStep_(old_value);
1429template<
class TypeTag>
1430template<
class Solver>
1432AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1433minTimeStepBeforeClosingWells_()
const
1435 return this->adaptive_time_stepping_.min_time_step_before_shutting_problematic_wells_;
1438template<
class TypeTag>
1439template<
class Solver>
1441AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1444 return this->adaptive_time_stepping_.min_time_step_;
1447#ifdef RESERVOIR_COUPLING_ENABLED
1448template<
class TypeTag>
1449template<
class Solver>
1450ReservoirCouplingMaster<typename AdaptiveTimeStepping<TypeTag>::Scalar>&
1451AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1452reservoirCouplingMaster_()
const
1454 return this->substepper_.reservoirCouplingMaster_();
1457template<
class TypeTag>
1458template<
class Solver>
1459ReservoirCouplingSlave<typename AdaptiveTimeStepping<TypeTag>::Scalar>&
1460AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1461reservoirCouplingSlave_()
const
1463 return this->substepper_.reservoirCouplingSlave_();
1467template<
class TypeTag>
1468template<
class Solver>
1470AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1471restartFactor_()
const
1473 return this->adaptive_time_stepping_.restart_factor_;
1476template<
class TypeTag>
1477template<
class Solver>
1478SimulatorReportSingle
1479AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1483 SimulatorReportSingle substep_report;
1485 auto handleFailure = [
this, &substep_report]
1486 (
const std::string& failure_reason,
const std::exception& e,
bool log_exception =
true)
1488 substep_report = solver_().failureReport();
1492 this->cause_of_failure_ = failure_reason;
1493 if (
const std::string what = e.what();
1494 !what.empty() && what != failure_reason)
1496 this->cause_of_failure_ +=
" (" + what +
")";
1498 if (log_exception && solverVerbose_()) {
1499 OpmLog::debug(std::string(
"Caught Exception: ") + e.what());
1504 substep_report = solver_().step(this->substep_timer_, &this->adaptive_time_stepping_.timeStepControl());
1505 if (solverVerbose_()) {
1507 OpmLog::debug(
"Overall linear iterations used: "
1511 catch (
const TooManyIterations& e) {
1512 handleFailure(
"Solver convergence failure - Iteration limit reached", e);
1514 catch (
const TimeSteppingBreakdown& e) {
1515 handleFailure(e.what(), e);
1517 catch (
const ConvergenceMonitorFailure& e) {
1518 handleFailure(
"Convergence monitor failure", e,
false);
1520 catch (
const LinearSolverProblem& e) {
1521 handleFailure(
"Linear solver convergence failure", e);
1523 catch (
const NumericalProblem& e) {
1524 handleFailure(
"Solver convergence failure - Numerical problem encountered", e);
1526 catch (
const std::runtime_error& e) {
1527 handleFailure(
"Runtime error encountered", e);
1529 catch (
const Dune::ISTLError& e) {
1530 handleFailure(
"ISTL error - Time step too large", e);
1532 catch (
const Dune::MatrixBlockError& e) {
1533 handleFailure(
"Matrix block error", e);
1536 return substep_report;
1539template<
class TypeTag>
1540template<
class Solver>
1542AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1543setTimeStep_(
double dt_estimate)
1545 this->substep_timer_.provideTimeStepEstimate(dt_estimate);
1548template<
class TypeTag>
1549template<
class Solver>
1551AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1554 return this->substepper_.solver_;
1558template<
class TypeTag>
1559template<
class Solver>
1561AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1562solverRestartMax_()
const
1564 return this->adaptive_time_stepping_.solver_restart_max_;
1567template<
class TypeTag>
1568template<
class Solver>
1570AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1571setSuggestedNextStep_(
double step)
1573 this->adaptive_time_stepping_.setSuggestedNextStep(step);
1576template <
class TypeTag>
1577template <
class Solver>
1578const SimulatorTimer&
1579AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1580simulatorTimer_()
const
1582 return this->substepper_.simulator_timer_;
1585template <
class TypeTag>
1586template <
class Solver>
1588AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1589solverVerbose_()
const
1591 return this->adaptive_time_stepping_.solver_verbose_;
1594template<
class TypeTag>
1595template<
class Solver>
1596boost::posix_time::ptime
1597AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1598startDateTime_()
const
1600 return simulatorTimer_().startDateTime();
1603template <
class TypeTag>
1604template <
class Solver>
1606AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1607suggestedNextTimestep_()
const
1609 return this->adaptive_time_stepping_.suggestedNextStep();
1612template <
class TypeTag>
1613template <
class Solver>
1615AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1616timeStepControlComputeEstimate_(
const double dt,
const int iterations,
1617 const AdaptiveSimulatorTimer& substepTimer)
const
1620 const SolutionTimeErrorSolverWrapper<Solver> relative_change{solver_()};
1621 return this->adaptive_time_stepping_.time_step_control_->computeTimeStepSize(
1622 dt, iterations, relative_change, substepTimer);
1625template <
class TypeTag>
1626template <
class Solver>
1628AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1629timeStepVerbose_()
const
1631 return this->adaptive_time_stepping_.timestep_verbose_;
1641template <
class TypeTag>
1642template <
class Solver>
1644AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1645updateSuggestedNextStep_()
1647 auto suggested_next_step = this->substep_timer_.currentStepLength();
1648 if (! std::isfinite(suggested_next_step)) {
1649 suggested_next_step = this->original_time_step_;
1651 if (timeStepVerbose_()) {
1652 std::ostringstream ss;
1653 this->substep_timer_.report(ss);
1654 ss <<
"Suggested next step size = "
1655 << unit::convert::to(suggested_next_step, unit::day) <<
" (days)" << std::endl;
1656 OpmLog::debug(ss.str());
1658 setSuggestedNextStep_(suggested_next_step);
1661template <
class TypeTag>
1662template <
class Solver>
1664AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1665useNewtonIteration_()
const
1667 return this->adaptive_time_stepping_.use_newton_iteration_;
1670template <
class TypeTag>
1671template <
class Solver>
1673AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1676 time::StopWatch perf_timer;
1678 auto& problem = solver_().model().simulator().problem();
1679 problem.writeOutput(
true);
1680 return perf_timer.secsSinceStart();
1687template<
class TypeTag>
1688template<
class Solver>
1689AdaptiveTimeStepping<TypeTag>::
1690SolutionTimeErrorSolverWrapper<Solver>::
1691SolutionTimeErrorSolverWrapper(
const Solver& solver)
1695template<
class TypeTag>
1696template<
class Solver>
1697double AdaptiveTimeStepping<TypeTag>::SolutionTimeErrorSolverWrapper<Solver>::relativeChange()
const
1700 return solver_.model().relativeChange();
Defines some fundamental parameters for all models.
Adaptive time-stepping coordinator for the black-oil simulator.
Definition: AdaptiveTimeStepping.hpp:93
double max_growth_
factor that limits the maximum growth of a time step
Definition: AdaptiveTimeStepping.hpp:435
double max_time_step_
maximal allowed time step size in days
Definition: AdaptiveTimeStepping.hpp:436
bool solver_verbose_
solver verbosity
Definition: AdaptiveTimeStepping.hpp:440
int solver_restart_max_
how many restart of solver are allowed
Definition: AdaptiveTimeStepping.hpp:439
double timestep_after_event_
suggested size of timestep after an event
Definition: AdaptiveTimeStepping.hpp:444
void init_(const UnitSystem &unitSystem)
Definition: AdaptiveTimeStepping_impl.hpp:430
void setSuggestedNextStep(const double x)
Set the suggested length for the next substep [s].
Definition: AdaptiveTimeStepping_impl.hpp:301
double suggestedNextStep() const
Definition: AdaptiveTimeStepping_impl.hpp:309
bool operator==(const AdaptiveTimeStepping< TypeTag > &rhs) const
Definition: AdaptiveTimeStepping_impl.hpp:141
static AdaptiveTimeStepping< TypeTag > serializationTestObjectSimple()
Definition: AdaptiveTimeStepping_impl.hpp:284
bool ignore_convergence_failure_
continue instead of stop when minimum time step is reached
Definition: AdaptiveTimeStepping.hpp:438
void serializeOp(Serializer &serializer)
Definition: AdaptiveTimeStepping_impl.hpp:213
void updateTUNING(double max_next_tstep, const Tuning &tuning)
Apply TUNING keyword parameters.
Definition: AdaptiveTimeStepping_impl.hpp:338
TimeStepControlType time_step_control_type_
type of time step control object
Definition: AdaptiveTimeStepping.hpp:431
const TimeStepControlInterface & timeStepControl() const
Definition: AdaptiveTimeStepping_impl.hpp:317
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),...
Definition: AdaptiveTimeStepping.hpp:119
bool full_timestep_initially_
beginning with the size of the time step from data file
Definition: AdaptiveTimeStepping.hpp:443
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:198
double growth_factor_
factor to multiply time step when solver recovered from failed convergence
Definition: AdaptiveTimeStepping.hpp:434
double restart_factor_
factor to multiply time step with when solver fails to converge
Definition: AdaptiveTimeStepping.hpp:433
double min_time_step_
minimal allowed time step size before throwing
Definition: AdaptiveTimeStepping.hpp:437
void updateNEXTSTEP(double max_next_tstep)
Set suggested_next_timestep_ to max_next_tstep iff max_next_tstep > 0.
Definition: AdaptiveTimeStepping_impl.hpp:326
static AdaptiveTimeStepping< TypeTag > serializationTestObjectHardcoded()
Definition: AdaptiveTimeStepping_impl.hpp:260
AdaptiveTimeStepping()=default
TimeStepController time_step_control_
time step control object
Definition: AdaptiveTimeStepping.hpp:432
static AdaptiveTimeStepping< TypeTag > serializationTestObjectPIDIt()
Definition: AdaptiveTimeStepping_impl.hpp:276
double min_time_step_before_shutting_problematic_wells_
< shut problematic wells when time step size in days are less than this
Definition: AdaptiveTimeStepping.hpp:448
static AdaptiveTimeStepping< TypeTag > serializationTestObject3rdOrder()
Definition: AdaptiveTimeStepping_impl.hpp:292
SimulatorReport & report()
Definition: AdaptiveTimeStepping_impl.hpp:252
static AdaptiveTimeStepping< TypeTag > serializationTestObjectPID()
Definition: AdaptiveTimeStepping_impl.hpp:268
static void registerParameters()
Definition: AdaptiveTimeStepping_impl.hpp:187
bool use_newton_iteration_
use newton iteration count for adaptive time step control
Definition: AdaptiveTimeStepping.hpp:445
Definition: SimulatorTimer.hpp:38
Definition: TimeStepControlInterface.hpp:51
auto Get(bool errorIfNotRegistered=true)
Retrieve a runtime parameter.
Definition: parametersystem.hpp:192
void logTimer(const AdaptiveSimulatorTimer &substep_timer)
void registerAdaptiveParameters()
std::set< std::string > consistentlyFailingWells(const std::vector< StepReport > &sr, bool requireRepeatedFailures)
std::tuple< TimeStepControlType, std::unique_ptr< TimeStepControlInterface >, bool > createController(const UnitSystem &unitSystem)
Definition: blackoilbioeffectsmodules.hh:45
std::string to_string(const ConvergenceReport::ReservoirFailure::Type t)
This file provides the infrastructure to retrieve run-time parameters.
static bool compare_gt_or_eq(double a, double b)
Determines if a is greater than b within the specified tolerance.
Definition: SimulatorReport.hpp:202