SpECTRE Documentation Coverage Report
Current view: top level - NumericalAlgorithms/TensorYlm - TensorYlm.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 50.0 % 2 1
Test Date: 2026-10-22 17:29:42
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              : /*!
       7              :  * \brief Holds functions that converts spatial tensors between scalar-Ylm
       8              :  * and tensor-Ylm basis, and functions that filter by doing such a conversion.
       9              :  *
      10              :  * \details We expand a spatial tensor of arbitrary rank
      11              :  * in terms of Cartesian components as follows:
      12              :  * \begin{align}
      13              :  * {\mathbf T} &= \sum_{\ell,m,\tilde{A}} {}_0 Y_{\ell m}
      14              :  *                T^{\tilde A}_{\ell m}\mathbf{e}_{\tilde A},
      15              :  * \end{align}
      16              :  * where ${}_0 Y_{\ell m}$ are the usual scalar spherical harmonics,
      17              :  * $T^{\tilde A}_{\ell m}$ are complex-valued expansion coefficients,
      18              :  * $\tilde A$ is a multi-index
      19              :  * $\tilde{A}=(\tilde{a}_1,\tilde{a}_2,\tilde{a}_3,\ldots)$, where each
      20              :  * of the $\tilde{a}_i$ take on values from 0 to 2, referring to
      21              :  * either $\mathbf{e}_x$, $\mathbf{e}_y$, or $\mathbf{e}_z$.
      22              :  * The sum over $\tilde A$ goes over all $\tilde A$ of the same rank.
      23              :  *
      24              :  * Similarly, we can expand the same spatial
      25              :  * tensor in terms of a complex tetrad:
      26              :  * \begin{align}
      27              :  * {\mathbf T} &= \sum_{\ell,m,A} {}_{s(\!A\!)}Y_{\ell m}
      28              :  *                T^A_{\ell m} \mathbf{e}_A,
      29              :  * \end{align}
      30              :  * where ${}_sY_{\ell m}$ are the spin-weighted harmonics,
      31              :  * $A$ is a multi-index $A=(a_1,a_2,a_3,\ldots)$, where each of the
      32              :  * $a_i$ refer to either $\mathbf{l}$,$\mathbf{m}$, or $\mathbf{\bar{m}}$,
      33              :  * and $s(\!A\!)$ is the spin weight, which is a function of
      34              :  * $A$: each $\mathbf{l}$ in $A$ adds the value zero, each $\mathbf{m}$
      35              :  * adds the value -1, and each $\mathbf{\bar{m}}$ adds the value +1.
      36              :  * (These values are the spin weights of the complex conjugates
      37              :  * of the basis vectors.)
      38              :  *
      39              :  * To allow for a compact notation where we don't need to write different
      40              :  * equations for different combinations of basis vectors,
      41              :  * we define two auxiliary quantities $k_j$ and $m_j$
      42              :  * that are functions of the Cartesian basis vectors:
      43              :  * \begin{align}
      44              :  *  k_j(\mathbf{e}_x) &= -j,\\
      45              :  *  k_j(\mathbf{e}_y) &=  i,\\
      46              :  *  k_j(\mathbf{e}_z) &= 1/\sqrt{2},\\
      47              :  *  m_j(\mathbf{e}_x) &= j,\\
      48              :  *  m_j(\mathbf{e}_y) &= j,\\
      49              :  *  m_j(\mathbf{e}_z) &= 0,
      50              :  * \end{align}
      51              :  * where the $i$ above is the imaginary unit $i=\sqrt{-1}$.
      52              :  * These quantities will be used in explicit formulas for transformations
      53              :  * between expansion coefficients.
      54              :  *
      55              :  * ### Spherepack coefficients
      56              :  *
      57              :  * Instead of using the actual spherical-harmonic or
      58              :  * spin-weighted spherical-harmonic coefficients $T^{B}_{\ell' m'}$ and
      59              :  * $T^{\tilde A}_{\ell'm'}$, we often work with
      60              :  * coefficients computed by Spherepack, which have a different normalization
      61              :  * and phase than the standard coefficients.  While Spherepack internally
      62              :  * stores real matrices it calls $a_{lm}$ and $b_{lm}$ (see Spherepack
      63              :  * documentation for details), we simplify things by defining
      64              :  * complex Spherepack coefficients
      65              :  * ${\breve T}^{B}_{\ell' m'}$ and ${\breve T}^{\tilde A}_{\ell'm'}$ that
      66              :  * have Spherepack normalization. These are related to the standard coefficients
      67              :  * by
      68              :  * \begin{align}
      69              :  *  {\breve T}^{A}_{\ell m} &= (-1)^m \sqrt{\frac{2}{\pi}} T^{B}_{\ell m},\\
      70              :  *  {\breve T}^{\tilde A}_{\ell m} &= (-1)^m \sqrt{\frac{2}{\pi}}
      71              :  *  T^{\tilde A}_{\ell m}.
      72              :  * \end{align}
      73              :  * Some of the formulas below are slightly different when acting on
      74              :  * Spherepack coefficients compared to standard coefficients.
      75              :  *
      76              :  * ## Transformations
      77              :  *
      78              :  * We can define the following transformations between the expansion
      79              :  * coefficients $T^A_{\ell m}$ and $T^{\tilde A}_{\ell m}$:
      80              :  * \begin{align}
      81              :  * T^{\tilde B}_{\ell' m'} &=
      82              :  * \sum_{\ell,m,A} C_{\ell' m' A}^{\ell m\tilde{B}} T^A_{\ell m},\\
      83              :  * T^{B}_{\ell' m'} &= \sum_{\ell m \tilde{A}}
      84              :  *                  C_{\ell' m'\tilde{A}}^{\ell mB}
      85              :  *                  T^{\tilde A}_{\ell m},
      86              :  * \end{align}
      87              :  * where the above transformations define the coefficients
      88              :  * $C_{\ell' m' A}^{\ell m\tilde{B}}$ and $C_{\ell' m'\tilde{A}}^{\ell mB}$.
      89              :  * Analytic expressions for these coefficients are derived in Klinger
      90              :  * and Scheel (in prep) and will be used here to compute the coefficients.
      91              :  *
      92              :  * For real-valued tensors, the coefficients $T^A_{\ell m}$ and
      93              :  * $T^{\tilde A}_{\ell m}$ for negative $m$ can be computed from the
      94              :  * complex conjugates of the same coefficients with positive $m$.  Therefore
      95              :  * we store and loop over only nonnegative $m$. This means we can write
      96              :  * \begin{align}
      97              :  * T^{\tilde B}_{\ell m} &= \sum_{A, \ell',m'\geq 0}
      98              :  *                  \left[
      99              :  *              C_{\ell m A}^{\ell' m'\tilde{B}} T^A_{\ell' m'}
     100              :  *               +{\hat C}_{\ell m A}^{\ell' m'\tilde{B}} T^A_{\ell' m'}{}^\star
     101              :  *                \right]\label{eq:S2C},\\
     102              :  * T^{B}_{\ell m} &= \sum_{\tilde{A},\ell',m'\geq 0}
     103              :  *                  \left[
     104              :  *                  C_{\ell m\tilde{A}}^{\ell' m' B}
     105              :  *                  T^{\tilde A}_{\ell' m'}
     106              :  *                  +{\hat C}_{\ell m\tilde{A}}^{\ell' m' B}
     107              :  *                  T^{\tilde A}_{\ell' m'}{}^\star
     108              :  *                  \right]\label{eq:C2S},
     109              :  * \end{align}
     110              :  * where
     111              :  * \begin{align}
     112              :  * {\hat C}_{\ell m A}^{\ell' m'\tilde{B}} &=
     113              :  *                 (1-\delta_{0m'})C_{\ell m A^\star}^{\ell' -m'\tilde{B}}
     114              :  *                 (-1)^{S(A)+m'},\\
     115              :  * {\hat C}_{\ell m\tilde{A}}^{\ell' m' B} &=
     116              :  *                (1-\delta_{0m'})C_{\ell m \tilde{A}}^{\ell' -m'B}
     117              :  *                 (-1)^{m'}.
     118              :  * \end{align}
     119              :  *
     120              :  * The functions FillCartToSphere and FillSphereToCart fill
     121              :  * sparse matrices that encode Eqs. $(\ref{eq:C2S})$ and
     122              :  * $(\ref{eq:S2C})$. When working on Spherepack coefficients, the functions
     123              :  * FillCartToSphere and FillSphereToCart instead
     124              :  * fill sparse matrices that encode
     125              :  * \begin{align}
     126              :  *  {\breve T}^{\tilde B}_{\ell m} &= (-1)^m\sum_{A, \ell',m'\geq 0}(-1)^{m'}
     127              :  *                  \left[
     128              :  *              C_{\ell m A}^{\ell' m'\tilde{B}} T^A_{\ell' m'}
     129              :  *               +{\hat C}_{\ell m A}^{\ell' m'\tilde{B}}
     130              :  *                {\breve T}^A_{\ell' m'}{}^\star
     131              :  *                \right]\label{eq:S2CSpherepack},\\
     132              :  *  {\breve T}^{B}_{\ell m} &= (-1)^m\sum_{\tilde{A},\ell',m'\geq 0}(-1)^{m'}
     133              :  *                  \left[
     134              :  *                  C_{\ell m\tilde{A}}^{\ell' m' B}
     135              :  *                  T^{\tilde A}_{\ell' m'}
     136              :  *                  +{\hat C}_{\ell m\tilde{A}}^{\ell' m' B}
     137              :  *                  {\breve T}^{\tilde A}_{\ell' m'}{}^\star
     138              :  *                  \right]\label{eq:C2SSpherepack}.
     139              :  * \end{align}
     140              :  *
     141              :  * ## Filtering
     142              :  *
     143              :  * Consider starting with coefficients $T^{\tilde A}_{\ell' m'}$,
     144              :  * transforming to spin-weighted harmonics, applying a filter to
     145              :  * the spin-weighted harmonic coefficients, and transforming back.
     146              :  * We can write this entire operation as
     147              :  * \begin{align}
     148              :  *   F_{\ell m \tilde{D}}^{\ell'' m''\tilde{A}} &=
     149              :  *   \sum_{\ell'=0}^{\ell_{\mathrm{cut}}^--1} C^{\ell' m' \tilde{A}}_{\ell m B}
     150              :  *   C^{\ell'' m'' B}_{\ell'  m' \tilde{D}}
     151              :  * + \sum_{\ell'=\ell_{\mathrm{cut}}^-}^{\ell_{\mathrm{cut}}^+}
     152              :  *   C^{\ell' m' \tilde{A}}_{\ell m B}
     153              :  *   C^{\ell'' m'' B}_{\ell'  m' \tilde{D}} f(\ell'),
     154              :  * \end{align}
     155              :  * where $f(\ell')$ is a filter function,
     156              :  * $\ell_{\mathrm{cut}}^{-}$ is the smallest $\ell$ mode that is filtered,
     157              :  * and
     158              :  * $\ell_{\mathrm{cut}}^{+}$ is the largest $\ell$ mode that is retained.
     159              :  *
     160              :  * There are two cases we care about.
     161              :  * The first is simple "Heaviside filtering", where
     162              :  * $\ell_{\mathrm{cut}}^{-} = \ell_{\mathrm{cut}}^{+}$ and $f(\ell')=1$.
     163              :  *
     164              :  * The second case is
     165              :  * \begin{align}
     166              :  *  f(\ell') &= \exp\left[-\alpha
     167              :  * \left(\frac{\ell'}{\ell_{\mathrm{cut}}^++1}\right)^{2 \sigma}\right],\\
     168              :  * \ell_{\mathrm{cut}}^- &= \mathrm{ceil}\left[(\ell_{\mathrm{cut}}^++1)
     169              :  *    \left(\frac{\epsilon}{\alpha}\right)^{1/(2\sigma)}\right],
     170              :  * \end{align}
     171              :  * where $\alpha$ is a parameter we choose to be 36, $\sigma$ is an integer
     172              :  * parameter typically between 28 and 32, and
     173              :  * $\epsilon$ is machine roundoff.
     174              :  * Note that the filter remains smooth at $\ell' = \ell_{\mathrm{cut}}^-$ and
     175              :  * it reduces to the simple filter as $\sigma \to \infty$.
     176              :  *
     177              :  * As with the transformations, we sum over only nonnegative $m$, so we can
     178              :  * write the action of the filter as
     179              :  * \begin{align}
     180              :  * T^{\tilde B}_{\ell m} &= \sum_{{\tilde A}, \ell',m'\geq 0}
     181              :  *                  \left[
     182              :  *              F_{\ell m {\tilde A}}^{\ell' m'\tilde{B}}
     183              :  *                T^{\tilde A}_{\ell' m'}
     184              :  *               +{\hat F}_{\ell m {\tilde A}}^{\ell' m'\tilde{B}}
     185              :  *               T^{\tilde A}_{\ell' m'}{}^\star
     186              :  *                \right]\label{eq:Filter},
     187              :  * \end{align}
     188              :  * where
     189              :  * \begin{align}
     190              :  * {\hat F}_{\ell m\tilde{A}}^{\ell' m' \tilde{B}} &=
     191              :  *                (1-\delta_{0m'})F_{\ell m \tilde{A}}^{\ell' -m' \tilde{B}}
     192              :  *                 (-1)^{m'}.
     193              :  * \end{align}
     194              :  *
     195              :  * When filtering Spherepack coefficients, the expression is
     196              :  * \begin{align}
     197              :  * {\breve T}^{\tilde B}_{\ell m} &=
     198              :  *           (-1)^m\sum_{{\tilde A}, \ell',m'\geq 0}(-1)^{m'}
     199              :  *                  \left[
     200              :  *              F_{\ell m {\tilde A}}^{\ell' m'\tilde{B}}
     201              :  *                {\breve T}^{\tilde A}_{\ell' m'}
     202              :  *               +{\hat F}_{\ell m {\tilde A}}^{\ell' m'\tilde{B}}
     203              :  *               {\breve T}^{\tilde A}_{\ell' m'}{}^\star
     204              :  *                \right]\label{eq:FilterSpherepack}.
     205              :  * \end{align}
     206              :  *
     207              :  * The function FillFilter encapsulates Eq. $(\ref{eq:Filter})$ or
     208              :  * Eq. $(\ref{eq:FilterSpherepack})$,
     209              :  * depending what type of coefficients are being filtered.
     210              :  */
     211              : namespace ylm::TensorYlm {
     212              : 
     213              : /// Instances of this class are passed to FillFilter,
     214              : /// FillCartToSphere, and FillSphereToCart to identify how the
     215              : /// coefficients are normalized.  This makes a difference because the
     216              : /// normalization is not just a constant factor.
     217            1 : enum class CoefficientNormalization {
     218              :   /// The standard normalization of the spherical-harmonic coefficients.
     219              :   Standard,
     220              :   /// The Spherepack normalization. Spherepack coefficients are standard
     221              :   /// coefficients multiplied by $(-1)^m \sqrt{2/\pi}$.
     222              :   Spherepack
     223              : };
     224              : }  // namespace ylm::TensorYlm
        

Generated by: LCOV version 2.0-1