source: trunk/python/scantable.py @ 2810

Last change on this file since 2810 was 2810, 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: a bug fix in sd.scantable.pack_blinfo().


  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 181.5 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 == 0:
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, retfitres=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. If False, a new scantable with
2709                           baseline subtracted is returned. Actually,
2710                           format of the returned value depends on both
2711                           insitu and retfitres (see below).
2712                           The default is taken from .asaprc (False)
2713            retfitres:     if True, the results of baseline fitting (i.e.,
2714                           coefficients and rms) are returned.
2715                           default is False.
2716                           The format of the returned value of this
2717                           function varies as follows:
2718                           (1) in case insitu=True and retfitres=True:
2719                               fitting result.
2720                           (2) in case insitu=True and retfitres=False:
2721                               None.
2722                           (3) in case insitu=False and retfitres=True:
2723                               a dictionary containing a new scantable
2724                               (with baseline subtracted) and the fitting
2725                               results.
2726                           (4) in case insitu=False and retfitres=False:
2727                               a new scantable (with baseline subtracted).
2728            inbltable:     name of input baseline table. The row number of
2729                           scantable and that of inbltable must be
2730                           identical.
2731            outbltable:    name of output baseline table where baseline
2732                           parameters and fitting results recorded.
2733                           default is ''(no output).
2734            overwrite:     if True when an existing baseline table is
2735                           specified for outbltable, overwrites it.
2736                           Otherwise there is no harm.
2737                           default is False.
2738        """
2739
2740        try:
2741            varlist = vars()
2742            if retfitres      is None: retfitres      = False
2743            if inbltable      is None: raise ValueError("bltable missing.")
2744            if outbltable     is None: outbltable     = ''
2745            if overwrite      is None: overwrite      = False
2746
2747            if insitu is None: insitu = rcParams['insitu']
2748            if insitu:
2749                workscan = self
2750            else:
2751                workscan = self.copy()
2752
2753            sres = workscan._apply_bltable(inbltable,
2754                                           retfitres,
2755                                           outbltable,
2756                                           os.path.exists(outbltable),
2757                                           overwrite)
2758            if retfitres: res = parse_fitresult(sres)
2759
2760            workscan._add_history('apply_bltable', varlist)
2761
2762            if insitu:
2763                self._assign(workscan)
2764                if retfitres:
2765                    return res
2766                else:
2767                    return None
2768            else:
2769                if retfitres:
2770                    return {'scantable': workscan, 'fitresults': res}
2771                else:
2772                    return workscan
2773       
2774        except RuntimeError, e:
2775            raise_fitting_failure_exception(e)
2776
2777    @asaplog_post_dec
2778    def sub_baseline(self, insitu=None, retfitres=None, blinfo=None, bltable=None, overwrite=None):
2779        """\
2780        Subtract baseline based on parameters written in the input list.
2781
2782        Parameters:
2783            insitu:        if True, baseline fitting/subtraction is done
2784                           in-situ. If False, a new scantable with
2785                           baseline subtracted is returned. Actually,
2786                           format of the returned value depends on both
2787                           insitu and retfitres (see below).
2788                           The default is taken from .asaprc (False)
2789            retfitres:     if True, the results of baseline fitting (i.e.,
2790                           coefficients and rms) are returned.
2791                           default is False.
2792                           The format of the returned value of this
2793                           function varies as follows:
2794                           (1) in case insitu=True and retfitres=True:
2795                               fitting result.
2796                           (2) in case insitu=True and retfitres=False:
2797                               None.
2798                           (3) in case insitu=False and retfitres=True:
2799                               a dictionary containing a new scantable
2800                               (with baseline subtracted) and the fitting
2801                               results.
2802                           (4) in case insitu=False and retfitres=False:
2803                               a new scantable (with baseline subtracted).
2804            blinfo:        baseline parameter set stored in a dictionary
2805                           or a list of dictionary. Each dictionary
2806                           corresponds to each spectrum and must contain
2807                           the following keys and values:
2808                             'row': row number,
2809                             'blfunc': function name. available ones include
2810                                       'poly', 'chebyshev', 'cspline' and
2811                                       'sinusoid',
2812                             'order': maximum order of polynomial. needed
2813                                      if blfunc='poly' or 'chebyshev',
2814                             'npiece': number or piecewise polynomial.
2815                                       needed if blfunc='cspline',
2816                             'nwave': a list of sinusoidal wave numbers.
2817                                      needed if blfunc='sinusoid', and
2818                             'masklist': min-max windows for channel mask.
2819                                         the specified ranges will be used
2820                                         for fitting.
2821            bltable:       name of output baseline table where baseline
2822                           parameters and fitting results recorded.
2823                           default is ''(no output).
2824            overwrite:     if True when an existing baseline table is
2825                           specified for bltable, overwrites it.
2826                           Otherwise there is no harm.
2827                           default is False.
2828                           
2829        Example:
2830            sub_baseline(blinfo=[{'row':0, 'blfunc':'poly', 'order':5,
2831                                  'masklist':[[10,350],[352,510]]},
2832                                 {'row':1, 'blfunc':'cspline', 'npiece':3,
2833                                  'masklist':[[3,16],[19,404],[407,511]]}
2834                                  ])
2835
2836                the first spectrum (row=0) will be fitted with polynomial
2837                of order=5 and the next one (row=1) will be fitted with cubic
2838                spline consisting of 3 pieces.
2839        """
2840
2841        try:
2842            varlist = vars()
2843            if retfitres      is None: retfitres      = False
2844            if blinfo         is None: blinfo         = []
2845            if bltable        is None: bltable        = ''
2846            if overwrite      is None: overwrite      = False
2847
2848            if insitu is None: insitu = rcParams['insitu']
2849            if insitu:
2850                workscan = self
2851            else:
2852                workscan = self.copy()
2853
2854            nrow = workscan.nrow()
2855
2856            in_blinfo = pack_blinfo(blinfo=blinfo, maxirow=nrow)
2857
2858            print "in_blinfo=< "+ str(in_blinfo)+" >"
2859
2860            sres = workscan._sub_baseline(in_blinfo,
2861                                          retfitres,
2862                                          bltable,
2863                                          os.path.exists(bltable),
2864                                          overwrite)
2865            if retfitres: res = parse_fitresult(sres)
2866           
2867            workscan._add_history('sub_baseline', varlist)
2868
2869            if insitu:
2870                self._assign(workscan)
2871                if retfitres:
2872                    return res
2873                else:
2874                    return None
2875            else:
2876                if retfitres:
2877                    return {'scantable': workscan, 'fitresults': res}
2878                else:
2879                    return workscan
2880
2881        except RuntimeError, e:
2882            raise_fitting_failure_exception(e)
2883
2884    @asaplog_post_dec
2885    def calc_aic(self, value=None, blfunc=None, order=None, mask=None,
2886                 whichrow=None, uselinefinder=None, edge=None,
2887                 threshold=None, chan_avg_limit=None):
2888        """\
2889        Calculates and returns model selection criteria for a specified
2890        baseline model and a given spectrum data.
2891        Available values include Akaike Information Criterion (AIC), the
2892        corrected Akaike Information Criterion (AICc) by Sugiura(1978),
2893        Bayesian Information Criterion (BIC) and the Generalised Cross
2894        Validation (GCV).
2895
2896        Parameters:
2897            value:         name of model selection criteria to calculate.
2898                           available ones include 'aic', 'aicc', 'bic' and
2899                           'gcv'. default is 'aicc'.
2900            blfunc:        baseline function name. available ones include
2901                           'chebyshev', 'cspline' and 'sinusoid'.
2902                           default is 'chebyshev'.
2903            order:         parameter for basline function. actually stands for
2904                           order of polynomial (order) for 'chebyshev',
2905                           number of spline pieces (npiece) for 'cspline' and
2906                           maximum wave number for 'sinusoid', respectively.
2907                           default is 5 (which is also the default order value
2908                           for [auto_]chebyshev_baseline()).
2909            mask:          an optional mask. default is [].
2910            whichrow:      row number. default is 0 (the first row)
2911            uselinefinder: use sd.linefinder() to flag out line regions
2912                           default is True.
2913            edge:           an optional number of channel to drop at
2914                            the edge of spectrum. If only one value is
2915                            specified, the same number will be dropped
2916                            from both sides of the spectrum. Default
2917                            is to keep all channels. Nested tuples
2918                            represent individual edge selection for
2919                            different IFs (a number of spectral channels
2920                            can be different)
2921                            default is (0, 0).
2922            threshold:      the threshold used by line finder. It is
2923                            better to keep it large as only strong lines
2924                            affect the baseline solution.
2925                            default is 3.
2926            chan_avg_limit: a maximum number of consequtive spectral
2927                            channels to average during the search of
2928                            weak and broad lines. The default is no
2929                            averaging (and no search for weak lines).
2930                            If such lines can affect the fitted baseline
2931                            (e.g. a high order polynomial is fitted),
2932                            increase this parameter (usually values up
2933                            to 8 are reasonable). Most users of this
2934                            method should find the default value sufficient.
2935                            default is 1.
2936
2937        Example:
2938            aic = scan.calc_aic(blfunc='chebyshev', order=5, whichrow=0)
2939        """
2940
2941        try:
2942            varlist = vars()
2943
2944            if value          is None: value          = 'aicc'
2945            if blfunc         is None: blfunc         = 'chebyshev'
2946            if order          is None: order          = 5
2947            if mask           is None: mask           = []
2948            if whichrow       is None: whichrow       = 0
2949            if uselinefinder  is None: uselinefinder  = True
2950            if edge           is None: edge           = (0, 0)
2951            if threshold      is None: threshold      = 3
2952            if chan_avg_limit is None: chan_avg_limit = 1
2953
2954            return self._calc_aic(value, blfunc, order, mask,
2955                                  whichrow, uselinefinder, edge,
2956                                  threshold, chan_avg_limit)
2957           
2958        except RuntimeError, e:
2959            raise_fitting_failure_exception(e)
2960
2961    @asaplog_post_dec
2962    def sinusoid_baseline(self, mask=None, applyfft=None,
2963                          fftmethod=None, fftthresh=None,
2964                          addwn=None, rejwn=None,
2965                          insitu=None,
2966                          clipthresh=None, clipniter=None,
2967                          plot=None,
2968                          getresidual=None,
2969                          showprogress=None, minnrow=None,
2970                          outlog=None,
2971                          blfile=None, csvformat=None,
2972                          bltable=None):
2973        """\
2974        Return a scan which has been baselined (all rows) with sinusoidal
2975        functions.
2976
2977        Parameters:
2978            mask:          an optional mask
2979            applyfft:      if True use some method, such as FFT, to find
2980                           strongest sinusoidal components in the wavenumber
2981                           domain to be used for baseline fitting.
2982                           default is True.
2983            fftmethod:     method to find the strong sinusoidal components.
2984                           now only 'fft' is available and it is the default.
2985            fftthresh:     the threshold to select wave numbers to be used for
2986                           fitting from the distribution of amplitudes in the
2987                           wavenumber domain.
2988                           both float and string values accepted.
2989                           given a float value, the unit is set to sigma.
2990                           for string values, allowed formats include:
2991                               'xsigma' or 'x' (= x-sigma level. e.g.,
2992                               '3sigma'), or
2993                               'topx' (= the x strongest ones, e.g. 'top5').
2994                           default is 3.0 (unit: sigma).
2995            addwn:         the additional wave numbers to be used for fitting.
2996                           list or integer value is accepted to specify every
2997                           wave numbers. also string value can be used in case
2998                           you need to specify wave numbers in a certain range,
2999                           e.g., 'a-b' (= a, a+1, a+2, ..., b-1, b),
3000                                 '<a'  (= 0,1,...,a-2,a-1),
3001                                 '>=a' (= a, a+1, ... up to the maximum wave
3002                                        number corresponding to the Nyquist
3003                                        frequency for the case of FFT).
3004                           default is [0].
3005            rejwn:         the wave numbers NOT to be used for fitting.
3006                           can be set just as addwn but has higher priority:
3007                           wave numbers which are specified both in addwn
3008                           and rejwn will NOT be used. default is [].
3009            insitu:        if False a new scantable is returned.
3010                           Otherwise, the scaling is done in-situ
3011                           The default is taken from .asaprc (False)
3012            clipthresh:    Clipping threshold. (default is 3.0, unit: sigma)
3013            clipniter:     maximum number of iteration of 'clipthresh'-sigma
3014                           clipping (default is 0)
3015            plot:      *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3016                           plot the fit and the residual. In this each
3017                           indivual fit has to be approved, by typing 'y'
3018                           or 'n'
3019            getresidual:   if False, returns best-fit values instead of
3020                           residual. (default is True)
3021            showprogress:  show progress status for large data.
3022                           default is True.
3023            minnrow:       minimum number of input spectra to show.
3024                           default is 1000.
3025            outlog:        Output the coefficients of the best-fit
3026                           function to logger (default is False)
3027            blfile:        Name of a text file in which the best-fit
3028                           parameter values to be written
3029                           (default is '': no file/logger output)
3030            csvformat:     if True blfile is csv-formatted, default is False.
3031            bltable:       name of a baseline table where fitting results
3032                           (coefficients, rms, etc.) are to be written.
3033                           if given, fitting results will NOT be output to
3034                           scantable (insitu=True) or None will be
3035                           returned (insitu=False).
3036                           (default is "": no table output)
3037
3038        Example:
3039            # return a scan baselined by a combination of sinusoidal curves
3040            # having wave numbers in spectral window up to 10,
3041            # also with 3-sigma clipping, iteration up to 4 times
3042            bscan = scan.sinusoid_baseline(addwn='<=10',clipthresh=3.0,clipniter=4)
3043
3044        Note:
3045            The best-fit parameter values output in logger and/or blfile are now
3046            based on specunit of 'channel'.
3047        """
3048       
3049        try:
3050            varlist = vars()
3051       
3052            if insitu is None: insitu = rcParams['insitu']
3053            if insitu:
3054                workscan = self
3055            else:
3056                workscan = self.copy()
3057           
3058            if mask          is None: mask          = []
3059            if applyfft      is None: applyfft      = True
3060            if fftmethod     is None: fftmethod     = 'fft'
3061            if fftthresh     is None: fftthresh     = 3.0
3062            if addwn         is None: addwn         = [0]
3063            if rejwn         is None: rejwn         = []
3064            if clipthresh    is None: clipthresh    = 3.0
3065            if clipniter     is None: clipniter     = 0
3066            if plot          is None: plot          = False
3067            if getresidual   is None: getresidual   = True
3068            if showprogress  is None: showprogress  = True
3069            if minnrow       is None: minnrow       = 1000
3070            if outlog        is None: outlog        = False
3071            if blfile        is None: blfile        = ''
3072            if csvformat     is None: csvformat     = False
3073            if bltable       is None: bltable       = ''
3074
3075            sapplyfft = 'true' if applyfft else 'false'
3076            fftinfo = ','.join([sapplyfft, fftmethod.lower(), str(fftthresh).lower()])
3077
3078            scsvformat = 'T' if csvformat else 'F'
3079
3080            #CURRENTLY, PLOT=true is UNAVAILABLE UNTIL sinusoidal fitting is implemented as a fitter method.
3081            workscan._sinusoid_baseline(mask,
3082                                        fftinfo,
3083                                        #applyfft, fftmethod.lower(),
3084                                        #str(fftthresh).lower(),
3085                                        workscan._parse_wn(addwn),
3086                                        workscan._parse_wn(rejwn),
3087                                        clipthresh, clipniter,
3088                                        getresidual,
3089                                        pack_progress_params(showprogress,
3090                                                             minnrow),
3091                                        outlog, scsvformat+blfile,
3092                                        bltable)
3093            workscan._add_history('sinusoid_baseline', varlist)
3094
3095            if bltable == '':
3096                if insitu:
3097                    self._assign(workscan)
3098                else:
3099                    return workscan
3100            else:
3101                if not insitu:
3102                    return None
3103           
3104        except RuntimeError, e:
3105            raise_fitting_failure_exception(e)
3106
3107
3108    @asaplog_post_dec
3109    def auto_sinusoid_baseline(self, mask=None, applyfft=None,
3110                               fftmethod=None, fftthresh=None,
3111                               addwn=None, rejwn=None,
3112                               insitu=None,
3113                               clipthresh=None, clipniter=None,
3114                               edge=None, threshold=None, chan_avg_limit=None,
3115                               plot=None,
3116                               getresidual=None,
3117                               showprogress=None, minnrow=None,
3118                               outlog=None,
3119                               blfile=None, csvformat=None,
3120                               bltable=None):
3121        """\
3122        Return a scan which has been baselined (all rows) with sinusoidal
3123        functions.
3124        Spectral lines are detected first using linefinder and masked out
3125        to avoid them affecting the baseline solution.
3126
3127        Parameters:
3128            mask:           an optional mask retreived from scantable
3129            applyfft:       if True use some method, such as FFT, to find
3130                            strongest sinusoidal components in the wavenumber
3131                            domain to be used for baseline fitting.
3132                            default is True.
3133            fftmethod:      method to find the strong sinusoidal components.
3134                            now only 'fft' is available and it is the default.
3135            fftthresh:      the threshold to select wave numbers to be used for
3136                            fitting from the distribution of amplitudes in the
3137                            wavenumber domain.
3138                            both float and string values accepted.
3139                            given a float value, the unit is set to sigma.
3140                            for string values, allowed formats include:
3141                                'xsigma' or 'x' (= x-sigma level. e.g.,
3142                                '3sigma'), or
3143                                'topx' (= the x strongest ones, e.g. 'top5').
3144                            default is 3.0 (unit: sigma).
3145            addwn:          the additional wave numbers to be used for fitting.
3146                            list or integer value is accepted to specify every
3147                            wave numbers. also string value can be used in case
3148                            you need to specify wave numbers in a certain range,
3149                            e.g., 'a-b' (= a, a+1, a+2, ..., b-1, b),
3150                                  '<a'  (= 0,1,...,a-2,a-1),
3151                                  '>=a' (= a, a+1, ... up to the maximum wave
3152                                         number corresponding to the Nyquist
3153                                         frequency for the case of FFT).
3154                            default is [0].
3155            rejwn:          the wave numbers NOT to be used for fitting.
3156                            can be set just as addwn but has higher priority:
3157                            wave numbers which are specified both in addwn
3158                            and rejwn will NOT be used. default is [].
3159            insitu:         if False a new scantable is returned.
3160                            Otherwise, the scaling is done in-situ
3161                            The default is taken from .asaprc (False)
3162            clipthresh:     Clipping threshold. (default is 3.0, unit: sigma)
3163            clipniter:      maximum number of iteration of 'clipthresh'-sigma
3164                            clipping (default is 0)
3165            edge:           an optional number of channel to drop at
3166                            the edge of spectrum. If only one value is
3167                            specified, the same number will be dropped
3168                            from both sides of the spectrum. Default
3169                            is to keep all channels. Nested tuples
3170                            represent individual edge selection for
3171                            different IFs (a number of spectral channels
3172                            can be different)
3173            threshold:      the threshold used by line finder. It is
3174                            better to keep it large as only strong lines
3175                            affect the baseline solution.
3176            chan_avg_limit: a maximum number of consequtive spectral
3177                            channels to average during the search of
3178                            weak and broad lines. The default is no
3179                            averaging (and no search for weak lines).
3180                            If such lines can affect the fitted baseline
3181                            (e.g. a high order polynomial is fitted),
3182                            increase this parameter (usually values up
3183                            to 8 are reasonable). Most users of this
3184                            method should find the default value sufficient.
3185            plot:       *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3186                            plot the fit and the residual. In this each
3187                            indivual fit has to be approved, by typing 'y'
3188                            or 'n'
3189            getresidual:    if False, returns best-fit values instead of
3190                            residual. (default is True)
3191            showprogress:   show progress status for large data.
3192                            default is True.
3193            minnrow:        minimum number of input spectra to show.
3194                            default is 1000.
3195            outlog:         Output the coefficients of the best-fit
3196                            function to logger (default is False)
3197            blfile:         Name of a text file in which the best-fit
3198                            parameter values to be written
3199                            (default is "": no file/logger output)
3200            csvformat:      if True blfile is csv-formatted, default is False.
3201            bltable:        name of a baseline table where fitting results
3202                            (coefficients, rms, etc.) are to be written.
3203                            if given, fitting results will NOT be output to
3204                            scantable (insitu=True) or None will be
3205                            returned (insitu=False).
3206                            (default is "": no table output)
3207
3208        Example:
3209            bscan = scan.auto_sinusoid_baseline(addwn='<=10', insitu=False)
3210       
3211        Note:
3212            The best-fit parameter values output in logger and/or blfile are now
3213            based on specunit of 'channel'.
3214        """
3215
3216        try:
3217            varlist = vars()
3218
3219            if insitu is None: insitu = rcParams['insitu']
3220            if insitu:
3221                workscan = self
3222            else:
3223                workscan = self.copy()
3224           
3225            if mask           is None: mask           = []
3226            if applyfft       is None: applyfft       = True
3227            if fftmethod      is None: fftmethod      = 'fft'
3228            if fftthresh      is None: fftthresh      = 3.0
3229            if addwn          is None: addwn          = [0]
3230            if rejwn          is None: rejwn          = []
3231            if clipthresh     is None: clipthresh     = 3.0
3232            if clipniter      is None: clipniter      = 0
3233            if edge           is None: edge           = (0,0)
3234            if threshold      is None: threshold      = 3
3235            if chan_avg_limit is None: chan_avg_limit = 1
3236            if plot           is None: plot           = False
3237            if getresidual    is None: getresidual    = True
3238            if showprogress   is None: showprogress   = True
3239            if minnrow        is None: minnrow        = 1000
3240            if outlog         is None: outlog         = False
3241            if blfile         is None: blfile         = ''
3242            if csvformat      is None: csvformat      = False
3243            if bltable        is None: bltable        = ''
3244
3245            sapplyfft = 'true' if applyfft else 'false'
3246            fftinfo = ','.join([sapplyfft, fftmethod.lower(), str(fftthresh).lower()])
3247
3248            scsvformat = 'T' if csvformat else 'F'
3249
3250            #CURRENTLY, PLOT=true is UNAVAILABLE UNTIL sinusoidal fitting is implemented as a fitter method.
3251            workscan._auto_sinusoid_baseline(mask,
3252                                             fftinfo,
3253                                             workscan._parse_wn(addwn),
3254                                             workscan._parse_wn(rejwn),
3255                                             clipthresh, clipniter,
3256                                             normalise_edge_param(edge),
3257                                             threshold, chan_avg_limit,
3258                                             getresidual,
3259                                             pack_progress_params(showprogress,
3260                                                                  minnrow),
3261                                             outlog, scsvformat+blfile, bltable)
3262            workscan._add_history("auto_sinusoid_baseline", varlist)
3263
3264            if bltable == '':
3265                if insitu:
3266                    self._assign(workscan)
3267                else:
3268                    return workscan
3269            else:
3270                if not insitu:
3271                    return None
3272           
3273        except RuntimeError, e:
3274            raise_fitting_failure_exception(e)
3275
3276    @asaplog_post_dec
3277    def cspline_baseline(self, mask=None, npiece=None, insitu=None,
3278                         clipthresh=None, clipniter=None, plot=None,
3279                         getresidual=None, showprogress=None, minnrow=None,
3280                         outlog=None, blfile=None, csvformat=None,
3281                         bltable=None):
3282        """\
3283        Return a scan which has been baselined (all rows) by cubic spline
3284        function (piecewise cubic polynomial).
3285
3286        Parameters:
3287            mask:         An optional mask
3288            npiece:       Number of pieces. (default is 2)
3289            insitu:       If False a new scantable is returned.
3290                          Otherwise, the scaling is done in-situ
3291                          The default is taken from .asaprc (False)
3292            clipthresh:   Clipping threshold. (default is 3.0, unit: sigma)
3293            clipniter:    maximum number of iteration of 'clipthresh'-sigma
3294                          clipping (default is 0)
3295            plot:     *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3296                          plot the fit and the residual. In this each
3297                          indivual fit has to be approved, by typing 'y'
3298                          or 'n'
3299            getresidual:  if False, returns best-fit values instead of
3300                          residual. (default is True)
3301            showprogress: show progress status for large data.
3302                          default is True.
3303            minnrow:      minimum number of input spectra to show.
3304                          default is 1000.
3305            outlog:       Output the coefficients of the best-fit
3306                          function to logger (default is False)
3307            blfile:       Name of a text file in which the best-fit
3308                          parameter values to be written
3309                          (default is "": no file/logger output)
3310            csvformat:    if True blfile is csv-formatted, default is False.
3311            bltable:      name of a baseline table where fitting results
3312                          (coefficients, rms, etc.) are to be written.
3313                          if given, fitting results will NOT be output to
3314                          scantable (insitu=True) or None will be
3315                          returned (insitu=False).
3316                          (default is "": no table output)
3317
3318        Example:
3319            # return a scan baselined by a cubic spline consisting of 2 pieces
3320            # (i.e., 1 internal knot),
3321            # also with 3-sigma clipping, iteration up to 4 times
3322            bscan = scan.cspline_baseline(npiece=2,clipthresh=3.0,clipniter=4)
3323       
3324        Note:
3325            The best-fit parameter values output in logger and/or blfile are now
3326            based on specunit of 'channel'.
3327        """
3328       
3329        try:
3330            varlist = vars()
3331           
3332            if insitu is None: insitu = rcParams['insitu']
3333            if insitu:
3334                workscan = self
3335            else:
3336                workscan = self.copy()
3337
3338            if mask         is None: mask         = []
3339            if npiece       is None: npiece       = 2
3340            if clipthresh   is None: clipthresh   = 3.0
3341            if clipniter    is None: clipniter    = 0
3342            if plot         is None: plot         = False
3343            if getresidual  is None: getresidual  = True
3344            if showprogress is None: showprogress = True
3345            if minnrow      is None: minnrow      = 1000
3346            if outlog       is None: outlog       = False
3347            if blfile       is None: blfile       = ''
3348            if csvformat    is None: csvformat    = False
3349            if bltable      is None: bltable      = ''
3350
3351            scsvformat = 'T' if csvformat else 'F'
3352
3353            #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
3354            workscan._cspline_baseline(mask, npiece,
3355                                       clipthresh, clipniter,
3356                                       getresidual,
3357                                       pack_progress_params(showprogress,
3358                                                            minnrow),
3359                                       outlog, scsvformat+blfile,
3360                                       bltable)
3361            workscan._add_history("cspline_baseline", varlist)
3362
3363            if bltable == '':
3364                if insitu:
3365                    self._assign(workscan)
3366                else:
3367                    return workscan
3368            else:
3369                if not insitu:
3370                    return None
3371           
3372        except RuntimeError, e:
3373            raise_fitting_failure_exception(e)
3374
3375    @asaplog_post_dec
3376    def auto_cspline_baseline(self, mask=None, npiece=None, insitu=None,
3377                              clipthresh=None, clipniter=None,
3378                              edge=None, threshold=None, chan_avg_limit=None,
3379                              getresidual=None, plot=None,
3380                              showprogress=None, minnrow=None, outlog=None,
3381                              blfile=None, csvformat=None, bltable=None):
3382        """\
3383        Return a scan which has been baselined (all rows) by cubic spline
3384        function (piecewise cubic polynomial).
3385        Spectral lines are detected first using linefinder and masked out
3386        to avoid them affecting the baseline solution.
3387
3388        Parameters:
3389            mask:           an optional mask retreived from scantable
3390            npiece:         Number of pieces. (default is 2)
3391            insitu:         if False a new scantable is returned.
3392                            Otherwise, the scaling is done in-situ
3393                            The default is taken from .asaprc (False)
3394            clipthresh:     Clipping threshold. (default is 3.0, unit: sigma)
3395            clipniter:      maximum number of iteration of 'clipthresh'-sigma
3396                            clipping (default is 0)
3397            edge:           an optional number of channel to drop at
3398                            the edge of spectrum. If only one value is
3399                            specified, the same number will be dropped
3400                            from both sides of the spectrum. Default
3401                            is to keep all channels. Nested tuples
3402                            represent individual edge selection for
3403                            different IFs (a number of spectral channels
3404                            can be different)
3405            threshold:      the threshold used by line finder. It is
3406                            better to keep it large as only strong lines
3407                            affect the baseline solution.
3408            chan_avg_limit: a maximum number of consequtive spectral
3409                            channels to average during the search of
3410                            weak and broad lines. The default is no
3411                            averaging (and no search for weak lines).
3412                            If such lines can affect the fitted baseline
3413                            (e.g. a high order polynomial is fitted),
3414                            increase this parameter (usually values up
3415                            to 8 are reasonable). Most users of this
3416                            method should find the default value sufficient.
3417            plot:       *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3418                            plot the fit and the residual. In this each
3419                            indivual fit has to be approved, by typing 'y'
3420                            or 'n'
3421            getresidual:    if False, returns best-fit values instead of
3422                            residual. (default is True)
3423            showprogress:   show progress status for large data.
3424                            default is True.
3425            minnrow:        minimum number of input spectra to show.
3426                            default is 1000.
3427            outlog:         Output the coefficients of the best-fit
3428                            function to logger (default is False)
3429            blfile:         Name of a text file in which the best-fit
3430                            parameter values to be written
3431                            (default is "": no file/logger output)
3432            csvformat:      if True blfile is csv-formatted, default is False.
3433            bltable:        name of a baseline table where fitting results
3434                            (coefficients, rms, etc.) are to be written.
3435                            if given, fitting results will NOT be output to
3436                            scantable (insitu=True) or None will be
3437                            returned (insitu=False).
3438                            (default is "": no table output)
3439
3440        Example:
3441            bscan = scan.auto_cspline_baseline(npiece=3, insitu=False)
3442       
3443        Note:
3444            The best-fit parameter values output in logger and/or blfile are now
3445            based on specunit of 'channel'.
3446        """
3447
3448        try:
3449            varlist = vars()
3450
3451            if insitu is None: insitu = rcParams['insitu']
3452            if insitu:
3453                workscan = self
3454            else:
3455                workscan = self.copy()
3456           
3457            #if mask           is None: mask           = [True for i in xrange(workscan.nchan())]
3458            if mask           is None: mask           = []
3459            if npiece         is None: npiece         = 2
3460            if clipthresh     is None: clipthresh     = 3.0
3461            if clipniter      is None: clipniter      = 0
3462            if edge           is None: edge           = (0, 0)
3463            if threshold      is None: threshold      = 3
3464            if chan_avg_limit is None: chan_avg_limit = 1
3465            if plot           is None: plot           = False
3466            if getresidual    is None: getresidual    = True
3467            if showprogress   is None: showprogress   = True
3468            if minnrow        is None: minnrow        = 1000
3469            if outlog         is None: outlog         = False
3470            if blfile         is None: blfile         = ''
3471            if csvformat      is None: csvformat      = False
3472            if bltable        is None: bltable        = ''
3473
3474            scsvformat = 'T' if csvformat else 'F'
3475
3476            #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
3477            workscan._auto_cspline_baseline(mask, npiece,
3478                                            clipthresh, clipniter,
3479                                            normalise_edge_param(edge),
3480                                            threshold,
3481                                            chan_avg_limit, getresidual,
3482                                            pack_progress_params(showprogress,
3483                                                                 minnrow),
3484                                            outlog,
3485                                            scsvformat+blfile,
3486                                            bltable)
3487            workscan._add_history("auto_cspline_baseline", varlist)
3488
3489            if bltable == '':
3490                if insitu:
3491                    self._assign(workscan)
3492                else:
3493                    return workscan
3494            else:
3495                if not insitu:
3496                    return None
3497           
3498        except RuntimeError, e:
3499            raise_fitting_failure_exception(e)
3500
3501    @asaplog_post_dec
3502    def chebyshev_baseline(self, mask=None, order=None, insitu=None,
3503                           clipthresh=None, clipniter=None, plot=None,
3504                           getresidual=None, showprogress=None, minnrow=None,
3505                           outlog=None, blfile=None, csvformat=None,
3506                           bltable=None):
3507        """\
3508        Return a scan which has been baselined (all rows) by Chebyshev polynomials.
3509
3510        Parameters:
3511            mask:         An optional mask
3512            order:        the maximum order of Chebyshev polynomial (default is 5)
3513            insitu:       If False a new scantable is returned.
3514                          Otherwise, the scaling is done in-situ
3515                          The default is taken from .asaprc (False)
3516            clipthresh:   Clipping threshold. (default is 3.0, unit: sigma)
3517            clipniter:    maximum number of iteration of 'clipthresh'-sigma
3518                          clipping (default is 0)
3519            plot:     *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3520                          plot the fit and the residual. In this each
3521                          indivual fit has to be approved, by typing 'y'
3522                          or 'n'
3523            getresidual:  if False, returns best-fit values instead of
3524                          residual. (default is True)
3525            showprogress: show progress status for large data.
3526                          default is True.
3527            minnrow:      minimum number of input spectra to show.
3528                          default is 1000.
3529            outlog:       Output the coefficients of the best-fit
3530                          function to logger (default is False)
3531            blfile:       Name of a text file in which the best-fit
3532                          parameter values to be written
3533                          (default is "": no file/logger output)
3534            csvformat:    if True blfile is csv-formatted, default is False.
3535            bltable:      name of a baseline table where fitting results
3536                          (coefficients, rms, etc.) are to be written.
3537                          if given, fitting results will NOT be output to
3538                          scantable (insitu=True) or None will be
3539                          returned (insitu=False).
3540                          (default is "": no table output)
3541
3542        Example:
3543            # return a scan baselined by a cubic spline consisting of 2 pieces
3544            # (i.e., 1 internal knot),
3545            # also with 3-sigma clipping, iteration up to 4 times
3546            bscan = scan.cspline_baseline(npiece=2,clipthresh=3.0,clipniter=4)
3547       
3548        Note:
3549            The best-fit parameter values output in logger and/or blfile are now
3550            based on specunit of 'channel'.
3551        """
3552       
3553        try:
3554            varlist = vars()
3555           
3556            if insitu is None: insitu = rcParams['insitu']
3557            if insitu:
3558                workscan = self
3559            else:
3560                workscan = self.copy()
3561
3562            if mask         is None: mask         = []
3563            if order        is None: order        = 5
3564            if clipthresh   is None: clipthresh   = 3.0
3565            if clipniter    is None: clipniter    = 0
3566            if plot         is None: plot         = False
3567            if getresidual  is None: getresidual  = True
3568            if showprogress is None: showprogress = True
3569            if minnrow      is None: minnrow      = 1000
3570            if outlog       is None: outlog       = False
3571            if blfile       is None: blfile       = ''
3572            if csvformat    is None: csvformat    = False
3573            if bltable      is None: bltable      = ''
3574
3575            scsvformat = 'T' if csvformat else 'F'
3576
3577            #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
3578            workscan._chebyshev_baseline(mask, order,
3579                                         clipthresh, clipniter,
3580                                         getresidual,
3581                                         pack_progress_params(showprogress,
3582                                                              minnrow),
3583                                         outlog, scsvformat+blfile,
3584                                         bltable)
3585            workscan._add_history("chebyshev_baseline", varlist)
3586
3587            if bltable == '':
3588                if insitu:
3589                    self._assign(workscan)
3590                else:
3591                    return workscan
3592            else:
3593                if not insitu:
3594                    return None
3595           
3596        except RuntimeError, e:
3597            raise_fitting_failure_exception(e)
3598
3599    @asaplog_post_dec
3600    def auto_chebyshev_baseline(self, mask=None, order=None, insitu=None,
3601                              clipthresh=None, clipniter=None,
3602                              edge=None, threshold=None, chan_avg_limit=None,
3603                              getresidual=None, plot=None,
3604                              showprogress=None, minnrow=None, outlog=None,
3605                              blfile=None, csvformat=None, bltable=None):
3606        """\
3607        Return a scan which has been baselined (all rows) by Chebyshev polynomials.
3608        Spectral lines are detected first using linefinder and masked out
3609        to avoid them affecting the baseline solution.
3610
3611        Parameters:
3612            mask:           an optional mask retreived from scantable
3613            order:          the maximum order of Chebyshev polynomial (default is 5)
3614            insitu:         if False a new scantable is returned.
3615                            Otherwise, the scaling is done in-situ
3616                            The default is taken from .asaprc (False)
3617            clipthresh:     Clipping threshold. (default is 3.0, unit: sigma)
3618            clipniter:      maximum number of iteration of 'clipthresh'-sigma
3619                            clipping (default is 0)
3620            edge:           an optional number of channel to drop at
3621                            the edge of spectrum. If only one value is
3622                            specified, the same number will be dropped
3623                            from both sides of the spectrum. Default
3624                            is to keep all channels. Nested tuples
3625                            represent individual edge selection for
3626                            different IFs (a number of spectral channels
3627                            can be different)
3628            threshold:      the threshold used by line finder. It is
3629                            better to keep it large as only strong lines
3630                            affect the baseline solution.
3631            chan_avg_limit: a maximum number of consequtive spectral
3632                            channels to average during the search of
3633                            weak and broad lines. The default is no
3634                            averaging (and no search for weak lines).
3635                            If such lines can affect the fitted baseline
3636                            (e.g. a high order polynomial is fitted),
3637                            increase this parameter (usually values up
3638                            to 8 are reasonable). Most users of this
3639                            method should find the default value sufficient.
3640            plot:       *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3641                            plot the fit and the residual. In this each
3642                            indivual fit has to be approved, by typing 'y'
3643                            or 'n'
3644            getresidual:    if False, returns best-fit values instead of
3645                            residual. (default is True)
3646            showprogress:   show progress status for large data.
3647                            default is True.
3648            minnrow:        minimum number of input spectra to show.
3649                            default is 1000.
3650            outlog:         Output the coefficients of the best-fit
3651                            function to logger (default is False)
3652            blfile:         Name of a text file in which the best-fit
3653                            parameter values to be written
3654                            (default is "": no file/logger output)
3655            csvformat:      if True blfile is csv-formatted, default is False.
3656            bltable:        name of a baseline table where fitting results
3657                            (coefficients, rms, etc.) are to be written.
3658                            if given, fitting results will NOT be output to
3659                            scantable (insitu=True) or None will be
3660                            returned (insitu=False).
3661                            (default is "": no table output)
3662
3663        Example:
3664            bscan = scan.auto_cspline_baseline(npiece=3, insitu=False)
3665       
3666        Note:
3667            The best-fit parameter values output in logger and/or blfile are now
3668            based on specunit of 'channel'.
3669        """
3670
3671        try:
3672            varlist = vars()
3673
3674            if insitu is None: insitu = rcParams['insitu']
3675            if insitu:
3676                workscan = self
3677            else:
3678                workscan = self.copy()
3679           
3680            if mask           is None: mask           = []
3681            if order          is None: order          = 5
3682            if clipthresh     is None: clipthresh     = 3.0
3683            if clipniter      is None: clipniter      = 0
3684            if edge           is None: edge           = (0, 0)
3685            if threshold      is None: threshold      = 3
3686            if chan_avg_limit is None: chan_avg_limit = 1
3687            if plot           is None: plot           = False
3688            if getresidual    is None: getresidual    = True
3689            if showprogress   is None: showprogress   = True
3690            if minnrow        is None: minnrow        = 1000
3691            if outlog         is None: outlog         = False
3692            if blfile         is None: blfile         = ''
3693            if csvformat      is None: csvformat      = False
3694            if bltable        is None: bltable        = ''
3695
3696            scsvformat = 'T' if csvformat else 'F'
3697
3698            #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
3699            workscan._auto_chebyshev_baseline(mask, order,
3700                                              clipthresh, clipniter,
3701                                              normalise_edge_param(edge),
3702                                              threshold,
3703                                              chan_avg_limit, getresidual,
3704                                              pack_progress_params(showprogress,
3705                                                                   minnrow),
3706                                              outlog, scsvformat+blfile,
3707                                              bltable)
3708            workscan._add_history("auto_chebyshev_baseline", varlist)
3709
3710            if bltable == '':
3711                if insitu:
3712                    self._assign(workscan)
3713                else:
3714                    return workscan
3715            else:
3716                if not insitu:
3717                    return None
3718           
3719        except RuntimeError, e:
3720            raise_fitting_failure_exception(e)
3721
3722    @asaplog_post_dec
3723    def poly_baseline(self, mask=None, order=None, insitu=None,
3724                      clipthresh=None, clipniter=None, plot=None,
3725                      getresidual=None, showprogress=None, minnrow=None,
3726                      outlog=None, blfile=None, csvformat=None,
3727                      bltable=None):
3728        """\
3729        Return a scan which has been baselined (all rows) by a polynomial.
3730        Parameters:
3731            mask:         an optional mask
3732            order:        the order of the polynomial (default is 0)
3733            insitu:       if False a new scantable is returned.
3734                          Otherwise, the scaling is done in-situ
3735                          The default is taken from .asaprc (False)
3736            clipthresh:   Clipping threshold. (default is 3.0, unit: sigma)
3737            clipniter:    maximum number of iteration of 'clipthresh'-sigma
3738                          clipping (default is 0)
3739            plot:         plot the fit and the residual. In this each
3740                          indivual fit has to be approved, by typing 'y'
3741                          or 'n'
3742            getresidual:  if False, returns best-fit values instead of
3743                          residual. (default is True)
3744            showprogress: show progress status for large data.
3745                          default is True.
3746            minnrow:      minimum number of input spectra to show.
3747                          default is 1000.
3748            outlog:       Output the coefficients of the best-fit
3749                          function to logger (default is False)
3750            blfile:       Name of a text file in which the best-fit
3751                          parameter values to be written
3752                          (default is "": no file/logger output)
3753            csvformat:    if True blfile is csv-formatted, default is False.
3754            bltable:      name of a baseline table where fitting results
3755                          (coefficients, rms, etc.) are to be written.
3756                          if given, fitting results will NOT be output to
3757                          scantable (insitu=True) or None will be
3758                          returned (insitu=False).
3759                          (default is "": no table output)
3760
3761        Example:
3762            # return a scan baselined by a third order polynomial,
3763            # not using a mask
3764            bscan = scan.poly_baseline(order=3)
3765        """
3766       
3767        try:
3768            varlist = vars()
3769       
3770            if insitu is None:
3771                insitu = rcParams["insitu"]
3772            if insitu:
3773                workscan = self
3774            else:
3775                workscan = self.copy()
3776
3777            if mask         is None: mask         = []
3778            if order        is None: order        = 0
3779            if clipthresh   is None: clipthresh   = 3.0
3780            if clipniter    is None: clipniter    = 0
3781            if plot         is None: plot         = False
3782            if getresidual  is None: getresidual  = True
3783            if showprogress is None: showprogress = True
3784            if minnrow      is None: minnrow      = 1000
3785            if outlog       is None: outlog       = False
3786            if blfile       is None: blfile       = ''
3787            if csvformat    is None: csvformat    = False
3788            if bltable      is None: bltable      = ''
3789
3790            scsvformat = 'T' if csvformat else 'F'
3791
3792            if plot:
3793                outblfile = (blfile != "") and \
3794                    os.path.exists(os.path.expanduser(
3795                                    os.path.expandvars(blfile))
3796                                   )
3797                if outblfile:
3798                    blf = open(blfile, "a")
3799               
3800                f = fitter()
3801                f.set_function(lpoly=order)
3802               
3803                rows = xrange(workscan.nrow())
3804                #if len(rows) > 0: workscan._init_blinfo()
3805
3806                action = "H"
3807                for r in rows:
3808                    f.x = workscan._getabcissa(r)
3809                    f.y = workscan._getspectrum(r)
3810                    if mask:
3811                        f.mask = mask_and(mask, workscan._getmask(r))    # (CAS-1434)
3812                    else: # mask=None
3813                        f.mask = workscan._getmask(r)
3814                   
3815                    f.data = None
3816                    f.fit()
3817
3818                    if action != "Y": # skip plotting when accepting all
3819                        f.plot(residual=True)
3820                    #accept_fit = raw_input("Accept fit ( [y]/n ): ")
3821                    #if accept_fit.upper() == "N":
3822                    #    #workscan._append_blinfo(None, None, None)
3823                    #    continue
3824                    accept_fit = self._get_verify_action("Accept fit?",action)
3825                    if r == 0: action = None
3826                    if accept_fit.upper() == "N":
3827                        continue
3828                    elif accept_fit.upper() == "R":
3829                        break
3830                    elif accept_fit.upper() == "A":
3831                        action = "Y"
3832                   
3833                    blpars = f.get_parameters()
3834                    masklist = workscan.get_masklist(f.mask, row=r, silent=True)
3835                    #workscan._append_blinfo(blpars, masklist, f.mask)
3836                    workscan._setspectrum((f.fitter.getresidual()
3837                                           if getresidual else f.fitter.getfit()), r)
3838                   
3839                    if outblfile:
3840                        rms = workscan.get_rms(f.mask, r)
3841                        dataout = \
3842                            workscan.format_blparams_row(blpars["params"],
3843                                                         blpars["fixed"],
3844                                                         rms, str(masklist),
3845                                                         r, True, csvformat)
3846                        blf.write(dataout)
3847
3848                f._p.unmap()
3849                f._p = None
3850
3851                if outblfile:
3852                    blf.close()
3853            else:
3854                workscan._poly_baseline(mask, order,
3855                                        clipthresh, clipniter, #
3856                                        getresidual,
3857                                        pack_progress_params(showprogress,
3858                                                             minnrow),
3859                                        outlog, scsvformat+blfile,
3860                                        bltable)  #
3861           
3862            workscan._add_history("poly_baseline", varlist)
3863           
3864            if insitu:
3865                self._assign(workscan)
3866            else:
3867                return workscan
3868           
3869        except RuntimeError, e:
3870            raise_fitting_failure_exception(e)
3871
3872    @asaplog_post_dec
3873    def auto_poly_baseline(self, mask=None, order=None, insitu=None,
3874                           clipthresh=None, clipniter=None,
3875                           edge=None, threshold=None, chan_avg_limit=None,
3876                           getresidual=None, plot=None,
3877                           showprogress=None, minnrow=None, outlog=None,
3878                           blfile=None, csvformat=None, bltable=None):
3879        """\
3880        Return a scan which has been baselined (all rows) by a polynomial.
3881        Spectral lines are detected first using linefinder and masked out
3882        to avoid them affecting the baseline solution.
3883
3884        Parameters:
3885            mask:           an optional mask retreived from scantable
3886            order:          the order of the polynomial (default is 0)
3887            insitu:         if False a new scantable is returned.
3888                            Otherwise, the scaling is done in-situ
3889                            The default is taken from .asaprc (False)
3890            clipthresh:     Clipping threshold. (default is 3.0, unit: sigma)
3891            clipniter:      maximum number of iteration of 'clipthresh'-sigma
3892                            clipping (default is 0)
3893            edge:           an optional number of channel to drop at
3894                            the edge of spectrum. If only one value is
3895                            specified, the same number will be dropped
3896                            from both sides of the spectrum. Default
3897                            is to keep all channels. Nested tuples
3898                            represent individual edge selection for
3899                            different IFs (a number of spectral channels
3900                            can be different)
3901            threshold:      the threshold used by line finder. It is
3902                            better to keep it large as only strong lines
3903                            affect the baseline solution.
3904            chan_avg_limit: a maximum number of consequtive spectral
3905                            channels to average during the search of
3906                            weak and broad lines. The default is no
3907                            averaging (and no search for weak lines).
3908                            If such lines can affect the fitted baseline
3909                            (e.g. a high order polynomial is fitted),
3910                            increase this parameter (usually values up
3911                            to 8 are reasonable). Most users of this
3912                            method should find the default value sufficient.
3913            plot:           plot the fit and the residual. In this each
3914                            indivual fit has to be approved, by typing 'y'
3915                            or 'n'
3916            getresidual:    if False, returns best-fit values instead of
3917                            residual. (default is True)
3918            showprogress:   show progress status for large data.
3919                            default is True.
3920            minnrow:        minimum number of input spectra to show.
3921                            default is 1000.
3922            outlog:         Output the coefficients of the best-fit
3923                            function to logger (default is False)
3924            blfile:         Name of a text file in which the best-fit
3925                            parameter values to be written
3926                            (default is "": no file/logger output)
3927            csvformat:      if True blfile is csv-formatted, default is False.
3928            bltable:        name of a baseline table where fitting results
3929                            (coefficients, rms, etc.) are to be written.
3930                            if given, fitting results will NOT be output to
3931                            scantable (insitu=True) or None will be
3932                            returned (insitu=False).
3933                            (default is "": no table output)
3934
3935        Example:
3936            bscan = scan.auto_poly_baseline(order=7, insitu=False)
3937        """
3938
3939        try:
3940            varlist = vars()
3941
3942            if insitu is None:
3943                insitu = rcParams['insitu']
3944            if insitu:
3945                workscan = self
3946            else:
3947                workscan = self.copy()
3948
3949            if mask           is None: mask           = []
3950            if order          is None: order          = 0
3951            if clipthresh     is None: clipthresh     = 3.0
3952            if clipniter      is None: clipniter      = 0
3953            if edge           is None: edge           = (0, 0)
3954            if threshold      is None: threshold      = 3
3955            if chan_avg_limit is None: chan_avg_limit = 1
3956            if plot           is None: plot           = False
3957            if getresidual    is None: getresidual    = True
3958            if showprogress   is None: showprogress   = True
3959            if minnrow        is None: minnrow        = 1000
3960            if outlog         is None: outlog         = False
3961            if blfile         is None: blfile         = ''
3962            if csvformat      is None: csvformat      = False
3963            if bltable        is None: bltable        = ''
3964
3965            scsvformat = 'T' if csvformat else 'F'
3966
3967            edge = normalise_edge_param(edge)
3968
3969            if plot:
3970                outblfile = (blfile != "") and \
3971                    os.path.exists(os.path.expanduser(os.path.expandvars(blfile)))
3972                if outblfile: blf = open(blfile, "a")
3973               
3974                from asap.asaplinefind import linefinder
3975                fl = linefinder()
3976                fl.set_options(threshold=threshold, avg_limit=chan_avg_limit)
3977                fl.set_scan(workscan)
3978               
3979                f = fitter()
3980                f.set_function(lpoly=order)
3981
3982                rows = xrange(workscan.nrow())
3983                #if len(rows) > 0: workscan._init_blinfo()
3984
3985                action = "H"
3986                for r in rows:
3987                    idx = 2*workscan.getif(r)
3988                    if mask:
3989                        msk = mask_and(mask, workscan._getmask(r)) # (CAS-1434)
3990                    else: # mask=None
3991                        msk = workscan._getmask(r)
3992                    fl.find_lines(r, msk, edge[idx:idx+2]) 
3993
3994                    f.x = workscan._getabcissa(r)
3995                    f.y = workscan._getspectrum(r)
3996                    f.mask = fl.get_mask()
3997                    f.data = None
3998                    f.fit()
3999
4000                    if action != "Y": # skip plotting when accepting all
4001                        f.plot(residual=True)
4002                    #accept_fit = raw_input("Accept fit ( [y]/n ): ")
4003                    accept_fit = self._get_verify_action("Accept fit?",action)
4004                    if r == 0: action = None
4005                    if accept_fit.upper() == "N":
4006                        #workscan._append_blinfo(None, None, None)
4007                        continue
4008                    elif accept_fit.upper() == "R":
4009                        break
4010                    elif accept_fit.upper() == "A":
4011                        action = "Y"
4012
4013                    blpars = f.get_parameters()
4014                    masklist = workscan.get_masklist(f.mask, row=r, silent=True)
4015                    #workscan._append_blinfo(blpars, masklist, f.mask)
4016                    workscan._setspectrum(
4017                        (f.fitter.getresidual() if getresidual
4018                                                else f.fitter.getfit()), r
4019                        )
4020
4021                    if outblfile:
4022                        rms = workscan.get_rms(f.mask, r)
4023                        dataout = \
4024                            workscan.format_blparams_row(blpars["params"],
4025                                                         blpars["fixed"],
4026                                                         rms, str(masklist),
4027                                                         r, True, csvformat)
4028                        blf.write(dataout)
4029                   
4030                f._p.unmap()
4031                f._p = None
4032
4033                if outblfile: blf.close()
4034            else:
4035                workscan._auto_poly_baseline(mask, order,
4036                                             clipthresh, clipniter,
4037                                             edge, threshold,
4038                                             chan_avg_limit, getresidual,
4039                                             pack_progress_params(showprogress,
4040                                                                  minnrow),
4041                                             outlog, scsvformat+blfile,
4042                                             bltable)
4043            workscan._add_history("auto_poly_baseline", varlist)
4044
4045            if bltable == '':
4046                if insitu:
4047                    self._assign(workscan)
4048                else:
4049                    return workscan
4050            else:
4051                if not insitu:
4052                    return None
4053           
4054        except RuntimeError, e:
4055            raise_fitting_failure_exception(e)
4056
4057    def _init_blinfo(self):
4058        """\
4059        Initialise the following three auxiliary members:
4060           blpars : parameters of the best-fit baseline,
4061           masklists : mask data (edge positions of masked channels) and
4062           actualmask : mask data (in boolean list),
4063        to keep for use later (including output to logger/text files).
4064        Used by poly_baseline() and auto_poly_baseline() in case of
4065        'plot=True'.
4066        """
4067        self.blpars = []
4068        self.masklists = []
4069        self.actualmask = []
4070        return
4071
4072    def _append_blinfo(self, data_blpars, data_masklists, data_actualmask):
4073        """\
4074        Append baseline-fitting related info to blpars, masklist and
4075        actualmask.
4076        """
4077        self.blpars.append(data_blpars)
4078        self.masklists.append(data_masklists)
4079        self.actualmask.append(data_actualmask)
4080        return
4081       
4082    @asaplog_post_dec
4083    def rotate_linpolphase(self, angle):
4084        """\
4085        Rotate the phase of the complex polarization O=Q+iU correlation.
4086        This is always done in situ in the raw data.  So if you call this
4087        function more than once then each call rotates the phase further.
4088
4089        Parameters:
4090
4091            angle:   The angle (degrees) to rotate (add) by.
4092
4093        Example::
4094
4095            scan.rotate_linpolphase(2.3)
4096
4097        """
4098        varlist = vars()
4099        self._math._rotate_linpolphase(self, angle)
4100        self._add_history("rotate_linpolphase", varlist)
4101        return
4102
4103    @asaplog_post_dec
4104    def rotate_xyphase(self, angle):
4105        """\
4106        Rotate the phase of the XY correlation.  This is always done in situ
4107        in the data.  So if you call this function more than once
4108        then each call rotates the phase further.
4109
4110        Parameters:
4111
4112            angle:   The angle (degrees) to rotate (add) by.
4113
4114        Example::
4115
4116            scan.rotate_xyphase(2.3)
4117
4118        """
4119        varlist = vars()
4120        self._math._rotate_xyphase(self, angle)
4121        self._add_history("rotate_xyphase", varlist)
4122        return
4123
4124    @asaplog_post_dec
4125    def swap_linears(self):
4126        """\
4127        Swap the linear polarisations XX and YY, or better the first two
4128        polarisations as this also works for ciculars.
4129        """
4130        varlist = vars()
4131        self._math._swap_linears(self)
4132        self._add_history("swap_linears", varlist)
4133        return
4134
4135    @asaplog_post_dec
4136    def invert_phase(self):
4137        """\
4138        Invert the phase of the complex polarisation
4139        """
4140        varlist = vars()
4141        self._math._invert_phase(self)
4142        self._add_history("invert_phase", varlist)
4143        return
4144
4145    @asaplog_post_dec
4146    def add(self, offset, insitu=None):
4147        """\
4148        Return a scan where all spectra have the offset added
4149
4150        Parameters:
4151
4152            offset:      the offset
4153
4154            insitu:      if False a new scantable is returned.
4155                         Otherwise, the scaling is done in-situ
4156                         The default is taken from .asaprc (False)
4157
4158        """
4159        if insitu is None: insitu = rcParams['insitu']
4160        self._math._setinsitu(insitu)
4161        varlist = vars()
4162        s = scantable(self._math._unaryop(self, offset, "ADD", False))
4163        s._add_history("add", varlist)
4164        if insitu:
4165            self._assign(s)
4166        else:
4167            return s
4168
4169    @asaplog_post_dec
4170    def scale(self, factor, tsys=True, insitu=None):
4171        """\
4172
4173        Return a scan where all spectra are scaled by the given 'factor'
4174
4175        Parameters:
4176
4177            factor:      the scaling factor (float or 1D float list)
4178
4179            insitu:      if False a new scantable is returned.
4180                         Otherwise, the scaling is done in-situ
4181                         The default is taken from .asaprc (False)
4182
4183            tsys:        if True (default) then apply the operation to Tsys
4184                         as well as the data
4185
4186        """
4187        if insitu is None: insitu = rcParams['insitu']
4188        self._math._setinsitu(insitu)
4189        varlist = vars()
4190        s = None
4191        import numpy
4192        if isinstance(factor, list) or isinstance(factor, numpy.ndarray):
4193            if isinstance(factor[0], list) or isinstance(factor[0],
4194                                                         numpy.ndarray):
4195                from asapmath import _array2dOp
4196                s = _array2dOp( self, factor, "MUL", tsys, insitu )
4197            else:
4198                s = scantable( self._math._arrayop( self, factor,
4199                                                    "MUL", tsys ) )
4200        else:
4201            s = scantable(self._math._unaryop(self, factor, "MUL", tsys))
4202        s._add_history("scale", varlist)
4203        if insitu:
4204            self._assign(s)
4205        else:
4206            return s
4207
4208    @preserve_selection
4209    def set_sourcetype(self, match, matchtype="pattern",
4210                       sourcetype="reference"):
4211        """\
4212        Set the type of the source to be an source or reference scan
4213        using the provided pattern.
4214
4215        Parameters:
4216
4217            match:          a Unix style pattern, regular expression or selector
4218
4219            matchtype:      'pattern' (default) UNIX style pattern or
4220                            'regex' regular expression
4221
4222            sourcetype:     the type of the source to use (source/reference)
4223
4224        """
4225        varlist = vars()
4226        stype = -1
4227        if sourcetype.lower().startswith("r") or sourcetype.lower() == "off":
4228            stype = 1
4229        elif sourcetype.lower().startswith("s") or sourcetype.lower() == "on":
4230            stype = 0
4231        else:
4232            raise ValueError("Illegal sourcetype use s(ource)/on or r(eference)/off")
4233        if matchtype.lower().startswith("p"):
4234            matchtype = "pattern"
4235        elif matchtype.lower().startswith("r"):
4236            matchtype = "regex"
4237        else:
4238            raise ValueError("Illegal matchtype, use p(attern) or r(egex)")
4239        sel = selector()
4240        if isinstance(match, selector):
4241            sel = match
4242        else:
4243            sel.set_query("SRCNAME=%s('%s')" % (matchtype, match))
4244        self.set_selection(sel)
4245        self._setsourcetype(stype)
4246        self._add_history("set_sourcetype", varlist)
4247
4248    @asaplog_post_dec
4249    @preserve_selection
4250    def auto_quotient(self, preserve=True, mode='paired', verify=False):
4251        """\
4252        This function allows to build quotients automatically.
4253        It assumes the observation to have the same number of
4254        "ons" and "offs"
4255
4256        Parameters:
4257
4258            preserve:       you can preserve (default) the continuum or
4259                            remove it.  The equations used are
4260
4261                            preserve: Output = Toff * (on/off) - Toff
4262
4263                            remove:   Output = Toff * (on/off) - Ton
4264
4265            mode:           the on/off detection mode
4266                            'paired' (default)
4267                            identifies 'off' scans by the
4268                            trailing '_R' (Mopra/Parkes) or
4269                            '_e'/'_w' (Tid) and matches
4270                            on/off pairs from the observing pattern
4271                            'time'
4272                            finds the closest off in time
4273
4274        .. todo:: verify argument is not implemented
4275
4276        """
4277        varlist = vars()
4278        modes = ["time", "paired"]
4279        if not mode in modes:
4280            msg = "please provide valid mode. Valid modes are %s" % (modes)
4281            raise ValueError(msg)
4282        s = None
4283        if mode.lower() == "paired":
4284            sel = self.get_selection()
4285            sel.set_query("SRCTYPE==psoff")
4286            self.set_selection(sel)
4287            offs = self.copy()
4288            sel.set_query("SRCTYPE==pson")
4289            self.set_selection(sel)
4290            ons = self.copy()
4291            s = scantable(self._math._quotient(ons, offs, preserve))
4292        elif mode.lower() == "time":
4293            s = scantable(self._math._auto_quotient(self, mode, preserve))
4294        s._add_history("auto_quotient", varlist)
4295        return s
4296
4297    @asaplog_post_dec
4298    def mx_quotient(self, mask = None, weight='median', preserve=True):
4299        """\
4300        Form a quotient using "off" beams when observing in "MX" mode.
4301
4302        Parameters:
4303
4304            mask:           an optional mask to be used when weight == 'stddev'
4305
4306            weight:         How to average the off beams.  Default is 'median'.
4307
4308            preserve:       you can preserve (default) the continuum or
4309                            remove it.  The equations used are:
4310
4311                                preserve: Output = Toff * (on/off) - Toff
4312
4313                                remove:   Output = Toff * (on/off) - Ton
4314
4315        """
4316        mask = mask or ()
4317        varlist = vars()
4318        on = scantable(self._math._mx_extract(self, 'on'))
4319        preoff = scantable(self._math._mx_extract(self, 'off'))
4320        off = preoff.average_time(mask=mask, weight=weight, scanav=False)
4321        from asapmath  import quotient
4322        q = quotient(on, off, preserve)
4323        q._add_history("mx_quotient", varlist)
4324        return q
4325
4326    @asaplog_post_dec
4327    def freq_switch(self, insitu=None):
4328        """\
4329        Apply frequency switching to the data.
4330
4331        Parameters:
4332
4333            insitu:      if False a new scantable is returned.
4334                         Otherwise, the swictching is done in-situ
4335                         The default is taken from .asaprc (False)
4336
4337        """
4338        if insitu is None: insitu = rcParams['insitu']
4339        self._math._setinsitu(insitu)
4340        varlist = vars()
4341        s = scantable(self._math._freqswitch(self))
4342        s._add_history("freq_switch", varlist)
4343        if insitu:
4344            self._assign(s)
4345        else:
4346            return s
4347
4348    @asaplog_post_dec
4349    def recalc_azel(self):
4350        """Recalculate the azimuth and elevation for each position."""
4351        varlist = vars()
4352        self._recalcazel()
4353        self._add_history("recalc_azel", varlist)
4354        return
4355
4356    @asaplog_post_dec
4357    def __add__(self, other):
4358        """
4359        implicit on all axes and on Tsys
4360        """
4361        varlist = vars()
4362        s = self.__op( other, "ADD" )
4363        s._add_history("operator +", varlist)
4364        return s
4365
4366    @asaplog_post_dec
4367    def __sub__(self, other):
4368        """
4369        implicit on all axes and on Tsys
4370        """
4371        varlist = vars()
4372        s = self.__op( other, "SUB" )
4373        s._add_history("operator -", varlist)
4374        return s
4375
4376    @asaplog_post_dec
4377    def __mul__(self, other):
4378        """
4379        implicit on all axes and on Tsys
4380        """
4381        varlist = vars()
4382        s = self.__op( other, "MUL" ) ;
4383        s._add_history("operator *", varlist)
4384        return s
4385
4386
4387    @asaplog_post_dec
4388    def __div__(self, other):
4389        """
4390        implicit on all axes and on Tsys
4391        """
4392        varlist = vars()
4393        s = self.__op( other, "DIV" )
4394        s._add_history("operator /", varlist)
4395        return s
4396
4397    @asaplog_post_dec
4398    def __op( self, other, mode ):
4399        s = None
4400        if isinstance(other, scantable):
4401            s = scantable(self._math._binaryop(self, other, mode))
4402        elif isinstance(other, float):
4403            if other == 0.0:
4404                raise ZeroDivisionError("Dividing by zero is not recommended")
4405            s = scantable(self._math._unaryop(self, other, mode, False))
4406        elif isinstance(other, list) or isinstance(other, numpy.ndarray):
4407            if isinstance(other[0], list) \
4408                    or isinstance(other[0], numpy.ndarray):
4409                from asapmath import _array2dOp
4410                s = _array2dOp( self, other, mode, False )
4411            else:
4412                s = scantable( self._math._arrayop( self, other,
4413                                                    mode, False ) )
4414        else:
4415            raise TypeError("Other input is not a scantable or float value")
4416        return s
4417
4418    @asaplog_post_dec
4419    def get_fit(self, row=0):
4420        """\
4421        Print or return the stored fits for a row in the scantable
4422
4423        Parameters:
4424
4425            row:    the row which the fit has been applied to.
4426
4427        """
4428        if row > self.nrow():
4429            return
4430        from asap.asapfit import asapfit
4431        fit = asapfit(self._getfit(row))
4432        asaplog.push( '%s' %(fit) )
4433        return fit.as_dict()
4434
4435    @preserve_selection
4436    def flag_nans(self):
4437        """\
4438        Utility function to flag NaN values in the scantable.
4439        """
4440        import numpy
4441        basesel = self.get_selection()
4442        for i in range(self.nrow()):
4443            sel = self.get_row_selector(i)
4444            self.set_selection(basesel+sel)
4445            nans = numpy.isnan(self._getspectrum(0))
4446        if numpy.any(nans):
4447            bnans = [ bool(v) for v in nans]
4448            self.flag(bnans)
4449
4450    def get_row_selector(self, rowno):
4451        return selector(rows=[rowno])
4452
4453    def _add_history(self, funcname, parameters):
4454        if not rcParams['scantable.history']:
4455            return
4456        # create date
4457        sep = "##"
4458        from datetime import datetime
4459        dstr = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
4460        hist = dstr+sep
4461        hist += funcname+sep#cdate+sep
4462        if parameters.has_key('self'):
4463            del parameters['self']
4464        for k, v in parameters.iteritems():
4465            if type(v) is dict:
4466                for k2, v2 in v.iteritems():
4467                    hist += k2
4468                    hist += "="
4469                    if isinstance(v2, scantable):
4470                        hist += 'scantable'
4471                    elif k2 == 'mask':
4472                        if isinstance(v2, list) or isinstance(v2, tuple):
4473                            hist += str(self._zip_mask(v2))
4474                        else:
4475                            hist += str(v2)
4476                    else:
4477                        hist += str(v2)
4478            else:
4479                hist += k
4480                hist += "="
4481                if isinstance(v, scantable):
4482                    hist += 'scantable'
4483                elif k == 'mask':
4484                    if isinstance(v, list) or isinstance(v, tuple):
4485                        hist += str(self._zip_mask(v))
4486                    else:
4487                        hist += str(v)
4488                else:
4489                    hist += str(v)
4490            hist += sep
4491        hist = hist[:-2] # remove trailing '##'
4492        self._addhistory(hist)
4493
4494
4495    def _zip_mask(self, mask):
4496        mask = list(mask)
4497        i = 0
4498        segments = []
4499        while mask[i:].count(1):
4500            i += mask[i:].index(1)
4501            if mask[i:].count(0):
4502                j = i + mask[i:].index(0)
4503            else:
4504                j = len(mask)
4505            segments.append([i, j])
4506            i = j
4507        return segments
4508
4509    def _get_ordinate_label(self):
4510        fu = "("+self.get_fluxunit()+")"
4511        import re
4512        lbl = "Intensity"
4513        if re.match(".K.", fu):
4514            lbl = "Brightness Temperature "+ fu
4515        elif re.match(".Jy.", fu):
4516            lbl = "Flux density "+ fu
4517        return lbl
4518
4519    def _check_ifs(self):
4520#        return len(set([self.nchan(i) for i in self.getifnos()])) == 1
4521        nchans = [self.nchan(i) for i in self.getifnos()]
4522        nchans = filter(lambda t: t > 0, nchans)
4523        return (sum(nchans)/len(nchans) == nchans[0])
4524
4525    @asaplog_post_dec
4526    def _fill(self, names, unit, average, opts={}):
4527        first = True
4528        fullnames = []
4529        for name in names:
4530            name = os.path.expandvars(name)
4531            name = os.path.expanduser(name)
4532            if not os.path.exists(name):
4533                msg = "File '%s' does not exists" % (name)
4534                raise IOError(msg)
4535            fullnames.append(name)
4536        if average:
4537            asaplog.push('Auto averaging integrations')
4538        stype = int(rcParams['scantable.storage'].lower() == 'disk')
4539        for name in fullnames:
4540            tbl = Scantable(stype)
4541            if is_ms( name ):
4542                r = msfiller( tbl )
4543            else:
4544                r = filler( tbl )
4545            msg = "Importing %s..." % (name)
4546            asaplog.push(msg, False)
4547            r.open(name, opts)
4548            rx = rcParams['scantable.reference']
4549            r.setreferenceexpr(rx)
4550            r.fill()
4551            if average:
4552                tbl = self._math._average((tbl, ), (), 'NONE', 'SCAN')
4553            if not first:
4554                tbl = self._math._merge([self, tbl])
4555            Scantable.__init__(self, tbl)
4556            r.close()
4557            del r, tbl
4558            first = False
4559            #flush log
4560        asaplog.post()
4561        if unit is not None:
4562            self.set_fluxunit(unit)
4563        if not is_casapy():
4564            self.set_freqframe(rcParams['scantable.freqframe'])
4565
4566    def _get_verify_action( self, msg, action=None ):
4567        valid_act = ['Y', 'N', 'A', 'R']
4568        if not action or not isinstance(action, str):
4569            action = raw_input("%s [Y/n/a/r] (h for help): " % msg)
4570        if action == '':
4571            return "Y"
4572        elif (action.upper()[0] in valid_act):
4573            return action.upper()[0]
4574        elif (action.upper()[0] in ['H','?']):
4575            print "Available actions of verification [Y|n|a|r]"
4576            print " Y : Yes for current data (default)"
4577            print " N : No for current data"
4578            print " A : Accept all in the following and exit from verification"
4579            print " R : Reject all in the following and exit from verification"
4580            print " H or ?: help (show this message)"
4581            return self._get_verify_action(msg)
4582        else:
4583            return 'Y'
4584
4585    def __getitem__(self, key):
4586        if key < 0:
4587            key += self.nrow()
4588        if key >= self.nrow():
4589            raise IndexError("Row index out of range.")
4590        return self._getspectrum(key)
4591
4592    def __setitem__(self, key, value):
4593        if key < 0:
4594            key += self.nrow()
4595        if key >= self.nrow():
4596            raise IndexError("Row index out of range.")
4597        if not hasattr(value, "__len__") or \
4598                len(value) > self.nchan(self.getif(key)):
4599            raise ValueError("Spectrum length doesn't match.")
4600        return self._setspectrum(value, key)
4601
4602    def __len__(self):
4603        return self.nrow()
4604
4605    def __iter__(self):
4606        for i in range(len(self)):
4607            yield self[i]
Note: See TracBrowser for help on using the repository browser.