% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/dm.detrend.R
\name{dm.detrend.fit}
\alias{dm.detrend.fit}
\title{Detrend and standardize dendrometer series from growth-fit residuals}
\usage{
dm.detrend.fit(
  x,
  series = NULL,
  seasons = NULL,
  epsilon = 1e-06,
  keep_na_rows = FALSE
)
}
\arguments{
\item{x}{An object of class \code{"dm_growth_fit"} returned by
[dm.growth.fit()] or [dm.growth.fit.double()].}

\item{series}{Optional character vector of dendrometer series to retain.
Default is \code{NULL}, meaning all available series are used.}

\item{seasons}{Optional character vector of vegetation-season labels to
retain. Default is \code{NULL}, meaning all available seasons are used.}

\item{epsilon}{Small positive constant added after shifting residuals by their
seasonal minimum. Default is \code{1e-6}. Use \code{0} to allow exact zeros.}

\item{keep_na_rows}{Logical. If \code{TRUE}, rows are retained even when the
observed or fitted value is missing; detrended values remain \code{NA}.
If \code{FALSE} (default), rows with missing observed or fitted values are
removed from the long output before standardization.}
}
\value{
A list of class \code{"dm_detrended"} with elements:
\describe{
  \item{call}{The matched function call.}
  \item{detrended_data}{Wide-format tibble with metadata columns and one
    detrended standardized series column per dendrometer.}
  \item{detrended_long}{Long-format tibble containing original daily values,
    reconstructed fitted values on the original scale, residuals, shifted
    residuals, and detrended standardized values.}
  \item{parameters}{Per-series and per-season summary table containing
    baseline values and residual standardization parameters.}
  \item{source_fit_statistics}{The original \code{x$fit_statistics} table.}
}
}
\description{
Creates detrended standardized dendrometer series from objects returned by
[dm.growth.fit()] or [dm.growth.fit.double()].

The function compares the original daily dendrometer series
(`x$original_daily_data`) with the fitted growth curve from `x$fitted_data`.
Because fitted values are stored on the processed scale used for modelling,
the function first reconstructs fitted values on the original daily scale by
adding back the seasonal baseline (the first non-missing original daily value
of each series within each vegetation season).

Residuals are then calculated as:
\deqn{residual = observed_{daily} - fitted_{original\ scale}}

To obtain a detrended standardized series with mean equal to 1 and no negative
values, residuals are transformed within each \code{series × season_label} as:
\deqn{z = \frac{residual - \min(residual) + \epsilon}{\mathrm{mean}(residual - \min(residual) + \epsilon)}}

where \eqn{\epsilon > 0} is a small constant ensuring strictly positive values.
If all residuals within a season are identical, the standardized series
becomes a constant vector of 1.
}
\details{
The function uses \code{x$original_daily_data}, which must be present in the
input object. If the object was created by an older version of
[dm.growth.fit()] or [dm.growth.fit.double()] that did not store
\code{original_daily_data}, the function will stop with an informative error.

Standardization is carried out separately within each vegetation season. This
means the mean of the detrended standardized series is 1 for each
\code{series × season_label}, not necessarily across the entire dataset.
}
\examples{
\donttest{
data(gf_nepa17)

fit1 <- dm.growth.fit(
  df = gf_nepa17,
  TreeNum = 1:2,
  method = "gompertz",
  year_mode = "yearly",
  verbose = FALSE
)

det1 <- dm.detrend.fit(fit1)
head(det1$detrended_data)
head(det1$parameters)

fit2 <- dm.growth.fit.double(
  df = gf_nepa17,
  TreeNum = 1,
  method = "gompertz",
  year_mode = "yearly",
  verbose = FALSE
)

det2 <- dm.detrend.fit(fit2)
head(det2$detrended_long)
}

}
