source: trunk/python/scantable.py @ 2809

Last change on this file since 2809 was 2809, checked in by WataruKawasaki, 11 years ago

New Development: No

JIRA Issue: No

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s): sd.scantable

Description: modified help texts of sub_baseline() and apply_bltable().


  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 179.0 KB
Line 
1"""This module defines the scantable class."""
2
3import os
4import re
5import tempfile
6import numpy
7try:
8    from functools import wraps as wraps_dec
9except ImportError:
10    from asap.compatibility import wraps as wraps_dec
11
12from asap.env import is_casapy
13from asap._asap import Scantable
14from asap._asap import filler, msfiller
15from asap.parameters import rcParams
16from asap.logging import asaplog, asaplog_post_dec
17from asap.selector import selector
18from asap.linecatalog import linecatalog
19from asap.coordinate import coordinate
20from asap.utils import _n_bools, mask_not, mask_and, mask_or, page
21from asap.asapfitter import fitter
22
23def preserve_selection(func):
24    @wraps_dec(func)
25    def wrap(obj, *args, **kw):
26        basesel = obj.get_selection()
27        try:
28            val = func(obj, *args, **kw)
29        finally:
30            obj.set_selection(basesel)
31        return val
32    return wrap
33
34def is_scantable(filename):
35    """Is the given file a scantable?
36
37    Parameters:
38
39        filename: the name of the file/directory to test
40
41    """
42    if ( os.path.isdir(filename)
43         and os.path.exists(filename+'/table.info')
44         and os.path.exists(filename+'/table.dat') ):
45        f=open(filename+'/table.info')
46        l=f.readline()
47        f.close()
48        match_pattern = '^Type = (Scantable)? *$'
49        if re.match(match_pattern,l):
50            return True
51        else:
52            return False
53    else:
54        return False
55##     return (os.path.isdir(filename)
56##             and not os.path.exists(filename+'/table.f1')
57##             and os.path.exists(filename+'/table.info'))
58
59def is_ms(filename):
60    """Is the given file a MeasurementSet?
61
62    Parameters:
63
64        filename: the name of the file/directory to test
65
66    """
67    if ( os.path.isdir(filename)
68         and os.path.exists(filename+'/table.info')
69         and os.path.exists(filename+'/table.dat') ):
70        f=open(filename+'/table.info')
71        l=f.readline()
72        f.close()
73        if ( l.find('Measurement Set') != -1 ):
74            return True
75        else:
76            return False
77    else:
78        return False
79
80def normalise_edge_param(edge):
81    """\
82    Convert a given edge value to a one-dimensional array that can be
83    given to baseline-fitting/subtraction functions.
84    The length of the output value will be an even because values for
85    the both sides of spectra are to be contained for each IF. When
86    the length is 2, the values will be applied to all IFs. If the length
87    is larger than 2, it will be 2*ifnos().
88    Accepted format of edge include:
89            * an integer - will be used for both sides of spectra of all IFs.
90                  e.g. 10 is converted to [10,10]
91            * an empty list/tuple [] - converted to [0, 0] and used for all IFs.
92            * a list/tuple containing an integer - same as the above case.
93                  e.g. [10] is converted to [10,10]
94            * a list/tuple containing two integers - will be used for all IFs.
95                  e.g. [5,10] is output as it is. no need to convert.
96            * a list/tuple of lists/tuples containing TWO integers -
97                  each element of edge will be used for each IF.
98                  e.g. [[5,10],[15,20]] - [5,10] for IF[0] and [15,20] for IF[1].
99                 
100                  If an element contains the same integer values, the input 'edge'
101                  parameter can be given in a simpler shape in the following cases:
102                      ** when len(edge)!=2
103                          any elements containing the same values can be replaced
104                          to single integers.
105                          e.g. [[15,15]] can be simplified to [15] (or [15,15] or 15 also).
106                          e.g. [[1,1],[2,2],[3,3]] can be simplified to [1,2,3].
107                      ** when len(edge)=2
108                          care is needed for this case: ONLY ONE of the
109                          elements can be a single integer,
110                          e.g. [[5,5],[10,10]] can be simplified to [5,[10,10]]
111                               or [[5,5],10], but can NOT be simplified to [5,10].
112                               when [5,10] given, it is interpreted as
113                               [[5,10],[5,10],[5,10],...] instead, as shown before.
114    """
115    from asap import _is_sequence_or_number as _is_valid
116    if isinstance(edge, list) or isinstance(edge, tuple):
117        for edgepar in edge:
118            if not _is_valid(edgepar, int):
119                raise ValueError, "Each element of the 'edge' tuple has \
120                                   to be a pair of integers or an integer."
121            if isinstance(edgepar, list) or isinstance(edgepar, tuple):
122                if len(edgepar) != 2:
123                    raise ValueError, "Each element of the 'edge' tuple has \
124                                       to be a pair of integers or an integer."
125    else:
126        if not _is_valid(edge, int):
127            raise ValueError, "Parameter 'edge' has to be an integer or a \
128                               pair of integers specified as a tuple. \
129                               Nested tuples are allowed \
130                               to make individual selection for different IFs."
131       
132
133    if isinstance(edge, int):
134        edge = [ edge, edge ]                 # e.g. 3   => [3,3]
135    elif isinstance(edge, list) or isinstance(edge, tuple):
136        if len(edge) == 0:
137            edge = [0, 0]                     # e.g. []  => [0,0]
138        elif len(edge) == 1:
139            if isinstance(edge[0], int):
140                edge = [ edge[0], edge[0] ]   # e.g. [1] => [1,1]
141
142    commonedge = True
143    if len(edge) > 2: commonedge = False
144    else:
145        for edgepar in edge:
146            if isinstance(edgepar, list) or isinstance(edgepar, tuple):
147                commonedge = False
148                break
149
150    if commonedge:
151        if len(edge) > 1:
152            norm_edge = edge
153        else:
154            norm_edge = edge + edge
155    else:
156        norm_edge = []
157        for edgepar in edge:
158            if isinstance(edgepar, int):
159                norm_edge += [edgepar, edgepar]
160            else:
161                norm_edge += edgepar
162
163    return norm_edge
164
165def raise_fitting_failure_exception(e):
166    msg = "The fit failed, possibly because it didn't converge."
167    if rcParams["verbose"]:
168        asaplog.push(str(e))
169        asaplog.push(str(msg))
170    else:
171        raise RuntimeError(str(e)+'\n'+msg)
172
173def pack_progress_params(showprogress, minnrow):
174    return str(showprogress).lower() + ',' + str(minnrow)
175
176def pack_blinfo(blinfo, maxirow):
177    """\
178    convert a dictionary or a list of dictionaries of baseline info
179    into a list of comma-separated strings.
180    """
181    if isinstance(blinfo, dict):
182        res = do_pack_blinfo(blinfo, maxirow)
183        return [res] if res != '' else []
184    elif isinstance(blinfo, list) or isinstance(blinfo, tuple):
185        res = []
186        for i in xrange(len(blinfo)):
187            resi = do_pack_blinfo(blinfo[i], maxirow)
188            if resi != '':
189                res.append(resi)
190    return res
191
192def do_pack_blinfo(blinfo, maxirow):
193    """\
194    convert a dictionary of baseline info for a spectrum into
195    a comma-separated string.
196    """
197    dinfo = {}
198    for key in ['row', 'blfunc', 'masklist']:
199        if blinfo.has_key(key):
200            val = blinfo[key]
201            if key == 'row':
202                irow = val
203            if isinstance(val, list) or isinstance(val, tuple):
204                slval = []
205                for i in xrange(len(val)):
206                    if isinstance(val[i], list) or isinstance(val[i], tuple):
207                        for j in xrange(len(val[i])):
208                            slval.append(str(val[i][j]))
209                    else:
210                        slval.append(str(val[i]))
211                sval = ",".join(slval)
212            else:
213                sval = str(val)
214
215            dinfo[key] = sval
216        else:
217            raise ValueError("'"+key+"' is missing in blinfo.")
218
219    if irow >= maxirow: return ''
220   
221    for key in ['order', 'npiece', 'nwave']:
222        if blinfo.has_key(key):
223            val = blinfo[key]
224            if isinstance(val, list) or isinstance(val, tuple):
225                slval = []
226                for i in xrange(len(val)):
227                    slval.append(str(val[i]))
228                sval = ",".join(slval)
229            else:
230                sval = str(val)
231            dinfo[key] = sval
232
233    blfunc = dinfo['blfunc']
234    fspec_keys = {'poly': 'order', 'chebyshev': 'order', 'cspline': 'npiece', 'sinusoid': 'nwave'}
235
236    fspec_key = fspec_keys[blfunc]
237    if not blinfo.has_key(fspec_key):
238        raise ValueError("'"+fspec_key+"' is missing in blinfo.")
239
240    clip_params_n = 0
241    for key in ['clipthresh', 'clipniter']:
242        if blinfo.has_key(key):
243            clip_params_n += 1
244            dinfo[key] = str(blinfo[key])
245
246    if clip_params_n == 0:
247        dinfo['clipthresh'] = '0.0'
248        dinfo['clipniter']  = '0'
249    elif clip_params_n != 2:
250        raise ValueError("both 'clipthresh' and 'clipniter' must be given for n-sigma clipping.")
251
252    lf_params_n = 0
253    for key in ['thresh', 'edge', 'chan_avg_limit']:
254        if blinfo.has_key(key):
255            lf_params_n += 1
256            val = blinfo[key]
257            if isinstance(val, list) or isinstance(val, tuple):
258                slval = []
259                for i in xrange(len(val)):
260                    slval.append(str(val[i]))
261                sval = ",".join(slval)
262            else:
263                sval = str(val)
264            dinfo[key] = sval
265
266    if lf_params_n == 3:
267        dinfo['use_linefinder'] = 'true'
268    elif lf_params_n == 1:
269        dinfo['use_linefinder'] = 'false'
270        dinfo['thresh']         = ''
271        dinfo['edge']           = ''
272        dinfo['chan_avg_limit'] = ''
273    else:
274        raise ValueError("all of 'thresh', 'edge' and 'chan_avg_limit' must be given to use linefinder.")
275   
276    slblinfo = [dinfo['row'], blfunc, dinfo[fspec_key], dinfo['masklist'], \
277                dinfo['clipthresh'], dinfo['clipniter'], \
278                dinfo['use_linefinder'], dinfo['thresh'], dinfo['edge'], dinfo['chan_avg_limit']]
279   
280    return ":".join(slblinfo)
281
282def parse_fitresult(sres):
283    """\
284    Parse the returned value of apply_bltable() or sub_baseline() and
285    extract row number, the best-fit coefficients and rms, then pack
286    them into a dictionary.
287    The input value is generated by Scantable::packFittingResults() and
288    formatted as 'row:coeff[0],coeff[1],..,coeff[n-1]:rms'.
289    """
290    res = []
291    for i in xrange(len(sres)):
292        (srow, scoeff, srms) = sres[i].split(":")
293        row = int(srow)
294        rms = float(srms)
295        lscoeff = scoeff.split(",")
296        coeff = []
297        for j in xrange(len(lscoeff)):
298            coeff.append(float(lscoeff[j]))
299        res.append({'row': row, 'coeff': coeff, 'rms': rms})
300
301    return res
302
303class scantable(Scantable):
304    """\
305        The ASAP container for scans (single-dish data).
306    """
307
308    @asaplog_post_dec
309    def __init__(self, filename, average=None, unit=None, parallactify=None,
310                 **args):
311        """\
312        Create a scantable from a saved one or make a reference
313
314        Parameters:
315
316            filename:     the name of an asap table on disk
317                          or
318                          the name of a rpfits/sdfits/ms file
319                          (integrations within scans are auto averaged
320                          and the whole file is read) or
321                          [advanced] a reference to an existing scantable
322
323            average:      average all integrations withinb a scan on read.
324                          The default (True) is taken from .asaprc.
325
326            unit:         brightness unit; must be consistent with K or Jy.
327                          Over-rides the default selected by the filler
328                          (input rpfits/sdfits/ms) or replaces the value
329                          in existing scantables
330
331            antenna:      for MeasurementSet input data only:
332                          Antenna selection. integer (id) or string
333                          (name or id).
334
335            parallactify: Indicate that the data had been parallactified.
336                          Default (false) is taken from rc file.
337
338            getpt:        Whether to import direction from MS/POINTING
339                          table properly or not.
340                          This is effective only when filename is MS.
341                          The default (True) is to import direction
342                          from MS/POINTING.
343
344            freq_tolsr:   Whether to convert frequency frame information
345                          to LSRK or not.
346                          This is effective only when filename is MS.
347                          The default (False) is to import frequency
348                          as is.
349                         
350        """
351        if average is None:
352            average = rcParams['scantable.autoaverage']
353        parallactify = parallactify or rcParams['scantable.parallactify']
354        varlist = vars()
355        from asap._asap import stmath
356        self._math = stmath( rcParams['insitu'] )
357        if isinstance(filename, Scantable):
358            Scantable.__init__(self, filename)
359        else:
360            if isinstance(filename, str):
361                filename = os.path.expandvars(filename)
362                filename = os.path.expanduser(filename)
363                if not os.path.exists(filename):
364                    s = "File '%s' not found." % (filename)
365                    raise IOError(s)
366                if is_scantable(filename):
367                    ondisk = rcParams['scantable.storage'] == 'disk'
368                    Scantable.__init__(self, filename, ondisk)
369                    if unit is not None:
370                        self.set_fluxunit(unit)
371                    if average:
372                        self._assign( self.average_time( scanav=True ) )
373                    # do not reset to the default freqframe
374                    #self.set_freqframe(rcParams['scantable.freqframe'])
375                elif is_ms(filename):
376                    # Measurement Set
377                    opts={'ms': {}}
378                    mskeys=['getpt','antenna','freq_tolsr']
379                    for key in mskeys:
380                        if key in args.keys():
381                            opts['ms'][key] = args[key]
382                    self._fill([filename], unit, average, opts)
383                elif os.path.isfile(filename):
384                    opts={'nro': {}}
385                    nrokeys=['freqref']
386                    for key in nrokeys:
387                        if key in args.keys():
388                            opts['nro'][key] = args[key]
389                    self._fill([filename], unit, average, opts)
390                    # only apply to new data not "copy constructor"
391                    self.parallactify(parallactify)
392                else:
393                    msg = "The given file '%s'is not a valid " \
394                          "asap table." % (filename)
395                    raise IOError(msg)
396            elif (isinstance(filename, list) or isinstance(filename, tuple)) \
397                  and isinstance(filename[-1], str):
398                self._fill(filename, unit, average)
399        self.parallactify(parallactify)
400        self._add_history("scantable", varlist)
401
402    @asaplog_post_dec
403    def save(self, name=None, format=None, overwrite=False):
404        """\
405        Store the scantable on disk. This can be an asap (aips++) Table,
406        SDFITS or MS2 format.
407
408        Parameters:
409
410            name:        the name of the outputfile. For format 'ASCII'
411                         this is the root file name (data in 'name'.txt
412                         and header in 'name'_header.txt)
413
414            format:      an optional file format. Default is ASAP.
415                         Allowed are:
416
417                            * 'ASAP' (save as ASAP [aips++] Table),
418                            * 'SDFITS' (save as SDFITS file)
419                            * 'ASCII' (saves as ascii text file)
420                            * 'MS2' (saves as an casacore MeasurementSet V2)
421                            * 'FITS' (save as image FITS - not readable by
422                                      class)
423                            * 'CLASS' (save as FITS readable by CLASS)
424
425            overwrite:   If the file should be overwritten if it exists.
426                         The default False is to return with warning
427                         without writing the output. USE WITH CARE.
428
429        Example::
430
431            scan.save('myscan.asap')
432            scan.save('myscan.sdfits', 'SDFITS')
433
434        """
435        from os import path
436        format = format or rcParams['scantable.save']
437        suffix = '.'+format.lower()
438        if name is None or name == "":
439            name = 'scantable'+suffix
440            msg = "No filename given. Using default name %s..." % name
441            asaplog.push(msg)
442        name = path.expandvars(name)
443        if path.isfile(name) or path.isdir(name):
444            if not overwrite:
445                msg = "File %s exists." % name
446                raise IOError(msg)
447        format2 = format.upper()
448        if format2 == 'ASAP':
449            self._save(name)
450        elif format2 == 'MS2':
451            msopt = {'ms': {'overwrite': overwrite } }
452            from asap._asap import mswriter
453            writer = mswriter( self )
454            writer.write( name, msopt )
455        else:
456            from asap._asap import stwriter as stw
457            writer = stw(format2)
458            writer.write(self, name)
459        return
460
461    def copy(self):
462        """Return a copy of this scantable.
463
464        *Note*:
465
466            This makes a full (deep) copy. scan2 = scan1 makes a reference.
467
468        Example::
469
470            copiedscan = scan.copy()
471
472        """
473        sd = scantable(Scantable._copy(self))
474        return sd
475
476    def drop_scan(self, scanid=None):
477        """\
478        Return a new scantable where the specified scan number(s) has(have)
479        been dropped.
480
481        Parameters:
482
483            scanid:    a (list of) scan number(s)
484
485        """
486        from asap import _is_sequence_or_number as _is_valid
487        from asap import _to_list
488        from asap import unique
489        if not _is_valid(scanid):
490            raise RuntimeError( 'Please specify a scanno to drop from the'
491                                ' scantable' )
492        scanid = _to_list(scanid)
493        allscans = unique([ self.getscan(i) for i in range(self.nrow())])
494        for sid in scanid: allscans.remove(sid)
495        if len(allscans) == 0:
496            raise ValueError("Can't remove all scans")
497        sel = selector(scans=allscans)
498        return self._select_copy(sel)
499
500    def _select_copy(self, selection):
501        orig = self.get_selection()
502        self.set_selection(orig+selection)
503        cp = self.copy()
504        self.set_selection(orig)
505        return cp
506
507    def get_scan(self, scanid=None):
508        """\
509        Return a specific scan (by scanno) or collection of scans (by
510        source name) in a new scantable.
511
512        *Note*:
513
514            See scantable.drop_scan() for the inverse operation.
515
516        Parameters:
517
518            scanid:    a (list of) scanno or a source name, unix-style
519                       patterns are accepted for source name matching, e.g.
520                       '*_R' gets all 'ref scans
521
522        Example::
523
524            # get all scans containing the source '323p459'
525            newscan = scan.get_scan('323p459')
526            # get all 'off' scans
527            refscans = scan.get_scan('*_R')
528            # get a susbset of scans by scanno (as listed in scan.summary())
529            newscan = scan.get_scan([0, 2, 7, 10])
530
531        """
532        if scanid is None:
533            raise RuntimeError( 'Please specify a scan no or name to '
534                                'retrieve from the scantable' )
535        try:
536            bsel = self.get_selection()
537            sel = selector()
538            if type(scanid) is str:
539                sel.set_name(scanid)
540                return self._select_copy(sel)
541            elif type(scanid) is int:
542                sel.set_scans([scanid])
543                return self._select_copy(sel)
544            elif type(scanid) is list:
545                sel.set_scans(scanid)
546                return self._select_copy(sel)
547            else:
548                msg = "Illegal scanid type, use 'int' or 'list' if ints."
549                raise TypeError(msg)
550        except RuntimeError:
551            raise
552
553    def __str__(self):
554        tempFile = tempfile.NamedTemporaryFile()
555        Scantable._summary(self, tempFile.name)
556        tempFile.seek(0)
557        asaplog.clear()
558        return tempFile.file.read()
559
560    @asaplog_post_dec
561    def summary(self, filename=None):
562        """\
563        Print a summary of the contents of this scantable.
564
565        Parameters:
566
567            filename:    the name of a file to write the putput to
568                         Default - no file output
569
570        """
571        if filename is not None:
572            if filename is "":
573                filename = 'scantable_summary.txt'
574            from os.path import expandvars, isdir
575            filename = expandvars(filename)
576            if isdir(filename):
577                msg = "Illegal file name '%s'." % (filename)
578                raise IOError(msg)
579        else:
580            filename = ""
581        Scantable._summary(self, filename)
582
583    def get_spectrum(self, rowno):
584        """Return the spectrum for the current row in the scantable as a list.
585
586        Parameters:
587
588             rowno:   the row number to retrieve the spectrum from
589
590        """
591        return self._getspectrum(rowno)
592
593    def get_mask(self, rowno):
594        """Return the mask for the current row in the scantable as a list.
595
596        Parameters:
597
598             rowno:   the row number to retrieve the mask from
599
600        """
601        return self._getmask(rowno)
602
603    def set_spectrum(self, spec, rowno):
604        """Set the spectrum for the current row in the scantable.
605
606        Parameters:
607
608             spec:   the new spectrum
609
610             rowno:  the row number to set the spectrum for
611
612        """
613        assert(len(spec) == self.nchan(self.getif(rowno)))
614        return self._setspectrum(spec, rowno)
615
616    def get_coordinate(self, rowno):
617        """Return the (spectral) coordinate for a a given 'rowno'.
618
619        *Note*:
620
621            * This coordinate is only valid until a scantable method modifies
622              the frequency axis.
623            * This coordinate does contain the original frequency set-up
624              NOT the new frame. The conversions however are done using the user
625              specified frame (e.g. LSRK/TOPO). To get the 'real' coordinate,
626              use scantable.freq_align first. Without it there is no closure,
627              i.e.::
628
629                  c = myscan.get_coordinate(0)
630                  c.to_frequency(c.get_reference_pixel()) != c.get_reference_value()
631
632        Parameters:
633
634             rowno:    the row number for the spectral coordinate
635
636        """
637        return coordinate(Scantable.get_coordinate(self, rowno))
638
639    def get_selection(self):
640        """\
641        Get the selection object currently set on this scantable.
642
643        Example::
644
645            sel = scan.get_selection()
646            sel.set_ifs(0)              # select IF 0
647            scan.set_selection(sel)     # apply modified selection
648
649        """
650        return selector(self._getselection())
651
652    def set_selection(self, selection=None, **kw):
653        """\
654        Select a subset of the data. All following operations on this scantable
655        are only applied to thi selection.
656
657        Parameters:
658
659            selection:    a selector object (default unset the selection), or
660                          any combination of 'pols', 'ifs', 'beams', 'scans',
661                          'cycles', 'name', 'query'
662
663        Examples::
664
665            sel = selector()         # create a selection object
666            self.set_scans([0, 3])    # select SCANNO 0 and 3
667            scan.set_selection(sel)  # set the selection
668            scan.summary()           # will only print summary of scanno 0 an 3
669            scan.set_selection()     # unset the selection
670            # or the equivalent
671            scan.set_selection(scans=[0,3])
672            scan.summary()           # will only print summary of scanno 0 an 3
673            scan.set_selection()     # unset the selection
674
675        """
676        if selection is None:
677            # reset
678            if len(kw) == 0:
679                selection = selector()
680            else:
681                # try keywords
682                for k in kw:
683                    if k not in selector.fields:
684                        raise KeyError("Invalid selection key '%s', "
685                                       "valid keys are %s" % (k,
686                                                              selector.fields))
687                selection = selector(**kw)
688        self._setselection(selection)
689
690    def get_row(self, row=0, insitu=None):
691        """\
692        Select a row in the scantable.
693        Return a scantable with single row.
694
695        Parameters:
696
697            row:    row no of integration, default is 0.
698            insitu: if False a new scantable is returned. Otherwise, the
699                    scaling is done in-situ. The default is taken from .asaprc
700                    (False)
701
702        """
703        if insitu is None:
704            insitu = rcParams['insitu']
705        if not insitu:
706            workscan = self.copy()
707        else:
708            workscan = self
709        # Select a row
710        sel = selector()
711        sel.set_rows([row])
712        workscan.set_selection(sel)
713        if not workscan.nrow() == 1:
714            msg = "Could not identify single row. %d rows selected." \
715                % (workscan.nrow())
716            raise RuntimeError(msg)
717        if insitu:
718            self._assign(workscan)
719        else:
720            return workscan
721
722    @asaplog_post_dec
723    def stats(self, stat='stddev', mask=None, form='3.3f', row=None):
724        """\
725        Determine the specified statistic of the current beam/if/pol
726        Takes a 'mask' as an optional parameter to specify which
727        channels should be excluded.
728
729        Parameters:
730
731            stat:    'min', 'max', 'min_abc', 'max_abc', 'sumsq', 'sum',
732                     'mean', 'var', 'stddev', 'avdev', 'rms', 'median'
733
734            mask:    an optional mask specifying where the statistic
735                     should be determined.
736
737            form:    format string to print statistic values
738
739            row:     row number of spectrum to process.
740                     (default is None: for all rows)
741
742        Example:
743            scan.set_unit('channel')
744            msk = scan.create_mask([100, 200], [500, 600])
745            scan.stats(stat='mean', mask=m)
746
747        """
748        mask = mask or []
749        if not self._check_ifs():
750            raise ValueError("Cannot apply mask as the IFs have different "
751                             "number of channels. Please use setselection() "
752                             "to select individual IFs")
753        rtnabc = False
754        if stat.lower().endswith('_abc'): rtnabc = True
755        getchan = False
756        if stat.lower().startswith('min') or stat.lower().startswith('max'):
757            chan = self._math._minmaxchan(self, mask, stat)
758            getchan = True
759            statvals = []
760        if not rtnabc:
761            if row == None:
762                statvals = self._math._stats(self, mask, stat)
763            else:
764                statvals = self._math._statsrow(self, mask, stat, int(row))
765
766        #def cb(i):
767        #    return statvals[i]
768
769        #return self._row_callback(cb, stat)
770
771        label=stat
772        #callback=cb
773        out = ""
774        #outvec = []
775        sep = '-'*50
776
777        if row == None:
778            rows = xrange(self.nrow())
779        elif isinstance(row, int):
780            rows = [ row ]
781
782        for i in rows:
783            refstr = ''
784            statunit= ''
785            if getchan:
786                qx, qy = self.chan2data(rowno=i, chan=chan[i])
787                if rtnabc:
788                    statvals.append(qx['value'])
789                    refstr = ('(value: %'+form) % (qy['value'])+' ['+qy['unit']+'])'
790                    statunit= '['+qx['unit']+']'
791                else:
792                    refstr = ('(@ %'+form) % (qx['value'])+' ['+qx['unit']+'])'
793
794            tm = self._gettime(i)
795            src = self._getsourcename(i)
796            out += 'Scan[%d] (%s) ' % (self.getscan(i), src)
797            out += 'Time[%s]:\n' % (tm)
798            if self.nbeam(-1) > 1: out +=  ' Beam[%d] ' % (self.getbeam(i))
799            if self.nif(-1) > 1:   out +=  ' IF[%d] ' % (self.getif(i))
800            if self.npol(-1) > 1:  out +=  ' Pol[%d] ' % (self.getpol(i))
801            #outvec.append(callback(i))
802            if len(rows) > 1:
803                # out += ('= %'+form) % (outvec[i]) +'   '+refstr+'\n'
804                out += ('= %'+form) % (statvals[i]) +'   '+refstr+'\n'
805            else:
806                # out += ('= %'+form) % (outvec[0]) +'   '+refstr+'\n'
807                out += ('= %'+form) % (statvals[0]) +'   '+refstr+'\n'
808            out +=  sep+"\n"
809
810        import os
811        if os.environ.has_key( 'USER' ):
812            usr = os.environ['USER']
813        else:
814            import commands
815            usr = commands.getoutput( 'whoami' )
816        tmpfile = '/tmp/tmp_'+usr+'_casapy_asap_scantable_stats'
817        f = open(tmpfile,'w')
818        print >> f, sep
819        print >> f, ' %s %s' % (label, statunit)
820        print >> f, sep
821        print >> f, out
822        f.close()
823        f = open(tmpfile,'r')
824        x = f.readlines()
825        f.close()
826        asaplog.push(''.join(x), False)
827
828        return statvals
829
830    def chan2data(self, rowno=0, chan=0):
831        """\
832        Returns channel/frequency/velocity and spectral value
833        at an arbitrary row and channel in the scantable.
834
835        Parameters:
836
837            rowno:   a row number in the scantable. Default is the
838                     first row, i.e. rowno=0
839
840            chan:    a channel in the scantable. Default is the first
841                     channel, i.e. pos=0
842
843        """
844        if isinstance(rowno, int) and isinstance(chan, int):
845            qx = {'unit': self.get_unit(),
846                  'value': self._getabcissa(rowno)[chan]}
847            qy = {'unit': self.get_fluxunit(),
848                  'value': self._getspectrum(rowno)[chan]}
849            return qx, qy
850
851    def stddev(self, mask=None):
852        """\
853        Determine the standard deviation of the current beam/if/pol
854        Takes a 'mask' as an optional parameter to specify which
855        channels should be excluded.
856
857        Parameters:
858
859            mask:    an optional mask specifying where the standard
860                     deviation should be determined.
861
862        Example::
863
864            scan.set_unit('channel')
865            msk = scan.create_mask([100, 200], [500, 600])
866            scan.stddev(mask=m)
867
868        """
869        return self.stats(stat='stddev', mask=mask);
870
871
872    def get_column_names(self):
873        """\
874        Return a  list of column names, which can be used for selection.
875        """
876        return list(Scantable.get_column_names(self))
877
878    def get_tsys(self, row=-1):
879        """\
880        Return the System temperatures.
881
882        Parameters:
883
884            row:    the rowno to get the information for. (default all rows)
885
886        Returns:
887
888            a list of Tsys values for the current selection
889
890        """
891        if row > -1:
892            return self._get_column(self._gettsys, row)
893        return self._row_callback(self._gettsys, "Tsys")
894
895    def get_tsysspectrum(self, row=-1):
896        """\
897        Return the channel dependent system temperatures.
898
899        Parameters:
900
901            row:    the rowno to get the information for. (default all rows)
902
903        Returns:
904
905            a list of Tsys values for the current selection
906
907        """
908        return self._get_column( self._gettsysspectrum, row )
909
910    def set_tsys(self, values, row=-1):
911        """\
912        Set the Tsys value(s) of the given 'row' or the whole scantable
913        (selection).
914       
915        Parameters:
916
917            values:    a scalar or list (if Tsys is a vector) of Tsys value(s)
918            row:       the row number to apply Tsys values to.
919                       (default all rows)
920                       
921        """
922           
923        if not hasattr(values, "__len__"):
924            values = [values]
925        self._settsys(values, row)
926
927    def get_weather(self, row=-1):
928        """\
929        Return the weather informations.
930
931        Parameters:
932
933            row:    the rowno to get the information for. (default all rows)
934
935        Returns:
936
937            a dict or list of of dicts of values for the current selection
938
939        """
940
941        values = self._get_column(self._get_weather, row)
942        if row > -1:
943            return {'temperature': values[0],
944                    'pressure': values[1], 'humidity' : values[2],
945                    'windspeed' : values[3], 'windaz' : values[4]
946                    }
947        else:
948            out = []
949            for r in values:
950
951                out.append({'temperature': r[0],
952                            'pressure': r[1], 'humidity' : r[2],
953                            'windspeed' : r[3], 'windaz' : r[4]
954                    })
955            return out
956
957    def _row_callback(self, callback, label):
958        out = ""
959        outvec = []
960        sep = '-'*50
961        for i in range(self.nrow()):
962            tm = self._gettime(i)
963            src = self._getsourcename(i)
964            out += 'Scan[%d] (%s) ' % (self.getscan(i), src)
965            out += 'Time[%s]:\n' % (tm)
966            if self.nbeam(-1) > 1:
967                out +=  ' Beam[%d] ' % (self.getbeam(i))
968            if self.nif(-1) > 1: out +=  ' IF[%d] ' % (self.getif(i))
969            if self.npol(-1) > 1: out +=  ' Pol[%d] ' % (self.getpol(i))
970            outvec.append(callback(i))
971            out += '= %3.3f\n' % (outvec[i])
972            out +=  sep+'\n'
973
974        asaplog.push(sep)
975        asaplog.push(" %s" % (label))
976        asaplog.push(sep)
977        asaplog.push(out)
978        asaplog.post()
979        return outvec
980
981    def _get_column(self, callback, row=-1, *args):
982        """
983        """
984        if row == -1:
985            return [callback(i, *args) for i in range(self.nrow())]
986        else:
987            if  0 <= row < self.nrow():
988                return callback(row, *args)
989
990
991    def get_time(self, row=-1, asdatetime=False, prec=-1):
992        """\
993        Get a list of time stamps for the observations.
994        Return a datetime object or a string (default) for each
995        integration time stamp in the scantable.
996
997        Parameters:
998
999            row:          row no of integration. Default -1 return all rows
1000
1001            asdatetime:   return values as datetime objects rather than strings
1002
1003            prec:         number of digits shown. Default -1 to automatic
1004                          calculation.
1005                          Note this number is equals to the digits of MVTime,
1006                          i.e., 0<prec<3: dates with hh:: only,
1007                          <5: with hh:mm:, <7 or 0: with hh:mm:ss,
1008                          and 6> : with hh:mm:ss.tt... (prec-6 t's added)
1009
1010        """
1011        from datetime import datetime
1012        if prec < 0:
1013            # automagically set necessary precision +1
1014            prec = 7 - \
1015                numpy.floor(numpy.log10(numpy.min(self.get_inttime(row))))
1016            prec = max(6, int(prec))
1017        else:
1018            prec = max(0, prec)
1019        if asdatetime:
1020            #precision can be 1 millisecond at max
1021            prec = min(12, prec)
1022
1023        times = self._get_column(self._gettime, row, prec)
1024        if not asdatetime:
1025            return times
1026        format = "%Y/%m/%d/%H:%M:%S.%f"
1027        if prec < 7:
1028            nsub = 1 + (((6-prec)/2) % 3)
1029            substr = [".%f","%S","%M"]
1030            for i in range(nsub):
1031                format = format.replace(substr[i],"")
1032        if isinstance(times, list):
1033            return [datetime.strptime(i, format) for i in times]
1034        else:
1035            return datetime.strptime(times, format)
1036
1037
1038    def get_inttime(self, row=-1):
1039        """\
1040        Get a list of integration times for the observations.
1041        Return a time in seconds for each integration in the scantable.
1042
1043        Parameters:
1044
1045            row:    row no of integration. Default -1 return all rows.
1046
1047        """
1048        return self._get_column(self._getinttime, row)
1049
1050
1051    def get_sourcename(self, row=-1):
1052        """\
1053        Get a list source names for the observations.
1054        Return a string for each integration in the scantable.
1055        Parameters:
1056
1057            row:    row no of integration. Default -1 return all rows.
1058
1059        """
1060        return self._get_column(self._getsourcename, row)
1061
1062    def get_elevation(self, row=-1):
1063        """\
1064        Get a list of elevations for the observations.
1065        Return a float for each integration in the scantable.
1066
1067        Parameters:
1068
1069            row:    row no of integration. Default -1 return all rows.
1070
1071        """
1072        return self._get_column(self._getelevation, row)
1073
1074    def get_azimuth(self, row=-1):
1075        """\
1076        Get a list of azimuths for the observations.
1077        Return a float for each integration in the scantable.
1078
1079        Parameters:
1080            row:    row no of integration. Default -1 return all rows.
1081
1082        """
1083        return self._get_column(self._getazimuth, row)
1084
1085    def get_parangle(self, row=-1):
1086        """\
1087        Get a list of parallactic angles for the observations.
1088        Return a float for each integration in the scantable.
1089
1090        Parameters:
1091
1092            row:    row no of integration. Default -1 return all rows.
1093
1094        """
1095        return self._get_column(self._getparangle, row)
1096
1097    def get_direction(self, row=-1):
1098        """
1099        Get a list of Positions on the sky (direction) for the observations.
1100        Return a string for each integration in the scantable.
1101
1102        Parameters:
1103
1104            row:    row no of integration. Default -1 return all rows
1105
1106        """
1107        return self._get_column(self._getdirection, row)
1108
1109    def get_directionval(self, row=-1):
1110        """\
1111        Get a list of Positions on the sky (direction) for the observations.
1112        Return a float for each integration in the scantable.
1113
1114        Parameters:
1115
1116            row:    row no of integration. Default -1 return all rows
1117
1118        """
1119        return self._get_column(self._getdirectionvec, row)
1120
1121    @asaplog_post_dec
1122    def set_unit(self, unit='channel'):
1123        """\
1124        Set the unit for all following operations on this scantable
1125
1126        Parameters:
1127
1128            unit:    optional unit, default is 'channel'. Use one of '*Hz',
1129                     'km/s', 'channel' or equivalent ''
1130
1131        """
1132        varlist = vars()
1133        if unit in ['', 'pixel', 'channel']:
1134            unit = ''
1135        inf = list(self._getcoordinfo())
1136        inf[0] = unit
1137        self._setcoordinfo(inf)
1138        self._add_history("set_unit", varlist)
1139
1140    @asaplog_post_dec
1141    def set_instrument(self, instr):
1142        """\
1143        Set the instrument for subsequent processing.
1144
1145        Parameters:
1146
1147            instr:    Select from 'ATPKSMB', 'ATPKSHOH', 'ATMOPRA',
1148                      'DSS-43' (Tid), 'CEDUNA', and 'HOBART'
1149
1150        """
1151        self._setInstrument(instr)
1152        self._add_history("set_instument", vars())
1153
1154    @asaplog_post_dec
1155    def set_feedtype(self, feedtype):
1156        """\
1157        Overwrite the feed type, which might not be set correctly.
1158
1159        Parameters:
1160
1161            feedtype:     'linear' or 'circular'
1162
1163        """
1164        self._setfeedtype(feedtype)
1165        self._add_history("set_feedtype", vars())
1166
1167    @asaplog_post_dec
1168    def set_doppler(self, doppler='RADIO'):
1169        """\
1170        Set the doppler for all following operations on this scantable.
1171
1172        Parameters:
1173
1174            doppler:    One of 'RADIO', 'OPTICAL', 'Z', 'BETA', 'GAMMA'
1175
1176        """
1177        varlist = vars()
1178        inf = list(self._getcoordinfo())
1179        inf[2] = doppler
1180        self._setcoordinfo(inf)
1181        self._add_history("set_doppler", vars())
1182
1183    @asaplog_post_dec
1184    def set_freqframe(self, frame=None):
1185        """\
1186        Set the frame type of the Spectral Axis.
1187
1188        Parameters:
1189
1190            frame:   an optional frame type, default 'LSRK'. Valid frames are:
1191                     'TOPO', 'LSRD', 'LSRK', 'BARY',
1192                     'GEO', 'GALACTO', 'LGROUP', 'CMB'
1193
1194        Example::
1195
1196            scan.set_freqframe('BARY')
1197
1198        """
1199        frame = frame or rcParams['scantable.freqframe']
1200        varlist = vars()
1201        # "REST" is not implemented in casacore
1202        #valid = ['REST', 'TOPO', 'LSRD', 'LSRK', 'BARY', \
1203        #           'GEO', 'GALACTO', 'LGROUP', 'CMB']
1204        valid = ['TOPO', 'LSRD', 'LSRK', 'BARY', \
1205                   'GEO', 'GALACTO', 'LGROUP', 'CMB']
1206
1207        if frame in valid:
1208            inf = list(self._getcoordinfo())
1209            inf[1] = frame
1210            self._setcoordinfo(inf)
1211            self._add_history("set_freqframe", varlist)
1212        else:
1213            msg  = "Please specify a valid freq type. Valid types are:\n", valid
1214            raise TypeError(msg)
1215
1216    @asaplog_post_dec
1217    def set_dirframe(self, frame=""):
1218        """\
1219        Set the frame type of the Direction on the sky.
1220
1221        Parameters:
1222
1223            frame:   an optional frame type, default ''. Valid frames are:
1224                     'J2000', 'B1950', 'GALACTIC'
1225
1226        Example:
1227
1228            scan.set_dirframe('GALACTIC')
1229
1230        """
1231        varlist = vars()
1232        Scantable.set_dirframe(self, frame)
1233        self._add_history("set_dirframe", varlist)
1234
1235    def get_unit(self):
1236        """\
1237        Get the default unit set in this scantable
1238
1239        Returns:
1240
1241            A unit string
1242
1243        """
1244        inf = self._getcoordinfo()
1245        unit = inf[0]
1246        if unit == '': unit = 'channel'
1247        return unit
1248
1249    @asaplog_post_dec
1250    def get_abcissa(self, rowno=0):
1251        """\
1252        Get the abcissa in the current coordinate setup for the currently
1253        selected Beam/IF/Pol
1254
1255        Parameters:
1256
1257            rowno:    an optional row number in the scantable. Default is the
1258                      first row, i.e. rowno=0
1259
1260        Returns:
1261
1262            The abcissa values and the format string (as a dictionary)
1263
1264        """
1265        abc = self._getabcissa(rowno)
1266        lbl = self._getabcissalabel(rowno)
1267        return abc, lbl
1268
1269    @asaplog_post_dec
1270    def flag(self, mask=None, unflag=False, row=-1):
1271        """\
1272        Flag the selected data using an optional channel mask.
1273
1274        Parameters:
1275
1276            mask:   an optional channel mask, created with create_mask. Default
1277                    (no mask) is all channels.
1278
1279            unflag:    if True, unflag the data
1280
1281            row:    an optional row number in the scantable.
1282                      Default -1 flags all rows
1283                     
1284        """
1285        varlist = vars()
1286        mask = mask or []
1287        self._flag(row, mask, unflag)
1288        self._add_history("flag", varlist)
1289
1290    @asaplog_post_dec
1291    def flag_row(self, rows=None, unflag=False):
1292        """\
1293        Flag the selected data in row-based manner.
1294
1295        Parameters:
1296
1297            rows:   list of row numbers to be flagged. Default is no row
1298                    (must be explicitly specified to execute row-based
1299                    flagging).
1300
1301            unflag: if True, unflag the data.
1302
1303        """
1304        varlist = vars()
1305        if rows is None:
1306            rows = []
1307        self._flag_row(rows, unflag)
1308        self._add_history("flag_row", varlist)
1309
1310    @asaplog_post_dec
1311    def clip(self, uthres=None, dthres=None, clipoutside=True, unflag=False):
1312        """\
1313        Flag the selected data outside a specified range (in channel-base)
1314
1315        Parameters:
1316
1317            uthres:      upper threshold.
1318
1319            dthres:      lower threshold
1320
1321            clipoutside: True for flagging data outside the range
1322                         [dthres:uthres].
1323                         False for flagging data inside the range.
1324
1325            unflag:      if True, unflag the data.
1326
1327        """
1328        varlist = vars()
1329        self._clip(uthres, dthres, clipoutside, unflag)
1330        self._add_history("clip", varlist)
1331
1332    @asaplog_post_dec
1333    def lag_flag(self, start, end, unit="MHz", insitu=None):
1334        """\
1335        Flag the data in 'lag' space by providing a frequency to remove.
1336        Flagged data in the scantable get interpolated over the region.
1337        No taper is applied.
1338
1339        Parameters:
1340
1341            start:    the start frequency (really a period within the
1342                      bandwidth)  or period to remove
1343
1344            end:      the end frequency or period to remove
1345
1346            unit:     the frequency unit (default 'MHz') or '' for
1347                      explicit lag channels
1348
1349        *Notes*:
1350
1351            It is recommended to flag edges of the band or strong
1352            signals beforehand.
1353
1354        """
1355        if insitu is None: insitu = rcParams['insitu']
1356        self._math._setinsitu(insitu)
1357        varlist = vars()
1358        base = { "GHz": 1000000000., "MHz": 1000000., "kHz": 1000., "Hz": 1.}
1359        if not (unit == "" or base.has_key(unit)):
1360            raise ValueError("%s is not a valid unit." % unit)
1361        if unit == "":
1362            s = scantable(self._math._lag_flag(self, start, end, "lags"))
1363        else:
1364            s = scantable(self._math._lag_flag(self, start*base[unit],
1365                                               end*base[unit], "frequency"))
1366        s._add_history("lag_flag", varlist)
1367        if insitu:
1368            self._assign(s)
1369        else:
1370            return s
1371
1372    @asaplog_post_dec
1373    def fft(self, rowno=None, mask=None, getrealimag=False):
1374        """\
1375        Apply FFT to the spectra.
1376        Flagged data in the scantable get interpolated over the region.
1377
1378        Parameters:
1379
1380            rowno:          The row number(s) to be processed. int, list
1381                            and tuple are accepted. By default (None), FFT
1382                            is applied to the whole data.
1383
1384            mask:           Auxiliary channel mask(s). Given as a boolean
1385                            list, it is applied to all specified rows.
1386                            A list of boolean lists can also be used to
1387                            apply different masks. In the latter case, the
1388                            length of 'mask' must be the same as that of
1389                            'rowno'. The default is None.
1390       
1391            getrealimag:    If True, returns the real and imaginary part
1392                            values of the complex results.
1393                            If False (the default), returns the amplitude
1394                            (absolute value) normalised with Ndata/2 and
1395                            phase (argument, in unit of radian).
1396
1397        Returns:
1398
1399            A list of dictionaries containing the results for each spectrum.
1400            Each dictionary contains two values, the real and the imaginary
1401            parts when getrealimag = True, or the amplitude(absolute value)
1402            and the phase(argument) when getrealimag = False. The key for
1403            these values are 'real' and 'imag', or 'ampl' and 'phase',
1404            respectively.
1405        """
1406        if rowno is None:
1407            rowno = []
1408        if isinstance(rowno, int):
1409            rowno = [rowno]
1410        elif not (isinstance(rowno, list) or isinstance(rowno, tuple)):
1411            raise TypeError("The row number(s) must be int, list or tuple.")
1412        if len(rowno) == 0: rowno = [i for i in xrange(self.nrow())]
1413
1414        usecommonmask = True
1415       
1416        if mask is None:
1417            mask = []
1418        if isinstance(mask, list) or isinstance(mask, tuple):
1419            if len(mask) == 0:
1420                mask = [[]]
1421            else:
1422                if isinstance(mask[0], bool):
1423                    if len(mask) != self.nchan(self.getif(rowno[0])):
1424                        raise ValueError("The spectra and the mask have "
1425                                         "different length.")
1426                    mask = [mask]
1427                elif isinstance(mask[0], list) or isinstance(mask[0], tuple):
1428                    usecommonmask = False
1429                    if len(mask) != len(rowno):
1430                        raise ValueError("When specifying masks for each "
1431                                         "spectrum, the numbers of them "
1432                                         "must be identical.")
1433                    for i in xrange(mask):
1434                        if len(mask[i]) != self.nchan(self.getif(rowno[i])):
1435                            raise ValueError("The spectra and the mask have "
1436                                             "different length.")
1437                else:
1438                    raise TypeError("The mask must be a boolean list or "
1439                                    "a list of boolean list.")
1440        else:
1441            raise TypeError("The mask must be a boolean list or a list of "
1442                            "boolean list.")
1443
1444        res = []
1445
1446        imask = 0
1447        for whichrow in rowno:
1448            fspec = self._fft(whichrow, mask[imask], getrealimag)
1449            nspec = len(fspec)
1450           
1451            i = 0
1452            v1 = []
1453            v2 = []
1454            reselem = {"real":[],"imag":[]} if getrealimag \
1455                                            else {"ampl":[],"phase":[]}
1456           
1457            while (i < nspec):
1458                v1.append(fspec[i])
1459                v2.append(fspec[i+1])
1460                i += 2
1461           
1462            if getrealimag:
1463                reselem["real"]  += v1
1464                reselem["imag"]  += v2
1465            else:
1466                reselem["ampl"]  += v1
1467                reselem["phase"] += v2
1468           
1469            res.append(reselem)
1470           
1471            if not usecommonmask:
1472                imask += 1
1473       
1474        return res
1475
1476    @asaplog_post_dec
1477    def create_mask(self, *args, **kwargs):
1478        """\
1479        Compute and return a mask based on [min, max] windows.
1480        The specified windows are to be INCLUDED, when the mask is
1481        applied.
1482
1483        Parameters:
1484
1485            [min, max], [min2, max2], ...
1486                Pairs of start/end points (inclusive)specifying the regions
1487                to be masked
1488
1489            invert:     optional argument. If specified as True,
1490                        return an inverted mask, i.e. the regions
1491                        specified are EXCLUDED
1492
1493            row:        create the mask using the specified row for
1494                        unit conversions, default is row=0
1495                        only necessary if frequency varies over rows.
1496
1497        Examples::
1498
1499            scan.set_unit('channel')
1500            # a)
1501            msk = scan.create_mask([400, 500], [800, 900])
1502            # masks everything outside 400 and 500
1503            # and 800 and 900 in the unit 'channel'
1504
1505            # b)
1506            msk = scan.create_mask([400, 500], [800, 900], invert=True)
1507            # masks the regions between 400 and 500
1508            # and 800 and 900 in the unit 'channel'
1509
1510            # c)
1511            #mask only channel 400
1512            msk =  scan.create_mask([400])
1513
1514        """
1515        row = kwargs.get("row", 0)
1516        data = self._getabcissa(row)
1517        u = self._getcoordinfo()[0]
1518        if u == "":
1519            u = "channel"
1520        msg = "The current mask window unit is %s" % u
1521        i = self._check_ifs()
1522        if not i:
1523            msg += "\nThis mask is only valid for IF=%d" % (self.getif(i))
1524        asaplog.push(msg)
1525        n = len(data)
1526        msk = _n_bools(n, False)
1527        # test if args is a 'list' or a 'normal *args - UGLY!!!
1528
1529        ws = (isinstance(args[-1][-1], int)
1530              or isinstance(args[-1][-1], float)) and args or args[0]
1531        for window in ws:
1532            if len(window) == 1:
1533                window = [window[0], window[0]]
1534            if len(window) == 0 or  len(window) > 2:
1535                raise ValueError("A window needs to be defined as "
1536                                 "[start(, end)]")
1537            if window[0] > window[1]:
1538                tmp = window[0]
1539                window[0] = window[1]
1540                window[1] = tmp
1541            for i in range(n):
1542                if data[i] >= window[0] and data[i] <= window[1]:
1543                    msk[i] = True
1544        if kwargs.has_key('invert'):
1545            if kwargs.get('invert'):
1546                msk = mask_not(msk)
1547        return msk
1548
1549    def get_masklist(self, mask=None, row=0, silent=False):
1550        """\
1551        Compute and return a list of mask windows, [min, max].
1552
1553        Parameters:
1554
1555            mask:       channel mask, created with create_mask.
1556
1557            row:        calcutate the masklist using the specified row
1558                        for unit conversions, default is row=0
1559                        only necessary if frequency varies over rows.
1560
1561        Returns:
1562
1563            [min, max], [min2, max2], ...
1564                Pairs of start/end points (inclusive)specifying
1565                the masked regions
1566
1567        """
1568        if not (isinstance(mask,list) or isinstance(mask, tuple)):
1569            raise TypeError("The mask should be list or tuple.")
1570        if len(mask) <= 0:
1571            raise TypeError("The mask elements should be > 0")
1572        data = self._getabcissa(row)
1573        if len(data) != len(mask):
1574            msg = "Number of channels in scantable != number of mask elements"
1575            raise TypeError(msg)
1576        u = self._getcoordinfo()[0]
1577        if u == "":
1578            u = "channel"
1579        msg = "The current mask window unit is %s" % u
1580        i = self._check_ifs()
1581        if not i:
1582            msg += "\nThis mask is only valid for IF=%d" % (self.getif(i))
1583        if not silent:
1584            asaplog.push(msg)
1585        masklist = []
1586        ist, ien = None, None
1587        ist, ien=self.get_mask_indices(mask)
1588        if ist is not None and ien is not None:
1589            for i in xrange(len(ist)):
1590                range=[data[ist[i]],data[ien[i]]]
1591                range.sort()
1592                masklist.append([range[0],range[1]])
1593        return masklist
1594
1595    def get_mask_indices(self, mask=None):
1596        """\
1597        Compute and Return lists of mask start indices and mask end indices.
1598
1599        Parameters:
1600
1601            mask:       channel mask, created with create_mask.
1602
1603        Returns:
1604
1605            List of mask start indices and that of mask end indices,
1606            i.e., [istart1,istart2,....], [iend1,iend2,....].
1607
1608        """
1609        if not (isinstance(mask,list) or isinstance(mask, tuple)):
1610            raise TypeError("The mask should be list or tuple.")
1611        if len(mask) <= 0:
1612            raise TypeError("The mask elements should be > 0")
1613        istart = []
1614        iend = []
1615        if mask[0]:
1616            istart.append(0)
1617        for i in range(len(mask)-1):
1618            if not mask[i] and mask[i+1]:
1619                istart.append(i+1)
1620            elif mask[i] and not mask[i+1]:
1621                iend.append(i)
1622        if mask[len(mask)-1]:
1623            iend.append(len(mask)-1)
1624        if len(istart) != len(iend):
1625            raise RuntimeError("Numbers of mask start != mask end.")
1626        for i in range(len(istart)):
1627            if istart[i] > iend[i]:
1628                raise RuntimeError("Mask start index > mask end index")
1629                break
1630        return istart,iend
1631
1632    @asaplog_post_dec
1633    def parse_maskexpr(self, maskstring):
1634        """
1635        Parse CASA type mask selection syntax (IF dependent).
1636
1637        Parameters:
1638            maskstring : A string mask selection expression.
1639                         A comma separated selections mean different IF -
1640                         channel combinations. IFs and channel selections
1641                         are partitioned by a colon, ':'.
1642                     examples:
1643                         ''          = all IFs (all channels)
1644                         '<2,4~6,9'  = IFs 0,1,4,5,6,9 (all channels)
1645                         '3:3~45;60' = channels 3 to 45 and 60 in IF 3
1646                         '0~1:2~6,8' = channels 2 to 6 in IFs 0,1, and
1647                                       all channels in IF8
1648        Returns:
1649        A dictionary of selected (valid) IF and masklist pairs,
1650        e.g. {'0': [[50,250],[350,462]], '2': [[100,400],[550,974]]}
1651        """
1652        if not isinstance(maskstring,str):
1653            asaplog.post()
1654            asaplog.push("Mask expression should be a string.")
1655            asaplog.post("ERROR")
1656       
1657        valid_ifs = self.getifnos()
1658        frequnit = self.get_unit()
1659        seldict = {}
1660        if maskstring == "":
1661            maskstring = str(valid_ifs)[1:-1]
1662        ## split each selection "IF range[:CHAN range]"
1663        sellist = maskstring.split(',')
1664        for currselstr in sellist:
1665            selset = currselstr.split(':')
1666            # spw and mask string (may include ~, < or >)
1667            spwmasklist = self._parse_selection(selset[0], typestr='integer',
1668                                                minval=min(valid_ifs),
1669                                                maxval=max(valid_ifs))
1670            for spwlist in spwmasklist:
1671                selspws = []
1672                for ispw in range(spwlist[0],spwlist[1]+1):
1673                    # Put into the list only if ispw exists
1674                    if valid_ifs.count(ispw):
1675                        selspws.append(ispw)
1676            del spwmasklist, spwlist
1677
1678            # parse frequency mask list
1679            if len(selset) > 1:
1680                freqmasklist = self._parse_selection(selset[1], typestr='float',
1681                                                     offset=0.)
1682            else:
1683                # want to select the whole spectrum
1684                freqmasklist = [None]
1685
1686            ## define a dictionary of spw - masklist combination
1687            for ispw in selspws:
1688                #print "working on", ispw
1689                spwstr = str(ispw)
1690                if len(selspws) == 0:
1691                    # empty spw
1692                    continue
1693                else:
1694                    ## want to get min and max of the spw and
1695                    ## offset to set for '<' and '>'
1696                    if frequnit == 'channel':
1697                        minfreq = 0
1698                        maxfreq = self.nchan(ifno=ispw)
1699                        offset = 0.5
1700                    else:
1701                        ## This is ugly part. need improvement
1702                        for ifrow in xrange(self.nrow()):
1703                            if self.getif(ifrow) == ispw:
1704                                #print "IF",ispw,"found in row =",ifrow
1705                                break
1706                        freqcoord = self.get_coordinate(ifrow)
1707                        freqs = self._getabcissa(ifrow)
1708                        minfreq = min(freqs)
1709                        maxfreq = max(freqs)
1710                        if len(freqs) == 1:
1711                            offset = 0.5
1712                        elif frequnit.find('Hz') > 0:
1713                            offset = abs(freqcoord.to_frequency(1,
1714                                                                unit=frequnit)
1715                                         -freqcoord.to_frequency(0,
1716                                                                 unit=frequnit)
1717                                         )*0.5
1718                        elif frequnit.find('m/s') > 0:
1719                            offset = abs(freqcoord.to_velocity(1,
1720                                                               unit=frequnit)
1721                                         -freqcoord.to_velocity(0,
1722                                                                unit=frequnit)
1723                                         )*0.5
1724                        else:
1725                            asaplog.post()
1726                            asaplog.push("Invalid frequency unit")
1727                            asaplog.post("ERROR")
1728                        del freqs, freqcoord, ifrow
1729                    for freq in freqmasklist:
1730                        selmask = freq or [minfreq, maxfreq]
1731                        if selmask[0] == None:
1732                            ## selection was "<freq[1]".
1733                            if selmask[1] < minfreq:
1734                                ## avoid adding region selection
1735                                selmask = None
1736                            else:
1737                                selmask = [minfreq,selmask[1]-offset]
1738                        elif selmask[1] == None:
1739                            ## selection was ">freq[0]"
1740                            if selmask[0] > maxfreq:
1741                                ## avoid adding region selection
1742                                selmask = None
1743                            else:
1744                                selmask = [selmask[0]+offset,maxfreq]
1745                        if selmask:
1746                            if not seldict.has_key(spwstr):
1747                                # new spw selection
1748                                seldict[spwstr] = []
1749                            seldict[spwstr] += [selmask]
1750                    del minfreq,maxfreq,offset,freq,selmask
1751                del spwstr
1752            del freqmasklist
1753        del valid_ifs
1754        if len(seldict) == 0:
1755            asaplog.post()
1756            asaplog.push("No valid selection in the mask expression: "
1757                         +maskstring)
1758            asaplog.post("WARN")
1759            return None
1760        msg = "Selected masklist:\n"
1761        for sif, lmask in seldict.iteritems():
1762            msg += "   IF"+sif+" - "+str(lmask)+"\n"
1763        asaplog.push(msg)
1764        return seldict
1765
1766    @asaplog_post_dec
1767    def parse_idx_selection(self, mode, selexpr):
1768        """
1769        Parse CASA type mask selection syntax of SCANNO, IFNO, POLNO,
1770        BEAMNO, and row number
1771
1772        Parameters:
1773            mode       : which column to select.
1774                         ['scan',|'if'|'pol'|'beam'|'row']
1775            selexpr    : A comma separated selection expression.
1776                     examples:
1777                         ''          = all (returns [])
1778                         '<2,4~6,9'  = indices less than 2, 4 to 6 and 9
1779                                       (returns [0,1,4,5,6,9])
1780        Returns:
1781        A List of selected indices
1782        """
1783        if selexpr == "":
1784            return []
1785        valid_modes = {'s': 'scan', 'i': 'if', 'p': 'pol',
1786                       'b': 'beam', 'r': 'row'}
1787        smode =  mode.lower()[0]
1788        if not (smode in valid_modes.keys()):
1789            msg = "Invalid mode '%s'. Valid modes are %s" %\
1790                  (mode, str(valid_modes.values()))
1791            asaplog.post()
1792            asaplog.push(msg)
1793            asaplog.post("ERROR")
1794        mode = valid_modes[smode]
1795        minidx = None
1796        maxidx = None
1797        if smode == 'r':
1798            minidx = 0
1799            maxidx = self.nrow()
1800        else:
1801            idx = getattr(self,"get"+mode+"nos")()
1802            minidx = min(idx)
1803            maxidx = max(idx)
1804            del idx
1805        sellist = selexpr.split(',')
1806        idxlist = []
1807        for currselstr in sellist:
1808            # single range (may include ~, < or >)
1809            currlist = self._parse_selection(currselstr, typestr='integer',
1810                                             minval=minidx,maxval=maxidx)
1811            for thelist in currlist:
1812                idxlist += range(thelist[0],thelist[1]+1)
1813        msg = "Selected %s: %s" % (mode.upper()+"NO", str(idxlist))
1814        asaplog.push(msg)
1815        return idxlist
1816
1817    def _parse_selection(self, selstr, typestr='float', offset=0.,
1818                         minval=None, maxval=None):
1819        """
1820        Parameters:
1821            selstr :    The Selection string, e.g., '<3;5~7;100~103;9'
1822            typestr :   The type of the values in returned list
1823                        ('integer' or 'float')
1824            offset :    The offset value to subtract from or add to
1825                        the boundary value if the selection string
1826                        includes '<' or '>' [Valid only for typestr='float']
1827            minval, maxval :  The minimum/maximum values to set if the
1828                              selection string includes '<' or '>'.
1829                              The list element is filled with None by default.
1830        Returns:
1831            A list of min/max pair of selections.
1832        Example:
1833            _parse_selection('<3;5~7;9',typestr='int',minval=0)
1834            --> returns [[0,2],[5,7],[9,9]]
1835            _parse_selection('<3;5~7;9',typestr='float',offset=0.5,minval=0)
1836            --> returns [[0.,2.5],[5.0,7.0],[9.,9.]]
1837        """
1838        selgroups = selstr.split(';')
1839        sellists = []
1840        if typestr.lower().startswith('int'):
1841            formatfunc = int
1842            offset = 1
1843        else:
1844            formatfunc = float
1845       
1846        for currsel in  selgroups:
1847            if currsel.find('~') > 0:
1848                # val0 <= x <= val1
1849                minsel = formatfunc(currsel.split('~')[0].strip())
1850                maxsel = formatfunc(currsel.split('~')[1].strip())
1851            elif currsel.strip().find('<=') > -1:
1852                bound = currsel.split('<=')
1853                try: # try "x <= val"
1854                    minsel = minval
1855                    maxsel = formatfunc(bound[1].strip())
1856                except ValueError: # now "val <= x"
1857                    minsel = formatfunc(bound[0].strip())
1858                    maxsel = maxval
1859            elif currsel.strip().find('>=') > -1:
1860                bound = currsel.split('>=')
1861                try: # try "x >= val"
1862                    minsel = formatfunc(bound[1].strip())
1863                    maxsel = maxval
1864                except ValueError: # now "val >= x"
1865                    minsel = minval
1866                    maxsel = formatfunc(bound[0].strip())
1867            elif currsel.strip().find('<') > -1:
1868                bound = currsel.split('<')
1869                try: # try "x < val"
1870                    minsel = minval
1871                    maxsel = formatfunc(bound[1].strip()) \
1872                             - formatfunc(offset)
1873                except ValueError: # now "val < x"
1874                    minsel = formatfunc(bound[0].strip()) \
1875                         + formatfunc(offset)
1876                    maxsel = maxval
1877            elif currsel.strip().find('>') > -1:
1878                bound = currsel.split('>')
1879                try: # try "x > val"
1880                    minsel = formatfunc(bound[1].strip()) \
1881                             + formatfunc(offset)
1882                    maxsel = maxval
1883                except ValueError: # now "val > x"
1884                    minsel = minval
1885                    maxsel = formatfunc(bound[0].strip()) \
1886                             - formatfunc(offset)
1887            else:
1888                minsel = formatfunc(currsel)
1889                maxsel = formatfunc(currsel)
1890            sellists.append([minsel,maxsel])
1891        return sellists
1892
1893#    def get_restfreqs(self):
1894#        """
1895#        Get the restfrequency(s) stored in this scantable.
1896#        The return value(s) are always of unit 'Hz'
1897#        Parameters:
1898#            none
1899#        Returns:
1900#            a list of doubles
1901#        """
1902#        return list(self._getrestfreqs())
1903
1904    def get_restfreqs(self, ids=None):
1905        """\
1906        Get the restfrequency(s) stored in this scantable.
1907        The return value(s) are always of unit 'Hz'
1908
1909        Parameters:
1910
1911            ids: (optional) a list of MOLECULE_ID for that restfrequency(s) to
1912                 be retrieved
1913
1914        Returns:
1915
1916            dictionary containing ids and a list of doubles for each id
1917
1918        """
1919        if ids is None:
1920            rfreqs = {}
1921            idlist = self.getmolnos()
1922            for i in idlist:
1923                rfreqs[i] = list(self._getrestfreqs(i))
1924            return rfreqs
1925        else:
1926            if type(ids) == list or type(ids) == tuple:
1927                rfreqs = {}
1928                for i in ids:
1929                    rfreqs[i] = list(self._getrestfreqs(i))
1930                return rfreqs
1931            else:
1932                return list(self._getrestfreqs(ids))
1933
1934    @asaplog_post_dec
1935    def set_restfreqs(self, freqs=None, unit='Hz'):
1936        """\
1937        Set or replace the restfrequency specified and
1938        if the 'freqs' argument holds a scalar,
1939        then that rest frequency will be applied to all the selected
1940        data.  If the 'freqs' argument holds
1941        a vector, then it MUST be of equal or smaller length than
1942        the number of IFs (and the available restfrequencies will be
1943        replaced by this vector).  In this case, *all* data have
1944        the restfrequency set per IF according
1945        to the corresponding value you give in the 'freqs' vector.
1946        E.g. 'freqs=[1e9, 2e9]'  would mean IF 0 gets restfreq 1e9 and
1947        IF 1 gets restfreq 2e9.
1948
1949        You can also specify the frequencies via a linecatalog.
1950
1951        Parameters:
1952
1953            freqs:   list of rest frequency values or string idenitfiers
1954
1955            unit:    unit for rest frequency (default 'Hz')
1956
1957
1958        Example::
1959
1960            # set the given restfrequency for the all currently selected IFs
1961            scan.set_restfreqs(freqs=1.4e9)
1962            # set restfrequencies for the n IFs  (n > 1) in the order of the
1963            # list, i.e
1964            # IF0 -> 1.4e9, IF1 ->  1.41e9, IF3 -> 1.42e9
1965            # len(list_of_restfreqs) == nIF
1966            # for nIF == 1 the following will set multiple restfrequency for
1967            # that IF
1968            scan.set_restfreqs(freqs=[1.4e9, 1.41e9, 1.42e9])
1969            # set multiple restfrequencies per IF. as a list of lists where
1970            # the outer list has nIF elements, the inner s arbitrary
1971            scan.set_restfreqs(freqs=[[1.4e9, 1.41e9], [1.67e9]])
1972
1973       *Note*:
1974
1975            To do more sophisticate Restfrequency setting, e.g. on a
1976            source and IF basis, use scantable.set_selection() before using
1977            this function::
1978
1979                # provided your scantable is called scan
1980                selection = selector()
1981                selection.set_name('ORION*')
1982                selection.set_ifs([1])
1983                scan.set_selection(selection)
1984                scan.set_restfreqs(freqs=86.6e9)
1985
1986        """
1987        varlist = vars()
1988        from asap import linecatalog
1989        # simple  value
1990        if isinstance(freqs, int) or isinstance(freqs, float):
1991            self._setrestfreqs([freqs], [""], unit)
1992        # list of values
1993        elif isinstance(freqs, list) or isinstance(freqs, tuple):
1994            # list values are scalars
1995            if isinstance(freqs[-1], int) or isinstance(freqs[-1], float):
1996                if len(freqs) == 1:
1997                    self._setrestfreqs(freqs, [""], unit)
1998                else:
1999                    # allow the 'old' mode of setting mulitple IFs
2000                    savesel = self._getselection()
2001                    sel = self.get_selection()
2002                    iflist = self.getifnos()
2003                    if len(freqs)>len(iflist):
2004                        raise ValueError("number of elements in list of list "
2005                                         "exeeds the current IF selections")
2006                    iflist = self.getifnos()
2007                    for i, fval in enumerate(freqs):
2008                        sel.set_ifs(iflist[i])
2009                        self._setselection(sel)
2010                        self._setrestfreqs([fval], [""], unit)
2011                    self._setselection(savesel)
2012
2013            # list values are dict, {'value'=, 'name'=)
2014            elif isinstance(freqs[-1], dict):
2015                values = []
2016                names = []
2017                for d in freqs:
2018                    values.append(d["value"])
2019                    names.append(d["name"])
2020                self._setrestfreqs(values, names, unit)
2021            elif isinstance(freqs[-1], list) or isinstance(freqs[-1], tuple):
2022                savesel = self._getselection()
2023                sel = self.get_selection()
2024                iflist = self.getifnos()
2025                if len(freqs)>len(iflist):
2026                    raise ValueError("number of elements in list of list exeeds"
2027                                     " the current IF selections")
2028                for i, fval in enumerate(freqs):
2029                    sel.set_ifs(iflist[i])
2030                    self._setselection(sel)
2031                    self._setrestfreqs(fval, [""], unit)
2032                self._setselection(savesel)
2033        # freqs are to be taken from a linecatalog
2034        elif isinstance(freqs, linecatalog):
2035            savesel = self._getselection()
2036            sel = self.get_selection()
2037            for i in xrange(freqs.nrow()):
2038                sel.set_ifs(iflist[i])
2039                self._setselection(sel)
2040                self._setrestfreqs([freqs.get_frequency(i)],
2041                                   [freqs.get_name(i)], "MHz")
2042                # ensure that we are not iterating past nIF
2043                if i == self.nif()-1: break
2044            self._setselection(savesel)
2045        else:
2046            return
2047        self._add_history("set_restfreqs", varlist)
2048
2049    @asaplog_post_dec
2050    def shift_refpix(self, delta):
2051        """\
2052        Shift the reference pixel of the Spectra Coordinate by an
2053        integer amount.
2054
2055        Parameters:
2056
2057            delta:   the amount to shift by
2058
2059        *Note*:
2060
2061            Be careful using this with broadband data.
2062
2063        """
2064        varlist = vars()
2065        Scantable.shift_refpix(self, delta)
2066        s._add_history("shift_refpix", varlist)
2067
2068    @asaplog_post_dec
2069    def history(self, filename=None):
2070        """\
2071        Print the history. Optionally to a file.
2072
2073        Parameters:
2074
2075            filename:    The name of the file to save the history to.
2076
2077        """
2078        hist = list(self._gethistory())
2079        out = "-"*80
2080        for h in hist:
2081            if h.startswith("---"):
2082                out = "\n".join([out, h])
2083            else:
2084                items = h.split("##")
2085                date = items[0]
2086                func = items[1]
2087                items = items[2:]
2088                out += "\n"+date+"\n"
2089                out += "Function: %s\n  Parameters:" % (func)
2090                for i in items:
2091                    if i == '':
2092                        continue
2093                    s = i.split("=")
2094                    out += "\n   %s = %s" % (s[0], s[1])
2095                out = "\n".join([out, "-"*80])
2096        if filename is not None:
2097            if filename is "":
2098                filename = 'scantable_history.txt'
2099            import os
2100            filename = os.path.expandvars(os.path.expanduser(filename))
2101            if not os.path.isdir(filename):
2102                data = open(filename, 'w')
2103                data.write(out)
2104                data.close()
2105            else:
2106                msg = "Illegal file name '%s'." % (filename)
2107                raise IOError(msg)
2108        return page(out)
2109
2110    #
2111    # Maths business
2112    #
2113    @asaplog_post_dec
2114    def average_time(self, mask=None, scanav=False, weight='tint', align=False):
2115        """\
2116        Return the (time) weighted average of a scan. Scans will be averaged
2117        only if the source direction (RA/DEC) is within 1' otherwise
2118
2119        *Note*:
2120
2121            in channels only - align if necessary
2122
2123        Parameters:
2124
2125            mask:     an optional mask (only used for 'var' and 'tsys'
2126                      weighting)
2127
2128            scanav:   True averages each scan separately
2129                      False (default) averages all scans together,
2130
2131            weight:   Weighting scheme.
2132                      'none'     (mean no weight)
2133                      'var'      (1/var(spec) weighted)
2134                      'tsys'     (1/Tsys**2 weighted)
2135                      'tint'     (integration time weighted)
2136                      'tintsys'  (Tint/Tsys**2)
2137                      'median'   ( median averaging)
2138                      The default is 'tint'
2139
2140            align:    align the spectra in velocity before averaging. It takes
2141                      the time of the first spectrum as reference time.
2142
2143        Example::
2144
2145            # time average the scantable without using a mask
2146            newscan = scan.average_time()
2147
2148        """
2149        varlist = vars()
2150        weight = weight or 'TINT'
2151        mask = mask or ()
2152        scanav = (scanav and 'SCAN') or 'NONE'
2153        scan = (self, )
2154
2155        if align:
2156            scan = (self.freq_align(insitu=False), )
2157        s = None
2158        if weight.upper() == 'MEDIAN':
2159            s = scantable(self._math._averagechannel(scan[0], 'MEDIAN',
2160                                                     scanav))
2161        else:
2162            s = scantable(self._math._average(scan, mask, weight.upper(),
2163                          scanav))
2164        s._add_history("average_time", varlist)
2165        return s
2166
2167    @asaplog_post_dec
2168    def convert_flux(self, jyperk=None, eta=None, d=None, insitu=None):
2169        """\
2170        Return a scan where all spectra are converted to either
2171        Jansky or Kelvin depending upon the flux units of the scan table.
2172        By default the function tries to look the values up internally.
2173        If it can't find them (or if you want to over-ride), you must
2174        specify EITHER jyperk OR eta (and D which it will try to look up
2175        also if you don't set it). jyperk takes precedence if you set both.
2176
2177        Parameters:
2178
2179            jyperk:      the Jy / K conversion factor
2180
2181            eta:         the aperture efficiency
2182
2183            d:           the geometric diameter (metres)
2184
2185            insitu:      if False a new scantable is returned.
2186                         Otherwise, the scaling is done in-situ
2187                         The default is taken from .asaprc (False)
2188
2189        """
2190        if insitu is None: insitu = rcParams['insitu']
2191        self._math._setinsitu(insitu)
2192        varlist = vars()
2193        jyperk = jyperk or -1.0
2194        d = d or -1.0
2195        eta = eta or -1.0
2196        s = scantable(self._math._convertflux(self, d, eta, jyperk))
2197        s._add_history("convert_flux", varlist)
2198        if insitu: self._assign(s)
2199        else: return s
2200
2201    @asaplog_post_dec
2202    def gain_el(self, poly=None, filename="", method="linear", insitu=None):
2203        """\
2204        Return a scan after applying a gain-elevation correction.
2205        The correction can be made via either a polynomial or a
2206        table-based interpolation (and extrapolation if necessary).
2207        You specify polynomial coefficients, an ascii table or neither.
2208        If you specify neither, then a polynomial correction will be made
2209        with built in coefficients known for certain telescopes (an error
2210        will occur if the instrument is not known).
2211        The data and Tsys are *divided* by the scaling factors.
2212
2213        Parameters:
2214
2215            poly:        Polynomial coefficients (default None) to compute a
2216                         gain-elevation correction as a function of
2217                         elevation (in degrees).
2218
2219            filename:    The name of an ascii file holding correction factors.
2220                         The first row of the ascii file must give the column
2221                         names and these MUST include columns
2222                         'ELEVATION' (degrees) and 'FACTOR' (multiply data
2223                         by this) somewhere.
2224                         The second row must give the data type of the
2225                         column. Use 'R' for Real and 'I' for Integer.
2226                         An example file would be
2227                         (actual factors are arbitrary) :
2228
2229                         TIME ELEVATION FACTOR
2230                         R R R
2231                         0.1 0 0.8
2232                         0.2 20 0.85
2233                         0.3 40 0.9
2234                         0.4 60 0.85
2235                         0.5 80 0.8
2236                         0.6 90 0.75
2237
2238            method:      Interpolation method when correcting from a table.
2239                         Values are  'nearest', 'linear' (default), 'cubic'
2240                         and 'spline'
2241
2242            insitu:      if False a new scantable is returned.
2243                         Otherwise, the scaling is done in-situ
2244                         The default is taken from .asaprc (False)
2245
2246        """
2247
2248        if insitu is None: insitu = rcParams['insitu']
2249        self._math._setinsitu(insitu)
2250        varlist = vars()
2251        poly = poly or ()
2252        from os.path import expandvars
2253        filename = expandvars(filename)
2254        s = scantable(self._math._gainel(self, poly, filename, method))
2255        s._add_history("gain_el", varlist)
2256        if insitu:
2257            self._assign(s)
2258        else:
2259            return s
2260
2261    @asaplog_post_dec
2262    def freq_align(self, reftime=None, method='cubic', insitu=None):
2263        """\
2264        Return a scan where all rows have been aligned in frequency/velocity.
2265        The alignment frequency frame (e.g. LSRK) is that set by function
2266        set_freqframe.
2267
2268        Parameters:
2269
2270            reftime:     reference time to align at. By default, the time of
2271                         the first row of data is used.
2272
2273            method:      Interpolation method for regridding the spectra.
2274                         Choose from 'nearest', 'linear', 'cubic' (default)
2275                         and 'spline'
2276
2277            insitu:      if False a new scantable is returned.
2278                         Otherwise, the scaling is done in-situ
2279                         The default is taken from .asaprc (False)
2280
2281        """
2282        if insitu is None: insitu = rcParams["insitu"]
2283        oldInsitu = self._math._insitu()
2284        self._math._setinsitu(insitu)
2285        varlist = vars()
2286        reftime = reftime or ""
2287        s = scantable(self._math._freq_align(self, reftime, method))
2288        s._add_history("freq_align", varlist)
2289        self._math._setinsitu(oldInsitu)
2290        if insitu:
2291            self._assign(s)
2292        else:
2293            return s
2294
2295    @asaplog_post_dec
2296    def opacity(self, tau=None, insitu=None):
2297        """\
2298        Apply an opacity correction. The data
2299        and Tsys are multiplied by the correction factor.
2300
2301        Parameters:
2302
2303            tau:         (list of) opacity from which the correction factor is
2304                         exp(tau*ZD)
2305                         where ZD is the zenith-distance.
2306                         If a list is provided, it has to be of length nIF,
2307                         nIF*nPol or 1 and in order of IF/POL, e.g.
2308                         [opif0pol0, opif0pol1, opif1pol0 ...]
2309                         if tau is `None` the opacities are determined from a
2310                         model.
2311
2312            insitu:      if False a new scantable is returned.
2313                         Otherwise, the scaling is done in-situ
2314                         The default is taken from .asaprc (False)
2315
2316        """
2317        if insitu is None:
2318            insitu = rcParams['insitu']
2319        self._math._setinsitu(insitu)
2320        varlist = vars()
2321        if not hasattr(tau, "__len__"):
2322            tau = [tau]
2323        s = scantable(self._math._opacity(self, tau))
2324        s._add_history("opacity", varlist)
2325        if insitu:
2326            self._assign(s)
2327        else:
2328            return s
2329
2330    @asaplog_post_dec
2331    def bin(self, width=5, insitu=None):
2332        """\
2333        Return a scan where all spectra have been binned up.
2334
2335        Parameters:
2336
2337            width:       The bin width (default=5) in pixels
2338
2339            insitu:      if False a new scantable is returned.
2340                         Otherwise, the scaling is done in-situ
2341                         The default is taken from .asaprc (False)
2342
2343        """
2344        if insitu is None:
2345            insitu = rcParams['insitu']
2346        self._math._setinsitu(insitu)
2347        varlist = vars()
2348        s = scantable(self._math._bin(self, width))
2349        s._add_history("bin", varlist)
2350        if insitu:
2351            self._assign(s)
2352        else:
2353            return s
2354
2355    @asaplog_post_dec
2356    def reshape(self, first, last, insitu=None):
2357        """Resize the band by providing first and last channel.
2358        This will cut off all channels outside [first, last].
2359        """
2360        if insitu is None:
2361            insitu = rcParams['insitu']
2362        varlist = vars()
2363        if last < 0:
2364            last = self.nchan()-1 + last
2365        s = None
2366        if insitu:
2367            s = self
2368        else:
2369            s = self.copy()
2370        s._reshape(first,last)
2371        s._add_history("reshape", varlist)
2372        if not insitu:
2373            return s       
2374
2375    @asaplog_post_dec
2376    def resample(self, width=5, method='cubic', insitu=None):
2377        """\
2378        Return a scan where all spectra have been binned up.
2379
2380        Parameters:
2381
2382            width:       The bin width (default=5) in pixels
2383
2384            method:      Interpolation method when correcting from a table.
2385                         Values are  'nearest', 'linear', 'cubic' (default)
2386                         and 'spline'
2387
2388            insitu:      if False a new scantable is returned.
2389                         Otherwise, the scaling is done in-situ
2390                         The default is taken from .asaprc (False)
2391
2392        """
2393        if insitu is None:
2394            insitu = rcParams['insitu']
2395        self._math._setinsitu(insitu)
2396        varlist = vars()
2397        s = scantable(self._math._resample(self, method, width))
2398        s._add_history("resample", varlist)
2399        if insitu:
2400            self._assign(s)
2401        else:
2402            return s
2403
2404    @asaplog_post_dec
2405    def average_pol(self, mask=None, weight='none'):
2406        """\
2407        Average the Polarisations together.
2408
2409        Parameters:
2410
2411            mask:        An optional mask defining the region, where the
2412                         averaging will be applied. The output will have all
2413                         specified points masked.
2414
2415            weight:      Weighting scheme. 'none' (default), 'var' (1/var(spec)
2416                         weighted), or 'tsys' (1/Tsys**2 weighted)
2417
2418        """
2419        varlist = vars()
2420        mask = mask or ()
2421        s = scantable(self._math._averagepol(self, mask, weight.upper()))
2422        s._add_history("average_pol", varlist)
2423        return s
2424
2425    @asaplog_post_dec
2426    def average_beam(self, mask=None, weight='none'):
2427        """\
2428        Average the Beams together.
2429
2430        Parameters:
2431            mask:        An optional mask defining the region, where the
2432                         averaging will be applied. The output will have all
2433                         specified points masked.
2434
2435            weight:      Weighting scheme. 'none' (default), 'var' (1/var(spec)
2436                         weighted), or 'tsys' (1/Tsys**2 weighted)
2437
2438        """
2439        varlist = vars()
2440        mask = mask or ()
2441        s = scantable(self._math._averagebeams(self, mask, weight.upper()))
2442        s._add_history("average_beam", varlist)
2443        return s
2444
2445    def parallactify(self, pflag):
2446        """\
2447        Set a flag to indicate whether this data should be treated as having
2448        been 'parallactified' (total phase == 0.0)
2449
2450        Parameters:
2451
2452            pflag:  Bool indicating whether to turn this on (True) or
2453                    off (False)
2454
2455        """
2456        varlist = vars()
2457        self._parallactify(pflag)
2458        self._add_history("parallactify", varlist)
2459
2460    @asaplog_post_dec
2461    def convert_pol(self, poltype=None):
2462        """\
2463        Convert the data to a different polarisation type.
2464        Note that you will need cross-polarisation terms for most conversions.
2465
2466        Parameters:
2467
2468            poltype:    The new polarisation type. Valid types are:
2469                        'linear', 'circular', 'stokes' and 'linpol'
2470
2471        """
2472        varlist = vars()
2473        s = scantable(self._math._convertpol(self, poltype))
2474        s._add_history("convert_pol", varlist)
2475        return s
2476
2477    @asaplog_post_dec
2478    def smooth(self, kernel="hanning", width=5.0, order=2, plot=False,
2479               insitu=None):
2480        """\
2481        Smooth the spectrum by the specified kernel (conserving flux).
2482
2483        Parameters:
2484
2485            kernel:     The type of smoothing kernel. Select from
2486                        'hanning' (default), 'gaussian', 'boxcar', 'rmedian'
2487                        or 'poly'
2488
2489            width:      The width of the kernel in pixels. For hanning this is
2490                        ignored otherwise it defauls to 5 pixels.
2491                        For 'gaussian' it is the Full Width Half
2492                        Maximum. For 'boxcar' it is the full width.
2493                        For 'rmedian' and 'poly' it is the half width.
2494
2495            order:      Optional parameter for 'poly' kernel (default is 2), to
2496                        specify the order of the polnomial. Ignored by all other
2497                        kernels.
2498
2499            plot:       plot the original and the smoothed spectra.
2500                        In this each indivual fit has to be approved, by
2501                        typing 'y' or 'n'
2502
2503            insitu:     if False a new scantable is returned.
2504                        Otherwise, the scaling is done in-situ
2505                        The default is taken from .asaprc (False)
2506
2507        """
2508        if insitu is None: insitu = rcParams['insitu']
2509        self._math._setinsitu(insitu)
2510        varlist = vars()
2511
2512        if plot: orgscan = self.copy()
2513
2514        s = scantable(self._math._smooth(self, kernel.lower(), width, order))
2515        s._add_history("smooth", varlist)
2516
2517        action = 'H'
2518        if plot:
2519            from asap.asapplotter import new_asaplot
2520            theplot = new_asaplot(rcParams['plotter.gui'])
2521            from matplotlib import rc as rcp
2522            rcp('lines', linewidth=1)
2523            theplot.set_panels()
2524            ylab=s._get_ordinate_label()
2525            #theplot.palette(0,["#777777","red"])
2526            for r in xrange(s.nrow()):
2527                xsm=s._getabcissa(r)
2528                ysm=s._getspectrum(r)
2529                xorg=orgscan._getabcissa(r)
2530                yorg=orgscan._getspectrum(r)
2531                if action != "N": #skip plotting if rejecting all
2532                    theplot.clear()
2533                    theplot.hold()
2534                    theplot.set_axes('ylabel',ylab)
2535                    theplot.set_axes('xlabel',s._getabcissalabel(r))
2536                    theplot.set_axes('title',s._getsourcename(r))
2537                    theplot.set_line(label='Original',color="#777777")
2538                    theplot.plot(xorg,yorg)
2539                    theplot.set_line(label='Smoothed',color="red")
2540                    theplot.plot(xsm,ysm)
2541                    ### Ugly part for legend
2542                    for i in [0,1]:
2543                        theplot.subplots[0]['lines'].append(
2544                            [theplot.subplots[0]['axes'].lines[i]]
2545                            )
2546                    theplot.release()
2547                    ### Ugly part for legend
2548                    theplot.subplots[0]['lines']=[]
2549                res = self._get_verify_action("Accept smoothing?",action)
2550                #print "IF%d, POL%d: got result = %s" %(s.getif(r),s.getpol(r),res)
2551                if r == 0: action = None
2552                #res = raw_input("Accept smoothing ([y]/n): ")
2553                if res.upper() == 'N':
2554                    # reject for the current rows
2555                    s._setspectrum(yorg, r)
2556                elif res.upper() == 'R':
2557                    # reject all the following rows
2558                    action = "N"
2559                    s._setspectrum(yorg, r)
2560                elif res.upper() == 'A':
2561                    # accept all the following rows
2562                    break
2563            theplot.quit()
2564            del theplot
2565            del orgscan
2566
2567        if insitu: self._assign(s)
2568        else: return s
2569
2570    @asaplog_post_dec
2571    def regrid_channel(self, width=5, plot=False, insitu=None):
2572        """\
2573        Regrid the spectra by the specified channel width
2574
2575        Parameters:
2576
2577            width:      The channel width (float) of regridded spectra
2578                        in the current spectral unit.
2579
2580            plot:       [NOT IMPLEMENTED YET]
2581                        plot the original and the regridded spectra.
2582                        In this each indivual fit has to be approved, by
2583                        typing 'y' or 'n'
2584
2585            insitu:     if False a new scantable is returned.
2586                        Otherwise, the scaling is done in-situ
2587                        The default is taken from .asaprc (False)
2588
2589        """
2590        if insitu is None: insitu = rcParams['insitu']
2591        varlist = vars()
2592
2593        if plot:
2594           asaplog.post()
2595           asaplog.push("Verification plot is not implemtnetd yet.")
2596           asaplog.post("WARN")
2597
2598        s = self.copy()
2599        s._regrid_specchan(width)
2600
2601        s._add_history("regrid_channel", varlist)
2602
2603#         if plot:
2604#             from asap.asapplotter import new_asaplot
2605#             theplot = new_asaplot(rcParams['plotter.gui'])
2606#             from matplotlib import rc as rcp
2607#             rcp('lines', linewidth=1)
2608#             theplot.set_panels()
2609#             ylab=s._get_ordinate_label()
2610#             #theplot.palette(0,["#777777","red"])
2611#             for r in xrange(s.nrow()):
2612#                 xsm=s._getabcissa(r)
2613#                 ysm=s._getspectrum(r)
2614#                 xorg=orgscan._getabcissa(r)
2615#                 yorg=orgscan._getspectrum(r)
2616#                 theplot.clear()
2617#                 theplot.hold()
2618#                 theplot.set_axes('ylabel',ylab)
2619#                 theplot.set_axes('xlabel',s._getabcissalabel(r))
2620#                 theplot.set_axes('title',s._getsourcename(r))
2621#                 theplot.set_line(label='Original',color="#777777")
2622#                 theplot.plot(xorg,yorg)
2623#                 theplot.set_line(label='Smoothed',color="red")
2624#                 theplot.plot(xsm,ysm)
2625#                 ### Ugly part for legend
2626#                 for i in [0,1]:
2627#                     theplot.subplots[0]['lines'].append(
2628#                         [theplot.subplots[0]['axes'].lines[i]]
2629#                         )
2630#                 theplot.release()
2631#                 ### Ugly part for legend
2632#                 theplot.subplots[0]['lines']=[]
2633#                 res = raw_input("Accept smoothing ([y]/n): ")
2634#                 if res.upper() == 'N':
2635#                     s._setspectrum(yorg, r)
2636#             theplot.quit()
2637#             del theplot
2638#             del orgscan
2639
2640        if insitu: self._assign(s)
2641        else: return s
2642
2643    @asaplog_post_dec
2644    def _parse_wn(self, wn):
2645        if isinstance(wn, list) or isinstance(wn, tuple):
2646            return wn
2647        elif isinstance(wn, int):
2648            return [ wn ]
2649        elif isinstance(wn, str):
2650            if '-' in wn:                            # case 'a-b' : return [a,a+1,...,b-1,b]
2651                val = wn.split('-')
2652                val = [int(val[0]), int(val[1])]
2653                val.sort()
2654                res = [i for i in xrange(val[0], val[1]+1)]
2655            elif wn[:2] == '<=' or wn[:2] == '=<':   # cases '<=a','=<a' : return [0,1,...,a-1,a]
2656                val = int(wn[2:])+1
2657                res = [i for i in xrange(val)]
2658            elif wn[-2:] == '>=' or wn[-2:] == '=>': # cases 'a>=','a=>' : return [0,1,...,a-1,a]
2659                val = int(wn[:-2])+1
2660                res = [i for i in xrange(val)]
2661            elif wn[0] == '<':                       # case '<a' :         return [0,1,...,a-2,a-1]
2662                val = int(wn[1:])
2663                res = [i for i in xrange(val)]
2664            elif wn[-1] == '>':                      # case 'a>' :         return [0,1,...,a-2,a-1]
2665                val = int(wn[:-1])
2666                res = [i for i in xrange(val)]
2667            elif wn[:2] == '>=' or wn[:2] == '=>':   # cases '>=a','=>a' : return [a,-999], which is
2668                                                     #                     then interpreted in C++
2669                                                     #                     side as [a,a+1,...,a_nyq]
2670                                                     #                     (CAS-3759)
2671                val = int(wn[2:])
2672                res = [val, -999]
2673                #res = [i for i in xrange(val, self.nchan()/2+1)]
2674            elif wn[-2:] == '<=' or wn[-2:] == '=<': # cases 'a<=','a=<' : return [a,-999], which is
2675                                                     #                     then interpreted in C++
2676                                                     #                     side as [a,a+1,...,a_nyq]
2677                                                     #                     (CAS-3759)
2678                val = int(wn[:-2])
2679                res = [val, -999]
2680                #res = [i for i in xrange(val, self.nchan()/2+1)]
2681            elif wn[0] == '>':                       # case '>a' :         return [a+1,-999], which is
2682                                                     #                     then interpreted in C++
2683                                                     #                     side as [a+1,a+2,...,a_nyq]
2684                                                     #                     (CAS-3759)
2685                val = int(wn[1:])+1
2686                res = [val, -999]
2687                #res = [i for i in xrange(val, self.nchan()/2+1)]
2688            elif wn[-1] == '<':                      # case 'a<' :         return [a+1,-999], which is
2689                                                     #                     then interpreted in C++
2690                                                     #                     side as [a+1,a+2,...,a_nyq]
2691                                                     #                     (CAS-3759)
2692                val = int(wn[:-1])+1
2693                res = [val, -999]
2694                #res = [i for i in xrange(val, self.nchan()/2+1)]
2695
2696            return res
2697        else:
2698            msg = 'wrong value given for addwn/rejwn'
2699            raise RuntimeError(msg)
2700
2701    @asaplog_post_dec
2702    def apply_bltable(self, insitu=None, inbltable=None, outbltable=None, overwrite=None):
2703        """\
2704        Subtract baseline based on parameters written in Baseline Table.
2705
2706        Parameters:
2707            insitu:        if True, baseline fitting/subtraction is done
2708                           in-situ and fitting results is returned. If
2709                           False, a dictionary containing new scantable
2710                           (with baseline subtracted) and fitting results
2711                           is returned.
2712                           The default is taken from .asaprc (False)
2713            inbltable:     name of input baseline table. The row number of
2714                           scantable and that of inbltable must be
2715                           identical.
2716            outbltable:    name of output baseline table where baseline
2717                           parameters and fitting results recorded.
2718                           default is ''(no output).
2719            overwrite:     if True when an existing baseline table is
2720                           specified for outbltable, overwrites it.
2721                           Otherwise there is no harm.
2722                           default is False.
2723        """
2724
2725        try:
2726            varlist = vars()
2727            if inbltable      is None: raise ValueError("bltable missing.")
2728            if outbltable     is None: outbltable     = ''
2729            if overwrite      is None: overwrite      = False
2730
2731            if insitu is None: insitu = rcParams['insitu']
2732            if insitu:
2733                workscan = self
2734            else:
2735                workscan = self.copy()
2736
2737            sres = workscan._apply_bltable(inbltable,
2738                                           outbltable,
2739                                           os.path.exists(outbltable),
2740                                           overwrite)
2741            res = parse_fitresult(sres)
2742
2743            workscan._add_history('apply_bltable', varlist)
2744
2745            if insitu:
2746                self._assign(workscan)
2747                return res
2748            else:
2749                return {'scantable': workscan, 'fitresults': res}
2750       
2751        except RuntimeError, e:
2752            raise_fitting_failure_exception(e)
2753
2754    @asaplog_post_dec
2755    def sub_baseline(self, insitu=None, blinfo=None, bltable=None, overwrite=None):
2756        """\
2757        Subtract baseline based on parameters written in the input list.
2758
2759        Parameters:
2760            insitu:        if True, baseline fitting/subtraction is done
2761                           in-situ and fitting results is returned. If
2762                           False, a dictionary containing new scantable
2763                           (with baseline subtracted) and fitting results
2764                           is returned.
2765                           The default is taken from .asaprc (False)
2766            blinfo:        baseline parameter set stored in a dictionary
2767                           or a list of dictionary. Each dictionary
2768                           corresponds to each spectrum and must contain
2769                           the following keys and values:
2770                             'row': row number,
2771                             'blfunc': function name. available ones include
2772                                       'poly', 'chebyshev', 'cspline' and
2773                                       'sinusoid',
2774                             'order': maximum order of polynomial. needed
2775                                      if blfunc='poly' or 'chebyshev',
2776                             'npiece': number or piecewise polynomial.
2777                                       needed if blfunc='cspline',
2778                             'nwave': a list of sinusoidal wave numbers.
2779                                      needed if blfunc='sinusoid', and
2780                             'masklist': min-max windows for channel mask.
2781                                         the specified ranges will be used
2782                                         for fitting.
2783            bltable:       name of output baseline table where baseline
2784                           parameters and fitting results recorded.
2785                           default is ''(no output).
2786            overwrite:     if True when an existing baseline table is
2787                           specified for bltable, overwrites it.
2788                           Otherwise there is no harm.
2789                           default is False.
2790                           
2791        Example:
2792            sub_baseline(blinfo=[{'row':0, 'blfunc':'poly', 'order':5,
2793                                  'masklist':[[10,350],[352,510]]},
2794                                 {'row':1, 'blfunc':'cspline', 'npiece':3,
2795                                  'masklist':[[3,16],[19,404],[407,511]]}
2796                                  ])
2797
2798                the first spectrum (row=0) will be fitted with polynomial
2799                of order=5 and the next one (row=1) will be fitted with cubic
2800                spline consisting of 3 pieces.
2801        """
2802
2803        try:
2804            varlist = vars()
2805            if blinfo         is None: blinfo         = []
2806            if bltable        is None: bltable        = ''
2807            if overwrite      is None: overwrite      = False
2808
2809            if insitu is None: insitu = rcParams['insitu']
2810            if insitu:
2811                workscan = self
2812            else:
2813                workscan = self.copy()
2814
2815            nrow = workscan.nrow()
2816
2817            in_blinfo = pack_blinfo(blinfo=blinfo, maxirow=nrow)
2818
2819            print "in_blinfo=< "+ str(in_blinfo)+" >"
2820
2821            sres = workscan._sub_baseline(in_blinfo,
2822                                          bltable,
2823                                          os.path.exists(bltable),
2824                                          overwrite)
2825            res = parse_fitresult(sres)
2826           
2827            workscan._add_history('sub_baseline', varlist)
2828
2829            if insitu:
2830                self._assign(workscan)
2831                return res
2832            else:
2833                return {'scantable': workscan, 'fitresults': res}
2834
2835        except RuntimeError, e:
2836            raise_fitting_failure_exception(e)
2837
2838    @asaplog_post_dec
2839    def calc_aic(self, value=None, blfunc=None, order=None, mask=None,
2840                 whichrow=None, uselinefinder=None, edge=None,
2841                 threshold=None, chan_avg_limit=None):
2842        """\
2843        Calculates and returns model selection criteria for a specified
2844        baseline model and a given spectrum data.
2845        Available values include Akaike Information Criterion (AIC), the
2846        corrected Akaike Information Criterion (AICc) by Sugiura(1978),
2847        Bayesian Information Criterion (BIC) and the Generalised Cross
2848        Validation (GCV).
2849
2850        Parameters:
2851            value:         name of model selection criteria to calculate.
2852                           available ones include 'aic', 'aicc', 'bic' and
2853                           'gcv'. default is 'aicc'.
2854            blfunc:        baseline function name. available ones include
2855                           'chebyshev', 'cspline' and 'sinusoid'.
2856                           default is 'chebyshev'.
2857            order:         parameter for basline function. actually stands for
2858                           order of polynomial (order) for 'chebyshev',
2859                           number of spline pieces (npiece) for 'cspline' and
2860                           maximum wave number for 'sinusoid', respectively.
2861                           default is 5 (which is also the default order value
2862                           for [auto_]chebyshev_baseline()).
2863            mask:          an optional mask. default is [].
2864            whichrow:      row number. default is 0 (the first row)
2865            uselinefinder: use sd.linefinder() to flag out line regions
2866                           default is True.
2867            edge:           an optional number of channel to drop at
2868                            the edge of spectrum. If only one value is
2869                            specified, the same number will be dropped
2870                            from both sides of the spectrum. Default
2871                            is to keep all channels. Nested tuples
2872                            represent individual edge selection for
2873                            different IFs (a number of spectral channels
2874                            can be different)
2875                            default is (0, 0).
2876            threshold:      the threshold used by line finder. It is
2877                            better to keep it large as only strong lines
2878                            affect the baseline solution.
2879                            default is 3.
2880            chan_avg_limit: a maximum number of consequtive spectral
2881                            channels to average during the search of
2882                            weak and broad lines. The default is no
2883                            averaging (and no search for weak lines).
2884                            If such lines can affect the fitted baseline
2885                            (e.g. a high order polynomial is fitted),
2886                            increase this parameter (usually values up
2887                            to 8 are reasonable). Most users of this
2888                            method should find the default value sufficient.
2889                            default is 1.
2890
2891        Example:
2892            aic = scan.calc_aic(blfunc='chebyshev', order=5, whichrow=0)
2893        """
2894
2895        try:
2896            varlist = vars()
2897
2898            if value          is None: value          = 'aicc'
2899            if blfunc         is None: blfunc         = 'chebyshev'
2900            if order          is None: order          = 5
2901            if mask           is None: mask           = []
2902            if whichrow       is None: whichrow       = 0
2903            if uselinefinder  is None: uselinefinder  = True
2904            if edge           is None: edge           = (0, 0)
2905            if threshold      is None: threshold      = 3
2906            if chan_avg_limit is None: chan_avg_limit = 1
2907
2908            return self._calc_aic(value, blfunc, order, mask,
2909                                  whichrow, uselinefinder, edge,
2910                                  threshold, chan_avg_limit)
2911           
2912        except RuntimeError, e:
2913            raise_fitting_failure_exception(e)
2914
2915    @asaplog_post_dec
2916    def sinusoid_baseline(self, mask=None, applyfft=None,
2917                          fftmethod=None, fftthresh=None,
2918                          addwn=None, rejwn=None,
2919                          insitu=None,
2920                          clipthresh=None, clipniter=None,
2921                          plot=None,
2922                          getresidual=None,
2923                          showprogress=None, minnrow=None,
2924                          outlog=None,
2925                          blfile=None, csvformat=None,
2926                          bltable=None):
2927        """\
2928        Return a scan which has been baselined (all rows) with sinusoidal
2929        functions.
2930
2931        Parameters:
2932            mask:          an optional mask
2933            applyfft:      if True use some method, such as FFT, to find
2934                           strongest sinusoidal components in the wavenumber
2935                           domain to be used for baseline fitting.
2936                           default is True.
2937            fftmethod:     method to find the strong sinusoidal components.
2938                           now only 'fft' is available and it is the default.
2939            fftthresh:     the threshold to select wave numbers to be used for
2940                           fitting from the distribution of amplitudes in the
2941                           wavenumber domain.
2942                           both float and string values accepted.
2943                           given a float value, the unit is set to sigma.
2944                           for string values, allowed formats include:
2945                               'xsigma' or 'x' (= x-sigma level. e.g.,
2946                               '3sigma'), or
2947                               'topx' (= the x strongest ones, e.g. 'top5').
2948                           default is 3.0 (unit: sigma).
2949            addwn:         the additional wave numbers to be used for fitting.
2950                           list or integer value is accepted to specify every
2951                           wave numbers. also string value can be used in case
2952                           you need to specify wave numbers in a certain range,
2953                           e.g., 'a-b' (= a, a+1, a+2, ..., b-1, b),
2954                                 '<a'  (= 0,1,...,a-2,a-1),
2955                                 '>=a' (= a, a+1, ... up to the maximum wave
2956                                        number corresponding to the Nyquist
2957                                        frequency for the case of FFT).
2958                           default is [0].
2959            rejwn:         the wave numbers NOT to be used for fitting.
2960                           can be set just as addwn but has higher priority:
2961                           wave numbers which are specified both in addwn
2962                           and rejwn will NOT be used. default is [].
2963            insitu:        if False a new scantable is returned.
2964                           Otherwise, the scaling is done in-situ
2965                           The default is taken from .asaprc (False)
2966            clipthresh:    Clipping threshold. (default is 3.0, unit: sigma)
2967            clipniter:     maximum number of iteration of 'clipthresh'-sigma
2968                           clipping (default is 0)
2969            plot:      *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
2970                           plot the fit and the residual. In this each
2971                           indivual fit has to be approved, by typing 'y'
2972                           or 'n'
2973            getresidual:   if False, returns best-fit values instead of
2974                           residual. (default is True)
2975            showprogress:  show progress status for large data.
2976                           default is True.
2977            minnrow:       minimum number of input spectra to show.
2978                           default is 1000.
2979            outlog:        Output the coefficients of the best-fit
2980                           function to logger (default is False)
2981            blfile:        Name of a text file in which the best-fit
2982                           parameter values to be written
2983                           (default is '': no file/logger output)
2984            csvformat:     if True blfile is csv-formatted, default is False.
2985            bltable:       name of a baseline table where fitting results
2986                           (coefficients, rms, etc.) are to be written.
2987                           if given, fitting results will NOT be output to
2988                           scantable (insitu=True) or None will be
2989                           returned (insitu=False).
2990                           (default is "": no table output)
2991
2992        Example:
2993            # return a scan baselined by a combination of sinusoidal curves
2994            # having wave numbers in spectral window up to 10,
2995            # also with 3-sigma clipping, iteration up to 4 times
2996            bscan = scan.sinusoid_baseline(addwn='<=10',clipthresh=3.0,clipniter=4)
2997
2998        Note:
2999            The best-fit parameter values output in logger and/or blfile are now
3000            based on specunit of 'channel'.
3001        """
3002       
3003        try:
3004            varlist = vars()
3005       
3006            if insitu is None: insitu = rcParams['insitu']
3007            if insitu:
3008                workscan = self
3009            else:
3010                workscan = self.copy()
3011           
3012            if mask          is None: mask          = []
3013            if applyfft      is None: applyfft      = True
3014            if fftmethod     is None: fftmethod     = 'fft'
3015            if fftthresh     is None: fftthresh     = 3.0
3016            if addwn         is None: addwn         = [0]
3017            if rejwn         is None: rejwn         = []
3018            if clipthresh    is None: clipthresh    = 3.0
3019            if clipniter     is None: clipniter     = 0
3020            if plot          is None: plot          = False
3021            if getresidual   is None: getresidual   = True
3022            if showprogress  is None: showprogress  = True
3023            if minnrow       is None: minnrow       = 1000
3024            if outlog        is None: outlog        = False
3025            if blfile        is None: blfile        = ''
3026            if csvformat     is None: csvformat     = False
3027            if bltable       is None: bltable       = ''
3028
3029            sapplyfft = 'true' if applyfft else 'false'
3030            fftinfo = ','.join([sapplyfft, fftmethod.lower(), str(fftthresh).lower()])
3031
3032            scsvformat = 'T' if csvformat else 'F'
3033
3034            #CURRENTLY, PLOT=true is UNAVAILABLE UNTIL sinusoidal fitting is implemented as a fitter method.
3035            workscan._sinusoid_baseline(mask,
3036                                        fftinfo,
3037                                        #applyfft, fftmethod.lower(),
3038                                        #str(fftthresh).lower(),
3039                                        workscan._parse_wn(addwn),
3040                                        workscan._parse_wn(rejwn),
3041                                        clipthresh, clipniter,
3042                                        getresidual,
3043                                        pack_progress_params(showprogress,
3044                                                             minnrow),
3045                                        outlog, scsvformat+blfile,
3046                                        bltable)
3047            workscan._add_history('sinusoid_baseline', varlist)
3048
3049            if bltable == '':
3050                if insitu:
3051                    self._assign(workscan)
3052                else:
3053                    return workscan
3054            else:
3055                if not insitu:
3056                    return None
3057           
3058        except RuntimeError, e:
3059            raise_fitting_failure_exception(e)
3060
3061
3062    @asaplog_post_dec
3063    def auto_sinusoid_baseline(self, mask=None, applyfft=None,
3064                               fftmethod=None, fftthresh=None,
3065                               addwn=None, rejwn=None,
3066                               insitu=None,
3067                               clipthresh=None, clipniter=None,
3068                               edge=None, threshold=None, chan_avg_limit=None,
3069                               plot=None,
3070                               getresidual=None,
3071                               showprogress=None, minnrow=None,
3072                               outlog=None,
3073                               blfile=None, csvformat=None,
3074                               bltable=None):
3075        """\
3076        Return a scan which has been baselined (all rows) with sinusoidal
3077        functions.
3078        Spectral lines are detected first using linefinder and masked out
3079        to avoid them affecting the baseline solution.
3080
3081        Parameters:
3082            mask:           an optional mask retreived from scantable
3083            applyfft:       if True use some method, such as FFT, to find
3084                            strongest sinusoidal components in the wavenumber
3085                            domain to be used for baseline fitting.
3086                            default is True.
3087            fftmethod:      method to find the strong sinusoidal components.
3088                            now only 'fft' is available and it is the default.
3089            fftthresh:      the threshold to select wave numbers to be used for
3090                            fitting from the distribution of amplitudes in the
3091                            wavenumber domain.
3092                            both float and string values accepted.
3093                            given a float value, the unit is set to sigma.
3094                            for string values, allowed formats include:
3095                                'xsigma' or 'x' (= x-sigma level. e.g.,
3096                                '3sigma'), or
3097                                'topx' (= the x strongest ones, e.g. 'top5').
3098                            default is 3.0 (unit: sigma).
3099            addwn:          the additional wave numbers to be used for fitting.
3100                            list or integer value is accepted to specify every
3101                            wave numbers. also string value can be used in case
3102                            you need to specify wave numbers in a certain range,
3103                            e.g., 'a-b' (= a, a+1, a+2, ..., b-1, b),
3104                                  '<a'  (= 0,1,...,a-2,a-1),
3105                                  '>=a' (= a, a+1, ... up to the maximum wave
3106                                         number corresponding to the Nyquist
3107                                         frequency for the case of FFT).
3108                            default is [0].
3109            rejwn:          the wave numbers NOT to be used for fitting.
3110                            can be set just as addwn but has higher priority:
3111                            wave numbers which are specified both in addwn
3112                            and rejwn will NOT be used. default is [].
3113            insitu:         if False a new scantable is returned.
3114                            Otherwise, the scaling is done in-situ
3115                            The default is taken from .asaprc (False)
3116            clipthresh:     Clipping threshold. (default is 3.0, unit: sigma)
3117            clipniter:      maximum number of iteration of 'clipthresh'-sigma
3118                            clipping (default is 0)
3119            edge:           an optional number of channel to drop at
3120                            the edge of spectrum. If only one value is
3121                            specified, the same number will be dropped
3122                            from both sides of the spectrum. Default
3123                            is to keep all channels. Nested tuples
3124                            represent individual edge selection for
3125                            different IFs (a number of spectral channels
3126                            can be different)
3127            threshold:      the threshold used by line finder. It is
3128                            better to keep it large as only strong lines
3129                            affect the baseline solution.
3130            chan_avg_limit: a maximum number of consequtive spectral
3131                            channels to average during the search of
3132                            weak and broad lines. The default is no
3133                            averaging (and no search for weak lines).
3134                            If such lines can affect the fitted baseline
3135                            (e.g. a high order polynomial is fitted),
3136                            increase this parameter (usually values up
3137                            to 8 are reasonable). Most users of this
3138                            method should find the default value sufficient.
3139            plot:       *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3140                            plot the fit and the residual. In this each
3141                            indivual fit has to be approved, by typing 'y'
3142                            or 'n'
3143            getresidual:    if False, returns best-fit values instead of
3144                            residual. (default is True)
3145            showprogress:   show progress status for large data.
3146                            default is True.
3147            minnrow:        minimum number of input spectra to show.
3148                            default is 1000.
3149            outlog:         Output the coefficients of the best-fit
3150                            function to logger (default is False)
3151            blfile:         Name of a text file in which the best-fit
3152                            parameter values to be written
3153                            (default is "": no file/logger output)
3154            csvformat:      if True blfile is csv-formatted, default is False.
3155            bltable:        name of a baseline table where fitting results
3156                            (coefficients, rms, etc.) are to be written.
3157                            if given, fitting results will NOT be output to
3158                            scantable (insitu=True) or None will be
3159                            returned (insitu=False).
3160                            (default is "": no table output)
3161
3162        Example:
3163            bscan = scan.auto_sinusoid_baseline(addwn='<=10', insitu=False)
3164       
3165        Note:
3166            The best-fit parameter values output in logger and/or blfile are now
3167            based on specunit of 'channel'.
3168        """
3169
3170        try:
3171            varlist = vars()
3172
3173            if insitu is None: insitu = rcParams['insitu']
3174            if insitu:
3175                workscan = self
3176            else:
3177                workscan = self.copy()
3178           
3179            if mask           is None: mask           = []
3180            if applyfft       is None: applyfft       = True
3181            if fftmethod      is None: fftmethod      = 'fft'
3182            if fftthresh      is None: fftthresh      = 3.0
3183            if addwn          is None: addwn          = [0]
3184            if rejwn          is None: rejwn          = []
3185            if clipthresh     is None: clipthresh     = 3.0
3186            if clipniter      is None: clipniter      = 0
3187            if edge           is None: edge           = (0,0)
3188            if threshold      is None: threshold      = 3
3189            if chan_avg_limit is None: chan_avg_limit = 1
3190            if plot           is None: plot           = False
3191            if getresidual    is None: getresidual    = True
3192            if showprogress   is None: showprogress   = True
3193            if minnrow        is None: minnrow        = 1000
3194            if outlog         is None: outlog         = False
3195            if blfile         is None: blfile         = ''
3196            if csvformat      is None: csvformat      = False
3197            if bltable        is None: bltable        = ''
3198
3199            sapplyfft = 'true' if applyfft else 'false'
3200            fftinfo = ','.join([sapplyfft, fftmethod.lower(), str(fftthresh).lower()])
3201
3202            scsvformat = 'T' if csvformat else 'F'
3203
3204            #CURRENTLY, PLOT=true is UNAVAILABLE UNTIL sinusoidal fitting is implemented as a fitter method.
3205            workscan._auto_sinusoid_baseline(mask,
3206                                             fftinfo,
3207                                             workscan._parse_wn(addwn),
3208                                             workscan._parse_wn(rejwn),
3209                                             clipthresh, clipniter,
3210                                             normalise_edge_param(edge),
3211                                             threshold, chan_avg_limit,
3212                                             getresidual,
3213                                             pack_progress_params(showprogress,
3214                                                                  minnrow),
3215                                             outlog, scsvformat+blfile, bltable)
3216            workscan._add_history("auto_sinusoid_baseline", varlist)
3217
3218            if bltable == '':
3219                if insitu:
3220                    self._assign(workscan)
3221                else:
3222                    return workscan
3223            else:
3224                if not insitu:
3225                    return None
3226           
3227        except RuntimeError, e:
3228            raise_fitting_failure_exception(e)
3229
3230    @asaplog_post_dec
3231    def cspline_baseline(self, mask=None, npiece=None, insitu=None,
3232                         clipthresh=None, clipniter=None, plot=None,
3233                         getresidual=None, showprogress=None, minnrow=None,
3234                         outlog=None, blfile=None, csvformat=None,
3235                         bltable=None):
3236        """\
3237        Return a scan which has been baselined (all rows) by cubic spline
3238        function (piecewise cubic polynomial).
3239
3240        Parameters:
3241            mask:         An optional mask
3242            npiece:       Number of pieces. (default is 2)
3243            insitu:       If False a new scantable is returned.
3244                          Otherwise, the scaling is done in-situ
3245                          The default is taken from .asaprc (False)
3246            clipthresh:   Clipping threshold. (default is 3.0, unit: sigma)
3247            clipniter:    maximum number of iteration of 'clipthresh'-sigma
3248                          clipping (default is 0)
3249            plot:     *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3250                          plot the fit and the residual. In this each
3251                          indivual fit has to be approved, by typing 'y'
3252                          or 'n'
3253            getresidual:  if False, returns best-fit values instead of
3254                          residual. (default is True)
3255            showprogress: show progress status for large data.
3256                          default is True.
3257            minnrow:      minimum number of input spectra to show.
3258                          default is 1000.
3259            outlog:       Output the coefficients of the best-fit
3260                          function to logger (default is False)
3261            blfile:       Name of a text file in which the best-fit
3262                          parameter values to be written
3263                          (default is "": no file/logger output)
3264            csvformat:    if True blfile is csv-formatted, default is False.
3265            bltable:      name of a baseline table where fitting results
3266                          (coefficients, rms, etc.) are to be written.
3267                          if given, fitting results will NOT be output to
3268                          scantable (insitu=True) or None will be
3269                          returned (insitu=False).
3270                          (default is "": no table output)
3271
3272        Example:
3273            # return a scan baselined by a cubic spline consisting of 2 pieces
3274            # (i.e., 1 internal knot),
3275            # also with 3-sigma clipping, iteration up to 4 times
3276            bscan = scan.cspline_baseline(npiece=2,clipthresh=3.0,clipniter=4)
3277       
3278        Note:
3279            The best-fit parameter values output in logger and/or blfile are now
3280            based on specunit of 'channel'.
3281        """
3282       
3283        try:
3284            varlist = vars()
3285           
3286            if insitu is None: insitu = rcParams['insitu']
3287            if insitu:
3288                workscan = self
3289            else:
3290                workscan = self.copy()
3291
3292            if mask         is None: mask         = []
3293            if npiece       is None: npiece       = 2
3294            if clipthresh   is None: clipthresh   = 3.0
3295            if clipniter    is None: clipniter    = 0
3296            if plot         is None: plot         = False
3297            if getresidual  is None: getresidual  = True
3298            if showprogress is None: showprogress = True
3299            if minnrow      is None: minnrow      = 1000
3300            if outlog       is None: outlog       = False
3301            if blfile       is None: blfile       = ''
3302            if csvformat    is None: csvformat    = False
3303            if bltable      is None: bltable      = ''
3304
3305            scsvformat = 'T' if csvformat else 'F'
3306
3307            #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
3308            workscan._cspline_baseline(mask, npiece,
3309                                       clipthresh, clipniter,
3310                                       getresidual,
3311                                       pack_progress_params(showprogress,
3312                                                            minnrow),
3313                                       outlog, scsvformat+blfile,
3314                                       bltable)
3315            workscan._add_history("cspline_baseline", varlist)
3316
3317            if bltable == '':
3318                if insitu:
3319                    self._assign(workscan)
3320                else:
3321                    return workscan
3322            else:
3323                if not insitu:
3324                    return None
3325           
3326        except RuntimeError, e:
3327            raise_fitting_failure_exception(e)
3328
3329    @asaplog_post_dec
3330    def auto_cspline_baseline(self, mask=None, npiece=None, insitu=None,
3331                              clipthresh=None, clipniter=None,
3332                              edge=None, threshold=None, chan_avg_limit=None,
3333                              getresidual=None, plot=None,
3334                              showprogress=None, minnrow=None, outlog=None,
3335                              blfile=None, csvformat=None, bltable=None):
3336        """\
3337        Return a scan which has been baselined (all rows) by cubic spline
3338        function (piecewise cubic polynomial).
3339        Spectral lines are detected first using linefinder and masked out
3340        to avoid them affecting the baseline solution.
3341
3342        Parameters:
3343            mask:           an optional mask retreived from scantable
3344            npiece:         Number of pieces. (default is 2)
3345            insitu:         if False a new scantable is returned.
3346                            Otherwise, the scaling is done in-situ
3347                            The default is taken from .asaprc (False)
3348            clipthresh:     Clipping threshold. (default is 3.0, unit: sigma)
3349            clipniter:      maximum number of iteration of 'clipthresh'-sigma
3350                            clipping (default is 0)
3351            edge:           an optional number of channel to drop at
3352                            the edge of spectrum. If only one value is
3353                            specified, the same number will be dropped
3354                            from both sides of the spectrum. Default
3355                            is to keep all channels. Nested tuples
3356                            represent individual edge selection for
3357                            different IFs (a number of spectral channels
3358                            can be different)
3359            threshold:      the threshold used by line finder. It is
3360                            better to keep it large as only strong lines
3361                            affect the baseline solution.
3362            chan_avg_limit: a maximum number of consequtive spectral
3363                            channels to average during the search of
3364                            weak and broad lines. The default is no
3365                            averaging (and no search for weak lines).
3366                            If such lines can affect the fitted baseline
3367                            (e.g. a high order polynomial is fitted),
3368                            increase this parameter (usually values up
3369                            to 8 are reasonable). Most users of this
3370                            method should find the default value sufficient.
3371            plot:       *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3372                            plot the fit and the residual. In this each
3373                            indivual fit has to be approved, by typing 'y'
3374                            or 'n'
3375            getresidual:    if False, returns best-fit values instead of
3376                            residual. (default is True)
3377            showprogress:   show progress status for large data.
3378                            default is True.
3379            minnrow:        minimum number of input spectra to show.
3380                            default is 1000.
3381            outlog:         Output the coefficients of the best-fit
3382                            function to logger (default is False)
3383            blfile:         Name of a text file in which the best-fit
3384                            parameter values to be written
3385                            (default is "": no file/logger output)
3386            csvformat:      if True blfile is csv-formatted, default is False.
3387            bltable:        name of a baseline table where fitting results
3388                            (coefficients, rms, etc.) are to be written.
3389                            if given, fitting results will NOT be output to
3390                            scantable (insitu=True) or None will be
3391                            returned (insitu=False).
3392                            (default is "": no table output)
3393
3394        Example:
3395            bscan = scan.auto_cspline_baseline(npiece=3, insitu=False)
3396       
3397        Note:
3398            The best-fit parameter values output in logger and/or blfile are now
3399            based on specunit of 'channel'.
3400        """
3401
3402        try:
3403            varlist = vars()
3404
3405            if insitu is None: insitu = rcParams['insitu']
3406            if insitu:
3407                workscan = self
3408            else:
3409                workscan = self.copy()
3410           
3411            #if mask           is None: mask           = [True for i in xrange(workscan.nchan())]
3412            if mask           is None: mask           = []
3413            if npiece         is None: npiece         = 2
3414            if clipthresh     is None: clipthresh     = 3.0
3415            if clipniter      is None: clipniter      = 0
3416            if edge           is None: edge           = (0, 0)
3417            if threshold      is None: threshold      = 3
3418            if chan_avg_limit is None: chan_avg_limit = 1
3419            if plot           is None: plot           = False
3420            if getresidual    is None: getresidual    = True
3421            if showprogress   is None: showprogress   = True
3422            if minnrow        is None: minnrow        = 1000
3423            if outlog         is None: outlog         = False
3424            if blfile         is None: blfile         = ''
3425            if csvformat      is None: csvformat      = False
3426            if bltable        is None: bltable        = ''
3427
3428            scsvformat = 'T' if csvformat else 'F'
3429
3430            #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
3431            workscan._auto_cspline_baseline(mask, npiece,
3432                                            clipthresh, clipniter,
3433                                            normalise_edge_param(edge),
3434                                            threshold,
3435                                            chan_avg_limit, getresidual,
3436                                            pack_progress_params(showprogress,
3437                                                                 minnrow),
3438                                            outlog,
3439                                            scsvformat+blfile,
3440                                            bltable)
3441            workscan._add_history("auto_cspline_baseline", varlist)
3442
3443            if bltable == '':
3444                if insitu:
3445                    self._assign(workscan)
3446                else:
3447                    return workscan
3448            else:
3449                if not insitu:
3450                    return None
3451           
3452        except RuntimeError, e:
3453            raise_fitting_failure_exception(e)
3454
3455    @asaplog_post_dec
3456    def chebyshev_baseline(self, mask=None, order=None, insitu=None,
3457                           clipthresh=None, clipniter=None, plot=None,
3458                           getresidual=None, showprogress=None, minnrow=None,
3459                           outlog=None, blfile=None, csvformat=None,
3460                           bltable=None):
3461        """\
3462        Return a scan which has been baselined (all rows) by Chebyshev polynomials.
3463
3464        Parameters:
3465            mask:         An optional mask
3466            order:        the maximum order of Chebyshev polynomial (default is 5)
3467            insitu:       If False a new scantable is returned.
3468                          Otherwise, the scaling is done in-situ
3469                          The default is taken from .asaprc (False)
3470            clipthresh:   Clipping threshold. (default is 3.0, unit: sigma)
3471            clipniter:    maximum number of iteration of 'clipthresh'-sigma
3472                          clipping (default is 0)
3473            plot:     *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3474                          plot the fit and the residual. In this each
3475                          indivual fit has to be approved, by typing 'y'
3476                          or 'n'
3477            getresidual:  if False, returns best-fit values instead of
3478                          residual. (default is True)
3479            showprogress: show progress status for large data.
3480                          default is True.
3481            minnrow:      minimum number of input spectra to show.
3482                          default is 1000.
3483            outlog:       Output the coefficients of the best-fit
3484                          function to logger (default is False)
3485            blfile:       Name of a text file in which the best-fit
3486                          parameter values to be written
3487                          (default is "": no file/logger output)
3488            csvformat:    if True blfile is csv-formatted, default is False.
3489            bltable:      name of a baseline table where fitting results
3490                          (coefficients, rms, etc.) are to be written.
3491                          if given, fitting results will NOT be output to
3492                          scantable (insitu=True) or None will be
3493                          returned (insitu=False).
3494                          (default is "": no table output)
3495
3496        Example:
3497            # return a scan baselined by a cubic spline consisting of 2 pieces
3498            # (i.e., 1 internal knot),
3499            # also with 3-sigma clipping, iteration up to 4 times
3500            bscan = scan.cspline_baseline(npiece=2,clipthresh=3.0,clipniter=4)
3501       
3502        Note:
3503            The best-fit parameter values output in logger and/or blfile are now
3504            based on specunit of 'channel'.
3505        """
3506       
3507        try:
3508            varlist = vars()
3509           
3510            if insitu is None: insitu = rcParams['insitu']
3511            if insitu:
3512                workscan = self
3513            else:
3514                workscan = self.copy()
3515
3516            if mask         is None: mask         = []
3517            if order        is None: order        = 5
3518            if clipthresh   is None: clipthresh   = 3.0
3519            if clipniter    is None: clipniter    = 0
3520            if plot         is None: plot         = False
3521            if getresidual  is None: getresidual  = True
3522            if showprogress is None: showprogress = True
3523            if minnrow      is None: minnrow      = 1000
3524            if outlog       is None: outlog       = False
3525            if blfile       is None: blfile       = ''
3526            if csvformat    is None: csvformat    = False
3527            if bltable      is None: bltable      = ''
3528
3529            scsvformat = 'T' if csvformat else 'F'
3530
3531            #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
3532            workscan._chebyshev_baseline(mask, order,
3533                                         clipthresh, clipniter,
3534                                         getresidual,
3535                                         pack_progress_params(showprogress,
3536                                                              minnrow),
3537                                         outlog, scsvformat+blfile,
3538                                         bltable)
3539            workscan._add_history("chebyshev_baseline", varlist)
3540
3541            if bltable == '':
3542                if insitu:
3543                    self._assign(workscan)
3544                else:
3545                    return workscan
3546            else:
3547                if not insitu:
3548                    return None
3549           
3550        except RuntimeError, e:
3551            raise_fitting_failure_exception(e)
3552
3553    @asaplog_post_dec
3554    def auto_chebyshev_baseline(self, mask=None, order=None, insitu=None,
3555                              clipthresh=None, clipniter=None,
3556                              edge=None, threshold=None, chan_avg_limit=None,
3557                              getresidual=None, plot=None,
3558                              showprogress=None, minnrow=None, outlog=None,
3559                              blfile=None, csvformat=None, bltable=None):
3560        """\
3561        Return a scan which has been baselined (all rows) by Chebyshev polynomials.
3562        Spectral lines are detected first using linefinder and masked out
3563        to avoid them affecting the baseline solution.
3564
3565        Parameters:
3566            mask:           an optional mask retreived from scantable
3567            order:          the maximum order of Chebyshev polynomial (default is 5)
3568            insitu:         if False a new scantable is returned.
3569                            Otherwise, the scaling is done in-situ
3570                            The default is taken from .asaprc (False)
3571            clipthresh:     Clipping threshold. (default is 3.0, unit: sigma)
3572            clipniter:      maximum number of iteration of 'clipthresh'-sigma
3573                            clipping (default is 0)
3574            edge:           an optional number of channel to drop at
3575                            the edge of spectrum. If only one value is
3576                            specified, the same number will be dropped
3577                            from both sides of the spectrum. Default
3578                            is to keep all channels. Nested tuples
3579                            represent individual edge selection for
3580                            different IFs (a number of spectral channels
3581                            can be different)
3582            threshold:      the threshold used by line finder. It is
3583                            better to keep it large as only strong lines
3584                            affect the baseline solution.
3585            chan_avg_limit: a maximum number of consequtive spectral
3586                            channels to average during the search of
3587                            weak and broad lines. The default is no
3588                            averaging (and no search for weak lines).
3589                            If such lines can affect the fitted baseline
3590                            (e.g. a high order polynomial is fitted),
3591                            increase this parameter (usually values up
3592                            to 8 are reasonable). Most users of this
3593                            method should find the default value sufficient.
3594            plot:       *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3595                            plot the fit and the residual. In this each
3596                            indivual fit has to be approved, by typing 'y'
3597                            or 'n'
3598            getresidual:    if False, returns best-fit values instead of
3599                            residual. (default is True)
3600            showprogress:   show progress status for large data.
3601                            default is True.
3602            minnrow:        minimum number of input spectra to show.
3603                            default is 1000.
3604            outlog:         Output the coefficients of the best-fit
3605                            function to logger (default is False)
3606            blfile:         Name of a text file in which the best-fit
3607                            parameter values to be written
3608                            (default is "": no file/logger output)
3609            csvformat:      if True blfile is csv-formatted, default is False.
3610            bltable:        name of a baseline table where fitting results
3611                            (coefficients, rms, etc.) are to be written.
3612                            if given, fitting results will NOT be output to
3613                            scantable (insitu=True) or None will be
3614                            returned (insitu=False).
3615                            (default is "": no table output)
3616
3617        Example:
3618            bscan = scan.auto_cspline_baseline(npiece=3, insitu=False)
3619       
3620        Note:
3621            The best-fit parameter values output in logger and/or blfile are now
3622            based on specunit of 'channel'.
3623        """
3624
3625        try:
3626            varlist = vars()
3627
3628            if insitu is None: insitu = rcParams['insitu']
3629            if insitu:
3630                workscan = self
3631            else:
3632                workscan = self.copy()
3633           
3634            if mask           is None: mask           = []
3635            if order          is None: order          = 5
3636            if clipthresh     is None: clipthresh     = 3.0
3637            if clipniter      is None: clipniter      = 0
3638            if edge           is None: edge           = (0, 0)
3639            if threshold      is None: threshold      = 3
3640            if chan_avg_limit is None: chan_avg_limit = 1
3641            if plot           is None: plot           = False
3642            if getresidual    is None: getresidual    = True
3643            if showprogress   is None: showprogress   = True
3644            if minnrow        is None: minnrow        = 1000
3645            if outlog         is None: outlog         = False
3646            if blfile         is None: blfile         = ''
3647            if csvformat      is None: csvformat      = False
3648            if bltable        is None: bltable        = ''
3649
3650            scsvformat = 'T' if csvformat else 'F'
3651
3652            #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
3653            workscan._auto_chebyshev_baseline(mask, order,
3654                                              clipthresh, clipniter,
3655                                              normalise_edge_param(edge),
3656                                              threshold,
3657                                              chan_avg_limit, getresidual,
3658                                              pack_progress_params(showprogress,
3659                                                                   minnrow),
3660                                              outlog, scsvformat+blfile,
3661                                              bltable)
3662            workscan._add_history("auto_chebyshev_baseline", varlist)
3663
3664            if bltable == '':
3665                if insitu:
3666                    self._assign(workscan)
3667                else:
3668                    return workscan
3669            else:
3670                if not insitu:
3671                    return None
3672           
3673        except RuntimeError, e:
3674            raise_fitting_failure_exception(e)
3675
3676    @asaplog_post_dec
3677    def poly_baseline(self, mask=None, order=None, insitu=None,
3678                      clipthresh=None, clipniter=None, plot=None,
3679                      getresidual=None, showprogress=None, minnrow=None,
3680                      outlog=None, blfile=None, csvformat=None,
3681                      bltable=None):
3682        """\
3683        Return a scan which has been baselined (all rows) by a polynomial.
3684        Parameters:
3685            mask:         an optional mask
3686            order:        the order of the polynomial (default is 0)
3687            insitu:       if False a new scantable is returned.
3688                          Otherwise, the scaling is done in-situ
3689                          The default is taken from .asaprc (False)
3690            clipthresh:   Clipping threshold. (default is 3.0, unit: sigma)
3691            clipniter:    maximum number of iteration of 'clipthresh'-sigma
3692                          clipping (default is 0)
3693            plot:         plot the fit and the residual. In this each
3694                          indivual fit has to be approved, by typing 'y'
3695                          or 'n'
3696            getresidual:  if False, returns best-fit values instead of
3697                          residual. (default is True)
3698            showprogress: show progress status for large data.
3699                          default is True.
3700            minnrow:      minimum number of input spectra to show.
3701                          default is 1000.
3702            outlog:       Output the coefficients of the best-fit
3703                          function to logger (default is False)
3704            blfile:       Name of a text file in which the best-fit
3705                          parameter values to be written
3706                          (default is "": no file/logger output)
3707            csvformat:    if True blfile is csv-formatted, default is False.
3708            bltable:      name of a baseline table where fitting results
3709                          (coefficients, rms, etc.) are to be written.
3710                          if given, fitting results will NOT be output to
3711                          scantable (insitu=True) or None will be
3712                          returned (insitu=False).
3713                          (default is "": no table output)
3714
3715        Example:
3716            # return a scan baselined by a third order polynomial,
3717            # not using a mask
3718            bscan = scan.poly_baseline(order=3)
3719        """
3720       
3721        try:
3722            varlist = vars()
3723       
3724            if insitu is None:
3725                insitu = rcParams["insitu"]
3726            if insitu:
3727                workscan = self
3728            else:
3729                workscan = self.copy()
3730
3731            if mask         is None: mask         = []
3732            if order        is None: order        = 0
3733            if clipthresh   is None: clipthresh   = 3.0
3734            if clipniter    is None: clipniter    = 0
3735            if plot         is None: plot         = False
3736            if getresidual  is None: getresidual  = True
3737            if showprogress is None: showprogress = True
3738            if minnrow      is None: minnrow      = 1000
3739            if outlog       is None: outlog       = False
3740            if blfile       is None: blfile       = ''
3741            if csvformat    is None: csvformat    = False
3742            if bltable      is None: bltable      = ''
3743
3744            scsvformat = 'T' if csvformat else 'F'
3745
3746            if plot:
3747                outblfile = (blfile != "") and \
3748                    os.path.exists(os.path.expanduser(
3749                                    os.path.expandvars(blfile))
3750                                   )
3751                if outblfile:
3752                    blf = open(blfile, "a")
3753               
3754                f = fitter()
3755                f.set_function(lpoly=order)
3756               
3757                rows = xrange(workscan.nrow())
3758                #if len(rows) > 0: workscan._init_blinfo()
3759
3760                action = "H"
3761                for r in rows:
3762                    f.x = workscan._getabcissa(r)
3763                    f.y = workscan._getspectrum(r)
3764                    if mask:
3765                        f.mask = mask_and(mask, workscan._getmask(r))    # (CAS-1434)
3766                    else: # mask=None
3767                        f.mask = workscan._getmask(r)
3768                   
3769                    f.data = None
3770                    f.fit()
3771
3772                    if action != "Y": # skip plotting when accepting all
3773                        f.plot(residual=True)
3774                    #accept_fit = raw_input("Accept fit ( [y]/n ): ")
3775                    #if accept_fit.upper() == "N":
3776                    #    #workscan._append_blinfo(None, None, None)
3777                    #    continue
3778                    accept_fit = self._get_verify_action("Accept fit?",action)
3779                    if r == 0: action = None
3780                    if accept_fit.upper() == "N":
3781                        continue
3782                    elif accept_fit.upper() == "R":
3783                        break
3784                    elif accept_fit.upper() == "A":
3785                        action = "Y"
3786                   
3787                    blpars = f.get_parameters()
3788                    masklist = workscan.get_masklist(f.mask, row=r, silent=True)
3789                    #workscan._append_blinfo(blpars, masklist, f.mask)
3790                    workscan._setspectrum((f.fitter.getresidual()
3791                                           if getresidual else f.fitter.getfit()), r)
3792                   
3793                    if outblfile:
3794                        rms = workscan.get_rms(f.mask, r)
3795                        dataout = \
3796                            workscan.format_blparams_row(blpars["params"],
3797                                                         blpars["fixed"],
3798                                                         rms, str(masklist),
3799                                                         r, True, csvformat)
3800                        blf.write(dataout)
3801
3802                f._p.unmap()
3803                f._p = None
3804
3805                if outblfile:
3806                    blf.close()
3807            else:
3808                workscan._poly_baseline(mask, order,
3809                                        clipthresh, clipniter, #
3810                                        getresidual,
3811                                        pack_progress_params(showprogress,
3812                                                             minnrow),
3813                                        outlog, scsvformat+blfile,
3814                                        bltable)  #
3815           
3816            workscan._add_history("poly_baseline", varlist)
3817           
3818            if insitu:
3819                self._assign(workscan)
3820            else:
3821                return workscan
3822           
3823        except RuntimeError, e:
3824            raise_fitting_failure_exception(e)
3825
3826    @asaplog_post_dec
3827    def auto_poly_baseline(self, mask=None, order=None, insitu=None,
3828                           clipthresh=None, clipniter=None,
3829                           edge=None, threshold=None, chan_avg_limit=None,
3830                           getresidual=None, plot=None,
3831                           showprogress=None, minnrow=None, outlog=None,
3832                           blfile=None, csvformat=None, bltable=None):
3833        """\
3834        Return a scan which has been baselined (all rows) by a polynomial.
3835        Spectral lines are detected first using linefinder and masked out
3836        to avoid them affecting the baseline solution.
3837
3838        Parameters:
3839            mask:           an optional mask retreived from scantable
3840            order:          the order of the polynomial (default is 0)
3841            insitu:         if False a new scantable is returned.
3842                            Otherwise, the scaling is done in-situ
3843                            The default is taken from .asaprc (False)
3844            clipthresh:     Clipping threshold. (default is 3.0, unit: sigma)
3845            clipniter:      maximum number of iteration of 'clipthresh'-sigma
3846                            clipping (default is 0)
3847            edge:           an optional number of channel to drop at
3848                            the edge of spectrum. If only one value is
3849                            specified, the same number will be dropped
3850                            from both sides of the spectrum. Default
3851                            is to keep all channels. Nested tuples
3852                            represent individual edge selection for
3853                            different IFs (a number of spectral channels
3854                            can be different)
3855            threshold:      the threshold used by line finder. It is
3856                            better to keep it large as only strong lines
3857                            affect the baseline solution.
3858            chan_avg_limit: a maximum number of consequtive spectral
3859                            channels to average during the search of
3860                            weak and broad lines. The default is no
3861                            averaging (and no search for weak lines).
3862                            If such lines can affect the fitted baseline
3863                            (e.g. a high order polynomial is fitted),
3864                            increase this parameter (usually values up
3865                            to 8 are reasonable). Most users of this
3866                            method should find the default value sufficient.
3867            plot:           plot the fit and the residual. In this each
3868                            indivual fit has to be approved, by typing 'y'
3869                            or 'n'
3870            getresidual:    if False, returns best-fit values instead of
3871                            residual. (default is True)
3872            showprogress:   show progress status for large data.
3873                            default is True.
3874            minnrow:        minimum number of input spectra to show.
3875                            default is 1000.
3876            outlog:         Output the coefficients of the best-fit
3877                            function to logger (default is False)
3878            blfile:         Name of a text file in which the best-fit
3879                            parameter values to be written
3880                            (default is "": no file/logger output)
3881            csvformat:      if True blfile is csv-formatted, default is False.
3882            bltable:        name of a baseline table where fitting results
3883                            (coefficients, rms, etc.) are to be written.
3884                            if given, fitting results will NOT be output to
3885                            scantable (insitu=True) or None will be
3886                            returned (insitu=False).
3887                            (default is "": no table output)
3888
3889        Example:
3890            bscan = scan.auto_poly_baseline(order=7, insitu=False)
3891        """
3892
3893        try:
3894            varlist = vars()
3895
3896            if insitu is None:
3897                insitu = rcParams['insitu']
3898            if insitu:
3899                workscan = self
3900            else:
3901                workscan = self.copy()
3902
3903            if mask           is None: mask           = []
3904            if order          is None: order          = 0
3905            if clipthresh     is None: clipthresh     = 3.0
3906            if clipniter      is None: clipniter      = 0
3907            if edge           is None: edge           = (0, 0)
3908            if threshold      is None: threshold      = 3
3909            if chan_avg_limit is None: chan_avg_limit = 1
3910            if plot           is None: plot           = False
3911            if getresidual    is None: getresidual    = True
3912            if showprogress   is None: showprogress   = True
3913            if minnrow        is None: minnrow        = 1000
3914            if outlog         is None: outlog         = False
3915            if blfile         is None: blfile         = ''
3916            if csvformat      is None: csvformat      = False
3917            if bltable        is None: bltable        = ''
3918
3919            scsvformat = 'T' if csvformat else 'F'
3920
3921            edge = normalise_edge_param(edge)
3922
3923            if plot:
3924                outblfile = (blfile != "") and \
3925                    os.path.exists(os.path.expanduser(os.path.expandvars(blfile)))
3926                if outblfile: blf = open(blfile, "a")
3927               
3928                from asap.asaplinefind import linefinder
3929                fl = linefinder()
3930                fl.set_options(threshold=threshold, avg_limit=chan_avg_limit)
3931                fl.set_scan(workscan)
3932               
3933                f = fitter()
3934                f.set_function(lpoly=order)
3935
3936                rows = xrange(workscan.nrow())
3937                #if len(rows) > 0: workscan._init_blinfo()
3938
3939                action = "H"
3940                for r in rows:
3941                    idx = 2*workscan.getif(r)
3942                    if mask:
3943                        msk = mask_and(mask, workscan._getmask(r)) # (CAS-1434)
3944                    else: # mask=None
3945                        msk = workscan._getmask(r)
3946                    fl.find_lines(r, msk, edge[idx:idx+2]) 
3947
3948                    f.x = workscan._getabcissa(r)
3949                    f.y = workscan._getspectrum(r)
3950                    f.mask = fl.get_mask()
3951                    f.data = None
3952                    f.fit()
3953
3954                    if action != "Y": # skip plotting when accepting all
3955                        f.plot(residual=True)
3956                    #accept_fit = raw_input("Accept fit ( [y]/n ): ")
3957                    accept_fit = self._get_verify_action("Accept fit?",action)
3958                    if r == 0: action = None
3959                    if accept_fit.upper() == "N":
3960                        #workscan._append_blinfo(None, None, None)
3961                        continue
3962                    elif accept_fit.upper() == "R":
3963                        break
3964                    elif accept_fit.upper() == "A":
3965                        action = "Y"
3966
3967                    blpars = f.get_parameters()
3968                    masklist = workscan.get_masklist(f.mask, row=r, silent=True)
3969                    #workscan._append_blinfo(blpars, masklist, f.mask)
3970                    workscan._setspectrum(
3971                        (f.fitter.getresidual() if getresidual
3972                                                else f.fitter.getfit()), r
3973                        )
3974
3975                    if outblfile:
3976                        rms = workscan.get_rms(f.mask, r)
3977                        dataout = \
3978                            workscan.format_blparams_row(blpars["params"],
3979                                                         blpars["fixed"],
3980                                                         rms, str(masklist),
3981                                                         r, True, csvformat)
3982                        blf.write(dataout)
3983                   
3984                f._p.unmap()
3985                f._p = None
3986
3987                if outblfile: blf.close()
3988            else:
3989                workscan._auto_poly_baseline(mask, order,
3990                                             clipthresh, clipniter,
3991                                             edge, threshold,
3992                                             chan_avg_limit, getresidual,
3993                                             pack_progress_params(showprogress,
3994                                                                  minnrow),
3995                                             outlog, scsvformat+blfile,
3996                                             bltable)
3997            workscan._add_history("auto_poly_baseline", varlist)
3998
3999            if bltable == '':
4000                if insitu:
4001                    self._assign(workscan)
4002                else:
4003                    return workscan
4004            else:
4005                if not insitu:
4006                    return None
4007           
4008        except RuntimeError, e:
4009            raise_fitting_failure_exception(e)
4010
4011    def _init_blinfo(self):
4012        """\
4013        Initialise the following three auxiliary members:
4014           blpars : parameters of the best-fit baseline,
4015           masklists : mask data (edge positions of masked channels) and
4016           actualmask : mask data (in boolean list),
4017        to keep for use later (including output to logger/text files).
4018        Used by poly_baseline() and auto_poly_baseline() in case of
4019        'plot=True'.
4020        """
4021        self.blpars = []
4022        self.masklists = []
4023        self.actualmask = []
4024        return
4025
4026    def _append_blinfo(self, data_blpars, data_masklists, data_actualmask):
4027        """\
4028        Append baseline-fitting related info to blpars, masklist and
4029        actualmask.
4030        """
4031        self.blpars.append(data_blpars)
4032        self.masklists.append(data_masklists)
4033        self.actualmask.append(data_actualmask)
4034        return
4035       
4036    @asaplog_post_dec
4037    def rotate_linpolphase(self, angle):
4038        """\
4039        Rotate the phase of the complex polarization O=Q+iU correlation.
4040        This is always done in situ in the raw data.  So if you call this
4041        function more than once then each call rotates the phase further.
4042
4043        Parameters:
4044
4045            angle:   The angle (degrees) to rotate (add) by.
4046
4047        Example::
4048
4049            scan.rotate_linpolphase(2.3)
4050
4051        """
4052        varlist = vars()
4053        self._math._rotate_linpolphase(self, angle)
4054        self._add_history("rotate_linpolphase", varlist)
4055        return
4056
4057    @asaplog_post_dec
4058    def rotate_xyphase(self, angle):
4059        """\
4060        Rotate the phase of the XY correlation.  This is always done in situ
4061        in the data.  So if you call this function more than once
4062        then each call rotates the phase further.
4063
4064        Parameters:
4065
4066            angle:   The angle (degrees) to rotate (add) by.
4067
4068        Example::
4069
4070            scan.rotate_xyphase(2.3)
4071
4072        """
4073        varlist = vars()
4074        self._math._rotate_xyphase(self, angle)
4075        self._add_history("rotate_xyphase", varlist)
4076        return
4077
4078    @asaplog_post_dec
4079    def swap_linears(self):
4080        """\
4081        Swap the linear polarisations XX and YY, or better the first two
4082        polarisations as this also works for ciculars.
4083        """
4084        varlist = vars()
4085        self._math._swap_linears(self)
4086        self._add_history("swap_linears", varlist)
4087        return
4088
4089    @asaplog_post_dec
4090    def invert_phase(self):
4091        """\
4092        Invert the phase of the complex polarisation
4093        """
4094        varlist = vars()
4095        self._math._invert_phase(self)
4096        self._add_history("invert_phase", varlist)
4097        return
4098
4099    @asaplog_post_dec
4100    def add(self, offset, insitu=None):
4101        """\
4102        Return a scan where all spectra have the offset added
4103
4104        Parameters:
4105
4106            offset:      the offset
4107
4108            insitu:      if False a new scantable is returned.
4109                         Otherwise, the scaling is done in-situ
4110                         The default is taken from .asaprc (False)
4111
4112        """
4113        if insitu is None: insitu = rcParams['insitu']
4114        self._math._setinsitu(insitu)
4115        varlist = vars()
4116        s = scantable(self._math._unaryop(self, offset, "ADD", False))
4117        s._add_history("add", varlist)
4118        if insitu:
4119            self._assign(s)
4120        else:
4121            return s
4122
4123    @asaplog_post_dec
4124    def scale(self, factor, tsys=True, insitu=None):
4125        """\
4126
4127        Return a scan where all spectra are scaled by the given 'factor'
4128
4129        Parameters:
4130
4131            factor:      the scaling factor (float or 1D float list)
4132
4133            insitu:      if False a new scantable is returned.
4134                         Otherwise, the scaling is done in-situ
4135                         The default is taken from .asaprc (False)
4136
4137            tsys:        if True (default) then apply the operation to Tsys
4138                         as well as the data
4139
4140        """
4141        if insitu is None: insitu = rcParams['insitu']
4142        self._math._setinsitu(insitu)
4143        varlist = vars()
4144        s = None
4145        import numpy
4146        if isinstance(factor, list) or isinstance(factor, numpy.ndarray):
4147            if isinstance(factor[0], list) or isinstance(factor[0],
4148                                                         numpy.ndarray):
4149                from asapmath import _array2dOp
4150                s = _array2dOp( self, factor, "MUL", tsys, insitu )
4151            else:
4152                s = scantable( self._math._arrayop( self, factor,
4153                                                    "MUL", tsys ) )
4154        else:
4155            s = scantable(self._math._unaryop(self, factor, "MUL", tsys))
4156        s._add_history("scale", varlist)
4157        if insitu:
4158            self._assign(s)
4159        else:
4160            return s
4161
4162    @preserve_selection
4163    def set_sourcetype(self, match, matchtype="pattern",
4164                       sourcetype="reference"):
4165        """\
4166        Set the type of the source to be an source or reference scan
4167        using the provided pattern.
4168
4169        Parameters:
4170
4171            match:          a Unix style pattern, regular expression or selector
4172
4173            matchtype:      'pattern' (default) UNIX style pattern or
4174                            'regex' regular expression
4175
4176            sourcetype:     the type of the source to use (source/reference)
4177
4178        """
4179        varlist = vars()
4180        stype = -1
4181        if sourcetype.lower().startswith("r") or sourcetype.lower() == "off":
4182            stype = 1
4183        elif sourcetype.lower().startswith("s") or sourcetype.lower() == "on":
4184            stype = 0
4185        else:
4186            raise ValueError("Illegal sourcetype use s(ource)/on or r(eference)/off")
4187        if matchtype.lower().startswith("p"):
4188            matchtype = "pattern"
4189        elif matchtype.lower().startswith("r"):
4190            matchtype = "regex"
4191        else:
4192            raise ValueError("Illegal matchtype, use p(attern) or r(egex)")
4193        sel = selector()
4194        if isinstance(match, selector):
4195            sel = match
4196        else:
4197            sel.set_query("SRCNAME=%s('%s')" % (matchtype, match))
4198        self.set_selection(sel)
4199        self._setsourcetype(stype)
4200        self._add_history("set_sourcetype", varlist)
4201
4202    @asaplog_post_dec
4203    @preserve_selection
4204    def auto_quotient(self, preserve=True, mode='paired', verify=False):
4205        """\
4206        This function allows to build quotients automatically.
4207        It assumes the observation to have the same number of
4208        "ons" and "offs"
4209
4210        Parameters:
4211
4212            preserve:       you can preserve (default) the continuum or
4213                            remove it.  The equations used are
4214
4215                            preserve: Output = Toff * (on/off) - Toff
4216
4217                            remove:   Output = Toff * (on/off) - Ton
4218
4219            mode:           the on/off detection mode
4220                            'paired' (default)
4221                            identifies 'off' scans by the
4222                            trailing '_R' (Mopra/Parkes) or
4223                            '_e'/'_w' (Tid) and matches
4224                            on/off pairs from the observing pattern
4225                            'time'
4226                            finds the closest off in time
4227
4228        .. todo:: verify argument is not implemented
4229
4230        """
4231        varlist = vars()
4232        modes = ["time", "paired"]
4233        if not mode in modes:
4234            msg = "please provide valid mode. Valid modes are %s" % (modes)
4235            raise ValueError(msg)
4236        s = None
4237        if mode.lower() == "paired":
4238            sel = self.get_selection()
4239            sel.set_query("SRCTYPE==psoff")
4240            self.set_selection(sel)
4241            offs = self.copy()
4242            sel.set_query("SRCTYPE==pson")
4243            self.set_selection(sel)
4244            ons = self.copy()
4245            s = scantable(self._math._quotient(ons, offs, preserve))
4246        elif mode.lower() == "time":
4247            s = scantable(self._math._auto_quotient(self, mode, preserve))
4248        s._add_history("auto_quotient", varlist)
4249        return s
4250
4251    @asaplog_post_dec
4252    def mx_quotient(self, mask = None, weight='median', preserve=True):
4253        """\
4254        Form a quotient using "off" beams when observing in "MX" mode.
4255
4256        Parameters:
4257
4258            mask:           an optional mask to be used when weight == 'stddev'
4259
4260            weight:         How to average the off beams.  Default is 'median'.
4261
4262            preserve:       you can preserve (default) the continuum or
4263                            remove it.  The equations used are:
4264
4265                                preserve: Output = Toff * (on/off) - Toff
4266
4267                                remove:   Output = Toff * (on/off) - Ton
4268
4269        """
4270        mask = mask or ()
4271        varlist = vars()
4272        on = scantable(self._math._mx_extract(self, 'on'))
4273        preoff = scantable(self._math._mx_extract(self, 'off'))
4274        off = preoff.average_time(mask=mask, weight=weight, scanav=False)
4275        from asapmath  import quotient
4276        q = quotient(on, off, preserve)
4277        q._add_history("mx_quotient", varlist)
4278        return q
4279
4280    @asaplog_post_dec
4281    def freq_switch(self, insitu=None):
4282        """\
4283        Apply frequency switching to the data.
4284
4285        Parameters:
4286
4287            insitu:      if False a new scantable is returned.
4288                         Otherwise, the swictching is done in-situ
4289                         The default is taken from .asaprc (False)
4290
4291        """
4292        if insitu is None: insitu = rcParams['insitu']
4293        self._math._setinsitu(insitu)
4294        varlist = vars()
4295        s = scantable(self._math._freqswitch(self))
4296        s._add_history("freq_switch", varlist)
4297        if insitu:
4298            self._assign(s)
4299        else:
4300            return s
4301
4302    @asaplog_post_dec
4303    def recalc_azel(self):
4304        """Recalculate the azimuth and elevation for each position."""
4305        varlist = vars()
4306        self._recalcazel()
4307        self._add_history("recalc_azel", varlist)
4308        return
4309
4310    @asaplog_post_dec
4311    def __add__(self, other):
4312        """
4313        implicit on all axes and on Tsys
4314        """
4315        varlist = vars()
4316        s = self.__op( other, "ADD" )
4317        s._add_history("operator +", varlist)
4318        return s
4319
4320    @asaplog_post_dec
4321    def __sub__(self, other):
4322        """
4323        implicit on all axes and on Tsys
4324        """
4325        varlist = vars()
4326        s = self.__op( other, "SUB" )
4327        s._add_history("operator -", varlist)
4328        return s
4329
4330    @asaplog_post_dec
4331    def __mul__(self, other):
4332        """
4333        implicit on all axes and on Tsys
4334        """
4335        varlist = vars()
4336        s = self.__op( other, "MUL" ) ;
4337        s._add_history("operator *", varlist)
4338        return s
4339
4340
4341    @asaplog_post_dec
4342    def __div__(self, other):
4343        """
4344        implicit on all axes and on Tsys
4345        """
4346        varlist = vars()
4347        s = self.__op( other, "DIV" )
4348        s._add_history("operator /", varlist)
4349        return s
4350
4351    @asaplog_post_dec
4352    def __op( self, other, mode ):
4353        s = None
4354        if isinstance(other, scantable):
4355            s = scantable(self._math._binaryop(self, other, mode))
4356        elif isinstance(other, float):
4357            if other == 0.0:
4358                raise ZeroDivisionError("Dividing by zero is not recommended")
4359            s = scantable(self._math._unaryop(self, other, mode, False))
4360        elif isinstance(other, list) or isinstance(other, numpy.ndarray):
4361            if isinstance(other[0], list) \
4362                    or isinstance(other[0], numpy.ndarray):
4363                from asapmath import _array2dOp
4364                s = _array2dOp( self, other, mode, False )
4365            else:
4366                s = scantable( self._math._arrayop( self, other,
4367                                                    mode, False ) )
4368        else:
4369            raise TypeError("Other input is not a scantable or float value")
4370        return s
4371
4372    @asaplog_post_dec
4373    def get_fit(self, row=0):
4374        """\
4375        Print or return the stored fits for a row in the scantable
4376
4377        Parameters:
4378
4379            row:    the row which the fit has been applied to.
4380
4381        """
4382        if row > self.nrow():
4383            return
4384        from asap.asapfit import asapfit
4385        fit = asapfit(self._getfit(row))
4386        asaplog.push( '%s' %(fit) )
4387        return fit.as_dict()
4388
4389    @preserve_selection
4390    def flag_nans(self):
4391        """\
4392        Utility function to flag NaN values in the scantable.
4393        """
4394        import numpy
4395        basesel = self.get_selection()
4396        for i in range(self.nrow()):
4397            sel = self.get_row_selector(i)
4398            self.set_selection(basesel+sel)
4399            nans = numpy.isnan(self._getspectrum(0))
4400        if numpy.any(nans):
4401            bnans = [ bool(v) for v in nans]
4402            self.flag(bnans)
4403
4404    def get_row_selector(self, rowno):
4405        return selector(rows=[rowno])
4406
4407    def _add_history(self, funcname, parameters):
4408        if not rcParams['scantable.history']:
4409            return
4410        # create date
4411        sep = "##"
4412        from datetime import datetime
4413        dstr = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
4414        hist = dstr+sep
4415        hist += funcname+sep#cdate+sep
4416        if parameters.has_key('self'):
4417            del parameters['self']
4418        for k, v in parameters.iteritems():
4419            if type(v) is dict:
4420                for k2, v2 in v.iteritems():
4421                    hist += k2
4422                    hist += "="
4423                    if isinstance(v2, scantable):
4424                        hist += 'scantable'
4425                    elif k2 == 'mask':
4426                        if isinstance(v2, list) or isinstance(v2, tuple):
4427                            hist += str(self._zip_mask(v2))
4428                        else:
4429                            hist += str(v2)
4430                    else:
4431                        hist += str(v2)
4432            else:
4433                hist += k
4434                hist += "="
4435                if isinstance(v, scantable):
4436                    hist += 'scantable'
4437                elif k == 'mask':
4438                    if isinstance(v, list) or isinstance(v, tuple):
4439                        hist += str(self._zip_mask(v))
4440                    else:
4441                        hist += str(v)
4442                else:
4443                    hist += str(v)
4444            hist += sep
4445        hist = hist[:-2] # remove trailing '##'
4446        self._addhistory(hist)
4447
4448
4449    def _zip_mask(self, mask):
4450        mask = list(mask)
4451        i = 0
4452        segments = []
4453        while mask[i:].count(1):
4454            i += mask[i:].index(1)
4455            if mask[i:].count(0):
4456                j = i + mask[i:].index(0)
4457            else:
4458                j = len(mask)
4459            segments.append([i, j])
4460            i = j
4461        return segments
4462
4463    def _get_ordinate_label(self):
4464        fu = "("+self.get_fluxunit()+")"
4465        import re
4466        lbl = "Intensity"
4467        if re.match(".K.", fu):
4468            lbl = "Brightness Temperature "+ fu
4469        elif re.match(".Jy.", fu):
4470            lbl = "Flux density "+ fu
4471        return lbl
4472
4473    def _check_ifs(self):
4474#        return len(set([self.nchan(i) for i in self.getifnos()])) == 1
4475        nchans = [self.nchan(i) for i in self.getifnos()]
4476        nchans = filter(lambda t: t > 0, nchans)
4477        return (sum(nchans)/len(nchans) == nchans[0])
4478
4479    @asaplog_post_dec
4480    def _fill(self, names, unit, average, opts={}):
4481        first = True
4482        fullnames = []
4483        for name in names:
4484            name = os.path.expandvars(name)
4485            name = os.path.expanduser(name)
4486            if not os.path.exists(name):
4487                msg = "File '%s' does not exists" % (name)
4488                raise IOError(msg)
4489            fullnames.append(name)
4490        if average:
4491            asaplog.push('Auto averaging integrations')
4492        stype = int(rcParams['scantable.storage'].lower() == 'disk')
4493        for name in fullnames:
4494            tbl = Scantable(stype)
4495            if is_ms( name ):
4496                r = msfiller( tbl )
4497            else:
4498                r = filler( tbl )
4499            msg = "Importing %s..." % (name)
4500            asaplog.push(msg, False)
4501            r.open(name, opts)
4502            rx = rcParams['scantable.reference']
4503            r.setreferenceexpr(rx)
4504            r.fill()
4505            if average:
4506                tbl = self._math._average((tbl, ), (), 'NONE', 'SCAN')
4507            if not first:
4508                tbl = self._math._merge([self, tbl])
4509            Scantable.__init__(self, tbl)
4510            r.close()
4511            del r, tbl
4512            first = False
4513            #flush log
4514        asaplog.post()
4515        if unit is not None:
4516            self.set_fluxunit(unit)
4517        if not is_casapy():
4518            self.set_freqframe(rcParams['scantable.freqframe'])
4519
4520    def _get_verify_action( self, msg, action=None ):
4521        valid_act = ['Y', 'N', 'A', 'R']
4522        if not action or not isinstance(action, str):
4523            action = raw_input("%s [Y/n/a/r] (h for help): " % msg)
4524        if action == '':
4525            return "Y"
4526        elif (action.upper()[0] in valid_act):
4527            return action.upper()[0]
4528        elif (action.upper()[0] in ['H','?']):
4529            print "Available actions of verification [Y|n|a|r]"
4530            print " Y : Yes for current data (default)"
4531            print " N : No for current data"
4532            print " A : Accept all in the following and exit from verification"
4533            print " R : Reject all in the following and exit from verification"
4534            print " H or ?: help (show this message)"
4535            return self._get_verify_action(msg)
4536        else:
4537            return 'Y'
4538
4539    def __getitem__(self, key):
4540        if key < 0:
4541            key += self.nrow()
4542        if key >= self.nrow():
4543            raise IndexError("Row index out of range.")
4544        return self._getspectrum(key)
4545
4546    def __setitem__(self, key, value):
4547        if key < 0:
4548            key += self.nrow()
4549        if key >= self.nrow():
4550            raise IndexError("Row index out of range.")
4551        if not hasattr(value, "__len__") or \
4552                len(value) > self.nchan(self.getif(key)):
4553            raise ValueError("Spectrum length doesn't match.")
4554        return self._setspectrum(value, key)
4555
4556    def __len__(self):
4557        return self.nrow()
4558
4559    def __iter__(self):
4560        for i in range(len(self)):
4561            yield self[i]
Note: See TracBrowser for help on using the repository browser.