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 56 commits into
base: develop
Choose a base branch
from
Draft

Conversation

sTamaroTum
Copy link

@sTamaroTum sTamaroTum commented Mar 6, 2024

TUM misalignment model

This is a proposal to include the misalignment model developed by TUM to floris v4. The methodology is based on the preprint available currently at https://wes.copernicus.org/preprints/wes-2023-133/ .
The model is coded into simulation/turbine/operation_models.py . It consists of the usual power(), thrust(), axial_induction() functions. There are two extra functions called compute_local_vertical_shear() and control_trajectory().

  • compute_local_vertical_shear() is called to evaluate the vertical (linear) shear that each rotor experience, based on the inflow velocity. This allows to make the power curve asymmetric w.r.t. yaw misalignment.
  • control_trajectory() determines the tip-speed-ratio and pitch angles that occur in operation. This routine assumes a standard region 2 control approach (i.e. k*rpm^2) and a region 3. Also region 2 1/2 is considered. In the future, different control strategies could be included, even user-defined.

The model requires a few new inputs that were added to the power_thrust_table in the yaml file. It also requires the cp-pitch-tsr curves for the turbine model considered. An .npz file is added to the turbine_library folder, as well as a file iea_3mw.yaml file ready for use with the model. This file refers to the IEA 3 MW reference turbine by Bortolotti et al. (2019). In the future, more wind turbine models could be added.

The model accepts power_setpoints inputs in watts to simulate derating.

The model allows also to obtain the pitch and tip speed ratio of the wind turbine. Right now the code is printing the values of tip speed ratio and pitch to screen. This could be removed for clarity, but get_pitch() and get_tsr() functions could be coded (?).

Related issue

Impacted areas of the software

simulation/turbine/operation_models.py

Additional supporting information

The model seem to work well with the examples, but it crashes at wind speeds higher than 18 m/s, because the operating tip-speed-ratio gets too low.

In the tum model, the tilt is negative when tower clearance is created. This seems conflicting with floris convention, so there is a sign change at the start of the power(), thrust() and axial_induction() functions.

Sorry if something is wrong, this is the first time I work with github.

Test results, if applicable

@sTamaroTum sTamaroTum changed the title Tum model 2 Tum misalignment model Mar 6, 2024
@misi9170
Copy link
Collaborator

misi9170 commented Nov 6, 2024

Hi @sTamaroTum ,

Thank you for your patience waiting for us to work through this pull request. I have finally been able to spend some time working on it, and have made various changes (while trying to ensure that I have not changed the outputs at all---see my comment about regression tests below).

Main changes

The main changes I've made while working through your code are the following:

  • Separated out the TUMLossTurbine from operation_models.py to its own file. There was enough code there that @rafmudaf and I felt that it deserved its own file; this also has the benefit of keeping your code contained to essentially one file, which is nice for development purposes. I know that I had originally suggested you put it in operation_model.py---sorry about contradicting my own advice there!
  • Reorganized the functions somewhat to be more intuitive, with power(), thrust_coefficient(), and axial_induction() appearing first, followed by the other functions, to be consistent with other operation models
  • Removing/consolidating duplicated code, in particular find_cp() and get_ct(). I also altered the axial_induction() method so that it mostly calls thrust_coefficient() and then operates on the returned Ct values to find the axial induction factor, according to your method.
  • Applied automated formatting using ruff format to apply a uniform format to the code. This does make the code a little longer than needed, and maybe doesn't fit your stylistic preference, but it makes it uniform throughout.
  • Removed the tum_rotor_velocity_yaw_correction() method from rotor_velocity.py because it wasn't called and anyway appears the same as rotor_velocity_yaw_correction().

Tests

I also separated out tests for the model into a new file tests/tum_operation_model_unit_test.py. To run the tests, you'll need to call pytest tests/tum_operation_model_unit_test.py. There are three tests currently: the first just checks that the TUMLossTurbine is a valid operation model; the second calls the TUMLossTurbine and is designed to check that it produces expected outputs for a series of selected inputs (but currently, does not actually check the outputs); and the final test is a regression test that I created to ensure that as I changed your code around, the same results were still obtained (but doesn't necessarily test that the outputs are, in themselves, correct). It would be great to get your input on the test_TUMLossTurbine test---are there any expected outputs given a canonical set of inputs (e.g., 0 yaw, or some derating, or similar)?

Documentation

It would be good to add a bit of high-level documentation on the TUM model. I will put a placeholder in imminently, but it would be good to have you add some extra there for people coming to FLORIS and wanting to know more about the model and how it works.

