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 82517 : CompositionDT::compositionDTParams() 23 : { 24 82517 : auto params = emptyInputParameters(); 25 : 26 330068 : params.addParam<Real>("initial_dt", "Initial value of dt"); 27 247551 : 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 82517 : return params; 34 0 : } 35 : 36 : InputParameters 37 14553 : CompositionDT::validParams() 38 : { 39 14553 : InputParameters params = TimeStepper::validParams(); 40 14553 : params += CompositionDT::compositionDTParams(); 41 : 42 14553 : params.addClassDescription("The time stepper takes all the other time steppers as input and " 43 : "returns the minimum time step size."); 44 : 45 14553 : return params; 46 0 : } 47 : 48 146 : CompositionDT::CompositionDT(const InputParameters & parameters) 49 : : TimeStepper(parameters), 50 146 : _has_initial_dt(isParamValid("initial_dt")), 51 146 : _initial_dt(_has_initial_dt ? getParam<Real>("initial_dt") : 0.), 52 292 : _lower_bound(getParam<std::vector<std::string>>("lower_bound").begin(), 53 438 : getParam<std::vector<std::string>>("lower_bound").end()), 54 146 : _current_time_stepper(nullptr), 55 146 : _largest_bound_time_stepper(nullptr), 56 146 : _closest_time_sequence_stepper(nullptr) 57 : { 58 : // Make sure the steppers in "lower_bound" exist 59 146 : const auto time_steppers = getTimeSteppers(); 60 159 : for (const auto & time_stepper_name : _lower_bound) 61 17 : if (std::find_if(time_steppers.begin(), 62 : time_steppers.end(), 63 51 : [&time_stepper_name](const auto & ts) 64 89 : { return ts->name() == time_stepper_name; }) == time_steppers.end() && 65 4 : _lower_bound.size() != 0) 66 8 : paramError( 67 : "lower_bound", "Failed to find a timestepper with the name '", time_stepper_name, "'"); 68 142 : } 69 : 70 : template <typename Lambda> 71 : void 72 5643 : CompositionDT::actOnTimeSteppers(Lambda && act) 73 : { 74 24744 : for (auto & ts : getTimeSteppers()) 75 19105 : act(*ts); 76 5639 : } 77 : 78 : void 79 142 : CompositionDT::init() 80 : { 81 582 : actOnTimeSteppers([](auto & ts) { ts.init(); }); 82 142 : } 83 : 84 : void 85 142 : CompositionDT::preExecute() 86 : { 87 582 : actOnTimeSteppers([](auto & ts) { ts.preExecute(); }); 88 142 : } 89 : 90 : void 91 1058 : CompositionDT::preSolve() 92 : { 93 4653 : actOnTimeSteppers([](auto & ts) { ts.preSolve(); }); 94 1058 : } 95 : 96 : void 97 989 : CompositionDT::postSolve() 98 : { 99 4430 : actOnTimeSteppers([](auto & ts) { ts.postSolve(); }); 100 989 : } 101 : 102 : void 103 134 : CompositionDT::postExecute() 104 : { 105 558 : actOnTimeSteppers([](auto & ts) { ts.postExecute(); }); 106 134 : } 107 : 108 : void 109 1062 : CompositionDT::preStep() 110 : { 111 4657 : actOnTimeSteppers([](auto & ts) { ts.preStep(); }); 112 1062 : } 113 : 114 : void 115 1058 : CompositionDT::postStep() 116 : { 117 4645 : actOnTimeSteppers([](auto & ts) { ts.postStep(); }); 118 1058 : } 119 : 120 : bool 121 1053 : CompositionDT::constrainStep(Real & dt) 122 : { 123 1053 : bool at_sync_point = TimeStepper::constrainStep(dt); 124 1053 : const auto time_steppers = getTimeSteppers(); 125 4630 : for (auto & ts : time_steppers) 126 3577 : if (ts->constrainStep(dt)) 127 0 : return true; 128 1053 : return at_sync_point; 129 1053 : } 130 : 131 : Real 132 272 : CompositionDT::computeInitialDT() 133 : { 134 272 : return _has_initial_dt ? _initial_dt : computeDT(); 135 : } 136 : 137 : Real 138 1133 : CompositionDT::computeDT() 139 : { 140 1133 : const auto time_steppers = getTimeSteppers(); 141 : // Note : compositionDT requires other active time steppers as input so no active time steppers 142 : // or only compositionDT is active is not allowed 143 1133 : if (time_steppers.size() < 1) 144 4 : mooseError("No TimeStepper(s) are currently active to compute a timestep"); 145 : 146 1129 : std::set<std::pair<Real, TimeStepper *>, CompareFirst> dts, bound_dt; 147 : 148 5010 : for (auto & ts : time_steppers) 149 3881 : if (!dynamic_cast<TimeSequenceStepperBase *>(ts)) 150 : { 151 2677 : ts->computeStep(); 152 2677 : const auto dt = ts->getCurrentDT(); 153 : 154 2677 : if (_lower_bound.count(ts->name())) 155 84 : bound_dt.emplace(dt, ts); 156 : else 157 2593 : dts.emplace(dt, ts); 158 : } 159 : 160 1129 : _current_time_stepper = dts.size() ? dts.begin()->second : nullptr; 161 1129 : _largest_bound_time_stepper = bound_dt.size() ? (--bound_dt.end())->second : nullptr; 162 : 163 1129 : _dt = produceCompositionDT(dts, bound_dt); 164 : 165 1129 : return _dt; 166 1129 : } 167 : 168 : Real 169 1129 : CompositionDT::getSequenceSteppersNextTime() 170 : { 171 1129 : const auto time_steppers = getTimeSteppers(); 172 : 173 1129 : std::vector<TimeSequenceStepperBase *> time_sequence_steppers; 174 5010 : for (auto & ts : time_steppers) 175 3881 : if (auto tss = dynamic_cast<TimeSequenceStepperBase *>(ts)) 176 1204 : time_sequence_steppers.push_back(tss); 177 : 178 1129 : if (time_sequence_steppers.empty()) 179 393 : return 0; 180 : 181 736 : Real next_time_to_hit = std::numeric_limits<Real>::max(); 182 1940 : for (auto & tss : time_sequence_steppers) 183 : { 184 1204 : Real ts_time_to_hit = tss->getNextTimeInSequence(); 185 : 186 1204 : if (ts_time_to_hit - _time <= _dt_min) 187 : { 188 108 : tss->increaseCurrentStep(); 189 108 : ts_time_to_hit = tss->getNextTimeInSequence(); 190 : } 191 1204 : if (next_time_to_hit > ts_time_to_hit) 192 : { 193 898 : _closest_time_sequence_stepper = tss; 194 898 : next_time_to_hit = ts_time_to_hit; 195 : } 196 : } 197 736 : return next_time_to_hit; 198 1129 : } 199 : 200 : Real 201 1129 : CompositionDT::produceCompositionDT( 202 : std::set<std::pair<Real, TimeStepper *>, CompareFirst> & dts, 203 : std::set<std::pair<Real, TimeStepper *>, CompareFirst> & bound_dts) 204 : { 205 : Real minDT, lower_bound, dt; 206 1129 : minDT = lower_bound = dt = 0.0; 207 1129 : if (!dts.empty()) 208 1129 : minDT = dts.begin()->first; 209 1129 : if (!bound_dts.empty()) 210 84 : lower_bound = bound_dts.rbegin()->first; 211 : 212 1129 : if (minDT > lower_bound) 213 1105 : dt = minDT; 214 : else 215 : { 216 24 : dt = lower_bound; 217 24 : _current_time_stepper = _largest_bound_time_stepper; 218 : } 219 : 220 1129 : auto ts = getSequenceSteppersNextTime(); 221 : 222 1129 : if (ts != 0 && (ts - _time) < dt) 223 : { 224 401 : _current_time_stepper = _closest_time_sequence_stepper; 225 401 : return std::min((ts - _time), dt); 226 : } 227 : else 228 728 : return dt; 229 : } 230 : 231 : std::vector<TimeStepper *> 232 9104 : CompositionDT::getTimeSteppers() 233 : { 234 9104 : std::vector<TimeStepper *> time_steppers; 235 9104 : _fe_problem.theWarehouse() 236 18208 : .query() 237 9104 : .condition<AttribSystem>("TimeStepper") 238 9104 : .queryInto(time_steppers); 239 : 240 : // Remove CompositionDT from time_steppers vector to avoid recursive call 241 9104 : time_steppers.erase(std::remove(time_steppers.begin(), time_steppers.end(), this), 242 9104 : time_steppers.end()); 243 9104 : return time_steppers; 244 0 : } 245 : 246 : void 247 1058 : CompositionDT::step() 248 : { 249 1058 : if (_current_time_stepper) 250 : { 251 1058 : _current_time_stepper->step(); 252 1058 : if (!converged()) 253 64 : _failure_count++; 254 : } 255 : else 256 0 : TimeStepper::step(); 257 1058 : } 258 : 259 : void 260 989 : CompositionDT::acceptStep() 261 : { 262 4430 : actOnTimeSteppers([](auto & ts) { ts.acceptStep(); }); 263 989 : } 264 : 265 : void 266 69 : CompositionDT::rejectStep() 267 : { 268 211 : actOnTimeSteppers([](auto & ts) { ts.rejectStep(); }); 269 65 : } 270 : 271 : bool 272 3309 : CompositionDT::converged() const 273 : { 274 3309 : return _current_time_stepper ? _current_time_stepper->converged() : TimeStepper::converged(); 275 : }