source: trunk/python/scantable.py @ 742

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

removed old fitter._verbose call

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