source: trunk/python/scantable.py@ 2940

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

New Development: No

JIRA Issue: Yes CAS-6485

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s): sd

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


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