00001 import numpy
00002 from asap import rcParams
00003 from asap.scantable import scantable
00004 from asap.selector import selector
00005 from asap._asap import stgrid, stgrid2
00006 import pylab as pl
00007 from logging import asaplog
00008
00009 class asapgrid_base(object):
00010 def __init__( self ):
00011 self.outfile = None
00012 self.ifno = None
00013 self.gridder = None
00014 self.infile = None
00015 self.scantab = None
00016
00017 def setData( self, infile ):
00018 raise NotImplementedError('setData is not implemented')
00019
00020 def setIF( self, ifno ):
00021 """
00022 Set IFNO to be processed. Currently, asapgrid allows to process
00023 only one IFNO for one gridding run even if the data contains
00024 multiple IFs. If you didn't specify IFNO, default value, which
00025 is IFNO in the first spectrum, will be processed.
00026
00027 ifno -- IFNO to be processed.
00028 """
00029 self.ifno = ifno
00030 self.gridder._setif( self.ifno )
00031
00032 def setPolList( self, pollist ):
00033 """
00034 Set list of polarization components you want to process.
00035 If not specified, all POLNOs will be processed.
00036
00037 pollist -- list of POLNOs.
00038 """
00039 self.gridder._setpollist( pollist )
00040
00041 def setScanList( self, scanlist ):
00042 """
00043 Set list of scans you want to process. If not specified, all
00044 scans will be processed.
00045
00046 scanlist -- list of SCANNOs.
00047 """
00048 self.gridder._setscanlist( scanlist )
00049
00050 def defineImage( self, nx=-1, ny=-1, cellx='', celly='', center='' ):
00051 """
00052 Define spatial grid.
00053
00054 First two parameters, nx and ny, define number of pixels of
00055 the grid. If which of those is not specified, it will be set
00056 to the same value as the other. If none of them are specified,
00057 it will be determined from map extent and cell size.
00058
00059 Next two parameters, cellx and celly, define size of pixel.
00060 You should set those parameters as string, which is constructed
00061 numerical value and unit, e.g. '0.5arcmin', or numerical value.
00062 If those values are specified as numerical value, their units
00063 will be assumed to 'arcsec'. If which of those is not specified,
00064 it will be set to the same value as the other. If none of them
00065 are specified, it will be determined from map extent and number
00066 of pixels, or set to '1arcmin' if neither nx nor ny is set.
00067
00068 The last parameter, center, define the central coordinate of
00069 the grid. You should specify its value as a string, like,
00070
00071 'J2000 05h08m50s -16d23m30s'
00072
00073 or
00074
00075 'J2000 05:08:50 -16.23.30'
00076
00077 You can omit equinox when you specify center coordinate. In that
00078 case, J2000 is assumed. If center is not specified, it will be
00079 determined from the observed positions of input data.
00080
00081 nx -- number of pixels along x (R.A.) direction.
00082 ny -- number of pixels along y (Dec.) direction.
00083 cellx -- size of pixel in x (R.A.) direction.
00084 celly -- size of pixel in y (Dec.) direction.
00085 center -- central position of the grid.
00086 """
00087 if not isinstance( cellx, str ):
00088 cellx = '%sarcsec'%(cellx)
00089 if not isinstance( celly, str ):
00090 celly = '%sarcsec'%(celly)
00091 self.gridder._defineimage( nx, ny, cellx, celly, center )
00092
00093 def setFunc( self, func='box', convsupport=-1, truncate="-1", gwidth="-1", jwidth="-1" ):
00094 """
00095 Set convolution function. Possible options are 'box' (Box-car,
00096 default), 'sf' (prolate spheroidal), 'gauss' (Gaussian), and
00097 'gjinc' (Gaussian * Jinc).
00098 Width of convolution function can be set using several parameters.
00099 For 'box' and 'sf', we have one parameter, convsupport, that
00100 specifies a cut-off radius of the convlolution function. By default
00101 (-1), convsupport is automatically set depending on each convolution
00102 function. Default values for convsupport are:
00103
00104 'box': 1 pixel
00105 'sf': 3 pixels
00106
00107 For 'gauss', we have two parameters for convolution function,
00108 truncate and gwidth. The truncate is similar to convsupport
00109 except that truncate allows to specify its value as float or
00110 string consisting of numeric and unit (e.g. '10arcsec' or
00111 '3pixel'). Available units are angular units ('arcsec', 'arcmin',
00112 'deg', etc.) and 'pixel'. Default unit is 'pixel' so that if
00113 you specify numerical value or string without unit to gwidth,
00114 the value will be interpreted as 'pixel'. gwidth is an HWHM of
00115 gaussian. It also allows string value. Interpretation of the
00116 value for gwidth is same as truncate. Default value for 'gauss'
00117 is
00118
00119 gwidth: '-1' ---> sqrt(log(2.0)) pixel
00120 truncate: '-1' ---> 3*gwidth pixel
00121
00122 For 'gjinc', there is an additional parameter jwidth that
00123 specifies a width of the jinc function whose functional form is
00124
00125 jinc(x) = J_1(pi*x/jwidth) / (pi*x/jwidth)
00126
00127 Default values for 'gjinc' is
00128
00129 gwidth: '-1' ---> 2.52*sqrt(log(2.0)) pixel
00130 jwidth: '-1' ---> 1.55
00131 truncate: '-1' ---> automatically truncate at first null
00132
00133 Default values for gwidth and jwidth are taken from Mangum et al.
00134 (2007).
00135
00136 func -- Function type ('box', 'sf', 'gauss', 'gjinc').
00137 convsupport -- Width of convolution function. Default (-1) is
00138 to choose pre-defined value for each convolution
00139 function. Effective only for 'box' and 'sf'.
00140 truncate -- Truncation radius of the convolution function.
00141 Acceptable value is an integer or a float in units of
00142 pixel, or a string consisting of numeric plus unit.
00143 Default unit for the string is 'pixel'. Default (-1)
00144 is to choose pre-defined value for each convolution
00145 function. Effective only for 'gauss' and 'gjinc'.
00146 gwidth -- The HWHM of the gaussian. Acceptable value is an integer
00147 or a float in units of pixel, or a string consisting of
00148 numeric plus unit. Default unit for the string is 'pixel'.
00149 Default (-1) is to choose pre-defined value for each
00150 convolution function. Effective only for 'gauss' and
00151 'gjinc'.
00152 jwidth -- The width of the jinc function. Acceptable value is an
00153 integer or a float in units of pixel, or a string
00154 consisting of numeric plus unit. Default unit for the
00155 string is 'pixel'. Default (-1) is to choose pre-defined
00156 value for each convolution function. Effective only for
00157 'gjinc'.
00158 """
00159 self.gridder._setfunc(func,
00160 convsupport=convsupport,
00161 truncate=truncate,
00162 gwidth=gwidth,
00163 jwidth=jwidth)
00164
00165 def setWeight( self, weightType='uniform' ):
00166 """
00167 Set weight type. Possible options are 'uniform' (default),
00168 'tint' (weight by integration time), 'tsys' (weight by
00169 Tsys: 1/Tsys**2), and 'tintsys' (weight by integration time
00170 as well as Tsys: tint/Tsys**2).
00171
00172 weightType -- weight type ('uniform', 'tint', 'tsys', 'tintsys')
00173 """
00174 self.gridder._setweight( weightType )
00175
00176 def enableClip( self ):
00177 """
00178 Enable min/max clipping.
00179
00180 By default, min/max clipping is disabled so that you should
00181 call this method before actual gridding if you want to do
00182 clipping.
00183 """
00184 self.gridder._enableclip()
00185
00186 def disableClip( self ):
00187 """
00188 Disable min/max clipping.
00189 """
00190 self.gridder._disableclip()
00191
00192 def grid( self ):
00193 """
00194 Actual gridding which will be done based on several user inputs.
00195 """
00196 self.gridder._grid()
00197
00198 def plotFunc(self, clear=True):
00199 """
00200 Support function to see the shape of current grid function.
00201
00202 clear -- clear panel if True. Default is True.
00203 """
00204 pl.figure(11)
00205 if clear:
00206 pl.clf()
00207 f = self.gridder._getfunc()
00208 convsampling = 100
00209 a = numpy.arange(0,len(f)/convsampling,1./convsampling,dtype=float)
00210 pl.plot(a,f,'.-')
00211 pl.xlabel('pixel')
00212 pl.ylabel('convFunc')
00213
00214 def save( self, outfile='' ):
00215 raise NotImplementedError('save is not implemented')
00216
00217 def plot( self, plotchan=-1, plotpol=-1, plotobs=False, plotgrid=False ):
00218 raise NotImplementedError('plot is not implemented')
00219
00220 def getResult( self ):
00221 raise NotImplementedError('getResult is not implemented')
00222
00223 class asapgrid(asapgrid_base):
00224 """
00225 The asapgrid class is defined to convolve data onto regular
00226 spatial grid. Typical usage is as follows:
00227
00228 # create asapgrid instance with two input data
00229 g = asapgrid( ['testimage1.asap','testimage2.asap'] )
00230 # set IFNO if necessary
00231 g.setIF( 0 )
00232 # set POLNOs if necessary
00233 g.setPolList( [0,1] )
00234 # set SCANNOs if necessary
00235 g.setScanList( [22,23,24] )
00236 # define image with full specification
00237 # you can skip some parameters (see help for defineImage)
00238 g.defineImage( nx=12, ny=12, cellx='10arcsec', celly='10arcsec',
00239 center='J2000 10h10m10s -5d05m05s' )
00240 # set convolution function
00241 g.setFunc( func='sf', convsupport=3 )
00242 # enable min/max clipping
00243 g.enableClip()
00244 # or, disable min/max clipping
00245 #g.disableClip()
00246 # actual gridding
00247 g.grid()
00248 # save result
00249 g.save( outfile='grid.asap' )
00250 # plot result
00251 g.plot( plotchan=1246, plotpol=-1, plotgrid=True, plotobs=True )
00252 """
00253 def __init__( self, infile ):
00254 """
00255 Create asapgrid instance.
00256
00257 infile -- input data as a string or string list if you want
00258 to grid more than one data at once.
00259 """
00260 super(asapgrid,self).__init__()
00261 self.gridder = stgrid()
00262 self.infile=infile
00263 self.setData(infile)
00264
00265 def setData( self, infile ):
00266 """
00267 Set data to be processed.
00268
00269 infile -- input data as a string or string list if you want
00270 to grid more than one data at once.
00271 """
00272 if isinstance( infile, str ):
00273 self.gridder._setin( infile )
00274 else:
00275 self.gridder._setfiles( infile )
00276 self.infile = infile
00277
00278 def save( self, outfile='' ):
00279 """
00280 Save result. By default, output data name will be constructed
00281 from first element of input data name list (e.g. 'input.asap.grid').
00282
00283 outfile -- output data name.
00284 """
00285 self.outfile = self.gridder._save( outfile )
00286
00287 def plot( self, plotchan=-1, plotpol=-1, plotobs=False, plotgrid=False ):
00288 """
00289 Plot gridded data.
00290
00291 plotchan -- Which channel you want to plot. Default (-1) is
00292 to average all the channels.
00293 plotpol -- Which polarization component you want to plot.
00294 Default (-1) is to average all the polarization
00295 components.
00296 plotobs -- Also plot observed position if True. Default
00297 is False. Setting True for large amount of spectra
00298 might be time consuming.
00299 plotgrid -- Also plot grid center if True. Default is False.
00300 Setting True for large number of grids might be
00301 time consuming.
00302 """
00303 import time
00304 t0=time.time()
00305
00306 storg = rcParams['scantable.storage']
00307 rcParams['scantable.storage'] = 'disk'
00308 plotter = _SDGridPlotter( self.infile, self.outfile, self.ifno )
00309 plotter.plot( chan=plotchan, pol=plotpol, plotobs=plotobs, plotgrid=plotgrid )
00310
00311 rcParams['scantable.storage'] = storg
00312 t1=time.time()
00313 asaplog.push('plot: elapsed time %s sec'%(t1-t0))
00314 asaplog.post('DEBUG','asapgrid.plot')
00315
00316 class asapgrid2(asapgrid_base):
00317 """
00318 The asapgrid class is defined to convolve data onto regular
00319 spatial grid. Typical usage is as follows:
00320
00321 # create asapgrid instance with input scantable
00322 s = scantable( 'testimage1.asap', average=False )
00323 g = asapgrid( s )
00324 # set IFNO if necessary
00325 g.setIF( 0 )
00326 # set POLNOs if necessary
00327 g.setPolList( [0,1] )
00328 # set SCANNOs if necessary
00329 g.setScanList( [22,23,24] )
00330 # define image with full specification
00331 # you can skip some parameters (see help for defineImage)
00332 g.defineImage( nx=12, ny=12, cellx='10arcsec', celly='10arcsec',
00333 center='J2000 10h10m10s -5d05m05s' )
00334 # set convolution function
00335 g.setFunc( func='sf', width=3 )
00336 # enable min/max clipping
00337 g.enableClip()
00338 # or, disable min/max clipping
00339 #g.disableClip()
00340 # actual gridding
00341 g.grid()
00342 # get result as scantable
00343 sg = g.getResult()
00344 """
00345 def __init__( self, scantab ):
00346 """
00347 Create asapgrid instance.
00348
00349 scantab -- input data as a scantable or a list of scantables
00350 to grid more than one data at once.
00351 """
00352 super(asapgrid2,self).__init__()
00353 self.gridder = stgrid2()
00354 self.scantab = scantab
00355 self.setData( scantab )
00356
00357 def setData( self, scantab ):
00358 """
00359 Set data to be processed.
00360
00361 scantab -- input data as a scantable or a list of scantables
00362 to grid more than one data at once.
00363 """
00364 if isinstance( scantab, scantable ):
00365 self.gridder._setin( scantab )
00366 else:
00367 self.gridder._setfiles( scantab )
00368 self.scantab = scantab
00369
00370 def getResult( self ):
00371 """
00372 Return gridded data as a scantable.
00373 """
00374 tp = 0 if rcParams['scantable.storage']=='memory' else 1
00375 return scantable( self.gridder._get( tp ), average=False )
00376
00377 class _SDGridPlotter:
00378 def __init__( self, infile, outfile=None, ifno=-1 ):
00379 if isinstance( infile, str ):
00380 self.infile = [infile]
00381 else:
00382 self.infile = infile
00383 self.outfile = outfile
00384 if self.outfile is None:
00385 self.outfile = self.infile[0].rstrip('/')+'.grid'
00386 self.nx = -1
00387 self.ny = -1
00388 self.nchan = 0
00389 self.npol = 0
00390 self.pollist = []
00391 self.cellx = 0.0
00392 self.celly = 0.0
00393 self.center = [0.0,0.0]
00394 self.nonzero = [[0.0],[0.0]]
00395 self.ifno = ifno
00396 self.tablein = None
00397 self.nrow = 0
00398 self.blc = None
00399 self.trc = None
00400 self.get()
00401
00402 def get( self ):
00403 s = scantable( self.outfile, average=False )
00404 self.nchan = len(s._getspectrum(0))
00405 nrow = s.nrow()
00406 pols = numpy.ones( nrow, dtype=int )
00407 for i in xrange(nrow):
00408 pols[i] = s.getpol(i)
00409 self.pollist, indices = numpy.unique( pols, return_inverse=True )
00410 self.npol = len(self.pollist)
00411 self.pollist = self.pollist[indices[:self.npol]]
00412
00413
00414
00415
00416 idx = 1
00417 d0 = s.get_direction( 0 ).split()[-2]
00418 d = s.get_direction(self.npol*idx)
00419 while( d is not None \
00420 and d.split()[-2] != d0):
00421 idx += 1
00422 d = s.get_direction(self.npol*idx)
00423
00424 self.nx = idx
00425 self.ny = nrow / (self.npol * idx )
00426
00427
00428 self.blc = s.get_directionval( 0 )
00429 self.trc = s.get_directionval( nrow-self.npol )
00430
00431
00432 if nrow > 1:
00433 incrx = s.get_directionval( self.npol )
00434 incry = s.get_directionval( self.nx*self.npol )
00435 else:
00436 incrx = [0.0,0.0]
00437 incry = [0.0,0.0]
00438 self.cellx = abs( self.blc[0] - incrx[0] )
00439 self.celly = abs( self.blc[1] - incry[1] )
00440
00441
00442 def plot( self, chan=-1, pol=-1, plotobs=False, plotgrid=False ):
00443 if pol < 0:
00444 opt = 'averaged over pol'
00445 else:
00446 opt = 'pol %s'%(pol)
00447 if type(chan) is list:
00448 opt += ', averaged over channel %s-%s'%(chan[0],chan[1])
00449 elif chan < 0:
00450 opt += ', averaged over channel'
00451 else:
00452 opt += ', channel %s'%(chan)
00453 data = self.getData( chan, pol )
00454
00455 title = 'Gridded Image (%s)'%(opt)
00456 pl.figure(10)
00457 pl.clf()
00458
00459 if plotgrid:
00460 x = numpy.arange(self.blc[0],self.trc[0]+0.5*self.cellx,self.cellx,dtype=float)
00461
00462
00463 ybase = numpy.ones(self.nx,dtype=float)*self.blc[1]
00464
00465 incr = self.celly
00466 for iy in xrange(self.ny):
00467 y = ybase + iy * incr
00468
00469 pl.plot(x,y,',',color='blue')
00470
00471 if plotobs:
00472 for i in xrange(len(self.infile)):
00473 self.createTableIn( self.infile[i] )
00474 irow = 0
00475 while ( irow < self.nrow ):
00476 chunk = self.getPointingChunk( irow )
00477
00478 pl.plot(chunk[0],chunk[1],',',color='green')
00479 irow += chunk.shape[1]
00480
00481
00482 extent=[self.trc[0]+0.5*self.cellx,
00483 self.blc[0]-0.5*self.cellx,
00484 self.blc[1]-0.5*self.celly,
00485 self.trc[1]+0.5*self.celly]
00486 deccorr = 1.0/numpy.cos(0.5*(self.blc[1]+self.trc[1]))
00487 pl.imshow(data,extent=extent,origin='lower',interpolation='nearest')
00488 pl.colorbar()
00489 pl.xlabel('R.A. [rad]')
00490 pl.ylabel('Dec. [rad]')
00491 ax = pl.axes()
00492 ax.set_aspect(deccorr)
00493 pl.title( title )
00494
00495 def createTableIn( self, tab ):
00496 del self.tablein
00497 self.tablein = scantable( tab, average=False )
00498 if self.ifno < 0:
00499 ifno = self.tablein.getif(0)
00500
00501 else:
00502 ifno = self.ifno
00503 sel = selector()
00504 sel.set_ifs( ifno )
00505 self.tablein.set_selection( sel )
00506 self.nchan = len(self.tablein._getspectrum(0))
00507 self.nrow = self.tablein.nrow()
00508 del sel
00509
00510
00511 def getPointingChunk( self, irow ):
00512 numchunk = 1000
00513 nrow = min( self.nrow-irow, numchunk )
00514
00515 v = numpy.zeros( (2,nrow), dtype=float )
00516 idx = 0
00517 for i in xrange(irow,irow+nrow):
00518 d = self.tablein.get_directionval( i )
00519 v[0,idx] = d[0]
00520 v[1,idx] = d[1]
00521 idx += 1
00522 return v
00523
00524 def getData( self, chan=-1, pol=-1 ):
00525 if type(chan) == list:
00526 spectra = self.__chanAverage(start=chan[0],end=chan[1])
00527 elif chan == -1:
00528 spectra = self.__chanAverage()
00529 else:
00530 spectra = self.__chanIndex( chan )
00531 data = spectra.reshape( (self.npol,self.ny,self.nx) )
00532 if pol == -1:
00533 retval = data.mean(axis=0)
00534 else:
00535 retval = data[pol]
00536 return retval
00537
00538 def __chanAverage( self, start=-1, end=-1 ):
00539 s = scantable( self.outfile, average=False )
00540 nrow = s.nrow()
00541 spectra = numpy.zeros( (self.npol,nrow/self.npol), dtype=float )
00542 irow = 0
00543 sp = [0 for i in xrange(self.nchan)]
00544 if start < 0:
00545 start = 0
00546 if end < 0:
00547 end = self.nchan
00548 for i in xrange(nrow/self.npol):
00549 for ip in xrange(self.npol):
00550 sp = s._getspectrum( irow )[start:end]
00551 spectra[ip,i] = numpy.mean( sp )
00552 irow += 1
00553
00554 return spectra
00555
00556 def __chanIndex( self, idx ):
00557 s = scantable( self.outfile, average=False )
00558 nrow = s.nrow()
00559 spectra = numpy.zeros( (self.npol,nrow/self.npol), dtype=float )
00560 irow = 0
00561 sp = [0 for i in xrange(self.nchan)]
00562 for i in xrange(nrow/self.npol):
00563 for ip in xrange(self.npol):
00564 sp = s._getspectrum( irow )
00565 spectra[ip,i] = sp[idx]
00566 irow += 1
00567 return spectra
00568
00569