def cvcimage(cvcobj, filestep, cubeslice, req_calsrc=None, docalibrate=True, pbcor=False): """Image a CVC object. Parameters ---------- cvcobj : CVCfiles() The covariance cube files object containing visibility cubes. filestep : int The file index to select. cubeslice : int The cube index in file. req_calsrc : str The requested sky source. docalibrate : bool Perform calibration or not. pbcor : bool Perform primary beam correction or not. Returns ------- ll : array The l-direction cosine map. mm : array The m-direction cosine map. images : tuple Tuple of polarized image maps. polrep : str Polarization representation of the images tuple. t : datetime Observation time. freq : float Observation frequency. stnid : str Station id. phaseref : tuple Direction of phase reference used for imaging. """ t = cvcobj.samptimeset[filestep][cubeslice] freq = cvcobj.freqset[filestep][cubeslice] cvcdata_unc = cvcobj.getdata(filestep) stnid = cvcobj.stnsesinfo.get_stnid() bandarr = cvcobj.stnsesinfo.get_bandarr() band = cvcobj.stnsesinfo.get_band() rcumode = cvcobj.stnsesinfo.get_rcumode() pointingstr = cvcobj.stnsesinfo.get_pointingstr() # Get/Compute ant positions stnPos, stnRot, antpos, stnIntilePos \ = antennafieldlib.getArrayBandParams(stnid, bandarr) septon = cvcobj.stnsesinfo.is_septon() if septon: elmap = cvcobj.stnsesinfo.get_septon_elmap() for tile, elem in enumerate(elmap): antpos[tile] = antpos[tile] + stnIntilePos[elem] # stn2Dcoord = stnRot.T * antpos.T # Apply calibration datatype = cvcobj.stnsesinfo.get_datatype() if datatype == 'acc': cvcdata, caltabhead = calibrationtables.calibrateACC( cvcdata_unc, rcumode, stnid, t, docalibrate) else: sb, nz = modeparms.freq2sb(freq) cvcdata, caltabhead = calibrationtables.calibrateXST( cvcdata_unc, sb, rcumode, stnid, t, docalibrate) cvpol = dataIO.cvc2cvpol(cvcdata) # Determine if allsky FoV if band == '10_90' or band == '30_90' or septon: allsky = True else: allsky = False # Determine phaseref if req_calsrc is not None: pntstr = ilisa.observations.directions.std_pointings(req_calsrc) elif allsky: pntstr = ilisa.observations.directions.std_pointings('Z') else: pntstr = pointingstr phaseref = pntstr.split(',') skyimage = True if skyimage: # Phase up visibilities cvpu, UVWxyz = phaseref_xstpol(cvpol[:, :, cubeslice, ...].squeeze(), t, freq, stnPos, antpos, phaseref) # Make image on phased up visibilities polrep, images, ll, mm = xst2skyim_stn2Dcoord(cvpu, UVWxyz.T, freq, include_autocorr=False, allsky=allsky, polrep_req='XY') if pbcor and canuse_dreambeam: # Get dreambeam jones: pointing = (float(phaseref[0]), float(phaseref[1]), 'STN') jonesfld, stnbasis, j2000basis = primarybeampat('LOFAR', stnid, bandarr, 'Hamaker', freq, pointing=pointing, obstime=t, lmgrid=(ll, mm)) ijones = numpy.linalg.inv(jonesfld) bri_ant = numpy.array([[images[0], images[1]], [images[2], images[3]]]) bri_ant = numpy.moveaxis(numpy.moveaxis(bri_ant, 0, -1), 0, -1) ijonesH = numpy.conj(numpy.swapaxes(ijones, -1, -2)) bri_xy_iau = numpy.matmul(numpy.matmul(ijones, bri_ant), ijonesH) images = (bri_xy_iau[:, :, 0, 0], bri_xy_iau[:, :, 0, 1], bri_xy_iau[:, :, 1, 0], bri_xy_iau[:, :, 1, 1]) if canuse_stokes and polrep == 'XY': images = convertxy2stokes(images[0], images[1], images[2], images[3]) polrep = 'Stokes' else: vis_S0 = cvpol[0, 0, cubeslice, ...].squeeze() + cvpol[0, 0, cubeslice, ...].squeeze() nfhimages, ll, mm = nearfield_grd_image(vis_S0, antpos, freq, include_autocorr=True) polrep = 'S0' images = numpy.real(nfhimages) return ll, mm, images, polrep, t, freq, stnid, phaseref
def cvc_image(cvcobj, filestep, cubeslice, req_calsrc=None, pbcor=False, fluxperbeam=True, polrep='stokes'): """ Image CVC object using beamformed synthesis Parameters ---------- cvcobj : CVCfiles() The covariance cube files object containing visibility cubes. filestep : int The file index to select. cubeslice : int The cube index in file. req_calsrc : str The requested sky source. pbcor : bool Perform primary beam correction or not. polrep : str Polarization representation to use for image. Returns ------- ll : array The l-direction cosine map. mm : array The m-direction cosine map. images : tuple Tuple of polarized image maps. t : datetime Observation time. freq : float Observation frequency. phaseref : tuple Direction of phase reference used for imaging. """ t = cvcobj.samptimeset[filestep][cubeslice] freq = cvcobj.freqset[filestep][cubeslice] pointingstr = cvcobj.scanrecinfo.get_pointingstr() stn_pos = cvcobj.stn_pos stn_antpos = cvcobj.stn_antpos cvcpol_lin = dataIO.cvc2polrep(cvcobj[filestep], crlpolrep='lin') allsky = cvcobj.scanrecinfo.get_allsky() phaseref = _req_calsrc_proc(req_calsrc, allsky, pointingstr) # Select a visibility snapshot cvpol_lin = cvcpol_lin[:, :, cubeslice, ...].squeeze() # Calculate UVW coords UVWxyz = calc_uvw(t, phaseref, stn_pos, stn_antpos) # Phase up visibilities cvpu_lin = phaseref_xstpol(cvpol_lin, UVWxyz, freq) # Determine FoV and image lm size bandarr = cvcobj.scanrecinfo.get_bandarr() lmsize = 2.0 if not allsky: d = antennafieldlib.ELEMENT_DIAMETER[bandarr] fov = 2*airydisk_radius(freq, d) lmsize = 1.0*fov # Make image on phased up visibilities imgs_lin, ll, mm = beamformed_image( cvpu_lin, UVWxyz.T, freq, use_autocorr=False, lmsize=lmsize, polrep='linear', fluxperbeam=fluxperbeam) # Potentially apply primary beam correction if pbcor and CANUSE_DREAMBEAM: # Get dreambeam jones: pointing = (float(phaseref[0]), float(phaseref[1]), 'STN') stnid = cvcobj.scanrecinfo.get_stnid() jonesfld, _stnbasis, _j2000basis = primarybeampat( 'LOFAR', stnid, bandarr, 'Hamaker', freq, pointing=pointing, obstime=t, lmgrid=(ll, mm)) ijones = numpy.linalg.inv(jonesfld) bri_ant = numpy.array([[imgs_lin[0], imgs_lin[1]], [imgs_lin[2], imgs_lin[3]]]) bri_ant = numpy.moveaxis(numpy.moveaxis(bri_ant, 0, -1), 0, -1) ijonesH = numpy.conj(numpy.swapaxes(ijones, -1, -2)) bri_xy_iau = numpy.matmul(numpy.matmul(ijones, bri_ant), ijonesH) imgs_lin = (bri_xy_iau[:, :, 0, 0], bri_xy_iau[:, :, 0, 1], bri_xy_iau[:, :, 1, 0], bri_xy_iau[:, :, 1, 1]) # Convert to requested polarization representation if polrep == 'stokes' and CANUSE_DREAMBEAM: images = convertxy2stokes(imgs_lin[0], imgs_lin[1], imgs_lin[2], imgs_lin[3]) elif polrep == 'circular' and CANUSE_DREAMBEAM: imgpolmat_lin = numpy.array([[imgs_lin[0], imgs_lin[1]], [imgs_lin[2], imgs_lin[3]]]) imgpolmat = cov_lin2cir(imgpolmat_lin) images = (imgpolmat[0][0], imgpolmat[0][1], imgpolmat[1][0], imgpolmat[1][1]) else: # polrep == 'linear' images = imgs_lin return images, ll, mm, phaseref
def xst2skyim_stn2Dcoord(xstpol, stn2Dcoord, freq, include_autocorr=True, allsky=False, polrep_req='Stokes'): """Image XSTpol data. Parameters ---------- xstpol : array The crosslet statistics data. stn2Dcoord: array The 2D array configuration matrix. freq : float The frequency of the the data in Hz. include_autocorr : bool Whether or not to include the autocorrelations. allsky : bool Should an allsky image be produced? polrep_req : str Requested type of representation for the polarimetric data. Can be 'Stokes' or 'XY'. (If dreamBeam package not accessible only 'XY' is possible) Returns ------- polrep : str The polarization representation of the image tuple. Can be 'Stokes' or 'XY'. (skyimag_0, skyimag_1, skyimag_2, skyimag_3): tuple Polarimetric image maps. If polrep='Stokes' (and dreamBeam package accessible) then the elements correspond to Stokes I,Q,U,V. If polrep='XY' then the elements correspond to XX,XY,YX,YY. ll : array The l direction cosine of the image. mm : array The m direction cosine of the image. """ if not include_autocorr: for indi in range(2): for indj in range(2): numpy.fill_diagonal(xstpol[indi, indj, :, :], 0.0) posU, posV = stn2Dcoord[0, :].squeeze(), stn2Dcoord[1, :].squeeze() lambda0 = c / freq k = 2 * numpy.pi / lambda0 if not allsky: lmext = fov(freq) else: lmext = 1.0 nrpix = 101 l, m = numpy.linspace(-lmext, lmext, nrpix), numpy.linspace(-lmext, lmext, nrpix) ll, mm = numpy.meshgrid(l, m) bf = numpy.exp(-1.j * k * (numpy.einsum('ij,k->ijk', ll, posU) + numpy.einsum('ij,k->ijk', mm, posV))) bfbf = numpy.einsum('ijk,ijl->ijkl', bf, numpy.conj(bf)) skyimag_xx = numpy.einsum('ijkl,kl->ij', bfbf, xstpol[0, 0, ...].squeeze()) skyimag_xy = numpy.einsum('ijkl,kl->ij', bfbf, xstpol[0, 1, ...].squeeze()) skyimag_yx = numpy.einsum('ijkl,kl->ij', bfbf, xstpol[1, 0, ...].squeeze()) skyimag_yy = numpy.einsum('ijkl,kl->ij', bfbf, xstpol[1, 1, ...].squeeze()) if polrep_req == 'Stokes' and canuse_stokes: skyimag_si, skyimag_sq, skyimag_su, skyimag_sv = convertxy2stokes( skyimag_xx, skyimag_xy, skyimag_yx, skyimag_yy) polrep = 'Stokes' return polrep, (skyimag_si, skyimag_sq, skyimag_su, skyimag_sv), ll, mm else: polrep = 'XY' return polrep, (skyimag_xx, skyimag_xy, skyimag_yx, skyimag_yy), ll, mm
def beamformed_image(xstpol, stn2Dcoord, freq, use_autocorr=True, lmsize=2.0, polrep='linear', fluxperbeam=True): """ Beamformed image XSTpol data. Parameters ---------- xstpol : array The crosslet statistics data. Should have format: xstpol[polport1, polport2, elemnr1, elemnr2] where polport1 and polport2 are the two polarization ports, e.g. X and Y, and elemnr1 and elemnr2 are two elements of the interferometer array configuration. stn2Dcoord : array The 2D array configuration matrix. freq : float The frequency of the the data in Hz. use_autocorr : bool Whether or not to include the autocorrelations. lmsize : float Size of image in (lm) direction-cosine units. Default 2.0 means allsky. polrep : str Requested type of representation for the polarimetric data. Can be 'linear' (default), 'circular', or 'stokes'. (If dreamBeam package not accessible only 'linear' is possible) fluxperbeam : bool If True, then the flux is per beam, else the flux is per sterradian. Returns ------- (skyimag_0, skyimag_1, skyimag_2, skyimag_3) : tuple Polarimetric image maps. If polrep='Stokes' (and dreamBeam package accessible) then the elements correspond to Stokes I,Q,U,V. If polrep='XY' then the elements correspond to XX,XY,YX,YY. ll : array The l direction cosine of the image. mm : array The m direction cosine of the image. """ if not use_autocorr: # Set Autocorrelations to zero: xstpol = numpy.copy(xstpol) # Copy since diagonal will be rewritten for indi in range(2): for indj in range(2): numpy.fill_diagonal(xstpol[indi, indj, :, :], 0.0) posU, posV = stn2Dcoord[0, :].squeeze(), stn2Dcoord[1, :].squeeze() lambda0 = sys.float_info.max if freq != 0.0: lambda0 = c / freq k = 2 * numpy.pi / lambda0 lmext = lmsize/2.0 nrpix = 101 l, m = numpy.linspace(-lmext, lmext, nrpix), numpy.linspace(-lmext, lmext, nrpix) ll, mm = numpy.meshgrid(l, m) bf = numpy.exp(-1.j*k*(numpy.einsum('ij,k->ijk', ll, posU) + numpy.einsum('ij,k->ijk', mm, posV))) bfbf = numpy.einsum('ijk,ijl->ijkl', bf, numpy.conj(bf)) skyimag_xx = numpy.einsum('ijkl,kl->ij', bfbf, xstpol[0, 0, ...].squeeze()) skyimag_xy = numpy.einsum('ijkl,kl->ij', bfbf, xstpol[0, 1, ...].squeeze()) skyimag_yx = numpy.einsum('ijkl,kl->ij', bfbf, xstpol[1, 0, ...].squeeze()) skyimag_yy = numpy.einsum('ijkl,kl->ij', bfbf, xstpol[1, 1, ...].squeeze()) if not fluxperbeam: ll2mm2 = ll**2+mm**2 beyond_horizon = ll2mm2 >= 1.0 nn = numpy.sqrt(1-ll2mm2.astype('complex')) # Weight values beyond horizon to zero nn[beyond_horizon] = 0.0 skyimag_xx = skyimag_xx * nn skyimag_xy = skyimag_xy * nn skyimag_yx = skyimag_yx * nn skyimag_yy = skyimag_yy * nn (skyimag_0, skyimag_1, skyimag_2, skyimag_3) = (None, None, None, None) if not CANUSE_DREAMBEAM or polrep == 'linear': (skyimag_0, skyimag_1, skyimag_2, skyimag_3) =\ (skyimag_xx, skyimag_xy, skyimag_yx, skyimag_yy) elif polrep == 'stokes': skyimag_si, skyimag_sq, skyimag_su, skyimag_sv = convertxy2stokes( skyimag_xx, skyimag_xy, skyimag_yx, skyimag_yy) (skyimag_0, skyimag_1, skyimag_2, skyimag_3) =\ (skyimag_si, skyimag_sq, skyimag_su, skyimag_sv) elif polrep == 'circular': skyimag_circ = cov_lin2cir([[skyimag_xx, skyimag_xy], [skyimag_yx, skyimag_yy]]) skyimag_0 = skyimag_circ[0][0] skyimag_1 = skyimag_circ[0][1] skyimag_2 = skyimag_circ[1][0] skyimag_3 = skyimag_circ[1][1] return (skyimag_0, skyimag_1, skyimag_2, skyimag_3), ll, mm