def CreateFrames(path, runName, runExt, t0, t1, plane, configFile): assert ((plane == 'xzplane') | (plane == 'xyplane')) planeSelect = {'xzplane': 'xzplane', 'xyplane': 'xyplane'}[plane] # Make sure the output directory exisits if not make it dirname = os.path.join(path, 'figs', plane) if not os.path.exists(dirname): os.makedirs(dirname) print(('Rendering ' + planeSelect + 'plane, storing frames at ' + dirname)) #Now check to make sure the files are correct data = pyLTR.Models.LFM(path, runName, ext=runExt) modelVars = data.getVarNames() 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 MAG 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() # Deal with the plot options if (configFile == None): vxOpts = {'min': -800., 'max': 800., 'colormap': 'RdBu_r'} vyOpts = {'min': -100., 'max': 100., 'colormap': 'RdBu_r'} vzOpts = {'min': -100., 'max': 100., 'colormap': 'RdBu_r'} bxOpts = {'min': -10., 'max': 10.} byOpts = {'min': -10., 'max': 10.} bzOpts = {'min': -10., 'max': 10.} rhoOpts = {'min': 0, 'max': 50} optsObject = { 'vx': vxOpts, 'vy': vyOpts, 'vz': vzOpts, 'bx': bxOpts, 'by': byOpts, 'bz': bzOpts, 'rho': rhoOpts } configFilename = os.path.join(dirname, 'MHDPlanes.config') print(("Writing plot config file at " + configFilename)) f = open(configFilename, 'w') f.write(pyLTR.yaml.safe_dump(optsObject, default_flow_style=False)) f.close() else: f = open(configFile, 'r') optsDict = pyLTR.yaml.safe_load(f.read()) f.close() if ('vx' in optsDict): vxOpts = optsDict['vx'] else: vxOpts = {'min': -800., 'max': 800., 'colormap': 'RdBu_r'} if ('vy' in optsDict): vyOpts = optsDict['vy'] else: vyOpts = {'min': -100., 'max': 100., 'colormap': 'RdBu_r'} if ('vz' in optsDict): vzOpts = optsDict['vz'] else: vzOpts = {'min': -100., 'max': 100., 'colormap': 'RdBu_r'} if ('bx' in optsDict): bxOpts = optsDict['bx'] else: bxOpts = {'min': -10., 'max': 10.} if ('by' in optsDict): byOpts = optsDict['by'] else: byOpts = {'min': -10., 'max': 10.} if ('bz' in optsDict): bzOpts = optsDict['bz'] else: bzOpts = {'min': -10., 'max': 10.} if ('rho' in optsDict): bzOpts = optsDict['rho'] else: rhoOpts = {'min': 0., 'max': 50.} vals = data.getEqSlice('X_grid', timeRange[0]) / 6.38e8 xeq = {'data': vals, 'name': r'$X$', 'units': r'$R_E$'} vals = data.getEqSlice('Y_grid', timeRange[0]) / 6.38e8 yeq = {'data': vals, 'name': r'$X$', 'units': r'$R_E$'} vals = data.getEqSlice('Z_grid', timeRange[0]) / 6.38e8 zeq = {'data': vals, 'name': r'$X$', 'units': r'$R_E$'} vals = data.getMerSlice('X_grid', timeRange[0]) / 6.38e8 xmer = {'data': vals, 'name': r'$X$', 'units': r'$R_E$'} vals = data.getMerSlice('Y_grid', timeRange[0]) / 6.38e8 ymer = {'data': vals, 'name': r'$X$', 'units': r'$R_E$'} vals = data.getMerSlice('Z_grid', timeRange[0]) / 6.38e8 zmer = {'data': vals, 'name': r'$X$', 'units': r'$R_E$'} for i, time in enumerate(timeRange[index0:index1]): try: #first read the data vals = data.getEqSlice('vx_', time) / 1000.0 vx = {'data': vals, 'name': r'$V_X$', 'units': r'km/s'} vals = data.getEqSlice('vy_', time) / 1000.0 vy = {'data': vals, 'name': r'$V_Y$', 'units': r'km/s'} vals = data.getEqSlice('vz_', time) / 1000.0 vz = {'data': vals, 'name': r'$V_Z$', 'units': r'km/s'} vals = data.getEqSlice('bx_', time) bx = {'data': vals, 'name': r'$B_X$', 'units': r'nT'} vals = data.getEqSlice('by_', time) by = {'data': vals, 'name': r'$B_Y$', 'units': r'nT'} vals = -1.0 * data.getEqSlice('bz_', time) bz = {'data': vals, 'name': r'$B_Z$', 'units': r'S'} # Now onto the plot tt = time.timetuple() p.figure(figsize=(16, 12)) p.figtext(0.5, 0.92, 'LFM ' + '\n%4d-%02d-%02d %02d:%02d:%02d' % (tt.tm_year, tt.tm_mon, tt.tm_mday, tt.tm_hour, tt.tm_min, tt.tm_sec), fontsize=14, multialignment='center') ax = p.subplot(231) x = xeq['data'] y = yeq['data'] pyLTR.Graphics.CutPlane.CutPlaneDict(x, y, vx, vxOpts, userAxes=ax) ax = p.subplot(234) pyLTR.Graphics.CutPlane.CutPlaneDict(x, y, vy, vyOpts, userAxes=ax) ax = p.subplot(232) pyLTR.Graphics.CutPlane.CutPlaneDict(x, y, vz, vzOpts, userAxes=ax) ax = p.subplot(235) pyLTR.Graphics.CutPlane.CutPlaneDict(x, y, bx, bxOpts, userAxes=ax) ax = p.subplot(233) pyLTR.Graphics.CutPlane.CutPlaneDict(x, y, by, byOpts, userAxes=ax) ax = p.subplot(236) pyLTR.Graphics.CutPlane.CutPlaneDict(x, y, bz, bzOpts, userAxes=ax) savefigName = os.path.join(path, 'figs', plane, 'frame_%05d.png' % i) p.savefig(savefigName, dpi=100) p.close() 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() return os.path.join(path, 'figs', plane)
def CreateFrames(path, runName, t0, t1, hemisphere, configFile): assert( (hemisphere == 'north') | (hemisphere == 'south') ) hemiSelect = {'north': 'North', 'south': 'South'}[hemisphere] # Make sure the output directory exisits if not make it dirname = os.path.join(path, 'figs', hemisphere) if not os.path.exists(dirname): os.makedirs( dirname ) print(('Rendering ' + hemiSelect + 'ern hemisphere, storing frames at ' + dirname)) #Now check to make sure the files are correct data = pyLTR.Models.MIX(path, runName) 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) 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() # Pre-compute r and theta x = data.read('Grid X', timeRange[index0]) y = data.read('Grid Y', timeRange[index0]) theta=n.arctan2(y,x) theta[theta<0]=theta[theta<0]+2*n.pi # plotting routines now rotate local noon to point up #theta=theta+n.pi/2 # to put noon up r=n.sqrt(x**2+y**2) # plotting routines now expect longitude and colatitude, in radians, stored in dictionaries longitude = {'data':theta,'name':r'\phi','units':r'rad'} colatitude = {'data':n.arcsin(r),'name':r'\theta','units':r'rad'} # Deal with the plot options if (configFile == None): potOpts={'min':-100.,'max':100.,'colormap':'bwr'} #'RdBu_r'} facOpts={'min':-1.,'max':1.,'colormap':'bwr'} #'RdBu_r'} pedOpts={'min':1.,'max':20.,'colormap':'plasma'} halOpts={'min':1.,'max':20.,'colormap':'plasma'} engOpts={'min':0.,'max':20.} flxOpts={'min':0.,'max':1.0e9,'format_str':'%.1e','colormap':'jet'} optsObject = {'pot':potOpts, 'fac':facOpts, 'ped':pedOpts, 'hall':halOpts, 'energy':engOpts, 'flux':flxOpts} configFilename=os.path.join(dirname,'IonSum.config') print(("Writing plot config file at " + configFilename)) f=open(configFilename,'w') f.write(pyLTR.yaml.safe_dump(optsObject,default_flow_style=False)) f.close() else: f=open(configFile,'r') optsDict=pyLTR.yaml.safe_load(f.read()) f.close() if ('pot' in optsDict): potOpts = optsDict['pot'] else: potOpts={'min':-100.,'max':100.,'colormap':'RdBu_r'} if ('fac' in optsDict): facOpts = optsDict['fac'] else: facOpts={'min':-1.,'max':1.,'colormap':'RdBu_r'} if ('ped' in optsDict): pedOpts = optsDict['ped'] else: pedOpts={'min':1.,'max':8.} if ('hall' in optsDict): halOpts = optsDict['hall'] else: halOpts={'min':1.,'max':8.} if ('energy' in optsDict): engOpts = optsDict['energy'] else: engOpts={'min':0.,'max':20.} if ('flux' in optsDict): flxOpts = optsDict['flux'] else: flxOpts={'min':0.,'max':1.0e9,'format_str':'%.1e'} for i,time in enumerate(timeRange[index0:index1]): try: #first read the data vals=data.read('Potential '+hemiSelect+' [V]',time)/1000.0 psi={'data':vals,'name':r'$\Phi$','units':r'kV'} vals=data.read('FAC '+hemiSelect+' [A/m^2]',time)*1.0e6 fac={'data':vals,'name':r'$J_{||}$', 'units':r'$\mu\mathrm{A/m^2}$'} vals1=data.read('Average energy '+hemiSelect+' [keV]',time) eng={'data':vals1,'name':r'Energy','units':r'keV'} vals2=data.read('Number flux '+hemiSelect+' [1/cm^2 s]',time) flx={'data':vals2,'name':r'Flux','units':r'$\mathrm{1/cm^2s}$'} hal={'data':vals1*vals2/10,'name':r'EFlux','units':r'??'} vals=data.read('Pedersen conductance '+hemiSelect+' [S]',time) ped={'data':vals,'name':r'$\Sigma_{P}$','units':r'S'} vals=data.read('Hall conductance '+hemiSelect+' [S]',time) #hal={'data':vals,'name':r'$\Sigma_{H}$','units':r'S'} # Now onto the plot tt=time.timetuple() p.figure(figsize=(16,12)) p.figtext(0.5,0.92,'MIX '+hemiSelect+ '\n%4d-%02d-%02d %02d:%02d:%02d' % (tt.tm_year,tt.tm_mon,tt.tm_mday, tt.tm_hour,tt.tm_min,tt.tm_sec), fontsize=14,multialignment='center') ax=p.subplot(231,polar=True) pyLTR.Graphics.PolarPlot.BasicPlotDict(longitude,colatitude,psi, potOpts,userAxes=ax,useMesh=True) ax=p.subplot(234,polar=True) pyLTR.Graphics.PolarPlot.BasicPlotDict(longitude,colatitude,fac, facOpts,userAxes=ax) ax=p.subplot(232,polar=True) pyLTR.Graphics.PolarPlot.BasicPlotDict(longitude,colatitude,ped, pedOpts,userAxes=ax) ax=p.subplot(235,polar=True) pyLTR.Graphics.PolarPlot.BasicPlotDict(longitude,colatitude,hal, flxOpts,userAxes=ax) ax=p.subplot(233,polar=True) pyLTR.Graphics.PolarPlot.BasicPlotDict(longitude,colatitude,eng, engOpts,userAxes=ax) ax=p.subplot(236,polar=True) pyLTR.Graphics.PolarPlot.BasicPlotDict(longitude,colatitude,flx, flxOpts,userAxes=ax) savefigName = os.path.join(path,'figs',hemisphere,'frame_summary_%05d.png'%i) p.savefig(savefigName,dpi=100) p.close() 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() return os.path.join(path,'figs',hemisphere)
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 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)
def CreateFrames(path='./', run='', t0='', t1='', hemisphere='north', geoGrid=False, ignoreBinary=False, binaryType='pkl', configFile=None): """ Compute deltaBs hemispheric grid given LFM-MIX output files in path. Computes: pngFiles - a list of PNG filenames, each corresponding to a snapshot in time of LFM-MIX ground deltaB vector fields NOTE: while the output is a list of filenames, the function generates binary pkl/mat files that can be read in by other software for further analysis. FIXME: southern hemisphere summary plots are presented from a point of view below the south pole, looking up. Likewise for the data files. This is not technically a right-handed frame of reference, so any analysis of southern hemisphere data must rotate fields 180 degrees about the X axis, or 0 longitude, 0 latitude line. This odd data file convention is consistent with how southern hemisphere data is stored in MIX files, but there is a strong argument to just store everything assuming the same (northern) POV, and rotate to a southern POV for display purposes only; this will require significant work. 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) hemisphere - specify 'north' or 'south' hemisphere (default is 'north') 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') configFile - specifies plotting config file; if None, default config file is path/figs/north|south/deltaBSum.config; if this doesn't exist, create new one with default config parameters. """ assert( (hemisphere == 'north') | (hemisphere == 'south') ) hemiSelect = {'north': 'North', 'south': 'South'}[hemisphere] # Make sure the output directory exisits if not make it dirname = os.path.join(path, 'figs', hemisphere) if not os.path.exists(dirname): os.makedirs( dirname ) print(('Rendering ' + hemiSelect + 'ern hemisphere, storing frames at ' + dirname)) #Now check to make sure the MIX files are correct dMIX = pyLTR.Models.MIX(path, run) modelVars = dMIX.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]']: assert( v in modelVars ) timeRange = dMIX.getTimeRange() #Now check to make sure the LFM files are correct dLFM = pyLTR.Models.LFM(path, run) modelVars = dLFM.getVarNames() for v in ['X_grid', 'Y_grid', 'Z_grid', 'bx_', 'by_', 'bz_']: assert( v in modelVars ) # check that LFM output timeRanges are exactly the same as MIX output timeRanges trLFM = dLFM.getTimeRange() # _roundTime() rounds to nearest minute by default, which should suffice here # NOTE: we do NOT change the time stamps at all, just make sure they match # to a 1-minute tolerance if list(map(_roundTime, timeRange)) != list(map(_roundTime, trLFM)): raise Exception(('Mismatched MIX and LFM output files')) if len(timeRange) == 0: raise Exception(('No data files found. Are you pointing to the correct run directory?')) ## Original code defaulted to entire data set if the user-supplied time range ## fell outside of the available data, almost certainly not a desired result. ## Now if the user requests a time range that falls completely outside of the ## available data, and exception is raised. ##index0 = 0 ##if t0: ## for i,t in enumerate(timeRange): ## if t0 >= t: ## index0 = i ## ###index1 = len(timeRange)-1 ##index1 = len(timeRange) # we were skipping the last valid time step ##if t1: ## for i,t in enumerate(timeRange): ## if t1 >= t: ## #index1 = i ## index1 = i + 1 # we were skipping the last valid time step if t0: if t1 and t1 < timeRange[0]: # upper time stamp below lowest available time stamp raise Exception('Requested time range falls outside available data') if t0 > timeRange[-1]: # lower time stamp above highest available time stamp raise Exception('Requested time range falls outside available data') for i,t in enumerate(timeRange): if t0 >= t: index0 = i else: index0 = 0 if t1: if t0 and t0 > timeRange[-1]: # lower time stamp above highest available time stamp raise Exception('Requested time range falls outside available data') if t1 < timeRange[0]: # upper time stamp below lowest available time stamp raise Exception('Requested time range falls outside available data') for i,t in enumerate(timeRange): if t1 >= t: index1 = i+1 else: index1 = len(timeRange) if index1 > index0: print(( 'Extracting LFM and MIX quantities for time series over %d time steps.' % (index1-index0) )) else: raise Exception('Requested time range is invalid') # Output a status bar displaying how far along the computation is. progress = pyLTR.StatusBar(0, index1-index0) progress.start() # Pre-compute r and theta x = dMIX.read('Grid X', timeRange[index0]) xdict={'data':x*6500e3,'name':'X','units':r'm'} y = dMIX.read('Grid Y', timeRange[index0]) ydict={'data':y*6500e3,'name':'Y','units':r'm'} theta=n.arctan2(y,x) theta[theta<0]=theta[theta<0]+2*n.pi # plotting routines now rotate local noon to point up #theta=theta+n.pi/2 # to put noon up r=n.sqrt(x**2+y**2) # plotting routines now expect longitude and colatitude, in radians, stored in dictionaries longitude = {'data':theta,'name':r'\phi','units':r'rad'} colatitude = {'data':n.arcsin(r),'name':r'\theta','units':r'rad'} # Deal with the plot options if (configFile == None and os.path.exists(os.path.join(dirname,'deltaBSum.config')) ): configFile = os.path.join(dirname,'deltaBSum.config') if configFile == None: # scalar radial magnetic pertubations dBradialTotOpts={'min':-100,'max':100,'colormap':'jet'} dBradialIonOpts={'min':-100,'max':100,'colormap':'jet'} dBradialFACOpts={'min':-100,'max':100,'colormap':'jet'} dBradialMagOpts={'min':-100,'max':100,'colormap':'jet'} # 2D vector horizontal perturbations dBhvecTotOpts={'width':.0025,'scale':1e3,'pivot':'middle'} dBhvecIonOpts={'width':.0025,'scale':1e3,'pivot':'middle'} dBhvecFACOpts={'width':.0025,'scale':1e3,'pivot':'middle'} dBhvecMagOpts={'width':.0025,'scale':1e3,'pivot':'middle'} # place all config dictionaries in one big dictionary optsObject = {'dBradialTot':dBradialTotOpts, 'dBradialIon':dBradialIonOpts, 'dBradialFAC':dBradialFACOpts, 'dBradialMag':dBradialMagOpts, 'dBhvecTot':dBhvecTotOpts, 'dBhvecIon':dBhvecIonOpts, 'dBhvecFAC':dBhvecFACOpts, 'dBhvecMag':dBhvecMagOpts, 'altPole':altPoleOpts} configFilename=os.path.join(dirname,'deltaBSum.config') print(("Writing plot config file at " + configFilename)) f=open(configFilename,'w') f.write(pyLTR.yaml.safe_dump(optsObject,default_flow_style=False)) f.close() else: f=open(configFile,'r') optsDict=pyLTR.yaml.safe_load(f.read()) f.close() if ('dBradialTot' in optsDict): dBradialTotOpts = optsDict['dBradialTot'] else: dBradialTotOpts={'min':-100.,'max':100.,'colormap':'jet'} if ('dBradialIon' in optsDict): dBradialIonOpts = optsDict['dBradialIon'] else: dBradialIonOpts={'min':-100.,'max':100.,'colormap':'jet'} if ('dBradialFAC' in optsDict): dBradialFACOpts = optsDict['dBradialFAC'] else: dBradialFACOpts={'min':-100.,'max':100.,'colormap':'jet'} if ('dBradialMag' in optsDict): dBradialMagOpts = optsDict['dBradialMag'] else: dBradialMagOpts={'min':-100.,'max':100.,'colormap':'jet'} if ('dBhvecTot' in optsDict): dBhvecTotOpts = optsDict['dBhvecTot'] else: dBhvecTotOpts={'min':-100.,'max':100.,'colormap':'jet'} if ('dBhvecIon' in optsDict): dBhvecIonOpts = optsDict['dBhvecIon'] else: dBhvecIonOpts={'min':-100.,'max':100.,'colormap':'jet'} if ('dBhvecFAC' in optsDict): dBhvecFACOpts = optsDict['dBhvecFAC'] else: dBhvecFACOpts={'min':-100.,'max':100.,'colormap':'jet'} if ('dBhvecMag' in optsDict): dBhvecMagOpts = optsDict['dBhvecMag'] else: dBhvecMagOpts={'min':-100.,'max':100.,'colormap':'jet'} if ('altPole' in optsDict): altPoleOpts = optsDict['altPole'] else: altPoleOpts = {'poleMarker1':'x', 'poleMarker2':'x', 'poleSize1':7, 'poleSize2':5, 'poleWidth1':3, 'poleWidth2':1, 'poleColor1':'blue', 'poleColor2':'white'} # initialize output list pngFilenames = [] for i,time in enumerate(timeRange[index0:index1]): try: try: # ignore binary file even if one exists if ignoreBinary: raise Exception # look for a .pkl file that already holds all the data required for # subsequent plots before recalculating all the derived data...if # this fails, look for a .mat file, if this fails, fall through to # recalculate all summary data filePrefix = os.path.join(path,'figs',hemisphere) # this is a possible race condition, but try/except just doesn't do what I want if os.path.exists(os.path.join(filePrefix, 'frame_deltaB_%04d-%02d-%02dT%02d-%02d-%02dZ.pkl'% (time.year,time.month,time.day, time.hour,time.minute,time.second))): binFilename = os.path.join(filePrefix, 'frame_deltaB_%04d-%02d-%02dT%02d-%02d-%02dZ.pkl'% (time.year,time.month,time.day, time.hour,time.minute,time.second)) fh=open(binFilename,'rb') allDict = pickle.load(fh) fh.close() elif os.path.exists(os.path.join(filePrefix, 'frame_deltaB_%04d-%02d-%02dT%02d-%02d-%02dZ.mat'% (time.year,time.month,time.day, time.hour,time.minute,time.second))): binFilename = os.path.join(filePrefix, 'frame_deltaB_%04d-%02d-%02dT%02d-%02d-%02dZ.mat'% (time.year,time.month,time.day, time.hour,time.minute,time.second)) fh=open(binFilename,'rb') allDict = sio.loadmat(fh, squeeze_me=True) fh.close() else: print(('No binary file found, recalculating '+ 'frame_deltaB_%04d-%02d-%02dT%02d-%02d-%02dZ'% (time.year,time.month,time.day,time.hour,time.minute,time.second)+ '...')) raise Exception # ignore binary file if the coordinate system is not consistent with geoGrid if ((geoGrid and allDict['coordinates'] != 'Geographic') or (not(geoGrid) and allDict['coordinates'] != 'Solar Magnetic')): raise Exception phi_dict,theta_dict,rho_dict = allDict['dB_obs'] phi = phi_dict['data'] * 1. # '*1' forces array of floats, NOT objects theta = theta_dict['data'] * 1. # '*1' forces array of floats, NOT objects rho = rho_dict['data'] * 1. # '*1' forces array of floats, NOT objects if geoGrid: phi_geo = phi theta_geo = theta rho_geo = rho dBphi_ion_dict,dBtheta_ion_dict,dBrho_ion_dict = allDict['dB_ion'] dBphi_ion = dBphi_ion_dict['data'] / 1e9 # convert to Tesla dBtheta_ion = dBtheta_ion_dict['data'] / 1e9 # convert to Tesla dBrho_ion = dBrho_ion_dict['data'] / 1e9 # convert to Tesla dBphi_fac_dict,dBtheta_fac_dict,dBrho_fac_dict = allDict['dB_fac'] dBphi_fac = dBphi_fac_dict['data'] / 1e9 # convert to Tesla dBtheta_fac = dBtheta_fac_dict['data'] / 1e9 # convert to Tesla dBrho_fac = dBrho_fac_dict['data'] / 1e9 # convert to Tesla dBphi_mag_dict,dBtheta_mag_dict,dBrho_mag_dict = allDict['dB_mag'] dBphi_mag = dBphi_mag_dict['data'] / 1e9 # convert to Tesla dBtheta_mag = dBtheta_mag_dict['data'] / 1e9 # convert to Tesla dBrho_mag = dBrho_mag_dict['data'] / 1e9 # convert to Tesla except: # first read the MIX data vals=dMIX.read('Potential '+hemiSelect+' [V]',time)/1000.0 psi_dict={'data':vals,'name':r'$\Phi$','units':r'kV'} vals=dMIX.read('Pedersen conductance '+hemiSelect+' [S]',time) sigmap_dict={'data':vals,'name':r'$\Sigma_{P}$','units':r'S'} vals=dMIX.read('Hall conductance '+hemiSelect+' [S]',time) sigmah_dict={'data':vals,'name':r'$\Sigma_{H}$','units':r'S'} vals=dMIX.read('FAC '+hemiSelect+' [A/m^2]',time) fac_dict={'data':vals*1e6,'name':r'$J_\parallel$','units':r'$\mu A/m^2$'} # then compute the electric field vectors ((phi_dict,theta_dict), (ephi_dict,etheta_dict)) = pyLTR.Physics.MIXCalcs.efieldDict( xdict, ydict, psi_dict, ri=6500e3) # then compute total, Pedersen, and Hall current vectors if hemisphere=='north': ((Jphi_dict,Jtheta_dict), (Jpedphi_dict,Jpedtheta_dict), (Jhallphi_dict,Jhalltheta_dict)) = pyLTR.Physics.MIXCalcs.jphithetaDict( (ephi_dict,etheta_dict), sigmap_dict, sigmah_dict, colatitude['data']) else: ((Jphi_dict,Jtheta_dict), (Jpedphi_dict,Jpedtheta_dict), (Jhallphi_dict,Jhalltheta_dict)) = pyLTR.Physics.MIXCalcs.jphithetaDict( (ephi_dict,etheta_dict), sigmap_dict, sigmah_dict, n.pi-colatitude['data']) # then generate the SSECS, starting with min/max bounds of ionosphere # segments phi = phi_dict['data'] theta = theta_dict['data'] # caclulate MIX grid cell boundaries in phi and theta rion_min = [None] * 3 # initialize empty 3 list rion_min[0] = p.zeros(phi.shape) rion_min[0][1:,:] = phi[1:,:] - p.diff(phi, axis=0)/2. rion_min[0][0,:] = phi[0,:] - p.diff(phi[0:2,:], axis=0).squeeze()/2. rion_min[1] = p.zeros(theta.shape) rion_min[1][:,1:] = theta[:,1:] - p.diff(theta, axis=1)/2. rion_min[1][:,0] = theta[:,0] - p.diff(theta[:,0:2], axis=1).squeeze()/2. rion_min[2] = p.zeros(theta.shape) rion_min[2][:,:] = 6500.e3 rion_max = [None] * 3 # initialize empty 3 list rion_max[0] = p.zeros(phi.shape) rion_max[0][:-1,:] = phi[:-1,:] + p.diff(phi, axis=0)/2. rion_max[0][-1,:] = phi[-1,:] + p.diff(phi[-2:,:], axis=0).squeeze()/2. rion_max[1] = p.zeros(theta.shape) rion_max[1][:,:-1] = theta[:,:-1] + p.diff(theta, axis=1)/2. rion_max[1][:,-1] = theta[:,-1] + p.diff(theta[:,-2:], axis=1).squeeze()/2. rion_max[2] = p.zeros(theta.shape) rion_max[2][:,:] = p.Inf # generate SSECS for ionospheric currents only (rv_ion, Jv_ion, dv_ion) = pyLTR.Physics.SSECS.ssecs_sphere([rion_min[0],rion_min[1],rion_min[2]], [rion_max[0],rion_max[1],rion_min[2]], (Jphi_dict['data']/1e6, Jtheta_dict['data']/1e6), 10, False) # generate SSECS inside LFM inner boundary (rv_IBin, Jv_IBin, dv_IBin) = pyLTR.Physics.SSECS.ssecs_sphere([rion_min[0],rion_min[1],rion_min[2]], [rion_max[0],rion_max[1],2.5*rion_min[2]], (Jphi_dict['data']/1e6, Jtheta_dict['data']/1e6), 10, False) # do NOT attempt to generate SSECS for FACs alone...this isn't possible # with existing code; However, the deltaB from FACs is the difference # between deltaBs calculated from the two SSECS above # generate SSECS outside LFM inner boundary # (this is serving as a proxy for magnetosphere currents for now) (rv_mag, Jv_mag, dv_mag) = pyLTR.Physics.SSECS.ssecs_sphere([rion_min[0],rion_min[1],2.5*rion_min[2]], [rion_max[0],rion_max[1],rion_min[2]], (Jphi_dict['data']/1e6, Jtheta_dict['data']/1e6), 10, False) # extract currents from MHD data # NOTE: LFM time stamps are not necessarily the same as MIX, so it # is necessary to use the LFM's timeRange list (i.e., trLFM) x=dLFM.read('X_grid', trLFM[index0:index1][i]) # this is in cm y=dLFM.read('Y_grid', trLFM[index0:index1][i]) # this is in cm z=dLFM.read('Z_grid', trLFM[index0:index1][i]) # this is in cm Bx=dLFM.read('bx_', trLFM[index0:index1][i]) # this is in G By=dLFM.read('by_', trLFM[index0:index1][i]) # this is in G Bz=dLFM.read('bz_', trLFM[index0:index1][i]) # this is in G hgrid=pyLTR.Grids.HexahedralGrid(x,y,z) xB,yB,zB=hgrid.cellCenters() hgridcc=pyLTR.Grids.HexahedralGrid(xB,yB,zB) # B is at cell centers Jx,Jy,Jz = pyLTR.Physics.LFMCurrent(hgridcc,Bx,By,Bz,rion=1) # ...should be A/m^2 given default input units xJ,yJ,zJ = hgridcc.cellCenters() # ...and J is at the centers of these cells xJ = xJ/100 # ...and the coordinates should be in meters for BS.py yJ = yJ/100 # ...and the coordinates should be in meters for BS.py zJ = zJ/100 # ...and the coordinates should be in meters for BS.py ldV = hgridcc.cellVolume()/(100**3) # ...and we need dV in m^3 for BS.py if hemisphere=='south': # it's easier to rotate the LFM grid than convert the MIX coordinates # for southern hemisphere output yJ = -yJ zJ = -zJ Jy = -Jy Jz = -Jz # # This is a little ugly...Quad (and Oct) resolution LFM runs use # MIX grids that are different resoltions than Single and Double # runs; not surprising, but I was slow to figure this out. Anyway, # we need to visualize and cross-validate on similar grids, thus # the following kludge ('kludge' because the better answer is to # specify a useful grid without any reference to the MIX grid). # if phi.size == 181*27: pass elif phi.size == 361*48: phi = phi[::2,[0,1,2,3,4]+list(range(5,48,2))] theta = theta[::2,[0,1,2,3,4]+list(range(5,48,2))] else: raise Exception('Unrecognized MIX grid dimensions') # calculate deltaBs on a grid that decimates MIX grid by 2/3, and removes # the lowest 3 colatitutdes phi = phi[::3,3:] theta = theta[::3,3:] rho = p.tile(6378e3,phi.shape) if geoGrid: phi_geo = phi theta_geo = theta rho_geo = rho x,y,z = pyLTR.transform.SPHtoCAR(phi,theta,rho) x,y,z = pyLTR.transform.GEOtoSM(x,y,z,time) phi,theta,rho = pyLTR.transform.CARtoSPH(x,y,z) # deltaB for ionospheric currents (dBphi_ion, dBtheta_ion, dBrho_ion) = pyLTR.Physics.BS.bs_sphere(rv_ion, Jv_ion, dv_ion, (phi,theta,rho)) # deltaB for currents inside IB (dBphi_IBin, dBtheta_IBin, dBrho_IBin) = pyLTR.Physics.BS.bs_sphere(rv_IBin, Jv_IBin, dv_IBin, (phi,theta,rho)) # difference between dB*_IBin and dB*_ion is the FAC inside IB dBphi_fac = dBphi_IBin - dBphi_ion dBtheta_fac = dBtheta_IBin - dBtheta_ion dBrho_fac = dBrho_IBin - dBrho_ion # deltaB from magnetospheric currents # convert cartesian positions and vectors to spherical lphi,ltheta,lrho,lJphi,lJtheta,lJrho=pyLTR.transform.CARtoSPH(xJ,yJ,zJ,Jx,Jy,Jz) (dBphi_mag, dBtheta_mag, dBrho_mag) = pyLTR.Physics.BS.bs_sphere((lphi,ltheta,lrho), (lJphi,lJtheta,lJrho), ldV, (phi,theta,rho)) if geoGrid: # rotate ionospheric contribution from SM to GEO coordinates; leave # position vectors unchanged for subsequent rotations x,y,z,dx,dy,dz = pyLTR.transform.SPHtoCAR(phi,theta,rho,dBphi_ion,dBtheta_ion,dBrho_ion) x,y,z = pyLTR.transform.SMtoGEO(x,y,z,time) dx,dy,dz = pyLTR.transform.SMtoGEO(dx,dy,dz,time) _, _, _, dBphi_ion, dBtheta_ion, dBrho_ion = pyLTR.transform.CARtoSPH(x,y,z,dx,dy,dz) # rotate FAC contribution from SM to GEO coordinates leave # position vectors unchanged for subsequent rotations x,y,z,dx,dy,dz = pyLTR.transform.SPHtoCAR(phi,theta,rho,dBphi_fac,dBtheta_fac,dBrho_fac) x,y,z = pyLTR.transform.SMtoGEO(x,y,z,time) dx,dy,dz = pyLTR.transform.SMtoGEO(dx,dy,dz,time) _, _, _, dBphi_fac, dBtheta_fac, dBrho_fac = pyLTR.transform.CARtoSPH(x,y,z,dx,dy,dz) # rotate magnetospheric contribution from SM to GEO coordinates x,y,z,dx,dy,dz = pyLTR.transform.SPHtoCAR(phi,theta,rho,dBphi_mag,dBtheta_mag,dBrho_mag) x,y,z = pyLTR.transform.SMtoGEO(x,y,z,time) dx,dy,dz = pyLTR.transform.SMtoGEO(dx,dy,dz,time) _, _, _, dBphi_mag, dBtheta_mag, dBrho_mag = pyLTR.transform.CARtoSPH(x,y,z,dx,dy,dz) phi = phi_geo theta = theta_geo rho = rho_geo # # end of [re]processing 'except' block # # (re)create grid dictionary for subsequent plots and pickling toPickle={} if hemisphere=='south': toPickle['pov'] = 'south' else: toPickle['pov'] = 'north' if geoGrid: toPickle['coordinates'] = 'Geographic' # get geographic coordinates of sm pole x,y,z = pyLTR.transform.SPHtoCAR(0,0,1) x,y,z = pyLTR.transform.SMtoGEO(x,y,z,time) poleCoords = pyLTR.transform.CARtoSPH(x,y,z) else: toPickle['coordinates'] = 'Solar Magnetic' ## # get sm coordinates of geographic pole ## x,y,z = pyLTR.transform.SPHtoCAR(0,0,1) ## x,y,z = pyLTR.transform.GEOtoSM(x,y,z,time) ## poleCoords = pyLTR.transform.CARtoSPH(x,y,z) ## now that MapPlot is being used, and until it can properly ## plot in centered SM coordinates, we want to just plot the ## magnetic pole; poleCoords = (0, 0, 1) phi_dict = {'data':phi,'name':r'$\phi$','units':r'rad'} theta_dict = {'data':theta,'name':r'$\theta$','units':r'rad'} rho_dict = {'data':rho,'name':r'$\rho$','units':r'm'} toPickle['dB_obs'] = (phi_dict,theta_dict,rho_dict) ##################################################################### ## ## FIXME: move plots from this function into if __name__ == '__main__' ## section like deltaBTimeSeries.py; plots will then only be ## generated if user requests it, and this function may be ## called as part of a module... ## But note: one reason the plots are generated inside this ## function is that a long time series of gridded ## data becomes unmanageable memory-wise fairly ## quickly...think this through carefully. -EJR ## ##################################################################### # Now onto the plots tt=time.timetuple() p.figure(1,figsize=(28,6)) p.figtext(0.5,0.92,'Ground '+'$\Delta{\mathbf{B}}$'+' - '+hemiSelect+ '\n%4d-%02d-%02d %02d:%02d:%02d' % (tt.tm_year,tt.tm_mon,tt.tm_mday, tt.tm_hour,tt.tm_min,tt.tm_sec), fontsize=14,multialignment='center') # plot total deltaB ax=p.subplot(141) # temporary dictionaries dBphi_dict = {'data':(dBphi_ion + dBphi_fac + dBphi_mag)*1e9,'name':r'$\Delta \mathrm{B}_{\phi}$','units':'nT'} dBtheta_dict = {'data':(dBtheta_ion + dBtheta_fac + dBtheta_mag)*1e9,'name':r'$\Delta \mathrm{B}_{\theta}$','units':'nT'} dBrho_dict = {'data':(dBrho_ion + dBrho_fac + dBrho_mag)*1e9,'name':r'$\Delta \mathrm{B}_{\rho}$','units':'nT'} bm = pyLTR.Graphics.MapPlot.QuiverPlotDict(phi_dict,theta_dict, dBrho_dict,(dBphi_dict, dBtheta_dict), dtUTC=time, coordSystem=toPickle['coordinates'], plotOpts1=dBradialTotOpts, plotOpts2=dBhvecTotOpts, points=[(poleCoords[0],poleCoords[1])], userAxes=ax, northPOV=hemisphere=='north') to=p.text(.05, .95, r"$\Delta \mathbf{B}_{\mathrm{Total}}$", fontsize=14, transform=ax.transAxes) # plot ionospheric deltaB ax=p.subplot(142) # temporary dictionaries dBphi_dict = {'data':(dBphi_ion)*1e9,'name':r'$\Delta \mathrm{B}_{\phi}$','units':'nT'} dBtheta_dict = {'data':(dBtheta_ion)*1e9,'name':r'$\Delta \mathrm{B}_{\theta}$','units':'nT'} dBrho_dict = {'data':(dBrho_ion)*1e9,'name':r'$\Delta \mathrm{B}_{\rho}$','units':'nT'} bm = pyLTR.Graphics.MapPlot.QuiverPlotDict(phi_dict,theta_dict, dBrho_dict,(dBphi_dict, dBtheta_dict), dtUTC=time, coordSystem=toPickle['coordinates'], plotOpts1=dBradialIonOpts, plotOpts2=dBhvecIonOpts, points=[(poleCoords[0],poleCoords[1])], userAxes=ax, northPOV=hemisphere=='north') to=p.text(.05, .95, r"$\Delta \mathbf{B}_{\mathrm{ion}}$", fontsize=14, transform=ax.transAxes) # for subsequent pickling toPickle['dB_ion'] = (dBphi_dict,dBtheta_dict,dBrho_dict) # plot FAC deltaB ax=p.subplot(143) # temporary dictionaries dBphi_dict = {'data':(dBphi_fac)*1e9,'name':r'$\Delta \mathrm{B}_{\phi}$','units':'nT'} dBtheta_dict = {'data':(dBtheta_fac)*1e9,'name':r'$\Delta \mathrm{B}_{\theta}$','units':'nT'} dBrho_dict = {'data':(dBrho_fac)*1e9,'name':r'$\Delta \mathrm{B}_{\rho}$','units':'nT'} bm = pyLTR.Graphics.MapPlot.QuiverPlotDict(phi_dict,theta_dict, dBrho_dict,(dBphi_dict, dBtheta_dict), dtUTC=time, coordSystem=toPickle['coordinates'], plotOpts1=dBradialFACOpts, plotOpts2=dBhvecFACOpts, points=[(poleCoords[0],poleCoords[1])], userAxes=ax, northPOV=hemisphere=='north') to=p.text(.05, .95, r"$\Delta \mathbf{B}_{\mathrm{fac}}$", fontsize=14, transform=ax.transAxes) # for subsequent pickling toPickle['dB_fac'] = (dBphi_dict,dBtheta_dict,dBrho_dict) # plot magnetospheric deltaB ax=p.subplot(144) # temporary dictionaries dBphi_dict = {'data':(dBphi_mag)*1e9,r'name':'$\Delta \mathrm{B}_{\phi}$','units':'nT'} dBtheta_dict = {'data':(dBtheta_mag)*1e9,r'name':'$\Delta \mathrm{B}_{\theta}$','units':'nT'} dBrho_dict = {'data':(dBrho_mag)*1e9,'name':r'$\Delta \mathrm{B}_{\rho}$','units':'nT'} bm = pyLTR.Graphics.MapPlot.QuiverPlotDict(phi_dict,theta_dict, dBrho_dict,(dBphi_dict, dBtheta_dict), dtUTC=time, coordSystem=toPickle['coordinates'], plotOpts1=dBradialMagOpts, plotOpts2=dBhvecMagOpts, points=[(poleCoords[0],poleCoords[1])], userAxes=ax, northPOV=hemisphere=='north') to=p.text(.05, .95, r"$\Delta \mathbf{B}_{\mathrm{mag}}$", fontsize=14, transform=ax.transAxes) # for subsequent pickling toPickle['dB_mag'] = (dBphi_dict,dBtheta_dict,dBrho_dict) #savefigName = os.path.join(path,'figs',hemisphere,'frame_deltaB_%05d.png'%i) filePrefix = os.path.join(path,'figs',hemisphere) pngFilename = os.path.join(filePrefix,'frame_deltaB_%04d-%02d-%02dT%02d-%02d-%02dZ.png'% (time.year,time.month,time.day,time.hour,time.minute,time.second)) p.savefig(pngFilename,dpi=150) p.clf() if binaryType.lower() == 'pkl' or binaryType.lower() == '.pkl' or binaryType.lower() == 'pickle': # --- Dump a pickle! pklFilename = os.path.join(filePrefix,'frame_deltaB_%04d-%02d-%02dT%02d-%02d-%02dZ.pkl'% (time.year,time.month,time.day,time.hour,time.minute,time.second)) fh = open(pklFilename, 'wb') pickle.dump(toPickle, fh, protocol=2) fh.close() elif binaryType.lower() == 'mat' or binaryType.lower() == '.mat' or binaryType.lower() == 'matlab': # --- Dump a .mat file! matFilename = os.path.join(filePrefix,'frame_deltaB_%04d-%02d-%02dT%02d-%02d-%02dZ.mat'% (time.year,time.month,time.day,time.hour,time.minute,time.second)) sio.savemat(matFilename, toPickle) elif binaryType.lower() == 'none': pass else: print(('Unrecognized binary type '+binaryType+' requested')) raise Exception 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 # append pngFilename to list of fully qualified filenames pngFilenames.append(pngFilename) progress.stop() progress.join() #return os.path.join(path,'figs',hemisphere) return pngFilenames