Skip to content

Assigning connectivities based on UGRID conventions - #1736

Open
dylannelson wants to merge 3 commits into
mainfrom
n2-naming
Open

Assigning connectivities based on UGRID conventions#1736
dylannelson wants to merge 3 commits into
mainfrom
n2-naming

Conversation

@dylannelson

@dylannelson dylannelson commented Sep 8, 2026

Copy link
Copy Markdown
Member

Closes #1717
Closes #1725
Why two in one? The reason for closing both in one PR is due to them being caused by the same problem. Having 3 dimensions in pre-existing connectivities results in swap_dims quietly breaking, causing both the issues seen above. By applying some cleaning both before and after swap_dims is called, both issues are solved together. As far as I can see, there is no evidence we would see one of the above errors without the other, and since the solution is in the same location, we may as well solve it once and here. Originally I solved the first one alone, but solving the 2nd would basically require deleting the whole original solution, and replacing it with a more general one. So rather than pushing 1 solution to main, deleting it, and pushing another, I say we just push this single refined solution (assuming it works as intended)

Overview

_read_ugrid renamed the trailing dimension of face_node_connectivity to n_max_face_nodes and left every other connectivity's equivalent dimension as whatever the source file called it. Reading fesom.mesh.diag.nc, which names those axes n3 and n2:

Connectivity File's name for the axis dims Before dims After
face_node_connectivity n3 ('n_face', 'n_max_face_nodes') unchanged
face_edge_connectivity n3 ('n_face', 'n_max_face_nodes') ('n_face', 'n_max_face_edges')
face_face_connectivity n3 ('n_face', 'n_max_face_nodes') ('n_face', 'n_max_face_faces')
edge_node_connectivity n2 ('n_edge', 'n2') ('n_edge', 'two')
edge_face_connectivity n2 ('n_edge', 'n2') ('n_edge', 'two')

Each connectivity's trailing dimension is now mapped to the name ugrid.CONNECTIVITY gives it, rather than one being hardcoded and the rest left alone. In this FESOM file (which is read in through the UGRID path) it uses one size-3 n3 for all three face connectivities. swap_dims call cannot express all 3, so the first connectivity renames it for the whole dataset and the remainder are renamed per variable. face_node_connectivity is first, so variables that are not connectivity all get n_max_face_nodes

Expected Usage

import uxarray as ux

uxgrid = ux.open_grid("fesom.mesh.diag.nc")

# the edge connectivities carried the file's own name for the trailing axis
uxgrid.edge_node_connectivity.dims
# before: ('n_edge', 'n2')
# after:  ('n_edge', 'two')

uxgrid.edge_face_connectivity.dims
# before: ('n_edge', 'n2')
# after:  ('n_edge', 'two')

# the face connectivities all shared one size-3 dimension
uxgrid.face_edge_connectivity.dims
# before: ('n_face', 'n_max_face_nodes')
# after:  ('n_face', 'n_max_face_edges')

# so indexing those axes by name now works
uxgrid.edge_node_connectivity.isel(two=0)
# before: ValueError: Dimensions {'two'} do not exist
# after:  the first node of every edge

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

  • [N/A] Docstrings updated with any function changes, and included in all new functions
  • [N/A] 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: Claude

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

contains test and explanation for how edge_node_connectivity and edge_face_connectivity interact with the trailing dimension "two"
@dylannelson dylannelson added run-benchmark Run ASV benchmark workflow extra dims Handling of non-grid dimensions, such as time or altitude labels Sep 8, 2026
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have stayed the same:

