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 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
def fit_visibility(vis, sc, tol=1e-6, niter=20, verbose=False, method='trust-exact', **kwargs): """Fit a single component to a visibility Uses the scipy.optimize.minimize function. :param vis: :param sc: Initial component :param tol: Tolerance of fit :param niter: Number of iterations :param verbose: :param method: 'CG', 'BFGS', 'Powell', 'trust-ncg', 'trust-exact', 'trust-krylov': default 'trust-exact' :param kwargs: :return: component, convergence info as a dictionary """ assert vis.polarisation_frame.type == 'stokesI', "Currently restricted to stokesI" # These derivative have been calculated using sympy. See visibility_fitting_sympy.py def J(params): # Params are flux, l, m S = params[0] l = params[1] m = params[2] u = vis.u[:, numpy.newaxis] v = vis.v[:, numpy.newaxis] vobs = vis.vis p = numpy.exp(-2j * numpy.pi * (u * l + v * m)) vres = vobs - S * p J = numpy.sum(vis.weight * (vres * numpy.conjugate(vres)).real) return J def Jboth(params): # Params are flux, l, m S = params[0] l = params[1] m = params[2] u = vis.u[:, numpy.newaxis] v = vis.v[:, numpy.newaxis] vobs = vis.vis p = numpy.exp(-2j * numpy.pi * (u * l + v * m)) vres = vobs - S * p Vrp = vres * numpy.conjugate(p) * vis.weight J = numpy.sum(vis.weight * (vres * numpy.conjugate(vres)).real) gradJ = numpy.array([ -2.0 * numpy.sum(Vrp.real), +4.0 * numpy.pi * S * numpy.sum(u * Vrp.imag), +4.0 * numpy.pi * S * numpy.sum(v * Vrp.imag) ]) return J, gradJ def hessian(params): S = params[0] l = params[1] m = params[2] u = vis.u[:, numpy.newaxis] v = vis.v[:, numpy.newaxis] w = vis.w[:, numpy.newaxis] wt = vis.weight vobs = vis.vis p = numpy.exp(-2j * numpy.pi * (u * l + v * m)) vres = vobs - S * p Vrp = vres * numpy.conjugate(p) hess = numpy.zeros([3, 3]) hess[0, 0] = 2.0 * numpy.sum(wt) hess[0, 1] = 4.0 * numpy.pi * numpy.sum(wt * u * Vrp.imag) hess[0, 2] = 4.0 * numpy.pi * numpy.sum(wt * v * Vrp.imag) hess[1, 1] = 8.0 * numpy.pi**2 * S * numpy.sum(wt * u**2 * (S + Vrp.real)) hess[1, 2] = 8.0 * numpy.pi**2 * S * numpy.sum(wt * u * v * (S + Vrp.real)) hess[2, 2] = 8.0 * numpy.pi**2 * S * numpy.sum(wt * v**2 * (S + Vrp.real)) hess[1, 0] = hess[0, 1] hess[2, 0] = hess[0, 2] hess[2, 1] = hess[1, 2] return hess # Initialize l,m,n to be in the direction of the component as defined in the frame of # visibility phasecentre l, m, n = skycoord_to_lmn(sc.direction, vis.phasecentre) x0 = numpy.array([sc.flux[0, 0], l, m]) bounds = ((None, None), (-0.1, -0.1), (-0.1, 0.1)) options = {'maxiter': niter, 'disp': verbose} res = {} import time start = time.time() if method == 'BFGS' or method == 'CG' or method == 'Powell': res = minimize(J, x0, method=method, options=options, tol=tol) elif method == 'Nelder-Mead': res = minimize(Jboth, x0, method=method, options=options, tol=tol) elif method == 'L-BFGS-B': res = minimize(Jboth, x0, method=method, jac=True, bounds=bounds, options=options, tol=tol) else: res = minimize(Jboth, x0, method=method, jac=True, hess=hessian, options=options, tol=tol) if verbose: print("Solution for %s took %.6f seconds" % (method, time.time() - start)) print("Solution = %s" % str(res.x)) print(res) sc.flux[...] = res.x[0] lmn = (res.x[1], res.x[2], 0.0) sc.direction = lmn_to_skycoord(lmn, vis.phasecentre) return sc, res
def test_skycoord_to_lmn(self): center = SkyCoord(ra=0, dec=0, unit=u.deg) north = SkyCoord(ra=0, dec=90, unit=u.deg) south = SkyCoord(ra=0, dec=-90, unit=u.deg) east = SkyCoord(ra=90, dec=0, unit=u.deg) west = SkyCoord(ra=-90, dec=0, unit=u.deg) assert_allclose(skycoord_to_lmn(center, center), (0, 0, 0)) assert_allclose(skycoord_to_lmn(north, center), (0, 1, -1)) assert_allclose(skycoord_to_lmn(south, center), (0, -1, -1)) assert_allclose(skycoord_to_lmn(south, north), (0, 0, -2), atol=1e-14) assert_allclose(skycoord_to_lmn(east, center), (1, 0, -1)) assert_allclose(skycoord_to_lmn(west, center), (-1, 0, -1)) assert_allclose(skycoord_to_lmn(center, west), (1, 0, -1)) assert_allclose(skycoord_to_lmn(north, west), (0, 1, -1), atol=1e-14) assert_allclose(skycoord_to_lmn(south, west), (0, -1, -1), atol=1e-14) assert_allclose(skycoord_to_lmn(north, east), (0, 1, -1), atol=1e-14) assert_allclose(skycoord_to_lmn(south, east), (0, -1, -1), atol=1e-14)