source: trunk/python/scantable.py@ 2767

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

New Development: Yes

JIRA Issue: Yes CAS-4794

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s): sd

Description: functions to apply/write STBaselineTable in which baseline parameters stored.


  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 178.1 KB
Line 
1"""This module defines the scantable class."""
2
3import os
4import re
5import tempfile
6import numpy
7try:
8 from functools import wraps as wraps_dec
9except ImportError:
10 from asap.compatibility import wraps as wraps_dec
11
12from asap.env import is_casapy
13from asap._asap import Scantable
14from asap._asap import filler, msfiller
15from asap.parameters import rcParams
16from asap.logging import asaplog, asaplog_post_dec
17from asap.selector import selector
18from asap.linecatalog import linecatalog
19from asap.coordinate import coordinate
20from asap.utils import _n_bools, mask_not, mask_and, mask_or, page
21from asap.asapfitter import fitter
22
23def preserve_selection(func):
24 @wraps_dec(func)
25 def wrap(obj, *args, **kw):
26 basesel = obj.get_selection()
27 try:
28 val = func(obj, *args, **kw)
29 finally:
30 obj.set_selection(basesel)
31 return val
32 return wrap
33
34def is_scantable(filename):
35 """Is the given file a scantable?
36
37 Parameters:
38
39 filename: the name of the file/directory to test
40
41 """
42 if ( os.path.isdir(filename)
43 and os.path.exists(filename+'/table.info')
44 and os.path.exists(filename+'/table.dat') ):
45 f=open(filename+'/table.info')
46 l=f.readline()
47 f.close()
48 match_pattern = '^Type = (Scantable)? *$'
49 if re.match(match_pattern,l):
50 return True
51 else:
52 return False
53 else:
54 return False
55## return (os.path.isdir(filename)
56## and not os.path.exists(filename+'/table.f1')
57## and os.path.exists(filename+'/table.info'))
58
59def is_ms(filename):
60 """Is the given file a MeasurementSet?
61
62 Parameters:
63
64 filename: the name of the file/directory to test
65
66 """
67 if ( os.path.isdir(filename)
68 and os.path.exists(filename+'/table.info')
69 and os.path.exists(filename+'/table.dat') ):
70 f=open(filename+'/table.info')
71 l=f.readline()
72 f.close()
73 if ( l.find('Measurement Set') != -1 ):
74 return True
75 else:
76 return False
77 else:
78 return False
79
80def normalise_edge_param(edge):
81 """\
82 Convert a given edge value to a one-dimensional array that can be
83 given to baseline-fitting/subtraction functions.
84 The length of the output value will be an even because values for
85 the both sides of spectra are to be contained for each IF. When
86 the length is 2, the values will be applied to all IFs. If the length
87 is larger than 2, it will be 2*ifnos().
88 Accepted format of edge include:
89 * an integer - will be used for both sides of spectra of all IFs.
90 e.g. 10 is converted to [10,10]
91 * an empty list/tuple [] - converted to [0, 0] and used for all IFs.
92 * a list/tuple containing an integer - same as the above case.
93 e.g. [10] is converted to [10,10]
94 * a list/tuple containing two integers - will be used for all IFs.
95 e.g. [5,10] is output as it is. no need to convert.
96 * a list/tuple of lists/tuples containing TWO integers -
97 each element of edge will be used for each IF.
98 e.g. [[5,10],[15,20]] - [5,10] for IF[0] and [15,20] for IF[1].
99
100 If an element contains the same integer values, the input 'edge'
101 parameter can be given in a simpler shape in the following cases:
102 ** when len(edge)!=2
103 any elements containing the same values can be replaced
104 to single integers.
105 e.g. [[15,15]] can be simplified to [15] (or [15,15] or 15 also).
106 e.g. [[1,1],[2,2],[3,3]] can be simplified to [1,2,3].
107 ** when len(edge)=2
108 care is needed for this case: ONLY ONE of the
109 elements can be a single integer,
110 e.g. [[5,5],[10,10]] can be simplified to [5,[10,10]]
111 or [[5,5],10], but can NOT be simplified to [5,10].
112 when [5,10] given, it is interpreted as
113 [[5,10],[5,10],[5,10],...] instead, as shown before.
114 """
115 from asap import _is_sequence_or_number as _is_valid
116 if isinstance(edge, list) or isinstance(edge, tuple):
117 for edgepar in edge:
118 if not _is_valid(edgepar, int):
119 raise ValueError, "Each element of the 'edge' tuple has \
120 to be a pair of integers or an integer."
121 if isinstance(edgepar, list) or isinstance(edgepar, tuple):
122 if len(edgepar) != 2:
123 raise ValueError, "Each element of the 'edge' tuple has \
124 to be a pair of integers or an integer."
125 else:
126 if not _is_valid(edge, int):
127 raise ValueError, "Parameter 'edge' has to be an integer or a \
128 pair of integers specified as a tuple. \
129 Nested tuples are allowed \
130 to make individual selection for different IFs."
131
132
133 if isinstance(edge, int):
134 edge = [ edge, edge ] # e.g. 3 => [3,3]
135 elif isinstance(edge, list) or isinstance(edge, tuple):
136 if len(edge) == 0:
137 edge = [0, 0] # e.g. [] => [0,0]
138 elif len(edge) == 1:
139 if isinstance(edge[0], int):
140 edge = [ edge[0], edge[0] ] # e.g. [1] => [1,1]
141
142 commonedge = True
143 if len(edge) > 2: commonedge = False
144 else:
145 for edgepar in edge:
146 if isinstance(edgepar, list) or isinstance(edgepar, tuple):
147 commonedge = False
148 break
149
150 if commonedge:
151 if len(edge) > 1:
152 norm_edge = edge
153 else:
154 norm_edge = edge + edge
155 else:
156 norm_edge = []
157 for edgepar in edge:
158 if isinstance(edgepar, int):
159 norm_edge += [edgepar, edgepar]
160 else:
161 norm_edge += edgepar
162
163 return norm_edge
164
165def raise_fitting_failure_exception(e):
166 msg = "The fit failed, possibly because it didn't converge."
167 if rcParams["verbose"]:
168 asaplog.push(str(e))
169 asaplog.push(str(msg))
170 else:
171 raise RuntimeError(str(e)+'\n'+msg)
172
173def pack_progress_params(showprogress, minnrow):
174 return str(showprogress).lower() + ',' + str(minnrow)
175
176def pack_blinfo(blinfo, maxirow):
177 """\
178 convert a dictionary or a list of dictionaries of baseline info
179 into a list of comma-separated strings.
180 """
181 if isinstance(blinfo, dict):
182 res = do_pack_blinfo(blinfo, maxirow)
183 return [res] if res != '' else []
184 elif isinstance(blinfo, list) or isinstance(blinfo, tuple):
185 res = []
186 for i in xrange(len(blinfo)):
187 resi = do_pack_blinfo(blinfo[i], maxirow)
188 if resi != '':
189 res.append(resi)
190 return res
191
192def do_pack_blinfo(blinfo, maxirow):
193 """\
194 convert a dictionary of baseline info for a spectrum into
195 a comma-separated string.
196 """
197 dinfo = {}
198 for key in ['row', 'blfunc', 'masklist']:
199 if blinfo.has_key(key):
200 val = blinfo[key]
201 if key == 'row':
202 irow = val
203 if isinstance(val, list) or isinstance(val, tuple):
204 slval = []
205 for i in xrange(len(val)):
206 if isinstance(val[i], list) or isinstance(val[i], tuple):
207 for j in xrange(len(val[i])):
208 slval.append(str(val[i][j]))
209 else:
210 slval.append(str(val[i]))
211 sval = ",".join(slval)
212 else:
213 sval = str(val)
214
215 dinfo[key] = sval
216 else:
217 raise ValueError("'"+key+"' is missing in blinfo.")
218
219 if irow >= maxirow: return ''
220
221 for key in ['order', 'npiece', 'nwave']:
222 if blinfo.has_key(key):
223 val = blinfo[key]
224 if isinstance(val, list) or isinstance(val, tuple):
225 slval = []
226 for i in xrange(len(val)):
227 slval.append(str(val[i]))
228 sval = ",".join(slval)
229 else:
230 sval = str(val)
231 dinfo[key] = sval
232
233 blfunc = dinfo['blfunc']
234 fspec_keys = {'poly': 'order', 'chebyshev': 'order', 'cspline': 'npiece', 'sinusoid': 'nwave'}
235
236 fspec_key = fspec_keys[blfunc]
237 if not blinfo.has_key(fspec_key):
238 raise ValueError("'"+fspec_key+"' is missing in blinfo.")
239
240 clip_params_n = 0
241 for key in ['clipthresh', 'clipniter']:
242 if blinfo.has_key(key):
243 clip_params_n += 1
244 dinfo[key] = str(blinfo[key])
245
246 if clip_params_n == 0:
247 dinfo['clipthresh'] = '0.0'
248 dinfo['clipniter'] = '0'
249 elif clip_params_n != 2:
250 raise ValueError("both 'clipthresh' and 'clipniter' must be given for n-sigma clipping.")
251
252 lf_params_n = 0
253 for key in ['thresh', 'edge', 'chan_avg_limit']:
254 if blinfo.has_key(key):
255 lf_params_n += 1
256 val = blinfo[key]
257 if isinstance(val, list) or isinstance(val, tuple):
258 slval = []
259 for i in xrange(len(val)):
260 slval.append(str(val[i]))
261 sval = ",".join(slval)
262 else:
263 sval = str(val)
264 dinfo[key] = sval
265
266 if lf_params_n == 3:
267 dinfo['use_linefinder'] = 'true'
268 elif lf_params_n == 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, insitu=None, mask=None, applyfft=None,
2892 fftmethod=None, fftthresh=None,
2893 addwn=None, rejwn=None, clipthresh=None,
2894 clipniter=None, plot=None,
2895 getresidual=None, showprogress=None,
2896 minnrow=None, outlog=None,
2897 blfile=None, csvformat=None,
2898 bltable=None):
2899 """\
2900 Return a scan which has been baselined (all rows) with sinusoidal
2901 functions.
2902
2903 Parameters:
2904 insitu: if False a new scantable is returned.
2905 Otherwise, the scaling is done in-situ
2906 The default is taken from .asaprc (False)
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 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
2939 clipniter: maximum number of iteration of 'clipthresh'-sigma
2940 clipping (default is 0)
2941 plot: *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
2942 plot the fit and the residual. In this each
2943 indivual fit has to be approved, by typing 'y'
2944 or 'n'
2945 getresidual: if False, returns best-fit values instead of
2946 residual. (default is True)
2947 showprogress: show progress status for large data.
2948 default is True.
2949 minnrow: minimum number of input spectra to show.
2950 default is 1000.
2951 outlog: Output the coefficients of the best-fit
2952 function to logger (default is False)
2953 blfile: Name of a text file in which the best-fit
2954 parameter values to be written
2955 (default is '': no file/logger output)
2956 csvformat: if True blfile is csv-formatted, default is False.
2957 bltable: name of a baseline table where fitting results
2958 (coefficients, rms, etc.) are to be written.
2959 if given, fitting results will NOT be output to
2960 scantable (insitu=True) or None will be
2961 returned (insitu=False).
2962 (default is "": no table output)
2963
2964 Example:
2965 # return a scan baselined by a combination of sinusoidal curves
2966 # having wave numbers in spectral window up to 10,
2967 # also with 3-sigma clipping, iteration up to 4 times
2968 bscan = scan.sinusoid_baseline(addwn='<=10',clipthresh=3.0,clipniter=4)
2969
2970 Note:
2971 The best-fit parameter values output in logger and/or blfile are now
2972 based on specunit of 'channel'.
2973 """
2974
2975 try:
2976 varlist = vars()
2977
2978 if insitu is None: insitu = rcParams['insitu']
2979 if insitu:
2980 workscan = self
2981 else:
2982 workscan = self.copy()
2983
2984 #if mask is None: mask = [True for i in xrange(workscan.nchan())]
2985 if mask is None: mask = []
2986 if applyfft is None: applyfft = True
2987 if fftmethod is None: fftmethod = 'fft'
2988 if fftthresh is None: fftthresh = 3.0
2989 if addwn is None: addwn = [0]
2990 if rejwn is None: rejwn = []
2991 if clipthresh is None: clipthresh = 3.0
2992 if clipniter is None: clipniter = 0
2993 if plot is None: plot = False
2994 if getresidual is None: getresidual = True
2995 if showprogress is None: showprogress = True
2996 if minnrow is None: minnrow = 1000
2997 if outlog is None: outlog = False
2998 if blfile is None: blfile = ''
2999 if csvformat is None: csvformat = False
3000 if bltable is None: bltable = ''
3001
3002 sapplyfft = 'true' if applyfft else 'false'
3003 fftinfo = ','.join([sapplyfft, fftmethod.lower(), str(fftthresh).lower()])
3004
3005 scsvformat = 'T' if csvformat else 'F'
3006
3007 #CURRENTLY, PLOT=true is UNAVAILABLE UNTIL sinusoidal fitting is implemented as a fitter method.
3008 workscan._sinusoid_baseline(mask,
3009 fftinfo,
3010 #applyfft, fftmethod.lower(),
3011 #str(fftthresh).lower(),
3012 workscan._parse_wn(addwn),
3013 workscan._parse_wn(rejwn),
3014 clipthresh, clipniter,
3015 getresidual,
3016 pack_progress_params(showprogress,
3017 minnrow),
3018 outlog, scsvformat+blfile,
3019 bltable)
3020 workscan._add_history('sinusoid_baseline', varlist)
3021
3022 if bltable == '':
3023 if insitu:
3024 self._assign(workscan)
3025 else:
3026 return workscan
3027 else:
3028 if not insitu:
3029 return None
3030
3031 except RuntimeError, e:
3032 raise_fitting_failure_exception(e)
3033
3034
3035 @asaplog_post_dec
3036 def auto_sinusoid_baseline(self, insitu=None, mask=None, applyfft=None,
3037 fftmethod=None, fftthresh=None,
3038 addwn=None, rejwn=None, clipthresh=None,
3039 clipniter=None, edge=None, threshold=None,
3040 chan_avg_limit=None, plot=None,
3041 getresidual=None, showprogress=None,
3042 minnrow=None, outlog=None,
3043 blfile=None, csvformat=None,
3044 bltable=None):
3045 """\
3046 Return a scan which has been baselined (all rows) with sinusoidal
3047 functions.
3048 Spectral lines are detected first using linefinder and masked out
3049 to avoid them affecting the baseline solution.
3050
3051 Parameters:
3052 insitu: if False a new scantable is returned.
3053 Otherwise, the scaling is done in-situ
3054 The default is taken from .asaprc (False)
3055 mask: an optional mask retreived from scantable
3056 applyfft: if True use some method, such as FFT, to find
3057 strongest sinusoidal components in the wavenumber
3058 domain to be used for baseline fitting.
3059 default is True.
3060 fftmethod: method to find the strong sinusoidal components.
3061 now only 'fft' is available and it is the default.
3062 fftthresh: the threshold to select wave numbers to be used for
3063 fitting from the distribution of amplitudes in the
3064 wavenumber domain.
3065 both float and string values accepted.
3066 given a float value, the unit is set to sigma.
3067 for string values, allowed formats include:
3068 'xsigma' or 'x' (= x-sigma level. e.g.,
3069 '3sigma'), or
3070 'topx' (= the x strongest ones, e.g. 'top5').
3071 default is 3.0 (unit: sigma).
3072 addwn: the additional wave numbers to be used for fitting.
3073 list or integer value is accepted to specify every
3074 wave numbers. also string value can be used in case
3075 you need to specify wave numbers in a certain range,
3076 e.g., 'a-b' (= a, a+1, a+2, ..., b-1, b),
3077 '<a' (= 0,1,...,a-2,a-1),
3078 '>=a' (= a, a+1, ... up to the maximum wave
3079 number corresponding to the Nyquist
3080 frequency for the case of FFT).
3081 default is [0].
3082 rejwn: the wave numbers NOT to be used for fitting.
3083 can be set just as addwn but has higher priority:
3084 wave numbers which are specified both in addwn
3085 and rejwn will NOT be used. default is [].
3086 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
3087 clipniter: maximum number of iteration of 'clipthresh'-sigma
3088 clipping (default is 0)
3089 edge: an optional number of channel to drop at
3090 the edge of spectrum. If only one value is
3091 specified, the same number will be dropped
3092 from both sides of the spectrum. Default
3093 is to keep all channels. Nested tuples
3094 represent individual edge selection for
3095 different IFs (a number of spectral channels
3096 can be different)
3097 threshold: the threshold used by line finder. It is
3098 better to keep it large as only strong lines
3099 affect the baseline solution.
3100 chan_avg_limit: a maximum number of consequtive spectral
3101 channels to average during the search of
3102 weak and broad lines. The default is no
3103 averaging (and no search for weak lines).
3104 If such lines can affect the fitted baseline
3105 (e.g. a high order polynomial is fitted),
3106 increase this parameter (usually values up
3107 to 8 are reasonable). Most users of this
3108 method should find the default value sufficient.
3109 plot: *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3110 plot the fit and the residual. In this each
3111 indivual fit has to be approved, by typing 'y'
3112 or 'n'
3113 getresidual: if False, returns best-fit values instead of
3114 residual. (default is True)
3115 showprogress: show progress status for large data.
3116 default is True.
3117 minnrow: minimum number of input spectra to show.
3118 default is 1000.
3119 outlog: Output the coefficients of the best-fit
3120 function to logger (default is False)
3121 blfile: Name of a text file in which the best-fit
3122 parameter values to be written
3123 (default is "": no file/logger output)
3124 csvformat: if True blfile is csv-formatted, default is False.
3125 bltable: name of a baseline table where fitting results
3126 (coefficients, rms, etc.) are to be written.
3127 if given, fitting results will NOT be output to
3128 scantable (insitu=True) or None will be
3129 returned (insitu=False).
3130 (default is "": no table output)
3131
3132 Example:
3133 bscan = scan.auto_sinusoid_baseline(addwn='<=10', insitu=False)
3134
3135 Note:
3136 The best-fit parameter values output in logger and/or blfile are now
3137 based on specunit of 'channel'.
3138 """
3139
3140 try:
3141 varlist = vars()
3142
3143 if insitu is None: insitu = rcParams['insitu']
3144 if insitu:
3145 workscan = self
3146 else:
3147 workscan = self.copy()
3148
3149 #if mask is None: mask = [True for i in xrange(workscan.nchan())]
3150 if mask is None: mask = []
3151 if applyfft is None: applyfft = True
3152 if fftmethod is None: fftmethod = 'fft'
3153 if fftthresh is None: fftthresh = 3.0
3154 if addwn is None: addwn = [0]
3155 if rejwn is None: rejwn = []
3156 if clipthresh is None: clipthresh = 3.0
3157 if clipniter is None: clipniter = 0
3158 if edge is None: edge = (0,0)
3159 if threshold is None: threshold = 3
3160 if chan_avg_limit is None: chan_avg_limit = 1
3161 if plot is None: plot = False
3162 if getresidual is None: getresidual = True
3163 if showprogress is None: showprogress = True
3164 if minnrow is None: minnrow = 1000
3165 if outlog is None: outlog = False
3166 if blfile is None: blfile = ''
3167 if csvformat is None: csvformat = False
3168 if bltable is None: bltable = ''
3169
3170 sapplyfft = 'true' if applyfft else 'false'
3171 fftinfo = ','.join([sapplyfft, fftmethod.lower(), str(fftthresh).lower()])
3172
3173 scsvformat = 'T' if csvformat else 'F'
3174
3175 #CURRENTLY, PLOT=true is UNAVAILABLE UNTIL sinusoidal fitting is implemented as a fitter method.
3176 workscan._auto_sinusoid_baseline(mask,
3177 fftinfo,
3178 workscan._parse_wn(addwn),
3179 workscan._parse_wn(rejwn),
3180 clipthresh, clipniter,
3181 normalise_edge_param(edge),
3182 threshold, chan_avg_limit,
3183 getresidual,
3184 pack_progress_params(showprogress,
3185 minnrow),
3186 outlog, scsvformat+blfile, bltable)
3187 workscan._add_history("auto_sinusoid_baseline", varlist)
3188
3189 if bltable == '':
3190 if insitu:
3191 self._assign(workscan)
3192 else:
3193 return workscan
3194 else:
3195 if not insitu:
3196 return None
3197
3198 except RuntimeError, e:
3199 raise_fitting_failure_exception(e)
3200
3201 @asaplog_post_dec
3202 def cspline_baseline(self, insitu=None, mask=None, npiece=None,
3203 clipthresh=None, clipniter=None, plot=None,
3204 getresidual=None, showprogress=None, minnrow=None,
3205 outlog=None, blfile=None, csvformat=None,
3206 bltable=None):
3207 """\
3208 Return a scan which has been baselined (all rows) by cubic spline
3209 function (piecewise cubic polynomial).
3210
3211 Parameters:
3212 insitu: If False a new scantable is returned.
3213 Otherwise, the scaling is done in-situ
3214 The default is taken from .asaprc (False)
3215 mask: An optional mask
3216 npiece: Number of pieces. (default is 2)
3217 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
3218 clipniter: maximum number of iteration of 'clipthresh'-sigma
3219 clipping (default is 0)
3220 plot: *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3221 plot the fit and the residual. In this each
3222 indivual fit has to be approved, by typing 'y'
3223 or 'n'
3224 getresidual: if False, returns best-fit values instead of
3225 residual. (default is True)
3226 showprogress: show progress status for large data.
3227 default is True.
3228 minnrow: minimum number of input spectra to show.
3229 default is 1000.
3230 outlog: Output the coefficients of the best-fit
3231 function to logger (default is False)
3232 blfile: Name of a text file in which the best-fit
3233 parameter values to be written
3234 (default is "": no file/logger output)
3235 csvformat: if True blfile is csv-formatted, default is False.
3236 bltable: name of a baseline table where fitting results
3237 (coefficients, rms, etc.) are to be written.
3238 if given, fitting results will NOT be output to
3239 scantable (insitu=True) or None will be
3240 returned (insitu=False).
3241 (default is "": no table output)
3242
3243 Example:
3244 # return a scan baselined by a cubic spline consisting of 2 pieces
3245 # (i.e., 1 internal knot),
3246 # also with 3-sigma clipping, iteration up to 4 times
3247 bscan = scan.cspline_baseline(npiece=2,clipthresh=3.0,clipniter=4)
3248
3249 Note:
3250 The best-fit parameter values output in logger and/or blfile are now
3251 based on specunit of 'channel'.
3252 """
3253
3254 try:
3255 varlist = vars()
3256
3257 if insitu is None: insitu = rcParams['insitu']
3258 if insitu:
3259 workscan = self
3260 else:
3261 workscan = self.copy()
3262
3263 #if mask is None: mask = [True for i in xrange(workscan.nchan())]
3264 if mask is None: mask = []
3265 if npiece is None: npiece = 2
3266 if clipthresh is None: clipthresh = 3.0
3267 if clipniter is None: clipniter = 0
3268 if plot is None: plot = False
3269 if getresidual is None: getresidual = True
3270 if showprogress is None: showprogress = True
3271 if minnrow is None: minnrow = 1000
3272 if outlog is None: outlog = False
3273 if blfile is None: blfile = ''
3274 if csvformat is None: csvformat = False
3275 if bltable is None: bltable = ''
3276
3277 scsvformat = 'T' if csvformat else 'F'
3278
3279 #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
3280 workscan._cspline_baseline(mask, npiece,
3281 clipthresh, clipniter,
3282 getresidual,
3283 pack_progress_params(showprogress,
3284 minnrow),
3285 outlog, scsvformat+blfile,
3286 bltable)
3287 workscan._add_history("cspline_baseline", varlist)
3288
3289 if bltable == '':
3290 if insitu:
3291 self._assign(workscan)
3292 else:
3293 return workscan
3294 else:
3295 if not insitu:
3296 return None
3297
3298 except RuntimeError, e:
3299 raise_fitting_failure_exception(e)
3300
3301 @asaplog_post_dec
3302 def auto_cspline_baseline(self, insitu=None, mask=None, npiece=None,
3303 clipthresh=None, clipniter=None,
3304 edge=None, threshold=None, chan_avg_limit=None,
3305 getresidual=None, plot=None,
3306 showprogress=None, minnrow=None, outlog=None,
3307 blfile=None, csvformat=None, bltable=None):
3308 """\
3309 Return a scan which has been baselined (all rows) by cubic spline
3310 function (piecewise cubic polynomial).
3311 Spectral lines are detected first using linefinder and masked out
3312 to avoid them affecting the baseline solution.
3313
3314 Parameters:
3315 insitu: if False a new scantable is returned.
3316 Otherwise, the scaling is done in-situ
3317 The default is taken from .asaprc (False)
3318 mask: an optional mask retreived from scantable
3319 npiece: Number of pieces. (default is 2)
3320 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
3321 clipniter: maximum number of iteration of 'clipthresh'-sigma
3322 clipping (default is 0)
3323 edge: an optional number of channel to drop at
3324 the edge of spectrum. If only one value is
3325 specified, the same number will be dropped
3326 from both sides of the spectrum. Default
3327 is to keep all channels. Nested tuples
3328 represent individual edge selection for
3329 different IFs (a number of spectral channels
3330 can be different)
3331 threshold: the threshold used by line finder. It is
3332 better to keep it large as only strong lines
3333 affect the baseline solution.
3334 chan_avg_limit: a maximum number of consequtive spectral
3335 channels to average during the search of
3336 weak and broad lines. The default is no
3337 averaging (and no search for weak lines).
3338 If such lines can affect the fitted baseline
3339 (e.g. a high order polynomial is fitted),
3340 increase this parameter (usually values up
3341 to 8 are reasonable). Most users of this
3342 method should find the default value sufficient.
3343 plot: *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3344 plot the fit and the residual. In this each
3345 indivual fit has to be approved, by typing 'y'
3346 or 'n'
3347 getresidual: if False, returns best-fit values instead of
3348 residual. (default is True)
3349 showprogress: show progress status for large data.
3350 default is True.
3351 minnrow: minimum number of input spectra to show.
3352 default is 1000.
3353 outlog: Output the coefficients of the best-fit
3354 function to logger (default is False)
3355 blfile: Name of a text file in which the best-fit
3356 parameter values to be written
3357 (default is "": no file/logger output)
3358 csvformat: if True blfile is csv-formatted, default is False.
3359 bltable: name of a baseline table where fitting results
3360 (coefficients, rms, etc.) are to be written.
3361 if given, fitting results will NOT be output to
3362 scantable (insitu=True) or None will be
3363 returned (insitu=False).
3364 (default is "": no table output)
3365
3366 Example:
3367 bscan = scan.auto_cspline_baseline(npiece=3, insitu=False)
3368
3369 Note:
3370 The best-fit parameter values output in logger and/or blfile are now
3371 based on specunit of 'channel'.
3372 """
3373
3374 try:
3375 varlist = vars()
3376
3377 if insitu is None: insitu = rcParams['insitu']
3378 if insitu:
3379 workscan = self
3380 else:
3381 workscan = self.copy()
3382
3383 #if mask is None: mask = [True for i in xrange(workscan.nchan())]
3384 if mask is None: mask = []
3385 if npiece is None: npiece = 2
3386 if clipthresh is None: clipthresh = 3.0
3387 if clipniter is None: clipniter = 0
3388 if edge is None: edge = (0, 0)
3389 if threshold is None: threshold = 3
3390 if chan_avg_limit is None: chan_avg_limit = 1
3391 if plot is None: plot = False
3392 if getresidual is None: getresidual = True
3393 if showprogress is None: showprogress = True
3394 if minnrow is None: minnrow = 1000
3395 if outlog is None: outlog = False
3396 if blfile is None: blfile = ''
3397 if csvformat is None: csvformat = False
3398 if bltable is None: bltable = ''
3399
3400 scsvformat = 'T' if csvformat else 'F'
3401
3402 #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
3403 workscan._auto_cspline_baseline(mask, npiece,
3404 clipthresh, clipniter,
3405 normalise_edge_param(edge),
3406 threshold,
3407 chan_avg_limit, getresidual,
3408 pack_progress_params(showprogress,
3409 minnrow),
3410 outlog,
3411 scsvformat+blfile,
3412 bltable)
3413 workscan._add_history("auto_cspline_baseline", varlist)
3414
3415 if bltable == '':
3416 if insitu:
3417 self._assign(workscan)
3418 else:
3419 return workscan
3420 else:
3421 if not insitu:
3422 return None
3423
3424 except RuntimeError, e:
3425 raise_fitting_failure_exception(e)
3426
3427 @asaplog_post_dec
3428 def chebyshev_baseline(self, insitu=None, mask=None, order=None,
3429 clipthresh=None, clipniter=None, plot=None,
3430 getresidual=None, showprogress=None, minnrow=None,
3431 outlog=None, blfile=None, csvformat=None,
3432 bltable=None):
3433 """\
3434 Return a scan which has been baselined (all rows) by Chebyshev polynomials.
3435
3436 Parameters:
3437 insitu: If False a new scantable is returned.
3438 Otherwise, the scaling is done in-situ
3439 The default is taken from .asaprc (False)
3440 mask: An optional mask
3441 order: the maximum order of Chebyshev polynomial (default is 5)
3442 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
3443 clipniter: maximum number of iteration of 'clipthresh'-sigma
3444 clipping (default is 0)
3445 plot: *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3446 plot the fit and the residual. In this each
3447 indivual fit has to be approved, by typing 'y'
3448 or 'n'
3449 getresidual: if False, returns best-fit values instead of
3450 residual. (default is True)
3451 showprogress: show progress status for large data.
3452 default is True.
3453 minnrow: minimum number of input spectra to show.
3454 default is 1000.
3455 outlog: Output the coefficients of the best-fit
3456 function to logger (default is False)
3457 blfile: Name of a text file in which the best-fit
3458 parameter values to be written
3459 (default is "": no file/logger output)
3460 csvformat: if True blfile is csv-formatted, default is False.
3461 bltable: name of a baseline table where fitting results
3462 (coefficients, rms, etc.) are to be written.
3463 if given, fitting results will NOT be output to
3464 scantable (insitu=True) or None will be
3465 returned (insitu=False).
3466 (default is "": no table output)
3467
3468 Example:
3469 # return a scan baselined by a cubic spline consisting of 2 pieces
3470 # (i.e., 1 internal knot),
3471 # also with 3-sigma clipping, iteration up to 4 times
3472 bscan = scan.cspline_baseline(npiece=2,clipthresh=3.0,clipniter=4)
3473
3474 Note:
3475 The best-fit parameter values output in logger and/or blfile are now
3476 based on specunit of 'channel'.
3477 """
3478
3479 try:
3480 varlist = vars()
3481
3482 if insitu is None: insitu = rcParams['insitu']
3483 if insitu:
3484 workscan = self
3485 else:
3486 workscan = self.copy()
3487
3488 if mask is None: mask = []
3489 if order is None: order = 5
3490 if clipthresh is None: clipthresh = 3.0
3491 if clipniter is None: clipniter = 0
3492 if plot is None: plot = False
3493 if getresidual is None: getresidual = True
3494 if showprogress is None: showprogress = True
3495 if minnrow is None: minnrow = 1000
3496 if outlog is None: outlog = False
3497 if blfile is None: blfile = ''
3498 if csvformat is None: csvformat = False
3499 if bltable is None: bltable = ''
3500
3501 scsvformat = 'T' if csvformat else 'F'
3502
3503 #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
3504 workscan._chebyshev_baseline(mask, order,
3505 clipthresh, clipniter,
3506 getresidual,
3507 pack_progress_params(showprogress,
3508 minnrow),
3509 outlog, scsvformat+blfile,
3510 bltable)
3511 workscan._add_history("chebyshev_baseline", varlist)
3512
3513 if bltable == '':
3514 if insitu:
3515 self._assign(workscan)
3516 else:
3517 return workscan
3518 else:
3519 if not insitu:
3520 return None
3521
3522 except RuntimeError, e:
3523 raise_fitting_failure_exception(e)
3524
3525 @asaplog_post_dec
3526 def auto_chebyshev_baseline(self, insitu=None, mask=None, order=None,
3527 clipthresh=None, clipniter=None,
3528 edge=None, threshold=None, chan_avg_limit=None,
3529 getresidual=None, plot=None,
3530 showprogress=None, minnrow=None, outlog=None,
3531 blfile=None, csvformat=None, bltable=None):
3532 """\
3533 Return a scan which has been baselined (all rows) by Chebyshev polynomials.
3534 Spectral lines are detected first using linefinder and masked out
3535 to avoid them affecting the baseline solution.
3536
3537 Parameters:
3538 insitu: if False a new scantable is returned.
3539 Otherwise, the scaling is done in-situ
3540 The default is taken from .asaprc (False)
3541 mask: an optional mask retreived from scantable
3542 order: the maximum order of Chebyshev polynomial (default is 5)
3543 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
3544 clipniter: maximum number of iteration of 'clipthresh'-sigma
3545 clipping (default is 0)
3546 edge: an optional number of channel to drop at
3547 the edge of spectrum. If only one value is
3548 specified, the same number will be dropped
3549 from both sides of the spectrum. Default
3550 is to keep all channels. Nested tuples
3551 represent individual edge selection for
3552 different IFs (a number of spectral channels
3553 can be different)
3554 threshold: the threshold used by line finder. It is
3555 better to keep it large as only strong lines
3556 affect the baseline solution.
3557 chan_avg_limit: a maximum number of consequtive spectral
3558 channels to average during the search of
3559 weak and broad lines. The default is no
3560 averaging (and no search for weak lines).
3561 If such lines can affect the fitted baseline
3562 (e.g. a high order polynomial is fitted),
3563 increase this parameter (usually values up
3564 to 8 are reasonable). Most users of this
3565 method should find the default value sufficient.
3566 plot: *** CURRENTLY UNAVAILABLE, ALWAYS FALSE ***
3567 plot the fit and the residual. In this each
3568 indivual fit has to be approved, by typing 'y'
3569 or 'n'
3570 getresidual: if False, returns best-fit values instead of
3571 residual. (default is True)
3572 showprogress: show progress status for large data.
3573 default is True.
3574 minnrow: minimum number of input spectra to show.
3575 default is 1000.
3576 outlog: Output the coefficients of the best-fit
3577 function to logger (default is False)
3578 blfile: Name of a text file in which the best-fit
3579 parameter values to be written
3580 (default is "": no file/logger output)
3581 csvformat: if True blfile is csv-formatted, default is False.
3582 bltable: name of a baseline table where fitting results
3583 (coefficients, rms, etc.) are to be written.
3584 if given, fitting results will NOT be output to
3585 scantable (insitu=True) or None will be
3586 returned (insitu=False).
3587 (default is "": no table output)
3588
3589 Example:
3590 bscan = scan.auto_cspline_baseline(npiece=3, insitu=False)
3591
3592 Note:
3593 The best-fit parameter values output in logger and/or blfile are now
3594 based on specunit of 'channel'.
3595 """
3596
3597 try:
3598 varlist = vars()
3599
3600 if insitu is None: insitu = rcParams['insitu']
3601 if insitu:
3602 workscan = self
3603 else:
3604 workscan = self.copy()
3605
3606 if mask is None: mask = []
3607 if order is None: order = 5
3608 if clipthresh is None: clipthresh = 3.0
3609 if clipniter is None: clipniter = 0
3610 if edge is None: edge = (0, 0)
3611 if threshold is None: threshold = 3
3612 if chan_avg_limit is None: chan_avg_limit = 1
3613 if plot is None: plot = False
3614 if getresidual is None: getresidual = True
3615 if showprogress is None: showprogress = True
3616 if minnrow is None: minnrow = 1000
3617 if outlog is None: outlog = False
3618 if blfile is None: blfile = ''
3619 if csvformat is None: csvformat = False
3620 if bltable is None: bltable = ''
3621
3622 scsvformat = 'T' if csvformat else 'F'
3623
3624 #CURRENTLY, PLOT=true UNAVAILABLE UNTIL cubic spline fitting is implemented as a fitter method.
3625 workscan._auto_chebyshev_baseline(mask, order,
3626 clipthresh, clipniter,
3627 normalise_edge_param(edge),
3628 threshold,
3629 chan_avg_limit, getresidual,
3630 pack_progress_params(showprogress,
3631 minnrow),
3632 outlog, scsvformat+blfile,
3633 bltable)
3634 workscan._add_history("auto_chebyshev_baseline", varlist)
3635
3636 if bltable == '':
3637 if insitu:
3638 self._assign(workscan)
3639 else:
3640 return workscan
3641 else:
3642 if not insitu:
3643 return None
3644
3645 except RuntimeError, e:
3646 raise_fitting_failure_exception(e)
3647
3648 @asaplog_post_dec
3649 def poly_baseline(self, insitu=None, mask=None, order=None,
3650 clipthresh=None, clipniter=None, plot=None,
3651 getresidual=None, showprogress=None, minnrow=None,
3652 outlog=None, blfile=None, csvformat=None,
3653 bltable=None):
3654 """\
3655 Return a scan which has been baselined (all rows) by a polynomial.
3656 Parameters:
3657 insitu: if False a new scantable is returned.
3658 Otherwise, the scaling is done in-situ
3659 The default is taken from .asaprc (False)
3660 mask: an optional mask
3661 order: the order of the polynomial (default is 0)
3662 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
3663 clipniter: maximum number of iteration of 'clipthresh'-sigma
3664 clipping (default is 0)
3665 plot: plot the fit and the residual. In this each
3666 indivual fit has to be approved, by typing 'y'
3667 or 'n'
3668 getresidual: if False, returns best-fit values instead of
3669 residual. (default is True)
3670 showprogress: show progress status for large data.
3671 default is True.
3672 minnrow: minimum number of input spectra to show.
3673 default is 1000.
3674 outlog: Output the coefficients of the best-fit
3675 function to logger (default is False)
3676 blfile: Name of a text file in which the best-fit
3677 parameter values to be written
3678 (default is "": no file/logger output)
3679 csvformat: if True blfile is csv-formatted, default is False.
3680 bltable: name of a baseline table where fitting results
3681 (coefficients, rms, etc.) are to be written.
3682 if given, fitting results will NOT be output to
3683 scantable (insitu=True) or None will be
3684 returned (insitu=False).
3685 (default is "": no table output)
3686
3687 Example:
3688 # return a scan baselined by a third order polynomial,
3689 # not using a mask
3690 bscan = scan.poly_baseline(order=3)
3691 """
3692
3693 try:
3694 varlist = vars()
3695
3696 if insitu is None:
3697 insitu = rcParams["insitu"]
3698 if insitu:
3699 workscan = self
3700 else:
3701 workscan = self.copy()
3702
3703 if mask is None: mask = []
3704 if order is None: order = 0
3705 if clipthresh is None: clipthresh = 3.0
3706 if clipniter is None: clipniter = 0
3707 if plot is None: plot = False
3708 if getresidual is None: getresidual = True
3709 if showprogress is None: showprogress = True
3710 if minnrow is None: minnrow = 1000
3711 if outlog is None: outlog = False
3712 if blfile is None: blfile = ''
3713 if csvformat is None: csvformat = False
3714 if bltable is None: bltable = ''
3715
3716 scsvformat = 'T' if csvformat else 'F'
3717
3718 if plot:
3719 outblfile = (blfile != "") and \
3720 os.path.exists(os.path.expanduser(
3721 os.path.expandvars(blfile))
3722 )
3723 if outblfile:
3724 blf = open(blfile, "a")
3725
3726 f = fitter()
3727 f.set_function(lpoly=order)
3728
3729 rows = xrange(workscan.nrow())
3730 #if len(rows) > 0: workscan._init_blinfo()
3731
3732 action = "H"
3733 for r in rows:
3734 f.x = workscan._getabcissa(r)
3735 f.y = workscan._getspectrum(r)
3736 if mask:
3737 f.mask = mask_and(mask, workscan._getmask(r)) # (CAS-1434)
3738 else: # mask=None
3739 f.mask = workscan._getmask(r)
3740
3741 f.data = None
3742 f.fit()
3743
3744 if action != "Y": # skip plotting when accepting all
3745 f.plot(residual=True)
3746 #accept_fit = raw_input("Accept fit ( [y]/n ): ")
3747 #if accept_fit.upper() == "N":
3748 # #workscan._append_blinfo(None, None, None)
3749 # continue
3750 accept_fit = self._get_verify_action("Accept fit?",action)
3751 if r == 0: action = None
3752 if accept_fit.upper() == "N":
3753 continue
3754 elif accept_fit.upper() == "R":
3755 break
3756 elif accept_fit.upper() == "A":
3757 action = "Y"
3758
3759 blpars = f.get_parameters()
3760 masklist = workscan.get_masklist(f.mask, row=r, silent=True)
3761 #workscan._append_blinfo(blpars, masklist, f.mask)
3762 workscan._setspectrum((f.fitter.getresidual()
3763 if getresidual else f.fitter.getfit()), r)
3764
3765 if outblfile:
3766 rms = workscan.get_rms(f.mask, r)
3767 dataout = \
3768 workscan.format_blparams_row(blpars["params"],
3769 blpars["fixed"],
3770 rms, str(masklist),
3771 r, True, csvformat)
3772 blf.write(dataout)
3773
3774 f._p.unmap()
3775 f._p = None
3776
3777 if outblfile:
3778 blf.close()
3779 else:
3780 workscan._poly_baseline(mask, order,
3781 clipthresh, clipniter, #
3782 getresidual,
3783 pack_progress_params(showprogress,
3784 minnrow),
3785 outlog, scsvformat+blfile,
3786 bltable) #
3787
3788 workscan._add_history("poly_baseline", varlist)
3789
3790 if insitu:
3791 self._assign(workscan)
3792 else:
3793 return workscan
3794
3795 except RuntimeError, e:
3796 raise_fitting_failure_exception(e)
3797
3798 @asaplog_post_dec
3799 def auto_poly_baseline(self, insitu=None, mask=None, order=None,
3800 clipthresh=None, clipniter=None,
3801 edge=None, threshold=None, chan_avg_limit=None,
3802 getresidual=None, plot=None,
3803 showprogress=None, minnrow=None, outlog=None,
3804 blfile=None, csvformat=None, bltable=None):
3805 """\
3806 Return a scan which has been baselined (all rows) by a polynomial.
3807 Spectral lines are detected first using linefinder and masked out
3808 to avoid them affecting the baseline solution.
3809
3810 Parameters:
3811 insitu: if False a new scantable is returned.
3812 Otherwise, the scaling is done in-situ
3813 The default is taken from .asaprc (False)
3814 mask: an optional mask retreived from scantable
3815 order: the order of the polynomial (default is 0)
3816 clipthresh: Clipping threshold. (default is 3.0, unit: sigma)
3817 clipniter: maximum number of iteration of 'clipthresh'-sigma
3818 clipping (default is 0)
3819 edge: an optional number of channel to drop at
3820 the edge of spectrum. If only one value is
3821 specified, the same number will be dropped
3822 from both sides of the spectrum. Default
3823 is to keep all channels. Nested tuples
3824 represent individual edge selection for
3825 different IFs (a number of spectral channels
3826 can be different)
3827 threshold: the threshold used by line finder. It is
3828 better to keep it large as only strong lines
3829 affect the baseline solution.
3830 chan_avg_limit: a maximum number of consequtive spectral
3831 channels to average during the search of
3832 weak and broad lines. The default is no
3833 averaging (and no search for weak lines).
3834 If such lines can affect the fitted baseline
3835 (e.g. a high order polynomial is fitted),
3836 increase this parameter (usually values up
3837 to 8 are reasonable). Most users of this
3838 method should find the default value sufficient.
3839 plot: plot the fit and the residual. In this each
3840 indivual fit has to be approved, by typing 'y'
3841 or 'n'
3842 getresidual: if False, returns best-fit values instead of
3843 residual. (default is True)
3844 showprogress: show progress status for large data.
3845 default is True.
3846 minnrow: minimum number of input spectra to show.
3847 default is 1000.
3848 outlog: Output the coefficients of the best-fit
3849 function to logger (default is False)
3850 blfile: Name of a text file in which the best-fit
3851 parameter values to be written
3852 (default is "": no file/logger output)
3853 csvformat: if True blfile is csv-formatted, default is False.
3854 bltable: name of a baseline table where fitting results
3855 (coefficients, rms, etc.) are to be written.
3856 if given, fitting results will NOT be output to
3857 scantable (insitu=True) or None will be
3858 returned (insitu=False).
3859 (default is "": no table output)
3860
3861 Example:
3862 bscan = scan.auto_poly_baseline(order=7, insitu=False)
3863 """
3864
3865 try:
3866 varlist = vars()
3867
3868 if insitu is None:
3869 insitu = rcParams['insitu']
3870 if insitu:
3871 workscan = self
3872 else:
3873 workscan = self.copy()
3874
3875 if mask is None: mask = []
3876 if order is None: order = 0
3877 if clipthresh is None: clipthresh = 3.0
3878 if clipniter is None: clipniter = 0
3879 if edge is None: edge = (0, 0)
3880 if threshold is None: threshold = 3
3881 if chan_avg_limit is None: chan_avg_limit = 1
3882 if plot is None: plot = False
3883 if getresidual is None: getresidual = True
3884 if showprogress is None: showprogress = True
3885 if minnrow is None: minnrow = 1000
3886 if outlog is None: outlog = False
3887 if blfile is None: blfile = ''
3888 if csvformat is None: csvformat = False
3889 if bltable is None: bltable = ''
3890
3891 scsvformat = 'T' if csvformat else 'F'
3892
3893 edge = normalise_edge_param(edge)
3894
3895 if plot:
3896 outblfile = (blfile != "") and \
3897 os.path.exists(os.path.expanduser(os.path.expandvars(blfile)))
3898 if outblfile: blf = open(blfile, "a")
3899
3900 from asap.asaplinefind import linefinder
3901 fl = linefinder()
3902 fl.set_options(threshold=threshold, avg_limit=chan_avg_limit)
3903 fl.set_scan(workscan)
3904
3905 f = fitter()
3906 f.set_function(lpoly=order)
3907
3908 rows = xrange(workscan.nrow())
3909 #if len(rows) > 0: workscan._init_blinfo()
3910
3911 action = "H"
3912 for r in rows:
3913 idx = 2*workscan.getif(r)
3914 if mask:
3915 msk = mask_and(mask, workscan._getmask(r)) # (CAS-1434)
3916 else: # mask=None
3917 msk = workscan._getmask(r)
3918 fl.find_lines(r, msk, edge[idx:idx+2])
3919
3920 f.x = workscan._getabcissa(r)
3921 f.y = workscan._getspectrum(r)
3922 f.mask = fl.get_mask()
3923 f.data = None
3924 f.fit()
3925
3926 if action != "Y": # skip plotting when accepting all
3927 f.plot(residual=True)
3928 #accept_fit = raw_input("Accept fit ( [y]/n ): ")
3929 accept_fit = self._get_verify_action("Accept fit?",action)
3930 if r == 0: action = None
3931 if accept_fit.upper() == "N":
3932 #workscan._append_blinfo(None, None, None)
3933 continue
3934 elif accept_fit.upper() == "R":
3935 break
3936 elif accept_fit.upper() == "A":
3937 action = "Y"
3938
3939 blpars = f.get_parameters()
3940 masklist = workscan.get_masklist(f.mask, row=r, silent=True)
3941 #workscan._append_blinfo(blpars, masklist, f.mask)
3942 workscan._setspectrum(
3943 (f.fitter.getresidual() if getresidual
3944 else f.fitter.getfit()), r
3945 )
3946
3947 if outblfile:
3948 rms = workscan.get_rms(f.mask, r)
3949 dataout = \
3950 workscan.format_blparams_row(blpars["params"],
3951 blpars["fixed"],
3952 rms, str(masklist),
3953 r, True, csvformat)
3954 blf.write(dataout)
3955
3956 f._p.unmap()
3957 f._p = None
3958
3959 if outblfile: blf.close()
3960 else:
3961 workscan._auto_poly_baseline(mask, order,
3962 clipthresh, clipniter,
3963 edge, threshold,
3964 chan_avg_limit, getresidual,
3965 pack_progress_params(showprogress,
3966 minnrow),
3967 outlog, scsvformat+blfile,
3968 bltable)
3969 workscan._add_history("auto_poly_baseline", varlist)
3970
3971 if bltable == '':
3972 if insitu:
3973 self._assign(workscan)
3974 else:
3975 return workscan
3976 else:
3977 if not insitu:
3978 return None
3979
3980 except RuntimeError, e:
3981 raise_fitting_failure_exception(e)
3982
3983 def _init_blinfo(self):
3984 """\
3985 Initialise the following three auxiliary members:
3986 blpars : parameters of the best-fit baseline,
3987 masklists : mask data (edge positions of masked channels) and
3988 actualmask : mask data (in boolean list),
3989 to keep for use later (including output to logger/text files).
3990 Used by poly_baseline() and auto_poly_baseline() in case of
3991 'plot=True'.
3992 """
3993 self.blpars = []
3994 self.masklists = []
3995 self.actualmask = []
3996 return
3997
3998 def _append_blinfo(self, data_blpars, data_masklists, data_actualmask):
3999 """\
4000 Append baseline-fitting related info to blpars, masklist and
4001 actualmask.
4002 """
4003 self.blpars.append(data_blpars)
4004 self.masklists.append(data_masklists)
4005 self.actualmask.append(data_actualmask)
4006 return
4007
4008 @asaplog_post_dec
4009 def rotate_linpolphase(self, angle):
4010 """\
4011 Rotate the phase of the complex polarization O=Q+iU correlation.
4012 This is always done in situ in the raw data. So if you call this
4013 function more than once then each call rotates the phase further.
4014
4015 Parameters:
4016
4017 angle: The angle (degrees) to rotate (add) by.
4018
4019 Example::
4020
4021 scan.rotate_linpolphase(2.3)
4022
4023 """
4024 varlist = vars()
4025 self._math._rotate_linpolphase(self, angle)
4026 self._add_history("rotate_linpolphase", varlist)
4027 return
4028
4029 @asaplog_post_dec
4030 def rotate_xyphase(self, angle):
4031 """\
4032 Rotate the phase of the XY correlation. This is always done in situ
4033 in the data. So if you call this function more than once
4034 then each call rotates the phase further.
4035
4036 Parameters:
4037
4038 angle: The angle (degrees) to rotate (add) by.
4039
4040 Example::
4041
4042 scan.rotate_xyphase(2.3)
4043
4044 """
4045 varlist = vars()
4046 self._math._rotate_xyphase(self, angle)
4047 self._add_history("rotate_xyphase", varlist)
4048 return
4049
4050 @asaplog_post_dec
4051 def swap_linears(self):
4052 """\
4053 Swap the linear polarisations XX and YY, or better the first two
4054 polarisations as this also works for ciculars.
4055 """
4056 varlist = vars()
4057 self._math._swap_linears(self)
4058 self._add_history("swap_linears", varlist)
4059 return
4060
4061 @asaplog_post_dec
4062 def invert_phase(self):
4063 """\
4064 Invert the phase of the complex polarisation
4065 """
4066 varlist = vars()
4067 self._math._invert_phase(self)
4068 self._add_history("invert_phase", varlist)
4069 return
4070
4071 @asaplog_post_dec
4072 def add(self, offset, insitu=None):
4073 """\
4074 Return a scan where all spectra have the offset added
4075
4076 Parameters:
4077
4078 offset: the offset
4079
4080 insitu: if False a new scantable is returned.
4081 Otherwise, the scaling is done in-situ
4082 The default is taken from .asaprc (False)
4083
4084 """
4085 if insitu is None: insitu = rcParams['insitu']
4086 self._math._setinsitu(insitu)
4087 varlist = vars()
4088 s = scantable(self._math._unaryop(self, offset, "ADD", False))
4089 s._add_history("add", varlist)
4090 if insitu:
4091 self._assign(s)
4092 else:
4093 return s
4094
4095 @asaplog_post_dec
4096 def scale(self, factor, tsys=True, insitu=None):
4097 """\
4098
4099 Return a scan where all spectra are scaled by the given 'factor'
4100
4101 Parameters:
4102
4103 factor: the scaling factor (float or 1D float list)
4104
4105 insitu: if False a new scantable is returned.
4106 Otherwise, the scaling is done in-situ
4107 The default is taken from .asaprc (False)
4108
4109 tsys: if True (default) then apply the operation to Tsys
4110 as well as the data
4111
4112 """
4113 if insitu is None: insitu = rcParams['insitu']
4114 self._math._setinsitu(insitu)
4115 varlist = vars()
4116 s = None
4117 import numpy
4118 if isinstance(factor, list) or isinstance(factor, numpy.ndarray):
4119 if isinstance(factor[0], list) or isinstance(factor[0],
4120 numpy.ndarray):
4121 from asapmath import _array2dOp
4122 s = _array2dOp( self, factor, "MUL", tsys, insitu )
4123 else:
4124 s = scantable( self._math._arrayop( self, factor,
4125 "MUL", tsys ) )
4126 else:
4127 s = scantable(self._math._unaryop(self, factor, "MUL", tsys))
4128 s._add_history("scale", varlist)
4129 if insitu:
4130 self._assign(s)
4131 else:
4132 return s
4133
4134 @preserve_selection
4135 def set_sourcetype(self, match, matchtype="pattern",
4136 sourcetype="reference"):
4137 """\
4138 Set the type of the source to be an source or reference scan
4139 using the provided pattern.
4140
4141 Parameters:
4142
4143 match: a Unix style pattern, regular expression or selector
4144
4145 matchtype: 'pattern' (default) UNIX style pattern or
4146 'regex' regular expression
4147
4148 sourcetype: the type of the source to use (source/reference)
4149
4150 """
4151 varlist = vars()
4152 stype = -1
4153 if sourcetype.lower().startswith("r") or sourcetype.lower() == "off":
4154 stype = 1
4155 elif sourcetype.lower().startswith("s") or sourcetype.lower() == "on":
4156 stype = 0
4157 else:
4158 raise ValueError("Illegal sourcetype use s(ource)/on or r(eference)/off")
4159 if matchtype.lower().startswith("p"):
4160 matchtype = "pattern"
4161 elif matchtype.lower().startswith("r"):
4162 matchtype = "regex"
4163 else:
4164 raise ValueError("Illegal matchtype, use p(attern) or r(egex)")
4165 sel = selector()
4166 if isinstance(match, selector):
4167 sel = match
4168 else:
4169 sel.set_query("SRCNAME=%s('%s')" % (matchtype, match))
4170 self.set_selection(sel)
4171 self._setsourcetype(stype)
4172 self._add_history("set_sourcetype", varlist)
4173
4174 @asaplog_post_dec
4175 @preserve_selection
4176 def auto_quotient(self, preserve=True, mode='paired', verify=False):
4177 """\
4178 This function allows to build quotients automatically.
4179 It assumes the observation to have the same number of
4180 "ons" and "offs"
4181
4182 Parameters:
4183
4184 preserve: you can preserve (default) the continuum or
4185 remove it. The equations used are
4186
4187 preserve: Output = Toff * (on/off) - Toff
4188
4189 remove: Output = Toff * (on/off) - Ton
4190
4191 mode: the on/off detection mode
4192 'paired' (default)
4193 identifies 'off' scans by the
4194 trailing '_R' (Mopra/Parkes) or
4195 '_e'/'_w' (Tid) and matches
4196 on/off pairs from the observing pattern
4197 'time'
4198 finds the closest off in time
4199
4200 .. todo:: verify argument is not implemented
4201
4202 """
4203 varlist = vars()
4204 modes = ["time", "paired"]
4205 if not mode in modes:
4206 msg = "please provide valid mode. Valid modes are %s" % (modes)
4207 raise ValueError(msg)
4208 s = None
4209 if mode.lower() == "paired":
4210 sel = self.get_selection()
4211 sel.set_query("SRCTYPE==psoff")
4212 self.set_selection(sel)
4213 offs = self.copy()
4214 sel.set_query("SRCTYPE==pson")
4215 self.set_selection(sel)
4216 ons = self.copy()
4217 s = scantable(self._math._quotient(ons, offs, preserve))
4218 elif mode.lower() == "time":
4219 s = scantable(self._math._auto_quotient(self, mode, preserve))
4220 s._add_history("auto_quotient", varlist)
4221 return s
4222
4223 @asaplog_post_dec
4224 def mx_quotient(self, mask = None, weight='median', preserve=True):
4225 """\
4226 Form a quotient using "off" beams when observing in "MX" mode.
4227
4228 Parameters:
4229
4230 mask: an optional mask to be used when weight == 'stddev'
4231
4232 weight: How to average the off beams. Default is 'median'.
4233
4234 preserve: you can preserve (default) the continuum or
4235 remove it. The equations used are:
4236
4237 preserve: Output = Toff * (on/off) - Toff
4238
4239 remove: Output = Toff * (on/off) - Ton
4240
4241 """
4242 mask = mask or ()
4243 varlist = vars()
4244 on = scantable(self._math._mx_extract(self, 'on'))
4245 preoff = scantable(self._math._mx_extract(self, 'off'))
4246 off = preoff.average_time(mask=mask, weight=weight, scanav=False)
4247 from asapmath import quotient
4248 q = quotient(on, off, preserve)
4249 q._add_history("mx_quotient", varlist)
4250 return q
4251
4252 @asaplog_post_dec
4253 def freq_switch(self, insitu=None):
4254 """\
4255 Apply frequency switching to the data.
4256
4257 Parameters:
4258
4259 insitu: if False a new scantable is returned.
4260 Otherwise, the swictching is done in-situ
4261 The default is taken from .asaprc (False)
4262
4263 """
4264 if insitu is None: insitu = rcParams['insitu']
4265 self._math._setinsitu(insitu)
4266 varlist = vars()
4267 s = scantable(self._math._freqswitch(self))
4268 s._add_history("freq_switch", varlist)
4269 if insitu:
4270 self._assign(s)
4271 else:
4272 return s
4273
4274 @asaplog_post_dec
4275 def recalc_azel(self):
4276 """Recalculate the azimuth and elevation for each position."""
4277 varlist = vars()
4278 self._recalcazel()
4279 self._add_history("recalc_azel", varlist)
4280 return
4281
4282 @asaplog_post_dec
4283 def __add__(self, other):
4284 """
4285 implicit on all axes and on Tsys
4286 """
4287 varlist = vars()
4288 s = self.__op( other, "ADD" )
4289 s._add_history("operator +", varlist)
4290 return s
4291
4292 @asaplog_post_dec
4293 def __sub__(self, other):
4294 """
4295 implicit on all axes and on Tsys
4296 """
4297 varlist = vars()
4298 s = self.__op( other, "SUB" )
4299 s._add_history("operator -", varlist)
4300 return s
4301
4302 @asaplog_post_dec
4303 def __mul__(self, other):
4304 """
4305 implicit on all axes and on Tsys
4306 """
4307 varlist = vars()
4308 s = self.__op( other, "MUL" ) ;
4309 s._add_history("operator *", varlist)
4310 return s
4311
4312
4313 @asaplog_post_dec
4314 def __div__(self, other):
4315 """
4316 implicit on all axes and on Tsys
4317 """
4318 varlist = vars()
4319 s = self.__op( other, "DIV" )
4320 s._add_history("operator /", varlist)
4321 return s
4322
4323 @asaplog_post_dec
4324 def __op( self, other, mode ):
4325 s = None
4326 if isinstance(other, scantable):
4327 s = scantable(self._math._binaryop(self, other, mode))
4328 elif isinstance(other, float):
4329 if other == 0.0:
4330 raise ZeroDivisionError("Dividing by zero is not recommended")
4331 s = scantable(self._math._unaryop(self, other, mode, False))
4332 elif isinstance(other, list) or isinstance(other, numpy.ndarray):
4333 if isinstance(other[0], list) \
4334 or isinstance(other[0], numpy.ndarray):
4335 from asapmath import _array2dOp
4336 s = _array2dOp( self, other, mode, False )
4337 else:
4338 s = scantable( self._math._arrayop( self, other,
4339 mode, False ) )
4340 else:
4341 raise TypeError("Other input is not a scantable or float value")
4342 return s
4343
4344 @asaplog_post_dec
4345 def get_fit(self, row=0):
4346 """\
4347 Print or return the stored fits for a row in the scantable
4348
4349 Parameters:
4350
4351 row: the row which the fit has been applied to.
4352
4353 """
4354 if row > self.nrow():
4355 return
4356 from asap.asapfit import asapfit
4357 fit = asapfit(self._getfit(row))
4358 asaplog.push( '%s' %(fit) )
4359 return fit.as_dict()
4360
4361 @preserve_selection
4362 def flag_nans(self):
4363 """\
4364 Utility function to flag NaN values in the scantable.
4365 """
4366 import numpy
4367 basesel = self.get_selection()
4368 for i in range(self.nrow()):
4369 sel = self.get_row_selector(i)
4370 self.set_selection(basesel+sel)
4371 nans = numpy.isnan(self._getspectrum(0))
4372 if numpy.any(nans):
4373 bnans = [ bool(v) for v in nans]
4374 self.flag(bnans)
4375
4376 def get_row_selector(self, rowno):
4377 return selector(rows=[rowno])
4378
4379 def _add_history(self, funcname, parameters):
4380 if not rcParams['scantable.history']:
4381 return
4382 # create date
4383 sep = "##"
4384 from datetime import datetime
4385 dstr = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
4386 hist = dstr+sep
4387 hist += funcname+sep#cdate+sep
4388 if parameters.has_key('self'):
4389 del parameters['self']
4390 for k, v in parameters.iteritems():
4391 if type(v) is dict:
4392 for k2, v2 in v.iteritems():
4393 hist += k2
4394 hist += "="
4395 if isinstance(v2, scantable):
4396 hist += 'scantable'
4397 elif k2 == 'mask':
4398 if isinstance(v2, list) or isinstance(v2, tuple):
4399 hist += str(self._zip_mask(v2))
4400 else:
4401 hist += str(v2)
4402 else:
4403 hist += str(v2)
4404 else:
4405 hist += k
4406 hist += "="
4407 if isinstance(v, scantable):
4408 hist += 'scantable'
4409 elif k == 'mask':
4410 if isinstance(v, list) or isinstance(v, tuple):
4411 hist += str(self._zip_mask(v))
4412 else:
4413 hist += str(v)
4414 else:
4415 hist += str(v)
4416 hist += sep
4417 hist = hist[:-2] # remove trailing '##'
4418 self._addhistory(hist)
4419
4420
4421 def _zip_mask(self, mask):
4422 mask = list(mask)
4423 i = 0
4424 segments = []
4425 while mask[i:].count(1):
4426 i += mask[i:].index(1)
4427 if mask[i:].count(0):
4428 j = i + mask[i:].index(0)
4429 else:
4430 j = len(mask)
4431 segments.append([i, j])
4432 i = j
4433 return segments
4434
4435 def _get_ordinate_label(self):
4436 fu = "("+self.get_fluxunit()+")"
4437 import re
4438 lbl = "Intensity"
4439 if re.match(".K.", fu):
4440 lbl = "Brightness Temperature "+ fu
4441 elif re.match(".Jy.", fu):
4442 lbl = "Flux density "+ fu
4443 return lbl
4444
4445 def _check_ifs(self):
4446# return len(set([self.nchan(i) for i in self.getifnos()])) == 1
4447 nchans = [self.nchan(i) for i in self.getifnos()]
4448 nchans = filter(lambda t: t > 0, nchans)
4449 return (sum(nchans)/len(nchans) == nchans[0])
4450
4451 @asaplog_post_dec
4452 def _fill(self, names, unit, average, opts={}):
4453 first = True
4454 fullnames = []
4455 for name in names:
4456 name = os.path.expandvars(name)
4457 name = os.path.expanduser(name)
4458 if not os.path.exists(name):
4459 msg = "File '%s' does not exists" % (name)
4460 raise IOError(msg)
4461 fullnames.append(name)
4462 if average:
4463 asaplog.push('Auto averaging integrations')
4464 stype = int(rcParams['scantable.storage'].lower() == 'disk')
4465 for name in fullnames:
4466 tbl = Scantable(stype)
4467 if is_ms( name ):
4468 r = msfiller( tbl )
4469 else:
4470 r = filler( tbl )
4471 msg = "Importing %s..." % (name)
4472 asaplog.push(msg, False)
4473 r.open(name, opts)
4474 rx = rcParams['scantable.reference']
4475 r.setreferenceexpr(rx)
4476 r.fill()
4477 if average:
4478 tbl = self._math._average((tbl, ), (), 'NONE', 'SCAN')
4479 if not first:
4480 tbl = self._math._merge([self, tbl])
4481 Scantable.__init__(self, tbl)
4482 r.close()
4483 del r, tbl
4484 first = False
4485 #flush log
4486 asaplog.post()
4487 if unit is not None:
4488 self.set_fluxunit(unit)
4489 if not is_casapy():
4490 self.set_freqframe(rcParams['scantable.freqframe'])
4491
4492 def _get_verify_action( self, msg, action=None ):
4493 valid_act = ['Y', 'N', 'A', 'R']
4494 if not action or not isinstance(action, str):
4495 action = raw_input("%s [Y/n/a/r] (h for help): " % msg)
4496 if action == '':
4497 return "Y"
4498 elif (action.upper()[0] in valid_act):
4499 return action.upper()[0]
4500 elif (action.upper()[0] in ['H','?']):
4501 print "Available actions of verification [Y|n|a|r]"
4502 print " Y : Yes for current data (default)"
4503 print " N : No for current data"
4504 print " A : Accept all in the following and exit from verification"
4505 print " R : Reject all in the following and exit from verification"
4506 print " H or ?: help (show this message)"
4507 return self._get_verify_action(msg)
4508 else:
4509 return 'Y'
4510
4511 def __getitem__(self, key):
4512 if key < 0:
4513 key += self.nrow()
4514 if key >= self.nrow():
4515 raise IndexError("Row index out of range.")
4516 return self._getspectrum(key)
4517
4518 def __setitem__(self, key, value):
4519 if key < 0:
4520 key += self.nrow()
4521 if key >= self.nrow():
4522 raise IndexError("Row index out of range.")
4523 if not hasattr(value, "__len__") or \
4524 len(value) > self.nchan(self.getif(key)):
4525 raise ValueError("Spectrum length doesn't match.")
4526 return self._setspectrum(value, key)
4527
4528 def __len__(self):
4529 return self.nrow()
4530
4531 def __iter__(self):
4532 for i in range(len(self)):
4533 yield self[i]
Note: See TracBrowser for help on using the repository browser.