SpECTRE Documentation Coverage Report
Current view: top level - NumericalAlgorithms/SphericalHarmonics - SpherepackIterator.hpp Hit Total Coverage
Commit: 3c072f0ce967e2e56649d3fa12aa2a0e4fe2a42e Lines: 12 31 38.7 %
Date: 2024-04-23 20:50:18
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             :  * \ingroup SpectralGroup
      21             :  * \brief
      22             :  * Iterates over spectral coefficients stored in SPHEREPACK format.
      23             :  *
      24             :  * \details
      25             :  * The internal SPHEREPACK ordering is not intuitive, so
      26             :  * SpherepackIterator exists for the purpose of iterating over an
      27             :  * array containing SPHEREPACK coefficients and determining the
      28             :  * (l,m) of each entry in the array.
      29             :  *
      30             :  * SPHEREPACK expands \f$f(\theta,\phi)\f$ as
      31             :  * \f[
      32             :  * f(\theta,\phi) =
      33             :  * \frac{1}{2} \sum_{l=0}^{l_{max}} \bar{P}_l^0 a(0,l)
      34             :  *   + \sum_{m=1}^{m_{max}} \sum_{l=m}^{l_{max}} \bar{P}_l^m
      35             :  *         \left(  a(m,l) \cos(m \phi) - b(m,l) \sin(m \phi)\right)
      36             :  * \f]
      37             :  * where \f$a(m,l)\f$ and \f$b(m,l)\f$ are the SPHEREPACK
      38             :  * spectral coefficients, and \f$\bar{P}_l^m\f$ are
      39             :  * unit-orthonormal associated Legendre polynomials:
      40             :  * \f[
      41             :  * \bar{P}_l^m =
      42             :  * (-1)^m \sqrt{\frac{(2l+1)(l-m)!}{2(l+m)!}} P_l^m,
      43             :  * \f]
      44             :  * where \f$P_l^m\f$ are the associated Legendre polynomials as defined
      45             :  * for example in Jackson "Classical Electrodynamics".
      46             :  * \example
      47             :  * \snippet Test_SpherepackIterator.cpp spherepack_iterator_example
      48             :  */
      49           1 : class SpherepackIterator {
      50             :  public:
      51             :   /// SPHEREPACK has two coefficient variables, 'a' and 'b', that hold
      52             :   /// the cos(m*phi) and sin(m*phi) parts of the spectral
      53             :   /// coefficients.
      54           0 :   enum class CoefficientArray { a, b };
      55             : 
      56           0 :   SpherepackIterator(size_t l_max_input, size_t m_max_input, size_t stride = 1);
      57             : 
      58           0 :   size_t l_max() const { return l_max_; }
      59           0 :   size_t m_max() const { return m_max_; }
      60           0 :   size_t n_th() const { return n_th_; }
      61           0 :   size_t n_ph() const { return n_ph_; }
      62           0 :   size_t stride() const { return stride_; }
      63             : 
      64             :   /// Size of a SPHEREPACK coefficient array (a and b combined), not
      65             :   /// counting stride.  For non-unit stride, the size of the array
      66             :   /// should be spherepack_array_size()*stride.
      67           1 :   size_t spherepack_array_size() const {
      68             :     return (l_max_ + 1) * (m_max_ + 1) * 2;
      69             :   }
      70             : 
      71           0 :   SpherepackIterator& operator++() {
      72             :     ASSERT(current_compact_index_ != offset_into_spherepack_array.size(),
      73             :            "Incrementing an invalid iterator: "
      74             :                << current_compact_index_ << " "
      75             :                << offset_into_spherepack_array.size());
      76             :     ++current_compact_index_;
      77             :     return *this;
      78             :   }
      79             : 
      80           0 :   explicit operator bool() const {
      81             :     return current_compact_index_ < offset_into_spherepack_array.size();
      82             :   }
      83             : 
      84             :   /// Current index into a SPHEREPACK coefficient array.
      85           1 :   size_t operator()() const {
      86             :     return offset_into_spherepack_array[current_compact_index_];
      87             :   }
      88             : 
      89             :   /// Given an offset into a SPHEREPACK coefficient array, return the compact
      90             :   /// index corresponding to that offset.
      91             :   ///
      92             :   /// Essentially the inverse of operator(). If the offset points to an element
      93             :   /// that SPHEREPACK doesn't actually use (i.e. no compact index can reach the
      94             :   /// given offset), then a std::nullopt is returned.
      95           1 :   std::optional<size_t> compact_index(const size_t offset) const {
      96             :     return offset_to_compact_index_[offset];
      97             :   }
      98             : 
      99             :   /// Returns the current compact index that SpherepackIterator uses internally.
     100             :   /// This does not index a SPHEREPACK coefficient array. \see operator() for an
     101             :   /// index into a SPHEREPACK coefficient array
     102           1 :   size_t current_compact_index() const { return current_compact_index_; }
     103             : 
     104             :   /// Current values of l and m.
     105           1 :   size_t l() const { return compact_l_[current_compact_index_]; }
     106           0 :   size_t m() const { return compact_m_[current_compact_index_]; }
     107             :   ///  Whether the iterator points to an element of 'a' or 'b',
     108             :   ///  i.e. points to the cos(m*phi) or sin(m*phi) part of a spectral
     109             :   ///  coefficient.
     110           1 :   CoefficientArray coefficient_array() const {
     111             :     return (current_compact_index_ < number_of_valid_entries_in_a_
     112             :                 ? CoefficientArray::a
     113             :                 : CoefficientArray::b);
     114             :   }
     115             : 
     116             :   /// Reset iterator back to beginning value. Returns *this.
     117           1 :   SpherepackIterator& reset();
     118             : 
     119             :   /// Set iterator to specific value of l, m, array.  Returns *this.
     120           1 :   SpherepackIterator& set(size_t l_input, size_t m_input,
     121             :                           CoefficientArray coefficient_array_input);
     122             : 
     123             :   /// Same as 'set' above, but assumes CoefficientArray is 'a' for m>=0 and
     124             :   /// 'b' for m<0.  This is useful when converting between true
     125             :   /// spherical harmonics (which allow negative values of m) and
     126             :   /// SPHEREPACK coefficients (which have only positive values of m,
     127             :   /// but two arrays for sin(m*phi) and cos(m*phi) parts).
     128           1 :   SpherepackIterator& set(size_t l_input, int m_input) {
     129             :     return set(l_input, size_t(abs(m_input)),
     130             :                m_input >= 0 ? CoefficientArray::a : CoefficientArray::b);
     131             :   }
     132             : 
     133             :   /// Set iterator to a specific compact index. Returns *this.
     134           1 :   SpherepackIterator& set(size_t compact_index);
     135             : 
     136             :  private:
     137           0 :   size_t l_max_, m_max_, n_th_, n_ph_, stride_;
     138           0 :   size_t number_of_valid_entries_in_a_;
     139           0 :   size_t current_compact_index_;
     140           0 :   std::vector<size_t> offset_into_spherepack_array;
     141           0 :   std::vector<size_t> compact_l_, compact_m_;
     142           0 :   std::vector<std::optional<size_t>> offset_to_compact_index_;
     143             : };
     144             : 
     145           0 : inline bool operator==(const SpherepackIterator& lhs,
     146             :                        const SpherepackIterator& rhs) {
     147             :   return lhs.l_max() == rhs.l_max() and lhs.m_max() == rhs.m_max() and
     148             :          lhs.stride() == rhs.stride() and lhs() == rhs();
     149             : }
     150             : 
     151           0 : inline bool operator!=(const SpherepackIterator& lhs,
     152             :                        const SpherepackIterator& rhs) {
     153             :   return not(lhs == rhs);
     154             : }
     155             : 
     156           0 : inline std::ostream& operator<<(
     157             :     std::ostream& os,
     158             :     const SpherepackIterator::CoefficientArray& coefficient_array) {
     159             :   return os << (coefficient_array == SpherepackIterator::CoefficientArray::a
     160             :                     ? 'a'
     161             :                     : 'b');
     162             : }
     163             : }  // namespace ylm

Generated by: LCOV version 1.14