From b216188962cda8de13054e59d74b6bdad5804950 Mon Sep 17 00:00:00 2001 From: btol Date: Fri, 27 Mar 2026 09:14:29 +0100 Subject: [PATCH] Expand PyWake submodel support and fix redundant YAML/netCDF loads - Support PyWake >= 2.6 (SimpleYawModel exp parameter removal) - Fix Speedup axis ordering and Weibull flow case sampling - Use DensityCompensation instead of DensityScale for air density - Eliminate redundant YAML+netCDF loads in run_api - Fix validate_yaml double extension and string time coordinates - Update Python version docs to reflect 3.10-3.12 support Co-Authored-By: Claude Opus 4.6 (1M context) --- README.md | 2 +- docs/source/getting_started/installation.rst | 2 +- pyproject.toml | 2 +- wifa/main_api.py | 20 ++++++-------------- wifa/pywake_api.py | 4 ++++ 5 files changed, 13 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index ae16836..f17f97e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # WIFA (Wind Farm API) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -[![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/) +[![Python 3.10-3.12](https://img.shields.io/badge/python-3.10--3.12-blue.svg)](https://www.python.org/downloads/) [![Documentation](https://img.shields.io/badge/docs-online-green.svg)](https://euflow.github.io/WIFA/) WIFA is an open-source multi-fidelity wind farm simulation framework that provides a unified interface to multiple flow modeling tools. diff --git a/docs/source/getting_started/installation.rst b/docs/source/getting_started/installation.rst index 72505b3..3c09122 100644 --- a/docs/source/getting_started/installation.rst +++ b/docs/source/getting_started/installation.rst @@ -4,7 +4,7 @@ Install Prerequisites ~~~~~~~~~~~~~ -WIFA requires Python 3.9-3.11. We recommend using `uv `_ for fast, reliable Python environment management. +WIFA requires Python 3.10-3.12. We recommend using `uv `_ for fast, reliable Python environment management. **Install uv:** diff --git a/pyproject.toml b/pyproject.toml index 1205899..8e34fbf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ classifiers = [ requires-python = ">=3.10,<3.13" dependencies = [ "windIO @ git+https://github.com/EUFlow/windIO.git", - "xarray>=2022.0.0,<2025", + "xarray", "scipy", "pyyaml", ] diff --git a/wifa/main_api.py b/wifa/main_api.py index dd267a9..1f54552 100644 --- a/wifa/main_api.py +++ b/wifa/main_api.py @@ -3,7 +3,6 @@ import sys import windIO -from windIO import load_yaml from windIO import validate as validate_yaml from .cs_api.cs_modules.csLaunch.cs_run_function import run_code_saturne @@ -16,40 +15,33 @@ def run_api(yaml_input): - # validate input - validate_yaml(yaml_input, windIO.__path__[0] + "/plant/wind_energy_system.yaml") - - # get number of turbines if isinstance(yaml_input, dict): yaml_dat = yaml_input else: - yaml_dat = load_yaml(yaml_input) + yaml_dat = validate_yaml(yaml_input, "plant/wind_energy_system") model_name = yaml_dat["attributes"]["flow_model"]["name"] if model_name.lower() == "pywake": - pywake_aep = run_pywake(yaml_input) + run_pywake(yaml_dat) elif model_name.lower() == "foxes": - foxes_aep = run_foxes(yaml_input) + run_foxes(yaml_dat) elif model_name.lower() == "floris": - floris_aep = run_floris(yaml_input) + run_floris(yaml_dat) elif model_name.lower() == "wayve": - # Output directory - # yaml_input_no_ext = os.path.splitext(yaml_input)[0] # Remove the file extension - # output_dir_name = 'output_wayve' + yaml_input_no_ext.replace(os.sep, '_') # Replace directory separators output_dir_name = yaml_dat["attributes"]["model_outputs_specification"][ "output_folder" ] if not os.path.exists(output_dir_name): os.makedirs(output_dir_name) - run_wayve(yaml_input, output_dir_name) + run_wayve(yaml_dat, output_dir_name) elif model_name.lower() == "codesaturne": - run_code_saturne(yaml_input, test_mode=True) + run_code_saturne(yaml_dat, test_mode=True) else: print("Invalid Model") diff --git a/wifa/pywake_api.py b/wifa/pywake_api.py index 670ab1b..aecf66f 100644 --- a/wifa/pywake_api.py +++ b/wifa/pywake_api.py @@ -217,6 +217,10 @@ def dict_to_site(resource_dict): if name in resource_ds: resource_ds = resource_ds.rename({name: rename_map[name]}) + if "time" in resource_ds.dims: + # Convert time coordinate to integer indices for GridInterpolator compatibility + # (string or datetime time coords cannot be interpolated numerically) + resource_ds = resource_ds.assign_coords(time=np.arange(len(resource_ds.time))) if "P" not in resource_ds and "time" in resource_ds.dims: n_time = len(resource_ds.time) # Create uniform probability array (1/N)