Skip to content

Make longitude range lazy for lazy Grid constructors - #1791

Draft
cmdupuis3 wants to merge 4 commits into
UXARRAY:mainfrom
cmdupuis3:cmd/lazy-lon-range
Draft

cmdupuis3 wants to merge 4 commits into
UXARRAY:mainfrom
cmdupuis3:cmd/lazy-lon-range

Conversation

@cmdupuis3

@cmdupuis3 cmdupuis3 commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #1792

Overview

_set_desired_longitude_range does if da.max() > 180 on a lazy reduction, three times (node_lon, edge_lon, face_lon). Re-fires on every Grid construction, so every isel and every copy() pays it again.

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.5

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

cmdupuis3 and others added 3 commits September 25, 2026 18:46
_set_desired_longitude_range decided whether to wrap by asking
lon.max() > 180. On a dask-backed coordinate that reduction is a compute,
and Grid.__init__ calls it -- so opening a chunked grid read and reduced
every longitude array before the caller had asked for anything, and did it
again on every isel and every copy(), each of which builds a new Grid.

The wrap is now xr.where((lon > 180) | (lon < -180), (lon + 180) % 360 - 180,
lon): elementwise, lazy, chunk-parallel, no reduction.

Measured on a synthetic 4M-node UGRID file, chunked at 500k nodes, best of 5:

                       dask computes    wall      tracemalloc peak
    open_grid (before)             3    23.3ms          12.2 MB
    open_grid (after)              2    16.2ms           1.0 MB
    isel      (before)             2
    isel      (after)              1

The computes that remain are a separate site on connectivity rather than
coordinates: _standardize_connectivity's conn.isnull().any() in io/_ugrid.py,
reached twice on the read path, and _slice_face_indices in grid/slice.py
materializing the connectivity it slices by. Neither is touched here.

Three behavioural differences, all from doing this per element rather than
per array.

  * In-range longitudes are now left exactly alone. (lon + 180) - 180 does
    not round-trip, so wrapping the whole array perturbed values that were
    already in range by up to 3e-14 degrees -- in outCSne30, 2.1182935e-14
    became 2.8421709e-14. On the elements that do need wrapping the two forms
    are bit-identical.

  * Longitudes below -180 are normalized. The old test was on the maximum
    alone, so it reached the negative tail only when the same array also held
    a value above 180.

  * Both endpoints are kept, so the interval is the closed [-180, 180].
    Folding 180.0 to -180.0 would match _xyz_to_lonlat_deg, which wraps
    unconditionally into the half-open interval, but it breaks
    antimeridian_face_indices: that reads a face as crossing from the span of
    its longitudes, and a face with one vertex at 180 and the rest near -170
    goes from a span of 350 to a span of 10 and disappears. Caught by
    test_antimeridian_point_on and
    test_to_geodataframe_preserves_antimeridian_faces.

Each variable is wrapped at most once, keyed on the xr.Variable object.
Without that, edge_lat -- which calls this on every property access,
outside its populate guard -- would stack a where layer onto the graph per
access. Keying on the Variable makes the memo
self-invalidating: assigning into _ds replaces that object, so a repopulated
or user-assigned coordinate is wrapped again.

The two Exodus round-trip tests compared a grid against its own
lon -> xyz -> lon reload with assert_allclose(rtol=1e-8), and passed only
because the old whole-array wrap applied to the original the identical
perturbation the reload applies. With the original left alone, the reload's
own error is exposed, and rtol is the wrong instrument for it twice over: a
longitude near zero has no magnitude for a relative tolerance to measure
against (outCSne30 nodes 4372, 4749, 7e-15 degrees apart), and longitude is
periodic, so a node on or one ulp short of the antimeridian reads 180.0 on
the original and -180.0 on the reload -- the same meridian, scored as a
360-degree error (179 nodes of outRLL1deg; outCSne30 nodes 3966, 5155).
Those two assertions now compare the difference modulo 360 to an absolute
tolerance, still ERROR_TOLERANCE. The helper still catches a 1e-7 shift and
still rejects an antipode.

