source: trunk/python/scantable.py@ 2775

Last change on this file since 2775 was 2771, checked in by WataruKawasaki, 12 years ago

New Development: No

JIRA Issue: No

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s): sd.scantable

Description: argument order change in baselining functions: mask at first, and order at second (for poly).


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