You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
python-snippets/ww3/update_noaa_ww3_forecasts.py

125 lines
3.7 KiB
Python

"""Update local copies of NOAA WW3 global wave forecast.
D. Howe
2019-12-13
"""
import os
import netCDF4
import pandas as pd
import xarray as xr
LON = 151.25
LAT = -34
VAR_NAMES = ['htsgwsfc', 'perpwsfc', 'dirpwsfc']
INPUT_DIR = 'csv'
TIMEZONE = 'Australia/Sydney'
DT = pd.Timedelta('6h') # Time between forecasts
def get_ww3_forecast(lon, lat, var_names, t):
"""Get NOAA WaveWatch III (WW3) global wave model forecast.
Args:
lon (float): longitude in degrees.
lat (float): latitude in degrees.
var_names (list): variable names.
t (datetime): timezone-aware local datetime.
Returns:
df (dataframe): forecast time series of selected variables.
filename (str): name of forecast file (e.g. 'nww320191212_18z').
Available variables:
dirpwsfc primary wave direction [deg]
dirswsfc secondary wave direction [deg]
htsgwsfc significant height of combined wind waves and swell [m]
perpwsfc primary wave mean period [s]
perswsfc secondary wave mean period [s]
ugrdsfc u-component of wind [m/s]
vgrdsfc v-component of wind [m/s]
wdirsfc wind direction (from which blowing) [deg]
windsfc wind speed [m/s]
wvdirsfc direction of wind waves [deg]
wvpersfc mean period of wind waves [s]
"""
base_url = 'https://nomads.ncep.noaa.gov:9090/dods/wave/nww3'
# Convert to UTC time, and round to nearest 6 hours
t_utc = t.tz_convert('UTC').floor('6h')
dirname = t_utc.strftime('nww3%Y%m%d')
filename = t_utc.strftime('nww3%Y%m%d_%Hz')
url = f'{base_url}/{dirname}/{filename}'
# Try to load dataset
ds = xr.open_dataset(url)
# Extract variables from dataset
ds = ds.sel(lon=lon, lat=lat, method='nearest')
df = ds[var_names].to_dataframe()
# Drop lat and lon columns
df = df.drop(columns=['lat', 'lon'])
# Convert timestamps to local timezone
df = df.tz_localize('UTC')
df = df.tz_convert(t.tz)
return df, filename
# Get current time
t_now = pd.Timestamp.now(tz=TIMEZONE)
for v in VAR_NAMES:
csv_name = v + '.csv'
try:
# Load local copy of variable time series
master = pd.read_csv(os.path.join(INPUT_DIR, csv_name),
index_col=[0, 1],
parse_dates=[1])
master.columns = master.columns.astype(int)
# Get start time of most recent forecast
t = master.index.get_level_values(level=1)[-1]
except FileNotFoundError:
index = pd.MultiIndex(levels=[[], []],
codes=[[], []],
names=['filename', 'start_time'])
master = pd.DataFrame(index=index)
# Use start time of 5 days hours before present
t = t_now - pd.Timedelta('5d')
while t < t_now:
t += DT
try:
# Get next forecast
df, filename = get_ww3_forecast(LON, LAT, [v], t)
except OSError:
# Stop if next forecast is not available
break
# Use filename as column name
df = df.rename(columns={v: filename})
# Convert timestamps to relative hours from start of model run
start_time = df.index[0]
df.index = ((df.index - start_time).total_seconds() / 3600).astype(int)
df.index.name = None
# Transpose to run time series along rows
df.columns = [[filename], [start_time]]
df = df.T
# Add to master dataframe
df.index.names = ['filename', 'start_time']
master = master.append(df)
if master.shape[0] > 0:
master.to_csv(os.path.join(INPUT_DIR, csv_name), float_format='%g')