source: trunk/python/scantable.py @ 280

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

document function 'save' better for 'image fits' output

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