source: trunk/python/scantable.py@ 2891

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

New Development: No

JIRA Issue: Yes CAS-5870

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes:

Module(s): sd

Description: added functions for scantable to correctly treat the given restfreq.


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