---
title: '**ipsecr** 1.4 - spatially explicit capture--recapture by inverse prediction'
author: "Murray Efford"
date: "`r Sys.Date()`"
output: 
  pdf_document: 
    toc: yes
    toc_depth: 1
vignette: > 
  %\VignetteIndexEntry{Spatially explicit capture--recapture by inverse prediction}
  \usepackage[utf8]{inputenc}
  %\VignetteEngine{knitr::rmarkdown}
header-includes: 
   - \renewcommand{\vec}[1]{\mathbf{#1}}
---

\vspace{12pt}

This document provides an overview of **ipsecr** 1.4, an R package for spatially explicit capture--recapture analysis (SECR) that uses simulation and inverse prediction instead of maximum likelihood, as in **secr** (Efford 2022), or MCMC, as in various Bayesian approaches. The parent package **secr** included the function `ip.secr`, now deprecated; **ipsecr** extends that capability in its central function `ipsecr.fit` whose arguments are closely modelled on `secr.fit` from **secr**. 

Simulation and inverse prediction allows some models to be fitted that strictly cannot be fitted by other methods. Single-catch traps are a common example.

There are limitations: **ipsecr** 1.4 allows variation in detection parameters (e.g., $\lambda_0$, $\sigma$) only with respect to individual and session. This excludes variation with respect to occasion, detector or previous detection (e.g., ~t, ~b or ~bk as allowed in **secr**). **ipsecr** does allow variation in $\lambda_0$ and $\sigma$ that depends on the location of each animal's activity centre, which is not allowed in **secr**.  

The package **plot3D** should be installed to display Fig. 2, and some results require secr >= 4.5.9.

# Inverse prediction for capture--recapture estimation

The method (Efford 2004; Efford, Dawson and Robbins 2004; see also Carothers 1979 and Pledger and Efford 1998) uses a vector-valued function of the raw data that provides one or more proxies for each coefficient (beta parameter) in the capture--recapture model. Each proxy is assumed to be monotonically related to the corresponding coefficient. 

We use $\vec x_p$ for the vector of known parameter values at which simulations are performed and $\vec y_p$ for the vectors of proxies computed from these simulated data. The method fits a multivariate multiple regression over a set of points in parameter space ('box') and inverts that regression to estimate parameter values $\vec x$ from the observed proxy vector $\vec y$.

The default proxy function `proxy.ms` works for simple models with two detection parameters. It uses a naive non-spatial estimate of population size (simply the number detected), the corresponding non-spatial detection probability $p$, and the 'root-pooled spatial variance' measure from the function `RPSV` in **secr** (argument CC = TRUE):

| Parameter | Proxy | Proxy scale |
|-----------|-------|-------------|
| Density D | number detected $n$ | log |
| Detection intercept $g_0$ or $\lambda_0$* | $\hat p$ | cloglog |
| Detection spatial scale $\sigma$ | RPSV | log |
\* depends on detection function

The monotonic relationship is demonstrated by simulation in the following figure.

![](linearityplot.png)

**Figure 1.** Monotonic relationships between parameters (x-axis, log scale) and their default proxies (y-axis). 100 single-catch traps at 20-m spacing on a square grid. 50 simulations for each level, with other parameters held at their central value. Red line follows mean.

The algorithm includes these steps

1. Compute proxy function from data
2. Simulate data for parameters at the vertices* of a box around plausible estimates
3. Compute proxy function for each simulation to generate predictor matrix 
4. Fit a multivariate multiple regression model with proxies at each vertex as the dependent variables
5. Invert regression model to estimate vector of parameters from the data proxies (1)
6. If the estimated parameters do not all lie inside box, adjust the box and repeat from (2)
7. Simulate at the estimates to obtain variance-covariance matrix 

\* including some centre points

```{r schematic, fig.width=6.5, fig.height=6.5, message = FALSE, echo = FALSE}
library(ipsecr)
if (requireNamespace('plot3D')) {
    par(mfrow=c(2,2), mar=c(1,1,1,1), oma=c(1,1,2,1))
    oldplot <- plot3D.IP(ipsecrdemo)
    plot3D.IP(ipsecrdemo, box=2, oldplot)
    mtext(outer = TRUE, side = 3, c('Parameter space','Proxy space'), 
        adj = c(0.21,0.77))
} else warning ('install package plot3D to generate Fig. 2')
```

**Figure 2.** Schematic process of fitting in `ipsecr.fit` (requires package plot3D). Simulations are conducted at the vertices of a box in parameter space (top left; link scale) centred on an initial guess (blue diamond). The results in proxy space (top right; frame connects design point means, centre omitted for clarity) support a linear model for proxies as a function of parameters. The model is inverted and applied to the observed proxy vector (yellow square) giving the centre of a new, smaller box in parameter space (bottom left). The model is refined by further simulations (bottom right) from which the final estimate is inferred (white square, bottom left)

# Simple example

This example uses a simulated single-catch trap dataset in **secr** that is loaded automatically when **ipsecr** is loaded. See [here](https://www.otago.ac.nz/density/pdfs/secr-datainput.pdf) for instructions on reading actual data.

```{r setup, message = FALSE, results = 'hide'}
library(ipsecr)
if (!require("spatstat")) warning ("install spatstat to run vignette code")
setNumThreads(2)   # adjust to number of available cores
```

```{r options, echo = FALSE}
runall <- FALSE
secr459 <- packageVersion('secr') >= '4.5.9'
```

```{r retrieve, eval = !runall, echo = FALSE}
# previously saved models ... see chunk 'saveall' at end
load(system.file("example", "fittedmodels.RData", package = "ipsecr"))
```


```{r ip.single, eval = runall, purl = FALSE}
ip.single <- ipsecr.fit(captdata, buffer = 100, detectfn = 'HHN')
```

The fitted model is of class 'ipsecr' for which there are the usual methods matching those in **secr** (`print`, `coef`, `predict`, `summary` etc. as detailed [below](#methods)).

```{r ip.single.output}
predict(ip.single)
```

# Proxy functions

The proxy function takes an **secr** capthist object as its first argument. It returns a vector of surrogate values, at least one for each coefficient (beta parameter) in the model. There does not strictly need to be a one-to-one relationship between proxies and coefficients, but multiple proxies have not so far been found useful and may muddy the water. The default function is `proxy.ms`. For example,

```{r exampleproxy}
proxy.ms(captdata)
```

`proxy.ms` works for models with variation in parameters D and NT. Detection parameters may vary spatially and by session. Users are free to define their own proxyfn.

Changing the proxy function may have little effect on the estimates. Here we demonstrate an older builtin proxy function `proxyfn1`:


```{r compareproxy0, eval = runall, purl = FALSE}
ip.single.1 <- ipsecr.fit(captdata, buffer = 100, detectfn = 'HHN', proxyfn = proxyfn1, 
    N.estimator = "null", verbose = FALSE)
```

```{r compareproxy1}
# secr function 'collate' works for both secr and ipsecr fits 
collate(ip.single, ip.single.1)[1,,,]
```

# Multi-session models

Data may take the form of independent samples. Models are constructed as in **secr** ([secr-multisession.pdf]). In **ipsecr  1.4**, density D, detection parameters, and non-target NT parameters may all depend on session or session covariates as in **secr**.

# Fitting a density gradient

Distiller and Borchers (2015) simulated an example with a gradient in population density to demonstrate their method for data from single-catch traps when the time of each capture is known. Inverse prediction may be used to estimate density from these data, but assuming a constant density can result in bias. Here we illustrate a strategy for fitting the density gradient with inverse prediction. 

This requires a proxy function that includes a proxy for the density gradient. As the function is a function of the capture histories alone we must use a gradient over detectors to stand for a gradient over points on the habitat mask. The default function `proxy.ms` does this automatically. A model in terms of mask coordinates and covariates is re-cast as a model in terms of detector coordinates and covariates. Proxies are coefficients of a glm for detector-specific counts as a function of the predictors, using a log link. 

First simulate some data with an east-west gradient in density.

```{r simch, eval = TRUE}
tr <- traps(captdata)
mask <- make.mask(tr)
covariates(mask) <- data.frame(D = (mask$x-265)/20)  # for sim.pop
set.seed(1237)
pop <- sim.popn(D = 'D', core = mask, model2D = 'IHP', buffer = 100)
ch <- sim.capthist(tr, popn = pop, detectfn = 'HHN', noccasions = 5, 
  detectpar = list(lambda0 = 0.2, sigma = 25))
# show east-west trend
table(tr[trap(ch),'x'])
```

Note that the x- and y-coordinates of traps and mask are scaled internally and independently to zero mean and unit variance.

```{r Dsurfacefit, eval = runall, purl = FALSE}
ipx <- ipsecr.fit(ch, mask = mask, detectfn = 'HHN', model = list(D~x))
```

```{r Dsurfaceoutput, eval = TRUE}
coef(ipx)
predict(ipx)
plot(predictDsurface(ipx))
plot(tr, add = TRUE)
plotMaskEdge(ipx$mask, add=T)
```

The fitted relationship is linear on the log scale, whereas it was simulated as linear on the natural scale. To better match the original trend it is possible to use an identity link for D. 

```{r Dsurfacetrend, fig.width = 6, fig.height = 4}
oldpar <- par(mar = c(4,6,4,4))
# model refers to scaled values of x, so repeat here
m <- mean(traps(ch)$x); s <- sd(traps(ch)$x)
xval <- seq(270,730,10)
xvals <- scale(xval, m, s)
pred <- predict(ipx, newdata = data.frame(x = xvals))
plot(0,0, type='n', xlim= c(270,730), ylim = c(0,40), xlab = 'x', ylab = 'Density')
lines(xval, sapply(pred, '[', 'D','estimate'), col = 'red', lwd=2)
abline(-265/20,0.05) # true linear trend
rug(unique(tr$x))    # trap locations
par(oldpar)
```

**Figure 3.** Estimated trend in density from log-linear model (red). Actual trend shown as black line.

# Non-target interference

The capthist data object may include an attribute 'nontarget' that is a binary $K \times S$ matrix ($K$ detectors, $S$ occasions) indicating whether detector $k$ was disturbed or occupied by non-target species on each occasion $s$. 

Disturbance at single-catch and capped detectors is usually taken to be exclusive of captures: an occupied trap cannot later catch a non-target animal or be disturbed, and vice versa. Multi-catch traps or binary proximity detectors may be disturbed after having registered detections, and both detections and interference are recorded (disturbance is independent of prior detector status, and has the effect of truncating the sampling interval). Variations may be specified with the details argument 'nontargettype' that takes one of the values 'exclusive', 'truncated', 'erased' or 'independent'.

| Type | Allowed detectors | Explanation |
|--------|------------|-------------------------------------------|
| 'exclusive' | single, capped | detector may be occupied or interfered with, but not both |
| 'truncated' | all | sampling interval ends at time of interference (default for all detectors except single and capped )|
| 'erased' | all |  interference erases any previous detections at a site in the particular interval|
| 'independent' | all | interference has no effect on detections, but is recorded and modelled | 

We illustrate the fitting of a model with non-target captures by simulating disturbance at about 50% of the 235 unoccupied traps in the 'captdata' dataset. (This is an ad hoc method, used only for generating demonstration data).

```{r nontargetdata}
set.seed(123)
ch <- captdata
attr(ch, 'nontarget') <- (1-t(apply(ch,2:3,sum))) * (runif(500)>0.5)
summary(ch)$nontarget
```

The attribute 'nontarget' is a matrix with one row per trap and one column per occasion. Entries are either 1 (nontarget or disturbed) or 0 (target species or undisturbed). For a dataset including non-target data `ipsecr.fit` automatically adds the parameter 'NT' for the hazard of a single ubiquitous disturbance process competing (in the 'exclusive' case) for detectors with each individual-specific capture process. The  non-target model may be suppressed by setting the details argument 'ignorenontarget = TRUE'.

Information on the disturbance process is given by the frequency of nontarget events in the capthist input (attribute 'nontarget'). The last element of the vector returned by the proxy function `proxy.ms` transforms this to a hazard on the log scale (i.e. complementary log-log of proportion):

```{r proxyfn2demo}
proxy.ms(ch)
```

```{r nontargetdemo, eval = runall, purl = FALSE}
ip.single.nontarget <- ipsecr.fit(ch, detectfn = 'HHN')
```

The estimate of lambda0 has risen compared to ip.single: 
```{r nontargetdemoresults}
predict(ip.single.nontarget)
```

Note that 'NT' cannot be estimated if all traps are occupied. 'NT' may be modelled as a function of session and detector (trap), but not occasion.


# Tuning the algorithm

The inverse prediction method assumes 

1. linear relationships between proxies and parameters (jointly, a hyper-plane), and 
2. negligible error in the predicted (mean) proxy for a given set of parameter values.

Performance of the algorithm with respect to these assumptions depends on several components of the 'details' argument of `ipsecr.fit` that may be seen as tuning parameters. The first assumption is more plausible for small regions of parameter space (hence a small 'boxsize'). The second assumption is eased by increasing the number of simulations. Actual settings are a compromise between these requirements and execution time. Users may choose a different compromise.

By default, the size of the box in parameter space is set to ± 'boxsize' units on the link scale. This may be changed to a multiple of the central value with `boxtype = 'relative'`.

It is usual to start with a wide box and to use a narrower box for subsequent simulations, on the assumption that the first box has selected a region of parameter space very close to the solution.

The stopping criterion 'dev.max' is used to exit the simulation loop early when sufficient precision has been achieved for all parameters. If `boxtype = 'absolute'` then the criterion is the standard error on the link scale. If `boxtype = 'relative'` then the criterion is the relative standard error (RSE or CV) on the link scale.

| Tuning parameter | Default | Description |
|--------------|--------- |----------------------------------|
| boxtype      | 'absolute' | 'absolute' or 'relative'  |
| boxsize1     | 0.2        | size of first box | 
| boxsize2     | 0.05       | boxsize for boxes after the first | 
| centre       | 3          | number of centre points |
| dev.max      | 0.002      | stopping criterion | 
| min.nsim     | 20         | minimum number of simulations per vertex |
| max.nsim     | 200        | maximum number of simulations per vertex | 
| max.nbox     | 5          | maximum number of boxes | 
| max.ntries   | 2          | maximum number of attempts to achieve valid simulation |
| var.nsim     | 2000       | number of simulations for variance-covariance matrix |

# Fractional designs

By default, **ipsecr** fits a full factorial design in the parameter space. For NP parameters, simulations are performed at $2^{NP}$ points, the corners of a hyperrectangle (box), plus possible centre points. The total number of simulations grows rapidly for large NP. Fractional factorial designs may omit some parameter combinations while retaining balance and other desirable characteristics.

The package **FrF2** may be used for fractional factorial designs (Groemping, 2014). 
Fractional designs are selected by setting `details = list(factorial = 'fractional')` in `ipsecr.fit`. 
```{r fractional0, eval = runall}
ip.Fr <- ipsecr.fit(captdata, detectfn = 'HHN', details = list(factorial = 'fractional'))
```

```{r retrieveipFr, eval = !runall, echo = FALSE}
# previously saved model ... see chunk 'saveall' at end
suppressMessages(load(system.file("example", "ip.Fr.RData", package = "ipsecr")))
```

```{r fractional1}
collate(ip.single, ip.Fr)[1,,,]
ip.single$proctime
ip.Fr$proctime
```

In this example the fractional design was actually slower than the full design because (i) there is little difference in the number of design points when NP = 3 (7 vs 11 with 3 centre points) and (ii) the fractional fit went to a third box. Conditions when fractional designs are faster have not been determined - they are probably useful only when parameters are numerous.

The default fractional design is a 1/2 factorial, illustrated by this code:
```{r fractional2, eval = FALSE, message = FALSE, warning = FALSE}
if (require('FrF2')) {
  NP <- 3
  boxsize <- rep(0.2,3)
  design <- FrF2(2^(NP-1),NP, factor.names = c('D','lambda0','sigma'), ncenter = 2)
  # recast factors as numeric
  design <- sapply(design, function(x) as.numeric(as.character(x)))
  design <- sweep(design, MAR=2, STATS = boxsize, FUN='*')
  # apply to beta
  beta <- log(c(5,0.2,25))
  designbeta <- sweep(design, MAR=2, STATS=beta, FUN='+')
  round(designbeta,3)
}
```
```
         D lambda0 sigma
[1,] 1.609  -1.609 3.219
[2,] 1.809  -1.409 3.419
[3,] 1.809  -1.809 3.019
[4,] 1.409  -1.809 3.419
[5,] 1.409  -1.409 3.019
[6,] 1.609  -1.609 3.219
```
The first and last rows are centre points.

For other designs you may specify the desired arguments of FrF2 as a list e.g., `details = list(factorial = 'fractional', FrF2args = list(nruns = 4, nfactors = 3, ncenter = 3))`. 

# Models with extra parameters

Extensions of **ipsecr** may involve the estimation of additional 'real' parameters (i.e. parameters other than D, g0, lambda0, sigma or NT). Extra parameters should be specified in the details argument 'extraparam', a named list with the numeric starting value of each parameter. Extra parameters are assumed to be constant: their corresponding models are set automatically to ~1. Extra parameters are passed internally to user-defined simulation functions via the 'details' argument.

Our example fits a clumped distribution of activity centres instead of the usual Poisson distribution. This uses a form of Neyman-Scott clustering (a Thomas distribution). The Thomas distribution draws cluster 'parent' points from a uniform (Poisson) distribution and places a Poisson random number of centres in a bivariate normal pattern around each parent. Parameters to be estimated are the overall intensity (density D), the expected number of centres per parent (mu), and the spatial spread of each cluster (named hsigma, following the cluster option in `secr::sim.popn`). Experimentation suggests that SECR data are usually inadequate to estimate both mu and hsigma, but there are biologically interesting scenarios for which hsigma may be considered known: specifically, clumped groups of animals sharing an activity centre may be modelled with hsigma = $\epsilon$ where $\epsilon$ is a small positive distance (e.g. 1 metre).

We proceed to estimate mu and fix hsigma. This requires a custom function for simulation and a custom proxy function. Simulation is straightforward - just a wrapper around the function from secr. For a cluster proxy we fit a Thomas distribution in **spatstat** (Baddeley and Turner 2005). This proxy is one of several possibilities, none obviously better than the rest. This requires that **spatstat** has been installed. 

First simulate some test data (requires secr >= 4.5.9):

```{r extraparamdata, eval = secr459}
grid <- make.grid(nx = 10, ny = 10, spacing = 20, detector = 'proximity')
msk <- make.mask(grid, buffer = 100)
set.seed(123)
pop <- sim.popn(D = 20, core = grid, buffer = 100, model2D = 'cluster', 
    details = list(mu = 5, hsigma = 1))
ch <- sim.capthist(grid, pop, detectfn = 14, detectpar = 
        list(lambda0 = 0.2, sigma = 20), noccasions = 5)
plot(ch, border = 20)
```

Next, call `ipsecr.fit` with these customizations:

* user proxyfn    : clusterproxyT
* user popmethod  : simclusteredpop
* user parameters : mu, hsigma
* fixed parameter : hsigma = 1


```{r extraparamfn}
# user function to simulate Thomas (Neyman-Scott) distribution of activity centres
# expect parameters mu and hsigma in list 'details$extraparam'
simclusteredpop <- function (mask, D, N, details) {
    secr::sim.popn(
        D = D[1], 
        core = mask, 
        buffer = 0, 
        Ndist = 'poisson',    # necessary for N-S cluster process
        model2D = 'cluster', 
        details = details$extraparam)
}
```

```{r extraparamdemo, eval = requireNamespace("spatstat") && runall}
# extend the built-in proxy with clumping argument mu
# spatstat fits Thomas process parameters kappa and scale = hsigma^2
# mu is a model parameter derived from mu = D / kappa
clusterproxyT <- function (capthist, ...) {
    pr <- ipsecr::proxy.ms(capthist)
    pp <- spatstat.geom::as.ppp(secr::centroids(capthist), 
        W = as.numeric(apply(secr::traps(capthist),2,range)))
    tfit <- spatstat.core::thomas.estK(pp)
    c(pr, logmu = log(tfit$modelpar['mu']))
}
clusterfitT <- ipsecr.fit(ch, proxyfn = clusterproxyT, mask = msk, 
    detectfn = 'HHN', details = list(popmethod = simclusteredpop, 
    extraparam = list(mu = 5, hsigma = NA)), fixed = list(hsigma = 1))
```

```{r clusterresults}
predict(clusterfitT)
```

The results are not very impressive (wide confidence intervals on both $\hat D$ and $\hat \mu$), but at least mu can be estimated. Let's compare with the MLE assuming a Poisson distribution of activity centres:

```{r clusterfitML, eval = runall}
clusterfitML <- secr.fit(ch, mask = msk, detectfn = 'HHN', trace = FALSE)
```
```{r clustercompareML}
predict(clusterfitML)
```

If the concern is to correct for the effect of clumping on the confidence interval for overall density then we would be better to apply a simple adjustment for overdispersion. Fletcher's c-hat (computed from the number of animals per detector) is 2.98, which suggests a more modest inflation of the variance estimate (below). Time-consuming simulations would be needed to determine which is the better approach, but I'm guessing it is Fletcher's c-hat.

```{r adjustvard}
secr::adjustVarD(clusterfitML)
```
 

# Relationship to package **secr** {#methods}

Some functionality of **ipsecr** is shared with **secr**.

Methods for 'ipsecr' of generic functions defined in **secr**

| Function | Description |
|----------|-----------------------------------------|
|makeNewData| generate dataframe suitable for `predict.ipsecr` |

Methods for 'ipsecr' of generic functions from base R and stats

| Function | Description |
|----------|------------------------------------------|
| coef     | coefficients (beta parameters) of fitted model |
| plot     | plot detection function from fitted model |
| print    | display 'ipsecr' object |
| predict  | predict real parameters |
| summary  | summarise fitted model |
| vcov     | variance-covariance matrix of coefficients (beta parameters) |

Functions from **secr** that work on fitted 'ipsecr' objects as-is

| Function | Description |
|----------|------------------------------------------------|
| ellipse.secr| plot confidence ellipse for 2 parameters |
| predictDsurface| predict density for each cell of mask |
| makeStart| generate starting values from various inputs |
| collate | tabulate results from multiple models |

# Troubleshooting and limitations

**ipsecr 1.4** is not intended for models with many sessions or many covariates. 

This version does not allow for variation in detection parameters 
(g0, lambda0, sigma) among occasions (e.g., g0~t, g0~b, g0~bk).

Only 2-parameter detection functions are allowed in `ipsecr.fit` (HN, EX, UN, HHN, HEX) (see ?detectfn). 3-parameter functions are simulated by `simCH`, but proxies for the shape parameter have not been explored (maybe some sample measure of bivariate skewness or tail weight).

## Sparse data

Simulation becomes unreliable with very sparse populations, or sparse sampling, 
because some simulated datasets will have no recaptures or even no captures. 
The code allows a failed simulation to be repeated (set the `max.ntries' 
details argument > 1), but results probably should not be relied upon when 
there are warning messages regarding failed simulations. 

## "simulations for box 1 did not reach target for proxy SE 0.002 "

This message may not be fatal. The target precision is arbitrary. 
Review the 'Variance bootstrap' table of verbose output.

## "solution not found after 5 attempts"

It seems ipsecr.fit is not converging on the right part of the parameter space. 
Try specifying a wider boxsize1 for the first box, or set starting values. 

```{r saveall, echo = FALSE, eval = runall}
save(ip.single, ip.single.1, ip.single.nontarget, ipx, clusterfitT, clusterfitML,
      file = '../inst/example/fittedmodels.RData')
save(ip.Fr, file = '../inst/example/ip.Fr.RData')
tools::resaveRdaFiles(paste0('../inst/example'),'xz')
```

# References

Baddeley, A. and Turner, R. (2005) spatstat: An R package for analyzing spatial point
  patterns. *Journal of Statistical Software* **12**, 1--42. DOI: 10.18637/jss.v012.i06

Borchers, D. L. and Efford, M. G. (2008) Spatially explicit maximum likelihood methods for capture--recapture studies. *Biometrics* **64**, 377--385.

Carothers, A. D. (1979) The effects of unequal catchability on Jolly--Seber estimates. *Biometrics* **29**, 79--100.

Distiller, G. and Borchers, D. L. (2015) A spatially explicit capture--recapture estimator for single-catch traps. *Ecology and Evolution* **5**, 5075--5087.

Efford, M. G. (2004) Density estimation in live-trapping studies. *Oikos* **106**, 598--610.

Efford, M. G. (2022). secr: Spatially explicit capture--recapture models. R package version
  4.5.6. https://CRAN.R-project.org/package=secr/
  
Efford, M. G. (2023) ipsecr: An R package for awkward spatial capture--recapture data. 
  *Methods in Ecology and Evolution* In review.

Efford, M. G., Dawson, D. K. and Robbins C. S. (2004) DENSITY: software
for analysing capture-recapture data from passive detector arrays.
*Animal Biodiversity and Conservation* **27**, 217--228.

Groemping, U. (2014). R Package FrF2 for Creating and Analyzing Fractional Factorial 2-Level Designs. *Journal of Statistical Software*, **56**, 1--56. https://www.jstatsoft.org/article/view/v056i01.

Pledger, S. and Efford, M. G. (1998)  Correction of bias due to heterogeneous capture probability in capture-recapture studies of open populations. *Biometrics* **54**, 888--898.

[secr-manual.pdf]: https://www.otago.ac.nz/density/pdfs/secr-manual.pdf
[secr-overview.pdf]: https://www.otago.ac.nz/density/pdfs/secr-overview.pdf
[secr-datainput.pdf]: https://www.otago.ac.nz/density/pdfs/secr-datainput.pdf
[secr-densitysurfaces.pdf]: https://www.otago.ac.nz/density/pdfs/secr-densitysurfaces.pdf
[secr-finitemixtures.pdf]: https://www.otago.ac.nz/density/pdfs/secr-finitemixtures.pdf
[secr-habitatmasks.pdf]: https://www.otago.ac.nz/density/pdfs/secr-habitatmasks.pdf
[secr-markresight.pdf]: https://www.otago.ac.nz/density/pdfs/secr-markresight.pdf
[secr-models.pdf]: https://www.otago.ac.nz/density/pdfs/secr-models.pdf
[secr-multisession.pdf]: https://www.otago.ac.nz/density/pdfs/secr-multisession.pdf
[secr-noneuclidean.pdf]: https://www.otago.ac.nz/density/pdfs/secr-noneuclidean.pdf
[secr-parameterisations.pdf]: https://www.otago.ac.nz/density/pdfs/secr-parameterisations.pdf
[secr-polygondetectors.pdf]: https://www.otago.ac.nz/density/pdfs/secr-polygondetectors.pdf
[secr-sound.pdf]: https://www.otago.ac.nz/density/pdfs/secr-sound.pdf
[secr-spatialdata.pdf]: https://www.otago.ac.nz/density/pdfs/secr-spatialdata.pdf
[secr-telemetry.pdf]: https://www.otago.ac.nz/density/pdfs/secr-telemetry.pdf
[secr-tutorial.pdf]: https://www.otago.ac.nz/density/pdfs/secr-tutorial.pdf
[secr-troubleshooting.pdf]: https://www.otago.ac.nz/density/pdfs/secr-troubleshooting.pdf
[secr-varyingeffort.pdf]: https://www.otago.ac.nz/density/pdfs/secr-varyingeffort.pdf

[secrdesign-vignette.pdf]: https://www.otago.ac.nz/density/pdfs/secrdesign-vignette.pdf
[secrlinear-vignette.pdf]: https://CRAN.R-project.org/package=secrlinear/vignettes/secrlinear-vignette.pdf

[secr-version4.pdf]: https://www.otago.ac.nz/density/pdfs/secr-version4.pdf

[phidot]: http://www.phidot.org/forum/
[secrgroup]: <https://groups.google.com/forum/#!forum/secrgroup>
[CRAN]: https://cran.r-project.org/package=secr
