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
|