source: trunk/python/scantable.py @ 1157

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

more argument types for scanatble.set_restfreqs; tidying.

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