DATA_SECTION
!! ad_comm::change_datafile_name("surp_prod1.dat");
init_int fyear;
init_int lyear;cat(fyear,lyear);
init_vector cpue(fyear,lyear);
init_vector
PARAMETER_SECTION
init_number log_r;
init_number log_q;
init_number log_K;
init_number log_sd_cpue;log_F(fyear,lyear);
init_vector
number r;
number q;
number K;
number sd_cat;
number sd_cpue;
bio(fyear,lyear+1);
vector cat_hat(fyear,lyear);
vector cpue_hat(fyear,lyear);
vector expl_out(fyear,lyear);
vector F(fyear,lyear);
vector
objective_function_value jnll;
INITIALIZATION_SECTION
-0.6
log_r -1
log_q 8.5
log_K -1
log_sd_cpue 1
log_F
PROCEDURE_SECTION
int t;
dvariable expl;
// Convert from log to normal space
= mfexp(log_r);
r = mfexp(log_q);
q = mfexp(log_K);
K = mfexp(log_F);
F = 0.05;
sd_cat = mfexp(log_sd_cpue);
sd_cpue
// Project the model forward
bio(fyear) = K;
for (t=fyear; t<=lyear; t++) {
= 1.0/(1.0+F(t));
expl bio(t+1) = bio(t) + r*bio(t)*(1.0-bio(t)/K) - expl*bio(t);
cat_hat(t) = expl * bio(t);
expl_out(t) = expl;
cpue_hat(t) = q * bio(t);
}
// Compute the likelihoods
= 0;
jnll for (t=fyear; t<=lyear; t++) {
+= 0.5 * square(log(cat(t)/cat_hat(t)) / sd_cat) + log(sd_cat);
jnll += 0.5 * square(log(cpue(t)/cpue_hat(t)) / sd_cpue) + log(sd_cpue);
jnll
}
GLOBALS_SECTION
#include <admodel.h>
#include <admb2r.cpp>
REPORT_SECTIONopen_r_file("out.rdat", 6, -999);
wrt_r_complete_vector("obs_cat", cat);
wrt_r_complete_vector("obs_cpue", cpue);
wrt_r_complete_vector("est_bio", bio);
wrt_r_complete_vector("est_cat", cat_hat);
wrt_r_complete_vector("est_cpue", cpue_hat);
wrt_r_complete_vector("est_expl", expl_out);
wrt_r_item("jnll", jnll);
close_r_file();
FINAL_SECTION
// extract Hessian matrix
open_r_file("hessian.rdat");
open_r_matrix("hessian");
wrt_r_matrix(get_hessian(),1,1);
close_r_matrix();
close_r_file();
Jitter test in ADMB using R
The goal of a jitter test is to check if alternative parameter starting points result in the same final parameter estimates and objective function. A jitter test should be conducted as one of the checks to make sure your model is consistent with convergence. It is recommended to conduct a jitter test across all model parameters.
This tutorial will walk through how to conduct a jitter test with ADMB models. The fastest way to run a jitter test in ADMB is to run it through the R environment, which will create an executable and run ADMB with the executable so you do not need to manually change the initial parameter values each iteration. However, this will require some additional steps to set up your code in both ADMB and R.
1 admb2r.cpp instructions
This tutorial requires this package called “admb2r”. This is a collection of AD Model Builder routines for saving complex data structures into a file that can be read into R. This cannot be automatically downloaded in the newer ADMB versions. You can keep a “admb2r.cpp” file where your .tpl and .dat files are, however that requires copying and pasting it every time you want to run a ADMB model.
These are instructions for using admb2r.cpp permanently. Copy admb2r.cpp to both the following folders:
admb/include
admb/include/contrib
A copy of admb2r.cpp is here. Once this is done you do not need to add “admb2r.cpp” to every project folder. This has been tested on Linux Mint, Windows, and Mac.
2 Set up ADMB
If possible, you should download the most recent ADMB version here. This recent version will print out additional error messages and allow you to run additional functions (like get_hessian()
).
2.1 Surplus production model - .tpl and .dat files
In this tutorial, we will look at a surplus production model. The .dat file name is called “surp_prod1.dat”. You can name the .tpl file anything, but in this tutorial, it will be called “surp_prod_jitter.tpl”.
This tutorial will not go through the surplus production model in details, but the model parameters are \(r\), \(K\), \(q\), \(F\), and \(sd_{cpue}\). Note that there is a standard deviation for the catch observations, but that is fixed in this model (\(sd_{catch}\) = 0.05) The objective function (jnll
) is the total objective function, which is the sum of the data likelihood for catch and index (CPUE) data, both of which follow a log normal distribution.
The default data file name is different than the .tpl file name. This is done using this command:
!! ad_com::change_datafile_name("surp_prod1.dat");
The data will be read from “surp_prod1.dat”. This is useful when you have many variants of the model that use the same data. This trick will be useful for the jitter test.
You can copy and paste the data “surp_prod1.dat” here:
# first year
1965
# last year
1988
# Catch
93.51
212.444
195.032
382.712
320.43
402.467
365.557
606.084
377.642
318.836
309.374
389.02
276.901
254.251
170.006
97.181
90.523
176.532
216.181
228.672
212.177
231.179
136.942
212
# Index
1.78
1.31
0.91
0.96
0.88
0.9
0.87
0.72
0.57
0.45
0.42
0.42
0.49
0.43
0.4
0.45
0.55
0.53
0.58
0.64
0.66
0.65
0.61
0.63
2.2 DATA_SECTION
In the surplus production example, we will jitter the following parameters: \(r\), \(K\), \(q\), and \(sd_{cpue}\).
!! ad_comm::change_datafile_name("log_r.dat");
init_number inlog_r;
!! ad_comm::change_datafile_name("log_K.dat");
init_number inlog_K;
!! ad_comm::change_datafile_name("log_q.dat");
init_number inlog_q;
!! ad_comm::change_datafile_name("log_sd_cpue.dat");
init_number inlog_sd_cpue;
This is similar to the previous command, but here the !! ad_com::change_datafile_name("log_r.dat")
command is reading parameter values (inlog_r
, inlog_q
, inlog_K
, inlog_sd_cpue
) from separate .dat files. This will be important in the R script as you can rewrite this .dat file to produce different starting values that will be read in ADMB one at a time. Note that the parameter name that is being read in (e.g., inlog_r
) should be different than the one in the PARAMETER_SECTION (the ones being used in the estimation; e.g., log_r
).
The entire DATA_SECTION will look like this:
DATA_SECTION!! ad_comm::change_datafile_name("log_r.dat");
init_number inlog_r;
!! ad_comm::change_datafile_name("log_K.dat");
init_number inlog_K;
!! ad_comm::change_datafile_name("log_q.dat");
init_number inlog_q;
!! ad_comm::change_datafile_name("log_sd_cpue.dat");
init_number inlog_sd_cpue;
!! ad_comm::change_datafile_name("surp_prod1.dat");
init_int fyear;
init_int lyear;cat(fyear,lyear);
init_vector cpue(fyear,lyear); init_vector
2.3 PARAMETER_SECTION
In this section, we will be overriding the starting parameter values declared in the INITIALIZATION_SECTION. This is why the parameter names above (e.g., inlog_r
) needs to be different than the ones (e.g., log_r
) being declared.
!! log_r = inlog_r;
!! log_K = inlog_K;
!! log_q = inlog_q;
!! log_sd_cpue = inlog_sd_cpue;
This will now read what was stored in the respective .dat files as the starting value of the parameter.
The entire PARAMETER_SECTION will look like this:
PARAMETER_SECTION
init_number log_r;
init_number log_q;
init_number log_K;
init_number log_sd_cpue;log_F(fyear,lyear);
init_vector
number r;
number q;
number K;
number sd_cat;
number sd_cpue;
bio(fyear,lyear+1);
vector cat_hat(fyear,lyear);
vector cpue_hat(fyear,lyear);
vector expl_out(fyear,lyear);
vector F(fyear,lyear);
vector
objective_function_value jnll;
// override starting values and read from .dat files
!! log_r = inlog_r;
!! log_K = inlog_K;
!! log_q = inlog_q;
!! log_sd_cpue = inlog_sd_cpue;
2.4 INITIALIZATION_SECTION
This section should either be commented out or empty as the .dat file for each parameters will override the starting value for that parameter. This is important for the jitter test to work:
INITIALIZATION_SECTION
// log_r -0.6
// log_q -9
// log_K 8.5
// log_sd_cpue -1
1 log_F
The next sections (PROCEDURE_SECTION, GLOBALS_SECTION, and REPORT_SECTION) should be the same as the original model.
2.5 FINAL_SECTION
In the final section, you will need to add a command to define an output file stream, write the output, and close the output file. This is using the functionality of “admb2r”.
myout("estpars.dat",ios::app);
ofstream << inlog_r << " " << log_r << " " << inlog_q << " " << log_q << " " << inlog_K << " " << log_K << " " << inlog_sd_cpue << " " << log_sd_cpue << " " << jnll << endl;
myoutmyout.close();
The “estpars.dat” file will eventually contain all the input starting values from R, estimated parameters from ADMB, and the objective function from ADMB. This is important as it will contain all the iterations and results of the jitter test and will be read into R as a table.
The entire FINAL_SECTION will look like this:
FINAL_SECTION
myout("estpars.dat",ios::app);
ofstream << inlog_r << " " << log_r << " " << inlog_q << " " << log_q << " " << inlog_K << " " << log_K << " " << inlog_sd_cpue << " " << log_sd_cpue << " " << jnll << endl;
myoutmyout.close();
// extract Hessian matrix
open_r_file("hessian.rdat");
open_r_matrix("hessian");
wrt_r_matrix(get_hessian(),1,1);
close_r_matrix();
close_r_file();
2.6 Entire ADMB example of the surplus production model
Here is the entire ADMB script for an example of conducting a jitter test with the surplus production model:
DATA_SECTION
!! ad_comm::change_datafile_name("log_r.dat");
init_number inlog_r;
!! ad_comm::change_datafile_name("log_K.dat");
init_number inlog_K;
!! ad_comm::change_datafile_name("log_q.dat");
init_number inlog_q;
!! ad_comm::change_datafile_name("log_sd_cpue.dat");
init_number inlog_sd_cpue;
!! ad_comm::change_datafile_name("surp_prod1.dat");
init_int fyear;
init_int lyear;cat(fyear,lyear);
init_vector cpue(fyear,lyear);
init_vector
PARAMETER_SECTION
init_number log_r;
init_number log_q;
init_number log_K;
init_number log_sd_cpue;log_F(fyear,lyear);
init_vector
number r;
number q;
number K;
number sd_cat;
number sd_cpue;
bio(fyear,lyear+1);
vector cat_hat(fyear,lyear);
vector cpue_hat(fyear,lyear);
vector expl_out(fyear,lyear);
vector F(fyear,lyear);
vector
objective_function_value jnll;
!! log_r = inlog_r;
!! log_K = inlog_K;
!! log_q = inlog_q;
!! log_sd_cpue = inlog_sd_cpue;
INITIALIZATION_SECTION
// log_r -0.6
// log_q -9
// log_K 8.5
1
log_F
PROCEDURE_SECTION
int t;
dvariable expl;
dvariable sum_sq;
// Convert from log to normal space
= mfexp(log_r);
r = mfexp(log_q);
q = mfexp(log_K);
K = mfexp(log_F);
F = 0.05;
sd_cat = mfexp(log_sd_cpue);
sd_cpue
// Project the model forward
bio(fyear) = K;
for (t=fyear; t<=lyear; t++) {
= 1.0/(1.0+F(t));
expl bio(t+1) = bio(t) + r*bio(t)*(1.0-bio(t)/K) - expl*bio(t);
cat_hat(t) = expl * bio(t);
expl_out(t) = expl;
cpue_hat(t) = q * bio(t);
}
// Compute the likelihoods
= 0;
jnll for (t=fyear; t<=lyear; t++) {
+= 0.5 * square(log(cat(t)/cat_hat(t)) / sd_cat) + log(sd_cat);
jnll += 0.5 * square(log(cpue(t)/cpue_hat(t)) / sd_cpue) + log(sd_cpue);
jnll
}
GLOBALS_SECTION#include <admodel.h>
#include <admb2r.cpp>
REPORT_SECTIONopen_r_file("out.rdat", 6, -999);
wrt_r_complete_vector("obs_cat", cat);
wrt_r_complete_vector("obs_cpue", cpue);
wrt_r_complete_vector("est_bio", bio);
wrt_r_complete_vector("est_cat", cat_hat);
wrt_r_complete_vector("est_cpue", cpue_hat);
wrt_r_complete_vector("est_expl", expl_out);
wrt_r_item("jnll", jnll);
close_r_file();
FINAL_SECTION
myout("estpars.dat",ios::app);
ofstream << inlog_r << " " << log_r << " " << inlog_q << " " << log_q << " " << inlog_K << " " << log_K << " " << inlog_sd_cpue << " " << log_sd_cpue << " " << jnll << endl;
myoutmyout.close();
// extract Hessian matrix
open_r_file("hessian.rdat");
open_r_matrix("hessian");
wrt_r_matrix(get_hessian(),1,1);
close_r_matrix();
close_r_file();
The next step is to set up a R script to run the jitter test.
3 Set up R
3.1 Add ADMB to your environment
The R script should work on all computer environments (Windows, Mac, Linux) as long as ADMB is properly setup. These are the instructions for each system:
Linux Mint (probably most other Linux):
- add this line to the end of .profile in Home directory:
export PATH=~/admb:$PATH
Mac
- add this line right before “export PATH” at end of .zprofile in Home directory:
PATH="~/admb:${PATH}"
Windows:
- In System Environment Variables, add
C:\ADMB-13.2\\bin
to Path
3.2 R helper functions
You will need these helper files to run ADMB through R:
base_funs.r - this contains three functions to read and compile a ADMB executable and run the ADMB model
compile_admb()
read_admb()
run_admb()
clean_admb.r - after you are done running your model, this will clean all the additional ADMB files in your directory.
You can also run this in R to download these files directly to your local directory:
download.file("https://raw.githubusercontent.com/lidach/addtools/main/R/base_funs.r", destfile = "base_funs.r")
download.file("https://raw.githubusercontent.com/lidach/addtools/main/R/clean_admb.r", destfile = "clean_admb.r")
These helper functions will be loaded in R using the source()
function (make sure these are in the same directory as the .tpl and .dat files):
source("base_funs.r")
source("clean_admb.r")
3.3 Compile and run ADMB in R
The R helper functions (“base_funs.r”) has a function “compile_admb.r” which will compile ADMB using a R command and through the R environment. The .tpl name in this tutorial is called “surp_prod_jitter”.
<- "surp_prod_jitter" # name of the .tpl file
tpl_name # compile ADMB
compile_admb(fn = tpl_name, verbose = TRUE)
We will include verbose = TRUE
, which will print out the compile messages from ADMB in the R console (should be the same as running the ADMB command prompt):
> compile_admb(fn = tpl_name, verbose = TRUE)
compiling with args: ' ' ...
compile output:
*** Parse: surp_prod_jitter.tpl xxglobal.tmp xxhtop.tmp header.tmp xxalloc.tmp xxtopm
.tmp 1 file(s) copied. tpl2cpp surp_prod_jitter *** Compile: surp_prod_jitter.cpp g
++ -c -std=c++17 -O2 -D_FILE_OFFSET_BITS=64 -DUSE_ADMB_CONTRIBS -D_USE_MATH_DEFINES -I.
-I"c:\ADMB-13.1\include" -I"c:\ADMB-13.1\include\contrib" -o surp_prod_jitter.obj
surp_prod_jitter.cpp *** Linking: surp_prod_jitter.obj g++ -static -o
surp_prod_jitter.exe surp_prod_jitter.obj "c:\ADMB-13.1\lib\libadmb-contrib-mingw64-g
++12.a" Successfully built 'surp_prod_jitter.exe'.
compile log:
Next we will create new .dat files, which will contain the starting parameter values that will be read into ADMB.
cat("-0.6", file = "log_r.dat", sep = "\n")
cat("-3", file = "log_q.dat", sep = "\n")
cat("8", file = "log_K.dat", sep = "\n")
cat("-1", file = "log_sd_cpue.dat", sep = "\n")
This will create four .dat files (“log_r.dat”,“log_q_dat”, “log_K.dat”, and “log_sd_cpue.dat”). You should see this in your local directory:
The .dat files should contain each initial value that is specified (open each file and check):
-0.6
forlog_r
-3
forlog_q
8
forlog_K
-1
forlog_sd_cpue
Next, we will run the ADMB model using the command run_admb()
:
run_admb(fn = tpl_name, verbose = TRUE)
What prints out in the R console should look exactly like what prints out in the ADMB command prompt:
> run_admb(fn = tpl_name, verbose = TRUE)
running compiled executable with args: ' '...
Run output:
Starting optimization of 'surp_prod_jitter' in phase 1 of 1 at Fri May 17 13:46:02 2024
phase= 1 | nvar= 28 | iter= 0 | nll=5.27e+03 | mag=6.89e+03 | par[ 3]=log_K
phase= 1 | nvar= 28 | iter= 20 | nll=3.49e+01 | mag=1.98e+02 | par[ 1]=log_r
phase= 1 | nvar= 28 | iter= 40 | nll=-7.59e+01 | mag=9.90e+00 | par[ 4]=log_sd_cpue
phase= 1 | nvar= 28 | iter= 60 | nll=-9.49e+01 | mag=2.44e+02 | par[ 1]=log_r
phase= 1 | nvar= 28 | iter= 80 | nll=-1.03e+02 | mag=3.72e+01 | par[ 1]=log_r
phase= 1 | nvar= 28 | iter=100 | nll=-1.10e+02 | mag=2.12e-02 | par[ 18]=log_F[14]
phase= 1 | nvar= 28 | iter=105 | nll=-1.10e+02 | mag=7.04e-05 | par[ 1]=log_r
Optimization completed after 0.002 s with final statistics:
nll=-110.045337 | mag=7.03848e-05 | par[ 1]=log_r
Calculating Hessian (28 variables): 20%, 40%, 60%, 80%, 100% done (0.001 s)
Inverting Hessian (28 variables): 20%, 40%, 60%, 80%, 100% done (0.021 s)
Starting standard error calculations... done (0.026 s)
Finished running model 'surp_prod_jitter' after 0.069 s.
This should produce a model result of the surplus production model (check the “.par” file).
3.4 Set up the jitter test
Next, we will create an object called dat
, which will show what is being read into “estpars.dat”. This dat
object is just a check to make sure the file contains the correct values (initial starting values from R, parameter estimates from ADMB, and the objective function from ADMB).
if (file.exists("estpars.dat")) {
<- read.table("estpars.dat")
dat colnames(dat) <- c("inlog_r", "log_r", "inlog_q", "log_q", "inlog_K", "log_K", "inlog_sd_cpue", "log_sd_cpue", "objn")
}
> dat
inlog_r log_r inlog_q log_q inlog_K log_K inlog_sd_cpue log_sd_cpue objn
1 -0.6 -0.993585 -3 -7.75477 8 7.94441 -1 -2.09553 -110.045
We will then delete “estpars.dat” as this contains the first run of the surplus production model. We will also create a replacement file (same name - “estpars.dat”) that will have the same column names as dat
object in R (and the same as the ones created in the FINAL_SECTION of ADMB). We will use the “estpars.dat” file to store each iteration of the jitter test:
# Delete any existing version of estpars.dat
if (file.exists("estpars.dat")) file.remove("estpars.dat")
# Create header for file so we know the variables.
# sep ["\n" needed for line feed]
cat("inlog_r log_r inlogq log_q inlogK log_K inlog_sd_cpue log_sd_cpue objn", file = "estpars.dat", sep = "\n")
This is what the “estpars.dat” file should look like:
Next we will create a set of starting values. We will declare how many iterations of the jitter test we would like to conduct (nrun <- # number of iterations
). We will randomize a set of starting values for \(r\), \(q\), \(K\), and \(sd_{cpue}\) using the rnorm()
function, and it will be randomized with a CV = 10% (you can test different CV values, but make sure the value will make sense for the parameters):
# Define a set of starting values
<- 50 # number of reruns with new values
nrun <- dat$log_r + rnorm(nrun, sd = 0.1)
st_log_r <- dat$log_q + rnorm(nrun, sd = 0.1)
st_log_q <- dat$log_K + rnorm(nrun, sd = 0.1)
st_log_K <- dat$log_sd_cpue + rnorm(nrun, sd = 0.1) st_log_sd_cpue
You should get different initial parameter values for \(r\), \(q\), \(K\), and \(sd_{cpue}\) (this is what st_log_r
looks like):
> st_log_r
[1] -0.9228182 -1.0814674 -0.9838309 -1.1326115 -1.0384462 -0.9755354 -0.9474958 -1.0096512 -1.0027850
[10] -1.0605927 -0.9374780 -1.1490212 -0.9859142 -0.9419287 -1.2039070 -0.9467160 -1.0082140 -0.8845776
[19] -1.0501845 -1.1293860 -1.1745426 -1.0972523 -1.0876272 -0.6523069 -1.0300151 -0.9892598 -1.0002751
[28] -1.0470151 -0.8234914 -1.0142313 -0.9383547 -0.7523401 -0.8571388 -1.0204309 -0.5843942 -0.9964475
[37] -1.1139635 -0.8975815 -1.0615098 -0.9125939 -0.8941080 -1.0473705 -1.1201994 -1.0117377 -0.9563844
[46] -1.0354310 -0.7548647 -0.9615213 -1.0294900 -1.0297567
This is where ADMB will run 50 times in a for loop, with each iteration reading different values of \(r\), \(q\), \(K\), and \(sd_{cpue}\) from the objects st_log_r
, st_log_q
, st_log_K
, and st_log_sd_cpue
. We will use the system()
function to rerun the ADMB model from the executable file (.exe
):
# Write out each value of the parameters and run ADMB program for each in loop
for (i in 1:length(st_log_r)) {
cat(st_log_r[i], file = "log_r.dat", sep = "") # write one st value to file
cat(st_log_q[i], file = "log_q.dat", sep = "") # write one st value to file
cat(st_log_K[i], file = "log_K.dat", sep = "") # write one st value to file
cat(st_log_sd_cpue[i], file = "log_sd_cpue.dat", sep = "") # write one st value to file
if(Sys.info()["sysname"] == "Windows") { # windows
system(paste0(tpl_name, ".exe"))
else { # most Mac's and Linux
} system(paste0("./", tpl_name))
} }
These lines of code will automatically detect the system you are using (Sys.info()
command), so this will work on all computer systems. Note that we do not need to manually recompile the model from the ADMB command prompt or use the admb
command to rerun the model.
3.5 Jitter test results
Now we will read in the “estpars.dat” file, which should contain all the iterations of the jitter test with different starting values of each parameter:
# read in and print results to console
<- read.table("estpars.dat", header = T)
jit_res jit_res
When you look at the jit_res
object, it should look like this:
> head(jit_res)
inlog_r log_r inlogq log_q inlogK log_K inlog_sd_cpue log_sd_cpue objn
1 -0.922818 -0.993586 -7.90445 -7.75477 7.86950 7.94441 -2.02155 -2.09553 -110.045
2 -1.081470 -0.993585 -7.81425 -7.75477 7.72846 7.94441 -2.03412 -2.09553 -110.045
3 -0.983831 -0.993585 -7.61159 -7.75477 8.04017 7.94441 -2.11698 -2.09553 -110.045
4 -1.132610 -0.993585 -7.84504 -7.75477 8.01831 7.94441 -2.03281 -2.09553 -110.045
5 -1.038450 -0.993586 -7.80241 -7.75477 8.09650 7.94441 -2.05765 -2.09553 -110.045
6 -0.975535 -0.993586 -7.90383 -7.75477 7.93884 7.94441 -1.99051 -2.09553 -110.045
There are some things to look out for in the jit_res
object:
The initial starting parameter values are different across the 50 iterations (
st_log_r
,st_log_q
,st_log_K
, andst_log_sd_cpue)
Make sure that the parameter estimates across the 50 iterations are the same (
log_r
,log_q
,log_K
, andlog_sd_cpue
) (note: there may be some rounding differences, but the estimates should not be significantly different)The objective function (joint negative log likelihood in this tutorial) are the same across the 50 iterations (
objn
).
We can also visualize the jitter test using a box plot. The box plot will show if there are any odd shapes in the box plot or any outliers. A jitter test that passes a convergence check will show no odd shapes in the box plot (no quartiles) and will not have any outliers (as shown below):
# boxplots - are there any weird shapes/outliers?
boxplot(jit_res[, c(2, 4, 6, 8, 9)])
After conducting the jitter test, we can run these functions that will clean the extra ADMB files that were compiled throughout the process:
# clean extra files
clean_admb(fn = tpl_name)
if (file.exists("estpars.dat")) file.remove("estpars.dat")
if (file.exists("out.rdat")) file.remove("out.rdat")
if (file.exists("hessian.rdat")) file.remove("hessian.rdat")
if (file.exists("log_K.dat")) file.remove("log_K.dat")
if (file.exists("log_r.dat")) file.remove("log_r.dat")
if (file.exists("log_q.dat")) file.remove("log_q.dat")
if (file.exists("log_sd_cpue.dat")) file.remove("log_sd_cpue.dat")
3.6 Entire R script for the jitter test of the surplus production model
Here is the entire R script for an example of conducting a jitter test with the surplus production model.
source("base_funs.r")
source("clean_admb.r")
<- "surp_prod_jitter"
tpl_name
# compile ADMB
compile_admb(fn = tpl_name, verbose = TRUE)
# set initial values and source from external files
cat("-0.6", file = "log_r.dat", sep = "\n")
cat("-3", file = "log_q.dat", sep = "\n")
cat("8", file = "log_K.dat", sep = "\n")
cat("-1", file = "log_sd_cpue.dat", sep = "\n")
# run ADMB
run_admb(fn = tpl_name, verbose = TRUE)
# get parameter estimates (used for jittering)
if (file.exists("estpars.dat")) {
<- read.table("estpars.dat")
dat colnames(dat) <- c("inlog_r", "log_r", "inlog_q", "log_q", "inlog_K", "log_K", "inlog_sd_cpue", "log_sd_cpue", "objn")
}
# Delete any existing version of estpars.dat
if (file.exists("estpars.dat")) file.remove("estpars.dat")
# Create header for file so we know the variables.
# sep ["\n" needed for line feed]
cat("inlog_r log_r inlogq log_q inlogK log_K inlog_sd_cpue log_sd_cpue objn", file = "estpars.dat", sep = "\n")
# Define a set of starting values
<- 50 # number of reruns with new values
nrun <- dat$log_r + rnorm(nrun, sd = 0.1)
st_log_r <- dat$log_q + rnorm(nrun, sd = 0.1)
st_log_q <- dat$log_K + rnorm(nrun, sd = 0.1)
st_log_K <- dat$log_sd_cpue + rnorm(nrun, sd = 0.1)
st_log_sd_cpue
# Write out each value of the parameters and run ADMB program for each in loop
for (i in 1:length(st_log_r)) {
cat(st_log_r[i], file = "log_r.dat", sep = "") # write one st value to file
cat(st_log_q[i], file = "log_q.dat", sep = "") # write one st value to file
cat(st_log_K[i], file = "log_K.dat", sep = "") # write one st value to file
cat(st_log_sd_cpue[i], file = "log_sd_cpue.dat", sep = "") # write one st value to file
if(Sys.info()["sysname"] == "Windows") { # windows
system(paste0(tpl_name, ".exe"))
else { # most Mac's and Linux
} system(paste0("./", tpl_name))
}
}
# read in and print results to console
<- read.table("estpars.dat", header = T)
jit_res
jit_res
# boxplots - are there any weird shapes/outliers?
boxplot(jit_res[, c(2, 4, 6, 8, 9)])
# clean extra files
clean_admb(fn = tpl_name)
if (file.exists("estpars.dat")) file.remove("estpars.dat")
if (file.exists("out.rdat")) file.remove("out.rdat")
if (file.exists("hessian.rdat")) file.remove("hessian.rdat")
if (file.exists("log_K.dat")) file.remove("log_K.dat")
if (file.exists("log_r.dat")) file.remove("log_r.dat")
if (file.exists("log_q.dat")) file.remove("log_q.dat")
if (file.exists("log_sd_cpue.dat")) file.remove("log_sd_cpue.dat")
4 Jitter test interpretation
There should not be any outliers or weird shapes in the box plots. Below is an example of how the box plot would look like if the jitter test fails:
A failed jitter test is indicative that there is something wrong with the model:
Incorrect parameterization
Bad starting values (they may not make sense for the parameter)
Incorrect specification of the objective function
Incorrect equations
Data is not informative enough to estimate the parameter
This should be done for every parameter. In this tutorial, the jitter test was not conducted on \(F\) and \(sd_{catch}\). However, to fully check the convergence of this model, the jitter test should also be conducted for all estimated values of \(F\) and sensitivity analysis should be conducted on the impacts of fixing \(sd_{catch}\).