MHKiT WPTO Hindcast Example

This example loads data from the WPTO hindcast data set, hosted on AWS.

Note: Some of the plotting functionality shown in this notebook will only work in Jupyter-notebook. Jupyter-Lab and VSCode may not work.

Dataset Description

The high-spatial-resolution dataset (hereafter the ‘3-hour’ dataset) currently spans the U.S. Exclusive Economic Zone (EEZ) along the West coast and around Hawaii with an unstructured grid that has ~200 m resolution in shallow water. The time step resolution for this spatial data is 3-hours and spans 32 years, 01/01/1979 - 12/31/2010.

The ‘virtual buoy dataset’ (hereafter the ‘1-hour’ dataset) is also available at specific locations within the large spatial domain. These virtual buoys span the same 32-years of the spatial dataset however the time resolution is 1-hour.

Included 3-hour Variables:

  • Dataset variables included are indexed by ‘coordinates’ (latitude and longitude), and a ‘time_index’. These variables can be accessed through the request_wpto_point_data function.

Variable Name

Units

energy_period

seconds

maximum_energy_period

degrees_true

mean_absolute_period

seconds

mean_zero-crossing_period

seconds

omni-directional_wave_power

Watts

peak_period

seconds

significant_wave_height

meters

water_depth

meters

spectral_width

none

directionality_coefficient

none

Included 1-hour Variables:

  • This dataset includes all variables in the spatial dataset as well as:

Variable Name

Units

maximum_energy_direction

degrees_true

mean_wave_direction

degrees_true

frequency_bin_edges

Hz

These variables can be accessed through the request_wpto_point_data function.

Directional Wave Spectra

  • The 1-hour data also contains directional wave spectra which can be accessed one year at time throught the request_wpto_directional_spectrum function.

Setting up Access to WPTO Hindcast Data

To access the WPTO hindcast data, you will need to configure h5pyd for data access on HSDS. To get your own API key, visit https://developer.nrel.gov/signup/.

To configure h5phd type:

hsconfigure

and enter at the prompt:

hs_endpoint = https://developer.nrel.gov/api/hsds
hs_username = None
hs_password = None
hs_api_key = {your key}

Using the WPTO Hindcast MHKiT Functions

In this section we will walk through an example to request hindcast data at a point using MHKiT. To start we will import the MHKiT wave module.

[1]:
from mhkit import wave

1. Check if Lat/Lon pair is in WPTO Hindcast Dataset

You can check to see if your desired data location is included in the WPTO Hindcast dataset using the region_selection function. If a valid lat/lon pair is passed, the name of the hindcast region is passed back, otherwise a message indicating that the pair is out or range is printed to the screen.

[2]:
lat_lon = [44.624076, -124.280097]
region = wave.io.hindcast.hindcast.region_selection(lat_lon)
print(region)
West_Coast

2. Download WPTO Hindcast Data from a Single Location

In this example we will request 3-hour significant wave height for 1995 at the point (44.624076,-124.280097, near the PacWave site). We will speficy each of these as a variable and pass them to the wave IO hindcast function request_wpto_dataset. The data type will be a high-spatial-resolution dataset, year(s) will be 1995, latitude/longitude pairs will be for a point near PacWave, and the parameter will be significant wave height.

[3]:
data_type = "3-hour"  # setting the data type to the 3-hour dataset
years = [1995]
lat_lon = (44.624076, -124.280097)
parameter = "significant_wave_height"

Hs, metadata = wave.io.hindcast.hindcast.request_wpto_point_data(
    data_type, parameter, lat_lon, years
)

View the metadata

We can check the metadata of our request to find information such as water depth, distance to shore, timezone (offset from UTC), and jurisdiction.

[4]:
metadata
[4]:
water_depth latitude longitude distance_to_shore timezone jurisdiction
0 77.429497 44.624298 -124.278999 15622.175781 -8 Federal

Hindcast Data Returned

We can also take a look at the first 5 rows of the returned data by call the head() method on the returned data. By calling this below we can see that the returned data has a time index and a single column of significant wave height. The siginifcant wave height column has a 0 integer on the end of it refering to the index in the metadata. In out next example the importance of this integer will become more clear as we begin to request multiple locations.

