LCOV - code coverage report
Current view: top level - src/timesteppers - TimeSequenceStepperBase.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 329044 Lines: 93 107 86.9 %
Date: 2026-08-03 21:12:22 Functions: 14 16 87.5 %
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 "TimeSequenceStepperBase.h"
      11             : #include "FEProblem.h"
      12             : #include "Transient.h"
      13             : 
      14             : #include <algorithm>
      15             : #include <functional>
      16             : 
      17             : InputParameters
      18       16245 : TimeSequenceStepperBase::validParams()
      19             : {
      20       16245 :   InputParameters params = TimeStepper::validParams();
      21       48735 :   params.addParam<bool>(
      22             :       "use_last_dt_after_last_t",
      23       32490 :       false,
      24             :       "If true, uses the final time step size for times after the last time in the sequence, "
      25             :       "instead of taking a single step directly to the simulation end time");
      26       32490 :   params.addParam<bool>(
      27       32490 :       "use_last_t_for_end_time", false, "Use last time in sequence as 'end_time' in Executioner.");
      28       16245 :   return params;
      29           0 : }
      30             : 
      31         394 : TimeSequenceStepperBase::TimeSequenceStepperBase(const InputParameters & parameters)
      32             :   : TimeStepper(parameters),
      33         394 :     _use_last_dt_after_last_t(getParam<bool>("use_last_dt_after_last_t")),
      34         788 :     _current_step(declareRestartableData<unsigned int>("current_step", 0)),
      35         788 :     _time_sequence(declareRestartableData<std::vector<Real>>("time_sequence")),
      36        1182 :     _set_end_time(getParam<bool>("use_last_t_for_end_time"))
      37             : {
      38         394 : }
      39             : 
      40             : void
      41         394 : TimeSequenceStepperBase::setupSequence(const std::vector<Real> & times)
      42             : {
      43             :   // In case of half transient, transient's end time needs to be reset to
      44             :   // be able to imprint TimeSequenceStepperBase's end time
      45         394 :   if (_app.testCheckpointHalfTransient())
      46          27 :     _executioner.endTime() = _executioner.endTime() * 2.0 - _executioner.getStartTime();
      47             : 
      48             :   // When restarting or recovering, we reload _time_sequence as restartable data
      49         394 :   if (_time_sequence.empty() || (!_app.isRestarting() && !_app.isRecovering()))
      50         331 :     updateSequence(times);
      51          63 :   else if (_app.isRecovering())
      52             :     mooseAssert(_current_step < _time_sequence.size() &&
      53             :                     _time_sequence[_current_step] - _time <= _timestep_tolerance &&
      54             :                     (_current_step + 1 == _time_sequence.size() ||
      55             :                      _time_sequence[_current_step + 1] - _time > _timestep_tolerance),
      56             :                 "The recovered current step must identify the last reached sequence time");
      57             :   else
      58             :   {
      59          36 :     if (!MooseUtils::absoluteFuzzyEqual(_executioner.getStartTime(), _time_sequence[0]))
      60           0 :       mooseError("Timesequencestepper does not allow the start time to be modified.");
      61             : 
      62          36 :     auto current_input_sequence = buildSequence(times);
      63             :     // Count the leading sequence entries already reached at the current time. Entries no greater
      64             :     // than _time + _timestep_tolerance are complete, so this count is also the index of the first
      65             :     // future entry, or sequence.size() if every entry is complete.
      66          72 :     const auto completed_prefix_size = [this](const auto & sequence)
      67             :     {
      68          72 :       return std::distance(sequence.begin(),
      69             :                            std::find_if(sequence.begin(),
      70             :                                         sequence.end(),
      71         268 :                                         [this](const auto sequence_time)
      72         340 :                                         { return sequence_time - _time > _timestep_tolerance; }));
      73          36 :     };
      74             : 
      75          36 :     const auto saved_prefix_size = completed_prefix_size(_time_sequence);
      76          36 :     const auto current_prefix_size = completed_prefix_size(current_input_sequence);
      77          36 :     if (current_prefix_size != saved_prefix_size)
      78           6 :       mooseError("The timesequence provided in the restart file must be identical to "
      79             :                  "the one in the old file through the restart time, but it contains ",
      80             :                  current_prefix_size,
      81             :                  " completed value(s) instead of ",
      82             :                  saved_prefix_size,
      83             :                  ".");
      84             : 
      85         110 :     for (const auto j : make_range(saved_prefix_size))
      86          80 :       if (!MooseUtils::absoluteFuzzyEqual(current_input_sequence[j], _time_sequence[j]))
      87           0 :         mooseError("The timesequence provided in the restart file must be identical to "
      88             :                    "the one in the old file through the restart time, but entry ",
      89           0 :                    j + 1,
      90             :                    " is ",
      91           0 :                    current_input_sequence[j],
      92             :                    " in the restart input and ",
      93           0 :                    _time_sequence[j],
      94             :                    " in the restarted input.");
      95             : 
      96          30 :     _time_sequence = std::move(current_input_sequence);
      97          30 :     synchronizeCurrentStep(_time, _timestep_tolerance);
      98          30 :   }
      99             : 
     100             :   // Set end time to last time in sequence if requested
     101         382 :   if (_set_end_time)
     102             :   {
     103          24 :     auto & end_time = _executioner.endTime();
     104          24 :     end_time = _time_sequence.back();
     105             :   }
     106             : 
     107         382 :   if (_app.testCheckpointHalfTransient())
     108             :   {
     109          27 :     unsigned int half = (_time_sequence.size() - 1) / 2;
     110          27 :     _executioner.endTime() = _time_sequence[half];
     111             :   }
     112         382 : }
     113             : 
     114             : std::vector<Real>
     115         609 : TimeSequenceStepperBase::buildSequence(const std::vector<Real> & times) const
     116             : {
     117         609 :   const Real start_time = _executioner.getStartTime();
     118         609 :   const Real end_time = _executioner.endTime();
     119             : 
     120             :   // make sure time sequence is in strictly ascending order
     121         609 :   if (!std::is_sorted(times.begin(), times.end(), std::less_equal<Real>()))
     122          12 :     paramError("time_sequence", "Time points must be in strictly ascending order.");
     123             : 
     124        1206 :   std::vector<Real> sequence{start_time};
     125        3338 :   for (const auto time : times)
     126        2735 :     if (time > start_time && time <= end_time)
     127        2417 :       sequence.push_back(time);
     128             : 
     129             :   // Always append end_time as a sentinel, even when it duplicates the last supplied time.
     130         603 :   if (!_set_end_time)
     131         581 :     sequence.push_back(end_time);
     132             : 
     133        1206 :   return sequence;
     134           0 : }
     135             : 
     136             : void
     137         573 : TimeSequenceStepperBase::updateSequence(const std::vector<Real> & times)
     138             : {
     139         573 :   _time_sequence = buildSequence(times);
     140         567 :   synchronizeCurrentStep(_time, _timestep_tolerance);
     141         567 : }
     142             : 
     143             : void
     144           0 : TimeSequenceStepperBase::resetSequence()
     145             : {
     146           0 :   _time_sequence.clear();
     147           0 : }
     148             : 
     149             : bool
     150        1463 : TimeSequenceStepperBase::advanceToFutureTime(Real time, Real tolerance, Real & next_time)
     151             : {
     152        1463 :   refreshSequence();
     153        1463 :   const auto first_future = findFirstFutureTime(time, tolerance);
     154        1463 :   if (first_future == _time_sequence.cend())
     155           0 :     return false;
     156             : 
     157        1463 :   next_time = *first_future;
     158        1463 :   return true;
     159             : }
     160             : 
     161             : std::vector<Real>::const_iterator
     162        2060 : TimeSequenceStepperBase::findFirstFutureTime(Real time, Real tolerance) const
     163             : {
     164        2060 :   return std::partition_point(_time_sequence.begin(),
     165        2060 :                               _time_sequence.end(),
     166        6099 :                               [time, tolerance](const auto sequence_time)
     167        8159 :                               { return sequence_time - time <= tolerance; });
     168             : }
     169             : 
     170             : void
     171         597 : TimeSequenceStepperBase::synchronizeCurrentStep(Real time, Real tolerance)
     172             : {
     173         597 :   const auto first_future = findFirstFutureTime(time, tolerance);
     174         597 :   _current_step =
     175         597 :       first_future == _time_sequence.cbegin()
     176         597 :           ? 0
     177        1194 :           : static_cast<unsigned int>(std::distance(_time_sequence.cbegin(), first_future) - 1);
     178         597 : }
     179             : 
     180             : Real
     181           0 : TimeSequenceStepperBase::getNextTimeInSequence()
     182             : {
     183           0 :   refreshSequence();
     184             :   mooseAssert(_current_step + 1 < _time_sequence.size(),
     185             :               "The time sequence must contain a future time");
     186           0 :   return _time_sequence[_current_step + 1];
     187             : }
     188             : 
     189             : void
     190        2155 : TimeSequenceStepperBase::acceptStep()
     191             : {
     192        2155 :   TimeStepper::acceptStep();
     193        2155 :   refreshSequence();
     194        6938 :   while (_current_step + 1 < _time_sequence.size() &&
     195        3339 :          _time_sequence[_current_step + 1] - _time <= _timestep_tolerance)
     196        1444 :     increaseCurrentStep();
     197        2155 : }
     198             : 
     199             : Real
     200         432 : TimeSequenceStepperBase::computeInitialDT()
     201             : {
     202         432 :   return computeDT();
     203             : }
     204             : 
     205             : Real
     206        1047 : TimeSequenceStepperBase::computeDT()
     207             : {
     208        1047 :   refreshSequence();
     209             :   mooseAssert(_current_step + 1 < _time_sequence.size(),
     210             :               "The time sequence must contain a future time");
     211        1047 :   const auto next_time = _time_sequence[_current_step + 1];
     212             : 
     213        1047 :   if (_use_last_dt_after_last_t)
     214             :   {
     215             :     // last *provided* time value index; actual last index corresponds to end time
     216          77 :     const auto last_t_index = _time_sequence.size() - 2;
     217          77 :     if (_current_step + 1 > last_t_index)
     218          22 :       return _time_sequence[last_t_index] - _time_sequence[last_t_index - 1];
     219             :   }
     220             : 
     221        1025 :   return next_time - _time;
     222             : }

Generated by: LCOV version 1.14