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 "CompositionDT.h" 11 : #include "MooseApp.h" 12 : #include "Transient.h" 13 : #include "TimeSequenceStepperBase.h" 14 : #include "IterationAdaptiveDT.h" 15 : #include "FEProblemBase.h" 16 : 17 : #include <limits> 18 : 19 : registerMooseObject("MooseApp", CompositionDT); 20 : 21 : InputParameters 22 71104 : CompositionDT::compositionDTParams() 23 : { 24 71104 : auto params = emptyInputParameters(); 25 : 26 284416 : params.addParam<Real>("initial_dt", "Initial value of dt"); 27 213312 : params.addParam<std::vector<std::string>>( 28 : "lower_bound", 29 : {}, 30 : "The maximum of these TimeSteppers will form the lower bound on the time " 31 : "step size. A single or multiple time steppers may be specified."); 32 : 33 71104 : return params; 34 0 : } 35 : 36 : InputParameters 37 3392 : CompositionDT::validParams() 38 : { 39 3392 : InputParameters params = TimeStepper::validParams(); 40 3392 : params += CompositionDT::compositionDTParams(); 41 : 42 3392 : params.addClassDescription("The time stepper takes all the other time steppers as input and " 43 : "returns the minimum time step size."); 44 : 45 3392 : return params; 46 0 : } 47 : 48 151 : CompositionDT::CompositionDT(const InputParameters & parameters) 49 : : TimeStepper(parameters), 50 151 : _has_initial_dt(isParamValid("initial_dt")), 51 151 : _initial_dt(_has_initial_dt ? getParam<Real>("initial_dt") : 0.), 52 302 : _lower_bound(getParam<std::vector<std::string>>("lower_bound").begin(), 53 453 : getParam<std::vector<std::string>>("lower_bound").end()), 54 151 : _current_time_stepper(nullptr), 55 151 : _largest_bound_time_stepper(nullptr), 56 151 : _closest_time_sequence_stepper(nullptr) 57 : { 58 : // Make sure the steppers in "lower_bound" exist 59 151 : const auto time_steppers = getTimeSteppers(); 60 163 : for (const auto & time_stepper_name : _lower_bound) 61 15 : if (std::find_if(time_steppers.begin(), 62 : time_steppers.end(), 63 45 : [&time_stepper_name](const auto & ts) 64 78 : { return ts->name() == time_stepper_name; }) == time_steppers.end() && 65 3 : _lower_bound.size() != 0) 66 6 : paramError( 67 : "lower_bound", "Failed to find a timestepper with the name '", time_stepper_name, "'"); 68 148 : } 69 : 70 : template <typename Lambda> 71 : void 72 5919 : CompositionDT::actOnTimeSteppers(Lambda && act) 73 : { 74 27839 : for (auto & ts : getTimeSteppers()) 75 21923 : act(*ts); 76 5916 : } 77 : 78 : void 79 148 : CompositionDT::init() 80 : { 81 148 : if (_app.testCheckpointHalfTransient()) 82 : { 83 10 : const auto half_end_time = _executioner.endTime(); 84 10 : actOnTimeSteppers( 85 10 : [this, half_end_time](auto & ts) 86 : { 87 38 : _executioner.endTime() = half_end_time; 88 38 : ts.init(); 89 38 : }); 90 10 : _executioner.endTime() = half_end_time; 91 : } 92 : else 93 606 : actOnTimeSteppers([](auto & ts) { ts.init(); }); 94 148 : } 95 : 96 : void 97 148 : CompositionDT::preExecute() 98 : { 99 654 : actOnTimeSteppers([](auto & ts) { ts.preExecute(); }); 100 148 : } 101 : 102 : void 103 1108 : CompositionDT::preSolve() 104 : { 105 5222 : actOnTimeSteppers([](auto & ts) { ts.preSolve(); }); 106 1108 : } 107 : 108 : void 109 1046 : CompositionDT::postSolve() 110 : { 111 5022 : actOnTimeSteppers([](auto & ts) { ts.postSolve(); }); 112 1046 : } 113 : 114 : void 115 142 : CompositionDT::postExecute() 116 : { 117 636 : actOnTimeSteppers([](auto & ts) { ts.postExecute(); }); 118 142 : } 119 : 120 : void 121 1111 : CompositionDT::preStep() 122 : { 123 5225 : actOnTimeSteppers([](auto & ts) { ts.preStep(); }); 124 1111 : } 125 : 126 : void 127 1108 : CompositionDT::postStep() 128 : { 129 5216 : actOnTimeSteppers([](auto & ts) { ts.postStep(); }); 130 1108 : } 131 : 132 : bool 133 1103 : CompositionDT::constrainStep(Real & dt) 134 : { 135 1103 : bool at_sync_point = TimeStepper::constrainStep(dt); 136 1103 : const auto time_steppers = getTimeSteppers(); 137 5199 : for (auto & ts : time_steppers) 138 4096 : if (ts->constrainStep(dt)) 139 0 : return true; 140 1103 : return at_sync_point; 141 1103 : } 142 : 143 : Real 144 276 : CompositionDT::computeInitialDT() 145 : { 146 276 : return _has_initial_dt ? _initial_dt : computeDT(); 147 : } 148 : 149 : Real 150 1190 : CompositionDT::computeDT() 151 : { 152 1190 : const auto time_steppers = getTimeSteppers(); 153 : // Note : compositionDT requires other active time steppers as input so no active time steppers 154 : // or only compositionDT is active is not allowed 155 1190 : if (time_steppers.size() < 1) 156 3 : mooseError("No TimeStepper(s) are currently active to compute a timestep"); 157 : 158 1187 : std::set<std::pair<Real, TimeStepper *>, CompareFirst> dts, bound_dt; 159 : 160 5643 : for (auto & ts : time_steppers) 161 4456 : if (!dynamic_cast<TimeSequenceStepperBase *>(ts)) 162 : { 163 2993 : ts->computeStep(); 164 2993 : const auto dt = ts->getCurrentDT(); 165 : 166 2993 : if (_lower_bound.count(ts->name())) 167 77 : bound_dt.emplace(dt, ts); 168 : else 169 2916 : dts.emplace(dt, ts); 170 : } 171 : 172 1187 : _current_time_stepper = dts.size() ? dts.begin()->second : nullptr; 173 1187 : _largest_bound_time_stepper = bound_dt.size() ? (--bound_dt.end())->second : nullptr; 174 : 175 1187 : _dt = produceCompositionDT(dts, bound_dt); 176 : 177 1187 : return _dt; 178 1187 : } 179 : 180 : Real 181 1187 : CompositionDT::getSequenceSteppersNextTime() 182 : { 183 1187 : const auto time_steppers = getTimeSteppers(); 184 : 185 1187 : std::vector<TimeSequenceStepperBase *> time_sequence_steppers; 186 5643 : for (auto & ts : time_steppers) 187 4456 : if (auto tss = dynamic_cast<TimeSequenceStepperBase *>(ts)) 188 1463 : time_sequence_steppers.push_back(tss); 189 : 190 1187 : if (time_sequence_steppers.empty()) 191 348 : return 0; 192 : 193 839 : Real next_time_to_hit = std::numeric_limits<Real>::max(); 194 2302 : for (auto & tss : time_sequence_steppers) 195 : { 196 : Real ts_time_to_hit; 197 1463 : if (!tss->advanceToFutureTime(_time, _dt_min, ts_time_to_hit)) 198 0 : continue; 199 : 200 1463 : if (next_time_to_hit > ts_time_to_hit) 201 : { 202 1055 : _closest_time_sequence_stepper = tss; 203 1055 : next_time_to_hit = ts_time_to_hit; 204 : } 205 : } 206 839 : return next_time_to_hit; 207 1187 : } 208 : 209 : Real 210 1187 : CompositionDT::produceCompositionDT( 211 : std::set<std::pair<Real, TimeStepper *>, CompareFirst> & dts, 212 : std::set<std::pair<Real, TimeStepper *>, CompareFirst> & bound_dts) 213 : { 214 : Real minDT, lower_bound, dt; 215 1187 : minDT = lower_bound = dt = 0.0; 216 1187 : if (!dts.empty()) 217 1187 : minDT = dts.begin()->first; 218 1187 : if (!bound_dts.empty()) 219 77 : lower_bound = bound_dts.rbegin()->first; 220 : 221 1187 : if (minDT > lower_bound) 222 1165 : dt = minDT; 223 : else 224 : { 225 22 : dt = lower_bound; 226 22 : _current_time_stepper = _largest_bound_time_stepper; 227 : } 228 : 229 1187 : auto ts = getSequenceSteppersNextTime(); 230 : 231 1187 : if (ts != 0 && (ts - _time) < dt) 232 : { 233 450 : _current_time_stepper = _closest_time_sequence_stepper; 234 450 : return std::min((ts - _time), dt); 235 : } 236 : else 237 737 : return dt; 238 : } 239 : 240 : std::vector<TimeStepper *> 241 9550 : CompositionDT::getTimeSteppers() 242 : { 243 9550 : std::vector<TimeStepper *> time_steppers; 244 9550 : _fe_problem.theWarehouse() 245 19100 : .query() 246 9550 : .condition<AttribSystem>("TimeStepper") 247 9550 : .queryInto(time_steppers); 248 : 249 : // Remove CompositionDT from time_steppers vector to avoid recursive call 250 9550 : time_steppers.erase(std::remove(time_steppers.begin(), time_steppers.end(), this), 251 9550 : time_steppers.end()); 252 9550 : return time_steppers; 253 0 : } 254 : 255 : void 256 1108 : CompositionDT::step() 257 : { 258 1108 : if (_current_time_stepper) 259 : { 260 1108 : _current_time_stepper->step(); 261 1108 : if (!converged()) 262 57 : _failure_count++; 263 : } 264 : else 265 0 : TimeStepper::step(); 266 1108 : } 267 : 268 : void 269 1046 : CompositionDT::acceptStep() 270 : { 271 5022 : actOnTimeSteppers([](auto & ts) { ts.acceptStep(); }); 272 1046 : } 273 : 274 : void 275 62 : CompositionDT::rejectStep() 276 : { 277 191 : actOnTimeSteppers([](auto & ts) { ts.rejectStep(); }); 278 59 : } 279 : 280 : bool 281 3460 : CompositionDT::converged() const 282 : { 283 3460 : return _current_time_stepper ? _current_time_stepper->converged() : TimeStepper::converged(); 284 : }