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