Change Before [38b33d8] <v2026.09.0> After [031b15a] Ratio Benchmark (Parameter)
5.66±0.2ms 5.85±0.3ms 1.03 bench_connectivity.Connectivity.time_edge_face('120km')
2.00±0.06ms 2.03±0.1ms 1.01 bench_connectivity.Connectivity.time_edge_face('480km')
4.57±0.1ms 4.72±0.3ms 1.03 bench_connectivity.Connectivity.time_edge_node('120km')
1.57±0.02ms 1.58±0.06ms 1.00 bench_connectivity.Connectivity.time_edge_node('480km')
4.61±0.2ms 4.65±0.3ms 1.01 bench_connectivity.Connectivity.time_face_edge('120km')
1.57±0.04ms 1.58±0.04ms 1.00 bench_connectivity.Connectivity.time_face_edge('480km')
6.78±0.09ms 6.91±0.1ms 1.02 bench_connectivity.Connectivity.time_face_face('120km')
2.42±0.05ms 2.49±0.1ms 1.03 bench_connectivity.Connectivity.time_face_face('480km')
68.5±4μs 70.7±3μs 1.03 bench_connectivity.Connectivity.time_face_node('120km')
66.6±5μs 72.3±3μs 1.09 bench_connectivity.Connectivity.time_face_node('480km')
485±8μs 480±20μs 0.99 bench_connectivity.Connectivity.time_n_nodes_per_face('120km')
416±9μs 431±20μs 1.03 bench_connectivity.Connectivity.time_n_nodes_per_face('480km')
6.23±0.2ms 6.12±0.2ms 0.98 bench_connectivity.Connectivity.time_node_edge('120km')
2.01±0.03ms 2.03±0.05ms 1.01 bench_connectivity.Connectivity.time_node_edge('480km')
85.3±6ms 81.5±7ms 0.95 bench_connectivity.Connectivity.time_node_face('120km')
5.20±0.3ms 5.36±0.4ms 1.03 bench_connectivity.Connectivity.time_node_face('480km')
8.41±0.04ms 8.70±0.4ms 1.04 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
2.72±0.08ms 2.81±0.07ms 1.03 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
10.2±10s 9.97±10ms ~0.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
2.21±0.03ms 2.17±0.06ms 0.98 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.99M 1.99M 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
2M 2M 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
2.16M 2.16M 1.00 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'))
335M 335M 1.00 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
365M 367M 1.01 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
336M 337M 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.20±0.07μs 1.22±0.02μs 1.02 geometry_kernels.AccucrossKernels.time_accucross
2.70±0.05μs 2.67±0.02μs 0.99 geometry_kernels.AccucrossKernels.time_accucross_pair
440±10ns 446±30ns 1.01 geometry_kernels.EFTPrimitives.time_acc_sqrt_re
456±10ns 431±10ns 0.95 geometry_kernels.EFTPrimitives.time_diff_of_products
391±10ns 391±10ns 1.00 geometry_kernels.EFTPrimitives.time_two_prod
390±20ns 376±9ns 0.96 geometry_kernels.EFTPrimitives.time_two_sum
691±10ns 671±10ns 0.97 geometry_kernels.GCAConstLatIntersection.time_accux_constlat_kernel
772±30ns 741±9ns 0.96 geometry_kernels.GCAConstLatIntersection.time_gca_const_lat_intersection
842±30ns 802±20ns 0.95 geometry_kernels.GCAConstLatIntersection.time_try_gca_const_lat_intersection
787±20ns 817±20ns 1.04 geometry_kernels.GCAGCAIntersection.time_accux_gca_kernel
927±10ns 957±30ns 1.03 geometry_kernels.GCAGCAIntersection.time_gca_gca_intersection
1.04±0.03μs 1.05±0.03μs 1.01 geometry_kernels.GCAGCAIntersection.time_try_gca_gca_intersection
52.6±0.5μs 52.9±0.1μs 1.00 geometry_kernels.OrientPredicates.time_on_minor_arc
1.10±0.06μs 1.12±0.05μs 1.02 geometry_kernels.OrientPredicates.time_orient3d_on_sphere
3.07±0.01ms 3.07±0.01ms 1.00 geometry_samebody.SameBodyConstLat.time_accux_dispatch
1.18±0ms 1.18±0ms 1.00 geometry_samebody.SameBodyConstLat.time_accux_kernel
2.31±0ms 2.31±0.01ms 1.00 geometry_samebody.SameBodyConstLat.time_fp64_dispatch
153±1μs 152±2μs 0.99 geometry_samebody.SameBodyConstLat.time_fp64_kernel
29.6±0.05ms 29.4±0.01ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_dispatch
6.30±0.01ms 6.32±0ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_kernel
23.8±0.02ms 23.7±0ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_dispatch
913±20μs 888±5μs 0.97 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_kernel
882±40ms 936±10ms 1.06 import.Imports.timeraw_import_uxarray
292M 292M 1.00 import.Imports.track_peakmem_import_uxarray
2.77±0.1ms 2.88±0.06ms 1.04 mpas_ocean.CheckNorm.time_check_norm('120km')
2.22±0.06ms 2.37±0.1ms 1.07 mpas_ocean.CheckNorm.time_check_norm('480km')
1.21±0.04ms 1.30±0.02ms 1.08 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
596±40μs 655±10μs 1.10 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
711±40μs 738±40μs 1.04 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
666±40μs 679±60μs 1.02 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
5.41±0.06ms 5.53±0.05ms 1.02 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('120km')
4.01±0.1ms 4.20±0.05ms 1.05 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('480km')
99.3±0.5ms 99.9±0.4ms 1.01 mpas_ocean.ConstructFaceLatLon.time_welzl('120km')
10.7±0.1ms 10.7±0.3ms 1.01 mpas_ocean.ConstructFaceLatLon.time_welzl('480km')
18.2±0.07ms 18.2±0.05ms 1.00 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
1.05±0.04ms 1.11±0.04ms 1.05 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
10.6±0.06ms 10.7±0.05ms 1.01 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
735±50μs 785±20μs 1.07 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
602±30ms 635±30ms 1.06 mpas_ocean.CrossSections.time_const_lat('120km', 1)
306±20ms 316±20ms 1.04 mpas_ocean.CrossSections.time_const_lat('120km', 2)
156±6ms 162±4ms 1.04 mpas_ocean.CrossSections.time_const_lat('120km', 4)
549±20ms 564±20ms 1.03 mpas_ocean.CrossSections.time_const_lat('480km', 1)
276±10ms 284±10ms 1.03 mpas_ocean.CrossSections.time_const_lat('480km', 2)
140±4ms 146±9ms 1.04 mpas_ocean.CrossSections.time_const_lat('480km', 4)
355M 355M 1.00 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('120km', 1)
355M 355M 1.00 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('120km', 2)
355M 355M 1.00 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('120km', 4)
338M 338M 1.00 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('480km', 1)
338M 338M 1.00 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('480km', 2)
338M 338M 1.00 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('480km', 4)
25.0±0.4ms 25.1±0.06ms 1.00 mpas_ocean.DualMesh.time_dual_mesh_construction('120km')
3.22±0.1ms 3.26±0.06ms 1.01 mpas_ocean.DualMesh.time_dual_mesh_construction('480km')
14.7±0.9ms 15.0±0.9ms 1.02 mpas_ocean.FaceAreas.time_face_areas('120km')
4.67±0.3ms 4.94±0.06ms 1.06 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')
728k 729k 1.00 mpas_ocean.FaceAreas.track_peakmem_face_areas('480km')
932±6ms 967±5ms 1.04 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
51.6±0.7ms 52.6±0.8ms 1.02 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
84.2±0.8ms 86.3±0.8ms 1.02 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
6.05±0.8ms 6.87±0.5ms ~1.13 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
14.8±0.4ms 16.1±0.5ms 1.08 mpas_ocean.Gradient.time_gradient('120km')
2.15±0.1ms 2.32±0.06ms 1.08 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.43M 3.43M 1.00 mpas_ocean.Gradient.track_peakmem_gradient('120km')
218k 218k 1.00 mpas_ocean.Gradient.track_peakmem_gradient('480km')
351M 350M 1.00 mpas_ocean.GradientColdStartRss.peakmem_gradient('120km')
330M 330M 1.00 mpas_ocean.GradientColdStartRss.peakmem_gradient('480km')
394±30μs 404±8μs 1.02 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
211±30μs 271±20μs ~1.28 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
577±50μs 612±20μs 1.06 mpas_ocean.Integrate.time_integrate('120km')
505±60μs 579±20μs ~1.15 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±3ms 186±2ms 1.02 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
182±2ms 187±2ms 1.03 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
182±4ms 187±2ms 1.03 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
14.0±0.7ms 15.0±0.07ms 1.07 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
13.9±0.7ms 15.1±0.2ms 1.08 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
14.0±0.7ms 15.0±0.1ms 1.08 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
237±1ms 241±0.6ms 1.02 mpas_ocean.NeighborhoodBuild.time_build('120km', 1.0)
1.27±0.01s 1.28±0s 1.01 mpas_ocean.NeighborhoodBuild.time_build('120km', 15.0)
492±4ms 499±4ms 1.01 mpas_ocean.NeighborhoodBuild.time_build('120km', 5.0)
13.0±0.2ms 13.2±0.1ms 1.01 mpas_ocean.NeighborhoodBuild.time_build('480km', 1.0)
25.0±0.5ms 25.2±0.1ms 1.01 mpas_ocean.NeighborhoodBuild.time_build('480km', 15.0)
16.1±0.2ms 16.5±0.1ms 1.03 mpas_ocean.NeighborhoodBuild.time_build('480km', 5.0)
233±2ms 242±0.8ms 1.04 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 1.0)
1.25±0.01s 1.27±0s 1.01 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 15.0)
487±2ms 495±3ms 1.02 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 5.0)
12.8±0.1ms 12.8±0.04ms 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('480km', 1.0)
24.3±0.3ms 24.6±0.08ms 1.01 mpas_ocean.NeighborhoodBuild.time_query_radius('480km', 15.0)
15.8±0.3ms 15.9±0.04ms 1.01 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)
44.3±0.8ms 45.6±1ms 1.03 mpas_ocean.NeighborhoodDask.time_mean('120km', 'grid_chunks')
22.6±0.2ms 22.7±0.02ms 1.01 mpas_ocean.NeighborhoodDask.time_mean('120km', 'numpy')
40.9±1ms 41.4±0.7ms 1.01 mpas_ocean.NeighborhoodDask.time_mean('120km', 'time_chunks')
11.9±0.6ms 13.1±0.1ms 1.10 mpas_ocean.NeighborhoodDask.time_mean('480km', 'grid_chunks')
662±20μs 703±10μs 1.06 mpas_ocean.NeighborhoodDask.time_mean('480km', 'numpy')
8.67±0.5ms 9.50±0.2ms 1.10 mpas_ocean.NeighborhoodDask.time_mean('480km', 'time_chunks')
5.84M 5.76M 0.99 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')
633k 680k 1.07 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'grid_chunks')
177k 177k 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'numpy')
544k 530k 0.97 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'time_chunks')
12.4±0.09s 13.2±0.1s 1.07 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('120km', 'mean')
13.4±0.2s 14.3±0.1s 1.07 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('120km', 'median')
236±10ms 231±3ms 0.98 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('480km', 'mean')
232±2ms 235±0.3ms 1.01 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('480km', 'median')
1.32±0.01s 1.32±0s 1.01 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('120km', 'mean')
1.49±0.01s 1.52±0.01s 1.02 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('120km', 'median')
25.5±0.7ms 25.8±0.05ms 1.01 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('480km', 'mean')
26.4±0.4ms 27.4±0.2ms 1.04 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('480km', 'median')
40.1±0.2ms 40.2±0.04ms 1.00 mpas_ocean.NeighborhoodReduce.time_reduce('120km', 'mean')
234±0.9ms 234±0.4ms 1.00 mpas_ocean.NeighborhoodReduce.time_reduce('120km', 'median')
626±100μs 710±20μs ~1.14 mpas_ocean.NeighborhoodReduce.time_reduce('480km', 'mean')
2.02±0.1ms 2.20±0.02ms 1.09 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')
386±30μs 414±20μs 1.07 mpas_ocean.PointInPolygon.time_face_search_xyz('120km')
385±40μs 435±10μs ~1.13 mpas_ocean.PointInPolygon.time_face_search_xyz('480km')
234±2ms 239±1ms 1.02 mpas_ocean.RemapDownsample.time_bilinear_remapping
291±3ms 302±2ms 1.03 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
16.2±0.5ms 16.6±0.2ms 1.02 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
1.33±0.01s 1.35±0s 1.02 mpas_ocean.RemapUpsample.time_bilinear_remapping
36.3±0.7ms 39.1±0.4ms 1.08 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
12.1±0.09ms 12.9±0.3ms 1.07 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
9.57±0.5ms 10.3±0.1ms 1.07 mpas_ocean.ZonalAverage.time_zonal_average('120km')
5.57±0.3ms 6.03±0.1ms 1.08 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.31±0.6ms 7.09±0.2ms ~1.12 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.8k 73.8k 1.00 quad_hexagon.QuadHexagon.track_peakmem_open_dataset
73k 73k 1.00 quad_hexagon.QuadHexagon.track_peakmem_open_grid

Benchmarks that have got worse:

Change Before [38b33d8] <v2026.09.0> After [031b15a] Ratio Benchmark (Parameter)
+ 411±20μs 465±20μs 1.13 mpas_ocean.PointInPolygon.time_face_search_lonlat('120km')
+ 382±40μs 466±20μs 1.22 mpas_ocean.PointInPolygon.time_face_search_lonlat('480km')
+ 7.27±0.8ms 8.82±0.2ms 1.21 quad_hexagon.QuadHexagon.time_open_dataset

@dylannelson

Copy link
Copy Markdown
Member Author

This branch

image

Older Versions:

image

@dylannelson dylannelson changed the title IO for fesom not converting n2 to two during open_grid Assigning connectivities based on UGRID conventions Sep 11, 2026
@dylannelson
dylannelson marked this pull request as ready for review September 11, 2026 16:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

extra dims Handling of non-grid dimensions, such as time or altitude run-benchmark Run ASV benchmark workflow

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Connectivities in different UGRID file reads can have different dimensions IO for fesom not converting n2 to two during open_grid

1 participant