SpECTRE Documentation Coverage Report
Current view: top level - NumericalAlgorithms/SpinWeightedSphericalHarmonics - SwshDerivatives.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 80.0 % 5 4
Test Date: 2026-10-22 17:29:42
Legend: Lines:     hit not hit

            Line data    Source code
       1            0 : // Distributed under the MIT License.
       2              : // See LICENSE.txt for details.
       3              : 
       4              : #pragma once
       5              : 
       6              : #include <complex>
       7              : #include <cstddef>
       8              : 
       9              : #include "DataStructures/ComplexDataVector.hpp"
      10              : #include "DataStructures/ComplexDiagonalModalOperator.hpp"
      11              : #include "DataStructures/ComplexModalVector.hpp"
      12              : #include "DataStructures/DataVector.hpp"
      13              : #include "DataStructures/SpinWeighted.hpp"
      14              : #include "DataStructures/Tags/TempTensor.hpp"
      15              : #include "DataStructures/TempBuffer.hpp"
      16              : #include "NumericalAlgorithms/SpinWeightedSphericalHarmonics/ComplexDataView.hpp"
      17              : #include "NumericalAlgorithms/SpinWeightedSphericalHarmonics/SwshCoefficients.hpp"
      18              : #include "NumericalAlgorithms/SpinWeightedSphericalHarmonics/SwshCollocation.hpp"
      19              : #include "NumericalAlgorithms/SpinWeightedSphericalHarmonics/SwshSettings.hpp"
      20              : #include "NumericalAlgorithms/SpinWeightedSphericalHarmonics/SwshTags.hpp"
      21              : #include "NumericalAlgorithms/SpinWeightedSphericalHarmonics/SwshTransform.hpp"
      22              : #include "Utilities/ForceInline.hpp"
      23              : #include "Utilities/Gsl.hpp"
      24              : #include "Utilities/TMPL.hpp"
      25              : 
      26              : namespace Spectral {
      27              : namespace Swsh {
      28              : namespace detail {
      29              : 
      30              : // Factors that appear in the modal representation of spin-weighted angular
      31              : // derivatives, needed for compute_coefficients_of_derivative
      32              : template <typename DerivativeKind>
      33              : SPECTRE_ALWAYS_INLINE std::complex<double> derivative_factor(int l, int s);
      34              : 
      35              : template <>
      36              : SPECTRE_ALWAYS_INLINE std::complex<double> derivative_factor<Tags::Eth>(
      37              :     const int l, const int s) {
      38              :   return sqrt(static_cast<std::complex<double>>((l - s) * (l + s + 1)));
      39              : }
      40              : 
      41              : template <>
      42              : SPECTRE_ALWAYS_INLINE std::complex<double> derivative_factor<Tags::Ethbar>(
      43              :     const int l, const int s) {
      44              :   return -sqrt(static_cast<std::complex<double>>((l + s) * (l - s + 1)));
      45              : }
      46              : 
      47              : template <>
      48              : SPECTRE_ALWAYS_INLINE std::complex<double> derivative_factor<Tags::EthEth>(
      49              :     const int l, const int s) {
      50              :   return sqrt(static_cast<std::complex<double>>((l - s - 1) * (l + s + 2) *
      51              :                                                 (l - s) * (l + s + 1)));
      52              : }
      53              : 
      54              : template <>
      55              : SPECTRE_ALWAYS_INLINE std::complex<double>
      56              : derivative_factor<Tags::EthbarEthbar>(const int l, const int s) {
      57              :   return sqrt(static_cast<std::complex<double>>((l + s - 1) * (l - s + 2) *
      58              :                                                 (l + s) * (l - s + 1)));
      59              : }
      60              : 
      61              : template <>
      62              : SPECTRE_ALWAYS_INLINE std::complex<double> derivative_factor<Tags::EthbarEth>(
      63              :     const int l, const int s) {
      64              :   return static_cast<std::complex<double>>(-(l - s) * (l + s + 1));
      65              : }
      66              : 
      67              : template <>
      68              : SPECTRE_ALWAYS_INLINE std::complex<double> derivative_factor<Tags::EthEthbar>(
      69              :     const int l, const int s) {
      70              :   return static_cast<std::complex<double>>(-(l + s) * (l - s + 1));
      71              : }
      72              : 
      73              : template <>
      74              : SPECTRE_ALWAYS_INLINE std::complex<double> derivative_factor<Tags::InverseEth>(
      75              :     const int l, const int s) {
      76              :   return (l - s + 1) * (l + s) == 0
      77              :              ? 0.0
      78              :              : 1.0 / sqrt(static_cast<std::complex<double>>((l - s + 1) *
      79              :                                                             (l + s)));
      80              : }
      81              : 
      82              : template <>
      83              : SPECTRE_ALWAYS_INLINE std::complex<double>
      84              : derivative_factor<Tags::InverseEthbar>(const int l, const int s) {
      85              :   return (l + s + 1) * (l - s) == 0
      86              :              ? 0.0
      87              :              : 1.0 / -sqrt(static_cast<std::complex<double>>((l + s + 1) *
      88              :                                                              (l - s)));
      89              : }
      90              : 
      91              : // For a particular derivative represented by `DerivativeKind` and input spin
      92              : // `Spin`, multiplies the derivative spectral factors with
      93              : // `pre_derivative_modes`, returning by pointer via parameter `derivative_modes`
      94              : template <typename DerivativeKind, int Spin>
      95              : void compute_coefficients_of_derivative(
      96              :     gsl::not_null<
      97              :         SpinWeighted<ComplexModalVector,
      98              :                      Spin + Tags::derivative_spin_weight<DerivativeKind>>*>
      99              :         derivative_modes,
     100              :     gsl::not_null<SpinWeighted<ComplexModalVector, Spin>*> pre_derivative_modes,
     101              :     size_t l_max, size_t number_of_radial_points);
     102              : 
     103              : // Helper function for dealing with the parameter packs in the utilities which
     104              : // evaluate several spin-weighted derivatives at once. The `apply` function of
     105              : // this struct locates the appropriate mode buffer in the input tuple
     106              : // `pre_derivative_mode_tuple`, and calls `compute_coefficients_of_derivative`,
     107              : // deriving the coefficients for `DerivativeTag` and returning by pointer.
     108              : template <typename DerivativeTag, typename PreDerivativeTagList>
     109              : struct dispatch_to_compute_coefficients_of_derivative {
     110              :   template <int Spin, typename... ModalTypes>
     111              :   static void apply(const gsl::not_null<SpinWeighted<ComplexModalVector, Spin>*>
     112              :                         derivative_modes,
     113              :                     const std::tuple<ModalTypes...>& pre_derivative_mode_tuple,
     114              :                     const size_t l_max, const size_t number_of_radial_points) {
     115              :     compute_coefficients_of_derivative<typename DerivativeTag::derivative_kind>(
     116              :         derivative_modes,
     117              :         get<tmpl::index_of<PreDerivativeTagList,
     118              :                            typename DerivativeTag::derivative_of>::value>(
     119              :             pre_derivative_mode_tuple),
     120              :         l_max, number_of_radial_points);
     121              :   }
     122              : };
     123              : 
     124              : // Helper function for dealing with the parameter packs in the utilities which
     125              : // evaluate several spin-weighted derivatives at once. The `apply` function of
     126              : // this struct locates the like-spin set of paired modes and nodes, and calls
     127              : // the member function of `SwshTransform` or `InverseSwshTransform` to perform
     128              : // the spin-weighted transform. This function is a friend of both
     129              : // `SwshTransform` and `InverseSwshTransform` to gain access to the private
     130              : // `apply_to_vectors`.
     131              : // The calling code will pass as tuples a superset of the quantities to be
     132              : // transformed, in the same order as the tags provided to `TagList`. The
     133              : // `modal_tuple` must be the storage destinations of the transforms in the
     134              : // same order as the `nodal_tuple`. The set of nodal tags to be transformed are
     135              : // the `TransformTags...` determined by the `SwshTransform` or
     136              : // `InverseSwshTransform`. The reason for using `tuple`s rather than
     137              : // `TaggedTuple`s or similar is to pass around spin-weighted vectors directly,
     138              : // rather than `Scalar`s, which allows for more condensed forwarding code.
     139              : template <typename Transform, typename TagList>
     140              : struct dispatch_to_transform;
     141              : 
     142              : template <ComplexRepresentation Representation, typename... TransformTags,
     143              :           typename TagList>
     144              : struct dispatch_to_transform<
     145              :     SwshTransform<tmpl::list<TransformTags...>, Representation>, TagList> {
     146              :   template <typename... ModalTypes, typename... NodalTypes>
     147              :   static void apply(const gsl::not_null<std::tuple<ModalTypes...>*> modal_tuple,
     148              :                     const std::tuple<NodalTypes...>& nodal_tuple,
     149              :                     const size_t l_max, const size_t number_of_radial_points) {
     150              :     SwshTransform<tmpl::list<TransformTags...>, Representation>::
     151              :         apply_to_vectors(
     152              :             get<tmpl::index_of<TagList, TransformTags>::value>(*modal_tuple)...,
     153              :             get<tmpl::index_of<TagList, TransformTags>::value>(nodal_tuple)...,
     154              :             l_max, number_of_radial_points);
     155              :   }
     156              : };
     157              : 
     158              : template <ComplexRepresentation Representation, typename... TransformTags,
     159              :           typename TagList>
     160              : struct dispatch_to_transform<
     161              :     InverseSwshTransform<tmpl::list<TransformTags...>, Representation>,
     162              :     TagList> {
     163              :   template <typename... NodalTypes, typename... ModalTypes>
     164              :   static void apply(const gsl::not_null<std::tuple<NodalTypes...>*> nodal_tuple,
     165              :                     const std::tuple<ModalTypes...>& modal_tuple,
     166              :                     const size_t l_max, const size_t number_of_radial_points) {
     167              :     InverseSwshTransform<tmpl::list<TransformTags...>, Representation>::
     168              :         apply_to_vectors(
     169              :             get<tmpl::index_of<TagList, TransformTags>::value>(*nodal_tuple)...,
     170              :             *get<tmpl::index_of<TagList, TransformTags>::value>(modal_tuple)...,
     171              :             l_max, number_of_radial_points);
     172              :   }
     173              : };
     174              : 
     175              : // template 'implementation' for the DataBox mutate-compatible interface to
     176              : // spin-weighted derivative evaluation. This impl version is needed to have easy
     177              : // access to the `UniqueDifferentiatedFromTagList` as a parameter pack
     178              : template <typename DerivativeTagList, typename UniqueDifferentiatedFromTagList,
     179              :           ComplexRepresentation Representation>
     180              : struct AngularDerivativesImpl;
     181              : 
     182              : template <typename... DerivativeTags, typename... UniqueDifferentiatedFromTags,
     183              :           ComplexRepresentation Representation>
     184              : struct AngularDerivativesImpl<tmpl::list<DerivativeTags...>,
     185              :                               tmpl::list<UniqueDifferentiatedFromTags...>,
     186              :                               Representation> {
     187              :   using return_tags =
     188              :       tmpl::list<DerivativeTags..., Tags::SwshTransform<DerivativeTags>...,
     189              :                  Tags::SwshTransform<UniqueDifferentiatedFromTags>...>;
     190              :   using argument_tags = tmpl::list<UniqueDifferentiatedFromTags..., Tags::LMax,
     191              :                                    Tags::NumberOfRadialPoints>;
     192              : 
     193              :   static void apply(
     194              :       const gsl::not_null<typename DerivativeTags::type*>... derivative_scalars,
     195              :       const gsl::not_null<typename Tags::SwshTransform<
     196              :           DerivativeTags>::type*>... transform_of_derivative_scalars,
     197              :       const gsl::not_null<typename Tags::SwshTransform<
     198              :           UniqueDifferentiatedFromTags>::type*>... transform_of_input_scalars,
     199              :       const typename UniqueDifferentiatedFromTags::type&... input_scalars,
     200              :       const size_t l_max, const size_t number_of_radial_points) {
     201              :     apply_to_vectors(make_not_null(&get(*transform_of_derivative_scalars))...,
     202              :                      make_not_null(&get(*transform_of_input_scalars))...,
     203              :                      make_not_null(&get(*derivative_scalars))...,
     204              :                      get(input_scalars)..., l_max, number_of_radial_points);
     205              :   }
     206              : 
     207              :   template <ComplexRepresentation FriendRepresentation,
     208              :             typename... DerivativeKinds, typename... ArgumentTypes,
     209              :             size_t... Is>
     210              :   // NOLINTNEXTLINE(readability-redundant-declaration)
     211              :   friend void angular_derivatives_impl(const std::tuple<ArgumentTypes...>&,
     212              :                                        size_t, size_t,
     213              :                                        std::index_sequence<Is...>,
     214              :                                        tmpl::list<DerivativeKinds...>,
     215              :                                        std::bool_constant<true>);
     216              : 
     217              :  private:
     218              :   // note inputs reordered to accommodate the alternative tag-free functions
     219              :   // which call into this function.
     220              :   static void apply_to_vectors(
     221              :       const gsl::not_null<typename Tags::SwshTransform<
     222              :           DerivativeTags>::type::type*>... transform_of_derivatives,
     223              :       const gsl::not_null<typename Tags::SwshTransform<
     224              :           UniqueDifferentiatedFromTags>::type::type*>... transform_of_inputs,
     225              :       const gsl::not_null<typename DerivativeTags::type::type*>... derivatives,
     226              :       const typename UniqueDifferentiatedFromTags::type::type&... inputs,
     227              :       const size_t l_max, const size_t number_of_radial_points) {
     228              :     // perform the forward transform on the minimal set of input nodal
     229              :     // quantities to obtain all of the requested derivatives
     230              :     using ForwardTransformList =
     231              :         make_transform_list_from_derivative_tags<Representation,
     232              :                                                  tmpl::list<DerivativeTags...>>;
     233              : 
     234              :     tmpl::for_each<ForwardTransformList>(
     235              :         [&number_of_radial_points, &l_max, &inputs...,
     236              :          &transform_of_inputs...](auto transform_v) {
     237              :           using transform = typename decltype(transform_v)::type;
     238              :           auto input_transforms = std::make_tuple(transform_of_inputs...);
     239              :           dispatch_to_transform<transform,
     240              :                                 tmpl::list<UniqueDifferentiatedFromTags...>>::
     241              :               apply(make_not_null(&input_transforms),
     242              :                     std::forward_as_tuple(inputs...), l_max,
     243              :                     number_of_radial_points);
     244              :         });
     245              : 
     246              :     // apply the modal derivative factors and place the result in the
     247              :     // `transform_of_derivatives`
     248              :     EXPAND_PACK_LEFT_TO_RIGHT(
     249              :         dispatch_to_compute_coefficients_of_derivative<
     250              :             DerivativeTags, tmpl::list<UniqueDifferentiatedFromTags...>>::
     251              :             apply(transform_of_derivatives,
     252              :                   std::make_tuple(transform_of_inputs...), l_max,
     253              :                   number_of_radial_points));
     254              : 
     255              :     // perform the inverse transform on the derivative results, placing the
     256              :     // result in the nodal `derivatives` passed by pointer.
     257              :     using InverseTransformList =
     258              :         make_inverse_transform_list<Representation,
     259              :                                     tmpl::list<DerivativeTags...>>;
     260              : 
     261              :     tmpl::for_each<InverseTransformList>([&number_of_radial_points, &l_max,
     262              :                                           &derivatives...,
     263              :                                           &transform_of_derivatives...](
     264              :                                              auto transform_v) {
     265              :       using transform = typename decltype(transform_v)::type;
     266              :       auto derivative_tuple = std::make_tuple(derivatives...);
     267              :       dispatch_to_transform<transform, tmpl::list<DerivativeTags...>>::apply(
     268              :           make_not_null(&derivative_tuple),
     269              :           std::make_tuple(transform_of_derivatives...), l_max,
     270              :           number_of_radial_points);
     271              :     });
     272              :   }
     273              : };
     274              : 
     275              : // metafunction for determining the tags needed to evaluate the derivative tags
     276              : // in `DerivativeTagList`, removing all duplicate tags.
     277              : template <typename DerivativeTagList>
     278              : struct unique_derived_from_list;
     279              : 
     280              : template <typename... DerivativeTags>
     281              : struct unique_derived_from_list<tmpl::list<DerivativeTags...>> {
     282              :   using type = tmpl::remove_duplicates<
     283              :       tmpl::list<typename DerivativeTags::derivative_of...>>;
     284              : };
     285              : }  // namespace detail
     286              : 
     287              : /*!
     288              :  * \ingroup SpectralGroup
     289              :  * \brief A \ref DataBoxGroup mutate-compatible computational struct for
     290              :  * computing a set of spin-weighted spherical harmonic derivatives by
     291              :  * grouping and batch-computing spin-weighted spherical harmonic transforms.
     292              :  *
     293              :  * \details A derivative is evaluated for each tag in `DerivativeTagList`. All
     294              :  * entries in `DerivativeTagList` must be the tag
     295              :  * `Spectral::Swsh::Tags::Derivative<Tag, DerivativeKind>` prefixing the `Tag`
     296              :  * to be differentiated, and indicating the spin-weighted derivative
     297              :  * `DerivativeKind` to be taken. A \ref DataBoxGroup on which this struct is
     298              :  * invoked must contain:
     299              :  * - each of the tags in `DerivativeTagList` (the results of the computation)
     300              :  * - each of the tags `Tag` prefixed by `Spectral::Swsh::Tags::Derivative` in
     301              :  * `DerivativeTagList` (the inputs of the computation).
     302              :  * - each of the tags `Spectral::Swsh::Tags::SwshTransform<DerivativeTag>` for
     303              :  *  `DerivativeTag`in `DerivativeTagList` (the buffers for the derivative
     304              :  * applied to the modes)
     305              :  * - each of the tags `Spectral::Swsh::Tags::SwshTransform<Tag>` for `Tag`
     306              :  * prefixed by any `DerivativeTag` in `DerivativeTagList` (the buffers for the
     307              :  * transforms of the input data).
     308              :  *
     309              :  * This function optimizes the derivative taking process by clustering like
     310              :  * spins of tags, forward-transforming each spin cluster together, applying the
     311              :  * factor for the derivative to each modal vector, re-clustering according to
     312              :  * the new spin weights (the derivatives alter the spin weights), and finally
     313              :  * inverse-transforming in clusters.
     314              :  */
     315              : template <typename DerivativeTagList, ComplexRepresentation Representation =
     316              :                                           ComplexRepresentation::Interleaved>
     317            1 : using AngularDerivatives = detail::AngularDerivativesImpl<
     318              :     DerivativeTagList,
     319              :     typename detail::unique_derived_from_list<DerivativeTagList>::type,
     320              :     Representation>;
     321              : 
     322              : /*!
     323              :  * \ingroup SpectralGroup
     324              :  * \brief Produces a `SpinWeighted<ComplexModalVector, Spin>` of the appropriate
     325              :  * size to be used as a modal buffer for `Spectral::Swsh::AngularDerivatives` or
     326              :  * `Spectral::Swsh::angular_derivatives`.
     327              :  *
     328              :  * \details The `Spectral::Swsh::angular_derivatives` and
     329              :  * `Spectral::Swsh::AngularDerivatives` interfaces require that calling code
     330              :  * provides a buffer for the intermediate transform results, to ensure that
     331              :  * callers are aware of the allocations and can suitably reuse buffers if
     332              :  * possible. This utility eases the creation of those buffers.
     333              :  */
     334              : template <int Spin>
     335            1 : auto swsh_buffer(const size_t l_max, const size_t number_of_radial_points) {
     336              :   return SpinWeighted<ComplexModalVector, Spin>{
     337              :       size_of_libsharp_coefficient_vector(l_max) * number_of_radial_points};
     338              : }
     339              : 
     340              : namespace detail {
     341              : // template 'implementation' for the `angular_derivatives` function below which
     342              : // evaluates an arbitrary number of derivatives, and places them in the set of
     343              : // nodal containers passed by pointer.
     344              : template <ComplexRepresentation Representation, typename... DerivativeKinds,
     345              :           typename... ArgumentTypes, size_t... Is>
     346              : void angular_derivatives_impl(
     347              :     const std::tuple<ArgumentTypes...>& argument_tuple, const size_t l_max,
     348              :     const size_t number_of_radial_points, std::index_sequence<Is...> /*meta*/,
     349              :     tmpl::list<DerivativeKinds...> /*meta*/,
     350              :     std::bool_constant<true> /*buffers_included_in_arguments*/) {
     351              :   AngularDerivatives<
     352              :       tmpl::list<Tags::Derivative<
     353              :           ::Tags::SpinWeighted<
     354              :               ::Tags::TempScalar<Is, ComplexDataVector>,
     355              :               std::integral_constant<
     356              :                   int, std::decay_t<decltype(get<Is + 3 * sizeof...(Is)>(
     357              :                            argument_tuple))>::spin>>,
     358              :           DerivativeKinds>...>,
     359              :       Representation>::apply_to_vectors(get<Is>(argument_tuple)...,
     360              :                                         get<Is + sizeof...(Is)>(
     361              :                                             argument_tuple)...,
     362              :                                         get<Is + 2 * sizeof...(Is)>(
     363              :                                             argument_tuple)...,
     364              :                                         get<Is + 3 * sizeof...(Is)>(
     365              :                                             argument_tuple)...,
     366              :                                         l_max, number_of_radial_points);
     367              : }
     368              : 
     369              : template <ComplexRepresentation Representation, typename... DerivativeKinds,
     370              :           typename... ArgumentTypes, size_t... Is>
     371              : void angular_derivatives_impl(
     372              :     const std::tuple<ArgumentTypes...>& argument_tuple, const size_t l_max,
     373              :     const size_t number_of_radial_points,
     374              :     std::index_sequence<Is...> index_sequence,
     375              :     tmpl::list<DerivativeKinds...> derivative_kinds,
     376              :     std::bool_constant<false> /*buffers_included_in_arguments*/) {
     377              :   auto derivative_buffer_tuple = std::make_tuple(
     378              :       swsh_buffer<std::decay_t<decltype(*get<Is>(argument_tuple))>::spin>(
     379              :           l_max, number_of_radial_points)...);
     380              :   auto input_buffer_tuple = std::make_tuple(
     381              :       swsh_buffer<std::decay_t<decltype(get<Is + sizeof...(Is)>(
     382              :           argument_tuple))>::spin>(l_max, number_of_radial_points)...);
     383              :   angular_derivatives_impl<Representation>(
     384              :       std::forward_as_tuple(make_not_null(&get<Is>(derivative_buffer_tuple))...,
     385              :                             make_not_null(&get<Is>(input_buffer_tuple))...,
     386              :                             get<Is>(argument_tuple)...,
     387              :                             get<Is + sizeof...(Is)>(argument_tuple)...),
     388              :       l_max, number_of_radial_points, index_sequence, derivative_kinds,
     389              :       std::bool_constant<true>{});
     390              : }
     391              : }  // namespace detail
     392              : 
     393              : /*!
     394              :  * \ingroup SpectralGroup
     395              :  * \brief Evaluate all of the spin-weighted derivatives in `DerivKindList` on
     396              :  * input `SpinWeighted<ComplexDataVector, Spin>` collocation data, returning by
     397              :  * pointer.
     398              :  *
     399              :  * \details This function provides two interfaces, one in which the caller
     400              :  * provides the intermediate coefficient buffers needed during the computation
     401              :  * of the derivatives, and one in which those buffers are temporarily allocated
     402              :  * during the derivative function calls.
     403              :  *
     404              :  * For the interface in which the caller does not provide buffers, the arguments
     405              :  * must take the following structure (enforced by internal function calls):
     406              :  *
     407              :  * - `size_t l_max` : angular resolution for the spherical representation
     408              :  * - `size_t number_of_radial_points` : radial resolution (number of consecutive
     409              :  * blocks to evaluate derivatives, for each input vector )
     410              :  * - for each `DerivKind` in `DerivKindList`, a
     411              :  * `gsl::not_null<SpinWeighted<ComplexDataVector, Spin +
     412              :  * Tags::derivative_spin_weight<DerivKind>>>` : the output of the derivative
     413              :  * evaluation
     414              :  * - for each `DerivKind` in `DerivKindList`, a `const
     415              :  * SpinWeighted<ComplexDataVector, Spin>&` (where the `Spin` for these arguments
     416              :  * matches the corresponding vector from the previous set) : the input to the
     417              :  * derivative evaluation.
     418              :  *
     419              :  * For the interface in which the caller does provide buffers, the arguments
     420              :  * must take the following structure (enforced by internal function calls):
     421              :  *
     422              :  * - `size_t l_max` : angular resolution for the spherical representation
     423              :  * - `size_t number_of_radial_points` : radial resolution (number of consecutive
     424              :  * blocks to evaluate derivatives, for each input vector )
     425              :  * - for each `DerivKind` in `DerivKindList`, a
     426              :  * `gsl::not_null<SpinWeighted<ComplexModalVector, Spin +
     427              :  * Tags::derivative_spin_weight<DerivKind>>>` : the buffer for the spin-weighted
     428              :  * spherical harmonic modes of the derivative quantities.
     429              :  * - for each `DerivKind` in `DerivKindList`, a `const
     430              :  * SpinWeighted<ComplexModalVector, Spin>` (where the `Spin` for these arguments
     431              :  * matches the corresponding vector from the previous set) : the buffer for the
     432              :  * spin-weighted spherical harmonic modes of the input quantities.
     433              :  * - for each `DerivKind` in `DerivKindList`, a
     434              :  * `gsl::not_null<SpinWeighted<ComplexDataVector, Spin +
     435              :  * Tags::derivative_spin_weight<DerivKind>>>` : the output of the derivative
     436              :  * evaluation
     437              :  * - for each `DerivKind` in `DerivKindList`, a `const
     438              :  * SpinWeighted<ComplexDataVector, Spin>` (where the `Spin` for these arguments
     439              :  * matches the corresponding vector from the previous set) : the input to the
     440              :  * derivative evaluation.
     441              :  *
     442              :  * The function `swsh_buffer` assists in generating the modal buffers of
     443              :  * appropriate size.
     444              :  */
     445              : template <
     446              :     typename DerivativeKindList,
     447              :     ComplexRepresentation Representation = ComplexRepresentation::Interleaved,
     448              :     typename... ArgumentTypes>
     449            1 : void angular_derivatives(const size_t l_max,                    // NOLINT
     450              :                          const size_t number_of_radial_points,  // NOLINT
     451              :                          const ArgumentTypes&... arguments) {
     452              :   static_assert(
     453              :       tmpl::size<DerivativeKindList>::value * 2 == sizeof...(ArgumentTypes) or
     454              :           tmpl::size<DerivativeKindList>::value * 4 == sizeof...(ArgumentTypes),
     455              :       "When using the tagless `angular_derivatives` interface, you must "
     456              :       "provide either one nodal input and one nodal output per derivative "
     457              :       "or one nodal input, one nodal output, and two appropriate "
     458              :       "intermediate transform buffers per derivative.");
     459              : 
     460              :   detail::angular_derivatives_impl<Representation>(
     461              :       std::forward_as_tuple(arguments...), l_max, number_of_radial_points,
     462              :       std::make_index_sequence<tmpl::size<DerivativeKindList>::value>{},
     463              :       DerivativeKindList{},
     464              :       std::bool_constant<tmpl::size<DerivativeKindList>::value * 4 ==
     465              :                          sizeof...(ArgumentTypes)>{});
     466              : }
     467              : 
     468              : /*!
     469              :  * \ingroup SpectralGroup
     470              :  * \brief Evaluate the spin-weighted derivative `DerivKind` on the provided
     471              :  * `SpinWeighted<ComplexDataVector, Spin>` collocation data, returning by value.
     472              :  */
     473              : template <
     474              :     typename DerivKind,
     475              :     ComplexRepresentation Representation = ComplexRepresentation::Interleaved,
     476              :     int Spin>
     477              : SpinWeighted<ComplexDataVector, Tags::derivative_spin_weight<DerivKind> + Spin>
     478            1 : angular_derivative(
     479              :     size_t l_max, size_t number_of_radial_points,
     480              :     const SpinWeighted<ComplexDataVector, Spin>& to_differentiate);
     481              : }  // namespace Swsh
     482              : }  // namespace Spectral
        

Generated by: LCOV version 2.0-1