216 lines
6.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import math
import sys
from http import HTTPStatus
from pathlib import Path
from typing import Annotated
from fastapi import APIRouter, HTTPException, Depends
from fastapi.responses import FileResponse
from sqlalchemy.orm import Session
from data.repository import WeatherRepository, WindParkRepository
from data.schemas import SFlorisInputParams, SFlorisOutputData, SFlorisInputParamsForWindPark
from data.database import get_db
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(
prefix="/api/floris",
tags=["Floris Api"],
)
@router.get("/get_windmill_data")
async def get_windmill_data(
data: Annotated[SFlorisInputParams, Depends()]
):
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 and yaw_angle must be the same",
)
fmodel = FlorisULSTU()
client = OpenMeteoClient()
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,
layout_y=data.layout_y,
wind_directions=wind_directions,
wind_speeds=wind_speeds,
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()
file_names = fmodel.visualization(data.plots)
return SFlorisOutputData(
file_name=file_names,
data=res
)
@router.get("/get_images")
async def get_images():
try:
images = [file.name for file in FLORIS_IMAGES_PATH.iterdir() if file.is_file()]
return {"images": images}
except Exception as e:
raise HTTPException(
status_code=500,
detail=str(e)
)
@router.get("/download_image/{image_name}")
async def download_image(
image_name: str
):
image_path = FLORIS_IMAGES_PATH / image_name
if not image_path.exists() or not image_path.is_file():
raise HTTPException(status_code=404, detail="Image not found")
return FileResponse(image_path, media_type="image/jpeg", filename=image_name)
@router.get("/get_windmill_data/{park_id}", response_model=SFlorisOutputData)
async def get_windmill_data_by_wind_park(
park_id: int,
data: Annotated[SFlorisInputParamsForWindPark, Depends()],
db: Session = Depends(get_db)
):
fmodel = FlorisULSTU()
client = OpenMeteoClient()
park = WindParkRepository.get(db, park_id)
turbines = WindParkRepository.get_turbines_by_park_id(park_id, db)
turbine_coordinates = [
get_new_coordinates(park.CenterLatitude, park.CenterLongitude, turbine.x_offset, turbine.y_offset)
for turbine in turbines
]
turbine_yaw_angles = [turbine.angle for turbine in turbines]
weather_info_list = [
client.get_weather_info(start_date=data.date_start, end_date=data.date_end, latitude=lat, longitude=lon)
for lat, lon in turbine_coordinates
]
park_centerX, park_centerY = get_absolute_coordinates(park.CenterLatitude, park.CenterLongitude)
turbineX = [
park_centerX + turbine.x_offset
for turbine in turbines
]
turbineY = [
park_centerY + turbine.y_offset
for turbine in turbines
]
wind_speeds = np.array([item[0][0] for item in weather_info_list])
wind_directions = np.array([item[1][0] for item in weather_info_list])
print(wind_directions)
fmodel.set(
layout_x=turbineX,
layout_y=turbineY,
wind_directions=wind_directions,
wind_speeds=wind_speeds,
turbulence_intensities=[0.1] * len(wind_directions)
)
yaw_angles = np.zeros((len(wind_directions), len(turbineX)))
for i in range(len(turbineX)):
yaw_angles[:, i] = turbine_yaw_angles[i]
fmodel.set(
yaw_angles=yaw_angles,
)
fmodel.run()
res = fmodel.get_turbine_powers().tolist()
file_names = fmodel.visualization(data.plots)
return SFlorisOutputData(
file_name=file_names,
data=res
)
def get_new_coordinates(lat, lon, dx, dy):
"""
Вычисляет новую широту и долготу, исходя из заданной точки и смещения по осям x и y.
:param lat: Широта исходной точки (в градусах)
:param lon: Долгота исходной точки (в градусах)
:param dx: Смещение по оси X (в метрах)
:param dy: Смещение по оси Y (в метрах)
:return: (новая_широта, новая_долгота)
"""
# Радиус Земли (в метрах)
R = 6378137 # Средний радиус Земли
# Преобразуем широту из градусов в радианы
lat_rad = math.radians(lat)
# Вычисляем смещение в градусах
dlat = dy / R * (180 / math.pi) # Смещение широты
dlon = dx / (R * math.cos(lat_rad)) * (180 / math.pi) # Смещение долготы
# Вычисляем новые координаты
new_lat = lat + dlat
new_lon = lon + dlon
return new_lat, new_lon
def get_absolute_coordinates(lat, lon):
"""
Конвертирует широту и долготу в абсолютные координаты (x, y) в метрах.
:param lat: Широта точки (в градусах)
:param lon: Долгота точки (в градусах)
:return: Абсолютные координаты (x, y) в метрах
"""
# Радиус Земли в метрах
R = 6378137
# Преобразуем широту и долготу из градусов в радианы
lat_rad = math.radians(lat)
lon_rad = math.radians(lon)
# Вычисляем координату y (по широте)
y = R * lat_rad # в метрах
# Вычисляем координату x (по долготе)
x = R * math.cos(lat_rad) * lon_rad # в метрах
return x, y