From d36adf55f1782f1f2b71e52ef9bbfd0c4158c58c Mon Sep 17 00:00:00 2001 From: shadowik Date: Mon, 14 Oct 2024 17:54:58 +0400 Subject: [PATCH 01/10] Initial Commit + Hardcode Example --- floris_module/__init__.py | 0 floris_module/src/gch.yaml | 244 +++++++++++++++++++++++++++++++++++++ floris_module/src/main.py | 83 +++++++++++++ 3 files changed, 327 insertions(+) create mode 100644 floris_module/__init__.py create mode 100644 floris_module/src/gch.yaml create mode 100644 floris_module/src/main.py diff --git a/floris_module/__init__.py b/floris_module/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/floris_module/src/gch.yaml b/floris_module/src/gch.yaml new file mode 100644 index 0000000..5c0ea8e --- /dev/null +++ b/floris_module/src/gch.yaml @@ -0,0 +1,244 @@ + +### +# A name for this input file. +# This is not currently only for the user's reference. +name: GCH + +### +# A description of the contents of this input file. +# This is not currently only for the user's reference. +description: Three turbines using Gauss Curl Hybrid model + +### +# The earliest verion of FLORIS this input file supports. +# This is not currently only for the user's reference. +floris_version: v4 + +### +# Configure the logging level and where to show the logs. +logging: + + ### + # Settings for logging to the console (i.e. terminal). + console: + + ### + # Can be "true" or "false". + enable: true + + ### + # Set the severity to show output. Messages at this level or higher will be shown. + # Can be one of "CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG". + level: WARNING + + ### + # Settings for logging to a file. + file: + + ### + # Can be "true" or "false". + enable: false + + ### + # Set the severity to show output. Messages at this level or higher will be shown. + # Can be one of "CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG". + level: WARNING + +### +# Configure the solver for the type of simulation. +solver: + + ### + # Select the solver type. + # Can be one of: "turbine_grid", "flow_field_grid", "flow_field_planar_grid". + type: turbine_grid + + ### + # Options for the turbine type selected above. See the solver documentation for available parameters. + turbine_grid_points: 3 + +### +# Configure the turbine types and their placement within the wind farm. +farm: + + ### + # Coordinates for the turbine locations in the x-direction which is typically considered + # to be the streamwise direction (left, right) when the wind is out of the west. + # The order of the coordinates here corresponds to the index of the turbine in the primary + # data structures. + layout_x: + - 0.0 + - 630.0 + - 1260.0 + + ### + # Coordinates for the turbine locations in the y-direction which is typically considered + # to be the spanwise direction (up, down) when the wind is out of the west. + # The order of the coordinates here corresponds to the index of the turbine in the primary + # data structures. + layout_y: + - 0.0 + - 0.0 + - 0.0 + + ### + # Listing of turbine types for placement at the x and y coordinates given above. + # The list length must be 1 or the same as ``layout_x`` and ``layout_y``. If it is a + # single value, all turbines are of the same type. Otherwise, the turbine type + # is mapped to the location at the same index in ``layout_x`` and ``layout_y``. + # The types can be either a name included in the turbine_library or + # a full definition of a wind turbine directly. + turbine_type: + - nrel_5MW + +### +# Configure the atmospheric conditions. +flow_field: + + ### + # Air density. + air_density: 1.225 + + ### + # The height to consider the "center" of the vertical wind speed profile + # due to shear. With a shear exponent not 1, the wind speed at this height + # will be the value given in ``wind_speeds``. Above and below this height, + # the wind speed will change according to the shear profile; see + # :py:meth:`.FlowField.initialize_velocity_field`. + # For farms consisting of one wind turbine type, use ``reference_wind_height: -1`` + # to use the hub height of the wind turbine definition. For multiple wind turbine + # types, the reference wind height must be given explicitly. + reference_wind_height: -1 + + ### + # The turbulence intensities to include in the simulation, specified as a decimal. + turbulence_intensities: + - 0.06 + + ### + # The wind directions to include in the simulation. + # 0 is north and 270 is west. + wind_directions: + - 270.0 + + ### + # The exponent used to model the wind shear profile; see + # :py:meth:`.FlowField.initialize_velocity_field`. + wind_shear: 0.12 + + ### + # The wind speeds to include in the simulation. + wind_speeds: + - 8.0 + + ### + # The wind veer as a constant value for all points in the grid. + wind_veer: 0.0 + + ### + # The conditions that are specified for use with the multi-dimensional Cp/Ct capbility. + # These conditions are external to FLORIS and specified by the user. They are used internally + # through a nearest-neighbor selection process to choose the correct Cp/Ct interpolants + # to use. + multidim_conditions: + Tp: 2.5 + Hs: 3.01 + +### +# Configure the wake model. +wake: + + ### + # Select the models to use for the simulation. + # See :py:mod:`~.wake` for a list + # of available models and their descriptions. + model_strings: + + ### + # Select the wake combination model. + combination_model: sosfs + + ### + # Select the wake deflection model. + deflection_model: gauss + + ### + # Select the wake turbulence model. + turbulence_model: crespo_hernandez + + ### + # Select the wake velocity deficit model. + velocity_model: gauss + + ### + # Can be "true" or "false". + enable_secondary_steering: true + + ### + # Can be "true" or "false". + enable_yaw_added_recovery: true + + ### + # Can be "true" or "false". + enable_active_wake_mixing: false + + ### + # Can be "true" or "false". + enable_transverse_velocities: true + + ### + # Configure the parameters for the wake deflection model + # selected above. + # Additional blocks can be provided for + # models that are not enabled, but the enabled model + # must have a corresponding parameter block. + wake_deflection_parameters: + gauss: + ad: 0.0 + alpha: 0.58 + bd: 0.0 + beta: 0.077 + dm: 1.0 + ka: 0.38 + kb: 0.004 + jimenez: + ad: 0.0 + bd: 0.0 + kd: 0.05 + + ### + # Configure the parameters for the wake velocity deficit model + # selected above. + # Additional blocks can be provided for + # models that are not enabled, but the enabled model + # must have a corresponding parameter block. + wake_velocity_parameters: + cc: + a_s: 0.179367259 + b_s: 0.0118889215 + c_s1: 0.0563691592 + c_s2: 0.13290157 + a_f: 3.11 + b_f: -0.68 + c_f: 2.41 + alpha_mod: 1.0 + gauss: + alpha: 0.58 + beta: 0.077 + ka: 0.38 + kb: 0.004 + jensen: + we: 0.05 + + ### + # Configure the parameters for the wake turbulence model + # selected above. + # Additional blocks can be provided for + # models that are not enabled, but the enabled model + # must have a corresponding parameter block. + wake_turbulence_parameters: + crespo_hernandez: + initial: 0.1 + constant: 0.5 + ai: 0.8 + downstream: -0.32 diff --git a/floris_module/src/main.py b/floris_module/src/main.py new file mode 100644 index 0000000..2160707 --- /dev/null +++ b/floris_module/src/main.py @@ -0,0 +1,83 @@ +import matplotlib.pyplot as plt +import numpy as np + +import floris.layout_visualization as layoutviz +from floris import FlorisModel +from floris.flow_visualization import visualize_cut_plane + + +# Create the plotting objects using matplotlib +fig, axarr = plt.subplots(3, 3, figsize=(16, 10), sharex=False) +axarr = axarr.flatten() + +MIN_WS = 1.0 +MAX_WS = 8.0 + +# Initialize FLORIS with the given input file. +fmodel = FlorisModel("./gch.yaml") + +# Change to 5-turbine layout with a wind direction from northwest +fmodel.set( + layout_x=[0, 0, 1000, 1000, 1000], layout_y=[0, 500, 0, 500, 1000], wind_directions=[300] +) + +# Plot 1: Visualize the flow +ax = axarr[0] +# Plot a horizatonal slice of the initial configuration +horizontal_plane = fmodel.calculate_horizontal_plane(height=90.0) +visualize_cut_plane( + horizontal_plane, + ax=ax, + min_speed=MIN_WS, + max_speed=MAX_WS, +) +# Plot the turbine points, setting the color to white +layoutviz.plot_turbine_points(fmodel, ax=ax, plotting_dict={"color": "w"}) +ax.set_title("Flow visualization and turbine points") + +# Plot 2: Show a particular flow case +ax = axarr[1] +turbine_names = [f"T{i}" for i in [10, 11, 12, 13, 22]] +layoutviz.plot_turbine_points(fmodel, ax=ax) +layoutviz.plot_turbine_labels( + fmodel, ax=ax, turbine_names=turbine_names, show_bbox=True, bbox_dict={"facecolor": "r"} +) +ax.set_title("Show turbine names with a red bounding box") + + +# Plot 2: Show turbine rotors on flow +ax = axarr[2] +fmodel.set(yaw_angles=np.array([[0., 30., 0., 0., 0.]])) +horizontal_plane = fmodel.calculate_horizontal_plane(height=90.0) +visualize_cut_plane(horizontal_plane, ax=ax, min_speed=MIN_WS, max_speed=MAX_WS) +layoutviz.plot_turbine_rotors(fmodel, ax=ax, yaw_angles=np.array([[0.0, 30.0, 0.0, 0.0, 0.0]])) +ax.set_title("Flow visualization with yawed turbine") + +# Plot 3: Show the layout, including wake directions +ax = axarr[3] +layoutviz.plot_turbine_points(fmodel, ax=ax) +layoutviz.plot_turbine_labels(fmodel, ax=ax, turbine_names=turbine_names) +layoutviz.plot_waking_directions(fmodel, ax=ax) +ax.set_title("Show turbine names and wake direction") + +# Plot 4: Plot a subset of the layout, and limit directions less than 7D +ax = axarr[4] +layoutviz.plot_turbine_points(fmodel, ax=ax, turbine_indices=[0, 1, 2, 3]) +layoutviz.plot_turbine_labels( + fmodel, ax=ax, turbine_names=turbine_names, turbine_indices=[0, 1, 2, 3] +) +layoutviz.plot_waking_directions(fmodel, ax=ax, turbine_indices=[0, 1, 2, 3], limit_dist_D=7) +ax.set_title("Plot a subset and limit wake line distance") + +# Plot with a shaded region +ax = axarr[5] +layoutviz.plot_turbine_points(fmodel, ax=ax) +layoutviz.shade_region(np.array([[0, 0], [300, 0], [300, 1000], [0, 700]]), ax=ax) +ax.set_title("Plot with a shaded region") + +# Change hub heights and plot as a proxy for terrain +ax = axarr[6] +fmodel.core.farm.hub_heights = np.array([110, 90, 100, 100, 95]) +layoutviz.plot_farm_terrain(fmodel, ax=ax) + +plt.show() \ No newline at end of file From 5e9df306e18e95364ec535546febaa06aba5998a Mon Sep 17 00:00:00 2001 From: shadowik Date: Mon, 14 Oct 2024 19:07:37 +0400 Subject: [PATCH 02/10] Create little docs --- floris_module/NOTES.md | 46 +++++++++++++++++++++++++++++ floris_module/docs/Yaw_example.png | Bin 0 -> 30675 bytes 2 files changed, 46 insertions(+) create mode 100644 floris_module/NOTES.md create mode 100644 floris_module/docs/Yaw_example.png diff --git a/floris_module/NOTES.md b/floris_module/NOTES.md new file mode 100644 index 0000000..9a03ec4 --- /dev/null +++ b/floris_module/NOTES.md @@ -0,0 +1,46 @@ +# Заметки по Floris + +## Описание +Здесь я буду описывать общую информацию для всех, +чтобы остальным не копать глубоко как пользоваться библиотекой + + +## Инициализация и концепты библиотеки + +1) Для работы Floris **требуется** специальный конфигурационный yaml файл. +В нем хранятся базовые данные о ветряках - их расположения, сила ветра и тому подобное. +Базовое его содержимое не так важно, так как впоследствии их можно будет изменить напрямую в процессе работы программы +(Буду постепенно искать интересующие нас параметры) + +2) Для инициализации используется класс `FlorisModel(yaml_path)` в библиотеке Floris. Объявляем переменную этим классом, +и передаем в него путь к нашему Yaml файлу +[Пример](https://nrel.github.io/floris/intro_concepts.html#build-the-model) + +3) Для изменения параметров заданных в yaml файле, используется метод set +[Пример](https://nrel.github.io/floris/intro_concepts.html#run-the-floris-wake-calculation) + +4) Запуск симуляции происходит с помощью ```fmodel.run()``` +[Пример](https://nrel.github.io/floris/intro_concepts.html#run-the-floris-wake-calculation) + +5) Получаем мощность турбин с помощью ```fmodel.get_turbine_powers()``` в ваттах в виде массива Numpy. +[Пример](https://nrel.github.io/floris/intro_concepts.html#get-turbine-power) + +6) Для каждого ветряка можно задать Yaw угол (Что такое Yaw угол показано на картинке) +[Пример](https://nrel.github.io/floris/intro_concepts.html#applying-yaw-angles) + +![Yaw_example.png](docs/Yaw_example.png) + + + + +## Параметры +1) farm - Общие настройки расположения турбин (Кол-во элементов, задает кол-во ветряков. Можно поставить 1 элемент, +в таком случае данные у всех ветряков будут одинаковые) + 1) layout_x - Список float координат турбин по оси X + 2) layout_y - Список float координат турбин по оси Y + 3) turbine_type - Список типов турбин +2) flow_field - Общие настройки атмосферных параметров (Кол-во элементов, задает кол-во экспериментов) + 1) wind_directions - Список float Направление ветра в градусах (при этом север принимается за 0° или 360°, + восток – за 90°, юг – за 180°, а запад – за 270°) + 2) turbulence_intensities - Список float силы? ветряков + 3) wind_speeds - Cписок скорости ветра (Наверное в м/с) \ No newline at end of file diff --git a/floris_module/docs/Yaw_example.png b/floris_module/docs/Yaw_example.png new file mode 100644 index 0000000000000000000000000000000000000000..7b4d7b59ba75762e616e39bed540c3f9ea73b361 GIT binary patch literal 30675 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 Date: Mon, 14 Oct 2024 19:09:44 +0400 Subject: [PATCH 03/10] Add gitignore and requirements.txt --- floris_module/.gitignore | 241 +++++++++++++++++++++++++++++++++ floris_module/requirements.txt | 22 +++ 2 files changed, 263 insertions(+) create mode 100644 floris_module/.gitignore create mode 100644 floris_module/requirements.txt diff --git a/floris_module/.gitignore b/floris_module/.gitignore new file mode 100644 index 0000000..2d62eb2 --- /dev/null +++ b/floris_module/.gitignore @@ -0,0 +1,241 @@ +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + diff --git a/floris_module/requirements.txt b/floris_module/requirements.txt new file mode 100644 index 0000000..6a93f4f --- /dev/null +++ b/floris_module/requirements.txt @@ -0,0 +1,22 @@ +attrs==24.2.0 +coloredlogs==15.0.1 +contourpy==1.3.0 +cycler==0.12.1 +FLORIS==4.1.1 +fonttools==4.54.1 +humanfriendly==10.0 +kiwisolver==1.4.7 +matplotlib==3.9.2 +numexpr==2.10.1 +numpy==1.26.4 +packaging==24.1 +pandas==2.2.3 +pillow==10.4.0 +pyparsing==3.2.0 +python-dateutil==2.9.0.post0 +pytz==2024.2 +PyYAML==6.0.2 +scipy==1.14.1 +shapely==2.0.6 +six==1.16.0 +tzdata==2024.2 From e0d114346a928140a9a34f79a5cad329bb89b6e1 Mon Sep 17 00:00:00 2001 From: shadowik Date: Tue, 15 Oct 2024 01:02:57 +0400 Subject: [PATCH 04/10] Interactive example --- floris_module/src/FlorisULSTU.py | 43 +++++++++++ floris_module/{ => src}/__init__.py | 0 floris_module/src/main.py | 114 +++++++++++----------------- 3 files changed, 86 insertions(+), 71 deletions(-) create mode 100644 floris_module/src/FlorisULSTU.py rename floris_module/{ => src}/__init__.py (100%) diff --git a/floris_module/src/FlorisULSTU.py b/floris_module/src/FlorisULSTU.py new file mode 100644 index 0000000..405a632 --- /dev/null +++ b/floris_module/src/FlorisULSTU.py @@ -0,0 +1,43 @@ +from floris import FlorisModel + + +_wind_direction_to_val: dict[str, float] = { + "N": 0.0, + "E": 90.0, + "S": 180.0, + "W": 270.0, +} + + +def _convert_winds_list_direction_definitions( + wind_directions: list[str], +) -> list[float]: + return list(map(lambda x: _convert_wind_direction_definition(x.upper()), wind_directions)) + + +def _convert_wind_direction_definition( + wind_direction: str +) -> float: + if not _check_wind_direction_definition(wind_direction): + raise ValueError(f"Wind direction {wind_direction} is not valid") + + return sum(map(lambda x: _wind_direction_to_val[x], wind_direction)) / len(wind_direction) + + +def _check_wind_direction_definition(wind_direction: str) -> bool: + if len(set(wind_direction) | set(_wind_direction_to_val)) > len(_wind_direction_to_val): + return False + return True + + +class FlorisULSTU(FlorisModel): + def __init__(self, url_yaml): + super().__init__(url_yaml) + + def set(self, **kwargs): + if ("wind_directions" in kwargs) and (kwargs["wind_directions"] is list[str]): + kwargs["wind_directions"] = _convert_winds_list_direction_definitions(kwargs["wind_directions"]) + + super().set(**kwargs) + + diff --git a/floris_module/__init__.py b/floris_module/src/__init__.py similarity index 100% rename from floris_module/__init__.py rename to floris_module/src/__init__.py diff --git a/floris_module/src/main.py b/floris_module/src/main.py index 2160707..51d8e1e 100644 --- a/floris_module/src/main.py +++ b/floris_module/src/main.py @@ -1,83 +1,55 @@ -import matplotlib.pyplot as plt import numpy as np +import matplotlib.pyplot as plt -import floris.layout_visualization as layoutviz -from floris import FlorisModel -from floris.flow_visualization import visualize_cut_plane +from FlorisULSTU import FlorisULSTU -# Create the plotting objects using matplotlib -fig, axarr = plt.subplots(3, 3, figsize=(16, 10), sharex=False) -axarr = axarr.flatten() -MIN_WS = 1.0 -MAX_WS = 8.0 - -# Initialize FLORIS with the given input file. -fmodel = FlorisModel("./gch.yaml") - -# Change to 5-turbine layout with a wind direction from northwest -fmodel.set( - layout_x=[0, 0, 1000, 1000, 1000], layout_y=[0, 500, 0, 500, 1000], wind_directions=[300] -) - -# Plot 1: Visualize the flow -ax = axarr[0] -# Plot a horizatonal slice of the initial configuration -horizontal_plane = fmodel.calculate_horizontal_plane(height=90.0) -visualize_cut_plane( - horizontal_plane, - ax=ax, - min_speed=MIN_WS, - max_speed=MAX_WS, -) -# Plot the turbine points, setting the color to white -layoutviz.plot_turbine_points(fmodel, ax=ax, plotting_dict={"color": "w"}) -ax.set_title("Flow visualization and turbine points") - -# Plot 2: Show a particular flow case -ax = axarr[1] -turbine_names = [f"T{i}" for i in [10, 11, 12, 13, 22]] -layoutviz.plot_turbine_points(fmodel, ax=ax) -layoutviz.plot_turbine_labels( - fmodel, ax=ax, turbine_names=turbine_names, show_bbox=True, bbox_dict={"facecolor": "r"} -) -ax.set_title("Show turbine names with a red bounding box") +# yaw_angles = np.zeros((4, 4)) +# print("Yaw angle array initialized with 0's") +# print(yaw_angles) +# +# print("First turbine yawed 25 degrees for every atmospheric condition") +# yaw_angles[:, 0] = 25 +# print(yaw_angles) +# +# fmodel.set(yaw_angles=yaw_angles) -# Plot 2: Show turbine rotors on flow -ax = axarr[2] -fmodel.set(yaw_angles=np.array([[0., 30., 0., 0., 0.]])) -horizontal_plane = fmodel.calculate_horizontal_plane(height=90.0) -visualize_cut_plane(horizontal_plane, ax=ax, min_speed=MIN_WS, max_speed=MAX_WS) -layoutviz.plot_turbine_rotors(fmodel, ax=ax, yaw_angles=np.array([[0.0, 30.0, 0.0, 0.0, 0.0]])) -ax.set_title("Flow visualization with yawed turbine") +if __name__ == "__main__": + fmodel = FlorisULSTU("gch.yaml") -# Plot 3: Show the layout, including wake directions -ax = axarr[3] -layoutviz.plot_turbine_points(fmodel, ax=ax) -layoutviz.plot_turbine_labels(fmodel, ax=ax, turbine_names=turbine_names) -layoutviz.plot_waking_directions(fmodel, ax=ax) -ax.set_title("Show turbine names and wake direction") + layout_x = list(map(float, input(f"Please enter x coordinates for turbines\n").split())) + layout_y = list(map(float, input(f"Please enter y coordinates for turbines\n").split())) -# Plot 4: Plot a subset of the layout, and limit directions less than 7D -ax = axarr[4] -layoutviz.plot_turbine_points(fmodel, ax=ax, turbine_indices=[0, 1, 2, 3]) -layoutviz.plot_turbine_labels( - fmodel, ax=ax, turbine_names=turbine_names, turbine_indices=[0, 1, 2, 3] -) -layoutviz.plot_waking_directions(fmodel, ax=ax, turbine_indices=[0, 1, 2, 3], limit_dist_D=7) -ax.set_title("Plot a subset and limit wake line distance") + fmodel.set( + layout_x=layout_x, layout_y=layout_y, + ) -# Plot with a shaded region -ax = axarr[5] -layoutviz.plot_turbine_points(fmodel, ax=ax) -layoutviz.shade_region(np.array([[0, 0], [300, 0], [300, 1000], [0, 700]]), ax=ax) -ax.set_title("Plot with a shaded region") + wind_directions = list(map(float, input(f"Please enter wind_directions for experiments\n").split())) + wind_speeds = list(map(float, input(f"Please enter wind_speed for experiments\n").split())) -# Change hub heights and plot as a proxy for terrain -ax = axarr[6] -fmodel.core.farm.hub_heights = np.array([110, 90, 100, 100, 95]) -layoutviz.plot_farm_terrain(fmodel, ax=ax) + fmodel.set( + wind_directions=wind_directions, wind_speeds=wind_speeds, turbulence_intensities=[0.1] * len(wind_directions), + ) + + fmodel.run() + + powers = fmodel.get_turbine_powers() / 1000.0 + + print("Dimensions of `powers`") + print(np.shape(powers)) + + N_TURBINES = fmodel.core.farm.n_turbines + + print() + print("Turbine powers for 8 m/s") + for i in range(2): + print(f"Wind condition {i}") + for j in range(N_TURBINES): + print(f" Turbine {j} - {powers[i, j]:7,.2f} kW") + print() + + print("Turbine powers for all turbines at all wind conditions") + print(powers) -plt.show() \ No newline at end of file From 1e6783b4761518535ce6257b76bf1f90a92981d7 Mon Sep 17 00:00:00 2001 From: shadowik Date: Tue, 15 Oct 2024 01:42:02 +0400 Subject: [PATCH 05/10] Create Weather Model + Update requirements.txt --- server/database.py | 31 ++++++++++++++++++++++++++++++- server/requirements.txt | 1 + 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/server/database.py b/server/database.py index 2776e93..861bddf 100644 --- a/server/database.py +++ b/server/database.py @@ -1,7 +1,9 @@ from sqlalchemy import create_engine, Column, Integer, String from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import sessionmaker +from sqlalchemy.orm import sessionmaker, Mapped, mapped_column +from sqlalchemy.dialects.mysql import TIMESTAMP, TIME, VARCHAR +from datetime import datetime DATABASE_URL = "mysql+pymysql://wind:wind@193.124.203.110:3306/wind_towers" @@ -19,3 +21,30 @@ class User(Base): id = Column(Integer, primary_key=True, index=True) name = Column(String(50), index=True) + + +class Weather(Base): + __tablename__ = "weather" + + id: Mapped[int] = mapped_column(primary_key=True) + BarTrend: Mapped[str] = mapped_column(VARCHAR(255)) + CRC: Mapped[str] = mapped_column(VARCHAR(255)) + DateStamp: Mapped[datetime] = mapped_column(TIMESTAMP) + DewPoint: Mapped[float] + HeatIndex: Mapped[float] + ETDay: Mapped[float] + HumIn: Mapped[float] + HumOut: Mapped[float] + Pressure: Mapped[float] + RainDay: Mapped[float] + RainMonth: Mapped[float] + RainRate: Mapped[float] + RainStorm: Mapped[float] + RainYear: Mapped[float] + SunRise: Mapped[datetime] = mapped_column(TIME) + SunSet:Mapped[datetime] = mapped_column(TIME) + TempIn: Mapped[float] + TempOut: Mapped[float] + WindDir: Mapped[str] = mapped_column(VARCHAR(50)) + WindSpeed: Mapped[float] + WindSpeed10Min: Mapped[float] diff --git a/server/requirements.txt b/server/requirements.txt index 5d438d4..8986ff1 100644 --- a/server/requirements.txt +++ b/server/requirements.txt @@ -24,6 +24,7 @@ PyYAML==6.0.2 rich==13.8.1 shellingham==1.5.4 sniffio==1.3.1 +SQLAlchemy==2.0.35 starlette==0.38.6 typer==0.12.5 typing_extensions==4.12.2 From 20379f8d37a952853f9ce39e396d36ed571e9f0d Mon Sep 17 00:00:00 2001 From: shadowik Date: Tue, 15 Oct 2024 02:33:16 +0400 Subject: [PATCH 06/10] Create Template for displaying Images --- server/database.py | 2 - server/main.py | 24 +++++++++- server/public/floris/Yaw_example.png | Bin 0 -> 30675 bytes server/src/floris_router.py | 36 ++++++++++++++ server/src/router.py | 1 + server/static/style.css | 67 +++++++++++++++++++++++++++ server/templates/main.html | 43 +++++++++++++++++ 7 files changed, 169 insertions(+), 4 deletions(-) create mode 100644 server/public/floris/Yaw_example.png create mode 100644 server/src/floris_router.py create mode 100644 server/static/style.css create mode 100644 server/templates/main.html diff --git a/server/database.py b/server/database.py index 861bddf..c6f5c78 100644 --- a/server/database.py +++ b/server/database.py @@ -7,8 +7,6 @@ from datetime import datetime DATABASE_URL = "mysql+pymysql://wind:wind@193.124.203.110:3306/wind_towers" - - engine = create_engine(DATABASE_URL) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) diff --git a/server/main.py b/server/main.py index afca163..d523ca6 100644 --- a/server/main.py +++ b/server/main.py @@ -1,13 +1,23 @@ -from fastapi import FastAPI, Depends -from fastapi.responses import RedirectResponse +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(): @@ -27,12 +37,22 @@ async def hello(): 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 diff --git a/server/public/floris/Yaw_example.png b/server/public/floris/Yaw_example.png new file mode 100644 index 0000000000000000000000000000000000000000..7b4d7b59ba75762e616e39bed540c3f9ea73b361 GIT binary patch literal 30675 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 + + + + + Image Viewer + + + +
+
+ Selected Image + + +
+
+

Available Images

+
    + {% for image in images %} +
  • {{ image }}
  • + {% endfor %} +
+
+
+ + + + From 6e8ec4f0f1c60393bd10adde2369e25719062ae4 Mon Sep 17 00:00:00 2001 From: shadowik Date: Wed, 16 Oct 2024 01:05:48 +0400 Subject: [PATCH 07/10] Change architecture, Main functionality, Little practise HTML template --- .../EvaluationEfficiencyOptimizationWind.iml | 18 +++- .idea/misc.xml | 5 +- .idea/other.xml | 6 ++ floris_module/src/__init__.py | 0 front/webpack.config.js | 2 +- .../floris_module}/.gitignore | 0 .../floris_module}/NOTES.md | 0 .../floris_module}/docs/Yaw_example.png | Bin .../floris_module}/requirements.txt | 0 .../floris_module}/src/FlorisULSTU.py | 35 +++++++- server/floris_module/src/__init__.py | 3 + .../floris_module}/src/gch.yaml | 10 +-- .../floris_module}/src/main.py | 0 server/main.py | 58 ------------ server/public/floris/Yaw_example.png | Bin 30675 -> 0 bytes server/src/data/database.py | 11 +++ server/{database.py => src/data/models.py} | 24 ++--- server/src/data/repository.py | 27 ++++++ server/src/data/schemas.py | 19 ++++ server/src/floris_router.py | 36 -------- server/src/main.py | 22 +++++ server/src/router.py | 1 - server/src/routers/floris_router.py | 73 +++++++++++++++ server/src/routers/floris_template_router.py | 65 ++++++++++++++ server/templates/floris_templates/main.html | 85 ++++++++++++++++++ server/templates/main.html | 43 --------- 26 files changed, 376 insertions(+), 167 deletions(-) create mode 100644 .idea/other.xml delete mode 100644 floris_module/src/__init__.py rename {floris_module => server/floris_module}/.gitignore (100%) rename {floris_module => server/floris_module}/NOTES.md (100%) rename {floris_module => server/floris_module}/docs/Yaw_example.png (100%) rename {floris_module => server/floris_module}/requirements.txt (100%) rename {floris_module => server/floris_module}/src/FlorisULSTU.py (54%) create mode 100644 server/floris_module/src/__init__.py rename {floris_module => server/floris_module}/src/gch.yaml (95%) rename {floris_module => server/floris_module}/src/main.py (100%) delete mode 100644 server/main.py delete mode 100644 server/public/floris/Yaw_example.png create mode 100644 server/src/data/database.py rename server/{database.py => src/data/models.py} (58%) create mode 100644 server/src/data/repository.py create mode 100644 server/src/data/schemas.py delete mode 100644 server/src/floris_router.py create mode 100644 server/src/main.py delete mode 100644 server/src/router.py create mode 100644 server/src/routers/floris_router.py create mode 100644 server/src/routers/floris_template_router.py create mode 100644 server/templates/floris_templates/main.html delete mode 100644 server/templates/main.html diff --git a/.idea/EvaluationEfficiencyOptimizationWind.iml b/.idea/EvaluationEfficiencyOptimizationWind.iml index d0876a7..32cf6f3 100644 --- a/.idea/EvaluationEfficiencyOptimizationWind.iml +++ b/.idea/EvaluationEfficiencyOptimizationWind.iml @@ -1,8 +1,22 @@ - - + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index d56657a..9af92d1 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,7 @@ - + + + \ No newline at end of file diff --git a/.idea/other.xml b/.idea/other.xml new file mode 100644 index 0000000..2e75c2e --- /dev/null +++ b/.idea/other.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/floris_module/src/__init__.py b/floris_module/src/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/front/webpack.config.js b/front/webpack.config.js index d840890..a40ac79 100644 --- a/front/webpack.config.js +++ b/front/webpack.config.js @@ -5,7 +5,7 @@ import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin'; const __dirname = path.resolve(); const config = { - entry: './src/index.tsx', + entry: './routers/index.tsx', output: { path: path.resolve(__dirname, 'dist'), filename: 'main.js', diff --git a/floris_module/.gitignore b/server/floris_module/.gitignore similarity index 100% rename from floris_module/.gitignore rename to server/floris_module/.gitignore diff --git a/floris_module/NOTES.md b/server/floris_module/NOTES.md similarity index 100% rename from floris_module/NOTES.md rename to server/floris_module/NOTES.md diff --git a/floris_module/docs/Yaw_example.png b/server/floris_module/docs/Yaw_example.png similarity index 100% rename from floris_module/docs/Yaw_example.png rename to server/floris_module/docs/Yaw_example.png diff --git a/floris_module/requirements.txt b/server/floris_module/requirements.txt similarity index 100% rename from floris_module/requirements.txt rename to server/floris_module/requirements.txt diff --git a/floris_module/src/FlorisULSTU.py b/server/floris_module/src/FlorisULSTU.py similarity index 54% rename from floris_module/src/FlorisULSTU.py rename to server/floris_module/src/FlorisULSTU.py index 405a632..d0971ac 100644 --- a/floris_module/src/FlorisULSTU.py +++ b/server/floris_module/src/FlorisULSTU.py @@ -1,4 +1,14 @@ +import os.path +import sys +import uuid +from pathlib import Path + 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] = { @@ -31,13 +41,34 @@ def _check_wind_direction_definition(wind_direction: str) -> bool: class FlorisULSTU(FlorisModel): - def __init__(self, url_yaml): + def __init__( + self, + url_yaml: Path = Path(__file__).parent / "gch.yaml" + ): super().__init__(url_yaml) 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"]) 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 + + diff --git a/server/floris_module/src/__init__.py b/server/floris_module/src/__init__.py new file mode 100644 index 0000000..4cc26c6 --- /dev/null +++ b/server/floris_module/src/__init__.py @@ -0,0 +1,3 @@ +from .FlorisULSTU import FlorisULSTU + +__all__ = ['FlorisULSTU'] \ No newline at end of file diff --git a/floris_module/src/gch.yaml b/server/floris_module/src/gch.yaml similarity index 95% rename from floris_module/src/gch.yaml rename to server/floris_module/src/gch.yaml index 5c0ea8e..01d727d 100644 --- a/floris_module/src/gch.yaml +++ b/server/floris_module/src/gch.yaml @@ -149,9 +149,9 @@ flow_field: wake: ### - # Select the models to use for the simulation. + # Select the data to use for the simulation. # See :py:mod:`~.wake` for a list - # of available models and their descriptions. + # of available data and their descriptions. model_strings: ### @@ -190,7 +190,7 @@ wake: # Configure the parameters for the wake deflection model # selected above. # 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. wake_deflection_parameters: gauss: @@ -210,7 +210,7 @@ wake: # Configure the parameters for the wake velocity deficit model # selected above. # 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. wake_velocity_parameters: cc: @@ -234,7 +234,7 @@ wake: # Configure the parameters for the wake turbulence model # selected above. # 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. wake_turbulence_parameters: crespo_hernandez: diff --git a/floris_module/src/main.py b/server/floris_module/src/main.py similarity index 100% rename from floris_module/src/main.py rename to server/floris_module/src/main.py diff --git a/server/main.py b/server/main.py deleted file mode 100644 index d523ca6..0000000 --- a/server/main.py +++ /dev/null @@ -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 diff --git a/server/public/floris/Yaw_example.png b/server/public/floris/Yaw_example.png deleted file mode 100644 index 7b4d7b59ba75762e616e39bed540c3f9ea73b361..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30675 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 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) diff --git a/server/templates/floris_templates/main.html b/server/templates/floris_templates/main.html new file mode 100644 index 0000000..9bc3c4b --- /dev/null +++ b/server/templates/floris_templates/main.html @@ -0,0 +1,85 @@ + + + + + + Image Viewer + + + + + + +
+
+
+
+
+ + + + + + + + + + + {% for row in weather %} + + + + + + {% endfor %} + +
#Wind DirectionWind Speed
+ + {{ row.WindDir }}{{ row.WindSpeed }}
+
+
+
+
+ X + +
+
+ Y + +
+
+
+ +
+
+ {{ data }} + {% if data is defined %} + Selected Image + {% endif %} +
+
+ + + + + + + diff --git a/server/templates/main.html b/server/templates/main.html deleted file mode 100644 index 01e50b9..0000000 --- a/server/templates/main.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - Image Viewer - - - -
-
- Selected Image - - -
-
-

