LCOV - code coverage report
Current view: top level - src/timesteppers - CompositionDT.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 909fe5 Lines: 134 139 96.4 %
Date: 2025-08-29 20:01:24 Functions: 39 39 100.0 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.14