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 gsl { 32 : template <typename> 33 : class not_null; 34 : } 35 : /// \endcond 36 : 37 : namespace amr { 38 : /// \ingroup AmrGroup 39 : /// \brief Computes the desired refinement level of the Element with ElementId 40 : /// `id` given the desired amr::Flag%s `flags` 41 : template <size_t VolumeDim> 42 1 : std::array<size_t, VolumeDim> desired_refinement_levels( 43 : const ElementId<VolumeDim>& id, const std::array<Flag, VolumeDim>& flags); 44 : 45 : /// \ingroup AmrGroup 46 : /// \brief Computes the desired refinement level of a neighboring Element with 47 : /// ElementId `neighbor_id` given its desired amr::Flag%s `neighbor_flags` 48 : /// taking into account the OrientationMap `orientation` of the neighbor 49 : /// 50 : /// \details The OrientationMap `orientation` is that from the Element that has 51 : /// a neighbor with ElementId `neighbor_id` 52 : template <size_t VolumeDim> 53 1 : std::array<size_t, VolumeDim> desired_refinement_levels_of_neighbor( 54 : const ElementId<VolumeDim>& neighbor_id, 55 : const std::array<Flag, VolumeDim>& neighbor_flags, 56 : const OrientationMap<VolumeDim>& orientation); 57 : 58 : /// \ingroup AmrGroup 59 : /// Fraction of the logical volume of a block covered by an element 60 : /// 61 : /// \note The sum of this over all the elements of a block should be one 62 : template <size_t VolumeDim> 63 1 : boost::rational<size_t> fraction_of_block_volume( 64 : const ElementId<VolumeDim>& element_id); 65 : 66 : /// \ingroup AmrGroup 67 : /// \brief Whether or not the Element with `element_id` can have a sibling 68 : /// in the given `direction` 69 : template <size_t VolumeDim> 70 1 : bool has_potential_sibling(const ElementId<VolumeDim>& element_id, 71 : const Direction<VolumeDim>& direction); 72 : 73 : /// \ingroup AmrGroup 74 : /// \brief Returns the ElementId of the parent of the Element with `element_id` 75 : /// using the refinement `flags` associated with `element_id` 76 : /// 77 : /// \details Note that at least one flag of `flags` must be Flag::Join and 78 : /// none of the `flags` can be Flag::Split. The parent ElementId is computed 79 : /// by looping over the SegmentId%s of `element_id` and using either the 80 : /// SegmentId or its parent depending upon whether or not the corresponding Flag 81 : /// is Flag::Join. 82 : template <size_t VolumeDim> 83 1 : ElementId<VolumeDim> id_of_parent(const ElementId<VolumeDim>& element_id, 84 : const std::array<Flag, VolumeDim>& flags); 85 : 86 : /// \ingroup AmrGroup 87 : /// \brief Returns the ElementIds of the children of the Element with 88 : /// `element_id` using the refinement `flags` associated with `element_id` 89 : /// 90 : /// \details Note that at least one flag of `flags` must be Flag::Split and 91 : /// none of the `flags` can be Flag::Join. The child ElementId%s are computed 92 : /// by looping over the SegmentId%s of `element_id` and using either the 93 : /// SegmentId or its children depending upon whether or not the corresponding 94 : /// flag is Flag::Split. 95 : template <size_t VolumeDim> 96 1 : std::vector<ElementId<VolumeDim>> ids_of_children( 97 : const ElementId<VolumeDim>& element_id, 98 : const std::array<Flag, VolumeDim>& flags, 99 : const std::optional<size_t>& child_grid_index = std::nullopt); 100 : 101 : /// \ingroup AmrGroup 102 : /// \brief The ElementIds of the neighbors of `element` that will join with it 103 : /// given refinement `flags` 104 : /// 105 : /// \note This function only returns the face neighbors of `element` that will 106 : /// join with it, and not the joining corner neighbors 107 : template <size_t VolumeDim> 108 1 : std::deque<ElementId<VolumeDim>> ids_of_joining_neighbors( 109 : const Element<VolumeDim>& element, 110 : const std::array<Flag, VolumeDim>& flags); 111 : 112 : /// \ingroup AmrGroup 113 : /// \brief Whether or not the Element is the child that should create the parent 114 : /// Element when joining elements 115 : /// 116 : /// \details This returns true if the Element is the lower sibling segment in 117 : /// all dimensions that are joining 118 : template <size_t VolumeDim> 119 1 : bool is_child_that_creates_parent(const ElementId<VolumeDim>& element_id, 120 : const std::array<Flag, VolumeDim>& flags); 121 : 122 : /// \ingroup AmrGroup 123 : /// \brief Prevent an Element from splitting in one dimension, while joining in 124 : /// another 125 : /// 126 : /// \details If `flags` (the AMR decisions of an Element) contains both 127 : /// amr::Flag::Split and amr::Flag::Join, then all change Join 128 : /// to amr::Flag::DoNothing. 129 : /// 130 : /// \returns true if any flag is changed 131 : /// 132 : /// \note This restriction could be relaxed, but it would greatly complicate 133 : /// the AMR algorithm. As a Join flag has the lowest priority, it causes 134 : /// no problems to replace it with a DoNothing flag. 135 : template <size_t VolumeDim> 136 1 : bool prevent_element_from_joining_while_splitting( 137 : gsl::not_null<std::array<Flag, VolumeDim>*> flags); 138 : } // namespace amr