697 lines
31 KiB
R
697 lines
31 KiB
R
##--------------------------------------------------------
|
|
## CMSY analysis with estimation of total biomass, including Bayesian Schaefer
|
|
## written by Rainer Froese with support from Gianpaolo Coro in 2013-2014
|
|
## This version adjusts biomass to average biomass over the year
|
|
## It also contains the FutureCrash option to improve prediction of final biomass
|
|
## Version 21 adds the purple point to indicate the 25th percentile of final biomass
|
|
## Version 22 accepts that no biomass or CPUE area available
|
|
##--------------------------------------------------------
|
|
library(R2jags) # Interface with JAGS
|
|
library(coda)
|
|
|
|
#-----------------------------------------
|
|
# Some general settings
|
|
#-----------------------------------------
|
|
# set.seed(999) # use for comparing results between runs
|
|
rm(list=ls(all=TRUE)) # clear previous variables etc
|
|
options(digits=3) # displays all numbers with three significant digits as default
|
|
graphics.off() # close graphics windows from previous sessions
|
|
|
|
#-----------------------------------------
|
|
# General settings for the analysis
|
|
#-----------------------------------------
|
|
sigR <- 0.02 # overall process error; 0.05 works reasonable for simulations, 0.02 for real data; 0 if deterministic model
|
|
n <- 10000 # initial number of r-k pairs
|
|
batch.mode <- T # set to TRUE to suppress graphs
|
|
write.output <- T # set to true if table of output is wanted
|
|
FutureCrash <- "No"
|
|
|
|
#-----------------------------------------
|
|
# Start output to screen
|
|
#-----------------------------------------
|
|
cat("-------------------------------------------\n")
|
|
cat("Catch-MSY Analysis,", date(),"\n")
|
|
cat("-------------------------------------------\n")
|
|
|
|
#------------------------------------------
|
|
# Read data and assign to vectors
|
|
#------------------------------------------
|
|
# filename_1 <- "AllStocks_Catch4.csv"
|
|
# filename_2 <- "AllStocks_ID4.csv"
|
|
# filename_1 <- "SimCatch.csv"
|
|
# filename_2 <- "SimSpec.csv"
|
|
# filename_2 <- "SimSpecWrongS.csv"
|
|
# filename_2 <- "SimSpecWrongI.csv"
|
|
# filename_2 <- "SimSpecWrongF.csv"
|
|
# filename_2 <- "SimSpecWrongH.csv"
|
|
# filename_2 <- "SimSpecWrongL.csv"
|
|
# filename_1 <- "FishDataLim.csv"
|
|
# filename_2 <- "FishDataLimSpec.csv"
|
|
filename_1 <- "WKLIFE4Stocks.csv"
|
|
filename_2 <- "WKLIFE4ID.csv"
|
|
|
|
outfile<-"outfile"
|
|
outfile.txt <- "outputfile.txt"
|
|
|
|
cdat <- read.csv(filename_1, header=T, dec=".", stringsAsFactors = FALSE)
|
|
cinfo <- read.csv(filename_2, header=T, dec=".", stringsAsFactors = FALSE)
|
|
cat("Files", filename_1, ",", filename_2, "read successfully","\n")
|
|
|
|
# Stocks with total biomass data and catch data from StartYear to EndYear
|
|
# stocks <- sort(as.character(cinfo$stock)) # All stocks
|
|
stocks<-"HLH_M07"
|
|
|
|
# select one stock after the other
|
|
for(stock in stocks) {
|
|
# assign data from cinfo to vectors
|
|
res <- as.character(cinfo$Resilience[cinfo$stock==stock])
|
|
StartYear <- as.numeric(cinfo$StartYear[cinfo$stock==stock])
|
|
EndYear <- as.numeric(cinfo$EndYear[cinfo$stock==stock])
|
|
r_low <- as.numeric(cinfo$r_low[cinfo$stock==stock])
|
|
r_hi <- as.numeric(cinfo$r_hi[cinfo$stock==stock])
|
|
stb_low <- as.numeric(cinfo$stb_low[cinfo$stock==stock])
|
|
stb_hi <- as.numeric(cinfo$stb_hi[cinfo$stock==stock])
|
|
intyr <- as.numeric(cinfo$intyr[cinfo$stock==stock])
|
|
intbio_low <- as.numeric(cinfo$intbio_low[cinfo$stock==stock])
|
|
intbio_hi <- as.numeric(cinfo$intbio_hi[cinfo$stock==stock])
|
|
endbio_low <- as.numeric(cinfo$endbio_low[cinfo$stock==stock])
|
|
endbio_hi <- as.numeric(cinfo$endbio_hi[cinfo$stock==stock])
|
|
Btype <- as.character(cinfo$Btype[cinfo$stock==stock])
|
|
FutureCrash <- as.character(cinfo$FutureCrash[cinfo$stock==stock])
|
|
comment <- as.character(cinfo$comment[cinfo$stock==stock])
|
|
|
|
|
|
# extract data on stock
|
|
yr <- as.numeric(cdat$yr[cdat$stock==stock & cdat$yr >= StartYear & cdat$yr <= EndYear])
|
|
ct <- as.numeric(cdat$ct[cdat$stock==stock & cdat$yr >= StartYear & cdat$yr <= EndYear])/1000 ## assumes that catch is given in tonnes, transforms to '000 tonnes
|
|
if(Btype=="observed" | Btype=="CPUE" | Btype=="simulated") {
|
|
bt <- as.numeric(cdat$TB[cdat$stock==stock & cdat$yr >= StartYear & cdat$yr <= EndYear])/1000 ## assumes that biomass is in tonnes, transforms to '000 tonnes
|
|
} else {bt <- NA}
|
|
nyr <- length(yr) # number of years in the time series
|
|
|
|
|
|
if(Btype!="observed") {bio <- bt}
|
|
# change biomass to moving average as assumed by Schaefer (but not for simulations or CPUE)
|
|
# for last year use reported bio
|
|
if(Btype=="observed") {
|
|
ma <- function(x){filter(x,rep(1/2,2),sides=2)}
|
|
bio <- ma(bt)
|
|
bio[length(bio)] <- bt[length(bt)] }
|
|
|
|
# initialize vectors for viable r, k, bt
|
|
rv.all <- vector()
|
|
kv.all <- vector()
|
|
btv.all <- matrix(data=vector(),ncol=nyr+1)
|
|
|
|
|
|
|
|
#----------------------------------------------------
|
|
# Determine initial ranges for parameters and biomass
|
|
#----------------------------------------------------
|
|
# initial range of r from input file
|
|
if(is.na(r_low)==F & is.na(r_hi)==F) {
|
|
start_r <- c(r_low,r_hi)
|
|
} else {
|
|
# initial range of r and CatchMult values based on resilience
|
|
if(res == "High") {
|
|
start_r <- c(0.6,1.5)} else if(res == "Medium") {
|
|
start_r <- c(0.2,0.8)} else if(res == "Low") {
|
|
start_r <- c(0.05,0.5)} else { # i.e. res== "Very low"
|
|
start_r <- c(0.015,0.1)}
|
|
}
|
|
|
|
|
|
# initial range of k values, assuming k will always be larger than max catch
|
|
# and max catch will never be smaller than a quarter of MSY
|
|
|
|
start_k <- c(max(ct),16*max(ct)/start_r[1])
|
|
|
|
# initial biomass range from input file
|
|
if(is.na(stb_low)==F & is.na(stb_hi)==F) {
|
|
startbio <- c(stb_low,stb_hi)
|
|
} else {
|
|
# us low biomass at start as default
|
|
startbio <- c(0.1,0.5)
|
|
}
|
|
|
|
MinYear <- yr[which.min(ct)]
|
|
MaxYear <- yr[which.max(ct)]
|
|
# use year and biomass range for intermediate biomass from input file
|
|
if(is.na(intbio_low)==F & is.na(intbio_hi)==F) {
|
|
intyr <- intyr
|
|
intbio <- c(intbio_low,intbio_hi)
|
|
# else if year of minimum catch is at least 3 years away from StartYear and EndYear of series, use min catch
|
|
} else if((MinYear - StartYear) > 3 & (EndYear - MinYear) > 3 ) {
|
|
# assume that biomass range in year before minimum catch was 0.01 - 0.4
|
|
intyr <- MinYear-1
|
|
intbio <- c(0.01,0.4)
|
|
# else if year of max catch is at least 3 years away from StartYear and EndYear of series, use max catch
|
|
} else if((MaxYear - StartYear) > 3 & (EndYear - MaxYear) > 3 ) {
|
|
# assume that biomass range in year before maximum catch was 0.3 - 0.9
|
|
intyr <- MaxYear-1
|
|
intbio <- c(0.3,0.9)
|
|
} else {
|
|
# assume uninformative range 0-1 in mid-year
|
|
intyr <- as.integer(mean(c(StartYear, EndYear)))
|
|
intbio <- c(0,1) }
|
|
# end of intbio setting
|
|
|
|
# final biomass range from input file
|
|
if(is.na(endbio_low)==F & is.na(endbio_hi)==F) {
|
|
endbio <- c(endbio_low,endbio_hi)
|
|
} else {
|
|
# else use Catch/maxCatch to estimate final biomass
|
|
endbio <- if(ct[nyr]/max(ct) > 0.5) {c(0.4,0.8)} else {c(0.01,0.4)}
|
|
} # end of final biomass setting
|
|
|
|
|
|
#----------------------------------------------
|
|
# MC with Schaefer Function filtering
|
|
#----------------------------------------------
|
|
Schaefer <- function(ri, ki, startbio, intyr, intbio, endbio, sigR, pt) {
|
|
|
|
# if stock is not expected to crash within 3 years if last catch continues
|
|
if(FutureCrash == "No") {
|
|
yr.s <- c(yr,EndYear+1,EndYear+2,EndYear+3)
|
|
ct.s <- c(ct,ct[yr==EndYear],ct[yr==EndYear],ct[yr==EndYear])
|
|
nyr.s <- length(yr.s)
|
|
} else{
|
|
yr.s <- yr
|
|
ct.s <- ct
|
|
nyr.s <- nyr
|
|
}
|
|
|
|
# create vector for initial biomasses
|
|
startbt <-seq(from =startbio[1], to=startbio[2], by = (startbio[2]-startbio[1])/10)
|
|
# create vectors for viable r, k and bt
|
|
rv <- array(-1:-1,dim=c(length(ri)*length(startbt))) #initialize array with -1. The -1 remaining after the process will be removed
|
|
kv <- array(-1:-1,dim=c(length(ri)*length(startbt)))
|
|
btv <- matrix(data=NA, nrow = (length(ri)*length(startbt)), ncol = nyr+1)
|
|
intyr.i <- which(yr.s==intyr) # get index of intermediate year
|
|
|
|
#loop through r-k pairs
|
|
npoints = length(ri)
|
|
nstartb = length(startbt)
|
|
|
|
for(i in 1 : npoints) {
|
|
if (i%%1000==0)
|
|
cat(".")
|
|
|
|
# create empty vector for annual biomasses
|
|
bt <- vector()
|
|
|
|
# loop through range of relative start biomasses
|
|
for(j in startbt) {
|
|
# set initial biomass, including process error
|
|
bt[1]=j*ki[i]*exp(rnorm(1,0, sigR)) ## set biomass in first year
|
|
|
|
#loop through years in catch time series
|
|
for(t in 1:nyr.s) { # for all years in the time series
|
|
xt=rnorm(1,0, sigR) # set new random process error for every year
|
|
|
|
# calculate biomass as function of previous year's biomass plus surplus production minus catch
|
|
bt[t+1]=(bt[t]+ri[i]*bt[t]*(1-bt[t]/ki[i])-ct.s[t])*exp(xt)
|
|
|
|
# if biomass < 0.01 k or > 1.1 k, discard r-k pair
|
|
if(bt[t+1] < 0.01*ki[i] || bt[t+1] > 1.1*ki[i]) { break } # stop looping through years, go to next upper level
|
|
|
|
if ((t+1)==intyr.i && (bt[t+1]>(intbio[2]*ki[i]) || bt[t+1]<(intbio[1]*ki[i]))) { break } #intermediate year check
|
|
|
|
} # end of loop of years
|
|
|
|
# if last biomass falls without expected ranges goto next r-k pair
|
|
if(t < nyr.s || bt[yr.s==EndYear] > (endbio[2]*ki[i]) || bt[yr.s==EndYear] < (endbio[1]*ki[i])) {
|
|
next } else {
|
|
# store r, k, and bt, plot point, then go to next startbt
|
|
rv[((i-1)*nstartb)+j] <- ri[i]
|
|
kv[((i-1)*nstartb)+j] <- ki[i]
|
|
btv[((i-1)*nstartb)+j,] <- bt[1:(nyr+1)]/ki[i] #substitute a row into the matrix, exclude FutureCrash years
|
|
if(pt==T) {points(x=ri[i], y=ki[i], pch=".", cex=2, col="black")
|
|
next }
|
|
}
|
|
} # end of loop of initial biomasses
|
|
} # end of loop of r-k pairs
|
|
|
|
rv=rv[rv!=-1]
|
|
kv=kv[kv!=-1]
|
|
btv=na.omit(btv) #delete first line
|
|
|
|
cat("\n")
|
|
return(list(rv, kv,btv))
|
|
} # end of Schaefer function
|
|
|
|
#------------------------------------------------------------------
|
|
# Uniform sampling of the r-k space
|
|
#------------------------------------------------------------------
|
|
# get random set of r and k from log space distribution
|
|
ri1 = exp(runif(n, log(start_r[1]), log(start_r[2])))
|
|
ki1 = exp(runif(n, log(start_k[1]), log(start_k[2])))
|
|
|
|
#-----------------------------------------------------------------
|
|
# Plot data and progress
|
|
#-----------------------------------------------------------------
|
|
#windows(14,9)
|
|
par(mfcol=c(2,3))
|
|
# plot catch
|
|
plot(x=yr, y=ct, ylim=c(0,1.2*max(ct)), type ="l", bty="l", main=paste(stock,"catch"), xlab="Year",
|
|
ylab="Catch", lwd=2)
|
|
points(x=yr[which.max(ct)], y=max(ct), col="red", lwd=2)
|
|
points(x=yr[which.min(ct)], y=min(ct), col="red", lwd=2)
|
|
|
|
# plot r-k graph
|
|
plot(ri1, ki1, xlim = start_r, ylim = start_k, log="xy", xlab="r", ylab="k", main="Finding viable r-k", pch=".", cex=2, bty="l", col="lightgrey")
|
|
|
|
#1 - Call MC-Schaefer function to preliminary explore the space without prior information
|
|
cat(stock, ": First Monte Carlo filtering of r-k space with ",n," points\n")
|
|
MCA <- Schaefer(ri=ri1, ki=ki1, startbio=startbio, intyr=intyr, intbio=intbio, endbio=endbio, sigR=sigR, pt=T)
|
|
rv.all <- append(rv.all,MCA[[1]])
|
|
kv.all <- append(kv.all,MCA[[2]])
|
|
btv.all <- rbind(btv.all,MCA[[3]])
|
|
#take viable r and k values
|
|
nviablepoints = length(rv.all)
|
|
cat("* Found ",nviablepoints," viable points from ",n," samples\n");
|
|
|
|
|
|
#if few points were found then resample and shrink the k log space
|
|
if (nviablepoints<=1000){
|
|
log.start_k.new <- log(start_k)
|
|
max_attempts = 3
|
|
current_attempts = 1
|
|
while (nviablepoints<=1000 && current_attempts<=max_attempts){
|
|
if(nviablepoints > 0) {
|
|
log.start_k.new[1] <- mean(c(log.start_k.new[1], min(log(kv.all))))
|
|
log.start_k.new[2] <- mean(c(log.start_k.new[2], max(log(kv.all)))) }
|
|
n.new=n*current_attempts #add more points
|
|
ri1 = exp(runif(n.new, log(start_r[1]), log(start_r[2])))
|
|
ki1 = exp(runif(n.new, log.start_k.new[1], log.start_k.new[2]))
|
|
cat("Shrinking k space: repeating Monte Carlo in the interval [",exp(log.start_k.new[1]),",",exp(log.start_k.new[2]),"]\n")
|
|
cat("Attempt ",current_attempts," of ",max_attempts," with ",n.new," points","\n")
|
|
MCA <- Schaefer(ri=ri1, ki=ki1, startbio=startbio, intyr=intyr, intbio=intbio, endbio=endbio, sigR=sigR, pt=T)
|
|
rv.all <- append(rv.all,MCA[[1]])
|
|
kv.all <- append(kv.all,MCA[[2]])
|
|
btv.all <- rbind(btv.all,MCA[[3]])
|
|
nviablepoints = length(rv.all) #recalculate viable points
|
|
cat("* Found altogether",nviablepoints," viable points \n");
|
|
current_attempts=current_attempts+1 #increment the number of attempts
|
|
}
|
|
}
|
|
|
|
# If tip of viable r-k pairs is 'thin', do extra sampling there
|
|
gm.rv = exp(mean(log(rv.all)))
|
|
if(length(rv.all[rv.all > 0.9*start_r[2]]) < 10) {
|
|
l.sample.r <- (gm.rv + max(rv.all))/2
|
|
cat("Final sampling in the tip area above r =",l.sample.r,"\n")
|
|
log.start_k.new <- c(log(0.8*min(kv.all)),log(max(kv.all[rv.all > l.sample.r])))
|
|
ri1 = exp(runif(50000, log(l.sample.r), log(start_r[2])))
|
|
ki1 = exp(runif(50000, log.start_k.new[1], log.start_k.new[2]))
|
|
MCA <- Schaefer(ri=ri1, ki=ki1, startbio=startbio, intyr=intyr, intbio=intbio, endbio=endbio, sigR=sigR, pt=T)
|
|
rv.all <- append(rv.all,MCA[[1]])
|
|
kv.all <- append(kv.all,MCA[[2]])
|
|
btv.all <- rbind(btv.all,MCA[[3]])
|
|
nviablepoints = length(rv.all) #recalculate viable points
|
|
cat("Found altogether", length(rv.all), "unique viable r-k pairs and biomass trajectories\n")
|
|
}
|
|
|
|
|
|
# ------------------------------------------------------------
|
|
# Bayesian analysis of catch & biomass with Schaefer model
|
|
# ------------------------------------------------------------
|
|
if(Btype == "observed" | Btype=="simulated") {
|
|
cat("Running Schaefer MCMC analysis....\n")
|
|
mcmc.burn <- as.integer(30000)
|
|
mcmc.chainLength <- as.integer(60000) # burn-in plus post-burn
|
|
mcmc.thin = 10 # to reduce autocorrelation
|
|
mcmc.chains = 3 # needs to be at least 2 for DIC
|
|
|
|
# Parameters to be returned by JAGS
|
|
jags.save.params=c('r','k','sigma.b', 'alpha', 'sigma.r') #
|
|
|
|
# JAGS model
|
|
Model = "model{
|
|
# to avoid crash due to 0 values
|
|
eps<-0.01
|
|
# set a quite narrow variation from the expected value
|
|
sigma.b <- 1/16
|
|
tau.b <- pow(sigma.b,-2)
|
|
|
|
Bm[1] <- log(alpha*k)
|
|
bio[1] ~ dlnorm(Bm[1],tau.b)
|
|
|
|
|
|
for (t in 2:nyr){
|
|
bio[t] ~ dlnorm(Bm[t],tau.b)
|
|
Bm[t] <- log(max(bio[t-1] + r*bio[t-1]*(1 - (bio[t-1])/k) - ct[t-1], eps))
|
|
}
|
|
|
|
# priors
|
|
alpha ~ dunif(0.01,1) # needed for fit of first biomass
|
|
#inverse cubic root relationship between the range of viable r and the size of the search space
|
|
inverseRangeFactor <- 1/((start_r[2]-start_r[1])^1/3)
|
|
|
|
# give sigma some variability in the inverse relationship
|
|
sigma.r ~ dunif(0.001*inverseRangeFactor,0.02*inverseRangeFactor)
|
|
tau.r <- pow(sigma.r,-2)
|
|
rm <- log((start_r[1]+start_r[2])/2)
|
|
r ~ dlnorm(rm,tau.r)
|
|
|
|
# search in the k space from the center of the range. Allow high variability
|
|
km <- log((start_k[1]+start_k[2])/2)
|
|
tau.k <- pow(km,-2)
|
|
k ~ dlnorm(km,tau.k)
|
|
|
|
#end model
|
|
}"
|
|
|
|
# Write JAGS model to file
|
|
cat(Model, file="r2jags.bug")
|
|
|
|
### random seed
|
|
set.seed(runif(1,1,500)) # needed in JAGS
|
|
|
|
### run model
|
|
jags_outputs <- jags(data=c('ct','bio','nyr', 'start_r', 'start_k'),
|
|
working.directory=NULL, inits=NULL,
|
|
parameters.to.save= jags.save.params,
|
|
model.file="r2jags.bug", n.chains = mcmc.chains,
|
|
n.burnin = mcmc.burn, n.thin = mcmc.thin, n.iter = mcmc.chainLength,
|
|
refresh=mcmc.burn/20, )
|
|
|
|
# ------------------------------------------------------
|
|
# Results from JAGS Schaefer
|
|
# ------------------------------------------------------
|
|
r_out <- as.numeric(mcmc(jags_outputs$BUGSoutput$sims.list$r))
|
|
k_out <- as.numeric(mcmc(jags_outputs$BUGSoutput$sims.list$k))
|
|
## sigma_out <- as.numeric(mcmc(jags_outputs$BUGSoutput$sims.list$sigma.b))
|
|
alpha_out <- as.numeric(mcmc(jags_outputs$BUGSoutput$sims.list$alpha))
|
|
## sigma.r_out <- as.numeric(mcmc(jags_outputs$BUGSoutput$sims.list$sigma.r))
|
|
|
|
mean.log.r.jags <- mean(log(r_out))
|
|
SD.log.r.jags <- sd(log(r_out))
|
|
lcl.log.r.jags <- mean.log.r.jags-1.96*SD.log.r.jags
|
|
ucl.log.r.jags <- mean.log.r.jags+1.96*SD.log.r.jags
|
|
gm.r.jags <- exp(mean.log.r.jags)
|
|
lcl.r.jags <- exp(lcl.log.r.jags)
|
|
ucl.r.jags <- exp(ucl.log.r.jags)
|
|
mean.log.k.jags <- mean(log(k_out))
|
|
SD.log.k.jags <- sd(log(k_out))
|
|
lcl.log.k.jags <- mean.log.k.jags-1.96*SD.log.k.jags
|
|
ucl.log.k.jags <- mean.log.k.jags+1.96*SD.log.k.jags
|
|
gm.k.jags <- exp(mean.log.k.jags)
|
|
lcl.k.jags <- exp(lcl.log.k.jags)
|
|
ucl.k.jags <- exp(ucl.log.k.jags)
|
|
mean.log.MSY.jags<- mean(log(r_out)+log(k_out)-log(4))
|
|
SD.log.MSY.jags <- sd(log(r_out)+log(k_out)-log(4))
|
|
gm.MSY.jags <- exp(mean.log.MSY.jags)
|
|
lcl.MSY.jags <- exp(mean.log.MSY.jags-1.96*SD.log.MSY.jags)
|
|
ucl.MSY.jags <- exp(mean.log.MSY.jags+1.96*SD.log.MSY.jags)
|
|
|
|
} # end of MCMC Schaefer loop
|
|
|
|
#------------------------------------
|
|
# get results from CMSY
|
|
#------------------------------------
|
|
# get estimate of most probable r as median of mid log.r-classes above cut-off
|
|
# get remaining viable log.r and log.k
|
|
rem.log.r <- log(rv.all[rv.all > gm.rv])
|
|
rem.log.k <- log(kv.all[rv.all>gm.rv])
|
|
# get vectors with numbers of r and mid values in about 25 classes
|
|
hist.log.r <- hist(x=rem.log.r, breaks=25, plot=F)
|
|
log.r.counts <- hist.log.r$counts
|
|
log.r.mids <- hist.log.r$mids
|
|
# get most probable log.r as mean of mids with counts > 0
|
|
log.r.est <- median(log.r.mids[which(log.r.counts > 0)])
|
|
lcl.log.r <- as.numeric(quantile(x=log.r.mids[which(log.r.counts > 0)], 0.025))
|
|
ucl.log.r <- as.numeric(quantile(x=log.r.mids[which(log.r.counts > 0)], 0.975))
|
|
r.est <- exp(log.r.est)
|
|
lcl.r.est <- exp(lcl.log.r)
|
|
ucl.r.est <- exp(ucl.log.r)
|
|
|
|
# do linear regression of log k ~ log r with slope fixed to -1 (from Schaefer)
|
|
reg <- lm(rem.log.k ~ 1 + offset(-1*rem.log.r))
|
|
int.reg <- as.numeric(reg[1])
|
|
sd.reg <- sd(resid(reg))
|
|
se.reg <- summary(reg)$coefficients[2]
|
|
# get estimate of log(k) from y where x = log.r.est
|
|
log.k.est <- int.reg + (-1) * log.r.est
|
|
# get estimates of CL of log.k.est from y +/- SD where x = lcl.log r or ucl.log.r
|
|
lcl.log.k <- int.reg + (-1) * ucl.log.r - sd.reg
|
|
ucl.log.k <- int.reg + (-1) * lcl.log.r + sd.reg
|
|
k.est <- exp(log.k.est)
|
|
lcl.k.est <- exp(lcl.log.k)
|
|
ucl.k.est <- exp(ucl.log.k)
|
|
|
|
# get MSY from remaining log r-k pairs
|
|
log.MSY.est <- mean(rem.log.r + rem.log.k - log(4))
|
|
sd.log.MSY.est <- sd(rem.log.r + rem.log.k - log(4))
|
|
lcl.log.MSY.est <- log.MSY.est - 1.96*sd.log.MSY.est
|
|
ucl.log.MSY.est <- log.MSY.est + 1.96*sd.log.MSY.est
|
|
MSY.est <- exp(log.MSY.est)
|
|
lcl.MSY.est <- exp(lcl.log.MSY.est)
|
|
ucl.MSY.est <- exp(ucl.log.MSY.est)
|
|
|
|
# get predicted biomass vectors as median and quantiles of trajectories
|
|
median.btv <- apply(btv.all,2, median)
|
|
lastyr.bio <- median.btv[length(median.btv)-1]
|
|
nextyr.bio <- median.btv[length(median.btv)]
|
|
lcl.btv <- apply(btv.all,2, quantile, probs=0.025)
|
|
q.btv <- apply(btv.all,2, quantile, probs=0.25)
|
|
ucl.btv <- apply(btv.all,2, quantile, probs=0.975)
|
|
lcl.lastyr.bio <- lcl.btv[length(lcl.btv)-1]
|
|
ucl.lastyr.bio <- ucl.btv[length(lcl.btv)-1]
|
|
lcl.nextyr.bio <- lcl.btv[length(lcl.btv)]
|
|
ucl.nextyr.bio <- ucl.btv[length(lcl.btv)]
|
|
|
|
# -----------------------------------------
|
|
# Plot results
|
|
# -----------------------------------------
|
|
# Analysis of viable r-k pairs
|
|
plot(x=rv.all, y=kv.all, xlim=start_r,
|
|
ylim=c(0.9*min(kv.all, ifelse(Btype == "observed",k_out,NA), na.rm=T), 1.1*max(kv.all)),
|
|
pch=16, col="grey",log="xy", bty="l",
|
|
xlab="r", ylab="k", main="Analysis of viable r-k")
|
|
abline(v=gm.rv, lty="dashed")
|
|
|
|
# plot points and best estimate from full Schaefer analysis
|
|
if(Btype == "observed"|Btype=="simulated") {
|
|
# plot r-k pairs from MCMC
|
|
points(x=r_out, y=k_out, pch=16,cex=0.5)
|
|
# plot best r-k pair from MCMC
|
|
points(x=gm.r.jags, y=gm.k.jags, pch=19, col="green")
|
|
lines(x=c(lcl.r.jags, ucl.r.jags),y=c(gm.k.jags,gm.k.jags), col="green")
|
|
lines(x=c(gm.r.jags,gm.r.jags),y=c(lcl.k.jags, ucl.k.jags), col="green")
|
|
}
|
|
|
|
# if data are from simulation, plot true r and k
|
|
if(Btype=="simulated") {
|
|
l.stock <- nchar(stock) # get length of sim stock name
|
|
r.char <- substr(stock,l.stock-1,l.stock) # get last character of sim stock name
|
|
r.sim <- NA # initialize vector for r used in simulation
|
|
if(r.char=="_H") {r.sim=1; lcl.r.sim=0.8; ucl.r.sim=1.25} else
|
|
if(r.char=="_M") {r.sim=0.5;lcl.r.sim=0.4;ucl.r.sim=0.62} else
|
|
if(r.char=="_L") {r.sim=0.25;lcl.r.sim=0.2;ucl.r.sim=0.31} else {r.sim=0.05;lcl.r.sim=0.04;ucl.r.sim=0.062}
|
|
# plot true r-k point with error bars
|
|
points(x=r.sim, y=1000, pch=19, col="red")
|
|
# add +/- 20% error bars
|
|
lines(x=c(lcl.r.sim,ucl.r.sim), y=c(1000,1000), col="red")
|
|
lines(x=c(r.sim,r.sim), y=c(800,1250), col="red")
|
|
}
|
|
|
|
# plot blue dot for proposed r-k, with 95% CL lines
|
|
points(x=r.est, y=k.est, pch=19, col="blue")
|
|
lines(x=c(lcl.r.est, ucl.r.est),y=c(k.est,k.est), col="blue")
|
|
lines(x=c(r.est,r.est),y=c(lcl.k.est, ucl.k.est), col="blue")
|
|
|
|
# plot biomass graph
|
|
# determine k to use for red line in b/k plot
|
|
if(Btype=="simulated") {k2use <- 1000} else
|
|
if(Btype == "observed") {k2use <- gm.k.jags} else {k2use <- k.est}
|
|
# determine hight of y-axis in plot
|
|
max.y <- max(c(bio/k2use,ucl.btv,0.6,startbio[2], intbio[2],endbio[2]),na.rm=T)
|
|
|
|
plot(x=yr,y=median.btv[1:nyr], lwd=2, xlab="Year", ylab="Relative biomass b/k", type="l",
|
|
ylim=c(0,max.y), bty="l", main=paste("Pred. biomass vs ", Btype,sep=""))
|
|
lines(x=yr, y=lcl.btv[1:nyr],type="l")
|
|
lines(x=yr, y=ucl.btv[1:nyr],type="l")
|
|
points(x=EndYear,y=q.btv[yr==EndYear], col="purple", cex=1.5, lwd=2)
|
|
abline(h=0.5, lty="dashed")
|
|
abline(h=0.25, lty="dotted")
|
|
lines(x=c(yr[1],yr[1]), y=startbio, col="blue")
|
|
lines(x=c(intyr,intyr), y=intbio, col="blue")
|
|
lines(x=c(max(yr),max(yr)), y=endbio, col="blue")
|
|
|
|
# if observed biomass is available, plot red biomass line
|
|
if(Btype == "observed"|Btype=="simulated") {
|
|
lines(x=yr, y=bio/k2use,type="l", col="red", lwd=1)
|
|
}
|
|
|
|
# if CPUE data are available, scale to predicted biomass range, plot red biomass line
|
|
if(Btype == "CPUE") {
|
|
par(new=T) # prepares for new plot on top of previous
|
|
plot(x=yr, y=bio, type="l", col="red", lwd=1,
|
|
ann=F,axes=F,ylim=c(0,1.2*max(bio, na.rm=T))) # forces this plot on top of previous one
|
|
axis(4, col="red", col.axis="red")
|
|
}
|
|
|
|
# plot yield and biomass against equilibrium surplus parabola
|
|
max.y <-max(c(ct/MSY.est,ifelse(Btype=="observed"|Btype=="simulated",ct/gm.MSY.jags,NA),1.2),na.rm=T)
|
|
# plot parabola
|
|
x=seq(from=0,to=2,by=0.001)
|
|
y=4*x-(2*x)^2
|
|
plot(x=x, y=y, xlim=c(0,1), ylim=c(0,max.y), type="l", bty="l",xlab="Relative biomass b/k",
|
|
ylab="Catch / MSY", main="Equilibrium curve")
|
|
# plot catch against CMSY biomass estimates
|
|
points(x=median.btv[1:nyr], y=ct/MSY.est, pch=16, col="grey")
|
|
points(x=q.btv[yr==EndYear],y=ct[yr==EndYear]/MSY.est, col="purple", cex=1.5, lwd=2)
|
|
# plot catch against observed biomass or CPUE
|
|
if(Btype == "observed"|Btype=="simulated") {
|
|
points(x=bio/k2use, y=ct/gm.MSY.jags, pch=16, cex=0.5)
|
|
}
|
|
|
|
# plot exploitation rate u against u.msy
|
|
# get u derived from predicted CMSY biomass
|
|
u.CMSY <- ct/(median.btv[1:nyr]*k.est)
|
|
u.msy.CMSY <- 1-exp(-r.est/2) # # Fmsy from CMSY expressed as exploitation rate
|
|
# get u from observed or simulated biomass
|
|
if(Btype == "observed"|Btype=="simulated") {
|
|
u.bio <- ct/bio
|
|
u.msy.bio <- 1-exp(-gm.r.jags/2)
|
|
}
|
|
# get u from CPUE
|
|
if(Btype == "CPUE") {
|
|
q=max(median.btv[1:nyr][is.na(bio)==F],na.rm=T)*k.est/max(bio,na.rm=T)
|
|
u.CPUE <- ct/(q*bio)
|
|
}
|
|
|
|
# determine upper bound of Y-axis
|
|
max.y <- max(c(1.5, 1.2*u.CMSY/u.msy.CMSY,ct[yr==EndYear]/(q.btv[yr==EndYear]*k.est)/u.msy.CMSY,
|
|
ifelse(Btype=="observed"|Btype=="simulated",max(u.bio[is.na(u.bio)==F]/u.msy.bio),0),
|
|
na.rm=T))
|
|
# plot u from CMSY
|
|
plot(x=yr,y=u.CMSY/u.msy.CMSY, type="l", bty="l", ylim=c(0,max.y), xlab="Year",
|
|
ylab="u / u_msy", main="Exploitation rate")
|
|
abline(h=1, lty="dashed")
|
|
points(x=EndYear,y=ct[yr==EndYear]/(q.btv[yr==EndYear]*k.est)/u.msy.CMSY, col="purple", cex=1.5, lwd=2)
|
|
# plot u from biomass
|
|
if(Btype == "observed"|Btype=="simulated") lines(x=yr, y=u.bio/u.msy.bio, col="red")
|
|
# plot u from CPUE
|
|
if(Btype == "CPUE") {
|
|
par(new=T) # prepares for new plot on top of previous
|
|
plot(x=yr, y=u.CPUE, type="l", col="red", ylim=c(0, 1.2*max(u.CPUE,na.rm=T)),ann=F,axes=F)
|
|
axis(4, col="red", col.axis="red")
|
|
}
|
|
if(batch.mode == TRUE) {dev.off()} # close plot window
|
|
|
|
# ------------------------------------------
|
|
# print input and results to screen
|
|
cat("---------------------------------------\n")
|
|
|
|
cat("Species:", cinfo$ScientificName[cinfo$stock==stock], "\n")
|
|
cat("Name and region:", cinfo$EnglishName[cinfo$stock==stock], ",", cinfo$Name[cinfo$stock==stock], "\n")
|
|
cat("Stock:",stock,"\n")
|
|
cat("Catch data used from years", min(yr),"-", max(yr), "\n")
|
|
cat("Prior initial relative biomass =", startbio[1], "-", startbio[2], "\n")
|
|
cat("Prior intermediate rel. biomass=", intbio[1], "-", intbio[2], "in year", intyr, "\n")
|
|
cat("Prior final relative biomass =", endbio[1], "-", endbio[2], "\n")
|
|
cat("If current catches continue, is the stock likely to crash within 3 years?",FutureCrash,"\n")
|
|
cat("Prior range for r =", format(start_r[1],digits=2), "-", format(start_r[2],digits=2),
|
|
", prior range for k =", start_k[1], "-", start_k[2],"\n")
|
|
|
|
# if data are simulated, print true r-k
|
|
if(filename_1=="SimCatch.csv") {
|
|
cat("True r =", r.sim, "(because input data were simulated with Schaefer model)\n")
|
|
cat("True k = 1000 \n")
|
|
cat("True MSY =", 1000*r.sim/4,"\n")
|
|
cat("True biomass in last year =",bio[length(bio)],"or",bio[length(bio)]/1000,"k \n")
|
|
cat("True mean catch / MSY ratio =", mean(ct)/(1000*r.sim/4),"\n")
|
|
}
|
|
# print results from full Schaefer if available
|
|
if(Btype == "observed"|Btype=="simulated") {
|
|
cat("Results from Bayesian Schaefer model using catch & biomass (",Btype,")\n")
|
|
cat("MSY =", gm.MSY.jags,", 95% CL =", lcl.MSY.jags, "-", ucl.MSY.jags,"\n")
|
|
cat("Mean catch / MSY =", mean(ct)/gm.MSY.jags,"\n")
|
|
if(Btype != "CPUE") {
|
|
cat("r =", gm.r.jags,", 95% CL =", lcl.r.jags, "-", ucl.r.jags,"\n")
|
|
cat("k =", gm.k.jags,", 95% CL =", lcl.k.jags, "-", ucl.k.jags,"\n")
|
|
}
|
|
}
|
|
# results of CMSY analysis
|
|
cat("Results of CMSY analysis \n")
|
|
cat("Altogether", nviablepoints,"unique viable r-k pairs were found \n")
|
|
cat(nviablepoints-length(rem.log.r),"r-k pairs above the initial geometric mean of r =", gm.rv, "were analysed\n")
|
|
cat("r =", r.est,", 95% CL =", lcl.r.est, "-", ucl.r.est,"\n")
|
|
cat("k =", k.est,", 95% CL =", lcl.k.est, "-", ucl.k.est,"\n")
|
|
cat("MSY =", MSY.est,", 95% CL =", lcl.MSY.est, "-", ucl.MSY.est,"\n")
|
|
cat("Predicted biomass in last year =", lastyr.bio, "2.5th perc =", lcl.lastyr.bio,
|
|
"97.5th perc =", ucl.lastyr.bio,"\n")
|
|
cat("Predicted biomass in next year =", nextyr.bio, "2.5th perc =", lcl.nextyr.bio,
|
|
"97.5th perc =", ucl.nextyr.bio,"\n")
|
|
cat("----------------------------------------------------------\n")
|
|
|
|
## Write some results into outfile
|
|
if(write.output == TRUE) {
|
|
# write data into csv file
|
|
output = data.frame(cinfo$ScientificName[cinfo$stock==stock], stock, StartYear, EndYear, mean(ct)*1000,
|
|
ifelse(Btype=="observed"|Btype=="simulate",bio[length(bio)],NA), # last biomass on record
|
|
ifelse(Btype == "observed"|Btype=="simulated",gm.MSY.jags,NA), # full Schaefer
|
|
ifelse(Btype == "observed"|Btype=="simulated",lcl.MSY.jags,NA),
|
|
ifelse(Btype == "observed"|Btype=="simulated",ucl.MSY.jags,NA),
|
|
ifelse(Btype == "observed"|Btype=="simulated",gm.r.jags,NA),
|
|
ifelse(Btype == "observed"|Btype=="simulated",lcl.r.jags,NA),
|
|
ifelse(Btype == "observed"|Btype=="simulated",ucl.r.jags,NA),
|
|
ifelse(Btype == "observed"|Btype=="simulated",gm.k.jags,NA),
|
|
ifelse(Btype == "observed"|Btype=="simulated",lcl.k.jags,NA),
|
|
ifelse(Btype == "observed"|Btype=="simulated",ucl.k.jags,NA),
|
|
r.est, lcl.r.est, ucl.r.est, # CMSY r
|
|
k.est, lcl.k.est, ucl.k.est, # CMSY k
|
|
MSY.est, lcl.MSY.est, ucl.MSY.est, # CMSY r
|
|
lastyr.bio, lcl.lastyr.bio, ucl.lastyr.bio, # last year bio
|
|
nextyr.bio, lcl.nextyr.bio, ucl.nextyr.bio)# last year + 1 bio
|
|
|
|
write.table(output, file=outfile, append = T, sep = ",",
|
|
dec = ".", row.names = FALSE, col.names = FALSE)
|
|
|
|
# write some text into text outfile.txt
|
|
|
|
cat("Species:", cinfo$ScientificName[cinfo$stock==stock], "\n",
|
|
"Name:", cinfo$EnglishName[cinfo$stock==stock], "\n",
|
|
"Region:", cinfo$Name[cinfo$stock==stock], "\n",
|
|
"Stock:",stock,"\n",
|
|
"Catch data used from years", min(yr),"-", max(yr),", biomass =", Btype, "\n",
|
|
"Prior initial relative biomass =", startbio[1], "-", startbio[2], "\n",
|
|
"Prior intermediate rel. biomass=", intbio[1], "-", intbio[2], "in year", intyr, "\n",
|
|
"Prior final relative biomass =", endbio[1], "-", endbio[2], "\n",
|
|
"Future crash with current catches?", FutureCrash, "\n",
|
|
"Prior range for r =", format(start_r[1],digits=2), "-", format(start_r[2],digits=2),
|
|
", prior range for k =", start_k[1], "-", start_k[2],"\n",
|
|
file=outfile.txt,append=T)
|
|
|
|
if(filename_1=="SimCatch.csv") {
|
|
cat(" True r =", r.sim, "(because input data were simulated with Schaefer model)\n",
|
|
"True k = 1000, true MSY =", 1000*r.sim/4,"\n",
|
|
"True biomass in last year =",bio[length(bio)],"or",bio[length(bio)]/1000,"k \n",
|
|
"True mean catch / MSY ratio =", mean(ct)/(1000*r.sim/4),"\n",
|
|
file=outfile.txt,append=T)
|
|
}
|
|
if(Btype == "observed"|Btype=="simulated") {
|
|
cat(" Results from Bayesian Schaefer model using catch & biomass \n",
|
|
"r =", gm.r.jags,", 95% CL =", lcl.r.jags, "-", ucl.r.jags,"\n",
|
|
"k =", gm.k.jags,", 95% CL =", lcl.k.jags, "-", ucl.k.jags,"\n",
|
|
"MSY =", gm.MSY.jags,", 95% CL =", lcl.MSY.jags, "-", ucl.MSY.jags,"\n",
|
|
"Mean catch / MSY =", mean(ct)/gm.MSY.jags,"\n",
|
|
file=outfile.txt,append=T)
|
|
}
|
|
cat(" Results of CMSY analysis with altogether", nviablepoints,"unique viable r-k pairs \n",
|
|
nviablepoints-length(rem.log.r),"r-k pairs above the initial geometric mean of r =", gm.rv, "were analysed\n",
|
|
"r =", r.est,", 95% CL =", lcl.r.est, "-", ucl.r.est,"\n",
|
|
"k =", k.est,", 95% CL =", lcl.k.est, "-", ucl.k.est,"\n",
|
|
"MSY =", MSY.est,", 95% CL =", lcl.MSY.est, "-", ucl.MSY.est,"\n",
|
|
"Predicted biomass last year b/k =", lastyr.bio, "2.5th perc b/k =", lcl.lastyr.bio,
|
|
"97.5th perc b/k =", ucl.lastyr.bio,"\n",
|
|
"Precautionary 25th percentile b/k =",q.btv[yr==EndYear],"\n",
|
|
"----------------------------------------------------------\n",
|
|
file=outfile.txt,append=T)
|
|
|
|
}
|
|
|
|
} # end of stocks loop
|