Skip to content

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

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

Avoid converting chunked data to Numpy arrays (i.e. .values calls)#1588
cmdupuis3 wants to merge 27 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 [3228024] After [168e484] Ratio Benchmark (Parameter)
- 518M 337M 0.65 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
- 637M 336M 0.53 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
- 661±2ms 515±3ms 0.78 mpas_ocean.CrossSections.time_const_lat('120km', 1)
- 333±4ms 262±3ms 0.79 mpas_ocean.CrossSections.time_const_lat('120km', 2)
- 172±0.7ms 137±0.8ms 0.8 mpas_ocean.CrossSections.time_const_lat('120km', 4)
- 443M 332M 0.75 mpas_ocean.FaceAreas.peakmem_compute_face_areas('480km')
- 466M 331M 0.71 mpas_ocean.Gradient.peakmem_gradient('480km')

Benchmarks that have stayed the same:

Change Before [3228024] After [168e484] Ratio Benchmark (Parameter)
233±0.3ms 233±0.7ms 1 bench_connectivity.Connectivity.time_edge_face('120km')
13.4±0.06ms 13.5±0.06ms 1.01 bench_connectivity.Connectivity.time_edge_face('480km')
231±0.4ms 231±0.2ms 1 bench_connectivity.Connectivity.time_edge_node('120km')
12.7±0.08ms 12.6±0.03ms 0.99 bench_connectivity.Connectivity.time_edge_node('480km')
231±1ms 231±1ms 1 bench_connectivity.Connectivity.time_face_edge('120km')
12.9±0.02ms 12.9±0.06ms 1 bench_connectivity.Connectivity.time_face_edge('480km')
825±3ms 820±2ms 0.99 bench_connectivity.Connectivity.time_face_face('120km')
51.4±0.8ms 50.9±0.8ms 0.99 bench_connectivity.Connectivity.time_face_face('480km')
63.5±3μs 62.9±2μs 0.99 bench_connectivity.Connectivity.time_face_node('120km')
59.5±1μs 65.0±7μs 1.09 bench_connectivity.Connectivity.time_face_node('480km')
387±7μs 394±10μs 1.02 bench_connectivity.Connectivity.time_n_nodes_per_face('120km')
314±8μs 310±5μs 0.99 bench_connectivity.Connectivity.time_n_nodes_per_face('480km')
232±0.2ms 239±7ms 1.03 bench_connectivity.Connectivity.time_node_edge('120km')
13.0±0.05ms 12.9±0.03ms 1 bench_connectivity.Connectivity.time_node_edge('480km')
83.4±1ms 80.1±0.9ms 0.96 bench_connectivity.Connectivity.time_node_face('120km')
4.89±0.02ms 4.83±0.04ms 0.99 bench_connectivity.Connectivity.time_node_face('480km')
336M 336M 1 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
367M 365M 0.99 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
7.41±0.04ms 7.47±0.03ms 1.01 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
2.52±0.02ms 2.51±0.02ms 0.99 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
9.52±0.02ms 9.49±0.02ms 1 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
1.94±0.01ms 1.93±0.01ms 0.99 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.19±0.06μs 1.18±0.04μs 0.99 geometry_kernels.AccucrossKernels.time_accucross
2.56±0.02μs 2.58±0.02μs 1.01 geometry_kernels.AccucrossKernels.time_accucross_pair
390±20ns 386±10ns 0.99 geometry_kernels.EFTPrimitives.time_acc_sqrt_re
400±20ns 411±30ns 1.03 geometry_kernels.EFTPrimitives.time_diff_of_products
346±20ns 350±20ns 1.01 geometry_kernels.EFTPrimitives.time_two_prod
341±4ns 341±20ns 1 geometry_kernels.EFTPrimitives.time_two_sum
1.40±0.02μs 1.38±0.02μs 0.99 geometry_kernels.GCAConstLatIntersection.time_accux_constlat_kernel
1.02±0.02μs 1.02±0.01μs 1 geometry_kernels.GCAConstLatIntersection.time_gca_const_lat_intersection
1.76±0.02μs 1.76±0.01μs 1 geometry_kernels.GCAConstLatIntersection.time_try_gca_const_lat_intersection
1.55±0.03μs 1.57±0.01μs 1.02 geometry_kernels.GCAGCAIntersection.time_accux_gca_kernel
1.27±0.03μs 1.24±0.01μs 0.97 geometry_kernels.GCAGCAIntersection.time_gca_gca_intersection
2.01±0.03μs 2.01±0.02μs 1 geometry_kernels.GCAGCAIntersection.time_try_gca_gca_intersection
38.0±0.2μs 36.9±0.6μs 0.97 geometry_kernels.OrientPredicates.time_on_minor_arc
671±5ns 676±30ns 1.01 geometry_kernels.OrientPredicates.time_orient3d_on_sphere
2.93±0.1ms 2.83±0ms 0.96 geometry_samebody.SameBodyConstLat.time_accux_dispatch
1.33±0.01ms 1.33±0.01ms 1 geometry_samebody.SameBodyConstLat.time_accux_kernel
1.81±0ms 1.81±0ms 1 geometry_samebody.SameBodyConstLat.time_fp64_dispatch
156±5μs 153±0.4μs 0.98 geometry_samebody.SameBodyConstLat.time_fp64_kernel
32.5±0.04ms 33.3±0.3ms 1.02 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_dispatch
10.6±0ms 10.6±0.02ms 1 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_kernel
27.3±0.3ms 27.9±0.4ms 1.02 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_dispatch
4.43±0.02ms 4.46±0.02ms 1.01 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_kernel
791±9ms 803±10ms 1.01 import.Imports.timeraw_import_uxarray
2.24±0.02ms 2.26±0.04ms 1.01 mpas_ocean.CheckNorm.time_check_norm('120km')
1.87±0.03ms 1.86±0.02ms 0.99 mpas_ocean.CheckNorm.time_check_norm('480km')
722±8ms 729±6ms 1.01 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
44.9±0.4ms 45.2±0.3ms 1.01 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
607±10μs 620±6μs 1.02 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
550±10μs 546±6μs 0.99 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
5.05±0.02ms 5.10±0.02ms 1.01 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('120km')
3.52±0.01ms 3.58±0.02ms 1.02 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('480km')
3.30±0.01s 3.32±0.01s 1.01 mpas_ocean.ConstructFaceLatLon.time_welzl('120km')
213±2ms 212±1ms 1 mpas_ocean.ConstructFaceLatLon.time_welzl('480km')
19.7±0.02ms 19.7±0.01ms 1 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
1.13±0.02ms 1.11±0.02ms 0.98 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
10.6±0.02ms 10.6±0.05ms 1 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
742±20μs 773±8μs 1.04 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
488±1ms 460±2ms 0.94 mpas_ocean.CrossSections.time_const_lat('480km', 1)
246±0.7ms 231±1ms 0.94 mpas_ocean.CrossSections.time_const_lat('480km', 2)
129±0.9ms 121±1ms 0.93 mpas_ocean.CrossSections.time_const_lat('480km', 4)
22.1±0.1ms 22.2±0.1ms 1 mpas_ocean.DualMesh.time_dual_mesh_construction('120km')
2.56±0.04ms 2.65±0.03ms 1.03 mpas_ocean.DualMesh.time_dual_mesh_construction('480km')
350M 350M 1 mpas_ocean.FaceAreas.peakmem_compute_face_areas('120km')
57.5±0.2ms 57.5±0.1ms 1 mpas_ocean.FaceAreas.time_compute_face_areas('120km')
5.96±0.03ms 5.95±0.03ms 1 mpas_ocean.FaceAreas.time_compute_face_areas('480km')
840±3ms 850±10ms 1.01 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
51.4±1ms 51.3±0.9ms 1 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
72.6±0.4ms 74.2±0.2ms 1.02 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
5.69±0.1ms 5.65±0.06ms 0.99 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
352M 351M 1 mpas_ocean.Gradient.peakmem_gradient('120km')
167±3ms 168±4ms 1 mpas_ocean.Gradient.time_gradient('120km')
11.5±0.2ms 11.8±4ms 1.03 mpas_ocean.Gradient.time_gradient('480km')
359±3μs 367±6μs 1.02 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
200±4μs 200±4μs 1 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
351M 351M 1 mpas_ocean.Integrate.peakmem_integrate('120km')
330M 330M 1 mpas_ocean.Integrate.peakmem_integrate('480km')
560±3μs 586±20μs 1.05 mpas_ocean.Integrate.time_integrate('120km')
480±20μs 488±20μs 1.02 mpas_ocean.Integrate.time_integrate('480km')
185±1ms 187±2ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
187±2ms 186±1ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
184±0.4ms 185±2ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
13.6±0.04ms 14.1±0.05ms 1.04 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
13.8±0.1ms 14.0±0.04ms 1.02 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
13.7±0.04ms 13.8±0.06ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
371±10μs 371±20μs 1 mpas_ocean.PointInPolygon.time_face_search_lonlat('120km')
359±10μs 345±10μs 0.96 mpas_ocean.PointInPolygon.time_face_search_lonlat('480km')
342±10μs 345±10μs 1.01 mpas_ocean.PointInPolygon.time_face_search_xyz('120km')
320±9μs 315±2μs 0.98 mpas_ocean.PointInPolygon.time_face_search_xyz('480km')
213±2ms 212±1ms 0.99 mpas_ocean.RemapDownsample.time_bilinear_remapping
228±0.6ms 228±1ms 1 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
15.5±0.09ms 15.4±0.08ms 0.99 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
1.19±0s 1.17±0.01s 0.99 mpas_ocean.RemapUpsample.time_bilinear_remapping
36.2±0.3ms 35.6±0.3ms 0.98 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
11.3±0.09ms 11.1±0.2ms 0.98 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
26.9±0.2ms 26.4±0.2ms 0.98 mpas_ocean.ZonalAverage.time_zonal_average('120km')
5.39±0.2ms 5.31±0.2ms 0.99 mpas_ocean.ZonalAverage.time_zonal_average('480km')
325M 327M 1 quad_hexagon.QuadHexagon.peakmem_open_dataset
325M 325M 1 quad_hexagon.QuadHexagon.peakmem_open_grid
6.53±0.1ms 6.51±0.1ms 1 quad_hexagon.QuadHexagon.time_open_dataset
5.51±0.1ms 5.44±0.07ms 0.99 quad_hexagon.QuadHexagon.time_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
@cmdupuis3

