source: trunk/python/scantable.py @ 2861

Last change on this file since 2861 was 2844, checked in by Takeshi Nakazato, 11 years ago

New Development: No

JIRA Issue: Yes CAS-5535

Ready for Test: Yes

Interface Changes: Yes

What Interface Changed: Removed freq_tolsr option from scantable constructor

Test Programs: sdsave unit test

Put in Release Notes: No

Module(s): sd

Description: Describe your changes here...

The parameter freq_tolsr is removed from scantable constructor.
It is removed from python layer as well as C++ layer.
Now the code always behaves like 'freq_tolsr=False'.

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