Repository navigation
Implement new wind orographic correction method - #2447
Conversation
* Updating wind downscaling code to use more descriptive variable names and function names, etc * Adding name to CLA * Adding myself to .mailmap * Adding myself to .mailmap * Adding myself to .mailmap * Adding myself to .mailmap * Trying without space * Fixing unit tests * Updating error log message * Attempting to fix .mailmap by using anon github email * Changing u* -> u_star for clarity * Changing missing spatial coordinates to match old behaviour * Update cli * Pin proj and fix numpy-update-related test failures (#2326) * Pinning proj to 9.7.1 * Adding myself to contributors list * Fix numpy-update test failures * Reverting float() change * Making variable names clearer * Removing duplicate entry * Updating variable names to be more intuitive * Improving variable names and docstrings * Updating variable names in unit tests to match code
* Updating wind downscaling code to use more descriptive variable names and function names, etc * Adding name to CLA * Adding myself to .mailmap * Adding myself to .mailmap * Adding myself to .mailmap * Adding myself to .mailmap * Trying without space * Fixing unit tests * Updating error log message * Attempting to fix .mailmap by using anon github email * Initial commit to split out HC + RC * Renaming tests to make them more descriptive * Working on unit tests * Changing u* -> u_star for clarity * Changing missing spatial coordinates to match old behaviour * Update cli * Changing name in __init__.py * Making RC fail when no roughness length supplied * Updating tests * Updating docstrings of unit tests to match test names * Making variable names clearer * Removing duplicate entry * Updating variable names to be more intuitive * Improving variable names and docstrings * Updating variable names in unit tests to match code * Fixing to work with surface data * Addressing PR review comments * Further tidying * Fixing acceptance tests * Updating unit test to fix HC + RC behaviour
mo-jbeaver
left a comment
There was a problem hiding this comment.
Overall, the function and tests are very comprehensive. The majority of the comments I have added are about the docstrings or adding comments for clarity. Unit test ran successfully, acceptance tests failed due to checksum mismatches. There was also a list of failures from when I ran srun_tests, that maybe a result of the branch being out of date.
|
Thank you for such a careful and detailed review @mo-jbeaver 😊 It may take me a while to work through these, but only because I want to go through each comment properly! |
|
Thanks you so much for such a comprehensive review. 😊 The acceptance tests are passing for me locally, so I wonder if the checksum mismatches could be due to the test-data version being used? Are you running against the updated test data in the linked PR? If not, I'd expect checksum failures because the accepted outputs have changed (I'm a bit out of my depth here with the acceptance tests though, so if that's not the cause, I might need to crowd-source some debugging!) metoppv/improver_test_data#148 Yes, I think the srun_tests failures may also be related if the branch is a little out of date. |
|
Thanks for the update @mo-AliceLake , I'm happy with the code changes made. Both the unit and acceptance tests passed but the srun_tests (which runs all unit and acceptance tests to look for conflicts) failed.
Hopefully, that should explain the errors I was getting but again happy with the code changes made. |
|
Thanks so much for your help @mo-jbeaver 😊 Your explanations were enough to help me work through everything in the end! I've now merged master into both branches (here and the improver_test_data PR), removed the stale wind_downscaling checksums, and updated test_compare.py::test_same to use the updated wind-orographic-correction orography files. The only remaining checksum difference to me seems to be visibility-combine-cloud-base/spot/kgo.nc. That appears to be because its test-data branch mobt_1291_visibility_cloud_base_update hasn't yet been merged into improver_test_data master yet (so it's unrelated to this PR) - I've asked if that can be merged. - Edit: This is now merged. 🙂 |
mo-jbeaver
left a comment
There was a problem hiding this comment.
Happy with all the updates made and the tests all passed successfully.
bayliffe
left a comment
There was a problem hiding this comment.
I am by no means finished with this review, but submitting to ensure the comments thus far are not lost. Please ignore until I am finished.
| if cube_heights.size == 1: | ||
| raise ValueError( | ||
| "Cannot interpolate wind_profile_cube to target_height_levels " | ||
| "when only one source height is available." | ||
| ) |
There was a problem hiding this comment.
I wondered why this check lived here rather than in the process method when the data is first ingested and then I noticed that this is a standalone function, as are many of these rather than methods on a plugin. Is there a reason for these to be standalone functions rather than components of a broader plugin as is more typical within IMPROVER?
There was a problem hiding this comment.
"Is there a reason for these to be standalone functions rather than components of a broader plugin as is more typical within IMPROVER?" - No reason, I've just never really coded with plugins. I'll try and learn a bit more then refactor.
bayliffe
left a comment
There was a problem hiding this comment.
These are the rest of my comments for this pass. Thanks for all of this work.
| max_friction_velocity=5.0, | ||
| ) | ||
|
|
||
| assert np.all(result > 0.0) |
There was a problem hiding this comment.
What in this test setup would cause the values to become negative and thus demonstrates that somehow this code ensures only positive values are returned? I cannot see it.
|
@bayliffe - thank you so much for such a comprehensive review, I really appreciate the time you've put into this. I've made a lot of changes off the back of this, which I think makes the script much better, but I realise also is quite a significant refactor... so it's probably not the easiest to re-review. With that in mind, the things I would really appreciate your thoughts on:
Thanks again 😊 |
gavinevans
left a comment
There was a problem hiding this comment.
Thanks @mo-AliceLake 👍
I'm just adding a brief comment about the plugin style, as requested. I'm not commenting on the science in any way. I'd say that the plugin mainly looks like I would expect, but I've noted a few things for consideration below.
| - apply the correction | ||
| """ | ||
|
|
||
| def __init__( |
There was a problem hiding this comment.
Just a brief comment on the general structure of this plugin, I'm not commenting on the science in any way. From a plugin layout perspective, I would expect:
- The process method to be the last method in the class.
- Cubes to be passed into process method and configurable variables to be passed into the
__init__. In this plugin, it seems like onlytarget_height_levelscould fall into that category. It seems like there are potentially a lot of variables that could be exposed in the__init__but these must currently rely on the default values specified in the various methods e.g._fit_log_wind_profile. - I'd expect that when calling methods on the class from within the class, the self.method_name style would be used, rather than OrographicWindCorrection.method_name.
- The plugin does seem complicated scientifically, so you could consider splitting the class into multiple classes. There seem to be 6 steps to the approach based on the documentation, so you could split it like that, or you could split it into differently. I definitely don't know enough about the approach to suggest a coherent way to split the plugin.
There was a problem hiding this comment.
Thank you @gavinevans , this is incredibly helpful 😊
I have refactored (again!) following your suggestions: now has multiple classes, decided best split as _TerrainDescriptionMethods, _WindProfileMethods and _TerrainResponseMethods.
bayliffe
left a comment
There was a problem hiding this comment.
Co-pilot notes that:
Target heights are not explicitly checked for positivity, duplicates, or being within the source profile’s range. In particular, out-of-range targets can result in non-finite output rather than a targeted exception.
It looks as though out of range target height levels (500m turbine?!) could lead to nan wind speeds, so you may want to include a check against these.
Thanks for the refactor, I think this much better fits our typical structure. I've not revisited the science code as I believe that is essentially unchanged.
| "uncorrected_wind_cube must include heights up to at least 300 m " | ||
| "above ground level, but max height provided is " | ||
| f"{np.max(self.original_height_levels)} m." | ||
| ) |
There was a problem hiding this comment.
You've not checked that the lower limit is present and I'm pretty sure you need 0m for this method to work so you can figure out your roughness, is that right? Should a check therefore be included?
There was a problem hiding this comment.
Actually I need at least two levels 0 <level height <= 300 (scientifically probably more than two, but I think that is up to a user to know that it will not interpolate well if they're passing in sparse data?!).
e.g. wind_speed_on_height_levels from StaGE starts at 5m (not 0m).
I've made the docstrings more explicit about this requirement and included a check for this.
bayliffe
left a comment
There was a problem hiding this comment.
The tiniest of questions, but I think this looks good. Thanks @mo-AliceLake.
| ), | ||
| # Wind | ||
| "wind_speed": Bounds((0, 50), "m s^-1"), | ||
| "wind_speed_at_hubheight": Bounds((0, 50), "m s^-1"), |
There was a problem hiding this comment.
I think this should be a suitable limit (~112mph), but I just want to check whether at ~300m we might need more headroom given that the wind is essentially unaffected by surface friction?
There was a problem hiding this comment.
I did actually think about this (and convert it to mph to get a sense check) - the honest answer is that without obs I had no idea, and just thought "112mph feels quite big".
I've now (this week!) got some obs data for a wind farm in Scotland and for a wind farm in Northern Ireland for 2024, so had a look in there as a sense-check, and they max at 52m/s, so yes I definitely need to increase this. Have chosen 100 m/s. Thank you for flagging. 🙂
bayliffe
left a comment
There was a problem hiding this comment.
Thanks for all the work on this @mo-AliceLake, it's looking really good. Happy to approve.
Addresses https://github.com/metoppv/mo-blue-team/issues/1277
Description
Implements the new wind orographic correction method within the IMPROVER repository, replacing the legacy wind downscaling approach.
This PR:
Testing
Test coverage