LCOV - code coverage report
Current view: top level - src/postprocessors - PseudoTimestep.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 101 104 97.1 %
Date: 2025-07-17 01:28:37 Functions: 10 10 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 "PseudoTimestep.h"
      11             : #include "FEProblemBase.h"
      12             : #include "NonlinearSystemBase.h"
      13             : #include "MathUtils.h"
      14             : #include "TransientBase.h"
      15             : #include "Restartable.h"
      16             : #include "libmesh/enum_norm_type.h"
      17             : 
      18             : registerMooseObject("MooseApp", PseudoTimestep);
      19             : 
      20             : InputParameters
      21       14337 : PseudoTimestep::validParams()
      22             : {
      23       14337 :   InputParameters params = GeneralPostprocessor::validParams();
      24             : 
      25             :   /// Enum that is used to select the timestep-selection method.
      26       14337 :   MooseEnum method("SER RDM EXP", "SER");
      27             : 
      28       14337 :   method.addDocumentation("SER", "Switched evolution relaxation");
      29       14337 :   method.addDocumentation("EXP", "Exponential progression");
      30       14337 :   method.addDocumentation("RDM", "Residual difference method");
      31             : 
      32       14337 :   params.addRequiredParam<MooseEnum>(
      33             :       "method", method, "The method used for pseudotimestep timemarching");
      34       14337 :   params.addRequiredRangeCheckedParam<Real>("initial_dt", "initial_dt > 0", "Initial timestep");
      35       14337 :   params.addRequiredRangeCheckedParam<Real>(
      36             :       "alpha", "alpha > 0", "The parameter alpha used in the scaling of the timestep");
      37       14337 :   params.addParam<Real>("max_dt", "The largest timestep allowed");
      38       14337 :   params.addParam<unsigned int>(
      39             :       "iterations_window",
      40             :       "For how many iterations should the residual be tracked (only applies to the SER method)");
      41             :   // Because this post-processor is meant to be used with PostprocessorDT, it
      42             :   // should be executed on initial (not included by default) and timestep end.
      43       43011 :   params.set<ExecFlagEnum>("execute_on") = {EXEC_TIMESTEP_END, EXEC_INITIAL};
      44       14337 :   params.suppressParameter<ExecFlagEnum>("execute_on");
      45             : 
      46       14337 :   params.addClassDescription("Computes pseudo-time steps for obtaining steady-state solutions "
      47             :                              "through a pseudo transient process.");
      48             : 
      49       28674 :   return params;
      50       28674 : }
      51             : 
      52          36 : PseudoTimestep::PseudoTimestep(const InputParameters & parameters)
      53             :   : GeneralPostprocessor(parameters),
      54          36 :     _method(getParam<MooseEnum>("method").getEnum<PseudotimeMethod>()),
      55          36 :     _initial_dt(getParam<Real>("initial_dt")),
      56          36 :     _alpha(getParam<Real>("alpha")),
      57          36 :     _bound(isParamValid("max_dt")),
      58          36 :     _max_dt(_bound ? getParam<Real>("max_dt") : std::numeric_limits<Real>::max()),
      59          36 :     _residual_norms_sequence(declareRestartableData<std::vector<Real>>("residual_norms_sequence")),
      60          72 :     _iterations_step_sequence(declareRestartableData<std::vector<Real>>("iterations_step_sequence"))
      61             : {
      62          36 :   if (!_fe_problem.isTransient())
      63           0 :     mooseError("This pseudotimestepper can only be used if the steady state is computed via time "
      64             :                "integration.");
      65             : 
      66          36 :   if (_method == PseudotimeMethod::SER)
      67             :   {
      68          12 :     if (parameters.isParamValid("iterations_window"))
      69          12 :       _iterations_window = getParam<unsigned int>("iterations_window");
      70             :     else
      71           0 :       _iterations_window = 1;
      72             :   }
      73          24 :   else if (parameters.isParamValid("iterations_window"))
      74           0 :     mooseError("The iterations window can be only provided for the SER method.");
      75          36 : }
      76             : 
      77             : void
      78         220 : PseudoTimestep::initialize()
      79             : {
      80             :   // start with the max
      81         220 :   _dt = std::numeric_limits<Real>::max();
      82         220 : }
      83             : 
      84             : Real
      85         220 : PseudoTimestep::getValue() const
      86             : {
      87         220 :   return _dt;
      88             : }
      89             : 
      90             : Real
      91         187 : PseudoTimestep::currentResidualNorm() const
      92             : {
      93         187 :   NonlinearSystemBase & nl = _fe_problem.getNonlinearSystemBase(_sys.number());
      94         187 :   Real res_norm = 0.0;
      95         374 :   for (const auto var_num : make_range(nl.system().n_vars()))
      96             :   {
      97             :     auto var_res =
      98         187 :         nl.system().calculate_norm(nl.getResidualNonTimeVector(), var_num, libMesh::DISCRETE_L2);
      99         187 :     res_norm = res_norm + std::pow(var_res, 2);
     100             :   }
     101         187 :   res_norm = std::sqrt(res_norm);
     102         187 :   return res_norm;
     103             : }
     104             : 
     105             : void
     106         187 : PseudoTimestep::outputPseudoTimestep(Real curr_time) const
     107             : {
     108         187 :   unsigned int curr_step = _fe_problem.timeStep();
     109         187 :   Real step_dt = _fe_problem.dt();
     110             : 
     111         187 :   unsigned int res_size = _residual_norms_sequence.size();
     112             : 
     113         187 :   _console << "Current step " << curr_step << " and current dt " << step_dt
     114         187 :            << " for  steady state residual " << _residual_norms_sequence[res_size - 1]
     115         187 :            << " at time " << curr_time << std::endl;
     116         187 : }
     117             : 
     118             : Real
     119          44 : PseudoTimestep::timestepSER() const
     120             : {
     121          44 :   const unsigned int curr_step = _fe_problem.timeStep();
     122             : 
     123          44 :   const unsigned int steps_size = _iterations_step_sequence.size();
     124          44 :   const unsigned int res_size = _residual_norms_sequence.size();
     125          44 :   const unsigned int prev_steps = std::min(_iterations_window + 1, curr_step);
     126             : 
     127         132 :   const Real factor = std::pow(_residual_norms_sequence[res_size - prev_steps] /
     128          44 :                                    _residual_norms_sequence[res_size - 1],
     129          44 :                                _alpha);
     130             : 
     131          44 :   const Real update_dt = _iterations_step_sequence[steps_size - 1] * factor;
     132          44 :   return update_dt;
     133             : }
     134             : 
     135             : Real
     136          66 : PseudoTimestep::timestepRDM() const
     137             : {
     138          66 :   const unsigned int res_size = _residual_norms_sequence.size();
     139          66 :   const unsigned int steps_size = _iterations_step_sequence.size();
     140             : 
     141          66 :   Real exponent = 0.0;
     142             : 
     143          66 :   if (_residual_norms_sequence[res_size - 1] < _residual_norms_sequence[res_size - 2])
     144         132 :     exponent = (_residual_norms_sequence[res_size - 2] - _residual_norms_sequence[res_size - 1]) /
     145          66 :                _residual_norms_sequence[res_size - 2];
     146          66 :   const Real update_dt = _iterations_step_sequence[steps_size - 1] * std::pow(_alpha, exponent);
     147          66 :   return update_dt;
     148             : }
     149             : 
     150             : Real
     151          44 : PseudoTimestep::timestepEXP() const
     152             : {
     153          44 :   const Real factor = MathUtils::pow(_alpha, _fe_problem.timeStep() - 1);
     154             : 
     155          44 :   const Real update_dt = _initial_dt * factor;
     156          44 :   return update_dt;
     157             : }
     158             : 
     159             : void
     160         220 : PseudoTimestep::execute()
     161             : {
     162         220 :   TransientBase * transient = dynamic_cast<TransientBase *>(_app.getExecutioner());
     163             : 
     164             :   Real res_norm;
     165             :   Real curr_dt;
     166             :   Real update_dt;
     167             : 
     168         220 :   if (_current_execute_flag == EXEC_INITIAL)
     169          33 :     _dt = _initial_dt;
     170             : 
     171             :   // at the end of each timestep call the postprocessor to set values for dt
     172         220 :   if (_current_execute_flag == EXEC_TIMESTEP_END)
     173             :   {
     174         187 :     res_norm = currentResidualNorm();
     175         187 :     _residual_norms_sequence.push_back(res_norm);
     176             : 
     177         187 :     curr_dt = transient->getDT();
     178         187 :     _iterations_step_sequence.push_back(curr_dt);
     179             : 
     180         187 :     _dt = curr_dt;
     181             : 
     182             :     // since some of the residual methods require previous residuals the pseudo timesteppers
     183             :     // start at the second step in the computation
     184         187 :     if (_fe_problem.timeStep() > 1)
     185             :     {
     186         154 :       update_dt = curr_dt;
     187         154 :       switch (_method)
     188             :       {
     189          44 :         case PseudotimeMethod::SER:
     190          44 :           update_dt = timestepSER();
     191          44 :           break;
     192          44 :         case PseudotimeMethod::EXP:
     193          44 :           update_dt = timestepEXP();
     194          44 :           break;
     195          66 :         case PseudotimeMethod::RDM:
     196          66 :           update_dt = timestepRDM();
     197          66 :           break;
     198             :       }
     199         154 :       if (_bound)
     200          44 :         _dt = std::min(_max_dt, update_dt);
     201             :       else
     202         110 :         _dt = update_dt;
     203             :     }
     204         187 :     outputPseudoTimestep(_fe_problem.time());
     205             :   }
     206         220 : }

Generated by: LCOV version 1.14