Tier 0.2 of the chunked refactor plan.

Test suite: 962 passed, 1 skipped. test_plot_with_features fails identically
before and after (matplotlib figure size, unrelated).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The elementwise wrap is the right shape for a dask-backed coordinate and the
wrong one for an array already in memory. There was never a compute to defer
on that path, only a scan, and elementwise costs a pass plus ~18 bytes per
node of temporaries -- two bool masks, the arithmetic, the result -- where a
reduction costs a pass and allocates nothing.

That matters because every open_grid/open_dataset call in the benchmark suite
is eager; none pass chunks=. So the previous commit, measured there, was a
regression and nothing else.

Measured on a synthetic 4M-node UGRID file, best of 5. The wrap in isolation:

                              in range         0..360
    old reduction               4.6ms  0MB    36.8ms  64MB
    elementwise only           20.9ms 72MB    38.1ms  72MB
    elementwise + guard         9.3ms  0MB    42.7ms  72MB

and through eager open_grid, where the file read dominates and the peak does
not move at all (180.0 MB in every arm):

                              in range         0..360
    base (cmd/nogil)           145.5ms         181.9ms
    elementwise only           164.4ms         186.1ms
    elementwise + guard        147.9ms         185.9ms

_lon_within_range is a guard, not a decision: when it is true the wrap is the
identity on every element, so skipping it cannot change a value.
test_eager_fast_path_agrees_with_the_where_element_for_element asserts that
directly against the unguarded expression rather than assuming it, over five
inputs including both endpoints, the negative tail and NaN.

The reductions are the thing that made the old code compute, so they are
allowed only where there is nothing to defer -- da.chunks is None. A
dask-backed array skips the guard entirely, which
test_guard_is_skipped_for_dask_backed_arrays pins by asserting the guard does
compute when handed one. The chunked numbers are unchanged: 2 graph
executions, 16.0ms, 1.0 MB peak.

`and` short-circuits, so an array that does need wrapping usually pays a
single max -- the same reduction the old code paid -- before falling through.
The 0..360 column above is that extra max: ~4.6ms on a 190ms open_grid.

Test suite: 973 passed, 1 skipped. test_plot_with_features fails identically
before and after (matplotlib figure size, unrelated).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every other open_grid in the suite is eager, so none of it can see what
Grid construction does to a dask-backed grid -- which is the path the lazy
longitude wrap changed, and the path the rest of the chunked refactor will
keep changing. OpenGridChunked adds time_open_grid and
track_peakmem_open_grid, parametrized over the oQU 480km and 120km meshes
already registered in helpers/_fixtures.py.

Chunks are held at N_CHUNKS=4 per grid dimension, so the graph is the same
shape at both resolutions and only the data under it grows. The file is read
directly rather than through CachedFixtures, because reading it is the
subject.

On MPAS this is where the lazy wrap matters most. node_lon, edge_lon and
face_lon all exist at construction, so the old max() > 180 check ran three
computes per open; the branch runs none. Measured with this benchmark's own
setup, best of 15, against HEAD's tree with coordinates.py taken from
cmd/nogil:

                      time               tracemalloc peak
                  base    branch        base    branch
    480km       60.5ms    56.5ms      3.27MB    3.27MB
    120km       42.3ms    38.0ms      3.53MB    4.02MB

The 120km peak reads higher on the branch, and it is not data. With gc
disabled, building the where graph allocates ~1.9 MB of transient objects,
nearly all in inspect.signature via dask/xarray op dispatch -- the same at
both resolutions and with a single chunk, so it does not scale with the
grid. At 480km it sits under the HDF5 read's own high-water mark; at 120km
the netCDF3 read is cheap enough that it becomes the peak. After a
gc.collect() the branch retains ~30 kB more than base, which is the extra
graph layers. Worth knowing for later steps: this benchmark sees
graph-construction overhead, not only bytes read.

