source: trunk/python/scantable.py@ 2932

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

New Development: No

JIRA Issue: Yes CAS-6465

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s): sd

Description: modified sd.scantable.parse_{idx|spw}_selection() so that no duplicated values appear in returned values.


  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 206.5 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
[2884]1837 '1.3~1.5GHz' = all spws that fall in or have at
1838 least some overwrap with frequency
1839 range between 1.3GHz and 1.5GHz.
1840 '1.3~1.5GHz:1.3~1.5GHz' = channels that fall
1841 between the specified
1842 frequency range in spws
1843 that fall in or have
1844 overwrap with the
1845 specified frequency
1846 range.
1847 '1:-200~250km/s' = channels that fall between the
1848 specified velocity range in
1849 spw 1.
[2897]1850 restfreq: the rest frequency.
1851 examples: '115.2712GHz', 115271201800.0
1852 frame: an optional frame type, default 'LSRK'. Valid frames are:
1853 'TOPO', 'LSRD', 'LSRK', 'BARY',
1854 'GEO', 'GALACTO', 'LGROUP', 'CMB'
1855 doppler: one of 'RADIO', 'OPTICAL', 'Z', 'BETA', 'GAMMA'
[2882]1856 Returns:
1857 A dictionary of selected (valid) spw and masklist pairs,
1858 e.g. {'0': [[50,250],[350,462]], '2': [[100,400],[550,974]]}
1859 """
1860 if not isinstance(selectstring, str):
1861 asaplog.post()
1862 asaplog.push("Expression of spw/channel selection must be a string.")
1863 asaplog.post("ERROR")
1864
1865 orig_unit = self.get_unit()
1866 self.set_unit('channel')
1867
[2891]1868 if restfreq is not None:
[2892]1869 orig_molids = self._getmolidcol_list()
1870 set_restfreq(self, restfreq)
[2882]1871
[2897]1872 orig_coord = self._getcoordinfo()
[2892]1873
1874 if frame is not None:
1875 orig_frame = orig_coord[1]
1876 self.set_freqframe(frame)
1877
1878 if doppler is not None:
1879 orig_doppler = orig_coord[2]
1880 self.set_doppler(doppler)
[2882]1881
1882 valid_ifs = self.getifnos()
1883
1884 comma_sep = selectstring.split(",")
1885 res = {}
1886
1887 for cms_elem in comma_sep:
1888 colon_sep = cms_elem.split(":")
1889
1890 if (len(colon_sep) > 2):
1891 raise RuntimeError("Invalid selection expression: more than two colons!")
1892
1893 # parse spw expression and store result in spw_list.
1894 # allowed cases include '', '*', 'a', '<a', '>a', 'a~b',
[2884]1895 # 'a~b*Hz' (where * can be '', 'k', 'M', 'G' etc.),
1896 # 'a~b*m/s' (where * can be '' or 'k') and also
[2882]1897 # several of the above expressions connected with ';'.
1898
1899 spw_list = []
1900
1901 semicolon_sep = colon_sep[0].split(";")
1902
1903 for scs_elem in semicolon_sep:
1904 scs_elem = scs_elem.strip()
1905
1906 lt_sep = scs_elem.split("<")
1907 gt_sep = scs_elem.split(">")
1908 ti_sep = scs_elem.split("~")
1909
1910 lt_sep_length = len(lt_sep)
1911 gt_sep_length = len(gt_sep)
1912 ti_sep_length = len(ti_sep)
1913
1914 len_product = lt_sep_length * gt_sep_length * ti_sep_length
1915
1916 if (len_product > 2):
1917 # '<', '>' and '~' must not coexist in a single spw expression
1918
1919 raise RuntimeError("Invalid spw selection.")
1920
1921 elif (len_product == 1):
1922 # '', '*', or single spw number.
1923
1924 if (scs_elem == "") or (scs_elem == "*"):
1925 spw_list = valid_ifs[:] # deep copy
1926
1927 else: # single number
[2887]1928 expr = int(scs_elem)
1929 spw_list.append(expr)
1930 if expr not in valid_ifs:
1931 asaplog.push("Invalid spw given. Ignored.")
1932
[2882]1933 else: # (len_product == 2)
[2887]1934 # namely, one of '<', '>' or '~' appears just once.
[2882]1935
1936 if (lt_sep_length == 2): # '<a'
1937 if is_number(lt_sep[1]):
[2886]1938 no_valid_spw = True
[2882]1939 for i in valid_ifs:
1940 if (i < float(lt_sep[1])):
1941 spw_list.append(i)
[2886]1942 no_valid_spw = False
1943
1944 if no_valid_spw:
1945 raise ValueError("Invalid spw selection ('<" + str(lt_sep[1]) + "').")
[2882]1946
1947 else:
[2886]1948 raise RuntimeError("Invalid spw selection.")
[2882]1949
1950 elif (gt_sep_length == 2): # '>a'
1951 if is_number(gt_sep[1]):
[2886]1952 no_valid_spw = True
[2882]1953 for i in valid_ifs:
1954 if (i > float(gt_sep[1])):
1955 spw_list.append(i)
[2886]1956 no_valid_spw = False
1957
1958 if no_valid_spw:
1959 raise ValueError("Invalid spw selection ('>" + str(gt_sep[1]) + "').")
[2882]1960
1961 else:
[2886]1962 raise RuntimeError("Invalid spw selection.")
[2882]1963
1964 else: # (ti_sep_length == 2) where both boundaries inclusive
1965 expr0 = ti_sep[0].strip()
1966 expr1 = ti_sep[1].strip()
1967
1968 if is_number(expr0) and is_number(expr1):
1969 # 'a~b'
1970 expr_pmin = min(float(expr0), float(expr1))
1971 expr_pmax = max(float(expr0), float(expr1))
[2887]1972 has_invalid_spw = False
[2886]1973 no_valid_spw = True
1974
[2882]1975 for i in valid_ifs:
1976 if (expr_pmin <= i) and (i <= expr_pmax):
1977 spw_list.append(i)
[2886]1978 no_valid_spw = False
[2887]1979 else:
1980 has_invalid_spw = True
[2886]1981
[2887]1982 if has_invalid_spw:
1983 msg = "Invalid spw is given. Ignored."
1984 asaplog.push(msg)
1985 asaplog.post()
1986
[2886]1987 if no_valid_spw:
1988 raise ValueError("No valid spw in range ('" + str(expr_pmin) + "~" + str(expr_pmax) + "').")
[2887]1989
[2884]1990 elif is_number(expr0) and is_frequency(expr1):
1991 # 'a~b*Hz'
1992 (expr_f0, expr_f1) = get_freq_by_string(expr0, expr1)
[2886]1993 no_valid_spw = True
1994
[2882]1995 for coord in self._get_coordinate_list():
1996 expr_p0 = coord['coord'].to_pixel(expr_f0)
1997 expr_p1 = coord['coord'].to_pixel(expr_f1)
1998 expr_pmin = min(expr_p0, expr_p1)
1999 expr_pmax = max(expr_p0, expr_p1)
2000
2001 spw = coord['if']
2002 pmin = 0.0
2003 pmax = float(self.nchan(spw) - 1)
2004
2005 if ((expr_pmax - pmin)*(expr_pmin - pmax) <= 0.0):
2006 spw_list.append(spw)
[2886]2007 no_valid_spw = False
2008
2009 if no_valid_spw:
2010 raise ValueError("No valid spw in range ('" + str(expr0) + "~" + str(expr1) + "').")
[2882]2011
[2884]2012 elif is_number(expr0) and is_velocity(expr1):
2013 # 'a~b*m/s'
2014 (expr_v0, expr_v1) = get_velocity_by_string(expr0, expr1)
[2882]2015 expr_vmin = min(expr_v0, expr_v1)
2016 expr_vmax = max(expr_v0, expr_v1)
[2886]2017 no_valid_spw = True
2018
[2882]2019 for coord in self._get_coordinate_list():
2020 spw = coord['if']
2021
2022 pmin = 0.0
2023 pmax = float(self.nchan(spw) - 1)
2024
2025 vel0 = coord['coord'].to_velocity(pmin)
2026 vel1 = coord['coord'].to_velocity(pmax)
2027
2028 vmin = min(vel0, vel1)
2029 vmax = max(vel0, vel1)
2030
2031 if ((expr_vmax - vmin)*(expr_vmin - vmax) <= 0.0):
2032 spw_list.append(spw)
[2886]2033 no_valid_spw = False
2034
2035 if no_valid_spw:
2036 raise ValueError("No valid spw in range ('" + str(expr0) + "~" + str(expr1) + "').")
[2882]2037
2038 else:
2039 # cases such as 'aGHz~bkm/s' are not allowed now
2040 raise RuntimeError("Invalid spw selection.")
2041
[2887]2042 # check spw list and remove invalid ones.
2043 # if no valid spw left, emit ValueError.
2044 if len(spw_list) == 0:
2045 raise ValueError("No valid spw in given range.")
2046
[2882]2047 # parse channel expression and store the result in crange_list.
2048 # allowed cases include '', 'a~b', 'a*Hz~b*Hz' (where * can be
2049 # '', 'k', 'M', 'G' etc.), 'a*m/s~b*m/s' (where * can be '' or 'k')
2050 # and also several of the above expressions connected with ';'.
2051
2052 for spw in spw_list:
2053 pmin = 0.0
2054 pmax = float(self.nchan(spw) - 1)
[2909]2055
2056 molid = self._getmolidcol_list()[self.get_first_rowno_by_if(spw)]
[2882]2057
2058 if (len(colon_sep) == 1):
2059 # no expression for channel selection,
2060 # which means all channels are to be selected.
2061 crange_list = [[pmin, pmax]]
2062
2063 else: # (len(colon_sep) == 2)
2064 crange_list = []
2065
2066 found = False
2067 for i in self._get_coordinate_list():
2068 if (i['if'] == spw):
2069 coord = i['coord']
2070 found = True
2071 break
2072
[2887]2073 if found:
2074 semicolon_sep = colon_sep[1].split(";")
2075 for scs_elem in semicolon_sep:
2076 scs_elem = scs_elem.strip()
[2882]2077
[2887]2078 ti_sep = scs_elem.split("~")
2079 ti_sep_length = len(ti_sep)
[2882]2080
[2887]2081 if (ti_sep_length > 2):
2082 raise RuntimeError("Invalid channel selection.")
[2882]2083
[2887]2084 elif (ti_sep_length == 1):
2085 if (scs_elem == "") or (scs_elem == "*"):
2086 # '' and '*' for all channels
2087 crange_list = [[pmin, pmax]]
2088 break
2089 elif (is_number(scs_elem)):
2090 # single channel given
2091 crange_list.append([float(scs_elem), float(scs_elem)])
2092 else:
2093 raise RuntimeError("Invalid channel selection.")
[2882]2094
[2887]2095 else: #(ti_sep_length == 2)
2096 expr0 = ti_sep[0].strip()
2097 expr1 = ti_sep[1].strip()
[2882]2098
[2887]2099 if is_number(expr0) and is_number(expr1):
2100 # 'a~b'
2101 expr_pmin = min(float(expr0), float(expr1))
2102 expr_pmax = max(float(expr0), float(expr1))
[2882]2103
[2887]2104 elif is_number(expr0) and is_frequency(expr1):
2105 # 'a~b*Hz'
2106 (expr_f0, expr_f1) = get_freq_by_string(expr0, expr1)
2107 expr_p0 = coord.to_pixel(expr_f0)
2108 expr_p1 = coord.to_pixel(expr_f1)
2109 expr_pmin = min(expr_p0, expr_p1)
2110 expr_pmax = max(expr_p0, expr_p1)
[2882]2111
[2887]2112 elif is_number(expr0) and is_velocity(expr1):
2113 # 'a~b*m/s'
[2909]2114 restf = self.get_restfreqs()[molid][0]
[2887]2115 (expr_v0, expr_v1) = get_velocity_by_string(expr0, expr1)
[2897]2116 dppl = self.get_doppler()
2117 expr_f0 = get_frequency_by_velocity(restf, expr_v0, dppl)
2118 expr_f1 = get_frequency_by_velocity(restf, expr_v1, dppl)
[2887]2119 expr_p0 = coord.to_pixel(expr_f0)
2120 expr_p1 = coord.to_pixel(expr_f1)
2121 expr_pmin = min(expr_p0, expr_p1)
2122 expr_pmax = max(expr_p0, expr_p1)
[2882]2123
[2887]2124 else:
2125 # cases such as 'aGHz~bkm/s' are not allowed now
2126 raise RuntimeError("Invalid channel selection.")
[2882]2127
[2887]2128 cmin = max(pmin, expr_pmin)
2129 cmax = min(pmax, expr_pmax)
2130 # if the given range of channel selection has overwrap with
2131 # that of current spw, output the overwrap area.
2132 if (cmin <= cmax):
2133 cmin = float(int(cmin + 0.5))
2134 cmax = float(int(cmax + 0.5))
2135 crange_list.append([cmin, cmax])
[2882]2136
2137 if (len(crange_list) == 0):
2138 crange_list.append([])
2139
[2910]2140 if (len(crange_list[0]) > 0):
2141 if res.has_key(spw):
2142 res[spw].extend(crange_list)
2143 else:
2144 res[spw] = crange_list
[2882]2145
[2887]2146 for spw in res.keys():
[2932]2147 if spw in valid_ifs:
2148 # remove duplicated chennal ranges
2149 for i in reversed(xrange(len(res[spw]))):
2150 for j in xrange(i):
2151 if ((res[spw][i][0]-res[spw][j][1])*(res[spw][i][1]-res[spw][j][0]) <= 0):
2152 res[spw][j][0] = min(res[spw][i][0], res[spw][j][0])
2153 res[spw][j][1] = max(res[spw][i][1], res[spw][j][1])
2154 res[spw].pop(i)
2155 break
2156 else:
[2887]2157 del res[spw]
2158
2159 if len(res) == 0:
2160 raise RuntimeError("No valid spw.")
2161
[2882]2162 # restore original values
[2892]2163 self.set_unit(orig_unit)
[2891]2164 if restfreq is not None:
[2892]2165 self._setmolidcol_list(orig_molids)
2166 if frame is not None:
2167 self.set_freqframe(orig_frame)
2168 if doppler is not None:
2169 self.set_doppler(orig_doppler)
[2882]2170
2171 return res
[2890]2172
[2882]2173 @asaplog_post_dec
2174 def get_first_rowno_by_if(self, ifno):
2175 found = False
2176 for irow in xrange(self.nrow()):
2177 if (self.getif(irow) == ifno):
2178 res = irow
2179 found = True
2180 break
2181
[2926]2182 if not found: raise RuntimeError("No valid spw.")
[2882]2183
2184 return res
2185
2186 @asaplog_post_dec
2187 def _get_coordinate_list(self):
2188 res = []
2189 spws = self.getifnos()
2190 for spw in spws:
2191 elem = {}
2192 elem['if'] = spw
2193 elem['coord'] = self.get_coordinate(self.get_first_rowno_by_if(spw))
2194 res.append(elem)
2195
2196 return res
2197
2198 @asaplog_post_dec
[2349]2199 def parse_maskexpr(self, maskstring):
[2013]2200 """
2201 Parse CASA type mask selection syntax (IF dependent).
2202
2203 Parameters:
2204 maskstring : A string mask selection expression.
2205 A comma separated selections mean different IF -
2206 channel combinations. IFs and channel selections
2207 are partitioned by a colon, ':'.
2208 examples:
[2015]2209 '' = all IFs (all channels)
[2013]2210 '<2,4~6,9' = IFs 0,1,4,5,6,9 (all channels)
2211 '3:3~45;60' = channels 3 to 45 and 60 in IF 3
2212 '0~1:2~6,8' = channels 2 to 6 in IFs 0,1, and
2213 all channels in IF8
2214 Returns:
2215 A dictionary of selected (valid) IF and masklist pairs,
2216 e.g. {'0': [[50,250],[350,462]], '2': [[100,400],[550,974]]}
2217 """
2218 if not isinstance(maskstring,str):
2219 asaplog.post()
[2611]2220 asaplog.push("Mask expression should be a string.")
[2013]2221 asaplog.post("ERROR")
2222
2223 valid_ifs = self.getifnos()
2224 frequnit = self.get_unit()
2225 seldict = {}
[2015]2226 if maskstring == "":
2227 maskstring = str(valid_ifs)[1:-1]
[2611]2228 ## split each selection "IF range[:CHAN range]"
[2867]2229 # split maskstring by "<spaces>,<spaces>"
2230 comma_sep = re.compile('\s*,\s*')
2231 sellist = comma_sep.split(maskstring)
2232 # separator by "<spaces>:<spaces>"
2233 collon_sep = re.compile('\s*:\s*')
[2013]2234 for currselstr in sellist:
[2867]2235 selset = collon_sep.split(currselstr)
[2013]2236 # spw and mask string (may include ~, < or >)
[2349]2237 spwmasklist = self._parse_selection(selset[0], typestr='integer',
[2611]2238 minval=min(valid_ifs),
[2349]2239 maxval=max(valid_ifs))
[2013]2240 for spwlist in spwmasklist:
2241 selspws = []
2242 for ispw in range(spwlist[0],spwlist[1]+1):
2243 # Put into the list only if ispw exists
2244 if valid_ifs.count(ispw):
2245 selspws.append(ispw)
2246 del spwmasklist, spwlist
2247
2248 # parse frequency mask list
2249 if len(selset) > 1:
[2349]2250 freqmasklist = self._parse_selection(selset[1], typestr='float',
2251 offset=0.)
[2013]2252 else:
2253 # want to select the whole spectrum
2254 freqmasklist = [None]
2255
2256 ## define a dictionary of spw - masklist combination
2257 for ispw in selspws:
2258 #print "working on", ispw
2259 spwstr = str(ispw)
2260 if len(selspws) == 0:
2261 # empty spw
2262 continue
2263 else:
2264 ## want to get min and max of the spw and
2265 ## offset to set for '<' and '>'
2266 if frequnit == 'channel':
2267 minfreq = 0
2268 maxfreq = self.nchan(ifno=ispw)
2269 offset = 0.5
2270 else:
2271 ## This is ugly part. need improvement
2272 for ifrow in xrange(self.nrow()):
2273 if self.getif(ifrow) == ispw:
2274 #print "IF",ispw,"found in row =",ifrow
2275 break
2276 freqcoord = self.get_coordinate(ifrow)
2277 freqs = self._getabcissa(ifrow)
2278 minfreq = min(freqs)
2279 maxfreq = max(freqs)
2280 if len(freqs) == 1:
2281 offset = 0.5
2282 elif frequnit.find('Hz') > 0:
[2349]2283 offset = abs(freqcoord.to_frequency(1,
2284 unit=frequnit)
2285 -freqcoord.to_frequency(0,
2286 unit=frequnit)
2287 )*0.5
[2013]2288 elif frequnit.find('m/s') > 0:
[2349]2289 offset = abs(freqcoord.to_velocity(1,
2290 unit=frequnit)
2291 -freqcoord.to_velocity(0,
2292 unit=frequnit)
2293 )*0.5
[2013]2294 else:
2295 asaplog.post()
2296 asaplog.push("Invalid frequency unit")
2297 asaplog.post("ERROR")
2298 del freqs, freqcoord, ifrow
2299 for freq in freqmasklist:
2300 selmask = freq or [minfreq, maxfreq]
2301 if selmask[0] == None:
2302 ## selection was "<freq[1]".
2303 if selmask[1] < minfreq:
2304 ## avoid adding region selection
2305 selmask = None
2306 else:
2307 selmask = [minfreq,selmask[1]-offset]
2308 elif selmask[1] == None:
2309 ## selection was ">freq[0]"
2310 if selmask[0] > maxfreq:
2311 ## avoid adding region selection
2312 selmask = None
2313 else:
2314 selmask = [selmask[0]+offset,maxfreq]
2315 if selmask:
2316 if not seldict.has_key(spwstr):
2317 # new spw selection
2318 seldict[spwstr] = []
2319 seldict[spwstr] += [selmask]
2320 del minfreq,maxfreq,offset,freq,selmask
2321 del spwstr
2322 del freqmasklist
2323 del valid_ifs
2324 if len(seldict) == 0:
2325 asaplog.post()
[2349]2326 asaplog.push("No valid selection in the mask expression: "
2327 +maskstring)
[2013]2328 asaplog.post("WARN")
2329 return None
2330 msg = "Selected masklist:\n"
2331 for sif, lmask in seldict.iteritems():
2332 msg += " IF"+sif+" - "+str(lmask)+"\n"
2333 asaplog.push(msg)
2334 return seldict
2335
[2611]2336 @asaplog_post_dec
2337 def parse_idx_selection(self, mode, selexpr):
2338 """
2339 Parse CASA type mask selection syntax of SCANNO, IFNO, POLNO,
2340 BEAMNO, and row number
2341
2342 Parameters:
2343 mode : which column to select.
2344 ['scan',|'if'|'pol'|'beam'|'row']
2345 selexpr : A comma separated selection expression.
2346 examples:
2347 '' = all (returns [])
2348 '<2,4~6,9' = indices less than 2, 4 to 6 and 9
2349 (returns [0,1,4,5,6,9])
2350 Returns:
2351 A List of selected indices
2352 """
2353 if selexpr == "":
2354 return []
2355 valid_modes = {'s': 'scan', 'i': 'if', 'p': 'pol',
2356 'b': 'beam', 'r': 'row'}
2357 smode = mode.lower()[0]
2358 if not (smode in valid_modes.keys()):
2359 msg = "Invalid mode '%s'. Valid modes are %s" %\
2360 (mode, str(valid_modes.values()))
2361 asaplog.post()
2362 asaplog.push(msg)
2363 asaplog.post("ERROR")
2364 mode = valid_modes[smode]
2365 minidx = None
2366 maxidx = None
2367 if smode == 'r':
2368 minidx = 0
2369 maxidx = self.nrow()
2370 else:
2371 idx = getattr(self,"get"+mode+"nos")()
2372 minidx = min(idx)
2373 maxidx = max(idx)
2374 del idx
[2867]2375 # split selexpr by "<spaces>,<spaces>"
2376 comma_sep = re.compile('\s*,\s*')
2377 sellist = comma_sep.split(selexpr)
[2611]2378 idxlist = []
2379 for currselstr in sellist:
2380 # single range (may include ~, < or >)
2381 currlist = self._parse_selection(currselstr, typestr='integer',
2382 minval=minidx,maxval=maxidx)
2383 for thelist in currlist:
2384 idxlist += range(thelist[0],thelist[1]+1)
[2932]2385 # remove duplicated elements after first ones
2386 for i in reversed(xrange(len(idxlist))):
2387 if idxlist.index(idxlist[i]) < i:
2388 idxlist.pop(i)
[2611]2389 msg = "Selected %s: %s" % (mode.upper()+"NO", str(idxlist))
2390 asaplog.push(msg)
2391 return idxlist
2392
[2349]2393 def _parse_selection(self, selstr, typestr='float', offset=0.,
[2351]2394 minval=None, maxval=None):
[2013]2395 """
2396 Parameters:
2397 selstr : The Selection string, e.g., '<3;5~7;100~103;9'
2398 typestr : The type of the values in returned list
2399 ('integer' or 'float')
2400 offset : The offset value to subtract from or add to
2401 the boundary value if the selection string
[2611]2402 includes '<' or '>' [Valid only for typestr='float']
[2013]2403 minval, maxval : The minimum/maximum values to set if the
2404 selection string includes '<' or '>'.
2405 The list element is filled with None by default.
2406 Returns:
2407 A list of min/max pair of selections.
2408 Example:
[2611]2409 _parse_selection('<3;5~7;9',typestr='int',minval=0)
2410 --> returns [[0,2],[5,7],[9,9]]
2411 _parse_selection('<3;5~7;9',typestr='float',offset=0.5,minval=0)
2412 --> returns [[0.,2.5],[5.0,7.0],[9.,9.]]
[2013]2413 """
[2867]2414 # split selstr by '<spaces>;<spaces>'
2415 semi_sep = re.compile('\s*;\s*')
2416 selgroups = semi_sep.split(selstr)
[2013]2417 sellists = []
2418 if typestr.lower().startswith('int'):
2419 formatfunc = int
[2611]2420 offset = 1
[2013]2421 else:
2422 formatfunc = float
2423
2424 for currsel in selgroups:
[2867]2425 if currsel.strip() == '*' or len(currsel.strip()) == 0:
2426 minsel = minval
2427 maxsel = maxval
[2013]2428 if currsel.find('~') > 0:
[2611]2429 # val0 <= x <= val1
[2013]2430 minsel = formatfunc(currsel.split('~')[0].strip())
[2867]2431 maxsel = formatfunc(currsel.split('~')[1].strip())
[2611]2432 elif currsel.strip().find('<=') > -1:
2433 bound = currsel.split('<=')
2434 try: # try "x <= val"
2435 minsel = minval
2436 maxsel = formatfunc(bound[1].strip())
2437 except ValueError: # now "val <= x"
2438 minsel = formatfunc(bound[0].strip())
2439 maxsel = maxval
2440 elif currsel.strip().find('>=') > -1:
2441 bound = currsel.split('>=')
2442 try: # try "x >= val"
2443 minsel = formatfunc(bound[1].strip())
2444 maxsel = maxval
2445 except ValueError: # now "val >= x"
2446 minsel = minval
2447 maxsel = formatfunc(bound[0].strip())
2448 elif currsel.strip().find('<') > -1:
2449 bound = currsel.split('<')
2450 try: # try "x < val"
2451 minsel = minval
2452 maxsel = formatfunc(bound[1].strip()) \
2453 - formatfunc(offset)
2454 except ValueError: # now "val < x"
2455 minsel = formatfunc(bound[0].strip()) \
[2013]2456 + formatfunc(offset)
[2611]2457 maxsel = maxval
2458 elif currsel.strip().find('>') > -1:
2459 bound = currsel.split('>')
2460 try: # try "x > val"
2461 minsel = formatfunc(bound[1].strip()) \
2462 + formatfunc(offset)
2463 maxsel = maxval
2464 except ValueError: # now "val > x"
2465 minsel = minval
2466 maxsel = formatfunc(bound[0].strip()) \
2467 - formatfunc(offset)
[2013]2468 else:
2469 minsel = formatfunc(currsel)
2470 maxsel = formatfunc(currsel)
2471 sellists.append([minsel,maxsel])
2472 return sellists
2473
[1819]2474# def get_restfreqs(self):
2475# """
2476# Get the restfrequency(s) stored in this scantable.
2477# The return value(s) are always of unit 'Hz'
2478# Parameters:
2479# none
2480# Returns:
2481# a list of doubles
2482# """
2483# return list(self._getrestfreqs())
2484
2485 def get_restfreqs(self, ids=None):
[1846]2486 """\
[256]2487 Get the restfrequency(s) stored in this scantable.
2488 The return value(s) are always of unit 'Hz'
[1846]2489
[256]2490 Parameters:
[1846]2491
[1819]2492 ids: (optional) a list of MOLECULE_ID for that restfrequency(s) to
2493 be retrieved
[1846]2494
[256]2495 Returns:
[1846]2496
[1819]2497 dictionary containing ids and a list of doubles for each id
[1846]2498
[256]2499 """
[1819]2500 if ids is None:
[2349]2501 rfreqs = {}
[1819]2502 idlist = self.getmolnos()
2503 for i in idlist:
[2349]2504 rfreqs[i] = list(self._getrestfreqs(i))
[1819]2505 return rfreqs
2506 else:
[2349]2507 if type(ids) == list or type(ids) == tuple:
2508 rfreqs = {}
[1819]2509 for i in ids:
[2349]2510 rfreqs[i] = list(self._getrestfreqs(i))
[1819]2511 return rfreqs
2512 else:
2513 return list(self._getrestfreqs(ids))
[102]2514
[2349]2515 @asaplog_post_dec
[931]2516 def set_restfreqs(self, freqs=None, unit='Hz'):
[1846]2517 """\
[931]2518 Set or replace the restfrequency specified and
[1938]2519 if the 'freqs' argument holds a scalar,
[931]2520 then that rest frequency will be applied to all the selected
2521 data. If the 'freqs' argument holds
2522 a vector, then it MUST be of equal or smaller length than
2523 the number of IFs (and the available restfrequencies will be
2524 replaced by this vector). In this case, *all* data have
2525 the restfrequency set per IF according
2526 to the corresponding value you give in the 'freqs' vector.
[1118]2527 E.g. 'freqs=[1e9, 2e9]' would mean IF 0 gets restfreq 1e9 and
[931]2528 IF 1 gets restfreq 2e9.
[1846]2529
[1395]2530 You can also specify the frequencies via a linecatalog.
[1153]2531
[931]2532 Parameters:
[1846]2533
[931]2534 freqs: list of rest frequency values or string idenitfiers
[1855]2535
[931]2536 unit: unit for rest frequency (default 'Hz')
[402]2537
[1846]2538
2539 Example::
2540
[1819]2541 # set the given restfrequency for the all currently selected IFs
[931]2542 scan.set_restfreqs(freqs=1.4e9)
[1845]2543 # set restfrequencies for the n IFs (n > 1) in the order of the
2544 # list, i.e
2545 # IF0 -> 1.4e9, IF1 -> 1.41e9, IF3 -> 1.42e9
2546 # len(list_of_restfreqs) == nIF
2547 # for nIF == 1 the following will set multiple restfrequency for
2548 # that IF
[1819]2549 scan.set_restfreqs(freqs=[1.4e9, 1.41e9, 1.42e9])
[1845]2550 # set multiple restfrequencies per IF. as a list of lists where
2551 # the outer list has nIF elements, the inner s arbitrary
2552 scan.set_restfreqs(freqs=[[1.4e9, 1.41e9], [1.67e9]])
[391]2553
[1846]2554 *Note*:
[1845]2555
[931]2556 To do more sophisticate Restfrequency setting, e.g. on a
2557 source and IF basis, use scantable.set_selection() before using
[1846]2558 this function::
[931]2559
[1846]2560 # provided your scantable is called scan
2561 selection = selector()
[2431]2562 selection.set_name('ORION*')
[1846]2563 selection.set_ifs([1])
2564 scan.set_selection(selection)
2565 scan.set_restfreqs(freqs=86.6e9)
2566
[931]2567 """
2568 varlist = vars()
[1157]2569 from asap import linecatalog
2570 # simple value
[1118]2571 if isinstance(freqs, int) or isinstance(freqs, float):
[1845]2572 self._setrestfreqs([freqs], [""], unit)
[1157]2573 # list of values
[1118]2574 elif isinstance(freqs, list) or isinstance(freqs, tuple):
[1157]2575 # list values are scalars
[1118]2576 if isinstance(freqs[-1], int) or isinstance(freqs[-1], float):
[1845]2577 if len(freqs) == 1:
2578 self._setrestfreqs(freqs, [""], unit)
2579 else:
2580 # allow the 'old' mode of setting mulitple IFs
2581 savesel = self._getselection()
[2599]2582 sel = self.get_selection()
[1845]2583 iflist = self.getifnos()
2584 if len(freqs)>len(iflist):
2585 raise ValueError("number of elements in list of list "
2586 "exeeds the current IF selections")
2587 iflist = self.getifnos()
2588 for i, fval in enumerate(freqs):
2589 sel.set_ifs(iflist[i])
2590 self._setselection(sel)
2591 self._setrestfreqs([fval], [""], unit)
2592 self._setselection(savesel)
2593
2594 # list values are dict, {'value'=, 'name'=)
[1157]2595 elif isinstance(freqs[-1], dict):
[1845]2596 values = []
2597 names = []
2598 for d in freqs:
2599 values.append(d["value"])
2600 names.append(d["name"])
2601 self._setrestfreqs(values, names, unit)
[1819]2602 elif isinstance(freqs[-1], list) or isinstance(freqs[-1], tuple):
[1157]2603 savesel = self._getselection()
[2599]2604 sel = self.get_selection()
[1322]2605 iflist = self.getifnos()
[1819]2606 if len(freqs)>len(iflist):
[1845]2607 raise ValueError("number of elements in list of list exeeds"
2608 " the current IF selections")
2609 for i, fval in enumerate(freqs):
[1322]2610 sel.set_ifs(iflist[i])
[1259]2611 self._setselection(sel)
[1845]2612 self._setrestfreqs(fval, [""], unit)
[1157]2613 self._setselection(savesel)
2614 # freqs are to be taken from a linecatalog
[1153]2615 elif isinstance(freqs, linecatalog):
2616 savesel = self._getselection()
[2599]2617 sel = self.get_selection()
[1153]2618 for i in xrange(freqs.nrow()):
[1322]2619 sel.set_ifs(iflist[i])
[1153]2620 self._setselection(sel)
[1845]2621 self._setrestfreqs([freqs.get_frequency(i)],
2622 [freqs.get_name(i)], "MHz")
[1153]2623 # ensure that we are not iterating past nIF
2624 if i == self.nif()-1: break
2625 self._setselection(savesel)
[931]2626 else:
2627 return
2628 self._add_history("set_restfreqs", varlist)
2629
[2349]2630 @asaplog_post_dec
[1360]2631 def shift_refpix(self, delta):
[1846]2632 """\
[1589]2633 Shift the reference pixel of the Spectra Coordinate by an
2634 integer amount.
[1846]2635
[1589]2636 Parameters:
[1846]2637
[1589]2638 delta: the amount to shift by
[1846]2639
2640 *Note*:
2641
[1589]2642 Be careful using this with broadband data.
[1846]2643
[1360]2644 """
[2349]2645 varlist = vars()
[1731]2646 Scantable.shift_refpix(self, delta)
[2349]2647 s._add_history("shift_refpix", varlist)
[931]2648
[1862]2649 @asaplog_post_dec
[2820]2650 def history(self, filename=None, nrows=-1, start=0):
[1846]2651 """\
[1259]2652 Print the history. Optionally to a file.
[1846]2653
[1348]2654 Parameters:
[1846]2655
[1928]2656 filename: The name of the file to save the history to.
[1846]2657
[1259]2658 """
[2820]2659 n = self._historylength()
2660 if nrows == -1:
2661 nrows = n
2662 if start+nrows > n:
2663 nrows = nrows-start
2664 if n > 1000 and nrows == n:
2665 nrows = 1000
2666 start = n-1000
2667 asaplog.push("Warning: History has {0} entries. Displaying last "
2668 "1000".format(n))
2669 hist = list(self._gethistory(nrows, start))
[794]2670 out = "-"*80
[484]2671 for h in hist:
[2820]2672 if not h.strip():
2673 continue
2674 if h.find("---") >-1:
2675 continue
[489]2676 else:
2677 items = h.split("##")
2678 date = items[0]
2679 func = items[1]
2680 items = items[2:]
[794]2681 out += "\n"+date+"\n"
2682 out += "Function: %s\n Parameters:" % (func)
[489]2683 for i in items:
[1938]2684 if i == '':
2685 continue
[489]2686 s = i.split("=")
[1118]2687 out += "\n %s = %s" % (s[0], s[1])
[2820]2688 out = "\n".join([out, "*"*80])
[1259]2689 if filename is not None:
2690 if filename is "":
2691 filename = 'scantable_history.txt'
2692 filename = os.path.expandvars(os.path.expanduser(filename))
2693 if not os.path.isdir(filename):
2694 data = open(filename, 'w')
2695 data.write(out)
2696 data.close()
2697 else:
2698 msg = "Illegal file name '%s'." % (filename)
[1859]2699 raise IOError(msg)
2700 return page(out)
[2349]2701
[513]2702 #
2703 # Maths business
2704 #
[1862]2705 @asaplog_post_dec
[2818]2706 def average_time(self, mask=None, scanav=False, weight='tint', align=False,
2707 avmode="NONE"):
[1846]2708 """\
[2349]2709 Return the (time) weighted average of a scan. Scans will be averaged
2710 only if the source direction (RA/DEC) is within 1' otherwise
[1846]2711
2712 *Note*:
2713
[1070]2714 in channels only - align if necessary
[1846]2715
[513]2716 Parameters:
[1846]2717
[513]2718 mask: an optional mask (only used for 'var' and 'tsys'
2719 weighting)
[1855]2720
[558]2721 scanav: True averages each scan separately
2722 False (default) averages all scans together,
[1855]2723
[1099]2724 weight: Weighting scheme.
2725 'none' (mean no weight)
2726 'var' (1/var(spec) weighted)
2727 'tsys' (1/Tsys**2 weighted)
2728 'tint' (integration time weighted)
2729 'tintsys' (Tint/Tsys**2)
2730 'median' ( median averaging)
[535]2731 The default is 'tint'
[1855]2732
[931]2733 align: align the spectra in velocity before averaging. It takes
2734 the time of the first spectrum as reference time.
[2818]2735 avmode: 'SOURCE' - also select by source name - or
2736 'NONE' (default). Not applicable for scanav=True or
2737 weight=median
[1846]2738
2739 Example::
2740
[513]2741 # time average the scantable without using a mask
[710]2742 newscan = scan.average_time()
[1846]2743
[513]2744 """
2745 varlist = vars()
[1593]2746 weight = weight or 'TINT'
2747 mask = mask or ()
[2818]2748 scanav = (scanav and 'SCAN') or avmode.upper()
[1118]2749 scan = (self, )
[1859]2750
2751 if align:
2752 scan = (self.freq_align(insitu=False), )
[2818]2753 asaplog.push("Note: Alignment is don on a source-by-source basis")
2754 asaplog.push("Note: Averaging (by default) is not")
2755 # we need to set it to SOURCE averaging here
[1859]2756 s = None
2757 if weight.upper() == 'MEDIAN':
2758 s = scantable(self._math._averagechannel(scan[0], 'MEDIAN',
2759 scanav))
2760 else:
2761 s = scantable(self._math._average(scan, mask, weight.upper(),
2762 scanav))
[1099]2763 s._add_history("average_time", varlist)
[513]2764 return s
[710]2765
[1862]2766 @asaplog_post_dec
[876]2767 def convert_flux(self, jyperk=None, eta=None, d=None, insitu=None):
[1846]2768 """\
[513]2769 Return a scan where all spectra are converted to either
2770 Jansky or Kelvin depending upon the flux units of the scan table.
2771 By default the function tries to look the values up internally.
2772 If it can't find them (or if you want to over-ride), you must
2773 specify EITHER jyperk OR eta (and D which it will try to look up
2774 also if you don't set it). jyperk takes precedence if you set both.
[1846]2775
[513]2776 Parameters:
[1846]2777
[513]2778 jyperk: the Jy / K conversion factor
[1855]2779
[513]2780 eta: the aperture efficiency
[1855]2781
[1928]2782 d: the geometric diameter (metres)
[1855]2783
[513]2784 insitu: if False a new scantable is returned.
2785 Otherwise, the scaling is done in-situ
2786 The default is taken from .asaprc (False)
[1846]2787
[513]2788 """
2789 if insitu is None: insitu = rcParams['insitu']
[876]2790 self._math._setinsitu(insitu)
[513]2791 varlist = vars()
[1593]2792 jyperk = jyperk or -1.0
2793 d = d or -1.0
2794 eta = eta or -1.0
[876]2795 s = scantable(self._math._convertflux(self, d, eta, jyperk))
2796 s._add_history("convert_flux", varlist)
2797 if insitu: self._assign(s)
2798 else: return s
[513]2799
[1862]2800 @asaplog_post_dec
[876]2801 def gain_el(self, poly=None, filename="", method="linear", insitu=None):
[1846]2802 """\
[513]2803 Return a scan after applying a gain-elevation correction.
2804 The correction can be made via either a polynomial or a
2805 table-based interpolation (and extrapolation if necessary).
2806 You specify polynomial coefficients, an ascii table or neither.
2807 If you specify neither, then a polynomial correction will be made
2808 with built in coefficients known for certain telescopes (an error
2809 will occur if the instrument is not known).
2810 The data and Tsys are *divided* by the scaling factors.
[1846]2811
[513]2812 Parameters:
[1846]2813
[513]2814 poly: Polynomial coefficients (default None) to compute a
2815 gain-elevation correction as a function of
2816 elevation (in degrees).
[1855]2817
[513]2818 filename: The name of an ascii file holding correction factors.
2819 The first row of the ascii file must give the column
2820 names and these MUST include columns
[2431]2821 'ELEVATION' (degrees) and 'FACTOR' (multiply data
[513]2822 by this) somewhere.
2823 The second row must give the data type of the
2824 column. Use 'R' for Real and 'I' for Integer.
2825 An example file would be
2826 (actual factors are arbitrary) :
2827
2828 TIME ELEVATION FACTOR
2829 R R R
2830 0.1 0 0.8
2831 0.2 20 0.85
2832 0.3 40 0.9
2833 0.4 60 0.85
2834 0.5 80 0.8
2835 0.6 90 0.75
[1855]2836
[513]2837 method: Interpolation method when correcting from a table.
[2431]2838 Values are 'nearest', 'linear' (default), 'cubic'
2839 and 'spline'
[1855]2840
[513]2841 insitu: if False a new scantable is returned.
2842 Otherwise, the scaling is done in-situ
2843 The default is taken from .asaprc (False)
[1846]2844
[513]2845 """
2846
2847 if insitu is None: insitu = rcParams['insitu']
[876]2848 self._math._setinsitu(insitu)
[513]2849 varlist = vars()
[1593]2850 poly = poly or ()
[513]2851 from os.path import expandvars
2852 filename = expandvars(filename)
[876]2853 s = scantable(self._math._gainel(self, poly, filename, method))
2854 s._add_history("gain_el", varlist)
[1593]2855 if insitu:
2856 self._assign(s)
2857 else:
2858 return s
[710]2859
[1862]2860 @asaplog_post_dec
[931]2861 def freq_align(self, reftime=None, method='cubic', insitu=None):
[1846]2862 """\
[513]2863 Return a scan where all rows have been aligned in frequency/velocity.
2864 The alignment frequency frame (e.g. LSRK) is that set by function
2865 set_freqframe.
[1846]2866
[513]2867 Parameters:
[1855]2868
[513]2869 reftime: reference time to align at. By default, the time of
2870 the first row of data is used.
[1855]2871
[513]2872 method: Interpolation method for regridding the spectra.
[2431]2873 Choose from 'nearest', 'linear', 'cubic' (default)
2874 and 'spline'
[1855]2875
[513]2876 insitu: if False a new scantable is returned.
2877 Otherwise, the scaling is done in-situ
2878 The default is taken from .asaprc (False)
[1846]2879
[513]2880 """
[931]2881 if insitu is None: insitu = rcParams["insitu"]
[2429]2882 oldInsitu = self._math._insitu()
[876]2883 self._math._setinsitu(insitu)
[513]2884 varlist = vars()
[1593]2885 reftime = reftime or ""
[931]2886 s = scantable(self._math._freq_align(self, reftime, method))
[876]2887 s._add_history("freq_align", varlist)
[2429]2888 self._math._setinsitu(oldInsitu)
[2349]2889 if insitu:
2890 self._assign(s)
2891 else:
2892 return s
[513]2893
[1862]2894 @asaplog_post_dec
[1725]2895 def opacity(self, tau=None, insitu=None):
[1846]2896 """\
[513]2897 Apply an opacity correction. The data
2898 and Tsys are multiplied by the correction factor.
[1846]2899
[513]2900 Parameters:
[1855]2901
[1689]2902 tau: (list of) opacity from which the correction factor is
[513]2903 exp(tau*ZD)
[1689]2904 where ZD is the zenith-distance.
2905 If a list is provided, it has to be of length nIF,
2906 nIF*nPol or 1 and in order of IF/POL, e.g.
2907 [opif0pol0, opif0pol1, opif1pol0 ...]
[1725]2908 if tau is `None` the opacities are determined from a
2909 model.
[1855]2910
[513]2911 insitu: if False a new scantable is returned.
2912 Otherwise, the scaling is done in-situ
2913 The default is taken from .asaprc (False)
[1846]2914
[513]2915 """
[2349]2916 if insitu is None:
2917 insitu = rcParams['insitu']
[876]2918 self._math._setinsitu(insitu)
[513]2919 varlist = vars()
[1689]2920 if not hasattr(tau, "__len__"):
2921 tau = [tau]
[876]2922 s = scantable(self._math._opacity(self, tau))
2923 s._add_history("opacity", varlist)
[2349]2924 if insitu:
2925 self._assign(s)
2926 else:
2927 return s
[513]2928
[1862]2929 @asaplog_post_dec
[513]2930 def bin(self, width=5, insitu=None):
[1846]2931 """\
[513]2932 Return a scan where all spectra have been binned up.
[1846]2933
[1348]2934 Parameters:
[1846]2935
[513]2936 width: The bin width (default=5) in pixels
[1855]2937
[513]2938 insitu: if False a new scantable is returned.
2939 Otherwise, the scaling is done in-situ
2940 The default is taken from .asaprc (False)
[1846]2941
[513]2942 """
[2349]2943 if insitu is None:
2944 insitu = rcParams['insitu']
[876]2945 self._math._setinsitu(insitu)
[513]2946 varlist = vars()
[876]2947 s = scantable(self._math._bin(self, width))
[1118]2948 s._add_history("bin", varlist)
[1589]2949 if insitu:
2950 self._assign(s)
2951 else:
2952 return s
[513]2953
[1862]2954 @asaplog_post_dec
[2672]2955 def reshape(self, first, last, insitu=None):
2956 """Resize the band by providing first and last channel.
2957 This will cut off all channels outside [first, last].
2958 """
2959 if insitu is None:
2960 insitu = rcParams['insitu']
2961 varlist = vars()
2962 if last < 0:
2963 last = self.nchan()-1 + last
2964 s = None
2965 if insitu:
2966 s = self
2967 else:
2968 s = self.copy()
2969 s._reshape(first,last)
2970 s._add_history("reshape", varlist)
2971 if not insitu:
2972 return s
2973
2974 @asaplog_post_dec
[513]2975 def resample(self, width=5, method='cubic', insitu=None):
[1846]2976 """\
[1348]2977 Return a scan where all spectra have been binned up.
[1573]2978
[1348]2979 Parameters:
[1846]2980
[513]2981 width: The bin width (default=5) in pixels
[1855]2982
[513]2983 method: Interpolation method when correcting from a table.
[2431]2984 Values are 'nearest', 'linear', 'cubic' (default)
2985 and 'spline'
[1855]2986
[513]2987 insitu: if False a new scantable is returned.
2988 Otherwise, the scaling is done in-situ
2989 The default is taken from .asaprc (False)
[1846]2990
[513]2991 """
[2349]2992 if insitu is None:
2993 insitu = rcParams['insitu']
[876]2994 self._math._setinsitu(insitu)
[513]2995 varlist = vars()
[876]2996 s = scantable(self._math._resample(self, method, width))
[1118]2997 s._add_history("resample", varlist)
[2349]2998 if insitu:
2999 self._assign(s)
3000 else:
3001 return s
[513]3002
[1862]3003 @asaplog_post_dec
[946]3004 def average_pol(self, mask=None, weight='none'):
[1846]3005 """\
[946]3006 Average the Polarisations together.
[1846]3007
[946]3008 Parameters:
[1846]3009
[946]3010 mask: An optional mask defining the region, where the
3011 averaging will be applied. The output will have all
3012 specified points masked.
[1855]3013
[946]3014 weight: Weighting scheme. 'none' (default), 'var' (1/var(spec)
3015 weighted), or 'tsys' (1/Tsys**2 weighted)
[1846]3016
[946]3017 """
3018 varlist = vars()
[1593]3019 mask = mask or ()
[1010]3020 s = scantable(self._math._averagepol(self, mask, weight.upper()))
[1118]3021 s._add_history("average_pol", varlist)
[992]3022 return s
[513]3023
[1862]3024 @asaplog_post_dec
[1145]3025 def average_beam(self, mask=None, weight='none'):
[1846]3026 """\
[1145]3027 Average the Beams together.
[1846]3028
[1145]3029 Parameters:
3030 mask: An optional mask defining the region, where the
3031 averaging will be applied. The output will have all
3032 specified points masked.
[1855]3033
[1145]3034 weight: Weighting scheme. 'none' (default), 'var' (1/var(spec)
3035 weighted), or 'tsys' (1/Tsys**2 weighted)
[1846]3036
[1145]3037 """
3038 varlist = vars()
[1593]3039 mask = mask or ()
[1145]3040 s = scantable(self._math._averagebeams(self, mask, weight.upper()))
3041 s._add_history("average_beam", varlist)
3042 return s
3043
[1586]3044 def parallactify(self, pflag):
[1846]3045 """\
[1843]3046 Set a flag to indicate whether this data should be treated as having
[1617]3047 been 'parallactified' (total phase == 0.0)
[1846]3048
[1617]3049 Parameters:
[1855]3050
[1843]3051 pflag: Bool indicating whether to turn this on (True) or
[1617]3052 off (False)
[1846]3053
[1617]3054 """
[1586]3055 varlist = vars()
3056 self._parallactify(pflag)
3057 self._add_history("parallactify", varlist)
3058
[1862]3059 @asaplog_post_dec
[992]3060 def convert_pol(self, poltype=None):
[1846]3061 """\
[992]3062 Convert the data to a different polarisation type.
[1565]3063 Note that you will need cross-polarisation terms for most conversions.
[1846]3064
[992]3065 Parameters:
[1855]3066
[992]3067 poltype: The new polarisation type. Valid types are:
[2431]3068 'linear', 'circular', 'stokes' and 'linpol'
[1846]3069
[992]3070 """
3071 varlist = vars()
[1859]3072 s = scantable(self._math._convertpol(self, poltype))
[1118]3073 s._add_history("convert_pol", varlist)
[992]3074 return s
3075
[1862]3076 @asaplog_post_dec
[2269]3077 def smooth(self, kernel="hanning", width=5.0, order=2, plot=False,
3078 insitu=None):
[1846]3079 """\
[513]3080 Smooth the spectrum by the specified kernel (conserving flux).
[1846]3081
[513]3082 Parameters:
[1846]3083
[513]3084 kernel: The type of smoothing kernel. Select from
[1574]3085 'hanning' (default), 'gaussian', 'boxcar', 'rmedian'
3086 or 'poly'
[1855]3087
[513]3088 width: The width of the kernel in pixels. For hanning this is
3089 ignored otherwise it defauls to 5 pixels.
3090 For 'gaussian' it is the Full Width Half
3091 Maximum. For 'boxcar' it is the full width.
[1574]3092 For 'rmedian' and 'poly' it is the half width.
[1855]3093
[1574]3094 order: Optional parameter for 'poly' kernel (default is 2), to
3095 specify the order of the polnomial. Ignored by all other
3096 kernels.
[1855]3097
[1819]3098 plot: plot the original and the smoothed spectra.
3099 In this each indivual fit has to be approved, by
3100 typing 'y' or 'n'
[1855]3101
[513]3102 insitu: if False a new scantable is returned.
3103 Otherwise, the scaling is done in-situ
3104 The default is taken from .asaprc (False)
[1846]3105
[513]3106 """
3107 if insitu is None: insitu = rcParams['insitu']
[876]3108 self._math._setinsitu(insitu)
[513]3109 varlist = vars()
[1819]3110
3111 if plot: orgscan = self.copy()
3112
[1574]3113 s = scantable(self._math._smooth(self, kernel.lower(), width, order))
[876]3114 s._add_history("smooth", varlist)
[1819]3115
[2610]3116 action = 'H'
[1819]3117 if plot:
[2150]3118 from asap.asapplotter import new_asaplot
3119 theplot = new_asaplot(rcParams['plotter.gui'])
[2535]3120 from matplotlib import rc as rcp
3121 rcp('lines', linewidth=1)
[2150]3122 theplot.set_panels()
[1819]3123 ylab=s._get_ordinate_label()
[2150]3124 #theplot.palette(0,["#777777","red"])
[1819]3125 for r in xrange(s.nrow()):
3126 xsm=s._getabcissa(r)
3127 ysm=s._getspectrum(r)
3128 xorg=orgscan._getabcissa(r)
3129 yorg=orgscan._getspectrum(r)
[2610]3130 if action != "N": #skip plotting if rejecting all
3131 theplot.clear()
3132 theplot.hold()
3133 theplot.set_axes('ylabel',ylab)
3134 theplot.set_axes('xlabel',s._getabcissalabel(r))
3135 theplot.set_axes('title',s._getsourcename(r))
3136 theplot.set_line(label='Original',color="#777777")
3137 theplot.plot(xorg,yorg)
3138 theplot.set_line(label='Smoothed',color="red")
3139 theplot.plot(xsm,ysm)
3140 ### Ugly part for legend
3141 for i in [0,1]:
3142 theplot.subplots[0]['lines'].append(
3143 [theplot.subplots[0]['axes'].lines[i]]
3144 )
3145 theplot.release()
3146 ### Ugly part for legend
3147 theplot.subplots[0]['lines']=[]
3148 res = self._get_verify_action("Accept smoothing?",action)
3149 #print "IF%d, POL%d: got result = %s" %(s.getif(r),s.getpol(r),res)
3150 if r == 0: action = None
3151 #res = raw_input("Accept smoothing ([y]/n): ")
[1819]3152 if res.upper() == 'N':
[2610]3153 # reject for the current rows
[1819]3154 s._setspectrum(yorg, r)
[2610]3155 elif res.upper() == 'R':
3156 # reject all the following rows
3157 action = "N"
3158 s._setspectrum(yorg, r)
3159 elif res.upper() == 'A':
3160 # accept all the following rows
3161 break
[2150]3162 theplot.quit()
3163 del theplot
[1819]3164 del orgscan
3165
[876]3166 if insitu: self._assign(s)
3167 else: return s
[513]3168
[2186]3169 @asaplog_post_dec
[2435]3170 def regrid_channel(self, width=5, plot=False, insitu=None):
3171 """\
3172 Regrid the spectra by the specified channel width
3173
3174 Parameters:
3175
3176 width: The channel width (float) of regridded spectra
3177 in the current spectral unit.
3178
3179 plot: [NOT IMPLEMENTED YET]
3180 plot the original and the regridded spectra.
3181 In this each indivual fit has to be approved, by
3182 typing 'y' or 'n'
3183
3184 insitu: if False a new scantable is returned.
3185 Otherwise, the scaling is done in-situ
3186 The default is taken from .asaprc (False)
3187
3188 """
3189 if insitu is None: insitu = rcParams['insitu']
3190 varlist = vars()
3191
3192 if plot:
3193 asaplog.post()
3194 asaplog.push("Verification plot is not implemtnetd yet.")
3195 asaplog.post("WARN")
3196
3197 s = self.copy()
3198 s._regrid_specchan(width)
3199
3200 s._add_history("regrid_channel", varlist)
3201
3202# if plot:
3203# from asap.asapplotter import new_asaplot
3204# theplot = new_asaplot(rcParams['plotter.gui'])
[2535]3205# from matplotlib import rc as rcp
3206# rcp('lines', linewidth=1)
[2435]3207# theplot.set_panels()
3208# ylab=s._get_ordinate_label()
3209# #theplot.palette(0,["#777777","red"])
3210# for r in xrange(s.nrow()):
3211# xsm=s._getabcissa(r)
3212# ysm=s._getspectrum(r)
3213# xorg=orgscan._getabcissa(r)
3214# yorg=orgscan._getspectrum(r)
3215# theplot.clear()
3216# theplot.hold()
3217# theplot.set_axes('ylabel',ylab)
3218# theplot.set_axes('xlabel',s._getabcissalabel(r))
3219# theplot.set_axes('title',s._getsourcename(r))
3220# theplot.set_line(label='Original',color="#777777")
3221# theplot.plot(xorg,yorg)
3222# theplot.set_line(label='Smoothed',color="red")
3223# theplot.plot(xsm,ysm)
3224# ### Ugly part for legend
3225# for i in [0,1]:
3226# theplot.subplots[0]['lines'].append(
3227# [theplot.subplots[0]['axes'].lines[i]]
3228# )
3229# theplot.release()
3230# ### Ugly part for legend
3231# theplot.subplots[0]['lines']=[]
3232# res = raw_input("Accept smoothing ([y]/n): ")
3233# if res.upper() == 'N':
3234# s._setspectrum(yorg, r)
3235# theplot.quit()
3236# del theplot
3237# del orgscan
3238
3239 if insitu: self._assign(s)
3240 else: return s
3241
3242 @asaplog_post_dec
[2186]3243 def _parse_wn(self, wn):
3244 if isinstance(wn, list) or isinstance(wn, tuple):
3245 return wn
3246 elif isinstance(wn, int):
3247 return [ wn ]
3248 elif isinstance(wn, str):
[2277]3249 if '-' in wn: # case 'a-b' : return [a,a+1,...,b-1,b]
[2186]3250 val = wn.split('-')
3251 val = [int(val[0]), int(val[1])]
3252 val.sort()
3253 res = [i for i in xrange(val[0], val[1]+1)]
[2277]3254 elif wn[:2] == '<=' or wn[:2] == '=<': # cases '<=a','=<a' : return [0,1,...,a-1,a]
[2186]3255 val = int(wn[2:])+1
3256 res = [i for i in xrange(val)]
[2277]3257 elif wn[-2:] == '>=' or wn[-2:] == '=>': # cases 'a>=','a=>' : return [0,1,...,a-1,a]
[2186]3258 val = int(wn[:-2])+1
3259 res = [i for i in xrange(val)]
[2277]3260 elif wn[0] == '<': # case '<a' : return [0,1,...,a-2,a-1]
[2186]3261 val = int(wn[1:])
3262 res = [i for i in xrange(val)]
[2277]3263 elif wn[-1] == '>': # case 'a>' : return [0,1,...,a-2,a-1]
[2186]3264 val = int(wn[:-1])
3265 res = [i for i in xrange(val)]
[2411]3266 elif wn[:2] == '>=' or wn[:2] == '=>': # cases '>=a','=>a' : return [a,-999], which is
3267 # then interpreted in C++
3268 # side as [a,a+1,...,a_nyq]
3269 # (CAS-3759)
[2186]3270 val = int(wn[2:])
[2411]3271 res = [val, -999]
3272 #res = [i for i in xrange(val, self.nchan()/2+1)]
3273 elif wn[-2:] == '<=' or wn[-2:] == '=<': # cases 'a<=','a=<' : return [a,-999], which is
3274 # then interpreted in C++
3275 # side as [a,a+1,...,a_nyq]
3276 # (CAS-3759)
[2186]3277 val = int(wn[:-2])
[2411]3278 res = [val, -999]
3279 #res = [i for i in xrange(val, self.nchan()/2+1)]
3280 elif wn[0] == '>': # case '>a' : return [a+1,-999], which is
3281 # then interpreted in C++
3282 # side as [a+1,a+2,...,a_nyq]
3283 # (CAS-3759)
[2186]3284 val = int(wn[1:])+1
[2411]3285 res = [val, -999]
3286 #res = [i for i in xrange(val, self.nchan()/2+1)]
3287 elif wn[-1] == '<': # case 'a<' : return [a+1,-999], which is
3288 # then interpreted in C++
3289 # side as [a+1,a+2,...,a_nyq]
3290 # (CAS-3759)
[2186]3291 val = int(wn[:-1])+1
[2411]3292 res = [val, -999]
3293 #res = [i for i in xrange(val, self.nchan()/2+1)]
[2012]3294
[2186]3295 return res
3296 else:
3297 msg = 'wrong value given for addwn/rejwn'
3298 raise RuntimeError(msg)
3299
[2713]3300 @asaplog_post_dec
[2810]3301 def apply_bltable(self, insitu=None, retfitres=None, inbltable=None, outbltable=None, overwrite=None):
[2767]3302 """\
3303 Subtract baseline based on parameters written in Baseline Table.
3304
3305 Parameters:
[2809]3306 insitu: if True, baseline fitting/subtraction is done
[2810]3307 in-situ. If False, a new scantable with
3308 baseline subtracted is returned. Actually,
3309 format of the returned value depends on both
3310 insitu and retfitres (see below).
[2767]3311 The default is taken from .asaprc (False)
[2810]3312 retfitres: if True, the results of baseline fitting (i.e.,
3313 coefficients and rms) are returned.
3314 default is False.
3315 The format of the returned value of this
3316 function varies as follows:
3317 (1) in case insitu=True and retfitres=True:
3318 fitting result.
3319 (2) in case insitu=True and retfitres=False:
3320 None.
3321 (3) in case insitu=False and retfitres=True:
3322 a dictionary containing a new scantable
3323 (with baseline subtracted) and the fitting
3324 results.
3325 (4) in case insitu=False and retfitres=False:
3326 a new scantable (with baseline subtracted).
[2767]3327 inbltable: name of input baseline table. The row number of
3328 scantable and that of inbltable must be
3329 identical.
3330 outbltable: name of output baseline table where baseline
3331 parameters and fitting results recorded.
3332 default is ''(no output).
[2809]3333 overwrite: if True when an existing baseline table is
3334 specified for outbltable, overwrites it.
3335 Otherwise there is no harm.
[2767]3336 default is False.
3337 """
3338
3339 try:
3340 varlist = vars()
[2810]3341 if retfitres is None: retfitres = False
[2767]3342 if inbltable is None: raise ValueError("bltable missing.")
3343 if outbltable is None: outbltable = ''
3344 if overwrite is None: overwrite = False
3345
3346 if insitu is None: insitu = rcParams['insitu']
3347 if insitu:
3348 workscan = self
3349 else:
3350 workscan = self.copy()
3351
3352 sres = workscan._apply_bltable(inbltable,
[2810]3353 retfitres,
[2767]3354 outbltable,
3355 os.path.exists(outbltable),
3356 overwrite)
[2810]3357 if retfitres: res = parse_fitresult(sres)
[2767]3358
3359 workscan._add_history('apply_bltable', varlist)
3360
3361 if insitu:
3362 self._assign(workscan)
[2810]3363 if retfitres:
3364 return res
3365 else:
3366 return None
[2767]3367 else:
[2810]3368 if retfitres:
3369 return {'scantable': workscan, 'fitresults': res}
3370 else:
3371 return workscan
[2767]3372
3373 except RuntimeError, e:
3374 raise_fitting_failure_exception(e)
3375
3376 @asaplog_post_dec
[2810]3377 def sub_baseline(self, insitu=None, retfitres=None, blinfo=None, bltable=None, overwrite=None):
[2767]3378 """\
3379 Subtract baseline based on parameters written in the input list.
3380
3381 Parameters:
[2809]3382 insitu: if True, baseline fitting/subtraction is done
[2810]3383 in-situ. If False, a new scantable with
3384 baseline subtracted is returned. Actually,
3385 format of the returned value depends on both
3386 insitu and retfitres (see below).
[2767]3387 The default is taken from .asaprc (False)
[2810]3388 retfitres: if True, the results of baseline fitting (i.e.,
3389 coefficients and rms) are returned.
3390 default is False.
3391 The format of the returned value of this
3392 function varies as follows:
3393 (1) in case insitu=True and retfitres=True:
3394 fitting result.
3395 (2) in case insitu=True and retfitres=False:
3396 None.
3397 (3) in case insitu=False and retfitres=True:
3398 a dictionary containing a new scantable
3399 (with baseline subtracted) and the fitting
3400 results.
3401 (4) in case insitu=False and retfitres=False:
3402 a new scantable (with baseline subtracted).
[2767]3403 blinfo: baseline parameter set stored in a dictionary
3404 or a list of dictionary. Each dictionary
3405 corresponds to each spectrum and must contain
3406 the following keys and values:
3407 'row': row number,
3408 'blfunc': function name. available ones include
3409 'poly', 'chebyshev', 'cspline' and
3410 'sinusoid',
3411 'order': maximum order of polynomial. needed
3412 if blfunc='poly' or 'chebyshev',
3413 'npiece': number or piecewise polynomial.
3414 needed if blfunc='cspline',
3415 'nwave': a list of sinusoidal wave numbers.
3416 needed if blfunc='sinusoid', and
3417 'masklist': min-max windows for channel mask.
3418 the specified ranges will be used
3419 for fitting.
3420 bltable: name of output baseline table where baseline
3421 parameters and fitting results recorded.
3422 default is ''(no output).
[2809]3423 overwrite: if True when an existing baseline table is
3424 specified for bltable, overwrites it.
3425 Otherwise there is no harm.
[2767]3426 default is False.
3427
3428 Example:
3429 sub_baseline(blinfo=[{'row':0, 'blfunc':'poly', 'order':5,
3430 'masklist':[[10,350],[352,510]]},
3431 {'row':1, 'blfunc':'cspline', 'npiece':3,
3432 'masklist':[[3,16],[19,404],[407,511]]}
3433 ])
3434
3435 the first spectrum (row=0) will be fitted with polynomial
3436 of order=5 and the next one (row=1) will be fitted with cubic
3437 spline consisting of 3 pieces.
3438 """
3439
3440 try:
3441 varlist = vars()
[2810]3442 if retfitres is None: retfitres = False
[2767]3443 if blinfo is None: blinfo = []
3444 if bltable is None: bltable = ''
3445 if overwrite is None: overwrite = False
3446
3447 if insitu is None: insitu = rcParams['insitu']
3448 if insitu:
3449 workscan = self
3450 else:
3451 workscan = self.copy()
3452
3453 nrow = workscan.nrow()
3454
3455 in_blinfo = pack_blinfo(blinfo=blinfo, maxirow=nrow)
3456
3457 print "in_blinfo=< "+ str(in_blinfo)+" >"
3458
3459 sres = workscan._sub_baseline(in_blinfo,
[2810]3460 retfitres,
[2767]3461 bltable,
3462 os.path.exists(bltable),
3463 overwrite)
[2810]3464 if retfitres: res = parse_fitresult(sres)
[2767]3465
3466 workscan._add_history('sub_baseline', varlist)
3467
3468 if insitu:
3469 self._assign(workscan)
[2810]3470 if retfitres:
3471 return res
3472 else:
3473 return None
[2767]3474 else:
[2810]3475 if retfitres:
3476 return {'scantable': workscan, 'fitresults': res}
3477 else:
3478 return workscan
[2767]3479
3480 except RuntimeError, e:
3481 raise_fitting_failure_exception(e)
3482
3483 @asaplog_post_dec
[2713]3484 def calc_aic(self, value=None, blfunc=None, order=None, mask=None,
3485 whichrow=None, uselinefinder=None, edge=None,
3486 threshold=None, chan_avg_limit=None):
3487 """\
3488 Calculates and returns model selection criteria for a specified
3489 baseline model and a given spectrum data.
3490 Available values include Akaike Information Criterion (AIC), the
3491 corrected Akaike Information Criterion (AICc) by Sugiura(1978),
3492 Bayesian Information Criterion (BIC) and the Generalised Cross
3493 Validation (GCV).
[2186]3494
[2713]3495 Parameters:
3496 value: name of model selection criteria to calculate.
3497 available ones include 'aic', 'aicc', 'bic' and
3498 'gcv'. default is 'aicc'.
3499 blfunc: baseline function name. available ones include
3500 'chebyshev', 'cspline' and 'sinusoid'.
3501 default is 'chebyshev'.
3502 order: parameter for basline function. actually stands for
3503 order of polynomial (order) for 'chebyshev',
3504 number of spline pieces (npiece) for 'cspline' and
3505 maximum wave number for 'sinusoid', respectively.
3506 default is 5 (which is also the default order value
3507 for [auto_]chebyshev_baseline()).
3508 mask: an optional mask. default is [].
3509 whichrow: row number. default is 0 (the first row)
3510 uselinefinder: use sd.linefinder() to flag out line regions
3511 default is True.
3512 edge: an optional number of channel to drop at
3513 the edge of spectrum. If only one value is
3514 specified, the same number will be dropped
3515 from both sides of the spectrum. Default
3516 is to keep all channels. Nested tuples
3517 represent individual edge selection for
3518 different IFs (a number of spectral channels
3519 can be different)
3520 default is (0, 0).
3521 threshold: the threshold used by line finder. It is
3522 better to keep it large as only strong lines
3523 affect the baseline solution.
3524 default is 3.
3525 chan_avg_limit: a maximum number of consequtive spectral
3526 channels to average during the search of
3527 weak and broad lines. The default is no
3528 averaging (and no search for weak lines).
3529 If such lines can affect the fitted baseline
3530 (e.g. a high order polynomial is fitted),
3531 increase this parameter (usually values up
3532 to 8 are reasonable). Most users of this
3533 method should find the default value sufficient.
3534 default is 1.
3535
3536 Example:
3537 aic = scan.calc_aic(blfunc='chebyshev', order=5, whichrow=0)
3538 """
3539
3540 try:
3541 varlist = vars()
3542
3543 if value is None: value = 'aicc'
3544 if blfunc is None: blfunc = 'chebyshev'
3545 if order is None: order = 5
3546 if mask is None: mask = []
3547 if whichrow is None: whichrow = 0
3548 if uselinefinder is None: uselinefinder = True
3549 if edge is None: edge = (0, 0)
3550 if threshold is None: threshold = 3
3551 if chan_avg_limit is None: chan_avg_limit = 1
3552
3553 return self._calc_aic(value, blfunc, order, mask,
3554 whichrow, uselinefinder, edge,
3555 threshold, chan_avg_limit)
3556
3557 except RuntimeError, e:
3558 raise_fitting_failure_exception(e)
3559
[1862]3560 @asaplog_post_dec
[2771]3561 def sinusoid_baseline(self, mask=None, applyfft=None,
[2269]3562 fftmethod=None, fftthresh=None,
[2771]3563 addwn=None, rejwn=None,
3564 insitu=None,
3565 clipthresh=None, clipniter=None,
3566 plot=None,
3567 getresidual=None,
3568 showprogress=None, minnrow=None,
3569 outlog=None,
[2767]3570 blfile=None, csvformat=None,
3571 bltable=None):
[2047]3572 """\
[2349]3573 Return a scan which has been baselined (all rows) with sinusoidal
3574 functions.
3575
[2047]3576 Parameters:
[2186]3577 mask: an optional mask
3578 applyfft: if True use some method, such as FFT, to find
3579 strongest sinusoidal components in the wavenumber
3580 domain to be used for baseline fitting.
3581 default is True.
3582 fftmethod: method to find the strong sinusoidal components.
3583 now only 'fft' is available and it is the default.
3584 fftthresh: the threshold to select wave numbers to be used for
3585 fitting from the distribution of amplitudes in the
3586 wavenumber domain.
3587 both float and string values accepted.
3588 given a float value, the unit is set to sigma.
3589 for string values, allowed formats include:
[2349]3590 'xsigma' or 'x' (= x-sigma level. e.g.,
3591 '3sigma'), or
[2186]3592 'topx' (= the x strongest ones, e.g. 'top5').
3593 default is 3.0 (unit: sigma).
3594 addwn: the additional wave numbers to be used for fitting.
3595 list or integer value is accepted to specify every
3596 wave numbers. also string value can be used in case
3597 you need to specify wave numbers in a certain range,
3598 e.g., 'a-b' (= a, a+1, a+2, ..., b-1, b),
3599 '<a' (= 0,1,...,a-2,a-1),
3600 '>=a' (= a, a+1, ... up to the maximum wave
3601 number corresponding to the Nyquist
3602 frequency for the case of FFT).
[2411]3603 default is [0].
[2186]3604 rejwn: the wave numbers NOT to be used for fitting.
3605 can be set just as addwn but has higher priority:
3606 wave numbers which are specified both in addwn
3607 and rejwn will NOT be used. default is [].
[2771]3608 insitu: if False a new scantable is returned.
3609 Otherwise, the scaling is done in-situ
3610 The default is taken from .asaprc (False)
[2081]3611 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
[2349]3612 clipniter: maximum number of iteration of 'clipthresh'-sigma
3613 clipping (default is 0)
[2081]3614 plot: *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3615 plot the fit and the residual. In this each
3616 indivual fit has to be approved, by typing 'y'
3617 or 'n'
3618 getresidual: if False, returns best-fit values instead of
3619 residual. (default is True)
[2189]3620 showprogress: show progress status for large data.
3621 default is True.
3622 minnrow: minimum number of input spectra to show.
3623 default is 1000.
[2081]3624 outlog: Output the coefficients of the best-fit
3625 function to logger (default is False)
3626 blfile: Name of a text file in which the best-fit
3627 parameter values to be written
[2186]3628 (default is '': no file/logger output)
[2641]3629 csvformat: if True blfile is csv-formatted, default is False.
[2767]3630 bltable: name of a baseline table where fitting results
3631 (coefficients, rms, etc.) are to be written.
3632 if given, fitting results will NOT be output to
3633 scantable (insitu=True) or None will be
3634 returned (insitu=False).
3635 (default is "": no table output)
[2047]3636
3637 Example:
[2349]3638 # return a scan baselined by a combination of sinusoidal curves
3639 # having wave numbers in spectral window up to 10,
[2047]3640 # also with 3-sigma clipping, iteration up to 4 times
[2186]3641 bscan = scan.sinusoid_baseline(addwn='<=10',clipthresh=3.0,clipniter=4)
[2081]3642
3643 Note:
3644 The best-fit parameter values output in logger and/or blfile are now
3645 based on specunit of 'channel'.
[2047]3646 """
3647
[2186]3648 try:
3649 varlist = vars()
[2047]3650
[2186]3651 if insitu is None: insitu = rcParams['insitu']
3652 if insitu:
3653 workscan = self
3654 else:
3655 workscan = self.copy()
3656
[2410]3657 if mask is None: mask = []
[2186]3658 if applyfft is None: applyfft = True
3659 if fftmethod is None: fftmethod = 'fft'
3660 if fftthresh is None: fftthresh = 3.0
[2411]3661 if addwn is None: addwn = [0]
[2186]3662 if rejwn is None: rejwn = []
3663 if clipthresh is None: clipthresh = 3.0
3664 if clipniter is None: clipniter = 0
3665 if plot is None: plot = False
3666 if getresidual is None: getresidual = True
[2189]3667 if showprogress is None: showprogress = True
3668 if minnrow is None: minnrow = 1000
[2186]3669 if outlog is None: outlog = False
3670 if blfile is None: blfile = ''
[2641]3671 if csvformat is None: csvformat = False
[2767]3672 if bltable is None: bltable = ''
[2047]3673
[2767]3674 sapplyfft = 'true' if applyfft else 'false'
3675 fftinfo = ','.join([sapplyfft, fftmethod.lower(), str(fftthresh).lower()])
[2641]3676
[2767]3677 scsvformat = 'T' if csvformat else 'F'
3678
[2081]3679 #CURRENTLY, PLOT=true is UNAVAILABLE UNTIL sinusoidal fitting is implemented as a fitter method.
[2767]3680 workscan._sinusoid_baseline(mask,
3681 fftinfo,
3682 #applyfft, fftmethod.lower(),
3683 #str(fftthresh).lower(),
[2349]3684 workscan._parse_wn(addwn),
[2643]3685 workscan._parse_wn(rejwn),
3686 clipthresh, clipniter,
3687 getresidual,
[2349]3688 pack_progress_params(showprogress,
[2641]3689 minnrow),
[2767]3690 outlog, scsvformat+blfile,
3691 bltable)
[2186]3692 workscan._add_history('sinusoid_baseline', varlist)
[2767]3693
3694 if bltable == '':
3695 if insitu:
3696 self._assign(workscan)
3697 else:
3698 return workscan
[2047]3699 else:
[2767]3700 if not insitu:
3701 return None
[2047]3702
3703 except RuntimeError, e:
[2186]3704 raise_fitting_failure_exception(e)
[2047]3705
3706
[2186]3707 @asaplog_post_dec
[2771]3708 def auto_sinusoid_baseline(self, mask=None, applyfft=None,
[2349]3709 fftmethod=None, fftthresh=None,
[2771]3710 addwn=None, rejwn=None,
3711 insitu=None,
3712 clipthresh=None, clipniter=None,
3713 edge=None, threshold=None, chan_avg_limit=None,
3714 plot=None,
3715 getresidual=None,
3716 showprogress=None, minnrow=None,
3717 outlog=None,
[2767]3718 blfile=None, csvformat=None,
3719 bltable=None):
[2047]3720 """\
[2349]3721 Return a scan which has been baselined (all rows) with sinusoidal
3722 functions.
[2047]3723 Spectral lines are detected first using linefinder and masked out
3724 to avoid them affecting the baseline solution.
3725
3726 Parameters:
[2189]3727 mask: an optional mask retreived from scantable
3728 applyfft: if True use some method, such as FFT, to find
3729 strongest sinusoidal components in the wavenumber
3730 domain to be used for baseline fitting.
3731 default is True.
3732 fftmethod: method to find the strong sinusoidal components.
3733 now only 'fft' is available and it is the default.
3734 fftthresh: the threshold to select wave numbers to be used for
3735 fitting from the distribution of amplitudes in the
3736 wavenumber domain.
3737 both float and string values accepted.
3738 given a float value, the unit is set to sigma.
3739 for string values, allowed formats include:
[2349]3740 'xsigma' or 'x' (= x-sigma level. e.g.,
3741 '3sigma'), or
[2189]3742 'topx' (= the x strongest ones, e.g. 'top5').
3743 default is 3.0 (unit: sigma).
3744 addwn: the additional wave numbers to be used for fitting.
3745 list or integer value is accepted to specify every
3746 wave numbers. also string value can be used in case
3747 you need to specify wave numbers in a certain range,
3748 e.g., 'a-b' (= a, a+1, a+2, ..., b-1, b),
3749 '<a' (= 0,1,...,a-2,a-1),
3750 '>=a' (= a, a+1, ... up to the maximum wave
3751 number corresponding to the Nyquist
3752 frequency for the case of FFT).
[2411]3753 default is [0].
[2189]3754 rejwn: the wave numbers NOT to be used for fitting.
3755 can be set just as addwn but has higher priority:
3756 wave numbers which are specified both in addwn
3757 and rejwn will NOT be used. default is [].
[2771]3758 insitu: if False a new scantable is returned.
3759 Otherwise, the scaling is done in-situ
3760 The default is taken from .asaprc (False)
[2189]3761 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
[2349]3762 clipniter: maximum number of iteration of 'clipthresh'-sigma
3763 clipping (default is 0)
[2189]3764 edge: an optional number of channel to drop at
3765 the edge of spectrum. If only one value is
3766 specified, the same number will be dropped
3767 from both sides of the spectrum. Default
3768 is to keep all channels. Nested tuples
3769 represent individual edge selection for
3770 different IFs (a number of spectral channels
3771 can be different)
3772 threshold: the threshold used by line finder. It is
3773 better to keep it large as only strong lines
3774 affect the baseline solution.
3775 chan_avg_limit: a maximum number of consequtive spectral
3776 channels to average during the search of
3777 weak and broad lines. The default is no
3778 averaging (and no search for weak lines).
3779 If such lines can affect the fitted baseline
3780 (e.g. a high order polynomial is fitted),
3781 increase this parameter (usually values up
3782 to 8 are reasonable). Most users of this
3783 method should find the default value sufficient.
3784 plot: *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3785 plot the fit and the residual. In this each
3786 indivual fit has to be approved, by typing 'y'
3787 or 'n'
3788 getresidual: if False, returns best-fit values instead of
3789 residual. (default is True)
3790 showprogress: show progress status for large data.
3791 default is True.
3792 minnrow: minimum number of input spectra to show.
3793 default is 1000.
3794 outlog: Output the coefficients of the best-fit
3795 function to logger (default is False)
3796 blfile: Name of a text file in which the best-fit
3797 parameter values to be written
3798 (default is "": no file/logger output)
[2641]3799 csvformat: if True blfile is csv-formatted, default is False.
[2767]3800 bltable: name of a baseline table where fitting results
3801 (coefficients, rms, etc.) are to be written.
3802 if given, fitting results will NOT be output to
3803 scantable (insitu=True) or None will be
3804 returned (insitu=False).
3805 (default is "": no table output)
[2047]3806
3807 Example:
[2186]3808 bscan = scan.auto_sinusoid_baseline(addwn='<=10', insitu=False)
[2081]3809
3810 Note:
3811 The best-fit parameter values output in logger and/or blfile are now
3812 based on specunit of 'channel'.
[2047]3813 """
3814
[2186]3815 try:
3816 varlist = vars()
[2047]3817
[2186]3818 if insitu is None: insitu = rcParams['insitu']
3819 if insitu:
3820 workscan = self
[2047]3821 else:
[2186]3822 workscan = self.copy()
3823
[2410]3824 if mask is None: mask = []
[2186]3825 if applyfft is None: applyfft = True
3826 if fftmethod is None: fftmethod = 'fft'
3827 if fftthresh is None: fftthresh = 3.0
[2411]3828 if addwn is None: addwn = [0]
[2186]3829 if rejwn is None: rejwn = []
3830 if clipthresh is None: clipthresh = 3.0
3831 if clipniter is None: clipniter = 0
3832 if edge is None: edge = (0,0)
3833 if threshold is None: threshold = 3
3834 if chan_avg_limit is None: chan_avg_limit = 1
3835 if plot is None: plot = False
3836 if getresidual is None: getresidual = True
[2189]3837 if showprogress is None: showprogress = True
3838 if minnrow is None: minnrow = 1000
[2186]3839 if outlog is None: outlog = False
3840 if blfile is None: blfile = ''
[2641]3841 if csvformat is None: csvformat = False
[2767]3842 if bltable is None: bltable = ''
[2047]3843
[2767]3844 sapplyfft = 'true' if applyfft else 'false'
3845 fftinfo = ','.join([sapplyfft, fftmethod.lower(), str(fftthresh).lower()])
[2641]3846
[2767]3847 scsvformat = 'T' if csvformat else 'F'
3848
[2277]3849 #CURRENTLY, PLOT=true is UNAVAILABLE UNTIL sinusoidal fitting is implemented as a fitter method.
[2767]3850 workscan._auto_sinusoid_baseline(mask,
3851 fftinfo,
[2349]3852 workscan._parse_wn(addwn),
3853 workscan._parse_wn(rejwn),
3854 clipthresh, clipniter,
3855 normalise_edge_param(edge),
3856 threshold, chan_avg_limit,
3857 getresidual,
3858 pack_progress_params(showprogress,
3859 minnrow),
[2767]3860 outlog, scsvformat+blfile, bltable)
[2047]3861 workscan._add_history("auto_sinusoid_baseline", varlist)
[2767]3862
3863 if bltable == '':
3864 if insitu:
3865 self._assign(workscan)
3866 else:
3867 return workscan
[2047]3868 else:
[2767]3869 if not insitu:
3870 return None
[2047]3871
3872 except RuntimeError, e:
[2186]3873 raise_fitting_failure_exception(e)
[2047]3874
3875 @asaplog_post_dec
[2771]3876 def cspline_baseline(self, mask=None, npiece=None, insitu=None,
[2349]3877 clipthresh=None, clipniter=None, plot=None,
3878 getresidual=None, showprogress=None, minnrow=None,
[2767]3879 outlog=None, blfile=None, csvformat=None,
3880 bltable=None):
[1846]3881 """\
[2349]3882 Return a scan which has been baselined (all rows) by cubic spline
3883 function (piecewise cubic polynomial).
3884
[513]3885 Parameters:
[2771]3886 mask: An optional mask
3887 npiece: Number of pieces. (default is 2)
[2189]3888 insitu: If False a new scantable is returned.
3889 Otherwise, the scaling is done in-situ
3890 The default is taken from .asaprc (False)
3891 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
[2349]3892 clipniter: maximum number of iteration of 'clipthresh'-sigma
3893 clipping (default is 0)
[2189]3894 plot: *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3895 plot the fit and the residual. In this each
3896 indivual fit has to be approved, by typing 'y'
3897 or 'n'
3898 getresidual: if False, returns best-fit values instead of
3899 residual. (default is True)
3900 showprogress: show progress status for large data.
3901 default is True.
3902 minnrow: minimum number of input spectra to show.
3903 default is 1000.
3904 outlog: Output the coefficients of the best-fit
3905 function to logger (default is False)
3906 blfile: Name of a text file in which the best-fit
3907 parameter values to be written
3908 (default is "": no file/logger output)
[2641]3909 csvformat: if True blfile is csv-formatted, default is False.
[2767]3910 bltable: name of a baseline table where fitting results
3911 (coefficients, rms, etc.) are to be written.
3912 if given, fitting results will NOT be output to
3913 scantable (insitu=True) or None will be
3914 returned (insitu=False).
3915 (default is "": no table output)
[1846]3916
[2012]3917 Example:
[2349]3918 # return a scan baselined by a cubic spline consisting of 2 pieces
3919 # (i.e., 1 internal knot),
[2012]3920 # also with 3-sigma clipping, iteration up to 4 times
3921 bscan = scan.cspline_baseline(npiece=2,clipthresh=3.0,clipniter=4)
[2081]3922
3923 Note:
3924 The best-fit parameter values output in logger and/or blfile are now
3925 based on specunit of 'channel'.
[2012]3926 """
3927
[2186]3928 try:
3929 varlist = vars()
3930
3931 if insitu is None: insitu = rcParams['insitu']
3932 if insitu:
3933 workscan = self
3934 else:
3935 workscan = self.copy()
[1855]3936
[2410]3937 if mask is None: mask = []
[2189]3938 if npiece is None: npiece = 2
3939 if clipthresh is None: clipthresh = 3.0
3940 if clipniter is None: clipniter = 0
3941 if plot is None: plot = False
3942 if getresidual is None: getresidual = True
3943 if showprogress is None: showprogress = True
3944 if minnrow is None: minnrow = 1000
3945 if outlog is None: outlog = False
3946 if blfile is None: blfile = ''
[2767]3947 if csvformat is None: csvformat = False
3948 if bltable is None: bltable = ''
[1855]3949
[2767]3950 scsvformat = 'T' if csvformat else 'F'
[2641]3951
[2012]3952 #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
[2767]3953 workscan._cspline_baseline(mask, npiece,
3954 clipthresh, clipniter,
[2349]3955 getresidual,
3956 pack_progress_params(showprogress,
[2641]3957 minnrow),
[2767]3958 outlog, scsvformat+blfile,
3959 bltable)
[2012]3960 workscan._add_history("cspline_baseline", varlist)
[2767]3961
3962 if bltable == '':
3963 if insitu:
3964 self._assign(workscan)
3965 else:
3966 return workscan
[2012]3967 else:
[2767]3968 if not insitu:
3969 return None
[2012]3970
3971 except RuntimeError, e:
[2186]3972 raise_fitting_failure_exception(e)
[1855]3973
[2186]3974 @asaplog_post_dec
[2771]3975 def auto_cspline_baseline(self, mask=None, npiece=None, insitu=None,
[2349]3976 clipthresh=None, clipniter=None,
3977 edge=None, threshold=None, chan_avg_limit=None,
3978 getresidual=None, plot=None,
3979 showprogress=None, minnrow=None, outlog=None,
[2767]3980 blfile=None, csvformat=None, bltable=None):
[2012]3981 """\
3982 Return a scan which has been baselined (all rows) by cubic spline
3983 function (piecewise cubic polynomial).
3984 Spectral lines are detected first using linefinder and masked out
3985 to avoid them affecting the baseline solution.
3986
3987 Parameters:
[2771]3988 mask: an optional mask retreived from scantable
3989 npiece: Number of pieces. (default is 2)
[2189]3990 insitu: if False a new scantable is returned.
3991 Otherwise, the scaling is done in-situ
3992 The default is taken from .asaprc (False)
3993 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
[2349]3994 clipniter: maximum number of iteration of 'clipthresh'-sigma
3995 clipping (default is 0)
[2189]3996 edge: an optional number of channel to drop at
3997 the edge of spectrum. If only one value is
3998 specified, the same number will be dropped
3999 from both sides of the spectrum. Default
4000 is to keep all channels. Nested tuples
4001 represent individual edge selection for
4002 different IFs (a number of spectral channels
4003 can be different)
4004 threshold: the threshold used by line finder. It is
4005 better to keep it large as only strong lines
4006 affect the baseline solution.
4007 chan_avg_limit: a maximum number of consequtive spectral
4008 channels to average during the search of
4009 weak and broad lines. The default is no
4010 averaging (and no search for weak lines).
4011 If such lines can affect the fitted baseline
4012 (e.g. a high order polynomial is fitted),
4013 increase this parameter (usually values up
4014 to 8 are reasonable). Most users of this
4015 method should find the default value sufficient.
4016 plot: *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
4017 plot the fit and the residual. In this each
4018 indivual fit has to be approved, by typing 'y'
4019 or 'n'
4020 getresidual: if False, returns best-fit values instead of
4021 residual. (default is True)
4022 showprogress: show progress status for large data.
4023 default is True.
4024 minnrow: minimum number of input spectra to show.
4025 default is 1000.
4026 outlog: Output the coefficients of the best-fit
4027 function to logger (default is False)
4028 blfile: Name of a text file in which the best-fit
4029 parameter values to be written
4030 (default is "": no file/logger output)
[2641]4031 csvformat: if True blfile is csv-formatted, default is False.
[2767]4032 bltable: name of a baseline table where fitting results
4033 (coefficients, rms, etc.) are to be written.
4034 if given, fitting results will NOT be output to
4035 scantable (insitu=True) or None will be
4036 returned (insitu=False).
4037 (default is "": no table output)
[1846]4038
[1907]4039 Example:
[2012]4040 bscan = scan.auto_cspline_baseline(npiece=3, insitu=False)
[2081]4041
4042 Note:
4043 The best-fit parameter values output in logger and/or blfile are now
4044 based on specunit of 'channel'.
[2012]4045 """
[1846]4046
[2186]4047 try:
4048 varlist = vars()
[2012]4049
[2186]4050 if insitu is None: insitu = rcParams['insitu']
4051 if insitu:
4052 workscan = self
[1391]4053 else:
[2186]4054 workscan = self.copy()
4055
[2410]4056 #if mask is None: mask = [True for i in xrange(workscan.nchan())]
4057 if mask is None: mask = []
[2186]4058 if npiece is None: npiece = 2
4059 if clipthresh is None: clipthresh = 3.0
4060 if clipniter is None: clipniter = 0
4061 if edge is None: edge = (0, 0)
4062 if threshold is None: threshold = 3
4063 if chan_avg_limit is None: chan_avg_limit = 1
4064 if plot is None: plot = False
4065 if getresidual is None: getresidual = True
[2189]4066 if showprogress is None: showprogress = True
4067 if minnrow is None: minnrow = 1000
[2186]4068 if outlog is None: outlog = False
4069 if blfile is None: blfile = ''
[2641]4070 if csvformat is None: csvformat = False
[2767]4071 if bltable is None: bltable = ''
[1819]4072
[2767]4073 scsvformat = 'T' if csvformat else 'F'
[2641]4074
[2277]4075 #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
[2767]4076 workscan._auto_cspline_baseline(mask, npiece,
4077 clipthresh, clipniter,
[2269]4078 normalise_edge_param(edge),
4079 threshold,
4080 chan_avg_limit, getresidual,
4081 pack_progress_params(showprogress,
4082 minnrow),
[2767]4083 outlog,
4084 scsvformat+blfile,
4085 bltable)
[2012]4086 workscan._add_history("auto_cspline_baseline", varlist)
[2767]4087
4088 if bltable == '':
4089 if insitu:
4090 self._assign(workscan)
4091 else:
4092 return workscan
[1856]4093 else:
[2767]4094 if not insitu:
4095 return None
[2012]4096
4097 except RuntimeError, e:
[2186]4098 raise_fitting_failure_exception(e)
[513]4099
[1931]4100 @asaplog_post_dec
[2771]4101 def chebyshev_baseline(self, mask=None, order=None, insitu=None,
[2645]4102 clipthresh=None, clipniter=None, plot=None,
4103 getresidual=None, showprogress=None, minnrow=None,
[2767]4104 outlog=None, blfile=None, csvformat=None,
4105 bltable=None):
[2645]4106 """\
4107 Return a scan which has been baselined (all rows) by Chebyshev polynomials.
4108
4109 Parameters:
[2771]4110 mask: An optional mask
4111 order: the maximum order of Chebyshev polynomial (default is 5)
[2645]4112 insitu: If False a new scantable is returned.
4113 Otherwise, the scaling is done in-situ
4114 The default is taken from .asaprc (False)
4115 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
4116 clipniter: maximum number of iteration of 'clipthresh'-sigma
4117 clipping (default is 0)
4118 plot: *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
4119 plot the fit and the residual. In this each
4120 indivual fit has to be approved, by typing 'y'
4121 or 'n'
4122 getresidual: if False, returns best-fit values instead of
4123 residual. (default is True)
4124 showprogress: show progress status for large data.
4125 default is True.
4126 minnrow: minimum number of input spectra to show.
4127 default is 1000.
4128 outlog: Output the coefficients of the best-fit
4129 function to logger (default is False)
4130 blfile: Name of a text file in which the best-fit
4131 parameter values to be written
4132 (default is "": no file/logger output)
4133 csvformat: if True blfile is csv-formatted, default is False.
[2767]4134 bltable: name of a baseline table where fitting results
4135 (coefficients, rms, etc.) are to be written.
4136 if given, fitting results will NOT be output to
4137 scantable (insitu=True) or None will be
4138 returned (insitu=False).
4139 (default is "": no table output)
[2645]4140
4141 Example:
4142 # return a scan baselined by a cubic spline consisting of 2 pieces
4143 # (i.e., 1 internal knot),
4144 # also with 3-sigma clipping, iteration up to 4 times
4145 bscan = scan.cspline_baseline(npiece=2,clipthresh=3.0,clipniter=4)
4146
4147 Note:
4148 The best-fit parameter values output in logger and/or blfile are now
4149 based on specunit of 'channel'.
4150 """
4151
4152 try:
4153 varlist = vars()
4154
4155 if insitu is None: insitu = rcParams['insitu']
4156 if insitu:
4157 workscan = self
4158 else:
4159 workscan = self.copy()
4160
4161 if mask is None: mask = []
4162 if order is None: order = 5
4163 if clipthresh is None: clipthresh = 3.0
4164 if clipniter is None: clipniter = 0
4165 if plot is None: plot = False
4166 if getresidual is None: getresidual = True
4167 if showprogress is None: showprogress = True
4168 if minnrow is None: minnrow = 1000
4169 if outlog is None: outlog = False
4170 if blfile is None: blfile = ''
[2767]4171 if csvformat is None: csvformat = False
4172 if bltable is None: bltable = ''
[2645]4173
[2767]4174 scsvformat = 'T' if csvformat else 'F'
[2645]4175
4176 #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
[2767]4177 workscan._chebyshev_baseline(mask, order,
4178 clipthresh, clipniter,
[2645]4179 getresidual,
4180 pack_progress_params(showprogress,
4181 minnrow),
[2767]4182 outlog, scsvformat+blfile,
4183 bltable)
[2645]4184 workscan._add_history("chebyshev_baseline", varlist)
[2767]4185
4186 if bltable == '':
4187 if insitu:
4188 self._assign(workscan)
4189 else:
4190 return workscan
[2645]4191 else:
[2767]4192 if not insitu:
4193 return None
[2645]4194
4195 except RuntimeError, e:
4196 raise_fitting_failure_exception(e)
4197
4198 @asaplog_post_dec
[2771]4199 def auto_chebyshev_baseline(self, mask=None, order=None, insitu=None,
[2645]4200 clipthresh=None, clipniter=None,
4201 edge=None, threshold=None, chan_avg_limit=None,
4202 getresidual=None, plot=None,
4203 showprogress=None, minnrow=None, outlog=None,
[2767]4204 blfile=None, csvformat=None, bltable=None):
[2645]4205 """\
4206 Return a scan which has been baselined (all rows) by Chebyshev polynomials.
4207 Spectral lines are detected first using linefinder and masked out
4208 to avoid them affecting the baseline solution.
4209
4210 Parameters:
[2771]4211 mask: an optional mask retreived from scantable
4212 order: the maximum order of Chebyshev polynomial (default is 5)
[2645]4213 insitu: if False a new scantable is returned.
4214 Otherwise, the scaling is done in-situ
4215 The default is taken from .asaprc (False)
4216 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
4217 clipniter: maximum number of iteration of 'clipthresh'-sigma
4218 clipping (default is 0)
4219 edge: an optional number of channel to drop at
4220 the edge of spectrum. If only one value is
4221 specified, the same number will be dropped
4222 from both sides of the spectrum. Default
4223 is to keep all channels. Nested tuples
4224 represent individual edge selection for
4225 different IFs (a number of spectral channels
4226 can be different)
4227 threshold: the threshold used by line finder. It is
4228 better to keep it large as only strong lines
4229 affect the baseline solution.
4230 chan_avg_limit: a maximum number of consequtive spectral
4231 channels to average during the search of
4232 weak and broad lines. The default is no
4233 averaging (and no search for weak lines).
4234 If such lines can affect the fitted baseline
4235 (e.g. a high order polynomial is fitted),
4236 increase this parameter (usually values up
4237 to 8 are reasonable). Most users of this
4238 method should find the default value sufficient.
4239 plot: *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
4240 plot the fit and the residual. In this each
4241 indivual fit has to be approved, by typing 'y'
4242 or 'n'
4243 getresidual: if False, returns best-fit values instead of
4244 residual. (default is True)
4245 showprogress: show progress status for large data.
4246 default is True.
4247 minnrow: minimum number of input spectra to show.
4248 default is 1000.
4249 outlog: Output the coefficients of the best-fit
4250 function to logger (default is False)
4251 blfile: Name of a text file in which the best-fit
4252 parameter values to be written
4253 (default is "": no file/logger output)
4254 csvformat: if True blfile is csv-formatted, default is False.
[2767]4255 bltable: name of a baseline table where fitting results
4256 (coefficients, rms, etc.) are to be written.
4257 if given, fitting results will NOT be output to
4258 scantable (insitu=True) or None will be
4259 returned (insitu=False).
4260 (default is "": no table output)
[2645]4261
4262 Example:
4263 bscan = scan.auto_cspline_baseline(npiece=3, insitu=False)
4264
4265 Note:
4266 The best-fit parameter values output in logger and/or blfile are now
4267 based on specunit of 'channel'.
4268 """
4269
4270 try:
4271 varlist = vars()
4272
4273 if insitu is None: insitu = rcParams['insitu']
4274 if insitu:
4275 workscan = self
4276 else:
4277 workscan = self.copy()
4278
4279 if mask is None: mask = []
4280 if order is None: order = 5
4281 if clipthresh is None: clipthresh = 3.0
4282 if clipniter is None: clipniter = 0
4283 if edge is None: edge = (0, 0)
4284 if threshold is None: threshold = 3
4285 if chan_avg_limit is None: chan_avg_limit = 1
4286 if plot is None: plot = False
4287 if getresidual is None: getresidual = True
4288 if showprogress is None: showprogress = True
4289 if minnrow is None: minnrow = 1000
4290 if outlog is None: outlog = False
4291 if blfile is None: blfile = ''
4292 if csvformat is None: csvformat = False
[2767]4293 if bltable is None: bltable = ''
[2645]4294
[2767]4295 scsvformat = 'T' if csvformat else 'F'
[2645]4296
4297 #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
[2767]4298 workscan._auto_chebyshev_baseline(mask, order,
4299 clipthresh, clipniter,
[2645]4300 normalise_edge_param(edge),
4301 threshold,
4302 chan_avg_limit, getresidual,
4303 pack_progress_params(showprogress,
4304 minnrow),
[2767]4305 outlog, scsvformat+blfile,
4306 bltable)
[2645]4307 workscan._add_history("auto_chebyshev_baseline", varlist)
[2767]4308
4309 if bltable == '':
4310 if insitu:
4311 self._assign(workscan)
4312 else:
4313 return workscan
[2645]4314 else:
[2767]4315 if not insitu:
4316 return None
[2645]4317
4318 except RuntimeError, e:
4319 raise_fitting_failure_exception(e)
4320
4321 @asaplog_post_dec
[2771]4322 def poly_baseline(self, mask=None, order=None, insitu=None,
[2767]4323 clipthresh=None, clipniter=None, plot=None,
[2269]4324 getresidual=None, showprogress=None, minnrow=None,
[2767]4325 outlog=None, blfile=None, csvformat=None,
4326 bltable=None):
[1907]4327 """\
4328 Return a scan which has been baselined (all rows) by a polynomial.
4329 Parameters:
[2771]4330 mask: an optional mask
4331 order: the order of the polynomial (default is 0)
[2189]4332 insitu: if False a new scantable is returned.
4333 Otherwise, the scaling is done in-situ
4334 The default is taken from .asaprc (False)
[2767]4335 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
4336 clipniter: maximum number of iteration of 'clipthresh'-sigma
4337 clipping (default is 0)
[2189]4338 plot: plot the fit and the residual. In this each
4339 indivual fit has to be approved, by typing 'y'
4340 or 'n'
4341 getresidual: if False, returns best-fit values instead of
4342 residual. (default is True)
4343 showprogress: show progress status for large data.
4344 default is True.
4345 minnrow: minimum number of input spectra to show.
4346 default is 1000.
4347 outlog: Output the coefficients of the best-fit
4348 function to logger (default is False)
4349 blfile: Name of a text file in which the best-fit
4350 parameter values to be written
4351 (default is "": no file/logger output)
[2641]4352 csvformat: if True blfile is csv-formatted, default is False.
[2767]4353 bltable: name of a baseline table where fitting results
4354 (coefficients, rms, etc.) are to be written.
4355 if given, fitting results will NOT be output to
4356 scantable (insitu=True) or None will be
4357 returned (insitu=False).
4358 (default is "": no table output)
[2012]4359
[1907]4360 Example:
4361 # return a scan baselined by a third order polynomial,
4362 # not using a mask
4363 bscan = scan.poly_baseline(order=3)
4364 """
[1931]4365
[2186]4366 try:
4367 varlist = vars()
[1931]4368
[2269]4369 if insitu is None:
4370 insitu = rcParams["insitu"]
[2186]4371 if insitu:
4372 workscan = self
4373 else:
4374 workscan = self.copy()
[1907]4375
[2410]4376 if mask is None: mask = []
[2189]4377 if order is None: order = 0
[2767]4378 if clipthresh is None: clipthresh = 3.0
4379 if clipniter is None: clipniter = 0
[2189]4380 if plot is None: plot = False
4381 if getresidual is None: getresidual = True
4382 if showprogress is None: showprogress = True
4383 if minnrow is None: minnrow = 1000
4384 if outlog is None: outlog = False
[2767]4385 if blfile is None: blfile = ''
[2641]4386 if csvformat is None: csvformat = False
[2767]4387 if bltable is None: bltable = ''
[1907]4388
[2767]4389 scsvformat = 'T' if csvformat else 'F'
[2641]4390
[2012]4391 if plot:
[2269]4392 outblfile = (blfile != "") and \
[2349]4393 os.path.exists(os.path.expanduser(
4394 os.path.expandvars(blfile))
4395 )
[2269]4396 if outblfile:
4397 blf = open(blfile, "a")
[2012]4398
[1907]4399 f = fitter()
4400 f.set_function(lpoly=order)
[2186]4401
4402 rows = xrange(workscan.nrow())
4403 #if len(rows) > 0: workscan._init_blinfo()
[2610]4404
4405 action = "H"
[1907]4406 for r in rows:
4407 f.x = workscan._getabcissa(r)
4408 f.y = workscan._getspectrum(r)
[2541]4409 if mask:
4410 f.mask = mask_and(mask, workscan._getmask(r)) # (CAS-1434)
4411 else: # mask=None
4412 f.mask = workscan._getmask(r)
4413
[1907]4414 f.data = None
4415 f.fit()
[2541]4416
[2610]4417 if action != "Y": # skip plotting when accepting all
4418 f.plot(residual=True)
4419 #accept_fit = raw_input("Accept fit ( [y]/n ): ")
4420 #if accept_fit.upper() == "N":
4421 # #workscan._append_blinfo(None, None, None)
4422 # continue
4423 accept_fit = self._get_verify_action("Accept fit?",action)
4424 if r == 0: action = None
[1907]4425 if accept_fit.upper() == "N":
4426 continue
[2610]4427 elif accept_fit.upper() == "R":
4428 break
4429 elif accept_fit.upper() == "A":
4430 action = "Y"
[2012]4431
4432 blpars = f.get_parameters()
4433 masklist = workscan.get_masklist(f.mask, row=r, silent=True)
4434 #workscan._append_blinfo(blpars, masklist, f.mask)
[2269]4435 workscan._setspectrum((f.fitter.getresidual()
4436 if getresidual else f.fitter.getfit()), r)
[1907]4437
[2012]4438 if outblfile:
4439 rms = workscan.get_rms(f.mask, r)
[2269]4440 dataout = \
4441 workscan.format_blparams_row(blpars["params"],
4442 blpars["fixed"],
4443 rms, str(masklist),
[2641]4444 r, True, csvformat)
[2012]4445 blf.write(dataout)
4446
[1907]4447 f._p.unmap()
4448 f._p = None
[2012]4449
[2349]4450 if outblfile:
4451 blf.close()
[1907]4452 else:
[2767]4453 workscan._poly_baseline(mask, order,
4454 clipthresh, clipniter, #
4455 getresidual,
[2269]4456 pack_progress_params(showprogress,
4457 minnrow),
[2767]4458 outlog, scsvformat+blfile,
4459 bltable) #
[1907]4460
4461 workscan._add_history("poly_baseline", varlist)
4462
4463 if insitu:
4464 self._assign(workscan)
4465 else:
4466 return workscan
4467
[1919]4468 except RuntimeError, e:
[2186]4469 raise_fitting_failure_exception(e)
[1907]4470
[2186]4471 @asaplog_post_dec
[2771]4472 def auto_poly_baseline(self, mask=None, order=None, insitu=None,
[2767]4473 clipthresh=None, clipniter=None,
4474 edge=None, threshold=None, chan_avg_limit=None,
4475 getresidual=None, plot=None,
4476 showprogress=None, minnrow=None, outlog=None,
4477 blfile=None, csvformat=None, bltable=None):
[1846]4478 """\
[1931]4479 Return a scan which has been baselined (all rows) by a polynomial.
[880]4480 Spectral lines are detected first using linefinder and masked out
4481 to avoid them affecting the baseline solution.
4482
4483 Parameters:
[2771]4484 mask: an optional mask retreived from scantable
4485 order: the order of the polynomial (default is 0)
[2189]4486 insitu: if False a new scantable is returned.
4487 Otherwise, the scaling is done in-situ
4488 The default is taken from .asaprc (False)
[2767]4489 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
4490 clipniter: maximum number of iteration of 'clipthresh'-sigma
4491 clipping (default is 0)
[2189]4492 edge: an optional number of channel to drop at
4493 the edge of spectrum. If only one value is
4494 specified, the same number will be dropped
4495 from both sides of the spectrum. Default
4496 is to keep all channels. Nested tuples
4497 represent individual edge selection for
4498 different IFs (a number of spectral channels
4499 can be different)
4500 threshold: the threshold used by line finder. It is
4501 better to keep it large as only strong lines
4502 affect the baseline solution.
4503 chan_avg_limit: a maximum number of consequtive spectral
4504 channels to average during the search of
4505 weak and broad lines. The default is no
4506 averaging (and no search for weak lines).
4507 If such lines can affect the fitted baseline
4508 (e.g. a high order polynomial is fitted),
4509 increase this parameter (usually values up
4510 to 8 are reasonable). Most users of this
4511 method should find the default value sufficient.
4512 plot: plot the fit and the residual. In this each
4513 indivual fit has to be approved, by typing 'y'
4514 or 'n'
4515 getresidual: if False, returns best-fit values instead of
4516 residual. (default is True)
4517 showprogress: show progress status for large data.
4518 default is True.
4519 minnrow: minimum number of input spectra to show.
4520 default is 1000.
4521 outlog: Output the coefficients of the best-fit
4522 function to logger (default is False)
4523 blfile: Name of a text file in which the best-fit
4524 parameter values to be written
4525 (default is "": no file/logger output)
[2641]4526 csvformat: if True blfile is csv-formatted, default is False.
[2767]4527 bltable: name of a baseline table where fitting results
4528 (coefficients, rms, etc.) are to be written.
4529 if given, fitting results will NOT be output to
4530 scantable (insitu=True) or None will be
4531 returned (insitu=False).
4532 (default is "": no table output)
[1846]4533
[2012]4534 Example:
4535 bscan = scan.auto_poly_baseline(order=7, insitu=False)
4536 """
[880]4537
[2186]4538 try:
4539 varlist = vars()
[1846]4540
[2269]4541 if insitu is None:
4542 insitu = rcParams['insitu']
[2186]4543 if insitu:
4544 workscan = self
4545 else:
4546 workscan = self.copy()
[1846]4547
[2410]4548 if mask is None: mask = []
[2186]4549 if order is None: order = 0
[2767]4550 if clipthresh is None: clipthresh = 3.0
4551 if clipniter is None: clipniter = 0
[2186]4552 if edge is None: edge = (0, 0)
4553 if threshold is None: threshold = 3
4554 if chan_avg_limit is None: chan_avg_limit = 1
4555 if plot is None: plot = False
4556 if getresidual is None: getresidual = True
[2189]4557 if showprogress is None: showprogress = True
4558 if minnrow is None: minnrow = 1000
[2186]4559 if outlog is None: outlog = False
4560 if blfile is None: blfile = ''
[2641]4561 if csvformat is None: csvformat = False
[2767]4562 if bltable is None: bltable = ''
[1846]4563
[2767]4564 scsvformat = 'T' if csvformat else 'F'
[2641]4565
[2186]4566 edge = normalise_edge_param(edge)
[880]4567
[2012]4568 if plot:
[2269]4569 outblfile = (blfile != "") and \
4570 os.path.exists(os.path.expanduser(os.path.expandvars(blfile)))
[2012]4571 if outblfile: blf = open(blfile, "a")
4572
[2186]4573 from asap.asaplinefind import linefinder
[2012]4574 fl = linefinder()
[2269]4575 fl.set_options(threshold=threshold, avg_limit=chan_avg_limit)
[2012]4576 fl.set_scan(workscan)
[2186]4577
[2012]4578 f = fitter()
4579 f.set_function(lpoly=order)
[880]4580
[2186]4581 rows = xrange(workscan.nrow())
4582 #if len(rows) > 0: workscan._init_blinfo()
[2610]4583
4584 action = "H"
[2012]4585 for r in rows:
[2186]4586 idx = 2*workscan.getif(r)
[2541]4587 if mask:
4588 msk = mask_and(mask, workscan._getmask(r)) # (CAS-1434)
4589 else: # mask=None
4590 msk = workscan._getmask(r)
4591 fl.find_lines(r, msk, edge[idx:idx+2])
[907]4592
[2012]4593 f.x = workscan._getabcissa(r)
4594 f.y = workscan._getspectrum(r)
4595 f.mask = fl.get_mask()
4596 f.data = None
4597 f.fit()
4598
[2610]4599 if action != "Y": # skip plotting when accepting all
4600 f.plot(residual=True)
4601 #accept_fit = raw_input("Accept fit ( [y]/n ): ")
4602 accept_fit = self._get_verify_action("Accept fit?",action)
4603 if r == 0: action = None
[2012]4604 if accept_fit.upper() == "N":
4605 #workscan._append_blinfo(None, None, None)
4606 continue
[2610]4607 elif accept_fit.upper() == "R":
4608 break
4609 elif accept_fit.upper() == "A":
4610 action = "Y"
[2012]4611
4612 blpars = f.get_parameters()
4613 masklist = workscan.get_masklist(f.mask, row=r, silent=True)
4614 #workscan._append_blinfo(blpars, masklist, f.mask)
[2349]4615 workscan._setspectrum(
4616 (f.fitter.getresidual() if getresidual
4617 else f.fitter.getfit()), r
4618 )
[2012]4619
4620 if outblfile:
4621 rms = workscan.get_rms(f.mask, r)
[2269]4622 dataout = \
4623 workscan.format_blparams_row(blpars["params"],
4624 blpars["fixed"],
4625 rms, str(masklist),
[2641]4626 r, True, csvformat)
[2012]4627 blf.write(dataout)
4628
4629 f._p.unmap()
4630 f._p = None
4631
4632 if outblfile: blf.close()
4633 else:
[2767]4634 workscan._auto_poly_baseline(mask, order,
4635 clipthresh, clipniter,
4636 edge, threshold,
[2269]4637 chan_avg_limit, getresidual,
4638 pack_progress_params(showprogress,
4639 minnrow),
[2767]4640 outlog, scsvformat+blfile,
4641 bltable)
4642 workscan._add_history("auto_poly_baseline", varlist)
[2012]4643
[2767]4644 if bltable == '':
4645 if insitu:
4646 self._assign(workscan)
4647 else:
4648 return workscan
[2012]4649 else:
[2767]4650 if not insitu:
4651 return None
[2012]4652
4653 except RuntimeError, e:
[2186]4654 raise_fitting_failure_exception(e)
[2012]4655
4656 def _init_blinfo(self):
4657 """\
4658 Initialise the following three auxiliary members:
4659 blpars : parameters of the best-fit baseline,
4660 masklists : mask data (edge positions of masked channels) and
4661 actualmask : mask data (in boolean list),
4662 to keep for use later (including output to logger/text files).
4663 Used by poly_baseline() and auto_poly_baseline() in case of
4664 'plot=True'.
4665 """
4666 self.blpars = []
4667 self.masklists = []
4668 self.actualmask = []
4669 return
[880]4670
[2012]4671 def _append_blinfo(self, data_blpars, data_masklists, data_actualmask):
4672 """\
4673 Append baseline-fitting related info to blpars, masklist and
4674 actualmask.
4675 """
4676 self.blpars.append(data_blpars)
4677 self.masklists.append(data_masklists)
4678 self.actualmask.append(data_actualmask)
4679 return
4680
[1862]4681 @asaplog_post_dec
[914]4682 def rotate_linpolphase(self, angle):
[1846]4683 """\
[914]4684 Rotate the phase of the complex polarization O=Q+iU correlation.
4685 This is always done in situ in the raw data. So if you call this
4686 function more than once then each call rotates the phase further.
[1846]4687
[914]4688 Parameters:
[1846]4689
[914]4690 angle: The angle (degrees) to rotate (add) by.
[1846]4691
4692 Example::
4693
[914]4694 scan.rotate_linpolphase(2.3)
[1846]4695
[914]4696 """
4697 varlist = vars()
[936]4698 self._math._rotate_linpolphase(self, angle)
[914]4699 self._add_history("rotate_linpolphase", varlist)
4700 return
[710]4701
[1862]4702 @asaplog_post_dec
[914]4703 def rotate_xyphase(self, angle):
[1846]4704 """\
[914]4705 Rotate the phase of the XY correlation. This is always done in situ
4706 in the data. So if you call this function more than once
4707 then each call rotates the phase further.
[1846]4708
[914]4709 Parameters:
[1846]4710
[914]4711 angle: The angle (degrees) to rotate (add) by.
[1846]4712
4713 Example::
4714
[914]4715 scan.rotate_xyphase(2.3)
[1846]4716
[914]4717 """
4718 varlist = vars()
[936]4719 self._math._rotate_xyphase(self, angle)
[914]4720 self._add_history("rotate_xyphase", varlist)
4721 return
4722
[1862]4723 @asaplog_post_dec
[914]4724 def swap_linears(self):
[1846]4725 """\
[1573]4726 Swap the linear polarisations XX and YY, or better the first two
[1348]4727 polarisations as this also works for ciculars.
[914]4728 """
4729 varlist = vars()
[936]4730 self._math._swap_linears(self)
[914]4731 self._add_history("swap_linears", varlist)
4732 return
4733
[1862]4734 @asaplog_post_dec
[914]4735 def invert_phase(self):
[1846]4736 """\
[914]4737 Invert the phase of the complex polarisation
4738 """
4739 varlist = vars()
[936]4740 self._math._invert_phase(self)
[914]4741 self._add_history("invert_phase", varlist)
4742 return
4743
[1862]4744 @asaplog_post_dec
[876]4745 def add(self, offset, insitu=None):
[1846]4746 """\
[513]4747 Return a scan where all spectra have the offset added
[1846]4748
[513]4749 Parameters:
[1846]4750
[513]4751 offset: the offset
[1855]4752
[513]4753 insitu: if False a new scantable is returned.
4754 Otherwise, the scaling is done in-situ
4755 The default is taken from .asaprc (False)
[1846]4756
[513]4757 """
4758 if insitu is None: insitu = rcParams['insitu']
[876]4759 self._math._setinsitu(insitu)
[513]4760 varlist = vars()
[876]4761 s = scantable(self._math._unaryop(self, offset, "ADD", False))
[1118]4762 s._add_history("add", varlist)
[876]4763 if insitu:
4764 self._assign(s)
4765 else:
[513]4766 return s
4767
[1862]4768 @asaplog_post_dec
[1308]4769 def scale(self, factor, tsys=True, insitu=None):
[1846]4770 """\
4771
[1938]4772 Return a scan where all spectra are scaled by the given 'factor'
[1846]4773
[513]4774 Parameters:
[1846]4775
[1819]4776 factor: the scaling factor (float or 1D float list)
[1855]4777
[513]4778 insitu: if False a new scantable is returned.
4779 Otherwise, the scaling is done in-situ
4780 The default is taken from .asaprc (False)
[1855]4781
[513]4782 tsys: if True (default) then apply the operation to Tsys
4783 as well as the data
[1846]4784
[513]4785 """
4786 if insitu is None: insitu = rcParams['insitu']
[876]4787 self._math._setinsitu(insitu)
[513]4788 varlist = vars()
[1819]4789 s = None
4790 import numpy
4791 if isinstance(factor, list) or isinstance(factor, numpy.ndarray):
[2320]4792 if isinstance(factor[0], list) or isinstance(factor[0],
4793 numpy.ndarray):
[1819]4794 from asapmath import _array2dOp
[2320]4795 s = _array2dOp( self, factor, "MUL", tsys, insitu )
[1819]4796 else:
[2320]4797 s = scantable( self._math._arrayop( self, factor,
4798 "MUL", tsys ) )
[1819]4799 else:
[2320]4800 s = scantable(self._math._unaryop(self, factor, "MUL", tsys))
[1118]4801 s._add_history("scale", varlist)
[876]4802 if insitu:
4803 self._assign(s)
4804 else:
[513]4805 return s
4806
[2349]4807 @preserve_selection
4808 def set_sourcetype(self, match, matchtype="pattern",
[1504]4809 sourcetype="reference"):
[1846]4810 """\
[1502]4811 Set the type of the source to be an source or reference scan
[1846]4812 using the provided pattern.
4813
[1502]4814 Parameters:
[1846]4815
[1504]4816 match: a Unix style pattern, regular expression or selector
[1855]4817
[1504]4818 matchtype: 'pattern' (default) UNIX style pattern or
4819 'regex' regular expression
[1855]4820
[1502]4821 sourcetype: the type of the source to use (source/reference)
[1846]4822
[1502]4823 """
4824 varlist = vars()
4825 stype = -1
[2480]4826 if sourcetype.lower().startswith("r") or sourcetype.lower() == "off":
[1502]4827 stype = 1
[2480]4828 elif sourcetype.lower().startswith("s") or sourcetype.lower() == "on":
[1502]4829 stype = 0
[1504]4830 else:
[2480]4831 raise ValueError("Illegal sourcetype use s(ource)/on or r(eference)/off")
[1504]4832 if matchtype.lower().startswith("p"):
4833 matchtype = "pattern"
4834 elif matchtype.lower().startswith("r"):
4835 matchtype = "regex"
4836 else:
4837 raise ValueError("Illegal matchtype, use p(attern) or r(egex)")
[1502]4838 sel = selector()
4839 if isinstance(match, selector):
4840 sel = match
4841 else:
[2480]4842 sel.set_query("SRCNAME=%s('%s')" % (matchtype, match))
4843 self.set_selection(sel)
[1502]4844 self._setsourcetype(stype)
[1573]4845 self._add_history("set_sourcetype", varlist)
[1502]4846
[2818]4847
4848 def set_sourcename(self, name):
4849 varlist = vars()
4850 self._setsourcename(name)
4851 self._add_history("set_sourcename", varlist)
4852
[1862]4853 @asaplog_post_dec
[1857]4854 @preserve_selection
[1819]4855 def auto_quotient(self, preserve=True, mode='paired', verify=False):
[1846]4856 """\
[670]4857 This function allows to build quotients automatically.
[1819]4858 It assumes the observation to have the same number of
[670]4859 "ons" and "offs"
[1846]4860
[670]4861 Parameters:
[1846]4862
[710]4863 preserve: you can preserve (default) the continuum or
4864 remove it. The equations used are
[1857]4865
[670]4866 preserve: Output = Toff * (on/off) - Toff
[1857]4867
[1070]4868 remove: Output = Toff * (on/off) - Ton
[1855]4869
[1573]4870 mode: the on/off detection mode
[1348]4871 'paired' (default)
4872 identifies 'off' scans by the
4873 trailing '_R' (Mopra/Parkes) or
4874 '_e'/'_w' (Tid) and matches
4875 on/off pairs from the observing pattern
[1502]4876 'time'
4877 finds the closest off in time
[1348]4878
[1857]4879 .. todo:: verify argument is not implemented
4880
[670]4881 """
[1857]4882 varlist = vars()
[1348]4883 modes = ["time", "paired"]
[670]4884 if not mode in modes:
[876]4885 msg = "please provide valid mode. Valid modes are %s" % (modes)
4886 raise ValueError(msg)
[1348]4887 s = None
4888 if mode.lower() == "paired":
[2840]4889 from asap._asap import srctype
[1857]4890 sel = self.get_selection()
[2840]4891 #sel.set_query("SRCTYPE==psoff")
4892 sel.set_types(srctype.psoff)
[1356]4893 self.set_selection(sel)
[1348]4894 offs = self.copy()
[2840]4895 #sel.set_query("SRCTYPE==pson")
4896 sel.set_types(srctype.pson)
[1356]4897 self.set_selection(sel)
[1348]4898 ons = self.copy()
4899 s = scantable(self._math._quotient(ons, offs, preserve))
4900 elif mode.lower() == "time":
4901 s = scantable(self._math._auto_quotient(self, mode, preserve))
[1118]4902 s._add_history("auto_quotient", varlist)
[876]4903 return s
[710]4904
[1862]4905 @asaplog_post_dec
[1145]4906 def mx_quotient(self, mask = None, weight='median', preserve=True):
[1846]4907 """\
[1143]4908 Form a quotient using "off" beams when observing in "MX" mode.
[1846]4909
[1143]4910 Parameters:
[1846]4911
[1145]4912 mask: an optional mask to be used when weight == 'stddev'
[1855]4913
[1143]4914 weight: How to average the off beams. Default is 'median'.
[1855]4915
[1145]4916 preserve: you can preserve (default) the continuum or
[1855]4917 remove it. The equations used are:
[1846]4918
[1855]4919 preserve: Output = Toff * (on/off) - Toff
4920
4921 remove: Output = Toff * (on/off) - Ton
4922
[1217]4923 """
[1593]4924 mask = mask or ()
[1141]4925 varlist = vars()
4926 on = scantable(self._math._mx_extract(self, 'on'))
[1143]4927 preoff = scantable(self._math._mx_extract(self, 'off'))
4928 off = preoff.average_time(mask=mask, weight=weight, scanav=False)
[1217]4929 from asapmath import quotient
[1145]4930 q = quotient(on, off, preserve)
[1143]4931 q._add_history("mx_quotient", varlist)
[1217]4932 return q
[513]4933
[1862]4934 @asaplog_post_dec
[718]4935 def freq_switch(self, insitu=None):
[1846]4936 """\
[718]4937 Apply frequency switching to the data.
[1846]4938
[718]4939 Parameters:
[1846]4940
[718]4941 insitu: if False a new scantable is returned.
4942 Otherwise, the swictching is done in-situ
4943 The default is taken from .asaprc (False)
[1846]4944
[718]4945 """
4946 if insitu is None: insitu = rcParams['insitu']
[876]4947 self._math._setinsitu(insitu)
[718]4948 varlist = vars()
[876]4949 s = scantable(self._math._freqswitch(self))
[1118]4950 s._add_history("freq_switch", varlist)
[1856]4951 if insitu:
4952 self._assign(s)
4953 else:
4954 return s
[718]4955
[1862]4956 @asaplog_post_dec
[780]4957 def recalc_azel(self):
[1846]4958 """Recalculate the azimuth and elevation for each position."""
[780]4959 varlist = vars()
[876]4960 self._recalcazel()
[780]4961 self._add_history("recalc_azel", varlist)
4962 return
4963
[1862]4964 @asaplog_post_dec
[513]4965 def __add__(self, other):
[2574]4966 """
4967 implicit on all axes and on Tsys
4968 """
[513]4969 varlist = vars()
[2574]4970 s = self.__op( other, "ADD" )
[513]4971 s._add_history("operator +", varlist)
4972 return s
4973
[1862]4974 @asaplog_post_dec
[513]4975 def __sub__(self, other):
4976 """
4977 implicit on all axes and on Tsys
4978 """
4979 varlist = vars()
[2574]4980 s = self.__op( other, "SUB" )
[513]4981 s._add_history("operator -", varlist)
4982 return s
[710]4983
[1862]4984 @asaplog_post_dec
[513]4985 def __mul__(self, other):
4986 """
4987 implicit on all axes and on Tsys
4988 """
4989 varlist = vars()
[2574]4990 s = self.__op( other, "MUL" ) ;
[513]4991 s._add_history("operator *", varlist)
4992 return s
4993
[710]4994
[1862]4995 @asaplog_post_dec
[513]4996 def __div__(self, other):
4997 """
4998 implicit on all axes and on Tsys
4999 """
5000 varlist = vars()
[2574]5001 s = self.__op( other, "DIV" )
5002 s._add_history("operator /", varlist)
5003 return s
5004
5005 @asaplog_post_dec
5006 def __op( self, other, mode ):
[513]5007 s = None
5008 if isinstance(other, scantable):
[2574]5009 s = scantable(self._math._binaryop(self, other, mode))
[513]5010 elif isinstance(other, float):
5011 if other == 0.0:
[718]5012 raise ZeroDivisionError("Dividing by zero is not recommended")
[2574]5013 s = scantable(self._math._unaryop(self, other, mode, False))
[2144]5014 elif isinstance(other, list) or isinstance(other, numpy.ndarray):
[2349]5015 if isinstance(other[0], list) \
5016 or isinstance(other[0], numpy.ndarray):
[2144]5017 from asapmath import _array2dOp
[2574]5018 s = _array2dOp( self, other, mode, False )
[2144]5019 else:
[2574]5020 s = scantable( self._math._arrayop( self, other,
5021 mode, False ) )
[513]5022 else:
[718]5023 raise TypeError("Other input is not a scantable or float value")
[513]5024 return s
5025
[1862]5026 @asaplog_post_dec
[530]5027 def get_fit(self, row=0):
[1846]5028 """\
[530]5029 Print or return the stored fits for a row in the scantable
[1846]5030
[530]5031 Parameters:
[1846]5032
[530]5033 row: the row which the fit has been applied to.
[1846]5034
[530]5035 """
5036 if row > self.nrow():
5037 return
[976]5038 from asap.asapfit import asapfit
[530]5039 fit = asapfit(self._getfit(row))
[1859]5040 asaplog.push( '%s' %(fit) )
5041 return fit.as_dict()
[530]5042
[2349]5043 @preserve_selection
[1483]5044 def flag_nans(self):
[1846]5045 """\
[1483]5046 Utility function to flag NaN values in the scantable.
5047 """
5048 import numpy
5049 basesel = self.get_selection()
5050 for i in range(self.nrow()):
[1589]5051 sel = self.get_row_selector(i)
5052 self.set_selection(basesel+sel)
[1483]5053 nans = numpy.isnan(self._getspectrum(0))
[2877]5054 if numpy.any(nans):
5055 bnans = [ bool(v) for v in nans]
5056 self.flag(bnans)
5057
5058 self.set_selection(basesel)
[1483]5059
[1588]5060 def get_row_selector(self, rowno):
[1992]5061 return selector(rows=[rowno])
[1573]5062
[484]5063 def _add_history(self, funcname, parameters):
[1435]5064 if not rcParams['scantable.history']:
5065 return
[484]5066 # create date
5067 sep = "##"
5068 from datetime import datetime
5069 dstr = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
5070 hist = dstr+sep
5071 hist += funcname+sep#cdate+sep
[2349]5072 if parameters.has_key('self'):
5073 del parameters['self']
[1118]5074 for k, v in parameters.iteritems():
[484]5075 if type(v) is dict:
[1118]5076 for k2, v2 in v.iteritems():
[484]5077 hist += k2
5078 hist += "="
[1118]5079 if isinstance(v2, scantable):
[484]5080 hist += 'scantable'
5081 elif k2 == 'mask':
[1118]5082 if isinstance(v2, list) or isinstance(v2, tuple):
[513]5083 hist += str(self._zip_mask(v2))
5084 else:
5085 hist += str(v2)
[484]5086 else:
[513]5087 hist += str(v2)
[484]5088 else:
5089 hist += k
5090 hist += "="
[1118]5091 if isinstance(v, scantable):
[484]5092 hist += 'scantable'
5093 elif k == 'mask':
[1118]5094 if isinstance(v, list) or isinstance(v, tuple):
[513]5095 hist += str(self._zip_mask(v))
5096 else:
5097 hist += str(v)
[484]5098 else:
5099 hist += str(v)
5100 hist += sep
5101 hist = hist[:-2] # remove trailing '##'
5102 self._addhistory(hist)
5103
[710]5104
[484]5105 def _zip_mask(self, mask):
5106 mask = list(mask)
5107 i = 0
5108 segments = []
5109 while mask[i:].count(1):
5110 i += mask[i:].index(1)
5111 if mask[i:].count(0):
5112 j = i + mask[i:].index(0)
5113 else:
[710]5114 j = len(mask)
[1118]5115 segments.append([i, j])
[710]5116 i = j
[484]5117 return segments
[714]5118
[626]5119 def _get_ordinate_label(self):
5120 fu = "("+self.get_fluxunit()+")"
5121 import re
5122 lbl = "Intensity"
[1118]5123 if re.match(".K.", fu):
[626]5124 lbl = "Brightness Temperature "+ fu
[1118]5125 elif re.match(".Jy.", fu):
[626]5126 lbl = "Flux density "+ fu
5127 return lbl
[710]5128
[876]5129 def _check_ifs(self):
[2349]5130# return len(set([self.nchan(i) for i in self.getifnos()])) == 1
[1986]5131 nchans = [self.nchan(i) for i in self.getifnos()]
[2004]5132 nchans = filter(lambda t: t > 0, nchans)
[876]5133 return (sum(nchans)/len(nchans) == nchans[0])
[976]5134
[1862]5135 @asaplog_post_dec
[1916]5136 def _fill(self, names, unit, average, opts={}):
[976]5137 first = True
5138 fullnames = []
5139 for name in names:
5140 name = os.path.expandvars(name)
5141 name = os.path.expanduser(name)
5142 if not os.path.exists(name):
5143 msg = "File '%s' does not exists" % (name)
5144 raise IOError(msg)
5145 fullnames.append(name)
5146 if average:
5147 asaplog.push('Auto averaging integrations')
[1079]5148 stype = int(rcParams['scantable.storage'].lower() == 'disk')
[976]5149 for name in fullnames:
[1073]5150 tbl = Scantable(stype)
[2004]5151 if is_ms( name ):
5152 r = msfiller( tbl )
5153 else:
5154 r = filler( tbl )
[976]5155 msg = "Importing %s..." % (name)
[1118]5156 asaplog.push(msg, False)
[2349]5157 r.open(name, opts)
[2480]5158 rx = rcParams['scantable.reference']
5159 r.setreferenceexpr(rx)
[1843]5160 r.fill()
[976]5161 if average:
[1118]5162 tbl = self._math._average((tbl, ), (), 'NONE', 'SCAN')
[976]5163 if not first:
[2902]5164 tbl = self._math._merge([self, tbl])
[976]5165 Scantable.__init__(self, tbl)
[1843]5166 r.close()
[1118]5167 del r, tbl
[976]5168 first = False
[1861]5169 #flush log
5170 asaplog.post()
[976]5171 if unit is not None:
5172 self.set_fluxunit(unit)
[1824]5173 if not is_casapy():
5174 self.set_freqframe(rcParams['scantable.freqframe'])
[976]5175
[2610]5176 def _get_verify_action( self, msg, action=None ):
5177 valid_act = ['Y', 'N', 'A', 'R']
5178 if not action or not isinstance(action, str):
5179 action = raw_input("%s [Y/n/a/r] (h for help): " % msg)
5180 if action == '':
5181 return "Y"
5182 elif (action.upper()[0] in valid_act):
5183 return action.upper()[0]
5184 elif (action.upper()[0] in ['H','?']):
5185 print "Available actions of verification [Y|n|a|r]"
5186 print " Y : Yes for current data (default)"
5187 print " N : No for current data"
5188 print " A : Accept all in the following and exit from verification"
5189 print " R : Reject all in the following and exit from verification"
5190 print " H or ?: help (show this message)"
5191 return self._get_verify_action(msg)
5192 else:
5193 return 'Y'
[2012]5194
[1402]5195 def __getitem__(self, key):
5196 if key < 0:
5197 key += self.nrow()
5198 if key >= self.nrow():
5199 raise IndexError("Row index out of range.")
5200 return self._getspectrum(key)
5201
5202 def __setitem__(self, key, value):
5203 if key < 0:
5204 key += self.nrow()
5205 if key >= self.nrow():
5206 raise IndexError("Row index out of range.")
5207 if not hasattr(value, "__len__") or \
5208 len(value) > self.nchan(self.getif(key)):
5209 raise ValueError("Spectrum length doesn't match.")
5210 return self._setspectrum(value, key)
5211
5212 def __len__(self):
5213 return self.nrow()
5214
5215 def __iter__(self):
5216 for i in range(len(self)):
5217 yield self[i]
Note: See TracBrowser for help on using the repository browser.