SpECTRE Documentation Coverage Report
Current view: top level - ParallelAlgorithms/LinearSolver/Actions - MakeIdentityIfSkipped.hpp Hit Total Coverage
Commit: bcc6763cee2b3f1593fb35e61fb83412a3313e95 Lines: 2 4 50.0 %
Date: 2024-09-16 17:23:19
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 <optional>
       7             : #include <tuple>
       8             : #include <utility>
       9             : 
      10             : #include "DataStructures/DataBox/DataBox.hpp"
      11             : #include "NumericalAlgorithms/Convergence/HasConverged.hpp"
      12             : #include "NumericalAlgorithms/Convergence/Reason.hpp"
      13             : #include "NumericalAlgorithms/Convergence/Tags.hpp"
      14             : #include "Parallel/AlgorithmExecution.hpp"
      15             : #include "ParallelAlgorithms/Actions/Goto.hpp"
      16             : #include "Utilities/Gsl.hpp"
      17             : 
      18             : /// \cond
      19             : namespace tuples {
      20             : template <typename... Tags>
      21             : struct TaggedTuple;
      22             : }  // namespace tuples
      23             : namespace Parallel {
      24             : template <typename Metavariables>
      25             : struct GlobalCache;
      26             : }  // namespace Parallel
      27             : /// \endcond
      28             : 
      29             : namespace LinearSolver {
      30             : /// Actions applicable to any parallel linear solver
      31             : namespace Actions {
      32             : 
      33             : /*!
      34             :  * \brief Make the iterative linear solve the identity operation on the source
      35             :  * vector if no iterations were performed at all. Useful for disabling a
      36             :  * preconditioner by setting its number of iterations to zero.
      37             :  *
      38             :  * When the linear solve is skipped, i.e. when it performs no iterations because
      39             :  * its number of iterations is set to zero, this action assumes \f$A=1\f$ so
      40             :  * \f$Ax=b\f$ solves to \f$x=b\f$. This is useful when the solver is used as
      41             :  * preconditioner, because then we can disable preconditioning by just not
      42             :  * iterating the preconditioner, i.e. by setting its number of iterations to
      43             :  * zero in the input file.
      44             :  *
      45             :  * To use this action, insert it into the action list just after iterating the
      46             :  * linear solver, i.e. after its `solve` action list:
      47             :  *
      48             :  * \snippet LinearSolverAlgorithmTestHelpers.hpp make_identity_if_skipped
      49             :  *
      50             :  * This action will set the `LinearSolverType::fields_tag` to the
      51             :  * `LinearSolverType::source_tag` whenever the linear solver has converged with
      52             :  * the reason `Convergence::Reason::NumIterations` or
      53             :  * `Convergence::Reason::MaxIterations` without actually having performed any
      54             :  * iterations.
      55             :  *
      56             :  * To run additional actions after this action has triggered, i.e. when the
      57             :  * linear solver is skipped, place them after this action and follow them by an
      58             :  * `::Actions::Label<ProceedLabel>`, where `ProceedLabel` is a type used for
      59             :  * identification. Pass the `ProceedLabel` as the second template parameter to
      60             :  * this action. Then, the actions between this action and the label will run
      61             :  * only when the linear solver is skipped. This is useful to set DataBox tags
      62             :  * that are usually updated by the linear solver.
      63             :  *
      64             :  * \par Details:
      65             :  * The standard behaviour of most linear solvers (i.e. when _not_ using this
      66             :  * action) is to keep the fields at their initial guess \f$x=x_0\f$ when it
      67             :  * performs no iterations. That behaviour is not handled well when the solver is
      68             :  * used as preconditioner and its parent always makes it start at \f$x_0=0\f$.
      69             :  * This is a reasonable choice to start the preconditioner but it also means
      70             :  * that the preconditioner doesn't reduce to the identity when it performs no
      71             :  * iterations. Using this action means not iterating the preconditioner at all
      72             :  * essentially disables preconditioning, switching the parent solver to an
      73             :  * unpreconditioned solve with some runtime and memory overhead associated with
      74             :  * initializing the preconditioner.
      75             :  */
      76             : template <typename LinearSolverType, typename ProceedLabel = void>
      77           1 : struct MakeIdentityIfSkipped {
      78             :   template <typename DbTagsList, typename... InboxTags, typename Metavariables,
      79             :             typename ArrayIndex, typename ActionList,
      80             :             typename ParallelComponent>
      81           0 :   static Parallel::iterable_action_return_t apply(
      82             :       db::DataBox<DbTagsList>& box,
      83             :       const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
      84             :       const Parallel::GlobalCache<Metavariables>& /*cache*/,
      85             :       const ArrayIndex& /*array_index*/, const ActionList /*meta*/,
      86             :       const ParallelComponent* const /*meta*/) {
      87             :     constexpr size_t this_action_index =
      88             :         tmpl::index_of<ActionList, MakeIdentityIfSkipped>::value;
      89             :     constexpr size_t proceed_action_index =
      90             :         tmpl::conditional_t<
      91             :             std::is_same_v<ProceedLabel, void>, tmpl::size_t<this_action_index>,
      92             :             tmpl::index_of<ActionList, ::Actions::Label<ProceedLabel>>>::value +
      93             :         1;
      94             : 
      95             :     const auto& has_converged = get<Convergence::Tags::HasConverged<
      96             :         typename LinearSolverType::options_group>>(box);
      97             :     if (has_converged and
      98             :         (has_converged.reason() == Convergence::Reason::NumIterations or
      99             :          has_converged.reason() == Convergence::Reason::MaxIterations) and
     100             :         has_converged.num_iterations() == 0) {
     101             :       db::mutate<typename LinearSolverType::fields_tag>(
     102             :           [](const auto fields, const auto& source) { *fields = source; },
     103             :           make_not_null(&box), get<typename LinearSolverType::source_tag>(box));
     104             :       return {Parallel::AlgorithmExecution::Continue, std::nullopt};
     105             :     }
     106             :     return {Parallel::AlgorithmExecution::Continue, proceed_action_index};
     107             :   }
     108             : };
     109             : 
     110             : namespace detail {
     111             : template <typename Tag>
     112             : struct ProceedLabel {};
     113             : }  // namespace detail
     114             : 
     115             : /// Run `MakeIdentityIfSkipped`, and also run the `BuildOperatorActions` if
     116             : /// the linear solver is skipped. See `MakeIdentityIfSkipped` for details.
     117             : template <typename LinearSolverType,
     118             :           typename BuildOperatorActions = tmpl::list<>,
     119             :           typename Label = typename LinearSolverType::options_group>
     120           1 : using make_identity_if_skipped = tmpl::conditional_t<
     121             :     std::is_same_v<BuildOperatorActions, tmpl::list<>>,
     122             :     MakeIdentityIfSkipped<LinearSolverType>,
     123             :     tmpl::list<
     124             :         MakeIdentityIfSkipped<LinearSolverType, detail::ProceedLabel<Label>>,
     125             :         BuildOperatorActions, ::Actions::Label<detail::ProceedLabel<Label>>>>;
     126             : 
     127             : }  // namespace Actions
     128             : }  // namespace LinearSolver

Generated by: LCOV version 1.14