From fcc910eb4417e3fd6d767921813e1546f91e577c Mon Sep 17 00:00:00 2001 From: akeeste Date: Thu, 12 Sep 2024 14:50:34 -0500 Subject: [PATCH 01/39] fix assignment in type_handling --- mhkit/utils/type_handling.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mhkit/utils/type_handling.py b/mhkit/utils/type_handling.py index 1b06c7d1..4179fa2f 100644 --- a/mhkit/utils/type_handling.py +++ b/mhkit/utils/type_handling.py @@ -176,7 +176,7 @@ def convert_to_dataarray(data, name="data"): data = data.to_array() data = data.sel(variable=keys[0]) data.name = keys[0] - data.drop_vars("variable") + data = data.drop_vars("variable") else: # Allow multiple variables if they have the same dimensions if all([data[keys[0]].dims == data[key].dims for key in keys]): From b19217c25f57ebe814d04a7a9020770b3c1a065a Mon Sep 17 00:00:00 2001 From: akeeste Date: Mon, 16 Sep 2024 11:18:15 -0500 Subject: [PATCH 02/39] temporary testing file --- mhkit/wave/speed_testing.py | 218 ++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 mhkit/wave/speed_testing.py diff --git a/mhkit/wave/speed_testing.py b/mhkit/wave/speed_testing.py new file mode 100644 index 00000000..e5672806 --- /dev/null +++ b/mhkit/wave/speed_testing.py @@ -0,0 +1,218 @@ +import numpy as np +import pandas as pd +import xarray as xr +from mhkit import wave +from mhkit.utils import to_numeric_array, convert_to_dataarray, convert_to_dataset +import timeit + +def _transform_dataset(data, name): + # Converting data from a Dataset into a DataArray will turn the variables + # columns into a 'variable' dimension. + # Converting it back to a dataset will keep this concise variable dimension + # but in the expected xr.Dataset/pd.DataFrame format + data = data.to_array() + data = convert_to_dataset(data, name=name) + data = data.rename({"variable": "index"}) + return data + +def frequency_moment_da(S, N, frequency_bins=None, frequency_dimension="", to_pandas=True): + S = convert_to_dataarray(S) + if not isinstance(N, int): + raise TypeError(f"N must be of type int. Got: {type(N)}") + if not isinstance(to_pandas, bool): + raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") + + if frequency_dimension == "": + frequency_dimension = list(S.coords)[0] + elif frequency_dimension not in list(S.dims): + raise ValueError( + f"frequency_dimension is not a dimension of S ({list(S.dims)}). Got: {frequency_dimension}." + ) + f = S[frequency_dimension] + + # Eq 8 in IEC 62600-101 + S = S.sel({frequency_dimension: slice(1e-12, f.max())}) # omit frequency of 0 + f = S[frequency_dimension] # reset frequency_dimension without the 0 frequency + + fn = np.power(f, N) + if frequency_bins is None: + delta_f = f.diff(dim=frequency_dimension) + delta_f0 = f[1] - f[0] + delta_f0 = delta_f0.assign_coords({frequency_dimension: f[0]}) + delta_f = xr.concat([delta_f0, delta_f], dim=frequency_dimension) + else: + delta_f = xr.DataArray( + data=convert_to_dataarray(frequency_bins), + dims=frequency_dimension, + coords={frequency_dimension: f}, + ) + + m = S * fn * delta_f + m = m.sum(dim=frequency_dimension) + + m.name = "m" + str(N) + + if to_pandas: + m = m.to_dataframe() + + return m + +def energy_period_da(S, frequency_dimension="", frequency_bins=None, to_pandas=True): + S = convert_to_dataarray(S) + if not isinstance(to_pandas, bool): + raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") + + mn1 = frequency_moment_da( + S, + -1, + frequency_bins=frequency_bins, + frequency_dimension=frequency_dimension, + to_pandas=False, + ) + m0 = frequency_moment_da( + S, + 0, + frequency_bins=frequency_bins, + frequency_dimension=frequency_dimension, + to_pandas=False, + ) + + # Eq 13 in IEC 62600-101 + Te = mn1 / m0 + Te.name = "Te" + + if to_pandas: + Te = Te.to_dataframe() + + return Te + + +def frequency_moment_np(S, N, frequency_bins=None, frequency_dimension="", to_pandas=True): + S = convert_to_dataarray(S) + if not isinstance(N, int): + raise TypeError(f"N must be of type int. Got: {type(N)}") + if not isinstance(to_pandas, bool): + raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") + + if frequency_dimension == "": + frequency_dimension = list(S.coords)[0] + elif frequency_dimension not in list(S.dims): + raise ValueError( + f"frequency_dimension is not a dimension of S ({list(S.dims)}). Got: {frequency_dimension}." + ) + f = S[frequency_dimension].values + mask = f >= 1e-12 + frequency_index = S.dims.index(frequency_dimension) + + S_np = to_numeric_array(S, name="S") + + # Eq 8 in IEC 62600-101 + mask_nd = mask * np.full(S_np.shape, True) + S_np = S_np[mask_nd].reshape(S_np.shape) # omit frequency of 0 + f = f[mask] # reset frequency_dimension without the 0 frequency + + fn = np.power(f, N) + if frequency_bins is None: + delta_f = np.diff(f, frequency_index) + delta_f0 = f[1] - f[0] + delta_f = np.concatenate(([delta_f0], delta_f)) + else: + delta_f = frequency_bins + + data = S_np * fn * delta_f + data = data.sum(frequency_index) + + m = S[{frequency_dimension:0}] + m = m.drop_vars(frequency_dimension) + m.name = "m" + str(N) + m.values = data + + # newDims = [dim for dim in S.dims if dim not in [frequency_dimension]] + # newCoords = {dim: coord for dim,coord in newDims if S.} + if to_pandas: + m = m.to_pandas() + + return m + +def energy_period_np(S, frequency_dimension="", frequency_bins=None, to_pandas=True): + S = convert_to_dataarray(S) + S_np = to_numeric_array(S, name="S") + + if not isinstance(to_pandas, bool): + raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") + + mn1 = frequency_moment_np( + S, + -1, + frequency_bins=frequency_bins, + frequency_dimension=frequency_dimension, + to_pandas=False, + ) + # mn1 = mn1.rename({"m-1": "Te"}) + m0 = frequency_moment_np( + S, + 0, + frequency_bins=frequency_bins, + frequency_dimension=frequency_dimension, + to_pandas=False, + ) + # m0 = m0.rename({"m0": "Te"}) + + # Eq 13 in IEC 62600-101 + Te = mn1 / m0 + Te.name = "Te" + + if to_pandas: + Te = Te.to_pandas() + + return Te + +# ndbc.read_file outputs the NDBC file data into two variables. +# raw_ndbc_data is a pandas DataFrame containing the file data. +# meta contains the meta data, if available. +# ndbc_data_file = "../../examples/data/wave/data.txt" +# [raw_ndbc_data, meta] = wave.io.ndbc.read_file(ndbc_data_file) +# raw_ndbc_data.head() +# ndbc_data = raw_ndbc_data.T + +parameter = "swden" +ndbc_available_data = wave.io.ndbc.available_data(parameter, '46050') +filenames = ndbc_available_data["filename"] +filenames = filenames.loc[1994:1996] # isolate data for 2018-2019 to speed up script +ndbc_requested_data = wave.io.ndbc.request_data(parameter, filenames) +all_ndbc_data = {} +# Create a Datetime Index and remove NOAA date columns for each year +for year in ndbc_requested_data: + year_data = ndbc_requested_data[year] + all_ndbc_data[year] = wave.io.ndbc.to_datetime_index(parameter, year_data) + + +ndbc_data = all_ndbc_data["2018"] +# ndbc_data = raw_ndbc_data.T + + +# # Uncomment for format testing +# # How to get the two below cases to work in the same way? +# te_np = energy_period_np(ndbc_data, frequency_dimension="variable") # masking this does work because shapes are compatible +# te_np = energy_period_np(ndbc_data.T, frequency_dimension="index") # masking this does NOT work because shapes are incompatible +# te_da = energy_period_da(ndbc_data, frequency_dimension="variable") +# te_df = wave.resource.energy_period(ndbc_data, frequency_dimension="variable") + +ndbc_data_da = convert_to_dataarray(ndbc_data) +ndbc_data_s = ndbc_data.iloc[:,0] +te = wave.resource.energy_period(ndbc_data, frequency_dimension="variable") +te_da = wave.resource.energy_period(ndbc_data_da, frequency_dimension="variable") +te_s = wave.resource.energy_period(ndbc_data_s, frequency_dimension="variable") + +# # Uncomment for speed testing +# # Initial results: +# # current: 43.4233, dataArray: 0.06466, numpy: 0.018468 +# # --> dataArray ~700x faster than current +# # --> numpy ~3.5x faster than dataArray +# n = 5 +# time = {} +# time["dataset"] = timeit.timeit(lambda: wave.resource.energy_period(ndbc_data), number=n)/n +# time["dataarray"] = timeit.timeit(lambda: energy_period_da(ndbc_data, frequency_dimension="index"), number=n)/n +# time["numpy"] = timeit.timeit(lambda: energy_period_np(ndbc_data, frequency_dimension="index"), number=n)/n + +ndbc_data From 5addc17215fb99e4045a43911cb4ab35f82215c1 Mon Sep 17 00:00:00 2001 From: akeeste Date: Mon, 16 Sep 2024 11:19:34 -0500 Subject: [PATCH 03/39] initial conversion of energy_period and frequency_moment to DataArray --- mhkit/wave/resource.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/mhkit/wave/resource.py b/mhkit/wave/resource.py index 0cfe28e0..6423dfc9 100644 --- a/mhkit/wave/resource.py +++ b/mhkit/wave/resource.py @@ -430,7 +430,7 @@ def frequency_moment(S, N, frequency_bins=None, frequency_dimension="", to_panda m: pandas DataFrame or xarray Dataset Nth Frequency Moment indexed by S.columns """ - S = convert_to_dataset(S) + S = convert_to_dataarray(S) if not isinstance(N, int): raise TypeError(f"N must be of type int. Got: {type(N)}") if not isinstance(to_pandas, bool): @@ -464,7 +464,7 @@ def frequency_moment(S, N, frequency_bins=None, frequency_dimension="", to_panda m = S * fn * delta_f m = m.sum(dim=frequency_dimension) - m = _transform_dataset(m, "m" + str(N)) + m.name = "m" + str(N) if to_pandas: m = m.to_dataframe() @@ -728,7 +728,7 @@ def energy_period(S, frequency_dimension="", frequency_bins=None, to_pandas=True Te: pandas DataFrame or xarray Dataset Wave energy period [s] indexed by S.columns """ - S = convert_to_dataset(S) + S = convert_to_dataarray(S) if not isinstance(to_pandas, bool): raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") @@ -738,17 +738,18 @@ def energy_period(S, frequency_dimension="", frequency_bins=None, to_pandas=True frequency_bins=frequency_bins, frequency_dimension=frequency_dimension, to_pandas=False, - ).rename({"m-1": "Te"}) + ) m0 = frequency_moment( S, 0, frequency_bins=frequency_bins, frequency_dimension=frequency_dimension, to_pandas=False, - ).rename({"m0": "Te"}) + ) # Eq 13 in IEC 62600-101 Te = mn1 / m0 + Te.name = "Te" if to_pandas: Te = Te.to_dataframe() From ac91b92516bb41773aea893dff0bf378babbb95e Mon Sep 17 00:00:00 2001 From: akeeste Date: Mon, 16 Sep 2024 12:55:48 -0500 Subject: [PATCH 04/39] energy_period working with variety of types and converting to dataArray base --- mhkit/wave/resource.py | 2 +- mhkit/wave/speed_testing.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mhkit/wave/resource.py b/mhkit/wave/resource.py index 6423dfc9..3b0ee697 100644 --- a/mhkit/wave/resource.py +++ b/mhkit/wave/resource.py @@ -752,7 +752,7 @@ def energy_period(S, frequency_dimension="", frequency_bins=None, to_pandas=True Te.name = "Te" if to_pandas: - Te = Te.to_dataframe() + Te = Te.to_pandas() return Te diff --git a/mhkit/wave/speed_testing.py b/mhkit/wave/speed_testing.py index e5672806..9a25d5bd 100644 --- a/mhkit/wave/speed_testing.py +++ b/mhkit/wave/speed_testing.py @@ -37,7 +37,7 @@ def frequency_moment_da(S, N, frequency_bins=None, frequency_dimension="", to_pa fn = np.power(f, N) if frequency_bins is None: delta_f = f.diff(dim=frequency_dimension) - delta_f0 = f[1] - f[0] + delta_f0 = f[0] delta_f0 = delta_f0.assign_coords({frequency_dimension: f[0]}) delta_f = xr.concat([delta_f0, delta_f], dim=frequency_dimension) else: @@ -199,10 +199,10 @@ def energy_period_np(S, frequency_dimension="", frequency_bins=None, to_pandas=T # te_df = wave.resource.energy_period(ndbc_data, frequency_dimension="variable") ndbc_data_da = convert_to_dataarray(ndbc_data) -ndbc_data_s = ndbc_data.iloc[:,0] +ndbc_data_s = ndbc_data.iloc[0,:] te = wave.resource.energy_period(ndbc_data, frequency_dimension="variable") te_da = wave.resource.energy_period(ndbc_data_da, frequency_dimension="variable") -te_s = wave.resource.energy_period(ndbc_data_s, frequency_dimension="variable") +te_s = wave.resource.energy_period(ndbc_data_s) # # Uncomment for speed testing # # Initial results: From 5d914a37e09e56be5c370f82d7e47a203a07ddc8 Mon Sep 17 00:00:00 2001 From: akeeste Date: Tue, 24 Sep 2024 14:34:34 -0500 Subject: [PATCH 05/39] extend xr.dataarray basis to all wave.resource functions --- mhkit/wave/resource.py | 208 ++++++++++++++++++----------------------- 1 file changed, 90 insertions(+), 118 deletions(-) diff --git a/mhkit/wave/resource.py b/mhkit/wave/resource.py index 3b0ee697..6f25b871 100644 --- a/mhkit/wave/resource.py +++ b/mhkit/wave/resource.py @@ -1,11 +1,10 @@ import warnings - from scipy.optimize import fsolve as _fsolve from scipy import signal as _signal import pandas as pd import xarray as xr import numpy as np -from mhkit.utils import to_numeric_array, convert_to_dataarray, convert_to_dataset +from mhkit.utils import to_numeric_array, convert_to_dataarray ### Spectrum @@ -54,7 +53,7 @@ def elevation_spectrum( # TODO: Add confidence intervals, equal energy frequency spacing, and NDBC # frequency spacing # TODO: may need to raise an error for the length of nnft- signal.welch breaks when nfft is too short - eta = convert_to_dataset(eta) + eta = convert_to_dataarray(eta) if not isinstance(sample_rate, (float, int)): raise TypeError( f"sample_rate must be of type int or float. Got: {type(sample_rate)}" @@ -87,26 +86,22 @@ def elevation_spectrum( + "temporal spacing for eta." ) - S = xr.Dataset() - for var in eta.data_vars: - data = eta[var] - if detrend: - data = _signal.detrend( - data.dropna(dim=time_dimension), axis=-1, type="linear", bp=0 - ) - [f, wave_spec_measured] = _signal.welch( - data, - fs=sample_rate, - window=window, - nperseg=nnft, - nfft=nnft, - noverlap=noverlap, - ) - S[var] = (["Frequency"], wave_spec_measured) - S = S.assign_coords({"Frequency": f}) + if detrend: + eta = _signal.detrend(eta.dropna(dim=time_dimension), axis=-1, type="linear", bp=0) + [f, S] = _signal.welch( + eta, + fs=sample_rate, + window=window, + nperseg=nnft, + nfft=nnft, + noverlap=noverlap, + ) + # S = (["Frequency"], wave_spec_measured) + # S = S.assign_coords({"Frequency": f}) + S = xr.DataArray(data=S, coords=["Frequency"], dims={"Frequency": f}) if to_pandas: - S = S.to_dataframe() + S = S.to_pandas() return S @@ -292,11 +287,11 @@ def surface_elevation( """ time_index = to_numeric_array(time_index, "time_index") - S = convert_to_dataset(S) + S = convert_to_dataarray(S) if not isinstance(seed, (type(None), int)): raise TypeError(f"If specified, seed must be of type int. Got: {type(seed)}") if not isinstance(phases, type(None)): - phases = convert_to_dataset(phases) + phases = convert_to_dataarray(phases) if not isinstance(method, str): raise TypeError(f"method must be of type str. Got: {type(method)}") if not isinstance(to_pandas, bool): @@ -361,48 +356,46 @@ def surface_elevation( data=2 * np.pi * f, dims=frequency_dimension, coords={frequency_dimension: f} ) - eta = xr.Dataset() - for var in S.data_vars: - if phases is None: - np.random.seed(seed) - phase = xr.DataArray( - data=2 * np.pi * np.random.rand(S[var].size), - dims=frequency_dimension, - coords={frequency_dimension: f}, - ) - else: - phase = phases[var] + if phases is None: + np.random.seed(seed) + phase = xr.DataArray( + data=2 * np.pi * np.random.rand(S[var].size), + dims=frequency_dimension, + coords={frequency_dimension: f}, + ) + else: + phase = phases[var] - # Wave amplitude times delta f - A = 2 * S[var] - A = A * delta_f - A = np.sqrt(A) + # Wave amplitude times delta f + A = 2 * S[var] + A = A * delta_f + A = np.sqrt(A) - if method == "ifft": - A_cmplx = A * (np.cos(phase) + 1j * np.sin(phase)) - eta_tmp = np.fft.irfft( - 0.5 * A_cmplx.values * time_index.size, time_index.size - ) - eta[var] = xr.DataArray( - data=eta_tmp, dims="Time", coords={"Time": time_index} - ) + if method == "ifft": + A_cmplx = A * (np.cos(phase) + 1j * np.sin(phase)) + eta_tmp = np.fft.irfft( + 0.5 * A_cmplx.values * time_index.size, time_index.size + ) + eta = xr.DataArray( + data=eta_tmp, dims="Time", coords={"Time": time_index} + ) - elif method == "sum_of_sines": - # Product of omega and time - B = np.outer(time_index, omega) - B = B.reshape((len(time_index), len(omega))) - B = xr.DataArray( - data=B, - dims=["Time", frequency_dimension], - coords={"Time": time_index, frequency_dimension: f}, - ) + elif method == "sum_of_sines": + # Product of omega and time + B = np.outer(time_index, omega) + B = B.reshape((len(time_index), len(omega))) + B = xr.DataArray( + data=B, + dims=["Time", frequency_dimension], + coords={"Time": time_index, frequency_dimension: f}, + ) - # wave elevation - C = np.cos(B + phase) - eta[var] = (C * A).sum(dim=frequency_dimension) + # wave elevation + C = np.cos(B + phase) + eta = (C * A).sum(dim=frequency_dimension) if to_pandas: - eta = eta.to_dataframe() + eta = eta.to_pandas() return eta @@ -467,7 +460,7 @@ def frequency_moment(S, N, frequency_bins=None, frequency_dimension="", to_panda m.name = "m" + str(N) if to_pandas: - m = m.to_dataframe() + m = m.to_pandas() return m @@ -495,7 +488,7 @@ def significant_wave_height( Hm0: pandas DataFrame or xarray Dataset Significant wave height [m] index by S.columns """ - S = convert_to_dataset(S) + S = convert_to_dataarray(S) if not isinstance(to_pandas, bool): raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") @@ -506,11 +499,11 @@ def significant_wave_height( frequency_bins=frequency_bins, frequency_dimension=frequency_dimension, to_pandas=False, - ).rename({"m0": "Hm0"}) + ) Hm0 = 4 * np.sqrt(m0) if to_pandas: - Hm0 = Hm0.to_dataframe() + Hm0 = Hm0.to_pandas() return Hm0 @@ -538,7 +531,6 @@ def average_zero_crossing_period( Tz: pandas DataFrame or xarray Dataset Average zero crossing period [s] indexed by S.columns """ - S = convert_to_dataset(S) if not isinstance(to_pandas, bool): raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") @@ -549,19 +541,18 @@ def average_zero_crossing_period( frequency_bins=frequency_bins, frequency_dimension=frequency_dimension, to_pandas=False, - ).rename({"m0": "Tz"}) + ) m2 = frequency_moment( S, 2, frequency_bins=frequency_bins, frequency_dimension=frequency_dimension, to_pandas=False, - ).rename({"m2": "Tz"}) - + ) Tz = np.sqrt(m0 / m2) if to_pandas: - Tz = Tz.to_dataframe() + Tz = Tz.to_pandas() return Tz @@ -590,7 +581,6 @@ def average_crest_period( Average wave period [s] indexed by S.columns """ - S = convert_to_dataset(S) if not isinstance(to_pandas, bool): raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") @@ -600,19 +590,19 @@ def average_crest_period( frequency_bins=frequency_bins, frequency_dimension=frequency_dimension, to_pandas=False, - ).rename({"m2": "Tavg"}) + ) m4 = frequency_moment( S, 4, frequency_bins=frequency_bins, frequency_dimension=frequency_dimension, to_pandas=False, - ).rename({"m4": "Tavg"}) + ) Tavg = np.sqrt(m2 / m4) if to_pandas: - Tavg = Tavg.to_dataframe() + Tavg = Tavg.to_pandas() return Tavg @@ -638,7 +628,6 @@ def average_wave_period(S, frequency_dimension="", frequency_bins=None, to_panda Tm: pandas DataFrame or xarray Dataset Mean wave period [s] indexed by S.columns """ - S = convert_to_dataset(S) if not isinstance(to_pandas, bool): raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") @@ -648,19 +637,19 @@ def average_wave_period(S, frequency_dimension="", frequency_bins=None, to_panda frequency_bins=frequency_bins, frequency_dimension=frequency_dimension, to_pandas=False, - ).rename({"m0": "Tm"}) + ) m1 = frequency_moment( S, 1, frequency_bins=frequency_bins, frequency_dimension=frequency_dimension, to_pandas=False, - ).rename({"m1": "Tm"}) + ) Tm = np.sqrt(m0 / m1) if to_pandas: - Tm = Tm.to_dataframe() + Tm = Tm.to_pandas() return Tm @@ -684,7 +673,7 @@ def peak_period(S, frequency_dimension="", to_pandas=True): Tp: pandas DataFrame or xarray Dataset Wave peak period [s] indexed by S.columns """ - S = convert_to_dataset(S) + S = convert_to_dataarray(S) if not isinstance(to_pandas, bool): raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") @@ -699,10 +688,8 @@ def peak_period(S, frequency_dimension="", to_pandas=True): fp = S.idxmax(dim=frequency_dimension) # Hz Tp = 1 / fp - Tp = _transform_dataset(Tp, "Tp") - if to_pandas: - Tp = Tp.to_dataframe() + Tp = Tp.to_pandas() return Tp @@ -778,7 +765,7 @@ def spectral_bandwidth(S, frequency_dimension="", frequency_bins=None, to_pandas e: pandas DataFrame or xarray Dataset Spectral bandwidth [s] indexed by S.columns """ - S = convert_to_dataset(S) + S = convert_to_dataarray(S) if not isinstance(to_pandas, bool): raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") @@ -788,26 +775,26 @@ def spectral_bandwidth(S, frequency_dimension="", frequency_bins=None, to_pandas frequency_bins=frequency_bins, frequency_dimension=frequency_dimension, to_pandas=False, - ).rename({"m2": "e"}) + ) m0 = frequency_moment( S, 0, frequency_bins=frequency_bins, frequency_dimension=frequency_dimension, to_pandas=False, - ).rename({"m0": "e"}) + ) m4 = frequency_moment( S, 4, frequency_bins=frequency_bins, frequency_dimension=frequency_dimension, to_pandas=False, - ).rename({"m4": "e"}) + ) e = np.sqrt(1 - (m2**2) / (m0 / m4)) if to_pandas: - e = e.to_dataframe() + e = e.to_pandas() return e @@ -833,7 +820,6 @@ def spectral_width(S, frequency_dimension="", frequency_bins=None, to_pandas=Tru v: pandas DataFrame or xarray Dataset Spectral width [m] indexed by S.columns """ - S = convert_to_dataset(S) if not isinstance(to_pandas, bool): raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") @@ -843,27 +829,27 @@ def spectral_width(S, frequency_dimension="", frequency_bins=None, to_pandas=Tru frequency_bins=frequency_bins, frequency_dimension=frequency_dimension, to_pandas=False, - ).rename({"m-2": "v"}) + ) m0 = frequency_moment( S, 0, frequency_bins=frequency_bins, frequency_dimension=frequency_dimension, to_pandas=False, - ).rename({"m0": "v"}) + ) mn1 = frequency_moment( S, -1, frequency_bins=frequency_bins, frequency_dimension=frequency_dimension, to_pandas=False, - ).rename({"m-1": "v"}) + ) # Eq 16 in IEC 62600-101 v = np.sqrt((m0 * mn2 / np.power(mn1, 2)) - 1) if to_pandas: - v = v.to_dataframe() + v = v.to_pandas() return v @@ -910,7 +896,7 @@ def energy_flux( J: pandas DataFrame or xarray Dataset Omni-directional wave energy flux [W/m] indexed by S.columns """ - S = convert_to_dataset(S) + S = convert_to_dataarray(S) if not isinstance(h, (int, float)): raise TypeError(f"h must be of type int or float. Got: {type(h)}") if not isinstance(deep, bool): @@ -934,8 +920,8 @@ def energy_flux( if deep: # Eq 8 in IEC 62600-100, deep water simplification - Te = energy_period(S, to_pandas=False).rename({"Te": "J"}) - Hm0 = significant_wave_height(S, to_pandas=False).rename({"Hm0": "J"}) + Te = energy_period(S, to_pandas=False) + Hm0 = significant_wave_height(S, to_pandas=False) coeff = rho * (g**2) / (64 * np.pi) @@ -946,9 +932,7 @@ def energy_flux( k = wave_number(f, h, rho, g, to_pandas=False) # wave celerity (group velocity) - Cg = wave_celerity(k, h, g, depth_check=True, ratio=ratio, to_pandas=False)[ - "Cg" - ] + Cg = wave_celerity(k, h, g, depth_check=True, ratio=ratio, to_pandas=False) # Calculating the wave energy flux, Eq 9 in IEC 62600-101 delta_f = f.diff(dim=frequency_dimension) @@ -959,10 +943,9 @@ def energy_flux( CgSdelF = S * delta_f * Cg J = rho * g * CgSdelF.sum(dim=frequency_dimension) - J = _transform_dataset(J, "J") if to_pandas: - J = J.to_dataframe() + J = J.to_pandas() return J @@ -998,8 +981,6 @@ def energy_period_to_peak_period(Te, gamma): factor = 0.8255 + 0.03852 * gamma - 0.005537 * gamma**2 + 0.0003154 * gamma**3 Tp = Te / factor - if isinstance(Tp, xr.Dataset): - Tp.rename({"Te": "Tp"}) return Tp @@ -1092,10 +1073,10 @@ def wave_celerity( ) Cg.name = "Cg" - Cg = Cg.to_dataset() + # Cg = Cg.to_dataset() if to_pandas: - Cg = Cg.to_dataframe() + Cg = Cg.to_pandas() return Cg @@ -1136,7 +1117,7 @@ def wave_number(f, h, rho=1025, g=9.80665, to_pandas=True): Parameters ----------- - f: int, float, numpy ndarray, pandas DataFrame, pandas Series, xarray DataArray, or xarray Dataset + f: int, float, numpy ndarray, pandas DataFrame, pandas Series, xarray DataArray Frequency [Hz] h: float Water depth [m] @@ -1154,7 +1135,7 @@ def wave_number(f, h, rho=1025, g=9.80665, to_pandas=True): """ if isinstance(f, (int, float)): f = np.asarray([f]) - f = convert_to_dataarray(f) + # f = convert_to_dataarray(f) if not isinstance(h, (int, float)): raise TypeError(f"h must be of type int or float. Got: {type(h)}") if not isinstance(rho, (int, float)): @@ -1184,11 +1165,12 @@ def func(kk): raise ValueError("Wave number not found. " + mesg) k0[mask] = k - k0.name = "k" - k = k0.to_dataset() + if isinstance(k0, (pd.Series, xr.DataArray)): + k0.name = "k" + # k = k0.to_dataset() - if to_pandas: - k = k.to_dataframe() + # if to_pandas: + # k = k.to_pandas() return k @@ -1232,13 +1214,3 @@ def depth_regime(l, h, ratio=2): return depth_reg - -def _transform_dataset(data, name): - # Converting data from a Dataset into a DataArray will turn the variables - # columns into a 'variable' dimension. - # Converting it back to a dataset will keep this concise variable dimension - # but in the expected xr.Dataset/pd.DataFrame format - data = data.to_array() - data = convert_to_dataset(data, name=name) - data = data.rename({"variable": "index"}) - return data From 8683b88737cb96a264fb679887e93218cff79759 Mon Sep 17 00:00:00 2001 From: akeeste Date: Tue, 24 Sep 2024 14:35:01 -0500 Subject: [PATCH 06/39] remove testing script --- mhkit/wave/speed_testing.py | 218 ------------------------------------ 1 file changed, 218 deletions(-) delete mode 100644 mhkit/wave/speed_testing.py diff --git a/mhkit/wave/speed_testing.py b/mhkit/wave/speed_testing.py deleted file mode 100644 index 9a25d5bd..00000000 --- a/mhkit/wave/speed_testing.py +++ /dev/null @@ -1,218 +0,0 @@ -import numpy as np -import pandas as pd -import xarray as xr -from mhkit import wave -from mhkit.utils import to_numeric_array, convert_to_dataarray, convert_to_dataset -import timeit - -def _transform_dataset(data, name): - # Converting data from a Dataset into a DataArray will turn the variables - # columns into a 'variable' dimension. - # Converting it back to a dataset will keep this concise variable dimension - # but in the expected xr.Dataset/pd.DataFrame format - data = data.to_array() - data = convert_to_dataset(data, name=name) - data = data.rename({"variable": "index"}) - return data - -def frequency_moment_da(S, N, frequency_bins=None, frequency_dimension="", to_pandas=True): - S = convert_to_dataarray(S) - if not isinstance(N, int): - raise TypeError(f"N must be of type int. Got: {type(N)}") - if not isinstance(to_pandas, bool): - raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") - - if frequency_dimension == "": - frequency_dimension = list(S.coords)[0] - elif frequency_dimension not in list(S.dims): - raise ValueError( - f"frequency_dimension is not a dimension of S ({list(S.dims)}). Got: {frequency_dimension}." - ) - f = S[frequency_dimension] - - # Eq 8 in IEC 62600-101 - S = S.sel({frequency_dimension: slice(1e-12, f.max())}) # omit frequency of 0 - f = S[frequency_dimension] # reset frequency_dimension without the 0 frequency - - fn = np.power(f, N) - if frequency_bins is None: - delta_f = f.diff(dim=frequency_dimension) - delta_f0 = f[0] - delta_f0 = delta_f0.assign_coords({frequency_dimension: f[0]}) - delta_f = xr.concat([delta_f0, delta_f], dim=frequency_dimension) - else: - delta_f = xr.DataArray( - data=convert_to_dataarray(frequency_bins), - dims=frequency_dimension, - coords={frequency_dimension: f}, - ) - - m = S * fn * delta_f - m = m.sum(dim=frequency_dimension) - - m.name = "m" + str(N) - - if to_pandas: - m = m.to_dataframe() - - return m - -def energy_period_da(S, frequency_dimension="", frequency_bins=None, to_pandas=True): - S = convert_to_dataarray(S) - if not isinstance(to_pandas, bool): - raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") - - mn1 = frequency_moment_da( - S, - -1, - frequency_bins=frequency_bins, - frequency_dimension=frequency_dimension, - to_pandas=False, - ) - m0 = frequency_moment_da( - S, - 0, - frequency_bins=frequency_bins, - frequency_dimension=frequency_dimension, - to_pandas=False, - ) - - # Eq 13 in IEC 62600-101 - Te = mn1 / m0 - Te.name = "Te" - - if to_pandas: - Te = Te.to_dataframe() - - return Te - - -def frequency_moment_np(S, N, frequency_bins=None, frequency_dimension="", to_pandas=True): - S = convert_to_dataarray(S) - if not isinstance(N, int): - raise TypeError(f"N must be of type int. Got: {type(N)}") - if not isinstance(to_pandas, bool): - raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") - - if frequency_dimension == "": - frequency_dimension = list(S.coords)[0] - elif frequency_dimension not in list(S.dims): - raise ValueError( - f"frequency_dimension is not a dimension of S ({list(S.dims)}). Got: {frequency_dimension}." - ) - f = S[frequency_dimension].values - mask = f >= 1e-12 - frequency_index = S.dims.index(frequency_dimension) - - S_np = to_numeric_array(S, name="S") - - # Eq 8 in IEC 62600-101 - mask_nd = mask * np.full(S_np.shape, True) - S_np = S_np[mask_nd].reshape(S_np.shape) # omit frequency of 0 - f = f[mask] # reset frequency_dimension without the 0 frequency - - fn = np.power(f, N) - if frequency_bins is None: - delta_f = np.diff(f, frequency_index) - delta_f0 = f[1] - f[0] - delta_f = np.concatenate(([delta_f0], delta_f)) - else: - delta_f = frequency_bins - - data = S_np * fn * delta_f - data = data.sum(frequency_index) - - m = S[{frequency_dimension:0}] - m = m.drop_vars(frequency_dimension) - m.name = "m" + str(N) - m.values = data - - # newDims = [dim for dim in S.dims if dim not in [frequency_dimension]] - # newCoords = {dim: coord for dim,coord in newDims if S.} - if to_pandas: - m = m.to_pandas() - - return m - -def energy_period_np(S, frequency_dimension="", frequency_bins=None, to_pandas=True): - S = convert_to_dataarray(S) - S_np = to_numeric_array(S, name="S") - - if not isinstance(to_pandas, bool): - raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") - - mn1 = frequency_moment_np( - S, - -1, - frequency_bins=frequency_bins, - frequency_dimension=frequency_dimension, - to_pandas=False, - ) - # mn1 = mn1.rename({"m-1": "Te"}) - m0 = frequency_moment_np( - S, - 0, - frequency_bins=frequency_bins, - frequency_dimension=frequency_dimension, - to_pandas=False, - ) - # m0 = m0.rename({"m0": "Te"}) - - # Eq 13 in IEC 62600-101 - Te = mn1 / m0 - Te.name = "Te" - - if to_pandas: - Te = Te.to_pandas() - - return Te - -# ndbc.read_file outputs the NDBC file data into two variables. -# raw_ndbc_data is a pandas DataFrame containing the file data. -# meta contains the meta data, if available. -# ndbc_data_file = "../../examples/data/wave/data.txt" -# [raw_ndbc_data, meta] = wave.io.ndbc.read_file(ndbc_data_file) -# raw_ndbc_data.head() -# ndbc_data = raw_ndbc_data.T - -parameter = "swden" -ndbc_available_data = wave.io.ndbc.available_data(parameter, '46050') -filenames = ndbc_available_data["filename"] -filenames = filenames.loc[1994:1996] # isolate data for 2018-2019 to speed up script -ndbc_requested_data = wave.io.ndbc.request_data(parameter, filenames) -all_ndbc_data = {} -# Create a Datetime Index and remove NOAA date columns for each year -for year in ndbc_requested_data: - year_data = ndbc_requested_data[year] - all_ndbc_data[year] = wave.io.ndbc.to_datetime_index(parameter, year_data) - - -ndbc_data = all_ndbc_data["2018"] -# ndbc_data = raw_ndbc_data.T - - -# # Uncomment for format testing -# # How to get the two below cases to work in the same way? -# te_np = energy_period_np(ndbc_data, frequency_dimension="variable") # masking this does work because shapes are compatible -# te_np = energy_period_np(ndbc_data.T, frequency_dimension="index") # masking this does NOT work because shapes are incompatible -# te_da = energy_period_da(ndbc_data, frequency_dimension="variable") -# te_df = wave.resource.energy_period(ndbc_data, frequency_dimension="variable") - -ndbc_data_da = convert_to_dataarray(ndbc_data) -ndbc_data_s = ndbc_data.iloc[0,:] -te = wave.resource.energy_period(ndbc_data, frequency_dimension="variable") -te_da = wave.resource.energy_period(ndbc_data_da, frequency_dimension="variable") -te_s = wave.resource.energy_period(ndbc_data_s) - -# # Uncomment for speed testing -# # Initial results: -# # current: 43.4233, dataArray: 0.06466, numpy: 0.018468 -# # --> dataArray ~700x faster than current -# # --> numpy ~3.5x faster than dataArray -# n = 5 -# time = {} -# time["dataset"] = timeit.timeit(lambda: wave.resource.energy_period(ndbc_data), number=n)/n -# time["dataarray"] = timeit.timeit(lambda: energy_period_da(ndbc_data, frequency_dimension="index"), number=n)/n -# time["numpy"] = timeit.timeit(lambda: energy_period_np(ndbc_data, frequency_dimension="index"), number=n)/n - -ndbc_data From e860034950e097b516888b4ff40ae4025637a47c Mon Sep 17 00:00:00 2001 From: akeeste Date: Tue, 24 Sep 2024 14:35:22 -0500 Subject: [PATCH 07/39] black formatting --- mhkit/wave/resource.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/mhkit/wave/resource.py b/mhkit/wave/resource.py index 6f25b871..d0875c74 100644 --- a/mhkit/wave/resource.py +++ b/mhkit/wave/resource.py @@ -87,7 +87,9 @@ def elevation_spectrum( ) if detrend: - eta = _signal.detrend(eta.dropna(dim=time_dimension), axis=-1, type="linear", bp=0) + eta = _signal.detrend( + eta.dropna(dim=time_dimension), axis=-1, type="linear", bp=0 + ) [f, S] = _signal.welch( eta, fs=sample_rate, @@ -373,12 +375,8 @@ def surface_elevation( if method == "ifft": A_cmplx = A * (np.cos(phase) + 1j * np.sin(phase)) - eta_tmp = np.fft.irfft( - 0.5 * A_cmplx.values * time_index.size, time_index.size - ) - eta = xr.DataArray( - data=eta_tmp, dims="Time", coords={"Time": time_index} - ) + eta_tmp = np.fft.irfft(0.5 * A_cmplx.values * time_index.size, time_index.size) + eta = xr.DataArray(data=eta_tmp, dims="Time", coords={"Time": time_index}) elif method == "sum_of_sines": # Product of omega and time @@ -1213,4 +1211,3 @@ def depth_regime(l, h, ratio=2): depth_reg = h / l > ratio return depth_reg - From 338282565e5aa556ced4e34b11b71441bcf00295 Mon Sep 17 00:00:00 2001 From: akeeste Date: Tue, 24 Sep 2024 15:36:49 -0500 Subject: [PATCH 08/39] fix most test formatting --- mhkit/tests/wave/test_resource_metrics.py | 31 ++++++++++++----------- mhkit/wave/resource.py | 12 ++++----- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/mhkit/tests/wave/test_resource_metrics.py b/mhkit/tests/wave/test_resource_metrics.py index 9cdf589f..830bfa64 100644 --- a/mhkit/tests/wave/test_resource_metrics.py +++ b/mhkit/tests/wave/test_resource_metrics.py @@ -95,7 +95,8 @@ def test_kfromw(self): expected = self.valdata1[i]["k"] k = wave.resource.wave_number(f, h, rho) - calculated = k.loc[:, "k"].values + # calculated = k.loc[:, "k"].values + calculated = k error = ((expected - calculated) ** 2).sum() # SSE self.assertLess(error, 1e-6) @@ -106,7 +107,7 @@ def test_kfromw_one_freq(self): h = 1e9 w = np.pi * 2 * f # deep water dispersion expected = w**2 / g - calculated = wave.resource.wave_number(f=f, h=h, g=g).values[0][0] + calculated = wave.resource.wave_number(f=f, h=h, g=g).item() error = np.abs(expected - calculated) self.assertLess(error, 1e-6) @@ -218,7 +219,7 @@ def test_moments(self): calculated = wave.resource.frequency_moment( S, int(m), frequency_bins=f_bins - ).iloc[0, 0] + ).item() error = np.abs(expected - calculated) / expected self.assertLess(error, 0.01) @@ -238,7 +239,7 @@ def test_energy_period_to_peak_period(self): f = np.linspace(1 / (10 * Tp), 3 / Tp, 100) S = wave.resource.jonswap_spectrum(f, Tp, Hs, g) - Te_calc = wave.resource.energy_period(S).values[0][0] + Te_calc = wave.resource.energy_period(S).item() error = np.abs(T - Te_calc) / Te_calc self.assertLess(error, 0.01) @@ -259,16 +260,16 @@ def test_metrics(self): expected = data["metrics"]["Hm0"] calculated = wave.resource.significant_wave_height( S, frequency_bins=f_bins - ).iloc[0, 0] + ) error = np.abs(expected - calculated) / expected # print('Hm0', expected, calculated, error) self.assertLess(error, 0.01) # Te expected = data["metrics"]["Te"] - calculated = wave.resource.energy_period(S, frequency_bins=f_bins).iloc[ - 0, 0 - ] + calculated = wave.resource.energy_period( + S, frequency_bins=f_bins + ).item() error = np.abs(expected - calculated) / expected # print('Te', expected, calculated, error) self.assertLess(error, 0.01) @@ -277,7 +278,7 @@ def test_metrics(self): expected = data["metrics"]["T0"] calculated = wave.resource.average_zero_crossing_period( S, frequency_bins=f_bins - ).iloc[0, 0] + ).item() error = np.abs(expected - calculated) / expected # print('T0', expected, calculated, error) self.assertLess(error, 0.01) @@ -289,7 +290,7 @@ def test_metrics(self): S, # Tc = Tavg**2 frequency_bins=f_bins, - ).iloc[0, 0] + ).item() ** 2 ) error = np.abs(expected - calculated) / expected @@ -300,14 +301,14 @@ def test_metrics(self): expected = np.sqrt(data["metrics"]["Tm"]) calculated = wave.resource.average_wave_period( S, frequency_bins=f_bins - ).iloc[0, 0] + ).item() error = np.abs(expected - calculated) / expected # print('Tm', expected, calculated, error) self.assertLess(error, 0.01) # Tp expected = data["metrics"]["Tp"] - calculated = wave.resource.peak_period(S).iloc[0, 0] + calculated = wave.resource.peak_period(S) error = np.abs(expected - calculated) / expected # print('Tp', expected, calculated, error) self.assertLess(error, 0.001) @@ -316,7 +317,7 @@ def test_metrics(self): expected = data["metrics"]["e"] calculated = wave.resource.spectral_bandwidth( S, frequency_bins=f_bins - ).iloc[0, 0] + ).item() error = np.abs(expected - calculated) / expected # print('e', expected, calculated, error) self.assertLess(error, 0.001) @@ -335,14 +336,14 @@ def test_metrics(self): expected = data["metrics"]["v"] calculated = wave.resource.spectral_width( S, frequency_bins=f_bins - ).iloc[0, 0] + ).item() error = np.abs(expected - calculated) / expected self.assertLess(error, 0.01) if file_i == "MC": expected = data["metrics"]["v"] # testing that default uniform frequency bin widths works - calculated = wave.resource.spectral_width(S).iloc[0, 0] + calculated = wave.resource.spectral_width(S).item() error = np.abs(expected - calculated) / expected self.assertLess(error, 0.01) diff --git a/mhkit/wave/resource.py b/mhkit/wave/resource.py index d0875c74..7a8fc141 100644 --- a/mhkit/wave/resource.py +++ b/mhkit/wave/resource.py @@ -90,7 +90,7 @@ def elevation_spectrum( eta = _signal.detrend( eta.dropna(dim=time_dimension), axis=-1, type="linear", bp=0 ) - [f, S] = _signal.welch( + [f, wave_spec_measured] = _signal.welch( eta, fs=sample_rate, window=window, @@ -98,9 +98,9 @@ def elevation_spectrum( nfft=nnft, noverlap=noverlap, ) - # S = (["Frequency"], wave_spec_measured) - # S = S.assign_coords({"Frequency": f}) - S = xr.DataArray(data=S, coords=["Frequency"], dims={"Frequency": f}) + S = xr.DataArray( + data=wave_spec_measured, dims=["Frequency"], coords={"Frequency": f} + ) if to_pandas: S = S.to_pandas() @@ -1162,10 +1162,10 @@ def func(kk): if not ier == 1: raise ValueError("Wave number not found. " + mesg) k0[mask] = k + k = k0 if isinstance(k0, (pd.Series, xr.DataArray)): - k0.name = "k" - # k = k0.to_dataset() + k.name = "k" # if to_pandas: # k = k.to_pandas() From c5241affcb0a482c47891773f67f5641813a4545 Mon Sep 17 00:00:00 2001 From: akeeste Date: Mon, 30 Sep 2024 10:51:35 -0500 Subject: [PATCH 09/39] use dataarrays instead of datasets in wave.performance --- mhkit/wave/performance.py | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/mhkit/wave/performance.py b/mhkit/wave/performance.py index 4d137dd4..d1d797e2 100644 --- a/mhkit/wave/performance.py +++ b/mhkit/wave/performance.py @@ -6,7 +6,7 @@ from mhkit import wave import matplotlib.pylab as plt from os.path import join -from mhkit.utils import convert_to_dataarray, convert_to_dataset +from mhkit.utils import convert_to_dataarray def capture_length(P, J, to_pandas=True): @@ -246,22 +246,22 @@ def power_matrix(LM, JM): Parameters ------------ - LM: pandas DataFrame or xarray Dataset + LM: pandas DataFrame, xarray DatArray, or xarray Dataset Capture length matrix - JM: pandas DataFrame or xarray Dataset + JM: pandas DataFrame, xarray DatArray, or xarray Dataset Wave energy flux matrix Returns --------- - PM: pandas DataFrame or xarray Dataset + PM: pandas DataFrame, xarray DatArray, or xarray Dataset Power matrix """ - if not isinstance(LM, (pd.DataFrame, xr.Dataset)): + if not isinstance(LM, (pd.DataFrame, xr.DataArray, xr.Dataset)): raise TypeError( f"LM must be of type pd.DataFrame or xr.Dataset. Got: {type(LM)}" ) - if not isinstance(JM, (pd.DataFrame, xr.Dataset)): + if not isinstance(JM, (pd.DataFrame, xr.DataArray, xr.Dataset)): raise TypeError( f"JM must be of type pd.DataFrame or xr.Dataset. Got: {type(JM)}" ) @@ -306,11 +306,11 @@ def mean_annual_energy_production_matrix(LM, JM, frequency): Parameters ------------ - LM: pandas DataFrame or xarray Dataset + LM: pandas DataFrame, xarray DatArray, or xarray Dataset Capture length - JM: pandas DataFrame or xarray Dataset + JM: pandas DataFrame, xarray DatArray, or xarray Dataset Wave energy flux - frequency: pandas DataFrame or xarray Dataset + frequency: pandas DataFrame, xarray DatArray, or xarray Dataset Data frequency for each bin Returns @@ -393,7 +393,7 @@ def power_performance_workflow( maep_matrix: float Mean annual energy production """ - S = convert_to_dataset(S) + S = convert_to_dataarray(S) if not isinstance(h, (int, float)): raise TypeError(f"h must be of type int or float. Got: {type(h)}") P = convert_to_dataarray(P) @@ -408,19 +408,16 @@ def power_performance_workflow( # Compute the enegy periods from the spectra data Te = wave.resource.energy_period(S, frequency_bins=frequency_bins, to_pandas=False) - Te = Te["Te"] # Compute the significant wave height from the NDBC spectra data Hm0 = wave.resource.significant_wave_height( S, frequency_bins=frequency_bins, to_pandas=False ) - Hm0 = Hm0["Hm0"] # Compute the energy flux from spectra data and water depth J = wave.resource.energy_flux( S, h, deep=deep, rho=rho, g=g, ratio=ratio, to_pandas=False ) - J = J["J"] # Calculate capture length from power and energy flux L = wave.performance.capture_length(P, J, to_pandas=False) From a2d5f619b65ee10aa01d2758046a25fd54f10f0b Mon Sep 17 00:00:00 2001 From: akeeste Date: Mon, 30 Sep 2024 15:08:26 -0500 Subject: [PATCH 10/39] revert surface_elevation function back to datasets --- mhkit/wave/resource.py | 66 +++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/mhkit/wave/resource.py b/mhkit/wave/resource.py index 7a8fc141..6c7049d5 100644 --- a/mhkit/wave/resource.py +++ b/mhkit/wave/resource.py @@ -358,39 +358,45 @@ def surface_elevation( data=2 * np.pi * f, dims=frequency_dimension, coords={frequency_dimension: f} ) - if phases is None: - np.random.seed(seed) - phase = xr.DataArray( - data=2 * np.pi * np.random.rand(S[var].size), - dims=frequency_dimension, - coords={frequency_dimension: f}, - ) - else: - phase = phases[var] + eta = xr.Dataset() + for var in S.data_vars: + if phases is None: + np.random.seed(seed) + phase = xr.DataArray( + data=2 * np.pi * np.random.rand(S[var].size), + dims=frequency_dimension, + coords={frequency_dimension: f}, + ) + else: + phase = phases[var] - # Wave amplitude times delta f - A = 2 * S[var] - A = A * delta_f - A = np.sqrt(A) + # Wave amplitude times delta f + A = 2 * S[var] + A = A * delta_f + A = np.sqrt(A) - if method == "ifft": - A_cmplx = A * (np.cos(phase) + 1j * np.sin(phase)) - eta_tmp = np.fft.irfft(0.5 * A_cmplx.values * time_index.size, time_index.size) - eta = xr.DataArray(data=eta_tmp, dims="Time", coords={"Time": time_index}) - - elif method == "sum_of_sines": - # Product of omega and time - B = np.outer(time_index, omega) - B = B.reshape((len(time_index), len(omega))) - B = xr.DataArray( - data=B, - dims=["Time", frequency_dimension], - coords={"Time": time_index, frequency_dimension: f}, - ) + if method == "ifft": + A_cmplx = A * (np.cos(phase) + 1j * np.sin(phase)) + eta_tmp = np.fft.irfft( + 0.5 * A_cmplx.values * time_index.size, time_index.size + ) + eta[var] = xr.DataArray( + data=eta_tmp, dims="Time", coords={"Time": time_index} + ) + + elif method == "sum_of_sines": + # Product of omega and time + B = np.outer(time_index, omega) + B = B.reshape((len(time_index), len(omega))) + B = xr.DataArray( + data=B, + dims=["Time", frequency_dimension], + coords={"Time": time_index, frequency_dimension: f}, + ) - # wave elevation - C = np.cos(B + phase) - eta = (C * A).sum(dim=frequency_dimension) + # wave elevation + C = np.cos(B + phase) + eta[var] = (C * A).sum(dim=frequency_dimension) if to_pandas: eta = eta.to_pandas() From e016fffb0389788f7506ceaed746045863153eec Mon Sep 17 00:00:00 2001 From: akeeste Date: Tue, 1 Oct 2024 14:41:19 -0500 Subject: [PATCH 11/39] Revert "revert surface_elevation function back to datasets" This reverts commit a2d5f619b65ee10aa01d2758046a25fd54f10f0b. --- mhkit/wave/resource.py | 66 +++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 36 deletions(-) diff --git a/mhkit/wave/resource.py b/mhkit/wave/resource.py index 6c7049d5..7a8fc141 100644 --- a/mhkit/wave/resource.py +++ b/mhkit/wave/resource.py @@ -358,45 +358,39 @@ def surface_elevation( data=2 * np.pi * f, dims=frequency_dimension, coords={frequency_dimension: f} ) - eta = xr.Dataset() - for var in S.data_vars: - if phases is None: - np.random.seed(seed) - phase = xr.DataArray( - data=2 * np.pi * np.random.rand(S[var].size), - dims=frequency_dimension, - coords={frequency_dimension: f}, - ) - else: - phase = phases[var] - - # Wave amplitude times delta f - A = 2 * S[var] - A = A * delta_f - A = np.sqrt(A) + if phases is None: + np.random.seed(seed) + phase = xr.DataArray( + data=2 * np.pi * np.random.rand(S[var].size), + dims=frequency_dimension, + coords={frequency_dimension: f}, + ) + else: + phase = phases[var] - if method == "ifft": - A_cmplx = A * (np.cos(phase) + 1j * np.sin(phase)) - eta_tmp = np.fft.irfft( - 0.5 * A_cmplx.values * time_index.size, time_index.size - ) - eta[var] = xr.DataArray( - data=eta_tmp, dims="Time", coords={"Time": time_index} - ) + # Wave amplitude times delta f + A = 2 * S[var] + A = A * delta_f + A = np.sqrt(A) - elif method == "sum_of_sines": - # Product of omega and time - B = np.outer(time_index, omega) - B = B.reshape((len(time_index), len(omega))) - B = xr.DataArray( - data=B, - dims=["Time", frequency_dimension], - coords={"Time": time_index, frequency_dimension: f}, - ) + if method == "ifft": + A_cmplx = A * (np.cos(phase) + 1j * np.sin(phase)) + eta_tmp = np.fft.irfft(0.5 * A_cmplx.values * time_index.size, time_index.size) + eta = xr.DataArray(data=eta_tmp, dims="Time", coords={"Time": time_index}) + + elif method == "sum_of_sines": + # Product of omega and time + B = np.outer(time_index, omega) + B = B.reshape((len(time_index), len(omega))) + B = xr.DataArray( + data=B, + dims=["Time", frequency_dimension], + coords={"Time": time_index, frequency_dimension: f}, + ) - # wave elevation - C = np.cos(B + phase) - eta[var] = (C * A).sum(dim=frequency_dimension) + # wave elevation + C = np.cos(B + phase) + eta = (C * A).sum(dim=frequency_dimension) if to_pandas: eta = eta.to_pandas() From a719620815dc3282e353c7202058d0d5ed06a2cc Mon Sep 17 00:00:00 2001 From: akeeste Date: Tue, 1 Oct 2024 14:44:49 -0500 Subject: [PATCH 12/39] allow datasets, 2d dataframes. Update test formatting appropriately --- mhkit/tests/wave/test_resource_metrics.py | 4 +-- mhkit/tests/wave/test_resource_spectrum.py | 20 +++++------ mhkit/wave/resource.py | 41 +++++++++++++--------- 3 files changed, 36 insertions(+), 29 deletions(-) diff --git a/mhkit/tests/wave/test_resource_metrics.py b/mhkit/tests/wave/test_resource_metrics.py index 830bfa64..9276d369 100644 --- a/mhkit/tests/wave/test_resource_metrics.py +++ b/mhkit/tests/wave/test_resource_metrics.py @@ -326,8 +326,8 @@ def test_metrics(self): if file_i != "CDiP": for i, j in zip(data["h"], data["J"]): expected = data["J"][j] - calculated = wave.resource.energy_flux(S, i) - error = np.abs(expected - calculated.values) / expected + calculated = wave.resource.energy_flux(S, i).item() + error = np.abs(expected - calculated) / expected self.assertLess(error, 0.1) # v diff --git a/mhkit/tests/wave/test_resource_spectrum.py b/mhkit/tests/wave/test_resource_spectrum.py index 5ac06cb2..843939f3 100644 --- a/mhkit/tests/wave/test_resource_spectrum.py +++ b/mhkit/tests/wave/test_resource_spectrum.py @@ -36,8 +36,8 @@ def tearDownClass(self): def test_pierson_moskowitz_spectrum(self): S = wave.resource.pierson_moskowitz_spectrum(self.f, self.Tp, self.Hs) - Hm0 = wave.resource.significant_wave_height(S).iloc[0, 0] - Tp0 = wave.resource.peak_period(S).iloc[0, 0] + Hm0 = wave.resource.significant_wave_height(S).item() + Tp0 = wave.resource.peak_period(S).item() errorHm0 = np.abs(self.Tp - Tp0) / self.Tp errorTp0 = np.abs(self.Hs - Hm0) / self.Hs @@ -60,8 +60,8 @@ def test_pierson_moskowitz_spectrum_zero_freq(self): def test_jonswap_spectrum(self): S = wave.resource.jonswap_spectrum(self.f, self.Tp, self.Hs) - Hm0 = wave.resource.significant_wave_height(S).iloc[0, 0] - Tp0 = wave.resource.peak_period(S).iloc[0, 0] + Hm0 = wave.resource.significant_wave_height(S).item() + Tp0 = wave.resource.peak_period(S).item() errorHm0 = np.abs(self.Tp - Tp0) / self.Tp errorTp0 = np.abs(self.Hs - Hm0) / self.Hs @@ -99,7 +99,7 @@ def test_surface_elevation_frequency_bins_np_and_pd(self): S1 = wave.resource.jonswap_spectrum(self.f, self.Tp, self.Hs * 1.1) S = pd.concat([S0, S1], axis=1) - eta0 = wave.resource.surface_elevation(S, self.t, seed=1) + eta0 = wave.resource.surface_elevation(S, self.t, seed=1, frequency_dimension='index') f_bins_np = np.array([np.diff(S.index)[0]] * len(S)) f_bins_pd = pd.DataFrame(f_bins_np, index=S.index, columns=["df"]) @@ -122,14 +122,14 @@ def test_surface_elevation_moments(self): eta, 1 / dt, len(eta.values), detrend=False, window="boxcar", noverlap=0 ) - m0 = wave.resource.frequency_moment(S, 0).m0.values[0] - m0n = wave.resource.frequency_moment(Sn, 0).m0.values[0] + m0 = wave.resource.frequency_moment(S, 0).values[0] + m0n = wave.resource.frequency_moment(Sn, 0).values[0] errorm0 = np.abs((m0 - m0n) / m0) self.assertLess(errorm0, 0.01) - m1 = wave.resource.frequency_moment(S, 1).m1.values[0] - m1n = wave.resource.frequency_moment(Sn, 1).m1.values[0] + m1 = wave.resource.frequency_moment(S, 1).values[0] + m1n = wave.resource.frequency_moment(Sn, 1).values[0] errorm1 = np.abs((m1 - m1n) / m1) self.assertLess(errorm1, 0.01) @@ -168,7 +168,7 @@ def test_user_spectrum_without_frequency_index_name_defined(self): expected_magnitude = [-0.983917, 1.274248, -2.129812] - assert_allclose(result["magnitude"], expected_magnitude, atol=1e-6) + assert_allclose(result, expected_magnitude, atol=1e-6) def test_ifft_sum_of_sines(self): S = wave.resource.jonswap_spectrum(self.f, self.Tp, self.Hs) diff --git a/mhkit/wave/resource.py b/mhkit/wave/resource.py index 7a8fc141..73ca34d7 100644 --- a/mhkit/wave/resource.py +++ b/mhkit/wave/resource.py @@ -289,6 +289,10 @@ def surface_elevation( """ time_index = to_numeric_array(time_index, "time_index") + if isinstance(S, pd.DataFrame) and len(S.columns) > 1: + frequency_axis = 1 + else: + frequency_axis = 0 S = convert_to_dataarray(S) if not isinstance(seed, (type(None), int)): raise TypeError(f"If specified, seed must be of type int. Got: {type(seed)}") @@ -300,12 +304,19 @@ def surface_elevation( raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") if frequency_dimension == "": - frequency_dimension = list(S.coords)[0] - - elif frequency_dimension not in list(S.dims): + frequency_dimension = list(S.coords)[frequency_axis] + elif frequency_dimension in list(S.dims): + frequency_axis = list(S.dims).index(frequency_dimension) + else: # frequency_dimension give, but not in list of possible dimensions raise ValueError( f"frequency_dimension is not a dimension of S ({list(S.dims)}). Got: {frequency_dimension}." ) + + # Create dimensions and coordinates for the new dataset (frequency becomes time) + new_dims = list(S.dims) + new_dims[frequency_axis] = 'Time' + new_coords = S.sum(dim=frequency_dimension).coords + new_coords = new_coords.assign({'Time': time_index}) f = S[frequency_dimension] if not isinstance(frequency_bins, (type(None), np.ndarray)): @@ -322,13 +333,10 @@ def surface_elevation( "shape of frequency_bins must match shape of the frequency dimension of S" ) if phases is not None: - if not list(phases.data_vars) == list(S.data_vars): - raise ValueError("phases must have the same variable names as S") - for var in phases.data_vars: - if not phases[var].shape == S[var].shape: - raise ValueError( - "shape of variables in phases must match shape of variables in S" - ) + if not phases.shape == S.shape: + raise ValueError( + "shape of variables in phases must match shape of variables in S" + ) if method is not None: if not (method == "ifft" or method == "sum_of_sines"): raise ValueError(f"Method must be 'ifft' or 'sum_of_sines'. Got: {method}") @@ -361,22 +369,21 @@ def surface_elevation( if phases is None: np.random.seed(seed) phase = xr.DataArray( - data=2 * np.pi * np.random.rand(S[var].size), + data=2 * np.pi * np.random.random_sample(S[frequency_dimension].shape), dims=frequency_dimension, coords={frequency_dimension: f}, ) else: - phase = phases[var] + phase = phases # Wave amplitude times delta f - A = 2 * S[var] - A = A * delta_f - A = np.sqrt(A) + A = np.sqrt(2 * S * delta_f) if method == "ifft": A_cmplx = A * (np.cos(phase) + 1j * np.sin(phase)) - eta_tmp = np.fft.irfft(0.5 * A_cmplx.values * time_index.size, time_index.size) - eta = xr.DataArray(data=eta_tmp, dims="Time", coords={"Time": time_index}) + # eta_tmp = np.fft.irfft(0.5 * A_cmplx.values * time_index.size, time_index.size) + eta_tmp = np.fft.irfftn(0.5 * A_cmplx * time_index.size, list(time_index.shape), axes=[frequency_axis]) + eta = xr.DataArray(data=eta_tmp, dims=new_dims, coords=new_coords) elif method == "sum_of_sines": # Product of omega and time From d585cb554a59bad123898c1349d36b97ee8e20aa Mon Sep 17 00:00:00 2001 From: akeeste Date: Wed, 2 Oct 2024 11:23:47 -0500 Subject: [PATCH 13/39] simplify and improve robustness of convert_to_dataarray for 1-var dataframes and 2+ var datasets --- mhkit/utils/type_handling.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/mhkit/utils/type_handling.py b/mhkit/utils/type_handling.py index 4179fa2f..323ff2c3 100644 --- a/mhkit/utils/type_handling.py +++ b/mhkit/utils/type_handling.py @@ -160,23 +160,13 @@ def convert_to_dataarray(data, name="data"): # iloc returns a Series with one value as expected. data = data.iloc[:, 0] else: - index = data.index.values - columns = data.columns.values - data = xr.DataArray( - data=data.T, - dims=("variable", "index"), - coords={"variable": columns, "index": index}, - ) + data = xr.DataArray(data) # Checks xr.Dataset input and converts to xr.DataArray if possible if isinstance(data, xr.Dataset): keys = list(data.keys()) if len(keys) == 1: - # if only one variable, remove the "variable" dimension and rename the DataArray to simplify - data = data.to_array() - data = data.sel(variable=keys[0]) - data.name = keys[0] - data = data.drop_vars("variable") + data = data[keys[0]] else: # Allow multiple variables if they have the same dimensions if all([data[keys[0]].dims == data[key].dims for key in keys]): From ac5b436e9cb5d33a55afa7a91cb0c6987b5a22c7 Mon Sep 17 00:00:00 2001 From: akeeste Date: Wed, 2 Oct 2024 11:34:14 -0500 Subject: [PATCH 14/39] update test formatting --- mhkit/tests/wave/test_resource_spectrum.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mhkit/tests/wave/test_resource_spectrum.py b/mhkit/tests/wave/test_resource_spectrum.py index 843939f3..58422ef8 100644 --- a/mhkit/tests/wave/test_resource_spectrum.py +++ b/mhkit/tests/wave/test_resource_spectrum.py @@ -99,7 +99,7 @@ def test_surface_elevation_frequency_bins_np_and_pd(self): S1 = wave.resource.jonswap_spectrum(self.f, self.Tp, self.Hs * 1.1) S = pd.concat([S0, S1], axis=1) - eta0 = wave.resource.surface_elevation(S, self.t, seed=1, frequency_dimension='index') + eta0 = wave.resource.surface_elevation(S, self.t, seed=1) f_bins_np = np.array([np.diff(S.index)[0]] * len(S)) f_bins_pd = pd.DataFrame(f_bins_np, index=S.index, columns=["df"]) @@ -122,14 +122,14 @@ def test_surface_elevation_moments(self): eta, 1 / dt, len(eta.values), detrend=False, window="boxcar", noverlap=0 ) - m0 = wave.resource.frequency_moment(S, 0).values[0] - m0n = wave.resource.frequency_moment(Sn, 0).values[0] + m0 = wave.resource.frequency_moment(S, 0).item() + m0n = wave.resource.frequency_moment(Sn, 0).item() errorm0 = np.abs((m0 - m0n) / m0) self.assertLess(errorm0, 0.01) - m1 = wave.resource.frequency_moment(S, 1).values[0] - m1n = wave.resource.frequency_moment(Sn, 1).values[0] + m1 = wave.resource.frequency_moment(S, 1).item() + m1n = wave.resource.frequency_moment(Sn, 1).item() errorm1 = np.abs((m1 - m1n) / m1) self.assertLess(errorm1, 0.01) From afc7f8cc86763eb3a5f9d3c0313d54737f849373 Mon Sep 17 00:00:00 2001 From: akeeste Date: Wed, 2 Oct 2024 11:35:04 -0500 Subject: [PATCH 15/39] clean up frequency_bin and method checks in elevation_surface --- mhkit/wave/resource.py | 53 ++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/mhkit/wave/resource.py b/mhkit/wave/resource.py index 73ca34d7..0d85acc5 100644 --- a/mhkit/wave/resource.py +++ b/mhkit/wave/resource.py @@ -272,13 +272,13 @@ def surface_elevation( method: str (optional) Method used to calculate the surface elevation. 'ifft' (Inverse Fast Fourier Transform) used by default if the - given frequency_bins==None. + given frequency_bins==None or is evenly spaced. 'sum_of_sines' explicitly sums each frequency component - and used by default if frequency_bins are provided. + and used by default if uneven frequency_bins are provided. The 'ifft' method is significantly faster. frequency_dimension: string (optional) Name of the xarray dimension corresponding to frequency. If not supplied, - defaults to the first dimension. Does not affect pandas input. + defaults to the first dimension (the index for pandas input). to_pandas: bool (optional) Flag to output pandas instead of xarray. Default = True. @@ -289,10 +289,6 @@ def surface_elevation( """ time_index = to_numeric_array(time_index, "time_index") - if isinstance(S, pd.DataFrame) and len(S.columns) > 1: - frequency_axis = 1 - else: - frequency_axis = 0 S = convert_to_dataarray(S) if not isinstance(seed, (type(None), int)): raise TypeError(f"If specified, seed must be of type int. Got: {type(seed)}") @@ -304,13 +300,13 @@ def surface_elevation( raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") if frequency_dimension == "": - frequency_dimension = list(S.coords)[frequency_axis] - elif frequency_dimension in list(S.dims): - frequency_axis = list(S.dims).index(frequency_dimension) - else: # frequency_dimension give, but not in list of possible dimensions + frequency_dimension = list(S.coords)[0] + elif frequency_dimension not in list(S.dims): + # frequency_dimension given, but not in list of possible dimensions raise ValueError( f"frequency_dimension is not a dimension of S ({list(S.dims)}). Got: {frequency_dimension}." ) + frequency_axis = list(S.dims).index(frequency_dimension) # Create dimensions and coordinates for the new dataset (frequency becomes time) new_dims = list(S.dims) @@ -330,37 +326,38 @@ def surface_elevation( if frequency_bins is not None: if not frequency_bins.squeeze().shape == f.shape: raise ValueError( - "shape of frequency_bins must match shape of the frequency dimension of S" + "shape of frequency_bins must only contain 1 column and match the shape of the frequency dimension of S" ) + delta_f = frequency_bins + delta_f_even = np.allclose(frequency_bins, frequency_bins[0]) + if delta_f_even: + # reduce delta_f to a scalar if it is uniform + delta_f = delta_f[0].item() + else: + delta_f = f.values[1] - f.values[0] + delta_f_even = np.allclose(f.diff(dim=frequency_dimension)[1:], delta_f) if phases is not None: if not phases.shape == S.shape: raise ValueError( "shape of variables in phases must match shape of variables in S" ) - if method is not None: - if not (method == "ifft" or method == "sum_of_sines"): - raise ValueError(f"Method must be 'ifft' or 'sum_of_sines'. Got: {method}") - if method == "ifft": + # ifft method must have a zero frequency and evenly spaced frequency bins if not f[0] == 0: warnings.warn( f"ifft method must have zero frequency defined. Lowest frequency is: {f[0].values}. Setting method to less efficient `sum_of_sines` method." ) method = "sum_of_sines" - - if frequency_bins is None: - delta_f = f.values[1] - f.values[0] - if not np.allclose(f.diff(dim=frequency_dimension)[1:], delta_f): - raise ValueError( - "Frequency bins are not evenly spaced. " - + "Define 'frequency_bins' or create a constant " - + "frequency spacing for S." + if not delta_f_even: + warnings.warn( + f"ifft method must have evenly spaced frequency bins. Setting method to less efficient `sum_of_sines` method." ) + method = "sum_of_sines" + elif method == 'sum_of_sines': + # For sum of sines, does not matter if there is a zero frequency or if frequency bins are evenly spaced + pass else: - if not len(frequency_bins.squeeze().shape) == 1: - raise ValueError("frequency_bins must only contain 1 column") - delta_f = frequency_bins - method = "sum_of_sines" + raise ValueError(f"Method must be 'ifft' or 'sum_of_sines'. Got: {method}") omega = xr.DataArray( data=2 * np.pi * f, dims=frequency_dimension, coords={frequency_dimension: f} From 8f1647fb3f69e33f6ff50a9379ac377c8960fbe2 Mon Sep 17 00:00:00 2001 From: akeeste Date: Wed, 2 Oct 2024 12:14:25 -0500 Subject: [PATCH 16/39] update and annotate type_handling --- mhkit/utils/type_handling.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mhkit/utils/type_handling.py b/mhkit/utils/type_handling.py index 323ff2c3..11e804c3 100644 --- a/mhkit/utils/type_handling.py +++ b/mhkit/utils/type_handling.py @@ -160,17 +160,21 @@ def convert_to_dataarray(data, name="data"): # iloc returns a Series with one value as expected. data = data.iloc[:, 0] else: + # With this conversion, dataframe columns always become "dim_1". + # Rename to "variable" to match how multiple Dataset variables get converted into a DataArray dimension data = xr.DataArray(data) + data = data.rename({'dim_1':'variable'}) # Checks xr.Dataset input and converts to xr.DataArray if possible if isinstance(data, xr.Dataset): keys = list(data.keys()) if len(keys) == 1: + # if only one variable, select that variable so reduce the Dataset to a DataArray data = data[keys[0]] else: # Allow multiple variables if they have the same dimensions if all([data[keys[0]].dims == data[key].dims for key in keys]): - data = data.to_array() + data = data.to_array().T # transpose so that the new "variable dimension" is the last dimension (matches DataFrame to DataArray behavior) else: raise ValueError( "Multivariate Datasets can only be input if all variables have the same dimensions." From c0d72d0a47344f6818706b5196d99311a04d2cc2 Mon Sep 17 00:00:00 2001 From: akeeste Date: Wed, 2 Oct 2024 12:15:02 -0500 Subject: [PATCH 17/39] black formatting --- mhkit/utils/type_handling.py | 8 +++++--- mhkit/wave/resource.py | 12 ++++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/mhkit/utils/type_handling.py b/mhkit/utils/type_handling.py index 11e804c3..d4643f6a 100644 --- a/mhkit/utils/type_handling.py +++ b/mhkit/utils/type_handling.py @@ -160,10 +160,10 @@ def convert_to_dataarray(data, name="data"): # iloc returns a Series with one value as expected. data = data.iloc[:, 0] else: - # With this conversion, dataframe columns always become "dim_1". + # With this conversion, dataframe columns always become "dim_1". # Rename to "variable" to match how multiple Dataset variables get converted into a DataArray dimension data = xr.DataArray(data) - data = data.rename({'dim_1':'variable'}) + data = data.rename({"dim_1": "variable"}) # Checks xr.Dataset input and converts to xr.DataArray if possible if isinstance(data, xr.Dataset): @@ -174,7 +174,9 @@ def convert_to_dataarray(data, name="data"): else: # Allow multiple variables if they have the same dimensions if all([data[keys[0]].dims == data[key].dims for key in keys]): - data = data.to_array().T # transpose so that the new "variable dimension" is the last dimension (matches DataFrame to DataArray behavior) + data = ( + data.to_array().T + ) # transpose so that the new "variable dimension" is the last dimension (matches DataFrame to DataArray behavior) else: raise ValueError( "Multivariate Datasets can only be input if all variables have the same dimensions." diff --git a/mhkit/wave/resource.py b/mhkit/wave/resource.py index 0d85acc5..66c3f3db 100644 --- a/mhkit/wave/resource.py +++ b/mhkit/wave/resource.py @@ -310,9 +310,9 @@ def surface_elevation( # Create dimensions and coordinates for the new dataset (frequency becomes time) new_dims = list(S.dims) - new_dims[frequency_axis] = 'Time' + new_dims[frequency_axis] = "Time" new_coords = S.sum(dim=frequency_dimension).coords - new_coords = new_coords.assign({'Time': time_index}) + new_coords = new_coords.assign({"Time": time_index}) f = S[frequency_dimension] if not isinstance(frequency_bins, (type(None), np.ndarray)): @@ -353,7 +353,7 @@ def surface_elevation( f"ifft method must have evenly spaced frequency bins. Setting method to less efficient `sum_of_sines` method." ) method = "sum_of_sines" - elif method == 'sum_of_sines': + elif method == "sum_of_sines": # For sum of sines, does not matter if there is a zero frequency or if frequency bins are evenly spaced pass else: @@ -379,7 +379,11 @@ def surface_elevation( if method == "ifft": A_cmplx = A * (np.cos(phase) + 1j * np.sin(phase)) # eta_tmp = np.fft.irfft(0.5 * A_cmplx.values * time_index.size, time_index.size) - eta_tmp = np.fft.irfftn(0.5 * A_cmplx * time_index.size, list(time_index.shape), axes=[frequency_axis]) + eta_tmp = np.fft.irfftn( + 0.5 * A_cmplx * time_index.size, + list(time_index.shape), + axes=[frequency_axis], + ) eta = xr.DataArray(data=eta_tmp, dims=new_dims, coords=new_coords) elif method == "sum_of_sines": From 8dddf42aaabded530727645377b669a6956e25b0 Mon Sep 17 00:00:00 2001 From: akeeste Date: Wed, 2 Oct 2024 14:08:24 -0500 Subject: [PATCH 18/39] minor type fix --- mhkit/tests/wave/test_performance.py | 1 + mhkit/utils/type_handling.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/mhkit/tests/wave/test_performance.py b/mhkit/tests/wave/test_performance.py index b8fce7cb..a12c8050 100644 --- a/mhkit/tests/wave/test_performance.py +++ b/mhkit/tests/wave/test_performance.py @@ -126,6 +126,7 @@ def test_powerperformance_workflow(self): if isfile(filename): os.remove(filename) P = pd.Series(np.random.normal(200, 40, 743), index=self.S.columns) + P.index.name = "variable" statistic = ["mean"] savepath = plotdir show_values = True diff --git a/mhkit/utils/type_handling.py b/mhkit/utils/type_handling.py index d4643f6a..e69dc5ef 100644 --- a/mhkit/utils/type_handling.py +++ b/mhkit/utils/type_handling.py @@ -163,7 +163,9 @@ def convert_to_dataarray(data, name="data"): # With this conversion, dataframe columns always become "dim_1". # Rename to "variable" to match how multiple Dataset variables get converted into a DataArray dimension data = xr.DataArray(data) - data = data.rename({"dim_1": "variable"}) + if data.dims[1] == "dim_1": + # Slight chance their is already a name for the columns + data = data.rename({"dim_1": "variable"}) # Checks xr.Dataset input and converts to xr.DataArray if possible if isinstance(data, xr.Dataset): From 3a170ff7c37d713798d56671cd4bd44c62764c6e Mon Sep 17 00:00:00 2001 From: akeeste Date: Wed, 2 Oct 2024 15:29:58 -0500 Subject: [PATCH 19/39] update type references in loads --- mhkit/loads/extreme/mler.py | 6 +++--- mhkit/tests/loads/test_loads.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mhkit/loads/extreme/mler.py b/mhkit/loads/extreme/mler.py index 5aa174d2..f77f7d88 100644 --- a/mhkit/loads/extreme/mler.py +++ b/mhkit/loads/extreme/mler.py @@ -61,9 +61,9 @@ def _calculate_spectral_values( spectrum_r = np.abs(rao_array) ** 2 * (2 * wave_spectrum) # Calculate spectral moments - m_0 = frequency_moment(pd.Series(spectrum_r, index=freq_hz), 0).iloc[0, 0] - m_1 = frequency_moment(pd.Series(spectrum_r, index=freq_hz), 1).iloc[0, 0] - m_2 = frequency_moment(pd.Series(spectrum_r, index=freq_hz), 2).iloc[0, 0] + m_0 = frequency_moment(pd.Series(spectrum_r, index=freq_hz), 0).item() + m_1 = frequency_moment(pd.Series(spectrum_r, index=freq_hz), 1).item() + m_2 = frequency_moment(pd.Series(spectrum_r, index=freq_hz), 2).item() # Calculate coefficient A_{R,n} coeff_a_rn = ( diff --git a/mhkit/tests/loads/test_loads.py b/mhkit/tests/loads/test_loads.py index 8c119a38..73b9a42d 100644 --- a/mhkit/tests/loads/test_loads.py +++ b/mhkit/tests/loads/test_loads.py @@ -422,7 +422,7 @@ def test_mler_wave_amp_normalize(self): mler["WaveSpectrum"] = self.mler["Res_Spec"].values mler["Phase"] = self.mler["phase"].values k = resource.wave_number(wave_freq, 70) - k = k.fillna(0) + np.nan_to_num(k, nan=0) mler_norm = loads.extreme.mler_wave_amp_normalize( 4.5 * 1.9, mler, self.sim, k.k.values ) @@ -442,7 +442,7 @@ def test_mler_export_time_series(self): mler["WaveSpectrum"] = self.mler["Norm_Spec"].values mler["Phase"] = self.mler["phase"].values k = resource.wave_number(wave_freq, 70) - k = k.fillna(0) + np.nan_to_num(k, nan=0) RAO = self.mler["RAO"].astype(complex) mler_ts = loads.extreme.mler_export_time_series( RAO.values, mler, self.sim, k.k.values From 42a85d81b610517e5abc5472eb8ed25b2cc7bde2 Mon Sep 17 00:00:00 2001 From: akeeste Date: Wed, 2 Oct 2024 15:45:13 -0500 Subject: [PATCH 20/39] update type references in loads - v2 --- mhkit/tests/loads/test_loads.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mhkit/tests/loads/test_loads.py b/mhkit/tests/loads/test_loads.py index 73b9a42d..2074364c 100644 --- a/mhkit/tests/loads/test_loads.py +++ b/mhkit/tests/loads/test_loads.py @@ -422,9 +422,9 @@ def test_mler_wave_amp_normalize(self): mler["WaveSpectrum"] = self.mler["Res_Spec"].values mler["Phase"] = self.mler["phase"].values k = resource.wave_number(wave_freq, 70) - np.nan_to_num(k, nan=0) + np.nan_to_num(k, 0) mler_norm = loads.extreme.mler_wave_amp_normalize( - 4.5 * 1.9, mler, self.sim, k.k.values + 4.5 * 1.9, mler, self.sim, k ) mler_norm.reset_index(drop=True, inplace=True) @@ -442,10 +442,10 @@ def test_mler_export_time_series(self): mler["WaveSpectrum"] = self.mler["Norm_Spec"].values mler["Phase"] = self.mler["phase"].values k = resource.wave_number(wave_freq, 70) - np.nan_to_num(k, nan=0) + np.nan_to_num(k, 0) RAO = self.mler["RAO"].astype(complex) mler_ts = loads.extreme.mler_export_time_series( - RAO.values, mler, self.sim, k.k.values + RAO.values, mler, self.sim, k ) mler_ts.index.name = None # compatibility with old data From 28b847bae7d7c6474d497f4fa40fe36a0bdf1c02 Mon Sep 17 00:00:00 2001 From: akeeste Date: Thu, 10 Oct 2024 12:14:56 -0500 Subject: [PATCH 21/39] black formatting --- mhkit/tests/loads/test_loads.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/mhkit/tests/loads/test_loads.py b/mhkit/tests/loads/test_loads.py index 2074364c..012a7ecb 100644 --- a/mhkit/tests/loads/test_loads.py +++ b/mhkit/tests/loads/test_loads.py @@ -423,9 +423,7 @@ def test_mler_wave_amp_normalize(self): mler["Phase"] = self.mler["phase"].values k = resource.wave_number(wave_freq, 70) np.nan_to_num(k, 0) - mler_norm = loads.extreme.mler_wave_amp_normalize( - 4.5 * 1.9, mler, self.sim, k - ) + mler_norm = loads.extreme.mler_wave_amp_normalize(4.5 * 1.9, mler, self.sim, k) mler_norm.reset_index(drop=True, inplace=True) assert_series_equal( @@ -444,9 +442,7 @@ def test_mler_export_time_series(self): k = resource.wave_number(wave_freq, 70) np.nan_to_num(k, 0) RAO = self.mler["RAO"].astype(complex) - mler_ts = loads.extreme.mler_export_time_series( - RAO.values, mler, self.sim, k - ) + mler_ts = loads.extreme.mler_export_time_series(RAO.values, mler, self.sim, k) mler_ts.index.name = None # compatibility with old data assert_frame_equal(self.mler_ts, mler_ts, atol=0.0001) From 2f04e879cc18e9f845229d813172967f2c5dfb8e Mon Sep 17 00:00:00 2001 From: akeeste Date: Thu, 10 Oct 2024 12:23:22 -0500 Subject: [PATCH 22/39] fix call to fillna() in MLER example --- examples/extreme_response_MLER_example.ipynb | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/examples/extreme_response_MLER_example.ipynb b/examples/extreme_response_MLER_example.ipynb index 2860c6ef..dc5d9402 100644 --- a/examples/extreme_response_MLER_example.ipynb +++ b/examples/extreme_response_MLER_example.ipynb @@ -197,7 +197,7 @@ "\n", "# generate wave number k\n", "k = resource.wave_number(wave_freq, 70)\n", - "k = k.fillna(0)\n", + "np.nan_to_num(k, 0)\n", "\n", "peakHeightDesired = Hs / 2 * 1.9\n", "mler_norm = extreme.mler_wave_amp_normalize(\n", @@ -256,7 +256,7 @@ "hash": "6acc4428af86beefd6565514d05fe9ce8e024621fafadd3627cdac7b7bd68bc4" }, "kernelspec": { - "display_name": "Python 3.8.10 64-bit ('MHKdev': conda)", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -270,10 +270,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.7" - }, - "orig_nbformat": 4 + "version": "3.12.4" + } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } From d3fcc025d6ae9e5e6315adee4183363e00fdee06 Mon Sep 17 00:00:00 2001 From: akeeste Date: Thu, 10 Oct 2024 12:28:37 -0500 Subject: [PATCH 23/39] fix references to k in MLER example --- examples/extreme_response_MLER_example.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/extreme_response_MLER_example.ipynb b/examples/extreme_response_MLER_example.ipynb index dc5d9402..be95fb28 100644 --- a/examples/extreme_response_MLER_example.ipynb +++ b/examples/extreme_response_MLER_example.ipynb @@ -201,7 +201,7 @@ "\n", "peakHeightDesired = Hs / 2 * 1.9\n", "mler_norm = extreme.mler_wave_amp_normalize(\n", - " peakHeightDesired, mler_data, sim, k.k.values\n", + " peakHeightDesired, mler_data, sim, k\n", ")" ] }, @@ -239,7 +239,7 @@ } ], "source": [ - "mler_ts = extreme.mler_export_time_series(RAO.values, mler_norm, sim, k.k.values)\n", + "mler_ts = extreme.mler_export_time_series(RAO.values, mler_norm, sim, k)\n", "mler_ts.plot(xlabel=\"Time (s)\", ylabel=\"[m] / [*]\", xlim=[-100, 100], grid=True)" ] }, From 07b503332754f426f6b75ce6d31340979210a6ff Mon Sep 17 00:00:00 2001 From: akeeste Date: Thu, 10 Oct 2024 13:33:37 -0500 Subject: [PATCH 24/39] add variable names to Hm0, Te, and Tp for DataFrame creation --- examples/environmental_contours_example.ipynb | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/examples/environmental_contours_example.ipynb b/examples/environmental_contours_example.ipynb index 9f5e72da..c97f2a63 100644 --- a/examples/environmental_contours_example.ipynb +++ b/examples/environmental_contours_example.ipynb @@ -647,9 +647,13 @@ " Hm0_list.append(resource.significant_wave_height(year_data.T))\n", " Te_list.append(resource.energy_period(year_data.T))\n", "\n", - "# Concatenate list of Series into a single DataFrame\n", + "# Concatenate each list of Series into a single Series\n", "Te = pd.concat(Te_list, axis=0)\n", "Hm0 = pd.concat(Hm0_list, axis=0)\n", + "\n", + "# Name each Series and concat into a dataFrame\n", + "Te.name = 'Te'\n", + "Hm0.name = 'Hm0'\n", "Hm0_Te = pd.concat([Hm0, Te], axis=1)\n", "\n", "# Drop any NaNs created from the calculation of Hm0 or Te\n", @@ -800,7 +804,7 @@ "source": [ "## Resource Clusters\n", "\n", - "Often in resource characterization we want to pick a few representative sea state to run an alaysis. To do this with the resource data in python we reccomend using a Gaussian Mixture Model (a more generalized k-means clustering method). Using sckitlearn this is very straigth forward. We combine our Hm0 and Te data into an N x 2 numpy array. We specify our number of components (number of representative sea states) and then call the fit method on the data. Fianlly, using the methods `means_` and `weights` we can organize the results into an easily digestable table." + "Often in resource characterization we want to pick a few representative sea state to run an alaysis. To do this with the resource data in python we reccomend using a Gaussian Mixture Model (a more generalized k-means clustering method). Using sckitlearn this is very straight forward. We combine our Hm0 and Te data into an N x 2 numpy array. We specify our number of components (number of representative sea states) and then call the fit method on the data. Fianlly, using the methods `means_` and `weights` we can organize the results into an easily digestable table." ] }, { @@ -933,9 +937,13 @@ " Hm0_list.append(resource.significant_wave_height(year_data.T))\n", " Tp_list.append(resource.peak_period(year_data.T))\n", "\n", - "# Concatenate list of Series into a single DataFrame\n", + "# Concatenate each list of Series into a single Series\n", "Tp = pd.concat(Tp_list, axis=0)\n", "Hm0 = pd.concat(Hm0_list, axis=0)\n", + "\n", + "# Name each Series and concat into a dataFrame\n", + "Tp.name = 'Tp'\n", + "Hm0.name = 'Hm0'\n", "Hm0_Tp = pd.concat([Hm0, Tp], axis=1)\n", "\n", "# Drop any NaNs created from the calculation of Hm0 or Te\n", @@ -1116,7 +1124,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3.9.13 ('.venv': venv)", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -1130,7 +1138,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.7" + "version": "3.12.4" }, "vscode": { "interpreter": { From 48112023a3ad5430f25a33f43b96b7bee64eaed0 Mon Sep 17 00:00:00 2001 From: akeeste Date: Thu, 10 Oct 2024 13:53:46 -0500 Subject: [PATCH 25/39] update pd.Series naming in examples --- .../PacWave_resource_characterization_example.ipynb | 12 ++++++++++-- examples/extreme_response_contour_example.ipynb | 8 ++++++-- .../extreme_response_full_sea_state_example.ipynb | 8 ++++++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/examples/PacWave_resource_characterization_example.ipynb b/examples/PacWave_resource_characterization_example.ipynb index 9f46be4b..98c8379e 100644 --- a/examples/PacWave_resource_characterization_example.ipynb +++ b/examples/PacWave_resource_characterization_example.ipynb @@ -1119,7 +1119,7 @@ "\n", " Tz_list.append(resource.average_zero_crossing_period(year_data.T))\n", "\n", - "# Concatenate list of Series into a single DataFrame\n", + "# Concatenate each list of Series into a single Series\n", "Te = pd.concat(Te_list, axis=0)\n", "Tp = pd.concat(Tp_list, axis=0)\n", "Hm0 = pd.concat(Hm0_list, axis=0)\n", @@ -1127,6 +1127,14 @@ "Tz = pd.concat(Tz_list, axis=0)\n", "data = pd.concat([Hm0, Te, Tp, J, Tz], axis=1)\n", "\n", + "# Name each Series and concat into a dataFrame\n", + "Te.name = 'Te'\n", + "Tp.name = 'Tp'\n", + "Hm0.name = 'Hm0'\n", + "J.name = 'J'\n", + "Tz.name = 'Tz'\n", + "data = pd.concat([Hm0, Te], axis=1)\n", + "\n", "# Calculate wave steepness\n", "data[\"Sm\"] = data.Hm0 / (9.81 / (2 * np.pi) * data.Tz**2)\n", "\n", @@ -1622,7 +1630,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.7" + "version": "3.12.4" } }, "nbformat": 4, diff --git a/examples/extreme_response_contour_example.ipynb b/examples/extreme_response_contour_example.ipynb index ae22dd57..0ee20f4c 100644 --- a/examples/extreme_response_contour_example.ipynb +++ b/examples/extreme_response_contour_example.ipynb @@ -72,9 +72,13 @@ " Hm0_list.append(resource.significant_wave_height(year_data.T))\n", " Te_list.append(resource.energy_period(year_data.T))\n", "\n", - "# Concatenate list of Series into a single DataFrame\n", + "# Concatenate each list of Series into a single Series\n", "Te = pd.concat(Te_list, axis=0)\n", "Hm0 = pd.concat(Hm0_list, axis=0)\n", + "\n", + "# Name each Series and concat into a dataFrame\n", + "Te.name = 'Te'\n", + "Hm0.name = 'Hm0'\n", "Hm0_Te = pd.concat([Hm0, Te], axis=1)\n", "\n", "# Drop any NaNs created from the calculation of Hm0 or Te\n", @@ -323,7 +327,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.7" + "version": "3.12.4" } }, "nbformat": 4, diff --git a/examples/extreme_response_full_sea_state_example.ipynb b/examples/extreme_response_full_sea_state_example.ipynb index 4181e1bc..76266e05 100644 --- a/examples/extreme_response_full_sea_state_example.ipynb +++ b/examples/extreme_response_full_sea_state_example.ipynb @@ -75,9 +75,13 @@ " Hm0_list.append(resource.significant_wave_height(year_data.T))\n", " Te_list.append(resource.energy_period(year_data.T))\n", "\n", - "# Concatenate list of Series into a single DataFrame\n", + "# Concatenate each list of Series into a single Series\n", "Te = pd.concat(Te_list, axis=0)\n", "Hm0 = pd.concat(Hm0_list, axis=0)\n", + "\n", + "# Name each Series and concat into a dataFrame\n", + "Te.name = 'Te'\n", + "Hm0.name = 'Hm0'\n", "Hm0_Te = pd.concat([Hm0, Te], axis=1)\n", "\n", "# Drop any NaNs created from the calculation of Hm0 or Te\n", @@ -573,7 +577,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.7" + "version": "3.12.4" } }, "nbformat": 4, From 77c1980f41675fbfca21e0a021c994b603d43966 Mon Sep 17 00:00:00 2001 From: akeeste Date: Fri, 11 Oct 2024 13:42:31 -0500 Subject: [PATCH 26/39] fix typo in pacwave notebook --- examples/PacWave_resource_characterization_example.ipynb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/PacWave_resource_characterization_example.ipynb b/examples/PacWave_resource_characterization_example.ipynb index 98c8379e..1ab0f33e 100644 --- a/examples/PacWave_resource_characterization_example.ipynb +++ b/examples/PacWave_resource_characterization_example.ipynb @@ -1125,7 +1125,6 @@ "Hm0 = pd.concat(Hm0_list, axis=0)\n", "J = pd.concat(J_list, axis=0)\n", "Tz = pd.concat(Tz_list, axis=0)\n", - "data = pd.concat([Hm0, Te, Tp, J, Tz], axis=1)\n", "\n", "# Name each Series and concat into a dataFrame\n", "Te.name = 'Te'\n", @@ -1133,7 +1132,7 @@ "Hm0.name = 'Hm0'\n", "J.name = 'J'\n", "Tz.name = 'Tz'\n", - "data = pd.concat([Hm0, Te], axis=1)\n", + "data = pd.concat([Hm0, Te, Tp, J, Tz], axis=1)\n", "\n", "# Calculate wave steepness\n", "data[\"Sm\"] = data.Hm0 / (9.81 / (2 * np.pi) * data.Tz**2)\n", From 6dbbc18a1e501aa9106dd70c3174aa1939ac475d Mon Sep 17 00:00:00 2001 From: akeeste Date: Mon, 14 Oct 2024 10:43:04 -0500 Subject: [PATCH 27/39] add variable names after data conversion --- mhkit/wave/resource.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/mhkit/wave/resource.py b/mhkit/wave/resource.py index 66c3f3db..6fba4a4a 100644 --- a/mhkit/wave/resource.py +++ b/mhkit/wave/resource.py @@ -402,6 +402,7 @@ def surface_elevation( if to_pandas: eta = eta.to_pandas() + eta.name = "eta" return eta @@ -463,10 +464,9 @@ def frequency_moment(S, N, frequency_bins=None, frequency_dimension="", to_panda m = S * fn * delta_f m = m.sum(dim=frequency_dimension) - m.name = "m" + str(N) - if to_pandas: m = m.to_pandas() + m.name = "m" + str(N) return m @@ -510,6 +510,7 @@ def significant_wave_height( if to_pandas: Hm0 = Hm0.to_pandas() + Hm0.name = "Hm0" return Hm0 @@ -559,6 +560,7 @@ def average_zero_crossing_period( if to_pandas: Tz = Tz.to_pandas() + Tz.name = "Tz" return Tz @@ -609,6 +611,7 @@ def average_crest_period( if to_pandas: Tavg = Tavg.to_pandas() + Tavg.name = "Tavg" return Tavg @@ -656,6 +659,7 @@ def average_wave_period(S, frequency_dimension="", frequency_bins=None, to_panda if to_pandas: Tm = Tm.to_pandas() + Tm.name = "Tm" return Tm @@ -696,6 +700,7 @@ def peak_period(S, frequency_dimension="", to_pandas=True): if to_pandas: Tp = Tp.to_pandas() + Tp.name = "Tp" return Tp @@ -742,10 +747,10 @@ def energy_period(S, frequency_dimension="", frequency_bins=None, to_pandas=True # Eq 13 in IEC 62600-101 Te = mn1 / m0 - Te.name = "Te" if to_pandas: Te = Te.to_pandas() + Te.name = "Te" return Te @@ -801,6 +806,7 @@ def spectral_bandwidth(S, frequency_dimension="", frequency_bins=None, to_pandas if to_pandas: e = e.to_pandas() + e.name = "e" return e @@ -856,6 +862,7 @@ def spectral_width(S, frequency_dimension="", frequency_bins=None, to_pandas=Tru if to_pandas: v = v.to_pandas() + v.name = "v" return v @@ -952,6 +959,7 @@ def energy_flux( if to_pandas: J = J.to_pandas() + J.name = "J" return J @@ -987,6 +995,8 @@ def energy_period_to_peak_period(Te, gamma): factor = 0.8255 + 0.03852 * gamma - 0.005537 * gamma**2 + 0.0003154 * gamma**3 Tp = Te / factor + if isinstance(Tp, (pd.Series, pd.DataFrame, xr.DataArray)): + Tp.name = "Tp" return Tp @@ -1079,10 +1089,9 @@ def wave_celerity( ) Cg.name = "Cg" - # Cg = Cg.to_dataset() - if to_pandas: Cg = Cg.to_pandas() + Cg.name = "Cg" return Cg @@ -1110,6 +1119,8 @@ def wave_length(k): ) l = 2 * np.pi / k + if isinstance(l, (pd.Series, pd.DataFrame, xr.DataArray)): + l.name = "l" return l @@ -1172,12 +1183,9 @@ def func(kk): k0[mask] = k k = k0 - if isinstance(k0, (pd.Series, xr.DataArray)): + if isinstance(k, (pd.Series, pd.DataFrame, xr.DataArray)): k.name = "k" - # if to_pandas: - # k = k.to_pandas() - return k @@ -1217,5 +1225,7 @@ def depth_regime(l, h, ratio=2): raise TypeError(f"h must be of type int or float. Got: {type(h)}") depth_reg = h / l > ratio + if isinstance(depth_reg, (pd.Series, pd.DataFrame, xr.DataArray)): + depth_reg.name = "depth_reg" return depth_reg From 664d2e9bfdef1779a4fb5a16b302e1fe14111f53 Mon Sep 17 00:00:00 2001 From: akeeste Date: Mon, 14 Oct 2024 11:06:25 -0500 Subject: [PATCH 28/39] update pacwave example --- examples/PacWave_resource_characterization_example.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/PacWave_resource_characterization_example.ipynb b/examples/PacWave_resource_characterization_example.ipynb index 1ab0f33e..32bcc49f 100644 --- a/examples/PacWave_resource_characterization_example.ipynb +++ b/examples/PacWave_resource_characterization_example.ipynb @@ -1597,7 +1597,7 @@ " J = []\n", " for i in range(len(result)):\n", " b = resource.jonswap_spectrum(f, result.Tp[i], result.Hm0[i])\n", - " J.extend([resource.energy_flux(b, h=399.0).values[0][0]])\n", + " J.extend([resource.energy_flux(b, h=399.0).item()])\n", "\n", " result[\"J\"] = J\n", " results[N] = result\n", @@ -1629,7 +1629,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.4" + "version": "3.12.7" } }, "nbformat": 4, From dad0d0aea2ea3be0f1d9af1221242a5d34b2a93c Mon Sep 17 00:00:00 2001 From: akeeste Date: Mon, 14 Oct 2024 11:07:16 -0500 Subject: [PATCH 29/39] add type check to all wave.resource variable naming --- mhkit/wave/resource.py | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/mhkit/wave/resource.py b/mhkit/wave/resource.py index 6fba4a4a..ab99518d 100644 --- a/mhkit/wave/resource.py +++ b/mhkit/wave/resource.py @@ -402,7 +402,8 @@ def surface_elevation( if to_pandas: eta = eta.to_pandas() - eta.name = "eta" + if isinstance(eta, (pd.Series, pd.DataFrame, xr.DataArray)): + eta.name = "eta" return eta @@ -466,7 +467,8 @@ def frequency_moment(S, N, frequency_bins=None, frequency_dimension="", to_panda if to_pandas: m = m.to_pandas() - m.name = "m" + str(N) + if isinstance(m, (pd.Series, pd.DataFrame, xr.DataArray)): + m.name = "m" + str(N) return m @@ -510,7 +512,8 @@ def significant_wave_height( if to_pandas: Hm0 = Hm0.to_pandas() - Hm0.name = "Hm0" + if isinstance(Hm0, (pd.Series, pd.DataFrame, xr.DataArray)): + Hm0.name = "Hm0" return Hm0 @@ -560,7 +563,8 @@ def average_zero_crossing_period( if to_pandas: Tz = Tz.to_pandas() - Tz.name = "Tz" + if isinstance(Tz, (pd.Series, pd.DataFrame, xr.DataArray)): + Tz.name = "Tz" return Tz @@ -611,7 +615,8 @@ def average_crest_period( if to_pandas: Tavg = Tavg.to_pandas() - Tavg.name = "Tavg" + if isinstance(Tavg, (pd.Series, pd.DataFrame, xr.DataArray)): + Tavg.name = "Tavg" return Tavg @@ -659,7 +664,8 @@ def average_wave_period(S, frequency_dimension="", frequency_bins=None, to_panda if to_pandas: Tm = Tm.to_pandas() - Tm.name = "Tm" + if isinstance(Tm, (pd.Series, pd.DataFrame, xr.DataArray)): + Tm.name = "Tm" return Tm @@ -700,7 +706,8 @@ def peak_period(S, frequency_dimension="", to_pandas=True): if to_pandas: Tp = Tp.to_pandas() - Tp.name = "Tp" + if isinstance(Tp, (pd.Series, pd.DataFrame, xr.DataArray)): + Tp.name = "Tp" return Tp @@ -750,7 +757,8 @@ def energy_period(S, frequency_dimension="", frequency_bins=None, to_pandas=True if to_pandas: Te = Te.to_pandas() - Te.name = "Te" + if isinstance(Te, (pd.Series, pd.DataFrame, xr.DataArray)): + Te.name = "Te" return Te @@ -806,7 +814,8 @@ def spectral_bandwidth(S, frequency_dimension="", frequency_bins=None, to_pandas if to_pandas: e = e.to_pandas() - e.name = "e" + if isinstance(e, (pd.Series, pd.DataFrame, xr.DataArray)): + e.name = "e" return e @@ -862,7 +871,8 @@ def spectral_width(S, frequency_dimension="", frequency_bins=None, to_pandas=Tru if to_pandas: v = v.to_pandas() - v.name = "v" + if isinstance(v, (pd.Series, pd.DataFrame, xr.DataArray)): + v.name = "v" return v @@ -959,7 +969,8 @@ def energy_flux( if to_pandas: J = J.to_pandas() - J.name = "J" + if isinstance(J, (pd.Series, pd.DataFrame, xr.DataArray)): + J.name = "J" return J @@ -1091,7 +1102,8 @@ def wave_celerity( if to_pandas: Cg = Cg.to_pandas() - Cg.name = "Cg" + if isinstance(Cg, (pd.Series, pd.DataFrame, xr.DataArray)): + Cg.name = "Cg" return Cg From 853521dd7efd16b869def21f537cd646cb4fe4b8 Mon Sep 17 00:00:00 2001 From: akeeste Date: Mon, 14 Oct 2024 11:24:46 -0500 Subject: [PATCH 30/39] update wave example with new data types --- examples/wave_example.ipynb | 5615 +++++++++++++++++------------------ 1 file changed, 2770 insertions(+), 2845 deletions(-) diff --git a/examples/wave_example.ipynb b/examples/wave_example.ipynb index e03f81fe..2beb8de1 100644 --- a/examples/wave_example.ipynb +++ b/examples/wave_example.ipynb @@ -1,2883 +1,2808 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# MHKiT Wave Module \n", - "The following example runs an application of the [MHKiT wave module](https://mhkit-software.github.io/MHKiT/mhkit-python/api.wave.html) to 1) read in NDBC data, 2) compute metrics from spectral data, 3) generate a capture length matrix, 4) calculate MAEP, and 5) plot the matrices.\n", - "\n", - "Start by importing the necessary python packages and MHKiT module." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import pandas as pd\n", - "from mhkit import wave" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Load NDBC Data \n", - "\n", - "We can use MHKiT to load data downloaded from https://www.ndbc.noaa.gov. \n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "c:\\users\\sterl\\codes\\mhkit-python\\mhkit\\wave\\io\\ndbc.py:99: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.\n", - " data = pd.read_csv(\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
0.02000.03250.03750.04250.04750.05250.05750.06250.06750.0725...0.33000.34000.35000.36500.38500.40500.42500.44500.46500.4850
2018-01-01 00:40:000.00.00.00.00.00.030.040.090.220.22...0.070.080.070.070.030.010.020.010.010.0
2018-01-01 01:40:000.00.00.00.00.00.020.060.080.210.21...0.070.070.080.020.010.020.010.010.000.0
2018-01-01 02:40:000.00.00.00.00.00.000.080.070.140.32...0.080.060.050.030.030.020.010.010.000.0
2018-01-01 03:40:000.00.00.00.00.00.000.130.220.260.32...0.050.060.050.030.030.010.010.000.000.0
2018-01-01 04:40:000.00.00.00.00.00.030.140.170.370.40...0.060.120.040.040.020.010.010.010.010.0
\n", - "

