Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

A Bayesian implementation of a Schaefer Surplus Production population dynamics model

A Bayesian implementation of a Schaefer Surplus Production population dynamics model

Background

A Surplus Production Model (SPM) describes the population biomass dynamics as a single biomass entity, conditioned on relative abundance observations. SPMs are based on theta-logistic density-dependent population growth theory, where population growth rates are higher at low abundance, and lower when approaching the carrying capacity.

For a SPM in discrete time, the biomass (B) at a given point in time (usually years) can be described as a function of the biomass, surplus production (P), and catch (C) at the previous year.

Bt=Bt−1+Pt−1−Ct−1B_{t} = B_{t-1} + P_{t-1} - C_{t-1}

The surplus production PP (i.e. the population growth in biomass at a given point in time) is a function of two parameters: the intrinsic rate of increase (rr), and carrying capacity (K):

Pt=rBt(1−BtK)−FtBtP_{t} = rB_{t}\left(1 - \frac{B_{t}}{K}\right) - F_{t}B_{t}

Observations are indices of relative abundance (II) scaled to biomass through (estimated) cachability coefficients qq:

I^=qBt\hat{I} = qB_{t}

Model Setup

  • Data: Observed catches C and one or more survey indices (columns starting with “Survey” followed by a number) over multiple years.

Likelihood

For each survey index, the likelihood is based on the log-normal errors between observed survey values and predicted biomass. The model assumes:

  • The observed survey index at time tt is ItI_t.

  • The predicted biomass at time tt (from the Schaefer model) is BtB_t.

  • The catchability coefficient QQ scales the expected survey to the biomass:

    Q=exp⁡(1n∑t=1nlog⁡(ItBt))Q = \exp\left(\frac{1}{n} \sum_{t=1}^n \log\left(\frac{I_t}{B_t}\right)\right)
  • The scaled prediction for the survey is Pt=It/QP_t = I_t / Q.

The residuals follow a log-normal distribution:

log⁡(BtPt)∼N(0,σ2)\log\left(\frac{B_t}{P_t}\right) \sim N(0, \sigma^2)

This means that for each year tt, the probability density of observing ItI_t given predicted BtB_t and σ\sigma is:

p(It∣Bt,Q,σ)=12π σexp⁡(−12σ2[log⁡(BtIt/Q)]2)p(I_t \mid B_t, Q, \sigma) = \frac{1}{\sqrt{2\pi}\,\sigma} \exp\left( -\frac{1}{2\sigma^2} \left[\log\left(\frac{B_t}{I_t/Q}\right)\right]^2 \right)

For each residual:

residualt=log⁡(BtIt/Q)\text{residual}_t = \log\left(\frac{B_t}{I_t/Q}\right)

and

p(residualt∣σ)=12π σexp⁡(−residualt22σ2)p(\text{residual}_t \mid \sigma) = \frac{1}{\sqrt{2\pi}\,\sigma} \exp\left( -\frac{\text{residual}_t^2}{2\sigma^2} \right)

The total likelihood across years is the product of these normal pdfs across observations.


Prior

  • Priors are placed on the parameters:

    • r∼N(μr,σr2)r \sim N(\mu_r, \sigma^2_r)

    • k∼N(μk,σk2)k \sim N(\mu_k, \sigma^2_k)

    • σ∼N(μσ,σσ2)\sigma \sim N(\mu_\sigma, \sigma^2_\sigma)

  • These are combined into the total NLL for use in Metropolis-Hastings.


Posterior

  • The (unormalized) posterior combines the likelihood and priors:

    p(r,k,σ∣data)∝p(data∣r,k,σ)⋅p(r)⋅p(k)⋅p(σ)p(r, k, \sigma | \text{data}) \propto p(\text{data} | r, k, \sigma) \cdot p(r) \cdot p(k) \cdot p(\sigma)

