Skip to content

Avoid converting chunked data to Numpy arrays (i.e. .values calls) - #1588

Open
cmdupuis3 wants to merge 34 commits into
UXARRAY:mainfrom
cmdupuis3:cmd/devalue
Open

Avoid converting chunked data to Numpy arrays (i.e. .values calls)#1588
cmdupuis3 wants to merge 34 commits into
UXARRAY:mainfrom
cmdupuis3:cmd/devalue

Conversation

@cmdupuis3

@cmdupuis3 cmdupuis3 commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

Partly addresses #1583

Overview

This PR is to resolve suboptimal usage of .values throughout the repo, primarily by deferring to lazy xarray and dask operations. See the table of usage sites in Issue #1583.

This specific PR is for the first two tables of usage sites; dead code and bugfixes aren't really included here. Aside from simple cases, some cases were solved by branching on whether the data type was already chunked, so scalability for some parts will depend on if you're using numpy or xarray/dask arrays at those points.

PR Checklist

General

  • An issue is linked created and linked
  • Add appropriate labels
  • Filled out Overview and Expected Usage (if applicable) sections

Testing

  • Adequate tests are created if there is new functionality
  • Tests cover all possible logical paths in your function
  • Tests are not too basic (such as simply calling a function and nothing else)

Documentation

  • Docstrings have been added to all new functions
  • Docstrings have updated with any function changes

@cmdupuis3 cmdupuis3 self-assigned this Jul 18, 2026
@cmdupuis3 cmdupuis3 added scalability Related to scalability & performance efforts run-benchmark Run ASV benchmark workflow labels Jul 18, 2026
@github-actions

github-actions Bot commented Jul 18, 2026

Copy link
Copy Markdown

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have improved:

Change Before [86269c1] After [dc1660d] Ratio Benchmark (Parameter)
- 901±200ns 731±5ns 0.81 geometry_kernels.GCAConstLatIntersection.time_accux_constlat_kernel
- 348±1ms 285±4ms 0.82 mpas_ocean.CrossSections.time_const_lat('120km', 1)
- 179±1ms 144±0.8ms 0.81 mpas_ocean.CrossSections.time_const_lat('120km', 2)
- 91.7±0.3ms 74.4±0.3ms 0.81 mpas_ocean.CrossSections.time_const_lat('120km', 4)

Benchmarks that have stayed the same:

