# R-Code to calculate Q10-value based on SCAPE Copyright (C) 2013 Fabian Gans,
# Miguel Mahecha This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your option)
# any later version. This program is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details. You should have received a copy of the GNU
# General Public License along with this program. If not, see
# <http://www.gnu.org/licenses/>.
#' Estimate temperature sensitivty value and time varying $R_b$ from temperature and efflux time series including uncertainty.
#'
#' @description
#' Function to determine the temperature sensitivity sensitivity and time varying
## basal efflux (R$_b(i)$) from a given transformed temperature and efflux
## (usually respiration) time series according the principle of 'SCAle dependent
## Parameter Estimation, SCAPE' (Mahecha et al. 2010). This function should not
## be called directly please use getQ10, getArrhenius or getLloydTaylor instead.
#' @param temperature numeric vector: temperature time series
#' @param respiration numeric vector: respiration time series
#' @param sf numeric: sampling rate, number of measurements (per day)
#' @param gettau numeric: function to transform the exponent in the sensitivity model
#' @param fborder numeric: boundary for dividing high- and low-frequency parts (in days)
#' @param M numeric vector: size of SSA window (in days)
#' @param nss numeric vector: number of surrogate samples
#' @param method String: method to be applied for signal decomposition (choose from 'Fourier','SSA','MA','EMD','Spline')
#' @param weights numeric vector: optional vector of weights to be used for linear regression, points can be set to 0 for bad data points
#' @param lag numeric vector: optional vector of time lags between respiration and temprature signal
#' @param gapFilling Logical: Choose whether Gap-Filling should be applied
#' @param doPlot Logical: Choose whether Surrogates should be plotted
#'
#' @description
#' General Function to determine the temperature sensitivity (\eqn{S}{S} value) and time varying basal efflux (\eqn{R_b}{R_b}) from a given temperature and efflux (usually respiration) time series.
#' The following general model is assumed:
#'
#' \eqn{Resp(i) = R_b e^\frac{S}{tau}}{Resp(i) = Rb exp(S/tau)},
#'
#' where \eqn{i}{i} is the time index. It has been shown, however, that this model is misleading when \eqn{R_b}{Rb} is varying over time which can be expected in many real world examples (e.g. Sampson et al. 2008).
#'
#' If \eqn{R_b}{Rb} varies slowly, i.e. with some low frequency then the 'scale dependent parameter estimation, SCAPE'
#' allows us to identify this oscillatory pattern. As a consequence, the estimation of \eqn{Q_{10}}{Q10} can be substantially stabilized (Mahecha et al. 2010). The model becomes
#'
#' \eqn{Resp(i) = R_b(i)Q_{10}^\frac{T(i)-Tref}{gamma}}{Resp(i) = Rb(i) * Q10^((T(i)-Tref)/(gamma)},
#'
#' where \eqn{R_b(i)}{Rb(i)} is the time varying 'basal respiration', i.e. the respiration expected at \eqn{Tref}{Tref}. The convenience function getQ10 allows to extract the \eqn{Q_{10}}{Q10} value minimizing the confounding factor of the time varying \eqn{R_b}{Rb}. Four different spectral methods can be used and compared. A surrogate technique (function by curtsey of Dr. Henning Rust, written in the context of Venema et al. 2006) is applied to propagate the uncertainty due to the decomposition.
#'
#' The user is strongly encouraged to use the function with caution, i.e. see critique by Graf et al. (2011).
#'
#' @return
#' @export
#'
#' @examples
#'
#' @author
#' Fabian Gans, Miguel D. Mahecha, MPI BGC Jena, Germany, fgans@bgc-jena.mpg.de mmahecha@bgc-jena.mpg.de
getSens <- function(temperature, respiration, sf, gettau, fborder = 30, M = -1, nss = 0,
method = "Fourier", weights = NULL, lag = NULL, gapFilling = TRUE, doPlot = FALSE) {
# Check if weights are given
cat("Checking and preparing data ")
if (length(weights) == 0)
weights = rep(1, length(temperature))
if ((length(weights) != length(temperature)) | (length(weights) != length(respiration)))
stop("Error: Input data must have the same length")
DAT <- data.frame(temperature, respiration, weights)
DAT <- testAndFillMissing(DAT, sf)
if (sd(DAT$temperature) == 0 | sd(DAT$respiration) == 0) {
stop("Constant time series not allowed!")
}
if (mean(DAT$temperature) < 150) {
cat("assuming temperature is given in deg C")
} else {
cat("assuming temperature is given in K")
DAT$temperature <- DAT$temperature - 273.15
}
DAT$respiration[DAT$respiration <= 0] <- quantile(DAT$respiration[DAT$respiration >
0], 0.01) # make sure there are no nonsense values
if (sum(DAT$respiration <= 0) > 0) {
warning("Some respiration data values are below 0. Please check your dataset.")
rold <- DAT$respiration
}
# define the weights
DAT$weights[DAT$respiration <= 0] <- 0
# define tau which will be decomposed
DAT$tau <- gettau(DAT$temperature)
# if (model == 'Q10') { DAT$tau <- (DAT$temperature -Tref)/gam } else if (model
# == 'Arrhenius') { R_gas_const = 8.3144621 # units J K−1 mol−1 DAT$temperature =
# DAT$temperature + 273.15 # Backtransform to Kelvin DAT$tau <-
# -1/DAT$temperature } else if (model == 'LloydTaylor') { Tref = Tref + 273.15 T0
# = 227.13 DAT$temperature = DAT$temperature + 273.15 # Backtransform to Kelvin
# DAT$tau <- ( 1/(Tref-T0) - 1/(DAT$temperature-T0) ) }
# add rho which will be decomposed
DAT$rho <- log(DAT$respiration)
if (any(is.na(DAT$rho))) {
dump.frames("debug_info", to.file = TRUE)
stop("Error, NA values in rho after file prep! See debug_info for details")
}
output <- list()
output$settings <- list()
output$settings$sf <- sf
output$settings$fborder <- fborder
output$settings$M <- M
output$settings$nss <- nss
output$settings$method <- method
output$settings$lag <- lag
output$settings$gapFilling <- gapFilling
cat(" ok\n")
cat("Decomposing datasets")
# Decompose temperature
x <- scapedecomp(x = DAT$tau, sf = sf, fborder = fborder, method = method, Ms = M)
DAT$tau.dec.lf <- x[, 1]
DAT$tau.dec.hf <- x[, 2]
# Decompose respiration
x <- scapedecomp(x = DAT$rho, sf = sf, fborder = fborder, method = method, Ms = M)
DAT$rho.dec.lf <- x[, 1]
DAT$rho.dec.hf <- x[, 2]
cat(" ok\n")
calcSensModel <- function(rho, tau, weights, lag) {
if (lag > 0) {
l <- length(rho)
rho <- rho[(lag + 1):l]
tau <- tau[1:(l - lag)]
weights <- weights[(lag + 1):l] * weights[1:(l - lag)]
} else if (lag < 0) {
l <- length(rho)
rho <- rho[1:(l + lag)]
tau <- tau[(1 - lag):l]
weights <- weights[1:(l + lag)] * weights[(1 - lag):l]
}
lmres <- lm(rho ~ tau - 1, weights = weights)
return(list(XYZ = lmres$coefficients, Confint = confint(lmres)[2] - confint(lmres)[1]))
}
# Generate Ensemble of surrogate base-respiration data
if (nss > 0) {
cat("Generating surrogates")
sur.rho.hf <- .iAAFTSurrogateEnsemble(DAT$rho.dec.hf, nss)
sur.rho <- array(data = rep(DAT$rho.dec.lf, nss), dim = c(nrow(DAT), nss)) +
sur.rho.hf + mean(DAT$rho)
sur.tau.hf <- .iAAFTSurrogateEnsemble(DAT$tau.dec.hf, nss)
sur.tau <- array(data = rep(DAT$tau.dec.lf, nss), dim = c(nrow(DAT), nss)) +
sur.tau.hf + mean(DAT$tau)
cat(" ok\n")
cat("Decomposing surrogates")
ens.dec <- aaply(.data = sur.rho, .fun = scapedecomp, .margins = 2, sf = sf,
fborder = fborder, Ms = M, method = method)
ens.rho.dec.lf <- t(ens.dec[, , 1])
ens.rho.dec.hf <- array(data = rep(DAT$rho, nss), dim = c(nrow(DAT), nss)) -
ens.rho.dec.lf
ens.rho.dec.hf <- apply(ens.rho.dec.hf, 2, function(z) z - mean(z))
ens.dec <- aaply(.data = sur.tau, .fun = scapedecomp, .margins = 2, sf = sf,
fborder = fborder, Ms = M, method = method)
ens.tau.dec.lf <- t(ens.dec[, , 1])
ens.tau.dec.hf <- array(data = rep(DAT$tau, nss), dim = c(nrow(DAT), nss)) -
ens.tau.dec.lf
ens.tau.dec.hf <- apply(ens.tau.dec.hf, 2, function(z) z - mean(z))
cat(" ok\n")
cat("fitting surrogate models")
output$SCAPE_XYZ_surr <- array(data = 0, dim = c(nss, nss))
output$SCAPE_Rb_surr <- array(data = 0, dim = c(nss, nss, nrow(DAT)))
output$SCAPE_Rpred_surr <- array(data = 0, dim = c(nss, nss, nrow(DAT)))
for (i in 1:nss) {
for (j in 1:nss) {
output$SCAPE_XYZ_surr[i, j] <- calcSensModel(ens.rho.dec.hf[, i],
ens.tau.dec.hf[, j], DAT$weights, 0)[[1]]
output$SCAPE_Rb_surr[i, j, ] <- getRb2Sens(tau_lf = ens.tau.dec.lf[,
j], rho_lf = ens.rho.dec.lf[, i], tau = sur.tau[, i], rho = sur.rho[,
j], S = output$SCAPE_XYZ_surr[i, j])
output$SCAPE_Rpred_surr[i, j, ] <- predictR(Rb = output$SCAPE_Rb_surr[i,
j, ], S = output$SCAPE_XYZ_surr[i, j], tau = DAT$tau, lag = 0)
}
}
output$surrogates <- list()
output$surrogates$rho.dec.lf <- ens.rho.dec.lf
output$surrogates$rho.dec.hf <- ens.rho.dec.hf
output$surrogates$tau.dec.lf <- ens.tau.dec.lf
output$surrogates$tau.dec.hf <- ens.tau.dec.hf
cat(" ok\n")
}
cat("Regression of SCAPE and Conventional method")
# No surrogates but taking confidence interval of linear fit
lmres_SCAPE <- calcSensModel(DAT$rho.dec.hf, DAT$tau.dec.hf, DAT$weights, 0)
output$SCAPE_XYZ <- unname(lmres_SCAPE[[1]])
output$SCAPE_XYZ_regression_confint <- unname(lmres_SCAPE[[2]])
if (is.na(output$SCAPE_XYZ)) {
warning("Sensitivity could not be determined, because hf-tau is empty")
output$SCAPE_XYZ <- 1
output$SCAPE_XYZ_regression_confint <- 0
}
# Another comparison, calculate Q10 with linear fit using logarithmic formula
lmres_Conv <- calcSensModel(DAT$rho - mean(DAT$rho), DAT$tau - mean(DAT$tau),
DAT$weights, 0)
output$Conv_XYZ <- unname(lmres_Conv[[1]])
output$Conv_Rb <- unname(exp(mean(DAT$rho) - lmres_Conv[[1]] * mean(DAT$tau)))
output$Conv_XYZ_regression_confint <- unname(lmres_Conv[[2]])
cat(" ok\n")
# Time lagged linear fits
if (length(lag > 0)) {
cat("Calculating time-lagged results")
output$lag_results <- list()
output$lag_results$XYZ <- array(NA, dim = c(length(lag), 4), list(Lag = as.character(lag),
Value = c("SCAPE_XYZ", "+/-", "Conv_XYZ", "+/-")))
ilag <- 1
for (tl in lag) {
lmres_SCAPE <- calcSensModel(DAT$rho.dec.hf, DAT$tau.dec.hf, DAT$weights,
tl)
lmres_Conv <- calcSensModel(DAT$rho - mean(DAT$rho), DAT$tau - mean(DAT$tau),
DAT$weights, tl)
output$lag_results$XYZ[ilag, ] <- c(lmres_SCAPE[[1]], lmres_SCAPE[[2]]/2,
lmres_Conv[[1]], lmres_Conv[[2]]/2)
ilag <- ilag + 1
}
if (nss > 0) {
output$lag_results$surrogate_XYZ <- array(NA, dim = c(length(lag), nss,
nss), list(Lag = as.character(lag), sur_rho = as.character(1:nss),
sur_tau = as.character(1:nss)))
for (i in 1:nss) {
for (j in 1:nss) {
ilag <- 1
for (tl in lag) {
lmres_SCAPE <- calcSensModel(ens.rho.dec.hf[, i], ens.tau.dec.hf[,
j], DAT$weights, tl)
output$lag_results$surrogate_XYZ[ilag, i, j] <- c(lmres_SCAPE[[1]])
ilag <- ilag + 1
}
}
}
}
cat(" ok\n")
}
cat("Reconstructing Rb")
output$SCAPE_Rb <- getRb2Sens(tau_lf = DAT$tau.dec.lf, rho_lf = DAT$rho.dec.lf,
tau = DAT$tau, rho = DAT$rho, S = output$SCAPE_XYZ)
DAT$SCAPE_R_pred <- predictR(Rb = output$SCAPE_Rb, S = output$SCAPE_XYZ, tau = DAT$tau,
lag = 0)
DAT$Conv_R_pred <- predictR(Rb = output$Conv_Rb, S = output$Conv_XYZ, tau = DAT$tau,
lag = 0)
# output$MEF<-MEFW(DAT$respiration_pred,DAT$respiration,w=DAT$weights)
cat(" ok\n")
output$DAT <- DAT
if (doPlot) {
if (nss == 0)
warning("No ensemble plot possible, because number of surrogates is set to 0") else plotensembles(output)
}
## value<< A list with elements $SCAPE_Q10 : the estimated \eqn{Q_{10}}{Q10} with
## the SCAPE principle and the method chosen. $Conv_Q10 : the conventional
## \eqn{Q_{10}}{Q10} (assuming constant Rb) $DAT$SCAPE_R_pred : the SCAPE
## prediction of respiration $DAT$SCAPE_Rb : the basal respiration based on the
## the SCAPE principle $DAT$Conv_R_pred : the conventional prediction of
## respiration $DAT$Conv_Rb : the conventional (constant) basal respiration
return(output)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.