SpECTRE Documentation Coverage Report
Current view: top level - NumericalAlgorithms/FiniteDifference - Filter.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 66.7 % 3 2
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              : #include <cstddef>
       7              : 
       8              : #include "Domain/Structure/DirectionMap.hpp"
       9              : #include "Utilities/Gsl.hpp"
      10              : 
      11              : /// \cond
      12              : template <size_t Dim>
      13              : class Mesh;
      14              : /// \endcond
      15              : 
      16              : namespace fd {
      17              : /*!
      18              :  * \brief Apply a low-pass filter to the data.
      19              :  *
      20              :  * The filter fits a Legendre polynomial of degree equal to `fd_order` to each
      21              :  * grid point and its neighboring points, then subtracts out the highest mode
      22              :  * contribution at the grid point. This is inspired by a Heaviside filter for
      23              :  * Legendre polynomial-based spectral methods.
      24              :  *
      25              :  * The filter at different orders is given by:
      26              :  *
      27              :  * \f{align*}{
      28              :  * F^{(9)} u_i&= -\frac{35 \times 531441}{128} \left(
      29              :  *                \frac{1}{6406400} (u_{i-4} + u_{i+4}) -
      30              :  *                \frac{1}{800800} (u_{i-3} + u_{i+3}) +
      31              :  *                \frac{1}{228800} (u_{i-2} + u_{i+2}) -
      32              :  *                \frac{1}{114400} (u_{i-1} + u_{i+1}) +
      33              :  *                \frac{1}{91520} u_i\right) \\
      34              :  * F^{(7)} u_i&= \frac{5 \times 16807}{16} \left(
      35              :  *                \frac{1}{95040} (u_{i-3} + u_{i+3}) -
      36              :  *                \frac{1}{15840} (u_{i-2} + u_{i+2}) +
      37              :  *                \frac{1}{6336} (u_{i-1} + u_{i+1}) -
      38              :  *                \frac{1}{4572} u_i\right) \\
      39              :  * F^{(5)} u_i&= -\frac{3 \times 125}{8} \left(
      40              :  *                \frac{1}{336} (u_{i-2} + u_{i+2}) -
      41              :  *                \frac{1}{84} (u_{i-1} + u_{i+1}) +
      42              :  *                \frac{1}{56} u_i\right) \\
      43              :  * F^{(3)} u_i&= \frac{1 \times 3}{2} \left(
      44              :  *                \frac{1}{4} (u_{i-1} + u_{i+1}) -
      45              :  *                \frac{1}{2} u_i\right)
      46              :  * \f}
      47              :  *
      48              :  * Dimensions with Cartoon bases are not filtered as there is nothing to filter.
      49              :  *
      50              :  * \note The \f$F^{(11)}\f$ filter isn't implemented yet.
      51              :  *
      52              :  * \note The argument \f$\epsilon\f$ controls how much of the mode is filter
      53              :  * out. \f$\epsilon=1\f$ means the highest mode is completely filtered while
      54              :  * \f$\epsilon=0\f$ means it's not at all filtered.
      55              :  */
      56              : template <size_t Dim>
      57            1 : void low_pass_filter(
      58              :     gsl::not_null<gsl::span<double>*> filtered_data,
      59              :     const gsl::span<const double>& volume_vars,
      60              :     const DirectionMap<Dim, gsl::span<const double>>& ghost_cell_vars,
      61              :     const Mesh<Dim>& volume_mesh, size_t number_of_variables, size_t fd_order,
      62              :     double epsilon);
      63              : 
      64              : /*!
      65              :  * \brief Apply Kreiss-Oliger dissipation \cite Kreiss1973 of order `fd_order`
      66              :  * to the variables.
      67              :  *
      68              :  * Define the operators \f$D_+\f$ and \f$D_-\f$ be defined as:
      69              :  *
      70              :  * \f{align*}{
      71              :  * D_+f_i&=\frac{(f_{i+1}-f_i)}{\Delta x} \\
      72              :  * D_-f_i&=\frac{(f_i-f_{i-1})}{\Delta x}
      73              :  * \f}
      74              :  *
      75              :  * where the subscript \f$i\f$ refers to the grid index. The dissipation
      76              :  * operators are generally applied dimension-by-dimension, and so we have:
      77              :  *
      78              :  * \f{align*}{
      79              :  * \mathcal{D}^{(2m)}=-\frac{(-1)^m}{2^{2m}}\Delta x^{2m-1}
      80              :  * \epsilon(D_{+})^m(D_{-})^m
      81              :  * \f}
      82              :  *
      83              :  * where \f$\epsilon\f$ controls the amount of dissipation and is restricted to
      84              :  * \f$0\leq\epsilon\leq1\f$, and \f$m\f$ is the order of the finite difference
      85              :  * derivative so as not to spoil the accuracy of the scheme. That is, for
      86              :  * second order FD, \f$m=2\f$ and one should use \f$\mathcal{D}^{(4)}\f$.
      87              :  * However, this choice requires a larger stencil and whether or not this is
      88              :  * necessary also depends on when and how in the algorithm the operators are
      89              :  * applied.
      90              :  *
      91              :  * We arrive at the following operators:
      92              :  *
      93              :  * \f{align*}{
      94              :  *  \mathcal{D}^{(2)}f_i&=-\frac{\epsilon}{\Delta x}
      95              :  *   (f_{i+1} - 2f_i+f_{i-1}) \\
      96              :  *  \mathcal{D}^{(4)}f_i&=-\frac{\epsilon}{16\Delta x}
      97              :  *   (f_{i+2}-4f_{i+1}+6f_i-4f_{i-1}+f_{i-2}) \\
      98              :  *  \mathcal{D}^{(6)}f_i&=\frac{\epsilon}{64\Delta x}(f_{i+3}-6f_{i+2}+15f_{i+1}
      99              :  *    -20f_i+15f_{i-1}-6f_{i-2}+f_{i-3}) \\
     100              :  *  \mathcal{D}^{(8)}f_i&=-\frac{\epsilon}{256\Delta x}
     101              :  *    (f_{i+4}-8f_{i+3}+28f_{i+2}-56f_{i+1}+70f_{i}-56f_{i-1}+28f_{i-2}
     102              :  *    -8f_{i-3}+f_{i-4}) \\
     103              :  *  \mathcal{D}^{(10)}f_i&=\frac{\epsilon}{1024\Delta x}
     104              :  *    (f_{i+5}-10f_{i+4}+45f_{i+3}
     105              :  *    -120f_{i+2}+210f_{i+1}-252f_{i}+210f_{i-1}-120f_{i-2}+45f_{i-3}
     106              :  *    -10f_{i-4}+f_{i-5})
     107              :  * \f}
     108              :  *
     109              :  * Dimensions with Cartoon bases are not filtered as there is nothing to filter.
     110              :  *
     111              :  * \note This function applies \f$\Delta x \mathcal{D}^{(2m)}\f$.
     112              :  */
     113              : template <size_t Dim>
     114            1 : void kreiss_oliger_filter(
     115              :     gsl::not_null<gsl::span<double>*> filtered_data,
     116              :     const gsl::span<const double>& volume_vars,
     117              :     const DirectionMap<Dim, gsl::span<const double>>& ghost_cell_vars,
     118              :     const Mesh<Dim>& volume_mesh, size_t number_of_variables, size_t fd_order,
     119              :     double epsilon);
     120              : }  // namespace fd
        

Generated by: LCOV version 2.0-1