pyuvdata icon indicating copy to clipboard operation
pyuvdata copied to clipboard

Add support for feed position angles

Open telegraphic opened this issue 1 year ago • 7 comments

Currently, the UVData object does not support arbitrary feed polarization angles. This would be useful, and UVFITS/MS files already support this (see below). My personal motivation is that the upcoming SKA-Low stations are all rotated at different angles for "polarization diversity" and to improve sidelobe response between antenna pairs.

Currently, when writing to UVFITS the polarization angle keywords are hardcoded. I can't see anything similar for MS, which uses the RECEPTOR_ANGLE keyword -- presumably casacore fills these with default values.

To make this possible, I think the following would have to happen:

  1. An attribute is added to UVData, e.g. UVData.feed_polarization_angle and __init__ is updated accordingly (with (90, 0) degrees as default values).
  2. All writers are updated to use these values.
  3. All readers are updated to read the relevant keywords when creating a UVData object.
  4. Tests are written (roundtrip conversion, e.g. UVData -> UVFITS -> UVData would exercise both read and write).
  5. Documentation is updated.

I don't have enough free cycles to take all this on, but I have some example code for UVFITS + MS below.

UVFITS keywords

From AIPS Memo 117.

In UVFITS, AIPS AN antenna table, the columns POLAA and POLAB should be updated:

POLAA  1E  degrees  Position angle feed A
POLAB  1E  degrees  Position angle feed B

The value of the POLAA column shall be the orientation of feed A, assumed independent of IF, given in degrees. Similarly, the POLAB column shall contain the feed orientation for feed B.

MS keywords

Need to update RECEPTOR_ANGLE column of the FEED table of a measurement set: https://safe.nrao.edu/wiki/bin/view/ALMA/ReceptorAngles

These angles are stored in radians. If there are multiple receiver bands in a measurement set, then multiple angles will be shown.

Miriad

No idea what keywords would need to change.

Proto-code


def write_ms(uv: UVData, filename: str, *args, **kwargs):
    """Write UVData to MeasurementSet.

    Notes:
        Calls uv.write_ms(), then applies station rotation patch.
    Args:
        uv (UVData): pyuvdata object to write to file.
        filename (str): Name of output filename.
        args (list): Arguments to pass to uv.write_ms
        kwargs (dict): Keyword arguments to pass to uv.write_ms
    """
    tables = import_optional_dependency('casacore.tables', errors='raise')

    uv.write_ms(filename, *args, **kwargs)

    # Patch RECEPTOR_ANGLE column
    with tables.table(f'{filename}/FEED', readonly=False) as t:
        logger.debug('Applying station rotation (RECEPTOR_ANGLE)')
        r_ang = np.zeros(shape=t.getcol('RECEPTOR_ANGLE').shape, dtype='float64')
        x_ang = -np.pi/180 * uv.receptor_angle
        r_ang[:, 0] = x_ang
        r_ang[:, 1] = x_ang + np.pi

        t.putcol('RECEPTOR_ANGLE', r_ang)


def write_uvfits(uv: UVData, filename: str, *args, **kwargs):
    """Write UVData to UVFITS.

    Notes:
        Calls uv.write_uvfits(), then applies station rotation patch.
    Args:
        uv (UVData): pyuvdata object to write to file.
        filename (str): Name of output filename.
        args (list): Arguments to pass to uv.write_uvfits
        kwargs (dict): Keyword arguments to pass to uv.write_uvfits
    """
    uv.write_uvfits(filename, *args, **kwargs)

    # Patch POLAA/POLAB columns
    with pf.open(filename, mode='update') as hdu:
        logger.debug('Applying station rotation (POLAA/POLAB)')
        hdu[1].data['POLAA'] = uv.receptor_angle
        hdu[1].data['POLAB'] = uv.receptor_angle + 90

telegraphic avatar Aug 23 '24 12:08 telegraphic