#!/usr/bin/python """ Module to handle formatting sodar data samples. A list of sample data. A sample: formattedDataObject[0] -> dictionary A sample header: formattedDataObject[0]['header'] -> dictionary A sample body: formattedDataObject[0]['body'] -> list of dictionaries Altitude data from a sample: formattedDataObject[0]['body'][0] -> dictionary """ __author__ = 'Chris Calloway' __email__ = 'cbc@unc.edu' __copyright__ = 'Copyright 2007 UNC-CH Department of Marine Science' __license__ = 'GPL2' import rawData import numpy as n import datetime class FormattedData(list): """Class to handle formatted daily sodar file data. A list of samples. """ def __init__(self, data): """Create formatted sodar daily data.""" super(FormattedData, self).__init__() self.extend([sample.data() for sample in data]) self._convert() self._stamp() self._beginStamp() self._endStamp() self._numIntervals() self._timeInterval() self._minAltitude() self._maxAltitude() self._numAltitudes() self._altInterval() def _convert(self): """Convert data to numbers and correct for invalid values.""" INVALID = "-9999" for sample in self: # convert header data to integers for key,value in sample['header'].items(): try: if value == INVALID: raise ValueError sample['header'][key] = int(value) except (ValueError, TypeError): sample['header'][key] = n.NaN # convert body data to floats for altitude in sample['body']: for key,value in altitude.items(): try: if value == INVALID: raise ValueError altitude[key] = float(value) except (ValueError, TypeError): altitude[key] = n.NaN def _stamp(self): """Add a datetime stamp item to each sample.""" for sample in self: header = sample['header'] sample['stamp'] = datetime.datetime(header['YEAR'], header['MONTH'], header['DAY'], header['HOUR'], header['MIN']) def _beginStamp(self): self.beginStamp = self[0]['stamp'] def _endStamp(self): self.endStamp = self[-1]['stamp'] def _numIntervals(self): self.numIntervals = len(self) def _timeInterval(self): """Add a time interval attribute.""" intervals = zip([sample['stamp'] for sample in self[:-1]], [sample['stamp'] for sample in self[1:]]) intervals = [interval[1] - interval[0] for interval in intervals] self.timeInterval = min(intervals) def _minAltitude(self): """Add an overall minimum altitude attribute.""" altitudes = [sample['body'][0]['ALT'] for sample in self] self.minAltitude = min(altitudes) def _maxAltitude(self): """Add an overall maximum altitude attribute.""" altitudes = [sample['body'][-1]['ALT'] for sample in self] self.maxAltitude = max(altitudes) def _numAltitudes(self): """Add an overall maximum number of altitudes attribute""" self.numAltitudes = max([len(sample['body']) for sample in self]) def _altInterval(self): """Add an overall altitude interval attribute.""" self.altInterval = (self.maxAltitude - self.minAltitude) / \ (self.numAltitudes - 1) def thetas(self): """Create a list of lists of horizontal directional data.""" return [[altitude['DIR'] for altitude in sample['body']] for sample in self] def radials(self): """Create a list of lists of horizontal radial velocity data.""" return [[altitude['SPEED'] for altitude in sample['body']] for sample in self] def wComponents(self): """Create a list of lists of vertical velocity data.""" return [[altitude['W'] for altitude in sample['body']] for sample in self] def echoStrengths(self): """Create a list of lists of echo strength data.""" return [[altitude['CT'] for altitude in sample['body']] for sample in self] def _main(): """Process as script from command line.""" import urllib2 try: rawDataHandle = urllib2.urlopen('http://nemo.isis.unc.edu/'\ 'data/nccoos/level0/ims/sodar/'\ '2008_01/20080101.dat') rawDataString = rawDataHandle.read() rawDataHandle.close() except: raise IOError("Failure to read raw test data") rawDataObject = rawData.RawData(rawDataString) formattedDataObject = FormattedData(rawDataObject) print "Time Interval =", formattedDataObject.timeInterval print "Minumum Altitude =", formattedDataObject.minAltitude print "Maximum Altitude =", formattedDataObject.maxAltitude print "Number of Altitudes =", formattedDataObject.numAltitudes print "Altitude Interval =", formattedDataObject.altInterval if __name__ == "__main__": _main()