Closed misi9170 closed 4 days ago
This all looks good @misi9170 , I left a few small comments. Going to approve but one additional thought I had is we could perhaps add a small test or two to ensure we keep this desired behavior, but isn't clearly necessary
Thanks @paulf81 --- testing is a good idea, I'll write a small test to check it. I don't see any comments though---perhaps those got lost somehow?
This all looks good @misi9170 , I left a few small comments. Going to approve but one additional thought I had is we could perhaps add a small test or two to ensure we keep this desired behavior, but isn't clearly necessary
Thanks @paulf81 --- testing is a good idea, I'll write a small test to check it. I don't see any comments though---perhaps those got lost somehow?
Huh! They did all disappear, bummer! I don't think they were particularly insightful, from memory they were like: 1) Is the difference between floris.copy() versus copy.deepcopy() important? 2) Just flagging we may need to one day route the helix setpoints through the same architecture (but not this PR) 3) Checking my understanding of the example outputs that the yaw angles of disabled turbines are meaningless and can be anything
@paulf81 on those points:
deepcopy()
is needed to copy over the power_setpoints
. Currently, FlorisModel.copy()
doesn't copy the control setpoints (yaw_angles
, power_setpoints
, etc) because it creates a FLORIS dictionary, which doesn't contain those values.copy()
problem above.YawOptimizerGeometric
code, because yaw angles are initialized at zero, but it was not immediately obvious how this should be done in YawOptimizerSR
and besides, it's not really true that the "optimal" yaw angle is zero for a disabled turbine anyway. Still, this may confuse users, and perhaps having special handling to set those yaw angles to zero would be good (alternatively, set them to NaN, which could be done in YawOptimizerGeometric
too).I've now added tests for:
set
ting simultaneously vs in multiple calls when using the "mixed"
operation modelThanks @misi9170 good to go on my end!
@paulf81 I have now added a small piece of code in the constructor of the base YawOptimization
class that automatically assigns minimum and maximum yaw angles of zero to disabled turbines. This does help make the output yaw angles more intuitive---thanks for the suggestion.
I incorrectly merged this PR directly into the main branch. I have forced pushed the reversion back to the previous commit on main, so main no longer contains this PR's changes. I've opened a new PR #1031 to merge this code into develop, as intended.
In #1016, @MiguelMarante raised the issue that the Serial Refine yaw optimizer ignores that some turbines are disabled. I converted this to an issue in #1022 .
This pull request enables that behavior, both for the Serial Refine routine as well as the Geometric yaw optimizer. Note that yaw optimization using Scipy is still not supported for the
"mixed-operation"
model (I looked into enabling this as well, but this will take more time and is not the priority).Affected areas of the code
In making the necessary changes to the yaw optimization routines, I also had to make the following changes:
FlorisModel.set()
was incorrectly treating lower power setpoints as though they were the default, which caused them to be ignored and reset whenset()
is called again. This was introduced in #823 by an erroneous commit of mine, a00bff8. This bug meant that callingset(disabled_turbines=[...])
followed by any otherset()
call would drop the information about disabling turbines.MixedOperationModel
to work better with yaw optimization.I've also added a new example, examples/examples_controloptimization/008....py, which is based heavily on @MiguelMarante 's example script in #1016.
Notes
In the yaw optimization routines, the solution involves passing
power_setpoints
through from the usersfmodel
to thefmodel_subset
attributes on the yaw optimization routines. While this works fine, it is yet another example of where control setpoints have to be piped through various pieces of the FLORIS code. To enable other setpoints to be used while optimizing yaw, this process will have to be repeated. We could consider moving to some sort of high-level data structure (possible just a dictionary) for the control setpoints, so that they can be lumped together and passed through the FLORIS code more readily.Results
Running the new example produces (removing the progress output from Serial Refine):
which is in line with expectations, see #1022.