Author: Frédéric Gosselin
Date: 2026-03-07

# runMCMCbtadjust Presentation

#### Frédéric Gosselin

#### 2026-03-07

# Introduction

This file is meant to present the function `runMCMC_btadjust()` in the `runMCMCbtadjust` package. The main aim of this function is to run a Markov Chain Monte Carlo (MCMC) for a specified Bayesian model while adapting automatically the burn-in and thinning parameters to meet pre-specified targets in terms of MCMC convergence and number of effective values of MCMC outputs - where the term “number of effective values” for the MCMC outputs refers to sample size adjusted for autocorrelation. This is done in only one call to the function that repeatedly calls the MCMC until criteria for convergence and number of effective values are met. This allows to obtain a MCMC output that is out of the transient phase of the MCMC (convergence) and that contains a pre-specified number of nearly independent draws from the posterior distribution (number of effective values).

This function has four main advantages:

    (i) it saves the analyst's programming time since he/she does not have to repeatedly diagnose and re-run MCMCs until desired levels of convergence and number of effective values are reached;

    (ii) it allows a minimal, normalized quality control of MCMC outputs by allowing to meet pre-specified levels in terms of convergence and number of quasi-independent values;

    (iii) it may save computer’s time when compared to cases where we have to restart the MCMC from the beginning if it has not converged or reached the specified number of effective values (as e.g. with `runMCMC` function in `NIMBLE`);

    and (iv) it can be applied with different MCMC R languages. Indeed, `runMCMC_btadjust()` uses other Bayesian packages to fit the MCMC. At present, only `JAGS`, `NIMBLE` and `greta` can be used as these are the main Bayesian fitting tools in R known by the package author and that permit to continue an already fitted MCMC - which is required for numerical efficiency. We will here show how to fit and compare a very simple model under these three languages, using the possibilities allowed by `runMCMC_btadjust()`.

`runMCMC_btadjust()` has a stronger integration with NIMBLE, for which it has the additional advantage of somewhat easing MCMC sampler control and extra calculations, i.e. calculations on the fitted model, after the end of the MCMC (see the separate two vignettes on these two topics).

We will here show how to fit and compare a very simple model under these three languages, using the possibilities allowed by `runMCMC_btadjust()`.

Our model is one of the simplest statistical model we could think of: inspired from Kéry (2010), we model data of weights of 1,000 Pilgrim falcons (Falco peregrinus) simulated from a Gaussian distribution with mean 600 grams and standard error 30 grams:

    set.seed(1)
    y1000<-rnorm(n=1000,mean=600,sd=30)

## NIMBLE

