Line data Source code
1 1 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : /// \file 5 : /// Defines actions ApplyLimiter and SendDataForLimiter 6 : 7 : #pragma once 8 : 9 : #include <boost/functional/hash.hpp> // IWYU pragma: keep 10 : #include <cstddef> 11 : #include <map> 12 : #include <optional> 13 : #include <unordered_map> 14 : #include <utility> 15 : 16 : #include "DataStructures/DataBox/DataBox.hpp" 17 : #include "Domain/Structure/DirectionalId.hpp" 18 : #include "Domain/Tags.hpp" 19 : #include "Parallel/AlgorithmExecution.hpp" 20 : #include "Parallel/GlobalCache.hpp" 21 : #include "Parallel/InboxInserters.hpp" 22 : #include "Parallel/Invoke.hpp" 23 : #include "Utilities/ErrorHandling/Assert.hpp" 24 : #include "Utilities/TaggedTuple.hpp" 25 : 26 : namespace Limiters { 27 0 : namespace Tags { 28 : /// \ingroup DiscontinuousGalerkinGroup 29 : /// \ingroup LimitersGroup 30 : /// \brief The inbox tag for limiter communication. 31 : template <typename Metavariables> 32 1 : struct LimiterCommunicationTag : public Parallel::InboxInserters::Map< 33 : LimiterCommunicationTag<Metavariables>> { 34 0 : static constexpr size_t volume_dim = Metavariables::system::volume_dim; 35 0 : using packaged_data_t = typename Metavariables::limiter::type::PackagedData; 36 0 : using temporal_id = typename Metavariables::temporal_id::type; 37 0 : using type = 38 : std::map<temporal_id, 39 : std::unordered_map<DirectionalId<volume_dim>, packaged_data_t, 40 : boost::hash<DirectionalId<volume_dim>>>>; 41 : }; 42 : } // namespace Tags 43 : 44 0 : namespace Actions { 45 : /// \ingroup ActionsGroup 46 : /// \ingroup DiscontinuousGalerkinGroup 47 : /// \ingroup LimitersGroup 48 : /// \brief Receive limiter data from neighbors, then apply limiter. 49 : /// 50 : /// Currently, is not tested for support of: 51 : /// - h-refinement 52 : /// Currently, does not support: 53 : /// - Local time-stepping 54 : /// 55 : /// Uses: 56 : /// - GlobalCache: 57 : /// - Metavariables::limiter 58 : /// - DataBox: 59 : /// - Metavariables::limiter::type::limit_argument_tags 60 : /// - Metavariables::temporal_id 61 : /// - Tags::Element<volume_dim> 62 : /// DataBox changes: 63 : /// - Adds: nothing 64 : /// - Removes: nothing 65 : /// - Modifies: 66 : /// - Metavariables::limiter::type::limit_tags 67 : /// 68 : /// \see SendDataForLimiter 69 : template <typename Metavariables> 70 1 : struct Limit { 71 0 : using const_global_cache_tags = tmpl::list<typename Metavariables::limiter>; 72 : 73 : public: 74 0 : using limiter_comm_tag = 75 : Limiters::Tags::LimiterCommunicationTag<Metavariables>; 76 0 : using inbox_tags = tmpl::list<limiter_comm_tag>; 77 : 78 : template <typename DbTags, typename... InboxTags, typename ArrayIndex, 79 : typename ActionList, typename ParallelComponent> 80 0 : static Parallel::iterable_action_return_t apply( 81 : db::DataBox<DbTags>& box, tuples::TaggedTuple<InboxTags...>& inboxes, 82 : const Parallel::GlobalCache<Metavariables>& cache, 83 : const ArrayIndex& /*array_index*/, const ActionList /*meta*/, 84 : const ParallelComponent* const /*meta*/) { 85 : static_assert( 86 : not Metavariables::local_time_stepping, 87 : "Limiter communication actions do not yet support local time stepping"); 88 : 89 : constexpr size_t volume_dim = Metavariables::system::volume_dim; 90 : 91 : const auto& local_temporal_id = 92 : db::get<typename Metavariables::temporal_id>(box); 93 : auto& inbox = tuples::get<limiter_comm_tag>(inboxes); 94 : const auto& received = inbox.find(local_temporal_id); 95 : 96 : const auto& element = db::get<domain::Tags::Element<volume_dim>>(box); 97 : const auto num_expected = element.neighbors().size(); 98 : if (num_expected > 0 and 99 : (received == inbox.end() or received->second.size() != num_expected)) { 100 : return {Parallel::AlgorithmExecution::Retry, std::nullopt}; 101 : } 102 : 103 : const auto& limiter = get<typename Metavariables::limiter>(cache); 104 : using mutate_tags = typename Metavariables::limiter::type::limit_tags; 105 : using argument_tags = 106 : typename Metavariables::limiter::type::limit_argument_tags; 107 : db::mutate_apply<mutate_tags, argument_tags>(limiter, make_not_null(&box), 108 : inbox[local_temporal_id]); 109 : 110 : inbox.erase(local_temporal_id); 111 : 112 : return {Parallel::AlgorithmExecution::Continue, std::nullopt}; 113 : } 114 : }; 115 : 116 : /// \ingroup ActionsGroup 117 : /// \ingroup DiscontinuousGalerkinGroup 118 : /// \ingroup LimitersGroup 119 : /// \brief Send local data needed for limiting. 120 : /// 121 : /// Currently, is not tested for support of: 122 : /// - h-refinement 123 : /// Currently, does not support: 124 : /// - Local time-stepping 125 : /// 126 : /// Uses: 127 : /// - GlobalCache: 128 : /// - Metavariables::limiter 129 : /// - DataBox: 130 : /// - Tags::Element<volume_dim> 131 : /// - Metavariables::limiter::type::package_argument_tags 132 : /// - Metavariables::temporal_id 133 : /// 134 : /// DataBox changes: 135 : /// - Adds: nothing 136 : /// - Removes: nothing 137 : /// - Modifies: nothing 138 : /// 139 : /// \see ApplyLimiter 140 : template <typename Metavariables> 141 1 : struct SendData { 142 0 : using const_global_cache_tags = tmpl::list<typename Metavariables::limiter>; 143 0 : using limiter_comm_tag = 144 : Limiters::Tags::LimiterCommunicationTag<Metavariables>; 145 : 146 : template <typename DbTags, typename... InboxTags, typename ArrayIndex, 147 : typename ActionList, typename ParallelComponent> 148 0 : static Parallel::iterable_action_return_t apply( 149 : db::DataBox<DbTags>& box, tuples::TaggedTuple<InboxTags...>& /*inboxes*/, 150 : Parallel::GlobalCache<Metavariables>& cache, 151 : const ArrayIndex& /*array_index*/, const ActionList /*meta*/, 152 : const ParallelComponent* const /*meta*/) { 153 : constexpr size_t volume_dim = Metavariables::system::volume_dim; 154 : 155 : auto& receiver_proxy = 156 : Parallel::get_parallel_component<ParallelComponent>(cache); 157 : const auto& element = db::get<domain::Tags::Element<volume_dim>>(box); 158 : const auto& temporal_id = db::get<typename Metavariables::temporal_id>(box); 159 : const auto& limiter = get<typename Metavariables::limiter>(cache); 160 : 161 : for (const auto& direction_neighbors : element.neighbors()) { 162 : const auto& direction = direction_neighbors.first; 163 : const size_t dimension = direction.dimension(); 164 : const auto& neighbors_in_direction = direction_neighbors.second; 165 : ASSERT(neighbors_in_direction.size() == 1, 166 : "h-adaptivity is not supported yet.\nDirection: " 167 : << direction << "\nDimension: " << dimension 168 : << "\nNeighbors:\n" 169 : << neighbors_in_direction); 170 : const auto& orientation = neighbors_in_direction.orientation(); 171 : const auto direction_from_neighbor = orientation(direction.opposite()); 172 : 173 : using argument_tags = 174 : typename Metavariables::limiter::type::package_argument_tags; 175 : const auto packaged_data = db::apply<argument_tags>( 176 : [&limiter](const auto&... args) { 177 : // Note: orientation is received as last element of pack `args` 178 : typename Metavariables::limiter::type::PackagedData pack{}; 179 : limiter.package_data(make_not_null(&pack), args...); 180 : return pack; 181 : }, 182 : box, orientation); 183 : 184 : for (const auto& neighbor : neighbors_in_direction) { 185 : Parallel::receive_data<limiter_comm_tag>( 186 : receiver_proxy[neighbor], temporal_id, 187 : std::make_pair(DirectionalId<volume_dim>{direction_from_neighbor, 188 : element.id()}, 189 : packaged_data)); 190 : 191 : } // loop over neighbors_in_direction 192 : } // loop over element.neighbors() 193 : 194 : return {Parallel::AlgorithmExecution::Continue, std::nullopt}; 195 : } 196 : }; 197 : } // namespace Actions 198 : } // namespace Limiters