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