i7aof.time¶
Purpose: Time utilities for annual averaging, CMIP-focused annual drivers, and time-bounds helpers used across workflows.
Public Python API (by module)¶
Module:
i7aof.time.averageannual_average(): Compute weighted annual means from monthly inputs; outputs one annual file per input. CLI:ismip7-antarctic-annual-average.
Module:
i7aof.time.cmipcompute_cmip_annual_averages(): Driver that discovers bias-corrected monthly CT/SA and TF files per model/scenario/climatology and writes annual means intoOyr/ct_sa_tf. CLI:ismip7-antarctic-cmip-annual-averages.
Module:
i7aof.time.boundscapture_time_bounds(): Capture existingtime_bndsif present, returning the variable name and DataArray (optional tuple).inject_time_bounds(): Inject previously capturedtime_bndsback into a dataset and settime.attrs['bounds']accordingly.
Required config options¶
i7aof.time.average: None.i7aof.time.bounds: None.i7aof.time.cmip: Usesi7aof.config.load_config()to resolveworkdirand grid metadata; no required keys beyond the standard configuration used elsewhere.
Outputs¶
Annual-mean NetCDF files written alongside inputs or into an explicit
out_dir.Naming:
If an input basename contains
Omon_, it is replaced withOyr_.Otherwise,
_annis inserted before the extension.
The CMIP driver combines CT/SA and TF into a shared
Oyr/ct_sa_tfdirectory underworkdir/biascorr/<model>/<scenario>/<clim_name>/.
Data model¶
Weighted monthly-to-annual means using month length via
time.dt.days_in_month.Requires complete years (exactly 12 months per year); errors otherwise.
Annual time stamps are at start-of-year with CF
time_bndscovering[start_of_year, start_of_next_year].Handles common CF calendars (gregorian, noleap, 360_day, proleptic_gregorian) using cftime.
Passes through non-time data vars and coordinates; only data variables with a
timedimension are averaged.Fill values and compression: annual outputs are written via
i7aof.io.write_netcdf()with an explicit policy that only'ct','sa', and'tf'carry_FillValueand compression; coordinate and other non-data variables never receive_FillValueencodings.
Runtime and external requirements¶
Core:
xarray,cftime,numpy.Interop:
i7aof.iofor robust NetCDF writing and CF time normalization;i7aof.coordsfor grid coordinate/bounds attachment and fill suppression on non-data.CLI: None beyond the project’s standard dependencies; see
dev-spec.txtfor the full conda-forge environment.
Usage¶
Python API (monthly → annual):
from i7aof.time.average import annual_average
outs = annual_average(["/path/to/monthly_*.nc"], out_dir="/out/annual", overwrite=True)
for p in outs:
print(p)
CLI (monthly → annual):
ismip7-antarctic-annual-average \
"/path/to/*.nc" \
--outdir "/out/annual" \
--overwrite
CMIP driver (bias-corrected CT/SA + TF):
from i7aof.time.cmip import compute_cmip_annual_averages
outs = compute_cmip_annual_averages(
model="NorESM2-MM", scenario="ssp585", clim_name="06_nov",
workdir="/scratch/work", overwrite=False, progress=True)
ismip7-antarctic-cmip-annual-averages \
-m NorESM2-MM -s ssp585 -c 06_nov \
-w /scratch/work --overwrite
Time-bounds helpers:
from i7aof.time.bounds import capture_time_bounds, inject_time_bounds
import xarray as xr
ds = xr.open_dataset("in.nc")
time_bounds = capture_time_bounds(ds)
# ... operations that drop/modify bounds ...
inject_time_bounds(ds, time_bounds)
Internals (for maintainers)¶
annual_average:
Expands globs, deduplicates inputs, and validates presence of a
timedimension.Heuristic chunking along
time(12) to avoid full loads; leveragesread_datasetfor cftime decoding.Verifies exactly 12 months per year; raises a helpful error listing offending years when possible.
Weights by days-in-month; casts float64 to float32 for data vars before averaging; preserves attributes.
Constructs
timeandtime_bndswith cftime classes based on the detected calendar.Keeps other coords and non-time data variables; sets
time.attrs['bounds'] = 'time_bnds'.Suppresses fill on non-data vars internally (via the time/encoding helpers in
i7aof.io) and writes usingi7aof.io.write_netcdf()withhas_fill_values=['ct','sa','tf']andcompression=['ct','sa','tf'].Writes to a temp file in the output directory and atomically renames to the final filename.
cmip:
Loads config to resolve
workdir; discovers monthly inputs underbiascorr/.../Omon/{ct_sa,tf}; writes annual outputs toOyr/ct_sa_tf.After averaging, re-opens each output to attach grid coordinates/bounds and re-applies the fill/compression policy before atomically replacing the file.
bounds:
capture_time_boundslooks uptime.attrs['bounds']and returns(name, dataarray)if present.inject_time_boundsputs the bounds variable back into the target dataset and resets thetimecoordinateboundsattribute.
Edge cases / validations¶
Missing
timedimension: error with a clear message.Non-12-month years: error with a list of offending years when available.
No data variables with a
timedimension: error.Calendar handling: defaults to proleptic gregorian when not specified; cftime classes used for supported calendars.
Safe writes: temp-file then atomic rename avoids partial outputs and supports resuming after interruptions.
Performance: chunking along
timeonly; all scans/writes are lazy-friendly.
Extension points¶
Seasonal or custom-period averages; mid-year time labeling options.
Configurable list of variables to carry
_FillValue/compression.Multi-file annual averaging with alignment; inclusion of additional metadata.