diff --git a/src/nature/energy.jl b/src/nature/energy.jl index 74937b9bf8ab6dd1f56576e236205743be3b6066..e6e9c844b1463cf87861988b081f15c627773d64 100644 --- a/src/nature/energy.jl +++ b/src/nature/energy.jl @@ -3,6 +3,9 @@ ### This file contains structs and functions for implementing Dynamic Energy Budgets. ### + +## STRUCTS + """ DEBparameters @@ -10,13 +13,18 @@ An immutable struct to save the parameter list for a species' Dynamic Energy Bud model. (See Sousa et al., 2010.) """ struct DEBparameters + maxsearchrate::Float64 # maximum amount of food handled per day (F_m) assimilation::Float64 # percentage of food biomass assimilated (y_EX) + growthefficiency::Float64 # yield of structure on reserve (y_VE) + v::Float64 # energy conductance + surfacesomaticmaintenance::Float64 # surface-specific somatic maintenance (J_ET) + volumesomaticmaintenance::Float64 # volume-specific somatic maintenance (J_EM) + #maturitymaintenance::Float64 # specific maturity maintenance (k_J) kappa::Float64 # percentage allocated to somatic maintenance and growth (k) - juvenilesize::Float64 # structure size at which an embryo becomes a juvenile (MHb) - adultsize::Float64 # structure size at which a juvenile becomes an adult (MHp) - maintenance::Float64 # daily percentage of body size needed per update for somatic and maturity maintenance - reproduction::Float64 # energy needed to produce an egg (= initial amount of reserve) - v::Float64 # energy conductance (XXX ???) + reproductionefficiency::Float64 # overhead cost of reproduction (k_R) + eggsize::Float64 # weight of an egg/embryo, = initial amount of reserve (M_E0) + juvenilesize::Float64 # structure size at which an embryo becomes a juvenile (M_Hb) + adultsize::Float64 # structure size at which a juvenile becomes an adult (M_Hp) end """ @@ -50,32 +58,111 @@ Ecology, 85(7), 1771–1789. https://doi.org/10.1890/03-9000 """ mutable struct EnergyBudget params::DEBparameters - reserve::Float64 - structure::Float64 - offspring::Float64 + reserve::Float64 # M_E + structure::Float64 # M_V + #maturity::Float64 # M_H + offspring::Float64 # M_ER end + +## INTERNAL CALCULATIONS + """ - biomass(energybudget) + volumetriclength(energybudget) -Calculate the total biomass of an individual based on its energy budget. -(Sum of the reserve, structure, and offspring buffers; Sibly et al. 2013.) +Calculate the structural length in cm based on an individual's weight +(assuming a density of 1 g/cm³ to calculate volume, see Kooijman 2009). """ -function biomass(deb::EnergyBudget) - deb.reserve + deb.structure + deb.offspring +function volumetriclength(deb::EnergyBudget) + #TODO is cm the right unit? + weight = deb.reserve + deb.structure + deb.offspring + vlength = weight ^ (1/3) + vlength end """ - feed!(biomass, energybudget) + maturitymaintenance(energybudget) -Consume a given quantity of food. Expands the energy reserve by an -amount determined by the assimilation rate. +Calculate the specific maturity maintenance k_J. +(Internal function.) +""" +function maturitymaintenance(deb::EnergyBudget) + y_VE = deb.params.growthefficiency + J_EM = deb.params.volumesomaticmaintenance + M_V = deb.structure + k_J = (y_VE * J_EM) / M_V + k_J +end + +""" + scaledreservedensity(energybudget) + +Calculate the scaled reserve density e. +(Internal function.) """ -function feed!(biomass::Float64, deb::EnergyBudget) - deb.reserve += biomass * deb.params.assimilation - #TODO reserve doesn't grow infinitely +function scaledreservedensity(deb::EnergyBudget) + J_EAm = deb.params.assimilation * deb.params.maxsearchrate + m_E = deb.reserve / deb.structure + m_Em = J_EAm / (deb.params.v * deb.structure) + e = m_E / m_Em + e end +""" + investmentratio(energybudget) + +Calculate the investment ratio g. +(Internal function.) +""" +function investmentratio(deb::EnergyBudget) + J_EAm = deb.params.assimilation * deb.params.maxsearchrate + y_VE = deb.params.growthefficiency + k = deb.params.kappa + v = deb.params.v + M_V = deb.structure + g = (v * M_V) / (k * J_EAm * y_VE) + g +end + +""" + growthrate(energybudget) + +Calculate the specific growth rate r. +(Internal function.) +""" +function growthrate(deb::EnergyBudget) + J_EAm = deb.params.assimilation * deb.params.maxsearchrate + J_ET = deb.params.surfacesomaticmaintenance + J_EM = deb.params.volumesomaticmaintenance + k = deb.params.kappa + v = deb.params.v + e = scaledreservedensity(deb) + g = investmentratio(deb) + L = volumetriclength(deb) + L_m = k * (J_EAm / J_EM) # max length + L_T = J_ET / J_EM # heating length + r = v * (e/L - (1+L_T/L)/L_m) / (e+g) + r +end + +""" + mobilisation(energybudget) + +Calculate the mobilisation rate J_EC. +(Internal function.) +""" +function mobilisation(deb::EnergyBudget) + M_E = deb.reserve + r = growthrate(deb) + v = deb.params.v + L = volumetriclength(deb) + J_EC = M_E * (v/L - r) + J_EC +end + + +## PUBLIC INTERFACE + """ update!(energybudget) @@ -86,25 +173,76 @@ Return `true` if the individual has enough energy to survive, or `false` if the reserve is empty and it starves. """ function update!(deb::EnergyBudget) - #TODO - mobilisation = 0 - somaticmaintenance = deb.params.maintenance # J_ES - maturitymaintenance = deb.params.maintenance # J_EJ + J_ET = deb.params.surfacesomaticmaintenance + J_EM = deb.params.volumesomaticmaintenance + k_R = deb.params.reproductionefficiency + y_VE = deb.params.growthefficiency + #k_J = deb.params.maturitymaintenance + k_J = maturitymaintenance(deb) + L = volumetriclength(deb) + k = deb.params.kappa + M_V = deb.structure + #M_H = deb.maturity + M_E = deb.reserve + + J_EC = mobilisation(deb) + + ## Somatic maintenance and growth + J_ES = J_EM * (L^3) + J_ET * (L^2) # somatic maintenance + J_EG = J_EC * k - J_ES # energy devoted to growth + J_VG = J_EG * y_VE # actual growth + #J_VG = growthrate(deb) * deb.structure # r*M_V + #XXX check if J_VG == J_EG * y_VE == r * M_V + deb.structure += J_VG + # juveniles grow until they reach adult size + #XXX growth should stop automatically at M_V == M_Hp if deb.structure < adultsize growth = (mobilisation*deb.params.kappa) - somaticmaintenance deb.structure += growth end + # juveniles increase in maturity, adults invest into reproduction - maturityreproduction = (mobilisation*(1-deb.params.kappa)) - maturitymaintenance - if deb.structure >= adultsize - deb.offspring += maturityreproduction + J_EJ = k_J * M_H # maturity maintenance + J_ER = J_EC*(1-k) - J_EJ # resources for reproduction + if M_V >= deb.params.adultsize + deb.offspring += J_ER * k_R + else + #deb.maturity += J_ER #XXX I'm ignoring the maturity buffer for now end - - deb.reserve -= mobilisation + + #XXX Check that J_EC == J_ES + J_EG + J_EJ + J_ER + deb.reserve -= J_EC return deb.reserve > 0 end +""" + feed!(quantity, energybudget) + +Consume a given quantity of food. Expands the energy reserve by an +amount determined by the assimilation rate. Returns `true` if successful, +`false` if the reserve is already full. +""" +function feed!(quantity::Float64, deb::EnergyBudget) + F_m = deb.params.maxsearchrate + y_EX = deb.params.assimilation + M_V = deb.structure + M_E = deb.reserve + v = deb.params.v + + J_EAm = y_EX * F_m # max assimilation rate + m_E = M_E / M_V # reserve density + m_Em = J_EAm / (v * M_V) # max reserve density + + # only feed if the reserve is not yet at maximum capacity + if m_E < m_Em + deb.reserve += quantity * y_EX + return true + else + return false + end +end + """ reproduce!(energybudget) @@ -113,9 +251,14 @@ embryo/egg, reducing the parent energy in the process. Returns the embryo's ener budget, or `nothing` if the conditions are not met. """ function reproduce!(deb::EnergyBudget) - if deb.structure >= deb.params.adultsize && deb.offspring >= deb.params.reproduction - deb.offspring -= deb.params.reproduction - return EnergyBudget(deb.params, deb.params.reproduction, 0.0, 0.0) + M_V = deb.structure + M_ER = deb.offspring + M_Hp = deb.params.adultsize + M_E0 = deb.params.eggsize + + if M_V >= M_Hp && M_ER >= M_E0 + deb.offspring -= M_E0 + return EnergyBudget(deb.params, M_E0, 0.0, 0.0) else return nothing end