Nothing
#' @title altnegLL calculate the Normal negative log-likelihood
#'
#' @description altnegLL calculates negLLM using the simplification
#' from Haddon (2011) using the ssq calculated within the function
#' spm
#'
#' @param inp a vector of model parameters (r,K,Binit)
#' @param indat a matrix with at least columns 'year', 'catch', and
#' 'cpue'
#'
#' @return a single value, the negative log-likelihood
#' @export
#'
#' @examples
#' data(dataspm)
#' pars <- log(c(r=0.2,K=6000,Binit=2800,sigma=0.2))
#' ans <- fitSPM(pars,fish=dataspm,schaefer=TRUE,maxiter=1000)
#' outfit(ans)
#' altnegLL(ans$estimate,dataspm) # should be -12.12879
altnegLL <- function(inp,indat) { # inp=pars; indat=dataspm
out <- spm(inp,indat)$outmat
pick <- which(indat[,"cpue"] > 0)
Nobs <- length(pick)
ssq <- sum((log(out[pick,"CPUE"])-log(out[pick,"predCE"]))^2)
sigma <- sqrt(ssq/Nobs)
negLogL <- (Nobs/2)*(log(2*pi) + 2*log(sigma) + 1)
return(negLogL)
} # end of altnegLL
#' @title fitSPM fits a surplus production model
#'
#' @description fitSPM fits a surplus production model (either Schaefer or
#' Fox) by first applying optim (using Nelder-Mead) and then nlm. Being
#' automated it is recommended that this only be used once plausible
#' initial parameters have been identified (through rules of thumb or
#' trial and error). It uses negLL1 to apply a negative log-likelihood,
#' assuming log-normal residual errors and uses a penalty to prevent
#' the first parameter (r) from becoming < 0.0. If that is not wanted then
#' set funkone to FALSE, which would then use negLL by itself.
#' The output object is the usual object output from nlm, which can
#' be neatly printed using the MQMF function outfit.
#' The $estimate values can be used in plotspmmod to plot the
#' outcome, or in spmboot to conduct bootstrap sampling of the residuals
#' from the CPUE model fit, to gain an appreciation of any uncertainty
#' in the analysis. Because it requires log(parameters) it does not
#' use the magnitude function to set the values of the parscale
#' parameters.
#'
#' @param pars the initial parameter values to start the search for the
#' optimum. These need to be on the log-scale (log-transformed)
#' @param fish the matrix containing the fishery data 'year', 'catch', and
#' 'cpue' as a minimum. These exact column names are required.
#' @param schaefer if TRUE, the default, then simpspm is used to fit the
#' Schaefer model. If FALSE then the approximate Fox model is fitted
#' by setting the p parameter to 1e-08 inside simpspm.
#' @param maxiter the maximum number of iterations to be used by nlm
#' @param funk the function used to generate the predicted cpue
#' @param funkone default = TRUE. Means use negLL1, which constrains the
#' first parameter (r) to be greater than 0. If FALSE then use negLL
#' which is identical to negLL1 but lacks the constraint.
#' @param hess default is FALSE; should one calculate the hessian matrix?
#' @param steptol the internal step tolerance, required in case nlm reports
#' the steptol as being too small. defaults to 1e-06
#'
#' @return an nlm output object as a list
#' @export
#'
#' @examples
#' data(dataspm)
#' dataspm <- as.matrix(dataspm) # faster than a data.frame
#' pars <- log(c(r=0.2,K=6000,Binit=2800,sigma=0.2))
#' ans <- fitSPM(pars,fish=dataspm,schaefer=TRUE,maxiter=1000)
#' outfit(ans) # Schaefer model -12.12879
#' ansF <- fitSPM(pars,dataspm,schaefer=FALSE,maxiter=1000)
#' outfit(ansF) # Fox model -12.35283
fitSPM <- function(pars,fish,schaefer=TRUE,maxiter=1000,
funk=simpspm,funkone=TRUE,hess=FALSE,steptol=1e-06) {
if (funkone) minim=negLL1 else minim=negLL
best <- optim(par=pars,fn=minim,funk=funk,indat=fish,schaefer=schaefer,
logobs=log(fish[,"cpue"]),method="Nelder-Mead",
control=list(maxit=maxiter))
best2 <- nlm(f=minim,p=best$par,funk=funk,indat=fish,schaefer=schaefer,
logobs=log(fish[,"cpue"]),steptol=steptol,
iterlim=maxiter,hessian=hess)
return(best2)
} # end of fitSPM
#' @title getlag is used to look for the response of cpue to previous catches
#'
#' @description getlag is a wrapper for the ccf function (cross correlation)
#' that is used within the spm analyses to determine at what
#' negative lag, if any, cpue data is informative about the stock
#' dynamics beyond any information already available in the catch data.
#' If the cpue is directly correlated with catches (lag=0 has a strong
#' correlation) then cpue will not add much more information to an
#' analysis. Only if there is a significant negative correlation is it
#' likely that the cpue will increase the information available and
#' make it more likely that an assessment model may be able to be fitted
#' meaningfully to the available data. If there is no significant
#' negative correlations then it becomes much more unlikely that a
#' useful model fit to the cpue will be possible. The getlag function
#' first finds those rows for which both catch and cpue have values
#' and then it runs the cross-correlation analysis. Thus, you cannot
#' have gaps in your cpue data although there can be catches at the
#' start or end of the time-series, or both, for which there are no
#' cpue data.
#'
#' @param fish the matrix or data.frame containing the fishery data
#' (year, catch, and cpue)
#' @param maxlag the lag.max parameter for the ccf function; defaults to 10
#' @param plotout should a plot be made; default=TRUE. If FALSE then,
#' assuming the result of the analysis is put into an object called
#' 'ans' a call to plot(ans) will generate the required plot.
#' @param indexI if there are more than one time-series of cpue/indices then
#' this parameter selects which to use
#'
#' @return an object of class acf, which can be plotted
#' @export
#'
#' @examples
#' year <- 1985:2008
#' catch <- c(1018,742,868,715,585,532,566,611,548,499,479,428,657,481,
#' 645,961,940,912,955,935,940,952,1030,985)
#' cpue <- c(0.6008,0.6583,0.6791,0.6889,0.7134,0.7221,0.7602,0.7931,0.8582,
#' 0.8876,1.0126,1.1533,1.2326,1.2764,1.3307,1.3538,1.2648,1.2510,
#' 1.2069,1.1552,1.1238,1.1281,1.1113,1.0377)
#' dat <- as.data.frame(cbind(year,catch,cpue))
#' out <- getlag(dat,plotout=FALSE)
#' plot(out,lwd=3,col=2)
#' str(out)
getlag <- function(fish,maxlag=10,plotout=TRUE,indexI=1) {
pickI <- grep("cpue",colnames(fish))
pick <- which((fish[,"catch"] > 0) & (fish[,pickI[indexI]] > 0))
ans <- ccf(x=fish[pick,"catch"],y=fish[pick,pickI[indexI]],
lag.max=maxlag,main="",type="correlation",plot=plotout,
ylab="Cross-Correlation")
return(ans)
} # end of getlag
#' @title getMSY calculates the MSY for the Polacheck et al 1993 equation
#'
#' @description getMSY calculates the MSY for the Polacheck et al 1993
#' generalized surplus production equation. This simplifies to rK/4
#' when p = 1.0. But this is a general equation that covers off for
#' all positive values of p.
#'
#' @param pars the model parameters r, K, Binit, sigma; p is kept separate
#' @param p asymmetry parameter for the Polacheck et al 1993 equation,
#' default=1.0 = Schaefer
#'
#' @references Polacheck, T., Hilborn, R., and A.E. Punt (1993) Fitting
#' surplus production models: Comparing methods and measuring uncertainty.
#' \emph{Canadian Journal of Fisheries and Aquatic Sciences},
#' 50: 2597-2607.
#'
#' @return the MSY
#' @export
#'
#' @examples
#' param <- c(r=1.1,K=1000.0,Binit=800.0,sigma=0.075)
#' getMSY(param,p=1.0) # 275 Schaefer equivalent
#' getMSY(param,p=1e-08) # 404.6674 Fox equivalent
getMSY <- function(pars,p=1.0) {
msy <- (pars[1]*pars[2])/((p+1)^((p+1)/p))
return(msy)
} # end of getMSY
#' @title getrmse calculates the rmse of the input 'invar' series
#'
#' @description getrmse calculates the root mean square error (rmse) of the
#' input invar series (defaults to 'cpue') against an input 'year' time
#' series. This is primarily designed to generate an alternative estimate
#' of the intrinsic variability of a cpue time-series to that which may be
#' obtained from a cpue standardization
#'
#' @param indat the matrix, spmdat, or data.frame containing both a 'year'
#' column and an invar column (default to 'cpue')
#' @param invar the column name of the variable whose rmse is wanted; defaults
#' to 'cpue'
#' @param inyr the column name that points to the 'year' name
#' @return a list of the rmse and the loess predicted values of the invar
#' for each year in the time-series
#' @export
#'
#' @examples
#' year <- 1986:1994
#' cpue <- c(1.2006,1.3547,1.0585,1.0846,0.9738,1.0437,0.7759,1.0532,1.284)
#' dat <- as.matrix(cbind(year,cpue))
#' getrmse(dat,invar="cpue") # should be 0.08265127
#' getrmse(dat,invar="cpue")$rmse
getrmse <- function(indat,invar="cpue",inyr="year"){
if (iscol(inyr,indat) & iscol(invar,indat)) {
nyr <- dim(indat)[1]
predictedCE <- rep(NA,nyr)
varloc <- grep(invar,colnames(indat))
nvar <- length(varloc)
if (nvar > 1) {
obsvar <- rep(NA,nyr)
for (i in 1:nvar) {
pick <- which(indat[,varloc[i]] > 0)
obsvar[pick] <- indat[pick,varloc[i]]
}
} else {
obsvar <- indat[,varloc]
}
picky <- which(obsvar > 0)
model <- loess(obsvar[picky] ~ indat[picky,inyr])
predictedCE[picky] <- model$fitted
rmse <- sqrt(sum(model$residuals^2)/model$n)
return(list(rmse=rmse,predictedCE=predictedCE))
} else {
warning("Input data should contain both 'year' and 'cpue' \n")
}
} # end of getrmseCE
#' @title parasympt generates N vectors from a multi-variate normal
#'
#' @description parasympt generates N vectors from a multi-variate normal
#' distribution for a surplus production model. This can be used
#' when estimating the uncertainty around an spm fit, or when
#' conducting projections from a model fit while attempting to
#' account for uncertainty. Use of this function requires the
#' mvnnorm package. It could be generalized to suit any model. It is
#' designed for use only with models fitted using maximum likelihood.
#'
#' @param bestmod the output from nlm containing the optimal parameters in
#' log-space, and the hessian
#' @param N the number of parameter vectors to be sampled from the multi-
#' variate normal defined by the optimal parameters and the inverse of
#' the hessian (the variance-covariance matrix).
#'
#' @return an N x numpar matrix of parameter vectors
#' @export
#'
#' @examples
#' data(abdat)
#' schf <- FALSE
#' param <- log(c(r=0.3,K=11500,Binit=3300,sigma=0.05))
#' bestmod <- nlm(f=negLL1,p=param,funk=simpspm,logobs=log(abdat$cpue),
#' indat=abdat,typsize=magnitude(param),iterlim=1000,
#' schaefer=schf,hessian = TRUE)
#' out <- spm(bestmod$estimate,indat=abdat,schaefer=schf)
#' matpar <- parasympt(bestmod,1000)
#' head(matpar,15)
#' pairs(matpar)
parasympt <- function(bestmod,N) {
optpar <- bestmod$estimate
if (is.null(dim(bestmod$hessian)))
stop("The input 'bestmod' must include a Hessian estimate!")
vcov <- solve(bestmod$hessian)
numpar <- length(optpar)
columns <- c("r","K","Sigma")
if (length(optpar) == 4) columns <- c(columns,"Sigma")
mvnpar <- matrix(exp(rmvnorm(N,mean=optpar,sigma=vcov)),nrow=N,
ncol=numpar,dimnames=list(1:N,columns))
return(mvnpar)
} # parasympt
#' @title plotlag plots the effect of a lag between two variables
#'
#' @description the use of the base function ccf can suggest a lagged
#' relationship between a driver variable and a react(ing) variable.
#' For example, cpue may respond to catches in a negative manner after
#' a lag of a few years. One looks for a negative lag, which would
#' imply that the driver variable influences the react(ing) variable
#' after the given lag has passed. The lag is always assumed to be
#' based on yearly intervals, though this can be changed.
#'
#' @param x the matrix containing columns of the named variables. It must
#' contain columns with the same names as the driver and react(ing)
#' variables
#' @param driver the variable doing the influencing
#' @param react the variable being influenced
#' @param lag the time lag before the influence is felt
#' @param interval the name of the time-interval variable, default='year'
#' @param filename default is empty. If a filename is put here a .png file
#' with that name will be put into the working directory.
#' @param resol the resolution of the png file, defaults to 200 dpi
#' @param fnt the font used in the plot and axes. Default=7, bold Times.
#' Using 6 gives Times, 1 will give SansSerif, 2 = bold Sans
#'
#' @return a list containing some summary results, the anova of the linear
#' model fitted in aov, and a summary of the linear model in summ
#' @export
#'
#' @examples
#' year <- 1985:2008
#' catch <- c(1018,742,868,715,585,532,566,611,548,499,479,428,657,481,645,
#' 961,940,912,955,935,940,952,1030,985)
#' cpue <- c(0.6008,0.6583,0.6791,0.6889,0.7134,0.7221,0.7602,0.7931,0.8582,
#' 0.8876,1.0126,1.1533,1.2326,1.2764,1.3307,1.3538,1.2648,1.2510,
#' 1.2069,1.1552,1.1238,1.1281,1.1113,1.0377)
#' dat <- cbind(year,catch,cpue)
#' out <- plotlag(dat,driver="catch",react="cpue",lag=7)
#' round(out$results,5)
#' out$summ
plotlag <- function(x, driver="catch",react="cpue",lag=0,interval="year",
filename="",resol=200,fnt=7){
oldpar <- par(no.readonly=TRUE)
on.exit(par(oldpar))
lenfile <- nchar(filename)
if (lenfile > 3) {
end <- substr(filename,(lenfile-3),lenfile)
if (end != ".png") filename <- paste0(filename,".png")
png(filename=filename,width=5,height=5.5,units="in",res=resol)
}
par(mfrow = c(3,1),mai = c(0.25, 0.45, 0.1, 0.05), oma = c(1.0,0,0,0))
par(cex=0.75,mgp=c(1.35,0.35,0), font.axis = 7, font = 7, font.lab=7)
colnames(x) <- tolower(colnames(x))
nobs <- dim(x)[1]
# plot 1
ymax <- max(x[,driver],na.rm=TRUE) * 1.025
plot(x[1:(nobs-lag),interval],x[1:(nobs-lag),driver],type="l",lwd=2,
xlab="",ylab=driver,ylim=c(0,ymax),yaxs="i",
panel.first = grid(col="grey"))
abline(h=0,col=1)
text(x[1,interval],0.9*ymax,paste0("lag = ",lag),cex=1.2,pos=4)
#plot 2
ymax <- max(x[,react],na.rm=TRUE) * 1.025
plot(x[(1+lag):nobs,interval],x[(1+lag):nobs,react],type="l",lwd=2,
xlab="",ylab=react,ylim=c(0,ymax),yaxs="i",
panel.first = grid(col="grey"))
abline(h=0,col=1)
#plot 3
plot(x[1:(nobs-lag),driver],x[(1+lag):nobs,react],type="p",pch=16,
ylim=c(0,max(x[,react],na.rm=TRUE)),panel.first = grid(),
ylab=react,xlab="")
mtext(driver,side=1,outer=TRUE,cex=1.0,line=0)
model <- lm(x[(1+lag):nobs,react] ~ x[1:(nobs-lag),driver])
abline(model,col=2)
if (lenfile > 0) {
outfile <- paste0(getwd(),"/",filename)
print(outfile)
dev.off()
}
ano <- anova(model)
summ <- summary(model)
results <- c(lag=lag,p=ano$`Pr(>F)`[1],
adj_r2=summ$adj.r.squared,df=ano$Df[2])
return(list(results=results,aov=anova(model),summ=summary(model)))
} # end of plotlag
#' @title plotspmmod plots an spm model fit given parameters and data
#'
#' @description plotspmmod takes a parameter set and the spmdat matrix
#' and plots the predicted depletion, catch, the CPUE and the model
#' fit to CPUE. If plotprod=TRUE, it also plots the productivity curves
#'
#' @param inp a vector of model parameters at least (r,K,B0)
#' @param indat a matrix with at least columns 'year', 'catch', and 'cpue'
#' @param schaefer if TRUE, the default, then the Schaefer SPM is used.
#' If FALSE then an approximate Fox SPM would be used
#' @param limit defaults to the Commonwealth limit of 0.2B0.
#' @param target defaults to the Commonwealth target of 0.48B0. Determines
#' the green line plotted on the exploitable biomass plot.
#' @param addrmse default is FALSE but if set TRUE this will add the loess
#' curve to the CPUE trend for comparison with the fitted line
#' @param fnt the font used in the plot and axes. Default=7, bold Times.
#' Using 6 gives Times, 1 will give SansSerif, 2 = bold Sans
#' @param plotout should one generate a plot or only do the calculations;
#' default is TRUE
#' @param vline defaults to 0 = no action but if a year is inserted,
#' which should generally be between two years to designate some
#' change in the time-series between two years, then a vertical line
#' will be added on year-based plots
#' @param plotprod if FALSE, the default, the productivity curves are
#' not plotted. If TRUE, two extra plots are produced.
#' @param maxy defaults to 0, if > 0 then that value will be used in the
#' plot of CPUE
#' @return invisibly a list of dynamics, production curve, MSY, and Bmsy
#' @export
#'
#' @examples
#' data(dataspm)
#' pars <- log(c(0.264,4740,3064,0.2))
#' ans <- plotspmmod(pars,dataspm,schaefer=TRUE,plotprod=TRUE)
#' best <- nlm(negLL,pars,funk=simpspm,indat=dataspm,
#' logobs=log(dataspm[,"cpue"]),steptol=1e-05)
#' outfit(best,backtran = TRUE)
#' ans <- plotspmmod(best$estimate,dataspm,schaefer=TRUE,plotout=TRUE,
#' plotprod=FALSE,addrmse=TRUE)
#' str(ans)
plotspmmod <- function(inp,indat,schaefer=TRUE,limit=0.2,
target=0.48,addrmse=FALSE,fnt=7,plotout=TRUE,
vline=0,plotprod=FALSE,maxy=0) {
if(schaefer) p <- 1 else p <- 1e-8
celoc <- grep("cpue",colnames(indat))
if (length(celoc) > 1){
out <- spmCE(inp=inp,indat=indat,schaefer = schaefer)
} else {
out <- spm(inp=inp,indat=indat,schaefer = schaefer)
}
ans <- out$outmat
# calc sigmaCE by cpue column
predloc <- grep("predCE",colnames(ans))
celoc <- grep("CPUE",colnames(ans))
nce <- length(celoc)
sigmaCE <- numeric(nce)
for (i in 1:nce) {
pickY <- which(ans[,celoc[i]] > 0)
sigmaCE[i] <- sum((log(ans[pickY,celoc[i]]) -
log(ans[pickY,predloc[i]]))^2)
sigmaCE[i] <- sqrt(sigmaCE[i]/length(pickY))
}
yrs <- ans[,"Year"]
nyr <- length(yrs)
depl <- ans[,"Depletion"] # for depletion plot
rmse <- list(rmse=NA,predictedCE=NA) # for cpue plot
rmseresid <- NA
unfishedB <- out$parameters[2] # for production results
minB <- 100
x <- seq(minB,unfishedB,length.out = 200)
pars <- out$parameters
y <- ((pars[1]/p)*x*(1-(x/pars[2])^p))
pick <- which.max(y)
pickLRP <- which.closest(limit*pars[2],x)
pickTRP <- which.closest(target*pars[2],x)
msy <- y[pick]
Bmsy <- x[pick]
Blim <- x[pickLRP]
Btarg <- x[pickTRP]
Ctarg <- y[pickTRP] # end of production results
xd <- x/unfishedB
Dmsy <- xd[pick]
Dcurr <- tail(depl,1)
if (plotout) {
oldpar <- par(no.readonly=TRUE)
on.exit(par(oldpar))
if (plotprod) par(mfcol= c(3,2)) else par(mfcol= c(2,2))
par(mai=c(0.35,0.4,0.1,0.05),oma=c(0.0,0.0,0,0))
par(cex=0.75, mgp=c(1.25,0.35,0), font.axis=7,font.lab=7,font=fnt)
# plot 1 Depletion through time
ymax <- max(depl) * 1.025
plot(yrs,depl,type="l",col=1,ylab="",xlab="",ylim=c(0,ymax),lwd=2,
yaxs="i", panel.first = grid())
title(ylab=list("ExploitB Depletion", cex=1.0, col=1, font=fnt),
xlab=list("Years", cex=1.0, col=1, font=fnt))
abline(h=c(0.2,target),col=c(2,3),lwd=1)
if (vline > 0) abline(v=vline,col=1,lty=2)
# plot2 Catch
ymax <- max(ans[,"Catch"],na.rm=T)*1.025
plot(yrs,ans[,"Catch"],type="l",pch=16,col=1,ylab="",xlab="",
ylim=c(0,ymax),lwd=2,yaxs="i",panel.first = grid())
abline(h=(out$msy),col=2)
if (vline > 0) abline(v=vline,col=1,lty=2)
title(ylab=list("Catch (t)", cex=1.0, col=1, font=fnt),
xlab=list("Years", cex=1.0, col=1, font=fnt))
# Plot 3 CPUE
celoc <- grep("CPUE",colnames(ans))
predloc <- grep("predCE",colnames(ans))
nce <- length(celoc)
if (nce > 1) {
obsce <- rep(NA,nyr)
for (i in 1:nce) {
pick <- which(ans[,celoc[i]] > 0)
obsce[pick] <- ans[pick,celoc[i]]
}
} else {
obsce <- ans[,celoc]
}
pickCE <- which(ans[,celoc[1]] > 0)
ymax <- max(ans[pickCE,c(celoc,predloc)],na.rm=T)*1.025
if (maxy > 0) ymax <- maxy
plot(yrs,ans[,celoc[1]],type="p",pch=16,col=1,cex=1.0,ylab="",xlab="",
ylim=c(0,ymax),yaxs="i",xlim=range(yrs),panel.first = grid())
if (vline > 0) abline(v=vline,col=1,lty=2)
lines(yrs[pickCE],ans[pickCE,predloc[1]],col=1,lwd=2)
if (nce > 1) {
for (i in 2:nce) {
pickCE <- which(ans[,celoc[i]] > 0)
points(yrs[pickCE],ans[pickCE,celoc[i]],pch=1,cex=1.0,col=1)
lines(yrs[pickCE],ans[pickCE,predloc[i]],col=i,lwd=2)
}
}
if (addrmse) {
CEnames <- colnames(ans)[celoc]
rmse <- vector("list",nce)
names(rmse) <- colnames(ans)[celoc]
for (i in 1:nce) { # use getrmse to fit loess
rmse[[i]] <- getrmse(ans,invar=CEnames[i],inyr="Year")
lines(yrs,c(rmse[[i]]$predictedCE),lwd=2,col=3,lty=2)
}
}
title(ylab=list("Scaled CPUE", cex=1.0, col=1, font=fnt),
xlab=list("Years", cex=1.0, col=1, font=fnt))
text(min(yrs),ymax*0.2,paste("p = ",p,sep=""),font=fnt,cex=1.0,pos=4)
text(min(yrs),ymax*0.1,paste("MSY = ",round(out$msy,3),sep=""),
font=fnt,cex=1.0,pos=4)
# plot4 cpue residuals
resid <- as.matrix(ans[,celoc]/ans[,predloc])
rmseresid <- numeric(nce)
nresid <- dim(resid)[1]
ymax <- getmax(resid)
ymin <- getmin(resid,mult=1.1)
plot(yrs,resid[,1],"n",ylim=c(ymin,ymax),ylab="Log Residuals",
xlab="Years",panel.first=grid())
abline(h=1.0,col=1,lty=2)
if (vline > 0) abline(v=vline,col=1,lty=2)
for (i in 1:nce) {
pickCE <- which(ans[,celoc[i]] > 0)
segments(x0=yrs[pickCE],y0=rep(1.0,length(pickCE)),x1=yrs[pickCE],
y1=resid[pickCE,i],lwd=2,col=2)
points(yrs[pickCE],resid[pickCE,i],pch=16,col=1,cex=1.0)
rmseresid[i] <- sqrt(sum(resid[,i]^2,na.rm=TRUE)/length(pickCE))
}
legend("topleft",colnames(ans)[celoc],round(rmseresid,3),
cex=1.0,bty="n")
if (plotprod) {
#plot5 Production curve
ymax <- getmax(y)
plot(x,y,type="l",col=1,ylab="",xlab="",ylim=c(0,ymax),lwd=2,
yaxs="i", panel.first = grid())
abline(v=c(Blim,Bmsy,Btarg),col=2)
abline(h=msy,col=2,lty=2)
text(Bmsy*1.05,ymax*0.1,paste("Bmsy = ",round(Bmsy,3),sep=""),
font=fnt,cex=1.0,pos=4)
text(0.8*unfishedB,0.925*msy,round(out$msy,3),font=fnt,cex=1,pos=4)
text(0.8*unfishedB,0.825*msy,"MSY",font=fnt,cex=1,pos=4)
title(ylab=list("Surplus Production", cex=1.0, col=1, font=fnt),
xlab=list("Biomass", cex=1.0, col=1, font=fnt))
#plot6 depletion production curve from biomass one
ymax <- getmax(y)
plot(xd,y,type="l",col=1,ylab="",xlab="",ylim=c(0,ymax),lwd=2,
yaxs="i", panel.first = grid())
abline(v=c(limit,Dmsy,target),col=c(2,4,3))
abline(h=c(Ctarg,msy),col=c(3,2),lty=2)
title(ylab=list("Surplus Production(t)", cex=1.0, col=1, font=fnt),
xlab=list("Depletion", cex=1.0, col=1, font=fnt))
}
}
result <- list(out,cbind(x,y),rmseresid,msy,Bmsy,Dmsy,Blim,Btarg,Ctarg,
Dcurr,rmse,sigmaCE)
names(result) <- c("Dynamics","BiomProd","rmseresid","MSY","Bmsy",
"Dmsy","Blim","Btarg","Ctarg","Dcurr","rmse","sigma")
return(invisible(result))
} # end of plotspmmod
#' @title plotproj generate a plot of a matrix of biomass projections
#'
#' @description plotproj generate a plot of a matrix of N biomass projections
#' and includes the option of including reference points relative to
#' Bzero = K. Quantiles are included in the plot
#'
#' @param projs the N x yrs matrix of biomass trajectories
#' @param spmout the object output from the function spm
#' @param qprob the quantiles to include in the plot, default=c(0.1,0.5,0.9)
#' @param refpts the proportion of Bzero=K acting as limit and target
#' reference points ( a vector of two)
#' @param fnt the font to use in the figure, default = 7 = bold Times
#'
#' @return This plots a graph and returns, invisibly, the requested
#' quantiles and the proportion less than the limit reference point.
#' @export
#'
#' @examples
#' data(abdat)
#' schf <- FALSE
#' param <- log(c(r=0.3,K=11500,Binit=3300,sigma=0.05))
#' bestmod <- nlm(f=negLL1,p=param,funk=simpspm,logobs=log(abdat$cpue),
#' indat=abdat,typsize=magnitude(param),iterlim=1000,
#' schaefer=schf,hessian = TRUE)
#' out <- spm(bestmod$estimate,indat=abdat,schaefer=schf)
#' matpar <- parasympt(bestmod,50) # use at least 1000 in reality
#' projs <- spmproj(matpar,abdat,projyr=10,constC=900)
#' plotproj(projs,out,qprob=c(0.1,0.5),refpts=c(0.2,0.4))
plotproj <- function(projs,spmout,qprob=c(0.1,0.5,0.9),
refpts=NULL,fnt=7) {
yrs <- as.numeric(colnames(projs))
N <- nrow(projs)
dyn <- spmout$outmat
lastyr <- max(dyn[,"Year"]) - 1
Bzero <- spmout$parameters["K"]
maxy <- getmax(projs)
oldpar <- par(no.readonly=TRUE)
on.exit(par(oldpar))
par(mfrow=c(1,1),mai=c(0.3,0.45,0.05,0.05),oma=c(0.0,0,0.0,0.0))
par(cex=0.75, mgp=c(1.35,0.35,0), font.axis=fnt,font=fnt,font.lab=fnt)
plot(yrs,projs[1,],type="n",ylab="Stock Biomass (t)", xlab="",
panel.first=grid(),ylim=c(0,maxy),yaxs="i")
for (i in 1:N) lines(yrs,projs[i,],lwd=1,col="grey")
qts <- NULL
if (is.vector(qprob)) {
qts <- as.matrix(apply(projs,2,function(x) quantile(x,probs=qprob)))
nqts <- length(qprob)
if (nqts > 1) {
for (i in 1:nqts) lines(yrs,qts[i,],lwd=1,col=2)
} else {
lines(yrs,qts,lwd=1,col=2)
}
}
lines(dyn[,"Year"],dyn[,"ModelB"],lwd=2,col=1)
ltLRP <- NULL
abline(v=(lastyr+0.5),col=4)
nyr <- length(yrs)
if (length(refpts) > 0) {
abline(h=refpts*Bzero,lwd=2,col=1,lty=2)
ltLRP <- length(which(projs[,nyr] < refpts[1]*Bzero))
}
ans <- list(qts=qts,ltLRP=ltLRP/N)
return(invisible(ans))
} # end of plotproj
#' @title plotspmdat plots the fish data containing catches and cpue
#'
#' @description plotspmdat plots a fish data set. It plots the catch
#' and CPUE against time
#'
#' @param x a data set that should contain 'year', 'catch', and
#' 'cpue'
#' @param ... extra parameters potentially used by plotspmdat
#'
#' @return nothing, but it does generate a new plot
#' @export
#'
#' @examples
#' yrs <- 2000:2010
#' catches <- rnorm(length(yrs),mean=150,sd=5)
#' ce <- rnorm(length(yrs),mean=20,sd=1)
#' fish <- as.data.frame(cbind(year=yrs,catch=catches,cpue=ce))
#' plotspmdat(fish)
plotspmdat <- function(x, ...){
colnames(x) <- tolower(colnames(x))
tmp <- match(c("year","catch","cpue"), colnames(x))
if (countgtzero(tmp) != 3) {
label <- paste0("Input data to plotspmdat must, at least, ",
"contain columns of year, catch, and cpue")
stop(label)
}
oldpar <- par(no.readonly=TRUE)
on.exit(par(oldpar))
par(mfrow = c(2,1),mai = c(0.25, 0.45, 0.1, 0.05), oma = c(0,0,0,0))
par(cex = 0.85, mgp = c(1.35,0.35,0),font.axis=7,font=7, font.lab=7)
ymax <- max(x[,"catch"],na.rm=TRUE) * 1.025
plot(x[,"year"],x[,"catch"],type="l",lwd=2,xlab="",ylab="Catch (t)",
ylim=c(0,ymax),yaxs="i",panel.first=grid())
abline(h=0,col=1)
ymax <- max(x[,"cpue"],na.rm=TRUE) * 1.025
plot(x[,"year"],x[,"cpue"],type="l",lwd=2,xlab="",ylab="CPUE",
ylim=c(0,ymax),yaxs="i",panel.first=grid())
abline(h=0,col=1)
} # end of plotspmdat
#' @title robustSPM does a robustness test on quality of fit of an SPM
#'
#' @description robustSPM conducts a robustness test on the quality of
#' fit of an SPM. This is done by using the original optimal model
#' parameters or the original guessed parameter values, add random
#' variation to each of them, and re-fit the model. This process
#' needs to be repeated multiple times. This should enable an
#' analysis of the stability of the modelling outcomes. If the
#' optimum parameters are used then add more variation, if initial
#' guesses are used you may need to select different starting
#' points so that the random variation covers the parameter space
#' reasonably well.
#'
#' @param inpar the parameter set with which to begin the trials
#' @param fish the fisheries data: at least year, catch, and cpue
#' @param N number of random trials to run; default = 10 = not enough
#' @param scaler the divisor that sets the degree of normal random
#' variation to add to the parameter values; default = 15 the
#' smaller the value the more variable the outcome
#' @param verbose progress and summary statistics to the screen?
#' default = FALSE
#' @param schaefer default = TRUE, which sets the analysis to the
#' Schaefer model. setting it to FALSE applies the approximate Fox model
#' @param funk the function used to generate the predicted cpue
#' @param funkone defaults=FALSE; use negLL or negLL1, with FALSE
#' robustSPM will use negLL, with TRUE it will use negLL1
#' which has a constraint on the first parameter to keep it > 0
#' @param steptol is the steptol from nlm as used in fitSPM, the
#' default value is 1e-06, as usual.
#'
#' @return a list containing the results from each run, the range of values
#' across runs, and the median values.
#' @export
#'
#' @examples
#' data(dataspm)
#' param <- log(c(r=0.24,K=5174,Binit=2846,sigma=0.164))
#' ans <- fitSPM(pars=param,fish=dataspm,schaefer=TRUE,maxiter=1000)
#' out <- robustSPM(ans$estimate,dataspm,N=5,scaler=40,verbose=TRUE,
#' schaefer=TRUE) # N should be 50, 100, or more
#' str(out)
#' print(out$results)
#' pairs(out$results[,c(6:8,11)]) # need a larger N!
robustSPM <- function(inpar,fish,N=10,scaler=40,verbose=FALSE,
schaefer=TRUE,funk=simpspm,funkone=FALSE,
steptol=1e-06) {
origpar <- inpar
if (length(origpar) == 3) {
pars <- cbind(rnorm(N,mean=origpar[1],sd=abs(origpar[1])/scaler),
rnorm(N,mean=origpar[2],sd=abs(origpar[2])/scaler),
rnorm(N,mean=origpar[3],sd=abs(origpar[3])/scaler))
columns <- c("ir","iK","isigma","iLike","r","K","sigma","-veLL","MSY",
"Iters")
} else {
pars <- cbind(rnorm(N,mean=origpar[1],sd=abs(origpar[1])/scaler),
rnorm(N,mean=origpar[2],sd=abs(origpar[2])/scaler),
rnorm(N,mean=origpar[3],sd=abs(origpar[3])/scaler),
rnorm(N,mean=origpar[4],sd=abs(origpar[4])/scaler))
columns <- c("ir","iK","iBinit","isigma","iLike","r","K","Binit",
"sigma","-veLL","MSY","Iters") # prefix i implies input
}
coln <- length(columns)
results <- matrix(0,nrow=N,ncol=coln,dimnames=list(1:N,columns))
for (i in 1:N) { # i=1
if (funkone) {
origLL <- negLL1(pars[i,],fish,funk=funk,logobs=log(fish[,"cpue"]),
schaefer=schaefer)
} else {
origLL <- negLL(pars[i,],fish,funk=funk,logobs=log(fish[,"cpue"]),
schaefer=schaefer)
}
bestSP <- fitSPM(pars[i,],fish,schaefer=schaefer,funk=funk,
funkone=funkone,steptol=steptol)
if (schaefer) pval=1.0 else pval=1e-08
opar <- exp(bestSP$estimate)
MSY <- getMSY(opar,p=pval)
results[i,] <- c(exp(pars[i,]),origLL,opar,bestSP$minimum,MSY,
bestSP$iterations[1])
if (verbose) cat(i," ")
}
if (verbose) cat("\n")
ordres <- results[order(results[,"-veLL"]),] # see best and worst fit
bounds <- apply(results,2,range)
medvalues <- apply(results,2,median)
if (verbose) {
print(round(bounds,3)) # see the minimum and maximum)
print(round(medvalues,3))
}
return(list(results=ordres,range=bounds,medians=medvalues))
} # end of robustSPM
#' @title simpspm calculates only the predicted log(CE) for an SPM
#'
#' @description simpspm calculates only the predicted log(CPUE) for a
#' Surplus Production Model (SPM). It sets the Polacheck et al, 1993
#' parameter 'p' depending on the schaefer boolean argument, and
#' this determines the asymmetry of the production curve. Note p is
#' set not estimated. If p = 1.0 then the SPM is the Schaefer model,
#' if it is 1e-8 it approximates the Fox model. The output of
#' log(CPUE) is to simplify the use of log-normal residual errors or
#' likelihoods. This function is designed for data consisting of
#' only a single cpue time-series. simpspm must have at least three
#' parameters, including the sigma, even if sum-of-squared residuals
#' is used as a minimizer, then sigma would just float. The column
#' names for year, catch and cpue are included to facilitate ease
#' of use with other data sets.
#'
#' @param pars the parameters of the SPM are either c(r,K,Binit,sigma),
#' or c(r, K, sigma), the sigma is required in both cases. Binit is
#' required if the fishery data starts after the stock has been
#' depleted. Each parameter must be log-transformed for improved
#' model stability and is back-transformed inside simpspm.
#' @param indat the data which needs to include year, catch, and cpue.
#' @param schaefer a logical value determining whether the spm is to be
#' a simple Schaefer model (p=1) or approximately a Fox model
#' (p=1e-08). The default is TRUE = Schaefer model
#' @param year column name within indat containing the years, default='year'
#' @param cats column name within indat containing the catches, default='catch'
#' @param index column name within indat containing the cpue. default='cpue'
#'
#' @return a vector of length nyrs of the predicted log(cpue)
#' @export
#'
#' @examples
#' data(abdat)
#' param <- log(c(r=0.4,K=9400,Binit=3400,sigma=0.05))
#' predCE <- simpspm(pars=param,indat=abdat)
#' cbind(abdat,exp(predCE))
simpspm <- function(pars, indat,schaefer=TRUE,
year="year",cats="catch",index="cpue") {
nyrs <- length(indat[,year])
biom <- numeric(nyrs+1)
catch <- indat[,cats]
ep <- exp(pars) # par contains at least log of (r,K, and sigma)
biom[1] <- ep[2]
if (length(pars) > 3) biom[1] <- ep[3] # Binit should be before sigma
#p is the location of mode parameter 1 = Schaefer, 1e-8 ~ Fox model
if(schaefer) p <- 1 else p <- 1e-8
for (yr in 1:nyrs) { # fill biom using Bt as an interim step
Bt <- biom[yr] # avoid negative biomass using a max statement
biom[yr+1] <- max(Bt + ((ep[1]/p)*Bt*(1-(Bt/ep[2])^p)-catch[yr]),40)
}
pick <- which(indat[,index] > 0)
qval <- exp(mean(log(indat[pick,index]/biom[pick])))
return(log(biom[1:nyrs] * qval)) # the log of predicted cpue
} # end of simpspm generates log-predicted cpue
#' @title simpspmM calculates predicted CE when multiple indices are present
#'
#' @description simpspmM calculates the predicted CPUE for an surplus
#' production model and is designed for when there are more than
#' one time-series of an index of relative abundance. The parameter
#' vector includes the standard deviations for the log-normal
#' distributions assumed for the indices of relative abundance.
#' They are not used in this function but will be when the
#' likelihoods are calculated as a next step in fitting the model.
#'
#' @param pars the parameters of the SPM = r, K, Binit if fishery is
#' depleted to start with (omit otherwise), and a sigma for each
#' cpue series. Each parameter is in log space and is
#' back-transformed inside simpspmM.
#' @param indat the data which needs to include year, catch, and cpue.
#' The latter should have a separate column for each fleet, with
#' a column name beginning with cpue or whatever name you put in
#' index (see below) for example cpue1, cpue2, etc.
#' @param schaefer a logical value determining whether the spm is to
#' be a simple Schaefer model (p=1) or approximately a Fox model
#' (p=1e-08). The default is TRUE
#' @param year column name within indat containing the years, default='year'
#' @param cats column name within indat containing the catches, default='catch'
#' @param index the prefix in the column names given to the indices of
#' relative abundance used, perhaps 'cpue' as in cpueTW, cpueAL,
#' etc. grep is used to search for columns containing this prefix
#' to identify whether there are more than one column of cpue data. Be sure
#' to only use the prefix for indices of relative abundance.
#'
#' @return a vector or matrix of nyrs of the predicted CPUE
#' @export
#'
#' @examples
#' data(twoindex)
#' fish <- as.matrix(twoindex)
#' pars <- log(c(0.04,155000,0.4,0.3))
#' bestSP <- nlm(f=negLLM,p=pars,funk=simpspmM,indat=fish,
#' schaefer=TRUE,logobs=log(fish[,c("cpue1","cpue2")]),
#' steptol=1e-06,harvpen=TRUE)
#' outfit(bestSP) # best fitting estimates
#' simpspmM(bestSP$estimate,fish) # the two log(predicted cpue)
simpspmM <- function(pars,indat,schaefer=TRUE,
year="year",cats="catch",index="cpue") {
celoc <- grep(index,colnames(indat))
nce <- length(celoc)
npar <- 2 + nce
nyrs <- length(indat[,"year"])
biom <- numeric(nyrs+1)
catch <- indat[,cats]
predCE <- matrix(NA,nrow=nyrs,ncol=nce)
r <- exp(pars[1])
K <- exp(pars[2])
biom[1] <- K
if (length(pars) > npar) biom[1] <- exp(pars[3])
if(schaefer) p <- 1 else p <- 1e-8
for (loc in 1:nyrs) {
Bt <- biom[loc]
biom[loc+1] <- max(Bt + ((r/p)*Bt*(1-(Bt/K)^p)-catch[loc]),40)
}
for (i in 1:nce) {
pick <- which(indat[,celoc[i]] > 0)
qval <- exp(mean(log(indat[pick,celoc[i]]/biom[pick])))
predCE[pick,i] <- log(biom[pick] * qval)
}
return(predCE)
} # end of simpspmM
#' @title spm calculates the dynamics of a Schaefer or Fox model
#'
#' @description spm calculates the dynamics using a Schaefer of Fox
#' model. The outputs include predicted Biomass, year, catch, cpue,
#' predicted cpue, contributions to q, ssq, and depletion levels.
#' Generally it would be more sensible to use simpspm when fitting
#' a Schaefer model or a Fox model as those functions are designed
#' to generate only the log of predicted cpue as required by the
#' functions ssq and negLL, but the example shows how it could be
#' used. The function spm is used inside 'plotspmmod' and could be
#' used alone, to generate a full list of model outputs after the
#' model has been fitted. spm is designed for working with a
#' single vector of an index of relative abundance. If there are
#' multiple vectors of the index then use simpspmM and spmCE.
#'
#' @param inp a vector of 3 or 4 model parameters (r,K,sigma) or (r, K,
#' Binit,sigma), you would use the latter if it was suspected that
#' the fishery data started after some initial depletion had
#' occurred. The sigma is an estimate of the variation of the cpue
#' through time. This is required but is only used when fitting the
#' model using negative log-likelihoods.
#' @param indat a matrix with at least columns year, catch, and cpue
#' @param schaefer a logical value determining whether the spm is to
#' be a simple Schaefer model (p=1) or approximately a Fox model
#' (p=1e-08). The default is TRUE
#' @param year the column name of the year variable (in case your dataset
#' names it fishingyearinwhichthecatchwastaken), default='year'
#' @param cats column name of the catch variable, default='catch'
#' @param index the name of the cpue variable, default='cpue'
#'
#' @return a list of five objects; parameters plus q, then outmat, the
#' matrix with the dynamics, msy the maximum sustainable yield, and
#' sumout, which contains r,K,B0,msy,p,q,Depl, FinalB, and InitDepl
#' @export
#'
#' @examples
#' data(abdat) # spm is used inside plotspmmod
#' pars <- log(c(0.35,7800,3500,0.05))
#' ans <- plotspmmod(pars,abdat) #not fitted, just guessed
#' bestSP <- fitSPM(pars=pars,fish=abdat,funk=simpspm)
#' outfit(bestSP) # best fitting estimates
#' ans <- plotspmmod(bestSP$estimate,abdat,schaefer=TRUE)
#' str(ans)
spm <- function(inp,indat,schaefer=TRUE,year="year",cats="catch",
index="cpue") {
years <- indat[,year]
catch <- indat[,cats]
cpue <- indat[,index]
nyrs <- length(years)
biom <- numeric(nyrs+1)
predCE <- matrix(NA,nrow=nyrs,ncol=1)
columns <- c("Year","ModelB","Catch","Depletion","Harvest")
addtxt <- c("CPUE","predCE")
columns <- c(columns,addtxt)
extendyrs <- c(years,(years[nyrs]+1))
answer <- matrix(NA,nrow=(nyrs+1),ncol=length(columns),
dimnames=list(extendyrs,columns))
answer[,"Catch"] <- c(catch,NA)
answer[,"Year"] <- extendyrs
r <- as.numeric(exp(inp[1]))
K <- as.numeric(exp(inp[2]))
biom[1] <- K
if (length(inp) > 3) biom[1] <- as.numeric(exp(inp[3]))
if(schaefer) p <- 1 else p <- 1e-8
for (index in 1:nyrs) { # index=1
Bt <- biom[index]
biom[index+1] <- max(Bt + ((r/p)*Bt*(1-(Bt/K)^p)-catch[index]),40)
}
pick <- which(indat[,"cpue"] > 0)
qval <- exp(mean(log(indat[pick,"cpue"]/biom[pick])))
answer[,"ModelB"] <- biom
answer[,"Depletion"] <- biom/K
answer[,"Harvest"] <- c(catch/biom[1:nyrs],NA)
answer[,"CPUE"] <- c(cpue,NA)
predCE <- biom * qval # apply same catchability across all years
answer[,"predCE"] <- predCE
msy <- r*K/((p+1)^((p+1)/p))
params <- c(exp(inp),qval)
if (length(params) == 4) {
names(params) <- c("r","K","Sigma","q")
} else {
names(params) <- c("r","K","Binit","Sigma","q")
}
sumout <- c(msy,p,answer[(nyrs+1),"Depletion"],answer[1,"Depletion"],
answer[(nyrs+1),"ModelB"])
names(sumout) <- c("msy","p","FinalDepl","InitDepl","FinalB")
output <- list(params,answer,msy,sumout,schaefer)
names(output) <- c("parameters","outmat","msy","sumout","schaefer")
return(output)
} # End of spm
#' @title spmboot conducts a bootstrap analysis on a spm model
#'
#' @description spmboot conducts a bootstrap analysis on a spm model.
#' It does this by saving the original fishery data, estimating
#' the cpue residuals, and multiplying the optimum predicted CPUE
#' by a bootstrap sample of the log-normal residuals (Haddon, 2011,
#' p311; and the On Uncertainty chapter in the URMQMF book, p195).
#' This bootstrap sample of CPUE replaces the original
#' fish[,"cpue"] and the model is re-fitted. This is repeated iter
#' times and the outputs reported ready for the derivation of
#' percentile confidence intervals. The optimum solution is used
#' as the first bootstrap replicate (it is standard practice to
#' include the original fit in the bootstrap analysis). If 1000
#' replicates are run this procedure can take a couple of minutes
#' on a reasonably fast computer. A comparison of the mean with
#' the median should provide some notion of any bias in the
#' mean estimate.
#'
#' @param optpar The optimum model parameters from fitting a surplus production
#' model
#' @param fishery fishery data containing the original observed cpue values
#' @param iter the number of bootstrap replicates to be run, default=1000
#' @param schaefer default=TRUE, should a Schaefer or a Fox model be run
#'
#' @return a list of two matrices. One containing the bootstrap parameters
#' and the other containing some of the dynamics, including the ModelB,
#' the bootstrap CPUE sample, the Depletion, and annual harvest rate.
#' @export
#'
#' @examples
#' data(dataspm); fish <- as.matrix(dataspm)
#' pars <- log(c(r=0.24,K=5150,Binit=2800,0.15))
#' ans <- fitSPM(pars,dataspm,schaefer=TRUE,maxiter=1000)
#' boots <- spmboot(ans$estimate,fishery=fish,iter=5,schaefer=TRUE)
#' dynam <- boots$dynam
#' bootpar <- boots$bootpar
#' rows <- colnames(bootpar)
#' columns <- c(c(0.025,0.05,0.5,0.95,0.975),"Mean")
#' bootCI <- matrix(NA,nrow=length(rows),ncol=length(columns),
#' dimnames=list(rows,columns))
#' for (i in 1:length(rows)) {
#' tmp <- sort(bootpar[,i])
#' qtil <- quantile(tmp,probs=c(0.025,0.05,0.5,0.95,0.975),na.rm=TRUE)
#' bootCI[i,] <- c(qtil,mean(tmp,na.rm=TRUE))
#' }
#' round(bootCI,3) # we used only 5 bootstraps for a speedy example, normally
#' pairs(bootpar[,c("r","K","Binit","MSY")]) # use 1000, 2000, or more
spmboot <- function(optpar,fishery,iter=1000,schaefer=TRUE) {
out <- spm(inp=optpar,indat=fishery,schaefer=schaefer)
outmat <- out$outmat
years <- fishery[,"year"]
nyrs <- length(years)
pickyr <- which(outmat[,"CPUE"] > 0)
cpueO <- outmat[pickyr,"CPUE"]
predO <- outmat[pickyr,"predCE"] # original values
resids <- cpueO/predO
varib <- c("r","K","sigma","-veLL")
lenpar <- length(optpar)
if (lenpar > 3) varib <- c("r","K","Binit","sigma","-veLL")
bootpar <- matrix(0,nrow=iter,ncol=length(varib),
dimnames=list(1:iter,varib))
columns <- c("ModelB","BootCE","predCE","Depletion","Harvest")
dynam <- array(0,dim=c(iter,nyrs,length(columns)),
dimnames=list(1:iter,years,columns))
dynam[1,,] <- outmat[1:nyrs,c(2,6,7,4,5)]
outspm <- fitSPM(optpar,fishery,schaefer=schaefer,maxiter=1000)
bootpar[1,] <- c(outspm$estimate,outspm$minimum)
for (i in 2:iter) { # i = 2
cpueOB <- rep(NA,nyrs) # bootstrap sample
cpueOB[pickyr] <- predO * sample(resids)
fishery[,"cpue"] <- cpueOB
outspm <- fitSPM(optpar,fishery,schaefer=schaefer,maxiter=1000)
bootpar[i,] <- c(outspm$estimate,outspm$minimum)
out <- spm(inp=outspm$estimate,indat=fishery,schaefer=schaefer)
dynam[i,,] <- out$outmat[1:nyrs,c(2,6,7,4,5)]
}
bootpar[,1:lenpar] <- exp(bootpar[,1:lenpar]) # backtransform parameters
if(schaefer) p <- 1 else p <- 1e-8
MSY <- (bootpar[,"r"]*bootpar[,"K"])/((p+1)^((p+1)/p))
Depl <- dynam[,nyrs,"Depletion"]
Harv <- dynam[,nyrs,"Harvest"]
bootpar <- cbind(bootpar,MSY,Depl,Harv)
return(list(dynam=dynam,bootpar=bootpar))
} # end of spmboot
#' @title spmCE - calculates the dynamics for multiple cpue time-series
#'
#' @description spmCE calculates the full dynamics using a Schaefer of Fox
#' model and is used instead of spm when there are multiple index
#' vectors. The outputs include predicted Biomass, year, catch,
#' cpue, predicted cpue, contributions to q, ssq, and depletion
#' levels. Generally it would be more sensible to use simpspmM when
#' fitting a Schaefer or Fox model as that function is designed to
#' generate only the predicted cpue vectors required by the function
#' negLLM, nevertheless, the example shows how it could be used.
#'
#' @param inp a vector of 2 or 3 model parameters (r,K) or (r,K,Binit),
#' you would use the latter if it was suspected that the fishery
#' data started after some initial depletion had occurred. In addition,
#' there should then be the same number of sigma values as there are
#' cpue time-series. For two cpue series with an initial depletion we
#' would expect to have r, K, Binit, sigma1 and sigma2
#' @param indat a matrix with at least columns 'year', 'catch', and 'cpue'
#' @param schaefer a logical value determining whether the spm is to be a
#' simple Schaefer model (p=1) or approximately a Fox model (p=1e-08).
#' The default is TRUE
#' @param year column name within indat containing the years, default='year'
#' @param cats column name within indat containing the catches, default='catch'
#' @param index column name within indat containing the prefix for cpue,
#' default='cpue'
#' @return a list of five objects; outmat the matrix with the dynamics
#' results, q catchability, msy the maximum sustainable yield, the
#' parameter values, and sumout, which contains r, K, B0, msy, p,
#' q, Depl, FinalB, and InitDepl
#'
#' @export
#'
#' @examples
#' data(twoindex)
#' fish <- as.matrix(twoindex)
#' pars <- log(c(0.04,155000,0.4,0.3))
#' bestSP <- nlm(f=negLLM,p=pars,funk=simpspmM,indat=fish,
#' schaefer=TRUE,logobs=log(fish[,c("cpue1","cpue2")]),
#' steptol=1e-06,harvpen=TRUE)
#' outfit(bestSP) # best fitting estimates
#' getMSY(exp(bestSP$estimate))
spmCE <- function(inp,indat,schaefer=TRUE,
year="year",cats="catch",index="cpue") {
celoc <- grep(index,colnames(indat))
nce <- length(celoc)
npar <- 2 + nce # r + K + nce_sigma
years <- indat[,year]
catch <- indat[,cats]
cpue <- as.matrix(indat[,celoc])
nyrs <- length(years)
biom <- numeric(nyrs+1)
qval <- numeric(nce)
predCE <- matrix(NA,nrow=nyrs,ncol=nce)
columns <- c("Year","ModelB","Catch","Depletion","Harvest")
addtxt <- c("CPUE","predCE")
if (nce > 1) {
addtxt <- c(paste0("CPUE",1:nce),paste0("predCE",1:nce))
}
columns <- c(columns,addtxt)
extendyrs <- c(years,(years[nyrs]+1))
answer <- matrix(NA,nrow=(nyrs+1),ncol=length(columns),
dimnames=list(extendyrs,columns))
answer[,"Catch"] <- c(catch,NA)
answer[,"Year"] <- extendyrs
r <- exp(inp[1])
K <- exp(inp[2])
biom[1] <-K
if (length(inp) > npar) biom[1] <- exp(inp[3])
if(schaefer) p <- 1 else p <- 1e-8
for (index in 1:nyrs) {
Bt <- biom[index]
biom[index+1] <- max(Bt + ((r/p)*Bt*(1-(Bt/K)^p)-catch[index]),40)
}
answer[,"ModelB"] <- biom
answer[,"Depletion"] <- biom/K
answer[,"Harvest"] <- c(catch/biom[1:nyrs],NA)
answer[,(5+1)] <- c(cpue[,1],NA)
pick <- which(indat[,celoc[1]] > 0)
qval[1] <- exp(mean(log(indat[pick,celoc[1]]/biom[pick])))
predCE <- biom *qval[1] # apply same catchability across all years
answer[,(5+nce+1)] <- predCE
if (nce > 1) {
for (i in 2:nce) {
pick <- which(indat[,celoc[i]] > 0)
qval[i] <- exp(mean(log(indat[pick,celoc[i]]/biom[pick])))
predCE <- biom * qval[i]
answer[,(5+i)] <- c(cpue[,i],NA)
answer[,(5+nce+i)] <- predCE
}
}
msy <- r*K/((p+1)^((p+1)/p))
if (length(inp) == npar) { copyp <- c(inp,inp[2])
} else { copyp <- inp
}
params <- exp(copyp)
names(params) <- c("r","K","Binit",paste0("Sigma",1:nce))
sumout <- c(msy,p,answer[(nyrs+1),"Depletion"],answer[1,"Depletion"],
answer[(nyrs+1),"ModelB"],qval)
names(sumout) <- c("msy","p","FinalDepl","InitDepl","FinalB","qs")
output <- list(params,answer,msy,sumout)
names(output) <- c("parameters","outmat","msy","sumout")
return(output)
} # End of spmCE
#' @title spmphaseplot - plots the phase plot of harvest rate vs biomass
#'
#' @description spmphaseplot uses the output from plotspmmod to plot up
#' the phase plot of harvest rate vs Biomass, marked with the limit
#' and default targets. It identifies the start and end years
#' (green and red dots) and permits the stock status to be determined
#' visually. It also plots out the catch time-series and harvest
#' rate time-series to aid in interpretation of the phase plot.
#'
#' @param answer the object output by the function plotspmmod,
#' containing the production curve, the fishery dynamics (predicted
#' harvest rate and biomass through time).
#' @param Blim limit reference point, default = 0.2 = 0.2B0.
#' @param Btarg what target reference point will be used in the phase
#' plot. A default of 0.5 is used.
#' @param filename default is empty. If a filename is put here a .png
#' file with that name will be put into the working directory.
#' @param resol the resolution of the png file, defaults to 200 dpi
#' @param fnt the font used in the plot and axes. Default=7, bold Times.
#' Using 6 gives Times, 1 will give SansSerif, 2 = bold Sans
#'
#' @return an invisible list of B0, Bmsy, Hmsy, and Hlim.
#' @export
#'
#' @examples
#' data(dataspm)
#' pars <- log(c(0.164,6740,3564,0.05))
#' bestSP <- fitSPM(pars,fish=dataspm,funkone=TRUE)
#' ans <- plotspmmod(bestSP$estimate,dataspm,schaefer=TRUE,addrmse=TRUE)
#' str(ans)
#' outs <- spmphaseplot(ans,fnt=7)
#' str(outs)
spmphaseplot <- function(answer,Blim=0.2,Btarg=0.5,filename="",resol=200,
fnt=7) {
lenfile <- nchar(filename)
if (lenfile > 3) {
end <- substr(filename,(lenfile-3),lenfile)
if (end != ".png") filename <- paste0(filename,".png")
png(filename=filename,width=5.5,height=5.0,units="in",res=resol)
}
prod <- answer$BiomProd
rK <- answer$Dynamics$parameters
B0 <- rK[2]
Bmsy <- answer$Bmsy
fishery <- answer$Dynamics$outmat
Hmsy <- answer$MSY/answer$Bmsy
Hmax <- getmax(fishery[,"Harvest"])
numval <- length(which(fishery[,"Harvest"] > 0))
pickD <- which.closest(0.2*B0,prod[,"x"])
Hlim <- prod[pickD,"y"]/prod[pickD,"x"]
oldpar <- par(no.readonly=TRUE)
on.exit(par(oldpar))
par(mai=c(0.45,0.45,0.05,0.05),oma=c(0.0,0,0.0,0.0))
par(cex=0.75, mgp=c(1.35,0.35,0), font.axis=fnt,font=fnt,font.lab=fnt)
layout(matrix(c(1,2)),heights=c(3,1))
plot(fishery[,"ModelB"],fishery[,"Harvest"],type="l",lwd=2,col=1,
xlab="Biomass",ylab="Annual Harvest Rate",ylim=c(0,Hmax),yaxs="i",
xlim=c(0,B0))
points(fishery[,"ModelB"],fishery[,"Harvest"],pch=16,cex=1.0,col=4)
points(fishery[1,"ModelB"],fishery[1,"Harvest"],pch=16,cex=1.5,col=3)
points(fishery[numval,"ModelB"],fishery[numval,"Harvest"],pch=16,
cex=1.5,col=2)
abline(v=c(Blim*B0,Btarg*B0,B0),col=c(2,3,3),lty=2)
abline(h=c(Hmsy,Hlim),col=c(3,2),lty=2)
text(Bmsy,0.05*Hmax,"Btarg",cex=1.0,font=fnt,pos=4)
text(Blim*B0,0.05*Hmax,"Blim",cex=1.0,font=fnt,pos=4)
text(0,0.95*Hlim,"Hlim",cex=1.0,font=fnt,pos=4)
text(0,0.95*Hmsy,"Hmsy",cex=1.0,font=fnt,pos=4)
# plot the catch and harvets rates
yrs <- as.numeric(rownames(fishery))
par(mai=c(0.3,0.45,0.05,0.45))
cmax <- getmax(fishery[,"Catch"])
plot(yrs,fishery[,"Catch"],type="l",lwd=2,col=2,ylab="",xlab="",
ylim=c(0,cmax),yaxs="i",panel.first=grid(ny=0))
par(new=TRUE)
hmax <- getmax(fishery[,"Harvest"])
plot(yrs,fishery[,"Harvest"],type="l",lwd=2,col=4,ylim=c(0,hmax),
yaxt="n",ylab="",yaxs="i",xlab="")
points(yrs[1],fishery[1,"Harvest"],pch=16,cex=1.5,col=3)
points(yrs[numval],fishery[numval,"Harvest"],pch=16,cex=1.5,col=2)
abline(h=c(Hmsy),col=c(3),lty=2)
ym2 <- round(hmax,2)
axis(side=4,at=seq(0,ym2,length=3),labels = seq(0,ym2,length=3))
mtext("Catch (t)",side=2,outer=F,line=1.2,font=fnt,cex=1.0,col=2)
mtext("Harvest Rate",side=4,outer=F,line=1.1,font=fnt,cex=1.0,col=4)
if (lenfile > 0) {
outfile <- paste0(getwd(),"/",filename)
print(outfile)
dev.off()
}
result <- list(B0=B0,Bmsy=Bmsy,Hmsy=Hmsy,Hlim=Hlim)
return(invisible(result))
} # end of spmphaseplot
#' @title spmproj calculates biomass trajectories for replicate parameters
#'
#' @description spmproj uses a matrix of parameter vectors to project
#' surplus production dynamics forward including future projection
#' years under constant catches. This is used to conduct risk
#' assessments for different constant catches allowing a search for
#' optimum future catch levels.
#'
#' @param parmat a matrix of N parameter vectors obtained from either
#' asymptotic errors (parasympt), bootstraps (bootpar), or from a
#' Bayesian analysis (parsbayes).
#' @param indat the fisheries data used during model fitting
#' @param constC the constant catch level imposed in the projection years
#' @param projyr the number of years of projection, default = 10
#' @param year name of the year variable within indat, default=year
#' @param cats name of the catch variable within indat, default=catch
#' @param index name of the cpue variable within indat, default=cpue
#'
#' @return an N x years matrix of biomass trajectories, one for each
#' parameter vector
#' @export
#'
#' @examples
#' data(abdat)
#' schf <- FALSE
#' param <- log(c(r=0.3,K=11500,Binit=3300,sigma=0.05))
#' bestmod <- nlm(f=negLL1,p=param,funk=simpspm,logobs=log(abdat$cpue),
#' indat=abdat,typsize=magnitude(param),iterlim=1000,
#' schaefer=schf,hessian = TRUE)
#' out <- spm(bestmod$estimate,indat=abdat,schaefer=schf)
#' matpar <- parasympt(bestmod,10) # normally use 1000 or more
#' projs <- spmproj(matpar,abdat,projyr=10,constC=900)
#' plotproj(projs,out)
spmproj <- function(parmat,indat,constC,projyr=10,
year="year",cats="catch",index="cpue") {
N <- nrow(parmat)
lastyr <- max(indat[,year])
yrproj <- (lastyr+1):(lastyr+projyr)
addrow <- cbind(yrproj,rep(constC,projyr),rep(NA,projyr))
colnames(addrow) <- c(year,cats,index)
projfish <- rbind(indat,addrow)
yrs <- projfish[,year]
numyr <- length(yrs)
projbio <- matrix(0,nrow=N,ncol=numyr,dimnames=list(1:N,yrs))
for (i in 1:N) { # i=2 # calculate the dynamics for each parameter set
dynP <- spm(log(parmat[i,1:4]),projfish,schaefer=FALSE)
projbio[i,] <- dynP$outmat[1:numyr,"ModelB"]
}
return(projbio)
} # end of spmproj
#' @title spmprojDet conducts forward projections from known conditions
#'
#' @description spmprojDet conducts deterministic forward projections of the
#' dynamics of a fitted surplus production model. The parameters and
#' original data need to be put through the function spm to form the
#' spmobj, i.e. the list generated by the function spm. This contains
#' all required information except for details of the projection.
#' The application of spm is where the dynamics are defined as
#' either Schaefer or Fox. If no plot is generated then the
#' projected dynamics are output invisibly, where the biomass and
#' predCE are matrices of years vs projcatch.
#'
#' @param spmobj the list generated by the function spm
#' @param projcatch the projected constant catch levels as a vector
#' @param projyr the number of years of projection. default = 10
#' @param plotout should the projection be plotted? default=FALSE
#' @param useft which font used in a plot? default=7 = bold times
#'
#' @return the projected biomass, CPUE, and the projected years
#' @export
#'
#' @examples
#' data(abdat)
#' param <- log(c(r=0.3,K=11500,Binit=3300,sigma=0.05))
#' bestmod <- nlm(f=negLL1,p=param,funk=simpspm,logobs=log(abdat$cpue),
#' indat=abdat,typsize=magnitude(param),iterlim=1000,
#' schaefer=FALSE)
#' out <- spm(bestmod$estimate,indat=abdat,schaefer=FALSE)
#' catches <- seq(700,1000,50)
#' spmprojDet(spmobj = out,projcatch=catches,projyr=10,plotout=TRUE)
spmprojDet <- function(spmobj,projcatch,projyr=10,plotout=FALSE,useft=7) {
if (spmobj$schaefer) p <- 1.0 else p <- 1e-08
ep <- spmobj$parameters
dyn=spmobj$outmat;
dynyr <- dim(dyn)[1] - 1
yrs <- dyn[1:dynyr,"Year"]
lastyr <- dyn[dynyr,"Year"]
yrsp <- seq((lastyr+1),(lastyr+projyr),1)
lastproj <- max(yrsp)
numcat <- length(projcatch)
biom <- matrix(0,nrow=projyr,ncol=numcat,dimnames=list(yrsp,projcatch))
for (ctch in 1:numcat) {
biom[1,ctch] <- dyn[(dynyr+1),"ModelB"]
for (index in 1:(projyr-1)) {
Bt <- biom[index,ctch]
biom[index+1,ctch] <- max(Bt + ((ep[1]/p)*Bt*(1-(Bt/ep[2])^p)-
projcatch[ctch]),40)
}
}
if (plotout) {
oldpar <- par(no.readonly=TRUE)
on.exit(par(oldpar))
for (ctch in 1:numcat) {
if (ctch > 1) {
lines(yrsp,biom[,ctch],lwd=2,col=2)
text(lastproj,tail(biom[,ctch],1),projcatch[ctch],pos=4)
} else {
maxyr <- lastproj + 2
par(mfrow=c(1,1), mai=c(0.45,0.45,0.05,0.05), mgp=c(1.35,0.35,0))
par(cex=0.75, font.axis=useft, font=useft, font.lab=useft)
plot(dyn[,"Year"],dyn[,"ModelB"],type="l",lwd=2,
xlim=c(1985,maxyr),ylim=c(0,6500),yaxs="i",
xlab="Year",ylab="Stock Biomass (t)",panel.first=grid())
abline(v=(lastyr+0.5),col=3,lwd=2)
}
}
} # end of plotout ifloop
predCE=spmobj$parameters[5]*biom
answer <- list(biom=biom,predCE=predCE,projyear=yrsp)
return(answer)
} # end spmprojDet
#' @title summspm extracts critical statistics from output of plotspmmod
#'
#' @description summspm extracts critical statistics from output of
#' plotspmmod. In particular it pulls out the catchability q, the MSY,
#' Bmsy, Dmsy, Blim, Btarg, Ctarg. and Dcurr.
#'
#' @param ans the object output from the function plotspmmod used to plot
#' the output of a surplus production analysis
#'
#' @return a matrix of statistics relating to MSY, expected yields, and
#' depletion levels
#' @export
#'
#' @examples
#' data(dataspm)
#' plotfishM(dataspm,spsname="Pink Ling")
#' pars <- log(c(0.264,4740,3064,0.05))
#' ans <- plotspmmod(pars,dataspm,schaefer=FALSE,plotout=FALSE)
#' bestSP <- fitSPM(pars,dataspm,schaefer=FALSE,maxiter=1000)
#' outfit(bestSP)
#' ans <- plotspmmod(bestSP$estimate,dataspm,schaefer=FALSE,plotout=FALSE)
#' summspm(ans)
summspm <- function(ans) {
output <- c(ans$Dynamics$parameters["q"],ans$MSY,ans$Bmsy,ans$Dmsy,
ans$Blim,ans$Btarg, ans$Ctarg,ans$Dcurr)
output <- as.matrix(cbind(1:8,round(output,4)))
rownames(output) <- c("q","MSY","Bmsy","Dmsy","Blim","Btarg",
"Ctarg","Dcurr")
colnames(output) <- c("Index","Statistic")
return(output)
} # end of summspm
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.