source: branches/alma/python/scantable.py @ 1684

Last change on this file since 1684 was 1684, checked in by Takeshi Nakazato, 14 years ago

New Development: No

JIRA Issue: Yes CAS-1810

Ready to Release: Yes

Interface Changes: Yes

What Interface Changed: Added 'antenna' parameter to scantable constructor

Test Programs: List test programs

Put in Release Notes: Yes

Module(s): atnf

Description: Describe your changes here...

I have added 'antenna' parameter to scantable constructor to be able to
select specific antenna from MS data with multiple antenna data.
Currently, only single antenna selection is working. For multiple antenna
selection, only first selection is used.


  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 86.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 linecatalog
7from asap import _n_bools, mask_not, mask_and, mask_or
8
9class scantable(Scantable):
10    """
11        The ASAP container for scans
12    """
13
14    def __init__(self, filename, average=None, unit=None, getpt=None, antenna=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            getpt:       for MeasurementSet input data only:
33                         If True, all pointing data are filled.
34                         The deafult is False, which makes time to load
35                         the MS data faster in some cases.
36        """
37        if average is None:
38            average = rcParams['scantable.autoaverage']
39        if getpt is None:
40            getpt = True
41        if antenna is None:
42            antenna = ''
43        elif type(antenna) == int:
44            antenna = '%s'%antenna
45        elif type(antenna) == list:
46            tmpstr = ''
47            for i in range( len(antenna) ):
48                if type(antenna[i]) == int:
49                    tmpstr = tmpstr + ('%s,'%(antenna[i]))
50                elif type(antenna[i]) == str:
51                    tmpstr=tmpstr+antenna[i]+','
52                else:
53                    asaplog.push('Bad antenna selection.')
54                    print_log('ERROR')
55                    return
56            antenna = tmpstr.rstrip(',')
57        varlist = vars()
58        from asap._asap import stmath
59        self._math = stmath( rcParams['insitu'] )
60        if isinstance(filename, Scantable):
61            Scantable.__init__(self, filename)
62        else:
63            if isinstance(filename, str):# or \
64#                (isinstance(filename, list) or isinstance(filename, tuple)) \
65#                  and isinstance(filename[-1], str):
66                import os.path
67                filename = os.path.expandvars(filename)
68                filename = os.path.expanduser(filename)
69                if not os.path.exists(filename):
70                    s = "File '%s' not found." % (filename)
71                    if rcParams['verbose']:
72                        asaplog.push(s)
73                        #print asaplog.pop().strip()
74                        print_log('ERROR')
75                        return
76                    raise IOError(s)
77                if os.path.isdir(filename) \
78                    and not os.path.exists(filename+'/table.f1'):
79                    # crude check if asap table
80                    if os.path.exists(filename+'/table.info'):
81                        ondisk = rcParams['scantable.storage'] == 'disk'
82                        Scantable.__init__(self, filename, ondisk)
83                        if unit is not None:
84                            self.set_fluxunit(unit)
85                        # do not reset to the default freqframe
86                        #self.set_freqframe(rcParams['scantable.freqframe'])
87                    else:
88                        msg = "The given file '%s'is not a valid " \
89                              "asap table." % (filename)
90                        if rcParams['verbose']:
91                            #print msg
92                            asaplog.push( msg )
93                            print_log( 'ERROR' )
94                            return
95                        else:
96                            raise IOError(msg)
97                else:
98                    self._fill([filename], unit, average, getpt, antenna)
99            elif (isinstance(filename, list) or isinstance(filename, tuple)) \
100                  and isinstance(filename[-1], str):
101                self._fill(filename, unit, average, getpt, antenna)
102        self._add_history("scantable", varlist)
103        print_log()
104
105    def save(self, name=None, format=None, overwrite=False):
106        """
107        Store the scantable on disk. This can be an asap (aips++) Table,
108        SDFITS or MS2 format.
109        Parameters:
110            name:        the name of the outputfile. For format "ASCII"
111                         this is the root file name (data in 'name'.txt
112                         and header in 'name'_header.txt)
113            format:      an optional file format. Default is ASAP.
114                         Allowed are - 'ASAP' (save as ASAP [aips++] Table),
115                                       'SDFITS' (save as SDFITS file)
116                                       'ASCII' (saves as ascii text file)
117                                       'MS2' (saves as an aips++
118                                              MeasurementSet V2)
119                                       'FITS' (save as image FITS - not
120                                               readable by class)
121                                       'CLASS' (save as FITS readable by CLASS)
122            overwrite:   If the file should be overwritten if it exists.
123                         The default False is to return with warning
124                         without writing the output. USE WITH CARE.
125        Example:
126            scan.save('myscan.asap')
127            scan.save('myscan.sdfits', 'SDFITS')
128        """
129        from os import path
130        if format is None: format = rcParams['scantable.save']
131        suffix = '.'+format.lower()
132        if name is None or name == "":
133            name = 'scantable'+suffix
134            msg = "No filename given. Using default name %s..." % name
135            asaplog.push(msg)
136        name = path.expandvars(name)
137        if path.isfile(name) or path.isdir(name):
138            if not overwrite:
139                msg = "File %s exists." % name
140                if rcParams['verbose']:
141                    #print msg
142                    asaplog.push( msg )
143                    print_log( 'ERROR' )
144                    return
145                else:
146                    raise IOError(msg)
147        format2 = format.upper()
148        if format2 == 'ASAP':
149            self._save(name)
150        else:
151            from asap._asap import stwriter as stw
152            writer = stw(format2)
153            writer.write(self, name)
154        print_log()
155        return
156
157    def copy(self):
158        """
159        Return a copy of this scantable.
160        Note:
161            This makes a full (deep) copy. scan2 = scan1 makes a reference.
162        Parameters:
163            none
164        Example:
165            copiedscan = scan.copy()
166        """
167        sd = scantable(Scantable._copy(self))
168        return sd
169
170    def drop_scan(self, scanid=None):
171        """
172        Return a new scantable where the specified scan number(s) has(have)
173        been dropped.
174        Parameters:
175            scanid:    a (list of) scan number(s)
176        """
177        from asap import _is_sequence_or_number as _is_valid
178        from asap import _to_list
179        from asap import unique
180        if not _is_valid(scanid):
181            if rcParams['verbose']:
182                #print "Please specify a scanno to drop from the scantable"
183                asaplog.push( 'Please specify a scanno to drop from the scantable' )
184                print_log( 'ERROR' )
185                return
186            else:
187                raise RuntimeError("No scan given")
188        try:
189            scanid = _to_list(scanid)
190            allscans = unique([ self.getscan(i) for i in range(self.nrow())])
191            for sid in scanid: allscans.remove(sid)
192            if len(allscans) == 0:
193                raise ValueError("Can't remove all scans")
194        except ValueError:
195            if rcParams['verbose']:
196                #print "Couldn't find any match."
197                print_log()
198                asaplog.push( "Couldn't find any match." )
199                print_log( 'ERROR' )
200                return
201            else: raise
202        try:
203            bsel = self.get_selection()
204            sel = selector()
205            sel.set_scans(allscans)
206            self.set_selection(bsel+sel)
207            scopy = self._copy()
208            self.set_selection(bsel)
209            return scantable(scopy)
210        except RuntimeError:
211            if rcParams['verbose']:
212                #print "Couldn't find any match."
213                print_log()
214                asaplog.push( "Couldn't find any match." )
215                print_log( 'ERROR' )
216            else:
217                raise
218
219
220    def get_scan(self, scanid=None):
221        """
222        Return a specific scan (by scanno) or collection of scans (by
223        source name) in a new scantable.
224        Note:
225            See scantable.drop_scan() for the inverse operation.
226        Parameters:
227            scanid:    a (list of) scanno or a source name, unix-style
228                       patterns are accepted for source name matching, e.g.
229                       '*_R' gets all 'ref scans
230        Example:
231            # get all scans containing the source '323p459'
232            newscan = scan.get_scan('323p459')
233            # get all 'off' scans
234            refscans = scan.get_scan('*_R')
235            # get a susbset of scans by scanno (as listed in scan.summary())
236            newscan = scan.get_scan([0, 2, 7, 10])
237        """
238        if scanid is None:
239            if rcParams['verbose']:
240                #print "Please specify a scan no or name to " \
241                #      "retrieve from the scantable"
242                asaplog.push( 'Please specify a scan no or name to retrieve from the scantable' )
243                print_log( 'ERROR' )
244                return
245            else:
246                raise RuntimeError("No scan given")
247
248        try:
249            bsel = self.get_selection()
250            sel = selector()
251            if type(scanid) is str:
252                sel.set_name(scanid)
253                self.set_selection(bsel+sel)
254                scopy = self._copy()
255                self.set_selection(bsel)
256                return scantable(scopy)
257            elif type(scanid) is int:
258                sel.set_scans([scanid])
259                self.set_selection(bsel+sel)
260                scopy = self._copy()
261                self.set_selection(bsel)
262                return scantable(scopy)
263            elif type(scanid) is list:
264                sel.set_scans(scanid)
265                self.set_selection(sel)
266                scopy = self._copy()
267                self.set_selection(bsel)
268                return scantable(scopy)
269            else:
270                msg = "Illegal scanid type, use 'int' or 'list' if ints."
271                if rcParams['verbose']:
272                    #print msg
273                    asaplog.push( msg )
274                    print_log( 'ERROR' )
275                else:
276                    raise TypeError(msg)
277        except RuntimeError:
278            if rcParams['verbose']:
279                #print "Couldn't find any match."
280                print_log()
281                asaplog.push( "Couldn't find any match." )
282                print_log( 'ERROR' )
283            else: raise
284
285    def __str__(self):
286        return Scantable._summary(self, True)
287
288    def summary(self, filename=None):
289        """
290        Print a summary of the contents of this scantable.
291        Parameters:
292            filename:    the name of a file to write the putput to
293                         Default - no file output
294            verbose:     print extra info such as the frequency table
295                         The default (False) is taken from .asaprc
296        """
297        info = Scantable._summary(self, True)
298        #if verbose is None: verbose = rcParams['scantable.verbosesummary']
299        if filename is not None:
300            if filename is "":
301                filename = 'scantable_summary.txt'
302            from os.path import expandvars, isdir
303            filename = expandvars(filename)
304            if not isdir(filename):
305                data = open(filename, 'w')
306                data.write(info)
307                data.close()
308            else:
309                msg = "Illegal file name '%s'." % (filename)
310                if rcParams['verbose']:
311                    #print msg
312                    asaplog.push( msg )
313                    print_log( 'ERROR' )
314                else:
315                    raise IOError(msg)
316        if rcParams['verbose']:
317            try:
318                from IPython.genutils import page as pager
319            except ImportError:
320                from pydoc import pager
321            pager(info)
322        else:
323            return info
324
325    def get_spectrum(self, rowno):
326        """Return the spectrum for the current row in the scantable as a list.
327        Parameters:
328             rowno:   the row number to retrieve the spectrum from       
329        """
330        return self._getspectrum(rowno)
331
332    def get_mask(self, rowno):
333        """Return the mask for the current row in the scantable as a list.
334        Parameters:
335             rowno:   the row number to retrieve the mask from       
336        """
337        return self._getmask(rowno)
338
339    def set_spectrum(self, spec, rowno):
340        """Return the spectrum for the current row in the scantable as a list.
341        Parameters:
342             spec:   the spectrum
343             rowno:    the row number to set the spectrum for       
344        """
345        assert(len(spec) == self.nchan())
346        return self._setspectrum(spec, rowno)
347
348    def get_selection(self):
349        """
350        Get the selection object currently set on this scantable.
351        Parameters:
352            none
353        Example:
354            sel = scan.get_selection()
355            sel.set_ifs(0)              # select IF 0
356            scan.set_selection(sel)     # apply modified selection
357        """
358        return selector(self._getselection())
359
360    def set_selection(self, selection=selector()):
361        """
362        Select a subset of the data. All following operations on this scantable
363        are only applied to thi selection.
364        Parameters:
365            selection:    a selector object (default unset the selection)
366        Examples:
367            sel = selector()         # create a selection object
368            self.set_scans([0, 3])    # select SCANNO 0 and 3
369            scan.set_selection(sel)  # set the selection
370            scan.summary()           # will only print summary of scanno 0 an 3
371            scan.set_selection()     # unset the selection
372        """
373        self._setselection(selection)
374
375    def get_row(self, row=0, insitu=None):
376        """
377        Select a row in the scantable.
378        Return a scantable with single row.
379        Parameters:
380            row: row no of integration, default is 0.
381            insitu: if False a new scantable is returned.
382                    Otherwise, the scaling is done in-situ
383                    The default is taken from .asaprc (False)
384        """
385        if insitu is None: insitu = rcParams['insitu']
386        if not insitu:
387            workscan = self.copy()
388        else:
389            workscan = self
390        # Select a row
391        sel=selector()
392        sel.set_scans([workscan.getscan(row)])
393        sel.set_cycles([workscan.getcycle(row)])
394        sel.set_beams([workscan.getbeam(row)])
395        sel.set_ifs([workscan.getif(row)])
396        sel.set_polarisations([workscan.getpol(row)])
397        sel.set_name(workscan._getsourcename(row))
398        workscan.set_selection(sel)
399        if not workscan.nrow() == 1:
400            msg = "Cloud not identify single row. %d rows selected."%(workscan.nrow())
401            raise RuntimeError(msg)
402        del sel
403        if insitu:
404            self._assign(workscan)
405        else:
406            return workscan
407
408    #def stats(self, stat='stddev', mask=None):
409    def stats(self, stat='stddev', mask=None, form='3.3f'):
410        """
411        Determine the specified statistic of the current beam/if/pol
412        Takes a 'mask' as an optional parameter to specify which
413        channels should be excluded.
414        Parameters:
415            stat:    'min', 'max', 'min_abc', 'max_abc', 'sumsq', 'sum',
416                     'mean', 'var', 'stddev', 'avdev', 'rms', 'median'
417            mask:    an optional mask specifying where the statistic
418                     should be determined.
419            form:    format string to print statistic values
420        Example:
421            scan.set_unit('channel')
422            msk = scan.create_mask([100, 200], [500, 600])
423            scan.stats(stat='mean', mask=m)
424        """
425        if mask == None:
426            mask = []
427        axes = ['Beam', 'IF', 'Pol', 'Time']
428        if not self._check_ifs():
429            raise ValueError("Cannot apply mask as the IFs have different "
430                             "number of channels. Please use setselection() "
431                             "to select individual IFs")
432        rtnabc = False
433        if stat.lower().endswith('_abc'): rtnabc = True
434        getchan = False
435        if stat.lower().startswith('min') or stat.lower().startswith('max'):
436            chan = self._math._minmaxchan(self, mask, stat)
437            getchan = True
438            statvals = []
439        if not rtnabc: statvals = self._math._stats(self, mask, stat)
440
441        out = ''
442        axes = []
443        for i in range(self.nrow()):
444            axis = []
445            axis.append(self.getscan(i))
446            axis.append(self.getbeam(i))
447            axis.append(self.getif(i))
448            axis.append(self.getpol(i))
449            axis.append(self.getcycle(i))
450            axes.append(axis)
451            tm = self._gettime(i)
452            src = self._getsourcename(i)
453            refstr = ''
454            statunit= ''
455            if getchan:
456                qx, qy = self.chan2data(rowno=i, chan=chan[i])
457                if rtnabc:
458                    statvals.append(qx['value'])
459                    #refstr = '(value: %3.3f' % (qy['value'])+' ['+qy['unit']+'])'
460                    refstr = ('(value: %'+form) % (qy['value'])+' ['+qy['unit']+'])'
461                    statunit= '['+qx['unit']+']'
462                else:
463                    #refstr = '(@ %3.3f' % (qx['value'])+' ['+qx['unit']+'])'
464                    refstr = ('(@ %'+form) % (qx['value'])+' ['+qx['unit']+'])'
465                    #statunit= ' ['+qy['unit']+']'
466            out += 'Scan[%d] (%s) ' % (axis[0], src)
467            out += 'Time[%s]:\n' % (tm)
468            if self.nbeam(-1) > 1: out +=  ' Beam[%d] ' % (axis[1])
469            if self.nif(-1) > 1: out +=  ' IF[%d] ' % (axis[2])
470            if self.npol(-1) > 1: out +=  ' Pol[%d] ' % (axis[3])
471            #out += '= %3.3f   ' % (statvals[i]) +refstr+'\n'
472            out += ('= %'+form) % (statvals[i]) +'   '+refstr+'\n'
473            out +=  "--------------------------------------------------\n"
474
475        if rcParams['verbose']:
476            import os
477            if os.environ.has_key( 'USER' ):
478                usr=os.environ['USER']
479            else:
480                import commands
481                usr=commands.getoutput( 'whoami' )
482            tmpfile='/tmp/tmp_'+usr+'_casapy_asap_scantable_stats'
483            f=open(tmpfile,'w')
484            print >> f, "--------------------------------------------------"
485            print >> f, " ", stat, statunit
486            print >> f, "--------------------------------------------------"
487            print >> f, out
488            f.close()
489            f=open(tmpfile,'r')
490            x=f.readlines()
491            f.close()
492            for xx in x:
493                asaplog.push( xx, False )
494            print_log()
495        #else:
496            #retval = { 'axesnames': ['scanno', 'beamno', 'ifno', 'polno', 'cycleno'],
497            #           'axes' : axes,
498            #           'data': statvals}
499        return statvals
500
501    def chan2data(self, rowno=0, chan=0):
502        """
503        Returns channel/frequency/velocity and spectral value
504        at an arbitrary row and channel in the scantable.
505        Parameters:
506            rowno:   a row number in the scantable. Default is the
507                     first row, i.e. rowno=0
508            chan:    a channel in the scantable. Default is the first
509                     channel, i.e. pos=0
510        """
511        if isinstance(rowno, int) and isinstance(chan, int):
512            qx = {'unit': self.get_unit(),
513                  'value': self._getabcissa(rowno)[chan]}
514            qy = {'unit': self.get_fluxunit(),
515                  'value': self._getspectrum(rowno)[chan]}
516            return qx, qy
517
518    def stddev(self, mask=None):
519        """
520        Determine the standard deviation of the current beam/if/pol
521        Takes a 'mask' as an optional parameter to specify which
522        channels should be excluded.
523        Parameters:
524            mask:    an optional mask specifying where the standard
525                     deviation should be determined.
526
527        Example:
528            scan.set_unit('channel')
529            msk = scan.create_mask([100, 200], [500, 600])
530            scan.stddev(mask=m)
531        """
532        return self.stats(stat='stddev', mask=mask);
533
534
535    def get_column_names(self):
536        """
537        Return a  list of column names, which can be used for selection.
538        """
539        return list(Scantable.get_column_names(self))
540
541    def get_tsys(self):
542        """
543        Return the System temperatures.
544        Returns:
545            a list of Tsys values for the current selection
546        """
547
548        return self._row_callback(self._gettsys, "Tsys")
549
550    def _row_callback(self, callback, label):
551        axes = []
552        axesnames = ['scanno', 'beamno', 'ifno', 'polno', 'cycleno']
553        out = ""
554        outvec = []
555        for i in range(self.nrow()):
556            axis = []
557            axis.append(self.getscan(i))
558            axis.append(self.getbeam(i))
559            axis.append(self.getif(i))
560            axis.append(self.getpol(i))
561            axis.append(self.getcycle(i))
562            axes.append(axis)
563            tm = self._gettime(i)
564            src = self._getsourcename(i)
565            out += 'Scan[%d] (%s) ' % (axis[0], src)
566            out += 'Time[%s]:\n' % (tm)
567            if self.nbeam(-1) > 1: out +=  ' Beam[%d] ' % (axis[1])
568            if self.nif(-1) > 1: out +=  ' IF[%d] ' % (axis[2])
569            if self.npol(-1) > 1: out +=  ' Pol[%d] ' % (axis[3])
570            outvec.append(callback(i))
571            out += '= %3.3f\n' % (outvec[i])
572            out +=  "--------------------------------------------------\n"
573        if rcParams['verbose']:
574            asaplog.push("--------------------------------------------------")
575            asaplog.push(" %s" % (label))
576            asaplog.push("--------------------------------------------------")
577            asaplog.push(out)
578            print_log()
579        # disabled because the vector seems more useful
580        #retval = {'axesnames': axesnames, 'axes': axes, 'data': outvec}
581        return outvec
582
583    def _get_column(self, callback, row=-1):
584        """
585        """
586        if row == -1:
587            return [callback(i) for i in range(self.nrow())]
588        else:
589            if  0 <= row < self.nrow():
590                return callback(row)
591
592
593    def get_time(self, row=-1, asdatetime=False):
594        """
595        Get a list of time stamps for the observations.
596        Return a datetime object for each integration time stamp in the scantable.
597        Parameters:
598            row:          row no of integration. Default -1 return all rows
599            asdatetime:   return values as datetime objects rather than strings
600        Example:
601            none
602        """
603        from time import strptime
604        from datetime import datetime
605        times = self._get_column(self._gettime, row)
606        if not asdatetime:
607            return times
608        format = "%Y/%m/%d/%H:%M:%S"
609        if isinstance(times, list):
610            return [datetime(*strptime(i, format)[:6]) for i in times]
611        else:
612            return datetime(*strptime(times, format)[:6])
613
614
615    def get_inttime(self, row=-1):
616        """
617        Get a list of integration times for the observations.
618        Return a time in seconds for each integration in the scantable.
619        Parameters:
620            row:    row no of integration. Default -1 return all rows.
621        Example:
622            none
623        """
624        return self._get_column(self._getinttime, row)       
625       
626
627    def get_sourcename(self, row=-1):
628        """
629        Get a list source names for the observations.
630        Return a string for each integration in the scantable.
631        Parameters:
632            row:    row no of integration. Default -1 return all rows.
633        Example:
634            none
635        """
636        return self._get_column(self._getsourcename, row)
637
638    def get_elevation(self, row=-1):
639        """
640        Get a list of elevations for the observations.
641        Return a float for each integration in the scantable.
642        Parameters:
643            row:    row no of integration. Default -1 return all rows.
644        Example:
645            none
646        """
647        return self._get_column(self._getelevation, row)
648
649    def get_azimuth(self, row=-1):
650        """
651        Get a list of azimuths for the observations.
652        Return a float for each integration in the scantable.
653        Parameters:
654            row:    row no of integration. Default -1 return all rows.
655        Example:
656            none
657        """
658        return self._get_column(self._getazimuth, row)
659
660    def get_parangle(self, row=-1):
661        """
662        Get a list of parallactic angles for the observations.
663        Return a float for each integration in the scantable.
664        Parameters:
665            row:    row no of integration. Default -1 return all rows.
666        Example:
667            none
668        """
669        return self._get_column(self._getparangle, row)
670
671    def get_direction(self, row=-1):
672        """
673        Get a list of Positions on the sky (direction) for the observations.
674        Return a float for each integration in the scantable.
675        Parameters:
676            row:    row no of integration. Default -1 return all rows
677        Example:
678            none
679        """
680        return self._get_column(self._getdirection, row)
681
682    def get_directionval(self, row=-1):
683        """
684        Get a list of Positions on the sky (direction) for the observations.
685        Return a float for each integration in the scantable.
686        Parameters:
687            row:    row no of integration. Default -1 return all rows
688        Example:
689            none
690        """
691        return self._get_column(self._getdirectionvec, row)
692
693    def set_unit(self, unit='channel'):
694        """
695        Set the unit for all following operations on this scantable
696        Parameters:
697            unit:    optional unit, default is 'channel'
698                     one of '*Hz', 'km/s', 'channel', ''
699        """
700        varlist = vars()
701        if unit in ['', 'pixel', 'channel']:
702            unit = ''
703        inf = list(self._getcoordinfo())
704        inf[0] = unit
705        self._setcoordinfo(inf)
706        self._add_history("set_unit", varlist)
707
708    def set_instrument(self, instr):
709        """
710        Set the instrument for subsequent processing.
711        Parameters:
712            instr:    Select from 'ATPKSMB', 'ATPKSHOH', 'ATMOPRA',
713                      'DSS-43' (Tid), 'CEDUNA', and 'HOBART'
714        """
715        self._setInstrument(instr)
716        self._add_history("set_instument", vars())
717        print_log()
718
719    def set_feedtype(self, feedtype):
720        """
721        Overwrite the feed type, which might not be set correctly.
722        Parameters:
723            feedtype:     'linear' or 'circular'
724        """
725        self._setfeedtype(feedtype)
726        self._add_history("set_feedtype", vars())
727        print_log()
728
729    def set_doppler(self, doppler='RADIO'):
730        """
731        Set the doppler for all following operations on this scantable.
732        Parameters:
733            doppler:    One of 'RADIO', 'OPTICAL', 'Z', 'BETA', 'GAMMA'
734        """
735        varlist = vars()
736        inf = list(self._getcoordinfo())
737        inf[2] = doppler
738        self._setcoordinfo(inf)
739        self._add_history("set_doppler", vars())
740        print_log()
741
742    def set_freqframe(self, frame=None):
743        """
744        Set the frame type of the Spectral Axis.
745        Parameters:
746            frame:   an optional frame type, default 'LSRK'. Valid frames are:
747                     'REST', 'TOPO', 'LSRD', 'LSRK', 'BARY',
748                     'GEO', 'GALACTO', 'LGROUP', 'CMB'
749        Examples:
750            scan.set_freqframe('BARY')
751        """
752        if frame is None: frame = rcParams['scantable.freqframe']
753        varlist = vars()
754        valid = ['REST', 'TOPO', 'LSRD', 'LSRK', 'BARY', \
755                   'GEO', 'GALACTO', 'LGROUP', 'CMB']
756
757        if frame in valid:
758            inf = list(self._getcoordinfo())
759            inf[1] = frame
760            self._setcoordinfo(inf)
761            self._add_history("set_freqframe", varlist)
762        else:
763            msg  = "Please specify a valid freq type. Valid types are:\n", valid
764            if rcParams['verbose']:
765                #print msg
766                asaplog.push( msg )
767                print_log( 'ERROR' )
768            else:
769                raise TypeError(msg)
770        print_log()
771
772    def set_dirframe(self, frame=""):
773        """
774        Set the frame type of the Direction on the sky.
775        Parameters:
776            frame:   an optional frame type, default ''. Valid frames are:
777                     'J2000', 'B1950', 'GALACTIC'
778        Examples:
779            scan.set_dirframe('GALACTIC')
780        """
781        varlist = vars()
782        try:
783            Scantable.set_dirframe(self, frame)
784        except RuntimeError, msg:
785            if rcParams['verbose']:
786                #print msg
787                print_log()
788                asaplog.push( str(msg) )
789                print_log( 'ERROR' )
790            else:
791                raise
792        self._add_history("set_dirframe", varlist)
793
794    def get_unit(self):
795        """
796        Get the default unit set in this scantable
797        Returns:
798            A unit string
799        """
800        inf = self._getcoordinfo()
801        unit = inf[0]
802        if unit == '': unit = 'channel'
803        return unit
804
805    def get_abcissa(self, rowno=0):
806        """
807        Get the abcissa in the current coordinate setup for the currently
808        selected Beam/IF/Pol
809        Parameters:
810            rowno:    an optional row number in the scantable. Default is the
811                      first row, i.e. rowno=0
812        Returns:
813            The abcissa values and the format string (as a dictionary)
814        """
815        abc = self._getabcissa(rowno)
816        lbl = self._getabcissalabel(rowno)
817        print_log()
818        return abc, lbl
819
820    def flag(self, mask=None, unflag=False):
821        """
822        Flag the selected data using an optional channel mask.
823        Parameters:
824            mask:   an optional channel mask, created with create_mask. Default
825                    (no mask) is all channels.
826            unflag:    if True, unflag the data
827        """
828        varlist = vars()
829        if mask is None:
830            mask = []
831        try:
832            self._flag(mask, unflag)
833        except RuntimeError, msg:
834            if rcParams['verbose']:
835                #print msg
836                print_log()
837                asaplog.push( str(msg) )
838                print_log( 'ERROR' )
839                return
840            else: raise
841        self._add_history("flag", varlist)
842
843    def flag_row(self, rows=[], unflag=False):
844        """
845        Flag the selected data in row-based manner.
846        Parameters:
847            rows:   list of row numbers to be flagged. Default is no row (must be explicitly specified to execute row-based flagging).
848            unflag: if True, unflag the data.
849        """
850        varlist = vars()
851        try:
852            self._flag_row(rows, unflag)
853        except RuntimeError, msg:
854            if rcParams['verbose']:
855                print_log()
856                asaplog.push( str(msg) )
857                print_log('ERROR')
858                return
859            else: raise
860        self._add_history("flag_row", varlist)
861       
862       
863    def lag_flag(self, frequency, width=0.0, unit="GHz", insitu=None):
864        """
865        Flag the data in 'lag' space by providing a frequency to remove.
866        Flagged data in the scantable gets set to 0.0 before the fft.
867        No taper is applied.
868        Parameters:
869            frequency:    the frequency (really a period within the bandwidth)
870                          to remove
871            width:        the width of the frequency to remove, to remove a
872                          range of frequencies around the centre.
873            unit:         the frequency unit (default "GHz")
874        Notes:
875            It is recommended to flag edges of the band or strong
876            signals beforehand.
877        """
878        if insitu is None: insitu = rcParams['insitu']
879        self._math._setinsitu(insitu)
880        varlist = vars()
881        base = { "GHz": 1000000000., "MHz": 1000000., "kHz": 1000., "Hz": 1. }
882        if not base.has_key(unit):
883            raise ValueError("%s is not a valid unit." % unit)
884        try:
885            s = scantable(self._math._lag_flag(self, frequency*base[unit],
886                                               width*base[unit]))
887        except RuntimeError, msg:
888            if rcParams['verbose']:
889                #print msg
890                print_log()
891                asaplog.push( str(msg) )
892                print_log( 'ERROR' )
893                return
894            else: raise
895        s._add_history("lag_flag", varlist)
896        print_log()
897        if insitu:
898            self._assign(s)
899        else:
900            return s
901
902
903    def create_mask(self, *args, **kwargs):
904        """
905        Compute and return a mask based on [min, max] windows.
906        The specified windows are to be INCLUDED, when the mask is
907        applied.
908        Parameters:
909            [min, max], [min2, max2], ...
910                Pairs of start/end points (inclusive)specifying the regions
911                to be masked
912            invert:     optional argument. If specified as True,
913                        return an inverted mask, i.e. the regions
914                        specified are EXCLUDED
915            row:        create the mask using the specified row for
916                        unit conversions, default is row=0
917                        only necessary if frequency varies over rows.
918        Example:
919            scan.set_unit('channel')
920            a)
921            msk = scan.create_mask([400, 500], [800, 900])
922            # masks everything outside 400 and 500
923            # and 800 and 900 in the unit 'channel'
924
925            b)
926            msk = scan.create_mask([400, 500], [800, 900], invert=True)
927            # masks the regions between 400 and 500
928            # and 800 and 900 in the unit 'channel'
929            c)
930            mask only channel 400
931            msk =  scan.create_mask([400, 400])
932        """
933        row = 0
934        if kwargs.has_key("row"):
935            row = kwargs.get("row")
936        data = self._getabcissa(row)
937        u = self._getcoordinfo()[0]
938        if rcParams['verbose']:
939            if u == "": u = "channel"
940            msg = "The current mask window unit is %s" % u
941            i = self._check_ifs()
942            if not i:
943                msg += "\nThis mask is only valid for IF=%d" % (self.getif(i))
944            asaplog.push(msg)
945        n = self.nchan()
946        msk = _n_bools(n, False)
947        # test if args is a 'list' or a 'normal *args - UGLY!!!
948
949        ws = (isinstance(args[-1][-1], int) or isinstance(args[-1][-1], float)) \
950             and args or args[0]
951        for window in ws:
952            if (len(window) != 2 or window[0] > window[1] ):
953                raise TypeError("A window needs to be defined as [min, max]")
954            for i in range(n):
955                if data[i] >= window[0] and data[i] <= window[1]:
956                    msk[i] = True
957        if kwargs.has_key('invert'):
958            if kwargs.get('invert'):
959                msk = mask_not(msk)
960        print_log()
961        return msk
962
963    def get_masklist(self, mask=None, row=0):
964        """
965        Compute and return a list of mask windows, [min, max].
966        Parameters:
967            mask:       channel mask, created with create_mask.
968            row:        calcutate the masklist using the specified row
969                        for unit conversions, default is row=0
970                        only necessary if frequency varies over rows.
971        Returns:
972            [min, max], [min2, max2], ...
973                Pairs of start/end points (inclusive)specifying
974                the masked regions
975        """
976        if not (isinstance(mask,list) or isinstance(mask, tuple)):
977            raise TypeError("The mask should be list or tuple.")
978        if len(mask) < 2:
979            raise TypeError("The mask elements should be > 1")
980        if self.nchan() != len(mask):
981            msg = "Number of channels in scantable != number of mask elements"
982            raise TypeError(msg)
983        data = self._getabcissa(row)
984        u = self._getcoordinfo()[0]
985        if rcParams['verbose']:
986            if u == "": u = "channel"
987            msg = "The current mask window unit is %s" % u
988            i = self._check_ifs()
989            if not i:
990                msg += "\nThis mask is only valid for IF=%d" % (self.getif(i))
991            asaplog.push(msg)
992        masklist=[]
993        ist, ien = None, None
994        ist, ien=self.get_mask_indices(mask)
995        if ist is not None and ien is not None:
996            for i in xrange(len(ist)):
997                range=[data[ist[i]],data[ien[i]]]
998                range.sort()
999                masklist.append([range[0],range[1]])
1000        return masklist
1001
1002    def get_mask_indices(self, mask=None):
1003        """
1004        Compute and Return lists of mask start indices and mask end indices.
1005         Parameters:
1006            mask:       channel mask, created with create_mask.
1007        Returns:
1008            List of mask start indices and that of mask end indices,
1009            i.e., [istart1,istart2,....], [iend1,iend2,....].
1010        """
1011        if not (isinstance(mask,list) or isinstance(mask, tuple)):
1012            raise TypeError("The mask should be list or tuple.")
1013        if len(mask) < 2:
1014            raise TypeError("The mask elements should be > 1")
1015        istart=[]
1016        iend=[]
1017        if mask[0]: istart.append(0)
1018        for i in range(len(mask)-1):
1019            if not mask[i] and mask[i+1]:
1020                istart.append(i+1)
1021            elif mask[i] and not mask[i+1]:
1022                iend.append(i)
1023        if mask[len(mask)-1]: iend.append(len(mask)-1)
1024        if len(istart) != len(iend):
1025            raise RuntimeError("Numbers of mask start != mask end.")
1026        for i in range(len(istart)):
1027            if istart[i] > iend[i]:
1028                raise RuntimeError("Mask start index > mask end index")
1029                break
1030        return istart,iend
1031
1032#    def get_restfreqs(self):
1033#        """
1034#        Get the restfrequency(s) stored in this scantable.
1035#        The return value(s) are always of unit 'Hz'
1036#        Parameters:
1037#            none
1038#        Returns:
1039#            a list of doubles
1040#        """
1041#        return list(self._getrestfreqs())
1042
1043    def get_restfreqs(self, ids=None):
1044        """
1045        Get the restfrequency(s) stored in this scantable.
1046        The return value(s) are always of unit 'Hz'
1047        Parameters:
1048            ids: (optional) a list of MOLECULE_ID for that restfrequency(s) to
1049                 be retrieved
1050        Returns:
1051            dictionary containing ids and a list of doubles for each id
1052        """
1053        if ids is None:
1054            rfreqs={}
1055            idlist = self.getmolnos()
1056            for i in idlist:
1057                rfreqs[i]=list(self._getrestfreqs(i))
1058            return rfreqs
1059        else:
1060            if type(ids)==list or type(ids)==tuple:
1061                rfreqs={}
1062                for i in ids:
1063                    rfreqs[i]=list(self._getrestfreqs(i))
1064                return rfreqs
1065            else:
1066                return list(self._getrestfreqs(ids))
1067            #return list(self._getrestfreqs(ids))
1068
1069    def set_restfreqs(self, freqs=None, unit='Hz'):
1070        """
1071        ********NEED TO BE UPDATED begin************
1072        Set or replace the restfrequency specified and
1073        If the 'freqs' argument holds a scalar,
1074        then that rest frequency will be applied to all the selected
1075        data.  If the 'freqs' argument holds
1076        a vector, then it MUST be of equal or smaller length than
1077        the number of IFs (and the available restfrequencies will be
1078        replaced by this vector).  In this case, *all* data have
1079        the restfrequency set per IF according
1080        to the corresponding value you give in the 'freqs' vector.
1081        E.g. 'freqs=[1e9, 2e9]'  would mean IF 0 gets restfreq 1e9 and
1082        IF 1 gets restfreq 2e9.
1083        ********NEED TO BE UPDATED end************
1084        You can also specify the frequencies via a linecatalog.
1085
1086        Parameters:
1087            freqs:   list of rest frequency values or string idenitfiers
1088            unit:    unit for rest frequency (default 'Hz')
1089
1090        Example:
1091            # set the given restfrequency for the all currently selected IFs
1092            scan.set_restfreqs(freqs=1.4e9)
1093            # set multiple restfrequencies to all the selected data
1094            scan.set_restfreqs(freqs=[1.4e9, 1.41e9, 1.42e9])
1095            # If the number of IFs in the data is >= 2 the IF0 gets the first
1096            # value IF1 the second... NOTE that freqs needs to be
1097            # specified in list of list (e.g. [[],[],...] ).
1098            scan.set_restfreqs(freqs=[[1.4e9],[1.67e9]])
1099            #set the given restfrequency for the whole table (by name)
1100            scan.set_restfreqs(freqs="OH1667")
1101
1102        Note:
1103            To do more sophisticate Restfrequency setting, e.g. on a
1104            source and IF basis, use scantable.set_selection() before using
1105            this function.
1106            # provide your scantable is call scan
1107            selection = selector()
1108            selection.set_name("ORION*")
1109            selection.set_ifs([1])
1110            scan.set_selection(selection)
1111            scan.set_restfreqs(freqs=86.6e9)
1112
1113        """
1114        varlist = vars()
1115        from asap import linecatalog
1116        # simple  value
1117        if isinstance(freqs, int) or isinstance(freqs, float):
1118            # TT mod
1119            #self._setrestfreqs(freqs, "",unit)
1120            self._setrestfreqs([freqs], [""],unit)
1121        # list of values
1122        elif isinstance(freqs, list) or isinstance(freqs, tuple):
1123            # list values are scalars
1124            if isinstance(freqs[-1], int) or isinstance(freqs[-1], float):
1125                self._setrestfreqs(freqs, [""],unit)
1126            # list values are tuples, (value, name)
1127            elif isinstance(freqs[-1], dict):
1128                #sel = selector()
1129                #savesel = self._getselection()
1130                #iflist = self.getifnos()
1131                #for i in xrange(len(freqs)):
1132                #    sel.set_ifs(iflist[i])
1133                #    self._setselection(sel)
1134                #    self._setrestfreqs(freqs[i], "",unit)
1135                #self._setselection(savesel)
1136                self._setrestfreqs(freqs["value"],
1137                                   freqs["name"], "MHz")
1138            elif isinstance(freqs[-1], list) or isinstance(freqs[-1], tuple):
1139                sel = selector()
1140                savesel = self._getselection()
1141                iflist = self.getifnos()
1142                if len(freqs)>len(iflist):
1143                    raise ValueError("number of elements in list of list exeeds the current IF selections")
1144                for i in xrange(len(freqs)):
1145                    sel.set_ifs(iflist[i])
1146                    self._setselection(sel)
1147                    self._setrestfreqs(freqs[i]["value"],
1148                                       freqs[i]["name"], "MHz")
1149                self._setselection(savesel)
1150        # freqs are to be taken from a linecatalog
1151        elif isinstance(freqs, linecatalog):
1152            sel = selector()
1153            savesel = self._getselection()
1154            for i in xrange(freqs.nrow()):
1155                sel.set_ifs(iflist[i])
1156                self._setselection(sel)
1157                self._setrestfreqs(freqs.get_frequency(i),
1158                                   freqs.get_name(i), "MHz")
1159                # ensure that we are not iterating past nIF
1160                if i == self.nif()-1: break
1161            self._setselection(savesel)
1162        else:
1163            return
1164        self._add_history("set_restfreqs", varlist)
1165
1166    def shift_refpix(self, delta):
1167        """
1168        Shift the reference pixel of the Spectra Coordinate by an
1169        integer amount.
1170        Parameters:
1171            delta:   the amount to shift by
1172        Note:
1173            Be careful using this with broadband data.
1174        """
1175        Scantable.shift(self, delta)
1176
1177    def history(self, filename=None):
1178        """
1179        Print the history. Optionally to a file.
1180        Parameters:
1181            filename:    The name  of the file to save the history to.
1182        """
1183        hist = list(self._gethistory())
1184        out = "-"*80
1185        for h in hist:
1186            if h.startswith("---"):
1187                out += "\n"+h
1188            else:
1189                items = h.split("##")
1190                date = items[0]
1191                func = items[1]
1192                items = items[2:]
1193                out += "\n"+date+"\n"
1194                out += "Function: %s\n  Parameters:" % (func)
1195                for i in items:
1196                    s = i.split("=")
1197                    out += "\n   %s = %s" % (s[0], s[1])
1198                out += "\n"+"-"*80
1199        if filename is not None:
1200            if filename is "":
1201                filename = 'scantable_history.txt'
1202            import os
1203            filename = os.path.expandvars(os.path.expanduser(filename))
1204            if not os.path.isdir(filename):
1205                data = open(filename, 'w')
1206                data.write(out)
1207                data.close()
1208            else:
1209                msg = "Illegal file name '%s'." % (filename)
1210                if rcParams['verbose']:
1211                    #print msg
1212                    asaplog.push( msg )
1213                    print_log( 'ERROR' )
1214                else:
1215                    raise IOError(msg)
1216        if rcParams['verbose']:
1217            try:
1218                from IPython.genutils import page as pager
1219            except ImportError:
1220                from pydoc import pager
1221            pager(out)
1222        else:
1223            return out
1224        return
1225    #
1226    # Maths business
1227    #
1228
1229    def average_time(self, mask=None, scanav=False, weight='tint', align=False):
1230        """
1231        Return the (time) weighted average of a scan.
1232        Note:
1233            in channels only - align if necessary
1234        Parameters:
1235            mask:     an optional mask (only used for 'var' and 'tsys'
1236                      weighting)
1237            scanav:   True averages each scan separately
1238                      False (default) averages all scans together,
1239            weight:   Weighting scheme.
1240                      'none'     (mean no weight)
1241                      'var'      (1/var(spec) weighted)
1242                      'tsys'     (1/Tsys**2 weighted)
1243                      'tint'     (integration time weighted)
1244                      'tintsys'  (Tint/Tsys**2)
1245                      'median'   ( median averaging)
1246                      The default is 'tint'
1247            align:    align the spectra in velocity before averaging. It takes
1248                      the time of the first spectrum as reference time.
1249        Example:
1250            # time average the scantable without using a mask
1251            newscan = scan.average_time()
1252        """
1253        varlist = vars()
1254        if weight is None: weight = 'TINT'
1255        if mask is None: mask = ()
1256        if scanav: scanav = "SCAN"
1257        else: scanav = "NONE"
1258        scan = (self, )
1259        try:
1260            if align:
1261                scan = (self.freq_align(insitu=False), )
1262            s = None
1263            if weight.upper() == 'MEDIAN':
1264                s = scantable(self._math._averagechannel(scan[0], 'MEDIAN',
1265                                                         scanav))
1266            else:
1267                s = scantable(self._math._average(scan, mask, weight.upper(),
1268                              scanav))
1269        except RuntimeError, msg:
1270            if rcParams['verbose']:
1271                #print msg
1272                print_log()
1273                asaplog.push( str(msg) )
1274                print_log( 'ERROR' )
1275                return
1276            else: raise
1277        s._add_history("average_time", varlist)
1278        print_log()
1279        return s
1280
1281    def convert_flux(self, jyperk=None, eta=None, d=None, insitu=None):
1282        """
1283        Return a scan where all spectra are converted to either
1284        Jansky or Kelvin depending upon the flux units of the scan table.
1285        By default the function tries to look the values up internally.
1286        If it can't find them (or if you want to over-ride), you must
1287        specify EITHER jyperk OR eta (and D which it will try to look up
1288        also if you don't set it). jyperk takes precedence if you set both.
1289        Parameters:
1290            jyperk:      the Jy / K conversion factor
1291            eta:         the aperture efficiency
1292            d:           the geomtric diameter (metres)
1293            insitu:      if False a new scantable is returned.
1294                         Otherwise, the scaling is done in-situ
1295                         The default is taken from .asaprc (False)
1296        """
1297        if insitu is None: insitu = rcParams['insitu']
1298        self._math._setinsitu(insitu)
1299        varlist = vars()
1300        if jyperk is None: jyperk = -1.0
1301        if d is None: d = -1.0
1302        if eta is None: eta = -1.0
1303        s = scantable(self._math._convertflux(self, d, eta, jyperk))
1304        s._add_history("convert_flux", varlist)
1305        print_log()
1306        if insitu: self._assign(s)
1307        else: return s
1308
1309    def gain_el(self, poly=None, filename="", method="linear", insitu=None):
1310        """
1311        Return a scan after applying a gain-elevation correction.
1312        The correction can be made via either a polynomial or a
1313        table-based interpolation (and extrapolation if necessary).
1314        You specify polynomial coefficients, an ascii table or neither.
1315        If you specify neither, then a polynomial correction will be made
1316        with built in coefficients known for certain telescopes (an error
1317        will occur if the instrument is not known).
1318        The data and Tsys are *divided* by the scaling factors.
1319        Parameters:
1320            poly:        Polynomial coefficients (default None) to compute a
1321                         gain-elevation correction as a function of
1322                         elevation (in degrees).
1323            filename:    The name of an ascii file holding correction factors.
1324                         The first row of the ascii file must give the column
1325                         names and these MUST include columns
1326                         "ELEVATION" (degrees) and "FACTOR" (multiply data
1327                         by this) somewhere.
1328                         The second row must give the data type of the
1329                         column. Use 'R' for Real and 'I' for Integer.
1330                         An example file would be
1331                         (actual factors are arbitrary) :
1332
1333                         TIME ELEVATION FACTOR
1334                         R R R
1335                         0.1 0 0.8
1336                         0.2 20 0.85
1337                         0.3 40 0.9
1338                         0.4 60 0.85
1339                         0.5 80 0.8
1340                         0.6 90 0.75
1341            method:      Interpolation method when correcting from a table.
1342                         Values are  "nearest", "linear" (default), "cubic"
1343                         and "spline"
1344            insitu:      if False a new scantable is returned.
1345                         Otherwise, the scaling is done in-situ
1346                         The default is taken from .asaprc (False)
1347        """
1348
1349        if insitu is None: insitu = rcParams['insitu']
1350        self._math._setinsitu(insitu)
1351        varlist = vars()
1352        if poly is None:
1353            poly = ()
1354        from os.path import expandvars
1355        filename = expandvars(filename)
1356        s = scantable(self._math._gainel(self, poly, filename, method))
1357        s._add_history("gain_el", varlist)
1358        print_log()
1359        if insitu: self._assign(s)
1360        else: return s
1361
1362    def freq_align(self, reftime=None, method='cubic', insitu=None):
1363        """
1364        Return a scan where all rows have been aligned in frequency/velocity.
1365        The alignment frequency frame (e.g. LSRK) is that set by function
1366        set_freqframe.
1367        Parameters:
1368            reftime:     reference time to align at. By default, the time of
1369                         the first row of data is used.
1370            method:      Interpolation method for regridding the spectra.
1371                         Choose from "nearest", "linear", "cubic" (default)
1372                         and "spline"
1373            insitu:      if False a new scantable is returned.
1374                         Otherwise, the scaling is done in-situ
1375                         The default is taken from .asaprc (False)
1376        """
1377        if insitu is None: insitu = rcParams["insitu"]
1378        self._math._setinsitu(insitu)
1379        varlist = vars()
1380        if reftime is None: reftime = ""
1381        s = scantable(self._math._freq_align(self, reftime, method))
1382        s._add_history("freq_align", varlist)
1383        print_log()
1384        if insitu: self._assign(s)
1385        else: return s
1386
1387    def opacity(self, tau, insitu=None):
1388        """
1389        Apply an opacity correction. The data
1390        and Tsys are multiplied by the correction factor.
1391        Parameters:
1392            tau:         Opacity from which the correction factor is
1393                         exp(tau*ZD)
1394                         where ZD is the zenith-distance
1395            insitu:      if False a new scantable is returned.
1396                         Otherwise, the scaling is done in-situ
1397                         The default is taken from .asaprc (False)
1398        """
1399        if insitu is None: insitu = rcParams['insitu']
1400        self._math._setinsitu(insitu)
1401        varlist = vars()
1402        s = scantable(self._math._opacity(self, tau))
1403        s._add_history("opacity", varlist)
1404        print_log()
1405        if insitu: self._assign(s)
1406        else: return s
1407
1408    def bin(self, width=5, insitu=None):
1409        """
1410        Return a scan where all spectra have been binned up.
1411        Parameters:
1412            width:       The bin width (default=5) in pixels
1413            insitu:      if False a new scantable is returned.
1414                         Otherwise, the scaling is done in-situ
1415                         The default is taken from .asaprc (False)
1416        """
1417        if insitu is None: insitu = rcParams['insitu']
1418        self._math._setinsitu(insitu)
1419        varlist = vars()
1420        s = scantable(self._math._bin(self, width))
1421        s._add_history("bin", varlist)
1422        print_log()
1423        if insitu: self._assign(s)
1424        else: return s
1425
1426
1427    def resample(self, width=5, method='cubic', insitu=None):
1428        """
1429        Return a scan where all spectra have been binned up.
1430       
1431        Parameters:
1432            width:       The bin width (default=5) in pixels
1433            method:      Interpolation method when correcting from a table.
1434                         Values are  "nearest", "linear", "cubic" (default)
1435                         and "spline"
1436            insitu:      if False a new scantable is returned.
1437                         Otherwise, the scaling is done in-situ
1438                         The default is taken from .asaprc (False)
1439        """
1440        if insitu is None: insitu = rcParams['insitu']
1441        self._math._setinsitu(insitu)
1442        varlist = vars()
1443        s = scantable(self._math._resample(self, method, width))
1444        s._add_history("resample", varlist)
1445        print_log()
1446        if insitu: self._assign(s)
1447        else: return s
1448
1449
1450    def average_pol(self, mask=None, weight='none'):
1451        """
1452        Average the Polarisations together.
1453        Parameters:
1454            mask:        An optional mask defining the region, where the
1455                         averaging will be applied. The output will have all
1456                         specified points masked.
1457            weight:      Weighting scheme. 'none' (default), 'var' (1/var(spec)
1458                         weighted), or 'tsys' (1/Tsys**2 weighted)
1459        """
1460        varlist = vars()
1461        if mask is None:
1462            mask = ()
1463        s = scantable(self._math._averagepol(self, mask, weight.upper()))
1464        s._add_history("average_pol", varlist)
1465        print_log()
1466        return s
1467
1468    def average_beam(self, mask=None, weight='none'):
1469        """
1470        Average the Beams together.
1471        Parameters:
1472            mask:        An optional mask defining the region, where the
1473                         averaging will be applied. The output will have all
1474                         specified points masked.
1475            weight:      Weighting scheme. 'none' (default), 'var' (1/var(spec)
1476                         weighted), or 'tsys' (1/Tsys**2 weighted)
1477        """
1478        varlist = vars()
1479        if mask is None:
1480            mask = ()
1481        s = scantable(self._math._averagebeams(self, mask, weight.upper()))
1482        s._add_history("average_beam", varlist)
1483        print_log()
1484        return s
1485
1486    def convert_pol(self, poltype=None):
1487        """
1488        Convert the data to a different polarisation type.
1489        Parameters:
1490            poltype:    The new polarisation type. Valid types are:
1491                        "linear", "stokes" and "circular"
1492        """
1493        varlist = vars()
1494        try:
1495            s = scantable(self._math._convertpol(self, poltype))
1496        except RuntimeError, msg:
1497            if rcParams['verbose']:
1498                #print msg
1499                print_log()
1500                asaplog.push( str(msg) )
1501                print_log( 'ERROR' )
1502                return
1503            else:
1504                raise
1505        s._add_history("convert_pol", varlist)
1506        print_log()
1507        return s
1508
1509    #def smooth(self, kernel="hanning", width=5.0, insitu=None):
1510    def smooth(self, kernel="hanning", width=5.0, plot=False, insitu=None):
1511        """
1512        Smooth the spectrum by the specified kernel (conserving flux).
1513        Parameters:
1514            kernel:     The type of smoothing kernel. Select from
1515                        'hanning' (default), 'gaussian', 'boxcar' and
1516                        'rmedian'
1517            width:      The width of the kernel in pixels. For hanning this is
1518                        ignored otherwise it defauls to 5 pixels.
1519                        For 'gaussian' it is the Full Width Half
1520                        Maximum. For 'boxcar' it is the full width.
1521                        For 'rmedian' it is the half width.
1522            plot:       plot the original and the smoothed spectra.
1523                        In this each indivual fit has to be approved, by
1524                        typing 'y' or 'n'
1525            insitu:     if False a new scantable is returned.
1526                        Otherwise, the scaling is done in-situ
1527                        The default is taken from .asaprc (False)
1528        Example:
1529             none
1530        """
1531        if insitu is None: insitu = rcParams['insitu']
1532        self._math._setinsitu(insitu)
1533        varlist = vars()
1534
1535        if plot: orgscan = self.copy()
1536
1537        s = scantable(self._math._smooth(self, kernel.lower(), width))
1538        s._add_history("smooth", varlist)
1539
1540        if plot:
1541            if rcParams['plotter.gui']:
1542                from asap.asaplotgui import asaplotgui as asaplot
1543            else:
1544                from asap.asaplot import asaplot
1545            self._p=asaplot()
1546            self._p.set_panels()
1547            ylab=s._get_ordinate_label()
1548            #self._p.palette(0,["#777777","red"])
1549            for r in xrange(s.nrow()):
1550                xsm=s._getabcissa(r)
1551                ysm=s._getspectrum(r)
1552                xorg=orgscan._getabcissa(r)
1553                yorg=orgscan._getspectrum(r)
1554                self._p.clear()
1555                self._p.hold()
1556                self._p.set_axes('ylabel',ylab)
1557                self._p.set_axes('xlabel',s._getabcissalabel(r))
1558                self._p.set_axes('title',s._getsourcename(r))
1559                self._p.set_line(label='Original',color="#777777")
1560                self._p.plot(xorg,yorg)
1561                self._p.set_line(label='Smoothed',color="red")
1562                self._p.plot(xsm,ysm)
1563                ### Ugly part for legend
1564                for i in [0,1]:
1565                    self._p.subplots[0]['lines'].append([self._p.subplots[0]['axes'].lines[i]])
1566                self._p.release()
1567                ### Ugly part for legend
1568                self._p.subplots[0]['lines']=[]
1569                res = raw_input("Accept smoothing ([y]/n): ")
1570                if res.upper() == 'N':
1571                    s._setspectrum(yorg, r)
1572            self._p.unmap()
1573            self._p = None
1574            del orgscan
1575
1576        print_log()
1577        if insitu: self._assign(s)
1578        else: return s
1579
1580
1581    def poly_baseline(self, mask=None, order=0, plot=False, uselin=False, insitu=None):
1582        """
1583        Return a scan which has been baselined (all rows) by a polynomial.
1584        Parameters:
1585            mask:       an optional mask
1586            order:      the order of the polynomial (default is 0)
1587            plot:       plot the fit and the residual. In this each
1588                        indivual fit has to be approved, by typing 'y'
1589                        or 'n'
1590            uselin:     use linear polynomial fit
1591            insitu:     if False a new scantable is returned.
1592                        Otherwise, the scaling is done in-situ
1593                        The default is taken from .asaprc (False)
1594        Example:
1595            # return a scan baselined by a third order polynomial,
1596            # not using a mask
1597            bscan = scan.poly_baseline(order=3)
1598        """
1599        if insitu is None: insitu = rcParams['insitu']
1600        if not insitu:
1601            workscan = self.copy()
1602        else:
1603            workscan = self
1604        varlist = vars()
1605        if mask is None:
1606            mask = [True for i in xrange(self.nchan(-1))]
1607       
1608        from asap.asapfitter import fitter
1609        try:
1610            f = fitter()
1611            if uselin:
1612                f.set_function(lpoly=order)
1613            else:
1614                f.set_function(poly=order)
1615
1616            rows = range(workscan.nrow())
1617            if len(rows) > 0:
1618                self.blpars = []
1619           
1620            for r in rows:
1621                # take into account flagtra info (CAS-1434)
1622                flagtra = workscan._getmask(r)
1623                actualmask = mask[:]
1624                if len(actualmask) == 0:
1625                    actualmask = list(flagtra[:])
1626                else:
1627                    if len(actualmask) != len(flagtra):
1628                        raise RuntimeError, "Mask and flagtra have different length"
1629                    else:
1630                        for i in range(0, len(actualmask)):
1631                            actualmask[i] = actualmask[i] and flagtra[i]
1632                f.set_scan(workscan, actualmask)
1633                f.x = workscan._getabcissa(r)
1634                f.y = workscan._getspectrum(r)
1635                f.data = None
1636                f.fit()
1637                if plot:
1638                    f.plot(residual=True)
1639                    x = raw_input("Accept fit ( [y]/n ): ")
1640                    if x.upper() == 'N':
1641                        self.blpars.append(None)
1642                        continue
1643                workscan._setspectrum(f.fitter.getresidual(), r)
1644                self.blpars.append(f.get_parameters())
1645
1646            if plot:
1647                f._p.unmap()
1648                f._p = None
1649            workscan._add_history("poly_baseline", varlist)
1650            print_log()
1651            if insitu: self._assign(workscan)
1652            else: return workscan
1653        except RuntimeError:
1654            msg = "The fit failed, possibly because it didn't converge."
1655            if rcParams['verbose']:
1656                #print msg
1657                print_log()
1658                asaplog.push( str(msg) )
1659                print_log( 'ERROR' )
1660                return
1661            else:
1662                raise RuntimeError(msg)
1663
1664
1665    def auto_poly_baseline(self, mask=[], edge=(0, 0), order=0,
1666                           threshold=3, chan_avg_limit=1, plot=False,
1667                           insitu=None):
1668        """
1669        Return a scan which has been baselined (all rows) by a polynomial.
1670        Spectral lines are detected first using linefinder and masked out
1671        to avoid them affecting the baseline solution.
1672
1673        Parameters:
1674            mask:       an optional mask retreived from scantable
1675            edge:       an optional number of channel to drop at
1676                        the edge of spectrum. If only one value is
1677                        specified, the same number will be dropped from
1678                        both sides of the spectrum. Default is to keep
1679                        all channels. Nested tuples represent individual
1680                        edge selection for different IFs (a number of spectral
1681                        channels can be different)
1682            order:      the order of the polynomial (default is 0)
1683            threshold:  the threshold used by line finder. It is better to
1684                        keep it large as only strong lines affect the
1685                        baseline solution.
1686            chan_avg_limit:
1687                        a maximum number of consequtive spectral channels to
1688                        average during the search of weak and broad lines.
1689                        The default is no averaging (and no search for weak
1690                        lines). If such lines can affect the fitted baseline
1691                        (e.g. a high order polynomial is fitted), increase this
1692                        parameter (usually values up to 8 are reasonable). Most
1693                        users of this method should find the default value
1694                        sufficient.
1695            plot:       plot the fit and the residual. In this each
1696                        indivual fit has to be approved, by typing 'y'
1697                        or 'n'
1698            insitu:     if False a new scantable is returned.
1699                        Otherwise, the scaling is done in-situ
1700                        The default is taken from .asaprc (False)
1701
1702        Example:
1703            scan2=scan.auto_poly_baseline(order=7)
1704        """
1705        if insitu is None: insitu = rcParams['insitu']
1706        varlist = vars()
1707        from asap.asapfitter import fitter
1708        from asap.asaplinefind import linefinder
1709        from asap import _is_sequence_or_number as _is_valid
1710
1711        # check whether edge is set up for each IF individually
1712        individualedge = False;
1713        if len(edge) > 1:
1714            if isinstance(edge[0], list) or isinstance(edge[0], tuple):
1715                individualedge = True;
1716
1717        if not _is_valid(edge, int) and not individualedge:
1718            raise ValueError, "Parameter 'edge' has to be an integer or a \
1719            pair of integers specified as a tuple. Nested tuples are allowed \
1720            to make individual selection for different IFs."
1721
1722        curedge = (0, 0)
1723        if individualedge:
1724            for edgepar in edge:
1725                if not _is_valid(edgepar, int):
1726                    raise ValueError, "Each element of the 'edge' tuple has \
1727                                       to be a pair of integers or an integer."
1728        else:
1729            curedge = edge;
1730
1731        # setup fitter
1732        f = fitter()
1733        f.set_function(poly=order)
1734
1735        # setup line finder
1736        fl = linefinder()
1737        fl.set_options(threshold=threshold,avg_limit=chan_avg_limit)
1738
1739        if not insitu:
1740            workscan = self.copy()
1741        else:
1742            workscan = self
1743
1744        fl.set_scan(workscan)
1745
1746        rows = range(workscan.nrow())
1747        # Save parameters of baseline fits & masklists as a class attribute.
1748        # NOTICE: It does not reflect changes in scantable!
1749        if len(rows) > 0:
1750            self.blpars=[]
1751            self.masklists=[]
1752        asaplog.push("Processing:")
1753        for r in rows:
1754            msg = " Scan[%d] Beam[%d] IF[%d] Pol[%d] Cycle[%d]" % \
1755                (workscan.getscan(r), workscan.getbeam(r), workscan.getif(r), \
1756                 workscan.getpol(r), workscan.getcycle(r))
1757            asaplog.push(msg, False)
1758
1759            # figure out edge parameter
1760            if individualedge:
1761                if len(edge) >= workscan.getif(r):
1762                    raise RuntimeError, "Number of edge elements appear to " \
1763                                        "be less than the number of IFs"
1764                    curedge = edge[workscan.getif(r)]
1765
1766            # take into account flagtra info (CAS-1434)
1767            flagtra = workscan._getmask(r)
1768            actualmask = mask[:]
1769            if len(actualmask) == 0:
1770                actualmask = list(flagtra[:])
1771            else:
1772                if len(actualmask) != len(flagtra):
1773                    raise RuntimeError, "Mask and flagtra have different length"
1774                else:
1775                    for i in range(0, len(actualmask)):
1776                        actualmask[i] = actualmask[i] and flagtra[i]
1777
1778            # setup line finder
1779            fl.find_lines(r, actualmask, curedge)
1780            outmask=fl.get_mask()
1781            f.set_scan(workscan, fl.get_mask())
1782            f.x = workscan._getabcissa(r)
1783            f.y = workscan._getspectrum(r)
1784            f.data = None
1785            f.fit()
1786           
1787            # Show mask list
1788            masklist=workscan.get_masklist(fl.get_mask(),row=r)
1789            msg = "mask range: "+str(masklist)
1790            asaplog.push(msg, False)
1791
1792            if plot:
1793                f.plot(residual=True)
1794                x = raw_input("Accept fit ( [y]/n ): ")
1795                if x.upper() == 'N':
1796                    self.blpars.append(None)
1797                    self.masklists.append(None)
1798                    continue
1799
1800            workscan._setspectrum(f.fitter.getresidual(), r)
1801            self.blpars.append(f.get_parameters())
1802            self.masklists.append(masklist)
1803        if plot:
1804            f._p.unmap()
1805            f._p = None
1806        workscan._add_history("auto_poly_baseline", varlist)
1807        if insitu:
1808            self._assign(workscan)
1809        else:
1810            return workscan
1811
1812    def rotate_linpolphase(self, angle):
1813        """
1814        Rotate the phase of the complex polarization O=Q+iU correlation.
1815        This is always done in situ in the raw data.  So if you call this
1816        function more than once then each call rotates the phase further.
1817        Parameters:
1818            angle:   The angle (degrees) to rotate (add) by.
1819        Examples:
1820            scan.rotate_linpolphase(2.3)
1821        """
1822        varlist = vars()
1823        self._math._rotate_linpolphase(self, angle)
1824        self._add_history("rotate_linpolphase", varlist)
1825        print_log()
1826        return
1827
1828
1829    def rotate_xyphase(self, angle):
1830        """
1831        Rotate the phase of the XY correlation.  This is always done in situ
1832        in the data.  So if you call this function more than once
1833        then each call rotates the phase further.
1834        Parameters:
1835            angle:   The angle (degrees) to rotate (add) by.
1836        Examples:
1837            scan.rotate_xyphase(2.3)
1838        """
1839        varlist = vars()
1840        self._math._rotate_xyphase(self, angle)
1841        self._add_history("rotate_xyphase", varlist)
1842        print_log()
1843        return
1844
1845    def swap_linears(self):
1846        """
1847        Swap the linear polarisations XX and YY, or better the first two
1848        polarisations as this also works for ciculars.
1849        """
1850        varlist = vars()
1851        self._math._swap_linears(self)
1852        self._add_history("swap_linears", varlist)
1853        print_log()
1854        return
1855
1856    def invert_phase(self):
1857        """
1858        Invert the phase of the complex polarisation
1859        """
1860        varlist = vars()
1861        self._math._invert_phase(self)
1862        self._add_history("invert_phase", varlist)
1863        print_log()
1864        return
1865
1866    def add(self, offset, insitu=None):
1867        """
1868        Return a scan where all spectra have the offset added
1869        Parameters:
1870            offset:      the offset
1871            insitu:      if False a new scantable is returned.
1872                         Otherwise, the scaling is done in-situ
1873                         The default is taken from .asaprc (False)
1874        """
1875        if insitu is None: insitu = rcParams['insitu']
1876        self._math._setinsitu(insitu)
1877        varlist = vars()
1878        s = scantable(self._math._unaryop(self, offset, "ADD", False))
1879        s._add_history("add", varlist)
1880        print_log()
1881        if insitu:
1882            self._assign(s)
1883        else:
1884            return s
1885
1886    def scale(self, factor, tsys=True, insitu=None):
1887        """
1888        Return a scan where all spectra are scaled by the give 'factor'
1889        Parameters:
1890            factor:      the scaling factor (float or 1D float list)
1891            insitu:      if False a new scantable is returned.
1892                         Otherwise, the scaling is done in-situ
1893                         The default is taken from .asaprc (False)
1894            tsys:        if True (default) then apply the operation to Tsys
1895                         as well as the data
1896        """
1897        if insitu is None: insitu = rcParams['insitu']
1898        self._math._setinsitu(insitu)
1899        varlist = vars()
1900        s = None
1901        import numpy
1902        if isinstance(factor, list) or isinstance(factor, numpy.ndarray):
1903            if isinstance(factor[0], list) or isinstance(factor[0], numpy.ndarray):
1904                from asapmath import _array2dOp
1905                s = _array2dOp( self.copy(), factor, "MUL", tsys )
1906            else:
1907                s = scantable( self._math._arrayop( self.copy(), factor, "MUL", tsys ) )
1908        else:
1909            s = scantable(self._math._unaryop(self.copy(), factor, "MUL", tsys))
1910        s._add_history("scale", varlist)
1911        print_log()
1912        if insitu:
1913            self._assign(s)
1914        else:
1915            return s
1916
1917    def set_sourcetype(self, match, matchtype="pattern",
1918                       sourcetype="reference"):
1919        """
1920        Set the type of the source to be an source or reference scan
1921        using the provided pattern:
1922        Parameters:
1923            match:          a Unix style pattern, regular expression or selector
1924            matchtype:      'pattern' (default) UNIX style pattern or
1925                            'regex' regular expression
1926            sourcetype:     the type of the source to use (source/reference)
1927        """
1928        varlist = vars()
1929        basesel = self.get_selection()
1930        stype = -1
1931        if sourcetype.lower().startswith("r"):
1932            stype = 1
1933        elif sourcetype.lower().startswith("s"):
1934            stype = 0
1935        else:
1936            raise ValueError("Illegal sourcetype use s(ource) or r(eference)")
1937        if matchtype.lower().startswith("p"):
1938            matchtype = "pattern"
1939        elif matchtype.lower().startswith("r"):
1940            matchtype = "regex"
1941        else:
1942            raise ValueError("Illegal matchtype, use p(attern) or r(egex)")
1943        sel = selector()
1944        if isinstance(match, selector):
1945            sel = match
1946        else:
1947            sel.set_query("SRCNAME == %s('%s')" % (matchtype, match))
1948        self.set_selection(basesel+sel)
1949        self._setsourcetype(stype)
1950        self.set_selection(basesel)
1951        s._add_history("set_sourcetype", varlist)
1952
1953    def auto_quotient(self, preserve=True, mode='paired', verify=False):
1954        """
1955        This function allows to build quotients automatically.
1956        It assumes the observation to have the same number of
1957        "ons" and "offs"
1958        Parameters:
1959            preserve:       you can preserve (default) the continuum or
1960                            remove it.  The equations used are
1961                            preserve: Output = Toff * (on/off) - Toff
1962                            remove:   Output = Toff * (on/off) - Ton
1963            mode:           the on/off detection mode
1964                            'paired' (default)
1965                            identifies 'off' scans by the
1966                            trailing '_R' (Mopra/Parkes) or
1967                            '_e'/'_w' (Tid) and matches
1968                            on/off pairs from the observing pattern
1969                            'time'
1970                            finds the closest off in time
1971
1972        """
1973        modes = ["time", "paired"]
1974        if not mode in modes:
1975            msg = "please provide valid mode. Valid modes are %s" % (modes)
1976            raise ValueError(msg)
1977        varlist = vars()
1978        s = None
1979        if mode.lower() == "paired":
1980            basesel = self.get_selection()
1981            sel = selector()+basesel
1982            sel.set_query("SRCTYPE==1")
1983            self.set_selection(sel)
1984            offs = self.copy()
1985            sel.set_query("SRCTYPE==0")
1986            self.set_selection(sel)
1987            ons = self.copy()
1988            s = scantable(self._math._quotient(ons, offs, preserve))
1989            self.set_selection(basesel)
1990        elif mode.lower() == "time":
1991            s = scantable(self._math._auto_quotient(self, mode, preserve))
1992        s._add_history("auto_quotient", varlist)
1993        print_log()
1994        return s
1995
1996    def mx_quotient(self, mask = None, weight='median', preserve=True):
1997        """
1998        Form a quotient using "off" beams when observing in "MX" mode.
1999        Parameters:
2000            mask:           an optional mask to be used when weight == 'stddev'
2001            weight:         How to average the off beams.  Default is 'median'.
2002            preserve:       you can preserve (default) the continuum or
2003                            remove it.  The equations used are
2004                            preserve: Output = Toff * (on/off) - Toff
2005                            remove:   Output = Toff * (on/off) - Ton
2006        """
2007        if mask is None: mask = ()
2008        varlist = vars()
2009        on = scantable(self._math._mx_extract(self, 'on'))
2010        preoff = scantable(self._math._mx_extract(self, 'off'))
2011        off = preoff.average_time(mask=mask, weight=weight, scanav=False)
2012        from asapmath  import quotient
2013        q = quotient(on, off, preserve)
2014        q._add_history("mx_quotient", varlist)
2015        print_log()
2016        return q
2017
2018    def freq_switch(self, insitu=None):
2019        """
2020        Apply frequency switching to the data.
2021        Parameters:
2022            insitu:      if False a new scantable is returned.
2023                         Otherwise, the swictching is done in-situ
2024                         The default is taken from .asaprc (False)
2025        Example:
2026            none
2027        """
2028        if insitu is None: insitu = rcParams['insitu']
2029        self._math._setinsitu(insitu)
2030        varlist = vars()
2031        s = scantable(self._math._freqswitch(self))
2032        s._add_history("freq_switch", varlist)
2033        print_log()
2034        if insitu: self._assign(s)
2035        else: return s
2036
2037    def recalc_azel(self):
2038        """
2039        Recalculate the azimuth and elevation for each position.
2040        Parameters:
2041            none
2042        Example:
2043        """
2044        varlist = vars()
2045        self._recalcazel()
2046        self._add_history("recalc_azel", varlist)
2047        print_log()
2048        return
2049
2050    def __add__(self, other):
2051        """
2052        implicit on all axes and on Tsys
2053        """
2054        return self._operation( other, "ADD" )
2055
2056    def __sub__(self, other):
2057        """
2058        implicit on all axes and on Tsys
2059        """
2060        return self._operation( other, 'SUB' )
2061
2062    def __mul__(self, other):
2063        """
2064        implicit on all axes and on Tsys
2065        """
2066        return self._operation( other, 'MUL' )
2067
2068    def __div__(self, other):
2069        """
2070        implicit on all axes and on Tsys
2071        """
2072        return self._operation( other, 'DIV' )
2073
2074    def get_fit(self, row=0):
2075        """
2076        Print or return the stored fits for a row in the scantable
2077        Parameters:
2078            row:    the row which the fit has been applied to.
2079        """
2080        if row > self.nrow():
2081            return
2082        from asap.asapfit import asapfit
2083        fit = asapfit(self._getfit(row))
2084        if rcParams['verbose']:
2085            #print fit
2086            asaplog.push( '%s' %(fit) )
2087            print_log()
2088            return
2089        else:
2090            return fit.as_dict()
2091
2092    def flag_nans(self):
2093        """
2094        Utility function to flag NaN values in the scantable.
2095        """
2096        import numpy
2097        basesel = self.get_selection()
2098        for i in range(self.nrow()):
2099            sel = selector()+basesel
2100            sel.set_scans(self.getscan(i))
2101            sel.set_beams(self.getbeam(i))
2102            sel.set_ifs(self.getif(i))
2103            sel.set_polarisations(self.getpol(i))
2104            self.set_selection(sel)
2105            nans = numpy.isnan(self._getspectrum(0))
2106        if numpy.any(nans):
2107            bnans = [ bool(v) for v in nans]
2108            self.flag(bnans)
2109        self.set_selection(basesel)
2110       
2111
2112    def _add_history(self, funcname, parameters):
2113        if not rcParams['scantable.history']:
2114            return
2115        # create date
2116        sep = "##"
2117        from datetime import datetime
2118        dstr = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
2119        hist = dstr+sep
2120        hist += funcname+sep#cdate+sep
2121        if parameters.has_key('self'): del parameters['self']
2122        for k, v in parameters.iteritems():
2123            if type(v) is dict:
2124                for k2, v2 in v.iteritems():
2125                    hist += k2
2126                    hist += "="
2127                    if isinstance(v2, scantable):
2128                        hist += 'scantable'
2129                    elif k2 == 'mask':
2130                        if isinstance(v2, list) or isinstance(v2, tuple):
2131                            hist += str(self._zip_mask(v2))
2132                        else:
2133                            hist += str(v2)
2134                    else:
2135                        hist += str(v2)
2136            else:
2137                hist += k
2138                hist += "="
2139                if isinstance(v, scantable):
2140                    hist += 'scantable'
2141                elif k == 'mask':
2142                    if isinstance(v, list) or isinstance(v, tuple):
2143                        hist += str(self._zip_mask(v))
2144                    else:
2145                        hist += str(v)
2146                else:
2147                    hist += str(v)
2148            hist += sep
2149        hist = hist[:-2] # remove trailing '##'
2150        self._addhistory(hist)
2151
2152
2153    def _zip_mask(self, mask):
2154        mask = list(mask)
2155        i = 0
2156        segments = []
2157        while mask[i:].count(1):
2158            i += mask[i:].index(1)
2159            if mask[i:].count(0):
2160                j = i + mask[i:].index(0)
2161            else:
2162                j = len(mask)
2163            segments.append([i, j])
2164            i = j
2165        return segments
2166
2167    def _get_ordinate_label(self):
2168        fu = "("+self.get_fluxunit()+")"
2169        import re
2170        lbl = "Intensity"
2171        if re.match(".K.", fu):
2172            lbl = "Brightness Temperature "+ fu
2173        elif re.match(".Jy.", fu):
2174            lbl = "Flux density "+ fu
2175        return lbl
2176
2177    def _check_ifs(self):
2178        nchans = [self.nchan(i) for i in range(self.nif(-1))]
2179        nchans = filter(lambda t: t > 0, nchans)
2180        return (sum(nchans)/len(nchans) == nchans[0])
2181
2182    def _fill(self, names, unit, average, getpt, antenna):
2183        import os
2184        from asap._asap import stfiller
2185        first = True
2186        fullnames = []
2187        for name in names:
2188            name = os.path.expandvars(name)
2189            name = os.path.expanduser(name)
2190            if not os.path.exists(name):
2191                msg = "File '%s' does not exists" % (name)
2192                if rcParams['verbose']:
2193                    asaplog.push(msg)
2194                    #print asaplog.pop().strip()
2195                    print_log( 'ERROR' )
2196                    return
2197                raise IOError(msg)
2198            fullnames.append(name)
2199        if average:
2200            asaplog.push('Auto averaging integrations')
2201        stype = int(rcParams['scantable.storage'].lower() == 'disk')
2202        for name in fullnames:
2203            tbl = Scantable(stype)
2204            r = stfiller(tbl)
2205            rx = rcParams['scantable.reference']
2206            r._setreferenceexpr(rx)
2207            msg = "Importing %s..." % (name)
2208            asaplog.push(msg, False)
2209            print_log()
2210            r._open(name, antenna, -1, -1, getpt)
2211            r._read()
2212            if average:
2213                tbl = self._math._average((tbl, ), (), 'NONE', 'SCAN')
2214            if not first:
2215                tbl = self._math._merge([self, tbl])
2216            Scantable.__init__(self, tbl)
2217            r._close()
2218            del r, tbl
2219            first = False
2220        if unit is not None:
2221            self.set_fluxunit(unit)
2222        #self.set_freqframe(rcParams['scantable.freqframe'])
2223
2224    def __getitem__(self, key):
2225        if key < 0:
2226            key += self.nrow()
2227        if key >= self.nrow():
2228            raise IndexError("Row index out of range.")
2229        return self._getspectrum(key)
2230
2231    def __setitem__(self, key, value):
2232        if key < 0:
2233            key += self.nrow()
2234        if key >= self.nrow():
2235            raise IndexError("Row index out of range.")
2236        if not hasattr(value, "__len__") or \
2237                len(value) > self.nchan(self.getif(key)):
2238            raise ValueError("Spectrum length doesn't match.")
2239        return self._setspectrum(value, key)
2240
2241    def __len__(self):
2242        return self.nrow()
2243
2244    def __iter__(self):
2245        for i in range(len(self)):
2246            yield self[i]
2247
2248    def _operation(self, other, opmode):
2249        varlist = vars()
2250        s = None
2251        import numpy
2252        if isinstance(other, scantable):
2253            s = scantable(self._math._binaryop(self.copy(), other, opmode))
2254        elif isinstance(other, float) or isinstance(other, int):
2255            if opmode == 'DIV' and float(other) == 0.0:
2256                raise ZeroDivisionError("Dividing by zero is not recommended")
2257            s = scantable(self._math._unaryop(self.copy(), other, opmode, False))
2258        elif isinstance(other, list) or isinstance(other, numpy.ndarray):
2259            if isinstance(other[0], list) or isinstance(other[0], numpy.ndarray):
2260                from asapmath import _array2dOp
2261                s = _array2dOp( self.copy(), other, opmode, False )
2262            else:
2263                s = scantable(self._math._arrayop(self.copy(), other, opmode, False))
2264        else:
2265            raise TypeError("Other input is not a scantable or float value or float list")
2266        opdic = {}
2267        opdic['ADD'] = '+'
2268        opdic['SUB'] = '-'
2269        opdic['MUL'] = '*'
2270        opdic['DIV'] = '/'
2271        s._add_history("operator %s" % opdic[opmode], varlist)
2272        print_log()
2273        return s
2274
2275       
Note: See TracBrowser for help on using the repository browser.