[5]:
Hs.head()
[5]:
significant_wave_height_0
time_index
1995-01-01 00:00:00+00:00 2.35354
1995-01-01 03:00:00+00:00 2.39468
1995-01-01 06:00:00+00:00 2.45756
1995-01-01 09:00:00+00:00 2.55913
1995-01-01 12:00:00+00:00 2.66992

3. Download WPTO Hindcast Data from Multiple Locations

Multiple locations can be requested by passing a list or tuple of lat/lon pairs. This time we will request the 3-hour energy period at two points. The data type and years requested remanin the same as before. By looking at the head of the returned DataFrame we can see that this time two energy periods are returned. The integers on each of the energy periods refer to the index in the metadata. This allows the user to connect the quantities of interest and the metadata fro each point.

[6]:
parameter = "energy_period"
lat_lon = ((44.624076, -124.280097), (43.489171, -125.152137))

Te, metadata = wave.io.hindcast.hindcast.request_wpto_point_data(
    data_type, parameter, lat_lon, years
)

# View Te from two locations
Te.head()
[6]:
energy_period_0 energy_period_1
time_index
1995-01-01 00:00:00+00:00 10.3433 10.1760
1995-01-01 03:00:00+00:00 10.2281 10.2641
1995-01-01 06:00:00+00:00 10.0164 10.1792
1995-01-01 09:00:00+00:00 10.0484 10.2410
1995-01-01 12:00:00+00:00 10.6579 10.5877
[7]:
metadata
[7]:
water_depth latitude longitude distance_to_shore timezone jurisdiction
0 77.429497 44.624298 -124.278999 15622.175781 -8 Federal
1 1337.407959 43.496300 -125.152000 64236.390625 -8 Federal

4. Download WPTO Hindcast Data from Multiple Years

Multiple years can be requested simply by adding years to the passed list. Recall the hindcast data spans 01/01/1979 - 12/31/2010. A demonstration of requesting multiple years of 3-hour data for a single point is shown below. By looking at the the returned data we can see that the data is returned in the order of the years passed to the function.

[8]:
years = [1995, 1996]
parameter = "omni-directional_wave_power"
lat_lon = (44.624076, -124.280097)

J, metadata = wave.io.hindcast.hindcast.request_wpto_point_data(
    data_type, parameter, lat_lon, years
)

J
[8]:
omni-directional_wave_power_0
time_index
1995-01-01 00:00:00+00:00 30134.0
1995-01-01 03:00:00+00:00 30805.0
1995-01-01 06:00:00+00:00 31709.0
1995-01-01 09:00:00+00:00 34476.0
1995-01-01 12:00:00+00:00 39892.0
... ...
1996-12-31 09:00:00+00:00 154849.0
1996-12-31 12:00:00+00:00 120543.0
1996-12-31 15:00:00+00:00 108288.0
1996-12-31 18:00:00+00:00 105609.0
1996-12-31 21:00:00+00:00 111097.0

5848 rows × 1 columns

[9]:
metadata
[9]:
water_depth latitude longitude distance_to_shore timezone jurisdiction
0 77.429497 44.624298 -124.278999 15622.175781 -8 Federal

5. Download 1-hour data

1-hour temporal resolutions data can be requested by passing ‘1-hour’ as the data_type. An example for requesting this higher temporal data is below.

[10]:
data_type = "1-hour"  # Setting the data_type to 1 hour data
years = [1995]
parameter = ["significant_wave_height", "peak_period", "mean_wave_direction"]
lat_lon = (44.624076, -124.280097)

data, metadata = wave.io.hindcast.hindcast.request_wpto_point_data(
    data_type, parameter, lat_lon, years
)

In looking at the returned data we see that the data is at an hourly temporal resolution.

[11]:
data.head()
[11]:
significant_wave_height_0 peak_period_0 mean_wave_direction_0
time_index
1995-01-01 01:00:00+00:00 2.484366 14.662757 15.084534
1995-01-01 02:00:00+00:00 2.630712 14.662757 25.247620
1995-01-01 03:00:00+00:00 2.593185 14.662757 26.125366
1995-01-01 04:00:00+00:00 2.563252 14.662757 26.771942
1995-01-01 05:00:00+00:00 2.534683 14.662757 27.553558

