def transform_and_check_data(p, z, qv, wind_dir, wind_speed, th): """Quality check and convert units of Uinversity of Wyoming sound data :param p: pressure :param z: heights :param qv: mixing ration :param wind_dir: wind direction :param wind_speed: wind speed :param th: potential temperature :returns: pressure, heights, mixing ration, u wind, v wind and potential temperature This ingests data loaded from file owr web and culls invalid rows (NaN in certain colums) and quality checks the data. Units are converted from the native uwyo data to the module standard SI units. """ # clean up NaNs and mark invalid rows for deletion nk = len(z) for k in np.arange(nk): delete_rows = [] if np.isnan(p[k]): delete_rows.append(k) if np.isnan(qv[k]): qv[k] = 0 if np.isnan(wind_speed[k]): wind_speed[k] = wind_speed[k - 1] if np.isnan(wind_dir[k]): wind_dir[k] = wind_dir[k - 1] # delete invalid rows p = np.delete(p, delete_rows) z = np.delete(z, delete_rows) qv = np.delete(qv, delete_rows) wind_dir = np.delete(wind_dir, delete_rows) wind_speed = np.delete(wind_speed, delete_rows) th = np.delete(th, delete_rows) # convert ingested units to our package standard units nk = len(z) p = p * 100. # hPa to Pa qv = qv / 1000. # g/kg to kg/kg wind_speed = wind_speed * 0.51444 # kts to m/s # convert wind direction,speed to u,v components u = np.empty(nk, np.float32) v = np.empty(nk, np.float32) for k in np.arange(nk): u[k], v[k] = dynamics.wind_deg_to_uv(wind_dir[k], wind_speed[k]) p[np.isnan(p)] = 0 qv[np.isnan(qv)] = 0 u[np.isnan(u)] = 0 v[np.isnan(v)] = 0 #reutrn data return (p, z, qv, u, v, th)
def transform_and_check_data(p, z, qv, wind_dir, wind_speed, th): """Quality check and convert units of Uinversity of Wyoming sound data :param p: pressure :param z: heights :param qv: mixing ration :param wind_dir: wind direction :param wind_speed: wind speed :param th: potential temperature :returns: pressure, heights, mixing ration, u wind, v wind and potential temperature This ingests data loaded from file owr web and culls invalid rows (NaN in certain colums) and quality checks the data. Units are converted from the native uwyo data to the module standard SI units. """ # clean up NaNs and mark invalid rows for deletion nk = len(z) for k in np.arange(nk): delete_rows = [] if np.isnan(p[k]): delete_rows.append(k) if np.isnan(qv[k]): qv[k] = 0 if np.isnan(wind_speed[k]): wind_speed[k] = wind_speed[k-1] if np.isnan(wind_dir[k]): wind_dir[k] = wind_dir[k-1] # delete invalid rows p = np.delete(p,delete_rows) z = np.delete(z,delete_rows) qv = np.delete(qv,delete_rows) wind_dir = np.delete(wind_dir, delete_rows) wind_speed = np.delete(wind_speed, delete_rows) th = np.delete(th, delete_rows) # convert ingested units to our package standard units nk = len(z) p = p * 100. # hPa to Pa qv = qv / 1000. # g/kg to kg/kg wind_speed = wind_speed * 0.51444 # kts to m/s # convert wind direction,speed to u,v components u = np.empty(nk, np.float32) v = np.empty(nk, np.float32) for k in np.arange(nk): u[k], v[k] = dynamics.wind_deg_to_uv(wind_dir[k], wind_speed[k]) #reutrn data return (p, z, qv, u, v, th)
def plot_sounding_data_csv(filename, output): """Plot SkewT from a CSV sounding data file :param filename: The name of the file to open. :type filename: str :param output: The name of the file to output plot :type output: str The datafile format is CSV with the following columns: - pressure (mb) - height (m) - temperature (C) - dew point (C) - wind direction (degrees) - wind speed (m/s) Missing values should be filled with the value -9999.00 """ p, z, T, Td, wdir, wspd = np.loadtxt(filename, delimiter=',', unpack=True) # Pressure to Pa p = p * 100. # z to km #z = z / 1000. # interpolate missing wind nk = len(z) u = np.empty(nk, np.float32) v = np.empty(nk, np.float32) for k in range(nk): if wdir[k] == -9999. and wspd[k] == -9999.: u[k] = v[k] = -9999. else: u[k], v[k] = dyn.wind_deg_to_uv(wdir[k], wspd[k]) #print('{0:5.2f} {1:5.2f} = {2:5.2f} {3:5.2f}'.format(wdir[k], wspd[k], u[k], v[k])) _z = np.empty(2, np.float32) _u = np.empty(2, np.float32) _v = np.empty(2, np.float32) print('INTERPOLATING') for k in range(nk): if wdir[k] == -9999. and wspd[k] == -9999.: kb = ke = k while kb >= 0 and wdir[kb] == -9999. and wspd[kb] == -9999.: kb -= 1 while ke <= nk - 1 and wdir[ke] == -9999. and wspd[ke] == -9999.: ke += 1 # everything in bounds if kb >= 0 and ke <= nk - 1: _z[0] = z[kb] _z[1] = z[ke] _u[0] = u[kb] _u[1] = u[ke] _v[0] = v[kb] _v[1] = v[ke] u[k] = pymeteo.interp.linear(_z, _u, z[k]) v[k] = pymeteo.interp.linear(_z, _v, z[k]) elif kb < 0: u[k] = u[ke] v[k] = v[ke] elif ke > nk - 1: u[k] = u[kb] v[k] = v[kb] for k in range(nk): # kt to m/s u[k] = u[k] * 0.5144444 v[k] = v[k] * 0.5144444 # print('{0:5.2f} {1:5.2f} = {2:5.2f} {3:5.2f}'.format(wdir[k], wspd[k], u[k], v[k])) # calc theta th = np.empty(nk, np.float32) # calc qv qv = np.empty(nk, np.float32) for k in range(nk): th[k] = met.theta(T[k] + met.T00, p[k]) w = met.es(Td[k] + met.T00) / met.es(T[k] + met.T00) pp = met.es(T[k] + met.T00) / p[k] qv[k] = 0.622 * pp * w #qv[k] = met.es(Td[k]+met.T00) / (met.Rv * (T[k]+met.T00)) #print(z, th, p, qv, u, v) plot(None, z, th, p, qv, u, v, output, title='Sounding Data')
def processDataSet(data): print("[+] Writing data into temporary file") tdata = tempfile.NamedTemporaryFile() tdata.write(data.read()) print("[-] Data written to {0}".format(tdata.name)) print("[+] Opening data as NetCDF") d = data.read() with netCDF4.Dataset(tdata.name, mode='r') as nc: print("[-] Dataset open with") _z = nc["altitude"][:] _T = nc["temperature"][:] _qv = nc["waterVaporMR"][:] windSpeed = nc["windSpeed"][:] windDir = nc["windDir"][:] _lon = nc["longitude"][:] _lat = nc["latitude"][:] flag = nc["sounding_flag"][:] _airport = nc["sounding_airport_id"][:] time = nc["soundingSecs"][:] print("[-] {0} Records".format(len(_z))) #conversions _p = thermo.p_from_pressure_altitude(_z, _T) _u, _v = dynamics.wind_deg_to_uv(windDir, windSpeed) _th = thermo.theta(_T, _p) # split the arrays when the flag changes sign splits = np.where(np.diff(time))[0] + 1 _z = np.split(_z, splits) _p = np.split(_p, splits) _th = np.split(_th, splits) _qv = np.split(_qv, splits) _u = np.split(_u, splits) _v = np.split(_v, splits) _lat = np.split(_lat, splits) _lon = np.split(_lon, splits) _airport = np.split(_airport, splits) time = np.split(time, splits) flag = np.split(flag, splits) print("[-] Found {0} profiles".format(len(_z))) #re-shape data outputData = [] for i in range(len(_z)): ts = time[i].compressed() if len(ts) == 0: # profiles without timestamps invalid? continue profileDir = flag[i][0] if (profileDir == 0): continue z = _z[i].filled() p = _p[i].filled() th = _th[i].filled() qv = _qv[i].filled() u = _u[i].filled() v = _v[i].filled() lat = _lat[i].filled() lon = _lon[i].filled() airport = getAirportByCode(_airport[i][0]) profileData = { "i": i, "n": len(z), "z": z if profileDir > 0 else z[::-1], "p": p if profileDir > 0 else p[::-1], "th": th if profileDir > 0 else th[::-1], "qv": qv if profileDir > 0 else qv[::-1], "u": u if profileDir > 0 else u[::-1], "v": v if profileDir > 0 else v[::-1], "lat": lat if profileDir > 0 else lat[::-1], "lon": lon if profileDir > 0 else lon[::-1], "airport": airport, "time": datetime.utcfromtimestamp(ts.mean()).strftime("%H%MZ"), "flag": profileDir } outputData.append(profileData) return outputData
def plot_sounding_data_csv(filename, output): """Plot SkewT from a CSV sounding data file :param filename: The name of the file to open. :type filename: str :param output: The name of the file to output plot :type output: str The datafile format is CSV with the following columns: - pressure (mb) - height (m) - temperature (C) - dew point (C) - wind direction (degrees) - wind speed (m/s) Missing values should be filled with the value -9999.00 """ p,z,T,Td,wdir,wspd = np.loadtxt(filename, delimiter=',', unpack=True) # Pressure to Pa p = p * 100. # z to km #z = z / 1000. # interpolate missing wind nk = len(z) u = np.empty(nk, np.float32) v = np.empty(nk, np.float32) for k in range(nk): if wdir[k] == -9999. and wspd[k] == -9999.: u[k] = v[k] = -9999. else: u[k], v[k] = dyn.wind_deg_to_uv(wdir[k], wspd[k]) #print('{0:5.2f} {1:5.2f} = {2:5.2f} {3:5.2f}'.format(wdir[k], wspd[k], u[k], v[k])) _z = np.empty(2,np.float32) _u = np.empty(2,np.float32) _v = np.empty(2,np.float32) print('INTERPOLATING') for k in range(nk): if wdir[k] == -9999. and wspd[k] == -9999.: kb = ke = k while kb >= 0 and wdir[kb] == -9999. and wspd[kb] == -9999.: kb -= 1 while ke <= nk-1 and wdir[ke] == -9999. and wspd[ke] == -9999.: ke += 1 # everything in bounds if kb >= 0 and ke <= nk-1: _z[0] = z[kb] _z[1] = z[ke] _u[0] = u[kb] _u[1] = u[ke] _v[0] = v[kb] _v[1] = v[ke] u[k] = pymeteo.interp.linear(_z, _u, z[k]) v[k] = pymeteo.interp.linear(_z, _v, z[k]) elif kb < 0: u[k] = u[ke] v[k] = v[ke] elif ke > nk-1: u[k] = u[kb] v[k] = v[kb] for k in range(nk): # kt to m/s u[k] = u[k] * 0.5144444 v[k] = v[k] * 0.5144444 # print('{0:5.2f} {1:5.2f} = {2:5.2f} {3:5.2f}'.format(wdir[k], wspd[k], u[k], v[k])) # calc theta th = np.empty(nk, np.float32) # calc qv qv = np.empty(nk, np.float32) for k in range(nk): th[k] = met.theta(T[k]+met.T00, p[k]) w = met.es(Td[k]+met.T00) / met.es(T[k]+met.T00) pp = met.es(T[k]+met.T00) / p[k] qv[k] = 0.622 * pp * w #qv[k] = met.es(Td[k]+met.T00) / (met.Rv * (T[k]+met.T00)) #print(z, th, p, qv, u, v) plot(None, z, th, p, qv, u, v, output, title='Sounding Data')