source: trunk/python/scantable.py@ 1211

Last change on this file since 1211 was 1203, checked in by mar637, 18 years ago

Using FFTServer::fft0 now, don't know what the difference is. Adde better docs, to explain the fact that the frequency to remove is really a period withing the bandwidth.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 62.0 KB
RevLine 
[876]1from asap._asap import Scantable
[226]2from asap import rcParams
[1118]3from asap import print_log
4from asap import asaplog
[946]5from asap import selector
[1134]6from asap import NUM
[1153]7from asap import linecatalog
[102]8
[876]9class scantable(Scantable):
[102]10 """
11 The ASAP container for scans
12 """
[710]13
[484]14 def __init__(self, filename, average=None, unit=None):
[102]15 """
16 Create a scantable from a saved one or make a reference
17 Parameters:
[181]18 filename: the name of an asap table on disk
19 or
20 the name of a rpfits/sdfits/ms file
21 (integrations within scans are auto averaged
22 and the whole file is read)
23 or
24 [advanced] a reference to an existing
[102]25 scantable
[484]26 average: average all integrations withinb a scan on read.
27 The default (True) is taken from .asaprc.
28 unit: brightness unit; must be consistent with K or Jy.
[340]29 Over-rides the default selected by the reader
30 (input rpfits/sdfits/ms) or replaces the value
31 in existing scantables
[710]32 """
[976]33 if average is None:
[710]34 average = rcParams['scantable.autoaverage']
[1118]35 #varlist = vars()
[876]36 from asap._asap import stmath
37 self._math = stmath()
38 if isinstance(filename, Scantable):
39 Scantable.__init__(self, filename)
[181]40 else:
[1118]41 if isinstance(filename, str):
[976]42 import os.path
43 filename = os.path.expandvars(filename)
44 filename = os.path.expanduser(filename)
45 if not os.path.exists(filename):
46 s = "File '%s' not found." % (filename)
[718]47 if rcParams['verbose']:
[976]48 asaplog.push(s)
49 print asaplog.pop().strip()
[718]50 return
[976]51 raise IOError(s)
[1115]52 if os.path.isdir(filename) \
[1118]53 and not os.path.exists(filename+'/table.f1'):
[976]54 # crude check if asap table
55 if os.path.exists(filename+'/table.info'):
[1118]56 ondisk = rcParams['scantable.storage'] == 'disk'
57 Scantable.__init__(self, filename, ondisk)
[976]58 if unit is not None:
59 self.set_fluxunit(unit)
60 self.set_freqframe(rcParams['scantable.freqframe'])
[718]61 else:
[1118]62 msg = "The given file '%s'is not a valid " \
63 "asap table." % (filename)
[976]64 if rcParams['verbose']:
65 print msg
66 return
67 else:
68 raise IOError(msg)
[226]69 else:
[1118]70 self._fill([filename], unit, average)
71 elif (isinstance(filename, list) or isinstance(filename, tuple)) \
[976]72 and isinstance(filename[-1], str):
73 self._fill(filename, unit, average)
[714]74 print_log()
[102]75
[876]76 def save(self, name=None, format=None, overwrite=False):
[116]77 """
[710]78 Store the scantable on disk. This can be an asap (aips++) Table, SDFITS,
[280]79 Image FITS or MS2 format.
[116]80 Parameters:
[1093]81 name: the name of the outputfile. For format "ASCII"
82 this is the root file name (data in 'name'.txt
[497]83 and header in 'name'_header.txt)
[116]84 format: an optional file format. Default is ASAP.
[280]85 Allowed are - 'ASAP' (save as ASAP [aips++] Table),
[194]86 'SDFITS' (save as SDFITS file)
[200]87 'ASCII' (saves as ascii text file)
[226]88 'MS2' (saves as an aips++
89 MeasurementSet V2)
[411]90 overwrite: If the file should be overwritten if it exists.
[256]91 The default False is to return with warning
[411]92 without writing the output. USE WITH CARE.
[116]93 Example:
94 scan.save('myscan.asap')
[1118]95 scan.save('myscan.sdfits', 'SDFITS')
[116]96 """
[411]97 from os import path
[226]98 if format is None: format = rcParams['scantable.save']
[256]99 suffix = '.'+format.lower()
[1118]100 if name is None or name == "":
[256]101 name = 'scantable'+suffix
[718]102 msg = "No filename given. Using default name %s..." % name
103 asaplog.push(msg)
[411]104 name = path.expandvars(name)
[256]105 if path.isfile(name) or path.isdir(name):
106 if not overwrite:
[718]107 msg = "File %s exists." % name
108 if rcParams['verbose']:
109 print msg
110 return
111 else:
112 raise IOError(msg)
[451]113 format2 = format.upper()
114 if format2 == 'ASAP':
[116]115 self._save(name)
116 else:
[989]117 from asap._asap import stwriter as stw
[1118]118 writer = stw(format2)
119 writer.write(self, name)
[718]120 print_log()
[116]121 return
122
[102]123 def copy(self):
124 """
125 Return a copy of this scantable.
126 Parameters:
[113]127 none
[102]128 Example:
129 copiedscan = scan.copy()
130 """
[876]131 sd = scantable(Scantable._copy(self))
[113]132 return sd
133
[1093]134 def drop_scan(self, scanid=None):
135 """
136 Return a new scantable where the specified scan number(s) has(have)
137 been dropped.
138 Parameters:
139 scanid: a (list of) scan number(s)
140 """
141 from asap import _is_sequence_or_number as _is_valid
142 from asap import _to_list
143 from asap import unique
144 if not _is_valid(scanid):
145 if rcParams['verbose']:
146 print "Please specify a scanno to drop from the scantable"
147 return
148 else:
149 raise RuntimeError("No scan given")
150 try:
151 scanid = _to_list(scanid)
152 allscans = unique([ self.getscan(i) for i in range(self.nrow())])
153 for sid in scanid: allscans.remove(sid)
[1118]154 if len(allscans) == 0:
155 raise ValueError("Can't remove all scans")
[1093]156 except ValueError:
157 if rcParams['verbose']:
158 print "Couldn't find any match."
159 return
160 else: raise
161 try:
162 bsel = self.get_selection()
163 sel = selector()
164 sel.set_scans(allscans)
165 self.set_selection(bsel+sel)
166 scopy = self._copy()
167 self.set_selection(bsel)
168 return scantable(scopy)
169 except RuntimeError:
[1118]170 if rcParams['verbose']:
171 print "Couldn't find any match."
172 else:
173 raise
[1093]174
175
[102]176 def get_scan(self, scanid=None):
177 """
178 Return a specific scan (by scanno) or collection of scans (by
179 source name) in a new scantable.
180 Parameters:
[513]181 scanid: a (list of) scanno or a source name, unix-style
182 patterns are accepted for source name matching, e.g.
183 '*_R' gets all 'ref scans
[102]184 Example:
[513]185 # get all scans containing the source '323p459'
186 newscan = scan.get_scan('323p459')
187 # get all 'off' scans
188 refscans = scan.get_scan('*_R')
189 # get a susbset of scans by scanno (as listed in scan.summary())
[1118]190 newscan = scan.get_scan([0, 2, 7, 10])
[102]191 """
192 if scanid is None:
[718]193 if rcParams['verbose']:
[1118]194 print "Please specify a scan no or name to " \
195 "retrieve from the scantable"
[718]196 return
197 else:
198 raise RuntimeError("No scan given")
199
[102]200 try:
[946]201 bsel = self.get_selection()
202 sel = selector()
[102]203 if type(scanid) is str:
[946]204 sel.set_name(scanid)
205 self.set_selection(bsel+sel)
[876]206 scopy = self._copy()
[946]207 self.set_selection(bsel)
[876]208 return scantable(scopy)
[102]209 elif type(scanid) is int:
[946]210 sel.set_scans([scanid])
211 self.set_selection(bsel+sel)
[876]212 scopy = self._copy()
[946]213 self.set_selection(bsel)
[876]214 return scantable(scopy)
[381]215 elif type(scanid) is list:
[946]216 sel.set_scans(scanid)
217 self.set_selection(sel)
[876]218 scopy = self._copy()
[946]219 self.set_selection(bsel)
[876]220 return scantable(scopy)
[381]221 else:
[718]222 msg = "Illegal scanid type, use 'int' or 'list' if ints."
223 if rcParams['verbose']:
224 print msg
225 else:
226 raise TypeError(msg)
[102]227 except RuntimeError:
[718]228 if rcParams['verbose']: print "Couldn't find any match."
229 else: raise
[102]230
231 def __str__(self):
[1118]232 return Scantable._summary(self, True)
[102]233
[976]234 def summary(self, filename=None):
[102]235 """
236 Print a summary of the contents of this scantable.
237 Parameters:
238 filename: the name of a file to write the putput to
239 Default - no file output
[381]240 verbose: print extra info such as the frequency table
241 The default (False) is taken from .asaprc
[102]242 """
[976]243 info = Scantable._summary(self, True)
244 #if verbose is None: verbose = rcParams['scantable.verbosesummary']
[102]245 if filename is not None:
[256]246 if filename is "":
247 filename = 'scantable_summary.txt'
[415]248 from os.path import expandvars, isdir
[411]249 filename = expandvars(filename)
[415]250 if not isdir(filename):
[413]251 data = open(filename, 'w')
252 data.write(info)
253 data.close()
254 else:
[718]255 msg = "Illegal file name '%s'." % (filename)
256 if rcParams['verbose']:
257 print msg
258 else:
259 raise IOError(msg)
260 if rcParams['verbose']:
[794]261 try:
262 from IPython.genutils import page as pager
263 except ImportError:
264 from pydoc import pager
265 pager(info)
[718]266 else:
267 return info
[710]268
[946]269
270 def get_selection(self):
271 """
[1005]272 Get the selection object currently set on this scantable.
273 Parameters:
274 none
275 Example:
276 sel = scan.get_selection()
277 sel.set_ifs(0) # select IF 0
278 scan.set_selection(sel) # apply modified selection
[946]279 """
280 return selector(self._getselection())
281
[1005]282 def set_selection(self, selection=selector()):
[946]283 """
[1005]284 Select a subset of the data. All following operations on this scantable
285 are only applied to thi selection.
286 Parameters:
287 selection: a selector object (default unset the selection)
288 Examples:
289 sel = selector() # create a selection object
[1118]290 self.set_scans([0, 3]) # select SCANNO 0 and 3
[1005]291 scan.set_selection(sel) # set the selection
292 scan.summary() # will only print summary of scanno 0 an 3
293 scan.set_selection() # unset the selection
[946]294 """
295 self._setselection(selection)
296
[876]297 def stats(self, stat='stddev', mask=None):
[102]298 """
[135]299 Determine the specified statistic of the current beam/if/pol
[102]300 Takes a 'mask' as an optional parameter to specify which
301 channels should be excluded.
302 Parameters:
[135]303 stat: 'min', 'max', 'sumsq', 'sum', 'mean'
304 'var', 'stddev', 'avdev', 'rms', 'median'
305 mask: an optional mask specifying where the statistic
[102]306 should be determined.
307 Example:
[113]308 scan.set_unit('channel')
[1118]309 msk = scan.create_mask([100, 200], [500, 600])
[135]310 scan.stats(stat='mean', mask=m)
[102]311 """
312 if mask == None:
[876]313 mask = []
[1118]314 axes = ['Beam', 'IF', 'Pol', 'Time']
[876]315 if not self._check_ifs():
[1118]316 raise ValueError("Cannot apply mask as the IFs have different "
317 "number of channels. Please use setselection() "
318 "to select individual IFs")
[256]319
[876]320 statvals = self._math._stats(self, mask, stat)
321 out = ''
322 axes = []
323 for i in range(self.nrow()):
324 axis = []
325 axis.append(self.getscan(i))
326 axis.append(self.getbeam(i))
327 axis.append(self.getif(i))
328 axis.append(self.getpol(i))
329 axis.append(self.getcycle(i))
330 axes.append(axis)
331 tm = self._gettime(i)
332 src = self._getsourcename(i)
333 out += 'Scan[%d] (%s) ' % (axis[0], src)
334 out += 'Time[%s]:\n' % (tm)
335 if self.nbeam(-1) > 1: out += ' Beam[%d] ' % (axis[1])
336 if self.nif(-1) > 1: out += ' IF[%d] ' % (axis[2])
337 if self.npol(-1) > 1: out += ' Pol[%d] ' % (axis[3])
338 out += '= %3.3f\n' % (statvals[i])
339 out += "--------------------------------------------------\n"
[256]340
[876]341 if rcParams['verbose']:
342 print "--------------------------------------------------"
[1118]343 print " ", stat
[876]344 print "--------------------------------------------------"
345 print out
[1118]346 retval = { 'axesnames': ['scanno', 'beamno', 'ifno', 'polno', 'cycleno'],
[876]347 'axes' : axes,
348 'data': statvals}
349 return retval
[102]350
[1118]351 def stddev(self, mask=None):
[135]352 """
353 Determine the standard deviation of the current beam/if/pol
354 Takes a 'mask' as an optional parameter to specify which
355 channels should be excluded.
356 Parameters:
357 mask: an optional mask specifying where the standard
358 deviation should be determined.
359
360 Example:
361 scan.set_unit('channel')
[1118]362 msk = scan.create_mask([100, 200], [500, 600])
[135]363 scan.stddev(mask=m)
364 """
[1118]365 return self.stats(stat='stddev', mask=mask);
[135]366
[1003]367
368 def column_names(self):
369 """
370 Return a list of column names, which can be used for selection.
371 """
372 return list(Scantable.column_names(self))
373
[876]374 def get_tsys(self):
[113]375 """
376 Return the System temperatures.
377 Parameters:
[876]378
[113]379 Returns:
[876]380 a list of Tsys values for the current selection
[113]381 """
[256]382
[876]383 return self._row_callback(self._gettsys, "Tsys")
[256]384
[876]385 def _row_callback(self, callback, label):
386 axes = []
[1118]387 axesnames = ['scanno', 'beamno', 'ifno', 'polno', 'cycleno']
[876]388 out = ""
[1118]389 outvec = []
[876]390 for i in range(self.nrow()):
391 axis = []
392 axis.append(self.getscan(i))
393 axis.append(self.getbeam(i))
394 axis.append(self.getif(i))
395 axis.append(self.getpol(i))
396 axis.append(self.getcycle(i))
397 axes.append(axis)
398 tm = self._gettime(i)
399 src = self._getsourcename(i)
400 out += 'Scan[%d] (%s) ' % (axis[0], src)
401 out += 'Time[%s]:\n' % (tm)
402 if self.nbeam(-1) > 1: out += ' Beam[%d] ' % (axis[1])
403 if self.nif(-1) > 1: out += ' IF[%d] ' % (axis[2])
404 if self.npol(-1) > 1: out += ' Pol[%d] ' % (axis[3])
405 outvec.append(callback(i))
406 out += '= %3.3f\n' % (outvec[i])
407 out += "--------------------------------------------------\n"
408 if rcParams['verbose']:
409 print "--------------------------------------------------"
410 print " %s" % (label)
411 print "--------------------------------------------------"
412 print out
[1175]413 # disabled because the vector seems more useful
414 #retval = {'axesnames': axesnames, 'axes': axes, 'data': outvec}
415 return outvec
[256]416
[1070]417 def _get_column(self, callback, row=-1):
418 """
419 """
420 if row == -1:
421 return [callback(i) for i in range(self.nrow())]
422 else:
423 if 0 <= row < self.nrow():
424 return callback(row)
[256]425
[1070]426
[407]427 def get_time(self, row=-1):
[113]428 """
429 Get a list of time stamps for the observations.
[181]430 Return a string for each integration in the scantable.
[113]431 Parameters:
[407]432 row: row no of integration. Default -1 return all rows
[113]433 Example:
434 none
435 """
[1175]436 from time import strptime
437 from datetime import datetime
438 times = self._get_column(self._gettime, row)
439 format = "%Y/%m/%d/%H:%M:%S"
440 if isinstance(times, list):
441 return [datetime(*strptime(i, format)[:6]) for i in times]
442 else:
443 return datetime(*strptime(times, format)[:6])
[102]444
[714]445 def get_sourcename(self, row=-1):
446 """
[794]447 Get a list source names for the observations.
[714]448 Return a string for each integration in the scantable.
449 Parameters:
450 row: row no of integration. Default -1 return all rows
451 Example:
452 none
453 """
[1070]454 return self._get_column(self._getsourcename, row)
[714]455
[794]456 def get_elevation(self, row=-1):
457 """
458 Get a list of elevations for the observations.
459 Return a float for each integration in the scantable.
460 Parameters:
461 row: row no of integration. Default -1 return all rows
462 Example:
463 none
464 """
[1070]465 return self._get_column(self._getelevation, row)
[794]466
467 def get_azimuth(self, row=-1):
468 """
469 Get a list of azimuths for the observations.
470 Return a float for each integration in the scantable.
471 Parameters:
472 row: row no of integration. Default -1 return all rows
473 Example:
474 none
475 """
[1070]476 return self._get_column(self._getazimuth, row)
[794]477
478 def get_parangle(self, row=-1):
479 """
480 Get a list of parallactic angles for the observations.
481 Return a float for each integration in the scantable.
482 Parameters:
483 row: row no of integration. Default -1 return all rows
484 Example:
485 none
486 """
[1070]487 return self._get_column(self._getparangle, row)
[794]488
[1070]489 def get_direction(self, row=-1):
490 """
491 Get a list of Positions on the sky (direction) for the observations.
492 Return a float for each integration in the scantable.
493 Parameters:
494 row: row no of integration. Default -1 return all rows
495 Example:
496 none
497 """
498 return self._get_column(self._getdirection, row)
499
[102]500 def set_unit(self, unit='channel'):
501 """
502 Set the unit for all following operations on this scantable
503 Parameters:
504 unit: optional unit, default is 'channel'
[1118]505 one of '*Hz', 'km/s', 'channel', ''
[102]506 """
[484]507 varlist = vars()
[1118]508 if unit in ['', 'pixel', 'channel']:
[113]509 unit = ''
510 inf = list(self._getcoordinfo())
511 inf[0] = unit
512 self._setcoordinfo(inf)
[1118]513 self._add_history("set_unit", varlist)
[113]514
[484]515 def set_instrument(self, instr):
[358]516 """
517 Set the instrument for subsequent processing
518 Parameters:
[710]519 instr: Select from 'ATPKSMB', 'ATPKSHOH', 'ATMOPRA',
[407]520 'DSS-43' (Tid), 'CEDUNA', and 'HOBART'
[358]521 """
522 self._setInstrument(instr)
[1118]523 self._add_history("set_instument", vars())
[718]524 print_log()
[358]525
[1190]526 def set_feedtype(self, feedtype):
527 """
528 Overwrite the feed type, which might not be set correctly.
529 Parameters:
530 feedtype: 'linear' or 'circular'
531 """
532 self._setfeedtype(feedtype)
533 self._add_history("set_feedtype", vars())
534 print_log()
535
[276]536 def set_doppler(self, doppler='RADIO'):
537 """
538 Set the doppler for all following operations on this scantable.
539 Parameters:
540 doppler: One of 'RADIO', 'OPTICAL', 'Z', 'BETA', 'GAMMA'
541 """
[484]542 varlist = vars()
[276]543 inf = list(self._getcoordinfo())
544 inf[2] = doppler
545 self._setcoordinfo(inf)
[1118]546 self._add_history("set_doppler", vars())
[718]547 print_log()
[710]548
[226]549 def set_freqframe(self, frame=None):
[113]550 """
551 Set the frame type of the Spectral Axis.
552 Parameters:
[591]553 frame: an optional frame type, default 'LSRK'. Valid frames are:
[1118]554 'REST', 'TOPO', 'LSRD', 'LSRK', 'BARY',
555 'GEO', 'GALACTO', 'LGROUP', 'CMB'
[113]556 Examples:
557 scan.set_freqframe('BARY')
558 """
[484]559 if frame is None: frame = rcParams['scantable.freqframe']
560 varlist = vars()
[1118]561 valid = ['REST', 'TOPO', 'LSRD', 'LSRK', 'BARY', \
562 'GEO', 'GALACTO', 'LGROUP', 'CMB']
[591]563
[989]564 if frame in valid:
[113]565 inf = list(self._getcoordinfo())
566 inf[1] = frame
567 self._setcoordinfo(inf)
[1118]568 self._add_history("set_freqframe", varlist)
[102]569 else:
[1118]570 msg = "Please specify a valid freq type. Valid types are:\n", valid
[718]571 if rcParams['verbose']:
572 print msg
573 else:
574 raise TypeError(msg)
575 print_log()
[710]576
[989]577 def set_dirframe(self, frame=""):
578 """
579 Set the frame type of the Direction on the sky.
580 Parameters:
581 frame: an optional frame type, default ''. Valid frames are:
582 'J2000', 'B1950', 'GALACTIC'
583 Examples:
584 scan.set_dirframe('GALACTIC')
585 """
586 varlist = vars()
587 try:
588 Scantable.set_dirframe(self, frame)
[1118]589 except RuntimeError, msg:
[989]590 if rcParams['verbose']:
591 print msg
592 else:
593 raise
[1118]594 self._add_history("set_dirframe", varlist)
[989]595
[113]596 def get_unit(self):
597 """
598 Get the default unit set in this scantable
599 Parameters:
600 Returns:
601 A unit string
602 """
603 inf = self._getcoordinfo()
604 unit = inf[0]
605 if unit == '': unit = 'channel'
606 return unit
[102]607
[158]608 def get_abcissa(self, rowno=0):
[102]609 """
[158]610 Get the abcissa in the current coordinate setup for the currently
[113]611 selected Beam/IF/Pol
612 Parameters:
[226]613 rowno: an optional row number in the scantable. Default is the
614 first row, i.e. rowno=0
[113]615 Returns:
[407]616 The abcissa values and it's format string (as a dictionary)
[113]617 """
[256]618 abc = self._getabcissa(rowno)
[710]619 lbl = self._getabcissalabel(rowno)
[718]620 print_log()
[158]621 return abc, lbl
[113]622
[1118]623 def flag(self, mask=None):
[1001]624 """
625 Flag the selected data using an optional channel mask.
626 Parameters:
627 mask: an optional channel mask, created with create_mask. Default
628 (no mask) is all channels.
629 """
630 varlist = vars()
[1118]631 if mask is None:
632 mask = []
[1001]633 try:
634 self._flag(mask)
[1118]635 except RuntimeError, msg:
[1001]636 if rcParams['verbose']:
637 print msg
638 return
639 else: raise
640 self._add_history("flag", varlist)
641
[1203]642 def lag_flag(self, frequency, width=0.0, unit="GHz", insitu=None):
[1192]643 """
644 Flag the data in 'lag' space by providing a frequency to remove.
645 Flagged data in the scantable gets set to 0.0 before the fft.
646 No taper is applied.
647 Parameters:
[1203]648 frequency: the frequency (really a period within the bandwidth) to remove
649 width: the width of the frequency to remove, to remove a range
650 of frequencies aroung the centre.
651 unit: the frequency unit (default "GHz")
652 Notes:
653 It is recommended to flag edges of the band or strong signals beforehand.
[1192]654 """
655 if insitu is None: insitu = rcParams['insitu']
656 self._math._setinsitu(insitu)
657 varlist = vars()
658 base = { "GHz": 100000000., "MHz": 1000000., "kHz": 1000., "Hz": 1. }
659 if not base.has_key(unit):
660 raise ValueError("%s is not a valid unit." % unit)
661 try:
[1200]662 s = scantable(self._math._lag_flag(self, frequency*base[unit],
663 width*base[unit]))
[1192]664 except RuntimeError, msg:
665 if rcParams['verbose']:
666 print msg
667 return
668 else: raise
669 s._add_history("lag_flag", varlist)
670 print_log()
671 if insitu:
672 self._assign(s)
673 else:
674 return s
[1001]675
[1192]676
[113]677 def create_mask(self, *args, **kwargs):
678 """
[1118]679 Compute and return a mask based on [min, max] windows.
[189]680 The specified windows are to be INCLUDED, when the mask is
[113]681 applied.
[102]682 Parameters:
[1118]683 [min, max], [min2, max2], ...
[1024]684 Pairs of start/end points (inclusive)specifying the regions
[102]685 to be masked
[189]686 invert: optional argument. If specified as True,
687 return an inverted mask, i.e. the regions
688 specified are EXCLUDED
[513]689 row: create the mask using the specified row for
690 unit conversions, default is row=0
691 only necessary if frequency varies over rows.
[102]692 Example:
[113]693 scan.set_unit('channel')
694 a)
[1118]695 msk = scan.create_mask([400, 500], [800, 900])
[189]696 # masks everything outside 400 and 500
[113]697 # and 800 and 900 in the unit 'channel'
698
699 b)
[1118]700 msk = scan.create_mask([400, 500], [800, 900], invert=True)
[189]701 # masks the regions between 400 and 500
[113]702 # and 800 and 900 in the unit 'channel'
[1024]703 c)
704 mask only channel 400
[1118]705 msk = scan.create_mask([400, 400])
[102]706 """
[513]707 row = 0
708 if kwargs.has_key("row"):
709 row = kwargs.get("row")
710 data = self._getabcissa(row)
[113]711 u = self._getcoordinfo()[0]
[718]712 if rcParams['verbose']:
[113]713 if u == "": u = "channel"
[718]714 msg = "The current mask window unit is %s" % u
[1118]715 i = self._check_ifs()
716 if not i:
[876]717 msg += "\nThis mask is only valid for IF=%d" % (self.getif(i))
[718]718 asaplog.push(msg)
[102]719 n = self.nchan()
[1134]720 msk = NUM.zeros(n)
[710]721 # test if args is a 'list' or a 'normal *args - UGLY!!!
722
[1118]723 ws = (isinstance(args[-1][-1], int) or isinstance(args[-1][-1], float)) \
724 and args or args[0]
[710]725 for window in ws:
[102]726 if (len(window) != 2 or window[0] > window[1] ):
[1118]727 raise TypeError("A window needs to be defined as [min, max]")
[102]728 for i in range(n):
[1024]729 if data[i] >= window[0] and data[i] <= window[1]:
[189]730 msk[i] = 1
[113]731 if kwargs.has_key('invert'):
732 if kwargs.get('invert'):
[1134]733 msk = NUM.logical_not(msk)
[718]734 print_log()
[102]735 return msk
[710]736
[256]737 def get_restfreqs(self):
738 """
739 Get the restfrequency(s) stored in this scantable.
740 The return value(s) are always of unit 'Hz'
741 Parameters:
742 none
743 Returns:
744 a list of doubles
745 """
746 return list(self._getrestfreqs())
[102]747
[402]748
[931]749 def set_restfreqs(self, freqs=None, unit='Hz'):
750 """
751 Set or replace the restfrequency specified and
752 If the 'freqs' argument holds a scalar,
753 then that rest frequency will be applied to all the selected
754 data. If the 'freqs' argument holds
755 a vector, then it MUST be of equal or smaller length than
756 the number of IFs (and the available restfrequencies will be
757 replaced by this vector). In this case, *all* data have
758 the restfrequency set per IF according
759 to the corresponding value you give in the 'freqs' vector.
[1118]760 E.g. 'freqs=[1e9, 2e9]' would mean IF 0 gets restfreq 1e9 and
[931]761 IF 1 gets restfreq 2e9.
[1153]762 You can also specify the frequencies via a linecatalog/
763
[931]764 Parameters:
765 freqs: list of rest frequency values or string idenitfiers
766 unit: unit for rest frequency (default 'Hz')
[402]767
[931]768 Example:
769 # set the given restfrequency for the whole table
770 scan.set_restfreqs(freqs=1.4e9)
771 # If thee number of IFs in the data is >= 2 the IF0 gets the first
772 # value IF1 the second...
[1118]773 scan.set_restfreqs(freqs=[1.4e9, 1.67e9])
[931]774 #set the given restfrequency for the whole table (by name)
775 scan.set_restfreqs(freqs="OH1667")
[391]776
[931]777 Note:
778 To do more sophisticate Restfrequency setting, e.g. on a
779 source and IF basis, use scantable.set_selection() before using
780 this function.
781 # provide your scantable is call scan
782 selection = selector()
783 selection.set_name("ORION*")
784 selection.set_ifs([1])
785 scan.set_selection(selection)
786 scan.set_restfreqs(freqs=86.6e9)
787
788 """
789 varlist = vars()
[1157]790 from asap import linecatalog
791 # simple value
[1118]792 if isinstance(freqs, int) or isinstance(freqs, float):
[1153]793 self._setrestfreqs(freqs, "",unit)
[1157]794 # list of values
[1118]795 elif isinstance(freqs, list) or isinstance(freqs, tuple):
[1157]796 # list values are scalars
[1118]797 if isinstance(freqs[-1], int) or isinstance(freqs[-1], float):
[931]798 sel = selector()
799 savesel = self._getselection()
800 for i in xrange(len(freqs)):
[946]801 sel.set_ifs([i])
[931]802 self._setselection(sel)
[1153]803 self._setrestfreqs(freqs[i], "",unit)
[931]804 self._setselection(savesel)
[1157]805 # list values are tuples, (value, name)
806 elif isinstance(freqs[-1], dict):
807 sel = selector()
808 savesel = self._getselection()
809 for i in xrange(len(freqs)):
810 sel.set_ifs([i])
811 self._setrestfreqs(freqs[i]["value"],
812 freqs[i]["name"], "MHz")
813 self._setselection(sel)
814 self._setselection(savesel)
815 # freqs are to be taken from a linecatalog
[1153]816 elif isinstance(freqs, linecatalog):
817 sel = selector()
818 savesel = self._getselection()
819 for i in xrange(freqs.nrow()):
820 sel.set_ifs([i])
821 self._setselection(sel)
822 self._setrestfreqs(freqs.get_frequency(i),
823 freqs.get_name(i), "MHz")
824 # ensure that we are not iterating past nIF
825 if i == self.nif()-1: break
826 self._setselection(savesel)
[931]827 else:
828 return
829 self._add_history("set_restfreqs", varlist)
830
831
832
[484]833 def history(self):
834 hist = list(self._gethistory())
[794]835 out = "-"*80
[484]836 for h in hist:
[489]837 if h.startswith("---"):
[794]838 out += "\n"+h
[489]839 else:
840 items = h.split("##")
841 date = items[0]
842 func = items[1]
843 items = items[2:]
[794]844 out += "\n"+date+"\n"
845 out += "Function: %s\n Parameters:" % (func)
[489]846 for i in items:
847 s = i.split("=")
[1118]848 out += "\n %s = %s" % (s[0], s[1])
[794]849 out += "\n"+"-"*80
850 try:
851 from IPython.genutils import page as pager
852 except ImportError:
853 from pydoc import pager
854 pager(out)
[484]855 return
856
[513]857 #
858 # Maths business
859 #
860
[931]861 def average_time(self, mask=None, scanav=False, weight='tint', align=False):
[513]862 """
[1070]863 Return the (time) weighted average of a scan.
[513]864 Note:
[1070]865 in channels only - align if necessary
[513]866 Parameters:
867 mask: an optional mask (only used for 'var' and 'tsys'
868 weighting)
[558]869 scanav: True averages each scan separately
870 False (default) averages all scans together,
[1099]871 weight: Weighting scheme.
872 'none' (mean no weight)
873 'var' (1/var(spec) weighted)
874 'tsys' (1/Tsys**2 weighted)
875 'tint' (integration time weighted)
876 'tintsys' (Tint/Tsys**2)
877 'median' ( median averaging)
[535]878 The default is 'tint'
[931]879 align: align the spectra in velocity before averaging. It takes
880 the time of the first spectrum as reference time.
[513]881 Example:
882 # time average the scantable without using a mask
[710]883 newscan = scan.average_time()
[513]884 """
885 varlist = vars()
[976]886 if weight is None: weight = 'TINT'
[513]887 if mask is None: mask = ()
[1099]888 if scanav: scanav = "SCAN"
889 else: scanav = "NONE"
[1118]890 scan = (self, )
[989]891 try:
[1118]892 if align:
893 scan = (self.freq_align(insitu=False), )
894 s = None
895 if weight.upper() == 'MEDIAN':
896 s = scantable(self._math._averagechannel(scan[0], 'MEDIAN',
897 scanav))
898 else:
899 s = scantable(self._math._average(scan, mask, weight.upper(),
900 scanav))
901 except RuntimeError, msg:
[989]902 if rcParams['verbose']:
903 print msg
904 return
905 else: raise
[1099]906 s._add_history("average_time", varlist)
[718]907 print_log()
[513]908 return s
[710]909
[876]910 def convert_flux(self, jyperk=None, eta=None, d=None, insitu=None):
[513]911 """
912 Return a scan where all spectra are converted to either
913 Jansky or Kelvin depending upon the flux units of the scan table.
914 By default the function tries to look the values up internally.
915 If it can't find them (or if you want to over-ride), you must
916 specify EITHER jyperk OR eta (and D which it will try to look up
917 also if you don't set it). jyperk takes precedence if you set both.
918 Parameters:
919 jyperk: the Jy / K conversion factor
920 eta: the aperture efficiency
921 d: the geomtric diameter (metres)
922 insitu: if False a new scantable is returned.
923 Otherwise, the scaling is done in-situ
924 The default is taken from .asaprc (False)
925 allaxes: if True apply to all spectra. Otherwise
926 apply only to the selected (beam/pol/if)spectra only
927 The default is taken from .asaprc (True if none)
928 """
929 if insitu is None: insitu = rcParams['insitu']
[876]930 self._math._setinsitu(insitu)
[513]931 varlist = vars()
932 if jyperk is None: jyperk = -1.0
933 if d is None: d = -1.0
934 if eta is None: eta = -1.0
[876]935 s = scantable(self._math._convertflux(self, d, eta, jyperk))
936 s._add_history("convert_flux", varlist)
937 print_log()
938 if insitu: self._assign(s)
939 else: return s
[513]940
[876]941 def gain_el(self, poly=None, filename="", method="linear", insitu=None):
[513]942 """
943 Return a scan after applying a gain-elevation correction.
944 The correction can be made via either a polynomial or a
945 table-based interpolation (and extrapolation if necessary).
946 You specify polynomial coefficients, an ascii table or neither.
947 If you specify neither, then a polynomial correction will be made
948 with built in coefficients known for certain telescopes (an error
949 will occur if the instrument is not known).
950 The data and Tsys are *divided* by the scaling factors.
951 Parameters:
952 poly: Polynomial coefficients (default None) to compute a
953 gain-elevation correction as a function of
954 elevation (in degrees).
955 filename: The name of an ascii file holding correction factors.
956 The first row of the ascii file must give the column
957 names and these MUST include columns
958 "ELEVATION" (degrees) and "FACTOR" (multiply data
959 by this) somewhere.
960 The second row must give the data type of the
961 column. Use 'R' for Real and 'I' for Integer.
962 An example file would be
963 (actual factors are arbitrary) :
964
965 TIME ELEVATION FACTOR
966 R R R
967 0.1 0 0.8
968 0.2 20 0.85
969 0.3 40 0.9
970 0.4 60 0.85
971 0.5 80 0.8
972 0.6 90 0.75
973 method: Interpolation method when correcting from a table.
974 Values are "nearest", "linear" (default), "cubic"
975 and "spline"
976 insitu: if False a new scantable is returned.
977 Otherwise, the scaling is done in-situ
978 The default is taken from .asaprc (False)
979 """
980
981 if insitu is None: insitu = rcParams['insitu']
[876]982 self._math._setinsitu(insitu)
[513]983 varlist = vars()
984 if poly is None:
[1118]985 poly = ()
[513]986 from os.path import expandvars
987 filename = expandvars(filename)
[876]988 s = scantable(self._math._gainel(self, poly, filename, method))
989 s._add_history("gain_el", varlist)
990 print_log()
991 if insitu: self._assign(s)
992 else: return s
[710]993
[931]994 def freq_align(self, reftime=None, method='cubic', insitu=None):
[513]995 """
996 Return a scan where all rows have been aligned in frequency/velocity.
997 The alignment frequency frame (e.g. LSRK) is that set by function
998 set_freqframe.
999 Parameters:
1000 reftime: reference time to align at. By default, the time of
1001 the first row of data is used.
1002 method: Interpolation method for regridding the spectra.
1003 Choose from "nearest", "linear", "cubic" (default)
1004 and "spline"
1005 insitu: if False a new scantable is returned.
1006 Otherwise, the scaling is done in-situ
1007 The default is taken from .asaprc (False)
1008 """
[931]1009 if insitu is None: insitu = rcParams["insitu"]
[876]1010 self._math._setinsitu(insitu)
[513]1011 varlist = vars()
[931]1012 if reftime is None: reftime = ""
1013 s = scantable(self._math._freq_align(self, reftime, method))
[876]1014 s._add_history("freq_align", varlist)
1015 print_log()
1016 if insitu: self._assign(s)
1017 else: return s
[513]1018
[876]1019 def opacity(self, tau, insitu=None):
[513]1020 """
1021 Apply an opacity correction. The data
1022 and Tsys are multiplied by the correction factor.
1023 Parameters:
1024 tau: Opacity from which the correction factor is
1025 exp(tau*ZD)
1026 where ZD is the zenith-distance
1027 insitu: if False a new scantable is returned.
1028 Otherwise, the scaling is done in-situ
1029 The default is taken from .asaprc (False)
1030 """
1031 if insitu is None: insitu = rcParams['insitu']
[876]1032 self._math._setinsitu(insitu)
[513]1033 varlist = vars()
[876]1034 s = scantable(self._math._opacity(self, tau))
1035 s._add_history("opacity", varlist)
1036 print_log()
1037 if insitu: self._assign(s)
1038 else: return s
[513]1039
1040 def bin(self, width=5, insitu=None):
1041 """
1042 Return a scan where all spectra have been binned up.
1043 width: The bin width (default=5) in pixels
1044 insitu: if False a new scantable is returned.
1045 Otherwise, the scaling is done in-situ
1046 The default is taken from .asaprc (False)
1047 """
1048 if insitu is None: insitu = rcParams['insitu']
[876]1049 self._math._setinsitu(insitu)
[513]1050 varlist = vars()
[876]1051 s = scantable(self._math._bin(self, width))
[1118]1052 s._add_history("bin", varlist)
[876]1053 print_log()
1054 if insitu: self._assign(s)
1055 else: return s
[513]1056
[710]1057
[513]1058 def resample(self, width=5, method='cubic', insitu=None):
1059 """
1060 Return a scan where all spectra have been binned up
1061 width: The bin width (default=5) in pixels
1062 method: Interpolation method when correcting from a table.
1063 Values are "nearest", "linear", "cubic" (default)
1064 and "spline"
1065 insitu: if False a new scantable is returned.
1066 Otherwise, the scaling is done in-situ
1067 The default is taken from .asaprc (False)
1068 """
1069 if insitu is None: insitu = rcParams['insitu']
[876]1070 self._math._setinsitu(insitu)
[513]1071 varlist = vars()
[876]1072 s = scantable(self._math._resample(self, method, width))
[1118]1073 s._add_history("resample", varlist)
[876]1074 print_log()
1075 if insitu: self._assign(s)
1076 else: return s
[513]1077
1078
[946]1079 def average_pol(self, mask=None, weight='none'):
1080 """
1081 Average the Polarisations together.
1082 Parameters:
1083 mask: An optional mask defining the region, where the
1084 averaging will be applied. The output will have all
1085 specified points masked.
1086 weight: Weighting scheme. 'none' (default), 'var' (1/var(spec)
1087 weighted), or 'tsys' (1/Tsys**2 weighted)
1088 """
1089 varlist = vars()
1090 if mask is None:
1091 mask = ()
[1010]1092 s = scantable(self._math._averagepol(self, mask, weight.upper()))
[1118]1093 s._add_history("average_pol", varlist)
[946]1094 print_log()
[992]1095 return s
[513]1096
[1145]1097 def average_beam(self, mask=None, weight='none'):
1098 """
1099 Average the Beams together.
1100 Parameters:
1101 mask: An optional mask defining the region, where the
1102 averaging will be applied. The output will have all
1103 specified points masked.
1104 weight: Weighting scheme. 'none' (default), 'var' (1/var(spec)
1105 weighted), or 'tsys' (1/Tsys**2 weighted)
1106 """
1107 varlist = vars()
1108 if mask is None:
1109 mask = ()
1110 s = scantable(self._math._averagebeams(self, mask, weight.upper()))
1111 s._add_history("average_beam", varlist)
1112 print_log()
1113 return s
1114
[992]1115 def convert_pol(self, poltype=None):
1116 """
1117 Convert the data to a different polarisation type.
1118 Parameters:
1119 poltype: The new polarisation type. Valid types are:
1120 "linear", "stokes" and "circular"
1121 """
1122 varlist = vars()
1123 try:
1124 s = scantable(self._math._convertpol(self, poltype))
[1118]1125 except RuntimeError, msg:
[992]1126 if rcParams['verbose']:
[1118]1127 print msg
1128 return
[992]1129 else:
1130 raise
[1118]1131 s._add_history("convert_pol", varlist)
[992]1132 print_log()
1133 return s
1134
[876]1135 def smooth(self, kernel="hanning", width=5.0, insitu=None):
[513]1136 """
1137 Smooth the spectrum by the specified kernel (conserving flux).
1138 Parameters:
1139 scan: The input scan
1140 kernel: The type of smoothing kernel. Select from
1141 'hanning' (default), 'gaussian' and 'boxcar'.
1142 The first three characters are sufficient.
1143 width: The width of the kernel in pixels. For hanning this is
1144 ignored otherwise it defauls to 5 pixels.
1145 For 'gaussian' it is the Full Width Half
1146 Maximum. For 'boxcar' it is the full width.
1147 insitu: if False a new scantable is returned.
1148 Otherwise, the scaling is done in-situ
1149 The default is taken from .asaprc (False)
1150 Example:
1151 none
1152 """
1153 if insitu is None: insitu = rcParams['insitu']
[876]1154 self._math._setinsitu(insitu)
[513]1155 varlist = vars()
[1118]1156 s = scantable(self._math._smooth(self, kernel.lower(), width))
[876]1157 s._add_history("smooth", varlist)
1158 print_log()
1159 if insitu: self._assign(s)
1160 else: return s
[513]1161
[876]1162
[1061]1163 def poly_baseline(self, mask=None, order=0, plot=False, insitu=None):
[513]1164 """
1165 Return a scan which has been baselined (all rows) by a polynomial.
1166 Parameters:
[794]1167 scan: a scantable
1168 mask: an optional mask
1169 order: the order of the polynomial (default is 0)
[1061]1170 plot: plot the fit and the residual. In this each
1171 indivual fit has to be approved, by typing 'y'
1172 or 'n'
[794]1173 insitu: if False a new scantable is returned.
1174 Otherwise, the scaling is done in-situ
1175 The default is taken from .asaprc (False)
[513]1176 Example:
1177 # return a scan baselined by a third order polynomial,
1178 # not using a mask
1179 bscan = scan.poly_baseline(order=3)
[579]1180 """
[513]1181 if insitu is None: insitu = rcParams['insitu']
1182 varlist = vars()
1183 if mask is None:
[1134]1184 mask = list(NUM.ones(self.nchan(-1)))
[513]1185 from asap.asapfitter import fitter
1186 f = fitter()
1187 f.set_scan(self, mask)
1188 f.set_function(poly=order)
[1061]1189 s = f.auto_fit(insitu, plot=plot)
[876]1190 s._add_history("poly_baseline", varlist)
[718]1191 print_log()
[876]1192 if insitu: self._assign(s)
1193 else: return s
[513]1194
[1118]1195 def auto_poly_baseline(self, mask=[], edge=(0, 0), order=0,
[1061]1196 threshold=3, plot=False, insitu=None):
[880]1197 """
1198 Return a scan which has been baselined (all rows) by a polynomial.
1199 Spectral lines are detected first using linefinder and masked out
1200 to avoid them affecting the baseline solution.
1201
1202 Parameters:
1203 mask: an optional mask retreived from scantable
1204 edge: an optional number of channel to drop at
1205 the edge of spectrum. If only one value is
1206 specified, the same number will be dropped from
1207 both sides of the spectrum. Default is to keep
[907]1208 all channels. Nested tuples represent individual
[976]1209 edge selection for different IFs (a number of spectral
1210 channels can be different)
[880]1211 order: the order of the polynomial (default is 0)
1212 threshold: the threshold used by line finder. It is better to
1213 keep it large as only strong lines affect the
1214 baseline solution.
[1061]1215 plot: plot the fit and the residual. In this each
1216 indivual fit has to be approved, by typing 'y'
1217 or 'n'
[880]1218 insitu: if False a new scantable is returned.
1219 Otherwise, the scaling is done in-situ
1220 The default is taken from .asaprc (False)
1221
1222 Example:
1223 scan2=scan.auto_poly_baseline(order=7)
1224 """
1225 if insitu is None: insitu = rcParams['insitu']
1226 varlist = vars()
1227 from asap.asapfitter import fitter
1228 from asap.asaplinefind import linefinder
1229 from asap import _is_sequence_or_number as _is_valid
1230
[976]1231 # check whether edge is set up for each IF individually
[1118]1232 individualedge = False;
1233 if len(edge) > 1:
1234 if isinstance(edge[0], list) or isinstance(edge[0], tuple):
1235 individualedge = True;
[907]1236
[1118]1237 if not _is_valid(edge, int) and not individualedge:
[909]1238 raise ValueError, "Parameter 'edge' has to be an integer or a \
[907]1239 pair of integers specified as a tuple. Nested tuples are allowed \
1240 to make individual selection for different IFs."
[919]1241
[1118]1242 curedge = (0, 0)
1243 if individualedge:
1244 for edgepar in edge:
1245 if not _is_valid(edgepar, int):
1246 raise ValueError, "Each element of the 'edge' tuple has \
1247 to be a pair of integers or an integer."
[907]1248 else:
[1118]1249 curedge = edge;
[880]1250
1251 # setup fitter
1252 f = fitter()
1253 f.set_function(poly=order)
1254
1255 # setup line finder
[1118]1256 fl = linefinder()
[880]1257 fl.set_options(threshold=threshold)
1258
1259 if not insitu:
[1118]1260 workscan = self.copy()
[880]1261 else:
[1118]1262 workscan = self
[880]1263
[907]1264 fl.set_scan(workscan)
1265
[1118]1266 rows = range(workscan.nrow())
[880]1267 asaplog.push("Processing:")
1268 for r in rows:
[1118]1269 msg = " Scan[%d] Beam[%d] IF[%d] Pol[%d] Cycle[%d]" % \
1270 (workscan.getscan(r), workscan.getbeam(r), workscan.getif(r), \
1271 workscan.getpol(r), workscan.getcycle(r))
[880]1272 asaplog.push(msg, False)
[907]1273
[976]1274 # figure out edge parameter
[1118]1275 if individualedge:
1276 if len(edge) >= workscan.getif(r):
1277 raise RuntimeError, "Number of edge elements appear to " \
1278 "be less than the number of IFs"
1279 curedge = edge[workscan.getif(r)]
[919]1280
[976]1281 # setup line finder
[1118]1282 fl.find_lines(r, mask, curedge)
[880]1283 f.set_scan(workscan, fl.get_mask())
1284 f.x = workscan._getabcissa(r)
1285 f.y = workscan._getspectrum(r)
1286 f.data = None
1287 f.fit()
1288 x = f.get_parameters()
[1061]1289 if plot:
1290 f.plot(residual=True)
1291 x = raw_input("Accept fit ( [y]/n ): ")
1292 if x.upper() == 'N':
1293 continue
[880]1294 workscan._setspectrum(f.fitter.getresidual(), r)
[1061]1295 if plot:
1296 f._p.unmap()
1297 f._p = None
1298 workscan._add_history("auto_poly_baseline", varlist)
[880]1299 if insitu:
1300 self._assign(workscan)
1301 else:
1302 return workscan
1303
[914]1304 def rotate_linpolphase(self, angle):
1305 """
1306 Rotate the phase of the complex polarization O=Q+iU correlation.
1307 This is always done in situ in the raw data. So if you call this
1308 function more than once then each call rotates the phase further.
1309 Parameters:
1310 angle: The angle (degrees) to rotate (add) by.
1311 Examples:
1312 scan.rotate_linpolphase(2.3)
1313 """
1314 varlist = vars()
[936]1315 self._math._rotate_linpolphase(self, angle)
[914]1316 self._add_history("rotate_linpolphase", varlist)
1317 print_log()
1318 return
[710]1319
[513]1320
[914]1321 def rotate_xyphase(self, angle):
1322 """
1323 Rotate the phase of the XY correlation. This is always done in situ
1324 in the data. So if you call this function more than once
1325 then each call rotates the phase further.
1326 Parameters:
1327 angle: The angle (degrees) to rotate (add) by.
1328 Examples:
1329 scan.rotate_xyphase(2.3)
1330 """
1331 varlist = vars()
[936]1332 self._math._rotate_xyphase(self, angle)
[914]1333 self._add_history("rotate_xyphase", varlist)
1334 print_log()
1335 return
1336
1337 def swap_linears(self):
1338 """
1339 Swap the linear polarisations XX and YY
1340 """
1341 varlist = vars()
[936]1342 self._math._swap_linears(self)
[914]1343 self._add_history("swap_linears", varlist)
1344 print_log()
1345 return
1346
1347 def invert_phase(self):
1348 """
1349 Invert the phase of the complex polarisation
1350 """
1351 varlist = vars()
[936]1352 self._math._invert_phase(self)
[914]1353 self._add_history("invert_phase", varlist)
1354 print_log()
1355 return
1356
[876]1357 def add(self, offset, insitu=None):
[513]1358 """
1359 Return a scan where all spectra have the offset added
1360 Parameters:
1361 offset: the offset
1362 insitu: if False a new scantable is returned.
1363 Otherwise, the scaling is done in-situ
1364 The default is taken from .asaprc (False)
1365 """
1366 if insitu is None: insitu = rcParams['insitu']
[876]1367 self._math._setinsitu(insitu)
[513]1368 varlist = vars()
[876]1369 s = scantable(self._math._unaryop(self, offset, "ADD", False))
[1118]1370 s._add_history("add", varlist)
[876]1371 print_log()
1372 if insitu:
1373 self._assign(s)
1374 else:
[513]1375 return s
1376
[1118]1377 def scale(self, factor, tsys=True, insitu=None, ):
[513]1378 """
1379 Return a scan where all spectra are scaled by the give 'factor'
1380 Parameters:
1381 factor: the scaling factor
1382 insitu: if False a new scantable is returned.
1383 Otherwise, the scaling is done in-situ
1384 The default is taken from .asaprc (False)
1385 tsys: if True (default) then apply the operation to Tsys
1386 as well as the data
1387 """
1388 if insitu is None: insitu = rcParams['insitu']
[876]1389 self._math._setinsitu(insitu)
[513]1390 varlist = vars()
[876]1391 s = scantable(self._math._unaryop(self, factor, "MUL", tsys))
[1118]1392 s._add_history("scale", varlist)
[876]1393 print_log()
1394 if insitu:
1395 self._assign(s)
1396 else:
[513]1397 return s
1398
[876]1399 def auto_quotient(self, mode='time', preserve=True):
[670]1400 """
1401 This function allows to build quotients automatically.
1402 It assumes the observation to have the same numer of
1403 "ons" and "offs"
1404 It will support "closest off in time" in the future
1405 Parameters:
1406 mode: the on/off detection mode; 'suffix' (default)
1407 'suffix' identifies 'off' scans by the
1408 trailing '_R' (Mopra/Parkes) or
1409 '_e'/'_w' (Tid)
[710]1410 preserve: you can preserve (default) the continuum or
1411 remove it. The equations used are
[670]1412 preserve: Output = Toff * (on/off) - Toff
[1070]1413 remove: Output = Toff * (on/off) - Ton
[670]1414 """
[876]1415 modes = ["time"]
[670]1416 if not mode in modes:
[876]1417 msg = "please provide valid mode. Valid modes are %s" % (modes)
1418 raise ValueError(msg)
1419 varlist = vars()
[1070]1420 s = scantable(self._math._auto_quotient(self, mode, preserve))
[1118]1421 s._add_history("auto_quotient", varlist)
[876]1422 print_log()
1423 return s
[710]1424
[1145]1425 def mx_quotient(self, mask = None, weight='median', preserve=True):
[1141]1426 """
[1143]1427 Form a quotient using "off" beams when observing in "MX" mode.
1428 Parameters:
[1145]1429 mask: an optional mask to be used when weight == 'stddev'
[1143]1430 weight: How to average the off beams. Default is 'median'.
[1145]1431 preserve: you can preserve (default) the continuum or
1432 remove it. The equations used are
1433 preserve: Output = Toff * (on/off) - Toff
1434 remove: Output = Toff * (on/off) - Ton
[1203]1435 """
[1143]1436 if mask is None: mask = ()
[1141]1437 varlist = vars()
1438 on = scantable(self._math._mx_extract(self, 'on'))
[1143]1439 preoff = scantable(self._math._mx_extract(self, 'off'))
1440 off = preoff.average_time(mask=mask, weight=weight, scanav=False)
[1203]1441 from asapmath import quotient
[1145]1442 q = quotient(on, off, preserve)
[1143]1443 q._add_history("mx_quotient", varlist)
[1145]1444 print_log()
[1203]1445 return q
[513]1446
[718]1447 def freq_switch(self, insitu=None):
1448 """
1449 Apply frequency switching to the data.
1450 Parameters:
1451 insitu: if False a new scantable is returned.
1452 Otherwise, the swictching is done in-situ
1453 The default is taken from .asaprc (False)
1454 Example:
1455 none
1456 """
1457 if insitu is None: insitu = rcParams['insitu']
[876]1458 self._math._setinsitu(insitu)
[718]1459 varlist = vars()
[876]1460 s = scantable(self._math._freqswitch(self))
[1118]1461 s._add_history("freq_switch", varlist)
[876]1462 print_log()
1463 if insitu: self._assign(s)
1464 else: return s
[718]1465
[780]1466 def recalc_azel(self):
1467 """
1468 Recalculate the azimuth and elevation for each position.
1469 Parameters:
1470 none
1471 Example:
1472 """
1473 varlist = vars()
[876]1474 self._recalcazel()
[780]1475 self._add_history("recalc_azel", varlist)
1476 print_log()
1477 return
1478
[513]1479 def __add__(self, other):
1480 varlist = vars()
1481 s = None
1482 if isinstance(other, scantable):
[876]1483 print "scantable + scantable NYI"
1484 return
[513]1485 elif isinstance(other, float):
[876]1486 s = scantable(self._math._unaryop(self, other, "ADD", False))
[513]1487 else:
[718]1488 raise TypeError("Other input is not a scantable or float value")
[513]1489 s._add_history("operator +", varlist)
[718]1490 print_log()
[513]1491 return s
1492
1493 def __sub__(self, other):
1494 """
1495 implicit on all axes and on Tsys
1496 """
1497 varlist = vars()
1498 s = None
1499 if isinstance(other, scantable):
[876]1500 print "scantable - scantable NYI"
1501 return
[513]1502 elif isinstance(other, float):
[876]1503 s = scantable(self._math._unaryop(self, other, "SUB", False))
[513]1504 else:
[718]1505 raise TypeError("Other input is not a scantable or float value")
[513]1506 s._add_history("operator -", varlist)
[718]1507 print_log()
[513]1508 return s
[710]1509
[513]1510 def __mul__(self, other):
1511 """
1512 implicit on all axes and on Tsys
1513 """
1514 varlist = vars()
1515 s = None
1516 if isinstance(other, scantable):
[876]1517 print "scantable * scantable NYI"
1518 return
[513]1519 elif isinstance(other, float):
[876]1520 s = scantable(self._math._unaryop(self, other, "MUL", False))
[513]1521 else:
[718]1522 raise TypeError("Other input is not a scantable or float value")
[513]1523 s._add_history("operator *", varlist)
[718]1524 print_log()
[513]1525 return s
1526
[710]1527
[513]1528 def __div__(self, other):
1529 """
1530 implicit on all axes and on Tsys
1531 """
1532 varlist = vars()
1533 s = None
1534 if isinstance(other, scantable):
[876]1535 print "scantable / scantable NYI"
1536 return
[513]1537 elif isinstance(other, float):
1538 if other == 0.0:
[718]1539 raise ZeroDivisionError("Dividing by zero is not recommended")
[876]1540 s = scantable(self._math._unaryop(self, other, "DIV", False))
[513]1541 else:
[718]1542 raise TypeError("Other input is not a scantable or float value")
[513]1543 s._add_history("operator /", varlist)
[718]1544 print_log()
[513]1545 return s
1546
[530]1547 def get_fit(self, row=0):
1548 """
1549 Print or return the stored fits for a row in the scantable
1550 Parameters:
1551 row: the row which the fit has been applied to.
1552 """
1553 if row > self.nrow():
1554 return
[976]1555 from asap.asapfit import asapfit
[530]1556 fit = asapfit(self._getfit(row))
[718]1557 if rcParams['verbose']:
[530]1558 print fit
1559 return
1560 else:
1561 return fit.as_dict()
1562
[484]1563 def _add_history(self, funcname, parameters):
1564 # create date
1565 sep = "##"
1566 from datetime import datetime
1567 dstr = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
1568 hist = dstr+sep
1569 hist += funcname+sep#cdate+sep
1570 if parameters.has_key('self'): del parameters['self']
[1118]1571 for k, v in parameters.iteritems():
[484]1572 if type(v) is dict:
[1118]1573 for k2, v2 in v.iteritems():
[484]1574 hist += k2
1575 hist += "="
[1118]1576 if isinstance(v2, scantable):
[484]1577 hist += 'scantable'
1578 elif k2 == 'mask':
[1118]1579 if isinstance(v2, list) or isinstance(v2, tuple):
[513]1580 hist += str(self._zip_mask(v2))
1581 else:
1582 hist += str(v2)
[484]1583 else:
[513]1584 hist += str(v2)
[484]1585 else:
1586 hist += k
1587 hist += "="
[1118]1588 if isinstance(v, scantable):
[484]1589 hist += 'scantable'
1590 elif k == 'mask':
[1118]1591 if isinstance(v, list) or isinstance(v, tuple):
[513]1592 hist += str(self._zip_mask(v))
1593 else:
1594 hist += str(v)
[484]1595 else:
1596 hist += str(v)
1597 hist += sep
1598 hist = hist[:-2] # remove trailing '##'
1599 self._addhistory(hist)
1600
[710]1601
[484]1602 def _zip_mask(self, mask):
1603 mask = list(mask)
1604 i = 0
1605 segments = []
1606 while mask[i:].count(1):
1607 i += mask[i:].index(1)
1608 if mask[i:].count(0):
1609 j = i + mask[i:].index(0)
1610 else:
[710]1611 j = len(mask)
[1118]1612 segments.append([i, j])
[710]1613 i = j
[484]1614 return segments
[714]1615
[626]1616 def _get_ordinate_label(self):
1617 fu = "("+self.get_fluxunit()+")"
1618 import re
1619 lbl = "Intensity"
[1118]1620 if re.match(".K.", fu):
[626]1621 lbl = "Brightness Temperature "+ fu
[1118]1622 elif re.match(".Jy.", fu):
[626]1623 lbl = "Flux density "+ fu
1624 return lbl
[710]1625
[876]1626 def _check_ifs(self):
1627 nchans = [self.nchan(i) for i in range(self.nif(-1))]
[889]1628 nchans = filter(lambda t: t > 0, nchans)
[876]1629 return (sum(nchans)/len(nchans) == nchans[0])
[976]1630
1631 def _fill(self, names, unit, average):
1632 import os
1633 from asap._asap import stfiller
1634 first = True
1635 fullnames = []
1636 for name in names:
1637 name = os.path.expandvars(name)
1638 name = os.path.expanduser(name)
1639 if not os.path.exists(name):
1640 msg = "File '%s' does not exists" % (name)
1641 if rcParams['verbose']:
1642 asaplog.push(msg)
1643 print asaplog.pop().strip()
1644 return
1645 raise IOError(msg)
1646 fullnames.append(name)
1647 if average:
1648 asaplog.push('Auto averaging integrations')
[1079]1649 stype = int(rcParams['scantable.storage'].lower() == 'disk')
[976]1650 for name in fullnames:
[1073]1651 tbl = Scantable(stype)
1652 r = stfiller(tbl)
[976]1653 msg = "Importing %s..." % (name)
[1118]1654 asaplog.push(msg, False)
[976]1655 print_log()
[1118]1656 r._open(name, -1, -1)
[976]1657 r._read()
[1073]1658 #tbl = r._getdata()
[976]1659 if average:
[1118]1660 tbl = self._math._average((tbl, ), (), 'NONE', 'SCAN')
[976]1661 #tbl = tbl2
1662 if not first:
1663 tbl = self._math._merge([self, tbl])
1664 #tbl = tbl2
1665 Scantable.__init__(self, tbl)
1666 r._close()
[1118]1667 del r, tbl
[976]1668 first = False
1669 if unit is not None:
1670 self.set_fluxunit(unit)
1671 self.set_freqframe(rcParams['scantable.freqframe'])
1672 #self._add_history("scantable", varlist)
1673
Note: See TracBrowser for help on using the repository browser.