Skip to content

Better chunking strategies for constlat intersections and zonal routines. - #1624

Open
cmdupuis3 wants to merge 76 commits into
mainfrom
cmd/accusphere3
Open

Better chunking strategies for constlat intersections and zonal routines.#1624
cmdupuis3 wants to merge 76 commits into
mainfrom
cmd/accusphere3

Conversation

@cmdupuis3

@cmdupuis3 cmdupuis3 commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

This PR contains two post-accusphere optimizations, eliminating low-level hard materializations by using a vector-based masking strategy rather than individual conditionals, and reduced zonal_mean peakmem by building only the candidate faces instead of the whole grid.

Partly addresses #1587

Closes #1650

Overview

Phase A eliminated the largest peak-memory amplifier in the zonal path: the port materialized the whole-grid (n_face, n_max, 2, 3) face-edge array up front (a 5.8× blow-up over the node coordinates, with a ~23 MB build peak on a 28k-face grid) even though each latitude only touches ~1% of faces. I added an @njit(parallel=True) subset builder, _get_cartesian_face_edge_nodes_array_subset, that constructs edges only for the candidate faces of a given latitude/band — bit-identical to indexing the full array — and rewired _compute_non_conservative_zonal_mean and _compute_face_band_weights to build per-candidate subsets instead of the whole grid. Peak memory for a 180-latitude zonal_mean dropped from 23.66 MB to 0.27 MB (≈88×) and it ran ~10% faster (no full build, no per-latitude fancy-index copies), verified lossless via a git-stash A/B (the only diff was a pre-existing 4.4e-16 parallel-reduction nondeterminism) with the full zonal/cross-section suite passing.