Metropolis-Hastings Algorithm Steps in the Code

  1. Initialization:

    • Chains are initialized at given starting values (inits).

  2. Proposal Step:

    • At each iteration, propose new values for rr, kk, and σ\sigma using normal random walks:

      r∗∼N(r(t−1),δ1),k∗∼N(k(t−1),δ2),σ∗∼∣N(σ(t−1),δ2)∣r^* \sim N(r^{(t-1)}, \delta_{1}), \quad k^* \sim N(k^{(t-1)}, \delta_{2}), \quad \sigma^* \sim |N(\sigma^{(t-1)}, \delta_{2})|
    • Hard rejection if the proposed r∗≤0r^* \leq 0.

  3. Acceptance Ratio:

    • Compute the difference in negative log-likelihoods (including priors) between proposal and current values.

    • Accept the proposal with probability min⁡(1,exp⁡(logR))\min(1, \exp(\text{logR})).

  4. Update Step:

    • If accepted, set (r,k,σ)(t)=(r∗,k∗,σ∗)(r, k, \sigma)^{(t)} = (r^*, k^*, \sigma^*); otherwise, retain previous values.

    • Repeat for nIter iterations, discarding nBurnIn as burn-in.

You can find some example usage below. Be warned that way more iterations (nIter and nBurnIn) are needed to achieve appropriate chain mixing and accurate parameter estimation. The example in this cookbook runs with fewer iterations due to computational limitations involved in deploying the cookbook.

Data loaded: (106, 4)
<Figure size 1500x800 with 6 Axes>
Chain 1 parameter means and SDs:
                Mean          SD
r           0.197385    0.002951
k      144017.244617  235.361362
sigma       0.891963    0.088519

Chain 2 parameter means and SDs:
                Mean          SD
r           0.196143    0.002650
k      144056.637323  210.385167
sigma       0.808503    0.085225

