6 #include <boost/variant/variant.hpp>
19 #include "DataStructures/DataBox/PrefixHelpers.hpp"
20 #include "Parallel/AlgorithmMetafunctions.hpp"
21 #include "Parallel/Algorithms/AlgorithmArrayDeclarations.hpp"
22 #include "Parallel/Algorithms/AlgorithmGroupDeclarations.hpp"
23 #include "Parallel/Algorithms/AlgorithmNodegroupDeclarations.hpp"
24 #include "Parallel/Algorithms/AlgorithmSingletonDeclarations.hpp"
25 #include "Parallel/CharmRegistration.hpp"
27 #include "Parallel/NodeLock.hpp"
28 #include "Parallel/ParallelComponentHelpers.hpp"
29 #include "Parallel/PhaseDependentActionList.hpp"
31 #include "Parallel/SimpleActionVisitation.hpp"
38 #include "Utilities/MakeString.hpp"
39 #include "Utilities/NoSuchType.hpp"
40 #include "Utilities/Overloader.hpp"
45 #include "Utilities/TaggedTuple.hpp"
46 #include "Utilities/TypeTraits.hpp"
54 template <
typename ParallelComponent,
typename PhaseDepActionList>
123 template <
typename ParallelComponent,
typename... PhaseDepActionListsPack>
124 class AlgorithmImpl<ParallelComponent, tmpl::list<PhaseDepActionListsPack...>>
125 :
public ParallelComponent::chare_type::template cbase<
127 typename get_array_index<typename ParallelComponent::chare_type>::
128 template f<ParallelComponent>> {
130 sizeof...(PhaseDepActionListsPack) > 0,
131 "Must have at least one phase dependent action list "
132 "(PhaseActions) in a parallel component. See the first template "
133 "parameter of 'AlgorithmImpl' in the error message to see which "
134 "component doesn't have any phase dependent action lists.");
139 tmpl::list<
typename PhaseDepActionListsPack::action_list...>>;
147 typename ParallelComponent::chare_type>::template f<ParallelComponent>;
149 using parallel_component = ParallelComponent;
154 typename chare_type::template cproxy<parallel_component, array_index>;
157 typename chare_type::template cbase<parallel_component, array_index>;
160 typename tmpl::front<tmpl::list<PhaseDepActionListsPack...>>::phase_type;
162 using phase_dependent_action_lists = tmpl::list<PhaseDepActionListsPack...>;
166 AlgorithmImpl() noexcept;
170 template <class... InitializationTags>
174 tuples::TaggedTuple<InitializationTags...> initialization_items) noexcept;
177 explicit AlgorithmImpl(CkMigrateMessage* ) noexcept;
179 void pup(PUP::er& p) noexcept
override {
180 #ifdef SPECTRE_CHARM_PROJECTIONS
181 p | non_action_time_start_;
183 if (performing_action_) {
184 ERROR(
"cannot serialize while performing action!");
186 p | performing_action_;
199 ~AlgorithmImpl()
override;
201 AlgorithmImpl(
const AlgorithmImpl& ) =
delete;
202 AlgorithmImpl& operator=(
const AlgorithmImpl& ) =
delete;
203 AlgorithmImpl(AlgorithmImpl&& ) =
delete;
204 AlgorithmImpl& operator=(AlgorithmImpl&& ) =
delete;
213 template <
typename Action,
typename Arg>
214 void reduction_action(Arg arg) noexcept;
218 template <
typename Action,
typename... Args>
221 template <
typename Action>
235 typename Action, typename... Args,
236 Requires<(sizeof...(Args), std::is_same_v<Parallel::Algorithms::Nodegroup,
237 chare_type>)> =
nullptr>
241 forward_tuple_to_threaded_action<Action>(
245 template <
typename Action>
250 Algorithm_detail::simple_action_visitor<Action, ParallelComponent>(
251 box_, *global_cache_,
252 static_cast<const array_index&
>(array_index_),
263 template <
typename ReceiveTag,
typename ReceiveDataType>
264 void receive_data(
typename ReceiveTag::temporal_id instance,
266 bool enable_if_disabled =
false) noexcept;
273 constexpr
void perform_algorithm() noexcept;
275 constexpr
void perform_algorithm(const
bool restart_if_terminated) noexcept {
276 if (restart_if_terminated) {
277 set_terminate(
false);
283 void start_phase(
const PhaseType next_phase) noexcept {
287 "An algorithm must always be set to terminate at the beginning of a "
288 "phase. Since this is not the case the previous phase did not end "
289 "correctly. The integer corresponding to the previous phase is: "
290 <<
static_cast<int>(phase_)
291 <<
" and the next phase is: " <<
static_cast<int>(next_phase));
311 static constexpr
bool is_singleton =
312 std::is_same_v<chare_type, Parallel::Algorithms::Singleton>;
314 template <
class Dummy = int,
315 Requires<(
sizeof(Dummy), is_singleton)> =
nullptr>
316 constexpr
void set_array_index() noexcept {}
317 template <
class Dummy = int,
318 Requires<(
sizeof(Dummy), not is_singleton)> =
nullptr>
319 void set_array_index() noexcept {
322 array_index_ =
static_cast<typename chare_type::template algorithm_type<
323 ParallelComponent, array_index
>&>(*this)
327 template <
typename PhaseDepActions,
size_t... Is>
328 constexpr
bool iterate_over_actions(
331 template <
typename Action,
typename... Args,
size_t... Is>
334 Algorithm_detail::simple_action_visitor<Action, ParallelComponent>(
335 box_, *global_cache_,
336 static_cast<const array_index&
>(array_index_),
337 std::forward<Args>(std::get<Is>(args))...);
340 template <
typename Action,
typename... Args,
size_t... Is>
341 void forward_tuple_to_threaded_action(
345 Algorithm_detail::simple_action_visitor<Action, ParallelComponent>(
346 box_, *global_cache_,
347 static_cast<const array_index&
>(array_index_), node_lock,
348 std::forward<Args>(std::get<Is>(args))...);
351 size_t number_of_actions_in_phase(
const PhaseType phase)
const noexcept {
352 size_t number_of_actions = 0;
353 const auto helper = [&number_of_actions, phase](
auto pdal_v) {
354 if (pdal_v.phase == phase) {
355 number_of_actions = pdal_v.number_of_actions;
359 return number_of_actions;
364 #ifdef SPECTRE_CHARM_PROJECTIONS
365 double non_action_time_start_;
369 bool performing_action_ =
false;
372 tmpl::conditional_t<Parallel::is_node_group_proxy<cproxy_type>::value,
376 bool terminate_{
true};
378 using all_cache_tags = get_const_global_cache_tags<metavariables>;
380 Tags::GlobalCacheImpl<metavariables>,
381 typename ParallelComponent::initialization_tags,
384 using databox_phase_types =
typename Algorithm_detail::build_databox_types<
385 tmpl::list<>, phase_dependent_action_lists, initial_databox,
386 inbox_tags_list, metavariables, array_index, ParallelComponent>::type;
388 template <
typename T>
389 struct get_databox_types {
390 using type =
typename T::databox_types;
393 using databox_types = tmpl::flatten<
394 tmpl::transform<databox_phase_types, get_databox_types<tmpl::_1>>>;
396 using variant_boxes = tmpl::remove_duplicates<
397 tmpl::push_front<databox_types, db::DataBox<tmpl::list<>>>>;
399 tuples::tagged_tuple_from_typelist<inbox_tags_list> inboxes_{};
400 array_index array_index_;
408 template <
typename ParallelComponent,
typename... PhaseDepActionListsPack>
409 AlgorithmImpl<ParallelComponent, tmpl::list<PhaseDepActionListsPack...>>::
410 AlgorithmImpl() noexcept {
414 template <
typename ParallelComponent,
typename... PhaseDepActionListsPack>
415 template <
class... InitializationTags>
416 AlgorithmImpl<ParallelComponent, tmpl::list<PhaseDepActionListsPack...>>::
417 AlgorithmImpl(
const Parallel::CProxy_GlobalCache<metavariables>&
420 initialization_items) noexcept
422 (void)initialization_items;
423 global_cache_ = global_cache_proxy.ckLocalBranch();
426 tmpl::list<Tags::GlobalCacheImpl<metavariables>,
427 typename ParallelComponent::initialization_tags>>>,
431 std::move(get<InitializationTags>(initialization_items))...);
434 template <
typename ParallelComponent,
typename... PhaseDepActionListsPack>
435 AlgorithmImpl<ParallelComponent, tmpl::list<PhaseDepActionListsPack...>>::
436 AlgorithmImpl(CkMigrateMessage* msg) noexcept
440 "The AlgorithmImpl has been constructed with a nullptr as a "
441 "CkMigrateMessage* -- most likely this indicates that a constructor "
442 "is being used incorrectly, as the CkMigrateMessage* constructor "
443 "should only be used by the charm framework when migrating. "
444 "Constructing with a nullptr CkMigrateMessage* is dangerous and can "
449 template <
typename ParallelComponent,
typename... PhaseDepActionListsPack>
450 AlgorithmImpl<ParallelComponent,
451 tmpl::list<PhaseDepActionListsPack...>>::~AlgorithmImpl() {
456 ParallelComponent>::registrar;
459 template <
typename ParallelComponent,
typename... PhaseDepActionListsPack>
460 template <
typename Action,
typename Arg>
461 void AlgorithmImpl<ParallelComponent, tmpl::list<PhaseDepActionListsPack...>>::
462 reduction_action(Arg arg) noexcept {
468 if (performing_action_) {
470 "Already performing an Action and cannot execute additional Actions "
471 "from inside of an Action. This is only possible if the "
472 "reduction_action function is not invoked via a proxy, which makes "
473 "no sense for a reduction.");
475 performing_action_ =
true;
477 forward_tuple_to_action<Action>(std::move(arg.data()),
479 performing_action_ =
false;
486 template <
typename ParallelComponent,
typename... PhaseDepActionListsPack>
487 template <
typename Action,
typename... Args>
488 void AlgorithmImpl<ParallelComponent, tmpl::list<PhaseDepActionListsPack...>>
::
495 if (performing_action_) {
497 "Already performing an Action and cannot execute additional Actions "
498 "from inside of an Action. This is only possible if the "
499 "simple_action function is not invoked via a proxy, which "
502 performing_action_ =
true;
503 forward_tuple_to_action<Action>(std::move(args),
505 performing_action_ =
false;
512 template <
typename ParallelComponent,
typename... PhaseDepActionListsPack>
513 template <
typename Action>
514 void AlgorithmImpl<ParallelComponent, tmpl::list<PhaseDepActionListsPack...>>
::
521 if (performing_action_) {
523 "Already performing an Action and cannot execute additional Actions "
524 "from inside of an Action. This is only possible if the "
525 "simple_action function is not invoked via a proxy, which "
528 performing_action_ =
true;
529 Algorithm_detail::simple_action_visitor<Action, ParallelComponent>(
530 box_, *global_cache_,
531 static_cast<const array_index&
>(array_index_));
532 performing_action_ =
false;
539 template <
typename ParallelComponent,
typename... PhaseDepActionListsPack>
540 template <
typename ReceiveTag,
typename ReceiveDataType>
541 void AlgorithmImpl<ParallelComponent, tmpl::list<PhaseDepActionListsPack...>>
::
542 receive_data(
typename ReceiveTag::temporal_id instance, ReceiveDataType&& t,
543 const bool enable_if_disabled) noexcept {
545 ReceiveTag>::registrar;
550 if (enable_if_disabled) {
553 ReceiveTag::insert_into_inbox(
555 std::forward<ReceiveDataType>(t));
560 ERROR(
"Fatal error: Unexpected exception caught in receive_data: "
566 template <
typename ParallelComponent,
typename... PhaseDepActionListsPack>
567 constexpr
void AlgorithmImpl<
569 tmpl::list<PhaseDepActionListsPack...>>::perform_algorithm() noexcept {
573 #ifdef SPECTRE_CHARM_PROJECTIONS
579 const auto invoke_for_phase = [
this](
auto phase_dep_v) noexcept {
580 using PhaseDep = decltype(phase_dep_v);
581 constexpr PhaseType phase = PhaseDep::phase;
582 using actions_list =
typename PhaseDep::action_list;
583 if (phase_ == phase) {
584 while (tmpl::size<actions_list>::value > 0 and not
get_terminate() and
585 iterate_over_actions<PhaseDep>(
598 #ifdef SPECTRE_CHARM_PROJECTIONS
599 traceUserBracketEvent(SPECTRE_CHARM_NON_ACTION_WALLTIME_EVENT_ID,
600 non_action_time_start_, sys::wall_time());
605 template <
typename ParallelComponent,
typename... PhaseDepActionListsPack>
606 template <
typename PhaseDepActions,
size_t... Is>
608 AlgorithmImpl<ParallelComponent, tmpl::list<PhaseDepActionListsPack...>>::
610 bool take_next_action =
true;
611 const auto helper = [
this, &take_next_action ](
auto iteration) noexcept {
612 constexpr
size_t iter = decltype(iteration)::value;
613 if (not(take_next_action and not terminate_ and algorithm_step_ == iter)) {
616 using actions_list =
typename PhaseDepActions::action_list;
617 using this_action = tmpl::at_c<actions_list, iter>;
637 this_action::apply(my_box, inboxes_, *global_cache_,
638 std::as_const(array_index_), actions_list{},
643 std::tie(box_, terminate_) =
644 this_action::apply(my_box, inboxes_, *global_cache_,
645 std::as_const(array_index_), actions_list{},
650 std::tie(box_, terminate_, algorithm_step_) =
651 this_action::apply(my_box, inboxes_, *global_cache_,
652 std::as_const(array_index_), actions_list{},
665 const auto& check_local_box) noexcept {
667 check_local_box, std::
as_const(inboxes_), *global_cache_,
671 const auto& ) noexcept {
return true; });
673 constexpr
size_t phase_index =
674 tmpl::index_of<phase_dependent_action_lists, PhaseDepActions>::value;
675 using databox_phase_type = tmpl::at_c<databox_phase_types, phase_index>;
676 using databox_types_this_phase =
typename databox_phase_type::databox_types;
678 const auto display_databox_error = [
this](
const size_t line_number,
680 auto... types) noexcept {
681 ERROR(
"The DataBox type being retrieved at algorithm step: "
682 << algorithm_step_ <<
" in phase " << phase_index
683 <<
" corresponding to action "
684 << pretty_type::get_name<this_action>() <<
" on line "
686 <<
" is not the correct type but is of variant index "
688 <<
". If you are using Goto and Label actions then you are using "
689 "them incorrectly. \nValid DataBox Types: \n "
693 << pretty_type::get_name<typename decltype(types)::type>())
694 <<
"\nVariant type:\n " << pretty_type::get_name<variant_boxes>());
705 [
this, &take_next_action, &check_if_ready, &invoke_this_action,
706 &display_databox_error](
auto current_iter) noexcept
708 decltype(current_iter)>::value> {
712 using first_databox = tmpl::at_c<databox_types_this_phase, 0>;
714 tmpl::at_c<databox_types_this_phase,
715 tmpl::size<databox_types_this_phase>::value - 1>;
716 using local_this_action =
717 tmpl::at_c<actions_list, decltype(current_iter)::value>;
720 tmpl::index_of<variant_boxes, first_databox>::value)) {
721 using this_databox = first_databox;
722 auto& box = boost::get<this_databox>(box_);
723 if (not check_if_ready(
724 Algorithm_detail::is_is_ready_callable_t<
725 local_this_action, this_databox,
726 tuples::tagged_tuple_from_typelist<inbox_tags_list>,
729 local_this_action{}, box)) {
730 take_next_action =
false;
733 performing_action_ =
true;
737 typename std::tuple_size<decltype(local_this_action::apply(
738 box, inboxes_, *global_cache_,
739 std::as_const(array_index_), actions_list{},
741 }
else if (box_.which() ==
743 tmpl::index_of<variant_boxes,
744 last_databox>::value)) {
745 using this_databox = last_databox;
746 auto& box = boost::get<this_databox>(box_);
747 if (not check_if_ready(
748 Algorithm_detail::is_is_ready_callable_t<
749 local_this_action, this_databox,
750 tuples::tagged_tuple_from_typelist<inbox_tags_list>,
753 local_this_action{}, box)) {
754 take_next_action =
false;
757 performing_action_ =
true;
761 typename std::tuple_size<decltype(local_this_action::apply(
762 box, inboxes_, *global_cache_,
763 std::as_const(array_index_), actions_list{},
766 display_databox_error(__LINE__, tmpl::type_<first_databox>{},
767 tmpl::type_<last_databox>{});
773 this, &take_next_action, &check_if_ready, &invoke_this_action, &
774 display_databox_error
775 ](
auto current_iter) noexcept
777 decltype(current_iter)>::value> {
781 using this_databox = tmpl::at_c<databox_types_this_phase,
782 decltype(current_iter)::value>;
783 using local_this_action =
784 tmpl::at_c<actions_list, decltype(current_iter)::value>;
787 tmpl::index_of<variant_boxes, this_databox>::value)) {
788 auto& box = boost::get<this_databox>(box_);
789 if (not check_if_ready(
790 Algorithm_detail::is_is_ready_callable_t<
791 local_this_action, this_databox,
792 tuples::tagged_tuple_from_typelist<inbox_tags_list>,
795 local_this_action{}, box)) {
796 take_next_action =
false;
799 performing_action_ =
true;
803 typename std::tuple_size<decltype(local_this_action::apply(
804 box, inboxes_, *global_cache_,
805 std::as_const(array_index_), actions_list{},
808 display_databox_error(__LINE__, tmpl::type_<this_databox>{});
812 performing_action_ =
false;
814 if (algorithm_step_ >= tmpl::size<actions_list>::value) {
822 return take_next_action;