def mfs_clean_spws(img, spws, chans, spwtype): """ Clean each supplied spw (MFS) Inputs: img :: Imaging object The Imaging object spws, chans :: lists spectral windows and channels to image spwtype :: string 'line' or 'cont', to determine which clean params to use Returns: Nothing """ for spw, chan in zip(spws, chans): # If not interactive, Lightly clean to get threshold imagename = "{0}.spw{1}.{2}.mfs".format(img.imfield, spw, img.stokes) if img.uvtaper: imagename = imagename + ".uvtaper" imagename = os.path.join(img.outdir, imagename) cleanspw = spw if chan: cleanspw = "{0}:{1}".format(spw, chan) if not img.interactive: # Save model if necessary savemodel = "none" if img.savemodel == "light": savemodel = "modelcolumn" img.logger.info("Lightly cleaning spw {0} (MFS)...".format(spw)) casa.tclean( vis=img.vis, imagename=imagename, phasecenter=img.cp["phasecenter"], field=img.field, spw=cleanspw, specmode="mfs", gridder=img.cp["gridder"], wprojplanes=img.cp["wprojplanes"], threshold="0mJy", niter=img.cp["lightniter"] * len(img.stokes), usemask="auto-multithresh", pbmask=img.cp[spwtype + "pbmask"], sidelobethreshold=img.cp[spwtype + "sidelobethreshold"], noisethreshold=img.cp[spwtype + "noisethreshold"], lownoisethreshold=img.cp[spwtype + "lownoisethreshold"], negativethreshold=img.cp[spwtype + "negativethreshold"], smoothfactor=img.cp[spwtype + "smoothfactor"], minbeamfrac=img.cp[spwtype + "minbeamfrac"], cutthreshold=img.cp[spwtype + "cutthreshold"], growiterations=img.cp[spwtype + "growiterations"], deconvolver="multiscale", scales=img.cp["scales"], gain=img.cp["gain"], cyclefactor=img.cp["cyclefactor"], imsize=img.cp["imsize"], pblimit=-1.0, cell=img.cp["cell"], weighting=img.cp["weighting"], robust=img.cp["robust"], uvtaper=img.outertaper, uvrange=img.uvrange, stokes=img.stokes, savemodel=savemodel, pbcor=False, restart=True, calcres=False, calcpsf=False, parallel=img.parallel, ) img.logger.info("Done.") # Get RMS of residuals dat = casa.imstat( imagename="{0}.residual".format(imagename), axes=[0, 1], mask="'{0}.mask' == 0".format(imagename), ) img.logger.info("Max un-masked RMS: {0:.2f} mJy/beam".format( 1000.0 * np.max(dat["rms"]))) img.logger.info( "Max un-masked MAD*1.4826: {0:.2f} mJy/beam".format( 1000.0 * 1.4826 * np.max(dat["medabsdevmed"]))) img.logger.info( "Using max(MAD) x 1.4826 x {0} as threshold".format( img.cp["nrms"])) threshold = "{0:.2f}mJy".format(img.cp["nrms"] * 1000.0 * 1.4826 * np.max(dat["medabsdevmed"])) else: threshold = "0.0mJy" # Clean to threshold # Save model if necessary savemodel = "none" if img.savemodel == "clean": savemodel = "modelcolumn" img.logger.info("Cleaning spw {0} (MFS) to threshold: {1}...".format( spw, threshold)) casa.tclean( vis=img.vis, imagename=imagename, field=img.field, phasecenter=img.cp["phasecenter"], spw=cleanspw, gridder=img.cp["gridder"], wprojplanes=img.cp["wprojplanes"], specmode="mfs", threshold=threshold, niter=img.cp["maxniter"] * len(img.stokes), usemask="auto-multithresh", pbmask=img.cp[spwtype + "pbmask"], sidelobethreshold=img.cp[spwtype + "sidelobethreshold"], noisethreshold=img.cp[spwtype + "noisethreshold"], lownoisethreshold=img.cp[spwtype + "lownoisethreshold"], negativethreshold=img.cp[spwtype + "negativethreshold"], smoothfactor=img.cp[spwtype + "smoothfactor"], minbeamfrac=img.cp[spwtype + "minbeamfrac"], cutthreshold=img.cp[spwtype + "cutthreshold"], growiterations=img.cp[spwtype + "growiterations"], deconvolver="multiscale", scales=img.cp["scales"], gain=img.cp["gain"], cyclefactor=img.cp["cyclefactor"], imsize=img.cp["imsize"], pblimit=-1.0, cell=img.cp["cell"], weighting=img.cp["weighting"], robust=img.cp["robust"], uvtaper=img.outertaper, uvrange=img.uvrange, pbcor=False, stokes=img.stokes, savemodel=savemodel, interactive=img.interactive, restart=True, calcres=False, calcpsf=False, parallel=img.parallel, ) img.logger.info("Done.") # Primary beam correction img.logger.info("Performing primary beam correction...") casa.impbcor( imagename="{0}.image".format(imagename), pbimage="{0}.pb.image".format(imagename), outfile="{0}.pbcor.image".format(imagename), overwrite=True, ) img.logger.info("Done.") # Export to fits img.logger.info("Exporting fits file...") casa.exportfits( imagename="{0}.image".format(imagename), fitsimage="{0}.clean.image.fits".format(imagename), overwrite=True, history=False, ) casa.exportfits( imagename="{0}.mask".format(imagename), fitsimage="{0}.clean.mask.fits".format(imagename), overwrite=True, history=False, ) casa.exportfits( imagename="{0}.residual".format(imagename), fitsimage="{0}.clean.residual.fits".format(imagename), overwrite=True, history=False, ) casa.exportfits( imagename="{0}.pbcor.image".format(imagename), fitsimage="{0}.clean.pbcor.image.fits".format(imagename), overwrite=True, history=False, ) img.logger.info("Done.")
def mfs_dirty_spws(img, spws, chans): """ Dirty image each supplied spw (MFS) Inputs: img :: Imaging object The Imaging object spws, chans :: lists spectral windows and channels to image Returns: Nothing """ for spw, chan in zip(spws, chans): imagename = "{0}.spw{1}.{2}.mfs".format(img.imfield, spw, img.stokes) if img.uvtaper: imagename = imagename + ".uvtaper" imagename = os.path.join(img.outdir, imagename) img.logger.info( "Generating dirty image of spw {0} (MFS)...".format(spw)) cleanspw = spw if chan: cleanspw = "{0}:{1}".format(spw, chan) casa.tclean( vis=img.vis, imagename=imagename, phasecenter=img.cp["phasecenter"], field=img.field, spw=cleanspw, specmode="mfs", gridder=img.cp["gridder"], wprojplanes=img.cp["wprojplanes"], threshold="0mJy", niter=0, deconvolver="multiscale", scales=img.cp["scales"], gain=img.cp["gain"], cyclefactor=img.cp["cyclefactor"], imsize=img.cp["imsize"], pblimit=-1.0, cell=img.cp["cell"], weighting=img.cp["weighting"], robust=img.cp["robust"], uvtaper=img.outertaper, uvrange=img.uvrange, stokes=img.stokes, pbcor=False, parallel=img.parallel, ) img.logger.info("Done.") # Generate primary beam image img.logger.info( "Generating primary beam image of spw {0} (MFS)...".format(spw)) makePB( vis=img.vis, field=img.field, spw=spw, uvrange=img.uvrange, stokes=img.stokes, imtemplate="{0}.image".format(imagename), outimage="{0}.pb.image".format(imagename), pblimit=img.cp["pblimit"], ) img.logger.info("Done.") # Primary beam correction img.logger.info("Performing primary beam correction...") casa.impbcor( imagename="{0}.image".format(imagename), pbimage="{0}.pb.image".format(imagename), outfile="{0}.pbcor.image".format(imagename), overwrite=True, ) img.logger.info("Done.") # Export to fits img.logger.info("Exporting fits file...") casa.exportfits( imagename="{0}.pb.image".format(imagename), fitsimage="{0}.pb.fits".format(imagename), overwrite=True, history=False, ) casa.exportfits( imagename="{0}.image".format(imagename), fitsimage="{0}.dirty.image.fits".format(imagename), overwrite=True, history=False, ) casa.exportfits( imagename="{0}.residual".format(imagename), fitsimage="{0}.dirty.residual.fits".format(imagename), overwrite=True, history=False, ) casa.exportfits( imagename="{0}.pbcor.image".format(imagename), fitsimage="{0}.dirty.pbcor.image.fits".format(imagename), overwrite=True, history=False, ) img.logger.info("Done.")
def channel_dirty_spws(img, spws, spwtype): """ Dirty image each supplied spectral window (channel cube) Inputs: img :: Imaging object The Imaging object spws :: string comma-separated string of spws to image spwtype :: string 'line' or 'cont', to determine which clean params to use Returns: Nothing """ # Set channel parameters if spwtype == "cont": restfreqs = [None for spw in spws] start = None width = img.cp["contwidth"] nchans = [None for spw in spws] outframe = img.cp["contoutframe"] veltype = None interpolation = None elif spwtype == "line": spw_inds = [ img.config.get("Spectral Windows", "Line").split(",").index(spw) for spw in spws ] restfreqs = [ img.config.get("Clean", "restfreqs").split(",")[spw_ind] for spw_ind in spw_inds ] outframe = img.cp["lineoutframe"] veltype = img.cp["veltype"] interpolation = img.cp["interpolation"] # Determine velocity-gridding parameter start, width, nchans = grid_parameters(img, spws) else: img.logger.critical("Error: spwtype {0} not supported".format(spwtype)) raise ValueError("Invalid spwtype") # Loop over spws for spw, restfreq, nchan in zip(spws, restfreqs, nchans): imagename = "{0}.spw{1}.{2}.channel".format(img.imfield, spw, img.stokes) if img.uvtaper: imagename = imagename + ".uvtaper" imagename = os.path.join(img.outdir, imagename) img.logger.info( "Dirty imaging spw {0} (restfreq: {1})...".format(spw, restfreq) ) casa.tclean( vis=img.vis, imagename=imagename, phasecenter=img.cp["phasecenter"], field=img.field, spw=spw, specmode="cube", gridder=img.cp["gridder"], wprojplanes=img.cp["wprojplanes"], threshold="0mJy", niter=0, deconvolver="multiscale", scales=img.cp["scales"], gain=img.cp["gain"], cyclefactor=img.cp["cyclefactor"], imsize=img.cp["imsize"], pblimit=-1.0, cell=img.cp["cell"], weighting=img.cp["weighting"], robust=img.cp["robust"], restfreq=restfreq, start=start, width=width, nchan=nchan, outframe=outframe, veltype=veltype, interpolation=interpolation, uvtaper=img.outertaper, uvrange=img.uvrange, stokes=img.stokes, pbcor=False, parallel=img.parallel, ) img.logger.info("Done.") # Generate primary beam image img.logger.info( "Generating primary beam image of spw {0} (channel)...".format(spw) ) makePB( vis=img.vis, field=img.field, spw=spw, uvrange=img.uvrange, stokes=img.stokes, imtemplate="{0}.image".format(imagename), outimage="{0}.pb.image".format(imagename), pblimit=img.cp["pblimit"], ) # Primary beam correction pbimage = "{0}.pb.image".format(imagename) img.logger.info("Performing primary beam correction...") if not os.path.exists(pbimage): raise ValueError( "Could not find {0}. Did you dirty MFS first?".format(pbimage) ) casa.impbcor( imagename="{0}.image".format(imagename), pbimage=pbimage, outfile="{0}.pbcor.image".format(imagename), overwrite=True, ) img.logger.info("Done.") # Export to fits img.logger.info("Exporting fits file...") velocity = spwtype == "line" casa.exportfits( imagename="{0}.pb.image".format(imagename), fitsimage="{0}.pb.fits".format(imagename), velocity=velocity, overwrite=True, history=False, ) casa.exportfits( imagename="{0}.image".format(imagename), fitsimage="{0}.dirty.image.fits".format(imagename), velocity=velocity, overwrite=True, history=False, ) casa.exportfits( imagename="{0}.residual".format(imagename), fitsimage="{0}.dirty.residual.fits".format(imagename), velocity=velocity, overwrite=True, history=False, ) casa.exportfits( imagename="{0}.pbcor.image".format(imagename), fitsimage="{0}.dirty.pbcor.image.fits".format(imagename), velocity=velocity, overwrite=True, history=False, ) img.logger.info("Done.")
def channel_clean_spws(img, spws, spwtype): """ Clean all supplied spws by channel using clean mask from MFS images. Inputs: img :: Imaging object The imaging object spws :: string comma-separated string of spws to image spwtype :: string 'line' or 'cont', to determine which clean params to use Returns: Nothing """ # # Set channel parameters # if spwtype == "cont": restfreqs = [None for spw in spws] start = None width = img.cp["contwidth"] nchans = [None for spw in spws] outframe = img.cp["contoutframe"] veltype = None interpolation = None elif spwtype == "line": spw_inds = [ img.config.get("Spectral Windows", "Line").split(",").index(spw) for spw in spws ] restfreqs = [ img.config.get("Clean", "restfreqs").split(",")[spw_ind] for spw_ind in spw_inds ] outframe = img.cp["lineoutframe"] veltype = img.cp["veltype"] interpolation = img.cp["interpolation"] # Determine velocity-gridding parameter start, width, nchans = grid_parameters(img, spws) else: img.logger.critical("Error: spwtype {0} not supported".format(spwtype)) raise ValueError("Invalid spwtype") # Loop over spws for spw, restfreq, nchan in zip(spws, restfreqs, nchans): # Get niters if nchan is None: # get number of channels from dirty image imagename = "{0}.spw{1}.{2}.channel".format(img.imfield, spw, img.stokes) if img.uvtaper: imagename = imagename + ".uvtaper" imagename = os.path.join(img.outdir, imagename) imagename = imagename + ".dirty.image.fits" if not os.path.exists(imagename): raise ValueError( "Must create dirty channel cube first: {0}".format(imagename) ) dirty_hdr = fits.getheader(imagename) lightniter = img.cp["lightniter"] * dirty_hdr["NAXIS3"] * len(img.stokes) niter = img.cp["maxniter"] * dirty_hdr["NAXIS3"] * len(img.stokes) else: lightniter = img.cp["lightniter"] * nchan * len(img.stokes) niter = img.cp["maxniter"] * nchan * len(img.stokes) # If not interactive, Lightly clean spw imagename = "{0}.spw{1}.{2}.channel".format(img.imfield, spw, img.stokes) if img.uvtaper: imagename = imagename + ".uvtaper" mask = "{0}.spw{1}.{2}.mfs.uvtaper.mask".format( img.imfield, spw, img.stokes ) else: mask = "{0}.spw{1}.{2}.mfs.mask".format(img.imfield, spw, img.stokes) imagename = os.path.join(img.outdir, imagename) mask = os.path.join(img.outdir, mask) if not os.path.isdir(mask): img.logger.critical("Error: {0} does not exist".format(mask)) raise ValueError("{0} does not exist".format(mask)) if not img.interactive: img.logger.info( "Lightly cleaning spw {0} (restfreq: {1})...".format(spw, restfreq) ) img.logger.info("Using mask: {0}".format(mask)) casa.tclean( vis=img.vis, imagename=imagename, phasecenter=img.cp["phasecenter"], field=img.field, spw=spw, gridder=img.cp["gridder"], wprojplanes=img.cp["wprojplanes"], specmode="cube", threshold="0mJy", niter=lightniter, mask=mask, deconvolver="multiscale", scales=img.cp["scales"], gain=img.cp["gain"], cyclefactor=img.cp["cyclefactor"], imsize=img.cp["imsize"], pblimit=-1.0, cell=img.cp["cell"], weighting=img.cp["weighting"], robust=img.cp["robust"], restfreq=restfreq, start=start, width=width, nchan=nchan, outframe=outframe, veltype=veltype, interpolation=interpolation, uvtaper=img.outertaper, uvrange=img.uvrange, stokes=img.stokes, pbcor=False, restart=True, calcres=False, calcpsf=False, parallel=img.parallel, ) # This generates a channel mask, so next clean can't # have mfs mask mask = "" # Get RMS of residuals dat = casa.imstat( imagename="{0}.residual".format(imagename), axes=[0, 1], mask="'{0}.mask' == 0".format(imagename), ) img.logger.info( "Max un-masked RMS: {0:.2f} mJy/beam".format( 1000.0 * np.max(dat["rms"]) ) ) img.logger.info( "Max un-masked MAD*1.4826: {0:.2f} mJy/beam".format( 1000.0 * 1.4826 * np.max(dat["medabsdevmed"]) ) ) img.logger.info( "Using max(MAD) x 1.4826 x {0} as threshold".format(img.cp["nrms"]) ) threshold = "{0:.2f}mJy".format( img.cp["nrms"] * 1000.0 * 1.4826 * np.max(dat["medabsdevmed"]) ) else: threshold = "0.0mJy" # Deep clean to threshold img.logger.info( "Cleaning spw {0} (restfreq: {1}) to threshold: {2}...".format( spw, restfreq, threshold ) ) if mask: img.logger.info("Using mask: {0}".format(mask)) casa.tclean( vis=img.vis, imagename=imagename, phasecenter=img.cp["phasecenter"], field=img.field, spw=spw, specmode="cube", gridder=img.cp["gridder"], wprojplanes=img.cp["wprojplanes"], threshold=threshold, niter=niter, mask=mask, deconvolver="multiscale", scales=img.cp["scales"], gain=img.cp["gain"], cyclefactor=img.cp["cyclefactor"], imsize=img.cp["imsize"], pblimit=-1.0, cell=img.cp["cell"], weighting=img.cp["weighting"], robust=img.cp["robust"], restfreq=restfreq, start=start, width=width, nchan=nchan, outframe=outframe, veltype=veltype, interpolation=interpolation, uvtaper=img.outertaper, uvrange=img.uvrange, pbcor=False, stokes=img.stokes, interactive=img.interactive, restart=True, calcres=False, calcpsf=False, parallel=img.parallel, ) img.logger.info("Done.") # Primary beam correction pbimage = "{0}.pb.image".format(imagename) img.logger.info("Performing primary beam correction...") if not os.path.exists(pbimage): raise ValueError( "Could not find {0}. Did you dirty MFS first?".format(pbimage) ) casa.impbcor( imagename="{0}.image".format(imagename), pbimage=pbimage, outfile="{0}.pbcor.image".format(imagename), overwrite=True, ) img.logger.info("Done.") # Export to fits img.logger.info("Exporting fits file...") velocity = spwtype == "line" casa.exportfits( imagename="{0}.image".format(imagename), fitsimage="{0}.clean.image.fits".format(imagename), velocity=velocity, overwrite=True, history=False, ) casa.exportfits( imagename="{0}.mask".format(imagename), fitsimage="{0}.clean.mask.fits".format(imagename), overwrite=True, history=False, ) casa.exportfits( imagename="{0}.residual".format(imagename), fitsimage="{0}.clean.residual.fits".format(imagename), velocity=velocity, overwrite=True, history=False, ) casa.exportfits( imagename="{0}.pbcor.image".format(imagename), fitsimage="{0}.clean.pbcor.image.fits".format(imagename), velocity=velocity, overwrite=True, history=False, ) img.logger.info("Done.")
def smooth_all(field, spws='', stokes='', imagetype='clean', mosaic=False, overwrite=False): """ Smooth all line and continuum images/cubes to largest beam size of any individual image/cube. Inputs: field :: string The field to analyze spws :: string comma separated string of spws to smooth stokes :: string The Stokes parameters in the image imagetype :: string What images to process. For example, 'dirty', 'clean', 'dirty.uvtaper', or 'clean.uvtaper' mosaic :: boolean if True, these are mosaic images (.linmos.fits) overwrite :: boolean if True, overwrite existing images Returns: Nothing """ myspws = ['spw{0}'.format(spw) if spw != 'cont' else spw for spw in spws.split(',')] # # Find beam major axes, minor axes, and position angles for all # available images # print("Finding largest synthesized beam") bmajs = [] bmins = [] # images imname = '{0}.{1}.{2}.mfs.{3}.image.fits' if mosaic: imname = '{0}.{1}.{2}.mfs.{3}.image.linmos.fits' images = [imname.format(field, spw, stokes, imagetype) for spw in myspws if os.path.exists(imname.format(field,spw,stokes,imagetype))] # residual images resimages = [image.replace('.image.', '.residual.') for image in images] # cubes imname = '{0}.{1}.{2}.channel.{3}.image.fits' if mosaic: imname = '{0}.{1}.{2}.channel.{3}.image.linmos.fits' cubes = [imname.format(field, spw, stokes, imagetype) for spw in myspws if os.path.exists(imname.format(field,spw,stokes,imagetype))] # residual cubes rescubes = [image.replace('.image.', '.residual.') for image in cubes] for imagename, resimagename in zip(images+cubes, resimages+rescubes): with fits.open(imagename) as imhdulist: bunit = imhdulist[0].header['BUNIT'] if len(imhdulist) > 1: bmaj = imhdulist[1].data['BMAJ'][0] # arcsec bmin = imhdulist[1].data['BMIN'][0] # arcsec bpa = imhdulist[1].data['BPA'][0] else: bmaj = imhdulist[0].header['BMAJ'] * 3600. # arcsec bmin = imhdulist[0].header['BMIN'] * 3600. # arcsec bpa = imhdulist[0].header['BPA'] # check that residual images have beams and units with fits.open(resimagename, 'update') as reshdulist: if 'BMIN' not in reshdulist[0].header: reshdulist[0].header['BMIN'] = bmin/3600. # deg reshdulist[0].header['BMAJ'] = bmaj/3600. # deg reshdulist[0].header['BPA'] = bpa if not reshdulist[0].header['BUNIT']: reshdulist[0].header['BUNIT'] = bunit # check that residual images have units # append bmajs.append(bmaj) bmins.append(bmin) # # Smooth available images to maximum (circular) beam size # + pixel diagonal size (otherwise imsmooth will complain) # cell_size = abs(casa.imhead(imagename)['incr'][0]) * 206265. bmaj_target = np.max(bmajs)+1.42*cell_size bmin_target = np.max(bmajs)+1.42*cell_size bpa_target = 0. print("Smoothing all images to") print("Major axis: {0:.2f} arcsec".format(bmaj_target)) print("Minor axis: {0:.2f} arcsec".format(bmin_target)) print("Position angle: {0:.2f} degs".format(bpa_target)) bmaj_target = {'unit':'arcsec','value':bmaj_target} bmin_target = {'unit':'arcsec','value':bmin_target} bpa_target = {'unit':'deg','value':bpa_target} for imagename, resimagename in zip(images+cubes, resimages+rescubes): # export velocity axis if this is a cube velocity = 'channel' in imagename # smooth image outfile = imagename.replace('.image.fits','.imsmooth.image') if mosaic: outfile = imagename.replace('.image.linmos.fits', '.imsmooth.image.linmos') casa.imsmooth(imagename=imagename,kernel='gauss', targetres=True,major=bmaj_target,minor=bmin_target, pa=bpa_target,outfile=outfile,overwrite=overwrite) casa.exportfits(imagename=outfile,fitsimage='{0}.fits'.format(outfile), velocity=velocity,overwrite=True,history=False) # primary beam correct if not mosaic: smoimagename = outfile pbimage = imagename.replace('.{0}.image.fits'.format(imagetype), '.pb.fits') outfile = imagename.replace('.image.fits', '.pbcor.imsmooth.image') casa.impbcor(imagename=smoimagename, pbimage=pbimage, outfile=outfile, overwrite=True) casa.exportfits(imagename=outfile,fitsimage='{0}.fits'.format(outfile), velocity=velocity,overwrite=True,history=False) # check that residual image has beam size, if not add it with fits.open(resimagename, 'update') as hdulist: hdu = hdulist[0] if 'BMIN' not in hdu.header: hdu.header['BMIN'] = bmin_target['value']/3600. hdu.header['BMAJ'] = bmaj_target['value']/3600. hdu.header['BPA'] = bpa_target['value'] # smooth residual image outfile = resimagename.replace('.residual.fits','.imsmooth.residual') if mosaic: outfile = resimagename.replace('.residual.linmos.fits', '.imsmooth.residual.linmos') casa.imsmooth(imagename=resimagename,kernel='gauss', targetres=True,major=bmaj_target,minor=bmin_target, pa=bpa_target,outfile=outfile,overwrite=overwrite) casa.exportfits(imagename=outfile,fitsimage='{0}.fits'.format(outfile), velocity=velocity,overwrite=True,history=False) print("Done!")