Skip to content

Commit

Permalink
getReproductionProportion() now always correctly returns a proporti…
Browse files Browse the repository at this point in the history
…on. Closing #299.
  • Loading branch information
gustavdelius committed Dec 8, 2024
1 parent e250c76 commit c2b7c50
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 65 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Authors@R: c(person("Gustav", "Delius", email="[email protected]",
comment = c(ORCID = "0000-0002-8478-3430")),
person("Richard", "Southwell", email="[email protected]",
role=c("ctb", "cph")))
Version: 2.5.3.9000
Version: 2.5.3.9001
License: GPL-3
Imports:
assertthat,
Expand Down
6 changes: 5 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
# Development version 2.5.3.9000
# Development version 2.5.3.9001

- `species` and `gears` columns are now never factors, so no longer need to
call `as.character()` so often.
- `validParams()` also calls `validGearParams()`.
- `validParams()` checks that `w_min` is valid for all species and increases it
if necessary.

## Bug fixes

- `getReproductionProportion()` no longer returns incorrect proportions > 1 (#299)

# mizer 2.5.3

A patch update so that users who had changed `w_max` manually in their model
Expand Down
112 changes: 56 additions & 56 deletions R/setReproduction.R
Original file line number Diff line number Diff line change
@@ -1,68 +1,68 @@
#' Set reproduction parameters
#'
#'
#' Sets the proportion of the total energy available for reproduction and growth
#' that is invested into reproduction as a function of the size of the
#' individual and sets additional density dependence.
#'
#'
#' @section Setting reproduction:
#'
#' For each species and at each size, the proportion \eqn{\psi}{psi} of the
#' available energy
#'
#' For each species and at each size, the proportion \eqn{\psi}{psi} of the
#' available energy
#' that is invested into reproduction is the product of two factors: the
#' proportion `maturity` of individuals that are mature and the proportion
#' `repro_prop` of the energy available to a mature individual that is
#' `repro_prop` of the energy available to a mature individual that is
#' invested into reproduction. There is a size `w_repro_max` at which all the
#' energy is invested into reproduction and therefore all growth stops. There
#' can be no fish larger than `w_repro_max`. If you have not specified the
#' `w_repro_max` column in the species parameter data frame, then the maximum size
#' `w_max` is used instead.
#'
#'
#' \subsection{Maturity ogive}{
#' If the the proportion of individuals that are mature is not supplied via
#' the `maturity` argument, then it is set to a sigmoidal
#' the `maturity` argument, then it is set to a sigmoidal
#' maturity ogive that changes from 0 to 1 at around the maturity size:
#' \deqn{{\tt maturity}(w) = \left[1+\left(\frac{w}{w_{mat}}\right)^{-U}\right]^{-1}.}{
#' maturity(w) = [1+(w/w_mat)^(-U)]^(-1)}
#' (To avoid clutter, we are not showing the species index in the equations,
#' although each species has its own maturity ogive.)
#' The maturity weights are taken from the `w_mat` column of the
#' The maturity weights are taken from the `w_mat` column of the
#' species_params data frame. Any missing maturity weights are set to 1/4 of the
#' maximum weight in the `w_max` column.
#'
#'
#' The exponent \eqn{U} determines the steepness of the maturity ogive. By
#' default it is chosen as \eqn{U = 10}, however this can be overridden by
#' including a column \code{w_mat25} in the species parameter dataframe that
#' specifies the weight at which 25% of individuals are mature, which sets
#' \eqn{U = \log(3) / \log(w_{mat} / w_{mat25}).}{U = log(3) / log(w_mat /
#' w_mat25).}
#'
#'
#' The sigmoidal function given above would strictly reach 1 only
#' asymptotically. Mizer instead sets the function equal to 1 already at a size
#' taken from the `w_repro_max` column in the species parameter data frame, if it
#' exists, or otherwise from the `w_max` column. Also, for computational
#' simplicity, any proportion smaller than `1e-8` is set to `0`.
#' }
#'
#'
#' \subsection{Investment into reproduction}{
#' If the the energy available to a mature individual that is
#' If the the energy available to a mature individual that is
#' invested into reproduction is not supplied via the `repro_prop` argument,
#' it is set to the allometric form
#' \deqn{{\tt repro\_prop}(w) = \left(\frac{w}{w_{\tt{repro\_max}}}\right)^{m-n}.}{
#' repro_prop(w) = (w/w_repro_max)^(m - n).}
#' Here \eqn{n} is the scaling exponent of the energy income rate. Hence
#' the exponent \eqn{m} determines the scaling of the investment into
#' reproduction for mature individuals. By default it is chosen to be
#' \eqn{m = 1} so that the rate at which energy is invested into reproduction
#' scales linearly with the size. This default can be overridden by including a
#' reproduction for mature individuals. By default it is chosen to be
#' \eqn{m = 1} so that the rate at which energy is invested into reproduction
#' scales linearly with the size. This default can be overridden by including a
#' column `m` in the species parameter dataframe. The maximum sizes are taken
#' from the `w_repro_max` column in the species parameter data frame, if it
#' exists, or otherwise from the `w_max` column.
#'
#'
#' The total proportion of energy invested into reproduction of an individual
#' of size \eqn{w} is then
#' \deqn{\psi(w) = {\tt maturity}(w){\tt repro\_prop}(w)}{psi(w) = maturity(w) * repro_prop(w)}
#' }
#'
#'
#' \subsection{Reproductive efficiency}{
#' The reproductive efficiency \eqn{\epsilon}, i.e., the proportion of energy allocated to
#' reproduction that results in egg biomass, is set through the `erepro`
Expand All @@ -72,7 +72,7 @@
#' [getRDI()]:
#' \deqn{R_{di} = \frac{\epsilon}{2 w_{min}} \int N(w) E_r(w) \psi(w) \, dw}{R_di = (\epsilon/(2 w_min)) \int N(w) E_r(w) \psi(w) dw}
#' }
#'
#'
#' \subsection{Density dependence}{
#' The stock-recruitment relationship is an emergent phenomenon in mizer, with
#' several sources of density dependence. Firstly, the amount of energy invested
Expand All @@ -81,7 +81,7 @@
#' larvae that grow up to recruitment size depends on the larval mortality,
#' which depends on the density of predators, and on larval growth rate, which
#' depends on density of prey.
#'
#'
#' Finally, to encode all the density dependence in the stock-recruitment
#' relationship that is not already included in the other two sources of density
#' dependence, mizer puts the the density-independent rate of egg production
Expand Down Expand Up @@ -109,11 +109,11 @@
#' were previously overwritten with custom values. If set to FALSE (default)
#' then a recalculation from the species parameters will take place only if no
#' custom values have been set.
#' @param RDD The name of the function calculating the density-dependent
#' reproduction rate from the density-independent rate. Defaults to
#' @param RDD The name of the function calculating the density-dependent
#' reproduction rate from the density-independent rate. Defaults to
#' "[BevertonHoltRDD()]".
#' @param ... Unused
#'
#'
#' @return `setReproduction()`: A MizerParams object with updated reproduction
#' parameters.
#' @export
Expand All @@ -123,12 +123,12 @@
#' # Plot maturity and reproduction ogives for Cod in North Sea model
#' maturity <- getMaturityProportion(NS_params)["Cod", ]
#' repro_prop <- getReproductionProportion(NS_params)["Cod", ]
#' df <- data.frame(Size = w(NS_params),
#' Reproduction = repro_prop,
#' Maturity = maturity,
#' df <- data.frame(Size = w(NS_params),
#' Reproduction = repro_prop,
#' Maturity = maturity,
#' Total = maturity * repro_prop)
#' dff <- melt(df, id.vars = "Size",
#' variable.name = "Type",
#' dff <- melt(df, id.vars = "Size",
#' variable.name = "Type",
#' value.name = "Proportion")
#' library(ggplot2)
#' ggplot(dff) + geom_line(aes(x = Size, y = Proportion, colour = Type))
Expand All @@ -144,24 +144,24 @@ setReproduction <- function(params, maturity = NULL,
exists(RDD),
is.function(get(RDD)))
species_params <- params@species_params

if (reset) {
if (!is.null(maturity)) {
warning("Because you set `reset = TRUE`, the value you provided ",
warning("Because you set `reset = TRUE`, the value you provided ",
"for `maturity` will be ignored and a value will be ",
"calculated from the species parameters.")
maturity <- NULL
}
comment(params@maturity) <- NULL
if (!is.null(repro_prop)) {
warning("Because you set `reset = TRUE`, the value you provided ",
warning("Because you set `reset = TRUE`, the value you provided ",
"for `repro_prop` will be ignored and a value will be ",
"calculated from the species parameters.")
repro_prop <- NULL
}
comment(params@psi) <- NULL
}

# Check maximum sizes
if (!("w_max" %in% colnames(species_params))) {
stop("The maximum sizes of the species must be specified in the w_max ",
Expand All @@ -180,12 +180,12 @@ setReproduction <- function(params, maturity = NULL,
# idx <- which.min(abs(species_params$w_max[i] - params@w))
# params@species_params$w_max[i] < params@w[idx]
# }

# set maturity proportion ----
if (!is.null(maturity)) {
assert_that(is.array(maturity),
identical(dim(maturity), dim(params@psi)))
if (!is.null(dimnames(maturity)) &&
if (!is.null(dimnames(maturity)) &&
!all(dimnames(maturity)[[1]] == species_params$species)) {
stop("You need to use the same ordering of species as in the ",
"params object: ", toString(species_params$species))
Expand Down Expand Up @@ -213,18 +213,18 @@ setReproduction <- function(params, maturity = NULL,
assert_that(all(species_params$w_mat > species_params$w_min))
assert_that(all(species_params$w_mat < species_params$w_max))
params@species_params$w_mat <- species_params$w_mat

# Set defaults for w_mat25
species_params <- set_species_param_default(
species_params, "w_mat25",
species_params, "w_mat25",
species_params$w_mat / (3 ^ (1 / 10)))
# Check w_mat25
assert_that(all(species_params$w_mat25 > species_params$w_min))
assert_that(all(species_params$w_mat25 < species_params$w_mat))
params@species_params$w_mat25 <- species_params$w_mat25

maturity <- params@maturity # To get the right dimensions
maturity[] <-
maturity[] <-
unlist(
tapply(params@w, seq_along(params@w),
function(wx, w_mat, w_mat25) {
Expand All @@ -235,10 +235,10 @@ setReproduction <- function(params, maturity = NULL,
w_mat25 = species_params$w_mat25
)
)
# For reasons of efficiency we next set all very small values to 0

# For reasons of efficiency we next set all very small values to 0
maturity[maturity < 1e-8] <- 0

# If maturity is protected by a comment, keep the old value
if (!is.null(comment(params@maturity))) {
if (different(params@maturity, maturity)) {
Expand All @@ -249,21 +249,21 @@ setReproduction <- function(params, maturity = NULL,
}
}
assert_that(all(maturity >= 0 & maturity <= 1))

# Need to update psi because it contains maturity as a factor
if (different(params@maturity, maturity)) {
params@psi[] <- params@psi / params@maturity * maturity
params@psi[is.nan(params@psi)] <- 0
}

params@maturity[] <- maturity
comment(params@maturity) <- comment(maturity)

# set reproduction proportion ----
if (!is.null(repro_prop)) {
assert_that(is.array(repro_prop),
identical(dim(repro_prop), dim(params@psi)))
if (!is.null(dimnames(repro_prop)) &&
if (!is.null(dimnames(repro_prop)) &&
!all(dimnames(repro_prop)[[1]] == species_params$species)) {
stop("You need to use the same ordering of species as in the ",
"params object: ", toString(species_params$species))
Expand All @@ -285,7 +285,7 @@ setReproduction <- function(params, maturity = NULL,
# Set defaults for w_repro_max
species_params <- set_species_param_default(species_params, "w_repro_max",
params@species_params$w_max)

repro_prop <- array(
unlist(
tapply(params@w, seq_along(params@w),
Expand All @@ -296,17 +296,17 @@ setReproduction <- function(params, maturity = NULL,
), dim = c(nrow(species_params), length(params@w)))
repro_prop[repro_prop > 1] <- 1
}

psi <- params@maturity * repro_prop
# psi should never be larger than 1
psi[psi > 1] <- 1
# Set psi for all w > w_repro_max to 1
psi[outer(species_params$w_repro_max, params@w, "<")] <- 1
assert_that(all(psi >= 0 & psi <= 1))

# if the slot is protected and the user did not supply a new repro_prop
# then don't overwrite the slot with auto-generated values. We can
# detect whether repro_prop is user-supplied by checking whether it has
# detect whether repro_prop is user-supplied by checking whether it has
# a comment.
if (!is.null(comment(params@psi)) && is.null(comment(repro_prop))) {
if (different(params@psi, psi)) {
Expand All @@ -317,36 +317,36 @@ setReproduction <- function(params, maturity = NULL,
params@psi[] <- psi
comment(params@psi) <- comment(repro_prop)
}

# If no erepro (reproductive efficiency), then set to 1
params <- set_species_param_default(params, "erepro", 1)
if (!all(params@species_params$erepro > 0)) {
stop("Some species have negative reproductive efficiency.")
}

# RDD function is currently called only with three arguments
if (!all(names(formals(RDD)) %in% c("rdi", "species_params", "params", "t", "..."))) {
stop("Arguments of RDD function can only contain 'rdi', 'species_params' and `t`.")
}
params@rates_funcs$RDD <- RDD
if (identical(params@rates_funcs$RDD, "BevertonHoltRDD")) {

# for legacy reasons (R_max used to be called r_max):
if ("r_max" %in% names(params@species_params)) {
params@species_params$R_max <- params@species_params$r_max
params@species_params$r_max <- NULL
message("The 'r_max' column has been renamed to 'R_max'.")
}

params <- set_species_param_default(params, "R_max", Inf)
}

params@time_modified <- lubridate::now()
return(params)
}

#' @rdname setReproduction
#' @return `getMaturityProportion()` or equivalently `maturity():
#' @return `getMaturityProportion()` or equivalently `maturity():
#' An array (species x size) that holds the proportion
#' of individuals of each species at size that are mature.
#' @export
Expand Down Expand Up @@ -379,11 +379,11 @@ getReproductionProportion <- function(params) {
assert_that(is(params, "MizerParams"))
repro_prop <- params@psi / params@maturity
repro_prop[is.nan(repro_prop)] <- 0
repro_prop[repro_prop > 1] <- 1
comment(repro_prop) <- comment(params@psi)
repro_prop
}


#' @rdname setReproduction
#' @export
repro_prop <- function(params) {
Expand Down
Loading

0 comments on commit c2b7c50

Please sign in to comment.