Skip to content

fix calculation in time derivation#397

Merged
rhaegar325 merged 4 commits into
mainfrom
fix_time_mismatching_in_calc_time
May 26, 2026
Merged

fix calculation in time derivation#397
rhaegar325 merged 4 commits into
mainfrom
fix_time_mismatching_in_calc_time

Conversation

@rhaegar325
Copy link
Copy Markdown
Collaborator

Fix tasmax/tasmin monthly time coordinate to month midpoint

Summary

The CMORised time coordinate for the monthly atmosphere variables tasmax and
tasmin was stamped at the end of each month instead of the midpoint of
the time_bnds cell. CF/CMIP6 require a time-mean coordinate to equal the
midpoint of its bounds, and the WCRP checker flagged this as a HIGH-priority
failure [TIME001] Check Time Squareness (weight = 3). This PR fixes the
tasmax/tasmin derivation path so time == midpoint(time_bnds).

Root cause

tasmaxcalculate_monthly_maximum and tasmincalculate_monthly_minimum
(in derivations/calc_utils.py) resampled daily data with
resample({time: "ME"}). Pandas "ME" (Month-End) labels each monthly bin at
the month-end timestamp.

Downstream, calculate_time_bounds builds the correct
[month-start, next-month-start) bounds (it uses only year/month), so time_bnds
was right — but the time coordinate sat at month-end, giving
time ≠ midpoint(time_bnds). Variables sourced from already-monthly data (e.g.
tas) carry mid-month stamps and were never affected, matching the
"only 2 of 86 files fail" observation.

tasmax time[0] = -43799.0  -> 1850-01-31T00:00:00   (month-end, wrong)
expected         -43813.5  -> 1850-01-16T12:00:00   (cell midpoint)

Fix

Added a small helper _monthly_midpoint_coord and applied it right after each
"ME" resample to recentre the time coordinate to the midpoint of its monthly
cell. Handles both datetime64 and cftime calendars.

def _monthly_midpoint_coord(time_da: xr.DataArray) -> xr.DataArray:
    """Relabel a resampled monthly time coordinate to each month's midpoint."""
    values = time_da.values
    is_cftime = isinstance(values.flat[0], cftime.datetime)
    midpoints = np.empty(len(values), dtype=object)
    for i, t in enumerate(values):
        if is_cftime:
            start = cftime.datetime(t.year, t.month, 1, calendar=t.calendar)
            if t.month == 12:
                nxt = cftime.datetime(t.year + 1, 1, 1, calendar=t.calendar)
            else:
                nxt = cftime.datetime(t.year, t.month + 1, 1, calendar=t.calendar)
        else:
            ts = pd.Timestamp(t)
            start = pd.Timestamp(year=ts.year, month=ts.month, day=1)
            nxt = start + pd.offsets.MonthBegin(1)
        midpoints[i] = start + (nxt - start) / 2
    if not is_cftime:
        midpoints = pd.DatetimeIndex(midpoints).values
    return time_da.copy(data=midpoints)

Files changed

File Change
src/access_moppy/derivations/calc_utils.py Add cftime/pandas imports; add _monthly_midpoint_coord; apply after both "ME" resamples; update docstring notes
tests/unit/test_derivations_calc_utils.py Add TestMonthlyTimeCoordinateMidpoint regression tests

@codecov
Copy link
Copy Markdown

codecov Bot commented May 26, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 74.5%. Comparing base (f0f8f8c) to head (66995a7).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##            main    #397     +/-   ##
=======================================
+ Coverage   74.3%   74.5%   +0.2%     
=======================================
  Files         28      28             
  Lines       5200    5237     +37     
  Branches     953     961      +8     
=======================================
+ Hits        3864    3901     +37     
  Misses      1113    1113             
  Partials     223     223             
Flag Coverage Δ
unit 74.5% <100.0%> (+0.2%) ⬆️

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

☔ View full report in Codecov by Sentry.
📢 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.

@rhaegar325 rhaegar325 merged commit c53ce06 into main May 26, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants