source: branches/alma/python/scantable.py@ 1628

Last change on this file since 1628 was 1627, checked in by Takeshi Nakazato, 15 years ago

New Development: No

JIRA Issue: No

Ready to Release: Yes

Interface Changes: No

What Interface Changed: Please list interface changes

Test Programs: List test programs

Put in Release Notes: No

Module(s): Module Names change impacts.

Description: Describe your changes here...

Bug fix.

asaplog.push( msg ) in the except section is not correct.
I have modified it to asaplog.push( msg.message ).


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