source: trunk/python/scantable.py @ 334

Last change on this file since 334 was 334, checked in by kil064, 19 years ago

track change to asapreader interface

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