LimiterActions.hpp
Go to the documentation of this file.
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> // IWYU pragma: keep
10 #include <cstddef>
11 #include <map>
12 #include <unordered_map>
13 #include <utility>
14 
16 #include "Domain/Tags.hpp"
17 #include "ErrorHandling/Assert.hpp"
19 #include "Parallel/Invoke.hpp"
21 
22 namespace SlopeLimiters {
23 namespace Tags {
24 /// \ingroup DiscontinuousGalerkinGroup
25 /// \ingroup SlopeLimitersGroup
26 /// \brief The inbox tag for limiter communication.
27 template <typename Metavariables>
29  static constexpr size_t volume_dim = Metavariables::system::volume_dim;
30  using packaged_data_t = typename Metavariables::limiter::type::PackagedData;
32  using type =
33  std::map<temporal_id,
36  packaged_data_t,
37  boost::hash<std::pair<Direction<volume_dim>,
38  ElementId<volume_dim>>>>>;
39 };
40 } // namespace Tags
41 
42 namespace Actions {
43 /// \ingroup ActionsGroup
44 /// \ingroup DiscontinuousGalerkinGroup
45 /// \ingroup SlopeLimitersGroup
46 /// \brief Receive limiter data from neighbors, then apply limiter.
47 ///
48 /// Currently, is not tested for support of:
49 /// - h-refinement
50 /// Currently, does not support:
51 /// - Local time-stepping
52 ///
53 /// Uses:
54 /// - ConstGlobalCache:
55 /// - Metavariables::limiter
56 /// - DataBox:
57 /// - Metavariables::limiter::type::limit_argument_tags
58 /// - Metavariables::temporal_id
59 /// - Tags::Element<volume_dim>
60 /// DataBox changes:
61 /// - Adds: nothing
62 /// - Removes: nothing
63 /// - Modifies:
64 /// - Metavariables::limiter::type::limit_tags
65 ///
66 /// \see SendDataForLimiter
67 template <typename Metavariables>
68 struct Limit {
69  using const_global_cache_tags = tmpl::list<typename Metavariables::limiter>;
70 
71  static_assert(
72  not Metavariables::local_time_stepping,
73  "Limiter communication actions do not yet support local time stepping");
74 
75  public:
76  using limiter_comm_tag =
78  using inbox_tags = tmpl::list<limiter_comm_tag>;
79 
80  template <typename DbTags, typename... InboxTags, typename ArrayIndex,
81  typename ActionList, typename ParallelComponent>
85  const ArrayIndex& /*array_index*/, const ActionList /*meta*/,
86  const ParallelComponent* const /*meta*/) noexcept {
87  using mutate_tags = typename Metavariables::limiter::type::limit_tags;
88  using argument_tags =
89  typename Metavariables::limiter::type::limit_argument_tags;
90 
91  const auto& limiter = get<typename Metavariables::limiter>(cache);
92  const auto& local_temporal_id =
93  db::get<typename Metavariables::temporal_id>(box);
94  auto& inbox = tuples::get<limiter_comm_tag>(inboxes);
95  db::mutate_apply<mutate_tags, argument_tags>(limiter, make_not_null(&box),
96  inbox[local_temporal_id]);
97 
98  inbox.erase(local_temporal_id);
99 
100  return std::forward_as_tuple(std::move(box));
101  }
102 
103  template <typename DbTags, typename... InboxTags, typename ArrayIndex>
104  static bool is_ready(
105  const db::DataBox<DbTags>& box,
106  const tuples::TaggedTuple<InboxTags...>& inboxes,
108  const ArrayIndex& /*array_index*/) noexcept {
109  constexpr size_t volume_dim = Metavariables::system::volume_dim;
110  const auto& element = db::get<::Tags::Element<volume_dim>>(box);
111  const auto num_expected = element.neighbors().size();
112  // Edge case where we do not receive any data
113  if (UNLIKELY(num_expected == 0)) {
114  return true;
115  }
116  const auto& local_temporal_id =
117  db::get<typename Metavariables::temporal_id>(box);
118  const auto& inbox = tuples::get<limiter_comm_tag>(inboxes);
119  const auto& received = inbox.find(local_temporal_id);
120  // Check we have at least some data from correct time
121  if (received == inbox.end()) {
122  return false;
123  }
124  // Check data was received from each neighbor
125  const size_t num_neighbors_received = received->second.size();
126  return (num_neighbors_received == num_expected);
127  }
128 };
129 
130 /// \ingroup ActionsGroup
131 /// \ingroup DiscontinuousGalerkinGroup
132 /// \ingroup SlopeLimitersGroup
133 /// \brief Send local data needed for limiting.
134 ///
135 /// Currently, is not tested for support of:
136 /// - h-refinement
137 /// Currently, does not support:
138 /// - Local time-stepping
139 ///
140 /// Uses:
141 /// - ConstGlobalCache:
142 /// - Metavariables::limiter
143 /// - DataBox:
144 /// - Tags::Element<volume_dim>
145 /// - Metavariables::limiter::type::package_argument_tags
146 /// - Metavariables::temporal_id
147 ///
148 /// DataBox changes:
149 /// - Adds: nothing
150 /// - Removes: nothing
151 /// - Modifies: nothing
152 ///
153 /// \see ApplyLimiter
154 template <typename Metavariables>
155 struct SendData {
156  using const_global_cache_tags = tmpl::list<typename Metavariables::limiter>;
157  using limiter_comm_tag =
159 
160  static_assert(
161  not Metavariables::local_time_stepping,
162  "Limiter communication actions do not yet support local time stepping");
163 
164  template <typename DbTags, typename... InboxTags, typename ArrayIndex,
165  typename ActionList, typename ParallelComponent>
169  const ArrayIndex& /*array_index*/, const ActionList /*meta*/,
170  const ParallelComponent* const /*meta*/) noexcept {
171  constexpr size_t volume_dim = Metavariables::system::volume_dim;
172 
173  auto& receiver_proxy =
174  Parallel::get_parallel_component<ParallelComponent>(cache);
175  const auto& element = db::get<::Tags::Element<volume_dim>>(box);
176  const auto& temporal_id = db::get<typename Metavariables::temporal_id>(box);
177  const auto& limiter = get<typename Metavariables::limiter>(cache);
178 
179  for (const auto& direction_neighbors : element.neighbors()) {
180  const auto& direction = direction_neighbors.first;
181  const size_t dimension = direction.dimension();
182  const auto& neighbors_in_direction = direction_neighbors.second;
183  ASSERT(neighbors_in_direction.size() == 1,
184  "h-adaptivity is not supported yet.\nDirection: "
185  << direction << "\nDimension: " << dimension
186  << "\nNeighbors:\n"
187  << neighbors_in_direction);
188  const auto& orientation = neighbors_in_direction.orientation();
189  const auto direction_from_neighbor = orientation(direction.opposite());
190 
191  using argument_tags =
192  typename Metavariables::limiter::type::package_argument_tags;
193  const auto packaged_data = db::apply<argument_tags>(
194  [&limiter](const auto&... args) noexcept {
195  // Note: orientation is received as last element of pack `args`
196  typename Metavariables::limiter::type::PackagedData pack{};
197  limiter.package_data(make_not_null(&pack), args...);
198  return pack;
199  },
200  box, orientation);
201 
202  for (const auto& neighbor : neighbors_in_direction) {
203  Parallel::receive_data<limiter_comm_tag>(
204  receiver_proxy[neighbor], temporal_id,
205  std::make_pair(
206  std::make_pair(direction_from_neighbor, element.id()),
207  packaged_data));
208 
209  } // loop over neighbors_in_direction
210  } // loop over element.neighbors()
211 
212  return std::forward_as_tuple(std::move(box));
213  }
214 };
215 } // namespace Actions
216 } // namespace SlopeLimiters
Defines class tuples::TaggedTuple.
#define UNLIKELY(x)
Definition: Gsl.hpp:72
Receive limiter data from neighbors, then apply limiter.
Definition: LimiterActions.hpp:68
An ElementId uniquely labels an Element. It is constructed from the BlockId of the Block to which the...
Definition: ElementId.hpp:36
#define ASSERT(a, m)
Assert that an expression should be true.
Definition: Assert.hpp:49
constexpr auto apply(F &&f, const DataBox< BoxTags > &box, Args &&... args)
Apply the function f with argument Tags TagsList from DataBox box
Definition: DataBox.hpp:1595
An associative container that is indexed by structs.
Definition: TaggedTuple.hpp:272
Defines classes and functions used for manipulating DataBox&#39;s.
Things relating to slope limiting.
Definition: LimiterActions.hpp:22
Definition: InterpolationTargetWedgeSectionTorus.hpp:24
Definition: DataBoxTag.hpp:29
A Charm++ chare that caches constant data once per Charm++ node.
Definition: ConstGlobalCache.hpp:76
The inbox tag for limiter communication.
Definition: LimiterActions.hpp:28
Defines macro ASSERT.
typename DataBox_detail::item_type_impl< TagList, Tag >::type item_type
Get the type that is returned by the Tag. If it is a base tag then a TagList must be passed as a seco...
Definition: DataBoxTag.hpp:410
gsl::not_null< T * > make_not_null(T *ptr) noexcept
Construct a not_null from a pointer. Often this will be done as an implicit conversion, but it may be necessary to perform the conversion explicitly when type deduction is desired.
Definition: Gsl.hpp:863
Defines tags related to domain quantities.
Send local data needed for limiting.
Definition: LimiterActions.hpp:155
Defines class template ConstGlobalCache.
Definition: ComputeTimeDerivative.hpp:28