Line data Source code
1 1 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : /// \file
5 : /// Declares function unnormalized_face_normal
6 :
7 : #pragma once
8 :
9 : #include <algorithm>
10 : #include <cstddef>
11 : #include <functional>
12 : #include <string>
13 : #include <unordered_map>
14 :
15 : #include "DataStructures/DataBox/Tag.hpp"
16 : #include "DataStructures/Tensor/TypeAliases.hpp"
17 : #include "Domain/CoordinateMaps/Tags.hpp"
18 : #include "Domain/FunctionsOfTime/Tags.hpp"
19 : #include "Domain/InterfaceComputeTags.hpp"
20 : #include "Domain/Tags.hpp" // IWYU pragma: keep
21 : #include "Time/Tags.hpp"
22 : #include "Utilities/Gsl.hpp"
23 : #include "Utilities/TMPL.hpp"
24 :
25 : /// \cond
26 : namespace domain {
27 : template <typename, typename, size_t>
28 : class CoordinateMapBase;
29 : } // namespace domain
30 : class DataVector;
31 : template <size_t>
32 : class Direction;
33 : template <size_t Dim, typename Frame>
34 : class ElementMap;
35 : template <size_t>
36 : class Mesh;
37 : /// \endcond
38 :
39 : /// @{
40 : /*!
41 : * \ingroup ComputationalDomainGroup
42 : * \brief Compute the outward grid normal on a face of an Element
43 : *
44 : * \details
45 : * Computes the grid-frame normal by taking the logical-frame unit
46 : * one-form in the given Direction and mapping it to the grid frame
47 : * with the given map, or the given inverse Jacobian.
48 : *
49 : * \example
50 : * \snippet Test_FaceNormal.cpp face_normal_example
51 : */
52 : template <size_t VolumeDim, typename TargetFrame>
53 1 : void unnormalized_face_normal(
54 : const gsl::not_null<tnsr::i<DataVector, VolumeDim, TargetFrame>*> result,
55 : const Mesh<VolumeDim - 1>& interface_mesh,
56 : const InverseJacobian<DataVector, VolumeDim, Frame::ElementLogical,
57 : TargetFrame>& inv_jacobian_on_interface,
58 : const Direction<VolumeDim>& direction);
59 :
60 : template <size_t VolumeDim, typename TargetFrame>
61 1 : tnsr::i<DataVector, VolumeDim, TargetFrame> unnormalized_face_normal(
62 : const Mesh<VolumeDim - 1>& interface_mesh,
63 : const InverseJacobian<DataVector, VolumeDim, Frame::ElementLogical,
64 : TargetFrame>& inv_jacobian_on_interface,
65 : const Direction<VolumeDim>& direction);
66 :
67 : template <size_t VolumeDim, typename TargetFrame>
68 1 : void unnormalized_face_normal(
69 : gsl::not_null<tnsr::i<DataVector, VolumeDim, TargetFrame>*> result,
70 : const Mesh<VolumeDim - 1>& interface_mesh,
71 : const ElementMap<VolumeDim, TargetFrame>& map,
72 : const Direction<VolumeDim>& direction);
73 :
74 : template <size_t VolumeDim, typename TargetFrame>
75 1 : tnsr::i<DataVector, VolumeDim, TargetFrame> unnormalized_face_normal(
76 : const Mesh<VolumeDim - 1>& interface_mesh,
77 : const ElementMap<VolumeDim, TargetFrame>& map,
78 : const Direction<VolumeDim>& direction);
79 :
80 : template <size_t VolumeDim, typename TargetFrame>
81 1 : void unnormalized_face_normal(
82 : gsl::not_null<tnsr::i<DataVector, VolumeDim, TargetFrame>*> result,
83 : const Mesh<VolumeDim - 1>& interface_mesh,
84 : const domain::CoordinateMapBase<Frame::ElementLogical, TargetFrame,
85 : VolumeDim>& map,
86 : const Direction<VolumeDim>& direction);
87 :
88 : template <size_t VolumeDim, typename TargetFrame>
89 1 : tnsr::i<DataVector, VolumeDim, TargetFrame> unnormalized_face_normal(
90 : const Mesh<VolumeDim - 1>& interface_mesh,
91 : const domain::CoordinateMapBase<Frame::ElementLogical, TargetFrame,
92 : VolumeDim>& map,
93 : const Direction<VolumeDim>& direction);
94 :
95 : template <size_t VolumeDim>
96 1 : void unnormalized_face_normal(
97 : gsl::not_null<tnsr::i<DataVector, VolumeDim, Frame::Inertial>*> result,
98 : const Mesh<VolumeDim - 1>& interface_mesh,
99 : const ElementMap<VolumeDim, Frame::Grid>& logical_to_grid_map,
100 : const domain::CoordinateMapBase<Frame::Grid, Frame::Inertial, VolumeDim>&
101 : grid_to_inertial_map,
102 : double time,
103 : const std::unordered_map<
104 : std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
105 : functions_of_time,
106 : const Direction<VolumeDim>& direction);
107 :
108 : template <size_t VolumeDim>
109 1 : tnsr::i<DataVector, VolumeDim, Frame::Inertial> unnormalized_face_normal(
110 : const Mesh<VolumeDim - 1>& interface_mesh,
111 : const ElementMap<VolumeDim, Frame::Grid>& logical_to_grid_map,
112 : const domain::CoordinateMapBase<Frame::Grid, Frame::Inertial, VolumeDim>&
113 : grid_to_inertial_map,
114 : double time,
115 : const std::unordered_map<
116 : std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
117 : functions_of_time,
118 : const Direction<VolumeDim>& direction);
119 : /// @}
120 :
121 : namespace domain {
122 : namespace Tags {
123 : /// \ingroup DataBoxTagsGroup
124 : /// \ingroup ComputationalDomainGroup
125 : /// The unnormalized face normal one form
126 : template <size_t VolumeDim, typename Frame = ::Frame::Inertial>
127 1 : struct UnnormalizedFaceNormal : db::SimpleTag {
128 0 : using type = tnsr::i<DataVector, VolumeDim, Frame>;
129 : };
130 :
131 : template <size_t VolumeDim, typename Frame = ::Frame::Inertial>
132 0 : struct UnnormalizedFaceNormalCompute
133 : : db::ComputeTag, UnnormalizedFaceNormal<VolumeDim, Frame> {
134 0 : using base = UnnormalizedFaceNormal<VolumeDim, Frame>;
135 0 : using return_type = typename base::type;
136 0 : static constexpr auto function = static_cast<void (*)(
137 : gsl::not_null<return_type*>, const ::Mesh<VolumeDim - 1>&,
138 : const ::ElementMap<VolumeDim, Frame>&, const ::Direction<VolumeDim>&)>(
139 : &unnormalized_face_normal);
140 0 : using argument_tags =
141 : tmpl::list<Mesh<VolumeDim - 1>, ElementMap<VolumeDim, Frame>,
142 : Direction<VolumeDim>>;
143 0 : using volume_tags = tmpl::list<ElementMap<VolumeDim, Frame>>;
144 : };
145 :
146 : template <size_t VolumeDim>
147 0 : struct UnnormalizedFaceNormalMovingMeshCompute
148 : : db::ComputeTag,
149 : UnnormalizedFaceNormal<VolumeDim, Frame::Inertial> {
150 0 : using base = UnnormalizedFaceNormal<VolumeDim, Frame::Inertial>;
151 0 : using return_type = typename base::type;
152 0 : static constexpr auto function = static_cast<void (*)(
153 : gsl::not_null<return_type*>, const ::Mesh<VolumeDim - 1>&,
154 : const ::ElementMap<VolumeDim, Frame::Grid>&,
155 : const domain::CoordinateMapBase<Frame::Grid, Frame::Inertial, VolumeDim>&,
156 : double,
157 : const std::unordered_map<
158 : std::string,
159 : std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&,
160 : const ::Direction<VolumeDim>&)>(&unnormalized_face_normal);
161 0 : using argument_tags =
162 : tmpl::list<Mesh<VolumeDim - 1>, ElementMap<VolumeDim, Frame::Grid>,
163 : CoordinateMaps::Tags::CoordinateMap<VolumeDim, Frame::Grid,
164 : Frame::Inertial>,
165 : ::Tags::Time, Tags::FunctionsOfTime, Direction<VolumeDim>>;
166 0 : using volume_tags =
167 : tmpl::list<ElementMap<VolumeDim, Frame::Grid>,
168 : CoordinateMaps::Tags::CoordinateMap<VolumeDim, Frame::Grid,
169 : Frame::Inertial>,
170 : ::Tags::Time, Tags::FunctionsOfTime>;
171 : };
172 :
173 : /// \ingroup DataBoxTagsGroup
174 : /// \ingroup ComputationalDomainGroup
175 : /// Specialisation of UnnormalizedFaceNormal for the external boundaries which
176 : /// inverts the normals. Since ExternalBoundariesDirections are meant to
177 : /// represent ghost elements, the normals should correspond to the normals in
178 : /// said element, which are inverted with respect to the current element.
179 : template <size_t VolumeDim, typename Frame>
180 1 : struct InterfaceCompute<Tags::BoundaryDirectionsExterior<VolumeDim>,
181 : UnnormalizedFaceNormalCompute<VolumeDim, Frame>>
182 : : db::ComputeTag,
183 : Tags::Interface<Tags::BoundaryDirectionsExterior<VolumeDim>,
184 : Tags::UnnormalizedFaceNormal<VolumeDim, Frame>> {
185 0 : using base = Tags::Interface<Tags::BoundaryDirectionsExterior<VolumeDim>,
186 : Tags::UnnormalizedFaceNormal<VolumeDim, Frame>>;
187 0 : using dirs = BoundaryDirectionsExterior<VolumeDim>;
188 :
189 0 : static std::string name() {
190 : return "BoundaryDirectionsExterior<UnnormalizedFaceNormal>";
191 : }
192 0 : using return_type = std::unordered_map<::Direction<VolumeDim>,
193 : tnsr::i<DataVector, VolumeDim, Frame>>;
194 0 : static void function(const gsl::not_null<return_type*> normals,
195 : const std::unordered_map<::Direction<VolumeDim>,
196 : ::Mesh<VolumeDim - 1>>& meshes,
197 : const ::ElementMap<VolumeDim, Frame>& map) {
198 : for (const auto& direction_and_mesh : meshes) {
199 : const auto& direction = direction_and_mesh.first;
200 : const auto& mesh = direction_and_mesh.second;
201 : auto internal_face_normal =
202 : unnormalized_face_normal(mesh, map, direction);
203 : std::transform(internal_face_normal.begin(), internal_face_normal.end(),
204 : internal_face_normal.begin(), std::negate<>());
205 : (*normals)[direction] = std::move(internal_face_normal);
206 : }
207 : }
208 :
209 0 : using argument_tags = tmpl::list<Tags::Interface<dirs, Mesh<VolumeDim - 1>>,
210 : Tags::ElementMap<VolumeDim, Frame>>;
211 : };
212 :
213 : template <size_t VolumeDim>
214 0 : struct InterfaceCompute<Tags::BoundaryDirectionsExterior<VolumeDim>,
215 : UnnormalizedFaceNormalMovingMeshCompute<VolumeDim>>
216 : : db::ComputeTag,
217 : Tags::Interface<
218 : Tags::BoundaryDirectionsExterior<VolumeDim>,
219 : Tags::UnnormalizedFaceNormal<VolumeDim, Frame::Inertial>> {
220 0 : using base =
221 : Tags::Interface<Tags::BoundaryDirectionsExterior<VolumeDim>,
222 : Tags::UnnormalizedFaceNormal<VolumeDim, Frame::Inertial>>;
223 0 : using dirs = BoundaryDirectionsExterior<VolumeDim>;
224 :
225 0 : static std::string name() {
226 : return "BoundaryDirectionsExterior<UnnormalizedFaceNormal>";
227 : }
228 0 : using return_type =
229 : std::unordered_map<::Direction<VolumeDim>,
230 : tnsr::i<DataVector, VolumeDim, Frame::Inertial>>;
231 0 : static void function(
232 : const gsl::not_null<return_type*> normals,
233 : const std::unordered_map<::Direction<VolumeDim>, ::Mesh<VolumeDim - 1>>&
234 : meshes,
235 : const ::ElementMap<VolumeDim, Frame::Grid>& logical_to_grid_map,
236 : const domain::CoordinateMapBase<Frame::Grid, Frame::Inertial, VolumeDim>&
237 : grid_to_inertial_map,
238 : const double time,
239 : const std::unordered_map<
240 : std::string,
241 : std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
242 : functions_of_time) {
243 : for (const auto& direction_and_mesh : meshes) {
244 : const auto& direction = direction_and_mesh.first;
245 : const auto& mesh = direction_and_mesh.second;
246 : auto internal_face_normal = unnormalized_face_normal(
247 : mesh, logical_to_grid_map, grid_to_inertial_map, time,
248 : functions_of_time, direction);
249 : std::transform(internal_face_normal.begin(), internal_face_normal.end(),
250 : internal_face_normal.begin(), std::negate<>());
251 : (*normals)[direction] = std::move(internal_face_normal);
252 : }
253 : }
254 :
255 0 : using argument_tags =
256 : tmpl::list<Tags::Interface<dirs, Mesh<VolumeDim - 1>>,
257 : Tags::ElementMap<VolumeDim, Frame::Grid>,
258 : CoordinateMaps::Tags::CoordinateMap<VolumeDim, Frame::Grid,
259 : Frame::Inertial>,
260 : ::Tags::Time, Tags::FunctionsOfTime>;
261 : };
262 :
263 : } // namespace Tags
264 : } // namespace domain
|