SpECTRE Documentation Coverage Report
Current view: top level - NumericalAlgorithms/SphericalHarmonics - SpherepackIterator.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 39.4 % 33 13
Test Date: 2026-10-22 17:29:42
Legend: Lines:     hit not hit

            Line data    Source code
       1            1 : // Distributed under the MIT License.
       2              : // See LICENSE.txt for details.
       3              : 
       4              : ///
       5              : /// \file
       6              : /// Defines class SpherepackIterator.
       7              : 
       8              : #pragma once
       9              : 
      10              : #include <cmath>
      11              : #include <cstddef>
      12              : #include <optional>
      13              : #include <ostream>
      14              : #include <vector>
      15              : 
      16              : #include "Utilities/ErrorHandling/Assert.hpp"
      17              : 
      18              : namespace ylm {
      19              : 
      20              : /*!
      21              :  * \ingroup SpectralGroup
      22              :  * \brief
      23              :  * Iterates over spectral coefficients stored in SPHEREPACK format.
      24              :  *
      25              :  * \details
      26              :  * The internal SPHEREPACK ordering is not intuitive, so
      27              :  * SpherepackIterator exists for the purpose of iterating over an
      28              :  * array containing SPHEREPACK coefficients and determining the
      29              :  * (l,m) of each entry in the array.
      30              :  *
      31              :  * SPHEREPACK expands \f$f(\theta,\phi)\f$ as
      32              :  * \f[
      33              :  * f(\theta,\phi) =
      34              :  * \frac{1}{2} \sum_{l=0}^{l_{max}} \bar{P}_l^0 a(0,l)
      35              :  *   + \sum_{m=1}^{m_{max}} \sum_{l=m}^{l_{max}} \bar{P}_l^m
      36              :  *         \left(  a(m,l) \cos(m \phi) - b(m,l) \sin(m \phi)\right)
      37              :  * \f]
      38              :  * where \f$a(m,l)\f$ and \f$b(m,l)\f$ are the SPHEREPACK
      39              :  * spectral coefficients, and \f$\bar{P}_l^m\f$ are
      40              :  * unit-orthonormal associated Legendre polynomials:
      41              :  * \f[
      42              :  * \bar{P}_l^m =
      43              :  * (-1)^m \sqrt{\frac{(2l+1)(l-m)!}{2(l+m)!}} P_l^m,
      44              :  * \f]
      45              :  * where \f$P_l^m\f$ are the associated Legendre polynomials as defined
      46              :  * for example in Jackson "Classical Electrodynamics".
      47              :  * \example
      48              :  * \snippet Test_SpherepackIterator.cpp spherepack_iterator_example
      49              :  */
      50            1 : class SpherepackIterator {
      51              :  public:
      52              :   /// SPHEREPACK has two coefficient variables, 'a' and 'b', that hold
      53              :   /// the cos(m*phi) and sin(m*phi) parts of the spectral
      54              :   /// coefficients.
      55            0 :   enum class CoefficientArray { a, b };
      56              : 
      57              :   /// Construct a SpherepackIterator.
      58              :   ///
      59              :   /// For all uses of SpherepackIterator by the SPHEREPACK routines,
      60              :   /// zero_m_is_real should be true, indicating that the m=0 values of
      61              :   /// the coefficients are real (or in other words, the 'b' array has
      62              :   /// no m=0 values).
      63              :   ///
      64              :   /// However, we sometimes use the same storage scheme (and hence
      65              :   /// SpherepackIterator) to hold spin-weighted-spherical-harmonic
      66              :   /// coefficients of complex quantities, in which case the m=0 values
      67              :   /// of the coefficients can be complex; in that case, zero_m_is_real
      68              :   /// should be false.
      69            1 :   SpherepackIterator(size_t l_max_input, size_t m_max_input, size_t stride = 1,
      70              :                      bool zero_m_is_real = true);
      71              : 
      72            0 :   size_t l_max() const { return l_max_; }
      73            0 :   size_t m_max() const { return m_max_; }
      74            0 :   size_t n_th() const { return n_th_; }
      75            0 :   size_t n_ph() const { return n_ph_; }
      76            0 :   size_t stride() const { return stride_; }
      77            0 :   bool zero_m_is_real() const { return zero_m_is_real_; }
      78              : 
      79              :   /// Size of a SPHEREPACK coefficient array (a and b combined), not
      80              :   /// counting stride.  For non-unit stride, the size of the array
      81              :   /// should be spherepack_array_size()*stride.
      82            1 :   size_t spherepack_array_size() const {
      83              :     return (l_max_ + 1) * (m_max_ + 1) * 2;
      84              :   }
      85              : 
      86            0 :   SpherepackIterator& operator++() {
      87              :     ASSERT(current_compact_index_ != offset_into_spherepack_array.size(),
      88              :            "Incrementing an invalid iterator: "
      89              :                << current_compact_index_ << " "
      90              :                << offset_into_spherepack_array.size());
      91              :     ++current_compact_index_;
      92              :     return *this;
      93              :   }
      94              : 
      95            0 :   explicit operator bool() const {
      96              :     return current_compact_index_ < offset_into_spherepack_array.size();
      97              :   }
      98              : 
      99              :   /// Current index into a SPHEREPACK coefficient array.
     100            1 :   size_t operator()() const {
     101              :     return offset_into_spherepack_array[current_compact_index_];
     102              :   }
     103              : 
     104              :   /// Given an offset into a SPHEREPACK coefficient array, return the compact
     105              :   /// index corresponding to that offset.
     106              :   ///
     107              :   /// Essentially the inverse of operator(). If the offset points to an element
     108              :   /// that SPHEREPACK doesn't actually use (i.e. no compact index can reach the
     109              :   /// given offset), then a std::nullopt is returned.
     110            1 :   std::optional<size_t> compact_index(const size_t offset) const {
     111              :     return offset_to_compact_index_[offset];
     112              :   }
     113              : 
     114              :   /// Returns the current compact index that SpherepackIterator uses internally.
     115              :   /// This does not index a SPHEREPACK coefficient array. \see operator() for an
     116              :   /// index into a SPHEREPACK coefficient array
     117            1 :   size_t current_compact_index() const { return current_compact_index_; }
     118              : 
     119              :   /// Current values of l and m.
     120            1 :   size_t l() const { return compact_l_[current_compact_index_]; }
     121            0 :   size_t m() const { return compact_m_[current_compact_index_]; }
     122              :   ///  Whether the iterator points to an element of 'a' or 'b',
     123              :   ///  i.e. points to the cos(m*phi) or sin(m*phi) part of a spectral
     124              :   ///  coefficient.
     125            1 :   CoefficientArray coefficient_array() const {
     126              :     return (current_compact_index_ < number_of_valid_entries_in_a_
     127              :                 ? CoefficientArray::a
     128              :                 : CoefficientArray::b);
     129              :   }
     130              : 
     131              :   /// Reset iterator back to beginning value. Returns *this.
     132            1 :   SpherepackIterator& reset();
     133              : 
     134              :   /// Set iterator to specific value of l, m, array.  Returns *this.
     135            1 :   SpherepackIterator& set(size_t l_input, size_t m_input,
     136              :                           CoefficientArray coefficient_array_input);
     137              : 
     138              :   /// Same as 'set' above, but assumes CoefficientArray is 'a' for m>=0 and
     139              :   /// 'b' for m<0.  This is useful when converting between true
     140              :   /// spherical harmonics (which allow negative values of m) and
     141              :   /// SPHEREPACK coefficients (which have only positive values of m,
     142              :   /// but two arrays for sin(m*phi) and cos(m*phi) parts).
     143            1 :   SpherepackIterator& set(size_t l_input, int m_input) {
     144              :     return set(l_input, size_t(abs(m_input)),
     145              :                m_input >= 0 ? CoefficientArray::a : CoefficientArray::b);
     146              :   }
     147              : 
     148              :   /// Set iterator to a specific compact index. Returns *this.
     149            1 :   SpherepackIterator& set(size_t compact_index);
     150              : 
     151              :  private:
     152            0 :   size_t l_max_, m_max_, n_th_, n_ph_, stride_;
     153            0 :   bool zero_m_is_real_;
     154            0 :   size_t number_of_valid_entries_in_a_;
     155            0 :   size_t current_compact_index_;
     156            0 :   std::vector<size_t> offset_into_spherepack_array;
     157            0 :   std::vector<size_t> compact_l_, compact_m_;
     158            0 :   std::vector<std::optional<size_t>> offset_to_compact_index_;
     159              : };
     160              : 
     161            0 : inline bool operator==(const SpherepackIterator& lhs,
     162              :                        const SpherepackIterator& rhs) {
     163              :   return lhs.l_max() == rhs.l_max() and lhs.m_max() == rhs.m_max() and
     164              :          lhs.stride() == rhs.stride() and lhs() == rhs() and
     165              :          lhs.zero_m_is_real() == rhs.zero_m_is_real();
     166              : }
     167              : 
     168            0 : inline bool operator!=(const SpherepackIterator& lhs,
     169              :                        const SpherepackIterator& rhs) {
     170              :   return not(lhs == rhs);
     171              : }
     172              : 
     173            0 : inline std::ostream& operator<<(
     174              :     std::ostream& os,
     175              :     const SpherepackIterator::CoefficientArray& coefficient_array) {
     176              :   return os << (coefficient_array == SpherepackIterator::CoefficientArray::a
     177              :                     ? 'a'
     178              :                     : 'b');
     179              : }
     180              : }  // namespace ylm
        

Generated by: LCOV version 2.0-1