Algorithm.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <boost/variant/variant.hpp>
7 #include <charm++.h>
8 #include <converse.h>
9 #include <cstddef>
10 #include <exception>
11 #include <initializer_list>
12 #include <limits>
13 #include <ostream>
14 #include <pup.h>
15 #include <tuple>
16 #include <unordered_map>
17 #include <unordered_set>
18 #include <utility>
19 
20 #include "DataStructures/DataBox/DataBox.hpp" // IWYU pragma: keep
21 #include "DataStructures/DataBox/PrefixHelpers.hpp"
22 #include "Parallel/AlgorithmMetafunctions.hpp"
23 #include "Parallel/Algorithms/AlgorithmArrayDeclarations.hpp"
24 #include "Parallel/Algorithms/AlgorithmGroupDeclarations.hpp"
25 #include "Parallel/Algorithms/AlgorithmNodegroupDeclarations.hpp"
26 #include "Parallel/Algorithms/AlgorithmSingletonDeclarations.hpp"
27 #include "Parallel/CharmRegistration.hpp"
28 #include "Parallel/GlobalCache.hpp"
29 #include "Parallel/Info.hpp"
30 #include "Parallel/NodeLock.hpp"
31 #include "Parallel/ParallelComponentHelpers.hpp"
32 #include "Parallel/PhaseDependentActionList.hpp"
33 #include "Parallel/PupStlCpp11.hpp"
34 #include "Parallel/SimpleActionVisitation.hpp"
35 #include "Parallel/Tags/Metavariables.hpp"
36 #include "Parallel/TypeTraits.hpp"
41 #include "Utilities/Gsl.hpp"
42 #include "Utilities/MakeString.hpp"
43 #include "Utilities/NoSuchType.hpp"
44 #include "Utilities/Overloader.hpp"
45 #include "Utilities/PrettyType.hpp"
46 #include "Utilities/Requires.hpp"
48 #include "Utilities/TMPL.hpp"
49 #include "Utilities/TaggedTuple.hpp"
50 #include "Utilities/TypeTraits.hpp"
51 
52 // IWYU pragma: no_include <array> // for tuple_size
53 
54 // IWYU pragma: no_include "Parallel/Algorithm.hpp" // Include... ourself?
55 
56 namespace Parallel {
57 /// \cond
58 template <typename ParallelComponent, typename PhaseDepActionList>
59 class AlgorithmImpl;
60 /// \endcond
61 
62 namespace Algorithm_detail {
63 template <typename Metavariables, typename Component, typename = std::void_t<>>
64 struct has_registration_list : std::false_type {};
65 
66 template <typename Metavariables, typename Component>
67 struct has_registration_list<
68  Metavariables, Component,
69  std::void_t<
70  typename Metavariables::template registration_list<Component>::type>>
71  : std::true_type {};
72 
73 template <typename Metavariables, typename Component>
74 constexpr bool has_registration_list_v =
75  has_registration_list<Metavariables, Component>::value;
76 } // namespace Algorithm_detail
77 
78 /*!
79  * \ingroup ParallelGroup
80  * \brief A distributed object (Charm++ Chare) that executes a series of Actions
81  * and is capable of sending and receiving data. Acts as an interface to
82  * Charm++.
83  *
84  * ### Different Types of Algorithms
85  * Charm++ chares can be one of four types, which is specified by the type alias
86  * `chare_type` inside the `ParallelComponent`. The four available types of
87  * Algorithms are:
88  * 1. A Parallel::Algorithms::Singleton where there is only one
89  * in the entire execution of the program.
90  * 2. A Parallel::Algorithms::Array which holds zero or more
91  * elements each of which is a distributed object on some core. An array can
92  * grow and shrink in size dynamically if need be and can also be bound to
93  * another array. That is, the bound array has the same number of elements as
94  * the array it is bound to, and elements with the same ID are on the same core.
95  * 3. A Parallel::Algorithms::Group, which is an array but there is
96  * one element per core and they are not able to be moved around between cores.
97  * These are typically useful for gathering data from array elements on their
98  * core, and then processing or reducing it.
99  * 4. A Parallel::Algorithms::Nodegroup, which is similar to a
100  * group except that there is one element per node. For Charm++ SMP (shared
101  * memory parallelism) builds a node corresponds to the usual definition of a
102  * node on a supercomputer. However, for non-SMP builds nodes and cores are
103  * equivalent. An important difference between groups and nodegroups is that
104  * entry methods (remote calls to functions) are not threadsafe on nodegroups.
105  * It is up to the person writing the Actions that will be executed on the
106  * Nodegroup Algorithm to ensure they are threadsafe.
107  *
108  * ### What is an Algorithm?
109  * An Algorithm is a distributed object, a Charm++ chare, that repeatedly
110  * executes a series of Actions. An Action is a struct that has a `static` apply
111  * function with signature:
112  *
113  * \code
114  * template <typename... DbTags, typename... InboxTags, typename Metavariables,
115  * typename ArrayIndex, typename ActionList>
116  * static auto apply(db::DataBox<tmpl::list<DbTags...>>& box,
117  * tuples::TaggedTuple<InboxTags...>& inboxes,
118  * const GlobalCache<Metavariables>& cache,
119  * const ArrayIndex& array_index,
120  * const TemporalId& temporal_id, const ActionList meta);
121  * \endcode
122  *
123  * Note that any of the arguments can be const or non-const references except
124  * `array_index`, which must be a `const&`.
125  *
126  * ### Explicit instantiations of entry methods
127  * The code in src/Parallel/CharmMain.tpp registers all entry methods, and if
128  * one is not properly registered then a static_assert explains how to have it
129  * be registered. If there is a bug in the implementation and an entry method
130  * isn't being registered or hitting a static_assert then Charm++ will give an
131  * error of the following form:
132  *
133  * \verbatim
134  * registration happened after init Entry point: simple_action(), addr:
135  * 0x555a3d0e2090
136  * ------------- Processor 0 Exiting: Called CmiAbort ------------
137  * Reason: Did you forget to instantiate a templated entry method in a .ci file?
138  * \endverbatim
139  *
140  * If you encounter this issue please file a bug report supplying everything
141  * necessary to reproduce the issue.
142  */
143 template <typename ParallelComponent, typename... PhaseDepActionListsPack>
144 class AlgorithmImpl<ParallelComponent, tmpl::list<PhaseDepActionListsPack...>>
145  : public ParallelComponent::chare_type::template cbase<
146  ParallelComponent,
147  typename get_array_index<typename ParallelComponent::chare_type>::
148  template f<ParallelComponent>> {
149  static_assert(
150  sizeof...(PhaseDepActionListsPack) > 0,
151  "Must have at least one phase dependent action list "
152  "(PhaseActions) in a parallel component. See the first template "
153  "parameter of 'AlgorithmImpl' in the error message to see which "
154  "component doesn't have any phase dependent action lists.");
155 
156  public:
157  /// List of Actions in the order that generates the DataBox types
158  using all_actions_list = tmpl::flatten<
159  tmpl::list<typename PhaseDepActionListsPack::action_list...>>;
160  /// The metavariables class passed to the Algorithm
161  using metavariables = typename ParallelComponent::metavariables;
162  /// List off all the Tags that can be received into the Inbox
164  /// The type of the object used to identify the element of the array, group
165  /// or nodegroup spatially. The default should be an `int`.
166  using array_index = typename get_array_index<
167  typename ParallelComponent::chare_type>::template f<ParallelComponent>;
168 
169  using parallel_component = ParallelComponent;
170  /// The type of the Chare
171  using chare_type = typename parallel_component::chare_type;
172  /// The Charm++ proxy object type
173  using cproxy_type =
174  typename chare_type::template cproxy<parallel_component, array_index>;
175  /// The Charm++ base object type
176  using cbase_type =
177  typename chare_type::template cbase<parallel_component, array_index>;
178  /// The type of the phases
179  using PhaseType =
180  typename tmpl::front<tmpl::list<PhaseDepActionListsPack...>>::phase_type;
181 
182  using phase_dependent_action_lists = tmpl::list<PhaseDepActionListsPack...>;
183 
184  /// \cond
185  // Needed for serialization
186  AlgorithmImpl() noexcept;
187  /// \endcond
188 
189  /// Constructor used by Main to initialize the algorithm
190  template <class... InitializationTags>
191  AlgorithmImpl(
192  const Parallel::CProxy_GlobalCache<metavariables>&
193  global_cache_proxy,
194  tuples::TaggedTuple<InitializationTags...> initialization_items) noexcept;
195 
196  /// Charm++ migration constructor, used after a chare is migrated
197  explicit AlgorithmImpl(CkMigrateMessage* /*msg*/) noexcept;
198 
199  void pup(PUP::er& p) noexcept override { // NOLINT
200 #ifdef SPECTRE_CHARM_PROJECTIONS
201  p | non_action_time_start_;
202 #endif
203  if (performing_action_) {
204  ERROR("cannot serialize while performing action!");
205  }
206  p | performing_action_;
207  p | phase_;
208  p | phase_bookmarks_;
209  p | algorithm_step_;
211  p | node_lock_;
212  }
213  p | terminate_;
214  p | halt_algorithm_until_next_phase_;
215  p | box_;
216  // After unpacking the DataBox, we "touch" the GlobalCache proxy inside.
217  // This forces the DataBox to recompute the GlobalCache* the next time it
218  // is needed, but delays this process until after the pupper is called.
219  // (This delay is important: updating the pointer requires calling
220  // ckLocalBranch() on the Charm++ proxy, and in a restart from checkpoint
221  // this call may not be well-defined until after components are finished
222  // unpacking.)
223  if (p.isUnpacking()) {
224  touch_global_cache_proxy_in_databox(box_);
225  }
226  p | inboxes_;
227  p | array_index_;
228  p | global_cache_proxy_;
229  // Note that `perform_registration_or_deregistration` passes the `box_` by
230  // const reference. If mutable access is required to the box, this function
231  // call needs to be carefully considered with respect to the `p | box_` call
232  // in both packing and unpacking scenarios.
233  //
234  // Note also that we don't perform (de)registrations when pup'ing for a
235  // checkpoint/restart. This enables a simpler first-pass implementation of
236  // checkpointing, though it means the restart must occur on the same
237  // hardware configuration (same number of nodes and same procs per node)
238  // used when writing the checkpoint.
239  if constexpr (Algorithm_detail::has_LoadBalancing_v<
240  typename metavariables::Phase>) {
241  if (phase_ == metavariables::Phase::LoadBalancing) {
242  perform_registration_or_deregistration(p, box_);
243  }
244  }
245  }
246  /// \cond
247  ~AlgorithmImpl() override;
248 
249  AlgorithmImpl(const AlgorithmImpl& /*unused*/) = delete;
250  AlgorithmImpl& operator=(const AlgorithmImpl& /*unused*/) = delete;
251  AlgorithmImpl(AlgorithmImpl&& /*unused*/) = delete;
252  AlgorithmImpl& operator=(AlgorithmImpl&& /*unused*/) = delete;
253  /// \endcond
254 
255  /*!
256  * \brief Calls the `apply` function `Action` after a reduction has been
257  * completed.
258  *
259  * The `apply` function must take `arg` as its last argument.
260  */
261  template <typename Action, typename Arg>
262  void reduction_action(Arg arg) noexcept;
263 
264  /// \brief Explicitly call the action `Action`. If the returned DataBox type
265  /// is not one of the types of the algorithm then a compilation error occurs.
266  template <typename Action, typename... Args>
267  void simple_action(std::tuple<Args...> args) noexcept;
268 
269  template <typename Action>
270  void simple_action() noexcept;
271 
272  /// \brief Call the `Action` sychronously, returning a result without any
273  /// parallelization. The action is called immediately and control flow returns
274  /// to the caller immediately upon completion.
275  ///
276  /// \note `Action` must have a type alias `return_type` specifying its return
277  /// type. This constraint is to simplify the variant visitation logic for the
278  /// \ref DataBoxGroup "DataBox".
279  template <typename Action, typename... Args>
280  typename Action::return_type local_synchronous_action(
281  Args&&... args) noexcept {
283  "Cannot call a (blocking) local synchronous action on a "
284  "chare that is not a NodeGroup");
285  return Algorithm_detail::local_synchronous_action_visitor<
286  Action, ParallelComponent>(box_, make_not_null(&node_lock_),
287  std::forward<Args>(args)...);
288  }
289 
290  /// @{
291  /// Call an Action on a local nodegroup requiring the Action to handle thread
292  /// safety.
293  ///
294  /// The `Parallel::NodeLock` of the nodegroup is passed to the Action instead
295  /// of the `action_list` as a `const gsl::not_null<Parallel::NodeLock*>&`. The
296  /// node lock can be locked with the `Parallel::NodeLock::lock()` function,
297  /// and unlocked with `Parallel::unlock()`. `Parallel::NodeLock::try_lock()`
298  /// is also provided in case something useful can be done if the lock couldn't
299  /// be acquired.
300  template <
301  typename Action, typename... Args,
302  Requires<(sizeof...(Args), std::is_same_v<Parallel::Algorithms::Nodegroup,
303  chare_type>)> = nullptr>
304  void threaded_action(std::tuple<Args...> args) noexcept {
305  (void)Parallel::charmxx::RegisterThreadedAction<ParallelComponent, Action,
306  Args...>::registrar;
307  forward_tuple_to_threaded_action<Action>(
308  std::move(args), std::make_index_sequence<sizeof...(Args)>{});
309  }
310 
311  template <typename Action>
312  void threaded_action() noexcept {
313  // NOLINTNEXTLINE(modernize-redundant-void-arg)
314  (void)Parallel::charmxx::RegisterThreadedAction<ParallelComponent,
315  Action>::registrar;
316  Algorithm_detail::simple_action_visitor<Action, ParallelComponent>(
317  box_, *(global_cache_proxy_.ckLocalBranch()),
318  static_cast<const array_index&>(array_index_),
319  make_not_null(&node_lock_));
320  }
321  /// @}
322 
323  /// \brief Receive data and store it in the Inbox, and try to continue
324  /// executing the algorithm
325  ///
326  /// When an algorithm has terminated it can be restarted by passing
327  /// `enable_if_disabled = true`. This allows long-term disabling and
328  /// re-enabling of algorithms
329  template <typename ReceiveTag, typename ReceiveDataType>
330  void receive_data(typename ReceiveTag::temporal_id instance,
331  ReceiveDataType&& t,
332  bool enable_if_disabled = false) noexcept;
333 
334  /// @{
335  /// Start evaluating the algorithm until it is stopped by an action.
336  constexpr void perform_algorithm() noexcept;
337 
338  constexpr void perform_algorithm(const bool restart_if_terminated) noexcept {
339  if (restart_if_terminated) {
340  set_terminate(false);
341  }
342  perform_algorithm();
343  }
344  /// @}
345 
346  /// Start execution of the phase-dependent action list in `next_phase`. If
347  /// `next_phase` has already been visited, execution will resume at the point
348  /// where the previous execution of the same phase left off.
349  void start_phase(const PhaseType next_phase) noexcept {
350  // terminate should be true since we exited a phase previously.
351  if (not get_terminate() and not halt_algorithm_until_next_phase_) {
352  ERROR(
353  "An algorithm must always be set to terminate at the beginning of a "
354  "phase. Since this is not the case the previous phase did not end "
355  "correctly. The integer corresponding to the previous phase is: "
356  << static_cast<int>(phase_)
357  << " and the next phase is: " << static_cast<int>(next_phase)
358  << ", The termination flag is: " << get_terminate()
359  << ", and the halt flag is: " << halt_algorithm_until_next_phase_);
360  }
361  // set terminate to true if there are no actions in this PDAL
362  set_terminate(number_of_actions_in_phase(next_phase) == 0);
363 
364  // Ideally, we'd set the bookmarks as we are leaving a phase, but there is
365  // no 'clean-up' code that we run when departing a phase, so instead we set
366  // the bookmark for the previous phase (still stored in `phase_` at this
367  // point), before we update the member variable `phase_`.
368  // Then, after updating `phase_`, we check if we've ever stored a bookmark
369  // for the new phase previously. If so, we start from where we left off,
370  // otherwise, start from the beginning of the action list.
371  phase_bookmarks_[phase_] = algorithm_step_;
372  phase_ = next_phase;
373  if(phase_bookmarks_.count(phase_) != 0) {
374  algorithm_step_ = phase_bookmarks_.at(phase_);
375  } else {
376  algorithm_step_ = 0;
377  }
378  halt_algorithm_until_next_phase_ = false;
379  perform_algorithm();
380  }
381 
382  /// Tell the Algorithm it should no longer execute the algorithm. This does
383  /// not mean that the execution of the program is terminated, but only that
384  /// the algorithm has terminated. An algorithm can be restarted by passing
385  /// `true` as the second argument to the `receive_data` method or by calling
386  /// perform_algorithm(true).
387  constexpr void set_terminate(const bool t) noexcept { terminate_ = t; }
388 
389  /// Check if an algorithm should continue being evaluated
390  constexpr bool get_terminate() const noexcept { return terminate_; }
391 
392  /// @{
393  /// Wrappers for charm++ informational functions.
394 
395  /// Number of processing elements
396  inline int number_of_procs() const noexcept {
397  return sys::number_of_procs();
398  }
399 
400  /// %Index of my processing element.
401  inline int my_proc() const noexcept { return sys::my_proc(); }
402 
403  /// Number of nodes.
404  inline int number_of_nodes() const noexcept {
405  return sys::number_of_nodes();
406  }
407 
408  /// %Index of my node.
409  inline int my_node() const noexcept { return sys::my_node(); }
410 
411  /// Number of processing elements on the given node.
412  inline int procs_on_node(const int node_index) const noexcept {
413  return sys::procs_on_node(node_index);
414  }
415 
416  /// The local index of my processing element on my node.
417  /// This is in the interval 0, ..., procs_on_node(my_node()) - 1.
418  inline int my_local_rank() const noexcept {
419  return sys::my_local_rank();
420  }
421 
422  /// %Index of first processing element on the given node.
423  inline int first_proc_on_node(const int node_index) const noexcept {
424  return sys::first_proc_on_node(node_index);
425  }
426 
427  /// %Index of the node for the given processing element.
428  inline int node_of(const int proc_index) const noexcept {
429  return sys::node_of(proc_index);
430  }
431 
432  /// The local index for the given processing element on its node.
433  inline int local_rank_of(const int proc_index) const noexcept {
434  return sys::local_rank_of(proc_index);
435  }
436  /// @}
437 
438  private:
439  template <typename ThisVariant, typename... Variants>
440  void touch_global_cache_proxy_in_databox_impl(
441  boost::variant<Variants...>& box, const gsl::not_null<int*> iter,
442  const gsl::not_null<bool*> already_visited) noexcept {
443  if constexpr (db::tag_is_retrievable_v<
445  if (box.which() == *iter and not *already_visited) {
446  db::mutate<Tags::GlobalCacheProxy<metavariables>>(
447  make_not_null(&(boost::get<ThisVariant>(box))),
449  proxy) noexcept { (void)proxy; });
450  *already_visited = true;
451  }
452  } else {
453  // silence warnings
454  (void)already_visited;
455  }
456  ++(*iter);
457  }
458 
459  template <typename... Variants>
460  void touch_global_cache_proxy_in_databox(
461  boost::variant<Variants...>& box) noexcept {
462  int iter = 0;
463  bool already_visited = false;
465  touch_global_cache_proxy_in_databox_impl<Variants>(box, &iter,
466  &already_visited));
467  }
468 
469  template <typename ThisVariant, typename... Variants, typename... Args>
470  void perform_registration_or_deregistration_impl(
471  PUP::er& p, const boost::variant<Variants...>& box,
472  const gsl::not_null<int*> iter,
473  const gsl::not_null<bool*> already_visited) noexcept {
474  // void cast to avoid compiler warnings about the unused variable in the
475  // false branch of the constexpr
476  (void)already_visited;
477  if (box.which() == *iter and not *already_visited) {
478  // The deregistration and registration below does not actually insert
479  // anything into the PUP::er stream, so nothing is done on a sizing pup.
480  if constexpr (Algorithm_detail::has_registration_list_v<
481  metavariables, ParallelComponent>) {
482  using registration_list =
483  typename metavariables::template registration_list<
484  ParallelComponent>::type;
485  if (p.isPacking()) {
486  tmpl::for_each<registration_list>([this, &box](
487  auto registration_v) noexcept {
488  using registration = typename decltype(registration_v)::type;
489  registration::template perform_deregistration<ParallelComponent>(
490  boost::get<ThisVariant>(box),
491  *(global_cache_proxy_.ckLocalBranch()), array_index_);
492  });
493  }
494  if (p.isUnpacking()) {
495  tmpl::for_each<registration_list>(
496  [this, &box](auto registration_v) noexcept {
497  using registration = typename decltype(registration_v)::type;
498  registration::template perform_registration<ParallelComponent>(
499  boost::get<ThisVariant>(box),
500  *(global_cache_proxy_.ckLocalBranch()), array_index_);
501  });
502  }
503  *already_visited = true;
504  }
505  }
506  ++(*iter);
507  }
508 
509  template <typename... Variants, typename... Args>
510  void perform_registration_or_deregistration(
511  PUP::er& p, const boost::variant<Variants...>& box) noexcept {
512  int iter = 0;
513  bool already_visited = false;
515  perform_registration_or_deregistration_impl<Variants>(
516  p, box, &iter, &already_visited));
517  }
518 
519  static constexpr bool is_singleton =
520  std::is_same_v<chare_type, Parallel::Algorithms::Singleton>;
521 
522  template <class Dummy = int,
523  Requires<(sizeof(Dummy), is_singleton)> = nullptr>
524  constexpr void set_array_index() noexcept {}
525  template <class Dummy = int,
526  Requires<(sizeof(Dummy), not is_singleton)> = nullptr>
527  void set_array_index() noexcept {
528  // down cast to the algorithm_type, so that the `thisIndex` method can be
529  // called, which is defined in the CBase class
530  array_index_ = static_cast<typename chare_type::template algorithm_type<
531  ParallelComponent, array_index>&>(*this)
532  .thisIndex;
533  }
534 
535  template <typename PhaseDepActions, size_t... Is>
536  constexpr bool iterate_over_actions(
537  std::index_sequence<Is...> /*meta*/) noexcept;
538 
539  template <typename Action, typename... Args, size_t... Is>
540  void forward_tuple_to_action(std::tuple<Args...>&& args,
541  std::index_sequence<Is...> /*meta*/) noexcept {
542  Algorithm_detail::simple_action_visitor<Action, ParallelComponent>(
543  box_, *(global_cache_proxy_.ckLocalBranch()),
544  static_cast<const array_index&>(array_index_),
545  std::forward<Args>(std::get<Is>(args))...);
546  }
547 
548  template <typename Action, typename... Args, size_t... Is>
549  void forward_tuple_to_threaded_action(
550  std::tuple<Args...>&& args,
551  std::index_sequence<Is...> /*meta*/) noexcept {
552  const gsl::not_null<Parallel::NodeLock*> node_lock{&node_lock_};
553  Algorithm_detail::simple_action_visitor<Action, ParallelComponent>(
554  box_, *(global_cache_proxy_.ckLocalBranch()),
555  static_cast<const array_index&>(array_index_), node_lock,
556  std::forward<Args>(std::get<Is>(args))...);
557  }
558 
559  size_t number_of_actions_in_phase(const PhaseType phase) const noexcept {
560  size_t number_of_actions = 0;
561  const auto helper = [&number_of_actions, phase](auto pdal_v) {
562  if (pdal_v.phase == phase) {
563  number_of_actions = pdal_v.number_of_actions;
564  }
565  };
566  EXPAND_PACK_LEFT_TO_RIGHT(helper(PhaseDepActionListsPack{}));
567  return number_of_actions;
568  }
569 
570  // Invoke the static `apply` method of `ThisAction`. The if constexprs are for
571  // handling the cases where the `apply` method returns a tuple of one, two,
572  // or three elements, in order:
573  // 1. A DataBox
574  // 2. Either:
575  // 2a. A bool determining whether or not to terminate (and potentially move
576  // to the next phase), or
577  // 2b. An `AlgorithmExecution` object describing whether to continue,
578  // pause, or halt.
579  // 3. An unsigned integer corresponding to which action in the current phase's
580  // algorithm to execute next.
581  //
582  // Returns whether the action ran successfully, i.e., did not return
583  // AlgorithmExecution::Retry.
584  template <typename ThisAction, typename ActionList, typename DbTags>
585  bool invoke_iterable_action(db::DataBox<DbTags>& my_box) noexcept {
586  static_assert(not Algorithm_detail::is_is_ready_callable_t<
587  ThisAction,
588  db::DataBox<DbTags>&,
589  tuples::tagged_tuple_from_typelist<inbox_tags_list>&,
591  array_index>{},
592  "Actions no longer support is_ready methods. Instead, "
593  "return AlgorithmExecution::Retry from apply().");
594 
595  auto action_return = ThisAction::apply(
596  my_box, inboxes_, *(global_cache_proxy_.ckLocalBranch()),
597  std::as_const(array_index_), ActionList{},
599 
600  static_assert(
601  Algorithm_detail::check_iterable_action_return_type<
602  ParallelComponent, ThisAction,
603  std::decay_t<decltype(action_return)>>::value,
604  "An iterable action has an invalid return type.\n"
605  "See the template parameters of "
606  "Algorithm_detail::check_iterable_action_return_type for details: the "
607  "first is the parallel component in question, the second is the "
608  "iterable action, and the third is the return type at fault.\n"
609  "The return type must be a tuple of length one, two, or three "
610  "with:\n"
611  " first type is an updated DataBox;\n"
612  " second type is either a bool (indicating termination) or a "
613  "`Parallel::AlgorithmExecution` object;\n"
614  " third type is a size_t indicating the next action in the current"
615  " phase.");
616 
617  constexpr size_t tuple_size =
618  std::tuple_size<decltype(action_return)>::value;
619  if constexpr (tuple_size >= 1_st) {
620  box_ = std::move(get<0>(action_return));
621  }
622  if constexpr (tuple_size >= 2_st) {
623  if constexpr (std::is_same_v<decltype(get<1>(action_return)), bool&>) {
624  terminate_ = get<1>(action_return);
625  } else {
626  switch(get<1>(action_return)) {
628  halt_algorithm_until_next_phase_ = true;
629  terminate_ = true;
630  break;
632  terminate_ = true;
633  break;
635  if constexpr (tuple_size >= 3_st) {
636  ASSERT(
637  get<2>(action_return) == std::numeric_limits<size_t>::max(),
638  "Switching actions on a Retry doesn't make sense. If you "
639  "need to return a three-element tuple, pass "
640  "std::numeric_limits<size_t>::max() as the last element.");
641  }
642  return false;
643  default:
644  break;
645  }
646  }
647  }
648  if constexpr (tuple_size >= 3_st) {
649  algorithm_step_ = get<2>(action_return);
650  }
651  return true;
652  }
653 
654  // Member variables
655 
656 #ifdef SPECTRE_CHARM_PROJECTIONS
657  double non_action_time_start_;
658 #endif
659 
660  Parallel::CProxy_GlobalCache<metavariables> global_cache_proxy_;
661  bool performing_action_ = false;
662  PhaseType phase_{};
663  std::unordered_map<PhaseType, size_t> phase_bookmarks_{};
664  std::size_t algorithm_step_ = 0;
665  tmpl::conditional_t<Parallel::is_node_group_proxy<cproxy_type>::value,
667  node_lock_;
668 
669  bool terminate_{true};
670  bool halt_algorithm_until_next_phase_{false};
671 
672  using all_cache_tags = get_const_global_cache_tags<metavariables>;
673  using initial_databox = db::compute_databox_type<tmpl::flatten<tmpl::list<
674  Tags::MetavariablesImpl<metavariables>,
675  Tags::GlobalCacheProxy<metavariables>,
676  typename ParallelComponent::initialization_tags,
677  Tags::GlobalCacheImplCompute<metavariables>,
679  // The types held by the boost::variant, box_
680  using databox_phase_types = typename Algorithm_detail::build_databox_types<
681  tmpl::list<>, phase_dependent_action_lists, initial_databox,
682  inbox_tags_list, metavariables, array_index, ParallelComponent>::type;
683 
684  template <typename T>
685  struct get_databox_types {
686  using type = typename T::databox_types;
687  };
688 
689  using databox_types = tmpl::flatten<
690  tmpl::transform<databox_phase_types, get_databox_types<tmpl::_1>>>;
691  // Create a boost::variant that can hold any of the DataBox's
692  using variant_boxes = tmpl::remove_duplicates<
693  tmpl::push_front<databox_types, db::DataBox<tmpl::list<>>>>;
695  tuples::tagged_tuple_from_typelist<inbox_tags_list> inboxes_{};
696  array_index array_index_;
697 };
698 
699 ////////////////////////////////////////////////////////////////
700 // Definitions
701 ////////////////////////////////////////////////////////////////
702 
703 /// \cond
704 template <typename ParallelComponent, typename... PhaseDepActionListsPack>
705 AlgorithmImpl<ParallelComponent, tmpl::list<PhaseDepActionListsPack...>>::
706  AlgorithmImpl() noexcept {
707  set_array_index();
708 }
709 
710 template <typename ParallelComponent, typename... PhaseDepActionListsPack>
711 template <class... InitializationTags>
712 AlgorithmImpl<ParallelComponent, tmpl::list<PhaseDepActionListsPack...>>::
713  AlgorithmImpl(const Parallel::CProxy_GlobalCache<metavariables>&
714  global_cache_proxy,
716  initialization_items) noexcept
717  : AlgorithmImpl() {
718  (void)initialization_items; // avoid potential compiler warnings if unused
719  // When we are using the LoadBalancing phase, we want the Main component to
720  // handle the synchronization, so the components do not participate in the
721  // charm++ `AtSync` barrier.
722  // The array parallel components are migratable so they get balanced
723  // appropriately when load balancing is triggered by the LoadBalancing phase
724  // in Main
725  if constexpr (std::is_same_v<typename ParallelComponent::chare_type,
727  Algorithm_detail::has_LoadBalancing_v<
728  typename metavariables::Phase>) {
729  this->usesAtSync = false;
730  this->setMigratable(true);
731  }
732  global_cache_proxy_ = global_cache_proxy;
733  box_ = db::create<
734  db::AddSimpleTags<tmpl::flatten<
735  tmpl::list<Tags::MetavariablesImpl<metavariables>,
736  Tags::GlobalCacheProxy<metavariables>,
737  typename ParallelComponent::initialization_tags>>>,
739  Tags::GlobalCacheImplCompute<metavariables>,
741  metavariables{},
742  global_cache_proxy_,
743  std::move(get<InitializationTags>(initialization_items))...);
744 }
745 
746 template <typename ParallelComponent, typename... PhaseDepActionListsPack>
747 AlgorithmImpl<ParallelComponent, tmpl::list<PhaseDepActionListsPack...>>::
748  AlgorithmImpl(CkMigrateMessage* msg) noexcept
749  : cbase_type(msg) {}
750 
751 template <typename ParallelComponent, typename... PhaseDepActionListsPack>
752 AlgorithmImpl<ParallelComponent,
753  tmpl::list<PhaseDepActionListsPack...>>::~AlgorithmImpl() {
754  // We place the registrar in the destructor since every AlgorithmImpl will
755  // have a destructor, but we have different constructors so it's not clear
756  // which will be instantiated.
758  ParallelComponent>::registrar;
759 }
760 
761 template <typename ParallelComponent, typename... PhaseDepActionListsPack>
762 template <typename Action, typename Arg>
763 void AlgorithmImpl<ParallelComponent, tmpl::list<PhaseDepActionListsPack...>>::
764  reduction_action(Arg arg) noexcept {
766  ParallelComponent, Action, std::decay_t<Arg>>::registrar;
767  if constexpr (std::is_same_v<Parallel::NodeLock, decltype(node_lock_)>) {
768  node_lock_.lock();
769  }
770  if (performing_action_) {
771  ERROR(
772  "Already performing an Action and cannot execute additional Actions "
773  "from inside of an Action. This is only possible if the "
774  "reduction_action function is not invoked via a proxy, which makes "
775  "no sense for a reduction.");
776  }
777  performing_action_ = true;
778  arg.finalize();
779  forward_tuple_to_action<Action>(std::move(arg.data()),
780  std::make_index_sequence<Arg::pack_size()>{});
781  performing_action_ = false;
782  if constexpr (std::is_same_v<Parallel::NodeLock, decltype(node_lock_)>) {
783  node_lock_.unlock();
784  }
785  perform_algorithm();
786 }
787 
788 template <typename ParallelComponent, typename... PhaseDepActionListsPack>
789 template <typename Action, typename... Args>
790 void AlgorithmImpl<ParallelComponent, tmpl::list<PhaseDepActionListsPack...>>::
791  simple_action(std::tuple<Args...> args) noexcept {
792  (void)Parallel::charmxx::RegisterSimpleAction<ParallelComponent, Action,
793  Args...>::registrar;
794  if constexpr (std::is_same_v<Parallel::NodeLock, decltype(node_lock_)>) {
795  node_lock_.lock();
796  }
797  if (performing_action_) {
798  ERROR(
799  "Already performing an Action and cannot execute additional Actions "
800  "from inside of an Action. This is only possible if the "
801  "simple_action function is not invoked via a proxy, which "
802  "we do not allow.");
803  }
804  performing_action_ = true;
805  forward_tuple_to_action<Action>(std::move(args),
806  std::make_index_sequence<sizeof...(Args)>{});
807  performing_action_ = false;
808  if constexpr (std::is_same_v<Parallel::NodeLock, decltype(node_lock_)>) {
809  node_lock_.unlock();
810  }
811  perform_algorithm();
812 }
813 
814 template <typename ParallelComponent, typename... PhaseDepActionListsPack>
815 template <typename Action>
816 void AlgorithmImpl<ParallelComponent, tmpl::list<PhaseDepActionListsPack...>>::
817  simple_action() noexcept {
818  (void)Parallel::charmxx::RegisterSimpleAction<ParallelComponent,
819  Action>::registrar;
820  if constexpr (std::is_same_v<Parallel::NodeLock, decltype(node_lock_)>) {
821  node_lock_.lock();
822  }
823  if (performing_action_) {
824  ERROR(
825  "Already performing an Action and cannot execute additional Actions "
826  "from inside of an Action. This is only possible if the "
827  "simple_action function is not invoked via a proxy, which "
828  "we do not allow.");
829  }
830  performing_action_ = true;
831  Algorithm_detail::simple_action_visitor<Action, ParallelComponent>(
832  box_, *(global_cache_proxy_.ckLocalBranch()),
833  static_cast<const array_index&>(array_index_));
834  performing_action_ = false;
835  if constexpr (std::is_same_v<Parallel::NodeLock, decltype(node_lock_)>) {
836  node_lock_.unlock();
837  }
838  perform_algorithm();
839 }
840 
841 template <typename ParallelComponent, typename... PhaseDepActionListsPack>
842 template <typename ReceiveTag, typename ReceiveDataType>
843 void AlgorithmImpl<ParallelComponent, tmpl::list<PhaseDepActionListsPack...>>::
844  receive_data(typename ReceiveTag::temporal_id instance, ReceiveDataType&& t,
845  const bool enable_if_disabled) noexcept {
846  (void)Parallel::charmxx::RegisterReceiveData<ParallelComponent,
847  ReceiveTag>::registrar;
848  try {
849  if constexpr (std::is_same_v<Parallel::NodeLock, decltype(node_lock_)>) {
850  node_lock_.lock();
851  }
852  if (enable_if_disabled) {
853  set_terminate(false);
854  }
855  ReceiveTag::insert_into_inbox(
856  make_not_null(&tuples::get<ReceiveTag>(inboxes_)), instance,
857  std::forward<ReceiveDataType>(t));
858  if constexpr (std::is_same_v<Parallel::NodeLock, decltype(node_lock_)>) {
859  node_lock_.unlock();
860  }
861  } catch (std::exception& e) {
862  ERROR("Fatal error: Unexpected exception caught in receive_data: "
863  << e.what());
864  }
865  perform_algorithm();
866 }
867 
868 template <typename ParallelComponent, typename... PhaseDepActionListsPack>
869 constexpr void AlgorithmImpl<
870  ParallelComponent,
871  tmpl::list<PhaseDepActionListsPack...>>::perform_algorithm() noexcept {
872  if (performing_action_ or get_terminate() or
873  halt_algorithm_until_next_phase_) {
874  return;
875  }
876 #ifdef SPECTRE_CHARM_PROJECTIONS
877  non_action_time_start_ = sys::wall_time();
878 #endif
879  if constexpr (std::is_same_v<Parallel::NodeLock, decltype(node_lock_)>) {
880  node_lock_.lock();
881  }
882  const auto invoke_for_phase = [this](auto phase_dep_v) noexcept {
883  using PhaseDep = decltype(phase_dep_v);
884  constexpr PhaseType phase = PhaseDep::phase;
885  using actions_list = typename PhaseDep::action_list;
886  if (phase_ == phase) {
887  while (tmpl::size<actions_list>::value > 0 and not get_terminate() and
888  not halt_algorithm_until_next_phase_ and
889  iterate_over_actions<PhaseDep>(
890  std::make_index_sequence<tmpl::size<actions_list>::value>{})) {
891  }
892  }
893  };
894  // Loop over all phases, once the current phase is found we perform the
895  // algorithm in that phase until we are no longer able to because we are
896  // waiting on data to be sent or because the algorithm has been marked as
897  // terminated.
898  EXPAND_PACK_LEFT_TO_RIGHT(invoke_for_phase(PhaseDepActionListsPack{}));
899  if constexpr (std::is_same_v<Parallel::NodeLock, decltype(node_lock_)>) {
900  node_lock_.unlock();
901  }
902 #ifdef SPECTRE_CHARM_PROJECTIONS
903  traceUserBracketEvent(SPECTRE_CHARM_NON_ACTION_WALLTIME_EVENT_ID,
904  non_action_time_start_, sys::wall_time());
905 #endif
906 }
907 /// \endcond
908 
909 template <typename ParallelComponent, typename... PhaseDepActionListsPack>
910 template <typename PhaseDepActions, size_t... Is>
911 constexpr bool
912 AlgorithmImpl<ParallelComponent, tmpl::list<PhaseDepActionListsPack...>>::
913  iterate_over_actions(const std::index_sequence<Is...> /*meta*/) noexcept {
914  bool take_next_action = true;
915  const auto helper = [this, &take_next_action](auto iteration) noexcept {
916  constexpr size_t iter = decltype(iteration)::value;
917  if (not(take_next_action and not terminate_ and
918  not halt_algorithm_until_next_phase_ and algorithm_step_ == iter)) {
919  return;
920  }
921  using actions_list = typename PhaseDepActions::action_list;
922  using this_action = tmpl::at_c<actions_list, iter>;
923 
924  constexpr size_t phase_index =
925  tmpl::index_of<phase_dependent_action_lists, PhaseDepActions>::value;
926  using databox_phase_type = tmpl::at_c<databox_phase_types, phase_index>;
927  using databox_types_this_phase = typename databox_phase_type::databox_types;
928 
929  using potential_databox_indices = std::conditional_t<
930  iter == 0_st,
931  tmpl::integral_list<size_t, 0_st,
932  tmpl::size<databox_types_this_phase>::value - 1_st>,
933  tmpl::integral_list<size_t, iter>>;
934  bool box_found = false;
935  tmpl::for_each<potential_databox_indices>(
936  [this, &box_found,
937  &take_next_action](auto potential_databox_index_v) noexcept {
938  constexpr size_t potential_databox_index =
939  decltype(potential_databox_index_v)::type::value;
940  using this_databox =
941  tmpl::at_c<databox_types_this_phase, potential_databox_index>;
942  if (not box_found and
943  box_.which() ==
944  static_cast<int>(
945  tmpl::index_of<variant_boxes, this_databox>::value)) {
946  box_found = true;
947  auto& box = boost::get<this_databox>(box_);
948  performing_action_ = true;
949  ++algorithm_step_;
950  if (not invoke_iterable_action<this_action, actions_list>(box)) {
951  take_next_action = false;
952  --algorithm_step_;
953  }
954  }
955  });
956  if (not box_found) {
957  ERROR(
958  "The DataBox type being retrieved at algorithm step: "
959  << algorithm_step_ << " in phase " << phase_index
960  << " corresponding to action " << pretty_type::get_name<this_action>()
961  << " is not the correct type but is of variant index " << box_.which()
962  << ". If you are using Goto and Label actions then you are using "
963  "them incorrectly.");
964  }
965 
966  performing_action_ = false;
967  // Wrap counter if necessary
968  if (algorithm_step_ >= tmpl::size<actions_list>::value) {
969  algorithm_step_ = 0;
970  }
971  };
972  // In case of no Actions avoid compiler warning.
973  (void)helper;
974  // This is a template for loop for Is
976  return take_next_action;
977 }
978 } // namespace Parallel
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::local_rank_of
int local_rank_of(const int proc_index) const noexcept
The local index for the given processing element on its node.
Definition: Algorithm.hpp:433
NoSuchType
Used to mark "no type" or "bad state" for metaprogramming.
Definition: NoSuchType.hpp:10
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::procs_on_node
int procs_on_node(const int node_index) const noexcept
Number of processing elements on the given node.
Definition: Algorithm.hpp:412
std::false_type
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::inbox_tags_list
Parallel::get_inbox_tags< all_actions_list > inbox_tags_list
List off all the Tags that can be received into the Inbox.
Definition: Algorithm.hpp:163
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::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: Algorithm.hpp:418
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
Parallel::GlobalCache
Definition: ElementReceiveInterpPoints.hpp:15
Parallel::is_node_group_proxy
Definition: TypeTraits.hpp:34
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::my_node
int my_node() const noexcept
Index of my node.
Definition: Algorithm.hpp:409
unordered_set
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::cbase_type
typename chare_type::template cbase< parallel_component, array_index > cbase_type
The Charm++ base object type.
Definition: Algorithm.hpp:177
GlobalCache.hpp
std::make_index_sequence
std::set_terminate
T set_terminate(T... args)
db::tag_is_retrievable_v
constexpr bool tag_is_retrievable_v
Definition: DataBox.hpp:61
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::my_proc
int my_proc() const noexcept
Index of my processing element.
Definition: Algorithm.hpp:401
Error.hpp
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::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::cproxy_type
typename chare_type::template cproxy< parallel_component, array_index > cproxy_type
The Charm++ proxy object type.
Definition: Algorithm.hpp:174
Parallel::procs_on_node
int procs_on_node(const int node_index, const DistribObject &distributed_object) noexcept
Number of processing elements on the given node.
Definition: Info.hpp:60
Parallel::number_of_procs
int number_of_procs(const DistribObject &distributed_object) noexcept
Number of processing elements.
Definition: Info.hpp:24
db::AddComputeTags
tmpl::flatten< tmpl::list< Tags... > > AddComputeTags
List of Compute Item Tags to add to the DataBox.
Definition: DataBox.hpp:863
ParallelInfo.hpp
Parallel::local_rank_of
int local_rank_of(const int proc_index, const DistribObject &distributed_object) noexcept
The local index for the given processing element on its node.
Definition: Info.hpp:100
BoostHelpers.hpp
tuple
Info.hpp
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::chare_type
typename parallel_component::chare_type chare_type
The type of the Chare.
Definition: Algorithm.hpp:171
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::all_actions_list
tmpl::flatten< tmpl::list< typename PhaseDepActionListsPack::action_list... > > all_actions_list
List of Actions in the order that generates the DataBox types.
Definition: Algorithm.hpp:159
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::number_of_procs
int number_of_procs() const noexcept
Wrappers for charm++ informational functions.
Definition: Algorithm.hpp:396
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
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::first_proc_on_node
int first_proc_on_node(const int node_index) const noexcept
Index of first processing element on the given node.
Definition: Algorithm.hpp:423
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
Parallel::first_proc_on_node
int first_proc_on_node(const int node_index, const DistribObject &distributed_object) noexcept
Index of first processing element on the given node.
Definition: Info.hpp:80
std::add_pointer_t
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::array_index
typename get_array_index< typename ParallelComponent::chare_type >::template f< ParallelComponent > array_index
The type of the object used to identify the element of the array, group or nodegroup spatially....
Definition: Algorithm.hpp:167
Parallel::my_node
int my_node(const DistribObject &distributed_object) noexcept
Index of my node.
Definition: Info.hpp:51
ActionTesting::get_terminate
bool get_terminate(const MockRuntimeSystem< Metavariables > &runner, const typename Component::array_index &array_index) noexcept
Returns whether or not the Component with index array_index has been terminated.
Definition: MockRuntimeSystemFreeFunctions.hpp:372
DataBox.hpp
Parallel::AlgorithmExecution::Pause
@ Pause
Stop the execution of iterable actions, but allow entry methods (communication) to explicitly request...
Parallel::charmxx::RegisterReceiveData
Derived class for registering receive_data functions.
Definition: CharmRegistration.hpp:428
cstddef
Assert.hpp
Parallel::my_proc
int my_proc(const DistribObject &distributed_object) noexcept
Index of my processing element.
Definition: Info.hpp:33
Parallel::local_synchronous_action
decltype(auto) local_synchronous_action(Proxy &&proxy, Args &&... args) noexcept
Invoke a local synchronous action on proxy
Definition: Invoke.hpp:79
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
tuples::TaggedTuple
An associative container that is indexed by structs.
Definition: TaggedTuple.hpp:271
Parallel::charmxx::RegisterThreadedAction
Derived class for registering threaded actions.
Definition: CharmRegistration.hpp:304
Parallel::Tags::GlobalCacheProxy
Definition: GlobalCache.hpp:666
Parallel::number_of_nodes
int number_of_nodes(const DistribObject &distributed_object) noexcept
Number of nodes.
Definition: Info.hpp:42
Parallel::Algorithms::Nodegroup
A struct that stores the charm++ types relevant for a particular nodegroup component.
Definition: AlgorithmNodegroupDeclarations.hpp:31
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::PhaseType
typename tmpl::front< tmpl::list< PhaseDepActionListsPack... > >::phase_type PhaseType
The type of the phases.
Definition: Algorithm.hpp:180
std::decay_t
ASSERT
#define ASSERT(a, m)
Assert that an expression should be true.
Definition: Assert.hpp:49
PupStlCpp11.hpp
Parallel::receive_data
void receive_data(Proxy &&proxy, typename ReceiveTag::temporal_id temporal_id, ReceiveDataType &&receive_data, const bool enable_if_disabled=false) noexcept
Send the data args... to the algorithm running on proxy, and tag the message with the identifier temp...
Definition: Invoke.hpp:32
sys::wall_time
double wall_time()
The elapsed wall time in seconds.
Definition: ParallelInfo.hpp:94
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::threaded_action
void threaded_action(std::tuple< Args... > args) noexcept
Call an Action on a local nodegroup requiring the Action to handle thread safety.
Definition: Algorithm.hpp:304
db::AddSimpleTags
tmpl::flatten< tmpl::list< Tags... > > AddSimpleTags
List of Tags to add to the DataBox.
Definition: DataBox.hpp:856
Parallel::Algorithms::Array
A struct that stores the charm++ types relevant for a particular array component.
Definition: AlgorithmArrayDeclarations.hpp:31
limits
Gsl.hpp
Parallel::my_local_rank
int my_local_rank(const DistribObject &distributed_object) noexcept
The local index of my processing element on my node. This is in the interval 0, .....
Definition: Info.hpp:71
TypeTraits.hpp
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::node_of
int node_of(const int proc_index) const noexcept
Index of the node for the given processing element.
Definition: Algorithm.hpp:428
Parallel::charmxx::RegisterParallelComponent
Derived class for registering parallel components.
Definition: CharmRegistration.hpp:138
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::start_phase
void start_phase(const PhaseType next_phase) noexcept
Start execution of the phase-dependent action list in next_phase. If next_phase has already been visi...
Definition: Algorithm.hpp:349
ForceInline.hpp
Requires.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
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::get_terminate
constexpr bool get_terminate() const noexcept
Check if an algorithm should continue being evaluated.
Definition: Algorithm.hpp:390
std::size_t
Parallel::simple_action
void simple_action(Proxy &&proxy) noexcept
Invoke a simple action on proxy
Definition: Invoke.hpp:62
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::metavariables
typename ParallelComponent::metavariables metavariables
The metavariables class passed to the Algorithm.
Definition: Algorithm.hpp:161
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
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::number_of_nodes
int number_of_nodes() const noexcept
Number of nodes.
Definition: Algorithm.hpp:404
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::threaded_action
void threaded_action() noexcept
Call an Action on a local nodegroup requiring the Action to handle thread safety.
Definition: Algorithm.hpp:312
Parallel::charmxx::RegisterSimpleAction
Derived class for registering simple actions.
Definition: CharmRegistration.hpp:228
ostream
unordered_map
Parallel::charmxx::RegisterReductionAction
Derived class for registering reduction actions.
Definition: CharmRegistration.hpp:472
std::numeric_limits
Parallel::node_of
int node_of(const int proc_index, const DistribObject &distributed_object) noexcept
Index of the node for the given processing element.
Definition: Info.hpp:90
Parallel
Functionality for parallelization.
Definition: ElementReceiveInterpPoints.hpp:13
TMPL.hpp
Parallel::AlgorithmImpl< ParallelComponent, tmpl::list< PhaseDepActionListsPack... > >::set_terminate
constexpr void set_terminate(const bool t) noexcept
Tell the Algorithm it should no longer execute the algorithm. This does not mean that the execution o...
Definition: Algorithm.hpp:387
gsl::not_null
Require a pointer to not be a nullptr
Definition: ReadSpecPiecewisePolynomial.hpp:13
initializer_list