LCOV - code coverage report
Current view: top level - src/timesteppers - CompositionDT.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 419b9d Lines: 134 139 96.4 %
Date: 2025-08-08 20:01:16 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       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             : }

Generated by: LCOV version 1.14