Line data Source code
1 1 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : /// \file
5 : /// Defines actions ApplyLimiter and SendDataForLimiter
6 :
7 : #pragma once
8 :
9 : #include <boost/functional/hash.hpp>
10 : #include <cstddef>
11 : #include <map>
12 : #include <optional>
13 : #include <unordered_map>
14 : #include <utility>
15 :
16 : #include "DataStructures/DataBox/DataBox.hpp"
17 : #include "DataStructures/TaggedTuple.hpp"
18 : #include "Domain/Structure/DirectionalId.hpp"
19 : #include "Domain/Tags.hpp"
20 : #include "Parallel/AlgorithmExecution.hpp"
21 : #include "Parallel/GlobalCache.hpp"
22 : #include "Parallel/InboxInserters.hpp"
23 : #include "Parallel/Invoke.hpp"
24 : #include "Utilities/ErrorHandling/Assert.hpp"
25 :
26 : namespace Limiters {
27 0 : namespace Tags {
28 : /// \ingroup DiscontinuousGalerkinGroup
29 : /// \ingroup LimitersGroup
30 : /// \brief The inbox tag for limiter communication.
31 : template <typename Metavariables>
32 1 : struct LimiterCommunicationTag : public Parallel::InboxInserters::Map<
33 : LimiterCommunicationTag<Metavariables>> {
34 0 : static constexpr size_t volume_dim = Metavariables::system::volume_dim;
35 0 : using packaged_data_t = typename Metavariables::limiter::type::PackagedData;
36 0 : using temporal_id = typename Metavariables::temporal_id::type;
37 0 : using type =
38 : std::map<temporal_id,
39 : std::unordered_map<DirectionalId<volume_dim>, packaged_data_t,
40 : boost::hash<DirectionalId<volume_dim>>>>;
41 : };
42 : } // namespace Tags
43 :
44 0 : namespace Actions {
45 : /// \ingroup ActionsGroup
46 : /// \ingroup DiscontinuousGalerkinGroup
47 : /// \ingroup LimitersGroup
48 : /// \brief Receive limiter data from neighbors, then apply limiter.
49 : ///
50 : /// Currently, is not tested for support of:
51 : /// - h-refinement
52 : /// Currently, does not support:
53 : /// - Local time-stepping
54 : ///
55 : /// Uses:
56 : /// - GlobalCache:
57 : /// - Metavariables::limiter
58 : /// - DataBox:
59 : /// - Metavariables::limiter::type::limit_argument_tags
60 : /// - Metavariables::temporal_id
61 : /// - Tags::Element<volume_dim>
62 : /// DataBox changes:
63 : /// - Adds: nothing
64 : /// - Removes: nothing
65 : /// - Modifies:
66 : /// - Metavariables::limiter::type::limit_tags
67 : ///
68 : /// \see SendDataForLimiter
69 : template <typename Metavariables>
70 1 : struct Limit {
71 0 : using const_global_cache_tags = tmpl::list<typename Metavariables::limiter>;
72 :
73 : public:
74 0 : using limiter_comm_tag =
75 : Limiters::Tags::LimiterCommunicationTag<Metavariables>;
76 0 : using inbox_tags = tmpl::list<limiter_comm_tag>;
77 :
78 : template <typename DbTags, typename... InboxTags, typename ArrayIndex,
79 : typename ActionList, typename ParallelComponent>
80 0 : static Parallel::iterable_action_return_t apply(
81 : db::DataBox<DbTags>& box, tuples::TaggedTuple<InboxTags...>& inboxes,
82 : const Parallel::GlobalCache<Metavariables>& cache,
83 : const ArrayIndex& /*array_index*/, const ActionList /*meta*/,
84 : const ParallelComponent* const /*meta*/) {
85 : static_assert(
86 : not Metavariables::local_time_stepping,
87 : "Limiter communication actions do not yet support local time stepping");
88 :
89 : constexpr size_t volume_dim = Metavariables::system::volume_dim;
90 :
91 : const auto& local_temporal_id =
92 : db::get<typename Metavariables::temporal_id>(box);
93 : auto& inbox = tuples::get<limiter_comm_tag>(inboxes);
94 : const auto& received = inbox.find(local_temporal_id);
95 :
96 : const auto& element = db::get<domain::Tags::Element<volume_dim>>(box);
97 : const auto num_expected = element.neighbors().size();
98 : if (num_expected > 0 and
99 : (received == inbox.end() or received->second.size() != num_expected)) {
100 : return {Parallel::AlgorithmExecution::Retry, std::nullopt};
101 : }
102 :
103 : const auto& limiter = get<typename Metavariables::limiter>(cache);
104 : using mutate_tags = typename Metavariables::limiter::type::limit_tags;
105 : using argument_tags =
106 : typename Metavariables::limiter::type::limit_argument_tags;
107 : db::mutate_apply<mutate_tags, argument_tags>(limiter, make_not_null(&box),
108 : inbox[local_temporal_id]);
109 :
110 : inbox.erase(local_temporal_id);
111 :
112 : return {Parallel::AlgorithmExecution::Continue, std::nullopt};
113 : }
114 : };
115 :
116 : /// \ingroup ActionsGroup
117 : /// \ingroup DiscontinuousGalerkinGroup
118 : /// \ingroup LimitersGroup
119 : /// \brief Send local data needed for limiting.
120 : ///
121 : /// Currently, is not tested for support of:
122 : /// - h-refinement
123 : /// Currently, does not support:
124 : /// - Local time-stepping
125 : ///
126 : /// Uses:
127 : /// - GlobalCache:
128 : /// - Metavariables::limiter
129 : /// - DataBox:
130 : /// - Tags::Element<volume_dim>
131 : /// - Metavariables::limiter::type::package_argument_tags
132 : /// - Metavariables::temporal_id
133 : ///
134 : /// DataBox changes:
135 : /// - Adds: nothing
136 : /// - Removes: nothing
137 : /// - Modifies: nothing
138 : ///
139 : /// \see ApplyLimiter
140 : template <typename Metavariables>
141 1 : struct SendData {
142 0 : using const_global_cache_tags = tmpl::list<typename Metavariables::limiter>;
143 0 : using limiter_comm_tag =
144 : Limiters::Tags::LimiterCommunicationTag<Metavariables>;
145 :
146 : template <typename DbTags, typename... InboxTags, typename ArrayIndex,
147 : typename ActionList, typename ParallelComponent>
148 0 : static Parallel::iterable_action_return_t apply(
149 : db::DataBox<DbTags>& box, tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
150 : Parallel::GlobalCache<Metavariables>& cache,
151 : const ArrayIndex& /*array_index*/, const ActionList /*meta*/,
152 : const ParallelComponent* const /*meta*/) {
153 : constexpr size_t volume_dim = Metavariables::system::volume_dim;
154 :
155 : auto& receiver_proxy =
156 : Parallel::get_parallel_component<ParallelComponent>(cache);
157 : const auto& element = db::get<domain::Tags::Element<volume_dim>>(box);
158 : const auto& temporal_id = db::get<typename Metavariables::temporal_id>(box);
159 : const auto& limiter = get<typename Metavariables::limiter>(cache);
160 :
161 : for (const auto& direction_neighbors : element.neighbors()) {
162 : const auto& direction = direction_neighbors.first;
163 : const size_t dimension = direction.dimension();
164 : const auto& neighbors_in_direction = direction_neighbors.second;
165 : ASSERT(neighbors_in_direction.size() == 1,
166 : "h-adaptivity is not supported yet.\nDirection: "
167 : << direction << "\nDimension: " << dimension
168 : << "\nNeighbors:\n"
169 : << neighbors_in_direction);
170 : const auto& neighbor_id = *(neighbors_in_direction.cbegin());
171 : const auto& orientation = neighbors_in_direction.orientation(neighbor_id);
172 : const auto direction_from_neighbor = orientation(direction.opposite());
173 :
174 : using argument_tags =
175 : typename Metavariables::limiter::type::package_argument_tags;
176 : const auto packaged_data = db::apply<argument_tags>(
177 : [&limiter](const auto&... args) {
178 : // Note: orientation is received as last element of pack `args`
179 : typename Metavariables::limiter::type::PackagedData pack{};
180 : limiter.package_data(make_not_null(&pack), args...);
181 : return pack;
182 : },
183 : box, orientation);
184 :
185 : for (const auto& neighbor : neighbors_in_direction) {
186 : Parallel::receive_data<limiter_comm_tag>(
187 : receiver_proxy[neighbor], temporal_id,
188 : std::make_pair(DirectionalId<volume_dim>{direction_from_neighbor,
189 : element.id()},
190 : packaged_data));
191 :
192 : } // loop over neighbors_in_direction
193 : } // loop over element.neighbors()
194 :
195 : return {Parallel::AlgorithmExecution::Continue, std::nullopt};
196 : }
197 : };
198 : } // namespace Actions
199 : } // namespace Limiters
|