示例#1
0
def hyperbeam(za, az, frequencies, fluxes, metafits=None):
    """Calculate MWA beam response using Hyperbeam package

    Parameters
    ----------
    za : array-like
        Zenith angles in radians
    az : array-like
        Azimuth angles in radians
    frequencies : array-like
        frequency channels
    fluxes : array-like
        Source flux densities in Jys
    metafits : string, optional
        Path to observation ID metafits file, by default None
    Returns
    -------
    numpy array
        Fluxes attenuated by MWA beam response
    """
    hbeam = mwa_hyperbeam.FEEBeam(
        "/home/kariuki/mwa_pb/mwa_full_embedded_element_pattern.h5")
    with fits.open(metafits) as hdu:
        delays = list(map(int, hdu[0].header["DELAYS"].split(",")))
    amps = [1] * 16
    beam_norm = True
    hjones = np.zeros((len(za), len(frequencies), 4), dtype=np.complex64)
    for chan in range(len(frequencies)):
        hjones[:, chan, :] = hbeam.calc_jones_array(az, za,
                                                    int(frequencies[chan]),
                                                    delays, amps, beam_norm)

    fluxes[:, :,
           0] = (hjones[:, :, 0] * np.conj(hjones[:, :, 0]) * fluxes[:, :, 0] +
                 hjones[:, :, 1] * np.conj(hjones[:, :, 1]) * fluxes[:, :, 0])

    fluxes[:, :,
           3] = (hjones[:, :, 2] * np.conj(hjones[:, :, 2]) * fluxes[:, :, 3] +
                 hjones[:, :, 3] * np.conj(hjones[:, :, 3]) * fluxes[:, :, 3])

    return fluxes
