LCOV - code coverage report
Current view: top level - src/tensor_solver - AdamsBashforthMoulton.C (source / functions) Hit Total Coverage
Test: idaholab/swift: #92 (25e020) with base b3cd84 Lines: 72 74 97.3 %
Date: 2025-09-10 17:10:32 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /**********************************************************************/
       2             : /*                    DO NOT MODIFY THIS HEADER                       */
       3             : /*             Swift, a Fourier spectral solver for MOOSE             */
       4             : /*                                                                    */
       5             : /*            Copyright 2024 Battelle Energy Alliance, LLC            */
       6             : /*                        ALL RIGHTS RESERVED                         */
       7             : /**********************************************************************/
       8             : 
       9             : #include "AdamsBashforthMoulton.h"
      10             : #include "TensorProblem.h"
      11             : #include "Conversion.h"
      12             : #include "DomainAction.h"
      13             : #include <array>
      14             : 
      15             : registerMooseObject("SwiftApp", AdamsBashforthMoulton);
      16             : registerMooseObjectRenamed("SwiftApp",
      17             :                            SemiImplicitSolver,
      18             :                            "10/01/2025 00:01",
      19             :                            AdamsBashforthMoulton);
      20             : 
      21             : namespace
      22             : {
      23             : // Max order supported (up to ABM5)
      24             : constexpr std::size_t max_order = 5;
      25             : }
      26             : 
      27             : InputParameters
      28         158 : AdamsBashforthMoulton::validParams()
      29             : {
      30         158 :   InputParameters params = SplitOperatorBase::validParams();
      31         158 :   params.addClassDescription("Adams-Bashforth-Moulton semi-implicit/explicit time integration "
      32             :                              "solver with optional implicit corrector.");
      33         316 :   params.addParam<unsigned int>("substeps", 1, "semi-implicit substeps per time step.");
      34         316 :   params.addRangeCheckedParam<std::size_t>("predictor_order",
      35         316 :                                            2,
      36         158 :                                            "predictor_order > 0 & predictor_order <= " +
      37         158 :                                                Moose::stringify(max_order),
      38             :                                            "Order of the Adams-Bashforth predictor.");
      39         316 :   params.addRangeCheckedParam<std::size_t>("corrector_order",
      40         316 :                                            2,
      41         158 :                                            "corrector_order > 0 & corrector_order <= " +
      42         158 :                                                Moose::stringify(max_order),
      43             :                                            "Order of the Adams-Moulton corrector.");
      44         316 :   params.addParam<std::size_t>(
      45             :       "corrector_steps",
      46         316 :       0,
      47             :       "Number the Adams-Moulton corrector steps to take (one is usually sufficient).");
      48         158 :   return params;
      49           0 : }
      50             : 
      51          78 : AdamsBashforthMoulton::AdamsBashforthMoulton(const InputParameters & parameters)
      52             :   : SplitOperatorBase(parameters),
      53          78 :     _substeps(getParam<unsigned int>("substeps")),
      54         156 :     _predictor_order(getParam<std::size_t>("predictor_order") - 1),
      55         156 :     _corrector_order(getParam<std::size_t>("corrector_order") - 1),
      56         156 :     _corrector_steps(getParam<std::size_t>("corrector_steps")),
      57          78 :     _sub_dt(_tensor_problem.subDt()),
      58         156 :     _sub_time(_tensor_problem.subTime())
      59             : {
      60          78 :   getVariables(_predictor_order);
      61          78 : }
      62             : 
      63             : void
      64        1004 : AdamsBashforthMoulton::computeBuffer()
      65             : {
      66             :   // Adams–Bashforth coefficients (zero-padded)
      67        1004 :   constexpr std::array<std::array<double, max_order>, max_order> beta = {{
      68             :       {1.0, 0.0, 0.0, 0.0, 0.0},                                                        // AB1
      69             :       {3.0 / 2.0, -1.0 / 2.0, 0.0, 0.0, 0.0},                                           // AB2
      70             :       {23.0 / 12.0, -16.0 / 12.0, 5.0 / 12.0, 0.0, 0.0},                                // AB3
      71             :       {55.0 / 24.0, -59.0 / 24.0, 37.0 / 24.0, -9.0 / 24.0, 0.0},                       // AB4
      72             :       {190.0 / 720.0, -2774.0 / 720.0, 2616.0 / 720.0, -1274.0 / 720.0, 251.0 / 720.0}, // AB5
      73             :   }};
      74             : 
      75             :   // Adams–Moulton coefficients (zero-padded)
      76        1004 :   constexpr std::array<std::array<double, max_order>, max_order> alpha = {{
      77             :       {1.0, 0.0, 0.0, 0.0, 0.0},                                                    // AM1
      78             :       {0.5, 0.5, 0.0, 0.0, 0.0},                                                    // AM2
      79             :       {5.0 / 12.0, 8.0 / 12.0, -1.0 / 12.0, 0.0, 0.0},                              // AM3
      80             :       {9.0 / 24.0, 19.0 / 24.0, -5.0 / 24.0, 1.0 / 24.0, 0.0},                      // AM4
      81             :       {251.0 / 720.0, 646.0 / 720.0, -264.0 / 720.0, 106.0 / 720.0, -19.0 / 720.0}, // AM5
      82             :   }};
      83             : 
      84        1004 :   const bool dt_changed = (_dt != _dt_old);
      85             : 
      86             :   torch::Tensor ubar;
      87        1004 :   _sub_dt = _dt / _substeps;
      88             : 
      89             :   // subcycles
      90       50708 :   for (const auto substep : make_range(_substeps))
      91             :   {
      92             :     // re-evaluate the solve compute
      93       49704 :     _compute->computeBuffer();
      94       49704 :     forwardBuffers();
      95             : 
      96             :     // Adams-Bashforth predictor on all variables
      97       49704 :     for (auto & [u,
      98             :                  reciprocal_buffer,
      99             :                  linear_reciprocal,
     100             :                  nonlinear_reciprocal,
     101      147408 :                  old_nonlinear_reciprocal] : _variables)
     102             :     {
     103       97704 :       const auto n_old = old_nonlinear_reciprocal.size();
     104             : 
     105             :       // Order is what the user requested, or what the available history allows for.
     106             :       // If dt changes between steps, we start at first order again
     107             :       const auto order =
     108      195408 :           std::min(substep < _predictor_order && dt_changed ? 0 : n_old, _predictor_order);
     109             : 
     110             :       // Adams-Bashforth
     111      195408 :       ubar = reciprocal_buffer + (_sub_dt * beta[order][0]) * nonlinear_reciprocal;
     112      262382 :       for (const auto i : make_range(order))
     113      494034 :         ubar += (_sub_dt * beta[order][i + 1]) * old_nonlinear_reciprocal[i];
     114             : 
     115       97704 :       if (linear_reciprocal)
     116      390816 :         ubar /= (1.0 - _sub_dt * *linear_reciprocal);
     117             : 
     118      195408 :       u = _domain.ifft(ubar);
     119             :     }
     120             : 
     121             :     // AB: y[n+1] = y[n] + dt * f(y[n])
     122             :     // AM: y[n+1] = y[n] + dt * f(y[n+1])
     123             : 
     124             :     // increment substep time
     125       49704 :     _sub_time += _sub_dt;
     126             : 
     127             :     // Adams-Moulton corrector
     128       49704 :     if (_corrector_steps)
     129             :     {
     130             :       // we need to keep the previous time step reciprocal_buffer if we run the AM corrector
     131        3000 :       std::vector<torch::Tensor> ubar_n(_variables.size());
     132        9000 :       for (const auto k : index_range(_variables))
     133        6000 :         ubar_n[k] = _variables[k]._reciprocal_buffer;
     134             : 
     135             :       // if the corrector order is AM2 or higher we also need the f calculated by AB prior to the
     136             :       // update to the current step values
     137             :       std::vector<torch::Tensor> N_n;
     138        3000 :       if (_corrector_order > 0)
     139             :       {
     140        1000 :         N_n.resize(_variables.size());
     141        3000 :         for (const auto k : index_range(_variables))
     142        2000 :           N_n[k] = _variables[k]._nonlinear_reciprocal;
     143             :       }
     144             : 
     145             :       // apply multiple corrector steps, going forward we probably want to allow users to fixpoint
     146             :       // iterate until a given convergence criterion is fulfilled.
     147        8000 :       for (std::size_t j = 0; j < _corrector_steps; ++j)
     148             :       {
     149             :         // re-evaluate the solve compute with the predicted variable values
     150        5000 :         _compute->computeBuffer();
     151        5000 :         forwardBuffers();
     152             : 
     153       15000 :         for (const auto k : index_range(_variables))
     154             :         {
     155       10000 :           auto & u = _variables[k]._buffer;
     156       10000 :           const auto * linear_reciprocal = _variables[k]._linear_reciprocal;
     157       10000 :           const auto & nonlinear_reciprocal_pred = _variables[k]._nonlinear_reciprocal;
     158       10000 :           const auto & old_nonlinear_reciprocal = _variables[k]._old_nonlinear_reciprocal;
     159             : 
     160             :           const auto n_old = old_nonlinear_reciprocal.size();
     161             :           const auto order =
     162       10000 :               std::min(substep < _corrector_order && dt_changed ? 1 : n_old + 1, _corrector_order);
     163       10000 :           if (order == 0)
     164        6000 :             continue;
     165             : 
     166       12000 :           ubar = ubar_n[k] + (_sub_dt * alpha[order][0]) * nonlinear_reciprocal_pred;
     167             : 
     168             :           if (order > 0)
     169             :           {
     170        8000 :             ubar += (_sub_dt * alpha[order][1]) * N_n[k];
     171        4000 :             for (const auto i : make_range(order - 1))
     172           0 :               ubar += (_sub_dt * alpha[order][i + 2]) * old_nonlinear_reciprocal[i];
     173             :           }
     174             : 
     175        4000 :           if (linear_reciprocal)
     176       16000 :             ubar /= (1.0 - _sub_dt * *linear_reciprocal);
     177             : 
     178        8000 :           u = _domain.ifft(ubar);
     179             :         }
     180             :       }
     181        3000 :     }
     182             : 
     183             :     // we skip the advanceState on the last substep because MOOSE will call that automatically
     184       49704 :     if (substep < _substeps - 1)
     185       48700 :       _tensor_problem.advanceState();
     186             :   }
     187        1004 : }

Generated by: LCOV version 1.14