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 71761 : TimeSequenceStepperBase::validParams() 19 : { 20 71761 : InputParameters params = TimeStepper::validParams(); 21 215283 : params.addParam<bool>( 22 : "use_last_dt_after_last_t", 23 143522 : 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 71761 : return params; 27 0 : } 28 : 29 219 : TimeSequenceStepperBase::TimeSequenceStepperBase(const InputParameters & parameters) 30 : : TimeStepper(parameters), 31 219 : _use_last_dt_after_last_t(getParam<bool>("use_last_dt_after_last_t")), 32 219 : _current_step(declareRestartableData<unsigned int>("current_step", 0)), 33 438 : _time_sequence(declareRestartableData<std::vector<Real>>("time_sequence")) 34 : { 35 219 : } 36 : 37 : void 38 241 : 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 241 : 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 241 : if (!_app.isRecovering()) 47 : { 48 : // also we need to do something different when restarting 49 230 : if (!_app.isRestarting()) 50 : { 51 : // sync _executioner.startTime and endTime with _time_sequence 52 193 : Real start_time = _executioner.getStartTime(); 53 193 : Real end_time = _executioner.endTime(); 54 : 55 : // make sure time sequence is in strictly ascending order 56 193 : 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 185 : _time_sequence.push_back(start_time); 60 1030 : for (unsigned int j = 0; j < times.size(); ++j) 61 : { 62 845 : if (times[j] > start_time && times[j] < end_time) 63 577 : _time_sequence.push_back(times[j]); 64 : } 65 185 : _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 37 : 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 37 : Real end_time = _executioner.endTime(); 81 : 82 : // make sure time sequence is in ascending order 83 212 : for (unsigned int j = 0; j < times.size() - 1; ++j) 84 175 : if (times[j + 1] <= times[j]) 85 0 : mooseError("time_sequence must be in ascending order."); 86 : 87 : // save the restarted time_sequence 88 37 : std::vector<Real> saved_time_sequence = _time_sequence; 89 37 : _time_sequence.clear(); 90 : 91 : // step 1: fill in the entries up to _current_step 92 141 : for (unsigned int j = 0; j <= _current_step; ++j) 93 : { 94 111 : 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 104 : _time_sequence.push_back(saved_time_sequence[j]); 102 : } 103 : 104 : // step 2: fill in the entries up after _current_step 105 110 : for (unsigned int j = _current_step + 1; j < times.size(); ++j) 106 : { 107 80 : if (times[j] < end_time) 108 60 : _time_sequence.push_back(times[j]); 109 : } 110 30 : _time_sequence.push_back(end_time); 111 30 : } 112 : } 113 : 114 226 : if (_app.testCheckpointHalfTransient()) 115 : { 116 11 : unsigned int half = (_time_sequence.size() - 1) / 2; 117 11 : _executioner.endTime() = _time_sequence[half]; 118 : } 119 226 : } 120 : 121 : void 122 634 : TimeSequenceStepperBase::step() 123 : { 124 634 : TimeStepper::step(); 125 634 : if (converged() && !_executioner.fixedPointSolve().XFEMRepeatStep()) 126 634 : _current_step++; 127 634 : } 128 : 129 : Real 130 266 : TimeSequenceStepperBase::computeInitialDT() 131 : { 132 266 : return computeDT(); 133 : } 134 : 135 : Real 136 669 : TimeSequenceStepperBase::computeDT() 137 : { 138 669 : if (_use_last_dt_after_last_t) 139 : { 140 : // last *provided* time value index; actual last index corresponds to end time 141 77 : const auto last_t_index = _time_sequence.size() - 2; 142 77 : if (_current_step + 1 > last_t_index) 143 22 : return _time_sequence[last_t_index] - _time_sequence[last_t_index - 1]; 144 : else 145 55 : return _time_sequence[_current_step + 1] - _time_sequence[_current_step]; 146 : } 147 : else 148 592 : return _time_sequence[_current_step + 1] - _time_sequence[_current_step]; 149 : } 150 : 151 : Real 152 8 : TimeSequenceStepperBase::computeFailedDT() 153 : { 154 8 : 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 8 : Real dt = _cutback_factor_at_failure * computeDT(); 159 8 : if (dt < _dt_min) 160 0 : dt = _dt_min; 161 8 : _time_sequence.insert(_time_sequence.begin() + _current_step + 1, 162 8 : _time_sequence[_current_step] + dt); 163 8 : return computeDT(); 164 : }