AdaptiveTimeStepping.hpp
Go to the documentation of this file.
1/*
2*/
3#ifndef OPM_ADAPTIVE_TIME_STEPPING_HPP
4#define OPM_ADAPTIVE_TIME_STEPPING_HPP
5
6#include <dune/common/version.hh>
7#if DUNE_VERSION_NEWER(DUNE_ISTL, 2, 8)
8#include <dune/istl/istlexception.hh>
9#else
10#include <dune/istl/ilu.hh>
11#endif
12
13#include <opm/common/Exceptions.hpp>
14#include <opm/common/ErrorMacros.hpp>
15#include <opm/common/OpmLog/OpmLog.hpp>
16
18
19#include <opm/grid/utility/StopWatch.hpp>
20
21#include <opm/input/eclipse/Units/Units.hpp>
22#include <opm/input/eclipse/Units/UnitSystem.hpp>
23
24#include <opm/input/eclipse/Schedule/Tuning.hpp>
25
26#include <opm/models/utils/basicproperties.hh>
27#include <opm/models/utils/parametersystem.hh>
28#include <opm/models/utils/propertysystem.hh>
29
36
37#include <fmt/format.h>
38
39#include <algorithm>
40#include <cassert>
41#include <cmath>
42#include <functional>
43#include <memory>
44#include <set>
45#include <sstream>
46#include <stdexcept>
47#include <string>
48#include <vector>
49
50namespace Opm::Properties {
51
52namespace TTag {
54 using InheritsFrom = std::tuple<EclTimeSteppingParameters>;
55};
56}
57
58template<class TypeTag, class MyTypeTag>
60 using type = UndefinedProperty;
61};
62template<class TypeTag, class MyTypeTag>
64 using type = UndefinedProperty;
65};
66template<class TypeTag, class MyTypeTag>
68 using type = UndefinedProperty;
69};
70template<class TypeTag, class MyTypeTag>
72 using type = UndefinedProperty;
73};
74template<class TypeTag, class MyTypeTag>
76 using type = UndefinedProperty;
77};
78template<class TypeTag, class MyTypeTag>
80 using type = UndefinedProperty;
81};
82template<class TypeTag, class MyTypeTag>
84 using type = UndefinedProperty;
85};
86template<class TypeTag, class MyTypeTag>
88 using type = UndefinedProperty;
89};
90template<class TypeTag, class MyTypeTag>
92 using type = UndefinedProperty;
93};
94template<class TypeTag, class MyTypeTag>
96 using type = UndefinedProperty;
97};
98template<class TypeTag, class MyTypeTag>
100 using type = UndefinedProperty;
101};
102template<class TypeTag, class MyTypeTag>
104 using type = UndefinedProperty;
105};
106template<class TypeTag, class MyTypeTag>
108 using type = UndefinedProperty;
109};
110template<class TypeTag, class MyTypeTag>
112 using type = UndefinedProperty;
113};
114template<class TypeTag, class MyTypeTag>
116 using type = UndefinedProperty;
117};
118template<class TypeTag, class MyTypeTag>
120 using type = UndefinedProperty;
121};
122template<class TypeTag, class MyTypeTag>
124 using type = UndefinedProperty;
125};
126
127template<class TypeTag>
128struct SolverContinueOnConvergenceFailure<TypeTag, TTag::FlowTimeSteppingParameters> {
129 static constexpr bool value = false;
130};
131template<class TypeTag>
132struct SolverMaxRestarts<TypeTag, TTag::FlowTimeSteppingParameters> {
133 static constexpr int value = 10;
134};
135template<class TypeTag>
136struct SolverVerbosity<TypeTag, TTag::FlowTimeSteppingParameters> {
137 static constexpr int value = 1;
138};
139template<class TypeTag>
140struct TimeStepVerbosity<TypeTag, TTag::FlowTimeSteppingParameters> {
141 static constexpr int value = 1;
142};
143template<class TypeTag>
144struct InitialTimeStepInDays<TypeTag, TTag::FlowTimeSteppingParameters> {
145 using type = GetPropType<TypeTag, Scalar>;
146 static constexpr type value = 1.0;
147};
148template<class TypeTag>
149struct FullTimeStepInitially<TypeTag, TTag::FlowTimeSteppingParameters> {
150 static constexpr bool value = false;
151};
152template<class TypeTag>
153struct TimeStepControl<TypeTag, TTag::FlowTimeSteppingParameters> {
154 static constexpr auto value = "pid+newtoniteration";
155};
156template<class TypeTag>
157struct TimeStepControlTolerance<TypeTag, TTag::FlowTimeSteppingParameters> {
158 using type = GetPropType<TypeTag, Scalar>;
159 static constexpr type value = 1e-1;
160};
161template<class TypeTag>
162struct TimeStepControlTargetIterations<TypeTag, TTag::FlowTimeSteppingParameters> {
163 static constexpr int value = 30;
164};
165template<class TypeTag>
166struct TimeStepControlTargetNewtonIterations<TypeTag, TTag::FlowTimeSteppingParameters> {
167 static constexpr int value = 8;
168};
169template<class TypeTag>
170struct TimeStepControlDecayRate<TypeTag, TTag::FlowTimeSteppingParameters> {
171 using type = GetPropType<TypeTag, Scalar>;
172 static constexpr type value = 0.75;
173};
174template<class TypeTag>
175struct TimeStepControlGrowthRate<TypeTag, TTag::FlowTimeSteppingParameters> {
176 using type = GetPropType<TypeTag, Scalar>;
177 static constexpr type value = 1.25;
178};
179template<class TypeTag>
180struct TimeStepControlDecayDampingFactor<TypeTag, TTag::FlowTimeSteppingParameters> {
181 using type = GetPropType<TypeTag, Scalar>;
182 static constexpr type value = 1.0;
183};
184template<class TypeTag>
185struct TimeStepControlGrowthDampingFactor<TypeTag, TTag::FlowTimeSteppingParameters> {
186 using type = GetPropType<TypeTag, Scalar>;
187 static constexpr type value = 3.2;
188};
189template<class TypeTag>
190struct TimeStepControlFileName<TypeTag, TTag::FlowTimeSteppingParameters> {
191 static constexpr auto value = "timesteps";
192};
193template<class TypeTag>
194struct MinTimeStepBeforeShuttingProblematicWellsInDays<TypeTag, TTag::FlowTimeSteppingParameters> {
195 using type = GetPropType<TypeTag, Scalar>;
196 static constexpr type value = 0.01;
197};
198
199template<class TypeTag>
200struct MinTimeStepBasedOnNewtonIterations<TypeTag, TTag::FlowTimeSteppingParameters> {
201 using type = GetPropType<TypeTag, Scalar>;
202 static constexpr type value = 0.0;
203};
204
205} // namespace Opm::Properties
206
207namespace Opm {
208
209struct StepReport;
210
211namespace detail {
212
213void logTimer(const AdaptiveSimulatorTimer& substepTimer);
214
215std::set<std::string> consistentlyFailingWells(const std::vector<StepReport>& sr);
216
217}
218
219 // AdaptiveTimeStepping
220 //---------------------
221 template<class TypeTag>
223 {
224 template <class Solver>
225 class SolutionTimeErrorSolverWrapper : public RelativeChangeInterface
226 {
227 const Solver& solver_;
228 public:
229 SolutionTimeErrorSolverWrapper(const Solver& solver)
230 : solver_(solver)
231 {}
232
234 double relativeChange() const
235 { return solver_.model().relativeChange(); }
236 };
237
238 template<class E>
239 void logException_(const E& exception, bool verbose)
240 {
241 if (verbose) {
242 std::string message;
243 message = "Caught Exception: ";
244 message += exception.what();
245 OpmLog::debug(message);
246 }
247 }
248
249 public:
251
253 AdaptiveTimeStepping(const UnitSystem& unitSystem,
254 const double max_next_tstep = -1.0,
255 const bool terminalOutput = true)
257 , restartFactor_(Parameters::get<TypeTag, Properties::SolverRestartFactor>()) // 0.33
258 , growthFactor_(Parameters::get<TypeTag, Properties::SolverGrowthFactor>()) // 2.0
259 , maxGrowth_(Parameters::get<TypeTag, Properties::SolverMaxGrowth>()) // 3.0
260 , maxTimeStep_(Parameters::get<TypeTag, Properties::SolverMaxTimeStepInDays>() * 24 * 60 * 60) // 365.25
261 , minTimeStep_(unitSystem.to_si(UnitSystem::measure::time, Parameters::get<TypeTag, Properties::SolverMinTimeStep>())) // 1e-12;
262 , ignoreConvergenceFailure_(Parameters::get<TypeTag, Properties::SolverContinueOnConvergenceFailure>()) // false;
263 , solverRestartMax_(Parameters::get<TypeTag, Properties::SolverMaxRestarts>()) // 10
264 , solverVerbose_(Parameters::get<TypeTag, Properties::SolverVerbosity>() > 0 && terminalOutput) // 2
265 , timestepVerbose_(Parameters::get<TypeTag, Properties::TimeStepVerbosity>() > 0 && terminalOutput) // 2
266 , suggestedNextTimestep_((max_next_tstep <= 0 ? Parameters::get<TypeTag, Properties::InitialTimeStepInDays>() : max_next_tstep) * 24 * 60 * 60) // 1.0
267 , fullTimestepInitially_(Parameters::get<TypeTag, Properties::FullTimeStepInitially>()) // false
268 , timestepAfterEvent_(Parameters::get<TypeTag, Properties::TimeStepAfterEventInDays>() * 24 * 60 * 60) // 1e30
269 , useNewtonIteration_(false)
270 , minTimeStepBeforeShuttingProblematicWells_(Parameters::get<TypeTag, Properties::MinTimeStepBeforeShuttingProblematicWellsInDays>() * unit::day)
271
272 {
273 init_(unitSystem);
274 }
275
276
277
281 AdaptiveTimeStepping(double max_next_tstep,
282 const Tuning& tuning,
283 const UnitSystem& unitSystem,
284 const bool terminalOutput = true)
286 , restartFactor_(tuning.TSFCNV)
287 , growthFactor_(tuning.TFDIFF)
288 , maxGrowth_(tuning.TSFMAX)
289 , maxTimeStep_(tuning.TSMAXZ) // 365.25
290 , minTimeStep_(tuning.TSFMIN) // 0.1;
292 , solverRestartMax_(Parameters::get<TypeTag, Properties::SolverMaxRestarts>()) // 10
293 , solverVerbose_(Parameters::get<TypeTag, Properties::SolverVerbosity>() > 0 && terminalOutput) // 2
294 , timestepVerbose_(Parameters::get<TypeTag, Properties::TimeStepVerbosity>() > 0 && terminalOutput) // 2
295 , suggestedNextTimestep_(max_next_tstep <= 0 ? Parameters::get<TypeTag, Properties::InitialTimeStepInDays>() * 24 * 60 * 60 : max_next_tstep) // 1.0
296 , fullTimestepInitially_(Parameters::get<TypeTag, Properties::FullTimeStepInitially>()) // false
297 , timestepAfterEvent_(tuning.TMAXWC) // 1e30
298 , useNewtonIteration_(false)
299 , minTimeStepBeforeShuttingProblematicWells_(Parameters::get<TypeTag, Properties::MinTimeStepBeforeShuttingProblematicWellsInDays>() * unit::day)
300 {
301 init_(unitSystem);
302 }
303
304 static void registerParameters()
305 {
306 registerEclTimeSteppingParameters<TypeTag>();
307 // TODO: make sure the help messages are correct (and useful)
308 Parameters::registerParam<TypeTag, Properties::SolverContinueOnConvergenceFailure>
309 ("Continue instead of stop when minimum solver time step is reached");
310 Parameters::registerParam<TypeTag, Properties::SolverMaxRestarts>
311 ("The maximum number of breakdowns before a substep is given up and "
312 "the simulator is terminated");
313 Parameters::registerParam<TypeTag, Properties::SolverVerbosity>
314 ("Specify the \"chattiness\" of the non-linear solver itself");
315 Parameters::registerParam<TypeTag, Properties::TimeStepVerbosity>
316 ("Specify the \"chattiness\" during the time integration");
317 Parameters::registerParam<TypeTag, Properties::InitialTimeStepInDays>
318 ("The size of the initial time step in days");
319 Parameters::registerParam<TypeTag, Properties::FullTimeStepInitially>
320 ("Always attempt to finish a report step using a single substep");
321 Parameters::registerParam<TypeTag, Properties::TimeStepControl>
322 ("The algorithm used to determine time-step sizes. "
323 "Valid options are: "
324 "'pid' (default), "
325 "'pid+iteration', "
326 "'pid+newtoniteration', "
327 "'iterationcount', "
328 "'newtoniterationcount' "
329 "and 'hardcoded'");
330 Parameters::registerParam<TypeTag, Properties::TimeStepControlTolerance>
331 ("The tolerance used by the time step size control algorithm");
332 Parameters::registerParam<TypeTag, Properties::TimeStepControlTargetIterations>
333 ("The number of linear iterations which the time step control scheme "
334 "should aim for (if applicable)");
335 Parameters::registerParam<TypeTag, Properties::TimeStepControlTargetNewtonIterations>
336 ("The number of Newton iterations which the time step control scheme "
337 "should aim for (if applicable)");
338 Parameters::registerParam<TypeTag, Properties::TimeStepControlDecayRate>
339 ("The decay rate of the time step size of the number of "
340 "target iterations is exceeded");
341 Parameters::registerParam<TypeTag, Properties::TimeStepControlGrowthRate>
342 ("The growth rate of the time step size of the number of "
343 "target iterations is undercut");
344 Parameters::registerParam<TypeTag, Properties::TimeStepControlDecayDampingFactor>
345 ("The decay rate of the time step decrease when the "
346 "target iterations is exceeded");
347 Parameters::registerParam<TypeTag, Properties::TimeStepControlGrowthDampingFactor>
348 ("The growth rate of the time step increase when the "
349 "target iterations is undercut");
350 Parameters::registerParam<TypeTag, Properties::TimeStepControlFileName>
351 ("The name of the file which contains the hardcoded time steps sizes");
352 Parameters::registerParam<TypeTag, Properties::MinTimeStepBeforeShuttingProblematicWellsInDays>
353 ("The minimum time step size in days for which problematic wells are not shut");
354 Parameters::registerParam<TypeTag, Properties::MinTimeStepBasedOnNewtonIterations>
355 ("The minimum time step size (in days for field and metric unit and hours for lab unit) "
356 "can be reduced to based on newton iteration counts");
357 }
358
364 template <class Solver>
365 SimulatorReport step(const SimulatorTimer& simulatorTimer,
366 Solver& solver,
367 const bool isEvent,
368 const std::vector<int>* fipnum = nullptr,
369 const std::function<bool()> tuningUpdater = [](){return false;})
370 {
371 // Maybe update tuning
372 tuningUpdater();
373 SimulatorReport report;
374 const double timestep = simulatorTimer.currentStepLength();
375
376 // init last time step as a fraction of the given time step
377 if (suggestedNextTimestep_ < 0) {
379 }
380
382 suggestedNextTimestep_ = timestep;
383 }
384
385 // use seperate time step after event
386 if (isEvent && timestepAfterEvent_ > 0) {
388 }
389
390 auto& simulator = solver.model().simulator();
391 auto& problem = simulator.problem();
392
393 // create adaptive step timer with previously used sub step size
394 AdaptiveSimulatorTimer substepTimer(simulatorTimer, suggestedNextTimestep_, maxTimeStep_);
395
396 // counter for solver restarts
397 int restarts = 0;
398
399 // sub step time loop
400 while (!substepTimer.done()) {
401 // Maybe update tuning
402 // get current delta t
403 auto oldValue = suggestedNextTimestep_;
404 if (tuningUpdater()) {
405 // Use provideTimeStepEstimate to make we sure don't simulate longer than the report step is.
406 substepTimer.provideTimeStepEstimate(suggestedNextTimestep_);
407 suggestedNextTimestep_ = oldValue;
408 }
409 const double dt = substepTimer.currentStepLength();
410 if (timestepVerbose_) {
411 detail::logTimer(substepTimer);
412 }
413
414 SimulatorReportSingle substepReport;
415 std::string causeOfFailure;
416 try {
417 substepReport = solver.step(substepTimer);
418
419 if (solverVerbose_) {
420 // report number of linear iterations
421 OpmLog::debug("Overall linear iterations used: " + std::to_string(substepReport.total_linear_iterations));
422 }
423 }
424 catch (const TooManyIterations& e) {
425 substepReport = solver.failureReport();
426 causeOfFailure = "Solver convergence failure - Iteration limit reached";
427
428 logException_(e, solverVerbose_);
429 // since linearIterations is < 0 this will restart the solver
430 }
431 catch (const LinearSolverProblem& e) {
432 substepReport = solver.failureReport();
433 causeOfFailure = "Linear solver convergence failure";
434
435 logException_(e, solverVerbose_);
436 // since linearIterations is < 0 this will restart the solver
437 }
438 catch (const NumericalProblem& e) {
439 substepReport = solver.failureReport();
440 causeOfFailure = "Solver convergence failure - Numerical problem encountered";
441
442 logException_(e, solverVerbose_);
443 // since linearIterations is < 0 this will restart the solver
444 }
445 catch (const std::runtime_error& e) {
446 substepReport = solver.failureReport();
447
448 logException_(e, solverVerbose_);
449 // also catch linear solver not converged
450 }
451 catch (const Dune::ISTLError& e) {
452 substepReport = solver.failureReport();
453
454 logException_(e, solverVerbose_);
455 // also catch errors in ISTL AMG that occur when time step is too large
456 }
457 catch (const Dune::MatrixBlockError& e) {
458 substepReport = solver.failureReport();
459
460 logException_(e, solverVerbose_);
461 // this can be thrown by ISTL's ILU0 in block mode, yet is not an ISTLError
462 }
463
464 //Pass substep to eclwriter for summary output
465 simulator.problem().setSubStepReport(substepReport);
466
467 report += substepReport;
468
469 bool continue_on_uncoverged_solution = ignoreConvergenceFailure_ &&
470 !substepReport.converged &&
471 dt <= minTimeStep_;
472
473 if (continue_on_uncoverged_solution && solverVerbose_) {
474 const auto msg = fmt::format(
475 "Solver failed to converge but timestep "
476 "{} is smaller or equal to {}\n"
477 "which is the minimum threshold given "
478 "by option --solver-min-time-step\n",
479 dt, minTimeStep_
480 );
481 OpmLog::problem(msg);
482 }
483
484 if (substepReport.converged || continue_on_uncoverged_solution) {
485
486 // advance by current dt
487 ++substepTimer;
488
489 // create object to compute the time error, simply forwards the call to the model
490 SolutionTimeErrorSolverWrapper<Solver> relativeChange(solver);
491
492 // compute new time step estimate
493 const int iterations = useNewtonIteration_ ? substepReport.total_newton_iterations
494 : substepReport.total_linear_iterations;
495 double dtEstimate = timeStepControl_->computeTimeStepSize(dt, iterations, relativeChange,
496 substepTimer.simulationTimeElapsed());
497
498 assert(dtEstimate > 0);
499 // limit the growth of the timestep size by the growth factor
500 dtEstimate = std::min(dtEstimate, double(maxGrowth_ * dt));
501 assert(dtEstimate > 0);
502 // further restrict time step size growth after convergence problems
503 if (restarts > 0) {
504 dtEstimate = std::min(growthFactor_ * dt, dtEstimate);
505 // solver converged, reset restarts counter
506 restarts = 0;
507 }
508
509 // Further restrict time step size if we are in
510 // prediction mode with THP constraints.
511 if (solver.model().wellModel().hasTHPConstraints()) {
512 const double maxPredictionTHPTimestep = 16.0 * unit::day;
513 dtEstimate = std::min(dtEstimate, maxPredictionTHPTimestep);
514 }
515 assert(dtEstimate > 0);
516 if (timestepVerbose_) {
517 std::ostringstream ss;
518 substepReport.reportStep(ss);
519 OpmLog::info(ss.str());
520 }
521
522 // write data if outputWriter was provided
523 // if the time step is done we do not need
524 // to write it as this will be done by the simulator
525 // anyway.
526 if (!substepTimer.done()) {
527 if (fipnum) {
528 solver.computeFluidInPlace(*fipnum);
529 }
530 time::StopWatch perfTimer;
531 perfTimer.start();
532
533 problem.writeOutput(simulatorTimer);
534
535 report.success.output_write_time += perfTimer.secsSinceStart();
536 }
537
538 // set new time step length
539 substepTimer.provideTimeStepEstimate(dtEstimate);
540
541 report.success.converged = substepTimer.done();
542 substepTimer.setLastStepFailed(false);
543
544 }
545 else { // in case of no convergence
546 substepTimer.setLastStepFailed(true);
547
548 // If we have restarted (i.e. cut the timestep) too
549 // many times, we have failed and throw an exception.
550 if (restarts >= solverRestartMax_) {
551 const auto msg = fmt::format(
552 "Solver failed to converge after cutting timestep {} times.",
553 restarts
554 );
555 if (solverVerbose_) {
556 OpmLog::error(msg);
557 }
558 // Use throw directly to prevent file and line
559 throw TimeSteppingBreakdown{msg};
560 }
561
562 // The new, chopped timestep.
563 const double newTimeStep = restartFactor_ * dt;
564
565
566 // If we have restarted (i.e. cut the timestep) too
567 // much, we have failed and throw an exception.
568 if (newTimeStep < minTimeStep_) {
569 const auto msg = fmt::format(
570 "Solver failed to converge after cutting timestep to {}\n"
571 "which is the minimum threshold given by option --solver-min-time-step\n",
573 );
574 if (solverVerbose_) {
575 OpmLog::error(msg);
576 }
577 // Use throw directly to prevent file and line
578 throw TimeSteppingBreakdown{msg};
579 }
580
581 // Define utility function for chopping timestep.
582 auto chopTimestep = [&]() {
583 substepTimer.provideTimeStepEstimate(newTimeStep);
584 if (solverVerbose_) {
585 const auto msg = fmt::format(
586 "{}\nTimestep chopped to {} days\n",
587 causeOfFailure,
588 std::to_string(unit::convert::to(substepTimer.currentStepLength(), unit::day))
589 );
590 OpmLog::problem(msg);
591 }
592 ++restarts;
593 };
594
595 const double minimumChoppedTimestep = minTimeStepBeforeShuttingProblematicWells_;
596 if (newTimeStep > minimumChoppedTimestep) {
597 chopTimestep();
598 } else {
599 // We are below the threshold, and will check if there are any
600 // wells we should close rather than chopping again.
601 std::set<std::string> failing_wells = detail::consistentlyFailingWells(solver.model().stepReports());
602 if (failing_wells.empty()) {
603 // Found no wells to close, chop the timestep as above.
604 chopTimestep();
605 } else {
606 // Close all consistently failing wells.
607 int num_shut_wells = 0;
608 for (const auto& well : failing_wells) {
609 bool was_shut = solver.model().wellModel().forceShutWellByName(well, substepTimer.simulationTimeElapsed());
610 if (was_shut) {
611 ++num_shut_wells;
612 }
613 }
614 if (num_shut_wells == 0) {
615 // None of the problematic wells were shut.
616 // We must fall back to chopping again.
617 chopTimestep();
618 } else {
619 substepTimer.provideTimeStepEstimate(dt);
620 if (solverVerbose_) {
621 std::string msg;
622 msg = "\nProblematic well(s) were shut: ";
623 for (const auto& well : failing_wells) {
624 msg += well;
625 msg += " ";
626 }
627 msg += "(retrying timestep)\n";
628 OpmLog::problem(msg);
629 }
630 }
631 }
632 }
633 }
634 problem.setNextTimeStepSize(substepTimer.currentStepLength());
635 }
636
637 // store estimated time step for next reportStep
638 suggestedNextTimestep_ = substepTimer.currentStepLength();
639 if (timestepVerbose_) {
640 std::ostringstream ss;
641 substepTimer.report(ss);
642 ss << "Suggested next step size = " << unit::convert::to(suggestedNextTimestep_, unit::day) << " (days)" << std::endl;
643 OpmLog::debug(ss.str());
644 }
645
646 if (! std::isfinite(suggestedNextTimestep_)) { // check for NaN
647 suggestedNextTimestep_ = timestep;
648 }
649 return report;
650 }
651
655 double suggestedNextStep() const
656 { return suggestedNextTimestep_; }
657
658 void setSuggestedNextStep(const double x)
660
661 void updateTUNING(double max_next_tstep, const Tuning& tuning)
662 {
663 restartFactor_ = tuning.TSFCNV;
664 growthFactor_ = tuning.TFDIFF;
665 maxGrowth_ = tuning.TSFMAX;
666 maxTimeStep_ = tuning.TSMAXZ;
667 updateNEXTSTEP(max_next_tstep);
668 timestepAfterEvent_ = tuning.TMAXWC;
669 }
670
671 void updateNEXTSTEP(double max_next_tstep)
672 {
673 // \Note Only update next suggested step if TSINIT was explicitly set in TUNING or NEXTSTEP is active.
674 if (max_next_tstep > 0) {
675 suggestedNextTimestep_ = max_next_tstep;
676 }
677 }
678
679 template<class Serializer>
680 void serializeOp(Serializer& serializer)
681 {
682 serializer(timeStepControlType_);
683 switch (timeStepControlType_) {
685 allocAndSerialize<HardcodedTimeStepControl>(serializer);
686 break;
688 allocAndSerialize<PIDAndIterationCountTimeStepControl>(serializer);
689 break;
691 allocAndSerialize<SimpleIterationCountTimeStepControl>(serializer);
692 break;
694 allocAndSerialize<PIDTimeStepControl>(serializer);
695 break;
696 }
697 serializer(restartFactor_);
698 serializer(growthFactor_);
699 serializer(maxGrowth_);
700 serializer(maxTimeStep_);
701 serializer(minTimeStep_);
702 serializer(ignoreConvergenceFailure_);
703 serializer(solverRestartMax_);
704 serializer(solverVerbose_);
705 serializer(timestepVerbose_);
706 serializer(suggestedNextTimestep_);
707 serializer(fullTimestepInitially_);
708 serializer(timestepAfterEvent_);
709 serializer(useNewtonIteration_);
711 }
712
714 {
715 return serializationTestObject_<HardcodedTimeStepControl>();
716 }
717
719 {
720 return serializationTestObject_<PIDTimeStepControl>();
721 }
722
724 {
725 return serializationTestObject_<PIDAndIterationCountTimeStepControl>();
726 }
727
729 {
730 return serializationTestObject_<SimpleIterationCountTimeStepControl>();
731 }
732
734 {
738 return false;
739 }
740
741 bool result = false;
742 switch (timeStepControlType_) {
744 result = castAndComp<HardcodedTimeStepControl>(rhs);
745 break;
747 result = castAndComp<PIDAndIterationCountTimeStepControl>(rhs);
748 break;
750 result = castAndComp<SimpleIterationCountTimeStepControl>(rhs);
751 break;
753 result = castAndComp<PIDTimeStepControl>(rhs);
754 break;
755 }
756
757 return result &&
758 this->restartFactor_ == rhs.restartFactor_ &&
759 this->growthFactor_ == rhs.growthFactor_ &&
760 this->maxGrowth_ == rhs.maxGrowth_ &&
761 this->maxTimeStep_ == rhs.maxTimeStep_ &&
762 this->minTimeStep_ == rhs.minTimeStep_ &&
765 this->solverVerbose_ == rhs.solverVerbose_ &&
771 }
772
773 private:
774 template<class Controller>
775 static AdaptiveTimeStepping<TypeTag> serializationTestObject_()
776 {
778
779 result.restartFactor_ = 1.0;
780 result.growthFactor_ = 2.0;
781 result.maxGrowth_ = 3.0;
782 result.maxTimeStep_ = 4.0;
783 result.minTimeStep_ = 5.0;
784 result.ignoreConvergenceFailure_ = true;
785 result.solverRestartMax_ = 6;
786 result.solverVerbose_ = true;
787 result.timestepVerbose_ = true;
788 result.suggestedNextTimestep_ = 7.0;
789 result.fullTimestepInitially_ = true;
790 result.useNewtonIteration_ = true;
792 result.timeStepControlType_ = Controller::Type;
793 result.timeStepControl_ = std::make_unique<Controller>(Controller::serializationTestObject());
794
795 return result;
796 }
797 template<class T, class Serializer>
798 void allocAndSerialize(Serializer& serializer)
799 {
800 if (!serializer.isSerializing()) {
801 timeStepControl_ = std::make_unique<T>();
802 }
803 serializer(*static_cast<T*>(timeStepControl_.get()));
804 }
805
806 template<class T>
807 bool castAndComp(const AdaptiveTimeStepping<TypeTag>& Rhs) const
808 {
809 const T* lhs = static_cast<const T*>(timeStepControl_.get());
810 const T* rhs = static_cast<const T*>(Rhs.timeStepControl_.get());
811 return *lhs == *rhs;
812 }
813
814 protected:
815 void init_(const UnitSystem& unitSystem)
816 {
817 // valid are "pid" and "pid+iteration"
818 std::string control = Parameters::get<TypeTag, Properties::TimeStepControl>(); // "pid"
819
820 const double tol = Parameters::get<TypeTag, Properties::TimeStepControlTolerance>(); // 1e-1
821 if (control == "pid") {
822 timeStepControl_ = std::make_unique<PIDTimeStepControl>(tol);
824 }
825 else if (control == "pid+iteration") {
826 const int iterations = Parameters::get<TypeTag, Properties::TimeStepControlTargetIterations>(); // 30
827 const double decayDampingFactor = Parameters::get<TypeTag, Properties::TimeStepControlDecayDampingFactor>(); // 1.0
828 const double growthDampingFactor = Parameters::get<TypeTag, Properties::TimeStepControlGrowthDampingFactor>(); // 3.2
829 timeStepControl_ = std::make_unique<PIDAndIterationCountTimeStepControl>(iterations, decayDampingFactor, growthDampingFactor, tol);
831 }
832 else if (control == "pid+newtoniteration") {
833 const int iterations = Parameters::get<TypeTag, Properties::TimeStepControlTargetNewtonIterations>(); // 8
834 const double decayDampingFactor = Parameters::get<TypeTag, Properties::TimeStepControlDecayDampingFactor>(); // 1.0
835 const double growthDampingFactor = Parameters::get<TypeTag, Properties::TimeStepControlGrowthDampingFactor>(); // 3.2
836 const double nonDimensionalMinTimeStepIterations = Parameters::get<TypeTag, Properties::MinTimeStepBasedOnNewtonIterations>(); // 0.0 by default
837 // the min time step can be reduced by the newton iteration numbers
838 double minTimeStepReducedByIterations = unitSystem.to_si(UnitSystem::measure::time, nonDimensionalMinTimeStepIterations);
839 timeStepControl_ = std::make_unique<PIDAndIterationCountTimeStepControl>(iterations, decayDampingFactor,
840 growthDampingFactor, tol, minTimeStepReducedByIterations);
842 useNewtonIteration_ = true;
843 }
844 else if (control == "iterationcount") {
845 const int iterations = Parameters::get<TypeTag, Properties::TimeStepControlTargetIterations>(); // 30
846 const double decayrate = Parameters::get<TypeTag, Properties::TimeStepControlDecayRate>(); // 0.75
847 const double growthrate = Parameters::get<TypeTag, Properties::TimeStepControlGrowthRate>(); // 1.25
848 timeStepControl_ = std::make_unique<SimpleIterationCountTimeStepControl>(iterations, decayrate, growthrate);
850 }
851 else if (control == "newtoniterationcount") {
852 const int iterations = Parameters::get<TypeTag, Properties::TimeStepControlTargetNewtonIterations>(); // 8
853 const double decayrate = Parameters::get<TypeTag, Properties::TimeStepControlDecayRate>(); // 0.75
854 const double growthrate = Parameters::get<TypeTag, Properties::TimeStepControlGrowthRate>(); // 1.25
855 timeStepControl_ = std::make_unique<SimpleIterationCountTimeStepControl>(iterations, decayrate, growthrate);
856 useNewtonIteration_ = true;
858 }
859 else if (control == "hardcoded") {
860 const std::string filename = Parameters::get<TypeTag, Properties::TimeStepControlFileName>(); // "timesteps"
861 timeStepControl_ = std::make_unique<HardcodedTimeStepControl>(filename);
863 }
864 else
865 OPM_THROW(std::runtime_error,
866 "Unsupported time step control selected " + control);
867
868 // make sure growth factor is something reasonable
869 assert(growthFactor_ >= 1.0);
870 }
871
872 using TimeStepController = std::unique_ptr<TimeStepControlInterface>;
873
878 double maxGrowth_;
890 };
891}
892
893#endif // OPM_ADAPTIVE_TIME_STEPPING_HPP
Simulation timer for adaptive time stepping.
Definition: AdaptiveSimulatorTimer.hpp:41
Definition: AdaptiveTimeStepping.hpp:223
double minTimeStep_
minimal allowed time step size before throwing
Definition: AdaptiveTimeStepping.hpp:880
double suggestedNextTimestep_
suggested size of next timestep
Definition: AdaptiveTimeStepping.hpp:885
bool solverVerbose_
solver verbosity
Definition: AdaptiveTimeStepping.hpp:883
void init_(const UnitSystem &unitSystem)
Definition: AdaptiveTimeStepping.hpp:815
void setSuggestedNextStep(const double x)
Definition: AdaptiveTimeStepping.hpp:658
double suggestedNextStep() const
Returns the simulator report for the failed substeps of the last report step.
Definition: AdaptiveTimeStepping.hpp:655
double growthFactor_
factor to multiply time step when solver recovered from failed convergence
Definition: AdaptiveTimeStepping.hpp:877
AdaptiveTimeStepping(const UnitSystem &unitSystem, const double max_next_tstep=-1.0, const bool terminalOutput=true)
contructor taking parameter object
Definition: AdaptiveTimeStepping.hpp:253
void serializeOp(Serializer &serializer)
Definition: AdaptiveTimeStepping.hpp:680
void updateTUNING(double max_next_tstep, const Tuning &tuning)
Definition: AdaptiveTimeStepping.hpp:661
static void registerParameters()
Definition: AdaptiveTimeStepping.hpp:304
TimeStepController timeStepControl_
time step control object
Definition: AdaptiveTimeStepping.hpp:875
static AdaptiveTimeStepping< TypeTag > serializationTestObjectSimple()
Definition: AdaptiveTimeStepping.hpp:728
bool fullTimestepInitially_
beginning with the size of the time step from data file
Definition: AdaptiveTimeStepping.hpp:886
AdaptiveTimeStepping(double max_next_tstep, const Tuning &tuning, const UnitSystem &unitSystem, const bool terminalOutput=true)
contructor taking parameter object
Definition: AdaptiveTimeStepping.hpp:281
std::unique_ptr< TimeStepControlInterface > TimeStepController
Definition: AdaptiveTimeStepping.hpp:872
double timestepAfterEvent_
suggested size of timestep after an event
Definition: AdaptiveTimeStepping.hpp:887
bool useNewtonIteration_
use newton iteration count for adaptive time step control
Definition: AdaptiveTimeStepping.hpp:888
bool timestepVerbose_
timestep verbosity
Definition: AdaptiveTimeStepping.hpp:884
int solverRestartMax_
how many restart of solver are allowed
Definition: AdaptiveTimeStepping.hpp:882
TimeStepControlType timeStepControlType_
type of time step control object
Definition: AdaptiveTimeStepping.hpp:874
double minTimeStepBeforeShuttingProblematicWells_
Definition: AdaptiveTimeStepping.hpp:889
bool operator==(const AdaptiveTimeStepping< TypeTag > &rhs)
Definition: AdaptiveTimeStepping.hpp:733
SimulatorReport step(const SimulatorTimer &simulatorTimer, Solver &solver, const bool isEvent, const std::vector< int > *fipnum=nullptr, const std::function< bool()> tuningUpdater=[](){return false;})
step method that acts like the solver::step method in a sub cycle of time steps
Definition: AdaptiveTimeStepping.hpp:365
static AdaptiveTimeStepping< TypeTag > serializationTestObjectPIDIt()
Definition: AdaptiveTimeStepping.hpp:723
void updateNEXTSTEP(double max_next_tstep)
Definition: AdaptiveTimeStepping.hpp:671
bool ignoreConvergenceFailure_
continue instead of stop when minimum time step is reached
Definition: AdaptiveTimeStepping.hpp:881
double maxTimeStep_
maximal allowed time step size in days
Definition: AdaptiveTimeStepping.hpp:879
static AdaptiveTimeStepping< TypeTag > serializationTestObjectHardcoded()
Definition: AdaptiveTimeStepping.hpp:713
double restartFactor_
factor to multiply time step with when solver fails to converge
Definition: AdaptiveTimeStepping.hpp:876
double maxGrowth_
factor that limits the maximum growth of a time step
Definition: AdaptiveTimeStepping.hpp:878
static AdaptiveTimeStepping< TypeTag > serializationTestObjectPID()
Definition: AdaptiveTimeStepping.hpp:718
Definition: TimeStepControlInterface.hpp:32
Definition: SimulatorTimer.hpp:39
double currentStepLength() const override
Definition: AluGridVanguard.hpp:57
void logTimer(const AdaptiveSimulatorTimer &substepTimer)
std::set< std::string > consistentlyFailingWells(const std::vector< StepReport > &sr)
Definition: BlackoilPhases.hpp:27
std::string to_string(const ConvergenceReport::ReservoirFailure::Type t)
TimeStepControlType
Definition: TimeStepControl.hpp:31
Definition: AdaptiveTimeStepping.hpp:79
UndefinedProperty type
Definition: AdaptiveTimeStepping.hpp:80
GetPropType< TypeTag, Scalar > type
Definition: AdaptiveTimeStepping.hpp:145
Definition: AdaptiveTimeStepping.hpp:75
UndefinedProperty type
Definition: AdaptiveTimeStepping.hpp:76
GetPropType< TypeTag, Scalar > type
Definition: AdaptiveTimeStepping.hpp:201
Definition: AdaptiveTimeStepping.hpp:123
UndefinedProperty type
Definition: AdaptiveTimeStepping.hpp:124
UndefinedProperty type
Definition: AdaptiveTimeStepping.hpp:120
Definition: AdaptiveTimeStepping.hpp:59
UndefinedProperty type
Definition: AdaptiveTimeStepping.hpp:60
Definition: AdaptiveTimeStepping.hpp:63
UndefinedProperty type
Definition: AdaptiveTimeStepping.hpp:64
Definition: AdaptiveTimeStepping.hpp:67
UndefinedProperty type
Definition: AdaptiveTimeStepping.hpp:68
Definition: AdaptiveTimeStepping.hpp:53
std::tuple< EclTimeSteppingParameters > InheritsFrom
Definition: AdaptiveTimeStepping.hpp:54
GetPropType< TypeTag, Scalar > type
Definition: AdaptiveTimeStepping.hpp:181
Definition: AdaptiveTimeStepping.hpp:107
UndefinedProperty type
Definition: AdaptiveTimeStepping.hpp:108
GetPropType< TypeTag, Scalar > type
Definition: AdaptiveTimeStepping.hpp:171
Definition: AdaptiveTimeStepping.hpp:99
UndefinedProperty type
Definition: AdaptiveTimeStepping.hpp:100
Definition: AdaptiveTimeStepping.hpp:115
UndefinedProperty type
Definition: AdaptiveTimeStepping.hpp:116
GetPropType< TypeTag, Scalar > type
Definition: AdaptiveTimeStepping.hpp:186
Definition: AdaptiveTimeStepping.hpp:111
UndefinedProperty type
Definition: AdaptiveTimeStepping.hpp:112
GetPropType< TypeTag, Scalar > type
Definition: AdaptiveTimeStepping.hpp:176
Definition: AdaptiveTimeStepping.hpp:103
UndefinedProperty type
Definition: AdaptiveTimeStepping.hpp:104
Definition: AdaptiveTimeStepping.hpp:83
UndefinedProperty type
Definition: AdaptiveTimeStepping.hpp:84
Definition: AdaptiveTimeStepping.hpp:91
UndefinedProperty type
Definition: AdaptiveTimeStepping.hpp:92
Definition: AdaptiveTimeStepping.hpp:95
UndefinedProperty type
Definition: AdaptiveTimeStepping.hpp:96
GetPropType< TypeTag, Scalar > type
Definition: AdaptiveTimeStepping.hpp:158
Definition: AdaptiveTimeStepping.hpp:87
UndefinedProperty type
Definition: AdaptiveTimeStepping.hpp:88
Definition: AdaptiveTimeStepping.hpp:71
UndefinedProperty type
Definition: AdaptiveTimeStepping.hpp:72
Definition: SimulatorReport.hpp:100
SimulatorReportSingle success
Definition: SimulatorReport.hpp:101
bool converged
Definition: SimulatorReport.hpp:54
double output_write_time
Definition: SimulatorReport.hpp:45
Definition: ConvergenceReport.hpp:225