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