5 rows × 47 columns

\n", - "
" - ], - "text/plain": [ - " 0.0200 0.0325 0.0375 0.0425 0.0475 0.0525 0.0575 \\\n", - "2018-01-01 00:40:00 0.0 0.0 0.0 0.0 0.0 0.03 0.04 \n", - "2018-01-01 01:40:00 0.0 0.0 0.0 0.0 0.0 0.02 0.06 \n", - "2018-01-01 02:40:00 0.0 0.0 0.0 0.0 0.0 0.00 0.08 \n", - "2018-01-01 03:40:00 0.0 0.0 0.0 0.0 0.0 0.00 0.13 \n", - "2018-01-01 04:40:00 0.0 0.0 0.0 0.0 0.0 0.03 0.14 \n", - "\n", - " 0.0625 0.0675 0.0725 ... 0.3300 0.3400 0.3500 \\\n", - "2018-01-01 00:40:00 0.09 0.22 0.22 ... 0.07 0.08 0.07 \n", - "2018-01-01 01:40:00 0.08 0.21 0.21 ... 0.07 0.07 0.08 \n", - "2018-01-01 02:40:00 0.07 0.14 0.32 ... 0.08 0.06 0.05 \n", - "2018-01-01 03:40:00 0.22 0.26 0.32 ... 0.05 0.06 0.05 \n", - "2018-01-01 04:40:00 0.17 0.37 0.40 ... 0.06 0.12 0.04 \n", - "\n", - " 0.3650 0.3850 0.4050 0.4250 0.4450 0.4650 0.4850 \n", - "2018-01-01 00:40:00 0.07 0.03 0.01 0.02 0.01 0.01 0.0 \n", - "2018-01-01 01:40:00 0.02 0.01 0.02 0.01 0.01 0.00 0.0 \n", - "2018-01-01 02:40:00 0.03 0.03 0.02 0.01 0.01 0.00 0.0 \n", - "2018-01-01 03:40:00 0.03 0.03 0.01 0.01 0.00 0.00 0.0 \n", - "2018-01-01 04:40:00 0.04 0.02 0.01 0.01 0.01 0.01 0.0 \n", - "\n", - "[5 rows x 47 columns]" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "ndbc_data_file = \"data/wave/data.txt\"\n", - "\n", - "# ndbc.read_file outputs the NDBC file data into two variables.\n", - "# raw_ndbc_data is a pandas DataFrame containing the file data.\n", - "# meta contains the meta data, if available.\n", - "[raw_ndbc_data, meta] = wave.io.ndbc.read_file(ndbc_data_file)\n", - "raw_ndbc_data.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The resulting DataFrame is spectra indexed (rows) by datetime with frequency as the columns. To use this data in MHKiT functions we must first transpose the DataFrame" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
2018-01-01 00:40:002018-01-01 01:40:002018-01-01 02:40:002018-01-01 03:40:002018-01-01 04:40:002018-01-01 05:40:002018-01-01 06:40:002018-01-01 07:40:002018-01-01 08:40:002018-01-01 09:40:00...2018-01-31 14:40:002018-01-31 15:40:002018-01-31 16:40:002018-01-31 17:40:002018-01-31 18:40:002018-01-31 19:40:002018-01-31 20:40:002018-01-31 21:40:002018-01-31 22:40:002018-01-31 23:40:00
0.02000.00.00.00.00.00.000.00.00.00.0...0.000.00.00.00.000.00.00.00.00.0
0.03250.00.00.00.00.00.000.00.00.00.0...0.000.00.00.00.000.00.00.00.00.0
0.03750.00.00.00.00.00.000.00.00.00.0...0.000.00.00.00.000.00.00.00.00.0
0.04250.00.00.00.00.00.000.00.00.00.0...0.000.00.00.00.000.00.00.00.00.0
0.04750.00.00.00.00.00.010.00.00.00.0...0.060.00.00.00.070.00.00.00.00.0
\n", - "

