# Copyright (C) 2012 VT SuperDARN Lab
# Full license can be found in LICENSE.txt
"""
*********************
**Module**: gme.mho
*********************
This module handles Millstone Hill ISR data
**Class**:
* :class:`mhoData`: Read Millstone Hill data, either locally if it can be found, or directly from Madrigal
"""
# constants
user_fullname = 'Sebastien de Larquier'
user_email = 'sdelarquier@vt.edu'
user_affiliation = 'Virginia Tech'
#####################################################
#####################################################
[docs]class mhoData(object):
"""Read Millstone Hill data, either locally if it can be found, or directly from Madrigal
**Args**:
* **expDate** (datetime.datetime): experiment date
* **[endDate]** (datetime.datetime): end date/time to look for experiment files on Madrigal
* **[getMad]** (bool): force download from Madrigal (overwrite any matching local file)
* **[dataPath]** (str): path where the local data should be read/saved
* **[fileExt]** (str): file extension (i.e., 'g.002'). If None is provided, it will just look for the most recent available one
* **user_fullname** (str): required to download data from Madrigal (no registration needed)
* **user_email** (str): required to download data from Madrigal (no registration needed)
* **user_affiliation** (str): required to download data from Madrigal (no registration needed)
**Example**:
::
# Get data for November 17-18, 2010
import datetime as dt
user_fullname = 'Sebastien de Larquier'
user_email = 'sdelarquier@vt.edu'
user_affiliation = 'Virginia Tech'
date = dt.datetime(2010,11,17,20)
edate = dt.datetime(2010,11,18,13)
data = mhoData( date, endDate=edate,
user_fullname=user_fullname,
user_email=user_email,
user_affiliation=user_affiliation )
written by Sebastien de Larquier, 2013-03
"""
def __init__(self, expDate, endDate=None,
dataPath=None, fileExt=None, getMad=False,
user_fullname=None, user_email=None, user_affiliation=None):
self.expDate = expDate
self.endDate = endDate
self.dataPath = dataPath
self.fileExt = fileExt
self.mhoCipher = {'nel': r'N$_e$ [$\log$(m$^{-3}$)]',
'ti': r'T$_i$ [K]',
'te': r'T$_e$ [K]',
'vo': r'v$_i$ [m/s]'}
# Look for the file locally
if not getMad:
filePath = self.getFileLocal()
# If no local files, get it from madrigal
if getMad or not filePath:
if None in [user_fullname, user_email, user_affiliation]:
print 'Error: Please provide user_fullname, user_email, user_affiliation.'
return
filePath = self.getFileMad(user_fullname, user_email, user_affiliation)
print filePath
if filePath:
self.readData(filePath)
[docs] def look(self):
"""Returns radar pointing directions during selected experiment
"""
import numpy as np
pointing = [(el, az) for el, az in zip(np.around(self.elev.flatten(),1), np.around(self.azim.flatten(),1))]
return np.unique(pointing)
[docs] def readData(self, filePath):
"""Read data from HDF5 file
**Args**:
* **filePath** (str): Path and name of HDF5 file
"""
import h5py as h5
import matplotlib as mp
import numpy as np
from utils import geoPack as gp
from utils import Re
import datetime as dt
with h5.File(filePath,'r') as f:
data = f['Data']['Array Layout']
data2D = data['2D Parameters']
data1D = data['1D Parameters']
params = f['Metadata']['Experiment Parameters']
self.nel = data2D['nel'][:].T
self.ne = data2D['ne'][:].T
self.ti = data2D['ti'][:].T
self.vo = data2D['vo'][:].T
self.te = data2D['tr'][:].T * self.ti
self.range = data['range'][:]
self.time = np.array( [ dt.datetime.utcfromtimestamp(tt) for tt in data['timestamps'][:].T ] )
self.elev = np.array( [data1D['el1'][:],
data1D['el2'][:]] ).T
self.azim = np.array( [data1D['az1'][:],
data1D['az2'][:]] ).T
try:
self.scntyp = data1D['scntyp'][:]
except:
self.scntyp = np.zeros(self.time.shape)
vinds = np.where( self.elev[:,0] >= 88. )
if len(vinds[0]) > 0:
self.scntyp[vinds] = 5
self.gdalt = data2D['gdalt'][:].T
self.position = [float(params[7][1]),
float(params[8][1]),
float(params[9][1])]
self.lat = data2D['glat'][:].T
self.lon = data2D['glon'][:].T
[docs] def getFileLocal(self):
"""Look for the file in the dataPath or current directory
**Belongs to**: :class:`mhoData`
**Returns**:
* **filePath**: the path and name of the data file
"""
import os, glob, datetime
import numpy as np
fileName = 'mlh{:%y%m%d}'.format( self.expDate )
if not self.fileExt:
dfiles = np.sort(glob.glob(self.dataPath+fileName+'?.???.hdf5'))
if not not list(dfiles):
self.fileExt = dfiles[-1][-10:-5]
else: return
fileName = fileName + self.fileExt + '.hdf5'
filePath = os.path.join(self.dataPath, fileName)
return filePath
[docs] def getFileMad(self, user_fullname, user_email, user_affiliation):
"""Look for the data on Madrigal
**Belongs to**: :class:`mhoData`
**Returns**:
* **filePath**: the path and name of the data file
"""
import madrigalWeb.madrigalWeb
import os, h5py, numpy, datetime
from matplotlib.dates import date2num, epoch2num, num2date
madrigalUrl = 'http://cedar.openmadrigal.org'
madData = madrigalWeb.madrigalWeb.MadrigalData(madrigalUrl)
# Start and end date/time
sdate = self.expDate
fdate = self.endDate if self.endDate else sdate + datetime.timedelta(days=1)
# Get experiment list
expList = madData.getExperiments(30,
sdate.year, sdate.month, sdate.day, sdate.hour,
sdate.minute, sdate.second,
fdate.year, fdate.month, fdate.day, fdate.hour,
fdate.minute, fdate.second)
if not expList: return
# Try to get the default file
thisFilename = False
fileList = madData.getExperimentFiles(expList[0].id)
for thisFile in fileList:
if thisFile.category == 1:
thisFilename = thisFile.name
break
if not thisFilename: return
# Download HDF5 file
result = madData.downloadFile(thisFilename,
os.path.join( self.dataPath,"{}.hdf5"\
.format(os.path.split(thisFilename)[1]) ),
user_fullname, user_email, user_affiliation,
format="hdf5")
# Now add some derived data to the hdf5 file
res = madData.isprint(thisFilename,
'YEAR,MONTH,DAY,HOUR,MIN,SEC,RANGE,GDALT,NE,NEL,MDTYP,GDLAT,GLON',
'', user_fullname, user_email, user_affiliation)
rows = res.split("\n")
filePath = os.path.join( self.dataPath,
os.path.split(thisFilename)[1]+'.hdf5' )
self.fileExt = ( os.path.split(thisFilename)[1] )[-1]
# Add new datasets to hdf5 file
with h5py.File(filePath,'r+') as f:
ftime = epoch2num( f['Data']['Array Layout']['timestamps'] )
frange = f['Data']['Array Layout']['range']
tDim, rDim = ftime.shape[0], frange.shape[0]
shape2d = (tDim, rDim)
gdalt = numpy.empty(shape2d)
gdalt[:] = numpy.nan
gdlat = numpy.empty(shape2d)
gdlat[:] = numpy.nan
gdlon = numpy.empty(shape2d)
gdlon[:] = numpy.nan
ne = numpy.empty(shape2d)
ne[:] = numpy.nan
nel = numpy.empty(shape2d)
nel[:] = numpy.nan
dtfmt = '%Y-%m-%d %H:%M:%S'
dttype = numpy.dtype('a{}'.format(len(dtfmt)+2))
dtime = numpy.empty(tDim, dtype=dttype)
# Iterate through the downloaded data
for r in rows:
dat = r.split()
if not dat: continue
# Figure out your range/time index
dt = datetime.datetime( int(dat[0]), int(dat[1]), int(dat[2]),
int(dat[3]), int(dat[4]), int(dat[5]) )
tind = numpy.where(ftime[:] <= date2num(dt))[0]
rind = numpy.where(frange[:] <= float(dat[6]))[0]
if not list(tind) or not list(rind): continue
if dat[7] != 'missing':
gdalt[tind[-1],rind[-1]] = float(dat[7])
if dat[8] != 'missing':
ne[tind[-1],rind[-1]] = float(dat[8])
if dat[9] != 'missing':
nel[tind[-1],rind[-1]] = float(dat[9])
dtime[tind[-1]] = dt.strftime(dtfmt)
if dat[11] != 'missing':
gdlat[tind[-1],rind[-1]] = float(dat[11])
if dat[12] != 'missing':
gdlon[tind[-1],rind[-1]] = float(dat[12])
# Add 2D datasets
parent = f['Data']['Array Layout']['2D Parameters']
gdalt_ds = parent.create_dataset('gdalt', data=gdalt)
gdalt_ds = parent.create_dataset('glat', data=gdlat)
gdalt_ds = parent.create_dataset('glon', data=gdlon)
ne_ds = parent.create_dataset('ne', data=ne)
nel_ds = parent.create_dataset('nel', data=nel)
# Add 1D datasets
parent = f['Data']['Array Layout']
datetime_ds = parent.create_dataset('datetime', data=dtime)
return filePath