Line data Source code
1 0 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : #pragma once 5 : 6 : #include <array> 7 : #include <cstddef> 8 : 9 : #include "DataStructures/Tensor/TypeAliases.hpp" 10 : #include "DataStructures/Variables.hpp" 11 : #include "Evolution/Systems/ScalarWave/ApplyTensorYlmFilter.hpp" 12 : #include "Evolution/Systems/ScalarWave/SphericalShellPowerMonitor.hpp" 13 : #include "NumericalAlgorithms/Spectral/Mesh.hpp" 14 : #include "Utilities/Gsl.hpp" 15 : 16 : /// \cond 17 : class DataVector; 18 : /// \endcond 19 : 20 0 : namespace ScalarWave::power_monitor { 21 : 22 : /// Holds separate SW filled-sphere power monitors for each evolved SW variable. 23 : /// Index 0 is the radial monitor and index 1 is the angular monitor. 24 1 : struct SwFilledSpherePowerMonitors { 25 0 : std::array<DataVector, 2> psi{}; 26 0 : std::array<DataVector, 2> pi{}; 27 0 : std::array<DataVector, 2> phi{}; 28 : }; 29 : 30 : /*! 31 : * \brief Compute radial and angular power monitors for the evolved ScalarWave 32 : * variables on a filled-sphere (ZernikeB3) element. 33 : * 34 : * Each monitor is an array with the radial monitor at index 0 and the angular 35 : * monitor at index 1. Both monitors are computed after transforming the SW 36 : * variables to TensorYlm coefficients in the grid frame using 37 : * `jac_inertial_to_grid`. \f$\Psi\f$ and \f$\Pi\f$ are scalars and need no 38 : * frame transform; \f$\Phi_i\f$ is transformed to the grid frame before the 39 : * SH analysis. 40 : * 41 : * **Radial monitor** (index 0): groups squared Jacobi spectral coefficients by 42 : * the radial mode index \f$\text{mode} = (n+1)/2\f$ where 43 : * \f$n = \ell + 2k\f$ is the total ZernikeB3 degree, \f$\ell\f$ is the 44 : * angular degree, and \f$k\f$ is the Jacobi radial index. The result has 45 : * \f$n_r\f$ entries. 46 : * 47 : * **Angular monitor** (index 1): groups squared Jacobi spectral coefficients 48 : * by angular degree \f$\ell\f$. Spin-weighted spherical harmonic modes with 49 : * \f$\ell < |s|\f$ (where \f$s\f$ is the spin weight of the TensorYlm 50 : * component) contribute zero to both the sum and the count. The result has 51 : * \f$\ell_\max + 1\f$ entries. 52 : * 53 : * The Cartesian-to-TensorYlm matrix in `cart_to_sphere_matrix` is filled on 54 : * first use and reused on subsequent calls. 55 : * 56 : * \param cart_to_sphere_matrix Cache for the Cartesian-to-TensorYlm sparse 57 : * matrix. 58 : * \param sw_vars ScalarWave variables at collocation points on the B3 ball 59 : * mesh. 60 : * \param mesh The ZernikeB3 mesh. 61 : * \param jac_inertial_to_grid Inverse Jacobian mapping inertial-frame spatial 62 : * tensor components to the grid frame. 63 : */ 64 1 : SwFilledSpherePowerMonitors sw_filled_sphere_power_monitors( 65 : gsl::not_null<SwCartToSphereMatrix*> cart_to_sphere_matrix, 66 : const Variables< 67 : ylm::TensorYlm::filter_detail::sw_vars_list<Frame::Inertial>>& sw_vars, 68 : const Mesh<3>& mesh, 69 : const InverseJacobian<DataVector, 3, Frame::Inertial, Frame::Grid>& 70 : jac_inertial_to_grid); 71 : 72 : } // namespace ScalarWave::power_monitor