floris_design #7
@ -1,7 +1,9 @@
|
||||
import math
|
||||
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
|
||||
@ -10,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,
|
||||
@ -53,22 +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 = {}
|
||||
|
||||
self.reset_operation()
|
||||
for param in interest_plots:
|
||||
if param not in dct_functions:
|
||||
res[param] = "Not found"
|
||||
continue
|
||||
res[param] = dct_functions[param]()
|
||||
|
||||
horizontal_plane = self.calculate_horizontal_plane(height=90.0)
|
||||
visualize_cut_plane(
|
||||
horizontal_plane,
|
||||
)
|
||||
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, 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}",
|
||||
)
|
||||
|
||||
# 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
|
@ -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)
|
||||
|
@ -14,13 +14,15 @@ class SWeatherInfo(BaseModel):
|
||||
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
|
||||
data: list[float]
|
||||
file_name: object
|
||||
data: object
|
||||
|
||||
|
||||
class WindTurbineTypeBase(BaseModel):
|
||||
@ -108,4 +110,4 @@ class WindTurbineWithParkDetailsResponse(BaseModel):
|
||||
comment: Optional[str]
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
orm_mode = True
|
||||
|
@ -8,12 +8,14 @@ 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))
|
||||
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(
|
||||
@ -26,23 +28,20 @@ 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()
|
||||
|
||||
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,
|
||||
@ -52,14 +51,22 @@ 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()
|
||||
|
||||
data = fmodel.get_turbine_powers()[0].tolist()
|
||||
file_name = fmodel.visualisation()
|
||||
res = fmodel.get_turbine_powers().tolist()
|
||||
file_names = fmodel.visualization(data.plots)
|
||||
|
||||
return SFlorisOutputData(
|
||||
file_name=file_name,
|
||||
data=data
|
||||
file_name=file_names,
|
||||
data=res
|
||||
)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user