SpECTRE Documentation Coverage Report
Current view: top level - Parallel/ArrayCollection - CreateElementsUsingDistribution.hpp Coverage Total Hit
Commit: a37d7b3c1803b88b537d2aef1c27ca5e6b499398 Lines: 50.0 % 2 1
Test Date: 2026-11-12 04:47: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 <array>
       7              : #include <cstddef>
       8              : #include <functional>
       9              : #include <optional>
      10              : #include <unordered_map>
      11              : #include <unordered_set>
      12              : #include <vector>
      13              : 
      14              : #include "Domain/Block.hpp"
      15              : #include "Domain/ElementDistribution.hpp"
      16              : #include "Domain/Structure/ElementId.hpp"
      17              : #include "Domain/Structure/InitialElementIds.hpp"
      18              : #include "Parallel/DomainDiagnosticInfo.hpp"
      19              : #include "Parallel/GlobalCache.hpp"
      20              : #include "Utilities/Numeric.hpp"
      21              : 
      22              : /// \cond
      23              : namespace Spectral {
      24              : enum class Basis : uint8_t;
      25              : enum class Quadrature : uint8_t;
      26              : }  // namespace Spectral
      27              : /// \endcond
      28              : 
      29              : namespace Parallel {
      30              : /*!
      31              :  * \brief Creates elements using a chosen distribution.
      32              :  *
      33              :  * The `func` is called with `(element_id, target_proc, target_node)` allowing
      34              :  * the `func` to insert the element with `element_id` on the target processor
      35              :  * and node.
      36              :  *
      37              :  * The `weighting_extents_override`, if present, gives per-element extents to
      38              :  * use instead of `initial_extents` only when computing the cost of elements
      39              :  * for the distribution (e.g. to weight elements that run the finite-difference
      40              :  * subcell scheme by their finite-difference grid rather than their DG grid).
      41              :  * Only elements whose weighting extents differ from `initial_extents` need an
      42              :  * entry; elements not found in the map use their block's `initial_extents`.
      43              :  * The actual `initial_extents` are always used for everything else, e.g. the
      44              :  * diagnostics below.
      45              :  */
      46              : template <typename F, size_t Dim, typename Metavariables>
      47            1 : void create_elements_using_distribution(
      48              :     const F& func, const std::optional<domain::ElementWeight>& element_weight,
      49              :     const std::vector<Block<Dim>>& blocks,
      50              :     const std::vector<std::array<size_t, Dim>>& initial_extents,
      51              :     const std::vector<std::array<size_t, Dim>>& initial_refinement_levels,
      52              :     const Spectral::Basis i1_basis, const Spectral::Quadrature i1_quadrature,
      53              : 
      54              :     const std::unordered_set<size_t>& procs_to_ignore,
      55              :     const size_t number_of_procs, const size_t number_of_nodes,
      56              :     const size_t num_of_procs_to_use,
      57              :     const Parallel::GlobalCache<Metavariables>& local_cache,
      58              :     const bool print_diagnostics,
      59              :     const std::optional<
      60              :         std::unordered_map<ElementId<Dim>, std::array<size_t, Dim>>>&
      61              :         weighting_extents_override = std::nullopt) {
      62              :   // Only need the element distribution if the element weight has a value
      63              :   // because then we have to use the space filling curve and not just use round
      64              :   // robin.
      65              :   domain::BlockZCurveProcDistribution<Dim> element_distribution{};
      66              :   if (element_weight.has_value()) {
      67              :     const std::unordered_map<ElementId<Dim>, std::array<size_t, Dim>>
      68              :         no_override{};
      69              :     const std::unordered_map<ElementId<Dim>, double> element_costs =
      70              :         domain::get_element_costs(blocks, initial_refinement_levels,
      71              :                                   initial_extents, element_weight.value(),
      72              :                                   i1_basis, i1_quadrature,
      73              :                                   weighting_extents_override.has_value()
      74              :                                       ? weighting_extents_override.value()
      75              :                                       : no_override);
      76              :     element_distribution = domain::BlockZCurveProcDistribution<Dim>{
      77              :         element_costs, num_of_procs_to_use, blocks, initial_refinement_levels,
      78              :         procs_to_ignore};
      79              :   }
      80              : 
      81              :   // Will be used to print domain diagnostic info
      82              :   std::vector<size_t> elements_per_core(number_of_procs, 0_st);
      83              :   std::vector<size_t> elements_per_node(number_of_nodes, 0_st);
      84              :   std::vector<size_t> grid_points_per_core(number_of_procs, 0_st);
      85              :   std::vector<size_t> grid_points_per_node(number_of_nodes, 0_st);
      86              : 
      87              :   size_t which_proc = 0;
      88              :   for (const auto& block : blocks) {
      89              :     const auto& initial_ref_levs = initial_refinement_levels[block.id()];
      90              :     const size_t grid_points_per_element =
      91              :         alg::accumulate(initial_extents[block.id()], 1_st, std::multiplies<>());
      92              : 
      93              :     const std::vector<ElementId<Dim>> element_ids =
      94              :         initial_element_ids(block.id(), initial_ref_levs);
      95              : 
      96              :     // Value means ZCurve. nullopt means round robin
      97              :     if (element_weight.has_value()) {
      98              :       for (const auto& element_id : element_ids) {
      99              :         const size_t target_proc =
     100              :             element_distribution.get_proc_for_element(element_id);
     101              :         const size_t target_node =
     102              :             Parallel::node_of<size_t>(target_proc, local_cache);
     103              :         func(element_id, target_proc, target_node);
     104              : 
     105              :         ++elements_per_core[target_proc];
     106              :         ++elements_per_node[target_node];
     107              :         grid_points_per_core[target_proc] += grid_points_per_element;
     108              :         grid_points_per_node[target_node] += grid_points_per_element;
     109              :       }
     110              :     } else {
     111              :       for (size_t i = 0; i < element_ids.size(); ++i) {
     112              :         while (procs_to_ignore.find(which_proc) != procs_to_ignore.end()) {
     113              :           which_proc = which_proc + 1 == number_of_procs ? 0 : which_proc + 1;
     114              :         }
     115              :         const size_t target_proc = which_proc;
     116              :         const size_t target_node =
     117              :             Parallel::node_of<size_t>(which_proc, local_cache);
     118              :         const ElementId<Dim> element_id(element_ids[i]);
     119              :         func(element_id, target_proc, target_node);
     120              : 
     121              :         ++elements_per_core[which_proc];
     122              :         ++elements_per_node[target_node];
     123              :         grid_points_per_core[which_proc] += grid_points_per_element;
     124              :         grid_points_per_node[target_node] += grid_points_per_element;
     125              : 
     126              :         which_proc = which_proc + 1 == number_of_procs ? 0 : which_proc + 1;
     127              :       }
     128              :     }
     129              :   }
     130              : 
     131              :   if (print_diagnostics) {
     132              :     Parallel::printf("\n%s\n", domain::diagnostic_info(
     133              :                                    blocks.size(), local_cache,
     134              :                                    elements_per_core, elements_per_node,
     135              :                                    grid_points_per_core, grid_points_per_node));
     136              :   }
     137              : }
     138              : }  // namespace Parallel
        

Generated by: LCOV version 2.0-1