Skip to content

Scalarized gca_gca_intersection - #1688

Open
cmdupuis3 wants to merge 9 commits into
mainfrom
cmd/gca_no_allocation
Open

Scalarized gca_gca_intersection#1688
cmdupuis3 wants to merge 9 commits into
mainfrom
cmd/gca_no_allocation

Conversation

@cmdupuis3

@cmdupuis3 cmdupuis3 commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Tangent issue to #1623, also related to #1648

Overview

The existing gca_gca_intersection uses four np.ndarray objects of size 3. The overhead incurred by using these python objects is njit compiled loops is significant, and we get about a 2x speedup in there by scalarizing gca_gca_intersection, _try_gca_gca_intersection, and _accux_gca, and using _on_minor_arc_xyz instead of on_minor_arc. That precipitates a ~10% speedup overall of _gca_gca_intersection.

This PR mainly provides scalarized versions of _accux_gca_scalar and _try_gca_gca_intersection. The vector versions are preserved, as established with _accux_constlat, but I think it's reasonable to delete all the vector versions if they aren't being used otherwise. Benchmarks for scalarized routines are added separately, but we could also delete the vector benchmarks if the vector routines go.

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

  • [NA] Adequate tests are created if there is new functionality
  • [NA] Tests are not too basic (such as simply calling a function and nothing else)
  • [NA] Tests cover all major paths in your new functions
  • If this PR could affect performance, ran ASV benchmarks and confirmed they show expected behavior (add a new benchmark if necessary)

Documentation

  • Docstrings have been added to all new functions
  • Docstrings have been updated with any function changes
  • Internal (private) function names start with an underscore (_)

AI Disclosure

AI Usage: Claude Opus 5 / Sonnet 5

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

Add scalar-argument L1/L2 siblings (_accux_gca_scalar,
_try_gca_gca_intersection_scalar) and rewire gca_gca_intersection to them,
cutting 4 heap allocations per edge to 1. Bit-identical output; ~2.7x on
the function in isolation, ~1.24x on serial face bounds.
gca_gca_intersection no longer calls the array-form _accux_gca /
_try_gca_gca_intersection, so benchmarking them no longer reflects the
dispatcher's actual cost. Point at the scalar siblings instead, skipping
gracefully (via skip_benchmark_if) on commits that predate them.
@cmdupuis3 cmdupuis3 added scalability Related to scalability & performance efforts run-benchmark Run ASV benchmark workflow labels Aug 19, 2026
@cmdupuis3

Copy link
Copy Markdown
Collaborator Author

pre-commit.ci autofix

@cmdupuis3 cmdupuis3 linked an issue Aug 19, 2026 that may be closed by this pull request
@cmdupuis3 cmdupuis3 self-assigned this Aug 19, 2026
@cmdupuis3

Copy link
Copy Markdown
Collaborator Author

pre-commit.ci autofix

@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have improved:

Change Before [644dd69] After [385b5ea] Ratio Benchmark (Parameter)
* failed 3.70±0.05μs n/a geometry_kernels.GCAGCAIntersection.time_accux_gca_kernel
* failed 1.29±0.03μs n/a geometry_kernels.GCAGCAIntersection.time_gca_gca_intersection
* failed 3.79±0.04μs n/a geometry_kernels.GCAGCAIntersection.time_try_gca_gca_intersection

Benchmarks that have stayed the same:

