Custom Management Procedures

openMSE was designed to be extensible in order to promote the development of new Management Procedures. In this section we design a series of new Management Procedures that include spatial controls and input controls in the form of size limit restrictions.

If you wish, you can also add your newly developed MPs to the package so they are accessible to other uses. Of course you will be credited as the author. Please contact us for details how to do this.

As described in the Populating the Data object section, real data are stored in a class of objects Data.

The runMSE function generates simulated data and puts it in exactly the same format as real data. This is highly desirable because it means that the same MP code that is tested in the MSE can then be used to make management recommendations.

If an MP is coded incorrectly it may catastrophically fail MSE testing and will therefore be excluded from use in management.

A Constant Catch MP

We’ve now got a better idea of the anatomy of an MP. It is a function that must accept three arguments (we will ignore plot for now):

  • x: a simulation number
  • Data: an object of class Data
  • reps: the MP can provide a sample of TACs reps long.

Let’s have a go at designing our own custom MP that can work with openMSE We’re going to develop an MP that sets the TAC as the ‘3rd highest catch’.

We decide to call our function THC

THC<-function(x, Data, reps){
  
  # Find the position of third highest catch
  
  THCpos<-order(Data@Cat[x,],decreasing=T)[3]
  
  # Make this the mean TAC recommendation
  
  THCmu<-Data@Cat[x,THCpos]
  
  # A sample of the THC is taken according to a fixed CV of 10%
  TACs <- THCmu * exp(rnorm(reps, -0.1^2/2, 0.1)) # this is a lognormal distribution

  Rec <- new("Rec") # create a 'Rec'object
  Rec@TAC <- TACs # assign the TACs to the TAC slot
  Rec # return the Rec object
}

To recap that’s just seven lines of code:

THC<-function(x, Data, reps){
  THCpos<-order(Data@Cat[x,],decreasing=T)[3]
  THCmu<-Data@Cat[x,THCpos]
  Rec <- new("Rec")
  Rec@TAC <- THCmu * exp(rnorm(reps, -0.1^2/2, 0.1))
  Rec
}

We can quickly test our new MP for the example Data object

THC(x=1,Data,reps=10)@TAC
##  [1] 4084.666 4233.960 4320.225 4247.745 3975.688 4635.546 4017.359 4417.738
##  [9] 4813.774 5363.664

Now that we know it works, to make the function compatible with the DLMtool package we have to assign it the class ‘MP’ so that DLMtool recognizes the function as a management procedure

class(THC)<-"MP"

A More Complex MP

The THC MP is simple and frankly not a great performer (depending on depletion, life-history, adherence to TAC recommendations).

Let’s innovate and create a brand new MP that could suit a catch-data-only stock like Indian Ocean Longtail tuna!

It may be possible to choose a single fleet and establish a catch rate that is ‘reasonable’ or ‘fairly productive’ relative to current catch rates. This could be for example, 40% of the highest catch rate observed for this fleet or, for example, 150% of current cpue levels.

It is straightforward to design an MP that will aim for this target index level by making adjustments to the TAC.

We will call this MP TCPUE, short for target catch per unit effort:

TCPUE<-function(x,Data,reps=100){
  
  mc<-0.05                             # max change in TAC 
  frac<-0.3                            # target index is 30% of max
  nyears<-length(Data@Ind[x,])         # number of years of data
  
  smoothI<-smooth.spline(Data@Ind[x,]) # smoothed index  
  targetI<-max(smoothI$y)*frac         # target 
  
  currentI<-mean(Data@Ind[x,(nyears-2):nyears]) # current index
  
  ratio<-currentI/targetI              # ratio currentI/targetI
  
  if(ratio < (1 - mc)) ratio <- 1 - mc # if currentI < targetI
  if(ratio > (1 + mc)) ratio <- 1 + mc # if currentI > targetI
 
  Rec <- new("Rec")
  Rec@TAC <- Data@MPrec[x] * ratio * exp(rnorm(reps, -Data@CV_Ind[x]^2/2, Data@CV_Ind[x]))
  Rec
}

The TCPUE function simply decreases the past TAC (stored in Data@MPrec) if the index is lower than the target and increases the TAC if the index is higher than the target.

All that is left is to assign the function as class MP so that openMSE recognizes it as a management procedure:

class(TCPUE)<-"MP"

Beyond the Catch Limit

All management procedures return an object of class Rec that contains 13 slots:

slotNames("Rec")
##  [1] "TAC"      "Effort"   "Spatial"  "Allocate" "LR5"      "LFR"     
##  [7] "HS"       "Rmaxlen"  "L5"       "LFS"      "Vmaxlen"  "Fdisc"   
## [13] "DR"       "Misc"

