GlobalCache.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 class template GlobalCache.
6 
7 #pragma once
8 
9 #include <string>
10 
11 #include "DataStructures/DataBox/Tag.hpp"
12 #include "ErrorHandling/Assert.hpp"
13 #include "Parallel/CharmRegistration.hpp"
14 #include "Parallel/ParallelComponentHelpers.hpp"
15 #include "Utilities/PrettyType.hpp"
16 #include "Utilities/Requires.hpp"
17 #include "Utilities/TMPL.hpp"
18 #include "Utilities/TaggedTuple.hpp"
19 #include "Utilities/TypeTraits/IsA.hpp"
20 
21 #include "Parallel/GlobalCache.decl.h"
22 
23 namespace Parallel {
24 
25 namespace GlobalCache_detail {
26 template <typename T>
27 struct type_for_get_helper {
28  using type = T;
29 };
30 
31 template <typename T, typename D>
32 struct type_for_get_helper<std::unique_ptr<T, D>> {
33  using type = T;
34 };
35 
36 // This struct provides a better error message if
37 // an unknown tag is requested from the GlobalCache.
38 template <typename GlobalCacheTag, typename ListOfPossibleTags>
39 struct list_of_matching_tags_helper {
40  using type = tmpl::filter<ListOfPossibleTags,
42  static_assert(not std::is_same_v<type, tmpl::list<>>,
43  "Trying to get a nonexistent tag from the GlobalCache. "
44  "To diagnose the problem, search for "
45  "'list_of_matching_tags_helper' in the error message. "
46  "The first template parameter of "
47  "'list_of_matching_tags_helper' is the requested tag, and "
48  "the second template parameter is a tmpl::list of all the "
49  "tags in the GlobalCache. One possible bug that may "
50  "lead to this error message is a missing or misspelled "
51  "const_global_cache_tags type alias.");
52 };
53 
54 // Note: Returned list does not need to be size 1
55 template <class GlobalCacheTag, class Metavariables>
56 using get_list_of_matching_tags = typename list_of_matching_tags_helper<
57  GlobalCacheTag, get_const_global_cache_tags<Metavariables>>::type;
58 
59 template <class GlobalCacheTag, class Metavariables>
60 using type_for_get = typename type_for_get_helper<
61  typename tmpl::front<GlobalCache_detail::get_list_of_matching_tags<
62  GlobalCacheTag, Metavariables>>::type>::type;
63 
64 template <class T, class = std::void_t<>>
65 struct has_component_being_mocked_alias : std::false_type {};
66 
67 template <class T>
68 struct has_component_being_mocked_alias<
69  T, std::void_t<typename T::component_being_mocked>> : std::true_type {};
70 
71 template <class T>
72 constexpr bool has_component_being_mocked_alias_v =
73  has_component_being_mocked_alias<T>::value;
74 
75 template <typename ComponentToFind, typename ComponentFromList>
76 struct get_component_if_mocked_helper {
77  static_assert(
78  has_component_being_mocked_alias_v<ComponentFromList>,
79  "The parallel component was not found, and it looks like it is not being "
80  "mocked. Did you forget to add it to the "
81  "'Metavariables::component_list'? See the first template parameter for "
82  "the component that we are looking for and the second template parameter "
83  "for the component that is being checked for mocking it.");
84  using type = std::is_same<typename ComponentFromList::component_being_mocked,
85  ComponentToFind>;
86 };
87 
88 /// In order to be able to use a mock action testing framework we need to be
89 /// able to get the correct parallel component from the global cache even when
90 /// the correct component is a mock. We do this by having the mocked components
91 /// have a member type alias `component_being_mocked`, and having
92 /// `Parallel::get_component` check if the component to be retrieved is in the
93 /// `metavariables::component_list`. If it is not in the `component_list` then
94 /// we search for a mock component that is mocking the component we are trying
95 /// to retrieve.
96 template <typename ComponentList, typename ParallelComponent>
97 using get_component_if_mocked = tmpl::front<tmpl::type_from<tmpl::conditional_t<
98  tmpl::list_contains_v<ComponentList, ParallelComponent>,
99  tmpl::type_<tmpl::list<ParallelComponent>>,
100  tmpl::lazy::find<ComponentList,
101  tmpl::type_<get_component_if_mocked_helper<
102  tmpl::pin<ParallelComponent>, tmpl::_1>>>>>>;
103 } // namespace GlobalCache_detail
104 
105 /// \ingroup ParallelGroup
106 /// A Charm++ chare that caches constant data once per Charm++ node.
107 ///
108 /// `Metavariables` must define the following metavariables:
109 /// - `component_list` typelist of ParallelComponents
110 /// - `const_global_cache_tags` (possibly empty) typelist of tags of
111 /// constant data
112 ///
113 /// The tag list for the items added to the GlobalCache is created by
114 /// combining the following tag lists:
115 /// - `Metavariables::const_global_cache_tags` which should contain only those
116 /// tags that cannot be added from the other tag lists below.
117 /// - `Component::const_global_cache_tags` for each `Component` in
118 /// `Metavariables::component_list` which should contain the tags needed by
119 /// any simple actions called on the Component, as well as tags need by the
120 /// `allocate_array` function of an array component. The type alias may be
121 /// omitted for an empty list.
122 /// - `Action::const_global_cache_tags` for each `Action` in the
123 /// `phase_dependent_action_list` of each `Component` of
124 /// `Metavariables::component_list` which should contain the tags needed by
125 /// that Action. The type alias may be omitted for an empty list.
126 ///
127 /// The tags in the `const_global_cache_tags` type lists are db::SimpleTag%s
128 /// that have a `using option_tags` type alias and a static function
129 /// `create_from_options` that are used to create the constant data from input
130 /// file options.
131 ///
132 /// References to items in the GlobalCache are also added to the
133 /// db::DataBox of each `Component` in the `Metavariables::component_list` with
134 /// the same tag with which they were inserted into the GlobalCache.
135 template <typename Metavariables>
136 class GlobalCache : public CBase_GlobalCache<Metavariables> {
137  using parallel_component_tag_list = tmpl::transform<
138  typename Metavariables::component_list,
139  tmpl::bind<
140  tmpl::type_,
141  tmpl::bind<Parallel::proxy_from_parallel_component, tmpl::_1>>>;
142 
143  public:
144  /// Access to the Metavariables template parameter
145  using metavariables = Metavariables;
146  /// Typelist of the ParallelComponents stored in the GlobalCache
147  using component_list = typename Metavariables::component_list;
148 
149  explicit GlobalCache(tuples::tagged_tuple_from_typelist<
151  global_cache) noexcept
152  : global_cache_(std::move(global_cache)) {}
153  explicit GlobalCache(CkMigrateMessage* /*msg*/) {}
154  ~GlobalCache() noexcept override {
156  GlobalCache<Metavariables>,
157  CkIndex_GlobalCache<Metavariables>>::registrar;
158  }
159  /// \cond
160  GlobalCache(const GlobalCache&) = default;
161  GlobalCache& operator=(const GlobalCache&) = default;
162  GlobalCache(GlobalCache&&) = default;
163  GlobalCache& operator=(GlobalCache&&) = default;
164  /// \endcond
165 
166  /// Entry method to set the ParallelComponents (should only be called once)
168  tuples::tagged_tuple_from_typelist<parallel_component_tag_list>&&
169  parallel_components,
170  const CkCallback& callback) noexcept;
171 
172  private:
173  // clang-tidy: false positive, redundant declaration
174  template <typename GlobalCacheTag, typename MV>
175  friend auto get(const GlobalCache<MV>& cache) noexcept // NOLINT
176  -> const GlobalCache_detail::type_for_get<GlobalCacheTag, MV>&;
177 
178  // clang-tidy: false positive, redundant declaration
179  template <typename ParallelComponentTag, typename MV>
180  friend auto get_parallel_component( // NOLINT
181  GlobalCache<MV>& cache) noexcept
182  -> Parallel::proxy_from_parallel_component<
183  GlobalCache_detail::get_component_if_mocked<
184  typename MV::component_list, ParallelComponentTag>>&;
185 
186  // clang-tidy: false positive, redundant declaration
187  template <typename ParallelComponentTag, typename MV>
188  friend auto get_parallel_component( // NOLINT
189  const GlobalCache<MV>& cache) noexcept
190  -> const Parallel::proxy_from_parallel_component<
191  GlobalCache_detail::get_component_if_mocked<
192  typename MV::component_list,
193  ParallelComponentTag>>&; // NOLINT
194 
195  tuples::tagged_tuple_from_typelist<get_const_global_cache_tags<Metavariables>>
196  global_cache_{};
197  tuples::tagged_tuple_from_typelist<parallel_component_tag_list>
198  parallel_components_{};
199  bool parallel_components_have_been_set_{false};
200 };
201 
202 template <typename Metavariables>
204  tuples::tagged_tuple_from_typelist<parallel_component_tag_list>&&
205  parallel_components,
206  const CkCallback& callback) noexcept {
207  ASSERT(!parallel_components_have_been_set_,
208  "Can only set the parallel_components once");
209  parallel_components_ = std::move(parallel_components);
210  parallel_components_have_been_set_ = true;
211  this->contribute(callback);
212 }
213 
214 // @{
215 /// \ingroup ParallelGroup
216 /// \brief Access the Charm++ proxy associated with a ParallelComponent
217 ///
218 /// \requires ParallelComponentTag is a tag in component_list
219 ///
220 /// \returns a Charm++ proxy that can be used to call an entry method on the
221 /// chare(s)
222 template <typename ParallelComponentTag, typename Metavariables>
224  -> Parallel::proxy_from_parallel_component<
225  GlobalCache_detail::get_component_if_mocked<
226  typename Metavariables::component_list, ParallelComponentTag>>& {
227  return tuples::get<tmpl::type_<Parallel::proxy_from_parallel_component<
228  GlobalCache_detail::get_component_if_mocked<
229  typename Metavariables::component_list, ParallelComponentTag>>>>(
230  cache.parallel_components_);
231 }
232 
233 template <typename ParallelComponentTag, typename Metavariables>
235  const GlobalCache<Metavariables>& cache) noexcept
236  -> const Parallel::proxy_from_parallel_component<
237  GlobalCache_detail::get_component_if_mocked<
238  typename Metavariables::component_list, ParallelComponentTag>>& {
239  return tuples::get<tmpl::type_<Parallel::proxy_from_parallel_component<
240  GlobalCache_detail::get_component_if_mocked<
241  typename Metavariables::component_list, ParallelComponentTag>>>>(
242  cache.parallel_components_);
243 }
244 // @}
245 
246 // @{
247 /// \ingroup ParallelGroup
248 /// \brief Access data in the cache
249 ///
250 /// \requires GlobalCacheTag is a tag in tag_list
251 ///
252 /// \returns a constant reference to an object in the cache
253 template <typename GlobalCacheTag, typename Metavariables>
254 auto get(const GlobalCache<Metavariables>& cache) noexcept -> const
255  GlobalCache_detail::type_for_get<GlobalCacheTag, Metavariables>& {
256  // We check if the tag is to be retrieved directly or via a base class
257  using tag = tmpl::front<GlobalCache_detail::get_list_of_matching_tags<
258  GlobalCacheTag, Metavariables>>;
259  static_assert(tmpl::size<GlobalCache_detail::get_list_of_matching_tags<
260  GlobalCacheTag, Metavariables>>::value == 1,
261  "Found more than one tag matching the GlobalCacheTag "
262  "requesting to be retrieved.");
263  return make_overloader(
264  [](std::true_type /*is_unique_ptr*/, auto&& local_cache)
265  -> decltype(
266  *(tuples::get<tag>(local_cache.global_cache_).get())) {
267  return *(
268  tuples::get<tag>(local_cache.global_cache_)
269  .get());
270  },
271  [](std::false_type /*is_unique_ptr*/, auto&& local_cache)
272  -> decltype(tuples::get<tag>(local_cache.global_cache_)) {
273  return tuples::get<tag>(
274  local_cache.global_cache_);
276 }
277 
278 namespace Tags {
279 /// \ingroup DataBoxTagsGroup
280 /// \ingroup ParallelGroup
281 /// Tag to retrieve the `Parallel::GlobalCache` from the DataBox.
283 
284 template <class Metavariables>
287  static std::string name() noexcept { return "GlobalCache"; }
288 };
289 
290 /// \ingroup DataBoxTagsGroup
291 /// \ingroup ParallelGroup
292 /// Tag used to retrieve data from the `Parallel::GlobalCache`. This is the
293 /// recommended way for compute tags to retrieve data out of the global cache.
294 template <class CacheTag>
295 struct FromGlobalCache : CacheTag, db::ComputeTag {
296  static std::string name() noexcept {
297  return "FromGlobalCache(" + pretty_type::short_name<CacheTag>() + ")";
298  }
299  template <class Metavariables>
300  static const GlobalCache_detail::type_for_get<CacheTag, Metavariables>&
301  function(const Parallel::GlobalCache<Metavariables>* const& cache) {
302  return Parallel::get<CacheTag>(*cache);
303  }
304  using argument_tags = tmpl::list<GlobalCache>;
305 };
306 } // namespace Tags
307 } // namespace Parallel
308 
309 #define CK_TEMPLATES_ONLY
310 #include "Parallel/GlobalCache.def.h"
311 #undef CK_TEMPLATES_ONLY
tt::is_a
Check if type T is a template specialization of U
Definition: IsA.hpp:41
std::is_same
db::ComputeTag
Marks a DataBoxTag as being a compute item that executes a function.
Definition: Tag.hpp:109
std::false_type
std::string
Parallel::GlobalCache< typename Component::metavariables >::metavariables
typename Component::metavariables metavariables
Access to the Metavariables template parameter.
Definition: GlobalCache.hpp:145
make_overloader
Overloader< Fs... > make_overloader(Fs... fs)
Create Overloader<Fs...>, see Overloader for details.
Definition: Overloader.hpp:109
get
constexpr Tag::type & get(Variables< TagList > &v) noexcept
Return Tag::type pointing into the contiguous array.
Definition: Variables.hpp:639
Parallel::GlobalCache
Definition: ElementReceiveInterpPoints.hpp:16
Parallel::get_parallel_component
auto get_parallel_component(GlobalCache< Metavariables > &cache) noexcept -> Parallel::proxy_from_parallel_component< GlobalCache_detail::get_component_if_mocked< typename Metavariables::component_list, ParallelComponentTag >> &
Access the Charm++ proxy associated with a ParallelComponent.
Definition: GlobalCache.hpp:223
PrettyType.hpp
Parallel::Tags::FromGlobalCache
Definition: GlobalCache.hpp:295
db::SimpleTag
Tags for the DataBox inherit from this type.
Definition: Tag.hpp:23
Parallel::GlobalCache::set_parallel_components
void set_parallel_components(tuples::tagged_tuple_from_typelist< parallel_component_tag_list > &&parallel_components, const CkCallback &callback) noexcept
Entry method to set the ParallelComponents (should only be called once)
Definition: GlobalCache.hpp:203
Assert.hpp
Parallel::Tags::GlobalCacheImpl
Definition: GlobalCache.hpp:285
db::BaseTag
Tags that are base tags, i.e. a simple or compute tag must derive off them for them to be useful.
Definition: Tag.hpp:41
Parallel::Tags::GlobalCache
Definition: GlobalCache.hpp:282
ASSERT
#define ASSERT(a, m)
Assert that an expression should be true.
Definition: Assert.hpp:51
Parallel::get_const_global_cache_tags
tmpl::remove_duplicates< tmpl::flatten< tmpl::list< typename detail::get_const_global_cache_tags_from_parallel_struct< Metavariables >::type, tmpl::transform< typename Metavariables::component_list, detail::get_const_global_cache_tags_from_parallel_struct< tmpl::_1 > >, tmpl::transform< typename Metavariables::component_list, detail::get_const_global_cache_tags_from_pdal< tmpl::_1 > >> >> get_const_global_cache_tags
Given the metavariables, get a list of the unique tags that will specify the items in the GlobalCache...
Definition: ParallelComponentHelpers.hpp:83
Parallel::GlobalCache< typename Component::metavariables >::component_list
typename typename Component::metavariables ::component_list component_list
Typelist of the ParallelComponents stored in the GlobalCache.
Definition: GlobalCache.hpp:147
Requires.hpp
Parallel::charmxx::RegisterChare
Derived class for registering chares.
Definition: CharmRegistration.hpp:172
Parallel::get
auto get(const GlobalCache< Metavariables > &cache) noexcept -> const GlobalCache_detail::type_for_get< GlobalCacheTag, Metavariables > &
Access data in the cache.
Definition: GlobalCache.hpp:254
Parallel
Contains functions that forward to Charm++ parallel functions.
Definition: ElementReceiveInterpPoints.hpp:14
TMPL.hpp
cpp20::find
constexpr InputIt find(InputIt first, InputIt last, const T &value)
Definition: Algorithm.hpp:136
std::is_base_of
string