source: trunk/python/scantable.py@ 2950

Last change on this file since 2950 was 2937, checked in by WataruKawasaki, 10 years ago

New Development: No

JIRA Issue: Yes CAS-6485

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s): sd

Description: modified scantable.parse_spw_selection() so that velocity corresponding to the central frequency rather than the centeral value of velocity range is checked in selecting spw via velocity ranges.


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