source: trunk/python/scantable.py@ 449

Last change on this file since 449 was 445, checked in by kil064, 20 years ago

add stokes conversion arg. to function 'save'

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