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

Add utilities for floris models #840

Merged
merged 15 commits into from
Mar 20, 2024
Merged

Conversation

paulf81
Copy link
Collaborator

@paulf81 paulf81 commented Mar 13, 2024

Add utilities for floris models

co-authored with @bayc

This pull request:

  • Adds helper functions to utilities to work with nested dictionaries
  • Add methods to the FlorisModel for getting/setting parameters using those functions
  • Adds methods for changing the power-thrust model
  • Adds testing for all new functions
  • Reorganizes FlorisModel for clarity

@paulf81 paulf81 added the v4 Focus of FLORIS v4 label Mar 13, 2024
@paulf81 paulf81 added this to the v4.0 milestone Mar 13, 2024
@paulf81 paulf81 self-assigned this Mar 13, 2024
floris/floris_model_utils.py Outdated Show resolved Hide resolved
floris/floris_model_utils.py Outdated Show resolved Hide resolved
floris/floris_model_utils.py Outdated Show resolved Hide resolved
floris/floris_model_utils.py Outdated Show resolved Hide resolved
@paulf81 paulf81 requested a review from rafmudaf March 13, 2024 15:46
@rafmudaf
Copy link
Collaborator

Architecturally, @paulf81 what do you think of putting nested_get, nested_set, and print_nested_dict in floris.utilities since they are general function, and the other functions that apply only to FlorisModel within the floris_model module?

@bayc
Copy link
Collaborator

bayc commented Mar 13, 2024

@paulf81 , agree with Raf's comments above. Also for reference, in this commit (cbd3cf8), I removed a slightly different version of this same functionality where the list of keys was optional, and if not provided, the object would be scraped for all attributes and those would be returned as a dictionary. Could be worth including if you think it is useful.

@paulf81
Copy link
Collaborator Author

paulf81 commented Mar 13, 2024

Architecturally, @paulf81 what do you think of putting nested_get, nested_set, and print_nested_dict in floris.utilities since they are general function, and the other functions that apply only to FlorisModel within the floris_model module?

Done!

@paulf81
Copy link
Collaborator Author

paulf81 commented Mar 13, 2024

@paulf81 , agree with Raf's comments above. Also for reference, in this commit (cbd3cf8), I removed a slightly different version of this same functionality where the list of keys was optional, and if not provided, the object would be scraped for all attributes and those would be returned as a dictionary. Could be worth including if you think it is useful.

Sounds interesting! Looking at the code I wasn't quite positive which function should be added back in, and then I think some of these will need an update to the v4 standards, do you want to try to add into this PR? Or a seperate one?

@bayc
Copy link
Collaborator

bayc commented Mar 15, 2024

Architecturally, @paulf81 what do you think of putting nested_get, nested_set, and print_nested_dict in floris.utilities since they are general function, and the other functions that apply only to FlorisModel within the floris_model module?

Done!

Hey @paulf81 , I think @rafmudaf was suggesting moving the get_fmodel_param, set_fmodel_param, and print_fmodel_dict functions onto the FlorisModel class itself. I have opened up a PR to your branch that does this here: paulf81#13. If you both can check it out and see if 1) this is what you meant @rafmudaf , and 2) @paulf81 you agree with the changes, then feel free to merge it @paulf81 .

@paulf81
Copy link
Collaborator Author

paulf81 commented Mar 15, 2024

@misi9170 , I added some code for getting/setting the power_thurst_model, and somehow it doesn't work. It may be this thing of how the turbine_type can be stored in a few possible formats but I was wondering if you might have a look at these new codes Monday and see if you spot my error? I added two simple tests: and this one is failing:

def test_set_power_thrust_model():

    fmodel = FlorisModel(configuration=YAML_INPUT)
    fmodel = set_power_thrust_model(fmodel, "simple-derating")
    assert get_power_thrust_model(fmodel) == "simple-derating"

@bayc
Copy link
Collaborator

bayc commented Mar 18, 2024

@misi9170 , I added some code for getting/setting the power_thurst_model, and somehow it doesn't work. It may be this thing of how the turbine_type can be stored in a few possible formats but I was wondering if you might have a look at these new codes Monday and see if you spot my error? I added two simple tests: and this one is failing:

def test_set_power_thrust_model():

    fmodel = FlorisModel(configuration=YAML_INPUT)
    fmodel = set_power_thrust_model(fmodel, "simple-derating")
    assert get_power_thrust_model(fmodel) == "simple-derating"

@paulf81 , @misi9170 I went ahead and added this functionality and test to my PR to your branch Paul in this commit: paulf81@afad340. I changed it so that is uses the currently loaded turbine type, updates the power_thrust_model, and passes that updated turbine type to the set method. This way we avoid an file I/O and this would retain any other changes made programmatically by the use to the turbine definition.

Move FlorisModel realted utilities onto FlorisModel class
@paulf81
Copy link
Collaborator Author

paulf81 commented Mar 18, 2024

@misi9170 , I added some code for getting/setting the power_thurst_model, and somehow it doesn't work. It may be this thing of how the turbine_type can be stored in a few possible formats but I was wondering if you might have a look at these new codes Monday and see if you spot my error? I added two simple tests: and this one is failing:

def test_set_power_thrust_model():

    fmodel = FlorisModel(configuration=YAML_INPUT)
    fmodel = set_power_thrust_model(fmodel, "simple-derating")
    assert get_power_thrust_model(fmodel) == "simple-derating"

