source: trunk/python/scantable.py@ 2399

Last change on this file since 2399 was 2351, checked in by Kana Sugimoto, 13 years ago

New Development: No

JIRA Issue: No (a minor bug fix)

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs: unit tests of sdbaseline (CASA)

Put in Release Notes: No

Module(s): sdbaseline (CASA)

Description: fix a minor typo introduced in rev.2348.


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