示例#2
0
def MWA_Tile_full_EE(za,
                     az,
                     freq,
                     delays=None,
                     zenithnorm=True,
                     power=True,
                     jones=False,
                     interp=True,
                     pixels_per_deg=5):
    """
    Use the new MWA tile model from beam_full_EE.py that includes mutual coupling
    and the simulated dipole response. Returns the XX and YY response to an
    unpolarised source.

    if jones=True, will return the Jones matrix instead of the XX,YY response.
    In this case, the power flag will be ignored.
    If interp=False, the pixels_per_deg will be ignored

    delays should be a numpy array of size (2,16), although a (16,) list or a (16,) array will also be accepted

    az - azimuth angles (radians), north through east.
    za - zenith angles (radian)
    """
    # Convert za and az into 2D numpy arrays, because the Advanced and FullEE models require that format.
    if type(za) is list:
        za = np.array(za)
    if type(az) is list:
        az = np.array(az)

    if (isinstance(za, float)) and (isinstance(
            az, float)):  # Convert float to 2D array
        za = np.array([[za]])
        az = np.array([[az]])
        dtype = 'float'
    elif (isinstance(za, np.ndarray)) and (isinstance(az, np.ndarray)):
        if (len(za.shape) == 1) and (len(az.shape)
                                     == 1):  # 1D array, convert to 2D array
            za = za[None, :]
            az = az[None, :]
            dtype = '1D'
        elif (len(za.shape) == 2) and (len(az.shape) == 2):
            dtype = '2D'
        else:
            dtype = 'bad'
    else:
        dtype = 'bad'

    if dtype == 'bad':
        logger.error(
            'ERROR - az/za data types must be the same, and either floats or 1 or 2 dimensional arrays'
        )
        return None

    # If we're not interpolating, and we could import hyperbeam, then use it to
    # calculate the Jones matrices.
    if not interp and "mwa_hyperbeam" in sys.modules:
        # Make "hyperbeam" a global variable to the Rust object. If it doesn't
        # exist, we need to create one.
        if "hyperbeam" not in globals():
            global hyperbeam
            try:
                # If this fails, it's either because MWA_BEAM_FILE isn't
                # defined, or there's something wrong with the file that
                # variable points to.
                hyperbeam = mwa_hyperbeam.FEEBeam()
            except mwa_hyperbeam.HyperbeamError:
                # Use the HDF5 file that's hopefully installed in mwa_pb.
                datadir = os.path.join(os.path.dirname(__file__), 'data')
                h5file = os.path.join(datadir,
                                      'mwa_full_embedded_element_pattern.h5')
                hyperbeam = mwa_hyperbeam.FEEBeam(h5file)

        # Rather than repeat the command to hyperbeam a bunch of times for
        # slightly different arguments, make a partially-applied function
        # (lambda).
        f = lambda d: hyperbeam.calc_jones_array(az[0, :],
                                                 za[0, :],
                                                 freq_hz=freq,
                                                 amps=[1] * 16,
                                                 delays=d,
                                                 norm_to_zenith=zenithnorm)
        if delays.shape[0] == 2:
            # Assume that both rows of the delays array are the same.
            j_flat = f(delays[0])
        else:
            j_flat = f(delays)
        # Make j in the format that the rest of mwa_pb expects.
        j = j_flat.reshape((1, -1, 2, 2))

    # Calculate the Jones matrices using the existing Python code.
    else:
        tile = beam_full_EE.get_AA_Cached(target_freq_Hz=freq)
        mybeam = beam_full_EE.Beam(
            tile, delays, amps=np.ones([2, 16])
        )  # calling with amplitudes=1 every time - otherwise they get overwritten !!!
        if interp:
            j = mybeam.get_interp_response(az, za, pixels_per_deg)
        else:
            j = mybeam.get_response(az, za)
        if zenithnorm:
            j = tile.apply_zenith_norm_Jones(j)  # Normalise

        # TO DO: do frequency interpolation here (with 2nd adjacent beam)

        # Use swapaxis to place jones matrices in last 2 dimensions
        # insead of first 2 dims.
        if len(j.shape) == 4:
            j = np.swapaxes(np.swapaxes(j, 0, 2), 1, 3)
        elif len(j.shape) == 3:  # 1-D
            j = np.swapaxes(np.swapaxes(j, 1, 2), 0, 1)
        else:  # single value
            pass

    if jones:
        if dtype == 'float':
            return j[0][0]
        elif dtype == '1D':
            return j[0]
        else:
            return j

    # Use mwa_tile makeUnpolInstrumentalResponse because we have swapped axes
    vis = mwa_tile.makeUnpolInstrumentalResponse(j, j)
    if not power:
        xx, yy = (np.sqrt(vis[:, :, 0, 0].real), np.sqrt(vis[:, :, 1, 1].real))
    else:
        xx, yy = (vis[:, :, 0, 0].real, vis[:, :, 1, 1].real)

    if dtype == 'float':
        return xx[0][0], yy[0][0]
    elif dtype == '1D':
        return xx[0], yy[0]
    else:
        return xx, yy
示例#3
0
import requests
import random
from astropy.table import Table
from astropy.coordinates import SkyCoord
import gc
gc.enable()

#from mwapy import ephem_utils,metadata
from vcstools.metadb_utils import getmeta, get_common_obs_metadata, get_ambient_temperature
from vcstools.pointing_utils import getTargetAZZA, getTargetRADec
from vcstools.general_utils import setup_logger, split_remove_remainder
from vcstools import data_load
from mwa_pb import primary_beam as pb
from mwa_pb import config
import mwa_hyperbeam
beam = mwa_hyperbeam.FEEBeam(config.h5file)
from vcstools.beam_calc import get_Trec
from vcstools.beam_sim import getTileLocations, get_obstime_duration, partial_convolve_sky_map,\
                              calcWaveNumbers, calcSkyPhase, calcArrayFactor, calc_pixel_area,\
                              calc_geometric_delay_distance, cal_phase_ord

logger = logging.getLogger(__name__)


