def _calc_PB(self, antenna): """ Calculate the primary beam size of antenna, using dish diamenter and rest frequency Average antenna diamter and reference frequency are adopted for calculation. The input argument should be a list of antenna IDs. """ casalog.post("Calculating Pirimary beam size:") # CAS-5410 Use private tools inside task scripts my_qa = qatool() pb_factor = 1.175 # Reference frequency ref_freq = self.restfreq if type(ref_freq) in [float, numpy.float64]: ref_freq = my_qa.tos(my_qa.quantity(ref_freq, 'Hz')) if not my_qa.compare(ref_freq, 'Hz'): msg = "Could not get the reference frequency. " + \ "Your data does not seem to have valid one in selected field.\n" + \ "PB is not calculated.\n" + \ "Please set restreq or cell manually to generate an image." raise Exception, msg # Antenna diameter antdiam_ave = self._get_average_antenna_diameter(antenna) # Calculate PB wave_length = 0.2997924 / my_qa.convert(my_qa.quantity(ref_freq),'GHz')['value'] D_m = my_qa.convert(antdiam_ave, 'm')['value'] lambda_D = wave_length / D_m * 3600. * 180 / numpy.pi PB = my_qa.quantity(pb_factor*lambda_D, 'arcsec') # Summary casalog.post("- Antenna diameter: %s m" % D_m) casalog.post("- Reference Frequency: %s" % ref_freq) casalog.post("PB size = %5.3f * lambda/D = %s" % (pb_factor, my_qa.tos(PB))) return PB
def execute(self): # CAS-5410 Use private tools inside task scripts qa = qatool() scan = self.worker.scan if self.kernel == 'regrid': if not qa.isquantity(self.chanwidth): errstr = "Invalid quantity chanwidth " + self.chanwidth raise Exception, errstr qchw = qa.quantity(self.chanwidth) oldUnit = scan.get_unit() if qchw['unit'] in ("", "channel", "pixel"): scan.set_unit("channel") elif qa.compare(self.chanwidth,"1Hz") or \ qa.compare(self.chanwidth,"1m/s"): scan.set_unit(qchw['unit']) else: errstr = "Invalid dimension of quantity chanwidth " + self.chanwidth raise Exception, errstr casalog.post("Regridding spectra in width " + self.chanwidth) scan.regrid_channel(width=qchw['value'], plot=self.verify, insitu=True) scan.set_unit(oldUnit) else: casalog.post("Smoothing spectra with kernel " + self.kernel) scan.smooth(kernel=self.kernel, width=self.kwidth, plot=self.verify, insitu=True)
def __to_arcsec(self, angle): """convert angle to arcsec and return the value without unit.""" my_qa = qatool() if my_qa.isangle(angle): return my_qa.getvalue(my_qa.convert(angle, "arcsec"))[0] elif my_qa.getunit(angle)=='': return float(angle) else: raise ValueError, "Invalid angle: %s" % (str(angle))
def ssobjangdiam(srcName, epoch, ephemdata="",unit=""): """ srcName: solar system object name (case insensitive) epoch: in string format (e.g. "2015/09/01:12:00:00") ephemdata: ephemeris data (default = "", look up the standard ~/alma/JPL_Horizons in the data repo unit: unit for the output ang. diam. """ defaultDataPath = os.getenv("CASAPATH").split()[0] + "/data/ephemerides/JPL-Horizons/" me = taskinit.metool() qa = taskinit.qatool() if ephemdata!="": datapath = ephemdata else: mjd = me.epoch("utc",epoch)['m0']['value'] datapath = findEphemTable(defaultDataPath, srcName, mjd) me.framecomet(datapath) me.doframe(me.epoch("utc", epoch)) me.doframe(me.observatory("ALMA")) angdiamrad= me.cometangdiam() if unit=="" or unit=="rad": angdiam = angdiamrad else: angdiam = qa.convert(qa.quantity(angdiamrad), unit) return angdiam
def execute(self): # CAS-5410 Use private tools inside task scripts qa = qatool() scan = self.worker.scan if self.kernel == 'regrid': if not qa.isquantity(self.chanwidth): errstr = "Invalid quantity chanwidth "+self.chanwidth raise Exception, errstr qchw = qa.quantity(self.chanwidth) oldUnit = scan.get_unit() if qchw['unit'] in ("", "channel", "pixel"): scan.set_unit("channel") elif qa.compare(self.chanwidth,"1Hz") or \ qa.compare(self.chanwidth,"1m/s"): scan.set_unit(qchw['unit']) else: errstr = "Invalid dimension of quantity chanwidth "+self.chanwidth raise Exception, errstr casalog.post( "Regridding spectra in width "+self.chanwidth ) scan.regrid_channel(width=qchw['value'],plot=self.verify,insitu=True) scan.set_unit(oldUnit) else: casalog.post( "Smoothing spectra with kernel "+self.kernel ) scan.smooth(kernel=self.kernel,width=self.kwidth,plot=self.verify,insitu=True)
def _get_pointing_extent(self): ### MS selection is ignored. This is not quite right. casalog.post("Calculating map extent from pointings.") # CAS-5410 Use private tools inside task scripts my_qa = qatool() ret_dict = {} colname = self.pointingcolumn.upper() # MSs should be registered to imager if not self.is_imager_opened: raise RuntimeError('Internal error: imager should be opened here.') if self.phasecenter == "": # defaut is J2000 base_mref = 'J2000' elif isinstance(self.phasecenter, int) or self.phasecenter.isdigit(): # may be field id self.open_table(self.field_table) base_mref = self.table.getcolkeyword('PHASE_DIR', 'MEASINFO')['Ref'] self.close_table() else: # may be phasecenter is explicitly specified pattern = '^([\-\+]?[0-9.]+([eE]?-?[0-9])?)|([\-\+]?[0-9][:h][0-9][:m][0-9.]s?)|([\-\+]?[0-9][.d][0-9][.d][0-9.]s?)$' items = self.phasecenter.split() base_mref = 'J2000' for i in items: s = i.strip() if re.match(pattern, s) is None: base_mref = s break mapextent = self.imager.mapextent(ref=base_mref, movingsource=self.ephemsrcname, pointingcolumntouse=colname) if mapextent['status'] is True: qheight = my_qa.quantity(mapextent['extent'][1], 'rad') qwidth = my_qa.quantity(mapextent['extent'][0], 'rad') qcent0 = my_qa.quantity(mapextent['center'][0], 'rad') qcent1 = my_qa.quantity(mapextent['center'][1], 'rad') scenter = '%s %s %s' % (base_mref, my_qa.formxxx( qcent0, 'hms'), my_qa.formxxx(qcent1, 'dms')) casalog.post("- Pointing center: %s" % scenter) casalog.post("- Pointing extent: [%s, %s] (projected)" % (my_qa.tos(qwidth), \ my_qa.tos(qheight))) ret_dict['center'] = scenter ret_dict['width'] = qwidth ret_dict['height'] = qheight else: casalog.post( 'Failed to derive map extent from the MSs registered to the imager probably due to mising valid data.', priority='SEVERE') ret_dict['center'] = '' ret_dict['width'] = my_qa.quantity(0.0, 'rad') ret_dict['height'] = my_qa.quantity(0.0, 'rad') return ret_dict
def __to_arcsec(self, angle): """convert angle to arcsec and return the value without unit.""" my_qa = qatool() if my_qa.isangle(angle): return my_qa.getvalue(my_qa.convert(angle, "arcsec"))[0] elif my_qa.getunit(angle) == '': return float(angle) else: raise ValueError, "Invalid angle: %s" % (str(angle))
def check_unit(unit_in,valid_unit=None,default_unit=None): # CAS-5410 Use private tools inside task scripts qa = qatool() if qa.check(unit_in): return valid_unit else: casalog.post('Undefined unit: \'%s\'...ignored'%(unit_in), priority='WARN') return default_unit
def check_unit(unit_in, valid_unit=None, default_unit=None): # CAS-5410 Use private tools inside task scripts qa = qatool() if qa.check(unit_in): return valid_unit else: casalog.post('Undefined unit: \'%s\'...ignored' % (unit_in), priority='WARN') return default_unit
def _get_pointing_extent(self): ### MS selection is ignored. This is not quite right. casalog.post("Calculating map extent from pointings.") # CAS-5410 Use private tools inside task scripts my_qa = qatool() ret_dict = {} colname = self.pointingcolumn.upper() # MSs should be registered to imager if not self.is_imager_opened: raise RuntimeError('Internal error: imager should be opened here.') if self.phasecenter == "": # defaut is J2000 base_mref = 'J2000' elif isinstance(self.phasecenter, int) or self.phasecenter.isdigit(): # may be field id self.open_table(self.field_table) base_mref = self.table.getcolkeyword('PHASE_DIR', 'MEASINFO')['Ref'] self.close_table() else: # may be phasecenter is explicitly specified pattern = '^([\-\+]?[0-9.]+([eE]?-?[0-9])?)|([\-\+]?[0-9][:h][0-9][:m][0-9.]s?)|([\-\+]?[0-9][.d][0-9][.d][0-9.]s?)$' items = self.phasecenter.split() base_mref = 'J2000' for i in items: s = i.strip() if re.match(pattern, s) is None: base_mref = s break mapextent = self.imager.mapextent(ref=base_mref, movingsource=self.ephemsrcname, pointingcolumntouse=colname) if mapextent['status'] is True: qheight = my_qa.quantity(mapextent['extent'][1], 'rad') qwidth = my_qa.quantity(mapextent['extent'][0], 'rad') qcent0 = my_qa.quantity(mapextent['center'][0], 'rad') qcent1 = my_qa.quantity(mapextent['center'][1], 'rad') scenter = '%s %s %s'%(base_mref, my_qa.formxxx(qcent0, 'hms'), my_qa.formxxx(qcent1, 'dms')) casalog.post("- Pointing center: %s" % scenter) casalog.post("- Pointing extent: [%s, %s] (projected)" % (my_qa.tos(qwidth), \ my_qa.tos(qheight))) ret_dict['center'] = scenter ret_dict['width'] = qwidth ret_dict['height'] = qheight else: casalog.post('Failed to derive map extent from the MSs registered to the imager probably due to mising valid data.', priority='SEVERE') ret_dict['center'] = '' ret_dict['width'] = my_qa.quantity(0.0, 'rad') ret_dict['height'] = my_qa.quantity(0.0, 'rad') return ret_dict
def __parse_width(self, val, cell_size_arcsec): """ Convert value in unit of arcsec if val is angle, returns a float value in unit of arcsec. else the unit is assumed to be pixel and multiplied by cell_size_arcsec """ my_qa = qatool() if my_qa.isangle(val): return self.__to_arcsec(val) elif my_qa.getunit(val) in ('', 'pixel'): return my_qa.getvalue(val)*cell_size_arcsec else: raise ValueError, "Invalid width %s" % str(val)
def __get_grid_parameters(self, calc=False): # CAS-5410 Use private tools inside task scripts qa = qatool() (nx,ny) = self.__get_mapsize() mapcenter = sdutil.get_map_center(self.center) (cellx,celly) = sdutil.get_cellx_celly(self.cell) if calc and \ ((mapcenter.split() != 3) or not qa.compare(cellx, "rad")): #(mapcenter,cellx,celly) = self.__calc_center_and_cell(mapcenter, cellx, celly) (mapcenter,cellx,celly) = self.__get_center_and_cell(nx, ny, mapcenter, cellx, celly) return (nx,ny,cellx,celly,mapcenter)
def set_antenna(self, diam, blockage="0.0m", taper=10): """ set parameters to construct antenna beam antenna diameter and blockage taper: the illumination taper in dB """ # try quantity my_qa = qatool() self.antenna_diam_m = my_qa.getvalue(my_qa.convert(diam, "m"))[0] self.antenna_block_m = my_qa.getvalue(my_qa.convert(blockage, "m"))[0] self.taper = taper self.is_antenna_set = True
def __parse_width(self, val, cell_size_arcsec): """ Convert value in unit of arcsec if val is angle, returns a float value in unit of arcsec. else the unit is assumed to be pixel and multiplied by cell_size_arcsec """ my_qa = qatool() if my_qa.isangle(val): return self.__to_arcsec(val) elif my_qa.getunit(val) in ('', 'pixel'): return my_qa.getvalue(val) * cell_size_arcsec else: raise ValueError, "Invalid width %s" % str(val)
def _get_imsize(self, width, height, dx, dy): casalog.post("Calculating pixel size.") # CAS-5410 Use private tools inside task scripts my_qa = qatool() ny = numpy.ceil( ( my_qa.convert(height, my_qa.getunit(dy))['value'] / \ my_qa.getvalue(dy) ) ) nx = numpy.ceil( ( my_qa.convert(width, my_qa.getunit(dx))['value'] / \ my_qa.getvalue(dx) ) ) casalog.post("- Map extent: [%s, %s]" % (my_qa.tos(width), my_qa.tos(height))) casalog.post("- Cell size: [%s, %s]" % (my_qa.tos(dx), my_qa.tos(dy))) casalog.post("Image pixel numbers to cover the extent: [%d, %d] (projected)" % \ (nx+1, ny+1)) return (int(nx+1), int(ny+1))
def __get_grid_parameters(self, calc=False): # CAS-5410 Use private tools inside task scripts qa = qatool() (nx, ny) = self.__get_mapsize() mapcenter = sdutil.get_map_center(self.center) (cellx, celly) = sdutil.get_cellx_celly(self.cell) if calc and \ ((mapcenter.split() != 3) or not qa.compare(cellx, "rad")): #(mapcenter,cellx,celly) = self.__calc_center_and_cell(mapcenter, cellx, celly) (mapcenter, cellx, celly) = self.__get_center_and_cell(nx, ny, mapcenter, cellx, celly) return (nx, ny, cellx, celly, mapcenter)
def __format_quantum_unit(self, data, unit): """ Returns False if data has an unit which in not a variation of input unit. Otherwise, returns input data as a quantum string. The input unit is added to the return value if no unit is in data. """ my_qa = qatool() if data == '' or my_qa.compare(data, unit): return data if my_qa.getunit(data) == '': casalog.post("No unit specified. Using '%s'" % unit) return '%f%s' % (data, unit) return None
def _get_imsize(self, width, height, dx, dy): casalog.post("Calculating pixel size.") # CAS-5410 Use private tools inside task scripts my_qa = qatool() ny = numpy.ceil( ( my_qa.convert(height, my_qa.getunit(dy))['value'] / \ my_qa.getvalue(dy) ) ) nx = numpy.ceil( ( my_qa.convert(width, my_qa.getunit(dx))['value'] / \ my_qa.getvalue(dx) ) ) casalog.post("- Map extent: [%s, %s]" % (my_qa.tos(width), my_qa.tos(height))) casalog.post("- Cell size: [%s, %s]" % (my_qa.tos(dx), my_qa.tos(dy))) casalog.post("Image pixel numbers to cover the extent: [%d, %d] (projected)" % \ (nx+1, ny+1)) return (int(nx + 1), int(ny + 1))
def __set_unit_labels(self): # CAS-5410 Use private tools inside task scripts qa = qatool() self.abclbl = self.scan.get_unit() if self.fluxunit != '': ordlbl = self.fluxunit else: ordlbl = self.scan.get_fluxunit() self.intlbl = ordlbl+' * '+self.abclbl # Check units if self.abclbl == 'channel' and not qa.check(self.abclbl): qa.define('channel','1 _') self.xunit = check_unit(self.abclbl,self.abclbl,'_') self.intunit = check_unit(ordlbl,ordlbl+'.'+self.abclbl,'_.'+self.abclbl)
def _get_average_antenna_diameter(self, antenna): my_qa = qatool() self.open_table(self.antenna_table) try: antdiam_unit = self.table.getcolkeyword('DISH_DIAMETER', 'QuantumUnits')[0] diams = self.table.getcol('DISH_DIAMETER') finally: self.close_table() if len(antenna) == 0: antdiam_ave = my_qa.quantity(diams.mean(), antdiam_unit) else: d_ave = sum([diams[idx] for idx in antenna])/float(len(antenna)) antdiam_ave = my_qa.quantity(d_ave, antdiam_unit) return antdiam_ave
def __set_unit_labels(self): # CAS-5410 Use private tools inside task scripts qa = qatool() self.abclbl = self.scan.get_unit() if self.fluxunit != '': ordlbl = self.fluxunit else: ordlbl = self.scan.get_fluxunit() self.intlbl = ordlbl + ' * ' + self.abclbl # Check units if self.abclbl == 'channel' and not qa.check(self.abclbl): qa.define('channel', '1 _') self.xunit = check_unit(self.abclbl, self.abclbl, '_') self.intunit = check_unit(ordlbl, ordlbl + '.' + self.abclbl, '_.' + self.abclbl)
def _get_average_antenna_diameter(self, antenna): my_qa = qatool() self.open_table(self.antenna_table) try: antdiam_unit = self.table.getcolkeyword('DISH_DIAMETER', 'QuantumUnits')[0] diams = self.table.getcol('DISH_DIAMETER') finally: self.close_table() if len(antenna) == 0: antdiam_ave = my_qa.quantity(diams.mean(), antdiam_unit) else: d_ave = sum([diams[idx] for idx in antenna]) / float(len(antenna)) antdiam_ave = my_qa.quantity(d_ave, antdiam_unit) return antdiam_ave
def primaryBeamArcsec(frequency, diameter, obscuration, taper, showEquation=True, use2007formula=True, fwhmfactor=None): """ Implements the Baars formula: b*lambda / D. if use2007formula==False, use the formula from ALMA Memo 456 if use2007formula==True, use the formula from Baars 2007 book (see au.baarsTaperFactor) In either case, the taper value is expected to be entered as positive. Note: if a negative value is entered, it is converted to positive. The effect of the central obstruction on the pattern is also accounted for by using a spline fit to Table 10.1 of Schroeder's Astronomical Optics. fwhmfactor: if given, then ignore the taper For further help and examples, see https://safe.nrao.edu/wiki/bin/view/ALMA/PrimaryBeamArcsec -- Todd Hunter Simplified version of the one in AnalysisUtils (revision 1.2204, 2015/02/18) """ if (fwhmfactor != None): taper = effectiveTaper(fwhmfactor, diameter, obscuration, use2007formula) if (taper == None): return if (taper < 0): taper = abs(taper) if (obscuration > 0.4 * diameter): print "This central obscuration is too large for the method of calculation employed here." return if (type(frequency) == str): my_qa = qatool() frequency = my_qa.getvalue(my_qa.convert(frequency, "Hz"))[0] lambdaMeters = 2.99792458e8 / frequency b = baarsTaperFactor(taper, use2007formula) * centralObstructionFactor( diameter, obscuration) if (showEquation): if (use2007formula): formula = "Baars (2007) Eq 4.13" else: formula = "ALMA memo 456 Eq. 18" casalog.post( "Coefficient from %s for a -%.1fdB edge taper and obscuration ratio=%g/%g = %.3f*lambda/D" % (formula, taper, obscuration, diameter, b)) return (b * lambdaMeters * 3600 * 180 / (diameter * np.pi))
def __calc_center_and_cell(self, center, cellx, celly): from numpy import array # CAS-5410 Use private tools inside task scripts qa = qatool() # Get map extent (in radian) dirarr = array(self.scan.get_directionval()).transpose() xmin = dirarr[0].min() xmax = dirarr[0].max() ymin = dirarr[1].min() ymax = dirarr[1].max() del dirarr # center of directions dircent = [0.5 * (xmax + xmin), 0.5 * (ymax + ymin)] centx = None centy = None # center is not specified if center.split() != 3: # set map center (string) to center of directions center = sdutil.get_map_center(dircent, unit="rad") # direction center in unit of radian (centx, centy) = dircent # cell is not specified if not qa.compare(cellx, "rad"): if not centx: # center is given. Get the value in radian lcent = center.split() centx = qa.convert(qa.toangle(lcent[1]), "rad") centy = qa.convert(qa.toangle(lcent[2]), "rad") # make sure centx is in +-pi of pointing center rotnum = round(abs(centx - dircent[0]) / (2 * pi)) if centx < dircent[0]: rotnum *= -1 centx -= rotnum * 2 * pi wx = 2. * max(abs(xmax - centx), abs(xmin - centx)) wy = 2. * max(abs(ymax - centy), abs(ymin - centy)) #print "mapsize = [%frad, %frad]" % (wx, wy) from numpy import cos (nx, ny) = self.__get_mapsize() cellx = qa.quantity(wx / float(max(nx - 1, 1)) * cos(centy), "rad") celly = qa.quantity(wy / float(max(ny - 1, 1)), "rad") return (center, qa.tos(cellx), qa.tos(celly))
def __calc_center_and_cell(self, center, cellx, celly): from numpy import array # CAS-5410 Use private tools inside task scripts qa = qatool() # Get map extent (in radian) dirarr = array(self.scan.get_directionval()).transpose() xmin = dirarr[0].min() xmax = dirarr[0].max() ymin = dirarr[1].min() ymax = dirarr[1].max() del dirarr # center of directions dircent = [0.5*(xmax + xmin), 0.5*(ymax + ymin)] centx = None centy = None # center is not specified if center.split() != 3: # set map center (string) to center of directions center = sdutil.get_map_center(dircent, unit= "rad") # direction center in unit of radian (centx, centy) = dircent # cell is not specified if not qa.compare(cellx, "rad"): if not centx: # center is given. Get the value in radian lcent = center.split() centx = qa.convert(qa.toangle(lcent[1]), "rad") centy = qa.convert(qa.toangle(lcent[2]), "rad") # make sure centx is in +-pi of pointing center rotnum = round(abs(centx - dircent[0])/(2*pi)) if centx < dircent[0]: rotnum *= -1 centx -= rotnum*2*pi wx = 2. * max(abs(xmax-centx), abs(xmin-centx)) wy = 2. * max(abs(ymax-centy), abs(ymin-centy)) #print "mapsize = [%frad, %frad]" % (wx, wy) from numpy import cos (nx,ny) = self.__get_mapsize() cellx = qa.quantity(wx/float(max(nx-1,1))*cos(centy), "rad") celly = qa.quantity(wy/float(max(ny-1,1)), "rad") return (center, qa.tos(cellx), qa.tos(celly))
def _calc_PB(vis, antenna_id, restfreq): """ Calculate the primary beam size of antenna, using dish diamenter and rest frequency Average antenna diamter and reference frequency are adopted for calculation. The input argument should be a list of antenna IDs. """ casalog.post("Calculating Pirimary beam size:") # CAS-5410 Use private tools inside task scripts my_qa = qatool() pb_factor = 1.175 # Reference frequency ref_freq = restfreq if type(ref_freq) in [float, numpy.float64]: ref_freq = my_qa.tos(my_qa.quantity(ref_freq, 'Hz')) if not my_qa.compare(ref_freq, 'Hz'): msg = "Could not get the reference frequency. " + \ "Your data does not seem to have valid one in selected field.\n" + \ "PB is not calculated.\n" + \ "Please set restreq or cell manually to generate an image." raise Exception, msg # Antenna diameter with open_table(os.path.join(vis, 'ANTENNA')) as tb: antdiam_ave = tb.getcell('DISH_DIAMETER', antenna_id) #antdiam_ave = self._get_average_antenna_diameter(antenna) # Calculate PB wave_length = 0.2997924 / my_qa.convert(my_qa.quantity(ref_freq), 'GHz')['value'] D_m = my_qa.convert(antdiam_ave, 'm')['value'] lambda_D = wave_length / D_m * 3600. * 180 / numpy.pi PB = my_qa.quantity(pb_factor * lambda_D, 'arcsec') # Summary casalog.post("- Antenna diameter: %s m" % D_m) casalog.post("- Reference Frequency: %s" % ref_freq) casalog.post("PB size = %5.3f * lambda/D = %s" % (pb_factor, my_qa.tos(PB))) return PB
def primaryBeamArcsec(frequency, diameter, obscuration, taper, showEquation=True, use2007formula=True, fwhmfactor=None): """ Implements the Baars formula: b*lambda / D. if use2007formula==False, use the formula from ALMA Memo 456 if use2007formula==True, use the formula from Baars 2007 book (see au.baarsTaperFactor) In either case, the taper value is expected to be entered as positive. Note: if a negative value is entered, it is converted to positive. The effect of the central obstruction on the pattern is also accounted for by using a spline fit to Table 10.1 of Schroeder's Astronomical Optics. fwhmfactor: if given, then ignore the taper For further help and examples, see https://safe.nrao.edu/wiki/bin/view/ALMA/PrimaryBeamArcsec -- Todd Hunter Simplified version of the one in AnalysisUtils (revision 1.2204, 2015/02/18) """ if (fwhmfactor != None): taper = effectiveTaper(fwhmfactor,diameter,obscuration,use2007formula) if (taper == None): return if (taper < 0): taper = abs(taper) if (obscuration>0.4*diameter): print "This central obscuration is too large for the method of calculation employed here." return if (type(frequency) == str): my_qa = qatool() frequency = my_qa.getvalue(my_qa.convert(frequency, "Hz"))[0] lambdaMeters = 2.99792458e8/frequency b = baarsTaperFactor(taper,use2007formula) * centralObstructionFactor(diameter, obscuration) if (showEquation): if (use2007formula): formula = "Baars (2007) Eq 4.13" else: formula = "ALMA memo 456 Eq. 18" casalog.post("Coefficient from %s for a -%.1fdB edge taper and obscuration ratio=%g/%g = %.3f*lambda/D" % (formula, taper, obscuration, diameter, b)) return(b*lambdaMeters*3600*180/(diameter*np.pi))
def __execute_press(self): ### # Pressed-out method (Sofue & Reich 1979) ### casalog.post( 'Apply Pressed-out method' ) # CAS-5410 Use private tools inside task scripts ia = gentools(['ia'])[0] # mask self.image = ia.newimagefromimage(infile=self.infiles,outfile=self.tmpmskname) # back-up original mask name is_initial_mask = (self.image.maskhandler('default')[0] != '') temp_maskname = "temporal" imshape = self.image.shape() ndim = len(imshape) nx = imshape[0] ny = imshape[1] if len(self.thresh) == 0: casalog.post( 'Use whole region' ) else: # mask pixels beyond thresholds maskstr = ("mask('%s')" % self.tmpmskname) if self.thresh[0] != self.nolimit: maskstr += (" && '%s'>=%f" % (self.tmpmskname, self.thresh[0])) if self.thresh[1] != self.nolimit: maskstr += (" && '%s'<=%f" % (self.tmpmskname, self.thresh[1])) # Need to flush to image once to calcmask ... sigh self.image.done() self.image = ia.newimage( self.tmpmskname ) self.image.calcmask(mask=maskstr, name=temp_maskname, asdefault=True) # smoothing #bmajor = 0.0 #bminor = 0.0 # CAS-5410 Use private tools inside task scripts qa = qatool() if type(self.beamsize) == str: qbeamsize = qa.quantity(self.beamsize) else: qbeamsize = qa.quantity(self.beamsize,'arcsec') if type(self.smoothsize) == str: #bmajor = smoothsize #bminor = smoothsize qsmoothsize = qa.quantity(self.smoothsize) else: #bmajor = '%sarcsec' % (beamsize*smoothsize) #bminor = '%sarcsec' % (beamsize*smoothsize) qsmoothsize = qa.mul(qbeamsize,self.smoothsize) bmajor = qsmoothsize bminor = qsmoothsize pa = qa.quantity(0.0, 'deg') # masked channels are replaced by zero and convolved here. self.convimage = self.image.convolve2d( outfile=self.tmppolyname, major=bmajor, minor=bminor, pa=pa, overwrite=True ) self.convimage.done() # get dTij (original - smoothed) self.convimage = ia.imagecalc(outfile=self.tmpconvname, pixels='"{org}" - "{conv}"'.format(org=self.tmpmskname, conv=self.tmppolyname), overwrite=True) # polynomial fit fitaxis = 0 if self.direction == 0.0: fitaxis = 0 elif self.direction == 90.0: fitaxis = 1 else: raise Exception, "Sorry, the task don't support inclined scan with respect to horizontal or vertical axis, right now." # Replace duplicated method ia.fitpolynomial with # ia.fitprofile #polyimage = convimage.fitpolynomial( fitfile=tmppolyname, axis=fitaxis, order=numpoly, overwrite=True ) #polyimage.done() if os.path.exists( self.tmppolyname ): # CAS-5410 Use private tools inside task scripts cu = utilstool() cu.removetable([self.tmppolyname]) self.convimage.setbrightnessunit('K') # Unfortunately, ia.fitprofile is very fragile. # Using numpy instead for fitting with masked pixels (KS, 2014/07/02) #resultdic = self.convimage.fitprofile( model=self.tmppolyname, axis=fitaxis, poly=self.numpoly, ngauss=0, multifit=True, gmncomps=0 ) self.__polynomial_fit_model(image=self.tmpmskname, model=self.tmppolyname,axis=fitaxis, order=self.numpoly) polyimage = ia.newimage( self.tmppolyname ) # set back defalut mask (need to get from self.image) avail_mask = polyimage.maskhandler('get') if is_initial_mask: casalog.post("copying mask from %s"%(self.infiles)) polyimage.calcmask("mask('%s')"%self.infiles,asdefault=True) else: #no mask in the original image polyimage.calcmask('T', asdefault=True) if temp_maskname in avail_mask: polyimage.maskhandler('delete', name=temp_maskname) # subtract fitted image from original map subtracted = ia.imagecalc(outfile=self.outfile, pixels='"{org}" - "{fit}"'.format(org=self.infiles, fit=self.tmppolyname), overwrite=self.overwrite) subtracted.done() # finalization polyimage.done(remove=True) self.convimage.done(remove=True) self.image.done()
def _summarize(self, fitsname, casaname, header, shape, taskargs): """Convenience function to populate dictionary for items to add to the ADMIT Summary. The contract function is self.summary(), called by AT() """ self._summary = {} self._summary['fitsname'] = SummaryEntry(fitsname) self._summary['casaname'] = SummaryEntry(casaname) # these are one-to-one match keywords easy = [ 'object', 'equinox', 'observer', 'date-obs', 'datamax', 'datamin', 'badpixel', 'vlsr', ] naxis = len(shape) self._summary['naxis'] = SummaryEntry(naxis) for i in range(naxis): j = i + 1 jay = str(j) easy.append('crpix' + jay) easy.append('ctype' + jay) easy.append('crval' + jay) easy.append('cdelt' + jay) easy.append('cunit' + jay) self._summary['naxis' + jay] = SummaryEntry(int(shape[i])) # FITS is only 8 chars. if 'telescope' in header: self._summary['telescop'] = SummaryEntry(header['telescope']) if 'imtype' in header: self._summary['bunit'] = SummaryEntry(header['bunit']) for k in easy: if k in header: self._summary[k] = SummaryEntry(header[k]) if 'restfreq' in header: self._summary['restfreq'] = SummaryEntry(header['restfreq'][0]) # These are in imhead returned as dictionaries {'unit','value'} # so we have to munge them # convert beam parameters qa = taskinit.qatool() if 'beampa' in header: self._summary['bpa'] = SummaryEntry( qa.convert(header['beampa'], 'deg')['value']) if 'beammajor' in header: self._summary['bmaj'] = SummaryEntry( qa.convert(header['beammajor'], 'rad')['value']) if 'beamminor' in header: self._summary['bmin'] = SummaryEntry( qa.convert(header['beamminor'], 'rad')['value']) # Now tag all summary items with task name and task ID. for k in self._summary: self._summary[k].setTaskname("Ingest_AT") self._summary[k].setTaskID(self.id(True)) self._summary[k].setTaskArgs(taskargs)
def run(self): """ The run method creates the BDP Parameters ---------- None Returns ------- None """ self._summary = {} dt = utils.Dtime("Smooth") dt.tag("start") # get the input keys bmaj = self.getkey("bmaj") bmin = self.getkey("bmin") bpa = self.getkey("bpa") velres = self.getkey("velres") # take care of potential issues in the unit strings # @todo if not provided? bmaj['unit'] = bmaj['unit'].lower() bmin['unit'] = bmin['unit'].lower() velres['unit'] = velres['unit'].lower() taskargs = "bmaj=%s bmin=%s bpa=%s velres=%s" % (bmaj, bmin, bpa, velres) ia = taskinit.iatool() qa = taskinit.qatool() bdpnames = [] for ibdp in self._bdp_in: istem = ibdp.getimagefile(bt.CASA) image_in = ibdp.baseDir() + istem bdp_name = self.mkext(istem, 'sim') image_out = self.dir(bdp_name) ia.open(image_in) h = casa.imhead(image_in, mode='list') pix_scale = np.abs(h['cdelt1'] * 206265.0) # pix scale in asec @todo QA ? CC = 299792458.0 # speed of light @todo somewhere else [utils.c , but in km/s] rest_freq = h['crval3'] # frequency pixel scale in km/s vel_scale = np.abs(CC * h['cdelt3'] / rest_freq / 1000.0) # unit conversion to arcsec (spatial) or km/s # (velocity) or some flavor of Hz. if (bmaj['unit'] == 'pixel'): bmaj = bmaj['value'] * pix_scale else: bmaj = bmaj['value'] if (bmin['unit'] == 'pixel'): bmin = bmin['value'] * pix_scale else: bmin = bmin['value'] hertz_input = False if velres['unit'] == 'pixel': velres['value'] = velres['value'] * vel_scale velres['unit'] = 'km/s' elif velres['unit'] == 'm/s': velres['value'] = velres['value'] / 1000.0 velres['unit'] = 'km/s' elif velres['unit'][-2:] == 'hz': hertz_input = True elif velres['unit'] == 'km/s': pass else: logging.error("Unknown units in velres=%s" % velres['unit']) rdata = bmaj # we smooth in velocity first. if smoothing in velocity # the cube apparently must be closed afterwards and # then reopened if spatial smoothing is to be done. if velres['value'] > 0: # handle the different units allowed. CASA doesn't # like lowercase for hz units... if not hertz_input: freq_res = str( velres['value'] * 1000.0 / CC * rest_freq) + 'Hz' else: freq_res = str(velres['value']) # try to convert velres to km/s for debug purposes velres['value'] = velres['value'] / rest_freq * CC / 1000.0 if (velres['unit'] == 'khz'): velres['value'] = velres['value'] * 1000.0 velres['unit'] = 'kHz' elif (velres['unit'] == 'mhz'): velres['value'] = velres['value'] * 1E6 velres['unit'] = 'MHz' elif (velres['unit'] == 'ghz'): velres['value'] = velres['value'] * 1E9 velres['unit'] = 'GHz' freq_res = freq_res + velres['unit'] # NB: there is apparently a bug in CASA. only smoothing along the frequency # axis does not work. sepconvolve gives a unit error (says axis unit is radian rather # than Hz). MUST smooth in 2+ dimensions if you want this to work. if (velres['value'] < vel_scale): raise Exception, "Desired velocity resolution %g less than pixel scale %g" % ( velres['value'], vel_scale) image_tmp = self.dir('tmp.smooth') im2=ia.sepconvolve(outfile=image_tmp,axes=[0,1,2], types=["boxcar","boxcar","gauss"],\ widths=['1pix','1pix',freq_res], overwrite=True) im2.done() logging.debug("sepconvolve to %s" % image_out) # for some reason, doing this in memory does not seem to work, so outfile must be specified. logging.info( "Smoothing cube to a velocity resolution of %s km/s" % str(velres['value'])) logging.info("Smoothing cube to a frequency resolution of %s" % freq_res) ia.close() ia.open(image_tmp) dt.tag("sepconvolve") else: image_tmp = image_out # now do the spatial smoothing convolve_to_min_beam = True # default is to convolve to a min enclosing beam if bmaj > 0 and bmin > 0: # form qa objects out of these so that casa can understand bmaj = qa.quantity(bmaj, 'arcsec') bmin = qa.quantity(bmin, 'arcsec') bpa = qa.quantity(bpa, 'deg') target_res = {} target_res['major'] = bmaj target_res['minor'] = bmin target_res['positionangle'] = bpa # throw an exception if cannot be convolved try: # for whatever reason, if you give convolve2d a beam parameter, # it complains ... im2=ia.convolve2d(outfile=image_out,major = bmaj,\ minor = bmin, pa = bpa,\ targetres=True,overwrite=True) im2.done() logging.info( "Smoothing cube to a resolution of %s by %s at a PA of %s" % (str(bmaj['value']), str( bmin['value']), str(bpa['value']))) convolve_to_min_beam = False achieved_res = target_res except: # @todo remind what you need ? logging.error("Warning: Could not convolve to requested resolution of "\ +str(bmaj['value']) + " by " + str(bmin['value']) + \ " at a PA of "+ str(bpa['value'])) raise Exception, "Could not convolve to beam given!" dt.tag("convolve2d-1") if convolve_to_min_beam: restoring_beams = ia.restoringbeam() commonbeam = ia.commonbeam() # for whatever reason, setrestoringbeam does not use the same set of hashes... commonbeam['positionangle'] = commonbeam['pa'] del commonbeam['pa'] # if there's one beam, apparently the beams keyword does not exist if 'beams' in restoring_beams: print "Smoothing cube to a resolution of "+ \ str(commonbeam['major']['value']) +" by "+ \ str(commonbeam['minor']['value'])+" at a PA of "\ +str(commonbeam['pa']['value']) target_res = commonbeam im2=ia.convolve2d(outfile=image_out,major=commonbeam['major'],\ minor=commonbeam['minor'],\ pa=commonbeam['positionangle'],\ targetres=True,overwrite=True) im2.done() achieved_res = commonbeam dt.tag("convolve2d-2") else: print "One beam for all planes. Smoothing to common beam redundant." achieved_res = commonbeam if velres['value'] < 0: ia.fromimage(outfile=image_out, infile=image_in) # not really doing anything # else, we've already done what we needed to ia.setrestoringbeam(beam=achieved_res) rdata = achieved_res['major']['value'] # else do no smoothing and just close the image ia.close() dt.tag("close") b1 = SpwCube_BDP(bdp_name) self.addoutput(b1) # need to update for multiple images. b1.setkey("image", Image(images={bt.CASA: bdp_name})) bdpnames = bdpnames.append(bdp_name) # and clean up the temp image before the next image if velres['value'] > 0: utils.remove(image_tmp) # thes are task arguments not summary entries. _bmaj = qa.convert(achieved_res['major'], 'rad')['value'] _bmin = qa.convert(achieved_res['minor'], 'rad')['value'] _bpa = qa.convert(achieved_res['positionangle'], 'deg')['value'] vres = "%.2f %s" % (velres['value'], velres['unit']) logging.regression("SMOOTH: %f %f" % (rdata, velres['value'])) self._summary["smooth"] = SummaryEntry( [bdp_name, convolve_to_min_beam, _bmaj, _bmin, _bpa, vres], "Smooth_AT", self.id(True), taskargs) dt.tag("done") dt.end()
def fixsyscaltimes(vis,newinterval=2.0): """ Fix TIME,INTERVAL columns in MS SYSCAL subtable Input: vis the MS containing the offending SYSCAL subtable newinterval the interval to use in revised entries This function is intended to repair MS SYSCAL tables that suffer from multiple TIME values (over antennas) per Tsys measurement. The gencal task (mode='tsys' expects all antennas to share the same TIME value for each Tsys measurement (and this is usually true). The function finds those measurements that have multiple TIMEs and replaces them with a common TIME value which takes the value mean(oldTIME-INTERVAL/2)+newinterval/2. Usually (always?), oldTIME-INTERVAL/2 is constant over antennas and represents the physical timestamp of the Tsys measurment. If the function finds no pathological timestamps, it does not revise the table. """ import pylab as mypl import math as mymath myqa=taskinit.qatool() mytb=taskinit.tbtool() mytb.open(vis+'/SYSCAL',nomodify=False) spws=mypl.unique(mytb.getcol("SPECTRAL_WINDOW_ID")) for ispw in spws: st=mytb.query('SPECTRAL_WINDOW_ID=='+str(ispw),name='byspw') times=st.getcol('TIME') interval=st.getcol('INTERVAL') timestamps=times-interval/2 t0=86400.0*mymath.floor(timestamps[0]/86400.0) utimes=mypl.unique(times-t0) nT=len(utimes) utimestamps=mypl.unique(mypl.floor(timestamps)-t0) nTS=len(utimestamps) msg='In spw='+str(ispw)+' found '+str(nTS)+' Tsys measurements with '+str(nT)+' TIMEs...' if nT==nTS: msg+='OK.' print msg else: msg+=' which is too many, so fixing it:' print msg for uts in utimestamps: mask = ((mypl.floor(timestamps))-t0==uts) uTIMEs=mypl.unique(times[mask]) nTIMEs=len(uTIMEs) newtime = mypl.mean(times[mask]-interval[mask]/2) + newinterval/2 msg=' Found '+str(nTIMEs)+' TIMEs at timestamp='+str(myqa.time(str(newtime-newinterval/2)+'s',form='ymd')[0]) if nTIMEs>1: msg+=':' print msg print ' TIMEs='+str([myqa.time(str(t)+'s',form='ymd')[0] for t in uTIMEs])+' --> '+str(myqa.time(str(newtime)+'s',form='ymd')[0])+' w/ INTERVAL='+str(newinterval) times[mask]=newtime interval[mask]=newinterval st.putcol('TIME',times) st.putcol('INTERVAL',interval) else: msg+='...ok.' print msg st.close() mytb.close()
def calc_statistics(self): # CAS-5410 Use private tools inside task scripts qa = qatool() self.savestats = '' self.returnstats = {} rootidx = [] # # Warning for multi-IF data # if len(self.scan.getifnos()) > 1: # casalog.post( 'The scantable contains multiple IF data.', priority='WARN' ) # casalog.post( 'Note the same mask(s) are applied to all IFs based on CHANNELS.', priority='WARN' ) # casalog.post( 'Baseline ranges may be incorrect for all but IF=%d.\n' % (self.scan.getif(0)), priority='WARN' ) # backup spec unit unit_org = self.scan.get_unit() self.scan.set_unit('channel') basesel = self.scan.get_selection() maskdict = {-1: []} if self.spw.strip() not in ['', '*']: maskdict = self.scan.parse_spw_selection(self.spw) for ifno, masklist in maskdict.items(): self.masklist = masklist if ifno > -1: sel = sd.selector(basesel) sel.set_ifs([ifno]) self.scan.set_selection(sel) rootidx += list(self.scan._get_root_row_idx()) del sel msg = "Working on IF%s" % (ifno) if (self.interactive): print "===%s===" % (msg) del msg # set mask self.__set_mask() # set formatter self.__set_formatter() # set unit labels self.__set_unit_labels() # calculate statistics #statsdict = get_stats(s, msk, formstr) self.__calc_stats() self.__merge_stats() # reset selection if ifno > -1: self.scan.set_selection(basesel) # restore spec unit self.scan.set_unit(unit_org) # sort return values in order of root table row idx if len(rootidx) > 0: self.__sort_stats_order(rootidx) # return values instead of lists if nrow = 1. if len(self.returnstats[self.returnstats.keys()[0]]) == 1: self.__stats_list_to_val() # reshape statsdict for return for k in ['min', 'max']: retsts = {} retsts['value'] = self.returnstats.pop('%s_abc' % (k)) retsts['unit'] = self.xunit self.returnstats['%s_abscissa' % (k)] = retsts for (k, u) in [('eqw', self.xunit), ('totint', self.intunit)]: retsts = {} retsts['value'] = self.returnstats[k] retsts['unit'] = u self.returnstats[k] = retsts
def _get_restfreq_if_empty(vislist, spw, field, restfreq): qa = qatool() rf = None # if restfreq is nonzero float value, return it if isinstance(restfreq, float): if restfreq != 0.0: rf = restfreq # if restfreq is valid frequency string, return it # numeric string is interpreted as a value in the unit of Hz elif isinstance(restfreq, str): q = qa.convert(qa.quantity(restfreq), 'Hz') if q['unit'] == 'Hz' and q['value'] > 0.0: rf = restfreq # if restfreq is valid quantity, return it elif isinstance(restfreq, dict): q = qa.convert(restfreq, 'Hz') if q['unit'] == 'Hz' and q['value'] > 0.0: rf = restfreq if isinstance(vislist, str): vis = vislist elif hasattr(vislist, '__iter__'): vis = vislist[0] else: raise RuntimeError( 'Internal Error: invalid vislist \'{0}\''.format(vislist)) if isinstance(spw, str): spwsel = spw elif hasattr(spw, '__iter__'): spwsel = spw[0] else: raise RuntimeError( 'Internal Error: invalid spw selection \'{0}\''.format(spw)) if isinstance(field, str): fieldsel = field elif hasattr(field, '__iter__'): fieldsel = field[0] else: raise RuntimeError( 'Internal Error: invalid field selection \'{0}\''.format(field)) with open_ms(vis) as ms: ms.msselect({'spw': spwsel, 'field': fieldsel}) ndx = ms.msselectedindices() if len(ndx['spw']) > 0: spwid = ndx['spw'][0] else: spwid = None if len(ndx['field']) > 0: fieldid = ndx['field'][0] else: fieldid = None sourceid = None if fieldid is not None: with open_table(os.path.join(vis, 'FIELD')) as tb: sourceid = tb.getcell('SOURCE_ID', fieldid) if sourceid < 0: sourceid = None if rf is None: # if restfrequency is defined in SOURCE table, return it with open_table(os.path.join(vis, 'SOURCE')) as tb: if 'REST_FREQUENCY' in tb.colnames(): tsel = None taql = '' if spwid is not None: taql = 'SPECTRAL_WINDOW_ID == {0}'.format(spwid) if sourceid is not None: delimiter = '&&' if len(taql) > 0 else '' taql += '{0}SOURCE_ID == {1}'.format(delimiter, sourceid) if len(taql) > 0: tsel = tb.query(taql) t = tsel else: t = tb try: nrow = t.nrows() if nrow > 0: for irow in xrange(nrow): if t.iscelldefined('REST_FREQUENCY', irow): rfs = t.getcell('REST_FREQUENCY', irow) if len(rfs) > 0: rf = rfs[0] break finally: if tsel is not None: tsel.close() if rf is None: if spwid is None: spwid = 0 # otherwise, return mean frequency of given spectral window with open_table(os.path.join(vis, 'SPECTRAL_WINDOW')) as tb: cf = tb.getcell('CHAN_FREQ', spwid) rf = cf.mean() assert rf is not None return rf
def calc_statistics(self): # CAS-5410 Use private tools inside task scripts qa = qatool() self.savestats = '' self.returnstats = {} rootidx = [] # # Warning for multi-IF data # if len(self.scan.getifnos()) > 1: # casalog.post( 'The scantable contains multiple IF data.', priority='WARN' ) # casalog.post( 'Note the same mask(s) are applied to all IFs based on CHANNELS.', priority='WARN' ) # casalog.post( 'Baseline ranges may be incorrect for all but IF=%d.\n' % (self.scan.getif(0)), priority='WARN' ) # backup spec unit unit_org = self.scan.get_unit() self.scan.set_unit('channel') basesel = self.scan.get_selection() maskdict = {-1: []} if self.spw.strip() not in ['', '*']: maskdict = self.scan.parse_spw_selection(self.spw) for ifno, masklist in maskdict.items(): self.masklist = masklist if ifno > -1: sel = sd.selector(basesel) sel.set_ifs([ifno]) self.scan.set_selection(sel) rootidx += list(self.scan._get_root_row_idx()) del sel msg = "Working on IF%s" % (ifno) if (self.interactive): print "===%s===" % (msg) del msg # set mask self.__set_mask() # set formatter self.__set_formatter() # set unit labels self.__set_unit_labels() # calculate statistics #statsdict = get_stats(s, msk, formstr) self.__calc_stats() self.__merge_stats() # reset selection if ifno > -1: self.scan.set_selection(basesel) # restore spec unit self.scan.set_unit(unit_org) # sort return values in order of root table row idx if len(rootidx) > 0: self.__sort_stats_order(rootidx) # return values instead of lists if nrow = 1. if len(self.returnstats[ self.returnstats.keys()[0] ]) == 1: self.__stats_list_to_val() # reshape statsdict for return for k in ['min','max']: retsts = {} retsts['value'] = self.returnstats.pop('%s_abc'%(k)) retsts['unit'] = self.xunit self.returnstats['%s_abscissa'%(k)] = retsts for (k,u) in [('eqw',self.xunit),('totint',self.intunit)]: retsts = {} retsts['value'] = self.returnstats[k] retsts['unit'] = u self.returnstats[k] = retsts
def set_beam_size(vis, imagename, field, spw, baseline, scan, intent, ephemsrcname, pointingcolumntouse, antenna_name, antenna_diameter, restfreq, gridfunction, convsupport, truncate, gwidth, jwidth): """ Set estimated beam size to the image. """ is_alma = antenna_name[0:2] in ['PM', 'DV', 'DA', 'CM'] blockage = '0.75m' if is_alma else '0.0m' with open_ia(imagename) as ia: csys = ia.coordsys() outref = csys.referencecode('direction')[0] cell = list(csys.increment(type='direction', format='s')['string']) old_tool = OldImagerBasedTools() sampling_params = old_tool.get_pointing_sampling_params( vis, field, spw, baseline, scan, intent, outref=outref, movingsource=ephemsrcname, pointingcolumntouse=pointingcolumntouse, antenna_name=antenna_name) qa = qatool() casalog.post('sampling_params={0}'.format(sampling_params)) xsampling, ysampling = qa.getvalue( qa.convert(sampling_params['sampling'], 'arcsec')) angle = qa.getvalue(qa.convert(sampling_params['angle'], 'deg'))[0] casalog.post('Detected raster sampling = [{0:f}, {1:f}] arcsec'.format( xsampling, ysampling)) # handling of failed sampling detection valid_sampling = True # TODO: copy from sdimaging implementation sampling = [xsampling, ysampling] if abs(xsampling) < 2.2e-3 or not numpy.isfinite(xsampling): casalog.post( "Invalid sampling=%s arcsec. Using the value of orthogonal direction=%s arcsec" % (xsampling, ysampling), priority="WARN") sampling = [ysampling] angle = 0.0 valid_sampling = False if abs(ysampling) < 1.0e-3 or not numpy.isfinite(ysampling): if valid_sampling: casalog.post( "Invalid sampling=%s arcsec. Using the value of orthogonal direction=%s arcsec" % (ysampling, xsampling), priority="WARN") sampling = [xsampling] angle = 0.0 valid_sampling = True # reduce sampling and cell if it's possible if len(sampling) > 1 and abs(sampling[0] - sampling[1]) <= 0.01 * abs(sampling[0]): sampling = [sampling[0]] angle = 0.0 if cell[0] == cell[1]: cell = [cell[0]] if valid_sampling: # actual calculation of beam size bu = sdbeamutil.TheoreticalBeam() bu.set_antenna(antenna_diameter, blockage) bu.set_sampling(sampling, "%fdeg" % angle) bu.set_image_param(cell, restfreq, gridfunction, convsupport, truncate, gwidth, jwidth, is_alma) bu.summary() imbeam_dict = bu.get_beamsize_image() casalog.post("Setting image beam: major=%s, minor=%s, pa=%s" % ( imbeam_dict['major'], imbeam_dict['minor'], imbeam_dict['pa'], )) # set beam size to image with open_ia(imagename) as ia: ia.setrestoringbeam(**imbeam_dict) else: # BOTH sampling was invalid casalog.post( "Could not detect valid raster sampling. Exitting without setting beam size to image", priority='WARN')
def __execute_press(self): ### # Pressed-out method (Sofue & Reich 1979) ### casalog.post("Apply Pressed-out method") # CAS-5410 Use private tools inside task scripts ia = gentools(["ia"])[0] # mask self.image = ia.newimagefromimage(infile=self.infiles, outfile=self.tmpmskname) # back-up original mask name is_initial_mask = self.image.maskhandler("default")[0] != "" temp_maskname = "temporal" imshape = self.image.shape() nx = imshape[0] ny = imshape[1] nchan = imshape[2] if len(self.thresh) == 0: casalog.post("Use whole region") else: # mask pixels beyond thresholds maskstr = "mask('%s')" % self.tmpmskname if self.thresh[0] != self.nolimit: maskstr += " && '%s'>=%f" % (self.tmpmskname, self.thresh[0]) if self.thresh[1] != self.nolimit: maskstr += " && '%s'<=%f" % (self.tmpmskname, self.thresh[1]) # Need to flush to image once to calcmask ... sigh self.image.done() self.image = ia.newimage(self.tmpmskname) self.image.calcmask(mask=maskstr, name=temp_maskname, asdefault=True) # smoothing # bmajor = 0.0 # bminor = 0.0 # CAS-5410 Use private tools inside task scripts qa = qatool() if type(self.beamsize) == str: qbeamsize = qa.quantity(self.beamsize) else: qbeamsize = qa.quantity(self.beamsize, "arcsec") if type(self.smoothsize) == str: # bmajor = smoothsize # bminor = smoothsize qsmoothsize = qa.quantity(self.smoothsize) else: # bmajor = '%sarcsec' % (beamsize*smoothsize) # bminor = '%sarcsec' % (beamsize*smoothsize) qsmoothsize = qa.mul(qbeamsize, self.smoothsize) bmajor = qsmoothsize bminor = qsmoothsize # masked channels are replaced by zero and convolved here. self.convimage = self.image.convolve2d(outfile=self.tmpconvname, major=bmajor, minor=bminor, overwrite=True) self.convimage.done() self.convimage = ia.newimage(self.tmpconvname) # get dTij (original - smoothed) if len(imshape) == 4: # with polarization axis npol = imshape[3] for ichan in range(nchan): for ipol in range(npol): pixmsk = self.image.getchunk([0, 0, ichan, ipol], [nx - 1, ny - 1, ichan, ipol]) pixsmo = self.convimage.getchunk([0, 0, ichan, ipol], [nx - 1, ny - 1, ichan, ipol]) pixsub = pixmsk - pixsmo self.convimage.putchunk(pixsub, [0, 0, ichan, ipol]) elif len(imshape) == 3: for ichan in range(nchan): # no polarization axis pixmsk = self.image.getchunk([0, 0, ichan], [nx - 1, ny - 1, ichan]) pixsmo = self.convimage.getchunk([0, 0, ichan], [nx - 1, ny - 1, ichan]) pixsub = pixmsk - pixsmo self.convimage.putchunk(pixsub, [0, 0, ichan]) # polynomial fit fitaxis = 0 if self.direction == 0.0: fitaxis = 0 elif self.direction == 90.0: fitaxis = 1 else: raise Exception, "Sorry, the task don't support inclined scan with respect to horizontal or vertical axis, right now." # Replace duplicated method ia.fitpolynomial with # ia.fitprofile # polyimage = convimage.fitpolynomial( fitfile=tmppolyname, axis=fitaxis, order=numpoly, overwrite=True ) # polyimage.done() if os.path.exists(self.tmppolyname): # CAS-5410 Use private tools inside task scripts cu = utilstool() cu.removetable([self.tmppolyname]) self.convimage.setbrightnessunit("K") # Unfortunately, ia.fitprofile is very fragile. # Using numpy instead for fitting with masked pixels (KS, 2014/07/02) # resultdic = self.convimage.fitprofile( model=self.tmppolyname, axis=fitaxis, poly=self.numpoly, ngauss=0, multifit=True, gmncomps=0 ) self.__polynomial_fit_model(image=self.tmpmskname, model=self.tmppolyname, axis=fitaxis, order=self.numpoly) polyimage = ia.newimage(self.tmppolyname) # set back defalut mask (need to get from self.image) avail_mask = polyimage.maskhandler("get") if is_initial_mask: casalog.post("copying mask from %s" % (self.infiles)) polyimage.calcmask("mask('%s')" % self.infiles, asdefault=True) else: # no mask in the original image polyimage.calcmask("T", asdefault=True) if temp_maskname in avail_mask: polyimage.maskhandler("delete", name=temp_maskname) # subtract fitted image from original map imageorg = ia.newimage(self.infiles) if len(imshape) == 4: # with polarization axis npol = imshape[3] for ichan in range(nchan): for ipol in range(npol): pixorg = imageorg.getchunk([0, 0, ichan, ipol], [nx - 1, ny - 1, ichan, ipol]) pixpol = polyimage.getchunk([0, 0, ichan, ipol], [nx - 1, ny - 1, ichan, ipol]) pixsub = pixorg - pixpol polyimage.putchunk(pixsub, [0, 0, ichan, ipol]) elif len(imshape) == 3: # no polarization axis for ichan in range(nchan): pixorg = imageorg.getchunk([0, 0, ichan], [nx - 1, ny - 1, ichan]) pixpol = polyimage.getchunk([0, 0, ichan], [nx - 1, ny - 1, ichan]) pixsub = pixorg - pixpol polyimage.putchunk(pixsub, [0, 0, ichan]) # output polyimage.rename(self.outfile, overwrite=self.overwrite) polyimage.done() self.convimage.done(remove=True) self.image.done() imageorg.done()
import astropy.units as u from astropy import constants try: from casac import casac synthesisutils = casac.synthesisutils from taskinit import msmdtool, casalog, qatool, tbtool, mstool, iatool from tasks import tclean except ImportError: from casatools import (quanta as qatool, table as tbtool, msmetadata as msmdtool, synthesisutils, ms as mstool, image as iatool) from casatasks import casalog, tclean msmd = msmdtool() ms = mstool() qa = qatool() st = synthesisutils() tb = tbtool() ia = iatool() def logprint(string, origin='almaimf_metadata', priority='INFO'): print(string) casalog.post(string, origin=origin, priority=priority) def is_7m(ms): """ Determine if a measurement set includes 7m data """ msmd.open(ms)
def _get_pointing_extent(phasecenter, vislist, field, spw, antenna, scan, intent, pointingcolumntouse, ephemsrcname): ### MS selection is ignored. This is not quite right. casalog.post("Calculating map extent from pointings.") # CAS-5410 Use private tools inside task scripts my_qa = qatool() ret_dict = {} if isinstance(vislist, str): vis = vislist else: vis = vislist[0] colname = pointingcolumntouse.upper() if phasecenter == "": # defaut is J2000 base_mref = 'J2000' elif isinstance(phasecenter, int) or phasecenter.isdigit(): # may be field id with open_table(os.path.join(vis, 'FIELD')) as tb: base_mref = tb.getcolkeyword('PHASE_DIR', 'MEASINFO')['Ref'] else: # may be phasecenter is explicitly specified pattern = '^([\-\+]?[0-9.]+([eE]?-?[0-9])?)|([\-\+]?[0-9][:h][0-9][:m][0-9.]s?)|([\-\+]?[0-9][.d][0-9][.d][0-9.]s?)$' items = phasecenter.split() base_mref = 'J2000' for i in items: s = i.strip() if re.match(pattern, s) is None: base_mref = s break t = OldImagerBasedTools() mapextent = t.get_map_extent(vislist, field, spw, antenna, scan, intent, ref=base_mref, movingsource=ephemsrcname, pointingcolumntouse=pointingcolumntouse) #mapextent = self.imager.mapextent(ref=base_mref, movingsource=ephemsrcname, # pointingcolumntouse=colname) if mapextent['status'] is True: qheight = my_qa.quantity(mapextent['extent'][1], 'rad') qwidth = my_qa.quantity(mapextent['extent'][0], 'rad') qcent0 = my_qa.quantity(mapextent['center'][0], 'rad') qcent1 = my_qa.quantity(mapextent['center'][1], 'rad') scenter = '%s %s %s' % (base_mref, my_qa.formxxx( qcent0, 'hms'), my_qa.formxxx(qcent1, 'dms')) casalog.post("- Pointing center: %s" % scenter) casalog.post("- Pointing extent: [%s, %s] (projected)" % (my_qa.tos(qwidth), \ my_qa.tos(qheight))) ret_dict['center'] = scenter ret_dict['width'] = qwidth ret_dict['height'] = qheight else: casalog.post( 'Failed to derive map extent from the MSs registered to the imager probably due to mising valid data.', priority='SEVERE') ret_dict['center'] = '' ret_dict['width'] = my_qa.quantity(0.0, 'rad') ret_dict['height'] = my_qa.quantity(0.0, 'rad') return ret_dict
class sdimaging_worker(sdutil.sdtask_template_imaging): def __init__(self, **kwargs): super(sdimaging_worker, self).__init__(**kwargs) self.imager_param = {} self.sorted_idx = [] def parameter_check(self): # outfile check sdutil.assert_outfile_canoverwrite_or_nonexistent( self.outfile, 'im', self.overwrite) sdutil.assert_outfile_canoverwrite_or_nonexistent( self.outfile + '.weight', 'im', self.overwrite) # fix spw if type(self.spw) == str: self.spw = self.__format_spw_string(self.spw) # check unit of start and width # fix default if self.mode == 'channel': if self.start == '': self.start = 0 if self.width == '': self.width = 1 else: if self.start == 0: self.start = '' if self.width == 1: self.width = '' # fix unit if self.mode == 'frequency': myunit = 'Hz' elif self.mode == 'velocity': myunit = 'km/s' else: # channel myunit = '' for name in ['start', 'width']: param = getattr(self, name) new_param = self.__format_quantum_unit(param, myunit) if new_param == None: raise ValueError, "Invalid unit for %s in mode %s: %s" % \ (name, self.mode, param) setattr(self, name, new_param) casalog.post("mode='%s': start=%s, width=%s, nchan=%d" % \ (self.mode, self.start, self.width, self.nchan)) # check length of selection parameters if is_string_type(self.infiles): nfile = 1 self.infiles = [self.infiles] else: nfile = len(self.infiles) for name in ['field', 'spw', 'antenna', 'scanno']: param = getattr(self, name) if not self.__check_selection_length(param, nfile): raise ValueError, "Length of %s != infiles." % (name) # set convsupport default if self.convsupport >= 0 and self.gridfunction.upper() != 'SF': casalog.post("user defined convsupport is ignored for %s kernel" % self.gridfunction, priority='WARN') self.convsupport = -1 def __format_spw_string(self, spw): """ Returns formatted spw selection string which is accepted by imager. """ if type(spw) != str: raise ValueError, "The parameter should be string." if spw.strip() == '*': spw = '' # WORKAROUND for CAS-6422, i.e., ":X~Y" fails while "*:X~Y" works. if spw.startswith(":"): spw = '*' + spw return spw def __format_quantum_unit(self, data, unit): """ Returns False if data has an unit which in not a variation of input unit. Otherwise, returns input data as a quantum string. The input unit is added to the return value if no unit is in data. """ my_qa = qatool() if data == '' or my_qa.compare(data, unit): return data if my_qa.getunit(data) == '': casalog.post("No unit specified. Using '%s'" % unit) return '%f%s' % (data, unit) return None def __check_selection_length(self, data, nfile): """ Returns true if data is either a string, an array with length 1 or nfile """ if not is_string_type(data) and len(data) not in [1, nfile]: return False return True def get_selection_param_for_ms(self, fileid, param): """ Returns valid selection string for a certain ms Arguments fileid : file idx in infiles list param : string (array) selection value """ if is_string_type(param): return param elif len(param) == 1: return param[0] else: return param[fileid] def get_selection_idx_for_ms(self, file_idx): """ Returns a dictionary of selection indices for i-th MS in infiles Argument: file idx in infiles list """ if file_idx < len(self.infiles) and file_idx > -1: vis = self.infiles[file_idx] field = self.get_selection_param_for_ms(file_idx, self.field) spw = self.get_selection_param_for_ms(file_idx, self.spw) spw = self.__format_spw_string(spw) antenna = self.get_selection_param_for_ms(file_idx, self.antenna) if antenna == -1: antenna = '' scan = self.get_selection_param_for_ms(file_idx, self.scanno) intent = self.get_selection_param_for_ms(file_idx, self.intent) my_ms = gentools(['ms'])[0] sel_ids = my_ms.msseltoindex(vis=vis, spw=spw, field=field, baseline=antenna, scan=scan) fieldid = list( sel_ids['field']) if len(sel_ids['field']) > 0 else -1 baseline = self.format_ac_baseline(sel_ids['antenna1']) scanid = list(sel_ids['scan']) if len(sel_ids['scan']) > 0 else "" # SPW (need to get a list of valid spws instead of -1) if len(sel_ids['channel']) > 0: spwid = [chanarr[0] for chanarr in sel_ids['channel']] elif spw == "": # No spw selection my_ms.open(vis) try: spwinfo = my_ms.getspectralwindowinfo() except: raise finally: my_ms.close() spwid = [int(idx) for idx in spwinfo.keys()] else: raise RuntimeError("Invalid spw selction, %s ,for MS %d" ( str(spw), file_idx)) return { 'field': fieldid, 'spw': spwid, 'baseline': baseline, 'scan': scanid, 'intent': intent, 'antenna1': sel_ids['antenna1'] } else: raise ValueError, ("Invalid file index, %d" % file_idx) def format_ac_baseline(self, in_antenna): """ format auto-correlation baseline string from antenna idx list """ # exact match string if is_string_type(in_antenna): if (len(in_antenna) != 0) and (in_antenna.find('&') == -1) \ and (in_antenna.find(';')==-1): in_antenna = + '&&&' return in_antenna # single integer -> list of int if type(in_antenna) == int: if in_antenna >= 0: in_antenna = [in_antenna] else: return -1 # format auto-corr string from antenna idices. baseline = '' for idx in in_antenna: if len(baseline) > 0: baseline += ';' if idx >= 0: baseline += (str(idx) + '&&&') return baseline def compile(self): # imaging mode self.imager_param['mode'] = self.mode # Work on selection of the first table in sorted list # to get default restfreq and outframe imhelper = cleanhelper(self.imager, self.infiles, casalog=casalog) imhelper.sortvislist(self.spw, self.mode, self.width) self.sorted_idx = imhelper.sortedvisindx selection_ids = self.get_selection_idx_for_ms(self.sorted_idx[0]) self.__update_subtable_name(self.infiles[self.sorted_idx[0]]) # field fieldid = selection_ids['field'][0] if type( selection_ids['field']) != int else selection_ids['field'] sourceid = -1 self.open_table(self.field_table) source_ids = self.table.getcol('SOURCE_ID') self.close_table() if self.field == '' or fieldid == -1: sourceid = source_ids[0] elif fieldid >= 0 and fieldid < len(source_ids): sourceid = source_ids[fieldid] else: raise ValueError, "No valid field in the first MS." # restfreq if self.restfreq == '' and self.source_table != '': self.open_table(self.source_table) source_ids = self.table.getcol('SOURCE_ID') for i in range(self.table.nrows()): if sourceid == source_ids[i] \ and self.table.iscelldefined('REST_FREQUENCY',i) \ and (selection_ids['spw'] == -1 or \ self.table.getcell('SPECTRAL_WINDOW_ID', i) in selection_ids['spw']): rf = self.table.getcell('REST_FREQUENCY', i) if len(rf) > 0: self.restfreq = self.table.getcell( 'REST_FREQUENCY', i)[0] break self.close_table() casalog.post("restfreq set to %s" % self.restfreq, "INFO") # REST_FREQUENCY column is optional (need retry if not exists) self.imager_param['restfreq'] = self.restfreq # # spw (define representative spw id = spwid_ref) spwid_ref = selection_ids['spw'][0] if type( selection_ids['spw']) != int else selection_ids['spw'] # Invalid spw selection should have handled at msselectiontoindex(). # -1 means all spw are selected. self.open_table(self.spw_table) if spwid_ref < 0: for id in range(self.table.nrows()): if self.table.getcell('NUM_CHAN', id) > 0: spwid_ref = id break if spwid_ref < 0: self.close_table() msg = 'No valid spw id exists in the first table' raise ValueError, msg self.allchannels = self.table.getcell('NUM_CHAN', spwid_ref) freq_chan0 = self.table.getcell('CHAN_FREQ', spwid_ref)[0] freq_inc0 = self.table.getcell('CHAN_WIDTH', spwid_ref)[0] # in case rest frequency is not defined yet. if self.restfreq == '': self.restfreq = '%fHz' % self.table.getcell( 'CHAN_FREQ', spwid_ref).mean() self.imager_param['restfreq'] = self.restfreq casalog.post( "Using mean freq of spw %d as restfreq: %s" % (spwid_ref, self.restfreq), "INFO") self.close_table() self.imager_param['spw'] = -1 #spwid_ref # outframe (force using the current frame) self.imager_param['outframe'] = self.outframe if self.outframe == '': if len(self.infiles) > 1: # The default will be 'LSRK' casalog.post( "Multiple MS inputs. The default outframe is set to 'LSRK'" ) self.imager_param['outframe'] = 'LSRK' else: # get from MS my_ms = gentools(['ms'])[0] my_ms.open(self.infiles[0]) spwinfo = my_ms.getspectralwindowinfo() my_ms.close() del my_ms for key, spwval in spwinfo.items(): if spwval['SpectralWindowId'] == spwid_ref: self.imager_param['outframe'] = spwval['Frame'] casalog.post("Using frequency frame of MS, '%s'" % self.imager_param['outframe']) break if self.imager_param['outframe'] == '': raise Exception, "Internal error of getting frequency frame of spw=%d." % spwid_ref else: casalog.post("Using frequency frame defined by user, '%s'" % self.imager_param['outframe']) # # antenna # in_antenna = self.antenna # backup for future use # if type(self.antenna)==int: # if self.antenna >= 0: # self.antenna=str(self.antenna)+'&&&' # else: # if (len(self.antenna) != 0) and (self.antenna.find('&') == -1) \ # and (self.antenna.find(';')==-1): # self.antenna = self.antenna + '&&&' def _configure_map_property(self): selection_ids = self.get_selection_idx_for_ms(self.sorted_idx[0]) # stokes if self.stokes == '': self.stokes = 'I' self.imager_param['stokes'] = self.stokes # gridfunction # outfile if os.path.exists(self.outfile) and self.overwrite: os.system('rm -rf %s' % (self.outfile)) if os.path.exists(self.outfile + '.weight') and self.overwrite: os.system('rm -rf %s' % (self.outfile + '.weight')) # cell cell = self.cell if cell == '' or cell[0] == '': # Calc PB grid_factor = 3. casalog.post( "The cell size will be calculated using PB size of antennas in the first MS" ) qPB = self._calc_PB(selection_ids['antenna1']) cell = '%f%s' % (qPB['value'] / grid_factor, qPB['unit']) casalog.post("Using cell size = PB/%4.2F = %s" % (grid_factor, cell)) (cellx, celly) = sdutil.get_cellx_celly(cell, unit='arcmin') self.imager_param['cellx'] = cellx self.imager_param['celly'] = celly # Calculate Pointing center and extent (if necessary) # return a dictionary with keys 'center', 'width', 'height' #imsize = self.imsize imsize = sdutil._to_list(self.imsize, int) or \ sdutil._to_list(self.imsize, numpy.integer) if imsize is None: imsize = self.imsize if hasattr(self.imsize, '__iter__') else [self.imsize] imsize = [int(numpy.ceil(v)) for v in imsize] casalog.post( "imsize is not integers. force converting to integer pixel numbers.", priority="WARN") casalog.post("rounded-up imsize: %s --> %s" % (str(self.imsize), str(imsize))) phasecenter = self.phasecenter if self.phasecenter == "" or \ len(imsize) == 0 or imsize[0] < 1: map_param = self._get_pointing_extent() # imsize if len(imsize) == 0 or imsize[0] < 1: imsize = self._get_imsize(map_param['width'], map_param['height'], cellx, celly) if self.phasecenter != "": casalog.post( "You defined phasecenter but not imsize. The image will cover as wide area as pointing in MS extends, but be centered at phasecenter. This could result in a strange image if your phasecenter is a part from the center of pointings", priority='WARN') if imsize[0] > 1024 or imsize[1] > 1024: casalog.post( "The calculated image pixel number is larger than 1024. It could take time to generate the image depending on your computer resource. Please wait...", priority='WARN') # phasecenter # if empty, it should be determined here... if self.phasecenter == "": phasecenter = map_param['center'] # imsize (nx, ny) = sdutil.get_nx_ny(imsize) self.imager_param['nx'] = nx self.imager_param['ny'] = ny # phasecenter self.imager_param['phasecenter'] = phasecenter self.imager_param['movingsource'] = self.ephemsrcname # channel map imhelper = cleanhelper(self.imager, self.infiles, casalog=casalog) imhelper.sortvislist(self.spw, self.mode, self.width) spwsel = str(',').join([str(spwid) for spwid in selection_ids['spw']]) srestf = self.imager_param['restfreq'] if is_string_type( self.imager_param['restfreq'] ) else "%fHz" % self.imager_param['restfreq'] (imnchan, imstart, imwidth) = imhelper.setChannelizeDefault( self.mode, spwsel, self.field, self.nchan, self.start, self.width, self.imager_param['outframe'], self.veltype, self.imager_param['phasecenter'], srestf) del imhelper # start and width if self.mode == 'velocity': startval = [self.imager_param['outframe'], imstart] widthval = imwidth elif self.mode == 'frequency': startval = [self.imager_param['outframe'], imstart] widthval = imwidth else: #self.mode==channel startval = int(self.start) widthval = int(self.width) if self.nchan < 0: self.nchan = self.allchannels self.imager_param['start'] = startval self.imager_param['step'] = widthval self.imager_param['nchan'] = imnchan #self.nchan def execute(self): # imaging casalog.post("Start imaging...", "INFO") if len(self.infiles) == 1: self.open_imager(self.infiles[0]) selection_ids = self.get_selection_idx_for_ms(0) spwsel = self.get_selection_param_for_ms(0, self.spw) if spwsel.strip() in ['', '*']: spwsel = selection_ids['spw'] ### TODO: channel selection based on spw ok = self.imager.selectvis( field=selection_ids['field'], #spw=selection_ids['spw'], spw=spwsel, nchan=-1, start=0, step=1, baseline=selection_ids['baseline'], scan=selection_ids['scan'], intent=selection_ids['intent']) if not ok: raise ValueError, "Selection is empty: you may want to review this MS selection" else: self.close_imager() #self.sorted_idx.reverse() for idx in self.sorted_idx.__reversed__(): name = self.infiles[idx] selection_ids = self.get_selection_idx_for_ms(idx) spwsel = self.get_selection_param_for_ms(idx, self.spw) if spwsel.strip() in ['', '*']: spwsel = selection_ids['spw'] ### TODO: channel selection based on spw self.imager.selectvis( vis=name, field=selection_ids['field'], #spw=selection_ids['spw'], spw=spwsel, nchan=-1, start=0, step=1, baseline=selection_ids['baseline'], scan=selection_ids['scan'], intent=selection_ids['intent']) # need to do this self.is_imager_opened = True # it should be called after infiles are registered to imager self._configure_map_property() casalog.post( "Using phasecenter \"%s\"" % (self.imager_param['phasecenter']), "INFO") self.imager.defineimage(**self.imager_param) #self.__get_param()) self.imager.setoptions(ftmachine='sd', gridfunction=self.gridfunction) self.imager.setsdoptions(pointingcolumntouse=self.pointingcolumn, convsupport=self.convsupport, truncate=self.truncate, gwidth=self.gwidth, jwidth=self.jwidth, minweight=0., clipminmax=self.clipminmax) self.imager.makeimage(type='singledish', image=self.outfile) weightfile = self.outfile + ".weight" self.imager.makeimage(type='coverage', image=weightfile) self.close_imager() if not os.path.exists(self.outfile): raise RuntimeError, "Failed to generate output image '%s'" % self.outfile if not os.path.exists(weightfile): raise RuntimeError, "Failed to generate weight image '%s'" % weightfile # Convert output images to proper output frame my_ia = gentools(['ia'])[0] my_ia.open(self.outfile) csys = my_ia.coordsys() csys.setconversiontype(spectral=csys.referencecode('spectra')[0]) my_ia.setcoordsys(csys.torecord()) my_ia.close() # Mask image pixels whose weight are smaller than minweight. # Weight image should have 0 weight for pixels below < minweight casalog.post("Start masking the map using minweight = %f" % \ self.minweight, "INFO") my_ia.open(weightfile) try: stat = my_ia.statistics(mask="'" + weightfile + "' > 0.0", robust=True) valid_pixels = stat['npts'] except RuntimeError, e: if e.message.find('No valid data found.') >= 0: valid_pixels = [0] else: raise e if len(valid_pixels) == 0 or valid_pixels[0] == 0: my_ia.close() casalog.post( "All pixels weight zero. This indicates no data in MS is in image area. Mask will not be set. Please check your image parameters.", "WARN") return median_weight = stat['median'][0] weight_threshold = median_weight * self.minweight casalog.post("Median of weight in the map is %f" % median_weight, \ "INFO") casalog.post("Pixels in map with weight <= median(weight)*minweight = %f will be masked." % \ (weight_threshold),"INFO") ###Leaving the original logic to calculate the number of masked pixels via ###product of median of and min_weight (which i don't understand the logic) ### if one wanted to find how many pixel were masked one could easily count the ### number of pixels set to false ### e.g after masking self.outfile below one could just do this ### nmasked_pixels=tb.calc('[select from "'+self.outfile+'"/mask0'+'" giving [nfalse(PagedArray )]]') my_tb = gentools(['tb'])[0] nmask_pixels = 0 nchan = stat['trc'][3] + 1 casalog.filter('ERROR') ### hide the useless message of tb.calc ### doing it by channel to make sure it does not go out of memory ####tab.calc try to load the whole chunk in ram for k in range(nchan): nmask_pixels += my_tb.calc('[select from "' + weightfile + '" giving [ntrue(map[,,,' + str(k) + '] <=' + str(median_weight * self.minweight) + ')]]')['0'][0] casalog.filter() ####set logging back to normal casalog.filter() ####set logging back to normal imsize = numpy.product(my_ia.shape()) my_ia.close() # Modify default mask my_ia.open(self.outfile) my_ia.calcmask("'%s'>%f" % (weightfile, weight_threshold), asdefault=True) my_ia.close() masked_fraction = 100. * ( 1. - (imsize - nmask_pixels) / float(valid_pixels[0])) casalog.post("This amounts to %5.1f %% of the area with nonzero weight." % \ ( masked_fraction ),"INFO") casalog.post("The weight image '%s' is returned by this task, if the user wishes to assess the results in detail." \ % (weightfile), "INFO") # Calculate theoretical beam size casalog.post("Calculating image beam size.") if self.gridfunction.upper() not in ['SF']: casalog.post( "Beam size definition for '%s' kernel is experimental." % self.gridfunction, priority='WARN') casalog.post( "You may want to take careful look at the restoring beam in the image.", priority='WARN') my_msmd = gentools(['msmd'])[0] # antenna diameter and blockage ref_ms_idx = self.sorted_idx[0] ref_ms_name = self.infiles[ref_ms_idx] selection_ids = self.get_selection_idx_for_ms(ref_ms_idx) ant_idx = selection_ids['antenna1'] diameter = self._get_average_antenna_diameter(ant_idx) my_msmd.open(ref_ms_name) ant_name = my_msmd.antennanames(ant_idx) my_msmd.close() is_alma = False for name in ant_name: if name[0:2] in ["PM", "DV", "DA", "CM"]: is_alma = True break blockage = "0.75m" if is_alma else "0.0m" # unknown blockage diameter # output reference code my_ia.open(self.outfile) csys = my_ia.coordsys() my_ia.close() outref = csys.referencecode('direction')[0] cell = list(csys.increment(type='direction', format='s')['string']) # pointing sampling ref_ms_spw = self.get_selection_param_for_ms(ref_ms_idx, self.spw) ref_ms_field = self.get_selection_param_for_ms(ref_ms_idx, self.field) ref_ms_scan = self.get_selection_param_for_ms(ref_ms_idx, self.scanno) # xSampling, ySampling, angle = sdutil.get_ms_sampling_arcsec(ref_ms_name, spw=ref_ms_spw, # antenna=selection_ids['baseline'], # field=ref_ms_field, # scan=ref_ms_scan,#timerange='', # outref=outref) # obtain sampling interval for beam calculation. self.open_imager(ref_ms_name) ok = self.imager.selectvis( field=ref_ms_field, #spw=selection_ids['spw'], spw=ref_ms_spw, nchan=-1, start=0, step=1, baseline=selection_ids['baseline'], scan=ref_ms_scan, intent=selection_ids['intent']) if len(ant_idx) > 1: casalog.post( "Using only antenna %s to calculate sampling interval" % ant_name[0]) ptg_samp = self.imager.pointingsampling( pattern='raster', ref=outref, movingsource=self.ephemsrcname, pointingcolumntouse=self.pointingcolumn, antenna=('%s&&&' % ant_name[0])) self.close_imager() my_qa = qatool() xSampling, ySampling = my_qa.getvalue( my_qa.convert(ptg_samp['sampling'], 'arcsec')) angle = my_qa.getvalue(my_qa.convert(ptg_samp['angle'], "deg"))[0] casalog.post("Detected raster sampling = [%f, %f] arcsec" % (xSampling, ySampling)) # handling of failed sampling detection valid_sampling = True sampling = [xSampling, ySampling] if abs(xSampling) < 2.2e-3 or not numpy.isfinite(xSampling): casalog.post( "Invalid sampling=%s arcsec. Using the value of orthogonal direction=%s arcsec" % (xSampling, ySampling), priority="WARN") sampling = [ySampling] angle = 0.0 valid_sampling = False if abs(ySampling) < 1.0e-3 or not numpy.isfinite(ySampling): if valid_sampling: casalog.post( "Invalid sampling=%s arcsec. Using the value of orthogonal direction=%s arcsec" % (ySampling, xSampling), priority="WARN") sampling = [xSampling] angle = 0.0 valid_sampling = True # reduce sampling and cell if it's possible if len(sampling) > 1 and abs(sampling[0] - sampling[1]) <= 0.01 * abs(sampling[0]): sampling = [sampling[0]] angle = 0.0 if cell[0] == cell[1]: cell = [cell[0]] if valid_sampling: # actual calculation of beam size bu = sdbeamutil.TheoreticalBeam() bu.set_antenna(diameter, blockage) bu.set_sampling(sampling, "%fdeg" % angle) bu.set_image_param(cell, self.restfreq, self.gridfunction, self.convsupport, self.truncate, self.gwidth, self.jwidth, is_alma) bu.summary() imbeam_dict = bu.get_beamsize_image() casalog.post("Setting image beam: major=%s, minor=%s, pa=%s" % ( imbeam_dict['major'], imbeam_dict['minor'], imbeam_dict['pa'], )) # set beam size to image my_ia.open(self.outfile) my_ia.setrestoringbeam(**imbeam_dict) my_ia.close() else: #BOTH sampling was invalid casalog.post( "Could not detect valid raster sampling. Exitting without setting beam size to image", priority='WARN')
raise Exception, 'Unable to continue with MMS processing' pdh.setupCluster('split') # Execute the jobs try: pdh.go() except Exception, instance: casalog.post('%s' % instance, 'ERROR') return False return True # Create local copies of some tools mtlocal = mttool() qalocal = qatool() mslocal = mstool() try: # Gather all the parameters in a dictionary. config = {} if keepflags: taqlstr = '' else: taqlstr = "NOT (FLAG_ROW OR ALL(FLAG))" if type(correlation) == list: correlation = ', '.join(correlation) correlation = correlation.upper()
def getPlotantsAntennaInfo(msname, log, exclude, checkbaselines): tb, me = gentools(['tb', 'me']) qa = qatool() telescope, arrayPos = getPlotantsObservatoryInfo(msname) arrayWgs84 = me.measure(arrayPos, 'WGS84') arrayLon, arrayLat, arrayAlt = [arrayWgs84[i]['value'] for i in ['m0','m1','m2']] # Open the ANTENNA subtable to get the names of the antennas in this MS and # their positions. Note that the entries in the ANTENNA subtable are pretty # much in random order, so antNames translates between their index and name # (e.g., index 11 = STD155). We'll need these indices for later, since the # main data table refers to the antennas by their indices, not names. anttabname = msname + '/ANTENNA' tb.open(anttabname) # Get antenna names from antenna table antNames = np.array(tb.getcol("NAME")).tolist() stationNames = np.array(tb.getcol("STATION")).tolist() if telescope == 'VLBA': # names = ant@station antNames = ['@'.join(antsta) for antsta in zip(antNames,stationNames)] # Get antenna positions from antenna table antPositions = np.array([me.position('ITRF', qa.quantity(x, 'm'), qa.quantity(y, 'm'), qa.quantity(z, 'm')) for (x, y, z) in tb.getcol('POSITION').transpose()]) tb.close() allAntIds = range(len(antNames)) if checkbaselines: # Get antenna ids from main table; this will add to runtime tb.open(msname) ants1 = tb.getcol('ANTENNA1') ants2 = tb.getcol('ANTENNA2') tb.close() antIdsUsed = list(set(np.append(ants1, ants2))) else: # use them all! antIdsUsed = allAntIds # handle exclude -- remove from antIdsUsed for antId in exclude: try: antNameId = antNames[antId] + " (id " + str(antId) + ")" antIdsUsed.remove(antId) casalog.post("Exclude antenna " + antNameId) except ValueError: casalog.post("Cannot exclude antenna " + antNameId + ": not in main table", "WARN") # apply antIdsUsed mask antNames = [antNames[i] for i in antIdsUsed] antPositions = [antPositions[i] for i in antIdsUsed] stationNames = [stationNames[i] for i in antIdsUsed] nAnts = len(antIdsUsed) print "Number of points being plotted:", nAnts casalog.post("Number of points being plotted: " + str(nAnts)) if nAnts == 0: # excluded all antennas return telescope, antNames, [], [], [] # Get the names, indices, and lat/lon/alt coords of "good" antennas. antWgs84s = np.array([me.measure(pos, 'WGS84') for pos in antPositions]) # Convert from lat, lon, alt to X, Y, Z (unless VLBA) # where X is east, Y is north, Z is up, # and 0, 0, 0 is the center # Note: this conversion is NOT exact, since it doesn't take into account # Earth's ellipticity! But it's close enough. if telescope == 'VLBA' and not log: antLons, antLats = [[pos[i] for pos in antWgs84s] for i in ['m0','m1']] antXs = [qa.convert(lon, 'deg')['value'] for lon in antLons] antYs = [qa.convert(lat, 'deg')['value'] for lat in antLats] else: antLons, antLats = [np.array( [pos[i]['value'] for pos in antWgs84s]) for i in ['m0','m1']] radE = 6370000. antXs = (antLons - arrayLon) * radE * np.cos(arrayLat) antYs = (antLats - arrayLat) * radE return telescope, antNames, antIdsUsed, antXs, antYs, stationNames