Line data Source code
1 : //* This file is part of the MOOSE framework 2 : //* https://mooseframework.inl.gov 3 : //* 4 : //* All rights reserved, see COPYRIGHT for full restrictions 5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT 6 : //* 7 : //* Licensed under LGPL 2.1, please see LICENSE for details 8 : //* https://www.gnu.org/licenses/lgpl-2.1.html 9 : 10 : #include "TimeStepper.h" 11 : #include "FEProblem.h" 12 : #include "TransientBase.h" 13 : #include "MooseApp.h" 14 : 15 : InputParameters 16 275671 : TimeStepper::validParams() 17 : { 18 275671 : InputParameters params = MooseObject::validParams(); 19 827013 : params.addParam<bool>( 20 551342 : "reset_dt", false, "Use when restarting a calculation to force a change in dt."); 21 827013 : params.addRangeCheckedParam<Real>( 22 : "cutback_factor_at_failure", 23 551342 : 0.5, 24 : "cutback_factor_at_failure>0 & cutback_factor_at_failure<1", 25 : "Factor to apply to timestep if a time step fails to converge."); 26 275671 : params.addParam<bool>("enable", true, "whether or not to enable the time stepper"); 27 275671 : params.declareControllable("enable"); 28 : 29 275671 : params.registerBase("TimeStepper"); 30 275671 : params.registerSystemAttributeName("TimeStepper"); 31 : 32 275671 : return params; 33 0 : } 34 : 35 30856 : TimeStepper::TimeStepper(const InputParameters & parameters) 36 : : MooseObject(parameters), 37 : Restartable(this, "TimeSteppers"), 38 : ScalarCoupleable(this), 39 30856 : _fe_problem(parameters.have_parameter<FEProblemBase *>("_fe_problem_base") 40 61712 : ? *getParam<FEProblemBase *>("_fe_problem_base") 41 30856 : : *getParam<FEProblem *>("_fe_problem")), 42 30856 : _executioner(*getCheckedPointerParam<TransientBase *>("_executioner")), 43 30856 : _time(_fe_problem.time()), 44 30856 : _time_old(_fe_problem.timeOld()), 45 30856 : _t_step(_fe_problem.timeStep()), 46 30856 : _dt(_fe_problem.dt()), 47 30856 : _dt_min(_executioner.dtMin()), 48 30856 : _dt_max(_executioner.dtMax()), 49 30856 : _end_time(_executioner.endTime()), 50 30856 : _sync_times(_app.getOutputWarehouse().getSyncTimes()), 51 30856 : _timestep_tolerance(_executioner.timestepTol()), 52 30856 : _verbose(_executioner.verbose()), 53 30856 : _converged(true), 54 30856 : _cutback_factor_at_failure(getParam<Real>("cutback_factor_at_failure")), 55 30856 : _reset_dt(getParam<bool>("reset_dt")), 56 30856 : _has_reset_dt(false), 57 30856 : _failure_count(0), 58 61712 : _current_dt(declareRestartableData<Real>("current_dt", 1.0)) 59 : { 60 30856 : } 61 : 62 28807 : TimeStepper::~TimeStepper() {} 63 : 64 : void 65 29042 : TimeStepper::init() 66 : { 67 29042 : } 68 : 69 : void 70 30222 : TimeStepper::preExecute() 71 : { 72 : // Delete all sync times that are at or before the begin time 73 30253 : while (!_sync_times.empty() && _time + _timestep_tolerance >= *_sync_times.begin()) 74 31 : _sync_times.erase(_sync_times.begin()); 75 30222 : } 76 : 77 : void 78 237374 : TimeStepper::computeStep() 79 : { 80 237374 : if (_t_step < 2 || (_reset_dt && !_has_reset_dt)) 81 : { 82 56446 : _has_reset_dt = true; 83 : 84 56446 : if (converged()) 85 55542 : _current_dt = computeInitialDT(); 86 : else 87 904 : _current_dt = computeFailedDT(); 88 : } 89 : else 90 : { 91 180928 : if (converged()) 92 177633 : _current_dt = computeDT(); 93 : else 94 3295 : _current_dt = computeFailedDT(); 95 : } 96 237253 : if (_current_dt < -TOLERANCE) 97 4 : mooseError("Negative time step detected :" + std::to_string(_current_dt) + 98 : " Investigate the TimeStepper to resolve this error"); 99 237249 : } 100 : 101 : bool 102 185314 : TimeStepper::constrainStep(Real & dt) 103 : { 104 185314 : bool at_sync_point = false; 105 : 106 185314 : std::ostringstream diag; 107 : 108 : // Don't let the time step size exceed maximum time step size 109 185314 : if (dt > _dt_max) 110 : { 111 216 : dt = _dt_max; 112 216 : diag << "Limiting dt to dtmax: " << std::setw(9) << std::setprecision(6) << std::setfill('0') 113 216 : << std::showpoint << std::left << _dt_max << std::endl; 114 : } 115 : 116 : // Don't allow time step size to be smaller than minimum time step size 117 185314 : if (dt < _dt_min) 118 : { 119 168 : dt = _dt_min; 120 168 : diag << "Increasing dt to dtmin: " << std::setw(9) << std::setprecision(6) << std::setfill('0') 121 168 : << std::showpoint << std::left << _dt_min << std::endl; 122 : } 123 : 124 : // Don't let time go beyond simulation end time (unless we're doing a half transient) 125 185314 : if (_time + dt > _end_time && !_app.testCheckpointHalfTransient()) 126 : { 127 1336 : dt = _end_time - _time; 128 : diag << "Limiting dt for end_time: " << std::setw(9) << std::setprecision(6) 129 1336 : << std::setfill('0') << std::showpoint << std::left << _end_time << " dt: " << std::setw(9) 130 1336 : << std::setprecision(6) << std::setfill('0') << std::showpoint << std::left << dt 131 1336 : << std::endl; 132 : } 133 : 134 : // Adjust to a sync time if supplied 135 185314 : if (!_sync_times.empty() && _time + dt + _timestep_tolerance >= (*_sync_times.begin())) 136 : { 137 315 : dt = *_sync_times.begin() - _time; 138 : diag << "Limiting dt for sync_time: " << std::setw(9) << std::setprecision(6) 139 315 : << std::setfill('0') << std::showpoint << std::left << *_sync_times.begin() 140 315 : << " dt: " << std::setw(9) << std::setprecision(6) << std::setfill('0') << std::showpoint 141 315 : << std::left << dt << std::endl; 142 : 143 315 : if (dt <= 0.0) 144 : { 145 0 : _console << diag.str(); 146 0 : mooseError("Adjusting to sync_time resulted in a non-positive time step. dt: ", 147 : dt, 148 : " sync_time: ", 149 0 : *_sync_times.begin(), 150 : " time: ", 151 0 : _time); 152 : } 153 : 154 315 : at_sync_point = true; 155 : } 156 : 157 185314 : if (_verbose) 158 : { 159 5684 : _console << diag.str(); 160 : } 161 : 162 185314 : return at_sync_point; 163 185314 : } 164 : 165 : void 166 253335 : TimeStepper::step() 167 : { 168 253335 : _converged = _executioner.timeStepSolveObject()->solve(); 169 : 170 253193 : if (!_converged) 171 4227 : _failure_count++; 172 253193 : } 173 : 174 : void 175 249597 : TimeStepper::acceptStep() 176 : { 177 : // If there are sync times at or before the current time, delete them 178 249912 : while (!_sync_times.empty() && _time + _timestep_tolerance >= *_sync_times.begin()) 179 : { 180 315 : _sync_times.erase(_sync_times.begin()); 181 : } 182 249597 : } 183 : 184 : void 185 5304 : TimeStepper::rejectStep() 186 : { 187 5304 : _fe_problem.restoreSolutions(); 188 5304 : } 189 : 190 : unsigned int 191 200 : TimeStepper::numFailures() const 192 : { 193 200 : return _failure_count; 194 : } 195 : 196 : bool 197 491165 : TimeStepper::converged() const 198 : { 199 491165 : return _converged; 200 : } 201 : 202 : Real 203 4106 : TimeStepper::computeFailedDT() 204 : { 205 4106 : if (_dt <= _dt_min) 206 117 : mooseError("Solve failed and timestep already at or below dtmin, cannot continue!"); 207 : 208 : // cut the time step 209 3989 : if (_cutback_factor_at_failure * _dt >= _dt_min) 210 3913 : return _cutback_factor_at_failure * _dt; 211 : else // (_cutback_factor_at_failure * _current_dt < _dt_min) 212 76 : return _dt_min; 213 : } 214 : 215 : void 216 0 : TimeStepper::forceTimeStep(Real dt) 217 : { 218 0 : _current_dt = dt; 219 0 : } 220 : 221 : void 222 0 : TimeStepper::forceNumSteps(const unsigned int num_steps) 223 : { 224 0 : _executioner.forceNumSteps(num_steps); 225 0 : }