We start with fitting the example with `NIMBLE` (cf. https://r-nimble.org/).

    library(runMCMCbtadjust)
    library(nimble)

Note that the version of `NIMBLE` needs to be controlled: package `runMCMCbtadjust` will not run with version 1.4.0 of `NIMBLE` for reasons detailed in https://github.com/nimble-dev/nimble/issues/1608. It is also preferable to use a version greater than or equal to 1.1.0.`In case you have installed verwion 1.4.0, consider installing version 1.4.1 through the command:`version::install.versions(‘nimble’, ‘1.4.1’)`, which requires the prior installation of package`version` if not already installed.

As `NIMBLE` distinguishes data that have random distributions from other data, we specify two distinct lists to contain these:

    ModelData <-list(mass = y1000)
    ModelConsts <- list(nobs = length(y1000))

We then write our Bayesian code within R with the `nimbleCode` function in the `nimble` package:

     ModelCode<-nimbleCode(
      {
        # Priors
        population.mean ~ dunif(0,5000)
        population.sd ~ dunif(0,100)

        # Normal distribution parameterized by precision = 1/variance in Nimble
        population.variance <- population.sd * population.sd
        precision <- 1 / population.variance

        # Likelihood
        for(i in 1:nobs){
          mass[i] ~ dnorm(population.mean, precision)
        }
      })

The model is a simple linear - and Gaussian - model with only an intercept -, actually the same model - for the likelihood section - as the probabilistic model used to generate the data.

Our - optional - next step is to specify starting values for model’s parameters. This is done by first writing a function that is repetitively called for each chain. We - also optionally - indicate the names of parameters to be saved and diagnosed in a vector called `params`:

    ModelInits <- function()
    {list (population.mean = rnorm(1,600,90), population.sd = runif(1, 1, 30))}

    Nchains <- 3

    set.seed(1)
    Inits<-lapply(1:Nchains,function(x){ModelInits()})

    #specifying the names of parameters to analyse and save:
    params <- c("population.mean", "population.sd")

    #devising the maximum level allowed for the Geweke diagnostic of convergence (cf. following)
    npars<-length(params)
    Gew.Max<-as.double(format(quantile(sapply(1:100000,function(x,N){max(abs(rnorm(N)))},npars),0.95),digits=3,scientific=FALSE))

We are now ready to launch `runMCMC_btadjust()`: since we use `NIMBLE`, we must specify arguments `code`, `data`, `constants` (see below), which are specific to `NIMBLE`, as well as `MCMC_language="Nimble"`. The next arguments of `runMCMC_btadjust()` that we will here work with are for most of them shared among `MCMC_language`s. We first do it on one chain (argument `Nchains=1`) using in the `control` list argument `neff.method="Coda"` to use the `Coda` method to calculate the number of effective parameters and `convtype="Geweke"` to use the Geweke method to diagnose convergence, with the pre-specified maximum - over analyzed parameters - convergence of 2.23 (`conv.max=`2.23) - coming from simulated 95% quantiles from standard gaussian distributions that Geweke diagnostics should theoretically follow - and the minimum - over analyzed parameters - number of effective values of 1,000 (`neff.min=1000`). Other arguments that are the same for all MCMC languages include `params` (parameter names to diagnose and save), `inits` (initial values - which are here provided through the list of values `Inits[1]` but could also have been specified through a function giving such a result - such as here `ModInits`), `niter.min` (minimum number of iterations), `niter.max` (maximum number of iterations), `nburnin.min`, `nburnin.max` `thin.min`, `thin.max` (minimum and maximum number of iterations for respectively the burn-in and thinning parameters):

    out.mcmc.Coda.Geweke<-runMCMC_btadjust(code=ModelCode, constants = ModelConsts, data = ModelData, MCMC_language="Nimble",
        Nchains=1, params=params, inits=Inits[1],
        niter.min=1000, niter.max=300000,
        nburnin.min=100, nburnin.max=200000,
        thin.min=1, thin.max=1000,
        conv.max=Gew.Max, neff.min=1000,
        control=list(neff.method="Coda", convtype="Geweke"))
    #> [1] "control$seed is NULL. Replaced by 1"
    #> ===== Monitors =====
    #> thin = 1: population.mean, population.sd
    #> ===== Samplers =====
    #> RW sampler (2)
    #>   - population.mean
    #>   - population.sd
    #> [1] "###################################################################################"
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> [1] "###################################################################################"
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> [1] "Raw multiplier of thin:  11.836"
    #> [1] "###################################################################################"
    #> [1] "Testing multiplier of thin:  12 :"
    #> [1] "Testing multiplier of thin:  11 :"
    #> [1] "Testing multiplier of thin:  10 :"
    #> [1] "Testing multiplier of thin:  9 :"
    #> [1] "Testing multiplier of thin:  8 :"
    #> [1] "Testing multiplier of thin:  7 :"
    #> [1] "Testing multiplier of thin:  6 :"
    #> [1] "Testing multiplier of thin:  5 :"
    #> [1] "Testing multiplier of thin:  4 :"
    #> [1] "Retained multiplier of thin:  4 :"
    #> [1] "###################################################################################"
    #> [1] "Case of niter update: Convergence and trying to reach end of MCMC at the end of next cycle"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> [1] "###################################################################################"
    #> [1] "Main MCMC sampling finished."
    #> [1] "###################################################################################"
    #> [1] "Final max raw multiplier of thin:  1.945"
    #> [1] "###################################################################################"
    #> [1] "Testing final multiplier of thin:  2 :"
    #> [1] "Retained final multiplier of thin:  2"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> [1] "MCMC has reached the required level of convergence."
    #> [1] "###################################################################################"
    #> [1] "MCMC has reached the required level of effective values."
    #> [1] "###################################################################################"

The above information printed during running `runMCMC_btadjust()` is somewhat elusive. It is possible to get more information printed with components `identifier.to.print`, `print.diagnostics`, `print.thinmult` and `innerprint` of the argument `control` of `runMCMC_btadjust()` or the component `showCompilerOutput` of `control.MCMC` - this last one being active only with `MCMC_language=="Nimble"`. See the help file of `runMCMC_btadjust()` for more information. By default, only `print.thinmult` is `TRUE` and therefore activated. We hereafter just show the activation of the `print.diagnostics` component to show the reader that it can produce useful information to better realize what is being done in terms of control of convergence and number of effective values.

    out.mcmc.Coda.Geweke.with.print.diagnostics<-runMCMC_btadjust(code=ModelCode, constants = ModelConsts, data = ModelData, MCMC_language="Nimble",
        Nchains=1, params=params, inits=Inits[1],
        niter.min=1000, niter.max=300000,
        nburnin.min=100, nburnin.max=200000,
        thin.min=1, thin.max=1000,
        conv.max=Gew.Max, neff.min=1000,
        control=list(neff.method="Coda", convtype="Geweke",print.diagnostics=TRUE))
    #> [1] "control$seed is NULL. Replaced by 1"
    #> ===== Monitors =====
    #> thin = 1: population.mean, population.sd
    #> ===== Samplers =====
    #> RW sampler (2)
    #>   - population.mean
    #>   - population.sd
    #> [1] "###################################################################################"
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> [1] "###################################################################################"
    #> [1] "Current state of diagnostics:"
    #>                 Nchains thin niter.tot Nvalues nu.burn
    #> MCMC parameters       1    1      2110    2010     101
    #> [1] "###################################################################################"
    #>          max median  mean      name_max prop_ab_p975 prop_ab_p995 prop_ab_p9995
    #> Geweke 1.316  1.131 1.131 population.sd            0            0             0
    #> [1] "###################################################################################"
    #>                      min median mean        name_min prop_bel_1000 prop_bel_5000 prop_bel_10000
    #> Neff             121.825    201  201 population.mean             1             1              1
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> [1] "###################################################################################"
    #> [1] "Current state of diagnostics:"
    #>                 Nchains thin niter.tot Nvalues nu.burn
    #> MCMC parameters       1    1      4220    4120     101
    #> [1] "###################################################################################"
    #>          max median  mean      name_max prop_ab_p975 prop_ab_p995 prop_ab_p9995
    #> Geweke 1.365  1.053 1.053 population.sd            0            0             0
    #> [1] "###################################################################################"
    #>                      min  median    mean        name_min prop_bel_1000 prop_bel_5000 prop_bel_10000
    #> Neff             348.092 505.908 505.908 population.mean             1             1              1
    #> [1] "###################################################################################"
    #> [1] "Raw multiplier of thin:  11.836"
    #> [1] "###################################################################################"
    #> [1] "Testing multiplier of thin:  12 :"
    #> [1] "###################################################################################"
    #> [1] "Current state of diagnostics:"
    #>                 Nchains thin niter.tot Nvalues nu.burn
    #> MCMC parameters       1   12      4220     344     101
    #> [1] "###################################################################################"
    #>          max median  mean      name_max prop_ab_p975 prop_ab_p995 prop_ab_p9995
    #> Geweke 1.968  1.324 1.324 population.sd          0.5            0             0
    #> [1] "###################################################################################"
    #>                      min  median    mean        name_min prop_bel_1000 prop_bel_5000 prop_bel_10000
    #> Neff             232.613 255.155 255.155 population.mean             1             1              1
    #> [1] "###################################################################################"
    #> [1] "Testing multiplier of thin:  11 :"
    #> [1] "###################################################################################"
    #> [1] "Current state of diagnostics:"
    #>                 Nchains thin niter.tot Nvalues nu.burn
    #> MCMC parameters       1   11      4220     375     101
    #> [1] "###################################################################################"
    #>          max median  mean      name_max prop_ab_p975 prop_ab_p995 prop_ab_p9995
    #> Geweke 1.207  0.962 0.962 population.sd            0            0             0
    #> [1] "###################################################################################"
    #>                     min median   mean        name_min prop_bel_1000 prop_bel_5000 prop_bel_10000
    #> Neff             258.94 316.97 316.97 population.mean             1             1              1
    #> [1] "###################################################################################"
    #> [1] "Testing multiplier of thin:  10 :"
    #> [1] "###################################################################################"
    #> [1] "Current state of diagnostics:"
    #>                 Nchains thin niter.tot Nvalues nu.burn
    #> MCMC parameters       1   10      4220     412     101
    #> [1] "###################################################################################"
    #>          max median  mean      name_max prop_ab_p975 prop_ab_p995 prop_ab_p9995
    #> Geweke 3.115  2.031 2.031 population.sd          0.5          0.5             0
    #> [1] "###################################################################################"
    #>                      min  median    mean        name_min prop_bel_1000 prop_bel_5000 prop_bel_10000
    #> Neff             320.917 335.843 335.843 population.mean             1             1              1
    #> [1] "###################################################################################"
    #> [1] "Testing multiplier of thin:  9 :"
    #> [1] "###################################################################################"
    #> [1] "Current state of diagnostics:"
    #>                 Nchains thin niter.tot Nvalues nu.burn
    #> MCMC parameters       1    9      4220     458     101
    #> [1] "###################################################################################"
    #>          max median  mean      name_max prop_ab_p975 prop_ab_p995 prop_ab_p9995
    #> Geweke 0.884  0.657 0.657 population.sd            0            0             0
    #> [1] "###################################################################################"
    #>                      min  median    mean        name_min prop_bel_1000 prop_bel_5000 prop_bel_10000
    #> Neff             348.084 352.522 352.522 population.mean             1             1              1
    #> [1] "###################################################################################"
    #> [1] "Testing multiplier of thin:  8 :"
    #> [1] "###################################################################################"
    #> [1] "Current state of diagnostics:"
    #>                 Nchains thin niter.tot Nvalues nu.burn
    #> MCMC parameters       1    8      4220     515     101
    #> [1] "###################################################################################"
    #>          max median  mean      name_max prop_ab_p975 prop_ab_p995 prop_ab_p9995
    #> Geweke 1.314  0.929 0.929 population.sd            0            0             0
    #> [1] "###################################################################################"
    #>                      min  median    mean        name_min prop_bel_1000 prop_bel_5000 prop_bel_10000
    #> Neff             376.341 417.327 417.327 population.mean             1             1              1
    #> [1] "###################################################################################"
    #> [1] "Testing multiplier of thin:  7 :"
    #> [1] "###################################################################################"
    #> [1] "Current state of diagnostics:"
    #>                 Nchains thin niter.tot Nvalues nu.burn
    #> MCMC parameters       1    7      4220     589     101
    #> [1] "###################################################################################"
    #>          max median  mean      name_max prop_ab_p975 prop_ab_p995 prop_ab_p9995
    #> Geweke 1.852  1.338 1.338 population.sd            0            0             0
    #> [1] "###################################################################################"
    #>                      min  median    mean        name_min prop_bel_1000 prop_bel_5000 prop_bel_10000
    #> Neff             342.466 395.531 395.531 population.mean             1             1              1
    #> [1] "###################################################################################"
    #> [1] "Testing multiplier of thin:  6 :"
    #> [1] "###################################################################################"
    #> [1] "Current state of diagnostics:"
    #>                 Nchains thin niter.tot Nvalues nu.burn
    #> MCMC parameters       1    6      4220     687     101
    #> [1] "###################################################################################"
    #>          max median  mean      name_max prop_ab_p975 prop_ab_p995 prop_ab_p9995
    #> Geweke 1.559  1.055 1.055 population.sd            0            0             0
    #> [1] "###################################################################################"
    #>                      min  median    mean        name_min prop_bel_1000 prop_bel_5000 prop_bel_10000
    #> Neff             315.687 504.592 504.592 population.mean             1             1              1
    #> [1] "###################################################################################"
    #> [1] "Testing multiplier of thin:  5 :"
    #> [1] "###################################################################################"
    #> [1] "Current state of diagnostics:"
    #>                 Nchains thin niter.tot Nvalues nu.burn
    #> MCMC parameters       1    5      4220     824     101
    #> [1] "###################################################################################"
    #>          max median mean      name_max prop_ab_p975 prop_ab_p995 prop_ab_p9995
    #> Geweke 2.093   1.35 1.35 population.sd          0.5            0             0
    #> [1] "###################################################################################"
    #>                      min  median    mean        name_min prop_bel_1000 prop_bel_5000 prop_bel_10000
    #> Neff             389.373 474.967 474.967 population.mean             1             1              1
    #> [1] "###################################################################################"
    #> [1] "Testing multiplier of thin:  4 :"
    #> [1] "###################################################################################"
    #> [1] "Current state of diagnostics:"
    #>                 Nchains thin niter.tot Nvalues nu.burn
    #> MCMC parameters       1    4      4220    1030     101
    #> [1] "###################################################################################"
    #>          max median  mean      name_max prop_ab_p975 prop_ab_p995 prop_ab_p9995
    #> Geweke 1.584  1.128 1.128 population.sd            0            0             0
    #> [1] "###################################################################################"
    #>                      min  median    mean        name_min prop_bel_1000 prop_bel_5000 prop_bel_10000
    #> Neff             382.086 489.519 489.519 population.mean             1             1              1
    #> [1] "###################################################################################"
    #> [1] "Retained multiplier of thin:  4 :"
    #> [1] "###################################################################################"
    #> [1] "Case of niter update: Convergence and trying to reach end of MCMC at the end of next cycle"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> [1] "###################################################################################"
    #> [1] "Current state of diagnostics:"
    #>                 Nchains thin niter.tot Nvalues nu.burn
    #> MCMC parameters       1    4     14036    3484     103
    #> [1] "###################################################################################"
    #>         max median mean      name_max prop_ab_p975 prop_ab_p995 prop_ab_p9995
    #> Geweke 0.89   0.69 0.69 population.sd            0            0             0
    #> [1] "###################################################################################"
    #>                       min   median     mean        name_min prop_bel_1000 prop_bel_5000 prop_bel_10000
    #> Neff             1791.552 2131.924 2131.924 population.mean             0             1              1
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> [1] "Main MCMC sampling finished."
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> [1] "Current state of diagnostics:"
    #>                 Nchains thin niter.tot Nvalues nu.burn
    #> MCMC parameters       1    4     14036    3484     103
    #> [1] "###################################################################################"
    #>         max median mean      name_max prop_ab_p975 prop_ab_p995 prop_ab_p9995
    #> Geweke 0.89   0.69 0.69 population.sd            0            0             0
    #> [1] "###################################################################################"
    #>                       min   median     mean        name_min prop_bel_1000 prop_bel_5000 prop_bel_10000
    #> Neff             1791.552 2131.924 2131.924 population.mean             0             1              1
    #> [1] "###################################################################################"
    #> [1] "Final max raw multiplier of thin:  1.945"
    #> [1] "###################################################################################"
    #> [1] "Testing final multiplier of thin:  2 :"
    #> [1] "###################################################################################"
    #> [1] "Current state of diagnostics:"
    #>                 Nchains thin niter.tot Nvalues nu.burn
    #> MCMC parameters       1    8     14036    1742     103
    #> [1] "###################################################################################"
    #>          max median  mean      name_max prop_ab_p975 prop_ab_p995 prop_ab_p9995
    #> Geweke 0.972  0.591 0.591 population.sd            0            0             0
    #> [1] "###################################################################################"
    #>                       min   median     mean        name_min prop_bel_1000 prop_bel_5000 prop_bel_10000
    #> Neff             1447.905 1591.316 1591.316 population.mean             0             1              1
    #> [1] "###################################################################################"
    #> [1] "Retained final multiplier of thin:  2"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> [1] "Current state of diagnostics:"
    #>                 Nchains thin niter.tot Nvalues nu.burn
    #> MCMC parameters       1    8     14036    1742     107
    #> [1] "###################################################################################"
    #>          max median  mean      name_max prop_ab_p975 prop_ab_p995 prop_ab_p9995
    #> Geweke 0.972  0.591 0.591 population.sd            0            0             0
    #> [1] "###################################################################################"
    #>                       min   median     mean        name_min prop_bel_1000 prop_bel_5000 prop_bel_10000
    #> Neff             1447.905 1591.316 1591.316 population.mean             0             1              1
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> [1] "MCMC has reached the required level of convergence."
    #> [1] "###################################################################################"
    #> [1] "MCMC has reached the required level of effective values."
    #> [1] "###################################################################################"

We advise the reader to use the `print.diagnostics` functionality but do not in the following to keep the length of the document to a minimum.

Before turning to other model fits, let us depict the nature of the result of `runMCMC_btadjust()` function. The length of the output 1 is always equal to the number of Markov Chains - argument `Nchains`. Its class is mcmc.list - a type of object classical for MCMC outputs and defined in the `coda` package. Each component of this list contains the successive retained values for each saved parameter as well as attributes that give information on the MCMC they come from - see the beginning of the first component below:

    length(out.mcmc.Coda.Geweke)
    #> [1] 1

    class(out.mcmc.Coda.Geweke)
    #> [1] "mcmc.list"

    head(out.mcmc.Coda.Geweke[[1]])
    #> Markov Chain Monte Carlo (MCMC) output:
    #> Start = 103
    #> End = 151
    #> Thinning interval = 8
    #>      population.mean population.sd
    #> [1,]        587.4004      35.26104
    #> [2,]        593.8190      32.44475
    #> [3,]        597.1063      30.95184
    #> [4,]        598.4965      30.94524
    #> [5,]        600.9747      31.64918
    #> [6,]        601.3179      30.75207
    #> [7,]        599.6316      31.46291

The output - i.e. the whole list - however has extra information in its `attributes`: indeed, `attributes` has 5 components, whose name are: call.params, final.params, final.diags, sessionInfo, class: in addition to containing the class of the object - here “mcmc.list” -, these attributes include information on the R session in which the function was executed - component `sessionInfo` -, the final diagnostics of the model - component `final.diags` -, the arguments used in the call of the `runMCMC_btadjust()` function - component `call.params` - and finally the final “parameters” of the function - component `final.params`. In case `MCMC_language` is not “Greta”, the `call.params` component contains either the entire data and /or the constants or a summary of these (to keep the output to a controlled object size) - this choice is controlled by the component `save.data` of parameter `control`. The component `final.params` has a series of heterogeneous parameters including whether the model has converged, has reached its targets in terms of numbers of effective values…, as well as information in terms of duration of the different sections of the analysis - which we will use in the sequence of this document. See the help file for more information as well as the below printing. The `final.diags` component contains the information on the convergence and number of effective values of the parameters. Finally, the `sessionInfo` component has many interesting info relative to the context in which the function `runMCMC_btadjust()` was executed (including platform, version of R, versions of packages…).

    names(attributes(out.mcmc.Coda.Geweke))
    #> [1] "call.params"  "final.params" "final.diags"  "sessionInfo"  "class"

    names(attributes(out.mcmc.Coda.Geweke)$package.versions)
    #> NULL

    attributes(out.mcmc.Coda.Geweke)$final.params
    #> $converged
    #> [1] TRUE
    #>
    #> $neffs.reached
    #> [1] TRUE
    #>
    #> $final.Nchains
    #> [1] 1
    #>
    #> $removed.chains
    #> integer(0)
    #>
    #> $burnin
    #> [1] 103
    #>
    #> $thin
    #> [1] 8
    #>
    #> $niter.tot
    #> [1] 14036
    #>
    #> $Nvalues
    #>
    #> MCMC parameters 1742
    #>
    #> $neff.min
    #>
    #> Neff             1447.905
    #>
    #> $neff.median
    #>
    #> Neff             1591.316
    #>
    #> $WAIC
    #> NULL
    #>
    #> $extraResults
    #> NULL
    #>
    #> $Temps
    #> $Temps$chain1
    #> NULL
    #>
    #>
    #> $duration
    #> Time difference of 26.98277 secs
    #>
    #> $duration.MCMC.preparation
    #> Time difference of 20.30516 secs
    #>
    #> $duration.MCMC.transient
    #> Time difference of 0.008573902 secs
    #>
    #> $duration.MCMC.asymptotic
    #> Time difference of 1.159808 secs
    #>
    #> $duration.MCMC.after
    #> Time difference of 4.887581e-05 secs
    #>
    #> $duration.btadjust
    #> Time difference of 5.509178 secs
    #>
    #> $CPUduration
    #> [1] 7.73
    #>
    #> $CPUduration.MCMC.preparation
    #> [1] 6.16
    #>
    #> $CPUduration.MCMC.transient
    #> [1] 0.0080721
    #>
    #> $CPUduration.MCMC.asymptotic
    #> [1] 1.091928
    #>
    #> $CPUduration.MCMC.after
    #> [1] 0
    #>
    #> $CPUduration.btadjust
    #> [1] 0.47
    #>
    #> $childCPUduration
    #> [1] NA
    #>
    #> $childCPUduration.MCMC.preparation
    #> [1] NA
    #>
    #> $childCPUduration.MCMC.transient
    #> [1] NA
    #>
    #> $childCPUduration.MCMC.asymptotic
    #> [1] NA
    #>
    #> $childCPUduration.MCMC.after
    #> [1] NA
    #>
    #> $childCPUduration.btadjust
    #> [1] NA
    #>
    #> $time_end
    #> [1] "2026-03-07 16:56:34 CET"

    attributes(out.mcmc.Coda.Geweke)$final.diags
    #> $params
    #>                 Nchains thin niter.tot Nvalues nu.burn
    #> MCMC parameters       1    8     14036    1742     107
    #>
    #> $conv_synth
    #>          max median  mean      name_max prop_ab_p975 prop_ab_p995 prop_ab_p9995
    #> Geweke 0.972  0.591 0.591 population.sd            0            0             0
    #>
    #> $neff_synth
    #>                       min   median     mean        name_min prop_bel_1000 prop_bel_5000 prop_bel_10000
    #> Neff             1447.905 1591.316 1591.316 population.mean             0             1              1
    #>
    #> $conv
    #> population.mean   population.sd
    #>       0.2106709       0.9719390
    #>
    #> $neff
    #> population.mean   population.sd
    #>        1447.905        1734.728

    attributes(out.mcmc.Coda.Geweke)$sessionInfo
    #> R version 4.4.0 (2024-04-24 ucrt)
    #> Platform: x86_64-w64-mingw32/x64
    #> Running under: Windows 11 x64 (build 22631)
    #>
    #> Matrix products: default
    #>
    #>
    #> locale:
    #> [1] LC_COLLATE=French_France.utf8  LC_CTYPE=French_France.utf8    LC_MONETARY=French_France.utf8
    #> [4] LC_NUMERIC=C                   LC_TIME=French_France.utf8
    #>
    #> time zone: Europe/Paris
    #> tzcode source: internal
    #>
    #> attached base packages:
    #> [1] stats     graphics  grDevices utils     datasets  methods   base
    #>
    #> other attached packages:
    #> [1] runMCMCbtadjust_1.1.3 rjags_4-15            coda_0.19-4.1         nimble_1.4.1
    #> [5] testthat_3.2.1.1
    #>
    #> loaded via a namespace (and not attached):
    #>   [1] remotes_2.5.0       rlang_1.1.4         magrittr_2.0.3      hunspell_3.0.3
    #>   [5] compiler_4.4.0      roxygen2_7.3.1      png_0.1-8           callr_3.7.6
    #>   [9] vctrs_0.6.5         stringr_1.5.1       profvis_0.3.8       pkgconfig_2.0.3
    #>  [13] crayon_1.5.3        fastmap_1.2.0       ellipsis_0.3.2      utf8_1.2.4
    #>  [17] promises_1.3.0      rmarkdown_2.27      sessioninfo_1.2.2   pracma_2.4.4
    #>  [21] ps_1.7.7            purrr_1.0.2         waldo_0.5.2         xfun_0.44
    #>  [25] cachem_1.1.0        covr_3.6.4          jsonlite_1.8.8      progress_1.2.3
    #>  [29] later_1.3.2         tensorflow_2.16.0   parallel_4.4.0      prettyunits_1.2.0
    #>  [33] R6_2.5.1            bslib_0.8.0         stringi_1.8.4       reticulate_1.37.0
    #>  [37] parallelly_1.37.1   pkgload_1.3.4       brio_1.1.5          jquerylib_0.1.4
    #>  [41] numDeriv_2016.8-1.1 Rcpp_1.0.13         knitr_1.48          usethis_2.2.3
    #>  [45] base64enc_0.1-3     Matrix_1.7-0        httpuv_1.6.15       igraph_2.0.3
    #>  [49] tidyselect_1.2.1    rstudioapi_0.16.0   yaml_2.3.8          codetools_0.2-20
    #>  [53] miniUI_0.1.1.1      curl_5.2.1          processx_3.8.4      listenv_0.9.1
    #>  [57] pkgbuild_1.4.4      lattice_0.22-6      tibble_3.2.1        shiny_1.8.1.1
    #>  [61] withr_3.0.1         evaluate_0.24.0     future_1.33.2       desc_1.4.3
    #>  [65] urlchecker_1.0.1    xml2_1.3.6          pillar_1.9.0        whisker_0.4.1
    #>  [69] DT_0.33             rex_1.2.1           generics_0.1.3      rprojroot_2.0.4
    #>  [73] xopen_1.0.1         hms_1.1.3           commonmark_1.9.1    globals_0.16.3
    #>  [77] xtable_1.8-4        glue_1.7.0          lazyeval_0.2.2      tools_4.4.0
    #>  [81] fs_1.6.4            grid_4.4.0          crosstalk_1.2.1     devtools_2.4.5
    #>  [85] cli_3.6.2           rappdirs_0.3.3      tfruns_1.5.3        rcmdcheck_1.4.0
    #>  [89] fansi_1.0.6         dplyr_1.1.4         praise_1.0.0        greta_0.4.5
    #>  [93] runjags_2.2.2-4     sass_0.4.9          digest_0.6.35       checkhelper_0.1.1
    #>  [97] htmlwidgets_1.6.4   memoise_2.0.1       htmltools_0.5.8.1   lifecycle_1.0.4
    #> [101] mime_0.12           spelling_2.3.0

We then run the MCMC with `r`Nchains`MCMC chains, the - default - Gelman-Rubin diagnostic of convergence and the -default-`rstan` method for calculating the number of effective values:

    out.mcmc<-runMCMC_btadjust(code=ModelCode, constants = ModelConsts, data = ModelData, MCMC_language="Nimble",
        Nchains=Nchains, params=params, inits=Inits,
        niter.min=1000, niter.max=300000,
        nburnin.min=100, nburnin.max=200000,
        thin.min=1, thin.max=1000,
        conv.max=1.05, neff.min=1000)
    #> [1] "control$seed is NULL. Replaced by 1"
    #> ===== Monitors =====
    #> thin = 1: population.mean, population.sd
    #> ===== Samplers =====
    #> RW sampler (2)
    #>   - population.mean
    #>   - population.sd
    #> ===== Monitors =====
    #> thin = 1: population.mean, population.sd
    #> ===== Samplers =====
    #> RW sampler (2)
    #>   - population.mean
    #>   - population.sd
    #> ===== Monitors =====
    #> thin = 1: population.mean, population.sd
    #> ===== Samplers =====
    #> RW sampler (2)
    #>   - population.mean
    #>   - population.sd
    #> [1] "###################################################################################"
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> [1] "###################################################################################"
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> [1] "Raw multiplier of thin:  4.796"
    #> [1] "###################################################################################"
    #> [1] "Testing multiplier of thin:  5 :"
    #> [1] "Testing multiplier of thin:  4 :"
    #> [1] "Retained multiplier of thin:  4 :"
    #> [1] "###################################################################################"
    #> [1] "Case of niter update: Convergence and trying to reach end of MCMC at the end of next cycle"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> [1] "###################################################################################"
    #> [1] "Main MCMC sampling finished."
    #> [1] "###################################################################################"
    #> [1] "Final max raw multiplier of thin:  1.489"
    #> [1] "###################################################################################"
    #> [1] "Retained final multiplier of thin:  1"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> [1] "MCMC has reached the required level of convergence."
    #> [1] "###################################################################################"
    #> [1] "MCMC has reached the required level of effective values."
    #> [1] "###################################################################################"

We compare the characteristics of the two MCMCs, both in terms of burn-in, thinning parameter, number of iterations and in terms of time (both total time and CPU time).

Comparison of the efficiency of first two NIMBLE models:
| Nimble.Coda.Geweke | Nimble.default
--- | --- | ---
converged | 1.00000000 | 1.00000000
neffs.reached | 1.00000000 | 1.00000000
final.Nchains | 1.00000000 | 3.00000000
burnin | 103.00000000 | 575.00000000
thin | 8.00000000 | 4.00000000
niter.tot | 14036.00000000 | 3252.00000000
Nvalues | 1742.00000000 | 2010.00000000
neff.min | 1447.90500000 | 1350.00000000
neff.median | 1591.31600000 | 1446.50000000
duration | 26.98276806 | 56.64315486
duration.MCMC.preparation | 20.30515981 | 47.74139595
duration.MCMC.transient | 0.00857390 | 0.15054391
duration.MCMC.asymptotic | 1.15980755 | 0.70088007
duration.MCMC.after | 0.00004888 | 0.00005102
duration.btadjust | 5.50917792 | 8.05028391
CPUduration | 7.73000000 | 12.13000000
CPUduration.MCMC.preparation | 6.16000000 | 10.57000000
CPUduration.MCMC.transient | 0.00807210 | 0.13968327
CPUduration.MCMC.asymptotic | 1.09192790 | 0.65031673
CPUduration.MCMC.after | 0.00000000 | 0.00000000
CPUduration.btadjust | 0.47000000 | 0.77000000
childCPUduration | NA | NA
childCPUduration.MCMC.preparation | NA | NA
childCPUduration.MCMC.transient | NA | NA
childCPUduration.MCMC.asymptotic | NA | NA
childCPUduration.MCMC.after | NA | NA
childCPUduration.btadjust | NA | NA

We acknowledge that the Coda.Geweke algorithm takes much less time (rows named “duration” and “CPUduration” in the previous table) than the classical setting to prepare data (rows named “duration.MCMC.preparation” and “CPUduration.MCMC.preparation”) - as NIMBLE takes quite a lot of time to prepare each MCMC chain - and we have 3 chains to prepare in the default setting compared to 1 with Geweke.

We also wished to run a third MCMC on one chain with Geweke diagnostic but the default, rstan method for number of effective values, assumed to be more conservative - i.e. to estimate lower numbers of effective values.

    out.mcmc.Geweke<-runMCMC_btadjust(code=ModelCode, constants = ModelConsts, data = ModelData, MCMC_language="Nimble",
        Nchains=1, params=params, inits=Inits[1],
        niter.min=1000, niter.max=300000,
        nburnin.min=100, nburnin.max=200000,
        thin.min=1, thin.max=1000,
        conv.max=Gew.Max, neff.min=1000,
        control=list(convtype="Geweke"))
    #> [1] "control$seed is NULL. Replaced by 1"
    #> ===== Monitors =====
    #> thin = 1: population.mean, population.sd
    #> ===== Samplers =====
    #> RW sampler (2)
    #>   - population.mean
    #>   - population.sd
    #> [1] "###################################################################################"
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> [1] "###################################################################################"
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> [1] "Raw multiplier of thin:  11.075"
    #> [1] "###################################################################################"
    #> [1] "Testing multiplier of thin:  11 :"
    #> [1] "Testing multiplier of thin:  10 :"
    #> [1] "Testing multiplier of thin:  9 :"
    #> [1] "Testing multiplier of thin:  8 :"
    #> [1] "Testing multiplier of thin:  7 :"
    #> [1] "Testing multiplier of thin:  6 :"
    #> [1] "Testing multiplier of thin:  5 :"
    #> [1] "Testing multiplier of thin:  4 :"
    #> [1] "Retained multiplier of thin:  4 :"
    #> [1] "###################################################################################"
    #> [1] "Case of niter update: Convergence and trying to reach end of MCMC at the end of next cycle"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> [1] "###################################################################################"
    #> [1] "Main MCMC sampling finished."
    #> [1] "###################################################################################"
    #> [1] "Final max raw multiplier of thin:  1.979"
    #> [1] "###################################################################################"
    #> [1] "Testing final multiplier of thin:  2 :"
    #> [1] "Retained final multiplier of thin:  2"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> [1] "MCMC has reached the required level of convergence."
    #> [1] "###################################################################################"
    #> [1] "MCMC has reached the required level of effective values."
    #> [1] "###################################################################################"

We compare the characteristics of the three `NIMBLE` MCMCs,

Comparison of the efficiency of the three NIMBLE models:
| Nimble.Coda.Geweke | Nimble.Geweke | Nimble.default
--- | --- | --- | ---
converged | 1.00000000 | 1.00000000 | 1.00000000
neffs.reached | 1.00000000 | 1.00000000 | 1.00000000
final.Nchains | 1.00000000 | 1.00000000 | 3.00000000
burnin | 103.00000000 | 103.00000000 | 575.00000000
thin | 8.00000000 | 8.00000000 | 4.00000000
niter.tot | 14036.00000000 | 13174.00000000 | 3252.00000000
Nvalues | 1742.00000000 | 1634.00000000 | 2010.00000000
neff.min | 1447.90500000 | 1327.00000000 | 1350.00000000
neff.median | 1591.31600000 | 1425.50000000 | 1446.50000000
duration | 26.98276806 | 26.11135793 | 56.64315486
duration.MCMC.preparation | 20.30515981 | 15.82847118 | 47.74139595
duration.MCMC.transient | 0.00857390 | 0.00904825 | 0.15054391
duration.MCMC.asymptotic | 1.15980755 | 1.14807365 | 0.70088007
duration.MCMC.after | 0.00004888 | 0.00004911 | 0.00005102
duration.btadjust | 5.50917792 | 9.12571573 | 8.05028391
CPUduration | 7.73000000 | 5.12000000 | 12.13000000
CPUduration.MCMC.preparation | 6.16000000 | 3.60000000 | 10.57000000
CPUduration.MCMC.transient | 0.00807210 | 0.00844519 | 0.13968327
CPUduration.MCMC.asymptotic | 1.09192790 | 1.07155481 | 0.65031673
CPUduration.MCMC.after | 0.00000000 | 0.00000000 | 0.00000000
CPUduration.btadjust | 0.47000000 | 0.44000000 | 0.77000000
childCPUduration | NA | NA | NA
childCPUduration.MCMC.preparation | NA | NA | NA
childCPUduration.MCMC.transient | NA | NA | NA
childCPUduration.MCMC.asymptotic | NA | NA | NA
childCPUduration.MCMC.after | NA | NA | NA
childCPUduration.btadjust | NA | NA | NA

Results did not completely corroborate our above expectations: the thinning parameter was not increased when changing from Coda.Geweke to Geweke as expected above (row “thin”).

We now turn to the comparison of the statistical parameter outputs. We use two sample Kolmogorov-Smirnov tests to compare each parameter by pairs of MCMC methods:

P-values of paired Kolmogorov-Smirnov tests of output parameters (columns) between the first three NIMBLE models (rows):
| mean | sd
--- | --- | ---
default vs. Geweke | 0.7580 | 0.0556
Coda.Geweke vs. Geweke | 1.0000 | 1.0000
Default vs. Coda.Geweke | 0.7884 | 0.1076

The p-values associated to the KS tests are not very small. This indicates that the MCMC outputs can be considered as being drawn from the same distributions.

These parameters are summarized in the next tables.

Summary of the statistical parameters of the Nimble Coda.Geweke model:
| Mean | SD | Naive SE | Time-series SE
--- | --- | --- | --- | ---
population.mean | 599.649 | 1.058 | 0.025 | 0.028
population.sd | 31.102 | 0.696 | 0.017 | 0.017

Summary of the statistical parameters of the Nimble Geweke model:
| Mean | SD | Naive SE | Time-series SE
--- | --- | --- | --- | ---
population.mean | 599.650 | 1.060 | 0.026 | 0.029
population.sd | 31.109 | 0.697 | 0.017 | 0.017

Summary of the statistical parameters of the Nimble default model:
| Mean | SD | Naive SE | Time-series SE
--- | --- | --- | --- | ---
population.mean | 599.664 | 1.003 | 0.022 | 0.027
population.sd | 31.072 | 0.706 | 0.016 | 0.017

We notice that parameter values are very close, that naive standard errors (SEs) are very close to Time-series SEs - which is linked to the automatic tuning of the thinning parameter which produces output samples which are nearly independent - and that differences between mean estimators are within several units of Time series-SEs - which we interpret is mostly due to the control of convergence.

# JAGS

We now turn to analyzing the same data with the same statistical model using `JAGS` with `runMCMC_btadjust()`. We rely on the data simulated above. In `JAGS`, we now put all the data in the same list:

    ModelData.Jags <-list(mass = y1000, nobs = length(y1000))

We then propose the use of `JAGS` with a specification of the model from within `R` - which we find more convenient. We therefore write the `JAGS` model within `R` as a character chain:

    modeltotransfer<-"model {

            # Priors
                population.mean ~ dunif(0,5000)
                population.sd ~ dunif(0,100)

                # Normal distribution parameterized by precision = 1/variance in Jags
            population.variance <- population.sd * population.sd
          precision <- 1 / population.variance

                # Likelihood
                for(i in 1:nobs){
                  mass[i] ~ dnorm(population.mean, precision)
                }
            }"

The other objects useful or required for running `runMCMC_btadjust` with `JAGS` are similar to those required with `NIMBLE` (`Inits`, `Nchains`, `params`) and are not repeated here.

We then launch `runMCMC_btadjust()` with `MCMC_language="Jags"`, specifying arguments `code` and `data` which are required in this case. Note that if we had written the `JAGS` code in a text file named `"ModelJags.txt"`, we would just have replaced in the command above `code=modeltotransfer` by `code="ModelJags.txt"`.

    set.seed(1)
    out.mcmc.Jags<-runMCMC_btadjust(code=modeltotransfer,  data = ModelData.Jags, MCMC_language="Jags",
        Nchains=Nchains, params=params, inits=Inits,
        niter.min=1000,niter.max=300000,
        nburnin.min=100,nburnin.max=200000,
        thin.min=1,thin.max=1000,
            conv.max=1.05,neff.min=1000)
    #> [1] "control$seed is NULL. Replaced by 1"
    #> Compiling model graph
    #>    Resolving undeclared variables
    #>    Allocating nodes
    #> Graph information:
    #>    Observed stochastic nodes: 1000
    #>    Unobserved stochastic nodes: 2
    #>    Total graph size: 1009
    #>
    #> Initializing model
    #>
    #>
     #> [1] "###################################################################################"
    #> [1] "Main MCMC sampling finished."
    #> [1] "###################################################################################"
    #> [1] "Final max raw multiplier of thin:  1.506"
    #> [1] "###################################################################################"
    #> [1] "Testing final multiplier of thin:  2 :"
    #> [1] "Retained final multiplier of thin:  2"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> [1] "MCMC has reached the required level of convergence."
    #> [1] "###################################################################################"
    #> [1] "MCMC has reached the required level of effective values."
    #> [1] "###################################################################################"

Here is a summary of the parameter estimates:

Summary of the statistical parameters of the Jags model:
| Mean | SD | Naive SE | Time-series SE
--- | --- | --- | --- | ---
population.mean | 599.666 | 0.988 | 0.019 | 0.019
population.sd | 31.079 | 0.692 | 0.013 | 0.013

Results seem in line with those of `NIMBLE`. We check this using a paired Kolmogorov-Smirnov tests with `NIMBLE` models:

P-values of paired Kolmogorov-Smirnov tests of output parameters (columns) of the Jags model with the three NIMBLE models (rows):
| mean | sd
--- | --- | ---
Nimble.Geweke vs. Jags | 0.9854 | 0.6104
Nimble.Coda.Geweke vs. Jags | 0.9686 | 0.7631
Nimble.Default vs. Jags | 0.7233 | 0.1412

Our results do confirm that the `JAGS` result cannot be considered as stemming from a different probability distribution than `NIMBLE` results.

We finally compare the efficiency of the `JAGS` and default `NIMBLE` MCMCs:

Comparison of the efficiency of the default NIMBLE model and the Jags model:
| Nimble.default | Jags
--- | --- | ---
converged | 1.00000000 | 1.00000000
neffs.reached | 1.00000000 | 1.00000000
final.Nchains | 3.00000000 | 3.00000000
burnin | 575.00000000 | 100.00000000
thin | 4.00000000 | 2.00000000
niter.tot | 3252.00000000 | 2000.00000000
Nvalues | 2010.00000000 | 2850.00000000
neff.min | 1350.00000000 | 2648.00000000
neff.median | 1446.50000000 | 2724.50000000
duration | 56.64315486 | 12.84117508
duration.MCMC.preparation | 47.74139595 | 2.91089392
duration.MCMC.transient | 0.15054391 | 0.17057251
duration.MCMC.asymptotic | 0.70088007 | 3.24087764
duration.MCMC.after | 0.00005102 | 0.00005293
duration.btadjust | 8.05028391 | 6.51877809
CPUduration | 12.13000000 | 4.82000000
CPUduration.MCMC.preparation | 10.57000000 | 1.50000000
CPUduration.MCMC.transient | 0.13968327 | 0.15650000
CPUduration.MCMC.asymptotic | 0.65031673 | 2.97350000
CPUduration.MCMC.after | 0.00000000 | 0.00000000
CPUduration.btadjust | 0.77000000 | 0.19000000
childCPUduration | NA | NA
childCPUduration.MCMC.preparation | NA | NA
childCPUduration.MCMC.transient | NA | NA
childCPUduration.MCMC.asymptotic | NA | NA
childCPUduration.MCMC.after | NA | NA
childCPUduration.btadjust | NA | NA

The conclusion is that `JAGS` is much faster than `NIMBLE` on this example (row named `duration` in the previous table), due to much less time devoted to MCMC preparation - as well as to burn-in/thinning adjustment (rows named `duration.MCMC.preparation` and `duration.btadjust` in the previous table). Actually there is no adjustment with `JAGS` (`niter.tot` is equal to the initial number of iterations). Yet, `NIMBLE` is quicker regarding MCMC updating by iteration since it took `NIMBLE` less time than `JAGS` for the transient phase (respectively less than twice time for the asymptotic phase) although using more than 5.75 (resp. 1.4089474 for the asymptotic phase) times more iterations than `JAGS`.

At first sight, we would also conclude that MCMC efficiency per effective value is also better with `NIMBLE` since both languages had the same target for the minimum number of effective value - 1,000 - and the total MCMC time was lower with `NIMBLE`. Yet, the number of effective values are different:

Comparison of the number of effective values between the default NIMBLE model and the JAGS model:
| Nimble.default | Jags
--- | --- | ---
Min. Number Eff. values | 1350.0000000 | 2648.0000000
MCMC CPU time per Effective Value | 0.0005852 | 0.0011820

Indeed, “JAGS” with just the first iterations produced a higher number of effective values - actually bigger than the targeted “neff.min” - than “NIMBLE”. Yet, the MCMC time per effective value remained lower with “NIMBLE” than with “JAGS” with this model (cf. table above).

# Greta

We finally run the `greta` version of our model with `runMCMC_btadjust()`. `greta` is rather different from `JAGS` and `NIMBLE` in that the model defines objects in R and thus does not require a model code to be passed to `runMCMC_btadjust()`, nor Data or Constants. The coding with `greta` is as follows:

    #in my setting I need to load not only greta but R6 & tensorflow packages
    library(greta)
    library (R6)
    library(tensorflow)

    #first requirement of greta: declaring the data that will be analyzed with the function as_data
    Y<-as_data(y1000)

    #we then proceed by writing the model directly in R, starting with the priors of the parameters using greta functions for probability distributions - here uniform()
    population.mean<-uniform(0,5000)
    population.sd<-uniform(0,100)

    #we then define the distribution of the data - here with the normal distribution - by default parametrized with a standard deviation in greta:
    try({distribution(Y)<-normal(population.mean,population.sd) })

    #we finally declare the greta model, which will be the object passed to runMCMC_btadjust
    m<-model(population.mean, population.sd)

    ### we finally have to prepare initial values with a specific greta function - initials:
    ModelInits.Greta <- function()
        {initials(population.mean = rnorm(1,600,90), population.sd = runif(1, 1, 30))}

    set.seed(1)
      Inits.Greta<-lapply(1:Nchains,function(x){ModelInits.Greta()})

We are now ready to fit the model with `runMCMC_btadjust()`, specifying `MCMC_language="Greta"` and giving the argument `model` instead of `code` and `data`:

    out.mcmc.greta<-runMCMC_btadjust(model=m, MCMC_language="Greta",
        Nchains=Nchains,params=params,inits=Inits.Greta,
            niter.min=1000,niter.max=300000,
        nburnin.min=100,nburnin.max=200000,
            thin.min=1,thin.max=1000,
            conv.max=1.05, neff.min=1000)
    #> [1] "control$seed is NULL. Replaced by 1"
    #> [1] "###################################################################################"
    #>
    #> [1] "Raw multiplier of thin:  4.399"
    #> [1] "###################################################################################"
    #> [1] "Testing multiplier of thin:  4 :"
    #> [1] "Testing multiplier of thin:  3 :"
    #> [1] "Retained multiplier of thin:  3 :"
    #> [1] "###################################################################################"
    #> [1] "Case of niter update: Convergence and trying to reach end of MCMC at the end of next cycle"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #>
    #> [1] "###################################################################################"
    #> [1] "Main MCMC sampling finished."
    #> [1] "###################################################################################"
    #> [1] "Final max raw multiplier of thin:  1.859"
    #> [1] "###################################################################################"
    #> [1] "Testing final multiplier of thin:  2 :"
    #> [1] "Retained final multiplier of thin:  1"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> [1] "MCMC has reached the required level of convergence."
    #> [1] "###################################################################################"
    #> [1] "MCMC has reached the required level of effective values."
    #> [1] "###################################################################################"

Summary of the statistical parameters of the greta model:
| Mean | SD | Naive SE | Time-series SE
--- | --- | --- | --- | ---
population.mean | 599.673 | 0.965 | 0.021 | 0.028
population.sd | 31.098 | 0.677 | 0.015 | 0.015

We first check that estimations are similar to those with `NIMBLE` and `JAGS` with paired Kolmogorov-Smirnov tests:

P-values of paired Kolmogorov-Smirnov tests of output parameters of the greta model with the default NIMBLE model and the JAGS model:
| mean | sd
--- | --- | ---
Nimble vs. greta | 0.6940 | 0.1166
Jags vs. greta | 0.7231 | 0.6482

We then report the efficiency of the MCMCs.

Comparison of the efficiency of the default NIMBLE, the JAGS and the greta models:
| Nimble.default | Jags | Greta
--- | --- | --- | ---
converged | 1.00000000 | 1.00000000 | 1.00000000
neffs.reached | 1.00000000 | 1.00000000 | 1.00000000
final.Nchains | 3.00000000 | 3.00000000 | 3.00000000
burnin | 575.00000000 | 100.00000000 | 0.00000000
thin | 4.00000000 | 2.00000000 | 3.00000000
niter.tot | 3252.00000000 | 2000.00000000 | 2113.00000000
Nvalues | 2010.00000000 | 2850.00000000 | 2115.00000000
neff.min | 1350.00000000 | 2648.00000000 | 1138.00000000
neff.median | 1446.50000000 | 2724.50000000 | 1582.00000000
duration | 56.64315486 | 12.84117508 | 23.48860598
duration.MCMC.preparation | 47.74139595 | 2.91089392 | 0.66471004
duration.MCMC.transient | 0.15054391 | 0.17057251 | 5.09996526
duration.MCMC.asymptotic | 0.70088007 | 3.24087764 | 10.77622659
duration.MCMC.after | 0.00005102 | 0.00005293 | 0.00004983
duration.btadjust | 8.05028391 | 6.51877809 | 6.94765425
CPUduration | 12.13000000 | 4.82000000 | 6.01000000
CPUduration.MCMC.preparation | 10.57000000 | 1.50000000 | 0.01000000
CPUduration.MCMC.transient | 0.13968327 | 0.15650000 | 1.87921619
CPUduration.MCMC.asymptotic | 0.65031673 | 2.97350000 | 3.97078381
CPUduration.MCMC.after | 0.00000000 | 0.00000000 | 0.00000000
CPUduration.btadjust | 0.77000000 | 0.19000000 | 0.15000000
childCPUduration | NA | NA | NA
childCPUduration.MCMC.preparation | NA | NA | NA
childCPUduration.MCMC.transient | NA | NA | NA
childCPUduration.MCMC.asymptotic | NA | NA | NA
childCPUduration.MCMC.after | NA | NA | NA
childCPUduration.btadjust | NA | NA | NA

MCMC time (rows `duration.MCMC.transient` & `duration.MCMC.asymptotic`) was far greater with `greta` than with `JAGS` and `NIMBLE`, for a minimum number of effective values with `greta` of 1138. Total duration is rather close with `greta` compared with `NIMBLE`, due to the great time required by `NIMBLE` for MCMC preparation - while this preparation is done outside `runMCMC_btadjust()` with `greta`. Yet, when we compare CPU total durations (`CPUduration`), `greta` gets worse than `NIMBLE` while it was the reverse for total duration (`duration`), simply because `greta` parallelized its process and therefore required more CPU time per time unit.

We tried to give a second chance to `greta`, based on the following post: https://forum.greta-stats.org/t/size-and-number-of-leapfrog-steps-in-hmc/332. The idea was to let `greta` have more information to adapt its hmc parameters during the warm-up phase by just having more chains to run - hereafter, 15.

    Nchains.Greta<-15
    ModelInits.Greta <- function()
        {initials(population.mean = rnorm(1,600,90), population.sd = runif(1, 1, 30))}

    set.seed(1)
    Inits.Greta<-lapply(1:Nchains.Greta,function(x){ModelInits.Greta()})

      out.mcmc.greta.morechains<-runMCMC_btadjust(model=m, MCMC_language="Greta",
        Nchains=Nchains.Greta,params=params,inits=Inits.Greta,
            niter.min=1000,niter.max=300000,
        nburnin.min=100,nburnin.max=200000,
            thin.min=1,thin.max=1000,
            conv.max=1.05, neff.min=1000)
    #> [1] "control$seed is NULL. Replaced by 1"
    #> [1] "###################################################################################"
    #>
    #> [1] "###################################################################################"
    #> [1] "Main MCMC sampling finished."
    #> [1] "###################################################################################"
    #> [1] "Final max raw multiplier of thin:  4.423"
    #> [1] "###################################################################################"
    #> [1] "Testing final multiplier of thin:  4 :"
    #> [1] "Retained final multiplier of thin:  4"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> [1] "MCMC has reached the required level of convergence."
    #> [1] "###################################################################################"
    #> [1] "MCMC has reached the required level of effective values."
    #> [1] "###################################################################################"

Summary of the statistical parameters of the greta model with 15 chains:
| Mean | SD | Naive SE | Time-series SE
--- | --- | --- | --- | ---
population.mean | 599.683 | 0.979 | 0.016 | 0.019
population.sd | 31.113 | 0.713 | 0.012 | 0.014

This run was indeed much faster. Parameter estimates were still not significantly different from those with `NIMBLE` and `JAGS` based on paired Kolmogorov-Smirnov tests:

P-values of paired Kolmogorov-Smirnov tests of output parameters of the greta model with 15 chains with the default NIMBLE model and the JAGS model:
| mean | sd
--- | --- | ---
Nimble vs. greta.morechains | 0.49343 | 0.03354
Jags vs. greta.morechains | 0.82098 | 0.09591

We now report the efficiency of the MCMCs:

Comparison of the efficiency of the default NIMBLE, the JAGS and the greta.morechains models:
| Nimble.default | Jags | Greta.morechains
--- | --- | --- | ---
converged | 1.00000000 | 1.00000000 | 1.00000000
neffs.reached | 1.00000000 | 1.00000000 | 1.00000000
final.Nchains | 3.00000000 | 3.00000000 | 15.00000000
burnin | 575.00000000 | 100.00000000 | 0.00000000
thin | 4.00000000 | 2.00000000 | 4.00000000
niter.tot | 3252.00000000 | 2000.00000000 | 1000.00000000
Nvalues | 2010.00000000 | 2850.00000000 | 3750.00000000
neff.min | 1350.00000000 | 2648.00000000 | 1979.00000000
neff.median | 1446.50000000 | 2724.50000000 | 2285.00000000
duration | 56.64315486 | 12.84117508 | 20.25214696
duration.MCMC.preparation | 47.74139595 | 2.91089392 | 0.71889520
duration.MCMC.transient | 0.15054391 | 0.17057251 | 7.39021599
duration.MCMC.asymptotic | 0.70088007 | 3.24087764 | 7.39021599
duration.MCMC.after | 0.00005102 | 0.00005293 | 0.00005317
duration.btadjust | 8.05028391 | 6.51877809 | 4.75276661
CPUduration | 12.13000000 | 4.82000000 | 5.77000000
CPUduration.MCMC.preparation | 10.57000000 | 1.50000000 | 0.00000000
CPUduration.MCMC.transient | 0.13968327 | 0.15650000 | 2.71000000
CPUduration.MCMC.asymptotic | 0.65031673 | 2.97350000 | 2.71000000
CPUduration.MCMC.after | 0.00000000 | 0.00000000 | 0.00000000
CPUduration.btadjust | 0.77000000 | 0.19000000 | 0.35000000
childCPUduration | NA | NA | NA
childCPUduration.MCMC.preparation | NA | NA | NA
childCPUduration.MCMC.transient | NA | NA | NA
childCPUduration.MCMC.asymptotic | NA | NA | NA
childCPUduration.MCMC.after | NA | NA | NA
childCPUduration.btadjust | NA | NA | NA

We still observed more CPU duration with `greta`, although the associated number of effective values for `greta` was now 1979, which rendered MCMC CPU efficiency with `greta` closer to `NIMBLE`.

# Parallelization

The function `runMCMC_btadjust()` now allows automatic parallelization of different Markov chains of the MCMC parts of the algorithm which can be of interest when we have several Markov chains. When the user wishes to use parallelization, the user should add to the call `control.MCMC=list(parallelize=TRUE)` - or of `parallelize=TRUE` in `control.MCMC` if already present. If `MCMC.language` is `Nimble`, due to restrictions of the CRAN, the user should also add `parallelizeInitExpr= expression(if(MCMC_language=="Nimble"){library(nimble);if(control.MCMC$APT) {library(nimbleAPT)}} else {NULL})` in `control.MCMC` or something equivalent. Here are examples below, with 2 chains only (a condition required by CRAN to accept parallelization in vignettes).

    library(parallel)

    ### put here to pass CRAN tests: https://stackoverflow.com/questions/41307178/error-processing-vignette-failed-with-diagnostics-4-simultaneous-processes-spa
    options(mc.cores=2)

    ### adapted the number of chains for the same reason
    Nchains.parallel<-2

    out.mcmc.Nimble.parallel<-runMCMC_btadjust(code=ModelCode, constants = ModelConsts, data = ModelData, MCMC_language="Nimble",
        Nchains=Nchains.parallel, params=params, inits=Inits[1:Nchains.parallel],
        niter.min=1000, niter.max=300000,
        nburnin.min=100, nburnin.max=200000,
        thin.min=1, thin.max=1000,
        conv.max=1.05, neff.min=1000,
        control.MCMC=list(parallelize=TRUE,
          parallelizeInitExpr= expression(if(MCMC_language=="Nimble"){library(nimble);if(control.MCMC$APT) {library(nimbleAPT)}} else {NULL})))
    #> [1] "control$seed is NULL. Replaced by 1"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> [1] "Raw multiplier of thin:  4.792"
    #> [1] "###################################################################################"
    #> [1] "Testing multiplier of thin:  5 :"
    #> [1] "Testing multiplier of thin:  4 :"
    #> [1] "Testing multiplier of thin:  3 :"
    #> [1] "Retained multiplier of thin:  3 :"
    #> [1] "###################################################################################"
    #> [1] "Case of niter update: Convergence and trying to reach end of MCMC at the end of next cycle"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> [1] "Main MCMC sampling finished."
    #> [1] "###################################################################################"
    #> [1] "Final max raw multiplier of thin:  1.653"
    #> [1] "###################################################################################"
    #> [1] "Testing final multiplier of thin:  2 :"
    #> [1] "Retained final multiplier of thin:  1"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> [1] "MCMC has reached the required level of convergence."
    #> [1] "###################################################################################"
    #> [1] "MCMC has reached the required level of effective values."
    #> [1] "###################################################################################"

    out.mcmc.Jags.parallel<-runMCMC_btadjust(code=modeltotransfer,  data = ModelData.Jags, MCMC_language="Jags",
        Nchains=Nchains.parallel, params=params, inits=Inits[1:Nchains.parallel],
        niter.min=1000,niter.max=300000,
        nburnin.min=100,nburnin.max=200000,
        thin.min=1,thin.max=1000,
            conv.max=1.05,neff.min=1000,
        control.MCMC=list(parallelize=TRUE))
    #> [1] "control$seed is NULL. Replaced by 1"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> [1] "Main MCMC sampling finished."
    #> [1] "###################################################################################"
    #> [1] "Final max raw multiplier of thin:  1.55"
    #> [1] "###################################################################################"
    #> [1] "Testing final multiplier of thin:  2 :"
    #> [1] "Retained final multiplier of thin:  2"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> [1] "MCMC has reached the required level of convergence."
    #> [1] "###################################################################################"
    #> [1] "MCMC has reached the required level of effective values."
    #> [1] "###################################################################################"

# Automatic removal of chains

We finally present an attractive feature of `runMCMC_btadjust()` which is to remove chains whose parameters are all invariable during the firs cycle of the MCMC. This is an issue that can appear for some chains, especially when initial values of parameters are far away from likely values and the MCMC sampler cannot move from the corresponding value. We here illustrate this on a simplified version of the above model in which the standard deviation is given (i.e. is not estimated) - simply because in the case the sampler can move for this parameter. We introduce a low standard deviation value in the normal distribution. Here is the code:

    ModelCode<-nimbleCode(
      {
        # Priors
        population.mean ~ dunif(0,5000)

        # Likelihood
        for(i in 1:nobs){
          mass[i] ~ dnorm(population.mean, 1)
        }
      })

We then update the initial values, introducing a very unlikely value in the second chain:

    Nchains <- 3

    ModelInits <- function()
    {list (population.mean = rnorm(1,600,2))}

    set.seed(1)
    Inits<-lapply(1:Nchains,function(x){ModelInits()})

    Inits[[2]]<-list(population.mean=-600)

    #specifying the names of parameters to analyse and save:
    params <- c("population.mean")

We then launch `runMCMC_btadjust()` in this setting:

    out.mcmc.pbIV<-runMCMC_btadjust(code=ModelCode, constants = ModelConsts, data = ModelData, MCMC_language="Nimble",
        Nchains=Nchains, params=params, inits=Inits,
        niter.min=1000, niter.max=300000,
        nburnin.min=100, nburnin.max=200000,
        thin.min=1, thin.max=1000,
        conv.max=1.05, neff.min=1000)
    #> [1] "control$seed is NULL. Replaced by 1"
    #> ===== Monitors =====
    #> thin = 1: population.mean
    #> ===== Samplers =====
    #> RW sampler (1)
    #>   - population.mean
    #> ===== Monitors =====
    #> thin = 1: population.mean
    #> ===== Samplers =====
    #> RW sampler (1)
    #>   - population.mean
    #> ===== Monitors =====
    #> thin = 1: population.mean
    #> ===== Samplers =====
    #> RW sampler (1)
    #>   - population.mean
    #> [1] "###################################################################################"
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> warning: problem initializing stochastic node population.mean: logProb is -Inf.
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> [1] "###################################################################################"
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> [1] "Raw multiplier of thin:  5.007"
    #> [1] "###################################################################################"
    #> [1] "Testing multiplier of thin:  5 :"
    #> [1] "Testing multiplier of thin:  4 :"
    #> [1] "Testing multiplier of thin:  3 :"
    #> [1] "Retained multiplier of thin:  3 :"
    #> [1] "###################################################################################"
    #> [1] "Case of niter update: Convergence and trying to reach end of MCMC at the end of next cycle"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> [1] "###################################################################################"
    #> [1] "Main MCMC sampling finished."
    #> [1] "###################################################################################"
    #> [1] "Final max raw multiplier of thin:  1.89"
    #> [1] "###################################################################################"
    #> [1] "Testing final multiplier of thin:  2 :"
    #> [1] "Retained final multiplier of thin:  1"
    #> [1] "###################################################################################"
    #> [1] "###################################################################################"
    #> [1] "MCMC has reached the required level of convergence."
    #> [1] "###################################################################################"
    #> [1] "MCMC has reached the required level of effective values."
    #> [1] "###################################################################################"

Despite the very unlikely value for chain 2, the model converges and reached the number of effective values. We also notice in the above that only two chains were updated - chains number 1 and 3. Actually, only two chains are present in the results and the output specifies that chain 2 was removed.

    length(out.mcmc.pbIV)
    #> [1] 2

    attributes(out.mcmc.pbIV)$final.params$final.Nchains
    #> [1] 2

    attributes(out.mcmc.pbIV)$final.params$removed.chains
    #> [1] 2

Note that if the removal of chains makes the number of chains pass from more than 1 to 1, the MCMC is stopped because the convergence diagnostic type and its targets would not adapt to a situation where there is only one chain.

    out.mcmc.pbIV.2chains<-runMCMC_btadjust(code=ModelCode, constants = ModelConsts, data = ModelData, MCMC_language="Nimble",
        Nchains=2, params=params, inits=Inits[1:2],
        niter.min=1000, niter.max=300000,
        nburnin.min=100, nburnin.max=200000,
        thin.min=1, thin.max=1000,
        conv.max=1.05, neff.min=1000)
    #> [1] "control$seed is NULL. Replaced by 1"
    #> ===== Monitors =====
    #> thin = 1: population.mean
    #> ===== Samplers =====
    #> RW sampler (1)
    #>   - population.mean
    #> ===== Monitors =====
    #> thin = 1: population.mean
    #> ===== Samplers =====
    #> RW sampler (1)
    #>   - population.mean
    #> [1] "###################################################################################"
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> warning: problem initializing stochastic node population.mean: logProb is -Inf.
    #> |-------------|-------------|-------------|-------------|
    #> |-------------------------------------------------------|
    #> Error in system.time({: Impossible to use the Gelman-Rubin convergence diagnostic with only one MCMC chain (***after update of Nchains***): please change Nchain or control$convtype or update your initial values

Removed chains are removed from the convergence and effective number diagnostics as well as from the outputs of `runMCMC_btadjust()`. If used with `Nimble`, it is also removed from the updated chains - thus saving computer resources. Such was not found possible with `Jags` and `Greta`. This

# Conclusion

We hope we have convinced the R user of Bayesian models that `runMCMC_btadjust()` can help having a more efficient, quality oriented use of these types of models while saving analyst’s and potentially computer time. Indeed, to recap, the aim of this function is to run a Markov Chain Monte Carlo (MCMC) for a specified Bayesian model while adapting automatically the burn-in and thinning parameters to meet pre-specified targets in terms of MCMC convergence and number of effective values of MCMC outputs. This is done in only one call to the function that repeatedly calls the MCMC until criteria for convergence and number of effective values are met. The function has four main advantages:

1. it saves the analyst’s programming time since he/she does not have to repeatedly diagnose and re-run MCMCs until desired levels of convergence and number of effective values are reached;

2. it allows a minimal, normalized quality control of MCMC outputs by allowing to meet pre-specified levels in terms of convergence and number of quasi-independent values;

3. it may save computer’s time when compared to cases where we have to restart the MCMC from the beginning if it has not converged or reached the specified number of effective values;

4. it can be applied with different MCMC fitting tools available in R - at present `greta`, `NIMBLE` and `JAGS`. This comes with two positive consequences in practice: first, allowing the user a more rigorous comparison between the three Bayesian fitting languages in terms of comparability of inference and of MCMC efficiency - especially in terms of CPU time per effective value; second, making it easier to develop the same Bayesian model with these different languages, which is to our experience welcome in practical cases, since these different languages have advantages over the other ones that vary from one context to the other.

# Acknowledgements

I wished to thank Frédéric Mortier (ANR Gambas project supervisor, project in which the initial versions of the package were developed), Pierre Bouchet, Ugoline Godeau and Marion Gosselin (INRAE, for collaboration on some codes that were preliminary to this package) and `NIMBLE` and `greta` users mailing lists.

The initial development of this package (up to version 1.1.1) was performed within the GAMBAS project funded by the French Agence Nationale pour la Recherche (ANR-18-CE02-0025) (cf. https://gambas.cirad.fr/).

# References

Kéry, M. 2010. Introduction to WinBUGS for ecologists: Bayesian approach to regression, ANOVA, mixed models and related analyses. Page 320. Book, Academic Press.