source: trunk/python/scantable.py @ 1217

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

Merge from Release2.1.0b tag

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 62.1 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        # disabled because the vector seems more useful
414        #retval = {'axesnames': axesnames, 'axes': axes, 'data': outvec}
415        return outvec
416
417    def _get_column(self, callback, row=-1):
418        """
419        """
420        if row == -1:
421            return [callback(i) for i in range(self.nrow())]
422        else:
423            if  0 <= row < self.nrow():
424                return callback(row)
425
426
427    def get_time(self, row=-1):
428        """
429        Get a list of time stamps 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        from time import strptime
437        from datetime import datetime
438        times = self._get_column(self._gettime, row)
439        format = "%Y/%m/%d/%H:%M:%S"
440        if isinstance(times, list):
441            return [datetime(*strptime(i, format)[:6]) for i in times]
442        else:
443            return datetime(*strptime(times, format)[:6])
444
445    def get_sourcename(self, row=-1):
446        """
447        Get a list source names for the observations.
448        Return a string for each integration in the scantable.
449        Parameters:
450            row:    row no of integration. Default -1 return all rows
451        Example:
452            none
453        """
454        return self._get_column(self._getsourcename, row)
455
456    def get_elevation(self, row=-1):
457        """
458        Get a list of elevations for the observations.
459        Return a float for each integration in the scantable.
460        Parameters:
461            row:    row no of integration. Default -1 return all rows
462        Example:
463            none
464        """
465        return self._get_column(self._getelevation, row)
466
467    def get_azimuth(self, row=-1):
468        """
469        Get a list of azimuths for the observations.
470        Return a float for each integration in the scantable.
471        Parameters:
472            row:    row no of integration. Default -1 return all rows
473        Example:
474            none
475        """
476        return self._get_column(self._getazimuth, row)
477
478    def get_parangle(self, row=-1):
479        """
480        Get a list of parallactic angles for the observations.
481        Return a float for each integration in the scantable.
482        Parameters:
483            row:    row no of integration. Default -1 return all rows
484        Example:
485            none
486        """
487        return self._get_column(self._getparangle, row)
488
489    def get_direction(self, row=-1):
490        """
491        Get a list of Positions on the sky (direction) for the observations.
492        Return a float for each integration in the scantable.
493        Parameters:
494            row:    row no of integration. Default -1 return all rows
495        Example:
496            none
497        """
498        return self._get_column(self._getdirection, row)
499
500    def set_unit(self, unit='channel'):
501        """
502        Set the unit for all following operations on this scantable
503        Parameters:
504            unit:    optional unit, default is 'channel'
505                     one of '*Hz', 'km/s', 'channel', ''
506        """
507        varlist = vars()
508        if unit in ['', 'pixel', 'channel']:
509            unit = ''
510        inf = list(self._getcoordinfo())
511        inf[0] = unit
512        self._setcoordinfo(inf)
513        self._add_history("set_unit", varlist)
514
515    def set_instrument(self, instr):
516        """
517        Set the instrument for subsequent processing
518        Parameters:
519            instr:    Select from 'ATPKSMB', 'ATPKSHOH', 'ATMOPRA',
520                      'DSS-43' (Tid), 'CEDUNA', and 'HOBART'
521        """
522        self._setInstrument(instr)
523        self._add_history("set_instument", vars())
524        print_log()
525
526    def set_feedtype(self, feedtype):
527        """
528        Overwrite the feed type, which might not be set correctly.
529        Parameters:
530            feedtype:     'linear' or 'circular'
531        """
532        self._setfeedtype(feedtype)
533        self._add_history("set_feedtype", vars())
534        print_log()
535
536    def set_doppler(self, doppler='RADIO'):
537        """
538        Set the doppler for all following operations on this scantable.
539        Parameters:
540            doppler:    One of 'RADIO', 'OPTICAL', 'Z', 'BETA', 'GAMMA'
541        """
542        varlist = vars()
543        inf = list(self._getcoordinfo())
544        inf[2] = doppler
545        self._setcoordinfo(inf)
546        self._add_history("set_doppler", vars())
547        print_log()
548
549    def set_freqframe(self, frame=None):
550        """
551        Set the frame type of the Spectral Axis.
552        Parameters:
553            frame:   an optional frame type, default 'LSRK'. Valid frames are:
554                     'REST', 'TOPO', 'LSRD', 'LSRK', 'BARY',
555                     'GEO', 'GALACTO', 'LGROUP', 'CMB'
556        Examples:
557            scan.set_freqframe('BARY')
558        """
559        if frame is None: frame = rcParams['scantable.freqframe']
560        varlist = vars()
561        valid = ['REST', 'TOPO', 'LSRD', 'LSRK', 'BARY', \
562                   'GEO', 'GALACTO', 'LGROUP', 'CMB']
563
564        if frame in valid:
565            inf = list(self._getcoordinfo())
566            inf[1] = frame
567            self._setcoordinfo(inf)
568            self._add_history("set_freqframe", varlist)
569        else:
570            msg  = "Please specify a valid freq type. Valid types are:\n", valid
571            if rcParams['verbose']:
572                print msg
573            else:
574                raise TypeError(msg)
575        print_log()
576
577    def set_dirframe(self, frame=""):
578        """
579        Set the frame type of the Direction on the sky.
580        Parameters:
581            frame:   an optional frame type, default ''. Valid frames are:
582                     'J2000', 'B1950', 'GALACTIC'
583        Examples:
584            scan.set_dirframe('GALACTIC')
585        """
586        varlist = vars()
587        try:
588            Scantable.set_dirframe(self, frame)
589        except RuntimeError, msg:
590            if rcParams['verbose']:
591                print msg
592            else:
593                raise
594        self._add_history("set_dirframe", varlist)
595
596    def get_unit(self):
597        """
598        Get the default unit set in this scantable
599        Parameters:
600        Returns:
601            A unit string
602        """
603        inf = self._getcoordinfo()
604        unit = inf[0]
605        if unit == '': unit = 'channel'
606        return unit
607
608    def get_abcissa(self, rowno=0):
609        """
610        Get the abcissa in the current coordinate setup for the currently
611        selected Beam/IF/Pol
612        Parameters:
613            rowno:    an optional row number in the scantable. Default is the
614                      first row, i.e. rowno=0
615        Returns:
616            The abcissa values and it's format string (as a dictionary)
617        """
618        abc = self._getabcissa(rowno)
619        lbl = self._getabcissalabel(rowno)
620        print_log()
621        return abc, lbl
622
623    def flag(self, mask=None):
624        """
625        Flag the selected data using an optional channel mask.
626        Parameters:
627            mask:   an optional channel mask, created with create_mask. Default
628                    (no mask) is all channels.
629        """
630        varlist = vars()
631        if mask is None:
632            mask = []
633        try:
634            self._flag(mask)
635        except RuntimeError, msg:
636            if rcParams['verbose']:
637                print msg
638                return
639            else: raise
640        self._add_history("flag", varlist)
641
642    def lag_flag(self, frequency, width=0.0, unit="GHz", insitu=None):
643        """
644        Flag the data in 'lag' space by providing a frequency to remove.
645        Flagged data in the scantable gets set to 0.0 before the fft.
646        No taper is applied.
647        Parameters:
648            frequency:    the frequency (really a period within the bandwidth) to remove
649            width:        the width of the frequency to remove, to remove a range
650                          of frequencies aroung the centre.
651            unit:         the frequency unit (default "GHz")
652        Notes:
653            It is recommended to flag edges of the band or strong signals beforehand.
654        """
655        if insitu is None: insitu = rcParams['insitu']
656        self._math._setinsitu(insitu)
657        varlist = vars()
658        base = { "GHz": 100000000., "MHz": 1000000., "kHz": 1000., "Hz": 1. }
659        if not base.has_key(unit):
660            raise ValueError("%s is not a valid unit." % unit)
661        try:
662            s = scantable(self._math._lag_flag(self, frequency*base[unit],
663                                               width*base[unit]))
664        except RuntimeError, msg:
665            if rcParams['verbose']:
666                print msg
667                return
668            else: raise
669        s._add_history("lag_flag", varlist)
670        print_log()
671        if insitu:
672            self._assign(s)
673        else:
674            return s
675
676
677    def create_mask(self, *args, **kwargs):
678        """
679        Compute and return a mask based on [min, max] windows.
680        The specified windows are to be INCLUDED, when the mask is
681        applied.
682        Parameters:
683            [min, max], [min2, max2], ...
684                Pairs of start/end points (inclusive)specifying the regions
685                to be masked
686            invert:     optional argument. If specified as True,
687                        return an inverted mask, i.e. the regions
688                        specified are EXCLUDED
689            row:        create the mask using the specified row for
690                        unit conversions, default is row=0
691                        only necessary if frequency varies over rows.
692        Example:
693            scan.set_unit('channel')
694            a)
695            msk = scan.create_mask([400, 500], [800, 900])
696            # masks everything outside 400 and 500
697            # and 800 and 900 in the unit 'channel'
698
699            b)
700            msk = scan.create_mask([400, 500], [800, 900], invert=True)
701            # masks the regions between 400 and 500
702            # and 800 and 900 in the unit 'channel'
703            c)
704            mask only channel 400
705            msk =  scan.create_mask([400, 400])
706        """
707        row = 0
708        if kwargs.has_key("row"):
709            row = kwargs.get("row")
710        data = self._getabcissa(row)
711        u = self._getcoordinfo()[0]
712        if rcParams['verbose']:
713            if u == "": u = "channel"
714            msg = "The current mask window unit is %s" % u
715            i = self._check_ifs()
716            if not i:
717                msg += "\nThis mask is only valid for IF=%d" % (self.getif(i))
718            asaplog.push(msg)
719        n = self.nchan()
720        msk = NUM.zeros(n)
721        # test if args is a 'list' or a 'normal *args - UGLY!!!
722
723        ws = (isinstance(args[-1][-1], int) or isinstance(args[-1][-1], float)) \
724             and args or args[0]
725        for window in ws:
726            if (len(window) != 2 or window[0] > window[1] ):
727                raise TypeError("A window needs to be defined as [min, max]")
728            for i in range(n):
729                if data[i] >= window[0] and data[i] <= window[1]:
730                    msk[i] = 1
731        if kwargs.has_key('invert'):
732            if kwargs.get('invert'):
733                msk = NUM.logical_not(msk)
734        print_log()
735        return msk
736
737    def get_restfreqs(self):
738        """
739        Get the restfrequency(s) stored in this scantable.
740        The return value(s) are always of unit 'Hz'
741        Parameters:
742            none
743        Returns:
744            a list of doubles
745        """
746        return list(self._getrestfreqs())
747
748
749    def set_restfreqs(self, freqs=None, unit='Hz'):
750        """
751        Set or replace the restfrequency specified and
752        If the 'freqs' argument holds a scalar,
753        then that rest frequency will be applied to all the selected
754        data.  If the 'freqs' argument holds
755        a vector, then it MUST be of equal or smaller length than
756        the number of IFs (and the available restfrequencies will be
757        replaced by this vector).  In this case, *all* data have
758        the restfrequency set per IF according
759        to the corresponding value you give in the 'freqs' vector.
760        E.g. 'freqs=[1e9, 2e9]'  would mean IF 0 gets restfreq 1e9 and
761        IF 1 gets restfreq 2e9.
762        You can also specify the frequencies via a linecatalog/
763
764        Parameters:
765            freqs:   list of rest frequency values or string idenitfiers
766            unit:    unit for rest frequency (default 'Hz')
767
768        Example:
769            # set the given restfrequency for the whole table
770            scan.set_restfreqs(freqs=1.4e9)
771            # If thee number of IFs in the data is >= 2 the IF0 gets the first
772            # value IF1 the second...
773            scan.set_restfreqs(freqs=[1.4e9, 1.67e9])
774            #set the given restfrequency for the whole table (by name)
775            scan.set_restfreqs(freqs="OH1667")
776
777        Note:
778            To do more sophisticate Restfrequency setting, e.g. on a
779            source and IF basis, use scantable.set_selection() before using
780            this function.
781            # provide your scantable is call scan
782            selection = selector()
783            selection.set_name("ORION*")
784            selection.set_ifs([1])
785            scan.set_selection(selection)
786            scan.set_restfreqs(freqs=86.6e9)
787
788        """
789        varlist = vars()
790        from asap import linecatalog
791        # simple  value
792        if isinstance(freqs, int) or isinstance(freqs, float):
793            self._setrestfreqs(freqs, "",unit)
794        # list of values
795        elif isinstance(freqs, list) or isinstance(freqs, tuple):
796            # list values are scalars
797            if isinstance(freqs[-1], int) or isinstance(freqs[-1], float):
798                sel = selector()
799                savesel = self._getselection()
800                for i in xrange(len(freqs)):
801                    sel.set_ifs([i])
802                    self._setselection(sel)
803                    self._setrestfreqs(freqs[i], "",unit)
804                self._setselection(savesel)
805            # list values are tuples, (value, name)
806            elif isinstance(freqs[-1], dict):
807                sel = selector()
808                savesel = self._getselection()
809                for i in xrange(len(freqs)):
810                    sel.set_ifs([i])
811                    self._setrestfreqs(freqs[i]["value"],
812                                       freqs[i]["name"], "MHz")
813                    self._setselection(sel)
814                self._setselection(savesel)
815        # freqs are to be taken from a linecatalog
816        elif isinstance(freqs, linecatalog):
817            sel = selector()
818            savesel = self._getselection()
819            for i in xrange(freqs.nrow()):
820                sel.set_ifs([i])
821                self._setselection(sel)
822                self._setrestfreqs(freqs.get_frequency(i),
823                                   freqs.get_name(i), "MHz")
824                # ensure that we are not iterating past nIF
825                if i == self.nif()-1: break
826            self._setselection(savesel)
827        else:
828            return
829        self._add_history("set_restfreqs", varlist)
830
831
832
833    def history(self):
834        hist = list(self._gethistory())
835        out = "-"*80
836        for h in hist:
837            if h.startswith("---"):
838                out += "\n"+h
839            else:
840                items = h.split("##")
841                date = items[0]
842                func = items[1]
843                items = items[2:]
844                out += "\n"+date+"\n"
845                out += "Function: %s\n  Parameters:" % (func)
846                for i in items:
847                    s = i.split("=")
848                    out += "\n   %s = %s" % (s[0], s[1])
849                out += "\n"+"-"*80
850        try:
851            from IPython.genutils import page as pager
852        except ImportError:
853            from pydoc import pager
854        pager(out)
855        return
856
857    #
858    # Maths business
859    #
860
861    def average_time(self, mask=None, scanav=False, weight='tint', align=False):
862        """
863        Return the (time) weighted average of a scan.
864        Note:
865            in channels only - align if necessary
866        Parameters:
867            mask:     an optional mask (only used for 'var' and 'tsys'
868                      weighting)
869            scanav:   True averages each scan separately
870                      False (default) averages all scans together,
871            weight:   Weighting scheme.
872                      'none'     (mean no weight)
873                      'var'      (1/var(spec) weighted)
874                      'tsys'     (1/Tsys**2 weighted)
875                      'tint'     (integration time weighted)
876                      'tintsys'  (Tint/Tsys**2)
877                      'median'   ( median averaging)
878                      The default is 'tint'
879            align:    align the spectra in velocity before averaging. It takes
880                      the time of the first spectrum as reference time.
881        Example:
882            # time average the scantable without using a mask
883            newscan = scan.average_time()
884        """
885        varlist = vars()
886        if weight is None: weight = 'TINT'
887        if mask is None: mask = ()
888        if scanav: scanav = "SCAN"
889        else: scanav = "NONE"
890        scan = (self, )
891        try:
892            if align:
893                scan = (self.freq_align(insitu=False), )
894            s = None
895            if weight.upper() == 'MEDIAN':
896                s = scantable(self._math._averagechannel(scan[0], 'MEDIAN',
897                                                         scanav))
898            else:
899                s = scantable(self._math._average(scan, mask, weight.upper(),
900                              scanav))
901        except RuntimeError, msg:
902            if rcParams['verbose']:
903                print msg
904                return
905            else: raise
906        s._add_history("average_time", varlist)
907        print_log()
908        return s
909
910    def convert_flux(self, jyperk=None, eta=None, d=None, insitu=None):
911        """
912        Return a scan where all spectra are converted to either
913        Jansky or Kelvin depending upon the flux units of the scan table.
914        By default the function tries to look the values up internally.
915        If it can't find them (or if you want to over-ride), you must
916        specify EITHER jyperk OR eta (and D which it will try to look up
917        also if you don't set it). jyperk takes precedence if you set both.
918        Parameters:
919            jyperk:      the Jy / K conversion factor
920            eta:         the aperture efficiency
921            d:           the geomtric diameter (metres)
922            insitu:      if False a new scantable is returned.
923                         Otherwise, the scaling is done in-situ
924                         The default is taken from .asaprc (False)
925        """
926        if insitu is None: insitu = rcParams['insitu']
927        self._math._setinsitu(insitu)
928        varlist = vars()
929        if jyperk is None: jyperk = -1.0
930        if d is None: d = -1.0
931        if eta is None: eta = -1.0
932        s = scantable(self._math._convertflux(self, d, eta, jyperk))
933        s._add_history("convert_flux", varlist)
934        print_log()
935        if insitu: self._assign(s)
936        else: return s
937
938    def gain_el(self, poly=None, filename="", method="linear", insitu=None):
939        """
940        Return a scan after applying a gain-elevation correction.
941        The correction can be made via either a polynomial or a
942        table-based interpolation (and extrapolation if necessary).
943        You specify polynomial coefficients, an ascii table or neither.
944        If you specify neither, then a polynomial correction will be made
945        with built in coefficients known for certain telescopes (an error
946        will occur if the instrument is not known).
947        The data and Tsys are *divided* by the scaling factors.
948        Parameters:
949            poly:        Polynomial coefficients (default None) to compute a
950                         gain-elevation correction as a function of
951                         elevation (in degrees).
952            filename:    The name of an ascii file holding correction factors.
953                         The first row of the ascii file must give the column
954                         names and these MUST include columns
955                         "ELEVATION" (degrees) and "FACTOR" (multiply data
956                         by this) somewhere.
957                         The second row must give the data type of the
958                         column. Use 'R' for Real and 'I' for Integer.
959                         An example file would be
960                         (actual factors are arbitrary) :
961
962                         TIME ELEVATION FACTOR
963                         R R R
964                         0.1 0 0.8
965                         0.2 20 0.85
966                         0.3 40 0.9
967                         0.4 60 0.85
968                         0.5 80 0.8
969                         0.6 90 0.75
970            method:      Interpolation method when correcting from a table.
971                         Values are  "nearest", "linear" (default), "cubic"
972                         and "spline"
973            insitu:      if False a new scantable is returned.
974                         Otherwise, the scaling is done in-situ
975                         The default is taken from .asaprc (False)
976        """
977
978        if insitu is None: insitu = rcParams['insitu']
979        self._math._setinsitu(insitu)
980        varlist = vars()
981        if poly is None:
982            poly = ()
983        from os.path import expandvars
984        filename = expandvars(filename)
985        s = scantable(self._math._gainel(self, poly, filename, method))
986        s._add_history("gain_el", varlist)
987        print_log()
988        if insitu: self._assign(s)
989        else: return s
990
991    def freq_align(self, reftime=None, method='cubic', insitu=None):
992        """
993        Return a scan where all rows have been aligned in frequency/velocity.
994        The alignment frequency frame (e.g. LSRK) is that set by function
995        set_freqframe.
996        Parameters:
997            reftime:     reference time to align at. By default, the time of
998                         the first row of data is used.
999            method:      Interpolation method for regridding the spectra.
1000                         Choose from "nearest", "linear", "cubic" (default)
1001                         and "spline"
1002            insitu:      if False a new scantable is returned.
1003                         Otherwise, the scaling is done in-situ
1004                         The default is taken from .asaprc (False)
1005        """
1006        if insitu is None: insitu = rcParams["insitu"]
1007        self._math._setinsitu(insitu)
1008        varlist = vars()
1009        if reftime is None: reftime = ""
1010        s = scantable(self._math._freq_align(self, reftime, method))
1011        s._add_history("freq_align", varlist)
1012        print_log()
1013        if insitu: self._assign(s)
1014        else: return s
1015
1016    def opacity(self, tau, insitu=None):
1017        """
1018        Apply an opacity correction. The data
1019        and Tsys are multiplied by the correction factor.
1020        Parameters:
1021            tau:         Opacity from which the correction factor is
1022                         exp(tau*ZD)
1023                         where ZD is the zenith-distance
1024            insitu:      if False a new scantable is returned.
1025                         Otherwise, the scaling is done in-situ
1026                         The default is taken from .asaprc (False)
1027        """
1028        if insitu is None: insitu = rcParams['insitu']
1029        self._math._setinsitu(insitu)
1030        varlist = vars()
1031        s = scantable(self._math._opacity(self, tau))
1032        s._add_history("opacity", varlist)
1033        print_log()
1034        if insitu: self._assign(s)
1035        else: return s
1036
1037    def bin(self, width=5, insitu=None):
1038        """
1039        Return a scan where all spectra have been binned up.
1040            width:       The bin width (default=5) in pixels
1041            insitu:      if False a new scantable is returned.
1042                         Otherwise, the scaling is done in-situ
1043                         The default is taken from .asaprc (False)
1044        """
1045        if insitu is None: insitu = rcParams['insitu']
1046        self._math._setinsitu(insitu)
1047        varlist = vars()
1048        s = scantable(self._math._bin(self, width))
1049        s._add_history("bin", varlist)
1050        print_log()
1051        if insitu: self._assign(s)
1052        else: return s
1053
1054
1055    def resample(self, width=5, method='cubic', insitu=None):
1056        """
1057        Return a scan where all spectra have been binned up
1058            width:       The bin width (default=5) in pixels
1059            method:      Interpolation method when correcting from a table.
1060                         Values are  "nearest", "linear", "cubic" (default)
1061                         and "spline"
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        """
1066        if insitu is None: insitu = rcParams['insitu']
1067        self._math._setinsitu(insitu)
1068        varlist = vars()
1069        s = scantable(self._math._resample(self, method, width))
1070        s._add_history("resample", varlist)
1071        print_log()
1072        if insitu: self._assign(s)
1073        else: return s
1074
1075
1076    def average_pol(self, mask=None, weight='none'):
1077        """
1078        Average the Polarisations together.
1079        Parameters:
1080            mask:        An optional mask defining the region, where the
1081                         averaging will be applied. The output will have all
1082                         specified points masked.
1083            weight:      Weighting scheme. 'none' (default), 'var' (1/var(spec)
1084                         weighted), or 'tsys' (1/Tsys**2 weighted)
1085        """
1086        varlist = vars()
1087        if mask is None:
1088            mask = ()
1089        s = scantable(self._math._averagepol(self, mask, weight.upper()))
1090        s._add_history("average_pol", varlist)
1091        print_log()
1092        return s
1093
1094    def average_beam(self, mask=None, weight='none'):
1095        """
1096        Average the Beams together.
1097        Parameters:
1098            mask:        An optional mask defining the region, where the
1099                         averaging will be applied. The output will have all
1100                         specified points masked.
1101            weight:      Weighting scheme. 'none' (default), 'var' (1/var(spec)
1102                         weighted), or 'tsys' (1/Tsys**2 weighted)
1103        """
1104        varlist = vars()
1105        if mask is None:
1106            mask = ()
1107        s = scantable(self._math._averagebeams(self, mask, weight.upper()))
1108        s._add_history("average_beam", varlist)
1109        print_log()
1110        return s
1111
1112    def convert_pol(self, poltype=None):
1113        """
1114        Convert the data to a different polarisation type.
1115        Parameters:
1116            poltype:    The new polarisation type. Valid types are:
1117                        "linear", "stokes" and "circular"
1118        """
1119        varlist = vars()
1120        try:
1121            s = scantable(self._math._convertpol(self, poltype))
1122        except RuntimeError, msg:
1123            if rcParams['verbose']:
1124                print msg
1125                return
1126            else:
1127                raise
1128        s._add_history("convert_pol", varlist)
1129        print_log()
1130        return s
1131
1132    def smooth(self, kernel="hanning", width=5.0, insitu=None):
1133        """
1134        Smooth the spectrum by the specified kernel (conserving flux).
1135        Parameters:
1136            scan:       The input scan
1137            kernel:     The type of smoothing kernel. Select from
1138                        'hanning' (default), 'gaussian' and 'boxcar'.
1139                        The first three characters are sufficient.
1140            width:      The width of the kernel in pixels. For hanning this is
1141                        ignored otherwise it defauls to 5 pixels.
1142                        For 'gaussian' it is the Full Width Half
1143                        Maximum. For 'boxcar' it is the full width.
1144            insitu:     if False a new scantable is returned.
1145                        Otherwise, the scaling is done in-situ
1146                        The default is taken from .asaprc (False)
1147        Example:
1148             none
1149        """
1150        if insitu is None: insitu = rcParams['insitu']
1151        self._math._setinsitu(insitu)
1152        varlist = vars()
1153        s = scantable(self._math._smooth(self, kernel.lower(), width))
1154        s._add_history("smooth", varlist)
1155        print_log()
1156        if insitu: self._assign(s)
1157        else: return s
1158
1159
1160    def poly_baseline(self, mask=None, order=0, plot=False, insitu=None):
1161        """
1162        Return a scan which has been baselined (all rows) by a polynomial.
1163        Parameters:
1164            scan:       a scantable
1165            mask:       an optional mask
1166            order:      the order of the polynomial (default is 0)
1167            plot:       plot the fit and the residual. In this each
1168                        indivual fit has to be approved, by typing 'y'
1169                        or 'n'
1170            insitu:     if False a new scantable is returned.
1171                        Otherwise, the scaling is done in-situ
1172                        The default is taken from .asaprc (False)
1173        Example:
1174            # return a scan baselined by a third order polynomial,
1175            # not using a mask
1176            bscan = scan.poly_baseline(order=3)
1177        """
1178        if insitu is None: insitu = rcParams['insitu']
1179        varlist = vars()
1180        if mask is None:
1181            mask = list(NUM.ones(self.nchan(-1)))
1182        from asap.asapfitter import fitter
1183        try:
1184            f = fitter()
1185            f.set_scan(self, mask)
1186            f.set_function(poly=order)
1187            s = f.auto_fit(insitu, plot=plot)
1188            s._add_history("poly_baseline", varlist)
1189            print_log()
1190            if insitu: self._assign(s)
1191            else: return s
1192        except RuntimeError:
1193            msg = "The fit failed, possibly because it didn't converge."
1194            if rcParams['verbose']:
1195                print msg
1196                return
1197            else:
1198                raise RuntimeError(msg)
1199
1200
1201    def auto_poly_baseline(self, mask=[], edge=(0, 0), order=0,
1202                           threshold=3, plot=False, insitu=None):
1203        """
1204        Return a scan which has been baselined (all rows) by a polynomial.
1205        Spectral lines are detected first using linefinder and masked out
1206        to avoid them affecting the baseline solution.
1207
1208        Parameters:
1209            mask:       an optional mask retreived from scantable
1210            edge:       an optional number of channel to drop at
1211                        the edge of spectrum. If only one value is
1212                        specified, the same number will be dropped from
1213                        both sides of the spectrum. Default is to keep
1214                        all channels. Nested tuples represent individual
1215                        edge selection for different IFs (a number of spectral
1216                        channels can be different)
1217            order:      the order of the polynomial (default is 0)
1218            threshold:  the threshold used by line finder. It is better to
1219                        keep it large as only strong lines affect the
1220                        baseline solution.
1221            plot:       plot the fit and the residual. In this each
1222                        indivual fit has to be approved, by typing 'y'
1223                        or 'n'
1224            insitu:     if False a new scantable is returned.
1225                        Otherwise, the scaling is done in-situ
1226                        The default is taken from .asaprc (False)
1227
1228        Example:
1229            scan2=scan.auto_poly_baseline(order=7)
1230        """
1231        if insitu is None: insitu = rcParams['insitu']
1232        varlist = vars()
1233        from asap.asapfitter import fitter
1234        from asap.asaplinefind import linefinder
1235        from asap import _is_sequence_or_number as _is_valid
1236
1237        # check whether edge is set up for each IF individually
1238        individualedge = False;
1239        if len(edge) > 1:
1240            if isinstance(edge[0], list) or isinstance(edge[0], tuple):
1241                individualedge = True;
1242
1243        if not _is_valid(edge, int) and not individualedge:
1244            raise ValueError, "Parameter 'edge' has to be an integer or a \
1245            pair of integers specified as a tuple. Nested tuples are allowed \
1246            to make individual selection for different IFs."
1247
1248        curedge = (0, 0)
1249        if individualedge:
1250            for edgepar in edge:
1251                if not _is_valid(edgepar, int):
1252                    raise ValueError, "Each element of the 'edge' tuple has \
1253                                       to be a pair of integers or an integer."
1254        else:
1255            curedge = edge;
1256
1257        # setup fitter
1258        f = fitter()
1259        f.set_function(poly=order)
1260
1261        # setup line finder
1262        fl = linefinder()
1263        fl.set_options(threshold=threshold)
1264
1265        if not insitu:
1266            workscan = self.copy()
1267        else:
1268            workscan = self
1269
1270        fl.set_scan(workscan)
1271
1272        rows = range(workscan.nrow())
1273        asaplog.push("Processing:")
1274        for r in rows:
1275            msg = " Scan[%d] Beam[%d] IF[%d] Pol[%d] Cycle[%d]" % \
1276                (workscan.getscan(r), workscan.getbeam(r), workscan.getif(r), \
1277                 workscan.getpol(r), workscan.getcycle(r))
1278            asaplog.push(msg, False)
1279
1280            # figure out edge parameter
1281            if individualedge:
1282                if len(edge) >= workscan.getif(r):
1283                    raise RuntimeError, "Number of edge elements appear to " \
1284                                        "be less than the number of IFs"
1285                    curedge = edge[workscan.getif(r)]
1286
1287            # setup line finder
1288            fl.find_lines(r, mask, curedge)
1289            f.set_scan(workscan, fl.get_mask())
1290            f.x = workscan._getabcissa(r)
1291            f.y = workscan._getspectrum(r)
1292            f.data = None
1293            f.fit()
1294            x = f.get_parameters()
1295            if plot:
1296                f.plot(residual=True)
1297                x = raw_input("Accept fit ( [y]/n ): ")
1298                if x.upper() == 'N':
1299                    continue
1300            workscan._setspectrum(f.fitter.getresidual(), r)
1301        if plot:
1302            f._p.unmap()
1303            f._p = None
1304        workscan._add_history("auto_poly_baseline", varlist)
1305        if insitu:
1306            self._assign(workscan)
1307        else:
1308            return workscan
1309
1310    def rotate_linpolphase(self, angle):
1311        """
1312        Rotate the phase of the complex polarization O=Q+iU correlation.
1313        This is always done in situ in the raw data.  So if you call this
1314        function more than once then each call rotates the phase further.
1315        Parameters:
1316            angle:   The angle (degrees) to rotate (add) by.
1317        Examples:
1318            scan.rotate_linpolphase(2.3)
1319        """
1320        varlist = vars()
1321        self._math._rotate_linpolphase(self, angle)
1322        self._add_history("rotate_linpolphase", varlist)
1323        print_log()
1324        return
1325
1326
1327    def rotate_xyphase(self, angle):
1328        """
1329        Rotate the phase of the XY correlation.  This is always done in situ
1330        in the data.  So if you call this function more than once
1331        then each call rotates the phase further.
1332        Parameters:
1333            angle:   The angle (degrees) to rotate (add) by.
1334        Examples:
1335            scan.rotate_xyphase(2.3)
1336        """
1337        varlist = vars()
1338        self._math._rotate_xyphase(self, angle)
1339        self._add_history("rotate_xyphase", varlist)
1340        print_log()
1341        return
1342
1343    def swap_linears(self):
1344        """
1345        Swap the linear polarisations XX and YY
1346        """
1347        varlist = vars()
1348        self._math._swap_linears(self)
1349        self._add_history("swap_linears", varlist)
1350        print_log()
1351        return
1352
1353    def invert_phase(self):
1354        """
1355        Invert the phase of the complex polarisation
1356        """
1357        varlist = vars()
1358        self._math._invert_phase(self)
1359        self._add_history("invert_phase", varlist)
1360        print_log()
1361        return
1362
1363    def add(self, offset, insitu=None):
1364        """
1365        Return a scan where all spectra have the offset added
1366        Parameters:
1367            offset:      the offset
1368            insitu:      if False a new scantable is returned.
1369                         Otherwise, the scaling is done in-situ
1370                         The default is taken from .asaprc (False)
1371        """
1372        if insitu is None: insitu = rcParams['insitu']
1373        self._math._setinsitu(insitu)
1374        varlist = vars()
1375        s = scantable(self._math._unaryop(self, offset, "ADD", False))
1376        s._add_history("add", varlist)
1377        print_log()
1378        if insitu:
1379            self._assign(s)
1380        else:
1381            return s
1382
1383    def scale(self, factor, tsys=True, insitu=None, ):
1384        """
1385        Return a scan where all spectra are scaled by the give 'factor'
1386        Parameters:
1387            factor:      the scaling factor
1388            insitu:      if False a new scantable is returned.
1389                         Otherwise, the scaling is done in-situ
1390                         The default is taken from .asaprc (False)
1391            tsys:        if True (default) then apply the operation to Tsys
1392                         as well as the data
1393        """
1394        if insitu is None: insitu = rcParams['insitu']
1395        self._math._setinsitu(insitu)
1396        varlist = vars()
1397        s = scantable(self._math._unaryop(self, factor, "MUL", tsys))
1398        s._add_history("scale", varlist)
1399        print_log()
1400        if insitu:
1401            self._assign(s)
1402        else:
1403            return s
1404
1405    def auto_quotient(self, mode='time', preserve=True):
1406        """
1407        This function allows to build quotients automatically.
1408        It assumes the observation to have the same numer of
1409        "ons" and "offs"
1410        It will support "closest off in time" in the future
1411        Parameters:
1412            mode:           the on/off detection mode; 'suffix' (default)
1413                            'suffix' identifies 'off' scans by the
1414                            trailing '_R' (Mopra/Parkes) or
1415                            '_e'/'_w' (Tid)
1416            preserve:       you can preserve (default) the continuum or
1417                            remove it.  The equations used are
1418                            preserve: Output = Toff * (on/off) - Toff
1419                            remove:   Output = Toff * (on/off) - Ton
1420        """
1421        modes = ["time"]
1422        if not mode in modes:
1423            msg = "please provide valid mode. Valid modes are %s" % (modes)
1424            raise ValueError(msg)
1425        varlist = vars()
1426        s = scantable(self._math._auto_quotient(self, mode, preserve))
1427        s._add_history("auto_quotient", varlist)
1428        print_log()
1429        return s
1430
1431    def mx_quotient(self, mask = None, weight='median', preserve=True):
1432        """
1433        Form a quotient using "off" beams when observing in "MX" mode.
1434        Parameters:
1435            mask:           an optional mask to be used when weight == 'stddev'
1436            weight:         How to average the off beams.  Default is 'median'.
1437            preserve:       you can preserve (default) the continuum or
1438                            remove it.  The equations used are
1439                            preserve: Output = Toff * (on/off) - Toff
1440                            remove:   Output = Toff * (on/off) - Ton
1441        """
1442        if mask is None: mask = ()
1443        varlist = vars()
1444        on = scantable(self._math._mx_extract(self, 'on'))
1445        preoff = scantable(self._math._mx_extract(self, 'off'))
1446        off = preoff.average_time(mask=mask, weight=weight, scanav=False)
1447        from asapmath  import quotient
1448        q = quotient(on, off, preserve)
1449        q._add_history("mx_quotient", varlist)
1450        print_log()
1451        return q
1452
1453    def freq_switch(self, insitu=None):
1454        """
1455        Apply frequency switching to the data.
1456        Parameters:
1457            insitu:      if False a new scantable is returned.
1458                         Otherwise, the swictching is done in-situ
1459                         The default is taken from .asaprc (False)
1460        Example:
1461            none
1462        """
1463        if insitu is None: insitu = rcParams['insitu']
1464        self._math._setinsitu(insitu)
1465        varlist = vars()
1466        s = scantable(self._math._freqswitch(self))
1467        s._add_history("freq_switch", varlist)
1468        print_log()
1469        if insitu: self._assign(s)
1470        else: return s
1471
1472    def recalc_azel(self):
1473        """
1474        Recalculate the azimuth and elevation for each position.
1475        Parameters:
1476            none
1477        Example:
1478        """
1479        varlist = vars()
1480        self._recalcazel()
1481        self._add_history("recalc_azel", varlist)
1482        print_log()
1483        return
1484
1485    def __add__(self, other):
1486        varlist = vars()
1487        s = None
1488        if isinstance(other, scantable):
1489            print "scantable + scantable NYI"
1490            return
1491        elif isinstance(other, float):
1492            s = scantable(self._math._unaryop(self, other, "ADD", False))
1493        else:
1494            raise TypeError("Other input is not a scantable or float value")
1495        s._add_history("operator +", varlist)
1496        print_log()
1497        return s
1498
1499    def __sub__(self, other):
1500        """
1501        implicit on all axes and on Tsys
1502        """
1503        varlist = vars()
1504        s = None
1505        if isinstance(other, scantable):
1506            print "scantable - scantable NYI"
1507            return
1508        elif isinstance(other, float):
1509            s = scantable(self._math._unaryop(self, other, "SUB", False))
1510        else:
1511            raise TypeError("Other input is not a scantable or float value")
1512        s._add_history("operator -", varlist)
1513        print_log()
1514        return s
1515
1516    def __mul__(self, other):
1517        """
1518        implicit on all axes and on Tsys
1519        """
1520        varlist = vars()
1521        s = None
1522        if isinstance(other, scantable):
1523            print "scantable * scantable NYI"
1524            return
1525        elif isinstance(other, float):
1526            s = scantable(self._math._unaryop(self, other, "MUL", False))
1527        else:
1528            raise TypeError("Other input is not a scantable or float value")
1529        s._add_history("operator *", varlist)
1530        print_log()
1531        return s
1532
1533
1534    def __div__(self, other):
1535        """
1536        implicit on all axes and on Tsys
1537        """
1538        varlist = vars()
1539        s = None
1540        if isinstance(other, scantable):
1541            print "scantable / scantable NYI"
1542            return
1543        elif isinstance(other, float):
1544            if other == 0.0:
1545                raise ZeroDivisionError("Dividing by zero is not recommended")
1546            s = scantable(self._math._unaryop(self, other, "DIV", False))
1547        else:
1548            raise TypeError("Other input is not a scantable or float value")
1549        s._add_history("operator /", varlist)
1550        print_log()
1551        return s
1552
1553    def get_fit(self, row=0):
1554        """
1555        Print or return the stored fits for a row in the scantable
1556        Parameters:
1557            row:    the row which the fit has been applied to.
1558        """
1559        if row > self.nrow():
1560            return
1561        from asap.asapfit import asapfit
1562        fit = asapfit(self._getfit(row))
1563        if rcParams['verbose']:
1564            print fit
1565            return
1566        else:
1567            return fit.as_dict()
1568
1569    def _add_history(self, funcname, parameters):
1570        # create date
1571        sep = "##"
1572        from datetime import datetime
1573        dstr = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
1574        hist = dstr+sep
1575        hist += funcname+sep#cdate+sep
1576        if parameters.has_key('self'): del parameters['self']
1577        for k, v in parameters.iteritems():
1578            if type(v) is dict:
1579                for k2, v2 in v.iteritems():
1580                    hist += k2
1581                    hist += "="
1582                    if isinstance(v2, scantable):
1583                        hist += 'scantable'
1584                    elif k2 == 'mask':
1585                        if isinstance(v2, list) or isinstance(v2, tuple):
1586                            hist += str(self._zip_mask(v2))
1587                        else:
1588                            hist += str(v2)
1589                    else:
1590                        hist += str(v2)
1591            else:
1592                hist += k
1593                hist += "="
1594                if isinstance(v, scantable):
1595                    hist += 'scantable'
1596                elif k == 'mask':
1597                    if isinstance(v, list) or isinstance(v, tuple):
1598                        hist += str(self._zip_mask(v))
1599                    else:
1600                        hist += str(v)
1601                else:
1602                    hist += str(v)
1603            hist += sep
1604        hist = hist[:-2] # remove trailing '##'
1605        self._addhistory(hist)
1606
1607
1608    def _zip_mask(self, mask):
1609        mask = list(mask)
1610        i = 0
1611        segments = []
1612        while mask[i:].count(1):
1613            i += mask[i:].index(1)
1614            if mask[i:].count(0):
1615                j = i + mask[i:].index(0)
1616            else:
1617                j = len(mask)
1618            segments.append([i, j])
1619            i = j
1620        return segments
1621
1622    def _get_ordinate_label(self):
1623        fu = "("+self.get_fluxunit()+")"
1624        import re
1625        lbl = "Intensity"
1626        if re.match(".K.", fu):
1627            lbl = "Brightness Temperature "+ fu
1628        elif re.match(".Jy.", fu):
1629            lbl = "Flux density "+ fu
1630        return lbl
1631
1632    def _check_ifs(self):
1633        nchans = [self.nchan(i) for i in range(self.nif(-1))]
1634        nchans = filter(lambda t: t > 0, nchans)
1635        return (sum(nchans)/len(nchans) == nchans[0])
1636
1637    def _fill(self, names, unit, average):
1638        import os
1639        from asap._asap import stfiller
1640        first = True
1641        fullnames = []
1642        for name in names:
1643            name = os.path.expandvars(name)
1644            name = os.path.expanduser(name)
1645            if not os.path.exists(name):
1646                msg = "File '%s' does not exists" % (name)
1647                if rcParams['verbose']:
1648                    asaplog.push(msg)
1649                    print asaplog.pop().strip()
1650                    return
1651                raise IOError(msg)
1652            fullnames.append(name)
1653        if average:
1654            asaplog.push('Auto averaging integrations')
1655        stype = int(rcParams['scantable.storage'].lower() == 'disk')
1656        for name in fullnames:
1657            tbl = Scantable(stype)
1658            r = stfiller(tbl)
1659            msg = "Importing %s..." % (name)
1660            asaplog.push(msg, False)
1661            print_log()
1662            r._open(name, -1, -1)
1663            r._read()
1664            #tbl = r._getdata()
1665            if average:
1666                tbl = self._math._average((tbl, ), (), 'NONE', 'SCAN')
1667                #tbl = tbl2
1668            if not first:
1669                tbl = self._math._merge([self, tbl])
1670                #tbl = tbl2
1671            Scantable.__init__(self, tbl)
1672            r._close()
1673            del r, tbl
1674            first = False
1675        if unit is not None:
1676            self.set_fluxunit(unit)
1677        self.set_freqframe(rcParams['scantable.freqframe'])
1678        #self._add_history("scantable", varlist)
1679
Note: See TracBrowser for help on using the repository browser.