Change Before [644dd69] After [385b5ea] Ratio Benchmark (Parameter)
194±0.8ms 193±0.4ms 0.99 bench_connectivity.Connectivity.time_edge_face('120km')
12.3±0.1ms 12.4±0.5ms 1.01 bench_connectivity.Connectivity.time_edge_face('480km')
206±10ms 192±0.7ms 0.93 bench_connectivity.Connectivity.time_edge_node('120km')
11.0±0.1ms 11.0±0.1ms 1.00 bench_connectivity.Connectivity.time_edge_node('480km')
204±10ms 194±0.9ms 0.95 bench_connectivity.Connectivity.time_face_edge('120km')
11.3±0.2ms 11.2±0.02ms 0.99 bench_connectivity.Connectivity.time_face_edge('480km')
878±6ms 882±5ms 1.00 bench_connectivity.Connectivity.time_face_face('120km')
58.8±1ms 56.4±0.8ms 0.96 bench_connectivity.Connectivity.time_face_face('480km')
74.8±4μs 75.0±10μs 1.00 bench_connectivity.Connectivity.time_face_node('120km')
73.3±3μs 70.5±2μs 0.96 bench_connectivity.Connectivity.time_face_node('480km')
435±10μs 425±10μs 0.98 bench_connectivity.Connectivity.time_n_nodes_per_face('120km')
356±6μs 367±10μs 1.03 bench_connectivity.Connectivity.time_n_nodes_per_face('480km')
193±0.6ms 194±1ms 1.00 bench_connectivity.Connectivity.time_node_edge('120km')
11.5±0.1ms 11.3±0.04ms 0.98 bench_connectivity.Connectivity.time_node_edge('480km')
90.7±3ms 84.7±2ms 0.93 bench_connectivity.Connectivity.time_node_face('120km')
5.55±0.2ms 5.35±0.07ms 0.96 bench_connectivity.Connectivity.time_node_face('480km')
8.59±0.1ms 7.78±0.07ms ~0.91 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
2.68±0.04ms 2.59±0.03ms 0.97 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
10.6±10s 9.11±10ms ~0.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
2.23±0.04ms 2.16±0ms 0.96 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.96M 1.95M 0.99 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
1.97M 1.96M 0.99 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
2.13M 2.12M 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
409M 409M 1.00 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
441M 439M 1.00 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
411M 411M 1.00 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
410M 411M 1.00 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.25±0.03μs 1.24±0.02μs 0.99 geometry_kernels.AccucrossKernels.time_accucross
2.76±0.05μs 2.76±0.03μs 1.00 geometry_kernels.AccucrossKernels.time_accucross_pair
451±10ns 431±5ns 0.96 geometry_kernels.EFTPrimitives.time_acc_sqrt_re
425±20ns 451±10ns 1.06 geometry_kernels.EFTPrimitives.time_diff_of_products
391±10ns 376±30ns 0.96 geometry_kernels.EFTPrimitives.time_two_prod
386±10ns 375±9ns 0.97 geometry_kernels.EFTPrimitives.time_two_sum
1.54±0.04μs 1.53±0.05μs 0.99 geometry_kernels.GCAConstLatIntersection.time_accux_constlat_kernel
1.17±0.03μs 1.11±0.03μs 0.94 geometry_kernels.GCAConstLatIntersection.time_gca_const_lat_intersection
1.97±0.02μs 1.98±0.03μs 1.01 geometry_kernels.GCAConstLatIntersection.time_try_gca_const_lat_intersection
52.1±0.2μs 52.1±0.8μs 1.00 geometry_kernels.OrientPredicates.time_on_minor_arc
1.14±0.05μs 1.15±0.01μs 1.01 geometry_kernels.OrientPredicates.time_orient3d_on_sphere
2.75±0.06ms 2.61±0.02ms 0.95 geometry_samebody.SameBodyConstLat.time_accux_dispatch
1.18±0.01ms 1.18±0.01ms 1.00 geometry_samebody.SameBodyConstLat.time_accux_kernel
1.71±0.01ms 1.73±0.01ms 1.01 geometry_samebody.SameBodyConstLat.time_fp64_dispatch
149±1μs 147±0.5μs 0.99 geometry_samebody.SameBodyConstLat.time_fp64_kernel
32.3±0.08ms 32.3±0.02ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_dispatch
10.3±0.02ms 10.3±0.02ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_kernel
26.6±0.04ms 26.5±0.02ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_dispatch
4.90±0.01ms 5.05±0.07ms 1.03 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_kernel
12.0±0.01s 12.3±0.2s 1.03 import.Imports.timeraw_import_uxarray
370M 367M 0.99 import.Imports.track_peakmem_import_uxarray
2.82±0.03ms 2.75±0.03ms 0.97 mpas_ocean.CheckNorm.time_check_norm('120km')
2.26±0.04ms 2.27±0.01ms 1.00 mpas_ocean.CheckNorm.time_check_norm('480km')
846±3ms 830±20ms 0.98 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
54.1±0.5ms 54.6±0.6ms 1.01 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
664±20μs 665±7μs 1.00 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
591±20μs 604±10μs 1.02 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
5.50±0.07ms 5.43±0.02ms 0.99 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('120km')
3.96±0.03ms 4.01±0.03ms 1.01 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('480km')
101±1ms 100±0.3ms 1.00 mpas_ocean.ConstructFaceLatLon.time_welzl('120km')
10.8±0.07ms 10.5±0.3ms 0.97 mpas_ocean.ConstructFaceLatLon.time_welzl('480km')
18.2±0.02ms 18.2±0.01ms 1.00 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
1.06±0.01ms 1.06±0.01ms 1.00 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
10.6±0.01ms 10.6±0.02ms 1.00 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
741±8μs 746±10μs 1.01 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
587±10ms 589±2ms 1.00 mpas_ocean.CrossSections.time_const_lat('120km', 1)
298±3ms 299±3ms 1.00 mpas_ocean.CrossSections.time_const_lat('120km', 2)
154±2ms 155±2ms 1.00 mpas_ocean.CrossSections.time_const_lat('120km', 4)
531±2ms 527±3ms 0.99 mpas_ocean.CrossSections.time_const_lat('480km', 1)
264±1ms 266±4ms 1.01 mpas_ocean.CrossSections.time_const_lat('480km', 2)
138±0.8ms 136±0.3ms 0.99 mpas_ocean.CrossSections.time_const_lat('480km', 4)
429M 429M 1.00 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('120km', 1)
429M 429M 1.00 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('120km', 2)
430M 429M 1.00 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('120km', 4)
412M 412M 1.00 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('480km', 1)
413M 412M 1.00 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('480km', 2)
412M 414M 1.01 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('480km', 4)
25.0±0.1ms 25.1±0.07ms 1.00 mpas_ocean.DualMesh.time_dual_mesh_construction('120km')
3.35±0.05ms 3.19±0.04ms 0.95 mpas_ocean.DualMesh.time_dual_mesh_construction('480km')
61.9±0.2ms 62.0±2ms 1.00 mpas_ocean.FaceAreas.time_face_areas('120km')
5.00±5s 7.78±5ms ~0.00 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')
817k 817k 1.00 mpas_ocean.FaceAreas.track_peakmem_face_areas('480km')
940±6ms 943±3ms 1.00 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
52.7±0.5ms 54.6±2ms 1.04 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
84.6±1ms 83.6±0.5ms 0.99 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
5.86±0.09ms 5.71±0.04ms 0.97 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
177±5ms 178±4ms 1.00 mpas_ocean.Gradient.time_gradient('120km')
12.7±0.1ms 12.3±0.1ms 0.97 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')
424M 424M 1.00 mpas_ocean.GradientColdStartRss.peakmem_gradient('120km')
404M 403M 1.00 mpas_ocean.GradientColdStartRss.peakmem_gradient('480km')
388±10μs 398±10μs 1.03 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
224±20μs 220±7μs 0.99 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
588±9μs 598±8μs 1.02 mpas_ocean.Integrate.time_integrate('120km')
548±30μs 550±10μs 1.00 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')
185±1ms 183±1ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
187±2ms 184±1ms 0.98 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
184±3ms 191±8ms 1.04 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
14.3±0.3ms 14.3±0.4ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
14.4±0.3ms 14.2±0.4ms 0.98 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
14.5±0.07ms 14.1±0.2ms 0.97 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
237±0.3ms 237±0.3ms 1.00 mpas_ocean.NeighborhoodBuild.time_build('120km', 1.0)
1.27±0s 1.27±0s 1.00 mpas_ocean.NeighborhoodBuild.time_build('120km', 15.0)
492±2ms 496±4ms 1.01 mpas_ocean.NeighborhoodBuild.time_build('120km', 5.0)
13.1±0.2ms 12.9±0.03ms 0.99 mpas_ocean.NeighborhoodBuild.time_build('480km', 1.0)
24.9±0.1ms 24.8±0.08ms 0.99 mpas_ocean.NeighborhoodBuild.time_build('480km', 15.0)
16.2±0.08ms 16.1±0.08ms 1.00 mpas_ocean.NeighborhoodBuild.time_build('480km', 5.0)
233±0.3ms 233±0.09ms 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 1.0)
1.26±0s 1.25±0s 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 15.0)
486±0.9ms 487±1ms 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 5.0)
12.6±0.02ms 12.6±0.02ms 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('480km', 1.0)
24.3±0.2ms 24.2±0.05ms 0.99 mpas_ocean.NeighborhoodBuild.time_query_radius('480km', 15.0)
15.8±0.2ms 15.7±0.03ms 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 824k 1.00 mpas_ocean.NeighborhoodBuild.track_peakmem_build('480km', 15.0)
384k 384k 1.00 mpas_ocean.NeighborhoodBuild.track_peakmem_build('480km', 5.0)
48.2±0.6ms 48.7±0.7ms 1.01 mpas_ocean.NeighborhoodDask.time_mean('120km', 'grid_chunks')
22.7±0.09ms 22.6±0.06ms 1.00 mpas_ocean.NeighborhoodDask.time_mean('120km', 'numpy')
44.7±0.6ms 46.6±1ms 1.04 mpas_ocean.NeighborhoodDask.time_mean('120km', 'time_chunks')
16.1±0.5ms 16.1±0.3ms 1.00 mpas_ocean.NeighborhoodDask.time_mean('480km', 'grid_chunks')
701±20μs 718±30μs 1.02 mpas_ocean.NeighborhoodDask.time_mean('480km', 'numpy')
12.3±0.5ms 13.1±0.7ms 1.07 mpas_ocean.NeighborhoodDask.time_mean('480km', 'time_chunks')
5.76M 5.84M 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.69M 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('120km', 'time_chunks')
676k 675k 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'grid_chunks')
177k 177k 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'numpy')
543k 544k 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'time_chunks')
12.3±0.01s 12.4±0.06s 1.01 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('120km', 'mean')
13.0±0s 13.0±0.03s 1.00 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('120km', 'median')
227±0.4ms 228±1ms 1.00 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('480km', 'mean')
235±1ms 234±0.5ms 1.00 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('480km', 'median')
1.31±0s 1.31±0s 1.00 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('120km', 'mean')
1.50±0s 1.50±0s 1.00 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('120km', 'median')
25.9±0.2ms 25.6±0.1ms 0.99 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('480km', 'mean')
27.0±0.2ms 27.0±0.2ms 1.00 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('480km', 'median')
40.2±0.06ms 40.2±0.02ms 1.00 mpas_ocean.NeighborhoodReduce.time_reduce('120km', 'mean')
233±0.2ms 233±0.1ms 1.00 mpas_ocean.NeighborhoodReduce.time_reduce('120km', 'median')
684±30μs 725±20μs 1.06 mpas_ocean.NeighborhoodReduce.time_reduce('480km', 'mean')
2.05±0.02ms 2.09±0.02ms 1.02 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.7k 19.7k 1.00 mpas_ocean.NeighborhoodReduce.track_peakmem_reduce('480km', 'mean')
20.2k 20.2k 1.00 mpas_ocean.NeighborhoodReduce.track_peakmem_reduce('480km', 'median')
408±20μs 415±10μs 1.02 mpas_ocean.PointInPolygon.time_face_search_lonlat('120km')
388±10μs 428±20μs ~1.10 mpas_ocean.PointInPolygon.time_face_search_lonlat('480km')
377±20μs 377±10μs 1.00 mpas_ocean.PointInPolygon.time_face_search_xyz('120km')
361±9μs 394±8μs 1.09 mpas_ocean.PointInPolygon.time_face_search_xyz('480km')
237±0.4ms 234±1ms 0.99 mpas_ocean.RemapDownsample.time_bilinear_remapping
289±0.7ms 284±1ms 0.98 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
15.8±0.06ms 15.8±0.06ms 1.00 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
1.38±0s 1.39±0s 1.01 mpas_ocean.RemapUpsample.time_bilinear_remapping
37.6±0.3ms 35.0±2ms 0.93 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
12.4±0.2ms 12.6±0.2ms 1.02 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
433M 431M 0.99 mpas_ocean.ZonalAveragePeakMem.peakmem_zonal_average('120km')
414M 413M 1.00 mpas_ocean.ZonalAveragePeakMem.peakmem_zonal_average('480km')
6.79±0.04ms 7.25±0.3ms 1.07 quad_hexagon.QuadHexagon.time_open_dataset
5.81±0.1ms 6.27±0.1ms 1.08 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.7k 73.8k 1.00 quad_hexagon.QuadHexagon.track_peakmem_open_dataset
72.8k 72.8k 1.00 quad_hexagon.QuadHexagon.track_peakmem_open_grid

