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

Implement TurbOPark as a Gaussian model #907

Merged
merged 47 commits into from
Jul 18, 2024

Conversation

JasperShell
Copy link

TurbOPark implemented like Gauss wake model using sequential_solver

The current implementation of TurbOPark follows Orsted's original implementation (https://github.com/OrstedRD/TurbOPark), and has a dedicated solver, turbopark_solver in solver.py.
However, the current implementation does not match the results of Orsted's model.

This pull request proposes a new implementation of the TurbOPark wake model, turboparkgauss.py. Instead of introducing a dedicated solver, it makes use of the sequential_solver, the same as used for Gauss (GCH) wake model.
This new implementation gives exact match with the original Orsted model.
It also improves the modularity of Floris, because this implementation doesn't need a dedicated solver.

Related issue

The new implementation benefits from the cubature_grid integration scheme that was introduced in #649. It uses:

solver:
  type: turbine_cubature_grid
  turbine_grid_points: 4    # any value greater or equal to 3 should work

Test cases

All test cases are stored in the PR_TurbOParkGauss folder.
In these examples, all turbines have a constant CT of 0.75. Wind speed is fixed to 8.0m/s and TI is set to 6%.

Example 1: Single wake

This example is based on Case_SingleTurbineWake.ipynb and Case_SingleTurbineWake.yaml
NOTE: This test case is built in Floris v3.6.
Because the new implementation uses the sequential_solver, also the full_flow_sequential_solver can be used to visualize a single wake. This is not possible with the current TurbOPark implementation.
The new implementation is compared with Orsted's model and with my own ShellWakes tool.
Screenshot 2024-05-14 102759

Example 2: Wind direction sweep

This example is based on Case_TwinPark_TurbOPark_implementation.py, Case_TwinPark_TurbOPark.yaml and Case_TwinPark_TurbOParkGauss.yaml.
NOTE: This test case is built in Floris v4.0.
A wind direction sweep is done with 2 wind turbines.
Example2

Example 3: Row of turbines

This example is based on Case_Rowpark_TurbOPark.py, Case_RowPark_TurbOPark.yaml and Case_RowPark_TurbOParkGauss.yaml
NOTE: This test case is built in Floris v4.0.
A fully aligned wind farm of 10 wind turbines with 5D spacing.
Example3

Examples 2 and 3 show the mismatch of the original implementation of turbopark.py and the matching implementation of turboparkgauss.py.

Note that in the same way, other wake models can be implemented that use the sequential_solver, as long as the wake profiles are smooth. Models like, gaussian, super-gaussian, double-gaussian, polynomial (Larson), and even EV.
Only hat-shaped models, like Jensen, or models with integrated super-positioning, like CC, require a dedicated solver.

@rafmudaf rafmudaf added the enhancement An improvement of an existing feature label May 14, 2024
@misi9170 misi9170 self-requested a review May 23, 2024 15:55
@rafmudaf rafmudaf changed the title Feature/turbopark as gauss Implement TurbOPark as a Gaussian model May 24, 2024
@misi9170
Copy link
Collaborator

misi9170 commented Jun 4, 2024

Hi @JasperShell , thank you again for taking the time to dig into FLORIS and for submitting this pull request. I've now had more of a chance to start working with it, and I've started with reorganizing the PR_TurbOParkGauss folder and turning it into an example in the examples/ directory (under a new subdirectory, examples_turbopark).

The key changes I've made are:

  • Condensing the floris input files into single files rather than using !includes throughout (not that there was anything wrong there, but just to be more consistent with other examples in the repository)
  • Condensing the two case scripts and one case notebook into a single script (001_compare_turbopark_implementations.py)
  • Renaming some variables and adding comments to the scripts; cleaning up the plots somewhat
  • Constructing the constant C_T model directly in the script
  • Moving the files over to the examples/examples_turbopark directory

Now, running 001_compare_turbopark_implementations.py produces the following figures (which match those from the case scripts/notebooks):
turbopark_1
turbopark_2

@misi9170
Copy link
Collaborator

misi9170 commented Jun 4, 2024

The process I'm planning for working on this PR is

  1. Reorganize examples
  2. Write regression tests (likely based on examples)
  3. Review models and model implementations, possibly request/discuss changes
  4. Add/update documentation
  5. Check tests still pass, then ask @rafmudaf / others to review

@misi9170
Copy link
Collaborator

misi9170 commented Jun 28, 2024

