source: trunk/python/scantable.py @ 372

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

add binding to function set_instrument (instead of direct pythin binding)

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