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/Prefixes.hpp"
15 : #include "DataStructures/DataBox/Tag.hpp"
16 : #include "DataStructures/DataBox/TagName.hpp"
17 : #include "DataStructures/Variables.hpp"
18 : #include "Utilities/Requires.hpp"
19 : #include "Utilities/TMPL.hpp"
20 : #include "Utilities/TypeTraits/IsA.hpp"
21 :
22 : /// \cond
23 : class DataVector;
24 : class Matrix;
25 : template <size_t Dim>
26 : class Mesh;
27 :
28 : namespace domain {
29 : namespace Tags {
30 : template <size_t Dim>
31 : struct Mesh;
32 : } // namespace Tags
33 : } // namespace domain
34 : namespace Tags {
35 : template <class TagList>
36 : struct Variables;
37 : } // namespace Tags
38 : /// \endcond
39 :
40 : namespace partial_derivatives_detail {
41 : void apply_matrix_in_first_dim(double* result, const double* input,
42 : const Matrix& matrix, size_t size,
43 : bool add_to_result = false);
44 : void apply_matrix_in_first_dim(std::complex<double>* result,
45 : const std::complex<double>* input,
46 : const Matrix& matrix, size_t size,
47 : bool add_to_result = false);
48 :
49 : // Transpose-free differentiation along all logical dimensions using
50 : // fixed-size kernels (dispatched on the extent of the contracted dimension),
51 : // writing the logical derivatives directly without the dgemm+transpose
52 : // pipeline. Returns false when the mesh is not supported (basis other than
53 : // Legendre/Chebyshev, or an extent outside the instantiated kernel range);
54 : // the caller must then fall back to the generic implementation.
55 : bool logical_derivatives_fast_path(const std::array<double*, 1>& logical_derivs,
56 : const double* u,
57 : size_t number_of_independent_components,
58 : const Mesh<1>& mesh);
59 : bool logical_derivatives_fast_path(const std::array<double*, 2>& logical_derivs,
60 : const double* u,
61 : size_t number_of_independent_components,
62 : const Mesh<2>& mesh);
63 : bool logical_derivatives_fast_path(const std::array<double*, 3>& logical_derivs,
64 : const double* u,
65 : size_t number_of_independent_components,
66 : const Mesh<3>& mesh);
67 :
68 : // As above, but additionally contracts with the inverse Jacobian one
69 : // component at a time, so the logical derivatives stay cache-resident and are
70 : // never written to main memory. `du` must have room for
71 : // `Dim * number_of_independent_components` components laid out as
72 : // [component][derivative index][grid points], matching
73 : // `partial_derivatives_impl`. `inverse_jacobian[d * Dim + i]` must point to
74 : // the (logical d, inertial i) component. Returns false when the mesh is not
75 : // supported.
76 : bool fused_partial_derivatives_fast_path(
77 : double* du, const double* u, size_t number_of_independent_components,
78 : const Mesh<1>& mesh, const std::array<const double*, 1>& inverse_jacobian);
79 : bool fused_partial_derivatives_fast_path(
80 : double* du, const double* u, size_t number_of_independent_components,
81 : const Mesh<2>& mesh, const std::array<const double*, 4>& inverse_jacobian);
82 : bool fused_partial_derivatives_fast_path(
83 : double* du, const double* u, size_t number_of_independent_components,
84 : const Mesh<3>& mesh, const std::array<const double*, 9>& inverse_jacobian);
85 : } // namespace partial_derivatives_detail
86 :
87 : /// @{
88 : /// \ingroup NumericalAlgorithmsGroup
89 : /// \brief Compute the partial derivatives of each variable with respect to
90 : /// the element logical coordinate.
91 : ///
92 : /// \requires `DerivativeTags` to be the head of `VariableTags`
93 : ///
94 : /// Returns a `Variables` with a spatial tensor index appended to the front
95 : /// of each tensor within `u` and each `Tag` wrapped with a `Tags::deriv`.
96 : ///
97 : /// \tparam DerivativeTags the subset of `VariableTags` for which derivatives
98 : /// are computed.
99 : template <typename DerivativeTags, typename VariableTags, size_t Dim>
100 1 : void logical_partial_derivatives(
101 : gsl::not_null<std::array<Variables<DerivativeTags>, Dim>*>
102 : logical_partial_derivatives_of_u,
103 : const Variables<VariableTags>& u, const Mesh<Dim>& mesh);
104 :
105 : template <typename DerivativeTags, typename VariableTags, size_t Dim>
106 1 : auto logical_partial_derivatives(const Variables<VariableTags>& u,
107 : const Mesh<Dim>& mesh)
108 : -> std::array<Variables<DerivativeTags>, Dim>;
109 : /// @}
110 :
111 : /// @{
112 : /*!
113 : * \ingroup NumericalAlgorithmsGroup
114 : * \brief Computes the logical partial derivative of a tensor, prepending the
115 : * spatial derivative index, e.g. for \f$\partial_i T_{a}{}^{b}\f$ the C++ call
116 : * is `get(i, a, b)`.
117 : *
118 : * There is an overload that accepts a `buffer` of size
119 : * `mesh.number_of_grid_points()` or larger. When passed this function performs
120 : * no memory allocations, which helps improve performance.
121 : *
122 : * If you have a `Variables` with several tensors you need to differentiate you
123 : * should use the `logical_partial_derivatives` function that operates on
124 : * `Variables` since that'll be more efficient.
125 : */
126 : template <typename DataType, typename SymmList, typename IndexList, size_t Dim>
127 1 : void logical_partial_derivative(
128 : gsl::not_null<TensorMetafunctions::prepend_spatial_index<
129 : Tensor<DataType, SymmList, IndexList>, Dim, UpLo::Lo,
130 : Frame::ElementLogical>*>
131 : logical_derivative_of_u,
132 : gsl::not_null<gsl::span<typename DataType::value_type>*> buffer,
133 : const Tensor<DataType, SymmList, IndexList>& u, const Mesh<Dim>& mesh);
134 :
135 : template <typename DataType, typename SymmList, typename IndexList, size_t Dim>
136 1 : void logical_partial_derivative(
137 : gsl::not_null<TensorMetafunctions::prepend_spatial_index<
138 : Tensor<DataType, SymmList, IndexList>, Dim, UpLo::Lo,
139 : Frame::ElementLogical>*>
140 : logical_derivative_of_u,
141 : const Tensor<DataType, SymmList, IndexList>& u, const Mesh<Dim>& mesh);
142 :
143 : template <typename DataType, typename SymmList, typename IndexList, size_t Dim>
144 1 : auto logical_partial_derivative(const Tensor<DataType, SymmList, IndexList>& u,
145 : const Mesh<Dim>& mesh)
146 : -> TensorMetafunctions::prepend_spatial_index<
147 : Tensor<DataType, SymmList, IndexList>, Dim, UpLo::Lo,
148 : Frame::ElementLogical>;
149 : /// @}
150 :
151 : /// @{
152 : /*!
153 : * \ingroup NumericalAlgorithmsGroup
154 : * \brief Compute the partial derivatives of each variable, using the Cartoon
155 : * method for directions not in the computational domain.
156 : *
157 : * For a spacetime with some Killing vector \f$\xi^a\f$, not only does the
158 : * metric respect the isometry via \f$\mathcal{L}_\xi g_{ab} = 0\f$, but the
159 : * fields must as well.
160 : *
161 : * In the case of axial symmetry about the \f$y\f$-axis, the Killing vector is
162 : * \f$\xi^a = (0, -z, 0, x)\f$, so we have that for a vector \f$V^a\f$,
163 : *
164 : * \f{align*}{
165 : * \mathcal{L}_\xi V^a &= \xi^b \partial_b V^a - V^b \partial_b \xi^a
166 : * = -z \partial_x V^a + x \partial_z V^a - V^b \partial_b \xi^a = 0.
167 : * \f}
168 : *
169 : * Choosing the computational domain to be the \f$z=0\f$ plane, get the result:
170 : *
171 : * \f{align*}{
172 : * \partial_z V^a &= \frac{V^b \partial_b \xi^a}{x}.
173 : * \f}
174 : *
175 : * In the case that $x=0$ is in the computational domain, L'Hôpital's
176 : * rule is used. For a general tensor,
177 : * \f$T^{a_0,\ldots,a_n}{}_{b_0,\ldots,b_m}\f$ we have
178 : *
179 : * \f{align*}{
180 : * \partial_z T^{a_0,\ldots,a_n}{}_{b_0,\ldots,b_m} &=
181 : * \left\{
182 : * \begin{array}{ll}
183 : * \partial_x(\sum_k
184 : * T^{a_0,\ldots,c_k,\ldots,a_n}{}_{b_0,\ldots,b_m}\partial_{c_k}
185 : * \xi^{a_k} & \\
186 : * \;\;\;\;\;-\sum_k
187 : * T^{a_0,\ldots,a_n}{}_{b_0,\ldots,c_k,\ldots,b_m}\partial_{b_k}
188 : * \xi^{c_k}
189 : * ) & \mathrm{if} \; x=0 \\
190 : * (\sum_k
191 : * T^{a_0,\ldots,c_k,\ldots,a_n}{}_{b_0,\ldots,b_m}\partial_{c_k}
192 : * \xi^{a_k} & \\
193 : * \;-\sum_k
194 : * T^{a_0,\ldots,a_n}{}_{b_0,\ldots,c_k,\ldots,b_m}\partial_{b_k}
195 : * \xi^{c_k})\frac{1}{x} & \mathrm{otherwise}
196 : * \end{array}\right.
197 : * \f}
198 : *
199 : * In the case of spherical symmetry, another Killing vector
200 : * \f$\xi'^a = (0, -y, x, 0) \f$ is used as well, with the above equation
201 : * easily generalizing. In that case, the computational domain is only the
202 : * \f$x\f$-axis.
203 : *
204 : * This function computes the partial derivatives of _all_ variables in
205 : * `VariableTags`. The additional parameter `inertial_coords` is used for
206 : * division by the \f$x\f$ coordinates. If \f$x=0\f$ is included in the domain,
207 : * it is assumed to be present only at the first index and is handled by
208 : * L'Hôpital's rule.
209 : *
210 : * The mesh is required to have the Cartoon basis in the last and potentially
211 : * second-to-last coordinates and the inverse Jacobian is accordingly used only
212 : * in the first and potentially second dimensions.
213 : */
214 : template <typename ResultTags, typename VariableTags, size_t Dim,
215 : typename DerivativeFrame, Requires<Dim == 3> = nullptr>
216 1 : void cartoon_partial_derivatives(
217 : gsl::not_null<Variables<ResultTags>*> du, const Variables<VariableTags>& u,
218 : const Mesh<Dim>& mesh,
219 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
220 : DerivativeFrame>& inverse_jacobian_3d,
221 : const tnsr::I<DataVector, Dim, Frame::Inertial>& inertial_coords);
222 : /// @}
223 :
224 : /// @{
225 : /// \ingroup NumericalAlgorithmsGroup
226 : /// \brief Compute the partial derivatives of each variable with respect to
227 : /// the coordinates of `DerivativeFrame`.
228 : ///
229 : /// Either compute partial derivatives of _all_ variables in `VariableTags`, or
230 : /// of a subset of the `VariablesTags`. The subset of tags (`DerivativeTags`)
231 : /// must be the head of `VariablesTags`.
232 : ///
233 : /// The return-by-reference overload infers all template parameters from the
234 : /// arguments. The tensor types in the output buffer must have a spatial index
235 : /// appended to the front.
236 : ///
237 : /// The return-by-value overload requires that the `DerivativeTags` are
238 : /// specified explicitly as the first template parameter. It returns a
239 : /// `Variables` with the `DerivativeTags` wrapped in `Tags::deriv`.
240 : template <typename ResultTags, typename DerivativeTags, size_t Dim,
241 : typename DerivativeFrame>
242 1 : void partial_derivatives(
243 : gsl::not_null<Variables<ResultTags>*> du,
244 : const std::array<Variables<DerivativeTags>, Dim>&
245 : logical_partial_derivatives_of_u,
246 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
247 : DerivativeFrame>& inverse_jacobian);
248 :
249 : template <typename ResultTags, typename VariableTags, size_t Dim,
250 : typename DerivativeFrame>
251 1 : void partial_derivatives(
252 : gsl::not_null<Variables<ResultTags>*> du, const Variables<VariableTags>& u,
253 : const Mesh<Dim>& mesh,
254 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
255 : DerivativeFrame>& inverse_jacobian);
256 :
257 : template <typename DerivativeTags, typename VariableTags, size_t Dim,
258 : typename DerivativeFrame>
259 1 : auto partial_derivatives(
260 : const Variables<VariableTags>& u, const Mesh<Dim>& mesh,
261 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
262 : DerivativeFrame>& inverse_jacobian)
263 : -> Variables<db::wrap_tags_in<Tags::deriv, DerivativeTags,
264 : tmpl::size_t<Dim>, DerivativeFrame>>;
265 : /// @}
266 :
267 : /// @{
268 : /// \ingroup NumericalAlgorithmsGroup
269 : /// \brief Compute the partial derivative of a `Tensor` with respect to
270 : /// the coordinates of `DerivativeFrame`.
271 : ///
272 : /// Returns a `Tensor` with a spatial tensor index appended to the front
273 : /// of the input `Tensor`.
274 : ///
275 : /// If you have a `Variables` with several tensors you need to differentiate,
276 : /// you should use the `partial_derivatives` function that operates on
277 : /// `Variables` since that'll be more efficient.
278 : template <typename DataType, typename SymmList, typename IndexList, size_t Dim,
279 : typename DerivativeFrame>
280 1 : void partial_derivative(
281 : const gsl::not_null<TensorMetafunctions::prepend_spatial_index<
282 : Tensor<DataType, SymmList, IndexList>, Dim, UpLo::Lo, DerivativeFrame>*>
283 : du,
284 : const TensorMetafunctions::prepend_spatial_index<
285 : Tensor<DataType, SymmList, IndexList>, Dim, UpLo::Lo,
286 : Frame::ElementLogical>& logical_partial_derivative_of_u,
287 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
288 : DerivativeFrame>& inverse_jacobian);
289 :
290 : template <typename DataType, typename SymmList, typename IndexList, size_t Dim,
291 : typename DerivativeFrame>
292 1 : void partial_derivative(
293 : const gsl::not_null<TensorMetafunctions::prepend_spatial_index<
294 : Tensor<DataType, SymmList, IndexList>, Dim, UpLo::Lo, DerivativeFrame>*>
295 : du,
296 : const Tensor<DataType, SymmList, IndexList>& u, const Mesh<Dim>& mesh,
297 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
298 : DerivativeFrame>& inverse_jacobian);
299 :
300 : template <typename DataType, typename SymmList, typename IndexList, size_t Dim,
301 : typename DerivativeFrame>
302 1 : auto partial_derivative(
303 : const Tensor<DataType, SymmList, IndexList>& u, const Mesh<Dim>& mesh,
304 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
305 : DerivativeFrame>& inverse_jacobian)
306 : -> TensorMetafunctions::prepend_spatial_index<
307 : Tensor<DataType, SymmList, IndexList>, Dim, UpLo::Lo, DerivativeFrame>;
308 : /// @}
309 :
310 : /// @{
311 : /// \ingroup NumericalAlgorithmsGroup
312 : /// \brief Compute the partial derivative of a `Tensor` with respect to
313 : /// the coordinates of `DerivativeFrame` when a Cartoon basis is being used.
314 : ///
315 : /// Returns a `Tensor` with a spatial tensor index appended to the front
316 : /// of the input `Tensor`.
317 : ///
318 : /// If you have a `Variables` with several tensors with Cartoon bases you need
319 : /// to differentiate, you should use the `cartoon_partial_derivatives` function
320 : /// that operates on `Variables` since that'll be more efficient.
321 : template <typename SymmList, typename IndexList, size_t Dim,
322 : typename DerivativeFrame, Requires<Dim == 3> = nullptr>
323 1 : void cartoon_partial_derivative(
324 : gsl::not_null<TensorMetafunctions::prepend_spatial_index<
325 : Tensor<DataVector, SymmList, IndexList>, Dim, UpLo::Lo,
326 : DerivativeFrame>*>
327 : du,
328 : const Tensor<DataVector, SymmList, IndexList>& u, const Mesh<Dim>& mesh,
329 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
330 : DerivativeFrame>& inverse_jacobian,
331 : const tnsr::I<DataVector, Dim, Frame::Inertial>& inertial_coords);
332 :
333 : template <typename SymmList, typename IndexList, size_t Dim,
334 : typename DerivativeFrame, Requires<Dim == 3> = nullptr>
335 1 : auto cartoon_partial_derivative(
336 : const Tensor<DataVector, SymmList, IndexList>& u, const Mesh<Dim>& mesh,
337 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
338 : DerivativeFrame>& inverse_jacobian,
339 : const tnsr::I<DataVector, Dim, Frame::Inertial>& inertial_coords)
340 : -> TensorMetafunctions::prepend_spatial_index<
341 : Tensor<DataVector, SymmList, IndexList>, Dim, UpLo::Lo,
342 : DerivativeFrame>;
343 : /// @}
344 :
345 : /// @{
346 : /// \ingroup NumericalAlgorithmsGroup
347 : /// \brief Calls the correct partial derivatives function, either normal
348 : /// partials or cartoon partials, as determined by mesh basis.
349 : ///
350 : /// To be used in executables that allow a Cartoon basis, a choice that is
351 : /// only known at runtime.
352 : template <typename ResultTags, typename VariableTags, size_t Dim,
353 : typename DerivativeFrame>
354 1 : void partial_derivatives(
355 : gsl::not_null<Variables<ResultTags>*> du,
356 : const Variables<VariableTags>& u, const Mesh<Dim>& mesh,
357 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
358 : DerivativeFrame>& inverse_jacobian,
359 : const tnsr::I<DataVector, Dim, Frame::Inertial>& inertial_coords);
360 : /// @}
361 :
362 : /// @{
363 : /// \ingroup NumericalAlgorithmsGroup
364 : /// \brief Calls the correct partial derivative function, either normal
365 : /// partial or cartoon partial, as determined by mesh basis.
366 : ///
367 : /// To be used in executables that allow a Cartoon basis, a choice that is
368 : /// only known at runtime.
369 : template <typename SymmList, typename IndexList, size_t Dim,
370 : typename DerivativeFrame>
371 1 : void partial_derivative(
372 : gsl::not_null<TensorMetafunctions::prepend_spatial_index<
373 : Tensor<DataVector, SymmList, IndexList>, Dim, UpLo::Lo,
374 : DerivativeFrame>*>
375 : du,
376 : const Tensor<DataVector, SymmList, IndexList>& u, const Mesh<Dim>& mesh,
377 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
378 : DerivativeFrame>& inverse_jacobian,
379 : const tnsr::I<DataVector, Dim, Frame::Inertial>& inertial_coords);
380 :
381 : template <typename SymmList, typename IndexList, size_t Dim,
382 : typename DerivativeFrame>
383 1 : auto partial_derivative(
384 : const Tensor<DataVector, SymmList, IndexList>& u, const Mesh<Dim>& mesh,
385 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
386 : DerivativeFrame>& inverse_jacobian,
387 : const tnsr::I<DataVector, Dim, Frame::Inertial>& inertial_coords)
388 : -> TensorMetafunctions::prepend_spatial_index<
389 : Tensor<DataVector, SymmList, IndexList>, Dim, UpLo::Lo,
390 : DerivativeFrame>;
391 : /// @}
392 :
393 : namespace Tags {
394 :
395 : /*!
396 : * \ingroup DataBoxTagsGroup
397 : * \brief Compute the spatial derivatives of tags in a Variables
398 : *
399 : * Computes the spatial derivatives of the Tensors in the Variables represented
400 : * by `VariablesTag` in the frame mapped to by `InverseJacobianTag`. To only
401 : * take the derivatives of a subset of these Tensors you can set the
402 : * `DerivTags` template parameter. It takes a `tmpl::list` of the desired
403 : * tags and defaults to the full `tags_list` of the Variables.
404 : *
405 : * For an executable that does not allow a Cartoon basis, the last parameter,
406 : * `InertialCoordsTag`, should not be passed.
407 : *
408 : * This tag may be retrieved via `::Tags::Variables<db::wrap_tags_in<deriv,
409 : * DerivTags, Dim, deriv_frame>`.
410 : */
411 : template <typename VariablesTag, typename MeshTag, typename InverseJacobianTag,
412 : typename DerivTags = typename VariablesTag::type::tags_list,
413 : typename InertialCoordsTag = void>
414 1 : struct DerivCompute
415 : : db::add_tag_prefix<
416 : deriv, ::Tags::Variables<DerivTags>,
417 : tmpl::size_t<
418 : tmpl::back<typename InverseJacobianTag::type::index_list>::dim>,
419 : typename tmpl::back<
420 : typename InverseJacobianTag::type::index_list>::Frame>,
421 : db::ComputeTag {
422 : private:
423 0 : using inv_jac_indices = typename InverseJacobianTag::type::index_list;
424 0 : static constexpr auto Dim = tmpl::back<inv_jac_indices>::dim;
425 0 : using deriv_frame = typename tmpl::back<inv_jac_indices>::Frame;
426 :
427 : public:
428 0 : using base = db::add_tag_prefix<
429 : deriv, ::Tags::Variables<DerivTags>,
430 : tmpl::size_t<
431 : tmpl::back<typename InverseJacobianTag::type::index_list>::dim>,
432 : typename tmpl::back<
433 : typename InverseJacobianTag::type::index_list>::Frame>;
434 0 : using return_type = typename base::type;
435 0 : static constexpr void function(
436 : gsl::not_null<return_type*> du, const typename VariablesTag::type& u,
437 : const Mesh<Dim>& mesh,
438 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
439 : deriv_frame>& inverse_jacobian) {
440 : partial_derivatives(du, u, mesh, inverse_jacobian);
441 : }
442 0 : static constexpr void function(
443 : gsl::not_null<return_type*> du, const typename VariablesTag::type& u,
444 : const Mesh<Dim>& mesh,
445 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
446 : deriv_frame>& inverse_jacobian,
447 : const tnsr::I<DataVector, Dim, Frame::Inertial>& inertial_coords) {
448 : partial_derivatives(du, u, mesh, inverse_jacobian, inertial_coords);
449 : }
450 0 : using argument_tags = tmpl::conditional_t<
451 : std::is_same_v<void, InertialCoordsTag>,
452 : tmpl::list<VariablesTag, MeshTag, InverseJacobianTag>,
453 : tmpl::list<VariablesTag, MeshTag, InverseJacobianTag, InertialCoordsTag>>;
454 : };
455 :
456 : /*!
457 : * \ingroup DataBoxTagsGroup
458 : * \brief Computes the spatial derivative of a single tensor tag not in a
459 : * Variables.
460 : *
461 : * Computes the spatial derivative for a single tensor represented by
462 : * 'TensorTag' in the frame mapped to by 'InverseJacobianTag'. It takes a
463 : * single Tensor designated by 'TensorTag', the inverse Jacobian, and a mesh.
464 : *
465 : * For an executable that does not allow a Cartoon basis, the last parameter,
466 : * `InertialCoordsTag`, should not be passed.
467 : */
468 : template <typename TensorTag, typename InverseJacobianTag, typename MeshTag,
469 : typename InertialCoordsTag = void>
470 1 : struct DerivTensorCompute
471 : : ::Tags::deriv<TensorTag,
472 : tmpl::size_t<tmpl::back<
473 : typename InverseJacobianTag::type::index_list>::dim>,
474 : typename tmpl::back<
475 : typename InverseJacobianTag::type::index_list>::Frame>,
476 : db::ComputeTag {
477 : private:
478 0 : using inv_jac_indices = typename InverseJacobianTag::type::index_list;
479 0 : static constexpr auto Dim = tmpl::back<inv_jac_indices>::dim;
480 0 : using deriv_frame = typename tmpl::back<inv_jac_indices>::Frame;
481 :
482 : public:
483 0 : using base = ::Tags::deriv<TensorTag, tmpl::size_t<Dim>, deriv_frame>;
484 0 : using return_type = typename base::type;
485 0 : static constexpr void function(
486 : const gsl::not_null<return_type*> du, const typename TensorTag::type& u,
487 : const Mesh<Dim>& mesh,
488 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
489 : deriv_frame>& inverse_jacobian) {
490 : partial_derivative(du, u, mesh, inverse_jacobian);
491 : }
492 0 : static constexpr void function(
493 : const gsl::not_null<return_type*> du, const typename TensorTag::type& u,
494 : const Mesh<Dim>& mesh,
495 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
496 : deriv_frame>& inverse_jacobian,
497 : const tnsr::I<DataVector, Dim, Frame::Inertial>& inertial_coords) {
498 : partial_derivative(du, u, mesh, inverse_jacobian, inertial_coords);
499 : }
500 0 : using argument_tags = tmpl::conditional_t<
501 : std::is_same_v<void, InertialCoordsTag>,
502 : tmpl::list<TensorTag, MeshTag, InverseJacobianTag>,
503 : tmpl::list<TensorTag, MeshTag, InverseJacobianTag, InertialCoordsTag>>;
504 : };
505 : } // namespace Tags
|