We’ve already seen the TAC slot in the previous example. The remaining slots relate to various forms of input control:

  • Effort (total allowable effort (TAE) relative to last historical year)
  • Spatial - Fraction of each area that is open
  • Allocate - Allocation of effort from closed areas to open areas
  • LR5 - Length at 5% retention
  • LFR - Length at 100% retention
  • HS - Upper slot limit
  • Rmaxlen - Retention of the maximum length class
  • L5 - Length at 5% selection (e.g a change in gear type)
  • LFS - Length at 100% selection (e.g a change in gear type)
  • Vmaxlen - Selectivity of the maximum length class
  • Fdisc - Update the discard mortality if required
  • Misc - An optional slot for storing additional information

See the help documentation or type class?Rec in the R console for more information on the contents of the Rec object.

The curE MP just keeps effort constant at current levels:

curE
## function (x, Data, reps, plot = FALSE) 
## {
##     rec <- new("Rec")
##     rec@Effort <- 1
##     if (plot) 
##         curE_plot(x, rec, Data)
##     rec
## }
## <bytecode: 0x000000001d76bf68>
## <environment: namespace:DLMtool>
## attr(,"class")
## [1] "MP"

Note that only the Effort slot in the Rec object is populated in this case.

To highlight the differences among Input control MPs, examine the spatial control MP MRreal that closes area 1 to fishing and reallocates fishing to the open area 2:

MRreal
## function (x, Data, reps, plot = FALSE) 
## {
##     rec <- new("Rec")
##     rec@Allocate <- 1
##     rec@Spatial <- c(0, rep(1, Data@nareas - 1))
##     if (plot) 
##         barplot(rec@Spatial, xlab = "Area", ylab = "Fraction Open", 
##             ylim = c(0, 1), names = 1:Data@nareas)
##     return(rec)
## }
## <bytecode: 0x000000001d8e1fc8>
## <environment: namespace:DLMtool>
## attr(,"class")
## [1] "MP"

In contrast MRnoreal does not reallocate fishing effort:

MRnoreal
## function (x, Data, reps, plot = FALSE) 
## {
##     rec <- new("Rec")
##     rec@Allocate <- 0
##     rec@Spatial <- c(0, rep(1, Data@nareas - 1))
##     if (plot) 
##         barplot(rec@Spatial, xlab = "Area", ylab = "Fraction Open", 
##             ylim = c(0, 1), names = 1:Data@nareas)
##     return(rec)
## }
## <bytecode: 0x000000001da75a08>
## <environment: namespace:DLMtool>
## attr(,"class")
## [1] "MP"

The MP matlenlim only specifies the parameters of length retention using an estimate of length at 50% maturity (Stock@L50):

matlenlim
## function (x, Data, reps, plot = FALSE) 
## {
##     rec <- new("Rec")
##     rec@LFR <- Data@L50[x]
##     rec@LR5 <- rec@LFR * 0.95
##     if (plot) 
##         size_lim_plot(x, Data, rec)
##     rec
## }
## <bytecode: 0x000000001dd82db0>
## <environment: namespace:DLMtool>
## attr(,"class")
## [1] "MP"

An Example Effort Control

Here we will copy and modify the MP we developed earlier to specify a new version of the target catch per unit effort MP (TCPUE) that provides effort recommendations:

TCPUE_e<-function(x,Data,reps=100){
  
  mc<-0.05                             # max change in TAC 
  frac<-0.3                            # target index is 30% of max
  nyears<-length(Data@Ind[x,])         # number of years of data
  
  smoothI<-smooth.spline(Data@Ind[x,]) # smoothed index  
  targetI<-max(smoothI$y)*frac         # target 
  
  currentI<-mean(Data@Ind[x,(nyears-2):nyears]) # current index
  
  ratio<-currentI/targetI              # ratio currentI/targetI
  
  if(ratio < (1 - mc)) ratio <- 1 - mc # if currentI < targetI
  if(ratio > (1 + mc)) ratio <- 1 + mc # if currentI > targetI
  
  rec <- new("Rec")
  rec@Effort <- Data@MPeff[x] * ratio
  rec
  
}

There have been surprisingly few changes to make TCPUE an input control MP that sets total allowable effort.

  1. We have had to use stored recommendations of effort in the Data@MPeff slot, and
  2. The final line of the MP is our input control recommendation that only modified the Effort.

That is all. Again, we need to assign our new function to class MP:

class(TCPUE_e)<-"MP"

Let’s test the two MPs and see how they [perform](/welcome-a-quick-tour/examining-results/:

testMSE<-runMSE(testOM,MPs=c("TCPUE","TCPUE_e"))
## Checking MPs
## Loading operating model
## Optimizing for user-specified movement
## Optimizing for user-specified depletion in last historical year
## Calculating historical stock and fishing dynamics
## Calculating MSY reference points for each year
## Calculating B-low reference points
## Calculating reference yield - best fixed F strategy
## Simulating observed data
## Running forward projections
## 1 / 2 Running MSE for TCPUE
## ..................................................
## 2 / 2 Running MSE for TCPUE_e
## ..................................................
NOAA_plot(testMSE)

##         PNOF B50  LTY    VY
## TCPUE   55.3  62 66.7 100.0
## TCPUE_e 10.0  40 66.7  33.3