Change Before [86269c1] After [dc1660d] Ratio Benchmark (Parameter)
112±1ms 111±0.7ms 1.00 bench_connectivity.Connectivity.time_edge_face('120km')
6.55±0.04ms 6.69±0.2ms 1.02 bench_connectivity.Connectivity.time_edge_face('480km')
109±0.2ms 110±0.2ms 1.01 bench_connectivity.Connectivity.time_edge_node('120km')
6.19±0.04ms 6.02±0.03ms 0.97 bench_connectivity.Connectivity.time_edge_node('480km')
110±1ms 111±0.7ms 1.00 bench_connectivity.Connectivity.time_face_edge('120km')
6.30±0.02ms 6.16±0.01ms 0.98 bench_connectivity.Connectivity.time_face_edge('480km')
410±1ms 411±1ms 1.00 bench_connectivity.Connectivity.time_face_face('120km')
25.3±0.2ms 25.1±0.08ms 0.99 bench_connectivity.Connectivity.time_face_face('480km')
35.9±0.7μs 36.1±1μs 1.01 bench_connectivity.Connectivity.time_face_node('120km')
32.8±2μs 33.1±0.8μs 1.01 bench_connectivity.Connectivity.time_face_node('480km')
236±7μs 236±4μs 1.00 bench_connectivity.Connectivity.time_n_nodes_per_face('120km')
179±2μs 178±3μs 0.99 bench_connectivity.Connectivity.time_n_nodes_per_face('480km')
111±2ms 111±0.9ms 1.00 bench_connectivity.Connectivity.time_node_edge('120km')
6.32±0.1ms 6.29±0.1ms 1.00 bench_connectivity.Connectivity.time_node_edge('480km')
37.4±0.3ms 37.0±0.4ms 0.99 bench_connectivity.Connectivity.time_node_face('120km')
2.38±0.01ms 2.41±0.04ms 1.01 bench_connectivity.Connectivity.time_node_face('480km')
4.55±0.02ms 4.56±0.02ms 1.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
1.47±0.02ms 1.48±0.02ms 1.01 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
6.02±6s 6.03±7ms ~0.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
1.05±0.03ms 1.07±0.01ms 1.02 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'))
2.04M 2.04M 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
2.04M 2.04M 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
2.21M 2.21M 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
38.2k 38.3k 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
336M 336M 1.00 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
365M 368M 1.01 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
338M 338M 1.00 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
337M 337M 1.00 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
601±10ns 611±30ns 1.02 geometry_kernels.AccucrossKernels.time_accucross
1.39±0.02μs 1.44±0.02μs 1.03 geometry_kernels.AccucrossKernels.time_accucross_pair
241±8ns 240±4ns 1.00 geometry_kernels.EFTPrimitives.time_acc_sqrt_re
240±8ns 236±10ns 0.98 geometry_kernels.EFTPrimitives.time_diff_of_products
211±0.5ns 211±4ns 1.00 geometry_kernels.EFTPrimitives.time_two_prod
210±5ns 210±4ns 1.00 geometry_kernels.EFTPrimitives.time_two_sum
561±5ns 576±10ns 1.03 geometry_kernels.GCAConstLatIntersection.time_gca_const_lat_intersection
966±10ns 992±20ns 1.03 geometry_kernels.GCAConstLatIntersection.time_try_gca_const_lat_intersection
831±7ns 841±9ns 1.01 geometry_kernels.GCAGCAIntersection.time_accux_gca_kernel
766±5ns 771±5ns 1.01 geometry_kernels.GCAGCAIntersection.time_gca_gca_intersection
1.09±0.02μs 1.08±0.01μs 0.99 geometry_kernels.GCAGCAIntersection.time_try_gca_gca_intersection
22.5±0.4μs 21.1±0.2μs 0.94 geometry_kernels.OrientPredicates.time_on_minor_arc
446±10ns 411±10ns 0.92 geometry_kernels.OrientPredicates.time_orient3d_on_sphere
1.55±0.07ms 1.49±0ms 0.96 geometry_samebody.SameBodyConstLat.time_accux_dispatch
647±4μs 655±8μs 1.01 geometry_samebody.SameBodyConstLat.time_accux_kernel
1.05±0.01ms 1.04±0.01ms 0.99 geometry_samebody.SameBodyConstLat.time_fp64_dispatch
82.3±0.9μs 83.2±0.2μs 1.01 geometry_samebody.SameBodyConstLat.time_fp64_kernel
23.4±0.02ms 24.1±0.4ms 1.03 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_dispatch
5.51±0.02ms 5.52±0.03ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_kernel
21.0±0.2ms 20.9±0.06ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_dispatch
3.33±0.01ms 3.34±0.01ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_kernel
473±2ms 472±3ms 1.00 import.Imports.timeraw_import_uxarray
293M 293M 1.00 import.Imports.track_peakmem_import_uxarray
1.28±0.01ms 1.29±0.01ms 1.01 mpas_ocean.CheckNorm.time_check_norm('120km')
1.05±0ms 1.05±0.01ms 1.00 mpas_ocean.CheckNorm.time_check_norm('480km')
361±2ms 363±0.6ms 1.00 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
22.8±0.03ms 22.7±0.07ms 1.00 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
355±4μs 348±8μs 0.98 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
302±10μs 292±1μs 0.97 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
2.44±0.01ms 2.45±0.01ms 1.00 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('120km')
1.93±0.01ms 1.93±0.02ms 1.00 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('480km')
2.09±0.01s 2.11±0.03s 1.01 mpas_ocean.ConstructFaceLatLon.time_welzl('120km')
133±0.7ms 132±0.6ms 0.99 mpas_ocean.ConstructFaceLatLon.time_welzl('480km')
12.5±0.01ms 12.5±0.04ms 1.00 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
685±30μs 682±20μs 1.00 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
6.43±0.02ms 6.41±0.02ms 1.00 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
454±20μs 413±20μs ~0.91 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
267±0.8ms 255±0.5ms 0.95 mpas_ocean.CrossSections.time_const_lat('480km', 1)
135±0.6ms 128±0.6ms 0.95 mpas_ocean.CrossSections.time_const_lat('480km', 2)
69.6±0.2ms 67.1±0.2ms 0.96 mpas_ocean.CrossSections.time_const_lat('480km', 4)
14.4±0.2ms 14.5±0.05ms 1.00 mpas_ocean.DualMesh.time_dual_mesh_construction('120km')
1.54±0.01ms 1.54±0.01ms 1.00 mpas_ocean.DualMesh.time_dual_mesh_construction('480km')
43.8±0.6ms 43.8±0.4ms 1.00 mpas_ocean.FaceAreas.time_face_areas('120km')
4.36±0.02ms 4.41±0.02ms 1.01 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')
836k 836k 1.00 mpas_ocean.FaceAreas.track_peakmem_face_areas('480km')
450±2ms 445±1ms 0.99 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
26.8±0.7ms 26.7±0.5ms 1.00 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
38.0±0.08ms 38.0±0.2ms 1.00 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
2.82±0.05ms 2.87±0.06ms 1.02 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
124±0.5ms 123±0.1ms 0.99 mpas_ocean.Gradient.time_gradient('120km')
8.29±0.03ms 8.33±0.04ms 1.00 mpas_ocean.Gradient.time_gradient('480km')
457k 457k 1.00 mpas_ocean.Gradient.track_nbytes_gradient('120km')
28.7k 28.7k 1.00 mpas_ocean.Gradient.track_nbytes_gradient('480km')
5.08M 5.08M 1.00 mpas_ocean.Gradient.track_peakmem_gradient('120km')
327k 328k 1.00 mpas_ocean.Gradient.track_peakmem_gradient('480km')
352M 352M 1.00 mpas_ocean.GradientColdStartRss.peakmem_gradient('120km')
331M 331M 1.00 mpas_ocean.GradientColdStartRss.peakmem_gradient('480km')
232±10μs 234±6μs 1.01 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
106±4μs 101±3μs 0.95 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
338±9μs 345±4μs 1.02 mpas_ocean.Integrate.time_integrate('120km')
259±4μs 261±5μ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')
95.4±0.6ms 95.5±0.6ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
95.7±0.6ms 95.2±1ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
94.9±0.7ms 96.5±0.9ms 1.02 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
6.98±0.04ms 7.12±0.03ms 1.02 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
6.98±0.03ms 7.02±0.05ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
7.03±0.05ms 7.20±0.08ms 1.02 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
194±6μs 195±2μs 1.00 mpas_ocean.PointInPolygon.time_face_search_lonlat('120km')
184±6μs 181±4μs 0.98 mpas_ocean.PointInPolygon.time_face_search_lonlat('480km')
177±5μs 188±5μs 1.06 mpas_ocean.PointInPolygon.time_face_search_xyz('120km')
172±5μs 168±2μs 0.98 mpas_ocean.PointInPolygon.time_face_search_xyz('480km')
118±0.3ms 119±0.9ms 1.01 mpas_ocean.RemapDownsample.time_bilinear_remapping
115±0.1ms 114±0.3ms 0.99 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
9.04±0.04ms 9.04±0.04ms 1.00 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
610±3ms 615±5ms 1.01 mpas_ocean.RemapUpsample.time_bilinear_remapping
21.2±0.3ms 20.4±0.3ms 0.96 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
6.87±0.3ms 6.88±0.2ms 1.00 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
14.9±0.6ms 14.8±0.2ms 0.99 mpas_ocean.ZonalAverage.time_zonal_average('120km')
2.68±0.02ms 2.75±0.03ms 1.02 mpas_ocean.ZonalAverage.time_zonal_average('480km')
3.46±0.06ms 3.50±0.04ms 1.01 quad_hexagon.QuadHexagon.time_open_dataset
2.88±0.01ms 2.88±0.02ms 1.00 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.5k 1.00 quad_hexagon.QuadHexagon.track_peakmem_open_dataset
73k 72.8k 1.00 quad_hexagon.QuadHexagon.track_peakmem_open_grid

