def theta_plots(pressure, temperature, mixing_ratio): """ plots for vertical profiles of potential temperature, equivalent potential temperature, and saturated equivalent potential temperature """ p = pressure * units('mbar') T = temperature * units('degC') q = mixing_ratio * units('kilogram/kilogram') lev = find_nearest(p.magnitude, 100) Td = mpcalc.dewpoint(mpcalc.vapor_pressure(p, q)) # dewpoint theta = mpcalc.potential_temperature(p, T) theta_e = mpcalc.equivalent_potential_temperature(p, T, Td) theta_es = mpcalc.equivalent_potential_temperature(p, T, T) plt.figure(figsize=(7, 7)) plt.plot(theta[:lev], p[:lev], '-ok') plt.plot(theta_e[:lev], p[:lev], '-ob') plt.plot(theta_es[:lev], p[:lev], '-or') plt.xlabel('Temperature [K]', fontsize=12) plt.ylabel('Pressure [hpa]', fontsize=12) plt.gca().invert_yaxis() plt.legend(['$\\theta$', '$\\theta_e$', '$\\theta_{es}$'], loc=1) plt.grid() return (plt)
def test_equivalent_potential_temperature(): """Test equivalent potential temperature calculation.""" p = 1000 * units.mbar t = 293. * units.kelvin td = 280. * units.kelvin ept = equivalent_potential_temperature(p, t, td) assert_almost_equal(ept, 311.18586467284007 * units.kelvin, 3)
def test_equivalent_potential_temperature(): """Test equivalent potential temperature calculation.""" p = 1000 * units.mbar t = 293. * units.kelvin td = 280. * units.kelvin ept = equivalent_potential_temperature(p, t, td) assert_almost_equal(ept, 311.18586467284007 * units.kelvin, 3)
def getDataFrame_UpperAir(model, station, init, hour): bufrData = BUFKIT.getBufkitData(model, station, init) if bufrData != False: # Verify data found modelSoundings = bufrData.SoundingParameters surfaceData = bufrData.SurfaceParameters[hour] soundingData = modelSoundings[hour + 1] z = [0 * units.meters] p = [surfaceData.pres] T = [surfaceData.t2ms] Td = [surfaceData.td2m] #Tw = [mpcalc.wet_bulb_temperature(surfaceData.pres, surfaceData.t2ms, surfaceData.td2m)] theta = [ mpcalc.potential_temperature(surfaceData.pres, surfaceData.t2ms) ] theta_e = [ mpcalc.equivalent_potential_temperature(surfaceData.pres, surfaceData.t2ms, surfaceData.td2m) ] u = [surfaceData.uwnd] v = [surfaceData.vwnd] for level in soundingData: z.append(level.hght) p.append(level.pres) T.append(level.tmpc) Td.append(level.dwpc) #Tw.append(mpcalc.wet_bulb_temperature(level.pres, level.tmpc, level.dwpc)) theta.append(mpcalc.potential_temperature(level.pres, level.tmpc)) theta_e.append( mpcalc.equivalent_potential_temperature( level.pres, level.tmpc, level.dwpc)) uv = mpcalc.wind_components(level.sknt, level.drct) u.append(uv[0]) v.append(uv[1]) return pd.DataFrame(list(zip(z, p, T, Td, theta, theta_e, u, v)), columns=[ 'height', 'pressure', 'temperature', 'dewpoint', 'theta', 'theta_e', 'u_wind', 'v_wind' ]) else: return False
def add_eqiv_potential_temp(tbs): temp = tbs['temp'].values * units.celsius rh = tbs['rh'].values * units.percent press = tbs['atm_pressure'].values * units.millibar # dewpt_pint = calc.dewpoint_rh(temp, rh) dewpt_pint = calc.dewpoint_from_relative_humidity(temp, rh) dewpt = np.array(dewpt_pint) tbs['dew_point'] = dewpt tbs['equiv_potential_temperature'] = np.array(calc.equivalent_potential_temperature(press, temp, dewpt_pint)) return
def equivalent_potential_temperature(pressure, temperature, dewpoint): r"""This method calls the metpy.calc function equivalent_potential_temperature which takes the pint.Quantity objects containing the isobaric level value and the temperature at that level and, assuming saturated water vapor, produces the corresponding equivalent potential temperature with the reference pressure being 1000 millibars. """ #eqpotemp = calc.equivalent_potential_temperature(pressure, temperature, dewpoint) return calc.equivalent_potential_temperature(pressure, temperature, dewpoint)
def calc_fronts(u, v, q, t, lon, lat, date_list): ''' Parse era5 variables to kinematics(), to calculate various thermal and kinematic front parameters. 12 are computed, but for brevity, only four are returned for now. ''' #Using MetPy, derive equivalent potential temperature ta_unit = units.units.K * t dp_unit = mpcalc.dewpoint_from_specific_humidity( q * units.units.dimensionless, ta_unit, 850 * units.units.hectopascals) thetae = np.array( mpcalc.equivalent_potential_temperature(850 * units.units.hectopascals, ta_unit, dp_unit)) #From the lat-lon information accompanying the ERA5 data, resconstruct 2d coordinates and grid spacing (dx, dy) x, y = np.meshgrid(lon, lat) dx, dy = mpcalc.lat_lon_grid_deltas(x, y) #Derive various kinematic/thermal diagnostics for each time step kinemats = [ kinematics(u[i], v[i], thetae[i], dx, dy, y, smooth=True, sigma=2) for i in np.arange(len(date_list)) ] F = [kinemats[i][0] for i in np.arange(len(date_list)) ] #Frontogenesis function (degC / 100 km / 3 hr) Fn = [kinemats[i][1] for i in np.arange(len(date_list)) ] #Frontogenetical function (deg C / 100 km / 3 hr) Fs = [kinemats[i][2] for i in np.arange(len(date_list)) ] #Rotational component of frontogensis (deg C/ 100 km / 3 hr) icon = [kinemats[i][3] for i in np.arange(len(date_list)) ] #Instantaneous contraction rate (s^-1 * 1e5) vgt = [kinemats[i][4] for i in np.arange(len(date_list)) ] #Horizontal velovity gradient tensor magnitude (s^-1 * 1e5) conv = [kinemats[i][5] for i in np.arange(len(date_list))] #Convergence (s^-1 * 1e5) vo = [kinemats[i][6] for i in np.arange(len(date_list))] #Relative vorticity (s^-1 * 1e5) tfp = [kinemats[i][7] for i in np.arange(len(date_list)) ] #Thermal front parameter (km^-2) mag_te = [kinemats[i][8] for i in np.arange(len(date_list)) ] #Magnitude of theta-e gradient (100 km ^-1) v_f = [kinemats[i][9] for i in np.arange(len(date_list))] #Advection of TFP (m/s) thetae = [kinemats[i][10] for i in np.arange(len(date_list)) ] #Theta-e (K), may be smoothed depending on arguments cond = [kinemats[i][11] for i in np.arange(len(date_list))] #Extra condition return [thetae, mag_te, tfp, v_f]
def compute_thetae(dset, tvar='t', rvar='r'): rh = mpcalc.dewpoint_from_relative_humidity(dset['t'], dset['r'] / 100.) theta_e = mpcalc.equivalent_potential_temperature(850 * units.hPa, dset['t'], rh).to('degC') theta_e = xr.DataArray(theta_e.magnitude, coords=dset['t'].coords, attrs={ 'standard_name': 'Equivalent potential temperature', 'units': theta_e.units }, name='theta_e') return xr.merge([dset, theta_e])
def calc_thta_vir(united_data): """ returns virtual potential temperature (K) and equvalent potential temperaure (K) """ pres = united_data['PRES'] temp = united_data['TEMP'] rh = united_data['HUM'] mixing = mpcalc.mixing_ratio_from_relative_humidity(rh, temp, pres) theta_vir = mpcalc.virtual_potential_temperature(pres, temp, mixing) td = mpcalc.dewpoint_rh(temp, rh) theta_e = mpcalc.equivalent_potential_temperature(pres, temp, td) return theta_vir, theta_e
def main(): """In the main function we basically read the files and prepare the variables to be plotted. This is not included in utils.py as it can change from case to case.""" file = glob(input_file) print_message('Using file '+file[0]) dset = xr.open_dataset(file[0]) dset = dset.metpy.parse_cf() # Select 850 hPa level using metpy dset_850hpa = dset theta_e = mpcalc.equivalent_potential_temperature(850 * units.hPa, dset['t'].metpy.sel(vertical=850 * units.hPa), mpcalc.dewpoint_rh(dset['t'].metpy.sel(vertical=850 * units.hPa), dset['r'].metpy.sel(vertical=850 * units.hPa)/100.)).to(units.degC) mslp = dset['prmsl'].metpy.unit_array.to('hPa') lon, lat = get_coordinates(dset) time = pd.to_datetime(dset.time.values) cum_hour=np.array((time-time[0]) / pd.Timedelta('1 hour')).astype("int") levels_thetae = np.arange(-25., 75., 1.) levels_mslp = np.arange(mslp.min().astype("int"), mslp.max().astype("int"), 7.) for projection in projections:# This works regardless if projections is either single value or array fig = plt.figure(figsize=(figsize_x, figsize_y)) ax = plt.gca() m, x, y =get_projection(lon, lat, projection) # Create a mask to retain only the points inside the globe # to avoid a bug in basemap and a problem in matplotlib mask = np.logical_or(x<1.e20, y<1.e20) x = np.compress(mask,x) y = np.compress(mask,y) # Parallelize the plotting by dividing into chunks and processes # All the arguments that need to be passed to the plotting function args=dict(m=m, x=x, y=y, ax=ax, theta_e=np.compress(mask, theta_e, axis=1), mslp=np.compress(mask, mslp, axis=1), levels_thetae=levels_thetae,levels_mslp=levels_mslp, time=time, projection=projection, cum_hour=cum_hour) print_message('Pre-processing finished, launching plotting scripts') if debug: plot_files(time[1:2], **args) else: # Parallelize the plotting by dividing into chunks and processes dates = chunks(time, chunks_size) plot_files_param=partial(plot_files, **args) p = Pool(processes) p.map(plot_files_param, dates)
def eqpt_approx(p, t, q): """ Computes equivalent potential temperature in [K] from pressure, temperature and specific humidity. Arguments: p -- pressure in [Pa] t -- temperature in [K] q -- specific humidity in [kg/kg] p, t and q can be scalars or NumPy arrays. Returns: equivalent potential temperature in [K]. """ return mpcalc.equivalent_potential_temperature( units.Pa * p, units.K * t, mpcalc.dewpoint_from_specific_humidity(units.Pa * p, units.K * t, q)).to("K").m
def eqpt_approx(p, t, q): """ Computes equivalent potential temperature in [K] from pressure, temperature and specific humidity. Arguments: p -- pressure in [Pa] t -- temperature in [K] q -- specific humidity in [kg/kg] p, t and q can be scalars or NumPy arrays. Returns: equivalent potential temperature in [K]. Same dimensions as the inputs. """ p = units.Quantity(p, "Pa") t = units.Quantity(t, "K") dew_temp = mpcalc.dewpoint_from_specific_humidity(p, t, q) eqpt_temp = mpcalc.equivalent_potential_temperature(p, t, dew_temp) return eqpt_temp.to('K').magnitude
def main(): load_start = dt.datetime.now() #Try parsing arguments using argparse parser = argparse.ArgumentParser( description='wrf non-parallel convective diagnostics processer') parser.add_argument("-m", help="Model name", required=True) parser.add_argument("-r", help="Region name (default is aus)", default="aus") parser.add_argument("-t1", help="Time start YYYYMMDDHH", required=True) parser.add_argument("-t2", help="Time end YYYYMMDDHH", required=True) parser.add_argument( "-e", help= "CMIP5 experiment name (not required if using era5, erai or barra)", default="") parser.add_argument( "--barpa_forcing_mdl", help="BARPA forcing model (erai or ACCESS1-0). Default erai.", default="erai") parser.add_argument( "--ens", help="CMIP5 ensemble name (not required if using era5, erai or barra)", default="r1i1p1") parser.add_argument("--group", help="CMIP6 modelling group name", default="") parser.add_argument("--project", help="CMIP6 modelling intercomparison project", default="CMIP") parser.add_argument("--ver6hr", help="Version on al33 for 6hr data", default="") parser.add_argument("--ver3hr", help="Version on al33 for 3hr data", default="") parser.add_argument("--issave", help="Save output (True or False, default is False)", default="False") parser.add_argument( "--ub4", help= "Where to get era5 data. Default True for ub4 project, otherwise rt52", default="True") parser.add_argument( "--outname", help= "Name of saved output. In the form *outname*_*t1*_*t2*.nc. Default behaviour is the model name", default=None) parser.add_argument( "--is_dcape", help="Should DCAPE be calculated? (1 or 0. Default is 1)", default=1) parser.add_argument( "--al33", help= "Should data be gathered from al33? Default is False, and data is gathered from r87. If True, then group is required", default="False") parser.add_argument( "--delta_t", help= "Time step spacing for ERA5 data, in hours. Default is one the minimum spacing (1 hour)", default="1") parser.add_argument( "--era5_interp", help= "Horizontally interpolate model data before calculating convective parameters", default="False") args = parser.parse_args() #Parse arguments from cmd line and set up inputs (date region model) model = args.m region = args.r t1 = args.t1 t2 = args.t2 issave = args.issave ub4 = args.ub4 al33 = args.al33 if args.outname == None: out_name = model else: out_name = args.outname is_dcape = args.is_dcape barpa_forcing_mdl = args.barpa_forcing_mdl experiment = args.e ensemble = args.ens group = args.group project = args.project ver6hr = args.ver6hr ver3hr = args.ver3hr delta_t = int(args.delta_t) era5_interp = args.era5_interp if region == "sa_small": start_lat = -38 end_lat = -26 start_lon = 132 end_lon = 142 elif region == "aus": start_lat = -44.525 end_lat = -9.975 start_lon = 111.975 end_lon = 156.275 elif region == "global": start_lat = -70 end_lat = 70 start_lon = -180 end_lon = 179.75 else: raise ValueError("INVALID REGION\n") domain = [start_lat, end_lat, start_lon, end_lon] try: time = [ dt.datetime.strptime(t1, "%Y%m%d%H"), dt.datetime.strptime(t2, "%Y%m%d%H") ] except: raise ValueError("INVALID START OR END TIME. SHOULD BE YYYYMMDDHH\n") if era5_interp == "True": era5_interp = True elif era5_interp == "False": era5_interp = False else: raise ValueError("\n INVALID era5_interp...SHOULD BE True OR False") if ub4 == "True": ub4 = True elif ub4 == "False": ub4 = False else: raise ValueError("\n INVALID ub4...SHOULD BE True OR False") if issave == "True": issave = True elif issave == "False": issave = False else: raise ValueError("\n INVALID ISSAVE...SHOULD BE True OR False") if al33 == "True": al33 = True elif al33 == "False": al33 = False else: raise ValueError("\n INVALID al33...SHOULD BE True OR False") #Load data print("LOADING DATA...") if model == "erai": ta,temp1,hur,hgt,terrain,p,ps,wap,ua,va,uas,vas,tas,ta2d,\ cp,tp,wg10,mod_cape,lon,lat,date_list = \ read_erai(domain,time) cp = cp.astype("float32", order="C") tp = tp.astype("float32", order="C") mod_cape = mod_cape.astype("float32", order="C") elif model == "era5": if ub4: ta,temp1,hur,hgt,terrain,p,ps,ua,va,uas,vas,tas,ta2d,\ cp,wg10,mod_cape,lon,lat,date_list = \ read_era5(domain,time,delta_t=delta_t) else: ta,temp1,hur,hgt,terrain,p,ps,ua,va,uas,vas,tas,ta2d,\ cp,tp,wg10,mod_cape,lon,lat,date_list = \ read_era5_rt52(domain,time,delta_t=delta_t) cp = cp.astype("float32", order="C") tp = tp.astype("float32", order="C") mod_cape = mod_cape.astype("float32", order="C") wap = np.zeros(hgt.shape) elif model == "barra": ta,temp1,hur,hgt,terrain,p,ps,wap,ua,va,uas,vas,tas,ta2d,wg10,lon,lat,date_list = \ read_barra(domain,time) elif model == "barra_fc": ta,temp1,hur,hgt,terrain,p,ps,wap,ua,va,uas,vas,tas,ta2d,wg10,lon,lat,date_list = \ read_barra_fc(domain,time) elif model == "barpa": ta,hur,hgt,terrain,p,ps,ua,va,uas,vas,tas,ta2d,wg10,lon,lat,date_list = \ read_barpa(domain, time, experiment, barpa_forcing_mdl, ensemble) wap = np.zeros(hgt.shape) temp1 = None elif model == "barra_ad": wg10,temp2,ta,temp1,hur,hgt,terrain,p,ps,wap,ua,va,uas,vas,tas,ta2d,lon,lat,date_list = \ read_barra_ad(domain, time, False) elif model in ["ACCESS1-0","ACCESS1-3","GFDL-CM3","GFDL-ESM2M","CNRM-CM5","MIROC5",\ "MRI-CGCM3","IPSL-CM5A-LR","IPSL-CM5A-MR","GFDL-ESM2G","bcc-csm1-1","MIROC-ESM",\ "BNU-ESM"]: #Check that t1 and t2 are in the same year year = np.arange(int(t1[0:4]), int(t2[0:4]) + 1) ta, hur, hgt, terrain, p_3d, ps, ua, va, uas, vas, tas, ta2d, tp, lon, lat, \ date_list = read_cmip(model, experiment, \ ensemble, year, domain, cmip_ver=5, al33=al33, group=group, ver6hr=ver6hr, ver3hr=ver3hr) wap = np.zeros(hgt.shape) wg10 = np.zeros(ps.shape) mod_cape = np.zeros(ps.shape) p = np.zeros(p_3d[0, :, 0, 0].shape) #date_list = pd.to_datetime(date_list).to_pydatetime() temp1 = None tp = tp.astype("float32", order="C") elif model in ["ACCESS-ESM1-5", "ACCESS-CM2"]: year = np.arange(int(t1[0:4]), int(t2[0:4]) + 1) ta, hur, hgt, terrain, p_3d, ps, ua, va, uas, vas, tas, ta2d, lon, lat, \ date_list = read_cmip(model, experiment,\ ensemble, year, domain, cmip_ver=6, group=group, project=project) wap = np.zeros(hgt.shape) wg10 = np.zeros(ps.shape) p = np.zeros(p_3d[0, :, 0, 0].shape) #date_list = pd.to_datetime(date_list).to_pydatetime() temp1 = None else: raise ValueError("Model not recognised") del temp1 ta = ta.astype("float32", order="C") hur = hur.astype("float32", order="C") hgt = hgt.astype("float32", order="C") terrain = terrain.astype("float32", order="C") p = p.astype("float32", order="C") ps = ps.astype("float32", order="C") wap = wap.astype("float32", order="C") ua = ua.astype("float32", order="C") va = va.astype("float32", order="C") uas = uas.astype("float32", order="C") vas = vas.astype("float32", order="C") tas = tas.astype("float32", order="C") ta2d = ta2d.astype("float32", order="C") wg10 = wg10.astype("float32", order="C") lon = lon.astype("float32", order="C") lat = lat.astype("float32", order="C") gc.collect() param = np.array([ "mu_cape", "mu_cin", "muq", "s06", "s0500", "lr700_500", "mhgt", "ta500", "tp" ]) if model in ["erai", "era5"]: param = np.concatenate([param, ["mod_cape"]]) #Option to interpolate to the ERA5 grid if era5_interp: #Interpolate model data to the ERA5 grid from era5_read import get_lat_lon_rt52 as get_era5_lat_lon era5_lon, era5_lat = get_era5_lat_lon() era5_lon_ind = np.where((era5_lon >= domain[2]) & (era5_lon <= domain[3]))[0] era5_lat_ind = np.where((era5_lat >= domain[0]) & (era5_lat <= domain[1]))[0] era5_lon = era5_lon[era5_lon_ind] era5_lat = era5_lat[era5_lat_ind] terrain = interp_era5(terrain, lon, lat, era5_lon, era5_lat, d3=False) #Set output array output_data = np.zeros( (ps.shape[0], era5_lat.shape[0], era5_lon.shape[0], len(param))) else: output_data = np.zeros( (ps.shape[0], ps.shape[1], ps.shape[2], len(param))) #Assign p levels to a 3d array, with same dimensions as input variables (ta, hgt, etc.) #If the 3d p-lvl array already exists, then declare the variable "mdl_lvl" as true. try: p_3d mdl_lvl = True full_p3d = p_3d except: mdl_lvl = False if era5_interp: p_3d = np.moveaxis(np.tile(p,[ta.shape[2],ta.shape[3],1]),[0,1,2],[1,2,0]).\ astype(np.float32) else: p_3d = np.moveaxis(np.tile(p,[era5_lat.shape[0],era5_lon.shape[0],1]),[0,1,2],[1,2,0]).\ astype(np.float32) print("LOAD TIME..." + str(dt.datetime.now() - load_start)) tot_start = dt.datetime.now() for t in np.arange(0, ta.shape[0]): cape_start = dt.datetime.now() if era5_interp: ta_t = interp_era5(ta[t], lon, lat, era5_lon, era5_lat, d3=True) hur_t = interp_era5(hur[t], lon, lat, era5_lon, era5_lat, d3=True) hgt_t = interp_era5(hgt[t], lon, lat, era5_lon, era5_lat, d3=True) ps_t = interp_era5(ps[t], lon, lat, era5_lon, era5_lat, d3=False) wap_t = interp_era5(wap[t], lon, lat, era5_lon, era5_lat, d3=True) ua_t = interp_era5(ua[t], lon, lat, era5_lon, era5_lat, d3=True) va_t = interp_era5(va[t], lon, lat, era5_lon, era5_lat, d3=True) uas_t = interp_era5(uas[t], lon, lat, era5_lon, era5_lat, d3=False) vas_t = interp_era5(vas[t], lon, lat, era5_lon, era5_lat, d3=False) tas_t = interp_era5(tas[t], lon, lat, era5_lon, era5_lat, d3=False) ta2d_t = interp_era5(ta2d[t], lon, lat, era5_lon, era5_lat, d3=False) tp_t = interp_era5(tp[t], lon, lat, era5_lon, era5_lat, d3=False) mod_cape_t = interp_era5(mod_cape[t], lon, lat, era5_lon, era5_lat, d3=False) else: ta_t = ta[t] hur_t = hur[t] hgt_t = hgt[t] ps_t = ps[t] wap_t = wap[t] ua_t = ua[t] va_t = va[t] uas_t = uas[t] vas_t = vas[t] tas_t = tas[t] ta2d_t = ta2d[t] tp_t = tp[t] mod_cape_t = mod_cape[t] print(date_list[t]) output = np.zeros((1, ps_t.shape[0], ps_t.shape[1], len(param))) if mdl_lvl: if era5_interp: p_3d = interp_era5(full_p3d[t], lon, lat, era5_lon, era5_lat, d3=True) else: p_3d = full_p3d[t] dp = get_dp(hur=hur_t, ta=ta_t, dp_mask=False) #Insert surface arrays, creating new arrays with "sfc" prefix sfc_ta = np.insert(ta_t, 0, tas_t, axis=0) sfc_hgt = np.insert(hgt_t, 0, terrain, axis=0) sfc_dp = np.insert(dp, 0, ta2d_t, axis=0) sfc_p_3d = np.insert(p_3d, 0, ps_t, axis=0) sfc_ua = np.insert(ua_t, 0, uas_t, axis=0) sfc_va = np.insert(va_t, 0, vas_t, axis=0) sfc_wap = np.insert(wap_t, 0, np.zeros(vas_t.shape), axis=0) #Sort by ascending p a,temp1,temp2 = np.meshgrid(np.arange(sfc_p_3d.shape[0]) , np.arange(sfc_p_3d.shape[1]),\ np.arange(sfc_p_3d.shape[2])) sort_inds = np.flip(np.lexsort([np.swapaxes(a, 1, 0), sfc_p_3d], axis=0), axis=0) sfc_hgt = np.take_along_axis(sfc_hgt, sort_inds, axis=0) sfc_dp = np.take_along_axis(sfc_dp, sort_inds, axis=0) sfc_p_3d = np.take_along_axis(sfc_p_3d, sort_inds, axis=0) sfc_ua = np.take_along_axis(sfc_ua, sort_inds, axis=0) sfc_va = np.take_along_axis(sfc_va, sort_inds, axis=0) sfc_ta = np.take_along_axis(sfc_ta, sort_inds, axis=0) #Calculate q and wet bulb for pressure level arrays with surface values sfc_ta_unit = units.units.degC * sfc_ta sfc_dp_unit = units.units.degC * sfc_dp sfc_p_unit = units.units.hectopascals * sfc_p_3d hur_unit = mpcalc.relative_humidity_from_dewpoint(ta_t*units.units.degC, dp*units.units.degC)*\ 100*units.units.percent q_unit = mpcalc.mixing_ratio_from_relative_humidity(hur_unit,\ ta_t*units.units.degC,np.array(p_3d)*units.units.hectopascals) sfc_hur_unit = mpcalc.relative_humidity_from_dewpoint(sfc_ta_unit, sfc_dp_unit)*\ 100*units.units.percent sfc_q_unit = mpcalc.mixing_ratio_from_relative_humidity(sfc_hur_unit,\ sfc_ta_unit,sfc_p_unit) sfc_theta_unit = mpcalc.potential_temperature(sfc_p_unit, sfc_ta_unit) sfc_thetae_unit = mpcalc.equivalent_potential_temperature( sfc_p_unit, sfc_ta_unit, sfc_dp_unit) sfc_thetae = np.array(mpcalc.equivalent_potential_temperature(ps_t*units.units.hectopascals,tas_t*units.units.degC,\ ta2d_t*units.units.degC)) sfc_q = np.array(sfc_q_unit) sfc_hur = np.array(sfc_hur_unit) #sfc_wb = np.array(wrf.wetbulb( sfc_p_3d*100, sfc_ta+273.15, sfc_q, units="degC")) #Use getcape.f90 #cape_gb_mu1, cape_gb_mu4 = getcape_driver(sfc_p_3d, sfc_ta, sfc_dp, ps_t) #Now get most-unstable CAPE (max CAPE in vertical, ensuring parcels used are AGL) cape3d = wrf.cape_3d(sfc_p_3d,sfc_ta+273.15,\ sfc_q,sfc_hgt,\ terrain,ps_t,\ True,meta=False, missing=0) cape = cape3d.data[0] cin = cape3d.data[1] lfc = cape3d.data[2] lcl = cape3d.data[3] el = cape3d.data[4] #Mask values which are below the surface and above 350 hPa AGL cape[(sfc_p_3d > ps_t) | (sfc_p_3d < (ps_t - 350))] = np.nan cin[(sfc_p_3d > ps_t) | (sfc_p_3d < (ps_t - 350))] = np.nan lfc[(sfc_p_3d > ps_t) | (sfc_p_3d < (ps_t - 350))] = np.nan lcl[(sfc_p_3d > ps_t) | (sfc_p_3d < (ps_t - 350))] = np.nan el[(sfc_p_3d > ps_t) | (sfc_p_3d < (ps_t - 350))] = np.nan #Get maximum (in the vertical), and get cin, lfc, lcl for the same parcel mu_cape_inds = np.tile(np.nanargmax(cape, axis=0), (cape.shape[0], 1, 1)) mu_cape = np.take_along_axis(cape, mu_cape_inds, 0)[0] mu_cin = np.take_along_axis(cin, mu_cape_inds, 0)[0] mu_lfc = np.take_along_axis(lfc, mu_cape_inds, 0)[0] mu_lcl = np.take_along_axis(lcl, mu_cape_inds, 0)[0] mu_el = np.take_along_axis(el, mu_cape_inds, 0)[0] muq = np.take_along_axis(sfc_q, mu_cape_inds, 0)[0] * 1000 #Calculate other parameters #Thermo thermo_start = dt.datetime.now() lr700_500 = get_lr_p(ta_t, p_3d, hgt_t, 700, 500) melting_hgt = get_t_hgt(sfc_ta, np.copy(sfc_hgt), 0, terrain) melting_hgt = np.where((melting_hgt < 0) | (np.isnan(melting_hgt)), 0, melting_hgt) ta500 = get_var_p_lvl(np.copy(sfc_ta), sfc_p_3d, 500) ta925 = get_var_p_lvl(np.copy(sfc_ta), sfc_p_3d, 925) ta850 = get_var_p_lvl(np.copy(sfc_ta), sfc_p_3d, 850) ta700 = get_var_p_lvl(np.copy(sfc_ta), sfc_p_3d, 700) rho = mpcalc.density( np.array(sfc_p_3d) * (units.units.hectopascal), sfc_ta * units.units.degC, sfc_q_unit) rho925 = np.array(get_var_p_lvl(np.array(rho), sfc_p_3d, 925)) rho850 = np.array(get_var_p_lvl(np.array(rho), sfc_p_3d, 850)) rho700 = np.array(get_var_p_lvl(np.array(rho), sfc_p_3d, 700)) #Winds winds_start = dt.datetime.now() s06 = get_shear_hgt(sfc_ua, sfc_va, np.copy(sfc_hgt), 0, 6000, terrain) s0500 = get_shear_p(ua_t, va_t, p_3d, "sfc", np.array([500]), p_3d, uas=uas_t, vas=vas_t)[0] #WAP if model in ["erai", "era5"]: sfc_w = mpcalc.vertical_velocity( wap_t * (units.units.pascal / units.units.second),\ np.array(p_3d) * (units.units.hectopascal), \ ta_t * units.units.degC, q_unit) w925 = np.array(get_var_p_lvl(np.array(sfc_w), p_3d, 925)) w850 = np.array(get_var_p_lvl(np.array(sfc_w), p_3d, 850)) w700 = np.array(get_var_p_lvl(np.array(sfc_w), p_3d, 700)) #Convergence if era5_interp: x, y = np.meshgrid(era5_lon, era5_lat) else: x, y = np.meshgrid(lon, lat) dx, dy = mpcalc.lat_lon_grid_deltas(x, y) u925 = np.array(get_var_p_lvl(np.copy(sfc_ua), sfc_p_3d, 925)) u850 = np.array(get_var_p_lvl(np.copy(sfc_ua), sfc_p_3d, 850)) u700 = np.array(get_var_p_lvl(np.copy(sfc_ua), sfc_p_3d, 700)) v925 = np.array(get_var_p_lvl(np.copy(sfc_va), sfc_p_3d, 925)) v850 = np.array(get_var_p_lvl(np.copy(sfc_va), sfc_p_3d, 850)) v700 = np.array(get_var_p_lvl(np.copy(sfc_va), sfc_p_3d, 700)) conv925 = -1e5 * np.array( mpcalc.divergence(u925 * (units.units.meter / units.units.second), v925 * (units.units.meter / units.units.second), dx, dy)) conv850 = -1e5 * np.array( mpcalc.divergence(u850 * (units.units.meter / units.units.second), v850 * (units.units.meter / units.units.second), dx, dy)) conv700 = -1e5 * np.array( mpcalc.divergence(u700 * (units.units.meter / units.units.second), v700 * (units.units.meter / units.units.second), dx, dy)) #CS6 mucs6 = mu_cape * np.power(s06, 1.67) #Fill output output = fill_output(output, t, param, ps, "mu_cape", mu_cape) output = fill_output(output, t, param, ps, "mu_cin", mu_cin) output = fill_output(output, t, param, ps, "muq", muq) output = fill_output(output, t, param, ps, "s06", s06) output = fill_output(output, t, param, ps, "s0500", s0500) output = fill_output(output, t, param, ps, "lr700_500", lr700_500) output = fill_output(output, t, param, ps, "ta500", ta500) output = fill_output(output, t, param, ps, "mhgt", melting_hgt) output = fill_output(output, t, param, ps, "tp", tp_t) if (model == "erai") | (model == "era5"): output = fill_output(output, t, param, ps, "mod_cape", mod_cape_t) output_data[t] = output print("SAVING DATA...") param_out = [] for param_name in param: temp_data = output_data[:, :, :, np.where(param == param_name)[0][0]] param_out.append(temp_data) #If the mhgt variable is zero everywhere, then it is likely that data has not been read. #In this case, all values are missing, set to zero. for t in np.arange(param_out[0].shape[0]): if param_out[np.where(param == "mhgt")[0][0]][t].max() == 0: for p in np.arange(len(param_out)): param_out[p][t] = np.nan if issave: if era5_interp: save_netcdf(region, model, out_name, date_list, era5_lat, era5_lon, param, param_out, \ out_dtype = "f4", compress=True) else: save_netcdf(region, model, out_name, date_list, lat, lon, param, param_out, \ out_dtype = "f4", compress=True) print(dt.datetime.now() - tot_start)
def test_equivalent_potential_temperature(): """Test equivalent potential temperature calculation.""" p = 999. * units.mbar t = 288. * units.kelvin ept = equivalent_potential_temperature(p, t) assert_almost_equal(ept, 315.9548 * units.kelvin, 3)
if __name__ == '__main__': temp = [0, 5, 10, 15, 20, 25] rh = [100, 100, 100, 100, 100, 100] pres = [850, 850, 850, 850, 850, 850] df = pd.DataFrame({'Temp.': temp, 'Humidity': rh, 'Pressure': pres}) print(df) print(df['Temp.'].values * units('deg')) print(df['Humidity'].values / 100.) print(df['Pressure'].values * 100.) # 露点温度の算出 dewpoint = dewpoint_from_relative_humidity( (df['Temp.'].values * units('degC')).to(units('K')), df['Humidity'].values / 100.) print('##### 露点温度 #####') print(dewpoint) print(dewpoint.to(units('K'))) # 相当温位の算出 potensial_temp = equivalent_potential_temperature( df['Pressure'].values * units('hPa'), (df['Temp.'].values * units('degC')).to(units('K')), dewpoint.to(units('K'))) print('##### 相当温位 #####') print(potensial_temp) # 'dewpoint': dewpoint_rh( (np.array(temp) * units('degC') ).to(units('K') ), # np.array(rh) / 100.).to(units('degF')),
def getData(model, station, time, fileExport=False, exportPath=''): df = getDataFrame_UpperAir(model, station, time, 0) try: # Verify data found df.head print(f'Reading {model} profile for {station} valid {time}') except: print( f'ERROR reading {model} profile for {station} valid {time}. No data found' ) return None if station == 'LO1': plot = SkewT.drawSkewT([model, time, 0, station, df], 10, 10, 100, True, 250, True, False, False, True, True) plotPath = exportPath.replace('data/BUFKIT', 'plots/SkewT') plotPath = plotPath.replace( '.csv', time.strftime("_SkewT_%Y%m%d_%H%M") + '.png') plot.savefig(plotPath, bbox_inches='tight') pblHeight = 0 dgzLayer = [-999, -999] desiredLevels = [[925.00 * units.hPa, False], [850.00 * units.hPa, False], [700.00 * units.hPa, False], [500.00 * units.hPa, False]] dataString = f'{model},{station},{time}' z = df['height'].values p = df['pressure'].values T = df['temperature'].values Td = df['dewpoint'].values theta = df['theta'].values theta_e = df['theta_e'].values u = df['u_wind'].values v = df['v_wind'].values for i in range(len(z)): if i > 0: # Calculate temperature lapse-rate dT = T[i] - T[i - 1] dz = (z[i] - z[i - 1]).to('km') dT_dz = dT / dz # Calculate dewpoint lapse-rate dTd = Td[i] - Td[i - 1] dTd_dz = dTd / dz # Calculate potential temperature lapse-rate thetaLwr = mpcalc.potential_temperature(p[i - 1], T[i - 1]) thetaUpr = mpcalc.potential_temperature(p[i], T[i]) dTheta_dz = (thetaUpr - thetaLwr) / dz # Calculate equivalent potential temperature lapse-rate theta_eLwr = mpcalc.equivalent_potential_temperature( p[i - 1], T[i - 1], Td[i - 1]) theta_eUpr = mpcalc.equivalent_potential_temperature( p[i], T[i], Td[i]) dThetaE_dz = (theta_eUpr - theta_eLwr) / dz #print(p[i], z[i], dT_dz, dTd_dz, dTheta_dz, dThetaE_dz) # Find PBL height # Look for where (dT/dz >= -9.8 and dθ/dz >= 0) or (dθ/dz >= 0.0 and dθ-e/dz >= 2) if (((dT_dz.magnitude >= -5.7) and (dTheta_dz.magnitude >= 0.0)) or ((dTheta_dz.magnitude >= 0.0) and (dThetaE_dz.magnitude >= 2.0))) and pblHeight == 0: pblHeight = z[i] #print('*****', p[i], z[i], dT_dz, dTheta_dz, dThetaE_dz) # Find DGZ layer if (-18.0 <= T[i].magnitude <= -12.0): # Update lower bound if not set if dgzLayer[0] == -999: dgzLayer[0] = p[i] # Update upper bound dgzLayer[1] = p[i] # Extract values at desired levels for dataLevel in desiredLevels: if (p[i - 1] >= dataLevel[0]) and ( p[i] <= dataLevel[0]) and dataLevel[1] == False: # Interpolate values to data level tmpc = LinearInterpolation(dataLevel[0], p[i - 1], p[i], T[i - 1], T[i]) dwpc = LinearInterpolation(dataLevel[0], p[i - 1], p[i], Td[i - 1], Td[i]) hght = LinearInterpolation(dataLevel[0], p[i - 1], p[i], z[i - 1], z[i]) # RH from dewpoint relh = mpcalc.relative_humidity_from_dewpoint( tmpc, dwpc).to('percent') # Calculate wind vector and interpolate values to data level uwnd = LinearInterpolation(dataLevel[0], p[i - 1], p[i], u[i - 1], u[i]) vwnd = LinearInterpolation(dataLevel[0], p[i - 1], p[i], v[i - 1], v[i]) # Wind speed/direction from u,v drct = mpcalc.wind_direction(uwnd, vwnd) sknt = mpcalc.wind_speed(uwnd, vwnd) # Output values dataString += f',{round(hght.magnitude, 2)},{round(tmpc.magnitude, 2)},{round(relh.magnitude, 2)},{round(uwnd.magnitude, 2)},{round(vwnd.magnitude, 2)}' dataLevel[1] = True # Derived quantities #dataString+=f',{round(pblHeight.magnitude, 2)}' # Go to next level i += 1 # Export to file if fileExport and exportPath != '': file = open(exportPath, 'a+') file.write(dataString + '\n') file.close() dataString = ''
def metpy_read_wrf_cross(fname, plevels, tidx_in, lons_out, lats_out, start, end): ds = xr.open_dataset(fname).metpy.parse_cf().squeeze() ds = ds.isel(Time=tidx) print(ds) ds1 = xr.Dataset() p = units.Quantity(to_np(ds.p), 'hPa') z = units.Quantity(to_np(ds.z), 'meter') u = units.Quantity(to_np(ds.u), 'm/s') v = units.Quantity(to_np(ds.v), 'm/s') w = units.Quantity(to_np(ds.w), 'm/s') tk = units.Quantity(to_np(ds.tk), 'kelvin') th = units.Quantity(to_np(ds.th), 'kelvin') eth = units.Quantity(to_np(ds.eth), 'kelvin') wspd = units.Quantity(to_np(ds.wspd), 'm/s') omega = units.Quantity(to_np(ds.omega), 'Pa/s') plevels_unit = plevels * units.hPa z, u, v, w, tk, th, eth, wspd, omega = log_interpolate_1d(plevels_unit, p, z, u, v, w, tk, th, eth, wspd, omega, axis=0) coords, dims = [plevs, ds.lat.values, ds.lon.values], ["level", "lat", "lon"] for name, var in zip( ['z', 'u', 'v', 'w', 'tk', 'th', 'eth', 'wspd', 'omega'], [z, u, v, w, tk, th, eth, wspd, omega]): #g = ndimage.gaussian_filter(var, sigma=3, order=0) ds1[name] = xr.DataArray(to_np(mpcalc.smooth_n_point(var, 9)), coords=coords, dims=dims) dx, dy = mpcalc.lat_lon_grid_deltas(ds.lon.values * units('degrees_E'), ds.lat.values * units('degrees_N')) # Calculate temperature advection using metpy function for i, plev in enumerate(plevs): adv = mpcalc.advection(eth[i, :, :], [u[i, :, :], v[i, :, :]], (dx, dy), dim_order='yx') * units('K/sec') adv = ndimage.gaussian_filter(adv, sigma=3, order=0) * units('K/sec') ds1['eth_adv_{:03d}'.format(plev)] = xr.DataArray( np.array(adv), coords=[ds.lat.values, ds.lon.values], dims=["lat", "lon"]) div = mpcalc.divergence(u[i, :, :], v[i, :, :], dx, dy, dim_order='yx') div = ndimage.gaussian_filter(div, sigma=3, order=0) * units('1/sec') ds1['div_{:03d}'.format(plev)] = xr.DataArray( np.array(div), coords=[ds.lat.values, ds.lon.values], dims=["lat", "lon"]) ds1['accrain'] = xr.DataArray(ds.accrain.values, coords=[ds.lat.values, ds.lon.values], dims=["lat", "lon"]) eth2 = mpcalc.equivalent_potential_temperature( ds.slp.values * units.hPa, ds.t2m.values * units('K'), ds.td2.values * units('celsius')) ds1['eth2'] = xr.DataArray(eth2, coords=[ds.lat.values, ds.lon.values], dims=["lat", "lon"]) #ds1['sst'] = xr.DataArray(ndimage.gaussian_filter(ds.sst.values, sigma=3, order=0)-273.15, coords=[ds.lat.values,ds.lon.values], dims=["lat","lon"]) ds1 = ds1.metpy.parse_cf().squeeze() cross = cross_section(ds1, start, end).set_coords(('lat', 'lon')) cross.u.attrs['units'] = 'm/s' cross.v.attrs['units'] = 'm/s' cross['t_wind'], cross['n_wind'] = mpcalc.cross_section_components( cross['u'], cross['v']) weights = np.cos(np.deg2rad(ds.lat)) ds_weighted = ds.weighted(weights) weighted = ds_weighted.mean(("lat")) return ds1, cross, weighted
dim_order='yx') * units('K/sec') PT850 = mpcalc.potential_temperature(850 * units.mbar, T850) FRONT_850 = mpcalc.frontogenesis(PT850, U850, V850, DX, DY, dim_order='YX') # ============================================================================= # FIG #5: 850: GEOPOTENTIAL HEIGHT, EQUIV. POT. TEMP, WINDS, LAPSE RATES # ============================================================================= H500 = HGT_DATA.variables['hgt'][TIME_INDEX, 5, :, :] H700 = HGT_DATA.variables['hgt'][TIME_INDEX, 3, :, :] T500 = AIR_DATA.variables['air'][TIME_INDEX, 5, :, :] * units('degC') T700 = AIR_DATA.variables['air'][TIME_INDEX, 3, :, :] * units('degC') LR = -1000 * (T500 - T700) / (H500 - H700) H850 = HGT_DATA.variables['hgt'][TIME_INDEX, 2, :, :] T850 = AIR_DATA.variables['air'][TIME_INDEX, 2, :, :] * units('kelvin') SH850 = SHUM_DATA.variables['shum'][TIME_INDEX, 2, :, :] DP850 = mpcalc.dewpoint_from_specific_humidity(SH850, T850, 850 * units.mbar) EPT850 = mpcalc.equivalent_potential_temperature(850 * units.mbar, T850, DP850) # ============================================================================= # FIG #6: 925: MOISTURE FLUX, MOISTURE FLUX CONVERGENCE, # ============================================================================= RH925 = HUM_DATA.variables['rhum'][TIME_INDEX, 1, :, :] SH925 = SHUM_DATA.variables['shum'][TIME_INDEX, 1, :, :] U925 = UWND_DATA.variables['uwnd'][TIME_INDEX, 1, :, :] * units('m/s') V925 = VWND_DATA.variables['vwnd'][TIME_INDEX, 1, :, :] * units('m/s') H925 = HGT_DATA.variables['hgt'][TIME_INDEX, 1, :, :] SH_ADV925 = mpcalc.advection(SH925, [U925, V925], (DX, DY), dim_order='yx') SH_DIV925 = SH925 * (mpcalc.divergence(U925, V925, DX, DY, dim_order='YX')) MFLUXX = SH925 * U925 MFLUXY = SH925 * V925 MFC_925 = SH_ADV925 + SH_DIV925 # ============================================================================= # FIG #7: SFC: MSLP, WIND, TEMPERATURE
def process_skewt(self): # Calculation index_p100 = get_pressure_level_index(self.p_i, 100) lcl_p, lcl_t = mpcalc.lcl(self.p_i[0], self.t_i[0], self.td_i[0]) lfc_p, lfc_t = mpcalc.lfc(self.p_i, self.t_i, self.td_i) el_p, el_t = mpcalc.el(self.p_i, self.t_i, self.td_i) prof = mpcalc.parcel_profile(self.p_i, self.t_i[0], self.td_i[0]).to('degC') cape, cin = mpcalc.cape_cin(self.p_i, self.t_i, self.td_i, prof) mucape, mucin = mpcalc.most_unstable_cape_cin(self.p_i, self.t_i, self.td_i) pwat = mpcalc.precipitable_water(self.td_i, self.p_i) i8 = get_pressure_level_index(self.p_i, 850) i7 = get_pressure_level_index(self.p_i, 700) i5 = get_pressure_level_index(self.p_i, 500) theta850 = mpcalc.equivalent_potential_temperature(850 * units('hPa'), self.t_i[i8], self.td_i[i5]) theta500 = mpcalc.equivalent_potential_temperature(500 * units('hPa'), self.t_i[i5], self.td_i[i5]) thetadiff = theta850 - theta500 k = self.t_i[i8] - self.t_i[i5] + self.td_i[i8] - (self.t_i[i7] - self.td_i[i7]) a = ((self.t_i[i8] - self.t_i[i5]) - (self.t_i[i8] - self.td_i[i5]) - (self.t_i[i7] - self.td_i[i7]) - (self.t_i[i5] - self.td_i[i5])) sw = c_sweat(np.array(self.t_i[i8].magnitude), np.array(self.td_i[i8].magnitude), np.array(self.t_i[i5].magnitude), np.array(self.u_i[i8].magnitude), np.array(self.v_i[i8].magnitude), np.array(self.u_i[i5].magnitude), np.array(self.v_i[i5].magnitude)) si = showalter_index(self.t_i[i8], self.td_i[i8], self.t_i[i5]) li = lifted_index(self.t_i[0], self.td_i[0], self.p_i[0], self.t_i[i5]) srh_pos, srh_neg, srh_tot = mpcalc.storm_relative_helicity(self.u_i, self.v_i, self.alt, 1000 * units('m')) sbcape, sbcin = mpcalc.surface_based_cape_cin(self.p_i, self.t_i, self.td_i) shr6km = mpcalc.bulk_shear(self.p_i, self.u_i, self.v_i, heights=self.alt, depth=6000 * units('m')) wshr6km = mpcalc.wind_speed(*shr6km) sigtor = mpcalc.significant_tornado(sbcape, delta_height(self.p_i[0], lcl_p), srh_tot, wshr6km)[0] # Plotting self.ax.set_ylim(1050, 100) self.ax.set_xlim(-40, 50) self.plot(self.p_i, self.t_i, 'r', linewidth=1) self.plot(self.p_i[:self.dp_idx], self.td_i[:self.dp_idx], 'g', linewidth=1) self.plot_barbs(self.p_i[:index_p100], self.u_i[:index_p100] * 1.94, self.v_i[:index_p100] * 1.94) self.plot(lcl_p, lcl_t, 'ko', markerfacecolor='black') self.plot(self.p_i, prof, 'k', linewidth=2) if cin.magnitude < 0: chi = -1 * cin.magnitude self.shade_cin(self.p_i, self.t_i, prof) elif cin.magnitude > 0: chi = cin.magnitude self.shade_cin(self.p_i, self.t_i, prof) else: chi = 0. self.shade_cape(self.p_i, self.t_i, prof) self.plot_dry_adiabats(linewidth=0.5) self.plot_moist_adiabats(linewidth=0.5) self.plot_mixing_lines(linewidth=0.5) plt.title('Skew-T Plot \nStation: {} Time: {}'.format(self.st, self.time.strftime('%Y.%m.%d %H:%M')), fontsize=14, loc='left') # Add hodograph ax = self._fig.add_axes([0.95, 0.71, 0.17, 0.17]) h = Hodograph(ax, component_range=50) h.add_grid(increment=20) h.plot_colormapped(self.u_i[:index_p100], self.v_i[:index_p100], self.alt[:index_p100], linewidth=1.2) # Annotate parameters # Annotate names namelist = ['CAPE', 'CIN', 'MUCAPE', 'PWAT', 'K', 'A', 'SWEAT', 'LCL', 'LFC', 'EL', 'SI', 'LI', 'T850-500', 'θse850-500', 'SRH', 'STP'] xcor = -50 ycor = -90 spacing = -9 for nm in namelist: ax.text(xcor, ycor, '{}: '.format(nm), fontsize=10) ycor += spacing # Annotate values varlist = [cape, chi, mucape, pwat, k, a, sw, lcl_p, lfc_p, el_p, si, li, self.t_i[i8] - self.t_i[i5], thetadiff, srh_tot, sigtor] xcor = 10 ycor = -90 for v in varlist: if hasattr(v, 'magnitude'): v = v.magnitude ax.text(xcor, ycor, str(np.round_(v, 2)), fontsize=10) ycor += spacing # Annotate units unitlist = ['J/kg', 'J/kg', 'J/kg', 'mm', '°C', '°C', '', 'hPa', 'hPa', 'hPa', '°C', '°C', '°C', '°C'] xcor = 45 ycor = -90 for u in unitlist: ax.text(xcor, ycor, ' {}'.format(u), fontsize=10) ycor += spacing
def jp_850_eptw(self, path): # 850hPa相当温位/風(日本域) path_fig = os.path.join(path, self.time_str1 + '.jpg') if (os.path.exists(path_fig)): return # 850hPa気温の取得 temp, lat, lon = self.grib2_select_jp('t', 850) temp = temp * units.kelvin # 850hPa風の取得 wind_u, _, _ = self.grib2_select_jp('u', 850) * units('m/s') wind_v, _, _ = self.grib2_select_jp('v', 850) * units('m/s') # 850hPa相対湿度の取得 rh, _, _ = self.grib2_select_jp('r', 850) rh *= 0.01 # 露点温度の計算 dewp = mpcalc.dewpoint_from_relative_humidity(temp, rh) # 相当温位の計算 ept = mpcalc.equivalent_potential_temperature(850 * units.hPa, temp, dewp) ept = gaussian_filter(ept, sigma=1.0) # 地図の描画 fig, ax = self.draw_map(self.mapcrs_jp, self.extent_jp) # 等温線を引く ept_arange = np.arange(255, 372, 3) ept_constant = ax.contourf(lon, lat, ept, ept_arange, extend='both', cmap='jet', transform=self.datacrs, alpha=0.9) ept_line = ax.contour(lon, lat, ept, ept_arange, colors='black', linestyles='solid', linewidths=1, transform=self.datacrs) plt.clabel(ept_line, levels=np.arange(258, 372, 6), fmt='%d', fontsize=self.fontsize) # カラーバーをつける cbar = self.draw_jp_colorbar(ept_constant) cbar.set_label('E.P.TEMP(K)', fontsize=self.fontsize) # 風ベクトルの表示 wind_arrow = (slice(None, None, 5), slice(None, None, 5)) ax.barbs(lon[wind_arrow], lat[wind_arrow], wind_u[wind_arrow].to('kt').m, wind_v[wind_arrow].to('kt').m, pivot='middle', length=8, color='black', alpha=0.5, transform=self.datacrs) # タイトルをつける self.draw_title(ax, '850hPa: E.P.TEMP(K), WIND ARROW(kt)', self.time_str2) # 大きさの調整 plt.subplots_adjust(bottom=0.05, top=0.95, left=0, right=1.0) # 保存 print(f'[{self.time_str2}] 850hPa相当温位/風(日本域)...{path_fig}'.format()) plt.savefig(path_fig) # 閉じる plt.close(fig=fig)
def read_TInsitu(pname, print_long, e_test, tstart=None, tend=None, d_testing=False): ''' Reads data files provided on TORUS19 EOL site (Important that datafiles and filenames follow TORUS19 readme) --- INPUT: filename string (following readme conventions for each platform) tstart,tend: datetime objects OUTPUT: dataframe containing all data collected during desired times ''' if pname in pform_names('UNL'): mmfile = glob.glob(config.g_mesonet_directory+config.day+'/mesonets/UNL/UNL.'+pname+'.*') # Test Data availability if d_testing == True: try: #if there is no files this will will cause the try statement to fail mtest = mmfile[0] return True except: return False # if the defn was only called to it will exit at this point (saving computing time) # + + + + + + + + + + + + ++ + + data_hold = [] #empty list to append to for i in range(len(mmfile)): ds = xr.open_dataset(mmfile[i]) #convert form epoch time to utc datetime object timearray = np.array([dt.datetime.utcfromtimestamp(t/1e9) for t in ds.time.values]) U,V = mpcalc.wind_components(ds.wind_speed, ds.wind_dir) lats = np.array([40]) * units.degrees #create new xarray dataset to make plotting easier cause original is trash dims = ['datetime'] coords = { 'datetime': timearray } data_vars = { 'lat': (dims, ds.lat.values, {'units':str(lats.units)}), 'lon': (dims, ds.lon.values, {'units':str(lats.units)}), 'Z_ASL': (dims, ds.alt.values, {'units':str(ds.alt.units)}), 'Z_AGL': (dims, np.zeros_like(ds.alt.values), {'units':str(ds.alt.units)}), 'Temperature': (dims, ds.fast_temp.values, {'units':str(ds.fast_temp.units)}), 'Dewpoint': (dims, ds.dewpoint.values, {'units':str(ds.dewpoint.units)}), 'RH': (dims, ds.calc_corr_RH.values, {'units':str(ds.calc_corr_RH.units)}), 'Pressure': (dims, ds.pressure.values, {'units':str(ds.pressure.units)}), 'U': (dims, U.m, {'units':str(U.units)}), 'V': (dims, V.m, {'units':str(V.units)}), 'Theta': (dims, ds.theta.values, {'units':str(ds.theta.units)}), 'Thetae': (dims, ds.theta_e.values, {'units':str(ds.theta_e.units)}), 'Thetav': (dims, ds.theta_v.values, {'units':str(ds.theta_v.units)}) } subds = xr.Dataset(data_vars, coords) #convert to pandas pd_unl = subds.to_dataframe() pd_unl.reset_index(inplace=True) # Subset the dataset to the desired 22:43 if tstart is None: hstart = pd_unl['datetime'].iloc[0] else: hstart = tstart if tend is None: hend = pd_unl['datetime'].iloc[-1] else: hend = tend # Save only desired iop data data_u = pd_unl.loc[(pd_unl['datetime'] >= hstart) & (pd_unl['datetime'] <= hend)] data_hold.append(data_u) #convert the list holding the dataframes to one large dataframe data_unl = pd.concat(data_hold) #drop all the columns that we will not use past this point (to save memory/computing time) data_unl = data_unl.drop(columns=['Temperature', 'Z_ASL', 'Z_AGL', 'Theta', 'Dewpoint', 'Pressure', 'RH']) # print(data_unl.memory_usage()) # data_unl.set_index('datetime', inplace=True, drop=False) return data_unl, 'UNL' # * * * elif pname in pform_names('NSSL'): mmfile = glob.glob(config.g_mesonet_directory+config.day+'/mesonets/NSSL/'+pname+'_'+config.day[2:]+'_QC_met.dat') # Test Data availability if d_testing == True: try: #if there is no files this will will cause the try statement to fail mtest = mmfile[0] return True except: return False # + + + + + + + + + + + + ++ + + mmfile=mmfile[0] # Read NSSL file using column names from readme column_names = ['id','time','lat','lon','alt','tfast','tslow','rh','p','dir','spd','qc1','qc2','qc3','qc4'] data = pd.read_csv(mmfile, header=0, delim_whitespace=True, names=column_names) data = data.drop_duplicates() # Find timedelta of hours since start of iop (IOP date taken from filename!) tiop = dt.datetime(2019, np.int(mmfile[-15:-13]), np.int(mmfile[-13:-11]), 0, 0, 0) if tstart is None: hstart = tiop hstart_dec = hstart.hour + (hstart.minute/60) + (hstart.second/3600) #convert to decimal hours HH.HHH else: hstart = float((tstart - tiop).seconds)/3600 hstart_dec = hstart if tend is None: hend = data['time'].iloc[-1] else: hend = (tend - tiop) if hend >= dt.timedelta(days=1): hend = float((tend-tiop).seconds)/3600 + 24. else: hend = float((tend-tiop)).seconds/3600 # Save only desired iop data data_nssl = data.loc[(data['time'] >= hstart_dec) & (data['time'] <= hend)] # Convert time into timedeltas date = dt.datetime.strptime('2019-'+mmfile[-15:-13]+'-'+mmfile[-13:-11],'%Y-%m-%d') time_deltas = [] for i in np.arange(len(data_nssl)): j = data_nssl['time'].iloc[i] time_deltas = np.append(time_deltas, date + dt.timedelta(hours=int(j), minutes=int((j*60) % 60), seconds=int((j*3600) % 60))) data_nssl['datetime'] = time_deltas ## Caclulate desired variables p, t = data_nssl['p'].values * units.hectopascal, data_nssl['tfast'].values * units.degC r_h = data_nssl['rh'].values/100 data_nssl['Theta'] = (mpcalc.potential_temperature(p, t)).m mixing = mpcalc.mixing_ratio_from_relative_humidity(r_h, t, p) data_nssl['Thetav'] = (mpcalc.virtual_potential_temperature(p, t, mixing)).m td = mpcalc.dewpoint_rh(temperature= t, rh= r_h) data_nssl['Thetae'] = (mpcalc.equivalent_potential_temperature(p, t, td)).m Spd, dire = data_nssl['spd'].values * units('m/s') , data_nssl['dir'].values * units('degrees') u, v = mpcalc.wind_components(Spd, dire) data_nssl['U'], data_nssl['V'] = u.to('knot'), v.to('knot') # q_list = ['qc1','qc2','qc3','qc4'] q_list = config.NSSL_qcflags data_nssl['all_qc_flags'] = data_nssl[q_list].sum(axis=1) # data_nssl.set_index('datetime', inplace=True, drop=False) #drop all the columns that we will not use past this point (to save memory/computing time) data_nssl = data_nssl.drop(columns=['rh', 'p', 'time', 'alt', 'Theta', 'tfast', 'tslow']) # print(data_nssl.memory_usage()) return data_nssl, 'NSSL' # * * * elif pname == 'UAS': if print_long == True: print("no code for reading UAS yet") if d_testing == True: return False return 'UAS'
def uaPlot(data, level, date, save_dir, ds, td_option): custom_layout = StationPlotLayout() custom_layout.add_barb('eastward_wind', 'northward_wind', units='knots') custom_layout.add_value('NW', 'air_temperature', fmt='.0f', units='degC', color='darkred') # Geopotential height and smooth hght = ds.Geopotential_height_isobaric.metpy.sel( vertical=level * units.hPa, time=date, lat=slice(85, 15), lon=slice(360 - 200, 360 - 10)) smooth_hght = mpcalc.smooth_n_point(hght, 9, 10) # Temperature, smooth, and convert to Celsius tmpk = ds.Temperature_isobaric.metpy.sel(vertical=level * units.hPa, time=date, lat=slice(85, 15), lon=slice(360 - 200, 360 - 10)) smooth_tmpc = (mpcalc.smooth_n_point(tmpk, 9, 10)).to('degC') #Calculate Theta-e rh = ds.Relative_humidity_isobaric.metpy.sel(vertical=level * units.hPa, time=date, lat=slice(85, 15), lon=slice( 360 - 200, 360 - 10)) td = mpcalc.dewpoint_from_relative_humidity(tmpk, rh) te = mpcalc.equivalent_potential_temperature(level * units.hPa, tmpk, td) smooth_te = mpcalc.smooth_n_point(te, 9, 10) #decide on the height format based on the level if level == 250: custom_layout.add_value('NE', 'height', fmt=lambda v: format(v, '1')[1:4], units='m', color='black') cint = 120 tint = 5 if level == 300: custom_layout.add_value('NE', 'height', fmt=lambda v: format(v, '1')[1:4], units='m', color='black') cint = 120 tint = 5 if level == 500: custom_layout.add_value('NE', 'height', fmt=lambda v: format(v, '1')[0:3], units='m', color='black') cint = 60 tint = 5 if level == 700: custom_layout.add_value('NE', 'height', fmt=lambda v: format(v, '1')[1:4], units='m', color='black') custom_layout.add_value('SW', 'tdd', units='degC', color='green') custom_layout.add_value('SE', 'thetae', units='degK', color='orange') temps = 'Tdd, and Theta-e' cint = 30 tint = 4 if level == 850: custom_layout.add_value('NE', 'height', fmt=lambda v: format(v, '1')[1:4], units='m', color='black') if td_option == True: custom_layout.add_value('SW', 'dew_point_temperature', units='degC', color='green') temps = 'Td, and Theta-e' if td_option == False: custom_layout.add_value('SW', 'tdd', units='degC', color='green') temps = 'Tdd, and Theta-e' # custom_layout.add_value('SW', 'tdd', units='degC', color='green') # temps = 'Tdd, and Theta-e' custom_layout.add_value('SE', 'thetae', units='degK', color='orange') cint = 30 tint = 4 if level == 925: custom_layout.add_value('NE', 'height', fmt=lambda v: format(v, '1')[1:4], units='m', color='black') if td_option == True: custom_layout.add_value('SW', 'dew_point_temperature', units='degC', color='green') temps = 'Td, and Theta-e' if td_option == False: custom_layout.add_value('SW', 'tdd', units='degC', color='green') temps = 'Tdd, and Theta-e' custom_layout.add_value('SE', 'thetae', units='degK', color='orange') cint = 30 tint = 4 globe = ccrs.Globe(ellipse='sphere', semimajor_axis=6371200., semiminor_axis=6371200.) proj = ccrs.Stereographic(central_longitude=-105., central_latitude=90., globe=globe, true_scale_latitude=60) # Plot the image fig = plt.figure(figsize=(40, 40)) ax = fig.add_subplot(1, 1, 1, projection=proj) state_boundaries = feat.NaturalEarthFeature( category='cultural', name='admin_1_states_provinces_lines', scale='10m', facecolor='none') coastlines = feat.NaturalEarthFeature('physical', 'coastline', '50m', facecolor='none') lakes = feat.NaturalEarthFeature('physical', 'lakes', '50m', facecolor='none') countries = feat.NaturalEarthFeature('cultural', 'admin_0_countries', '50m', facecolor='none') ax.add_feature(state_boundaries, zorder=2, edgecolor='grey') ax.add_feature(lakes, zorder=2, edgecolor='grey') ax.add_feature(coastlines, zorder=2, edgecolor='grey') ax.add_feature(lakes, zorder=2, edgecolor='grey') ax.add_feature(countries, zorder=2, edgecolor='grey') ax.coastlines(resolution='50m', zorder=2, color='grey') ax.set_extent([-132., -70, 26., 80.], ccrs.PlateCarree()) stationData = dataDict(data) stationplot = StationPlot(ax, stationData['longitude'], stationData['latitude'], transform=ccrs.PlateCarree(), fontsize=22) custom_layout.plot(stationplot, stationData) # Plot Solid Contours of Geopotential Height cs = ax.contour(hght.lon, hght.lat, smooth_hght.m, range(0, 20000, cint), colors='black', transform=ccrs.PlateCarree()) clabels = plt.clabel(cs, fmt='%d', colors='white', inline_spacing=5, use_clabeltext=True, fontsize=22) # Contour labels with black boxes and white text for t in clabels: t.set_bbox({'facecolor': 'black', 'pad': 4}) t.set_fontweight('heavy') #Check levels for different contours if level == 250 or level == 300 or level == 500: # Plot Dashed Contours of Temperature cs2 = ax.contour(hght.lon, hght.lat, smooth_tmpc.m, range(-60, 51, tint), colors='red', transform=ccrs.PlateCarree()) clabels = plt.clabel(cs2, fmt='%d', colors='red', inline_spacing=5, use_clabeltext=True, fontsize=22) # Set longer dashes than default for c in cs2.collections: c.set_dashes([(0, (5.0, 3.0))]) temps = 'T' if level == 700 or level == 850 or level == 925: # Plot Dashed Contours of Temperature cs2 = ax.contour(hght.lon, hght.lat, smooth_te.m, range(210, 360, tint), colors='orange', transform=ccrs.PlateCarree()) clabels = plt.clabel(cs2, fmt='%d', colors='orange', inline_spacing=5, use_clabeltext=True, fontsize=22) # Set longer dashes than default for c in cs2.collections: c.set_dashes([(0, (5.0, 3.0))]) dpi = plt.rcParams['savefig.dpi'] = 255 date = date + timedelta(hours=6) text = AnchoredText(str(level) + 'mb Wind, Heights, and ' + temps + ' Valid: {0:%Y-%m-%d} {0:%H}:00UTC'.format(date), loc=3, frameon=True, prop=dict(fontsize=22)) ax.add_artist(text) plt.tight_layout() save_fname = '{0:%Y%m%d_%H}z_'.format(date) + str(level) + 'mb.pdf' plt.savefig(save_dir / save_fname, dpi=dpi, bbox_inches='tight')
def scalardata(field, valid_time, targetdir=".", debug=False): # Get color map, levels, and netCDF variable name appropriate for requested variable (from fieldinfo module). info = fieldinfo[field] if debug: print("scalardata: found", field, "fieldinfo:", info) cmap = colors.ListedColormap(info['cmap']) levels = info['levels'] fvar = info['fname'][0] # Get narr file and filename. ifile = get(valid_time, targetdir=targetdir, narrtype=info['filename']) if debug: print("About to open " + ifile) nc = xarray.open_dataset(ifile) # Tried to rename vars and dimensions so metpy.parse_cf() would not warn "Found latitude/longitude values, assuming latitude_longitude for projection grid_mapping variable" # It didn't help. Only commenting out the metpy.parse_cf() line helped. # It didn't help with MetpyDeprecationWarning: Multidimensional coordinate lat assigned for axis "y". This behavior has been deprecated and will be removed in v1.0 (only one-dimensional coordinates will be available for the "y" axis) either #nc = nc.rename_vars({"gridlat_221": "lat", "gridlon_221" : "lon"}) #nc = nc.rename_dims({"gridx_221": "x", "gridy_221" : "y"}) #nc = nc.metpy.parse_cf() # TODO: figure out why filled contour didn't have .metpy.parse_cf() if fvar not in nc.variables: print(fvar, "not in", ifile, '. Try', nc.var()) sys.exit(1) # Define data array. Speed and shear derived differently. # Define 'long_name' attribute # if field[0:5] == "speed": u = nc[info['fname'][0]] v = nc[info['fname'][1]] data = u # copy metadata/coordinates from u data.values = wind_speed(u, v) data.attrs['long_name'] = "wind speed" elif field[0:3] == 'shr' and '_' in field: du, dv = shear(field, valid_time=valid_time, targetdir=targetdir, debug=debug) ws = wind_speed(du, dv) attrs = { 'long_name': 'wind shear', 'units': str(ws.units), 'verttitle': du.attrs["verttitle"] } # Use .m magnitude because you can't transfer units of pint quantity to xarray numpy array (xarray.values) data = xarray.DataArray(data=ws.m, dims=du.dims, coords=du.coords, name=field, attrs=attrs) elif field == 'theta2': pres = nc[info['fname'][0]] temp = nc[info['fname'][1]] data = pres # retain xarray metadata/coordinates theta = potential_temperature(pres, temp) data.values = theta data.attrs['units'] = str(theta.units) data.attrs['long_name'] = 'potential temperature' elif field == 'thetae2': pres = nc[info['fname'][0]] temp = nc[info['fname'][1]] dwpt = nc[info['fname'][2]] data = pres # retain xarray metadata/coordinates thetae = equivalent_potential_temperature(pres, temp, dwpt) data.values = thetae data.attrs['units'] = str(thetae.units) data.attrs['long_name'] = 'equivalent potential temperature' elif field == 'scp' or field == 'stp' or field == 'tctp': cape = nc[info['fname'][0]] cin = nc[info['fname'][1]] ifile = get(valid_time, targetdir=targetdir, narrtype=narrFlx) ncFlx = xarray.open_dataset(ifile).metpy.parse_cf() srh = ncFlx[info['fname'][2]] shear_layer = info['fname'][3] bulk_shear = scalardata(shear_layer, valid_time, targetdir=targetdir, debug=debug) lifted_condensation_level_height = scalardata('zlcl', valid_time, targetdir=targetdir, debug=debug) if field == 'scp': # In SPC help, cin is positive in SCP formulation. cin_term = -40 / cin cin_term = cin_term.where(cin < -40, other=1) scp = supercell_composite(cape, srh, bulk_shear) * cin_term.metpy.unit_array attrs = { 'units': str(scp.units), 'long_name': 'supercell composite parameter' } data = xarray.DataArray(data=scp, dims=cape.dims, coords=cape.coords, name=field, attrs=attrs) if field == 'stp': cin_term = (200 + cin) / 150 cin_term = cin_term.where(cin <= -50, other=1) cin_term = cin_term.where(cin >= -200, other=0) # CAPE, srh, bulk_shear, cin may be one vertical level, but LCL may be multiple heights. # xarray.broadcast() makes them all multiple heights with same shape, so significant_tornado doesn't # complain about expecting lat/lon 2 dimensions and getting 3 dimensions.. (cape, lifted_condensation_level_height, srh, bulk_shear, cin_term) = xarray.broadcast(cape, lifted_condensation_level_height, srh, bulk_shear, cin_term) stp = significant_tornado(cape, lifted_condensation_level_height, srh, bulk_shear) * cin_term.metpy.unit_array attrs = { 'units': str(stp.units), 'long_name': 'significant tornado parameter', 'verttitle': lifted_condensation_level_height.attrs['verttitle'] } data = xarray.DataArray(data=stp, dims=cape.dims, coords=cape.coords, name=field, attrs=attrs) if field == 'tctp': tctp = srh / (40 * munits['m**2/s**2']) * bulk_shear / ( 12 * munits['m/s']) * (2000 - lifted_condensation_level_height ) / (1400 * munits.m) # But NARR storm relative helicity (srh) is 0-3 km AGL, while original TCTP expects 0-1 km AGL. # So the shear term is too large using the NARR srh. Normalize the srh term with a larger denominator. # In STP, srh is normalized by 150 m**2/s**2. Use that. tctp_0_3kmsrh = srh / (150 * munits['m**2/s**2']) * bulk_shear / ( 12 * munits['m/s']) * (2000 - lifted_condensation_level_height ) / (1400 * munits.m) attrs = { 'units': 'dimensionless', 'long_name': 'TC tornado parameter' } data = xarray.DataArray(data=tctp_0_3kmsrh, dims=cape.dims, coords=cape.coords, name=field, attrs=attrs) elif field == 'lcl': pres = nc[info['fname'][0]] temp = nc[info['fname'][1]] dwpt = nc[info['fname'][2]] LCL_pressure, LCL_temperature = lcl(pres.fillna(pres.mean()), temp.fillna(temp.mean()), dwpt.fillna(dwpt.mean())) # convert units to string or xarray.DataArray.metpy.unit_array dies with ttributeError: 'NoneType' object has no attribute 'evaluate' attrs = { "long_name": "lifted condensation level", "units": str(LCL_pressure.units), "from": "metpy.calc.lcl" } data = xarray.DataArray(data=LCL_pressure, coords=pres.coords, dims=pres.dims, name='LCL', attrs=attrs) elif field == 'zlcl': LCL_pressure = scalardata('lcl', valid_time, targetdir=targetdir, debug=debug) ifile = get(valid_time, targetdir=targetdir, narrtype=narr3D) nc3D = xarray.open_dataset(ifile).metpy.parse_cf() hgt3D = nc3D["HGT_221_ISBL"] data = pressure_to_height(LCL_pressure, hgt3D, targetdir=targetdir) else: data = nc[fvar] data = units(data, info, debug=debug) data = vertical(data, info, debug=debug) data = temporal(data, info, debug=debug) data.attrs['field'] = field data.attrs['ifile'] = os.path.realpath(ifile) data.attrs['levels'] = levels data.attrs['cmap'] = cmap if data.min() > levels[-1] or data.max() < levels[0]: print('levels', levels, 'out of range of data', data.min(), data.max()) sys.exit(2) return data
def Time_Crossection_rh_uv_theta_e( initTime=None, model='ECMWF', points={ 'lon': [116.3833], 'lat': [39.9] }, levels=[1000, 950, 925, 900, 850, 800, 700, 600, 500, 400, 300, 200], t_gap=3, t_range=[0, 48], output_dir=None): fhours = np.arange(t_range[0], t_range[1], t_gap) # 读数据 try: data_dir = [ utl.Cassandra_dir(data_type='high', data_source=model, var_name='TMP', lvl=''), utl.Cassandra_dir(data_type='high', data_source=model, var_name='UGRD', lvl=''), utl.Cassandra_dir(data_type='high', data_source=model, var_name='VGRD', lvl=''), utl.Cassandra_dir(data_type='high', data_source=model, var_name='RH', lvl='') ] except KeyError: raise ValueError('Can not find all directories needed') if (initTime == None): initTime = get_latest_initTime(data_dir[0][0:-1] + "850") filenames = [initTime + '.' + str(fhour).zfill(3) for fhour in fhours] TMP_4D = get_model_3D_grids(directory=data_dir[0][0:-1], filenames=filenames, levels=levels, allExists=False) TMP_2D = TMP_4D.interp(lon=('points', points['lon']), lat=('points', points['lat'])) filenames = [initTime + '.' + str(fhour).zfill(3) for fhour in fhours] u_4D = get_model_3D_grids(directory=data_dir[1][0:-1], filenames=filenames, levels=levels, allExists=False) u_2D = u_4D.interp(lon=('points', points['lon']), lat=('points', points['lat'])) filenames = [initTime + '.' + str(fhour).zfill(3) for fhour in fhours] v_4D = get_model_3D_grids(directory=data_dir[2][0:-1], filenames=filenames, levels=levels, allExists=False) v_2D = v_4D.interp(lon=('points', points['lon']), lat=('points', points['lat'])) filenames = [initTime + '.' + str(fhour).zfill(3) for fhour in fhours] rh_4D = get_model_3D_grids(directory=data_dir[3][0:-1], filenames=filenames, levels=levels, allExists=False) rh_2D = rh_4D.interp(lon=('points', points['lon']), lat=('points', points['lat'])) rh_2D.attrs['model'] = model rh_2D.attrs['points'] = points Td_2D = mpcalc.dewpoint_rh(TMP_2D['data'].values * units.celsius, rh_2D['data'].values * units.percent) rh, pressure = xr.broadcast(rh_2D['data'], rh_2D['level']) Theta_e = mpcalc.equivalent_potential_temperature( pressure, TMP_2D['data'].values * units.celsius, Td_2D) theta_e_2D = xr.DataArray(np.array(Theta_e), coords=rh_2D['data'].coords, dims=rh_2D['data'].dims, attrs={'units': Theta_e.units}) crossection_graphics.draw_Time_Crossection_rh_uv_theta_e( rh_2D=rh_2D, u_2D=u_2D, v_2D=v_2D, theta_e_2D=theta_e_2D, t_range=t_range, output_dir=output_dir)
def test_equivalent_potential_temperature(): """Test equivalent potential temperature calculation.""" p = 999. * units.mbar t = 288. * units.kelvin ept = equivalent_potential_temperature(p, t) assert_almost_equal(ept, 315.9548 * units.kelvin, 3)
def Time_Crossection_rh_uv_theta_e(initTime=None,model='ECMWF',data_source='MICAPS',points={'lon':[116.3833], 'lat':[39.9]}, levels=[1000, 950, 925, 900, 850, 800, 700,600,500,400,300,200], t_gap=3,t_range=[0,48],output_dir=None,**kwargs): fhours = np.arange(t_range[0], t_range[1], t_gap) if(data_source == 'MICAPS'): try: data_dir = [utl.Cassandra_dir(data_type='high',data_source=model,var_name='TMP',lvl=''), utl.Cassandra_dir(data_type='high',data_source=model,var_name='UGRD',lvl=''), utl.Cassandra_dir(data_type='high',data_source=model,var_name='VGRD',lvl=''), utl.Cassandra_dir(data_type='high',data_source=model,var_name='RH',lvl=''), utl.Cassandra_dir(data_type='surface',data_source=model,var_name='PSFC')] except KeyError: raise ValueError('Can not find all directories needed') if(initTime==None): initTime = get_latest_initTime(data_dir[0][0:-1]+"850") filenames = [initTime+'.'+str(fhour).zfill(3) for fhour in fhours] TMP_4D=get_model_3D_grids(directory=data_dir[0][0:-1],filenames=filenames,levels=levels, allExists=False) u_4D=get_model_3D_grids(directory=data_dir[1][0:-1],filenames=filenames,levels=levels, allExists=False) v_4D=get_model_3D_grids(directory=data_dir[2][0:-1],filenames=filenames,levels=levels, allExists=False) rh_4D=get_model_3D_grids(directory=data_dir[3][0:-1],filenames=filenames,levels=levels, allExists=False) Psfc_3D=get_model_grids(directory=data_dir[4][0:-1],filenames=filenames,allExists=False) if(data_source == 'CIMISS'): if(initTime != None): filename = utl.model_filename(initTime, 0,UTC=True) else: filename=utl.filename_day_back_model(day_back=0,fhour=0,UTC=True) try: rh_4D=CMISS_IO.cimiss_model_3D_grids(init_time_str='20'+filename[0:8],valid_times=fhours, data_code=utl.CMISS_data_code(data_source=model,var_name='RHU'), fcst_levels=levels, fcst_ele="RHU", units='%',pbar=True) u_4D=CMISS_IO.cimiss_model_3D_grids(init_time_str='20'+filename[0:8],valid_times=fhours, data_code=utl.CMISS_data_code(data_source=model,var_name='WIU'), fcst_levels=levels, fcst_ele="WIU", units='m/s',pbar=True) v_4D=CMISS_IO.cimiss_model_3D_grids(init_time_str='20'+filename[0:8],valid_times=fhours, data_code=utl.CMISS_data_code(data_source=model,var_name='WIV'), fcst_levels=levels, fcst_ele="WIV", units='m/s',pbar=True) TMP_4D=CMISS_IO.cimiss_model_3D_grids(init_time_str='20'+filename[0:8],valid_times=fhours, data_code=utl.CMISS_data_code(data_source=model,var_name='TEM'), fcst_levels=levels, fcst_ele="TEM", units='K',pbar=True) TMP_4D['data'].values=TMP_4D['data'].values-273.15 Psfc_3D=CMISS_IO.cimiss_model_grids(init_time_str='20'+filename[0:8], valid_times=fhours, data_code=utl.CMISS_data_code(data_source=model,var_name='PRS'), fcst_level=0, fcst_ele="PRS", units='Pa',pbar=True) except KeyError: raise ValueError('Can not find all data needed') TMP_2D=TMP_4D.interp(lon=('points', points['lon']), lat=('points', points['lat'])) u_2D=u_4D.interp(lon=('points', points['lon']), lat=('points', points['lat'])) v_2D=v_4D.interp(lon=('points', points['lon']), lat=('points', points['lat'])) rh_2D=rh_4D.interp(lon=('points', points['lon']), lat=('points', points['lat'])) rh_2D.attrs['model']=model rh_2D.attrs['points']=points Psfc_1D=Psfc_3D.interp(lon=('points', points['lon']), lat=('points', points['lat'])) v_2D2,pressure_2D = xr.broadcast(v_2D['data'],v_2D['level']) v_2D2,Psfc_2D = xr.broadcast(v_2D['data'],Psfc_1D['data']) Td_2D = mpcalc.dewpoint_rh(TMP_2D['data'].values*units.celsius, rh_2D['data'].values* units.percent) terrain_2D=pressure_2D-Psfc_2D rh,pressure = xr.broadcast(rh_2D['data'],rh_2D['level']) Theta_e=mpcalc.equivalent_potential_temperature(pressure, TMP_2D['data'].values*units.celsius, Td_2D) theta_e_2D = xr.DataArray(np.array(Theta_e), coords=rh_2D['data'].coords, dims=rh_2D['data'].dims, attrs={'units': Theta_e.units}) crossection_graphics.draw_Time_Crossection_rh_uv_theta_e( rh_2D=rh_2D, u_2D=u_2D, v_2D=v_2D,theta_e_2D=theta_e_2D,terrain_2D=terrain_2D, t_range=t_range,output_dir=output_dir)
def Crosssection_Wind_Theta_e_Qv( initTime=None, fhour=24, levels=[1000, 950, 925, 900, 850, 800, 700,600,500,400,300,200], day_back=0,model='GRAPES_GFS',data_source='MICAPS', lw_ratio=[16,9], output_dir=None, st_point = [20, 120.0], ed_point = [50, 130.0], map_extent=[70,140,15,55], h_pos=[0.125, 0.665, 0.25, 0.2],**kwargs ): if(data_source == 'MICAPS'): try: data_dir = [utl.Cassandra_dir(data_type='high',data_source=model,var_name='RH',lvl=''), utl.Cassandra_dir(data_type='high',data_source=model,var_name='UGRD',lvl=''), utl.Cassandra_dir(data_type='high',data_source=model,var_name='VGRD',lvl=''), utl.Cassandra_dir(data_type='high',data_source=model,var_name='TMP',lvl=''), utl.Cassandra_dir(data_type='high',data_source=model,var_name='HGT',lvl='500'), utl.Cassandra_dir(data_type='surface',data_source=model,var_name='PSFC')] except KeyError: raise ValueError('Can not find all directories needed') # get filename if(initTime != None): filename = utl.model_filename(initTime, fhour) else: filename=utl.filename_day_back_model(day_back=day_back,fhour=fhour) # retrieve data from micaps server rh=get_model_3D_grid(directory=data_dir[0][0:-1],filename=filename,levels=levels, allExists=False) u=get_model_3D_grid(directory=data_dir[1][0:-1],filename=filename,levels=levels, allExists=False) v=get_model_3D_grid(directory=data_dir[2][0:-1],filename=filename,levels=levels, allExists=False) v2=get_model_3D_grid(directory=data_dir[2][0:-1],filename=filename,levels=levels, allExists=False) t=get_model_3D_grid(directory=data_dir[3][0:-1],filename=filename,levels=levels, allExists=False) gh=get_model_grid(data_dir[4], filename=filename) psfc=get_model_grid(data_dir[5], filename=filename) if(data_source == 'CIMISS'): # get filename if(initTime != None): filename = utl.model_filename(initTime, fhour,UTC=True) else: filename=utl.filename_day_back_model(day_back=day_back,fhour=fhour,UTC=True) try: rh=CMISS_IO.cimiss_model_3D_grid(init_time_str='20'+filename[0:8],valid_time=fhour, data_code=utl.CMISS_data_code(data_source=model,var_name='RHU'), fcst_levels=levels, fcst_ele="RHU", units='%') u=CMISS_IO.cimiss_model_3D_grid(init_time_str='20'+filename[0:8],valid_time=fhour, data_code=utl.CMISS_data_code(data_source=model,var_name='WIU'), fcst_levels=levels, fcst_ele="WIU", units='m/s') v=CMISS_IO.cimiss_model_3D_grid(init_time_str='20'+filename[0:8],valid_time=fhour, data_code=utl.CMISS_data_code(data_source=model,var_name='WIV'), fcst_levels=levels, fcst_ele="WIV", units='m/s') v2=CMISS_IO.cimiss_model_3D_grid(init_time_str='20'+filename[0:8],valid_time=fhour, data_code=utl.CMISS_data_code(data_source=model,var_name='WIV'), fcst_levels=levels, fcst_ele="WIV", units='m/s') t=CMISS_IO.cimiss_model_3D_grid(init_time_str='20'+filename[0:8],valid_time=fhour, data_code=utl.CMISS_data_code(data_source=model,var_name='TEM'), fcst_levels=levels, fcst_ele="TEM", units='K') t['data'].values=t['data'].values-273.15 gh=CMISS_IO.cimiss_model_by_time('20'+filename[0:8],valid_time=fhour, data_code=utl.CMISS_data_code(data_source=model,var_name='GPH'), fcst_level=500, fcst_ele="GPH", units='gpm') gh['data'].values=gh['data'].values/10. psfc=CMISS_IO.cimiss_model_by_time('20'+filename[0:8], valid_time=fhour, data_code=utl.CMISS_data_code(data_source=model,var_name='PRS'), fcst_level=0, fcst_ele="PRS", units='Pa') psfc['data']=psfc['data']/100. except KeyError: raise ValueError('Can not find all data needed') rh = rh.metpy.parse_cf().squeeze() u = u.metpy.parse_cf().squeeze() v = v.metpy.parse_cf().squeeze() v2 = v2.metpy.parse_cf().squeeze() psfc=psfc.metpy.parse_cf().squeeze() t = t.metpy.parse_cf().squeeze() resolution=u['lon'][1]-u['lon'][0] x,y=np.meshgrid(u['lon'], u['lat']) # +form 3D psfc mask1 = ( (psfc['lon']>=t['lon'].values.min())& (psfc['lon']<=t['lon'].values.max())& (psfc['lat']>=t['lat'].values.min())& (psfc['lat']<=t['lat'].values.max()) ) t2,psfc_bdcst=xr.broadcast(t['data'],psfc['data'].where(mask1, drop=True)) mask2=(psfc_bdcst > -10000) psfc_bdcst=psfc_bdcst.where(mask2, drop=True) # -form 3D psfc dx,dy=mpcalc.lat_lon_grid_deltas(u['lon'],u['lat']) #rh=rh.rename(dict(lat='latitude',lon='longitude')) cross = cross_section(rh, st_point, ed_point) cross_rh=cross.set_coords(('lat', 'lon')) cross = cross_section(u, st_point, ed_point) cross_u=cross.set_coords(('lat', 'lon')) cross = cross_section(v, st_point, ed_point) cross_v=cross.set_coords(('lat', 'lon')) cross_psfc = cross_section(psfc_bdcst, st_point, ed_point) cross_u['data'].attrs['units']=units.meter/units.second cross_v['data'].attrs['units']=units.meter/units.second cross_u['t_wind'], cross_v['n_wind'] = mpcalc.cross_section_components(cross_u['data'],cross_v['data']) cross = cross_section(t, st_point, ed_point) cross_t=cross.set_coords(('lat', 'lon')) cross_Td = mpcalc.dewpoint_rh(cross_t['data'].values*units.celsius, cross_rh['data'].values* units.percent) rh,pressure = xr.broadcast(cross_rh['data'],cross_t['level']) pressure.attrs['units']='hPa' Qv = mpcalc.specific_humidity_from_dewpoint(cross_Td, pressure) cross_Qv = xr.DataArray(np.array(Qv)*1000., coords=cross_rh['data'].coords, dims=cross_rh['data'].dims, attrs={'units': units('g/kg')}) Theta_e=mpcalc.equivalent_potential_temperature(pressure, cross_t['data'].values*units.celsius, cross_Td) cross_terrain=pressure-cross_psfc cross_Theta_e = xr.DataArray(np.array(Theta_e), coords=cross_rh['data'].coords, dims=cross_rh['data'].dims, attrs={'units': Theta_e.units}) crossection_graphics.draw_Crosssection_Wind_Theta_e_Qv( cross_Qv=cross_Qv, cross_Theta_e=cross_Theta_e, cross_u=cross_u, cross_v=cross_v,cross_terrain=cross_terrain,gh=gh, h_pos=h_pos,st_point=st_point,ed_point=ed_point, levels=levels,map_extent=map_extent,lw_ratio=lw_ratio, output_dir=output_dir)
def Crosssection_Wind_Theta_e_Qv( initial_time=None, fhour=24, levels=[1000, 950, 925, 900, 850, 800, 700, 600, 500, 400, 300, 200], day_back=0, model='ECMWF', output_dir=None, st_point=[20, 120.0], ed_point=[50, 130.0], map_extent=[70, 140, 15, 55], h_pos=[0.125, 0.665, 0.25, 0.2]): # micaps data directory try: data_dir = [ utl.Cassandra_dir(data_type='high', data_source=model, var_name='RH', lvl=''), utl.Cassandra_dir(data_type='high', data_source=model, var_name='UGRD', lvl=''), utl.Cassandra_dir(data_type='high', data_source=model, var_name='VGRD', lvl=''), utl.Cassandra_dir(data_type='high', data_source=model, var_name='TMP', lvl=''), utl.Cassandra_dir(data_type='high', data_source=model, var_name='HGT', lvl='500') ] except KeyError: raise ValueError('Can not find all directories needed') # get filename if (initial_time != None): filename = utl.model_filename(initial_time, fhour) else: filename = utl.filename_day_back_model(day_back=day_back, fhour=fhour) # retrieve data from micaps server rh = get_model_3D_grid(directory=data_dir[0][0:-1], filename=filename, levels=levels, allExists=False) if rh is None: return rh = rh.metpy.parse_cf().squeeze() u = get_model_3D_grid(directory=data_dir[1][0:-1], filename=filename, levels=levels, allExists=False) if u is None: return u = u.metpy.parse_cf().squeeze() v = get_model_3D_grid(directory=data_dir[2][0:-1], filename=filename, levels=levels, allExists=False) if v is None: return v = v.metpy.parse_cf().squeeze() v2 = get_model_3D_grid(directory=data_dir[2][0:-1], filename=filename, levels=levels, allExists=False) if v2 is None: return v2 = v2.metpy.parse_cf().squeeze() t = get_model_3D_grid(directory=data_dir[3][0:-1], filename=filename, levels=levels, allExists=False) if t is None: return t = t.metpy.parse_cf().squeeze() gh = get_model_grid(data_dir[4], filename=filename) if t is None: return resolution = u['lon'][1] - u['lon'][0] x, y = np.meshgrid(u['lon'], u['lat']) dx, dy = mpcalc.lat_lon_grid_deltas(u['lon'], u['lat']) for ilvl in levels: u2d = u.sel(level=ilvl) #u2d['data'].attrs['units']=units.meter/units.second v2d = v.sel(level=ilvl) #v2d['data'].attrs['units']=units.meter/units.second absv2d = mpcalc.absolute_vorticity( u2d['data'].values * units.meter / units.second, v2d['data'].values * units.meter / units.second, dx, dy, y * units.degree) if (ilvl == levels[0]): absv3d = v2 absv3d['data'].loc[dict(level=ilvl)] = np.array(absv2d) else: absv3d['data'].loc[dict(level=ilvl)] = np.array(absv2d) absv3d['data'].attrs['units'] = absv2d.units #rh=rh.rename(dict(lat='latitude',lon='longitude')) cross = cross_section(rh, st_point, ed_point) cross_rh = cross.set_coords(('lat', 'lon')) cross = cross_section(u, st_point, ed_point) cross_u = cross.set_coords(('lat', 'lon')) cross = cross_section(v, st_point, ed_point) cross_v = cross.set_coords(('lat', 'lon')) cross_u['data'].attrs['units'] = units.meter / units.second cross_v['data'].attrs['units'] = units.meter / units.second cross_u['t_wind'], cross_v['n_wind'] = mpcalc.cross_section_components( cross_u['data'], cross_v['data']) cross = cross_section(t, st_point, ed_point) cross_t = cross.set_coords(('lat', 'lon')) cross = cross_section(absv3d, st_point, ed_point) cross_Td = mpcalc.dewpoint_rh(cross_t['data'].values * units.celsius, cross_rh['data'].values * units.percent) rh, pressure = xr.broadcast(cross_rh['data'], cross_t['level']) Qv = mpcalc.specific_humidity_from_dewpoint(cross_Td, pressure) cross_Qv = xr.DataArray(np.array(Qv) * 1000., coords=cross_rh['data'].coords, dims=cross_rh['data'].dims, attrs={'units': units('g/kg')}) Theta_e = mpcalc.equivalent_potential_temperature( pressure, cross_t['data'].values * units.celsius, cross_Td) cross_Theta_e = xr.DataArray(np.array(Theta_e), coords=cross_rh['data'].coords, dims=cross_rh['data'].dims, attrs={'units': Theta_e.units}) crossection_graphics.draw_Crosssection_Wind_Theta_e_Qv( cross_Qv=cross_Qv, cross_Theta_e=cross_Theta_e, cross_u=cross_u, cross_v=cross_v, gh=gh, h_pos=h_pos, st_point=st_point, ed_point=ed_point, levels=levels, map_extent=map_extent, output_dir=output_dir)
def metpy_temp_adv(fname, plevels, tidx): ds = xr.open_dataset(fname).metpy.parse_cf().squeeze() ds = ds.isel(Time=tidx) print(ds) dx, dy = mpcalc.lat_lon_grid_deltas(ds.lon.values * units('degrees_E'), ds.lat.values * units('degrees_N')) plevels_unit = plevels * units.hPa ds1 = xr.Dataset() p = units.Quantity(to_np(ds.p), 'hPa') z = units.Quantity(to_np(ds.z), 'meter') u = units.Quantity(to_np(ds.u), 'm/s') v = units.Quantity(to_np(ds.v), 'm/s') w = units.Quantity(to_np(ds.w), 'm/s') tk = units.Quantity(to_np(ds.tk), 'kelvin') th = units.Quantity(to_np(ds.th), 'kelvin') eth = units.Quantity(to_np(ds.eth), 'kelvin') wspd = units.Quantity(to_np(ds.wspd), 'm/s') omega = units.Quantity(to_np(ds.omega), 'Pa/s') z, u, v, w, tk, th, eth, wspd, omega = log_interpolate_1d(plevels_unit, p, z, u, v, w, tk, th, eth, wspd, omega, axis=0) coords, dims = [plevs, ds.lat.values, ds.lon.values], ["level", "lat", "lon"] for name, var in zip( ['z', 'u', 'v', 'w', 'tk', 'th', 'eth', 'wspd', 'omega'], [z, u, v, w, tk, th, eth, wspd, omega]): #g = ndimage.gaussian_filter(var, sigma=3, order=0) ds1[name] = xr.DataArray(to_np(var), coords=coords, dims=dims) # Calculate temperature advection using metpy function for i, plev in enumerate(plevs): uqvect, vqvect = mpcalc.q_vector(u[i, :, :], v[i, :, :], th[i, :, :], plev * units.hPa, dx, dy) #uqvect, vqvect = mpcalc.q_vector(u[i,:,:], v[i,:,:], th.to('degC')[i,:,:], plev*units.hPa, dx, dy) q_div = -2 * mpcalc.divergence(uqvect, vqvect, dx, dy, dim_order='yx') ds1['uq_{:03d}'.format(plev)] = xr.DataArray( np.array(uqvect), coords=[ds.lat.values, ds.lon.values], dims=["lat", "lon"]) ds1['vq_{:03d}'.format(plev)] = xr.DataArray( np.array(vqvect), coords=[ds.lat.values, ds.lon.values], dims=["lat", "lon"]) ds1['q_div_{:03d}'.format(plev)] = xr.DataArray( np.array(q_div), coords=[ds.lat.values, ds.lon.values], dims=["lat", "lon"]) # adv = mpcalc.advection(tk[i,:,:], [u[i,:,:], v[i,:,:]], (dx, dy), dim_order='yx') * units('K/sec') # adv = ndimage.gaussian_filter(adv, sigma=3, order=0) * units('K/sec') # ds1['tk_adv_{:03d}'.format(plev)] = xr.DataArray(np.array(adv), coords=[ds.lat.values,ds.lon.values], dims=["lat","lon"]) # # adv = mpcalc.advection(th[i,:,:], [u[i,:,:], v[i,:,:]], (dx, dy), dim_order='yx') * units('K/sec') # adv = ndimage.gaussian_filter(adv, sigma=3, order=0) * units('K/sec') # ds1['th_adv_{:03d}'.format(plev)] = xr.DataArray(np.array(adv), coords=[ds.lat.values,ds.lon.values], dims=["lat","lon"]) # adv = mpcalc.advection(eth[i, :, :], [u[i, :, :], v[i, :, :]], (dx, dy), dim_order='yx') * units('K/sec') adv = ndimage.gaussian_filter(adv, sigma=3, order=0) * units('K/sec') ds1['eth_adv_{:03d}'.format(plev)] = xr.DataArray( np.array(adv), coords=[ds.lat.values, ds.lon.values], dims=["lat", "lon"]) div = mpcalc.divergence(u[i, :, :], v[i, :, :], dx, dy, dim_order='yx') div = ndimage.gaussian_filter(div, sigma=3, order=0) * units('1/sec') ds1['div_{:03d}'.format(plev)] = xr.DataArray( np.array(div), coords=[ds.lat.values, ds.lon.values], dims=["lat", "lon"]) ds1['Time'] = ds.Time eth2 = mpcalc.equivalent_potential_temperature( ds.slp.values * units.hPa, ds.t2m.values * units('K'), ds.td2.values * units('celsius')) ds1['eth2'] = xr.DataArray(eth2, coords=[ds.lat.values, ds.lon.values], dims=["lat", "lon"]) ds1['sst'] = xr.DataArray( ndimage.gaussian_filter(ds.sst.values, sigma=3, order=0) - 273.15, coords=[ds.lat.values, ds.lon.values], dims=["lat", "lon"]) ds1['t2m'] = xr.DataArray(ds.t2m.values, coords=[ds.lat.values, ds.lon.values], dims=["lat", "lon"]) ds1['th2'] = xr.DataArray(ds.th2.values, coords=[ds.lat.values, ds.lon.values], dims=["lat", "lon"]) ds1['mask'] = xr.DataArray(ds.mask.values, coords=[ds.lat.values, ds.lon.values], dims=["lat", "lon"]) ds1['u10'] = xr.DataArray(ds.u10.values, coords=[ds.lat.values, ds.lon.values], dims=["lat", "lon"]) ds1['v10'] = xr.DataArray(ds.v10.values, coords=[ds.lat.values, ds.lon.values], dims=["lat", "lon"]) ds1['slp'] = xr.DataArray(ds.slp.values, coords=[ds.lat.values, ds.lon.values], dims=["lat", "lon"]) ds1['rain'] = xr.DataArray(ds.rain.values, coords=[ds.lat.values, ds.lon.values], dims=["lat", "lon"]) ds1['accrain'] = xr.DataArray(ds.accrain.values, coords=[ds.lat.values, ds.lon.values], dims=["lat", "lon"]) #ds1['latent'] = xr.DataArray(ds.latent.values, coords=[ds.lat.values,ds.lon.values], dims=["lat","lon"]) #ds1['acclatent'] = xr.DataArray(ds.acclatent.values, coords=[ds.lat.values,ds.lon.values], dims=["lat","lon"]) return ds1
def main(): ### START OF USER SETTINGS BLOCK ### # FILE/DATA SETTINGS # file path to input datafile = '/home/jgodwin/python/sfc_observations/surface_observations.txt' timefile = '/home/jgodwin/python/sfc_observations/validtime.txt' # MAP SETTINGS # map names (for tracking purposes) maps = ['CONUS','Texas','Floater 1'] restart_domain = [True,False] # map boundaries west = [-120,-108,-108] east = [-70,-93,-85] south = [20,25,37] north = [50,38,52] # OUTPUT SETTINGS # save directory for output savedir = '/var/www/html/images/' # filenames ("_[variable].png" will be appended, so only a descriptor like "conus" is needed) savenames = ['conus','texas','floater1'] # TEST MODE SETTINGS test = False testnum = 3 ### END OF USER SETTINGS BLOCK ### for i in range(len(maps)): if test and i != testnum: continue print(maps[i]) # create the map projection cenlon = (west[i] + east[i]) / 2.0 cenlat = (south[i] + north[i]) / 2.0 sparallel = cenlat if cenlat > 0: cutoff = -30 flip = False elif cenlat < 0: cutoff = 30 flip = True if restart_domain: to_proj = ccrs.LambertConformal(central_longitude=cenlon,central_latitude=cenlat,standard_parallels=[sparallel],cutoff=cutoff) # open the data vt = open(timefile).read() with open(datafile) as f: data = pd.read_csv(f,header=0,names=['siteID','lat','lon','elev','slp','temp','sky','dpt','wx','wdr',\ 'wsp'],na_values=-99999) # filter data by lat/lon data = data[(data['lat'] >= south[i]-2.0) & (data['lat'] <= north[i]+2.0) & (data['lon'] >= west[i]-2.0)\ & (data['lon'] <= east[i]+2.0)] # remove questionable data data = data[(cToF(data['temp']) <= 120) & (cToF(data['dpt']) <= 80)] # project lat/lon onto final projection print("Creating map projection.") lon = data['lon'].values lat = data['lat'].values xp, yp, _ = to_proj.transform_points(ccrs.Geodetic(), lon, lat).T # remove missing data from pressure and interpolate # we'll give this a try and see if it can help with my CPU credit problem if restart_domain: print("Performing Cressman interpolation.") x_masked, y_masked, pres = remove_nan_observations(xp, yp, data['slp'].values) slpgridx, slpgridy, slp = interpolate_to_grid(x_masked, y_masked, pres, interp_type='cressman', minimum_neighbors=1, search_radius=400000, hres=100000) # get wind information and remove missing data wind_speed = (data['wsp'].values * units('knots')) wind_dir = data['wdr'].values * units.degree good_indices = np.where((~np.isnan(wind_dir)) & (~np.isnan(wind_speed))) x_masked = xp[good_indices] y_masked = yp[good_indices] wind_speed = wind_speed[good_indices] wind_dir = wind_dir[good_indices] u, v = wind_components(wind_speed, wind_dir) windgridx, windgridy, uwind = interpolate_to_grid(x_masked, y_masked, np.array(u), interp_type='cressman', search_radius=400000, hres=100000) _, _, vwind = interpolate_to_grid(x_masked, y_masked, np.array(v), interp_type='cressman', search_radius=400000, hres=100000) # get temperature information data['temp'] = cToF(data['temp']) x_masked, y_masked, t = remove_nan_observations(xp, yp, data['temp'].values) tempx, tempy, temp = interpolate_to_grid(x_masked, y_masked, t, interp_type='cressman', minimum_neighbors=3, search_radius=200000, hres=18000) temp = np.ma.masked_where(np.isnan(temp), temp) # get dewpoint information data['dpt'] = cToF(data['dpt']) x_masked,y_masked,td = remove_nan_observations(xp,yp,data['dpt'].values) dptx,dpty,dewp = interpolate_to_grid(x_masked,y_masked,td,interp_type='cressman',\ minimum_neighbors=3,search_radius=200000,hres=18000) dewp = np.ma.masked_where(np.isnan(dewp),dewp) # interpolate wind speed x_masked,y_masked,wspd = remove_nan_observations(xp,yp,data['wsp'].values) wspx,wspy,speed = interpolate_to_grid(x_masked,y_masked,wspd,interp_type='cressman',\ minimum_neighbors=3,search_radius=200000,hres=18000) speed = np.ma.masked_where(np.isnan(speed),speed) # derived values # station pressure data['pres'] = stationPressure(data['slp'],data['elev']) # theta-E data['thetae'] = equivalent_potential_temperature(data['pres'].values*units.hPa,data['temp'].values*units.degF,data['dpt'].values*units.degF) x_masked,y_masked,thetae = remove_nan_observations(xp,yp,data['thetae'].values) thex,they,thte = interpolate_to_grid(x_masked,y_masked,thetae,interp_type='cressman',\ minimum_neighbors=3,search_radius=200000,hres=18000) thte = np.ma.masked_where(np.isnan(thte),thte) # mixing ratio relh = relative_humidity_from_dewpoint(data['temp'].values*units.degF,data['dpt'].values*units.degF) mixr = mixing_ratio_from_relative_humidity(relh,data['temp'].values*units.degF,data['pres'].values*units.hPa) * 1000.0 x_masked,y_masked,mixrat = remove_nan_observations(xp,yp,mixr) mrx,mry,mrat = interpolate_to_grid(x_masked,y_masked,mixrat,interp_type='cressman',\ minimum_neighbors=3,search_radius=200000,hres=18000) mrat = np.ma.masked_where(np.isnan(mrat),mrat) # set up the state borders state_boundaries = cfeature.NaturalEarthFeature(category='cultural',\ name='admin_1_states_provinces_lines',scale='50m',facecolor='none') # SCALAR VARIABLES TO PLOT # variable names (will appear in plot title) variables = ['Temperature','Dewpoint','Wind Speed','Theta-E','Mixing Ratio'] # units (for colorbar label) unitlabels = ['F','F','kt','K','g/kg'] # list of actual variables to plot vardata = [temp,dewp,speed,thte,mrat] # tag in output filename varplots = ['temp','dewp','wspd','thte','mrat'] # levels: (lower,upper,step) levs = [[-20,105,5],[30,85,5],[0,70,5],[250,380,5],[0,22,2]] # colormaps colormaps = ['hsv_r','Greens','plasma','hsv_r','Greens'] for j in range(len(variables)): print("\t%s" % variables[j]) fig = plt.figure(figsize=(20, 10)) view = fig.add_subplot(1, 1, 1, projection=to_proj) # set up the map and plot the interpolated grids levels = list(range(levs[j][0],levs[j][1],levs[j][2])) cmap = plt.get_cmap(colormaps[j]) norm = BoundaryNorm(levels, ncolors=cmap.N, clip=True) labels = variables[j] + " (" + unitlabels[j] + ")" # add map features view.set_extent([west[i],east[i],south[i],north[i]]) view.add_feature(state_boundaries,edgecolor='black') view.add_feature(cfeature.OCEAN,zorder=-1) view.add_feature(cfeature.COASTLINE,zorder=2) view.add_feature(cfeature.BORDERS, linewidth=2,edgecolor='black') # plot the sea-level pressure cs = view.contour(slpgridx, slpgridy, slp, colors='k', levels=list(range(990, 1034, 4))) view.clabel(cs, inline=1, fontsize=12, fmt='%i') # plot the scalar background mmb = view.pcolormesh(tempx, tempy, vardata[j], cmap=cmap, norm=norm) fig.colorbar(mmb, shrink=.4, orientation='horizontal', pad=0.02, boundaries=levels, \ extend='both',label=labels) # plot the wind barbs view.barbs(windgridx, windgridy, uwind, vwind, alpha=.4, length=5,flip_barb=flip) # plot title and save view.set_title('%s (shaded), SLP, and Wind (valid %s)' % (variables[j],vt)) plt.savefig('/var/www/html/images/%s_%s.png' % (savenames[i],varplots[j]),bbox_inches='tight') # close everything fig.clear() view.clear() plt.close(fig) f.close() print("Script finished.")
# noL = list(launch.keys())[-8:] noL = list(launch.keys())[-12:] # colorL = ['r','o','y','g','b','p','k',''] cmap = cm.get_cmap('rainbow', 10) colorL = cmap(range(10)) i = 0 for no in noL: time = dtmdtm.strptime(launch[f"{no}"], "%Y/%m/%d %H:%M:%S") print(no, time) st = STreader(no, launch[f"{no}"], Path('../../data/ST')) try: P, T, Td, U, V = st.read() Theta = mcalc.potential_temperature(P, T).to('K') print(Theta) Thetae = mcalc.equivalent_potential_temperature(P, T, Td).to('K') ## UTC UTC = max((time + dtmdt(minutes=25)).hour, (time - dtmdt(minutes=25)).hour) - 8 LST = max((time + dtmdt(minutes=25)).hour, (time - dtmdt(minutes=25)).hour) if (UTC < 0): UTC += 24 title = (time - dtmdt(days=1)).strftime('%m%d') else: title = time.strftime('%m%d') ## main data plt.plot(Thetae, P,
def getData(self, time, model_vars, mdl2stnd, previous_data=None): ''' Name: awips_model_base Purpose: A function to get data from NAM40 model to create HDWX products Inputs: request : A DataAccessLayer request object time : List of datatime(s) for data to grab model_vars : Dictionary with variables/levels to get mdl2stnd : Dictionary to convert from model variable names to standardized names Outputs: Returns a dictionary containing all data Keywords: previous_data : Dictionary with data from previous time step ''' log = logging.getLogger(__name__) # Set up function for logger initTime, fcstTime = get_init_fcst_times(time[0]) data = { 'model': self._request.getLocationNames()[0], 'initTime': initTime, 'fcstTime': fcstTime } # Initialize empty dictionary log.info('Attempting to download {} data'.format(data['model'])) for var in model_vars: # Iterate over variables in the vars list log.debug('Getting: {}'.format(var)) self._request.setParameters(*model_vars[var]['parameters']) # Set parameters for the download request self._request.setLevels(*model_vars[var]['levels']) # Set levels for the download request response = DAL.getGridData(self._request, time) # Request the data for res in response: # Iterate over all data request responses varName = res.getParameter() # Get name of the variable in the response varLvl = res.getLevel() # Get level of the variable in the response varName = mdl2stnd[varName] # Convert variable name to local standarized name if varName not in data: data[varName] = {} # If variable name NOT in data dictionary, initialize new dictionary under key data[varName][varLvl] = res.getRawData() # Add data under level name try: # Try to unit = units(res.getUnit()) # Get units and convert to MetPy units except: # On exception unit = '?' # Set units to ? else: # If get units success data[varName][varLvl] *= unit # Get data and create MetPy quantity by multiplying by units log.debug( 'Got data for:\n Var: {}\n Lvl: {}\n Unit: {}'.format( varName, varLvl, unit)) data['lon'], data['lat'] = res.getLatLonCoords() # Get latitude and longitude values data['lon'] *= units('degree') # Add units of degree to longitude data['lat'] *= units('degree') # Add units of degree to latitude # Absolute vorticity dx, dy = lat_lon_grid_deltas(data['lon'], data['lat']) # Get grid spacing in x and y uTag = mdl2stnd[model_vars['wind']['parameters'][0]] # Get initial tag name for u-wind vTag = mdl2stnd[model_vars['wind']['parameters'][1]] # Get initial tag name for v-wind if (uTag in data) and ( vTag in data): # If both tags are in the data structure data['abs_vort'] = {} # Add absolute vorticity key for lvl in model_vars['wind'][ 'levels']: # Iterate over all leves in the wind data if (lvl in data[uTag]) and ( lvl in data[vTag] ): # If given level in both u- and v-wind dictionaries log.debug('Computing absolute vorticity at {}'.format(lvl)) data['abs_vort'][ lvl ] = \ absolute_vorticity( data[uTag][lvl], data[vTag][lvl], dx, dy, data['lat'] ) # Compute absolute vorticity # 1000 MB equivalent potential temperature if ('temperature' in data) and ( 'dewpoint' in data): # If temperature AND depoint data were downloaded data['theta_e'] = {} T, Td = 'temperature', 'dewpoint' if ('1000.0MB' in data[T]) and ( '1000.0MB' in data[Td] ): # If temperature AND depoint data were downloaded log.debug( 'Computing equivalent potential temperature at 1000 hPa') data['theta_e']['1000.0MB'] = equivalent_potential_temperature( 1000.0 * units('hPa'), data[T]['1000.0MB'], data[Td]['1000.0MB']) return data # MLCAPE log.debug('Computing mixed layer CAPE') T_lvl = list(data[T].keys()) Td_lvl = list(data[Td].keys()) levels = list(set(T_lvl).intersection(Td_lvl)) levels = [float(lvl.replace('MB', '')) for lvl in levels] levels = sorted(levels, reverse=True) nLvl = len(levels) if nLvl > 0: log.debug( 'Found {} matching levels in temperature and dewpoint data' .format(nLvl)) nLat, nLon = data['lon'].shape data['MLCAPE'] = np.zeros(( nLat, nLon, ), dtype=np.float32) * units('J/kg') TT = np.zeros(( nLvl, nLat, nLon, ), dtype=np.float32) * units('degC') TTd = np.zeros(( nLvl, nLat, nLon, ), dtype=np.float32) * units('degC') log.debug('Sorting temperature and dewpoint data by level') for i in range(nLvl): key = '{:.1f}MB'.format(levels[i]) TT[i, :, :] = data[T][key].to('degC') TTd[i, :, :] = data[Td][key].to('degC') levels = np.array(levels) * units.hPa depth = 100.0 * units.hPa log.debug('Iterating over grid boxes to compute MLCAPE') for j in range(nLat): for i in range(nLon): try: _, T_parc, Td_parc = mixed_parcel( levels, TT[:, j, i], TTd[:, j, i], depth=depth, interpolate=False, ) profile = parcel_profile(levels, T_parc, Td_parc) cape, cin = cape_cin(levels, TT[:, j, i], TTd[:, j, i], profile) except: log.warning( 'Failed to compute MLCAPE for lon/lat: {}; {}'. format(data['lon'][j, i], data['lat'][j, i])) else: data['MLCAPE'][j, i] = cape return data
skew.plot(p, Td, 'g') #plots the barbs my_interval = np.arange(100, 1000, 20) * units('mbar') ix = resample_nn_1d(p, my_interval) skew.plot_barbs(p[ix], u[ix], v[ix]) skew.ax.set_ylim(1075, 100) skew.ax.set_ylabel('Pressure (hPa)') lcl_pressure, lcl_temperature = mpcalc.lcl(p[0], T[0], Td[0]) #LCL pwat = mpcalc.precipitable_water(Td, p, 500 * units.hectopascal).to('in') #PWAT cape, cin = mpcalc.most_unstable_cape_cin(p[:], T[:], Td[:]) #MUCAPE cape_sfc, cin_sfc = mpcalc.surface_based_cape_cin(p, T, Td) #SBCAPE prof = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC') #parcel profile equiv_pot_temp = mpcalc.equivalent_potential_temperature(p, T, Td) #equivalent potential temperature el_pressure, el_temperature = mpcalc.el(p, T, Td) #elevated level lfc_pressure, lfc_temperature = mpcalc.lfc(p, T, Td) #LFC #calculates shear u_threekm_bulk_shear, v_threekm_bulk_shear = mpcalc.bulk_shear(p, u, v, hgt, bottom = min(hgt), depth = 3000 * units.meter) threekm_bulk_shear = mpcalc.get_wind_speed(u_threekm_bulk_shear, v_threekm_bulk_shear) u_onekm_bulk_shear, v_onekm_bulk_shear = mpcalc.bulk_shear(p, u, v, hgt, bottom = min(hgt), depth = 1000 * units.meter) onekm_bulk_shear = mpcalc.get_wind_speed(u_onekm_bulk_shear, v_onekm_bulk_shear) #shows the level of the LCL, LFC, and EL. skew.ax.text(T[0].magnitude, p[0].magnitude + 5, str(int(np.round(T[0].to('degF').magnitude))), fontsize = 'medium', horizontalalignment = 'left', verticalalignment = 'top', color = 'red') skew.ax.text(Td[0].magnitude, p[0].magnitude + 5, str(int(np.round(Td[0].to('degF').magnitude))), fontsize = 'medium', horizontalalignment = 'right', verticalalignment = 'top', color = 'green') skew.ax.text(lcl_temperature.magnitude + 5, lcl_pressure.magnitude, "---- LCL", fontsize = 'medium', verticalalignment = 'center') skew.ax.text(Td[0].magnitude - 10, p[0].magnitude, 'SFC: {}hPa ----'.format(p[0].magnitude), fontsize = 'medium', horizontalalignment = 'right', verticalalignment = 'center', color = 'black')