I am currently trying to use RTMB to fit SCR (spatial capture-recapture) models. I am using the following objective function:
objective.fn = function(params) {
# --------------------------------------
# Pulling in 'data.vec'
getDat = function(null) {
print("Get data")
env_get(data.env, "data")
}
empty = rep(params$beta0, 0)
data.vec = DataEval(getDat, empty)
# --------------------------------------
# Unpacking parameters
beta0 = params[["beta0"]]
logit.g0 = params[["logit.g0"]]
log.sigma = params[["log.sigma"]]
g0 = exp(logit.g0)/(1 + exp(logit.g0))
sigma = exp(log.sigma)
# Unpacking data
nocc = data[["n.occasions"]]
mask.dists = data[["mask.dists"]]
n.traps = ncol(mask.dists)
n.mask = nrow(mask.dists)
mask = data[["mask"]]
a = attr(mask, "area")
# Unpacking 'data.vec'
animal.indicator = data.vec[1:M]
capt.hist = matrix(data.vec[-(1:M)], ncol=n.traps)
n = sum(animal.indicator)
# --------------------------------------
## Negative log-likelihood calculations
# Density at each mask point (homogeneous density)
D = rep(exp(beta0), n.mask)
# Detection probability calculations
mask.probs = g0 * exp( -mask.dists^2 / (2 * sigma^2) )
p.avoid = advector(rep(0, n.mask))
p.avoid = (apply(1 - mask.probs, 1, prod)) ^ nocc
p.det = 1 - p.avoid
# E[n]
esa.mult.D = sum(a * D * p.det)
# Contribution of each capture history to the log-likelihood
mask.integrand = exp((log(mask.probs) %*% t(capt.hist)) + (log(1-mask.probs) %*% t(nocc-capt.hist)) + log(D) - log(esa.mult.D))
log.lik.contr = log(colSums(mask.integrand))
# Sending contributions for unobserved animals to 0. Then, summing across all contributions
log.f.capt = sum(log.lik.contr * animal.indicator)
# Log-likelihood contribution for n
log.f.n = dpois(n, esa.mult.D, log=TRUE)
# Overall log-likelihood
ll = log.f.n + log.f.capt
# Calculating the negative log-likelihood
nllike = ll * (-1)
# --------------------------------------
ADREPORT(g0)
ADREPORT(sigma)
nllike
}
I have tried to write this objective function so that I can reuse the output from MakeADFun() to fit my model to multiple data sets. I understand that when updating data, I must be working with a vector of fixed length. However, when fitting these models, the data I want to update (the capture history matrix) often changes dimension. For each data set, the number of observed animals determines the number of rows in the matrix.
To get around this, I select a value of M large enough so that the probability of observing M animals is essentially 0. I fit my model to a capture history matrix with M rows, where the last M-n rows represent artificial, unobserved animals that I manually add to the data.
Specifically, I assume the first 1:M elements of the vector labelled 'data.vec' specify an indicator vector, and the remaining elements specify the corresponding capture history matrix. This capture history matrix will have M rows, where the last M-n rows will be all-0 capture histories. Rows representing observed animals will correspond to a value of 1 in the indicator vector, and vice versa. I use the indicator vector in my calculations so that the unobserved animals do not contribute anything to the final value of the log-likelihood.
I have two main questions:
1) Are there ways I can make my objective function more efficient?
2) I would like to fit my SCR model to many simulated datasets. The approach described in (a) is my best attempt at providing the data as a vector of fixed length, so I do not have to re-run MakeADFun() to fit my model to every data set. Does this seem like a good approach, or are there any other recommended solutions to this?
Let me know if I can clarify anything. Thank you in advance!
On 30 Jun 2025, at 07.39, 'Rishika Chopara' via TMB Users <tmb-...@googlegroups.com> wrote:I am currently trying to use RTMB to fit SCR (spatial capture-recapture) models. I am using the following objective function:
objective.fn = function(params) {
# --------------------------------------
# Pulling in 'data.vec'
getDat = function(null) {
print("Get data")
env_get(data.env, "data")
}
empty = rep(params$beta0, 0)
data.vec = DataEval(getDat, empty)
# --------------------------------------
# Unpacking parameters
beta0 = params[["beta0"]]
logit.g0 = params[["logit.g0"]]
log.sigma = params[["log.sigma"]]
g0 = exp(logit.g0)/(1 + exp(logit.g0))
sigma = exp(log.sigma)
# Unpacking data
nocc = data[["n.occasions"]]
mask.dists = data[["mask.dists"]]
n.traps = ncol(mask.dists)
n.mask = nrow(mask.dists)
mask = data[["mask"]]
a = attr(mask, "area")
Let me know if I can clarify anything. Thank you in advance!
--
To post to this group, send email to us...@tmb-project.org. Before posting, please check the wiki and issuetracker at https://github.com/kaskr/adcomp/. Please try to create a simple repeatable example to go with your question (e.g issues 154, 134, 51). Use the issuetracker to report bugs.
---
You received this message because you are subscribed to the Google Groups "TMB Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to tmb-users+...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/tmb-users/e26e5d17-32a2-48f7-a5fe-ffc2cd131d7dn%40googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/tmb-users/ec60798d-e2e4-4f64-b020-871c0448d1b0n%40googlegroups.com.