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 "TimeSequenceStepperBase.h" 11 : #include "FEProblem.h" 12 : #include "Transient.h" 13 : 14 : #include <algorithm> 15 : #include <functional> 16 : 17 : InputParameters 18 71995 : TimeSequenceStepperBase::validParams() 19 : { 20 71995 : InputParameters params = TimeStepper::validParams(); 21 215985 : params.addParam<bool>( 22 : "use_last_dt_after_last_t", 23 143990 : false, 24 : "If true, uses the final time step size for times after the last time in the sequence, " 25 : "instead of taking a single step directly to the simulation end time"); 26 143990 : params.addParam<bool>( 27 143990 : "use_last_t_for_end_time", false, "Use last time in sequence as 'end_time' in Executioner."); 28 71995 : return params; 29 0 : } 30 : 31 336 : TimeSequenceStepperBase::TimeSequenceStepperBase(const InputParameters & parameters) 32 : : TimeStepper(parameters), 33 336 : _use_last_dt_after_last_t(getParam<bool>("use_last_dt_after_last_t")), 34 672 : _current_step(declareRestartableData<unsigned int>("current_step", 0)), 35 672 : _time_sequence(declareRestartableData<std::vector<Real>>("time_sequence")), 36 1008 : _set_end_time(getParam<bool>("use_last_t_for_end_time")) 37 : { 38 336 : } 39 : 40 : void 41 336 : TimeSequenceStepperBase::setupSequence(const std::vector<Real> & times) 42 : { 43 : // In case of half transient, transient's end time needs to be reset to 44 : // be able to imprint TimeSequenceStepperBase's end time 45 336 : if (_app.testCheckpointHalfTransient()) 46 14 : _executioner.endTime() = _executioner.endTime() * 2.0 - _executioner.getStartTime(); 47 : 48 : // only set up _time_sequence if the app is _not_ recovering 49 336 : if (!_app.isRecovering()) 50 : { 51 : // also we need to do something different when restarting 52 322 : if (!_app.isRestarting() || _time_sequence.empty()) 53 275 : updateSequence(times); 54 : else 55 : { 56 : // in case of restart it should be allowed to modify _time_sequence if it follows the 57 : // following rule: 58 : // all times up to _current_step are identical 59 : // 1. start time cannot be modified 60 : // 2. the entries in _time_sequence and times must be equal up to entry with index 61 : // _current_step 62 : 63 47 : if (!MooseUtils::absoluteFuzzyEqual(_executioner.getStartTime(), _time_sequence[0])) 64 0 : mooseError("Timesequencestepper does not allow the start time to be modified."); 65 : 66 : // sync _executioner.endTime with _time_sequence 67 47 : Real end_time = _executioner.endTime(); 68 : 69 : // make sure time sequence is in ascending order 70 243 : for (unsigned int j = 0; j < times.size() - 1; ++j) 71 196 : if (times[j + 1] <= times[j]) 72 0 : mooseError("time_sequence must be in ascending order."); 73 : 74 47 : if (times.size() < _current_step + 1) 75 14 : mooseError("The timesequence provided in the restart file must be identical to " 76 : "the one in the old file up to entry number ", 77 0 : _current_step + 1, 78 : " but there are only ", 79 7 : times.size(), 80 : " value(s) provided for the timesequence in the restart input."); 81 : 82 : // save the restarted time_sequence 83 40 : std::vector<Real> saved_time_sequence = _time_sequence; 84 : 85 40 : _time_sequence.clear(); 86 : 87 : // step 1: fill in the entries up to _current_step 88 153 : for (unsigned int j = 0; j <= _current_step; ++j) 89 : { 90 120 : if (!MooseUtils::absoluteFuzzyEqual(times[j], saved_time_sequence[j])) 91 14 : mooseError("The timesequence provided in the restart file must be identical to " 92 : "the one in the old file up to entry number ", 93 0 : _current_step + 1, 94 : " but entry ", 95 7 : j + 1, 96 : " is ", 97 7 : times[j], 98 : " in the restart input but ", 99 7 : saved_time_sequence[j], 100 : " in the restarted input."); 101 : 102 113 : _time_sequence.push_back(saved_time_sequence[j]); 103 : } 104 : 105 : // step 2: fill in the entries up after _current_step 106 121 : for (unsigned int j = _current_step + 1; j < times.size(); ++j) 107 : { 108 88 : if (times[j] < end_time) 109 66 : _time_sequence.push_back(times[j]); 110 : } 111 : 112 33 : if (!_set_end_time) 113 33 : _time_sequence.push_back(end_time); 114 33 : } 115 : } 116 : 117 : // Set end time to last time in sequence if requested 118 314 : if (_set_end_time) 119 : { 120 13 : auto & end_time = _executioner.endTime(); 121 13 : end_time = _time_sequence.back(); 122 : } 123 : 124 314 : if (_app.testCheckpointHalfTransient()) 125 : { 126 14 : unsigned int half = (_time_sequence.size() - 1) / 2; 127 14 : _executioner.endTime() = _time_sequence[half]; 128 : } 129 314 : } 130 : 131 : void 132 563 : TimeSequenceStepperBase::updateSequence(const std::vector<Real> & times) 133 : { 134 563 : Real start_time = _executioner.getStartTime(); 135 563 : Real end_time = _executioner.endTime(); 136 : 137 : // make sure time sequence is in strictly ascending order 138 563 : if (!std::is_sorted(times.begin(), times.end(), std::less_equal<Real>())) 139 16 : paramError("time_sequence", "Time points must be in strictly ascending order."); 140 : 141 555 : _time_sequence.push_back(start_time); 142 3002 : for (unsigned int j = 0; j < times.size(); ++j) 143 : { 144 2447 : if (times[j] > start_time && times[j] < end_time) 145 2038 : _time_sequence.push_back(times[j]); 146 : } 147 : 148 555 : if (!_set_end_time) 149 543 : _time_sequence.push_back(end_time); 150 555 : } 151 : 152 : void 153 288 : TimeSequenceStepperBase::resetSequence() 154 : { 155 288 : _time_sequence.clear(); 156 288 : } 157 : 158 : void 159 1849 : TimeSequenceStepperBase::acceptStep() 160 : { 161 1849 : TimeStepper::acceptStep(); 162 1849 : if (MooseUtils::absoluteFuzzyGreaterEqual(_time, getNextTimeInSequence())) 163 1226 : increaseCurrentStep(); 164 1849 : } 165 : 166 : Real 167 362 : TimeSequenceStepperBase::computeInitialDT() 168 : { 169 362 : return computeDT(); 170 : } 171 : 172 : Real 173 972 : TimeSequenceStepperBase::computeDT() 174 : { 175 972 : if (_use_last_dt_after_last_t) 176 : { 177 : // last *provided* time value index; actual last index corresponds to end time 178 84 : const auto last_t_index = _time_sequence.size() - 2; 179 84 : if (_current_step + 1 > last_t_index) 180 24 : return _time_sequence[last_t_index] - _time_sequence[last_t_index - 1]; 181 : else 182 60 : return _time_sequence[_current_step + 1] - _time_sequence[_current_step]; 183 : } 184 : else 185 888 : return _time_sequence[_current_step + 1] - _time_sequence[_current_step]; 186 : } 187 : 188 : Real 189 9 : TimeSequenceStepperBase::computeFailedDT() 190 : { 191 9 : if (computeDT() <= _dt_min) 192 0 : mooseError("Solve failed and timestep already at or below dtmin, cannot continue!"); 193 : 194 : // cut the time step in a half if possible 195 9 : Real dt = _cutback_factor_at_failure * computeDT(); 196 9 : if (dt < _dt_min) 197 0 : dt = _dt_min; 198 9 : _time_sequence.insert(_time_sequence.begin() + _current_step + 1, 199 9 : _time_sequence[_current_step] + dt); 200 9 : return computeDT(); 201 : }