From 7db293de96302ddd78c4e43729be499096baf8a2 Mon Sep 17 00:00:00 2001 From: shadowik Date: Mon, 4 Nov 2024 01:59:43 +0400 Subject: [PATCH 1/3] Add multiple charts for wind turbines --- server/floris_module/src/FlorisULSTU.py | 23 +++++++++++++++------ server/floris_module/src/OpenMeteoClient.py | 12 +++++------ server/src/data/schemas.py | 3 +-- server/src/routers/floris_router.py | 15 ++++++-------- 4 files changed, 30 insertions(+), 23 deletions(-) diff --git a/server/floris_module/src/FlorisULSTU.py b/server/floris_module/src/FlorisULSTU.py index d0971ac..9010471 100644 --- a/server/floris_module/src/FlorisULSTU.py +++ b/server/floris_module/src/FlorisULSTU.py @@ -1,3 +1,4 @@ +import math import os.path import sys import uuid @@ -54,14 +55,24 @@ class FlorisULSTU(FlorisModel): super().set(**kwargs) def visualisation(self): + wind_dirs = self.core.flow_field.wind_directions + wind_speeds = self.core.flow_field.wind_speeds + experiment_counts = len(wind_dirs) + near_square = math.ceil(math.sqrt(experiment_counts)) + fig, axarr = plt.subplots(near_square, near_square, figsize=(15,8)) + axarr = axarr.flatten() - self.reset_operation() - - horizontal_plane = self.calculate_horizontal_plane(height=90.0) - visualize_cut_plane( - horizontal_plane, - ) + for experiment_count in range(experiment_counts): + self.reset_operation() + self.set(wind_speeds=[wind_speeds[0]], wind_directions=[wind_dirs[0]], turbulence_intensities=[0.05]) + ax = axarr[experiment_count] + horizontal_plane = self.calculate_horizontal_plane(height=90.0) + visualize_cut_plane( + horizontal_plane, + ax=ax, + title=f"Wind flow day {experiment_count + 1}", + ) # plot_turbine_labels(self, axarr[0, 0]) filename = str(uuid.uuid4()) + ".png" diff --git a/server/floris_module/src/OpenMeteoClient.py b/server/floris_module/src/OpenMeteoClient.py index deddd5d..9a9a5c4 100644 --- a/server/floris_module/src/OpenMeteoClient.py +++ b/server/floris_module/src/OpenMeteoClient.py @@ -17,7 +17,7 @@ class OpenMeteoClient: params = { "latitude": latitude, "longitude": longitude, - "hourly": ["wind_speed_10m", "wind_direction_10m"], + "daily": ["wind_speed_10m_max", "wind_direction_10m_dominant"], "timezone": self.timezone, "start_date": start_date, "end_date": end_date @@ -27,13 +27,13 @@ class OpenMeteoClient: def process_response(self, response): # Process hourly data - hourly = response.Hourly() - hourly_wind_speed_10m = hourly.Variables(0).ValuesAsNumpy() - hourly_wind_direction_10m = hourly.Variables(1).ValuesAsNumpy() + daily = response.Daily() + daily_wind_speed_10m = daily.Variables(0).ValuesAsNumpy() + daily_wind_direction_10m = daily.Variables(1).ValuesAsNumpy() - return hourly_wind_speed_10m.tolist(), hourly_wind_direction_10m.tolist() + return daily_wind_speed_10m.tolist(), daily_wind_direction_10m.tolist() - def get_weather_info(self, latitude, longitude, start_date, end_date): + def get_weather_info(self, start_date, end_date, latitude=54.35119762746125, longitude=48.389356992149345): responses = self.fetch_weather_data(latitude, longitude, start_date, end_date) response = responses[0] self.process_response(response) diff --git a/server/src/data/schemas.py b/server/src/data/schemas.py index 6558a9d..f7efa37 100644 --- a/server/src/data/schemas.py +++ b/server/src/data/schemas.py @@ -1,5 +1,4 @@ from datetime import date - from pydantic import BaseModel, Field from fastapi import Query @@ -19,4 +18,4 @@ class SFlorisInputParams(BaseModel): class SFlorisOutputData(BaseModel): file_name: str - data: list[float] \ No newline at end of file + data: object \ No newline at end of file diff --git a/server/src/routers/floris_router.py b/server/src/routers/floris_router.py index ddccce5..6abd3e4 100644 --- a/server/src/routers/floris_router.py +++ b/server/src/routers/floris_router.py @@ -14,6 +14,7 @@ sys.path.append(str(Path(__file__).parent.parent.parent)) from floris_module.src import FlorisULSTU from floris_module.src.OpenMeteoClient import OpenMeteoClient + FLORIS_IMAGES_PATH = Path(__file__).parent.parent.parent / "public" / "floris" router = APIRouter( @@ -36,13 +37,9 @@ async def get_windmill_data( client = OpenMeteoClient() - wind_directions = list() - wind_speeds = list() - - for i in range(len(data.layout_x)): - i_result = client.get_weather_info(data.layout_x[i], data.layout_y[i], data.date_start, data.date_end) - wind_speeds.extend(i_result[0]) - wind_directions.extend(i_result[1]) + climate_info = client.get_weather_info(data.date_start, data.date_end) + wind_speeds = climate_info[0] + wind_directions = climate_info[1] fmodel.set( layout_x=data.layout_x, @@ -54,12 +51,12 @@ async def get_windmill_data( fmodel.run() - data = fmodel.get_turbine_powers()[0].tolist() + res = fmodel.get_turbine_powers().tolist() file_name = fmodel.visualisation() return SFlorisOutputData( file_name=file_name, - data=data + data=res ) From 7cdbd654327894173015eb4e6501c9bc3319420d Mon Sep 17 00:00:00 2001 From: shadowik Date: Mon, 4 Nov 2024 02:24:15 +0400 Subject: [PATCH 2/3] Yaw angles and fix --- server/floris_module/src/FlorisULSTU.py | 3 ++- server/src/data/schemas.py | 1 + server/src/routers/floris_router.py | 14 ++++++++++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/server/floris_module/src/FlorisULSTU.py b/server/floris_module/src/FlorisULSTU.py index 9010471..92604cd 100644 --- a/server/floris_module/src/FlorisULSTU.py +++ b/server/floris_module/src/FlorisULSTU.py @@ -65,7 +65,8 @@ class FlorisULSTU(FlorisModel): for experiment_count in range(experiment_counts): self.reset_operation() - self.set(wind_speeds=[wind_speeds[0]], wind_directions=[wind_dirs[0]], turbulence_intensities=[0.05]) + self.set(wind_speeds=[wind_speeds[experiment_count]], wind_directions=[wind_dirs[experiment_count]], + turbulence_intensities=[0.05]) ax = axarr[experiment_count] horizontal_plane = self.calculate_horizontal_plane(height=90.0) visualize_cut_plane( diff --git a/server/src/data/schemas.py b/server/src/data/schemas.py index f7efa37..a096654 100644 --- a/server/src/data/schemas.py +++ b/server/src/data/schemas.py @@ -12,6 +12,7 @@ class SWeatherInfo(BaseModel): class SFlorisInputParams(BaseModel): layout_x: list[float] = Field(Query([])) layout_y: list[float] = Field(Query([])) + yaw_angle: list[float] = Field(Query([])) date_start: date date_end: date diff --git a/server/src/routers/floris_router.py b/server/src/routers/floris_router.py index 6abd3e4..cd5ea16 100644 --- a/server/src/routers/floris_router.py +++ b/server/src/routers/floris_router.py @@ -8,6 +8,7 @@ from fastapi.responses import FileResponse from data.repository import WeatherRepository from data.schemas import SFlorisInputParams, SFlorisOutputData, SWeatherInfo +import numpy as np sys.path.append(str(Path(__file__).parent.parent.parent)) @@ -27,12 +28,13 @@ router = APIRouter( async def get_windmill_data( data: Annotated[SFlorisInputParams, Depends()] ): - if len(data.layout_x) != len(data.layout_y): + if len(data.layout_x) != len(data.layout_y) and len(data.layout_x) != len(data.yaw_angle): raise HTTPException( status_code=HTTPStatus.BAD_REQUEST, - detail="Length of layout x and y must be the same", + detail="Length of layout x and y and yaw_angle must be the same", ) + fmodel = FlorisULSTU() client = OpenMeteoClient() @@ -49,6 +51,14 @@ async def get_windmill_data( turbulence_intensities=[0.1] * len(wind_directions) ) + yaw_angles = np.zeros((len(wind_directions), len(data.layout_x))) + for i in range(len(data.layout_x)): + yaw_angles[:, i] = data.yaw_angle[i] + + fmodel.set( + yaw_angles=yaw_angles, + ) + fmodel.run() res = fmodel.get_turbine_powers().tolist() From dee27b731bc20a60404954fc8cc02508b8b9f390 Mon Sep 17 00:00:00 2001 From: shadowik Date: Tue, 5 Nov 2024 02:04:46 +0400 Subject: [PATCH 3/3] New type of plots --- server/floris_module/src/FlorisULSTU.py | 73 ++++++++++++++++++++++--- server/src/data/schemas.py | 3 +- server/src/routers/floris_router.py | 4 +- 3 files changed, 69 insertions(+), 11 deletions(-) diff --git a/server/floris_module/src/FlorisULSTU.py b/server/floris_module/src/FlorisULSTU.py index 92604cd..7883d97 100644 --- a/server/floris_module/src/FlorisULSTU.py +++ b/server/floris_module/src/FlorisULSTU.py @@ -3,6 +3,7 @@ import os.path import sys import uuid from pathlib import Path +from typing import Set from floris import FlorisModel from floris.flow_visualization import visualize_cut_plane @@ -11,7 +12,6 @@ import floris.layout_visualization as layoutviz import matplotlib.pyplot as plt - _wind_direction_to_val: dict[str, float] = { "N": 0.0, "E": 90.0, @@ -54,33 +54,90 @@ class FlorisULSTU(FlorisModel): super().set(**kwargs) - def visualisation(self): + def visualization( + self, + interest_plots: Set[str] + ): + dct_functions = { + "horizontal_plane": self._horizontal_plane_visualization, + "vertical_plane": self._vertical_plane_visualization, + } + + res = {} + + for param in interest_plots: + if param not in dct_functions: + res[param] = "Not found" + continue + res[param] = dct_functions[param]() + + return res + + def _horizontal_plane_visualization(self): + return self._plane_visualization(self.calculate_horizontal_plane, {"height": 90.0}) + + def _vertical_plane_visualization(self): + return self._plane_visualization(self.calculate_y_plane, + {"crossstream_dist": 0.0, + "x_resolution": 200, + "z_resolution": 100}) + + def _plane_visualization(self, plane_func, func_params: dict[str, float] = {}): wind_dirs = self.core.flow_field.wind_directions wind_speeds = self.core.flow_field.wind_speeds experiment_counts = len(wind_dirs) near_square = math.ceil(math.sqrt(experiment_counts)) - fig, axarr = plt.subplots(near_square, near_square, figsize=(15,8)) - axarr = axarr.flatten() + fig, ax_arr = plt.subplots(near_square, near_square, figsize=(15, 8)) + ax_arr = ax_arr.flatten() for experiment_count in range(experiment_counts): self.reset_operation() self.set(wind_speeds=[wind_speeds[experiment_count]], wind_directions=[wind_dirs[experiment_count]], turbulence_intensities=[0.05]) - ax = axarr[experiment_count] - horizontal_plane = self.calculate_horizontal_plane(height=90.0) + ax = ax_arr[experiment_count] + plane = plane_func(**func_params) visualize_cut_plane( - horizontal_plane, + plane, ax=ax, title=f"Wind flow day {experiment_count + 1}", ) - # plot_turbine_labels(self, axarr[0, 0]) filename = str(uuid.uuid4()) + ".png" plt.savefig(Path(__file__).parent.parent.parent / f"public/floris/{filename}") plt.close() + self.set(wind_speeds=wind_speeds, wind_directions=wind_dirs, turbulence_intensities=[0.05] * len(wind_dirs)) + return filename + def _cross_visualization(self, plane_func, func_params: dict[str, float] = {}): + wind_dirs = self.core.flow_field.wind_directions + wind_speeds = self.core.flow_field.wind_speeds + + experiment_counts = len(wind_dirs) + near_square = math.ceil(math.sqrt(experiment_counts)) + fig, ax_arr = plt.subplots(near_square, near_square, figsize=(15, 8)) + ax_arr = ax_arr.flatten() + + for experiment_count in range(experiment_counts): + self.reset_operation() + self.set(wind_speeds=[wind_speeds[experiment_count]], wind_directions=[wind_dirs[experiment_count]], + turbulence_intensities=[0.05]) + ax = ax_arr[experiment_count] + plane = plane_func(**func_params) + visualize_cut_plane( + plane, + ax=ax, + title=f"Wind flow day {experiment_count + 1}", + ) + + filename = str(uuid.uuid4()) + ".png" + plt.savefig(Path(__file__).parent.parent.parent / f"public/floris/{filename}") + plt.close() + + self.set(wind_speeds=wind_speeds, wind_directions=wind_dirs, turbulence_intensities=[0.05] * len(wind_dirs)) + + return filename \ No newline at end of file diff --git a/server/src/data/schemas.py b/server/src/data/schemas.py index a096654..9a8b958 100644 --- a/server/src/data/schemas.py +++ b/server/src/data/schemas.py @@ -13,10 +13,11 @@ class SFlorisInputParams(BaseModel): layout_x: list[float] = Field(Query([])) layout_y: list[float] = Field(Query([])) yaw_angle: list[float] = Field(Query([])) + plots: set[str] = Field(Query(["horizontal_plane"])) date_start: date date_end: date class SFlorisOutputData(BaseModel): - file_name: str + file_name: object data: object \ No newline at end of file diff --git a/server/src/routers/floris_router.py b/server/src/routers/floris_router.py index cd5ea16..cb68762 100644 --- a/server/src/routers/floris_router.py +++ b/server/src/routers/floris_router.py @@ -62,10 +62,10 @@ async def get_windmill_data( fmodel.run() res = fmodel.get_turbine_powers().tolist() - file_name = fmodel.visualisation() + file_names = fmodel.visualization(data.plots) return SFlorisOutputData( - file_name=file_name, + file_name=file_names, data=res )