source: trunk/python/scantable.py @ 2772

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

New Development: No

JIRA Issue: No

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s): sd.scantable

Description: argument order change in baselining functions: mask at first, and order at second (for poly).


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