Skip to content

Commit e952a40

Browse files
authored
Merge pull request OPM#6280 from erikhide/general-controller-further-updates
Further updates and fixes to general controller
2 parents 52b5e2e + 6cf2d41 commit e952a40

File tree

9 files changed

+198
-61
lines changed

9 files changed

+198
-61
lines changed

opm/simulators/flow/NonlinearSolver.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,9 @@ struct NonlinearSolverParameters
176176
OPM_THROW_NOLOG(TooManyIterations, msg);
177177
}
178178
auto relativeChange = model_->relativeChange();
179-
if (timeStepControl && !timeStepControl->timeStepAccepted(relativeChange)) {
179+
if (timeStepControl && !timeStepControl->timeStepAccepted(relativeChange, timer.currentStepLength())) {
180180
report.converged = false;
181+
report.time_step_rejected = true;
181182
failureReport_ = report;
182183

183184
std::string msg = "Relative change in solution for time step was " + std::to_string(relativeChange) + ", which is larger than the tolerance accepted by the timestepping algorithm.";

opm/simulators/timestepping/AdaptiveTimeStepping.cpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,19 @@ void registerAdaptiveParameters()
142142
Parameters::Register<Parameters::TimeStepControlRejectCompletedStep>
143143
("(Only applicable for the general 3rd order controller.) Include rejection of completed "
144144
"time steps if the relative change is larger than the time step control tolerance");
145+
Parameters::Register<Parameters::TimeStepControlToleranceTestVersion>
146+
("(Only applicable for the general 3rd order controller.) Ways to decide if the time step "
147+
"should be rejected. Options: 'standard' and 'control-error-filtering'. The standard "
148+
"version compares relative change to tolerance directly to decide if the time step should "
149+
"be rejected, while the control-error-filtering version compares the relative change "
150+
"in time step size to the max-reduction-time-step parameter.");
151+
Parameters::Register<Parameters::TimeStepControlMaxReductionTimeStep>
152+
("(Only applicable for the general 3rd order controller, using 'control-error-filtering' "
153+
"as time-step-control-tolerance-test-version) If the (proposed) relative change in time "
154+
"step size is larger than this parameter, the time step will be rejected.");
155+
Parameters::Register<Parameters::TimeStepControlParameters>
156+
("(Only applicable for the general 3rd order controller.) Parameters for the general "
157+
"3rd order controller. Should be given as 'beta_1;beta_2;beta_3;alpha_2;alpha_3'.");
145158
}
146159

147160
std::tuple<TimeStepControlType, std::unique_ptr<TimeStepControlInterface>, bool>
@@ -220,13 +233,21 @@ createController(const UnitSystem& unitSystem)
220233
}},
221234
{"general3rdorder",
222235
[tol]() {
223-
const double safetyFactor = Parameters::Get<Parameters::TimeStepControlSafetyFactor>(); // 0.8
224-
const bool rejectCompletedStep = Parameters::Get<Parameters::TimeStepControlRejectCompletedStep>(); // false
236+
const double safetyFactor = Parameters::Get<Parameters::TimeStepControlSafetyFactor>();
237+
const bool rejectCompletedStep = Parameters::Get<Parameters::TimeStepControlRejectCompletedStep>();
238+
const std::string toleranceTestVersion = Parameters::Get<Parameters::TimeStepControlToleranceTestVersion>();
239+
const double maxReductionTimeStep = Parameters::Get<Parameters::TimeStepControlMaxReductionTimeStep>();
240+
const std::string parameters = Parameters::Get<Parameters::TimeStepControlParameters>();
241+
const bool verbose = Parameters::Get<Parameters::TimeStepVerbosity>();
225242
return RetVal{
226243
TimeStepControlType::General3rdOrder,
227244
std::make_unique<General3rdOrderController>(tol,
228245
safetyFactor,
229-
rejectCompletedStep),
246+
rejectCompletedStep,
247+
toleranceTestVersion,
248+
maxReductionTimeStep,
249+
parameters,
250+
verbose),
230251
false
231252
};
232253
}},

