Compares each source observation with the mean or mean/SD pair for the same recurrent day, month, or meteorological season. Matching uses the canonical group key rather than climatological pseudo-time.
Usage
cube_anomaly(x, climatology, type = c("difference", "z"))Arguments
- x
A valid memory or lazy NetCDF ocean cube.
- climatology
An intact in-memory result from
cube_climatology().- type
Either "difference" or "z".
Details
climatology must be the intact canonical memory cube returned by
cube_climatology(), including its aligned sample SD and complete recurring
group key. A climatology whose scientific metadata were discarded by a
selection or crop is rejected. Its reference period identifies the baseline
but does not restrict source timestamps, so x may fall inside or outside
that period.
Longitude, latitude, depth, variables and variable order must be exactly identical. Defined unit strings and canonical calendars must match exactly; if both sides lack units the computation continues with a warning and an unverified-units QA record. One-sided missing units or different strings are errors, and no unit conversion is attempted. Date sources require a Date baseline and POSIXct sources require the baseline's recorded POSIXct input class; POSIXct instants remain UTC with sub-day precision. There is no interpolation, tolerance, subsetting, conversion, or automatic reordering.
Matching uses recurrent keys rather than climatological pseudo-time:
MM-DD for daily, 01 through 12 for monthly, and DJF/MAM/JJA/SON for
seasonal climatology. Daily leap = "keep" matches February 29 separately,
"drop" retains its source timestamp but returns NA, and "feb28" maps it
to the February-28-equivalent group without shifting March 1. Subdaily
observations remain pointwise and use their UTC calendar day/month/season.
Difference anomalies are source - climatological mean and preserve source
units. Z anomalies divide that difference by the climatological sample SD
and use unit "1" for every variable. Only finite source, mean, and (for z)
SD values are computed. Zero or non-finite SD produces NA, any negative
finite SD is a global climatology error, and every positive finite SD,
however small, is valid. Canonical output never retains Inf or NaN.
Memory and lazy NetCDF sources share the same calculation. Lazy sources are read through bounded indexed blocks rather than as one complete source cube; the final anomaly cube is materialized in memory with source dimensions and timestamps plus compact QA and provenance.
Examples
x <- ocean_cube(
lon = -80, lat = -12, depth = 0,
time = as.Date(c("2020-01-01", "2021-01-01")),
data = array(c(12, 8), c(1, 1, 1, 2, 1)),
vars = "temperature", units = "degC"
)
baseline <- suppressWarnings(cube_climatology(x, "month"))
cube_anomaly(x, baseline, "difference")
#> <ocean_cube>
#> backend : memory
#> source : <unspecified>
#> dimensions : 1 x 1 x 1 x 2 x 1 [lon x lat x depth x time x var]
#> lon : -80 to -80 (n = 1)
#> lat : -12 to -12 (n = 1)
#> depth : 0 to 0 (n = 1)
#> time : 2020-01-01 to 2021-01-01 (n = 2)
#> variables : temperature
cube_anomaly(x, baseline, "z")
#> <ocean_cube>
#> backend : memory
#> source : <unspecified>
#> dimensions : 1 x 1 x 1 x 2 x 1 [lon x lat x depth x time x var]
#> lon : -80 to -80 (n = 1)
#> lat : -12 to -12 (n = 1)
#> depth : 0 to 0 (n = 1)
#> time : 2020-01-01 to 2021-01-01 (n = 2)
#> variables : temperature
daily <- ocean_cube(
lon = -80, lat = -12, depth = 0,
time = as.Date(c("2020-02-28", "2020-02-29", "2021-02-28")),
data = array(c(10, 14, 12), c(1, 1, 1, 3, 1)),
vars = "temperature", units = "degC"
)
daily_clim <- suppressWarnings(cube_climatology(daily, "day", leap = "feb28"))
cube_anomaly(daily, daily_clim)
#> <ocean_cube>
#> backend : memory
#> source : <unspecified>
#> dimensions : 1 x 1 x 1 x 3 x 1 [lon x lat x depth x time x var]
#> lon : -80 to -80 (n = 1)
#> lat : -12 to -12 (n = 1)
#> depth : 0 to 0 (n = 1)
#> time : 2020-02-28 to 2021-02-28 (n = 3)
#> variables : temperature
seasonal <- ocean_cube(
lon = -80, lat = -12, depth = 0,
time = as.Date(c("2025-12-15", "2026-01-15", "2026-02-15")),
data = array(c(3, 6, 9), c(1, 1, 1, 3, 1)),
vars = "temperature", units = "degC"
)
seasonal_clim <- suppressWarnings(cube_climatology(seasonal, "season"))
cube_anomaly(seasonal, seasonal_clim)
#> <ocean_cube>
#> backend : memory
#> source : <unspecified>
#> dimensions : 1 x 1 x 1 x 3 x 1 [lon x lat x depth x time x var]
#> lon : -80 to -80 (n = 1)
#> lat : -12 to -12 (n = 1)
#> depth : 0 to 0 (n = 1)
#> time : 2025-12-15 to 2026-02-15 (n = 3)
#> variables : temperature