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