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