source: trunk/python/scantable.py @ 739

Last change on this file since 739 was 721, checked in by mar637, 19 years ago

more asaplog changes

  • 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._verbose(True)
1078        f.set_scan(self, mask)
1079        f.set_function(poly=order)
1080        sf = f.auto_fit(insitu)
1081        if insitu:
1082            self._add_history("poly_baseline", varlist)
1083            print_log()
1084            return
1085        else:
1086            sf._add_history("poly_baseline", varlist)
1087            print_log()
1088            return sf
1089
1090    def auto_poly_baseline(self, mask=None, edge=(0,0), order=0,
1091                           threshold=3,insitu=None):
1092        """
1093        Return a scan which has been baselined (all rows) by a polynomial.
1094        Spectral lines are detected first using linefinder and masked out
1095        to avoid them affecting the baseline solution.
1096
1097        Parameters:
1098            mask:       an optional mask retreived from scantable
1099            edge:       an optional number of channel to drop at
1100                        the edge of spectrum. If only one value is
1101                        specified, the same number will be dropped from
1102                        both sides of the spectrum. Default is to keep
1103                        all channels
1104            order:      the order of the polynomial (default is 0)
1105            threshold:  the threshold used by line finder. It is better to
1106                        keep it large as only strong lines affect the
1107                        baseline solution.
1108            insitu:     if False a new scantable is returned.
1109                        Otherwise, the scaling is done in-situ
1110                        The default is taken from .asaprc (False)
1111
1112        Example:
1113            scan2=scan.auto_poly_baseline(order=7)
1114        """
1115        if insitu is None: insitu = rcParams['insitu']
1116        varlist = vars()
1117        from asap.asapfitter import fitter
1118        from asap.asaplinefind import linefinder
1119        from asap import _is_sequence_or_number as _is_valid
1120
1121        if not _is_valid(edge, int):
1122
1123            raise RuntimeError, "Parameter 'edge' has to be an integer or a \
1124            pair of integers specified as a tuple"
1125
1126        # setup fitter
1127        f = fitter()
1128        f.set_function(poly=order)
1129
1130        # setup line finder
1131        fl=linefinder()
1132        fl.set_options(threshold=threshold)
1133
1134        if not insitu:
1135            workscan=self.copy()
1136        else:
1137            workscan=self
1138
1139        sel=workscan.get_cursor()
1140        rows=range(workscan.nrow())
1141        from asap import asaplog
1142        for i in range(workscan.nbeam()):
1143            workscan.setbeam(i)
1144            for j in range(workscan.nif()):
1145                workscan.setif(j)
1146                for k in range(workscan.npol()):
1147                    workscan.setpol(k)
1148                    asaplog.push("Processing:")
1149                    msg = 'Beam[%d], IF[%d], Pol[%d]' % (i,j,k)
1150                    asaplog.push(msg)
1151                    for iRow in rows:
1152                       fl.set_scan(workscan,mask,edge)
1153                       fl.find_lines(iRow)
1154                       f.set_scan(workscan, fl.get_mask())
1155                       f.x=workscan._getabcissa(iRow)
1156                       f.y=workscan._getspectrum(iRow)
1157                       f.data=None
1158                       f.fit()
1159                       x=f.get_parameters()
1160                       workscan._setspectrum(f.fitter.getresidual(),iRow)
1161        workscan.set_cursor(sel[0],sel[1],sel[2])
1162        if not insitu:
1163            return workscan
1164
1165    def rotate_linpolphase(self, angle, allaxes=None):
1166        """
1167        Rotate the phase of the complex polarization O=Q+iU correlation.
1168        This is always done in situ in the raw data.  So if you call this
1169        function more than once then each call rotates the phase further.
1170        Parameters:
1171            angle:   The angle (degrees) to rotate (add) by.
1172            allaxes: If True apply to all spectra. Otherwise
1173                     apply only to the selected (beam/pol/if)spectra only.
1174                     The default is taken from .asaprc (True if none)
1175        Examples:
1176            scan.rotate_linpolphase(2.3)
1177    """
1178        if allaxes is None: allaxes = rcParams['scantable.allaxes']
1179        varlist = vars()
1180        from asap._asap import _rotate_linpolphase as _rotate
1181        _rotate(self, angle, allaxes)
1182        self._add_history("rotate_linpolphase", varlist)
1183        print_log()
1184        return
1185
1186
1187    def rotate_xyphase(self, angle, allaxes=None):
1188        """
1189        Rotate the phase of the XY correlation.  This is always done in situ
1190        in the data.  So if you call this function more than once
1191        then each call rotates the phase further.
1192        Parameters:
1193            angle:   The angle (degrees) to rotate (add) by.
1194            allaxes: If True apply to all spectra. Otherwise
1195                     apply only to the selected (beam/pol/if)spectra only.
1196                     The default is taken from .asaprc (True if none)
1197        Examples:
1198            scan.rotate_xyphase(2.3)
1199        """
1200        if allaxes is None: allaxes = rcParams['scantable.allaxes']
1201        varlist = vars()
1202        from asap._asap import _rotate_xyphase
1203        _rotate_xyphase(self, angle, allaxes)
1204        self._add_history("rotate_xyphase", varlist)
1205        print_log()
1206        return
1207
1208
1209    def add(self, offset, insitu=None, allaxes=None):
1210        """
1211        Return a scan where all spectra have the offset added
1212        Parameters:
1213            offset:      the offset
1214            insitu:      if False a new scantable is returned.
1215                         Otherwise, the scaling is done in-situ
1216                         The default is taken from .asaprc (False)
1217            allaxes:     if True apply to all spectra. Otherwise
1218                         apply only to the selected (beam/pol/if)spectra only
1219                         The default is taken from .asaprc (True if none)
1220        """
1221        if allaxes is None: allaxes = rcParams['scantable.allaxes']
1222        if insitu is None: insitu = rcParams['insitu']
1223        varlist = vars()
1224        if not insitu:
1225            from asap._asap import add as _add
1226            s = scantable(_add(self, offset, allaxes))
1227            s._add_history("add",varlist)
1228            print_log()
1229            return s
1230        else:
1231            from asap._asap import add_insitu as _add
1232            _add(self, offset, allaxes)
1233            self._add_history("add",varlist)
1234            print_log()
1235            return
1236
1237    def scale(self, factor, insitu=None, allaxes=None, tsys=True):
1238        """
1239        Return a scan where all spectra are scaled by the give 'factor'
1240        Parameters:
1241            factor:      the scaling factor
1242            insitu:      if False a new scantable is returned.
1243                         Otherwise, the scaling is done in-situ
1244                         The default is taken from .asaprc (False)
1245            allaxes:     if True apply to all spectra. Otherwise
1246                         apply only to the selected (beam/pol/if)spectra only.
1247                         The default is taken from .asaprc (True if none)
1248            tsys:        if True (default) then apply the operation to Tsys
1249                         as well as the data
1250        """
1251        if allaxes is None: allaxes = rcParams['scantable.allaxes']
1252        if insitu is None: insitu = rcParams['insitu']
1253        varlist = vars()
1254        if not insitu:
1255            from asap._asap import scale as _scale
1256            s = scantable(_scale(self, factor, allaxes, tsys))
1257            s._add_history("scale",varlist)
1258            print_log()
1259            return s
1260        else:
1261            from asap._asap import scale_insitu as _scale
1262            _scale(self, factor, allaxes, tsys)
1263            self._add_history("scale",varlist)
1264            print_log()
1265            return
1266
1267    def auto_quotient(self, mode='suffix', preserve=True):
1268        """
1269        This function allows to build quotients automatically.
1270        It assumes the observation to have the same numer of
1271        "ons" and "offs"
1272        It will support "closest off in time" in the future
1273        Parameters:
1274            mode:           the on/off detection mode; 'suffix' (default)
1275                            'suffix' identifies 'off' scans by the
1276                            trailing '_R' (Mopra/Parkes) or
1277                            '_e'/'_w' (Tid)
1278            preserve:       you can preserve (default) the continuum or
1279                            remove it.  The equations used are
1280                            preserve: Output = Toff * (on/off) - Toff
1281                            remove:   Output = Tref * (on/off) - Ton
1282        """
1283        modes = ["suffix","time"]
1284        if not mode in modes:
1285            print "please provide valid mode. Valid modes are %s" % (modes)
1286            return None
1287        from asap._asap import quotient as _quot
1288        if mode == "suffix":
1289            srcs = self.get_scan("*[^_ewR]")
1290            refs = self.get_scan("*[_ewR]")
1291            if isinstance(srcs,scantable) and isinstance(refs,scantable):
1292                ns,nr = srcs.nrow(),refs.nrow()
1293                if nr > ns:
1294                    refs = refs.get_scan(range(ns))
1295                print_log()
1296                return scantable(_quot(srcs,refs, preserve))
1297            else:
1298                msg = "Couldn't find any on/off pairs"
1299                if rcParams['verbose']:
1300                    print msg
1301                    return
1302                else:
1303                    raise RuntimeError()
1304        else:
1305            if rcParams['verbose']: print "not yet implemented"
1306            return None
1307
1308    def quotient(self, other, isreference=True, preserve=True):
1309        """
1310        Return the quotient of a 'source' (on) scan and a 'reference' (off)
1311        scan.
1312        The reference can have just one row, even if the signal has many.
1313        Otherwise they must have the same number of rows.
1314        The cursor of the output scan is set to 0
1315        Parameters:
1316            other:          the 'other' scan
1317            isreference:    if the 'other' scan is the reference (default)
1318                            or source
1319            preserve:       you can preserve (default) the continuum or
1320                            remove it.  The equations used are
1321                            preserve: Output = Toff * (on/off) - Toff
1322                            remove:   Output = Tref * (on/off) - Ton
1323        Example:
1324            # src is a scantable for an 'on' scan, ref for an 'off' scantable
1325            q1 = src.quotient(ref)
1326            q2 = ref.quotient(src, isreference=False)
1327            # gives the same result
1328        """
1329        from asap._asap import quotient as _quot
1330        try:
1331            s = None
1332            if isreference:
1333                s = scantable(_quot(self, other, preserve))
1334            else:
1335                s = scantable(_quot(other, self, preserve))
1336            print_log()
1337            return s
1338        except RuntimeError,e:
1339            if rcParams['verbose']:
1340                print e
1341                return
1342            else: raise
1343
1344    def freq_switch(self, insitu=None):
1345        """
1346        Apply frequency switching to the data.
1347        Parameters:
1348            insitu:      if False a new scantable is returned.
1349                         Otherwise, the swictching is done in-situ
1350                         The default is taken from .asaprc (False)
1351        Example:
1352            none
1353        """
1354        if insitu is None: insitu = rcParams['insitu']
1355        varlist = vars()
1356        try:
1357            if insitu:
1358                from asap._asap import _frequency_switch_insitu
1359                _frequency_switch_insitu(self)
1360                self._add_history("freq_switch", varlist)
1361                print_log()
1362                return
1363            else:
1364                from asap._asap import _frequency_switch
1365                sf = scantable(_frequency_switch(self))
1366                sf._add_history("freq_switch", varlist)
1367                print_log()
1368                return sf
1369        except RuntimeError,e:
1370            if rcParams['verbose']: print e
1371            else: raise
1372
1373    def __add__(self, other):
1374        varlist = vars()
1375        s = None
1376        if isinstance(other, scantable):
1377            from asap._asap import b_operate as _bop
1378            s = scantable(_bop(self, other, 'add', True))
1379        elif isinstance(other, float):
1380            from asap._asap import add as _add
1381            s = scantable(_add(self, other, True))
1382        else:
1383            raise TypeError("Other input is not a scantable or float value")
1384        s._add_history("operator +", varlist)
1385        print_log()
1386        return s
1387
1388
1389    def __sub__(self, other):
1390        """
1391        implicit on all axes and on Tsys
1392        """
1393        varlist = vars()
1394        s = None
1395        if isinstance(other, scantable):
1396            from asap._asap import b_operate as _bop
1397            s = scantable(_bop(self, other, 'sub', True))
1398        elif isinstance(other, float):
1399            from asap._asap import add as _add
1400            s = scantable(_add(self, -other, True))
1401        else:
1402            raise TypeError("Other input is not a scantable or float value")
1403        s._add_history("operator -", varlist)
1404        print_log()
1405        return s
1406
1407    def __mul__(self, other):
1408        """
1409        implicit on all axes and on Tsys
1410        """
1411        varlist = vars()
1412        s = None
1413        if isinstance(other, scantable):
1414            from asap._asap import b_operate as _bop
1415            s = scantable(_bop(self, other, 'mul', True))
1416        elif isinstance(other, float):
1417            if other == 0.0:
1418                raise ZeroDivisionError("Dividing by zero is not recommended")
1419            from asap._asap import scale as _sca
1420            s = scantable(_sca(self, other, True))
1421        else:
1422            raise TypeError("Other input is not a scantable or float value")
1423        s._add_history("operator *", varlist)
1424        print_log()
1425        return s
1426
1427
1428    def __div__(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, 'div', 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, 1.0/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    def get_fit(self, row=0):
1449        """
1450        Print or return the stored fits for a row in the scantable
1451        Parameters:
1452            row:    the row which the fit has been applied to.
1453        """
1454        if row > self.nrow():
1455            return
1456        from asap import asapfit
1457        fit = asapfit(self._getfit(row))
1458        if rcParams['verbose']:
1459            print fit
1460            return
1461        else:
1462            return fit.as_dict()
1463
1464    def _add_history(self, funcname, parameters):
1465        # create date
1466        sep = "##"
1467        from datetime import datetime
1468        dstr = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
1469        hist = dstr+sep
1470        hist += funcname+sep#cdate+sep
1471        if parameters.has_key('self'): del parameters['self']
1472        for k,v in parameters.iteritems():
1473            if type(v) is dict:
1474                for k2,v2 in v.iteritems():
1475                    hist += k2
1476                    hist += "="
1477                    if isinstance(v2,scantable):
1478                        hist += 'scantable'
1479                    elif k2 == 'mask':
1480                        if isinstance(v2,list) or isinstance(v2,tuple):
1481                            hist += str(self._zip_mask(v2))
1482                        else:
1483                            hist += str(v2)
1484                    else:
1485                        hist += str(v2)
1486            else:
1487                hist += k
1488                hist += "="
1489                if isinstance(v,scantable):
1490                    hist += 'scantable'
1491                elif k == 'mask':
1492                    if isinstance(v,list) or isinstance(v,tuple):
1493                        hist += str(self._zip_mask(v))
1494                    else:
1495                        hist += str(v)
1496                else:
1497                    hist += str(v)
1498            hist += sep
1499        hist = hist[:-2] # remove trailing '##'
1500        self._addhistory(hist)
1501
1502
1503    def _zip_mask(self, mask):
1504        mask = list(mask)
1505        i = 0
1506        segments = []
1507        while mask[i:].count(1):
1508            i += mask[i:].index(1)
1509            if mask[i:].count(0):
1510                j = i + mask[i:].index(0)
1511            else:
1512                j = len(mask)
1513            segments.append([i,j])
1514            i = j
1515        return segments
1516
1517    def _get_ordinate_label(self):
1518        fu = "("+self.get_fluxunit()+")"
1519        import re
1520        lbl = "Intensity"
1521        if re.match(".K.",fu):
1522            lbl = "Brightness Temperature "+ fu
1523        elif re.match(".Jy.",fu):
1524            lbl = "Flux density "+ fu
1525        return lbl
1526
Note: See TracBrowser for help on using the repository browser.