source: trunk/python/scantable.py@ 433

Last change on this file since 433 was 432, checked in by kil064, 20 years ago

add rotate_xyphase

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.7 KB
Line 
1from asap._asap import sdtable
2from asap import rcParams
3from numarray import ones,zeros
4import sys
5
6class scantable(sdtable):
7 """
8 The ASAP container for scans
9 """
10
11 def __init__(self, filename, unit=None):
12 """
13 Create a scantable from a saved one or make a reference
14 Parameters:
15 filename: the name of an asap table on disk
16 or
17 the name of a rpfits/sdfits/ms file
18 (integrations within scans are auto averaged
19 and the whole file is read)
20 or
21 [advanced] a reference to an existing
22 scantable
23 unit: brightness unit; must be consistent with K or Jy.
24 Over-rides the default selected by the reader
25 (input rpfits/sdfits/ms) or replaces the value
26 in existing scantables
27 """
28 self._vb = rcParams['verbose']
29 self._p = None
30 from os import stat as st
31 import stat
32 if isinstance(filename,sdtable):
33 sdtable.__init__(self, filename)
34 if unit is not None:
35 self.set_fluxunit(unit)
36 else:
37 import os.path
38 if not os.path.exists(filename):
39 print "File '%s' not found." % (filename)
40 return
41 filename = os.path.expandvars(filename)
42 if os.path.isdir(filename):
43 # crude check if asap table
44 if os.path.exists(filename+'/table.info'):
45 sdtable.__init__(self, filename)
46 if unit is not None:
47 self.set_fluxunit(unit)
48 else:
49 print "The given file '%s'is not a valid asap table." % (filename)
50 return
51 else:
52 autoav = rcParams['scantable.autoaverage']
53
54 from asap._asap import sdreader
55 ifSel = -1
56 beamSel = -1
57 r = sdreader(filename,ifSel,beamSel)
58 print 'Importing data...'
59 r._read([-1])
60 tbl = r._getdata()
61 if unit is not None:
62 tbl.set_fluxunit(unit)
63 if autoav:
64 from asap._asap import average
65 tmp = tuple([tbl])
66 print 'Auto averaging integrations...'
67 tbl2 = average(tmp,(),True,'none')
68 sdtable.__init__(self,tbl2)
69 del r,tbl
70 else:
71 sdtable.__init__(self,tbl)
72
73 def save(self, name=None, format=None, overwrite=False):
74 """
75 Store the scantable on disk. This can be an asap (aips++) Table, SDFITS,
76 Image FITS or MS2 format.
77 Parameters:
78 name: the name of the outputfile. For format="FITS" this
79 is the directory file name into which all the files will
80 be written (default is 'asap_FITS')
81 format: an optional file format. Default is ASAP.
82 Allowed are - 'ASAP' (save as ASAP [aips++] Table),
83 'SDFITS' (save as SDFITS file)
84 'FITS' (saves each row as a FITS Image)
85 'ASCII' (saves as ascii text file)
86 'MS2' (saves as an aips++
87 MeasurementSet V2)
88 overwrite: If the file should be overwritten if it exists.
89 The default False is to return with warning
90 without writing the output. USE WITH CARE.
91 Example:
92 scan.save('myscan.asap')
93 scan.save('myscan.sdfits','SDFITS')
94 """
95 from os import path
96 if format is None: format = rcParams['scantable.save']
97 suffix = '.'+format.lower()
98 if name is None or name =="":
99 name = 'scantable'+suffix
100 print "No filename given. Using default name %s..." % name
101 name = path.expandvars(name)
102 if path.isfile(name) or path.isdir(name):
103 if not overwrite:
104 print "File %s already exists." % name
105 return
106 if format == 'ASAP':
107 self._save(name)
108 else:
109 from asap._asap import sdwriter as _sw
110 w = _sw(format)
111 w.write(self, name)
112 return
113
114 def copy(self):
115 """
116 Return a copy of this scantable.
117 Parameters:
118 none
119 Example:
120 copiedscan = scan.copy()
121 """
122 sd = scantable(sdtable._copy(self))
123 return sd
124
125 def get_scan(self, scanid=None):
126 """
127 Return a specific scan (by scanno) or collection of scans (by
128 source name) in a new scantable.
129 Parameters:
130 scanid: a scanno or a source name
131 Example:
132 scan.get_scan('323p459')
133 # gets all scans containing the source '323p459'
134 """
135 if scanid is None:
136 print "Please specify a scan no or name to retrieve from the scantable"
137 try:
138 if type(scanid) is str:
139 s = sdtable._getsource(self,scanid)
140 return scantable(s)
141 elif type(scanid) is int:
142 s = sdtable._getscan(self,[scanid])
143 return scantable(s)
144 elif type(scanid) is list:
145 s = sdtable._getscan(self,scanid)
146 return scantable(s)
147 else:
148 print "Illegal scanid type, use 'int' or 'list' if ints."
149 except RuntimeError:
150 print "Couldn't find any match."
151
152 def __str__(self):
153 return sdtable._summary(self,True)
154
155 def summary(self,filename=None, verbose=None):
156 """
157 Print a summary of the contents of this scantable.
158 Parameters:
159 filename: the name of a file to write the putput to
160 Default - no file output
161 verbose: print extra info such as the frequency table
162 The default (False) is taken from .asaprc
163 """
164 info = sdtable._summary(self, verbose)
165 if verbose is None: verbose = rcParams['scantable.verbosesummary']
166 if filename is not None:
167 if filename is "":
168 filename = 'scantable_summary.txt'
169 from os.path import expandvars, isdir
170 filename = expandvars(filename)
171 if not isdir(filename):
172 data = open(filename, 'w')
173 data.write(info)
174 data.close()
175 else:
176 print "Illegal file name '%s'." % (filename)
177 print info
178
179 def set_cursor(self, thebeam=0,theif=0,thepol=0):
180 """
181 Set the spectrum for individual operations.
182 Parameters:
183 thebeam,theif,thepol: a number
184 Example:
185 scan.set_cursor(0,0,1)
186 pol1sig = scan.stats(all=False) # returns std dev for beam=0
187 # if=0, pol=1
188 """
189 self.setbeam(thebeam)
190 self.setpol(thepol)
191 self.setif(theif)
192 return
193
194 def get_cursor(self):
195 """
196 Return/print a the current 'cursor' into the Beam/IF/Pol cube.
197 Parameters:
198 none
199 Returns:
200 a list of values (currentBeam,currentIF,currentPol)
201 Example:
202 none
203 """
204 i = self.getbeam()
205 j = self.getif()
206 k = self.getpol()
207 if self._vb:
208 print "--------------------------------------------------"
209 print " Cursor position"
210 print "--------------------------------------------------"
211 out = 'Beam=%d IF=%d Pol=%d ' % (i,j,k)
212 print out
213 return i,j,k
214
215 def stats(self, stat='stddev', mask=None, all=None):
216 """
217 Determine the specified statistic of the current beam/if/pol
218 Takes a 'mask' as an optional parameter to specify which
219 channels should be excluded.
220 Parameters:
221 stat: 'min', 'max', 'sumsq', 'sum', 'mean'
222 'var', 'stddev', 'avdev', 'rms', 'median'
223 mask: an optional mask specifying where the statistic
224 should be determined.
225 all: if true show all (default or .asaprc) rather
226 that the cursor selected spectrum of Beam/IF/Pol
227
228 Example:
229 scan.set_unit('channel')
230 msk = scan.create_mask([100,200],[500,600])
231 scan.stats(stat='mean', mask=m)
232 """
233 if all is None: all = rcParams['scantable.allaxes']
234 from asap._asap import stats as _stats
235 from numarray import array,zeros,Float
236 if mask == None:
237 mask = ones(self.nchan())
238 axes = ['Beam','IF','Pol','Time']
239
240 if all:
241 n = self.nbeam()*self.nif()*self.npol()*self.nrow()
242 shp = [self.nbeam(),self.nif(),self.npol(),self.nrow()]
243 arr = array(zeros(n),shape=shp,type=Float)
244
245 for i in range(self.nbeam()):
246 self.setbeam(i)
247 for j in range(self.nif()):
248 self.setif(j)
249 for k in range(self.npol()):
250 self.setpol(k)
251 arr[i,j,k,:] = _stats(self,mask,stat,-1)
252 retval = {'axes': axes, 'data': arr, 'cursor':None}
253 tm = [self._gettime(val) for val in range(self.nrow())]
254 if self._vb:
255 self._print_values(retval,stat,tm)
256 return retval
257
258 else:
259 i,j,k = (self.getbeam(),self.getif(),self.getpol())
260 statval = _stats(self,mask,stat,-1)
261 out = ''
262 for l in range(self.nrow()):
263 tm = self._gettime(l)
264 out += 'Time[%s]:\n' % (tm)
265 if self.nbeam() > 1: out += ' Beam[%d] ' % (i)
266 if self.nif() > 1: out += ' IF[%d] ' % (j)
267 if self.npol() > 1: out += ' Pol[%d] ' % (k)
268 out += '= %3.3f\n' % (statval[l])
269 out += "--------------------------------------------------\n"
270
271 if self._vb:
272 print "--------------------------------------------------"
273 print " ",stat
274 print "--------------------------------------------------"
275 print out
276 retval = {'axes': axes, 'data': array(statval), 'cursor':(i,j,k)}
277 return retval
278
279 def stddev(self,mask=None, all=None):
280 """
281 Determine the standard deviation of the current beam/if/pol
282 Takes a 'mask' as an optional parameter to specify which
283 channels should be excluded.
284 Parameters:
285 mask: an optional mask specifying where the standard
286 deviation should be determined.
287 all: optional flag to show all or a cursor selected
288 spectrum of Beam/IF/Pol. Default is all or taken
289 from .asaprc
290
291 Example:
292 scan.set_unit('channel')
293 msk = scan.create_mask([100,200],[500,600])
294 scan.stddev(mask=m)
295 """
296 if all is None: all = rcParams['scantable.allaxes']
297 return self.stats(stat='stddev',mask=mask, all=all);
298
299 def get_tsys(self, all=None):
300 """
301 Return the System temperatures.
302 Parameters:
303 all: optional parameter to get the Tsys values for all
304 Beams/IFs/Pols (default) or just the one selected
305 with scantable.set_cursor()
306 [True or False]
307 Returns:
308 a list of Tsys values.
309 """
310 if all is None: all = rcParams['scantable.allaxes']
311 from numarray import array,zeros,Float
312 axes = ['Beam','IF','Pol','Time']
313
314 if all:
315 n = self.nbeam()*self.nif()*self.npol()*self.nrow()
316 shp = [self.nbeam(),self.nif(),self.npol(),self.nrow()]
317 arr = array(zeros(n),shape=shp,type=Float)
318
319 for i in range(self.nbeam()):
320 self.setbeam(i)
321 for j in range(self.nif()):
322 self.setif(j)
323 for k in range(self.npol()):
324 self.setpol(k)
325 arr[i,j,k,:] = self._gettsys()
326 retval = {'axes': axes, 'data': arr, 'cursor':None}
327 tm = [self._gettime(val) for val in range(self.nrow())]
328 if self._vb:
329 self._print_values(retval,'Tsys',tm)
330 return retval
331
332 else:
333 i,j,k = (self.getbeam(),self.getif(),self.getpol())
334 statval = self._gettsys()
335 out = ''
336 for l in range(self.nrow()):
337 tm = self._gettime(l)
338 out += 'Time[%s]:\n' % (tm)
339 if self.nbeam() > 1: out += ' Beam[%d] ' % (i)
340 if self.nif() > 1: out += ' IF[%d] ' % (j)
341 if self.npol() > 1: out += ' Pol[%d] ' % (k)
342 out += '= %3.3f\n' % (statval[l])
343 out += "--------------------------------------------------\n"
344
345 if self._vb:
346 print "--------------------------------------------------"
347 print " TSys"
348 print "--------------------------------------------------"
349 print out
350 retval = {'axes': axes, 'data': array(statval), 'cursor':(i,j,k)}
351 return retval
352
353 def get_time(self, row=-1):
354 """
355 Get a list of time stamps for the observations.
356 Return a string for each integration in the scantable.
357 Parameters:
358 row: row no of integration. Default -1 return all rows
359 Example:
360 none
361 """
362 out = []
363 if row == -1:
364 for i in range(self.nrow()):
365 out.append(self._gettime(i))
366 return out
367 else:
368 if row < self.nrow():
369 return self._gettime(row)
370
371 def set_unit(self, unit='channel'):
372 """
373 Set the unit for all following operations on this scantable
374 Parameters:
375 unit: optional unit, default is 'channel'
376 one of '*Hz','km/s','channel', ''
377 """
378
379 if unit in ['','pixel', 'channel']:
380 unit = ''
381 inf = list(self._getcoordinfo())
382 inf[0] = unit
383 self._setcoordinfo(inf)
384 if self._p: self.plot()
385
386 def set_instrument (self, instr):
387 """
388 Set the instrument for subsequent processing
389 Parameters:
390 instr: Select from 'ATPKSMB', 'ATPKSHOH', 'ATMOPRA',
391 'DSS-43' (Tid), 'CEDUNA', and 'HOBART'
392 """
393 self._setInstrument(instr)
394
395 def set_doppler(self, doppler='RADIO'):
396 """
397 Set the doppler for all following operations on this scantable.
398 Parameters:
399 doppler: One of 'RADIO', 'OPTICAL', 'Z', 'BETA', 'GAMMA'
400 """
401
402 inf = list(self._getcoordinfo())
403 inf[2] = doppler
404 self._setcoordinfo(inf)
405 if self._p: self.plot()
406
407 def set_freqframe(self, frame=None):
408 """
409 Set the frame type of the Spectral Axis.
410 Parameters:
411 frame: an optional frame type, default 'LSRK'.
412 Examples:
413 scan.set_freqframe('BARY')
414 """
415 if not frame: frame = rcParams['scantable.freqframe']
416 valid = ['REST','TOPO','LSRD','LSRK','BARY', \
417 'GEO','GALACTO','LGROUP','CMB']
418 if frame in valid:
419 inf = list(self._getcoordinfo())
420 inf[1] = frame
421 self._setcoordinfo(inf)
422 else:
423 print "Please specify a valid freq type. Valid types are:\n",valid
424
425 def get_unit(self):
426 """
427 Get the default unit set in this scantable
428 Parameters:
429 Returns:
430 A unit string
431 """
432 inf = self._getcoordinfo()
433 unit = inf[0]
434 if unit == '': unit = 'channel'
435 return unit
436
437 def get_abcissa(self, rowno=0):
438 """
439 Get the abcissa in the current coordinate setup for the currently
440 selected Beam/IF/Pol
441 Parameters:
442 rowno: an optional row number in the scantable. Default is the
443 first row, i.e. rowno=0
444 Returns:
445 The abcissa values and it's format string (as a dictionary)
446 """
447 abc = self._getabcissa(rowno)
448 lbl = self._getabcissalabel(rowno)
449 return abc, lbl
450 #return {'abcissa':abc,'label':lbl}
451
452 def create_mask(self, *args, **kwargs):
453 """
454 Compute and return a mask based on [min,max] windows.
455 The specified windows are to be INCLUDED, when the mask is
456 applied.
457 Parameters:
458 [min,max],[min2,max2],...
459 Pairs of start/end points specifying the regions
460 to be masked
461 invert: optional argument. If specified as True,
462 return an inverted mask, i.e. the regions
463 specified are EXCLUDED
464 Example:
465 scan.set_unit('channel')
466
467 a)
468 msk = scan.set_mask([400,500],[800,900])
469 # masks everything outside 400 and 500
470 # and 800 and 900 in the unit 'channel'
471
472 b)
473 msk = scan.set_mask([400,500],[800,900], invert=True)
474 # masks the regions between 400 and 500
475 # and 800 and 900 in the unit 'channel'
476
477 """
478 u = self._getcoordinfo()[0]
479 if self._vb:
480 if u == "": u = "channel"
481 print "The current mask window unit is", u
482 n = self.nchan()
483 data = self._getabcissa()
484 msk = zeros(n)
485 for window in args:
486 if (len(window) != 2 or window[0] > window[1] ):
487 print "A window needs to be defined as [min,max]"
488 return
489 for i in range(n):
490 if data[i] >= window[0] and data[i] < window[1]:
491 msk[i] = 1
492 if kwargs.has_key('invert'):
493 if kwargs.get('invert'):
494 from numarray import logical_not
495 msk = logical_not(msk)
496 return msk
497
498 def get_restfreqs(self):
499 """
500 Get the restfrequency(s) stored in this scantable.
501 The return value(s) are always of unit 'Hz'
502 Parameters:
503 none
504 Returns:
505 a list of doubles
506 """
507 return list(self._getrestfreqs())
508
509 def lines(self):
510 """
511 Print the list of known spectral lines
512 """
513 sdtable._lines(self)
514
515 def set_restfreqs(self, freqs=None, unit='Hz', lines=None, source=None, theif=None):
516 """
517 Select the restfrequency for the specified source and IF OR
518 replace for all IFs. If the 'freqs' argument holds a scalar,
519 then that rest frequency will be applied to the selected
520 data (and added to the list of available rest frequencies).
521 In this way, you can set a rest frequency for each
522 source and IF combination. If the 'freqs' argument holds
523 a vector, then it MUST be of length the number of IFs
524 (and the available restfrequencies will be replaced by
525 this vector). In this case, *all* data ('source' and
526 'theif' are ignored) have the restfrequency set per IF according
527 to the corresponding value you give in the 'freqs' vector.
528 E.g. 'freqs=[1e9,2e9]' would mean IF 0 gets restfreq 1e9 and
529 IF 1 gets restfreq 2e9.
530
531 You can also specify the frequencies via known line names
532 in the argument 'lines'. Use 'freqs' or 'lines'. 'freqs'
533 takes precedence. See the list of known names via function
534 scantable.lines()
535 Parameters:
536 freqs: list of rest frequencies
537 unit: unit for rest frequency (default 'Hz')
538 lines: list of known spectral lines names (alternative to freqs).
539 See possible list via scantable.lines()
540 source: Source name (blank means all)
541 theif: IF (-1 means all)
542 Example:
543 scan.set_restfreqs(freqs=1.4e9, source='NGC253', theif=2)
544 scan.set_restfreqs(freqs=[1.4e9,1.67e9])
545 """
546 if source is None:
547 source = ""
548 if theif is None:
549 theif = -1
550 t = type(freqs)
551 if t is int or t is float:
552 freqs = [freqs]
553 if freqs is None:
554 freqs = []
555 t = type(lines)
556 if t is str:
557 lines = [lines]
558 if lines is None:
559 lines = []
560 sdtable._setrestfreqs(self, freqs, unit, lines, source, theif)
561 return
562
563
564 def flag_spectrum(self, thebeam, theif, thepol):
565 """
566 This flags a selected spectrum in the scan 'for good'.
567 USE WITH CARE - not reversible.
568 Use masks for non-permanent exclusion of channels.
569 Parameters:
570 thebeam,theif,thepol: all have to be explicitly
571 specified
572 Example:
573 scan.flag_spectrum(0,0,1)
574 flags the spectrum for Beam=0, IF=0, Pol=1
575 """
576 if (thebeam < self.nbeam() and
577 theif < self.nif() and
578 thepol < self.npol()):
579 sdtable.setbeam(self, thebeam)
580 sdtable.setif(self, theif)
581 sdtable.setpol(self, thepol)
582 sdtable._flag(self)
583 else:
584 print "Please specify a valid (Beam/IF/Pol)"
585 return
586
587 def rotate_xyphase (self, angle, all=None):
588 """
589 Rotate the phase of the XY correlation. This is done in situ
590 in the data. So if you call this function more than once
591 then each call rotates the phase further.
592 Parameters:
593 angle: The angle (degrees) to rotate (add) by.
594 all: if true operate on all axes (default or .asaprc) rather
595 than the cursor selected spectrum of Beam/IF
596 Examples:
597 scan.rotate_xyphase(2.3)
598 """
599 if all is None: all = rcParams['scantable.allaxes']
600 sdtable._rotate_xyphase(self, angle, all)
601
602 def plot(self, what='spectrum',col='Pol', panel=None):
603 """
604 Plot the spectra contained in the scan. Alternatively you can also
605 Plot Tsys vs Time
606 Parameters:
607 what: a choice of 'spectrum' (default) or 'tsys'
608 col: which out of Beams/IFs/Pols should be colour stacked
609 panel: set up multiple panels, currently not working.
610 """
611 print "Warning! Not fully functional. Use plotter.plot() instead"
612
613 validcol = {'Beam':self.nbeam(),'IF':self.nif(),'Pol':self.npol()}
614
615 validyax = ['spectrum','tsys']
616 from asap.asaplot import ASAPlot
617 if not self._p:
618 self._p = ASAPlot()
619 #print "Plotting not enabled"
620 #return
621 if self._p.is_dead:
622 del self._p
623 self._p = ASAPlot()
624 npan = 1
625 x = None
626 if what == 'tsys':
627 n = self.nrow()
628 if n < 2:
629 print "Only one integration. Can't plot."
630 return
631 self._p.hold()
632 self._p.clear()
633 if panel == 'Time':
634 npan = self.nrow()
635 self._p.set_panels(rows=npan)
636 xlab,ylab,tlab = None,None,None
637 self._vb = False
638 sel = self.get_cursor()
639 for i in range(npan):
640 if npan > 1:
641 self._p.subplot(i)
642 for j in range(validcol[col]):
643 x = None
644 y = None
645 m = None
646 tlab = self._getsourcename(i)
647 import re
648 tlab = re.sub('_S','',tlab)
649 if col == 'Beam':
650 self.setbeam(j)
651 elif col == 'IF':
652 self.setif(j)
653 elif col == 'Pol':
654 self.setpol(j)
655 if what == 'tsys':
656 x = range(self.nrow())
657 xlab = 'Time [pixel]'
658 m = list(ones(len(x)))
659 y = []
660 ylab = r'$T_{sys}$'
661 for k in range(len(x)):
662 y.append(self._gettsys(k))
663 else:
664 x,xlab = self.get_abcissa(i)
665 y = self._getspectrum(i)
666 ylab = r'Flux'
667 m = self._getmask(i)
668 llab = col+' '+str(j)
669 self._p.set_line(label=llab)
670 self._p.plot(x,y,m)
671 self._p.set_axes('xlabel',xlab)
672 self._p.set_axes('ylabel',ylab)
673 self._p.set_axes('title',tlab)
674 self._p.release()
675 self.set_cursor(sel[0],sel[1],sel[2])
676 self._vb = rcParams['verbose']
677 return
678
679 print out
680
681 def _print_values(self, dat, label='', timestamps=[]):
682 d = dat['data']
683 a = dat['axes']
684 shp = d.getshape()
685 out = ''
686 for i in range(shp[3]):
687 out += '%s [%s]:\n' % (a[3],timestamps[i])
688 t = d[:,:,:,i]
689 for j in range(shp[0]):
690 if shp[0] > 1: out += ' %s[%d] ' % (a[0],j)
691 for k in range(shp[1]):
692 if shp[1] > 1: out += ' %s[%d] ' % (a[1],k)
693 for l in range(shp[2]):
694 if shp[2] > 1: out += ' %s[%d] ' % (a[2],l)
695 out += '= %3.3f\n' % (t[j,k,l])
696 out += "--------------------------------------------------\n"
697 print "--------------------------------------------------"
698 print " ", label
699 print "--------------------------------------------------"
700 print out
Note: See TracBrowser for help on using the repository browser.