From 852ccceec53c6bd43f68e75c4cded9dde174fc4c Mon Sep 17 00:00:00 2001 From: "Mads M. Pedersen" <mmpe@dtu.dk> Date: Tue, 22 Jun 2021 09:54:01 +0000 Subject: [PATCH] new site based on global wind atlas data --- py_wake/site/xrsite.py | 52 +++++++++++++++++++++++-- py_wake/tests/test_sites/test_xrsite.py | 27 ++++++++++++- py_wake/utils/weibull.py | 5 +++ 3 files changed, 80 insertions(+), 4 deletions(-) diff --git a/py_wake/site/xrsite.py b/py_wake/site/xrsite.py index af53d989c..db92dca22 100644 --- a/py_wake/site/xrsite.py +++ b/py_wake/site/xrsite.py @@ -1,9 +1,11 @@ -import xarray as xr -from py_wake.site.distance import StraightDistance import numpy as np -from py_wake.utils.grid_interpolator import GridInterpolator, EqDistRegGrid2DInterpolator +from numpy import newaxis as na +import xarray as xr +from requests import get from py_wake.site._site import Site +from py_wake.site.distance import StraightDistance from py_wake.utils import weibull +from py_wake.utils.grid_interpolator import GridInterpolator, EqDistRegGrid2DInterpolator class XRSite(Site): @@ -309,3 +311,47 @@ class UniformWeibullSite(XRSite): if ti is not None: ds['TI'] = ti XRSite.__init__(self, ds, interp_method=interp_method, shear=shear) + + +class GlobalWindAtlasSite(XRSite): + """Site with Global Wind Climate (GWC) from the Global Wind Atlas based on + lat and long which is interpolated at specific roughness and height. + """ + + def __init__(self, lat, long, height, roughness, ti=None, **kwargs): + """ + Parameters + ---------- + lat: float + Latitude of the location + long: float + Longitude of the location + height: float + Height of the location + roughness: float + roughness length at the location + """ + self.gwc_ds = self._read_gwc(lat, long) + if ti is not None: + self.gwc_ds['TI'] = ti + XRSite.__init__(self, ds=self.gwc_ds.interp(height=height, roughness=roughness), **kwargs) + + def _read_gwc(self, lat, long): + url_str = f'https://globalwindatlas.info/api/gwa/custom/Lib/?lat={lat}&long={long}' + lines = get(url_str).text.strip().split('\r\n') + + # Read header information one line at a time + # desc = txt[0].strip() # File Description + nrough, nhgt, nsec = map(int, lines[1].split()) # dimensions + roughnesses = np.array(lines[2].split(), dtype=float) # Roughness classes + heights = np.array(lines[3].split(), dtype=float) # heights + data = np.array([l.split() for l in lines[4:]], dtype=float).reshape((nrough, nhgt * 2 + 1, nsec)) + freq = data[:, 0] / data[:, 0].sum(1)[:, na] + A = data[:, 1::2] + k = data[:, 2::2] + ds = xr.Dataset({'Weibull_A': (["roughness", "height", "wd"], A), + 'Weibull_k': (["roughness", "height", "wd"], k), + "Sector_frequency": (["roughness", "wd"], freq)}, + coords={"height": heights, "roughness": roughnesses, + "wd": np.linspace(0, 360, nsec, endpoint=False)}) + return ds diff --git a/py_wake/tests/test_sites/test_xrsite.py b/py_wake/tests/test_sites/test_xrsite.py index f095949b7..3f7c9c539 100644 --- a/py_wake/tests/test_sites/test_xrsite.py +++ b/py_wake/tests/test_sites/test_xrsite.py @@ -1,6 +1,6 @@ import numpy as np from py_wake.site.shear import PowerShear -from py_wake.site.xrsite import XRSite +from py_wake.site.xrsite import XRSite, GlobalWindAtlasSite import xarray as xr from py_wake.tests import npt import pytest @@ -190,6 +190,31 @@ def test_complex_grid_local_wind(complex_grid_site): [0.01079997, 0.01656828, 0.02257487]]) +def test_GlobalWindAtlasSite(): + ref = Hornsrev1Site() + lat, long = 55.52972, 7.906111 # hornsrev + + site = GlobalWindAtlasSite(lat, long, height=70, roughness=0.001, ti=0.075) + ref_mean = weibull.mean(ref.ds.Weibull_A, ref.ds.Weibull_k) + gwa_mean = weibull.mean(site.ds.Weibull_A, site.ds.Weibull_k) + + if 0: + plt.figure() + plt.plot(ref.ds.wd, ref_mean, label='HornsrevSite') + plt.plot(site.ds.wd, gwa_mean, label='HornsrevSite') + for r in [0, 1.5]: + for h in [10, 200]: + A, k = [site.gwc_ds[v].sel(roughness=r, height=h) for v in ['Weibull_A', 'Weibull_k']] + plt.plot(site.gwc_ds.wd, weibull.mean(A, k), label=f'{h}, {r}') + plt.legend() + + plt.show() + + npt.assert_allclose(gwa_mean, ref_mean, atol=1.4) + for var, atol in [('Sector_frequency', 0.03), ('Weibull_A', 1.6), ('Weibull_k', 0.4)]: + npt.assert_allclose(site.ds[var], ref.ds[var], atol=atol) + + def test_wrong_height(): ti = 0.1 ds = xr.Dataset( diff --git a/py_wake/utils/weibull.py b/py_wake/utils/weibull.py index d6714e658..0b3998906 100644 --- a/py_wake/utils/weibull.py +++ b/py_wake/utils/weibull.py @@ -1,4 +1,9 @@ import numpy as np +from scipy.special import gamma + + +def mean(A, k): + return A * gamma(1 + 1 / k) def cdf(ws, A, k): -- GitLab