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