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