source: trunk/python/scantable.py@ 1294

Last change on this file since 1294 was 1280, checked in by mar637, 18 years ago

Merge from Release2.1.1b tag

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