Skip to content

Avoid tiny numpy arrays in numba: optimize intersections.py (and refactor: "un-scalarize") - #1727

Open
Sevans711 wants to merge 4 commits into
mainfrom
sevans/tinynumpynumba-optimize-intersections.py
Open

Avoid tiny numpy arrays in numba: optimize intersections.py (and refactor: "un-scalarize")#1727
Sevans711 wants to merge 4 commits into
mainfrom
sevans/tinynumpynumba-optimize-intersections.py

Conversation

@Sevans711

@Sevans711 Sevans711 commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Closes #1726 (sub-issue of #1648)

Overview

Optimizes numba routines in uxarray/grid/intersections.py to avoid constructing many tiny numpy arrays inside numba routines, as discussed in #1648. ASV benchmarks seem to show roughly 2x speedup of intersections algorithms, and no performance degradations. Hard to know for sure how gca_gca intersection performance has been affected because those benchmarks are failing on main right now (see discussion on #1688 for details), but the results here at least seem to be the right order of magnitude (roughly 1 μs; latest successes of these benchmarks on main were roughly 1 to 1.5μs).

Additionally, refactors the intersections.py routines to restore prior behavior (from before #1688 merged) of using 3-vector inputs and outputs where possible. To maintain performance improvements, just use tuples instead of allocating tiny numpy arrays. The discussion in PR 1688 clarified the intent was to restore to the pre-scalarized function interfaces where possible without sacrificing performance.

A few changes are within scope of the original issue but the reasoning is not necessarily obvious directly from inspecting the code diff; clarifying here:

  • Previously, gca_gca_intersection output (len(result) == number of intersections) did not match its docstring, which promised shape (2,3) result but filling unused rows with NaNs. This PR updates the implementation to fill unused rows with NaNs, and always return a tuple of 2 length-3 tuples, like ((x1,y1,z1),(x2,y2,z2)), filling with NaNs to represent nonexistent intersection points. (The consistent shape is necessary for the performance optimization here. Numba complains that it "Can't unify return type" if the output length depends on the number of intersections.) The test suite has been updated accordingly, to check for nans instead of len(result).
    • Also updated the docstring of get_number_of_intersections to clarify that it could now be applied to results from gca_gca_intersection too.
  • Removes scalarized versions of methods where non-scalarized versions now suffice. I.e., removed _accux_constlat_scalar (use _accux_constlat instead), and _snap_const_lat_endpoint_xy (use _snap_const_lat_endpoint instead). By using tuples instead of tiny numpy arrays, the "non-scalar" versions also avoid allocation costs, so there is no performance-related need to continue maintaining the scalarized versions.
  • Similarly, updated arcs.py, removing _on_minor_arc_xyz by moving its logic into on_minor_arc, since the scalarized version wasn't being used anywhere anymore (except in benchmarking suite, which has been updated appropriately to use on_minor_arc). Updated on_minor_arc docstring to clarify inputs don't need to be numpy arrays; tuples of length 3 also work just fine.
  • Improved various docstrings, updating docstrings where needed to explain new behavior, but also adding to existing docstrings to clarify meanings and expectations about inputs and outputs, and removing now-obsolete notes about preferring scalarized versions.

PR Checklist

General

  • An issue is created and linked
  • Added appropriate labels (if your uxarray repo permissions allow it)
  • Filled out Overview and Expected Usage (if applicable) sections

Testing & Benchmarking

  • There is adequate test coverage of changes from this PR (add new tests if needed)
  • If this PR could affect performance, ran ASV benchmarks and confirmed they show expected behavior (add a new benchmark if necessary)

Documentation and Examples

  • Docstrings updated with any function changes, and included in all new functions
  • User (public) functions added to docs/api.rst; internal (private) function names start with an underscore (_)
  • [N/A] If touched any notebook files, cleared the output of all cells before committing
  • [N/A] If added new notebook files, put into appropriate directories and referenced in appropriate files

AI Disclosure

AI Usage: GitHub Copilot's inline code suggestions, plus some Claude for numba debugging questions

  • I have tested and take responsibility for all AI-generated content in my PR.

undo many changes from #1688 because tuples are easier to read than scalars, and maintain all performance improvements. (There was some intent there to refactor back to vectors, but it got merged before that happened, with the intent to refactor being pushed as something to be handled later.)

Also optimizes to avoid creating numpy array of shape (2,3) for every gca_gca_intersection() call.

And, updates gca_gca_intersection() output to always be a tuple of 2 length-3 tuples, filling with NaNs, as promised in the docstring, instead of a numpy array with shape depending on number of intersections.
and other relevant intersections methods. Removes scalarized versions of related methods: _accux_constlat_scalar, _snap_const_lat_endpoint_xy, _on_minor_arc_xyz,  (if you really want to provide a bunch of scalars, just convert to tuples at call site; using tuples has the same performance as a scalarized implementation but it means there is no longer any need to maintain two versions of each method.)
@Sevans711 Sevans711 self-assigned this Sep 1, 2026
@Sevans711 Sevans711 added scalability Related to scalability & performance efforts run-benchmark Run ASV benchmark workflow labels Sep 1, 2026
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have improved:

Change Before [5e8021d] After [2baee7e] Ratio Benchmark (Parameter)
- 1.46±0.02μs 680±30ns 0.46 geometry_kernels.GCAConstLatIntersection.time_accux_constlat_kernel
- 1.05±0.02μs 835±20ns 0.80 geometry_kernels.GCAConstLatIntersection.time_gca_const_lat_intersection
- 1.92±0.05μs 849±20ns 0.44 geometry_kernels.GCAConstLatIntersection.time_try_gca_const_lat_intersection
* failed 855±20ns n/a geometry_kernels.GCAGCAIntersection.time_accux_gca_kernel
* failed 1.03±0.02μs n/a geometry_kernels.GCAGCAIntersection.time_gca_gca_intersection
* failed 1.19±0.03μs n/a geometry_kernels.GCAGCAIntersection.time_try_gca_gca_intersection

Benchmarks that have stayed the same:

Change Before [5e8021d] After [2baee7e] Ratio Benchmark (Parameter)
185±4ms 180±2ms 0.97 bench_connectivity.Connectivity.time_edge_face('120km')
11.2±0.08ms 11.6±0.3ms 1.04 bench_connectivity.Connectivity.time_edge_face('480km')
181±0.5ms 229±50ms ~1.26 bench_connectivity.Connectivity.time_edge_node('120km')
10.2±0.06ms 10.3±0.1ms 1.01 bench_connectivity.Connectivity.time_edge_node('480km')
178±0.6ms 179±0.9ms 1.00 bench_connectivity.Connectivity.time_face_edge('120km')
10.6±0.09ms 10.7±0.03ms 1.00 bench_connectivity.Connectivity.time_face_edge('480km')
832±5ms 834±10ms 1.00 bench_connectivity.Connectivity.time_face_face('120km')
52.4±0.6ms 52.9±0.4ms 1.01 bench_connectivity.Connectivity.time_face_face('480km')
66.2±2μs 66.3±2μs 1.00 bench_connectivity.Connectivity.time_face_node('120km')
69.6±5μs 65.0±4μs 0.93 bench_connectivity.Connectivity.time_face_node('480km')
442±6μs 452±10μs 1.02 bench_connectivity.Connectivity.time_n_nodes_per_face('120km')
333±10μs 338±6μs 1.02 bench_connectivity.Connectivity.time_n_nodes_per_face('480km')
189±9ms 181±3ms 0.96 bench_connectivity.Connectivity.time_node_edge('120km')
10.7±0.08ms 10.7±0.1ms 1.00 bench_connectivity.Connectivity.time_node_edge('480km')
77.7±1ms 79.1±2ms 1.02 bench_connectivity.Connectivity.time_node_face('120km')
4.86±0.04ms 4.92±0.05ms 1.01 bench_connectivity.Connectivity.time_node_face('480km')
8.50±0.1ms 10.2±0.2ms ~1.20 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
2.49±0.02ms 2.80±0.1ms ~1.12 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
9.27±9s 12.8±10ms ~0.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
1.86±0.03ms 1.93±0.06ms 1.04 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
57.3k 57.3k 1.00 face_bounds.FaceBounds.track_nbytes_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
12.3k 12.3k 1.00 face_bounds.FaceBounds.track_nbytes_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
123k 123k 1.00 face_bounds.FaceBounds.track_nbytes_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
128 128 1.00 face_bounds.FaceBounds.track_nbytes_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.27M 1.27M 1.00 face_bounds.FaceBounds.track_nbytes_grid_with_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
50.1k 50.1k 1.00 face_bounds.FaceBounds.track_nbytes_grid_with_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
1.48M 1.48M 1.00 face_bounds.FaceBounds.track_nbytes_grid_with_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
712 712 1.00 face_bounds.FaceBounds.track_nbytes_grid_with_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.87M 1.9M 1.01 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
1.88M 1.9M 1.01 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
2.04M 2.07M 1.01 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
38.3k 38.3k 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
336M 336M 1.00 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
366M 365M 1.00 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
338M 338M 1.00 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
336M 336M 1.00 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.17±0.02μs 1.23±0.03μs 1.05 geometry_kernels.AccucrossKernels.time_accucross
2.66±0.04μs 2.62±0.02μs 0.98 geometry_kernels.AccucrossKernels.time_accucross_pair
404±40ns 431±10ns 1.07 geometry_kernels.EFTPrimitives.time_acc_sqrt_re
408±30ns 416±20ns 1.02 geometry_kernels.EFTPrimitives.time_diff_of_products
411±20ns 367±10ns ~0.89 geometry_kernels.EFTPrimitives.time_two_prod
413±20ns 410±20ns 0.99 geometry_kernels.EFTPrimitives.time_two_sum
52.9±0.4μs 53.0±1μs 1.00 geometry_kernels.OrientPredicates.time_on_minor_arc
1.16±0.03μs 1.20±0.06μs 1.04 geometry_kernels.OrientPredicates.time_orient3d_on_sphere
failed failed n/a geometry_samebody.SameBodyConstLat.time_accux_dispatch
failed failed n/a geometry_samebody.SameBodyConstLat.time_accux_kernel
failed failed n/a geometry_samebody.SameBodyConstLat.time_fp64_dispatch
failed failed n/a geometry_samebody.SameBodyConstLat.time_fp64_kernel
47.6±0ms 47.6±0.04ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_dispatch
6.58±0ms 6.57±0ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_kernel
67.5±0ms 67.0±0.1ms 0.99 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_dispatch
5.39±0ms 5.33±0.03ms 0.99 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_kernel
753±2ms 750±7ms 1.00 import.Imports.timeraw_import_uxarray
294M 294M 1.00 import.Imports.track_peakmem_import_uxarray
3.55±0.06ms 3.48±0.05ms 0.98 mpas_ocean.CheckNorm.time_check_norm('120km')
2.19±0.04ms 2.14±0.03ms 0.98 mpas_ocean.CheckNorm.time_check_norm('480km')
816±3ms 809±8ms 0.99 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
50.0±0.2ms 49.3±0.3ms 0.99 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
707±10μs 695±6μs 0.98 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
543±6μs 541±8μs 0.99 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
4.78±0.08ms 4.89±0.06ms 1.02 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('120km')
3.71±0.07ms 3.63±0.05ms 0.98 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('480km')
119±0.5ms 119±0.3ms 1.00 mpas_ocean.ConstructFaceLatLon.time_welzl('120km')
12.1±0.1ms 11.6±0.5ms 0.95 mpas_ocean.ConstructFaceLatLon.time_welzl('480km')
14.0±0.3ms 13.7±0.07ms 0.98 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
927±6μs 939±9μs 1.01 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
10.9±0.02ms 10.0±0.9ms 0.91 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
672±6μs 670±6μs 1.00 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
553±10ms 553±4ms 1.00 mpas_ocean.CrossSections.time_const_lat('120km', 1)
279±6ms 278±2ms 0.99 mpas_ocean.CrossSections.time_const_lat('120km', 2)
145±2ms 144±1ms 0.99 mpas_ocean.CrossSections.time_const_lat('120km', 4)
485±7ms 482±1ms 0.99 mpas_ocean.CrossSections.time_const_lat('480km', 1)
245±4ms 244±3ms 1.00 mpas_ocean.CrossSections.time_const_lat('480km', 2)
126±0.5ms 127±1ms 1.01 mpas_ocean.CrossSections.time_const_lat('480km', 4)
356M 356M 1.00 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('120km', 1)
356M 356M 1.00 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('120km', 2)
356M 356M 1.00 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('120km', 4)
339M 339M 1.00 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('480km', 1)
339M 339M 1.00 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('480km', 2)
339M 339M 1.00 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('480km', 4)
31.7±0.1ms 31.9±0.1ms 1.01 mpas_ocean.DualMesh.time_dual_mesh_construction('120km')
3.34±0.09ms 3.35±0.02ms 1.00 mpas_ocean.DualMesh.time_dual_mesh_construction('480km')
92.1±0.3ms 92.5±1ms 1.00 mpas_ocean.FaceAreas.time_face_areas('120km')
10.2±0.2ms 10.3±0.1ms 1.02 mpas_ocean.FaceAreas.time_face_areas('480km')
229k 229k 1.00 mpas_ocean.FaceAreas.track_nbytes_face_areas('120km')
14.3k 14.3k 1.00 mpas_ocean.FaceAreas.track_nbytes_face_areas('480km')
2.12M 2.12M 1.00 mpas_ocean.FaceAreas.track_peakmem_face_areas('120km')
798k 798k 1.00 mpas_ocean.FaceAreas.track_peakmem_face_areas('480km')
859±2ms 852±2ms 0.99 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
52.8±0.7ms 53.0±1ms 1.00 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
76.8±0.9ms 75.5±0.6ms 0.98 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
6.00±0.08ms 5.91±0.2ms 0.98 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
256±1ms 255±2ms 0.99 mpas_ocean.Gradient.time_gradient('120km')
17.4±0.06ms 17.3±0.2ms 1.00 mpas_ocean.Gradient.time_gradient('480km')
457k 457k 1.00 mpas_ocean.Gradient.track_nbytes_gradient('120km')
28.7k 28.7k 1.00 mpas_ocean.Gradient.track_nbytes_gradient('480km')
5.08M 5.08M 1.00 mpas_ocean.Gradient.track_peakmem_gradient('120km')
328k 328k 1.00 mpas_ocean.Gradient.track_peakmem_gradient('480km')
353M 355M 1.01 mpas_ocean.GradientColdStartRss.peakmem_gradient('120km')
334M 332M 0.99 mpas_ocean.GradientColdStartRss.peakmem_gradient('480km')
467±10μs 461±8μs 0.99 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
205±7μs 207±5μs 1.01 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
638±20μs 669±20μs 1.05 mpas_ocean.Integrate.time_integrate('120km')
513±6μs 520±8μs 1.01 mpas_ocean.Integrate.time_integrate('480km')
18.4M 18.4M 1.00 mpas_ocean.Integrate.track_nbytes_integrate('120km')
1.2M 1.2M 1.00 mpas_ocean.Integrate.track_nbytes_integrate('480km')
172±0.7ms 171±0.7ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
172±0.7ms 172±1ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
171±1ms 173±2ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
13.3±0.2ms 13.3±0.2ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
13.4±0.4ms 13.5±0.09ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
13.5±0.1ms 13.7±0.2ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
176±0.2ms 176±0.6ms 1.00 mpas_ocean.NeighborhoodBuild.time_build('120km', 1.0)
1.03±0s 1.03±0.01s 1.01 mpas_ocean.NeighborhoodBuild.time_build('120km', 15.0)
377±2ms 377±2ms 1.00 mpas_ocean.NeighborhoodBuild.time_build('120km', 5.0)
11.0±0.02ms 11.0±0.05ms 0.99 mpas_ocean.NeighborhoodBuild.time_build('480km', 1.0)
21.1±0.04ms 20.9±0.1ms 0.99 mpas_ocean.NeighborhoodBuild.time_build('480km', 15.0)
13.8±0.05ms 13.8±0.06ms 1.00 mpas_ocean.NeighborhoodBuild.time_build('480km', 5.0)
171±0.2ms 172±0.6ms 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 1.0)
984±2ms 984±1ms 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 15.0)
374±1ms 370±1ms 0.99 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 5.0)
10.7±0.03ms 10.6±0.01ms 0.99 mpas_ocean.NeighborhoodBuild.time_query_radius('480km', 1.0)
20.4±0.03ms 20.3±0.04ms 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('480km', 15.0)
13.5±0.1ms 13.4±0.05ms 0.99 mpas_ocean.NeighborhoodBuild.time_query_radius('480km', 5.0)
1.19 1.19 1.00 mpas_ocean.NeighborhoodBuild.track_mean_neighbors('120km', 1.0)
612.76 612.76 1.00 mpas_ocean.NeighborhoodBuild.track_mean_neighbors('120km', 15.0)
74.17 74.17 1.00 mpas_ocean.NeighborhoodBuild.track_mean_neighbors('120km', 5.0)
1.0 1.0 1.00 mpas_ocean.NeighborhoodBuild.track_mean_neighbors('480km', 1.0)
37.29 37.29 1.00 mpas_ocean.NeighborhoodBuild.track_mean_neighbors('480km', 15.0)
6.57 6.57 1.00 mpas_ocean.NeighborhoodBuild.track_mean_neighbors('480km', 5.0)
728k 728k 1.00 mpas_ocean.NeighborhoodBuild.track_nbytes_neighbors('120km', 1.0)
141M 141M 1.00 mpas_ocean.NeighborhoodBuild.track_nbytes_neighbors('120km', 15.0)
17.4M 17.4M 1.00 mpas_ocean.NeighborhoodBuild.track_nbytes_neighbors('120km', 5.0)
43k 43k 1.00 mpas_ocean.NeighborhoodBuild.track_nbytes_neighbors('480km', 1.0)
563k 563k 1.00 mpas_ocean.NeighborhoodBuild.track_nbytes_neighbors('480km', 15.0)
123k 123k 1.00 mpas_ocean.NeighborhoodBuild.track_nbytes_neighbors('480km', 5.0)
5.72M 5.72M 1.00 mpas_ocean.NeighborhoodBuild.track_peakmem_build('120km', 1.0)
145M 145M 1.00 mpas_ocean.NeighborhoodBuild.track_peakmem_build('120km', 15.0)
21.5M 21.5M 1.00 mpas_ocean.NeighborhoodBuild.track_peakmem_build('120km', 5.0)
362k 362k 1.00 mpas_ocean.NeighborhoodBuild.track_peakmem_build('480km', 1.0)
825k 825k 1.00 mpas_ocean.NeighborhoodBuild.track_peakmem_build('480km', 15.0)
384k 384k 1.00 mpas_ocean.NeighborhoodBuild.track_peakmem_build('480km', 5.0)
46.7±0.3ms 46.5±0.6ms 1.00 mpas_ocean.NeighborhoodDask.time_mean('120km', 'grid_chunks')
23.6±0.04ms 23.6±0.06ms 1.00 mpas_ocean.NeighborhoodDask.time_mean('120km', 'numpy')
43.0±0.8ms 42.9±0.4ms 1.00 mpas_ocean.NeighborhoodDask.time_mean('120km', 'time_chunks')
11.6±0.2ms 11.8±0.2ms 1.01 mpas_ocean.NeighborhoodDask.time_mean('480km', 'grid_chunks')
608±7μs 601±7μs 0.99 mpas_ocean.NeighborhoodDask.time_mean('480km', 'numpy')
8.76±0.2ms 8.50±0.2ms 0.97 mpas_ocean.NeighborhoodDask.time_mean('480km', 'time_chunks')
5.84M 5.91M 1.01 mpas_ocean.NeighborhoodDask.track_peakmem_mean('120km', 'grid_chunks')
2.75M 2.75M 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('120km', 'numpy')
5.69M 5.67M 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('120km', 'time_chunks')
702k 680k 0.97 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'grid_chunks')
177k 177k 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'numpy')
537k 530k 0.99 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'time_chunks')
10.7±0.01s 10.6±0.02s 1.00 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('120km', 'mean')
11.2±0.01s 11.2±0.01s 1.00 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('120km', 'median')
188±0.2ms 189±1ms 1.01 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('480km', 'mean')
196±0.1ms 196±0.3ms 1.00 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('480km', 'median')
1.06±0s 1.07±0s 1.00 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('120km', 'mean')
1.23±0s 1.24±0.01s 1.00 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('120km', 'median')
21.6±0.03ms 21.3±0.08ms 0.98 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('480km', 'mean')
22.9±0.05ms 22.8±0.2ms 1.00 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('480km', 'median')
42.7±0.09ms 42.6±0.04ms 1.00 mpas_ocean.NeighborhoodReduce.time_reduce('120km', 'mean')
208±0.3ms 208±0.4ms 1.00 mpas_ocean.NeighborhoodReduce.time_reduce('120km', 'median')
681±10μs 656±30μs 0.96 mpas_ocean.NeighborhoodReduce.time_reduce('480km', 'mean')
2.12±0.02ms 2.09±0.04ms 0.99 mpas_ocean.NeighborhoodReduce.time_reduce('480km', 'median')
239k 239k 1.00 mpas_ocean.NeighborhoodReduce.track_peakmem_reduce('120km', 'mean')
245k 245k 1.00 mpas_ocean.NeighborhoodReduce.track_peakmem_reduce('120km', 'median')
19.4k 19.4k 1.00 mpas_ocean.NeighborhoodReduce.track_peakmem_reduce('480km', 'mean')
19.9k 19.9k 1.00 mpas_ocean.NeighborhoodReduce.track_peakmem_reduce('480km', 'median')
402±10μs 381±10μs 0.95 mpas_ocean.PointInPolygon.time_face_search_lonlat('120km')
372±7μs 361±6μs 0.97 mpas_ocean.PointInPolygon.time_face_search_lonlat('480km')
372±8μs 350±9μs 0.94 mpas_ocean.PointInPolygon.time_face_search_xyz('120km')
353±8μs 345±5μs 0.98 mpas_ocean.PointInPolygon.time_face_search_xyz('480km')
226±0.06ms 228±0.5ms 1.01 mpas_ocean.RemapDownsample.time_bilinear_remapping
253±2ms 256±0.5ms 1.01 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
15.3±0.07ms 15.3±0.1ms 1.00 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
1.20±0.01s 1.20±0s 1.00 mpas_ocean.RemapUpsample.time_bilinear_remapping
37.8±0.2ms 37.5±0.4ms 0.99 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
14.2±0.2ms 14.0±0.06ms 0.98 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
11.4±0.2ms 10.6±0.1ms 0.93 mpas_ocean.ZonalAverage.time_zonal_average('120km')
5.64±0.1ms 5.31±0.06ms 0.94 mpas_ocean.ZonalAverage.time_zonal_average('480km')
357M 357M 1.00 mpas_ocean.ZonalAveragePeakMem.peakmem_zonal_average('120km')
340M 340M 1.00 mpas_ocean.ZonalAveragePeakMem.peakmem_zonal_average('480km')
6.77±0.2ms 6.55±0.09ms 0.97 quad_hexagon.QuadHexagon.time_open_dataset
5.58±0.05ms 5.49±0.06ms 0.98 quad_hexagon.QuadHexagon.time_open_grid
408 408 1.00 quad_hexagon.QuadHexagon.track_nbytes_open_dataset
392 392 1.00 quad_hexagon.QuadHexagon.track_nbytes_open_grid
73.5k 73.8k 1.00 quad_hexagon.QuadHexagon.track_peakmem_open_dataset
72.8k 73k 1.00 quad_hexagon.QuadHexagon.track_peakmem_open_grid

@Sevans711
Sevans711 marked this pull request as ready for review September 2, 2026 18:37
@Sevans711

Copy link
Copy Markdown
Collaborator Author

Marking as ready for review because tests passed and ASV benchmarks look good. Pinging @cmdupuis3 regarding the gca_gca non-constant-latitude benchmarks, since they are failing on main so it is hard to compare. Do you think another intersections-related benchmark needs to be added as part of this PR or is it okay to move forward as-is?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

run-benchmark Run ASV benchmark workflow scalability Related to scalability & performance efforts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Avoid tiny numpy arrays in numba: optimize intersections.py

1 participant