MockDistributedObject.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <algorithm>
7 #include <array>
8 #include <boost/preprocessor/control/if.hpp>
9 #include <boost/preprocessor/logical/compl.hpp>
10 #include <boost/preprocessor/logical/not.hpp>
11 #include <boost/preprocessor/punctuation/comma_if.hpp>
12 #include <boost/preprocessor/repetition/repeat.hpp>
13 #include <converse.h>
14 #include <cstddef>
15 #include <deque>
16 #include <exception>
17 #include <memory>
18 #include <tuple>
19 #include <unordered_map>
20 #include <utility>
21 
22 #include "Parallel/AlgorithmMetafunctions.hpp"
23 #include "Parallel/GlobalCache.hpp"
24 #include "Parallel/NodeLock.hpp"
25 #include "Parallel/ParallelComponentHelpers.hpp"
26 #include "Parallel/PhaseDependentActionList.hpp"
27 #include "Parallel/SimpleActionVisitation.hpp"
28 #include "Parallel/Tags/Metavariables.hpp"
31 #include "Utilities/Gsl.hpp"
32 #include "Utilities/NoSuchType.hpp"
33 #include "Utilities/Overloader.hpp"
34 #include "Utilities/PrettyType.hpp"
35 #include "Utilities/StdHelpers.hpp"
36 #include "Utilities/TMPL.hpp"
37 #include "Utilities/TypeTraits.hpp"
38 
39 namespace ActionTesting {
40 /// \cond
41 struct MockNodeGroupChare;
42 /// \endcond
43 
44 namespace detail {
45 
46 #define ACTION_TESTING_CHECK_MOCK_ACTION_LIST(NAME) \
47  template <typename Component, typename = std::void_t<>> \
48  struct get_##NAME##_mocking_list { \
49  using replace_these_##NAME = tmpl::list<>; \
50  using with_these_##NAME = tmpl::list<>; \
51  }; \
52  template <typename Component> \
53  struct get_##NAME##_mocking_list< \
54  Component, std::void_t<typename Component::replace_these_##NAME, \
55  typename Component::with_these_##NAME>> { \
56  using replace_these_##NAME = typename Component::replace_these_##NAME; \
57  using with_these_##NAME = typename Component::with_these_##NAME; \
58  }; \
59  template <typename Component> \
60  using replace_these_##NAME##_t = \
61  typename get_##NAME##_mocking_list<Component>::replace_these_##NAME; \
62  template <typename Component> \
63  using with_these_##NAME##_t = \
64  typename get_##NAME##_mocking_list<Component>::with_these_##NAME
65 
66 ACTION_TESTING_CHECK_MOCK_ACTION_LIST(simple_actions);
67 ACTION_TESTING_CHECK_MOCK_ACTION_LIST(threaded_actions);
68 #undef ACTION_TESTING_CHECK_MOCK_ACTION_LIST
69 
70 template <typename Component, typename = std::void_t<>>
71 struct get_initialization_tags_from_component {
72  using type = tmpl::list<>;
73 };
74 
75 template <typename Component>
76 struct get_initialization_tags_from_component<
77  Component, std::void_t<typename Component::initialization_tags>> {
78  using type = typename Component::initialization_tags;
79 };
80 
81 // Given the tags `SimpleTags`, forwards them into the `DataBox`.
82 template <typename SimpleTagsList>
83 struct ForwardAllOptionsToDataBox;
84 
85 template <typename... SimpleTags>
86 struct ForwardAllOptionsToDataBox<tmpl::list<SimpleTags...>> {
87  using simple_tags = tmpl::list<SimpleTags...>;
88 
89  template <typename DbTagsList, typename... Args>
90  static auto apply(db::DataBox<DbTagsList>&& box, Args&&... args) noexcept {
91  static_assert(
92  sizeof...(SimpleTags) == sizeof...(Args),
93  "The number of arguments passed to ForwardAllOptionsToDataBox must "
94  "match the number of SimpleTags passed.");
95  return db::create_from<db::RemoveTags<>, simple_tags>(
96  std::move(box), std::forward<Args>(args)...);
97  }
98 };
99 
100 // Returns the type of `Tag` (including const and reference-ness as would be
101 // returned by `db::get<Tag>`) if the tag is in the `DataBox` of type
102 // `DataBoxType`, otherwise returns `NoSuchType`.
103 template <typename Tag, typename DataBoxType,
104  bool = db::tag_is_retrievable_v<Tag, DataBoxType>>
105 struct item_type_if_contained;
106 
107 template <typename Tag, typename DataBoxType>
108 struct item_type_if_contained<Tag, DataBoxType, true> {
109  using type = decltype(db::get<Tag>(DataBoxType{}));
110 };
111 
112 template <typename Tag, typename DataBoxType>
113 struct item_type_if_contained<Tag, DataBoxType, false> {
114  using type = NoSuchType;
115 };
116 
117 template <typename Tag, typename DataBoxType>
118 using item_type_if_contained_t =
119  typename item_type_if_contained<Tag, DataBoxType>::type;
120 } // namespace detail
121 
122 /// Wraps a size_t representing the node number. This is so the user
123 /// can write things like `emplace_array_component(NodeId{3},...)` instead of
124 /// `emplace_array_component(3,...)`.
125 struct NodeId {
126  size_t value;
127 };
128 
129 inline bool operator==(const NodeId& lhs, const NodeId& rhs) noexcept {
130  return lhs.value == rhs.value;
131 }
132 
133 inline bool operator!=(const NodeId& lhs, const NodeId& rhs) noexcept {
134  return not(lhs==rhs);
135 }
136 
137 /// Wraps a size_t representing the local core number. This is so the
138 /// user can write things like
139 /// `emplace_array_component(NodeId{3},LocalCoreId{2},...)` instead of
140 /// `emplace_array_component(3,2,...)`.
141 ///
142 /// The local core number is unique for each core on the same node,
143 /// but cores on different nodes can have the same local core number.
144 /// For example, if there are 3 nodes with 2
145 /// cores each, then the cores on the first node have local core numbers
146 /// 0 and 1, the cores on the second node also have local core numbers
147 /// 0 and 1, and so on.
148 struct LocalCoreId {
149  size_t value;
150 };
151 
152 inline bool operator==(const LocalCoreId& lhs,
153  const LocalCoreId& rhs) noexcept {
154  return lhs.value == rhs.value;
155 }
156 
157 inline bool operator!=(const LocalCoreId& lhs,
158  const LocalCoreId& rhs) noexcept {
159  return not(lhs==rhs);
160 }
161 
162 /// Wraps a size_t representing the global core number.
163 ///
164 /// The global core number is unique for each core, even if the cores
165 /// are on different nodes. For example, if there are 3 nodes with 2
166 /// cores each, the global core number goes from 0 through 5 to label
167 /// each of the 6 cores, and no two cores have the same global core
168 /// number.
169 struct GlobalCoreId {
170  size_t value;
171 };
172 
173 inline bool operator==(const GlobalCoreId& lhs,
174  const GlobalCoreId& rhs) noexcept {
175  return lhs.value == rhs.value;
176 }
177 
178 inline bool operator!=(const GlobalCoreId& lhs,
179  const GlobalCoreId& rhs) noexcept {
180  return not(lhs==rhs);
181 }
182 } // namespace ActionTesting
183 
184 namespace std {
185 template <>
186 struct hash<ActionTesting::NodeId> {
187  size_t operator()(const ActionTesting::NodeId& t) const { return t.value; }
188 };
189 
190 template <>
191 struct hash<ActionTesting::LocalCoreId> {
192  size_t operator()(const ActionTesting::LocalCoreId& t) const {
193  return t.value;
194  }
195 };
196 
197 template <>
198 struct hash<ActionTesting::GlobalCoreId> {
199  size_t operator()(const ActionTesting::GlobalCoreId& t) const {
200  return t.value;
201  }
202 };
203 } // namespace std
204 
205 namespace ActionTesting {
206 /// MockDistributedObject mocks the AlgorithmImpl class. It should not be
207 /// considered as part of the user interface.
208 ///
209 /// `MockDistributedObject` represents an object on a supercomputer
210 /// that can have methods invoked on it (possibly) remotely; this is
211 /// standard nomenclature in the HPC community, based on the idea that
212 /// such objects get distributed among the cores/nodes on an HPC (even
213 /// though each object typically lives on only one core). For
214 /// example, an element of an array chare in charm++ is a mock
215 /// distributed object, whereas the entire array chare is a collection
216 /// of mock distributed objects, each with its own array
217 /// index.
218 /// `MockDistributedObject` is a modified implementation of
219 /// `AlgorithmImpl` and so some of the code is shared between the
220 /// two. The main difference is that `MockDistributedObject` has
221 /// support for introspection. For example, it is possible to check
222 /// how many simple actions are queued, to look at the inboxes,
223 /// etc. Another key difference is that `MockDistributedObject` runs
224 /// only one action in the action list at a time. This is done in
225 /// order to provide opportunity for introspection and checking
226 /// statements before and after actions are invoked.
227 template <typename Component>
229  private:
230  class InvokeActionBase {
231  public:
232  InvokeActionBase() = default;
233  InvokeActionBase(const InvokeActionBase&) = default;
234  InvokeActionBase& operator=(const InvokeActionBase&) = default;
235  InvokeActionBase(InvokeActionBase&&) = default;
236  InvokeActionBase& operator=(InvokeActionBase&&) = default;
237  virtual ~InvokeActionBase() = default;
238  virtual void invoke_action() noexcept = 0;
239  };
240 
241  // Holds the arguments to be passed to the simple action once it is invoked.
242  // We delay simple action calls that are made from within an action for
243  // several reasons:
244  // - This is consistent with what actually happens in the parallel code
245  // - This prevents possible stack overflows
246  // - Allows better introspection and control over the Actions' behavior
247  template <typename Action, typename... Args>
248  class InvokeSimpleAction : public InvokeActionBase {
249  public:
250  InvokeSimpleAction(MockDistributedObject* mock_distributed_object,
251  std::tuple<Args...> args)
252  : mock_distributed_object_(mock_distributed_object),
253  args_(std::move(args)) {}
254 
255  explicit InvokeSimpleAction(MockDistributedObject* mock_distributed_object)
256  : mock_distributed_object_(mock_distributed_object) {}
257 
258  void invoke_action() noexcept override {
259  if (not valid_) {
260  ERROR(
261  "Cannot invoke the exact same simple action twice. This is an "
262  "internal bug in the action testing framework. Please file an "
263  "issue.");
264  }
265  valid_ = false;
266  invoke_action_impl(std::move(args_));
267  }
268 
269  private:
270  template <typename Arg0, typename... Rest>
271  void invoke_action_impl(std::tuple<Arg0, Rest...> args) noexcept {
272  mock_distributed_object_->simple_action<Action>(std::move(args), true);
273  }
274 
275  template <typename... LocalArgs,
276  Requires<sizeof...(LocalArgs) == 0> = nullptr>
277  void invoke_action_impl(std::tuple<LocalArgs...> /*args*/) noexcept {
278  mock_distributed_object_->simple_action<Action>(true);
279  }
280 
281  MockDistributedObject* mock_distributed_object_;
282  std::tuple<Args...> args_{};
283  bool valid_{true};
284  };
285 
286  // Holds the arguments passed to threaded actions. `InvokeThreadedAction` is
287  // analogous to `InvokeSimpleAction`.
288  template <typename Action, typename... Args>
289  class InvokeThreadedAction : public InvokeActionBase {
290  public:
291  InvokeThreadedAction(MockDistributedObject* mock_distributed_object,
292  std::tuple<Args...> args)
293  : mock_distributed_object_(mock_distributed_object),
294  args_(std::move(args)) {}
295 
296  explicit InvokeThreadedAction(
297  MockDistributedObject* mock_distributed_object)
298  : mock_distributed_object_(mock_distributed_object) {}
299 
300  void invoke_action() noexcept override {
301  if (not valid_) {
302  ERROR(
303  "Cannot invoke the exact same threaded action twice. This is an "
304  "internal bug in the action testing framework. Please file an "
305  "issue.");
306  }
307  valid_ = false;
308  invoke_action_impl(std::move(args_));
309  }
310 
311  private:
312  template <typename Arg0, typename... Rest>
313  void invoke_action_impl(std::tuple<Arg0, Rest...> args) noexcept {
314  mock_distributed_object_->threaded_action<Action>(std::move(args), true);
315  }
316 
317  template <typename... LocalArgs,
318  Requires<sizeof...(LocalArgs) == 0> = nullptr>
319  void invoke_action_impl(std::tuple<LocalArgs...> /*args*/) noexcept {
320  mock_distributed_object_->threaded_action<Action>(true);
321  }
322 
323  MockDistributedObject* mock_distributed_object_;
324  std::tuple<Args...> args_{};
325  bool valid_{true};
326  };
327 
328  public:
329  using phase_dependent_action_lists =
330  typename Component::phase_dependent_action_list;
331  static_assert(tmpl::size<phase_dependent_action_lists>::value > 0,
332  "Must have at least one phase dependent action list "
333  "(PhaseActions) in a parallel component.");
334 
335  using all_actions_list = tmpl::flatten<tmpl::transform<
336  phase_dependent_action_lists,
338 
339  using metavariables = typename Component::metavariables;
340 
341  using inbox_tags_list =
343 
344  using array_index = typename Parallel::get_array_index<
345  typename Component::chare_type>::template f<Component>;
346 
347  using parallel_component = Component;
348 
349  using PhaseType =
350  typename tmpl::front<phase_dependent_action_lists>::phase_type;
351 
353  using initialization_tags =
354  typename detail::get_initialization_tags_from_component<Component>::type;
355  using initial_tags = tmpl::flatten<tmpl::list<
359  using initial_databox = db::compute_databox_type<initial_tags>;
360 
361  // The types held by the boost::variant, box_
362  using databox_phase_types =
363  typename Parallel::Algorithm_detail::build_databox_types<
364  tmpl::list<>, phase_dependent_action_lists, initial_databox,
365  inbox_tags_list, metavariables, typename Component::array_index,
366  Component>::type;
367  template <typename T>
369  using type = typename T::databox_types;
370  };
371 
372  using databox_types = tmpl::flatten<
373  tmpl::transform<databox_phase_types, get_databox_types<tmpl::_1>>>;
374  using variant_boxes = tmpl::remove_duplicates<
375  tmpl::push_front<databox_types, db::DataBox<tmpl::list<>>>>;
376 
377  MockDistributedObject() = default;
378 
379  template <typename... Options>
381  const NodeId node_id, const LocalCoreId local_core_id,
383  mock_global_cores,
385  mock_nodes_and_local_cores,
386  const array_index& index,
388  tuples::tagged_tuple_from_typelist<inbox_tags_list>* inboxes,
389  Options&&... opts)
390  : mock_node_(node_id.value),
391  mock_local_core_(local_core_id.value),
392  mock_global_cores_(std::move(mock_global_cores)),
393  mock_nodes_and_local_cores_(std::move(mock_nodes_and_local_cores)),
394  array_index_(index),
395  global_cache_(cache),
396  inboxes_(inboxes) {
397  box_ = detail::ForwardAllOptionsToDataBox<initialization_tags>::apply(
398  db::create<
402  all_cache_tags>>>(
403  metavariables{}, global_cache_),
404  std::forward<Options>(opts)...);
405  }
406 
407  void set_phase(PhaseType phase) noexcept {
408  phase_ = phase;
409  algorithm_step_ = 0;
410  terminate_ = number_of_actions_in_phase(phase) == 0;
411  halt_algorithm_until_next_phase_ = false;
412  }
413  PhaseType get_phase() const noexcept { return phase_; }
414 
415  void set_terminate(bool t) noexcept { terminate_ = t; }
416  bool get_terminate() const noexcept { return terminate_; }
417 
418  // Actions may call this, but since tests step through actions manually it has
419  // no effect.
420  void perform_algorithm() noexcept {}
421 
422  size_t number_of_actions_in_phase(const PhaseType phase) const noexcept {
423  size_t number_of_actions = 0;
424  tmpl::for_each<phase_dependent_action_lists>(
425  [&number_of_actions, phase](auto pdal_v) {
426  const auto pdal = tmpl::type_from<decltype(pdal_v)>{};
427  if (pdal.phase == phase) {
428  number_of_actions = pdal.number_of_actions;
429  }
430  });
431  return number_of_actions;
432  }
433 
434  /// @{
435  /// Returns the DataBox with the tags set from the GlobalCache and the
436  /// tags in `AdditionalTagsList`. If the DataBox type is incorrect
437  /// `std::terminate` is called.
438  template <typename AdditionalTagsList>
439  auto& get_databox() noexcept {
440  using box_type = db::compute_databox_type<
441  tmpl::flatten<tmpl::list<initial_tags, AdditionalTagsList>>>;
442  return boost::get<box_type>(box_);
443  }
444 
445  template <typename AdditionalTagsList>
446  const auto& get_databox() const noexcept {
447  using box_type = db::compute_databox_type<
448  tmpl::flatten<tmpl::list<initial_tags, AdditionalTagsList>>>;
449  return boost::get<box_type>(box_);
450  }
451  /// @}
452 
453  /// Walks through the variant of DataBoxes and retrieves the tag from the
454  /// current one, if the current DataBox has the tag. If the current DataBox
455  /// does not have the requested tag it is an error.
456  template <typename Tag>
457  const auto& get_databox_tag() const noexcept {
458  return get_databox_tag_visitation<Tag>(box_);
459  }
460 
461  template <typename Tag>
462  bool box_contains() const noexcept {
463  return box_contains_visitation<Tag>(box_);
464  }
465 
466  template <typename Tag>
467  bool tag_is_retrievable() const noexcept {
468  return tag_is_retrievable_visitation<Tag>(box_);
469  }
470 
471  /// @{
472  /// Returns the `boost::variant` of DataBoxes.
473  auto& get_variant_box() noexcept { return box_; }
474 
475  const auto& get_variant_box() const noexcept { return box_; }
476  /// @}
477 
478  /// Force the next action invoked to be the `next_action_id`th action in the
479  /// current phase.
480  void force_next_action_to_be(const size_t next_action_id) noexcept {
481  algorithm_step_ = next_action_id;
482  }
483 
484  /// Returns which action (by integer) will be invoked next in the current
485  /// phase.
486  size_t get_next_action_index() const noexcept { return algorithm_step_; }
487 
488  /// Invoke the next action in the action list for the current phase,
489  /// failing if it was not ready.
490  void next_action() noexcept;
491 
492  /// Invoke the next action in the action list for the current phase,
493  /// returning whether the action was ready.
494  bool next_action_if_ready() noexcept;
495 
496  /// Defines the methods used for invoking threaded and simple actions. Since
497  /// the two cases are so similar we use a macro to reduce the amount of
498  /// redundant code.
499 #define SIMPLE_AND_THREADED_ACTIONS(USE_SIMPLE_ACTION, NAME) \
500  template <typename Action, typename... Args, \
501  Requires<not tmpl::list_contains_v< \
502  detail::replace_these_##NAME##s_t<Component>, Action>> = \
503  nullptr> \
504  void NAME(std::tuple<Args...> args, \
505  const bool direct_from_action_runner = false) noexcept { \
506  if (direct_from_action_runner) { \
507  performing_action_ = true; \
508  forward_tuple_to_##NAME<Action>( \
509  std::move(args), std::make_index_sequence<sizeof...(Args)>{}); \
510  performing_action_ = false; \
511  } else { \
512  NAME##_queue_.push_back( \
513  std::make_unique<BOOST_PP_IF(USE_SIMPLE_ACTION, InvokeSimpleAction, \
514  InvokeThreadedAction) < Action, \
515  Args...> > (this, std::move(args))); \
516  } \
517  } \
518  template <typename Action, typename... Args, \
519  Requires<tmpl::list_contains_v< \
520  detail::replace_these_##NAME##s_t<Component>, Action>> = \
521  nullptr> \
522  void NAME(std::tuple<Args...> args, \
523  const bool direct_from_action_runner = false) noexcept { \
524  using index_of_action = \
525  tmpl::index_of<detail::replace_these_##NAME##s_t<Component>, Action>; \
526  using new_action = tmpl::at_c<detail::with_these_##NAME##s_t<Component>, \
527  index_of_action::value>; \
528  if (direct_from_action_runner) { \
529  performing_action_ = true; \
530  forward_tuple_to_##NAME<new_action>( \
531  std::move(args), std::make_index_sequence<sizeof...(Args)>{}); \
532  performing_action_ = false; \
533  } else { \
534  NAME##_queue_.push_back( \
535  std::make_unique<BOOST_PP_IF(USE_SIMPLE_ACTION, InvokeSimpleAction, \
536  InvokeThreadedAction) < new_action, \
537  Args...> > (this, std::move(args))); \
538  } \
539  } \
540  template <typename Action, \
541  Requires<not tmpl::list_contains_v< \
542  detail::replace_these_##NAME##s_t<Component>, Action>> = \
543  nullptr> \
544  void NAME(const bool direct_from_action_runner = false) noexcept { \
545  if (direct_from_action_runner) { \
546  performing_action_ = true; \
547  Parallel::Algorithm_detail::simple_action_visitor<Action, Component>( \
548  box_, *global_cache_, \
549  std::as_const(array_index_) \
550  BOOST_PP_COMMA_IF(BOOST_PP_NOT(USE_SIMPLE_ACTION)) BOOST_PP_IF( \
551  USE_SIMPLE_ACTION, , make_not_null(&node_lock_))); \
552  performing_action_ = false; \
553  } else { \
554  NAME##_queue_.push_back( \
555  std::make_unique<BOOST_PP_IF(USE_SIMPLE_ACTION, InvokeSimpleAction, \
556  InvokeThreadedAction) < Action> > \
557  (this)); \
558  } \
559  } \
560  template <typename Action, \
561  Requires<tmpl::list_contains_v< \
562  detail::replace_these_##NAME##s_t<Component>, Action>> = \
563  nullptr> \
564  void NAME(const bool direct_from_action_runner = false) noexcept { \
565  using index_of_action = \
566  tmpl::index_of<detail::replace_these_##NAME##s_t<Component>, Action>; \
567  using new_action = tmpl::at_c<detail::with_these_##NAME##s_t<Component>, \
568  index_of_action::value>; \
569  if (direct_from_action_runner) { \
570  performing_action_ = true; \
571  Parallel::Algorithm_detail::simple_action_visitor<new_action, \
572  Component>( \
573  box_, *global_cache_, \
574  std::as_const(array_index_) \
575  BOOST_PP_COMMA_IF(BOOST_PP_NOT(USE_SIMPLE_ACTION)) BOOST_PP_IF( \
576  USE_SIMPLE_ACTION, , make_not_null(&node_lock_))); \
577  performing_action_ = false; \
578  } else { \
579  simple_action_queue_.push_back( \
580  std::make_unique<BOOST_PP_IF(USE_SIMPLE_ACTION, InvokeSimpleAction, \
581  InvokeThreadedAction) < new_action> > \
582  (this)); \
583  } \
584  }
585 
586  SIMPLE_AND_THREADED_ACTIONS(1, simple_action)
587  SIMPLE_AND_THREADED_ACTIONS(0, threaded_action)
588 #undef SIMPLE_AND_THREADED_ACTIONS
589 
590  // local synchronous actions are performed as direct function calls
591  // regardless, so their 'mocking' implementation is no different from their
592  // original implementation
593  template <typename Action, typename... Args>
594  typename Action::return_type local_synchronous_action(
595  Args&&... args) noexcept {
596  static_assert(std::is_same_v<typename Component::chare_type,
598  "Cannot call a local synchronous action on a chare that is "
599  "not a NodeGroup");
600  return Parallel::Algorithm_detail::local_synchronous_action_visitor<
601  Action, Component>(box_, make_not_null(&node_lock_),
602  std::forward<Args>(args)...);
603  }
604 
605  bool is_simple_action_queue_empty() const noexcept {
606  return simple_action_queue_.empty();
607  }
608 
609  size_t simple_action_queue_size() const noexcept {
610  return simple_action_queue_.size();
611  }
612 
613  void invoke_queued_simple_action() noexcept {
614  if (simple_action_queue_.empty()) {
615  ERROR(
616  "There are no queued simple actions to invoke. Are you sure a "
617  "previous action invoked a simple action on this component?");
618  }
619  simple_action_queue_.front()->invoke_action();
620  simple_action_queue_.pop_front();
621  }
622 
623  bool is_threaded_action_queue_empty() const noexcept {
624  return threaded_action_queue_.empty();
625  }
626 
627  size_t threaded_action_queue_size() const noexcept {
628  return threaded_action_queue_.size();
629  }
630 
631  void invoke_queued_threaded_action() noexcept {
632  if (threaded_action_queue_.empty()) {
633  ERROR(
634  "There are no queued threaded actions to invoke. Are you sure a "
635  "previous action invoked a threaded action on this component?");
636  }
637  threaded_action_queue_.front()->invoke_action();
638  threaded_action_queue_.pop_front();
639  }
640 
641  template <typename InboxTag, typename Data>
642  void receive_data(const typename InboxTag::temporal_id& id, Data&& data,
643  const bool enable_if_disabled = false) {
644  // The variable `enable_if_disabled` might be useful in the future but is
645  // not needed now. However, it is required by the interface to be compliant
646  // with the Algorithm invocations.
647  (void)enable_if_disabled;
648  InboxTag::insert_into_inbox(
649  make_not_null(&tuples::get<InboxTag>(*inboxes_)), id,
650  std::forward<Data>(data));
651  }
652 
654  return *global_cache_;
655  }
656 
657  /// @{
658  /// Wrappers for charm++ informational functions.
659 
660  /// Number of processing elements
661  int number_of_procs() const noexcept;
662 
663  /// Global %Index of my processing element.
664  int my_proc() const noexcept;
665 
666  /// Number of nodes.
667  int number_of_nodes() const noexcept;
668 
669  /// %Index of my node.
670  int my_node() const noexcept;
671 
672  /// Number of processing elements on the given node.
673  int procs_on_node(int node_index) const noexcept;
674 
675  /// The local index of my processing element on my node.
676  /// This is in the interval 0, ..., procs_on_node(my_node()) - 1.
677  int my_local_rank() const noexcept;
678 
679  /// %Index of first processing element on the given node.
680  int first_proc_on_node(int node_index) const noexcept;
681 
682  /// %Index of the node for the given processing element.
683  int node_of(int proc_index) const noexcept;
684 
685  /// The local index for the given processing element on its node.
686  int local_rank_of(int proc_index) const noexcept;
687  /// @}
688 
689  private:
690  template <typename Action, typename... Args, size_t... Is>
691  void forward_tuple_to_simple_action(
692  std::tuple<Args...>&& args,
693  std::index_sequence<Is...> /*meta*/) noexcept {
694  Parallel::Algorithm_detail::simple_action_visitor<Action, Component>(
695  box_, *global_cache_, std::as_const(array_index_),
696  std::forward<Args>(std::get<Is>(args))...);
697  }
698 
699  template <typename Action, typename... Args, size_t... Is>
700  void forward_tuple_to_threaded_action(
701  std::tuple<Args...>&& args,
702  std::index_sequence<Is...> /*meta*/) noexcept {
703  Parallel::Algorithm_detail::simple_action_visitor<Action, Component>(
704  box_, *global_cache_, std::as_const(array_index_),
705  make_not_null(&node_lock_), std::forward<Args>(std::get<Is>(args))...);
706  }
707 
708  template <typename ThisAction, typename ActionList, typename DbTags>
709  bool invoke_iterable_action(db::DataBox<DbTags>& my_box) noexcept {
710  auto action_return = ThisAction::apply(
711  my_box, *inboxes_, *global_cache_, std::as_const(array_index_),
712  ActionList{}, std::add_pointer_t<Component>{});
713 
714  static_assert(
715  Parallel::Algorithm_detail::check_iterable_action_return_type<
716  parallel_component, ThisAction,
717  std::decay_t<decltype(action_return)>>::value,
718  "An iterable action has an invalid return type.\n"
719  "See the template parameters of "
720  "Algorithm_detail::check_iterable_action_return_type for details: the "
721  "first is the parallel component in question, the second is the "
722  "iterable action, and the third is the return type at fault.\n"
723  "The return type must be a tuple of length one, two, or three "
724  "with:\n"
725  " first type is an updated DataBox;\n"
726  " second type is either a bool (indicating termination) or a "
727  "`Parallel::AlgorithmExecution` object;\n"
728  " third type is a size_t indicating the next action in the current"
729  " phase.");
730 
731  constexpr size_t tuple_size =
732  std::tuple_size<decltype(action_return)>::value;
733  if constexpr (tuple_size >= 1_st) {
734  box_ = std::move(std::get<0>(action_return));
735  }
736  if constexpr (tuple_size >= 2_st) {
737  if constexpr (std::is_same_v<decltype(std::get<1>(action_return)),
738  bool&>) {
739  terminate_ = std::get<1>(action_return);
740  } else {
741  switch (std::get<1>(action_return)) {
743  halt_algorithm_until_next_phase_ = true;
744  terminate_ = true;
745  break;
747  terminate_ = true;
748  break;
750  return false;
751  default:
752  break;
753  }
754  }
755  }
756  if constexpr (tuple_size >= 3_st) {
757  algorithm_step_ = std::get<2>(action_return);
758  }
759  return true;
760  }
761 
762  template <typename PhaseDepActions, size_t... Is>
763  bool next_action_impl(std::index_sequence<Is...> /*meta*/) noexcept;
764 
765  template <typename Tag, typename ThisVariantBox, typename Type,
766  typename... Variants,
767  Requires<tmpl::size<tmpl::filter<
768  typename ThisVariantBox::tags_list,
769  std::is_base_of<tmpl::pin<Tag>, tmpl::_1>>>::value !=
770  0> = nullptr>
771  void get_databox_tag_visitation_impl(
772  const Type** result, const gsl::not_null<int*> iter,
773  const gsl::not_null<bool*> already_visited,
774  const boost::variant<Variants...>& box) const noexcept {
775  if (box.which() == *iter and not *already_visited) {
776  *result = &db::get<Tag>(boost::get<ThisVariantBox>(box));
777  (void)result;
778  *already_visited = true;
779  }
780  (*iter)++;
781  }
782  template <typename Tag, typename ThisVariantBox, typename Type,
783  typename... Variants,
784  Requires<tmpl::size<tmpl::filter<
785  typename ThisVariantBox::tags_list,
786  std::is_base_of<tmpl::pin<Tag>, tmpl::_1>>>::value ==
787  0> = nullptr>
788  void get_databox_tag_visitation_impl(
789  const Type** /*result*/, const gsl::not_null<int*> iter,
790  const gsl::not_null<bool*> already_visited,
791  const boost::variant<Variants...>& box) const noexcept {
792  if (box.which() == *iter and not *already_visited) {
793  ERROR("Cannot retrieve tag: "
794  << db::tag_name<Tag>()
795  << " from the current DataBox because it is not in it.");
796  }
797  (*iter)++;
798  }
799 
800  template <typename Tag, typename... Variants>
801  const auto& get_databox_tag_visitation(
802  const boost::variant<Variants...>& box) const noexcept {
803  using item_types = tmpl::remove_duplicates<tmpl::remove_if<
804  tmpl::list<cpp20::remove_cvref_t<
805  detail::item_type_if_contained_t<Tag, Variants>>...>,
807  static_assert(tmpl::size<item_types>::value != 0,
808  "Could not find the tag or the tag as a base tag in any "
809  "DataBox in the get_databox_tag function.");
810  static_assert(
811  tmpl::size<item_types>::value < 2,
812  "Found the tag in or the tag as a base tag in more than one DataBox in "
813  "the get_databox_tag function. This means you need to explicitly "
814  "retrieve the DataBox type to retrieve the tag or file an issue "
815  "requesting a get_databox_tag function that can also take a type "
816  "explicitly. We have not yet encountered a need for this functionality "
817  "but it could be added.");
818  const tmpl::front<item_types>* result = nullptr;
819  int iter = 0;
820  bool already_visited = false;
821  EXPAND_PACK_LEFT_TO_RIGHT(get_databox_tag_visitation_impl<Tag, Variants>(
822  &result, &iter, &already_visited, box));
823  if (result == nullptr) {
824  ERROR("The result pointer is nullptr, which it should never be.\n");
825  }
826  return *result;
827  }
828 
829  template <typename Tag, typename ThisVariantBox, typename... Variants,
830  Requires<tmpl::list_contains_v<typename ThisVariantBox::tags_list,
831  Tag>> = nullptr>
832  void box_contains_visitation_impl(
833  bool* const contains_tag, const gsl::not_null<int*> iter,
834  const boost::variant<Variants...>& box) const noexcept {
835  if (box.which() == *iter) {
836  *contains_tag =
837  tmpl::list_contains_v<typename ThisVariantBox::tags_list, Tag>;
838  }
839  (*iter)++;
840  }
841  template <typename Tag, typename ThisVariantBox, typename... Variants,
842  Requires<not tmpl::list_contains_v<
843  typename ThisVariantBox::tags_list, Tag>> = nullptr>
844  void box_contains_visitation_impl(
845  bool* const /*contains_tag*/, const gsl::not_null<int*> iter,
846  const boost::variant<Variants...>& /*box*/) const noexcept {
847  (*iter)++;
848  }
849 
850  template <typename Tag, typename... Variants>
851  bool box_contains_visitation(
852  const boost::variant<Variants...>& box) const noexcept {
853  bool contains_tag = false;
854  int iter = 0;
856  box_contains_visitation_impl<Tag, Variants>(&contains_tag, &iter, box));
857  return contains_tag;
858  }
859 
860  template <typename Tag, typename... Variants>
861  bool tag_is_retrievable_visitation(
862  const boost::variant<Variants...>& box) const noexcept {
863  bool is_retrievable = false;
864  const auto helper = [&box, &is_retrievable](auto box_type) noexcept {
865  using DataBoxType = typename decltype(box_type)::type;
866  if (static_cast<int>(
867  tmpl::index_of<tmpl::list<Variants...>, DataBoxType>::value) ==
868  box.which()) {
869  is_retrievable = db::tag_is_retrievable_v<Tag, DataBoxType>;
870  }
871  };
872  EXPAND_PACK_LEFT_TO_RIGHT(helper(tmpl::type_<Variants>{}));
873  return is_retrievable;
874  }
875 
876  bool terminate_{false};
877  bool halt_algorithm_until_next_phase_{false};
878  make_boost_variant_over<variant_boxes> box_ = db::DataBox<tmpl::list<>>{};
879  // The next action we should execute.
880  size_t algorithm_step_ = 0;
881  bool performing_action_ = false;
882  PhaseType phase_{};
883 
884  size_t mock_node_{0};
885  size_t mock_local_core_{0};
886  // mock_global_cores[node][local_core] is the global_core.
888  mock_global_cores_{};
889  // mock_nodes_and_local_cores_[global_core] is the pair node,local_core.
891  mock_nodes_and_local_cores_{};
892 
893  typename Component::array_index array_index_{};
895  nullptr};
896  tuples::tagged_tuple_from_typelist<inbox_tags_list>* inboxes_{nullptr};
897  std::deque<std::unique_ptr<InvokeActionBase>> simple_action_queue_;
898  std::deque<std::unique_ptr<InvokeActionBase>> threaded_action_queue_;
899  Parallel::NodeLock node_lock_;
900 };
901 
902 template <typename Component>
904  if (not next_action_if_ready()) {
905  ERROR("Attempted to run an action, but it returned "
906  "AlgorithmExecution::Retry. Actions that are expected to retry "
907  "can be tested with next_action_if_ready().");
908  }
909 }
910 
911 template <typename Component>
913  bool found_matching_phase = false;
914  bool was_ready = false;
915  const auto invoke_for_phase =
916  [this, &found_matching_phase, &was_ready](auto phase_dep_v) noexcept {
917  using PhaseDep = typename decltype(phase_dep_v)::type;
918  constexpr PhaseType phase = PhaseDep::phase;
919  using actions_list = typename PhaseDep::action_list;
920  if (phase_ == phase) {
921  found_matching_phase = true;
922  was_ready = this->template next_action_impl<PhaseDep>(
923  std::make_index_sequence<tmpl::size<actions_list>::value>{});
924  }
925  };
926  tmpl::for_each<phase_dependent_action_lists>(invoke_for_phase);
927  if (not found_matching_phase) {
928  ERROR("Could not find any actions in the current phase for the component '"
929  << pretty_type::short_name<Component>() << "'.");
930  }
931  return was_ready;
932 }
933 
934 template <typename Component>
935 template <typename PhaseDepActions, size_t... Is>
937  std::index_sequence<Is...> /*meta*/) noexcept {
938  if (UNLIKELY(performing_action_)) {
939  ERROR(
940  "Cannot call an Action while already calling an Action on the same "
941  "MockDistributedObject (an element of a parallel component array, or a "
942  "parallel component singleton).");
943  }
944  if (UNLIKELY(halt_algorithm_until_next_phase_)) {
945  ERROR(
946  "The algorithm has been halted pending a phase change. No iterable "
947  "action can be executed until after the next change of phase.");
948  }
949  // Keep track of if we already evaluated an action since we want `next_action`
950  // to only evaluate one per call.
951  bool already_did_an_action = false;
952  bool was_ready = true;
953  const auto helper = [this, &already_did_an_action,
954  &was_ready](auto iteration) noexcept {
955  constexpr size_t iter = decltype(iteration)::value;
956  if (already_did_an_action or algorithm_step_ != iter) {
957  return;
958  }
959 
960  using actions_list = typename PhaseDepActions::action_list;
961  using this_action = tmpl::at_c<actions_list, iter>;
962 
963  constexpr size_t phase_index =
964  tmpl::index_of<phase_dependent_action_lists, PhaseDepActions>::value;
965  using databox_phase_type = tmpl::at_c<databox_phase_types, phase_index>;
966  using databox_types_this_phase = typename databox_phase_type::databox_types;
967 
968  using potential_databox_indices = std::conditional_t<
969  iter == 0_st,
970  tmpl::integral_list<size_t, 0_st,
971  tmpl::size<databox_types_this_phase>::value - 1_st>,
972  tmpl::integral_list<size_t, iter>>;
973  bool box_found = false;
974  tmpl::for_each<potential_databox_indices>(
975  [this, &box_found,
976  &was_ready](auto potential_databox_index_v) noexcept {
977  constexpr size_t potential_databox_index =
978  decltype(potential_databox_index_v)::type::value;
979  using this_databox =
980  tmpl::at_c<databox_types_this_phase, potential_databox_index>;
981  if (not box_found and
982  box_.which() ==
983  static_cast<int>(
984  tmpl::index_of<variant_boxes, this_databox>::value)) {
985  box_found = true;
986  auto& box = boost::get<this_databox>(box_);
987  performing_action_ = true;
988  ++algorithm_step_;
989  if (not invoke_iterable_action<this_action, actions_list>(box)) {
990  was_ready = false;
991  --algorithm_step_;
992  }
993  }
994  });
995  if (not box_found) {
996  ERROR(
997  "The DataBox type being retrieved at algorithm step: "
998  << algorithm_step_ << " in phase " << phase_index
999  << " corresponding to action " << pretty_type::get_name<this_action>()
1000  << " is not the correct type but is of variant index " << box_.which()
1001  << ". If you are using Goto and Label actions then you are using "
1002  "them incorrectly.");
1003  }
1004 
1005  performing_action_ = false;
1006  already_did_an_action = true;
1007  // Wrap counter if necessary
1008  if (algorithm_step_ >= tmpl::size<actions_list>::value) {
1009  algorithm_step_ = 0;
1010  }
1011  };
1012  // Silence compiler warning when there are no Actions.
1013  (void)helper;
1015  return was_ready;
1016 }
1017 
1018 template <typename Component>
1020  return static_cast<int>(mock_nodes_and_local_cores_.size());
1021 }
1022 
1023 template <typename Component>
1025  return static_cast<int>(mock_global_cores_.at(NodeId{mock_node_})
1026  .at(LocalCoreId{mock_local_core_})
1027  .value);
1028 }
1029 
1030 template <typename Component>
1032  return static_cast<int>(mock_global_cores_.size());
1033 }
1034 
1035 template <typename Component>
1037  return static_cast<int>(mock_node_);
1038 }
1039 
1040 template <typename Component>
1042  const int node_index) const noexcept {
1043  return static_cast<int>(
1044  mock_global_cores_.at(NodeId{static_cast<size_t>(node_index)}).size());
1045 }
1046 
1047 template <typename Component>
1049  return static_cast<int>(mock_local_core_);
1050 }
1051 
1052 template <typename Component>
1054  const int node_index) const noexcept {
1055  return static_cast<int>(
1056  mock_global_cores_.at(NodeId{static_cast<size_t>(node_index)})
1057  .at(LocalCoreId{0})
1058  .value);
1059 }
1060 
1061 template <typename Component>
1063  const int proc_index) const noexcept {
1064  return static_cast<int>(mock_nodes_and_local_cores_
1065  .at(GlobalCoreId{static_cast<size_t>(proc_index)})
1066  .first.value);
1067 }
1068 
1069 template <typename Component>
1071  const int proc_index) const noexcept {
1072  return static_cast<int>(mock_nodes_and_local_cores_
1073  .at(GlobalCoreId{static_cast<size_t>(proc_index)})
1074  .second.value);
1075 }
1076 
1077 } // namespace ActionTesting
std::hash::operator()
T operator()(T... args)
NoSuchType
Used to mark "no type" or "bad state" for metaprogramming.
Definition: NoSuchType.hpp:10
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::apply
T apply(T... args)
std::is_same
ActionTesting::MockDistributedObject::local_rank_of
int local_rank_of(int proc_index) const noexcept
The local index for the given processing element on its node.
Definition: MockDistributedObject.hpp:1070
ActionTesting::MockNodeGroupChare
A mock class for the CMake-generated Parallel::Algorithms::NodeGroup
Definition: ActionTesting.hpp:665
std::integral_constant
EXPAND_PACK_LEFT_TO_RIGHT
#define EXPAND_PACK_LEFT_TO_RIGHT(...)
Expand a parameter pack evaluating the terms from left to right.
Definition: TMPL.hpp:601
utility
Parallel::AlgorithmExecution::Retry
@ Retry
Temporarily stop executing iterable actions, but try the same action again after receiving data from ...
exception
UNLIKELY
#define UNLIKELY(x)
Definition: Gsl.hpp:73
Parallel::GlobalCache< typename Component::metavariables >
ActionTesting
Structures used for mocking the parallel components framework in order to test actions.
Definition: ActionTesting.hpp:337
std::pair
GlobalCache.hpp
std::index_sequence
Parallel::Tags::MetavariablesImpl
Definition: Metavariables.hpp:15
ActionTesting::MockDistributedObject::procs_on_node
int procs_on_node(int node_index) const noexcept
Number of processing elements on the given node.
Definition: MockDistributedObject.hpp:1041
Error.hpp
ActionTesting::MockDistributedObject::get_databox_types
Definition: MockDistributedObject.hpp:368
Parallel::AlgorithmExecution::Halt
@ Halt
Stop the execution of iterable actions and do not allow their execution until after a phase change....
PrettyType.hpp
db::compute_databox_type
typename detail::compute_dbox_type< TagList >::type compute_databox_type
Returns the type of the DataBox that would be constructed from the TagList of tags.
Definition: DataBox.hpp:882
Parallel::Tags::FromGlobalCache
Definition: GlobalCache.hpp:694
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::threaded_action
void threaded_action(const gsl::not_null< MockRuntimeSystem< Metavariables > * > runner, const typename Component::array_index &array_index, Args &&... args) noexcept
Runs the simple action Action on the array_indexth element of the parallel component Component.
Definition: MockRuntimeSystemFreeFunctions.hpp:309
db::AddComputeTags
tmpl::flatten< tmpl::list< Tags... > > AddComputeTags
List of Compute Item Tags to add to the DataBox.
Definition: DataBox.hpp:863
BoostHelpers.hpp
tuple
ActionTesting::next_action_if_ready
bool next_action_if_ready(const gsl::not_null< MockRuntimeSystem< Metavariables > * > runner, 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: MockRuntimeSystemFreeFunctions.hpp:287
algorithm
ActionTesting::MockDistributedObject::next_action
void next_action() noexcept
Invoke the next action in the action list for the current phase, failing if it was not ready.
Definition: MockDistributedObject.hpp:903
ActionTesting::MockDistributedObject::node_of
int node_of(int proc_index) const noexcept
Index of the node for the given processing element.
Definition: MockDistributedObject.hpp:1062
ActionTesting::GlobalCoreId
Wraps a size_t representing the global core number.
Definition: MockDistributedObject.hpp:169
Parallel::get_inbox_tags
tmpl::remove_duplicates< tmpl::join< tmpl::transform< ActionsList, detail::get_inbox_tags_from_action< tmpl::_1 > >> > get_inbox_tags
Given a list of Actions, get a list of the unique inbox tags.
Definition: ParallelComponentHelpers.hpp:32
ActionTesting::MockDistributedObject::get_databox_tag
const auto & get_databox_tag() const noexcept
Walks through the variant of DataBoxes and retrieves the tag from the current one,...
Definition: MockDistributedObject.hpp:457
Parallel::NodeLock
A typesafe wrapper for a lock for synchronization of shared resources on a given node,...
Definition: NodeLock.hpp:25
ERROR
#define ERROR(m)
prints an error message to the standard error stream and aborts the program.
Definition: Error.hpp:37
db::create
constexpr auto create(Args &&... args)
Create a new DataBox.
Definition: DataBox.hpp:907
std::add_pointer_t
Options
Utilities for parsing input files.
Definition: MinmodType.hpp:8
ActionTesting::MockDistributedObject::get_databox
const auto & get_databox() const noexcept
Returns the DataBox with the tags set from the GlobalCache and the tags in AdditionalTagsList....
Definition: MockDistributedObject.hpp:446
Parallel::AlgorithmExecution::Pause
@ Pause
Stop the execution of iterable actions, but allow entry methods (communication) to explicitly request...
cstddef
ActionTesting::MockDistributedObject::my_node
int my_node() const noexcept
Index of my node.
Definition: MockDistributedObject.hpp:1036
array
make_boost_variant_over
typename detail::make_boost_variant_over_impl< tmpl::remove_duplicates< Sequence > >::type make_boost_variant_over
Create a boost::variant with all all the types inside the typelist Sequence.
Definition: BoostHelpers.hpp:43
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::MockDistributedObject::get_databox
auto & get_databox() noexcept
Returns the DataBox with the tags set from the GlobalCache and the tags in AdditionalTagsList....
Definition: MockDistributedObject.hpp:439
ActionTesting::MockDistributedObject
MockDistributedObject mocks the AlgorithmImpl class. It should not be considered as part of the user ...
Definition: MockDistributedObject.hpp:228
deque
ActionTesting::MockDistributedObject::number_of_nodes
int number_of_nodes() const noexcept
Number of nodes.
Definition: MockDistributedObject.hpp:1031
ActionTesting::MockDistributedObject::my_local_rank
int my_local_rank() const noexcept
The local index of my processing element on my node. This is in the interval 0, .....
Definition: MockDistributedObject.hpp:1048
Parallel::Tags::GlobalCacheImpl
Definition: GlobalCache.hpp:671
Parallel::get_action_list_from_phase_dep_action_list
(Lazy) metafunction to get the action list from a PhaseActions
Definition: PhaseDependentActionList.hpp:29
ActionTesting::MockDistributedObject::number_of_procs
int number_of_procs() const noexcept
Wrappers for charm++ informational functions.
Definition: MockDistributedObject.hpp:1019
memory
ActionTesting::MockDistributedObject::my_proc
int my_proc() const noexcept
Global Index of my processing element.
Definition: MockDistributedObject.hpp:1024
std::decay_t
ActionTesting::MockDistributedObject::force_next_action_to_be
void force_next_action_to_be(const size_t next_action_id) noexcept
Force the next action invoked to be the next_action_idth action in the current phase.
Definition: MockDistributedObject.hpp:480
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
db::AddSimpleTags
tmpl::flatten< tmpl::list< Tags... > > AddSimpleTags
List of Tags to add to the DataBox.
Definition: DataBox.hpp:856
ActionTesting::cache
Parallel::GlobalCache< Metavariables > & cache(MockRuntimeSystem< Metavariables > &runner, const ArrayIndex &array_index) noexcept
Returns the GlobalCache of Component with index array_index.
Definition: MockRuntimeSystemFreeFunctions.hpp:382
ActionTesting::simple_action
void simple_action(const gsl::not_null< MockRuntimeSystem< Metavariables > * > runner, const typename Component::array_index &array_index, Args &&... args) noexcept
Runs the simple action Action on the array_indexth element of the parallel component Component.
Definition: MockRuntimeSystemFreeFunctions.hpp:297
Gsl.hpp
ActionTesting::MockDistributedObject::next_action_if_ready
bool next_action_if_ready() noexcept
Invoke the next action in the action list for the current phase, returning whether the action was rea...
Definition: MockDistributedObject.hpp:912
ActionTesting::MockDistributedObject::get_variant_box
const auto & get_variant_box() const noexcept
Returns the boost::variant of DataBoxes.
Definition: MockDistributedObject.hpp:475
db::wrap_tags_in
tmpl::transform< TagList, tmpl::bind< Wrapper, tmpl::_1, tmpl::pin< Args >... > > wrap_tags_in
Create a new tmpl::list of tags by wrapping each tag in TagList in Wrapper<_, Args....
Definition: PrefixHelpers.hpp:30
ActionTesting::MockDistributedObject::get_next_action_index
size_t get_next_action_index() const noexcept
Returns which action (by integer) will be invoked next in the current phase.
Definition: MockDistributedObject.hpp:486
StdHelpers.hpp
ActionTesting::MockDistributedObject::first_proc_on_node
int first_proc_on_node(int node_index) const noexcept
Index of first processing element on the given node.
Definition: MockDistributedObject.hpp:1053
make_not_null
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,...
Definition: Gsl.hpp:880
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
std::conditional_t
unordered_map
TMPL.hpp
ActionTesting::MockDistributedObject::get_variant_box
auto & get_variant_box() noexcept
Returns the boost::variant of DataBoxes.
Definition: MockDistributedObject.hpp:473
std::is_base_of
gsl::not_null
Require a pointer to not be a nullptr
Definition: ReadSpecPiecewisePolynomial.hpp:13