Hi @JasperShell , I've now looked carefully through your implementation of the TurboPark model and compared with Pedersen et al (2022). I think it's in really great shape, and I'm just about ready to move onto finalizing things (adding a bit of documentation etc). Before I do that though, I have a couple of requests:

  1. I've made small formatting and stylistic changes throughout, and it would be great if you could take a high-level look through the files and make sure you are happy with them. You could first look here to see the changes to all of the files (as compared to the develop branch that this will merge into). That view does not distinguish between your code and the changes that I've made. Then, this view shows specifically the changes I have made compared to your changes; there are many files touched because I have merged in the develop branch, so I think you could just look specifically at the wake_velocity/turboparkgauss.py file and ensure that you're happy with that, and ignore the rest.

  2. For the purpose of this pull request, I'd prefer for us to include the Turbopark model only and remove the Doublegauss model. We'd be very happy to include the Doublegauss model in FLORIS, but I feel that that should be a separate pull request so that we can keep the development history clear and so that we can build out tests, examples, and documentation for that in a separate effort. It's easy for me to remove doublegauss.py and the other changes associated with the Doublegauss model, but I wanted to check that you are happy for me to do that (and also give you the opportunity now to create a branch from the feature/turbopark_as_gauss branch that keeps the Doublegauss model on it for the purpose of submitting a separate pull request, although we'll always be able to go back and find that in the commit history too).

I'll wait for your response on both of these and then move forward with finalizing the pull request and asking for reviews from @rafmudaf and @paulf81 .

…ke as argument

Removed sigma_max_rel, because that restriction is not needed in this implementation.

Therefore also removed wtg_overlapping mask

Introduced include_mirror_wake as input argument
This wake model was only included to demonstrate that other wake models could be implemented.
The current implementation was not complete, it had some shortcomings compared to the latest literature.
Hence, removing it from this pull request. It can be introduced later in another pull request.
@JasperShell
Copy link
Author

JasperShell commented Jul 2, 2024

Hi @misi9170,
Thanks for processing our proposed changes. Good to see that you fully integrated it into Floris.

  1. I had two other considerations when reviewing the turboparkgauss.py file:
  • Could "include_mirror_wake" be an input argument, like "A" and "sigma_max_rel" instead of hardcoded?

  • I also believe we can remove the argument "sigma_max_rel", and thereby the boolean wtg_overlapping. This is argument was included in Orsted's Matlab code to accelerate it, but has no physical meaning. In the new Floris implementation, which uses cubature integration, this does not accelerate things (the opposite is true since it adds a number of irrelevant lines of code).

I pushed these proposed changes in a new commit.

  1. On Doublegauss, I agree to take it out. It was not a completely correct implementation. It was included to show that other types of wake models could be included as well with this new approach. Hence, better to take it out in this pull request and potentially open a new pull request lateron.

I removed the doublegauss wake model in another commit.

@misi9170
Copy link
Collaborator

misi9170 commented Jul 2, 2024

@paulf81 @bayc @rafmudaf this is now ready for review. As I've already been through it thoroughly, I'm happy to merge once one of you is happy. @Bartdoekemeijer , I've also added you as a reviewer in case you'd like to take a look and provide any comments.

@misi9170
Copy link
Collaborator

misi9170 commented Jul 2, 2024

I'll document here for future reference that this implementation has optional mirror wakes to model the effect of the ground or sea surface. The Boolean field include_mirror_wake in the wake_velocity_parameters>turboparkgauss dictionary on the floris input yaml can be used to switch this on and off (defaults to True, i.e., include mirror wakes).

Mirror wake functionality is also available in the empirical Gaussian (EmG) model; but there, it is currently hardcoded to True. I will create an issue to move this option up to the user level on the FLORIS yaml, in the same way as this PR does for the Turboparkgauss model.

floris/core/wake.py Outdated Show resolved Hide resolved
floris/core/wake.py Outdated Show resolved Hide resolved
more faithful to the original description provided by Nygaard et al and uses
the sequential_solver, and compares it to the existing implementation in
Floris.
"""
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could we add here a note on where the data comparison_data comes from, is it from one of the referenced papers? Or the website?

Copy link
Author

Choose a reason for hiding this comment

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

The testcases were my own, so not based on literature. The comparison data comes from running Orsted's Matlab code.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I've now added a text comment saying that the comparison data comes from running Ørsted's Matlab code.


# Plot the data and compare
ax[1].scatter(
turbines, df_rowpark["wws"], s=80, marker="o", c="k", label="Orsted - TurbOPark"
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe if not too bulky could add (Source: ...)

Copy link
Collaborator

@paulf81 paulf81 left a comment

Choose a reason for hiding this comment

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

Thank you very much @JasperShell for this contribution! Only very minor comments from me so I'm going to approve. But I did have two optional thoughts I wanted to check with you and also @misi9170:

  1. Should we add a warning to the former turbopark model if we have a preference toward the new?
  2. More for @misi9170 , the tests are failing on my computer locally but that is due to randomoptregtest so I'll open a separate issue

@JasperShell
Copy link
Author

@paulf81, thanks for approving this pull request.

On your first point, first of all it is primarily up to you and @misi9170 as owners of the tool.
I would add a warning that the original implementation deviates from Orsted's reference code, and that therefore a new implementation is introduced. I would also add that at some point the original implementation will be phased out.
A similar message is proposed for the documentation, about which @misi9170 and I connected over email.

@paulf81
Copy link
Collaborator

paulf81 commented Jul 5, 2024

Thank you for the comments @JasperShell , I'll meet up with @misi9170 and I think we can get this merged very soon!

@misi9170 misi9170 merged commit 296628a into NREL:develop Jul 18, 2024
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement An improvement of an existing feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants