from __future__ import absolute_import import os import re import glob import pylab as pl from casatasks.private.casa_transition import is_CASA6 if is_CASA6: from casatools import table, image, imager from casatasks import casalog, sdimaging, imregrid, immath, concat, feather from . import sdbeamutil from .simutil import * tb = table( ) ia = image( ) im = imager( ) else: from taskinit import * from simutil import * from sdimaging import sdimaging from imregrid import imregrid from immath import immath from concat import concat from feather import feather import sdbeamutil from casa_stack_manip import stack_frame_find # the global tb, ia, and im tools are used def simanalyze( project=None, image=None, # if image==False: imagename=None, skymodel=None, # else: vis=None, modelimage=None, imsize=None, imdirection=None, cell=None, interactive=None, niter=None, threshold=None, weighting=None, mask=None, outertaper=None, pbcor=None, stokes=None, featherimage=None, # endif analyze=None, showuv=None, showpsf=None, showmodel=None, showconvolved=None, showclean=None, showresidual=None, showdifference=None, showfidelity=None, graphics=None, verbose=None, overwrite=None, dryrun=False, logfile=None ): #def simanalyze(project='sim', image=True, imagename='default', skymodel='', vis='default', modelimage='', imsize=[128, 128], imdirection='', cell='', interactive=False, niter=0, threshold='0.1mJy', weighting='natural', mask=[], outertaper=[''], stokes='I', featherimage='', analyze=False, showuv=True, showpsf=True, showmodel=True, showconvolved=False, showclean=True, showresidual=False, showdifference=True, showfidelity=True, graphics='both', verbose=False, overwrite=True, dryrun=False): # Collect a list of parameter values to save inputs in_params = locals() casalog.origin('simanalyze') if verbose: casalog.filter(level="DEBUG2") if not is_CASA6: myf = stack_frame_find( ) # create the utility object: myutil = simutil() if logfile: myutil.reportfile=logfile myutil.openreport() if verbose: myutil.verbose = True msg = myutil.msg # put output in directory called "project" fileroot = project if not os.path.exists(fileroot): msg(fileroot+" directory doesn't exist - the task expects to find results from creating the datasets there, like the skymodel.",priority="error") # msg should raise an exception for priority=error if not is_CASA6: saveinputs = myf['saveinputs'] saveinputs('simanalyze',fileroot+"/"+project+".simanalyze.last") # myparams=in_params) else: casalog.post("saveinputs not available in casatasks, skipping saving simanalyze inputs", priority='INFO') if (not image) and (not analyze): casalog.post("No operation to be done. Exiting from task.", "WARN") return grscreen = False grfile = False if graphics == "both": grscreen = True grfile = True if graphics == "screen": grscreen = True if graphics == "file": grfile = True try: # Predefined parameters pbcoeff = 1.13 ## PB defined as pbcoeff*lambda/d # handle '$project' in modelimage modelimage = modelimage.replace('$project',project) featherimage = featherimage.replace('$project',project) #========================= # things we need: model_cell, model_direction if user doesn't specify - # so find those first, and get information using util.modifymodel # with skymodel=newmodel # we need to parse either the mslist or imagename (if image=False) # first, so that we can pick the appropriate skymodel, # if there are several. skymodel_searchstring="NOT SPECIFIED" if not (image or dryrun): user_imagename=imagename if user_imagename=="default" or len(user_imagename)<=0: images= glob.glob(fileroot+"/*image") if len(images)<1: emsg = "can't find any image in project directory" raise RuntimeError(emsg) if len(images)>1: msg("found multiple images in project directory",priority="warn") msg("using "+images[0],priority="warn") imagename=images[0] # trim .image suffix: imagename= imagename.replace(".image","") # if the user hasn't specified a sky model image, we can try to # see if their imagename contains something like the project and # configuration, as it would if simobserve created it. user_skymodel=skymodel if not os.path.exists(user_skymodel): if os.path.exists(fileroot+"/"+user_skymodel): user_skymodel=fileroot+"/"+user_skymodel elif len(user_skymodel)>0: raise RuntimeError("Can't find your specified skymodel "+user_skymodel) # try to strip a searchable identifier tmpstring=user_skymodel.split("/")[-1] skymodel_searchstring=tmpstring.replace(".image","") if image: # check for default measurement sets: default_mslist = glob.glob(fileroot+"/*ms") n_default=len(default_mslist) # is the user requesting this ms? default_requested=[] for i in range(n_default): default_requested.append(False) # parse ms parameter and check for existance; # initial ms list if vis=="default" or len(vis)==0: mslist0=default_mslist else: mslist0 = vis.split(',') # verified found ms list mslist = [] mstype = [] mstoimage=[] tpmstoimage=None for ms0 in mslist0: if not len(ms0): continue ms1 = ms0.replace('$project',project) # MSes in fileroot/ have priority if os.path.exists(fileroot+"/"+ms1): ms1 = fileroot + "/" + ms1 if os.path.exists(ms1)or dryrun: mslist.append(ms1) # mark as requested if default_mslist.count(ms1): i=default_mslist.index(ms1) default_requested[i]=True # check if noisy in name if re.search('noisy.',ms1): ms1_raw=str.join("",re.split('noisy.',ms1)) if default_mslist.count(ms1_raw): i=default_mslist.index(ms1_raw) default_requested[i]=True else: # not noisy if ms1.endswith(".sd.ms"): ms1_noisy=re.split('.sd.ms',ms1)[0]+'.noisy.sd.ms' else: ms1_noisy=re.split('.ms',ms1)[0]+'.noisy.ms' if default_mslist.count(ms1_noisy): i=default_mslist.index(ms1_noisy) default_requested[i]=True if vis == "default": continue msg("You requested "+ms1+" but there is a noisy version of the ms in your project directory - if your intent is to model noisy data you may want to check inputs",priority="warn") # check if the ms is tp data or not. if dryrun: # HACK mstype.append('INT') mstoimage.append(ms1) elif myutil.ismstp(ms1,halt=False): mstype.append('TP') tpmstoimage = ms1 # XXX TODO more than one TP ms will not be handled # correctly msg("Found a total power measurement set, %s." % ms1,origin='simanalyze') else: mstype.append('INT') mstoimage.append(ms1) msg("Found a synthesis measurement set, %s." % ms1,origin='simanalyze') else: msg("measurement set "+ms1+" not found -- removing from imaging list") # check default mslist for unrequested ms: for i in range(n_default): if not default_requested[i]: msg("Project directory contains "+default_mslist[i]+" but you have not requested to include it in your simulated image.") if not mstoimage and len(tpmstoimage) == 0: raise RuntimeError("No MS found to image") # now try to parse the mslist for an identifier string that # we can use to find the right skymodel if there are several if len(mstoimage) == 0 and len(tpmstoimage) > 0: tmpstring = tpmstoimage.split("/")[-1] else: tmpstring=(mstoimage[0]).split("/")[-1] skymodel_searchstring=tmpstring.replace(".ms","") # more than one to image? if len(mstoimage) > 1: msg("Multiple interferometric ms found:",priority="info",origin='simanalyze') for i in range(len(mstoimage)): msg(" "+mstoimage[i],priority="info",origin='simanalyze') msg(" will be concated and simultaneously deconvolved; if something else is desired, please specify vis, or image manually and use image=F",priority="info",origin='simanalyze') concatms=project+"/"+project+".concat.ms" weights = get_concatweights(mstoimage) msg(" concat("+str(mstoimage)+",concatvis='"+concatms+"',visweightscale="+str(weights)+")",origin='simanalyze') if not dryrun: concat(mstoimage,concatvis=concatms,visweightscale=weights) mstoimage=[concatms] #======================================================== # now we can search for skymodel, and if there are several, # pick the one that is closest to either the imagename, # or the first MS if there are several MS to image. components_only=False # first look for skymodel, if not then compskymodel skymodels=glob.glob(fileroot+"/"+project+"*.skymodel")+glob.glob(fileroot+"/"+project+"*.newmodel") nmodels=len(skymodels) skymodel_index=0 if nmodels>1: msg("Found %i sky model images:" % nmodels,origin='simanalyze') # use the skymodel_searchstring to try to pick the right one # print them out for the user while we're at it. for i in range(nmodels): msg(" "+skymodels[i]) if skymodels[i].count(skymodel_searchstring)>0: skymodel_index=i msg("Using skymodel "+skymodels[skymodel_index],origin='simanalyze') if nmodels>=1: skymodel=skymodels[skymodel_index] else: skymodel="" if os.path.exists(skymodel): msg("Sky model image "+skymodel+" found.",origin='simanalyze') else: skymodels=glob.glob(fileroot+"/"+project+"*.compskymodel") nmodels=len(skymodels) if nmodels>1: msg("Found %i sky model images:" % nmodels,origin='simanalyze') for ff in skymodels: msg(" "+ff) msg("Using "+skymodels[0],origin='simanalyze') if nmodels>=1: skymodel=skymodels[0] else: skymodel="" if os.path.exists(skymodel): msg("Sky model image "+skymodel+" found.",origin='simanalyze') components_only=True elif not dryrun: msg("Can't find a model image in your project directory, named skymodel or compskymodel - output image will be created, but comparison with the input model is not possible.",priority="warn",origin='simanalyze') analyze=False modelflat = skymodel+".flat" if os.path.exists(skymodel): if not (os.path.exists(modelflat) or dryrun): myutil.flatimage(skymodel,verbose=verbose) # modifymodel just collects info if skymodel==newmodel (model_refdir,model_cell,model_size, model_nchan,model_specrefval,model_specrefpix,model_width, model_stokes) = myutil.modifymodel(skymodel,skymodel, "","","","","",-1, flatimage=False) cell_asec=qa.convert(model_cell[0],'arcsec')['value'] ##################################################################### # clean if desired, use noisy image for further calculation if present # todo suggest a cell size from psf? ##################################################################### if image: # make sure cell is defined if is_array_type(cell): if len(cell) > 0: cell0 = cell[0] else: cell0 = "" else: cell0 = cell if len(cell0)<=0: cell = model_cell if is_array_type(cell): if len(cell) == 1: cell = [cell[0],cell[0]] else: cell = [cell,cell] # cells are positive by convention cell = [qa.abs(cell[0]),qa.abs(cell[1])] # and imsize if is_array_type(imsize): if len(imsize) > 0: imsize0 = imsize[0] if len(imsize) > 1: imsize1 = imsize[1] else: imsize1 = imsize0 else: imsize0 = -1 else: imsize0 = imsize if imsize0 <= 0: imsize = [int(pl.ceil(qa.convert(qa.div(model_size[0],cell[0]),"")['value'])), int(pl.ceil(qa.convert(qa.div(model_size[1],cell[1]),"")['value']))] else: imsize=[imsize0,imsize1] if len(mstoimage) == 0: if tpmstoimage: sd_only = True else: msg("no measurement sets found to image",priority="error",origin='simanalyze') else: sd_only = False # get some quantities from the interferometric ms # TODO use something like aU.baselineStats for this, and the 90% baseline maxbase=0. if len(mstoimage)>1 and dryrun: msg("imaging multiple ms not possible in dryrun mode",priority="warn",origin="simanalyze") # TODO make work better for multiple MS for msfile in mstoimage: if os.path.exists(msfile): tb.open(msfile) rawdata = tb.getcol("UVW") tb.done() maxbase = max([max(rawdata[0,]),max(rawdata[1,])]) # in m psfsize = 0.3/qa.convert(qa.quantity(model_specrefval),'GHz')['value']/maxbase*3600.*180/pl.pi # lambda/b converted to arcsec minimsize = 8* int(psfsize/cell_asec) elif dryrun: minimsize = min(imsize) psfsize = qa.mul(cell[0],3) # HACK else: raise RuntimeError(mstoimage+" not found.") if imsize[0] < minimsize: msg("The number of image pixel in x-axis, %d, is small to cover 8 x PSF. Setting x pixel number, %d." % (imsize[0], minimsize), priority='warn',origin='simanalyze') imsize[0] = minimsize if imsize[1] < minimsize: msg("The number of image pixel in y-axis, %d, is small to cover 8 x PSF. Setting y pixel number, %d" % (imsize[1], minimsize), priority='warn',origin='simanalyze') imsize[1] = minimsize tpimage=None # Do single dish imaging first if tpmstoimage exists. if tpmstoimage and os.path.exists(tpmstoimage): msg('creating image from ms: '+tpmstoimage,origin='simanalyze') #if len(mstoimage): # tpimage = project + '.sd.image' #else: # tpimage = project + '.image' tpimage = project + '.sd.image' tpimage = fileroot + "/" + tpimage if len(mstoimage): if len(modelimage) and tpimage != modelimage and \ tpimage != fileroot+"/"+modelimage: msg("modelimage parameter set to "+modelimage+" but also creating a new total power image "+tpimage,priority="warn",origin='simanalyze') msg("assuming you know what you want, and using modelimage="+modelimage+" in deconvolution",priority="warn",origin='simanalyze') elif len(featherimage) and tpimage != featherimage and \ tpimage != fileroot+"/"+featherimage: msg("featherimage parameter set to "+featherimage+" but also creating a new total power image "+tpimage,priority="warn",origin='simanalyze') msg("assuming you know what you want, and using featherimage="+featherimage+" in feather",priority="warn",origin='simanalyze') # Get PB size of TP Antenna # !! aveant will only be set if modifymodel or setpointings and in # any case it will the the aveant of the INTERFM array - we want the SD if os.path.exists(tpmstoimage): # antenna diameter tb.open(tpmstoimage+"/ANTENNA") diams = tb.getcol("DISH_DIAMETER") tb.close() aveant = pl.mean(diams) # theoretical antenna beam size pb_asec = sdbeamutil.primaryBeamArcsec(qa.tos(qa.convert(qa.quantity(model_specrefval),'GHz')),aveant,(0.75 if aveant==12.0 else 0.0),10.0) elif dryrun: aveant = 12.0 pb_asec = pbcoeff*0.29979/qa.convert(qa.quantity(model_specrefval),'GHz')['value']/aveant*3600.*180/pl.pi else: raise RuntimeError(tpmstoimage+" not found.") # default PSF from PB of antenna imbeam = {'major': qa.quantity(pb_asec,'arcsec'), 'minor': qa.quantity(pb_asec,'arcsec'), 'positionangle': qa.quantity(0.0,'deg')} # Common imaging parameters sdim_param = dict(infiles=[tpmstoimage], overwrite=overwrite, phasecenter=model_refdir, mode='channel', nchan=model_nchan, start=0, width=1) if True: #SF gridding msg("Generating TP image using 'SF' kernel.",origin='simanalyze') beamsamp = 9 sfcell_asec = pb_asec/beamsamp sfcell = qa.tos(qa.quantity(sfcell_asec, "arcsec")) cell_asec = [qa.convert(cell[0],"arcsec")['value'], qa.convert(cell[1],"arcsec")['value']] if cell_asec[0] > sfcell_asec or \ cell_asec[1] > sfcell_asec: # imregrid() may not work properly for regrid of # small to large cell msg("The requested cell size is too large to invoke SF gridding. Please set cell size <= %f arcsec or grid TP MS '%s' manually" % (sfcell_asec, tpmstoimage),priority="error",origin='simanalyze') sfsupport = 6 temp_out = tpimage+"0" temp_cell = [sfcell, sfcell] # too small - is imsize too small to start with? # needs to cover all pointings. temp_imsize = [int(pl.ceil(cell_asec[0]/sfcell_asec*imsize[0])), int(pl.ceil(cell_asec[1]/sfcell_asec*imsize[1]))] msg("Using predefined algorithm to define grid parameters.",origin='simanalyze') msg("SF gridding summary",origin='simanalyze') msg("- Antenna primary beam: %f arcsec" % pb_asec,origin='simanalyze') msg("- Image pixels per antenna PB (predefined): %f" % beamsamp,origin='simanalyze') msg("- Cell size (arcsec): [%s, %s]" % (temp_cell[0], temp_cell[1]),origin='simanalyze') msg("- Imsize to cover final TP image area: [%d, %d] (type: %s)" % (temp_imsize[0], temp_imsize[1], type(temp_imsize[0])),origin='simanalyze') msg("- convolution support: %d" % sfsupport,origin='simanalyze') # kernel specific imaging parameters sdim_param['gridfunction'] = 'SF' sdim_param['convsupport'] = sfsupport sdim_param['outfile'] = temp_out sdim_param['imsize'] = temp_imsize sdim_param['cell'] = temp_cell msg(get_taskstr('sdimaging', sdim_param), priority="info") if not dryrun: sdimaging(**sdim_param) if not os.path.exists(temp_out): raise RuntimeError("TP imaging failed.") # Scale image by convolved beam / antenna primary beam ia.open(temp_out) imbeam = ia.restoringbeam() ia.close() try: beam_area_ratio = qa.getvalue(qa.convert(imbeam['major'], "arcsec")) \ * qa.getvalue(qa.convert(imbeam['minor'], "arcsec")) \ / pb_asec**2 except KeyError: # this shouldn't hit when simutil.imtclean sets restoringbeam='common' msg("using center channel values to calculate beam area ratio", origin='simanalyze', priority='info') chan_index = int(imbeam['nChannels']/2) pol_index = 0 beam_area_ratio = qa.getvalue(qa.convert(imbeam['major'], "arcsec")) \ * qa.getvalue(qa.convert(imbeam['minor'], "arcsec")) \ / pb_asec**2 msg("Scaling TP image intensity by %f." % (beam_area_ratio),origin='simanalyze') temp_in = temp_out temp_out = temp_out + ".scaled" immath(imagename=temp_in, mode='evalexpr', expr="IM0*%f" % (beam_area_ratio), outfile=temp_out) if not os.path.exists(temp_out): raise RuntimeError("TP image scaling failed.") # Regrid TP image to final resolution msg("Regridding TP image to final resolution",origin='simanalyze') msg("- cell size (arecsec): [%s, %s]" % (cell[0], cell[1]),origin='simanalyze') msg("- imsize: [%d, %d]" % (imsize[0], imsize[1]),origin='simanalyze') if not dryrun: ia.open(temp_out) newcsys = ia.coordsys() ia.close() dir_idx = newcsys.findcoordinate("direction")['world'] newcsys.setreferencepixel([imsize[0]/2., imsize[1]/2.], type="direction") incr = newcsys.increment(type='direction')['numeric'] newincr = [incr[0]*cell_asec[0]/sfcell_asec, incr[1]*cell_asec[1]/sfcell_asec,] newcsys.setincrement(newincr, type="direction") # sdtemplate = imregrid(imagename=temp_out, template="get") sdtemplate['csys'] = newcsys.torecord() for idx in range(len(dir_idx)): sdtemplate['shap'][ dir_idx[idx] ] = imsize[idx] imregrid(imagename=temp_out, interpolation="cubic", template=sdtemplate, output=tpimage, overwrite=overwrite) del newcsys, sdtemplate, incr, newincr, dir_idx del temp_out, temp_cell, temp_imsize, sfcell_asec, cell_asec else: #PB grid msg("Generating TP image using 'PB' kernel.",origin='simanalyze') # Final TP cell and image size. # imsize and cell are already int and quantum arrays sdimsize = imsize sdcell = [qa.tos(cell[0]), qa.tos(cell[1])] ### TODO: need to set phasecenter properly based on imdirection # kernel specific imaging parameters sdim_param['gridfunction'] = 'PB' sdim_param['outfile'] = tpimage sdim_param['imsize'] = sdimsize sdim_param['cell'] = sdcell msg(get_taskstr('sdimaging', sdim_param), priority="info") if not dryrun: sdimaging(**sdim_param) del sdimsize, sdcell # TODO: Define PSF of image here # for now use default # get image beam size form TP image if os.path.exists(tpimage): ia.open(tpimage) beam = ia.restoringbeam() ia.close() if sd_only: try: bmarea = beam['major']['value']*beam['minor']['value']*1.1331 #arcsec2 except KeyError: # this shouldn't hit when simutil.imtclean sets restoringbeam='common' msg("using center channel values to calculate beam area", origin='simanalyze', priority='info') chan_index = int(beam['nChannels']/2) pol_index = 0 bmarea = (beam['beams']['*'+str(chan_index)]['*'+str(pol_index)]['major']['value'] * beam['beams']['*'+str(chan_index)]['*'+str(pol_index)]['minor']['value'] * 1.1331) #arcsec2 bmarea = bmarea/(cell[0]['value']*cell[1]['value']) # bm area in pix else: del beam #del beam msg('generation of total power image '+tpimage+' complete.',origin='simanalyze') # update TP ms name the for following steps sdmsfile = tpmstoimage sd_any = True imagename = re.split('.image$',tpimage)[0] # End of single dish imaging part outflat_current = False convsky_current = False if image and len(mstoimage) > 0: # for reruns foo=mstoimage[0] foo=foo.replace(".ms","") foo=foo.replace(project,"") foo=foo.replace("/","") project=project+foo imagename = fileroot + "/" + project # get nfld, sourcefieldlist, from (interfm) ms if it was not just created # TODO make work better for multiple mstoimage (figures below) if os.path.exists(mstoimage[0]): tb.open(mstoimage[0]+"/SOURCE") code = tb.getcol("CODE") sourcefieldlist = pl.where(code=='OBJ')[0] nfld = len(sourcefieldlist) tb.done() elif dryrun: nfld=1 # HACK msfile = mstoimage[0] # set cleanmode automatically (for interfm) if nfld == 1: cleanmode = "csclean" gridder = "standard" else: cleanmode = "mosaic" gridder = "mosaic" # keep the same default minor cycle algorithm for imtclean # as previously used in imclean deconvolver = "clark" # clean insists on using an existing model if its present if os.path.exists(imagename+".image"): shutil.rmtree(imagename+".image") if os.path.exists(imagename+".model"): shutil.rmtree(imagename+".model") # An image in fileroot/ has priority if len(modelimage) > 0 and os.path.exists(fileroot+"/"+modelimage): modelimage = fileroot + "/" + modelimage msg("Found modelimage, %s." % modelimage,origin='simanalyze') # in simdata we use imdirection instead of model_refdir if not myutil.isdirection(imdirection,halt=False): imdirection=model_refdir myutil.imtclean(mstoimage,imagename, gridder,deconvolver, cell,imsize,imdirection, interactive,niter,threshold, weighting,outertaper,pbcor,stokes, modelimage=modelimage,mask=mask, dryrun=dryrun) ## Disabled as part of CAS-12502 #myutil.imclean(mstoimage,imagename, # cleanmode,cell,imsize,imdirection, # interactive,niter,threshold,weighting, # outertaper,pbcor,stokes, # #sourcefieldlist=sourcefieldlist, # modelimage=modelimage,mask=mask,dryrun=dryrun) # create imagename.flat and imagename.residual.flat: if not dryrun: myutil.flatimage(imagename+".image",verbose=verbose) myutil.flatimage(imagename+".residual",verbose=verbose) outflat_current = True # feather if featherimage: if not os.path.exists(featherimage): raise RuntimeError("Could not find featherimage "+featherimage) else: featherimage="" if tpimage: # if you set modelimage, then it won't force tpimage into # featherimage. this could be hard to explain # to the user. if os.path.exists(tpimage) and not os.path.exists(modelimage): featherimage=tpimage if os.path.exists(featherimage): msg("feathering the interfermetric image "+imagename+".image with "+featherimage,origin='simanalyze',priority="info") # TODO call with params? msg("feather('"+imagename+".feather.image','"+imagename+".image','"+featherimage+"')",priority="info") if not dryrun: feather(imagename+".feather.image",imagename+".image",featherimage) # copy residual flat image shutil.copytree(imagename+".residual.flat",imagename+".feather.residual.flat") imagename=imagename+".feather" # but replace combined flat image myutil.flatimage(imagename+".image",verbose=verbose) if verbose: msg(" ") msg("done inverting and cleaning",origin='simanalyze') if not is_array_type(cell): cell = [cell,cell] if len(cell) <= 1: cell = [qa.quantity(cell[0]),qa.quantity(cell[0])] else: cell = [qa.quantity(cell[0]),qa.quantity(cell[1])] cell = [qa.abs(cell[0]),qa.abs(cell[0])] # get beam from output clean image if verbose: msg("getting beam from "+imagename+".image",origin='simanalyze') if os.path.exists(imagename+".image"): ia.open(imagename+".image") beam = ia.restoringbeam() ia.close() # model has units of Jy/pix - calculate beam area from clean image # (even if we are not plotting graphics) try: bmarea = beam['major']['value']*beam['minor']['value']*1.1331 #arcsec2 except KeyError: # this shouldn't hit when simutil.imtclean sets restoringbeam='common' msg("using center channel values to calculate beam area", origin='simanalyze', priority='info') chan_index = int(beam['nChannels']/2) pol_index = 0 bmarea = (beam['beams']['*'+str(chan_index)]['*'+str(pol_index)]['major']['value'] * beam['beams']['*'+str(chan_index)]['*'+str(pol_index)]['minor']['value'] * 1.1331) #arcsec2 bmarea = bmarea/(cell[0]['value']*cell[1]['value']) # bm area in pix msg("synthesized beam area in output pixels = %f" % bmarea,origin='simanalyze') if image: # show model, convolved model, clean image, and residual if grfile: file = fileroot + "/" + project + ".image.png" else: file = "" else: mslist=[] if dryrun: grscreen=False grfile=False analyze=False if image and len(mstoimage) > 0: if grscreen or grfile: myutil.newfig(multi=[2,2,1],show=grscreen) # create regridded and convolved sky model image myutil.convimage(modelflat,imagename+".image.flat") convsky_current = True # don't remake this for analysis in this run disprange = [] # passing empty list causes return of disprange # original sky regridded to output pixels but not convolved with beam discard = myutil.statim(modelflat+".regrid",disprange=disprange,showstats=False) myutil.nextfig() # convolved sky model - units of Jy/bm disprange = [] discard = myutil.statim(modelflat+".regrid.conv",disprange=disprange) myutil.nextfig() # clean image - also in Jy/beam # although because of DC offset, better to reset disprange disprange = [] discard = myutil.statim(imagename+".image.flat",disprange=disprange) myutil.nextfig() if len(mstoimage) > 0: myutil.nextfig() # clean residual image - Jy/bm discard = myutil.statim(imagename+".residual.flat",disprange=disprange) myutil.endfig(show=grscreen,filename=file) ##################################################################### # analysis if analyze: if not os.path.exists(imagename+".image"): if os.path.exists(fileroot+"/"+imagename+".image"): imagename=fileroot+"/"+imagename else: emsg = "Can't find a simulated image - expecting "+imagename raise RuntimeError(emsg) # we should have skymodel.flat created above if not image: if not os.path.exists(imagename+".image"): emsg = "you must image before analyzing." raise RuntimeError(emsg) # get beam from output clean image if verbose: msg("getting beam from "+imagename+".image",origin="analysis") ia.open(imagename+".image") beam = ia.restoringbeam() ia.close() # model has units of Jy/pix - calculate beam area from clean image cell = myutil.cellsize(imagename+".image") cell= [ qa.convert(cell[0],'arcsec'), qa.convert(cell[1],'arcsec') ] # (even if we are not plotting graphics) try: bmarea = beam['major']['value']*beam['minor']['value']*1.1331 #arcsec2 except KeyError: # this shouldn't hit when simutil.imtclean sets restoringbeam='common' msg("using center channel values to calculate beam area", origin='simanalyze', priority='info') chan_index = int(beam['nChannels']/2) pol_index = 0 bmarea = (beam['beams']['*'+str(chan_index)]['*'+str(pol_index)]['major']['value'] * beam['beams']['*'+str(chan_index)]['*'+str(pol_index)]['minor']['value'] * 1.1331) #arcsec2 bmarea = bmarea/(cell[0]['value']*cell[1]['value']) # bm area in pix msg("synthesized beam area in output pixels = %f" % bmarea) # flat output:? if the user manually cleaned, this may not exist outflat = imagename + ".image.flat" if (not outflat_current) or (not os.path.exists(outflat)): # create imagename.flat and imagename.residual.flat myutil.flatimage(imagename+".image",verbose=verbose) if os.path.exists(imagename+".residual"): myutil.flatimage(imagename+".residual",verbose=verbose) else: if showresidual: msg(imagename+".residual not found -- residual will not be plotted",priority="warn") showresidual = False outflat_current = True # regridded and convolved input:? if not convsky_current: myutil.convimage(modelflat,imagename+".image.flat") convsky_current = True # now should have all the flat, convolved etc even if didn't run "image" # make difference image. # immath does Jy/bm if image but only if ia.setbrightnessunit("Jy/beam") in convimage() convolved = modelflat + ".regrid.conv" difference = imagename + '.diff' diff_ia = ia.imagecalc(difference, "'%s' - '%s'" % (convolved, outflat), overwrite=True) diff_ia.setbrightnessunit("Jy/beam") # get rms of difference image for fidelity calculation #ia.open(difference) diffstats = diff_ia.statistics(robust=True, verbose=False,list=False) diff_ia.close() del diff_ia maxdiff = diffstats['medabsdevmed'] if maxdiff != maxdiff: maxdiff = 0. if type(maxdiff) != type(0.): if maxdiff.__len__() > 0: maxdiff = maxdiff[0] else: maxdiff = 0. # Make fidelity image. absdiff = imagename + '.absdiff' calc_ia = ia.imagecalc(absdiff, "max(abs('%s'), %f)" % (difference, maxdiff/pl.sqrt(2.0)), overwrite=True) calc_ia.close() fidelityim = imagename + '.fidelity' calc_ia = ia.imagecalc(fidelityim, "abs('%s') / '%s'" % (convolved, absdiff), overwrite=True) calc_ia.close() msg("fidelity image calculated",origin="analysis") # scalar fidelity absconv = imagename + '.absconv' calc_ia = ia.imagecalc(absconv, "abs('%s')" % convolved, overwrite=True) if ia.isopen(): ia.close() #probably not necessary calc_ia.close() del calc_ia ia.open(absconv) modelstats = ia.statistics(robust=True, verbose=False,list=False) maxmodel = modelstats['max'] if maxmodel != maxmodel: maxmodel = 0. if type(maxmodel) != type(0.): if maxmodel.__len__() > 0: maxmodel = maxmodel[0] else: maxmodel = 0. ia.close() scalarfidel = maxmodel/maxdiff msg("fidelity range (max model / rms difference) = "+str(scalarfidel),origin="analysis") # now, what does the user want to actually display? # need MS for showuv and showpsf if not image: msfile = fileroot + "/" + project + ".ms" elif sd_only: # imaged and single dish only msfile = tpmstoimage # psf is not available for SD only sim if os.path.exists(msfile) and myutil.ismstp(msfile,halt=False): if showpsf: msg("single dish simulation -- psf will not be plotted",priority='warn') showpsf = False if (not image) and (not os.path.exists(msfile)): if showpsf or showuv: msg("No image is generated in this run. Default MS, '%s', does not exist -- uv and psf will not be plotted" % msfile,priority='warn') showpsf = False showuv = False # if the order in the task input changes, change it here too figs = [showuv,showpsf,showmodel,showconvolved,showclean,showresidual,showdifference,showfidelity] nfig = figs.count(True) if nfig > 6: msg("only displaying first 6 selected panels in graphic output",priority="warn") if nfig <= 0: return if nfig < 4: multi = [1,nfig,1] else: if nfig == 4: multi = [2,2,1] else: multi = [2,3,1] if grfile: file = fileroot + "/" + project + ".analysis.png" else: file = "" if grscreen or grfile: myutil.newfig(multi=multi,show=grscreen) # if order in task parameters changes, change here too if showuv: # TODO loop over all ms - show all UV including zero if len(mslist)>1: msg("Using only "+msfile+" for uv plot",priority="warn",origin='simanalyze') tb.open(msfile) rawdata = tb.getcol("UVW") tb.done() pl.box() maxbase = max([max(rawdata[0,]),max(rawdata[1,])]) # in m klam_m = 300/qa.convert(model_specrefval,'GHz')['value'] pl.plot(rawdata[0,]/klam_m,rawdata[1,]/klam_m,'b,') pl.plot(-rawdata[0,]/klam_m,-rawdata[1,]/klam_m,'b,') ax = pl.gca() ax.yaxis.LABELPAD = -4 pl.xlabel('u[klambda]',fontsize='x-small') pl.ylabel('v[klambda]',fontsize='x-small') pl.axis('equal') # Add zero-spacing (single dish) if not yet plotted # TODO make this a check over all ms # if predict_sd and not myutil.ismstp(msfile,halt=False): # pl.plot([0.],[0.],'r,') myutil.nextfig() if showpsf: if image: psfim = imagename + ".psf" else: psfim = project + ".quick.psf" if not os.path.exists(psfim): if len(mslist)>1: msg("Using only "+msfile+" for psf generation",priority="warn") im.open(msfile) # TODO spectral parms im.defineimage(cellx=qa.tos(model_cell[0]),nx=max([minimsize,128])) if os.path.exists(psfim): shutil.rmtree(psfim) im.approximatepsf(psf=psfim) # beam is set above (even in "analyze" only) # note that if image, beam has fields 'major' whereas if not, it # has fields like 'bmaj'. # beam=im.fitpsf(psf=psfim) im.done() ia.open(psfim) beamcs = ia.coordsys() beam_array = ia.getchunk(axes=[beamcs.findcoordinate("spectral")['pixel'][0],beamcs.findcoordinate("stokes")['pixel'][0]],dropdeg=True) nn = beam_array.shape xextent = nn[0]*cell_asec*0.5 xextent = [xextent,-xextent] yextent = nn[1]*cell_asec*0.5 yextent = [-yextent,yextent] flipped_array = beam_array.transpose() ttrans_array = flipped_array.tolist() ttrans_array.reverse() pl.imshow(ttrans_array,interpolation='bilinear',cmap=pl.cm.jet,extent=xextent+yextent,origin="lower") psfim.replace(project+"/","") pl.title(psfim,fontsize="x-small") try: b = qa.convert(beam['major'],'arcsec')['value'] pl.xlim([-3*b,3*b]) pl.ylim([-3*b,3*b]) ax = pl.gca() pl.text(0.05,0.95,"bmaj=%7.1e\nbmin=%7.1e" % (beam['major']['value'], beam['minor']['value']), transform = ax.transAxes,bbox=dict(facecolor='white', alpha=0.7),size="x-small",verticalalignment="top") except KeyError: # this shouldn't hit when simutil.imtclean sets restoringbeam='common' msg("using center channel beam values for plot configuration", origin='simanalyze', priority='info') chan_index = int(beam['nChannels']/2) pol_index = 0 b = qa.convert(beam['beams']['*'+str(chan_index)]['*'+str(pol_index)]['major'],'arcsec')['value'] pl.xlim([-3*b,3*b]) pl.ylim([-3*b,3*b]) ax = pl.gca() pl.text(0.05, 0.95, "bmaj=%7.1e\nbmin=%7.1e" % (beam['beams']['*'+str(chan_index)]['*'+str(pol_index)]['major']['value'], beam['beams']['*'+str(chan_index)]['*'+str(pol_index)]['minor']['value']), transform = ax.transAxes,bbox=dict(facecolor='white', alpha=0.7),size="x-small",verticalalignment="top") ia.close() myutil.nextfig() disprange = [] # first plot will define range if showmodel: discard = myutil.statim(modelflat+".regrid",incell=cell,disprange=disprange,showstats=False) myutil.nextfig() disprange = [] if showconvolved: discard = myutil.statim(modelflat+".regrid.conv") # if disprange gets set here, it'll be Jy/bm myutil.nextfig() if showclean: # own scaling because of DC/zero spacing offset discard = myutil.statim(imagename+".image.flat") myutil.nextfig() if showresidual: # it gets its own scaling discard = myutil.statim(imagename+".residual.flat") myutil.nextfig() if showdifference: # it gets its own scaling. discard = myutil.statim(imagename+".diff") myutil.nextfig() if showfidelity: # it gets its own scaling. discard = myutil.statim(imagename+".fidelity",showstats=False) myutil.nextfig() myutil.endfig(show=grscreen,filename=file) sim_min,sim_max,sim_rms,sim_units = myutil.statim(imagename+".image.flat",plot=False) # if not displaying still print stats: # 20100505 ia.stats changed to return Jy/bm: msg('Simulation rms: '+str(sim_rms/bmarea)+" Jy/pix = "+ str(sim_rms)+" Jy/bm",origin="analysis") msg('Simulation max: '+str(sim_max/bmarea)+" Jy/pix = "+ str(sim_max)+" Jy/bm",origin="analysis") #msg('Simulation rms: '+str(sim_rms)+" Jy/pix = "+ # str(sim_rms*bmarea)+" Jy/bm",origin="analysis") #msg('Simulation max: '+str(sim_max)+" Jy/pix = "+ # str(sim_max*bmarea)+" Jy/bm",origin="analysis") try: msg('Beam bmaj: '+str(beam['major']['value'])+ ' bmin: '+str(beam['minor']['value'])+ ' bpa: '+str(beam['positionangle']['value']), origin="analysis") except KeyError: # per-plane beams... pol_index = 0 for chan_index in range(0, beam['nChannels']): msg('polarization '+str(pol_index) + ' channel '+str(chan_index) + ' Beam' ' bmaj: '+str(beam['beams']['*'+str(chan_index)]['*'+str(pol_index)]['major']['value'])+ ' bmin: '+str(beam['beams']['*'+str(chan_index)]['*'+str(pol_index)]['minor']['value'])+ ' bpa: '+str(beam['beams']['*'+str(chan_index)]['*'+str(pol_index)]['positionangle']['value']), origin="analysis") # cleanup - delete newmodel, newmodel.flat etc # flat kept by user request CAS-5509 # if os.path.exists(imagename+".image.flat"): # shutil.rmtree(imagename+".image.flat") if os.path.exists(imagename+".residual.flat"): shutil.rmtree(imagename+".residual.flat") # .flux.pbcoverage is nessesary for feather. #if os.path.exists(imagename+".flux.pbcoverage"): # shutil.rmtree(imagename+".flux.pbcoverage") absdiff = imagename + '.absdiff' if os.path.exists(absdiff): shutil.rmtree(absdiff) absconv = imagename + '.absconv' if os.path.exists(absconv): shutil.rmtree(absconv) # if os.path.exists(imagename+".diff"): # shutil.rmtree(imagename+".diff") if os.path.exists(imagename+".quick.psf") and os.path.exists(imagename+".psf"): shutil.rmtree(imagename+".quick.psf") finalize_tools() if myutil.isreport(): myutil.closereport() finally: finalize_tools() def finalize_tools(): if ia.isopen(): ia.close() im.close() tb.close() ### A helper function to get concat weight def get_concatweights(mslist): if type(mslist) == str: mslist = [mslist] if not is_array_type(mslist): raise TypeError("get_concatweights: input should be a list of MS names") if len(mslist) < 2 and os.path.exists(mslist[0]): return (1.) if not os.path.exists(mslist[0]): raise ValueError("Could not find input file, %s" % mslist[0]) # Get integration to compare. (mytb, mymsmd) = gentools(['tb', 'msmd']) try: mytb.open(mslist[0]) tint0 = mytb.getcell('INTERVAL',0) finally: mytb.close() # Get antenna diameter of the first MS. try: mytb.open(mslist[0]+'/ANTENNA') diam0 = mytb.getcell('DISH_DIAMETER', 0) finally: mytb.close() weights = [] for thems in mslist: if not os.path.exists(thems): raise ValueError("Could not find input file, %s" % thems) # MS check - assumes that all antennas, spws, and data are used # Check the number of spw try: mytb.open(thems+'/SPECTRAL_WINDOW') if mytb.nrows() > 1: casalog.post("simanalyze can not calculate concat weight of MSes with multiple spectral windows in an MS. Please concatenate them manually.", priority="ERROR") finally: mytb.close() # Check antenna diameters in MS try: mytb.open(thems+'/ANTENNA') diams = mytb.getcol('DISH_DIAMETER') finally: mytb.close() for diam in diams: if (diam != diams[0]): casalog.post("simanalyze can not calculate concat weight of MSes with multiple antenna diameters in an MS. Please concatenate them manually.", priority="ERROR") # Check integrations in MS try: mytb.open(thems) integs = mytb.getcol('INTERVAL') finally: mytb.close() for tint in integs: if (tint != integs[0]): casalog.post("simanalyze can not calculate concat weight of MSes with multiple integration times in an MS. Please concatenate them manually.", priority="ERROR") # Check integration is equal to tint0 if integs[0] != tint0: casalog.post("simanalyze can not calculate concat weight of MSes with different integration times. Please concatenate them manually.", priority="ERROR") del integs # Now calculate weight weights.append((diams[0]/diam0)**2) # end of MS loop if len(mslist) != len(weights): raise RuntimeError("Could not calculate weight of some MSes.") return weights