@cmdupuis3

Copy link
Copy Markdown
Collaborator Author

pre-commit.ci autofix

@cmdupuis3

Copy link
Copy Markdown
Collaborator Author

There's some spurious asv results from machine variability, but the benchmarks consistenly show peak-mem reductions and some speedups for cross-sections.

@cmdupuis3
cmdupuis3 requested a review from erogluorhan July 20, 2026 23:25
@cmdupuis3
cmdupuis3 marked this pull request as ready for review July 20, 2026 23:26
@cmdupuis3
cmdupuis3 requested a review from rajeeja July 23, 2026 23:26
@cmdupuis3

Copy link
Copy Markdown
Collaborator Author

pre-commit.ci autofix

@Sevans711
Sevans711 self-requested a review July 27, 2026 16:18

@Sevans711 Sevans711 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @cmdupuis3, thank you for proposing these changes! Overall these look like good clean changes which should help improve the scalability of uxarray.

I have some notes/suggestions/requested changes. Primarily, I noticed that there are missing regression tests. This may be especially important for places with significant changes (more significant than just replacing obj.values with obj.data):

  • UxDataArray.integrate()
  • UxDataArrayCrossSectionAccessor.__call__()
  • uxarray.plot.matplotlib._nearest_neighbor_resample()
  • RemapAccessor.apply_weights()

