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 "NumericalAlgorithms/Spectral/Parity.hpp"
9 :
10 : /// \cond
11 : class Matrix;
12 : template <size_t>
13 : class Mesh;
14 : /// \endcond
15 :
16 : namespace Spectral {
17 : /*!
18 : * \ingroup SpectralGroup
19 : * \brief Matrices for filtering spectral coefficients.
20 : */
21 1 : namespace filtering {
22 : /*!
23 : * \brief Returns a `Matrix` by which to multiply the nodal coefficients to
24 : * apply a stable exponential filter.
25 : *
26 : * The exponential filter rescales the modal coefficients according to:
27 : *
28 : * \f{align*}{
29 : * c_i\to c_i \exp\left[-\alpha \left(\frac{i}{N}\right)^{2m}\right]
30 : * \f}
31 : *
32 : * where \f$c_i\f$ are the zero-indexed modal coefficients, \f$N\f$ is the basis
33 : * degree (number of grid points per element per dimension minus one),
34 : * \f$\alpha\f$ determines how much the coefficients are rescaled, and \f$m\f$
35 : * determines how aggressive/broad the filter is (lower values means filtering
36 : * more coefficients). Setting \f$\alpha=36\f$ results in setting the highest
37 : * coefficient to machine precision, effectively zeroing it out.
38 : *
39 : * For filtering the Fourier basis, both \f$\cos\f$ and \f$\sin\f$
40 : * contributions to a given \f$m\f$-mode are equally weighted.
41 : *
42 : * The Parity argument is only used for ZernikeB1 and HalfFourier bases, where
43 : * the modal space is parity dependent.
44 : *
45 : * For the HalfFourier basis, \f$\cos(k\phi)\f$ and \f$\sin(k\phi)\f$ with the
46 : * same wavenumber \f$k\f$ are weighted equally, and the odd-parity Nyquist mode
47 : * \f$\sin(N\phi)\f$ is removed.
48 : *
49 : * \note The filter matrix is not cached by the function because it depends on a
50 : * double, an integer, and the mesh, which could make caching very memory
51 : * intensive. The caller of this function is responsible for determining whether
52 : * or not the matrix should be cached.
53 : */
54 1 : Matrix exponential_filter(const Mesh<1>& mesh, double alpha,
55 : unsigned half_power,
56 : Parity parity = Parity::Uninitialized);
57 :
58 : /*!
59 : * \brief Zeros the lowest `number_of_modes_to_zero` modal coefficients. Note
60 : * that the matrix must be applied to a nodal representation.
61 : *
62 : * Given a function \f$u\f$
63 : *
64 : * \f{align}{
65 : * u(x)=\sum_{i=0}^N c_i P_i(x),
66 : * \f}
67 : *
68 : * where \f$c_i\f$ are the modal coefficients and \f$P_i(x)\f$ is the basis
69 : * (e.g. Legendre polynomials), the filter matrix will take the *nodal*
70 : * representation of \f$u\f$ and zero out the lowest `number_of_modes_to_zero`
71 : * modal coefficients. That is, after the filter is applied \f$u\to\bar{u}\f$ is
72 : *
73 : * \f{align}{
74 : * \bar{u}(x)=\sum_{i=k}^N c_i P_i(x),
75 : * \f}
76 : *
77 : * where \f$k\f$ is the number of modes set to zero. The output \f$\bar{u}\f$ is
78 : * also in the *nodal* representation.
79 : *
80 : * The Parity argument is only used for ZernikeB1 bases, where the modal space
81 : * is parity dependent.
82 : */
83 1 : const Matrix& zero_lowest_modes(
84 : const Mesh<1>& mesh, size_t number_of_modes_to_zero,
85 : Spectral::Parity parity = Spectral::Parity::Uninitialized);
86 :
87 : /*!
88 : * \brief Zeros the highest `number_of_modes_to_zero` modal coefficients. Note
89 : * that the matrix must be applied to a nodal representation.
90 : *
91 : * Given a function \f$u\f$
92 : *
93 : * \f{align}{
94 : * u(x)=\sum_{i=0}^N c_i P_i(x),
95 : * \f}
96 : *
97 : * where \f$c_i\f$ are the modal coefficients and \f$P_i(x)\f$ is the basis
98 : * (e.g. Legendre polynomials), the filter matrix will take the *nodal*
99 : * representation of \f$u\f$ and zero out the highest `number_of_modes_to_zero`
100 : * modal coefficients. That is, after the filter is applied \f$u\to\bar{u}\f$ is
101 : *
102 : * \f{align}{
103 : * \bar{u}(x)=\sum_{i=0}^{N-k} c_i P_i(x),
104 : * \f}
105 : *
106 : * where \f$k\f$ is the number of modes set to zero. The output \f$\bar{u}\f$ is
107 : * also in the *nodal* representation. The constant (\f$i=0\f$) mode is never
108 : * removed for any basis.
109 : *
110 : * For the Fourier basis the "modes" are the \f$m\f$-modes: the highest
111 : * `number_of_modes_to_zero` \f$m\f$-modes are zeroed, with both the \f$\cos\f$
112 : * and \f$\sin\f$ contributions to a given \f$m\f$-mode treated identically.
113 : *
114 : * \note Only the Legendre, Chebyshev, and Fourier bases are supported. Unlike
115 : * `zero_lowest_modes`, there is no parity argument and the ZernikeB1 basis is
116 : * not supported.
117 : */
118 1 : const Matrix& zero_highest_modes(const Mesh<1>& mesh,
119 : size_t number_of_modes_to_zero);
120 : } // namespace filtering
121 : } // namespace Spectral
|