% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/api-advanced.R
\name{anchor_to_baseline}
\alias{anchor_to_baseline}
\alias{print.mfrm_anchored_fit}
\alias{summary.mfrm_anchored_fit}
\alias{print.summary.mfrm_anchored_fit}
\title{Fit new data anchored to a baseline calibration}
\usage{
anchor_to_baseline(
  new_data,
  baseline_fit,
  person,
  facets,
  score,
  anchor_facets = NULL,
  include_person = FALSE,
  weight = NULL,
  model = NULL,
  method = NULL,
  anchor_policy = "warn",
  ...
)

\method{print}{mfrm_anchored_fit}(x, ...)

\method{summary}{mfrm_anchored_fit}(object, ...)

\method{print}{summary.mfrm_anchored_fit}(x, ...)
}
\arguments{
\item{new_data}{Data frame in long format (one row per rating).}

\item{baseline_fit}{An \code{mfrm_fit} object from a previous calibration.}

\item{person}{Character column name for person/examinee.}

\item{facets}{Character vector of facet column names.}

\item{score}{Character column name for the rating score.}

\item{anchor_facets}{Character vector of facets to anchor (default: all
non-Person facets).}

\item{include_person}{If \code{TRUE}, also anchor person estimates.}

\item{weight}{Optional character column name for observation weights.}

\item{model}{Scale model override; defaults to baseline model.}

\item{method}{Estimation method override; defaults to baseline method.}

\item{anchor_policy}{How to handle anchor issues: \code{"warn"}, \code{"error"},
\code{"silent"}.}

\item{...}{Ignored.}

\item{x}{An \code{mfrm_anchored_fit} object.}

\item{object}{An \code{mfrm_anchored_fit} object (for \code{summary}).}
}
\value{
Object of class \code{mfrm_anchored_fit} with components:
\describe{
\item{fit}{The anchored \code{mfrm_fit} object.}
\item{diagnostics}{Output of \code{\link[=diagnose_mfrm]{diagnose_mfrm()}} on the anchored fit.}
\item{baseline_anchors}{Anchor table extracted from the baseline.}
\item{drift}{Tibble of element-level drift statistics.}
}
}
\description{
Re-estimates a fitted many-facet model on new data while holding selected
facet parameters fixed at the values from a previous (baseline) calibration.
This is the standard workflow for placing new data onto an existing scale,
linking test forms, or carrying a baseline calibration across
administration windows.
For bounded \code{GPCM}, treat this as direct exploratory anchor/drift support
rather than as the package's formal linking-synthesis route.
}
\details{
This function automates the baseline-anchored calibration workflow:
\enumerate{
\item Extracts anchor values from the baseline fit using \code{\link[=make_anchor_table]{make_anchor_table()}}.
\item Re-estimates the model on \code{new_data} with those anchors fixed via
\code{fit_mfrm(..., anchors = anchor_table)}.
\item Runs \code{\link[=diagnose_mfrm]{diagnose_mfrm()}} on the anchored fit.
\item Computes element-level differences (new estimate minus baseline
estimate) for every common element.
}

The \code{model} and \code{method} arguments default to the baseline fit's settings
so the calibration framework remains consistent.  Elements present in the
anchor table but absent from the new data are handled according to
\code{anchor_policy}: \code{"warn"} (default) emits a message, \code{"error"} stops
execution, and \code{"silent"} ignores silently.

The returned \code{drift} table is best interpreted as an anchored consistency
check. When a facet is fixed through \code{anchor_facets}, those anchored levels
are constrained in the new run, so their reported differences are not an
independent drift analysis. For genuine cross-wave drift monitoring, fit the
waves separately and use \code{\link[=detect_anchor_drift]{detect_anchor_drift()}} on the resulting fits.

Element-level differences are calculated for every element that appears in
both the baseline and the new calibration:
\deqn{\Delta_e = \hat{\delta}_{e,\text{new}} - \hat{\delta}_{e,\text{base}}}
An element is \strong{flagged} when \eqn{|\Delta_e| > 0.5} logits or
\eqn{|\Delta_e / SE_{\Delta_e}| > 2.0}, where
\eqn{SE_{\Delta_e} = \sqrt{SE_{\mathrm{base}}^2 + SE_{\mathrm{new}}^2}}.
}
\section{Which function should I use?}{

\itemize{
\item Use \code{anchor_to_baseline()} when you have one new dataset and want to place
it directly on a baseline scale.
\item Use \code{\link[=detect_anchor_drift]{detect_anchor_drift()}} when you already have multiple fitted waves
and want to compare their stability.
\item Use \code{\link[=build_equating_chain]{build_equating_chain()}} when you need cumulative offsets across an
ordered series of waves.
}
}

\section{Interpreting output}{

\itemize{
\item \verb{$drift}: one row per common element with columns \code{Facet}, \code{Level},
\code{Baseline}, \code{New}, \code{Drift}, \code{SE_Baseline}, \code{SE_New}, \code{SE_Diff},
\code{Drift_SE_Ratio}, and \code{Flag}.
Read this as an anchored consistency table. Small absolute differences
indicate that the anchored re-fit stayed close to the baseline scale.
Flagged rows warrant review, but they are not a substitute for a separate
drift study on unanchored common elements.
\item \verb{$fit}: the full anchored \code{mfrm_fit} object, usable with
\code{\link[=diagnose_mfrm]{diagnose_mfrm()}}, \code{\link[=measurable_summary_table]{measurable_summary_table()}}, etc.
\item \verb{$diagnostics}: pre-computed diagnostics for the anchored calibration.
\item \verb{$baseline_anchors}: the anchor table fed to \code{\link[=fit_mfrm]{fit_mfrm()}}, useful for
reviewing which elements were constrained.
}
}

\section{Typical workflow}{

\enumerate{
\item Fit the baseline model: \code{fit1 <- fit_mfrm(...)}.
\item Collect new data (e.g., a later administration).
\item Call \code{res <- anchor_to_baseline(new_data, fit1, ...)}.
\item Inspect \code{summary(res)} to confirm the anchored run remains close to the
baseline scale.
\item For multi-wave drift monitoring, fit waves separately and pass the fits to
\code{\link[=detect_anchor_drift]{detect_anchor_drift()}} or \code{\link[=build_equating_chain]{build_equating_chain()}}.
}
}

\examples{
\donttest{
d1 <- load_mfrmr_data("study1")
keep1 <- unique(d1$Person)[1:15]
d1 <- d1[d1$Person \%in\% keep1, , drop = FALSE]
fit1 <- fit_mfrm(d1, "Person", c("Rater", "Criterion"), "Score",
                 method = "JML", maxit = 30)
d2 <- load_mfrmr_data("study2")
keep2 <- unique(d2$Person)[1:15]
d2 <- d2[d2$Person \%in\% keep2, , drop = FALSE]
res <- anchor_to_baseline(d2, fit1, "Person",
                          c("Rater", "Criterion"), "Score",
                          anchor_facets = "Criterion")
summary(res)
head(res$drift[, c("Facet", "Level", "Drift", "Flag")])
res$baseline_anchors[1:3, ]
}
}
\seealso{
\code{\link[=fit_mfrm]{fit_mfrm()}}, \code{\link[=make_anchor_table]{make_anchor_table()}}, \code{\link[=detect_anchor_drift]{detect_anchor_drift()}},
\code{\link[=diagnose_mfrm]{diagnose_mfrm()}}, \code{\link[=build_equating_chain]{build_equating_chain()}}, \link{mfrmr_linking_and_dff}
}
