Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ dependencies = [
"py_wake>=2.6.5",
"foxes>=1.6.2",
"windIO @ git+https://github.com/EUFlow/windIO.git",
"wayve @ git+https://gitlab.kuleuven.be/TFSO-software/wayve@dev_foxes",
"floris @ git+https://github.com/lejeunemax/floris.git@windIO",
"wayve @ git+https://gitlab.kuleuven.be/TFSO-software/wayve",
"numpy>=1.22,<3.0",
"xarray>=2022.0.0,<2025",
"mpmath",
]
Expand Down
11 changes: 9 additions & 2 deletions tests/test_floris.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,18 @@
import shutil
from pathlib import Path

import floris
import numpy as np
import pytest
import xarray as xr
from floris.turbine_library import build_cosine_loss_turbine_dict

try:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

THis feels a bit off. Shouldn't we be able to trust floris is installed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was to skip the tests for Python versions not supported by Floris, but I agree we could make it more explicit.

Something like what I am using in another branch: https://github.com/EUFLOW/WIFA/pull/53/changes#diff-f94225c5bf10b634a7ad34c965e9f67dd9cc2db995eff9822e6ac3441b019eb8R15

import floris
from floris.turbine_library import build_cosine_loss_turbine_dict
except (ImportError, TypeError):
pytest.skip(
"floris not available or incompatible with this Python version",
allow_module_level=True,
)
from windIO import __path__ as wiop
from windIO import load_yaml
from windIO import validate as validate_yaml
Expand Down
20 changes: 20 additions & 0 deletions tests/test_pywake.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import shutil
from pathlib import Path

import numpy as np
Expand Down Expand Up @@ -441,6 +442,25 @@ def test_turbine_specific_speeds_timeseries():
npt.assert_allclose(wifa_res, manual_aep, rtol=1e-6)


def test_pywake_dict_timeseries_per_turbine_with_density(tmp_path):
from conftest import make_timeseries_per_turbine_system_dict

# Run with density
system_dict = make_timeseries_per_turbine_system_dict("pywake")
output_dir = tmp_path / "output_pywake_ts"
aep_with = run_pywake(system_dict, output_dir=str(output_dir))
assert np.isfinite(aep_with) and aep_with > 0

# Run without density — same config but density removed
system_dict_no = make_timeseries_per_turbine_system_dict("pywake")
del system_dict_no["site"]["energy_resource"]["wind_resource"]["density"]
output_dir_no = tmp_path / "output_pywake_ts_no_density"
aep_without = run_pywake(system_dict_no, output_dir=str(output_dir_no))

# Density correction should change AEP (test data varies around 1.225)
assert aep_with != aep_without


# if __name__ == "__main__":
# test_heterogeneous_wind_rose()
# simple_yaml_to_pywake('../examples/cases/windio_4turbines_multipleTurbines/plant_energy_turbine/IEA_10MW_turbine.yaml')
Expand Down
23 changes: 17 additions & 6 deletions wifa/pywake_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ def dict_to_site(resource_dict):
"sector_probability": "Sector_frequency",
"turbulence_intensity": "TI",
"wind_turbine": "i",
"density": "Air_density",
}

# Smart rename for wind_direction and wind_speed
Expand Down Expand Up @@ -428,14 +429,21 @@ def get_resource_data(var_name):
TIs.append(ti_int)
TI = ti_int

data_vars = {
"WS": (["h", "time"], np.array(speeds)),
"WD": (["h", "time"], np.array(dirs)),
"TI": (["h", "time"], np.array(TIs)),
"P": 1,
}
if "density" in wind_resource:
density_vals = np.array(wind_resource["density"]["data"])[cases_idx]
density_dims = wind_resource["density"].get("dims", ["time"])
if "wind_turbine" in density_dims:
density_vals = np.mean(density_vals, axis=1)
data_vars["Air_density"] = (["time"], density_vals)
site = XRSite(
xr.Dataset(
data_vars={
"WS": (["h", "time"], np.array(speeds)),
"WD": (["h", "time"], np.array(dirs)),
"TI": (["h", "time"], np.array(TIs)),
"P": 1,
},
data_vars=data_vars,
coords={"h": seen, "time": np.arange(len(times))},
)
)
Expand All @@ -452,6 +460,9 @@ def get_resource_data(var_name):
site = dict_to_site(wind_resource)
else:
site = Hornsrev1Site()
if "density" in wind_resource:
density_vals = np.array(wind_resource["density"]["data"])[cases_idx]
site.ds["Air_density"] = (("time",), density_vals)

# Handle TI
if "turbulence_intensity" not in wind_resource:
Expand Down
5 changes: 3 additions & 2 deletions wifa/wayve_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -824,8 +824,9 @@ def flow_io_abl(wind_resource_dat, time_index, zh, h1, dh_max=None, serz=True):
)
# Geostrophic wind speed
z = np.linspace(h, 15.0e3, 1000)
U3 = np.trapz(np.interp(z, zs, us), z) / (15.0e3 - h)
V3 = np.trapz(np.interp(z, zs, vs), z) / (15.0e3 - h)
_trapezoid = np.trapezoid if hasattr(np, "trapezoid") else np.trapz
U3 = _trapezoid(np.interp(z, zs, us), z) / (15.0e3 - h)
V3 = _trapezoid(np.interp(z, zs, vs), z) / (15.0e3 - h)
# Upper layer thickness
h2 = h - h1
if (
Expand Down