Other notes

  • To generalize the loading of the .npz file, I've had to alter type_dec.py to allow for strings to appear on the yaml dictionaries. This isn't something you need to concern yourself with, but I'm recording the change here.
  • I had originally made a change to FlorisModel because of a small bug, but I ended up opening a separate pull request for that ([BUGFIX] Address reference wind height warnings raised unnecessarily #1017)
  • In the pull request description, you mentioned that values of tip speed ratio and pitch are printed. For now, I have simply disabled this, but can these be removed?
  • The IEA 3MW model is not something we have supported in the past---is this needed, or is it fine to remove it?
  • I was missing the .npz file for the IEA 15MW model. From the code, it looks like you have this data locally, but I didn't find it in the repository. To make progress, I ended up finding the old .npz file for the IEA 3MW and renaming it to the IEA 15MW. However, I assume that you have accurate information for the IEA 15MW cp/ct surface---could you upload that (feel free to just overwrite the data currently named LUT_iea15MW.npz)

Next steps

At this stage, it would be great to get your input on the following:

  • Are you OK with the changes made to the TUMLossTurbine model (on tum_operation_model.py)?
  • Could you upload the correct Cp/Ct data for the IEA 15MW turbine, if you have it?
  • Could you take a pass through the test_TUMLossTurbine test and update it to include expected outputs and test? I'm happy to discuss further on what appropriate tests should be
  • Could you add a high-level description to the skeleton documentation that I've added (or will add very soon!)
  • Let me know if it is fine to go ahead and remove the print statements for tsr and pitch

In the meantime, I have the following action items:

  • Create a placeholder for documentation
  • Check the issue for wind speeds above 18m/s and possibly raise a helpful error if this situation occurs

Once we are happy that the code is final, @rafmudaf and I will take a last pass through it to see if there are any other final changes needed before we merge.

Again, my apologies on how long this took for us to get to---I hope that we'll be able to move it forward more rapidly now that I've been able to spend some time with it!

Misha

@misi9170
Copy link
Collaborator

misi9170 commented Nov 6, 2024

Just a few small updates to my comment above:

  • I've tested over a range of wind speeds from 0m/s to 30m/s, and everything seems to be working fine
  • I also tested with a single grid point (that is, only one velocity across the rotor) and this fails. Based on the description of compute_local_vertical_shear, this is expected---with only one point on the rotor, the algorithm for computing shear fails. I've added a check for this and now raise an error if this situation occurs. Is raising an error the appropriate outcome?
  • I've added placeholder documentation for the model in docs/operation_model_user.ipynb. You'll find that there is a markdown block titled "TUM loss model" that needs to be filled out a bit. If you could add a paragraph describing the model at a high level, and also indicate what the needed parameters refer to, that would be great

floris/core/turbine/tum_operation_model.py Show resolved Hide resolved
floris/core/turbine/tum_operation_model.py Outdated Show resolved Hide resolved
@@ -29,31 +29,44 @@ operation_model: 'cosine-loss'
###
# Parameters needed to evaluate the power and thrust produced by the turbine.
power_thrust_table:
### Power thrust table parameters
### General parameters
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a heads up that these comments are used to automatically generate this page in the docs: https://nrel.github.io/floris/input_reference_turbine.html. The structure (number of hashes) and location relative to the key/value pairs does matter. If you haven't it's worthwhile to build the docs locally and see the result.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, my bad, thanks---I'll do that and adjust as needed

@@ -59,7 +59,7 @@ def floris_array_converter(data: Iterable) -> np.ndarray:
raise TypeError(e.args[0] + f". Data given: {data}")
return a

def floris_numeric_dict_converter(data: dict) -> dict:
def floris_numeric_dict_converter(data: dict, allow_strings=False) -> dict:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider an "allow_any" flag instead of specifically allowing strings. Also, consider not using this function if you want to convert a dictionary that isn't all numbers. And also there's a new argument added but the docstring isn't updated.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm now also realizing it may make more sense to load the data stored in the string ahead of time, which would avoid this issue. I'm going to see if that'll work

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More and more, having yet another version of the inputs defined in this standalone class only for testing seems wasteful. I'm suggesting it be addressed here, but just pointing it out.

def test_TUMLossTurbine():

# NOTE: These tests should be updated to reflect actual expected behavior
# of the TUMLossTurbine model. Currently, match the CosineLossTurbine model.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget about this one!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants