|
| 1 | +// Distributed under the MIT License. |
| 2 | +// See LICENSE.txt for details. |
| 3 | + |
| 4 | +#include "ParallelAlgorithms/LinearSolver/Multigrid/Hierarchy.hpp" |
| 5 | + |
| 6 | +#include <array> |
| 7 | +#include <cstddef> |
| 8 | +#include <unordered_set> |
| 9 | +#include <vector> |
| 10 | + |
| 11 | +#include "Domain/Structure/ElementId.hpp" |
| 12 | +#include "Domain/Structure/SegmentId.hpp" |
| 13 | +#include "Domain/Structure/Side.hpp" |
| 14 | +#include "Utilities/ErrorHandling/Assert.hpp" |
| 15 | +#include "Utilities/GenerateInstantiations.hpp" |
| 16 | + |
| 17 | +namespace LinearSolver::multigrid { |
| 18 | + |
| 19 | +template <size_t Dim> |
| 20 | +std::vector<std::array<size_t, Dim>> coarsen( |
| 21 | + std::vector<std::array<size_t, Dim>> initial_refinement_levels) noexcept { |
| 22 | + for (auto& block_refinement : initial_refinement_levels) { |
| 23 | + for (size_t d = 0; d < Dim; ++d) { |
| 24 | + auto& refinement_level = gsl::at(block_refinement, d); |
| 25 | + if (refinement_level > 0) { |
| 26 | + --refinement_level; |
| 27 | + } |
| 28 | + } |
| 29 | + } |
| 30 | + return initial_refinement_levels; |
| 31 | +} |
| 32 | + |
| 33 | +template <size_t Dim> |
| 34 | +ElementId<Dim> parent_id(const ElementId<Dim>& child_id) noexcept { |
| 35 | + std::array<SegmentId, Dim> parent_segment_ids = child_id.segment_ids(); |
| 36 | + for (size_t d = 0; d < Dim; ++d) { |
| 37 | + auto& segment_id = gsl::at(parent_segment_ids, d); |
| 38 | + if (segment_id.refinement_level() > 0) { |
| 39 | + segment_id = segment_id.id_of_parent(); |
| 40 | + } |
| 41 | + } |
| 42 | + return {child_id.block_id(), std::move(parent_segment_ids), |
| 43 | + child_id.grid_index() + 1}; |
| 44 | +} |
| 45 | + |
| 46 | +namespace { |
| 47 | +template <size_t Dim> |
| 48 | +void assert_finest_grid( |
| 49 | + const std::array<SegmentId, Dim>& parent_segment_ids, |
| 50 | + const std::array<size_t, Dim>& children_refinement_levels) noexcept { |
| 51 | + for (size_t d = 0; d < Dim; ++d) { |
| 52 | + ASSERT(gsl::at(children_refinement_levels, d) == |
| 53 | + gsl::at(parent_segment_ids, d).refinement_level(), |
| 54 | + "On the finest grid, expected the children refinement levels " |
| 55 | + << children_refinement_levels |
| 56 | + << " to equal the refinement levels of the parent segment IDs " |
| 57 | + << parent_segment_ids << " in dimension " << d << "."); |
| 58 | + } |
| 59 | +} |
| 60 | + |
| 61 | +std::unordered_set<SegmentId> child_segment_ids_impl( |
| 62 | + const SegmentId& parent_segment_id, |
| 63 | + const size_t children_refinement_level) noexcept { |
| 64 | + ASSERT(parent_segment_id.refinement_level() == children_refinement_level or |
| 65 | + (children_refinement_level > 0 and |
| 66 | + parent_segment_id.refinement_level() == |
| 67 | + children_refinement_level - 1), |
| 68 | + "The parent refinement level must be exactly 1 smaller than the " |
| 69 | + "children refinement level, or the same. Parent refinement level: " |
| 70 | + << parent_segment_id.refinement_level() |
| 71 | + << ", children refinement level: " << children_refinement_level); |
| 72 | + if (parent_segment_id.refinement_level() < children_refinement_level) { |
| 73 | + return {parent_segment_id.id_of_child(Side::Lower), |
| 74 | + parent_segment_id.id_of_child(Side::Upper)}; |
| 75 | + } else { |
| 76 | + return {parent_segment_id}; |
| 77 | + } |
| 78 | +} |
| 79 | +} // namespace |
| 80 | + |
| 81 | +template <> |
| 82 | +std::unordered_set<ElementId<1>> child_ids<1>( |
| 83 | + const ElementId<1>& parent_id, |
| 84 | + const std::array<size_t, 1>& children_refinement_levels) noexcept { |
| 85 | + if (parent_id.grid_index() == 0) { |
| 86 | +#ifdef SPECTRE_DEBUG |
| 87 | + assert_finest_grid(parent_id.segment_ids(), children_refinement_levels); |
| 88 | +#endif // SPECTRE_DEBUG |
| 89 | + return {}; |
| 90 | + } |
| 91 | + const std::unordered_set<SegmentId> child_segment_ids = |
| 92 | + child_segment_ids_impl(parent_id.segment_ids()[0], |
| 93 | + children_refinement_levels[0]); |
| 94 | + std::unordered_set<ElementId<1>> child_ids{}; |
| 95 | + for (const auto& child_segment_id : child_segment_ids) { |
| 96 | + child_ids.emplace(parent_id.block_id(), |
| 97 | + std::array<SegmentId, 1>{child_segment_id}, |
| 98 | + parent_id.grid_index() - 1); |
| 99 | + } |
| 100 | + return child_ids; |
| 101 | +} |
| 102 | + |
| 103 | +template <> |
| 104 | +std::unordered_set<ElementId<2>> child_ids<2>( |
| 105 | + const ElementId<2>& parent_id, |
| 106 | + const std::array<size_t, 2>& children_refinement_levels) noexcept { |
| 107 | + if (parent_id.grid_index() == 0) { |
| 108 | +#ifdef SPECTRE_DEBUG |
| 109 | + assert_finest_grid(parent_id.segment_ids(), children_refinement_levels); |
| 110 | +#endif // SPECTRE_DEBUG |
| 111 | + return {}; |
| 112 | + } |
| 113 | + std::array<std::unordered_set<SegmentId>, 2> child_segment_ids{}; |
| 114 | + for (size_t d = 0; d < 2; ++d) { |
| 115 | + gsl::at(child_segment_ids, d) = |
| 116 | + child_segment_ids_impl(gsl::at(parent_id.segment_ids(), d), |
| 117 | + gsl::at(children_refinement_levels, d)); |
| 118 | + } |
| 119 | + std::unordered_set<ElementId<2>> child_ids{}; |
| 120 | + for (const auto& child_segment_id_x : child_segment_ids[0]) { |
| 121 | + for (const auto& child_segment_id_y : child_segment_ids[1]) { |
| 122 | + child_ids.emplace( |
| 123 | + parent_id.block_id(), |
| 124 | + std::array<SegmentId, 2>{{child_segment_id_x, child_segment_id_y}}, |
| 125 | + parent_id.grid_index() - 1); |
| 126 | + } |
| 127 | + } |
| 128 | + return child_ids; |
| 129 | +} |
| 130 | + |
| 131 | +template <> |
| 132 | +std::unordered_set<ElementId<3>> child_ids<3>( |
| 133 | + const ElementId<3>& parent_id, |
| 134 | + const std::array<size_t, 3>& children_refinement_levels) noexcept { |
| 135 | + if (parent_id.grid_index() == 0) { |
| 136 | +#ifdef SPECTRE_DEBUG |
| 137 | + assert_finest_grid(parent_id.segment_ids(), children_refinement_levels); |
| 138 | +#endif // SPECTRE_DEBUG |
| 139 | + return {}; |
| 140 | + } |
| 141 | + std::array<std::unordered_set<SegmentId>, 3> child_segment_ids{}; |
| 142 | + for (size_t d = 0; d < 3; ++d) { |
| 143 | + gsl::at(child_segment_ids, d) = |
| 144 | + child_segment_ids_impl(gsl::at(parent_id.segment_ids(), d), |
| 145 | + gsl::at(children_refinement_levels, d)); |
| 146 | + } |
| 147 | + std::unordered_set<ElementId<3>> child_ids{}; |
| 148 | + for (const auto& child_segment_id_x : child_segment_ids[0]) { |
| 149 | + for (const auto& child_segment_id_y : child_segment_ids[1]) { |
| 150 | + for (const auto& child_segment_id_z : child_segment_ids[2]) { |
| 151 | + child_ids.emplace( |
| 152 | + parent_id.block_id(), |
| 153 | + std::array<SegmentId, 3>{ |
| 154 | + {child_segment_id_x, child_segment_id_y, child_segment_id_z}}, |
| 155 | + parent_id.grid_index() - 1); |
| 156 | + } |
| 157 | + } |
| 158 | + } |
| 159 | + return child_ids; |
| 160 | +} |
| 161 | + |
| 162 | +#define DIM(data) BOOST_PP_TUPLE_ELEM(0, data) |
| 163 | +#define INSTANTIATE(r, data) \ |
| 164 | + template std::vector<std::array<size_t, DIM(data)>> coarsen( \ |
| 165 | + std::vector<std::array<size_t, DIM(data)>> \ |
| 166 | + initial_refinement_levels) noexcept; \ |
| 167 | + template ElementId<DIM(data)> parent_id( \ |
| 168 | + const ElementId<DIM(data)>& child_id) noexcept; |
| 169 | + |
| 170 | +GENERATE_INSTANTIATIONS(INSTANTIATE, (1, 2, 3)) |
| 171 | + |
| 172 | +#undef DIM |
| 173 | +#undef INSTANTIATE |
| 174 | + |
| 175 | +} // namespace LinearSolver::multigrid |
0 commit comments