Region sampler (region_sampler)

calc_proj_operator(region_pixel_ra, region_pixel_dec, region_fluxes, region_idxs, ant_pos, antpairs, freqs, times, beams, latitude=-0.5361913261514378)

Calculate a visibility vector for each point source, as a function of frequency, time, and baseline. This is the projection operator from point source amplitude to visibilities. Gains are not included.

Parameters:

Name Type Description Default
region_pixel_ra, region_pixel_dec (list of array_like

RA and Dec of each pixel (axcross all regions), in radians.

required
region_fluxes array_like

Flux for each pixel (across all regions), as a function of frequency.

required
region_idxs list of array_like

List of pixel indices for each region.

required
ant_pos dict

Dictionary of antenna positions, [x, y, z], in m. The keys should be the numerical antenna IDs.

required
antpairs list of tuple

List of tuples containing pairs of antenna IDs, one for each baseline.

required
freqs array_like

Frequencies, in MHz.

required
times array_like

LSTs, in radians.

required
beams list of UVBeam

List of UVBeam objects, one for each antenna.

required
latitude float

Latitude of the observing site, in radians.

-0.5361913261514378

Returns:

Name Type Description
proj_operator array_like

The projection operator from region amplitudes to visibilities. This is an array of the visibility values for each region.

Source code in hydra/region_sampler.py
def calc_proj_operator(
    region_pixel_ra,
    region_pixel_dec,
    region_fluxes,
    region_idxs,
    ant_pos,
    antpairs,
    freqs,
    times,
    beams,
    latitude=-0.5361913261514378,
):
    """
    Calculate a visibility vector for each point source, as a function of
    frequency, time, and baseline. This is the projection operator from point
    source amplitude to visibilities. Gains are not included.

    Parameters:
        region_pixel_ra, region_pixel_dec (list of array_like):
            RA and Dec of each pixel (axcross all regions), in radians.
        region_fluxes (array_like):
            Flux for each pixel (across all regions), as a function of frequency.
        region_idxs (list of array_like):
            List of pixel indices for each region.
        ant_pos (dict):
            Dictionary of antenna positions, [x, y, z], in m. The keys should
            be the numerical antenna IDs.
        antpairs (list of tuple):
            List of tuples containing pairs of antenna IDs, one for each
            baseline.
        freqs (array_like):
            Frequencies, in MHz.
        times (array_like):
            LSTs, in radians.
        beams (list of UVBeam):
            List of UVBeam objects, one for each antenna.
        latitude (float):
            Latitude of the observing site, in radians.

    Returns:
        proj_operator (array_like):
            The projection operator from region amplitudes to visibilities. This
            is an array of the visibility values for each region.
    """
    Nregions = len(region_idxs)
    Nants = len(ant_pos)
    Nvis = len(antpairs)
    ants = list(ant_pos.keys())

    # Empty array of per-point source visibilities
    vis_region = np.zeros((Nvis, freqs.size, times.size, Nregions), dtype=np.complex128)

    # Get visibility for each region
    for j in range(Nregions):
        # Returns shape (NFREQS, NTIMES, NANTS, NANTS)
        vis = simulate_vis(
            ants=ant_pos,
            fluxes=region_fluxes[region_idxs[j], :],
            ra=region_pixel_ra[region_idxs[j]],
            dec=region_pixel_dec[region_idxs[j]],
            freqs=freqs * 1e6,
            lsts=times,
            beams=beams,
            polarized=False,
            precision=2,
            latitude=latitude,
            use_feed="x",
        )

        # Allocate computed visibilities to only available baselines (saves memory)
        for i, bl in enumerate(antpairs):
            idx1 = ants.index(bl[0])
            idx2 = ants.index(bl[1])
            vis_region[i, :, :, j] = vis[:, :, idx1, idx2]

    return vis_region

get_diffuse_sky_model_pixels(freqs, nside=32, sky_model='gsm2016')

Returns arrays of the pixel RA, Dec locations and per-pixel frequency spectra from a given sky model. By default this is GSM, as implemented in pygdsm.

Parameters:

Name Type Description Default
freqs array_like

Frequencies, in MHz.

required
nside int

Healpix nside to use when constructing the sky model.

32
sky_model str

Which sky modle to use, from pyGDSM. One of: 'gsm2008', 'gsm2016', 'haslam', 'lfss'.

'gsm2016'

Returns:

Name Type Description

ra, dec (array_like): ICRS RA and Dec locations of each pixel. RA range is (0, 360) deg, Dec range is (-90, +90) deg, but they are returned in radians.

sky_maps array_like

The frequency spectrum in each pixel. Shape is (Npix, Nfreq).

Source code in hydra/region_sampler.py
def get_diffuse_sky_model_pixels(freqs, nside=32, sky_model="gsm2016"):
    """
    Returns arrays of the pixel RA, Dec locations and per-pixel frequency
    spectra from a given sky model. By default this is GSM, as implemented
    in `pygdsm`.

    Parameters:
        freqs (array_like):
            Frequencies, in MHz.

        nside (int):
            Healpix nside to use when constructing the sky model.

        sky_model (str):
            Which sky modle to use, from pyGDSM. One of:
            'gsm2008', 'gsm2016', 'haslam', 'lfss'.

    Returns:
        ra, dec (array_like):
            ICRS RA and Dec locations of each pixel. RA range is (0, 360) deg, 
            Dec range is (-90, +90) deg, but they are returned in radians.

        sky_maps (array_like):
            The frequency spectrum in each pixel. Shape is `(Npix, Nfreq)`.
    """
    # Get expected frequency units
    freqs_MHz = freqs

    # Initialise sky model and extract data cube
    assert sky_model in [
        "gsm2008",
        "gsm2016",
        "haslam",
        "lfsm",
    ], "Available sky models: 'gsm2008', 'gsm2016', 'haslam', 'lfsm'"
    if sky_model == "gsm2008":
        model = pygdsm.GlobalSkyModel(freq_unit="MHz", include_cmb=False)
    if sky_model == "gsm2016":
        try:
            model = pygdsm.GlobalSkyModel2016(freq_unit="MHz", include_cmb=False)
        except(AttributeError):
            # Different versions of pygdsm changed the API
            model = pygdsm.GlobalSkyModel16(freq_unit="MHz", include_cmb=False)
    if sky_model == "haslam":
        model = pygdsm.HaslamSkyModel(freq_unit="MHz", include_cmb=False)
    if sky_model == "lfsm":
        model = pygdsm.LowFrequencySkyModel(freq_unit="MHz", include_cmb=False)

    model.generate(freqs_MHz)
    sky_maps = model.generated_map_data  # (Nfreqs, Npix), should be in Kelvin

    # Must change nside to make compute practical
    nside_gsm = hp.npix2nside(sky_maps[0].size)
    sky_maps = hp.ud_grade(sky_maps, nside_out=nside)

    # Convert from Kelvin to Jy/sr
    equiv = u.brightness_temperature(freqs_MHz * u.MHz, beam_area=1 * u.sr)
    Ksr_per_Jy = ((1 * u.Jy).to(u.K, equivalencies=equiv) * u.sr / u.Jy).value
    for i in range(Ksr_per_Jy.size):
        sky_maps[i] /= Ksr_per_Jy[i]  # converts K to Jy/sr

    # Get pixel RA/Dec coords (assumes Galactic coords for sky map data)
    idxs = np.arange(sky_maps[0].size)
    pix_lon, pix_lat = hp.pix2ang(nside, idxs, lonlat=True)
    gal_coords = Galactic(l=pix_lon * u.deg, b=pix_lat * u.deg)

    icrs_frame = ICRS()
    eq_coords = gal_coords.transform_to(icrs_frame)
    ra = eq_coords.ra.rad
    dec = eq_coords.dec.rad

    # Returns list of pixels with spectra as effective point sources
    return ra, dec, sky_maps.T

segmented_diffuse_sky_model_pixels(ra, dec, sky_maps, freqs, nregions, smoothing_fwhm=None)

Returns a list of pixel indices for each region in a diffuse sky map. This function currently uses a crude spectral index measurement to segment the map into regions with roughly equal numbers of pixels. Smoothing can be used to reduce sharp edges. The regions can be disconnected.

Parameters:

Name Type Description Default
ra, dec (array_like

ICRS RA and Dec locations of each pixel.

required
sky_maps array_like

The frequency spectrum in each pixel.

required
freqs array_like

Frequencies, in MHz.

required
nregions int

The number of regions of roughly equal numbers of pixels to segment the sky map into.

required
smoothing_fwhm float

Smoothing FWHM (in degrees) to apply to the segmented map in order to reduce sharp edges. The smoothing is applied to a map of region indices. It is then re-segmented, which can result in a slight reduction in the number of segments due to round-off of region indices.

None

Returns:

Name Type Description
idxs list of array_like

List of arrays, with each array containing the array indices of the pixels that belong to each region.

Source code in hydra/region_sampler.py
def segmented_diffuse_sky_model_pixels(
    ra, dec, sky_maps, freqs, nregions, smoothing_fwhm=None
):
    """
    Returns a list of pixel indices for each region in a diffuse sky map.
    This function currently uses a crude spectral index measurement to
    segment the map into regions with roughly equal numbers of pixels.
    Smoothing can be used to reduce sharp edges. The regions can be
    disconnected.

    Parameters:
        ra, dec (array_like):
            ICRS RA and Dec locations of each pixel.

        sky_maps (array_like):
            The frequency spectrum in each pixel.

        freqs (array_like):
            Frequencies, in MHz.

        nregions (int):
            The number of regions of roughly equal numbers of pixels to
            segment the sky map into.

        smoothing_fwhm (float):
            Smoothing FWHM (in degrees) to apply to the segmented map in
            order to reduce sharp edges. The smoothing is applied to a map
            of region indices. It is then re-segmented, which can result
            in a slight reduction in the number of segments due to
            round-off of region indices.

    Returns:
        idxs (list of array_like):
            List of arrays, with each array containing the array indices
            of the pixels that belong to each region.
    """
    # Crude spectral index map
    beta = np.log(sky_maps[:, 0] / sky_maps[:, 1]) / np.log(freqs[0] / freqs[1])

    # Sort spectral index map and break up into ~equal-sized segments
    beta_sorted = np.sort(beta)
    bounds = beta_sorted[:: beta_sorted.size // nregions]

    # Loop over regions and select pixels belonging to each region
    regions = np.zeros(beta.size, dtype=int)
    for i in range(bounds.size - 1):
        # These have >= and <= to ensure that all pixels belong somewhere
        idxs = np.where(np.logical_and(beta >= bounds[i], beta <= bounds[i + 1]))
        regions[idxs] = i

    # Apply smoothing and then re-segment
    if smoothing_fwhm is not None:
        regions_smoothed = hp.smoothing(regions, fwhm=np.deg2rad(smoothing_fwhm))
        regions_final = regions_smoothed.astype(int)
    else:
        regions_final = regions

    # Create list of indices
    unique_idxs = np.sort(np.unique(regions_final))
    idx_list = [np.where(regions_final == i)[0] for i in unique_idxs]
    return idx_list