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 16005 : TimeSequenceStepperBase::validParams() 19 : { 20 16005 : InputParameters params = TimeStepper::validParams(); 21 48015 : params.addParam<bool>( 22 : "use_last_dt_after_last_t", 23 32010 : 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 32010 : params.addParam<bool>( 27 32010 : "use_last_t_for_end_time", false, "Use last time in sequence as 'end_time' in Executioner."); 28 16005 : return params; 29 0 : } 30 : 31 352 : TimeSequenceStepperBase::TimeSequenceStepperBase(const InputParameters & parameters) 32 : : TimeStepper(parameters), 33 352 : _use_last_dt_after_last_t(getParam<bool>("use_last_dt_after_last_t")), 34 704 : _current_step(declareRestartableData<unsigned int>("current_step", 0)), 35 704 : _time_sequence(declareRestartableData<std::vector<Real>>("time_sequence")), 36 1056 : _set_end_time(getParam<bool>("use_last_t_for_end_time")) 37 : { 38 352 : } 39 : 40 : void 41 352 : 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 352 : if (_app.testCheckpointHalfTransient()) 46 17 : _executioner.endTime() = _executioner.endTime() * 2.0 - _executioner.getStartTime(); 47 : 48 : // only set up _time_sequence if the app is _not_ recovering 49 352 : if (!_app.isRecovering()) 50 : { 51 : // also we need to do something different when restarting 52 335 : if (!_app.isRestarting() || _time_sequence.empty()) 53 299 : 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 36 : 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 36 : Real end_time = _executioner.endTime(); 68 : 69 : // make sure time sequence is in ascending order 70 194 : for (unsigned int j = 0; j < times.size() - 1; ++j) 71 158 : if (times[j + 1] <= times[j]) 72 0 : mooseError("time_sequence must be in ascending order."); 73 : 74 36 : if (times.size() < _current_step + 1) 75 6 : 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 3 : times.size(), 80 : " value(s) provided for the timesequence in the restart input."); 81 : 82 : // save the restarted time_sequence 83 33 : std::vector<Real> saved_time_sequence = _time_sequence; 84 : 85 33 : _time_sequence.clear(); 86 : 87 : // step 1: fill in the entries up to _current_step 88 129 : for (unsigned int j = 0; j <= _current_step; ++j) 89 : { 90 99 : if (!MooseUtils::absoluteFuzzyEqual(times[j], saved_time_sequence[j])) 91 6 : 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 3 : j + 1, 96 : " is ", 97 3 : times[j], 98 : " in the restart input but ", 99 3 : saved_time_sequence[j], 100 : " in the restarted input."); 101 : 102 96 : _time_sequence.push_back(saved_time_sequence[j]); 103 : } 104 : 105 : // step 2: fill in the entries up after _current_step 106 110 : for (unsigned int j = _current_step + 1; j < times.size(); ++j) 107 : { 108 80 : if (times[j] < end_time) 109 60 : _time_sequence.push_back(times[j]); 110 : } 111 : 112 30 : if (!_set_end_time) 113 30 : _time_sequence.push_back(end_time); 114 30 : } 115 : } 116 : 117 : // Set end time to last time in sequence if requested 118 340 : if (_set_end_time) 119 : { 120 24 : auto & end_time = _executioner.endTime(); 121 24 : end_time = _time_sequence.back(); 122 : } 123 : 124 340 : if (_app.testCheckpointHalfTransient()) 125 : { 126 17 : unsigned int half = (_time_sequence.size() - 1) / 2; 127 17 : _executioner.endTime() = _time_sequence[half]; 128 : } 129 340 : } 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 12 : paramError("time_sequence", "Time points must be in strictly ascending order."); 140 : 141 557 : _time_sequence.push_back(start_time); 142 3026 : for (unsigned int j = 0; j < times.size(); ++j) 143 : { 144 2469 : if (times[j] > start_time && times[j] <= end_time) 145 2208 : _time_sequence.push_back(times[j]); 146 : } 147 : 148 557 : if (!_set_end_time) 149 535 : _time_sequence.push_back(end_time); 150 557 : } 151 : 152 : void 153 264 : TimeSequenceStepperBase::resetSequence() 154 : { 155 264 : _time_sequence.clear(); 156 264 : } 157 : 158 : void 159 2008 : TimeSequenceStepperBase::acceptStep() 160 : { 161 2008 : TimeStepper::acceptStep(); 162 2008 : if (MooseUtils::absoluteFuzzyGreaterEqual(_time, getNextTimeInSequence())) 163 1289 : increaseCurrentStep(); 164 2008 : } 165 : 166 : Real 167 384 : TimeSequenceStepperBase::computeInitialDT() 168 : { 169 384 : return computeDT(); 170 : } 171 : 172 : Real 173 979 : TimeSequenceStepperBase::computeDT() 174 : { 175 979 : if (_use_last_dt_after_last_t) 176 : { 177 : // last *provided* time value index; actual last index corresponds to end time 178 77 : const auto last_t_index = _time_sequence.size() - 2; 179 77 : if (_current_step + 1 > last_t_index) 180 22 : return _time_sequence[last_t_index] - _time_sequence[last_t_index - 1]; 181 : else 182 55 : return _time_sequence[_current_step + 1] - _time_sequence[_current_step]; 183 : } 184 : else 185 902 : return _time_sequence[_current_step + 1] - _time_sequence[_current_step]; 186 : } 187 : 188 : Real 189 5 : TimeSequenceStepperBase::computeFailedDT() 190 : { 191 5 : 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 5 : Real dt = _cutback_factor_at_failure * computeDT(); 196 5 : if (dt < _dt_min) 197 0 : dt = _dt_min; 198 5 : _time_sequence.insert(_time_sequence.begin() + _current_step + 1, 199 5 : _time_sequence[_current_step] + dt); 200 5 : return computeDT(); 201 : }