def satDXToTimeSeries(filename): file = open(filename) data = ft.read(file) (rows, cols) = data.shape dict = pyLTR.TimeSeries() mon = [] mday = [] dayFraction = [] doy = [] atime = [] for i in range(rows): d = datetime.date(int(data[i, 0]), 1, 1) + datetime.timedelta(int(data[i, 1]) - 1) mon.append(d.month) mday.append(d.day) dayFraction = (data[i, 2] + data[i, 3] / 60.0 + data[i, 4] / 3600.0) / 24.0 doy.append(float(data[i, 1]) + dayFraction) #atime.append(datetime.datetime(d.year,d.month,d.day,data[i,2],data[i,3],data[i,4])) dict.append('time_doy', 'Day of Year', ' ', doy) dict.append('density', 'Den', r'$\mathrm{1/cm^3}$', data[:, 5]) dict.append('vx', 'Vx', r'$\mathrm{km/s}$', data[:, 6]) dict.append('vy', 'Vy', r'$\mathrm{km/s}$', data[:, 7]) dict.append('vz', 'Vz', r'$\mathrm{km/s}$', data[:, 8]) dict.append('p', 'P', r'$\mathrm{keV/cm^3}$', data[:, 9]) dict.append('bx', 'Bx', r'$\mathrm{nT}$', data[:, 10]) dict.append('by', 'By', r'$\mathrm{nT}$', data[:, 11]) dict.append('bz', 'Bz', r'$\mathrm{nT}$', data[:, 12]) dict.append('ex', 'Ex', r'$\mathrm{V/m}$', data[:, 13]) dict.append('ey', 'Ey', r'$\mathrm{V/m}$', data[:, 14]) dict.append('ez', 'Ez', r'$\mathrm{V/m}$', data[:, 15]) return dict
def __init__(self, filename = None): self.data = pyLTR.TimeSeries() self.bad_data = ['-1.00000E+31'] # Match the beginning of a line with a date & time (i.e. 16-04-2008 00:00:00.000) self.dateRegEx = r=re.compile(r'^\d{2}\-\d{2}-\d{4} \d{2}\:\d{2}\:\d{2}\.\d{3}') self.__read(filename) self.__appendDerivedQuantities()
def extractQuantities(path, run, t0, t1): """ Extract MIX quantities from the input path. Execute `mixTimeSeries.py --help` for details on the function parameters (path,run,t0,t1). Outputs a pyLTR.TimeSeries object containing the data. """ data = pyLTR.Models.MIX(path, run) # hard-coded input for testing & debugging: #data = pyLTR.Models.LFM('/hao/aim2/schmitt/data/LTR-2_0_1b/r1432/March1995/LR/single', 'LRs') #Make sure variables are defined in the model. modelVars = data.getVarNames() for v in [ 'Grid X', 'Grid Y', 'Poynting flux North [???]', 'Poynting flux South [???]', 'FAC North [A/m^2]', 'FAC South [A/m^2]', 'Number flux North [1/cm^2 s]', 'Number flux South [1/cm^2 s]', 'BBE average energy North [keV]', 'BBE average energy South [keV]', 'BBE number flux North [1/cm^2 s]', 'BBE number flux South [1/cm^2 s]', 'Cusp average energy North [keV]', 'Cusp average energy South [keV]', 'Cusp number flux North [1/cm^2 s]', 'Cusp number flux South [1/cm^2 s]' ]: # print v assert (v in modelVars) timeRange = data.getTimeRange() if len(timeRange) == 0: raise Exception(( 'No data files found. Are you pointing to the correct run directory?' )) index0 = 0 if t0: for i, t in enumerate(timeRange): if t0 >= t: index0 = i index1 = len(timeRange) - 1 if t1: for i, t in enumerate(timeRange): if t1 >= t: index1 = i print(('Extracting MIX quantities for time series over %d time steps.' % (index1 - index0))) # Output a status bar displaying how far along the computation is. progress = pyLTR.StatusBar(0, index1 - index0) progress.start() t_doy = [] isparNorth = [] isparSouth = [] hpNorth = [] hpSouth = [] asparNorth = [] asparSouth = [] bbe = 0 cusp = 0 # Pre-compute area of the grid. x = data.read('Grid X', timeRange[index0]) y = data.read('Grid Y', timeRange[index0]) # Fix singularity at the pole x[:, 0] = 0.0 y[:, 0] = 0.0 z = numpy.sqrt(1.0 - x**2 - y**2) ri = 6500.0e3 # Radius of ionosphere in meters areaMixGrid = pyLTR.math.integrate.calcFaceAreas(x, y, z) * ri * ri for i, time in enumerate(timeRange[index0:index1]): try: # -- Day of Year tt = time.timetuple() t_doy.append(tt.tm_yday + tt.tm_hour / 24.0 + tt.tm_min / 1440.0 + tt.tm_sec / 86400.0) # --- Cross Polar Cap Potential psi = data.read('Poynting flux North [???]', time) psi[psi < 0] = 0. spar = areaMixGrid * psi[:-1, :-1] # is MIX grid in m^2? spar is in mW/m^2 # mW to GW isparNorth.append(spar.sum() * 1.e-12) spar = psi[psi > 0.1].mean() asparNorth.append(spar.sum()) psi = data.read('Poynting flux South [???]', time) psi[psi > 0] = 0. spar = areaMixGrid * psi[:-1, :-1] # is MIX grid in m^2? spar is in mW/m^2 # mW to GW isparSouth.append(spar.sum() * -1.e-12) spar = psi[psi < -0.1].mean() asparSouth.append(spar.sum() * -1.) # --- Hemispheric Power energy = data.read('Average energy North [keV]', time) flux = data.read('Number flux North [1/cm^2 s]', time) mhp = areaMixGrid * energy[:-1, :-1] * flux[:-1, :-1] flux = data.read('BBE number flux North [1/cm^2 s]', time) energy = data.read('BBE average energy North [keV]', time) bbe = areaMixGrid * energy[:-1, :-1] * flux[:-1, :-1] flux = data.read('Cusp number flux North [1/cm^2 s]', time) energy = data.read('Cusp average energy North [keV]', time) cusp = areaMixGrid * energy[:-1, :-1] * flux[:-1, :-1] hp = mhp + bbe + cusp # KeV/cm^2s to mW/m^2 to GW hpNorth.append(hp.sum() * 1.6e-21) energy = data.read('Average energy South [keV]', time) flux = data.read('Number flux South [1/cm^2 s]', time) mhp = areaMixGrid * energy[:-1, :-1] * flux[:-1, :-1] flux = data.read('BBE number flux South [1/cm^2 s]', time) energy = data.read('BBE average energy South [keV]', time) bbe = areaMixGrid * energy[:-1, :-1] * flux[:-1, :-1] flux = data.read('Cusp number flux South [1/cm^2 s]', time) energy = data.read('Cusp average energy South [keV]', time) cusp = areaMixGrid * energy[:-1, :-1] * flux[:-1, :-1] hp = mhp + bbe + cusp # KeV/cm^2s to mW/m^2 to GW hpSouth.append(hp.sum() * 1.6e-21) progress.increment() except KeyboardInterrupt: # Exit when the user hits CTRL+C. progress.stop() progress.join() print('Exiting.') import sys sys.exit(0) except: # Cleanup progress bar if something bad happened. progress.stop() progress.join() raise progress.stop() progress.join() dataNorth = pyLTR.TimeSeries() dataSouth = pyLTR.TimeSeries() dataNorth.append('datetime', 'Date & Time', '', timeRange[index0:index1]) dataSouth.append('datetime', 'Date & Time', '', timeRange[index0:index1]) dataNorth.append('doy', 'Day of Year', '', t_doy) dataSouth.append('doy', 'Day of Year', '', t_doy) # "N" and "S" label subscripts are redundant here, potentially leading to # mis-labeling of plots #dataNorth.append('cpcp', r'$\Phi_N$', 'kV', cpcpNorth) #dataSouth.append('cpcp', r'$\Phi_S$', 'kV', cpcpSouth) # #dataNorth.append('hp', r'$HP_N$', 'GW', hpNorth) #dataSouth.append('hp', r'$HP_S$', 'GW', hpSouth) # #dataNorth.append('ipfac', r'$FAC_N$', 'MA', ipfacNorth) #dataSouth.append('ipfac', r'$FAC_S$', 'MA', ipfacSouth) dataNorth.append('ispar', r'$Integrated S||$', 'GW', isparNorth) dataSouth.append('ispar', r'$Integrated S||$', 'GW', isparSouth) dataNorth.append('hp', r'$THP$', 'GW', hpNorth) dataSouth.append('hp', r'$THP$', 'GW', hpSouth) dataNorth.append('aspar', r'$Mean S||r$', 'mW/m^2', asparNorth) dataSouth.append('aspar', r'$Mean S||$', 'mW/m^2', asparSouth) return (dataNorth, dataSouth)
def getDst(path, runName, t0, t1): """ Returns a pyLTR.TimeSeries object containing the DST index Parameters: path: path to run runName: name of run we wish to compute DST for. """ data = pyLTR.Models.LFM(path, runName) # Hard-code a subset (useful for testing & debugging): #data = pyLTR.Models.LFM('/Users/schmitt/paraview/testData/March1995_LM_r1432_single', 'LMs') # Make sure variables are defined in the model. modelVars = data.getVarNames() for v in ['X_grid', 'Y_grid', 'Z_grid', 'bi_', 'bj_', 'bk_', 'bx_', 'by_', 'bz_', 'c_', 'ei_', 'ej_', 'ek_', 'rho_', 'vx_', 'vy_', 'vz_']: assert( v in modelVars ) timeRange = data.getTimeRange() if len(timeRange) == 0: raise Exception(('No data files found. Are you pointing to the correct run directory?')) index0 = 0 if t0: for i,t in enumerate(timeRange): if t0 >= t: index0 = i index1 = len(timeRange)-1 if t1: for i,t in enumerate(timeRange): if t1 >= t: index1 = i t_doy = [] dst = [] # Pre-compute some quantities #FIXME: Should this be a configurable parameter? earthRadius = 6.38e8 #earthRadius = 6340e5 x = data.read('X_grid', timeRange[index0]) / earthRadius y = data.read('Y_grid', timeRange[index0]) / earthRadius z = data.read('Z_grid', timeRange[index0]) / earthRadius dipStr = data.readAttribute('dipole_moment', timeRange[index0]) dipStr = dipStr.split('=')[1].strip().split()[0] gauss_2_nT = 1.0e5 dipoleMoment = float(dipStr) / (earthRadius**3) * gauss_2_nT print('Reticulating splines') #FIXME: nPoints and radius should be configurable nPoints = 4 radius = 3.0 (xc, yc, zc) = getCellCenters(x,y,z) ijk = getDstIndices(xc,yc,zc, nPoints, radius) print(( 'Extracting DST from MHD files for time series over %d time steps.' % (index1-index0) )) # Output a status bar displaying how far along the computation is. progress = pyLTR.StatusBar(0, index1-index0) progress.start() for i,time in enumerate(timeRange[index0:index1]): try: tt = time.timetuple() dayFraction = (tt.tm_hour+tt.tm_min/60.+tt.tm_sec/(60.*60.))/24. t_doy.append( float(tt.tm_yday) + dayFraction ) ## Skip the file if it can't be read. try: data.readAttribute('time', time) except HDF4Error as msg: sys.stderr.write('HDF4Error: Trouble "' + data._LFM__io.filename + '"\n') sys.stderr.write('HDF4 Error message: "' + str(msg) + '"\n') sys.stderr.write('Skipping file.\n') sys.stderr.flush() #FIXME: What's the correct behavior here for the dst # value? Set to last known good value? Pop array values? dst.append(dst[len(dst)-1]) continue # Calculate DST dstVal = 0.0 for idx in ijk: #FIXME: when count=[1,1,1], data.read(...) returns a 3d # array with just one element! #FIXME: setting a particular start index doesn't work # because dimensions are transposed because Fortran # does the I/O... so just read all the data :-( #bz = data.read('bz_', time, start=idx, count=(1,1,1)) bz = data.read('bz_', time) # scale to nT bz = bz[idx[0], idx[1], idx[2]] * gauss_2_nT dip = dipole( (xc[idx[0],idx[1],idx[2]], yc[idx[0],idx[1],idx[2]], zc[idx[0],idx[1],idx[2]]), dipoleMoment) dstVal += bz - dip[2] dstVal /= len(ijk) dst.append( dstVal ) progress.increment() except KeyboardInterrupt: # Exit when the user hits CTRL+C. progress.stop() progress.join() print('Exiting.') sys.exit(0) except: # Cleanup progress bar if something bad happened. progress.stop() progress.join() raise progress.stop() progress.join() if len(dst) == 0: raise Exception(('No data computed. Did you specify a valid run path?')) data = pyLTR.TimeSeries() data.append('datetime', 'Date & Time', '', timeRange[index0:index1]) data.append('doy', 'Day of Year', '', t_doy) data.append('dst', 'Disturbance Storm Time Index', 'nT', dst) return data
def calculateIndex(path='./', run='', t0='', t1='', obsList=None, geoGrid=False, ignoreBinary=False, binaryType='pkl', outDirName='figs'): """ Compute deltaBs at virtual observatories, then generate an Dst-like index, given LFM-MIX output files in path. Computes: SymAsyDst - a dict of pyLTR.TimeSeries objects, corresponding to the total, ionospheric current, field-aligned current, and magnetospheric current constituent of dBH (mag dipole northward, scaled by mag latitude), dBD (mag dipole eastward), and dBDst (horizontal, scaled by mag latitude), including both symmetric and asymmetric components. NOTE: while the outputs are pyLTR.TimeSeries objects, the function generates binary pkl/mat files that combine each specified observatory for each time step; this helps reduce re-computation time for subsequent calls to this function, and provides snapshots of output to be read in by alternative analysis software Requires: Nothing, all inputs are optional Optional: path - path to data directory holding LFM and MIX model output files (default is current directory) run - output filename prefix identifying LFM-MIX run (i.e., the part of the filename prior to [mhd|mix]_yyyy-mm-ddTHH-MM-SSZ.hdf) (default is any mhd|mix files in path) t0 - datetime object specifying the earliest of available time step to include in the extraction (default is earliest available) t1 - datetime object specfiying the latest of available time step to include in the extraction (default is last available) obsList - a list of lists of observatory coordinates [phi,theta,rho,ID] where ID is an optional 4th element to each coordinate set that, ideally, uniquely identifies the observatory...if ID is not specified, it is assigned an empty string. (default is coordinate system origin) geoGrid - if True, assume observatory coordinates are in geographic coordinates rather than solar magnetic; same for outputs (default is False) ignoreBinary - if True, ignore any pre-computed binary files and re- compute everything from scratch; NOTE: individual binary files will be ignored anyway if they are incompatible with specified inputs, but this option avoids reading the binary file entirely. (default is False) binaryType - binary type to generate, NOT to read in...routine looks for PKL files first, then mat files, then proceeds to re-compute if neither are available. (default is 'pkl') outDirName - name of directory into which all output will be placed; must be a relative path, to be appended to the input path; this is also where binary pkl/mat files will be expected if/when the function tries to read pre-computed data. (default is 'figs') """ # define and geo-locate virtual observatories if obsList==None or len(obsList) == 0: obsList = _defaultObs() # force geoGrid=True geoGrid=True # get delta B time series for Dst stations dBExtract = pyLTR.Tools.deltaBTimeSeries.extractQuantities dBObs = dBExtract(path=path, run=run, t0=t0, t1=t1, obsList=obsList, geoGrid=geoGrid, ignoreBinary=ignoreBinary, binaryType=binaryType, outDirName=outDirName) # convert lists of constituent vector components into NumPy arrays dBNorthIon = p.array([elem['dBIon']['North']['data'] for elem in dBObs]).T dBNorthFAC = p.array([elem['dBFAC']['North']['data'] for elem in dBObs]).T dBNorthMag = p.array([elem['dBMag']['North']['data'] for elem in dBObs]).T dBNorthTot = p.array([elem['dBTot']['North']['data'] for elem in dBObs]).T dBEastIon = p.array([elem['dBIon']['East']['data'] for elem in dBObs]).T dBEastFAC = p.array([elem['dBFAC']['East']['data'] for elem in dBObs]).T dBEastMag = p.array([elem['dBMag']['East']['data'] for elem in dBObs]).T dBEastTot = p.array([elem['dBTot']['East']['data'] for elem in dBObs]).T dBDownIon = p.array([elem['dBIon']['Down']['data'] for elem in dBObs]).T dBDownFAC = p.array([elem['dBFAC']['Down']['data'] for elem in dBObs]).T dBDownMag = p.array([elem['dBMag']['Down']['data'] for elem in dBObs]).T dBDownTot = p.array([elem['dBTot']['Down']['data'] for elem in dBObs]).T # convert deltaB vectors into local geomagnetic coordinates if they # are not there already if geoGrid: # extract geographic spherical coordinates phis = p.array([elem['dBTot']['phiGEO']['data'] for elem in dBObs]).T thetas = p.array([elem['dBTot']['thetaGEO']['data'] for elem in dBObs]).T rhos = p.array([elem['dBTot']['rhoGEO']['data'] for elem in dBObs]).T # extract datetime stamps datetimes = p.array([elem['dBTot']['datetime']['data'] for elem in dBObs]).T # convert Tot constituent to dipole North,East,Down coordinates # (must loop over time steps for correct time-dependent transforms) for i,ts in enumerate(datetimes): x,y,z,dx,dy,dz = pyLTR.transform.SPHtoCAR(phis[i,:], thetas[i,:], rhos[i,:], dBEastTot[i,:], -dBNorthTot[i,:], -dBDownTot[i,:]) x,y,z = pyLTR.transform.GEOtoSM(x,y,z,ts[0]) dx,dy,dz = pyLTR.transform.GEOtoSM(dx,dy,dz,ts[0]) p_ts,t_ts,r_ts,dp_ts,dt_ts,dr_ts = pyLTR.transform.CARtoSPH(x,y,z,dx,dy,dz) dBNorthTot[i,:] = -dt_ts dBEastTot[i,:] = dp_ts dBDownTot[i,:] = -dr_ts # convert Ion constituent to dipole North,East,Down coordinates # (must loop over time steps for correct time-dependent transforms) for i,ts in enumerate(datetimes): x,y,z,dx,dy,dz = pyLTR.transform.SPHtoCAR(phis[i,:], thetas[i,:], rhos[i,:], dBEastIon[i,:], -dBNorthIon[i,:], -dBDownIon[i,:]) x,y,z = pyLTR.transform.GEOtoSM(x,y,z,ts[0]) dx,dy,dz = pyLTR.transform.GEOtoSM(dx,dy,dz,ts[0]) p_ts,t_ts,r_ts,dp_ts,dt_ts,dr_ts = pyLTR.transform.CARtoSPH(x,y,z,dx,dy,dz) dBNorthIon[i,:] = -dt_ts dBEastIon[i,:] = dp_ts dBDownIon[i,:] = -dr_ts # convert FAC constituent to dipole North,East,Down coordinates # (must loop over time steps for correct time-dependent transforms) for i,ts in enumerate(datetimes): x,y,z,dx,dy,dz = pyLTR.transform.SPHtoCAR(phis[i,:], thetas[i,:], rhos[i,:], dBEastFAC[i,:], -dBNorthFAC[i,:], -dBDownFAC[i,:]) x,y,z = pyLTR.transform.GEOtoSM(x,y,z,ts[0]) dx,dy,dz = pyLTR.transform.GEOtoSM(dx,dy,dz,ts[0]) p_ts,t_ts,r_ts,dp_ts,dt_ts,dr_ts = pyLTR.transform.CARtoSPH(x,y,z,dx,dy,dz) dBNorthFAC[i,:] = -dt_ts dBEastFAC[i,:] = dp_ts dBDownFAC[i,:] = -dr_ts # convert Mag constituent to dipole North,East,Down coordinates # (must loop over time steps for correct time-dependent transforms) for i,ts in enumerate(datetimes): x,y,z,dx,dy,dz = pyLTR.transform.SPHtoCAR(phis[i,:], thetas[i,:], rhos[i,:], dBEastMag[i,:], -dBNorthMag[i,:], -dBDownMag[i,:]) x,y,z = pyLTR.transform.GEOtoSM(x,y,z,ts[0]) dx,dy,dz = pyLTR.transform.GEOtoSM(dx,dy,dz,ts[0]) p_ts,t_ts,r_ts,dp_ts,dt_ts,dr_ts = pyLTR.transform.CARtoSPH(x,y,z,dx,dy,dz) # note that we didn't update phis,thetas,rhos until now because we needed # them to remain in geographic for previous calls to GEOtoSM phis[i,:] = p_ts thetas[i,:] = t_ts rhos[i,:] = r_ts dBNorthMag[i,:] = -dt_ts dBEastMag[i,:] = dp_ts dBDownMag[i,:] = -dr_ts else: # extract SM spherical coordinates phis = p.array([elem['dBTot']['phiSM']['data'] for elem in dBObs]).T thetas = p.array([elem['dBTot']['thetaSM']['data'] for elem in dBObs]).T rhos = p.array([elem['dBTot']['rhoSM']['data'] for elem in dBObs]).T # everything else is already in the necessary coordinates # Now to replicate (more-or-less) SYM/ASY/Dst index algorithm(s) from # Kyoto WDC (i.e., http://wdc.kugi.kyoto-u.ac.jp/aeasy/asy.pdf) # symH is average of stations northward field normalized by the cosine # of the stations' dipole latitude # (this differs slightly from Sugiura's technique, which has never been # mathematically or physically sensible; also, the "paper" cited above # describes some sort of additional normalization for the ASY indices, # but is extremely confusing, so we're leaving that out for now) symHTot = (dBNorthTot / p.cos(p.pi/2 - thetas)).mean(axis=1) # indices to max/min disturbance are all based on the total current system; # this allows the constituents to sum up to give the total HMaxIdx = ((dBNorthTot / p.cos(p.pi/2 - thetas)) ).argmax(axis=1) HMinIdx = ((dBNorthTot / p.cos(p.pi/2 - thetas)) ).argmin(axis=1) # I do not understand how slices and index arrays are combined, so just create # an index array for all time steps (rows) allT = list(range(dBNorthTot.shape[0])) # indices from total current system #symHTot = (dBNorthTot / p.cos(p.pi/2 - thetas)).mean(axis=1) # redundant HMaxTot = ((dBNorthTot / p.cos(p.pi/2 - thetas)) )[allT,HMaxIdx] HMinTot = ((dBNorthTot / p.cos(p.pi/2 - thetas)) )[allT,HMinIdx] asyHTot = HMaxTot - HMinTot # indices from ionospheric current system symHIon = (dBNorthIon / p.cos(p.pi/2 - thetas)).mean(axis=1) HMaxIon = ((dBNorthIon / p.cos(p.pi/2 - thetas)) )[allT,HMaxIdx] HMinIon = ((dBNorthIon / p.cos(p.pi/2 - thetas)) )[allT,HMinIdx] asyHIon = HMaxIon - HMinIon # indices from field-aligned current system symHFAC = (dBNorthFAC / p.cos(p.pi/2 - thetas)).mean(axis=1) HMaxFAC = ((dBNorthFAC / p.cos(p.pi/2 - thetas)) )[allT,HMaxIdx] HMinFAC = ((dBNorthFAC / p.cos(p.pi/2 - thetas)) )[allT,HMinIdx] asyHFAC = HMaxFAC - HMinFAC # indices from magnetospheric current system symHMag = (dBNorthMag / p.cos(p.pi/2 - thetas)).mean(axis=1) HMaxMag = ((dBNorthMag / p.cos(p.pi/2 - thetas)) )[allT,HMaxIdx] HMinMag = ((dBNorthMag / p.cos(p.pi/2 - thetas)) )[allT,HMinIdx] asyHMag = HMaxMag - HMinMag # symD is average of stations eastward field, but NOT normalized by the # cosine of dipole latitude # (the "paper" cited above describes some sort of normalization for the ASY # indices, but is extremely confusing, so we're leaving that out for now) symDTot = dBEastTot.mean(axis=1) # indices to max/min disturbance are all based on the total current system; # this allows the constituents to sum up to give the total DMaxIdx = (dBEastTot ).argmax(axis=1) DMinIdx = (dBEastTot ).argmin(axis=1) # I do not understand how slices and index arrays are combined, so just create # an index array for all time steps (rows) allT = list(range(dBNorthTot.shape[0])) # indices from total current system #symDTot = dBEastTot.mean(axis=1) # redundant DMaxTot = (dBEastTot )[allT,DMaxIdx] DMinTot = (dBEastTot )[allT,DMinIdx] asyDTot = DMaxTot - DMinTot # indices from ionospheric current system symDIon = dBEastIon.mean(axis=1) DMaxIon = (dBEastIon )[allT,DMaxIdx] DMinIon = (dBEastIon )[allT,DMinIdx] asyDIon = DMaxIon - DMinIon # indices from field-aligned current system symDFAC = dBEastFAC.mean(axis=1) DMaxFAC = (dBEastFAC )[allT,DMaxIdx] DMinFAC = (dBEastFAC )[allT,DMinIdx] asyDFAC = DMaxFAC - DMinFAC # indices from magnetospheric current system symDMag = dBEastMag.mean(axis=1) DMaxMag = (dBEastMag )[allT,DMaxIdx] DMinMag = (dBEastMag )[allT,DMinIdx] asyDMag = DMaxMag - DMinMag """ FIXME NEED TO GET DST SIGN RIGHT, JUST LIKE WITH AE...IN OTHER WORDS, ADD BASELINE PRIOR TO VECTOR SUMMING, THEN SUBTRACT BASELINE TO ZERO OUT FIXME """ # Dst is average of stations' horizontal field normalized by the cosine # the stations' dipole latitude # (this differs slightly from Sugiura's technique, which has never been # mathematically or physically sensible; also, the "paper" cited above # describes some sort of additional normalization for the ASY indices, # but is extremely confusing, so we're leaving that out for now) #dBHorizTot = ( (p.sqrt((dBNorthTot+5e4)**2+dBEastTot**2) - # (5e4*p.cos(p.arctan2(dBEastTot,(dBNorthTot+5e4)) ) )) / # p.cos(p.pi/2 - thetas)) #dBHorizIon = ( (p.sqrt((dBNorthIon+5e4)**2+dBEastIon**2) - # (5e4*p.cos(p.arctan2(dBEastIon,(dBNorthIon+5e4)) ) )) / # p.cos(p.pi/2 - thetas)) #dBHorizFAC = ( (p.sqrt((dBNorthFAC+5e4)**2+dBEastFAC**2) - # (5e4*p.cos(p.arctan2(dBEastFAC,(dBNorthFAC+5e4)) ) )) / # p.cos(p.pi/2 - thetas)) #dBHorizMag = ( (p.sqrt((dBNorthMag+5e4)**2+dBEastMag**2) - # (5e4*p.cos(p.arctan2(dBEastMag,(dBNorthMag+5e4)) ) )) / # p.cos(p.pi/2 - thetas)) # calculate main field to add to deltaB before calculating horizontal field, # then subtract quadratic sum of main field components, assuming this is the # equivalent to removing a quiet baseline...I know this seems like a strange # thing to do, but real-world indices have positive and negative values, # which would be impossible if vector-component baselines were removed # *before* adding up the disturbance vectors; so, we add plausible vector # component baselines to our disturbance vectors to emulate how real-world # observations are collected, determine the horizontal field, then remove # the horizontal baseline. dipoleMF = pyLTR.Tools.deltaBTimeSeries._dipoleMF mfObs = [dipoleMF(obs['dBTot'], geoGrid) for obs in dBObs] BNorth = p.array([obs['North']['data'] for obs in mfObs]).T BEast = p.array([obs['East']['data'] for obs in mfObs]).T BDown = p.array([obs['Down']['data'] for obs in mfObs]).T dBHorizIon = p.sqrt((dBNorthIon + BNorth)**2 + (dBEastIon + BEast)**2) # add main field dBHorizIon = dBHorizIon - p.sqrt(BNorth**2 + BEast**2) # remove horiz baseline dBHorizFAC = p.sqrt((dBNorthFAC + BNorth)**2 + (dBEastFAC + BEast)**2) # add main field dBHorizFAC = dBHorizFAC - p.sqrt(BNorth**2 + BEast**2) # remove horiz baseline dBHorizMag = p.sqrt((dBNorthMag + BNorth)**2 + (dBEastMag + BEast)**2) # add main field dBHorizMag = dBHorizMag - p.sqrt(BNorth**2 + BEast**2) # remove horiz baseline dBHorizTot = p.sqrt((dBNorthTot + BNorth)**2 + (dBEastTot + BEast)**2) # add main field dBHorizTot = dBHorizTot - p.sqrt(BNorth**2 + BEast**2) # remove horiz baseline # indices to max/min disturbance are all based on the total current system; # this allows the constituents to sum up to give the total DstMaxIdx = dBHorizTot.argmax(axis=1) DstMinIdx = dBHorizTot.argmin(axis=1) # I do not understand how slices and index arrays are combined, so just create # an index array for all time steps (rows) allT = list(range(dBNorthTot.shape[0])) # indices from total current system symDstTot = dBHorizTot.mean(axis=1) DstMaxTot = dBHorizTot[allT,DstMaxIdx] DstMinTot = dBHorizTot[allT,DstMinIdx] asyDstTot = DstMaxTot - DstMinTot # indices from ionospheric current system symDstIon = dBHorizIon.mean(axis=1) DstMaxIon = dBHorizIon[allT,DstMaxIdx] DstMinIon = dBHorizIon[allT,DstMinIdx] asyDstIon = DstMaxIon - DstMinIon # indices from field-aligned current system symDstFAC = dBHorizFAC.mean(axis=1) DstMaxFAC = dBHorizFAC[allT,DstMaxIdx] DstMinFAC = dBHorizFAC[allT,DstMinIdx] asyDstFAC = DstMaxFAC - DstMinFAC # indices from magnetospheric current system symDstMag = dBHorizMag.mean(axis=1) DstMaxMag = dBHorizMag[allT,DstMaxIdx] DstMinMag = dBHorizMag[allT,DstMinIdx] asyDstMag = DstMaxMag - DstMinMag # create time series object to hold sum total of constituents dBTot = pyLTR.TimeSeries() dBTot.append('datetime', 'Date & Time', '', dBObs[0]['dBTot']['datetime']['data']) dBTot.append('doy', 'Day of Year', 'days', dBObs[0]['dBTot']['doy']['data']) dBTot.append('SYMH', r'$\Delta B_{average}$', 'nT', symHTot.tolist()) dBTot.append('ASYH', r'$\Delta B_{envelope}$', 'nT', asyHTot.tolist()) dBTot.append('MaxH', r'$\Delta B_{upper}$', 'nT', HMaxTot.tolist()) dBTot.append('MinH', r'$\Delta B_{lower}$', 'nT', HMinTot.tolist()) dBTot.append('dBH', r'$\Delta B$', 'nT', (dBNorthTot / p.cos(p.pi/2 - thetas)).tolist()) dBTot.append('SYMD', r'$\Delta B_{average}$', 'nT', symDTot.tolist()) dBTot.append('ASYD', r'$\Delta B_{envelope}$', 'nT', asyDTot.tolist()) dBTot.append('MaxD', r'$\Delta B_{upper}$', 'nT', DMaxTot.tolist()) dBTot.append('MinD', r'$\Delta B_{lower}$', 'nT', DMinTot.tolist()) dBTot.append('dBD', r'$\Delta B$', 'nT', dBEastTot.tolist()) dBTot.append('SYMDst', r'$\Delta B_{average}$', 'nT', symDstTot.tolist()) dBTot.append('ASYDst', r'$\Delta B_{envelope}$', 'nT', asyDstTot.tolist()) dBTot.append('MaxDst', r'$\Delta B_{upper}$', 'nT', DstMaxTot.tolist()) dBTot.append('MinDst', r'$\Delta B_{lower}$', 'nT', DstMinTot.tolist()) #dBTot.append('dBDst', r'$\Delta B$', 'nT', p.sqrt(dBNorthTot**2+dBEastTot**2) / p.cos(p.pi/2 - thetas).tolist()) dBTot.append('dBDst', r'$\Delta B$', 'nT', dBHorizTot.tolist()) # create time series object to hold ionospheric current constituent dBIon = pyLTR.TimeSeries() dBIon.append('datetime', 'Date & Time', '', dBObs[0]['dBIon']['datetime']['data']) dBIon.append('doy', 'Day of Year', 'days', dBObs[0]['dBIon']['doy']['data']) dBIon.append('SYMH', r'$\Delta B_{average}$', 'nT', symHIon.tolist()) dBIon.append('ASYH', r'$\Delta B_{envelope}$', 'nT', asyHIon.tolist()) dBIon.append('MaxH', r'$\Delta B_{upper}$', 'nT', HMaxIon.tolist()) dBIon.append('MinH', r'$\Delta B_{lower}$', 'nT', HMinIon.tolist()) dBIon.append('dBH', r'$\Delta B$', 'nT', (dBNorthIon / p.cos(p.pi/2 - thetas)).tolist()) dBIon.append('SYMD', r'$\Delta B_{average}$', 'nT', symDIon.tolist()) dBIon.append('ASYD', r'$\Delta B_{envelope}$', 'nT', asyDIon.tolist()) dBIon.append('MaxD', r'$\Delta B_{upper}$', 'nT', DMaxIon.tolist()) dBIon.append('MinD', r'$\Delta B_{lower}$', 'nT', DMinIon.tolist()) dBIon.append('dBD', r'$\Delta B$', 'nT', dBEastIon.tolist()) dBIon.append('SYMDst', r'$\Delta B_{average}$', 'nT', symDstIon.tolist()) dBIon.append('ASYDst', r'$\Delta B_{envelope}$', 'nT', asyDstIon.tolist()) dBIon.append('MaxDst', r'$\Delta B_{upper}$', 'nT', DstMaxIon.tolist()) dBIon.append('MinDst', r'$\Delta B_{lower}$', 'nT', DstMinIon.tolist()) #dBIon.append('dBDst', r'$\Delta B$', 'nT', p.sqrt(dBNorthIon**2+dBEastIon**2) / p.cos(p.pi/2 - thetas).tolist()) dBIon.append('dBDst', r'$\Delta B$', 'nT', dBHorizIon.tolist()) # create time series object to hold field-aligned current constituent dBFAC = pyLTR.TimeSeries() dBFAC.append('datetime', 'Date & Time', '', dBObs[0]['dBFAC']['datetime']['data']) dBFAC.append('doy', 'Day of Year', 'days', dBObs[0]['dBFAC']['doy']['data']) dBFAC.append('SYMH', r'$\Delta B_{average}$', 'nT', symHFAC.tolist()) dBFAC.append('ASYH', r'$\Delta B_{envelope}$', 'nT', asyHFAC.tolist()) dBFAC.append('MaxH', r'$\Delta B_{upper}$', 'nT', HMaxFAC.tolist()) dBFAC.append('MinH', r'$\Delta B_{lower}$', 'nT', HMinFAC.tolist()) dBFAC.append('dBH', r'$\Delta B$', 'nT', (dBNorthFAC / p.cos(p.pi/2 - thetas)).tolist()) dBFAC.append('SYMD', r'$\Delta B_{average}$', 'nT', symDFAC.tolist()) dBFAC.append('ASYD', r'$\Delta B_{envelope}$', 'nT', asyDFAC.tolist()) dBFAC.append('MaxD', r'$\Delta B_{upper}$', 'nT', DMaxFAC.tolist()) dBFAC.append('MinD', r'$\Delta B_{lower}$', 'nT', DMinFAC.tolist()) dBFAC.append('dBD', r'$\Delta B$', 'nT', dBEastFAC.tolist()) dBFAC.append('SYMDst', r'$\Delta B_{average}$', 'nT', symDstFAC.tolist()) dBFAC.append('ASYDst', r'$\Delta B_{envelope}$', 'nT', asyDstFAC.tolist()) dBFAC.append('MaxDst', r'$\Delta B_{upper}$', 'nT', DstMaxFAC.tolist()) dBFAC.append('MinDst', r'$\Delta B_{lower}$', 'nT', DstMinFAC.tolist()) #dBFAC.append('dBDst', r'$\Delta B$', 'nT', p.sqrt(dBNorthFAC**2+dBEastFAC**2) / p.cos(p.pi/2 - thetas).tolist()) dBFAC.append('dBDst', r'$\Delta B$', 'nT', dBHorizFAC.tolist()) # create time series object to hold magnetospheric constituent dBMag = pyLTR.TimeSeries() dBMag.append('datetime', 'Date & Time', '', dBObs[0]['dBMag']['datetime']['data']) dBMag.append('doy', 'Day of Year', 'days', dBObs[0]['dBMag']['doy']['data']) dBMag.append('SYMH', r'$\Delta B_{average}$', 'nT', symHMag.tolist()) dBMag.append('ASYH', r'$\Delta B_{envelope}$', 'nT', asyHMag.tolist()) dBMag.append('MaxH', r'$\Delta B_{upper}$', 'nT', HMaxMag.tolist()) dBMag.append('MinH', r'$\Delta B_{lower}$', 'nT', HMinMag.tolist()) dBMag.append('dBH', r'$\Delta B$', 'nT', (dBNorthMag / p.cos(p.pi/2 - thetas)).tolist()) dBMag.append('SYMD', r'$\Delta B_{average}$', 'nT', symDMag.tolist()) dBMag.append('ASYD', r'$\Delta B_{envelope}$', 'nT', asyDMag.tolist()) dBMag.append('MaxD', r'$\Delta B_{upper}$', 'nT', DMaxMag.tolist()) dBMag.append('MinD', r'$\Delta B_{lower}$', 'nT', DMinMag.tolist()) dBMag.append('dBD', r'$\Delta B$', 'nT', dBEastMag.tolist()) dBMag.append('SYMDst', r'$\Delta B_{average}$', 'nT', symDstMag.tolist()) dBMag.append('ASYDst', r'$\Delta B_{envelope}$', 'nT', asyDstMag.tolist()) dBMag.append('MaxDst', r'$\Delta B_{upper}$', 'nT', DstMaxMag.tolist()) dBMag.append('MinDst', r'$\Delta B_{lower}$', 'nT', DstMinMag.tolist()) #dBMag.append('dBDst', r'$\Delta B$', 'nT', p.sqrt(dBNorthMag**2+dBEastMag**2) / p.cos(p.pi/2 - thetas).tolist()) dBMag.append('dBDst', r'$\Delta B$', 'nT', dBHorizMag.tolist()) SymAsyDst = {'dBTot':dBTot, 'dBIon':dBIon, 'dBFAC':dBFAC, 'dBMag':dBMag} return (SymAsyDst)
def calculateIndex(path='./', run='', t0='', t1='', obsList=None, geoGrid=False, ignoreBinary=False, binaryType='pkl', outDirName='figs'): """ Compute deltaBs at virtual observatories, then generate an AE-like index, given LFM-MIX output files in path. Computes: AEdB - a dict of pyLTR.TimeSeries objects, corresponding to the total, ionospheric current, field-aligned current, and magnetospheric current constituent of the AE, AU, AL, and the delta B_h's used to derived these indices. NOTE: while the outputs are pyLTR.TimeSeries objects, the function generates binary pkl/mat files that combine each specified observatory for each time step; this helps reduce re-computation time for subsequent calls to this function, and provides snapshots of output to be read in by alternative analysis software Requires: Nothing, all inputs are optional Optional: path - path to data directory holding LFM and MIX model output files (default is current directory) run - output filename prefix identifying LFM-MIX run (i.e., the part of the filename prior to [mhd|mix]_yyyy-mm-ddTHH-MM-SSZ.hdf) (default is any mhd|mix files in path) t0 - datetime object specifying the earliest of available time step to include in the extraction (default is earliest available) t1 - datetime object specfiying the latest of available time step to include in the extraction (default is last available) obsList - a list of lists of observatory coordinates [phi,theta,rho,ID] where ID is an optional 4th element to each coordinate set that, ideally, uniquely identifies the observatory...if ID is not specified, it is assigned an empty string. (default is coordinate system origin) geoGrid - if True, assume observatory coordinates are in geographic coordinates rather than solar magnetic; same for outputs (default is False) ignoreBinary - if True, ignore any pre-computed binary files and re- compute everything from scratch; NOTE: individual binary files will be ignored anyway if they are incompatible with specified inputs, but this option avoids reading the binary file entirely. (default is False) binaryType - binary type to generate, NOT to read in...routine looks for PKL files first, then mat files, then proceeds to re-compute if neither are available. (default is 'pkl') outDirName - name of directory into which all output will be placed; must be a relative path, to be appended to the input path; this is also where binary pkl/mat files will be expected if/when the function tries to read pre-computed data. (default is 'figs') """ # define and geo-locate virtual observatories if obsList == None or len(obsList) == 0: obsList = _defaultObs() # force geoGrid=True geoGrid = True #print(('obsList: ',obsList)) # get delta B time series for AE stations dBExtract = pyLTR.Tools.deltaBTimeSeries.extractQuantities dBObs = dBExtract(path=path, run=run, t0=t0, t1=t1, obsList=obsList, geoGrid=geoGrid, ignoreBinary=ignoreBinary, binaryType=binaryType, outDirName=outDirName) # convert lists of constituent vector components into NumPy arrays dBNorthIon = p.array([obs['dBIon']['North']['data'] for obs in dBObs]).T dBNorthFAC = p.array([obs['dBFAC']['North']['data'] for obs in dBObs]).T dBNorthMag = p.array([obs['dBMag']['North']['data'] for obs in dBObs]).T dBNorthTot = p.array([obs['dBTot']['North']['data'] for obs in dBObs]).T dBEastIon = p.array([obs['dBIon']['East']['data'] for obs in dBObs]).T dBEastFAC = p.array([obs['dBFAC']['East']['data'] for obs in dBObs]).T dBEastMag = p.array([obs['dBMag']['East']['data'] for obs in dBObs]).T dBEastTot = p.array([obs['dBTot']['East']['data'] for obs in dBObs]).T dBDownIon = p.array([obs['dBIon']['Down']['data'] for obs in dBObs]).T dBDownFAC = p.array([obs['dBFAC']['Down']['data'] for obs in dBObs]).T dBDownMag = p.array([obs['dBMag']['Down']['data'] for obs in dBObs]).T dBDownTot = p.array([obs['dBTot']['Down']['data'] for obs in dBObs]).T # calculate main field to add to deltaB before calculating horizontal field, # then subtract quadratic sum of main field components, assuming this is the # equivalent to removing a quiet baseline...I know this seems like a strange # thing to do, but real-world indices have positive and negative values, # which would be impossible if vector-component baselines were removed # *before* adding up the disturbance vectors; so, we add plausible vector # component baselines to our disturbance vectors to emulate how real-world # observations are collected, determine the horizontal field, then remove # the horizontal baseline. dipoleMF = pyLTR.Tools.deltaBTimeSeries._dipoleMF mfObs = [dipoleMF(obs['dBTot'], geoGrid) for obs in dBObs] BNorth = p.array([obs['North']['data'] for obs in mfObs]).T BEast = p.array([obs['East']['data'] for obs in mfObs]).T BDown = p.array([obs['Down']['data'] for obs in mfObs]).T dBHorizIon = p.sqrt( (dBNorthIon + BNorth)**2 + (dBEastIon + BEast)**2) # add main field dBHorizIon = dBHorizIon - p.sqrt( BNorth**2 + BEast**2) # remove horiz baseline dBHorizFAC = p.sqrt( (dBNorthFAC + BNorth)**2 + (dBEastFAC + BEast)**2) # add main field dBHorizFAC = dBHorizFAC - p.sqrt( BNorth**2 + BEast**2) # remove horiz baseline dBHorizMag = p.sqrt( (dBNorthMag + BNorth)**2 + (dBEastMag + BEast)**2) # add main field dBHorizMag = dBHorizMag - p.sqrt( BNorth**2 + BEast**2) # remove horiz baseline dBHorizTot = p.sqrt( (dBNorthTot + BNorth)**2 + (dBEastTot + BEast)**2) # add main field dBHorizTot = dBHorizTot - p.sqrt( BNorth**2 + BEast**2) # remove horiz baseline # compute simulated AU and AL based on the total field, then apply this to # mag, ion, and fac constituents to get constituent AEs that sum to the total. # NOTE: this is NOT the same as calculating envelopes for each constituent AUidx = dBHorizTot.argmax(axis=1) ALidx = dBHorizTot.argmin(axis=1) # I do not understand how slices and index arrays are combined, so just create # an index array for all time steps (rows) allT = list(range(dBHorizTot.shape[0])) AUTot = dBHorizTot[allT, AUidx] ALTot = dBHorizTot[allT, ALidx] AETot = AUTot - ALTot AUIon = dBHorizIon[allT, AUidx] ALIon = dBHorizIon[allT, ALidx] AEIon = AUIon - ALIon AUFAC = dBHorizFAC[allT, AUidx] ALFAC = dBHorizFAC[allT, ALidx] AEFAC = AUFAC - ALFAC AUMag = dBHorizMag[allT, AUidx] ALMag = dBHorizMag[allT, ALidx] AEMag = AUMag - ALMag # create time series object to hold sum total of constituents dBTot = pyLTR.TimeSeries() dBTot.append('datetime', 'Date & Time', '', dBObs[0]['dBTot']['datetime']['data']) dBTot.append('doy', 'Day of Year', 'days', dBObs[0]['dBTot']['doy']['data']) dBTot.append('AE', r'$\Delta B_{envelope}$', 'nT', AETot.tolist()) dBTot.append('AU', r'$\Delta B_{upper}$', 'nT', AUTot.tolist()) dBTot.append('AL', r'$\Delta B_{lower}$', 'nT', ALTot.tolist()) #dBTot.append('dBh', r'$\Delta B$', 'nT', dBHorizTot.tolist()) dBTot.append('dBh', [r'$\Delta B_{%s}' % o[3] for o in obsList], 'nT', dBHorizTot.tolist()) # create time series object to hold ionospheric current constituent dBIon = pyLTR.TimeSeries() dBIon.append('datetime', 'Date & Time', '', dBObs[0]['dBIon']['datetime']['data']) dBIon.append('doy', 'Day of Year', 'days', dBObs[0]['dBIon']['doy']['data']) dBIon.append('AE', r'$\Delta B_{envelope}$', 'nT', AEIon.tolist()) dBIon.append('AU', r'$\Delta B_{upper}$', 'nT', AUIon.tolist()) dBIon.append('AL', r'$\Delta B_{lower}$', 'nT', ALIon.tolist()) #dBIon.append('dBh', r'$\Delta B$', 'nT', dBHorizIon.tolist()) dBIon.append('dBh', [r'$\Delta B_{%s}$' % o[3] for o in obsList], 'nT', dBHorizIon.tolist()) # create time series object to hold field aligned current constituent dBFAC = pyLTR.TimeSeries() dBFAC.append('datetime', 'Date & Time', '', dBObs[0]['dBFAC']['datetime']['data']) dBFAC.append('doy', 'Day of Year', 'days', dBObs[0]['dBFAC']['doy']['data']) dBFAC.append('AE', r'$\Delta B_{envelope}$', 'nT', AEFAC.tolist()) dBFAC.append('AU', r'$\Delta B_{upper}$', 'nT', AUFAC.tolist()) dBFAC.append('AL', r'$\Delta B_{lower}$', 'nT', ALFAC.tolist()) #dBFAC.append('dBh', r'$\Delta B$', 'nT', dBHorizFAC.tolist()) dBFAC.append('dBh', [r'$\Delta B_{%s}$' % o[3] for o in obsList], 'nT', dBHorizFAC.tolist()) # create time series object to hold magnetospheric current constituent dBMag = pyLTR.TimeSeries() dBMag.append('datetime', 'Date & Time', '', dBObs[0]['dBMag']['datetime']['data']) dBMag.append('doy', 'Day of Year', 'days', dBObs[0]['dBMag']['doy']['data']) dBMag.append('AE', r'$\Delta B_{envelope}$', 'nT', AEMag.tolist()) dBMag.append('AU', r'$\Delta B_{upper}$', 'nT', AUMag.tolist()) dBMag.append('AL', r'$\Delta B_{lower}$', 'nT', ALMag.tolist()) #dBMag.append('dBh', r'$\Delta B$', 'nT', dBHorizMag.tolist()) dBMag.append('dBh', [r'$\Delta B_{%s}$' % o[3] for o in obsList], 'nT', dBHorizMag.tolist()) # output is a dictionary of time series objects AEdB = {'dBTot': dBTot, 'dBIon': dBIon, 'dBFAC': dBFAC, 'dBMag': dBMag} return (AEdB)
def extractQuantities(path, run, t0, t1): """ Extract MIX quantities from the input path. Execute `mixTimeSeries.py --help` for details on the function parameters (path,run,t0,t1). Outputs a pyLTR.TimeSeries object containing the data. """ data = pyLTR.Models.MIX(path, run) # hard-coded input for testing & debugging: #data = pyLTR.Models.LFM('/hao/aim2/schmitt/data/LTR-2_0_1b/r1432/March1995/LR/single', 'LRs') #Make sure variables are defined in the model. modelVars = data.getVarNames() for v in [ 'Grid X', 'Grid Y', 'Potential North [V]', 'Potential South [V]', 'FAC North [A/m^2]', 'FAC South [A/m^2]', 'Pedersen conductance North [S]', 'Pedersen conductance South [S]', 'Hall conductance North [S]', 'Hall conductance South [S]', 'Average energy North [keV]', 'Average energy South [keV]', 'Number flux North [1/cm^2 s]', 'Number flux South [1/cm^2 s]' ]: assert (v in modelVars) timeRange = data.getTimeRange() if len(timeRange) == 0: raise Exception(( 'No data files found. Are you pointing to the correct run directory?' )) index0 = 0 if t0: for i, t in enumerate(timeRange): if t0 >= t: index0 = i index1 = len(timeRange) - 1 if t1: for i, t in enumerate(timeRange): if t1 >= t: index1 = i print(('Extracting MIX quantities for time series over %d time steps.' % (index1 - index0))) # Output a status bar displaying how far along the computation is. progress = pyLTR.StatusBar(0, index1 - index0) progress.start() t_doy = [] mhpNorth = [] mhpSouth = [] bhpNorth = [] bhpSouth = [] chpNorth = [] chpSouth = [] # Pre-compute area of the grid. x = data.read('Grid X', timeRange[index0]) y = data.read('Grid Y', timeRange[index0]) # Fix singularity at the pole x[:, 0] = 0.0 y[:, 0] = 0.0 z = numpy.sqrt(1.0 - x**2 - y**2) ri = 6500.0e3 # Radius of ionosphere areaMixGrid = pyLTR.math.integrate.calcFaceAreas(x, y, z) * ri * ri doBBEaverage = 1 doCUSPaverage = 1 averagesize = 5 for i, time in enumerate(timeRange[index0:index1]): try: # -- Day of Year tt = time.timetuple() t_doy.append(tt.tm_yday + tt.tm_hour / 24.0 + tt.tm_min / 1440.0 + tt.tm_sec / 86400.0) # --- MonoDiffuse Hemispheric Power energy = data.read('Average energy North [keV]', time) flux = data.read('Number flux North [1/cm^2 s]', time) hp = areaMixGrid * energy[:-1, :-1] * flux[:-1, :-1] # KeV/cm^2s to mW/m^2 to GW mhpNorth.append(hp.sum() * 1.6e-21) energy = data.read('Average energy South [keV]', time) flux = data.read('Number flux South [1/cm^2 s]', time) hp = areaMixGrid * energy[:-1, :-1] * flux[:-1, :-1] # KeV/cm^2s to mW/m^2 to GW mhpSouth.append(hp.sum() * 1.6e-21) # --- BBE Hemispheric Power flux = data.read('BBE number flux North [1/cm^2 s]', time) energy = data.read('BBE average energy North [keV]', time) hp = areaMixGrid * energy[:-1, :-1] * flux[:-1, :-1] # KeV/cm^2s to mW/m^2 to GW if doBBEaverage and i > averagesize: bhpNorth.append( (sum(bhpNorth[-averagesize:-1]) + hp.sum() * 1.6e-21) / averagesize) else: bhpNorth.append(hp.sum() * 1.6e-21) flux = data.read('BBE number flux South [1/cm^2 s]', time) energy = data.read('BBE average energy South [keV]', time) hp = areaMixGrid * energy[:-1, :-1] * flux[:-1, :-1] # KeV/cm^2s to mW/m^2 to GW if doBBEaverage and i > averagesize: bhpSouth.append( (sum(bhpSouth[-averagesize:-1]) + hp.sum() * 1.6e-21) / averagesize) else: bhpSouth.append(hp.sum() * 1.6e-21) # --- Cusp Hemispheric Power flux = data.read('Cusp number flux North [1/cm^2 s]', time) energy = data.read('Cusp average energy North [keV]', time) hp = areaMixGrid * energy[:-1, :-1] * flux[:-1, :-1] # KeV/cm^2s to mW/m^2 to GW if doCUSPaverage and i > averagesize: chpNorth.append( (sum(chpNorth[-averagesize:-1]) + hp.sum() * 1.6e-21) / averagesize) else: chpNorth.append(hp.sum() * 1.6e-21) flux = data.read('Cusp number flux South [1/cm^2 s]', time) energy = data.read('Cusp average energy South [keV]', time) hp = areaMixGrid * energy[:-1, :-1] * flux[:-1, :-1] # KeV/cm^2s to mW/m^2 to GW if doCUSPaverage and i > averagesize: chpSouth.append( (sum(chpSouth[-averagesize:-1]) + hp.sum() * 1.6e-21) / averagesize) else: chpSouth.append(hp.sum() * 1.6e-21) progress.increment() except KeyboardInterrupt: # Exit when the user hits CTRL+C. progress.stop() progress.join() print('Exiting.') import sys sys.exit(0) except: # Cleanup progress bar if something bad happened. progress.stop() progress.join() raise progress.stop() progress.join() dataNorth = pyLTR.TimeSeries() dataSouth = pyLTR.TimeSeries() dataNorth.append('datetime', 'Date & Time', '', timeRange[index0:index1]) dataSouth.append('datetime', 'Date & Time', '', timeRange[index0:index1]) dataNorth.append('doy', 'Day of Year', '', t_doy) dataSouth.append('doy', 'Day of Year', '', t_doy) # "N" and "S" label subscripts are redundant here, potentially leading to # mis-labeling of plots #dataNorth.append('cpcp', r'$\Phi_N$', 'kV', cpcpNorth) #dataSouth.append('cpcp', r'$\Phi_S$', 'kV', cpcpSouth) # #dataNorth.append('hp', r'$HP_N$', 'GW', hpNorth) #dataSouth.append('hp', r'$HP_S$', 'GW', hpSouth) # #dataNorth.append('ipfac', r'$FAC_N$', 'MA', ipfacNorth) #dataSouth.append('ipfac', r'$FAC_S$', 'MA', ipfacSouth) dataNorth.append('diffusemono', r'$DiffuseMono$', 'GW', mhpNorth) dataSouth.append('diffusemono', r'$DiffuseMono$', 'GW', mhpSouth) dataNorth.append('bbe', r'$BBE$', 'GW', bhpNorth) dataSouth.append('bbe', r'$BBE$', 'GW', bhpSouth) dataNorth.append('cusp', r'$Cusp$', 'GW', chpNorth) dataSouth.append('cusp', r'$Cusp$', 'GW', chpSouth) return (dataNorth, dataSouth)
def extractQuantities(path, run, runExt, t0, t1): """ Extract LFM ION quantities from the input path. Execute `lfmionTimeSeries.py --help` for details on the function parameters (path,run,t0,t1). Outputs a pyLTR.TimeSeries object containing the data. """ data = pyLTR.Models.LFMION(path, run, ext=runExt) # hard-coded input for testing & debugging: #data = pyLTR.Models.LFM('/hao/aim2/schmitt/data/LTR-2_0_1b/r1432/March1995/LR/single', 'LRs') #Make sure variables are defined in the model. modelVars = data.getVarNames() for v in [ 'x_interp', 'y_interp', 'potnorth', 'potsouth', 'curnorth', 'cursouth', 'SigmaP_north', 'SigmaP_south', 'SigmaH_north', 'SigmaH_south', 'avE_north', 'avE_south', 'fluxnorth', 'fluxsouth' ]: assert (v in modelVars) timeRange = data.getTimeRange() if len(timeRange) == 0: raise Exception(( 'No data files found. Are you pointing to the correct run directory?' )) index0 = 0 if t0: for i, t in enumerate(timeRange): if t0 >= t: index0 = i index1 = len(timeRange) - 1 if t1: for i, t in enumerate(timeRange): if t1 >= t: index1 = i print( ('Extracting LFM ION quantities for time series over %d time steps.' % (index1 - index0))) # Output a status bar displaying how far along the computation is. progress = pyLTR.StatusBar(0, index1 - index0) progress.start() t_doy = [] cpcpNorth = [] cpcpSouth = [] hpNorth = [] hpSouth = [] ipfacNorth = [] ipfacSouth = [] # Pre-compute area of the grid. x = data.read('x_interp', timeRange[index0]) y = data.read('y_interp', timeRange[index0]) # Fix singularity at the pole x[:, 0] = 0.0 y[:, 0] = 0.0 z = numpy.sqrt(1.0 - x**2 - y**2) ri = 6370.0e3 # Radius of ionosphere areaMixGrid = pyLTR.math.integrate.calcFaceAreas(x, y, z) * ri * ri for i, time in enumerate(timeRange[index0:index1]): try: # -- Day of Year tt = time.timetuple() t_doy.append(tt.tm_yday + tt.tm_hour / 24.0 + tt.tm_min / 1440.0 + tt.tm_sec / 86400.0) # --- Cross Polar Cap Potential psiNorth = data.read('potnorth', time) / 1000.0 cpcpNorth.append(psiNorth.max() - psiNorth.min()) psiSouth = data.read('potsouth', time) / 1000.0 cpcpSouth.append(psiSouth.max() - psiSouth.min()) # --- Hemispheric Power energy = data.read('avE_north', time) flux = data.read('fluxnorth', time) hp = areaMixGrid * energy[:-1, :-1] * flux[:-1, :-1] # KeV/cm^2s to mW/m^2 to GW hpNorth.append(hp.sum() * 1.6e-21) energy = data.read('avE_south', time) flux = data.read('fluxsouth', time) hp = areaMixGrid * energy[:-1, :-1] * flux[:-1, :-1] # KeV/cm^2s to mW/m^2 to GW hpSouth.append(hp.sum() * 1.6e-21) # --- Positive current density fac = data.read('curnorth', time) fac[fac <= 0] = 0.0 pfac = areaMixGrid * fac[:-1, :-1] ipfacNorth.append(pfac.sum() / 1.0e6) fac = data.read('cursouth', time) fac[fac <= 0] = 0.0 pfac = areaMixGrid * fac[:-1, :-1] ipfacSouth.append(pfac.sum() / 1.0e6) progress.increment() except KeyboardInterrupt: # Exit when the user hits CTRL+C. progress.stop() progress.join() print('Exiting.') import sys sys.exit(0) except: # Cleanup progress bar if something bad happened. progress.stop() progress.join() raise progress.stop() progress.join() dataNorth = pyLTR.TimeSeries() dataSouth = pyLTR.TimeSeries() dataNorth.append('datetime', 'Date & Time', '', timeRange[index0:index1]) dataSouth.append('datetime', 'Date & Time', '', timeRange[index0:index1]) dataNorth.append('doy', 'Day of Year', '', t_doy) dataSouth.append('doy', 'Day of Year', '', t_doy) dataNorth.append('cpcp', r'$\Phi_N$', 'kV', cpcpNorth) dataSouth.append('cpcp', r'$\Phi_S$', 'kV', cpcpSouth) dataNorth.append('hp', r'$HP_N$', 'GW', hpNorth) dataSouth.append('hp', r'$HP_S$', 'GW', hpSouth) dataNorth.append('ipfac', r'$FAC_N$', 'MA', ipfacNorth) dataSouth.append('ipfac', r'$FAC_S$', 'MA', ipfacSouth) return (dataNorth, dataSouth)
# Custom imports import pyLTR if __name__ == '__main__': # Generate some arrays x = numpy.deg2rad(numpy.arange(0, 360, 1, float)) y = numpy.sin(x) y1 = numpy.cos(x) y2 = y + y1 z = 2.0 * y z1 = 2.0 * y1 z2 = 2.0 * y2 # Store arrays as pyLTR.TimeSeries objects Dict = pyLTR.TimeSeries() Dict.append('Xval', 'Time', 's', x) Dict.append('Yval', 'Amp', 'm', y) Dict.append('Y1val', 'Amp 1', 'ft', y1) Dict.append('Y2val', 'Amp 2', 'cm', y2) Dict['MetaData'] = "This is the metadata" Dict2 = pyLTR.TimeSeries() Dict2.append('Xval', 'Time', 's', x) Dict2.append('Yval', 'Amp', 'm', z) Dict2.append('Y1val', 'Amp 1', 'ft', z1) Dict2.append('Y2val', 'Amp 2', 'cm', z2) Dict2['MetaData'] = "This is the metadata" # Make simple Time Series plots via pyLTR.Graphics.TimeSeries module: pylab.figure(1)