Skip to contents

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".

Value

An in-memory ocean cube with source dimensions and timestamps.

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