Benchmarks that have got worse:

Change Before [644dd69] After [385b5ea] Ratio Benchmark (Parameter)
+ 38.3k 52.8k 1.38 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
+ 9.27±0.06ms 10.4±0.1ms 1.12 mpas_ocean.ZonalAverage.time_zonal_average('120km')
+ 4.86±0.08ms 5.86±0.1ms 1.2 mpas_ocean.ZonalAverage.time_zonal_average('480km')

@cmdupuis3

Copy link
Copy Markdown
Collaborator Author

Before I remove the backwards-compatibility (which will be redundant after this merges), here are the CI benchmarks for gca_gca intersections, showing about a 10% speedup.

Benchmarks that have improved:

Change Before [9d5bcdb] After [e0bfadc] Ratio Benchmark (Parameter)
* failed 3.35±0.03μs n/a geometry_kernels.GCAGCAIntersection.time_accux_gca_kernel
- 1.26±0.03μs 1.13±0.02μs 0.90 geometry_kernels.GCAGCAIntersection.time_gca_gca_intersection
* failed 3.46±0.05μs n/a geometry_kernels.GCAGCAIntersection.time_try_gca_gca_intersection
- 216±10μs 195±5μs 0.91 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')

@cmdupuis3

Copy link
Copy Markdown
Collaborator Author