Phase B moved the six edge/face screeners (constant_lat/lon_intersections_no_extreme, constant_lat/lon_intersections_face_bounds, faces_within_lat/lon_bounds) off @njit and onto plain vectorized NumPy, drawing the boundary so the low-level Numba kernels stay for real geometry while these memory-bound elementwise predicates use NumPy — which is ~2.1× faster here and, unlike an njit kernel that forces a full .values materialization, composes with dask (a single _flatnonzero helper leans on NumPy's array_function protocol so a dask mask reduces block-wise, no explicit dask branch). Call sites pass .data instead of .values so a chunked grid stays lazy, and edge coordinates are gathered positionally (node_z.data[conn.ravel()].reshape(...)) to stay chunk-friendly. Along the way it fixed two real latent bugs: get_edges_at_constant_latitude referenced a nonexistent self.edge_node_z (it raised AttributeError on every call), and both edge paths crashed on chunked grids because xarray can't vindex with a dask indexer. Results are bit-identical to the original per-element loops across 300 randomized trials, dask==numpy, and it's committed as bf0abbe "Lazy intersections".

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

rajeeja added 30 commits June 8, 2026 15:47
…rite intersections, add 241 baseline testsgit status! - most came from accusphere
- benchmarks/geometry_kernels.py: ASV micro-benchmarks for all three
  layers of the EFT intersection stack (_accux_gca, _try_gca_gca_intersection,
  gca_gca_intersection, _accux_constlat, _try_gca_const_lat_intersection,
  gca_const_lat_intersection) plus EFT primitives and point-in-polygon;
  all functions warmed before timing so results reflect steady-state cost
- test/test_plot.py: add test_to_raster_auto_extent verifying that the
  axis limits change and the raster contains finite data
…rectness fixes

Review comments addressed:
- Remove "near-double precision" / "sufficient" overclaims; say "roughly twice
  as accurate" and note the robustness tier boundary clearly
- Explain _lon_bounds_from_vertices is required for UXarray antimeridian
  encoding and cannot be removed
- Add block comment before _no_extreme functions clarifying they are
  pre-existing edge screeners unrelated to the EFT stack
- Document SoS as explicit future work in _point_in_polygon_sphere docstring
- L2 pos_fin/neg_fin: replace ternary with int(); exploit neg=-pos symmetry
- Label computation: drop dead local*0 term, use integer mask arithmetic
- Remove vertex-lat snap from bounds: _face_location_info already captures
  interior arc extrema accurately via the compensated kernel
- _ON_MINOR_ARC_TOL: document intentional 1e-10 vs C++ 1e-8 divergence

Bug fixes:
- on_minor_arc: add antipodal-endpoint guard; a x b = 0 for antipodal inputs
  so every point on the great circle passes the collinearity test (false pos)
- bounds.py: replace mask arithmetic use_ext*z_ext + (1-use_ext)*z_edge with
  plain if/else; 0*NaN = NaN propagates when norm=0, if/else does not
- _point_in_polygon_sphere: ray-nudge now restarts the loop from i=0 so all
  edges are counted with the same ray (mid-loop nudge corrupted crossing parity)

Cleanup:
- Remove _flip_sign, _SIGN_NEG, _SIGN_POS, _SIGN_ZERO dead code from
  point_in_face.py; inline literals in _counts_as_crossing
- Remove _SNAP_TOL_DEG constant and snap_tol_deg parameter throughout bounds.py
- Notebook: fix Grid.get_point_on_face -> get_faces_containing_point; remove
  incorrect geometry.py row from Section 4 table; add accucross_pair and
  acc_sqrt_re to Section 2 building-blocks table
…PI name

- ci/environment.yml: pin tornado<6.5.7 to avoid ssl.SSLError in panel 1.9.3
  on Python 3.11 Windows (conda-forge regression, 2026-06-10)
- intersections.py: remove _gca_gca_intersection_cartesian shim (dead code);
  add comment explaining _snap_const_lat_endpoint snap_sq constant
- test_intersections.py: update 4 call sites to use gca_gca_intersection directly
- spherical-geometry-accuracy.ipynb: fix stale Grid.get_point_on_face ->
  Grid.get_faces_containing_point (2 occurrences)
…rite intersections, add 241 baseline testsgit status! - most came from accusphere
Reconcile diverged accusphere branch. Resolutions:
- intersections.py: restore inline=always on L1 kernels (_accux_constlat,
  _accux_gca) for allocation scalar-replacement
- point_in_face.py: keep restart-loop ray casting (consistent parity),
  adopt named sign constants, drop unused _flip_sign
- arcs.py: keep antipodal-endpoint guard in on_minor_arc
- bounds.py: keep vertex-latitude snapping (snap_tol_deg) path
- computing.py: keep detailed docstring with SIAM/EGUsphere references
Add an LLVM fma intrinsic and route two_prod through a single fused
multiply-add for its error term on hardware that supports it, selected at
import time and validated to be bit-exact against the Veltkamp split. Falls
back to the portable Veltkamp form otherwise, so there is no hard FMA
dependency.

The FMA path is ~2x faster in the compensated geometry kernels (each
two_prod drops from ~17 flops to one FMADD) and is numerically identical:
all 241 AccuSphGeom baseline cases pass unchanged.
Add _accux_constlat_scalar, which takes the arc endpoints as six scalars and
returns the candidate coordinates as scalars instead of two np.empty(3)
arrays. _accux_constlat now wraps it so the array API is unchanged.

Returning scalars lets Numba keep the candidates in registers, so a batch
loop over many edges does no per-point heap allocation. On a 16M-point
const-lat sweep this is ~2.7x faster than the array-returning path and drops
the AccuX/FP64 cost ratio from ~19x to ~7x. Bit-identical results; all 241
AccuSphGeom baseline cases pass.
@cmdupuis3 cmdupuis3 self-assigned this Jul 27, 2026
@cmdupuis3 cmdupuis3 added the scalability Related to scalability & performance efforts label Jul 27, 2026
@cmdupuis3

Copy link
Copy Markdown
Collaborator Author

pre-commit.ci autofix

@cmdupuis3 cmdupuis3 added the benchmarking Related to benchmarks, memory usage, and/or time profiling label Jul 28, 2026
@cmdupuis3 cmdupuis3 added the run-benchmark Run ASV benchmark workflow label Jul 29, 2026
@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have improved:

Change Before [fa82d7b] After [ff458b6] Ratio Benchmark (Parameter)
- 520M 336M 0.65 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
- 631M 336M 0.53 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
- 12.1±1ms 10.6±0.02ms 0.87 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
- 436M 331M 0.76 mpas_ocean.FaceAreas.peakmem_compute_face_areas('480km')
- 431M 330M 0.76 mpas_ocean.Gradient.peakmem_gradient('480km')
- 26.7±0.1ms 9.17±0.04ms 0.34 mpas_ocean.ZonalAverage.time_zonal_average('120km')
- 5.93±0.05ms 4.77±0.2ms 0.81 mpas_ocean.ZonalAverage.time_zonal_average('480km')

Benchmarks that have stayed the same:

Change Before [fa82d7b] After [ff458b6] Ratio Benchmark (Parameter)
200±0.6ms 199±0.9ms 1.00 bench_connectivity.Connectivity.time_edge_face('120km')
12.4±0.4ms 12.0±0.04ms 0.97 bench_connectivity.Connectivity.time_edge_face('480km')
198±0.4ms 199±3ms 1.00 bench_connectivity.Connectivity.time_edge_node('120km')
11.1±0.06ms 11.1±0.02ms 1.00 bench_connectivity.Connectivity.time_edge_node('480km')
199±1ms 214±10ms 1.08 bench_connectivity.Connectivity.time_face_edge('120km')
11.4±0.06ms 11.7±0.1ms 1.02 bench_connectivity.Connectivity.time_face_edge('480km')
877±4ms 878±5ms 1.00 bench_connectivity.Connectivity.time_face_face('120km')
55.7±2ms 55.6±0.2ms 1.00 bench_connectivity.Connectivity.time_face_face('480km')
74.4±3μs 67.3±1μs ~0.90 bench_connectivity.Connectivity.time_face_node('120km')
70.6±3μs 69.9±2μs 0.99 bench_connectivity.Connectivity.time_face_node('480km')
416±5μs 420±10μs 1.01 bench_connectivity.Connectivity.time_n_nodes_per_face('120km')
349±20μs 351±7μs 1.01 bench_connectivity.Connectivity.time_n_nodes_per_face('480km')
11.5±0.04ms 11.4±0.1ms 0.99 bench_connectivity.Connectivity.time_node_edge('480km')
79.9±3ms 79.3±2ms 0.99 bench_connectivity.Connectivity.time_node_face('120km')
5.17±0.2ms 5.24±0.03ms 1.01 bench_connectivity.Connectivity.time_node_face('480km')
334M 334M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
364M 366M 1.01 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
8.46±0.04ms 8.44±0.07ms 1.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
2.66±0.02ms 2.74±0.05ms 1.03 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
10.1±0.03ms 10.2±0.04ms 1.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
2.11±0.03ms 2.17±0.01ms 1.03 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.18±0.05μs 1.22±0.04μs 1.03 geometry_kernels.AccucrossKernels.time_accucross
2.77±0.03μs 2.78±0.03μs 1.00 geometry_kernels.AccucrossKernels.time_accucross_pair
446±10ns 426±10ns 0.96 geometry_kernels.EFTPrimitives.time_acc_sqrt_re
421±10ns 416±20ns 0.99 geometry_kernels.EFTPrimitives.time_diff_of_products
385±10ns 371±10ns 0.96 geometry_kernels.EFTPrimitives.time_two_prod
371±10ns 381±8ns 1.03 geometry_kernels.EFTPrimitives.time_two_sum
1.52±0.02μs 1.49±0.04μs 0.98 geometry_kernels.GCAConstLatIntersection.time_accux_constlat_kernel
1.14±0.02μs 1.10±0.02μs 0.96 geometry_kernels.GCAConstLatIntersection.time_gca_const_lat_intersection
1.91±0.05μs 1.90±0.05μs 1.00 geometry_kernels.GCAConstLatIntersection.time_try_gca_const_lat_intersection
1.65±0.01μs 1.63±0.06μs 0.99 geometry_kernels.GCAGCAIntersection.time_accux_gca_kernel
1.42±0.02μs 1.43±0.05μs 1.01 geometry_kernels.GCAGCAIntersection.time_gca_gca_intersection
2.21±0.03μs 2.16±0.03μs 0.98 geometry_kernels.GCAGCAIntersection.time_try_gca_gca_intersection
51.6±1μs 50.1±1μs 0.97 geometry_kernels.OrientPredicates.time_on_minor_arc
1.08±0.03μs 1.13±0.04μs 1.04 geometry_kernels.OrientPredicates.time_orient3d_on_sphere
2.73±0.1ms 2.61±0.01ms 0.95 geometry_samebody.SameBodyConstLat.time_accux_dispatch
1.17±0.01ms 1.17±0.01ms 1.00 geometry_samebody.SameBodyConstLat.time_accux_kernel
1.72±0.01ms 1.71±0.01ms 1.00 geometry_samebody.SameBodyConstLat.time_fp64_dispatch
147±3μs 148±0.7μs 1.00 geometry_samebody.SameBodyConstLat.time_fp64_kernel
32.6±0.1ms 32.6±0.2ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_dispatch
10.2±0ms 10.2±0.01ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_kernel
26.4±0.03ms 26.4±0.03ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_dispatch
5.05±0.01ms 4.90±0.02ms 0.97 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_kernel
805±4ms 822±10ms 1.02 import.Imports.timeraw_import_uxarray
2.73±0.03ms 2.83±0.01ms 1.04 mpas_ocean.CheckNorm.time_check_norm('120km')
2.24±0.02ms 2.26±0.01ms 1.01 mpas_ocean.CheckNorm.time_check_norm('480km')
827±9ms 851±7ms 1.03 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
53.9±0.6ms 54.5±2ms 1.01 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
666±10μs 652±9μs 0.98 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
573±10μs 600±5μs 1.05 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
5.36±0.01ms 5.41±0.05ms 1.01 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('120km')
3.88±0.03ms 3.92±0.02ms 1.01 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('480km')
3.49±0.04s 3.46±0.03s 0.99 mpas_ocean.ConstructFaceLatLon.time_welzl('120km')
223±0.7ms 223±2ms 1.00 mpas_ocean.ConstructFaceLatLon.time_welzl('480km')
18.2±0.02ms 18.2±0.03ms 1.00 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
1.05±0.01ms 1.03±0.02ms 0.98 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
748±20μs 720±30μs 0.96 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
711±10ms 716±30ms 1.01 mpas_ocean.CrossSections.time_const_lat('120km', 1)
357±3ms 355±5ms 0.99 mpas_ocean.CrossSections.time_const_lat('120km', 2)
183±2ms 182±3ms 0.99 mpas_ocean.CrossSections.time_const_lat('120km', 4)
544±4ms 550±5ms 1.01 mpas_ocean.CrossSections.time_const_lat('480km', 1)
277±3ms 277±3ms 1.00 mpas_ocean.CrossSections.time_const_lat('480km', 2)
143±1ms 142±1ms 1.00 mpas_ocean.CrossSections.time_const_lat('480km', 4)
354M 354M 1.00 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('120km', 1)
354M 354M 1.00 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('120km', 2)
354M 354M 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)
337M 338M 1.00 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('480km', 4)
24.4±0.1ms 24.6±0.6ms 1.01 mpas_ocean.DualMesh.time_dual_mesh_construction('120km')
3.03±0.06ms 3.08±0.1ms 1.02 mpas_ocean.DualMesh.time_dual_mesh_construction('480km')
349M 349M 1.00 mpas_ocean.FaceAreas.peakmem_compute_face_areas('120km')
60.7±0.4ms 60.6±0.08ms 1.00 mpas_ocean.FaceAreas.time_compute_face_areas('120km')
6.87±0.1ms 6.83±0.1ms 0.99 mpas_ocean.FaceAreas.time_compute_face_areas('480km')
958±4ms 946±2ms 0.99 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
51.9±0.7ms 63.6±10ms ~1.23 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
83.6±0.4ms 84.0±0.2ms 1.01 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
5.86±0.05ms 5.58±0.08ms 0.95 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
351M 350M 1.00 mpas_ocean.Gradient.peakmem_gradient('120km')
175±0.5ms 176±0.5ms 1.00 mpas_ocean.Gradient.time_gradient('120km')
12.3±0.03ms 12.4±0.05ms 1.01 mpas_ocean.Gradient.time_gradient('480km')
363±10μs 383±7μs 1.05 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
198±6μs 207±5μs 1.04 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
350M 350M 1.00 mpas_ocean.Integrate.peakmem_integrate('120km')
329M 329M 1.00 mpas_ocean.Integrate.peakmem_integrate('480km')
524±7μs 551±20μs 1.05 mpas_ocean.Integrate.time_integrate('120km')
487±30μs 488±20μs 1.00 mpas_ocean.Integrate.time_integrate('480km')
184±2ms 187±5ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
183±3ms 182±2ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
182±1ms 186±1ms 1.02 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
13.5±0.2ms 14.0±0.3ms 1.03 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
13.7±0.1ms 13.7±0.09ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
13.5±0.3ms 13.9±0.08ms 1.02 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
413±10μs 427±10μs 1.03 mpas_ocean.PointInPolygon.time_face_search_lonlat('120km')
407±10μs 417±9μs 1.02 mpas_ocean.PointInPolygon.time_face_search_lonlat('480km')
377±9μs 383±9μs 1.02 mpas_ocean.PointInPolygon.time_face_search_xyz('120km')
249±0.8ms 246±1ms 0.99 mpas_ocean.RemapDownsample.time_bilinear_remapping
294±8ms 284±3ms 0.97 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
15.6±0.1ms 16.0±0.1ms 1.02 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
1.43±0s 1.46±0.01s 1.02 mpas_ocean.RemapUpsample.time_bilinear_remapping
37.1±0.5ms 36.4±0.4ms 0.98 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
12.5±0.2ms 12.2±0.1ms 0.98 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
378M 358M 0.95 mpas_ocean.ZonalAveragePeakMem.peakmem_zonal_average('120km')
340M 339M 1.00 mpas_ocean.ZonalAveragePeakMem.peakmem_zonal_average('480km')
325M 326M 1.01 quad_hexagon.QuadHexagon.peakmem_open_dataset
324M 324M 1.00 quad_hexagon.QuadHexagon.peakmem_open_grid
7.14±0.2ms 7.03±0.2ms 0.98 quad_hexagon.QuadHexagon.time_open_dataset
5.97±0.1ms 6.01±0.3ms 1.01 quad_hexagon.QuadHexagon.time_open_grid

