source: branches/plotter2/python/scantable.py@ 2937

Last change on this file since 2937 was 2820, checked in by Malte Marquarding, 11 years ago

Issue #293: added scantbale.drop_history and added extra parameters to scantable.history to allow selection of rows

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