casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables
asapgrid.py
Go to the documentation of this file.
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         # to load scantable on disk
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         # back to original setup
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         #print 'pollist=',self.pollist
00413         #print 'npol=',self.npol
00414         #print 'nrow=',nrow
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         #print 'nx,ny=',self.nx,self.ny
00427 
00428         self.blc = s.get_directionval( 0 )
00429         self.trc = s.get_directionval( nrow-self.npol )
00430         #print self.blc
00431         #print self.trc
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         #print 'cellx,celly=',self.cellx,self.celly
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         #data = numpy.fliplr( data )
00455         title = 'Gridded Image (%s)'%(opt)
00456         pl.figure(10)
00457         pl.clf()
00458         # plot grid position
00459         if plotgrid:
00460             x = numpy.arange(self.blc[0],self.trc[0]+0.5*self.cellx,self.cellx,dtype=float)
00461             #print 'len(x)=',len(x)
00462             #print 'x=',x
00463             ybase = numpy.ones(self.nx,dtype=float)*self.blc[1]
00464             #print 'len(ybase)=',len(ybase)
00465             incr = self.celly 
00466             for iy in xrange(self.ny):
00467                 y = ybase + iy * incr
00468                 #print y
00469                 pl.plot(x,y,',',color='blue')
00470         # plot observed position
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                     #print chunk
00478                     pl.plot(chunk[0],chunk[1],',',color='green')
00479                     irow += chunk.shape[1]
00480                     #print irow
00481         # show image
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             #print 'ifno=',ifno
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         #print 'nrow=',nrow
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