source: trunk/python/scantable.py@ 2908

Last change on this file since 2908 was 2902, checked in by Takeshi Nakazato, 11 years ago

New Development: No

JIRA Issue: Yes CAS-5875

Ready for Test: Yes

Interface Changes: No

What Interface Changed: Please list interface changes

Test Programs: test_sdcoadd

Put in Release Notes: Yes/No

Module(s): Module Names change impacts.

Description: Describe your changes here...

Another possible fix for broken build of standalone asap which may
be more reasonable and more robust than before.


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