Three things the numbers above depend on:

  * Compare each resolution to its own history, not to the other. The two
    files are different formats -- oQU480.grid.nc is netCDF4/HDF5,
    oQU120.grid.nc is netCDF3 -- and the HDF5 open costs more, so 480km reads
    slower than 120km despite a sixteenth of the data.

  * Each open gets a fresh copy of the chunks dict. match_chunks_to_ugrid
    (core/utils.py) writes the source-format dimension names into the
    dict it is handed, so a reused one gives every sample after the first a
    different argument.

  * The warning "The specified chunks separate the stored chunks" is
    filtered. oQU480 stores layerThickness, ssh and zMid as one chunk of all
    1791 cells, so any n_face chunking splits them and xarray warns once per
    open -- about data variables the grid reader drops.

Checked by calling the class the way asv does (setup(param), then the
time_/track_ methods) under -W error::UserWarning. Not run through asv
itself: its discovery subprocess cannot import uxarray from the uxarray
conda env, where the package is not installed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cmdupuis3 cmdupuis3 self-assigned this Sep 25, 2026
@cmdupuis3 cmdupuis3 added scalability Related to scalability & performance efforts run-benchmark Run ASV benchmark workflow labels Sep 25, 2026
@github-actions

github-actions Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have improved:

Change Before [379c895] <v2026.09.1> After [4470c74] Ratio Benchmark (Parameter)
- 354M 283M 0.8 import.Imports.track_peakmem_import_uxarray
- 2 1 0.5 lazy_grid_construction.LazyGridConstruction.track_computes_isel
- 3 2 0.67 lazy_grid_construction.LazyGridConstruction.track_computes_open_grid_chunked
- 104±0.4ms 93.9±2ms 0.9 lazy_grid_construction.OpenGridChunked.time_open_grid('120km')
- 2.81M 2.11M 0.75 lazy_grid_construction.OpenGridChunked.track_peakmem_open_grid('120km')
- 354M 320M 0.91 mpas_ocean.GradientColdStartRss.track_peakmem_gradient('480km')

Benchmarks that have stayed the same:

