Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <cstddef>
7 : #include <mutex>
8 : #include <stdexcept>
9 :
10 : #include "DataStructures/DataBox/DataBox.hpp"
11 : #include "Domain/Structure/ElementId.hpp"
12 : #include "Parallel/ArrayCollection/Tags/NumberOfElementsTerminated.hpp"
13 : #include "Parallel/GlobalCache.hpp"
14 : #include "Parallel/Local.hpp"
15 : #include "Parallel/NodeLock.hpp"
16 : #include "Utilities/ErrorHandling/Assert.hpp"
17 : #include "Utilities/ErrorHandling/Error.hpp"
18 : #include "Utilities/Gsl.hpp"
19 :
20 : namespace Parallel::Actions {
21 : /// \brief Set the element with ID `my_element_id` to be terminated. This is
22 : /// always invoked on the local component via
23 : /// `Parallel::local_synchronous_action`
24 : ///
25 : /// In the future we can use this to try and elide Charm++ calls when the
26 : /// receiver is local.
27 1 : struct SetTerminateOnElement {
28 0 : using return_type = void;
29 :
30 : template <typename ParallelComponent, typename DbTagList,
31 : typename Metavariables, size_t Dim>
32 0 : static return_type apply(
33 : db::DataBox<DbTagList>& box, gsl::not_null<Parallel::NodeLock*> node_lock,
34 : gsl::not_null<Parallel::GlobalCache<Metavariables>*> cache,
35 : const ElementId<Dim>& my_element_id, bool terminate_value);
36 : };
37 :
38 : template <typename ParallelComponent, typename DbTagList,
39 : typename Metavariables, size_t Dim>
40 0 : auto SetTerminateOnElement::apply(
41 : db::DataBox<DbTagList>& box,
42 : const gsl::not_null<Parallel::NodeLock*> node_lock,
43 : const gsl::not_null<Parallel::GlobalCache<Metavariables>*> cache,
44 : const ElementId<Dim>& my_element_id, const bool terminate_value)
45 : -> return_type {
46 : std::lock_guard node_guard(*node_lock);
47 : db::mutate<typename ParallelComponent::element_collection_tag,
48 : Parallel::Tags::NumberOfElementsTerminated>(
49 : [&cache, &my_element_id, &node_lock, terminate_value](
50 : const auto element_collection_ptr,
51 : const auto num_terminated_ptr) -> void {
52 : try {
53 : // Note: The nodelock is checked by set_terminate as a sanity
54 : // check and as a way of making set_terminate difficult to use
55 : // without this action.
56 : //
57 : // Note: since this is a local synchronous action running on the
58 : // element that called it, we already have the element locked and so
59 : // setting terminate is threadsafe.
60 : //
61 : // Note: the element's set_terminate updates num_terminated
62 : // correctly so we don't need to handle that here.
63 : element_collection_ptr->at(my_element_id)
64 : .set_terminate(num_terminated_ptr, node_lock, terminate_value);
65 :
66 : // Update the state of the nodegroup. Specifically, if _all_
67 : // elements are set to be terminated, we terminate the nodegroup,
68 : // otherwise we do not.
69 : auto* local_branch = Parallel::local_branch(
70 : Parallel::get_parallel_component<ParallelComponent>(*cache));
71 : ASSERT(local_branch != nullptr,
72 : "The local branch is nullptr, which is inconsistent");
73 : local_branch->set_terminate(*num_terminated_ptr ==
74 : element_collection_ptr->size());
75 : } catch (const std::out_of_range&) {
76 : ERROR("Could not find element with ID " << my_element_id
77 : << " on node");
78 : }
79 : },
80 : make_not_null(&box));
81 : }
82 : } // namespace Parallel::Actions
|