opm/simulators/timestepping/AdaptiveTimeStepping.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ struct MinTimeStepBeforeShuttingProblematicWellsInDays { static constexpr double
4949
struct MinTimeStepBasedOnNewtonIterations { static constexpr double value = 0.0; };
5050
struct TimeStepControlSafetyFactor { static constexpr double value = 0.8; };
5151
struct TimeStepControlRejectCompletedStep { static constexpr bool value = false; };
52+
struct TimeStepControlToleranceTestVersion { static constexpr auto value = "standard"; };
53+
struct TimeStepControlMaxReductionTimeStep { static constexpr double value = 0.1; };
54+
struct TimeStepControlParameters { static constexpr auto value = "0.125;0.25;0.125;0.75;0.25"; };
5255

5356
} // namespace Opm::Parameters
5457

opm/simulators/timestepping/AdaptiveTimeStepping_impl.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,15 @@ run()
825825
this->substep_timer_.setLastStepFailed(true);
826826
checkTimeStepMaxRestartLimit_(restarts);
827827

828-
const double new_time_step = restartFactor_() * dt;
828+
double new_time_step = restartFactor_() * dt;
829+
if (substep_report.time_step_rejected) {
830+
const double tol = Parameters::Get<Parameters::TimeStepControlTolerance>();
831+
const double safetyFactor = Parameters::Get<Parameters::TimeStepControlSafetyFactor>();
832+
const double temp_time_step = std::sqrt(safetyFactor * tol / solver_().model().relativeChange()) * dt;
833+
if (temp_time_step < dt) { // added in case suggested time step is not a reduction
834+
new_time_step = temp_time_step;
835+
}
836+
}
829837
checkTimeStepMinLimit_(new_time_step);
830838
bool wells_shut = false;
831839
if (new_time_step > minTimeStepBeforeClosingWells_()) {

opm/simulators/timestepping/SimulatorReport.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ namespace Opm
3535
return SimulatorReportSingle{1.0, 2.0, 3.0, 4.0, 5.0, 6.0,
3636
7.0, 8.0, 9.0, 10.0, 11.0, 12.0,
3737
13, 14, 15, 16, 17, 18,
38-
true, false, 19, 20.0, 21.0,
38+
true, false, false, 19, 20.0, 21.0,
3939
22, 23, 24, 25, 26, 27, 28};
4040
}
4141

@@ -60,6 +60,7 @@ namespace Opm
6060
this->min_linear_iterations == rhs.min_linear_iterations &&
6161
this->max_linear_iterations == rhs.max_linear_iterations &&
6262
this->converged == rhs.converged &&
63+
this->time_step_rejected == rhs.time_step_rejected &&
6364
this->well_group_control_changed == rhs.well_group_control_changed &&
6465
this->exit_status == rhs.exit_status &&
6566
this->global_time == rhs.global_time &&

opm/simulators/timestepping/SimulatorReport.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ namespace Opm
5353
unsigned int max_linear_iterations = 0;
5454

5555
bool converged = false;
56+
bool time_step_rejected = false;
5657
bool well_group_control_changed = false;
5758
int exit_status = EXIT_SUCCESS;
5859

@@ -101,6 +102,7 @@ namespace Opm
101102
serializer(min_linear_iterations);
102103
serializer(max_linear_iterations);
103104
serializer(converged);
105+
serializer(time_step_rejected);
104106
serializer(well_group_control_changed);
105107
serializer(exit_status);
106108
serializer(global_time);

opm/simulators/timestepping/TimeStepControl.cpp

Lines changed: 112 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <string>
2929
#include <fstream>
3030
#include <iostream>
31+
#include <sstream>
3132
#include <limits>
3233

