source: trunk/python/scantable.py@ 2966

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

New Development: No

JIRA Issue: Yes CAS-6598

Ready for Test: Yes

Interface Changes: Yes

What Interface Changed: method parameter (removed)

Test Programs: test_sdscale

Put in Release Notes: No

Module(s): sd

Description: removed a parameter of sd.scantable.scale(), skip_flaggedrow, and also changed the default behaviour of the method to skip scaling for row-flagged spectra.


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