source: trunk/python/asapgrid.py@ 2683

Last change on this file since 2683 was 2680, checked in by Takeshi Nakazato, 12 years ago

New Development: No

JIRA Issue: Yes CAS-4429

Ready for Test: Yes

Interface Changes: No

What Interface Changed: Please list interface changes

Test Programs: List test programs

Put in Release Notes: Yes/No

Module(s): Module Names change impacts.

Description: Describe your changes here...

Refactored asapgrid module by defining asapgrid_base class.


File size: 20.3 KB
Line 
1import numpy
2from asap import rcParams
3from asap.scantable import scantable
4from asap.selector import selector
5from asap._asap import stgrid, stgrid2
6import pylab as pl
7from logging import asaplog
8
9class asapgrid_base(object):
10 def __init__( self ):
11 self.outfile = None
12 self.ifno = None
13 self.gridder = None
14 self.infile = None
15 self.scantab = None
16
17 def setData( self, infile ):
18 raise NotImplementedError('setData is not implemented')
19
20 def setIF( self, ifno ):
21 """
22 Set IFNO to be processed. Currently, asapgrid allows to process
23 only one IFNO for one gridding run even if the data contains
24 multiple IFs. If you didn't specify IFNO, default value, which
25 is IFNO in the first spectrum, will be processed.
26
27 ifno -- IFNO to be processed.
28 """
29 self.ifno = ifno
30 self.gridder._setif( self.ifno )
31
32 def setPolList( self, pollist ):
33 """
34 Set list of polarization components you want to process.
35 If not specified, all POLNOs will be processed.
36
37 pollist -- list of POLNOs.
38 """
39 self.gridder._setpollist( pollist )
40
41 def setScanList( self, scanlist ):
42 """
43 Set list of scans you want to process. If not specified, all
44 scans will be processed.
45
46 scanlist -- list of SCANNOs.
47 """
48 self.gridder._setscanlist( scanlist )
49
50 def defineImage( self, nx=-1, ny=-1, cellx='', celly='', center='' ):
51 """
52 Define spatial grid.
53
54 First two parameters, nx and ny, define number of pixels of
55 the grid. If which of those is not specified, it will be set
56 to the same value as the other. If none of them are specified,
57 it will be determined from map extent and cell size.
58
59 Next two parameters, cellx and celly, define size of pixel.
60 You should set those parameters as string, which is constructed
61 numerical value and unit, e.g. '0.5arcmin', or numerical value.
62 If those values are specified as numerical value, their units
63 will be assumed to 'arcsec'. If which of those is not specified,
64 it will be set to the same value as the other. If none of them
65 are specified, it will be determined from map extent and number
66 of pixels, or set to '1arcmin' if neither nx nor ny is set.
67
68 The last parameter, center, define the central coordinate of
69 the grid. You should specify its value as a string, like,
70
71 'J2000 05h08m50s -16d23m30s'
72
73 or
74
75 'J2000 05:08:50 -16.23.30'
76
77 You can omit equinox when you specify center coordinate. In that
78 case, J2000 is assumed. If center is not specified, it will be
79 determined from the observed positions of input data.
80
81 nx -- number of pixels along x (R.A.) direction.
82 ny -- number of pixels along y (Dec.) direction.
83 cellx -- size of pixel in x (R.A.) direction.
84 celly -- size of pixel in y (Dec.) direction.
85 center -- central position of the grid.
86 """
87 if not isinstance( cellx, str ):
88 cellx = '%sarcsec'%(cellx)
89 if not isinstance( celly, str ):
90 celly = '%sarcsec'%(celly)
91 self.gridder._defineimage( nx, ny, cellx, celly, center )
92
93 def setFunc( self, func='box', convsupport=-1, truncate="-1", gwidth="-1", jwidth="-1" ):
94 """
95 Set convolution function. Possible options are 'box' (Box-car,
96 default), 'sf' (prolate spheroidal), 'gauss' (Gaussian), and
97 'gjinc' (Gaussian * Jinc).
98 Width of convolution function can be set using several parameters.
99 For 'box' and 'sf', we have one parameter, convsupport, that
100 specifies a cut-off radius of the convlolution function. By default
101 (-1), convsupport is automatically set depending on each convolution
102 function. Default values for convsupport are:
103
104 'box': 1 pixel
105 'sf': 3 pixels
106
107 For 'gauss', we have two parameters for convolution function,
108 truncate and gwidth. The truncate is similar to convsupport
109 except that truncate allows to specify its value as float or
110 string consisting of numeric and unit (e.g. '10arcsec' or
111 '3pixel'). Available units are angular units ('arcsec', 'arcmin',
112 'deg', etc.) and 'pixel'. Default unit is 'pixel' so that if
113 you specify numerical value or string without unit to gwidth,
114 the value will be interpreted as 'pixel'. gwidth is an HWHM of
115 gaussian. It also allows string value. Interpretation of the
116 value for gwidth is same as truncate. Default value for 'gauss'
117 is
118
119 gwidth: '-1' ---> sqrt(log(2.0)) pixel
120 truncate: '-1' ---> 3*gwidth pixel
121
122 For 'gjinc', there is an additional parameter jwidth that
123 specifies a width of the jinc function whose functional form is
124
125 jinc(x) = J_1(pi*x/jwidth) / (pi*x/jwidth)
126
127 Default values for 'gjinc' is
128
129 gwidth: '-1' ---> 2.52*sqrt(log(2.0)) pixel
130 jwidth: '-1' ---> 1.55
131 truncate: '-1' ---> automatically truncate at first null
132
133 Default values for gwidth and jwidth are taken from Mangum et al.
134 (2007).
135
136 func -- Function type ('box', 'sf', 'gauss', 'gjinc').
137 convsupport -- Width of convolution function. Default (-1) is
138 to choose pre-defined value for each convolution
139 function. Effective only for 'box' and 'sf'.
140 truncate -- Truncation radius of the convolution function.
141 Acceptable value is an integer or a float in units of
142 pixel, or a string consisting of numeric plus unit.
143 Default unit for the string is 'pixel'. Default (-1)
144 is to choose pre-defined value for each convolution
145 function. Effective only for 'gauss' and 'gjinc'.
146 gwidth -- The HWHM of the gaussian. Acceptable value is an integer
147 or a float in units of pixel, or a string consisting of
148 numeric plus unit. Default unit for the string is 'pixel'.
149 Default (-1) is to choose pre-defined value for each
150 convolution function. Effective only for 'gauss' and
151 'gjinc'.
152 jwidth -- The width of the jinc function. Acceptable value is an
153 integer or a float in units of pixel, or a string
154 consisting of numeric plus unit. Default unit for the
155 string is 'pixel'. Default (-1) is to choose pre-defined
156 value for each convolution function. Effective only for
157 'gjinc'.
158 """
159 self.gridder._setfunc(func,
160 convsupport=convsupport,
161 truncate=truncate,
162 gwidth=gwidth,
163 jwidth=jwidth)
164
165 def setWeight( self, weightType='uniform' ):
166 """
167 Set weight type. Possible options are 'uniform' (default),
168 'tint' (weight by integration time), 'tsys' (weight by
169 Tsys: 1/Tsys**2), and 'tintsys' (weight by integration time
170 as well as Tsys: tint/Tsys**2).
171
172 weightType -- weight type ('uniform', 'tint', 'tsys', 'tintsys')
173 """
174 self.gridder._setweight( weightType )
175
176 def enableClip( self ):
177 """
178 Enable min/max clipping.
179
180 By default, min/max clipping is disabled so that you should
181 call this method before actual gridding if you want to do
182 clipping.
183 """
184 self.gridder._enableclip()
185
186 def disableClip( self ):
187 """
188 Disable min/max clipping.
189 """
190 self.gridder._disableclip()
191
192 def grid( self ):
193 """
194 Actual gridding which will be done based on several user inputs.
195 """
196 self.gridder._grid()
197
198 def plotFunc(self, clear=True):
199 """
200 Support function to see the shape of current grid function.
201
202 clear -- clear panel if True. Default is True.
203 """
204 pl.figure(11)
205 if clear:
206 pl.clf()
207 f = self.gridder._getfunc()
208 convsampling = 100
209 a = numpy.arange(0,len(f)/convsampling,1./convsampling,dtype=float)
210 pl.plot(a,f,'.-')
211 pl.xlabel('pixel')
212 pl.ylabel('convFunc')
213
214 def save( self, outfile='' ):
215 raise NotImplementedError('save is not implemented')
216
217 def plot( self, plotchan=-1, plotpol=-1, plotobs=False, plotgrid=False ):
218 raise NotImplementedError('plot is not implemented')
219
220 def getResult( self ):
221 raise NotImplementedError('getResult is not implemented')
222
223class asapgrid(asapgrid_base):
224 """
225 The asapgrid class is defined to convolve data onto regular
226 spatial grid. Typical usage is as follows:
227
228 # create asapgrid instance with two input data
229 g = asapgrid( ['testimage1.asap','testimage2.asap'] )
230 # set IFNO if necessary
231 g.setIF( 0 )
232 # set POLNOs if necessary
233 g.setPolList( [0,1] )
234 # set SCANNOs if necessary
235 g.setScanList( [22,23,24] )
236 # define image with full specification
237 # you can skip some parameters (see help for defineImage)
238 g.defineImage( nx=12, ny=12, cellx='10arcsec', celly='10arcsec',
239 center='J2000 10h10m10s -5d05m05s' )
240 # set convolution function
241 g.setFunc( func='sf', convsupport=3 )
242 # enable min/max clipping
243 g.enableClip()
244 # or, disable min/max clipping
245 #g.disableClip()
246 # actual gridding
247 g.grid()
248 # save result
249 g.save( outfile='grid.asap' )
250 # plot result
251 g.plot( plotchan=1246, plotpol=-1, plotgrid=True, plotobs=True )
252 """
253 def __init__( self, infile ):
254 """
255 Create asapgrid instance.
256
257 infile -- input data as a string or string list if you want
258 to grid more than one data at once.
259 """
260 super(asapgrid,self).__init__()
261 self.gridder = stgrid()
262 self.infile=infile
263 self.setData(infile)
264
265 def setData( self, infile ):
266 """
267 Set data to be processed.
268
269 infile -- input data as a string or string list if you want
270 to grid more than one data at once.
271 """
272 if isinstance( infile, str ):
273 self.gridder._setin( infile )
274 else:
275 self.gridder._setfiles( infile )
276 self.infile = infile
277
278 def save( self, outfile='' ):
279 """
280 Save result. By default, output data name will be constructed
281 from first element of input data name list (e.g. 'input.asap.grid').
282
283 outfile -- output data name.
284 """
285 self.outfile = self.gridder._save( outfile )
286
287 def plot( self, plotchan=-1, plotpol=-1, plotobs=False, plotgrid=False ):
288 """
289 Plot gridded data.
290
291 plotchan -- Which channel you want to plot. Default (-1) is
292 to average all the channels.
293 plotpol -- Which polarization component you want to plot.
294 Default (-1) is to average all the polarization
295 components.
296 plotobs -- Also plot observed position if True. Default
297 is False. Setting True for large amount of spectra
298 might be time consuming.
299 plotgrid -- Also plot grid center if True. Default is False.
300 Setting True for large number of grids might be
301 time consuming.
302 """
303 import time
304 t0=time.time()
305 # to load scantable on disk
306 storg = rcParams['scantable.storage']
307 rcParams['scantable.storage'] = 'disk'
308 plotter = _SDGridPlotter( self.infile, self.outfile, self.ifno )
309 plotter.plot( chan=plotchan, pol=plotpol, plotobs=plotobs, plotgrid=plotgrid )
310 # back to original setup
311 rcParams['scantable.storage'] = storg
312 t1=time.time()
313 asaplog.push('plot: elapsed time %s sec'%(t1-t0))
314 asaplog.post('DEBUG','asapgrid.plot')
315
316class asapgrid2(asapgrid_base):
317 """
318 The asapgrid class is defined to convolve data onto regular
319 spatial grid. Typical usage is as follows:
320
321 # create asapgrid instance with input scantable
322 s = scantable( 'testimage1.asap', average=False )
323 g = asapgrid( s )
324 # set IFNO if necessary
325 g.setIF( 0 )
326 # set POLNOs if necessary
327 g.setPolList( [0,1] )
328 # set SCANNOs if necessary
329 g.setScanList( [22,23,24] )
330 # define image with full specification
331 # you can skip some parameters (see help for defineImage)
332 g.defineImage( nx=12, ny=12, cellx='10arcsec', celly='10arcsec',
333 center='J2000 10h10m10s -5d05m05s' )
334 # set convolution function
335 g.setFunc( func='sf', width=3 )
336 # enable min/max clipping
337 g.enableClip()
338 # or, disable min/max clipping
339 #g.disableClip()
340 # actual gridding
341 g.grid()
342 # get result as scantable
343 sg = g.getResult()
344 """
345 def __init__( self, scantab ):
346 """
347 Create asapgrid instance.
348
349 scantab -- input data as a scantable or a list of scantables
350 to grid more than one data at once.
351 """
352 super(asapgrid2,self).__init__()
353 self.gridder = stgrid2()
354 self.scantab = scantab
355 self.setData( scantab )
356
357 def setData( self, scantab ):
358 """
359 Set data to be processed.
360
361 scantab -- input data as a scantable or a list of scantables
362 to grid more than one data at once.
363 """
364 if isinstance( scantab, scantable ):
365 self.gridder._setin( scantab )
366 else:
367 self.gridder._setfiles( scantab )
368 self.scantab = scantab
369
370 def getResult( self ):
371 """
372 Return gridded data as a scantable.
373 """
374 tp = 0 if rcParams['scantable.storage']=='memory' else 1
375 return scantable( self.gridder._get( tp ), average=False )
376
377class _SDGridPlotter:
378 def __init__( self, infile, outfile=None, ifno=-1 ):
379 if isinstance( infile, str ):
380 self.infile = [infile]
381 else:
382 self.infile = infile
383 self.outfile = outfile
384 if self.outfile is None:
385 self.outfile = self.infile[0].rstrip('/')+'.grid'
386 self.nx = -1
387 self.ny = -1
388 self.nchan = 0
389 self.npol = 0
390 self.pollist = []
391 self.cellx = 0.0
392 self.celly = 0.0
393 self.center = [0.0,0.0]
394 self.nonzero = [[0.0],[0.0]]
395 self.ifno = ifno
396 self.tablein = None
397 self.nrow = 0
398 self.blc = None
399 self.trc = None
400 self.get()
401
402 def get( self ):
403 s = scantable( self.outfile, average=False )
404 self.nchan = len(s._getspectrum(0))
405 nrow = s.nrow()
406 pols = numpy.ones( nrow, dtype=int )
407 for i in xrange(nrow):
408 pols[i] = s.getpol(i)
409 self.pollist, indices = numpy.unique( pols, return_inverse=True )
410 self.npol = len(self.pollist)
411 self.pollist = self.pollist[indices[:self.npol]]
412 #print 'pollist=',self.pollist
413 #print 'npol=',self.npol
414 #print 'nrow=',nrow
415
416 idx = 1
417 d0 = s.get_direction( 0 ).split()[-2]
418 d = s.get_direction(self.npol*idx)
419 while( d is not None \
420 and d.split()[-2] != d0):
421 idx += 1
422 d = s.get_direction(self.npol*idx)
423
424 self.nx = idx
425 self.ny = nrow / (self.npol * idx )
426 #print 'nx,ny=',self.nx,self.ny
427
428 self.blc = s.get_directionval( 0 )
429 self.trc = s.get_directionval( nrow-self.npol )
430 #print self.blc
431 #print self.trc
432 if nrow > 1:
433 incrx = s.get_directionval( self.npol )
434 incry = s.get_directionval( self.nx*self.npol )
435 else:
436 incrx = [0.0,0.0]
437 incry = [0.0,0.0]
438 self.cellx = abs( self.blc[0] - incrx[0] )
439 self.celly = abs( self.blc[1] - incry[1] )
440 #print 'cellx,celly=',self.cellx,self.celly
441
442 def plot( self, chan=-1, pol=-1, plotobs=False, plotgrid=False ):
443 if pol < 0:
444 opt = 'averaged over pol'
445 else:
446 opt = 'pol %s'%(pol)
447 if type(chan) is list:
448 opt += ', averaged over channel %s-%s'%(chan[0],chan[1])
449 elif chan < 0:
450 opt += ', averaged over channel'
451 else:
452 opt += ', channel %s'%(chan)
453 data = self.getData( chan, pol )
454 #data = numpy.fliplr( data )
455 title = 'Gridded Image (%s)'%(opt)
456 pl.figure(10)
457 pl.clf()
458 # plot grid position
459 if plotgrid:
460 x = numpy.arange(self.blc[0],self.trc[0]+0.5*self.cellx,self.cellx,dtype=float)
461 #print 'len(x)=',len(x)
462 #print 'x=',x
463 ybase = numpy.ones(self.nx,dtype=float)*self.blc[1]
464 #print 'len(ybase)=',len(ybase)
465 incr = self.celly
466 for iy in xrange(self.ny):
467 y = ybase + iy * incr
468 #print y
469 pl.plot(x,y,',',color='blue')
470 # plot observed position
471 if plotobs:
472 for i in xrange(len(self.infile)):
473 self.createTableIn( self.infile[i] )
474 irow = 0
475 while ( irow < self.nrow ):
476 chunk = self.getPointingChunk( irow )
477 #print chunk
478 pl.plot(chunk[0],chunk[1],',',color='green')
479 irow += chunk.shape[1]
480 #print irow
481 # show image
482 extent=[self.trc[0]+0.5*self.cellx,
483 self.blc[0]-0.5*self.cellx,
484 self.blc[1]-0.5*self.celly,
485 self.trc[1]+0.5*self.celly]
486 deccorr = 1.0/numpy.cos(0.5*(self.blc[1]+self.trc[1]))
487 pl.imshow(data,extent=extent,origin='lower',interpolation='nearest')
488 pl.colorbar()
489 pl.xlabel('R.A. [rad]')
490 pl.ylabel('Dec. [rad]')
491 ax = pl.axes()
492 ax.set_aspect(deccorr)
493 pl.title( title )
494
495 def createTableIn( self, tab ):
496 del self.tablein
497 self.tablein = scantable( tab, average=False )
498 if self.ifno < 0:
499 ifno = self.tablein.getif(0)
500 #print 'ifno=',ifno
501 else:
502 ifno = self.ifno
503 sel = selector()
504 sel.set_ifs( ifno )
505 self.tablein.set_selection( sel )
506 self.nchan = len(self.tablein._getspectrum(0))
507 self.nrow = self.tablein.nrow()
508 del sel
509
510
511 def getPointingChunk( self, irow ):
512 numchunk = 1000
513 nrow = min( self.nrow-irow, numchunk )
514 #print 'nrow=',nrow
515 v = numpy.zeros( (2,nrow), dtype=float )
516 idx = 0
517 for i in xrange(irow,irow+nrow):
518 d = self.tablein.get_directionval( i )
519 v[0,idx] = d[0]
520 v[1,idx] = d[1]
521 idx += 1
522 return v
523
524 def getData( self, chan=-1, pol=-1 ):
525 if type(chan) == list:
526 spectra = self.__chanAverage(start=chan[0],end=chan[1])
527 elif chan == -1:
528 spectra = self.__chanAverage()
529 else:
530 spectra = self.__chanIndex( chan )
531 data = spectra.reshape( (self.npol,self.ny,self.nx) )
532 if pol == -1:
533 retval = data.mean(axis=0)
534 else:
535 retval = data[pol]
536 return retval
537
538 def __chanAverage( self, start=-1, end=-1 ):
539 s = scantable( self.outfile, average=False )
540 nrow = s.nrow()
541 spectra = numpy.zeros( (self.npol,nrow/self.npol), dtype=float )
542 irow = 0
543 sp = [0 for i in xrange(self.nchan)]
544 if start < 0:
545 start = 0
546 if end < 0:
547 end = self.nchan
548 for i in xrange(nrow/self.npol):
549 for ip in xrange(self.npol):
550 sp = s._getspectrum( irow )[start:end]
551 spectra[ip,i] = numpy.mean( sp )
552 irow += 1
553
554 return spectra
555
556 def __chanIndex( self, idx ):
557 s = scantable( self.outfile, average=False )
558 nrow = s.nrow()
559 spectra = numpy.zeros( (self.npol,nrow/self.npol), dtype=float )
560 irow = 0
561 sp = [0 for i in xrange(self.nchan)]
562 for i in xrange(nrow/self.npol):
563 for ip in xrange(self.npol):
564 sp = s._getspectrum( irow )
565 spectra[ip,i] = sp[idx]
566 irow += 1
567 return spectra
568
569
Note: See TracBrowser for help on using the repository browser.