LCOV - code coverage report
Current view: top level - src/timesteppers - CompositionDT.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 134 139 96.4 %
Date: 2025-07-17 01:28:37 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       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             : }

Generated by: LCOV version 1.14