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

⛈️ #15

Merged
merged 1 commit into from
Jun 9, 2024
Merged

⛈️ #15

merged 1 commit into from
Jun 9, 2024

Conversation

leaver2000
Copy link
Owner

@leaver2000 leaver2000 commented Jun 9, 2024

Summary by Sourcery

This pull request introduces several new features, including the broadcast_nz decorator, new element classes, and functions for calculating equilibrium levels, downdraft CAPE, and most unstable parcel properties. It also includes bug fixes, enhancements to existing functions, and updates to the documentation and test cases.

  • New Features:
    • Introduced broadcast_nz decorator to handle broadcasting of input arrays for various functions.
    • Added new classes ElementNd, Element1d, and Element2d to represent elements with generic types and dimensions.
    • Implemented new functions el_lfc, downdraft_cape, and most_unstable_parcel to calculate equilibrium levels, downdraft CAPE, and most unstable parcel properties respectively.
    • Added support for dewpoint_from_specific_humidity function in _ufunc.pyx.
  • Bug Fixes:
    • Fixed off-by-one error in the determination of upper index for intersection calculations.
  • Enhancements:
    • Refactored find_intersections function to use Element2d class for better structure and readability.
    • Improved intersect_1d function in functional.cpp to handle both increasing and decreasing directions and added support for logarithmic x-values.
    • Enhanced parcel_profile and parcel_profile_with_lcl functions to handle both broadcast and matrix modes more efficiently.
    • Updated README.md with detailed type annotations and usage examples for better clarity.
  • Documentation:
    • Updated README.md to include detailed type annotations and usage examples for the parcel_profile function.
  • Tests:
    • Added new test cases in functional_test.py and core_test.py to validate the new features and enhancements.
    • Refactored existing tests to use the new find_intersections function and Element2d class.

Copy link

sourcery-ai bot commented Jun 9, 2024

Reviewer's Guide by Sourcery

This pull request introduces significant changes to the nzthermo library, focusing on enhancing the functionality and performance of various thermodynamic calculations. The changes include the addition of new functions, refactoring of existing ones, and improvements in type annotations and parallel processing using OpenMP and Cython. The modifications span across multiple files, including core Python files, Cython files, and C++ headers and source files.

File-Level Changes

Files Changes
src/nzthermo/core.py
src/nzthermo/functional.py
src/nzthermo/_core.pyx
src/nzthermo/_ufunc.pyi
src/nzthermo/_core.pyi
src/nzthermo/_ufunc.pyx
src/nzthermo/typing.py
Refactored core functionality and added new utility functions and data structures for better performance and readability.
tests/functional_test.py
tests/core_test.py
Updated test cases to match the new function signatures and data structures.
src/lib/functional.cpp
src/lib/libthermo.cpp
src/include/functional.hpp
src/include/common.hpp
src/include/libthermo.hpp
Added new utility functions and refactored existing ones for better performance and readability.

Tips
  • Trigger a new Sourcery review by commenting @sourcery-ai review on the pull request.
  • You can change your review settings at any time by accessing your dashboard:
    • Enable or disable the Sourcery-generated pull request summary or reviewer's guide;
    • Change the review language;
  • You can always contact us if you have any questions or feedback.

@leaver2000 leaver2000 merged commit 87d5940 into master Jun 9, 2024
1 check failed
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @leaver2000 - I've reviewed your changes and they look great!

Here's what I looked at during the review
  • 🟡 General issues: 13 issues found
  • 🟢 Security: all looks good
  • 🟡 Testing: 5 issues found
  • 🟡 Complexity: 1 issue found

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment to tell me if it was helpful.

x, y = self.x, self.y
nx = np.arange(x.shape[0])
if which == "bottom":
idx = np.argmin(~np.isnan(x), axis=1) - 1 # the last non-nan value
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Potential off-by-one error

The calculation np.argmin(~np.isnan(x), axis=1) - 1 might lead to an off-by-one error if all values are NaN. Consider adding a check to handle this case.

*args: _P.args,
**kwargs: _P.kwargs,
) -> _T:
# TODO
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Incomplete TODO comment

The TODO comment is incomplete. Consider providing more details or removing it if it is no longer relevant.

Comment on lines +90 to +91
# TODO: because the _multiple_el_lfc_options function is highly dependent on the output of
# find_intersections combining them into a class is probably the best idea.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Incomplete TODO comment

The TODO comment suggests combining functions into a class but does not provide enough context. Consider elaborating on the plan or removing the comment if it is no longer relevant.

Comment on lines +134 to +136
if mixed_layer_depth is None:
r = mixing_ratio(uf.saturation_vapor_pressure(td0[:, newaxis]), p0[:, newaxis])
else:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Unimplemented feature

The else block raises a NotImplementedError for mixed_layer_depth. Consider implementing this feature or providing more context on when it will be implemented.



@overload
def exactly_2d(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Function name clarity

Consider renaming the function exactly_2d to something more descriptive, such as ensure_2d, to better convey its purpose.

Suggested change
def exactly_2d(
@overload
def ensure_2d(
__x: np.ndarray[Any, np.dtype[np.float_]],
) -> np.ndarray[shape[N, Z], np.dtype[np.float_]]: ...

t0 = temperature[:, 0] # (N,)
dewpoint_start: np.ndarray[shape[N], np.dtype[float_]] | None = None,
) -> ElementNd[shape[N], float_]:
p0, t0 = pressure[:, 0], temperature[:, 0]
if dewpoint_start is None:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): We've found these issues:

Comment on lines +393 to +395
dcape = -(Rd * F.nantrapz(delta, logp, axis=1))

return dcape
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Inline variable that is immediately returned (inline-immediately-returned-variable)

Suggested change
dcape = -(Rd * F.nantrapz(delta, logp, axis=1))
return dcape
return -(Rd * F.nantrapz(delta, logp, axis=1))

Comment on lines +81 to +84
if len(values) == 1:
return values[0]

return tuple(values)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): We've found these issues:

Suggested change
if len(values) == 1:
return values[0]
return tuple(values)
return values[0] if len(values) == 1 else tuple(values)

Comment on lines +102 to +109
values = []
for x in args:
values.append(np.where(np.isnan(x), np.roll(x, 1, axis=1), x))

if len(values) == 1:
return values[0]

def interp_nan(x: NDArray[float_], /, copy: bool = True) -> NDArray[float_]:
if copy is True:
x = x.copy()
mask = np.isnan(x)
x[mask] = np.interp(np.flatnonzero(mask), np.flatnonzero(~mask), x[~mask])
return x
return tuple(values)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): We've found these issues:

Suggested change
values = []
for x in args:
values.append(np.where(np.isnan(x), np.roll(x, 1, axis=1), x))
if len(values) == 1:
return values[0]
def interp_nan(x: NDArray[float_], /, copy: bool = True) -> NDArray[float_]:
if copy is True:
x = x.copy()
mask = np.isnan(x)
x[mask] = np.interp(np.flatnonzero(mask), np.flatnonzero(~mask), x[~mask])
return x
return tuple(values)
values = [np.where(np.isnan(x), np.roll(x, 1, axis=1), x) for x in args]
return values[0] if len(values) == 1 else tuple(values)

equal_nan: bool = False,
) -> NDArray[np.bool_]:
return np.logical_and(op(a, b), np.isclose(a, b, rtol=rtol, atol=atol, equal_nan=equal_nan))
if log_x is True:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Simplify comparison to boolean (simplify-boolean-comparison)

Suggested change
if log_x is True:
if log_x:

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