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