casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables
caltab_convert2.py
Go to the documentation of this file.
00001 
00002 # ------------------------------------------------------------------------------
00003 
00004 # caltab_convert2.py
00005 
00006 # NB:
00007 # 0. I threw this code together because it's temporary, so I'm not happy with
00008 #    the design.
00009 # 1. These functions are provided as a convenience to convert old-format
00010 #    caltables to new-format caltables.
00011 # 2. BPOLY and GSPLINE caltables are not supported.
00012 # 3. The information transferred should be enough for most calibration purposes.
00013 # 4. Simple bugs will be fixed.  If new features are required, however, you must
00014 #    recalculate a new-format caltable.
00015 
00016 # Modification history:
00017 # ---------------------
00018 # 2011 Jan 30 - Nick Elias, NRAO
00019 #               Initial version.
00020 
00021 # ------------------------------------------------------------------------------
00022 
00023 # Imports
00024 
00025 import os
00026 
00027 import numpy
00028 
00029 from casac import casac
00030 
00031 # ------------------------------------------------------------------------------
00032 
00033 # caltab_convert2
00034 
00035 # NB: I threw this code together because it's temporary, so I'm not happy with
00036 # the design.
00037 
00038 # NB: The type of the PARAM (and PARAMERR) columns in the new-format caltable
00039 # cannot be determined from the old-format caltable, so it must be supplied by
00040 # the user (see the inputs).  It is either 'float' or 'complex'.  It should be
00041 # easy to choose the correct value.  Delays, WVR, etc. type calibration data
00042 # correspond to 'float'.  Gains, bandpass, polarization, etc. type calibration
00043 # data correspond to 'complex'.  If you are not sure what to use, ask George
00044 # Moellenbrock or Nick Elias.
00045 
00046 # NB: If all of the values in the NUM_CHAN column of the old-format caltable
00047 # are 1, this function assumes that the calibration is averaged over frequency
00048 # for each spectral window.  The average frequency is the median over all
00049 # channels listed in the MS.  This scheme ignores user channel selection
00050 # information, which is not available.
00051 
00052 # NB: The REF_ANT column in the old-format caltable (analogous to the ANTENNA2
00053 # column in the new-format caltable) is messed up, which means that I fill
00054 # ANTENNA2 with -1.  Hopefully, that will not create a fatal problem.
00055 
00056 # Inputs:
00057 # -------
00058 # caltabold - The name of the old-format caltable.
00059 # ms        - The name of the MS associated with the old-format caltable.
00060 # pType     - The type of data in the PARAM column of the new-format caltable.
00061 #             The allowed types are 'float' and 'complex'.
00062 # caltabnew - The name of the new-format caltable.  It is optional.  The
00063 #             default is caltabold + '.new'.
00064 
00065 # Modification history:
00066 # ---------------------
00067 # 2012 Jan 30 - Nick Elias, NRAO
00068 #               Initial version.
00069 # 2012 Mar 26 - gmoellen: fixed header information
00070 # 2012 May 09 - gmoellen: added proper cal_desc_id->spw_id conversion
00071 #
00072 # ------------------------------------------------------------------------------
00073 
00074 def caltab_convert2( caltabold, ms, pType, caltabnew='' ):
00075 
00076         # Check the inputs
00077 
00078         if not os.path.exists( caltabold ):
00079                 raise IOError( 'Invalid old-format caltable.' )
00080 
00081         if not os.path.exists( ms ):
00082                 raise IOError( 'Invalid visibility file (MS).' )
00083 
00084         pTypeTemp = pType.strip().lower()
00085         if ( pTypeTemp != 'complex' and pTypeTemp != 'float' ):
00086                 raise Exception( 'Invalid parameter type ("complex" or "float").' )
00087 
00088         if caltabnew == '': caltabnew = caltabold + '.new'
00089         if os.path.exists( caltabnew ):
00090                 raise IOError( 'New-format caltable already exists.' )
00091 
00092 
00093         # Open the old-format caltable and get the number of rows
00094 
00095         tbOld = casac.table()
00096         tbOld.open( caltabold )
00097         nRow = tbOld.nrows()
00098 
00099         # Get spwid map from old CAL_DESC subtable
00100         tbCD = casac.table()
00101         tbCD.open( caltabold+'/CAL_DESC' )
00102         spwmap=tbCD.getcol('SPECTRAL_WINDOW_ID')[0,:]
00103         tbCD.close()
00104 
00105         # Create the empty new-format caltable with the correct number of rows
00106 
00107         tbNew = casac.table()
00108         tbNew.create( caltabnew, desc_new( pTypeTemp ) )
00109 
00110         tbNew.addrows( nRow )
00111 
00112 
00113         # Transfer most column information from the old-format caltable to the
00114         # new-format caltable.  NB: The REF_ANT column in the old-format
00115         # caltable (analogous to the ANTENNA2 column in the new-format caltable)
00116         # is messed up, which means that I fill ANTENNA2 with -1.
00117 
00118         tbNew.putcol( 'ANTENNA1', tbOld.getcol( 'ANTENNA1' ) )
00119         tbNew.putcol( 'ANTENNA2', -1.0*numpy.ones( nRow, dtype='int' ) )
00120         tbNew.putcol( 'FIELD_ID', tbOld.getcol( 'FIELD_ID' ) )
00121         tbNew.putcol( 'FLAG', tbOld.getcol( 'FLAG' ) )
00122         tbNew.putcol( 'INTERVAL', tbOld.getcol( 'INTERVAL' ) )
00123         tbNew.putcol( 'SNR', tbOld.getcol( 'SNR' ) )
00124         # Map CAL_DESC_ID to SPECTRAL_WINDOW_ID:
00125         tbNew.putcol( 'SPECTRAL_WINDOW_ID', spwmap[tbOld.getcol( 'CAL_DESC_ID' )] )
00126         tbNew.putcol( 'TIME', tbOld.getcol( 'TIME' ) )
00127         tbNew.putcol( 'WEIGHT', tbOld.getcol( 'FIT_WEIGHT' ) )
00128 
00129 
00130         # Transfer the parameter column from the old-format caltable to the
00131         # new-format caltable, taking the type into account.  No parameter
00132         # errors are present in the old-format caltable, so they are set to
00133         # 1.0 (+j0.0).
00134 
00135         param = tbOld.getcol( 'GAIN' )
00136         if pTypeTemp == 'float':
00137                 param = param.real
00138                 tbNew.putcol( 'FPARAM', param )
00139         else:
00140                 tbNew.putcol( 'CPARAM', param )
00141 
00142         tbNew.putcol( 'PARAMERR', -1.0*numpy.ones(param.shape,dtype='float') )
00143 
00144 
00145         # Determine the scans and put them into the new-format caltable
00146 
00147         scanTimes = get_scantimes( ms )
00148         keys = scanTimes.keys()
00149 
00150         times = tbOld.getcol( 'TIME' )
00151         scans = numpy.zeros( 0, dtype='int' )
00152 
00153         for t in times.tolist():
00154         
00155                 flag = False
00156 
00157                 for i in range( len(keys) ):
00158                         k = keys[i]
00159                         if t>=scanTimes[k]['min'] and t<scanTimes[k]['max']:
00160                                 flag = True
00161                                 scans = numpy.append( scans, k )
00162                                 break
00163                         if i == len(keys)-1: break
00164                         l = keys[i+1]
00165                         if t>=scanTimes[k]['max'] and t<scanTimes[l]['min']:
00166                                 flag = True
00167                                 scans = numpy.append( scans, l )
00168                                 break
00169 
00170                 if not flag: scans = numpy.append( scans, -1 )
00171 
00172         tbNew.putcol( 'SCAN_NUMBER', scans )
00173 
00174 
00175         # Copy the appropriate subcaltables from the MS to the new-format
00176         # caltable
00177 
00178         arg = 'cp -r ' + ms + '/ANTENNA ' + caltabnew
00179         os.system( arg )
00180 
00181         arg = 'cp -r ' + ms + '/FIELD ' + caltabnew
00182         os.system( arg )
00183 
00184 #       arg = 'cp -r ' + caltabold + '/CAL_HISTORY ' + caltabnew + '/HISTORY'
00185 #       os.system( arg )
00186 
00187         tbHis = casac.table()
00188         tbHis.open(ms+'/HISTORY')
00189         tbHis.copy(newtablename=caltabnew+'/HISTORY',deep=True,valuecopy=True,norows=True)
00190         tbHis.close()
00191         del tbHis
00192         
00193         arg = 'cp -r ' + ms + '/SPECTRAL_WINDOW ' + caltabnew \
00194                 + '/SPECTRAL_WINDOW'
00195         os.system( arg )
00196 
00197 
00198         # Add the info and keywords to the main table of the new-format caltable
00199         tabinfo=tbOld.info()
00200 
00201         tbNew.putinfo(tabinfo)
00202 
00203         if (pTypeTemp=='complex'):
00204                 tbNew.putkeyword( 'ParType', 'Complex' )
00205         if (pTypeTemp=='float'):
00206                 tbNew.putkeyword( 'ParType', 'Float' )
00207         
00208         tbNew.putkeyword( 'MSName', ms )
00209         tbNew.putkeyword( 'VisCal', tabinfo['subType'] )
00210                           
00211         polBasis = get_polbasis( ms )
00212         tbNew.putkeyword( 'PolBasis', polBasis )
00213 
00214         tbNew.putkeyword( 'ANTENNA', 'Table: ' + caltabnew + '/ANTENNA' )
00215         tbNew.putkeyword( 'FIELD', 'Table: ' + caltabnew + '/FIELD' )
00216         tbNew.putkeyword( 'HISTORY', 'Table: ' + caltabnew + '/HISTORY' )
00217         tbNew.putkeyword( 'SPECTRAL_WINDOW',
00218                 'Table: ' + caltabnew + '/SPECTRAL_WINDOW' )
00219 
00220 
00221         # Add the column keywords to the main table of the new-format caltable
00222 
00223         colList = ['INTERVAL', 'TIME']
00224 
00225         for col in colList:
00226                 colKeys = tbOld.getcolkeywords( col )
00227                 if colKeys != {}: tbNew.putcolkeywords( col, colKeys )
00228 
00229 
00230         # Close the old- and new- format caltables
00231 
00232         tbOld.close()
00233         del tbOld
00234 
00235         tbNew.close()
00236         del tbNew
00237 
00238 
00239         # Get the channel ranges from the CAL_DESC subtable of the old-format
00240         # caltable
00241 
00242         tbDesc = casac.table()
00243         tbDesc.open( caltabold + '/CAL_DESC' )
00244 
00245         nDesc = tbDesc.nrows()
00246         rDesc = range( nDesc )
00247 
00248         spwMap = tbDesc.getcol( 'SPECTRAL_WINDOW_ID' )[0]
00249 
00250         chanMin = numpy.zeros( nDesc, dtype='int' )
00251         chanMax = numpy.zeros( nDesc, dtype='int' )
00252 
00253         for d in rDesc:
00254                 chanRange = tbDesc.getcol( 'CHAN_RANGE', startrow=d, nrow=1 )
00255                 chanMin[d] = numpy.min( chanRange[0,:,:,:][0,:,0] )
00256                 chanMax[d] = numpy.max( chanRange[1,:,:,:][0,:,0] )
00257 
00258         if numpy.all( chanMax - chanMin + 1 == 1 ):
00259                 gain = True
00260         else:
00261                 gain = False
00262 
00263         tbDesc.close()
00264         del tbDesc
00265 
00266 
00267         # Modify the columns of the new-format caltable according to the
00268         # channel ranges
00269 
00270         tbSPW = casac.table()
00271         tbSPW.open( caltabnew + '/SPECTRAL_WINDOW', nomodify=False )
00272 
00273         for d in rDesc:
00274 
00275                 s = int( spwMap[d] )
00276 
00277                 nChan = int( chanMax[d] - chanMin[d] + 1 )
00278                 tbSPW.putcell( 'NUM_CHAN', s, nChan )
00279 
00280                 chanFreq = tbSPW.getcell( 'CHAN_FREQ', s )
00281                 if gain:
00282                         chanFreq = numpy.median( chanFreq )
00283                 else:
00284                         chanFreq = chanFreq[chanMin[d]:chanMax[d]+1]
00285                 tbSPW.putcell( 'CHAN_FREQ', s, chanFreq )
00286 
00287                 chanWidth = tbSPW.getcell( 'CHAN_WIDTH', s )
00288                 if gain:
00289                         chanWidth = numpy.sum( chanWidth )
00290                 else:
00291                         chanWidth = chanWidth[chanMin[d]:chanMax[d]+1]
00292                 tbSPW.putcell( 'CHAN_WIDTH', s, chanWidth )
00293                 tbSPW.putcell( 'EFFECTIVE_BW', s, chanWidth )
00294                 tbSPW.putcell( 'RESOLUTION', s, chanWidth )
00295 
00296                 totalBandwidth = numpy.sum( chanWidth )
00297                 tbSPW.putcell( 'TOTAL_BANDWIDTH', s, totalBandwidth )
00298 
00299         tbSPW.close()
00300         del tbSPW
00301 
00302 
00303         # Return True
00304 
00305         return True
00306 
00307 # ------------------------------------------------------------------------------
00308 
00309 def get_scantimes( ms ):
00310 
00311         # Open the MS
00312 
00313         tbHandle = casac.table()
00314         tbHandle.open( ms )
00315 
00316 
00317         # Get the time and scan columns
00318 
00319         times = tbHandle.getcol( 'TIME' )
00320         scans = tbHandle.getcol( 'SCAN_NUMBER' )
00321 
00322 
00323         # Assign each time to the proper scan
00324 
00325         d = dict()
00326 
00327         for r in range( tbHandle.nrows() ):
00328                 if not d.has_key( scans[r] ): d[scans[r]] = list()
00329                 d[scans[r]].append( times[r] )
00330 
00331         tbHandle.close()
00332         del tbHandle
00333 
00334 
00335         # Get the minimum and maximum time for each scan
00336 
00337         scanTimes = dict()
00338 
00339         for k in d.keys():
00340                 scanTimes[k] = dict()
00341                 scanTimes[k]['min'] = numpy.min( d[k] )
00342                 scanTimes[k]['max'] = numpy.max( d[k] )
00343 
00344 
00345         # Return the minimum and maximum time for each scan
00346 
00347         return scanTimes
00348 
00349 # ------------------------------------------------------------------------------
00350 
00351 def get_polbasis( ms ):
00352 
00353         # Open the MS
00354 
00355         tbHandle = casac.table()
00356         tbHandle.open( ms + '/FEED' )
00357 
00358 
00359         # Get the POLARIZATION_TYPE column
00360 
00361         pt = tbHandle.getcol( 'POLARIZATION_TYPE' )
00362 
00363 
00364         # Determine the polarization basis
00365 
00366         if pt[0,:][0] == 'R' or pt[1,:][0] == 'R':
00367                 polBasis = 'CIRCULAR'
00368         else:
00369                 polBasis = 'LINEAR'
00370 
00371 
00372         # Return the polarization basis
00373 
00374         return polBasis
00375 
00376 # ------------------------------------------------------------------------------
00377 
00378 def desc_new( pType ):
00379 
00380         desc = dict()
00381 
00382         desc['ANTENNA1'] = {'comment': '',
00383                 'dataManagerGroup': 'StandardStMan',
00384                 'dataManagerType': 'StandardStMan',
00385                 'maxlen': 0,
00386                 'option': 5,
00387                 'valueType': 'int'}
00388 
00389         desc['ANTENNA2'] = {'comment': '',
00390                 'dataManagerGroup': 'StandardStMan',
00391                 'dataManagerType': 'StandardStMan',
00392                 'maxlen': 0,
00393                 'option': 5,
00394                 'valueType': 'int'}
00395 
00396         desc['FIELD_ID'] = {'comment': '',
00397                 'dataManagerGroup': 'StandardStMan',
00398                 'dataManagerType': 'StandardStMan',
00399                 'maxlen': 0,
00400                 'option': 5,
00401                 'valueType': 'int'}
00402 
00403         desc['FLAG'] = {'comment': '',
00404                 'dataManagerGroup': 'StandardStMan',
00405                 'dataManagerType': 'StandardStMan',
00406                 'maxlen': 0,
00407                 'ndim': -1,
00408                 'option': 0,
00409                 'valueType': 'boolean'}
00410 
00411         desc['INTERVAL'] = {'comment': '',
00412                 'dataManagerGroup': 'StandardStMan',
00413                 'dataManagerType': 'StandardStMan',
00414                 'maxlen': 0,
00415                 'option': 5,
00416                 'valueType': 'double'}
00417 
00418         if pType.lower() == 'float':
00419                 desc['FPARAM'] = {'comment': '',
00420                         'dataManagerGroup': 'StandardStMan',
00421                         'dataManagerType': 'StandardStMan',
00422                         'maxlen': 0,
00423                         'ndim': -1,
00424                         'option': 0,
00425                         'valueType': 'float'}
00426         else:
00427                 desc['CPARAM'] = {'comment': '',
00428                         'dataManagerGroup': 'StandardStMan',
00429                         'dataManagerType': 'StandardStMan',
00430                         'maxlen': 0,
00431                         'ndim': -1,
00432                         'option': 0,
00433                         'valueType': 'complex'}
00434 
00435         desc['PARAMERR'] = {'comment': '',
00436                 'dataManagerGroup': 'StandardStMan',
00437                 'dataManagerType': 'StandardStMan',
00438                 'maxlen': 0,
00439                 'ndim': -1,
00440                 'option': 0,
00441                 'valueType': 'float'}
00442 
00443         desc['SCAN_NUMBER'] = {'comment': '',
00444                 'dataManagerGroup': 'StandardStMan',
00445                 'dataManagerType': 'StandardStMan',
00446                 'maxlen': 0,
00447                 'option': 5,
00448                 'valueType': 'int'}
00449 
00450         desc['SNR'] = {'comment': '',
00451                 'dataManagerGroup': 'StandardStMan',
00452                 'dataManagerType': 'StandardStMan',
00453                 'maxlen': 0,
00454                 'ndim': -1,
00455                 'option': 0,
00456                 'valueType': 'float'}
00457 
00458         desc['SPECTRAL_WINDOW_ID'] = {'comment': '',
00459                 'dataManagerGroup': 'StandardStMan',
00460                 'dataManagerType': 'StandardStMan',
00461                 'maxlen': 0,
00462                 'option': 5,
00463                 'valueType': 'int'}
00464 
00465         desc['TIME'] = {'comment': '',
00466                 'dataManagerGroup': 'StandardStMan',
00467                 'dataManagerType': 'StandardStMan',
00468                 'maxlen': 0,
00469                 'option': 5,
00470                 'valueType': 'double'}
00471 
00472         desc['WEIGHT'] = {'comment': '',
00473                 'dataManagerGroup': 'StandardStMan',
00474                 'dataManagerType': 'StandardStMan',
00475                 'maxlen': 0,
00476                 'ndim': -1,
00477                 'option': 0,
00478                 'valueType': 'float'}
00479 
00480         desc['_define_hypercolumn_'] = {}
00481 
00482         return desc
00483