SpECTRE Documentation Coverage Report
Current view: top level - NumericalAlgorithms/SpinWeightedSphericalHarmonics - SwshDerivatives.hpp Hit Total Coverage
Commit: bcc6763cee2b3f1593fb35e61fb83412a3313e95 Lines: 4 5 80.0 %
Date: 2024-09-16 17:23:19
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 =
     191             :       tmpl::list<UniqueDifferentiatedFromTags..., Tags::LMaxBase,
     192             :                  Tags::NumberOfRadialPointsBase>;
     193             : 
     194             :   static void apply(
     195             :       const gsl::not_null<typename DerivativeTags::type*>... derivative_scalars,
     196             :       const gsl::not_null<typename Tags::SwshTransform<
     197             :           DerivativeTags>::type*>... transform_of_derivative_scalars,
     198             :       const gsl::not_null<typename Tags::SwshTransform<
     199             :           UniqueDifferentiatedFromTags>::type*>... transform_of_input_scalars,
     200             :       const typename UniqueDifferentiatedFromTags::type&... input_scalars,
     201             :       const size_t l_max, const size_t number_of_radial_points) {
     202             :     apply_to_vectors(make_not_null(&get(*transform_of_derivative_scalars))...,
     203             :                      make_not_null(&get(*transform_of_input_scalars))...,
     204             :                      make_not_null(&get(*derivative_scalars))...,
     205             :                      get(input_scalars)..., l_max, number_of_radial_points);
     206             :   }
     207             : 
     208             :   template <ComplexRepresentation FriendRepresentation,
     209             :             typename... DerivativeKinds, typename... ArgumentTypes,
     210             :             size_t... Is>
     211             :   // NOLINTNEXTLINE(readability-redundant-declaration)
     212             :   friend void angular_derivatives_impl(const std::tuple<ArgumentTypes...>&,
     213             :                                        size_t, size_t,
     214             :                                        std::index_sequence<Is...>,
     215             :                                        tmpl::list<DerivativeKinds...>,
     216             :                                        std::bool_constant<true>);
     217             : 
     218             :  private:
     219             :   // note inputs reordered to accommodate the alternative tag-free functions
     220             :   // which call into this function.
     221             :   static void apply_to_vectors(
     222             :       const gsl::not_null<typename Tags::SwshTransform<
     223             :           DerivativeTags>::type::type*>... transform_of_derivatives,
     224             :       const gsl::not_null<typename Tags::SwshTransform<
     225             :           UniqueDifferentiatedFromTags>::type::type*>... transform_of_inputs,
     226             :       const gsl::not_null<typename DerivativeTags::type::type*>... derivatives,
     227             :       const typename UniqueDifferentiatedFromTags::type::type&... inputs,
     228             :       const size_t l_max, const size_t number_of_radial_points) {
     229             :     // perform the forward transform on the minimal set of input nodal
     230             :     // quantities to obtain all of the requested derivatives
     231             :     using ForwardTransformList =
     232             :         make_transform_list_from_derivative_tags<Representation,
     233             :                                                  tmpl::list<DerivativeTags...>>;
     234             : 
     235             :     tmpl::for_each<ForwardTransformList>(
     236             :         [&number_of_radial_points, &l_max, &inputs...,
     237             :          &transform_of_inputs...](auto transform_v) {
     238             :           using transform = typename decltype(transform_v)::type;
     239             :           auto input_transforms = std::make_tuple(transform_of_inputs...);
     240             :           dispatch_to_transform<transform,
     241             :                                 tmpl::list<UniqueDifferentiatedFromTags...>>::
     242             :               apply(make_not_null(&input_transforms),
     243             :                     std::forward_as_tuple(inputs...), l_max,
     244             :                     number_of_radial_points);
     245             :         });
     246             : 
     247             :     // apply the modal derivative factors and place the result in the
     248             :     // `transform_of_derivatives`
     249             :     EXPAND_PACK_LEFT_TO_RIGHT(
     250             :         dispatch_to_compute_coefficients_of_derivative<
     251             :             DerivativeTags, tmpl::list<UniqueDifferentiatedFromTags...>>::
     252             :             apply(transform_of_derivatives,
     253             :                   std::make_tuple(transform_of_inputs...), l_max,
     254             :                   number_of_radial_points));
     255             : 
     256             :     // perform the inverse transform on the derivative results, placing the
     257             :     // result in the nodal `derivatives` passed by pointer.
     258             :     using InverseTransformList =
     259             :         make_inverse_transform_list<Representation,
     260             :                                     tmpl::list<DerivativeTags...>>;
     261             : 
     262             :     tmpl::for_each<InverseTransformList>([&number_of_radial_points, &l_max,
     263             :                                           &derivatives...,
     264             :                                           &transform_of_derivatives...](
     265             :                                              auto transform_v) {
     266             :       using transform = typename decltype(transform_v)::type;
     267             :       auto derivative_tuple = std::make_tuple(derivatives...);
     268             :       dispatch_to_transform<transform, tmpl::list<DerivativeTags...>>::apply(
     269             :           make_not_null(&derivative_tuple),
     270             :           std::make_tuple(transform_of_derivatives...), l_max,
     271             :           number_of_radial_points);
     272             :     });
     273             :   }
     274             : };
     275             : 
     276             : // metafunction for determining the tags needed to evaluate the derivative tags
     277             : // in `DerivativeTagList`, removing all duplicate tags.
     278             : template <typename DerivativeTagList>
     279             : struct unique_derived_from_list;
     280             : 
     281             : template <typename... DerivativeTags>
     282             : struct unique_derived_from_list<tmpl::list<DerivativeTags...>> {
     283             :   using type = tmpl::remove_duplicates<
     284             :       tmpl::list<typename DerivativeTags::derivative_of...>>;
     285             : };
     286             : }  // namespace detail
     287             : 
     288             : /*!
     289             :  * \ingroup SpectralGroup
     290             :  * \brief A \ref DataBoxGroup mutate-compatible computational struct for
     291             :  * computing a set of spin-weighted spherical harmonic derivatives by
     292             :  * grouping and batch-computing spin-weighted spherical harmonic transforms.
     293             :  *
     294             :  * \details A derivative is evaluated for each tag in `DerivativeTagList`. All
     295             :  * entries in `DerivativeTagList` must be the tag
     296             :  * `Spectral::Swsh::Tags::Derivative<Tag, DerivativeKind>` prefixing the `Tag`
     297             :  * to be differentiated, and indicating the spin-weighted derivative
     298             :  * `DerivativeKind` to be taken. A \ref DataBoxGroup on which this struct is
     299             :  * invoked must contain:
     300             :  * - each of the tags in `DerivativeTagList` (the results of the computation)
     301             :  * - each of the tags `Tag` prefixed by `Spectral::Swsh::Tags::Derivative` in
     302             :  * `DerivativeTagList` (the inputs of the computation).
     303             :  * - each of the tags `Spectral::Swsh::Tags::SwshTransform<DerivativeTag>` for
     304             :  *  `DerivativeTag`in `DerivativeTagList` (the buffers for the derivative
     305             :  * applied to the modes)
     306             :  * - each of the tags `Spectral::Swsh::Tags::SwshTransform<Tag>` for `Tag`
     307             :  * prefixed by any `DerivativeTag` in `DerivativeTagList` (the buffers for the
     308             :  * transforms of the input data).
     309             :  *
     310             :  * This function optimizes the derivative taking process by clustering like
     311             :  * spins of tags, forward-transforming each spin cluster together, applying the
     312             :  * factor for the derivative to each modal vector, re-clustering according to
     313             :  * the new spin weights (the derivatives alter the spin weights), and finally
     314             :  * inverse-transforming in clusters.
     315             :  */
     316             : template <typename DerivativeTagList, ComplexRepresentation Representation =
     317             :                                           ComplexRepresentation::Interleaved>
     318           1 : using AngularDerivatives = detail::AngularDerivativesImpl<
     319             :     DerivativeTagList,
     320             :     typename detail::unique_derived_from_list<DerivativeTagList>::type,
     321             :     Representation>;
     322             : 
     323             : /*!
     324             :  * \ingroup SpectralGroup
     325             :  * \brief Produces a `SpinWeighted<ComplexModalVector, Spin>` of the appropriate
     326             :  * size to be used as a modal buffer for `Spectral::Swsh::AngularDerivatives` or
     327             :  * `Spectral::Swsh::angular_derivatives`.
     328             :  *
     329             :  * \details The `Spectral::Swsh::angular_derivatives` and
     330             :  * `Spectral::Swsh::AngularDerivatives` interfaces require that calling code
     331             :  * provides a buffer for the intermediate transform results, to ensure that
     332             :  * callers are aware of the allocations and can suitably reuse buffers if
     333             :  * possible. This utility eases the creation of those buffers.
     334             :  */
     335             : template <int Spin>
     336           1 : auto swsh_buffer(const size_t l_max, const size_t number_of_radial_points) {
     337             :   return SpinWeighted<ComplexModalVector, Spin>{
     338             :       size_of_libsharp_coefficient_vector(l_max) * number_of_radial_points};
     339             : }
     340             : 
     341             : namespace detail {
     342             : // template 'implementation' for the `angular_derivatives` function below which
     343             : // evaluates an arbitrary number of derivatives, and places them in the set of
     344             : // nodal containers passed by pointer.
     345             : template <ComplexRepresentation Representation, typename... DerivativeKinds,
     346             :           typename... ArgumentTypes, size_t... Is>
     347             : void angular_derivatives_impl(
     348             :     const std::tuple<ArgumentTypes...>& argument_tuple, const size_t l_max,
     349             :     const size_t number_of_radial_points, std::index_sequence<Is...> /*meta*/,
     350             :     tmpl::list<DerivativeKinds...> /*meta*/,
     351             :     std::bool_constant<true> /*buffers_included_in_arguments*/) {
     352             :   AngularDerivatives<
     353             :       tmpl::list<Tags::Derivative<
     354             :           ::Tags::SpinWeighted<
     355             :               ::Tags::TempScalar<Is, ComplexDataVector>,
     356             :               std::integral_constant<
     357             :                   int, std::decay_t<decltype(get<Is + 3 * sizeof...(Is)>(
     358             :                            argument_tuple))>::spin>>,
     359             :           DerivativeKinds>...>,
     360             :       Representation>::apply_to_vectors(get<Is>(argument_tuple)...,
     361             :                                         get<Is + sizeof...(Is)>(
     362             :                                             argument_tuple)...,
     363             :                                         get<Is + 2 * sizeof...(Is)>(
     364             :                                             argument_tuple)...,
     365             :                                         get<Is + 3 * sizeof...(Is)>(
     366             :                                             argument_tuple)...,
     367             :                                         l_max, number_of_radial_points);
     368             : }
     369             : 
     370             : template <ComplexRepresentation Representation, typename... DerivativeKinds,
     371             :           typename... ArgumentTypes, size_t... Is>
     372             : void angular_derivatives_impl(
     373             :     const std::tuple<ArgumentTypes...>& argument_tuple, const size_t l_max,
     374             :     const size_t number_of_radial_points,
     375             :     std::index_sequence<Is...> index_sequence,
     376             :     tmpl::list<DerivativeKinds...> derivative_kinds,
     377             :     std::bool_constant<false> /*buffers_included_in_arguments*/) {
     378             :   auto derivative_buffer_tuple = std::make_tuple(
     379             :       swsh_buffer<std::decay_t<decltype(*get<Is>(argument_tuple))>::spin>(
     380             :           l_max, number_of_radial_points)...);
     381             :   auto input_buffer_tuple = std::make_tuple(
     382             :       swsh_buffer<std::decay_t<decltype(get<Is + sizeof...(Is)>(
     383             :           argument_tuple))>::spin>(l_max, number_of_radial_points)...);
     384             :   angular_derivatives_impl<Representation>(
     385             :       std::forward_as_tuple(make_not_null(&get<Is>(derivative_buffer_tuple))...,
     386             :                             make_not_null(&get<Is>(input_buffer_tuple))...,
     387             :                             get<Is>(argument_tuple)...,
     388             :                             get<Is + sizeof...(Is)>(argument_tuple)...),
     389             :       l_max, number_of_radial_points, index_sequence, derivative_kinds,
     390             :       std::bool_constant<true>{});
     391             : }
     392             : }  // namespace detail
     393             : 
     394             : /*!
     395             :  * \ingroup SpectralGroup
     396             :  * \brief Evaluate all of the spin-weighted derivatives in `DerivKindList` on
     397             :  * input `SpinWeighted<ComplexDataVector, Spin>` collocation data, returning by
     398             :  * pointer.
     399             :  *
     400             :  * \details This function provides two interfaces, one in which the caller
     401             :  * provides the intermediate coefficient buffers needed during the computation
     402             :  * of the derivatives, and one in which those buffers are temporarily allocated
     403             :  * during the derivative function calls.
     404             :  *
     405             :  * For the interface in which the caller does not provide buffers, the arguments
     406             :  * must take the following structure (enforced by internal function calls):
     407             :  *
     408             :  * - `size_t l_max` : angular resolution for the spherical representation
     409             :  * - `size_t number_of_radial_points` : radial resolution (number of consecutive
     410             :  * blocks to evaluate derivatives, for each input vector )
     411             :  * - for each `DerivKind` in `DerivKindList`, a
     412             :  * `gsl::not_null<SpinWeighted<ComplexDataVector, Spin +
     413             :  * Tags::derivative_spin_weight<DerivKind>>>` : the output of the derivative
     414             :  * evaluation
     415             :  * - for each `DerivKind` in `DerivKindList`, a `const
     416             :  * SpinWeighted<ComplexDataVector, Spin>&` (where the `Spin` for these arguments
     417             :  * matches the corresponding vector from the previous set) : the input to the
     418             :  * derivative evaluation.
     419             :  *
     420             :  * For the interface in which the caller does provide buffers, the arguments
     421             :  * must take the following structure (enforced by internal function calls):
     422             :  *
     423             :  * - `size_t l_max` : angular resolution for the spherical representation
     424             :  * - `size_t number_of_radial_points` : radial resolution (number of consecutive
     425             :  * blocks to evaluate derivatives, for each input vector )
     426             :  * - for each `DerivKind` in `DerivKindList`, a
     427             :  * `gsl::not_null<SpinWeighted<ComplexModalVector, Spin +
     428             :  * Tags::derivative_spin_weight<DerivKind>>>` : the buffer for the spin-weighted
     429             :  * spherical harmonic modes of the derivative quantities.
     430             :  * - for each `DerivKind` in `DerivKindList`, a `const
     431             :  * SpinWeighted<ComplexModalVector, Spin>` (where the `Spin` for these arguments
     432             :  * matches the corresponding vector from the previous set) : the buffer for the
     433             :  * spin-weighted spherical harmonic modes of the input quantities.
     434             :  * - for each `DerivKind` in `DerivKindList`, a
     435             :  * `gsl::not_null<SpinWeighted<ComplexDataVector, Spin +
     436             :  * Tags::derivative_spin_weight<DerivKind>>>` : the output of the derivative
     437             :  * evaluation
     438             :  * - for each `DerivKind` in `DerivKindList`, a `const
     439             :  * SpinWeighted<ComplexDataVector, Spin>` (where the `Spin` for these arguments
     440             :  * matches the corresponding vector from the previous set) : the input to the
     441             :  * derivative evaluation.
     442             :  *
     443             :  * The function `swsh_buffer` assists in generating the modal buffers of
     444             :  * appropriate size.
     445             :  */
     446             : template <
     447             :     typename DerivativeKindList,
     448             :     ComplexRepresentation Representation = ComplexRepresentation::Interleaved,
     449             :     typename... ArgumentTypes>
     450           1 : void angular_derivatives(const size_t l_max,                    // NOLINT
     451             :                          const size_t number_of_radial_points,  // NOLINT
     452             :                          const ArgumentTypes&... arguments) {
     453             :   static_assert(
     454             :       tmpl::size<DerivativeKindList>::value * 2 == sizeof...(ArgumentTypes) or
     455             :           tmpl::size<DerivativeKindList>::value * 4 == sizeof...(ArgumentTypes),
     456             :       "When using the tagless `angular_derivatives` interface, you must "
     457             :       "provide either one nodal input and one nodal output per derivative "
     458             :       "or one nodal input, one nodal output, and two appropriate "
     459             :       "intermediate transform buffers per derivative.");
     460             : 
     461             :   detail::angular_derivatives_impl<Representation>(
     462             :       std::forward_as_tuple(arguments...), l_max, number_of_radial_points,
     463             :       std::make_index_sequence<tmpl::size<DerivativeKindList>::value>{},
     464             :       DerivativeKindList{},
     465             :       std::bool_constant<tmpl::size<DerivativeKindList>::value * 4 ==
     466             :                          sizeof...(ArgumentTypes)>{});
     467             : }
     468             : 
     469             : /*!
     470             :  * \ingroup SpectralGroup
     471             :  * \brief Evaluate the spin-weighted derivative `DerivKind` on the provided
     472             :  * `SpinWeighted<ComplexDataVector, Spin>` collocation data, returning by value.
     473             :  */
     474             : template <
     475             :     typename DerivKind,
     476             :     ComplexRepresentation Representation = ComplexRepresentation::Interleaved,
     477             :     int Spin>
     478             : SpinWeighted<ComplexDataVector, Tags::derivative_spin_weight<DerivKind> + Spin>
     479           1 : angular_derivative(
     480             :     size_t l_max, size_t number_of_radial_points,
     481             :     const SpinWeighted<ComplexDataVector, Spin>& to_differentiate);
     482             : }  // namespace Swsh
     483             : }  // namespace Spectral

Generated by: LCOV version 1.14