intercompare.py 45.89 KiB
import numpy as np
import xarray as xr
from util.setup import home_dir
from util.lon_lat_grid import earth_to_indexs
from util.util import haversine_np
#from deeplearning.amv_raob import get_profile_multi
from util.gfs_reader import get_vert_profile_s
import cartopy
from cartopy import *
import metpy.calc as mpcalc
import cartopy.crs as ccrs
from metpy.units import units
import h5py
import time
from scipy.interpolate import interp1d
from util.util import minimize_quadratic
from netCDF4 import Dataset
import datetime
from datetime import timezone
#-- AMV intercompare stuff ------------------------------------------
class MyGenericException(Exception):
def __init__(self, message):
self.message = message
amv_hdr_list = ['lat', 'lon', 'tbox', 'sbox', 'spd', 'dir', 'pres', 'lowl', 'mspd', 'mdir',
'alb', 'corr', 'tmet', 'perr', 'qi', 'cqi', 'qif']
raob_hdr_list = ['pres', 'temp', 'dir', 'spd']
raob_spd_idx = raob_hdr_list.index('spd')
raob_dir_idx = raob_hdr_list.index('dir')
amv_lon_idx = amv_hdr_list.index('lon')
amv_lat_idx = amv_hdr_list.index('lat')
amv_pres_idx = amv_hdr_list.index('pres')
raob_pres_idx = raob_hdr_list.index('pres')
amv_spd_idx = amv_hdr_list.index('spd')
amv_dir_idx = amv_hdr_list.index('dir')
amv_prs_idx = amv_hdr_list.index('pres')
amv_qi_idx = amv_hdr_list.index('qi')
amv_cqi_idx = amv_hdr_list.index('cqi')
amv_qif_idx = amv_hdr_list.index('qif')
amv_centers_list = ['EUM', 'BRZ', 'JMA', 'KMA', 'NOA', 'NWC']
def get_amv_nd(filename):
header = None
data = []
with open(filename) as file:
for line in file:
if header is None:
header = line
continue
toks = line.split(';')
id = float(toks[0])
lat = float(toks[1])
lon = float(toks[2])
tbox = float(toks[3])
sbox = float(toks[4])
spd = float(toks[5])
dir = float(toks[6])
pres = float(toks[7])
lowl = float(toks[8])
mspd = float(toks[9])
mdir = float(toks[10])
alb = float(toks[11])
corr = float(toks[12])
tmet = float(toks[13])
perr = float(toks[14])
hmet = float(toks[15])
qi = float(toks[16])
qif = float(toks[17])
cqi = float(toks[18])
if pres < 10 or pres > 1050:
continue
if lat < -90 or lat > 90:
continue
if lon < -180 or lon > 180:
continue
if spd < 0 or spd > 150:
continue
if dir < 0 or dir > 360:
continue
tup = (lat, lon, tbox, sbox, spd, dir, pres, lowl, mspd, mdir, alb, corr, tmet, perr, qi, cqi, qif)
data.append(tup)
return np.array(data)
def filter_amvs(amvs, qitype=amv_cqi_idx, qival=50, lat_range=None):
if lat_range is not None:
keep = np.logical_and(amvs[:, amv_lat_idx] > lat_range[0], amvs[:, amv_lat_idx] < lat_range[1])
if np.sum(keep) == 0:
return None
amvs = amvs[keep, :]
if qitype is None:
return amvs
keep = amvs[:, qitype] >= qival
if np.sum(keep) == 0:
return None
else:
return amvs[keep, :]
def get_raob_dict_cdf(pathname):
filename = os.path.split(pathname)[1]
dt_str = (((fname.split('raob_soundings'))[1]).split('.'))[0]
dto = datetime.datetime.strptime(dt_str, '%Y%m%d_%H%M').replace(tzinfo=timezone.utc)
rtgrp = Dataset(pathname, 'r', format='NETCDF3')
sta_lats_var = rtgrp['staLat']
sta_lats_var.set_always_mask(False)
sta_lats_var.set_auto_mask(False)
sta_lons_var = rtgrp['staLon']
sta_lons_var.set_always_mask(False)
sta_lons_var.set_auto_mask(False)
sta_lats = sta_lats_var[:]
sta_lons = sta_lons_var[:]
sta_msk = np.logical_and(sta_lats > -90.0, sta_lats < 90.0)
# sta_msk = np.invert(sta_lats._mask)
num_sta = np.sum(sta_msk)
sta_lats = sta_lats[sta_msk]
sta_lons = sta_lons[sta_msk]
# mandatory levels
man_levs = rtgrp['prMan']
man_levs = man_levs[:, :]
num_man_levs = rtgrp['numMand']
num_man_levs = num_man_levs[:]._data
man_temp = rtgrp['tpMan']
man_temp = man_temp[:, :]
man_spd = rtgrp['wsMan']
man_spd = man_spd[:, :]
man_dir = rtgrp['wdMan']
man_dir = man_dir[:, :]
# significant levels
sig_levs = rtgrp['prSigW']
sig_levs = sig_levs[:, :]
num_sig_levs = rtgrp['numSigW']
num_sig_levs = num_sig_levs[:]._data
sig_temp = rtgrp['tpSigW']
sig_temp = sig_temp[:, :]
sig_spd = rtgrp['wsSigW']
sig_spd = sig_spd[:, :]
sig_dir = rtgrp['wdSigW']
sig_dir = sig_dir[:, :]
man_levs = man_levs[sta_msk,]
num_man_levs = num_man_levs[sta_msk]
sig_levs = sig_levs[sta_msk,]
num_sig_levs = num_sig_levs[sta_msk]
man_temp = man_temp[sta_msk,]
man_spd = man_spd[sta_msk,]
man_dir = man_dir[sta_msk,]
sig_temp = sig_temp[sta_msk,]
sig_spd = sig_spd[sta_msk,]
sig_dir = sig_dir[sta_msk,]
raob_dct = {}
for k in range(num_sta):
lon = sta_lons[k]
lat = sta_lats[k]
vld_man = np.invert(man_levs[k]._mask)
vld_man = np.logical_and(vld_man, np.invert(man_spd[k]._mask))
vld_man = np.logical_and(vld_man, np.invert(man_dir[k]._mask))
vld_sig = np.invert(sig_levs[k]._mask)
vld_sig = np.logical_and(vld_sig, np.invert(sig_spd[k]._mask))
vld_sig = np.logical_and(vld_sig, np.invert(sig_dir[k]._mask))
vld_man_levs = man_levs[k, vld_man]
vld_man_spd = man_spd[k, vld_man]
vld_man_dir = man_dir[k, vld_man]
vld_man_temp = man_temp[k, vld_man]
s_idxs = np.argsort(vld_man_levs)
s_man_levs = vld_man_levs[s_idxs]
s_man_spd = vld_man_spd[s_idxs]
s_man_dir = vld_man_dir[s_idxs]
s_man_temp = vld_man_temp[s_idxs]
vld_sig_levs = sig_levs[k, vld_sig]
vld_sig_spd = sig_spd[k, vld_sig]
vld_sig_dir = sig_dir[k, vld_sig]
vld_sig_temp = sig_temp[k, vld_sig]
all_levs = np.append(s_man_levs, vld_sig_levs)
all_temp = np.append(s_man_temp, vld_sig_temp)
all_spd = np.append(s_man_spd, vld_sig_spd)
all_dir = np.append(s_man_dir, vld_sig_dir)
if len(all_levs) == 0:
continue
s_idxs = np.argsort(all_levs)
all_levs = all_levs[s_idxs]
all_temp = all_temp[s_idxs]
all_spd = all_spd[s_idxs]
all_dir = all_dir[s_idxs]
all_levs = all_levs[::-1]
all_temp = all_temp[::-1]
all_spd = all_spd[::-1]
all_dir = all_dir[::-1]
raob = np.stack([all_levs._data, all_temp._data, all_spd._data, all_dir._data], axis=1)
raob_dct[(lat, lon)] = raob
rtgrp.close()
return raob_dct, dto.timestamp()
def get_raob_dict(filename):
header = None
data = []
raob_dict = {}
with open(filename) as file:
for line in file:
if header is None:
header = line
continue
toks = line.split()
lat = float(toks[0])
lon = float(toks[1])
pres = float(toks[2])
temp = float(toks[3])
dir = float(toks[4])
spd = float(toks[5])
tup = (lat, lon, pres, temp, dir, spd)
data.append(tup)
file.close()
key = None
for tup in data:
loc = (tup[0], tup[1])
rtup = (tup[2], tup[3], tup[4], tup[5])
if loc != key:
lst = []
lst.append(rtup)
key = loc
raob_dict[key] = lst
else:
lst = raob_dict.get(loc)
lst.append(rtup)
return raob_dict_to_nd(raob_dict)
def raob_dict_to_nd(raob_dict):
loc_keys = raob_dict.keys()
loc_to_nd = {}
for key in loc_keys:
obs_lst = raob_dict.get(key)
loc_to_nd[key] = np.array(obs_lst)
return loc_to_nd
def amv_bulk_stats(amvs, qitype=amv_cqi_idx, qival=50):
idx = amv_hdr_list.index('lat')
lat_min = amvs[:, idx].min()
lat_max = amvs[:, idx].max()
print(lat_min, lat_max)
idx = amv_hdr_list.index('lon')
lon_min = amvs[:, idx].min()
lon_max = amvs[:, idx].max()
print(lon_min, lon_max)
good = amvs[:, qitype] >= qival
num_good = np.sum(good)
good_amvs = amvs[good, :]
print('------------------------------')
print('num good amvs: ', num_good)
sidx = amv_hdr_list.index('spd')
spd_min = good_amvs[:, sidx].min()
spd_max = good_amvs[:, sidx].max()
print('spd min/max/mean: ', spd_min, spd_max, np.average(good_amvs[:, sidx]))
pidx = amv_hdr_list.index('pres')
p_min = good_amvs[:, pidx].min()
p_max = good_amvs[:, pidx].max()
print('pres min/max/mean: ', p_min, p_max, np.average(good_amvs[:, pidx]))
low = good_amvs[:, pidx] >= 700
mid = np.logical_and(good_amvs[:, pidx] < 700, good_amvs[:, pidx] > 400)
hgh = good_amvs[:, pidx] <= 400
n_low = np.sum(low)
n_mid = np.sum(mid)
n_hgh = np.sum(hgh)
print('% low: ', 100.0*(n_low/num_good))
print('% mid: ', 100.0*(n_mid/num_good))
print('% hgh: ', 100.0*(n_hgh/num_good))
print('---------------------------')
print('Low Spd min/max/mean: ', good_amvs[low, sidx].min(), good_amvs[low, sidx].max(), good_amvs[low,sidx].mean())
print('Low Press min/max/mean: ', good_amvs[low, pidx].min(), good_amvs[low, pidx].max(), good_amvs[low, pidx].mean())
print('---------------------------')
print('Mid Spd min/max/mean: ', good_amvs[mid, sidx].min(), good_amvs[mid, sidx].max(), good_amvs[mid, sidx].mean())
print('Mid Press min/max/mean: ', good_amvs[mid, pidx].min(), good_amvs[mid, pidx].max(), good_amvs[mid, pidx].mean())
print('---------------------------')
print('Hgh Spd min/max/mean: ', good_amvs[hgh, sidx].min(), good_amvs[hgh, sidx].max(), good_amvs[hgh, sidx].mean())
print('Hgh Press min/max/mean: ', good_amvs[hgh, pidx].min(), good_amvs[hgh, pidx].max(), good_amvs[hgh, pidx].mean())
print('----------------------------')
press_diff_threshold = 100.0 # mb
dist_threshold = 150.0 # km
km_per_deg = 111.0
# Find raobs within threshold distance for each (lat, lon) point
def get_raob_neighbors(lats, lons, raob_dct, dist_threshold=150):
nbor_dct = {}
num_pts = lats.shape[0]
keys = list(raob_dct.keys())
rlat_s = []
rlon_s = []
for ll_tup in keys:
rlat = ll_tup[0]
rlon = ll_tup[1]
rlat_s.append(rlat)
rlon_s.append(rlon)
rlats = np.array(rlat_s)
rlons = np.array(rlon_s)
for j in range(num_pts):
alat = lats[j]
alon = lons[j]
dist = haversine_np(rlons, rlats, alon, alat)
ridxs = (np.nonzero(dist < dist_threshold))[0]
if ridxs.shape[0] != 0:
nbor_keys = []
for i in range(ridxs.shape[0]):
nbor_keys.append(keys[ridxs[i]])
nbor_dct[j] = (nbor_keys, dist[ridxs])
else:
nbor_dct[j] = None
return nbor_dct
# Find points (lat, lon) within threshold distance to each raob
def get_neighbors_to_raob(lats, lons, raob_dct):
nbor_dct = {}
keys = list(raob_dct.keys())
for ll_tup in keys:
rlat = ll_tup[0]
rlon = ll_tup[1]
dist = haversine_np(lons, lats, rlon, rlat)
idxs = (np.nonzero(dist < dist_threshold))[0]
if idxs.shape[0] != 0:
nbor_keys = []
for i in range(idxs.shape[0]):
nbor_keys.append(idxs[i])
nbor_dct[ll_tup] = (nbor_keys, dist[idxs])
else:
nbor_dct[ll_tup] = None
return nbor_dct
def amv_raob_diff_2(amvs, raob_dct):
aspd = amvs[:, amv_spd_idx]
adir = amvs[:, amv_dir_idx]
aprs = amvs[:, amv_prs_idx]
alat = amvs[:, amv_lat_idx]
alon = amvs[:, amv_lon_idx]
spd_diffs, dir_diffs = amv_raob_diff(alat, alon, aspd, adir, aprs, raob_dct)
return spd_diffs, dir_diffs
def amv_raob_diff(amv_lat, amv_lon, amv_spd, amv_dir, amv_press, raob_dct):
num_amvs = amv_lat.shape[0]
amv_u = -amv_spd * np.sin((np.pi/180.0) * amv_dir)
amv_v = -amv_spd * np.cos((np.pi/180.0) * amv_dir)
raob_nbor_dct = get_raob_neighbors(amv_lat, amv_lon, raob_dct)
dir_diffs = []
spd_diffs = []
u_diffs = []
v_diffs = []
prs_diffs = []
for j in range(num_amvs): # compute stats
tup = raob_nbor_dct[j]
if tup is not None:
nbor_keys = tup[0]
nbor_dsts = tup[1]
for ll_tup in nbor_keys:
raob = raob_dct.get(ll_tup)
pdiff = amv_press[j] - raob[:, raob_pres_idx]
lev_idx = np.argmin(np.abs(pdiff))
if np.abs(pdiff[lev_idx]) > press_diff_threshold:
continue
aspd = amv_spd[j]
adir = amv_dir[j]
rdir = raob[lev_idx, raob_dir_idx]
rspd = raob[lev_idx, raob_spd_idx]
ddiff = direction_difference(adir, rdir)
dir_diffs.append(ddiff)
spd_diffs.append(aspd - rspd)
au = amv_u[j]
av = amv_v[j]
ru = -rspd * np.sin((np.pi / 180.0) * rdir)
rv = -rspd * np.cos((np.pi / 180.0) * rdir)
udiff = au - ru
vdiff = av - rv
u_diffs.append(udiff)
v_diffs.append(vdiff)
prs_diffs.append(pdiff[lev_idx])
num = len(u_diffs)
dir_diffs = np.array(dir_diffs)
spd_diffs = np.array(spd_diffs)
prs_diffs = np.array(prs_diffs)
u_diffs = np.array(u_diffs)
v_diffs = np.array(v_diffs)
# spd_bias = np.sqrt(np.sum(u_diffs)**2 + np.sum(v_diffs)**2) / num
# spd_rms = np.sqrt((np.sqrt(np.sum(np.array(u_diffs) ** 2)/num))**2 + (np.sqrt(np.sum(np.array(v_diffs) ** 2)/num))**2)
# dir_bias = np.average(dir_diffs)
print('num amvs: ', num_amvs)
print('num samples: ', num)
spd_mean = np.mean(spd_diffs)
spd_std = np.std(spd_diffs)
print('spd MAD/bias/rms: ', np.average(np.abs(spd_diffs)), spd_mean, np.sqrt(spd_mean**2 + spd_std**2))
print('-----------------')
dir_mean = np.mean(dir_diffs)
print('dir bias: ', dir_mean)
print('-----------------------')
vd = np.sqrt(u_diffs**2 + v_diffs**2)
vd_mean = np.mean(vd)
vd_std = np.std(vd)
print('VD bias/rms: ', vd_mean, np.sqrt(vd_mean**2 + vd_std**2))
print('--------------')
pd_std = np.std(prs_diffs)
pd_mean = np.mean(prs_diffs)
print('press bias/rms ', pd_mean, np.sqrt(pd_mean**2 + pd_std**2))
print('------------------------------------------')
return spd_diffs, dir_diffs
def run_best_fit(amvs, raob_dct, dist_threshold=200, min_num_levs=20):
num_amvs = amvs.shape[0]
bestfits = []
raob_nbor_dct = get_raob_neighbors(amvs[:, amv_lat_idx], amvs[:, amv_lon_idx], raob_dct, dist_threshold=dist_threshold)
for j in range(num_amvs):
tup = raob_nbor_dct[j]
if tup is not None:
nbor_keys = tup[0]
nbor_dsts = tup[1]
s_i = np.argsort(nbor_dsts).tolist()
for k in range(len(nbor_keys)):
dist = nbor_dsts[s_i[k]]
ll_tup = nbor_keys[s_i[k]]
raob = raob_dct.get(ll_tup)
if raob.shape[0] < min_num_levs:
continue
rspd = raob[:, raob_spd_idx]
rdir = raob[:, raob_dir_idx]
rprs = raob[:, raob_pres_idx]
aspd = amvs[j, amv_spd_idx]
adir = amvs[j, amv_dir_idx]
aprs = amvs[j, amv_prs_idx]
alat = amvs[j, amv_lat_idx]
alon = amvs[j, amv_lon_idx]
bf = best_fit(aspd, adir, aprs, alat, alon, rspd, rdir, rprs)
bf = (j, bf[0], bf[1], bf[2], bf[3])
if bf[4] == 0:
bestfits.append(bf)
break
return bestfits
def run_amv_clavr_compare(amvs, clvr_filename):
h5file = h5py.File(clvr_filename, 'r')
# Keep this for reference
# lons = h5file['longitude'][0:2500, :]
# lats = h5file['latitude'][0:2500, :]
# lons = np.where(lons < 0, lons + 360, lons)
# lons = np.where(lons == -639, np.nan, lons)
# lats = np.where(lats == -999.0, np.nan, lats)
# ll_grid = LonLatGrid(lons, lats)
t0 = int(round(time.time() * 1000))
t1 = int(round(time.time() * 1000))
a_lons = []
a_lats = []
for k in range(5000):
lon = amvs[k, amv_lon_idx]
lat = amvs[k, amv_lat_idx]
a_lons.append(lon)
a_lats.append(lat)
a_lons = np.array(a_lons)
a_lats = np.array(a_lats)
idxs = earth_to_indexs(a_lons, a_lats, 5500)
print('search time: ', (int(round(time.time() * 1000)) - t1))
print('--------------')
def run_best_fit_gfs_all(amvs, gfs_filename):
num_centers = len(amvs)
bfs_s = []
for k in range(num_centers):
bfs = run_best_fit_gfs(amvs[k], gfs_filename)
bfs_s.append(bfs)
return bfs_s
def run_best_fit_gfs(amvs, gfs_filename, amv_lat_idx=amv_lat_idx, amv_lon_idx=amv_lon_idx, amv_prs_idx=amv_prs_idx,
amv_spd_idx=amv_spd_idx, amv_dir_idx=amv_dir_idx, method='nearest'):
xr_dataset = xr.open_dataset(gfs_filename)
num_amvs = amvs.shape[0]
bestfits = []
gfs_press = xr_dataset['pressure levels']
gfs_press = gfs_press.data
gfs_press = gfs_press[::-1]
uv_wind = get_vert_profile_s(xr_dataset, ['u-wind', 'v-wind'], amvs[:, amv_lon_idx], amvs[:, amv_lat_idx], method=method)
uv_wind = uv_wind.data
wspd, wdir = spd_dir_from_uv(uv_wind[0,:,:], uv_wind[1,:,:])
wspd = wspd.magnitude
wdir = wdir.magnitude
wspd = wspd[:,::-1]
wdir = wdir[:,::-1]
for j in range(num_amvs):
aspd = amvs[j, amv_spd_idx]
adir = amvs[j, amv_dir_idx]
aprs = amvs[j, amv_prs_idx]
alat = amvs[j, amv_lat_idx]
alon = amvs[j, amv_lon_idx]
gfs_spd = wspd[j]
gfs_dir = wdir[j]
bf = best_fit(aspd, adir, aprs, alat, alon, gfs_spd, gfs_dir, gfs_press)
# bf = (j, bf[0], bf[1], bf[2], bf[3])
# if bf[4] == 0:
# bestfits.append(bf)
bestfits.append(bf)
return bestfits
def raob_gfs_diff(raob_dct, gfs_filename):
r_press = 900.0
n_raobs = len(raob_dct)
keys = list(raob_dct.keys())
rb_lats = []
rb_lons = []
rb_spd = []
rb_dir = []
for ll_tup in keys:
prof = raob_dct[ll_tup]
raob_pres_prof = raob_dct[ll_tup][:, raob_pres_idx]
pdiff = r_press - raob_pres_prof
lev_idx = np.argmin(np.abs(pdiff))
rb_lats.append(ll_tup[0])
rb_lons.append(ll_tup[1])
rb_spd.append(prof[lev_idx, raob_spd_idx])
rb_dir.append(prof[lev_idx, raob_dir_idx])
rb_lons = np.array(rb_lons)
rb_lats = np.array(rb_lats)
rb_spd = np.array(rb_spd)
rb_dir = np.array(rb_dir)
xr_dataset = xr.open_dataset(gfs_filename)
gfs_press = xr_dataset['pressure levels']
g_lev_idx = np.argmin(np.abs(500 - gfs_press))
uv_wind = get_profile_multi(xr_dataset, ['u-wind', 'v-wind'], rb_lons, rb_lats)
uv_wind = uv_wind.data
wspd, wdir = spd_dir_from_uv(uv_wind[0,:,:], uv_wind[1,:,:])
g_wspd = wspd.magnitude
g_wdir = wdir.magnitude
dir_diffs = []
spd_diffs = []
u_diffs = []
v_diffs = []
for j in range(n_raobs):
rspd = rb_spd[j]
rdir = rb_dir[j]
gspd = g_wspd[j, g_lev_idx]
gdir = g_wdir[j, g_lev_idx]
print(rspd, gspd, ':', rdir, gdir)
ddiff = direction_difference(gdir, rdir)
dir_diffs.append(ddiff)
spd_diffs.append(gspd - rspd)
gu = -gspd * np.sin((np.pi / 180.0) * gdir)
gv = -gspd * np.cos((np.pi / 180.0) * gdir)
ru = -rspd * np.sin((np.pi / 180.0) * rdir)
rv = -rspd * np.cos((np.pi / 180.0) * rdir)
udiff = gu - ru
vdiff = gv - rv
u_diffs.append(udiff)
v_diffs.append(vdiff)
num = len(u_diffs)
dir_diffs = np.array(dir_diffs)
spd_diffs = np.array(spd_diffs)
u_diffs = np.array(u_diffs)
v_diffs = np.array(v_diffs)
# spd_bias = np.sqrt(np.sum(u_diffs)**2 + np.sum(v_diffs)**2) / num
# spd_rms = np.sqrt((np.sqrt(np.sum(np.array(u_diffs) ** 2)/num))**2 + (np.sqrt(np.sum(np.array(v_diffs) ** 2)/num))**2)
# dir_bias = np.average(dir_diffs)
print('num rabos: ', n_raobs)
print('num samples: ', num)
spd_mean = np.mean(spd_diffs)
spd_std = np.std(spd_diffs)
print('spd MAD/bias/rms: ', np.average(np.abs(spd_diffs)), spd_mean, np.sqrt(spd_mean**2 + spd_std**2))
print('-----------------')
dir_mean = np.mean(dir_diffs)
print('dir bias: ', dir_mean)
print('-----------------------')
vd = np.sqrt(u_diffs**2 + v_diffs**2)
vd_mean = np.mean(vd)
vd_std = np.std(vd)
print('VD bias/rms: ', vd_mean, np.sqrt(vd_mean**2 + vd_std**2))
print('--------------')
return None
def amv_gfs_diff(amvs, gfs_filename):
xr_dataset = xr.open_dataset(gfs_filename)
num_amvs = amvs.shape[0]
gfs_press = xr_dataset['pressure levels']
uv_wind = get_profile_multi(xr_dataset, ['u-wind', 'v-wind'], amvs[:, amv_lon_idx], amvs[:, amv_lat_idx])
uv_wind = uv_wind.data
wspd, wdir = spd_dir_from_uv(uv_wind[0,:,:], uv_wind[1,:,:])
wspd = wspd.magnitude
wdir = wdir.magnitude
amv_u = -amvs[:, amv_spd_idx] * np.sin((np.pi / 180.0) * amvs[:, amv_dir_idx])
amv_v = -amvs[:, amv_spd_idx] * np.cos((np.pi / 180.0) * amvs[:, amv_dir_idx])
dir_diffs = []
spd_diffs = []
u_diffs = []
v_diffs = []
prs_diffs = []
for j in range(num_amvs):
aspd = amvs[j, amv_spd_idx]
adir = amvs[j, amv_dir_idx]
aprs = amvs[j, amv_prs_idx]
pdiff = aprs - gfs_press
lev_idx = np.argmin(np.abs(pdiff))
if np.abs(pdiff[lev_idx]) > press_diff_threshold:
continue
rspd = wspd[j, lev_idx]
rdir = wdir[j, lev_idx]
ddiff = direction_difference(adir, rdir)
dir_diffs.append(ddiff)
spd_diffs.append(aspd - rspd)
au = amv_u[j]
av = amv_v[j]
ru = -rspd * np.sin((np.pi / 180.0) * rdir)
rv = -rspd * np.cos((np.pi / 180.0) * rdir)
udiff = au - ru
vdiff = av - rv
u_diffs.append(udiff)
v_diffs.append(vdiff)
prs_diffs.append(pdiff[lev_idx])
num = len(u_diffs)
dir_diffs = np.array(dir_diffs)
spd_diffs = np.array(spd_diffs)
prs_diffs = np.array(prs_diffs)
u_diffs = np.array(u_diffs)
v_diffs = np.array(v_diffs)
# spd_bias = np.sqrt(np.sum(u_diffs)**2 + np.sum(v_diffs)**2) / num
# spd_rms = np.sqrt((np.sqrt(np.sum(np.array(u_diffs) ** 2)/num))**2 + (np.sqrt(np.sum(np.array(v_diffs) ** 2)/num))**2)
# dir_bias = np.average(dir_diffs)
print('num amvs: ', num_amvs)
print('num samples: ', num)
spd_mean = np.mean(spd_diffs)
spd_std = np.std(spd_diffs)
print('spd MAD/bias/rms: ', np.average(np.abs(spd_diffs)), spd_mean, np.sqrt(spd_mean**2 + spd_std**2))
print('-----------------')
dir_mean = np.mean(dir_diffs)
print('dir bias: ', dir_mean)
print('-----------------------')
vd = np.sqrt(u_diffs**2 + v_diffs**2)
vd_mean = np.mean(vd)
vd_std = np.std(vd)
print('VD bias/rms: ', vd_mean, np.sqrt(vd_mean**2 + vd_std**2))
print('--------------')
pd_std = np.std(prs_diffs)
pd_mean = np.mean(prs_diffs)
print('press bias/rms ', pd_mean, np.sqrt(pd_mean**2 + pd_std**2))
print('------------------------------------------')
return None
# ddiff = np.abs(adir - rdir)
# if ddiff > 180:
# ddiff = 360 - ddiff
# if rdir < adir:
# ddiff = -1 * ddiff
# else:
# if rdir > adir:
# ddiff = -1 * ddiff
def direction_difference(dir_a, dir_b):
diff = np.abs(dir_a - dir_b)
d180 = diff > 180
diff = np.where(d180, 360 - diff, diff)
diff = np.where(d180, np.where(dir_b < dir_a, -1 * diff, diff), np.where(dir_b > dir_a, -1 * diff, diff))
return diff
def get_amv_winds_match(dist_threshold=150, qitype=amv_cqi_idx, qival=50, lat_range=[-60, 60]):
#----- match all to EUM
amvs_eum = get_amv_nd('/Users/tomrink/data/amv_intercompare/EUM321_csv.csv')
amvs_brz = get_amv_nd('/Users/tomrink/data/amv_intercompare/BRZCPTECfin_121_csv.csv')
amvs_jma = get_amv_nd('/Users/tomrink/data/amv_intercompare/JMA421_csv.csv')
amvs_kma = get_amv_nd('/Users/tomrink/data/amv_intercompare/KMA521NI_csv.csv')
amvs_noa = get_amv_nd('/Users/tomrink/data/amv_intercompare/NOA621_csv.csv')
amvs_nwc = get_amv_nd('/Users/tomrink/data/amv_intercompare/NWC721_csv.csv')
amvs_eum = filter_amvs(amvs_eum, qitype=qitype, qival=qival, lat_range=lat_range)
amvs_brz = filter_amvs(amvs_brz, qitype=qitype, qival=qival, lat_range=lat_range)
amvs_jma = filter_amvs(amvs_jma, qitype=qitype, qival=qival, lat_range=lat_range)
amvs_kma = filter_amvs(amvs_kma, qitype=qitype, qival=qival, lat_range=lat_range)
amvs_nwc = filter_amvs(amvs_nwc, qitype=qitype, qival=qival, lat_range=lat_range)
amvs_noa = filter_amvs(amvs_noa, qitype=qitype, qival=qival, lat_range=lat_range)
lat_idx = amv_hdr_list.index('lat')
lon_idx = amv_hdr_list.index('lon')
num_eum = amvs_eum.shape[0]
print('num EUM amvs: ', num_eum)
eum_idxs = []
brz_idxs = []
jma_idxs = []
kma_idxs = []
noa_idxs = []
nwc_idxs = []
cnt = 0
for i in range(num_eum):
dist = haversine_np(amvs_nwc[:, lon_idx], amvs_nwc[:, lat_idx], amvs_eum[i, lon_idx], amvs_eum[i, lat_idx])
i_nwc = np.argmin(dist)
dist = dist[i_nwc]
if dist < dist_threshold:
dist = haversine_np(amvs_brz[:, lon_idx], amvs_brz[:, lat_idx], amvs_eum[i, lon_idx], amvs_eum[i, lat_idx])
i_brz = np.argmin(dist)
dist = dist[i_brz]
if dist < dist_threshold:
dist = haversine_np(amvs_jma[:, lon_idx], amvs_jma[:, lat_idx], amvs_eum[i, lon_idx], amvs_eum[i, lat_idx])
i_jma = np.argmin(dist)
dist = dist[i_jma]
if dist < dist_threshold:
dist = haversine_np(amvs_noa[:, lon_idx], amvs_noa[:, lat_idx], amvs_eum[i, lon_idx], amvs_eum[i, lat_idx])
i_noa = np.argmin(dist)
dist = dist[i_noa]
if dist < dist_threshold:
dist = haversine_np(amvs_kma[:, lon_idx], amvs_kma[:, lat_idx], amvs_eum[i, lon_idx], amvs_eum[i, lat_idx])
i_kma = np.argmin(dist)
dist = dist[i_kma]
if dist < dist_threshold:
eum_idxs.append(i)
brz_idxs.append(i_brz)
kma_idxs.append(i_kma)
jma_idxs.append(i_jma)
noa_idxs.append(i_noa)
nwc_idxs.append(i_nwc)
cnt += 1
print('total num matches: ', cnt)
eum_idxs = np.array(eum_idxs)
brz_idxs = np.array(brz_idxs)
kma_idxs = np.array(kma_idxs)
jma_idxs = np.array(jma_idxs)
noa_idxs = np.array(noa_idxs)
nwc_idxs = np.array(nwc_idxs)
amvs_dict = {}
amvs_dict['EUM'] = amvs_eum[eum_idxs, :]
amvs_dict['BRZ'] = amvs_brz[brz_idxs, :]
amvs_dict['KMA'] = amvs_kma[kma_idxs, :]
amvs_dict['JMA'] = amvs_jma[jma_idxs, :]
amvs_dict['NOA'] = amvs_noa[noa_idxs, :]
amvs_dict['NWC'] = amvs_nwc[nwc_idxs, :]
return amvs_dict
def run_best_fit_all(amvs_dict, raobs_pathname, dist_threshold=200, min_num_levs=20):
raob_dct = get_raob_dict(raobs_pathname)
print('got raobs')
bfs_dct = {}
for key in amv_centers_list:
amvs = amvs_dict.get(key)
bfs = run_best_fit(amvs, raob_dct, dist_threshold=dist_threshold, min_num_levs=min_num_levs)
print('done: ', key)
bfs_dct[key] = bfs
return bfs_dct
def best_fit(amv_spd, amv_dir, amv_prs, amv_lat, amv_lon, fcst_spd, fcst_dir, fcst_prs, verbose=False):
"""Finds the background model best fit pressure associated with the AMV.
The model best-fit pressure is the height (in pressure units) where the
vector difference between the observed AMV and model background is a
minimum. This calculation may only work approximately 1/3 of the time.
Reference:
Salonen et al (2012), "Characterising AMV height assignment error by
comparing best-fit pressure statistics from the Met Office and ECMWF
System." Proceedings of the 11th International Winds Workshop,
Auckland, New Zealand, 20-24 February 2012.
Input contained in amv_data and fcst_data:
amv_spd - AMV speed m/s
amv_dir - AMV direction deg
amv_prs - AMV pressure hPa
fcst_spd - (level) forecast speed m/s
fcst_dir - (level) forecast direction (deg)
fcst_prs - (level) forecast pressure (hPa)
Output contained in bf_data:
SatwindBestFitU - AMV best fit U component m, unconstrained value is undef
SatwindBestFitV - AMV best fit V component m, unconstrained value is undef
bfit_prs - AMV best fit pressure m/s, unconstrained value is undef
flag - 0 found, 1 not contrained, 2 vec diff minimum not met, 3 failed to find suitable fcst pressure match
History:
10/2012 - Steve Wanzong - Created in Fortran
10/2013 - Sharon Nebuda - rewritten for python
"""
undef = -9999.0
fcst_num_levels = fcst_spd.shape[0]
SatwindBestFitPress = undef
SatwindBestFitU = undef
SatwindBestFitV = undef
PressDiff = 150. # pressure above and below AMV to look for fit
TopPress = 50. # highest level to allow search
flag = 3
bf_data = (undef, undef, undef, flag)
if amv_prs < TopPress:
if verbose:
print('AMV location lat,lon,prs ({0},{1},{2}) is higher than pressure {3}'.format(amv_lat,amv_lon,amv_prs,TopPress))
return bf_data
# Calculate the pressure +/- 150 hPa from the AMV pressure.
PressMax = amv_prs + PressDiff
PressMin = max((amv_prs-PressDiff), TopPress)
# 1d array of indicies to consider for best fit location
kk = np.where((fcst_prs<PressMax) & (fcst_prs>PressMin))
if len(kk[0]) == 0:
if verbose:
print('AMV location lat,lon,prs ({0},{1},{2}) failed to find fcst prs around AMV'.format(amv_lat,amv_lon,amv_prs))
return bf_data
# Diagnostic field: Find the model minimum speed and maximum speed within PressDiff of the AMV.
if verbose:
SatwindMinSpeed = min(fcst_spd[kk])
SatwindMaxSpeed = max(fcst_spd[kk])
# Compute U anv V for both AMVs and forecast
dr = 0.0174533 # pi/180
amv_uwind = -amv_spd * np.sin(dr*amv_dir)
amv_vwind = -amv_spd * np.cos(dr*amv_dir)
fcst_uwind = -fcst_spd * np.sin(dr*fcst_dir)
fcst_vwind = -fcst_spd * np.cos(dr*fcst_dir)
# Calculate the vector difference between the AMV and model background at all levels.
VecDiff = np.sqrt((amv_uwind - fcst_uwind) ** 2 + (amv_vwind - fcst_vwind) ** 2)
# Find the model level of best-fit pressure, from the minimum vector difference.
MinVecDiff = min(VecDiff[kk])
imin = np.where(VecDiff == MinVecDiff)
if imin[0].size == 0:
if verbose:
print('AMV location lat,lon,prs ({0},{1},{2}) failed to find min vector difference in layers around AMV'.format(amv_lat,amv_lon,amv_prs))
return bf_data
imin = imin[0][0]
# Use a parabolic fit to find the best-fit pressure.
# p2 - Minimized model pressure at level imin (hPa)
# v2 - Minimized vector difference at level imin (m/s)
# p1 - 1 pressure level lower in atmosphere than p2
# p3 - 1 pressure level above in atmosphere than p2
# v1 - Vector difference 1 pressure level lower than p2
# v3 - Vector difference 1 pressure level above than p2
p2 = fcst_prs[imin]
v2 = VecDiff[imin]
SatwindBestFitPress = p2
SatwindBestFitU = fcst_uwind[imin]
SatwindBestFitV = fcst_vwind[imin]
# assumes fcst data level 0 at surface and (fcst_num_levels-1) at model top
# if bottom model level
if imin == 0 or imin == fcst_num_levels - 1:
if verbose:
print('AMV location lat,lon,alt ({0},{1},{2}) min vector difference at top/bottom'.format(amv_lat,amv_lon,amv_prs))
else:
p3 = fcst_prs[imin+1]
p1 = fcst_prs[imin-1]
v3 = VecDiff[imin+1]
v1 = VecDiff[imin-1]
if p3 > TopPress and v1 != v2 and v2 != v3: # check not collinear, above allowed region
SatwindBestFitPress = p2 - (0.5 *
((((p2 - p1) * (p2 - p1) * (v2 - v3)) - ((p2 - p3) * (p2 - p3) * (v2 - v1))) /
(((p2 - p1) * (v2 - v3)) - ((p2 - p3) * (v2 - v1)))))
if (SatwindBestFitPress < p3) or (SatwindBestFitPress > p1):
if (verbose):
print('Best Fit not found between two pressure layers')
print('SatwindBestFitPress {0} p1 {1} p2 {2} p3 {3} imin {4}'.format(SatwindBestFitPress,p1,p2,p3,imin))
SatwindBestFitPress = p2
# Find best fit U and V by linear interpolation.
if p2 != SatwindBestFitPress:
if p2 < SatwindBestFitPress:
LevBelow = imin - 1
LevAbove = imin
Prop = (SatwindBestFitPress - p1) / (p2 - p1)
else:
LevBelow = imin
LevAbove = imin + 1
Prop = (SatwindBestFitPress - p2) / (p3 - p2)
SatwindBestFitU = fcst_uwind[LevBelow] * (1.0 - Prop) + fcst_uwind[LevAbove] * Prop
SatwindBestFitV = fcst_vwind[LevBelow] * (1.0 - Prop) + fcst_vwind[LevAbove] * Prop
SatwindGoodConstraint = 1
flag = 0
# Check for overall good agreement
vdiff = np.sqrt((fcst_uwind - SatwindBestFitU) ** 2 + (fcst_vwind - SatwindBestFitV) ** 2)
min_vdiff = min(vdiff)
if min_vdiff > 4.0:
SatwindGoodConstraint = 0
flag = 2
# Check for a substantial secondary local minimum or if local minimum is too broad
if SatwindGoodConstraint == 1:
mm = np.where(fcst_prs > (SatwindBestFitPress + 100))[0]
nn = np.where(fcst_prs < (SatwindBestFitPress - 100))[0]
if (np.sum(vdiff[mm] < (min_vdiff + 2.0)) + np.sum(vdiff[nn] < (min_vdiff + 2.0))) > 0:
SatwindGoodConstraint = 0
flag = 1
if SatwindGoodConstraint == 1:
bfit_prs = SatwindBestFitPress
bfit_u = SatwindBestFitU
bfit_v = SatwindBestFitV
else:
bfit_prs = undef
bfit_u = undef
bfit_v = undef
if verbose:
print('*** AMV best-fit *********************************')
print('AMV -> p/minspd/maxspd: {0} {1} {2}'.format(amv_prs,SatwindMinSpeed,SatwindMaxSpeed))
# print('Bestfit -> p1,p2,p3,v1,v2,v3: {0} {1} {2} {3} {4} {5}'.format(p1,p2,p3,v1,v2,v3))
print('Bestfit -> pbest,bfu,bfv,amvu,amvv,bgu,bgv: {0} {1} {2} {3} {4} {5} {6}'.format(
SatwindBestFitPress,SatwindBestFitU,SatwindBestFitV,amv_uwind,amv_vwind,fcst_uwind[imin],fcst_vwind[imin]))
print('Good Constraint: {0}'.format(SatwindGoodConstraint))
print('Minimum Vector Difference: {0}'.format(VecDiff[imin]))
print('Vector Difference Profile: ')
print(vdiff)
print('Pressure Profile: ')
print(fcst_prs)
if (abs(SatwindBestFitU - amv_uwind) > 4.0) or (abs(SatwindBestFitV - amv_vwind) > 4.0):
print('U Diff: {0}'.format(abs(SatwindBestFitU - amv_uwind)))
print('V Diff: {0}'.format(abs(SatwindBestFitV - amv_vwind)))
bf_data = (bfit_u, bfit_v, bfit_prs, flag)
return bf_data
def best_fit_altitude(amv_spd, amv_dir, amv_alt, amv_lat, amv_lon, fcst_spd, fcst_dir, fcst_alt,
amv_uwind=None, amv_vwind=None,
fcst_uwind=None, fcst_vwind=None,
alt_top=25000.0, alt_bot=0.0, bf_half_width=1000.0, constraint_half_width=1000.0, verbose=False):
fcst_num_levels = fcst_alt.shape[0]
flag = 3
bf_tup = (np.nan, np.nan, np.nan, flag)
if amv_alt > alt_top:
if verbose:
print('AMV location lat,lon,lat ({0},{1},{2}) is higher than max altitude {3}'.format(amv_lat, amv_lon, amv_alt, alt_top))
return bf_tup
# Calculate the height +/- alt_diff from the AMV height
alt_max = min((amv_alt + bf_half_width), alt_top)
alt_min = max((amv_lat - bf_half_width), alt_bot)
# 1d array of indices to consider for best fit height
kk = np.where((fcst_alt > alt_min) & (fcst_alt < alt_max))
if kk[0].size == 0:
if verbose:
print('AMV location lat,lon,alt ({0},{1},{2}) failed to find fcst alt around AMV'.format(amv_lat,amv_lon,amv_alt))
return bf_tup
# Compute U anv V for both AMVs and forecast
if amv_uwind is None:
amv_uwind = -amv_spd * np.sin((np.pi/180.0)*amv_dir)
amv_vwind = -amv_spd * np.cos((np.pi/180.0)*amv_dir)
if fcst_uwind is None:
fcst_uwind = -fcst_spd * np.sin((np.pi/180.0)*fcst_dir)
fcst_vwind = -fcst_spd * np.cos((np.pi/180.0)*fcst_dir)
else:
fcst_spd = np.sqrt(fcst_uwind**2 + fcst_vwind**2)
# Diagnostic field: Find the model minimum speed and maximum speed within PressDiff of the AMV.
if verbose:
sat_wind_min_spd = min(fcst_spd[kk])
sat_wind_max_spd = max(fcst_spd[kk])
# Calculate the vector difference between the AMV and model background at all levels.
vec_diff = np.sqrt((amv_uwind - fcst_uwind) ** 2 + (amv_vwind - fcst_vwind) ** 2)
# Find the model level of best-fit pressure, from the minimum vector difference.
min_vec_diff = min(vec_diff[kk])
imin = np.where(vec_diff == min_vec_diff)
if imin[0].size == 0:
if verbose:
print('AMV location lat,lon,alt ({0},{1},{2}) failed to find min vector difference in layers around AMV'.format(amv_lat,amv_lon,amv_alt))
return bf_tup
imin = imin[0][0]
a2 = fcst_alt[imin]
v2 = vec_diff[imin]
sat_wind_best_fit_alt = a2
sat_wind_best_fit_u = fcst_uwind[imin]
sat_wind_best_fit_v = fcst_vwind[imin]
if imin == 0 or imin == (fcst_num_levels - 1):
if verbose:
print('AMV location lat,lon,alt ({0},{1},{2}) min vector difference at top/bottom'.format(amv_lat,amv_lon,amv_alt))
else:
a1 = fcst_alt[imin-1]
v1 = vec_diff[imin-1]
a3 = fcst_alt[imin+1]
v3 = vec_diff[imin+1]
# check not co-linear and below alt_max
if a3 < alt_max and v1 != v2 and v2 != v3:
sat_wind_best_fit_alt = minimize_quadratic(a1, a2, a3, v1, v2, v3)
if sat_wind_best_fit_alt < a1 or sat_wind_best_fit_alt > a3:
sat_wind_best_fit_alt = a2
# Find best fit U and V by linear interpolation:
if a2 != sat_wind_best_fit_alt:
if a2 < sat_wind_best_fit_alt:
lev_below = imin
lev_above = imin + 1
prop = (sat_wind_best_fit_alt - a2) / (a3 - a2)
else:
lev_below = imin - 1
lev_above = imin
prop = (sat_wind_best_fit_alt - a1) / (a2 - a1)
sat_wind_best_fit_u = fcst_uwind[lev_below] * (1.0 - prop) + fcst_uwind[lev_above] * prop
sat_wind_best_fit_v = fcst_vwind[lev_below] * (1.0 - prop) + fcst_vwind[lev_above] * prop
# check contraints
good_constraint = 1
flag = 0
# Check for overall good agreement: want vdiff less than 4 m/s
vdiff = np.sqrt((fcst_uwind - sat_wind_best_fit_u) ** 2 + (fcst_vwind - sat_wind_best_fit_v) ** 2)
min_vdiff = min(vdiff)
if min_vdiff > 4.0:
good_constraint = 0
flag = 2
# Check for a substantial secondary local minimum or if local minimum is too broad
if good_constraint == 1:
mm = np.where(fcst_alt > (sat_wind_best_fit_alt + constraint_half_width))[0]
nn = np.where(fcst_alt < (sat_wind_best_fit_alt - constraint_half_width))[0]
if (np.sum(vdiff[mm] < (min_vdiff + 2.0)) + np.sum(vdiff[nn] < (min_vdiff + 2.0))) > 0:
good_constraint = 0
flag = 1
if good_constraint == 1:
bf_tup = (sat_wind_best_fit_u, sat_wind_best_fit_v, sat_wind_best_fit_alt, flag)
else:
bf_tup = (np.nan, np.nan, np.nan, flag)
if verbose:
print('*** AMV best-fit ***')
print('AMV -> p/minspd/maxspd: {0} {1} {2}'.format(amv_alt,sat_wind_min_spd,sat_wind_max_spd))
# print('Bestfit -> p1,p2,p3,v1,v2,v3: {0} {1} {2} {3} {4} {5}'.format(p1,p2,p3,v1,v2,v3))
print('Bestfit -> pbest,bfu,bfv,amvu,amvv,bgu,bgv: {0} {1} {2} {3} {4} {5} {6}'.format(
sat_wind_best_fit_alt,sat_wind_best_fit_u,sat_wind_best_fit_v,amv_uwind,amv_vwind,fcst_uwind[imin],fcst_vwind[imin]))
print('Good Constraint: {0}'.format(good_constraint))
print('Minimum Vector Difference: {0}'.format(vec_diff[imin]))
print('Vector Difference Profile: ')
print(vdiff)
print('Altitude Profile: ')
print(fcst_alt)
if (abs(sat_wind_best_fit_u - amv_uwind) > 4.0) or (abs(sat_wind_best_fit_v - amv_vwind) > 4.0):
print('U Diff: {0}'.format(abs(sat_wind_best_fit_u - amv_uwind)))
print('V Diff: {0}'.format(abs(sat_wind_best_fit_v - amv_vwind)))
return bf_tup
def get_press_bin_ranges(lop, hip, bin_size=100):
bin_ranges = []
delp = hip - lop
nbins = int(delp/bin_size)
for i in range(nbins):
rng = [lop + i*bin_size, lop + i*bin_size + bin_size]
bin_ranges.append(rng)
return bin_ranges
def analyze_best_fit_all(amvs_dct, bfs_dct, bin_size=200):
pres_mad = []
pres_bias = []
spd_mad = []
spd_bias = []
dir_mad = []
dir_bias = []
for key in amv_centers_list:
amvs = amvs_dct.get(key)
bfs = bfs_dct.get(key)
x_values, bin_pres, num_pres, bin_spd, num_spd, bin_dir, num_dir = analyze_best_fit_single(amvs, bfs, bin_size=bin_size)
pres_mad_c = []
pres_bias_c = []
spd_mad_c = []
spd_bias_c = []
dir_mad_c = []
dir_bias_c = []
for i in range(len(x_values)):
pres_mad_c.append(np.average(np.abs(bin_pres[i])))
pres_bias_c.append(np.average(bin_pres[i]))
spd_mad_c.append(np.average(np.abs(bin_spd[i])))
spd_bias_c.append(np.average(bin_spd[i]))
dir_mad_c.append(np.average(np.abs(bin_dir[i])))
dir_bias_c.append(np.average(bin_dir[i]))
pres_mad.append(pres_mad_c)
pres_bias.append(pres_bias_c)
spd_mad.append(spd_mad_c)
spd_bias.append(spd_bias_c)
dir_mad.append(dir_mad_c)
dir_bias.append(dir_bias_c)
return x_values, pres_mad, pres_bias, spd_mad, spd_bias, dir_mad, dir_bias
def analyze_best_fit_single(amvs, bfs, bin_size=200):
bfs = np.array(bfs)
keep_idxs = bfs[:, 0]
keep_idxs = keep_idxs.astype(np.int32)
amv_p = amvs[keep_idxs, amv_pres_idx]
bf_p = bfs[:, 3]
diff = amv_p - bf_p
mad = np.average(np.abs(diff))
bias = np.average(diff)
print('********************************************************')
print('num of best fits: ', bf_p.shape[0])
print('press, MAD: ', mad)
print('press, bias: ', bias)
pd_std = np.std(diff)
pd_mean = np.mean(diff)
print('press bias/rms ', pd_mean, np.sqrt(pd_mean**2 + pd_std**2))
print('------------------------------------------')
bin_ranges = get_press_bin_ranges(50, 1050, bin_size=bin_size)
bin_pres = bin_data_by(diff, amv_p, bin_ranges)
amv_spd = amvs[keep_idxs, amv_spd_idx]
amv_dir = amvs[keep_idxs, amv_dir_idx]
bf_spd, bf_dir = spd_dir_from_uv(bfs[:, 1], bfs[:, 2])
diff = amv_spd * units('m/s') - bf_spd
spd_mad = np.average(np.abs(diff))
spd_bias = np.average(diff)
print('spd, MAD: ', spd_mad)
print('spd, bias: ', spd_bias)
spd_mean = np.mean(diff)
spd_std = np.std(diff)
print('spd MAD/bias/rms: ', np.average(np.abs(diff)), spd_mean, np.sqrt(spd_mean**2 + spd_std**2))
print('-----------------')
bin_spd = bin_data_by(diff, amv_p, bin_ranges)
amv_dir = amv_dir * units.deg
dir_diff = direction_difference(amv_dir, bf_dir)
print('dir, MAD: ', np.average(np.abs(dir_diff)))
print('dir bias: ', np.average(dir_diff))
print('-------------------------------------')
bin_dir = bin_data_by(dir_diff, amv_p, bin_ranges)
amv_u, amv_v = uv_from_spd_dir(amvs[keep_idxs, amv_spd_idx], amvs[keep_idxs, amv_dir_idx])
u_diffs = amv_u - (bfs[:, 1] * units('m/s'))
v_diffs = amv_v - (bfs[:, 2] * units('m/s'))
vd = np.sqrt(u_diffs**2 + v_diffs**2)
vd_mean = np.mean(vd)
vd_std = np.std(vd)
print('VD bias/rms: ', vd_mean, np.sqrt(vd_mean**2 + vd_std**2))
print('------------------------------------------')
x_values = []
num_pres = []
num_spd = []
num_dir = []
for i in range(len(bin_ranges)):
x_values.append(np.average(bin_ranges[i]))
num_pres.append(bin_pres[i].shape[0])
num_spd.append(bin_spd[i].shape[0])
num_dir.append(bin_dir[i].shape[0])
return x_values, bin_pres, num_pres, bin_spd, num_spd, bin_dir, num_dir
def bin_data_by(a, b, bin_ranges):
nbins = len(bin_ranges)
binned_data = []
for i in range(nbins):
rng = bin_ranges[i]
idxs = (b >= rng[0]) & (b < rng[1])
binned_data.append(a[idxs])
return binned_data
# earth relative
def uv_from_spd_dir(speed, direction, speed_unit=None, dir_unit=None):
if speed_unit is None:
speed_unit = units('m/s')
if dir_unit is None:
dir_unit = units.deg
u, v = mpcalc.wind_components(speed * speed_unit, direction * dir_unit)
return u, v
def spd_dir_from_uv(u, v, speed_unit=None):
if speed_unit is None:
speed_unit = units('m/s')
dir = mpcalc.wind_direction(u * speed_unit, v * speed_unit)
spd = mpcalc.wind_speed(u * speed_unit, v * speed_unit)
return spd, dir
# earth relative to projection
def uv_proj_from_uv_earth(u_earth, v_earth, lons, lats, proj, units=None):
if units is None:
units = units('m/s')
u_proj, v_proj = proj.transform_vectors(ccrs.PlateCarree(), lons, lats, u_earth, v_earth)
return u_proj, v_proj
# wind direction conversion
def azimuth_to_met(direction):
direction += 180
direction = np.where(direction < 360, direction, direction - 360.0)
return direction