It may be nice to add a regression test for UxDataset.to_xarray() too, even though the changes here are minor, since that feels like a very core part of the functionality.

The tests could be similar to what you added already in test_topological_agg.py (plus my additional request on that file): ensure that numpy and dask inputs ultimately give the same values (plus assert that the dask inputs lead to dask outputs).

Other parts of the code changes here might benefit from similar tests, but I don't know if that should be necessary. For example, the changes in _geos just replace obj.values with obj.data; does a regression test need to be added for that or no? Curious to hear from @erogluorhan and/or @rajeeja on this question in particular.

Misc. note: I'm not sure if I fully understand the changes to uxarray/cross_sections files. I need to make sure to take a closer look at those during a subsequent review.

Comment thread uxarray/core/aggregation.py
Comment thread uxarray/core/aggregation.py Outdated
Comment thread uxarray/core/aggregation.py
Comment thread uxarray/core/aggregation.py Outdated
Comment thread uxarray/core/dataarray.py Outdated
Comment thread uxarray/core/dataarray.py
Comment thread test/core/test_topological_agg.py
@erogluorhan erogluorhan changed the title Devalue uxarray to make it less expensive Avoid converting chunked data to Numpy arrays (i.e. .values calls) in the code Jul 27, 2026
@erogluorhan erogluorhan changed the title Avoid converting chunked data to Numpy arrays (i.e. .values calls) in the code Avoid converting chunked data to Numpy arrays (i.e. .values calls) Jul 27, 2026
@github-project-automation github-project-automation Bot moved this to 👀 In review in UXarray Development Aug 7, 2026
@cmdupuis3 cmdupuis3 moved this from 👀 In review to 🏗 In progress in UXarray Development Aug 7, 2026
@cmdupuis3 cmdupuis3 moved this from 🏗 In progress to 👀 In review in UXarray Development Aug 7, 2026
cmdupuis3 and others added 6 commits August 10, 2026 09:38
A stash pop was committed in 9cfd53e with its markers intact, making the
module a syntax error. Both sides were additive, so keep both.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@Sevans711 Sevans711 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks almost ready to merge, I just have a few minor comments remaining!

Requires response:

  • I noticed the mpas_ocean.Integrate.time_integrate('480km') benchmark has worsened slightly. Is this expected behavior? Do you think this is real, a rounding error, or something else?
  • I would suggest to remove all of the pytest.importorskip calls; I left an inline comment with more details.

The rest of this comment does not require response. It includes the notes I wrote down, for future reference.

Other Benchmarking:

  • The cross sections benchmarks seem to have improved, which is great!
  • I'm ignoring peakmem "improvements" (as per #1605)
  • Even though other benchmarks didn't show notable improvements, I think that is fine, because they didn't get worse, either. Also, this PR isn't fully closing the original issue, anyway, it is just addressing part of it.

Testing:

I checked all the cases where I previously requested tests for correctness (numpy & dask give same result) and regression tests (check dask inputs cause dask outputs); here is what I found:

  • (Looks done to me! Confirmed tests pass here, fail on main.) UxDataArray.integrate()
  • (Looks done to me! Confirmed tests pass here, fail on main. Also, the tests do a good job covering a variety of possible failure cases, by including multiple dimensions and some nan / some non-nan values.) UxDataArrayCrossSectionAccessor.__call__()
  • (Not done, but now I'm less sure if it's necessary; left an inline comment to discuss.) uxarray.plot.matplotlib._nearest_neighbor_resample()
  • (Looks done to me! Confirmed tests pass here, fail on main. Also, the tests do a good job covering nontrivial cases, like handling multiple dimensions.) RemapAccessor.apply_weights()
  • (Not done, but optional; no need to block merging for this.) UxDataset.to_xarray()