3334
#include <opm/common/ErrorMacros.hpp>
@@ -292,83 +293,150 @@ namespace Opm
292293
General3rdOrderController::General3rdOrderController( const double tolerance,
293294
const double safetyFactor,
294295
const bool rejectCompletedStep,
296+
const std::string& toleranceTestVersion,
297+
const double maxReductionTimeStep,
298+
const std::string& parameters,
295299
const bool verbose)
296300
: tolerance_( tolerance )
297301
, safetyFactor_( safetyFactor )
298302
, rejectCompletedStep_( rejectCompletedStep )
299-
, errors_( 3, tolerance_ )
300-
, timeSteps_ ( 3, 1.0 )
303+
, maxReductionTimeStep_( maxReductionTimeStep )
301304
, verbose_( verbose )
302-
{}
305+
{
306+
std::istringstream parameters_stream(parameters);
307+
std::string value;
308+
int counter = 0;
309+
try {
310+
while (std::getline(parameters_stream, value, ';'))
311+
{
312+
if (counter < 3) {
313+
beta_[counter] = std::stod(value);
314+
}
315+
else {
316+
alpha_[counter - 3] = std::stod(value);
317+
}
318+
counter++;
319+
}
320+
}
321+
catch (const std::exception& e) {
322+
OPM_THROW(std::runtime_error, "The parameter string for the time step controller is invalid: " + parameters);
323+
}
324+
325+
if (toleranceTestVersion == "standard") {
326+
toleranceTestVersion_ = ToleranceTestVersions::Standard;
327+
}
328+
else if (toleranceTestVersion == "control-error-filtering") {
329+
toleranceTestVersion_ = ToleranceTestVersions::ControlErrorFiltering;
330+
}
331+
else {
332+
OPM_THROW(std::runtime_error, "Unsupported tolerance test version given: " + toleranceTestVersion);
333+
}
334+
}
303335

304336
General3rdOrderController
305337
General3rdOrderController::serializationTestObject()
306338
{
307-
General3rdOrderController result(1.0, 0.8, true);
339+
General3rdOrderController result(1.0, 2.0, false, "standard", 3.0, "0.125;0.25;0.125;0.75;0.25", false);
308340
result.errors_ = {2.0, 3.0};
309341

310342
return result;
311343
}
312344

313345
double General3rdOrderController::
314-
computeTimeStepSize(const double dt, const int /*iterations */, const RelativeChangeInterface& relChange, const AdaptiveSimulatorTimer& substepTimer) const
346+
computeTimeStepSize(const double dt, const int /* iterations */, const RelativeChangeInterface& /* relChange */, const AdaptiveSimulatorTimer& substepTimer) const
315347
{
316-
// Shift errors and time steps
317-
for( int i = 0; i < 2; ++i )
348+
if (errors_[0] == 0 || errors_[1] == 0 || errors_[2] == 0)
318349
{
319-
errors_[i] = errors_[i+1];
320-
timeSteps_[i] = timeSteps_[i+1];
350+
if ( verbose_ )
351+
{
352+
OpmLog::info("The solution between time steps does not change, there is no time step constraint from the controller.");
353+
}
354+
return std::numeric_limits<double>::max();
321355
}
322356

323-
// Store new error and time step
324-
const double error = relChange.relativeChange();
325-
errors_[2] = error;
326-
timeSteps_[2] = dt;
327357
for( int i = 0; i < 2; ++i )
328358
{
329359
assert(std::isfinite(errors_[i]));
330360
}
331361

332-
if (errors_[0] == 0 || errors_[1] == 0 || errors_[2] == 0.)
362+
// Use an I controller after report time steps
363+
if (substepTimer.currentStepNum() < 3)
333364
{
334-
if ( verbose_ )
335-
OpmLog::info("The solution between time steps does not change, there is no time step constraint from the controller.");
336-
return std::numeric_limits<double>::max();
337-
}
338-
// Use an I controller after report time steps or chopped time steps
339-
else if (substepTimer.currentStepNum() < 3 || substepTimer.lastStepFailed() || counterSinceFailure_ > 0)
340-
{
341-
if (substepTimer.lastStepFailed() || counterSinceFailure_ > 0)
342-
counterSinceFailure_++;
343-
if (counterSinceFailure_ > 1)
344-
counterSinceFailure_ = 0;
345-
const double newDt = dt * std::pow(safetyFactor_ * tolerance_ / errors_[2], 0.35);
346-
if( verbose_ )
365+
controllerVersion_ = InternalControlVersions::IController;
366+
const double newDt = dt * timeStepFactor(errors_, timeSteps_);
367+
if (verbose_)
368+
{
347369
OpmLog::info(fmt::format("Computed step size (pow): {} days", unit::convert::to( newDt, unit::day )));
370+
}
348371
return newDt;
349372
}
350373
// Use the general third order controller for all other time steps
351374
else
352375
{
353-
const std::array<double, 3> beta = { 0.125, 0.25, 0.125 };
354-
const std::array<double, 2> alpha = { 0.375, 0.125 };
355-
const double newDt = dt * std::pow(safetyFactor_ * tolerance_ / errors_[2], beta[0]) *
356-
std::pow(safetyFactor_ * tolerance_ / errors_[1], beta[1]) *
357-
std::pow(safetyFactor_ * tolerance_ / errors_[0], beta[2]) *
358-
std::pow(timeSteps_[2] / timeSteps_[1], -alpha[0]) *
359-
std::pow(timeSteps_[1] / timeSteps_[0], -alpha[1]);
360-
if( verbose_ )
376+
controllerVersion_ = InternalControlVersions::General3rdOrder;
377+
const double newDt = dt * timeStepFactor(errors_, timeSteps_);
378+
if (verbose_)
379+
{
361380
OpmLog::info(fmt::format("Computed step size (pow): {} days", unit::convert::to( newDt, unit::day )));
381+
}
362382
return newDt;
363383
}
364384
}
365385

