primary_beam_cuda

Tests for the functions in WODEN/src/primary_beam_cuda.cu. These functions calculate the beam responses for the following beam models:

  • Gaussian - a frequency dependent Gaussian beam; FWHM can be set by user

  • EDA2 - a single MWA dipole on an infinite ground screen

  • MWA analytic - an analytic model of the MWA primary beam taken from the RTS

  • MWA FEE (coarse) - the Fully Embedded Element MWA model (1.28 MHz frequency resolution)

  • MWA FEE (interp) - frequency interpolated MWA FEE model (80 kHz resolution between 167 - 197 MHz)

See Primary Beams for more discussion on primary beams.

test_gaussian_beam.c

This calls primary_beam_cuda::test_kern_gaussian_beam, which in turn tests primary_beam_cuda::kern_gaussian_beam, the kernel that calculates the Gaussian primary beam response. As a Gaussian is an easy function to calculate, I’ve setup tests that calculate a north-south and east-west strip of the beam response, and then compare that to a 1D Gaussian calculation.

As kern_gaussian_beam just takes in l,m coords, these tests just generate 100 l,m coords that span from -1 to +1. The tests check whether the kernel produces the expected coordinates in the l and m strips, as well as changing with frequency as expected, by testing 5 input frequencies with a given reference frequency. For each input frequency \(\nu\), the output is checked against the following calculations:

  • When setting m = 0, assert gain = \(\exp\left[-\frac{1}{2} \left( \frac{l}{\sigma} \frac{\nu}{\nu_0} \right)^2 \right]\)

  • When setting l = 0, assert gain = \(\exp\left[-\frac{1}{2} \left( \frac{m}{\sigma} \frac{\nu}{\nu_0} \right)^2 \right]\)

where \(\nu_0\) is the reference frequency, and \(\sigma_0\) the std of the Gaussian in terms of l,m coords. These calculations are made using C with 64 bit precision. The beam responses are tested to be within an absolute tolerance of 1e-10 from expectations for the FLOAT compiled code, and 1e-16 for the DOUBLE compiled code.

test_analytic_dipole_beam.c

This calls primary_beam_cuda::test_analytic_dipole_beam, which in turn tests primary_beam_cuda::calculate_analytic_dipole_beam, code that copies az/za angles into GPU memory, calculates an analytic dipole response toward those directions, and then frees the az/za coords from GPU memory.

Nothing exiting in this test, just call the function for 25 directions on the sky, for two time steps and two frequencies (a total of 100 beam calculations), and check that the real beam gains match stored expected values, and the imaginary values equal zero. The expected values have been generated using the DOUBLE precision compiled code, and so the absolute tolerance of within 1e-12 is set by how many decimal places I’ve stored in the lookup table. The FLOAT precision must match within 1e-6 of these stored values.

test_MWA_analytic.c

Todo

stick the maths of what the analytic beam does here (it is involved).

This calls primary_beam_cuda::test_calculate_MWA_analytic_beam, which calls primary_beam_cuda::calculate_MWA_analytic_beam, which calculates an analytic version of the MWA primary beam, based on ideal dipoles. This code calculates the primary beam response of the MWA using methods from RTS. The analytic beam is purely real.

This test runs with an off-zenith pointing, with a grid of 101 by 101 of az/za or two time steps, and two frequencies (150 and 200MHz). The az/za coords for both time steps are identical, but test whether the time/frequency ordering of the outputs are correct. The beam responses are tested to be within an absolute tolerance of 1e-6 from expectations for the FLOAT compiled code, and 1e-8 for the DOUBLE compiled code (the responses are only stored to 1e-8 precision for testing to save space on disk).

If you want to look at your outputs, you can run the notebook located at cmake_testing/primary_beam_cuda/run_header_setup_and_plots.ipynb. Along with setting up the az/za coords used in the testing, it will generate a number of plots. It will plot the real gains and leakages of the MWA analytic beam (e.g. jones_MWA_analy_gains_nside101_t00_f200.000MHz.png):

