SpECTRE Documentation Coverage Report
Current view: top level - NumericalAlgorithms/Spectral - SwshCoefficients.hpp Hit Total Coverage
Commit: 1346ad6481207e62443c625b65dc162a206d7d67 Lines: 28 50 56.0 %
Date: 2024-04-25 18:47:43
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 <memory>
       8             : #include <sharp_cxx.h>
       9             : 
      10             : #include "DataStructures/ComplexModalVector.hpp"
      11             : #include "DataStructures/SpinWeighted.hpp"
      12             : #include "NumericalAlgorithms/Spectral/SwshCollocation.hpp"
      13             : #include "NumericalAlgorithms/Spectral/SwshSettings.hpp"
      14             : #include "Utilities/ConstantExpressions.hpp"
      15             : #include "Utilities/ForceInline.hpp"
      16             : #include "Utilities/Gsl.hpp"
      17             : 
      18             : // IWYU pragma: no_forward_declare SpinWeighted
      19             : 
      20             : namespace Spectral {
      21             : namespace Swsh {
      22             : 
      23             : /// \ingroup SwshGroup
      24             : /// \brief Convenience function for determining the number of spin-weighted
      25             : /// spherical harmonics coefficients that are stored for a given `l_max`
      26             : ///
      27             : /// \details This includes the factor of 2 associated with needing
      28             : /// to store both the transform of the real and imaginary parts, so is the
      29             : /// full size of the result of a libsharp swsh transform.
      30             : ///
      31             : /// \note Assumes the triangular libsharp representation is used.
      32             : constexpr SPECTRE_ALWAYS_INLINE size_t
      33           1 : size_of_libsharp_coefficient_vector(const size_t l_max) {
      34             :   return (l_max + 1) * (l_max + 2);  // "triangular" representation
      35             : }
      36             : 
      37             : /*!
      38             :  * \ingroup SwshGroup
      39             :  * \brief Compute the relative sign change necessary to convert between the
      40             :  * libsharp basis for spin weight `from_spin_weight` to the basis for spin
      41             :  * weight `to_spin_weight`, for the real component coefficients if `real` is
      42             :  * true, otherwise for the imaginary component coefficients. The sign change for
      43             :  * a given coefficient is equivalent to the product of
      44             :  * `sharp_swsh_sign(from_spin, m, real) * sharp_swsh_sign(to_spin, m,
      45             :  * real)`. Due to the form of the signs, it does not end up depending on m (the
      46             :  * m's in the power of \f$-1\f$'s cancel).
      47             :  * For full details of the libsharp sign conventions, see the documentation for
      48             :  * TransformJob.
      49             :  *
      50             :  * \details The sign change is obtained by the
      51             :  * difference between the libsharp convention and the convention which uses:
      52             :  *
      53             :  * \f[
      54             :  * {}_s Y_{\ell m} (\theta, \phi) = (-1)^m \sqrt{\frac{2 l + 1}{4 \pi}}
      55             :  * D^{\ell}{}_{-m s}(\phi, \theta, 0).
      56             :  * \f]
      57             :  *
      58             :  * See \cite Goldberg1966uu
      59             :  */
      60           1 : constexpr SPECTRE_ALWAYS_INLINE double sharp_swsh_sign_change(
      61             :     const int from_spin_weight, const int to_spin_weight, const bool real) {
      62             :   if (real) {
      63             :     return (from_spin_weight == 0 ? -1.0 : 1.0) *
      64             :            (from_spin_weight >= 0 ? -1.0 : 1.0) *
      65             :            ((from_spin_weight < 0 and (from_spin_weight % 2 == 0)) ? -1.0
      66             :                                                                    : 1.0) *
      67             :            (to_spin_weight == 0 ? -1.0 : 1.0) *
      68             :            (to_spin_weight >= 0 ? -1.0 : 1.0) *
      69             :            ((to_spin_weight < 0 and (to_spin_weight % 2 == 0)) ? -1.0 : 1.0);
      70             :   }
      71             :   return (from_spin_weight == 0 ? -1.0 : 1.0) *
      72             :          ((from_spin_weight < 0 and (from_spin_weight % 2 == 0)) ? 1.0 : -1.0) *
      73             :          (to_spin_weight == 0 ? -1.0 : 1.0) *
      74             :          ((to_spin_weight < 0 and (to_spin_weight % 2 == 0)) ? 1.0 : -1.0);
      75             : }
      76             : 
      77             : /*!
      78             :  * \ingroup SwshGroup
      79             :  * \brief Compute the sign change between the libsharp convention and the set
      80             :  * of spin-weighted spherical harmonics given by the relation to the Wigner
      81             :  * rotation matrices.
      82             :  *
      83             :  * \details The sign change is obtained via the difference between the libsharp
      84             :  * convention and the convention which uses:
      85             :  *
      86             :  * \f[
      87             :  * {}_s Y_{\ell m} (\theta, \phi) = (-1)^m \sqrt{\frac{2 l + 1}{4 \pi}}
      88             :  * D^{\ell}{}_{-m s}(\phi, \theta, 0).
      89             :  * \f]
      90             :  *
      91             :  * See \cite Goldberg1966uu.
      92             :  * The sign change is computed for the real component coefficients if `real` is
      93             :  * true, otherwise for the imaginary component coefficients. For full details on
      94             :  * the sign convention used in libsharp, see the documentation for TransformJob.
      95             :  * This function outputs the \f$\mathrm{sign}(m, s, \mathrm{real})\f$ necessary
      96             :  * to produce the conversion between Goldberg moments and libsharp moments:
      97             :  *
      98             :  * \f{align*}{
      99             :  * {}_s Y_{\ell m}^{\mathrm{real}, \mathrm{sharp}}  =& \mathrm{sign}(m, s,
     100             :  * \mathrm{real=true}) {}_s Y_{\ell m}^{\mathrm{Goldberg}}\\
     101             :  * {}_s Y_{\ell m}^{\mathrm{imag}, \mathrm{sharp}}  =&
     102             :  * \mathrm{sign}(m, s, \mathrm{real=false}) {}_s Y_{\ell
     103             :  * m}^{\mathrm{Goldberg}}.
     104             :  * \f}
     105             :  *
     106             :  * Note that in this equation, the "real" and "imag" superscripts refer to the
     107             :  * set of basis functions used for the decomposition of the real and imaginary
     108             :  * part of the spin-weighted collocation points, not real or imaginary parts of
     109             :  * the basis functions themselves.
     110             :  */
     111           1 : constexpr SPECTRE_ALWAYS_INLINE double sharp_swsh_sign(const int spin_weight,
     112             :                                                        const int m,
     113             :                                                        const bool real) {
     114             :   if (real) {
     115             :     if (m >= 0) {
     116             :       return (spin_weight > 0 ? -1.0 : 1.0) *
     117             :              ((spin_weight < 0 and (spin_weight % 2 == 0)) ? -1.0 : 1.0);
     118             :     }
     119             :     return (spin_weight == 0 ? -1.0 : 1.0) *
     120             :            ((spin_weight >= 0 and (m % 2 == 0)) ? -1.0 : 1.0) *
     121             :            (spin_weight < 0 and (m + spin_weight) % 2 == 0 ? -1.0 : 1.0);
     122             :   }
     123             :   if (m >= 0) {
     124             :     return (spin_weight == 0 ? -1.0 : 1.0) *
     125             :            ((spin_weight < 0 and (spin_weight % 2 == 0)) ? 1.0 : -1.0);
     126             :   }
     127             :   return (spin_weight == 0 ? -1.0 : 1.0) *
     128             :          ((spin_weight >= 0 and (m % 2 == 0)) ? -1.0 : 1.0) *
     129             :          ((spin_weight < 0 and (m + spin_weight) % 2 != 0) ? -1.0 : 1.0);
     130             : }
     131             : 
     132             : namespace detail {
     133             : struct DestroySharpAlm {
     134             :   void operator()(sharp_alm_info* to_delete) {
     135             :     sharp_destroy_alm_info(to_delete);
     136             :   }
     137             : };
     138             : }  // namespace detail
     139             : 
     140             : /// Points to a single pair of modes in a libsharp-compatible
     141             : /// spin-weighted spherical harmonic modal representation.
     142           1 : struct LibsharpCoefficientInfo {
     143           0 :   size_t transform_of_real_part_offset;
     144           0 :   size_t transform_of_imag_part_offset;
     145           0 :   size_t l_max;
     146           0 :   size_t l;
     147           0 :   size_t m;
     148             : };
     149             : 
     150             : /*!
     151             :  * \ingroup SwshGroup
     152             :  * \brief A container for libsharp metadata for the spin-weighted spherical
     153             :  * harmonics modal representation.
     154             :  *
     155             :  * \details
     156             :  * The CoefficientsMetadata class acts as a memory-safe container for a
     157             :  * `sharp_alm_info*`, required for use of libsharp transform utilities.
     158             :  * The libsharp utilities are currently constructed to only provide user
     159             :  * functions with collocation data for spin-weighted functions and
     160             :  * derivatives.  This class also provides an iterator for
     161             :  * easily traversing a libsharp-compatible modal representation.
     162             :  *
     163             :  * \note The libsharp representation of coefficients is altered from the
     164             :  * standard mathematical definitions in a nontrivial way. There are a number of
     165             :  * important features to the data storage of the coefficients.
     166             :  * - they are stored as a set of complex values, but each vector of complex
     167             :  *   values is the transform of only the real or imaginary part of the
     168             :  *   collocation data
     169             :  * - because each vector of complex coefficients is related to the transform of
     170             :  *   a set of doubles, only (about) half of the m's are stored (m >= 0), because
     171             :  *   the remaining m modes are determinable by conjugation from the positive m
     172             :  *   modes, given that they represent the transform of a purely real or purely
     173             :  *   imaginary collocation quantity
     174             :  * - they are stored in an l-varies-fastest, triangular representation. To be
     175             :  *   concrete, for an l_max=2, the order of coefficient storage is (l, m):
     176             :  *   [(0, 0), (1, 0), (2, 0), (1, 1), (2, 1), (2, 2)]
     177             :  * - due to the restriction of representing only the transform of real
     178             :  *   quantities, the m=0 modes always have vanishing imaginary component.
     179             :  */
     180           1 : class CoefficientsMetadata {
     181             :  public:
     182             :   /// An iterator for easily traversing a libsharp-compatible spin-weighted
     183             :   /// spherical harmonic modal representation.
     184             :   /// The `operator*()` returns a `LibsharpCoefficientInfo`, which  contains two
     185             :   /// offsets, `transform_of_real_part_offset` and
     186             :   /// `transform_of_imag_part_offset`, and the `l_max`, `l` and `m` associated
     187             :   /// with the values at those offsets.
     188             :   ///
     189             :   /// \note this currently assumes, as do many of the utilities in this file,
     190             :   /// that the libsharp representation is chosen to be the triangular
     191             :   /// coefficient representation. If alternative representations are desired,
     192             :   /// alterations will be needed.
     193           1 :   class CoefficientsIndexIterator {
     194             :    public:
     195           0 :     explicit CoefficientsIndexIterator(const size_t l_max,
     196             :                                        const size_t start_l = 0,
     197             :                                        const size_t start_m = 0)
     198             :         : m_{start_m}, l_{start_l}, l_max_{l_max} {}
     199             : 
     200           0 :     LibsharpCoefficientInfo operator*() const {
     201             :       // permit dereferencing the iterator only if the return represents a
     202             :       // viable location in the coefficient vector
     203             :       ASSERT(l_ <= l_max_ && m_ <= l_max_, "coefficients iterator overflow");
     204             :       size_t offset = ((3 + 2 * l_max_ - m_) * m_) / 2 + l_ - m_;
     205             :       return LibsharpCoefficientInfo{
     206             :           offset,
     207             :           offset +
     208             :               Spectral::Swsh::size_of_libsharp_coefficient_vector(l_max_) / 2,
     209             :           l_max_, l_, m_};
     210             :     }
     211             : 
     212             :     /// advance the iterator by one position (prefix)
     213           1 :     CoefficientsIndexIterator& operator++() {
     214             :       // permit altering the iterator only if the new value is between the
     215             :       // anticipated begin and end, inclusive
     216             :       ASSERT(l_ <= l_max_ && m_ <= l_max_, "coefficients iterator overflow");
     217             :       if (l_ == l_max_) {
     218             :         ++m_;
     219             :         l_ = m_;
     220             :       } else {
     221             :         ++l_;
     222             :       }
     223             :       return *this;
     224             :     };
     225             : 
     226             :     /// advance the iterator by one position (postfix)
     227             :     // NOLINTNEXTLINE(readability-const-return-type)
     228           1 :     const CoefficientsIndexIterator operator++(int) {
     229             :       auto pre_increment = *this;
     230             :       ++*this;
     231             :       return pre_increment;
     232             :     }
     233             : 
     234             :     /// retreat the iterator by one position (prefix)
     235           1 :     CoefficientsIndexIterator& operator--() {
     236             :       // permit altering the iterator only if the new value is between the
     237             :       // anticipated begin and end, inclusive
     238             :       ASSERT(l_ <= l_max_ + 1 && m_ <= l_max_ + 1,
     239             :              "coefficients iterator overflow");
     240             :       if (l_ == m_) {
     241             :         --m_;
     242             :         l_ = l_max_;
     243             :       } else {
     244             :         --l_;
     245             :       }
     246             :       return *this;
     247             :     }
     248             : 
     249             :     /// retreat the iterator by one position (postfix)
     250             :     // NOLINTNEXTLINE(readability-const-return-type)
     251           1 :     const CoefficientsIndexIterator operator--(int) {
     252             :       auto pre_decrement = *this;
     253             :       --*this;
     254             :       return pre_decrement;
     255             :     }
     256             : 
     257             :     /// @{
     258             :     /// (In)Equivalence checks the object as well as the l and m current
     259             :     /// position.
     260           1 :     bool operator==(const CoefficientsIndexIterator& rhs) const {
     261             :       return m_ == rhs.m_ and l_ == rhs.l_ and l_max_ == rhs.l_max_;
     262             :     }
     263           1 :     bool operator!=(const CoefficientsIndexIterator& rhs) const {
     264             :       return not(*this == rhs);
     265             :     }
     266             :     /// @}
     267             : 
     268             :    private:
     269           0 :     size_t m_;
     270           0 :     size_t l_;
     271           0 :     size_t l_max_;
     272             :   };
     273             : 
     274           0 :   explicit CoefficientsMetadata(size_t l_max);
     275             : 
     276           0 :   ~CoefficientsMetadata() = default;
     277           0 :   CoefficientsMetadata() = default;
     278           0 :   CoefficientsMetadata(const CoefficientsMetadata&) = delete;
     279           0 :   CoefficientsMetadata(CoefficientsMetadata&&) = default;
     280           0 :   CoefficientsMetadata& operator=(const CoefficientsMetadata&) = delete;
     281           0 :   CoefficientsMetadata& operator=(CoefficientsMetadata&&) = default;
     282           0 :   sharp_alm_info* get_sharp_alm_info() const { return alm_info_.get(); }
     283             : 
     284           0 :   size_t l_max() const { return l_max_; }
     285             : 
     286             :   /// returns the number of (complex) entries in a libsharp-compatible
     287             :   /// coefficients vector. This includes the factor of 2 associated with needing
     288             :   /// to store both the transform of the real and imaginary parts, so is the
     289             :   /// full size of the result of a libsharp swsh transform.
     290           1 :   size_t size() const { return size_of_libsharp_coefficient_vector(l_max_); }
     291             : 
     292             :   /// @{
     293             :   /// \brief Get a bidirectional iterator to the start of the series of modes.
     294           1 :   CoefficientsMetadata::CoefficientsIndexIterator begin() const {
     295             :     return CoefficientsIndexIterator(l_max_, 0, 0);
     296             :   }
     297           1 :   CoefficientsMetadata::CoefficientsIndexIterator cbegin() const {
     298             :     return begin();
     299             :   }
     300             :   /// @}
     301             : 
     302             :   /// @{
     303             :   /// \brief Get a bidirectional iterator to the end of the series of modes.
     304           1 :   CoefficientsMetadata::CoefficientsIndexIterator end() const {
     305             :     return CoefficientsIndexIterator(l_max_, l_max_ + 1, l_max_ + 1);
     306             :   }
     307           1 :   CoefficientsMetadata::CoefficientsIndexIterator cend() const { return end(); }
     308             :   /// @}
     309             : 
     310             :  private:
     311           0 :   std::unique_ptr<sharp_alm_info, detail::DestroySharpAlm> alm_info_;
     312           0 :   size_t l_max_ = 0;
     313             : };
     314             : 
     315             : /*!
     316             :  * \ingroup SwshGroup
     317             :  * \brief Generation function for obtaining a `CoefficientsMetadata` object
     318             :  * which is computed by the libsharp calls only once, then lazily cached as a
     319             :  * singleton via a static member of a function template. This is the preferred
     320             :  * method for obtaining a `CoefficientsMetadata` when the `l_max` is not very
     321             :  * large
     322             :  *
     323             :  * See the comments in the similar implementation found in `SwshCollocation.hpp`
     324             :  * for more details on the lazy cache.
     325             :  */
     326           1 : const CoefficientsMetadata& cached_coefficients_metadata(size_t l_max);
     327             : 
     328             : /// @{
     329             : /*!
     330             :  * \ingroup SwshGroup
     331             :  * \brief Compute the mode coefficient for the convention of
     332             :  * \cite Goldberg1966uu.
     333             :  *
     334             :  * \details  See the documentation for `TransformJob` for complete
     335             :  * details on the libsharp and Goldberg coefficient representations.
     336             :  * This interface takes a `LibsharpCoefficientInfo`, so that iterating over the
     337             :  * libsharp data structure and performing computations based on the
     338             :  * corresponding Goldberg modes is convenient. Two functions are provided, one
     339             :  * for the positive m modes in the Goldberg representation, and one for the
     340             :  * negative m modes, as the distinction is not made by the coefficient iterator.
     341             :  *
     342             :  * \param coefficient_info An iterator which stores an \f$l\f$ and \f$|m|\f$
     343             :  * for the mode to be converted to the Goldberg form.
     344             :  * \param libsharp_modes The libsharp-compatible modal storage to be accessed
     345             :  * \param radial_offset The index of which angular slice is desired. Modes for
     346             :  * concentric spherical shells are stored as consecutive blocks of angular
     347             :  * modes.
     348             :  */
     349             : template <int Spin>
     350           1 : std::complex<double> libsharp_mode_to_goldberg_plus_m(
     351             :     const LibsharpCoefficientInfo& coefficient_info,
     352             :     const SpinWeighted<ComplexModalVector, Spin>& libsharp_modes,
     353             :     size_t radial_offset);
     354             : 
     355             : template <int Spin>
     356           1 : std::complex<double> libsharp_mode_to_goldberg_minus_m(
     357             :     const LibsharpCoefficientInfo& coefficient_info,
     358             :     const SpinWeighted<ComplexModalVector, Spin>& libsharp_modes,
     359             :     size_t radial_offset);
     360             : /// @}
     361             : 
     362             : /*!
     363             :  * \ingroup SwshGroup
     364             :  * \brief Compute the mode coefficient for the convention of
     365             :  * \cite Goldberg1966uu. See the documentation for `TransformJob` for complete
     366             :  * details on the libsharp and Goldberg coefficient representations.
     367             :  *
     368             :  * \details This interface extracts the (`l`, `m`) Goldberg mode from the
     369             :  * provided libsharp-compatible `libsharp_modes`, at angular slice
     370             :  * `radial_offset` (Modes for concentric spherical shells are stored as
     371             :  * consecutive blocks of angular modes). `l_max` must also be specified to
     372             :  * determine the representation details.
     373             :  */
     374             : template <int Spin>
     375           1 : std::complex<double> libsharp_mode_to_goldberg(
     376             :     size_t l, int m, size_t l_max,
     377             :     const SpinWeighted<ComplexModalVector, Spin>& libsharp_modes,
     378             :     size_t radial_offset);
     379             : 
     380             : /*!
     381             :  * \ingroup SwshGroup
     382             :  * \brief Set modes of a libsharp-compatible data structure by specifying the
     383             :  * modes in the \cite Goldberg1966uu representation.
     384             :  *
     385             :  * \details This interface takes a `LibsharpCoefficientInfo`, so that iterating
     386             :  * over the libsharp data structure and performing edits based on the
     387             :  * corresponding Goldberg modes is convenient.
     388             :  *
     389             :  * \param coefficient_info An iterator which stores an \f$l\f$ and \f$|m|\f$
     390             :  * for the mode to be written by the input Goldberg modes. Note that both the
     391             :  * \f$+m\f$ and \f$-m\f$ modes must be simultaneously changed, due to the
     392             :  * representation details. See discussion in `TransformJob` for details.
     393             :  * \param libsharp_modes The libsharp-compatible modal storage to be altered.
     394             :  * \param radial_offset The index of which angular slice is desired. Modes for
     395             :  * concentric spherical shells are stored as consecutive blocks of angular
     396             :  * modes.
     397             :  * \param goldberg_plus_m_mode_value The coefficient in the Goldberg
     398             :  * representation (\f$l\f$, \f$m\f$)
     399             :  * \param goldberg_minus_m_mode_value The coefficient in the Goldberg
     400             :  * representation (\f$l\f$, \f$-m\f$)
     401             :  */
     402             : template <int Spin>
     403           1 : void goldberg_modes_to_libsharp_modes_single_pair(
     404             :     const LibsharpCoefficientInfo& coefficient_info,
     405             :     gsl::not_null<SpinWeighted<ComplexModalVector, Spin>*> libsharp_modes,
     406             :     size_t radial_offset, std::complex<double> goldberg_plus_m_mode_value,
     407             :     std::complex<double> goldberg_minus_m_mode_value);
     408             : 
     409             : /*!
     410             :  * \ingroup SwshGroup
     411             :  * \brief Set modes of a libsharp-compatible data structure by specifying the
     412             :  * modes in the \cite Goldberg1966uu representation.
     413             :  *
     414             :  * \details This interface sets the (\f$l\f$, \f$\pm m\f$), modes in a
     415             :  * libsharp-compatible representation from modes specified in the Goldberg
     416             :  * representation. Note that both the \f$+m\f$ and \f$-m\f$ modes must be
     417             :  * simultaneously changed, due to the representation details. See discussion in
     418             :  * `TransformJob` for details.
     419             :  * \param libsharp_modes The libsharp-compatible modal storage to be altered.
     420             :  * \param radial_offset The index of which angular slice is desired. Modes for
     421             :  * concentric spherical shells are stored as consecutive blocks of angular
     422             :  * modes.
     423             :  * \param goldberg_plus_m_mode_value The coefficient in the Goldberg
     424             :  * representation (\f$l\f$, \f$m\f$)
     425             :  * \param goldberg_minus_m_mode_value The coefficient in the Goldberg
     426             :  * representation (\f$l\f$, \f$-m\f$)
     427             :  * \param l the spherical harmonic \f$l\f$ mode requested
     428             :  * \param m the spherical harmonic \f$m\f$ mode requested
     429             :  * \param l_max the `l_max` for the provided coefficient set
     430             :  */
     431             : template <int Spin>
     432           1 : void goldberg_modes_to_libsharp_modes_single_pair(
     433             :     size_t l, int m, size_t l_max,
     434             :     gsl::not_null<SpinWeighted<ComplexModalVector, Spin>*> libsharp_modes,
     435             :     size_t radial_offset, std::complex<double> goldberg_plus_m_mode_value,
     436             :     std::complex<double> goldberg_minus_m_mode_value);
     437             : 
     438             : /// @{
     439             : /*!
     440             :  * \ingroup SwshGroup
     441             :  * \brief Compute the set of Goldberg Spin-weighted spherical harmonic modes (in
     442             :  * the convention of  \cite Goldberg1966uu) from a libsharp-compatible series of
     443             :  * modes.
     444             :  *
     445             :  * \details Modes for concentric spherical shells are stored as consecutive
     446             :  * blocks of angular modes in both representations.
     447             :  */
     448             : template <int Spin>
     449           1 : void libsharp_to_goldberg_modes(
     450             :     gsl::not_null<SpinWeighted<ComplexModalVector, Spin>*> goldberg_modes,
     451             :     const SpinWeighted<ComplexModalVector, Spin>& libsharp_modes, size_t l_max);
     452             : 
     453             : template <int Spin>
     454           1 : SpinWeighted<ComplexModalVector, Spin> libsharp_to_goldberg_modes(
     455             :     const SpinWeighted<ComplexModalVector, Spin>& libsharp_modes, size_t l_max);
     456             : /// @}
     457             : 
     458             : /// @{
     459             : /*!
     460             :  * \ingroup SwshGroup
     461             :  * \brief Compute the set of libsharp-compatible spin-weighted spherical
     462             :  * harmonic modes  from a set of Goldberg modes (following the convention of
     463             :  * \cite Goldberg1966uu)
     464             :  *
     465             :  * \details Internally iterates and uses the
     466             :  * `goldberg_modes_to_libsharp_modes_single_pair()`. In many applications where
     467             :  * it is not necessary to store the full Goldberg representation, memory
     468             :  * allocation can be saved by manually performing the iteration and calls to
     469             :  * `goldberg_modes_to_libsharp_modes_single_pair()`.
     470             :  */
     471             : template <int Spin>
     472           1 : void goldberg_to_libsharp_modes(
     473             :     gsl::not_null<SpinWeighted<ComplexModalVector, Spin>*> libsharp_modes,
     474             :     const SpinWeighted<ComplexModalVector, Spin>& goldberg_modes, size_t l_max);
     475             : 
     476             : template <int Spin>
     477           1 : SpinWeighted<ComplexModalVector, Spin> goldberg_to_libsharp_modes(
     478             :     const SpinWeighted<ComplexModalVector, Spin>& goldberg_modes, size_t l_max);
     479             : /// @}
     480             : 
     481             : /*!
     482             :  * \ingroup SwshGroup
     483             :  * \brief Returns the index into a vector of modes consistent with
     484             :  * \cite Goldberg1966uu.
     485             :  *
     486             :  * \details `radial_offset` is used to index into three-dimensional data in
     487             :  * which concentric spherical shells are stored as consecutive blocks of angular
     488             :  * modes. Goldberg modes are stored in an m varies fastest, and ascending
     489             :  * \f$m\f$ and \f$l\f$ values. So, the first several modes are (l, m):
     490             :  *
     491             :  * [(0, 0), (1, -1), (1, 0), (1, 1), (2, -2), ...]
     492             :  */
     493             : constexpr SPECTRE_ALWAYS_INLINE size_t
     494           1 : goldberg_mode_index(const size_t l_max, const size_t l, const int m,
     495             :                     const size_t radial_offset = 0) {
     496             :   return static_cast<size_t>(
     497             :       static_cast<int>(square(l_max + 1) * radial_offset + square(l) + l) + m);
     498             : }
     499             : 
     500             : }  // namespace Swsh
     501             : }  // namespace Spectral

Generated by: LCOV version 1.14