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