Lower Columbia River Rainbow Trout Spawning Analysis 2018

The suggested citation for this analytic report is:

Thorley, J.L. and Dalgarno, S. (2018) Lower Columbia River Rainbow Trout Spawning Analysis 2018. A Poisson Consulting Analysis Report. URL: https://www.poissonconsulting.ca/f/934446658.


Each spring in the Lower Columbia River (LCR) below the Hugh L. Keenleyside Dam (HLK) and in the Lower Kootenay River (LKR) below the Brilliant Dam, thousands of Rainbow Trout spawn. Since 1992, BC Hydro has stabilized the spring discharge releases from HLK to protect Rainbow Trout redds from dewatering.

The primary goal of the current analysis to estimate the abundance of spawners and the stock-recruitment relationship.

Data Preparation

The aerial spawner counts were conducted by Mountain Water Research. The age-1 recruitment estimates were provided by the Fish Population Indexing Program.

The study area was divided into three sections: the LCR above the LKR, the LKR and the LCR below the LKR. Redd and spawner counts upstream of Norns Creek Fan and downstream of Genelle were excluded from the section totals because they constitute less than 0.1% of the total count and were not surveyed in all years. The redd and spawner counts for the Right Upstream Bank above Robson Bridge were also excluded as they appear to be primarily driven by viewing conditions (and constitute less than 2.5% of the total). Viewing conditions were classified as Good or Poor. If information on the viewing conditions was not available a decline in the redd count of more than one third of the cumulative maximum count for a particular section was assumed to be caused by poor viewing conditions.

The data were prepared for analysis using R version 3.5.1 (R Core Team 2017).

Statistical Analysis

Model parameters were estimated using Bayesian methods. The Bayesian estimates were produced using JAGS (Plummer 2015) and Stan (Carpenter et al. 2017). For additional information on Bayesian modelling in the BUGS language, of which JAGS uses a dialect, the reader is referred to Kery and Schaub (2011). For additional information on Bayesian modelling in the Stan language the reader is referred to Stan Development Team (2017).

Unless indicated otherwise, the Bayesian analyses used uninformative uniform or normal prior distributions (Kery and Schaub 2011, 36). The posterior distributions were estimated from 1,500 Markov Chain Monte Carlo (MCMC) samples thinned from the second halves of three chains (Kery and Schaub 2011, 38–40). Model convergence was confirmed by ensuring that \(\hat{R} < 1.1\) (Kery and Schaub 2011, 40) for each of the monitored parameters (Kery and Schaub 2011, 61).

The parameters are summarised in terms of the point estimate, standard deviation (sd), the z-score, lower and upper 95% credible limits (CLs) and the p-value (Kery and Schaub 2011, 37, 42). A p-value of 0.05 indicates that the lower or upper 95% CL is 0. The estimate is the median (50th percentile) of the MCMC samples, the z-score is \(\mathrm{mean}/\mathrm{sd}\) and the 95% CLs are the 2.5th and 97.5th percentiles.

The results are displayed graphically by plotting the modeled relationships between particular variables and the response(s) with the remaining variables held constant. In general, continuous and discrete fixed variables are held constant at their mean and first level values, respectively, while random variables are held constant at their typical values (expected values of the underlying hyperdistributions) (Kery and Schaub 2011, 77–82). When informative the influence of particular variables is expressed in terms of the effect size (i.e., percent change in the response variable) with 95% confidence/credible intervals (CIs, Bradford, Korman, and Higgins 2005).

The analyses were implemented using R version 3.5.1 (R Core Team 2017) and the jmbr and smbr packages.

Model Descriptions


The spawner abundance and spawn timings were estimated from the aerial fish and redd counts for the three sections using an Area-Under-The-Curve (AUC) model.

Key assumptions of the AUC model include:

  • Spawner abundance varies by river section.
  • Spawner abundance varies randomly by year and section within year.
  • Spawner observer efficiency is between 0.8 and 1.0.
  • Number of redds per spawner is between 1 and 2.
  • Spawner residence time is between 14 and 21 days as determined in a previous year’s analysis.
  • Redd residence time is between 30 and 40 days.
  • Spawner arrival and departure times are normally distributed.
  • Spawner arrival duration (SD of normal distribution) varies randomly by section within year.
  • Peak spawner arrival timing varies randomly by year.
  • The residual variations in the spawner and redd counts are described by separate Negative Binomial distributions.


The relationship between the number of spawners and the resultant number of age-1 fish was estimated using a Beverton-Holt stock-recruitment model (Walters and Martell 2004):

