SpECTRE Documentation Coverage Report
Current view: top level - NumericalAlgorithms/SphericalHarmonics - TensorYlmFilter.hpp Hit Total Coverage
Commit: 1e29a35ad8559408f21493dc5db8a49a237bb2f0 Lines: 1 2 50.0 %
Date: 2026-03-31 22:27:51
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 "NumericalAlgorithms/SphericalHarmonics/TensorYlm.hpp"
       7             : 
       8             : #include <cstddef>
       9             : #include <optional>
      10             : 
      11             : #include "DataStructures/DataVector.hpp"
      12             : #include "Utilities/Gsl.hpp"
      13             : 
      14             : namespace ylm::TensorYlm {
      15             : 
      16             : /*!
      17             :  * \brief Fills a sparse matrix that does a TensorYlm filter operation.
      18             :  *
      19             :  * If the CoefficientNormalization parameter is set to Standard, then
      20             :  * assumes that $T^{\tilde A}_{\ell' m'}$ is stored in a
      21             :  * Tensor<DataVector>.  Multiplying (one plus) the resulting
      22             :  * sparse matrix by the Tensor<DataVector> is equivalent to
      23             :  * evaluating the right-hand side of Eq. $(\ref{eq:Filter})$.
      24             :  * If the CoefficientNormalization parameter is set to Spherepack, then
      25             :  * assumes the matrix will multiply a Tensor<DataVector> containing
      26             :  * ${\breve T}^{\tilde A}_{\ell' m'}$ and the filter operation is equivalent to
      27             :  * Eq. $(\ref{eq:FilterSpherepack})$.
      28             :  *
      29             :  * We assume that the independent components of the Tensor<DataVector>
      30             :  * are stored contiguously in memory, in order of the storage_index of
      31             :  * the Tensor.  However, we do allow for a stride.  This means that we
      32             :  * can point to memory starting with the first element of
      33             :  * $T^{\tilde A}_{\ell' m'}$ and multiply that by the sparse matrix we compute
      34             :  * here, and get the filtered result.
      35             :  *
      36             :  * The memory layout here is different than in SpEC.  In SpEC, each
      37             :  * tensor component is stored in separately-allocated memory, so the
      38             :  * SpEC equivalent of the fill_filter function fills $N^2$ sparse
      39             :  * matrices, where $N$ is the number of independent components of the
      40             :  * Tensor. The advantage of the SpEC method is that each sparse matrix
      41             :  * is smaller, so sorting elements into the correct order while
      42             :  * constructing each sparse matrix is faster (sorting is > linear in
      43             :  * the number of matrix elements).  The disadvantage of the SpEC
      44             :  * method is that evaluating the filter for a single Tensor involves
      45             :  * $N^2$ matrix-vector multiplications, whereas here evaluating the
      46             :  * filter involves only one matrix-vector multiplication, which should
      47             :  * have more efficient memory access.  It is not clear which method is
      48             :  * faster overall without more profiling.
      49             :  *
      50             :  * ## Explicit formulas
      51             :  *
      52             :  * The following formulas come from Klinger and Scheel, in prep.
      53             :  *
      54             :  * For rank-0 tensors, the expression is simple because there
      55             :  * is no change of basis, only a filter based on $\ell$.
      56             :  * \begin{align}
      57             :  *  F_{l m \tilde{D}}^{\ell'' m''\tilde{A}} &=
      58             :  *  \delta(\tilde{D},\tilde{A})\delta_{\ell \ell''}\delta_{m m''}
      59             :  *  \left[1-
      60             :  *  \delta(\ell_{\mathrm{cut}}^-\leq \ell \leq \ell_{\mathrm{max}}) g(\ell)
      61             :  *  \right].
      62             :  * \end{align}
      63             :  *
      64             :  * For rank-1 tensors, the expression for
      65             :  * $F_{l m \tilde{D}}^{\ell'' m''\tilde{A}}$ is
      66             :  * \begin{align}
      67             :  *  F_{l m \tilde{D}}^{\ell'' m''\tilde{A}} &=
      68             :  *  \delta(\tilde{D},\tilde{A})\delta_{\ell \ell''}\delta_{m m''}
      69             :  *  \nonumber \\
      70             :  *  &- (-1)^{m+m''} (-1)^{\delta(\tilde{D},\mathbf{e}_y)}
      71             :  *  \delta(\ell,\ell'')
      72             :  *  \sum_{\ell'=\ell_{\mathrm{cut}}^-}^{\ell_{\mathrm{max}}+1}
      73             :  *  \frac{2\ell'+1}{2} g(\ell') \nonumber \\
      74             :  *  &\times \sum_{j,p,m'} k_j(\tilde{D})k_p(\tilde{A})
      75             :  *    \left(\begin{array}{rrr}
      76             :  *     \ell&\ell'&1\cr
      77             :  *      -m''&m'&m_j(\tilde{D})
      78             :  *    \end{array}\right)
      79             :  *    \left(\begin{array}{rrr}
      80             :  *     \ell&\ell'&1\cr
      81             :  *      -m&m'&m_p(\tilde{A})
      82             :  *    \end{array}\right),
      83             :  * \end{align}
      84             :  * where the 6-element "matrices"
      85             :  * in parentheses are Wigner 3-J symbols, and where
      86             :  * \begin{align}
      87             :  *  g(\ell') &=
      88             :  *  \left\{\begin{array}{lr}
      89             :  *      1-f(\ell') & \ell' \leq \ell_{\mathrm{cut}}^+,\\
      90             :  *      1 & \ell' > \ell_{\mathrm{cut}}^+.
      91             :  *  \end{array}\right.
      92             :  * \end{align}
      93             :  *
      94             :  * For second-rank tensors, the expression for
      95             :  * $F_{l m \tilde{D}}^{\ell'' m''\tilde{A}}$ is
      96             :  * \begin{align}
      97             :  *  F_{l m \tilde{D}}^{\ell'' m''\tilde{A}}
      98             :  *  &=
      99             :  *  \delta(\tilde{D},\tilde{A})\delta_{\ell \ell''}\delta_{m m''}
     100             :  * \nonumber \\
     101             :  * &-
     102             :  *  \frac{1}{4}
     103             :  * (-1)^{\delta(\tilde{D}_1,\mathbf{e}_y)}
     104             :  * (-1)^{\delta(\tilde{D}_2,\mathbf{e}_y)}
     105             :  *  \delta_{\ell \ell''}
     106             :  * \nonumber \\
     107             :  * &\times
     108             :  * \sum_{\ell'=\ell_{\mathrm{cut}}^-}^{\ell_{\mathrm{max}}+2}
     109             :  * (2\ell'+1) g(\ell')
     110             :  * \sum_{u,v,p,q,\bar{\ell},\tilde{m},\bar{m},m'}
     111             :  * (2 \bar{\ell}+1) S(\bar{\ell},\tilde{D})
     112             :  * k_u(\tilde{D}_1) k_v(\tilde{D}_2)
     113             :  * k_p(\tilde{A}_1) k_q(\tilde{A}_2)
     114             :  * \nonumber \\
     115             :  * &\times
     116             :  *    \left(\begin{array}{rrr}
     117             :  *     \ell&\ell'&\bar{\ell}\cr
     118             :  *      -m&m'&\bar{m}
     119             :  *    \end{array}\right)
     120             :  *    \left(\begin{array}{rrr}
     121             :  *     1&1&\bar{\ell}\cr
     122             :  *      m_p(\tilde{A}_1)&m_q(\tilde{A}_2)&-\bar{m}
     123             :  *    \end{array}\right)
     124             :  * \nonumber \\
     125             :  * &\times
     126             :  *    \left(\begin{array}{rrr}
     127             :  *     \ell'&\ell&\bar{\ell}\cr
     128             :  *      -m'&m''&\tilde{m}
     129             :  *    \end{array}\right)
     130             :  *    \left(\begin{array}{rrr}
     131             :  *     1&1&\bar{\ell}\cr
     132             :  *      m_u(\tilde{D}_1)&m_v(\tilde{D}_2)&\tilde{m}
     133             :  *    \end{array}\right),
     134             :  *  \label{eq:RankTwoTransformWithCut}
     135             :  * \end{align}
     136             :  * where the factor $S(\bar{\ell},\tilde{D})$ is a symmetry factor.
     137             :  * For a 2nd-rank tensor with no symmetries, $S(\bar{\ell},\tilde{D})$ is
     138             :  * unity, but for a tensor symmetric in $(\tilde{D_1},\tilde{D_2})$
     139             :  * the matrix elements $F_{l m \tilde{D}}^{\ell'' m''\tilde{A}}$ are
     140             :  * multiplied only by tensor components with $\tilde{D_1}\geq\tilde{D_2}$
     141             :  * and the symmetry is accounted for by setting
     142             :  * \begin{align}
     143             :  *   S(\bar{\ell},\tilde{D}) &=
     144             :  *   (1+(-1)^{\bar{\ell}})\frac{2-\delta(\tilde{D_1},\tilde{D_2})}{2}.
     145             :  * \end{align}
     146             :  *
     147             :  * For third-rank tensors, the expression for
     148             :  * $F_{l m \tilde{D}}^{\ell'' m''\tilde{A}}$ is
     149             :  * \begin{align}
     150             :  *  F_{l m \tilde{D}}^{\ell'' m''\tilde{A}}
     151             :  *  &=
     152             :  *  \delta(\tilde{D},\tilde{A})\delta_{\ell \ell''}\delta_{m m''}
     153             :  *  \nonumber \\
     154             :  * &-
     155             :  *  \frac{1}{8}
     156             :  *  (-1)^{\delta(\tilde{D}_1,\mathbf{e}_y)}
     157             :  *  (-1)^{\delta(\tilde{D}_2,\mathbf{e}_y)}
     158             :  *  (-1)^{\delta(\tilde{D}_3,\mathbf{e}_y)}
     159             :  *  \delta_{\ell \ell''}
     160             :  *  \nonumber \\
     161             :  *  &\times
     162             :  *  \sum_{\ell'=\ell_{\mathrm{cut}}^-}^{\ell_{\mathrm{max}}+3}
     163             :  *  (2\ell'+1) g(\ell')
     164             :  *  \sum_{u,v,w,p,q,r,\tilde{m},\bar{\ell},\bar{m},
     165             :  *  \hat{\ell},\hat{m},\check{m},m'}
     166             :  *  (2 \bar{\ell}+1) S(\bar{\ell},\tilde{D})
     167             :  *  (2 \hat{\ell}+1)
     168             :  *  \nonumber \\
     169             :  *  &\qquad\times
     170             :  *  k_u(\tilde{D}_2) k_v(\tilde{D}_3) k_w(\tilde{D}_1)
     171             :  *  k_p(\tilde{A}_2) k_q(\tilde{A}_3) k_r(\tilde{A}_1)
     172             :  *  (-1)^{\tilde{m}-\bar{m}}
     173             :  *  \nonumber \\
     174             :  *  &\qquad\times
     175             :  *    \left(\begin{array}{rrr}
     176             :  *     1&1&\bar{\ell}\cr
     177             :  *     m_p(\tilde{A}_2)&m_q(\tilde{A}_3)&-\bar{m}
     178             :  *    \end{array}\right)
     179             :  *    \left(\begin{array}{rrr}
     180             :  *     1&1&\bar{\ell}\cr
     181             :  *     m_u(\tilde{D}_2)&m_v(\tilde{D}_3)&\tilde{m}
     182             :  *    \end{array}\right)
     183             :  *  \nonumber \\
     184             :  *  &\qquad\times
     185             :  *    \left(\begin{array}{rrr}
     186             :  *     \ell&\ell'&\hat{\ell}\cr
     187             :  *     -m&m'&\check{m}
     188             :  *    \end{array}\right)
     189             :  *    \left(\begin{array}{rrr}
     190             :  *     \ell'&\ell&\hat{\ell}\cr
     191             :  *     -m'&m''&\hat{m}
     192             :  *    \end{array}\right)
     193             :  *  \nonumber \\
     194             :  *  &\qquad\times
     195             :  *    \left(\begin{array}{rrr}
     196             :  *     1&\bar{\ell}&\hat{\ell}\cr
     197             :  *     m_r(\tilde{A}_1)&\bar{m}&-\check{m}
     198             :  *    \end{array}\right)
     199             :  *    \left(\begin{array}{rrr}
     200             :  *     1&\bar{\ell}&\hat{\ell}\cr
     201             :  *     m_w(\tilde{D}_1)&-\tilde{m}&\hat{m}
     202             :  *    \end{array}\right).
     203             :  *    \label{eq:RankThreeTransformWithCut}
     204             :  * \end{align}
     205             :  * As in the rank-2 case,
     206             :  * $S(\bar{\ell},\tilde{D})$ is a symmetry factor that is unity
     207             :  * for a tensor with no symmetries and is
     208             :  * \begin{align}
     209             :  *   S(\bar{\ell},\tilde{D}) &=
     210             :  *   (1+(-1)^{\bar{\ell}})\frac{2-\delta(\tilde{D_2},\tilde{D_3})}{2}
     211             :  * \end{align}
     212             :  * for a tensor symmetric on its last two indices. We don't consider
     213             :  * other symmetries because we don't find them in the cases we care
     214             :  * about.
     215             :  *
     216             :  * \tparam TensorStructure A Tensor_detail::Structure
     217             :  * \tparam SparseMatrixType A sparse matrix fillable by SparseMatrixFiller
     218             :  *
     219             :  * \param matrix The sparse matrix to fill
     220             :  * \param ell_max The maximum ylm ell value.
     221             :  * \param number_of_ell_modes_to_kill How many top ell modes to set to zero.
     222             :  * \param half_power The half power $\sigma$ for more complicated filtering.
     223             :  * \param coefficient_normalization Describes the normalization of coefficients.
     224             :  *
     225             :  *  If half_power is std::nullopt, implements a Heaviside filter.
     226             :  *  Otherwise, the filter is the more complicated one described in the
     227             :  *  TensorYlm namespace documentation, with $\sigma$ equal to
     228             :  *  half_power and $\ell_{\mathrm{cut}}^+$ equal to $\ell_{\rm max}$
     229             :  *  minus number_of_ell_modes_to_kill.
     230             :  *
     231             :  */
     232             : template <typename TensorStructure, typename SparseMatrixType>
     233           1 : void fill_filter(gsl::not_null<SparseMatrixType*> matrix, size_t ell_max,
     234             :                  size_t number_of_ell_modes_to_kill,
     235             :                  std::optional<size_t> half_power,
     236             :                  CoefficientNormalization coefficient_normalization);
     237             : 
     238             : }  // namespace ylm::TensorYlm

Generated by: LCOV version 1.14