-
Notifications
You must be signed in to change notification settings - Fork 182
Implement TurbOPark as a Gaussian model #907
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
Conversation
|
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:
Now, running 001_compare_turbopark_implementations.py produces the following figures (which match those from the case scripts/notebooks): |
|
The process I'm planning for working on this PR is
|
|
@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. |
|
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 Mirror wake functionality is also available in the empirical Gaussian (EmG) model; but there, it is currently hardcoded to |
| 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. | ||
| """ |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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" |
There was a problem hiding this comment.
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: ...)
paulf81
left a comment
There was a problem hiding this 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:
- Should we add a warning to the former turbopark model if we have a preference toward the new?
- More for @misi9170 , the tests are failing on my computer locally but that is due to randomoptregtest so I'll open a separate issue
|
@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. |
|
Thank you for the comments @JasperShell , I'll meet up with @misi9170 and I think we can get this merged very soon! |
|
Thank you all for working on this! I'm (very belatedly) trying to integrate this into my local version of FLORIS v3.1 for legacy reasons, where we have some other connected applications and have not yet updated. I'm running into some issues downstream. I ran both the test case included in this PR as well as the Orsted test case (https://github.com/OrstedRD/TurbOPark/blob/main/TurbOParkExamples.pdf) and in both cases, I get slightly more wake recovery downstream:
My thought is that this is coming from a change affecting SOSFS or some other aspect of wake combination, since the first turbine matches very well. I'm going to compare against the latest version, but just thought I'd write here in case something immediately springs to mind as to what could be happening here. |
|
Hi @mr483 , My first guess is that this has to do with using a square grid for points, rather than the cubature grid suggested for the I'm not 100% sure about this, but I do think this could lead to the differences in results that you are seeing (or at least contribute to them). |
|
That was my thought too, except that even when I increase the grid resolution to very high numbers (100 for example), the magnitude of the error is unchanged. Anyway, I will keep investigating, thanks for the tip. EDIT: Ah - I see why cubature would normally be expected to give different results, since radius_ratio is 0.5 on the standard rectangular grid. But for me, I changed this a while ago to be 1.0 and then do postprocessing in rotor-averaging function to include only points within the rotor area, so this should be unaffected. |
|
In the unlikely case someone else needs to implement this in an older FLORIS version (<4.1), the relevant thing which I was missing was the bugfix for the None turbulence model: #894 After that is implemented, matches perfectly. |
|
@mr483 , good sleuthing, and thanks for posting the solution here! |




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_solverinsolver.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 thesequential_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:
Test cases
All test cases are stored in the
PR_TurbOParkGaussfolder.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.ipynbandCase_SingleTurbineWake.yamlNOTE: This test case is built in Floris v3.6.
Because the new implementation uses the
sequential_solver, also thefull_flow_sequential_solvercan 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.
Example 2: Wind direction sweep
This example is based on

Case_TwinPark_TurbOPark_implementation.py,Case_TwinPark_TurbOPark.yamlandCase_TwinPark_TurbOParkGauss.yaml.NOTE: This test case is built in Floris v4.0.
A wind direction sweep is done with 2 wind turbines.
Example 3: Row of turbines
This example is based on

Case_Rowpark_TurbOPark.py,Case_RowPark_TurbOPark.yamlandCase_RowPark_TurbOParkGauss.yamlNOTE: This test case is built in Floris v4.0.
A fully aligned wind farm of 10 wind turbines with 5D spacing.
Examples 2 and 3 show the mismatch of the original implementation of
turbopark.pyand the matching implementation ofturboparkgauss.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.