Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tum misalignment model #832

Draft
wants to merge 62 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
d79e2c5
Add a place-holder mit loss function
paulf81 Feb 8, 2024
3f1ec29
track new mit loss model
paulf81 Feb 8, 2024
afcb344
Add mit loss model to tests
paulf81 Feb 8, 2024
c03e250
import mit loss model
paulf81 Feb 8, 2024
135dc64
add mit loss model class
paulf81 Feb 8, 2024
96538e7
Add an example to compare loss models
paulf81 Feb 8, 2024
c098819
Update example for clarity
misi9170 Feb 9, 2024
80ed080
Placeholder tests.
misi9170 Feb 9, 2024
56ba06c
test attributes.
misi9170 Feb 9, 2024
c78107f
Update names
paulf81 Feb 9, 2024
c55e3cd
fix comment
paulf81 Feb 9, 2024
5aa21dc
New TUM misalignment model and new IEA file
sTamaroTum Mar 5, 2024
a85ba4a
Merge branch 'tum_model_2' into v4
sTamaroTum Mar 5, 2024
c805ee0
ok
sTamaroTum Mar 6, 2024
3d40302
small fix
sTamaroTum Mar 6, 2024
448ac07
removed useless lines
sTamaroTum Mar 6, 2024
1957805
Remove assertions from tests; tests will need building out. Robust pa…
misi9170 Mar 6, 2024
4511a85
set, run in example.
misi9170 Mar 6, 2024
f68ac86
Format for ruff.
misi9170 Mar 6, 2024
3efd3fe
Remove assertions on tests; tests will still need to be built.
misi9170 Mar 6, 2024
5801a2a
Merge branch 'v4' into tum_model_2
misi9170 Mar 6, 2024
7ff1425
Remove v3 generator_efficiency key (remains on power_thrust_table for…
misi9170 Mar 6, 2024
f9de335
Added an if statement in get_ct() and find_cp() functions to add a sm…
sTamaroTum Mar 7, 2024
e108522
Replaced rotor_average_velocities with rotor_effective_velocities whe…
sTamaroTum Mar 7, 2024
84e0a5d
Added some np.squeeze() to suppress warnings arising during pytest
sTamaroTum Mar 7, 2024
39b0433
Corrected incoherent interpolation method (cubic) in get_pitch() and …
sTamaroTum Mar 7, 2024
f275e85
Testing the IEA 15 MW with the tum-loss model
sTamaroTum Mar 8, 2024
9111366
Added the look-up tables of Cp and Ct for the IEAs 10MW and 15MW, and…
sTamaroTum Mar 8, 2024
66ad254
Merge develop and v4 updates; add comments to turbine yamls.
misi9170 Nov 5, 2024
829e87f
Bring example up to v4.
misi9170 Nov 5, 2024
0ced9d2
Set reference_wind_height explicitly to avoid warning.
misi9170 Nov 5, 2024
6081de7
Formating updates.
misi9170 Nov 5, 2024
b66a9a6
Update 3mw model fields.
misi9170 Nov 5, 2024
825a808
Separate TUM operation model to own file.
misi9170 Nov 5, 2024
1c8b4c3
Remove tum_rotor_velocity_yaw_correction, since it is not used and ap…
misi9170 Nov 5, 2024
adf35cb
Add reg test for development purposes.
misi9170 Nov 5, 2024
97c42a5
Separate find_cp and get_ct functions.
misi9170 Nov 5, 2024
95c81b2
Simplify axial_induction() by calling similar code in thrust_coeffici…
misi9170 Nov 5, 2024
a521dcd
Add further comments to power() and thrust_coefficient() methods.
misi9170 Nov 5, 2024
e5b821b
Simplify calls to control_trajectory().
misi9170 Nov 5, 2024
97f2a17
Various formatting changes throughout for improved alignment with res…
misi9170 Nov 5, 2024
ea684ac
Move to kW as base power unit for consistency with other turbine spec…
misi9170 Nov 5, 2024
c6445a0
Format using ruff format.
misi9170 Nov 5, 2024
92d1720
Specify data file on turbine yaml; update to type_dec to allow strings
misi9170 Nov 5, 2024
77ec24d
Revert "Set reference_wind_height explicitly to avoid warning."
misi9170 Nov 6, 2024
1f63aec
Raise error if velocities provided are insufficient to get shear info…
misi9170 Nov 6, 2024
655cf0c
Add description in documentation (still to build out).
misi9170 Nov 6, 2024
47170f8
Simplifying formatting; adding references to equations in paper where…
misi9170 Nov 7, 2024
b072291
Vectorize interpolation operations.
misi9170 Nov 7, 2024
f00a469
Make all functions staticmethods on TUMLossModel
misi9170 Nov 9, 2024
6950d28
Switch to cosd, sind from floris.utilities.
misi9170 Nov 9, 2024
94ec713
Add correct 15MW data and remove 3MW model. Reg tests fail due to upd…
misi9170 Nov 18, 2024
b18819b
Update base values in reg test.
misi9170 Nov 18, 2024
437afe8
Remove unneeded print statements.
misi9170 Nov 18, 2024
71a2251
Load cp_ct data on turbine construction rather than in operation mode…
misi9170 Nov 18, 2024
0f8887b
Rename cp_ct data file to be clearer. Update fields in all turine mod…
misi9170 Nov 18, 2024
b62a04d
Add 5mw and 10mw cp ct data (tests failing).
misi9170 Nov 25, 2024
edad57f
Store loaded data as nested lists for generality
misi9170 Nov 25, 2024
5555df3
Update reg tests results to reflect new data for nrel 5MW cp/ct surface.
misi9170 Nov 25, 2024
63f6b9b
Ensure data is read in as numpy arrays
misi9170 Dec 2, 2024
52537ee
Tests for TUMLossTurbine built out. Fails similarity test to existing…
misi9170 Dec 2, 2024
b4a93f7
Change operation model name to ControllerDependentTurbine.
misi9170 Dec 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 79 additions & 2 deletions docs/operation_models_user.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -460,10 +460,87 @@
"ax[1].set_ylabel(\"Power [kW]\")"
]
},
{
"cell_type": "markdown",
"id": "92912bf7",
"metadata": {},
"source": [
"### Controller-dependent model\n",
"\n",
"User-level name: `\"controller-dependent\"`\n",
"\n",
"Underlying class: `ControllerDependentTurbine`\n",
"\n",
"Required data on `power_thrust_table`:\n",
"- `rotor_solidity`: (scalar)\n",
"- `rated_rpm`: (scalar)\n",
"- `generator_efficiency`: (scalar)\n",
"- `rated_power`: (scalar)\n",
"- `rotor_diameter`: (scalar)\n",
"- `beta`: (scalar)\n",
"- `cd`: (scalar)\n",
"- `cl_alfa`: (scalar)\n",
"- `cp_ct_data_file`: (string)\n",
"\n",
"The `\"controller-dependent\"` operation model is an advanced operation model that uses the turbine's Cp/Ct\n",
"surface to optimize performance under yaw misalignment.\n",
"\n",
"TODO: add description of the model at a high level, and also what each of the parameters listed above (`rotor_solidity`, `rated_rpm`, etc) is used for in the model.\n",
"\n",
"Details can be found in {cite:t}`tamaro2024beyondcosine`."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "92912bf7",
"id": "6e4c5ba2",
"metadata": {},
"outputs": [],
"source": [
"N = 101 # How many steps to cover yaw range in\n",
"yaw_max = 30 # Maximum yaw to test\n",
"\n",
"# Set up the yaw angle sweep\n",
"yaw_angles = np.linspace(-yaw_max, yaw_max, N).reshape(-1,1)\n",
"\n",
"# We can use the same FlorisModel, but we'll set it up for this test\n",
"fmodel.set(\n",
" wind_data=TimeSeries(\n",
" wind_speeds=np.ones(N) * 8.0,\n",
" wind_directions=np.ones(N) * 270.0,\n",
" turbulence_intensities=0.06\n",
" ),\n",
" yaw_angles=yaw_angles,\n",
")\n",
"\n",
"# We'll compare the \"controller-dependent\" model to the standard \"cosine-loss\" model\n",
"op_models = [\"cosine-loss\", \"controller-dependent\"]\n",
"results = {}\n",
"\n",
"for op_model in op_models:\n",
" print(f\"Evaluating model: {op_model}\")\n",
" fmodel.set_operation_model(op_model)\n",
"\n",
" fmodel.run()\n",
" results[op_model] = fmodel.get_turbine_powers().squeeze()\n",
"\n",
"fig, ax = plt.subplots()\n",
"colors = [\"C0\", \"k\"]\n",
"linestyles = [\"solid\", \"dashed\"]\n",
"for key, c, ls in zip(results, colors, linestyles):\n",
" central_power = results[key][yaw_angles.squeeze() == 0]\n",
" ax.plot(yaw_angles.squeeze(), results[key]/central_power, label=key, color=c, linestyle=ls)\n",
"\n",
"ax.grid(True)\n",
"ax.legend()\n",
"ax.set_xlabel(\"Yaw angle [deg]\")\n",
"ax.set_ylabel(\"Normalized turbine power [deg]\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "90d5c155",
"metadata": {},
"outputs": [],
"source": []
Expand All @@ -485,7 +562,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.2"
"version": "3.10.6"
}
},
"nbformat": 4,
Expand Down
12 changes: 12 additions & 0 deletions docs/references.bib
Original file line number Diff line number Diff line change
Expand Up @@ -299,3 +299,15 @@ @article{SinnerFleming2024grs
title = {Robust wind farm layout optimization},
journal = {Journal of Physics: Conference Series},
}

@Article{tamaro2024beyondcosine,
AUTHOR = {Tamaro, S. and Campagnolo, F. and Bottasso, C. L.},
TITLE = {On the power and control of a misaligned rotor -- beyond the cosine law},
JOURNAL = {Wind Energy Science},
VOLUME = {9},
YEAR = {2024},
NUMBER = {7},
PAGES = {1547--1575},
URL = {https://wes.copernicus.org/articles/9/1547/2024/},
DOI = {10.5194/wes-9-1547-2024}
}
58 changes: 58 additions & 0 deletions examples/examples_operation_models/001_compare_yaw_loss.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"""Example: Compare yaw loss
This example shows demonstrates how the Controller-dependent operation model (developed at TUM)
alters how a turbine loses power to yaw compared to the standard cosine loss model.
"""

import matplotlib.pyplot as plt
import numpy as np

from floris import FlorisModel


# Parameters
N = 101 # How many steps to cover yaw range in
yaw_max = 30 # Maximum yaw to test

# Set up the yaw angle sweep
yaw_angles = np.zeros((N,1))
yaw_angles[:,0] = np.linspace(-yaw_max, yaw_max, N)

# Create the FLORIS model
fmodel = FlorisModel("../inputs/gch.yaml")

# Initialize to a simple 1 turbine case with n_findex = N
fmodel.set(
layout_x=[0],
layout_y=[0],
wind_directions=270 * np.ones(N),
wind_speeds=8 * np.ones(N),
turbulence_intensities=0.06 * np.ones(N),
yaw_angles=yaw_angles,
)

# Loop over the operational models to compare
op_models = ["cosine-loss", "controller-dependent"]
results = {}

for op_model in op_models:

print(f"Evaluating model: {op_model}")
fmodel.set_operation_model(op_model)

fmodel.run()
results[op_model] = fmodel.get_turbine_powers().squeeze()

# Plot the results
fig, ax = plt.subplots()
colors = ["C0", "k"]
linestyles = ["solid", "dashed"]
for key, c, ls in zip(results, colors, linestyles):
central_power = results[key][yaw_angles.squeeze() == 0]
ax.plot(yaw_angles.squeeze(), results[key]/central_power, label=key, color=c, linestyle=ls)

ax.grid(True)
ax.legend()
ax.set_xlabel("Yaw angle [deg]")
ax.set_ylabel("Normalized turbine power [deg]")

plt.show()
1 change: 1 addition & 0 deletions floris/core/turbine/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

from floris.core.turbine.controller_dependent_operation_model import ControllerDependentTurbine
from floris.core.turbine.operation_models import (
AWCTurbine,
CosineLossTurbine,
Expand Down
Loading