Skip to content

Streamline exact rolling output construction - #775

Merged
d-chambers merged 2 commits into
masterfrom
rolling-fast-mean
Jul 25, 2026
Merged

Streamline exact rolling output construction#775
d-chambers merged 2 commits into
masterfrom
rolling-fast-mean

Conversation

@d-chambers

@d-chambers d-chambers commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Description

Follow-up to #765 and #768, covering the "additional exact rolling cleanup" items: reduce the per-call overhead of patch.rolling(...) without changing any numerics.

Profiling a representative localized DAS patch ((28, 600) float32, 10-sample centered distance window) showed that ~90% of a rolling mean was metadata and array bookkeeping rather than the reduction itself. Three things stood out:

  • _PatchRollerInfo inherits from a pydantic model, so every patch.rolling(...) call paid validation for an ephemeral, internal object.
  • _pad_roll_array allocated three arrays: astype then np.pad then np.roll. Because the padding is all NaN, the roll is equivalent to writing the data at an offset, so one allocation suffices.
  • Both engines built the output through Patch.update(data=..., coords=..., attrs=...). That calls CoordManager.update_from_attrs, and then Patch.__init__ reconciles attrs against coords again, so the coord summaries were rebuilt twice per call even though the roller had already produced a valid CoordManager and PatchAttrs.

Changes:

  • _PatchRollerInfo is now a frozen dataclass.
  • _pad_roll_array pads and centers in a single allocation.
  • get_coords returns the patch's coord manager unchanged when there is no step (the rolling dimension is unchanged in that case).
  • A shared _new_patch helper constructs the output Patch directly from the coords and attrs the roller already built. Both engines use it.

No public API or behavior change; engine, step, center, overlap and all reductions behave exactly as before.

Verification

Output was compared against master over a sweep of 3,536 combinations: both engines, all six reductions plus apply, 1D/2D/3D patches, int64/float32/float64 data, data containing NaN and ±inf, patches with units and with non-dimensional coords, windows of 1/2/3/11, with and without step and centering. Data bytes, dtype, shape, coords and serialized attrs are identical in every case, and the 182 combinations that raise produce the same exception and message.

Timings

Wall clock per call, mean of 200 runs:

Case master this PR
(28, 600) distance window 10, centered 0.634 ms 0.319 ms
(28, 600) time window 10 0.874 ms 0.582 ms
(28, 600) window 11, step 3, centered 0.687 ms 0.423 ms
(300, 2000) time window 10 16.23 ms 13.60 ms
pandas engine, 1D, window 5 1.375 ms 1.115 ms

The large-patch case gains less because it is dominated by the reduction itself rather than by overhead.

Checklist

I have (if applicable):

  • referenced the GitHub issue this PR closes.
  • documented the new feature with docstrings and/or appropriate doc page.
  • included tests. See testing guidelines.
  • added the "ready_for_review" tag once the PR is ready to be reviewed.

Summary by CodeRabbit

  • Bug Fixes
    • Improved rolling mean correctness, including proper step handling, padding/alignment, and centering behavior.
    • Preserved rolling metadata: coordinates, units, non-coordinate attributes, dimension info, and consistent history entries.
  • Performance
    • Optimized rolling execution by reducing redundant patch/coordinate reconciliation and improving array padding/alignment.
  • Tests
    • Added a benchmark covering the full rolling-mean call path.
    • Added tests validating rolling metadata preservation and accurate metadata updates.

The numpy roller allocated three arrays to pad and center its result, and
both engines rebuilt the output Patch through Patch.update, which
reconciles attrs against coords a second time even though the roller has
already built both. _PatchRollerInfo also paid pydantic validation on
every rolling call despite being an ephemeral internal object.

- make _PatchRollerInfo a frozen dataclass
- pad and center in a single allocation instead of pad + roll
- reuse the patch coord manager when there is no step
- construct the output Patch directly from the built coords and attrs

Output is bit-for-bit unchanged: data, coords, attrs and raised errors
match over a sweep of both engines, all reductions, apply, 1D/2D/3D,
int/float32/float64, NaN and inf data, and windows of 1-11 with and
without step and centering.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@d-chambers d-chambers added the ready_for_review PR is ready for review label Jul 25, 2026
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 221d18dc-0730-46d4-8f6c-44f3f68b4729