386+
double General3rdOrderController::
387+
timeStepFactor(const std::array<double, 3>& errors, const std::array<double, 3>& timeSteps) const
388+
{
389+
if (controllerVersion_ == InternalControlVersions::General3rdOrder)
390+
{
391+
return std::pow(safetyFactor_ * tolerance_ / errors[2], beta_[0]) *
392+
std::pow(safetyFactor_ * tolerance_ / errors[1], beta_[1]) *
393+
std::pow(safetyFactor_ * tolerance_ / errors[0], beta_[2]) *
394+
std::pow(timeSteps[2] / timeSteps[1], -alpha_[0]) *
395+
std::pow(timeSteps[1] / timeSteps[0], -alpha_[1]);
396+
}
397+
// controllerVersion_ == InternalControlVersions::IController
398+
return std::pow(safetyFactor_ * tolerance_ / errors[2], 0.35);
399+
}
400+
366401
bool General3rdOrderController::
367-
timeStepAccepted(const double error) const
402+
timeStepAccepted(const double error, const double timeStepJustCompleted) const
368403
{
369-
if (rejectCompletedStep_ && error > tolerance_)
370-
return false;
371-
return true;
404+
bool acceptTimeStep = true;
405+
406+
// Reject time step if chosen tolerance test version fails
407+
if (toleranceTestVersion_ == ToleranceTestVersions::Standard)
408+
{
409+
if (rejectCompletedStep_ && error > tolerance_)
410+
{
411+
acceptTimeStep = false;
412+
}
413+
}
414+
else if (toleranceTestVersion_ == ToleranceTestVersions::ControlErrorFiltering)
415+
{
416+
const std::array<double, 3> tempErrors{errors_[0], errors_[1], error};
417+
const std::array<double, 3> tempTimeSteps{timeSteps_[0], timeSteps_[1], timeStepJustCompleted};
418+
const double stepFactor = timeStepFactor(tempErrors, tempTimeSteps);
419+
if (rejectCompletedStep_ && stepFactor < maxReductionTimeStep_)
420+
{
421+
acceptTimeStep = false;
422+
}
423+
}
424+
425+
if (acceptTimeStep)
426+
{
427+
// Shift errors and time steps
428+
for( int i = 0; i < 2; ++i )
429+
{
430+
errors_[i] = errors_[i+1];
431+
timeSteps_[i] = timeSteps_[i+1];
432+
}
433+
434+
// Store new error and time step
435+
errors_[2] = error;
436+
timeSteps_[2] = timeStepJustCompleted;
437+
}
438+
439+
return acceptTimeStep;
372440
}
373441

374442
bool General3rdOrderController::operator==(const General3rdOrderController& ctrl) const
@@ -378,6 +446,11 @@ namespace Opm
378446
this->rejectCompletedStep_ == ctrl.rejectCompletedStep_ &&
379447
this->errors_ == ctrl.errors_ &&
380448
this->timeSteps_ == ctrl.timeSteps_ &&
449+
this->beta_ == ctrl.beta_ &&
450+
this->alpha_ == ctrl.alpha_ &&
451+
this->controllerVersion_ == ctrl.controllerVersion_ &&
452+
this->toleranceTestVersion_ == ctrl.toleranceTestVersion_ &&
453+
this->maxReductionTimeStep_ == ctrl.maxReductionTimeStep_ &&
381454
this->verbose_ == ctrl.verbose_;
382455
}
383456

0 commit comments

Comments
 (0)