SpECTRE Documentation Coverage Report
Current view: top level - ParallelAlgorithms/LinearSolver/Schwarz - Schwarz.hpp Hit Total Coverage
Commit: eded15d6fcfa762a5dfde087b28df9bcedd8b386 Lines: 1 13 7.7 %
Date: 2024-04-15 22:23:51
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 "IO/Observer/Helpers.hpp"
       7             : #include "ParallelAlgorithms/LinearSolver/AsynchronousSolvers/ElementActions.hpp"
       8             : #include "ParallelAlgorithms/LinearSolver/Schwarz/ElementActions.hpp"
       9             : #include "Utilities/ProtocolHelpers.hpp"
      10             : #include "Utilities/TMPL.hpp"
      11             : 
      12             : /// Items related to the %Schwarz linear solver
      13             : ///
      14             : /// \see `LinearSolver::Schwarz::Schwarz`
      15             : namespace LinearSolver::Schwarz {
      16             : 
      17             : /*!
      18             :  * \ingroup LinearSolverGroup
      19             :  * \brief An additive Schwarz subdomain solver for linear systems of equations
      20             :  * \f$Ax=b\f$.
      21             :  *
      22             :  * This Schwarz-type linear solver works by solving many sub-problems in
      23             :  * parallel and combining their solutions as a weighted sum to converge towards
      24             :  * the global solution. Each sub-problem is the restriction of the global
      25             :  * problem to an element-centered subdomain, which consists of a central element
      26             :  * and an overlap region with its neighbors. The decomposition into independent
      27             :  * sub-problems makes this linear solver very parallelizable, avoiding global
      28             :  * synchronization points altogether. It is commonly used as a preconditioner to
      29             :  * Krylov-type solvers such as `LinearSolver::gmres::Gmres` or
      30             :  * `LinearSolver::cg::ConjugateGradient`, or as the "smoother" for a Multigrid
      31             :  * solver (which may in turn precondition a Krylov-type solver).
      32             :  *
      33             :  * This linear solver relies on an implementation of the global linear operator
      34             :  * \f$A(x)\f$ and its restriction to a subdomain \f$A_{ss}(x)\f$. Each step of
      35             :  * the algorithm expects that \f$A(x)\f$ is computed and stored in the DataBox
      36             :  * as `db::add_tag_prefix<LinearSolver::Tags::OperatorAppliedTo, operand_tag>`.
      37             :  * To perform a solve, add the `solve` action list to an array parallel
      38             :  * component. Pass the actions that compute \f$A(x)\f$, as well as any further
      39             :  * actions you wish to run in each step of the algorithm, as the first template
      40             :  * parameter to `solve`. If you add the `solve` action list multiple times, use
      41             :  * the second template parameter to label each solve with a different type.
      42             :  * Pass the subdomain operator as the `SubdomainOperator` template parameter to
      43             :  * this class (not to the `solve` action list template). See the paragraph below
      44             :  * for information on implementing a subdomain operator.
      45             :  *
      46             :  * \par Subdomain geometry:
      47             :  * The image below gives an overview of the structure of an element-centered
      48             :  * subdomain:
      49             :  *
      50             :  * \image html subdomain_structure.svg "Fig. 1: An element-centered subdomain" width=600px
      51             :  *
      52             :  * Fig. 1 shows part of a 2-dimensional computational domain. The domain is
      53             :  * composed of elements (light gray) that each carry a Legendre-Gauss-Lobatto
      54             :  * mesh of grid points (black dots). The diagonally shaded region to the left
      55             :  * illustrates an external domain boundary. The lines between neighboring
      56             :  * element faces illustrate mortar meshes, which are relevant when implementing
      57             :  * a subdomain operator in a DG context but play no role in the Schwarz
      58             :  * algorithm. The dashed line gives an example of an element-centered subdomain
      59             :  * with a maximum of 2 grid points of overlap into neighboring elements. For
      60             :  * details on how the number of overlap points is chosen see
      61             :  * `LinearSolver::Schwarz::overlap_extent`. Note that the subdomain does not
      62             :  * extend into corner- or edge-neighbors, which is different to both
      63             :  * \cite Stiller2016a and \cite Vincent2019qpd. The reason we don't include
      64             :  * such diagonal couplings is that in a DG context information only propagates
      65             :  * across faces, as noted in \cite Stiller2016a. By eliminating the corner-
      66             :  * and edge-neighbors we significantly reduce the complexity of the subdomain
      67             :  * geometry and potentially also the communication costs. However, the
      68             :  * advantages and disadvantages of this choice have yet to be carefully
      69             :  * evaluated.
      70             :  *
      71             :  * \par Subdomain operator:
      72             :  * The Schwarz subdomain solver relies on a restriction of the global linear
      73             :  * problem \f$Ax=b\f$ to the subdomains. The subdomain operator
      74             :  * \f$A_{ss}=R_s A R_s^T\f$, where \f$R_s\f$ is the restriction operator,
      75             :  * essentially assumes that its operand is zero everywhere but within the
      76             :  * subdomain (see Section 3.1 in \cite Stiller2016a). Therefore it can be
      77             :  * evaluated entirely on an element-centered subdomain with no need to
      78             :  * communicate with neighbors within each subdomain-operator application, as
      79             :  * opposed to the global linear operator that typically requires
      80             :  * nearest-neighbor communications. See
      81             :  * `LinearSolver::Schwarz::SubdomainOperator` for details on how to
      82             :  * implement a subdomain operator for your problem.
      83             :  *
      84             :  * \par Algorithm overview:
      85             :  * In each iteration, the Schwarz algorithm computes the residual \f$r=b-Ax\f$,
      86             :  * restricts it to all subdomains as \f$r_s=R_s r\f$ and communicates data on
      87             :  * overlap regions with neighboring elements. Once an element has received all
      88             :  * data on its subdomain it solves the sub-problem \f$A_{ss}\delta x_s=r_s\f$
      89             :  * for the correction \f$\delta x_s\f$, where \f$\delta x_s\f$ and \f$r_s\f$
      90             :  * have data only on the points of the subdomain and \f$A_{ss}\f$ is the
      91             :  * subdomain operator. Since all elements perform such a subdomain-solve, we end
      92             :  * up with a subdomain solution \f$\delta x_s\f$ on every subdomain, and the
      93             :  * solutions overlap. Therefore, the algorithm communicates subdomain solutions
      94             :  * on overlap regions with neighboring elements and adds them to the solution
      95             :  * field \f$x\f$ as a weighted sum.
      96             :  *
      97             :  * \par Applying the global linear operator:
      98             :  * In order to compute the residual \f$r=b-Ax\f$ that will be restricted to the
      99             :  * subdomains to serve as source for the subdomain solves, we must apply the
     100             :  * global linear operator \f$A\f$ to the solution field \f$x\f$ once per Schwarz
     101             :  * iteration. The global linear operator typically introduces nearest-neighbor
     102             :  * couplings between elements but no global synchronization point (as opposed to
     103             :  * Krylov-type solvers such as `LinearSolver::gmres::Gmres` that require global
     104             :  * inner products in each iteration). The algorithm assumes that the action list
     105             :  * passed to `solve` applies the global linear operator, as described above.
     106             :  *
     107             :  * \par Subdomain solves:
     108             :  * Each subdomain solve is local to an element, since the data on the subdomain
     109             :  * has been made available through communication with the neighboring elements.
     110             :  * We can now use any means to solve the subdomain problem that's appropriate
     111             :  * for the subdomain operator \f$A_{ss}\f$. For example, if the subdomain
     112             :  * operator was available as an explicit matrix we could invert it directly.
     113             :  * Since it is typically a matrix-free operator a common approach to solve the
     114             :  * subdomain problem is by means of an iterative Krylov-type method, such as
     115             :  * GMRES or Conjugate Gradient, ideally with an appropriate preconditioner (yes,
     116             :  * this would be preconditioned Krylov-methods solving the subdomains of the
     117             :  * Schwarz solver, which might in turn precondition a global Krylov-solver -
     118             :  * it's preconditioners all the way down). Currently, the linear solvers listed
     119             :  * in `LinearSolver::Serial` are available to solve subdomains. They include
     120             :  * Krylov-type methods that support nested preconditioning with any other linear
     121             :  * solver. Additional problem-specific subdomain preconditioners can be added
     122             :  * with the `SubdomainPreconditioners` template parameter. Note that the choice
     123             :  * of subdomain solver (and, by extension, the choice of subdomain
     124             :  * preconditioner) affects only the _performance_ of the Schwarz solver, not its
     125             :  * convergence or parallelization properties (assuming the subdomain solutions
     126             :  * it produces are sufficiently precise).
     127             :  *
     128             :  * \par Weighting:
     129             :  * Once the subdomain solutions \f$\delta x_s\f$ have been found they must be
     130             :  * combined where they have multiple values, i.e. on overlap regions of the
     131             :  * subdomains. We use an additive approach where we combine the subdomain
     132             :  * solutions as a weighted sum, which has the advantage over "multiplicative"
     133             :  * Schwarz methods that the subdomains decouple and can be solved in parallel.
     134             :  * See `LinearSolver::Schwarz::element_weight` and Section 3.1 of
     135             :  * \cite Stiller2016a for details. Note that we must account for the missing
     136             :  * corner- and edge-neighbors when constructing the weights. See
     137             :  * `LinearSolver::Schwarz::intruding_weight` for a discussion.
     138             :  *
     139             :  * \par Array sections
     140             :  * This linear solver requires no synchronization between elements, so it runs
     141             :  * on all elements in the array parallel component. Partitioning of the elements
     142             :  * in sections is only relevant for observing residual norms. Pass the section
     143             :  * ID tag for the `ArraySectionIdTag` template parameter if residual norms
     144             :  * should be computed over a section. Pass `void` (default) to compute residual
     145             :  * norms over all elements in the array.
     146             :  *
     147             :  * \par Possible improvements:
     148             :  * - Specify the number of overlap points as a fraction of the element width
     149             :  * instead of a fixed number. This was shown in \cite Stiller2016b to achieve
     150             :  * scale-independent convergence at the cost of increasing subdomain sizes.
     151             :  */
     152             : template <typename FieldsTag, typename OptionsGroup, typename SubdomainOperator,
     153             :           typename SubdomainPreconditioners = tmpl::list<>,
     154             :           typename SourceTag =
     155             :               db::add_tag_prefix<::Tags::FixedSource, FieldsTag>,
     156             :           typename ArraySectionIdTag = void>
     157           1 : struct Schwarz {
     158           0 :   using operand_tag = FieldsTag;
     159           0 :   using fields_tag = FieldsTag;
     160           0 :   using source_tag = SourceTag;
     161           0 :   using options_group = OptionsGroup;
     162             : 
     163           0 :   using component_list = tmpl::list<>;
     164           0 :   using observed_reduction_data_tags = observers::make_reduction_data_tags<
     165             :       tmpl::list<async_solvers::reduction_data, detail::reduction_data>>;
     166           0 :   using subdomain_solver =
     167             :       detail::subdomain_solver<FieldsTag, SubdomainOperator,
     168             :                                SubdomainPreconditioners>;
     169             : 
     170           0 :   using initialize_element = tmpl::list<
     171             :       async_solvers::InitializeElement<FieldsTag, OptionsGroup, SourceTag>,
     172             :       detail::InitializeElement<FieldsTag, OptionsGroup, SubdomainOperator,
     173             :                                 SubdomainPreconditioners>>;
     174             : 
     175           0 :   using amr_projectors = initialize_element;
     176             : 
     177           0 :   using register_element =
     178             :       tmpl::list<async_solvers::RegisterElement<FieldsTag, OptionsGroup,
     179             :                                                 SourceTag, ArraySectionIdTag>,
     180             :                  detail::RegisterElement<FieldsTag, OptionsGroup, SourceTag,
     181             :                                          ArraySectionIdTag>>;
     182             : 
     183             :   template <typename ApplyOperatorActions, typename Label = OptionsGroup>
     184           0 :   using solve = tmpl::list<
     185             :       async_solvers::PrepareSolve<FieldsTag, OptionsGroup, SourceTag, Label,
     186             :                                   ArraySectionIdTag>,
     187             :       detail::SendOverlapData<FieldsTag, OptionsGroup, SubdomainOperator>,
     188             :       detail::SolveSubdomain<FieldsTag, OptionsGroup, SubdomainOperator,
     189             :                              ArraySectionIdTag>,
     190             :       detail::ReceiveOverlapSolution<FieldsTag, OptionsGroup,
     191             :                                      SubdomainOperator>,
     192             :       ApplyOperatorActions,
     193             :       async_solvers::CompleteStep<FieldsTag, OptionsGroup, SourceTag, Label,
     194             :                                   ArraySectionIdTag>>;
     195             : };
     196             : 
     197             : }  // namespace LinearSolver::Schwarz

Generated by: LCOV version 1.14