This is a very good point. A low Rhat alone only tells you so much!
A few months ago I adapted some code (below) to run an "auto" and parallel version of NIMBLE that checks both for Rhat and ESS, for a case where I needed 5,000 independent samples of the posterior.
...
clusterExport(cl, c("nimblecode", "inits", "nimbledata", "nimbleconstants",
"params", "nt", "nb", "
ni.it", "data.array"))
for (j in seq_along(cl)) {
set.seed(j)
init <- inits()
clusterExport(cl[j], "init")
}
#run short chains in parallel on clusters
out1 <- clusterEvalQ(cl, {
library(nimble)
library(coda)
model <- nimbleModel(code = nimblecode, name = "model",
constants = nimbleconstants, data = nimbledata,
inits = init)
Cmodel <- compileNimble(model)
modelConf <- configureMCMC(model)
modelConf$resetMonitors()
modelConf$addMonitors(params)
modelMCMC <- buildMCMC(modelConf)
CmodelMCMC <- compileNimble(modelMCMC, project = model)
CmodelMCMC$run(nb, reset = TRUE, thin=nt)
return(as.mcmc(as.matrix(CmodelMCMC$mvSamples)))
})
out.mcmc <- mcmc.list(out1)
out.mcmc <- window(out.mcmc, start=2) #remove first row of NA's
out.summary <- MCMCsummary(out.mcmc)
# extend chains if not converged
start.time = Sys.time() # Set timers
place <- nb
while ((max(out.summary$Rhat, na.rm = T)>1.1 ||
min(out.summary$n.eff[out.summary$n.eff>0], na.rm = T)<5000) && place<niter.max) {
cat(place, round(max(out.summary$Rhat, na.rm = T), 2),
min(out.summary$n.eff[out.summary$n.eff>0], na.rm = T), "\n")
out2 <- clusterEvalQ(cl, {
CmodelMCMC$run(
ni.it, reset = FALSE, thin=nt)
return(as.mcmc(as.matrix(CmodelMCMC$mvSamples)))
})
out.mcmc.update1 <- mcmc.list(out2)
#Remove burn-in
out.mcmc.update1 <- window(out.mcmc.update1, start=place + 1)
# Save summary
options(max.print = 5000)
out.summary <- MCMCsummary(out.mcmc.update1)
sink(file=paste0(name2, ".summary.txt"))
print(out.summary)
sink()
place <- place +
ni.it}