Available Images

-
    - {% for image in images %} -
  • {{ image }}
  • - {% endfor %} -
-
-
- - - - From 61eb44b8fa1042d3b54e92e53bee56fc99184205 Mon Sep 17 00:00:00 2001 From: shadowik Date: Wed, 16 Oct 2024 01:09:32 +0400 Subject: [PATCH 08/10] Add public dir --- server/public/floris/git_init | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 server/public/floris/git_init diff --git a/server/public/floris/git_init b/server/public/floris/git_init new file mode 100644 index 0000000..e69de29 From 4f659b1149c7916e343e04cd3e357635e7655a96 Mon Sep 17 00:00:00 2001 From: shadowik Date: Sun, 20 Oct 2024 13:33:15 +0400 Subject: [PATCH 09/10] Weather Api endpoint --- .idea/dataSources.xml | 12 ++++++++++++ .idea/jsLibraryMappings.xml | 6 ++++++ .idea/webResources.xml | 14 ++++++++++++++ server/src/main.py | 7 ++----- server/src/routers/weather_router.py | 13 +++++++++++++ 5 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 .idea/dataSources.xml create mode 100644 .idea/jsLibraryMappings.xml create mode 100644 .idea/webResources.xml create mode 100644 server/src/routers/weather_router.py diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..7b6529f --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,12 @@ + + + + + mariadb + true + org.mariadb.jdbc.Driver + jdbc:mariadb://193.124.203.110:3306/wind_towers + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml new file mode 100644 index 0000000..6fa30af --- /dev/null +++ b/.idea/jsLibraryMappings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/webResources.xml b/.idea/webResources.xml new file mode 100644 index 0000000..913f4b6 --- /dev/null +++ b/.idea/webResources.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/server/src/main.py b/server/src/main.py index 692fdde..a535ffc 100644 --- a/server/src/main.py +++ b/server/src/main.py @@ -6,6 +6,7 @@ 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 +from routers.weather_router import router as weather_router app = FastAPI() @@ -15,8 +16,4 @@ 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 +app.include_router(weather_router) diff --git a/server/src/routers/weather_router.py b/server/src/routers/weather_router.py new file mode 100644 index 0000000..01703fe --- /dev/null +++ b/server/src/routers/weather_router.py @@ -0,0 +1,13 @@ +from fastapi import APIRouter +from data.repository import WeatherRepository + +router = APIRouter( + prefix="/api/weather", + tags=["Weather Api"], +) + + +@router.get("/") +async def get_weather(): + return WeatherRepository().get_all() + From e29917fbca5c50c7afe8d64977b11b6d4bf59ccd Mon Sep 17 00:00:00 2001 From: shadowik Date: Sun, 20 Oct 2024 15:48:17 +0400 Subject: [PATCH 10/10] Fix build application from terminal --- server/README.md | 11 ++++++++--- server/src/data/repository.py | 6 +++--- server/src/main.py | 2 ++ server/src/routers/floris_router.py | 7 +++++-- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/server/README.md b/server/README.md index 5e79c49..f69b485 100644 --- a/server/README.md +++ b/server/README.md @@ -20,8 +20,13 @@ ```zsh pip install -r requirements.txt ``` - -4. Start FastAPI process + +4. Enter src directory ```zsh - fastapi dev main.py + cd src + ``` + +5. Start FastAPI process + ```zsh + uvicorn main:app --reload ``` \ No newline at end of file diff --git a/server/src/data/repository.py b/server/src/data/repository.py index 2411229..b9fbc39 100644 --- a/server/src/data/repository.py +++ b/server/src/data/repository.py @@ -1,8 +1,8 @@ from sqlalchemy import select -from .database import session_maker -from .models import Weather -from .schemas import SWeatherInfo +from data.database import session_maker +from data.models import Weather +from data.schemas import SWeatherInfo class WeatherRepository: diff --git a/server/src/main.py b/server/src/main.py index a535ffc..a4a7788 100644 --- a/server/src/main.py +++ b/server/src/main.py @@ -1,3 +1,5 @@ +import sys + from pathlib import Path from fastapi import FastAPI diff --git a/server/src/routers/floris_router.py b/server/src/routers/floris_router.py index 4e6a260..7bbca30 100644 --- a/server/src/routers/floris_router.py +++ b/server/src/routers/floris_router.py @@ -1,3 +1,4 @@ +import sys from http import HTTPStatus from pathlib import Path from typing import Annotated @@ -8,9 +9,11 @@ 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") +sys.path.append(str(Path(__file__).parent.parent.parent)) +from floris_module.src import FlorisULSTU + +FLORIS_IMAGES_PATH = Path(__file__).parent.parent.parent / "public" / "floris" router = APIRouter( prefix="/api/floris",