% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/bayesian_update.R
\name{update_species_tolerances}
\alias{update_species_tolerances}
\title{Update species tolerance parameters from field observations (Bayesian)}
\usage{
update_species_tolerances(
  records,
  species,
  update_vars = NULL,
  presence_col = "presence",
  method = c("map", "mcmc"),
  n_iter = 5000L,
  n_warmup = 1000L,
  prior_sd_fraction = 0.2,
  min_records = 20L,
  verbose = TRUE
)
}
\arguments{
\item{records}{Dataframe of field observations. Must contain columns
\code{lat}, \code{lon}, a presence/absence column (1 = present, 0 = absent), and
columns matching the environmental variables to update (e.g.
\code{temperature}, \code{salinity}, \code{depth}).}

\item{species}{Character. Species key (e.g. \code{"ostrea_edulis"}). See
\code{\link[=list_species]{list_species()}}.}

\item{update_vars}{Character vector. Variables to update parameters for.
Defaults to all numeric scored variables present in \code{records}.}

\item{presence_col}{Character. Name of presence/absence column (default
\code{"presence"}).}

\item{method}{Character. \code{"map"} (default, fast) or \code{"mcmc"} (full posterior).}

\item{n_iter}{Integer. MCMC iterations (default 5000; ignored for MAP).}

\item{n_warmup}{Integer. MCMC warm-up / burn-in (default 1000; ignored for MAP).}

\item{prior_sd_fraction}{Numeric. Prior SD as fraction of parameter range
(default 0.20 = 20 percent). Wider = weaker / more data-driven prior.}

\item{min_records}{Integer. Minimum matched records required (default 20).}

\item{verbose}{Logical. Print progress and diagnostics (default TRUE).}
}
\value{
Invisibly: a named list with elements:
\itemize{
\item \code{species}: species key
\item \code{method}: "map" or "mcmc"
\item \code{n_records}: number of matched records used
\item \code{loglik_null}: log-likelihood of intercept-only model
\item \code{loglik_fit}: log-likelihood at MAP/posterior mean
\item \code{mcfadden_r2}: 1 - loglik_fit / loglik_null (pseudo-R^2)
\item \code{updated_params}: named list of updated parameter values per variable
\item \code{posterior_sd}: named list of posterior SD per parameter (from Laplace/MCMC)
\item \code{prior_params}: the parameter values before updating (for comparison)
\item \code{convergence}: optim() convergence code (0 = success; MAP only)
}

Side effect: updates the in-session cache accessed by \code{\link[=score_locations]{score_locations()}}.
}
\description{
Fits a Bayesian logistic regression linking AHP suitability scores to
observed presence/absence, then updates the optimal-range tolerance
parameters for one or more scored variables.

\strong{Default method (MAP + Laplace):} finds the Maximum A Posteriori estimate
via \code{optim()} (L-BFGS-B) and approximates the posterior as a multivariate
normal using the numerical Hessian. Fast; suitable for routine use.

\strong{MCMC method:} Random-Walk Metropolis-Hastings sampler for full posterior
samples. Recommended when n < 50 or when credible intervals are needed for
publication. May take several minutes for large parameter sets.

Posteriors are stored in a package-level cache so that repeated calls
accumulate evidence (sequential Bayesian updating). Use
\code{\link[=save_tolerance_update]{save_tolerance_update()}} to persist between sessions.
}
\section{What gets updated}{

For each variable in \code{update_vars}, the function estimates shifts in
\code{optimal_min} and \code{optimal_max} (the sweet-spot bounds), plus
\code{acceptable_min} / \code{poor_min} and \code{acceptable_max} / \code{poor_max} (shoulder
bounds, updated proportionally to maintain curve shape). Parameters are
constrained to biologically plausible ranges via box constraints in the
optimiser.
}

\examples{
\donttest{
# Field records with presence/absence + environmental measurements
records <- data.frame(
  lat      = c(51.5, 51.6, 51.7, 51.8, 51.4),
  lon      = c(-4.1, -4.2, -4.0, -4.3, -4.0),
  presence = c(1, 1, 0, 0, 1),
  temperature = c(16.2, 17.1, 12.3, 11.0, 15.8),
  salinity    = c(32, 33, 31, 30, 34),
  depth       = c(5, 8, 15, 20, 3)
)

fit <- update_species_tolerances(
  records = records,
  species = "ostrea_edulis",
  update_vars = c("temperature", "salinity", "depth")
)

# See updated parameters
get_tolerance_posteriors("ostrea_edulis")

# Re-run predict_oyster -- it will automatically use updated parameters
result <- predict_oyster(survey, "ostrea_edulis")

# Save to disk for next session
save_tolerance_update("ostrea_edulis")
}
}
\seealso{
\code{\link[=get_tolerance_posteriors]{get_tolerance_posteriors()}}, \code{\link[=reset_tolerance_update]{reset_tolerance_update()}},
\code{\link[=save_tolerance_update]{save_tolerance_update()}}, \code{\link[=load_tolerance_update]{load_tolerance_update()}}
}
