Fix leap-year Oct/Dec notch in the monthly FOD decay mask - #39
Merged
Conversation
estimate_emissions_monthly masked deposits younger than the ~half-year emission lag with a strict `integral_adjusted > 0`. The cutoff is integral_adjusted == 0 (deposit exactly 0.5 yr old). In a LEAP year the monthly grid lands exactly on it for the deposit six months before a 31-day emission month (Jun->Dec, Apr->Oct: 183/366 == 0.5); in a common year it lands just past it (183/365 == 0.50137). Because integral_adjusted is a difference of two O(k) cumulative sums, at the cutoff it is 0 +/- ~1e-15 (catastrophic cancellation), so a bare `> 0` dropped that whole deposit-month unpredictably -> a spurious ~1-2% notch in the 31-day peak months (Oct, Dec) in leap years only. This surfaced as Climate TRACE QA "de-trended z-score > 3" flags on modeled countries at Oct-2020/Dec-2020 (e.g. BGD, CMR). Fix: mask with a tolerance (`>= -1e-9`) — well below any real k-time step (genuine just-past-cutoff values are ~1e-4..1e-3) but above FP noise — so the exact-half-year deposit is retained consistently in leap and common years. Impact (model-output-change): within-year redistribution only; the leap-year monthly profile is smoothed (Oct/Dec notch closes to the ~0.2% genuine 365-vs-366-day floor), and leap-year ANNUAL totals rise by the physically-real extra-day mass (~+0.25%; +0.36% on a BGD-like hot/wet growing site). Common years are bit-for-bit unchanged; only leap-year Oct/Dec cells move, all additive, no other-month leakage (validated across k regimes + BGD's real inputs). Reported/single-value sites are unaffected (this path is modeled-only). Paired with RMI_Climate_TRACE_Waste_Methane PR #78 (branch country-exceedance-source-trace), whose diagnostic surfaced and traced this. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Fixes a leap-year floating-point edge case in SWEET’s monthly first-order-decay kernel by making the half-year emission-lag mask tolerant to numerical noise at the exact cutoff, preventing spurious Oct/Dec dips in leap years for modeled sites.
Changes:
- Replace a strict
integral_adjusted > 0mask with a tolerance-based cutoff (>= -1e-9) to avoid grid-aligned half-year artifacts in leap years. - Add detailed in-code rationale documenting the leap-year cutoff alignment and the FP cancellation behavior.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes a leap-year artifact in SWEET's monthly first-order-decay kernel (
estimate_emissions_monthly) that produced a spurious ~1–2% dip in the 31-day peak months (October, December) of modeled sites, in leap years only. It surfaced as Climate TRACE QA "de-trended z-score > 3" flags on smoothly-growing modeled countries at Oct-2020 and Dec-2020 (e.g. Bangladesh, Cameroon), traced by the diagnostic in the paired RMI PR (see below).Bug
SWEET_python/model_v2.py→SWEET.estimate_emissions_monthly(the modeled-site monthly path; reported/single-value sites don't use it).Root cause
The kernel masks deposits younger than the ~half-year emission lag with a strict
integral_adjusted > 0(L270). The cutoff isintegral_adjusted == 0(deposit exactly 0.5 yr old). In a leap year the monthly grid lands exactly on it for the deposit six months before a 31-day emission month (Jun→Dec, Apr→Oct:183/366 == 0.5); in a common year it lands just past (183/365 == 0.50137). Sinceintegral_adjustedis a difference of two O(k) cumulative sums, at the cutoff it evaluates to0 ± ~1e-15(catastrophic cancellation) — so a bare> 0(and, as tested, a bare>= 0) includes/drops that whole deposit-month unpredictably, notching Oct/Dec in leap years. September (184/366 = 0.5027) never grid-aligns → no notch (confirming null).Fix
Mask with a small tolerance:
integral_adjusted >= -1e-9. The tolerance is far below any real k-time step (genuine just-past-cutoff values are ~1e-4…1e-3) but above FP noise, so the exact-half-year deposit is retained consistently in leap and common years.Impact —
model-output-changeWithin-year redistribution; common years are bit-for-bit unchanged. In leap years:
Only modeled sites are affected; reported/single-value city paths use a flat
annual/12split and are untouched.Validation
Ran the real kernel (DB-free
City.site_only_estimate_trace→estimate_emissions_monthly), UNFIXED vs fixed, on constant-waste normal-k (k≈0.17) and fast-k (k≈0.69) sites and a BGD-like site built from asset 13169's actual parquet inputs (25.8 °C / 1955 mm, dumpsite, open 1990, growing waste reproduced to the ton):Whole-series diff (every month 2000–2050): the only cells that change are leap-year October and December, all additive; zero non-leap and zero other-calendar-month movement.
Acceptance Criteria
model-output-change.>= 0).Definition of Done
Cross-repo pairing: branch
country-exceedance-source-trace, paired withRMI_Climate_TRACE_Waste_MethanePR #78 (thecountry_exceedance_trace.pydiagnostic that surfaced and traced this). Please review/merge together.🤖 Generated with Claude Code