SpECTRE Documentation Coverage Report
Current view: top level - ParallelAlgorithms/LinearSolver/Schwarz - ElementActions.hpp Hit Total Coverage
Commit: edb1b5199a4a86c269aedbb831767801169f3e8a Lines: 0 1 0.0 %
Date: 2021-04-19 16:23: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             : #include <map>
       8             : #include <string>
       9             : #include <tuple>
      10             : #include <unordered_map>
      11             : #include <utility>
      12             : #include <vector>
      13             : 
      14             : #include "DataStructures/DataBox/DataBox.hpp"
      15             : #include "DataStructures/DataBox/PrefixHelpers.hpp"
      16             : #include "DataStructures/DataBox/Tag.hpp"
      17             : #include "DataStructures/Index.hpp"
      18             : #include "Domain/InterfaceComputeTags.hpp"
      19             : #include "Domain/InterfaceHelpers.hpp"
      20             : #include "Domain/Structure/Element.hpp"
      21             : #include "Domain/Structure/ElementId.hpp"
      22             : #include "Domain/Structure/OrientationMapHelpers.hpp"
      23             : #include "Domain/Tags.hpp"
      24             : #include "IO/Observer/Actions/RegisterWithObservers.hpp"
      25             : #include "IO/Observer/ArrayComponentId.hpp"
      26             : #include "IO/Observer/ObservationId.hpp"
      27             : #include "IO/Observer/Protocols/ReductionDataFormatter.hpp"
      28             : #include "IO/Observer/ReductionActions.hpp"
      29             : #include "IO/Observer/TypeOfObservation.hpp"
      30             : #include "Informer/Tags.hpp"
      31             : #include "Informer/Verbosity.hpp"
      32             : #include "NumericalAlgorithms/Convergence/Tags.hpp"
      33             : #include "NumericalAlgorithms/LinearSolver/ExplicitInverse.hpp"
      34             : #include "NumericalAlgorithms/LinearSolver/Gmres.hpp"
      35             : #include "NumericalAlgorithms/Spectral/Mesh.hpp"
      36             : #include "NumericalAlgorithms/Spectral/Spectral.hpp"
      37             : #include "Options/Options.hpp"
      38             : #include "Parallel/GlobalCache.hpp"
      39             : #include "Parallel/InboxInserters.hpp"
      40             : #include "Parallel/Invoke.hpp"
      41             : #include "Parallel/ParallelComponentHelpers.hpp"
      42             : #include "Parallel/Printf.hpp"
      43             : #include "Parallel/Reduction.hpp"
      44             : #include "ParallelAlgorithms/DiscontinuousGalerkin/HasReceivedFromAllMortars.hpp"
      45             : #include "ParallelAlgorithms/Initialization/MergeIntoDataBox.hpp"
      46             : #include "ParallelAlgorithms/Initialization/MutateAssign.hpp"
      47             : #include "ParallelAlgorithms/LinearSolver/Schwarz/Actions/CommunicateOverlapFields.hpp"
      48             : #include "ParallelAlgorithms/LinearSolver/Schwarz/ComputeTags.hpp"
      49             : #include "ParallelAlgorithms/LinearSolver/Schwarz/ElementCenteredSubdomainData.hpp"
      50             : #include "ParallelAlgorithms/LinearSolver/Schwarz/OverlapHelpers.hpp"
      51             : #include "ParallelAlgorithms/LinearSolver/Schwarz/Tags.hpp"
      52             : #include "ParallelAlgorithms/LinearSolver/Tags.hpp"
      53             : #include "Utilities/Gsl.hpp"
      54             : #include "Utilities/PrettyType.hpp"
      55             : #include "Utilities/ProtocolHelpers.hpp"
      56             : #include "Utilities/TMPL.hpp"
      57             : #include "Utilities/TaggedTuple.hpp"
      58             : 
      59             : namespace LinearSolver::Schwarz::detail {
      60             : 
      61             : using reduction_data = Parallel::ReductionData<
      62             :     // Iteration
      63             :     Parallel::ReductionDatum<size_t, funcl::AssertEqual<>>,
      64             :     // Number of subdomains (= number of elements)
      65             :     Parallel::ReductionDatum<size_t, funcl::Plus<>>,
      66             :     // Average number of subdomain solver iterations
      67             :     Parallel::ReductionDatum<size_t, funcl::Plus<>, funcl::Divides<>,
      68             :                              std::index_sequence<1>>,
      69             :     // Minimum number of subdomain solver iterations
      70             :     Parallel::ReductionDatum<size_t, funcl::Min<>>,
      71             :     // Maximum number of subdomain solver iterations
      72             :     Parallel::ReductionDatum<size_t, funcl::Max<>>>;
      73             : 
      74             : template <typename OptionsGroup>
      75             : struct SubdomainStatsFormatter
      76             :     : tt::ConformsTo<observers::protocols::ReductionDataFormatter> {
      77             :   using reduction_data = Schwarz::detail::reduction_data;
      78             :   std::string operator()(const size_t iteration_id, const size_t num_subdomains,
      79             :                          const size_t avg_subdomain_its,
      80             :                          const size_t min_subdomain_its,
      81             :                          const size_t max_subdomain_its) const noexcept {
      82             :     return Options::name<OptionsGroup>() + "(" + get_output(iteration_id) +
      83             :            ") completed all " + get_output(num_subdomains) +
      84             :            " subdomain solves. Average of number of iterations: " +
      85             :            get_output(avg_subdomain_its) + " (min " +
      86             :            get_output(min_subdomain_its) + ", max " +
      87             :            get_output(max_subdomain_its) + ").";
      88             :   }
      89             :   // NOLINTNEXTLINE(google-runtime-references)
      90             :   void pup(PUP::er& /*p*/) noexcept {}
      91             : };
      92             : 
      93             : template <typename OptionsGroup>
      94             : struct RegisterObservers {
      95             :   template <typename ParallelComponent, typename DbTagsList,
      96             :             typename ArrayIndex>
      97             :   static std::pair<observers::TypeOfObservation, observers::ObservationKey>
      98             :   register_info(const db::DataBox<DbTagsList>& /*box*/,
      99             :                 const ArrayIndex& /*array_index*/) noexcept {
     100             :     return {observers::TypeOfObservation::Reduction,
     101             :             observers::ObservationKey{pretty_type::get_name<OptionsGroup>() +
     102             :                                       "SubdomainSolves"}};
     103             :   }
     104             : };
     105             : 
     106             : template <typename FieldsTag, typename OptionsGroup, typename SourceTag>
     107             : using RegisterElement =
     108             :     observers::Actions::RegisterWithObservers<RegisterObservers<OptionsGroup>>;
     109             : 
     110             : template <typename OptionsGroup, typename ParallelComponent,
     111             :           typename Metavariables, typename ArrayIndex>
     112             : void contribute_to_subdomain_stats_observation(
     113             :     const size_t iteration_id, const size_t subdomain_solve_num_iterations,
     114             :     Parallel::GlobalCache<Metavariables>& cache,
     115             :     const ArrayIndex& array_index) noexcept {
     116             :   auto& local_observer =
     117             :       *Parallel::get_parallel_component<observers::Observer<Metavariables>>(
     118             :            cache)
     119             :            .ckLocalBranch();
     120             :   auto formatter =
     121             :       UNLIKELY(get<logging::Tags::Verbosity<OptionsGroup>>(cache) >=
     122             :                ::Verbosity::Verbose)
     123             :           ? std::make_optional(SubdomainStatsFormatter<OptionsGroup>{})
     124             :           : std::nullopt;
     125             :   Parallel::simple_action<observers::Actions::ContributeReductionData>(
     126             :       local_observer,
     127             :       observers::ObservationId(
     128             :           iteration_id,
     129             :           pretty_type::get_name<OptionsGroup>() + "SubdomainSolves"),
     130             :       observers::ArrayComponentId{
     131             :           std::add_pointer_t<ParallelComponent>{nullptr},
     132             :           Parallel::ArrayIndex<ArrayIndex>(array_index)},
     133             :       std::string{"/" + Options::name<OptionsGroup>() + "SubdomainSolves"},
     134             :       std::vector<std::string>{"Iteration", "NumSubdomains", "AvgNumIterations",
     135             :                                "MinNumIterations", "MaxNumIterations"},
     136             :       reduction_data{iteration_id, 1, subdomain_solve_num_iterations,
     137             :                      subdomain_solve_num_iterations,
     138             :                      subdomain_solve_num_iterations},
     139             :       std::move(formatter));
     140             : }
     141             : 
     142             : template <typename SubdomainDataType, typename OptionsGroup>
     143             : struct SubdomainDataBufferTag : db::SimpleTag {
     144             :   static std::string name() noexcept {
     145             :     return "SubdomainData(" + Options::name<OptionsGroup>() + ")";
     146             :   }
     147             :   using type = SubdomainDataType;
     148             : };
     149             : 
     150             : // Allow factory-creating any of these serial linear solvers for use as
     151             : // subdomain solver
     152             : template <typename FieldsTag, typename SubdomainOperator,
     153             :           typename SubdomainData = ElementCenteredSubdomainData<
     154             :               SubdomainOperator::volume_dim,
     155             :               typename db::add_tag_prefix<LinearSolver::Tags::Residual,
     156             :                                           FieldsTag>::tags_list>>
     157             : using subdomain_solver = LinearSolver::Serial::LinearSolver<
     158             :     tmpl::list<::LinearSolver::Serial::Registrars::Gmres<SubdomainData>,
     159             :                ::LinearSolver::Serial::Registrars::ExplicitInverse>>;
     160             : 
     161             : template <typename FieldsTag, typename OptionsGroup, typename SubdomainOperator>
     162             : struct InitializeElement {
     163             :  private:
     164             :   using fields_tag = FieldsTag;
     165             :   using residual_tag =
     166             :       db::add_tag_prefix<LinearSolver::Tags::Residual, fields_tag>;
     167             :   static constexpr size_t Dim = SubdomainOperator::volume_dim;
     168             :   using SubdomainData =
     169             :       ElementCenteredSubdomainData<Dim, typename residual_tag::tags_list>;
     170             :   using subdomain_solver_tag = Tags::SubdomainSolver<
     171             :       std::unique_ptr<subdomain_solver<FieldsTag, SubdomainOperator>>,
     172             :       OptionsGroup>;
     173             : 
     174             :  public:
     175             :   using initialization_tags =
     176             :       tmpl::list<domain::Tags::InitialExtents<Dim>, subdomain_solver_tag>;
     177             :   using initialization_tags_to_keep = tmpl::list<subdomain_solver_tag>;
     178             :   using const_global_cache_tags = tmpl::list<Tags::MaxOverlap<OptionsGroup>>;
     179             : 
     180             :   using simple_tags =
     181             :       tmpl::list<Tags::Overlaps<residual_tag, Dim, OptionsGroup>,
     182             :                  SubdomainDataBufferTag<SubdomainData, OptionsGroup>>;
     183             :   using compute_tags = tmpl::list<
     184             :       domain::Tags::InternalDirectionsCompute<Dim>,
     185             :       domain::Tags::BoundaryDirectionsInteriorCompute<Dim>,
     186             :       domain::Tags::InterfaceCompute<domain::Tags::InternalDirections<Dim>,
     187             :                                      domain::Tags::Direction<Dim>>,
     188             :       domain::Tags::InterfaceCompute<
     189             :           domain::Tags::BoundaryDirectionsInterior<Dim>,
     190             :           domain::Tags::Direction<Dim>>,
     191             :       Tags::IntrudingExtentsCompute<Dim, OptionsGroup>,
     192             :       Tags::IntrudingOverlapWidthsCompute<Dim, OptionsGroup>,
     193             :       domain::Tags::LogicalCoordinates<Dim>,
     194             :       Tags::ElementWeightCompute<Dim, OptionsGroup>,
     195             :       domain::Tags::InterfaceCompute<
     196             :           domain::Tags::InternalDirections<Dim>,
     197             :           Tags::IntrudingOverlapWeightCompute<Dim, OptionsGroup>>>;
     198             :   template <typename DbTagsList, typename... InboxTags, typename Metavariables,
     199             :             typename ActionList, typename ParallelComponent>
     200             :   static auto apply(db::DataBox<DbTagsList>& box,
     201             :                     const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
     202             :                     const Parallel::GlobalCache<Metavariables>& /*cache*/,
     203             :                     const ElementId<Dim>& /*element_id*/,
     204             :                     const ActionList /*meta*/,
     205             :                     const ParallelComponent* const /*meta*/) noexcept {
     206             :     const auto& element_mesh = db::get<domain::Tags::Mesh<Dim>>(box);
     207             :     const size_t element_num_points = element_mesh.number_of_grid_points();
     208             :     Initialization::mutate_assign<
     209             :         tmpl::list<SubdomainDataBufferTag<SubdomainData, OptionsGroup>>>(
     210             :         make_not_null(&box), SubdomainData{element_num_points});
     211             :     return std::make_tuple(std::move(box));
     212             :   }
     213             : };
     214             : 
     215             : // Restrict the residual to neighboring subdomains that overlap with this
     216             : // element and send the data to those elements
     217             : template <typename FieldsTag, typename OptionsGroup, typename SubdomainOperator>
     218             : using SendOverlapData = LinearSolver::Schwarz::Actions::SendOverlapFields<
     219             :     tmpl::list<db::add_tag_prefix<LinearSolver::Tags::Residual, FieldsTag>>,
     220             :     OptionsGroup, true>;
     221             : 
     222             : // Wait for the residual data on regions of this element's subdomain that
     223             : // overlap with other elements.
     224             : template <typename FieldsTag, typename OptionsGroup, typename SubdomainOperator>
     225             : using ReceiveOverlapData = LinearSolver::Schwarz::Actions::ReceiveOverlapFields<
     226             :     SubdomainOperator::volume_dim,
     227             :     tmpl::list<db::add_tag_prefix<LinearSolver::Tags::Residual, FieldsTag>>,
     228             :     OptionsGroup>;
     229             : 
     230             : template <size_t Dim, typename OptionsGroup, typename OverlapSolution>
     231             : struct OverlapSolutionInboxTag
     232             :     : public Parallel::InboxInserters::Map<
     233             :           OverlapSolutionInboxTag<Dim, OptionsGroup, OverlapSolution>> {
     234             :   using temporal_id = size_t;
     235             :   using type = std::map<temporal_id, OverlapMap<Dim, OverlapSolution>>;
     236             : };
     237             : 
     238             : // Once the residual data is available on all overlaps, solve the restricted
     239             : // problem for this element-centered subdomain. Apply the weighted solution on
     240             : // this element directly and send the solution on overlap regions to the
     241             : // neighbors that they overlap with.
     242             : template <typename FieldsTag, typename OptionsGroup, typename SubdomainOperator>
     243             : struct SolveSubdomain {
     244             :  private:
     245             :   using fields_tag = FieldsTag;
     246             :   using residual_tag =
     247             :       db::add_tag_prefix<LinearSolver::Tags::Residual, fields_tag>;
     248             :   static constexpr size_t Dim = SubdomainOperator::volume_dim;
     249             :   using SubdomainData =
     250             :       ElementCenteredSubdomainData<Dim, typename residual_tag::tags_list>;
     251             :   using OverlapData = typename SubdomainData::OverlapData;
     252             :   using overlap_solution_inbox_tag =
     253             :       OverlapSolutionInboxTag<Dim, OptionsGroup, OverlapData>;
     254             : 
     255             :  public:
     256             :   using const_global_cache_tags =
     257             :       tmpl::list<Tags::MaxOverlap<OptionsGroup>,
     258             :                  logging::Tags::Verbosity<OptionsGroup>>;
     259             : 
     260             :   template <typename DbTagsList, typename... InboxTags, typename Metavariables,
     261             :             typename ActionList, typename ParallelComponent>
     262             :   static std::tuple<db::DataBox<DbTagsList>&&> apply(
     263             :       db::DataBox<DbTagsList>& box,
     264             :       const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
     265             :       Parallel::GlobalCache<Metavariables>& cache,
     266             :       const ElementId<Dim>& element_id, const ActionList /*meta*/,
     267             :       const ParallelComponent* const /*meta*/) noexcept {
     268             :     const size_t iteration_id =
     269             :         get<Convergence::Tags::IterationId<OptionsGroup>>(box);
     270             : 
     271             :     // Do some logging
     272             :     if (UNLIKELY(get<logging::Tags::Verbosity<OptionsGroup>>(box) >=
     273             :                  ::Verbosity::Debug)) {
     274             :       Parallel::printf("%s %s(%zu): Solve subdomain\n", element_id,
     275             :                        Options::name<OptionsGroup>(), iteration_id);
     276             :     }
     277             : 
     278             :     const auto& element = db::get<domain::Tags::Element<Dim>>(box);
     279             :     const size_t max_overlap = db::get<Tags::MaxOverlap<OptionsGroup>>(box);
     280             : 
     281             :     // Assemble the subdomain data from the data on the element and the
     282             :     // communicated overlap data
     283             :     db::mutate<SubdomainDataBufferTag<SubdomainData, OptionsGroup>,
     284             :                Tags::Overlaps<residual_tag, Dim, OptionsGroup>>(
     285             :         make_not_null(&box),
     286             :         [max_overlap, &element](
     287             :             const gsl::not_null<SubdomainData*> subdomain_data,
     288             :             const auto overlap_residuals, const auto& residual) noexcept {
     289             :           subdomain_data->element_data = residual;
     290             :           // Nothing was communicated if the overlaps are empty
     291             :           if (LIKELY(max_overlap > 0 and element.number_of_neighbors() > 0)) {
     292             :             subdomain_data->overlap_data = std::move(*overlap_residuals);
     293             :           }
     294             :         },
     295             :         db::get<residual_tag>(box));
     296             :     const auto& subdomain_residual =
     297             :         db::get<SubdomainDataBufferTag<SubdomainData, OptionsGroup>>(box);
     298             : 
     299             :     // Allocate workspace memory for repeatedly applying the subdomain operator
     300             :     SubdomainOperator subdomain_operator{};
     301             : 
     302             :     // Construct the subdomain operator
     303             :     const auto apply_subdomain_operator =
     304             :         [&box, &subdomain_operator](const gsl::not_null<SubdomainData*> result,
     305             :                                     const SubdomainData& operand) noexcept {
     306             :       // The subdomain operator can retrieve any information on the subdomain
     307             :       // geometry that is available through the DataBox. The user is responsible
     308             :       // for communicating this information across neighbors if necessary.
     309             :       subdomain_operator(result, operand, box);
     310             :     };
     311             : 
     312             :     // Solve the subdomain problem
     313             :     const auto& subdomain_solver =
     314             :         get<Tags::SubdomainSolverBase<OptionsGroup>>(box);
     315             :     auto subdomain_solve_initial_guess_in_solution_out =
     316             :         make_with_value<SubdomainData>(subdomain_residual, 0.);
     317             :     const auto subdomain_solve_has_converged = subdomain_solver.solve(
     318             :         make_not_null(&subdomain_solve_initial_guess_in_solution_out),
     319             :         apply_subdomain_operator, subdomain_residual);
     320             :     // Re-naming the solution buffer for the code below
     321             :     auto& subdomain_solution = subdomain_solve_initial_guess_in_solution_out;
     322             : 
     323             :     // Do some logging and observing
     324             :     if (UNLIKELY(get<logging::Tags::Verbosity<OptionsGroup>>(box) >=
     325             :                  ::Verbosity::Quiet)) {
     326             :       if (not subdomain_solve_has_converged or
     327             :           subdomain_solve_has_converged.reason() ==
     328             :               Convergence::Reason::MaxIterations) {
     329             :         Parallel::printf(
     330             :             "%s %s(%zu): WARNING: Subdomain solver did not converge in %zu "
     331             :             "iterations: %e -> %e\n",
     332             :             element_id, Options::name<OptionsGroup>(), iteration_id,
     333             :             subdomain_solve_has_converged.num_iterations(),
     334             :             subdomain_solve_has_converged.initial_residual_magnitude(),
     335             :             subdomain_solve_has_converged.residual_magnitude());
     336             :       } else if (UNLIKELY(get<logging::Tags::Verbosity<OptionsGroup>>(box) >=
     337             :                           ::Verbosity::Debug)) {
     338             :         Parallel::printf(
     339             :             "%s %s(%zu): Subdomain solver converged in %zu iterations (%s): %e "
     340             :             "-> %e\n",
     341             :             element_id, Options::name<OptionsGroup>(), iteration_id,
     342             :             subdomain_solve_has_converged.num_iterations(),
     343             :             subdomain_solve_has_converged.reason(),
     344             :             subdomain_solve_has_converged.initial_residual_magnitude(),
     345             :             subdomain_solve_has_converged.residual_magnitude());
     346             :       }
     347             :     }
     348             :     contribute_to_subdomain_stats_observation<OptionsGroup, ParallelComponent>(
     349             :         iteration_id + 1, subdomain_solve_has_converged.num_iterations(), cache,
     350             :         element_id);
     351             : 
     352             :     // Apply weighting
     353             :     if (LIKELY(max_overlap > 0)) {
     354             :       subdomain_solution.element_data *=
     355             :           get(db::get<Tags::Weight<OptionsGroup>>(box));
     356             :     }
     357             : 
     358             :     // Apply solution to central element
     359             :     db::mutate<fields_tag>(make_not_null(&box),
     360             :                            [&subdomain_solution](const auto fields) noexcept {
     361             :                              *fields += subdomain_solution.element_data;
     362             :                            });
     363             : 
     364             :     // Send overlap solutions back to the neighbors that they are on
     365             :     if (LIKELY(max_overlap > 0)) {
     366             :       auto& receiver_proxy =
     367             :           Parallel::get_parallel_component<ParallelComponent>(cache);
     368             :       for (auto& [overlap_id, overlap_solution] :
     369             :            subdomain_solution.overlap_data) {
     370             :         const auto& direction = overlap_id.first;
     371             :         const auto& neighbor_id = overlap_id.second;
     372             :         const auto& orientation =
     373             :             element.neighbors().at(direction).orientation();
     374             :         const auto direction_from_neighbor = orientation(direction.opposite());
     375             :         Parallel::receive_data<overlap_solution_inbox_tag>(
     376             :             receiver_proxy[neighbor_id], iteration_id,
     377             :             std::make_pair(
     378             :                 OverlapId<Dim>{direction_from_neighbor, element.id()},
     379             :                 std::move(overlap_solution)));
     380             :       }
     381             :     }
     382             :     return {std::move(box)};
     383             :   }
     384             : };
     385             : 
     386             : // Wait for the subdomain solutions on regions within this element that overlap
     387             : // with neighboring element-centered subdomains. Combine the solutions as a
     388             : // weighted sum.
     389             : template <typename FieldsTag, typename OptionsGroup, typename SubdomainOperator>
     390             : struct ReceiveOverlapSolution {
     391             :  private:
     392             :   using fields_tag = FieldsTag;
     393             :   using residual_tag =
     394             :       db::add_tag_prefix<LinearSolver::Tags::Residual, fields_tag>;
     395             :   static constexpr size_t Dim = SubdomainOperator::volume_dim;
     396             :   using SubdomainData =
     397             :       ElementCenteredSubdomainData<Dim, typename residual_tag::tags_list>;
     398             :   using OverlapSolution = typename SubdomainData::OverlapData;
     399             :   using overlap_solution_inbox_tag =
     400             :       OverlapSolutionInboxTag<Dim, OptionsGroup, OverlapSolution>;
     401             : 
     402             :  public:
     403             :   using const_global_cache_tags = tmpl::list<Tags::MaxOverlap<OptionsGroup>>;
     404             :   using inbox_tags = tmpl::list<overlap_solution_inbox_tag>;
     405             : 
     406             :   template <typename DbTagsList, typename... InboxTags, typename Metavariables,
     407             :             size_t Dim>
     408             :   static bool is_ready(const db::DataBox<DbTagsList>& box,
     409             :                        const tuples::TaggedTuple<InboxTags...>& inboxes,
     410             :                        const Parallel::GlobalCache<Metavariables>& /*cache*/,
     411             :                        const ElementId<Dim>& /*element_id*/) noexcept {
     412             :     if (UNLIKELY(db::get<Tags::MaxOverlap<OptionsGroup>>(box) == 0)) {
     413             :       return true;
     414             :     }
     415             :     return dg::has_received_from_all_mortars<overlap_solution_inbox_tag>(
     416             :         get<Convergence::Tags::IterationId<OptionsGroup>>(box),
     417             :         get<domain::Tags::Element<Dim>>(box), inboxes);
     418             :   }
     419             : 
     420             :   template <typename DbTagsList, typename... InboxTags, typename Metavariables,
     421             :             typename ActionList, typename ParallelComponent>
     422             :   static std::tuple<db::DataBox<DbTagsList>&&> apply(
     423             :       db::DataBox<DbTagsList>& box, tuples::TaggedTuple<InboxTags...>& inboxes,
     424             :       const Parallel::GlobalCache<Metavariables>& /*cache*/,
     425             :       const ElementId<Dim>& element_id, const ActionList /*meta*/,
     426             :       const ParallelComponent* const /*meta*/) noexcept {
     427             :     const size_t iteration_id =
     428             :         get<Convergence::Tags::IterationId<OptionsGroup>>(box);
     429             :     const auto& element = db::get<domain::Tags::Element<Dim>>(box);
     430             : 
     431             :     // Nothing to do if overlap is empty
     432             :     if (UNLIKELY(db::get<Tags::MaxOverlap<OptionsGroup>>(box) == 0 or
     433             :                  element.number_of_neighbors() == 0)) {
     434             :       return {std::move(box)};
     435             :     }
     436             : 
     437             :     // Do some logging
     438             :     if (UNLIKELY(get<logging::Tags::Verbosity<OptionsGroup>>(box) >=
     439             :                  ::Verbosity::Debug)) {
     440             :       Parallel::printf("%s %s(%zu): Receive overlap solution\n", element_id,
     441             :                        Options::name<OptionsGroup>(), iteration_id);
     442             :     }
     443             : 
     444             :     // Add solutions on overlaps to this element's solution in a weighted sum
     445             :     const auto received_overlap_solutions =
     446             :         std::move(tuples::get<overlap_solution_inbox_tag>(inboxes)
     447             :                       .extract(iteration_id)
     448             :                       .mapped());
     449             :     db::mutate<fields_tag>(
     450             :         make_not_null(&box),
     451             :         [&received_overlap_solutions](
     452             :             const auto fields, const Index<Dim>& full_extents,
     453             :             const std::array<size_t, Dim>& all_intruding_extents,
     454             :             const std::unordered_map<Direction<Dim>, Scalar<DataVector>>&
     455             :                 all_intruding_overlap_weights) noexcept {
     456             :           for (const auto& [overlap_id, overlap_solution] :
     457             :                received_overlap_solutions) {
     458             :             const auto& direction = overlap_id.first;
     459             :             const auto& intruding_extents =
     460             :                 gsl::at(all_intruding_extents, direction.dimension());
     461             :             const auto& overlap_weight =
     462             :                 all_intruding_overlap_weights.at(direction);
     463             :             LinearSolver::Schwarz::add_overlap_data(
     464             :                 fields, overlap_solution * get(overlap_weight), full_extents,
     465             :                 intruding_extents, direction);
     466             :           }
     467             :         },
     468             :         db::get<domain::Tags::Mesh<Dim>>(box).extents(),
     469             :         db::get<Tags::IntrudingExtents<Dim, OptionsGroup>>(box),
     470             :         db::get<domain::Tags::Interface<domain::Tags::InternalDirections<Dim>,
     471             :                                         Tags::Weight<OptionsGroup>>>(box));
     472             :     return {std::move(box)};
     473             :   }
     474             : };
     475             : 
     476             : }  // namespace LinearSolver::Schwarz::detail

Generated by: LCOV version 1.14