Skip to contents

cube_climatology() computes a recurrent daily, monthly, or meteorological seasonal climatology without pooling raw observations across years. Raw finite observations are first averaged within each day-year, month-year, or season-year replicate. The climatological mean and sample standard deviation are then calculated across those replicates with equal replicate weights.

Usage

cube_climatology(
  x,
  by,
  period = NULL,
  leap = c("feb28", "drop", "keep"),
  min_n = 1L,
  diagnostics = FALSE
)

Arguments

x

A valid <ocean_cube> using the memory or NetCDF backend.

by

A character scalar selecting "day", "month", or "season".

period

NULL for the full source range, or two ordered bounds defining a closed reference interval. Bounds must use the same Date or POSIXct semantics as x$time; POSIXct bounds are exact UTC instants. Intersecting bounds outside the source range are clipped with one warning and both the requested and effective periods are retained.

leap

Daily leap-day policy: "drop" removes February 29, "keep" retains it as an independent group, and "feb28" first combines February 28 and 29 within a leap year into one equally weighted February-28-equivalent replicate. leap is not applicable to monthly or seasonal climatologies.

min_n

A finite positive integer-like scalar giving the minimum number of valid period-year replicates required per cell and recurrent group.

diagnostics

A non-missing logical scalar. If TRUE, aligned n_clim_valid and replicate-coverage arrays are retained in qa$climatology. Sample SD is always retained independently of this flag.

Value

An in-memory <ocean_cube>. data contains the climatological mean. The aligned sample SD is in climatology$sd, and recurrent keys are in climatology$group_key.

Details

Inner period means use equal finite-observation weighting; duration weighting is not performed. Across years or season-years, every valid replicate has one equal weight. Irregular or gapped sampling emits at most one warning per call and is recorded in provenance. n_clim_total counts eligible calendar-period opportunities, n_clim_valid counts finite period-year replicates, and coverage_fraction = n_clim_valid / n_clim_total when the denominator is positive.

The output always contains a complete recurrent cycle. Daily keys are stable MM-DD values: drop and feb28 use the 365-day year 2001, while keep uses leap year 2000. Monthly timestamps are the first days of 2001. Seasonal timestamps are DJF 2000-12-01, MAM 2001-03-01, JJA 2001-06-01, and SON 2001-09-01. These timestamps are a strictly increasing climatological pseudo-time representation, not the historical reference period. Date input produces Date output; POSIXct input produces UTC POSIXct midnight output.

Partial first and last periods are retained. Lazy NetCDF input is processed with bounded source-period and spatial/depth/variable reads; neither the full source cube nor a full chronological intermediate cube is materialized. cube_slice() and cube_crop() deliberately discard dimensional scientific metadata and record that action in provenance, so select or crop the source before computing a climatology when the SD must remain attached.

Examples

monthly <- ocean_cube(
  lon = -80, lat = -12, depth = 0,
  time = as.Date(c("2020-01-01", "2021-01-01")),
  data = array(c(10, 20), c(1, 1, 1, 2, 1)), vars = "temperature"
)
suppressWarnings(cube_climatology(monthly, by = "month"))
#> <ocean_cube>
#>   backend    : memory
#>   source     : <unspecified>
#>   dimensions : 1 x 1 x 1 x 12 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       : 2001-01-01 to 2001-12-01 (n = 12)
#>   variables  : temperature

daily <- ocean_cube(
  lon = -80, lat = -12, depth = 0,
  time = as.Date(c("2020-02-28", "2020-02-29")),
  data = array(c(20, 40), c(1, 1, 1, 2, 1)), vars = "temperature"
)
cube_climatology(daily, by = "day", leap = "feb28")
#> <ocean_cube>
#>   backend    : memory
#>   source     : <unspecified>
#>   dimensions : 1 x 1 x 1 x 365 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       : 2001-01-01 to 2001-12-31 (n = 365)
#>   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"
)
cube_climatology(seasonal, by = "season")
#> <ocean_cube>
#>   backend    : memory
#>   source     : <unspecified>
#>   dimensions : 1 x 1 x 1 x 4 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       : 2000-12-01 to 2001-09-01 (n = 4)
#>   variables  : temperature
suppressWarnings(cube_climatology(monthly, by = "month", diagnostics = TRUE))
#> <ocean_cube>
#>   backend    : memory
#>   source     : <unspecified>
#>   dimensions : 1 x 1 x 1 x 12 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       : 2001-01-01 to 2001-12-01 (n = 12)
#>   variables  : temperature