source: trunk/python/scantable.py@ 2819

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

Issue #291: added scantable.set_sourcename to overwrite sourcename to allow freq_align to work. Exposed 'SOURCE' averaging to python api. Added some logging to freq_align refering to the sources it aligns to

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 182.1 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):
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 hist = list(self._gethistory())
2079 out = "-"*80
2080 for h in hist:
2081 if h.startswith("---"):
2082 out = "\n".join([out, h])
2083 else:
2084 items = h.split("##")
2085 date = items[0]
2086 func = items[1]
2087 items = items[2:]
2088 out += "\n"+date+"\n"
2089 out += "Function: %s\n Parameters:" % (func)
2090 for i in items:
2091 if i == '':
2092 continue
2093 s = i.split("=")
2094 out += "\n %s = %s" % (s[0], s[1])
2095 out = "\n".join([out, "-"*80])
2096 if filename is not None:
2097 if filename is "":
2098 filename = 'scantable_history.txt'
2099 import os
2100 filename = os.path.expandvars(os.path.expanduser(filename))
2101 if not os.path.isdir(filename):
2102 data = open(filename, 'w')
2103 data.write(out)
2104 data.close()
2105 else:
2106 msg = "Illegal file name '%s'." % (filename)
2107 raise IOError(msg)
2108 return page(out)
2109
2110 #
2111 # Maths business
2112 #
2113 @asaplog_post_dec
2114 def average_time(self, mask=None, scanav=False, weight='tint', align=False,
2115 avmode="NONE"):
2116 """\
2117 Return the (time) weighted average of a scan. Scans will be averaged
2118 only if the source direction (RA/DEC) is within 1' otherwise
2119
2120 *Note*:
2121
2122 in channels only - align if necessary
2123
2124 Parameters:
2125
2126 mask: an optional mask (only used for 'var' and 'tsys'
2127 weighting)
2128
2129 scanav: True averages each scan separately
2130 False (default) averages all scans together,
2131
2132 weight: Weighting scheme.
2133 'none' (mean no weight)
2134 'var' (1/var(spec) weighted)
2135 'tsys' (1/Tsys**2 weighted)
2136 'tint' (integration time weighted)
2137 'tintsys' (Tint/Tsys**2)
2138 'median' ( median averaging)
2139 The default is 'tint'
2140
2141 align: align the spectra in velocity before averaging. It takes
2142 the time of the first spectrum as reference time.
2143 avmode: 'SOURCE' - also select by source name - or
2144 'NONE' (default). Not applicable for scanav=True or
2145 weight=median
2146
2147 Example::
2148
2149 # time average the scantable without using a mask
2150 newscan = scan.average_time()
2151
2152 """
2153 varlist = vars()
2154 weight = weight or 'TINT'
2155 mask = mask or ()
2156 scanav = (scanav and 'SCAN') or avmode.upper()
2157 scan = (self, )
2158
2159 if align:
2160 scan = (self.freq_align(insitu=False), )
2161 asaplog.push("Note: Alignment is don on a source-by-source basis")
2162 asaplog.push("Note: Averaging (by default) is not")
2163 # we need to set it to SOURCE averaging here
2164 s = None
2165 if weight.upper() == 'MEDIAN':
2166 s = scantable(self._math._averagechannel(scan[0], 'MEDIAN',
2167 scanav))
2168 else:
2169 s = scantable(self._math._average(scan, mask, weight.upper(),
2170 scanav))
2171 s._add_history("average_time", varlist)
2172 return s
2173
2174 @asaplog_post_dec
2175 def convert_flux(self, jyperk=None, eta=None, d=None, insitu=None):
2176 """\
2177 Return a scan where all spectra are converted to either
2178 Jansky or Kelvin depending upon the flux units of the scan table.
2179 By default the function tries to look the values up internally.
2180 If it can't find them (or if you want to over-ride), you must
2181 specify EITHER jyperk OR eta (and D which it will try to look up
2182 also if you don't set it). jyperk takes precedence if you set both.
2183
2184 Parameters:
2185
2186 jyperk: the Jy / K conversion factor
2187
2188 eta: the aperture efficiency
2189
2190 d: the geometric diameter (metres)
2191
2192 insitu: if False a new scantable is returned.
2193 Otherwise, the scaling is done in-situ
2194 The default is taken from .asaprc (False)
2195
2196 """
2197 if insitu is None: insitu = rcParams['insitu']
2198 self._math._setinsitu(insitu)
2199 varlist = vars()
2200 jyperk = jyperk or -1.0
2201 d = d or -1.0
2202 eta = eta or -1.0
2203 s = scantable(self._math._convertflux(self, d, eta, jyperk))
2204 s._add_history("convert_flux", varlist)
2205 if insitu: self._assign(s)
2206 else: return s
2207
2208 @asaplog_post_dec
2209 def gain_el(self, poly=None, filename="", method="linear", insitu=None):
2210 """\
2211 Return a scan after applying a gain-elevation correction.
2212 The correction can be made via either a polynomial or a
2213 table-based interpolation (and extrapolation if necessary).
2214 You specify polynomial coefficients, an ascii table or neither.
2215 If you specify neither, then a polynomial correction will be made
2216 with built in coefficients known for certain telescopes (an error
2217 will occur if the instrument is not known).
2218 The data and Tsys are *divided* by the scaling factors.
2219
2220 Parameters:
2221
2222 poly: Polynomial coefficients (default None) to compute a
2223 gain-elevation correction as a function of
2224 elevation (in degrees).
2225
2226 filename: The name of an ascii file holding correction factors.
2227 The first row of the ascii file must give the column
2228 names and these MUST include columns
2229 'ELEVATION' (degrees) and 'FACTOR' (multiply data
2230 by this) somewhere.
2231 The second row must give the data type of the
2232 column. Use 'R' for Real and 'I' for Integer.
2233 An example file would be
2234 (actual factors are arbitrary) :
2235
2236 TIME ELEVATION FACTOR
2237 R R R
2238 0.1 0 0.8
2239 0.2 20 0.85
2240 0.3 40 0.9
2241 0.4 60 0.85
2242 0.5 80 0.8
2243 0.6 90 0.75
2244
2245 method: Interpolation method when correcting from a table.
2246 Values are 'nearest', 'linear' (default), 'cubic'
2247 and 'spline'
2248
2249 insitu: if False a new scantable is returned.
2250 Otherwise, the scaling is done in-situ
2251 The default is taken from .asaprc (False)
2252
2253 """
2254
2255 if insitu is None: insitu = rcParams['insitu']
2256 self._math._setinsitu(insitu)
2257 varlist = vars()
2258 poly = poly or ()
2259 from os.path import expandvars
2260 filename = expandvars(filename)
2261 s = scantable(self._math._gainel(self, poly, filename, method))
2262 s._add_history("gain_el", varlist)
2263 if insitu:
2264 self._assign(s)
2265 else:
2266 return s
2267
2268 @asaplog_post_dec
2269 def freq_align(self, reftime=None, method='cubic', insitu=None):
2270 """\
2271 Return a scan where all rows have been aligned in frequency/velocity.
2272 The alignment frequency frame (e.g. LSRK) is that set by function
2273 set_freqframe.
2274
2275 Parameters:
2276
2277 reftime: reference time to align at. By default, the time of
2278 the first row of data is used.
2279
2280 method: Interpolation method for regridding the spectra.
2281 Choose from 'nearest', 'linear', 'cubic' (default)
2282 and 'spline'
2283
2284 insitu: if False a new scantable is returned.
2285 Otherwise, the scaling is done in-situ
2286 The default is taken from .asaprc (False)
2287
2288 """
2289 if insitu is None: insitu = rcParams["insitu"]
2290 oldInsitu = self._math._insitu()
2291 self._math._setinsitu(insitu)
2292 varlist = vars()
2293 reftime = reftime or ""
2294 s = scantable(self._math._freq_align(self, reftime, method))
2295 s._add_history("freq_align", varlist)
2296 self._math._setinsitu(oldInsitu)
2297 if insitu:
2298 self._assign(s)
2299 else:
2300 return s
2301
2302 @asaplog_post_dec
2303 def opacity(self, tau=None, insitu=None):
2304 """\
2305 Apply an opacity correction. The data
2306 and Tsys are multiplied by the correction factor.
2307
2308 Parameters:
2309
2310 tau: (list of) opacity from which the correction factor is
2311 exp(tau*ZD)
2312 where ZD is the zenith-distance.
2313 If a list is provided, it has to be of length nIF,
2314 nIF*nPol or 1 and in order of IF/POL, e.g.
2315 [opif0pol0, opif0pol1, opif1pol0 ...]
2316 if tau is `None` the opacities are determined from a
2317 model.
2318
2319 insitu: if False a new scantable is returned.
2320 Otherwise, the scaling is done in-situ
2321 The default is taken from .asaprc (False)
2322
2323 """
2324 if insitu is None:
2325 insitu = rcParams['insitu']
2326 self._math._setinsitu(insitu)
2327 varlist = vars()
2328 if not hasattr(tau, "__len__"):
2329 tau = [tau]
2330 s = scantable(self._math._opacity(self, tau))
2331 s._add_history("opacity", varlist)
2332 if insitu:
2333 self._assign(s)
2334 else:
2335 return s
2336
2337 @asaplog_post_dec
2338 def bin(self, width=5, insitu=None):
2339 """\
2340 Return a scan where all spectra have been binned up.
2341
2342 Parameters:
2343
2344 width: The bin width (default=5) in pixels
2345
2346 insitu: if False a new scantable is returned.
2347 Otherwise, the scaling is done in-situ
2348 The default is taken from .asaprc (False)
2349
2350 """
2351 if insitu is None:
2352 insitu = rcParams['insitu']
2353 self._math._setinsitu(insitu)
2354 varlist = vars()
2355 s = scantable(self._math._bin(self, width))
2356 s._add_history("bin", varlist)
2357 if insitu:
2358 self._assign(s)
2359 else:
2360 return s
2361
2362 @asaplog_post_dec
2363 def reshape(self, first, last, insitu=None):
2364 """Resize the band by providing first and last channel.
2365 This will cut off all channels outside [first, last].
2366 """
2367 if insitu is None:
2368 insitu = rcParams['insitu']
2369 varlist = vars()
2370 if last < 0:
2371 last = self.nchan()-1 + last
2372 s = None
2373 if insitu:
2374 s = self
2375 else:
2376 s = self.copy()
2377 s._reshape(first,last)
2378 s._add_history("reshape", varlist)
2379 if not insitu:
2380 return s
2381
2382 @asaplog_post_dec
2383 def resample(self, width=5, method='cubic', insitu=None):
2384 """\
2385 Return a scan where all spectra have been binned up.
2386
2387 Parameters:
2388
2389 width: The bin width (default=5) in pixels
2390
2391 method: Interpolation method when correcting from a table.
2392 Values are 'nearest', 'linear', 'cubic' (default)
2393 and 'spline'
2394
2395 insitu: if False a new scantable is returned.
2396 Otherwise, the scaling is done in-situ
2397 The default is taken from .asaprc (False)
2398
2399 """
2400 if insitu is None:
2401 insitu = rcParams['insitu']
2402 self._math._setinsitu(insitu)
2403 varlist = vars()
2404 s = scantable(self._math._resample(self, method, width))
2405 s._add_history("resample", varlist)
2406 if insitu:
2407 self._assign(s)
2408 else:
2409 return s
2410
2411 @asaplog_post_dec
2412 def average_pol(self, mask=None, weight='none'):
2413 """\
2414 Average the Polarisations together.
2415
2416 Parameters:
2417
2418 mask: An optional mask defining the region, where the
2419 averaging will be applied. The output will have all
2420 specified points masked.
2421
2422 weight: Weighting scheme. 'none' (default), 'var' (1/var(spec)
2423 weighted), or 'tsys' (1/Tsys**2 weighted)
2424
2425 """
2426 varlist = vars()
2427 mask = mask or ()
2428 s = scantable(self._math._averagepol(self, mask, weight.upper()))
2429 s._add_history("average_pol", varlist)
2430 return s
2431
2432 @asaplog_post_dec
2433 def average_beam(self, mask=None, weight='none'):
2434 """\
2435 Average the Beams together.
2436
2437 Parameters:
2438 mask: An optional mask defining the region, where the
2439 averaging will be applied. The output will have all
2440 specified points masked.
2441
2442 weight: Weighting scheme. 'none' (default), 'var' (1/var(spec)
2443 weighted), or 'tsys' (1/Tsys**2 weighted)
2444
2445 """
2446 varlist = vars()
2447 mask = mask or ()
2448 s = scantable(self._math._averagebeams(self, mask, weight.upper()))
2449 s._add_history("average_beam", varlist)
2450 return s
2451
2452 def parallactify(self, pflag):
2453 """\
2454 Set a flag to indicate whether this data should be treated as having
2455 been 'parallactified' (total phase == 0.0)
2456
2457 Parameters:
2458
2459 pflag: Bool indicating whether to turn this on (True) or
2460 off (False)
2461
2462 """
2463 varlist = vars()
2464 self._parallactify(pflag)
2465 self._add_history("parallactify", varlist)
2466
2467 @asaplog_post_dec
2468 def convert_pol(self, poltype=None):
2469 """\
2470 Convert the data to a different polarisation type.
2471 Note that you will need cross-polarisation terms for most conversions.
2472
2473 Parameters:
2474
2475 poltype: The new polarisation type. Valid types are:
2476 'linear', 'circular', 'stokes' and 'linpol'
2477
2478 """
2479 varlist = vars()
2480 s = scantable(self._math._convertpol(self, poltype))
2481 s._add_history("convert_pol", varlist)
2482 return s
2483
2484 @asaplog_post_dec
2485 def smooth(self, kernel="hanning", width=5.0, order=2, plot=False,
2486 insitu=None):
2487 """\
2488 Smooth the spectrum by the specified kernel (conserving flux).
2489
2490 Parameters:
2491
2492 kernel: The type of smoothing kernel. Select from
2493 'hanning' (default), 'gaussian', 'boxcar', 'rmedian'
2494 or 'poly'
2495
2496 width: The width of the kernel in pixels. For hanning this is
2497 ignored otherwise it defauls to 5 pixels.
2498 For 'gaussian' it is the Full Width Half
2499 Maximum. For 'boxcar' it is the full width.
2500 For 'rmedian' and 'poly' it is the half width.
2501
2502 order: Optional parameter for 'poly' kernel (default is 2), to
2503 specify the order of the polnomial. Ignored by all other
2504 kernels.
2505
2506 plot: plot the original and the smoothed spectra.
2507 In this each indivual fit has to be approved, by
2508 typing 'y' or 'n'
2509
2510 insitu: if False a new scantable is returned.
2511 Otherwise, the scaling is done in-situ
2512 The default is taken from .asaprc (False)
2513
2514 """
2515 if insitu is None: insitu = rcParams['insitu']
2516 self._math._setinsitu(insitu)
2517 varlist = vars()
2518
2519 if plot: orgscan = self.copy()
2520
2521 s = scantable(self._math._smooth(self, kernel.lower(), width, order))
2522 s._add_history("smooth", varlist)
2523
2524 action = 'H'
2525 if plot:
2526 from asap.asapplotter import new_asaplot
2527 theplot = new_asaplot(rcParams['plotter.gui'])
2528 from matplotlib import rc as rcp
2529 rcp('lines', linewidth=1)
2530 theplot.set_panels()
2531 ylab=s._get_ordinate_label()
2532 #theplot.palette(0,["#777777","red"])
2533 for r in xrange(s.nrow()):
2534 xsm=s._getabcissa(r)
2535 ysm=s._getspectrum(r)
2536 xorg=orgscan._getabcissa(r)
2537 yorg=orgscan._getspectrum(r)
2538 if action != "N": #skip plotting if rejecting all
2539 theplot.clear()
2540 theplot.hold()
2541 theplot.set_axes('ylabel',ylab)
2542 theplot.set_axes('xlabel',s._getabcissalabel(r))
2543 theplot.set_axes('title',s._getsourcename(r))
2544 theplot.set_line(label='Original',color="#777777")
2545 theplot.plot(xorg,yorg)
2546 theplot.set_line(label='Smoothed',color="red")
2547 theplot.plot(xsm,ysm)
2548 ### Ugly part for legend
2549 for i in [0,1]:
2550 theplot.subplots[0]['lines'].append(
2551 [theplot.subplots[0]['axes'].lines[i]]
2552 )
2553 theplot.release()
2554 ### Ugly part for legend
2555 theplot.subplots[0]['lines']=[]
2556 res = self._get_verify_action("Accept smoothing?",action)
2557 #print "IF%d, POL%d: got result = %s" %(s.getif(r),s.getpol(r),res)
2558 if r == 0: action = None
2559 #res = raw_input("Accept smoothing ([y]/n): ")
2560 if res.upper() == 'N':
2561 # reject for the current rows
2562 s._setspectrum(yorg, r)
2563 elif res.upper() == 'R':
2564 # reject all the following rows
2565 action = "N"
2566 s._setspectrum(yorg, r)
2567 elif res.upper() == 'A':
2568 # accept all the following rows
2569 break
2570 theplot.quit()
2571 del theplot
2572 del orgscan
2573
2574 if insitu: self._assign(s)
2575 else: return s
2576
2577 @asaplog_post_dec
2578 def regrid_channel(self, width=5, plot=False, insitu=None):
2579 """\
2580 Regrid the spectra by the specified channel width
2581
2582 Parameters:
2583
2584 width: The channel width (float) of regridded spectra
2585 in the current spectral unit.
2586
2587 plot: [NOT IMPLEMENTED YET]
2588 plot the original and the regridded spectra.
2589 In this each indivual fit has to be approved, by
2590 typing 'y' or 'n'
2591
2592 insitu: if False a new scantable is returned.
2593 Otherwise, the scaling is done in-situ
2594 The default is taken from .asaprc (False)
2595
2596 """
2597 if insitu is None: insitu = rcParams['insitu']
2598 varlist = vars()
2599
2600 if plot:
2601 asaplog.post()
2602 asaplog.push("Verification plot is not implemtnetd yet.")
2603 asaplog.post("WARN")
2604
2605 s = self.copy()
2606 s._regrid_specchan(width)
2607
2608 s._add_history("regrid_channel", varlist)
2609
2610# if plot:
2611# from asap.asapplotter import new_asaplot
2612# theplot = new_asaplot(rcParams['plotter.gui'])
2613# from matplotlib import rc as rcp
2614# rcp('lines', linewidth=1)
2615# theplot.set_panels()
2616# ylab=s._get_ordinate_label()
2617# #theplot.palette(0,["#777777","red"])
2618# for r in xrange(s.nrow()):
2619# xsm=s._getabcissa(r)
2620# ysm=s._getspectrum(r)
2621# xorg=orgscan._getabcissa(r)
2622# yorg=orgscan._getspectrum(r)
2623# theplot.clear()
2624# theplot.hold()
2625# theplot.set_axes('ylabel',ylab)
2626# theplot.set_axes('xlabel',s._getabcissalabel(r))
2627# theplot.set_axes('title',s._getsourcename(r))
2628# theplot.set_line(label='Original',color="#777777")
2629# theplot.plot(xorg,yorg)
2630# theplot.set_line(label='Smoothed',color="red")
2631# theplot.plot(xsm,ysm)
2632# ### Ugly part for legend
2633# for i in [0,1]:
2634# theplot.subplots[0]['lines'].append(
2635# [theplot.subplots[0]['axes'].lines[i]]
2636# )
2637# theplot.release()
2638# ### Ugly part for legend
2639# theplot.subplots[0]['lines']=[]
2640# res = raw_input("Accept smoothing ([y]/n): ")
2641# if res.upper() == 'N':
2642# s._setspectrum(yorg, r)
2643# theplot.quit()
2644# del theplot
2645# del orgscan
2646
2647 if insitu: self._assign(s)
2648 else: return s
2649
2650 @asaplog_post_dec
2651 def _parse_wn(self, wn):
2652 if isinstance(wn, list) or isinstance(wn, tuple):
2653 return wn
2654 elif isinstance(wn, int):
2655 return [ wn ]
2656 elif isinstance(wn, str):
2657 if '-' in wn: # case 'a-b' : return [a,a+1,...,b-1,b]
2658 val = wn.split('-')
2659 val = [int(val[0]), int(val[1])]
2660 val.sort()
2661 res = [i for i in xrange(val[0], val[1]+1)]
2662 elif wn[:2] == '<=' or wn[:2] == '=<': # cases '<=a','=<a' : return [0,1,...,a-1,a]
2663 val = int(wn[2:])+1
2664 res = [i for i in xrange(val)]
2665 elif wn[-2:] == '>=' or wn[-2:] == '=>': # cases 'a>=','a=>' : return [0,1,...,a-1,a]
2666 val = int(wn[:-2])+1
2667 res = [i for i in xrange(val)]
2668 elif wn[0] == '<': # case '<a' : return [0,1,...,a-2,a-1]
2669 val = int(wn[1:])
2670 res = [i for i in xrange(val)]
2671 elif wn[-1] == '>': # case 'a>' : return [0,1,...,a-2,a-1]
2672 val = int(wn[:-1])
2673 res = [i for i in xrange(val)]
2674 elif wn[:2] == '>=' or wn[:2] == '=>': # cases '>=a','=>a' : return [a,-999], which is
2675 # then interpreted in C++
2676 # side as [a,a+1,...,a_nyq]
2677 # (CAS-3759)
2678 val = int(wn[2:])
2679 res = [val, -999]
2680 #res = [i for i in xrange(val, self.nchan()/2+1)]
2681 elif wn[-2:] == '<=' or wn[-2:] == '=<': # cases 'a<=','a=<' : return [a,-999], which is
2682 # then interpreted in C++
2683 # side as [a,a+1,...,a_nyq]
2684 # (CAS-3759)
2685 val = int(wn[:-2])
2686 res = [val, -999]
2687 #res = [i for i in xrange(val, self.nchan()/2+1)]
2688 elif wn[0] == '>': # case '>a' : return [a+1,-999], which is
2689 # then interpreted in C++
2690 # side as [a+1,a+2,...,a_nyq]
2691 # (CAS-3759)
2692 val = int(wn[1:])+1
2693 res = [val, -999]
2694 #res = [i for i in xrange(val, self.nchan()/2+1)]
2695 elif wn[-1] == '<': # case 'a<' : return [a+1,-999], which is
2696 # then interpreted in C++
2697 # side as [a+1,a+2,...,a_nyq]
2698 # (CAS-3759)
2699 val = int(wn[:-1])+1
2700 res = [val, -999]
2701 #res = [i for i in xrange(val, self.nchan()/2+1)]
2702
2703 return res
2704 else:
2705 msg = 'wrong value given for addwn/rejwn'
2706 raise RuntimeError(msg)
2707
2708 @asaplog_post_dec
2709 def apply_bltable(self, insitu=None, retfitres=None, inbltable=None, outbltable=None, overwrite=None):
2710 """\
2711 Subtract baseline based on parameters written in Baseline Table.
2712
2713 Parameters:
2714 insitu: if True, baseline fitting/subtraction is done
2715 in-situ. If False, a new scantable with
2716 baseline subtracted is returned. Actually,
2717 format of the returned value depends on both
2718 insitu and retfitres (see below).
2719 The default is taken from .asaprc (False)
2720 retfitres: if True, the results of baseline fitting (i.e.,
2721 coefficients and rms) are returned.
2722 default is False.
2723 The format of the returned value of this
2724 function varies as follows:
2725 (1) in case insitu=True and retfitres=True:
2726 fitting result.
2727 (2) in case insitu=True and retfitres=False:
2728 None.
2729 (3) in case insitu=False and retfitres=True:
2730 a dictionary containing a new scantable
2731 (with baseline subtracted) and the fitting
2732 results.
2733 (4) in case insitu=False and retfitres=False:
2734 a new scantable (with baseline subtracted).
2735 inbltable: name of input baseline table. The row number of
2736 scantable and that of inbltable must be
2737 identical.
2738 outbltable: name of output baseline table where baseline
2739 parameters and fitting results recorded.
2740 default is ''(no output).
2741 overwrite: if True when an existing baseline table is
2742 specified for outbltable, overwrites it.
2743 Otherwise there is no harm.
2744 default is False.
2745 """
2746
2747 try:
2748 varlist = vars()
2749 if retfitres is None: retfitres = False
2750 if inbltable is None: raise ValueError("bltable missing.")
2751 if outbltable is None: outbltable = ''
2752 if overwrite is None: overwrite = False
2753
2754 if insitu is None: insitu = rcParams['insitu']
2755 if insitu:
2756 workscan = self
2757 else:
2758 workscan = self.copy()
2759
2760 sres = workscan._apply_bltable(inbltable,
2761 retfitres,
2762 outbltable,
2763 os.path.exists(outbltable),
2764 overwrite)
2765 if retfitres: res = parse_fitresult(sres)
2766
2767 workscan._add_history('apply_bltable', varlist)
2768
2769 if insitu:
2770 self._assign(workscan)
2771 if retfitres:
2772 return res
2773 else:
2774 return None
2775 else:
2776 if retfitres:
2777 return {'scantable': workscan, 'fitresults': res}
2778 else:
2779 return workscan
2780
2781 except RuntimeError, e:
2782 raise_fitting_failure_exception(e)
2783
2784 @asaplog_post_dec
2785 def sub_baseline(self, insitu=None, retfitres=None, blinfo=None, bltable=None, overwrite=None):
2786 """\
2787 Subtract baseline based on parameters written in the input list.
2788
2789 Parameters:
2790 insitu: if True, baseline fitting/subtraction is done
2791 in-situ. If False, a new scantable with
2792 baseline subtracted is returned. Actually,
2793 format of the returned value depends on both
2794 insitu and retfitres (see below).
2795 The default is taken from .asaprc (False)
2796 retfitres: if True, the results of baseline fitting (i.e.,
2797 coefficients and rms) are returned.
2798 default is False.
2799 The format of the returned value of this
2800 function varies as follows:
2801 (1) in case insitu=True and retfitres=True:
2802 fitting result.
2803 (2) in case insitu=True and retfitres=False:
2804 None.
2805 (3) in case insitu=False and retfitres=True:
2806 a dictionary containing a new scantable
2807 (with baseline subtracted) and the fitting
2808 results.
2809 (4) in case insitu=False and retfitres=False:
2810 a new scantable (with baseline subtracted).
2811 blinfo: baseline parameter set stored in a dictionary
2812 or a list of dictionary. Each dictionary
2813 corresponds to each spectrum and must contain
2814 the following keys and values:
2815 'row': row number,
2816 'blfunc': function name. available ones include
2817 'poly', 'chebyshev', 'cspline' and
2818 'sinusoid',
2819 'order': maximum order of polynomial. needed
2820 if blfunc='poly' or 'chebyshev',
2821 'npiece': number or piecewise polynomial.
2822 needed if blfunc='cspline',
2823 'nwave': a list of sinusoidal wave numbers.
2824 needed if blfunc='sinusoid', and
2825 'masklist': min-max windows for channel mask.
2826 the specified ranges will be used
2827 for fitting.
2828 bltable: name of output baseline table where baseline
2829 parameters and fitting results recorded.
2830 default is ''(no output).
2831 overwrite: if True when an existing baseline table is
2832 specified for bltable, overwrites it.
2833 Otherwise there is no harm.
2834 default is False.
2835
2836 Example:
2837 sub_baseline(blinfo=[{'row':0, 'blfunc':'poly', 'order':5,
2838 'masklist':[[10,350],[352,510]]},
2839 {'row':1, 'blfunc':'cspline', 'npiece':3,
2840 'masklist':[[3,16],[19,404],[407,511]]}
2841 ])
2842
2843 the first spectrum (row=0) will be fitted with polynomial
2844 of order=5 and the next one (row=1) will be fitted with cubic
2845 spline consisting of 3 pieces.
2846 """
2847
2848 try:
2849 varlist = vars()
2850 if retfitres is None: retfitres = False
2851 if blinfo is None: blinfo = []
2852 if bltable is None: bltable = ''
2853 if overwrite is None: overwrite = False
2854
2855 if insitu is None: insitu = rcParams['insitu']
2856 if insitu:
2857 workscan = self
2858 else:
2859 workscan = self.copy()
2860
2861 nrow = workscan.nrow()
2862
2863 in_blinfo = pack_blinfo(blinfo=blinfo, maxirow=nrow)
2864
2865 print "in_blinfo=< "+ str(in_blinfo)+" >"
2866
2867 sres = workscan._sub_baseline(in_blinfo,
2868 retfitres,
2869 bltable,
2870 os.path.exists(bltable),
2871 overwrite)
2872 if retfitres: res = parse_fitresult(sres)
2873
2874 workscan._add_history('sub_baseline', varlist)
2875
2876 if insitu:
2877 self._assign(workscan)
2878 if retfitres:
2879 return res
2880 else:
2881 return None
2882 else:
2883 if retfitres:
2884 return {'scantable': workscan, 'fitresults': res}
2885 else:
2886 return workscan
2887
2888 except RuntimeError, e:
2889 raise_fitting_failure_exception(e)
2890
2891 @asaplog_post_dec
2892 def calc_aic(self, value=None, blfunc=None, order=None, mask=None,
2893 whichrow=None, uselinefinder=None, edge=None,
2894 threshold=None, chan_avg_limit=None):
2895 """\
2896 Calculates and returns model selection criteria for a specified
2897 baseline model and a given spectrum data.
2898 Available values include Akaike Information Criterion (AIC), the
2899 corrected Akaike Information Criterion (AICc) by Sugiura(1978),
2900 Bayesian Information Criterion (BIC) and the Generalised Cross
2901 Validation (GCV).
2902
2903 Parameters:
2904 value: name of model selection criteria to calculate.
2905 available ones include 'aic', 'aicc', 'bic' and
2906 'gcv'. default is 'aicc'.
2907 blfunc: baseline function name. available ones include
2908 'chebyshev', 'cspline' and 'sinusoid'.
2909 default is 'chebyshev'.
2910 order: parameter for basline function. actually stands for
2911 order of polynomial (order) for 'chebyshev',
2912 number of spline pieces (npiece) for 'cspline' and
2913 maximum wave number for 'sinusoid', respectively.
2914 default is 5 (which is also the default order value
2915 for [auto_]chebyshev_baseline()).
2916 mask: an optional mask. default is [].
2917 whichrow: row number. default is 0 (the first row)
2918 uselinefinder: use sd.linefinder() to flag out line regions
2919 default is True.
2920 edge: an optional number of channel to drop at
2921 the edge of spectrum. If only one value is
2922 specified, the same number will be dropped
2923 from both sides of the spectrum. Default
2924 is to keep all channels. Nested tuples
2925 represent individual edge selection for
2926 different IFs (a number of spectral channels
2927 can be different)
2928 default is (0, 0).
2929 threshold: the threshold used by line finder. It is
2930 better to keep it large as only strong lines
2931 affect the baseline solution.
2932 default is 3.
2933 chan_avg_limit: a maximum number of consequtive spectral
2934 channels to average during the search of
2935 weak and broad lines. The default is no
2936 averaging (and no search for weak lines).
2937 If such lines can affect the fitted baseline
2938 (e.g. a high order polynomial is fitted),
2939 increase this parameter (usually values up
2940 to 8 are reasonable). Most users of this
2941 method should find the default value sufficient.
2942 default is 1.
2943
2944 Example:
2945 aic = scan.calc_aic(blfunc='chebyshev', order=5, whichrow=0)
2946 """
2947
2948 try:
2949 varlist = vars()
2950
2951 if value is None: value = 'aicc'
2952 if blfunc is None: blfunc = 'chebyshev'
2953 if order is None: order = 5
2954 if mask is None: mask = []
2955 if whichrow is None: whichrow = 0
2956 if uselinefinder is None: uselinefinder = True
2957 if edge is None: edge = (0, 0)
2958 if threshold is None: threshold = 3
2959 if chan_avg_limit is None: chan_avg_limit = 1
2960
2961 return self._calc_aic(value, blfunc, order, mask,
2962 whichrow, uselinefinder, edge,
2963 threshold, chan_avg_limit)
2964
2965 except RuntimeError, e:
2966 raise_fitting_failure_exception(e)
2967
2968 @asaplog_post_dec
2969 def sinusoid_baseline(self, mask=None, applyfft=None,
2970 fftmethod=None, fftthresh=None,
2971 addwn=None, rejwn=None,
2972 insitu=None,
2973 clipthresh=None, clipniter=None,
2974 plot=None,
2975 getresidual=None,
2976 showprogress=None, minnrow=None,
2977 outlog=None,
2978 blfile=None, csvformat=None,
2979 bltable=None):
2980 """\
2981 Return a scan which has been baselined (all rows) with sinusoidal
2982 functions.
2983
2984 Parameters:
2985 mask: an optional mask
2986 applyfft: if True use some method, such as FFT, to find
2987 strongest sinusoidal components in the wavenumber
2988 domain to be used for baseline fitting.
2989 default is True.
2990 fftmethod: method to find the strong sinusoidal components.
2991 now only 'fft' is available and it is the default.
2992 fftthresh: the threshold to select wave numbers to be used for
2993 fitting from the distribution of amplitudes in the
2994 wavenumber domain.
2995 both float and string values accepted.
2996 given a float value, the unit is set to sigma.
2997 for string values, allowed formats include:
2998 'xsigma' or 'x' (= x-sigma level. e.g.,
2999 '3sigma'), or
3000 'topx' (= the x strongest ones, e.g. 'top5').
3001 default is 3.0 (unit: sigma).
3002 addwn: the additional wave numbers to be used for fitting.
3003 list or integer value is accepted to specify every
3004 wave numbers. also string value can be used in case
3005 you need to specify wave numbers in a certain range,
3006 e.g., 'a-b' (= a, a+1, a+2, ..., b-1, b),
3007 '<a' (= 0,1,...,a-2,a-1),
3008 '>=a' (= a, a+1, ... up to the maximum wave
3009 number corresponding to the Nyquist
3010 frequency for the case of FFT).
3011 default is [0].
3012 rejwn: the wave numbers NOT to be used for fitting.
3013 can be set just as addwn but has higher priority:
3014 wave numbers which are specified both in addwn
3015 and rejwn will NOT be used. default is [].
3016 insitu: if False a new scantable is returned.
3017 Otherwise, the scaling is done in-situ
3018 The default is taken from .asaprc (False)
3019 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
3020 clipniter: maximum number of iteration of 'clipthresh'-sigma
3021 clipping (default is 0)
3022 plot: *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3023 plot the fit and the residual. In this each
3024 indivual fit has to be approved, by typing 'y'
3025 or 'n'
3026 getresidual: if False, returns best-fit values instead of
3027 residual. (default is True)
3028 showprogress: show progress status for large data.
3029 default is True.
3030 minnrow: minimum number of input spectra to show.
3031 default is 1000.
3032 outlog: Output the coefficients of the best-fit
3033 function to logger (default is False)
3034 blfile: Name of a text file in which the best-fit
3035 parameter values to be written
3036 (default is '': no file/logger output)
3037 csvformat: if True blfile is csv-formatted, default is False.
3038 bltable: name of a baseline table where fitting results
3039 (coefficients, rms, etc.) are to be written.
3040 if given, fitting results will NOT be output to
3041 scantable (insitu=True) or None will be
3042 returned (insitu=False).
3043 (default is "": no table output)
3044
3045 Example:
3046 # return a scan baselined by a combination of sinusoidal curves
3047 # having wave numbers in spectral window up to 10,
3048 # also with 3-sigma clipping, iteration up to 4 times
3049 bscan = scan.sinusoid_baseline(addwn='<=10',clipthresh=3.0,clipniter=4)
3050
3051 Note:
3052 The best-fit parameter values output in logger and/or blfile are now
3053 based on specunit of 'channel'.
3054 """
3055
3056 try:
3057 varlist = vars()
3058
3059 if insitu is None: insitu = rcParams['insitu']
3060 if insitu:
3061 workscan = self
3062 else:
3063 workscan = self.copy()
3064
3065 if mask is None: mask = []
3066 if applyfft is None: applyfft = True
3067 if fftmethod is None: fftmethod = 'fft'
3068 if fftthresh is None: fftthresh = 3.0
3069 if addwn is None: addwn = [0]
3070 if rejwn is None: rejwn = []
3071 if clipthresh is None: clipthresh = 3.0
3072 if clipniter is None: clipniter = 0
3073 if plot is None: plot = False
3074 if getresidual is None: getresidual = True
3075 if showprogress is None: showprogress = True
3076 if minnrow is None: minnrow = 1000
3077 if outlog is None: outlog = False
3078 if blfile is None: blfile = ''
3079 if csvformat is None: csvformat = False
3080 if bltable is None: bltable = ''
3081
3082 sapplyfft = 'true' if applyfft else 'false'
3083 fftinfo = ','.join([sapplyfft, fftmethod.lower(), str(fftthresh).lower()])
3084
3085 scsvformat = 'T' if csvformat else 'F'
3086
3087 #CURRENTLY, PLOT=true is UNAVAILABLE UNTIL sinusoidal fitting is implemented as a fitter method.
3088 workscan._sinusoid_baseline(mask,
3089 fftinfo,
3090 #applyfft, fftmethod.lower(),
3091 #str(fftthresh).lower(),
3092 workscan._parse_wn(addwn),
3093 workscan._parse_wn(rejwn),
3094 clipthresh, clipniter,
3095 getresidual,
3096 pack_progress_params(showprogress,
3097 minnrow),
3098 outlog, scsvformat+blfile,
3099 bltable)
3100 workscan._add_history('sinusoid_baseline', varlist)
3101
3102 if bltable == '':
3103 if insitu:
3104 self._assign(workscan)
3105 else:
3106 return workscan
3107 else:
3108 if not insitu:
3109 return None
3110
3111 except RuntimeError, e:
3112 raise_fitting_failure_exception(e)
3113
3114
3115 @asaplog_post_dec
3116 def auto_sinusoid_baseline(self, mask=None, applyfft=None,
3117 fftmethod=None, fftthresh=None,
3118 addwn=None, rejwn=None,
3119 insitu=None,
3120 clipthresh=None, clipniter=None,
3121 edge=None, threshold=None, chan_avg_limit=None,
3122 plot=None,
3123 getresidual=None,
3124 showprogress=None, minnrow=None,
3125 outlog=None,
3126 blfile=None, csvformat=None,
3127 bltable=None):
3128 """\
3129 Return a scan which has been baselined (all rows) with sinusoidal
3130 functions.
3131 Spectral lines are detected first using linefinder and masked out
3132 to avoid them affecting the baseline solution.
3133
3134 Parameters:
3135 mask: an optional mask retreived from scantable
3136 applyfft: if True use some method, such as FFT, to find
3137 strongest sinusoidal components in the wavenumber
3138 domain to be used for baseline fitting.
3139 default is True.
3140 fftmethod: method to find the strong sinusoidal components.
3141 now only 'fft' is available and it is the default.
3142 fftthresh: the threshold to select wave numbers to be used for
3143 fitting from the distribution of amplitudes in the
3144 wavenumber domain.
3145 both float and string values accepted.
3146 given a float value, the unit is set to sigma.
3147 for string values, allowed formats include:
3148 'xsigma' or 'x' (= x-sigma level. e.g.,
3149 '3sigma'), or
3150 'topx' (= the x strongest ones, e.g. 'top5').
3151 default is 3.0 (unit: sigma).
3152 addwn: the additional wave numbers to be used for fitting.
3153 list or integer value is accepted to specify every
3154 wave numbers. also string value can be used in case
3155 you need to specify wave numbers in a certain range,
3156 e.g., 'a-b' (= a, a+1, a+2, ..., b-1, b),
3157 '<a' (= 0,1,...,a-2,a-1),
3158 '>=a' (= a, a+1, ... up to the maximum wave
3159 number corresponding to the Nyquist
3160 frequency for the case of FFT).
3161 default is [0].
3162 rejwn: the wave numbers NOT to be used for fitting.
3163 can be set just as addwn but has higher priority:
3164 wave numbers which are specified both in addwn
3165 and rejwn will NOT be used. default is [].
3166 insitu: if False a new scantable is returned.
3167 Otherwise, the scaling is done in-situ
3168 The default is taken from .asaprc (False)
3169 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
3170 clipniter: maximum number of iteration of 'clipthresh'-sigma
3171 clipping (default is 0)
3172 edge: an optional number of channel to drop at
3173 the edge of spectrum. If only one value is
3174 specified, the same number will be dropped
3175 from both sides of the spectrum. Default
3176 is to keep all channels. Nested tuples
3177 represent individual edge selection for
3178 different IFs (a number of spectral channels
3179 can be different)
3180 threshold: the threshold used by line finder. It is
3181 better to keep it large as only strong lines
3182 affect the baseline solution.
3183 chan_avg_limit: a maximum number of consequtive spectral
3184 channels to average during the search of
3185 weak and broad lines. The default is no
3186 averaging (and no search for weak lines).
3187 If such lines can affect the fitted baseline
3188 (e.g. a high order polynomial is fitted),
3189 increase this parameter (usually values up
3190 to 8 are reasonable). Most users of this
3191 method should find the default value sufficient.
3192 plot: *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3193 plot the fit and the residual. In this each
3194 indivual fit has to be approved, by typing 'y'
3195 or 'n'
3196 getresidual: if False, returns best-fit values instead of
3197 residual. (default is True)
3198 showprogress: show progress status for large data.
3199 default is True.
3200 minnrow: minimum number of input spectra to show.
3201 default is 1000.
3202 outlog: Output the coefficients of the best-fit
3203 function to logger (default is False)
3204 blfile: Name of a text file in which the best-fit
3205 parameter values to be written
3206 (default is "": no file/logger output)
3207 csvformat: if True blfile is csv-formatted, default is False.
3208 bltable: name of a baseline table where fitting results
3209 (coefficients, rms, etc.) are to be written.
3210 if given, fitting results will NOT be output to
3211 scantable (insitu=True) or None will be
3212 returned (insitu=False).
3213 (default is "": no table output)
3214
3215 Example:
3216 bscan = scan.auto_sinusoid_baseline(addwn='<=10', insitu=False)
3217
3218 Note:
3219 The best-fit parameter values output in logger and/or blfile are now
3220 based on specunit of 'channel'.
3221 """
3222
3223 try:
3224 varlist = vars()
3225
3226 if insitu is None: insitu = rcParams['insitu']
3227 if insitu:
3228 workscan = self
3229 else:
3230 workscan = self.copy()
3231
3232 if mask is None: mask = []
3233 if applyfft is None: applyfft = True
3234 if fftmethod is None: fftmethod = 'fft'
3235 if fftthresh is None: fftthresh = 3.0
3236 if addwn is None: addwn = [0]
3237 if rejwn is None: rejwn = []
3238 if clipthresh is None: clipthresh = 3.0
3239 if clipniter is None: clipniter = 0
3240 if edge is None: edge = (0,0)
3241 if threshold is None: threshold = 3
3242 if chan_avg_limit is None: chan_avg_limit = 1
3243 if plot is None: plot = False
3244 if getresidual is None: getresidual = True
3245 if showprogress is None: showprogress = True
3246 if minnrow is None: minnrow = 1000
3247 if outlog is None: outlog = False
3248 if blfile is None: blfile = ''
3249 if csvformat is None: csvformat = False
3250 if bltable is None: bltable = ''
3251
3252 sapplyfft = 'true' if applyfft else 'false'
3253 fftinfo = ','.join([sapplyfft, fftmethod.lower(), str(fftthresh).lower()])
3254
3255 scsvformat = 'T' if csvformat else 'F'
3256
3257 #CURRENTLY, PLOT=true is UNAVAILABLE UNTIL sinusoidal fitting is implemented as a fitter method.
3258 workscan._auto_sinusoid_baseline(mask,
3259 fftinfo,
3260 workscan._parse_wn(addwn),
3261 workscan._parse_wn(rejwn),
3262 clipthresh, clipniter,
3263 normalise_edge_param(edge),
3264 threshold, chan_avg_limit,
3265 getresidual,
3266 pack_progress_params(showprogress,
3267 minnrow),
3268 outlog, scsvformat+blfile, bltable)
3269 workscan._add_history("auto_sinusoid_baseline", varlist)
3270
3271 if bltable == '':
3272 if insitu:
3273 self._assign(workscan)
3274 else:
3275 return workscan
3276 else:
3277 if not insitu:
3278 return None
3279
3280 except RuntimeError, e:
3281 raise_fitting_failure_exception(e)
3282
3283 @asaplog_post_dec
3284 def cspline_baseline(self, mask=None, npiece=None, insitu=None,
3285 clipthresh=None, clipniter=None, plot=None,
3286 getresidual=None, showprogress=None, minnrow=None,
3287 outlog=None, blfile=None, csvformat=None,
3288 bltable=None):
3289 """\
3290 Return a scan which has been baselined (all rows) by cubic spline
3291 function (piecewise cubic polynomial).
3292
3293 Parameters:
3294 mask: An optional mask
3295 npiece: Number of pieces. (default is 2)
3296 insitu: If False a new scantable is returned.
3297 Otherwise, the scaling is done in-situ
3298 The default is taken from .asaprc (False)
3299 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
3300 clipniter: maximum number of iteration of 'clipthresh'-sigma
3301 clipping (default is 0)
3302 plot: *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3303 plot the fit and the residual. In this each
3304 indivual fit has to be approved, by typing 'y'
3305 or 'n'
3306 getresidual: if False, returns best-fit values instead of
3307 residual. (default is True)
3308 showprogress: show progress status for large data.
3309 default is True.
3310 minnrow: minimum number of input spectra to show.
3311 default is 1000.
3312 outlog: Output the coefficients of the best-fit
3313 function to logger (default is False)
3314 blfile: Name of a text file in which the best-fit
3315 parameter values to be written
3316 (default is "": no file/logger output)
3317 csvformat: if True blfile is csv-formatted, default is False.
3318 bltable: name of a baseline table where fitting results
3319 (coefficients, rms, etc.) are to be written.
3320 if given, fitting results will NOT be output to
3321 scantable (insitu=True) or None will be
3322 returned (insitu=False).
3323 (default is "": no table output)
3324
3325 Example:
3326 # return a scan baselined by a cubic spline consisting of 2 pieces
3327 # (i.e., 1 internal knot),
3328 # also with 3-sigma clipping, iteration up to 4 times
3329 bscan = scan.cspline_baseline(npiece=2,clipthresh=3.0,clipniter=4)
3330
3331 Note:
3332 The best-fit parameter values output in logger and/or blfile are now
3333 based on specunit of 'channel'.
3334 """
3335
3336 try:
3337 varlist = vars()
3338
3339 if insitu is None: insitu = rcParams['insitu']
3340 if insitu:
3341 workscan = self
3342 else:
3343 workscan = self.copy()
3344
3345 if mask is None: mask = []
3346 if npiece is None: npiece = 2
3347 if clipthresh is None: clipthresh = 3.0
3348 if clipniter is None: clipniter = 0
3349 if plot is None: plot = False
3350 if getresidual is None: getresidual = True
3351 if showprogress is None: showprogress = True
3352 if minnrow is None: minnrow = 1000
3353 if outlog is None: outlog = False
3354 if blfile is None: blfile = ''
3355 if csvformat is None: csvformat = False
3356 if bltable is None: bltable = ''
3357
3358 scsvformat = 'T' if csvformat else 'F'
3359
3360 #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
3361 workscan._cspline_baseline(mask, npiece,
3362 clipthresh, clipniter,
3363 getresidual,
3364 pack_progress_params(showprogress,
3365 minnrow),
3366 outlog, scsvformat+blfile,
3367 bltable)
3368 workscan._add_history("cspline_baseline", varlist)
3369
3370 if bltable == '':
3371 if insitu:
3372 self._assign(workscan)
3373 else:
3374 return workscan
3375 else:
3376 if not insitu:
3377 return None
3378
3379 except RuntimeError, e:
3380 raise_fitting_failure_exception(e)
3381
3382 @asaplog_post_dec
3383 def auto_cspline_baseline(self, mask=None, npiece=None, insitu=None,
3384 clipthresh=None, clipniter=None,
3385 edge=None, threshold=None, chan_avg_limit=None,
3386 getresidual=None, plot=None,
3387 showprogress=None, minnrow=None, outlog=None,
3388 blfile=None, csvformat=None, bltable=None):
3389 """\
3390 Return a scan which has been baselined (all rows) by cubic spline
3391 function (piecewise cubic polynomial).
3392 Spectral lines are detected first using linefinder and masked out
3393 to avoid them affecting the baseline solution.
3394
3395 Parameters:
3396 mask: an optional mask retreived from scantable
3397 npiece: Number of pieces. (default is 2)
3398 insitu: if False a new scantable is returned.
3399 Otherwise, the scaling is done in-situ
3400 The default is taken from .asaprc (False)
3401 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
3402 clipniter: maximum number of iteration of 'clipthresh'-sigma
3403 clipping (default is 0)
3404 edge: an optional number of channel to drop at
3405 the edge of spectrum. If only one value is
3406 specified, the same number will be dropped
3407 from both sides of the spectrum. Default
3408 is to keep all channels. Nested tuples
3409 represent individual edge selection for
3410 different IFs (a number of spectral channels
3411 can be different)
3412 threshold: the threshold used by line finder. It is
3413 better to keep it large as only strong lines
3414 affect the baseline solution.
3415 chan_avg_limit: a maximum number of consequtive spectral
3416 channels to average during the search of
3417 weak and broad lines. The default is no
3418 averaging (and no search for weak lines).
3419 If such lines can affect the fitted baseline
3420 (e.g. a high order polynomial is fitted),
3421 increase this parameter (usually values up
3422 to 8 are reasonable). Most users of this
3423 method should find the default value sufficient.
3424 plot: *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3425 plot the fit and the residual. In this each
3426 indivual fit has to be approved, by typing 'y'
3427 or 'n'
3428 getresidual: if False, returns best-fit values instead of
3429 residual. (default is True)
3430 showprogress: show progress status for large data.
3431 default is True.
3432 minnrow: minimum number of input spectra to show.
3433 default is 1000.
3434 outlog: Output the coefficients of the best-fit
3435 function to logger (default is False)
3436 blfile: Name of a text file in which the best-fit
3437 parameter values to be written
3438 (default is "": no file/logger output)
3439 csvformat: if True blfile is csv-formatted, default is False.
3440 bltable: name of a baseline table where fitting results
3441 (coefficients, rms, etc.) are to be written.
3442 if given, fitting results will NOT be output to
3443 scantable (insitu=True) or None will be
3444 returned (insitu=False).
3445 (default is "": no table output)
3446
3447 Example:
3448 bscan = scan.auto_cspline_baseline(npiece=3, insitu=False)
3449
3450 Note:
3451 The best-fit parameter values output in logger and/or blfile are now
3452 based on specunit of 'channel'.
3453 """
3454
3455 try:
3456 varlist = vars()
3457
3458 if insitu is None: insitu = rcParams['insitu']
3459 if insitu:
3460 workscan = self
3461 else:
3462 workscan = self.copy()
3463
3464 #if mask is None: mask = [True for i in xrange(workscan.nchan())]
3465 if mask is None: mask = []
3466 if npiece is None: npiece = 2
3467 if clipthresh is None: clipthresh = 3.0
3468 if clipniter is None: clipniter = 0
3469 if edge is None: edge = (0, 0)
3470 if threshold is None: threshold = 3
3471 if chan_avg_limit is None: chan_avg_limit = 1
3472 if plot is None: plot = False
3473 if getresidual is None: getresidual = True
3474 if showprogress is None: showprogress = True
3475 if minnrow is None: minnrow = 1000
3476 if outlog is None: outlog = False
3477 if blfile is None: blfile = ''
3478 if csvformat is None: csvformat = False
3479 if bltable is None: bltable = ''
3480
3481 scsvformat = 'T' if csvformat else 'F'
3482
3483 #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
3484 workscan._auto_cspline_baseline(mask, npiece,
3485 clipthresh, clipniter,
3486 normalise_edge_param(edge),
3487 threshold,
3488 chan_avg_limit, getresidual,
3489 pack_progress_params(showprogress,
3490 minnrow),
3491 outlog,
3492 scsvformat+blfile,
3493 bltable)
3494 workscan._add_history("auto_cspline_baseline", varlist)
3495
3496 if bltable == '':
3497 if insitu:
3498 self._assign(workscan)
3499 else:
3500 return workscan
3501 else:
3502 if not insitu:
3503 return None
3504
3505 except RuntimeError, e:
3506 raise_fitting_failure_exception(e)
3507
3508 @asaplog_post_dec
3509 def chebyshev_baseline(self, mask=None, order=None, insitu=None,
3510 clipthresh=None, clipniter=None, plot=None,
3511 getresidual=None, showprogress=None, minnrow=None,
3512 outlog=None, blfile=None, csvformat=None,
3513 bltable=None):
3514 """\
3515 Return a scan which has been baselined (all rows) by Chebyshev polynomials.
3516
3517 Parameters:
3518 mask: An optional mask
3519 order: the maximum order of Chebyshev polynomial (default is 5)
3520 insitu: If False a new scantable is returned.
3521 Otherwise, the scaling is done in-situ
3522 The default is taken from .asaprc (False)
3523 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
3524 clipniter: maximum number of iteration of 'clipthresh'-sigma
3525 clipping (default is 0)
3526 plot: *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3527 plot the fit and the residual. In this each
3528 indivual fit has to be approved, by typing 'y'
3529 or 'n'
3530 getresidual: if False, returns best-fit values instead of
3531 residual. (default is True)
3532 showprogress: show progress status for large data.
3533 default is True.
3534 minnrow: minimum number of input spectra to show.
3535 default is 1000.
3536 outlog: Output the coefficients of the best-fit
3537 function to logger (default is False)
3538 blfile: Name of a text file in which the best-fit
3539 parameter values to be written
3540 (default is "": no file/logger output)
3541 csvformat: if True blfile is csv-formatted, default is False.
3542 bltable: name of a baseline table where fitting results
3543 (coefficients, rms, etc.) are to be written.
3544 if given, fitting results will NOT be output to
3545 scantable (insitu=True) or None will be
3546 returned (insitu=False).
3547 (default is "": no table output)
3548
3549 Example:
3550 # return a scan baselined by a cubic spline consisting of 2 pieces
3551 # (i.e., 1 internal knot),
3552 # also with 3-sigma clipping, iteration up to 4 times
3553 bscan = scan.cspline_baseline(npiece=2,clipthresh=3.0,clipniter=4)
3554
3555 Note:
3556 The best-fit parameter values output in logger and/or blfile are now
3557 based on specunit of 'channel'.
3558 """
3559
3560 try:
3561 varlist = vars()
3562
3563 if insitu is None: insitu = rcParams['insitu']
3564 if insitu:
3565 workscan = self
3566 else:
3567 workscan = self.copy()
3568
3569 if mask is None: mask = []
3570 if order is None: order = 5
3571 if clipthresh is None: clipthresh = 3.0
3572 if clipniter is None: clipniter = 0
3573 if plot is None: plot = False
3574 if getresidual is None: getresidual = True
3575 if showprogress is None: showprogress = True
3576 if minnrow is None: minnrow = 1000
3577 if outlog is None: outlog = False
3578 if blfile is None: blfile = ''
3579 if csvformat is None: csvformat = False
3580 if bltable is None: bltable = ''
3581
3582 scsvformat = 'T' if csvformat else 'F'
3583
3584 #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
3585 workscan._chebyshev_baseline(mask, order,
3586 clipthresh, clipniter,
3587 getresidual,
3588 pack_progress_params(showprogress,
3589 minnrow),
3590 outlog, scsvformat+blfile,
3591 bltable)
3592 workscan._add_history("chebyshev_baseline", varlist)
3593
3594 if bltable == '':
3595 if insitu:
3596 self._assign(workscan)
3597 else:
3598 return workscan
3599 else:
3600 if not insitu:
3601 return None
3602
3603 except RuntimeError, e:
3604 raise_fitting_failure_exception(e)
3605
3606 @asaplog_post_dec
3607 def auto_chebyshev_baseline(self, mask=None, order=None, insitu=None,
3608 clipthresh=None, clipniter=None,
3609 edge=None, threshold=None, chan_avg_limit=None,
3610 getresidual=None, plot=None,
3611 showprogress=None, minnrow=None, outlog=None,
3612 blfile=None, csvformat=None, bltable=None):
3613 """\
3614 Return a scan which has been baselined (all rows) by Chebyshev polynomials.
3615 Spectral lines are detected first using linefinder and masked out
3616 to avoid them affecting the baseline solution.
3617
3618 Parameters:
3619 mask: an optional mask retreived from scantable
3620 order: the maximum order of Chebyshev polynomial (default is 5)
3621 insitu: if False a new scantable is returned.
3622 Otherwise, the scaling is done in-situ
3623 The default is taken from .asaprc (False)
3624 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
3625 clipniter: maximum number of iteration of 'clipthresh'-sigma
3626 clipping (default is 0)
3627 edge: an optional number of channel to drop at
3628 the edge of spectrum. If only one value is
3629 specified, the same number will be dropped
3630 from both sides of the spectrum. Default
3631 is to keep all channels. Nested tuples
3632 represent individual edge selection for
3633 different IFs (a number of spectral channels
3634 can be different)
3635 threshold: the threshold used by line finder. It is
3636 better to keep it large as only strong lines
3637 affect the baseline solution.
3638 chan_avg_limit: a maximum number of consequtive spectral
3639 channels to average during the search of
3640 weak and broad lines. The default is no
3641 averaging (and no search for weak lines).
3642 If such lines can affect the fitted baseline
3643 (e.g. a high order polynomial is fitted),
3644 increase this parameter (usually values up
3645 to 8 are reasonable). Most users of this
3646 method should find the default value sufficient.
3647 plot: *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3648 plot the fit and the residual. In this each
3649 indivual fit has to be approved, by typing 'y'
3650 or 'n'
3651 getresidual: if False, returns best-fit values instead of
3652 residual. (default is True)
3653 showprogress: show progress status for large data.
3654 default is True.
3655 minnrow: minimum number of input spectra to show.
3656 default is 1000.
3657 outlog: Output the coefficients of the best-fit
3658 function to logger (default is False)
3659 blfile: Name of a text file in which the best-fit
3660 parameter values to be written
3661 (default is "": no file/logger output)
3662 csvformat: if True blfile is csv-formatted, default is False.
3663 bltable: name of a baseline table where fitting results
3664 (coefficients, rms, etc.) are to be written.
3665 if given, fitting results will NOT be output to
3666 scantable (insitu=True) or None will be
3667 returned (insitu=False).
3668 (default is "": no table output)
3669
3670 Example:
3671 bscan = scan.auto_cspline_baseline(npiece=3, insitu=False)
3672
3673 Note:
3674 The best-fit parameter values output in logger and/or blfile are now
3675 based on specunit of 'channel'.
3676 """
3677
3678 try:
3679 varlist = vars()
3680
3681 if insitu is None: insitu = rcParams['insitu']
3682 if insitu:
3683 workscan = self
3684 else:
3685 workscan = self.copy()
3686
3687 if mask is None: mask = []
3688 if order is None: order = 5
3689 if clipthresh is None: clipthresh = 3.0
3690 if clipniter is None: clipniter = 0
3691 if edge is None: edge = (0, 0)
3692 if threshold is None: threshold = 3
3693 if chan_avg_limit is None: chan_avg_limit = 1
3694 if plot is None: plot = False
3695 if getresidual is None: getresidual = True
3696 if showprogress is None: showprogress = True
3697 if minnrow is None: minnrow = 1000
3698 if outlog is None: outlog = False
3699 if blfile is None: blfile = ''
3700 if csvformat is None: csvformat = False
3701 if bltable is None: bltable = ''
3702
3703 scsvformat = 'T' if csvformat else 'F'
3704
3705 #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
3706 workscan._auto_chebyshev_baseline(mask, order,
3707 clipthresh, clipniter,
3708 normalise_edge_param(edge),
3709 threshold,
3710 chan_avg_limit, getresidual,
3711 pack_progress_params(showprogress,
3712 minnrow),
3713 outlog, scsvformat+blfile,
3714 bltable)
3715 workscan._add_history("auto_chebyshev_baseline", varlist)
3716
3717 if bltable == '':
3718 if insitu:
3719 self._assign(workscan)
3720 else:
3721 return workscan
3722 else:
3723 if not insitu:
3724 return None
3725
3726 except RuntimeError, e:
3727 raise_fitting_failure_exception(e)
3728
3729 @asaplog_post_dec
3730 def poly_baseline(self, mask=None, order=None, insitu=None,
3731 clipthresh=None, clipniter=None, plot=None,
3732 getresidual=None, showprogress=None, minnrow=None,
3733 outlog=None, blfile=None, csvformat=None,
3734 bltable=None):
3735 """\
3736 Return a scan which has been baselined (all rows) by a polynomial.
3737 Parameters:
3738 mask: an optional mask
3739 order: the order of the polynomial (default is 0)
3740 insitu: if False a new scantable is returned.
3741 Otherwise, the scaling is done in-situ
3742 The default is taken from .asaprc (False)
3743 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
3744 clipniter: maximum number of iteration of 'clipthresh'-sigma
3745 clipping (default is 0)
3746 plot: plot the fit and the residual. In this each
3747 indivual fit has to be approved, by typing 'y'
3748 or 'n'
3749 getresidual: if False, returns best-fit values instead of
3750 residual. (default is True)
3751 showprogress: show progress status for large data.
3752 default is True.
3753 minnrow: minimum number of input spectra to show.
3754 default is 1000.
3755 outlog: Output the coefficients of the best-fit
3756 function to logger (default is False)
3757 blfile: Name of a text file in which the best-fit
3758 parameter values to be written
3759 (default is "": no file/logger output)
3760 csvformat: if True blfile is csv-formatted, default is False.
3761 bltable: name of a baseline table where fitting results
3762 (coefficients, rms, etc.) are to be written.
3763 if given, fitting results will NOT be output to
3764 scantable (insitu=True) or None will be
3765 returned (insitu=False).
3766 (default is "": no table output)
3767
3768 Example:
3769 # return a scan baselined by a third order polynomial,
3770 # not using a mask
3771 bscan = scan.poly_baseline(order=3)
3772 """
3773
3774 try:
3775 varlist = vars()
3776
3777 if insitu is None:
3778 insitu = rcParams["insitu"]
3779 if insitu:
3780 workscan = self
3781 else:
3782 workscan = self.copy()
3783
3784 if mask is None: mask = []
3785 if order is None: order = 0
3786 if clipthresh is None: clipthresh = 3.0
3787 if clipniter is None: clipniter = 0
3788 if plot is None: plot = False
3789 if getresidual is None: getresidual = True
3790 if showprogress is None: showprogress = True
3791 if minnrow is None: minnrow = 1000
3792 if outlog is None: outlog = False
3793 if blfile is None: blfile = ''
3794 if csvformat is None: csvformat = False
3795 if bltable is None: bltable = ''
3796
3797 scsvformat = 'T' if csvformat else 'F'
3798
3799 if plot:
3800 outblfile = (blfile != "") and \
3801 os.path.exists(os.path.expanduser(
3802 os.path.expandvars(blfile))
3803 )
3804 if outblfile:
3805 blf = open(blfile, "a")
3806
3807 f = fitter()
3808 f.set_function(lpoly=order)
3809
3810 rows = xrange(workscan.nrow())
3811 #if len(rows) > 0: workscan._init_blinfo()
3812
3813 action = "H"
3814 for r in rows:
3815 f.x = workscan._getabcissa(r)
3816 f.y = workscan._getspectrum(r)
3817 if mask:
3818 f.mask = mask_and(mask, workscan._getmask(r)) # (CAS-1434)
3819 else: # mask=None
3820 f.mask = workscan._getmask(r)
3821
3822 f.data = None
3823 f.fit()
3824
3825 if action != "Y": # skip plotting when accepting all
3826 f.plot(residual=True)
3827 #accept_fit = raw_input("Accept fit ( [y]/n ): ")
3828 #if accept_fit.upper() == "N":
3829 # #workscan._append_blinfo(None, None, None)
3830 # continue
3831 accept_fit = self._get_verify_action("Accept fit?",action)
3832 if r == 0: action = None
3833 if accept_fit.upper() == "N":
3834 continue
3835 elif accept_fit.upper() == "R":
3836 break
3837 elif accept_fit.upper() == "A":
3838 action = "Y"
3839
3840 blpars = f.get_parameters()
3841 masklist = workscan.get_masklist(f.mask, row=r, silent=True)
3842 #workscan._append_blinfo(blpars, masklist, f.mask)
3843 workscan._setspectrum((f.fitter.getresidual()
3844 if getresidual else f.fitter.getfit()), r)
3845
3846 if outblfile:
3847 rms = workscan.get_rms(f.mask, r)
3848 dataout = \
3849 workscan.format_blparams_row(blpars["params"],
3850 blpars["fixed"],
3851 rms, str(masklist),
3852 r, True, csvformat)
3853 blf.write(dataout)
3854
3855 f._p.unmap()
3856 f._p = None
3857
3858 if outblfile:
3859 blf.close()
3860 else:
3861 workscan._poly_baseline(mask, order,
3862 clipthresh, clipniter, #
3863 getresidual,
3864 pack_progress_params(showprogress,
3865 minnrow),
3866 outlog, scsvformat+blfile,
3867 bltable) #
3868
3869 workscan._add_history("poly_baseline", varlist)
3870
3871 if insitu:
3872 self._assign(workscan)
3873 else:
3874 return workscan
3875
3876 except RuntimeError, e:
3877 raise_fitting_failure_exception(e)
3878
3879 @asaplog_post_dec
3880 def auto_poly_baseline(self, mask=None, order=None, insitu=None,
3881 clipthresh=None, clipniter=None,
3882 edge=None, threshold=None, chan_avg_limit=None,
3883 getresidual=None, plot=None,
3884 showprogress=None, minnrow=None, outlog=None,
3885 blfile=None, csvformat=None, bltable=None):
3886 """\
3887 Return a scan which has been baselined (all rows) by a polynomial.
3888 Spectral lines are detected first using linefinder and masked out
3889 to avoid them affecting the baseline solution.
3890
3891 Parameters:
3892 mask: an optional mask retreived from scantable
3893 order: the order of the polynomial (default is 0)
3894 insitu: if False a new scantable is returned.
3895 Otherwise, the scaling is done in-situ
3896 The default is taken from .asaprc (False)
3897 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
3898 clipniter: maximum number of iteration of 'clipthresh'-sigma
3899 clipping (default is 0)
3900 edge: an optional number of channel to drop at
3901 the edge of spectrum. If only one value is
3902 specified, the same number will be dropped
3903 from both sides of the spectrum. Default
3904 is to keep all channels. Nested tuples
3905 represent individual edge selection for
3906 different IFs (a number of spectral channels
3907 can be different)
3908 threshold: the threshold used by line finder. It is
3909 better to keep it large as only strong lines
3910 affect the baseline solution.
3911 chan_avg_limit: a maximum number of consequtive spectral
3912 channels to average during the search of
3913 weak and broad lines. The default is no
3914 averaging (and no search for weak lines).
3915 If such lines can affect the fitted baseline
3916 (e.g. a high order polynomial is fitted),
3917 increase this parameter (usually values up
3918 to 8 are reasonable). Most users of this
3919 method should find the default value sufficient.
3920 plot: plot the fit and the residual. In this each
3921 indivual fit has to be approved, by typing 'y'
3922 or 'n'
3923 getresidual: if False, returns best-fit values instead of
3924 residual. (default is True)
3925 showprogress: show progress status for large data.
3926 default is True.
3927 minnrow: minimum number of input spectra to show.
3928 default is 1000.
3929 outlog: Output the coefficients of the best-fit
3930 function to logger (default is False)
3931 blfile: Name of a text file in which the best-fit
3932 parameter values to be written
3933 (default is "": no file/logger output)
3934 csvformat: if True blfile is csv-formatted, default is False.
3935 bltable: name of a baseline table where fitting results
3936 (coefficients, rms, etc.) are to be written.
3937 if given, fitting results will NOT be output to
3938 scantable (insitu=True) or None will be
3939 returned (insitu=False).
3940 (default is "": no table output)
3941
3942 Example:
3943 bscan = scan.auto_poly_baseline(order=7, insitu=False)
3944 """
3945
3946 try:
3947 varlist = vars()
3948
3949 if insitu is None:
3950 insitu = rcParams['insitu']
3951 if insitu:
3952 workscan = self
3953 else:
3954 workscan = self.copy()
3955
3956 if mask is None: mask = []
3957 if order is None: order = 0
3958 if clipthresh is None: clipthresh = 3.0
3959 if clipniter is None: clipniter = 0
3960 if edge is None: edge = (0, 0)
3961 if threshold is None: threshold = 3
3962 if chan_avg_limit is None: chan_avg_limit = 1
3963 if plot is None: plot = False
3964 if getresidual is None: getresidual = True
3965 if showprogress is None: showprogress = True
3966 if minnrow is None: minnrow = 1000
3967 if outlog is None: outlog = False
3968 if blfile is None: blfile = ''
3969 if csvformat is None: csvformat = False
3970 if bltable is None: bltable = ''
3971
3972 scsvformat = 'T' if csvformat else 'F'
3973
3974 edge = normalise_edge_param(edge)
3975
3976 if plot:
3977 outblfile = (blfile != "") and \
3978 os.path.exists(os.path.expanduser(os.path.expandvars(blfile)))
3979 if outblfile: blf = open(blfile, "a")
3980
3981 from asap.asaplinefind import linefinder
3982 fl = linefinder()
3983 fl.set_options(threshold=threshold, avg_limit=chan_avg_limit)
3984 fl.set_scan(workscan)
3985
3986 f = fitter()
3987 f.set_function(lpoly=order)
3988
3989 rows = xrange(workscan.nrow())
3990 #if len(rows) > 0: workscan._init_blinfo()
3991
3992 action = "H"
3993 for r in rows:
3994 idx = 2*workscan.getif(r)
3995 if mask:
3996 msk = mask_and(mask, workscan._getmask(r)) # (CAS-1434)
3997 else: # mask=None
3998 msk = workscan._getmask(r)
3999 fl.find_lines(r, msk, edge[idx:idx+2])
4000
4001 f.x = workscan._getabcissa(r)
4002 f.y = workscan._getspectrum(r)
4003 f.mask = fl.get_mask()
4004 f.data = None
4005 f.fit()
4006
4007 if action != "Y": # skip plotting when accepting all
4008 f.plot(residual=True)
4009 #accept_fit = raw_input("Accept fit ( [y]/n ): ")
4010 accept_fit = self._get_verify_action("Accept fit?",action)
4011 if r == 0: action = None
4012 if accept_fit.upper() == "N":
4013 #workscan._append_blinfo(None, None, None)
4014 continue
4015 elif accept_fit.upper() == "R":
4016 break
4017 elif accept_fit.upper() == "A":
4018 action = "Y"
4019
4020 blpars = f.get_parameters()
4021 masklist = workscan.get_masklist(f.mask, row=r, silent=True)
4022 #workscan._append_blinfo(blpars, masklist, f.mask)
4023 workscan._setspectrum(
4024 (f.fitter.getresidual() if getresidual
4025 else f.fitter.getfit()), r
4026 )
4027
4028 if outblfile:
4029 rms = workscan.get_rms(f.mask, r)
4030 dataout = \
4031 workscan.format_blparams_row(blpars["params"],
4032 blpars["fixed"],
4033 rms, str(masklist),
4034 r, True, csvformat)
4035 blf.write(dataout)
4036
4037 f._p.unmap()
4038 f._p = None
4039
4040 if outblfile: blf.close()
4041 else:
4042 workscan._auto_poly_baseline(mask, order,
4043 clipthresh, clipniter,
4044 edge, threshold,
4045 chan_avg_limit, getresidual,
4046 pack_progress_params(showprogress,
4047 minnrow),
4048 outlog, scsvformat+blfile,
4049 bltable)
4050 workscan._add_history("auto_poly_baseline", varlist)
4051
4052 if bltable == '':
4053 if insitu:
4054 self._assign(workscan)
4055 else:
4056 return workscan
4057 else:
4058 if not insitu:
4059 return None
4060
4061 except RuntimeError, e:
4062 raise_fitting_failure_exception(e)
4063
4064 def _init_blinfo(self):
4065 """\
4066 Initialise the following three auxiliary members:
4067 blpars : parameters of the best-fit baseline,
4068 masklists : mask data (edge positions of masked channels) and
4069 actualmask : mask data (in boolean list),
4070 to keep for use later (including output to logger/text files).
4071 Used by poly_baseline() and auto_poly_baseline() in case of
4072 'plot=True'.
4073 """
4074 self.blpars = []
4075 self.masklists = []
4076 self.actualmask = []
4077 return
4078
4079 def _append_blinfo(self, data_blpars, data_masklists, data_actualmask):
4080 """\
4081 Append baseline-fitting related info to blpars, masklist and
4082 actualmask.
4083 """
4084 self.blpars.append(data_blpars)
4085 self.masklists.append(data_masklists)
4086 self.actualmask.append(data_actualmask)
4087 return
4088
4089 @asaplog_post_dec
4090 def rotate_linpolphase(self, angle):
4091 """\
4092 Rotate the phase of the complex polarization O=Q+iU correlation.
4093 This is always done in situ in the raw data. So if you call this
4094 function more than once then each call rotates the phase further.
4095
4096 Parameters:
4097
4098 angle: The angle (degrees) to rotate (add) by.
4099
4100 Example::
4101
4102 scan.rotate_linpolphase(2.3)
4103
4104 """
4105 varlist = vars()
4106 self._math._rotate_linpolphase(self, angle)
4107 self._add_history("rotate_linpolphase", varlist)
4108 return
4109
4110 @asaplog_post_dec
4111 def rotate_xyphase(self, angle):
4112 """\
4113 Rotate the phase of the XY correlation. This is always done in situ
4114 in the data. So if you call this function more than once
4115 then each call rotates the phase further.
4116
4117 Parameters:
4118
4119 angle: The angle (degrees) to rotate (add) by.
4120
4121 Example::
4122
4123 scan.rotate_xyphase(2.3)
4124
4125 """
4126 varlist = vars()
4127 self._math._rotate_xyphase(self, angle)
4128 self._add_history("rotate_xyphase", varlist)
4129 return
4130
4131 @asaplog_post_dec
4132 def swap_linears(self):
4133 """\
4134 Swap the linear polarisations XX and YY, or better the first two
4135 polarisations as this also works for ciculars.
4136 """
4137 varlist = vars()
4138 self._math._swap_linears(self)
4139 self._add_history("swap_linears", varlist)
4140 return
4141
4142 @asaplog_post_dec
4143 def invert_phase(self):
4144 """\
4145 Invert the phase of the complex polarisation
4146 """
4147 varlist = vars()
4148 self._math._invert_phase(self)
4149 self._add_history("invert_phase", varlist)
4150 return
4151
4152 @asaplog_post_dec
4153 def add(self, offset, insitu=None):
4154 """\
4155 Return a scan where all spectra have the offset added
4156
4157 Parameters:
4158
4159 offset: the offset
4160
4161 insitu: if False a new scantable is returned.
4162 Otherwise, the scaling is done in-situ
4163 The default is taken from .asaprc (False)
4164
4165 """
4166 if insitu is None: insitu = rcParams['insitu']
4167 self._math._setinsitu(insitu)
4168 varlist = vars()
4169 s = scantable(self._math._unaryop(self, offset, "ADD", False))
4170 s._add_history("add", varlist)
4171 if insitu:
4172 self._assign(s)
4173 else:
4174 return s
4175
4176 @asaplog_post_dec
4177 def scale(self, factor, tsys=True, insitu=None):
4178 """\
4179
4180 Return a scan where all spectra are scaled by the given 'factor'
4181
4182 Parameters:
4183
4184 factor: the scaling factor (float or 1D float list)
4185
4186 insitu: if False a new scantable is returned.
4187 Otherwise, the scaling is done in-situ
4188 The default is taken from .asaprc (False)
4189
4190 tsys: if True (default) then apply the operation to Tsys
4191 as well as the data
4192
4193 """
4194 if insitu is None: insitu = rcParams['insitu']
4195 self._math._setinsitu(insitu)
4196 varlist = vars()
4197 s = None
4198 import numpy
4199 if isinstance(factor, list) or isinstance(factor, numpy.ndarray):
4200 if isinstance(factor[0], list) or isinstance(factor[0],
4201 numpy.ndarray):
4202 from asapmath import _array2dOp
4203 s = _array2dOp( self, factor, "MUL", tsys, insitu )
4204 else:
4205 s = scantable( self._math._arrayop( self, factor,
4206 "MUL", tsys ) )
4207 else:
4208 s = scantable(self._math._unaryop(self, factor, "MUL", tsys))
4209 s._add_history("scale", varlist)
4210 if insitu:
4211 self._assign(s)
4212 else:
4213 return s
4214
4215 @preserve_selection
4216 def set_sourcetype(self, match, matchtype="pattern",
4217 sourcetype="reference"):
4218 """\
4219 Set the type of the source to be an source or reference scan
4220 using the provided pattern.
4221
4222 Parameters:
4223
4224 match: a Unix style pattern, regular expression or selector
4225
4226 matchtype: 'pattern' (default) UNIX style pattern or
4227 'regex' regular expression
4228
4229 sourcetype: the type of the source to use (source/reference)
4230
4231 """
4232 varlist = vars()
4233 stype = -1
4234 if sourcetype.lower().startswith("r") or sourcetype.lower() == "off":
4235 stype = 1
4236 elif sourcetype.lower().startswith("s") or sourcetype.lower() == "on":
4237 stype = 0
4238 else:
4239 raise ValueError("Illegal sourcetype use s(ource)/on or r(eference)/off")
4240 if matchtype.lower().startswith("p"):
4241 matchtype = "pattern"
4242 elif matchtype.lower().startswith("r"):
4243 matchtype = "regex"
4244 else:
4245 raise ValueError("Illegal matchtype, use p(attern) or r(egex)")
4246 sel = selector()
4247 if isinstance(match, selector):
4248 sel = match
4249 else:
4250 sel.set_query("SRCNAME=%s('%s')" % (matchtype, match))
4251 self.set_selection(sel)
4252 self._setsourcetype(stype)
4253 self._add_history("set_sourcetype", varlist)
4254
4255
4256 def set_sourcename(self, name):
4257 varlist = vars()
4258 self._setsourcename(name)
4259 self._add_history("set_sourcename", varlist)
4260
4261 @asaplog_post_dec
4262 @preserve_selection
4263 def auto_quotient(self, preserve=True, mode='paired', verify=False):
4264 """\
4265 This function allows to build quotients automatically.
4266 It assumes the observation to have the same number of
4267 "ons" and "offs"
4268
4269 Parameters:
4270
4271 preserve: you can preserve (default) the continuum or
4272 remove it. The equations used are
4273
4274 preserve: Output = Toff * (on/off) - Toff
4275
4276 remove: Output = Toff * (on/off) - Ton
4277
4278 mode: the on/off detection mode
4279 'paired' (default)
4280 identifies 'off' scans by the
4281 trailing '_R' (Mopra/Parkes) or
4282 '_e'/'_w' (Tid) and matches
4283 on/off pairs from the observing pattern
4284 'time'
4285 finds the closest off in time
4286
4287 .. todo:: verify argument is not implemented
4288
4289 """
4290 varlist = vars()
4291 modes = ["time", "paired"]
4292 if not mode in modes:
4293 msg = "please provide valid mode. Valid modes are %s" % (modes)
4294 raise ValueError(msg)
4295 s = None
4296 if mode.lower() == "paired":
4297 sel = self.get_selection()
4298 sel.set_query("SRCTYPE==psoff")
4299 self.set_selection(sel)
4300 offs = self.copy()
4301 sel.set_query("SRCTYPE==pson")
4302 self.set_selection(sel)
4303 ons = self.copy()
4304 s = scantable(self._math._quotient(ons, offs, preserve))
4305 elif mode.lower() == "time":
4306 s = scantable(self._math._auto_quotient(self, mode, preserve))
4307 s._add_history("auto_quotient", varlist)
4308 return s
4309
4310 @asaplog_post_dec
4311 def mx_quotient(self, mask = None, weight='median', preserve=True):
4312 """\
4313 Form a quotient using "off" beams when observing in "MX" mode.
4314
4315 Parameters:
4316
4317 mask: an optional mask to be used when weight == 'stddev'
4318
4319 weight: How to average the off beams. Default is 'median'.
4320
4321 preserve: you can preserve (default) the continuum or
4322 remove it. The equations used are:
4323
4324 preserve: Output = Toff * (on/off) - Toff
4325
4326 remove: Output = Toff * (on/off) - Ton
4327
4328 """
4329 mask = mask or ()
4330 varlist = vars()
4331 on = scantable(self._math._mx_extract(self, 'on'))
4332 preoff = scantable(self._math._mx_extract(self, 'off'))
4333 off = preoff.average_time(mask=mask, weight=weight, scanav=False)
4334 from asapmath import quotient
4335 q = quotient(on, off, preserve)
4336 q._add_history("mx_quotient", varlist)
4337 return q
4338
4339 @asaplog_post_dec
4340 def freq_switch(self, insitu=None):
4341 """\
4342 Apply frequency switching to the data.
4343
4344 Parameters:
4345
4346 insitu: if False a new scantable is returned.
4347 Otherwise, the swictching is done in-situ
4348 The default is taken from .asaprc (False)
4349
4350 """
4351 if insitu is None: insitu = rcParams['insitu']
4352 self._math._setinsitu(insitu)
4353 varlist = vars()
4354 s = scantable(self._math._freqswitch(self))
4355 s._add_history("freq_switch", varlist)
4356 if insitu:
4357 self._assign(s)
4358 else:
4359 return s
4360
4361 @asaplog_post_dec
4362 def recalc_azel(self):
4363 """Recalculate the azimuth and elevation for each position."""
4364 varlist = vars()
4365 self._recalcazel()
4366 self._add_history("recalc_azel", varlist)
4367 return
4368
4369 @asaplog_post_dec
4370 def __add__(self, other):
4371 """
4372 implicit on all axes and on Tsys
4373 """
4374 varlist = vars()
4375 s = self.__op( other, "ADD" )
4376 s._add_history("operator +", varlist)
4377 return s
4378
4379 @asaplog_post_dec
4380 def __sub__(self, other):
4381 """
4382 implicit on all axes and on Tsys
4383 """
4384 varlist = vars()
4385 s = self.__op( other, "SUB" )
4386 s._add_history("operator -", varlist)
4387 return s
4388
4389 @asaplog_post_dec
4390 def __mul__(self, other):
4391 """
4392 implicit on all axes and on Tsys
4393 """
4394 varlist = vars()
4395 s = self.__op( other, "MUL" ) ;
4396 s._add_history("operator *", varlist)
4397 return s
4398
4399
4400 @asaplog_post_dec
4401 def __div__(self, other):
4402 """
4403 implicit on all axes and on Tsys
4404 """
4405 varlist = vars()
4406 s = self.__op( other, "DIV" )
4407 s._add_history("operator /", varlist)
4408 return s
4409
4410 @asaplog_post_dec
4411 def __op( self, other, mode ):
4412 s = None
4413 if isinstance(other, scantable):
4414 s = scantable(self._math._binaryop(self, other, mode))
4415 elif isinstance(other, float):
4416 if other == 0.0:
4417 raise ZeroDivisionError("Dividing by zero is not recommended")
4418 s = scantable(self._math._unaryop(self, other, mode, False))
4419 elif isinstance(other, list) or isinstance(other, numpy.ndarray):
4420 if isinstance(other[0], list) \
4421 or isinstance(other[0], numpy.ndarray):
4422 from asapmath import _array2dOp
4423 s = _array2dOp( self, other, mode, False )
4424 else:
4425 s = scantable( self._math._arrayop( self, other,
4426 mode, False ) )
4427 else:
4428 raise TypeError("Other input is not a scantable or float value")
4429 return s
4430
4431 @asaplog_post_dec
4432 def get_fit(self, row=0):
4433 """\
4434 Print or return the stored fits for a row in the scantable
4435
4436 Parameters:
4437
4438 row: the row which the fit has been applied to.
4439
4440 """
4441 if row > self.nrow():
4442 return
4443 from asap.asapfit import asapfit
4444 fit = asapfit(self._getfit(row))
4445 asaplog.push( '%s' %(fit) )
4446 return fit.as_dict()
4447
4448 @preserve_selection
4449 def flag_nans(self):
4450 """\
4451 Utility function to flag NaN values in the scantable.
4452 """
4453 import numpy
4454 basesel = self.get_selection()
4455 for i in range(self.nrow()):
4456 sel = self.get_row_selector(i)
4457 self.set_selection(basesel+sel)
4458 nans = numpy.isnan(self._getspectrum(0))
4459 if numpy.any(nans):
4460 bnans = [ bool(v) for v in nans]
4461 self.flag(bnans)
4462
4463 def get_row_selector(self, rowno):
4464 return selector(rows=[rowno])
4465
4466 def _add_history(self, funcname, parameters):
4467 if not rcParams['scantable.history']:
4468 return
4469 # create date
4470 sep = "##"
4471 from datetime import datetime
4472 dstr = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
4473 hist = dstr+sep
4474 hist += funcname+sep#cdate+sep
4475 if parameters.has_key('self'):
4476 del parameters['self']
4477 for k, v in parameters.iteritems():
4478 if type(v) is dict:
4479 for k2, v2 in v.iteritems():
4480 hist += k2
4481 hist += "="
4482 if isinstance(v2, scantable):
4483 hist += 'scantable'
4484 elif k2 == 'mask':
4485 if isinstance(v2, list) or isinstance(v2, tuple):
4486 hist += str(self._zip_mask(v2))
4487 else:
4488 hist += str(v2)
4489 else:
4490 hist += str(v2)
4491 else:
4492 hist += k
4493 hist += "="
4494 if isinstance(v, scantable):
4495 hist += 'scantable'
4496 elif k == 'mask':
4497 if isinstance(v, list) or isinstance(v, tuple):
4498 hist += str(self._zip_mask(v))
4499 else:
4500 hist += str(v)
4501 else:
4502 hist += str(v)
4503 hist += sep
4504 hist = hist[:-2] # remove trailing '##'
4505 self._addhistory(hist)
4506
4507
4508 def _zip_mask(self, mask):
4509 mask = list(mask)
4510 i = 0
4511 segments = []
4512 while mask[i:].count(1):
4513 i += mask[i:].index(1)
4514 if mask[i:].count(0):
4515 j = i + mask[i:].index(0)
4516 else:
4517 j = len(mask)
4518 segments.append([i, j])
4519 i = j
4520 return segments
4521
4522 def _get_ordinate_label(self):
4523 fu = "("+self.get_fluxunit()+")"
4524 import re
4525 lbl = "Intensity"
4526 if re.match(".K.", fu):
4527 lbl = "Brightness Temperature "+ fu
4528 elif re.match(".Jy.", fu):
4529 lbl = "Flux density "+ fu
4530 return lbl
4531
4532 def _check_ifs(self):
4533# return len(set([self.nchan(i) for i in self.getifnos()])) == 1
4534 nchans = [self.nchan(i) for i in self.getifnos()]
4535 nchans = filter(lambda t: t > 0, nchans)
4536 return (sum(nchans)/len(nchans) == nchans[0])
4537
4538 @asaplog_post_dec
4539 def _fill(self, names, unit, average, opts={}):
4540 first = True
4541 fullnames = []
4542 for name in names:
4543 name = os.path.expandvars(name)
4544 name = os.path.expanduser(name)
4545 if not os.path.exists(name):
4546 msg = "File '%s' does not exists" % (name)
4547 raise IOError(msg)
4548 fullnames.append(name)
4549 if average:
4550 asaplog.push('Auto averaging integrations')
4551 stype = int(rcParams['scantable.storage'].lower() == 'disk')
4552 for name in fullnames:
4553 tbl = Scantable(stype)
4554 if is_ms( name ):
4555 r = msfiller( tbl )
4556 else:
4557 r = filler( tbl )
4558 msg = "Importing %s..." % (name)
4559 asaplog.push(msg, False)
4560 r.open(name, opts)
4561 rx = rcParams['scantable.reference']
4562 r.setreferenceexpr(rx)
4563 r.fill()
4564 if average:
4565 tbl = self._math._average((tbl, ), (), 'NONE', 'SCAN')
4566 if not first:
4567 tbl = self._math._merge([self, tbl])
4568 Scantable.__init__(self, tbl)
4569 r.close()
4570 del r, tbl
4571 first = False
4572 #flush log
4573 asaplog.post()
4574 if unit is not None:
4575 self.set_fluxunit(unit)
4576 if not is_casapy():
4577 self.set_freqframe(rcParams['scantable.freqframe'])
4578
4579 def _get_verify_action( self, msg, action=None ):
4580 valid_act = ['Y', 'N', 'A', 'R']
4581 if not action or not isinstance(action, str):
4582 action = raw_input("%s [Y/n/a/r] (h for help): " % msg)
4583 if action == '':
4584 return "Y"
4585 elif (action.upper()[0] in valid_act):
4586 return action.upper()[0]
4587 elif (action.upper()[0] in ['H','?']):
4588 print "Available actions of verification [Y|n|a|r]"
4589 print " Y : Yes for current data (default)"
4590 print " N : No for current data"
4591 print " A : Accept all in the following and exit from verification"
4592 print " R : Reject all in the following and exit from verification"
4593 print " H or ?: help (show this message)"
4594 return self._get_verify_action(msg)
4595 else:
4596 return 'Y'
4597
4598 def __getitem__(self, key):
4599 if key < 0:
4600 key += self.nrow()
4601 if key >= self.nrow():
4602 raise IndexError("Row index out of range.")
4603 return self._getspectrum(key)
4604
4605 def __setitem__(self, key, value):
4606 if key < 0:
4607 key += self.nrow()
4608 if key >= self.nrow():
4609 raise IndexError("Row index out of range.")
4610 if not hasattr(value, "__len__") or \
4611 len(value) > self.nchan(self.getif(key)):
4612 raise ValueError("Spectrum length doesn't match.")
4613 return self._setspectrum(value, key)
4614
4615 def __len__(self):
4616 return self.nrow()
4617
4618 def __iter__(self):
4619 for i in range(len(self)):
4620 yield self[i]
Note: See TracBrowser for help on using the repository browser.