I'm wondering if we need the vector-valued _accux_gca, _try_gca_gca_intersection, and _accux_constlat anymore, since we're only really using the scalarized versions at this point?

@cmdupuis3
cmdupuis3 marked this pull request as ready for review August 24, 2026 22:39
@rajeeja

rajeeja commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

I'm wondering if we need the vector-valued _accux_gca, _try_gca_gca_intersection, and _accux_constlat anymore, since we're only really using the scalarized versions at this point?

Yes, drop all three. _accux_constlat goes outright since gca_const_lat_intersection already uses _accux_constlat_scalar; the GCA/GCA pair needs a _accux_gca_scalar (six floats in/out, status logic inlined) first so gca_gca_intersection has a scalar path, then _accux_gca and _try_gca_gca_intersection can go.

@cmdupuis3

Copy link
Copy Markdown
Collaborator Author

I took out two of them, but I left _accux_constlat since it's a little stickier and not technically in-scope for this PR.

@erogluorhan

erogluorhan commented Aug 25, 2026

Copy link
Copy Markdown
Member

Before I remove the backwards-compatibility (which will be redundant after this merges), here are the CI benchmarks for gca_gca intersections, showing about a 10% speedup.

Benchmarks that have improved:

Change Before [9d5bcdb] After [e0bfadc] Ratio Benchmark (Parameter)

  • failed 3.35±0.03μs n/a geometry_kernels.GCAGCAIntersection.time_accux_gca_kernel
  • 1.26±0.03μs 1.13±0.02μs 0.90 geometry_kernels.GCAGCAIntersection.time_gca_gca_intersection
  • failed 3.46±0.05μs n/a geometry_kernels.GCAGCAIntersection.time_try_gca_gca_intersection
  • 216±10μs 195±5μs 0.91 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')

Everything in this PR looks good to me, and I will approve it once actions complete, but one question about these benchmarks: How much of confidence do we have about these microsecond times, e.g. measuring process overhead vs actual operations?

@cmdupuis3

Copy link
Copy Markdown
Collaborator Author

In general, a little less than larger ones, but in this case, you can check the last few commits and see the benchmarks are consistently about 10% lower, so I'm confident it's not a fluke here.

@erogluorhan erogluorhan added run-benchmark Run ASV benchmark workflow and removed run-benchmark Run ASV benchmark workflow labels Aug 25, 2026
@erogluorhan
erogluorhan self-requested a review August 25, 2026 17:43
@cmdupuis3
cmdupuis3 requested a review from rajeeja August 25, 2026 21:27
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.

Scalarizing gca_gca_intersection

3 participants