Line data Source code
1 1 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : /// \file 5 : /// Functions used for adaptive mesh refinement decisions. 6 : 7 : #pragma once 8 : 9 : #include <array> 10 : #include <boost/rational.hpp> 11 : #include <cstddef> 12 : #include <deque> 13 : #include <optional> 14 : #include <vector> 15 : 16 : #include "Domain/Amr/Flag.hpp" 17 : 18 : /// \cond 19 : template <size_t VolumeDim> 20 : class Direction; 21 : 22 : template <size_t VolumeDim> 23 : class Element; 24 : 25 : template <size_t VolumeDim> 26 : class ElementId; 27 : 28 : template <size_t VolumeDim> 29 : class OrientationMap; 30 : 31 : namespace domain { 32 : enum class Topology : uint8_t; 33 : } // namespace domain 34 : 35 : namespace gsl { 36 : template <typename> 37 : class not_null; 38 : } // namespace gsl 39 : /// \endcond 40 : 41 : namespace amr { 42 : /// \ingroup AmrGroup 43 : /// \brief Computes the desired refinement level of the Element with ElementId 44 : /// `id` given the desired amr::Flag%s `flags` 45 : template <size_t VolumeDim> 46 1 : std::array<size_t, VolumeDim> desired_refinement_levels( 47 : const ElementId<VolumeDim>& id, const std::array<Flag, VolumeDim>& flags); 48 : 49 : /// \ingroup AmrGroup 50 : /// \brief Computes the desired refinement level of a neighboring Element with 51 : /// ElementId `neighbor_id` given its desired amr::Flag%s `neighbor_flags` 52 : /// taking into account the OrientationMap `orientation` of the neighbor 53 : /// 54 : /// \details The OrientationMap `orientation` is that from the Element that has 55 : /// a neighbor with ElementId `neighbor_id` 56 : template <size_t VolumeDim> 57 1 : std::array<size_t, VolumeDim> desired_refinement_levels_of_neighbor( 58 : const ElementId<VolumeDim>& neighbor_id, 59 : const std::array<Flag, VolumeDim>& neighbor_flags, 60 : const OrientationMap<VolumeDim>& orientation); 61 : 62 : /// \ingroup AmrGroup 63 : /// Fraction of the logical volume of a block covered by an element 64 : /// 65 : /// \note The sum of this over all the elements of a block should be one 66 : template <size_t VolumeDim> 67 1 : boost::rational<size_t> fraction_of_block_volume( 68 : const ElementId<VolumeDim>& element_id); 69 : 70 : /// \ingroup AmrGroup 71 : /// \brief Whether or not the Element with `element_id` can have a sibling 72 : /// in the given `direction` 73 : template <size_t VolumeDim> 74 1 : bool has_potential_sibling(const ElementId<VolumeDim>& element_id, 75 : const Direction<VolumeDim>& direction); 76 : 77 : /// \ingroup AmrGroup 78 : /// \brief Returns the ElementId of the parent of the Element with `element_id` 79 : /// using the refinement `flags` associated with `element_id` 80 : /// 81 : /// \details Note that at least one flag of `flags` must be Flag::Join and 82 : /// none of the `flags` can be Flag::Split. The parent ElementId is computed 83 : /// by looping over the SegmentId%s of `element_id` and using either the 84 : /// SegmentId or its parent depending upon whether or not the corresponding Flag 85 : /// is Flag::Join. 86 : template <size_t VolumeDim> 87 1 : ElementId<VolumeDim> id_of_parent(const ElementId<VolumeDim>& element_id, 88 : const std::array<Flag, VolumeDim>& flags); 89 : 90 : /// \ingroup AmrGroup 91 : /// \brief Returns the ElementIds of the children of the Element with 92 : /// `element_id` using the refinement `flags` associated with `element_id` 93 : /// 94 : /// \details Note that at least one flag of `flags` must be Flag::Split and 95 : /// none of the `flags` can be Flag::Join. The child ElementId%s are computed 96 : /// by looping over the SegmentId%s of `element_id` and using either the 97 : /// SegmentId or its children depending upon whether or not the corresponding 98 : /// flag is Flag::Split. 99 : template <size_t VolumeDim> 100 1 : std::vector<ElementId<VolumeDim>> ids_of_children( 101 : const ElementId<VolumeDim>& element_id, 102 : const std::array<Flag, VolumeDim>& flags, 103 : const std::optional<size_t>& child_grid_index = std::nullopt); 104 : 105 : /// \ingroup AmrGroup 106 : /// \brief The ElementIds of the neighbors of `element` that will join with it 107 : /// given refinement `flags` 108 : /// 109 : /// \note This function only returns the face neighbors of `element` that will 110 : /// join with it, and not the joining corner neighbors 111 : template <size_t VolumeDim> 112 1 : std::deque<ElementId<VolumeDim>> ids_of_joining_neighbors( 113 : const Element<VolumeDim>& element, 114 : const std::array<Flag, VolumeDim>& flags); 115 : 116 : /// \ingroup AmrGroup 117 : /// \brief Whether or not the Element is the child that should create the parent 118 : /// Element when joining elements 119 : /// 120 : /// \details This returns true if the Element is the lower sibling segment in 121 : /// all dimensions that are joining 122 : template <size_t VolumeDim> 123 1 : bool is_child_that_creates_parent(const ElementId<VolumeDim>& element_id, 124 : const std::array<Flag, VolumeDim>& flags); 125 : 126 : /// \ingroup AmrGroup 127 : /// \brief Prevent an Element from splitting in one dimension, while joining in 128 : /// another 129 : /// 130 : /// \details If `flags` (the AMR decisions of an Element) contains both 131 : /// amr::Flag::Split and amr::Flag::Join, then all change Join 132 : /// to amr::Flag::DoNothing. 133 : /// 134 : /// \returns true if any flag is changed 135 : /// 136 : /// \note This restriction could be relaxed, but it would greatly complicate 137 : /// the AMR algorithm. As a Join flag has the lowest priority, it causes 138 : /// no problems to replace it with a DoNothing flag. 139 : template <size_t VolumeDim> 140 1 : bool prevent_element_from_joining_while_splitting( 141 : gsl::not_null<std::array<Flag, VolumeDim>*> flags); 142 : 143 : /// \ingroup AmrGroup 144 : /// \brief Enforce restrictions on AMR decisions for h-refinement based on the 145 : /// topologies of the Element. 146 : /// 147 : /// \details Angular topologies (e.g. S1 or S2) and cartoon topologies (e.g. 148 : /// (CartoonSphere) cannot be h-refined. 149 : template <size_t VolumeDim> 150 1 : void enforce_h_refinement_topology_restrictions( 151 : gsl::not_null<std::array<Flag, VolumeDim>*> flags, 152 : const std::array<domain::Topology, VolumeDim>& topologies); 153 : 154 : /// \ingroup AmrGroup 155 : /// \brief Enforce restrictions on AMR decisions for p-refinement based on the 156 : /// topologies of the Element. 157 : /// 158 : /// \details Multi-dimensional topologies (e.g. S2, B2, B3) have relationships 159 : /// between their extents that must be enforced so that the highest modes 160 : /// are correctly represented. Cartoon topologies cannot be p-refined. 161 : template <size_t VolumeDim> 162 1 : void enforce_p_refinement_topology_restrictions( 163 : [[maybe_unused]] gsl::not_null<std::array<Flag, VolumeDim>*> flags, 164 : [[maybe_unused]] const std::array<domain::Topology, VolumeDim>& topologies); 165 : } // namespace amr