LCOV - code coverage report
Current view: top level - src/timeintegrators - LStableDirk2.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 60 66 90.9 %
Date: 2025-07-17 01:28:37 Functions: 5 7 71.4 %
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 "LStableDirk2.h"
      11             : #include "NonlinearSystem.h"
      12             : #include "FEProblem.h"
      13             : #include "PetscSupport.h"
      14             : 
      15             : using namespace libMesh;
      16             : 
      17             : registerMooseObject("MooseApp", LStableDirk2);
      18             : 
      19             : InputParameters
      20       14484 : LStableDirk2::validParams()
      21             : {
      22       14484 :   InputParameters params = TimeIntegrator::validParams();
      23       14484 :   params.addClassDescription(
      24             :       "Second order diagonally implicit Runge Kutta method (Dirk) with two stages.");
      25       14484 :   return params;
      26           0 : }
      27             : 
      28         146 : LStableDirk2::LStableDirk2(const InputParameters & parameters)
      29             :   : TimeIntegrator(parameters),
      30         146 :     _stage(1),
      31         146 :     _residual_stage1(addVector("residual_stage1", false, GHOSTED)),
      32         146 :     _residual_stage2(addVector("residual_stage2", false, GHOSTED)),
      33         292 :     _alpha(1. - 0.5 * std::sqrt(2))
      34             : {
      35         146 :   mooseInfo("LStableDirk2 and other multistage TimeIntegrators are known not to work with "
      36             :             "Materials/AuxKernels that accumulate 'state' and should be used with caution.");
      37         146 : }
      38             : 
      39             : void
      40        7327 : LStableDirk2::computeTimeDerivatives()
      41             : {
      42             :   // We are multiplying by the method coefficients in postResidual(), so
      43             :   // the time derivatives are of the same form at every stage although
      44             :   // the current solution varies depending on the stage.
      45        7327 :   if (!_sys.solutionUDot())
      46           0 :     mooseError("LStableDirk2: Time derivative of solution (`u_dot`) is not stored. Please set "
      47             :                "uDotRequested() to true in FEProblemBase befor requesting `u_dot`.");
      48             : 
      49        7327 :   NumericVector<Number> & u_dot = *_sys.solutionUDot();
      50        7327 :   u_dot = *_solution;
      51        7327 :   computeTimeDerivativeHelper(u_dot, _solution_old);
      52        7327 :   u_dot.close();
      53        7327 :   computeDuDotDu();
      54        7327 : }
      55             : 
      56             : void
      57           0 : LStableDirk2::computeADTimeDerivatives(ADReal & ad_u_dot,
      58             :                                        const dof_id_type & dof,
      59             :                                        ADReal & /*ad_u_dotdot*/) const
      60             : {
      61           0 :   computeTimeDerivativeHelper(ad_u_dot, _solution_old(dof));
      62           0 : }
      63             : 
      64             : void
      65         231 : LStableDirk2::solve()
      66             : {
      67             :   // Time at end of step
      68         231 :   Real time_new = _fe_problem.time();
      69             : 
      70             :   // Time at beginning of step
      71         231 :   Real time_old = _fe_problem.timeOld();
      72             : 
      73             :   // Time at stage 1
      74         231 :   Real time_stage1 = time_old + _alpha * _dt;
      75             : 
      76             :   // Reset iteration counts
      77         231 :   _n_nonlinear_iterations = 0;
      78         231 :   _n_linear_iterations = 0;
      79             : 
      80             :   // Compute first stage
      81         231 :   _fe_problem.initPetscOutputAndSomeSolverSettings();
      82         231 :   _console << "1st stage" << std::endl;
      83         231 :   _stage = 1;
      84         231 :   _fe_problem.time() = time_stage1;
      85         231 :   _nl->system().solve();
      86         231 :   _nl->destroyColoring();
      87         231 :   _n_nonlinear_iterations += getNumNonlinearIterationsLastSolve();
      88         231 :   _n_linear_iterations += getNumLinearIterationsLastSolve();
      89             : 
      90             :   // Abort time step immediately on stage failure - see TimeIntegrator doc page
      91         231 :   if (!_fe_problem.converged(_nl->number()))
      92          10 :     return;
      93             : 
      94             :   // Compute second stage
      95         221 :   _fe_problem.initPetscOutputAndSomeSolverSettings();
      96         221 :   _console << "2nd stage" << std::endl;
      97         221 :   _stage = 2;
      98         221 :   _fe_problem.timeOld() = time_stage1;
      99         221 :   _fe_problem.time() = time_new;
     100         221 :   _nl->potentiallySetupFiniteDifferencing();
     101         221 :   _nl->system().solve();
     102         221 :   _n_nonlinear_iterations += getNumNonlinearIterationsLastSolve();
     103         221 :   _n_linear_iterations += getNumLinearIterationsLastSolve();
     104             : 
     105             :   // Reset time at beginning of step to its original value
     106         221 :   _fe_problem.timeOld() = time_old;
     107             : }
     108             : 
     109             : void
     110        7305 : LStableDirk2::postResidual(NumericVector<Number> & residual)
     111             : {
     112        7305 :   if (_stage == 1)
     113             :   {
     114             :     // In the standard RK notation, the stage 1 residual is given by:
     115             :     //
     116             :     // R := (Y_1 - y_n)/dt - alpha*f(t_n + alpha*dt, Y_1) = 0
     117             :     //
     118             :     // where:
     119             :     // .) f(t_n + alpha*dt, Y_1) corresponds to the residuals of the
     120             :     //    non-time kernels.  We'll save this as "_residual_stage1" to use
     121             :     //    later.
     122             :     // .) (Y_1 - y_n)/dt corresponds to the residual of the time kernels.
     123             :     // .) The minus sign in front of alpha is already "baked in" to
     124             :     //    the non-time residuals, so it does not appear here.
     125        3690 :     *_residual_stage1 = *_Re_non_time;
     126        3690 :     _residual_stage1->close();
     127             : 
     128        3690 :     residual.add(1., *_Re_time);
     129        3690 :     residual.add(_alpha, *_residual_stage1);
     130        3690 :     residual.close();
     131             :   }
     132        3615 :   else if (_stage == 2)
     133             :   {
     134             :     // In the standard RK notation, the stage 2 residual is given by:
     135             :     //
     136             :     // R := (Y_2 - y_n)/dt - (1-alpha)*f(t_n + alpha*dt, Y_1) - alpha*f(t_n + dt, Y_2) = 0
     137             :     //
     138             :     // where:
     139             :     // .) f(t_n + alpha*dt, Y_1) has already been saved as _residual_stage1.
     140             :     // .) f(t_n + dt, Y_2) will now be saved as "_residual_stage2".
     141             :     // .) (Y_2 - y_n)/dt corresponds to the residual of the time kernels.
     142             :     // .) The minus signs are once again "baked in" to the non-time
     143             :     //    residuals, so they do not appear here.
     144             :     //
     145             :     // The solution at the end of stage 2, i.e. Y_2, is also the final solution.
     146        3615 :     *_residual_stage2 = *_Re_non_time;
     147        3615 :     _residual_stage2->close();
     148             : 
     149        3615 :     residual.add(1., *_Re_time);
     150        3615 :     residual.add(1. - _alpha, *_residual_stage1);
     151        3615 :     residual.add(_alpha, *_residual_stage2);
     152        3615 :     residual.close();
     153             :   }
     154             :   else
     155           0 :     mooseError("LStableDirk2::postResidual(): Member variable _stage can only have values 1 or 2.");
     156        7305 : }

Generated by: LCOV version 1.14