@paulf81 , @misi9170 I went ahead and added this functionality and test to my PR to your branch Paul in this commit: paulf81@afad340. I changed it so that is uses the currently loaded turbine type, updates the power_thrust_model, and passes that updated turbine type to the set method. This way we avoid an file I/O and this would retain any other changes made programmatically by the use to the turbine definition.

Thank you @bayc , I merged your pr into mine so those changes are now reflected in this pull request

@paulf81
Copy link
Collaborator Author

paulf81 commented Mar 18, 2024

Architecturally, @paulf81 what do you think of putting nested_get, nested_set, and print_nested_dict in floris.utilities since they are general function, and the other functions that apply only to FlorisModel within the floris_model module?

@rafmudaf this is now done, following the merge of @bayc code

@paulf81
Copy link
Collaborator Author

paulf81 commented Mar 18, 2024

@rafmudaf , I merged in @bayc changes and I think your requested changes are in

@misi9170 , have a look at the new change power-thrust model @bayc implemented, it's a lot shorter than previous and just wanted to make sure I'm not forgetting a reason we went back to the full yaml file before

@misi9170
Copy link
Collaborator

@paulf81 @bayc

Those look fine to me. For some reason, @paulf81 , I can't see the history of what you had implemented earlier that wasn't working? But perhaps the fix was to add the self.set(turbine_type=[turbine_type]) line---this is definitely required for the FlorisModel to be reinstantiated, which will be needed to reassign the operation model.

@paulf81
Copy link
Collaborator Author

paulf81 commented Mar 19, 2024

@paulf81 @bayc

Those look fine to me. For some reason, @paulf81 , I can't see the history of what you had implemented earlier that wasn't working? But perhaps the fix was to add the self.set(turbine_type=[turbine_type]) line---this is definitely required for the FlorisModel to be reinstantiated, which will be needed to reassign the operation model.

I think that's now moot, it was the change power-thrust functions I had written, but Chris' versions don't seem to suffer from this problem

@misi9170
Copy link
Collaborator

Overall this looks fine to me, but so that we have a record and some guidelines for future development, what is the logic behind the reorganization of the FlorisModel class?

The only objection I have is that I would have kept reset_operation() closer to set() and _reinitialize(), but perhaps there's a good reason to have that moved down!

@paulf81
Copy link
Collaborator Author

paulf81 commented Mar 19, 2024

Overall this looks fine to me, but so that we have a record and some guidelines for future development, what is the logic behind the reorganization of the FlorisModel class?

The only objection I have is that I would have kept reset_operation() closer to set() and _reinitialize(), but perhaps there's a good reason to have that moved down!

@bayc would you mind to comment here?

@rafmudaf
Copy link
Collaborator

The only objection I have is that I would have kept reset_operation() closer to set() and _reinitialize(), but perhaps there's a good reason to have that moved down!

It's subtle, but I also suggest to put set(), reset_operation(), and _reinitialize() above run() since they'll always be used in that order.

@bayc
Copy link
Collaborator

bayc commented Mar 20, 2024

@misi9170 @rafmudaf , after dividing into subsections, I just went with alphabetical order, starting with public methods and ending with private methods. Happy to rearrange as you see fit though.

@misi9170
Copy link
Collaborator

misi9170 commented Mar 20, 2024

I definitely like the idea of having the different methods grouped. I've reorganized them again slightly and pushed up the change (which we can certainly revert), so that now we have:

  1. __init__()

### Methods for setting and running the FlorisModel

  1. _reinitialize()
  2. _set_operation()
  3. set()
  4. reset_operation()
  5. run()
  6. run_no_wake()

### Methods for extracting turbine performance after running
7. get_turbine_powers()
8. get_farm_power()
9. get_farm_AEP()
10. get_farm_AEP_with_wind_data()
11. (11--13) get_turbine_(performance properties)()

### Methods for sampling and visualization

  • sampling and viz methods in no particular order

### Utility methods

  • various utility methods in no particular order, but now include assign_hub_height_to_ref_height() and get_turbine_layout()

### Properties

  • various properties in no particular order

### v3 functions that are removed - raise an error if used

  • calculate_wake() and reinitialize(), which raise an error if called.

Regarding the ordering I've chosen for the setting and running:

  • I've first listed the underlying hidden methods that actually set up the Core object
  • Then, I've given set() (the first call a user normally makes after instantiation) and reset_operation() (may not be used very frequently, but is essentially a wrapper around _reinitialize() and does not require having run, so makes sense to me to be here
  • Finally, run() (the user's normal second call) and run_no_wake()

Regarding the ordering I've chosen for extracting turbine performance after running

  • get_turbine_powers(), get_farm_powers(), get_farm_AEP(), and get_farm_AEP_with_wind_data() are essentially in ascending order, as each calls the one before it in its operation.*
  • the other get_turbine...() methods are not called often and are grouped afterwards in no particular order.

@bayc
Copy link
Collaborator

bayc commented Mar 20, 2024

That organization works for me @misi9170 !

@paulf81
Copy link
Collaborator Author

paulf81 commented Mar 20, 2024

This is great @misi9170 thank you!

@rafmudaf if good for you I can merge?

@paulf81 paulf81 merged commit b43c9c5 into NREL:v4 Mar 20, 2024
8 checks passed
@paulf81 paulf81 deleted the feature/floris_model_utils_2 branch March 20, 2024 15:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
v4 Focus of FLORIS v4
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

4 participants