📥 Commits

Reviewing files that changed from the base of the PR and between 2dea65f and 8d1b78d.

📒 Files selected for processing (1)
  • tests/test_proc/test_rolling.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/test_proc/test_rolling.py

📝 Walkthrough

Walkthrough

Changes

Rolling metadata and output handling

Layer / File(s) Summary
Rolling state and output construction
dascore/proc/rolling.py
Replaces the rolling state model with a frozen slots dataclass, updates stepped-coordinate computation, and constructs output patches directly.
Engine-specific rolling results
dascore/proc/rolling.py
Aligns NumPy results through NaN-filled arrays and updates Pandas repacking to use direct patch construction with attributes.
Metadata validation and benchmark coverage
tests/test_proc/test_rolling.py, benchmarks/test_patch_benchmarks.py
Adds metadata-preservation tests and a benchmark covering rolling-object creation plus mean computation.

Possibly related PRs

  • DASDAE/dascore#681: Updates the same rolling engine implementations and patch/coordinate repacking paths.

Suggested labels: proc

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change to rolling output construction.
Description check ✅ Passed The description follows the template with problem, changes, verification, timings, and checklist items filled in.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rolling-fast-mean

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot added patch related to Patch class proc Related to processing module labels Jul 25, 2026
@codecov

codecov Bot commented Jul 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.93%. Comparing base (09aac2f) to head (8d1b78d).
⚠️ Report is 2 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #775   +/-   ##
=======================================
  Coverage   99.93%   99.93%           
=======================================
  Files         145      145           
  Lines       12859    12864    +5     
=======================================
+ Hits        12851    12856    +5     
  Misses          8        8           
Flag Coverage Δ
unittests 99.93% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@dascore/proc/rolling.py`:
- Around line 153-156: Update the rolling execution path around the raw result
conversion before _pad_roll_array: preserve the dtype returned by function, and
only promote or cast when required to represent NaN padding. Avoid forcing
float64 so float32 remains float32 and complex outputs retain their imaginary
components, while keeping _new_patch and the existing rolling flow unchanged.

In `@tests/test_proc/test_rolling.py`:
- Around line 291-295: Update test_attrs_conform_to_coords to parameterize the
rolling engine over both "numpy" and "pandas", pass the selected engine to
random_patch.rolling, and retain the existing attrs/coords assertions for each
parameterized case.
- Around line 260-267: Strengthen rolling metadata tests in
tests/test_proc/test_rolling.py at lines 260-267 and 284-289: update
test_units_preserved to include or iterate over a non-dimension coordinate and
verify its units after rolling, and update the later test to compare that
coordinate’s values and metadata with the input rather than only checking its
name and presence.
- Around line 276-282: Strengthen test_history_appended for both parametrized
engines by replacing the broad history[-1] substring check with an exact
assertion that the new entry ends with ".apply(mean)" or matches the fully
formatted expected history entry, while preserving the existing length
assertion.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e61e08eb-fbeb-4cc1-998b-0304450d4b32

📥 Commits

Reviewing files that changed from the base of the PR and between 2426bbc and 2dea65f.

📒 Files selected for processing (3)
  • benchmarks/test_patch_benchmarks.py
  • dascore/proc/rolling.py
  • tests/test_proc/test_rolling.py

Comment thread dascore/proc/rolling.py
Comment thread tests/test_proc/test_rolling.py
Comment thread tests/test_proc/test_rolling.py Outdated
Comment thread tests/test_proc/test_rolling.py Outdated
- assert the exact history entry per engine
- check units and values of non-dimensional coords, not just dims
- exercise both engines for the non-dim coord and attrs/coords cases
@coderabbitai coderabbitai Bot removed the patch related to Patch class label Jul 25, 2026
@d-chambers
d-chambers merged commit 357968b into master Jul 25, 2026
26 checks passed
@d-chambers
d-chambers deleted the rolling-fast-mean branch July 25, 2026 08:39
@d-chambers d-chambers mentioned this pull request Aug 4, 2026
4 tasks
@d-chambers d-chambers removed the ready_for_review PR is ready for review label Aug 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

proc Related to processing module

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant