SpECTRE Documentation Coverage Report
Current view: top level - NumericalAlgorithms/Spectral - SwshTransform.hpp Hit Total Coverage
Commit: 3c072f0ce967e2e56649d3fa12aa2a0e4fe2a42e Lines: 10 11 90.9 %
Date: 2024-04-23 20:50:18
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             : #include <sharp_cxx.h>
       9             : #include <type_traits>
      10             : #include <utility>
      11             : #include <vector>
      12             : 
      13             : #include "DataStructures/DataBox/PrefixHelpers.hpp"
      14             : #include "DataStructures/SpinWeighted.hpp"
      15             : #include "DataStructures/Tags.hpp"
      16             : #include "DataStructures/Tags/TempTensor.hpp"
      17             : #include "NumericalAlgorithms/Spectral/ComplexDataView.hpp"
      18             : #include "NumericalAlgorithms/Spectral/SwshCoefficients.hpp"  // IWYU pragma: keep
      19             : #include "NumericalAlgorithms/Spectral/SwshCollocation.hpp"
      20             : #include "NumericalAlgorithms/Spectral/SwshTags.hpp"
      21             : #include "Utilities/Gsl.hpp"
      22             : #include "Utilities/TMPL.hpp"
      23             : 
      24             : // IWYU pragma: no_forward_declare Coefficients
      25             : // IWYU pragma: no_forward_declare SpinWeighted
      26             : 
      27             : class ComplexDataVector;
      28             : class ComplexModalVector;
      29             : 
      30             : namespace Spectral {
      31             : namespace Swsh {
      32             : 
      33             : namespace detail {
      34             : // libsharp has an internal maximum number of transforms that is not in the
      35             : // public interface, so we must hard-code its value here
      36             : static const size_t max_libsharp_transforms = 100;
      37             : 
      38             : // appends to a vector of pointers `collocation_data` the set of pointers
      39             : // associated with angular views of the provided collocation data `vector`. The
      40             : // associated views are appended into `collocation_views`. If `positive_spin` is
      41             : // false, this function will conjugate the views, and therefore potentially
      42             : // conjugate (depending on `Representation`) the input data `vectors`. This
      43             : // behavior is chosen to avoid frequent copies of the input data `vector` for
      44             : // optimization. The conjugation must be undone after the call to libsharp
      45             : // transforms using `conjugate_views` to restore the input data to its original
      46             : // state.
      47             : template <ComplexRepresentation Representation>
      48             : void append_libsharp_collocation_pointers(
      49             :     gsl::not_null<std::vector<double*>*> collocation_data,
      50             :     gsl::not_null<std::vector<ComplexDataView<Representation>>*>
      51             :         collocation_views,
      52             :     gsl::not_null<ComplexDataVector*> vector, size_t l_max, bool positive_spin);
      53             : 
      54             : // Perform a conjugation on a vector of `ComplexDataView`s if `Spin` < 0. This
      55             : // is used for undoing the conjugation described in the code comment for
      56             : // `append_libsharp_collocation_pointers`
      57             : template <int Spin, ComplexRepresentation Representation>
      58             : SPECTRE_ALWAYS_INLINE void conjugate_views(
      59             :     gsl::not_null<std::vector<ComplexDataView<Representation>>*>
      60             :         collocation_views) {
      61             :   if (Spin < 0) {
      62             :     for (auto& view : *collocation_views) {
      63             :       view.conjugate();
      64             :     }
      65             :   }
      66             : }
      67             : 
      68             : // appends to a vector of pointers the set of pointers associated with
      69             : // angular views of the provided coefficient vector. When working with the
      70             : // libsharp coefficient representation, note the intricacies mentioned in
      71             : // the documentation for `TransformJob`.
      72             : void append_libsharp_coefficient_pointers(
      73             :     gsl::not_null<std::vector<std::complex<double>*>*> coefficient_data,
      74             :     gsl::not_null<ComplexModalVector*> vector, size_t l_max);
      75             : 
      76             : // perform the actual libsharp execution calls on an input and output set of
      77             : // pointers. This function handles the complication of a limited maximum number
      78             : // of simultaneous transforms, performing multiple execution calls on pointer
      79             : // blocks if necessary.
      80             : template <ComplexRepresentation Representation>
      81             : void execute_libsharp_transform_set(
      82             :     const sharp_jobtype& jobtype, int spin,
      83             :     gsl::not_null<std::vector<std::complex<double>*>*> coefficient_data,
      84             :     gsl::not_null<std::vector<double*>*> collocation_data,
      85             :     gsl::not_null<const CollocationMetadata<Representation>*>
      86             :         collocation_metadata,
      87             :     const sharp_alm_info* alm_info, size_t num_transforms);
      88             : 
      89             : // template 'implementation' for the `swsh_transform` function below which
      90             : // performs an arbitrary number of transforms, and places them in the same
      91             : // number of destination modal containers passed by pointer.
      92             : // template notes: the parameter pack represents a collection of ordered modal
      93             : // data passed by pointer, followed by ordered nodal data passed by const
      94             : // reference. The first modal value is separated to infer the `Spin` template
      95             : // parameter.
      96             : template <ComplexRepresentation Representation, int Spin,
      97             :           typename... ModalThenNodalTypes, size_t... Is>
      98             : void swsh_transform_impl(
      99             :     size_t l_max, size_t number_of_radial_points,
     100             :     std::index_sequence<Is...> /*meta*/,
     101             :     gsl::not_null<SpinWeighted<ComplexModalVector, Spin>*> first_coefficient,
     102             :     const ModalThenNodalTypes&... coefficients_then_collocations);
     103             : 
     104             : // template 'implementation' for the `inverse_swsh_transform` function below
     105             : // which performs an arbitrary number of transforms, and places them in the same
     106             : // number of destination nodal containers passed by pointer.
     107             : // template notes: the parameter pack represents a collection of ordered nodal
     108             : // data passed by pointer, followed by ordered modal data passed by const
     109             : // reference. The first nodal value is separated to infer the `Spin` template
     110             : // parameter.
     111             : template <ComplexRepresentation Representation, int Spin,
     112             :           typename... NodalThenModalTypes, size_t... Is>
     113             : void inverse_swsh_transform_impl(
     114             :     size_t l_max, size_t number_of_radial_points,
     115             :     std::index_sequence<Is...> /*meta*/,
     116             :     gsl::not_null<SpinWeighted<ComplexDataVector, Spin>*> first_collocation,
     117             :     const NodalThenModalTypes&... collocations_then_coefficients);
     118             : 
     119             : // forward declaration for friend specification of helper from
     120             : // `SwshDerivatives.hpp`
     121             : template <typename Transform, typename FullTagList>
     122             : struct dispatch_to_transform;
     123             : }  // namespace detail
     124             : 
     125             : /*!
     126             :  * \ingroup SwshGroup
     127             :  * \brief Perform a forward libsharp spin-weighted spherical harmonic transform
     128             :  * on any number of supplied `SpinWeighted<ComplexDataVector, Spin>`.
     129             :  *
     130             :  * \details This function places the result in one or more
     131             :  * `SpinWeighted<ComplexModalVector, Spin>` returned via provided
     132             :  * pointer.  This is a simpler interface to the same functionality as the
     133             :  * \ref DataBoxGroup mutation compatible `SwshTransform`.
     134             :  *
     135             :  * The following parameter ordering for the multiple input interface is enforced
     136             :  * by the interior function calls, but is not obvious from the explicit
     137             :  * parameter packs in this function signature:
     138             :  *
     139             :  * - `size_t l_max` : angular resolution for the transform
     140             :  * - `size_t number_of_radial_points` : radial resolution (number of consecutive
     141             :  * transforms in each of the vectors)
     142             :  * - any number of `gsl::not_null<SpinWeighted<ComplexModalVector,
     143             :  * Spin>*>`, all sharing the same `Spin` : The return-by-pointer containers for
     144             :  * the transformed modal quantities
     145             :  * - the same number of `const SpinWeighted<ComplexDataVector, Spin>&`, with the
     146             :  * same `Spin` as the previous function argument set : The input containers of
     147             :  * nodal spin-weighted spherical harmonic data.
     148             :  *
     149             :  * template parameters:
     150             :  * - `Representation`: Either `ComplexRepresentation::Interleaved` or
     151             :  * `ComplexRepresentation::RealsThenImags`, indicating the representation for
     152             :  * intermediate steps of the transformation. The two representations will give
     153             :  * identical results but may help or hurt performance depending on the task.
     154             :  * If unspecified, defaults to `ComplexRepresentation::Interleaved`.
     155             :  *
     156             :  * The result is a set of libsharp-compatible coefficients.
     157             :  * \see SwshTransform for more details on the mathematics of the libsharp
     158             :  * data structures.
     159             :  *
     160             :  * \warning The collocation data is taken by const reference, but can be
     161             :  * temporarily altered in-place during intermediate parts of the computation.
     162             :  * The input data is guaranteed to return to its original state by the end of
     163             :  * the function. In a setting in which multiple threads access the same data
     164             :  * passed as input to this function, a lock must be used to prevent access
     165             :  * during the execution of the transform.
     166             :  */
     167             : template <
     168             :     ComplexRepresentation Representation = ComplexRepresentation::Interleaved,
     169             :     int Spin, typename... ModalThenNodalTypes>
     170           1 : void swsh_transform(
     171             :     const size_t l_max, const size_t number_of_radial_points,
     172             :     const gsl::not_null<SpinWeighted<ComplexModalVector, Spin>*>
     173             :         first_coefficient,
     174             :     const ModalThenNodalTypes&... coefficients_then_collocations) {
     175             :   static_assert(
     176             :       sizeof...(ModalThenNodalTypes) % 2 == 1,
     177             :       "The number of modal arguments passed to swsh_transform must equal the "
     178             :       "number of nodal arguments, so the total number of arguments must be "
     179             :       "even.");
     180             :   detail::swsh_transform_impl<Representation>(
     181             :       l_max, number_of_radial_points,
     182             :       std::make_index_sequence<(sizeof...(coefficients_then_collocations) + 1) /
     183             :                                2>{},
     184             :       first_coefficient, coefficients_then_collocations...);
     185             : }
     186             : 
     187             : /*!
     188             :  * \ingroup SwshGroup
     189             :  * \brief Perform a forward libsharp spin-weighted spherical harmonic transform
     190             :  * on a single supplied `SpinWeighted<ComplexDataVector, Spin>`.
     191             :  *
     192             :  * \details This function returns a `SpinWeighted<ComplexModalVector, Spin>` by
     193             :  * value (causing an allocation). This is a simpler interface to the same
     194             :  * functionality as the \ref DataBoxGroup mutation compatible `SwshTransform`.
     195             :  * If you have two or more vectors to transform at once, consider the
     196             :  * pass-by-pointer version of `Spectral::Swsh::swsh_transform` or the \ref
     197             :  * DataBoxGroup interface `InverseSwshTransform`, as they are more efficient for
     198             :  * performing several transforms at once.
     199             :  *
     200             :  * The result is a set of libsharp-compatible coefficients.
     201             :  * \see SwshTransform for more details on the mathematics of the libsharp
     202             :  * data structures.
     203             :  *
     204             :  * \warning The collocation data is taken by const reference, but can be
     205             :  * temporarily altered in-place during intermediate parts of the computation.
     206             :  * The input data is guaranteed to return to its original state by the end of
     207             :  * the function. In a setting in which multiple threads access the same data
     208             :  * passed as input to this function, a lock must be used to prevent access
     209             :  * during the execution of the transform.
     210             :  */
     211             : template <
     212             :     ComplexRepresentation Representation = ComplexRepresentation::Interleaved,
     213             :     int Spin>
     214           1 : SpinWeighted<ComplexModalVector, Spin> swsh_transform(
     215             :     size_t l_max, size_t number_of_radial_points,
     216             :     const SpinWeighted<ComplexDataVector, Spin>& collocation);
     217             : 
     218             : /*!
     219             :  * \ingroup SwshGroup
     220             :  * \brief Perform an inverse libsharp spin-weighted spherical harmonic transform
     221             :  * on any number of supplied `SpinWeighted<ComplexModalVector, Spin>`.
     222             :  *
     223             :  * \details This function places the result in one or more
     224             :  * `SpinWeighted<ComplexDataVector, Spin>` returned via provided
     225             :  * pointer.  This is a simpler interface to the same functionality as the
     226             :  * \ref DataBoxGroup mutation compatible `InverseSwshTransform`.
     227             :  *
     228             :  * The following parameter ordering for the multiple input interface is enforced
     229             :  * by the interior function calls, but is not obvious from the explicit
     230             :  * parameter packs in this function signature:
     231             :  *
     232             :  * - `size_t l_max` : angular resolution for the transform
     233             :  * - `size_t number_of_radial_points` : radial resolution (number of consecutive
     234             :  * transforms in each of the vectors)
     235             :  * - any number of `gsl::not_null<SpinWeighted<ComplexDataVector,
     236             :  * Spin>*>`, all sharing the same `Spin` : The return-by-pointer containers for
     237             :  * the transformed nodal quantities
     238             :  * - the same number of `const SpinWeighted<ComplexModalVector, Spin>&`, with
     239             :  * the same `Spin` as the previous function argument set : The input containers
     240             :  * of modal spin-weighted spherical harmonic data.
     241             :  *
     242             :  * template parameters:
     243             :  * - `Representation`: Either `ComplexRepresentation::Interleaved` or
     244             :  * `ComplexRepresentation::RealsThenImags`, indicating the representation for
     245             :  * intermediate steps of the transformation. The two representations will give
     246             :  * identical results but may help or hurt performance depending on the task.
     247             :  * If unspecified, defaults to `ComplexRepresentation::Interleaved`.
     248             :  *
     249             :  * The input is a set of libsharp-compatible coefficients.
     250             :  * \see SwshTransform for more details on the mathematics of the libsharp
     251             :  * data structures.
     252             :  */
     253             : template <
     254             :     ComplexRepresentation Representation = ComplexRepresentation::Interleaved,
     255             :     int Spin, typename... NodalThenModalTypes>
     256           1 : void inverse_swsh_transform(
     257             :     const size_t l_max, const size_t number_of_radial_points,
     258             :     const gsl::not_null<SpinWeighted<ComplexDataVector, Spin>*>
     259             :         first_collocation,
     260             :     const NodalThenModalTypes&... collocations_then_coefficients) {
     261             :   static_assert(
     262             :       sizeof...(NodalThenModalTypes) % 2 == 1,
     263             :       "The number of nodal arguments passed to inverse_swsh_transform must "
     264             :       "equal the number of modal arguments, so the total number of arguments "
     265             :       "must be even.");
     266             :   detail::inverse_swsh_transform_impl<Representation>(
     267             :       l_max, number_of_radial_points,
     268             :       std::make_index_sequence<(sizeof...(collocations_then_coefficients) + 1) /
     269             :                                2>{},
     270             :       first_collocation, collocations_then_coefficients...);
     271             : }
     272             : 
     273             : /*!
     274             :  * \ingroup SwshGroup
     275             :  * \brief Perform an inverse libsharp spin-weighted spherical harmonic transform
     276             :  * on a single supplied `SpinWeighted<ComplexModalVector, Spin>`.
     277             :  *
     278             :  * \details This function returns a `SpinWeighted<ComplexDataVector, Spin>` by
     279             :  * value (causing an allocation). This is a simpler interface to the same
     280             :  * functionality as the \ref DataBoxGroup mutation compatible
     281             :  * `InverseSwshTransform`. If you have two or more vectors to transform at once,
     282             :  * consider the pass-by-pointer version of
     283             :  * `Spectral::Swsh::inverse_swsh_transform` or the \ref DataBoxGroup interface
     284             :  * `SwshTransform`, as they are more efficient for performing several transforms
     285             :  * at once.
     286             :  *
     287             :  * The input is a set of libsharp-compatible coefficients.
     288             :  * \see SwshTransform for more details on the mathematics of the libsharp
     289             :  * data structures.
     290             :  */
     291             : template <
     292             :     ComplexRepresentation Representation = ComplexRepresentation::Interleaved,
     293             :     int Spin>
     294           1 : SpinWeighted<ComplexDataVector, Spin> inverse_swsh_transform(
     295             :     size_t l_max, size_t number_of_radial_points,
     296             :     const SpinWeighted<ComplexModalVector, Spin>& libsharp_coefficients);
     297             : 
     298             : /*!
     299             :  * \ingroup SwshGroup
     300             :  * \brief A \ref DataBoxGroup mutate-compatible computational struct for
     301             :  * performing several spin-weighted spherical harmonic transforms. Internally
     302             :  * dispatches to libsharp.
     303             :  *
     304             :  * \details
     305             :  * Template Parameters:
     306             :  * - `Representation`: The element of the `ComplexRepresentation` enum which
     307             :  *   parameterizes how the data passed to libsharp will be represented. Two
     308             :  *   options are available:
     309             :  *  - `ComplexRepresentation:Interleaved`: indicates that the real and imaginary
     310             :  *    parts of the collocation values will be passed to libsharp as pointers
     311             :  *    into existing complex data structures, minimizing copies, but maintaining
     312             :  *    a stride of 2 for 'adjacent' real or imaginary values.
     313             :  *  - `ComplexRepresentation::RealsThenImags`: indicates that the real and
     314             :  *    imaginary parts of the collocation values will be passed to libsharp as
     315             :  *    separate contiguous blocks. At current, this introduces both allocations
     316             :  *    and copies.  **optimization note** In the future most of the allocations
     317             :  *    can be aggregated to calling code, which would pass in buffers by
     318             :  *    `not_null` pointers.
     319             :  *
     320             :  *  For performance-sensitive code, both options should be tested, as each
     321             :  *  strategy has trade-offs.
     322             :  * - `TagList`: A `tmpl::list` of Tags to be forward transformed. The tags must
     323             :  * represent the nodal data.
     324             :  *
     325             :  * \note The signs obtained from libsharp transformations must be handled
     326             :  * carefully. (In particular, it does not use the sign convention you will find
     327             :  * in [Wikipedia]
     328             :  * (https://en.wikipedia.org/wiki/Spin-weighted_spherical_harmonics)).
     329             :  * - libsharp deals only with the transformation of real values, so
     330             :  *   transformation of complex values must be done for real and imaginary parts
     331             :  *   separately.
     332             :  * - due to only transforming real components, it stores only the positive
     333             :  *   \f$m\f$ modes (as the rest would be redundant). Therefore, the negative
     334             :  *   \f$m\f$ modes must be inferred from conjugation and further sign changes.
     335             :  * - libsharp only has the capability of transforming positive spin weighted
     336             :  *   quantities. Therefore, additional steps are taken (involving further
     337             :  *   conjugation of the provided data) in order to use those utilities on
     338             :  *   negative spin-weighted quantities. The resulting modes have yet more sign
     339             :  *   changes that must be taken into account.
     340             :  *
     341             :  * The decomposition resulting from the libsharp transform for spin \f$s\f$ and
     342             :  * complex spin-weighted \f${}_s f\f$ can be represented mathematically as:
     343             :  *
     344             :  * \f{align*}{
     345             :  * {}_s f(\theta, \phi) = \sum_{\ell = 0}^{\ell_\mathrm{max}} \Bigg\{&
     346             :  * \left(\sum_{m = 0}^{\ell} a^\mathrm{sharp, real}_{l m} {}_s Y_{\ell
     347             :  * m}^\mathrm{sharp, real}\right) + \left(\sum_{m=1}^{\ell}
     348             :  * \left(a^\mathrm{sharp, real}_{l m}{}\right)^*
     349             :  * {}_s Y_{\ell -m}^\mathrm{sharp, real}\right) \notag\\
     350             :  * &+ i \left[\left(\sum_{m = 0}^{\ell} a^\mathrm{sharp, imag}_{l m} {}_s
     351             :  * Y_{\ell m}^\mathrm{sharp, imag}\right) + \left(\sum_{m=1}^{\ell}
     352             :  * \left(a^\mathrm{sharp, imag}_{l m}{}\right)^* {}_s Y_{\ell -m}^\mathrm{sharp,
     353             :  * imag} \right)\right] \Bigg\},
     354             :  * \f}
     355             :  *
     356             :  * where
     357             :  *
     358             :  * \f{align*}{
     359             :  * {}_s Y_{\ell m}^\mathrm{sharp, real} &=
     360             :  * \begin{cases}
     361             :  * (-1)^{s + 1} {}_s Y_{\ell m}, & \mathrm{for}\; s < 0, m \ge 0 \\
     362             :  * {}_s Y_{\ell m}, & \mathrm{for}\; s = 0, m \ge 0 \\
     363             :  * - {}_s Y_{\ell m}, & \mathrm{for}\; s > 0, m \ge 0 \\
     364             :  * (-1)^{s + m + 1} {}_s Y_{\ell m}, & \mathrm{for}\; s < 0, m < 0 \\
     365             :  * (-1)^{m} {}_s Y_{\ell m}, & \mathrm{for}\; s = 0, m < 0 \\
     366             :  * (-1)^{m + 1} {}_s Y_{\ell m}, & \mathrm{for}\; s > 0, m < 0
     367             :  * \end{cases} \\
     368             :  * &\equiv {}_s S_{\ell m}^{\mathrm{real}} {}_s Y_{\ell m}\\
     369             :  * {}_s Y_{\ell m}^\mathrm{sharp, imag} &=
     370             :  * \begin{cases}
     371             :  * (-1)^{s + 1} {}_s Y_{\ell m}, & \mathrm{for}\; s < 0, m \ge 0 \\
     372             :  * -{}_s Y_{\ell m}, & \mathrm{for}\; s = 0, m \ge 0 \\
     373             :  * {}_s Y_{\ell m}, & \mathrm{for}\; s > 0, m \ge 0 \\
     374             :  * (-1)^{s + m} {}_s Y_{\ell m}, & \mathrm{for}\; s < 0, m < 0 \\
     375             :  * (-1)^{m} {}_s Y_{\ell m}, & \mathrm{for}\; s = 0, m < 0 \\
     376             :  * (-1)^{m + 1} {}_s Y_{\ell m}, & \mathrm{for}\; s > 0, m < 0
     377             :  * \end{cases} \\
     378             :  * &\equiv {}_s S_{\ell m}^{\mathrm{real}} {}_s Y_{\ell m},
     379             :  * \f}
     380             :  *
     381             :  * where the unadorned \f${}_s Y_{\ell m}\f$ on the right-hand-sides follow the
     382             :  * (older) convention of \cite Goldberg1966uu. Note the phase in these
     383             :  * expressions is not completely standardized, so should be checked carefully
     384             :  * whenever coefficient data is directly manipulated.
     385             :  *
     386             :  * For reference, we can compute the relation between Goldberg spin-weighted
     387             :  * moments \f${}_s f_{\ell m}\f$, defined as
     388             :  *
     389             :  * \f[ {}_s f(\theta, \phi) = \sum_{\ell = 0}^{\ell_\mathrm{max}} \sum_{m =
     390             :  * -\ell}^{\ell} {}_s f_{\ell m} {}_s Y_{\ell m}
     391             :  * \f]
     392             :  *
     393             :  * so,
     394             :  * \f[
     395             :  * {}_s f_{\ell m} =
     396             :  * \begin{cases}
     397             :  * a_{\ell m}^{\mathrm{sharp}, \mathrm{real}}  {}_s S_{\ell m}^{\mathrm{real}} +
     398             :  * a_{\ell m}^{\mathrm{sharp}, \mathrm{imag}}  {}_s S_{\ell m}^{\mathrm{imag}} &
     399             :  * \mathrm{for} \; m \ge 0 \\
     400             :  * \left(a_{\ell -m}^{\mathrm{sharp}, \mathrm{real}}\right)^* {}_s S_{\ell
     401             :  * m}^{\mathrm{real}} + \left(a_{\ell -m}^{\mathrm{sharp},
     402             :  * \mathrm{imag}}\right)^* {}_s S_{\ell m}^{\mathrm{imag}} &
     403             :  * \mathrm{for} \; m < 0 \\
     404             :  * \end{cases} \f]
     405             :  *
     406             :  *
     407             :  * The resulting coefficients \f$a_{\ell m}\f$ are stored in a triangular,
     408             :  * \f$\ell\f$-varies-fastest configuration. So, for instance, the first
     409             :  * \f$\ell_\mathrm{max}\f$ entries contain the coefficients for \f$m=0\f$ and
     410             :  * all \f$\ell\f$s, and the next \f$\ell_\mathrm{max} - 1\f$ entries contain the
     411             :  * coefficients for \f$m=1\f$ and \f$1 \le \ell \le \ell_\mathrm{max} \f$, and
     412             :  * so on.
     413             :  */
     414             : template <typename TagList, ComplexRepresentation Representation =
     415             :                                 ComplexRepresentation::Interleaved>
     416           1 : struct SwshTransform;
     417             : 
     418             : /// \cond
     419             : template <typename... TransformTags, ComplexRepresentation Representation>
     420             : struct SwshTransform<tmpl::list<TransformTags...>, Representation> {
     421             :   static constexpr int spin =
     422             :       tmpl::front<tmpl::list<TransformTags...>>::type::type::spin;
     423             : 
     424             :   static_assert(tmpl2::flat_all_v<TransformTags::type::type::spin == spin...>,
     425             :                 "All Tags in TagList submitted to SwshTransform must have the "
     426             :                 "same spin weight.");
     427             : 
     428             :   using return_tags = tmpl::list<Tags::SwshTransform<TransformTags>...>;
     429             :   using argument_tags = tmpl::list<TransformTags..., Tags::LMaxBase,
     430             :                                    Tags::NumberOfRadialPointsBase>;
     431             : 
     432             :   static void apply(
     433             :       const gsl::not_null<
     434             :           typename Tags::SwshTransform<TransformTags>::type*>... coefficients,
     435             :       const typename TransformTags::type&... collocations, const size_t l_max,
     436             :       const size_t number_of_radial_points) {
     437             :     // forward to the version which takes parameter packs of vectors
     438             :     apply_to_vectors(make_not_null(&get(*coefficients))...,
     439             :                      get(collocations)..., l_max, number_of_radial_points);
     440             :   }
     441             : 
     442             :   // the convenience transform functions call the private member directly, so
     443             :   // need to be friends
     444             :   // redundant declaration due to forward declaration needs in earlier part of
     445             :   // file and friend requirements
     446             :   template <ComplexRepresentation FriendRepresentation, int FriendSpin,
     447             :             typename... CoefficientThenCollocationTypes, size_t... Is>
     448             :   // NOLINTNEXTLINE(readability-redundant-declaration)
     449             :   friend void detail::swsh_transform_impl(
     450             :       size_t, size_t, std::index_sequence<Is...>,
     451             :       gsl::not_null<SpinWeighted<ComplexModalVector, FriendSpin>*>,
     452             :       const CoefficientThenCollocationTypes&...);
     453             : 
     454             :   // friend declaration for helper function from `SwshDerivatives.hpp`
     455             :   template <typename Transform, typename FullTagList>
     456             :   friend struct detail::dispatch_to_transform;
     457             : 
     458             :  private:
     459             :   static void apply_to_vectors(
     460             :       const gsl::not_null<typename Tags::SwshTransform<
     461             :           TransformTags>::type::type*>... coefficients,
     462             :       const typename TransformTags::type::type&... collocations, size_t l_max,
     463             :       size_t number_of_radial_points);
     464             : };
     465             : /// \endcond
     466             : 
     467             : /*!
     468             :  * \ingroup SwshGroup
     469             :  * \brief A \ref DataBoxGroup mutate-compatible computational struct for
     470             :  * performing several spin-weighted inverse spherical harmonic transforms.
     471             :  * Internally dispatches to libsharp.
     472             :  *
     473             :  * \details
     474             :  * Template Parameters:
     475             :  * - `Representation`: The element of the `ComplexRepresentation` enum which
     476             :  *   parameterizes how the data passed to libsharp will be represented. Two
     477             :  *   options are available:
     478             :  *  - `ComplexRepresentation:Interleaved`: indicates that the real and imaginary
     479             :  *    parts of the collocation values will be passed to libsharp as pointers
     480             :  *    into existing complex data structures, minimizing copies, but maintaining
     481             :  *    a stride of 2 for 'adjacent' real or imaginary values.
     482             :  *  - `ComplexRepresentation::RealsThenImags`: indicates that the real and
     483             :  *    imaginary parts of the collocation values will be passed to libsharp as
     484             :  *    separate contiguous blocks. At current, this introduces both allocations
     485             :  *    and copies.  **optimization note** In the future most of the allocations
     486             :  *    can be aggregated to calling code, which would pass in buffers by
     487             :  *    `not_null` pointers.
     488             :  *
     489             :  *  For performance-sensitive code, both options should be tested, as each
     490             :  *  strategy has trade-offs.
     491             :  * - `TagList`: A `tmpl::list` of Tags to be inverse transformed. The tags must
     492             :  * represent the nodal data being transformed to.
     493             :  *
     494             :  * \see `SwshTransform` for mathematical notes regarding the libsharp modal
     495             :  * representation taken as input for this computational struct.
     496             :  */
     497             : template <typename TagList, ComplexRepresentation Representation =
     498             :                                 ComplexRepresentation::Interleaved>
     499           1 : struct InverseSwshTransform;
     500             : 
     501             : /// \cond
     502             : template <typename... TransformTags, ComplexRepresentation Representation>
     503             : struct InverseSwshTransform<tmpl::list<TransformTags...>, Representation> {
     504             :   static constexpr int spin =
     505             :       tmpl::front<tmpl::list<TransformTags...>>::type::type::spin;
     506             : 
     507             :   static_assert(
     508             :       tmpl2::flat_all_v<TransformTags ::type::type::spin == spin...>,
     509             :       "All Tags in TagList submitted to InverseSwshTransform must have the "
     510             :       "same spin weight.");
     511             : 
     512             :   using return_tags = tmpl::list<TransformTags...>;
     513             :   using argument_tags =
     514             :       tmpl::list<Tags::SwshTransform<TransformTags>..., Tags::LMaxBase,
     515             :                  Tags::NumberOfRadialPointsBase>;
     516             : 
     517             :   static void apply(
     518             :       const gsl::not_null<typename TransformTags::type*>... collocations,
     519             :       const typename Tags::SwshTransform<TransformTags>::type&... coefficients,
     520             :       const size_t l_max, const size_t number_of_radial_points) {
     521             :     // forward to the version which takes parameter packs of vectors
     522             :     apply_to_vectors(make_not_null(&get(*collocations))...,
     523             :                      get(coefficients)..., l_max, number_of_radial_points);
     524             :   }
     525             : 
     526             :   // the convenience transform functions call the private member directly, so
     527             :   // need to be friends
     528             :   // redundant declaration due to forward declaration needs in earlier part of
     529             :   // file and friend requirements
     530             :   template <ComplexRepresentation FriendRepresentation, int FriendSpin,
     531             :             typename... CollocationThenCoefficientTypes, size_t... Is>
     532             :   // NOLINTNEXTLINE(readability-redundant-declaration)
     533             :   friend void detail::inverse_swsh_transform_impl(
     534             :       size_t, size_t, std::index_sequence<Is...>,
     535             :       gsl::not_null<SpinWeighted<ComplexDataVector, FriendSpin>*>,
     536             :       const CollocationThenCoefficientTypes&...);
     537             : 
     538             :   // friend declaration for helper function from `SwshDerivatives.hpp`
     539             :   template <typename Transform, typename FullTagList>
     540             :   friend struct detail::dispatch_to_transform;
     541             : 
     542             :  private:
     543             :   static void apply_to_vectors(
     544             :       const gsl::not_null<typename TransformTags::type::type*>... collocations,
     545             :       const typename Tags::SwshTransform<
     546             :           TransformTags>::type::type&... coefficients,
     547             :       size_t l_max, size_t number_of_radial_points);
     548             : };
     549             : 
     550             : template <typename... TransformTags, ComplexRepresentation Representation>
     551             : void SwshTransform<tmpl::list<TransformTags...>, Representation>::
     552             :     apply_to_vectors(const gsl::not_null<typename Tags::SwshTransform<
     553             :                          TransformTags>::type::type*>... coefficients,
     554             :                      const typename TransformTags::type::type&... collocations,
     555             :                      const size_t l_max, const size_t number_of_radial_points) {
     556             :   EXPAND_PACK_LEFT_TO_RIGHT(coefficients->destructive_resize(
     557             :       size_of_libsharp_coefficient_vector(l_max) * number_of_radial_points));
     558             : 
     559             :   // assemble a list of pointers into the collocation point data. This is
     560             :   // required because libsharp expects pointers to pointers.
     561             :   std::vector<detail::ComplexDataView<Representation>> pre_transform_views;
     562             :   pre_transform_views.reserve(number_of_radial_points *
     563             :                               sizeof...(TransformTags));
     564             :   std::vector<double*> pre_transform_collocation_data;
     565             :   pre_transform_collocation_data.reserve(2 * number_of_radial_points *
     566             :                                          sizeof...(TransformTags));
     567             : 
     568             :   // clang-tidy: const-cast, object is temporarily modified and returned to
     569             :   // original state
     570             :   EXPAND_PACK_LEFT_TO_RIGHT(detail::append_libsharp_collocation_pointers(
     571             :       make_not_null(&pre_transform_collocation_data),
     572             :       make_not_null(&pre_transform_views),
     573             :       make_not_null(&const_cast<typename TransformTags::type::type&>(  // NOLINT
     574             :                          collocations)
     575             :                          .data()),
     576             :       l_max, spin >= 0));
     577             : 
     578             :   std::vector<std::complex<double>*> post_transform_coefficient_data;
     579             :   post_transform_coefficient_data.reserve(2 * number_of_radial_points *
     580             :                                           sizeof...(TransformTags));
     581             : 
     582             :   EXPAND_PACK_LEFT_TO_RIGHT(detail::append_libsharp_coefficient_pointers(
     583             :       make_not_null(&post_transform_coefficient_data),
     584             :       make_not_null(&coefficients->data()), l_max));
     585             : 
     586             :   const size_t num_transforms =
     587             :       (spin == 0 ? 2 : 1) * number_of_radial_points * sizeof...(TransformTags);
     588             :   const auto* collocation_metadata =
     589             :       &cached_collocation_metadata<Representation>(l_max);
     590             :   const auto* alm_info =
     591             :       cached_coefficients_metadata(l_max).get_sharp_alm_info();
     592             : 
     593             :   detail::execute_libsharp_transform_set(
     594             :       SHARP_MAP2ALM, spin, make_not_null(&post_transform_coefficient_data),
     595             :       make_not_null(&pre_transform_collocation_data),
     596             :       make_not_null(collocation_metadata), alm_info, num_transforms);
     597             : 
     598             :   detail::conjugate_views<spin>(make_not_null(&pre_transform_views));
     599             : }
     600             : 
     601             : template <typename... TransformTags, ComplexRepresentation Representation>
     602             : void InverseSwshTransform<tmpl::list<TransformTags...>, Representation>::
     603             :     apply_to_vectors(const gsl::not_null<
     604             :                          typename TransformTags::type::type*>... collocations,
     605             :                      const typename Tags::SwshTransform<
     606             :                          TransformTags>::type::type&... coefficients,
     607             :                      const size_t l_max, const size_t number_of_radial_points) {
     608             :   EXPAND_PACK_LEFT_TO_RIGHT(collocations->destructive_resize(
     609             :       number_of_swsh_collocation_points(l_max) * number_of_radial_points));
     610             : 
     611             :   std::vector<std::complex<double>*> pre_transform_coefficient_data;
     612             :   pre_transform_coefficient_data.reserve(2 * number_of_radial_points *
     613             :                                          sizeof...(TransformTags));
     614             :   // clang-tidy: const-cast, object is temporarily modified and returned to
     615             :   // original state
     616             :   EXPAND_PACK_LEFT_TO_RIGHT(detail::append_libsharp_coefficient_pointers(
     617             :       make_not_null(&pre_transform_coefficient_data),
     618             :       make_not_null(&const_cast<typename Tags::SwshTransform<  // NOLINT
     619             :                          TransformTags>::type::type&>(coefficients)
     620             :                          .data()),
     621             :       l_max));
     622             : 
     623             :   std::vector<detail::ComplexDataView<Representation>> post_transform_views;
     624             :   post_transform_views.reserve(number_of_radial_points *
     625             :                                sizeof...(TransformTags));
     626             :   std::vector<double*> post_transform_collocation_data;
     627             :   post_transform_collocation_data.reserve(2 * number_of_radial_points *
     628             :                                           sizeof...(TransformTags));
     629             : 
     630             :   EXPAND_PACK_LEFT_TO_RIGHT(detail::append_libsharp_collocation_pointers(
     631             :       make_not_null(&post_transform_collocation_data),
     632             :       make_not_null(&post_transform_views),
     633             :       make_not_null(&collocations->data()), l_max, true));
     634             : 
     635             :   // libsharp considers two arrays per transform when spin is not zero.
     636             :   const size_t num_transforms =
     637             :       (spin == 0 ? 2 : 1) * number_of_radial_points * sizeof...(TransformTags);
     638             :   const auto* collocation_metadata =
     639             :       &cached_collocation_metadata<Representation>(l_max);
     640             :   const auto* alm_info =
     641             :       cached_coefficients_metadata(l_max).get_sharp_alm_info();
     642             : 
     643             :   detail::execute_libsharp_transform_set(
     644             :       SHARP_ALM2MAP, spin, make_not_null(&pre_transform_coefficient_data),
     645             :       make_not_null(&post_transform_collocation_data),
     646             :       make_not_null(collocation_metadata), alm_info, num_transforms);
     647             : 
     648             :   detail::conjugate_views<spin>(make_not_null(&post_transform_views));
     649             : 
     650             :   // The inverse transformed collocation data has just been placed in the
     651             :   // memory blocks controlled by the `ComplexDataView`s. Finally, that data
     652             :   // must be flushed back to the Variables.
     653             :   for (auto& view : post_transform_views) {
     654             :     view.copy_back_to_source();
     655             :   }
     656             : }
     657             : /// \endcond
     658             : 
     659             : namespace detail {
     660             : 
     661             : template <ComplexRepresentation Representation, int Spin,
     662             :           typename... ModalThenNodalTypes, size_t... Is>
     663             : void swsh_transform_impl(
     664             :     const size_t l_max, const size_t number_of_radial_points,
     665             :     std::index_sequence<Is...> /*meta*/,
     666             :     const gsl::not_null<SpinWeighted<ComplexModalVector, Spin>*>
     667             :         first_coefficient,
     668             :     const ModalThenNodalTypes&... coefficients_then_collocations) {
     669             :   SwshTransform<
     670             :       tmpl::list<::Tags::SpinWeighted<::Tags::TempScalar<Is, ComplexDataVector>,
     671             :                                       std::integral_constant<int, Spin>>...>>::
     672             :       apply_to_vectors(first_coefficient, coefficients_then_collocations...,
     673             :                        l_max, number_of_radial_points);
     674             : }
     675             : 
     676             : template <ComplexRepresentation Representation, int Spin,
     677             :           typename... NodalThenModalTypes, size_t... Is>
     678             : void inverse_swsh_transform_impl(
     679             :     const size_t l_max, const size_t number_of_radial_points,
     680             :     std::index_sequence<Is...> /*meta*/,
     681             :     const gsl::not_null<SpinWeighted<ComplexDataVector, Spin>*>
     682             :         first_collocation,
     683             :     const NodalThenModalTypes&... collocations_then_coefficients) {
     684             :   InverseSwshTransform<
     685             :       tmpl::list<::Tags::SpinWeighted<::Tags::TempScalar<Is, ComplexDataVector>,
     686             :                                       std::integral_constant<int, Spin>>...>>::
     687             :       apply_to_vectors(first_collocation, collocations_then_coefficients...,
     688             :                        l_max, number_of_radial_points);
     689             : }
     690             : 
     691             : // A metafunction for binning a provided tag list into `SwshTransform` objects
     692             : // according to spin-weight
     693             : template <int MinSpin, ComplexRepresentation Representation, typename TagList,
     694             :           typename IndexSequence>
     695             : struct make_transform_list_impl;
     696             : 
     697             : template <int MinSpin, ComplexRepresentation Representation, typename TagList,
     698             :           int... Is>
     699             : struct make_transform_list_impl<MinSpin, Representation, TagList,
     700             :                                 std::integer_sequence<int, Is...>> {
     701             :   using type = tmpl::flatten<tmpl::list<tmpl::conditional_t<
     702             :       not std::is_same_v<get_tags_with_spin<Is + MinSpin, TagList>,
     703             :                          tmpl::list<>>,
     704             :       SwshTransform<get_tags_with_spin<Is + MinSpin, TagList>, Representation>,
     705             :       tmpl::list<>>...>>;
     706             : };
     707             : 
     708             : // A metafunction for binning a provided tag list into `InverseSwshTransform`
     709             : // objects according to spin-weight
     710             : template <int MinSpin, ComplexRepresentation Representation, typename TagList,
     711             :           typename IndexSequence>
     712             : struct make_inverse_transform_list_impl;
     713             : 
     714             : template <int MinSpin, ComplexRepresentation Representation, typename TagList,
     715             :           int... Is>
     716             : struct make_inverse_transform_list_impl<MinSpin, Representation, TagList,
     717             :                                         std::integer_sequence<int, Is...>> {
     718             :   using type = tmpl::flatten<tmpl::list<tmpl::conditional_t<
     719             :       not std::is_same_v<get_tags_with_spin<Is + MinSpin, TagList>,
     720             :                          tmpl::list<>>,
     721             :       InverseSwshTransform<get_tags_with_spin<Is + MinSpin, TagList>,
     722             :                            Representation>,
     723             :       tmpl::list<>>...>>;
     724             : };
     725             : }  // namespace detail
     726             : 
     727             : /// @{
     728             : /// \ingroup SwshGroup
     729             : /// \brief Assemble a `tmpl::list` of `SwshTransform`s or
     730             : /// `InverseSwshTransform`s given a list of tags `TagList` that need to be
     731             : /// transformed. The `Representation` is the
     732             : /// `Spectral::Swsh::ComplexRepresentation` to use for the transformations.
     733             : ///
     734             : /// \details Up to five `SwshTransform`s or `InverseSwshTransform`s will be
     735             : /// returned, corresponding to the possible spin values. Any number of
     736             : /// transformations are aggregated into that set of `SwshTransform`s (or
     737             : /// `InverseSwshTransform`s). The number of transforms is up to five because the
     738             : /// libsharp utility only has capability to perform spin-weighted spherical
     739             : /// harmonic transforms for integer spin-weights from -2 to 2.
     740             : ///
     741             : /// \snippet Test_SwshTransform.cpp make_transform_list
     742             : template <ComplexRepresentation Representation, typename TagList>
     743           1 : using make_transform_list = typename detail::make_transform_list_impl<
     744             :     -2, Representation, TagList,
     745             :     decltype(std::make_integer_sequence<int, 5>{})>::type;
     746             : 
     747             : template <ComplexRepresentation Representation, typename TagList>
     748           1 : using make_inverse_transform_list =
     749             :     typename detail::make_inverse_transform_list_impl<
     750             :         -2, Representation, TagList,
     751             :         decltype(std::make_integer_sequence<int, 5>{})>::type;
     752             : /// @}
     753             : 
     754             : /// \ingroup SwshGroup
     755             : /// \brief Assemble a `tmpl::list` of `SwshTransform`s given a list of
     756             : /// `Spectral::Swsh::Tags::Derivative<Tag, Derivative>` that need to be
     757             : /// computed. The `SwshTransform`s constructed by this type alias correspond to
     758             : /// the `Tag`s in the list.
     759             : ///
     760             : /// \details This is intended as a convenience utility for the first step of a
     761             : /// derivative routine, where one transforms the set of fields for which
     762             : /// derivatives are required.
     763             : ///
     764             : /// \snippet Test_SwshTransform.cpp make_transform_from_derivative_tags
     765             : template <ComplexRepresentation Representation, typename DerivativeTagList>
     766           1 : using make_transform_list_from_derivative_tags =
     767             :     typename detail::make_transform_list_impl<
     768             :         -2, Representation,
     769             :         tmpl::transform<DerivativeTagList,
     770             :                         tmpl::bind<db::remove_tag_prefix, tmpl::_1>>,
     771             :         decltype(std::make_integer_sequence<int, 5>{})>::type;
     772             : 
     773             : /// \ingroup SwshGroup
     774             : /// \brief Convert spin-weighted spherical harmonic data to a new set of
     775             : /// collocation points (either downsampling or upsampling)
     776             : template <int Spin>
     777           1 : void interpolate_to_collocation(
     778             :     gsl::not_null<SpinWeighted<ComplexDataVector, Spin>*> target,
     779             :     const SpinWeighted<ComplexDataVector, Spin>& source, size_t target_l_max,
     780             :     size_t source_l_max, size_t number_of_radial_points);
     781             : 
     782             : }  // namespace Swsh
     783             : }  // namespace Spectral

Generated by: LCOV version 1.14