<Figure size 1500x500 with 3 Axes>
{'biomass_mean': array([144056.63732285, 143978.63732285, 143871.92822773, 143768.11070624, 143727.58823719, 143692.97824653, 143682.12252692, 143684.38364952, 143679.20227326, 143703.03088565, 143710.20854022, 143682.98467648, 143677.07355217, 143662.31532055, 143652.43585114, 143619.48299691, 143604.95546614, 143593.25927165, 143597.84208635, 143596.5312428 , 143588.47548798, 143568.98932042, 143561.29957275, 143574.10744542, 143591.41982854, 143561.35864079, 143528.15441532, 143484.41646481, 143105.19146332, 142329.56167036, 141043.23491192, 140461.90277321, 140506.35019897, 140707.49625249, 140975.06578666, 141142.48709121, 141148.43111999, 141165.25329715, 141251.90628796, 141343.23295272, 141400.3316539 , 141310.64813336, 141077.89622792, 140947.98281541, 140872.47255346, 140672.12381843, 140643.27810231, 140538.81994878, 140777.86199805, 140805.22617317, 141168.46547699, 137436.49322518, 133854.21550413, 133325.50901376, 134426.39728174, 135336.83491938, 135851.41678469, 136449.90949347, 136706.88662357, 137171.68912687, 137585.3303395 , 137477.36243068, 137623.65910685, 137259.85579597, 129142.86214572, 109924.04908076, 87173.46992059, 67893.93883369, 64492.51066006, 61135.01371456, 58706.24282091, 55754.34241157, 49363.4321558 , 45082.70358496, 38448.76488138, 33515.12736843, 31762.10433922, 30205.71294487, 26539.87620543, 24067.69785609, 21085.07546541, 18291.57991383, 14765.16522528, 13207.35764579, 11445.54395897, 9463.03312172, 9210.77276375, 10437.80938123, 12244.89304826, 14286.0678756 , 16520.92952671, 19051.4171225 , 21891.15210705, 25062.43028658, 28688.63222166, 32716.05734639, 37103.59925582, 41804.40298388, 46664.59922028, 51585.65504621, 56968.73522657, 62485.81964823, 63875.34311192, 60773.10745313, 57686.91946691, 55559.35528873]), 'biomass_lower': array([143734.09231232, 143656.09231232, 143550.1395661 , 143446.53648257, 143405.85134656, 143371.08430548, 143360.08001917, 143362.21556054, 143356.93586307, 143380.68273773, 143387.8117288 , 143360.55409703, 143354.59745884, 143339.79898317, 143329.87739063, 143296.88426202, 143282.30209567, 143270.55247647, 143275.08476892, 143273.73688235, 143265.65076352, 143246.1349142 , 143238.40817814, 143251.18134563, 143268.47491547, 143238.41065518, 143205.18334186, 143161.40421939, 142782.11641866, 142006.17640568, 140719.07099029, 140136.23691958, 140179.08024179, 140378.96630023, 140645.66166668, 140812.56662344, 140818.21302272, 140834.80061924, 140921.27723761, 141012.52317961, 141069.62124545, 140979.97733714, 140747.19435046, 140617.09292887, 140541.34074703, 140340.74482236, 140311.56005895, 140206.80913769, 140445.54246434, 140472.82658176, 140836.02086218, 137104.26859632, 133519.55994078, 132986.39399629, 134083.24043857, 134991.12692356, 135504.27024162, 136101.96012332, 136358.71994099, 136823.53441494, 137237.52785872, 137130.15152552, 137276.84967936, 136913.48031684, 128796.57277943, 109572.00299395, 86803.40105487, 67492.64635301, 64027.59034471, 60599.791183 , 58095.97110021, 55064.01770089, 48586.24883405, 44205.2697752 , 37457.67768343, 32389.3312699 , 30478.44116219, 28743.13775244, 24874.09673023, 22162.59116537, 18900.81378583, 15777.28626288, 11859.23672156, 9828.91491102, 7508.89087289, 4862.59874123, 3815.37618752, 4109.55441537, 4844.85525605, 5669.4110967 , 6534.77714401, 7536.33853476, 8686.83158717, 10013.06498394, 11649.94942308, 13568.5391562 , 15761.18621702, 18223.68934715, 20853.3550096 , 23602.90920617, 26924.32675444, 30577.23206155, 30370.99746904, 25626.62575655, 20425.18997299, 15561.30628714]), 'biomass_upper': array([144430.51637464, 144352.51637464, 144245.87053145, 144142.19087386, 144101.86452386, 144067.44670263, 144056.77516174, 144059.19470681, 144054.14016981, 144078.07599312, 144085.32133647, 144058.1465694 , 144052.29740485, 144037.59427284, 144027.77152781, 143994.87275903, 143980.41593931, 143968.78899396, 143973.43757092, 143972.17641399, 143964.1620733 , 143944.71608746, 143937.07482761, 143949.92834469, 143967.26737602, 143937.21372323, 143904.04007109, 143860.35398758, 143481.20674596, 142705.94865997, 141420.55436774, 140841.02540996, 140887.421876 , 141090.13162042, 141358.81954708, 141526.9375545 , 141533.31382828, 141550.48470436, 141637.4089742 , 141728.88558313, 141786.03089107, 141696.3377782 , 141463.65225953, 141333.98624074, 141258.78639792, 141058.75471206, 141030.33526683, 140926.25071654, 141165.68609874, 141193.17376946, 141556.49134582, 137824.27971209, 134244.89447948, 133721.52306719, 134827.31949352, 135740.95373675, 136257.43432637, 136857.06817587, 137114.47733509, 137579.41509187, 137992.76347822, 137884.19152717, 138030.08094911, 137665.81246861, 129548.74867211, 110336.7738998 , 87607.5920285 , 68486.66454683, 65425.06189206, 62418.39200105, 60356.297999 , 57789.30702227, 51808.24607149, 47983.78349172, 41854.64483408, 37499.42535447, 36407.65253983, 35591.70105026, 32756.92410365, 31246.09982891, 29367.76184722, 27857.8286277 , 25827.82779695, 26040.03611879, 26326.16347331, 26720.73076039, 29236.54276803, 33601.61173589, 38859.38878482, 44608.83894264, 50746.5153962 , 57291.43820068, 64143.94706203, 71192.28818936, 78411.39839534, 85580.82465388, 92508.24971202, 99024.84020478, 104896.34192868, 110008.74566889, 114802.06239211, 118950.81609906, 118278.71872778, 113181.61352312, 108831.88451815, 105995.78705558]), 'scaled_surveys': {'Survey 1': array([ nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, 46673.23520396, nan, nan, 69720.39641341, nan, nan, 37610.03393571, nan, nan, 24989.73522152, nan, nan, 47863.22259546, nan, nan, 37854.46377829, nan, nan, 62509.71605734, nan, nan, 12742.51363548, nan, nan, 6876.19741359, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan]), 'Survey 2': array([ nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, 7629.50352123, 10998.64453642, 3599.15462324, 3518.1506015 , 11032.23373143, 6437.27912099, 32723.20234422, 52367.41616547, 52720.29473575, 65635.47315639, 64640.352634 , 98701.77568606, 81055.95648727, 121390.37588683, 106668.44146118, 83854.02210337, nan, nan, nan])}}