5 rows × 743 columns

\n", - "
" - ], - "text/plain": [ - " 2018-01-01 00:40:00 2018-01-01 01:40:00 2018-01-01 02:40:00 \\\n", - "0.0200 0.0 0.0 0.0 \n", - "0.0325 0.0 0.0 0.0 \n", - "0.0375 0.0 0.0 0.0 \n", - "0.0425 0.0 0.0 0.0 \n", - "0.0475 0.0 0.0 0.0 \n", - "\n", - " 2018-01-01 03:40:00 2018-01-01 04:40:00 2018-01-01 05:40:00 \\\n", - "0.0200 0.0 0.0 0.00 \n", - "0.0325 0.0 0.0 0.00 \n", - "0.0375 0.0 0.0 0.00 \n", - "0.0425 0.0 0.0 0.00 \n", - "0.0475 0.0 0.0 0.01 \n", - "\n", - " 2018-01-01 06:40:00 2018-01-01 07:40:00 2018-01-01 08:40:00 \\\n", - "0.0200 0.0 0.0 0.0 \n", - "0.0325 0.0 0.0 0.0 \n", - "0.0375 0.0 0.0 0.0 \n", - "0.0425 0.0 0.0 0.0 \n", - "0.0475 0.0 0.0 0.0 \n", - "\n", - " 2018-01-01 09:40:00 ... 2018-01-31 14:40:00 2018-01-31 15:40:00 \\\n", - "0.0200 0.0 ... 0.00 0.0 \n", - "0.0325 0.0 ... 0.00 0.0 \n", - "0.0375 0.0 ... 0.00 0.0 \n", - "0.0425 0.0 ... 0.00 0.0 \n", - "0.0475 0.0 ... 0.06 0.0 \n", - "\n", - " 2018-01-31 16:40:00 2018-01-31 17:40:00 2018-01-31 18:40:00 \\\n", - "0.0200 0.0 0.0 0.00 \n", - "0.0325 0.0 0.0 0.00 \n", - "0.0375 0.0 0.0 0.00 \n", - "0.0425 0.0 0.0 0.00 \n", - "0.0475 0.0 0.0 0.07 \n", - "\n", - " 2018-01-31 19:40:00 2018-01-31 20:40:00 2018-01-31 21:40:00 \\\n", - "0.0200 0.0 0.0 0.0 \n", - "0.0325 0.0 0.0 0.0 \n", - "0.0375 0.0 0.0 0.0 \n", - "0.0425 0.0 0.0 0.0 \n", - "0.0475 0.0 0.0 0.0 \n", - "\n", - " 2018-01-31 22:40:00 2018-01-31 23:40:00 \n", - "0.0200 0.0 0.0 \n", - "0.0325 0.0 0.0 \n", - "0.0375 0.0 0.0 \n", - "0.0425 0.0 0.0 \n", - "0.0475 0.0 0.0 \n", - "\n", - "[5 rows x 743 columns]" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Transpose raw NDBC data\n", - "ndbc_data = raw_ndbc_data.T\n", - "ndbc_data.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Compute Wave Metrics \n", - "We will now use MHKiT to compute the significant wave height, energy period, and energy flux. " - ] - }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# MHKiT Wave Module \n", + "The following example runs an application of the [MHKiT wave module](https://mhkit-software.github.io/MHKiT/mhkit-python/api.wave.html) to 1) read in NDBC data, 2) compute metrics from spectral data, 3) generate a capture length matrix, 4) calculate MAEP, and 5) plot the matrices.\n", + "\n", + "Start by importing the necessary python packages and MHKiT module." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "from mhkit import wave" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Load NDBC Data \n", + "\n", + "We can use MHKiT to load data downloaded from https://www.ndbc.noaa.gov. \n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Te
index
2018-01-01 00:40:007.458731
2018-01-01 01:40:007.682413
2018-01-01 02:40:007.498263
2018-01-01 03:40:007.676198
2018-01-01 04:40:007.669476
\n", - "
" - ], - "text/plain": [ - " Te\n", - "index \n", - "2018-01-01 00:40:00 7.458731\n", - "2018-01-01 01:40:00 7.682413\n", - "2018-01-01 02:40:00 7.498263\n", - "2018-01-01 03:40:00 7.676198\n", - "2018-01-01 04:40:00 7.669476" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Compute the enegy periods from the NDBC spectra data\n", - "Te = wave.resource.energy_period(ndbc_data)\n", - "Te.head()" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\users\\sterl\\codes\\mhkit-python\\mhkit\\wave\\io\\ndbc.py:99: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.\n", + " data = pd.read_csv(\n" + ] }, { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Hm0
index
2018-01-01 00:40:000.939574
2018-01-01 01:40:001.001399
2018-01-01 02:40:000.924770
2018-01-01 03:40:000.962497
2018-01-01 04:40:000.989949
\n", - "
" - ], - "text/plain": [ - " Hm0\n", - "index \n", - "2018-01-01 00:40:00 0.939574\n", - "2018-01-01 01:40:00 1.001399\n", - "2018-01-01 02:40:00 0.924770\n", - "2018-01-01 03:40:00 0.962497\n", - "2018-01-01 04:40:00 0.989949" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
0.02000.03250.03750.04250.04750.05250.05750.06250.06750.0725...0.33000.34000.35000.36500.38500.40500.42500.44500.46500.4850
2018-01-01 00:40:000.00.00.00.00.00.030.040.090.220.22...0.070.080.070.070.030.010.020.010.010.0
2018-01-01 01:40:000.00.00.00.00.00.020.060.080.210.21...0.070.070.080.020.010.020.010.010.000.0
2018-01-01 02:40:000.00.00.00.00.00.000.080.070.140.32...0.080.060.050.030.030.020.010.010.000.0
2018-01-01 03:40:000.00.00.00.00.00.000.130.220.260.32...0.050.060.050.030.030.010.010.000.000.0
2018-01-01 04:40:000.00.00.00.00.00.030.140.170.370.40...0.060.120.040.040.020.010.010.010.010.0
\n", + "

5 rows × 47 columns

\n", + "
" ], - "source": [ - "# Compute the significant wave height from the NDBC spectra data\n", - "Hm0 = wave.resource.significant_wave_height(ndbc_data)\n", - "Hm0.head()" + "text/plain": [ + " 0.0200 0.0325 0.0375 0.0425 0.0475 0.0525 0.0575 \\\n", + "2018-01-01 00:40:00 0.0 0.0 0.0 0.0 0.0 0.03 0.04 \n", + "2018-01-01 01:40:00 0.0 0.0 0.0 0.0 0.0 0.02 0.06 \n", + "2018-01-01 02:40:00 0.0 0.0 0.0 0.0 0.0 0.00 0.08 \n", + "2018-01-01 03:40:00 0.0 0.0 0.0 0.0 0.0 0.00 0.13 \n", + "2018-01-01 04:40:00 0.0 0.0 0.0 0.0 0.0 0.03 0.14 \n", + "\n", + " 0.0625 0.0675 0.0725 ... 0.3300 0.3400 0.3500 \\\n", + "2018-01-01 00:40:00 0.09 0.22 0.22 ... 0.07 0.08 0.07 \n", + "2018-01-01 01:40:00 0.08 0.21 0.21 ... 0.07 0.07 0.08 \n", + "2018-01-01 02:40:00 0.07 0.14 0.32 ... 0.08 0.06 0.05 \n", + "2018-01-01 03:40:00 0.22 0.26 0.32 ... 0.05 0.06 0.05 \n", + "2018-01-01 04:40:00 0.17 0.37 0.40 ... 0.06 0.12 0.04 \n", + "\n", + " 0.3650 0.3850 0.4050 0.4250 0.4450 0.4650 0.4850 \n", + "2018-01-01 00:40:00 0.07 0.03 0.01 0.02 0.01 0.01 0.0 \n", + "2018-01-01 01:40:00 0.02 0.01 0.02 0.01 0.01 0.00 0.0 \n", + "2018-01-01 02:40:00 0.03 0.03 0.02 0.01 0.01 0.00 0.0 \n", + "2018-01-01 03:40:00 0.03 0.03 0.01 0.01 0.00 0.00 0.0 \n", + "2018-01-01 04:40:00 0.04 0.02 0.01 0.01 0.01 0.01 0.0 \n", + "\n", + "[5 rows x 47 columns]" ] - }, + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ndbc_data_file = \"data/wave/data.txt\"\n", + "\n", + "# ndbc.read_file outputs the NDBC file data into two variables.\n", + "# raw_ndbc_data is a pandas DataFrame containing the file data.\n", + "# meta contains the meta data, if available.\n", + "[raw_ndbc_data, meta] = wave.io.ndbc.read_file(ndbc_data_file)\n", + "raw_ndbc_data.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The resulting DataFrame is spectra indexed (rows) by datetime with frequency as the columns. To use this data in MHKiT functions we must first transpose the DataFrame" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
J
index
2018-01-01 00:40:003354.825613
2018-01-01 01:40:003916.541523
2018-01-01 02:40:003278.298930
2018-01-01 03:40:003664.246679
2018-01-01 04:40:003867.014933
\n", - "
" - ], - "text/plain": [ - " J\n", - "index \n", - "2018-01-01 00:40:00 3354.825613\n", - "2018-01-01 01:40:00 3916.541523\n", - "2018-01-01 02:40:00 3278.298930\n", - "2018-01-01 03:40:00 3664.246679\n", - "2018-01-01 04:40:00 3867.014933" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
2018-01-01 00:40:002018-01-01 01:40:002018-01-01 02:40:002018-01-01 03:40:002018-01-01 04:40:002018-01-01 05:40:002018-01-01 06:40:002018-01-01 07:40:002018-01-01 08:40:002018-01-01 09:40:00...2018-01-31 14:40:002018-01-31 15:40:002018-01-31 16:40:002018-01-31 17:40:002018-01-31 18:40:002018-01-31 19:40:002018-01-31 20:40:002018-01-31 21:40:002018-01-31 22:40:002018-01-31 23:40:00
0.02000.00.00.00.00.00.000.00.00.00.0...0.000.00.00.00.000.00.00.00.00.0
0.03250.00.00.00.00.00.000.00.00.00.0...0.000.00.00.00.000.00.00.00.00.0
0.03750.00.00.00.00.00.000.00.00.00.0...0.000.00.00.00.000.00.00.00.00.0
0.04250.00.00.00.00.00.000.00.00.00.0...0.000.00.00.00.000.00.00.00.00.0
0.04750.00.00.00.00.00.010.00.00.00.0...0.060.00.00.00.070.00.00.00.00.0
\n", + "

5 rows × 743 columns

\n", + "
" ], - "source": [ - "# Set water depth to 60 m\n", - "h = 60\n", - "\n", - "# Compute the energy flux from the NDBC spectra data and water depth\n", - "J = wave.resource.energy_flux(ndbc_data, h)\n", - "J.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Conversion from DataFrames to Series\n", - "MHKiT functions typically take in Pandas Series so that the function knows exactly which column to use. Pandas Series are one-dimensional ndarrays with axis labels which are most commonly encountered when a single column is requested from a DataFrame (e.g. `ndbc_data['2018-01-01 01:40:00']` returns a Pandas Series from the Pandas DataFrame of all frequencies at the specified time). \n", - "\n", - "To the above results (energy Period, energy flux, and significant wave height) were returned as DataFrames. For DataFrames which only have one column the conversion from DataFrame to Series can accomplished using the `squeeze` method. Alternatively we can call on the column header. Both methods are demonstrated below:" + "text/plain": [ + " 2018-01-01 00:40:00 2018-01-01 01:40:00 2018-01-01 02:40:00 \\\n", + "0.0200 0.0 0.0 0.0 \n", + "0.0325 0.0 0.0 0.0 \n", + "0.0375 0.0 0.0 0.0 \n", + "0.0425 0.0 0.0 0.0 \n", + "0.0475 0.0 0.0 0.0 \n", + "\n", + " 2018-01-01 03:40:00 2018-01-01 04:40:00 2018-01-01 05:40:00 \\\n", + "0.0200 0.0 0.0 0.00 \n", + "0.0325 0.0 0.0 0.00 \n", + "0.0375 0.0 0.0 0.00 \n", + "0.0425 0.0 0.0 0.00 \n", + "0.0475 0.0 0.0 0.01 \n", + "\n", + " 2018-01-01 06:40:00 2018-01-01 07:40:00 2018-01-01 08:40:00 \\\n", + "0.0200 0.0 0.0 0.0 \n", + "0.0325 0.0 0.0 0.0 \n", + "0.0375 0.0 0.0 0.0 \n", + "0.0425 0.0 0.0 0.0 \n", + "0.0475 0.0 0.0 0.0 \n", + "\n", + " 2018-01-01 09:40:00 ... 2018-01-31 14:40:00 2018-01-31 15:40:00 \\\n", + "0.0200 0.0 ... 0.00 0.0 \n", + "0.0325 0.0 ... 0.00 0.0 \n", + "0.0375 0.0 ... 0.00 0.0 \n", + "0.0425 0.0 ... 0.00 0.0 \n", + "0.0475 0.0 ... 0.06 0.0 \n", + "\n", + " 2018-01-31 16:40:00 2018-01-31 17:40:00 2018-01-31 18:40:00 \\\n", + "0.0200 0.0 0.0 0.00 \n", + "0.0325 0.0 0.0 0.00 \n", + "0.0375 0.0 0.0 0.00 \n", + "0.0425 0.0 0.0 0.00 \n", + "0.0475 0.0 0.0 0.07 \n", + "\n", + " 2018-01-31 19:40:00 2018-01-31 20:40:00 2018-01-31 21:40:00 \\\n", + "0.0200 0.0 0.0 0.0 \n", + "0.0325 0.0 0.0 0.0 \n", + "0.0375 0.0 0.0 0.0 \n", + "0.0425 0.0 0.0 0.0 \n", + "0.0475 0.0 0.0 0.0 \n", + "\n", + " 2018-01-31 22:40:00 2018-01-31 23:40:00 \n", + "0.0200 0.0 0.0 \n", + "0.0325 0.0 0.0 \n", + "0.0375 0.0 0.0 \n", + "0.0425 0.0 0.0 \n", + "0.0475 0.0 0.0 \n", + "\n", + "[5 rows x 743 columns]" ] - }, + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Transpose raw NDBC data\n", + "ndbc_data = raw_ndbc_data.T\n", + "ndbc_data.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Compute Wave Metrics \n", + "We will now use MHKiT to compute the significant wave height, energy period, and energy flux. " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "index\n", - "2018-01-01 00:40:00 7.458731\n", - "2018-01-01 01:40:00 7.682413\n", - "2018-01-01 02:40:00 7.498263\n", - "2018-01-01 03:40:00 7.676198\n", - "2018-01-01 04:40:00 7.669476\n", - "Name: Te, dtype: float64" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Te
index
2018-01-01 00:40:007.458731
2018-01-01 01:40:007.682413
2018-01-01 02:40:007.498263
2018-01-01 03:40:007.676198
2018-01-01 04:40:007.669476
\n", + "
" ], - "source": [ - "# Convert the energy period DataFrame to a Series.\n", - "Te = Te.squeeze()\n", - "Te.head()" + "text/plain": [ + " Te\n", + "index \n", + "2018-01-01 00:40:00 7.458731\n", + "2018-01-01 01:40:00 7.682413\n", + "2018-01-01 02:40:00 7.498263\n", + "2018-01-01 03:40:00 7.676198\n", + "2018-01-01 04:40:00 7.669476" ] - }, + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Compute the enegy periods from the NDBC spectra data\n", + "Te = wave.resource.energy_period(ndbc_data)\n", + "Te.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "index\n", - "2018-01-01 00:40:00 0.939574\n", - "2018-01-01 01:40:00 1.001399\n", - "2018-01-01 02:40:00 0.924770\n", - "2018-01-01 03:40:00 0.962497\n", - "2018-01-01 04:40:00 0.989949\n", - " ... \n", - "2018-01-31 19:40:00 2.650811\n", - "2018-01-31 20:40:00 3.086746\n", - "2018-01-31 21:40:00 2.650358\n", - "2018-01-31 22:40:00 2.941428\n", - "2018-01-31 23:40:00 2.895928\n", - "Name: Hm0, Length: 743, dtype: float64\n", - "index\n", - "2018-01-01 00:40:00 3354.825613\n", - "2018-01-01 01:40:00 3916.541523\n", - "2018-01-01 02:40:00 3278.298930\n", - "2018-01-01 03:40:00 3664.246679\n", - "2018-01-01 04:40:00 3867.014933\n", - " ... \n", - "2018-01-31 19:40:00 37596.750775\n", - "2018-01-31 20:40:00 52532.427635\n", - "2018-01-31 21:40:00 38153.227517\n", - "2018-01-31 22:40:00 50501.872907\n", - "2018-01-31 23:40:00 47070.874952\n", - "Name: J, Length: 743, dtype: float64\n" - ] - } + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Hm0
index
2018-01-01 00:40:000.939574
2018-01-01 01:40:001.001399
2018-01-01 02:40:000.924770
2018-01-01 03:40:000.962497
2018-01-01 04:40:000.989949
\n", + "
" ], - "source": [ - "# Alternatively, convert to Series by calling a specific column in the DataFrame\n", - "Hm0 = Hm0[\"Hm0\"]\n", - "print(Hm0)\n", - "\n", - "J = J[\"J\"]\n", - "print(J)" + "text/plain": [ + " Hm0\n", + "index \n", + "2018-01-01 00:40:00 0.939574\n", + "2018-01-01 01:40:00 1.001399\n", + "2018-01-01 02:40:00 0.924770\n", + "2018-01-01 03:40:00 0.962497\n", + "2018-01-01 04:40:00 0.989949" ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Generate Random Power Data\n", - "\n", - "For demonstration purposes, this example uses synthetic power data generated from statistical distributions. In a real application, the user would provide power values from a WEC. The data is stored in pandas Series, containing 743 points. " - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "# Set the random seed, to reproduce results\n", - "np.random.seed(1)\n", - "# Generate random power values\n", - "P = pd.Series(np.random.normal(200, 40, 743), index=J.index)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Capture Length Matrices\n", - "\n", - "The following operations create capture length matrices, as specified by the IEC/TS 62600-100. But first, we need to calculate capture length and define bin centers. The mean capture length matrix is printed below. Keep in mind that this data has been artificially generated, so it may not be representative of what a real-world scatter diagram would look like." - ] - }, + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Compute the significant wave height from the NDBC spectra data\n", + "Hm0 = wave.resource.significant_wave_height(ndbc_data)\n", + "Hm0.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
y_centers0.01.02.03.04.05.06.07.08.09.010.011.012.013.014.015.016.0
x_centers
0.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
0.5NaNNaNNaNNaNNaNNaNNaN0.1202860.053376NaNNaNNaNNaNNaNNaNNaNNaN
1.0NaNNaNNaNNaNNaNNaN0.1106860.0680700.0494520.065912NaN0.0565930.0299500.017234NaNNaNNaN
1.5NaNNaNNaNNaNNaNNaNNaN0.0197490.018673NaNNaN0.0124730.0112050.0123070.010432NaNNaN
2.0NaNNaNNaNNaNNaNNaNNaN0.0138820.0125470.0096720.0087700.0085850.0075250.0052720.007809NaNNaN
2.5NaNNaNNaNNaNNaNNaNNaNNaN0.0072440.0064880.0057880.0056520.0051800.0042600.0036230.004509NaN
3.0NaNNaNNaNNaNNaNNaNNaN0.0045000.0056600.0046910.0041090.0039520.0031040.0034080.0022910.001792NaN
3.5NaNNaNNaNNaNNaNNaNNaNNaN0.0039240.0036740.0030200.0027460.0022470.0020000.0022570.002033NaN
4.0NaNNaNNaNNaNNaNNaNNaNNaN0.0031850.0025130.0023860.0021470.0022460.0016050.001730NaNNaN
4.5NaNNaNNaNNaNNaNNaNNaNNaN0.0023430.0020870.0019190.0015900.001438NaNNaNNaNNaN
5.0NaNNaNNaNNaNNaNNaNNaNNaN0.0019130.0017200.0017160.0014110.0012190.001345NaNNaNNaN
5.5NaNNaNNaNNaNNaNNaNNaNNaN0.0021010.0015160.0013310.0009020.001033NaNNaNNaNNaN
6.0NaNNaNNaNNaNNaNNaNNaNNaNNaN0.0010970.000895NaN0.0008580.000987NaNNaNNaN
6.5NaNNaNNaNNaNNaNNaNNaNNaNNaN0.0008370.0010240.000419NaN0.000688NaNNaNNaN
7.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0.0004610.000633NaNNaNNaN
7.5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0.000553NaNNaN0.0003120.000437NaNNaN
8.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0.0004430.000351NaN
8.5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0.0004180.000405
9.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
9.5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0.000153NaN
10.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0.000281
10.5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0.0002040.000225
\n", - "
" - ], - "text/plain": [ - "y_centers 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 \\\n", - "x_centers \n", - "0.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "0.5 NaN NaN NaN NaN NaN NaN NaN 0.120286 0.053376 \n", - "1.0 NaN NaN NaN NaN NaN NaN 0.110686 0.068070 0.049452 \n", - "1.5 NaN NaN NaN NaN NaN NaN NaN 0.019749 0.018673 \n", - "2.0 NaN NaN NaN NaN NaN NaN NaN 0.013882 0.012547 \n", - "2.5 NaN NaN NaN NaN NaN NaN NaN NaN 0.007244 \n", - "3.0 NaN NaN NaN NaN NaN NaN NaN 0.004500 0.005660 \n", - "3.5 NaN NaN NaN NaN NaN NaN NaN NaN 0.003924 \n", - "4.0 NaN NaN NaN NaN NaN NaN NaN NaN 0.003185 \n", - "4.5 NaN NaN NaN NaN NaN NaN NaN NaN 0.002343 \n", - "5.0 NaN NaN NaN NaN NaN NaN NaN NaN 0.001913 \n", - "5.5 NaN NaN NaN NaN NaN NaN NaN NaN 0.002101 \n", - "6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "6.5 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "7.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "7.5 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "8.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "8.5 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "9.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "9.5 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "10.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "10.5 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "\n", - "y_centers 9.0 10.0 11.0 12.0 13.0 14.0 \\\n", - "x_centers \n", - "0.0 NaN NaN NaN NaN NaN NaN \n", - "0.5 NaN NaN NaN NaN NaN NaN \n", - "1.0 0.065912 NaN 0.056593 0.029950 0.017234 NaN \n", - "1.5 NaN NaN 0.012473 0.011205 0.012307 0.010432 \n", - "2.0 0.009672 0.008770 0.008585 0.007525 0.005272 0.007809 \n", - "2.5 0.006488 0.005788 0.005652 0.005180 0.004260 0.003623 \n", - "3.0 0.004691 0.004109 0.003952 0.003104 0.003408 0.002291 \n", - "3.5 0.003674 0.003020 0.002746 0.002247 0.002000 0.002257 \n", - "4.0 0.002513 0.002386 0.002147 0.002246 0.001605 0.001730 \n", - "4.5 0.002087 0.001919 0.001590 0.001438 NaN NaN \n", - "5.0 0.001720 0.001716 0.001411 0.001219 0.001345 NaN \n", - "5.5 0.001516 0.001331 0.000902 0.001033 NaN NaN \n", - "6.0 0.001097 0.000895 NaN 0.000858 0.000987 NaN \n", - "6.5 0.000837 0.001024 0.000419 NaN 0.000688 NaN \n", - "7.0 NaN NaN NaN 0.000461 0.000633 NaN \n", - "7.5 NaN 0.000553 NaN NaN 0.000312 0.000437 \n", - "8.0 NaN NaN NaN NaN NaN 0.000443 \n", - "8.5 NaN NaN NaN NaN NaN NaN \n", - "9.0 NaN NaN NaN NaN NaN NaN \n", - "9.5 NaN NaN NaN NaN NaN NaN \n", - "10.0 NaN NaN NaN NaN NaN NaN \n", - "10.5 NaN NaN NaN NaN NaN NaN \n", - "\n", - "y_centers 15.0 16.0 \n", - "x_centers \n", - "0.0 NaN NaN \n", - "0.5 NaN NaN \n", - "1.0 NaN NaN \n", - "1.5 NaN NaN \n", - "2.0 NaN NaN \n", - "2.5 0.004509 NaN \n", - "3.0 0.001792 NaN \n", - "3.5 0.002033 NaN \n", - "4.0 NaN NaN \n", - "4.5 NaN NaN \n", - "5.0 NaN NaN \n", - "5.5 NaN NaN \n", - "6.0 NaN NaN \n", - "6.5 NaN NaN \n", - "7.0 NaN NaN \n", - "7.5 NaN NaN \n", - "8.0 0.000351 NaN \n", - "8.5 0.000418 0.000405 \n", - "9.0 NaN NaN \n", - "9.5 0.000153 NaN \n", - "10.0 NaN 0.000281 \n", - "10.5 0.000204 0.000225 " - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
J
index
2018-01-01 00:40:003354.825613
2018-01-01 01:40:003916.541523
2018-01-01 02:40:003278.298930
2018-01-01 03:40:003664.246679
2018-01-01 04:40:003867.014933
\n", + "
" ], - "source": [ - "# Calculate capture length\n", - "L = wave.performance.capture_length(P, J)\n", - "\n", - "# Generate bins for Hm0 and Te, input format (start, stop, step_size)\n", - "Hm0_bins = np.arange(0, Hm0.values.max() + 0.5, 0.5)\n", - "Te_bins = np.arange(0, Te.values.max() + 1, 1)\n", - "\n", - "# Create capture length matrices using mean, standard deviation, count, min and max statistics\n", - "LM_mean = wave.performance.capture_length_matrix(Hm0, Te, L, \"mean\", Hm0_bins, Te_bins)\n", - "LM_std = wave.performance.capture_length_matrix(Hm0, Te, L, \"std\", Hm0_bins, Te_bins)\n", - "LM_count = wave.performance.capture_length_matrix(\n", - " Hm0, Te, L, \"count\", Hm0_bins, Te_bins\n", - ")\n", - "LM_min = wave.performance.capture_length_matrix(Hm0, Te, L, \"min\", Hm0_bins, Te_bins)\n", - "LM_max = wave.performance.capture_length_matrix(Hm0, Te, L, \"max\", Hm0_bins, Te_bins)\n", - "\n", - "# Show mean capture length matrix\n", - "LM_mean" + "text/plain": [ + " J\n", + "index \n", + "2018-01-01 00:40:00 3354.825613\n", + "2018-01-01 01:40:00 3916.541523\n", + "2018-01-01 02:40:00 3278.298930\n", + "2018-01-01 03:40:00 3664.246679\n", + "2018-01-01 04:40:00 3867.014933" ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Additional capture length matrices can be computed, for example, the frequency matrix is computed below." - ] - }, + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Set water depth to 60 m\n", + "h = 60\n", + "\n", + "# Compute the energy flux from the NDBC spectra data and water depth\n", + "J = wave.resource.energy_flux(ndbc_data, h)\n", + "J.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Note on data types\n", + "MHKiT functions typically allow Pandas Series, Pandas DataFrame, or xarray DataArray input. Multidimensional data (DataFrames and DataArrays) typically require an index or dimension name to specify the frequency or time dimension in question. If not supplied, the first dimension is assumed to be the relevant dimension.\n", + "\n", + "The above results (energy period, energy flux, and significant wave height) were returned as Pandas Series. 2D wave spectral data (frequency x time) was input and the frequency dimension was reduced leaving 1D, columnar data as the output. In Pandas, this is represented as a Series. If a DataArray with 3 or more dimensions was input, the output would be a DataArray with one fewer dimensions." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Generate Random Power Data\n", + "\n", + "For demonstration purposes, this example uses synthetic power data generated from statistical distributions. In a real application, the user would provide power values from a WEC. The data is stored in pandas Series, containing 743 points. " + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "# Set the random seed, to reproduce results\n", + "np.random.seed(1)\n", + "# Generate random power values\n", + "P = pd.Series(np.random.normal(200, 40, 743), index=J.index)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Capture Length Matrices\n", + "\n", + "The following operations create capture length matrices, as specified by the IEC/TS 62600-100. But first, we need to calculate capture length and define bin centers. The mean capture length matrix is printed below. Keep in mind that this data has been artificially generated, so it may not be representative of what a real-world scatter diagram would look like." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
y_centers0.01.02.03.04.05.06.07.08.09.010.011.012.013.014.015.016.0
x_centers
0.00.00.00.00.00.00.00.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.000000
0.50.00.00.00.00.00.00.0000000.0026920.0013460.0000000.0000000.0000000.0000000.0000000.0000000.0000000.000000
1.00.00.00.00.00.00.00.0013460.0067290.0040380.0013460.0000000.0026920.0026920.0013460.0000000.0000000.000000
1.50.00.00.00.00.00.00.0000000.0053840.0026920.0000000.0000000.0094210.0040380.0067290.0053840.0000000.000000
2.00.00.00.00.00.00.00.0000000.0026920.0053840.0188430.0188430.0296100.0215340.0013460.0026920.0000000.000000
2.50.00.00.00.00.00.00.0000000.0000000.0134590.0524900.0551820.0188430.0255720.0228800.0053840.0013460.000000
3.00.00.00.00.00.00.00.0000000.0013460.0215340.0444150.0471060.0201880.0121130.0107670.0107670.0013460.000000
3.50.00.00.00.00.00.00.0000000.0000000.0067290.0403770.0296100.0471060.0040380.0080750.0040380.0013460.000000
4.00.00.00.00.00.00.00.0000000.0000000.0094210.0174970.0296100.0403770.0026920.0040380.0053840.0000000.000000
4.50.00.00.00.00.00.00.0000000.0000000.0161510.0134590.0174970.0228800.0121130.0000000.0000000.0000000.000000
5.00.00.00.00.00.00.00.0000000.0000000.0026920.0080750.0080750.0107670.0228800.0013460.0000000.0000000.000000
5.50.00.00.00.00.00.00.0000000.0000000.0013460.0121130.0067290.0040380.0148050.0000000.0000000.0000000.000000
6.00.00.00.00.00.00.00.0000000.0000000.0000000.0026920.0026920.0000000.0053840.0013460.0000000.0000000.000000
6.50.00.00.00.00.00.00.0000000.0000000.0000000.0026920.0026920.0013460.0000000.0026920.0000000.0000000.000000
7.00.00.00.00.00.00.00.0000000.0000000.0000000.0000000.0000000.0000000.0013460.0040380.0000000.0000000.000000
7.50.00.00.00.00.00.00.0000000.0000000.0000000.0000000.0013460.0000000.0000000.0013460.0080750.0000000.000000
8.00.00.00.00.00.00.00.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0026920.0026920.000000
8.50.00.00.00.00.00.00.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0013460.001346
9.00.00.00.00.00.00.00.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.000000
9.50.00.00.00.00.00.00.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0013460.000000
10.00.00.00.00.00.00.00.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.001346
10.50.00.00.00.00.00.00.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0013460.001346
\n", - "
" - ], - "text/plain": [ - "y_centers 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 \\\n", - "x_centers \n", - "0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", - "0.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.002692 0.001346 \n", - "1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.001346 0.006729 0.004038 \n", - "1.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.005384 0.002692 \n", - "2.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.002692 0.005384 \n", - "2.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.013459 \n", - "3.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.001346 0.021534 \n", - "3.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.006729 \n", - "4.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.009421 \n", - "4.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.016151 \n", - "5.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.002692 \n", - "5.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.001346 \n", - "6.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", - "6.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", - "7.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", - "7.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", - "8.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", - "8.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", - "9.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", - "9.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", - "10.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", - "10.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", - "\n", - "y_centers 9.0 10.0 11.0 12.0 13.0 14.0 \\\n", - "x_centers \n", - "0.0 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 \n", - "0.5 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 \n", - "1.0 0.001346 0.000000 0.002692 0.002692 0.001346 0.000000 \n", - "1.5 0.000000 0.000000 0.009421 0.004038 0.006729 0.005384 \n", - "2.0 0.018843 0.018843 0.029610 0.021534 0.001346 0.002692 \n", - "2.5 0.052490 0.055182 0.018843 0.025572 0.022880 0.005384 \n", - "3.0 0.044415 0.047106 0.020188 0.012113 0.010767 0.010767 \n", - "3.5 0.040377 0.029610 0.047106 0.004038 0.008075 0.004038 \n", - "4.0 0.017497 0.029610 0.040377 0.002692 0.004038 0.005384 \n", - "4.5 0.013459 0.017497 0.022880 0.012113 0.000000 0.000000 \n", - "5.0 0.008075 0.008075 0.010767 0.022880 0.001346 0.000000 \n", - "5.5 0.012113 0.006729 0.004038 0.014805 0.000000 0.000000 \n", - "6.0 0.002692 0.002692 0.000000 0.005384 0.001346 0.000000 \n", - "6.5 0.002692 0.002692 0.001346 0.000000 0.002692 0.000000 \n", - "7.0 0.000000 0.000000 0.000000 0.001346 0.004038 0.000000 \n", - "7.5 0.000000 0.001346 0.000000 0.000000 0.001346 0.008075 \n", - "8.0 0.000000 0.000000 0.000000 0.000000 0.000000 0.002692 \n", - "8.5 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 \n", - "9.0 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 \n", - "9.5 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 \n", - "10.0 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 \n", - "10.5 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 \n", - "\n", - "y_centers 15.0 16.0 \n", - "x_centers \n", - "0.0 0.000000 0.000000 \n", - "0.5 0.000000 0.000000 \n", - "1.0 0.000000 0.000000 \n", - "1.5 0.000000 0.000000 \n", - "2.0 0.000000 0.000000 \n", - "2.5 0.001346 0.000000 \n", - "3.0 0.001346 0.000000 \n", - "3.5 0.001346 0.000000 \n", - "4.0 0.000000 0.000000 \n", - "4.5 0.000000 0.000000 \n", - "5.0 0.000000 0.000000 \n", - "5.5 0.000000 0.000000 \n", - "6.0 0.000000 0.000000 \n", - "6.5 0.000000 0.000000 \n", - "7.0 0.000000 0.000000 \n", - "7.5 0.000000 0.000000 \n", - "8.0 0.002692 0.000000 \n", - "8.5 0.001346 0.001346 \n", - "9.0 0.000000 0.000000 \n", - "9.5 0.001346 0.000000 \n", - "10.0 0.000000 0.001346 \n", - "10.5 0.001346 0.001346 " - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
y_centers0.01.02.03.04.05.06.07.08.09.010.011.012.013.014.015.016.0
x_centers
0.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
0.5NaNNaNNaNNaNNaNNaNNaN0.1202860.053376NaNNaNNaNNaNNaNNaNNaNNaN
1.0NaNNaNNaNNaNNaNNaN0.1106860.0680700.0494520.065912NaN0.0565930.0299500.017234NaNNaNNaN
1.5NaNNaNNaNNaNNaNNaNNaN0.0197490.018673NaNNaN0.0124730.0112050.0123070.010432NaNNaN
2.0NaNNaNNaNNaNNaNNaNNaN0.0138820.0125470.0096720.0087700.0085850.0075250.0052720.007809NaNNaN
2.5NaNNaNNaNNaNNaNNaNNaNNaN0.0072440.0064880.0057880.0056520.0051800.0042600.0036230.004509NaN
3.0NaNNaNNaNNaNNaNNaNNaN0.0045000.0056600.0046910.0041090.0039520.0031040.0034080.0022910.001792NaN
3.5NaNNaNNaNNaNNaNNaNNaNNaN0.0039240.0036740.0030200.0027460.0022470.0020000.0022570.002033NaN
4.0NaNNaNNaNNaNNaNNaNNaNNaN0.0031850.0025130.0023860.0021470.0022460.0016050.001730NaNNaN
4.5NaNNaNNaNNaNNaNNaNNaNNaN0.0023430.0020870.0019190.0015900.001438NaNNaNNaNNaN
5.0NaNNaNNaNNaNNaNNaNNaNNaN0.0019130.0017200.0017160.0014110.0012190.001345NaNNaNNaN
5.5NaNNaNNaNNaNNaNNaNNaNNaN0.0021010.0015160.0013310.0009020.001033NaNNaNNaNNaN
6.0NaNNaNNaNNaNNaNNaNNaNNaNNaN0.0010970.000895NaN0.0008580.000987NaNNaNNaN
6.5NaNNaNNaNNaNNaNNaNNaNNaNNaN0.0008370.0010240.000419NaN0.000688NaNNaNNaN
7.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0.0004610.000633NaNNaNNaN
7.5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0.000553NaNNaN0.0003120.000437NaNNaN
8.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0.0004430.000351NaN
8.5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0.0004180.000405
9.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
9.5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0.000153NaN
10.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0.000281
10.5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0.0002040.000225
\n", + "
" ], - "source": [ - "# Create capture length matrices using frequency\n", - "LM_freq = wave.performance.capture_length_matrix(\n", - " Hm0, Te, L, \"frequency\", Hm0_bins, Te_bins\n", - ")\n", - "\n", - "# Show capture length matrix using frequency\n", - "LM_freq" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `capture_length_matrix` function can also be used as an arbitrary matrix generator. To do this, simply pass a different Series in the place of capture length (L). For example, while not specified by the IEC standards, if the user doesn't have the omnidirectional wave flux, the average power matrix could hypothetically be generated in the following manner." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "# Demonstration of arbitrary matrix generator\n", - "PM_mean_not_standard = wave.performance.capture_length_matrix(\n", - " Hm0, Te, P, \"mean\", Hm0_bins, Te_bins\n", - ")" + "text/plain": [ + "y_centers 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 \\\n", + "x_centers \n", + "0.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "0.5 NaN NaN NaN NaN NaN NaN NaN 0.120286 0.053376 \n", + "1.0 NaN NaN NaN NaN NaN NaN 0.110686 0.068070 0.049452 \n", + "1.5 NaN NaN NaN NaN NaN NaN NaN 0.019749 0.018673 \n", + "2.0 NaN NaN NaN NaN NaN NaN NaN 0.013882 0.012547 \n", + "2.5 NaN NaN NaN NaN NaN NaN NaN NaN 0.007244 \n", + "3.0 NaN NaN NaN NaN NaN NaN NaN 0.004500 0.005660 \n", + "3.5 NaN NaN NaN NaN NaN NaN NaN NaN 0.003924 \n", + "4.0 NaN NaN NaN NaN NaN NaN NaN NaN 0.003185 \n", + "4.5 NaN NaN NaN NaN NaN NaN NaN NaN 0.002343 \n", + "5.0 NaN NaN NaN NaN NaN NaN NaN NaN 0.001913 \n", + "5.5 NaN NaN NaN NaN NaN NaN NaN NaN 0.002101 \n", + "6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "6.5 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "7.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "7.5 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "8.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "8.5 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "9.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "9.5 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "10.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "10.5 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "\n", + "y_centers 9.0 10.0 11.0 12.0 13.0 14.0 \\\n", + "x_centers \n", + "0.0 NaN NaN NaN NaN NaN NaN \n", + "0.5 NaN NaN NaN NaN NaN NaN \n", + "1.0 0.065912 NaN 0.056593 0.029950 0.017234 NaN \n", + "1.5 NaN NaN 0.012473 0.011205 0.012307 0.010432 \n", + "2.0 0.009672 0.008770 0.008585 0.007525 0.005272 0.007809 \n", + "2.5 0.006488 0.005788 0.005652 0.005180 0.004260 0.003623 \n", + "3.0 0.004691 0.004109 0.003952 0.003104 0.003408 0.002291 \n", + "3.5 0.003674 0.003020 0.002746 0.002247 0.002000 0.002257 \n", + "4.0 0.002513 0.002386 0.002147 0.002246 0.001605 0.001730 \n", + "4.5 0.002087 0.001919 0.001590 0.001438 NaN NaN \n", + "5.0 0.001720 0.001716 0.001411 0.001219 0.001345 NaN \n", + "5.5 0.001516 0.001331 0.000902 0.001033 NaN NaN \n", + "6.0 0.001097 0.000895 NaN 0.000858 0.000987 NaN \n", + "6.5 0.000837 0.001024 0.000419 NaN 0.000688 NaN \n", + "7.0 NaN NaN NaN 0.000461 0.000633 NaN \n", + "7.5 NaN 0.000553 NaN NaN 0.000312 0.000437 \n", + "8.0 NaN NaN NaN NaN NaN 0.000443 \n", + "8.5 NaN NaN NaN NaN NaN NaN \n", + "9.0 NaN NaN NaN NaN NaN NaN \n", + "9.5 NaN NaN NaN NaN NaN NaN \n", + "10.0 NaN NaN NaN NaN NaN NaN \n", + "10.5 NaN NaN NaN NaN NaN NaN \n", + "\n", + "y_centers 15.0 16.0 \n", + "x_centers \n", + "0.0 NaN NaN \n", + "0.5 NaN NaN \n", + "1.0 NaN NaN \n", + "1.5 NaN NaN \n", + "2.0 NaN NaN \n", + "2.5 0.004509 NaN \n", + "3.0 0.001792 NaN \n", + "3.5 0.002033 NaN \n", + "4.0 NaN NaN \n", + "4.5 NaN NaN \n", + "5.0 NaN NaN \n", + "5.5 NaN NaN \n", + "6.0 NaN NaN \n", + "6.5 NaN NaN \n", + "7.0 NaN NaN \n", + "7.5 NaN NaN \n", + "8.0 0.000351 NaN \n", + "8.5 0.000418 0.000405 \n", + "9.0 NaN NaN \n", + "9.5 0.000153 NaN \n", + "10.0 NaN 0.000281 \n", + "10.5 0.000204 0.000225 " ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `capture_length_matrix` function can also use a callable function as the statistic argument. For example, suppose that we wanted to generate a matrix with the variance of the capture length. We could achieve this by passing the NumPy variance function `np.var` into the `capture_length_matrix` function, as shown below." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "# Demonstration of passing a callable function to the matrix generator\n", - "LM_variance = wave.performance.capture_length_matrix(\n", - " Hm0, Te, L, np.var, Hm0_bins, Te_bins\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Power Matrices\n", - "As specified in IEC/TS 62600-100, the power matrix is generated from the capture length matrix and wave energy flux matrix, as shown below" - ] - }, + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Calculate capture length\n", + "L = wave.performance.capture_length(P, J)\n", + "\n", + "# Generate bins for Hm0 and Te, input format (start, stop, step_size)\n", + "Hm0_bins = np.arange(0, Hm0.values.max() + 0.5, 0.5)\n", + "Te_bins = np.arange(0, Te.values.max() + 1, 1)\n", + "\n", + "# Create capture length matrices using mean, standard deviation, count, min and max statistics\n", + "LM_mean = wave.performance.capture_length_matrix(Hm0, Te, L, \"mean\", Hm0_bins, Te_bins)\n", + "LM_std = wave.performance.capture_length_matrix(Hm0, Te, L, \"std\", Hm0_bins, Te_bins)\n", + "LM_count = wave.performance.capture_length_matrix(\n", + " Hm0, Te, L, \"count\", Hm0_bins, Te_bins\n", + ")\n", + "LM_min = wave.performance.capture_length_matrix(Hm0, Te, L, \"min\", Hm0_bins, Te_bins)\n", + "LM_max = wave.performance.capture_length_matrix(Hm0, Te, L, \"max\", Hm0_bins, Te_bins)\n", + "\n", + "# Show mean capture length matrix\n", + "LM_mean" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Additional capture length matrices can be computed, for example, the frequency matrix is computed below." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
y_centers0.01.02.03.04.05.06.07.08.09.010.011.012.013.014.015.016.0
x_centers
0.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
0.5NaNNaNNaNNaNNaNNaNNaN224.996117.594NaNNaNNaNNaNNaNNaNNaNNaN
1.0NaNNaNNaNNaNNaNNaN212.762202.713188.707187.103NaN213.926174.154164.886NaNNaNNaN
1.5NaNNaNNaNNaNNaNNaNNaN176.402199.802NaNNaN201.883191.598221.705190.124NaNNaN
2.0NaNNaNNaNNaNNaNNaNNaN203.667216.857192.965201.633216.268209.634162.569232.530NaNNaN
2.5NaNNaNNaNNaNNaNNaNNaNNaN193.397203.529196.907212.883211.277202.760199.263272.421NaN
3.0NaNNaNNaNNaNNaNNaNNaN170.739216.459197.484200.895212.107193.837222.185169.497122.296NaN
3.5NaNNaNNaNNaNNaNNaNNaNNaN194.894214.108202.725206.901184.099186.077221.659186.201NaN
4.0NaNNaNNaNNaNNaNNaNNaNNaN217.289189.403201.362207.532207.971172.771213.854NaNNaN
4.5NaNNaNNaNNaNNaNNaNNaNNaN197.994194.238205.559203.195197.980NaNNaNNaNNaN
5.0NaNNaNNaNNaNNaNNaNNaNNaN198.149196.527222.219215.221204.002254.004NaNNaNNaN
5.5NaNNaNNaNNaNNaNNaNNaNNaN249.158212.561212.734168.655208.220NaNNaNNaNNaN
6.0NaNNaNNaNNaNNaNNaNNaNNaNNaN182.314159.418NaN208.418241.347NaNNaNNaN
6.5NaNNaNNaNNaNNaNNaNNaNNaNNaN164.712233.890110.517NaN207.919NaNNaNNaN
7.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN155.691229.022NaNNaNNaN
7.5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN166.855NaNNaN128.897198.053NaNNaN
8.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN230.281184.510NaN
8.5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN248.338264.534
9.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
9.5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN116.230NaN
10.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN244.634
10.5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN190.849212.411
\n", - "
" - ], - "text/plain": [ - "y_centers 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 \\\n", - "x_centers \n", - "0.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "0.5 NaN NaN NaN NaN NaN NaN NaN 224.996 117.594 \n", - "1.0 NaN NaN NaN NaN NaN NaN 212.762 202.713 188.707 \n", - "1.5 NaN NaN NaN NaN NaN NaN NaN 176.402 199.802 \n", - "2.0 NaN NaN NaN NaN NaN NaN NaN 203.667 216.857 \n", - "2.5 NaN NaN NaN NaN NaN NaN NaN NaN 193.397 \n", - "3.0 NaN NaN NaN NaN NaN NaN NaN 170.739 216.459 \n", - "3.5 NaN NaN NaN NaN NaN NaN NaN NaN 194.894 \n", - "4.0 NaN NaN NaN NaN NaN NaN NaN NaN 217.289 \n", - "4.5 NaN NaN NaN NaN NaN NaN NaN NaN 197.994 \n", - "5.0 NaN NaN NaN NaN NaN NaN NaN NaN 198.149 \n", - "5.5 NaN NaN NaN NaN NaN NaN NaN NaN 249.158 \n", - "6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "6.5 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "7.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "7.5 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "8.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "8.5 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "9.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "9.5 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "10.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "10.5 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", - "\n", - "y_centers 9.0 10.0 11.0 12.0 13.0 14.0 15.0 \\\n", - "x_centers \n", - "0.0 NaN NaN NaN NaN NaN NaN NaN \n", - "0.5 NaN NaN NaN NaN NaN NaN NaN \n", - "1.0 187.103 NaN 213.926 174.154 164.886 NaN NaN \n", - "1.5 NaN NaN 201.883 191.598 221.705 190.124 NaN \n", - "2.0 192.965 201.633 216.268 209.634 162.569 232.530 NaN \n", - "2.5 203.529 196.907 212.883 211.277 202.760 199.263 272.421 \n", - "3.0 197.484 200.895 212.107 193.837 222.185 169.497 122.296 \n", - "3.5 214.108 202.725 206.901 184.099 186.077 221.659 186.201 \n", - "4.0 189.403 201.362 207.532 207.971 172.771 213.854 NaN \n", - "4.5 194.238 205.559 203.195 197.980 NaN NaN NaN \n", - "5.0 196.527 222.219 215.221 204.002 254.004 NaN NaN \n", - "5.5 212.561 212.734 168.655 208.220 NaN NaN NaN \n", - "6.0 182.314 159.418 NaN 208.418 241.347 NaN NaN \n", - "6.5 164.712 233.890 110.517 NaN 207.919 NaN NaN \n", - "7.0 NaN NaN NaN 155.691 229.022 NaN NaN \n", - "7.5 NaN 166.855 NaN NaN 128.897 198.053 NaN \n", - "8.0 NaN NaN NaN NaN NaN 230.281 184.510 \n", - "8.5 NaN NaN NaN NaN NaN NaN 248.338 \n", - "9.0 NaN NaN NaN NaN NaN NaN NaN \n", - "9.5 NaN NaN NaN NaN NaN NaN 116.230 \n", - "10.0 NaN NaN NaN NaN NaN NaN NaN \n", - "10.5 NaN NaN NaN NaN NaN NaN 190.849 \n", - "\n", - "y_centers 16.0 \n", - "x_centers \n", - "0.0 NaN \n", - "0.5 NaN \n", - "1.0 NaN \n", - "1.5 NaN \n", - "2.0 NaN \n", - "2.5 NaN \n", - "3.0 NaN \n", - "3.5 NaN \n", - "4.0 NaN \n", - "4.5 NaN \n", - "5.0 NaN \n", - "5.5 NaN \n", - "6.0 NaN \n", - "6.5 NaN \n", - "7.0 NaN \n", - "7.5 NaN \n", - "8.0 NaN \n", - "8.5 264.534 \n", - "9.0 NaN \n", - "9.5 NaN \n", - "10.0 244.634 \n", - "10.5 212.411 " - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
y_centers0.01.02.03.04.05.06.07.08.09.010.011.012.013.014.015.016.0
x_centers
0.00.00.00.00.00.00.00.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.000000
0.50.00.00.00.00.00.00.0000000.0026920.0013460.0000000.0000000.0000000.0000000.0000000.0000000.0000000.000000
1.00.00.00.00.00.00.00.0013460.0067290.0040380.0013460.0000000.0026920.0026920.0013460.0000000.0000000.000000
1.50.00.00.00.00.00.00.0000000.0053840.0026920.0000000.0000000.0094210.0040380.0067290.0053840.0000000.000000
2.00.00.00.00.00.00.00.0000000.0026920.0053840.0188430.0188430.0296100.0215340.0013460.0026920.0000000.000000
2.50.00.00.00.00.00.00.0000000.0000000.0134590.0524900.0551820.0188430.0255720.0228800.0053840.0013460.000000
3.00.00.00.00.00.00.00.0000000.0013460.0215340.0444150.0471060.0201880.0121130.0107670.0107670.0013460.000000
3.50.00.00.00.00.00.00.0000000.0000000.0067290.0403770.0296100.0471060.0040380.0080750.0040380.0013460.000000
4.00.00.00.00.00.00.00.0000000.0000000.0094210.0174970.0296100.0403770.0026920.0040380.0053840.0000000.000000
4.50.00.00.00.00.00.00.0000000.0000000.0161510.0134590.0174970.0228800.0121130.0000000.0000000.0000000.000000
5.00.00.00.00.00.00.00.0000000.0000000.0026920.0080750.0080750.0107670.0228800.0013460.0000000.0000000.000000
5.50.00.00.00.00.00.00.0000000.0000000.0013460.0121130.0067290.0040380.0148050.0000000.0000000.0000000.000000
6.00.00.00.00.00.00.00.0000000.0000000.0000000.0026920.0026920.0000000.0053840.0013460.0000000.0000000.000000
6.50.00.00.00.00.00.00.0000000.0000000.0000000.0026920.0026920.0013460.0000000.0026920.0000000.0000000.000000
7.00.00.00.00.00.00.00.0000000.0000000.0000000.0000000.0000000.0000000.0013460.0040380.0000000.0000000.000000
7.50.00.00.00.00.00.00.0000000.0000000.0000000.0000000.0013460.0000000.0000000.0013460.0080750.0000000.000000
8.00.00.00.00.00.00.00.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0026920.0026920.000000
8.50.00.00.00.00.00.00.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0013460.001346
9.00.00.00.00.00.00.00.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.000000
9.50.00.00.00.00.00.00.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0013460.000000
10.00.00.00.00.00.00.00.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.001346
10.50.00.00.00.00.00.00.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0013460.001346
\n", + "
" ], - "source": [ - "# Create wave energy flux matrix using mean\n", - "JM = wave.performance.wave_energy_flux_matrix(Hm0, Te, J, \"mean\", Hm0_bins, Te_bins)\n", - "\n", - "# Create power matrix using mean\n", - "PM_mean = wave.performance.power_matrix(LM_mean, JM)\n", - "\n", - "# Create power matrix using standard deviation\n", - "PM_std = wave.performance.power_matrix(LM_std, JM)\n", - "\n", - "# Show mean power matrix, round to 3 decimals\n", - "PM_mean.round(3)" + "text/plain": [ + "y_centers 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 \\\n", + "x_centers \n", + "0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", + "0.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.002692 0.001346 \n", + "1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.001346 0.006729 0.004038 \n", + "1.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.005384 0.002692 \n", + "2.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.002692 0.005384 \n", + "2.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.013459 \n", + "3.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.001346 0.021534 \n", + "3.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.006729 \n", + "4.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.009421 \n", + "4.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.016151 \n", + "5.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.002692 \n", + "5.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.001346 \n", + "6.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", + "6.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", + "7.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", + "7.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", + "8.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", + "8.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", + "9.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", + "9.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", + "10.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", + "10.5 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 \n", + "\n", + "y_centers 9.0 10.0 11.0 12.0 13.0 14.0 \\\n", + "x_centers \n", + "0.0 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 \n", + "0.5 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 \n", + "1.0 0.001346 0.000000 0.002692 0.002692 0.001346 0.000000 \n", + "1.5 0.000000 0.000000 0.009421 0.004038 0.006729 0.005384 \n", + "2.0 0.018843 0.018843 0.029610 0.021534 0.001346 0.002692 \n", + "2.5 0.052490 0.055182 0.018843 0.025572 0.022880 0.005384 \n", + "3.0 0.044415 0.047106 0.020188 0.012113 0.010767 0.010767 \n", + "3.5 0.040377 0.029610 0.047106 0.004038 0.008075 0.004038 \n", + "4.0 0.017497 0.029610 0.040377 0.002692 0.004038 0.005384 \n", + "4.5 0.013459 0.017497 0.022880 0.012113 0.000000 0.000000 \n", + "5.0 0.008075 0.008075 0.010767 0.022880 0.001346 0.000000 \n", + "5.5 0.012113 0.006729 0.004038 0.014805 0.000000 0.000000 \n", + "6.0 0.002692 0.002692 0.000000 0.005384 0.001346 0.000000 \n", + "6.5 0.002692 0.002692 0.001346 0.000000 0.002692 0.000000 \n", + "7.0 0.000000 0.000000 0.000000 0.001346 0.004038 0.000000 \n", + "7.5 0.000000 0.001346 0.000000 0.000000 0.001346 0.008075 \n", + "8.0 0.000000 0.000000 0.000000 0.000000 0.000000 0.002692 \n", + "8.5 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 \n", + "9.0 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 \n", + "9.5 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 \n", + "10.0 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 \n", + "10.5 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 \n", + "\n", + "y_centers 15.0 16.0 \n", + "x_centers \n", + "0.0 0.000000 0.000000 \n", + "0.5 0.000000 0.000000 \n", + "1.0 0.000000 0.000000 \n", + "1.5 0.000000 0.000000 \n", + "2.0 0.000000 0.000000 \n", + "2.5 0.001346 0.000000 \n", + "3.0 0.001346 0.000000 \n", + "3.5 0.001346 0.000000 \n", + "4.0 0.000000 0.000000 \n", + "4.5 0.000000 0.000000 \n", + "5.0 0.000000 0.000000 \n", + "5.5 0.000000 0.000000 \n", + "6.0 0.000000 0.000000 \n", + "6.5 0.000000 0.000000 \n", + "7.0 0.000000 0.000000 \n", + "7.5 0.000000 0.000000 \n", + "8.0 0.002692 0.000000 \n", + "8.5 0.001346 0.001346 \n", + "9.0 0.000000 0.000000 \n", + "9.5 0.001346 0.000000 \n", + "10.0 0.000000 0.001346 \n", + "10.5 0.001346 0.001346 " ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Calculate MAEP\n", - "There are two ways to calculate the mean annual energy production (MEAP). One is from capture length and wave energy flux matrices, the other is from time-series data, as shown below." - ] - }, + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Create capture length matrices using frequency\n", + "LM_freq = wave.performance.capture_length_matrix(\n", + " Hm0, Te, L, \"frequency\", Hm0_bins, Te_bins\n", + ")\n", + "\n", + "# Show capture length matrix using frequency\n", + "LM_freq" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `capture_length_matrix` function can also be used as an arbitrary matrix generator. To do this, simply pass a different Series in the place of capture length (L). For example, while not specified by the IEC standards, if the user doesn't have the omnidirectional wave flux, the average power matrix could hypothetically be generated in the following manner." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "# Demonstration of arbitrary matrix generator\n", + "PM_mean_not_standard = wave.performance.capture_length_matrix(\n", + " Hm0, Te, P, \"mean\", Hm0_bins, Te_bins\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `capture_length_matrix` function can also use a callable function as the statistic argument. For example, suppose that we wanted to generate a matrix with the variance of the capture length. We could achieve this by passing the NumPy variance function `np.var` into the `capture_length_matrix` function, as shown below." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# Demonstration of passing a callable function to the matrix generator\n", + "LM_variance = wave.performance.capture_length_matrix(\n", + " Hm0, Te, L, np.var, Hm0_bins, Te_bins\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Power Matrices\n", + "As specified in IEC/TS 62600-100, the power matrix is generated from the capture length matrix and wave energy flux matrix, as shown below" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "MAEP from timeseries = 1767087.5275863332\n", - "MAEP from matrices = 1781210.865283919\n" - ] - } + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
y_centers0.01.02.03.04.05.06.07.08.09.010.011.012.013.014.015.016.0
x_centers
0.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
0.5NaNNaNNaNNaNNaNNaNNaN224.996117.594NaNNaNNaNNaNNaNNaNNaNNaN
1.0NaNNaNNaNNaNNaNNaN212.762202.713188.707187.103NaN213.926174.154164.886NaNNaNNaN
1.5NaNNaNNaNNaNNaNNaNNaN176.402199.802NaNNaN201.883191.598221.705190.124NaNNaN
2.0NaNNaNNaNNaNNaNNaNNaN203.667216.857192.965201.633216.268209.634162.569232.530NaNNaN
2.5NaNNaNNaNNaNNaNNaNNaNNaN193.397203.529196.907212.883211.277202.760199.263272.421NaN
3.0NaNNaNNaNNaNNaNNaNNaN170.739216.459197.484200.895212.107193.837222.185169.497122.296NaN
3.5NaNNaNNaNNaNNaNNaNNaNNaN194.894214.108202.725206.901184.099186.077221.659186.201NaN
4.0NaNNaNNaNNaNNaNNaNNaNNaN217.289189.403201.362207.532207.971172.771213.854NaNNaN
4.5NaNNaNNaNNaNNaNNaNNaNNaN197.994194.238205.559203.195197.980NaNNaNNaNNaN
5.0NaNNaNNaNNaNNaNNaNNaNNaN198.149196.527222.219215.221204.002254.004NaNNaNNaN
5.5NaNNaNNaNNaNNaNNaNNaNNaN249.158212.561212.734168.655208.220NaNNaNNaNNaN
6.0NaNNaNNaNNaNNaNNaNNaNNaNNaN182.314159.418NaN208.418241.347NaNNaNNaN
6.5NaNNaNNaNNaNNaNNaNNaNNaNNaN164.712233.890110.517NaN207.919NaNNaNNaN
7.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN155.691229.022NaNNaNNaN
7.5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN166.855NaNNaN128.897198.053NaNNaN
8.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN230.281184.510NaN
8.5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN248.338264.534
9.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
9.5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN116.230NaN
10.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN244.634
10.5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN190.849212.411
\n", + "
" ], - "source": [ - "# Calcaulte maep from timeseries\n", - "maep_timeseries = wave.performance.mean_annual_energy_production_timeseries(L, J)\n", - "print(\"MAEP from timeseries = \", maep_timeseries)\n", - "\n", - "# Calcaulte maep from matrix \n", - "# See Issue #339\n", - "# maep_matrix = wave.performance.mean_annual_energy_production_matrix(\n", - "# LM_mean, JM, LM_freq\n", - "# )\n", - "\n", - "T = 8766 # Average length of a year (h)\n", - "maep_matrix = T * np.nansum(LM_mean * JM * LM_freq)\n", - "\n", - "print(\"MAEP from matrices = \", maep_matrix)" + "text/plain": [ + "y_centers 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 \\\n", + "x_centers \n", + "0.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "0.5 NaN NaN NaN NaN NaN NaN NaN 224.996 117.594 \n", + "1.0 NaN NaN NaN NaN NaN NaN 212.762 202.713 188.707 \n", + "1.5 NaN NaN NaN NaN NaN NaN NaN 176.402 199.802 \n", + "2.0 NaN NaN NaN NaN NaN NaN NaN 203.667 216.857 \n", + "2.5 NaN NaN NaN NaN NaN NaN NaN NaN 193.397 \n", + "3.0 NaN NaN NaN NaN NaN NaN NaN 170.739 216.459 \n", + "3.5 NaN NaN NaN NaN NaN NaN NaN NaN 194.894 \n", + "4.0 NaN NaN NaN NaN NaN NaN NaN NaN 217.289 \n", + "4.5 NaN NaN NaN NaN NaN NaN NaN NaN 197.994 \n", + "5.0 NaN NaN NaN NaN NaN NaN NaN NaN 198.149 \n", + "5.5 NaN NaN NaN NaN NaN NaN NaN NaN 249.158 \n", + "6.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "6.5 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "7.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "7.5 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "8.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "8.5 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "9.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "9.5 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "10.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "10.5 NaN NaN NaN NaN NaN NaN NaN NaN NaN \n", + "\n", + "y_centers 9.0 10.0 11.0 12.0 13.0 14.0 15.0 \\\n", + "x_centers \n", + "0.0 NaN NaN NaN NaN NaN NaN NaN \n", + "0.5 NaN NaN NaN NaN NaN NaN NaN \n", + "1.0 187.103 NaN 213.926 174.154 164.886 NaN NaN \n", + "1.5 NaN NaN 201.883 191.598 221.705 190.124 NaN \n", + "2.0 192.965 201.633 216.268 209.634 162.569 232.530 NaN \n", + "2.5 203.529 196.907 212.883 211.277 202.760 199.263 272.421 \n", + "3.0 197.484 200.895 212.107 193.837 222.185 169.497 122.296 \n", + "3.5 214.108 202.725 206.901 184.099 186.077 221.659 186.201 \n", + "4.0 189.403 201.362 207.532 207.971 172.771 213.854 NaN \n", + "4.5 194.238 205.559 203.195 197.980 NaN NaN NaN \n", + "5.0 196.527 222.219 215.221 204.002 254.004 NaN NaN \n", + "5.5 212.561 212.734 168.655 208.220 NaN NaN NaN \n", + "6.0 182.314 159.418 NaN 208.418 241.347 NaN NaN \n", + "6.5 164.712 233.890 110.517 NaN 207.919 NaN NaN \n", + "7.0 NaN NaN NaN 155.691 229.022 NaN NaN \n", + "7.5 NaN 166.855 NaN NaN 128.897 198.053 NaN \n", + "8.0 NaN NaN NaN NaN NaN 230.281 184.510 \n", + "8.5 NaN NaN NaN NaN NaN NaN 248.338 \n", + "9.0 NaN NaN NaN NaN NaN NaN NaN \n", + "9.5 NaN NaN NaN NaN NaN NaN 116.230 \n", + "10.0 NaN NaN NaN NaN NaN NaN NaN \n", + "10.5 NaN NaN NaN NaN NaN NaN 190.849 \n", + "\n", + "y_centers 16.0 \n", + "x_centers \n", + "0.0 NaN \n", + "0.5 NaN \n", + "1.0 NaN \n", + "1.5 NaN \n", + "2.0 NaN \n", + "2.5 NaN \n", + "3.0 NaN \n", + "3.5 NaN \n", + "4.0 NaN \n", + "4.5 NaN \n", + "5.0 NaN \n", + "5.5 NaN \n", + "6.0 NaN \n", + "6.5 NaN \n", + "7.0 NaN \n", + "7.5 NaN \n", + "8.0 NaN \n", + "8.5 264.534 \n", + "9.0 NaN \n", + "9.5 NaN \n", + "10.0 244.634 \n", + "10.5 212.411 " ] - }, + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Create wave energy flux matrix using mean\n", + "JM = wave.performance.wave_energy_flux_matrix(Hm0, Te, J, \"mean\", Hm0_bins, Te_bins)\n", + "\n", + "# Create power matrix using mean\n", + "PM_mean = wave.performance.power_matrix(LM_mean, JM)\n", + "\n", + "# Create power matrix using standard deviation\n", + "PM_std = wave.performance.power_matrix(LM_std, JM)\n", + "\n", + "# Show mean power matrix, round to 3 decimals\n", + "PM_mean.round(3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Calculate MAEP\n", + "There are two ways to calculate the mean annual energy production (MEAP). One is from capture length and wave energy flux matrices, the other is from time-series data, as shown below." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Graphics\n", - "The graphics function `plot_matrix` can be used to visualize results. It is important to note that the plotting function assumes the step size between bins to be linear." - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "MAEP from timeseries = 1767087.5275863332\n", + "MAEP from matrices = 1781210.865283919\n" + ] + } + ], + "source": [ + "# Calcaulte maep from timeseries\n", + "maep_timeseries = wave.performance.mean_annual_energy_production_timeseries(L, J)\n", + "print(\"MAEP from timeseries = \", maep_timeseries)\n", + "\n", + "# Calcaulte maep from matrix \n", + "# See Issue #339\n", + "# maep_matrix = wave.performance.mean_annual_energy_production_matrix(\n", + "# LM_mean, JM, LM_freq\n", + "# )\n", + "\n", + "T = 8766 # Average length of a year (h)\n", + "maep_matrix = T * np.nansum(LM_mean * JM * LM_freq)\n", + "\n", + "print(\"MAEP from matrices = \", maep_matrix)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Graphics\n", + "The graphics function `plot_matrix` can be used to visualize results. It is important to note that the plotting function assumes the step size between bins to be linear." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Plot the capture length mean matrix\n", - "ax = wave.graphics.plot_matrix(LM_mean)" + "data": { + "image/png": "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", + "text/plain": [ + "
" ] - }, + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Plot the capture length mean matrix\n", + "ax = wave.graphics.plot_matrix(LM_mean)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The plotting function only requires the matrix as input, but the function can also take several other arguments.\n", + "The list of optional arguments is: `xlabel, ylabel, zlabel, show_values, and ax`. The following uses these optional arguments. The matplotlib package is imported to define an axis with a larger figure size." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "scrolled": true + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The plotting function only requires the matrix as input, but the function can also take several other arguments.\n", - "The list of optional arguments is: `xlabel, ylabel, zlabel, show_values, and ax`. The following uses these optional arguments. The matplotlib package is imported to define an axis with a larger figure size." + "data": { + "text/plain": [ + "" ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" }, { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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wt27d5GSkqK9vn//fmg0Gnh7e1fy0zEOya4GIiIiqgnE2MRN33ghISHYvHkzfvjhB1hbW2vnmCgUClhZWUEmk2HSpEmYOXMmPD090aFDB3z11Vf4448/8P333wN4PMrSv39/jBkzBlFRUXj48CFCQ0Px9ttvV+tKIIDJChERUY23cuVKAI+nVzxtw4YNeO+99wAAYWFhyM/Px8SJE3H79m14enoiLi4OLVq00NbftGkTQkND0bdvX5iYmGDw4MH44osvquo2yiQTyps08oJSq9VQKBTIycnR61khEdGLwl8xUpS4e3KM+x43MX+eF8f++XdX1LU27qyKvHsaBLS/wt9D/+CcFSIiIpI0PgYiIiIygAYyaIz8t78GfOjxNI6sEBERkaRxZIWIiMgAUlgNVNtxZIWIiIgkjSMrREREBigSTFAkGHm7fS7U1SH5kZV79+4hLCwMLi4usLKygo+PD44dO1Zm/YSEBMhkshKlul/CREREtdPjCbbGL/SE5EdWRo8ejdOnT+Obb76Bk5MTNm7cCD8/P5w9exaNGzcus9358+d11qY/+yZJIiIiqhkkPbLy4MEDbN++HZ999hlefvlluLm5YdasWXBzc9Pu1lcWe3t7KJVKbTExkfStEhFRDaX5563LxizGXgpd00n603j06BGKiopgaWmpc97Kykrn1del6dChAxwdHfHKK6/g0KFD5dYtKCiAWq3WKURERCQNkk5WrK2toVKpMHfuXNy4cQNFRUXYuHEjkpOTkZmZWWobR0dHREVFYfv27di+fTucnZ3Rq1cvnDhxosyvExkZCYVCoS3Ozs5i3RIREdUyxRNsjV3oCcm/G+jSpUsYOXIkDhw4AFNTU3Ts2BEvvfQSUlJScO7cuQrF8PX1RdOmTfHNN9+Uer2goAAFBQXaY7VaDWdnZ76TgYioDHw30JPYW1I9UMfa1Kix798rwtsdzvL30D8kP8G2RYsWSExMRF5eHtRqNRwdHTF06FA0b968wjG6du1a7mMjuVwOuVxujO4SEdELRiPCHBNut6+rxowz1a1bF46Ojrhz5w727NmDgQMHVrhtamoqHB0dRewdERERiUXyIyt79uyBIAho1aoVLl68iEmTJsHd3R0jRowAAEREROD69ev4+uuvAQBLliyBq6sr2rRpg/z8fKxduxb79+/H3r17q/M2iIiolioSZCgS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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Customize the matrix plot\n", - "import matplotlib.pylab as plt\n", - "\n", - "plt.figure(figsize=(6, 6))\n", - "ax = plt.gca()\n", - "wave.graphics.plot_matrix(\n", - " PM_mean,\n", - " xlabel=\"Te (s)\",\n", - " ylabel=\"Hm0 (m)\",\n", - " zlabel=\"Mean Power (kW)\",\n", - " show_values=False,\n", - " ax=ax,\n", - ")" + "data": { + "image/png": "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wt27d5GSkqK9vn//fmg0Gnh7e1fy0zEOya4GIiIiqgnE2MRN33ghISHYvHkzfvjhB1hbW2vnmCgUClhZWUEmk2HSpEmYOXMmPD090aFDB3z11Vf4448/8P333wN4PMrSv39/jBkzBlFRUXj48CFCQ0Px9ttvV+tKIIDJChERUY23cuVKAI+nVzxtw4YNeO+99wAAYWFhyM/Px8SJE3H79m14enoiLi4OLVq00NbftGkTQkND0bdvX5iYmGDw4MH44osvquo2yiQTyps08oJSq9VQKBTIycnR61khEdGLwl8xUpS4e3KM+x43MX+eF8f++XdX1LU27qyKvHsaBLS/wt9D/+CcFSIiIpI0PgYiIiIygAYyaIz8t78GfOjxNI6sEBERkaRxZIWIiMgAUlgNVNtxZIWIiIgkjSMrREREBigSTFAkGHm7fS7U1SH5kZV79+4hLCwMLi4usLKygo+PD44dO1Zm/YSEBMhkshKlul/CREREtdPjCbbGL/SE5EdWRo8ejdOnT+Obb76Bk5MTNm7cCD8/P5w9exaNGzcus9358+d11qY/+yZJIiIiqhkkPbLy4MEDbN++HZ999hlefvlluLm5YdasWXBzc9Pu1lcWe3t7KJVKbTExkfStEhFRDaX5563LxizGXgpd00n603j06BGKiopgaWmpc97Kykrn1del6dChAxwdHfHKK6/g0KFD5dYtKCiAWq3WKURERCQNkk5WrK2toVKpMHfuXNy4cQNFRUXYuHEjkpOTkZmZWWobR0dHREVFYfv27di+fTucnZ3Rq1cvnDhxosyvExkZCYVCoS3Ozs5i3RIREdUyxRNsjV3oCcm/G+jSpUsYOXIkDhw4AFNTU3Ts2BEvvfQSUlJScO7cuQrF8PX1RdOmTfHNN9+Uer2goAAFBQXaY7VaDWdnZ76TgYioDHw30JPYW1I9UMfa1Kix798rwtsdzvL30D8kP8G2RYsWSExMRF5eHtRqNRwdHTF06FA0b968wjG6du1a7mMjuVwOuVxujO4SEdELRiPCHBNut6+rxowz1a1bF46Ojrhz5w727NmDgQMHVrhtamoqHB0dRewdERERiUXyIyt79uyBIAho1aoVLl68iEmTJsHd3R0jRowAAEREROD69ev4+uuvAQBLliyBq6sr2rRpg/z8fKxduxb79+/H3r17q/M2iIiolioSZCgS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", + "text/plain": [ + "
" ] + }, + "metadata": {}, + "output_type": "display_data" } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.7" - } + ], + "source": [ + "# Customize the matrix plot\n", + "import matplotlib.pylab as plt\n", + "\n", + "plt.figure(figsize=(6, 6))\n", + "ax = plt.gca()\n", + "wave.graphics.plot_matrix(\n", + " PM_mean,\n", + " xlabel=\"Te (s)\",\n", + " ylabel=\"Hm0 (m)\",\n", + " zlabel=\"Mean Power (kW)\",\n", + " show_values=False,\n", + " ax=ax,\n", + ")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" }, - "nbformat": 4, - "nbformat_minor": 4 + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 4 } From 28e67f60b6fff03a65224694fa28d8b20a4dc189 Mon Sep 17 00:00:00 2001 From: akeeste Date: Mon, 14 Oct 2024 11:46:27 -0500 Subject: [PATCH 31/39] pull buoy name from metadata in cdip example --- examples/cdip_example.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/cdip_example.ipynb b/examples/cdip_example.ipynb index 0f5028af..698d794b 100644 --- a/examples/cdip_example.ipynb +++ b/examples/cdip_example.ipynb @@ -576,7 +576,7 @@ "Hs = buoy_data[\"data\"][\"wave\"][\"waveHs\"]\n", "Tp = buoy_data[\"data\"][\"wave\"][\"waveTp\"]\n", "Dp = buoy_data[\"data\"][\"wave\"][\"waveDp\"]\n", - "buoy_name = buoy_data[\"data\"][\"wave\"].name\n", + "buoy_name = buoy_data[\"metadata\"][\"name\"]\n", "ax = graphics.plot_compendium(Hs, Tp, Dp, buoy_name)" ] }, @@ -590,7 +590,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -604,7 +604,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.7" + "version": "3.12.7" } }, "nbformat": 4, From 69e694b63870eb80c4ca3df2d57bce496c06490b Mon Sep 17 00:00:00 2001 From: akeeste Date: Mon, 14 Oct 2024 13:46:47 -0500 Subject: [PATCH 32/39] tighten up example timing --- .github/workflows/generate_notebook_matrix.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/generate_notebook_matrix.py b/.github/workflows/generate_notebook_matrix.py index 02f81a00..966f921e 100644 --- a/.github/workflows/generate_notebook_matrix.py +++ b/.github/workflows/generate_notebook_matrix.py @@ -14,14 +14,14 @@ "cdip_example.ipynb": 420, "Delft3D_example.ipynb": 180, "directional_waves.ipynb": 180, - "environmental_contours_example.ipynb": 360, - "extreme_response_contour_example.ipynb": 360, - "extreme_response_full_sea_state_example.ipynb": 360, - "extreme_response_MLER_example.ipynb": 360, + "environmental_contours_example.ipynb": 240, + "extreme_response_contour_example.ipynb": 240, + "extreme_response_full_sea_state_example.ipynb": 240, + "extreme_response_MLER_example.ipynb": 240, "loads_example.ipynb": 180, "metocean_example.ipynb": 180, "mooring_example.ipynb": 240, - "PacWave_resource_characterization_example.ipynb": 780, + "PacWave_resource_characterization_example.ipynb": 240, "power_example.ipynb": 180, "qc_example.ipynb": 180, "river_example.ipynb": 180, From 243a99908f9f0691e022b4d756ba78ecfeeebf5d Mon Sep 17 00:00:00 2001 From: akeeste Date: Thu, 17 Oct 2024 12:27:52 -0500 Subject: [PATCH 33/39] address minor review comments, add some type checking tests --- mhkit/tests/wave/test_resource_metrics.py | 19 +++++++++++++------ mhkit/utils/type_handling.py | 2 +- mhkit/wave/performance.py | 12 ++++++------ mhkit/wave/resource.py | 1 - 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/mhkit/tests/wave/test_resource_metrics.py b/mhkit/tests/wave/test_resource_metrics.py index 9276d369..b1266fff 100644 --- a/mhkit/tests/wave/test_resource_metrics.py +++ b/mhkit/tests/wave/test_resource_metrics.py @@ -95,11 +95,11 @@ def test_kfromw(self): expected = self.valdata1[i]["k"] k = wave.resource.wave_number(f, h, rho) - # calculated = k.loc[:, "k"].values calculated = k error = ((expected - calculated) ** 2).sum() # SSE self.assertLess(error, 1e-6) + self.assertIsInstance(calculated, type(f)) def test_kfromw_one_freq(self): g = 9.81 @@ -110,18 +110,23 @@ def test_kfromw_one_freq(self): calculated = wave.resource.wave_number(f=f, h=h, g=g).item() error = np.abs(expected - calculated) self.assertLess(error, 1e-6) + self.assertIsInstance(calculated, type(f)) def test_wave_length(self): k_array = np.asarray([1.0, 2.0, 10.0, 3.0]) - k_int = int(k_array[0]) k_float = k_array[0] k_df = pd.DataFrame(k_array, index=[1, 2, 3, 4]) k_series = k_df[0] - for l in [k_array, k_int, k_float, k_df, k_series]: - l_calculated = wave.resource.wave_length(l) - self.assertTrue(np.all(2.0 * np.pi / l == l_calculated)) + for k in [k_int]: + l_calculated = wave.resource.wave_length(k) + self.assertTrue(np.all(2.0 * np.pi / k == l_calculated)) + + for k in [k_array, k_float, k_df, k_series]: + l_calculated = wave.resource.wave_length(k) + self.assertTrue(np.all(2.0 * np.pi / k == l_calculated)) + self.assertIsInstance(l_calculated, type(k)) def test_depth_regime(self): h = 10 @@ -145,11 +150,13 @@ def test_depth_regime(self): for l in [l_array, l_series, l_da, l_ds]: calculated = wave.resource.depth_regime(l, h) self.assertTrue(np.all(expected == calculated)) + self.assertIsInstance(calculated, type(l)) # special formatting for pd.DataFrame for l in [l_df]: calculated = wave.resource.depth_regime(l, h) self.assertTrue(np.all(expected == calculated[0])) + self.assertIsInstance(calculated, type(l)) def test_wave_celerity(self): # Depth regime ratio @@ -235,10 +242,10 @@ def test_energy_period_to_peak_period(self): for g in gamma: for T in Te: Tp = wave.resource.energy_period_to_peak_period(T, g) + self.assertIsInstance(Tp, type(T)) f = np.linspace(1 / (10 * Tp), 3 / Tp, 100) S = wave.resource.jonswap_spectrum(f, Tp, Hs, g) - Te_calc = wave.resource.energy_period(S).item() error = np.abs(T - Te_calc) / Te_calc diff --git a/mhkit/utils/type_handling.py b/mhkit/utils/type_handling.py index e69dc5ef..634bebea 100644 --- a/mhkit/utils/type_handling.py +++ b/mhkit/utils/type_handling.py @@ -164,7 +164,7 @@ def convert_to_dataarray(data, name="data"): # Rename to "variable" to match how multiple Dataset variables get converted into a DataArray dimension data = xr.DataArray(data) if data.dims[1] == "dim_1": - # Slight chance their is already a name for the columns + # Slight chance there is already a name for the columns data = data.rename({"dim_1": "variable"}) # Checks xr.Dataset input and converts to xr.DataArray if possible diff --git a/mhkit/wave/performance.py b/mhkit/wave/performance.py index d1d797e2..160918cc 100644 --- a/mhkit/wave/performance.py +++ b/mhkit/wave/performance.py @@ -246,14 +246,14 @@ def power_matrix(LM, JM): Parameters ------------ - LM: pandas DataFrame, xarray DatArray, or xarray Dataset + LM: pandas DataFrame, xarray DataArray, or xarray Dataset Capture length matrix - JM: pandas DataFrame, xarray DatArray, or xarray Dataset + JM: pandas DataFrame, xarray DataArray, or xarray Dataset Wave energy flux matrix Returns --------- - PM: pandas DataFrame, xarray DatArray, or xarray Dataset + PM: pandas DataFrame, xarray DataArray, or xarray Dataset Power matrix """ @@ -306,11 +306,11 @@ def mean_annual_energy_production_matrix(LM, JM, frequency): Parameters ------------ - LM: pandas DataFrame, xarray DatArray, or xarray Dataset + LM: pandas DataFrame, xarray DataArray, or xarray Dataset Capture length - JM: pandas DataFrame, xarray DatArray, or xarray Dataset + JM: pandas DataFrame, xarray DataArray, or xarray Dataset Wave energy flux - frequency: pandas DataFrame, xarray DatArray, or xarray Dataset + frequency: pandas DataFrame, xarray DataArray, or xarray Dataset Data frequency for each bin Returns diff --git a/mhkit/wave/resource.py b/mhkit/wave/resource.py index ab99518d..9d421fe2 100644 --- a/mhkit/wave/resource.py +++ b/mhkit/wave/resource.py @@ -1164,7 +1164,6 @@ def wave_number(f, h, rho=1025, g=9.80665, to_pandas=True): """ if isinstance(f, (int, float)): f = np.asarray([f]) - # f = convert_to_dataarray(f) if not isinstance(h, (int, float)): raise TypeError(f"h must be of type int or float. Got: {type(h)}") if not isinstance(rho, (int, float)): From a7241f3898e542baa247fa72d120c8190fe461e9 Mon Sep 17 00:00:00 2001 From: akeeste Date: Thu, 17 Oct 2024 14:42:45 -0500 Subject: [PATCH 34/39] complicated dataset and dataframe handling in surface_elevation and elevation_spectrum --- mhkit/wave/resource.py | 279 ++++++++++++++++++++++------------------- 1 file changed, 153 insertions(+), 126 deletions(-) diff --git a/mhkit/wave/resource.py b/mhkit/wave/resource.py index 9d421fe2..643e0365 100644 --- a/mhkit/wave/resource.py +++ b/mhkit/wave/resource.py @@ -4,7 +4,7 @@ import pandas as pd import xarray as xr import numpy as np -from mhkit.utils import to_numeric_array, convert_to_dataarray +from mhkit.utils import to_numeric_array, convert_to_dataarray, convert_to_dataset ### Spectrum @@ -46,14 +46,14 @@ def elevation_spectrum( Returns --------- - S: pandas DataFrame or xr.Dataset - Spectral density [m^2/Hz] indexed by frequency [Hz] + S: pandas DataFrame, pandas Series, xarray DataArray, or xarray Dataset + Spectral density [m^2/Hz] indexed by frequency [Hz]. Type depends on + number of variables in eta and value of the to_pandas flag. """ # TODO: Add confidence intervals, equal energy frequency spacing, and NDBC # frequency spacing # TODO: may need to raise an error for the length of nnft- signal.welch breaks when nfft is too short - eta = convert_to_dataarray(eta) if not isinstance(sample_rate, (float, int)): raise TypeError( f"sample_rate must be of type int or float. Got: {type(sample_rate)}" @@ -70,37 +70,50 @@ def elevation_spectrum( raise ValueError(f"sample_rate must be > 0. Got: {sample_rate}") if not isinstance(to_pandas, bool): raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") - - if time_dimension == "": - time_dimension = list(eta.dims)[0] - else: - if time_dimension not in list(eta.dims): + + if isinstance(eta, xr.DataArray): + eta = convert_to_dataset(eta,"eta") + elif isinstance(eta, pd.Series): + if eta.name == None: + eta.name = "eta" + eta = pd.DataFrame(eta) + + S = xr.Dataset() + for var in eta.data_vars if isinstance(eta, xr.Dataset) else eta.columns: + eta_subset = convert_to_dataarray(eta[var]) + if time_dimension == "": + time_dimension = list(eta_subset.dims)[0] + else: + if time_dimension not in list(eta_subset.dims): + raise ValueError( + f"time_dimension is not a dimension of eta[{var}] ({list(eta_subset.dims)}). Got: {time_dimension}." + ) + time = eta_subset[time_dimension] + delta_t = time.values[1] - time.values[0] + if not np.allclose(time.diff(dim=time_dimension)[1:], delta_t): raise ValueError( - f"time_dimension is not a dimension of eta ({list(eta.dims)}). Got: {time_dimension}." + "Time bins are not evenly spaced. Create a constant " + + f"temporal spacing for eta[{var}]." ) - time = eta[time_dimension] - delta_t = time.values[1] - time.values[0] - if not np.allclose(time.diff(dim=time_dimension)[1:], delta_t): - raise ValueError( - "Time bins are not evenly spaced. Create a constant " - + "temporal spacing for eta." - ) - if detrend: - eta = _signal.detrend( - eta.dropna(dim=time_dimension), axis=-1, type="linear", bp=0 + if detrend: + eta_subset = _signal.detrend( + eta_subset.dropna(dim=time_dimension), axis=-1, type="linear", bp=0 + ) + [f, wave_spec_measured] = _signal.welch( + eta_subset, + fs=sample_rate, + window=window, + nperseg=nnft, + nfft=nnft, + noverlap=noverlap, ) - [f, wave_spec_measured] = _signal.welch( - eta, - fs=sample_rate, - window=window, - nperseg=nnft, - nfft=nnft, - noverlap=noverlap, - ) - S = xr.DataArray( - data=wave_spec_measured, dims=["Frequency"], coords={"Frequency": f} - ) + S[var] = (["Frequency"], wave_spec_measured) + S = S.assign_coords({"Frequency": f}) + + varList = list(S.data_vars) + if len(varList) == 1: + S = S[varList[0]] if to_pandas: S = S.to_pandas() @@ -285,11 +298,11 @@ def surface_elevation( Returns --------- eta: pandas DataFrame or xarray Dataset - Wave surface elevation [m] indexed by time [s] + Wave surface elevation [m] indexed by time [s]. Type depends on + number of variables in eta and value of the to_pandas flag. """ time_index = to_numeric_array(time_index, "time_index") - S = convert_to_dataarray(S) if not isinstance(seed, (type(None), int)): raise TypeError(f"If specified, seed must be of type int. Got: {type(seed)}") if not isinstance(phases, type(None)): @@ -299,106 +312,120 @@ def surface_elevation( if not isinstance(to_pandas, bool): raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") - if frequency_dimension == "": - frequency_dimension = list(S.coords)[0] - elif frequency_dimension not in list(S.dims): - # frequency_dimension given, but not in list of possible dimensions - raise ValueError( - f"frequency_dimension is not a dimension of S ({list(S.dims)}). Got: {frequency_dimension}." - ) - frequency_axis = list(S.dims).index(frequency_dimension) - - # Create dimensions and coordinates for the new dataset (frequency becomes time) - new_dims = list(S.dims) - new_dims[frequency_axis] = "Time" - new_coords = S.sum(dim=frequency_dimension).coords - new_coords = new_coords.assign({"Time": time_index}) - f = S[frequency_dimension] - - if not isinstance(frequency_bins, (type(None), np.ndarray)): - frequency_bins = convert_to_dataarray(frequency_bins) - elif isinstance(frequency_bins, np.ndarray): - frequency_bins = xr.DataArray( - data=frequency_bins, - dims=frequency_dimension, - coords={frequency_dimension: f}, - ) - if frequency_bins is not None: - if not frequency_bins.squeeze().shape == f.shape: - raise ValueError( - "shape of frequency_bins must only contain 1 column and match the shape of the frequency dimension of S" - ) - delta_f = frequency_bins - delta_f_even = np.allclose(frequency_bins, frequency_bins[0]) - if delta_f_even: - # reduce delta_f to a scalar if it is uniform - delta_f = delta_f[0].item() - else: - delta_f = f.values[1] - f.values[0] - delta_f_even = np.allclose(f.diff(dim=frequency_dimension)[1:], delta_f) - if phases is not None: - if not phases.shape == S.shape: + + if isinstance(S, xr.DataArray): + S = convert_to_dataset(S,"S") + elif isinstance(S, pd.Series): + if S.name == None: + S.name = "S" + S = pd.DataFrame(S) + + eta = xr.Dataset() + for var in S.data_vars if isinstance(S, xr.Dataset) else S.columns: + S_subset = convert_to_dataarray(S[var]) + if frequency_dimension == "": + frequency_dimension = list(S_subset.coords)[0] + elif frequency_dimension not in list(S_subset.dims): + # frequency_dimension given, but not in list of possible dimensions raise ValueError( - "shape of variables in phases must match shape of variables in S" + f"frequency_dimension is not a dimension of S[{var}] ({list(S_subset.dims)}). Got: {frequency_dimension}." ) - if method == "ifft": - # ifft method must have a zero frequency and evenly spaced frequency bins - if not f[0] == 0: - warnings.warn( - f"ifft method must have zero frequency defined. Lowest frequency is: {f[0].values}. Setting method to less efficient `sum_of_sines` method." + frequency_axis = list(S_subset.dims).index(frequency_dimension) + + # Create dimensions and coordinates for the new dataset (frequency becomes time) + new_dims = list(S_subset.dims) + new_dims[frequency_axis] = "Time" + new_coords = S_subset.sum(dim=frequency_dimension).coords + new_coords = new_coords.assign({"Time": time_index}) + f = S_subset[frequency_dimension] + + if not isinstance(frequency_bins, (type(None), np.ndarray)): + frequency_bins = convert_to_dataarray(frequency_bins) + elif isinstance(frequency_bins, np.ndarray): + frequency_bins = xr.DataArray( + data=frequency_bins, + dims=frequency_dimension, + coords={frequency_dimension: f}, ) - method = "sum_of_sines" - if not delta_f_even: - warnings.warn( - f"ifft method must have evenly spaced frequency bins. Setting method to less efficient `sum_of_sines` method." + if frequency_bins is not None: + if not frequency_bins.squeeze().shape == f.shape: + raise ValueError( + "shape of frequency_bins must only contain 1 column and match the shape of the frequency dimension of S" + ) + delta_f = frequency_bins + delta_f_even = np.allclose(frequency_bins, frequency_bins[0]) + if delta_f_even: + # reduce delta_f to a scalar if it is uniform + delta_f = delta_f[0].item() + else: + delta_f = f.values[1] - f.values[0] + delta_f_even = np.allclose(f.diff(dim=frequency_dimension)[1:], delta_f) + if phases is not None: + if not phases.shape == S.shape: + raise ValueError( + "shape of variables in phases must match shape of variables in S" + ) + if method == "ifft": + # ifft method must have a zero frequency and evenly spaced frequency bins + if not f[0] == 0: + warnings.warn( + f"ifft method must have zero frequency defined. Lowest frequency is: {f[0].values}. Setting method to less efficient `sum_of_sines` method." + ) + method = "sum_of_sines" + if not delta_f_even: + warnings.warn( + f"ifft method must have evenly spaced frequency bins. Setting method to less efficient `sum_of_sines` method." + ) + method = "sum_of_sines" + elif method == "sum_of_sines": + # For sum of sines, does not matter if there is a zero frequency or if frequency bins are evenly spaced + pass + else: + raise ValueError(f"Method must be 'ifft' or 'sum_of_sines'. Got: {method}") + + omega = xr.DataArray( + data=2 * np.pi * f, dims=frequency_dimension, coords={frequency_dimension: f} + ) + + if phases is None: + np.random.seed(seed) + phase = xr.DataArray( + data=2 * np.pi * np.random.random_sample(S_subset[frequency_dimension].shape), + dims=frequency_dimension, + coords={frequency_dimension: f}, ) - method = "sum_of_sines" - elif method == "sum_of_sines": - # For sum of sines, does not matter if there is a zero frequency or if frequency bins are evenly spaced - pass - else: - raise ValueError(f"Method must be 'ifft' or 'sum_of_sines'. Got: {method}") + else: + phase = phases - omega = xr.DataArray( - data=2 * np.pi * f, dims=frequency_dimension, coords={frequency_dimension: f} - ) + # Wave amplitude times delta f + A = np.sqrt(2 * S_subset * delta_f) - if phases is None: - np.random.seed(seed) - phase = xr.DataArray( - data=2 * np.pi * np.random.random_sample(S[frequency_dimension].shape), - dims=frequency_dimension, - coords={frequency_dimension: f}, - ) - else: - phase = phases - - # Wave amplitude times delta f - A = np.sqrt(2 * S * delta_f) - - if method == "ifft": - A_cmplx = A * (np.cos(phase) + 1j * np.sin(phase)) - # eta_tmp = np.fft.irfft(0.5 * A_cmplx.values * time_index.size, time_index.size) - eta_tmp = np.fft.irfftn( - 0.5 * A_cmplx * time_index.size, - list(time_index.shape), - axes=[frequency_axis], - ) - eta = xr.DataArray(data=eta_tmp, dims=new_dims, coords=new_coords) - - elif method == "sum_of_sines": - # Product of omega and time - B = np.outer(time_index, omega) - B = B.reshape((len(time_index), len(omega))) - B = xr.DataArray( - data=B, - dims=["Time", frequency_dimension], - coords={"Time": time_index, frequency_dimension: f}, - ) + if method == "ifft": + A_cmplx = A * (np.cos(phase) + 1j * np.sin(phase)) + eta_tmp = np.fft.irfftn( + 0.5 * A_cmplx * time_index.size, + list(time_index.shape), + axes=[frequency_axis], + ) + eta[var] = xr.DataArray(data=eta_tmp, dims=new_dims, coords=new_coords) + + elif method == "sum_of_sines": + # Product of omega and time + B = np.outer(time_index, omega) + B = B.reshape((len(time_index), len(omega))) + B = xr.DataArray( + data=B, + dims=["Time", frequency_dimension], + coords={"Time": time_index, frequency_dimension: f}, + ) + + # wave elevation + C = np.cos(B + phase) + eta[var] = (C * A).sum(dim=frequency_dimension) - # wave elevation - C = np.cos(B + phase) - eta = (C * A).sum(dim=frequency_dimension) + varList = list(eta.data_vars) + if len(varList) == 1: + eta = eta[varList[0]] if to_pandas: eta = eta.to_pandas() From d13bb223b6aa8c15e02dfa2ab93383b393f9caf1 Mon Sep 17 00:00:00 2001 From: akeeste Date: Thu, 17 Oct 2024 15:09:10 -0500 Subject: [PATCH 35/39] restore and simplify dataset input to elevation_spectrum, surface_elevation --- mhkit/tests/wave/test_resource_spectrum.py | 2 +- mhkit/wave/resource.py | 181 +++++++++------------ 2 files changed, 81 insertions(+), 102 deletions(-) diff --git a/mhkit/tests/wave/test_resource_spectrum.py b/mhkit/tests/wave/test_resource_spectrum.py index 58422ef8..39015c55 100644 --- a/mhkit/tests/wave/test_resource_spectrum.py +++ b/mhkit/tests/wave/test_resource_spectrum.py @@ -168,7 +168,7 @@ def test_user_spectrum_without_frequency_index_name_defined(self): expected_magnitude = [-0.983917, 1.274248, -2.129812] - assert_allclose(result, expected_magnitude, atol=1e-6) + assert_allclose(result.values[:,0], expected_magnitude, atol=1e-6) def test_ifft_sum_of_sines(self): S = wave.resource.jonswap_spectrum(self.f, self.Tp, self.Hs) diff --git a/mhkit/wave/resource.py b/mhkit/wave/resource.py index 643e0365..5ce55730 100644 --- a/mhkit/wave/resource.py +++ b/mhkit/wave/resource.py @@ -47,13 +47,13 @@ def elevation_spectrum( Returns --------- S: pandas DataFrame, pandas Series, xarray DataArray, or xarray Dataset - Spectral density [m^2/Hz] indexed by frequency [Hz]. Type depends on - number of variables in eta and value of the to_pandas flag. + Spectral density [m^2/Hz] indexed by frequency [Hz]. """ # TODO: Add confidence intervals, equal energy frequency spacing, and NDBC # frequency spacing # TODO: may need to raise an error for the length of nnft- signal.welch breaks when nfft is too short + eta = convert_to_dataset(eta,"eta") if not isinstance(sample_rate, (float, int)): raise TypeError( f"sample_rate must be of type int or float. Got: {type(sample_rate)}" @@ -70,32 +70,25 @@ def elevation_spectrum( raise ValueError(f"sample_rate must be > 0. Got: {sample_rate}") if not isinstance(to_pandas, bool): raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") - - if isinstance(eta, xr.DataArray): - eta = convert_to_dataset(eta,"eta") - elif isinstance(eta, pd.Series): - if eta.name == None: - eta.name = "eta" - eta = pd.DataFrame(eta) - S = xr.Dataset() - for var in eta.data_vars if isinstance(eta, xr.Dataset) else eta.columns: - eta_subset = convert_to_dataarray(eta[var]) - if time_dimension == "": - time_dimension = list(eta_subset.dims)[0] - else: - if time_dimension not in list(eta_subset.dims): - raise ValueError( - f"time_dimension is not a dimension of eta[{var}] ({list(eta_subset.dims)}). Got: {time_dimension}." - ) - time = eta_subset[time_dimension] - delta_t = time.values[1] - time.values[0] - if not np.allclose(time.diff(dim=time_dimension)[1:], delta_t): + if time_dimension == "": + time_dimension = list(eta.dims)[0] + else: + if time_dimension not in list(eta.dims): raise ValueError( - "Time bins are not evenly spaced. Create a constant " - + f"temporal spacing for eta[{var}]." + f"time_dimension is not a dimension of eta ({list(eta.dims)}). Got: {time_dimension}." ) + time = eta[time_dimension] + delta_t = time.values[1] - time.values[0] + if not np.allclose(time.diff(dim=time_dimension)[1:], delta_t): + raise ValueError( + "Time bins are not evenly spaced. Create a constant " + + f"temporal spacing for eta." + ) + S = xr.Dataset() + for var in eta.data_vars: + eta_subset = eta[var] if detrend: eta_subset = _signal.detrend( eta_subset.dropna(dim=time_dimension), axis=-1, type="linear", bp=0 @@ -111,10 +104,6 @@ def elevation_spectrum( S[var] = (["Frequency"], wave_spec_measured) S = S.assign_coords({"Frequency": f}) - varList = list(S.data_vars) - if len(varList) == 1: - S = S[varList[0]] - if to_pandas: S = S.to_pandas() @@ -302,91 +291,85 @@ def surface_elevation( number of variables in eta and value of the to_pandas flag. """ + S = convert_to_dataset(S,"S") time_index = to_numeric_array(time_index, "time_index") if not isinstance(seed, (type(None), int)): raise TypeError(f"If specified, seed must be of type int. Got: {type(seed)}") if not isinstance(phases, type(None)): - phases = convert_to_dataarray(phases) + phases = convert_to_dataset(phases) if not isinstance(method, str): raise TypeError(f"method must be of type str. Got: {type(method)}") if not isinstance(to_pandas, bool): raise TypeError(f"to_pandas must be of type bool. Got: {type(to_pandas)}") - - if isinstance(S, xr.DataArray): - S = convert_to_dataset(S,"S") - elif isinstance(S, pd.Series): - if S.name == None: - S.name = "S" - S = pd.DataFrame(S) + if frequency_dimension == "": + frequency_dimension = list(S.coords)[0] + elif frequency_dimension not in list(S.dims): + # frequency_dimension given, but not in list of possible dimensions + raise ValueError( + f"frequency_dimension is not a dimension of S ({list(S.dims)}). Got: {frequency_dimension}." + ) + frequency_axis = list(S.dims).index(frequency_dimension) - eta = xr.Dataset() - for var in S.data_vars if isinstance(S, xr.Dataset) else S.columns: - S_subset = convert_to_dataarray(S[var]) - if frequency_dimension == "": - frequency_dimension = list(S_subset.coords)[0] - elif frequency_dimension not in list(S_subset.dims): - # frequency_dimension given, but not in list of possible dimensions + # Create dimensions and coordinates for the new dataset (frequency becomes time) + new_dims = list(S.dims) + new_dims[frequency_axis] = "Time" + new_coords = S.sum(dim=frequency_dimension).coords + new_coords = new_coords.assign({"Time": time_index}) + f = S[frequency_dimension] + + if not isinstance(frequency_bins, (type(None), np.ndarray)): + frequency_bins = convert_to_dataarray(frequency_bins) + elif isinstance(frequency_bins, np.ndarray): + frequency_bins = xr.DataArray( + data=frequency_bins, + dims=frequency_dimension, + coords={frequency_dimension: f}, + ) + if frequency_bins is not None: + if not frequency_bins.squeeze().shape == f.shape: raise ValueError( - f"frequency_dimension is not a dimension of S[{var}] ({list(S_subset.dims)}). Got: {frequency_dimension}." + "shape of frequency_bins must only contain 1 column and match the shape of the frequency dimension of S" ) - frequency_axis = list(S_subset.dims).index(frequency_dimension) - - # Create dimensions and coordinates for the new dataset (frequency becomes time) - new_dims = list(S_subset.dims) - new_dims[frequency_axis] = "Time" - new_coords = S_subset.sum(dim=frequency_dimension).coords - new_coords = new_coords.assign({"Time": time_index}) - f = S_subset[frequency_dimension] - - if not isinstance(frequency_bins, (type(None), np.ndarray)): - frequency_bins = convert_to_dataarray(frequency_bins) - elif isinstance(frequency_bins, np.ndarray): - frequency_bins = xr.DataArray( - data=frequency_bins, - dims=frequency_dimension, - coords={frequency_dimension: f}, - ) - if frequency_bins is not None: - if not frequency_bins.squeeze().shape == f.shape: - raise ValueError( - "shape of frequency_bins must only contain 1 column and match the shape of the frequency dimension of S" - ) - delta_f = frequency_bins - delta_f_even = np.allclose(frequency_bins, frequency_bins[0]) - if delta_f_even: - # reduce delta_f to a scalar if it is uniform - delta_f = delta_f[0].item() - else: - delta_f = f.values[1] - f.values[0] - delta_f_even = np.allclose(f.diff(dim=frequency_dimension)[1:], delta_f) - if phases is not None: - if not phases.shape == S.shape: + delta_f = frequency_bins + delta_f_even = np.allclose(frequency_bins, frequency_bins[0]) + if delta_f_even: + # reduce delta_f to a scalar if it is uniform + delta_f = delta_f[0].item() + else: + delta_f = f.values[1] - f.values[0] + delta_f_even = np.allclose(f.diff(dim=frequency_dimension)[1:], delta_f) + if phases is not None: + for var in phases.data_vars: + if not phases[var].shape == S[var].shape: raise ValueError( "shape of variables in phases must match shape of variables in S" ) - if method == "ifft": - # ifft method must have a zero frequency and evenly spaced frequency bins - if not f[0] == 0: - warnings.warn( - f"ifft method must have zero frequency defined. Lowest frequency is: {f[0].values}. Setting method to less efficient `sum_of_sines` method." - ) - method = "sum_of_sines" - if not delta_f_even: - warnings.warn( - f"ifft method must have evenly spaced frequency bins. Setting method to less efficient `sum_of_sines` method." - ) - method = "sum_of_sines" - elif method == "sum_of_sines": - # For sum of sines, does not matter if there is a zero frequency or if frequency bins are evenly spaced - pass - else: - raise ValueError(f"Method must be 'ifft' or 'sum_of_sines'. Got: {method}") + if method == "ifft": + # ifft method must have a zero frequency and evenly spaced frequency bins + if not f[0] == 0: + warnings.warn( + f"ifft method must have zero frequency defined. Lowest frequency is: {f[0].values}. Setting method to less efficient `sum_of_sines` method." + ) + method = "sum_of_sines" + if not delta_f_even: + warnings.warn( + f"ifft method must have evenly spaced frequency bins. Setting method to less efficient `sum_of_sines` method." + ) + method = "sum_of_sines" + elif method == "sum_of_sines": + # For sum of sines, does not matter if there is a zero frequency or if frequency bins are evenly spaced + pass + else: + raise ValueError(f"Method must be 'ifft' or 'sum_of_sines'. Got: {method}") - omega = xr.DataArray( - data=2 * np.pi * f, dims=frequency_dimension, coords={frequency_dimension: f} - ) + omega = xr.DataArray( + data=2 * np.pi * f, dims=frequency_dimension, coords={frequency_dimension: f} + ) + eta = xr.Dataset() + for var in S.data_vars: + S_subset = S[var] if phases is None: np.random.seed(seed) phase = xr.DataArray( @@ -395,7 +378,7 @@ def surface_elevation( coords={frequency_dimension: f}, ) else: - phase = phases + phase = phases[var] # Wave amplitude times delta f A = np.sqrt(2 * S_subset * delta_f) @@ -423,10 +406,6 @@ def surface_elevation( C = np.cos(B + phase) eta[var] = (C * A).sum(dim=frequency_dimension) - varList = list(eta.data_vars) - if len(varList) == 1: - eta = eta[varList[0]] - if to_pandas: eta = eta.to_pandas() if isinstance(eta, (pd.Series, pd.DataFrame, xr.DataArray)): From 0b3036659ab61ddeff025cd8775435edfcf82106 Mon Sep 17 00:00:00 2001 From: akeeste Date: Thu, 17 Oct 2024 15:10:01 -0500 Subject: [PATCH 36/39] black formatting --- mhkit/tests/wave/test_resource_metrics.py | 2 +- mhkit/tests/wave/test_resource_spectrum.py | 2 +- mhkit/wave/resource.py | 10 ++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/mhkit/tests/wave/test_resource_metrics.py b/mhkit/tests/wave/test_resource_metrics.py index b1266fff..3df52fcd 100644 --- a/mhkit/tests/wave/test_resource_metrics.py +++ b/mhkit/tests/wave/test_resource_metrics.py @@ -122,7 +122,7 @@ def test_wave_length(self): for k in [k_int]: l_calculated = wave.resource.wave_length(k) self.assertTrue(np.all(2.0 * np.pi / k == l_calculated)) - + for k in [k_array, k_float, k_df, k_series]: l_calculated = wave.resource.wave_length(k) self.assertTrue(np.all(2.0 * np.pi / k == l_calculated)) diff --git a/mhkit/tests/wave/test_resource_spectrum.py b/mhkit/tests/wave/test_resource_spectrum.py index 39015c55..d2c0f235 100644 --- a/mhkit/tests/wave/test_resource_spectrum.py +++ b/mhkit/tests/wave/test_resource_spectrum.py @@ -168,7 +168,7 @@ def test_user_spectrum_without_frequency_index_name_defined(self): expected_magnitude = [-0.983917, 1.274248, -2.129812] - assert_allclose(result.values[:,0], expected_magnitude, atol=1e-6) + assert_allclose(result.values[:, 0], expected_magnitude, atol=1e-6) def test_ifft_sum_of_sines(self): S = wave.resource.jonswap_spectrum(self.f, self.Tp, self.Hs) diff --git a/mhkit/wave/resource.py b/mhkit/wave/resource.py index 5ce55730..a507792a 100644 --- a/mhkit/wave/resource.py +++ b/mhkit/wave/resource.py @@ -53,7 +53,7 @@ def elevation_spectrum( # TODO: Add confidence intervals, equal energy frequency spacing, and NDBC # frequency spacing # TODO: may need to raise an error for the length of nnft- signal.welch breaks when nfft is too short - eta = convert_to_dataset(eta,"eta") + eta = convert_to_dataset(eta, "eta") if not isinstance(sample_rate, (float, int)): raise TypeError( f"sample_rate must be of type int or float. Got: {type(sample_rate)}" @@ -287,11 +287,11 @@ def surface_elevation( Returns --------- eta: pandas DataFrame or xarray Dataset - Wave surface elevation [m] indexed by time [s]. Type depends on + Wave surface elevation [m] indexed by time [s]. Type depends on number of variables in eta and value of the to_pandas flag. """ - S = convert_to_dataset(S,"S") + S = convert_to_dataset(S, "S") time_index = to_numeric_array(time_index, "time_index") if not isinstance(seed, (type(None), int)): raise TypeError(f"If specified, seed must be of type int. Got: {type(seed)}") @@ -373,7 +373,9 @@ def surface_elevation( if phases is None: np.random.seed(seed) phase = xr.DataArray( - data=2 * np.pi * np.random.random_sample(S_subset[frequency_dimension].shape), + data=2 + * np.pi + * np.random.random_sample(S_subset[frequency_dimension].shape), dims=frequency_dimension, coords={frequency_dimension: f}, ) From 0c5f5be59f7973f40d44c7d487f641106c85b8e1 Mon Sep 17 00:00:00 2001 From: akeeste Date: Thu, 17 Oct 2024 15:11:07 -0500 Subject: [PATCH 37/39] update missed docstring --- mhkit/wave/resource.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mhkit/wave/resource.py b/mhkit/wave/resource.py index a507792a..488df50c 100644 --- a/mhkit/wave/resource.py +++ b/mhkit/wave/resource.py @@ -287,8 +287,7 @@ def surface_elevation( Returns --------- eta: pandas DataFrame or xarray Dataset - Wave surface elevation [m] indexed by time [s]. Type depends on - number of variables in eta and value of the to_pandas flag. + Wave surface elevation [m] indexed by time [s]. """ S = convert_to_dataset(S, "S") From ef669bd94fedd82777189f9fb477a00723b0e60e Mon Sep 17 00:00:00 2001 From: akeeste Date: Mon, 21 Oct 2024 09:38:18 -0500 Subject: [PATCH 38/39] use np.nan_to_num correctly in test_loads --- mhkit/tests/loads/test_loads.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mhkit/tests/loads/test_loads.py b/mhkit/tests/loads/test_loads.py index 012a7ecb..633763f8 100644 --- a/mhkit/tests/loads/test_loads.py +++ b/mhkit/tests/loads/test_loads.py @@ -422,7 +422,7 @@ def test_mler_wave_amp_normalize(self): mler["WaveSpectrum"] = self.mler["Res_Spec"].values mler["Phase"] = self.mler["phase"].values k = resource.wave_number(wave_freq, 70) - np.nan_to_num(k, 0) + k = np.nan_to_num(k, nan=0) mler_norm = loads.extreme.mler_wave_amp_normalize(4.5 * 1.9, mler, self.sim, k) mler_norm.reset_index(drop=True, inplace=True) From 0a4bbfb5869b3d1c24b05f476997f57ff2d03b62 Mon Sep 17 00:00:00 2001 From: ssolson Date: Tue, 22 Oct 2024 08:25:56 -0600 Subject: [PATCH 39/39] Speed up wave (#6) * matplotlib >=3.8 * remove debug --- mhkit/tests/wave/test_resource_spectrum.py | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/mhkit/tests/wave/test_resource_spectrum.py b/mhkit/tests/wave/test_resource_spectrum.py index d2c0f235..e52f53bf 100644 --- a/mhkit/tests/wave/test_resource_spectrum.py +++ b/mhkit/tests/wave/test_resource_spectrum.py @@ -149,6 +149,39 @@ def test_surface_elevation_rmse(self): self.assertLess(rmse_sum, 0.02) + def test_elevation_spectrum_multiple_variables(self): + time = np.linspace(0, 100, 1000) + eta1 = np.sin(2 * np.pi * 0.1 * time) + eta2 = np.sin(2 * np.pi * 0.2 * time) + eta3 = np.sin(2 * np.pi * 0.3 * time) + + eta_dataset = xr.Dataset( + { + "eta1": (["time"], eta1), + "eta2": (["time"], eta2), + "eta3": (["time"], eta3), + }, + coords={"time": time}, + ) + + sample_rate = 10 + nnft = 256 + + spectra = wave.resource.elevation_spectrum(eta_dataset, sample_rate, nnft) + + # For each variable, find the frequency at which the spectrum has its maximum value + for var_name, expected_peak_freq in [ + ("eta1", 0.117), + ("eta2", 0.2), + ("eta3", 0.3125), + ]: + spec_values = spectra[var_name].values + peak_index = np.argmax(spec_values) + peak_freq = spectra.index[peak_index] + + # Assert that the peak frequency is close to the expected frequency + self.assertAlmostEqual(peak_freq, expected_peak_freq, places=2) + def test_mhkit_spectrum_without_frequency_index_name_defined(self): S = wave.resource.jonswap_spectrum(self.f, self.Tp, self.Hs) S.index.name = None