Copy link
Copy Markdown
Collaborator Author

pre-commit.ci autofix

@cmdupuis3
cmdupuis3 requested a review from Sevans711 July 28, 2026 16:54
@cmdupuis3

Copy link
Copy Markdown
Collaborator Author

@erogluorhan Sam and I were wondering about your philosophy with respect to dask versus numpy routines. I was thinking that if we have a case where the numpy routine could be faster than a dask routine in some situations, we might want to keep both, or maybe you'd want to go all in on dask for simplicity.

if isinstance(uxda.data, np.ndarray):
    aggregated_var = _apply_node_to_face_aggregation_numpy(uxda, ...)
elif isinstance(uxda.data, da.Array):
    # apply aggregation on dask array, TODO:
    aggregated_var = _apply_node_to_face_aggregation_numpy(uxda, ...)
else:
    raise ValueError

This is something in main's aggregate.py. I fleshed out the dask branch, but now we still have this logic, and I left the numpy routine in on this branch.

@erogluorhan

Copy link
Copy Markdown
Member

@erogluorhan Sam and I were wondering about your philosophy with respect to dask versus numpy routines. I was thinking that if we have a case where the numpy routine could be faster than a dask routine in some situations, we might want to keep both, or maybe you'd want to go all in on dask for simplicity.

