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
2 changes: 1 addition & 1 deletion examples/cases/KUL_LES/wind_energy_system/analysis_VM.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ HPC_config:
mesh_node_number: 2
mesh_ntasks_per_node: 48
mesh_wall_time_hours: 1
run_partition: ""
#run_partition: ""
#
wckey: ""

Expand Down
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ classifiers = [
requires-python = ">=3.9,<3.12"
dependencies = [
"py_wake>=2.6.5",
"foxes>=1.7.0",
"foxes @ git+https://github.com/FraunhoferIWES/foxes.git@eu_flow",
"windIO @ git+https://github.com/EUFlow/windIO.git",
"wayve @ git+https://gitlab.kuleuven.be/TFSO-software/wayve@dev_foxes",
#"numpy<2",
Expand All @@ -68,6 +68,9 @@ Homepage = "https://github.com/EUFLOW/WIFA/"
Repository = "https://github.com/EUFLOW/WIFA.git"
"Bug Tracker" = "https://github.com/EUFLOW/WIFA/issues"

[tool.pytest.ini_options]
pythonpath = ["tests"]

[tool.setuptools.packages.find]
exclude = ["notebooks", "examples", "tests", "docs", "recipe", "results", "output"]

Expand Down
236 changes: 236 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
import numpy as np

# DTU 10MW turbine data
# (from examples/cases/windio_4turbines/plant_energy_turbine/DTU_10MW_turbine.yaml)
_TURBINE = {
"name": "DTU 10MW Offshore Reference Turbine",
"hub_height": 119.0,
"rotor_diameter": 178.3,
"performance": {
"power_curve": {
"power_wind_speeds": [
4.0,
5.0,
6.0,
7.0,
8.0,
9.0,
10.0,
11.0,
12.0,
13.0,
14.0,
15.0,
16.0,
17.0,
18.0,
19.0,
20.0,
21.0,
22.0,
23.0,
24.0,
25.0,
],
"power_values": [
263388.0,
751154.0,
1440738.0,
2355734.0,
3506858.0,
4993092.0,
6849310.0,
9116402.0,
10000754.0,
10009590.0,
10000942.0,
10042678.0,
10003480.0,
10001600.0,
10001506.0,
10013632.0,
10007428.0,
10005360.0,
10002728.0,
10001130.0,
10004984.0,
9997558.0,
],
},
"Ct_curve": {
"Ct_wind_speeds": [
4.0,
5.0,
6.0,
7.0,
8.0,
9.0,
10.0,
11.0,
12.0,
13.0,
14.0,
15.0,
16.0,
17.0,
18.0,
19.0,
20.0,
21.0,
22.0,
23.0,
24.0,
25.0,
],
"Ct_values": [
0.923,
0.919,
0.904,
0.858,
0.814,
0.814,
0.814,
0.814,
0.577,
0.419,
0.323,
0.259,
0.211,
0.175,
0.148,
0.126,
0.109,
0.095,
0.084,
0.074,
0.066,
0.059,
],
},
},
}

# 3 turbines in a row, ~7D spacing (7 * 178.3 = 1248.1)
_LAYOUT_X = [0, 1248.1, 2496.2]
_LAYOUT_Y = [0, 0, 0]

# Jensen wake model, minimal analysis config
_ANALYSIS = {
"wind_deficit_model": {
"name": "Jensen",
"wake_expansion_coefficient": {"k_a": 0.0, "k_b": 0.04},
},
"deflection_model": {"name": "None"},
"turbulence_model": {"name": "STF2005", "c1": 1.0, "c2": 1.0},
"superposition_model": {
"ws_superposition": "Linear",
"ti_superposition": "Squared",
},
"rotor_averaging": {"name": "Center"},
"blockage_model": {"name": "None"},
}


def make_timeseries_per_turbine_system_dict(flow_model_name):
"""Build a complete system dict with per-turbine timeseries data including density.

3 turbines, 6 timesteps, all variables have dims ["time", "wind_turbine"].
"""
n_times = 6
n_turbines = 3

# fmt: off
ws_data = [
[9.0, 8.5, 9.2],
[10.0, 9.8, 10.5],
[7.5, 7.2, 7.8],
[8.0, 7.6, 8.3],
[11.0, 10.8, 11.2],
[9.5, 9.0, 9.8],
]
wd_data = [
[270.0, 269.5, 270.5],
[268.0, 267.5, 268.8],
[272.0, 271.0, 272.5],
[270.5, 270.0, 271.0],
[269.0, 268.5, 269.5],
[271.0, 270.5, 271.5],
]
ti_data = [
[0.06, 0.07, 0.05],
[0.08, 0.09, 0.07],
[0.05, 0.06, 0.05],
[0.07, 0.08, 0.06],
[0.10, 0.09, 0.08],
[0.06, 0.07, 0.06],
]
# Turbine 0 off at timesteps 2-3
operating_data = [
[1, 1, 1],
[1, 1, 1],
[0, 1, 1],
[0, 1, 1],
[1, 1, 1],
[1, 1, 1],
]
density_data = [
[1.225, 1.223, 1.227],
[1.220, 1.218, 1.222],
[1.230, 1.228, 1.232],
[1.228, 1.226, 1.230],
[1.218, 1.220, 1.222],
[1.235, 1.233, 1.230],
]
# fmt: on

return {
"name": "Dict test: timeseries per-turbine with density",
"site": {
"name": "Test site",
"boundaries": {
"polygons": [{"x": [-90, 2600, 2600, -90], "y": [90, 90, -90, -90]}]
},
"energy_resource": {
"name": "Test resource",
"wind_resource": {
"time": list(range(n_times)),
"wind_turbine": list(range(n_turbines)),
"wind_speed": {
"data": ws_data,
"dims": ["time", "wind_turbine"],
},
"wind_direction": {
"data": wd_data,
"dims": ["time", "wind_turbine"],
},
"turbulence_intensity": {
"data": ti_data,
"dims": ["time", "wind_turbine"],
},
"operating": {
"data": operating_data,
"dims": ["time", "wind_turbine"],
},
"density": {
"data": density_data,
"dims": ["time", "wind_turbine"],
},
},
},
},
"wind_farm": {
"name": "Test farm",
"layouts": [{"coordinates": {"x": _LAYOUT_X, "y": _LAYOUT_Y}}],
"turbines": _TURBINE,
},
"attributes": {
"flow_model": {"name": flow_model_name},
"analysis": _ANALYSIS,
"model_outputs_specification": {
"turbine_outputs": {
"turbine_nc_filename": "turbine_data.nc",
"output_variables": ["power"],
},
},
},
}
31 changes: 31 additions & 0 deletions tests/test_foxes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from pathlib import Path
from shutil import rmtree

import numpy as np
from windIO import __path__ as wiop
from windIO import validate as validate_yaml

Expand Down Expand Up @@ -81,6 +82,35 @@ def test_foxes_timeseries_with_operating_flag():
_run_foxes(wes_dir)


def test_timeseries_per_turbine_with_density(tmp_path=Path(".")):
import foxes.variables as FV
from conftest import make_timeseries_per_turbine_system_dict

# Run with density
system_dict = make_timeseries_per_turbine_system_dict("foxes")
output_dir = tmp_path / "output_foxes_ts"
farm_results = run_foxes(system_dict, verbosity=0, output_dir=str(output_dir))[0]
farmP_with = farm_results[FV.P].sum()
# print("Farm power with density:", farmP_with)
assert np.isfinite(farmP_with) and farmP_with > 0

# Run without density — same config but density removed
system_dict_no = make_timeseries_per_turbine_system_dict("foxes")
del system_dict_no["site"]["energy_resource"]["wind_resource"]["density"]
output_dir_no = tmp_path / "output_foxes_ts_no_density"
farm_results_no = run_foxes(
system_dict_no, verbosity=0, output_dir=str(output_dir_no)
)[0]
farmP_without = farm_results_no[FV.P].sum()
# print("Farm power without density:", farmP_without)

rmtree(output_dir)
rmtree(output_dir_no)

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


if __name__ == "__main__":
test_foxes_KUL()
test_foxes_4wts()
Expand All @@ -90,3 +120,4 @@ def test_foxes_timeseries_with_operating_flag():
test_foxes_heterogeneous_wind_rose_at_turbines()
test_foxes_heterogeneous_wind_rose_map()
test_foxes_simple_wind_rose()
test_timeseries_per_turbine_with_density()