source: trunk/python/scantable.py@ 2750

Last change on this file since 2750 was 2713, checked in by WataruKawasaki, 12 years ago

New Development: Yes

JIRA Issue: Yes CAS-3618

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s): sd

Description: new method for scantable to calculate AIC, AICc, BIC and GCV.


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