Change Before [379c895] <v2026.09.1> After [4470c74] Ratio Benchmark (Parameter)
5.31±0.05ms 5.16±0.04ms 0.97 bench_connectivity.Connectivity.time_edge_face('120km')
2.06±0.05ms 1.98±0.02ms 0.96 bench_connectivity.Connectivity.time_edge_face('480km')
4.36±0.02ms 4.35±0.04ms 1.00 bench_connectivity.Connectivity.time_edge_node('120km')
1.59±0.01ms 1.58±0.02ms 0.99 bench_connectivity.Connectivity.time_edge_node('480km')
4.36±0.04ms 4.34±0.09ms 1.00 bench_connectivity.Connectivity.time_face_edge('120km')
1.59±0.01ms 1.59±0.02ms 1.00 bench_connectivity.Connectivity.time_face_edge('480km')
6.19±0.01ms 6.17±0.03ms 1.00 bench_connectivity.Connectivity.time_face_face('120km')
2.36±0.02ms 2.33±0.03ms 0.99 bench_connectivity.Connectivity.time_face_face('480km')
54.2±2μs 53.7±0.8μs 0.99 bench_connectivity.Connectivity.time_face_node('120km')
53.6±1μs 51.6±0.4μs 0.96 bench_connectivity.Connectivity.time_face_node('480km')
449±10μs 434±7μs 0.97 bench_connectivity.Connectivity.time_n_nodes_per_face('120km')
363±8μs 370±10μs 1.02 bench_connectivity.Connectivity.time_n_nodes_per_face('480km')
5.73±0.04ms 5.70±0.05ms 0.99 bench_connectivity.Connectivity.time_node_edge('120km')
2.01±0.01ms 1.99±0.01ms 0.99 bench_connectivity.Connectivity.time_node_edge('480km')
77.7±1ms 75.6±0.8ms 0.97 bench_connectivity.Connectivity.time_node_face('120km')
5.26±0.06ms 5.10±0.07ms 0.97 bench_connectivity.Connectivity.time_node_face('480km')
8.42±0.06ms 8.70±0.4ms 1.03 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
2.71±0.04ms 2.72±0.07ms 1.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
6.97±7s 10.2±10ms ~0.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
1.54±0.02ms 1.54±0.02ms 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'))
354M 326M 0.92 face_bounds.FaceBoundsColdStartRss.track_peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
354M 326M 0.92 face_bounds.FaceBoundsColdStartRss.track_peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
354M 327M 0.92 face_bounds.FaceBoundsColdStartRss.track_peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
354M 327M 0.92 face_bounds.FaceBoundsColdStartRss.track_peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.14±0.02μs 1.13±0.01μs 0.99 geometry_kernels.AccucrossKernels.time_accucross
2.61±0.03μs 2.58±0.02μs 0.99 geometry_kernels.AccucrossKernels.time_accucross_pair
456±10ns 466±20ns 1.02 geometry_kernels.EFTPrimitives.time_acc_sqrt_re
431±9ns 451±10ns 1.05 geometry_kernels.EFTPrimitives.time_diff_of_products
401±10ns 396±20ns 0.99 geometry_kernels.EFTPrimitives.time_two_prod
396±10ns 391±8ns 0.99 geometry_kernels.EFTPrimitives.time_two_sum
696±40ns 691±20ns 0.99 geometry_kernels.GCAConstLatIntersection.time_accux_constlat_kernel
767±40ns 721±20ns 0.94 geometry_kernels.GCAConstLatIntersection.time_gca_const_lat_intersection
851±30ns 782±10ns 0.92 geometry_kernels.GCAConstLatIntersection.time_try_gca_const_lat_intersection
806±20ns 811±20ns 1.01 geometry_kernels.GCAGCAIntersection.time_accux_gca_kernel
932±20ns 907±20ns 0.97 geometry_kernels.GCAGCAIntersection.time_gca_gca_intersection
1.06±0.01μs 1.02±0.02μs 0.97 geometry_kernels.GCAGCAIntersection.time_try_gca_gca_intersection
52.7±1μs 51.9±0.4μs 0.98 geometry_kernels.OrientPredicates.time_on_minor_arc
52.2±2μs 51.4±0.3μs 0.98 geometry_kernels.OrientPredicates.time_orient3d_on_sphere
3.06±0.03ms 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±0.07ms 2.29±0.01ms 1.00 geometry_samebody.SameBodyConstLat.time_fp64_dispatch
148±0.5μs 148±4μs 1.00 geometry_samebody.SameBodyConstLat.time_fp64_kernel
30.1±2ms 29.6±0.02ms 0.98 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_dispatch
6.27±0.01ms 6.28±0.02ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_kernel
24.3±1ms 23.6±0.06ms 0.97 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_dispatch
894±2μs 859±0.9μs 0.96 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_kernel
903±7ms 908±10ms 1.01 import.Imports.timeraw_import_uxarray
135±1ms 124±3ms 0.92 lazy_grid_construction.OpenGridChunked.time_open_grid('480km')
2.06M 2.2M 1.07 lazy_grid_construction.OpenGridChunked.track_peakmem_open_grid('480km')
2.52±0.04ms 2.45±0.02ms 0.97 mpas_ocean.CheckNorm.time_check_norm('120km')
2.04±0.02ms 1.98±0.03ms 0.97 mpas_ocean.CheckNorm.time_check_norm('480km')
1.15±0.01ms 1.14±0.01ms 0.99 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
552±10μs 554±10μs 1.00 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
662±20μs 644±8μs 0.97 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
604±10μs 593±10μs 0.98 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
5.34±0.03ms 5.38±0.03ms 1.01 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('120km')
3.84±0.02ms 3.85±0.05ms 1.00 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('480km')
97.2±0.1ms 96.6±0.3ms 0.99 mpas_ocean.ConstructFaceLatLon.time_welzl('120km')
10.2±0.1ms 9.70±0.3ms 0.96 mpas_ocean.ConstructFaceLatLon.time_welzl('480km')
18.6±0.04ms 18.7±0.09ms 1.01 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
975±20μs 977±30μs 1.00 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
10.0±0.1ms 9.89±0.03ms 0.99 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
612±20μs 605±20μs 0.99 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
599±20ms 644±4ms 1.07 mpas_ocean.CrossSections.time_const_lat('120km', 1)
302±7ms 320±3ms 1.06 mpas_ocean.CrossSections.time_const_lat('120km', 2)
161±3ms 165±0.3ms 1.03 mpas_ocean.CrossSections.time_const_lat('120km', 4)
556±5ms 586±10ms 1.06 mpas_ocean.CrossSections.time_const_lat('480km', 1)
272±2ms 291±3ms 1.07 mpas_ocean.CrossSections.time_const_lat('480km', 2)
143±3ms 149±2ms 1.04 mpas_ocean.CrossSections.time_const_lat('480km', 4)
354M 346M 0.98 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('120km', 1)
354M 345M 0.98 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('120km', 2)
354M 345M 0.98 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('120km', 4)
354M 329M 0.93 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('480km', 1)
354M 328M 0.93 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('480km', 2)
354M 329M 0.93 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('480km', 4)
26.0±0.3ms 25.8±0.06ms 0.99 mpas_ocean.DualMesh.time_dual_mesh_construction('120km')
3.09±0.1ms 3.07±0.06ms 0.99 mpas_ocean.DualMesh.time_dual_mesh_construction('480km')
14.7±0.6ms 14.3±0.7ms 0.98 mpas_ocean.FaceAreas.time_face_areas('120km')
4.51±0.3ms 4.25±0.2ms 0.94 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')
714k 715k 1.00 mpas_ocean.FaceAreas.track_peakmem_face_areas('480km')
907±10ms 906±5ms 1.00 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
49.1±0.4ms 50.8±0.5ms 1.04 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
81.8±0.4ms 80.6±0.5ms 0.99 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
5.00±0.3ms 4.98±0.1ms 1.00 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
13.3±0.06ms 13.1±0.07ms 0.98 mpas_ocean.Gradient.time_gradient('120km')
1.82±0.02ms 1.79±0.01ms 0.98 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')
354M 341M 0.96 mpas_ocean.GradientColdStartRss.track_peakmem_gradient('120km')
275±2μs 275±7μs 1.00 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
149±0.8μs 151±8μs 1.01 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
204±6μs 204±7μs 1.00 mpas_ocean.Integrate.time_integrate('120km')
184±1μs 185±4μ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')
181±1ms 181±2ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
181±1ms 179±1ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
181±1ms 181±2ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
13.2±0.3ms 12.8±0.07ms 0.97 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
13.1±0.2ms 12.8±0.1ms 0.98 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
13.0±0.1ms 12.8±0.07ms 0.98 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
247±1ms 245±1ms 0.99 mpas_ocean.NeighborhoodBuild.time_build('120km', 1.0)
1.31±0s 1.31±0s 1.00 mpas_ocean.NeighborhoodBuild.time_build('120km', 15.0)
507±3ms 504±2ms 0.99 mpas_ocean.NeighborhoodBuild.time_build('120km', 5.0)
13.3±0.04ms 13.5±0.05ms 1.02 mpas_ocean.NeighborhoodBuild.time_build('480km', 1.0)
25.3±0.1ms 25.1±0.06ms 0.99 mpas_ocean.NeighborhoodBuild.time_build('480km', 15.0)
16.4±0.04ms 16.5±0.1ms 1.01 mpas_ocean.NeighborhoodBuild.time_build('480km', 5.0)
241±0.3ms 241±1ms 1.00 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)
505±2ms 502±3ms 0.99 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 5.0)
13.0±0.09ms 13.1±0.05ms 1.01 mpas_ocean.NeighborhoodBuild.time_query_radius('480km', 1.0)
24.7±0.03ms 24.7±0.04ms 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('480km', 15.0)
16.0±0.02ms 16.0±0.02ms 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)
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)
43.7±0.3ms 43.8±0.7ms 1.00 mpas_ocean.NeighborhoodDask.time_mean('120km', 'grid_chunks')
22.6±0.03ms 22.6±0.07ms 1.00 mpas_ocean.NeighborhoodDask.time_mean('120km', 'numpy')
39.9±0.7ms 39.9±0.8ms 1.00 mpas_ocean.NeighborhoodDask.time_mean('120km', 'time_chunks')
11.5±0.2ms 11.5±0.2ms 1.00 mpas_ocean.NeighborhoodDask.time_mean('480km', 'grid_chunks')
680±7μs 698±20μs 1.03 mpas_ocean.NeighborhoodDask.time_mean('480km', 'numpy')
8.25±0.08ms 8.30±0.07ms 1.01 mpas_ocean.NeighborhoodDask.time_mean('480km', 'time_chunks')
5.84M 5.84M 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.69M 5.68M 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('120km', 'time_chunks')
685k 675k 0.99 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'grid_chunks')
177k 177k 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'numpy')
546k 542k 0.99 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'time_chunks')
12.6±0.01s 12.6±0.01s 1.00 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('120km', 'mean')
13.2±0.01s 13.2±0.01s 1.00 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('120km', 'median')
226±1ms 227±1ms 1.01 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('480km', 'mean')
233±2ms 231±2ms 0.99 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('480km', 'median')
1.35±0.01s 1.35±0.01s 1.00 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('120km', 'mean')
1.54±0.01s 1.55±0s 1.00 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('120km', 'median')
25.8±0.1ms 25.6±0.02ms 0.99 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('480km', 'mean')
26.9±0.04ms 27.1±0.2ms 1.01 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('480km', 'median')
38.0±0.2ms 38.0±0.2ms 1.00 mpas_ocean.NeighborhoodReduce.time_reduce('120km', 'mean')
233±1ms 234±0.9ms 1.00 mpas_ocean.NeighborhoodReduce.time_reduce('120km', 'median')
472±20μs 434±10μs 0.92 mpas_ocean.NeighborhoodReduce.time_reduce('480km', 'mean')
1.67±0.02ms 1.65±0.02ms 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')
426±20μs 410±10μs 0.96 mpas_ocean.PointInPolygon.time_face_search_lonlat('120km')
407±10μs 399±4μs 0.98 mpas_ocean.PointInPolygon.time_face_search_lonlat('480km')
390±9μs 386±9μs 0.99 mpas_ocean.PointInPolygon.time_face_search_xyz('120km')
384±10μs 368±10μs 0.96 mpas_ocean.PointInPolygon.time_face_search_xyz('480km')
132±1ms 129±0.3ms 0.97 mpas_ocean.RemapDownsample.time_bilinear_remapping
17.0±0.03ms 17.1±0.09ms 1.01 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
15.5±0.07ms 15.4±0.06ms 0.99 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
1.43±0s 1.41±0.01s 0.98 mpas_ocean.RemapUpsample.time_bilinear_remapping
26.5±0.6ms 26.2±0.3ms 0.99 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
11.7±0.1ms 11.6±0.1ms 0.99 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
8.35±0.2ms 8.24±0.2ms 0.99 mpas_ocean.ZonalAverage.time_zonal_average('120km')
5.23±0.04ms 5.13±0.2ms 0.98 mpas_ocean.ZonalAverage.time_zonal_average('480km')
354M 347M 0.98 mpas_ocean.ZonalAveragePeakMem.track_peakmem_zonal_average('120km')
354M 329M 0.93 mpas_ocean.ZonalAveragePeakMem.track_peakmem_zonal_average('480km')
1.0302572049242855 1.0293927518234183 1.00 nogil_scaling.GILScaling.track_gil_scaling
7.27±0.09ms 7.49±0.04ms 1.03 quad_hexagon.QuadHexagon.time_open_dataset
6.10±0.09ms 6.55±0.06ms 1.07 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
72.8k 73.6k 1.01 quad_hexagon.QuadHexagon.track_peakmem_open_dataset
72.3k 72.7k 1.01 quad_hexagon.QuadHexagon.track_peakmem_open_grid

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.

_set_desired_longitude_range forces materialization in open_grid

1 participant