Skip to content

Optimize _get_faces_constLat_intersection_info - #1799

Draft
cmdupuis3 wants to merge 4 commits into
UXARRAY:mainfrom
cmdupuis3:cmd/optimize_integrate
Draft

cmdupuis3 wants to merge 4 commits into
UXARRAY:mainfrom
cmdupuis3:cmd/optimize_integrate

Conversation

@cmdupuis3

@cmdupuis3 cmdupuis3 commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #1570

Maybe related to #790

Overview

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 (_)

AI Disclosure

AI Usage: Claude Opus 5

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

@cmdupuis3 cmdupuis3 self-assigned this Sep 30, 2026
@cmdupuis3 cmdupuis3 added scalability Related to scalability & performance efforts run-benchmark Run ASV benchmark workflow labels Sep 30, 2026
cmdupuis3 and others added 2 commits September 30, 2026 13:30
Adapt the Numba intersection kernel to two changes on main:

- UXARRAY#1727 changed gca_const_lat_intersection to return a tuple of tuples
  instead of a (2, 3) array, so the kernel now reads points as
  intersections[r][i] rather than intersections[r, i].
- UXARRAY#1705 made the no-intersection and concave-face errors format the face
  array into their messages, which Numba cannot do, so both raises move
  from the kernel into the Python wrapper. The kernel now also returns the
  number of non-dummy edges that the concave check needs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have improved:

Change Before [9609c3a] After [2e252bb] Ratio Benchmark (Parameter)
- 349M 276M 0.79 import.Imports.track_peakmem_import_uxarray
- 349M 314M 0.9 mpas_ocean.GradientColdStartRss.track_peakmem_gradient('480km')
- 2.26±0.01s 15.4±0.6ms 0.01 mpas_ocean.ZonalAverage.time_zonal_average_robust('120km')
- 560±3ms 6.10±0.1ms 0.01 mpas_ocean.ZonalAverage.time_zonal_average_robust('480km')

Benchmarks that have stayed the same:

