def polarisation(self): """ Produces individual images for Stokes Q,U, cleans them with the mask from Stokes I and combines them in a cube. Then uses RM-Synthesis to produce a Faraday cube and clean it. """ subs_setinit.setinitdirs(self) subs_setinit.setdatasetnamestomiriad(self) logger.info(' Polarisation imaging is going to be implemented later')
def reset(self): """ Function to reset the current step and remove all generated data. Be careful! Deletes all data generated in this step! """ subs_setinit.setinitdirs(self) subs_setinit.setdatasetnamestomiriad(self) logger.warning(' Deleting all self-calibrated data.') subs_managefiles.director(self, 'ch', self.selfcaldir) subs_managefiles.director(self, 'rm', self.selfcaldir + '/*')
def reset(self): """ Function to reset the current step and remove all generated data. Be careful! Deletes all data generated in this step! """ subs_setinit.setinitdirs(self) subs_setinit.setdatasetnamestomiriad(self) logger.warning('Deleting all data products ready for transfer!') subs_managefiles.director(self, 'ch', self.basedir) subs_managefiles.director(self, 'rm', self.transferdir)
def flagline(self): """ Creates an image cube of the different chunks and measures the rms in each channel. All channels with an rms outside of a given sigma interval are flagged in the continuum calibration, but are still used for line imaging. """ if self.selfcal_flagline: subs_setinit.setinitdirs(self) subs_setinit.setdatasetnamestomiriad(self) logger.info(' Automatic flagging of HI-line/RFI started') subs_managefiles.director(self, 'ch', self.selfcaldir) for chunk in self.list_chunks(): subs_managefiles.director(self, 'ch', self.selfcaldir + '/' + str(chunk)) logger.info('Looking through data chunk ' + str(chunk) + ' #') invert = lib.miriad('invert') invert.vis = chunk + '.mir' invert.map = 'map' invert.beam = 'beam' invert.imsize = self.selfcal_image_imsize invert.cell = self.selfcal_image_cellsize invert.stokes = 'ii' invert.slop = 1 invert.go() if os.path.exists('map'): fits = lib.miriad('fits') fits.in_ = 'map' fits.op = 'xyout' fits.out = 'map.fits' fits.go() cube = pyfits.open('map.fits') data = cube[0].data std = np.nanstd(data, axis=(0, 2, 3)) median = np.median(std) stdall = np.nanstd(std) diff = std - median detections = np.where(np.abs(self.selfcal_flagline_sigma * diff) > stdall)[0] if len(detections) > 0: logger.info('Found high noise in channel(s) ' + str(detections).lstrip('[').rstrip(']') + ' #') for d in detections: uvflag = lib.miriad('uvflag') uvflag.vis = chunk + '.mir' uvflag.flagval = 'flag' uvflag.line = "'" + 'channel,1,' + str(d + 1) + "'" uvflag.go() logger.info( 'Flagged channel(s) ' + str(detections).lstrip('[').rstrip(']') + ' in data chunk ' + str( chunk) + ' #') else: logger.info('No high noise found in data chunk ' + str(chunk) + ' #') subs_managefiles.director(self, 'rm', self.selfcaldir + '/' + str(chunk) + '/' + 'map') subs_managefiles.director(self, 'rm', self.selfcaldir + '/' + str(chunk) + '/' + 'map.fits') subs_managefiles.director(self, 'rm', self.selfcaldir + '/' + str(chunk) + '/' + 'beam') else: logger.info(' No data in chunk ' + str(chunk) + '!') logger.info(' Automatic flagging of HI-line/RFI done')
def list_chunks(self): """ Checks how many chunk directories exist and returns a list of them. """ subs_setinit.setinitdirs(self) subs_setinit.setdatasetnamestomiriad(self) for n in range(100): if os.path.exists(self.selfcaldir + '/' + str(n).zfill(2)): pass else: break # Stop the counting loop at the directory you cannot find anymore chunks = range(n) chunkstr = [str(i).zfill(2) for i in chunks] return chunkstr
def check_starting_conditions(self): """ Check that the miriad file from convert exists. If it does not exists, none of the subsequent tasks in go need to be executed. This seems necessary as not all the tasks do this check and they do not have to. A single task is enough. Not sure if it is necessary to add all the param variables from selfcal and set them False if the check fails. For now, just use the main one Args: self Return: (bool): True if file is found, otherwise False """ logger.info( "Beam {}: Checking starting conditions for TRANSFER".format( self.beam)) # initial setup subs_setinit.setinitdirs(self) subs_setinit.setdatasetnamestomiriad(self) # path to converted miriad file mir_file = os.path.join(self.crosscaldir, self.target) # check that the file exists if os.path.isdir(mir_file): # miriad file exists logger.info( "Beam {}: Checking starting conditions for TRANSFER ... Done: All good." .format(self.beam)) return True else: # miriad file does not exists logger.warning( "Beam {}: Checking starting conditions for TRANSFER ... Done: Failed" .format(self.beam)) logger.warning( "Beam {}: Did not find main miriad file in {}".format( self.beam, mir_file)) return False
def reset(self): """ Function to reset the current step and remove all generated data. Be careful! Deletes all data generated in this step! """ subs_setinit.setinitdirs(self) subs_setinit.setdatasetnamestomiriad(self) if os.path.isdir(self.mosdir): logger.warning('Deleting all mosaicked data products.') subs_managefiles.director(self, 'ch', self.basedir) subs_managefiles.director(self, 'rm', self.mosdir) logger.warning( 'Deleting all parameter file entries for MOSAIC module') subs_param.del_param(self, 'mosaic_continuum_mf_status') subs_param.del_param(self, 'mosaic_continuum_mf_continuumstatus') subs_param.del_param(self, 'mosaic_continuum_mf_copystatus') subs_param.del_param(self, 'mosaic_continuum_mf_convolstatus') subs_param.del_param(self, 'mosaic_continuum_mf_continuumbeamparams') subs_param.del_param(self, 'mosaic_continuum_mf_continuumimagestats') else: logger.warning('Mosaicked data products are not present!')
def splitdata(self): """ Applies calibrator corrections to data, splits the data into chunks in frequency and bins it to the given frequency resolution for the self-calibration """ if self.selfcal_splitdata: subs_setinit.setinitdirs(self) subs_setinit.setdatasetnamestomiriad(self) subs_managefiles.director(self, 'ch', self.selfcaldir) logger.info(' Splitting of target data into individual frequency chunks started') if os.path.exists(self.selfcaldir + '/' + self.target): logger.info('Calibrator corrections already seem to have been applied #') else: logger.info('Applying calibrator solutions to target data before averaging #') uvaver = lib.miriad('uvaver') uvaver.vis = self.crosscaldir + '/' + self.target uvaver.out = self.selfcaldir + '/' + self.target uvaver.go() logger.info('Calibrator solutions to target data applied #') if self.selfcal_flagantenna != '': uvflag = lib.miriad('uvflag') uvflag.vis = self.selfcaldir + '/' + self.target uvflag.flagval = 'flag' uvflag.select = 'antenna(' + str(self.selfcal_flagantenna) + ')' uvflag.go() else: pass try: uv = aipy.miriad.UV(self.selfcaldir + '/' + self.target) except RuntimeError: raise ApercalException(' No data in your selfcal directory!') try: nsubband = len(uv['nschan']) # Number of subbands in data except TypeError: nsubband = 1 # Only one subband in data since exception was triggered logger.info('Found ' + str(nsubband) + ' subband(s) in target data #') counter = 0 # Counter for naming the chunks and directories for subband in range(nsubband): logger.info('Started splitting of subband ' + str(subband) + ' #') if nsubband == 1: numchan = uv['nschan'] finc = np.fabs(uv['sdf']) else: numchan = uv['nschan'][subband] # Number of channels per subband finc = np.fabs(uv['sdf'][subband]) # Frequency increment for each channel subband_bw = numchan * finc # Bandwidth of one subband subband_chunks = round(subband_bw / self.selfcal_splitdata_chunkbandwidth) # Round to the closest power of 2 for frequency chunks with the same bandwidth over the frequency # range of a subband subband_chunks = int(np.power(2, np.ceil(np.log(subband_chunks) / np.log(2)))) if subband_chunks == 0: subband_chunks = 1 chunkbandwidth = (numchan / subband_chunks) * finc logger.info('Adjusting chunk size to ' + str( chunkbandwidth) + ' GHz for regular gridding of the data chunks over frequency #') for chunk in range(subband_chunks): logger.info( 'Starting splitting of data chunk ' + str(chunk) + ' for subband ' + str(subband) + ' #') binchan = round( self.selfcal_splitdata_channelbandwidth / finc) # Number of channels per frequency bin chan_per_chunk = numchan / subband_chunks if chan_per_chunk % binchan == 0: # Check if the freqeuncy bin exactly fits logger.info('Using frequency binning of ' + str( self.selfcal_splitdata_channelbandwidth) + ' for all subbands #') else: # Increase the frequency bin to keep a regular grid for the chunks while chan_per_chunk % binchan != 0: binchan = binchan + 1 else: # Check if the calculated bin is not larger than the subband channel number if chan_per_chunk >= binchan: pass else: # Set the frequency bin to the number of channels in the chunk of the subband binchan = chan_per_chunk logger.info('Increasing frequency bin of data chunk ' + str( chunk) + ' to keep bandwidth of chunks equal over the whole bandwidth #') logger.info('New frequency bin is ' + str(binchan * finc) + ' GHz #') nchan = int(chan_per_chunk / binchan) # Total number of output channels per chunk start = 1 + chunk * chan_per_chunk width = int(binchan) step = int(width) subs_managefiles.director(self, 'mk', self.selfcaldir + '/' + str(counter).zfill(2)) uvaver = lib.miriad('uvaver') uvaver.vis = self.selfcaldir + '/' + self.target uvaver.out = self.selfcaldir + '/' + str(counter).zfill(2) + '/' + str(counter).zfill(2) + '.mir' uvaver.select = "'" + 'window(' + str(subband + 1) + ')' + "'" uvaver.line = "'" + 'channel,' + str(nchan) + ',' + str(start) + ',' + str(width) + ',' + str( step) + "'" uvaver.go() counter = counter + 1 logger.info('Splitting of data chunk ' + str(chunk) + ' for subband ' + str(subband) + ' done #') logger.info('Splitting of data for subband ' + str(subband) + ' done #') logger.info(' Splitting of target data into individual frequency chunks done')
def __init__(self, file_=None, **kwargs): self.default = lib.load_config(self, file_) subs_setinit.setinitdirs(self) subs_setinit.setdatasetnamestomiriad(self)
def run_continuum_minoriteration(self, chunk, majc, minc, drmin, theoretical_noise_threshold): """ Does a selfcal minor iteration for the standard mode chunk: The frequency chunk to image and calibrate maj: Current major iteration min: Current minor iteration drmin: maximum dynamic range for minor iteration theoretical_noise_threshold: calculated theoretical noise threshold """ subs_setinit.setinitdirs(self) subs_setinit.setdatasetnamestomiriad(self) logger.info('Minor self-calibration cycle ' + str(minc) + ' for frequency chunk ' + chunk + ' started #') if minc == 0: invert = lib.miriad('invert') # Create the dirty image invert.vis = chunk + '.mir' invert.map = str(majc).zfill(2) + '/map_' + str(minc).zfill(2) invert.beam = str(majc).zfill(2) + '/beam_' + str(minc).zfill(2) invert.imsize = self.selfcal_image_imsize invert.cell = self.selfcal_image_cellsize invert.stokes = 'ii' invert.options = 'mfs,double' invert.slop = 1 invert.robust = -2 invert.go() imax = self.calc_imax(str(majc).zfill(2) + '/map_' + str(minc).zfill(2)) noise_threshold = self.calc_noise_threshold(imax, minc, majc) dynamic_range_threshold = calc_dynamic_range_threshold(imax, drmin, self.selfcal_standard_minorcycle0_dr) mask_threshold, mask_threshold_type = calc_mask_threshold(theoretical_noise_threshold, noise_threshold, dynamic_range_threshold) logger.info('Mask threshold for major/minor cycle ' + str(majc) + '/' + str(minc) + ' set to ' + str( mask_threshold) + ' Jy/beam #') logger.info('Mask threshold set by ' + str(mask_threshold_type) + ' #') if majc == 0: maths = lib.miriad('maths') maths.out = str(majc).zfill(2) + '/mask_' + str(minc).zfill(2) maths.exp = '"<' + str(majc).zfill(2) + '/map_' + str(minc).zfill(2) + '>"' maths.mask = '"<' + str(majc).zfill(2) + '/map_' + str(minc).zfill(2) + '>.gt.' + str( mask_threshold) + '"' maths.go() logger.info('Mask with threshold ' + str(mask_threshold) + ' Jy/beam created #') else: subs_managefiles.director(self, 'cp', str(majc).zfill(2) + '/mask_' + str(minc).zfill(2), file_=str(majc - 1).zfill(2) + '/mask_' + str( self.selfcal_standard_minorcycle - 1).zfill(2)) logger.info('Mask from last minor iteration of last major cycle copied #') clean_cutoff = self.calc_clean_cutoff(mask_threshold) logger.info('Clean threshold at major/minor cycle ' + str(majc) + '/' + str(minc) + ' was set to ' + str( clean_cutoff) + ' Jy/beam #') clean = lib.miriad('clean') # Clean the image down to the calculated threshold clean.map = str(majc).zfill(2) + '/map_' + str(0).zfill(2) clean.beam = str(majc).zfill(2) + '/beam_' + str(0).zfill(2) clean.out = str(majc).zfill(2) + '/model_' + str(minc).zfill(2) clean.cutoff = clean_cutoff clean.niters = 1000000 clean.region = '"' + 'mask(' + str(majc).zfill(2) + '/mask_' + str(minc).zfill(2) + ')' + '"' clean.go() logger.info('Major/minor cycle ' + str(majc) + '/' + str(minc) + ' cleaning done #') restor = lib.miriad('restor') restor.model = str(majc).zfill(2) + '/model_' + str(minc).zfill(2) restor.beam = str(majc).zfill(2) + '/beam_' + str(0).zfill(2) restor.map = str(majc).zfill(2) + '/map_' + str(0).zfill(2) restor.out = str(majc).zfill(2) + '/image_' + str(minc).zfill(2) restor.mode = 'clean' restor.go() # Create the cleaned image logger.info('Cleaned image for major/minor cycle ' + str(majc) + '/' + str(minc) + ' created #') restor.mode = 'residual' restor.out = str(majc).zfill(2) + '/residual_' + str(minc).zfill(2) restor.go() logger.info('Residual image for major/minor cycle ' + str(majc) + '/' + str(minc) + ' created #') logger.info('Peak of the residual image is ' + str( self.calc_imax(str(majc).zfill(2) + '/residual_' + str(minc).zfill(2))) + ' Jy/beam #') logger.info('RMS of the residual image is ' + str( self.calc_irms(str(majc).zfill(2) + '/residual_' + str(minc).zfill(2))) + ' Jy/beam #') else: imax = self.calc_imax(str(majc).zfill(2) + '/map_' + str(0).zfill(2)) noise_threshold = self.calc_noise_threshold(imax, minc, majc) dynamic_range_threshold = calc_dynamic_range_threshold(imax, drmin, self.selfcal_standard_minorcycle0_dr) mask_threshold, mask_threshold_type = calc_mask_threshold(theoretical_noise_threshold, noise_threshold, dynamic_range_threshold) logger.info('Mask threshold for major/minor cycle ' + str(majc) + '/' + str(minc) + ' set to ' + str( mask_threshold) + ' Jy/beam #') logger.info('Mask threshold set by ' + str(mask_threshold_type) + ' #') maths = lib.miriad('maths') maths.out = str(majc).zfill(2) + '/mask_' + str(minc).zfill(2) maths.exp = '"<' + str(majc).zfill(2) + '/image_' + str(minc - 1).zfill(2) + '>"' maths.mask = '"<' + str(majc).zfill(2) + '/image_' + str(minc - 1).zfill(2) + '>.gt.' + str( mask_threshold) + '"' maths.go() logger.info('Mask with threshold ' + str(mask_threshold) + ' Jy/beam created #') clean_cutoff = self.calc_clean_cutoff(mask_threshold) logger.info('Clean threshold at major/minor cycle ' + str(majc) + '/' + str(minc) + ' was set to ' + str( clean_cutoff) + ' Jy/beam #') clean = lib.miriad('clean') # Clean the image down to the calculated threshold clean.map = str(majc).zfill(2) + '/map_' + str(0).zfill(2) clean.beam = str(majc).zfill(2) + '/beam_' + str(0).zfill(2) clean.model = str(majc).zfill(2) + '/model_' + str(minc - 1).zfill(2) clean.out = str(majc).zfill(2) + '/model_' + str(minc).zfill(2) clean.cutoff = clean_cutoff clean.niters = 1000000 clean.region = '"' + 'mask(' + str(majc).zfill(2) + '/mask_' + str(minc).zfill(2) + ')' + '"' clean.go() logger.info('Major/minor cycle ' + str(majc) + '/' + str(minc) + ' cleaning done #') restor = lib.miriad('restor') restor.model = str(majc).zfill(2) + '/model_' + str(minc).zfill(2) restor.beam = str(majc).zfill(2) + '/beam_' + str(0).zfill(2) restor.map = str(majc).zfill(2) + '/map_' + str(0).zfill(2) restor.out = str(majc).zfill(2) + '/image_' + str(minc).zfill(2) restor.mode = 'clean' restor.go() # Create the cleaned image logger.info('Cleaned image for major/minor cycle ' + str(majc) + '/' + str(minc) + ' created #') restor.mode = 'residual' restor.out = str(majc).zfill(2) + '/residual_' + str(minc).zfill(2) restor.go() logger.info('Residual image for major/minor cycle ' + str(majc) + '/' + str(minc) + ' created #') logger.info('Peak of the residual image is ' + str( self.calc_imax(str(majc).zfill(2) + '/residual_' + str(minc).zfill(2))) + ' Jy/beam #') logger.info('RMS of the residual image is ' + str( self.calc_irms(str(majc).zfill(2) + '/residual_' + str(minc).zfill(2))) + ' Jy/beam #') logger.info('Minor self-calibration cycle ' + str(minc) + ' for frequency chunk ' + chunk + ' finished #')
def selfcal_standard(self): """ Executes the standard method of self-calibration with the given parameters """ subs_setinit.setinitdirs(self) subs_setinit.setdatasetnamestomiriad(self) logger.info(' Starting standard self calibration routine') subs_managefiles.director(self, 'ch', self.selfcaldir) for chunk in self.list_chunks(): logger.info('Starting standard self-calibration routine on frequency chunk ' + chunk + ' #') subs_managefiles.director(self, 'ch', self.selfcaldir + '/' + chunk) if os.path.isfile(self.selfcaldir + '/' + chunk + '/' + chunk + '.mir/visdata'): theoretical_noise = calc_theoretical_noise(self.selfcaldir + '/' + chunk + '/' + chunk + '.mir') logger.info('Theoretical noise for chunk ' + chunk + ' is ' + str(theoretical_noise) + ' Jy/beam #') theoretical_noise_threshold = self.calc_theoretical_noise_threshold(theoretical_noise) logger.info('Your theoretical noise threshold will be ' + str( self.selfcal_standard_nsigma) + ' times the theoretical noise corresponding to ' + str( theoretical_noise_threshold) + ' Jy/beam #') dr_list = calc_dr_maj(self.selfcal_standard_drinit, self.selfcal_standard_dr0, self.selfcal_standard_majorcycle, self.selfcal_standard_majorcycle_function) logger.info( 'Your dynamic range limits are set to ' + str(dr_list) + ' for the major self-calibration cycles #') for majc in range(self.selfcal_standard_majorcycle): logger.info( 'Major self-calibration cycle ' + str(majc) + ' for frequency chunk ' + chunk + ' started #') subs_managefiles.director(self, 'mk', self.selfcaldir + '/' + str(chunk) + '/' + str(majc).zfill(2)) # Calculate the dynamic ranges during minor cycles dr_minlist = self.calc_dr_min(dr_list, majc, self.selfcal_standard_minorcycle, self.selfcal_standard_minorcycle_function) logger.info('The minor cycle dynamic range limits for major cycle ' + str(majc) + ' are ' + str( dr_minlist) + ' #') for minc in range(self.selfcal_standard_minorcycle): try: self.run_continuum_minoriteration(chunk, majc, minc, dr_minlist[minc], theoretical_noise_threshold) except Exception: logger.warning('Chunk ' + chunk + ' does not seem to contain data to image #') break try: logger.info('Doing self-calibration with uvmin=' + str( self.selfcal_standard_uvmin[majc]) + ', uvmax=' + str( self.selfcal_standard_uvmax[majc]) + ', solution interval=' + str( self.selfcal_standard_solint[majc]) + ' minutes for major cycle ' + str(majc).zfill( 2) + ' #') selfcal = lib.miriad('selfcal') selfcal.vis = chunk + '.mir' selfcal.select = '"' + 'uvrange(' + str(self.selfcal_standard_uvmin[majc]) + ',' + str( self.selfcal_standard_uvmax[majc]) + ')"' selfcal.model = str(majc).zfill(2) + '/model_' + str(minc).zfill(2) selfcal.interval = self.selfcal_standard_solint[majc] # Choose reference antenna if given if self.selfcal_refant == '': pass else: selfcal.refant = self.selfcal_refant # Enable amplitude calibration if triggered if not self.selfcal_standard_amp: # See if we want to do amplitude calibration selfcal.options = 'mfs,phase' elif self.selfcal_standard_amp: selfcal.options = 'mfs,amp' elif self.selfcal_standard_amp == 'auto': modelflux = self.calc_isum(str(majc).zfill(2) + '/model_' + str(minc).zfill(2)) if modelflux >= self.selfcal_standard_amp_auto_limit: logger.info( 'Flux of clean model is ' + str(modelflux) + ' Jy. Doing amplitude calibration. #') selfcal.options = 'mfs,amp' else: selfcal.options = 'mfs,phase' if self.selfcal_standard_nfbin >= 1: selfcal.nfbin = self.selfcal_standard_nfbin selfcal.go() logger.info('Major self-calibration cycle ' + str( majc) + ' for frequency chunk ' + chunk + ' finished #') except Exception: logger.warning( 'Model for self-calibration not found. No further calibration on this chunk possible!') break logger.info('Standard self-calibration routine for chunk ' + chunk + ' finished #') else: logger.warning('No data in chunk ' + chunk + '. Maybe all data is flagged? #') logger.info(' Standard self calibration routine finished')
def parametric(self): """ Parametric self calibration using an NVSS/FIRST skymodel and calculating spectral indices by source matching with WENSS. """ if self.selfcal_parametric: subs_setinit.setinitdirs(self) subs_setinit.setdatasetnamestomiriad(self) logger.info(' Doing parametric self calibration') subs_managefiles.director(self, 'ch', self.selfcaldir) for chunk in self.list_chunks(): logger.info('Starting parametric self calibration routine on chunk ' + chunk + ' #') subs_managefiles.director(self, 'ch', self.selfcaldir + '/' + chunk) subs_managefiles.director(self, 'mk', self.selfcaldir + '/' + chunk + '/' + 'pm') parametric_textfile = lsm.lsm_model(chunk + '.mir', self.selfcal_parametric_skymodel_radius, self.selfcal_parametric_skymodel_cutoff, self.selfcal_parametric_skymodel_distance) lsm.write_model(self.selfcaldir + '/' + chunk + '/' + 'pm' + '/model.txt', parametric_textfile) logger.info('Creating model from textfile model.txt for chunk ' + chunk + ' #') uv = aipy.miriad.UV(self.selfcaldir + '/' + chunk + '/' + chunk + '.mir') freq = uv['sfreq'] uvmodel = lib.miriad('uvmodel') uvmodel.vis = chunk + '.mir' parametric_modelfile = open(self.selfcaldir + '/' + str(chunk) + '/' + 'pm' + '/model.txt', 'r') for n, source in enumerate(parametric_modelfile.readlines()): if n == 0: uvmodel.options = 'replace,mfs' else: uvmodel.options = 'add,mfs' uvmodel.offset = source.split(',')[0] + ',' + source.split(',')[1] uvmodel.flux = source.split(',')[2] + ',i,' + str(freq) + ',' + source.split(',')[4].rstrip( '\n') + ',0,0' uvmodel.out = 'pm/tmp' + str(n) uvmodel.go() uvmodel.vis = uvmodel.out subs_managefiles.director(self, 'rn', 'pm/model', uvmodel.out) # Rename the last modelfile to model subs_managefiles.director(self, 'rm', 'pm/tmp*') # Remove all the obsolete modelfiles logger.info('Doing parametric self-calibration on chunk {} with solution interval {} min' 'and uvrange limits of {}~{} klambda #'.format(chunk, self.selfcal_parametric_solint, self.selfcal_parametric_uvmin, self.selfcal_parametric_uvmax)) selfcal = lib.miriad('selfcal') selfcal.vis = chunk + '.mir' selfcal.model = 'pm/model' selfcal.interval = self.selfcal_parametric_solint selfcal.select = "'" + 'uvrange(' + str(self.selfcal_parametric_uvmin) + ',' + str( self.selfcal_parametric_uvmax) + ')' + "'" # Choose reference antenna if given if self.selfcal_refant == '': pass else: selfcal.refant = self.selfcal_refant # Do amplitude calibration if wanted if self.selfcal_parametric_amp: selfcal.options = 'mfs,amp' else: selfcal.options = 'mfs' selfcal.go() logger.info('Parametric self calibration routine on chunk ' + chunk + ' done! #') logger.info(' Parametric self calibration done') else: logger.info(' Parametric self calibration disabled')
def convert_selfcaluv2uvfits(self): """ Looks for the last self-calibrated uv-fits file, copies its gains over to the original file, applies them and coverts to UVFITS format """ subs_setinit.setinitdirs(self) sbeam = 'selfcal_B' + str(self.beam).zfill(2) tbeam = 'transfer_B' + str(self.beam).zfill(2) # Create the parameters for the parameter file for the conversion of the UVFITS-files transfertargetbeamsselfcaluv2uvfitsstatus = get_param_def( self, tbeam + '_targetbeams_selfcaluv2uvfits_status', False) if self.transfer_convert_selfcaluv2uvfits: subs_setinit.setinitdirs(self) subs_setinit.setdatasetnamestomiriad(self) subs_managefiles.director(self, 'ch', self.transferdir, verbose=True) if not transfertargetbeamsselfcaluv2uvfitsstatus: # Get the status of the selfcal for the specified beam selfcaltargetbeamsphasestatus = get_param_def( self, sbeam + '_targetbeams_phase_status', False) selfcaltargetbeamsampstatus = get_param_def( self, sbeam + '_targetbeams_amp_status', False) datasetname_amp = os.path.join( self.selfcaldir, self.target).rstrip('.mir') + '_amp.mir' datasetname_phase = os.path.join(self.selfcaldir, self.target) logger.debug("Setting amplitude selfcal file name: {}".format( datasetname_amp)) logger.debug("Setting phase selfcal file name: {}".format( datasetname_phase)) # datasetname_amp = self.get_target_path().rstrip('.mir') + '_amp.mir' # datasetname_phase = self.get_target_path() if os.path.isdir( datasetname_amp) and selfcaltargetbeamsampstatus: logger.info('Beam ' + self.beam + ': Using amplitude self-calibrated dataset!') dataset = datasetname_amp elif os.path.isdir( datasetname_phase) and selfcaltargetbeamsphasestatus: logger.info( 'Beam ' + self.beam + ': Using phase self-calibrated dataset. Amplitude calibration was not successful or not wanted!' ) dataset = datasetname_phase else: dataset = None if dataset is not None: # Copy the raw dataset to the transfer directory subs_managefiles.director( self, 'cp', self.transferdir + '/' + self.target, file_=self.crosscaldir + '/' + self.target) if selfcaltargetbeamsampstatus: gpcopy = lib.miriad('gpcopy') gpcopy.vis = datasetname_phase gpcopy.out = self.transferdir + '/' + self.target gpcopy.go() uvaver = lib.miriad('uvaver') uvaver.vis = self.transferdir + '/' + self.target uvaver.out = self.transferdir + '/' + \ self.target.rstrip('.mir') + '_phase.mir' uvaver.go() gpcopy = lib.miriad('gpcopy') gpcopy.vis = datasetname_amp gpcopy.out = self.transferdir + '/' + \ self.target.rstrip('.mir') + '_phase.mir' gpcopy.go() fits = lib.miriad('fits') fits.op = 'uvout' fits.in_ = self.transferdir + '/' + \ self.target.rstrip('.mir') + '_phase.mir' fits.out = self.transferdir + '/' + \ self.target.rstrip('.mir') + '.UVFITS' fits.go() if os.path.isfile(self.transferdir + '/' + self.target.rstrip('.mir') + '.UVFITS'): subs_managefiles.director( self, 'rm', self.transferdir + '/' + self.target) subs_managefiles.director( self, 'rm', self.transferdir + '/' + self.target.rstrip('.mir') + '_phase.mir') transfertargetbeamsselfcaluv2uvfitsstatus = True else: logger.error( 'Beam ' + self.beam + ': Conversion was not successful. No UVFITS-file generated!' ) transfertargetbeamsselfcaluv2uvfitsstatus = False elif selfcaltargetbeamsphasestatus: gpcopy = lib.miriad('gpcopy') gpcopy.vis = datasetname_phase gpcopy.out = self.transferdir + '/' + self.target gpcopy.go() fits = lib.miriad('fits') fits.op = 'uvout' fits.in_ = self.transferdir + '/' + self.target fits.out = self.transferdir + '/' + \ self.target.rstrip('.mir') + '.UVFITS' fits.go() if os.path.isfile(self.transferdir + '/' + self.target.rstrip('.mir') + '.UVFITS'): subs_managefiles.director( self, 'rm', self.transferdir + '/' + self.target) transfertargetbeamsselfcaluv2uvfitsstatus = True else: logger.error( 'Beam ' + self.beam + ': Conversion was not successful. No UVFITS-file generated!' ) transfertargetbeamsselfcaluv2uvfitsstatus = False else: logger.error( 'Beam ' + self.beam + ': Self-calibration was not successful. No conversion to UVFITS-format possible!' ) transfertargetbeamsselfcaluv2uvfitsstatus = False else: logger.info( 'Beam ' + self.beam + ': Conversion of final calibrated data to UVFITS-format already successfully executed!' ) else: logger.info( 'Beam ' + self.beam + ': Conversion of final calibrated data to UVFITS-format not selected!' ) # Save the derived parameters to the parameter file subs_param.add_param(self, tbeam + '_targetbeams_selfcaluv2uvfits_status', transfertargetbeamsselfcaluv2uvfitsstatus)
def mosaic_continuum_mf(self): """Looks for all available stacked continuum images and mosaics them into one large image.""" subs_setinit.setinitdirs(self) subs_setinit.setdatasetnamestomiriad(self) ########################################################################################################## # Check if the parameter is already in the parameter file and load it otherwise create the needed arrays # ########################################################################################################## mosaiccontinuummfstatus = get_param_def( self, 'mosaic_continuum_mf_status', False) # Status of the continuum mf mosaic mosaiccontinuummfcontinuumstatus = get_param_def( self, 'mosaic_continuum_mf_continuumstatus', np.full(self.NBEAMS, False)) # Status of the continuum imaging mosaiccontinuummfcopystatus = get_param_def( self, 'mosaic_continuum_mf_copystatus', np.full(self.NBEAMS, False)) # Status of the copy of the images mosaiccontinuummfconvolstatus = get_param_def( self, 'mosaic_continuum_mf_convolstatus', np.full(self.NBEAMS, False)) # Status of the convolved images mosaiccontinuummfcontinuumbeamparams = get_param_def( self, 'mosaic_continuum_mf_continuumbeamparams', np.full((self.NBEAMS, 3), np.nan)) # Beam sizes of the input images mosaiccontinuummfcontinuumimagestats = get_param_def( self, 'mosaic_continuum_mf_continuumimagestats', np.full((self.NBEAMS, 3), np.nan)) # Image statistics of the input images # Start the mosaicking of the stacked continuum images if self.mosaic_continuum_mf: subs_setinit.setinitdirs(self) subs_setinit.setdatasetnamestomiriad(self) subs_managefiles.director(self, 'ch', self.mosdir + '/continuum') if not mosaiccontinuummfstatus: logger.info('Mosaicking multi-frequency continuum images') # Acquire the results and statistics from continuum mf imaging for b in range(self.NBEAMS): mosaiccontinuummfcontinuumstatus[b] = get_param_def( self, 'continuum_B' + str(b).zfill(2) + '_targetbeams_mf_status', False) if mosaiccontinuummfcontinuumstatus[b]: finalminor = get_param_def( self, 'continuum_B' + str(b).zfill(2) + '_targetbeams_mf_final_minorcycle', np.nan) subs_managefiles.director( self, 'cp', str(b).zfill(2) + '.fits', file_=self.basedir + str(b).zfill(2) + '/' + self.contsubdir + '/' + 'image_mf_' + str(finalminor).zfill(2) + '.fits') if os.path.isfile(str(b).zfill(2) + '.fits'): mosaiccontinuummfcopystatus[b] = True subs_convim.fitstomir( str(b).zfill(2) + '.fits', str(b).zfill(2)) subs_managefiles.director( self, 'rm', str(b).zfill(2) + '.fits') else: mosaiccontinuummfcopystatus[b] = False logger.warning('Beam ' + str(b).zfill(2) + ' was not copied successfully!') # Copy the images over to the mosaic directory for b in range(self.NBEAMS): if mosaiccontinuummfcontinuumstatus[ b] and mosaiccontinuummfcopystatus[b]: # Get the image beam parameters and the image statistics mosaiccontinuummfcontinuumimagestats[ b, :] = subs_imstats.getimagestats( self, str(b).zfill(2)) mosaiccontinuummfcontinuumbeamparams[ b, :] = subs_readmirhead.getbeamimage( str(b).zfill(2)) else: logger.warning( 'Skipping Beam ' + str(b).zfill(2) + '! Continuum mf-imaging was not successful or continuum image not available!' ) # Calculate the synthesised beam and reject outliers (algorithm needs to be updated) rejbeams, beamparams = subs_combim.calc_synbeam( mosaiccontinuummfcontinuumbeamparams) # Convolve all the images to the calculated beam for b in range(self.NBEAMS): if mosaiccontinuummfcontinuumstatus[ b] and mosaiccontinuummfcopystatus[b]: try: convol = lib.miriad('convol') convol.map = str(b).zfill(2) convol.fwhm = str(beamparams[0]) + ',' + str( beamparams[1]) convol.pa = str(beamparams[2]) convol.options = 'final' convol.out = str(b).zfill(2) + '_cv' convol.go() if os.path.isdir(str(b).zfill(2) + '_cv'): mosaiccontinuummfconvolstatus[b] = True else: mosaiccontinuummfconvolstatus[b] = False logger.warning( 'Beam ' + str(b).zfill(2) + ' could not be convolved to the calculated beam size! File not there!' ) except: mosaiccontinuummfconvolstatus[b] = False logger.warning( 'Beam ' + str(b).zfill(2) + ' could not be convolved to the calculated beam size!' ) # Combine all the images using linmos (needs to be updated with proper primary beam model) linmosimages = '' linmosrms = '' for b in range(self.NBEAMS): if mosaiccontinuummfcontinuumstatus[ b] and mosaiccontinuummfcopystatus[ b] and mosaiccontinuummfconvolstatus[b]: linmosimages = linmosimages + str(b).zfill(2) + '_cv,' linmosrms = linmosrms + str( subs_imstats.getimagestats( self, str(b).zfill(2) + '_cv')[2]) + ',' linmos = lib.miriad('linmos') linmos.in_ = linmosimages.rstrip(',') linmos.rms = linmosrms.rstrip(',') linmos.out = self.target.rstrip('.MS') + '_mf' linmos.go() if os.path.isdir(self.target.rstrip('.MS') + '_mf'): mosaiccontinuummfstatus = True subs_convim.mirtofits( self.target.rstrip('.MS') + '_mf', self.target.rstrip('.MS') + '_mf.fits') logger.info( 'Mosaicking of multi-frequency image successful!') else: mosaiccontinuummfstatus = False logger.error( 'Multi-freqeuncy mosaic was not created successfully!') else: mosaiccontinuummfstatus = True logger.info( 'Multi-frequency continuum mosaic was already successfully created!' ) # Save the derived parameters to the parameter file subs_param.add_param(self, 'mosaic_continuum_mf_status', mosaiccontinuummfstatus) subs_param.add_param(self, 'mosaic_continuum_mf_continuumstatus', mosaiccontinuummfcontinuumstatus) subs_param.add_param(self, 'mosaic_continuum_mf_copystatus', mosaiccontinuummfcopystatus) subs_param.add_param(self, 'mosaic_continuum_mf_convolstatus', mosaiccontinuummfconvolstatus) subs_param.add_param(self, 'mosaic_continuum_mf_continuumbeamparams', mosaiccontinuummfcontinuumbeamparams) subs_param.add_param(self, 'mosaic_continuum_mf_continuumimagestats', mosaiccontinuummfcontinuumimagestats)