def createArrayFactor(za, az, pixel_area, data):
    """
    Primary function to calculate the array factor with the given information.

    Input:
      delays - the beamformer delays required for point tile beam (should be a set of 16 numbers)
      time -  the time at which to evaluate the target position (as we need Azimuth and Zenith angle, which are time dependent)
def test_hyperbeam_vs_pb():
    """Compares the results of the FEE beam model using mwa_pb and mwa_hyperbeam."""
    beam = mwa_hyperbeam.FEEBeam(config.h5file)

    # Set up fake data.
    n = 100000
    az = np.linspace(0, 0.9 * np.pi, n)
    za = np.linspace(0.1, 0.9 * np.pi / 2, n)
    freq = 167000000
    delays = [0] * 16
    amps = [1.0] * 16
    test_decimals = 4

    # Jones --------------------------------------------------
    print("Jones benchmarks")
    # mwa_pb method
    start_time = time.perf_counter()
    pb_jones = primary_beam.MWA_Tile_full_EE(za,
                                             az,
                                             freq=freq,
                                             delays=np.array(delays),
                                             zenithnorm=True,
                                             power=True,
                                             jones=True,
                                             interp=False)
    print("mwa_pb:    {:6.3f} s".format(time.perf_counter() - start_time))

    # hyperbeam method
    #print(freq, delays, amps)
    start_time = time.perf_counter()
    hb_jones = beam.calc_jones_array(az, za, freq, delays, amps, True)
    print("hyperbeam: {:6.3f} s".format(time.perf_counter() - start_time))
    hb_jones = hb_jones.reshape(n, 2, 2)

    # Compare Jones
    assert_almost_equal(pb_jones, hb_jones, decimal=test_decimals)

    # Power ---------------------------------------------------
    print("\nPower benchmarks")
    # mwa_pb method
    start_time = time.perf_counter()
    pb_xx, pb_yy = primary_beam.MWA_Tile_full_EE(za,
                                                 az,
                                                 freq=freq,
                                                 delays=np.array(delays),
                                                 zenithnorm=True,
                                                 power=True)
    print("mwa_pb:    {:6.3f} s".format(time.perf_counter() - start_time))

    # hyperbeam method
    start_time = time.perf_counter()
    hb_jones = beam.calc_jones_array(az, za, freq, delays, amps, True)
    hb_jones = hb_jones.reshape(1, n, 2, 2)
    vis = primary_beam.mwa_tile.makeUnpolInstrumentalResponse(
        hb_jones, hb_jones)
    hb_xx, hb_yy = (vis[:, :, 0, 0].real, vis[:, :, 1, 1].real)
    print("hyperbeam: {:6.3f} s".format(time.perf_counter() - start_time))

    # Compare power
    assert_almost_equal(pb_xx, hb_xx[0], decimal=test_decimals)
    assert_almost_equal(pb_yy, hb_yy[0], decimal=test_decimals)
def get_beam_power_over_time(names_ra_dec,
                             common_metadata=None,
                             dt=296,
                             centeronly=True,
                             verbose=False,
                             option='analytic',
                             degrees=False,
                             start_time=0):
    """Calculates the zenith normalised power for each source over time.

    Parameters
    ----------
    names_ra_dec : `list`
        An array in the format [[source_name, RAJ, DecJ]]
    common_metadata : `list`, optional
        The list of common metadata generated from :py:meth:`vcstools.metadb_utils.get_common_obs_metadata`
    dt : `int`, optional
        The time interval of how often powers are calculated. |br| Default: 296.
    centeronly : `boolean`, optional
        Only calculates for the centre frequency. |br| Default: `True`.
    verbose : `boolean`, optional
        If `True` will not supress the output from mwa_pb. |br| Default: `False`.
    option : `str`, optional
        The primary beam model to use out of [analytic, advanced, full_EE, hyperbeam]. |br| Default: analytic.
    degrees : `boolean`, optional
        If true assumes RAJ and DecJ are in degrees. |br| Default: `False`.
    start_time : `int`, optional
        The time in seconds from the begining of the observation to start calculating at. |br| Default: 0.

    Returns
    -------
    Powers : `numpy.array`, (len(names_ra_dec), ntimes, nfreqs)
        The zenith normalised power for each source over time.
    """
    if common_metadata is None:
        common_metadata = get_common_obs_metadata(obsid)
    obsid, _, _, time, delays, centrefreq, channels = common_metadata
    names_ra_dec = np.array(names_ra_dec)
    amps = [1.0] * 16
    logger.debug("Calculating beam power for OBS ID: {0}".format(obsid))

    if option == 'hyperbeam':
        if "mwa_hyperbeam" not in sys.modules:
            logger.error(
                "mwa_hyperbeam not installed so can not use hyperbeam to create a beam model. Exiting"
            )
            sys.exit(1)
        beam = mwa_hyperbeam.FEEBeam(config.h5file)

    # Work out time steps to calculate over
    starttimes = np.arange(start_time, time + start_time, dt)
    stoptimes = starttimes + dt
    stoptimes[stoptimes > time] = time
    ntimes = len(starttimes)
    midtimes = float(obsid) + 0.5 * (starttimes + stoptimes)

    # Work out frequency steps
    if centeronly:
        if centrefreq > 1e6:
            logger.warning(
                "centrefreq is greater than 1e6, assuming input with units of Hz."
            )
            frequencies = np.array([centrefreq])
        else:
            frequencies = np.array([centrefreq]) * 1e6
        nfreqs = 1
    else:
        # in Hz
        frequencies = np.array(channels) * 1.28e6
        nfreqs = len(channels)

    # Set up np power array
    PowersX = np.zeros((len(names_ra_dec), ntimes, nfreqs))
    PowersY = np.zeros((len(names_ra_dec), ntimes, nfreqs))

    # Convert RA and Dec to desired units
    if degrees:
        RAs = np.array(names_ra_dec[:, 1], dtype=float)
        Decs = np.array(names_ra_dec[:, 2], dtype=float)
    else:
        RAs, Decs = sex2deg(names_ra_dec[:, 1], names_ra_dec[:, 2])
    # Then check if they're valid
    if len(RAs) == 0:
        sys.stderr.write('Must supply >=1 source positions\n')
        return None
    if not len(RAs) == len(Decs):
        sys.stderr.write('Must supply equal numbers of RAs and Decs\n')
        return None

    if verbose is False:
        #Supress print statements of the primary beam model functions
        sys.stdout = open(os.devnull, 'w')
    for itime in range(ntimes):
        # this differ's from the previous ephem_utils method by 0.1 degrees
        _, Azs, Zas = mwa_alt_az_za(midtimes[itime],
                                    ra=RAs,
                                    dec=Decs,
                                    degrees=True)
        # go from altitude to zenith angle
        theta = np.radians(Zas)
        phi = np.radians(Azs)
        for ifreq in range(nfreqs):
            #Decide on beam model
            if option == 'analytic':
                rX, rY = primary_beam.MWA_Tile_analytic(
                    theta,
                    phi,
                    freq=frequencies[ifreq],
                    delays=delays,
                    zenithnorm=True,
                    power=True)
            elif option == 'advanced':
                rX, rY = primary_beam.MWA_Tile_advanced(
                    theta,
                    phi,
                    freq=frequencies[ifreq],
                    delays=delays,
                    zenithnorm=True,
                    power=True)
            elif option == 'full_EE':
                rX, rY = primary_beam.MWA_Tile_full_EE(theta,
                                                       phi,
                                                       freq=frequencies[ifreq],
                                                       delays=delays,
                                                       zenithnorm=True,
                                                       power=True)
            elif option == 'hyperbeam':
                jones = beam.calc_jones_array(phi, theta,
                                              int(frequencies[ifreq]),
                                              delays[0], amps, True)
                jones = jones.reshape(1, len(phi), 2, 2)
                vis = primary_beam.mwa_tile.makeUnpolInstrumentalResponse(
                    jones, jones)
                rX, rY = (vis[:, :, 0, 0].real, vis[:, :, 1, 1].real)
        PowersX[:, itime, ifreq] = rX
        PowersY[:, itime, ifreq] = rY
    if verbose is False:
        sys.stdout = sys.__stdout__
    Powers = 0.5 * (PowersX + PowersY)
    return Powers