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
RevLine 
[1846]1"""This module defines the scantable class."""
2
[1697]3import os
[2751]4import re
[2315]5import tempfile
[1948]6import numpy
[1691]7try:
8    from functools import wraps as wraps_dec
9except ImportError:
10    from asap.compatibility import wraps as wraps_dec
11
[1824]12from asap.env import is_casapy
[876]13from asap._asap import Scantable
[2004]14from asap._asap import filler, msfiller
[1824]15from asap.parameters import rcParams
[1862]16from asap.logging import asaplog, asaplog_post_dec
[1824]17from asap.selector import selector
18from asap.linecatalog import linecatalog
[1600]19from asap.coordinate import coordinate
[1859]20from asap.utils import _n_bools, mask_not, mask_and, mask_or, page
[1907]21from asap.asapfitter import fitter
[102]22
[1689]23def preserve_selection(func):
[1691]24    @wraps_dec(func)
[1689]25    def wrap(obj, *args, **kw):
26        basesel = obj.get_selection()
[1857]27        try:
28            val = func(obj, *args, **kw)
29        finally:
30            obj.set_selection(basesel)
[1689]31        return val
32    return wrap
33
[1846]34def is_scantable(filename):
35    """Is the given file a scantable?
[1689]36
[1846]37    Parameters:
38
39        filename: the name of the file/directory to test
40
41    """
[1883]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()
[2753]48        match_pattern = '^Type = (Scantable)? *$'
[2751]49        if re.match(match_pattern,l):
[1883]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'))
[1697]58
[1883]59def is_ms(filename):
60    """Is the given file a MeasurementSet?
[1697]61
[1883]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
[2186]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]
[2277]91            * an empty list/tuple [] - converted to [0, 0] and used for all IFs.
[2186]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.
[2277]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:
[2186]102                      ** when len(edge)!=2
[2277]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].
[2186]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]]
[2277]111                               or [[5,5],10], but can NOT be simplified to [5,10].
[2186]112                               when [5,10] given, it is interpreted as
[2277]113                               [[5,10],[5,10],[5,10],...] instead, as shown before.
[2186]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
[2189]173def pack_progress_params(showprogress, minnrow):
174    return str(showprogress).lower() + ',' + str(minnrow)
175
[2767]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
[876]303class scantable(Scantable):
[1846]304    """\
305        The ASAP container for scans (single-dish data).
[102]306    """
[1819]307
[1862]308    @asaplog_post_dec
[2315]309    def __init__(self, filename, average=None, unit=None, parallactify=None,
310                 **args):
[1846]311        """\
[102]312        Create a scantable from a saved one or make a reference
[1846]313
[102]314        Parameters:
[1846]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
[484]326            unit:         brightness unit; must be consistent with K or Jy.
[1846]327                          Over-rides the default selected by the filler
328                          (input rpfits/sdfits/ms) or replaces the value
329                          in existing scantables
330
[1920]331            antenna:      for MeasurementSet input data only:
[2349]332                          Antenna selection. integer (id) or string
333                          (name or id).
[1846]334
[2349]335            parallactify: Indicate that the data had been parallactified.
336                          Default (false) is taken from rc file.
[1846]337
[2754]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                         
[710]350        """
[976]351        if average is None:
[710]352            average = rcParams['scantable.autoaverage']
[1593]353        parallactify = parallactify or rcParams['scantable.parallactify']
[1259]354        varlist = vars()
[876]355        from asap._asap import stmath
[1819]356        self._math = stmath( rcParams['insitu'] )
[876]357        if isinstance(filename, Scantable):
358            Scantable.__init__(self, filename)
[181]359        else:
[1697]360            if isinstance(filename, str):
[976]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)
[1697]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)
[2008]371                    if average:
372                        self._assign( self.average_time( scanav=True ) )
[1819]373                    # do not reset to the default freqframe
374                    #self.set_freqframe(rcParams['scantable.freqframe'])
[1883]375                elif is_ms(filename):
[1916]376                    # Measurement Set
377                    opts={'ms': {}}
[2753]378                    mskeys=['getpt','antenna','freq_tolsr']
[1916]379                    for key in mskeys:
380                        if key in args.keys():
381                            opts['ms'][key] = args[key]
382                    self._fill([filename], unit, average, opts)
[1893]383                elif os.path.isfile(filename):
[2761]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)
[2350]390                    # only apply to new data not "copy constructor"
391                    self.parallactify(parallactify)
[1883]392                else:
[1819]393                    msg = "The given file '%s'is not a valid " \
394                          "asap table." % (filename)
[1859]395                    raise IOError(msg)
[1118]396            elif (isinstance(filename, list) or isinstance(filename, tuple)) \
[976]397                  and isinstance(filename[-1], str):
[1916]398                self._fill(filename, unit, average)
[1586]399        self.parallactify(parallactify)
[1259]400        self._add_history("scantable", varlist)
[102]401
[1862]402    @asaplog_post_dec
[876]403    def save(self, name=None, format=None, overwrite=False):
[1846]404        """\
[1280]405        Store the scantable on disk. This can be an asap (aips++) Table,
406        SDFITS or MS2 format.
[1846]407
[116]408        Parameters:
[1846]409
[2431]410            name:        the name of the outputfile. For format 'ASCII'
[1093]411                         this is the root file name (data in 'name'.txt
[497]412                         and header in 'name'_header.txt)
[1855]413
[116]414            format:      an optional file format. Default is ASAP.
[1855]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)
[2315]421                            * 'FITS' (save as image FITS - not readable by
422                                      class)
[1855]423                            * 'CLASS' (save as FITS readable by CLASS)
424
[411]425            overwrite:   If the file should be overwritten if it exists.
[256]426                         The default False is to return with warning
[411]427                         without writing the output. USE WITH CARE.
[1855]428
[1846]429        Example::
430
[116]431            scan.save('myscan.asap')
[1118]432            scan.save('myscan.sdfits', 'SDFITS')
[1846]433
[116]434        """
[411]435        from os import path
[1593]436        format = format or rcParams['scantable.save']
[256]437        suffix = '.'+format.lower()
[1118]438        if name is None or name == "":
[256]439            name = 'scantable'+suffix
[718]440            msg = "No filename given. Using default name %s..." % name
441            asaplog.push(msg)
[411]442        name = path.expandvars(name)
[256]443        if path.isfile(name) or path.isdir(name):
444            if not overwrite:
[718]445                msg = "File %s exists." % name
[1859]446                raise IOError(msg)
[451]447        format2 = format.upper()
448        if format2 == 'ASAP':
[116]449            self._save(name)
[2029]450        elif format2 == 'MS2':
451            msopt = {'ms': {'overwrite': overwrite } }
452            from asap._asap import mswriter
453            writer = mswriter( self )
454            writer.write( name, msopt )
[116]455        else:
[989]456            from asap._asap import stwriter as stw
[1118]457            writer = stw(format2)
458            writer.write(self, name)
[116]459        return
460
[102]461    def copy(self):
[1846]462        """Return a copy of this scantable.
463
464        *Note*:
465
[1348]466            This makes a full (deep) copy. scan2 = scan1 makes a reference.
[1846]467
468        Example::
469
[102]470            copiedscan = scan.copy()
[1846]471
[102]472        """
[876]473        sd = scantable(Scantable._copy(self))
[113]474        return sd
475
[1093]476    def drop_scan(self, scanid=None):
[1846]477        """\
[1093]478        Return a new scantable where the specified scan number(s) has(have)
479        been dropped.
[1846]480
[1093]481        Parameters:
[1846]482
[1093]483            scanid:    a (list of) scan number(s)
[1846]484
[1093]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):
[2315]490            raise RuntimeError( 'Please specify a scanno to drop from the'
491                                ' scantable' )
[1859]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)
[1093]499
[1594]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
[102]507    def get_scan(self, scanid=None):
[1855]508        """\
[102]509        Return a specific scan (by scanno) or collection of scans (by
510        source name) in a new scantable.
[1846]511
512        *Note*:
513
[1348]514            See scantable.drop_scan() for the inverse operation.
[1846]515
[102]516        Parameters:
[1846]517
[513]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
[1846]521
522        Example::
523
[513]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())
[1118]529            newscan = scan.get_scan([0, 2, 7, 10])
[1846]530
[102]531        """
532        if scanid is None:
[1859]533            raise RuntimeError( 'Please specify a scan no or name to '
534                                'retrieve from the scantable' )
[102]535        try:
[946]536            bsel = self.get_selection()
537            sel = selector()
[102]538            if type(scanid) is str:
[946]539                sel.set_name(scanid)
[1594]540                return self._select_copy(sel)
[102]541            elif type(scanid) is int:
[946]542                sel.set_scans([scanid])
[1594]543                return self._select_copy(sel)
[381]544            elif type(scanid) is list:
[946]545                sel.set_scans(scanid)
[1594]546                return self._select_copy(sel)
[381]547            else:
[718]548                msg = "Illegal scanid type, use 'int' or 'list' if ints."
[1859]549                raise TypeError(msg)
[102]550        except RuntimeError:
[1859]551            raise
[102]552
553    def __str__(self):
[2315]554        tempFile = tempfile.NamedTemporaryFile()
555        Scantable._summary(self, tempFile.name)
556        tempFile.seek(0)
557        asaplog.clear()
558        return tempFile.file.read()
[102]559
[2315]560    @asaplog_post_dec
[976]561    def summary(self, filename=None):
[1846]562        """\
[102]563        Print a summary of the contents of this scantable.
[1846]564
[102]565        Parameters:
[1846]566
[1931]567            filename:    the name of a file to write the putput to
[102]568                         Default - no file output
[1846]569
[102]570        """
571        if filename is not None:
[256]572            if filename is "":
573                filename = 'scantable_summary.txt'
[415]574            from os.path import expandvars, isdir
[411]575            filename = expandvars(filename)
[2286]576            if isdir(filename):
[718]577                msg = "Illegal file name '%s'." % (filename)
[1859]578                raise IOError(msg)
[2286]579        else:
580            filename = ""
581        Scantable._summary(self, filename)
[710]582
[1512]583    def get_spectrum(self, rowno):
[1471]584        """Return the spectrum for the current row in the scantable as a list.
[1846]585
[1471]586        Parameters:
[1846]587
[1573]588             rowno:   the row number to retrieve the spectrum from
[1846]589
[1471]590        """
591        return self._getspectrum(rowno)
[946]592
[1471]593    def get_mask(self, rowno):
594        """Return the mask for the current row in the scantable as a list.
[1846]595
[1471]596        Parameters:
[1846]597
[1573]598             rowno:   the row number to retrieve the mask from
[1846]599
[1471]600        """
601        return self._getmask(rowno)
602
603    def set_spectrum(self, spec, rowno):
[1938]604        """Set the spectrum for the current row in the scantable.
[1846]605
[1471]606        Parameters:
[1846]607
[1855]608             spec:   the new spectrum
[1846]609
[1855]610             rowno:  the row number to set the spectrum for
611
[1471]612        """
[2348]613        assert(len(spec) == self.nchan(self.getif(rowno)))
[1471]614        return self._setspectrum(spec, rowno)
615
[1600]616    def get_coordinate(self, rowno):
617        """Return the (spectral) coordinate for a a given 'rowno'.
[1846]618
619        *Note*:
620
[1600]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,
[1846]627              i.e.::
[1600]628
[1846]629                  c = myscan.get_coordinate(0)
630                  c.to_frequency(c.get_reference_pixel()) != c.get_reference_value()
631
[1600]632        Parameters:
[1846]633
[1600]634             rowno:    the row number for the spectral coordinate
635
636        """
637        return coordinate(Scantable.get_coordinate(self, rowno))
638
[946]639    def get_selection(self):
[1846]640        """\
[1005]641        Get the selection object currently set on this scantable.
[1846]642
643        Example::
644
[1005]645            sel = scan.get_selection()
646            sel.set_ifs(0)              # select IF 0
647            scan.set_selection(sel)     # apply modified selection
[1846]648
[946]649        """
650        return selector(self._getselection())
651
[1576]652    def set_selection(self, selection=None, **kw):
[1846]653        """\
[1005]654        Select a subset of the data. All following operations on this scantable
655        are only applied to thi selection.
[1846]656
[1005]657        Parameters:
[1697]658
[1846]659            selection:    a selector object (default unset the selection), or
[2431]660                          any combination of 'pols', 'ifs', 'beams', 'scans',
661                          'cycles', 'name', 'query'
[1697]662
[1846]663        Examples::
[1697]664
[1005]665            sel = selector()         # create a selection object
[1118]666            self.set_scans([0, 3])    # select SCANNO 0 and 3
[1005]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
[1697]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
[1846]674
[946]675        """
[1576]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:
[2320]684                        raise KeyError("Invalid selection key '%s', "
685                                       "valid keys are %s" % (k,
686                                                              selector.fields))
[1576]687                selection = selector(**kw)
[946]688        self._setselection(selection)
689
[1819]690    def get_row(self, row=0, insitu=None):
[1846]691        """\
[1819]692        Select a row in the scantable.
693        Return a scantable with single row.
[1846]694
[1819]695        Parameters:
[1846]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
[1819]702        """
[2349]703        if insitu is None:
704            insitu = rcParams['insitu']
[1819]705        if not insitu:
706            workscan = self.copy()
707        else:
708            workscan = self
709        # Select a row
[2349]710        sel = selector()
[1992]711        sel.set_rows([row])
[1819]712        workscan.set_selection(sel)
713        if not workscan.nrow() == 1:
[2349]714            msg = "Could not identify single row. %d rows selected." \
715                % (workscan.nrow())
[1819]716            raise RuntimeError(msg)
717        if insitu:
718            self._assign(workscan)
719        else:
720            return workscan
721
[1862]722    @asaplog_post_dec
[1907]723    def stats(self, stat='stddev', mask=None, form='3.3f', row=None):
[1846]724        """\
[135]725        Determine the specified statistic of the current beam/if/pol
[102]726        Takes a 'mask' as an optional parameter to specify which
727        channels should be excluded.
[1846]728
[102]729        Parameters:
[1846]730
[1819]731            stat:    'min', 'max', 'min_abc', 'max_abc', 'sumsq', 'sum',
732                     'mean', 'var', 'stddev', 'avdev', 'rms', 'median'
[1855]733
[135]734            mask:    an optional mask specifying where the statistic
[102]735                     should be determined.
[1855]736
[1819]737            form:    format string to print statistic values
[1846]738
[1907]739            row:     row number of spectrum to process.
740                     (default is None: for all rows)
[1846]741
[1907]742        Example:
[113]743            scan.set_unit('channel')
[1118]744            msk = scan.create_mask([100, 200], [500, 600])
[135]745            scan.stats(stat='mean', mask=m)
[1846]746
[102]747        """
[1593]748        mask = mask or []
[876]749        if not self._check_ifs():
[1118]750            raise ValueError("Cannot apply mask as the IFs have different "
751                             "number of channels. Please use setselection() "
752                             "to select individual IFs")
[1819]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 = []
[1907]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))
[256]765
[1819]766        #def cb(i):
767        #    return statvals[i]
[256]768
[1819]769        #return self._row_callback(cb, stat)
[102]770
[1819]771        label=stat
772        #callback=cb
773        out = ""
774        #outvec = []
775        sep = '-'*50
[1907]776
777        if row == None:
778            rows = xrange(self.nrow())
779        elif isinstance(row, int):
780            rows = [ row ]
781
782        for i in rows:
[1819]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)
[1907]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))
[1819]801            #outvec.append(callback(i))
[1907]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'
[1819]808            out +=  sep+"\n"
809
[1859]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
[1819]828        return statvals
829
830    def chan2data(self, rowno=0, chan=0):
[1846]831        """\
[1819]832        Returns channel/frequency/velocity and spectral value
833        at an arbitrary row and channel in the scantable.
[1846]834
[1819]835        Parameters:
[1846]836
[1819]837            rowno:   a row number in the scantable. Default is the
838                     first row, i.e. rowno=0
[1855]839
[1819]840            chan:    a channel in the scantable. Default is the first
841                     channel, i.e. pos=0
[1846]842
[1819]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
[1118]851    def stddev(self, mask=None):
[1846]852        """\
[135]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.
[1846]856
[135]857        Parameters:
[1846]858
[135]859            mask:    an optional mask specifying where the standard
860                     deviation should be determined.
861
[1846]862        Example::
863
[135]864            scan.set_unit('channel')
[1118]865            msk = scan.create_mask([100, 200], [500, 600])
[135]866            scan.stddev(mask=m)
[1846]867
[135]868        """
[1118]869        return self.stats(stat='stddev', mask=mask);
[135]870
[1003]871
[1259]872    def get_column_names(self):
[1846]873        """\
[1003]874        Return a  list of column names, which can be used for selection.
875        """
[1259]876        return list(Scantable.get_column_names(self))
[1003]877
[1730]878    def get_tsys(self, row=-1):
[1846]879        """\
[113]880        Return the System temperatures.
[1846]881
882        Parameters:
883
884            row:    the rowno to get the information for. (default all rows)
885
[113]886        Returns:
[1846]887
[876]888            a list of Tsys values for the current selection
[1846]889
[113]890        """
[1730]891        if row > -1:
892            return self._get_column(self._gettsys, row)
[876]893        return self._row_callback(self._gettsys, "Tsys")
[256]894
[2406]895    def get_tsysspectrum(self, row=-1):
896        """\
897        Return the channel dependent system temperatures.
[1730]898
[2406]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
[1730]910    def get_weather(self, row=-1):
[1846]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
[1730]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
[876]940    def _row_callback(self, callback, label):
941        out = ""
[1118]942        outvec = []
[1590]943        sep = '-'*50
[876]944        for i in range(self.nrow()):
945            tm = self._gettime(i)
946            src = self._getsourcename(i)
[1590]947            out += 'Scan[%d] (%s) ' % (self.getscan(i), src)
[876]948            out += 'Time[%s]:\n' % (tm)
[1590]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))
[876]953            outvec.append(callback(i))
954            out += '= %3.3f\n' % (outvec[i])
[1590]955            out +=  sep+'\n'
[1859]956
957        asaplog.push(sep)
958        asaplog.push(" %s" % (label))
959        asaplog.push(sep)
960        asaplog.push(out)
[1861]961        asaplog.post()
[1175]962        return outvec
[256]963
[1947]964    def _get_column(self, callback, row=-1, *args):
[1070]965        """
966        """
967        if row == -1:
[1947]968            return [callback(i, *args) for i in range(self.nrow())]
[1070]969        else:
[1819]970            if  0 <= row < self.nrow():
[1947]971                return callback(row, *args)
[256]972
[1070]973
[1948]974    def get_time(self, row=-1, asdatetime=False, prec=-1):
[1846]975        """\
[113]976        Get a list of time stamps for the observations.
[1938]977        Return a datetime object or a string (default) for each
978        integration time stamp in the scantable.
[1846]979
[113]980        Parameters:
[1846]981
[1348]982            row:          row no of integration. Default -1 return all rows
[1855]983
[1348]984            asdatetime:   return values as datetime objects rather than strings
[1846]985
[2349]986            prec:         number of digits shown. Default -1 to automatic
987                          calculation.
[1948]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,
[1947]991                          and 6> : with hh:mm:ss.tt... (prec-6 t's added)
992
[113]993        """
[1175]994        from datetime import datetime
[1948]995        if prec < 0:
996            # automagically set necessary precision +1
[2349]997            prec = 7 - \
998                numpy.floor(numpy.log10(numpy.min(self.get_inttime(row))))
[1948]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
[1947]1006        times = self._get_column(self._gettime, row, prec)
[1348]1007        if not asdatetime:
[1392]1008            return times
[1947]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],"")
[1175]1015        if isinstance(times, list):
[1947]1016            return [datetime.strptime(i, format) for i in times]
[1175]1017        else:
[1947]1018            return datetime.strptime(times, format)
[102]1019
[1348]1020
1021    def get_inttime(self, row=-1):
[1846]1022        """\
[1348]1023        Get a list of integration times for the observations.
1024        Return a time in seconds for each integration in the scantable.
[1846]1025
[1348]1026        Parameters:
[1846]1027
[1348]1028            row:    row no of integration. Default -1 return all rows.
[1846]1029
[1348]1030        """
[1573]1031        return self._get_column(self._getinttime, row)
[1348]1032
[1573]1033
[714]1034    def get_sourcename(self, row=-1):
[1846]1035        """\
[794]1036        Get a list source names for the observations.
[714]1037        Return a string for each integration in the scantable.
1038        Parameters:
[1846]1039
[1348]1040            row:    row no of integration. Default -1 return all rows.
[1846]1041
[714]1042        """
[1070]1043        return self._get_column(self._getsourcename, row)
[714]1044
[794]1045    def get_elevation(self, row=-1):
[1846]1046        """\
[794]1047        Get a list of elevations for the observations.
1048        Return a float for each integration in the scantable.
[1846]1049
[794]1050        Parameters:
[1846]1051
[1348]1052            row:    row no of integration. Default -1 return all rows.
[1846]1053
[794]1054        """
[1070]1055        return self._get_column(self._getelevation, row)
[794]1056
1057    def get_azimuth(self, row=-1):
[1846]1058        """\
[794]1059        Get a list of azimuths for the observations.
1060        Return a float for each integration in the scantable.
[1846]1061
[794]1062        Parameters:
[1348]1063            row:    row no of integration. Default -1 return all rows.
[1846]1064
[794]1065        """
[1070]1066        return self._get_column(self._getazimuth, row)
[794]1067
1068    def get_parangle(self, row=-1):
[1846]1069        """\
[794]1070        Get a list of parallactic angles for the observations.
1071        Return a float for each integration in the scantable.
[1846]1072
[794]1073        Parameters:
[1846]1074
[1348]1075            row:    row no of integration. Default -1 return all rows.
[1846]1076
[794]1077        """
[1070]1078        return self._get_column(self._getparangle, row)
[794]1079
[1070]1080    def get_direction(self, row=-1):
1081        """
1082        Get a list of Positions on the sky (direction) for the observations.
[1594]1083        Return a string for each integration in the scantable.
[1855]1084
[1070]1085        Parameters:
[1855]1086
[1070]1087            row:    row no of integration. Default -1 return all rows
[1855]1088
[1070]1089        """
1090        return self._get_column(self._getdirection, row)
1091
[1391]1092    def get_directionval(self, row=-1):
[1846]1093        """\
[1391]1094        Get a list of Positions on the sky (direction) for the observations.
1095        Return a float for each integration in the scantable.
[1846]1096
[1391]1097        Parameters:
[1846]1098
[1391]1099            row:    row no of integration. Default -1 return all rows
[1846]1100
[1391]1101        """
1102        return self._get_column(self._getdirectionvec, row)
1103
[1862]1104    @asaplog_post_dec
[102]1105    def set_unit(self, unit='channel'):
[1846]1106        """\
[102]1107        Set the unit for all following operations on this scantable
[1846]1108
[102]1109        Parameters:
[1846]1110
1111            unit:    optional unit, default is 'channel'. Use one of '*Hz',
1112                     'km/s', 'channel' or equivalent ''
1113
[102]1114        """
[484]1115        varlist = vars()
[1118]1116        if unit in ['', 'pixel', 'channel']:
[113]1117            unit = ''
1118        inf = list(self._getcoordinfo())
1119        inf[0] = unit
1120        self._setcoordinfo(inf)
[1118]1121        self._add_history("set_unit", varlist)
[113]1122
[1862]1123    @asaplog_post_dec
[484]1124    def set_instrument(self, instr):
[1846]1125        """\
[1348]1126        Set the instrument for subsequent processing.
[1846]1127
[358]1128        Parameters:
[1846]1129
[710]1130            instr:    Select from 'ATPKSMB', 'ATPKSHOH', 'ATMOPRA',
[407]1131                      'DSS-43' (Tid), 'CEDUNA', and 'HOBART'
[1846]1132
[358]1133        """
1134        self._setInstrument(instr)
[1118]1135        self._add_history("set_instument", vars())
[358]1136
[1862]1137    @asaplog_post_dec
[1190]1138    def set_feedtype(self, feedtype):
[1846]1139        """\
[1190]1140        Overwrite the feed type, which might not be set correctly.
[1846]1141
[1190]1142        Parameters:
[1846]1143
[1190]1144            feedtype:     'linear' or 'circular'
[1846]1145
[1190]1146        """
1147        self._setfeedtype(feedtype)
1148        self._add_history("set_feedtype", vars())
1149
[1862]1150    @asaplog_post_dec
[276]1151    def set_doppler(self, doppler='RADIO'):
[1846]1152        """\
[276]1153        Set the doppler for all following operations on this scantable.
[1846]1154
[276]1155        Parameters:
[1846]1156
[276]1157            doppler:    One of 'RADIO', 'OPTICAL', 'Z', 'BETA', 'GAMMA'
[1846]1158
[276]1159        """
[484]1160        varlist = vars()
[276]1161        inf = list(self._getcoordinfo())
1162        inf[2] = doppler
1163        self._setcoordinfo(inf)
[1118]1164        self._add_history("set_doppler", vars())
[710]1165
[1862]1166    @asaplog_post_dec
[226]1167    def set_freqframe(self, frame=None):
[1846]1168        """\
[113]1169        Set the frame type of the Spectral Axis.
[1846]1170
[113]1171        Parameters:
[1846]1172
[591]1173            frame:   an optional frame type, default 'LSRK'. Valid frames are:
[1819]1174                     'TOPO', 'LSRD', 'LSRK', 'BARY',
[1118]1175                     'GEO', 'GALACTO', 'LGROUP', 'CMB'
[1846]1176
1177        Example::
1178
[113]1179            scan.set_freqframe('BARY')
[1846]1180
[113]1181        """
[1593]1182        frame = frame or rcParams['scantable.freqframe']
[484]1183        varlist = vars()
[1819]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', \
[1118]1188                   'GEO', 'GALACTO', 'LGROUP', 'CMB']
[591]1189
[989]1190        if frame in valid:
[113]1191            inf = list(self._getcoordinfo())
1192            inf[1] = frame
1193            self._setcoordinfo(inf)
[1118]1194            self._add_history("set_freqframe", varlist)
[102]1195        else:
[1118]1196            msg  = "Please specify a valid freq type. Valid types are:\n", valid
[1859]1197            raise TypeError(msg)
[710]1198
[1862]1199    @asaplog_post_dec
[989]1200    def set_dirframe(self, frame=""):
[1846]1201        """\
[989]1202        Set the frame type of the Direction on the sky.
[1846]1203
[989]1204        Parameters:
[1846]1205
[989]1206            frame:   an optional frame type, default ''. Valid frames are:
1207                     'J2000', 'B1950', 'GALACTIC'
[1846]1208
1209        Example:
1210
[989]1211            scan.set_dirframe('GALACTIC')
[1846]1212
[989]1213        """
1214        varlist = vars()
[1859]1215        Scantable.set_dirframe(self, frame)
[1118]1216        self._add_history("set_dirframe", varlist)
[989]1217
[113]1218    def get_unit(self):
[1846]1219        """\
[113]1220        Get the default unit set in this scantable
[1846]1221
[113]1222        Returns:
[1846]1223
[113]1224            A unit string
[1846]1225
[113]1226        """
1227        inf = self._getcoordinfo()
1228        unit = inf[0]
1229        if unit == '': unit = 'channel'
1230        return unit
[102]1231
[1862]1232    @asaplog_post_dec
[158]1233    def get_abcissa(self, rowno=0):
[1846]1234        """\
[158]1235        Get the abcissa in the current coordinate setup for the currently
[113]1236        selected Beam/IF/Pol
[1846]1237
[113]1238        Parameters:
[1846]1239
[226]1240            rowno:    an optional row number in the scantable. Default is the
1241                      first row, i.e. rowno=0
[1846]1242
[113]1243        Returns:
[1846]1244
[1348]1245            The abcissa values and the format string (as a dictionary)
[1846]1246
[113]1247        """
[256]1248        abc = self._getabcissa(rowno)
[710]1249        lbl = self._getabcissalabel(rowno)
[158]1250        return abc, lbl
[113]1251
[1862]1252    @asaplog_post_dec
[2322]1253    def flag(self, mask=None, unflag=False, row=-1):
[1846]1254        """\
[1001]1255        Flag the selected data using an optional channel mask.
[1846]1256
[1001]1257        Parameters:
[1846]1258
[1001]1259            mask:   an optional channel mask, created with create_mask. Default
1260                    (no mask) is all channels.
[1855]1261
[1819]1262            unflag:    if True, unflag the data
[1846]1263
[2322]1264            row:    an optional row number in the scantable.
1265                      Default -1 flags all rows
1266                     
[1001]1267        """
1268        varlist = vars()
[1593]1269        mask = mask or []
[1994]1270        self._flag(row, mask, unflag)
[1001]1271        self._add_history("flag", varlist)
1272
[1862]1273    @asaplog_post_dec
[2322]1274    def flag_row(self, rows=None, unflag=False):
[1846]1275        """\
[1819]1276        Flag the selected data in row-based manner.
[1846]1277
[1819]1278        Parameters:
[1846]1279
[1843]1280            rows:   list of row numbers to be flagged. Default is no row
[2322]1281                    (must be explicitly specified to execute row-based
1282                    flagging).
[1855]1283
[1819]1284            unflag: if True, unflag the data.
[1846]1285
[1819]1286        """
1287        varlist = vars()
[2322]1288        if rows is None:
1289            rows = []
[1859]1290        self._flag_row(rows, unflag)
[1819]1291        self._add_history("flag_row", varlist)
1292
[1862]1293    @asaplog_post_dec
[1819]1294    def clip(self, uthres=None, dthres=None, clipoutside=True, unflag=False):
[1846]1295        """\
[1819]1296        Flag the selected data outside a specified range (in channel-base)
[1846]1297
[1819]1298        Parameters:
[1846]1299
[1819]1300            uthres:      upper threshold.
[1855]1301
[1819]1302            dthres:      lower threshold
[1846]1303
[2322]1304            clipoutside: True for flagging data outside the range
1305                         [dthres:uthres].
[1928]1306                         False for flagging data inside the range.
[1855]1307
[1846]1308            unflag:      if True, unflag the data.
1309
[1819]1310        """
1311        varlist = vars()
[1859]1312        self._clip(uthres, dthres, clipoutside, unflag)
[1819]1313        self._add_history("clip", varlist)
1314
[1862]1315    @asaplog_post_dec
[1584]1316    def lag_flag(self, start, end, unit="MHz", insitu=None):
[1846]1317        """\
[1192]1318        Flag the data in 'lag' space by providing a frequency to remove.
[2177]1319        Flagged data in the scantable get interpolated over the region.
[1192]1320        No taper is applied.
[1846]1321
[1192]1322        Parameters:
[1846]1323
[1579]1324            start:    the start frequency (really a period within the
1325                      bandwidth)  or period to remove
[1855]1326
[1579]1327            end:      the end frequency or period to remove
[1855]1328
[2431]1329            unit:     the frequency unit (default 'MHz') or '' for
[1579]1330                      explicit lag channels
[1846]1331
1332        *Notes*:
1333
[1579]1334            It is recommended to flag edges of the band or strong
[1348]1335            signals beforehand.
[1846]1336
[1192]1337        """
1338        if insitu is None: insitu = rcParams['insitu']
1339        self._math._setinsitu(insitu)
1340        varlist = vars()
[1579]1341        base = { "GHz": 1000000000., "MHz": 1000000., "kHz": 1000., "Hz": 1.}
1342        if not (unit == "" or base.has_key(unit)):
[1192]1343            raise ValueError("%s is not a valid unit." % unit)
[1859]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"))
[1192]1349        s._add_history("lag_flag", varlist)
1350        if insitu:
1351            self._assign(s)
1352        else:
1353            return s
[1001]1354
[1862]1355    @asaplog_post_dec
[2349]1356    def fft(self, rowno=None, mask=None, getrealimag=False):
[2177]1357        """\
1358        Apply FFT to the spectra.
1359        Flagged data in the scantable get interpolated over the region.
1360
1361        Parameters:
[2186]1362
1363            rowno:          The row number(s) to be processed. int, list
[2349]1364                            and tuple are accepted. By default (None), FFT
[2186]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
[2349]1372                            'rowno'. The default is None.
[2177]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
[2186]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',
[2177]1387            respectively.
1388        """
[2349]1389        if rowno is None:
1390            rowno = []
[2177]1391        if isinstance(rowno, int):
1392            rowno = [rowno]
1393        elif not (isinstance(rowno, list) or isinstance(rowno, tuple)):
[2186]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
[2411]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:
[2349]1424            raise TypeError("The mask must be a boolean list or a list of "
1425                            "boolean list.")
[2186]1426
1427        res = []
1428
1429        imask = 0
1430        for whichrow in rowno:
1431            fspec = self._fft(whichrow, mask[imask], getrealimag)
1432            nspec = len(fspec)
[2177]1433           
[2349]1434            i = 0
1435            v1 = []
1436            v2 = []
1437            reselem = {"real":[],"imag":[]} if getrealimag \
1438                                            else {"ampl":[],"phase":[]}
[2177]1439           
[2186]1440            while (i < nspec):
1441                v1.append(fspec[i])
1442                v2.append(fspec[i+1])
[2349]1443                i += 2
[2186]1444           
[2177]1445            if getrealimag:
[2186]1446                reselem["real"]  += v1
1447                reselem["imag"]  += v2
[2177]1448            else:
[2186]1449                reselem["ampl"]  += v1
1450                reselem["phase"] += v2
[2177]1451           
[2186]1452            res.append(reselem)
1453           
[2349]1454            if not usecommonmask:
1455                imask += 1
[2186]1456       
[2177]1457        return res
1458
1459    @asaplog_post_dec
[113]1460    def create_mask(self, *args, **kwargs):
[1846]1461        """\
[1118]1462        Compute and return a mask based on [min, max] windows.
[189]1463        The specified windows are to be INCLUDED, when the mask is
[113]1464        applied.
[1846]1465
[102]1466        Parameters:
[1846]1467
[1118]1468            [min, max], [min2, max2], ...
[1024]1469                Pairs of start/end points (inclusive)specifying the regions
[102]1470                to be masked
[1855]1471
[189]1472            invert:     optional argument. If specified as True,
1473                        return an inverted mask, i.e. the regions
1474                        specified are EXCLUDED
[1855]1475
[513]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.
[1846]1479
1480        Examples::
1481
[113]1482            scan.set_unit('channel')
[1846]1483            # a)
[1118]1484            msk = scan.create_mask([400, 500], [800, 900])
[189]1485            # masks everything outside 400 and 500
[113]1486            # and 800 and 900 in the unit 'channel'
1487
[1846]1488            # b)
[1118]1489            msk = scan.create_mask([400, 500], [800, 900], invert=True)
[189]1490            # masks the regions between 400 and 500
[113]1491            # and 800 and 900 in the unit 'channel'
[1846]1492
1493            # c)
1494            #mask only channel 400
[1554]1495            msk =  scan.create_mask([400])
[1846]1496
[102]1497        """
[1554]1498        row = kwargs.get("row", 0)
[513]1499        data = self._getabcissa(row)
[113]1500        u = self._getcoordinfo()[0]
[1859]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)
[2348]1508        n = len(data)
[1295]1509        msk = _n_bools(n, False)
[710]1510        # test if args is a 'list' or a 'normal *args - UGLY!!!
1511
[2349]1512        ws = (isinstance(args[-1][-1], int)
1513              or isinstance(args[-1][-1], float)) and args or args[0]
[710]1514        for window in ws:
[1554]1515            if len(window) == 1:
1516                window = [window[0], window[0]]
1517            if len(window) == 0 or  len(window) > 2:
[2349]1518                raise ValueError("A window needs to be defined as "
1519                                 "[start(, end)]")
[1545]1520            if window[0] > window[1]:
1521                tmp = window[0]
1522                window[0] = window[1]
1523                window[1] = tmp
[102]1524            for i in range(n):
[1024]1525                if data[i] >= window[0] and data[i] <= window[1]:
[1295]1526                    msk[i] = True
[113]1527        if kwargs.has_key('invert'):
1528            if kwargs.get('invert'):
[1295]1529                msk = mask_not(msk)
[102]1530        return msk
[710]1531
[1931]1532    def get_masklist(self, mask=None, row=0, silent=False):
[1846]1533        """\
[1819]1534        Compute and return a list of mask windows, [min, max].
[1846]1535
[1819]1536        Parameters:
[1846]1537
[1819]1538            mask:       channel mask, created with create_mask.
[1855]1539
[1819]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.
[1846]1543
[1819]1544        Returns:
[1846]1545
[1819]1546            [min, max], [min2, max2], ...
1547                Pairs of start/end points (inclusive)specifying
1548                the masked regions
[1846]1549
[1819]1550        """
1551        if not (isinstance(mask,list) or isinstance(mask, tuple)):
1552            raise TypeError("The mask should be list or tuple.")
[2427]1553        if len(mask) <= 0:
1554            raise TypeError("The mask elements should be > 0")
[2348]1555        data = self._getabcissa(row)
1556        if len(data) != len(mask):
[1819]1557            msg = "Number of channels in scantable != number of mask elements"
1558            raise TypeError(msg)
1559        u = self._getcoordinfo()[0]
[1859]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))
[1931]1566        if not silent:
1567            asaplog.push(msg)
[2349]1568        masklist = []
[1819]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):
[1846]1579        """\
[1819]1580        Compute and Return lists of mask start indices and mask end indices.
[1855]1581
1582        Parameters:
1583
[1819]1584            mask:       channel mask, created with create_mask.
[1846]1585
[1819]1586        Returns:
[1846]1587
[1819]1588            List of mask start indices and that of mask end indices,
1589            i.e., [istart1,istart2,....], [iend1,iend2,....].
[1846]1590
[1819]1591        """
1592        if not (isinstance(mask,list) or isinstance(mask, tuple)):
1593            raise TypeError("The mask should be list or tuple.")
[2427]1594        if len(mask) <= 0:
1595            raise TypeError("The mask elements should be > 0")
[2349]1596        istart = []
1597        iend = []
1598        if mask[0]:
1599            istart.append(0)
[1819]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)
[2349]1605        if mask[len(mask)-1]:
1606            iend.append(len(mask)-1)
[1819]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
[2013]1615    @asaplog_post_dec
[2349]1616    def parse_maskexpr(self, maskstring):
[2013]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:
[2015]1626                         ''          = all IFs (all channels)
[2013]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()
[2611]1637            asaplog.push("Mask expression should be a string.")
[2013]1638            asaplog.post("ERROR")
1639       
1640        valid_ifs = self.getifnos()
1641        frequnit = self.get_unit()
1642        seldict = {}
[2015]1643        if maskstring == "":
1644            maskstring = str(valid_ifs)[1:-1]
[2611]1645        ## split each selection "IF range[:CHAN range]"
[2013]1646        sellist = maskstring.split(',')
1647        for currselstr in sellist:
1648            selset = currselstr.split(':')
1649            # spw and mask string (may include ~, < or >)
[2349]1650            spwmasklist = self._parse_selection(selset[0], typestr='integer',
[2611]1651                                                minval=min(valid_ifs),
[2349]1652                                                maxval=max(valid_ifs))
[2013]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:
[2349]1663                freqmasklist = self._parse_selection(selset[1], typestr='float',
1664                                                     offset=0.)
[2013]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:
[2349]1696                            offset = abs(freqcoord.to_frequency(1,
1697                                                                unit=frequnit)
1698                                         -freqcoord.to_frequency(0,
1699                                                                 unit=frequnit)
1700                                         )*0.5
[2013]1701                        elif frequnit.find('m/s') > 0:
[2349]1702                            offset = abs(freqcoord.to_velocity(1,
1703                                                               unit=frequnit)
1704                                         -freqcoord.to_velocity(0,
1705                                                                unit=frequnit)
1706                                         )*0.5
[2013]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()
[2349]1739            asaplog.push("No valid selection in the mask expression: "
1740                         +maskstring)
[2013]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
[2611]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
[2349]1800    def _parse_selection(self, selstr, typestr='float', offset=0.,
[2351]1801                         minval=None, maxval=None):
[2013]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
[2611]1809                        includes '<' or '>' [Valid only for typestr='float']
[2013]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:
[2611]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.]]
[2013]1820        """
1821        selgroups = selstr.split(';')
1822        sellists = []
1823        if typestr.lower().startswith('int'):
1824            formatfunc = int
[2611]1825            offset = 1
[2013]1826        else:
1827            formatfunc = float
1828       
1829        for currsel in  selgroups:
1830            if currsel.find('~') > 0:
[2611]1831                # val0 <= x <= val1
[2013]1832                minsel = formatfunc(currsel.split('~')[0].strip())
1833                maxsel = formatfunc(currsel.split('~')[1].strip())
[2611]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()) \
[2013]1858                         + formatfunc(offset)
[2611]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)
[2013]1870            else:
1871                minsel = formatfunc(currsel)
1872                maxsel = formatfunc(currsel)
1873            sellists.append([minsel,maxsel])
1874        return sellists
1875
[1819]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):
[1846]1888        """\
[256]1889        Get the restfrequency(s) stored in this scantable.
1890        The return value(s) are always of unit 'Hz'
[1846]1891
[256]1892        Parameters:
[1846]1893
[1819]1894            ids: (optional) a list of MOLECULE_ID for that restfrequency(s) to
1895                 be retrieved
[1846]1896
[256]1897        Returns:
[1846]1898
[1819]1899            dictionary containing ids and a list of doubles for each id
[1846]1900
[256]1901        """
[1819]1902        if ids is None:
[2349]1903            rfreqs = {}
[1819]1904            idlist = self.getmolnos()
1905            for i in idlist:
[2349]1906                rfreqs[i] = list(self._getrestfreqs(i))
[1819]1907            return rfreqs
1908        else:
[2349]1909            if type(ids) == list or type(ids) == tuple:
1910                rfreqs = {}
[1819]1911                for i in ids:
[2349]1912                    rfreqs[i] = list(self._getrestfreqs(i))
[1819]1913                return rfreqs
1914            else:
1915                return list(self._getrestfreqs(ids))
[102]1916
[2349]1917    @asaplog_post_dec
[931]1918    def set_restfreqs(self, freqs=None, unit='Hz'):
[1846]1919        """\
[931]1920        Set or replace the restfrequency specified and
[1938]1921        if the 'freqs' argument holds a scalar,
[931]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.
[1118]1929        E.g. 'freqs=[1e9, 2e9]'  would mean IF 0 gets restfreq 1e9 and
[931]1930        IF 1 gets restfreq 2e9.
[1846]1931
[1395]1932        You can also specify the frequencies via a linecatalog.
[1153]1933
[931]1934        Parameters:
[1846]1935
[931]1936            freqs:   list of rest frequency values or string idenitfiers
[1855]1937
[931]1938            unit:    unit for rest frequency (default 'Hz')
[402]1939
[1846]1940
1941        Example::
1942
[1819]1943            # set the given restfrequency for the all currently selected IFs
[931]1944            scan.set_restfreqs(freqs=1.4e9)
[1845]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
[1819]1951            scan.set_restfreqs(freqs=[1.4e9, 1.41e9, 1.42e9])
[1845]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]])
[391]1955
[1846]1956       *Note*:
[1845]1957
[931]1958            To do more sophisticate Restfrequency setting, e.g. on a
1959            source and IF basis, use scantable.set_selection() before using
[1846]1960            this function::
[931]1961
[1846]1962                # provided your scantable is called scan
1963                selection = selector()
[2431]1964                selection.set_name('ORION*')
[1846]1965                selection.set_ifs([1])
1966                scan.set_selection(selection)
1967                scan.set_restfreqs(freqs=86.6e9)
1968
[931]1969        """
1970        varlist = vars()
[1157]1971        from asap import linecatalog
1972        # simple  value
[1118]1973        if isinstance(freqs, int) or isinstance(freqs, float):
[1845]1974            self._setrestfreqs([freqs], [""], unit)
[1157]1975        # list of values
[1118]1976        elif isinstance(freqs, list) or isinstance(freqs, tuple):
[1157]1977            # list values are scalars
[1118]1978            if isinstance(freqs[-1], int) or isinstance(freqs[-1], float):
[1845]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()
[2599]1984                    sel = self.get_selection()
[1845]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'=)
[1157]1997            elif isinstance(freqs[-1], dict):
[1845]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)
[1819]2004            elif isinstance(freqs[-1], list) or isinstance(freqs[-1], tuple):
[1157]2005                savesel = self._getselection()
[2599]2006                sel = self.get_selection()
[1322]2007                iflist = self.getifnos()
[1819]2008                if len(freqs)>len(iflist):
[1845]2009                    raise ValueError("number of elements in list of list exeeds"
2010                                     " the current IF selections")
2011                for i, fval in enumerate(freqs):
[1322]2012                    sel.set_ifs(iflist[i])
[1259]2013                    self._setselection(sel)
[1845]2014                    self._setrestfreqs(fval, [""], unit)
[1157]2015                self._setselection(savesel)
2016        # freqs are to be taken from a linecatalog
[1153]2017        elif isinstance(freqs, linecatalog):
2018            savesel = self._getselection()
[2599]2019            sel = self.get_selection()
[1153]2020            for i in xrange(freqs.nrow()):
[1322]2021                sel.set_ifs(iflist[i])
[1153]2022                self._setselection(sel)
[1845]2023                self._setrestfreqs([freqs.get_frequency(i)],
2024                                   [freqs.get_name(i)], "MHz")
[1153]2025                # ensure that we are not iterating past nIF
2026                if i == self.nif()-1: break
2027            self._setselection(savesel)
[931]2028        else:
2029            return
2030        self._add_history("set_restfreqs", varlist)
2031
[2349]2032    @asaplog_post_dec
[1360]2033    def shift_refpix(self, delta):
[1846]2034        """\
[1589]2035        Shift the reference pixel of the Spectra Coordinate by an
2036        integer amount.
[1846]2037
[1589]2038        Parameters:
[1846]2039
[1589]2040            delta:   the amount to shift by
[1846]2041
2042        *Note*:
2043
[1589]2044            Be careful using this with broadband data.
[1846]2045
[1360]2046        """
[2349]2047        varlist = vars()
[1731]2048        Scantable.shift_refpix(self, delta)
[2349]2049        s._add_history("shift_refpix", varlist)
[931]2050
[1862]2051    @asaplog_post_dec
[1259]2052    def history(self, filename=None):
[1846]2053        """\
[1259]2054        Print the history. Optionally to a file.
[1846]2055
[1348]2056        Parameters:
[1846]2057
[1928]2058            filename:    The name of the file to save the history to.
[1846]2059
[1259]2060        """
[484]2061        hist = list(self._gethistory())
[794]2062        out = "-"*80
[484]2063        for h in hist:
[489]2064            if h.startswith("---"):
[1857]2065                out = "\n".join([out, h])
[489]2066            else:
2067                items = h.split("##")
2068                date = items[0]
2069                func = items[1]
2070                items = items[2:]
[794]2071                out += "\n"+date+"\n"
2072                out += "Function: %s\n  Parameters:" % (func)
[489]2073                for i in items:
[1938]2074                    if i == '':
2075                        continue
[489]2076                    s = i.split("=")
[1118]2077                    out += "\n   %s = %s" % (s[0], s[1])
[1857]2078                out = "\n".join([out, "-"*80])
[1259]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)
[1859]2090                raise IOError(msg)
2091        return page(out)
[2349]2092
[513]2093    #
2094    # Maths business
2095    #
[1862]2096    @asaplog_post_dec
[931]2097    def average_time(self, mask=None, scanav=False, weight='tint', align=False):
[1846]2098        """\
[2349]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
[1846]2101
2102        *Note*:
2103
[1070]2104            in channels only - align if necessary
[1846]2105
[513]2106        Parameters:
[1846]2107
[513]2108            mask:     an optional mask (only used for 'var' and 'tsys'
2109                      weighting)
[1855]2110
[558]2111            scanav:   True averages each scan separately
2112                      False (default) averages all scans together,
[1855]2113
[1099]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)
[535]2121                      The default is 'tint'
[1855]2122
[931]2123            align:    align the spectra in velocity before averaging. It takes
2124                      the time of the first spectrum as reference time.
[1846]2125
2126        Example::
2127
[513]2128            # time average the scantable without using a mask
[710]2129            newscan = scan.average_time()
[1846]2130
[513]2131        """
2132        varlist = vars()
[1593]2133        weight = weight or 'TINT'
2134        mask = mask or ()
2135        scanav = (scanav and 'SCAN') or 'NONE'
[1118]2136        scan = (self, )
[1859]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))
[1099]2147        s._add_history("average_time", varlist)
[513]2148        return s
[710]2149
[1862]2150    @asaplog_post_dec
[876]2151    def convert_flux(self, jyperk=None, eta=None, d=None, insitu=None):
[1846]2152        """\
[513]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.
[1846]2159
[513]2160        Parameters:
[1846]2161
[513]2162            jyperk:      the Jy / K conversion factor
[1855]2163
[513]2164            eta:         the aperture efficiency
[1855]2165
[1928]2166            d:           the geometric diameter (metres)
[1855]2167
[513]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)
[1846]2171
[513]2172        """
2173        if insitu is None: insitu = rcParams['insitu']
[876]2174        self._math._setinsitu(insitu)
[513]2175        varlist = vars()
[1593]2176        jyperk = jyperk or -1.0
2177        d = d or -1.0
2178        eta = eta or -1.0
[876]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
[513]2183
[1862]2184    @asaplog_post_dec
[876]2185    def gain_el(self, poly=None, filename="", method="linear", insitu=None):
[1846]2186        """\
[513]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.
[1846]2195
[513]2196        Parameters:
[1846]2197
[513]2198            poly:        Polynomial coefficients (default None) to compute a
2199                         gain-elevation correction as a function of
2200                         elevation (in degrees).
[1855]2201
[513]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
[2431]2205                         'ELEVATION' (degrees) and 'FACTOR' (multiply data
[513]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
[1855]2220
[513]2221            method:      Interpolation method when correcting from a table.
[2431]2222                         Values are  'nearest', 'linear' (default), 'cubic'
2223                         and 'spline'
[1855]2224
[513]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)
[1846]2228
[513]2229        """
2230
2231        if insitu is None: insitu = rcParams['insitu']
[876]2232        self._math._setinsitu(insitu)
[513]2233        varlist = vars()
[1593]2234        poly = poly or ()
[513]2235        from os.path import expandvars
2236        filename = expandvars(filename)
[876]2237        s = scantable(self._math._gainel(self, poly, filename, method))
2238        s._add_history("gain_el", varlist)
[1593]2239        if insitu:
2240            self._assign(s)
2241        else:
2242            return s
[710]2243
[1862]2244    @asaplog_post_dec
[931]2245    def freq_align(self, reftime=None, method='cubic', insitu=None):
[1846]2246        """\
[513]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.
[1846]2250
[513]2251        Parameters:
[1855]2252
[513]2253            reftime:     reference time to align at. By default, the time of
2254                         the first row of data is used.
[1855]2255
[513]2256            method:      Interpolation method for regridding the spectra.
[2431]2257                         Choose from 'nearest', 'linear', 'cubic' (default)
2258                         and 'spline'
[1855]2259
[513]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)
[1846]2263
[513]2264        """
[931]2265        if insitu is None: insitu = rcParams["insitu"]
[2429]2266        oldInsitu = self._math._insitu()
[876]2267        self._math._setinsitu(insitu)
[513]2268        varlist = vars()
[1593]2269        reftime = reftime or ""
[931]2270        s = scantable(self._math._freq_align(self, reftime, method))
[876]2271        s._add_history("freq_align", varlist)
[2429]2272        self._math._setinsitu(oldInsitu)
[2349]2273        if insitu:
2274            self._assign(s)
2275        else:
2276            return s
[513]2277
[1862]2278    @asaplog_post_dec
[1725]2279    def opacity(self, tau=None, insitu=None):
[1846]2280        """\
[513]2281        Apply an opacity correction. The data
2282        and Tsys are multiplied by the correction factor.
[1846]2283
[513]2284        Parameters:
[1855]2285
[1689]2286            tau:         (list of) opacity from which the correction factor is
[513]2287                         exp(tau*ZD)
[1689]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 ...]
[1725]2292                         if tau is `None` the opacities are determined from a
2293                         model.
[1855]2294
[513]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)
[1846]2298
[513]2299        """
[2349]2300        if insitu is None:
2301            insitu = rcParams['insitu']
[876]2302        self._math._setinsitu(insitu)
[513]2303        varlist = vars()
[1689]2304        if not hasattr(tau, "__len__"):
2305            tau = [tau]
[876]2306        s = scantable(self._math._opacity(self, tau))
2307        s._add_history("opacity", varlist)
[2349]2308        if insitu:
2309            self._assign(s)
2310        else:
2311            return s
[513]2312
[1862]2313    @asaplog_post_dec
[513]2314    def bin(self, width=5, insitu=None):
[1846]2315        """\
[513]2316        Return a scan where all spectra have been binned up.
[1846]2317
[1348]2318        Parameters:
[1846]2319
[513]2320            width:       The bin width (default=5) in pixels
[1855]2321
[513]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)
[1846]2325
[513]2326        """
[2349]2327        if insitu is None:
2328            insitu = rcParams['insitu']
[876]2329        self._math._setinsitu(insitu)
[513]2330        varlist = vars()
[876]2331        s = scantable(self._math._bin(self, width))
[1118]2332        s._add_history("bin", varlist)
[1589]2333        if insitu:
2334            self._assign(s)
2335        else:
2336            return s
[513]2337
[1862]2338    @asaplog_post_dec
[2672]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
[513]2359    def resample(self, width=5, method='cubic', insitu=None):
[1846]2360        """\
[1348]2361        Return a scan where all spectra have been binned up.
[1573]2362
[1348]2363        Parameters:
[1846]2364
[513]2365            width:       The bin width (default=5) in pixels
[1855]2366
[513]2367            method:      Interpolation method when correcting from a table.
[2431]2368                         Values are  'nearest', 'linear', 'cubic' (default)
2369                         and 'spline'
[1855]2370
[513]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)
[1846]2374
[513]2375        """
[2349]2376        if insitu is None:
2377            insitu = rcParams['insitu']
[876]2378        self._math._setinsitu(insitu)
[513]2379        varlist = vars()
[876]2380        s = scantable(self._math._resample(self, method, width))
[1118]2381        s._add_history("resample", varlist)
[2349]2382        if insitu:
2383            self._assign(s)
2384        else:
2385            return s
[513]2386
[1862]2387    @asaplog_post_dec
[946]2388    def average_pol(self, mask=None, weight='none'):
[1846]2389        """\
[946]2390        Average the Polarisations together.
[1846]2391
[946]2392        Parameters:
[1846]2393
[946]2394            mask:        An optional mask defining the region, where the
2395                         averaging will be applied. The output will have all
2396                         specified points masked.
[1855]2397
[946]2398            weight:      Weighting scheme. 'none' (default), 'var' (1/var(spec)
2399                         weighted), or 'tsys' (1/Tsys**2 weighted)
[1846]2400
[946]2401        """
2402        varlist = vars()
[1593]2403        mask = mask or ()
[1010]2404        s = scantable(self._math._averagepol(self, mask, weight.upper()))
[1118]2405        s._add_history("average_pol", varlist)
[992]2406        return s
[513]2407
[1862]2408    @asaplog_post_dec
[1145]2409    def average_beam(self, mask=None, weight='none'):
[1846]2410        """\
[1145]2411        Average the Beams together.
[1846]2412
[1145]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.
[1855]2417
[1145]2418            weight:      Weighting scheme. 'none' (default), 'var' (1/var(spec)
2419                         weighted), or 'tsys' (1/Tsys**2 weighted)
[1846]2420
[1145]2421        """
2422        varlist = vars()
[1593]2423        mask = mask or ()
[1145]2424        s = scantable(self._math._averagebeams(self, mask, weight.upper()))
2425        s._add_history("average_beam", varlist)
2426        return s
2427
[1586]2428    def parallactify(self, pflag):
[1846]2429        """\
[1843]2430        Set a flag to indicate whether this data should be treated as having
[1617]2431        been 'parallactified' (total phase == 0.0)
[1846]2432
[1617]2433        Parameters:
[1855]2434
[1843]2435            pflag:  Bool indicating whether to turn this on (True) or
[1617]2436                    off (False)
[1846]2437
[1617]2438        """
[1586]2439        varlist = vars()
2440        self._parallactify(pflag)
2441        self._add_history("parallactify", varlist)
2442
[1862]2443    @asaplog_post_dec
[992]2444    def convert_pol(self, poltype=None):
[1846]2445        """\
[992]2446        Convert the data to a different polarisation type.
[1565]2447        Note that you will need cross-polarisation terms for most conversions.
[1846]2448
[992]2449        Parameters:
[1855]2450
[992]2451            poltype:    The new polarisation type. Valid types are:
[2431]2452                        'linear', 'circular', 'stokes' and 'linpol'
[1846]2453
[992]2454        """
2455        varlist = vars()
[1859]2456        s = scantable(self._math._convertpol(self, poltype))
[1118]2457        s._add_history("convert_pol", varlist)
[992]2458        return s
2459
[1862]2460    @asaplog_post_dec
[2269]2461    def smooth(self, kernel="hanning", width=5.0, order=2, plot=False,
2462               insitu=None):
[1846]2463        """\
[513]2464        Smooth the spectrum by the specified kernel (conserving flux).
[1846]2465
[513]2466        Parameters:
[1846]2467
[513]2468            kernel:     The type of smoothing kernel. Select from
[1574]2469                        'hanning' (default), 'gaussian', 'boxcar', 'rmedian'
2470                        or 'poly'
[1855]2471
[513]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.
[1574]2476                        For 'rmedian' and 'poly' it is the half width.
[1855]2477
[1574]2478            order:      Optional parameter for 'poly' kernel (default is 2), to
2479                        specify the order of the polnomial. Ignored by all other
2480                        kernels.
[1855]2481
[1819]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'
[1855]2485
[513]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)
[1846]2489
[513]2490        """
2491        if insitu is None: insitu = rcParams['insitu']
[876]2492        self._math._setinsitu(insitu)
[513]2493        varlist = vars()
[1819]2494
2495        if plot: orgscan = self.copy()
2496
[1574]2497        s = scantable(self._math._smooth(self, kernel.lower(), width, order))
[876]2498        s._add_history("smooth", varlist)
[1819]2499
[2610]2500        action = 'H'
[1819]2501        if plot:
[2150]2502            from asap.asapplotter import new_asaplot
2503            theplot = new_asaplot(rcParams['plotter.gui'])
[2535]2504            from matplotlib import rc as rcp
2505            rcp('lines', linewidth=1)
[2150]2506            theplot.set_panels()
[1819]2507            ylab=s._get_ordinate_label()
[2150]2508            #theplot.palette(0,["#777777","red"])
[1819]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)
[2610]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): ")
[1819]2536                if res.upper() == 'N':
[2610]2537                    # reject for the current rows
[1819]2538                    s._setspectrum(yorg, r)
[2610]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
[2150]2546            theplot.quit()
2547            del theplot
[1819]2548            del orgscan
2549
[876]2550        if insitu: self._assign(s)
2551        else: return s
[513]2552
[2186]2553    @asaplog_post_dec
[2435]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'])
[2535]2589#             from matplotlib import rc as rcp
2590#             rcp('lines', linewidth=1)
[2435]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
[2186]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):
[2277]2633            if '-' in wn:                            # case 'a-b' : return [a,a+1,...,b-1,b]
[2186]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)]
[2277]2638            elif wn[:2] == '<=' or wn[:2] == '=<':   # cases '<=a','=<a' : return [0,1,...,a-1,a]
[2186]2639                val = int(wn[2:])+1
2640                res = [i for i in xrange(val)]
[2277]2641            elif wn[-2:] == '>=' or wn[-2:] == '=>': # cases 'a>=','a=>' : return [0,1,...,a-1,a]
[2186]2642                val = int(wn[:-2])+1
2643                res = [i for i in xrange(val)]
[2277]2644            elif wn[0] == '<':                       # case '<a' :         return [0,1,...,a-2,a-1]
[2186]2645                val = int(wn[1:])
2646                res = [i for i in xrange(val)]
[2277]2647            elif wn[-1] == '>':                      # case 'a>' :         return [0,1,...,a-2,a-1]
[2186]2648                val = int(wn[:-1])
2649                res = [i for i in xrange(val)]
[2411]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)
[2186]2654                val = int(wn[2:])
[2411]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)
[2186]2661                val = int(wn[:-2])
[2411]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)
[2186]2668                val = int(wn[1:])+1
[2411]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)
[2186]2675                val = int(wn[:-1])+1
[2411]2676                res = [val, -999]
2677                #res = [i for i in xrange(val, self.nchan()/2+1)]
[2012]2678
[2186]2679            return res
2680        else:
2681            msg = 'wrong value given for addwn/rejwn'
2682            raise RuntimeError(msg)
2683
[2713]2684    @asaplog_post_dec
[2767]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
[2713]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).
[2186]2824
[2713]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
[1862]2890    @asaplog_post_dec
[2771]2891    def sinusoid_baseline(self, mask=None, applyfft=None,
[2269]2892                          fftmethod=None, fftthresh=None,
[2771]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,
[2767]2900                          blfile=None, csvformat=None,
2901                          bltable=None):
[2047]2902        """\
[2349]2903        Return a scan which has been baselined (all rows) with sinusoidal
2904        functions.
2905
[2047]2906        Parameters:
[2186]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:
[2349]2920                               'xsigma' or 'x' (= x-sigma level. e.g.,
2921                               '3sigma'), or
[2186]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).
[2411]2933                           default is [0].
[2186]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 [].
[2771]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)
[2081]2941            clipthresh:    Clipping threshold. (default is 3.0, unit: sigma)
[2349]2942            clipniter:     maximum number of iteration of 'clipthresh'-sigma
2943                           clipping (default is 0)
[2081]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)
[2189]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.
[2081]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
[2186]2958                           (default is '': no file/logger output)
[2641]2959            csvformat:     if True blfile is csv-formatted, default is False.
[2767]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)
[2047]2966
2967        Example:
[2349]2968            # return a scan baselined by a combination of sinusoidal curves
2969            # having wave numbers in spectral window up to 10,
[2047]2970            # also with 3-sigma clipping, iteration up to 4 times
[2186]2971            bscan = scan.sinusoid_baseline(addwn='<=10',clipthresh=3.0,clipniter=4)
[2081]2972
2973        Note:
2974            The best-fit parameter values output in logger and/or blfile are now
2975            based on specunit of 'channel'.
[2047]2976        """
2977       
[2186]2978        try:
2979            varlist = vars()
[2047]2980       
[2186]2981            if insitu is None: insitu = rcParams['insitu']
2982            if insitu:
2983                workscan = self
2984            else:
2985                workscan = self.copy()
2986           
[2410]2987            if mask          is None: mask          = []
[2186]2988            if applyfft      is None: applyfft      = True
2989            if fftmethod     is None: fftmethod     = 'fft'
2990            if fftthresh     is None: fftthresh     = 3.0
[2411]2991            if addwn         is None: addwn         = [0]
[2186]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
[2189]2997            if showprogress  is None: showprogress  = True
2998            if minnrow       is None: minnrow       = 1000
[2186]2999            if outlog        is None: outlog        = False
3000            if blfile        is None: blfile        = ''
[2641]3001            if csvformat     is None: csvformat     = False
[2767]3002            if bltable       is None: bltable       = ''
[2047]3003
[2767]3004            sapplyfft = 'true' if applyfft else 'false'
3005            fftinfo = ','.join([sapplyfft, fftmethod.lower(), str(fftthresh).lower()])
[2641]3006
[2767]3007            scsvformat = 'T' if csvformat else 'F'
3008
[2081]3009            #CURRENTLY, PLOT=true is UNAVAILABLE UNTIL sinusoidal fitting is implemented as a fitter method.
[2767]3010            workscan._sinusoid_baseline(mask,
3011                                        fftinfo,
3012                                        #applyfft, fftmethod.lower(),
3013                                        #str(fftthresh).lower(),
[2349]3014                                        workscan._parse_wn(addwn),
[2643]3015                                        workscan._parse_wn(rejwn),
3016                                        clipthresh, clipniter,
3017                                        getresidual,
[2349]3018                                        pack_progress_params(showprogress,
[2641]3019                                                             minnrow),
[2767]3020                                        outlog, scsvformat+blfile,
3021                                        bltable)
[2186]3022            workscan._add_history('sinusoid_baseline', varlist)
[2767]3023
3024            if bltable == '':
3025                if insitu:
3026                    self._assign(workscan)
3027                else:
3028                    return workscan
[2047]3029            else:
[2767]3030                if not insitu:
3031                    return None
[2047]3032           
3033        except RuntimeError, e:
[2186]3034            raise_fitting_failure_exception(e)
[2047]3035
3036
[2186]3037    @asaplog_post_dec
[2771]3038    def auto_sinusoid_baseline(self, mask=None, applyfft=None,
[2349]3039                               fftmethod=None, fftthresh=None,
[2771]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,
[2767]3048                               blfile=None, csvformat=None,
3049                               bltable=None):
[2047]3050        """\
[2349]3051        Return a scan which has been baselined (all rows) with sinusoidal
3052        functions.
[2047]3053        Spectral lines are detected first using linefinder and masked out
3054        to avoid them affecting the baseline solution.
3055
3056        Parameters:
[2189]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:
[2349]3070                                'xsigma' or 'x' (= x-sigma level. e.g.,
3071                                '3sigma'), or
[2189]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).
[2411]3083                            default is [0].
[2189]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 [].
[2771]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)
[2189]3091            clipthresh:     Clipping threshold. (default is 3.0, unit: sigma)
[2349]3092            clipniter:      maximum number of iteration of 'clipthresh'-sigma
3093                            clipping (default is 0)
[2189]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)
[2641]3129            csvformat:      if True blfile is csv-formatted, default is False.
[2767]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)
[2047]3136
3137        Example:
[2186]3138            bscan = scan.auto_sinusoid_baseline(addwn='<=10', insitu=False)
[2081]3139       
3140        Note:
3141            The best-fit parameter values output in logger and/or blfile are now
3142            based on specunit of 'channel'.
[2047]3143        """
3144
[2186]3145        try:
3146            varlist = vars()
[2047]3147
[2186]3148            if insitu is None: insitu = rcParams['insitu']
3149            if insitu:
3150                workscan = self
[2047]3151            else:
[2186]3152                workscan = self.copy()
3153           
[2410]3154            if mask           is None: mask           = []
[2186]3155            if applyfft       is None: applyfft       = True
3156            if fftmethod      is None: fftmethod      = 'fft'
3157            if fftthresh      is None: fftthresh      = 3.0
[2411]3158            if addwn          is None: addwn          = [0]
[2186]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
[2189]3167            if showprogress   is None: showprogress   = True
3168            if minnrow        is None: minnrow        = 1000
[2186]3169            if outlog         is None: outlog         = False
3170            if blfile         is None: blfile         = ''
[2641]3171            if csvformat      is None: csvformat      = False
[2767]3172            if bltable        is None: bltable        = ''
[2047]3173
[2767]3174            sapplyfft = 'true' if applyfft else 'false'
3175            fftinfo = ','.join([sapplyfft, fftmethod.lower(), str(fftthresh).lower()])
[2641]3176
[2767]3177            scsvformat = 'T' if csvformat else 'F'
3178
[2277]3179            #CURRENTLY, PLOT=true is UNAVAILABLE UNTIL sinusoidal fitting is implemented as a fitter method.
[2767]3180            workscan._auto_sinusoid_baseline(mask,
3181                                             fftinfo,
[2349]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),
[2767]3190                                             outlog, scsvformat+blfile, bltable)
[2047]3191            workscan._add_history("auto_sinusoid_baseline", varlist)
[2767]3192
3193            if bltable == '':
3194                if insitu:
3195                    self._assign(workscan)
3196                else:
3197                    return workscan
[2047]3198            else:
[2767]3199                if not insitu:
3200                    return None
[2047]3201           
3202        except RuntimeError, e:
[2186]3203            raise_fitting_failure_exception(e)
[2047]3204
3205    @asaplog_post_dec
[2771]3206    def cspline_baseline(self, mask=None, npiece=None, insitu=None,
[2349]3207                         clipthresh=None, clipniter=None, plot=None,
3208                         getresidual=None, showprogress=None, minnrow=None,
[2767]3209                         outlog=None, blfile=None, csvformat=None,
3210                         bltable=None):
[1846]3211        """\
[2349]3212        Return a scan which has been baselined (all rows) by cubic spline
3213        function (piecewise cubic polynomial).
3214
[513]3215        Parameters:
[2771]3216            mask:         An optional mask
3217            npiece:       Number of pieces. (default is 2)
[2189]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)
[2349]3222            clipniter:    maximum number of iteration of 'clipthresh'-sigma
3223                          clipping (default is 0)
[2189]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)
[2641]3239            csvformat:    if True blfile is csv-formatted, default is False.
[2767]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)
[1846]3246
[2012]3247        Example:
[2349]3248            # return a scan baselined by a cubic spline consisting of 2 pieces
3249            # (i.e., 1 internal knot),
[2012]3250            # also with 3-sigma clipping, iteration up to 4 times
3251            bscan = scan.cspline_baseline(npiece=2,clipthresh=3.0,clipniter=4)
[2081]3252       
3253        Note:
3254            The best-fit parameter values output in logger and/or blfile are now
3255            based on specunit of 'channel'.
[2012]3256        """
3257       
[2186]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()
[1855]3266
[2410]3267            if mask         is None: mask         = []
[2189]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       = ''
[2767]3277            if csvformat    is None: csvformat    = False
3278            if bltable      is None: bltable      = ''
[1855]3279
[2767]3280            scsvformat = 'T' if csvformat else 'F'
[2641]3281
[2012]3282            #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
[2767]3283            workscan._cspline_baseline(mask, npiece,
3284                                       clipthresh, clipniter,
[2349]3285                                       getresidual,
3286                                       pack_progress_params(showprogress,
[2641]3287                                                            minnrow),
[2767]3288                                       outlog, scsvformat+blfile,
3289                                       bltable)
[2012]3290            workscan._add_history("cspline_baseline", varlist)
[2767]3291
3292            if bltable == '':
3293                if insitu:
3294                    self._assign(workscan)
3295                else:
3296                    return workscan
[2012]3297            else:
[2767]3298                if not insitu:
3299                    return None
[2012]3300           
3301        except RuntimeError, e:
[2186]3302            raise_fitting_failure_exception(e)
[1855]3303
[2186]3304    @asaplog_post_dec
[2771]3305    def auto_cspline_baseline(self, mask=None, npiece=None, insitu=None,
[2349]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,
[2767]3310                              blfile=None, csvformat=None, bltable=None):
[2012]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:
[2771]3318            mask:           an optional mask retreived from scantable
3319            npiece:         Number of pieces. (default is 2)
[2189]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)
[2349]3324            clipniter:      maximum number of iteration of 'clipthresh'-sigma
3325                            clipping (default is 0)
[2189]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)
[2641]3361            csvformat:      if True blfile is csv-formatted, default is False.
[2767]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)
[1846]3368
[1907]3369        Example:
[2012]3370            bscan = scan.auto_cspline_baseline(npiece=3, insitu=False)
[2081]3371       
3372        Note:
3373            The best-fit parameter values output in logger and/or blfile are now
3374            based on specunit of 'channel'.
[2012]3375        """
[1846]3376
[2186]3377        try:
3378            varlist = vars()
[2012]3379
[2186]3380            if insitu is None: insitu = rcParams['insitu']
3381            if insitu:
3382                workscan = self
[1391]3383            else:
[2186]3384                workscan = self.copy()
3385           
[2410]3386            #if mask           is None: mask           = [True for i in xrange(workscan.nchan())]
3387            if mask           is None: mask           = []
[2186]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
[2189]3396            if showprogress   is None: showprogress   = True
3397            if minnrow        is None: minnrow        = 1000
[2186]3398            if outlog         is None: outlog         = False
3399            if blfile         is None: blfile         = ''
[2641]3400            if csvformat      is None: csvformat      = False
[2767]3401            if bltable        is None: bltable        = ''
[1819]3402
[2767]3403            scsvformat = 'T' if csvformat else 'F'
[2641]3404
[2277]3405            #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
[2767]3406            workscan._auto_cspline_baseline(mask, npiece,
3407                                            clipthresh, clipniter,
[2269]3408                                            normalise_edge_param(edge),
3409                                            threshold,
3410                                            chan_avg_limit, getresidual,
3411                                            pack_progress_params(showprogress,
3412                                                                 minnrow),
[2767]3413                                            outlog,
3414                                            scsvformat+blfile,
3415                                            bltable)
[2012]3416            workscan._add_history("auto_cspline_baseline", varlist)
[2767]3417
3418            if bltable == '':
3419                if insitu:
3420                    self._assign(workscan)
3421                else:
3422                    return workscan
[1856]3423            else:
[2767]3424                if not insitu:
3425                    return None
[2012]3426           
3427        except RuntimeError, e:
[2186]3428            raise_fitting_failure_exception(e)
[513]3429
[1931]3430    @asaplog_post_dec
[2771]3431    def chebyshev_baseline(self, mask=None, order=None, insitu=None,
[2645]3432                           clipthresh=None, clipniter=None, plot=None,
3433                           getresidual=None, showprogress=None, minnrow=None,
[2767]3434                           outlog=None, blfile=None, csvformat=None,
3435                           bltable=None):
[2645]3436        """\
3437        Return a scan which has been baselined (all rows) by Chebyshev polynomials.
3438
3439        Parameters:
[2771]3440            mask:         An optional mask
3441            order:        the maximum order of Chebyshev polynomial (default is 5)
[2645]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.
[2767]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)
[2645]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       = ''
[2767]3501            if csvformat    is None: csvformat    = False
3502            if bltable      is None: bltable      = ''
[2645]3503
[2767]3504            scsvformat = 'T' if csvformat else 'F'
[2645]3505
3506            #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
[2767]3507            workscan._chebyshev_baseline(mask, order,
3508                                         clipthresh, clipniter,
[2645]3509                                         getresidual,
3510                                         pack_progress_params(showprogress,
3511                                                              minnrow),
[2767]3512                                         outlog, scsvformat+blfile,
3513                                         bltable)
[2645]3514            workscan._add_history("chebyshev_baseline", varlist)
[2767]3515
3516            if bltable == '':
3517                if insitu:
3518                    self._assign(workscan)
3519                else:
3520                    return workscan
[2645]3521            else:
[2767]3522                if not insitu:
3523                    return None
[2645]3524           
3525        except RuntimeError, e:
3526            raise_fitting_failure_exception(e)
3527
3528    @asaplog_post_dec
[2771]3529    def auto_chebyshev_baseline(self, mask=None, order=None, insitu=None,
[2645]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,
[2767]3534                              blfile=None, csvformat=None, bltable=None):
[2645]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:
[2771]3541            mask:           an optional mask retreived from scantable
3542            order:          the maximum order of Chebyshev polynomial (default is 5)
[2645]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.
[2767]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)
[2645]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
[2767]3623            if bltable        is None: bltable        = ''
[2645]3624
[2767]3625            scsvformat = 'T' if csvformat else 'F'
[2645]3626
3627            #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
[2767]3628            workscan._auto_chebyshev_baseline(mask, order,
3629                                              clipthresh, clipniter,
[2645]3630                                              normalise_edge_param(edge),
3631                                              threshold,
3632                                              chan_avg_limit, getresidual,
3633                                              pack_progress_params(showprogress,
3634                                                                   minnrow),
[2767]3635                                              outlog, scsvformat+blfile,
3636                                              bltable)
[2645]3637            workscan._add_history("auto_chebyshev_baseline", varlist)
[2767]3638
3639            if bltable == '':
3640                if insitu:
3641                    self._assign(workscan)
3642                else:
3643                    return workscan
[2645]3644            else:
[2767]3645                if not insitu:
3646                    return None
[2645]3647           
3648        except RuntimeError, e:
3649            raise_fitting_failure_exception(e)
3650
3651    @asaplog_post_dec
[2771]3652    def poly_baseline(self, mask=None, order=None, insitu=None,
[2767]3653                      clipthresh=None, clipniter=None, plot=None,
[2269]3654                      getresidual=None, showprogress=None, minnrow=None,
[2767]3655                      outlog=None, blfile=None, csvformat=None,
3656                      bltable=None):
[1907]3657        """\
3658        Return a scan which has been baselined (all rows) by a polynomial.
3659        Parameters:
[2771]3660            mask:         an optional mask
3661            order:        the order of the polynomial (default is 0)
[2189]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)
[2767]3665            clipthresh:   Clipping threshold. (default is 3.0, unit: sigma)
3666            clipniter:    maximum number of iteration of 'clipthresh'-sigma
3667                          clipping (default is 0)
[2189]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)
[2641]3682            csvformat:    if True blfile is csv-formatted, default is False.
[2767]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)
[2012]3689
[1907]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        """
[1931]3695       
[2186]3696        try:
3697            varlist = vars()
[1931]3698       
[2269]3699            if insitu is None:
3700                insitu = rcParams["insitu"]
[2186]3701            if insitu:
3702                workscan = self
3703            else:
3704                workscan = self.copy()
[1907]3705
[2410]3706            if mask         is None: mask         = []
[2189]3707            if order        is None: order        = 0
[2767]3708            if clipthresh   is None: clipthresh   = 3.0
3709            if clipniter    is None: clipniter    = 0
[2189]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
[2767]3715            if blfile       is None: blfile       = ''
[2641]3716            if csvformat    is None: csvformat    = False
[2767]3717            if bltable      is None: bltable      = ''
[1907]3718
[2767]3719            scsvformat = 'T' if csvformat else 'F'
[2641]3720
[2012]3721            if plot:
[2269]3722                outblfile = (blfile != "") and \
[2349]3723                    os.path.exists(os.path.expanduser(
3724                                    os.path.expandvars(blfile))
3725                                   )
[2269]3726                if outblfile:
3727                    blf = open(blfile, "a")
[2012]3728               
[1907]3729                f = fitter()
3730                f.set_function(lpoly=order)
[2186]3731               
3732                rows = xrange(workscan.nrow())
3733                #if len(rows) > 0: workscan._init_blinfo()
[2610]3734
3735                action = "H"
[1907]3736                for r in rows:
3737                    f.x = workscan._getabcissa(r)
3738                    f.y = workscan._getspectrum(r)
[2541]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                   
[1907]3744                    f.data = None
3745                    f.fit()
[2541]3746
[2610]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
[1907]3755                    if accept_fit.upper() == "N":
3756                        continue
[2610]3757                    elif accept_fit.upper() == "R":
3758                        break
3759                    elif accept_fit.upper() == "A":
3760                        action = "Y"
[2012]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)
[2269]3765                    workscan._setspectrum((f.fitter.getresidual()
3766                                           if getresidual else f.fitter.getfit()), r)
[1907]3767                   
[2012]3768                    if outblfile:
3769                        rms = workscan.get_rms(f.mask, r)
[2269]3770                        dataout = \
3771                            workscan.format_blparams_row(blpars["params"],
3772                                                         blpars["fixed"],
3773                                                         rms, str(masklist),
[2641]3774                                                         r, True, csvformat)
[2012]3775                        blf.write(dataout)
3776
[1907]3777                f._p.unmap()
3778                f._p = None
[2012]3779
[2349]3780                if outblfile:
3781                    blf.close()
[1907]3782            else:
[2767]3783                workscan._poly_baseline(mask, order,
3784                                        clipthresh, clipniter, #
3785                                        getresidual,
[2269]3786                                        pack_progress_params(showprogress,
3787                                                             minnrow),
[2767]3788                                        outlog, scsvformat+blfile,
3789                                        bltable)  #
[1907]3790           
3791            workscan._add_history("poly_baseline", varlist)
3792           
3793            if insitu:
3794                self._assign(workscan)
3795            else:
3796                return workscan
3797           
[1919]3798        except RuntimeError, e:
[2186]3799            raise_fitting_failure_exception(e)
[1907]3800
[2186]3801    @asaplog_post_dec
[2771]3802    def auto_poly_baseline(self, mask=None, order=None, insitu=None,
[2767]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):
[1846]3808        """\
[1931]3809        Return a scan which has been baselined (all rows) by a polynomial.
[880]3810        Spectral lines are detected first using linefinder and masked out
3811        to avoid them affecting the baseline solution.
3812
3813        Parameters:
[2771]3814            mask:           an optional mask retreived from scantable
3815            order:          the order of the polynomial (default is 0)
[2189]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)
[2767]3819            clipthresh:     Clipping threshold. (default is 3.0, unit: sigma)
3820            clipniter:      maximum number of iteration of 'clipthresh'-sigma
3821                            clipping (default is 0)
[2189]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)
[2641]3856            csvformat:      if True blfile is csv-formatted, default is False.
[2767]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)
[1846]3863
[2012]3864        Example:
3865            bscan = scan.auto_poly_baseline(order=7, insitu=False)
3866        """
[880]3867
[2186]3868        try:
3869            varlist = vars()
[1846]3870
[2269]3871            if insitu is None:
3872                insitu = rcParams['insitu']
[2186]3873            if insitu:
3874                workscan = self
3875            else:
3876                workscan = self.copy()
[1846]3877
[2410]3878            if mask           is None: mask           = []
[2186]3879            if order          is None: order          = 0
[2767]3880            if clipthresh     is None: clipthresh     = 3.0
3881            if clipniter      is None: clipniter      = 0
[2186]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
[2189]3887            if showprogress   is None: showprogress   = True
3888            if minnrow        is None: minnrow        = 1000
[2186]3889            if outlog         is None: outlog         = False
3890            if blfile         is None: blfile         = ''
[2641]3891            if csvformat      is None: csvformat      = False
[2767]3892            if bltable        is None: bltable        = ''
[1846]3893
[2767]3894            scsvformat = 'T' if csvformat else 'F'
[2641]3895
[2186]3896            edge = normalise_edge_param(edge)
[880]3897
[2012]3898            if plot:
[2269]3899                outblfile = (blfile != "") and \
3900                    os.path.exists(os.path.expanduser(os.path.expandvars(blfile)))
[2012]3901                if outblfile: blf = open(blfile, "a")
3902               
[2186]3903                from asap.asaplinefind import linefinder
[2012]3904                fl = linefinder()
[2269]3905                fl.set_options(threshold=threshold, avg_limit=chan_avg_limit)
[2012]3906                fl.set_scan(workscan)
[2186]3907               
[2012]3908                f = fitter()
3909                f.set_function(lpoly=order)
[880]3910
[2186]3911                rows = xrange(workscan.nrow())
3912                #if len(rows) > 0: workscan._init_blinfo()
[2610]3913
3914                action = "H"
[2012]3915                for r in rows:
[2186]3916                    idx = 2*workscan.getif(r)
[2541]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]) 
[907]3922
[2012]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
[2610]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
[2012]3934                    if accept_fit.upper() == "N":
3935                        #workscan._append_blinfo(None, None, None)
3936                        continue
[2610]3937                    elif accept_fit.upper() == "R":
3938                        break
3939                    elif accept_fit.upper() == "A":
3940                        action = "Y"
[2012]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)
[2349]3945                    workscan._setspectrum(
3946                        (f.fitter.getresidual() if getresidual
3947                                                else f.fitter.getfit()), r
3948                        )
[2012]3949
3950                    if outblfile:
3951                        rms = workscan.get_rms(f.mask, r)
[2269]3952                        dataout = \
3953                            workscan.format_blparams_row(blpars["params"],
3954                                                         blpars["fixed"],
3955                                                         rms, str(masklist),
[2641]3956                                                         r, True, csvformat)
[2012]3957                        blf.write(dataout)
3958                   
3959                f._p.unmap()
3960                f._p = None
3961
3962                if outblfile: blf.close()
3963            else:
[2767]3964                workscan._auto_poly_baseline(mask, order,
3965                                             clipthresh, clipniter,
3966                                             edge, threshold,
[2269]3967                                             chan_avg_limit, getresidual,
3968                                             pack_progress_params(showprogress,
3969                                                                  minnrow),
[2767]3970                                             outlog, scsvformat+blfile,
3971                                             bltable)
3972            workscan._add_history("auto_poly_baseline", varlist)
[2012]3973
[2767]3974            if bltable == '':
3975                if insitu:
3976                    self._assign(workscan)
3977                else:
3978                    return workscan
[2012]3979            else:
[2767]3980                if not insitu:
3981                    return None
[2012]3982           
3983        except RuntimeError, e:
[2186]3984            raise_fitting_failure_exception(e)
[2012]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
[880]4000
[2012]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       
[1862]4011    @asaplog_post_dec
[914]4012    def rotate_linpolphase(self, angle):
[1846]4013        """\
[914]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.
[1846]4017
[914]4018        Parameters:
[1846]4019
[914]4020            angle:   The angle (degrees) to rotate (add) by.
[1846]4021
4022        Example::
4023
[914]4024            scan.rotate_linpolphase(2.3)
[1846]4025
[914]4026        """
4027        varlist = vars()
[936]4028        self._math._rotate_linpolphase(self, angle)
[914]4029        self._add_history("rotate_linpolphase", varlist)
4030        return
[710]4031
[1862]4032    @asaplog_post_dec
[914]4033    def rotate_xyphase(self, angle):
[1846]4034        """\
[914]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.
[1846]4038
[914]4039        Parameters:
[1846]4040
[914]4041            angle:   The angle (degrees) to rotate (add) by.
[1846]4042
4043        Example::
4044
[914]4045            scan.rotate_xyphase(2.3)
[1846]4046
[914]4047        """
4048        varlist = vars()
[936]4049        self._math._rotate_xyphase(self, angle)
[914]4050        self._add_history("rotate_xyphase", varlist)
4051        return
4052
[1862]4053    @asaplog_post_dec
[914]4054    def swap_linears(self):
[1846]4055        """\
[1573]4056        Swap the linear polarisations XX and YY, or better the first two
[1348]4057        polarisations as this also works for ciculars.
[914]4058        """
4059        varlist = vars()
[936]4060        self._math._swap_linears(self)
[914]4061        self._add_history("swap_linears", varlist)
4062        return
4063
[1862]4064    @asaplog_post_dec
[914]4065    def invert_phase(self):
[1846]4066        """\
[914]4067        Invert the phase of the complex polarisation
4068        """
4069        varlist = vars()
[936]4070        self._math._invert_phase(self)
[914]4071        self._add_history("invert_phase", varlist)
4072        return
4073
[1862]4074    @asaplog_post_dec
[876]4075    def add(self, offset, insitu=None):
[1846]4076        """\
[513]4077        Return a scan where all spectra have the offset added
[1846]4078
[513]4079        Parameters:
[1846]4080
[513]4081            offset:      the offset
[1855]4082
[513]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)
[1846]4086
[513]4087        """
4088        if insitu is None: insitu = rcParams['insitu']
[876]4089        self._math._setinsitu(insitu)
[513]4090        varlist = vars()
[876]4091        s = scantable(self._math._unaryop(self, offset, "ADD", False))
[1118]4092        s._add_history("add", varlist)
[876]4093        if insitu:
4094            self._assign(s)
4095        else:
[513]4096            return s
4097
[1862]4098    @asaplog_post_dec
[1308]4099    def scale(self, factor, tsys=True, insitu=None):
[1846]4100        """\
4101
[1938]4102        Return a scan where all spectra are scaled by the given 'factor'
[1846]4103
[513]4104        Parameters:
[1846]4105
[1819]4106            factor:      the scaling factor (float or 1D float list)
[1855]4107
[513]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)
[1855]4111
[513]4112            tsys:        if True (default) then apply the operation to Tsys
4113                         as well as the data
[1846]4114
[513]4115        """
4116        if insitu is None: insitu = rcParams['insitu']
[876]4117        self._math._setinsitu(insitu)
[513]4118        varlist = vars()
[1819]4119        s = None
4120        import numpy
4121        if isinstance(factor, list) or isinstance(factor, numpy.ndarray):
[2320]4122            if isinstance(factor[0], list) or isinstance(factor[0],
4123                                                         numpy.ndarray):
[1819]4124                from asapmath import _array2dOp
[2320]4125                s = _array2dOp( self, factor, "MUL", tsys, insitu )
[1819]4126            else:
[2320]4127                s = scantable( self._math._arrayop( self, factor,
4128                                                    "MUL", tsys ) )
[1819]4129        else:
[2320]4130            s = scantable(self._math._unaryop(self, factor, "MUL", tsys))
[1118]4131        s._add_history("scale", varlist)
[876]4132        if insitu:
4133            self._assign(s)
4134        else:
[513]4135            return s
4136
[2349]4137    @preserve_selection
4138    def set_sourcetype(self, match, matchtype="pattern",
[1504]4139                       sourcetype="reference"):
[1846]4140        """\
[1502]4141        Set the type of the source to be an source or reference scan
[1846]4142        using the provided pattern.
4143
[1502]4144        Parameters:
[1846]4145
[1504]4146            match:          a Unix style pattern, regular expression or selector
[1855]4147
[1504]4148            matchtype:      'pattern' (default) UNIX style pattern or
4149                            'regex' regular expression
[1855]4150
[1502]4151            sourcetype:     the type of the source to use (source/reference)
[1846]4152
[1502]4153        """
4154        varlist = vars()
4155        stype = -1
[2480]4156        if sourcetype.lower().startswith("r") or sourcetype.lower() == "off":
[1502]4157            stype = 1
[2480]4158        elif sourcetype.lower().startswith("s") or sourcetype.lower() == "on":
[1502]4159            stype = 0
[1504]4160        else:
[2480]4161            raise ValueError("Illegal sourcetype use s(ource)/on or r(eference)/off")
[1504]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)")
[1502]4168        sel = selector()
4169        if isinstance(match, selector):
4170            sel = match
4171        else:
[2480]4172            sel.set_query("SRCNAME=%s('%s')" % (matchtype, match))
4173        self.set_selection(sel)
[1502]4174        self._setsourcetype(stype)
[1573]4175        self._add_history("set_sourcetype", varlist)
[1502]4176
[1862]4177    @asaplog_post_dec
[1857]4178    @preserve_selection
[1819]4179    def auto_quotient(self, preserve=True, mode='paired', verify=False):
[1846]4180        """\
[670]4181        This function allows to build quotients automatically.
[1819]4182        It assumes the observation to have the same number of
[670]4183        "ons" and "offs"
[1846]4184
[670]4185        Parameters:
[1846]4186
[710]4187            preserve:       you can preserve (default) the continuum or
4188                            remove it.  The equations used are
[1857]4189
[670]4190                            preserve: Output = Toff * (on/off) - Toff
[1857]4191
[1070]4192                            remove:   Output = Toff * (on/off) - Ton
[1855]4193
[1573]4194            mode:           the on/off detection mode
[1348]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
[1502]4200                            'time'
4201                            finds the closest off in time
[1348]4202
[1857]4203        .. todo:: verify argument is not implemented
4204
[670]4205        """
[1857]4206        varlist = vars()
[1348]4207        modes = ["time", "paired"]
[670]4208        if not mode in modes:
[876]4209            msg = "please provide valid mode. Valid modes are %s" % (modes)
4210            raise ValueError(msg)
[1348]4211        s = None
4212        if mode.lower() == "paired":
[1857]4213            sel = self.get_selection()
[1875]4214            sel.set_query("SRCTYPE==psoff")
[1356]4215            self.set_selection(sel)
[1348]4216            offs = self.copy()
[1875]4217            sel.set_query("SRCTYPE==pson")
[1356]4218            self.set_selection(sel)
[1348]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))
[1118]4223        s._add_history("auto_quotient", varlist)
[876]4224        return s
[710]4225
[1862]4226    @asaplog_post_dec
[1145]4227    def mx_quotient(self, mask = None, weight='median', preserve=True):
[1846]4228        """\
[1143]4229        Form a quotient using "off" beams when observing in "MX" mode.
[1846]4230
[1143]4231        Parameters:
[1846]4232
[1145]4233            mask:           an optional mask to be used when weight == 'stddev'
[1855]4234
[1143]4235            weight:         How to average the off beams.  Default is 'median'.
[1855]4236
[1145]4237            preserve:       you can preserve (default) the continuum or
[1855]4238                            remove it.  The equations used are:
[1846]4239
[1855]4240                                preserve: Output = Toff * (on/off) - Toff
4241
4242                                remove:   Output = Toff * (on/off) - Ton
4243
[1217]4244        """
[1593]4245        mask = mask or ()
[1141]4246        varlist = vars()
4247        on = scantable(self._math._mx_extract(self, 'on'))
[1143]4248        preoff = scantable(self._math._mx_extract(self, 'off'))
4249        off = preoff.average_time(mask=mask, weight=weight, scanav=False)
[1217]4250        from asapmath  import quotient
[1145]4251        q = quotient(on, off, preserve)
[1143]4252        q._add_history("mx_quotient", varlist)
[1217]4253        return q
[513]4254
[1862]4255    @asaplog_post_dec
[718]4256    def freq_switch(self, insitu=None):
[1846]4257        """\
[718]4258        Apply frequency switching to the data.
[1846]4259
[718]4260        Parameters:
[1846]4261
[718]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)
[1846]4265
[718]4266        """
4267        if insitu is None: insitu = rcParams['insitu']
[876]4268        self._math._setinsitu(insitu)
[718]4269        varlist = vars()
[876]4270        s = scantable(self._math._freqswitch(self))
[1118]4271        s._add_history("freq_switch", varlist)
[1856]4272        if insitu:
4273            self._assign(s)
4274        else:
4275            return s
[718]4276
[1862]4277    @asaplog_post_dec
[780]4278    def recalc_azel(self):
[1846]4279        """Recalculate the azimuth and elevation for each position."""
[780]4280        varlist = vars()
[876]4281        self._recalcazel()
[780]4282        self._add_history("recalc_azel", varlist)
4283        return
4284
[1862]4285    @asaplog_post_dec
[513]4286    def __add__(self, other):
[2574]4287        """
4288        implicit on all axes and on Tsys
4289        """
[513]4290        varlist = vars()
[2574]4291        s = self.__op( other, "ADD" )
[513]4292        s._add_history("operator +", varlist)
4293        return s
4294
[1862]4295    @asaplog_post_dec
[513]4296    def __sub__(self, other):
4297        """
4298        implicit on all axes and on Tsys
4299        """
4300        varlist = vars()
[2574]4301        s = self.__op( other, "SUB" )
[513]4302        s._add_history("operator -", varlist)
4303        return s
[710]4304
[1862]4305    @asaplog_post_dec
[513]4306    def __mul__(self, other):
4307        """
4308        implicit on all axes and on Tsys
4309        """
4310        varlist = vars()
[2574]4311        s = self.__op( other, "MUL" ) ;
[513]4312        s._add_history("operator *", varlist)
4313        return s
4314
[710]4315
[1862]4316    @asaplog_post_dec
[513]4317    def __div__(self, other):
4318        """
4319        implicit on all axes and on Tsys
4320        """
4321        varlist = vars()
[2574]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 ):
[513]4328        s = None
4329        if isinstance(other, scantable):
[2574]4330            s = scantable(self._math._binaryop(self, other, mode))
[513]4331        elif isinstance(other, float):
4332            if other == 0.0:
[718]4333                raise ZeroDivisionError("Dividing by zero is not recommended")
[2574]4334            s = scantable(self._math._unaryop(self, other, mode, False))
[2144]4335        elif isinstance(other, list) or isinstance(other, numpy.ndarray):
[2349]4336            if isinstance(other[0], list) \
4337                    or isinstance(other[0], numpy.ndarray):
[2144]4338                from asapmath import _array2dOp
[2574]4339                s = _array2dOp( self, other, mode, False )
[2144]4340            else:
[2574]4341                s = scantable( self._math._arrayop( self, other,
4342                                                    mode, False ) )
[513]4343        else:
[718]4344            raise TypeError("Other input is not a scantable or float value")
[513]4345        return s
4346
[1862]4347    @asaplog_post_dec
[530]4348    def get_fit(self, row=0):
[1846]4349        """\
[530]4350        Print or return the stored fits for a row in the scantable
[1846]4351
[530]4352        Parameters:
[1846]4353
[530]4354            row:    the row which the fit has been applied to.
[1846]4355
[530]4356        """
4357        if row > self.nrow():
4358            return
[976]4359        from asap.asapfit import asapfit
[530]4360        fit = asapfit(self._getfit(row))
[1859]4361        asaplog.push( '%s' %(fit) )
4362        return fit.as_dict()
[530]4363
[2349]4364    @preserve_selection
[1483]4365    def flag_nans(self):
[1846]4366        """\
[1483]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()):
[1589]4372            sel = self.get_row_selector(i)
4373            self.set_selection(basesel+sel)
[1483]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
[1588]4379    def get_row_selector(self, rowno):
[1992]4380        return selector(rows=[rowno])
[1573]4381
[484]4382    def _add_history(self, funcname, parameters):
[1435]4383        if not rcParams['scantable.history']:
4384            return
[484]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
[2349]4391        if parameters.has_key('self'):
4392            del parameters['self']
[1118]4393        for k, v in parameters.iteritems():
[484]4394            if type(v) is dict:
[1118]4395                for k2, v2 in v.iteritems():
[484]4396                    hist += k2
4397                    hist += "="
[1118]4398                    if isinstance(v2, scantable):
[484]4399                        hist += 'scantable'
4400                    elif k2 == 'mask':
[1118]4401                        if isinstance(v2, list) or isinstance(v2, tuple):
[513]4402                            hist += str(self._zip_mask(v2))
4403                        else:
4404                            hist += str(v2)
[484]4405                    else:
[513]4406                        hist += str(v2)
[484]4407            else:
4408                hist += k
4409                hist += "="
[1118]4410                if isinstance(v, scantable):
[484]4411                    hist += 'scantable'
4412                elif k == 'mask':
[1118]4413                    if isinstance(v, list) or isinstance(v, tuple):
[513]4414                        hist += str(self._zip_mask(v))
4415                    else:
4416                        hist += str(v)
[484]4417                else:
4418                    hist += str(v)
4419            hist += sep
4420        hist = hist[:-2] # remove trailing '##'
4421        self._addhistory(hist)
4422
[710]4423
[484]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:
[710]4433                j = len(mask)
[1118]4434            segments.append([i, j])
[710]4435            i = j
[484]4436        return segments
[714]4437
[626]4438    def _get_ordinate_label(self):
4439        fu = "("+self.get_fluxunit()+")"
4440        import re
4441        lbl = "Intensity"
[1118]4442        if re.match(".K.", fu):
[626]4443            lbl = "Brightness Temperature "+ fu
[1118]4444        elif re.match(".Jy.", fu):
[626]4445            lbl = "Flux density "+ fu
4446        return lbl
[710]4447
[876]4448    def _check_ifs(self):
[2349]4449#        return len(set([self.nchan(i) for i in self.getifnos()])) == 1
[1986]4450        nchans = [self.nchan(i) for i in self.getifnos()]
[2004]4451        nchans = filter(lambda t: t > 0, nchans)
[876]4452        return (sum(nchans)/len(nchans) == nchans[0])
[976]4453
[1862]4454    @asaplog_post_dec
[1916]4455    def _fill(self, names, unit, average, opts={}):
[976]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')
[1079]4467        stype = int(rcParams['scantable.storage'].lower() == 'disk')
[976]4468        for name in fullnames:
[1073]4469            tbl = Scantable(stype)
[2004]4470            if is_ms( name ):
4471                r = msfiller( tbl )
4472            else:
4473                r = filler( tbl )
[976]4474            msg = "Importing %s..." % (name)
[1118]4475            asaplog.push(msg, False)
[2349]4476            r.open(name, opts)
[2480]4477            rx = rcParams['scantable.reference']
4478            r.setreferenceexpr(rx)
[1843]4479            r.fill()
[976]4480            if average:
[1118]4481                tbl = self._math._average((tbl, ), (), 'NONE', 'SCAN')
[976]4482            if not first:
4483                tbl = self._math._merge([self, tbl])
4484            Scantable.__init__(self, tbl)
[1843]4485            r.close()
[1118]4486            del r, tbl
[976]4487            first = False
[1861]4488            #flush log
4489        asaplog.post()
[976]4490        if unit is not None:
4491            self.set_fluxunit(unit)
[1824]4492        if not is_casapy():
4493            self.set_freqframe(rcParams['scantable.freqframe'])
[976]4494
[2610]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'
[2012]4513
[1402]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.