Previously I noted I need to look closer at cross sections. After doing so and considering the new cross sections tests, I am feeling convinced that the cross sections changes should be working as intended. Noting that the extra dims included in those tests might also help with #1461.

Comment thread uxarray/plot/matplotlib.py
Comment thread test/core/test_topological_agg.py Outdated
@cmdupuis3

Copy link
Copy Markdown
Collaborator Author

I noticed the mpas_ocean.Integrate.time_integrate('480km') benchmark has worsened slightly. Is this expected behavior? Do you think this is real, a rounding error, or something else?

It isn't real, you can rerun the benchmarks and it'll probably disappear. There's always a chance with the smaller benchmarks that they'll trigger due to machine variability. 1.1x is pretty suspect.

@rajeeja

rajeeja commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

While reviewing this I noticed the numpy aggregation paths drop coords and attrs while your new dask paths preserve them via apply_ufunc, so on this branch .chunk() decides whether .sel(time=...) works on the result. That turned out to be a pre-existing bug on main, so I filed #1665 and opened #1666 against main rather than adding it here. Merging main once that lands should bring your two paths back into agreement.

@cmdupuis3

Copy link
Copy Markdown
Collaborator Author

pre-commit.ci autofix

@Sevans711 Sevans711 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks to me like this is ready to merge into main!

Any guesses as to why the mpas_ocean.CrossSections.time_const_lat benchmarks show improvements now, but didn't show improvements in prior iterations of this PR? (This question is non-blocking, since it's an improvement! Just curious if you have insights about this.)

@cmdupuis3

Copy link
Copy Markdown
Collaborator Author

@Sevans711 They've shown improvements for a while now, that's not recent. There are some changes to how cross-sections are caluculated on chunked grids that served as the .values fix, they weren't as trivial as most other changes here.

@Sevans711

Copy link
Copy Markdown
Collaborator

They've shown improvements for a while now, that's not recent. There are some changes to how cross-sections are caluculated on chunked grids that served as the .values fix, they weren't as trivial as most other changes here.

Ah, woops! I confused myself by looking at my prior comment mentioning the benchmarks. Thank you for clarifying!

@rljacob
rljacob requested a balanced review from Copilot August 14, 2026 18:15
@rljacob

rljacob commented Aug 14, 2026

Copy link
Copy Markdown
Member

I have copilot access on github and will ask it to do a review.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves lazy execution by replacing eager .values conversions with Dask/xarray-compatible operations.

Changes:

  • Adds lazy remapping, aggregation, integration, and cross-section paths.
  • Preserves chunked backing arrays during grid and format conversions.
  • Adds Dask parity tests for key operations.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
uxarray/remap/structured.py Preserves lazy arrays during reshaping.
uxarray/remap/apply_weights.py Applies sparse weights blockwise.
uxarray/remap/accessor.py Documents lazy weight application.
uxarray/plot/matplotlib.py Loads only sampled faces.
uxarray/io/_scrip.py Preserves lazy SCRIP coordinates.
uxarray/io/_geos.py Preserves GEOS backing arrays.
uxarray/grid/slice.py Adds lazy connectivity remapping.
uxarray/grid/grid.py Avoids unnecessary grid materialization.
uxarray/cross_sections/sample.py Removes eager Numba gathering.
uxarray/cross_sections/dataarray_accessor.py Implements lazy cross-section gathering.
uxarray/core/dataset.py Preserves backing arrays in duals.
uxarray/core/dataarray.py Adds lazy integration and transformations.
uxarray/core/aggregation.py Implements Dask topological aggregation.
test/test_cross_sections.py Tests lazy cross-sections.
test/precomputed_weights_test.py Tests lazy sparse remapping.
test/grid/integrate/test_basic.py Tests lazy integration.
test/core/test_topological_agg.py Tests Dask aggregations.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread uxarray/grid/slice.py Outdated
Comment thread uxarray/grid/slice.py
Comment thread uxarray/core/aggregation.py Outdated
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

Status: 👀 In review

Development

Successfully merging this pull request may close these issues.

6 participants