Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,12 @@
* **`LCR`**, the Labrador Current retroflection index, joins the climate index
catalog. Published with Jutras et al. (2023) and cited in `index_dictionary()`.

* **Every climate index now declares its `units`**, surfaced in
`index_dictionary()`. Most are standardized anomalies, in standard deviations
rather than anything physical; only `AMO` (degrees C) and `AMOC` (Sverdrups)
carry real units. A coefficient fitted to one of those is not comparable with
one fitted to `NAO`, and a table of model output gave no way to tell.

* **`AMOC`**, the overturning transport measured by the RAPID array at 26.5°N,
joins it too. Unlike the other indices this is a direct measurement rather than
a pressure or SST pattern — which is also its limitation: it begins in April
Expand Down
21 changes: 16 additions & 5 deletions R/climate_indices.R
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
#' year?") and useless for spatial ones. A model given only indices cannot
#' produce a map.
#'
#' @return a named list, one entry per index, each with `label`, `source`,
#' `url`, and `description`
#' @return a named list, one entry per index, each with `label`, `units`,
#' `source`, `url`, and `description`
#' @examples
#' names(climate_indices())
#' @seealso [fetch_climate_index()], [attach_climate_index()]
Expand All @@ -20,6 +20,7 @@ climate_indices <- function() {
list(
NAO = list(
label = "North Atlantic Oscillation",
units = "standardized anomaly",
source = "NOAA CPC",
url = "https://www.cpc.ncep.noaa.gov/products/precip/CWlink/pna/norm.nao.monthly.b5001.current.ascii.table",
format = "cpc_table",
Expand All @@ -31,6 +32,7 @@ climate_indices <- function() {
),
AO = list(
label = "Arctic Oscillation",
units = "standardized anomaly",
source = "NOAA CPC",
url = "https://www.cpc.ncep.noaa.gov/products/precip/CWlink/daily_ao_index/monthly.ao.index.b50.current.ascii.table",
format = "cpc_table",
Expand All @@ -40,6 +42,7 @@ climate_indices <- function() {
),
AMO = list(
label = "Atlantic Multidecadal Oscillation",
units = "degrees C",
source = "NOAA PSL",
url = "https://psl.noaa.gov/data/correlation/amon.us.long.data",
format = "psl_table",
Expand All @@ -50,6 +53,7 @@ climate_indices <- function() {
),
PDO = list(
label = "Pacific Decadal Oscillation",
units = "standardized anomaly",
source = "NOAA PSL",
url = "https://psl.noaa.gov/data/correlation/pdo.data",
format = "psl_table",
Expand All @@ -60,6 +64,7 @@ climate_indices <- function() {
),
LCR = list(
label = "Labrador Current retroflection",
units = "fraction",
source = "Jutras et al. 2023, Nature Communications",
url = paste0("https://static-content.springer.com/esm/",
"art%3A10.1038%2Fs41467-023-38321-y/MediaObjects/",
Expand All @@ -83,6 +88,7 @@ climate_indices <- function() {
),
AMOC = list(
label = "Atlantic Meridional Overturning Circulation",
units = "Sv",
source = "RAPID-MOCHA-WBTS array at 26.5N",
url = "https://rapid.ac.uk/sites/default/files/rapid_data/moc_transports.nc",
format = "rapid_netcdf",
Expand Down Expand Up @@ -118,8 +124,13 @@ index_dictionary <- function() {
catalog <- climate_indices()
dictionary <- do.call(rbind, lapply(names(catalog), function(name) {
entry <- catalog[[name]]
data.frame(name = name, label = entry$label, source = entry$source,
url = entry$url,
data.frame(name = name, label = entry$label,
# Most of these are standardized anomalies, which is a unit in
# the sense that matters: it says the number is in standard
# deviations rather than in anything physical, so a coefficient
# fitted to it is not comparable with one fitted to AMOC.
units = entry$units %||% NA_character_,
source = entry$source, url = entry$url,
# Indices published with a paper carry its citation. The
# operational ones from NOAA have no single paper to point at,
# so this is empty for them rather than invented.
Expand All @@ -139,7 +150,7 @@ print.datamatch_index_dictionary <- function(x, ...) {
flat <- as.data.frame(x)
cat("Climate indices available by name\n")
cat(strrep("-", 62), "\n", sep = "")
print(flat[c("name", "label", "source")], row.names = FALSE, right = FALSE)
print(flat[c("name", "label", "units", "source")], row.names = FALSE, right = FALSE)
cat("\nThese have no spatial dimension: one value per month, basin-wide.\n")

cited <- flat[!is.na(flat$reference), ]
Expand Down
21 changes: 13 additions & 8 deletions README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -701,14 +701,19 @@ useless for spatial ones. A model given only indices cannot produce a map.

Six are available, and they are not interchangeable.

| Name | What it measures | Timescale | Record |
|---|---|---|---|
| `NAO` | Pressure difference, Icelandic Low to Azores High | Year to year | 1950– |
| `AO` | Strength of the polar vortex | Year to year | 1950– |
| `AMO` | Detrended North Atlantic SST anomaly | Multidecadal | 1948– |
| `PDO` | Leading mode of North Pacific SST | Decadal | 1948– |
| `LCR` | Retroflection of the Labrador Current | Year to year | 1993–2014 |
| `AMOC` | Overturning transport at 26.5°N | Year to year | 2004– |
| Name | What it measures | Units | Timescale | Record |
|---|---|---|---|---|
| `NAO` | Pressure difference, Icelandic Low to Azores High | standardized anomaly | Year to year | 1950– |
| `AO` | Strength of the polar vortex | standardized anomaly | Year to year | 1950– |
| `AMO` | Detrended North Atlantic SST anomaly | degrees C | Multidecadal | 1948– |
| `PDO` | Leading mode of North Pacific SST | standardized anomaly | Decadal | 1948– |
| `LCR` | Retroflection of the Labrador Current | fraction | Year to year | 1993–2014 |
| `AMOC` | Overturning transport at 26.5°N | Sv | Year to year | 2004– |

Most are **standardized anomalies** — in standard deviations, not anything
physical. Only `AMO` (degrees C) and `AMOC` (Sverdrups) carry real units, so a
coefficient fitted to one of those is not comparable with one fitted to `NAO`.
`index_dictionary()` carries the units at runtime.

**`NAO`** is the usual first choice in the Northwest Atlantic. It sets the
strength and track of the westerlies, and with them heat flux and mixing over the
Expand Down
21 changes: 13 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -780,14 +780,19 @@ useless for spatial ones. A model given only indices cannot produce a map.

Six are available, and they are not interchangeable.

| Name | What it measures | Timescale | Record |
|---|---|---|---|
| `NAO` | Pressure difference, Icelandic Low to Azores High | Year to year | 1950– |
| `AO` | Strength of the polar vortex | Year to year | 1950– |
| `AMO` | Detrended North Atlantic SST anomaly | Multidecadal | 1948– |
| `PDO` | Leading mode of North Pacific SST | Decadal | 1948– |
| `LCR` | Retroflection of the Labrador Current | Year to year | 1993–2014 |
| `AMOC` | Overturning transport at 26.5°N | Year to year | 2004– |
| Name | What it measures | Units | Timescale | Record |
|---|---|---|---|---|
| `NAO` | Pressure difference, Icelandic Low to Azores High | standardized anomaly | Year to year | 1950– |
| `AO` | Strength of the polar vortex | standardized anomaly | Year to year | 1950– |
| `AMO` | Detrended North Atlantic SST anomaly | degrees C | Multidecadal | 1948– |
| `PDO` | Leading mode of North Pacific SST | standardized anomaly | Decadal | 1948– |
| `LCR` | Retroflection of the Labrador Current | fraction | Year to year | 1993–2014 |
| `AMOC` | Overturning transport at 26.5°N | Sv | Year to year | 2004– |

Most are **standardized anomalies** — in standard deviations, not anything
physical. Only `AMO` (degrees C) and `AMOC` (Sverdrups) carry real units, so a
coefficient fitted to one of those is not comparable with one fitted to `NAO`.
`index_dictionary()` carries the units at runtime.

**`NAO`** is the usual first choice in the Northwest Atlantic. It sets the
strength and track of the westerlies, and with them heat flux and mixing over the
Expand Down
4 changes: 2 additions & 2 deletions man/climate_indices.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions tests/testthat/test-climate-indices.R
Original file line number Diff line number Diff line change
Expand Up @@ -542,3 +542,33 @@ test_that("the overturning index carries its citation", {
expect_true(any(grepl("Cite when used", output)))
expect_true(any(grepl("AMOC", output)))
})

test_that("every index declares its units", {
# A coefficient fitted to AMOC is in Sverdrups; one fitted to NAO is per
# standard deviation. Without units recorded, the two look comparable in a
# table of model output and are not.
catalog <- climate_indices()

for (name in names(catalog)) {
expect_true(nzchar(catalog[[name]]$units %||% ""),
info = paste(name, "has no units"))
}

# The physical ones say what they are; the standardized ones say that they
# are standardized rather than pretending to be dimensionless.
expect_equal(catalog$AMOC$units, "Sv")
expect_equal(catalog$AMO$units, "degrees C")
expect_equal(catalog$NAO$units, "standardized anomaly")
})

test_that("units reach the dictionary and its printed output", {
dictionary <- as.data.frame(index_dictionary())

expect_true("units" %in% names(dictionary))
expect_false(anyNA(dictionary$units))
expect_equal(dictionary$units[dictionary$name == "AMOC"], "Sv")

output <- capture.output(print(index_dictionary()))
expect_true(any(grepl("units", output)))
expect_true(any(grepl("Sv", output)))
})
Loading