Benchmarks that have got worse:

Change Before [fa82d7b] After [ff458b6] Ratio Benchmark (Parameter)
+ 199±2ms 222±3ms 1.12 bench_connectivity.Connectivity.time_node_edge('120km')
+ 355±5μs 400±10μs 1.13 mpas_ocean.PointInPolygon.time_face_search_xyz('480km')

@cmdupuis3
cmdupuis3 requested a review from rajeeja July 29, 2026 22:38
@cmdupuis3
cmdupuis3 marked this pull request as ready for review July 29, 2026 22:38
@rajeeja

rajeeja commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Thanks for putting this together. I'll take a look at this and post my comments soon

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

Verified independently: subset builder is bit-identical to whole-grid builder (tested HEALPix + mixed-polygon MPAS), vectorized screeners match brute-force reference, both dask/AttributeError bugs reproduce on main and are fixed here. Two small comments below, non-blocking on correctness but worth addressing before merge.

Comment thread uxarray/core/zonal.py
nedge = n_nodes_per_face[f]
weights[pos] = _compute_band_overlap_area(
faces_edge_nodes_xyz[f, :nedge], zmin, zmax
if partial.size:

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.

New branch (zero partial faces). Add a test for a band with only fully-contained faces.

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.

Not sure what you mean here... The weights are already computed for all faces overlapping the band, this branch only reweights partial faces, so a strict fully-contained set of faces is already accounted for by the time this branch is reached.

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.

Fair — correctness is unaffected. I just meant the partial.size == 0 case is untested; a band with only fully-contained faces would cover it. Non-blocking.

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.

I think it technically is tested for bands=[-90, 90] in test_conservative_full_sphere_conservation, but maybe we can add a test on a less trivial band.

On the other hand, this opened a rabbit hole that led to issue #1644, so we might want to fix that first.

@erogluorhan erogluorhan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Overall this looks good to me. Just a couple questions:

  • Should we worry about the couple benchmarks that got worse? I believe, no, they shouldn't be directly related to the changes here, but am curious about your thoughts.
  • Could you add test cases to cover the two latent bugs that this PR fixes?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

benchmarking Related to benchmarks, memory usage, and/or time profiling 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.

Post-accusphere optimized routines (constlat intersections and zonal)

4 participants