source: trunk/python/scantable.py@ 2852

Last change on this file since 2852 was 2844, checked in by Takeshi Nakazato, 11 years ago

New Development: No

JIRA Issue: Yes CAS-5535

Ready for Test: Yes

Interface Changes: Yes

What Interface Changed: Removed freq_tolsr option from scantable constructor

Test Programs: sdsave unit test

Put in Release Notes: No

Module(s): sd

Description: Describe your changes here...

The parameter freq_tolsr is removed from scantable constructor.
It is removed from python layer as well as C++ layer.
Now the code always behaves like 'freq_tolsr=False'.

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