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 <boost/functional/hash.hpp>
9 : #include <cstddef>
10 : #include <functional>
11 : #include <tuple>
12 : #include <type_traits>
13 : #include <utility> // IWYU pragma: keep // for std::forward
14 :
15 : #include "DataStructures/ApplyMatrices.hpp"
16 : #include "DataStructures/DataBox/PrefixHelpers.hpp"
17 : #include "DataStructures/DataBox/Prefixes.hpp"
18 : #include "DataStructures/Matrix.hpp"
19 : #include "DataStructures/Variables.hpp"
20 : #include "Domain/Structure/Direction.hpp"
21 : #include "Domain/Structure/DirectionalId.hpp"
22 : #include "Domain/Structure/ElementId.hpp"
23 : #include "NumericalAlgorithms/DiscontinuousGalerkin/LiftFlux.hpp"
24 : #include "NumericalAlgorithms/Spectral/Mesh.hpp"
25 : #include "NumericalAlgorithms/Spectral/Projection.hpp"
26 : #include "Utilities/Algorithm.hpp"
27 : #include "Utilities/ConstantExpressions.hpp"
28 : #include "Utilities/ErrorHandling/Assert.hpp"
29 : #include "Utilities/Gsl.hpp"
30 : #include "Utilities/MakeArray.hpp"
31 : #include "Utilities/TMPL.hpp"
32 : /// \cond
33 : template <size_t VolumeDim>
34 : class ElementId;
35 : template <size_t VolumeDim>
36 : class OrientationMap;
37 : // IWYU pragma: no_forward_declare Variables
38 : /// \endcond
39 :
40 : namespace dg {
41 :
42 : template <size_t VolumeDim>
43 0 : using MortarId = DirectionalId<VolumeDim>;
44 : template <size_t MortarDim>
45 0 : using MortarSize = std::array<Spectral::MortarSize, MortarDim>;
46 : template <size_t VolumeDim, typename ValueType>
47 0 : using MortarMap = std::unordered_map<MortarId<VolumeDim>, ValueType,
48 : boost::hash<MortarId<VolumeDim>>>;
49 :
50 : /// \ingroup DiscontinuousGalerkinGroup
51 : /// Find a mesh for a mortar capable of representing data from either
52 : /// of two faces.
53 : ///
54 : /// \warning Make sure the two face meshes are oriented the same, i.e.
55 : /// their dimensions align. This is facilitated by the `orientation`
56 : /// passed to `domain::Initialization::create_initial_mesh`, for
57 : /// example.
58 : template <size_t Dim>
59 1 : Mesh<Dim> mortar_mesh(const Mesh<Dim>& face_mesh1, const Mesh<Dim>& face_mesh2);
60 :
61 : /// \ingroup DiscontinuousGalerkinGroup
62 : /// Determine the size of the mortar (i.e., the part of the face it
63 : /// covers) for communicating with a neighbor. This is the size
64 : /// relative to the size of \p self, and will not generally agree with
65 : /// that determined by \p neighbor.
66 : template <size_t Dim>
67 1 : MortarSize<Dim - 1> mortar_size(const ElementId<Dim>& self,
68 : const ElementId<Dim>& neighbor,
69 : size_t dimension,
70 : const OrientationMap<Dim>& orientation);
71 :
72 : /// @{
73 : /// \ingroup DiscontinuousGalerkinGroup
74 : /// Project variables from a face to a mortar.
75 : template <typename Tags, size_t Dim>
76 1 : void project_to_mortar(const gsl::not_null<Variables<Tags>*> result,
77 : const Variables<Tags>& vars, const Mesh<Dim>& face_mesh,
78 : const Mesh<Dim>& mortar_mesh,
79 : const MortarSize<Dim>& mortar_size) {
80 : const auto projection_matrices = Spectral::projection_matrix_parent_to_child(
81 : face_mesh, mortar_mesh, mortar_size);
82 : // We don't add an ASSERT about sizes here because there's already one in
83 : // apply_matrices
84 : apply_matrices(result, projection_matrices, vars, face_mesh.extents());
85 : }
86 :
87 : template <typename Tags, size_t Dim>
88 1 : Variables<Tags> project_to_mortar(const Variables<Tags>& vars,
89 : const Mesh<Dim>& face_mesh,
90 : const Mesh<Dim>& mortar_mesh,
91 : const MortarSize<Dim>& mortar_size) {
92 : Variables<Tags> result{mortar_mesh.number_of_grid_points()};
93 : project_to_mortar(make_not_null(&result), vars, face_mesh, mortar_mesh,
94 : mortar_size);
95 : return result;
96 : }
97 : /// @}
98 :
99 : /// @{
100 : /// \ingroup DiscontinuousGalerkinGroup
101 : /// Project variables from a mortar to a face.
102 : template <typename Tags, size_t Dim>
103 1 : void project_from_mortar(const gsl::not_null<Variables<Tags>*> result,
104 : const Variables<Tags>& vars,
105 : const Mesh<Dim>& face_mesh,
106 : const Mesh<Dim>& mortar_mesh,
107 : const MortarSize<Dim>& mortar_size) {
108 : ASSERT(Spectral::needs_projection(face_mesh, mortar_mesh, mortar_size),
109 : "project_from_mortar should not be called if the interface mesh and "
110 : "mortar mesh are identical. Please elide the copy instead.");
111 : const auto projection_matrices = Spectral::projection_matrix_child_to_parent(
112 : mortar_mesh, face_mesh, mortar_size);
113 : // We don't add an ASSERT about sizes here because there's already one in
114 : // apply_matrices
115 : apply_matrices(result, projection_matrices, vars, mortar_mesh.extents());
116 : }
117 :
118 : template <typename Tags, size_t Dim>
119 1 : Variables<Tags> project_from_mortar(const Variables<Tags>& vars,
120 : const Mesh<Dim>& face_mesh,
121 : const Mesh<Dim>& mortar_mesh,
122 : const MortarSize<Dim>& mortar_size) {
123 : ASSERT(Spectral::needs_projection(face_mesh, mortar_mesh, mortar_size),
124 : "project_from_mortar should not be called if the interface mesh and "
125 : "mortar mesh are identical. Please elide the copy instead.");
126 : Variables<Tags> result{face_mesh.number_of_grid_points()};
127 : project_from_mortar(make_not_null(&result), vars, face_mesh, mortar_mesh,
128 : mortar_size);
129 : return result;
130 : }
131 : /// @}
132 :
133 : /// @{
134 : /// \brief Performs a perfect hash of the mortars into $2^{d-1}$ slots on the
135 : /// range $[0, 2^{d-1})$.
136 : ///
137 : /// This is particularly useful when hashing into statically-sized maps based
138 : /// on the number of dimensions.
139 : template <size_t DimMinusOne>
140 1 : size_t hash(const std::array<Spectral::ChildSize, DimMinusOne>& mortar_size) {
141 : if constexpr (DimMinusOne == 2) {
142 : return static_cast<size_t>(mortar_size[0]) % 2 +
143 : 2 * (static_cast<size_t>(mortar_size[1]) % 2);
144 : } else if constexpr (DimMinusOne == 1) {
145 : return static_cast<size_t>(mortar_size[0]) % 2;
146 : } else if constexpr (DimMinusOne == 0) {
147 : (void)mortar_size;
148 : return 0;
149 : } else {
150 : static_assert(DimMinusOne == 2 or DimMinusOne == 1 or DimMinusOne == 0);
151 : }
152 : }
153 :
154 : template <size_t Dim>
155 0 : struct MortarSizeHash {
156 : template <size_t MaxSize>
157 0 : static constexpr bool is_perfect = MaxSize == two_to_the(Dim);
158 :
159 0 : size_t operator()(
160 : const std::array<Spectral::ChildSize, Dim - 1>& mortar_size) {
161 : return hash(mortar_size);
162 : }
163 : };
164 : /// @}
165 : } // namespace dg
|