Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <charm++.h>
7 : #include <cstddef>
8 : #include <exception>
9 : #include <pup.h>
10 : #include <string>
11 : #include <type_traits>
12 : #include <utility>
13 :
14 : #include "DataStructures/DataBox/DataBox.hpp"
15 : #include "DataStructures/DataBox/MetavariablesTag.hpp"
16 : #include "DataStructures/DataBox/PrefixHelpers.hpp"
17 : #include "Domain/Structure/ElementId.hpp"
18 : #include "Parallel/AlgorithmExecution.hpp"
19 : #include "Parallel/AlgorithmMetafunctions.hpp"
20 : #include "Parallel/ArrayCollection/DgElementArrayMemberBase.hpp"
21 : #include "Parallel/ArrayCollection/SetTerminateOnElement.hpp"
22 : #include "Parallel/GlobalCache.hpp"
23 : #include "Parallel/Info.hpp"
24 : #include "Parallel/Invoke.hpp"
25 : #include "Parallel/Local.hpp"
26 : #include "Parallel/ParallelComponentHelpers.hpp"
27 : #include "Parallel/Phase.hpp"
28 : #include "Parallel/Tags/ArrayIndex.hpp"
29 : #include "ParallelAlgorithms/Initialization/MutateAssign.hpp"
30 : #include "Utilities/ErrorHandling/Assert.hpp"
31 : #include "Utilities/ErrorHandling/Error.hpp"
32 : #include "Utilities/Gsl.hpp"
33 : #include "Utilities/MakeString.hpp"
34 : #include "Utilities/PrettyType.hpp"
35 : #include "Utilities/Serialization/CharmPupable.hpp"
36 : #include "Utilities/System/Abort.hpp"
37 : #include "Utilities/TMPL.hpp"
38 : #include "Utilities/TaggedTuple.hpp"
39 :
40 : /// \cond
41 : namespace Parallel {
42 : template <size_t Dim, class Metavariables, class PhaseDepActionList>
43 : struct DgElementCollection;
44 : } // namespace Parallel
45 : /// \endcond
46 :
47 : namespace Parallel {
48 : /*!
49 : * \brief An element or multiple elements stored contiguously on a group or
50 : * nodegroup.
51 : *
52 : * Consider first the simpler case where each `DgElementArrayMember` is single
53 : * DG or FD element. Each has a DataBox, and inbox. The various bookkeeping
54 : * constructs are stored in the `DgElementArrayMemberBase`. The
55 : * `DgElementArrayMember` is effectively the distributed object that has
56 : * remote entry methods invoked on it. However, a `DgElementArrayMember` is
57 : * not tied to a particalur core since it lives on a nodegroup (the
58 : * `DgElementCollection`). It is also possible to use a group instead of a
59 : * nodegroup, but that is mostly of interest when using GPUs.
60 : */
61 : template <size_t Dim, typename Metavariables, typename PhaseDepActionList,
62 : typename SimpleTagsFromOptions>
63 1 : class DgElementArrayMember;
64 :
65 : template <size_t Dim, typename Metavariables,
66 : typename... PhaseDepActionListsPack, typename SimpleTagsFromOptions>
67 : // NOLINTNEXTLINE(cppcoreguidelines-virtual-class-destructor)
68 0 : class DgElementArrayMember<Dim, Metavariables,
69 : tmpl::list<PhaseDepActionListsPack...>,
70 : SimpleTagsFromOptions>
71 : : public DgElementArrayMemberBase<Dim> {
72 : public:
73 0 : using ParallelComponent =
74 : DgElementCollection<Dim, Metavariables,
75 : tmpl::list<PhaseDepActionListsPack...>>;
76 :
77 : /// List of Actions in the order that generates the DataBox types
78 1 : using all_actions_list = tmpl::flatten<
79 : tmpl::list<typename PhaseDepActionListsPack::action_list...>>;
80 : /// The metavariables class passed to the Algorithm
81 1 : using metavariables = Metavariables;
82 : /// List of all the Tags that can be received into the Inbox
83 1 : using inbox_tags_list = Parallel::get_inbox_tags<all_actions_list>;
84 0 : using phase_dependent_action_lists = tmpl::list<PhaseDepActionListsPack...>;
85 0 : using all_cache_tags = get_const_global_cache_tags<metavariables>;
86 :
87 0 : using databox_type = db::compute_databox_type<tmpl::flatten<tmpl::list<
88 : Tags::MetavariablesImpl<metavariables>, Tags::ArrayIndex<ElementId<Dim>>,
89 : Tags::GlobalCacheProxy<metavariables>, SimpleTagsFromOptions,
90 : Tags::GlobalCacheCompute<metavariables>,
91 : Tags::ResourceInfoReference<metavariables>,
92 : db::wrap_tags_in<Tags::FromGlobalCache, all_cache_tags, metavariables>,
93 : Algorithm_detail::get_pdal_simple_tags<phase_dependent_action_lists>,
94 : Algorithm_detail::get_pdal_compute_tags<phase_dependent_action_lists>>>>;
95 :
96 0 : using inbox_type = tuples::tagged_tuple_from_typelist<inbox_tags_list>;
97 :
98 0 : DgElementArrayMember() = default;
99 :
100 : template <class... InitializationTags>
101 0 : DgElementArrayMember(
102 : const Parallel::CProxy_GlobalCache<Metavariables>& global_cache_proxy,
103 : tuples::TaggedTuple<InitializationTags...> initialization_items,
104 : ElementId<Dim> element_id);
105 :
106 : /// \cond
107 : ~DgElementArrayMember() override = default;
108 :
109 : DgElementArrayMember(const DgElementArrayMember& /*unused*/) = default;
110 : DgElementArrayMember& operator=(const DgElementArrayMember& /*unused*/) =
111 : default;
112 : DgElementArrayMember(DgElementArrayMember&& /*unused*/) = default;
113 : DgElementArrayMember& operator=(DgElementArrayMember&& /*unused*/) = default;
114 :
115 : WRAPPED_PUPable_decl_base_template( // NOLINT
116 : SINGLE_ARG(DgElementArrayMemberBase<Dim>), DgElementArrayMember);
117 :
118 : explicit DgElementArrayMember(CkMigrateMessage* msg);
119 : /// \endcond
120 :
121 : /// Start execution of the phase-dependent action list in `next_phase`. If
122 : /// `next_phase` has already been visited, execution will resume at the point
123 : /// where the previous execution of the same phase left off.
124 : ///
125 : /// If \p force is true, then regardless of how this component terminated
126 : /// (error or deadlock), it will resume.
127 : ///
128 : /// \warning Don't set \p force to true unless you are absolutely sure you
129 : /// want to. This can have very unintended consequences if used incorrectly.
130 1 : void start_phase(Parallel::Phase next_phase, bool force = false) override;
131 :
132 0 : const auto& databox() const { return box_; }
133 :
134 : /// Start evaluating the algorithm until it is stopped by an action.
135 1 : void perform_algorithm() override;
136 :
137 : template <typename ThisAction, typename PhaseIndex, typename DataBoxIndex>
138 0 : bool invoke_iterable_action();
139 :
140 : /*!
141 : * \brief Invokes a simple action on the element.
142 : *
143 : * \note This does not lock the element. It is up to the calling action to
144 : * lock the element if needed.
145 : */
146 : template <typename Action, typename... Args>
147 1 : void simple_action(Args&&... args) {
148 : try {
149 : if (this->performing_action_) {
150 : ERROR(
151 : "Already performing an Action and cannot execute additional "
152 : "Actions from inside of an Action. This is only possible if the "
153 : "simple_action function is not invoked via a proxy, which "
154 : "we do not allow.");
155 : }
156 : this->performing_action_ = true;
157 : Action::template apply<ParallelComponent>(
158 : box_, *Parallel::local_branch(global_cache_proxy_), this->element_id_,
159 : std::forward<Args>(args)...);
160 : this->performing_action_ = false;
161 : perform_algorithm();
162 : } catch (const std::exception& exception) {
163 : initiate_shutdown(exception);
164 : }
165 : }
166 :
167 : /// Print the expanded type aliases
168 1 : std::string print_types() const override;
169 :
170 : /// Print the current contents of the inboxes
171 1 : std::string print_inbox() const override;
172 :
173 : /// Print the current contents of the DataBox
174 1 : std::string print_databox() const override;
175 :
176 : /// @{
177 : /// Get read access to all the inboxes
178 1 : auto& inboxes() { return inboxes_; }
179 1 : const auto& inboxes() const { return inboxes_; }
180 1 : const auto& get_inboxes() const { return inboxes(); }
181 : /// @}
182 :
183 0 : void pup(PUP::er& p) override;
184 :
185 : private:
186 0 : size_t number_of_actions_in_phase(Parallel::Phase phase) const;
187 :
188 : // After catching an exception, shutdown the simulation
189 0 : void initiate_shutdown(const std::exception& exception);
190 :
191 : template <typename PhaseDepActions, size_t... Is>
192 0 : bool iterate_over_actions(std::index_sequence<Is...> /*meta*/);
193 : static_assert(std::is_move_constructible_v<databox_type>);
194 : static_assert(std::is_move_constructible_v<inbox_type>);
195 :
196 0 : Parallel::CProxy_GlobalCache<Metavariables> global_cache_proxy_{};
197 0 : databox_type box_{};
198 0 : inbox_type inboxes_{};
199 : };
200 :
201 : /// \cond
202 : template <size_t Dim, typename Metavariables,
203 : typename... PhaseDepActionListsPack, typename SimpleTagsFromOptions>
204 : DgElementArrayMember<
205 : Dim, Metavariables, tmpl::list<PhaseDepActionListsPack...>,
206 : SimpleTagsFromOptions>::DgElementArrayMember(CkMigrateMessage* msg)
207 : : DgElementArrayMemberBase<Dim>(msg) {}
208 :
209 : template <size_t Dim, typename Metavariables,
210 : typename... PhaseDepActionListsPack, typename SimpleTagsFromOptions>
211 : template <class... InitializationTags>
212 : DgElementArrayMember<Dim, Metavariables, tmpl::list<PhaseDepActionListsPack...>,
213 : SimpleTagsFromOptions>::
214 : DgElementArrayMember(
215 : const Parallel::CProxy_GlobalCache<Metavariables>& global_cache_proxy,
216 : tuples::TaggedTuple<InitializationTags...> initialization_items,
217 : ElementId<Dim> element_id)
218 : : Parallel::DgElementArrayMemberBase<Dim>(
219 : std::move(element_id),
220 : Parallel::my_node<size_t>(
221 : *Parallel::local_branch(global_cache_proxy))),
222 : global_cache_proxy_(global_cache_proxy) {
223 : (void)initialization_items; // avoid potential compiler warnings if unused
224 : ::Initialization::mutate_assign<
225 : tmpl::list<Tags::ArrayIndex<ElementId<Dim>>,
226 : Tags::GlobalCacheProxy<Metavariables>, InitializationTags...>>(
227 : make_not_null(&box_), this->element_id_, global_cache_proxy_,
228 : std::move(get<InitializationTags>(initialization_items))...);
229 : }
230 :
231 : template <size_t Dim, typename Metavariables,
232 : typename... PhaseDepActionListsPack, typename SimpleTagsFromOptions>
233 : void DgElementArrayMember<
234 : Dim, Metavariables, tmpl::list<PhaseDepActionListsPack...>,
235 : SimpleTagsFromOptions>::start_phase(const Parallel::Phase next_phase,
236 : const bool force) {
237 : try {
238 : auto& cache = *Parallel::local_branch(global_cache_proxy_);
239 : // terminate should be true since we exited a phase previously.
240 : if (force) {
241 : Parallel::local_synchronous_action<
242 : Parallel::Actions::SetTerminateOnElement>(
243 : Parallel::get_parallel_component<ParallelComponent>(cache),
244 : make_not_null(&cache), this->element_id_, true);
245 : }
246 : if (not this->get_terminate() and
247 : not this->halt_algorithm_until_next_phase_) {
248 : ERROR(
249 : "An algorithm must always be set to terminate at the beginning of a "
250 : "phase. Since this is not the case the previous phase did not end "
251 : "correctly. The previous phase is: "
252 : << this->phase_ << " and the next phase is: " << next_phase
253 : << ", The termination flag is: " << this->get_terminate()
254 : << ", and the halt flag is: "
255 : << this->halt_algorithm_until_next_phase_ << ' '
256 : << this->element_id_);
257 : }
258 : // set terminate to true if there are no actions in this PDAL
259 : Parallel::local_synchronous_action<
260 : Parallel::Actions::SetTerminateOnElement>(
261 : Parallel::get_parallel_component<ParallelComponent>(cache),
262 : make_not_null(&cache), this->element_id_,
263 : number_of_actions_in_phase(next_phase) == 0);
264 :
265 : // Ideally, we'd set the bookmarks as we are leaving a phase, but there is
266 : // no 'clean-up' code that we run when departing a phase, so instead we set
267 : // the bookmark for the previous phase (still stored in `phase_` at this
268 : // point), before we update the member variable `phase_`.
269 : // Then, after updating `phase_`, we check if we've ever stored a bookmark
270 : // for the new phase previously. If so, we start from where we left off,
271 : // otherwise, start from the beginning of the action list.
272 : this->phase_bookmarks_[this->phase_] = this->algorithm_step_;
273 : this->phase_ = next_phase;
274 : if (this->phase_bookmarks_.count(this->phase_) != 0) {
275 : this->algorithm_step_ = this->phase_bookmarks_.at(this->phase_);
276 : } else {
277 : this->algorithm_step_ = 0;
278 : }
279 : this->halt_algorithm_until_next_phase_ = false;
280 : perform_algorithm();
281 : } catch (const std::exception& exception) {
282 : initiate_shutdown(exception);
283 : }
284 : }
285 :
286 : template <size_t Dim, typename Metavariables,
287 : typename... PhaseDepActionListsPack, typename SimpleTagsFromOptions>
288 : void DgElementArrayMember<Dim, Metavariables,
289 : tmpl::list<PhaseDepActionListsPack...>,
290 : SimpleTagsFromOptions>::perform_algorithm() {
291 : try {
292 : if (this->performing_action_ or this->get_terminate() or
293 : this->halt_algorithm_until_next_phase_) {
294 : return;
295 : }
296 : const auto invoke_for_phase = [this](auto phase_dep_v) {
297 : using PhaseDep = decltype(phase_dep_v);
298 : constexpr Parallel::Phase phase = PhaseDep::phase;
299 : using actions_list = typename PhaseDep::action_list;
300 : if (this->phase_ == phase) {
301 : while (
302 : tmpl::size<actions_list>::value > 0 and
303 : not this->get_terminate() and
304 : not this->halt_algorithm_until_next_phase_ and
305 : iterate_over_actions<PhaseDep>(
306 : std::make_index_sequence<tmpl::size<actions_list>::value>{})) {
307 : }
308 : tmpl::for_each<actions_list>([this](auto action_v) {
309 : using action = tmpl::type_from<decltype(action_v)>;
310 : if (this->algorithm_step_ ==
311 : tmpl::index_of<actions_list, action>::value) {
312 : this->deadlock_analysis_next_iterable_action_ =
313 : pretty_type::name<action>();
314 : }
315 : });
316 : }
317 : };
318 : // Loop over all phases, once the current phase is found we perform the
319 : // algorithm in that phase until we are no longer able to because we are
320 : // waiting on data to be sent or because the algorithm has been marked as
321 : // terminated.
322 : EXPAND_PACK_LEFT_TO_RIGHT(invoke_for_phase(PhaseDepActionListsPack{}));
323 : } catch (const std::exception& exception) {
324 : initiate_shutdown(exception);
325 : }
326 : }
327 :
328 : template <size_t Dim, typename Metavariables,
329 : typename... PhaseDepActionListsPack, typename SimpleTagsFromOptions>
330 : std::string
331 : DgElementArrayMember<Dim, Metavariables, tmpl::list<PhaseDepActionListsPack...>,
332 : SimpleTagsFromOptions>::print_types() const {
333 : std::ostringstream os;
334 : os << "Algorithm type aliases:\n";
335 : os << "using all_actions_list = " << pretty_type::get_name<all_actions_list>()
336 : << ";\n";
337 :
338 : os << "using metavariables = " << pretty_type::get_name<metavariables>()
339 : << ";\n";
340 : os << "using inbox_tags_list = " << pretty_type::get_name<inbox_tags_list>()
341 : << ";\n";
342 : os << "using array_index = " << pretty_type::get_name<ElementId<Dim>>()
343 : << ";\n";
344 : os << "using parallel_component = "
345 : << pretty_type::get_name<ParallelComponent>() << ";\n";
346 : os << "using phase_dependent_action_lists = "
347 : << pretty_type::get_name<phase_dependent_action_lists>() << ";\n";
348 : os << "using all_cache_tags = " << pretty_type::get_name<all_cache_tags>()
349 : << ";\n";
350 : os << "using databox_type = " << pretty_type::get_name<databox_type>()
351 : << ";\n";
352 : return os.str();
353 : }
354 :
355 : template <size_t Dim, typename Metavariables,
356 : typename... PhaseDepActionListsPack, typename SimpleTagsFromOptions>
357 : std::string
358 : DgElementArrayMember<Dim, Metavariables, tmpl::list<PhaseDepActionListsPack...>,
359 : SimpleTagsFromOptions>::print_inbox() const {
360 : std::ostringstream os;
361 : os << "inboxes_ = " << inboxes_ << ";\n";
362 : return os.str();
363 : }
364 :
365 : template <size_t Dim, typename Metavariables,
366 : typename... PhaseDepActionListsPack, typename SimpleTagsFromOptions>
367 : std::string
368 : DgElementArrayMember<Dim, Metavariables, tmpl::list<PhaseDepActionListsPack...>,
369 : SimpleTagsFromOptions>::print_databox() const {
370 : std::ostringstream os;
371 : os << "box_:\n" << box_;
372 : return os.str();
373 : }
374 :
375 : template <size_t Dim, typename Metavariables,
376 : typename... PhaseDepActionListsPack, typename SimpleTagsFromOptions>
377 : template <typename PhaseDepActions, size_t... Is>
378 : bool DgElementArrayMember<Dim, Metavariables,
379 : tmpl::list<PhaseDepActionListsPack...>,
380 : SimpleTagsFromOptions>::
381 : iterate_over_actions(const std::index_sequence<Is...> /*meta*/) {
382 : bool take_next_action = true;
383 : const auto helper = [this, &take_next_action](auto iteration) {
384 : constexpr size_t iter = decltype(iteration)::value;
385 : if (not(take_next_action and not this->terminate_ and
386 : not this->halt_algorithm_until_next_phase_ and
387 : this->algorithm_step_ == iter)) {
388 : return;
389 : }
390 : using actions_list = typename PhaseDepActions::action_list;
391 : using this_action = tmpl::at_c<actions_list, iter>;
392 :
393 : constexpr size_t phase_index =
394 : tmpl::index_of<phase_dependent_action_lists, PhaseDepActions>::value;
395 : this->performing_action_ = true;
396 : ++(this->algorithm_step_);
397 : // While the overhead from using the local entry method to enable
398 : // profiling is fairly small (<2%), we still avoid it when we aren't
399 : // tracing.
400 : // #ifdef SPECTRE_CHARM_PROJECTIONS
401 : // if constexpr (Parallel::is_array<parallel_component>::value) {
402 : // if (not this->thisProxy[array_index_]
403 : // .template invoke_iterable_action<
404 : // this_action, std::integral_constant<size_t,
405 : // phase_index>, std::integral_constant<size_t,
406 : // iter>>()) {
407 : // take_next_action = false;
408 : // --algorithm_step_;
409 : // }
410 : // } else {
411 : // #endif // SPECTRE_CHARM_PROJECTIONS
412 : if (not invoke_iterable_action<this_action,
413 : std::integral_constant<size_t, phase_index>,
414 : std::integral_constant<size_t, iter>>()) {
415 : take_next_action = false;
416 : --(this->algorithm_step_);
417 : }
418 : // #ifdef SPECTRE_CHARM_PROJECTIONS
419 : // }
420 : // #endif // SPECTRE_CHARM_PROJECTIONS
421 : this->performing_action_ = false;
422 : // Wrap counter if necessary
423 : if (this->algorithm_step_ >= tmpl::size<actions_list>::value) {
424 : this->algorithm_step_ = 0;
425 : }
426 : };
427 : // In case of no Actions avoid compiler warning.
428 : (void)helper;
429 : // This is a template for loop for Is
430 : EXPAND_PACK_LEFT_TO_RIGHT(helper(std::integral_constant<size_t, Is>{}));
431 : return take_next_action;
432 : }
433 :
434 : template <size_t Dim, typename Metavariables,
435 : typename... PhaseDepActionListsPack, typename SimpleTagsFromOptions>
436 : template <typename ThisAction, typename PhaseIndex, typename DataBoxIndex>
437 : bool DgElementArrayMember<Dim, Metavariables,
438 : tmpl::list<PhaseDepActionListsPack...>,
439 : SimpleTagsFromOptions>::invoke_iterable_action() {
440 : using phase_dep_action =
441 : tmpl::at_c<phase_dependent_action_lists, PhaseIndex::value>;
442 : using actions_list = typename phase_dep_action::action_list;
443 :
444 : #ifdef SPECTRE_CHARM_PROJECTIONS
445 : if constexpr (Parallel::is_array<ParallelComponent>::value) {
446 : (void)Parallel::charmxx::RegisterInvokeIterableAction<
447 : ParallelComponent, ThisAction, PhaseIndex, DataBoxIndex>::registrar;
448 : }
449 : #endif // SPECTRE_CHARM_PROJECTIONS
450 :
451 : const auto& [requested_execution_return, next_action_step] =
452 : ThisAction::apply(box_, inboxes_,
453 : *Parallel::local_branch(global_cache_proxy_),
454 : std::as_const(this->element_id_), actions_list{},
455 : std::add_pointer_t<ParallelComponent>{});
456 : const auto& requested_execution = requested_execution_return;
457 :
458 : if (next_action_step.has_value()) {
459 : ASSERT(
460 : AlgorithmExecution::Retry != requested_execution,
461 : "Switching actions on Retry doesn't make sense. Specify std::nullopt "
462 : "as the second argument of the iterable action return type");
463 : this->algorithm_step_ = next_action_step.value();
464 : }
465 :
466 : switch (requested_execution) {
467 : case AlgorithmExecution::Continue:
468 : return true;
469 : case AlgorithmExecution::Retry:
470 : return false;
471 : case AlgorithmExecution::Pause: {
472 : auto& cache = *Parallel::local_branch(global_cache_proxy_);
473 : Parallel::local_synchronous_action<
474 : Parallel::Actions::SetTerminateOnElement>(
475 : Parallel::get_parallel_component<ParallelComponent>(cache),
476 : make_not_null(&cache), this->element_id_, true);
477 : return true;
478 : }
479 : case AlgorithmExecution::Halt: {
480 : // Need to make sure halt also gets propagated to the nodegroup
481 : this->halt_algorithm_until_next_phase_ = true;
482 : auto& cache = *Parallel::local_branch(global_cache_proxy_);
483 : Parallel::local_synchronous_action<
484 : Parallel::Actions::SetTerminateOnElement>(
485 : Parallel::get_parallel_component<ParallelComponent>(cache),
486 : make_not_null(&cache), this->element_id_, true);
487 : return true;
488 : }
489 : default: // LCOV_EXCL_LINE
490 : // LCOV_EXCL_START
491 : ERROR("No case for a Parallel::AlgorithmExecution with integral value "
492 : << static_cast<std::underlying_type_t<AlgorithmExecution>>(
493 : requested_execution)
494 : << "\n");
495 : // LCOV_EXCL_STOP
496 : };
497 : }
498 :
499 : template <size_t Dim, typename Metavariables,
500 : typename... PhaseDepActionListsPack, typename SimpleTagsFromOptions>
501 : size_t DgElementArrayMember<
502 : Dim, Metavariables, tmpl::list<PhaseDepActionListsPack...>,
503 : SimpleTagsFromOptions>::number_of_actions_in_phase(const Parallel::Phase
504 : phase) const {
505 : size_t number_of_actions = 0;
506 : const auto helper = [&number_of_actions, phase](auto pdal_v) {
507 : if (pdal_v.phase == phase) {
508 : number_of_actions = pdal_v.number_of_actions;
509 : }
510 : };
511 : EXPAND_PACK_LEFT_TO_RIGHT(helper(PhaseDepActionListsPack{}));
512 : return number_of_actions;
513 : }
514 :
515 : template <size_t Dim, typename Metavariables,
516 : typename... PhaseDepActionListsPack, typename SimpleTagsFromOptions>
517 : void DgElementArrayMember<
518 : Dim, Metavariables, tmpl::list<PhaseDepActionListsPack...>,
519 : SimpleTagsFromOptions>::initiate_shutdown(const std::exception& exception) {
520 : // In order to make it so that we can later run other actions for cleanup
521 : // (e.g. dumping data) we need to make sure that we enable running actions
522 : // again
523 : this->performing_action_ = false;
524 : // Send message to `Main` that we received an exception and set termination.
525 : auto* global_cache = Parallel::local_branch(global_cache_proxy_);
526 : if (UNLIKELY(global_cache == nullptr)) {
527 : // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
528 : CkError(
529 : "Global cache pointer is null. This is an internal inconsistency "
530 : "error. Please file an issue.");
531 : sys::abort("");
532 : }
533 : auto main_proxy = global_cache->get_main_proxy();
534 : if (UNLIKELY(not main_proxy.has_value())) {
535 : // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
536 : CkError(
537 : "The main proxy has not been set in the global cache when terminating "
538 : "the component. This is an internal inconsistency error. Please file "
539 : "an issue.");
540 : sys::abort("");
541 : }
542 : const std::string message = MakeString{}
543 : << "Message: " << exception.what() << "\nType: "
544 : << pretty_type::get_runtime_type_name(exception);
545 : main_proxy.value().add_exception_message(message);
546 : auto& cache = *Parallel::local_branch(global_cache_proxy_);
547 : Parallel::local_synchronous_action<Parallel::Actions::SetTerminateOnElement>(
548 : Parallel::get_parallel_component<ParallelComponent>(cache),
549 : make_not_null(&cache), this->element_id_, true);
550 : }
551 :
552 : template <size_t Dim, typename Metavariables,
553 : typename... PhaseDepActionListsPack, typename SimpleTagsFromOptions>
554 : void DgElementArrayMember<Dim, Metavariables,
555 : tmpl::list<PhaseDepActionListsPack...>,
556 : SimpleTagsFromOptions>::pup(PUP::er& p) {
557 : DgElementArrayMemberBase<Dim>::pup(p);
558 : p | global_cache_proxy_;
559 : p | box_;
560 : p | inboxes_;
561 : if (p.isUnpacking()) {
562 : // Since we need the global cache to set the node, the derived class
563 : // does it instead of the base class.
564 : this->my_node_ =
565 : Parallel::my_node<size_t>(*Parallel::local_branch(global_cache_proxy_));
566 : }
567 : }
568 :
569 : template <size_t Dim, typename Metavariables,
570 : typename... PhaseDepActionListsPack, typename SimpleTagsFromOptions>
571 : PUP::able::PUP_ID DgElementArrayMember<
572 : Dim, Metavariables, tmpl::list<PhaseDepActionListsPack...>,
573 : SimpleTagsFromOptions>::my_PUP_ID = // NOLINT
574 : 0;
575 : /// \endcond
576 : } // namespace Parallel
|