Skip to content

SHARPlib v1.4.0#113

Merged
keltonhalbert merged 66 commits into
mainfrom
release/v1.4.0
Apr 1, 2026
Merged

SHARPlib v1.4.0#113
keltonhalbert merged 66 commits into
mainfrom
release/v1.4.0

Conversation

@keltonhalbert

@keltonhalbert keltonhalbert commented Apr 1, 2026

Copy link
Copy Markdown
Owner

This PR merges all changes made in SHARPlib v1.4.0. This update contains new features, optimizations, bug fixes, and code-maintentance/quality-of-life improvements.

SHARPlib v1.4.0

New Features

  • Lookup table based pseudoadiabatic parcel ascent for all parcel lifters.
    • New struct for computing/storing lookup table data: sharp::lut_data.
      • This new struct is templated on a given parcel lifting functor (e.g. sharp::lifter_cm1) to construct a lookup table in memory. This lookup table can then be used to perform interpolation lookups rather than having to directly solve for moist adiabatic ascent. It is intended that this only be run once ahead of bulk computations, and is thread safe. NOTE: Only works for pseudoadiabatic ascent and will throw an error if using reversible adiabatic ascent.
    • New parcel lifting struct: sharp::lifter_lut.
      • Instead of directly solving the ODEs for moist pseudoadiabatic ascent, it will use a previously constructed lookup table and interpolate to get the parcel temperature. The tradeoff is a slight (but configurable/controlalble) loss of accuracy that is nearly negligible for a huge gain in performance -- especially when processing gridded data. Like the other parcel lifting functors, this one is not thread safe. That is to say, each thread should have its own lifter, but every thread's lifter can share the lookup table data the lifter uses.
      • All functions that take a parcel lifter as an argument support this option out of the box.
  • Calculation of mean_wind now uses native data levels instead of interpolating.
    • This does result in slightly different calculation of values, but the differences are minor. This will technically be more accurate and better represent the actual data being calculated, where the interpolation method had the effect of smoothing profiles out.

Bug Fixes

  • Addressed edge case behavior in integrate_layer_trapz.
    • Some edge cases with missing data could result in buggy and slightly erroneous behavior. A fix was introduced to better handle these rarer edge cases.
  • Improved array size check consistency in the python bindings
    • Users should (hopefully) not notice a difference, but now all python bindings strictly check to make sure that all input arrays have the same size. Previously, this check was applied inconsistently.

Quality of Life/Code Maintenance

  • Refactored the nanobind python bindings to be a little more flexible and maintainable.
    • The python bindings were beginning to get unwieldy. There were manually written functions for every single overload that needed to be specialized on various parcel lifters or layer types. There was also a lot of duplicate code for things like returning python-owned arrays and checking array length. This refactor makes use of template metaprogramming techniques to offload a lot of that work to the compiler, meaning there is only one source of "truth" for a function binding (and its documentation) that needs to be maintained. While end users will not notice any differences, the result is a much easier to maintain set of bindings that are more readily extensible for new features in the future.

…pass, renamed several variables, improved const correctness and data sharing
…ovide either LUT/lifter_lut. Added missing and NaN data checks. Updated documentation. Added test for LUTs
LUT based parcel ascent implemented (#101)
This PR implements a major refactor of how the nanobind python bindings are generated.

With the introduction of the parcel ascent lookup tables, the amount of explicit instantiations for various functions increased dramatically... and would have a much larger increase per additional lifter added in the future. So, it was prudent and worthwhile to look at refactoring the nanobind python bindings. The primary goal was to leverage the strong recurring patterns that occur in the binding functions to generalize code. A new header file, binding_utils.h, is the destination for template metaprogramming code that leverages the compiler to generate bindings based on known structures. This approach has reduced duplicate code, simplified the process for adding new bindings in the future, and better standardized the bindings to be more consistent. It has also had the effect of helping reduce duplicate documentation and documentation errors.
This PR updates `mean_wind` to integrate on native-level data, rather than iterating on interpolated pressure levels. This should result in more accurate/correct computations, and potentially more performant as well. Tests were updated to account for changes in known-values.
This PR addresses some inconsistencies with how `integrate_layer_trapz` handles missing data. It also avoids some edge cases where a divide by zero can occur, and correctly returns MISSING if all data are missing.
@keltonhalbert keltonhalbert added this to the 1.4.0 milestone Apr 1, 2026
@keltonhalbert keltonhalbert self-assigned this Apr 1, 2026
@keltonhalbert

Copy link
Copy Markdown
Owner Author

Once I update the python notebook example (#114), this should be good to merge and release. Hopefully before the end of the day tomorrow!

@keltonhalbert
keltonhalbert merged commit 6f878b3 into main Apr 1, 2026
27 checks passed
@keltonhalbert
keltonhalbert deleted the release/v1.4.0 branch April 1, 2026 21:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant