def test_phase_rotate(self): uvw = numpy.array([(1, 0, 0), (0, 1, 0), (0, 0, 1)]) pos = [ SkyCoord(17, 35, unit=u.deg), SkyCoord(17, 30, unit=u.deg), SkyCoord(12, 30, unit=u.deg), SkyCoord(11, 35, unit=u.deg), SkyCoord(51, 35, unit=u.deg), SkyCoord(15, 70, unit=u.deg) ] # Sky coordinates to reproject to for phasecentre in pos: for newphasecentre in pos: # Rotate UVW xyz = uvw_to_xyz(uvw, -phasecentre.ra.rad, phasecentre.dec.rad) uvw_rotated = xyz_to_uvw(xyz, -newphasecentre.ra.rad, newphasecentre.dec.rad) # Determine phasor l_p, m_p, n_p = skycoord_to_lmn(phasecentre, newphasecentre) phasor = simulate_point(uvw_rotated, l_p, m_p) for sourcepos in pos: # Simulate visibility at old and new phase centre l, m, _ = skycoord_to_lmn(sourcepos, phasecentre) vis = simulate_point(uvw, l, m) l_r, m_r, _ = skycoord_to_lmn(sourcepos, newphasecentre) vis_rotated = simulate_point(uvw_rotated, l_r, m_r) # Difference should be given by phasor assert_allclose(vis * phasor, vis_rotated, atol=1e-10)
def predict_skycomponent_visibility( vis: Union[Visibility, BlockVisibility], sc: Union[Skycomponent, List[Skycomponent]]) -> Visibility: """Predict the visibility from a Skycomponent, add to existing visibility, for Visibility or BlockVisibility :param vis: Visibility or BlockVisibility :param sc: Skycomponent or list of SkyComponents :return: Visibility or BlockVisibility """ if not isinstance(sc, collections.Iterable): sc = [sc] if isinstance(vis, Visibility): _, im_nchan = list(get_frequency_map(vis, None)) npol = vis.polarisation_frame.npol for comp in sc: assert_same_chan_pol(vis, comp) l, m, n = skycoord_to_lmn(comp.direction, vis.phasecentre) phasor = simulate_point(vis.uvw, l, m) for ivis in range(vis.nvis): for pol in range(npol): vis.data['vis'][ivis, pol] += comp.flux[im_nchan[ivis], pol] * phasor[ivis] elif isinstance(vis, BlockVisibility): nchan = vis.nchan npol = vis.npol k = numpy.array(vis.frequency) / constants.c.to('m/s').value for comp in sc: assert_same_chan_pol(vis, comp) flux = comp.flux if comp.polarisation_frame != vis.polarisation_frame: flux = convert_pol_frame(flux, comp.polarisation_frame, vis.polarisation_frame) l, m, n = skycoord_to_lmn(comp.direction, vis.phasecentre) for chan in range(nchan): phasor = simulate_point(vis.uvw * k[chan], l, m) for pol in range(npol): vis.data['vis'][..., chan, pol] += flux[chan, pol] * phasor[...] return vis
def predict_skycomponent_visibility( vis: Visibility, sc: Union[Skycomponent, List[Skycomponent]]) -> Visibility: """Predict the visibility from a Skycomponent, add to existing visibility, for Visibility :param vis: Visibility :param sc: Skycomponent or list of SkyComponents :return: Visibility """ assert type(vis) is Visibility, "vis is not a Visibility: %r" % vis if not isinstance(sc, collections.Iterable): sc = [sc] _, ichan = list(get_frequency_map(vis, None)) npol = vis.polarisation_frame.npol for comp in sc: l, m, n = skycoord_to_lmn(comp.direction, vis.phasecentre) phasor = simulate_point(vis.uvw, l, m) for ivis in range(vis.nvis): for pol in range(npol): vis.data['vis'][ivis, pol] += comp.flux[ichan[ivis], pol] * phasor[ivis] # coords = phasor, ichan # for pol in range(npol): # vis.data['vis'][:,pol] += [comp.flux[ic, pol] * p for p, ic in zip(*coords)] return vis
def sum_visibility(vis: Visibility, direction: SkyCoord) -> numpy.array: """ Direct Fourier summation in a given direction :param vis: Visibility to be summed :param direction: Direction of summation :return: flux[nch,npol], weight[nch,pol] """ # TODO: Convert to Visibility or remove? svis = copy_visibility(vis) l, m, n = skycoord_to_lmn(direction, svis.phasecentre) phasor = numpy.conjugate(simulate_point(svis.uvw, l, m)) # Need to put correct mapping here _, frequency = get_frequency_map(svis, None) frequency = list(frequency) nchan = max(frequency) + 1 npol = svis.polarisation_frame.npol flux = numpy.zeros([nchan, npol]) weight = numpy.zeros([nchan, npol]) coords = svis.vis, svis.weight, phasor, list(frequency) for v, wt, p, ic in zip(*coords): for pol in range(npol): flux[ic, pol] += numpy.real(wt[pol] * v[pol] * p) weight[ic, pol] += wt[pol] flux[weight > 0.0] = flux[weight > 0.0] / weight[weight > 0.0] flux[weight <= 0.0] = 0.0 return flux, weight
def test_simulate_point(self): # Prepare a synthetic layout uvw = numpy.concatenate(numpy.concatenate(numpy.transpose(numpy.mgrid[-3:4, -3:4, 0:1]))) bls = baselines(uvw) # Should have positive amplitude for the middle of the picture vis = simulate_point(bls, 0, 0) assert_allclose(vis, numpy.ones(len(vis))) # For the half-way point the result is either -1 or 1 # depending on whether the baseline length is even bl_even = 1 - 2 * (numpy.sum(bls, axis=1) % 2) vis = simulate_point(bls, 0.5, 0.5) assert_allclose(vis, bl_even) vis = simulate_point(bls, -0.5, 0.5) assert_allclose(vis, bl_even) vis = simulate_point(bls, 0.5, -0.5) assert_allclose(vis, bl_even) vis = simulate_point(bls, -0.5, -0.5) assert_allclose(vis, bl_even)
def phaserotate_visibility(vis: Visibility, newphasecentre: SkyCoord, tangent=True, inverse=False) -> Visibility: """ Phase rotate from the current phase centre to a new phase centre If tangent is False the uvw are recomputed and the visibility phasecentre is updated. Otherwise only the visibility phases are adjusted :param vis: Visibility to be rotated :param newphasecentre: :param tangent: Stay on the same tangent plane? (True) :param inverse: Actually do the opposite :return: Visibility """ assert isinstance(vis, Visibility), "vis is not a Visibility: %r" % vis l, m, n = skycoord_to_lmn(newphasecentre, vis.phasecentre) # No significant change? if numpy.abs(n) > 1e-15: # Make a new copy newvis = copy_visibility(vis) phasor = simulate_point(newvis.uvw, l, m) nvis, npol = vis.vis.shape # TODO: Speed up (broadcast rules not obvious to me) if inverse: for i in range(nvis): for pol in range(npol): newvis.data['vis'][i, pol] *= phasor[i] else: for i in range(nvis): for pol in range(npol): newvis.data['vis'][i, pol] *= numpy.conj(phasor[i]) # To rotate UVW, rotate into the global XYZ coordinate system and back. We have the option of # staying on the tangent plane or not. If we stay on the tangent then the raster will # join smoothly at the edges. If we change the tangent then we will have to reproject to get # the results on the same image, in which case overlaps or gaps are difficult to deal with. if not tangent: if inverse: xyz = uvw_to_xyz(vis.data['uvw'], ha=-newvis.phasecentre.ra.rad, dec=newvis.phasecentre.dec.rad) newvis.data['uvw'][...] = \ xyz_to_uvw(xyz, ha=-newphasecentre.ra.rad, dec=newphasecentre.dec.rad)[...] else: # This is the original (non-inverse) code xyz = uvw_to_xyz(newvis.data['uvw'], ha=-newvis.phasecentre.ra.rad, dec=newvis.phasecentre.dec.rad) newvis.data['uvw'][...] = xyz_to_uvw(xyz, ha=-newphasecentre.ra.rad, dec=newphasecentre.dec.rad)[ ...] newvis.phasecentre = newphasecentre return newvis else: return vis
def predict_skycomponent_blockvisibility(vis: BlockVisibility, sc: Union[Skycomponent, List[Skycomponent]], **kwargs) -> BlockVisibility: """Predict the visibility from a Skycomponent, add to existing visibility, for BlockVisibility :param vis: BlockVisibility :param sc: Skycomponent or list of SkyComponents :param spectral_mode: {mfs|channel} (channel) :return: BlockVisibility """ assert type( vis) is BlockVisibility, "vis is not a BlockVisibility: %r" % vis if not isinstance(sc, collections.Iterable): sc = [sc] nchan = vis.nchan npol = vis.npol if not isinstance(sc, collections.Iterable): sc = [sc] k = vis.frequency / constants.c.to('m/s').value for comp in sc: assert_same_chan_pol(vis, comp) flux = comp.flux if comp.polarisation_frame != vis.polarisation_frame: flux = convert_pol_frame(flux, comp.polarisation_frame, vis.polarisation_frame) l, m, n = skycoord_to_lmn(comp.direction, vis.phasecentre) for chan in range(nchan): phasor = simulate_point(vis.uvw * k[chan], l, m) for pol in range(npol): vis.data['vis'][..., chan, pol] += flux[chan, pol] * phasor[...] return vis