Change Before [9609c3a] After [2e252bb] Ratio Benchmark (Parameter)
5.37±0.02ms 5.31±0.04ms 0.99 bench_connectivity.Connectivity.time_edge_face('120km')
2.01±0.01ms 1.97±0.01ms 0.98 bench_connectivity.Connectivity.time_edge_face('480km')
4.35±0.01ms 4.33±0.02ms 1.00 bench_connectivity.Connectivity.time_edge_node('120km')
1.58±0ms 1.56±0.01ms 0.99 bench_connectivity.Connectivity.time_edge_node('480km')
4.39±0.05ms 4.37±0.02ms 1.00 bench_connectivity.Connectivity.time_face_edge('120km')
1.58±0.01ms 1.55±0.02ms 0.98 bench_connectivity.Connectivity.time_face_edge('480km')
6.21±0.04ms 6.24±0.06ms 1.01 bench_connectivity.Connectivity.time_face_face('120km')
2.35±0.02ms 2.34±0.03ms 1.00 bench_connectivity.Connectivity.time_face_face('480km')
53.1±0.6μs 53.4±0.7μs 1.01 bench_connectivity.Connectivity.time_face_node('120km')
54.3±1μs 53.3±3μs 0.98 bench_connectivity.Connectivity.time_face_node('480km')
432±8μs 428±10μs 0.99 bench_connectivity.Connectivity.time_n_nodes_per_face('120km')
376±20μs 367±10μs 0.98 bench_connectivity.Connectivity.time_n_nodes_per_face('480km')
5.70±0.03ms 5.68±0.03ms 1.00 bench_connectivity.Connectivity.time_node_edge('120km')
2.06±0.01ms 1.99±0.01ms 0.97 bench_connectivity.Connectivity.time_node_edge('480km')
77.8±1ms 77.3±1ms 0.99 bench_connectivity.Connectivity.time_node_face('120km')
5.16±0.09ms 5.16±0.02ms 1.00 bench_connectivity.Connectivity.time_node_face('480km')
8.40±0.07ms 8.69±0.3ms 1.03 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
2.74±0.05ms 2.73±0.04ms 1.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
7.09±7s 10.1±10ms ~0.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
1.56±0.03ms 1.54±0.01ms 0.99 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.98M 1.98M 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
1.97M 1.97M 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
2.13M 2.14M 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
35.5k 35.5k 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
349M 319M 0.91 face_bounds.FaceBoundsColdStartRss.track_peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
349M 319M 0.91 face_bounds.FaceBoundsColdStartRss.track_peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
349M 320M 0.92 face_bounds.FaceBoundsColdStartRss.track_peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
349M 320M 0.91 face_bounds.FaceBoundsColdStartRss.track_peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.16±0.04μs 1.14±0.01μs 0.99 geometry_kernels.AccucrossKernels.time_accucross
2.64±0.03μs 2.61±0.03μs 0.99 geometry_kernels.AccucrossKernels.time_accucross_pair
461±5ns 446±10ns 0.97 geometry_kernels.EFTPrimitives.time_acc_sqrt_re
436±10ns 436±10ns 1.00 geometry_kernels.EFTPrimitives.time_diff_of_products
396±10ns 391±20ns 0.99 geometry_kernels.EFTPrimitives.time_two_prod
391±10ns 400±20ns 1.02 geometry_kernels.EFTPrimitives.time_two_sum
697±30ns 736±30ns 1.06 geometry_kernels.GCAConstLatIntersection.time_accux_constlat_kernel
746±30ns 772±40ns 1.03 geometry_kernels.GCAConstLatIntersection.time_gca_const_lat_intersection
812±20ns 782±20ns 0.96 geometry_kernels.GCAConstLatIntersection.time_try_gca_const_lat_intersection
812±20ns 842±30ns 1.04 geometry_kernels.GCAGCAIntersection.time_accux_gca_kernel
911±40ns 932±30ns 1.02 geometry_kernels.GCAGCAIntersection.time_gca_gca_intersection
1.06±0.02μs 1.04±0.3μs 0.98 geometry_kernels.GCAGCAIntersection.time_try_gca_gca_intersection
52.0±1μs 51.1±0.5μs 0.98 geometry_kernels.OrientPredicates.time_on_minor_arc
52.3±0.7μs 51.3±0.3μs 0.98 geometry_kernels.OrientPredicates.time_orient3d_on_sphere
3.06±0ms 3.06±0ms 1.00 geometry_samebody.SameBodyConstLat.time_accux_dispatch
1.16±0ms 1.16±0ms 1.00 geometry_samebody.SameBodyConstLat.time_accux_kernel
2.28±0ms 2.30±0.02ms 1.01 geometry_samebody.SameBodyConstLat.time_fp64_dispatch
147±0.1μs 148±0.3μs 1.01 geometry_samebody.SameBodyConstLat.time_fp64_kernel
29.8±0.1ms 29.6±0.2ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_dispatch
6.27±0ms 6.27±0ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_kernel
24.1±0.09ms 23.7±0.2ms 0.98 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_dispatch
861±1μs 860±9μs 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_kernel
919±6ms 916±6ms 1.00 import.Imports.timeraw_import_uxarray
2.50±0.03ms 2.56±0.02ms 1.02 mpas_ocean.CheckNorm.time_check_norm('120km')
2.06±0.01ms 2.03±0.03ms 0.99 mpas_ocean.CheckNorm.time_check_norm('480km')
1.15±0.01ms 1.16±0.01ms 1.01 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
554±20μs 565±10μs 1.02 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
677±6μs 659±20μs 0.97 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
618±10μs 595±10μs 0.96 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
5.39±0.03ms 5.31±0.04ms 0.98 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('120km')
3.89±0.04ms 3.85±0.02ms 0.99 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('480km')
97.3±0.5ms 96.8±0.2ms 1.00 mpas_ocean.ConstructFaceLatLon.time_welzl('120km')
10.2±0.2ms 9.63±0.3ms 0.94 mpas_ocean.ConstructFaceLatLon.time_welzl('480km')
18.6±0.03ms 18.8±0.09ms 1.01 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
962±20μs 979±20μs 1.02 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
9.94±0.04ms 10.0±0.05ms 1.01 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
614±30μs 621±10μs 1.01 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
606±8ms 601±4ms 0.99 mpas_ocean.CrossSections.time_const_lat('120km', 1)
305±1ms 301±1ms 0.99 mpas_ocean.CrossSections.time_const_lat('120km', 2)
157±0.4ms 156±3ms 0.99 mpas_ocean.CrossSections.time_const_lat('120km', 4)
549±10ms 555±4ms 1.01 mpas_ocean.CrossSections.time_const_lat('480km', 1)
274±4ms 280±2ms 1.02 mpas_ocean.CrossSections.time_const_lat('480km', 2)
143±1ms 141±2ms 0.99 mpas_ocean.CrossSections.time_const_lat('480km', 4)
349M 339M 0.97 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('120km', 1)
349M 339M 0.97 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('120km', 2)
349M 339M 0.97 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('120km', 4)
349M 322M 0.92 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('480km', 1)
349M 322M 0.92 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('480km', 2)
349M 322M 0.92 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('480km', 4)
25.9±0.1ms 26.0±0.03ms 1.00 mpas_ocean.DualMesh.time_dual_mesh_construction('120km')
2.96±0.03ms 2.93±0.02ms 0.99 mpas_ocean.DualMesh.time_dual_mesh_construction('480km')
14.3±0.5ms 14.1±0.6ms 0.99 mpas_ocean.FaceAreas.time_face_areas('120km')
4.36±0.4ms 4.28±0.1ms 0.98 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')
713k 715k 1.00 mpas_ocean.FaceAreas.track_peakmem_face_areas('480km')
902±7ms 916±8ms 1.02 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
52.6±0.9ms 52.0±1ms 0.99 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
81.2±0.6ms 83.1±0.4ms 1.02 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
5.13±0.3ms 5.11±0.2ms 1.00 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
13.5±0.1ms 13.2±0.07ms 0.98 mpas_ocean.Gradient.time_gradient('120km')
1.80±0.01ms 1.81±0.01ms 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')
3.2M 3.2M 1.00 mpas_ocean.Gradient.track_peakmem_gradient('120km')
204k 204k 1.00 mpas_ocean.Gradient.track_peakmem_gradient('480km')
349M 335M 0.96 mpas_ocean.GradientColdStartRss.track_peakmem_gradient('120km')
283±10μs 276±10μs 0.97 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
150±5μs 152±9μs 1.02 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
204±6μs 217±10μs 1.06 mpas_ocean.Integrate.time_integrate('120km')
188±1μs 191±8μs 1.02 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')
182±1ms 183±0.8ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
184±1ms 186±1ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
183±1ms 182±2ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
13.2±0.2ms 13.2±0.2ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
13.2±0.1ms 13.0±0.1ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
13.2±0.3ms 12.9±0.08ms 0.98 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
247±1ms 245±0.2ms 0.99 mpas_ocean.NeighborhoodBuild.time_build('120km', 1.0)
1.31±0s 1.30±0s 0.99 mpas_ocean.NeighborhoodBuild.time_build('120km', 15.0)
506±1ms 504±2ms 1.00 mpas_ocean.NeighborhoodBuild.time_build('120km', 5.0)
13.5±0.1ms 13.3±0.02ms 0.98 mpas_ocean.NeighborhoodBuild.time_build('480km', 1.0)
25.4±0.2ms 25.1±0.04ms 0.99 mpas_ocean.NeighborhoodBuild.time_build('480km', 15.0)
16.6±0.09ms 16.5±0.1ms 1.00 mpas_ocean.NeighborhoodBuild.time_build('480km', 5.0)
240±0.5ms 242±1ms 1.01 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 1.0)
1.28±0s 1.28±0s 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 15.0)
501±3ms 500±0.8ms 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 5.0)
12.9±0.03ms 12.9±0.02ms 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('480km', 1.0)
24.8±0.08ms 24.8±0.09ms 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('480km', 15.0)
16.0±0.03ms 16.0±0.06ms 1.00 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)
824k 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)
39.8±0.4ms 39.4±0.2ms 0.99 mpas_ocean.NeighborhoodDask.time_mean('120km', 'grid_chunks')
18.4±0.07ms 18.2±0.05ms 0.99 mpas_ocean.NeighborhoodDask.time_mean('120km', 'numpy')
35.7±0.6ms 35.8±0.3ms 1.00 mpas_ocean.NeighborhoodDask.time_mean('120km', 'time_chunks')
11.0±0.2ms 10.8±0.06ms 0.98 mpas_ocean.NeighborhoodDask.time_mean('480km', 'grid_chunks')
775±10μs 788±7μs 1.02 mpas_ocean.NeighborhoodDask.time_mean('480km', 'numpy')
7.51±0.09ms 7.55±0.1ms 1.00 mpas_ocean.NeighborhoodDask.time_mean('480km', 'time_chunks')
5.83M 5.83M 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('120km', 'grid_chunks')
2.75M 2.75M 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('120km', 'numpy')
5.68M 5.68M 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('120km', 'time_chunks')
177k 177k 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'numpy')
539k 538k 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'time_chunks')
12.5±0.01s 12.5±0s 1.00 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('120km', 'mean')
13.2±0s 13.2±0.01s 1.00 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('120km', 'median')
225±0.6ms 225±0.4ms 1.00 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('480km', 'mean')
231±0.5ms 234±0.9ms 1.01 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('480km', 'median')
1.33±0s 1.33±0s 1.00 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('120km', 'mean')
1.53±0s 1.54±0.01s 1.01 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('120km', 'median')
25.9±0.2ms 25.7±0.1ms 0.99 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('480km', 'mean')
27.1±0.2ms 26.9±0.07ms 0.99 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('480km', 'median')
31.1±0.2ms 31.1±0.2ms 1.00 mpas_ocean.NeighborhoodReduce.time_reduce('120km', 'mean')
228±1ms 228±1ms 1.00 mpas_ocean.NeighborhoodReduce.time_reduce('120km', 'median')
454±20μs 456±30μs 1.00 mpas_ocean.NeighborhoodReduce.time_reduce('480km', 'mean')
1.70±0.03ms 1.70±0.02ms 1.00 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.5k 19.5k 1.00 mpas_ocean.NeighborhoodReduce.track_peakmem_reduce('480km', 'mean')
20k 20k 1.00 mpas_ocean.NeighborhoodReduce.track_peakmem_reduce('480km', 'median')
413±5μs 397±4μs 0.96 mpas_ocean.PointInPolygon.time_face_search_lonlat('120km')
406±10μs 400±10μs 0.99 mpas_ocean.PointInPolygon.time_face_search_lonlat('480km')
372±10μs 397±5μs 1.07 mpas_ocean.PointInPolygon.time_face_search_xyz('120km')
384±5μs 380±10μs 0.99 mpas_ocean.PointInPolygon.time_face_search_xyz('480km')
131±0.1ms 130±0.4ms 0.99 mpas_ocean.RemapDownsample.time_bilinear_remapping
17.0±0.09ms 17.0±0.2ms 1.00 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
15.5±0.09ms 15.4±0.06ms 1.00 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
1.43±0.01s 1.43±0.01s 1.00 mpas_ocean.RemapUpsample.time_bilinear_remapping
25.9±0.2ms 26.1±0.4ms 1.01 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
12.4±0.3ms 12.3±0.3ms 0.99 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
8.32±0.2ms 8.44±0.1ms 1.01 mpas_ocean.ZonalAverage.time_zonal_average('120km')
5.19±0.1ms 5.18±0.1ms 1.00 mpas_ocean.ZonalAverage.time_zonal_average('480km')
349M 341M 0.98 mpas_ocean.ZonalAveragePeakMem.track_peakmem_zonal_average('120km')
349M 324M 0.93 mpas_ocean.ZonalAveragePeakMem.track_peakmem_zonal_average('480km')
1.0276093757186207 1.0104514007263392 0.98 nogil_scaling.GILScaling.track_gil_scaling
7.70±0.2ms 7.40±0.03ms 0.96 quad_hexagon.QuadHexagon.time_open_dataset
6.53±0.2ms 6.41±0.1ms 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.9k 1.01 quad_hexagon.QuadHexagon.track_peakmem_open_dataset
72.6k 73k 1.01 quad_hexagon.QuadHexagon.track_peakmem_open_grid

Benchmarks that have got worse:

Change Before [9609c3a] After [2e252bb] Ratio Benchmark (Parameter)
+ 659k 757k 1.15 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'grid_chunks')

… Numba

The robust path built several tiny polars DataFrames per candidate face,
and that fixed per-call overhead was nearly its whole runtime. Each
latitude is now two Numba calls: one computing every candidate face's
longitude intervals, and one running the overlap sweep line. Results are
bit-identical, and robust zonal means are 52-86x faster, now within
1.3-2.7x of the default path instead of 100-200x slower.

Both new per-latitude kernels release the GIL. Each call does milliseconds
of work, so from 4 threads the robust weights take 1.09x the single-thread
wall time instead of 4.03x.

The private helpers now use arrays instead of DataFrames:
_zonal_face_weights_robust returns the weights, _get_zonal_face_interval
returns (start, end) rows, and _process_overlapped_intervals takes
starts/ends/face indices and returns per-face contributions. A face whose
crossing longitudes cannot be paired into intervals now raises ValueError
rather than polars' ShapeError.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

Unoptimized routines in integrate.py

1 participant