MockRuntimeSystem.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <algorithm>
7 #include <cstddef>
8 #include <memory>
9 #include <numeric>
10 #include <tuple>
11 #include <unordered_map>
12 #include <unordered_set>
13 #include <utility>
14 
16 #include "Parallel/GlobalCache.hpp"
17 #include "Parallel/ParallelComponentHelpers.hpp"
19 #include "Utilities/TMPL.hpp"
20 #include "Utilities/TaggedTuple.hpp"
21 #include "Utilities/TypeTraits.hpp"
22 #include "Utilities/TypeTraits/IsA.hpp"
23 
24 /// \cond
25 namespace ActionTesting {
26 template <typename Component>
27 class MockDistributedObject;
28 template <typename SimpleTagsList, typename ComputeTagsList = tmpl::list<>>
29 struct InitializeDataBox;
30 struct MockArrayChare;
31 struct MockGroupChare;
32 struct MockNodeGroupChare;
33 struct MockSingletonChare;
34 } // namespace ActionTesting
35 /// \endcond
36 
37 namespace ActionTesting {
38 
39 namespace detail {
40 // `get_initialization` computes the type of the TaggedTuple that holds the
41 // initial simple tags for the DataBox, as well as the
42 // `initialize_databox_action` so that the user interface to the Action Testing
43 // does not require the user to redundantly specify this information.
44 // `get_initialization` also performs various sanity checks for the user.
45 template <typename Component>
46 struct get_initialization {
47  using phase = typename Component::metavariables::Phase;
48 
49  template <typename T>
50  struct is_initialization_phase {
51  using type =
53  };
54 
55  using initialization_pdal_list =
56  tmpl::filter<typename Component::phase_dependent_action_list,
57  is_initialization_phase<tmpl::_1>>;
58  static_assert(
59  tmpl::size<initialization_pdal_list>::value == 1,
60  "Must have exactly one Initialization PhaseDependentActionList");
61 
62  using initialization_pdal = typename tmpl::front<initialization_pdal_list>;
63 
64  static_assert(
65  tt::is_a_v<ActionTesting::InitializeDataBox,
66  tmpl::front<typename initialization_pdal::action_list>>,
67  "The first action in the initialization phase must be "
68  "ActionTesting::InitializeDataBox, even if the simple and "
69  "compute tags are empty.");
70 
71  using initialize_databox_action =
72  tmpl::front<typename initialization_pdal::action_list>;
73 
74  using InitialValues = typename initialize_databox_action::InitialValues;
75 };
76 
77 // Checks whether or not the `Metavariables` has a `Phase::Initialization`.
78 template <typename Metavariables, typename = std::void_t<>>
79 struct has_initialization_phase : std::false_type {};
80 
81 template <typename Metavariables>
82 struct has_initialization_phase<
83  Metavariables, std::void_t<decltype(Metavariables::Phase::Initialization)>>
84  : std::true_type {};
85 
86 template <typename Metavariables>
87 constexpr bool has_initialization_phase_v =
88  has_initialization_phase<Metavariables>::value;
89 } // namespace detail
90 
91 /// \ingroup TestingFrameworkGroup
92 /// A class that mocks the infrastructure needed to run actions. It simulates
93 /// message passing using the inbox infrastructure and handles most of the
94 /// arguments to the apply method. This mocks the Charm++ runtime system as
95 /// well as the layer built on top of it as part of SpECTRE.
96 template <typename Metavariables>
98  public:
99  // No moving, since MockCollectionOfDistributedObjectsProxy holds a pointer to
100  // us.
101  MockRuntimeSystem(const MockRuntimeSystem&) = delete;
103  MockRuntimeSystem& operator=(const MockRuntimeSystem&) = delete;
104  MockRuntimeSystem& operator=(MockRuntimeSystem&&) = delete;
105  ~MockRuntimeSystem() = default;
106 
107  template <typename Component>
108  struct InboxesTag {
109  using type = std::unordered_map<
110  typename Component::array_index,
111  tuples::tagged_tuple_from_typelist<
112  typename MockDistributedObject<Component>::inbox_tags_list>>;
113  };
114 
115  template <typename Component>
117  using type = std::unordered_map<typename Component::array_index,
119  };
120 
122  using CacheTuple = tuples::tagged_tuple_from_typelist<
124  using MutableCacheTuple = tuples::tagged_tuple_from_typelist<
126 
127  using mock_objects_tags =
128  tmpl::transform<typename Metavariables::component_list,
129  tmpl::bind<MockDistributedObjectsTag, tmpl::_1>>;
130  using CollectionOfMockDistributedObjects =
131  tuples::tagged_tuple_from_typelist<mock_objects_tags>;
132  using Inboxes = tuples::tagged_tuple_from_typelist<
133  tmpl::transform<typename Metavariables::component_list,
134  tmpl::bind<InboxesTag, tmpl::_1>>>;
135 
136 
137  /// Construct from the tuple of GlobalCache objects.
139  CacheTuple cache_contents, MutableCacheTuple mutable_cache_contents = {},
140  const std::vector<size_t>& number_of_mock_cores_on_each_mock_node = {1})
141  : mock_global_cores_(
142  [&number_of_mock_cores_on_each_mock_node]() noexcept {
143  std::unordered_map<NodeId,
145  mock_global_cores{};
146  size_t global_core = 0;
147  for (size_t node = 0;
148  node < number_of_mock_cores_on_each_mock_node.size();
149  ++node) {
151  for (size_t local_core = 0;
152  local_core < number_of_mock_cores_on_each_mock_node[node];
153  ++local_core, ++global_core) {
154  global_cores.insert(
155  {LocalCoreId{local_core}, GlobalCoreId{global_core}});
156  }
157  mock_global_cores.insert({NodeId{node}, global_cores});
158  }
159  return mock_global_cores;
160  }()),
161  mock_nodes_and_local_cores_(
162  [&number_of_mock_cores_on_each_mock_node]() noexcept {
164  mock_nodes_and_local_cores{};
165  size_t global_core = 0;
166  for (size_t node = 0;
167  node < number_of_mock_cores_on_each_mock_node.size();
168  ++node) {
169  for (size_t local_core = 0;
170  local_core < number_of_mock_cores_on_each_mock_node[node];
171  ++local_core, ++global_core) {
172  mock_nodes_and_local_cores.insert(
173  {GlobalCoreId{global_core},
174  std::make_pair(NodeId{node}, LocalCoreId{local_core})});
175  }
176  }
177  return mock_nodes_and_local_cores;
178  }()),
179  mutable_caches_(mock_nodes_and_local_cores_.size()),
180  caches_(mock_nodes_and_local_cores_.size()) {
181  // Fill the parallel components in each cache. There is one cache
182  // per mock core. The parallel components held in each cache (i.e. the
183  // MockProxies) are filled with the same GlobalCache data, and are
184  // passed the mock node and mock core associated with that cache.
185  // The actual chares held in each cache are emplaced by the user explicitly
186  // on a chosen node and core, via `emplace_component`.
187  for (const auto& [global_core_id, node_and_local_core] :
188  mock_nodes_and_local_cores_) {
189  const size_t global_core = global_core_id.value;
190  mutable_caches_.at(global_core) =
191  std::make_unique<Parallel::MutableGlobalCache<Metavariables>>(
192  serialize_and_deserialize(mutable_cache_contents));
193  caches_.at(global_core) = std::make_unique<GlobalCache>(
194  serialize_and_deserialize(cache_contents),
195  mutable_caches_.at(global_core).get());
196  // Note that lambdas cannot capture structured bindings,
197  // so we define node and local_core here.
198  const auto& node = node_and_local_core.first.value;
199  const auto& local_core = node_and_local_core.second.value;
200  tmpl::for_each<typename Metavariables::component_list>(
201  [this, &global_core, &node, &local_core](auto component) {
202  using Component = tmpl::type_from<decltype(component)>;
203  Parallel::get_parallel_component<Component>(
204  *caches_.at(global_core))
205  .set_data(&tuples::get<MockDistributedObjectsTag<Component>>(
206  mock_distributed_objects_),
207  &tuples::get<InboxesTag<Component>>(inboxes_),
208  node, local_core, global_core);
209  });
210  }
211  }
212 
213  /// Construct from the tuple of GlobalCache and MutableGlobalCache
214  /// objects that might be in a different order.
215  template <typename... CacheTags, typename... MutableCacheTags>
217  tuples::TaggedTuple<CacheTags...> cache_contents,
218  tuples::TaggedTuple<MutableCacheTags...> mutable_cache_contents = {},
219  const std::vector<size_t>& number_of_mock_cores_on_each_mock_node = {1})
220  : MockRuntimeSystem(
221  tuples::reorder<CacheTuple>(std::move(cache_contents)),
222  tuples::reorder<MutableCacheTuple>(
223  std::move(mutable_cache_contents)),
224  number_of_mock_cores_on_each_mock_node) {}
225 
226  /// Emplace an array component that does not need to be initialized.
227  template <typename Component, typename... Options>
229  const NodeId node_id, const LocalCoreId local_core_id,
230  const typename Component::array_index& array_index,
231  Options&&... opts) noexcept {
232  mock_distributed_objects<Component>().emplace(
233  array_index,
235  node_id, local_core_id, mock_global_cores_,
236  mock_nodes_and_local_cores_, array_index,
237  caches_.at(mock_global_cores_.at(node_id).at(local_core_id).value)
238  .get(),
239  // Next line inserts element into inboxes_ and returns ptr to it.
240  &(tuples::get<InboxesTag<Component>>(inboxes_)[array_index]),
241  std::forward<Options>(opts)...));
242  }
243 
244  /// Emplace a singleton component that does not need to be initialized.
245  template <typename Component, typename... Options>
247  const LocalCoreId local_core_id,
248  Options&&... opts) noexcept {
249  static_assert(
250  std::is_same_v<typename Component::chare_type, MockSingletonChare>,
251  "emplace_singleton_component expects a MockSingletonChare");
252  // For a singleton, use an array index of zero.
253  const typename Component::array_index array_index{0};
254  mock_distributed_objects<Component>().emplace(
255  array_index,
257  node_id, local_core_id, mock_global_cores_,
258  mock_nodes_and_local_cores_, array_index,
259  caches_.at(mock_global_cores_.at(node_id).at(local_core_id).value)
260  .get(),
261  // Next line inserts element into inboxes_ and returns ptr to it.
262  &(tuples::get<InboxesTag<Component>>(inboxes_)[array_index]),
263  std::forward<Options>(opts)...));
264  }
265 
266  /// Emplace a group component that does not need to be initialized.
267  template <typename Component, typename... Options>
268  void emplace_group_component(Options&&... opts) noexcept {
269  static_assert(
270  std::is_same_v<typename Component::chare_type, MockGroupChare>,
271  "emplace_group_component expects a MockGroupChare");
272  // Emplace once for each core, index by global_core.
273  for (const auto& [global_core_id, node_and_local_core] :
274  mock_nodes_and_local_cores_) {
275  const size_t global_core = global_core_id.value;
276  const typename Component::array_index array_index = global_core;
277  mock_distributed_objects<Component>().emplace(
278  array_index,
280  node_and_local_core.first, node_and_local_core.second,
281  mock_global_cores_, mock_nodes_and_local_cores_, array_index,
282  caches_.at(global_core).get(),
283  // Next line inserts element into inboxes_ and returns ptr to it.
284  &(tuples::get<InboxesTag<Component>>(inboxes_)[array_index]),
285  std::forward<Options>(opts)...));
286  }
287  }
288 
289  /// Emplace a nodegroup component that does not need to be initialized.
290  template <typename Component, typename... Options>
291  void emplace_nodegroup_component(Options&&... opts) noexcept {
292  static_assert(
293  std::is_same_v<typename Component::chare_type, MockNodeGroupChare>,
294  "emplace_nodegroup_component expects a MockNodeGroupChare");
295  // Emplace once for each node, index by node number.
296  for (const auto& [node, local_and_global_cores] : mock_global_cores_) {
297  const typename Component::array_index array_index = node.value;
298  // Use first proc on each node as global_core
299  const size_t global_core =
300  local_and_global_cores.at(LocalCoreId{0}).value;
301  mock_distributed_objects<Component>().emplace(
302  array_index,
304  node, LocalCoreId{0}, mock_global_cores_,
305  mock_nodes_and_local_cores_, array_index,
306  caches_.at(global_core).get(),
307  // Next line inserts element into inboxes_ and returns ptr to it.
308  &(tuples::get<InboxesTag<Component>>(inboxes_)[array_index]),
309  std::forward<Options>(opts)...));
310  }
311  }
312 
313  /// Emplace a component that does not need to be initialized.
314  /// emplace_component is deprecated in favor of
315  /// emplace_array_component, emplace_singleton_component,
316  /// emplace_group_component, and emplace_nodegroup_component.
317  template <typename Component, typename... Options>
318  void emplace_component(const typename Component::array_index& array_index,
319  Options&&... opts) noexcept {
320  emplace_array_component<Component>(NodeId{0}, LocalCoreId{0}, array_index,
321  std::forward<Options>(opts)...);
322  }
323 
324  /// Emplace an array component that needs to be initialized.
325  template <typename Component, typename... Options>
327  const NodeId node_id, const LocalCoreId local_core_id,
328  const typename Component::array_index& array_index,
329  const typename detail::get_initialization<Component>::InitialValues&
330  initial_values,
331  Options&&... opts) noexcept {
332  detail::get_initialization<Component>::initialize_databox_action::
333  set_initial_values(initial_values);
334  auto [iterator, emplace_was_successful] =
335  mock_distributed_objects<Component>().emplace(
336  array_index,
338  node_id, local_core_id, mock_global_cores_,
339  mock_nodes_and_local_cores_, array_index,
340  caches_
341  .at(mock_global_cores_.at(node_id).at(local_core_id).value)
342  .get(),
343  // Next line inserts element into inboxes_ and returns ptr to
344  // it.
345  &(tuples::get<InboxesTag<Component>>(inboxes_)[array_index]),
346  std::forward<Options>(opts)...));
347  if (not emplace_was_successful) {
348  ERROR("Failed to insert parallel component '"
349  << pretty_type::get_name<Component>() << "' with index "
350  << array_index);
351  }
352  iterator->second.set_phase(Metavariables::Phase::Initialization);
353  iterator->second.next_action();
354  }
355 
356  /// Emplace a singleton component that needs to be initialized.
357  template <typename Component, typename... Options>
359  const NodeId node_id, const LocalCoreId local_core_id,
360  const typename detail::get_initialization<Component>::InitialValues&
361  initial_values,
362  Options&&... opts) noexcept {
363  static_assert(
364  std::is_same_v<typename Component::chare_type, MockSingletonChare>,
365  "emplace_singleton_component_and_initialize expects a "
366  "MockSingletonChare");
367  // Use 0 for the array_index
368  const typename Component::array_index& array_index{0};
369  detail::get_initialization<Component>::initialize_databox_action::
370  set_initial_values(initial_values);
371  auto [iterator, emplace_was_successful] =
372  mock_distributed_objects<Component>().emplace(
373  array_index,
375  node_id, local_core_id, mock_global_cores_,
376  mock_nodes_and_local_cores_, array_index,
377  caches_
378  .at(mock_global_cores_.at(node_id).at(local_core_id).value)
379  .get(),
380  // Next line inserts element into inboxes_ and returns ptr to
381  // it.
382  &(tuples::get<InboxesTag<Component>>(inboxes_)[array_index]),
383  std::forward<Options>(opts)...));
384  if (not emplace_was_successful) {
385  ERROR("Failed to insert parallel component '"
386  << pretty_type::get_name<Component>() << "' with index "
387  << array_index);
388  }
389  iterator->second.set_phase(Metavariables::Phase::Initialization);
390  iterator->second.next_action();
391  }
392 
393  /// Emplace a group component that needs to be initialized.
394  template <typename Component, typename... Options>
396  const typename detail::get_initialization<Component>::InitialValues&
397  initial_values,
398  Options&&... opts) noexcept {
399  static_assert(
400  std::is_same_v<typename Component::chare_type, MockGroupChare>,
401  "emplace_group_component_and_initialize expects a MockGroupChare");
402  // Emplace once for each core, index by global_core.
403  for (const auto& [global_core_id, node_and_local_core] :
404  mock_nodes_and_local_cores_) {
405  // Need to set initial values for each component, since the
406  // InitialDataBox action does a std::move.
407  detail::get_initialization<Component>::initialize_databox_action::
408  set_initial_values(initial_values);
409  const size_t global_core = global_core_id.value;
410  const typename Component::array_index array_index = global_core;
411  auto [iterator, emplace_was_successful] =
412  mock_distributed_objects<Component>().emplace(
413  array_index,
415  node_and_local_core.first, node_and_local_core.second,
416  mock_global_cores_, mock_nodes_and_local_cores_, array_index,
417  caches_.at(global_core).get(),
418  // Next line inserts element into inboxes_ and returns ptr to
419  // it.
420  &(tuples::get<InboxesTag<Component>>(inboxes_)[array_index]),
421  std::forward<Options>(opts)...));
422  if (not emplace_was_successful) {
423  ERROR("Failed to insert parallel component '"
424  << pretty_type::get_name<Component>() << "' with index "
425  << array_index);
426  }
427  iterator->second.set_phase(Metavariables::Phase::Initialization);
428  iterator->second.next_action();
429  }
430  }
431 
432  /// Emplace a nodegroup component that needs to be initialized.
433  template <typename Component, typename... Options>
435  const typename detail::get_initialization<Component>::InitialValues&
436  initial_values,
437  Options&&... opts) noexcept {
438  static_assert(
439  std::is_same_v<typename Component::chare_type, MockNodeGroupChare>,
440  "emplace_nodegroup_component_and_initialize expects a "
441  "MockNodeGroupChare");
442  // Emplace once for each node, index by node number.
443  for (const auto& [node, local_and_global_cores] : mock_global_cores_) {
444  // Need to set initial values for each component, since the
445  // InitialDataBox action does a std::move.
446  detail::get_initialization<Component>::initialize_databox_action::
447  set_initial_values(initial_values);
448  const typename Component::array_index array_index = node.value;
449  // Use first proc on each node as global_core
450  const size_t global_core =
451  local_and_global_cores.at(LocalCoreId{0}).value;
452  auto [iterator, emplace_was_successful] =
453  mock_distributed_objects<Component>().emplace(
454  array_index,
456  node, LocalCoreId{0}, mock_global_cores_,
457  mock_nodes_and_local_cores_, array_index,
458  caches_.at(global_core).get(),
459  // Next line inserts element into inboxes_ and returns ptr to
460  // it.
461  &(tuples::get<InboxesTag<Component>>(inboxes_)[array_index]),
462  std::forward<Options>(opts)...));
463  if (not emplace_was_successful) {
464  ERROR("Failed to insert parallel component '"
465  << pretty_type::get_name<Component>() << "' with index "
466  << array_index);
467  }
468  iterator->second.set_phase(Metavariables::Phase::Initialization);
469  iterator->second.next_action();
470  }
471  }
472 
473  /// Emplace a component that needs to be initialized.
474  /// emplace_component_and_initialize is deprecated in favor of
475  /// emplace_array_component_and_initialize,
476  /// emplace_singleton_component_and_initialize,
477  /// emplace_group_component_and_initialize, and
478  /// emplace_nodegroup_component_and_initialize.
479  template <typename Component, typename... Options,
480  typename Metavars = Metavariables,
483  const typename Component::array_index& array_index,
484  const typename detail::get_initialization<Component>::InitialValues&
485  initial_values,
486  Options&&... opts) noexcept {
487  emplace_array_component_and_initialize<Component>(
488  NodeId{0}, LocalCoreId{0}, array_index, initial_values,
489  std::forward<Options>(opts)...);
490  }
491 
492  /// @{
493  /// Invoke the simple action `Action` on the `Component` labeled by
494  /// `array_index` immediately.
495  template <typename Component, typename Action, typename Arg0,
496  typename... Args>
497  void simple_action(const typename Component::array_index& array_index,
498  Arg0&& arg0, Args&&... args) noexcept {
499  mock_distributed_objects<Component>()
500  .at(array_index)
501  .template simple_action<Action>(
502  std::make_tuple(std::forward<Arg0>(arg0),
503  std::forward<Args>(args)...),
504  true);
505  }
506 
507  template <typename Component, typename Action>
509  const typename Component::array_index& array_index) noexcept {
510  mock_distributed_objects<Component>()
511  .at(array_index)
512  .template simple_action<Action>(true);
513  }
514  /// @}
515 
516  /// @{
517  /// Invoke the threaded action `Action` on the `Component` labeled by
518  /// `array_index` immediately.
519  template <typename Component, typename Action, typename Arg0,
520  typename... Args>
521  void threaded_action(const typename Component::array_index& array_index,
522  Arg0&& arg0, Args&&... args) noexcept {
523  mock_distributed_objects<Component>()
524  .at(array_index)
525  .template threaded_action<Action>(
526  std::make_tuple(std::forward<Arg0>(arg0),
527  std::forward<Args>(args)...),
528  true);
529  }
530 
531  template <typename Component, typename Action>
533  const typename Component::array_index& array_index) noexcept {
534  mock_distributed_objects<Component>()
535  .at(array_index)
536  .template threaded_action<Action>(true);
537  }
538  /// @}
539 
540  /// Return true if there are no queued simple actions on the
541  /// `Component` labeled by `array_index`.
542  template <typename Component>
544  const typename Component::array_index& array_index) const noexcept {
545  return mock_distributed_objects<Component>()
546  .at(array_index)
547  .is_simple_action_queue_empty();
548  }
549 
550  /// Return the number of queued simple actions on the
551  /// `Component` labeled by `array_index`.
552  template <typename Component>
554  const typename Component::array_index& array_index) const noexcept {
555  return mock_distributed_objects<Component>()
556  .at(array_index)
557  .simple_action_queue_size();
558  }
559 
560  /// Invoke the next queued simple action on the `Component` labeled by
561  /// `array_index`.
562  template <typename Component>
564  const typename Component::array_index& array_index) noexcept {
565  mock_distributed_objects<Component>()
566  .at(array_index)
567  .invoke_queued_simple_action();
568  }
569 
570  /// Return true if there are no queued threaded actions on the
571  /// `Component` labeled by `array_index`.
572  template <typename Component>
574  const typename Component::array_index& array_index) const noexcept {
575  return mock_distributed_objects<Component>()
576  .at(array_index)
577  .is_threaded_action_queue_empty();
578  }
579 
580  /// Return the number of queued threaded actions on the
581  /// `Component` labeled by `array_index`.
582  template <typename Component>
584  const typename Component::array_index& array_index) const noexcept {
585  return mock_distributed_objects<Component>()
586  .at(array_index)
587  .threaded_action_queue_size();
588  }
589 
590  /// Invoke the next queued threaded action on the `Component` labeled by
591  /// `array_index`.
592  template <typename Component>
594  const typename Component::array_index& array_index) noexcept {
595  mock_distributed_objects<Component>()
596  .at(array_index)
597  .invoke_queued_threaded_action();
598  }
599 
600  /// Instead of the next call to `next_action` applying the next action in
601  /// the action list, force the next action to be `Action`
602  template <typename Component, typename Action>
604  const typename Component::array_index& array_index) noexcept {
605  static_assert(
606  tmpl::list_contains_v<
607  typename MockDistributedObject<Component>::all_actions_list,
608  Action>,
609  "Cannot force a next action that is not in the action list of the "
610  "parallel component. See the first template parameter of "
611  "'force_next_action_to_be' for the component and the second template "
612  "parameter for the action.");
613  bool found_matching_phase = false;
614  const auto invoke_for_phase =
615  [this, &array_index, &found_matching_phase](auto phase_dep_v) noexcept {
616  using PhaseDep = decltype(phase_dep_v);
617  constexpr typename Metavariables::Phase phase = PhaseDep::type::phase;
618  using actions_list = typename PhaseDep::type::action_list;
619  auto& distributed_object =
620  this->mock_distributed_objects<Component>().at(array_index);
621  if (distributed_object.get_phase() == phase) {
622  found_matching_phase = true;
623  distributed_object.force_next_action_to_be(
624  tmpl::conditional_t<
625  std::is_same<tmpl::no_such_type_,
626  tmpl::index_of<actions_list, Action>>::value,
628  tmpl::index_of<actions_list, Action>>::value);
629  }
630  };
631  tmpl::for_each<typename MockDistributedObject<
632  Component>::phase_dependent_action_lists>(invoke_for_phase);
633  if (not found_matching_phase) {
634  ERROR(
635  "Could not find any actions in the current phase for the component '"
636  << pretty_type::short_name<Component>()
637  << "'. Maybe you are not in the phase you expected to be in? The "
638  "integer value corresponding to the current phase is "
639  << static_cast<int>(this->mock_distributed_objects<Component>()
640  .at(array_index)
641  .get_phase()));
642  }
643  }
644 
645  /// Obtain the index into the action list of the next action.
646  template <typename Component>
648  const typename Component::array_index& array_index) const noexcept {
649  return mock_distributed_objects<Component>()
650  .at(array_index)
651  .get_next_action_index();
652  }
653 
654  /// Invoke the next action in the ActionList on the parallel component
655  /// `Component` on the component labeled by `array_index`, failing if it was
656  /// not ready.
657  template <typename Component>
659  const typename Component::array_index& array_index) noexcept {
660  mock_distributed_objects<Component>().at(array_index).next_action();
661  }
662 
663  /// Invoke the next action in the ActionList on the parallel component
664  /// `Component` on the component labeled by `array_index`, returning whether
665  /// it was ready.
666  template <typename Component>
668  const typename Component::array_index& array_index) noexcept {
669  return mock_distributed_objects<Component>()
670  .at(array_index)
671  .next_action_if_ready();
672  }
673 
674  /// @{
675  /// Access the inboxes for a given component.
676  template <typename Component>
677  auto inboxes() noexcept -> std::unordered_map<
678  typename Component::array_index,
679  tuples::tagged_tuple_from_typelist<
680  typename MockDistributedObject<Component>::inbox_tags_list>>& {
681  return tuples::get<InboxesTag<Component>>(inboxes_);
682  }
683 
684  template <typename Component>
685  auto inboxes() const noexcept -> const std::unordered_map<
686  typename Component::array_index,
687  tuples::tagged_tuple_from_typelist<
688  typename MockDistributedObject<Component>::inbox_tags_list>>& {
689  return tuples::get<InboxesTag<Component>>(inboxes_);
690  }
691  /// @}
692 
693  /// Find the set of array indices on Component where the specified
694  /// inbox is not empty.
695  template <typename Component, typename InboxTag>
696  auto nonempty_inboxes() noexcept
697  -> std::unordered_set<typename Component::array_index> {
699  for (const auto& element_box : inboxes<Component>()) {
700  if (not tuples::get<InboxTag>(element_box.second).empty()) {
701  result.insert(element_box.first);
702  }
703  }
704  return result;
705  }
706 
707  /// Access the mocked distributed objects for a component, indexed by array
708  /// index.
709  template <typename Component>
710  auto& mock_distributed_objects() noexcept {
711  return tuples::get<MockDistributedObjectsTag<Component>>(
712  mock_distributed_objects_);
713  }
714 
715  template <typename Component>
716  const auto& mock_distributed_objects() const noexcept {
717  return tuples::get<MockDistributedObjectsTag<Component>>(
718  mock_distributed_objects_);
719  }
720 
721  /// Set the phase of all parallel components to `next_phase`
722  void set_phase(const typename Metavariables::Phase next_phase) noexcept {
723  tmpl::for_each<mock_objects_tags>(
724  [this, &next_phase](auto component_v) noexcept {
725  for (auto& object : tuples::get<typename decltype(component_v)::type>(
726  mock_distributed_objects_)) {
727  object.second.set_phase(next_phase);
728  }
729  });
730  }
731 
732  /// Return number of (mock) global cores.
733  size_t num_global_cores() const noexcept {
734  return mock_nodes_and_local_cores_.size();
735  }
736 
737  /// Return number of (mock) nodes.
738  size_t num_nodes() const noexcept { return mock_global_cores_.size(); }
739 
740  private:
742  mock_global_cores_{};
744  mock_nodes_and_local_cores_{};
745  // There is one MutableGlobalCache and one GlobalCache per
746  // global_core. We need to keep a vector of unique_ptrs rather than
747  // a vector of objects because MutableGlobalCache and GlobalCache
748  // are not move-assignable or copyable (because of their charm++
749  // base classes, in particular CkReductionMgr).
751  mutable_caches_{};
753  Inboxes inboxes_{};
754  CollectionOfMockDistributedObjects mock_distributed_objects_{};
755 };
756 } // namespace ActionTesting
ActionTesting::MockRuntimeSystem::emplace_component
void emplace_component(const typename Component::array_index &array_index, Options &&... opts) noexcept
Emplace a component that does not need to be initialized. emplace_component is deprecated in favor of...
Definition: MockRuntimeSystem.hpp:318
ActionTesting::MockRuntimeSystem::is_simple_action_queue_empty
bool is_simple_action_queue_empty(const typename Component::array_index &array_index) const noexcept
Return true if there are no queued simple actions on the Component labeled by array_index.
Definition: MockRuntimeSystem.hpp:543
ActionTesting::MockRuntimeSystem::invoke_queued_simple_action
void invoke_queued_simple_action(const typename Component::array_index &array_index) noexcept
Invoke the next queued simple action on the Component labeled by array_index.
Definition: MockRuntimeSystem.hpp:563
ActionTesting::MockRuntimeSystem::MockDistributedObjectsTag
Definition: MockRuntimeSystem.hpp:116
ActionTesting::MockRuntimeSystem::invoke_queued_threaded_action
void invoke_queued_threaded_action(const typename Component::array_index &array_index) noexcept
Invoke the next queued threaded action on the Component labeled by array_index.
Definition: MockRuntimeSystem.hpp:593
gsl::at
constexpr T & at(std::array< T, N > &arr, Size index)
Retrieve a entry from a container, with checks in Debug mode that the index being retrieved is valid.
Definition: Gsl.hpp:125
std::is_same
ActionTesting::MockRuntimeSystem::set_phase
void set_phase(const typename Metavariables::Phase next_phase) noexcept
Set the phase of all parallel components to next_phase
Definition: MockRuntimeSystem.hpp:722
std::integral_constant
ActionTesting::MockRuntimeSystem::emplace_array_component_and_initialize
void emplace_array_component_and_initialize(const NodeId node_id, const LocalCoreId local_core_id, const typename Component::array_index &array_index, const typename detail::get_initialization< Component >::InitialValues &initial_values, Options &&... opts) noexcept
Emplace an array component that needs to be initialized.
Definition: MockRuntimeSystem.hpp:326
ActionTesting::MockRuntimeSystem::emplace_group_component_and_initialize
void emplace_group_component_and_initialize(const typename detail::get_initialization< Component >::InitialValues &initial_values, Options &&... opts) noexcept
Emplace a group component that needs to be initialized.
Definition: MockRuntimeSystem.hpp:395
utility
ActionTesting::MockRuntimeSystem::nonempty_inboxes
auto nonempty_inboxes() noexcept -> std::unordered_set< typename Component::array_index >
Find the set of array indices on Component where the specified inbox is not empty.
Definition: MockRuntimeSystem.hpp:696
ActionTesting::MockRuntimeSystem
Definition: MockRuntimeSystem.hpp:97
ActionTesting::MockRuntimeSystem::MockRuntimeSystem
MockRuntimeSystem(tuples::TaggedTuple< CacheTags... > cache_contents, tuples::TaggedTuple< MutableCacheTags... > mutable_cache_contents={}, const std::vector< size_t > &number_of_mock_cores_on_each_mock_node={1})
Construct from the tuple of GlobalCache and MutableGlobalCache objects that might be in a different o...
Definition: MockRuntimeSystem.hpp:216
Parallel::GlobalCache
Definition: ElementReceiveInterpPoints.hpp:15
ActionTesting::MockRuntimeSystem::next_action_if_ready
bool next_action_if_ready(const typename Component::array_index &array_index) noexcept
Invoke the next action in the ActionList on the parallel component Component on the component labeled...
Definition: MockRuntimeSystem.hpp:667
ActionTesting::MockRuntimeSystem::is_threaded_action_queue_empty
bool is_threaded_action_queue_empty(const typename Component::array_index &array_index) const noexcept
Return true if there are no queued threaded actions on the Component labeled by array_index.
Definition: MockRuntimeSystem.hpp:573
ActionTesting
Structures used for mocking the parallel components framework in order to test actions.
Definition: ActionTesting.hpp:337
unordered_set
ActionTesting::MockRuntimeSystem::next_action
void next_action(const typename Component::array_index &array_index) noexcept
Invoke the next action in the ActionList on the parallel component Component on the component labeled...
Definition: MockRuntimeSystem.hpp:658
GlobalCache.hpp
std::vector< size_t >
Error.hpp
ActionTesting::MockRuntimeSystem::force_next_action_to_be
void force_next_action_to_be(const typename Component::array_index &array_index) noexcept
Instead of the next call to next_action applying the next action in the action list,...
Definition: MockRuntimeSystem.hpp:603
tt::is_a_v
constexpr bool is_a_v
Definition: IsA.hpp:50
ActionTesting::MockRuntimeSystem::emplace_singleton_component
void emplace_singleton_component(const NodeId node_id, const LocalCoreId local_core_id, Options &&... opts) noexcept
Emplace a singleton component that does not need to be initialized.
Definition: MockRuntimeSystem.hpp:246
ActionTesting::LocalCoreId
Wraps a size_t representing the local core number. This is so the user can write things like emplace_...
Definition: MockDistributedObject.hpp:148
ActionTesting::MockRuntimeSystem::inboxes
auto inboxes() noexcept -> std::unordered_map< typename Component::array_index, tuples::tagged_tuple_from_typelist< typename MockDistributedObject< Component >::inbox_tags_list >> &
Access the inboxes for a given component.
Definition: MockRuntimeSystem.hpp:677
tuple
db::get
const auto & get(const DataBox< TagList > &box) noexcept
Retrieve the item with tag Tag from the DataBox.
Definition: DataBox.hpp:791
ActionTesting::MockRuntimeSystem::emplace_nodegroup_component
void emplace_nodegroup_component(Options &&... opts) noexcept
Emplace a nodegroup component that does not need to be initialized.
Definition: MockRuntimeSystem.hpp:291
ActionTesting::MockRuntimeSystem::number_of_queued_simple_actions
size_t number_of_queued_simple_actions(const typename Component::array_index &array_index) const noexcept
Return the number of queued simple actions on the Component labeled by array_index.
Definition: MockRuntimeSystem.hpp:553
ActionTesting::MockRuntimeSystem::simple_action
void simple_action(const typename Component::array_index &array_index) noexcept
Invoke the simple action Action on the Component labeled by array_index immediately.
Definition: MockRuntimeSystem.hpp:508
algorithm
ActionTesting::MockRuntimeSystem::num_global_cores
size_t num_global_cores() const noexcept
Return number of (mock) global cores.
Definition: MockRuntimeSystem.hpp:733
TestHelpers.hpp
ERROR
#define ERROR(m)
prints an error message to the standard error stream and aborts the program.
Definition: Error.hpp:37
Options
Utilities for parsing input files.
Definition: MinmodType.hpp:8
ActionTesting::MockRuntimeSystem::simple_action
void simple_action(const typename Component::array_index &array_index, Arg0 &&arg0, Args &&... args) noexcept
Invoke the simple action Action on the Component labeled by array_index immediately.
Definition: MockRuntimeSystem.hpp:497
ActionTesting::MockRuntimeSystem::emplace_nodegroup_component_and_initialize
void emplace_nodegroup_component_and_initialize(const typename detail::get_initialization< Component >::InitialValues &initial_values, Options &&... opts) noexcept
Emplace a nodegroup component that needs to be initialized.
Definition: MockRuntimeSystem.hpp:434
cstddef
ActionTesting::MockRuntimeSystem::MockRuntimeSystem
MockRuntimeSystem(CacheTuple cache_contents, MutableCacheTuple mutable_cache_contents={}, const std::vector< size_t > &number_of_mock_cores_on_each_mock_node={1})
Construct from the tuple of GlobalCache objects.
Definition: MockRuntimeSystem.hpp:138
ActionTesting::MockRuntimeSystem::InboxesTag
Definition: MockRuntimeSystem.hpp:108
ActionTesting::NodeId
Wraps a size_t representing the node number. This is so the user can write things like emplace_array_...
Definition: MockDistributedObject.hpp:125
ActionTesting::MockRuntimeSystem::number_of_queued_threaded_actions
size_t number_of_queued_threaded_actions(const typename Component::array_index &array_index) const noexcept
Return the number of queued threaded actions on the Component labeled by array_index.
Definition: MockRuntimeSystem.hpp:583
ActionTesting::MockRuntimeSystem::emplace_group_component
void emplace_group_component(Options &&... opts) noexcept
Emplace a group component that does not need to be initialized.
Definition: MockRuntimeSystem.hpp:268
ActionTesting::MockDistributedObject
MockDistributedObject mocks the AlgorithmImpl class. It should not be considered as part of the user ...
Definition: MockDistributedObject.hpp:228
ActionTesting::MockRuntimeSystem::emplace_array_component
void emplace_array_component(const NodeId node_id, const LocalCoreId local_core_id, const typename Component::array_index &array_index, Options &&... opts) noexcept
Emplace an array component that does not need to be initialized.
Definition: MockRuntimeSystem.hpp:228
tuples::TaggedTuple
An associative container that is indexed by structs.
Definition: TaggedTuple.hpp:271
ActionTesting::MockRuntimeSystem::num_nodes
size_t num_nodes() const noexcept
Return number of (mock) nodes.
Definition: MockRuntimeSystem.hpp:738
memory
serialize_and_deserialize
T serialize_and_deserialize(const T &t)
Serializes and deserializes an object t of type T
Definition: TestHelpers.hpp:45
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:117
ActionTesting::MockRuntimeSystem::threaded_action
void threaded_action(const typename Component::array_index &array_index, Arg0 &&arg0, Args &&... args) noexcept
Invoke the threaded action Action on the Component labeled by array_index immediately.
Definition: MockRuntimeSystem.hpp:521
ActionTesting::MockRuntimeSystem::emplace_component_and_initialize
void emplace_component_and_initialize(const typename Component::array_index &array_index, const typename detail::get_initialization< Component >::InitialValues &initial_values, Options &&... opts) noexcept
Emplace a component that needs to be initialized. emplace_component_and_initialize is deprecated in f...
Definition: MockRuntimeSystem.hpp:482
ActionTesting::MockRuntimeSystem::mock_distributed_objects
auto & mock_distributed_objects() noexcept
Access the mocked distributed objects for a component, indexed by array index.
Definition: MockRuntimeSystem.hpp:710
ActionTesting::MockRuntimeSystem::threaded_action
void threaded_action(const typename Component::array_index &array_index) noexcept
Invoke the threaded action Action on the Component labeled by array_index immediately.
Definition: MockRuntimeSystem.hpp:532
Parallel::get_mutable_global_cache_tags
tmpl::remove_duplicates< tmpl::flatten< tmpl::list< typename detail::get_mutable_global_cache_tags_from_parallel_struct< Metavariables >::type, tmpl::transform< typename Metavariables::component_list, detail::get_mutable_global_cache_tags_from_parallel_struct< tmpl::_1 > >, tmpl::transform< typename Metavariables::component_list, detail::get_mutable_global_cache_tags_from_pdal< tmpl::_1 > >> >> get_mutable_global_cache_tags
Given the metavariables, get a list of the unique tags that will specify the mutable items in the Glo...
Definition: ParallelComponentHelpers.hpp:135
Requires
typename Requires_detail::requires_impl< B >::template_error_type_failed_to_meet_requirements_on_template_parameters Requires
Express requirements on the template parameters of a function or class, replaces std::enable_if_t
Definition: Requires.hpp:67
numeric
unordered_map
ActionTesting::MockRuntimeSystem::emplace_singleton_component_and_initialize
void emplace_singleton_component_and_initialize(const NodeId node_id, const LocalCoreId local_core_id, const typename detail::get_initialization< Component >::InitialValues &initial_values, Options &&... opts) noexcept
Emplace a singleton component that needs to be initialized.
Definition: MockRuntimeSystem.hpp:358
ActionTesting::MockRuntimeSystem::get_next_action_index
size_t get_next_action_index(const typename Component::array_index &array_index) const noexcept
Obtain the index into the action list of the next action.
Definition: MockRuntimeSystem.hpp:647
TMPL.hpp
ActionTesting::MockRuntimeSystem::inboxes
auto inboxes() const noexcept -> const std::unordered_map< typename Component::array_index, tuples::tagged_tuple_from_typelist< typename MockDistributedObject< Component >::inbox_tags_list >> &
Access the inboxes for a given component.
Definition: MockRuntimeSystem.hpp:685