if isinstance(uxda.data, np.ndarray):
    aggregated_var = _apply_node_to_face_aggregation_numpy(uxda, ...)
elif isinstance(uxda.data, da.Array):
    # apply aggregation on dask array, TODO:
    aggregated_var = _apply_node_to_face_aggregation_numpy(uxda, ...)
else:
    raise ValueError

This is something in main's aggregate.py. I fleshed out the dask branch, but now we still have this logic, and I left the numpy routine in on this branch.

If I am understanding this correctly, question is about the use of routines, not data structures. If so, using standard NumPy functions directly on chunked Dask-backed Xarray objects should be completely safe with chunks. Let me know if this helps.

@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

def test_node_to_face_dask_reproduces_numpy(gridpath):
# the numpy (eager) and dask (chunked) branches must agree
da = pytest.importorskip("dask") # dask-backed branch requires dask

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.

Remove the importorskip calls everywhere; tests should crash if dask is not installed, not be skipped silently (well, mostly silently). Existing tests currently on main already use dask without importorskip, and the CI for the test suite installs dask, so it should be safe to assume dask is available.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

If we're assuming that dask is available for these tests though, why can't we assume that in the source code? My strategy lately has been to hedge with the assumption that dask will eventually be optional at the package level, but you're saying here I should be moving in the opposite direction?

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.

Let's chat offline about this to clear things up and report back here once we're on the same page! I will send you a DM.

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.

Reporting back from our chat: basically, the following are all true, which can be confusing but is technically not self-contradictory:

  1. Tests (and benchmarks) assume all dependencies are installed and do not care about import time, so dask should be imported at tops of files there.
  2. uxarray source code assumes dask is a required dependency, i.e. that it is installed and always safe to import.
  3. uxarray souce code cares about import time, and import dask isn't blazingly fast, so dask should only be imported inside functions that use it, instead of at tops of files.

Conclusion: pytest.importorskip should indeed be removed throughout the test suite.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Dask imports have been moved back to the tops of files for test files

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

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.

4 participants