Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <array>
7 : #include <memory>
8 : #include <string>
9 : #include <type_traits>
10 : #include <unordered_map>
11 :
12 : #include "DataStructures/Tensor/Identity.hpp"
13 : #include "DataStructures/Tensor/Tensor.hpp"
14 : #include "Domain/FunctionsOfTime/FunctionOfTime.hpp"
15 : #include "Utilities/DereferenceWrapper.hpp"
16 : #include "Utilities/ErrorHandling/FloatingPointExceptions.hpp"
17 : #include "Utilities/Gsl.hpp"
18 : #include "Utilities/TypeTraits/RemoveReferenceWrapper.hpp"
19 :
20 : namespace domain {
21 : namespace CoordinateMap_detail {
22 : /// @{
23 : /// Call the map passing in the time and FunctionsOfTime if the map is
24 : /// time-dependent
25 : template <typename T, size_t Dim, typename Map>
26 : void apply_map(
27 : const gsl::not_null<std::array<T, Dim>*> t_map_point, const Map& the_map,
28 : const double /*t*/,
29 : const std::unordered_map<
30 : std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
31 : /*functions_of_time*/,
32 : const std::false_type /*is_time_independent*/) {
33 : if (LIKELY(not the_map.is_identity())) {
34 : *t_map_point = the_map(*t_map_point);
35 : }
36 : }
37 :
38 : template <typename T, size_t Dim, typename Map>
39 : void apply_map(
40 : const gsl::not_null<std::array<T, Dim>*> t_map_point, const Map& the_map,
41 : const double t,
42 : const std::unordered_map<
43 : std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
44 : functions_of_time,
45 : const std::true_type
46 : /*is_time_dependent*/) {
47 : ASSERT(not functions_of_time.empty(),
48 : "A function of time must be present if the maps are time-dependent.");
49 : ASSERT(
50 : [t]() {
51 : const ScopedFpeState disable_fpes(false);
52 : return not std::isnan(t);
53 : }(),
54 : "The time must not be NaN for time-dependent maps.");
55 : *t_map_point = the_map(*t_map_point, t, functions_of_time);
56 : }
57 :
58 : template <typename T, size_t Dim, typename Map>
59 : auto apply_map(
60 : const Map& the_map, const std::array<T, Dim>& source_points,
61 : const double /*t*/,
62 : const std::unordered_map<
63 : std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
64 : /*functions_of_time*/,
65 : const std::false_type /*is_time_independent*/) {
66 : if (LIKELY(not the_map.is_identity())) {
67 : return the_map(source_points);
68 : }
69 : std::decay_t<decltype(the_map(source_points))> result{};
70 : for (size_t i = 0; i < result.size(); ++i) {
71 : gsl::at(result, i) = gsl::at(source_points, i);
72 : }
73 : return result;
74 : }
75 :
76 : template <typename T, size_t Dim, typename Map>
77 : auto apply_map(
78 : const Map& the_map, const std::array<T, Dim>& source_points, const double t,
79 : const std::unordered_map<
80 : std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
81 : functions_of_time,
82 : const std::true_type
83 : /*is_time_dependent*/) {
84 : // Note: We don't forward to the return-by-not-null version to avoid
85 : // additional allocations of the target points array. That is, we would
86 : // allocate the target points array once here, and then again inside the call
87 : // to the coordinate map.
88 : ASSERT(not functions_of_time.empty(),
89 : "A function of time must be present if the maps are time-dependent.");
90 : ASSERT(
91 : [t]() {
92 : const ScopedFpeState disable_fpes(false);
93 : return not std::isnan(t);
94 : }(),
95 : "The time must not be NaN for time-dependent maps.");
96 : return the_map(source_points, t, functions_of_time);
97 : }
98 : /// @}
99 :
100 : /// @{
101 : template <typename T, size_t Dim, typename Map>
102 : auto apply_inverse_map(
103 : const Map& the_map, const std::array<T, Dim>& target_points,
104 : const double /*t*/,
105 : const std::unordered_map<
106 : std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
107 : /*functions_of_time*/,
108 : const std::false_type /*is_time_independent*/) {
109 : if (LIKELY(not the_map.is_identity())) {
110 : return the_map.inverse(target_points);
111 : }
112 : using UnwrappedT = tt::remove_cvref_wrap_t<T>;
113 : std::decay_t<decltype(the_map.inverse(target_points))> result{
114 : std::array<UnwrappedT, Dim>{}};
115 : for (size_t i = 0; i < target_points.size(); ++i) {
116 : gsl::at(*result, i) = gsl::at(target_points, i);
117 : }
118 : return result;
119 : }
120 :
121 : template <typename T, size_t Dim, typename Map>
122 : auto apply_inverse_map(
123 : const Map& the_map, const std::array<T, Dim>& target_points, const double t,
124 : const std::unordered_map<
125 : std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
126 : functions_of_time,
127 : const std::true_type
128 : /*is_time_dependent*/) {
129 : ASSERT(not functions_of_time.empty(),
130 : "A function of time must be present if the maps are time-dependent.");
131 : ASSERT(
132 : [t]() {
133 : const ScopedFpeState disable_fpes(false);
134 : return not std::isnan(t);
135 : }(),
136 : "The time must not be NaN for time-dependent maps.");
137 : return the_map.inverse(target_points, t, functions_of_time);
138 : }
139 : /// @}
140 :
141 : /// @{
142 : /// Compute the frame velocity
143 : template <typename T, size_t Dim, typename Map>
144 : auto apply_frame_velocity(
145 : const Map& /*the_map*/, const std::array<T, Dim>& source_points,
146 : const double /*t*/,
147 : const std::unordered_map<
148 : std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
149 : /*functions_of_time*/,
150 : const std::false_type /*is_time_independent*/) {
151 : return make_array<Map::dim, tt::remove_cvref_wrap_t<T>>(
152 : make_with_value<tt::remove_cvref_wrap_t<T>>(
153 : dereference_wrapper(source_points[0]), 0.0));
154 : }
155 :
156 : template <typename T, size_t Dim, typename Map>
157 : auto apply_frame_velocity(
158 : const Map& the_map, const std::array<T, Dim>& source_points, const double t,
159 : const std::unordered_map<
160 : std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
161 : functions_of_time,
162 : const std::true_type
163 : /*is_time_dependent*/) {
164 : ASSERT(not functions_of_time.empty(),
165 : "A function of time must be present if the maps are time-dependent.");
166 : ASSERT(
167 : [t]() {
168 : const ScopedFpeState disable_fpes(false);
169 : return not std::isnan(t);
170 : }(),
171 : "The time must not be NaN for time-dependent maps.");
172 : return the_map.frame_velocity(source_points, t, functions_of_time);
173 : }
174 : /// @}
175 :
176 : /// @{
177 : /// Compute the Jacobian
178 : template <typename T, size_t Dim, typename Map>
179 : auto apply_jacobian(
180 : const Map& the_map, const std::array<T, Dim>& source_points,
181 : const double /*t*/,
182 : const std::unordered_map<
183 : std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
184 : /*functions_of_time*/,
185 : const std::false_type /*is_time_independent*/) {
186 : if (LIKELY(not the_map.is_identity())) {
187 : return the_map.jacobian(source_points);
188 : }
189 : return identity<Dim>(dereference_wrapper(source_points[0]));
190 : }
191 :
192 : template <typename T, size_t Dim, typename Map>
193 : auto apply_jacobian(
194 : const Map& the_map, const std::array<T, Dim>& source_points, const double t,
195 : const std::unordered_map<
196 : std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
197 : functions_of_time,
198 : const std::true_type
199 : /*is_time_dependent*/) {
200 : ASSERT(not functions_of_time.empty(),
201 : "A function of time must be present if the maps are time-dependent.");
202 : ASSERT(
203 : [t]() {
204 : const ScopedFpeState disable_fpes(false);
205 : return not std::isnan(t);
206 : }(),
207 : "The time must not be NaN for time-dependent maps.");
208 : if (LIKELY(not the_map.is_identity())) {
209 : return the_map.jacobian(source_points, t, functions_of_time);
210 : }
211 : return identity<Dim>(dereference_wrapper(source_points[0]));
212 : }
213 : /// @}
214 :
215 : /// @{
216 : /// Compute the Jacobian
217 : template <typename T, size_t Dim, typename Map>
218 : auto apply_inverse_jacobian(
219 : const Map& the_map, const std::array<T, Dim>& source_points,
220 : const double /*t*/,
221 : const std::unordered_map<
222 : std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
223 : /*functions_of_time*/,
224 : const std::false_type /*is_time_independent*/) {
225 : if (LIKELY(not the_map.is_identity())) {
226 : return the_map.inv_jacobian(source_points);
227 : }
228 : return identity<Dim>(dereference_wrapper(source_points[0]));
229 : }
230 :
231 : template <typename T, size_t Dim, typename Map>
232 : auto apply_inverse_jacobian(
233 : const Map& the_map, const std::array<T, Dim>& source_points, const double t,
234 : const std::unordered_map<
235 : std::string, std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
236 : functions_of_time,
237 : const std::true_type
238 : /*is_time_dependent*/) {
239 : ASSERT(not functions_of_time.empty(),
240 : "A function of time must be present if the maps are time-dependent.");
241 : ASSERT(
242 : [t]() {
243 : const ScopedFpeState disable_fpes(false);
244 : return not std::isnan(t);
245 : }(),
246 : "The time must not be NaN for time-dependent maps.");
247 : if (LIKELY(not the_map.is_identity())) {
248 : return the_map.inv_jacobian(source_points, t, functions_of_time);
249 : }
250 : return identity<Dim>(dereference_wrapper(source_points[0]));
251 : }
252 : /// @}
253 : } // namespace CoordinateMap_detail
254 : } // namespace domain
|