Line data Source code
1 1 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : /// \file
5 : /// Defines functions computing partial derivatives.
6 :
7 : #pragma once
8 :
9 : #include <array>
10 : #include <cstddef>
11 : #include <string>
12 :
13 : #include "DataStructures/DataBox/PrefixHelpers.hpp"
14 : #include "DataStructures/DataBox/Tag.hpp"
15 : #include "DataStructures/DataBox/TagName.hpp"
16 : #include "DataStructures/Variables.hpp"
17 : #include "Utilities/Requires.hpp"
18 : #include "Utilities/TMPL.hpp"
19 : #include "Utilities/TypeTraits/IsA.hpp"
20 :
21 : /// \cond
22 : class DataVector;
23 : template <size_t Dim>
24 : class Mesh;
25 :
26 : namespace domain {
27 : namespace Tags {
28 : template <size_t Dim>
29 : struct Mesh;
30 : } // namespace Tags
31 : } // namespace domain
32 : namespace Tags {
33 : template <class TagList>
34 : struct Variables;
35 : } // namespace Tags
36 : /// \endcond
37 :
38 : namespace Tags {
39 : /*!
40 : * \ingroup DataBoxTagsGroup
41 : * \brief Prefix indicating spatial derivatives
42 : *
43 : * Prefix indicating the spatial derivatives of a Tensor.
44 : *
45 : * \tparam Tag The tag to wrap
46 : * \tparam Dim The volume dim as a type (e.g. `tmpl::size_t<Dim>`)
47 : * \tparam Frame The frame of the derivative index
48 : *
49 : * \see Tags::DerivCompute
50 : */
51 : template <typename Tag, typename Dim, typename Frame, typename = std::nullptr_t>
52 1 : struct deriv;
53 :
54 : template <typename Tag, typename Dim, typename Frame>
55 0 : struct deriv<Tag, Dim, Frame, Requires<tt::is_a_v<Tensor, typename Tag::type>>>
56 : : db::PrefixTag, db::SimpleTag {
57 0 : using type =
58 : TensorMetafunctions::prepend_spatial_index<typename Tag::type, Dim::value,
59 : UpLo::Lo, Frame>;
60 0 : using tag = Tag;
61 : };
62 :
63 : /*!
64 : * \ingroup DataBoxTagsGroup
65 : * \brief Prefix indicating spacetime derivatives
66 : *
67 : * Prefix indicating the spacetime derivatives of a Tensor or that a Variables
68 : * contains spatial derivatives of Tensors.
69 : *
70 : * \tparam Tag The tag to wrap
71 : * \tparam Dim The volume dim as a type (e.g. `tmpl::size_t<Dim>`)
72 : * \tparam Frame The frame of the derivative index
73 : */
74 : template <typename Tag, typename Dim, typename Frame, typename = std::nullptr_t>
75 1 : struct spacetime_deriv;
76 :
77 : template <typename Tag, typename Dim, typename Frame>
78 0 : struct spacetime_deriv<Tag, Dim, Frame,
79 : Requires<tt::is_a_v<Tensor, typename Tag::type>>>
80 : : db::PrefixTag, db::SimpleTag {
81 0 : using type =
82 : TensorMetafunctions::prepend_spacetime_index<typename Tag::type,
83 : Dim::value, UpLo::Lo, Frame>;
84 0 : using tag = Tag;
85 : };
86 :
87 : } // namespace Tags
88 :
89 : /// @{
90 : /// \ingroup NumericalAlgorithmsGroup
91 : /// \brief Compute the partial derivatives of each variable with respect to
92 : /// the element logical coordinate.
93 : ///
94 : /// \requires `DerivativeTags` to be the head of `VariableTags`
95 : ///
96 : /// Returns a `Variables` with a spatial tensor index appended to the front
97 : /// of each tensor within `u` and each `Tag` wrapped with a `Tags::deriv`.
98 : ///
99 : /// \tparam DerivativeTags the subset of `VariableTags` for which derivatives
100 : /// are computed.
101 : template <typename DerivativeTags, typename VariableTags, size_t Dim>
102 1 : void logical_partial_derivatives(
103 : gsl::not_null<std::array<Variables<DerivativeTags>, Dim>*>
104 : logical_partial_derivatives_of_u,
105 : const Variables<VariableTags>& u, const Mesh<Dim>& mesh);
106 :
107 : template <typename DerivativeTags, typename VariableTags, size_t Dim>
108 1 : auto logical_partial_derivatives(const Variables<VariableTags>& u,
109 : const Mesh<Dim>& mesh)
110 : -> std::array<Variables<DerivativeTags>, Dim>;
111 : /// @}
112 :
113 : /// @{
114 : /*!
115 : * \ingroup NumericalAlgorithmsGroup
116 : * \brief Computes the logical partial derivative of a tensor, prepending the
117 : * spatial derivative index, e.g. for \f$\partial_i T_{a}{}^{b}\f$ the C++ call
118 : * is `get(i, a, b)`.
119 : *
120 : * There is an overload that accepts a `buffer` of size
121 : * `mesh.number_of_grid_points()` or larger. When passed this function performs
122 : * no memory allocations, which helps improve performance.
123 : *
124 : * If you have a `Variables` with several tensors you need to differentiate you
125 : * should use the `logical_partial_derivatives` function that operates on
126 : * `Variables` since that'll be more efficient.
127 : */
128 : template <typename SymmList, typename IndexList, size_t Dim>
129 1 : void logical_partial_derivative(
130 : gsl::not_null<TensorMetafunctions::prepend_spatial_index<
131 : Tensor<DataVector, SymmList, IndexList>, Dim, UpLo::Lo,
132 : Frame::ElementLogical>*>
133 : logical_derivative_of_u,
134 : gsl::not_null<gsl::span<double>*> buffer,
135 : const Tensor<DataVector, SymmList, IndexList>& u, const Mesh<Dim>& mesh);
136 :
137 : template <typename SymmList, typename IndexList, size_t Dim>
138 1 : void logical_partial_derivative(
139 : gsl::not_null<TensorMetafunctions::prepend_spatial_index<
140 : Tensor<DataVector, SymmList, IndexList>, Dim, UpLo::Lo,
141 : Frame::ElementLogical>*>
142 : logical_derivative_of_u,
143 : const Tensor<DataVector, SymmList, IndexList>& u, const Mesh<Dim>& mesh);
144 :
145 : template <typename SymmList, typename IndexList, size_t Dim>
146 1 : auto logical_partial_derivative(
147 : const Tensor<DataVector, SymmList, IndexList>& u, const Mesh<Dim>& mesh)
148 : -> TensorMetafunctions::prepend_spatial_index<
149 : Tensor<DataVector, SymmList, IndexList>, Dim, UpLo::Lo,
150 : Frame::ElementLogical>;
151 : /// @}
152 :
153 : /// @{
154 : /// \ingroup NumericalAlgorithmsGroup
155 : /// \brief Compute the partial derivatives of each variable with respect to
156 : /// the coordinates of `DerivativeFrame`.
157 : ///
158 : /// Either compute partial derivatives of _all_ variables in `VariableTags`, or
159 : /// of a subset of the `VariablesTags`. The subset of tags (`DerivativeTags`)
160 : /// must be the head of `VariablesTags`.
161 : ///
162 : /// The return-by-reference overload infers all template parameters from the
163 : /// arguments. The tensor types in the output buffer must have a spatial index
164 : /// appended to the front.
165 : ///
166 : /// The return-by-value overload requires that the `DerivativeTags` are
167 : /// specified explicitly as the first template parameter. It returns a
168 : /// `Variables` with the `DerivativeTags` wrapped in `Tags::deriv`.
169 : template <typename ResultTags, typename DerivativeTags, size_t Dim,
170 : typename DerivativeFrame>
171 1 : void partial_derivatives(
172 : gsl::not_null<Variables<ResultTags>*> du,
173 : const std::array<Variables<DerivativeTags>, Dim>&
174 : logical_partial_derivatives_of_u,
175 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
176 : DerivativeFrame>& inverse_jacobian);
177 :
178 : template <typename ResultTags, typename VariableTags, size_t Dim,
179 : typename DerivativeFrame>
180 1 : void partial_derivatives(
181 : gsl::not_null<Variables<ResultTags>*> du, const Variables<VariableTags>& u,
182 : const Mesh<Dim>& mesh,
183 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
184 : DerivativeFrame>& inverse_jacobian);
185 :
186 : template <typename DerivativeTags, typename VariableTags, size_t Dim,
187 : typename DerivativeFrame>
188 1 : auto partial_derivatives(
189 : const Variables<VariableTags>& u, const Mesh<Dim>& mesh,
190 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
191 : DerivativeFrame>& inverse_jacobian)
192 : -> Variables<db::wrap_tags_in<Tags::deriv, DerivativeTags,
193 : tmpl::size_t<Dim>, DerivativeFrame>>;
194 : /// @}
195 :
196 : /// @{
197 : /// \ingroup NumericalAlgorithmsGroup
198 : /// \brief Compute the partial derivative of a `Tensor` with respect to
199 : /// the coordinates of `DerivativeFrame`.
200 : ///
201 : /// Returns a `Tensor` with a spatial tensor index appended to the front
202 : /// of the input `Tensor`.
203 : ///
204 : /// If you have a `Variables` with several tensors you need to differentiate,
205 : /// you should use the `partial_derivatives` function that operates on
206 : /// `Variables` since that'll be more efficient.
207 : template <typename SymmList, typename IndexList, size_t Dim,
208 : typename DerivativeFrame>
209 1 : void partial_derivative(
210 : const gsl::not_null<TensorMetafunctions::prepend_spatial_index<
211 : Tensor<DataVector, SymmList, IndexList>, Dim, UpLo::Lo,
212 : DerivativeFrame>*>
213 : du,
214 : const TensorMetafunctions::prepend_spatial_index<
215 : Tensor<DataVector, SymmList, IndexList>, Dim, UpLo::Lo,
216 : Frame::ElementLogical>& logical_partial_derivative_of_u,
217 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
218 : DerivativeFrame>& inverse_jacobian);
219 :
220 : template <typename SymmList, typename IndexList, size_t Dim,
221 : typename DerivativeFrame>
222 1 : void partial_derivative(
223 : const gsl::not_null<TensorMetafunctions::prepend_spatial_index<
224 : Tensor<DataVector, SymmList, IndexList>, Dim, UpLo::Lo,
225 : DerivativeFrame>*>
226 : du,
227 : const Tensor<DataVector, SymmList, IndexList>& u, const Mesh<Dim>& mesh,
228 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
229 : DerivativeFrame>& inverse_jacobian);
230 :
231 : template <typename SymmList, typename IndexList, size_t Dim,
232 : typename DerivativeFrame>
233 1 : auto partial_derivative(
234 : const Tensor<DataVector, SymmList, IndexList>& u, const Mesh<Dim>& mesh,
235 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
236 : DerivativeFrame>& inverse_jacobian)
237 : -> TensorMetafunctions::prepend_spatial_index<
238 : Tensor<DataVector, SymmList, IndexList>, Dim, UpLo::Lo,
239 : DerivativeFrame>;
240 : /// @}
241 :
242 : namespace Tags {
243 :
244 : /*!
245 : * \ingroup DataBoxTagsGroup
246 : * \brief Compute the spatial derivatives of tags in a Variables
247 : *
248 : * Computes the spatial derivatives of the Tensors in the Variables represented
249 : * by `VariablesTag` in the frame mapped to by `InverseJacobianTag`. To only
250 : * take the derivatives of a subset of these Tensors you can set the
251 : * `DerivTags` template parameter. It takes a `tmpl::list` of the desired
252 : * tags and defaults to the full `tags_list` of the Variables.
253 : *
254 : * This tag may be retrieved via `::Tags::Variables<db::wrap_tags_in<deriv,
255 : * DerivTags, Dim, deriv_frame>`.
256 : */
257 : template <typename VariablesTag, typename MeshTag, typename InverseJacobianTag,
258 : typename DerivTags = typename VariablesTag::type::tags_list>
259 1 : struct DerivCompute
260 : : db::add_tag_prefix<
261 : deriv, ::Tags::Variables<DerivTags>,
262 : tmpl::size_t<
263 : tmpl::back<typename InverseJacobianTag::type::index_list>::dim>,
264 : typename tmpl::back<
265 : typename InverseJacobianTag::type::index_list>::Frame>,
266 : db::ComputeTag {
267 : private:
268 0 : using inv_jac_indices = typename InverseJacobianTag::type::index_list;
269 0 : static constexpr auto Dim = tmpl::back<inv_jac_indices>::dim;
270 0 : using deriv_frame = typename tmpl::back<inv_jac_indices>::Frame;
271 :
272 : public:
273 0 : using base = db::add_tag_prefix<
274 : deriv, ::Tags::Variables<DerivTags>,
275 : tmpl::size_t<
276 : tmpl::back<typename InverseJacobianTag::type::index_list>::dim>,
277 : typename tmpl::back<
278 : typename InverseJacobianTag::type::index_list>::Frame>;
279 0 : using return_type = typename base::type;
280 0 : static constexpr void (*function)(
281 : gsl::not_null<return_type*>, const typename VariablesTag::type&,
282 : const Mesh<Dim>&,
283 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
284 : deriv_frame>&) =
285 : partial_derivatives<typename return_type::tags_list,
286 : typename VariablesTag::type::tags_list, Dim,
287 : deriv_frame>;
288 0 : using argument_tags = tmpl::list<VariablesTag, MeshTag, InverseJacobianTag>;
289 : };
290 :
291 : /*!
292 : * \ingroup DataBoxTagsGroup
293 : * \brief Computes the spatial derivative of a single tensor tag not in a
294 : * Variables.
295 : *
296 : * Computes the spatial derivative for a single tensor represented by
297 : * 'TensorTag' in the frame mapped to by 'InverseJacobianTag'. It takes a
298 : * single Tensor designated by 'TensorTag', the inverse Jacobian, and a mesh.
299 : */
300 : template <typename TensorTag, typename InverseJacobianTag, typename MeshTag>
301 1 : struct DerivTensorCompute
302 : : ::Tags::deriv<TensorTag,
303 : tmpl::size_t<tmpl::back<
304 : typename InverseJacobianTag::type::index_list>::dim>,
305 : typename tmpl::back<
306 : typename InverseJacobianTag::type::index_list>::Frame>,
307 : db::ComputeTag {
308 : private:
309 0 : using inv_jac_indices = typename InverseJacobianTag::type::index_list;
310 0 : static constexpr auto Dim = tmpl::back<inv_jac_indices>::dim;
311 0 : using deriv_frame = typename tmpl::back<inv_jac_indices>::Frame;
312 :
313 : public:
314 0 : using base = ::Tags::deriv<TensorTag, tmpl::size_t<Dim>, deriv_frame>;
315 0 : using return_type = typename base::type;
316 0 : static constexpr void (*function)(
317 : gsl::not_null<return_type*>, const typename TensorTag::type&,
318 : const Mesh<Dim>&,
319 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
320 : deriv_frame>&) =
321 : partial_derivative<typename TensorTag::type::symmetry,
322 : typename TensorTag::type::index_list, Dim,
323 : deriv_frame>;
324 0 : using argument_tags =
325 : tmpl::list<TensorTag, domain::Tags::Mesh<Dim>, InverseJacobianTag>;
326 : };
327 : } // namespace Tags
|