source: trunk/python/scantable.py@ 2610

Last change on this file since 2610 was 2610, checked in by Kana Sugimoto, 13 years ago

New Development: No (an enhancement)

JIRA Issue: Yes (CAS-4146/Trac-276)

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs: Interactive tests

Put in Release Notes: Yes

Module(s): scantable, sdbaseline (blfunc='poly'), sdsmooth (kernel!='regrid')

Description:

Implemented a way to exit from verification in the middle of scantable.
Added choises 'a', 'r', and 'h' in actions. Below is the full list of actions.
Available actions of verification [Y|n|a|r]

Y : Yes for current data (default)
N : No for current data
A : Accept all in the following and exit from verification
R : Reject all in the following and exit from verification
H or ?: help (show this message)


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