def run(self): """ Main program for OverlapIntegral """ dt = utils.Dtime("OverlapIntegral") self._summary = {} chans =self.getkey("chans") cmap = self.getkey("cmap") normalize = self.getkey("normalize") doCross = True doCross = False myplot = APlot(pmode=self._plot_mode,ptype=self._plot_type,abspath=self.dir()) dt.tag("start") n = len(self._bdp_in) if n==0: raise Exception,"Need at least 1 input Image_BDP " logging.debug("Processing %d input maps" % n) data = range(n) # array in which each element is placeholder for the data mdata = range(n) # array to hold the max in each array summarytable = admit.util.Table() summarytable.columns = ["File name","Spectral Line ID"] summarytable.description = "Images used in Overlap Integral" for i in range(n): bdpfile = self._bdp_in[i].getimagefile(bt.CASA) if hasattr(self._bdp_in[i],"line"): line = getattr(self._bdp_in[i],"line") logging.info("Map %d: %s" % (i,line.uid)) lineid = line.uid else: lineid="no line" data[i] = casautil.getdata(self.dir(bdpfile),chans) mdata[i] = data[i].max() logging.info("shape[%d] = %s with %d good data" % (i,data[i].shape,data[i].count())) if i==0: shape = data[i].shape outfile = self.mkext("testOI","oi") else: if shape != data[i].shape: raise Exception,"Shapes not the same, cannot overlap them" # collect the file names and line identifications for the summary summarytable.addRow([bdpfile,lineid]) logging.regression("OI: %s" % str(mdata)) if len(shape)>2 and shape[2] > 1: raise Exception,"Cannot handle 3D cubes yet" if doCross: # debug: produce all cross-corr's of the N input maps (expensive!) crossn(data, myplot) dt.tag("crossn") b1 = Image_BDP(outfile) self.addoutput(b1) b1.setkey("image", Image(images={bt.CASA:outfile})) dt.tag("open") useClone = True # to create an output dataset, clone the first input, but using the chans=ch0~ch1 # e.g. using imsubimage(infile,outfile=,chans= if len(chans) > 0: # ia.regrid() doesn't have the chans= taskinit.ia.open(self.dir(self._bdp_in[0].getimagefile(bt.CASA))) taskinit.ia.regrid(outfile=self.dir(outfile)) taskinit.ia.close() else: # 2D for now if not useClone: logging.info("OVERLAP out=%s" % outfile) taskinit.ia.fromimage(infile=self.dir(self._bdp_in[0].getimagefile(bt.CASA)), outfile=self.dir(outfile), overwrite=True) taskinit.ia.close() dt.tag("fromimage") if n==3: # RGB logging.info("RGB mode") out = rgb1(data[0],data[1],data[2], normalize) else: # simple sum out = data[0] for i in range(1,n): out = out + data[i] if useClone: casautil.putdata_raw(self.dir(outfile),out,clone=self.dir(self._bdp_in[0].getimagefile(bt.CASA))) else: taskinit.ia.open(self.dir(outfile)) s1 = taskinit.ia.shape() s0 = [0,0,0,0] r1 = taskinit.rg.box(blc=s0,trc=s1) pixeldata = out.data pixelmask = ~out.mask taskinit.ia.putregion(pixels=pixeldata, pixelmask=pixelmask, region=r1) taskinit.ia.close() title = "OverlapIntegral" pdata = np.rot90(out.squeeze()) logging.info("PDATA: %s" % str(pdata.shape)) myplot.map1(pdata,title,"testOI",thumbnail=True,cmap=cmap) #----------------------------- # Populate summary information #----------------------------- taskargs = "chans=%s cmap=%s" % (chans, cmap) imname = "" thumbnailname = "" # uncomment when ready. imname = myplot.getFigure(figno=myplot.figno,relative=True) thumbnailname = myplot.getThumbnail(figno=myplot.figno,relative=True) #@todo fill in caption with more info - line names, etc. caption = "Need descriptive caption here" summaryinfo = [summarytable.serialize(),imname,thumbnailname,caption] self._summary["overlap"] = SummaryEntry(summaryinfo, "OverlapIntegral_AT", self.id(True),taskargs) #----------------------------- dt.tag("done") dt.end()
def run(self): """ The run method creates the BDP Parameters ---------- None Returns ------- None """ dt = utils.Dtime("SFind2D") # tagging time self._summary = {} # get key words that user input nsigma = self.getkey("numsigma") sigma = self.getkey("sigma") region = self.getkey("region") robust = self.getkey("robust") snmax = self.getkey("snmax") ds9 = True # writes a "ds9.reg" file mpl = True # aplot.map1() plot dynlog = 20.0 # above this value of dyn range finder chart is log I-scaled bpatch = True # patch units to Jy/beam for ia.findsources() # get the input casa image from bdp[0] bdpin = self._bdp_in[0] infile = bdpin.getimagefile(bt.CASA) if mpl: data = np.flipud(np.rot90(casautil.getdata(self.dir(infile)).data)) # check if there is a 2nd image (which will be a PB) for i in range(len(self._bdp_in)): print 'BDP',i,type(self._bdp_in[i]) if self._bdp_in[2] != None: bdpin_pb = self._bdp_in[1] bdpin_cst = self._bdp_in[2] print "Need to process PB" else: bdpin_pb = None bdpin_cst = self._bdp_in[1] print "No PB given" # get the output bdp basename slbase = self.mkext(infile,'sl') # make sure it's a 2D map if not casautil.mapdim(self.dir(infile),2): raise Exception,"Input map dimension not 2: %s" % infile # arguments for imstat call if required args = {"imagename" : self.dir(infile)} if region != "": args["region"] = region dt.tag("start") # The following code sets the sigma level for searching for sources using # the sigma and snmax keyword as appropriate # if no CubeStats BDP was given and no sigma was specified: # find a noise level via casa.imstat() # if a CubeStat_BDP is given get it from there. if bdpin_cst == None: # get statistics from input image with imstat because no CubeStat_BDP stat = casa.imstat(**args) dmin = float(stat["min"][0]) # these would be wrong if robust were used already dmax = float(stat["max"][0]) args.update(casautil.parse_robust(robust)) # only now add robust keywords for the sigma stat = casa.imstat(**args) if sigma <= 0.0 : sigma = float(stat["sigma"][0]) dt.tag("imstat") else: # get statistics from CubeStat_BDP sigma = bdpin_cst.get("sigma") dmin = bdpin_cst.get("minval") dmax = bdpin_cst.get("maxval") self.setkey("sigma",sigma) # calculate cutoff based either on RMS or dynamic range limitation drange = dmax/(nsigma*sigma) if snmax < 0.0 : snmax = drange if drange > snmax : cutoff = 1.0/snmax else: cutoff = 1.0/drange logging.info("sigma, dmin, dmax, snmax, cutoff %g %g %g %g %g" % (sigma, dmin, dmax, snmax, cutoff)) # define arguments for call to findsources args2 = {"cutoff" : cutoff} args2["nmax"] = 30 if region != "" : args2["region"] = region #args2["mask"] = "" args2["point"] = False args2["width"] = 5 args2["negfind"] = False # set-up for SourceList_BDP slbdp = SourceList_BDP(slbase) # connect to casa image and call casa ia.findsources tool taskinit.ia.open(self.dir(infile)) # findsources() cannot deal with 'Jy/beam.km/s' ??? # so for the duration of findsources() we patch it bunit = taskinit.ia.brightnessunit() if bpatch and bunit != 'Jy/beam': logging.warning("Temporarely patching your %s units to Jy/beam for ia.findsources()" % bunit) taskinit.ia.setbrightnessunit('Jy/beam') else: bpatch = False atab = taskinit.ia.findsources(**args2) if bpatch: taskinit.ia.setbrightnessunit(bunit) taskargs = "nsigma=%4.1f sigma=%g region=%s robust=%s snmax=%5.1f" % (nsigma,sigma,str(region),str(robust),snmax) dt.tag("findsources") nsources = atab["nelements"] xtab = [] ytab = [] logscale = False sumflux = 0.0 if nsources > 0: # @TODO: Why are Xpix, YPix not stored in the table? # -> PJT: I left them out since they are connected to an image which may not be available here # but we should store the frequency of the observation here for later bandmerging logging.debug("%s" % str(atab['component0']['shape'])) logging.info("Right Ascen. Declination X(pix) Y(pix) Peak Flux Major Minor PA SNR") funits = atab['component0']['flux']['unit'] if atab['component0']['shape'].has_key('majoraxis'): sunits = atab['component0']['shape']['majoraxis']['unit'] aunits = atab['component0']['shape']['positionangle']['unit'] else: sunits = "n/a" aunits = "n/a" punits = taskinit.ia.summary()['unit'] logging.info(" %s %s %s %s %s" % (punits,funits,sunits,sunits,aunits)) # # @todo future improvement is to look at image coordinates and control output appropriately # if ds9: # @todo variable name regname = self.mkext(infile,'ds9.reg') fp9 = open(self.dir(regname),"w!") for i in range(nsources): c = "component%d" % i name = "%d" % (i+1) r = atab[c]['shape']['direction']['m0']['value'] d = atab[c]['shape']['direction']['m1']['value'] pixel = taskinit.ia.topixel([r,d]) xpos = pixel['numeric'][0] ypos = pixel['numeric'][1] rd = taskinit.ia.toworld([xpos,ypos],'s') ra = rd['string'][0][:12] dec = rd['string'][1][:12] flux = atab[c]['flux']['value'][0] sumflux = sumflux + flux if atab[c]['shape'].has_key('majoraxis'): smajor = atab[c]['shape']['majoraxis']['value'] sminor = atab[c]['shape']['minoraxis']['value'] sangle = atab[c]['shape']['positionangle']['value'] else: smajor = 0.0 sminor = 0.0 sangle = 0.0 peakstr = taskinit.ia.pixelvalue([xpos,ypos,0,0]) if len(peakstr) == 0: logging.warning("Problem with source %d @ %d,%d" % (i,xpos,ypos)) continue peakf = peakstr['value']['value'] snr = peakf/sigma if snr > dynlog: logscale = True logging.info("%s %s %8.2f %8.2f %10.3g %10.3g %7.3f %7.3f %6.1f %6.1f" % (ra,dec,xpos,ypos,peakf,flux,smajor,sminor,sangle,snr)) xtab.append(xpos) ytab.append(ypos) slbdp.addRow([name,ra,dec,flux,peakf,smajor,sminor,sangle]) if ds9: ras = ra des = dec.replace('.',':',2) msg = 'ellipse(%s,%s,%g",%g",%g) # text={%s}' % (ras,des,smajor,sminor,sangle+90.0,i+1) fp9.write("%s\n" % msg) if ds9: fp9.close() logging.info("Wrote ds9.reg") dt.tag("table") logging.regression("CONTFLUX: %d %g" % (nsources,sumflux)) summary = taskinit.ia.summary() beammaj = summary['restoringbeam']['major']['value'] beammin = summary['restoringbeam']['minor']['value'] beamunit = summary['restoringbeam']['minor']['unit'] beamang = summary['restoringbeam']['positionangle']['value'] angunit = summary['restoringbeam']['positionangle']['unit'] # @todo add to table comments? logging.info(" Fitted Gaussian size; NOT deconvolved source size.") logging.info(" Restoring Beam: Major axis: %10.3g %s , Minor axis: %10.3g %s , PA: %5.1f %s" % (beammaj, beamunit, beammin, beamunit, beamang, angunit)) # form into a xml table # output is a table_bdp self.addoutput(slbdp) # instantiate a plotter for all plots made herein myplot = APlot(ptype=self._plot_type,pmode=self._plot_mode,abspath=self.dir()) # make output png with circles marking sources found if mpl: circles=[] nx = data.shape[1] # data[] array was already flipud(rot90)'d ny = data.shape[0] # for (x,y) in zip(xtab,ytab): circles.append([x,y,1]) # @todo variable name if logscale: logging.warning("LogScaling applied") data = data/sigma data = np.where(data<0,-np.log10(1-data),+np.log10(1+data)) title = "SFind2D: %d sources" % nsources myplot.map1(data,title,slbase,thumbnail=True,circles=circles) #--------------------------------------------------------- # Get the figure and thumbmail names and create a caption #--------------------------------------------------------- imname = myplot.getFigure(figno=myplot.figno,relative=True) thumbnailname = myplot.getThumbnail(figno=myplot.figno,relative=True) caption = "Image of input map with sources found by SFind2D overlayed in green." slbdp.table.description="Table of source locations and sizes (not deconvolved)" #--------------------------------------------------------- # Add finder image to the BDP #--------------------------------------------------------- image = Image(images={bt.PNG: imname}, thumbnail=thumbnailname, thumbnailtype=bt.PNG, description=caption) slbdp.image.addimage(image, "finderimage") #------------------------------------------------------------- # Create the summary entry for the table and image #------------------------------------------------------------- self._summary["sources"] = SummaryEntry([slbdp.table.serialize(), slbdp.image.serialize()], "SFind2D_AT", self.id(True), taskargs) dt.tag("done") dt.end()
class PVCorr_AT(AT): """PV correllation in a PVSlice map. PVCorr_AT computes a cross-correlation of a feature in a PVSlice with the whole PVSlice, looking for repeated patterns to detect spectral lines. Much like the output from CubeStats_AT and CubeSpectrum_AT, this table can then be given to LineID_AT to attempt a line identification. See also :ref:`PVCorr-AT-Design` for the design document. **Keywords** **numsigma**: float Minimum intensity, in terms of sigma, above which a selected portion of the spectrum will be used for cross-correlation. Default: 3.0. **range**: integer list If given, it has to be a list with 2 channel numbers, the first and last channel (0-based channels) of the range which to use for the cross-correlation. Default: []. **nchan**: integer The number of channels (in case range= was not used) that defines the line. The line is centers on the strongest point in the input PV-map. If 0 is given, it will watershed down from the strongest line. Default: 0. **Input BDPs** **PVSlice_BDP**: count: 1 Input PV Slice. As created with e.g. PVSlice_AT. **CubeStats_BDP**: count: 1 Input cube statistics from which the RMS is taken. **Output BDPs** **PVCorr_BDP**: count: 1 Output table. """ def __init__(self,**keyval): keys = {"numsigma" : 3.0, # N-sigma "range" : [], # optional channel range "nchan" : 0, # number of channels around the channel where the peak is } AT.__init__(self,keys,keyval) self._version = "1.0.1" self.set_bdp_in([(Image_BDP,1,bt.REQUIRED), # @todo optional 2nd PVSlice can be used to draw the template from (CubeStats_BDP,1,bt.REQUIRED)]) self.set_bdp_out([(PVCorr_BDP,1)]) def summary(self): """Returns the summary dictionary from the AT, for merging into the ADMIT Summary object. PVCorr_AT adds the following to ADMIT summary: .. table:: :class: borderless +----------+----------+-----------------------------------+ | Key | type | Description | +==========+==========+===================================+ | pvcorr | list | correlation diagram | +----------+----------+-----------------------------------+ Parameters ---------- None Returns ------- dict Dictionary of SummaryEntry """ if hasattr(self,"_summary"): return self._summary else: return {} def run(self): dt = utils.Dtime("PVCorr") self._summary = {} numsigma = self.getkey("numsigma") mode = 1 # PV corr mode (1,2,3) normalize = True # normalize = False b1 = self._bdp_in[0] # PVSlice_BDP fin = b1.getimagefile(bt.CASA) # CASA image data = casautil.getdata_raw(self.dir(fin)) # grab the data as a numpy array self.myplot = APlot(ptype=self._plot_type,pmode=self._plot_mode,abspath=self.dir()) #print 'DATA[0,0]:',data[0,0] #print 'pv shape: ',data.shape npos = data.shape[0] nvel = data.shape[1] dt.tag("getdata") b2 = self._bdp_in[1] # CubeStats_BDP sigma = b2.sigma # global sigma in the cube cutoff = numsigma * sigma freq = b2.table.getColumnByName("frequency") chans = self.getkey("range") # range of channels, if used if len(chans) > 0: if len(chans) != 2: logging.fatal("range=%s" % chans) raise Exception,"range= needs two values, left and right (inclusive) channel" ch0 = chans[0] ch1 = chans[1] else: nchan = self.getkey("nchan") imstat0 = casa.imstat(self.dir(fin)) # @todo can use data[] now xmaxpos = imstat0['maxpos'][0] ymaxpos = imstat0['maxpos'][1] logging.info("MAXPOS-VEL %s %g" % (str(imstat0['maxpos']),imstat0['max'][0])) if nchan > 0: # expand around it, later ch0,ch1 will be checked for running off the edge ch0 = ymaxpos - nchan/2 ch1 = ymaxpos + nchan/2 else: # watershed down to find ch0 and ch1 ? # this doesn't work well in crowded areas ch0 = ymaxpos ch1 = ymaxpos spmax = data.max(axis=0) k = spmax.argmax() n = len(spmax) logging.debug('spmax %s %d %g' % (str(spmax.shape),k,spmax[k])) # find lower cutoff for i in range(n): ch0 = ymaxpos - i if ch0<0: break if spmax[ch0] < cutoff: break ch0 = ch0 + 1 # find higher cutoff for i in range(n): ch1 = ymaxpos + i if ch1==n: break if spmax[ch1] < cutoff: break ch1 = ch1 - 1 dt.tag("imstat") bdp_name = self.mkext(fin,"pvc") # output PVCorr_BDP b3 = PVCorr_BDP(bdp_name) self.addoutput(b3) if ch0<0 or ch1>=nvel: # this probably only happens to small cubes (problematic for PVCorr) # or when the strongest line is really close to the edge of the band # (which is probably ok) if ch0<0 and ch1>=nvel: logging.warning("Serious issues with the size of this cube") if ch0<0: logging.warning("Resetting ch0 edge to 0") ch0=0 if ch1>=nvel: ch1=nvel-1 logging.warning("Resetting ch1 edge to the maximum") if ch0 > ch1: logging.warning("Sanity swapping ch0,1 due to likely noisy data") ch0,ch1 = ch1,ch0 if mode == 1: out,rms = mode1(data, ch0, ch1, cutoff, normalize) corr = out elif mode == 2: out,rms = mode2(data, ch0, ch1, cutoff) # slower 2D version corr = out[npos/2,:] # center cut, but could also try feature detection elif mode == 3: out,rms = self.mode3(data, ch0, ch1, cutoff) # Doug's faster 2D version # get the peak of each column corr = np.amax(out,axis=0) # print "PVCORR SHAPE ",corr.shape," mode", mode if len(corr) > 0: # print "SHAPE out:",out.shape,corr.shape,npos/2 ch = range(len(corr)) if len(corr) != len(freq): logging.fatal("ch (%d) and freq (%d) do not have same size" % (len(corr),len(freq))) raise Exception,"ch and freq do not have same dimension" dt.tag("mode") labels = ["channel", "frequency", "pvcorr"] units = ["number", "GHz", "N/A"] data = (ch, freq, corr) table = Table(columns=labels,units=units,data=np.column_stack(data)) else: # still construct a table, but with no rows labels = ["channel", "frequency", "pvcorr"] units = ["number", "GHz", "N/A"] table = Table(columns=labels,units=units) b3.setkey("table",table) b3.setkey("sigma",float(rms)) dt.tag("table") if len(corr) > 0: table.exportTable(self.dir("testPVCorr.tab"),cols=['frequency','pvcorr']) test_single(ch,freq,corr) logging.regression("PVC: %f %f" % (corr.min(),corr.max())) title = 'PVCorr mode=%d [%d,%d] %g' % (mode,ch0,ch1,cutoff) x = ch xlab = 'Channel' y = [corr] ylab = 'PV Correlation' p1 = "%s_%d" % (bdp_name,0) segp = [] segp.append( [0,len(ch),0.0,0.0] ) segp.append( [0,len(ch),3.0*rms, 3.0*rms] ) # @todo: in principle we know with given noise and size of box, what the sigma in pvcorr should be self.myplot.plotter(x,y,title,figname=p1,xlab=xlab,ylab=ylab,segments=segp, thumbnail=True) #out1 = np.rot90 (data.reshape((nvel,npos)) ) if mode > 1: self.myplot.map1(data=out,title="testing PVCorr_AT: mode%d"%mode,figname='testPVCorr', thumbnail=True) taskargs = "numsigma=%.1f range=[%d,%d]" % (numsigma,ch0,ch1) caption = "Position-velocity correlation plot" thumbname = self.myplot.getThumbnail(figno=self.myplot.figno,relative=True) figname = self.myplot.getFigure(figno=self.myplot.figno,relative=True) image = Image(images={bt.PNG: figname}, thumbnail=thumbname, thumbnailtype=bt.PNG, description=caption) b3.image.addimage(image, "pvcorr") self._summary["pvcorr"] = SummaryEntry([figname,thumbname,caption,fin],"PVCorr_AT",self.id(True),taskargs) else: self._summary["pvcorr"] = None logging.warning("No summary") logging.regression("PVC: -1") dt.tag("done") dt.end() def mode3(self, data, v0, v1, dmin=0.0): """ v0..v1 (both inclusive) are channel selections threshold on dmin @todo the frequency axis is not properly calibrated here @todo a full 2D is slow, we only need the 1D version """ print "PVCorr mode3: v0,1=",v0,v1 smin = data.min() #s = data[v0:v1+1,:] s = data[:,v0:v1+1] if dmin==0.0: logging.warning("Using all data in crosscorr") f = s else: f = np.where(s>dmin,s,0) # find out where the zeros are temp = np.amax(f,axis=1) nz = np.nonzero(temp) # trim the kernel in the y direction, removing rows that are all 0.0 f = f[nz[0][0]:nz[0][-1],:] f0 = np.where(s>smin,1,0) f1 = np.where(s>dmin,1,0) fmax = f.max() print "PVCorr mode3:",f1.sum(),'/',f0.sum(),'min/max',smin,fmax out = scipy.signal.correlate2d(data,f,mode='same') self.myplot.map1(data=f,title="PVCorr 2D Kernel",figname='PVCorrKernel', thumbnail=True) print 'PVCorr min/max:',out.min(),out.max() n1,m1,s1,n2,m2,s2 = stats.mystats(out.flatten()) print "PVCorr stats", n1,m1,s1,n2,m2,s2 rms_est = s2/np.sqrt(f1.sum()) return out,rms_est
def run(self): """Runs the task. Parameters ---------- None Returns ------- None """ self._summary = {} pvslicesummary = [] sumslicetype = 'slice' sliceargs = [] dt = utils.Dtime("PVSlice") # import here, otherwise sphinx cannot parse from impv import impv from imsmooth import imsmooth pvslice = self.getkey( 'slice') # x_s,y_s,x_e,y_e (start and end of line) pvslit = self.getkey( 'slit') # x_c,y_c,len,pa (center, length and PA of line) # BDP's used : # b10 = input BDP # b11 = input BDP (moment) # b12 = input BDP (new style cubestats w/ maxpos) # b2 = output BDP b10 = self._bdp_in[0] # input SpwCube fin = b10.getimagefile(bt.CASA) # input name b11 = self._bdp_in[1] # b12 = self._bdp_in[2] clip = self.getkey('clip') # clipping to data for Moment-of-Inertia gamma = self.getkey( 'gamma') # gamma factor to data for Moment-of-Inertia if b11 != None and len(pvslice) == 0 and len(pvslit) == 0: # if a map (e.g. cubesum ) given, and no slice/slit, get a best pvslice from that (pvslice, clip) = map_to_slit(self.dir(b11.getimagefile(bt.CASA)), clip=clip, gamma=gamma) elif b12 != None and len(pvslice) == 0 and len(pvslit) == 0: # PPP doesn't seem to work too well yet logging.debug("testing new slice computation from a PPP") max = b12.table.getColumnByName("max") maxposx = b12.table.getColumnByName("maxposx") maxposy = b12.table.getColumnByName("maxposy") if maxposx == None: raise Exception, "PPP was not enabled in your CubeStats" (pvslice, clip) = tab_to_slit([maxposx, maxposy, max], clip=clip, gamma=gamma) sliceargs = deepcopy(pvslice) if len(sliceargs) == 0: logging.warning("no slice for plot yet") # ugh, this puts single quotes around the numbers formattedslice = str(["%.2f" % a for a in sliceargs]) taskargs = "slice=" + formattedslice dt.tag("slice") pvname = self.mkext(fin, 'pv') # output image name b2 = PVSlice_BDP(pvname) self.addoutput(b2) width = self.getkey( 'width' ) # @todo also: "4arcsec" (can't work since it's a single keyword) if len(pvslice) == 4: start = pvslice[: 2] # @todo also allow: ["14h20m20.5s","-30d45m25.4s"] end = pvslice[2:] impv(self.dir(fin), self.dir(pvname), "coords", start=start, end=end, width=width, overwrite=True) elif len(pvslit) == 4: sumslicetype = 'slit' sliceargs = deepcopy(pvslit) formattedslice = str(["%.2f" % a for a in sliceargs]) taskargs = "slit=" + formattedslice # length="40arcsec" same as {"value": 40, "unit": "arcsec"}) center = pvslit[: 2] # @todo also: ["14h20m20.5s","-30d45m25.4s"]. length = pvslit[ 2] # @todo also: "40arcsec", {"value": 40, "unit": "arcsec"}) if type(pvslit[3]) is float or type(pvslit[3]) is int: pa = "%gdeg" % pvslit[3] else: pa = pvslit[3] impv(self.dir(fin), self.dir(pvname), "length", center=center, length=length, pa=pa, width=width, overwrite=True) else: raise Exception, "no valid input slit= or slice= or bad Moment_BDP input" sliceargs.append(width) taskargs = taskargs + " width=%d" % width dt.tag("impv") smooth = self.getkey('pvsmooth') if len(smooth) > 0: if len(smooth) == 1: smooth.append(smooth[0]) major = '%dpix' % smooth[0] minor = '%dpix' % smooth[1] logging.info("imsmooth PV slice: %s %s" % (major, minor)) imsmooth(self.dir(pvname), outfile=self.dir(pvname) + '.smooth', kernel='boxcar', major=major, minor=minor) dt.tag("imsmooth") # utils.rename(self.dir(pvname)+'.smooth',self.dir(pvname)) # @todo we will keep the smooth PVslice for inspection, no further flow work # get some statistics data = casautil.getdata_raw(self.dir(pvname)) rpix = stats.robust(data.flatten()) r_mean = rpix.mean() r_std = rpix.std() r_max = rpix.max() logging.info("PV stats: mean/std/max %f %f %f" % (r_mean, r_std, r_max)) logging.regression("PVSLICE: %f %f %f" % (r_mean, r_std, r_max)) myplot = APlot(ptype=self._plot_type, pmode=self._plot_mode, abspath=self.dir()) # hack to get a slice on a mom0map # @todo if pmode is not png, can viewer handle this? figname = pvname + ".png" slicename = self.dir(figname) overlay = pvname + "_overlay" if b11 != None: f11 = b11.getimagefile(bt.CASA) tb = taskinit.tbtool() tb.open(self.dir(f11)) data = tb.getcol('map') nx = data.shape[0] ny = data.shape[1] tb.close() d1 = np.flipud(np.rot90(data.reshape((nx, ny)))) if len(pvslice) == 4: segm = [[pvslice[0], pvslice[2], pvslice[1], pvslice[3]]] pa = np.arctan2(pvslice[2] - pvslice[0], pvslice[1] - pvslice[3]) * 180.0 / np.pi title = "PV Slice location : slice PA=%.1f" % pa xcen = (pvslice[0] + pvslice[2]) / 2.0 ycen = (pvslice[1] + pvslice[3]) / 2.0 elif len(pvslit) == 4: # can only do this now if using pixel coordinates xcen = pvslit[0] ycen = pvslit[1] slen = pvslit[2] pard = pvslit[3] * np.pi / 180.0 cosp = np.cos(pard) sinp = np.sin(pard) halflen = 0.5 * slen segm = [[ xcen - halflen * sinp, xcen + halflen * sinp, ycen + halflen * cosp, ycen - halflen * cosp ]] pa = pvslit[3] title = "PV Slice location : slit PA=%g" % pa else: # bogus, some error in pvslice logging.warning("bogus segm since pvslice=%s" % str(pvslice)) segm = [[10, 20, 10, 20]] pa = -999.999 title = "PV Slice location - bad PA" logging.info("MAP1 segm %s %s" % (str(segm), str(pvslice))) if d1.max() < clip: logging.warning("datamax=%g, clip=%g" % (d1.max(), clip)) title = title + ' (no signal over %g?)' % clip myplot.map1(d1, title, overlay, segments=segm, thumbnail=True, zoom=self.getkey("zoom"), star=[xcen, ycen]) else: myplot.map1(d1, title, overlay, segments=segm, range=[clip], thumbnail=True, zoom=self.getkey("zoom"), star=[xcen, ycen]) dt.tag("plot") overlayname = myplot.getFigure(figno=myplot.figno, relative=True) overlaythumbname = myplot.getThumbnail(figno=myplot.figno, relative=True) Qover = True else: Qover = False implot = ImPlot(pmode=self._plot_mode, ptype=self._plot_type, abspath=self.dir()) implot.plotter(rasterfile=pvname, figname=pvname, colorwedge=True) thumbname = implot.getThumbnail(figno=implot.figno, relative=True) figname = implot.getFigure(figno=implot.figno, relative=True) if False: # debug: # # @todo tmp1 is ok, tmp2 is not displaying the whole thing # use casa_imview, not casa.imview - if this is enabled. # old style: viewer() seems to plot full image, but imview() wants square pixels? casa.viewer(infile=self.dir(pvname), outfile=self.dir('tmp1.pv.png'), gui=False, outformat="png") casa.imview(raster={ 'file': self.dir(pvname), 'colorwedge': True, 'scaling': -1 }, axes={'y': 'Declination'}, out=self.dir('tmp2.pv.png')) # # -> this one works, axes= should be correct # imview(raster={'file':'x.pv', 'colorwedge' : True, 'scaling':-1},axes={'y':'Frequency'}) # # @TODO big fixme, we're going to reuse 'tmp1.pv.png' because implot give a broken view figname = 'tmp1.pv.png' # @todo technically we don't know what map it was overlay'd on.... CubeSum/Moment0 overlaycaption = "Location of position-velocity slice overlaid on a CubeSum map" pvcaption = "Position-velocity diagram through emission centroid" pvimage = Image(images={ bt.CASA: pvname, bt.PNG: figname }, thumbnail=thumbname, thumbnailtype=bt.PNG, description=pvcaption) b2.setkey("image", pvimage) b2.setkey("mean", float(r_mean)) b2.setkey("sigma", float(r_std)) if Qover: thispvsummary = [ sumslicetype, sliceargs, figname, thumbname, pvcaption, overlayname, overlaythumbname, overlaycaption, pvname, fin ] else: thispvsummary = [ sumslicetype, sliceargs, figname, thumbname, pvcaption, pvname, fin ] # Yes, this is a nested list. Against the day when PVSLICE can # compute multiple slices per map. pvslicesummary.append(thispvsummary) self._summary["pvslices"] = SummaryEntry(pvslicesummary, "PVSlice_AT", self.id(True), taskargs) dt.tag("done") dt.end()