6. Calculate a Directional JPD

Using numpy, we can calculate a directional JPD using the 1-hour data requested above.

[12]:
from numpy import histogramdd, array, arange, mean

# Generate bins for Hm0, Te and Direction
Hm0_bins = arange(0, data.significant_wave_height_0.values.max() + 0.5, 0.5)
Te_bins = arange(0, data.peak_period_0.values.max() + 1, 1)
Dir_bins = arange(0, data.mean_wave_direction_0.values.max() + 10, 10)

# Combine data for better handling
jpd_3d = array(
    [
        data.significant_wave_height_0.values.flatten(),
        data.peak_period_0.values.flatten(),
        data.mean_wave_direction_0.values.flatten(),
    ]
).T

# Calculate the bin centers of the data
Hm0_center = array(
    [mean([Hm0_bins[i + 1], Hm0_bins[i]]) for i in range(Hm0_bins.shape[0] - 1)]
)
Te_center = array(
    [mean([Te_bins[i + 1], Te_bins[i]]) for i in range(Te_bins.shape[0] - 1)]
)
Dir_center = array(
    [mean([Dir_bins[i + 1], Dir_bins[i]]) for i in range(Dir_bins.shape[0] - 1)]
)


# Calculate the JPD for Hm0, Te, and Dir
probability, edges = histogramdd(
    jpd_3d, bins=[Hm0_bins, Te_bins, Dir_bins], density=True
)

We can then plot the directional JPD using matplotlib. Click along the slider below the plot to view the JPD for each incoming wave direction.

[13]:
%matplotlib notebook

import matplotlib.pyplot as plt
from numpy import arange
from matplotlib.widgets import Slider


fig, ax = plt.subplots()
fig.subplots_adjust(right=0.8, bottom=0.25)

d = 0
plot_jpd = probability[:, :, d]

im = ax.imshow(plot_jpd, origin="lower", aspect="auto")

axcolor = "lightgoldenrodyellow"
axDir = plt.axes([0.3, 0.075, 0.45, 0.03], facecolor=axcolor)

newD = Slider(axDir, "Income Wave\n Direction", 5, 355, valinit=d, valstep=10)


def update(val):
    d = int(newD.val / 10)
    im.set_data(probability[:, :, d])
    fig.canvas.draw()


newD.on_changed(update)

cax = fig.add_axes([0.82, 0.3, 0.03, 0.5])
cbar = fig.colorbar(im, cax=cax, orientation="vertical")

cbar.set_label("Probability Density (1/(sec*m*deg)", rotation=270, labelpad=15)

ax.set_xlabel("Te (seconds)")
ax.set_ylabel("Hm0 (meters)")

ax.set_xticks(arange(len(Te_center)))
ax.set_yticks(arange(len(Hm0_center)))
ax.set_xticklabels(Te_center, rotation=45)
ax.set_yticklabels(Hm0_center)

fig.suptitle("Joint Probability Density\n of Hm0 and Te per Direction")
[13]:
Text(0.5, 0.98, 'Joint Probability Density\n of Hm0 and Te per Direction')

7. Download Directional Spectra Data

1-hour directional wave spectra data can be downloaded using request_wpto_directional_spectrum. The spectra data will be returned as an xarray while the metadata will be returned as a Pandas DataFrame.

[14]:
year = "1993"  # only one year can be passed at a time as a string
lat_lon = (43.489171, -125.152137)
dir_spectra, meta = wave.io.hindcast.hindcast.request_wpto_directional_spectrum(
    lat_lon, year
)

print(dir_spectra)
<xarray.Dataset>
Dimensions:     (time_index: 8748, frequency: 29, direction: 24)
Coordinates:
  * time_index  (time_index) object 725850000000000000 ... 757378800000000000
  * frequency   (frequency) float64 0.035 0.0385 0.0424 ... 0.4173 0.4591 0.505
  * direction   (direction) float64 7.5 22.5 37.5 52.5 ... 322.5 337.5 352.5
Data variables:
    58          (time_index, frequency, direction) float32 0.0 0.0 ... 7.968e-05