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
|