Change architecture, Main functionality, Little practise HTML template
This commit is contained in:
parent
20379f8d37
commit
6e8ec4f0f1
@ -1,8 +1,22 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module type="PYTHON_MODULE" version="4">
|
<module type="PYTHON_MODULE" version="4">
|
||||||
<component name="NewModuleRootManager">
|
<component name="NewModuleRootManager">
|
||||||
<content url="file://$MODULE_DIR$" />
|
<content url="file://$MODULE_DIR$">
|
||||||
<orderEntry type="inheritedJdk" />
|
<sourceFolder url="file://$MODULE_DIR$/server/floris_module/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/server/src" isTestSource="false" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/server/floris_module/.venv" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="jdk" jdkName="Python 3.12 (EvaluationEfficiencyOptimizationWind)" jdkType="Python SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" name="bootstrap" level="application" />
|
||||||
|
<orderEntry type="library" name="@popperjs/core" level="application" />
|
||||||
|
</component>
|
||||||
|
<component name="TemplatesService">
|
||||||
|
<option name="TEMPLATE_CONFIGURATION" value="Jinja2" />
|
||||||
|
<option name="TEMPLATE_FOLDERS">
|
||||||
|
<list>
|
||||||
|
<option value="$MODULE_DIR$/server/src/templates" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
@ -1,4 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9" project-jdk-type="Python SDK" />
|
<component name="Black">
|
||||||
|
<option name="sdkName" value="Python 3.12 (EvaluationEfficiencyOptimizationWind) (2)" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 (EvaluationEfficiencyOptimizationWind)" project-jdk-type="Python SDK" />
|
||||||
</project>
|
</project>
|
6
.idea/other.xml
Normal file
6
.idea/other.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="PySciProjectComponent">
|
||||||
|
<option name="PY_INTERACTIVE_PLOTS_SUGGESTED" value="true" />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -5,7 +5,7 @@ import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin';
|
|||||||
const __dirname = path.resolve();
|
const __dirname = path.resolve();
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
entry: './src/index.tsx',
|
entry: './routers/index.tsx',
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, 'dist'),
|
path: path.resolve(__dirname, 'dist'),
|
||||||
filename: 'main.js',
|
filename: 'main.js',
|
||||||
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
@ -1,4 +1,14 @@
|
|||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
import uuid
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from floris import FlorisModel
|
from floris import FlorisModel
|
||||||
|
from floris.flow_visualization import visualize_cut_plane
|
||||||
|
from floris.layout_visualization import plot_turbine_labels
|
||||||
|
import floris.layout_visualization as layoutviz
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
|
|
||||||
_wind_direction_to_val: dict[str, float] = {
|
_wind_direction_to_val: dict[str, float] = {
|
||||||
@ -31,13 +41,34 @@ def _check_wind_direction_definition(wind_direction: str) -> bool:
|
|||||||
|
|
||||||
|
|
||||||
class FlorisULSTU(FlorisModel):
|
class FlorisULSTU(FlorisModel):
|
||||||
def __init__(self, url_yaml):
|
def __init__(
|
||||||
|
self,
|
||||||
|
url_yaml: Path = Path(__file__).parent / "gch.yaml"
|
||||||
|
):
|
||||||
super().__init__(url_yaml)
|
super().__init__(url_yaml)
|
||||||
|
|
||||||
def set(self, **kwargs):
|
def set(self, **kwargs):
|
||||||
if ("wind_directions" in kwargs) and (kwargs["wind_directions"] is list[str]):
|
if ("wind_directions" in kwargs) and (type(kwargs["wind_directions"][0]) is str):
|
||||||
kwargs["wind_directions"] = _convert_winds_list_direction_definitions(kwargs["wind_directions"])
|
kwargs["wind_directions"] = _convert_winds_list_direction_definitions(kwargs["wind_directions"])
|
||||||
|
|
||||||
super().set(**kwargs)
|
super().set(**kwargs)
|
||||||
|
|
||||||
|
def visualisation(self):
|
||||||
|
|
||||||
|
|
||||||
|
self.reset_operation()
|
||||||
|
|
||||||
|
horizontal_plane = self.calculate_horizontal_plane(height=90.0)
|
||||||
|
visualize_cut_plane(
|
||||||
|
horizontal_plane,
|
||||||
|
)
|
||||||
|
|
||||||
|
# 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()
|
||||||
|
|
||||||
|
return filename
|
||||||
|
|
||||||
|
|
||||||
|
|
3
server/floris_module/src/__init__.py
Normal file
3
server/floris_module/src/__init__.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from .FlorisULSTU import FlorisULSTU
|
||||||
|
|
||||||
|
__all__ = ['FlorisULSTU']
|
@ -149,9 +149,9 @@ flow_field:
|
|||||||
wake:
|
wake:
|
||||||
|
|
||||||
###
|
###
|
||||||
# Select the models to use for the simulation.
|
# Select the data to use for the simulation.
|
||||||
# See :py:mod:`~.wake` for a list
|
# See :py:mod:`~.wake` for a list
|
||||||
# of available models and their descriptions.
|
# of available data and their descriptions.
|
||||||
model_strings:
|
model_strings:
|
||||||
|
|
||||||
###
|
###
|
||||||
@ -190,7 +190,7 @@ wake:
|
|||||||
# Configure the parameters for the wake deflection model
|
# Configure the parameters for the wake deflection model
|
||||||
# selected above.
|
# selected above.
|
||||||
# Additional blocks can be provided for
|
# Additional blocks can be provided for
|
||||||
# models that are not enabled, but the enabled model
|
# data that are not enabled, but the enabled model
|
||||||
# must have a corresponding parameter block.
|
# must have a corresponding parameter block.
|
||||||
wake_deflection_parameters:
|
wake_deflection_parameters:
|
||||||
gauss:
|
gauss:
|
||||||
@ -210,7 +210,7 @@ wake:
|
|||||||
# Configure the parameters for the wake velocity deficit model
|
# Configure the parameters for the wake velocity deficit model
|
||||||
# selected above.
|
# selected above.
|
||||||
# Additional blocks can be provided for
|
# Additional blocks can be provided for
|
||||||
# models that are not enabled, but the enabled model
|
# data that are not enabled, but the enabled model
|
||||||
# must have a corresponding parameter block.
|
# must have a corresponding parameter block.
|
||||||
wake_velocity_parameters:
|
wake_velocity_parameters:
|
||||||
cc:
|
cc:
|
||||||
@ -234,7 +234,7 @@ wake:
|
|||||||
# Configure the parameters for the wake turbulence model
|
# Configure the parameters for the wake turbulence model
|
||||||
# selected above.
|
# selected above.
|
||||||
# Additional blocks can be provided for
|
# Additional blocks can be provided for
|
||||||
# models that are not enabled, but the enabled model
|
# data that are not enabled, but the enabled model
|
||||||
# must have a corresponding parameter block.
|
# must have a corresponding parameter block.
|
||||||
wake_turbulence_parameters:
|
wake_turbulence_parameters:
|
||||||
crespo_hernandez:
|
crespo_hernandez:
|
@ -1,58 +0,0 @@
|
|||||||
from fastapi import FastAPI, Depends, Request
|
|
||||||
from fastapi.responses import RedirectResponse, HTMLResponse
|
|
||||||
from sqlalchemy.orm import Session
|
|
||||||
from sqlalchemy.future import select
|
|
||||||
from database import SessionLocal, User, Base, engine
|
|
||||||
from fastapi.templating import Jinja2Templates
|
|
||||||
from fastapi.staticfiles import StaticFiles
|
|
||||||
|
|
||||||
from src.floris_router import router as floris_router
|
|
||||||
from src.floris_router import get_images
|
|
||||||
|
|
||||||
Base.metadata.create_all(bind=engine)
|
|
||||||
|
|
||||||
app = FastAPI()
|
|
||||||
templates = Jinja2Templates(directory="templates")
|
|
||||||
|
|
||||||
app.mount("/static", StaticFiles(directory="static"), name="static")
|
|
||||||
app.mount("/public", StaticFiles(directory="public"), name="public")
|
|
||||||
|
|
||||||
app.include_router(floris_router)
|
|
||||||
|
|
||||||
|
|
||||||
def get_db():
|
|
||||||
db = SessionLocal()
|
|
||||||
try:
|
|
||||||
yield db
|
|
||||||
finally:
|
|
||||||
db.close()
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/hello")
|
|
||||||
async def hello():
|
|
||||||
return {"message": "Hello, World!"}
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
|
||||||
async def redirect_to_docs():
|
|
||||||
return RedirectResponse(url="/docs")
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/users")
|
|
||||||
def read_users(db: Session = Depends(get_db)):
|
|
||||||
result = db.execute(select(User))
|
|
||||||
users = result.scalars().all() # Получаем всех пользователей
|
|
||||||
return users
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/main", response_class=HTMLResponse)
|
|
||||||
async def main(request: Request):
|
|
||||||
params = {"request": request}
|
|
||||||
params.update(await get_images())
|
|
||||||
|
|
||||||
return templates.TemplateResponse("main.html", params)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import uvicorn
|
|
||||||
uvicorn.run(app, host="localhost", port=8080) # Изменено на localhost
|
|
Binary file not shown.
Before Width: | Height: | Size: 30 KiB |
11
server/src/data/database.py
Normal file
11
server/src/data/database.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
from sqlalchemy import create_engine
|
||||||
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
|
||||||
|
# TODO Maybe create env file
|
||||||
|
DATABASE_URL = "mysql+pymysql://wind:wind@193.124.203.110:3306/wind_towers"
|
||||||
|
|
||||||
|
engine = create_engine(DATABASE_URL)
|
||||||
|
session_maker = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,28 +1,15 @@
|
|||||||
from sqlalchemy import create_engine, Column, Integer, String
|
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
|
||||||
from sqlalchemy.orm import sessionmaker, Mapped, mapped_column
|
|
||||||
from sqlalchemy.dialects.mysql import TIMESTAMP, TIME, VARCHAR
|
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
DATABASE_URL = "mysql+pymysql://wind:wind@193.124.203.110:3306/wind_towers"
|
from sqlalchemy.orm import Mapped, mapped_column, DeclarativeBase
|
||||||
|
from sqlalchemy.dialects.mysql import TIMESTAMP, TIME, VARCHAR
|
||||||
engine = create_engine(DATABASE_URL)
|
|
||||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
|
||||||
|
|
||||||
|
|
||||||
Base = declarative_base()
|
class Base(DeclarativeBase):
|
||||||
|
pass
|
||||||
|
|
||||||
class User(Base):
|
|
||||||
__tablename__ = "user" # Убедитесь, что эта таблица существует
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
|
||||||
name = Column(String(50), index=True)
|
|
||||||
|
|
||||||
|
|
||||||
class Weather(Base):
|
class Weather(Base):
|
||||||
__tablename__ = "weather"
|
__tablename__ = "weather_data"
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
BarTrend: Mapped[str] = mapped_column(VARCHAR(255))
|
BarTrend: Mapped[str] = mapped_column(VARCHAR(255))
|
||||||
@ -46,3 +33,4 @@ class Weather(Base):
|
|||||||
WindDir: Mapped[str] = mapped_column(VARCHAR(50))
|
WindDir: Mapped[str] = mapped_column(VARCHAR(50))
|
||||||
WindSpeed: Mapped[float]
|
WindSpeed: Mapped[float]
|
||||||
WindSpeed10Min: Mapped[float]
|
WindSpeed10Min: Mapped[float]
|
||||||
|
|
27
server/src/data/repository.py
Normal file
27
server/src/data/repository.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
from sqlalchemy import select
|
||||||
|
|
||||||
|
from .database import session_maker
|
||||||
|
from .models import Weather
|
||||||
|
from .schemas import SWeatherInfo
|
||||||
|
|
||||||
|
|
||||||
|
class WeatherRepository:
|
||||||
|
@classmethod
|
||||||
|
def get_all(cls):
|
||||||
|
with session_maker() as session:
|
||||||
|
query = (
|
||||||
|
select(Weather)
|
||||||
|
)
|
||||||
|
res = session.execute(query)
|
||||||
|
weather_models = res.scalars().all()
|
||||||
|
return [SWeatherInfo.model_validate(weather, from_attributes=True) for weather in weather_models]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_by_id(cls, id):
|
||||||
|
with session_maker() as session:
|
||||||
|
query = (
|
||||||
|
select(Weather).where(Weather.id == id)
|
||||||
|
)
|
||||||
|
res = session.execute(query)
|
||||||
|
weather_model = res.scalars().first()
|
||||||
|
return SWeatherInfo.model_validate(weather_model, from_attributes=True)
|
19
server/src/data/schemas.py
Normal file
19
server/src/data/schemas.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
from pydantic import BaseModel, Field
|
||||||
|
from fastapi import Query
|
||||||
|
|
||||||
|
|
||||||
|
class SWeatherInfo(BaseModel):
|
||||||
|
id: int
|
||||||
|
WindDir: str
|
||||||
|
WindSpeed: float
|
||||||
|
|
||||||
|
|
||||||
|
class SFlorisInputParams(BaseModel):
|
||||||
|
weather_id: int
|
||||||
|
layout_x: list[float] = Field(Query([]))
|
||||||
|
layout_y: list[float] = Field(Query([]))
|
||||||
|
|
||||||
|
|
||||||
|
class SFlorisOutputData(BaseModel):
|
||||||
|
file_name: str
|
||||||
|
data: list[float]
|
@ -1,36 +0,0 @@
|
|||||||
from pathlib import Path
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException
|
|
||||||
from fastapi.responses import FileResponse
|
|
||||||
|
|
||||||
|
|
||||||
STATIC_DIR = Path("public/floris")
|
|
||||||
|
|
||||||
router = APIRouter(
|
|
||||||
prefix="/floris",
|
|
||||||
tags=["Static Files from Floris"],
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/get_images")
|
|
||||||
async def get_images():
|
|
||||||
try:
|
|
||||||
images = [file.name for file in STATIC_DIR.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 = STATIC_DIR / 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)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
22
server/src/main.py
Normal file
22
server/src/main.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
from fastapi.staticfiles import StaticFiles
|
||||||
|
|
||||||
|
from routers.floris_router import router as floris_router
|
||||||
|
from routers.floris_template_router import router as floris_template_router
|
||||||
|
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
app.mount("/static", StaticFiles(directory=Path("../static")), name="static")
|
||||||
|
app.mount("/public", StaticFiles(directory=Path("../public")), name="public")
|
||||||
|
|
||||||
|
app.include_router(floris_router)
|
||||||
|
app.include_router(floris_template_router)
|
||||||
|
|
||||||
|
|
||||||
|
# if __name__ == "__main__":
|
||||||
|
# import uvicorn
|
||||||
|
# uvicorn.run(app, host="localhost", port=8080) # Изменено на localhost
|
@ -1 +0,0 @@
|
|||||||
st
|
|
73
server/src/routers/floris_router.py
Normal file
73
server/src/routers/floris_router.py
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
from http import HTTPStatus
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Annotated
|
||||||
|
|
||||||
|
from fastapi import APIRouter, HTTPException, Depends
|
||||||
|
from fastapi.responses import FileResponse
|
||||||
|
|
||||||
|
from data.repository import WeatherRepository
|
||||||
|
from data.schemas import SFlorisInputParams, SFlorisOutputData, SWeatherInfo
|
||||||
|
|
||||||
|
from FlorisULSTU import FlorisULSTU
|
||||||
|
|
||||||
|
FLORIS_IMAGES_PATH = Path("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):
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=HTTPStatus.BAD_REQUEST,
|
||||||
|
detail="Length of layout x and y must be the same",
|
||||||
|
)
|
||||||
|
|
||||||
|
atmosphere_param: SWeatherInfo = WeatherRepository().get_by_id(data.weather_id)
|
||||||
|
|
||||||
|
fmodel = FlorisULSTU()
|
||||||
|
fmodel.set(
|
||||||
|
layout_x=data.layout_x,
|
||||||
|
layout_y=data.layout_y,
|
||||||
|
wind_directions=[atmosphere_param.WindDir],
|
||||||
|
wind_speeds=[atmosphere_param.WindSpeed],
|
||||||
|
)
|
||||||
|
fmodel.run()
|
||||||
|
|
||||||
|
data = fmodel.get_turbine_powers()[0].tolist()
|
||||||
|
file_name = fmodel.visualisation()
|
||||||
|
|
||||||
|
return SFlorisOutputData(
|
||||||
|
file_name=file_name,
|
||||||
|
data=data
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@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)
|
||||||
|
|
||||||
|
|
||||||
|
|
65
server/src/routers/floris_template_router.py
Normal file
65
server/src/routers/floris_template_router.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
from typing import Annotated
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Request, Form, Depends
|
||||||
|
from fastapi.responses import HTMLResponse
|
||||||
|
from fastapi.templating import Jinja2Templates
|
||||||
|
|
||||||
|
from data.repository import WeatherRepository
|
||||||
|
from data.schemas import SFlorisInputParams
|
||||||
|
|
||||||
|
from routers.floris_router import get_windmill_data
|
||||||
|
|
||||||
|
templates = Jinja2Templates(directory=Path("../templates/floris_templates"))
|
||||||
|
|
||||||
|
router = APIRouter(
|
||||||
|
prefix="",
|
||||||
|
tags=["floris_template"],
|
||||||
|
include_in_schema=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/", response_class=HTMLResponse)
|
||||||
|
async def get_main(request: Request, context: dict | None = None):
|
||||||
|
if context is None:
|
||||||
|
context = {}
|
||||||
|
|
||||||
|
params = {"request": request, "weather": WeatherRepository.get_all()}
|
||||||
|
|
||||||
|
if context is not None:
|
||||||
|
params.update(context)
|
||||||
|
|
||||||
|
return templates.TemplateResponse("main.html", params)
|
||||||
|
|
||||||
|
|
||||||
|
def transform_windmill_data(
|
||||||
|
options: Annotated[str, Form()],
|
||||||
|
x: Annotated[str, Form()],
|
||||||
|
y: Annotated[str, Form()]
|
||||||
|
) -> SFlorisInputParams | None:
|
||||||
|
|
||||||
|
if not all([options, x, y]):
|
||||||
|
return None
|
||||||
|
|
||||||
|
return SFlorisInputParams(
|
||||||
|
weather_id=int(options),
|
||||||
|
layout_x=list(map(float, x.split())),
|
||||||
|
layout_y=list(map(float, y.split())),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/", response_class=HTMLResponse)
|
||||||
|
async def post_main(
|
||||||
|
request: Request,
|
||||||
|
windmill_params: Annotated[SFlorisInputParams | None, Depends(transform_windmill_data)] = None,
|
||||||
|
):
|
||||||
|
if windmill_params is None:
|
||||||
|
return await get_main(request)
|
||||||
|
|
||||||
|
data = await get_windmill_data(windmill_params)
|
||||||
|
context = {
|
||||||
|
'data': data.data,
|
||||||
|
'file_name': data.file_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
return await get_main(request, context)
|
85
server/templates/floris_templates/main.html
Normal file
85
server/templates/floris_templates/main.html
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Image Viewer</title>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.1/css/bootstrap.min.css" integrity="sha512-T584yQ/tdRR5QwOpfvDfVQUidzfgc2339Lc8uBDtcp/wYu80d7jwBgAxbyMh0a9YM9F8N3tdErpFI8iaGx6x5g==" crossorigin="anonymous" referrerpolicy="no-referrer">
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.1/js/bootstrap.min.js" integrity="sha512-UR25UO94eTnCVwjbXozyeVd6ZqpaAE9naiEUBK/A+QDbfSTQFhPGj5lOR6d8tsgbBk84Ggb5A3EkjsOgPRPcKA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="row m-5">
|
||||||
|
<form class="col" method="post">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<div class="btn-group" data-toggle="buttons">
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">#</th>
|
||||||
|
<th scope="col">Wind Direction</th>
|
||||||
|
<th scope="col">Wind Speed</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
{% for row in weather %}
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<label class="btn btn-outline-primary">{{ row.id }}
|
||||||
|
<input type="radio" class="btn-check"
|
||||||
|
name="options" id="option_{{ row.id }}" value="{{ row.id }}" autocomplete="off">
|
||||||
|
</label>
|
||||||
|
</th>
|
||||||
|
<td>{{ row.WindDir }}</td>
|
||||||
|
<td>{{ row.WindSpeed }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<div class="input-group flex-nowrap">
|
||||||
|
<span class="input-group-text" id="addon-wrapping">X</span>
|
||||||
|
<input name="x" type="text" class="form-control" placeholder="X axis" aria-label="X axis" aria-describedby="addon-wrapping">
|
||||||
|
</div>
|
||||||
|
<div class="input-group flex-nowrap">
|
||||||
|
<span class="input-group-text" id="addon-wrapping">Y</span>
|
||||||
|
<input name="y" type="text" class="form-control" placeholder="Y axis" aria-label="Y axis" aria-describedby="addon-wrapping">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary w-100">Submit</button>
|
||||||
|
</form>
|
||||||
|
<div class="col">
|
||||||
|
{{ data }}
|
||||||
|
{% if data is defined %}
|
||||||
|
<img id="display-image" src="/public/floris/{{ file_name }}" alt="Selected Image">
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function selectImage(imageName) {
|
||||||
|
const imgElement = document.getElementById('display-image');
|
||||||
|
imgElement.src = `/public/floris/${imageName}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateImage() {
|
||||||
|
alert("Image generation functionality not implemented yet.");
|
||||||
|
}
|
||||||
|
|
||||||
|
function downloadImage() {
|
||||||
|
const imgElement = document.getElementById('display-image');
|
||||||
|
const imageName = imgElement.src.split('/').pop();
|
||||||
|
window.location.href = `/floris/download_image/${imageName}`;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@ -1,43 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Image Viewer</title>
|
|
||||||
<link rel="stylesheet" href="/static/style.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<div class="image-viewer">
|
|
||||||
<img id="display-image" src="/public/floris/Yaw_example.png" alt="Selected Image">
|
|
||||||
<button onclick="generateImage()">Generate Image</button>
|
|
||||||
<button onclick="downloadImage()">Download Image</button>
|
|
||||||
</div>
|
|
||||||
<div class="image-list">
|
|
||||||
<h3>Available Images</h3>
|
|
||||||
<ul id="image-list">
|
|
||||||
{% for image in images %}
|
|
||||||
<li onclick="selectImage('{{ image }}')">{{ image }}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function selectImage(imageName) {
|
|
||||||
const imgElement = document.getElementById('display-image');
|
|
||||||
imgElement.src = `/public/floris/${imageName}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateImage() {
|
|
||||||
alert("Image generation functionality not implemented yet.");
|
|
||||||
}
|
|
||||||
|
|
||||||
function downloadImage() {
|
|
||||||
const imgElement = document.getElementById('display-image');
|
|
||||||
const imageName = imgElement.src.split('/').pop();
|
|
||||||
window.location.href = `/floris/download_image/${imageName}`;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Loading…
Reference in New Issue
Block a user