| Title: | Time of Emergence of Climate Signals from Internal Variability |
|---|---|
| Description: | Detects when a forced climate change signal emerges from internal variability ('time of emergence') in annual climate time series such as temperature or precipitation. The signal is estimated with a linear, quadratic or locally weighted smoother and compared with noise estimated from a baseline period. Emergence is defined through configurable signal-to-noise thresholds and persistence rules. Uncertainty in the time of emergence is quantified by autoregressive or moving-block bootstrap resampling. Helpers are provided for multi-member ensembles, threshold sensitivity, anomaly and annual aggregation, Mann-Kendall trend tests with trend-free prewhitening, and synthetic data generation. The approach builds on Hawkins and Sutton (2012) <doi:10.1029/2011GL050087>, Yue et al. (2002) <doi:10.1002/hyp.1095> and Sen (1968) <doi:10.1080/01621459.1968.10480934>. |
| Authors: | Abul Kashem Faruki Fahim [aut, cre, cph] (ORCID: <https://orcid.org/0000-0002-8554-4730>) |
| Maintainer: | Abul Kashem Faruki Fahim <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0 |
| Built: | 2026-10-10 14:14:38 UTC |
| Source: | https://github.com/cran/toeclim |
Draws the observed series, the fitted signal, the noise envelope
(baseline mean +/- k * sigma) and the time of emergence. If a bootstrap
was run, its interval is shaded.
## S3 method for class 'toe' plot(x, xlab = "Time", ylab = "Value", main = "Time of emergence", ...)## S3 method for class 'toe' plot(x, xlab = "Time", ylab = "Value", main = "Time of emergence", ...)
x |
A |
xlab, ylab
|
Axis labels. |
main |
Title. |
... |
Further arguments passed to |
x, invisibly.
d <- toe_simulate(n_years = 150, slope = 0.03, onset = 1970, seed = 8) plot(toe_emerge(d$member_01, d$year, baseline = c(1900, 1950)))d <- toe_simulate(n_years = 150, slope = 0.03, onset = 1970, seed = 8) plot(toe_emerge(d$member_01, d$year, baseline = c(1900, 1950)))
Shows every member (thin lines), the ensemble mean, the pooled emergence time and a rug of the individual member emergence times.
## S3 method for class 'toe_ensemble' plot( x, xlab = "Time", ylab = "Value", main = "Ensemble time of emergence", ... )## S3 method for class 'toe_ensemble' plot( x, xlab = "Time", ylab = "Value", main = "Ensemble time of emergence", ... )
x |
A |
xlab, ylab
|
Axis labels. |
main |
Title. |
... |
Further arguments passed to |
x, invisibly.
d <- toe_simulate(n_years = 150, onset = 1970, n_members = 6, seed = 9) ens <- toe_ensemble(d[, grep("^member", names(d))], d$year, baseline = c(1900, 1950)) plot(ens)d <- toe_simulate(n_years = 150, onset = 1970, n_members = 6, seed = 9) ens <- toe_ensemble(d[, grep("^member", names(d))], d$year, baseline = c(1900, 1950)) plot(ens)
Collapses monthly, daily or other sub-annual observations to one value per
calendar year. Years with too few valid observations are set to NA so that
partial years do not bias the annual statistic.
toe_annual(x, dates, fun = mean, min_frac = 0.8)toe_annual(x, dates, fun = mean, min_frac = 0.8)
x |
Numeric vector of observations. |
dates |
Vector of the same length as |
fun |
Function used to aggregate within each year. Defaults to
|
min_frac |
Minimum fraction (0 to 1) of the maximum number of
observations per year that must be non-missing for a year to be kept.
Defaults to |
A data frame with columns year, value (the aggregated value,
NA for incomplete years) and n (number of valid observations).
dates <- seq(as.Date("2000-01-01"), as.Date("2004-12-01"), by = "month") x <- rnorm(length(dates), mean = 10) x[c(3, 4, 5, 6, 7, 8)] <- NA # a gappy year toe_annual(x, dates)dates <- seq(as.Date("2000-01-01"), as.Date("2004-12-01"), by = "month") x <- rnorm(length(dates), mean = 10) x[c(3, 4, 5, 6, 7, 8)] <- NA # a gappy year toe_annual(x, dates)
Subtracts a climatological mean, computed over a baseline period, from every observation. The climatology can be a single mean or can be resolved by calendar month or day of year to remove the seasonal cycle.
toe_anomaly(x, time, baseline, by = c("none", "month", "day"))toe_anomaly(x, time, baseline, by = c("none", "month", "day"))
x |
Numeric vector of observations. |
time |
Either numeric years (only with |
baseline |
Numeric vector |
by |
Resolution of the climatology: |
A data frame with columns time, value, climatology and
anomaly.
dates <- seq(as.Date("1980-01-01"), as.Date("2019-12-01"), by = "month") x <- 10 + 8 * sin(2 * pi * (as.integer(format(dates, "%m")) - 1) / 12) + rnorm(length(dates)) a <- toe_anomaly(x, dates, baseline = c(1981, 2010), by = "month") head(a)dates <- seq(as.Date("1980-01-01"), as.Date("2019-12-01"), by = "month") x <- 10 + 8 * sin(2 * pi * (as.integer(format(dates, "%m")) - 1) / 12) + rnorm(length(dates)) a <- toe_anomaly(x, dates, baseline = c(1981, 2010), by = "month") head(a)
Estimates when a forced signal becomes distinguishable from internal
variability in a single time series. The series is decomposed into a smooth
signal (relative to the baseline mean) and noise (standard deviation
estimated from the baseline period or from residuals). The time of
emergence is the first time after the baseline at which the
signal-to-noise ratio |S/N| reaches k and persistence criteria are met.
toe_emerge( x, time = NULL, baseline, signal = c("quadratic", "linear", "loess"), span = 0.5, k = 2, persist = 5L, sustain = c("window", "end"), noise = c("baseline", "residual"), direction = c("both", "positive", "negative"), n_boot = 0L, boot = c("ar1", "block"), block_length = NULL, conf_level = 0.9, seed = NULL )toe_emerge( x, time = NULL, baseline, signal = c("quadratic", "linear", "loess"), span = 0.5, k = 2, persist = 5L, sustain = c("window", "end"), noise = c("baseline", "residual"), direction = c("both", "positive", "negative"), n_boot = 0L, boot = c("ar1", "block"), block_length = NULL, conf_level = 0.9, seed = NULL )
x |
Numeric vector, typically annual anomalies or annual means. Missing values are dropped with a warning. |
time |
Numeric vector of times (e.g. years), strictly increasing. If
|
baseline |
Numeric vector |
signal |
Signal estimator: |
span |
Smoothing span for |
k |
Signal-to-noise threshold in units of noise standard deviations.
Default |
persist |
Minimum number of consecutive time steps for which the
threshold must be exceeded. Default |
sustain |
How persistence is judged. |
noise |
Noise estimator. |
direction |
Direction of change that counts as emergence: |
n_boot |
Number of bootstrap replicates used to quantify uncertainty in
the time of emergence. |
boot |
Bootstrap scheme: |
block_length |
Block length for |
conf_level |
Confidence level for the bootstrap interval. Default
|
seed |
Optional integer seed. The global random number state is restored on exit. |
The bootstrap resamples residuals around the fitted signal, adds them back
to the signal, and repeats the entire procedure (signal fit, noise
estimate and emergence rule). The resulting distribution of emergence times
includes NA for replicates that never emerge; the proportion that
emerge is reported as prob_emerged. The interval is computed from the
replicates that do emerge.
Persistence is counted in observations, so time should be regularly
spaced (e.g. annual).
An object of class toe, a list with elements
toeTime of emergence, or NA if the signal never emerges.
dataData frame with time, value, signal (fit minus
baseline mean), snr and exceed.
sigmaNoise standard deviation used.
baseline_meanBaseline mean of x.
bootNULL, or a list with toe (vector of replicate times),
ci, prob_emerged, conf_level and method.
paramsThe settings used.
Forced climate responses are rarely straight lines: they are often flat
and then accelerate. A straight-line fit to such a record is too high early
on and can cross the noise threshold before the change actually begins.
In a simulation study bundled with the package's development (200 series,
true onset 1970, true emergence about 1990), a linear signal produced a
median emergence year of 1971 and emerged before onset in 35% of series,
whereas quadratic and loess signals gave medians of 1990 and 1989 and
never emerged before onset. "quadratic" is therefore the default. Use
"linear" only when a constant rate of change is plausible.
Hawkins, E. and Sutton, R. (2012) doi:10.1029/2011GL050087.
toe_ensemble(), toe_sensitivity(), toe_prob(),
toe_noise(), toe_simulate()
d <- toe_simulate(n_years = 150, slope = 0.03, onset = 1970, sigma = 0.3, phi = 0.5, seed = 10) fit <- toe_emerge(d$member_01, d$year, baseline = c(1900, 1950)) fit # With bootstrap uncertainty (small n_boot to keep the example fast) fit_b <- toe_emerge(d$member_01, d$year, baseline = c(1900, 1950), n_boot = 100, seed = 1) fit_b$boot$ci plot(fit_b)d <- toe_simulate(n_years = 150, slope = 0.03, onset = 1970, sigma = 0.3, phi = 0.5, seed = 10) fit <- toe_emerge(d$member_01, d$year, baseline = c(1900, 1950)) fit # With bootstrap uncertainty (small n_boot to keep the example fast) fit_b <- toe_emerge(d$member_01, d$year, baseline = c(1900, 1950), n_boot = 100, seed = 1) fit_b$boot$ci plot(fit_b)
Applies toe_emerge() to every member of a multi-member ensemble (e.g. a
climate model initial-condition large ensemble) and summarises the spread
of emergence times. Optionally also estimates a pooled emergence time
from the ensemble-mean signal against the average single-member noise.
toe_ensemble(x, time = NULL, baseline, pooled = TRUE, ...)toe_ensemble(x, time = NULL, baseline, pooled = TRUE, ...)
x |
A numeric matrix or data frame with one row per time step and one column per ensemble member. |
time |
Numeric vector of times with length |
baseline |
Numeric vector |
pooled |
Logical. Also estimate the pooled ensemble-mean emergence?
Default |
... |
Further arguments passed to |
An object of class toe_ensemble, a list with
membersData frame with member, toe and sigma.
summaryNamed vector: n, n_emerged, median, min, max,
q05, q95 of member emergence times (over members that emerge).
pooledA toe object for the ensemble mean (or NULL).
dataData frame of time and the input members.
d <- toe_simulate(n_years = 150, slope = 0.03, onset = 1970, n_members = 8, seed = 4) ens <- toe_ensemble(d[, grep("^member", names(d))], d$year, baseline = c(1900, 1950)) ensd <- toe_simulate(n_years = 150, slope = 0.03, onset = 1970, n_members = 8, seed = 4) ens <- toe_ensemble(d[, grep("^member", names(d))], d$year, baseline = c(1900, 1950)) ens
A synthetic data set that mimics a regional annual-mean temperature
anomaly from a single-model initial-condition large ensemble. It is
generated with toe_simulate() and is intended for examples, tests and
teaching; it does not represent any real model or observation.
toe_exampletoe_example
A data frame with 201 rows (1900-2100) and 12 variables:
Calendar year.
The true forced response (degrees C), known by construction.
Annual anomaly (degrees C) for each ensemble member.
The forced response is flat until 1980 and then warms at 0.03 degrees C per year. Noise is AR(1) with standard deviation 0.35 and lag-1 autocorrelation 0.6.
Simulated; see data-raw/toe_example.R.
toe_simulate(), toe_ensemble()
head(toe_example[, 1:4])head(toe_example[, 1:4])
Removes a smooth signal from a series and characterises what is left: its standard deviation, lag-1 autocorrelation and the effective number of independent samples.
toe_noise( x, time = NULL, signal = c("quadratic", "linear", "loess"), span = 0.5 )toe_noise( x, time = NULL, signal = c("quadratic", "linear", "loess"), span = 0.5 )
x |
Numeric vector. |
time |
Numeric vector of times, strictly increasing. If |
signal |
Signal model removed before computing noise statistics:
|
span |
Smoothing span for |
A list with elements sigma (residual standard deviation, adjusted
for the degrees of freedom used by the signal model), phi (lag-1
autocorrelation), n_eff (effective sample size,
n * (1 - phi) / (1 + phi), capped at n), residuals and signal.
d <- toe_simulate(n_years = 100, sigma = 0.3, phi = 0.6, seed = 42) str(toe_noise(d$member_01, d$year)[c("sigma", "phi", "n_eff")])d <- toe_simulate(n_years = 100, sigma = 0.3, phi = 0.6, seed = 42) str(toe_noise(d$member_01, d$year)[c("sigma", "phi", "n_eff")])
Uses the bootstrap distribution stored in a toe_emerge() result to
estimate the probability that the signal has emerged by each of the
supplied times, P(ToE <= t). Replicates that never emerge count as "not
emerged".
toe_prob(object, times)toe_prob(object, times)
object |
A |
times |
Numeric vector of times at which to evaluate the probability. |
A data frame with columns time and prob.
d <- toe_simulate(n_years = 150, slope = 0.03, onset = 1970, seed = 3) f <- toe_emerge(d$member_01, d$year, baseline = c(1900, 1950), n_boot = 100, seed = 2) toe_prob(f, times = c(1990, 2000, 2010, 2030))d <- toe_simulate(n_years = 150, slope = 0.03, onset = 1970, seed = 3) f <- toe_emerge(d$member_01, d$year, baseline = c(1900, 1950), n_boot = 100, seed = 2) toe_prob(f, times = c(1990, 2000, 2010, 2030))
Re-estimates emergence over a grid of signal-to-noise thresholds k and
persistence lengths, making the dependence on these subjective choices
explicit.
toe_sensitivity( x, time = NULL, baseline, k = c(1, 2, 3), persist = c(1, 5, 10), ... )toe_sensitivity( x, time = NULL, baseline, k = c(1, 2, 3), persist = c(1, 5, 10), ... )
x |
Numeric vector, typically annual anomalies or annual means. Missing values are dropped with a warning. |
time |
Numeric vector of times (e.g. years), strictly increasing. If
|
baseline |
Numeric vector |
k |
Numeric vector of thresholds. |
persist |
Numeric vector of persistence lengths. |
... |
Further arguments passed to |
A data frame with columns k, persist and toe.
d <- toe_simulate(n_years = 150, slope = 0.03, onset = 1970, seed = 5) toe_sensitivity(d$member_01, d$year, baseline = c(1900, 1950), k = c(1, 2, 3), persist = c(1, 5, 10))d <- toe_simulate(n_years = 150, slope = 0.03, onset = 1970, seed = 5) toe_sensitivity(d$member_01, d$year, baseline = c(1900, 1950), k = c(1, 2, 3), persist = c(1, 5, 10))
Generates annual series consisting of a piecewise-linear forced response
(flat until onset, then rising at slope per year) plus stationary AR(1)
noise. Useful for testing emergence methods against a known truth.
toe_simulate( n_years = 150, start = 1900, slope = 0.03, onset = start + 60, sigma = 0.3, phi = 0.5, n_members = 1, seed = NULL )toe_simulate( n_years = 150, start = 1900, slope = 0.03, onset = start + 60, sigma = 0.3, phi = 0.5, n_members = 1, seed = NULL )
n_years |
Number of years. Default |
start |
First year. Default |
slope |
Forced trend after |
onset |
Year at which the trend begins. Default |
sigma |
Marginal standard deviation of the noise. Default |
phi |
Lag-1 autocorrelation of the noise, between -1 and 1 (exclusive).
Default |
n_members |
Number of independent noise realisations (ensemble
members). Default |
seed |
Optional integer seed; the global random state is restored. |
A data frame with columns year, forced (the true forced
response) and one column per member named member_01, member_02, ...
d <- toe_simulate(n_years = 100, n_members = 3, seed = 1) head(d)d <- toe_simulate(n_years = 100, n_members = 3, seed = 1) head(d)
Estimates the linear trend with the Theil-Sen estimator and tests its significance with the Mann-Kendall test. Because serial correlation inflates false-positive rates, the test optionally applies trend-free prewhitening (TFPW; Yue et al., 2002) when the lag-1 autocorrelation of the detrended series is significant.
toe_trend(x, time = NULL, conf_level = 0.95, prewhiten = TRUE)toe_trend(x, time = NULL, conf_level = 0.95, prewhiten = TRUE)
x |
Numeric vector. |
time |
Numeric vector of times (e.g. years), strictly increasing. If
|
conf_level |
Confidence level for the slope interval. Default |
prewhiten |
Logical; apply trend-free prewhitening when lag-1
autocorrelation is significant? Default |
An object of class toe_trend, a list with elements slope,
intercept, slope_ci, conf_level, S (Mann-Kendall statistic),
z, p_value, n, r1 (lag-1 autocorrelation of detrended data),
prewhitened (logical) and call. The slope is in units of x per unit
of time.
Sen (1968) doi:10.1080/01621459.1968.10480934; Yue et al. (2002) doi:10.1002/hyp.1095.
d <- toe_simulate(n_years = 80, slope = 0.02, onset = 1900, seed = 1) toe_trend(d$member_01, d$year)d <- toe_simulate(n_years = 80, slope = 0.02, onset = 1900, seed = 1) toe_trend(d$member_01, d$year)