\[ R = \frac{\alpha \cdot S}{1 + \beta \cdot S} \quad,\]

where \(S\) is the spawners (stock), \(R\) is the recruits, \(\alpha\) is the recruits per spawner at low density and \(\beta\) determines the density-dependence.

Key assumptions of the stock-recruitment model include:

  • The recruits per spawner at low density (\(\alpha\)) is normally distributed with a mean of 90 and a SD of 50.
  • The recruits per spawner varies with the percent of redds dewatered.
  • The residual variation in the number of recruits is log-normally distributed.

The mean of 90 for \(\alpha\) was based on an average of 2,900 eggs per female spawner, a 50:50 sex ratio, 50% egg survival, 50% post-emergence fall survival, 50% overwintering survival and 50% summer survival.

The carrying capacity is \(\alpha / \beta\).

Model Templates


data {
  int<lower=0> nObs;
  int<lower=0> nSection;
  int<lower=0> nYear;

  int Year[nObs];
  int Section[nObs];
  real Doy[nObs];
  int Spawners[nObs];
  int Redds[nObs];
parameters {
  vector<lower=5,upper=10>[nSection] bSpawnerAbundanceSection;

  real<lower=0,upper=2> sSpawnerAbundanceYear;
  vector[nYear] bSpawnerAbundanceYear;
  real<lower=0,upper=2> sSpawnerAbundanceSectionYear;
  vector[nSection * nYear] bSpawnerAbundanceSectionYear;

  real<lower=0.8,upper=1.0> bSpawnerObserverEfficiency;
  real<lower=0.0,upper=2.0> bReddObserverEfficiency;

  real<lower=1, upper=2> bReddPerSpawner;

  real<lower=14, upper=21> bSpawnerResidenceTime;
  real<lower=30, upper=40> bReddResidenceTime;

  real<lower=100, upper=150> bPeakSpawnerArrivalTiming;

  real<lower=0,upper=21> sPeakSpawnerArrivalTimingYear;
  vector[nYear] bPeakSpawnerArrivalTimingYear;

  real<lower=log(10), upper=log(50)> bSpawnerArrivalDuration;

  real<lower=0,upper=2> sSpawnerArrivalDurationSectionYear;
  vector[nSection * nYear] bSpawnerArrivalDurationSectionYear;

  real<lower=0, upper=2> bDispersionRedds;
  real<lower=0, upper=2> bDispersionSpawners;
model {
  vector[nObs] eSpawnerAbundance;
  vector[nObs] ePeakSpawnerArrivalTiming;
  vector[nObs] eSpawnerArrivalDuration;

  vector[nObs] eRedds;
  vector[nObs] eSpawners;

  bSpawnerAbundanceYear ~ normal(0, sSpawnerAbundanceYear);
  bSpawnerAbundanceSectionYear ~ normal(0, sSpawnerAbundanceSectionYear);

  bPeakSpawnerArrivalTimingYear ~ normal(0, sPeakSpawnerArrivalTimingYear);
  bSpawnerArrivalDurationSectionYear ~ normal(0, sSpawnerArrivalDurationSectionYear);

  for (i in 1:nObs) {
    eSpawnerAbundance[i] = exp(bSpawnerAbundanceSection[Section[i]] + bSpawnerAbundanceYear[Year[i]] + bSpawnerAbundanceSectionYear[((Section[i] - 1) * Year[i]) + Year[i]]);

    ePeakSpawnerArrivalTiming[i] = bPeakSpawnerArrivalTiming + bPeakSpawnerArrivalTimingYear[Year[i]];

    eSpawnerArrivalDuration[i] = exp(bSpawnerArrivalDuration + bSpawnerArrivalDurationSectionYear[((Section[i] - 1) * Year[i]) + Year[i]]);

    eRedds[i] = eSpawnerAbundance[i] * bReddPerSpawner * bReddObserverEfficiency * (normal_cdf(Doy[i], ePeakSpawnerArrivalTiming[i], eSpawnerArrivalDuration[i]) - normal_cdf(Doy[i], ePeakSpawnerArrivalTiming[i] + bReddResidenceTime, eSpawnerArrivalDuration[i]));

    eSpawners[i] = eSpawnerAbundance[i] * bSpawnerObserverEfficiency * (normal_cdf(Doy[i], ePeakSpawnerArrivalTiming[i], eSpawnerArrivalDuration[i]) - normal_cdf(Doy[i], ePeakSpawnerArrivalTiming[i] + bSpawnerResidenceTime, eSpawnerArrivalDuration[i]));
  Redds ~ neg_binomial_2(eRedds, 1/bDispersionRedds);
  Spawners ~ neg_binomial_2(eSpawners, 1/bDispersionSpawners);

Template 1. AUC model.


model {

  bAlpha ~ dnorm(90, 50^-2) T(1,)
  bAlphaDewatered ~ dnorm(0, 2^-2)
  bBeta ~ dnorm(-5, 5^-2)
  sRecruits ~ dunif(0, 2)

  for(i in 1:length(Stock)) {
    log(eAlpha[i]) <- log(bAlpha) + bAlphaDewatered * Dewatered[i]
    log(eBeta[i]) <- bBeta
    eRecruits[i] <- eAlpha[i] * Stock[i] / (1 + eBeta[i] * Stock[i])
    Recruits[i] ~ dlnorm(log(eRecruits[i]), sRecruits^-2)

Template 2.




Table 1. Parameter descriptions.

Parameter Description
bDispersionRedds Clustering parameter for Redds
bDispersionSpawners Clustering parameter for Spawner
bPeakSpawnerArrivalTiming Intercept for ePeakSpawnerArrivalTiming
bPeakSpawnerArrivalTimingYear[i] Effect of ith Year on bPeakSpawnerArrivalTiming
bReddObserverEfficiency Redd observer efficiency
bReddPerSpawner Number of redds per spawner
bReddResidenceTime Redd residence time (days)
bSpawnerAbundanceSection[i] Intercept for log(eSpawnerAbundance) by Section
bSpawnerAbundanceSectionYear[i] Effect of Section by Year on bSpawnerAbundanceSection
bSpawnerAbundanceYear[i] Effect of ith Year on bSpawnerAbundanceSection
bSpawnerArrivalDuration[i] Intercept for log(eSpawnerArrivalDuration)
bSpawnerArrivalDurationSectionYear[i] Effect of Section by Year on bSpawnerArrivalDuration
bSpawnerObsEfficiency Spawner observer efficiency
bSpawnerResidenceTime Spawner residence time (days)
Doy[i] Day of the year of ith count
ePeakSpawnerArrivalTiming[i] Expected Doy of peak spawner arrival for ith count
eSpawnerAbundance[i] Expected spawner abundance for ith count
eSpawnerArrivalDuration[i] Expected SD of spawner arrival timing for ith count
Redds[i] Observed number of redds on ith count
Section[i] Section of ith count
Spawners[i] Observed number of fish on ith count
sPeakSpawnerArrivalTimingYear SD of bPeakSpawnerArrivalTimingYear
sSpawnerAbundanceSectionYear SD of bSpawnerAbundanceSectionYear
sSpawnerAbundanceYear SD of bSpawnerAbundanceYear
sSpawnerArrivalDurationSectionYear SD of bSpawnerArrivalDurationSectionYear
Year[i] Year of ith count

Table 2. Model coefficients.

term estimate sd zscore lower upper pvalue
bDispersionRedds 0.0637051 0.0061613 10.374498 0.0524675 0.0767115 7e-04
bDispersionSpawners 0.3539547 0.0288701 12.316814 0.3026709 0.4170390 7e-04
bPeakSpawnerArrivalTiming 117.6892961 2.3854974 49.321980 113.0233654 122.3957975 7e-04
bReddObserverEfficiency 0.5645274 0.1217781 4.722354 0.3765360 0.8171811 7e-04
bReddPerSpawner 1.4073038 0.2835794 5.071441 1.0219257 1.9621557 7e-04
bReddResidenceTime 32.0573562 2.1215308 15.373843 30.1023635 37.8457172 7e-04
bSpawnerAbundanceSection[1] 7.3285175 0.2006368 36.512773 6.9273329 7.6751803 7e-04
bSpawnerAbundanceSection[2] 6.6294694 0.2014922 32.867142 6.2187510 6.9717098 7e-04
bSpawnerAbundanceSection[3] 7.8697039 0.2047534 38.406725 7.4624092 8.2333417 7e-04
bSpawnerArrivalDuration 3.1721320 0.0358610 88.478686 3.1037130 3.2424805 7e-04
bSpawnerObserverEfficiency 0.9059636 0.0563495 16.026934 0.8040606 0.9938792 7e-04
bSpawnerResidenceTime 19.6810469 1.3042694 14.856393 16.1809839 20.9313131 7e-04
sPeakSpawnerArrivalTimingYear 8.3850071 1.8649550 4.641040 5.8098781 12.9778684 7e-04
sSpawnerAbundanceSectionYear 0.1478012 0.0301194 4.990114 0.0983256 0.2168681 7e-04
sSpawnerAbundanceYear 0.6497327 0.1333599 5.019832 0.4592398 0.9897478 7e-04
sSpawnerArrivalDurationSectionYear 0.1806274 0.0287631 6.339208 0.1339776 0.2447777 7e-04

Table 3. Model summary.

n K nchains niters nthin ess rhat converged
481 16 3 500 1 154 1.024 TRUE


Table 4. Parameter descriptions.

Parameter Description
bAlpha Intercept for eAlpha
bAlphaDewatered Effect of Dewatered on log(bAlpha)
bBeta Intercept for log(eBeta)
Dewatered[i] Proportional redd dewatering in ith spawn year
eAlpha Expected number of recruits at low density
eBeta Expected density-dependence
eRecruits[i] Expected Recruits
Recruits[i] Number of age-1 recruits from ith spawn year
sRecruits SD of residual variation in Recruits
Stock[i] Number of spawners in ith spawn year

Table 5. Model coefficients.

term estimate sd zscore lower upper pvalue
bAlpha 107.8514990 41.1785294 2.693460 39.5864437 199.1224960 0.0007
bAlphaDewatered 0.1813919 0.0612213 2.967033 0.0604210 0.3047707 0.0053
bBeta -5.3907348 0.4371864 -12.456668 -6.4832232 -4.7450059 0.0007
sRecruits 0.2232654 0.0469900 4.879267 0.1581004 0.3388865 0.0007

Table 6. Model summary.

n K nchains niters nthin ess rhat converged
17 4 3 500 1000 1413 1 TRUE


Figure 1. Predicted and actual aerial fish and redd counts in the LCR above the LKR by date and year.
Figure 2. Predicted and actual aerial fish and redd counts in the LKR by date and year.
Figure 3. Predicted and actual aerial fish and redd counts in the LCR below the LKR by date and year.
Figure 4. Estimated total spawner abundance by year (with 95% CIs).
Figure 5. Dewatered redds by year.
Figure 6. Estimated percent redd dewatering by year (with 95% CIs).
Figure 7. Estimated start (2.5% spawners arrived), peak and end (2.5% of spawners remaining) spawn timing by year and section (with 95% CIs).


Figure 8. Predicted stock-recruitment relationship from spawners to subsequent age-1 recruits by spawn year (with 95% CIs).
Figure 9. Predicted age-1 recruits carrying capacity by percentage egg dewatering (with 95% CRIs).


The organisations and individuals whose contributions have made this analysis report possible include:

  • BC Hydro
    • Darin Nishi
    • Margo Dennis
    • Guy Martel
    • Philip Bradshaw
    • James Baxter
  • Mountain Water Research
    • Jeremy Baxter
  • Poisson Consulting
    • Robyn Irvine
  • Dam Helicopters
    • Duncan Wassick
  • Highland Helicopters
    • Phil Hocking
    • Mark Homis
  • Golder Associates
    • Dustin Ford
    • Demitria Burgoon
    • David Roscoe
  • Additional Support
    • Clint Tarala
    • Crystal Lawrence
    • Gary Pavan
    • Gerry Nellestijn
    • Jay Bowers


Bradford, Michael J, Josh Korman, and Paul S Higgins. 2005. “Using Confidence Intervals to Estimate the Response of Salmon Populations (Oncorhynchus Spp.) to Experimental Habitat Alterations.” Canadian Journal of Fisheries and Aquatic Sciences 62 (12): 2716–26. https://doi.org/10.1139/f05-179.

Carpenter, Bob, Andrew Gelman, Matthew D. Hoffman, Daniel Lee, Ben Goodrich, Michael Betancourt, Marcus Brubaker, Jiqiang Guo, Peter Li, and Allen Riddell. 2017. “Stan : A Probabilistic Programming Language.” Journal of Statistical Software 76 (1). https://doi.org/10.18637/jss.v076.i01.

Kery, Marc, and Michael Schaub. 2011. Bayesian Population Analysis Using WinBUGS : A Hierarchical Perspective. Boston: Academic Press. http://www.vogelwarte.ch/bpa.html.

Plummer, Martyn. 2015. “JAGS Version 4.0.1 User Manual.” http://sourceforge.net/projects/mcmc-jags/files/Manuals/4.x/.

R Core Team. 2017. “R: A Language and Environment for Statistical Computing.” Vienna, Austria: R Foundation for Statistical Computing. https://www.R-project.org/.

Stan Development Team. 2017. “Stan Modeling Language User’s Guide and Reference Manual.”

Walters, Carl J., and Steven J. D. Martell. 2004. Fisheries Ecology and Management. Princeton, N.J: Princeton University Press.