LCOV - code coverage report
Current view: top level - src/timesteppers - CompositionDT.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 329044 Lines: 139 145 95.9 %
Date: 2026-08-03 21:12:22 Functions: 41 41 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       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             : }

Generated by: LCOV version 1.14