SpECTRE Documentation Coverage Report
Current view: top level - ParallelAlgorithms/LinearSolver/Multigrid - Multigrid.hpp Hit Total Coverage
Commit: de0084593a37be7727c6c4da0be2184b0f8d9ed4 Lines: 3 16 18.8 %
Date: 2025-11-04 23:26:01
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : // Distributed under the MIT License.
       2             : // See LICENSE.txt for details.
       3             : 
       4             : #pragma once
       5             : 
       6             : #include <cstddef>
       7             : 
       8             : #include "DataStructures/DataBox/Prefixes.hpp"
       9             : #include "IO/Observer/Actions/RegisterWithObservers.hpp"
      10             : #include "IO/Observer/Helpers.hpp"
      11             : #include "ParallelAlgorithms/Actions/Goto.hpp"
      12             : #include "ParallelAlgorithms/LinearSolver/AsynchronousSolvers/ElementActions.hpp"
      13             : #include "ParallelAlgorithms/LinearSolver/Multigrid/ElementActions.hpp"
      14             : #include "ParallelAlgorithms/LinearSolver/Multigrid/ObserveVolumeData.hpp"
      15             : #include "Utilities/TMPL.hpp"
      16             : 
      17             : /// Items related to the multigrid linear solver
      18             : ///
      19             : /// \see `LinearSolver::multigrid::Multigrid`
      20             : namespace LinearSolver::multigrid {
      21             : 
      22             : /// A label indicating the pre-smoothing step in a V-cycle multigrid algorithm,
      23             : /// i.e. the smoothing step before sending the residual to the coarser (parent)
      24             : /// grid
      25           1 : struct VcycleDownLabel {};
      26             : 
      27             : /// A label indicating the post-smoothing step in a V-cycle multigrid algorithm,
      28             : /// i.e. the smoothing step before sending the correction to the finer (child)
      29             : /// grid
      30           1 : struct VcycleUpLabel {};
      31             : 
      32             : /*!
      33             :  * \brief A V-cycle geometric multgrid solver for linear equations \f$Ax = b\f$
      34             :  *
      35             :  * This linear solver iteratively corrects an initial guess \f$x_0\f$ by
      36             :  * restricting the residual \f$b - Ax\f$ to a series of coarser grids, solving
      37             :  * for a correction on the coarser grids, and then prolongating (interpolating)
      38             :  * the correction back to the finer grids. The solves on grids with different
      39             :  * scales can very effectively solve large-scale modes in the solution, which
      40             :  * Krylov-type linear solvers such as GMRES or Conjugate Gradients typically
      41             :  * struggle with. Therefore, a multigrid solver can be an effective
      42             :  * preconditioner for Krylov-type linear solvers (see
      43             :  * `LinearSolver::gmres::Gmres` and `LinearSolver::cg::ConjugateGradient`). See
      44             :  * \cite Briggs2000jp for an introduction to multigrid methods.
      45             :  *
      46             :  * \par Grid hierarchy
      47             :  * This geometric multigrid solver relies on a strategy to coarsen the
      48             :  * computational grid in a way that removes small-scale modes. We currently
      49             :  * h-coarsen the initial domain, meaning that we create multigrid levels by
      50             :  * successively combining two elements into one along every dimension of the
      51             :  * grid. We only p-coarsen the grid in the sense that we choose the smaller of
      52             :  * the two polynomial degrees when combining elements. This strategy follows
      53             :  * \cite Vincent2019qpd. See `LinearSolver::multigrid::ElementsAllocator` and
      54             :  * `LinearSolver::multigrid::coarsen` for the code that creates the initial
      55             :  * multigrid hierarchy.
      56             :  * Once the initial grids are created, AMR steps can create incrementally finer
      57             :  * grids. For this to work, AMR must be configured with the compile-time option
      58             :  * `keep_coarse_grids = true` (see `amr::protocols::AmrMetavariables`).
      59             :  *
      60             :  * \par Inter-mesh operators
      61             :  * The algorithm relies on operations that project data between grids. Residuals
      62             :  * are projected from finer to coarser grids ("restriction") and solutions are
      63             :  * projected from coarser to finer grids ("prolongation"). We use the standard
      64             :  * \f$L_2\f$-projections implemented in
      65             :  * `Spectral::projection_matrix_child_to_parent` and
      66             :  * `Spectral::projection_matrix_parent_to_child`, where "child" means the finer
      67             :  * grid and "parent" means the coarser grid. Note that the residuals \f$b -
      68             :  * Ax\f$ may or may not already include a mass matrix and Jacobian factors,
      69             :  * depending on the implementation of the linear operator \f$A\f$. To account
      70             :  * for this, provide a tag as the `ResidualIsMassiveTag` that holds a `bool`.
      71             :  * See section 3 in \cite Fortunato2019jl for details on the inter-mesh
      72             :  * operators.
      73             :  *
      74             :  * \par Smoother and bottom solver
      75             :  * On every level of the grid hierarchy the multigrid solver relies on a
      76             :  * "smoother" that performs an approximate linear solve on that level. The
      77             :  * smoother can be any linear solver that solves the `smooth_fields_tag` for the
      78             :  * source in the `smooth_source_tag`. Useful smoothers are asynchronous linear
      79             :  * solvers that parallelize well, such as `LinearSolver::Schwarz::Schwarz`. The
      80             :  * multigrid algorithm doesn't assume anything about the smoother, but requires
      81             :  * only that the `PreSmootherActions` and the `PostSmootherActions` passed to
      82             :  * `solve` leave the `smooth_fields_tag` in a state that represents an
      83             :  * approximate solution to the `smooth_source_tag`, and that
      84             :  * `db::add_tag_prefix<LinearSolver::Tags::OperatorAppliedTo,
      85             :  * smooth_fields_tag>` is left up-to-date as well.
      86             :  * The smoother can assume that, on entry, these two tags represent the initial
      87             :  * fields and the linear operator applied to the initial fields, respectively.
      88             :  * Here's an example of setting up a smoother for the multigrid solver:
      89             :  *
      90             :  * \snippet Test_MultigridAlgorithm.cpp setup_smoother
      91             :  *
      92             :  * On the coarsest level of the grid hierarchy, the multigrid algorithm can also
      93             :  * use a separate "bottom solver". If enabled, the bottom solver replaces the
      94             :  * pre-smoother on the coarsest grid. The bottom solver can also be any linear
      95             :  * solver, but it is typically a direct solver that solves the linear problem
      96             :  * exactly (see `LinearSolver::Actions::BuildMatrix` for a good bottom solver).
      97             :  *
      98             :  * The smoother and bottom solver can be used to construct an action list like
      99             :  * this:
     100             :  *
     101             :  * \snippet Test_MultigridAlgorithm.cpp action_list
     102             :  *
     103             :  * \par Algorithm overview
     104             :  * Every iteration of the multigrid algorithm performs a V-cycle over the grid
     105             :  * hierarchy. One V-cycle consists of first "going down" the grid hierarchy,
     106             :  * from the finest to successively coarser grids, smoothing on every level
     107             :  * ("pre-smoothing", can be controlled by the option
     108             :  * `LinearSolver::multigrid::Tags::EnablePreSmoothing`),
     109             :  * and then "going up" the grid hierarchy again, smoothing on
     110             :  * every level again ("post-smoothing"). When going down, the algorithm projects
     111             :  * the remaining residual of the smoother to the next-coarser grid, setting it
     112             :  * as the source for the smoother on the coarser grid. When going up again, the
     113             :  * algorithm projects the solution of the smoother to the next-finer grid,
     114             :  * adding it to the solution on the finer grid as a correction. The bottom-most
     115             :  * coarsest grid (the "tip" of the V-cycle) may run the bottom solver instead of
     116             :  * the pre-smoother. It may also skip the post-smoother, so the result of the
     117             :  * bottom solver is immediately projected up to the finer grid (controlled by
     118             :  * the options `LinearSolver::multigrid::Tags::UseBottomSolver` and
     119             :  * `LinearSolver::multigrid::Tags::EnablePostSmoothingAtBottom`). On the
     120             :  * top-most finest grid (the "original" grid that represents the overall
     121             :  * solution) the algorithm applies the smoothing and the corrections from the
     122             :  * coarser grids directly to the solution fields.
     123             :  */
     124             : template <typename Metavariables, size_t Dim, typename FieldsTag,
     125             :           typename OptionsGroup, typename ResidualIsMassiveTag,
     126             :           typename SourceTag =
     127             :               db::add_tag_prefix<::Tags::FixedSource, FieldsTag>>
     128           1 : struct Multigrid {
     129           0 :   using fields_tag = FieldsTag;
     130           0 :   using options_group = OptionsGroup;
     131           0 :   using source_tag = SourceTag;
     132             : 
     133           0 :   using operand_tag = FieldsTag;
     134             : 
     135           0 :   using smooth_source_tag = source_tag;
     136           0 :   using smooth_fields_tag = fields_tag;
     137             : 
     138           0 :   using component_list = tmpl::list<>;
     139             : 
     140           0 :   using observed_reduction_data_tags = observers::make_reduction_data_tags<
     141             :       tmpl::list<async_solvers::reduction_data>>;
     142             : 
     143           0 :   using initialize_element = tmpl::list<
     144             :       async_solvers::InitializeElement<FieldsTag, OptionsGroup, SourceTag>,
     145             :       detail::InitializeElement<Dim, FieldsTag, OptionsGroup, SourceTag>>;
     146             : 
     147           0 :   using amr_projectors = initialize_element;
     148             : 
     149           0 :   using register_element = tmpl::list<
     150             :       async_solvers::RegisterElement<FieldsTag, OptionsGroup, SourceTag,
     151             :                                      ::amr::Tags::IsFinestGrid>,
     152             :       observers::Actions::RegisterWithObservers<
     153             :           detail::RegisterWithVolumeObserver<OptionsGroup>>>;
     154             : 
     155             :   template <typename ApplyOperatorActions, typename PreSmootherActions,
     156             :             typename PostSmootherActions,
     157             :             typename BottomSolverActions = tmpl::list<>,
     158             :             typename Label = OptionsGroup>
     159           0 :   using solve = tmpl::list<
     160             :       async_solvers::PrepareSolve<FieldsTag, OptionsGroup, SourceTag, Label,
     161             :                                   ::amr::Tags::IsFinestGrid, false>,
     162             :       detail::ReceiveResidualFromFinerGrid<Dim, FieldsTag, OptionsGroup,
     163             :                                            SourceTag>,
     164             :       detail::PreparePreSmoothing<
     165             :           FieldsTag, OptionsGroup, SourceTag,
     166             :           not std::is_same_v<BottomSolverActions, tmpl::list<>>>,
     167             :       // No need to apply the linear operator here:
     168             :       // - On the finest grid, the operator applied to the fields should have
     169             :       //   already been computed at this point, either applied to the initial
     170             :       //   fields before the multigrid solver is invoked, or by the smoother at
     171             :       //   the end of the previous V-cycle.
     172             :       // - On coarser grids, the initial fields are zero, so the operator
     173             :       //   applied to them is also zero.
     174             :       PreSmootherActions,
     175             :       detail::SkipBottomSolver<FieldsTag, OptionsGroup, SourceTag>,
     176             :       BottomSolverActions,
     177             :       detail::SkipPostSmoothingAtBottom<FieldsTag, OptionsGroup, SourceTag>,
     178             :       detail::SendResidualToCoarserGrid<FieldsTag, OptionsGroup,
     179             :                                         ResidualIsMassiveTag, SourceTag>,
     180             :       detail::ReceiveCorrectionFromCoarserGrid<Dim, FieldsTag, OptionsGroup,
     181             :                                                SourceTag>,
     182             :       ApplyOperatorActions, ::Actions::Label<detail::PostSmoothingBeginLabel>,
     183             :       PostSmootherActions,
     184             :       detail::SendCorrectionToFinerGrid<FieldsTag, OptionsGroup, SourceTag>,
     185             :       detail::ObserveVolumeData<FieldsTag, OptionsGroup, SourceTag>,
     186             :       async_solvers::CompleteStep<FieldsTag, OptionsGroup, SourceTag, Label,
     187             :                                   ::amr::Tags::IsFinestGrid, false>>;
     188             : };
     189             : 
     190             : }  // namespace LinearSolver::multigrid

Generated by: LCOV version 1.14