source: trunk/python/scantable.py@ 1916

Last change on this file since 1916 was 1916, checked in by Takeshi Nakazato, 14 years ago

New Development: No

JIRA Issue: No

Ready for Test: Yes

Interface Changes: No

What Interface Changed: Please list interface changes

Test Programs: sd regression tests

Put in Release Notes: No

Module(s): Module Names change impacts.

Description: Describe your changes here...

The antenna and getpt parameters for MS filler is effective again.


  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 92.7 KB
RevLine 
[1846]1"""This module defines the scantable class."""
2
[1697]3import os
[1691]4try:
5 from functools import wraps as wraps_dec
6except ImportError:
7 from asap.compatibility import wraps as wraps_dec
8
[1824]9from asap.env import is_casapy
[876]10from asap._asap import Scantable
[1843]11from asap._asap import filler
[1824]12from asap.parameters import rcParams
[1862]13from asap.logging import asaplog, asaplog_post_dec
[1824]14from asap.selector import selector
15from asap.linecatalog import linecatalog
[1600]16from asap.coordinate import coordinate
[1859]17from asap.utils import _n_bools, mask_not, mask_and, mask_or, page
[1907]18from asap.asapfitter import fitter
[102]19
[1689]20
21def preserve_selection(func):
[1691]22 @wraps_dec(func)
[1689]23 def wrap(obj, *args, **kw):
24 basesel = obj.get_selection()
[1857]25 try:
26 val = func(obj, *args, **kw)
27 finally:
28 obj.set_selection(basesel)
[1689]29 return val
30 return wrap
31
[1846]32def is_scantable(filename):
33 """Is the given file a scantable?
[1689]34
[1846]35 Parameters:
36
37 filename: the name of the file/directory to test
38
39 """
[1883]40 if ( os.path.isdir(filename)
41 and os.path.exists(filename+'/table.info')
42 and os.path.exists(filename+'/table.dat') ):
43 f=open(filename+'/table.info')
44 l=f.readline()
45 f.close()
46 #if ( l.find('Scantable') != -1 ):
47 if ( l.find('Measurement Set') == -1 ):
48 return True
49 else:
50 return False
51 else:
52 return False
53## return (os.path.isdir(filename)
54## and not os.path.exists(filename+'/table.f1')
55## and os.path.exists(filename+'/table.info'))
[1697]56
[1883]57def is_ms(filename):
58 """Is the given file a MeasurementSet?
[1697]59
[1883]60 Parameters:
61
62 filename: the name of the file/directory to test
63
64 """
65 if ( os.path.isdir(filename)
66 and os.path.exists(filename+'/table.info')
67 and os.path.exists(filename+'/table.dat') ):
68 f=open(filename+'/table.info')
69 l=f.readline()
70 f.close()
71 if ( l.find('Measurement Set') != -1 ):
72 return True
73 else:
74 return False
75 else:
76 return False
77
[876]78class scantable(Scantable):
[1846]79 """\
80 The ASAP container for scans (single-dish data).
[102]81 """
[1819]82
[1862]83 @asaplog_post_dec
[1916]84 #def __init__(self, filename, average=None, unit=None, getpt=None,
85 # antenna=None, parallactify=None):
86 def __init__(self, filename, average=None, unit=None, parallactify=None, **args):
[1846]87 """\
[102]88 Create a scantable from a saved one or make a reference
[1846]89
[102]90 Parameters:
[1846]91
92 filename: the name of an asap table on disk
93 or
94 the name of a rpfits/sdfits/ms file
95 (integrations within scans are auto averaged
96 and the whole file is read) or
97 [advanced] a reference to an existing scantable
98
99 average: average all integrations withinb a scan on read.
100 The default (True) is taken from .asaprc.
101
[484]102 unit: brightness unit; must be consistent with K or Jy.
[1846]103 Over-rides the default selected by the filler
104 (input rpfits/sdfits/ms) or replaces the value
105 in existing scantables
106
107 getpt: for MeasurementSet input data only:
108 If True, all pointing data are filled.
109 The deafult is False, which makes time to load
110 the MS data faster in some cases.
111
112 antenna: Antenna selection. integer (id) or string (name or id).
113
114 parallactify: Indicate that the data had been parallatified. Default
115 is taken from rc file.
116
[710]117 """
[976]118 if average is None:
[710]119 average = rcParams['scantable.autoaverage']
[1916]120 #if getpt is None:
121 # getpt = True
122 #if antenna is not None:
123 # asaplog.push("Antenna selection currently unsupported."
124 # "Using ''")
125 # asaplog.post('WARN')
126 #if antenna is None:
127 # antenna = ''
128 #elif type(antenna) == int:
129 # antenna = '%s' % antenna
130 #elif type(antenna) == list:
131 # tmpstr = ''
132 # for i in range( len(antenna) ):
133 # if type(antenna[i]) == int:
134 # tmpstr = tmpstr + ('%s,'%(antenna[i]))
135 # elif type(antenna[i]) == str:
136 # tmpstr=tmpstr+antenna[i]+','
137 # else:
138 # raise TypeError('Bad antenna selection.')
139 # antenna = tmpstr.rstrip(',')
[1593]140 parallactify = parallactify or rcParams['scantable.parallactify']
[1259]141 varlist = vars()
[876]142 from asap._asap import stmath
[1819]143 self._math = stmath( rcParams['insitu'] )
[876]144 if isinstance(filename, Scantable):
145 Scantable.__init__(self, filename)
[181]146 else:
[1697]147 if isinstance(filename, str):
[976]148 filename = os.path.expandvars(filename)
149 filename = os.path.expanduser(filename)
150 if not os.path.exists(filename):
151 s = "File '%s' not found." % (filename)
152 raise IOError(s)
[1697]153 if is_scantable(filename):
154 ondisk = rcParams['scantable.storage'] == 'disk'
155 Scantable.__init__(self, filename, ondisk)
156 if unit is not None:
157 self.set_fluxunit(unit)
[1819]158 # do not reset to the default freqframe
159 #self.set_freqframe(rcParams['scantable.freqframe'])
[1883]160 #elif os.path.isdir(filename) \
161 # and not os.path.exists(filename+'/table.f1'):
162 elif is_ms(filename):
[1916]163 # Measurement Set
164 opts={'ms': {}}
165 mskeys=['getpt','antenna']
166 for key in mskeys:
167 if key in args.keys():
168 opts['ms'][key] = args[key]
169 #self._fill([filename], unit, average, getpt, antenna)
170 self._fill([filename], unit, average, opts)
[1893]171 elif os.path.isfile(filename):
[1916]172 #self._fill([filename], unit, average, getpt, antenna)
173 self._fill([filename], unit, average)
[1883]174 else:
[1819]175 msg = "The given file '%s'is not a valid " \
176 "asap table." % (filename)
[1859]177 raise IOError(msg)
[1118]178 elif (isinstance(filename, list) or isinstance(filename, tuple)) \
[976]179 and isinstance(filename[-1], str):
[1916]180 #self._fill(filename, unit, average, getpt, antenna)
181 self._fill(filename, unit, average)
[1586]182 self.parallactify(parallactify)
[1259]183 self._add_history("scantable", varlist)
[102]184
[1862]185 @asaplog_post_dec
[876]186 def save(self, name=None, format=None, overwrite=False):
[1846]187 """\
[1280]188 Store the scantable on disk. This can be an asap (aips++) Table,
189 SDFITS or MS2 format.
[1846]190
[116]191 Parameters:
[1846]192
[1093]193 name: the name of the outputfile. For format "ASCII"
194 this is the root file name (data in 'name'.txt
[497]195 and header in 'name'_header.txt)
[1855]196
[116]197 format: an optional file format. Default is ASAP.
[1855]198 Allowed are:
199
200 * 'ASAP' (save as ASAP [aips++] Table),
201 * 'SDFITS' (save as SDFITS file)
202 * 'ASCII' (saves as ascii text file)
203 * 'MS2' (saves as an casacore MeasurementSet V2)
204 * 'FITS' (save as image FITS - not readable by class)
205 * 'CLASS' (save as FITS readable by CLASS)
206
[411]207 overwrite: If the file should be overwritten if it exists.
[256]208 The default False is to return with warning
[411]209 without writing the output. USE WITH CARE.
[1855]210
[1846]211 Example::
212
[116]213 scan.save('myscan.asap')
[1118]214 scan.save('myscan.sdfits', 'SDFITS')
[1846]215
[116]216 """
[411]217 from os import path
[1593]218 format = format or rcParams['scantable.save']
[256]219 suffix = '.'+format.lower()
[1118]220 if name is None or name == "":
[256]221 name = 'scantable'+suffix
[718]222 msg = "No filename given. Using default name %s..." % name
223 asaplog.push(msg)
[411]224 name = path.expandvars(name)
[256]225 if path.isfile(name) or path.isdir(name):
226 if not overwrite:
[718]227 msg = "File %s exists." % name
[1859]228 raise IOError(msg)
[451]229 format2 = format.upper()
230 if format2 == 'ASAP':
[116]231 self._save(name)
232 else:
[989]233 from asap._asap import stwriter as stw
[1118]234 writer = stw(format2)
235 writer.write(self, name)
[116]236 return
237
[102]238 def copy(self):
[1846]239 """Return a copy of this scantable.
240
241 *Note*:
242
[1348]243 This makes a full (deep) copy. scan2 = scan1 makes a reference.
[1846]244
245 Example::
246
[102]247 copiedscan = scan.copy()
[1846]248
[102]249 """
[876]250 sd = scantable(Scantable._copy(self))
[113]251 return sd
252
[1093]253 def drop_scan(self, scanid=None):
[1846]254 """\
[1093]255 Return a new scantable where the specified scan number(s) has(have)
256 been dropped.
[1846]257
[1093]258 Parameters:
[1846]259
[1093]260 scanid: a (list of) scan number(s)
[1846]261
[1093]262 """
263 from asap import _is_sequence_or_number as _is_valid
264 from asap import _to_list
265 from asap import unique
266 if not _is_valid(scanid):
[1859]267 raise RuntimeError( 'Please specify a scanno to drop from the scantable' )
268 scanid = _to_list(scanid)
269 allscans = unique([ self.getscan(i) for i in range(self.nrow())])
270 for sid in scanid: allscans.remove(sid)
271 if len(allscans) == 0:
272 raise ValueError("Can't remove all scans")
273 sel = selector(scans=allscans)
274 return self._select_copy(sel)
[1093]275
[1594]276 def _select_copy(self, selection):
277 orig = self.get_selection()
278 self.set_selection(orig+selection)
279 cp = self.copy()
280 self.set_selection(orig)
281 return cp
282
[102]283 def get_scan(self, scanid=None):
[1855]284 """\
[102]285 Return a specific scan (by scanno) or collection of scans (by
286 source name) in a new scantable.
[1846]287
288 *Note*:
289
[1348]290 See scantable.drop_scan() for the inverse operation.
[1846]291
[102]292 Parameters:
[1846]293
[513]294 scanid: a (list of) scanno or a source name, unix-style
295 patterns are accepted for source name matching, e.g.
296 '*_R' gets all 'ref scans
[1846]297
298 Example::
299
[513]300 # get all scans containing the source '323p459'
301 newscan = scan.get_scan('323p459')
302 # get all 'off' scans
303 refscans = scan.get_scan('*_R')
304 # get a susbset of scans by scanno (as listed in scan.summary())
[1118]305 newscan = scan.get_scan([0, 2, 7, 10])
[1846]306
[102]307 """
308 if scanid is None:
[1859]309 raise RuntimeError( 'Please specify a scan no or name to '
310 'retrieve from the scantable' )
[102]311 try:
[946]312 bsel = self.get_selection()
313 sel = selector()
[102]314 if type(scanid) is str:
[946]315 sel.set_name(scanid)
[1594]316 return self._select_copy(sel)
[102]317 elif type(scanid) is int:
[946]318 sel.set_scans([scanid])
[1594]319 return self._select_copy(sel)
[381]320 elif type(scanid) is list:
[946]321 sel.set_scans(scanid)
[1594]322 return self._select_copy(sel)
[381]323 else:
[718]324 msg = "Illegal scanid type, use 'int' or 'list' if ints."
[1859]325 raise TypeError(msg)
[102]326 except RuntimeError:
[1859]327 raise
[102]328
329 def __str__(self):
[1118]330 return Scantable._summary(self, True)
[102]331
[976]332 def summary(self, filename=None):
[1846]333 """\
[102]334 Print a summary of the contents of this scantable.
[1846]335
[102]336 Parameters:
[1846]337
[102]338 filename: the name of a file to write the putput to
339 Default - no file output
[1846]340
[102]341 """
[976]342 info = Scantable._summary(self, True)
[102]343 if filename is not None:
[256]344 if filename is "":
345 filename = 'scantable_summary.txt'
[415]346 from os.path import expandvars, isdir
[411]347 filename = expandvars(filename)
[415]348 if not isdir(filename):
[413]349 data = open(filename, 'w')
350 data.write(info)
351 data.close()
352 else:
[718]353 msg = "Illegal file name '%s'." % (filename)
[1859]354 raise IOError(msg)
355 return page(info)
[710]356
[1512]357 def get_spectrum(self, rowno):
[1471]358 """Return the spectrum for the current row in the scantable as a list.
[1846]359
[1471]360 Parameters:
[1846]361
[1573]362 rowno: the row number to retrieve the spectrum from
[1846]363
[1471]364 """
365 return self._getspectrum(rowno)
[946]366
[1471]367 def get_mask(self, rowno):
368 """Return the mask for the current row in the scantable as a list.
[1846]369
[1471]370 Parameters:
[1846]371
[1573]372 rowno: the row number to retrieve the mask from
[1846]373
[1471]374 """
375 return self._getmask(rowno)
376
377 def set_spectrum(self, spec, rowno):
378 """Return the spectrum for the current row in the scantable as a list.
[1846]379
[1471]380 Parameters:
[1846]381
[1855]382 spec: the new spectrum
[1846]383
[1855]384 rowno: the row number to set the spectrum for
385
[1471]386 """
387 assert(len(spec) == self.nchan())
388 return self._setspectrum(spec, rowno)
389
[1600]390 def get_coordinate(self, rowno):
391 """Return the (spectral) coordinate for a a given 'rowno'.
[1846]392
393 *Note*:
394
[1600]395 * This coordinate is only valid until a scantable method modifies
396 the frequency axis.
397 * This coordinate does contain the original frequency set-up
398 NOT the new frame. The conversions however are done using the user
399 specified frame (e.g. LSRK/TOPO). To get the 'real' coordinate,
400 use scantable.freq_align first. Without it there is no closure,
[1846]401 i.e.::
[1600]402
[1846]403 c = myscan.get_coordinate(0)
404 c.to_frequency(c.get_reference_pixel()) != c.get_reference_value()
405
[1600]406 Parameters:
[1846]407
[1600]408 rowno: the row number for the spectral coordinate
409
410 """
411 return coordinate(Scantable.get_coordinate(self, rowno))
412
[946]413 def get_selection(self):
[1846]414 """\
[1005]415 Get the selection object currently set on this scantable.
[1846]416
417 Example::
418
[1005]419 sel = scan.get_selection()
420 sel.set_ifs(0) # select IF 0
421 scan.set_selection(sel) # apply modified selection
[1846]422
[946]423 """
424 return selector(self._getselection())
425
[1576]426 def set_selection(self, selection=None, **kw):
[1846]427 """\
[1005]428 Select a subset of the data. All following operations on this scantable
429 are only applied to thi selection.
[1846]430
[1005]431 Parameters:
[1697]432
[1846]433 selection: a selector object (default unset the selection), or
434 any combination of "pols", "ifs", "beams", "scans",
435 "cycles", "name", "query"
[1697]436
[1846]437 Examples::
[1697]438
[1005]439 sel = selector() # create a selection object
[1118]440 self.set_scans([0, 3]) # select SCANNO 0 and 3
[1005]441 scan.set_selection(sel) # set the selection
442 scan.summary() # will only print summary of scanno 0 an 3
443 scan.set_selection() # unset the selection
[1697]444 # or the equivalent
445 scan.set_selection(scans=[0,3])
446 scan.summary() # will only print summary of scanno 0 an 3
447 scan.set_selection() # unset the selection
[1846]448
[946]449 """
[1576]450 if selection is None:
451 # reset
452 if len(kw) == 0:
453 selection = selector()
454 else:
455 # try keywords
456 for k in kw:
457 if k not in selector.fields:
458 raise KeyError("Invalid selection key '%s', valid keys are %s" % (k, selector.fields))
459 selection = selector(**kw)
[946]460 self._setselection(selection)
461
[1819]462 def get_row(self, row=0, insitu=None):
[1846]463 """\
[1819]464 Select a row in the scantable.
465 Return a scantable with single row.
[1846]466
[1819]467 Parameters:
[1846]468
469 row: row no of integration, default is 0.
470 insitu: if False a new scantable is returned. Otherwise, the
471 scaling is done in-situ. The default is taken from .asaprc
472 (False)
473
[1819]474 """
475 if insitu is None: insitu = rcParams['insitu']
476 if not insitu:
477 workscan = self.copy()
478 else:
479 workscan = self
480 # Select a row
481 sel=selector()
482 sel.set_scans([workscan.getscan(row)])
483 sel.set_cycles([workscan.getcycle(row)])
484 sel.set_beams([workscan.getbeam(row)])
485 sel.set_ifs([workscan.getif(row)])
486 sel.set_polarisations([workscan.getpol(row)])
487 sel.set_name(workscan._getsourcename(row))
488 workscan.set_selection(sel)
489 if not workscan.nrow() == 1:
490 msg = "Cloud not identify single row. %d rows selected."%(workscan.nrow())
491 raise RuntimeError(msg)
492 del sel
493 if insitu:
494 self._assign(workscan)
495 else:
496 return workscan
497
[1862]498 @asaplog_post_dec
[1907]499 def stats(self, stat='stddev', mask=None, form='3.3f', row=None):
[1846]500 """\
[135]501 Determine the specified statistic of the current beam/if/pol
[102]502 Takes a 'mask' as an optional parameter to specify which
503 channels should be excluded.
[1846]504
[102]505 Parameters:
[1846]506
[1819]507 stat: 'min', 'max', 'min_abc', 'max_abc', 'sumsq', 'sum',
508 'mean', 'var', 'stddev', 'avdev', 'rms', 'median'
[1855]509
[135]510 mask: an optional mask specifying where the statistic
[102]511 should be determined.
[1855]512
[1819]513 form: format string to print statistic values
[1846]514
[1907]515 row: row number of spectrum to process.
516 (default is None: for all rows)
[1846]517
[1907]518 Example:
[113]519 scan.set_unit('channel')
[1118]520 msk = scan.create_mask([100, 200], [500, 600])
[135]521 scan.stats(stat='mean', mask=m)
[1846]522
[102]523 """
[1593]524 mask = mask or []
[876]525 if not self._check_ifs():
[1118]526 raise ValueError("Cannot apply mask as the IFs have different "
527 "number of channels. Please use setselection() "
528 "to select individual IFs")
[1819]529 rtnabc = False
530 if stat.lower().endswith('_abc'): rtnabc = True
531 getchan = False
532 if stat.lower().startswith('min') or stat.lower().startswith('max'):
533 chan = self._math._minmaxchan(self, mask, stat)
534 getchan = True
535 statvals = []
[1907]536 if not rtnabc:
537 if row == None:
538 statvals = self._math._stats(self, mask, stat)
539 else:
540 statvals = self._math._statsrow(self, mask, stat, int(row))
[256]541
[1819]542 #def cb(i):
543 # return statvals[i]
[256]544
[1819]545 #return self._row_callback(cb, stat)
[102]546
[1819]547 label=stat
548 #callback=cb
549 out = ""
550 #outvec = []
551 sep = '-'*50
[1907]552
553 if row == None:
554 rows = xrange(self.nrow())
555 elif isinstance(row, int):
556 rows = [ row ]
557
558 for i in rows:
[1819]559 refstr = ''
560 statunit= ''
561 if getchan:
562 qx, qy = self.chan2data(rowno=i, chan=chan[i])
563 if rtnabc:
564 statvals.append(qx['value'])
565 refstr = ('(value: %'+form) % (qy['value'])+' ['+qy['unit']+'])'
566 statunit= '['+qx['unit']+']'
567 else:
568 refstr = ('(@ %'+form) % (qx['value'])+' ['+qx['unit']+'])'
569
570 tm = self._gettime(i)
571 src = self._getsourcename(i)
572 out += 'Scan[%d] (%s) ' % (self.getscan(i), src)
573 out += 'Time[%s]:\n' % (tm)
[1907]574 if self.nbeam(-1) > 1: out += ' Beam[%d] ' % (self.getbeam(i))
575 if self.nif(-1) > 1: out += ' IF[%d] ' % (self.getif(i))
576 if self.npol(-1) > 1: out += ' Pol[%d] ' % (self.getpol(i))
[1819]577 #outvec.append(callback(i))
[1907]578 if len(rows) > 1:
579 # out += ('= %'+form) % (outvec[i]) +' '+refstr+'\n'
580 out += ('= %'+form) % (statvals[i]) +' '+refstr+'\n'
581 else:
582 # out += ('= %'+form) % (outvec[0]) +' '+refstr+'\n'
583 out += ('= %'+form) % (statvals[0]) +' '+refstr+'\n'
[1819]584 out += sep+"\n"
585
[1859]586 import os
587 if os.environ.has_key( 'USER' ):
588 usr = os.environ['USER']
589 else:
590 import commands
591 usr = commands.getoutput( 'whoami' )
592 tmpfile = '/tmp/tmp_'+usr+'_casapy_asap_scantable_stats'
593 f = open(tmpfile,'w')
594 print >> f, sep
595 print >> f, ' %s %s' % (label, statunit)
596 print >> f, sep
597 print >> f, out
598 f.close()
599 f = open(tmpfile,'r')
600 x = f.readlines()
601 f.close()
602 asaplog.push(''.join(x), False)
603
[1819]604 return statvals
605
606 def chan2data(self, rowno=0, chan=0):
[1846]607 """\
[1819]608 Returns channel/frequency/velocity and spectral value
609 at an arbitrary row and channel in the scantable.
[1846]610
[1819]611 Parameters:
[1846]612
[1819]613 rowno: a row number in the scantable. Default is the
614 first row, i.e. rowno=0
[1855]615
[1819]616 chan: a channel in the scantable. Default is the first
617 channel, i.e. pos=0
[1846]618
[1819]619 """
620 if isinstance(rowno, int) and isinstance(chan, int):
621 qx = {'unit': self.get_unit(),
622 'value': self._getabcissa(rowno)[chan]}
623 qy = {'unit': self.get_fluxunit(),
624 'value': self._getspectrum(rowno)[chan]}
625 return qx, qy
626
[1118]627 def stddev(self, mask=None):
[1846]628 """\
[135]629 Determine the standard deviation of the current beam/if/pol
630 Takes a 'mask' as an optional parameter to specify which
631 channels should be excluded.
[1846]632
[135]633 Parameters:
[1846]634
[135]635 mask: an optional mask specifying where the standard
636 deviation should be determined.
637
[1846]638 Example::
639
[135]640 scan.set_unit('channel')
[1118]641 msk = scan.create_mask([100, 200], [500, 600])
[135]642 scan.stddev(mask=m)
[1846]643
[135]644 """
[1118]645 return self.stats(stat='stddev', mask=mask);
[135]646
[1003]647
[1259]648 def get_column_names(self):
[1846]649 """\
[1003]650 Return a list of column names, which can be used for selection.
651 """
[1259]652 return list(Scantable.get_column_names(self))
[1003]653
[1730]654 def get_tsys(self, row=-1):
[1846]655 """\
[113]656 Return the System temperatures.
[1846]657
658 Parameters:
659
660 row: the rowno to get the information for. (default all rows)
661
[113]662 Returns:
[1846]663
[876]664 a list of Tsys values for the current selection
[1846]665
[113]666 """
[1730]667 if row > -1:
668 return self._get_column(self._gettsys, row)
[876]669 return self._row_callback(self._gettsys, "Tsys")
[256]670
[1730]671
672 def get_weather(self, row=-1):
[1846]673 """\
674 Return the weather informations.
675
676 Parameters:
677
678 row: the rowno to get the information for. (default all rows)
679
680 Returns:
681
682 a dict or list of of dicts of values for the current selection
683
684 """
685
[1730]686 values = self._get_column(self._get_weather, row)
687 if row > -1:
688 return {'temperature': values[0],
689 'pressure': values[1], 'humidity' : values[2],
690 'windspeed' : values[3], 'windaz' : values[4]
691 }
692 else:
693 out = []
694 for r in values:
695
696 out.append({'temperature': r[0],
697 'pressure': r[1], 'humidity' : r[2],
698 'windspeed' : r[3], 'windaz' : r[4]
699 })
700 return out
701
[876]702 def _row_callback(self, callback, label):
703 out = ""
[1118]704 outvec = []
[1590]705 sep = '-'*50
[876]706 for i in range(self.nrow()):
707 tm = self._gettime(i)
708 src = self._getsourcename(i)
[1590]709 out += 'Scan[%d] (%s) ' % (self.getscan(i), src)
[876]710 out += 'Time[%s]:\n' % (tm)
[1590]711 if self.nbeam(-1) > 1:
712 out += ' Beam[%d] ' % (self.getbeam(i))
713 if self.nif(-1) > 1: out += ' IF[%d] ' % (self.getif(i))
714 if self.npol(-1) > 1: out += ' Pol[%d] ' % (self.getpol(i))
[876]715 outvec.append(callback(i))
716 out += '= %3.3f\n' % (outvec[i])
[1590]717 out += sep+'\n'
[1859]718
719 asaplog.push(sep)
720 asaplog.push(" %s" % (label))
721 asaplog.push(sep)
722 asaplog.push(out)
[1861]723 asaplog.post()
[1175]724 return outvec
[256]725
[1070]726 def _get_column(self, callback, row=-1):
727 """
728 """
729 if row == -1:
730 return [callback(i) for i in range(self.nrow())]
731 else:
[1819]732 if 0 <= row < self.nrow():
[1070]733 return callback(row)
[256]734
[1070]735
[1348]736 def get_time(self, row=-1, asdatetime=False):
[1846]737 """\
[113]738 Get a list of time stamps for the observations.
[1348]739 Return a datetime object for each integration time stamp in the scantable.
[1846]740
[113]741 Parameters:
[1846]742
[1348]743 row: row no of integration. Default -1 return all rows
[1855]744
[1348]745 asdatetime: return values as datetime objects rather than strings
[1846]746
[113]747 """
[1175]748 from time import strptime
749 from datetime import datetime
[1392]750 times = self._get_column(self._gettime, row)
[1348]751 if not asdatetime:
[1392]752 return times
[1175]753 format = "%Y/%m/%d/%H:%M:%S"
754 if isinstance(times, list):
755 return [datetime(*strptime(i, format)[:6]) for i in times]
756 else:
757 return datetime(*strptime(times, format)[:6])
[102]758
[1348]759
760 def get_inttime(self, row=-1):
[1846]761 """\
[1348]762 Get a list of integration times for the observations.
763 Return a time in seconds for each integration in the scantable.
[1846]764
[1348]765 Parameters:
[1846]766
[1348]767 row: row no of integration. Default -1 return all rows.
[1846]768
[1348]769 """
[1573]770 return self._get_column(self._getinttime, row)
[1348]771
[1573]772
[714]773 def get_sourcename(self, row=-1):
[1846]774 """\
[794]775 Get a list source names for the observations.
[714]776 Return a string for each integration in the scantable.
777 Parameters:
[1846]778
[1348]779 row: row no of integration. Default -1 return all rows.
[1846]780
[714]781 """
[1070]782 return self._get_column(self._getsourcename, row)
[714]783
[794]784 def get_elevation(self, row=-1):
[1846]785 """\
[794]786 Get a list of elevations for the observations.
787 Return a float for each integration in the scantable.
[1846]788
[794]789 Parameters:
[1846]790
[1348]791 row: row no of integration. Default -1 return all rows.
[1846]792
[794]793 """
[1070]794 return self._get_column(self._getelevation, row)
[794]795
796 def get_azimuth(self, row=-1):
[1846]797 """\
[794]798 Get a list of azimuths for the observations.
799 Return a float for each integration in the scantable.
[1846]800
[794]801 Parameters:
[1348]802 row: row no of integration. Default -1 return all rows.
[1846]803
[794]804 """
[1070]805 return self._get_column(self._getazimuth, row)
[794]806
807 def get_parangle(self, row=-1):
[1846]808 """\
[794]809 Get a list of parallactic angles for the observations.
810 Return a float for each integration in the scantable.
[1846]811
[794]812 Parameters:
[1846]813
[1348]814 row: row no of integration. Default -1 return all rows.
[1846]815
[794]816 """
[1070]817 return self._get_column(self._getparangle, row)
[794]818
[1070]819 def get_direction(self, row=-1):
820 """
821 Get a list of Positions on the sky (direction) for the observations.
[1594]822 Return a string for each integration in the scantable.
[1855]823
[1070]824 Parameters:
[1855]825
[1070]826 row: row no of integration. Default -1 return all rows
[1855]827
[1070]828 """
829 return self._get_column(self._getdirection, row)
830
[1391]831 def get_directionval(self, row=-1):
[1846]832 """\
[1391]833 Get a list of Positions on the sky (direction) for the observations.
834 Return a float for each integration in the scantable.
[1846]835
[1391]836 Parameters:
[1846]837
[1391]838 row: row no of integration. Default -1 return all rows
[1846]839
[1391]840 """
841 return self._get_column(self._getdirectionvec, row)
842
[1862]843 @asaplog_post_dec
[102]844 def set_unit(self, unit='channel'):
[1846]845 """\
[102]846 Set the unit for all following operations on this scantable
[1846]847
[102]848 Parameters:
[1846]849
850 unit: optional unit, default is 'channel'. Use one of '*Hz',
851 'km/s', 'channel' or equivalent ''
852
[102]853 """
[484]854 varlist = vars()
[1118]855 if unit in ['', 'pixel', 'channel']:
[113]856 unit = ''
857 inf = list(self._getcoordinfo())
858 inf[0] = unit
859 self._setcoordinfo(inf)
[1118]860 self._add_history("set_unit", varlist)
[113]861
[1862]862 @asaplog_post_dec
[484]863 def set_instrument(self, instr):
[1846]864 """\
[1348]865 Set the instrument for subsequent processing.
[1846]866
[358]867 Parameters:
[1846]868
[710]869 instr: Select from 'ATPKSMB', 'ATPKSHOH', 'ATMOPRA',
[407]870 'DSS-43' (Tid), 'CEDUNA', and 'HOBART'
[1846]871
[358]872 """
873 self._setInstrument(instr)
[1118]874 self._add_history("set_instument", vars())
[358]875
[1862]876 @asaplog_post_dec
[1190]877 def set_feedtype(self, feedtype):
[1846]878 """\
[1190]879 Overwrite the feed type, which might not be set correctly.
[1846]880
[1190]881 Parameters:
[1846]882
[1190]883 feedtype: 'linear' or 'circular'
[1846]884
[1190]885 """
886 self._setfeedtype(feedtype)
887 self._add_history("set_feedtype", vars())
888
[1862]889 @asaplog_post_dec
[276]890 def set_doppler(self, doppler='RADIO'):
[1846]891 """\
[276]892 Set the doppler for all following operations on this scantable.
[1846]893
[276]894 Parameters:
[1846]895
[276]896 doppler: One of 'RADIO', 'OPTICAL', 'Z', 'BETA', 'GAMMA'
[1846]897
[276]898 """
[484]899 varlist = vars()
[276]900 inf = list(self._getcoordinfo())
901 inf[2] = doppler
902 self._setcoordinfo(inf)
[1118]903 self._add_history("set_doppler", vars())
[710]904
[1862]905 @asaplog_post_dec
[226]906 def set_freqframe(self, frame=None):
[1846]907 """\
[113]908 Set the frame type of the Spectral Axis.
[1846]909
[113]910 Parameters:
[1846]911
[591]912 frame: an optional frame type, default 'LSRK'. Valid frames are:
[1819]913 'TOPO', 'LSRD', 'LSRK', 'BARY',
[1118]914 'GEO', 'GALACTO', 'LGROUP', 'CMB'
[1846]915
916 Example::
917
[113]918 scan.set_freqframe('BARY')
[1846]919
[113]920 """
[1593]921 frame = frame or rcParams['scantable.freqframe']
[484]922 varlist = vars()
[1819]923 # "REST" is not implemented in casacore
924 #valid = ['REST', 'TOPO', 'LSRD', 'LSRK', 'BARY', \
925 # 'GEO', 'GALACTO', 'LGROUP', 'CMB']
926 valid = ['TOPO', 'LSRD', 'LSRK', 'BARY', \
[1118]927 'GEO', 'GALACTO', 'LGROUP', 'CMB']
[591]928
[989]929 if frame in valid:
[113]930 inf = list(self._getcoordinfo())
931 inf[1] = frame
932 self._setcoordinfo(inf)
[1118]933 self._add_history("set_freqframe", varlist)
[102]934 else:
[1118]935 msg = "Please specify a valid freq type. Valid types are:\n", valid
[1859]936 raise TypeError(msg)
[710]937
[1862]938 @asaplog_post_dec
[989]939 def set_dirframe(self, frame=""):
[1846]940 """\
[989]941 Set the frame type of the Direction on the sky.
[1846]942
[989]943 Parameters:
[1846]944
[989]945 frame: an optional frame type, default ''. Valid frames are:
946 'J2000', 'B1950', 'GALACTIC'
[1846]947
948 Example:
949
[989]950 scan.set_dirframe('GALACTIC')
[1846]951
[989]952 """
953 varlist = vars()
[1859]954 Scantable.set_dirframe(self, frame)
[1118]955 self._add_history("set_dirframe", varlist)
[989]956
[113]957 def get_unit(self):
[1846]958 """\
[113]959 Get the default unit set in this scantable
[1846]960
[113]961 Returns:
[1846]962
[113]963 A unit string
[1846]964
[113]965 """
966 inf = self._getcoordinfo()
967 unit = inf[0]
968 if unit == '': unit = 'channel'
969 return unit
[102]970
[1862]971 @asaplog_post_dec
[158]972 def get_abcissa(self, rowno=0):
[1846]973 """\
[158]974 Get the abcissa in the current coordinate setup for the currently
[113]975 selected Beam/IF/Pol
[1846]976
[113]977 Parameters:
[1846]978
[226]979 rowno: an optional row number in the scantable. Default is the
980 first row, i.e. rowno=0
[1846]981
[113]982 Returns:
[1846]983
[1348]984 The abcissa values and the format string (as a dictionary)
[1846]985
[113]986 """
[256]987 abc = self._getabcissa(rowno)
[710]988 lbl = self._getabcissalabel(rowno)
[158]989 return abc, lbl
[113]990
[1862]991 @asaplog_post_dec
[1819]992 def flag(self, mask=None, unflag=False):
[1846]993 """\
[1001]994 Flag the selected data using an optional channel mask.
[1846]995
[1001]996 Parameters:
[1846]997
[1001]998 mask: an optional channel mask, created with create_mask. Default
999 (no mask) is all channels.
[1855]1000
[1819]1001 unflag: if True, unflag the data
[1846]1002
[1001]1003 """
1004 varlist = vars()
[1593]1005 mask = mask or []
[1859]1006 self._flag(mask, unflag)
[1001]1007 self._add_history("flag", varlist)
1008
[1862]1009 @asaplog_post_dec
[1819]1010 def flag_row(self, rows=[], unflag=False):
[1846]1011 """\
[1819]1012 Flag the selected data in row-based manner.
[1846]1013
[1819]1014 Parameters:
[1846]1015
[1843]1016 rows: list of row numbers to be flagged. Default is no row
1017 (must be explicitly specified to execute row-based flagging).
[1855]1018
[1819]1019 unflag: if True, unflag the data.
[1846]1020
[1819]1021 """
1022 varlist = vars()
[1859]1023 self._flag_row(rows, unflag)
[1819]1024 self._add_history("flag_row", varlist)
1025
[1862]1026 @asaplog_post_dec
[1819]1027 def clip(self, uthres=None, dthres=None, clipoutside=True, unflag=False):
[1846]1028 """\
[1819]1029 Flag the selected data outside a specified range (in channel-base)
[1846]1030
[1819]1031 Parameters:
[1846]1032
[1819]1033 uthres: upper threshold.
[1855]1034
[1819]1035 dthres: lower threshold
[1846]1036
[1819]1037 clipoutside: True for flagging data outside the range [dthres:uthres].
1038 False for glagging data inside the range.
[1855]1039
[1846]1040 unflag: if True, unflag the data.
1041
[1819]1042 """
1043 varlist = vars()
[1859]1044 self._clip(uthres, dthres, clipoutside, unflag)
[1819]1045 self._add_history("clip", varlist)
1046
[1862]1047 @asaplog_post_dec
[1584]1048 def lag_flag(self, start, end, unit="MHz", insitu=None):
[1846]1049 """\
[1192]1050 Flag the data in 'lag' space by providing a frequency to remove.
[1584]1051 Flagged data in the scantable gets interpolated over the region.
[1192]1052 No taper is applied.
[1846]1053
[1192]1054 Parameters:
[1846]1055
[1579]1056 start: the start frequency (really a period within the
1057 bandwidth) or period to remove
[1855]1058
[1579]1059 end: the end frequency or period to remove
[1855]1060
[1584]1061 unit: the frequency unit (default "MHz") or "" for
[1579]1062 explicit lag channels
[1846]1063
1064 *Notes*:
1065
[1579]1066 It is recommended to flag edges of the band or strong
[1348]1067 signals beforehand.
[1846]1068
[1192]1069 """
1070 if insitu is None: insitu = rcParams['insitu']
1071 self._math._setinsitu(insitu)
1072 varlist = vars()
[1579]1073 base = { "GHz": 1000000000., "MHz": 1000000., "kHz": 1000., "Hz": 1.}
1074 if not (unit == "" or base.has_key(unit)):
[1192]1075 raise ValueError("%s is not a valid unit." % unit)
[1859]1076 if unit == "":
1077 s = scantable(self._math._lag_flag(self, start, end, "lags"))
1078 else:
1079 s = scantable(self._math._lag_flag(self, start*base[unit],
1080 end*base[unit], "frequency"))
[1192]1081 s._add_history("lag_flag", varlist)
1082 if insitu:
1083 self._assign(s)
1084 else:
1085 return s
[1001]1086
[1862]1087 @asaplog_post_dec
[113]1088 def create_mask(self, *args, **kwargs):
[1846]1089 """\
[1118]1090 Compute and return a mask based on [min, max] windows.
[189]1091 The specified windows are to be INCLUDED, when the mask is
[113]1092 applied.
[1846]1093
[102]1094 Parameters:
[1846]1095
[1118]1096 [min, max], [min2, max2], ...
[1024]1097 Pairs of start/end points (inclusive)specifying the regions
[102]1098 to be masked
[1855]1099
[189]1100 invert: optional argument. If specified as True,
1101 return an inverted mask, i.e. the regions
1102 specified are EXCLUDED
[1855]1103
[513]1104 row: create the mask using the specified row for
1105 unit conversions, default is row=0
1106 only necessary if frequency varies over rows.
[1846]1107
1108 Examples::
1109
[113]1110 scan.set_unit('channel')
[1846]1111 # a)
[1118]1112 msk = scan.create_mask([400, 500], [800, 900])
[189]1113 # masks everything outside 400 and 500
[113]1114 # and 800 and 900 in the unit 'channel'
1115
[1846]1116 # b)
[1118]1117 msk = scan.create_mask([400, 500], [800, 900], invert=True)
[189]1118 # masks the regions between 400 and 500
[113]1119 # and 800 and 900 in the unit 'channel'
[1846]1120
1121 # c)
1122 #mask only channel 400
[1554]1123 msk = scan.create_mask([400])
[1846]1124
[102]1125 """
[1554]1126 row = kwargs.get("row", 0)
[513]1127 data = self._getabcissa(row)
[113]1128 u = self._getcoordinfo()[0]
[1859]1129 if u == "":
1130 u = "channel"
1131 msg = "The current mask window unit is %s" % u
1132 i = self._check_ifs()
1133 if not i:
1134 msg += "\nThis mask is only valid for IF=%d" % (self.getif(i))
1135 asaplog.push(msg)
[102]1136 n = self.nchan()
[1295]1137 msk = _n_bools(n, False)
[710]1138 # test if args is a 'list' or a 'normal *args - UGLY!!!
1139
[1118]1140 ws = (isinstance(args[-1][-1], int) or isinstance(args[-1][-1], float)) \
1141 and args or args[0]
[710]1142 for window in ws:
[1554]1143 if len(window) == 1:
1144 window = [window[0], window[0]]
1145 if len(window) == 0 or len(window) > 2:
1146 raise ValueError("A window needs to be defined as [start(, end)]")
[1545]1147 if window[0] > window[1]:
1148 tmp = window[0]
1149 window[0] = window[1]
1150 window[1] = tmp
[102]1151 for i in range(n):
[1024]1152 if data[i] >= window[0] and data[i] <= window[1]:
[1295]1153 msk[i] = True
[113]1154 if kwargs.has_key('invert'):
1155 if kwargs.get('invert'):
[1295]1156 msk = mask_not(msk)
[102]1157 return msk
[710]1158
[1819]1159 def get_masklist(self, mask=None, row=0):
[1846]1160 """\
[1819]1161 Compute and return a list of mask windows, [min, max].
[1846]1162
[1819]1163 Parameters:
[1846]1164
[1819]1165 mask: channel mask, created with create_mask.
[1855]1166
[1819]1167 row: calcutate the masklist using the specified row
1168 for unit conversions, default is row=0
1169 only necessary if frequency varies over rows.
[1846]1170
[1819]1171 Returns:
[1846]1172
[1819]1173 [min, max], [min2, max2], ...
1174 Pairs of start/end points (inclusive)specifying
1175 the masked regions
[1846]1176
[1819]1177 """
1178 if not (isinstance(mask,list) or isinstance(mask, tuple)):
1179 raise TypeError("The mask should be list or tuple.")
1180 if len(mask) < 2:
1181 raise TypeError("The mask elements should be > 1")
1182 if self.nchan() != len(mask):
1183 msg = "Number of channels in scantable != number of mask elements"
1184 raise TypeError(msg)
1185 data = self._getabcissa(row)
1186 u = self._getcoordinfo()[0]
[1859]1187 if u == "":
1188 u = "channel"
1189 msg = "The current mask window unit is %s" % u
1190 i = self._check_ifs()
1191 if not i:
1192 msg += "\nThis mask is only valid for IF=%d" % (self.getif(i))
1193 asaplog.push(msg)
[1819]1194 masklist=[]
1195 ist, ien = None, None
1196 ist, ien=self.get_mask_indices(mask)
1197 if ist is not None and ien is not None:
1198 for i in xrange(len(ist)):
1199 range=[data[ist[i]],data[ien[i]]]
1200 range.sort()
1201 masklist.append([range[0],range[1]])
1202 return masklist
1203
1204 def get_mask_indices(self, mask=None):
[1846]1205 """\
[1819]1206 Compute and Return lists of mask start indices and mask end indices.
[1855]1207
1208 Parameters:
1209
[1819]1210 mask: channel mask, created with create_mask.
[1846]1211
[1819]1212 Returns:
[1846]1213
[1819]1214 List of mask start indices and that of mask end indices,
1215 i.e., [istart1,istart2,....], [iend1,iend2,....].
[1846]1216
[1819]1217 """
1218 if not (isinstance(mask,list) or isinstance(mask, tuple)):
1219 raise TypeError("The mask should be list or tuple.")
1220 if len(mask) < 2:
1221 raise TypeError("The mask elements should be > 1")
1222 istart=[]
1223 iend=[]
1224 if mask[0]: istart.append(0)
1225 for i in range(len(mask)-1):
1226 if not mask[i] and mask[i+1]:
1227 istart.append(i+1)
1228 elif mask[i] and not mask[i+1]:
1229 iend.append(i)
1230 if mask[len(mask)-1]: iend.append(len(mask)-1)
1231 if len(istart) != len(iend):
1232 raise RuntimeError("Numbers of mask start != mask end.")
1233 for i in range(len(istart)):
1234 if istart[i] > iend[i]:
1235 raise RuntimeError("Mask start index > mask end index")
1236 break
1237 return istart,iend
1238
1239# def get_restfreqs(self):
1240# """
1241# Get the restfrequency(s) stored in this scantable.
1242# The return value(s) are always of unit 'Hz'
1243# Parameters:
1244# none
1245# Returns:
1246# a list of doubles
1247# """
1248# return list(self._getrestfreqs())
1249
1250 def get_restfreqs(self, ids=None):
[1846]1251 """\
[256]1252 Get the restfrequency(s) stored in this scantable.
1253 The return value(s) are always of unit 'Hz'
[1846]1254
[256]1255 Parameters:
[1846]1256
[1819]1257 ids: (optional) a list of MOLECULE_ID for that restfrequency(s) to
1258 be retrieved
[1846]1259
[256]1260 Returns:
[1846]1261
[1819]1262 dictionary containing ids and a list of doubles for each id
[1846]1263
[256]1264 """
[1819]1265 if ids is None:
1266 rfreqs={}
1267 idlist = self.getmolnos()
1268 for i in idlist:
1269 rfreqs[i]=list(self._getrestfreqs(i))
1270 return rfreqs
1271 else:
1272 if type(ids)==list or type(ids)==tuple:
1273 rfreqs={}
1274 for i in ids:
1275 rfreqs[i]=list(self._getrestfreqs(i))
1276 return rfreqs
1277 else:
1278 return list(self._getrestfreqs(ids))
1279 #return list(self._getrestfreqs(ids))
[102]1280
[931]1281 def set_restfreqs(self, freqs=None, unit='Hz'):
[1846]1282 """\
[931]1283 Set or replace the restfrequency specified and
1284 If the 'freqs' argument holds a scalar,
1285 then that rest frequency will be applied to all the selected
1286 data. If the 'freqs' argument holds
1287 a vector, then it MUST be of equal or smaller length than
1288 the number of IFs (and the available restfrequencies will be
1289 replaced by this vector). In this case, *all* data have
1290 the restfrequency set per IF according
1291 to the corresponding value you give in the 'freqs' vector.
[1118]1292 E.g. 'freqs=[1e9, 2e9]' would mean IF 0 gets restfreq 1e9 and
[931]1293 IF 1 gets restfreq 2e9.
[1846]1294
[1395]1295 You can also specify the frequencies via a linecatalog.
[1153]1296
[931]1297 Parameters:
[1846]1298
[931]1299 freqs: list of rest frequency values or string idenitfiers
[1855]1300
[931]1301 unit: unit for rest frequency (default 'Hz')
[402]1302
[1846]1303
1304 Example::
1305
[1819]1306 # set the given restfrequency for the all currently selected IFs
[931]1307 scan.set_restfreqs(freqs=1.4e9)
[1845]1308 # set restfrequencies for the n IFs (n > 1) in the order of the
1309 # list, i.e
1310 # IF0 -> 1.4e9, IF1 -> 1.41e9, IF3 -> 1.42e9
1311 # len(list_of_restfreqs) == nIF
1312 # for nIF == 1 the following will set multiple restfrequency for
1313 # that IF
[1819]1314 scan.set_restfreqs(freqs=[1.4e9, 1.41e9, 1.42e9])
[1845]1315 # set multiple restfrequencies per IF. as a list of lists where
1316 # the outer list has nIF elements, the inner s arbitrary
1317 scan.set_restfreqs(freqs=[[1.4e9, 1.41e9], [1.67e9]])
[391]1318
[1846]1319 *Note*:
[1845]1320
[931]1321 To do more sophisticate Restfrequency setting, e.g. on a
1322 source and IF basis, use scantable.set_selection() before using
[1846]1323 this function::
[931]1324
[1846]1325 # provided your scantable is called scan
1326 selection = selector()
1327 selection.set_name("ORION*")
1328 selection.set_ifs([1])
1329 scan.set_selection(selection)
1330 scan.set_restfreqs(freqs=86.6e9)
1331
[931]1332 """
1333 varlist = vars()
[1157]1334 from asap import linecatalog
1335 # simple value
[1118]1336 if isinstance(freqs, int) or isinstance(freqs, float):
[1845]1337 self._setrestfreqs([freqs], [""], unit)
[1157]1338 # list of values
[1118]1339 elif isinstance(freqs, list) or isinstance(freqs, tuple):
[1157]1340 # list values are scalars
[1118]1341 if isinstance(freqs[-1], int) or isinstance(freqs[-1], float):
[1845]1342 if len(freqs) == 1:
1343 self._setrestfreqs(freqs, [""], unit)
1344 else:
1345 # allow the 'old' mode of setting mulitple IFs
1346 sel = selector()
1347 savesel = self._getselection()
1348 iflist = self.getifnos()
1349 if len(freqs)>len(iflist):
1350 raise ValueError("number of elements in list of list "
1351 "exeeds the current IF selections")
1352 iflist = self.getifnos()
1353 for i, fval in enumerate(freqs):
1354 sel.set_ifs(iflist[i])
1355 self._setselection(sel)
1356 self._setrestfreqs([fval], [""], unit)
1357 self._setselection(savesel)
1358
1359 # list values are dict, {'value'=, 'name'=)
[1157]1360 elif isinstance(freqs[-1], dict):
[1845]1361 values = []
1362 names = []
1363 for d in freqs:
1364 values.append(d["value"])
1365 names.append(d["name"])
1366 self._setrestfreqs(values, names, unit)
[1819]1367 elif isinstance(freqs[-1], list) or isinstance(freqs[-1], tuple):
[1157]1368 sel = selector()
1369 savesel = self._getselection()
[1322]1370 iflist = self.getifnos()
[1819]1371 if len(freqs)>len(iflist):
[1845]1372 raise ValueError("number of elements in list of list exeeds"
1373 " the current IF selections")
1374 for i, fval in enumerate(freqs):
[1322]1375 sel.set_ifs(iflist[i])
[1259]1376 self._setselection(sel)
[1845]1377 self._setrestfreqs(fval, [""], unit)
[1157]1378 self._setselection(savesel)
1379 # freqs are to be taken from a linecatalog
[1153]1380 elif isinstance(freqs, linecatalog):
1381 sel = selector()
1382 savesel = self._getselection()
1383 for i in xrange(freqs.nrow()):
[1322]1384 sel.set_ifs(iflist[i])
[1153]1385 self._setselection(sel)
[1845]1386 self._setrestfreqs([freqs.get_frequency(i)],
1387 [freqs.get_name(i)], "MHz")
[1153]1388 # ensure that we are not iterating past nIF
1389 if i == self.nif()-1: break
1390 self._setselection(savesel)
[931]1391 else:
1392 return
1393 self._add_history("set_restfreqs", varlist)
1394
[1360]1395 def shift_refpix(self, delta):
[1846]1396 """\
[1589]1397 Shift the reference pixel of the Spectra Coordinate by an
1398 integer amount.
[1846]1399
[1589]1400 Parameters:
[1846]1401
[1589]1402 delta: the amount to shift by
[1846]1403
1404 *Note*:
1405
[1589]1406 Be careful using this with broadband data.
[1846]1407
[1360]1408 """
[1731]1409 Scantable.shift_refpix(self, delta)
[931]1410
[1862]1411 @asaplog_post_dec
[1259]1412 def history(self, filename=None):
[1846]1413 """\
[1259]1414 Print the history. Optionally to a file.
[1846]1415
[1348]1416 Parameters:
[1846]1417
[1348]1418 filename: The name of the file to save the history to.
[1846]1419
[1259]1420 """
[484]1421 hist = list(self._gethistory())
[794]1422 out = "-"*80
[484]1423 for h in hist:
[489]1424 if h.startswith("---"):
[1857]1425 out = "\n".join([out, h])
[489]1426 else:
1427 items = h.split("##")
1428 date = items[0]
1429 func = items[1]
1430 items = items[2:]
[794]1431 out += "\n"+date+"\n"
1432 out += "Function: %s\n Parameters:" % (func)
[489]1433 for i in items:
1434 s = i.split("=")
[1118]1435 out += "\n %s = %s" % (s[0], s[1])
[1857]1436 out = "\n".join([out, "-"*80])
[1259]1437 if filename is not None:
1438 if filename is "":
1439 filename = 'scantable_history.txt'
1440 import os
1441 filename = os.path.expandvars(os.path.expanduser(filename))
1442 if not os.path.isdir(filename):
1443 data = open(filename, 'w')
1444 data.write(out)
1445 data.close()
1446 else:
1447 msg = "Illegal file name '%s'." % (filename)
[1859]1448 raise IOError(msg)
1449 return page(out)
[513]1450 #
1451 # Maths business
1452 #
[1862]1453 @asaplog_post_dec
[931]1454 def average_time(self, mask=None, scanav=False, weight='tint', align=False):
[1846]1455 """\
[1070]1456 Return the (time) weighted average of a scan.
[1846]1457
1458 *Note*:
1459
[1070]1460 in channels only - align if necessary
[1846]1461
[513]1462 Parameters:
[1846]1463
[513]1464 mask: an optional mask (only used for 'var' and 'tsys'
1465 weighting)
[1855]1466
[558]1467 scanav: True averages each scan separately
1468 False (default) averages all scans together,
[1855]1469
[1099]1470 weight: Weighting scheme.
1471 'none' (mean no weight)
1472 'var' (1/var(spec) weighted)
1473 'tsys' (1/Tsys**2 weighted)
1474 'tint' (integration time weighted)
1475 'tintsys' (Tint/Tsys**2)
1476 'median' ( median averaging)
[535]1477 The default is 'tint'
[1855]1478
[931]1479 align: align the spectra in velocity before averaging. It takes
1480 the time of the first spectrum as reference time.
[1846]1481
1482 Example::
1483
[513]1484 # time average the scantable without using a mask
[710]1485 newscan = scan.average_time()
[1846]1486
[513]1487 """
1488 varlist = vars()
[1593]1489 weight = weight or 'TINT'
1490 mask = mask or ()
1491 scanav = (scanav and 'SCAN') or 'NONE'
[1118]1492 scan = (self, )
[1859]1493
1494 if align:
1495 scan = (self.freq_align(insitu=False), )
1496 s = None
1497 if weight.upper() == 'MEDIAN':
1498 s = scantable(self._math._averagechannel(scan[0], 'MEDIAN',
1499 scanav))
1500 else:
1501 s = scantable(self._math._average(scan, mask, weight.upper(),
1502 scanav))
[1099]1503 s._add_history("average_time", varlist)
[513]1504 return s
[710]1505
[1862]1506 @asaplog_post_dec
[876]1507 def convert_flux(self, jyperk=None, eta=None, d=None, insitu=None):
[1846]1508 """\
[513]1509 Return a scan where all spectra are converted to either
1510 Jansky or Kelvin depending upon the flux units of the scan table.
1511 By default the function tries to look the values up internally.
1512 If it can't find them (or if you want to over-ride), you must
1513 specify EITHER jyperk OR eta (and D which it will try to look up
1514 also if you don't set it). jyperk takes precedence if you set both.
[1846]1515
[513]1516 Parameters:
[1846]1517
[513]1518 jyperk: the Jy / K conversion factor
[1855]1519
[513]1520 eta: the aperture efficiency
[1855]1521
[513]1522 d: the geomtric diameter (metres)
[1855]1523
[513]1524 insitu: if False a new scantable is returned.
1525 Otherwise, the scaling is done in-situ
1526 The default is taken from .asaprc (False)
[1846]1527
[513]1528 """
1529 if insitu is None: insitu = rcParams['insitu']
[876]1530 self._math._setinsitu(insitu)
[513]1531 varlist = vars()
[1593]1532 jyperk = jyperk or -1.0
1533 d = d or -1.0
1534 eta = eta or -1.0
[876]1535 s = scantable(self._math._convertflux(self, d, eta, jyperk))
1536 s._add_history("convert_flux", varlist)
1537 if insitu: self._assign(s)
1538 else: return s
[513]1539
[1862]1540 @asaplog_post_dec
[876]1541 def gain_el(self, poly=None, filename="", method="linear", insitu=None):
[1846]1542 """\
[513]1543 Return a scan after applying a gain-elevation correction.
1544 The correction can be made via either a polynomial or a
1545 table-based interpolation (and extrapolation if necessary).
1546 You specify polynomial coefficients, an ascii table or neither.
1547 If you specify neither, then a polynomial correction will be made
1548 with built in coefficients known for certain telescopes (an error
1549 will occur if the instrument is not known).
1550 The data and Tsys are *divided* by the scaling factors.
[1846]1551
[513]1552 Parameters:
[1846]1553
[513]1554 poly: Polynomial coefficients (default None) to compute a
1555 gain-elevation correction as a function of
1556 elevation (in degrees).
[1855]1557
[513]1558 filename: The name of an ascii file holding correction factors.
1559 The first row of the ascii file must give the column
1560 names and these MUST include columns
1561 "ELEVATION" (degrees) and "FACTOR" (multiply data
1562 by this) somewhere.
1563 The second row must give the data type of the
1564 column. Use 'R' for Real and 'I' for Integer.
1565 An example file would be
1566 (actual factors are arbitrary) :
1567
1568 TIME ELEVATION FACTOR
1569 R R R
1570 0.1 0 0.8
1571 0.2 20 0.85
1572 0.3 40 0.9
1573 0.4 60 0.85
1574 0.5 80 0.8
1575 0.6 90 0.75
[1855]1576
[513]1577 method: Interpolation method when correcting from a table.
1578 Values are "nearest", "linear" (default), "cubic"
1579 and "spline"
[1855]1580
[513]1581 insitu: if False a new scantable is returned.
1582 Otherwise, the scaling is done in-situ
1583 The default is taken from .asaprc (False)
[1846]1584
[513]1585 """
1586
1587 if insitu is None: insitu = rcParams['insitu']
[876]1588 self._math._setinsitu(insitu)
[513]1589 varlist = vars()
[1593]1590 poly = poly or ()
[513]1591 from os.path import expandvars
1592 filename = expandvars(filename)
[876]1593 s = scantable(self._math._gainel(self, poly, filename, method))
1594 s._add_history("gain_el", varlist)
[1593]1595 if insitu:
1596 self._assign(s)
1597 else:
1598 return s
[710]1599
[1862]1600 @asaplog_post_dec
[931]1601 def freq_align(self, reftime=None, method='cubic', insitu=None):
[1846]1602 """\
[513]1603 Return a scan where all rows have been aligned in frequency/velocity.
1604 The alignment frequency frame (e.g. LSRK) is that set by function
1605 set_freqframe.
[1846]1606
[513]1607 Parameters:
[1855]1608
[513]1609 reftime: reference time to align at. By default, the time of
1610 the first row of data is used.
[1855]1611
[513]1612 method: Interpolation method for regridding the spectra.
1613 Choose from "nearest", "linear", "cubic" (default)
1614 and "spline"
[1855]1615
[513]1616 insitu: if False a new scantable is returned.
1617 Otherwise, the scaling is done in-situ
1618 The default is taken from .asaprc (False)
[1846]1619
[513]1620 """
[931]1621 if insitu is None: insitu = rcParams["insitu"]
[876]1622 self._math._setinsitu(insitu)
[513]1623 varlist = vars()
[1593]1624 reftime = reftime or ""
[931]1625 s = scantable(self._math._freq_align(self, reftime, method))
[876]1626 s._add_history("freq_align", varlist)
1627 if insitu: self._assign(s)
1628 else: return s
[513]1629
[1862]1630 @asaplog_post_dec
[1725]1631 def opacity(self, tau=None, insitu=None):
[1846]1632 """\
[513]1633 Apply an opacity correction. The data
1634 and Tsys are multiplied by the correction factor.
[1846]1635
[513]1636 Parameters:
[1855]1637
[1689]1638 tau: (list of) opacity from which the correction factor is
[513]1639 exp(tau*ZD)
[1689]1640 where ZD is the zenith-distance.
1641 If a list is provided, it has to be of length nIF,
1642 nIF*nPol or 1 and in order of IF/POL, e.g.
1643 [opif0pol0, opif0pol1, opif1pol0 ...]
[1725]1644 if tau is `None` the opacities are determined from a
1645 model.
[1855]1646
[513]1647 insitu: if False a new scantable is returned.
1648 Otherwise, the scaling is done in-situ
1649 The default is taken from .asaprc (False)
[1846]1650
[513]1651 """
1652 if insitu is None: insitu = rcParams['insitu']
[876]1653 self._math._setinsitu(insitu)
[513]1654 varlist = vars()
[1689]1655 if not hasattr(tau, "__len__"):
1656 tau = [tau]
[876]1657 s = scantable(self._math._opacity(self, tau))
1658 s._add_history("opacity", varlist)
1659 if insitu: self._assign(s)
1660 else: return s
[513]1661
[1862]1662 @asaplog_post_dec
[513]1663 def bin(self, width=5, insitu=None):
[1846]1664 """\
[513]1665 Return a scan where all spectra have been binned up.
[1846]1666
[1348]1667 Parameters:
[1846]1668
[513]1669 width: The bin width (default=5) in pixels
[1855]1670
[513]1671 insitu: if False a new scantable is returned.
1672 Otherwise, the scaling is done in-situ
1673 The default is taken from .asaprc (False)
[1846]1674
[513]1675 """
1676 if insitu is None: insitu = rcParams['insitu']
[876]1677 self._math._setinsitu(insitu)
[513]1678 varlist = vars()
[876]1679 s = scantable(self._math._bin(self, width))
[1118]1680 s._add_history("bin", varlist)
[1589]1681 if insitu:
1682 self._assign(s)
1683 else:
1684 return s
[513]1685
[1862]1686 @asaplog_post_dec
[513]1687 def resample(self, width=5, method='cubic', insitu=None):
[1846]1688 """\
[1348]1689 Return a scan where all spectra have been binned up.
[1573]1690
[1348]1691 Parameters:
[1846]1692
[513]1693 width: The bin width (default=5) in pixels
[1855]1694
[513]1695 method: Interpolation method when correcting from a table.
1696 Values are "nearest", "linear", "cubic" (default)
1697 and "spline"
[1855]1698
[513]1699 insitu: if False a new scantable is returned.
1700 Otherwise, the scaling is done in-situ
1701 The default is taken from .asaprc (False)
[1846]1702
[513]1703 """
1704 if insitu is None: insitu = rcParams['insitu']
[876]1705 self._math._setinsitu(insitu)
[513]1706 varlist = vars()
[876]1707 s = scantable(self._math._resample(self, method, width))
[1118]1708 s._add_history("resample", varlist)
[876]1709 if insitu: self._assign(s)
1710 else: return s
[513]1711
[1862]1712 @asaplog_post_dec
[946]1713 def average_pol(self, mask=None, weight='none'):
[1846]1714 """\
[946]1715 Average the Polarisations together.
[1846]1716
[946]1717 Parameters:
[1846]1718
[946]1719 mask: An optional mask defining the region, where the
1720 averaging will be applied. The output will have all
1721 specified points masked.
[1855]1722
[946]1723 weight: Weighting scheme. 'none' (default), 'var' (1/var(spec)
1724 weighted), or 'tsys' (1/Tsys**2 weighted)
[1846]1725
[946]1726 """
1727 varlist = vars()
[1593]1728 mask = mask or ()
[1010]1729 s = scantable(self._math._averagepol(self, mask, weight.upper()))
[1118]1730 s._add_history("average_pol", varlist)
[992]1731 return s
[513]1732
[1862]1733 @asaplog_post_dec
[1145]1734 def average_beam(self, mask=None, weight='none'):
[1846]1735 """\
[1145]1736 Average the Beams together.
[1846]1737
[1145]1738 Parameters:
1739 mask: An optional mask defining the region, where the
1740 averaging will be applied. The output will have all
1741 specified points masked.
[1855]1742
[1145]1743 weight: Weighting scheme. 'none' (default), 'var' (1/var(spec)
1744 weighted), or 'tsys' (1/Tsys**2 weighted)
[1846]1745
[1145]1746 """
1747 varlist = vars()
[1593]1748 mask = mask or ()
[1145]1749 s = scantable(self._math._averagebeams(self, mask, weight.upper()))
1750 s._add_history("average_beam", varlist)
1751 return s
1752
[1586]1753 def parallactify(self, pflag):
[1846]1754 """\
[1843]1755 Set a flag to indicate whether this data should be treated as having
[1617]1756 been 'parallactified' (total phase == 0.0)
[1846]1757
[1617]1758 Parameters:
[1855]1759
[1843]1760 pflag: Bool indicating whether to turn this on (True) or
[1617]1761 off (False)
[1846]1762
[1617]1763 """
[1586]1764 varlist = vars()
1765 self._parallactify(pflag)
1766 self._add_history("parallactify", varlist)
1767
[1862]1768 @asaplog_post_dec
[992]1769 def convert_pol(self, poltype=None):
[1846]1770 """\
[992]1771 Convert the data to a different polarisation type.
[1565]1772 Note that you will need cross-polarisation terms for most conversions.
[1846]1773
[992]1774 Parameters:
[1855]1775
[992]1776 poltype: The new polarisation type. Valid types are:
[1565]1777 "linear", "circular", "stokes" and "linpol"
[1846]1778
[992]1779 """
1780 varlist = vars()
[1859]1781 s = scantable(self._math._convertpol(self, poltype))
[1118]1782 s._add_history("convert_pol", varlist)
[992]1783 return s
1784
[1862]1785 @asaplog_post_dec
[1819]1786 def smooth(self, kernel="hanning", width=5.0, order=2, plot=False, insitu=None):
[1846]1787 """\
[513]1788 Smooth the spectrum by the specified kernel (conserving flux).
[1846]1789
[513]1790 Parameters:
[1846]1791
[513]1792 kernel: The type of smoothing kernel. Select from
[1574]1793 'hanning' (default), 'gaussian', 'boxcar', 'rmedian'
1794 or 'poly'
[1855]1795
[513]1796 width: The width of the kernel in pixels. For hanning this is
1797 ignored otherwise it defauls to 5 pixels.
1798 For 'gaussian' it is the Full Width Half
1799 Maximum. For 'boxcar' it is the full width.
[1574]1800 For 'rmedian' and 'poly' it is the half width.
[1855]1801
[1574]1802 order: Optional parameter for 'poly' kernel (default is 2), to
1803 specify the order of the polnomial. Ignored by all other
1804 kernels.
[1855]1805
[1819]1806 plot: plot the original and the smoothed spectra.
1807 In this each indivual fit has to be approved, by
1808 typing 'y' or 'n'
[1855]1809
[513]1810 insitu: if False a new scantable is returned.
1811 Otherwise, the scaling is done in-situ
1812 The default is taken from .asaprc (False)
[1846]1813
[513]1814 """
1815 if insitu is None: insitu = rcParams['insitu']
[876]1816 self._math._setinsitu(insitu)
[513]1817 varlist = vars()
[1819]1818
1819 if plot: orgscan = self.copy()
1820
[1574]1821 s = scantable(self._math._smooth(self, kernel.lower(), width, order))
[876]1822 s._add_history("smooth", varlist)
[1819]1823
1824 if plot:
1825 if rcParams['plotter.gui']:
1826 from asap.asaplotgui import asaplotgui as asaplot
1827 else:
1828 from asap.asaplot import asaplot
1829 self._p=asaplot()
1830 self._p.set_panels()
1831 ylab=s._get_ordinate_label()
1832 #self._p.palette(0,["#777777","red"])
1833 for r in xrange(s.nrow()):
1834 xsm=s._getabcissa(r)
1835 ysm=s._getspectrum(r)
1836 xorg=orgscan._getabcissa(r)
1837 yorg=orgscan._getspectrum(r)
1838 self._p.clear()
1839 self._p.hold()
1840 self._p.set_axes('ylabel',ylab)
1841 self._p.set_axes('xlabel',s._getabcissalabel(r))
1842 self._p.set_axes('title',s._getsourcename(r))
1843 self._p.set_line(label='Original',color="#777777")
1844 self._p.plot(xorg,yorg)
1845 self._p.set_line(label='Smoothed',color="red")
1846 self._p.plot(xsm,ysm)
1847 ### Ugly part for legend
1848 for i in [0,1]:
1849 self._p.subplots[0]['lines'].append([self._p.subplots[0]['axes'].lines[i]])
1850 self._p.release()
1851 ### Ugly part for legend
1852 self._p.subplots[0]['lines']=[]
1853 res = raw_input("Accept smoothing ([y]/n): ")
1854 if res.upper() == 'N':
1855 s._setspectrum(yorg, r)
1856 self._p.unmap()
1857 self._p = None
1858 del orgscan
1859
[876]1860 if insitu: self._assign(s)
1861 else: return s
[513]1862
[1862]1863 @asaplog_post_dec
[1907]1864 def old_poly_baseline(self, mask=None, order=0, plot=False, uselin=False, insitu=None, rows=None):
[1846]1865 """\
[513]1866 Return a scan which has been baselined (all rows) by a polynomial.
[1907]1867
[513]1868 Parameters:
[1846]1869
[794]1870 mask: an optional mask
[1855]1871
[794]1872 order: the order of the polynomial (default is 0)
[1855]1873
[1061]1874 plot: plot the fit and the residual. In this each
1875 indivual fit has to be approved, by typing 'y'
1876 or 'n'
[1855]1877
[1391]1878 uselin: use linear polynomial fit
[1855]1879
[794]1880 insitu: if False a new scantable is returned.
1881 Otherwise, the scaling is done in-situ
1882 The default is taken from .asaprc (False)
[1846]1883
[1907]1884 rows: row numbers of spectra to be processed.
1885 (default is None: for all rows)
1886
1887 Example:
[513]1888 # return a scan baselined by a third order polynomial,
1889 # not using a mask
1890 bscan = scan.poly_baseline(order=3)
[1846]1891
[579]1892 """
[513]1893 if insitu is None: insitu = rcParams['insitu']
[1819]1894 if not insitu:
1895 workscan = self.copy()
1896 else:
1897 workscan = self
[513]1898 varlist = vars()
1899 if mask is None:
[1907]1900 mask = [True for i in xrange(self.nchan())]
[1819]1901
[1217]1902 try:
1903 f = fitter()
[1391]1904 if uselin:
1905 f.set_function(lpoly=order)
1906 else:
1907 f.set_function(poly=order)
[1819]1908
[1907]1909 if rows == None:
1910 rows = xrange(workscan.nrow())
1911 elif isinstance(rows, int):
1912 rows = [ rows ]
1913
[1819]1914 if len(rows) > 0:
1915 self.blpars = []
[1907]1916 self.masklists = []
1917 self.actualmask = []
1918
[1819]1919 for r in rows:
1920 f.x = workscan._getabcissa(r)
1921 f.y = workscan._getspectrum(r)
[1907]1922 f.mask = mask_and(mask, workscan._getmask(r)) # (CAS-1434)
[1819]1923 f.data = None
1924 f.fit()
1925 if plot:
1926 f.plot(residual=True)
1927 x = raw_input("Accept fit ( [y]/n ): ")
1928 if x.upper() == 'N':
1929 self.blpars.append(None)
[1907]1930 self.masklists.append(None)
1931 self.actualmask.append(None)
[1819]1932 continue
1933 workscan._setspectrum(f.fitter.getresidual(), r)
1934 self.blpars.append(f.get_parameters())
[1907]1935 self.masklists.append(workscan.get_masklist(f.mask, row=r))
1936 self.actualmask.append(f.mask)
[1819]1937
1938 if plot:
1939 f._p.unmap()
1940 f._p = None
1941 workscan._add_history("poly_baseline", varlist)
[1856]1942 if insitu:
1943 self._assign(workscan)
1944 else:
1945 return workscan
[1217]1946 except RuntimeError:
1947 msg = "The fit failed, possibly because it didn't converge."
[1859]1948 raise RuntimeError(msg)
[513]1949
[1819]1950
[1907]1951 def poly_baseline(self, mask=None, order=0, plot=False, batch=False, insitu=None, rows=None):
1952 """\
1953 Return a scan which has been baselined (all rows) by a polynomial.
1954 Parameters:
1955 mask: an optional mask
1956 order: the order of the polynomial (default is 0)
1957 plot: plot the fit and the residual. In this each
1958 indivual fit has to be approved, by typing 'y'
1959 or 'n'. Ignored if batch = True.
1960 batch: if True a faster algorithm is used and logs
1961 including the fit results are not output
1962 (default is False)
1963 insitu: if False a new scantable is returned.
1964 Otherwise, the scaling is done in-situ
1965 The default is taken from .asaprc (False)
1966 rows: row numbers of spectra to be processed.
1967 (default is None: for all rows)
1968 Example:
1969 # return a scan baselined by a third order polynomial,
1970 # not using a mask
1971 bscan = scan.poly_baseline(order=3)
1972 """
1973 if insitu is None: insitu = rcParams["insitu"]
1974 if insitu:
1975 workscan = self
1976 else:
1977 workscan = self.copy()
1978
1979 varlist = vars()
1980 nchan = workscan.nchan()
1981
1982 if mask is None:
1983 mask = [True for i in xrange(nchan)]
1984
1985 try:
1986 if rows == None:
1987 rows = xrange(workscan.nrow())
1988 elif isinstance(rows, int):
1989 rows = [ rows ]
1990
1991 if len(rows) > 0:
1992 self.blpars = []
1993 self.masklists = []
1994 self.actualmask = []
1995
1996 if batch:
1997 for r in rows:
[1908]1998 workscan._poly_baseline_batch(mask, order, r)
[1907]1999 elif plot:
2000 f = fitter()
2001 f.set_function(lpoly=order)
2002 for r in rows:
2003 f.x = workscan._getabcissa(r)
2004 f.y = workscan._getspectrum(r)
2005 f.mask = mask_and(mask, workscan._getmask(r)) # (CAS-1434)
2006 f.data = None
2007 f.fit()
2008
2009 f.plot(residual=True)
2010 accept_fit = raw_input("Accept fit ( [y]/n ): ")
2011 if accept_fit.upper() == "N":
2012 self.blpars.append(None)
2013 self.masklists.append(None)
2014 self.actualmask.append(None)
2015 continue
2016 workscan._setspectrum(f.fitter.getresidual(), r)
2017 self.blpars.append(f.get_parameters())
2018 self.masklists.append(workscan.get_masklist(f.mask, row=r))
2019 self.actualmask.append(f.mask)
2020
2021 f._p.unmap()
2022 f._p = None
2023 else:
2024 import array
2025 for r in rows:
2026 pars = array.array("f", [0.0 for i in range(order+1)])
2027 pars_adr = pars.buffer_info()[0]
2028 pars_len = pars.buffer_info()[1]
2029
2030 errs = array.array("f", [0.0 for i in range(order+1)])
2031 errs_adr = errs.buffer_info()[0]
2032 errs_len = errs.buffer_info()[1]
2033
2034 fmsk = array.array("i", [1 for i in range(nchan)])
2035 fmsk_adr = fmsk.buffer_info()[0]
2036 fmsk_len = fmsk.buffer_info()[1]
2037
2038 workscan._poly_baseline(mask, order, r, pars_adr, pars_len, errs_adr, errs_len, fmsk_adr, fmsk_len)
2039
2040 params = pars.tolist()
2041 fmtd = ""
2042 for i in xrange(len(params)): fmtd += " p%d= %3.6f," % (i, params[i])
2043 fmtd = fmtd[:-1] # remove trailing ","
2044 errors = errs.tolist()
2045 fmask = fmsk.tolist()
2046 for i in xrange(len(fmask)): fmask[i] = (fmask[i] > 0) # transform (1/0) -> (True/False)
2047
2048 self.blpars.append({"params":params, "fixed":[], "formatted":fmtd, "errors":errors})
2049 self.masklists.append(workscan.get_masklist(fmask, r))
2050 self.actualmask.append(fmask)
2051
2052 asaplog.push(str(fmtd))
2053
2054 workscan._add_history("poly_baseline", varlist)
2055
2056 if insitu:
2057 self._assign(workscan)
2058 else:
2059 return workscan
2060
2061 except RuntimeError:
2062 msg = "The fit failed, possibly because it didn't converge."
2063 if rcParams["verbose"]:
2064 asaplog.push(str(msg))
2065 return
2066 else:
2067 raise RuntimeError(msg)
2068
2069
2070 def auto_poly_baseline(self, mask=None, edge=(0, 0), order=0,
[1280]2071 threshold=3, chan_avg_limit=1, plot=False,
[1907]2072 insitu=None, rows=None):
[1846]2073 """\
[880]2074 Return a scan which has been baselined (all rows) by a polynomial.
2075 Spectral lines are detected first using linefinder and masked out
2076 to avoid them affecting the baseline solution.
2077
2078 Parameters:
[1846]2079
[880]2080 mask: an optional mask retreived from scantable
[1846]2081
2082 edge: an optional number of channel to drop at the edge of
2083 spectrum. If only one value is
[880]2084 specified, the same number will be dropped from
2085 both sides of the spectrum. Default is to keep
[907]2086 all channels. Nested tuples represent individual
[976]2087 edge selection for different IFs (a number of spectral
2088 channels can be different)
[1846]2089
[880]2090 order: the order of the polynomial (default is 0)
[1846]2091
[880]2092 threshold: the threshold used by line finder. It is better to
2093 keep it large as only strong lines affect the
2094 baseline solution.
[1846]2095
[1280]2096 chan_avg_limit:
2097 a maximum number of consequtive spectral channels to
2098 average during the search of weak and broad lines.
2099 The default is no averaging (and no search for weak
2100 lines). If such lines can affect the fitted baseline
2101 (e.g. a high order polynomial is fitted), increase this
2102 parameter (usually values up to 8 are reasonable). Most
2103 users of this method should find the default value
2104 sufficient.
[1846]2105
[1061]2106 plot: plot the fit and the residual. In this each
2107 indivual fit has to be approved, by typing 'y'
2108 or 'n'
[1846]2109
[880]2110 insitu: if False a new scantable is returned.
2111 Otherwise, the scaling is done in-situ
2112 The default is taken from .asaprc (False)
[1907]2113 rows: row numbers of spectra to be processed.
2114 (default is None: for all rows)
[880]2115
[1846]2116
2117 Example::
2118
2119 scan2 = scan.auto_poly_baseline(order=7, insitu=False)
2120
[880]2121 """
2122 if insitu is None: insitu = rcParams['insitu']
2123 varlist = vars()
2124 from asap.asaplinefind import linefinder
2125 from asap import _is_sequence_or_number as _is_valid
2126
[976]2127 # check whether edge is set up for each IF individually
[1118]2128 individualedge = False;
2129 if len(edge) > 1:
2130 if isinstance(edge[0], list) or isinstance(edge[0], tuple):
2131 individualedge = True;
[907]2132
[1118]2133 if not _is_valid(edge, int) and not individualedge:
[909]2134 raise ValueError, "Parameter 'edge' has to be an integer or a \
[907]2135 pair of integers specified as a tuple. Nested tuples are allowed \
2136 to make individual selection for different IFs."
[919]2137
[1118]2138 curedge = (0, 0)
2139 if individualedge:
2140 for edgepar in edge:
2141 if not _is_valid(edgepar, int):
2142 raise ValueError, "Each element of the 'edge' tuple has \
2143 to be a pair of integers or an integer."
[907]2144 else:
[1118]2145 curedge = edge;
[880]2146
[1907]2147 if not insitu:
2148 workscan = self.copy()
2149 else:
2150 workscan = self
2151
[880]2152 # setup fitter
2153 f = fitter()
[1907]2154 f.set_function(lpoly=order)
[880]2155
2156 # setup line finder
[1118]2157 fl = linefinder()
[1268]2158 fl.set_options(threshold=threshold,avg_limit=chan_avg_limit)
[880]2159
[907]2160 fl.set_scan(workscan)
2161
[1907]2162 if mask is None:
2163 mask = _n_bools(workscan.nchan(), True)
2164
2165 if rows is None:
2166 rows = xrange(workscan.nrow())
2167 elif isinstance(rows, int):
2168 rows = [ rows ]
2169
[1819]2170 # Save parameters of baseline fits & masklists as a class attribute.
2171 # NOTICE: It does not reflect changes in scantable!
2172 if len(rows) > 0:
2173 self.blpars=[]
2174 self.masklists=[]
[1907]2175 self.actualmask=[]
[880]2176 asaplog.push("Processing:")
2177 for r in rows:
[1118]2178 msg = " Scan[%d] Beam[%d] IF[%d] Pol[%d] Cycle[%d]" % \
2179 (workscan.getscan(r), workscan.getbeam(r), workscan.getif(r), \
2180 workscan.getpol(r), workscan.getcycle(r))
[880]2181 asaplog.push(msg, False)
[907]2182
[976]2183 # figure out edge parameter
[1118]2184 if individualedge:
2185 if len(edge) >= workscan.getif(r):
2186 raise RuntimeError, "Number of edge elements appear to " \
2187 "be less than the number of IFs"
2188 curedge = edge[workscan.getif(r)]
[919]2189
[1907]2190 actualmask = mask_and(mask, workscan._getmask(r)) # (CAS-1434)
[1819]2191
[976]2192 # setup line finder
[1819]2193 fl.find_lines(r, actualmask, curedge)
[1907]2194
[1819]2195 f.x = workscan._getabcissa(r)
2196 f.y = workscan._getspectrum(r)
[1907]2197 f.mask = fl.get_mask()
[1819]2198 f.data = None
[880]2199 f.fit()
[1819]2200
2201 # Show mask list
[1907]2202 masklist=workscan.get_masklist(f.mask, row=r)
[1819]2203 msg = "mask range: "+str(masklist)
2204 asaplog.push(msg, False)
2205
[1061]2206 if plot:
2207 f.plot(residual=True)
2208 x = raw_input("Accept fit ( [y]/n ): ")
2209 if x.upper() == 'N':
[1819]2210 self.blpars.append(None)
2211 self.masklists.append(None)
[1907]2212 self.actualmask.append(None)
[1061]2213 continue
[1819]2214
[880]2215 workscan._setspectrum(f.fitter.getresidual(), r)
[1819]2216 self.blpars.append(f.get_parameters())
2217 self.masklists.append(masklist)
[1907]2218 self.actualmask.append(f.mask)
[1061]2219 if plot:
2220 f._p.unmap()
2221 f._p = None
2222 workscan._add_history("auto_poly_baseline", varlist)
[880]2223 if insitu:
2224 self._assign(workscan)
2225 else:
2226 return workscan
2227
[1862]2228 @asaplog_post_dec
[914]2229 def rotate_linpolphase(self, angle):
[1846]2230 """\
[914]2231 Rotate the phase of the complex polarization O=Q+iU correlation.
2232 This is always done in situ in the raw data. So if you call this
2233 function more than once then each call rotates the phase further.
[1846]2234
[914]2235 Parameters:
[1846]2236
[914]2237 angle: The angle (degrees) to rotate (add) by.
[1846]2238
2239 Example::
2240
[914]2241 scan.rotate_linpolphase(2.3)
[1846]2242
[914]2243 """
2244 varlist = vars()
[936]2245 self._math._rotate_linpolphase(self, angle)
[914]2246 self._add_history("rotate_linpolphase", varlist)
2247 return
[710]2248
[1862]2249 @asaplog_post_dec
[914]2250 def rotate_xyphase(self, angle):
[1846]2251 """\
[914]2252 Rotate the phase of the XY correlation. This is always done in situ
2253 in the data. So if you call this function more than once
2254 then each call rotates the phase further.
[1846]2255
[914]2256 Parameters:
[1846]2257
[914]2258 angle: The angle (degrees) to rotate (add) by.
[1846]2259
2260 Example::
2261
[914]2262 scan.rotate_xyphase(2.3)
[1846]2263
[914]2264 """
2265 varlist = vars()
[936]2266 self._math._rotate_xyphase(self, angle)
[914]2267 self._add_history("rotate_xyphase", varlist)
2268 return
2269
[1862]2270 @asaplog_post_dec
[914]2271 def swap_linears(self):
[1846]2272 """\
[1573]2273 Swap the linear polarisations XX and YY, or better the first two
[1348]2274 polarisations as this also works for ciculars.
[914]2275 """
2276 varlist = vars()
[936]2277 self._math._swap_linears(self)
[914]2278 self._add_history("swap_linears", varlist)
2279 return
2280
[1862]2281 @asaplog_post_dec
[914]2282 def invert_phase(self):
[1846]2283 """\
[914]2284 Invert the phase of the complex polarisation
2285 """
2286 varlist = vars()
[936]2287 self._math._invert_phase(self)
[914]2288 self._add_history("invert_phase", varlist)
2289 return
2290
[1862]2291 @asaplog_post_dec
[876]2292 def add(self, offset, insitu=None):
[1846]2293 """\
[513]2294 Return a scan where all spectra have the offset added
[1846]2295
[513]2296 Parameters:
[1846]2297
[513]2298 offset: the offset
[1855]2299
[513]2300 insitu: if False a new scantable is returned.
2301 Otherwise, the scaling is done in-situ
2302 The default is taken from .asaprc (False)
[1846]2303
[513]2304 """
2305 if insitu is None: insitu = rcParams['insitu']
[876]2306 self._math._setinsitu(insitu)
[513]2307 varlist = vars()
[876]2308 s = scantable(self._math._unaryop(self, offset, "ADD", False))
[1118]2309 s._add_history("add", varlist)
[876]2310 if insitu:
2311 self._assign(s)
2312 else:
[513]2313 return s
2314
[1862]2315 @asaplog_post_dec
[1308]2316 def scale(self, factor, tsys=True, insitu=None):
[1846]2317 """\
2318
[513]2319 Return a scan where all spectra are scaled by the give 'factor'
[1846]2320
[513]2321 Parameters:
[1846]2322
[1819]2323 factor: the scaling factor (float or 1D float list)
[1855]2324
[513]2325 insitu: if False a new scantable is returned.
2326 Otherwise, the scaling is done in-situ
2327 The default is taken from .asaprc (False)
[1855]2328
[513]2329 tsys: if True (default) then apply the operation to Tsys
2330 as well as the data
[1846]2331
[513]2332 """
2333 if insitu is None: insitu = rcParams['insitu']
[876]2334 self._math._setinsitu(insitu)
[513]2335 varlist = vars()
[1819]2336 s = None
2337 import numpy
2338 if isinstance(factor, list) or isinstance(factor, numpy.ndarray):
2339 if isinstance(factor[0], list) or isinstance(factor[0], numpy.ndarray):
2340 from asapmath import _array2dOp
2341 s = _array2dOp( self.copy(), factor, "MUL", tsys )
2342 else:
2343 s = scantable( self._math._arrayop( self.copy(), factor, "MUL", tsys ) )
2344 else:
2345 s = scantable(self._math._unaryop(self.copy(), factor, "MUL", tsys))
[1118]2346 s._add_history("scale", varlist)
[876]2347 if insitu:
2348 self._assign(s)
2349 else:
[513]2350 return s
2351
[1504]2352 def set_sourcetype(self, match, matchtype="pattern",
2353 sourcetype="reference"):
[1846]2354 """\
[1502]2355 Set the type of the source to be an source or reference scan
[1846]2356 using the provided pattern.
2357
[1502]2358 Parameters:
[1846]2359
[1504]2360 match: a Unix style pattern, regular expression or selector
[1855]2361
[1504]2362 matchtype: 'pattern' (default) UNIX style pattern or
2363 'regex' regular expression
[1855]2364
[1502]2365 sourcetype: the type of the source to use (source/reference)
[1846]2366
[1502]2367 """
2368 varlist = vars()
2369 basesel = self.get_selection()
2370 stype = -1
2371 if sourcetype.lower().startswith("r"):
2372 stype = 1
2373 elif sourcetype.lower().startswith("s"):
2374 stype = 0
[1504]2375 else:
[1502]2376 raise ValueError("Illegal sourcetype use s(ource) or r(eference)")
[1504]2377 if matchtype.lower().startswith("p"):
2378 matchtype = "pattern"
2379 elif matchtype.lower().startswith("r"):
2380 matchtype = "regex"
2381 else:
2382 raise ValueError("Illegal matchtype, use p(attern) or r(egex)")
[1502]2383 sel = selector()
2384 if isinstance(match, selector):
2385 sel = match
2386 else:
[1504]2387 sel.set_query("SRCNAME == %s('%s')" % (matchtype, match))
[1502]2388 self.set_selection(basesel+sel)
2389 self._setsourcetype(stype)
2390 self.set_selection(basesel)
[1573]2391 self._add_history("set_sourcetype", varlist)
[1502]2392
[1862]2393 @asaplog_post_dec
[1857]2394 @preserve_selection
[1819]2395 def auto_quotient(self, preserve=True, mode='paired', verify=False):
[1846]2396 """\
[670]2397 This function allows to build quotients automatically.
[1819]2398 It assumes the observation to have the same number of
[670]2399 "ons" and "offs"
[1846]2400
[670]2401 Parameters:
[1846]2402
[710]2403 preserve: you can preserve (default) the continuum or
2404 remove it. The equations used are
[1857]2405
[670]2406 preserve: Output = Toff * (on/off) - Toff
[1857]2407
[1070]2408 remove: Output = Toff * (on/off) - Ton
[1855]2409
[1573]2410 mode: the on/off detection mode
[1348]2411 'paired' (default)
2412 identifies 'off' scans by the
2413 trailing '_R' (Mopra/Parkes) or
2414 '_e'/'_w' (Tid) and matches
2415 on/off pairs from the observing pattern
[1502]2416 'time'
2417 finds the closest off in time
[1348]2418
[1857]2419 .. todo:: verify argument is not implemented
2420
[670]2421 """
[1857]2422 varlist = vars()
[1348]2423 modes = ["time", "paired"]
[670]2424 if not mode in modes:
[876]2425 msg = "please provide valid mode. Valid modes are %s" % (modes)
2426 raise ValueError(msg)
[1348]2427 s = None
2428 if mode.lower() == "paired":
[1857]2429 sel = self.get_selection()
[1875]2430 sel.set_query("SRCTYPE==psoff")
[1356]2431 self.set_selection(sel)
[1348]2432 offs = self.copy()
[1875]2433 sel.set_query("SRCTYPE==pson")
[1356]2434 self.set_selection(sel)
[1348]2435 ons = self.copy()
2436 s = scantable(self._math._quotient(ons, offs, preserve))
2437 elif mode.lower() == "time":
2438 s = scantable(self._math._auto_quotient(self, mode, preserve))
[1118]2439 s._add_history("auto_quotient", varlist)
[876]2440 return s
[710]2441
[1862]2442 @asaplog_post_dec
[1145]2443 def mx_quotient(self, mask = None, weight='median', preserve=True):
[1846]2444 """\
[1143]2445 Form a quotient using "off" beams when observing in "MX" mode.
[1846]2446
[1143]2447 Parameters:
[1846]2448
[1145]2449 mask: an optional mask to be used when weight == 'stddev'
[1855]2450
[1143]2451 weight: How to average the off beams. Default is 'median'.
[1855]2452
[1145]2453 preserve: you can preserve (default) the continuum or
[1855]2454 remove it. The equations used are:
[1846]2455
[1855]2456 preserve: Output = Toff * (on/off) - Toff
2457
2458 remove: Output = Toff * (on/off) - Ton
2459
[1217]2460 """
[1593]2461 mask = mask or ()
[1141]2462 varlist = vars()
2463 on = scantable(self._math._mx_extract(self, 'on'))
[1143]2464 preoff = scantable(self._math._mx_extract(self, 'off'))
2465 off = preoff.average_time(mask=mask, weight=weight, scanav=False)
[1217]2466 from asapmath import quotient
[1145]2467 q = quotient(on, off, preserve)
[1143]2468 q._add_history("mx_quotient", varlist)
[1217]2469 return q
[513]2470
[1862]2471 @asaplog_post_dec
[718]2472 def freq_switch(self, insitu=None):
[1846]2473 """\
[718]2474 Apply frequency switching to the data.
[1846]2475
[718]2476 Parameters:
[1846]2477
[718]2478 insitu: if False a new scantable is returned.
2479 Otherwise, the swictching is done in-situ
2480 The default is taken from .asaprc (False)
[1846]2481
[718]2482 """
2483 if insitu is None: insitu = rcParams['insitu']
[876]2484 self._math._setinsitu(insitu)
[718]2485 varlist = vars()
[876]2486 s = scantable(self._math._freqswitch(self))
[1118]2487 s._add_history("freq_switch", varlist)
[1856]2488 if insitu:
2489 self._assign(s)
2490 else:
2491 return s
[718]2492
[1862]2493 @asaplog_post_dec
[780]2494 def recalc_azel(self):
[1846]2495 """Recalculate the azimuth and elevation for each position."""
[780]2496 varlist = vars()
[876]2497 self._recalcazel()
[780]2498 self._add_history("recalc_azel", varlist)
2499 return
2500
[1862]2501 @asaplog_post_dec
[513]2502 def __add__(self, other):
2503 varlist = vars()
2504 s = None
2505 if isinstance(other, scantable):
[1573]2506 s = scantable(self._math._binaryop(self, other, "ADD"))
[513]2507 elif isinstance(other, float):
[876]2508 s = scantable(self._math._unaryop(self, other, "ADD", False))
[513]2509 else:
[718]2510 raise TypeError("Other input is not a scantable or float value")
[513]2511 s._add_history("operator +", varlist)
2512 return s
2513
[1862]2514 @asaplog_post_dec
[513]2515 def __sub__(self, other):
2516 """
2517 implicit on all axes and on Tsys
2518 """
2519 varlist = vars()
2520 s = None
2521 if isinstance(other, scantable):
[1588]2522 s = scantable(self._math._binaryop(self, other, "SUB"))
[513]2523 elif isinstance(other, float):
[876]2524 s = scantable(self._math._unaryop(self, other, "SUB", False))
[513]2525 else:
[718]2526 raise TypeError("Other input is not a scantable or float value")
[513]2527 s._add_history("operator -", varlist)
2528 return s
[710]2529
[1862]2530 @asaplog_post_dec
[513]2531 def __mul__(self, other):
2532 """
2533 implicit on all axes and on Tsys
2534 """
2535 varlist = vars()
2536 s = None
2537 if isinstance(other, scantable):
[1588]2538 s = scantable(self._math._binaryop(self, other, "MUL"))
[513]2539 elif isinstance(other, float):
[876]2540 s = scantable(self._math._unaryop(self, other, "MUL", False))
[513]2541 else:
[718]2542 raise TypeError("Other input is not a scantable or float value")
[513]2543 s._add_history("operator *", varlist)
2544 return s
2545
[710]2546
[1862]2547 @asaplog_post_dec
[513]2548 def __div__(self, other):
2549 """
2550 implicit on all axes and on Tsys
2551 """
2552 varlist = vars()
2553 s = None
2554 if isinstance(other, scantable):
[1589]2555 s = scantable(self._math._binaryop(self, other, "DIV"))
[513]2556 elif isinstance(other, float):
2557 if other == 0.0:
[718]2558 raise ZeroDivisionError("Dividing by zero is not recommended")
[876]2559 s = scantable(self._math._unaryop(self, other, "DIV", False))
[513]2560 else:
[718]2561 raise TypeError("Other input is not a scantable or float value")
[513]2562 s._add_history("operator /", varlist)
2563 return s
2564
[1862]2565 @asaplog_post_dec
[530]2566 def get_fit(self, row=0):
[1846]2567 """\
[530]2568 Print or return the stored fits for a row in the scantable
[1846]2569
[530]2570 Parameters:
[1846]2571
[530]2572 row: the row which the fit has been applied to.
[1846]2573
[530]2574 """
2575 if row > self.nrow():
2576 return
[976]2577 from asap.asapfit import asapfit
[530]2578 fit = asapfit(self._getfit(row))
[1859]2579 asaplog.push( '%s' %(fit) )
2580 return fit.as_dict()
[530]2581
[1483]2582 def flag_nans(self):
[1846]2583 """\
[1483]2584 Utility function to flag NaN values in the scantable.
2585 """
2586 import numpy
2587 basesel = self.get_selection()
2588 for i in range(self.nrow()):
[1589]2589 sel = self.get_row_selector(i)
2590 self.set_selection(basesel+sel)
[1483]2591 nans = numpy.isnan(self._getspectrum(0))
2592 if numpy.any(nans):
2593 bnans = [ bool(v) for v in nans]
2594 self.flag(bnans)
2595 self.set_selection(basesel)
2596
[1588]2597 def get_row_selector(self, rowno):
2598 return selector(beams=self.getbeam(rowno),
2599 ifs=self.getif(rowno),
2600 pols=self.getpol(rowno),
2601 scans=self.getscan(rowno),
2602 cycles=self.getcycle(rowno))
[1573]2603
[484]2604 def _add_history(self, funcname, parameters):
[1435]2605 if not rcParams['scantable.history']:
2606 return
[484]2607 # create date
2608 sep = "##"
2609 from datetime import datetime
2610 dstr = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
2611 hist = dstr+sep
2612 hist += funcname+sep#cdate+sep
2613 if parameters.has_key('self'): del parameters['self']
[1118]2614 for k, v in parameters.iteritems():
[484]2615 if type(v) is dict:
[1118]2616 for k2, v2 in v.iteritems():
[484]2617 hist += k2
2618 hist += "="
[1118]2619 if isinstance(v2, scantable):
[484]2620 hist += 'scantable'
2621 elif k2 == 'mask':
[1118]2622 if isinstance(v2, list) or isinstance(v2, tuple):
[513]2623 hist += str(self._zip_mask(v2))
2624 else:
2625 hist += str(v2)
[484]2626 else:
[513]2627 hist += str(v2)
[484]2628 else:
2629 hist += k
2630 hist += "="
[1118]2631 if isinstance(v, scantable):
[484]2632 hist += 'scantable'
2633 elif k == 'mask':
[1118]2634 if isinstance(v, list) or isinstance(v, tuple):
[513]2635 hist += str(self._zip_mask(v))
2636 else:
2637 hist += str(v)
[484]2638 else:
2639 hist += str(v)
2640 hist += sep
2641 hist = hist[:-2] # remove trailing '##'
2642 self._addhistory(hist)
2643
[710]2644
[484]2645 def _zip_mask(self, mask):
2646 mask = list(mask)
2647 i = 0
2648 segments = []
2649 while mask[i:].count(1):
2650 i += mask[i:].index(1)
2651 if mask[i:].count(0):
2652 j = i + mask[i:].index(0)
2653 else:
[710]2654 j = len(mask)
[1118]2655 segments.append([i, j])
[710]2656 i = j
[484]2657 return segments
[714]2658
[626]2659 def _get_ordinate_label(self):
2660 fu = "("+self.get_fluxunit()+")"
2661 import re
2662 lbl = "Intensity"
[1118]2663 if re.match(".K.", fu):
[626]2664 lbl = "Brightness Temperature "+ fu
[1118]2665 elif re.match(".Jy.", fu):
[626]2666 lbl = "Flux density "+ fu
2667 return lbl
[710]2668
[876]2669 def _check_ifs(self):
2670 nchans = [self.nchan(i) for i in range(self.nif(-1))]
[889]2671 nchans = filter(lambda t: t > 0, nchans)
[876]2672 return (sum(nchans)/len(nchans) == nchans[0])
[976]2673
[1862]2674 @asaplog_post_dec
[1916]2675 #def _fill(self, names, unit, average, getpt, antenna):
2676 def _fill(self, names, unit, average, opts={}):
[976]2677 first = True
2678 fullnames = []
2679 for name in names:
2680 name = os.path.expandvars(name)
2681 name = os.path.expanduser(name)
2682 if not os.path.exists(name):
2683 msg = "File '%s' does not exists" % (name)
2684 raise IOError(msg)
2685 fullnames.append(name)
2686 if average:
2687 asaplog.push('Auto averaging integrations')
[1079]2688 stype = int(rcParams['scantable.storage'].lower() == 'disk')
[976]2689 for name in fullnames:
[1073]2690 tbl = Scantable(stype)
[1843]2691 r = filler(tbl)
[1504]2692 rx = rcParams['scantable.reference']
[1843]2693 r.setreferenceexpr(rx)
[976]2694 msg = "Importing %s..." % (name)
[1118]2695 asaplog.push(msg, False)
[1916]2696 #opts = {'ms': {'antenna' : antenna, 'getpt': getpt} }
[1904]2697 r.open(name, opts)# antenna, -1, -1, getpt)
[1843]2698 r.fill()
[976]2699 if average:
[1118]2700 tbl = self._math._average((tbl, ), (), 'NONE', 'SCAN')
[976]2701 if not first:
2702 tbl = self._math._merge([self, tbl])
2703 Scantable.__init__(self, tbl)
[1843]2704 r.close()
[1118]2705 del r, tbl
[976]2706 first = False
[1861]2707 #flush log
2708 asaplog.post()
[976]2709 if unit is not None:
2710 self.set_fluxunit(unit)
[1824]2711 if not is_casapy():
2712 self.set_freqframe(rcParams['scantable.freqframe'])
[976]2713
[1402]2714 def __getitem__(self, key):
2715 if key < 0:
2716 key += self.nrow()
2717 if key >= self.nrow():
2718 raise IndexError("Row index out of range.")
2719 return self._getspectrum(key)
2720
2721 def __setitem__(self, key, value):
2722 if key < 0:
2723 key += self.nrow()
2724 if key >= self.nrow():
2725 raise IndexError("Row index out of range.")
2726 if not hasattr(value, "__len__") or \
2727 len(value) > self.nchan(self.getif(key)):
2728 raise ValueError("Spectrum length doesn't match.")
2729 return self._setspectrum(value, key)
2730
2731 def __len__(self):
2732 return self.nrow()
2733
2734 def __iter__(self):
2735 for i in range(len(self)):
2736 yield self[i]
Note: See TracBrowser for help on using the repository browser.