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> 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> 47 #include <opm/simulators/timestepping/EclTimeSteppingParams.hpp> 55 #include <boost/date_time/posix_time/posix_time.hpp> 56 #include <fmt/format.h> 57 #include <fmt/ranges.h> 65 template<
class TypeTag>
66 AdaptiveTimeStepping<TypeTag>::
67 AdaptiveTimeStepping(
const UnitSystem& unit_system,
69 const double max_next_tstep,
70 const bool terminal_output
72 : time_step_control_{}
73 , restart_factor_{Parameters::Get<Parameters::SolverRestartFactor<Scalar>>()}
74 , growth_factor_{Parameters::Get<Parameters::SolverGrowthFactor<Scalar>>()}
75 , max_growth_{Parameters::Get<Parameters::SolverMaxGrowth<Scalar>>()}
77 Parameters::Get<Parameters::SolverMaxTimeStepInDays<Scalar>>() * 24 * 60 * 60}
79 unit_system.to_si(UnitSystem::measure::time,
80 Parameters::Get<Parameters::SolverMinTimeStep<Scalar>>())}
81 , ignore_convergence_failure_{
82 Parameters::Get<Parameters::SolverContinueOnConvergenceFailure>()}
83 , solver_restart_max_{Parameters::Get<Parameters::SolverMaxRestarts>()}
84 , solver_verbose_{Parameters::Get<Parameters::SolverVerbosity>() > 0 && terminal_output}
85 , timestep_verbose_{Parameters::Get<Parameters::TimeStepVerbosity>() > 0 && terminal_output}
86 , suggested_next_timestep_{
87 (max_next_tstep <= 0 ? Parameters::Get<Parameters::InitialTimeStepInDays>()
88 : max_next_tstep) * 24 * 60 * 60}
89 , full_timestep_initially_{Parameters::Get<Parameters::FullTimeStepInitially>()}
90 , timestep_after_event_{
91 Parameters::Get<Parameters::TimeStepAfterEventInDays<Scalar>>() * 24 * 60 * 60}
92 , use_newton_iteration_{
false}
93 , min_time_step_before_shutting_problematic_wells_{
94 Parameters::Get<Parameters::MinTimeStepBeforeShuttingProblematicWellsInDays>() * unit::day}
106 template<
class TypeTag>
107 AdaptiveTimeStepping<TypeTag>::
108 AdaptiveTimeStepping(
double max_next_tstep,
109 const Tuning& tuning,
110 const UnitSystem& unit_system,
112 const bool terminal_output
114 : time_step_control_{}
115 , restart_factor_{tuning.TSFCNV}
116 , growth_factor_{tuning.TFDIFF}
117 , max_growth_{tuning.TSFMAX}
118 , max_time_step_{tuning.TSMAXZ}
119 , min_time_step_{tuning.TSMINZ}
120 , ignore_convergence_failure_{
true}
121 , solver_restart_max_{Parameters::Get<Parameters::SolverMaxRestarts>()}
122 , solver_verbose_{Parameters::Get<Parameters::SolverVerbosity>() > 0 && terminal_output}
123 , timestep_verbose_{Parameters::Get<Parameters::TimeStepVerbosity>() > 0 && terminal_output}
124 , suggested_next_timestep_{
125 max_next_tstep <= 0 ? Parameters::Get<Parameters::InitialTimeStepInDays>() * 24 * 60 * 60
127 , full_timestep_initially_{Parameters::Get<Parameters::FullTimeStepInitially>()}
128 , timestep_after_event_{tuning.TMAXWC}
129 , use_newton_iteration_{
false}
130 , min_time_step_before_shutting_problematic_wells_{
131 Parameters::Get<Parameters::MinTimeStepBeforeShuttingProblematicWellsInDays>() * unit::day}
137 template<
class TypeTag>
139 AdaptiveTimeStepping<TypeTag>::
140 operator==(
const AdaptiveTimeStepping<TypeTag>& rhs)
const 142 if (this->time_step_control_type_ != rhs.time_step_control_type_ ||
143 (this->time_step_control_ && !rhs.time_step_control_) ||
144 (!this->time_step_control_ && rhs.time_step_control_)) {
149 switch (this->time_step_control_type_) {
150 case TimeStepControlType::HardCodedTimeStep:
151 result = castAndComp<HardcodedTimeStepControl>(rhs);
153 case TimeStepControlType::PIDAndIterationCount:
154 result = castAndComp<PIDAndIterationCountTimeStepControl>(rhs);
156 case TimeStepControlType::SimpleIterationCount:
157 result = castAndComp<SimpleIterationCountTimeStepControl>(rhs);
159 case TimeStepControlType::PID:
160 result = castAndComp<PIDTimeStepControl>(rhs);
162 case TimeStepControlType::General3rdOrder:
163 result = castAndComp<General3rdOrderController>(rhs);
168 this->restart_factor_ == rhs.restart_factor_ &&
169 this->growth_factor_ == rhs.growth_factor_ &&
170 this->max_growth_ == rhs.max_growth_ &&
171 this->max_time_step_ == rhs.max_time_step_ &&
172 this->min_time_step_ == rhs.min_time_step_ &&
173 this->ignore_convergence_failure_ == rhs.ignore_convergence_failure_ &&
174 this->solver_restart_max_== rhs.solver_restart_max_ &&
175 this->solver_verbose_ == rhs.solver_verbose_ &&
176 this->full_timestep_initially_ == rhs.full_timestep_initially_ &&
177 this->timestep_after_event_ == rhs.timestep_after_event_ &&
178 this->use_newton_iteration_ == rhs.use_newton_iteration_ &&
179 this->min_time_step_before_shutting_problematic_wells_ ==
180 rhs.min_time_step_before_shutting_problematic_wells_;
183 template<
class TypeTag>
185 AdaptiveTimeStepping<TypeTag>::
188 registerEclTimeSteppingParameters<Scalar>();
189 detail::registerAdaptiveParameters();
193 template<
class TypeTag>
194 template <
class Solver>
202 SubStepper<Solver> sub_stepper{
203 *
this, simulator_timer, solver, is_event, tuning_updater,
205 return sub_stepper.run();
208 template<
class TypeTag>
209 template<
class Serializer>
214 serializer(this->time_step_control_type_);
215 switch (this->time_step_control_type_) {
216 case TimeStepControlType::HardCodedTimeStep:
217 allocAndSerialize<HardcodedTimeStepControl>(serializer);
219 case TimeStepControlType::PIDAndIterationCount:
220 allocAndSerialize<PIDAndIterationCountTimeStepControl>(serializer);
222 case TimeStepControlType::SimpleIterationCount:
223 allocAndSerialize<SimpleIterationCountTimeStepControl>(serializer);
225 case TimeStepControlType::PID:
226 allocAndSerialize<PIDTimeStepControl>(serializer);
228 case TimeStepControlType::General3rdOrder:
229 allocAndSerialize<General3rdOrderController>(serializer);
232 serializer(this->restart_factor_);
233 serializer(this->growth_factor_);
234 serializer(this->max_growth_);
235 serializer(this->max_time_step_);
236 serializer(this->min_time_step_);
237 serializer(this->ignore_convergence_failure_);
238 serializer(this->solver_restart_max_);
239 serializer(this->solver_verbose_);
240 serializer(this->timestep_verbose_);
241 serializer(this->suggested_next_timestep_);
242 serializer(this->full_timestep_initially_);
243 serializer(this->timestep_after_event_);
244 serializer(this->use_newton_iteration_);
245 serializer(this->min_time_step_before_shutting_problematic_wells_);
248 template<
class TypeTag>
250 AdaptiveTimeStepping<TypeTag>::
256 template<
class TypeTag>
257 AdaptiveTimeStepping<TypeTag>
258 AdaptiveTimeStepping<TypeTag>::
259 serializationTestObjectHardcoded()
261 return serializationTestObject_<HardcodedTimeStepControl>();
264 template<
class TypeTag>
265 AdaptiveTimeStepping<TypeTag>
266 AdaptiveTimeStepping<TypeTag>::
267 serializationTestObjectPID()
269 return serializationTestObject_<PIDTimeStepControl>();
272 template<
class TypeTag>
273 AdaptiveTimeStepping<TypeTag>
274 AdaptiveTimeStepping<TypeTag>::
275 serializationTestObjectPIDIt()
277 return serializationTestObject_<PIDAndIterationCountTimeStepControl>();
280 template<
class TypeTag>
281 AdaptiveTimeStepping<TypeTag>
282 AdaptiveTimeStepping<TypeTag>::
283 serializationTestObjectSimple()
285 return serializationTestObject_<SimpleIterationCountTimeStepControl>();
288 template<
class TypeTag>
289 AdaptiveTimeStepping<TypeTag>
290 AdaptiveTimeStepping<TypeTag>::
291 serializationTestObject3rdOrder()
293 return serializationTestObject_<General3rdOrderController>();
297 template<
class TypeTag>
302 this->suggested_next_timestep_ = x;
305 template<
class TypeTag>
310 return this->suggested_next_timestep_;
313 template<
class TypeTag>
318 return *this->time_step_control_;
322 template<
class TypeTag>
329 if (max_next_tstep > 0) {
330 this->suggested_next_timestep_ = max_next_tstep;
334 template<
class TypeTag>
339 this->restart_factor_ = tuning.TSFCNV;
340 this->growth_factor_ = tuning.TFDIFF;
341 this->max_growth_ = tuning.TSFMAX;
342 this->max_time_step_ = tuning.TSMAXZ;
343 updateNEXTSTEP(max_next_tstep);
344 this->timestep_after_event_ = tuning.TMAXWC;
351 template<
class TypeTag>
352 template<
class T,
class Serializer>
357 if (!serializer.isSerializing()) {
358 this->time_step_control_ = std::make_unique<T>();
360 serializer(*static_cast<T*>(this->time_step_control_.get()));
363 template<
class TypeTag>
366 AdaptiveTimeStepping<TypeTag>::
367 castAndComp(
const AdaptiveTimeStepping<TypeTag>& Rhs)
const 369 const T* lhs =
static_cast<const T*
>(this->time_step_control_.get());
370 const T* rhs =
static_cast<const T*
>(Rhs.time_step_control_.get());
374 template<
class TypeTag>
376 AdaptiveTimeStepping<TypeTag>::
377 maybeModifySuggestedTimeStepAtBeginningOfReportStep_(
const double original_time_step,
381 if (this->suggested_next_timestep_ < 0) {
382 this->suggested_next_timestep_ = this->restart_factor_ * original_time_step;
385 if (this->full_timestep_initially_) {
386 this->suggested_next_timestep_ = original_time_step;
390 if (is_event && this->timestep_after_event_ > 0) {
391 this->suggested_next_timestep_ = this->timestep_after_event_;
395 template<
class TypeTag>
396 template<
class Controller>
397 AdaptiveTimeStepping<TypeTag>
398 AdaptiveTimeStepping<TypeTag>::
399 serializationTestObject_()
401 AdaptiveTimeStepping<TypeTag> result;
403 result.restart_factor_ = 1.0;
404 result.growth_factor_ = 2.0;
405 result.max_growth_ = 3.0;
406 result.max_time_step_ = 4.0;
407 result.min_time_step_ = 5.0;
408 result.ignore_convergence_failure_ =
true;
409 result.solver_restart_max_ = 6;
410 result.solver_verbose_ =
true;
411 result.timestep_verbose_ =
true;
412 result.suggested_next_timestep_ = 7.0;
413 result.full_timestep_initially_ =
true;
414 result.use_newton_iteration_ =
true;
415 result.min_time_step_before_shutting_problematic_wells_ = 9.0;
416 result.time_step_control_type_ = Controller::Type;
417 result.time_step_control_ =
418 std::make_unique<Controller>(Controller::serializationTestObject());
427 template<
class TypeTag>
428 void AdaptiveTimeStepping<TypeTag>::
429 init_(
const UnitSystem& unitSystem)
431 std::tie(time_step_control_type_,
433 use_newton_iteration_) = detail::createController(unitSystem);
435 if (this->growth_factor_ < 1.0) {
436 OPM_THROW(std::runtime_error,
437 "Growth factor cannot be less than 1.");
447 template<
class TypeTag>
448 template<
class Solver>
449 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
450 SubStepper(AdaptiveTimeStepping<TypeTag>& adaptive_time_stepping,
451 const SimulatorTimer& simulator_timer,
454 const TuningUpdateCallback& tuning_updater)
455 : adaptive_time_stepping_{adaptive_time_stepping}
456 , simulator_timer_{simulator_timer}
458 , is_event_{is_event}
459 , tuning_updater_{tuning_updater}
463 template<
class TypeTag>
464 template<
class Solver>
465 AdaptiveTimeStepping<TypeTag>&
466 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
467 getAdaptiveTimerStepper()
469 return adaptive_time_stepping_;
472 template<
class TypeTag>
473 template<
class Solver>
475 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
478 #ifdef RESERVOIR_COUPLING_ENABLED 479 if (isReservoirCouplingSlave_() && reservoirCouplingSlave_().activated()) {
480 return runStepReservoirCouplingSlave_();
482 else if (isReservoirCouplingMaster_() && reservoirCouplingMaster_().activated()) {
483 return runStepReservoirCouplingMaster_();
486 return runStepOriginal_();
489 return runStepOriginal_();
497 #ifdef RESERVOIR_COUPLING_ENABLED 498 template<
class TypeTag>
499 template<
class Solver>
501 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
502 isReservoirCouplingMaster_()
const 504 return this->solver_.model().simulator().reservoirCouplingMaster() !=
nullptr;
507 template<
class TypeTag>
508 template<
class Solver>
510 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
511 isReservoirCouplingSlave_()
const 513 return this->solver_.model().simulator().reservoirCouplingSlave() !=
nullptr;
517 template<
class TypeTag>
518 template<
class Solver>
520 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
521 maybeModifySuggestedTimeStepAtBeginningOfReportStep_(
const double original_time_step)
523 this->adaptive_time_stepping_.maybeModifySuggestedTimeStepAtBeginningOfReportStep_(
524 original_time_step, this->is_event_
527 if (this->adaptive_time_stepping_.time_step_control_type_ != TimeStepControlType::HardCodedTimeStep) {
531 struct ZeroRelativeChange final : RelativeChangeInterface {
532 double relativeChange()
const override {
return 0.0; }
533 } zero_relative_change;
535 const auto* hardcoded_control =
static_cast<const HardcodedTimeStepControl*
>(
536 this->adaptive_time_stepping_.time_step_control_.get());
537 AdaptiveSimulatorTimer report_step_timer{
538 this->simulator_timer_.startDateTime(),
540 this->simulator_timer_.simulationTimeElapsed(),
542 this->simulator_timer_.reportStepNum(),
546 const double hardcoded_initial_step = hardcoded_control->computeTimeStepSize(
549 zero_relative_change,
551 if (std::isfinite(hardcoded_initial_step) && hardcoded_initial_step > 0.0) {
552 this->adaptive_time_stepping_.setSuggestedNextStep(hardcoded_initial_step);
559 template<
class TypeTag>
560 template<
class Solver>
562 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
563 maybeUpdateTuning_(
double elapsed,
double substep_length,
int sub_step_number)
const 565 return this->tuning_updater_(elapsed, substep_length, sub_step_number);
568 template<
class TypeTag>
569 template<
class Solver>
571 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
574 return this->adaptive_time_stepping_.max_time_step_;
577 template <
class TypeTag>
578 template <
class Solver>
580 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
583 const auto elapsed = this->simulator_timer_.simulationTimeElapsed();
584 const auto original_time_step = this->simulator_timer_.currentStepLength();
585 const auto report_step = this->simulator_timer_.reportStepNum();
586 maybeUpdateTuning_(elapsed, suggestedNextTimestep_(), 0);
587 maybeModifySuggestedTimeStepAtBeginningOfReportStep_(original_time_step);
589 AdaptiveSimulatorTimer substep_timer{
590 this->simulator_timer_.startDateTime(),
593 suggestedNextTimestep_(),
597 SubStepIteration<Solver> substepIteration{*
this, substep_timer, original_time_step,
true};
598 return substepIteration.run();
601 template <
class TypeTag>
602 template <
class Solver>
604 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
605 suggestedNextTimestep_()
const 607 return this->adaptive_time_stepping_.suggestedNextStep();
611 #ifdef RESERVOIR_COUPLING_ENABLED 617 template <
class TypeTag>
618 template <
class Solver>
620 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
621 checkIfSlaveIsTerminated_()
623 if (reservoirCouplingSlave_().terminated()) {
624 OPM_THROW(ReservoirCouplingError,
625 "Internal error: attempt to run a coupled substep loop after the slave " 626 "has been terminated by the master process");
645 template <
class TypeTag>
646 template <
class Solver>
648 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
649 getRcMasterSyncStepLength_(
double prev_step,
651 double step_end_time)
653 const bool sync_at_report_steps = reservoirCouplingMaster_().syncAtReportSteps();
654 double current_step_length;
655 if (sync_at_report_steps) {
656 current_step_length = prev_step;
658 const double remaining = step_end_time - current_time;
659 current_step_length = std::min({suggestedNextTimestep_(), maxTimeStep_(), remaining});
672 current_step_length = reservoirCouplingMaster_().maybeChopSubStep(current_step_length, current_time);
673 auto num_active = reservoirCouplingMaster_().numActivatedSlaves();
674 OpmLog::info(fmt::format(
675 "\nChoosing next sync time{} between master and {} active slave {}: {:.2f} days",
676 sync_at_report_steps ?
" (RSYNC)" :
"",
677 num_active, (num_active == 1 ?
"process" :
"processes"),
678 current_step_length / unit::day
680 return current_step_length;
683 template <
class TypeTag>
684 template <
class Solver>
685 ReservoirCouplingMaster<typename AdaptiveTimeStepping<TypeTag>::Scalar>&
686 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
687 reservoirCouplingMaster_()
689 return *(this->solver_.model().simulator().reservoirCouplingMaster());
692 template <
class TypeTag>
693 template <
class Solver>
694 ReservoirCouplingSlave<typename AdaptiveTimeStepping<TypeTag>::Scalar>&
695 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
696 reservoirCouplingSlave_()
698 return *(this->solver_.model().simulator().reservoirCouplingSlave());
755 template <
class TypeTag>
756 template <
class Solver>
758 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
759 runStepReservoirCouplingMaster_()
762 const double original_time_step = this->simulator_timer_.currentStepLength();
763 double current_time{this->simulator_timer_.simulationTimeElapsed()};
764 double step_end_time = current_time + original_time_step;
765 const double report_step_start_time = current_time;
766 int report_step_substep_offset = 0;
773 auto current_step_length = original_time_step;
774 auto report_step_idx = this->simulator_timer_.currentStepNum();
775 if (report_step_idx == 0 && iteration == 0) {
776 reservoirCouplingMaster_().initTimeStepping();
778 SimulatorReport report;
780 reservoirCouplingMaster_().maybeReceiveActivationHandshakeFromSlaves(current_time);
782 reservoirCouplingMaster_().sendDontTerminateSignalToSlaves();
783 reservoirCouplingMaster_().receiveNextReportDateFromSlaves();
784 const bool start_of_report_step = (iteration == 0);
785 if (start_of_report_step) {
786 reservoirCouplingMaster_().initStartOfReportStep(report_step_idx);
787 maybeUpdateTuning_(current_time, suggestedNextTimestep_(), 0);
788 maybeModifySuggestedTimeStepAtBeginningOfReportStep_(original_time_step);
790 current_step_length = getRcMasterSyncStepLength_(
791 current_step_length, current_time, step_end_time);
792 reservoirCouplingMaster_().sendNextTimeStepToSlaves(current_step_length);
793 AdaptiveSimulatorTimer substep_timer{
794 this->simulator_timer_.startDateTime(),
797 suggestedNextTimestep_(),
798 this->simulator_timer_.reportStepNum(),
804 substep_timer.setReportStepStartTime(report_step_start_time);
805 substep_timer.setReportStepTotalTime(step_end_time);
806 substep_timer.setReportStepSubstepOffset(report_step_substep_offset);
808 current_time + current_step_length, step_end_time
813 reservoirCouplingMaster_().setFirstSubstepOfSyncTimestep(
true);
817 reservoirCouplingMaster_().setNeedsSlaveDataReceive(
true);
818 SubStepIteration<Solver> substepIteration{*
this, substep_timer, current_step_length, final_step};
819 const auto sub_steps_report = substepIteration.run();
820 report += sub_steps_report;
821 report_step_substep_offset += substep_timer.currentStepNum();
822 current_time += current_step_length;
831 template <
class TypeTag>
832 template <
class Solver>
834 AdaptiveTimeStepping<TypeTag>::SubStepper<Solver>::
835 runStepReservoirCouplingSlave_()
837 checkIfSlaveIsTerminated_();
839 const double original_time_step = this->simulator_timer_.currentStepLength();
840 double current_time{this->simulator_timer_.simulationTimeElapsed()};
841 double step_end_time = current_time + original_time_step;
842 const double report_step_start_time = current_time;
843 int report_step_substep_offset = 0;
844 SimulatorReport report;
845 auto report_step_idx = this->simulator_timer_.currentStepNum();
846 if (report_step_idx == 0 && iteration == 0) {
847 reservoirCouplingSlave_().initTimeStepping();
850 bool start_of_report_step = (iteration == 0);
851 if (reservoirCouplingSlave_().maybeReceiveTerminateSignalFromMaster()) {
855 reservoirCouplingSlave_().sendNextReportDateToMasterProcess();
856 const auto timestep = reservoirCouplingSlave_().receiveNextTimeStepFromMaster();
857 if (start_of_report_step) {
858 maybeUpdateTuning_(current_time, suggestedNextTimestep_(), 0);
859 maybeModifySuggestedTimeStepAtBeginningOfReportStep_(timestep);
861 AdaptiveSimulatorTimer substep_timer{
862 this->simulator_timer_.startDateTime(),
865 suggestedNextTimestep_(),
866 this->simulator_timer_.reportStepNum(),
872 substep_timer.setReportStepStartTime(report_step_start_time);
873 substep_timer.setReportStepTotalTime(step_end_time);
874 substep_timer.setReportStepSubstepOffset(report_step_substep_offset);
876 current_time + timestep, step_end_time
881 reservoirCouplingSlave_().setFirstSubstepOfSyncTimestep(
true);
882 SubStepIteration<Solver> substepIteration{*
this, substep_timer, timestep, final_step};
883 const auto sub_steps_report = substepIteration.run();
884 report += sub_steps_report;
885 report_step_substep_offset += substep_timer.currentStepNum();
886 current_time += timestep;
894 #endif // RESERVOIR_COUPLING_ENABLED 901 template<
class TypeTag>
902 template<
class Solver>
903 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
904 SubStepIteration(SubStepper<Solver>& substepper,
905 AdaptiveSimulatorTimer& substep_timer,
906 const double original_time_step,
908 : substepper_{substepper}
909 , substep_timer_{substep_timer}
910 , original_time_step_{original_time_step}
911 , final_step_{final_step}
912 , adaptive_time_stepping_{substepper.getAdaptiveTimerStepper()}
916 template <
class TypeTag>
917 template <
class Solver>
919 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
922 auto& simulator = solver_().model().simulator();
923 auto& problem = simulator.problem();
926 SimulatorReport report;
929 while (!this->substep_timer_.done()) {
933 maybeUpdateTuningAndTimeStep_();
935 const double dt = this->substep_timer_.currentStepLength();
936 if (timeStepVerbose_()) {
937 detail::logTimer(this->substep_timer_);
940 maybeUpdateLastSubstepOfSyncTimestep_(dt);
941 auto substep_report = runSubStep_();
942 markFirstSubStepAsFinished_();
944 if (substep_report.converged || checkContinueOnUnconvergedSolution_(dt)) {
945 Dune::Timer perfTimer;
948 problem.setSubStepReport(substep_report);
949 auto& full_report = adaptive_time_stepping_.report();
950 full_report += substep_report;
951 problem.setSimulationReport(full_report);
952 problem.endTimeStep();
953 substep_report.pre_post_time += perfTimer.stop();
955 report += substep_report;
957 OPM_TIMEBLOCK(convergenceSucceeded);
958 ++this->substep_timer_;
960 const int iterations = getNumIterations_(substep_report);
961 auto dt_estimate = timeStepControlComputeEstimate_(
962 dt, iterations, this->substep_timer_);
964 assert(dt_estimate > 0);
965 dt_estimate = maybeRestrictTimeStepGrowth_(dt, dt_estimate, restarts);
968 maybeReportSubStep_(substep_report);
969 if (this->final_step_ && this->substep_timer_.done()) {
974 report.success.output_write_time += writeOutput_();
978 setTimeStep_(dt_estimate);
980 report.success.converged = this->substep_timer_.done();
981 this->substep_timer_.setLastStepFailed(
false);
984 OPM_TIMEBLOCK(convergenceFailed);
985 report += substep_report;
986 this->substep_timer_.setLastStepFailed(
true);
987 checkTimeStepMaxRestartLimit_(restarts);
989 double new_time_step = restartFactor_() * dt;
990 if (substep_report.time_step_rejected) {
991 const double tol = Parameters::Get<Parameters::TimeStepControlTolerance>();
992 const double safetyFactor = Parameters::Get<Parameters::TimeStepControlSafetyFactor>();
993 const double temp_time_step = std::sqrt(safetyFactor * tol / solver_().model().relativeChange()) * dt;
994 if (temp_time_step < dt) {
995 new_time_step = temp_time_step;
998 checkTimeStepMinLimit_(new_time_step);
999 bool wells_shut =
false;
1000 if (new_time_step > minTimeStepBeforeClosingWells_()) {
1001 chopTimeStep_(new_time_step);
1003 wells_shut = chopTimeStepOrCloseFailingWells_(new_time_step);
1012 problem.setNextTimeStepSize(this->substep_timer_.currentStepLength());
1014 updateSuggestedNextStep_();
1024 template<
class TypeTag>
1025 template<
class Solver>
1027 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1028 checkContinueOnUnconvergedSolution_(
double dt)
const 1030 const bool continue_on_uncoverged_solution = ignoreConvergenceFailure_() && dt <= minTimeStep_();
1031 if (continue_on_uncoverged_solution && solverVerbose_()) {
1033 const auto msg = fmt::format(
1034 "Solver failed to converge but timestep {} is smaller or equal to {}\n" 1035 "which is the minimum threshold given by option --solver-min-time-step\n",
1038 OpmLog::problem(msg);
1040 return continue_on_uncoverged_solution;
1043 template<
class TypeTag>
1044 template<
class Solver>
1046 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1047 checkTimeStepMaxRestartLimit_(
const int restarts)
const 1051 if (restarts >= solverRestartMax_()) {
1052 const auto msg = fmt::format(
1053 fmt::runtime(
"Solver failed to converge after cutting timestep {} times."), restarts
1055 if (solverVerbose_()) {
1059 throw TimeSteppingBreakdown{msg};
1063 template<
class TypeTag>
1064 template<
class Solver>
1066 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1067 checkTimeStepMinLimit_(
const double new_time_step)
const 1069 using Meas = UnitSystem::measure;
1072 if (new_time_step < minTimeStep_()) {
1073 std::string msg =
"Solver failed to converge after cutting timestep to ";
1074 if (Parameters::Get<Parameters::EnableTuning>()) {
1075 const UnitSystem& unit_system = solver_().model().simulator().vanguard().eclState().getDeckUnitSystem();
1077 "{:.3E} {}\nwhich is the minimum threshold given by the TUNING keyword\n",
1078 unit_system.from_si(Meas::time, minTimeStep_()),
1079 unit_system.name(Meas::time)
1084 "{:.3E} DAYS\nwhich is the minimum threshold given by option --solver-min-time-step\n",
1085 minTimeStep_() / 86400.0
1088 if (solverVerbose_()) {
1092 throw TimeSteppingBreakdown{msg};
1096 template<
class TypeTag>
1097 template<
class Solver>
1099 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1100 chopTimeStep_(
const double new_time_step)
1102 setTimeStep_(new_time_step);
1103 if (solverVerbose_()) {
1104 const auto msg = fmt::format(fmt::runtime(
"{}\nTimestep chopped to {} days\n"),
1105 this->cause_of_failure_,
1106 unit::convert::to(this->substep_timer_.currentStepLength(), unit::day));
1107 OpmLog::problem(msg);
1111 template<
class TypeTag>
1112 template<
class Solver>
1114 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1115 chopTimeStepOrCloseFailingWells_(
const double new_time_step)
1117 bool wells_shut =
false;
1124 const bool requireRepeatedFailures =
1125 new_time_step > (minTimeStepBeforeClosingWells_() * restartFactor_() * restartFactor_());
1126 const std::set<std::string> failing_wells =
1127 detail::consistentlyFailingWells(solver_().model().stepReports(), requireRepeatedFailures);
1129 if (failing_wells.empty()) {
1131 chopTimeStep_(new_time_step);
1134 std::vector<std::string> shut_wells;
1135 for (
const auto& well : failing_wells) {
1136 const bool was_shut =
1137 solver_().model().wellModel().forceShutWellByName(well,
1138 this->substep_timer_.simulationTimeElapsed(),
1141 shut_wells.push_back(well);
1145 if (shut_wells.empty()) {
1146 for (
const auto& well : failing_wells) {
1147 const bool was_shut =
1148 solver_().model().wellModel().forceShutWellByName(well,
1149 this->substep_timer_.simulationTimeElapsed(),
1152 shut_wells.push_back(well);
1157 if (shut_wells.empty()) {
1158 chopTimeStep_(new_time_step);
1161 if (solverVerbose_()) {
1162 const std::string msg =
1163 fmt::format(fmt::runtime(
"\nProblematic well(s) were shut: {}" 1164 "(retrying timestep)\n"),
1165 fmt::join(shut_wells,
" "));
1166 OpmLog::problem(msg);
1173 template<
class TypeTag>
1174 template<
class Solver>
1175 boost::posix_time::ptime
1176 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1177 currentDateTime_()
const 1179 return simulatorTimer_().currentDateTime();
1182 template<
class TypeTag>
1183 template<
class Solver>
1185 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1186 getNumIterations_(
const SimulatorReportSingle &substep_report)
const 1188 if (useNewtonIteration_()) {
1189 return substep_report.total_newton_iterations;
1192 return substep_report.total_linear_iterations;
1196 template<
class TypeTag>
1197 template<
class Solver>
1199 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1200 growthFactor_()
const 1202 return this->adaptive_time_stepping_.growth_factor_;
1205 template<
class TypeTag>
1206 template<
class Solver>
1208 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1209 ignoreConvergenceFailure_()
const 1211 return adaptive_time_stepping_.ignore_convergence_failure_;
1214 template<
class TypeTag>
1215 template<
class Solver>
1217 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1218 isReservoirCouplingMaster_()
const 1220 return this->substepper_.isReservoirCouplingMaster_();
1223 template<
class TypeTag>
1224 template<
class Solver>
1226 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1227 isReservoirCouplingSlave_()
const 1229 return this->substepper_.isReservoirCouplingSlave_();
1232 template<
class TypeTag>
1233 template<
class Solver>
1235 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1236 markFirstSubStepAsFinished_()
const 1238 #ifdef RESERVOIR_COUPLING_ENABLED 1242 if (isReservoirCouplingMaster_()) {
1243 reservoirCouplingMaster_().setFirstSubstepOfSyncTimestep(
false);
1245 else if (isReservoirCouplingSlave_()) {
1246 reservoirCouplingSlave_().setFirstSubstepOfSyncTimestep(
false);
1252 template<
class TypeTag>
1253 template<
class Solver>
1255 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1258 return this->adaptive_time_stepping_.max_growth_;
1261 template<
class TypeTag>
1262 template<
class Solver>
1264 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1265 maybeReportSubStep_(SimulatorReportSingle substep_report)
const 1267 if (timeStepVerbose_()) {
1268 std::ostringstream ss;
1269 substep_report.reportStep(ss);
1270 OpmLog::info(ss.str());
1274 template<
class TypeTag>
1275 template<
class Solver>
1277 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1278 maybeRestrictTimeStepGrowth_(
const double dt,
double dt_estimate,
const int restarts)
const 1281 dt_estimate = std::min(dt_estimate,
double(maxGrowth_() * dt));
1282 assert(dt_estimate > 0);
1285 dt_estimate = std::min(growthFactor_() * dt, dt_estimate);
1292 template<
class TypeTag>
1293 template<
class Solver>
1295 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1296 maybeUpdateLastSubstepOfSyncTimestep_([[maybe_unused]]
const double dt)
1298 #ifdef RESERVOIR_COUPLING_ENABLED 1303 if (isReservoirCouplingSlave_()) {
1305 this->substep_timer_.simulationTimeElapsed() + dt,
1306 this->substep_timer_.totalTime()
1308 reservoirCouplingSlave_().setLastSubstepOfSyncTimestep(is_last);
1316 template<
class TypeTag>
1317 template<
class Solver>
1319 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1320 maybeUpdateTuningAndTimeStep_()
1328 const auto old_value = suggestedNextTimestep_();
1329 if (this->substepper_.maybeUpdateTuning_(this->substep_timer_.simulationTimeElapsed(),
1330 this->substep_timer_.currentStepLength(),
1331 this->substep_timer_.currentStepNum()))
1338 setTimeStep_(suggestedNextTimestep_());
1339 setSuggestedNextStep_(old_value);
1343 template<
class TypeTag>
1344 template<
class Solver>
1346 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1347 minTimeStepBeforeClosingWells_()
const 1349 return this->adaptive_time_stepping_.min_time_step_before_shutting_problematic_wells_;
1352 template<
class TypeTag>
1353 template<
class Solver>
1355 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1356 minTimeStep_()
const 1358 return this->adaptive_time_stepping_.min_time_step_;
1361 #ifdef RESERVOIR_COUPLING_ENABLED 1362 template<
class TypeTag>
1363 template<
class Solver>
1364 ReservoirCouplingMaster<typename AdaptiveTimeStepping<TypeTag>::Scalar>&
1365 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1366 reservoirCouplingMaster_()
const 1368 return this->substepper_.reservoirCouplingMaster_();
1371 template<
class TypeTag>
1372 template<
class Solver>
1373 ReservoirCouplingSlave<typename AdaptiveTimeStepping<TypeTag>::Scalar>&
1374 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1375 reservoirCouplingSlave_()
const 1377 return this->substepper_.reservoirCouplingSlave_();
1381 template<
class TypeTag>
1382 template<
class Solver>
1384 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1385 restartFactor_()
const 1387 return this->adaptive_time_stepping_.restart_factor_;
1390 template<
class TypeTag>
1391 template<
class Solver>
1392 SimulatorReportSingle
1393 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1397 SimulatorReportSingle substep_report;
1399 auto handleFailure = [
this, &substep_report]
1400 (
const std::string& failure_reason,
const std::exception& e,
bool log_exception =
true)
1402 substep_report = solver_().failureReport();
1403 this->cause_of_failure_ = failure_reason;
1404 if (log_exception && solverVerbose_()) {
1405 OpmLog::debug(std::string(
"Caught Exception: ") + e.what());
1410 substep_report = solver_().step(this->substep_timer_, &this->adaptive_time_stepping_.timeStepControl());
1411 if (solverVerbose_()) {
1413 OpmLog::debug(
"Overall linear iterations used: " 1414 + std::to_string(substep_report.total_linear_iterations));
1417 catch (
const TooManyIterations& e) {
1418 handleFailure(
"Solver convergence failure - Iteration limit reached", e);
1420 catch (
const TimeSteppingBreakdown& e) {
1421 handleFailure(e.what(), e);
1423 catch (
const ConvergenceMonitorFailure& e) {
1424 handleFailure(
"Convergence monitor failure", e,
false);
1426 catch (
const LinearSolverProblem& e) {
1427 handleFailure(
"Linear solver convergence failure", e);
1429 catch (
const NumericalProblem& e) {
1430 handleFailure(
"Solver convergence failure - Numerical problem encountered", e);
1432 catch (
const std::runtime_error& e) {
1433 handleFailure(
"Runtime error encountered", e);
1435 catch (
const Dune::ISTLError& e) {
1436 handleFailure(
"ISTL error - Time step too large", e);
1438 catch (
const Dune::MatrixBlockError& e) {
1439 handleFailure(
"Matrix block error", e);
1442 return substep_report;
1445 template<
class TypeTag>
1446 template<
class Solver>
1448 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1449 setTimeStep_(
double dt_estimate)
1451 this->substep_timer_.provideTimeStepEstimate(dt_estimate);
1454 template<
class TypeTag>
1455 template<
class Solver>
1457 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1460 return this->substepper_.solver_;
1464 template<
class TypeTag>
1465 template<
class Solver>
1467 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1468 solverRestartMax_()
const 1470 return this->adaptive_time_stepping_.solver_restart_max_;
1473 template<
class TypeTag>
1474 template<
class Solver>
1476 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1477 setSuggestedNextStep_(
double step)
1479 this->adaptive_time_stepping_.setSuggestedNextStep(step);
1482 template <
class TypeTag>
1483 template <
class Solver>
1484 const SimulatorTimer&
1485 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1486 simulatorTimer_()
const 1488 return this->substepper_.simulator_timer_;
1491 template <
class TypeTag>
1492 template <
class Solver>
1494 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1495 solverVerbose_()
const 1497 return this->adaptive_time_stepping_.solver_verbose_;
1500 template<
class TypeTag>
1501 template<
class Solver>
1502 boost::posix_time::ptime
1503 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1504 startDateTime_()
const 1506 return simulatorTimer_().startDateTime();
1509 template <
class TypeTag>
1510 template <
class Solver>
1512 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1513 suggestedNextTimestep_()
const 1515 return this->adaptive_time_stepping_.suggestedNextStep();
1518 template <
class TypeTag>
1519 template <
class Solver>
1521 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1522 timeStepControlComputeEstimate_(
const double dt,
const int iterations,
1523 const AdaptiveSimulatorTimer& substepTimer)
const 1526 const SolutionTimeErrorSolverWrapper<Solver> relative_change{solver_()};
1527 return this->adaptive_time_stepping_.time_step_control_->computeTimeStepSize(
1528 dt, iterations, relative_change, substepTimer);
1531 template <
class TypeTag>
1532 template <
class Solver>
1534 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1535 timeStepVerbose_()
const 1537 return this->adaptive_time_stepping_.timestep_verbose_;
1547 template <
class TypeTag>
1548 template <
class Solver>
1550 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1551 updateSuggestedNextStep_()
1553 auto suggested_next_step = this->substep_timer_.currentStepLength();
1554 if (! std::isfinite(suggested_next_step)) {
1555 suggested_next_step = this->original_time_step_;
1557 if (timeStepVerbose_()) {
1558 std::ostringstream ss;
1559 this->substep_timer_.report(ss);
1560 ss <<
"Suggested next step size = " 1561 << unit::convert::to(suggested_next_step, unit::day) <<
" (days)" << std::endl;
1562 OpmLog::debug(ss.str());
1564 setSuggestedNextStep_(suggested_next_step);
1567 template <
class TypeTag>
1568 template <
class Solver>
1570 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1571 useNewtonIteration_()
const 1573 return this->adaptive_time_stepping_.use_newton_iteration_;
1576 template <
class TypeTag>
1577 template <
class Solver>
1579 AdaptiveTimeStepping<TypeTag>::SubStepIteration<Solver>::
1580 writeOutput_()
const 1582 time::StopWatch perf_timer;
1584 auto& problem = solver_().model().simulator().problem();
1585 problem.writeOutput(
true);
1586 return perf_timer.secsSinceStart();
1593 template<
class TypeTag>
1594 template<
class Solver>
1595 AdaptiveTimeStepping<TypeTag>::
1596 SolutionTimeErrorSolverWrapper<Solver>::
1597 SolutionTimeErrorSolverWrapper(
const Solver& solver)
1601 template<
class TypeTag>
1602 template<
class Solver>
1603 double AdaptiveTimeStepping<TypeTag>::SolutionTimeErrorSolverWrapper<Solver>::relativeChange()
const 1606 return solver_.model().relativeChange();
1611 #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:300
Adaptive time-stepping coordinator for the black-oil simulator.
Definition: AdaptiveTimeStepping.hpp:92
Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
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:325
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:197
void updateTUNING(double max_next_tstep, const Tuning &tuning)
Apply TUNING keyword parameters.
Definition: AdaptiveTimeStepping_impl.hpp:337
TimeStepControlInterface.
Definition: TimeStepControlInterface.hpp:50
double suggestedNextStep() const
Current suggested length for the next substep [s].
Definition: AdaptiveTimeStepping_impl.hpp:308
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:183