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 <typeinfo> 10 : #include <utility> 11 : 12 : #include "DataStructures/DataBox/DataBox.hpp" 13 : #include "DataStructures/DataBox/ObservationBox.hpp" 14 : #include "Domain/Amr/Flag.hpp" 15 : #include "Domain/Structure/ElementId.hpp" 16 : #include "Domain/Tags.hpp" 17 : #include "IO/Logging/Tags.hpp" 18 : #include "IO/Logging/Verbosity.hpp" 19 : #include "Options/String.hpp" 20 : #include "Parallel/GlobalCache.hpp" 21 : #include "Parallel/Printf/Printf.hpp" 22 : #include "ParallelAlgorithms/Amr/Criteria/Criterion.hpp" 23 : #include "ParallelAlgorithms/Amr/Criteria/Tags/Criteria.hpp" 24 : #include "ParallelAlgorithms/Amr/Policies/EnforcePolicies.hpp" 25 : #include "ParallelAlgorithms/Amr/Policies/Tags.hpp" 26 : #include "ParallelAlgorithms/Amr/Projectors/Mesh.hpp" 27 : #include "ParallelAlgorithms/Amr/Tags.hpp" 28 : #include "ParallelAlgorithms/EventsAndTriggers/Event.hpp" 29 : #include "Utilities/Algorithm.hpp" 30 : #include "Utilities/ErrorHandling/Assert.hpp" 31 : #include "Utilities/ErrorHandling/Error.hpp" 32 : #include "Utilities/Gsl.hpp" 33 : #include "Utilities/MakeArray.hpp" 34 : #include "Utilities/Serialization/CharmPupable.hpp" 35 : #include "Utilities/TMPL.hpp" 36 : 37 : /// \cond 38 : namespace PUP { 39 : class er; 40 : } // namespace PUP 41 : namespace Tags { 42 : struct TimeStepId; 43 : } // namespace Tags 44 : namespace evolution::dg::Tags { 45 : template <size_t Dim> 46 : struct MortarNextTemporalId; 47 : } // namespace evolution::dg::Tags 48 : /// \endcond 49 : 50 : namespace amr::Events { 51 : namespace detail { 52 : template <typename Criterion> 53 : struct get_tags { 54 : using type = typename Criterion::compute_tags_for_observation_box; 55 : }; 56 : 57 : } // namespace detail 58 : 59 : /// \ingroup AmrGroup 60 : /// \brief Performs p-refinement on the domain 61 : /// 62 : /// \details 63 : /// - Loops over all p-refinement criteria specified in the input file. 64 : /// If no valid p-refinement decision is requested, no change is 65 : /// made to the Element. 66 : /// - Updates the Mesh and all return tags of Metavariables::amr::projectors 67 : /// 68 : /// \warning This does not communicate the new Mesh to its neighbors, nor does 69 : /// it update ::domain::Tags::NeighborMesh 70 1 : class RefineMesh : public Event { 71 : public: 72 : /// \cond 73 : explicit RefineMesh(CkMigrateMessage* m); 74 : using PUP::able::register_constructor; 75 : WRAPPED_PUPable_decl_template(RefineMesh); // NOLINT 76 : /// \endcond 77 : 78 0 : using options = tmpl::list<>; 79 0 : static constexpr Options::String help = {"Perform p-refinement"}; 80 : 81 0 : RefineMesh(); 82 : 83 0 : using compute_tags_for_observation_box = tmpl::list<>; 84 0 : using return_tags = tmpl::list<::Tags::DataBox>; 85 0 : using argument_tags = tmpl::list<>; 86 : 87 : template <typename DbTags, typename Metavariables, typename Component> 88 0 : void operator()(const gsl::not_null<db::DataBox<DbTags>*> box, 89 : Parallel::GlobalCache<Metavariables>& cache, 90 : const ElementId<Metavariables::volume_dim>& element_id, 91 : const Component* const /*meta*/, 92 : const ObservationValue& /*observation_value*/) const { 93 : constexpr size_t volume_dim = Metavariables::volume_dim; 94 : if (alg::any_of( 95 : db::get<evolution::dg::Tags::MortarNextTemporalId<volume_dim>>( 96 : *box), 97 : [&](const auto& mortar) { 98 : return mortar.second != db::get<::Tags::TimeStepId>(*box); 99 : })) { 100 : ERROR_NO_TRACE( 101 : "Cannot refine mesh when not temporally aligned with neighbors."); 102 : } 103 : 104 : // Evaluate AMR p-refinement criteria 105 : auto overall_decision = make_array<volume_dim>(amr::Flag::Undefined); 106 : 107 : using compute_tags = tmpl::remove_duplicates<tmpl::flatten<tmpl::transform< 108 : tmpl::at<typename Metavariables::factory_creation::factory_classes, 109 : Criterion>, 110 : detail::get_tags<tmpl::_1>>>>; 111 : auto observation_box = make_observation_box<compute_tags>(box); 112 : 113 : const auto& refinement_criteria = 114 : db::get<amr::Criteria::Tags::Criteria>(*box); 115 : for (const auto& criterion : refinement_criteria) { 116 : if (criterion->type() == amr::Criteria::Type::h) { 117 : continue; 118 : } 119 : auto decision = criterion->evaluate(observation_box, cache, element_id); 120 : ASSERT(alg::none_of(decision, 121 : [](amr::Flag flag) { 122 : return flag == amr::Flag::Split or 123 : flag == amr::Flag::Join; 124 : }), 125 : "The criterion '" << typeid(*criterion).name() 126 : << "' requested h-refinement, but claims to be " 127 : "for p-refinement."); 128 : for (size_t d = 0; d < volume_dim; ++d) { 129 : overall_decision[d] = std::max(overall_decision[d], decision[d]); 130 : } 131 : } 132 : // If no refinement criteria requested p-refinement, then set flag to 133 : // do nothing 134 : for (size_t d = 0; d < volume_dim; ++d) { 135 : if (overall_decision[d] == amr::Flag::Undefined) { 136 : overall_decision[d] = amr::Flag::DoNothing; 137 : } 138 : } 139 : 140 : // Now p-refine 141 : const auto old_mesh_and_element = 142 : std::make_pair(db::get<::domain::Tags::Mesh<volume_dim>>(*box), 143 : db::get<::domain::Tags::Element<volume_dim>>(*box)); 144 : const auto& old_mesh = old_mesh_and_element.first; 145 : const auto& verbosity = 146 : db::get<logging::Tags::Verbosity<amr::OptionTags::AmrGroup>>(*box); 147 : 148 : // Enforce policies 149 : const auto& policies = db::get<amr::Tags::Policies>(*box); 150 : amr::enforce_policies(make_not_null(&overall_decision), policies, 151 : element_id, old_mesh); 152 : 153 : if (alg::any_of(overall_decision, [](amr::Flag flag) { 154 : return (flag == amr::Flag::IncreaseResolution or 155 : flag == amr::Flag::DecreaseResolution); 156 : })) { 157 : db::mutate<::domain::Tags::Mesh<volume_dim>>( 158 : [&old_mesh, 159 : &overall_decision](const gsl::not_null<Mesh<volume_dim>*> mesh) { 160 : *mesh = amr::projectors::mesh(old_mesh, overall_decision); 161 : }, 162 : box); 163 : 164 : if (verbosity >= Verbosity::Debug) { 165 : Parallel::printf( 166 : "Increasing order of element %s: %s -> %s\n", element_id, 167 : old_mesh.extents(), 168 : db::get<::domain::Tags::Mesh<volume_dim>>(*box).extents()); 169 : } 170 : 171 : // Run the projectors. 172 : tmpl::for_each<typename Metavariables::amr::projectors>( 173 : [&box, &old_mesh_and_element](auto projector_v) { 174 : using projector = typename decltype(projector_v)::type; 175 : try { 176 : db::mutate_apply<projector>(box, old_mesh_and_element); 177 : } catch (std::exception& e) { 178 : ERROR("Error in AMR projector '" 179 : << pretty_type::get_name<projector>() << "':\n" 180 : << e.what()); 181 : } 182 : }); 183 : } 184 : } 185 : 186 0 : using is_ready_argument_tags = tmpl::list<>; 187 : 188 : template <typename Metavariables, typename ArrayIndex, typename Component> 189 0 : bool is_ready(Parallel::GlobalCache<Metavariables>& /*cache*/, 190 : const ArrayIndex& /*array_index*/, 191 : const Component* const /*meta*/) const { 192 : return true; 193 : } 194 : 195 1 : bool needs_evolved_variables() const override { return true; } 196 : 197 : // NOLINTNEXTLINE(google-runtime-references) 198 0 : void pup(PUP::er& p) override; 199 : }; 200 : } // namespace amr::Events