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 "Utilities/Gsl.hpp"
9 :
10 : /// \cond
11 : class DataVector;
12 : template <size_t Dim>
13 : class Mesh;
14 : /// \endcond
15 :
16 : namespace Spectral {
17 :
18 : /*!
19 : * \ingroup SpectralGroup
20 : * \brief Transform nodal ZernikeB2 data on a disk to modal space.
21 : *
22 : * Transforms \p num_components independent disk slices simultaneously. This
23 : * is the same operation as done in the disk filtering, while cylinder
24 : * filtering batches more optimally so we choose not to refactor them to use
25 : * this looped version. The Fourier nodal-to-modal step is applied to all
26 : * components in a single batched DGEMM while the Zernike nodal-to-modal
27 : * step loops over components.
28 : *
29 : * \param modal Output spectral coefficients.
30 : * Size: `num_components * zernike_b2_disk_spectral_size(n_r_max, n_phi/2)`.
31 : * Layout: `modal[comp * spectral_size + spec_index]`.
32 : * \param buf Scratch buffer. Size: `>= 2 * num_components * n_r * n_phi`.
33 : * \param u Input nodal values.
34 : * Size: `num_components * n_r * n_phi`.
35 : * Layout: `u[comp * n_r * n_phi + i_r + n_r * j_phi]`.
36 : * \param n_r Number of radial grid points.
37 : * \param n_phi Number of azimuthal grid points (must be odd).
38 : * \param n_r_max Maximum Zernike degree.
39 : * \param num_components Number of independent disk slices to transform.
40 : */
41 1 : void zernike_b2_disk_nodal_to_modal(gsl::not_null<DataVector*> modal,
42 : gsl::not_null<DataVector*> buf,
43 : const DataVector& u, size_t n_r,
44 : size_t n_phi, size_t n_r_max,
45 : size_t num_components = 1);
46 :
47 : /// @{
48 : /*!
49 : * \ingroup SpectralGroup
50 : * \brief Returns the radial B2 power monitor indexed by radial spectral level
51 : * \f$\ell = (n+1)/2\f$ for a function on a ZernikeB2 disk or cylinder mesh.
52 : *
53 : * \details For functions represented on a filled disk by ZernikeB2 basis
54 : * functions, the radial and angular spectral spaces are coupled. This function
55 : * transforms to the combined ZernikeB2 spectral space and groups based on
56 : * spectral level, meaning all spectral modes \f$(n, m)\f$ satisfying \f$(n+1)/2
57 : * = \ell\f$ (using integer division), across all \f$m\f$ and both cosine and
58 : * sine components, are pooled together.
59 : *
60 : * The returned DataVector has \f$N_r\f$ entries \f$(\ell = 0, 1, \ldots,
61 : * N_r - 1)\f$. The \f$\ell\f$-th entry is
62 : *
63 : * \f{align*}{
64 : * P_\ell[\psi] = \sqrt{ \frac{1}{S_\ell}
65 : * \sum_{\substack{n,m: \\ (n+1)/2 = \ell}} \left| c_{n,m} \right|^2 },
66 : * \f}
67 : *
68 : * where \f$c_{n,m}\f$ are the ZernikeB2 spectral coefficients summing over
69 : * both cosine and sine components for \f$m \geq 1\f$, and \f$S_\ell\f$ is
70 : * the total number of spectral coefficient slots at level \f$\ell\f$
71 : * (including slots that are zero).
72 : *
73 : * For the 3D (cylinder) overload, coefficients are pooled across all
74 : * \f$z\f$-slices: \f$S_\ell\f$ is multiplied by the number of \f$z\f$ points.
75 : */
76 1 : void b2_power_monitor_radial(gsl::not_null<DataVector*> result,
77 : const DataVector& u, const Mesh<2>& mesh);
78 1 : void b2_power_monitor_radial(gsl::not_null<DataVector*> result,
79 : const DataVector& u, const Mesh<3>& mesh);
80 : /// @}
81 :
82 : /// @{
83 : /*!
84 : * \ingroup SpectralGroup
85 : * \brief Returns the B2 power monitor indexed by azimuthal wavenumber \f$m\f$
86 : * for a function on a ZernikeB2 disk or cylinder mesh.
87 : *
88 : * \details For functions represented on a filled disk by ZernikeB2 basis
89 : * functions, the radial and angular spectral spaces are coupled. This function
90 : * transforms to the combined ZernikeB2 spectral space and returns the
91 : * root-mean-square of the spectral coefficients at each azimuthal wavenumber
92 : * \f$m = 0, 1, \ldots, M\f$, where \f$M = N_\phi / 2\f$ and \f$N_\phi\f$ is the
93 : * number of azimuthal grid points.
94 : *
95 : * The returned DataVector has \f$M + 1\f$ entries. The \f$m\f$-th entry is
96 : *
97 : * \f{align*}{
98 : * P_m[\psi] = \sqrt{ \frac{1}{S_m} \sum_n \left| c_{n,m} \right|^2 },
99 : * \f}
100 : *
101 : * where \f$c_{n,m}\f$ are the ZernikeB2 spectral coefficients of \f$\psi\f$
102 : * at angular wavenumber \f$m\f$ (summing over both cosine and sine components
103 : * for \f$m \geq 1\f$), and \f$S_m\f$ is the number of terms in the sum.
104 : *
105 : * For the 3D (cylinder) overload, coefficients are pooled across all
106 : * \f$z\f$-slices: \f$S_m\f$ is multiplied by the number of \f$z\f$ points.
107 : */
108 1 : void b2_power_monitor_angular(gsl::not_null<DataVector*> result,
109 : const DataVector& u, const Mesh<2>& mesh);
110 1 : void b2_power_monitor_angular(gsl::not_null<DataVector*> result,
111 : const DataVector& u, const Mesh<3>& mesh);
112 : /// @}
113 : } // namespace Spectral
|