SpECTRE Documentation Coverage Report
Current view: top level - ParallelAlgorithms/LinearSolver/Actions - MakeIdentityIfSkipped.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 50.0 % 4 2
Test Date: 2026-10-22 17:29:42
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 2.0-1