################################################################################ # # task_swappol.py # # # Copyright (C) 2009 # Associated Universities, Inc. Washington DC, USA. # # This script is free software; you can redistribute it and/or modify it # under the terms of the GNU Library General Public License as published by # the Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This library is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public # License for more details. # # You should have received a copy of the GNU Library General Public License # along with this library; if not, write to the Free Software Foundation, # Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. # # Correspondence concerning AIPS++ should be adressed as follows: # Internet email: aips2-request@nrao.edu. # Postal address: AIPS++ Project Office # National Radio Astronomy Observatory # 520 Edgemont Road # Charlottesville, VA 22903-2475 USA # # # Huib Intema (NRAO) # # # # # # # # swappol stands for swap polarizations. # # # # task_swappol.py is a python script providing a task for swapping the R and L # (or X and Y) polarizations for a selection of antennas. This is particularly # useful for fixing VLA lowband observations from the commissioning period # (midway 2012 through midway 2013), where various antenna polarization cables # were mislabelled. # This task swaps polarizations in the raw visibilities 'DATA' column. This task # does not swap polarizations in calibration tables. It should therefore be run # prior to any calibration tasks. # # # # # # # # # To provide a CASA-alternative for the AIPS task SWPOL (or FIXRL). # # # # # ################################################################################ from taskinit import * import os, shutil, numpy, math, pdb ################################################################################ gigabyte = 1024L * 1024L * 1024L # bytes ################################################################################ def swappol( vis = '', outputvis = '', antenna = '', spw = '', field = '', scan = '', rows_per_block = 10000L, data_cache = gigabyte ): #, observation = '' ): # initialize task casalog.origin('swappol') ms_tool, md_tool, tb_tool = gentools( [ 'ms', 'msmd', 'tb' ] ) # define stokes ids stokes_dict = { 'I' : 1, 'Q' : 2, 'U' : 3, 'V' : 4, 'RR' : 5, 'RL' : 6, 'LR' : 7, 'LL' : 8, 'XX' : 9, 'XY' : 10, 'YX' : 11, 'YY' : 12 } stokes_full_RL_list = [ stokes_dict[ x ] for x in [ 'RR', 'RL', 'LR', 'LL' ] ] stokes_full_RL_list.sort() stokes_full_XY_list = [ stokes_dict[ x ] for x in [ 'XX', 'XY', 'YX', 'YY' ] ] stokes_full_XY_list.sort() # handle input & output MS names if ( ( len( vis ) == 0 ) or ( not os.path.exists( vis ) ) ): casalog.post( 'Input MS does not exist.', 'SEVERE' ) return False if ( ( outputvis != '' ) and ( outputvis != vis ) ): if ( os.path.exists( outputvis ) ): casalog.post( 'Output MS already exists. ' + 'Please remove or choose a different outputvis name.', 'SEVERE' ) return False if ( ( outputvis == '' ) or ( outputvis == vis ) ): casalog.post( 'Overwriting original MS ...', 'NORMAL' ) outputvis = vis # get MS info md_tool.open( vis ) antenna_count = md_tool.nantennas() spw_count = md_tool.nspw() field_count = md_tool.nfields() scan_count = md_tool.nscans() row_count = int( md_tool.nrows() ) # obs_count = ... md_tool.close() # parse data selection parameters ms_tool.open( vis ) selection = ms_tool.msseltoindex( vis = vis, baseline = antenna, spw = spw, field = field, scan = scan ) #, observation = observation ) antennas = selection[ 'antenna1' ] baselines = selection[ 'antenna2' ] spws = selection[ 'spw' ] fields = selection[ 'field' ] scans = selection[ 'scan' ] ms_tool.close() if ( antenna == '' ): casalog.post( "Antenna selection is empty.", 'SEVERE' ) return False if ( len( antennas ) == 0 ): casalog.post( "Antenna selection returned zero results.", 'SEVERE' ) return False if ( len( baselines ) != antenna_count ): casalog.post( "Antenna selection should not contain baseline selections.", 'SEVERE' ) return False if ( len( spws ) == 0 ): spws = numpy.arange( spw_count, dtype = spws.dtype ) if ( len( fields ) == 0 ): fields = numpy.arange( field_count, dtype = fields.dtype ) if ( len( scans ) == 0 ): # scans = numpy.arange( scan_count, dtype = scans.dtype ) scans = numpy.arange( 1000000L, dtype = scans.dtype ) # if ( len( obss ) == 0 ): # obss = numpy.arange( obs_count, dtype = obss.dtype ) # pdb.set_trace() # create data description id selection dd_table = read_table( vis + '/DATA_DESCRIPTION' ) spw_table = read_table( vis + '/SPECTRAL_WINDOW' ) pol_table = read_table( vis + '/POLARIZATION' ) dds = [] swap_table = [] for dd_id in range( len( dd_table ) ): spw_id = dd_table[ dd_id ][ 'SPECTRAL_WINDOW_ID' ] pol_id = dd_table[ dd_id ][ 'POLARIZATION_ID' ] # check if spw in selection if ( not spw_id in spws ): continue # check for flagged rows if ( dd_table[ dd_id ][ 'FLAG_ROW' ] or spw_table[ spw_id ][ 'FLAG_ROW' ] or pol_table[ pol_id ][ 'FLAG_ROW' ] ): # casalog.post( "Spectral window %d" % spw_id + " is flagged" + # " and will not be swapped." , 'WARN' ) continue pol_array = pol_table[ pol_id ][ 'CORR_TYPE' ] pol_list = pol_array.tolist() pol_list.sort() if ( ( pol_list != stokes_full_RL_list ) and ( pol_list != stokes_full_XY_list ) ): casalog.post( "Spectral window %d" % spw_id + " does not contain a " + "suitable set of polarization products to be swapped." , 'WARN' ) continue dds.append( dd_id ) dd_count = len( dds ) if ( dd_count == 0 ): casalog.post( "No polarizations found that can be swapped.", 'SEVERE') return False dds = numpy.array( dds, dtype = numpy.int32 ) # compute polarization permutation matrices # [ 0 ] for ANT1 only: PP,PQ,QP,QQ <-> QP,QQ,PP,PQ (2,3,0,1) # [ 1 ] for ANT2 only: PP,PQ,QP,QQ <-> PQ,PP,QQ,QP (1,0,3,2) # [ 2 ] for ANT1 & ANT2: PP,PQ,QP,QQ <-> QQ,QP,PQ,PP (3,2,1,0) perms = numpy.array( [ [ 2,3,0,1 ], [ 1,0,3,2 ], [ 3,2,1,0 ] ], dtype = numpy.int16 ) perm_count = len( perms ) dd_perms = numpy.zeros( ( dd_count, 3,4,4 ), dtype = numpy.bool ) for i in range( dd_count ): pol_id = dd_table[ dds[ i ] ][ 'POLARIZATION_ID' ] pols = pol_table[ pol_id ][ 'CORR_TYPE' ] pols = pols - pols.min() pols = pols.reshape( ( 1,4 ) ).repeat( 4, axis = 0 ) perms = numpy.array( perms, dtype = pols.dtype ) for j in range( perm_count ): perm = perms[ j ].reshape( ( 4,1 ) ).repeat( 4, axis = 1 ) dd_perms[ i, j ] = ( pols == perm ) # create selection masks from main table columns tb_tool.open( vis ) data = tb_tool.getcol( 'FLAG_ROW' ) mask = numpy.invert( data.transpose() ) data = tb_tool.getcol( 'FIELD_ID' ) mask = mask & numpy.in1d( data.transpose(), fields ) data = tb_tool.getcol( 'SCAN_NUMBER' ) mask = mask & numpy.in1d( data.transpose(), scans ) # data = tb_tool.getcol( 'OBSERVATION_ID' ) # mask = mask & numpy.in1d( data.transpose(), obss ) data = tb_tool.getcol( 'DATA_DESC_ID' ) ms_dd_id = data.transpose() mask = mask & numpy.in1d( ms_dd_id, dds ) data = tb_tool.getcol( 'ANTENNA1' ) mask_ant1 = numpy.in1d( data.transpose(), antennas ) data = tb_tool.getcol( 'ANTENNA2' ) mask_ant2 = numpy.in1d( data.transpose(), antennas ) tb_tool.close() mask = mask & ( mask_ant1 | mask_ant2 ) if ( not numpy.any( mask ) ): casalog.post( 'Selection did not yield any data to modify.', 'NORMAL' ) if ( outputvis != vis ): casalog.post( 'No data modified, therefore no outputvis created.', 'WARN' ) return True mask_perms = [] for i in range( dd_count ): mask_perm0 = mask & ( ms_dd_id == dds[ i ] ) & numpy.invert( mask_ant2 ) mask_perm1 = mask & ( ms_dd_id == dds[ i ] ) & numpy.invert( mask_ant1 ) mask_perm2 = mask & ( ms_dd_id == dds[ i ] ) & ( mask_ant1 & mask_ant2 ) mask_perms.append( [ mask_perm0, mask_perm1, mask_perm2 ] ) mask_perms = numpy.array( mask_perms, dtype = numpy.bool ) # create outputvis main table if ( outputvis != vis ): casalog.post( 'Copying original MS to outputvis ...', 'NORMAL' ) shutil.copytree( vis, outputvis ) # open outputvis main table for writing # limit memory usage for main data columns tb_tool.open( outputvis, nomodify = False ) #, lockoptions = 'user' ) tb_tool.setmaxcachesize( 'DATA', data_cache ) tb_tool.setmaxcachesize( 'FLAG', data_cache / 16 ) # tb_tool.setmaxcachesize( 'FLAG_CATEGORY', data_cache / ... ) # tb_tool.setmaxcachesize( 'WEIGHT_SPECTRUM', data_cache / ... ) tb_tool.lock() casalog.post( 'Processing visibilities ...', 'NORMAL' ) casalog.post( '... %3d percent done' % ( 0 ), 'NORMAL' ) # read per block block_count = int( math.ceil( float( row_count ) / float( rows_per_block ) ) ) blocks_done = 0L rows_done = 0L not_done = True while ( not_done ): # read data columns start_row = blocks_done * rows_per_block end_row = min( start_row + rows_per_block, row_count ) delta_rows = end_row - start_row if ( delta_rows < rows_per_block ): not_done = False if ( delta_rows <= 0 ): continue data = tb_tool.getcol( 'DATA', startrow = start_row, nrow = delta_rows ) ms_data = data.transpose() data = tb_tool.getcol( 'FLAG', startrow = start_row, nrow = delta_rows ) ms_flag = data.transpose() # data = tb_tool.getcol( 'FLAG_CATEGORY', startrow = start_row, nrow = delta_rows ) # ms_flag_cat = data.transpose() # data = tb_tool.getcol( 'WEIGHT_SPECTRUM', startrow = start_row, nrow = delta_rows ) # ms_weights = data.transpose() del data # modify data for i in range( dd_count ): for j in range( perm_count ): mask_perm = mask_perms[ i, j, start_row : end_row ] if ( numpy.any( mask_perm ) ): perm = dd_perms[ i, j ] ms_data[ mask_perm ] = numpy.dot( ms_data[ mask_perm ], perm ) ms_flag[ mask_perm ] = numpy.dot( ms_flag[ mask_perm ], perm ) # ms_flag_cat[ mask_perm ] = numpy.dot( ms_flag_cat[ mask_perm ], perm ) # ms_weights[ mask_perm ] = numpy.dot( ms_weights[ mask_perm ], perm ) # write modified data tb_tool.putcol( 'DATA', ms_data.transpose(), startrow = start_row, nrow = delta_rows ) tb_tool.putcol( 'FLAG', ms_flag.transpose(), startrow = start_row, nrow = delta_rows ) # tb_tool.putcol( 'FLAG_CATEGORY', ms_flag_cat.transpose(), startrow = start_row, # nrow = delta_rows ) # tb_tool.putcol( 'WEIGHT_SPECTRUM', ms_weights.transpose(), startrow = start_row, # nrow = delta_rows ) tb_tool.flush() del ms_data, ms_flag # del ms_flag_cat, ms_weights # track progress blocks_done = blocks_done + 1 casalog.post( '... %4d / %4d blocks done' % ( blocks_done, block_count ), 'DEBUGGING' ) fraction = float( end_row ) / float( row_count ) fraction = round( 10. * fraction ) / 10. delta = end_row - int( round( fraction * float( row_count ) ) ) if ( ( delta > 0 ) and ( delta < rows_per_block ) ): casalog.post( '... %3d percent done' % ( int( 100. * fraction ) ), 'NORMAL' ) # close outputvis main table casalog.post( '... %3d percent done' % ( 100 ), 'NORMAL' ) tb_tool.unlock() tb_tool.close() # fix SYSPOWER table too sp_table_path = vis + '/SYSPOWER' if ( not os.path.exists( sp_table_path ) ): return True tb_tool.open( sp_table_path, nomodify = False ) #, lockoptions = 'user' ) tb_tool.lock() casalog.post( 'Processing SYSPOWER table ...', 'NORMAL' ) ant_ids = tb_tool.getcol( 'ANTENNA_ID' ) mask = numpy.in1d( ant_ids.transpose(), antennas ) spw_ids = tb_tool.getcol( 'SPECTRAL_WINDOW_ID' ) mask = mask & numpy.in1d( spw_ids.transpose(), spws ) pdiff = tb_tool.getcol( 'SWITCHED_DIFF' ) pdiff[ : , mask ] = pdiff[ :: -1 , mask ] tb_tool.putcol( 'SWITCHED_DIFF', pdiff ) psum = tb_tool.getcol( 'SWITCHED_SUM' ) psum[ : , mask ] = psum[ :: -1 , mask ] tb_tool.putcol( 'SWITCHED_SUM', psum ) greq = tb_tool.getcol( 'REQUANTIZER_GAIN' ) greq[ : , mask ] = greq[ :: -1 , mask ] tb_tool.putcol( 'REQUANTIZER_GAIN', greq ) tb_tool.unlock() tb_tool.close() casalog.post( '... done', 'NORMAL' ) return True ################################################################################ def read_table( table_name ): skip_columns = [ 'ASSOC_SPW_ID', 'ASSOC_NATURE' ] # cause errors tb_tool, = gentools( [ 'tb' ] ) tb_tool.open( table_name ) column_names = tb_tool.colnames() for colname in skip_columns: if ( colname in column_names ): column_names.remove( colname ) column_count = len( column_names ) row_count = tb_tool.nrows() columns = [] for colname in column_names: try: column = tb_tool.getcol( colname ) except RuntimeError: column = numpy.array( [ [] for i in range( row_count ) ], dtype = numpy.float64 ) column = column.transpose() columns.append( column ) table = [] for row_id in range( row_count ): row = {} for col_id in range( column_count ): column = columns[ col_id ] value = ( column.transpose() )[ row_id ] row[ column_names[ col_id ] ] = value table.append( row ) tb_tool.close() return table ################################################################################