source: trunk/python/scantable.py @ 2767

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

New Development: Yes

JIRA Issue: Yes CAS-4794

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s): sd

Description: functions to apply/write STBaselineTable in which baseline parameters stored.


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