source: branches/Release12/python/scantable.py @ 786

Last change on this file since 786 was 786, checked in by mar637, 18 years ago

added allaxes arg to poly_baseline

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 59.4 KB
Line 
1from asap._asap import sdtable
2from asap import rcParams
3from asap import print_log
4from numarray import ones,zeros
5import sys
6
7class scantable(sdtable):
8    """
9        The ASAP container for scans
10    """
11
12    def __init__(self, filename, average=None, unit=None):
13        """
14        Create a scantable from a saved one or make a reference
15        Parameters:
16            filename:    the name of an asap table on disk
17                         or
18                         the name of a rpfits/sdfits/ms file
19                         (integrations within scans are auto averaged
20                         and the whole file is read)
21                         or
22                         [advanced] a reference to an existing
23                         scantable
24            average:     average all integrations withinb a scan on read.
25                         The default (True) is taken from .asaprc.
26            unit:         brightness unit; must be consistent with K or Jy.
27                         Over-rides the default selected by the reader
28                         (input rpfits/sdfits/ms) or replaces the value
29                         in existing scantables
30        """
31        if average is None or type(average) is not bool:
32            average = rcParams['scantable.autoaverage']
33
34        varlist = vars()
35        self._p = None
36        from asap import asaplog
37        if isinstance(filename,sdtable):
38            sdtable.__init__(self, filename)
39            if unit is not None:
40                self.set_fluxunit(unit)
41        else:
42            import os.path
43            if not os.path.exists(filename):
44                s = "File '%s' not found." % (filename)
45                if rcParams['verbose']:
46                    asaplog.push(s)
47                    print asaplog.pop().strip()
48                    return
49                raise IOError(s)
50            filename = os.path.expandvars(filename)
51            if os.path.isdir(filename):
52                # crude check if asap table
53                if os.path.exists(filename+'/table.info'):
54                    sdtable.__init__(self, filename)
55                    if unit is not None:
56                        self.set_fluxunit(unit)
57                else:
58                    msg = "The given file '%s'is not a valid asap table." % (filename)
59                    if rcParams['verbose']:
60                        print msg
61                        return
62                    else:
63                        raise IOError(msg)
64            else:
65                from asap._asap import sdreader
66                ifSel = -1
67                beamSel = -1
68                r = sdreader()
69                r._open(filename,ifSel,beamSel)
70                asaplog.push('Importing data...')
71                print_log()
72                r._read([-1])
73                tbl = r._getdata()
74                if unit is not None:
75                    tbl.set_fluxunit(unit)
76                if average:
77                    from asap._asap import average as _av
78                    asaplog.push('Auto averaging integrations...')
79                    print_log()
80                    tbl2 = _av((tbl,),(),True,'none')
81                    sdtable.__init__(self,tbl2)
82                    del tbl2
83                else:
84                    sdtable.__init__(self,tbl)
85                del r,tbl
86                self._add_history("scantable", varlist)
87        print_log()
88
89    def save(self, name=None, format=None, stokes=False, overwrite=False):
90        """
91        Store the scantable on disk. This can be an asap (aips++) Table, SDFITS,
92        Image FITS or MS2 format.
93        Parameters:
94            name:        the name of the outputfile. For format="FITS" this
95                         is the directory file name into which all the files
96                         will be written (default is 'asap_FITS'). For format
97                         "ASCII" this is the root file name (data in 'name'.txt
98                         and header in 'name'_header.txt)
99            format:      an optional file format. Default is ASAP.
100                         Allowed are - 'ASAP' (save as ASAP [aips++] Table),
101                                       'SDFITS' (save as SDFITS file)
102                                       'FITS' (saves each row as a FITS Image)
103                                       'ASCII' (saves as ascii text file)
104                                       'MS2' (saves as an aips++
105                                              MeasurementSet V2)
106            stokes:      Convert to Stokes parameters (only available
107                         currently with FITS and ASCII formats.
108                         Default is False.
109            overwrite:   If the file should be overwritten if it exists.
110                         The default False is to return with warning
111                         without writing the output. USE WITH CARE.
112        Example:
113            scan.save('myscan.asap')
114            scan.save('myscan.sdfits','SDFITS')
115        """
116        from os import path
117        if format is None: format = rcParams['scantable.save']
118        suffix = '.'+format.lower()
119        if name is None or name =="":
120            name = 'scantable'+suffix
121            from asap import asaplog
122            msg = "No filename given. Using default name %s..." % name
123            asaplog.push(msg)
124        name = path.expandvars(name)
125        if path.isfile(name) or path.isdir(name):
126            if not overwrite:
127                msg = "File %s exists." % name
128                if rcParams['verbose']:
129                    print msg
130                    return
131                else:
132                    raise IOError(msg)
133        format2 = format.upper()
134        if format2 == 'ASAP':
135            self._save(name)
136        else:
137            from asap._asap import sdwriter as _sw
138            w = _sw(format2)
139            w.write(self, name, stokes)
140
141        print_log()
142        return
143
144    def copy(self):
145        """
146        Return a copy of this scantable.
147        Parameters:
148            none
149        Example:
150            copiedscan = scan.copy()
151        """
152        sd = scantable(sdtable._copy(self))
153        return sd
154
155    def get_scan(self, scanid=None):
156        """
157        Return a specific scan (by scanno) or collection of scans (by
158        source name) in a new scantable.
159        Parameters:
160            scanid:    a (list of) scanno or a source name, unix-style
161                       patterns are accepted for source name matching, e.g.
162                       '*_R' gets all 'ref scans
163        Example:
164            # get all scans containing the source '323p459'
165            newscan = scan.get_scan('323p459')
166            # get all 'off' scans
167            refscans = scan.get_scan('*_R')
168            # get a susbset of scans by scanno (as listed in scan.summary())
169            newscan = scan.get_scan([0,2,7,10])
170        """
171        if scanid is None:
172            if rcParams['verbose']:
173                print "Please specify a scan no or name to retrieve from the scantable"
174                return
175            else:
176                raise RuntimeError("No scan given")
177
178        try:
179            if type(scanid) is str:
180                s = sdtable._getsource(self,scanid)
181                return scantable(s)
182            elif type(scanid) is int:
183                s = sdtable._getscan(self,[scanid])
184                return scantable(s)
185            elif type(scanid) is list:
186                s = sdtable._getscan(self,scanid)
187                return scantable(s)
188            else:
189                msg = "Illegal scanid type, use 'int' or 'list' if ints."
190                if rcParams['verbose']:
191                    print msg
192                else:
193                    raise TypeError(msg)
194        except RuntimeError:
195            if rcParams['verbose']: print "Couldn't find any match."
196            else: raise
197
198    def __str__(self):
199        return sdtable._summary(self,True)
200
201    def summary(self,filename=None, verbose=None):
202        """
203        Print a summary of the contents of this scantable.
204        Parameters:
205            filename:    the name of a file to write the putput to
206                         Default - no file output
207            verbose:     print extra info such as the frequency table
208                         The default (False) is taken from .asaprc
209        """
210        info = sdtable._summary(self, verbose)
211        if verbose is None: verbose = rcParams['scantable.verbosesummary']
212        if filename is not None:
213            if filename is "":
214                filename = 'scantable_summary.txt'
215            from os.path import expandvars, isdir
216            filename = expandvars(filename)
217            if not isdir(filename):
218                data = open(filename, 'w')
219                data.write(info)
220                data.close()
221            else:
222                msg = "Illegal file name '%s'." % (filename)
223                if rcParams['verbose']:
224                    print msg
225                else:
226                    raise IOError(msg)
227        if rcParams['verbose']:
228            print info
229        else:
230            return info
231
232    def set_cursor(self, beam=0, IF=0, pol=0):
233        """
234        Set the spectrum for individual operations.
235        Parameters:
236            beam, IF, pol:    a number
237        Example:
238            scan.set_cursor(0,0,1)
239            pol1sig = scan.stats(all=False) # returns std dev for beam=0
240                                            # if=0, pol=1
241        """
242        varlist = vars()
243        self.setbeam(beam)
244        self.setpol(pol)
245        self.setif(IF)
246        self._add_history("set_cursor",varlist)
247        return
248
249    def get_cursor(self):
250        """
251        Return/print a the current 'cursor' into the Beam/IF/Pol cube.
252        Parameters:
253            none
254        Returns:
255            a list of values (currentBeam,currentIF,currentPol)
256        Example:
257            none
258        """
259        i = self.getbeam()
260        j = self.getif()
261        k = self.getpol()
262        from asap import asaplog
263        out = "--------------------------------------------------\n"
264        out += " Cursor position\n"
265        out += "--------------------------------------------------\n"
266        out += 'Beam=%d IF=%d Pol=%d ' % (i,j,k)
267        asaplog.push(out)
268        print_log()
269        return i,j,k
270
271    def stats(self, stat='stddev', mask=None, allaxes=None):
272        """
273        Determine the specified statistic of the current beam/if/pol
274        Takes a 'mask' as an optional parameter to specify which
275        channels should be excluded.
276        Parameters:
277            stat:    'min', 'max', 'sumsq', 'sum', 'mean'
278                     'var', 'stddev', 'avdev', 'rms', 'median'
279            mask:    an optional mask specifying where the statistic
280                     should be determined.
281            allaxes: if True apply to all spectra. Otherwise
282                     apply only to the selected (beam/pol/if)spectra only.
283                     The default is taken from .asaprc (True if none)
284        Example:
285            scan.set_unit('channel')
286            msk = scan.create_mask([100,200],[500,600])
287            scan.stats(stat='mean', mask=m)
288        """
289        if allaxes is None: allaxes = rcParams['scantable.allaxes']
290        from asap._asap import stats as _stats
291        from numarray import array,zeros,Float
292        if mask == None:
293            mask = ones(self.nchan())
294        axes = ['Beam','IF','Pol','Time']
295
296        beamSel,IFSel,polSel = (self.getbeam(),self.getif(),self.getpol())
297        if allaxes:
298            n = self.nbeam()*self.nif()*self.npol()*self.nrow()
299            shp = [self.nbeam(),self.nif(),self.npol(),self.nrow()]
300            arr = array(zeros(n),shape=shp,type=Float)
301
302            for i in range(self.nbeam()):
303                self.setbeam(i)
304                for j in range(self.nif()):
305                    self.setif(j)
306                    for k in range(self.npol()):
307                        self.setpol(k)
308                        arr[i,j,k,:] = _stats(self,mask,stat,-1)
309            retval = {'axes': axes, 'data': arr, 'cursor':None}
310            tm = [self._gettime(val) for val in range(self.nrow())]
311            if rcParams['verbose']:
312                self._print_values(retval,stat,tm)
313            self.setbeam(beamSel)
314            self.setif(IFSel)
315            self.setpol(polSel)
316            return retval
317
318        else:
319            statval = _stats(self,mask,stat,-1)
320            out = ''
321            for l in range(self.nrow()):
322                tm = self._gettime(l)
323                out += 'Time[%s]:\n' % (tm)
324                if self.nbeam() > 1: out +=  ' Beam[%d] ' % (beamSel)
325                if self.nif() > 1: out +=  ' IF[%d] ' % (IFSel)
326                if self.npol() > 1: out +=  ' Pol[%d] ' % (polSel)
327                out += '= %3.3f\n' % (statval[l])
328                out +=  "--------------------------------------------------\n"
329
330            if rcParams['verbose']:
331                print "--------------------------------------------------"
332                print " ",stat
333                print "--------------------------------------------------"
334                print out
335            retval = {'axes': axes, 'data': array(statval), 'cursor':(i,j,k)}
336            return retval
337
338    def stddev(self,mask=None, allaxes=None):
339        """
340        Determine the standard deviation of the current beam/if/pol
341        Takes a 'mask' as an optional parameter to specify which
342        channels should be excluded.
343        Parameters:
344            mask:    an optional mask specifying where the standard
345                     deviation should be determined.
346            allaxes: optional flag to show all or a cursor selected
347                     spectrum of Beam/IF/Pol. Default is all or taken
348                     from .asaprc
349
350        Example:
351            scan.set_unit('channel')
352            msk = scan.create_mask([100,200],[500,600])
353            scan.stddev(mask=m)
354        """
355        if allaxes is None: allaxes = rcParams['scantable.allaxes']
356        return self.stats(stat='stddev',mask=mask, allaxes=allaxes);
357
358    def get_tsys(self, allaxes=None):
359        """
360        Return the System temperatures.
361        Parameters:
362           allaxes:     if True apply to all spectra. Otherwise
363                        apply only to the selected (beam/pol/if)spectra only.
364                        The default is taken from .asaprc (True if none)
365        Returns:
366            a list of Tsys values.
367        """
368        if allaxes is None: allaxes = rcParams['scantable.allaxes']
369        from numarray import array,zeros,Float
370        axes = ['Beam','IF','Pol','Time']
371
372        if allaxes:
373            n = self.nbeam()*self.nif()*self.npol()*self.nrow()
374            shp = [self.nbeam(),self.nif(),self.npol(),self.nrow()]
375            arr = array(zeros(n),shape=shp,type=Float)
376
377            for i in range(self.nbeam()):
378                self.setbeam(i)
379                for j in range(self.nif()):
380                    self.setif(j)
381                    for k in range(self.npol()):
382                        self.setpol(k)
383                        arr[i,j,k,:] = self._gettsys()
384            retval = {'axes': axes, 'data': arr, 'cursor':None}
385            tm = [self._gettime(val) for val in range(self.nrow())]
386            if rcParams['verbose']:
387                self._print_values(retval,'Tsys',tm)
388            return retval
389
390        else:
391            i,j,k = (self.getbeam(),self.getif(),self.getpol())
392            statval = self._gettsys()
393            out = ''
394            for l in range(self.nrow()):
395                tm = self._gettime(l)
396                out += 'Time[%s]:\n' % (tm)
397                if self.nbeam() > 1: out +=  ' Beam[%d] ' % (i)
398                if self.nif() > 1: out +=  ' IF[%d] ' % (j)
399                if self.npol() > 1: out +=  ' Pol[%d] ' % (k)
400                out += '= %3.3f\n' % (statval[l])
401                out +=  "--------------------------------------------------\n"
402
403            if rcParams['verbose']:
404                print "--------------------------------------------------"
405                print " TSys"
406                print "--------------------------------------------------"
407                print out
408            retval = {'axes': axes, 'data': array(statval), 'cursor':(i,j,k)}
409            return retval
410
411    def get_time(self, row=-1):
412        """
413        Get a list of time stamps for the observations.
414        Return a string for each integration in the scantable.
415        Parameters:
416            row:    row no of integration. Default -1 return all rows
417        Example:
418            none
419        """
420        out = []
421        if row == -1:
422            for i in range(self.nrow()):
423                out.append(self._gettime(i))
424            return out
425        else:
426            if row < self.nrow():
427                return self._gettime(row)
428
429    def get_sourcename(self, row=-1):
430        """
431        Get a list source anmes for the observations.
432        Return a string for each integration in the scantable.
433        Parameters:
434            row:    row no of integration. Default -1 return all rows
435        Example:
436            none
437        """
438        out = []
439        if row == -1:
440            return [self._getsourcename(i) for i in range(self.nrow())]
441        else:
442            if  0 <= row < self.nrow():
443                return self._getsourcename(row)
444
445    def set_unit(self, unit='channel'):
446        """
447        Set the unit for all following operations on this scantable
448        Parameters:
449            unit:    optional unit, default is 'channel'
450                     one of '*Hz','km/s','channel', ''
451        """
452        varlist = vars()
453        if unit in ['','pixel', 'channel']:
454            unit = ''
455        inf = list(self._getcoordinfo())
456        inf[0] = unit
457        self._setcoordinfo(inf)
458        if self._p: self.plot()
459        self._add_history("set_unit",varlist)
460
461    def set_instrument(self, instr):
462        """
463        Set the instrument for subsequent processing
464        Parameters:
465            instr:    Select from 'ATPKSMB', 'ATPKSHOH', 'ATMOPRA',
466                      'DSS-43' (Tid), 'CEDUNA', and 'HOBART'
467        """
468        self._setInstrument(instr)
469        self._add_history("set_instument",vars())
470        print_log()
471
472    def set_doppler(self, doppler='RADIO'):
473        """
474        Set the doppler for all following operations on this scantable.
475        Parameters:
476            doppler:    One of 'RADIO', 'OPTICAL', 'Z', 'BETA', 'GAMMA'
477        """
478        varlist = vars()
479        inf = list(self._getcoordinfo())
480        inf[2] = doppler
481        self._setcoordinfo(inf)
482        if self._p: self.plot()
483        self._add_history("set_doppler",vars())
484        print_log()
485
486    def set_freqframe(self, frame=None):
487        """
488        Set the frame type of the Spectral Axis.
489        Parameters:
490            frame:   an optional frame type, default 'LSRK'. Valid frames are:
491                     'REST','TOPO','LSRD','LSRK','BARY',
492                     'GEO','GALACTO','LGROUP','CMB'
493        Examples:
494            scan.set_freqframe('BARY')
495        """
496        if frame is None: frame = rcParams['scantable.freqframe']
497        varlist = vars()
498        valid = ['REST','TOPO','LSRD','LSRK','BARY', \
499                   'GEO','GALACTO','LGROUP','CMB']
500
501        if frame in valid:
502            inf = list(self._getcoordinfo())
503            inf[1] = frame
504            self._setcoordinfo(inf)
505            self._add_history("set_freqframe",varlist)
506        else:
507            msg  = "Please specify a valid freq type. Valid types are:\n",valid
508            if rcParams['verbose']:
509                print msg
510            else:
511                raise TypeError(msg)
512        print_log()
513
514    def get_unit(self):
515        """
516        Get the default unit set in this scantable
517        Parameters:
518        Returns:
519            A unit string
520        """
521        inf = self._getcoordinfo()
522        unit = inf[0]
523        if unit == '': unit = 'channel'
524        return unit
525
526    def get_abcissa(self, rowno=0):
527        """
528        Get the abcissa in the current coordinate setup for the currently
529        selected Beam/IF/Pol
530        Parameters:
531            rowno:    an optional row number in the scantable. Default is the
532                      first row, i.e. rowno=0
533        Returns:
534            The abcissa values and it's format string (as a dictionary)
535        """
536        abc = self._getabcissa(rowno)
537        lbl = self._getabcissalabel(rowno)
538        print_log()
539        return abc, lbl
540
541    def create_mask(self, *args, **kwargs):
542        """
543        Compute and return a mask based on [min,max] windows.
544        The specified windows are to be INCLUDED, when the mask is
545        applied.
546        Parameters:
547            [min,max],[min2,max2],...
548                Pairs of start/end points specifying the regions
549                to be masked
550            invert:     optional argument. If specified as True,
551                        return an inverted mask, i.e. the regions
552                        specified are EXCLUDED
553            row:        create the mask using the specified row for
554                        unit conversions, default is row=0
555                        only necessary if frequency varies over rows.
556        Example:
557            scan.set_unit('channel')
558
559            a)
560            msk = scan.set_mask([400,500],[800,900])
561            # masks everything outside 400 and 500
562            # and 800 and 900 in the unit 'channel'
563
564            b)
565            msk = scan.set_mask([400,500],[800,900], invert=True)
566            # masks the regions between 400 and 500
567            # and 800 and 900 in the unit 'channel'
568
569        """
570        row = 0
571        if kwargs.has_key("row"):
572            row = kwargs.get("row")
573        data = self._getabcissa(row)
574        u = self._getcoordinfo()[0]
575        if rcParams['verbose']:
576            if u == "": u = "channel"
577            from asap import asaplog
578            msg = "The current mask window unit is %s" % u
579            asaplog.push(msg)
580        n = self.nchan()
581        msk = zeros(n)
582        # test if args is a 'list' or a 'normal *args - UGLY!!!
583
584        ws = (isinstance(args[-1][-1],int) or isinstance(args[-1][-1],float)) and args or args[0]
585        for window in ws:
586            if (len(window) != 2 or window[0] > window[1] ):
587                raise TypeError("A window needs to be defined as [min,max]")
588            for i in range(n):
589                if data[i] >= window[0] and data[i] < window[1]:
590                    msk[i] = 1
591        if kwargs.has_key('invert'):
592            if kwargs.get('invert'):
593                from numarray import logical_not
594                msk = logical_not(msk)
595        print_log()
596        return msk
597
598    def get_restfreqs(self):
599        """
600        Get the restfrequency(s) stored in this scantable.
601        The return value(s) are always of unit 'Hz'
602        Parameters:
603            none
604        Returns:
605            a list of doubles
606        """
607        return list(self._getrestfreqs())
608
609    def lines(self):
610        """
611        Print the list of known spectral lines
612        """
613        l = sdtable._lines(self)
614        if rcParams['verbose']:
615            print l
616        else:
617            return l
618
619    def set_restfreqs(self, freqs=None, unit='Hz', lines=None, source=None,
620                      theif=None):
621        """
622        Select the restfrequency for the specified source and IF OR
623        replace for all IFs.  If the 'freqs' argument holds a scalar,
624        then that rest frequency will be applied to the selected
625        data (and added to the list of available rest frequencies).
626        In this way, you can set a rest frequency for each
627        source and IF combination.   If the 'freqs' argument holds
628        a vector, then it MUST be of length the number of IFs
629        (and the available restfrequencies will be replaced by
630        this vector).  In this case, *all* data ('source' and
631        'theif' are ignored) have the restfrequency set per IF according
632        to the corresponding value you give in the 'freqs' vector.
633        E.g. 'freqs=[1e9,2e9]'  would mean IF 0 gets restfreq 1e9 and
634        IF 1 gets restfreq 2e9.
635
636        You can also specify the frequencies via known line names
637        in the argument 'lines'.  Use 'freqs' or 'lines'.  'freqs'
638        takes precedence. See the list of known names via function
639        scantable.lines()
640        Parameters:
641            freqs:   list of rest frequencies
642            unit:    unit for rest frequency (default 'Hz')
643            lines:   list of known spectral lines names (alternative to freqs).
644                     See possible list via scantable.lines()
645            source:  Source name (blank means all)
646            theif:   IF (-1 means all)
647        Example:
648            scan.set_restfreqs(freqs=1.4e9, source='NGC253', theif=2)
649            scan.set_restfreqs(freqs=[1.4e9,1.67e9])
650        """
651        varlist = vars()
652        if source is None:
653            source = ""
654        if theif is None:
655            theif = -1
656        t = type(freqs)
657        if t is int or t is float:
658           freqs = [freqs]
659        if freqs is None:
660           freqs = []
661        t = type(lines)
662        if t is str:
663           lines = [lines]
664        if lines is None:
665           lines = []
666        sdtable._setrestfreqs(self, freqs, unit, lines, source, theif)
667        self._add_history("set_restfreqs", varlist)
668
669
670
671    def flag_spectrum(self, thebeam, theif, thepol):
672        """
673        This flags a selected spectrum in the scan 'for good'.
674        USE WITH CARE - not reversible.
675        Use masks for non-permanent exclusion of channels.
676        Parameters:
677            thebeam,theif,thepol:    all have to be explicitly
678                                     specified
679        Example:
680            scan.flag_spectrum(0,0,1)
681            flags the spectrum for Beam=0, IF=0, Pol=1
682        """
683        if (thebeam < self.nbeam() and
684            theif < self.nif() and
685            thepol < self.npol()):
686            sdtable.setbeam(self, thebeam)
687            sdtable.setif(self, theif)
688            sdtable.setpol(self, thepol)
689            sdtable._flag(self)
690            self._add_history("flag_spectrum", vars())
691        else:
692            print "Please specify a valid (Beam/IF/Pol)"
693        return
694
695    def _print_values(self, dat, label='', timestamps=[]):
696        d = dat['data']
697        a = dat['axes']
698        shp = d.getshape()
699        out = ''
700        for i in range(shp[3]):
701            out += '%s [%s]:\n' % (a[3],timestamps[i])
702            t = d[:,:,:,i]
703            for j in range(shp[0]):
704                if shp[0] > 1: out +=  ' %s[%d] ' % (a[0],j)
705                for k in range(shp[1]):
706                    if shp[1] > 1: out +=  ' %s[%d] ' % (a[1],k)
707                    for l in range(shp[2]):
708                        if shp[2] > 1: out +=  ' %s[%d] ' % (a[2],l)
709                        out += '= %3.3f\n' % (t[j,k,l])
710            out += "-"*80
711            out += "\n"
712        print "-"*80
713        print " ", label
714        print "-"*80
715        print out
716
717    def history(self):
718        hist = list(self._gethistory())
719        print "-"*80
720        for h in hist:
721            if h.startswith("---"):
722                print h
723            else:
724                items = h.split("##")
725                date = items[0]
726                func = items[1]
727                items = items[2:]
728                print date
729                print "Function: %s\n  Parameters:" % (func)
730                for i in items:
731                    s = i.split("=")
732                    print "   %s = %s" % (s[0],s[1])
733                print "-"*80
734        return
735
736    #
737    # Maths business
738    #
739
740    def average_time(self, mask=None, scanav=False, weight='tint'):
741        """
742        Return the (time) average of a scan, or apply it 'insitu'.
743        Note:
744            in channels only
745            The cursor of the output scan is set to 0.
746        Parameters:
747            one scan or comma separated  scans
748            mask:     an optional mask (only used for 'var' and 'tsys'
749                      weighting)
750            scanav:   True averages each scan separately
751                      False (default) averages all scans together,
752            weight:   Weighting scheme. 'none', 'var' (1/var(spec)
753                      weighted), 'tsys' (1/Tsys**2 weighted), 'tint'
754                      (integration time weighted) or 'tintsys' (Tint/Tsys**2).
755                      The default is 'tint'
756        Example:
757            # time average the scantable without using a mask
758            newscan = scan.average_time()
759        """
760        varlist = vars()
761        if weight is None: weight = 'tint'
762        if mask is None: mask = ()
763        from asap._asap import average as _av
764        s = scantable(_av((self,), mask, scanav, weight))
765        s._add_history("average_time",varlist)
766        print_log()
767        return s
768
769    def convert_flux(self, jyperk=None, eta=None, d=None, insitu=None,
770                     allaxes=None):
771        """
772        Return a scan where all spectra are converted to either
773        Jansky or Kelvin depending upon the flux units of the scan table.
774        By default the function tries to look the values up internally.
775        If it can't find them (or if you want to over-ride), you must
776        specify EITHER jyperk OR eta (and D which it will try to look up
777        also if you don't set it). jyperk takes precedence if you set both.
778        Parameters:
779            jyperk:      the Jy / K conversion factor
780            eta:         the aperture efficiency
781            d:           the geomtric diameter (metres)
782            insitu:      if False a new scantable is returned.
783                         Otherwise, the scaling is done in-situ
784                         The default is taken from .asaprc (False)
785            allaxes:         if True apply to all spectra. Otherwise
786                         apply only to the selected (beam/pol/if)spectra only
787                         The default is taken from .asaprc (True if none)
788        """
789        if allaxes is None: allaxes = rcParams['scantable.allaxes']
790        if insitu is None: insitu = rcParams['insitu']
791        varlist = vars()
792        if jyperk is None: jyperk = -1.0
793        if d is None: d = -1.0
794        if eta is None: eta = -1.0
795        if not insitu:
796            from asap._asap import convertflux as _convert
797            s = scantable(_convert(self, d, eta, jyperk, allaxes))
798            s._add_history("convert_flux", varlist)
799            print_log()
800            return s
801        else:
802            from asap._asap import convertflux_insitu as _convert
803            _convert(self, d, eta, jyperk, allaxes)
804            self._add_history("convert_flux", varlist)
805            print_log()
806            return
807
808    def gain_el(self, poly=None, filename="", method="linear",
809                insitu=None, allaxes=None):
810        """
811        Return a scan after applying a gain-elevation correction.
812        The correction can be made via either a polynomial or a
813        table-based interpolation (and extrapolation if necessary).
814        You specify polynomial coefficients, an ascii table or neither.
815        If you specify neither, then a polynomial correction will be made
816        with built in coefficients known for certain telescopes (an error
817        will occur if the instrument is not known).
818        The data and Tsys are *divided* by the scaling factors.
819        Parameters:
820            poly:        Polynomial coefficients (default None) to compute a
821                         gain-elevation correction as a function of
822                         elevation (in degrees).
823            filename:    The name of an ascii file holding correction factors.
824                         The first row of the ascii file must give the column
825                         names and these MUST include columns
826                         "ELEVATION" (degrees) and "FACTOR" (multiply data
827                         by this) somewhere.
828                         The second row must give the data type of the
829                         column. Use 'R' for Real and 'I' for Integer.
830                         An example file would be
831                         (actual factors are arbitrary) :
832
833                         TIME ELEVATION FACTOR
834                         R R R
835                         0.1 0 0.8
836                         0.2 20 0.85
837                         0.3 40 0.9
838                         0.4 60 0.85
839                         0.5 80 0.8
840                         0.6 90 0.75
841            method:      Interpolation method when correcting from a table.
842                         Values are  "nearest", "linear" (default), "cubic"
843                         and "spline"
844            insitu:      if False a new scantable is returned.
845                         Otherwise, the scaling is done in-situ
846                         The default is taken from .asaprc (False)
847            allaxes:     If True apply to all spectra. Otherwise
848                         apply only to the selected (beam/pol/if) spectra only
849                         The default is taken from .asaprc (True if none)
850        """
851
852        if allaxes is None: allaxes = rcParams['scantable.allaxes']
853        if insitu is None: insitu = rcParams['insitu']
854        varlist = vars()
855        if poly is None:
856           poly = ()
857        from os.path import expandvars
858        filename = expandvars(filename)
859        if not insitu:
860            from asap._asap import gainel as _gainEl
861            s = scantable(_gainEl(self, poly, filename, method, allaxes))
862            s._add_history("gain_el", varlist)
863            print_log()
864            return s
865        else:
866            from asap._asap import gainel_insitu as _gainEl
867            _gainEl(self, poly, filename, method, allaxes)
868            self._add_history("gain_el", varlist)
869            print_log()
870            return
871
872    def freq_align(self, reftime=None, method='cubic', perif=False,
873                   insitu=None):
874        """
875        Return a scan where all rows have been aligned in frequency/velocity.
876        The alignment frequency frame (e.g. LSRK) is that set by function
877        set_freqframe.
878        Parameters:
879            reftime:     reference time to align at. By default, the time of
880                         the first row of data is used.
881            method:      Interpolation method for regridding the spectra.
882                         Choose from "nearest", "linear", "cubic" (default)
883                         and "spline"
884            perif:       Generate aligners per freqID (no doppler tracking) or
885                         per IF (scan-based doppler tracking)
886            insitu:      if False a new scantable is returned.
887                         Otherwise, the scaling is done in-situ
888                         The default is taken from .asaprc (False)
889        """
890        if insitu is None: insitu = rcParams['insitu']
891        varlist = vars()
892        if reftime is None: reftime = ''
893        perfreqid = not perif
894        if not insitu:
895            from asap._asap import freq_align as _align
896            s = scantable(_align(self, reftime, method, perfreqid))
897            s._add_history("freq_align", varlist)
898            print_log()
899            return s
900        else:
901            from asap._asap import freq_align_insitu as _align
902            _align(self, reftime, method, perfreqid)
903            self._add_history("freq_align", varlist)
904            print_log()
905            return
906
907    def opacity(self, tau, insitu=None, allaxes=None):
908        """
909        Apply an opacity correction. The data
910        and Tsys are multiplied by the correction factor.
911        Parameters:
912            tau:         Opacity from which the correction factor is
913                         exp(tau*ZD)
914                         where ZD is the zenith-distance
915            insitu:      if False a new scantable is returned.
916                         Otherwise, the scaling is done in-situ
917                         The default is taken from .asaprc (False)
918            allaxes:     if True apply to all spectra. Otherwise
919                         apply only to the selected (beam/pol/if)spectra only
920                         The default is taken from .asaprc (True if none)
921        """
922        if allaxes is None: allaxes = rcParams['scantable.allaxes']
923        if insitu is None: insitu = rcParams['insitu']
924        varlist = vars()
925        if not insitu:
926            from asap._asap import opacity as _opacity
927            s = scantable(_opacity(self, tau, allaxes))
928            s._add_history("opacity", varlist)
929            print_log()
930            return s
931        else:
932            from asap._asap import opacity_insitu as _opacity
933            _opacity(self, tau, allaxes)
934            self._add_history("opacity", varlist)
935            print_log()
936            return
937
938    def bin(self, width=5, insitu=None):
939        """
940        Return a scan where all spectra have been binned up.
941            width:       The bin width (default=5) in pixels
942            insitu:      if False a new scantable is returned.
943                         Otherwise, the scaling is done in-situ
944                         The default is taken from .asaprc (False)
945        """
946        if insitu is None: insitu = rcParams['insitu']
947        varlist = vars()
948        if not insitu:
949            from asap._asap import bin as _bin
950            s = scantable(_bin(self, width))
951            s._add_history("bin",varlist)
952            print_log()
953            return s
954        else:
955            from asap._asap import bin_insitu as _bin
956            _bin(self, width)
957            self._add_history("bin",varlist)
958            print_log()
959            return
960
961
962    def resample(self, width=5, method='cubic', insitu=None):
963        """
964        Return a scan where all spectra have been binned up
965            width:       The bin width (default=5) in pixels
966            method:      Interpolation method when correcting from a table.
967                         Values are  "nearest", "linear", "cubic" (default)
968                         and "spline"
969            insitu:      if False a new scantable is returned.
970                         Otherwise, the scaling is done in-situ
971                         The default is taken from .asaprc (False)
972        """
973        if insitu is None: insitu = rcParams['insitu']
974        varlist = vars()
975        if not insitu:
976            from asap._asap import resample as _resample
977            s = scantable(_resample(self, method, width))
978            s._add_history("resample",varlist)
979            print_log()
980            return s
981        else:
982            from asap._asap import resample_insitu as _resample
983            _resample(self, method, width)
984            self._add_history("resample",varlist)
985            print_log()
986            return
987
988    def average_pol(self, mask=None, weight='none', insitu=None):
989        """
990        Average the Polarisations together.
991        The polarisation cursor of the output scan is set to 0
992        Parameters:
993            mask:        An optional mask defining the region, where the
994                         averaging will be applied. The output will have all
995                         specified points masked.
996            weight:      Weighting scheme. 'none' (default), 'var' (1/var(spec)
997                         weighted), or 'tsys' (1/Tsys**2 weighted)
998            insitu:      if False a new scantable is returned.
999                         Otherwise, the scaling is done in-situ
1000                         The default is taken from .asaprc (False)
1001        """
1002        if insitu is None: insitu = rcParams['insitu']
1003        varlist = vars()
1004
1005        if mask is None:
1006            mask = ()
1007        if not insitu:
1008            from asap._asap import averagepol as _avpol
1009            s = scantable(_avpol(self, mask, weight))
1010            s._add_history("average_pol",varlist)
1011            print_log()
1012            return s
1013        else:
1014            from asap._asap import averagepol_insitu as _avpol
1015            _avpol(self, mask, weight)
1016            self._add_history("average_pol",varlist)
1017            print_log()
1018            return
1019
1020    def smooth(self, kernel="hanning", width=5.0, insitu=None, allaxes=None):
1021        """
1022        Smooth the spectrum by the specified kernel (conserving flux).
1023        Parameters:
1024            scan:       The input scan
1025            kernel:     The type of smoothing kernel. Select from
1026                        'hanning' (default), 'gaussian' and 'boxcar'.
1027                        The first three characters are sufficient.
1028            width:      The width of the kernel in pixels. For hanning this is
1029                        ignored otherwise it defauls to 5 pixels.
1030                        For 'gaussian' it is the Full Width Half
1031                        Maximum. For 'boxcar' it is the full width.
1032            insitu:     if False a new scantable is returned.
1033                        Otherwise, the scaling is done in-situ
1034                        The default is taken from .asaprc (False)
1035            allaxes:    If True (default) apply to all spectra. Otherwise
1036                        apply only to the selected (beam/pol/if)spectra only
1037                        The default is taken from .asaprc (True if none)
1038        Example:
1039             none
1040        """
1041        if allaxes is None: allaxes = rcParams['scantable.allaxes']
1042        if insitu is None: insitu = rcParams['insitu']
1043        varlist = vars()
1044        if not insitu:
1045            from asap._asap import smooth as _smooth
1046            s = scantable(_smooth(self,kernel,width,allaxes))
1047            s._add_history("smooth", varlist)
1048            print_log()
1049            return s
1050        else:
1051            from asap._asap import smooth_insitu as _smooth
1052            _smooth(self,kernel,width,allaxes)
1053            self._add_history("smooth", varlist)
1054            print_log()
1055            return
1056
1057    def poly_baseline(self, mask=None, order=0, insitu=None, allaxes=None):
1058        """
1059        Return a scan which has been baselined (all rows) by a polynomial.
1060        Parameters:
1061            scan:       a scantable
1062            mask:       an optional mask
1063            order:      the order of the polynomial (default is 0)
1064            insitu:     if False a new scantable is returned.
1065                        Otherwise, the scaling is done in-situ
1066                        The default is taken from .asaprc (False)
1067            allaxes:    If True (default) apply to all spectra. Otherwise
1068                        apply only to the selected (beam/pol/if)spectra only
1069                        The default is taken from .asaprc (True if none)
1070        Example:
1071            # return a scan baselined by a third order polynomial,
1072            # not using a mask
1073            bscan = scan.poly_baseline(order=3)
1074        """
1075        if allaxes is None: allaxes = rcParams['scantable.allaxes']
1076        if insitu is None: insitu = rcParams['insitu']
1077        varlist = vars()
1078        if mask is None:
1079            from numarray import ones
1080            mask = list(ones(self.nchan()))
1081        from asap.asapfitter import fitter
1082        f = fitter()
1083        f.set_scan(self, mask)
1084        f.set_function(poly=order)
1085        sf = f.auto_fit(insitu,allaxes)
1086        if insitu:
1087            self._add_history("poly_baseline", varlist)
1088            print_log()
1089            return
1090        else:
1091            sf._add_history("poly_baseline", varlist)
1092            print_log()
1093            return sf
1094
1095    def auto_poly_baseline(self, mask=None, edge=(0,0), order=0,
1096                           threshold=3,insitu=None):
1097        """
1098        Return a scan which has been baselined (all rows) by a polynomial.
1099        Spectral lines are detected first using linefinder and masked out
1100        to avoid them affecting the baseline solution.
1101
1102        Parameters:
1103            mask:       an optional mask retreived from scantable
1104            edge:       an optional number of channel to drop at
1105                        the edge of spectrum. If only one value is
1106                        specified, the same number will be dropped from
1107                        both sides of the spectrum. Default is to keep
1108                        all channels
1109            order:      the order of the polynomial (default is 0)
1110            threshold:  the threshold used by line finder. It is better to
1111                        keep it large as only strong lines affect the
1112                        baseline solution.
1113            insitu:     if False a new scantable is returned.
1114                        Otherwise, the scaling is done in-situ
1115                        The default is taken from .asaprc (False)
1116
1117        Example:
1118            scan2=scan.auto_poly_baseline(order=7)
1119        """
1120        if insitu is None: insitu = rcParams['insitu']
1121        varlist = vars()
1122        from asap.asapfitter import fitter
1123        from asap.asaplinefind import linefinder
1124        from asap import _is_sequence_or_number as _is_valid
1125
1126        if not _is_valid(edge, int):
1127
1128            raise RuntimeError, "Parameter 'edge' has to be an integer or a \
1129            pair of integers specified as a tuple"
1130
1131        # setup fitter
1132        f = fitter()
1133        f.set_function(poly=order)
1134
1135        # setup line finder
1136        fl=linefinder()
1137        fl.set_options(threshold=threshold)
1138
1139        if not insitu:
1140            workscan=self.copy()
1141        else:
1142            workscan=self
1143
1144        sel=workscan.get_cursor()
1145        rows=range(workscan.nrow())
1146        from asap import asaplog
1147        for i in range(workscan.nbeam()):
1148            workscan.setbeam(i)
1149            for j in range(workscan.nif()):
1150                workscan.setif(j)
1151                for k in range(workscan.npol()):
1152                    workscan.setpol(k)
1153                    asaplog.push("Processing:")
1154                    msg = 'Beam[%d], IF[%d], Pol[%d]' % (i,j,k)
1155                    asaplog.push(msg)
1156                    for iRow in rows:
1157                       fl.set_scan(workscan,mask,edge)
1158                       fl.find_lines(iRow)
1159                       f.set_scan(workscan, fl.get_mask())
1160                       f.x=workscan._getabcissa(iRow)
1161                       f.y=workscan._getspectrum(iRow)
1162                       f.data=None
1163                       f.fit()
1164                       x=f.get_parameters()
1165                       workscan._setspectrum(f.fitter.getresidual(),iRow)
1166        workscan.set_cursor(sel[0],sel[1],sel[2])
1167        if not insitu:
1168            return workscan
1169
1170    def rotate_linpolphase(self, angle, allaxes=None):
1171        """
1172        Rotate the phase of the complex polarization O=Q+iU correlation.
1173        This is always done in situ in the raw data.  So if you call this
1174        function more than once then each call rotates the phase further.
1175        Parameters:
1176            angle:   The angle (degrees) to rotate (add) by.
1177            allaxes: If True apply to all spectra. Otherwise
1178                     apply only to the selected (beam/pol/if)spectra only.
1179                     The default is taken from .asaprc (True if none)
1180        Examples:
1181            scan.rotate_linpolphase(2.3)
1182    """
1183        if allaxes is None: allaxes = rcParams['scantable.allaxes']
1184        varlist = vars()
1185        from asap._asap import _rotate_linpolphase as _rotate
1186        _rotate(self, angle, allaxes)
1187        self._add_history("rotate_linpolphase", varlist)
1188        print_log()
1189        return
1190
1191
1192    def rotate_xyphase(self, angle, allaxes=None):
1193        """
1194        Rotate the phase of the XY correlation.  This is always done in situ
1195        in the data.  So if you call this function more than once
1196        then each call rotates the phase further.
1197        Parameters:
1198            angle:   The angle (degrees) to rotate (add) by.
1199            allaxes: If True apply to all spectra. Otherwise
1200                     apply only to the selected (beam/pol/if)spectra only.
1201                     The default is taken from .asaprc (True if none)
1202        Examples:
1203            scan.rotate_xyphase(2.3)
1204        """
1205        if allaxes is None: allaxes = rcParams['scantable.allaxes']
1206        varlist = vars()
1207        from asap._asap import _rotate_xyphase
1208        _rotate_xyphase(self, angle, allaxes)
1209        self._add_history("rotate_xyphase", varlist)
1210        print_log()
1211        return
1212
1213
1214    def add(self, offset, insitu=None, allaxes=None):
1215        """
1216        Return a scan where all spectra have the offset added
1217        Parameters:
1218            offset:      the offset
1219            insitu:      if False a new scantable is returned.
1220                         Otherwise, the scaling is done in-situ
1221                         The default is taken from .asaprc (False)
1222            allaxes:     if True apply to all spectra. Otherwise
1223                         apply only to the selected (beam/pol/if)spectra only
1224                         The default is taken from .asaprc (True if none)
1225        """
1226        if allaxes is None: allaxes = rcParams['scantable.allaxes']
1227        if insitu is None: insitu = rcParams['insitu']
1228        varlist = vars()
1229        if not insitu:
1230            from asap._asap import add as _add
1231            s = scantable(_add(self, offset, allaxes))
1232            s._add_history("add",varlist)
1233            print_log()
1234            return s
1235        else:
1236            from asap._asap import add_insitu as _add
1237            _add(self, offset, allaxes)
1238            self._add_history("add",varlist)
1239            print_log()
1240            return
1241
1242    def scale(self, factor, insitu=None, allaxes=None, tsys=True):
1243        """
1244        Return a scan where all spectra are scaled by the give 'factor'
1245        Parameters:
1246            factor:      the scaling factor
1247            insitu:      if False a new scantable is returned.
1248                         Otherwise, the scaling is done in-situ
1249                         The default is taken from .asaprc (False)
1250            allaxes:     if True apply to all spectra. Otherwise
1251                         apply only to the selected (beam/pol/if)spectra only.
1252                         The default is taken from .asaprc (True if none)
1253            tsys:        if True (default) then apply the operation to Tsys
1254                         as well as the data
1255        """
1256        if allaxes is None: allaxes = rcParams['scantable.allaxes']
1257        if insitu is None: insitu = rcParams['insitu']
1258        varlist = vars()
1259        if not insitu:
1260            from asap._asap import scale as _scale
1261            s = scantable(_scale(self, factor, allaxes, tsys))
1262            s._add_history("scale",varlist)
1263            print_log()
1264            return s
1265        else:
1266            from asap._asap import scale_insitu as _scale
1267            _scale(self, factor, allaxes, tsys)
1268            self._add_history("scale",varlist)
1269            print_log()
1270            return
1271
1272    def auto_quotient(self, mode='suffix', preserve=True):
1273        """
1274        This function allows to build quotients automatically.
1275        It assumes the observation to have the same numer of
1276        "ons" and "offs"
1277        It will support "closest off in time" in the future
1278        Parameters:
1279            mode:           the on/off detection mode; 'suffix' (default)
1280                            'suffix' identifies 'off' scans by the
1281                            trailing '_R' (Mopra/Parkes) or
1282                            '_e'/'_w' (Tid)
1283            preserve:       you can preserve (default) the continuum or
1284                            remove it.  The equations used are
1285                            preserve: Output = Toff * (on/off) - Toff
1286                            remove:   Output = Tref * (on/off) - Ton
1287        """
1288        modes = ["suffix","time"]
1289        if not mode in modes:
1290            print "please provide valid mode. Valid modes are %s" % (modes)
1291            return None
1292        from asap._asap import quotient as _quot
1293        if mode == "suffix":
1294            srcs = self.get_scan("*[^_ewR]")
1295            refs = self.get_scan("*[_ewR]")
1296            if isinstance(srcs,scantable) and isinstance(refs,scantable):
1297                from asap import asaplog
1298                ns,nr = srcs.nrow(),refs.nrow()
1299                msg = "Found %i Off and %i On scans" % (ns,nr)
1300                asaplog.push(msg)
1301                if nr > ns:
1302                    asaplog("Found more Off integrations than On scans - dropping excess Offs.")
1303                    refs = refs.get_scan(range(ns))
1304                print_log()
1305                return scantable(_quot(srcs,refs, preserve))
1306            else:
1307                msg = "Couldn't find any on/off pairs"
1308                if rcParams['verbose']:
1309                    print msg
1310                    return
1311                else:
1312                    raise RuntimeError()
1313        else:
1314            if rcParams['verbose']: print "not yet implemented"
1315            return None
1316
1317    def quotient(self, other, isreference=True, preserve=True):
1318        """
1319        Return the quotient of a 'source' (on) scan and a 'reference' (off)
1320        scan.
1321        The reference can have just one row, even if the signal has many.
1322        Otherwise they must have the same number of rows.
1323        The cursor of the output scan is set to 0
1324        Parameters:
1325            other:          the 'other' scan
1326            isreference:    if the 'other' scan is the reference (default)
1327                            or source
1328            preserve:       you can preserve (default) the continuum or
1329                            remove it.  The equations used are
1330                            preserve: Output = Toff * (on/off) - Toff
1331                            remove:   Output = Tref * (on/off) - Ton
1332        Example:
1333            # src is a scantable for an 'on' scan, ref for an 'off' scantable
1334            q1 = src.quotient(ref)
1335            q2 = ref.quotient(src, isreference=False)
1336            # gives the same result
1337        """
1338        from asap._asap import quotient as _quot
1339        try:
1340            s = None
1341            if isreference:
1342                s = scantable(_quot(self, other, preserve))
1343            else:
1344                s = scantable(_quot(other, self, preserve))
1345            print_log()
1346            return s
1347        except RuntimeError,e:
1348            if rcParams['verbose']:
1349                print e
1350                return
1351            else: raise
1352
1353    def freq_switch(self, insitu=None):
1354        """
1355        Apply frequency switching to the data.
1356        Parameters:
1357            insitu:      if False a new scantable is returned.
1358                         Otherwise, the swictching is done in-situ
1359                         The default is taken from .asaprc (False)
1360        Example:
1361            none
1362        """
1363        if insitu is None: insitu = rcParams['insitu']
1364        varlist = vars()
1365        try:
1366            if insitu:
1367                from asap._asap import _frequency_switch_insitu
1368                _frequency_switch_insitu(self)
1369                self._add_history("freq_switch", varlist)
1370                print_log()
1371                return
1372            else:
1373                from asap._asap import _frequency_switch
1374                sf = scantable(_frequency_switch(self))
1375                sf._add_history("freq_switch", varlist)
1376                print_log()
1377                return sf
1378        except RuntimeError,e:
1379            if rcParams['verbose']: print e
1380            else: raise
1381
1382    def recalc_azel(self):
1383        """
1384        Recalculate the azimuth and elevation for each position.
1385        Parameters:
1386            none
1387        Example:
1388        """
1389        varlist = vars()
1390        self._recalc_azel()
1391        self._add_history("recalc_azel", varlist)
1392        print_log()
1393        return
1394
1395    def __add__(self, other):
1396        varlist = vars()
1397        s = None
1398        if isinstance(other, scantable):
1399            from asap._asap import b_operate as _bop
1400            s = scantable(_bop(self, other, 'add', True))
1401        elif isinstance(other, float):
1402            from asap._asap import add as _add
1403            s = scantable(_add(self, other, True))
1404        else:
1405            raise TypeError("Other input is not a scantable or float value")
1406        s._add_history("operator +", varlist)
1407        print_log()
1408        return s
1409
1410    def __sub__(self, other):
1411        """
1412        implicit on all axes and on Tsys
1413        """
1414        varlist = vars()
1415        s = None
1416        if isinstance(other, scantable):
1417            from asap._asap import b_operate as _bop
1418            s = scantable(_bop(self, other, 'sub', True))
1419        elif isinstance(other, float):
1420            from asap._asap import add as _add
1421            s = scantable(_add(self, -other, True))
1422        else:
1423            raise TypeError("Other input is not a scantable or float value")
1424        s._add_history("operator -", varlist)
1425        print_log()
1426        return s
1427
1428    def __mul__(self, other):
1429        """
1430        implicit on all axes and on Tsys
1431        """
1432        varlist = vars()
1433        s = None
1434        if isinstance(other, scantable):
1435            from asap._asap import b_operate as _bop
1436            s = scantable(_bop(self, other, 'mul', True))
1437        elif isinstance(other, float):
1438            if other == 0.0:
1439                raise ZeroDivisionError("Dividing by zero is not recommended")
1440            from asap._asap import scale as _sca
1441            s = scantable(_sca(self, other, True))
1442        else:
1443            raise TypeError("Other input is not a scantable or float value")
1444        s._add_history("operator *", varlist)
1445        print_log()
1446        return s
1447
1448
1449    def __div__(self, other):
1450        """
1451        implicit on all axes and on Tsys
1452        """
1453        varlist = vars()
1454        s = None
1455        if isinstance(other, scantable):
1456            from asap._asap import b_operate as _bop
1457            s = scantable(_bop(self, other, 'div', True))
1458        elif isinstance(other, float):
1459            if other == 0.0:
1460                raise ZeroDivisionError("Dividing by zero is not recommended")
1461            from asap._asap import scale as _sca
1462            s = scantable(_sca(self, 1.0/other, True))
1463        else:
1464            raise TypeError("Other input is not a scantable or float value")
1465        s._add_history("operator /", varlist)
1466        print_log()
1467        return s
1468
1469    def get_fit(self, row=0):
1470        """
1471        Print or return the stored fits for a row in the scantable
1472        Parameters:
1473            row:    the row which the fit has been applied to.
1474        """
1475        if row > self.nrow():
1476            return
1477        from asap import asapfit
1478        fit = asapfit(self._getfit(row))
1479        if rcParams['verbose']:
1480            print fit
1481            return
1482        else:
1483            return fit.as_dict()
1484
1485    def _add_history(self, funcname, parameters):
1486        # create date
1487        sep = "##"
1488        from datetime import datetime
1489        dstr = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
1490        hist = dstr+sep
1491        hist += funcname+sep#cdate+sep
1492        if parameters.has_key('self'): del parameters['self']
1493        for k,v in parameters.iteritems():
1494            if type(v) is dict:
1495                for k2,v2 in v.iteritems():
1496                    hist += k2
1497                    hist += "="
1498                    if isinstance(v2,scantable):
1499                        hist += 'scantable'
1500                    elif k2 == 'mask':
1501                        if isinstance(v2,list) or isinstance(v2,tuple):
1502                            hist += str(self._zip_mask(v2))
1503                        else:
1504                            hist += str(v2)
1505                    else:
1506                        hist += str(v2)
1507            else:
1508                hist += k
1509                hist += "="
1510                if isinstance(v,scantable):
1511                    hist += 'scantable'
1512                elif k == 'mask':
1513                    if isinstance(v,list) or isinstance(v,tuple):
1514                        hist += str(self._zip_mask(v))
1515                    else:
1516                        hist += str(v)
1517                else:
1518                    hist += str(v)
1519            hist += sep
1520        hist = hist[:-2] # remove trailing '##'
1521        self._addhistory(hist)
1522
1523
1524    def _zip_mask(self, mask):
1525        mask = list(mask)
1526        i = 0
1527        segments = []
1528        while mask[i:].count(1):
1529            i += mask[i:].index(1)
1530            if mask[i:].count(0):
1531                j = i + mask[i:].index(0)
1532            else:
1533                j = len(mask)
1534            segments.append([i,j])
1535            i = j
1536        return segments
1537
1538    def _get_ordinate_label(self):
1539        fu = "("+self.get_fluxunit()+")"
1540        import re
1541        lbl = "Intensity"
1542        if re.match(".K.",fu):
1543            lbl = "Brightness Temperature "+ fu
1544        elif re.match(".Jy.",fu):
1545            lbl = "Flux density "+ fu
1546        return lbl
1547
Note: See TracBrowser for help on using the repository browser.