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 : /// \cond
9 : class DataVector;
10 : class Matrix;
11 : /// \endcond
12 :
13 : namespace Spectral {
14 :
15 : /*!
16 : * \ingroup SpectralGroup
17 : *
18 : * \brief A collection of helper functions for using a Fourier series
19 : *
20 : * \details The general real-valued Fourier series is given by:
21 : * \f[
22 : * f(x) = a_0 + \sum_{n=1}^{\infty} a_n \cos(nx) + b_n \sin(nx)
23 : * \f]
24 : * where
25 : * \f{align*}
26 : * a_0 &= \frac{1}{2\pi} \int_0^{2\pi} f(x) dx \\
27 : * a_n &= \frac{1}{\pi} \int_0^{2\pi} f(x) \cos(nx) dx \\
28 : * b_n &= \frac{1}{\pi} \int_0^{2\pi} f(x) \sin(nx) dx
29 : * \f}
30 : *
31 : * If a function is discretized at \f$N\f$ collocation points, the modal
32 : * representation will have \f$N\f$ spectral coefficients consisting of
33 : * \f{align*}
34 : * a_n & \qquad \text{for } n = 0, \ldots, \frac{N}{2} \\
35 : * b_n & \qquad \text{for } n = 1, \ldots, \frac{N-1}{2}
36 : * \f}
37 : * Thus to represent all terms through the harmonic \f$M\f$ requires \f$N = 2M
38 : * +1\f$ collocation points.
39 : *
40 : * For more details about using Fourier series see e.g. \cite Boyd2001 and
41 : * \cite Fornberg1996.
42 : */
43 1 : class Fourier {
44 : public:
45 : /*!
46 : * \brief Value of the basis function \f$\Phi_k(x)\f$
47 : *
48 : * \details We define the basis functions as
49 : * \f{align*}{
50 : * \Phi_k(x)
51 : * &=\begin{cases}
52 : * \hfil \cos(kx) \hfil & \text{if } k \geq 0 \\
53 : * \hfil \sin(-kx) \hfil & \text{if } k < 0
54 : * \end{cases}
55 : * \f}
56 : */
57 : template <typename T>
58 1 : static T basis_function_value(int k, const T& x);
59 :
60 : /*!
61 : * \brief The normalization square \f$c_k\f$ of the basis function
62 : * \f$\Phi_k(x)\f$, i.e. the definite integral of its square.
63 : *
64 : * \details
65 : * In particular,
66 : * \f{align*}{
67 : * c_k
68 : * &=\begin{cases}
69 : * \hfil 2 \pi \hfil & \text{if } k = 0 \\
70 : * \hfil \pi \hfil & \text{otherwise}
71 : * \end{cases}
72 : * \f}
73 : */
74 1 : static double basis_function_normalization_square(int k);
75 :
76 : /*!
77 : * \brief Collocation points \f$\{x_i\}\f$
78 : *
79 : * \details The collocation points on the interval \f$0 \leq x < 2 \pi\f$ are
80 : * given by
81 : * \f[
82 : * x_i = \frac{2 \pi i}{N}
83 : * \f]
84 : */
85 1 : static DataVector collocation_points(size_t num_points);
86 :
87 : /*!
88 : * \brief Quadrature weights \f$\{w_i\}\f$
89 : *
90 : * \details The quadrature weights are given by
91 : * \f[
92 : * w_i = \frac{2 \pi}{N}
93 : * \f]
94 : */
95 1 : static DataVector quadrature_weights(size_t num_points);
96 :
97 : /*!
98 : * \brief Storage index (offset) \f$i\f$ into a ModalVector (representing the
99 : * coefficients) of the given mode \f$k\f$
100 : *
101 : * \details The modal coefficients are stored in a ModalVector as
102 : * \f$\{u_0, u_1, u_{-1}, u_2, u_{-2}, \ldots, u_M, u_{-M}\}\f$,
103 : * where \f$u_{-M}\f$ is omitted if the number of coefficients is even.
104 : * Therefore the storage index \f$i\f$ for the mode \f$u_k\f$ is:
105 : * \f{align*}{
106 : * i
107 : * &=\begin{cases}
108 : * \hfil 0 \hfil & \text{if } k = 0 \\
109 : * \hfil 2k-1 \hfil & \text{if } k > 0 \\
110 : * \hfil -2k \hfil & \text{if } k < 0
111 : * \end{cases}
112 : * \f}
113 : */
114 1 : static size_t modal_storage_index(int k);
115 :
116 : /*!
117 : * \brief Mode \f$k\f$ corresponding to given storage index (offset) \f$i\f$
118 : * into a ModalVector (representing the coefficients)
119 : *
120 : * \details The modal coefficients are stored in a ModalVector as
121 : * \f$\{u_0, u_1, u_{-1}, u_2, u_{-2}, \ldots, u_M, u_{-M}\}\f$,
122 : * where \f$u_{-M}\f$ is omitted if the number of coefficients is even.
123 : * Therefore the storage index \f$i\f$ for the mode \f$u_k\f$ is:
124 : * \f{align*}{
125 : * k
126 : * &=\begin{cases}
127 : * \hfil 0 \hfil & \text{if } i = 0 \\
128 : * \hfil 1 + \frac{i}{2} \hfil & \text{if } i \text{ is odd} \\
129 : * \hfil -\frac{i}{2} \hfil & \text{if } i \text{ is even}
130 : * \end{cases}
131 : * \f}
132 : */
133 1 : static int mode_at_storage_index(size_t storage_index);
134 :
135 : /*!
136 : * \brief Matrix \f$D_{i,j}\f$ used to obtain the first derivative
137 : *
138 : * \details The differentiation matrix is given by:
139 : * \f{align*}{
140 : * D_{i,j}
141 : * &=\begin{cases}
142 : * \hfil 0 \hfil & \text{if } i = j \\
143 : * \hfil \frac{1}{2} (-1)^{i-j} \csc \left[0.5 (x_i - x_j)\right] \hfil &
144 : * \text{if } i \neq j,\; N \text{ is odd} \\
145 : * \hfil \frac{1}{2} (-1)^{i-j} \cot \left[0.5 (x_i - x_j)\right] \hfil &
146 : * \text{if } i \neq j,\; N \text{ is even}
147 : * \end{cases}
148 : * \f}
149 : */
150 1 : static Matrix differentiation_matrix(size_t num_points);
151 :
152 : /*!
153 : * \brief %Matrix used to interpolate to the \p target_points.
154 : *
155 : * \details Each row of the matrix is given by the interpolation weights for
156 : * interpolating to a particular target point \f$x\f$. At each target point,
157 : * \f$x\f$, the interpolation weights are given by:
158 : * \f{align*}{
159 : * C_j(x)
160 : * &=\begin{cases}
161 : * \hfil \frac{1}{N} \sin \left[0.5 N(x - x_j)\right]
162 : * \csc \left[0.5 (x - x_j)\right] \hfil & \text{if } N \text{ is odd} \\
163 : * \hfil \frac{1}{N} \sin \left[0.5 N (x - x_j)\right]
164 : * \cot \left[0.5 (x - x_j)\right] \hfil & \text{if } N \text{ is even}
165 : * \end{cases}
166 : * \f}
167 : * where \f$x_j\f$ are the collocation_points.
168 : */
169 : template <typename T>
170 1 : static Matrix interpolation_matrix(size_t num_points, const T& target_points);
171 : };
172 : } // namespace Spectral
|