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 71799 : TimeSequenceStepperBase::validParams() 19 : { 20 71799 : InputParameters params = TimeStepper::validParams(); 21 215397 : params.addParam<bool>( 22 : "use_last_dt_after_last_t", 23 143598 : 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 71799 : return params; 27 0 : } 28 : 29 238 : TimeSequenceStepperBase::TimeSequenceStepperBase(const InputParameters & parameters) 30 : : TimeStepper(parameters), 31 238 : _use_last_dt_after_last_t(getParam<bool>("use_last_dt_after_last_t")), 32 238 : _current_step(declareRestartableData<unsigned int>("current_step", 0)), 33 476 : _time_sequence(declareRestartableData<std::vector<Real>>("time_sequence")) 34 : { 35 238 : } 36 : 37 : void 38 262 : TimeSequenceStepperBase::setupSequence(const std::vector<Real> & times) 39 : { 40 : // In case of half transient, transient's end time needs to be reset to 41 : // be able to imprint TimeSequenceStepperBase's end time 42 262 : if (_app.testCheckpointHalfTransient()) 43 11 : _executioner.endTime() = _executioner.endTime() * 2.0 - _executioner.getStartTime(); 44 : 45 : // only set up _time_sequence if the app is _not_ recovering 46 262 : if (!_app.isRecovering()) 47 : { 48 : // also we need to do something different when restarting 49 251 : if (!_app.isRestarting()) 50 : { 51 : // sync _executioner.startTime and endTime with _time_sequence 52 211 : Real start_time = _executioner.getStartTime(); 53 211 : Real end_time = _executioner.endTime(); 54 : 55 : // make sure time sequence is in strictly ascending order 56 211 : if (!std::is_sorted(times.begin(), times.end(), std::less_equal<Real>())) 57 8 : paramError("time_sequence", "Time points must be in strictly ascending order."); 58 : 59 203 : _time_sequence.push_back(start_time); 60 1130 : for (unsigned int j = 0; j < times.size(); ++j) 61 : { 62 927 : if (times[j] > start_time && times[j] < end_time) 63 633 : _time_sequence.push_back(times[j]); 64 : } 65 203 : _time_sequence.push_back(end_time); 66 : } 67 : else 68 : { 69 : // in case of restart it should be allowed to modify _time_sequence if it follows the 70 : // following rule: 71 : // all times up to _current_step are identical 72 : // 1. start time cannot be modified 73 : // 2. the entries in _time_sequence and times must be equal up to entry with index 74 : // _current_step 75 : 76 40 : if (!MooseUtils::absoluteFuzzyEqual(_executioner.getStartTime(), _time_sequence[0])) 77 0 : mooseError("Timesequencestepper does not allow the start time to be modified."); 78 : 79 : // sync _executioner.endTime with _time_sequence 80 40 : Real end_time = _executioner.endTime(); 81 : 82 : // make sure time sequence is in ascending order 83 229 : for (unsigned int j = 0; j < times.size() - 1; ++j) 84 189 : if (times[j + 1] <= times[j]) 85 0 : mooseError("time_sequence must be in ascending order."); 86 : 87 : // save the restarted time_sequence 88 40 : std::vector<Real> saved_time_sequence = _time_sequence; 89 40 : _time_sequence.clear(); 90 : 91 : // step 1: fill in the entries up to _current_step 92 153 : for (unsigned int j = 0; j <= _current_step; ++j) 93 : { 94 120 : if (!MooseUtils::absoluteFuzzyEqual(times[j], saved_time_sequence[j])) 95 14 : mooseError("The timesequence provided in the restart file must be identical to " 96 : "the one in the old file up to entry number ", 97 7 : _current_step + 1, 98 : " = ", 99 7 : saved_time_sequence[_current_step]); 100 : 101 113 : _time_sequence.push_back(saved_time_sequence[j]); 102 : } 103 : 104 : // step 2: fill in the entries up after _current_step 105 121 : for (unsigned int j = _current_step + 1; j < times.size(); ++j) 106 : { 107 88 : if (times[j] < end_time) 108 66 : _time_sequence.push_back(times[j]); 109 : } 110 33 : _time_sequence.push_back(end_time); 111 33 : } 112 : } 113 : 114 247 : if (_app.testCheckpointHalfTransient()) 115 : { 116 11 : unsigned int half = (_time_sequence.size() - 1) / 2; 117 11 : _executioner.endTime() = _time_sequence[half]; 118 : } 119 247 : } 120 : 121 : void 122 1219 : TimeSequenceStepperBase::acceptStep() 123 : { 124 1219 : TimeStepper::acceptStep(); 125 1219 : if (MooseUtils::absoluteFuzzyGreaterEqual(_time, getNextTimeInSequence())) 126 785 : increaseCurrentStep(); 127 1219 : } 128 : 129 : Real 130 292 : TimeSequenceStepperBase::computeInitialDT() 131 : { 132 292 : return computeDT(); 133 : } 134 : 135 : Real 136 735 : TimeSequenceStepperBase::computeDT() 137 : { 138 735 : if (_use_last_dt_after_last_t) 139 : { 140 : // last *provided* time value index; actual last index corresponds to end time 141 84 : const auto last_t_index = _time_sequence.size() - 2; 142 84 : if (_current_step + 1 > last_t_index) 143 24 : return _time_sequence[last_t_index] - _time_sequence[last_t_index - 1]; 144 : else 145 60 : return _time_sequence[_current_step + 1] - _time_sequence[_current_step]; 146 : } 147 : else 148 651 : return _time_sequence[_current_step + 1] - _time_sequence[_current_step]; 149 : } 150 : 151 : Real 152 9 : TimeSequenceStepperBase::computeFailedDT() 153 : { 154 9 : if (computeDT() <= _dt_min) 155 0 : mooseError("Solve failed and timestep already at or below dtmin, cannot continue!"); 156 : 157 : // cut the time step in a half if possible 158 9 : Real dt = _cutback_factor_at_failure * computeDT(); 159 9 : if (dt < _dt_min) 160 0 : dt = _dt_min; 161 9 : _time_sequence.insert(_time_sequence.begin() + _current_step + 1, 162 9 : _time_sequence[_current_step] + dt); 163 9 : return computeDT(); 164 : }