Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <algorithm>
7 : #include <array>
8 : #include <cstddef>
9 : #include <unordered_map>
10 :
11 : #include "DataStructures/DataBox/DataBox.hpp"
12 : #include "Domain/Amr/Flag.hpp"
13 : #include "Domain/Amr/Tags/Flags.hpp"
14 : #include "Domain/Amr/Tags/NeighborFlags.hpp"
15 : #include "Domain/Amr/UpdateAmrDecision.hpp"
16 : #include "Domain/Structure/Element.hpp"
17 : #include "Domain/Structure/ElementId.hpp"
18 : #include "Domain/Structure/Neighbors.hpp"
19 : #include "Domain/Tags.hpp"
20 : #include "Parallel/ArrayCollection/IsDgElementCollection.hpp"
21 : #include "Parallel/ArrayCollection/SimpleActionOnElement.hpp"
22 : #include "Parallel/ArrayCollection/Tags/ElementLocations.hpp"
23 : #include "Parallel/GlobalCache.hpp"
24 : #include "Parallel/Invoke.hpp"
25 : #include "ParallelAlgorithms/Actions/GetItemFromDistributedObject.hpp"
26 : #include "ParallelAlgorithms/Amr/Policies/Policies.hpp"
27 : #include "ParallelAlgorithms/Amr/Policies/Tags.hpp"
28 : #include "ParallelAlgorithms/Amr/Projectors/Mesh.hpp"
29 : #include "Utilities/Algorithm.hpp"
30 : #include "Utilities/ErrorHandling/Error.hpp"
31 : #include "Utilities/Gsl.hpp"
32 : #include "Utilities/PrettyType.hpp"
33 : #include "Utilities/TMPL.hpp"
34 :
35 : namespace amr::Actions {
36 : /// \brief Given the AMR decision of a neighboring Element, potentially update
37 : /// the AMR decision of the target Element.
38 : ///
39 : /// DataBox:
40 : /// - Uses:
41 : /// * domain::Tags::Element<volume_dim>
42 : /// - Modifies:
43 : /// * amr::Tags::NeighborInfo
44 : /// * amr::Tags::Info (if AMR decision is updated)
45 : ///
46 : /// Invokes:
47 : /// - amr::Actions::UpdateAmrDecision on all neighboring Element%s (if AMR
48 : /// decision is updated)
49 : ///
50 : /// \details This Element calls amr::update_amr_decision to see if its
51 : /// AMR decision needs to be updated. If it does, the Element will call
52 : /// amr::Actions::UpdateAmrDecision on its neighbors.
53 : ///
54 1 : struct UpdateAmrDecision {
55 : template <typename ParallelComponent, typename DbTagList,
56 : typename Metavariables>
57 0 : static void apply(db::DataBox<DbTagList>& box,
58 : Parallel::GlobalCache<Metavariables>& cache,
59 : const ElementId<Metavariables::volume_dim>& /*element_id*/,
60 : const ElementId<Metavariables::volume_dim>& neighbor_id,
61 : const Info<Metavariables::volume_dim>& neighbor_amr_info) {
62 : constexpr size_t volume_dim = Metavariables::volume_dim;
63 : auto& my_amr_info = db::get_mutable_reference<amr::Tags::Info<volume_dim>>(
64 : make_not_null(&box));
65 : auto& my_neighbors_amr_info =
66 : db::get_mutable_reference<amr::Tags::NeighborInfo<volume_dim>>(
67 : make_not_null(&box));
68 :
69 : // Actions can be executed in any order. Therefore we need to check:
70 : // - If we received info from a neighbor multiple times, but not in the
71 : // order they were sent. Neighbor info should only be sent again if
72 : // the flags have changed to a higher priority (i.e. higher integral value
73 : // of the flag) or the new mesh has a larger number of grid points.
74 : if (1 == my_neighbors_amr_info.count(neighbor_id)) {
75 : const auto& previously_received_info =
76 : my_neighbors_amr_info.at(neighbor_id);
77 : if (previously_received_info.new_mesh.number_of_grid_points() >=
78 : neighbor_amr_info.new_mesh.number_of_grid_points() and
79 : not std::lexicographical_compare(
80 : previously_received_info.flags.begin(),
81 : previously_received_info.flags.end(),
82 : neighbor_amr_info.flags.begin(), neighbor_amr_info.flags.end())) {
83 : return;
84 : }
85 : }
86 :
87 : my_neighbors_amr_info.insert_or_assign(neighbor_id, neighbor_amr_info);
88 :
89 : auto& my_amr_flags = my_amr_info.flags;
90 : // Actions can be executed in any order. Therefore we need to check:
91 : // - If we have evaluated our own AMR decision. If not, return.
92 : if (amr::Flag::Undefined == my_amr_flags[0]) {
93 : using ::operator<<;
94 : ASSERT(volume_dim == alg::count(my_amr_flags, amr::Flag::Undefined),
95 : "Flags should be all Undefined, not " << my_amr_flags);
96 : return;
97 : }
98 :
99 : const auto& element = get<::domain::Tags::Element<volume_dim>>(box);
100 : const auto my_initial_new_mesh = my_amr_info.new_mesh;
101 :
102 : const bool my_amr_decision_changed = amr::update_amr_decision(
103 : make_not_null(&my_amr_flags), element, neighbor_id,
104 : neighbor_amr_info.flags,
105 : get<amr::Tags::Policies>(box)
106 : .enforce_two_to_one_balance_in_normal_direction());
107 :
108 : auto& my_new_mesh = my_amr_info.new_mesh;
109 : my_new_mesh = amr::projectors::new_mesh_to_communicate_to_neighbors(
110 : get<::domain::Tags::Mesh<volume_dim>>(box), my_amr_flags, element,
111 : my_neighbors_amr_info);
112 :
113 : if (my_amr_decision_changed or my_new_mesh != my_initial_new_mesh) {
114 : auto& amr_element_array =
115 : Parallel::get_parallel_component<ParallelComponent>(cache);
116 : for (const auto& direction_neighbors : element.neighbors()) {
117 : for (const auto& id : direction_neighbors.second.ids()) {
118 : if constexpr (Parallel::is_dg_element_collection_v<
119 : ParallelComponent>) {
120 : const auto neighbor_location = static_cast<int>(
121 : Parallel::local_synchronous_action<
122 : Parallel::Actions::GetItemFromDistributedOject<
123 : Parallel::Tags::ElementLocations<volume_dim>>>(
124 : Parallel::get_parallel_component<ParallelComponent>(cache))
125 : ->at(id));
126 : Parallel::threaded_action<Parallel::Actions::SimpleActionOnElement<
127 : UpdateAmrDecision, true>>(amr_element_array[neighbor_location],
128 : id, element.id(), my_amr_info);
129 : } else {
130 : Parallel::simple_action<UpdateAmrDecision>(
131 : amr_element_array[id], element.id(), my_amr_info);
132 : }
133 : }
134 : }
135 : }
136 : }
137 : };
138 : } // namespace amr::Actions
|