../../_images/jones_MWA_analy_gains_nside101_t00_f200.000MHz.png

as well as the linear Stokes polarisations (e.g. linear_pol_MWA_analy_gains_nside101_t00_f200.000MHz.png):

../../_images/linear_pol_MWA_analy_gains_nside101_t00_f200.000MHz.png

test_run_hyperbeam.c

This calls primary_beam_cuda::test_run_hyperbeam_cuda, which calls primary_beam_cuda::run_hyperbeam_cuda, which is a wrapper around mwa_hyperbeam to calculate the MWA FEE beam.

The MWA beam pointing direction on the sky is controlled by a set of 16 delays. In these tests, three different delays settings are tested at 50MHz, 150MHz, and 250MHz (a total of nine tests). Each test is run with ~10,000 sky directions, for two time steps (with identical az/za coords; in reality, those change with time) and three fine frequency channels. The fine frequency channels all lie with a 1.28MHz frequency resolution of the FEE beam model, so should come out identically. Test with two times and three freqs to check our indexing is working correctly. For each combination of settings, the beam gains output by test_run_hyperbeam.c are compared to those stored in the header test_run_hyperbeam.h.

The header test_run_hyperbeam.h is generated by the notebook run_header_setup_and_plots.ipynb, which uses the Python implementation of mwa_hyperbeam to calculate expected outcomes.

All delay and frequency combinations are run with both parallactic angle rotation applied and not. Both the FLOAT and DOUBLE codes are checked to match the Python version of mwa_hyperbeam to a tolerance of 1e-6 (only one library is linked from mwa_hyperbeam so the accuracy is the same). Again, running run_header_setup_and_plots.ipynb will produce plots.

When applying parallactic angle rotation, and latitude is required, which can change with time (happens when precessing the array back to J2000 for every time step). To check things are working, two time steps with different latitudes are called. To accomodate all these variables, a smaller number of directions on the sky are used to save space / computation.

First, an example zenith pointing in Stokes linear (linear_pol_hyperbeam_rot_zenith_gains_nside51_t00_f200.000MHz.png):

../../_images/linear_pol_hyperbeam_rot_zenith_gains_nside51_t00_f200.000MHz.png

and the equivalent hyperbeam outputs to the pointing used above in test_MWA_analytic.c for comparison:

../../_images/jones_hyperbeam_rot_offzen2_gains_nside51_t00_f200.000MHz.png

as well as the linear Stokes polarisations (e.g. linear_pol_MWA_analy_gains_nside101_t00_f200.000MHz.png):

../../_images/linear_pol_hyperbeam_rot_offzen2_gains_nside51_t00_f200.000MHz.png

which shows qualitatively the Stokes polarisation responses off zenith are broadly similar between the analytic and FEE beams, but the mutual coupling does modify the response. The gains and leakages are strikingly different, but this is in part because the analytic beam is purely real, whereas the FEE model is complex.

test_run_hyperbeam_interp.c

This calls primary_beam_cuda::test_run_hyperbeam_cuda, which calls primary_beam_cuda::run_hyperbeam_cuda, which is a wrapper around mwa_hyperbeam to calculate the MWA FEE beam. Unlike test_run_hyperbeam.c however, we used the interpolated hdf5 file which has a higher frequency resolution, to give a smooth response as a function of frequency.

Three tests are run, with three different pointings and three different frequency ranges. The output values are then tested against values output by python version of hyperdrive, with the outputs tested to a tolerance of 1e-10.

Only five coordinate directions are tested, as the accuracy of the beam across the sky is tested for many many directions by test_run_hyperbeam.c, which is using the same code. This test is really check that the correct frequencies are called, and subsequently mapped correctly. Again, we can plot the outputs using run_header_setup_and_plots.ipynb,which yields plots like offzen1_freqs2.png, plotting the gains and leakages as a function of frequency, for five different direction on the sky (each a different row):

../../_images/offzen1_freqs2.png