Repository navigation
Conversation
There was a problem hiding this comment.
Thanks @bayc ! You'll see that I left a laundry list of suggestions below. But overall, there are a couple of bigger things I'd like to get at. The first (and probably biggest) from the source code perspective is, is it possible to avoid the allocation of the new attributes on the FlowField class if the user sets enable_turbine_turbulence_grid to False? I'm finding a non-negligible increase in memory usage being caused by the new arrays, and we've run into memory issues in the past when running FLORIS with large wind farms, so I'd rather not add memory burden for users that won't be using this feature. Computational speed doesn't seem to be affected, so that's good!
Then, I'd like to have some additional information added so that users can understand what has been added here. I think at minimum that'd be an example that calculates the SAWS/SATI for various turbines in a farm and plots the result, but ideally we'd also have a new documentation page on this, too (possibly a new chapter under User reference?
Last, could we get some tests added for the new code?
|
|
||
| return turbine_powers | ||
|
|
||
| def get_turbine_powers_percent(self): |
There was a problem hiding this comment.
I'm not sure I quite understand this method? It seems to compute the percentage of rated power that the power setpoint is, but the docstring states that it calculates the percentage of power that each turbine is producing, relative to its setpoint? Is this method being used (if so, maybe the docstring needs updating)?
There was a problem hiding this comment.
Typo, good catch. It returns the percent of the max power for that turbine that the turbine is currently operating at. Updated to reflect the correct wording.
There was a problem hiding this comment.
I believe self.core.farm.power_setpoints / turbine_max_powers will return the percentage of max power that the setpoint is, regardless of whether the turbine is actually operating at that setpoint or not.
For instance, for a 5MW rated turbine, let's say the power setpoint is 3MW but the turbine is only operating at 2MW (due to the wind resource it is experiencing).
I think this method will return 60% (3/5). To me though, the docstring and name of the method seem to imply that the "answer" should be 40% (2/5). Could you confirm on that?
There was a problem hiding this comment.
@bayc , this is my only remaining concern. Once we're clear on this we'll be good to merge. However, if I'm honest, my preference is simply to remove this method entirely and push this operation to the user's software, since it doesn't have anything to do with the solve (just computes the ratio between two user inputs: the turbine power rating and the power setpoint).
|
@bayc , I've made a few commits here to try to address my own concerns about increased memory usage. For reference, the last commit before my changes is 4f15fb8. I've mostly tried to avoid declaring new attributes on import copy
import sys
from conftest import SampleInputs
from pympler import asizeof # Will need to install, not part of the FLORIS requirements
from floris.core import Core
def run_floris():
sample_inputs = SampleInputs()
sample_inputs.core["wake"]["model_strings"]["velocity_model"] = "gauss"
sample_inputs.core["wake"]["model_strings"]["deflection_model"] = "gauss"
sample_inputs.core["wake"]["enable_secondary_steering"] = True
sample_inputs.core["wake"]["enable_yaw_added_recovery"] = True
sample_inputs.core["wake"]["enable_transverse_velocities"] = True
sample_inputs.core["wake"]["enable_turbine_turbulence_grid"] = False # Comment out this line when running on develop
N_TURBINES = 100
N_FINDEX = 72 * 25 # Size of a characteristic wind rose
TURBINE_DIAMETER = sample_inputs.core["farm"]["turbine_type"][0]["rotor_diameter"]
sample_inputs.core["farm"]["layout_x"] = [5 * TURBINE_DIAMETER * i for i in range(N_TURBINES)]
sample_inputs.core["farm"]["layout_y"] = [0.0 for i in range(N_TURBINES)]
sample_inputs.core["flow_field"]["wind_directions"] = N_FINDEX * [270.0]
sample_inputs.core["flow_field"]["wind_speeds"] = N_FINDEX * [8.0]
sample_inputs.core["flow_field"]["turbulence_intensities"] = N_FINDEX * [0.06]
N = 1
for i in range(N):
core = Core.from_dict(copy.deepcopy(sample_inputs.core))
core.initialize_domain()
core.steady_state_atmospheric_condition()
print(asizeof.asizeof(core.flow_field)/1e6) # ~MB
print("\n", asizeof.asizeof(core)/1e6) # ~MB
if __name__=="__main__":
run_floris()Running on develop, I get 145 MB for Could you take a look over my changes and see if you are happy with them? I also went ahead and renamed the methods on After this, I think a minimal product would be to add some tests; documentation and examples could wait (I'd just open an issue and tag you in it to do that at a later date). And maybe you could weigh in on whether the After these updates, I'd probably rereview to comb through minor bits and pieces. |
@misi9170 Thanks for making these changes and tackling the memory issue! I reviewed your changes and believe they should all return the same values, so that looks good to me. I've also worked to address your comments and believe the PR is ready for your re-review. |
Enable TI and WS calculation to support surrogate models for DELs
This PR includes changes to support the use of FLORIS as part of the DEL surrogate load modeling process described in:
Guilloré, A., Campagnolo, F., & Bottasso, C. L. (2024, June). A control-oriented load surrogate model based on sector-averaged inflow quantities: capturing damage for unwaked, waked, wake-steering and curtailed wind turbines. In Journal of Physics: Conference Series (Vol. 2767, No. 3, p. 032019). IOP Publishing.
The main capabilities added are the calculation of sector-averaged wind speeds (SAWS) and sector-averaged turbulence intensities (SATI), as described in the reference above. In short, the turbine rotor is divided into 4 sectors, centered on the vertical and horizontal axes. The average WS and TI are calculated for each of these sectors and used as inputs into the surrogate model to predict various DELs.
In FLORIS, the averages in these sectors are computed as an average of the respective edge of the 3x3 square grid of points on the turbine's rotor plane. This also requires FLORIS to model TI on the rotor plane as heterogenous vs the current homogenous approach. A flag to enable to resulting change in turbine TI values has been added to preserve the previous method as the default.
Related issue
None.
Impacted areas of the software
sovler.pydeflection/gauss.py4 new methods in
floris_model.py:get_turbine_powers_percentget_turbine_grid_TIsget_turbine_SAWSget_turbine_SATIAdditional supporting information
None.
Test results, if applicable
Passing.