← CascadiaTools home

This appendix is the technical record. For a gentler introduction to each example, see the worked examples.

Appendix S1. Worked examples for every CascadiaTools module

Supporting Information for: CascadiaTools: a validated, AI-guided analysis harness for ecology, wildlife, fisheries and conservation genetics. T. Levi, Cascadia Wildlife Lab.

Each example follows the same workflow an AI agent follows for a researcher. It gives the question, the prompt the researcher typed, the study design, and the true values used to simulate the example dataset. It then shows planted-truth recovery at that design (the acceptance gate), estimates from the example data set against the truth, convergence and goodness of fit, the report's interpretation, and the module's default publication figures. A verdict of DONE means every interpreted estimand passed the gate at this design. OPEN means at least one did not; the reason is stated, and the example shows how the harness reports it. All example data are simulated, and every result can be reproduced with the listed commands.

Regression and causal inference

S1.1 glm: Wood Thrush point counts: negative-binomial GLMM with survey-effort offset and station random intercepts (simulated example)

DONE All interpreted estimands (canopy, elevation, forest-type effects, mean count) pass planted truth at this design (|rel. bias| <= 7.2%, coverage 0.905-0.940); fit converged; DHARMa all p > 0.5; module cross-checked and negative controls in VALIDATION.md. Station SD (FAIL, -17.6% bias, 23% singular fits) and NB theta (unbounded in 7/199) are nuisance parameters and are not interpreted.

Question

Does the number of Wood Thrushes counted change with canopy cover, elevation and forest type?

What the researcher typed

I have Wood Thrush point counts in wood_thrush_counts.csv: 45 stations, each counted 4 times in May-June 2025. Most counts were 10 minutes, some were 5. I want to know whether the number of thrushes changes with canopy cover, elevation and forest type. Please analyse it and give me a report with figures I can use in a paper.

Study design

ItemValue
stations45
visits_per_station4
observations180
familynbinom2 (log link)
offsetsurvey_min (5 or 10 min); results per 10-min count
random_effect(1|station)
predictorscanopy_cover_pct, elevation_m, forest_type (deciduous/mixed/conifer; all station-level)
forest_type_countsdeciduous = 15; mixed = 15; conifer = 15

True values used to simulate the example data

ItemValue
beta_intercept-2.08
beta_canopy_cover_pct_per_SD0.39
beta_elevation_m_per_SD-0.281
beta_forest_type_mixed-0.25
beta_forest_type_conifer-0.9
rate_ratio_canopy_per_10pct1.284
rate_ratio_elevation_per_100m0.887
rate_ratio_mixed0.779
rate_ratio_conifer0.407
mean_count_per_10min_at_reference1.249
re_sd_station0.45
nb_size_theta3
generatordev/glm/make_examples.R, seed 20261018; converted by dev/glm/si_truth.R

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpassnote
beta_canopy_cover_pct0.390.3865-0.00910.94–PASS–
beta_elevation_m-0.28-0.27490.01810.905–PASS–
beta_forest_type_conifer-0.9-0.88970.01140.94–PASS–
beta_forest_type_mixed-0.25-0.24490.02050.93–PASS–
beta_intercept-2.08-2.101-0.010.915–PASS–
mean_response_at_reference0.12490.12520.00240.915–PASS–
nb_size_theta3––––FAILnot gradable: 7/199 fits at theta > 100 (boundary); median estimate 3.21 (+7%); coverage 0.95 among finite CIs
rate_ratio_canopy_cover_pct1.4771.4840.00440.94–PASS–
rate_ratio_elevation_m0.75580.76730.01520.905–PASS–
rate_ratio_forest_type_conifer0.40660.43570.07160.94–PASS–
rate_ratio_forest_type_mixed0.77880.81720.04930.93–PASS–
re_sd_station0.450.3708-0.17590.94–FAILFAIL mean bias -17.6% (3 MC SE = 0.050 < |bias| 0.079); 45/199 fits singular (SD ~0), median -7.8%; not interpreted

Estimates from the example data

paramestimatelowerupper
rate_ratio_canopy_cover_pct_per_101.3941.1821.645
rate_ratio_elevation_m_per_1000.94890.85431.054
rate_ratio_forest_type_conifer0.48160.2480.9353
rate_ratio_forest_type_mixed1.1450.65092.014
rate_ratio_canopy_cover_pct1.681.2982.174
rate_ratio_elevation_m0.88440.69181.131
mean_response_at_reference1.0960.7271.651
beta_intercept-2.211-2.621-1.801
beta_canopy_cover_pct0.51870.26080.7766
beta_elevation_m-0.1228-0.36850.1229
beta_forest_type_conifer-0.7307-1.394-0.06685
beta_forest_type_mixed0.1355-0.42940.7003
re_sd_station0.55990.33790.9279
nb_size_theta5.8891.12430.84

Convergence and goodness of fit

ItemValue
convergedyes
engineglmmTMB 1.1.15.2, REML variance parameters
dharma_uniformity_p0.67
dharma_dispersion_ratio1.1
dharma_dispersion_p0.52
dharma_outlier_p1
dharma_zero_inflation_p0.98
dharma_p_rawuniformity = 0.6723; dispersion = 0.52; outliers = 1; zero_inflation = 0.976
r2_marginal0.165
r2_conditional0.275
warningsnone

Interpretation from the report

Per 10 percentage points of canopy cover (%) this is associated with a 39% higher expected Wood Thrush count (rate ratio 1.39, 95% CI 1.18 to 1.64).
Across the observed range of canopy cover (%) (42 to 98), with other continuous predictors at their mean; forest type = deciduous; typical station, the expected Wood Thrush count goes from 0.432 to 2.78.
Per 100 m of elevation (m) this is associated with a 5.1% lower expected Wood Thrush count (rate ratio 0.949, 95% CI 0.854 to 1.05). The 95% interval includes no effect: the data are compatible with effects from 31% lower to 13% higher, including none.
Compared with forest type = deciduous (reference), forest type = conifer is associated with a 52% lower expected Wood Thrush count (rate ratio 0.482, 95% CI 0.248 to 0.935): 0.528 vs 1.1.
Compared with forest type = deciduous (reference), forest type = mixed is associated with a 15% higher expected Wood Thrush count (rate ratio 1.15, 95% CI 0.651 to 2.01): 1.25 vs 1.1. The 95% interval includes no effect: the data are compatible with effects from 35% lower to 101% higher, including none.
Model checks: DHARMa simulated residuals showed no detectable problems with distribution, dispersion, outliers or zeros (all p >= 0.05).
These are effects on the expected count as recorded, which combines how many/whether animals are present with how likely they are to be detected or recorded.

Figures

Figure: Conditional effects of every predictor on the expected Wood Thrush count per 10 survey minutes (typical station).
effects_panel. Conditional effects of every predictor on the expected Wood Thrush count per 10 survey minutes (typical station). Panels: A, Canopy cover (%); B, Elevation (m); C, Forest type. Lines/points: estimates; bands/bars: 95% confidence intervals from the sampling distribution of the fixed effects; in each panel the other predictors are held at their mean (continuous) or reference level (factors) and random effects at zero. Rug: observed predictor values.
Figure: Expected Wood Thrush count per 10 survey minutes (line) versus Canopy cover (%), with 95% confidence band from 2000 draws from the multivariate-normal sampling distribution of the fixed effects.
effect_canopy_cover_pct. Expected Wood Thrush count per 10 survey minutes (line) versus Canopy cover (%), with 95% confidence band from 2000 draws from the multivariate-normal sampling distribution of the fixed effects. Other predictors held at: Elevation (m) at its mean; Forest type = deciduous; random effects at zero (a typical station). Rug: observed values of Canopy cover (%). The curve spans the observed range only.
Figure: Expected Wood Thrush count per 10 survey minutes (line) versus Elevation (m), with 95% confidence band from 2000 draws from the multivariate-normal sampling distribution of the fixed effects.
effect_elevation_m. Expected Wood Thrush count per 10 survey minutes (line) versus Elevation (m), with 95% confidence band from 2000 draws from the multivariate-normal sampling distribution of the fixed effects. Other predictors held at: Canopy cover (%) at its mean; Forest type = deciduous; random effects at zero (a typical station). Rug: observed values of Elevation (m). The curve spans the observed range only.
Figure: Expected Wood Thrush count per 10 survey minutes for each level of Forest type (points) with 95% confidence intervals from 2000 draws from the sampling distribution of the fixed effects.
effect_forest_type. Expected Wood Thrush count per 10 survey minutes for each level of Forest type (points) with 95% confidence intervals from 2000 draws from the sampling distribution of the fixed effects. Other predictors held at: Canopy cover (%), Elevation (m) at their means; random effects at zero (a typical station).
Figure: Rate ratio for each predictor (points) with 95% Wald confidence intervals (bars) on a log axis: continuous predictors per 1 SD (SD in brackets, original units), factor levels against the reference level.
coefficients. Rate ratio for each predictor (points) with 95% Wald confidence intervals (bars) on a log axis: continuous predictors per 1 SD (SD in brackets, original units), factor levels against the reference level. Dashed line: no effect (1). A value of 1.5 means a 50% higher expected count.
Figure: DHARMa simulated quantile residuals (250 simulations). (A) QQ plot against the uniform distribution expected under a correct model; points should follow the dashed line (Kolmogorov-Smirnov uniformity p = 0.67). (B) Residuals…
residuals. DHARMa simulated quantile residuals (250 simulations). (A) QQ plot against the uniform distribution expected under a correct model; points should follow the dashed line (Kolmogorov-Smirnov uniformity p = 0.67). (B) Residuals against the rank-transformed model prediction; solid lines are the 0.25, 0.5 and 0.75 quantiles of the residuals in bins of the prediction and should lie flat on the dashed lines (dispersion test p = 0.52; outlier test p = 1; zero-inflation p = 0.98).
Figure: Estimated random intercepts (conditional modes, points) of Station with 95% intervals from their conditional SDs (bars), sorted by estimate, shown as multipliers of the expected value on a log axis.
random_effects. Estimated random intercepts (conditional modes, points) of Station with 95% intervals from their conditional SDs (bars), sorted by estimate, shown as multipliers of the expected value on a log axis. Dashed line: a typical station (random effect 0). These intervals do not include uncertainty in the fixed effects.

Limits that matter at this design

recovery settings

ItemValue
nsim200
converged199/200
seconds_per_fit_median0.56
coverage_bound0.904

Commands to reproduce

bin/ejob -c 1 -m 2 -t 0:10:00 -l logs/glm_si_truth.log -- bin/Rscript dev/glm/si_truth.R
bin/ejob -c 4 -m 8 -t 0:20:00 -l logs/glm_si_selftest.log -- bin/Rscript core/run.R selftest glm --config modules/glm/example/recovery.yaml --nsim 8 --cores 4 --out dev/glm/si_selftest
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/glm_si_recover.log -- bin/Rscript core/run.R recover glm --config modules/glm/example/recovery.yaml --nsim 200 --cores 16 --out results/glm/si/recovery
bin/ejob -c 1 -m 2 -t 0:10:00 -l logs/glm_si_reccheck.log -- bin/Rscript dev/glm/si_recovery_check.R
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/glm_si_fit.log -- bin/Rscript core/run.R fit glm --config modules/glm/example/config.yaml --out results/glm/si/fit
bin/ejob -c 2 -m 8 -t 0:20:00 -l logs/glm_si_figs.log -- bin/Rscript core/run.R figures glm --fit results/glm/si/fit/glm_fit.rds --config modules/glm/example/config.yaml
bin/ejob -c 1 -m 2 -t 0:10:00 -l logs/glm_si_summary.log -- bin/Rscript dev/glm/si_summary.R

Step-by-step walkthrough: modules/glm/example/WALKTHROUGH.md.

S1.2 causal: Does riparian canopy cover cause more juvenile trout? Causal effect from 140 observational stream reaches (DAG + g-computation, simulated data with known truth)

DONE

Question

If riparian canopy cover were increased by 10 percentage points, how many more juvenile trout per 100 m reach would we expect, and how much of that effect runs through cooler August water temperature?

What the researcher typed

I surveyed 140 stream reaches last summer, one electrofishing pass each. The file is stream_trout_reaches.csv. I want to know whether riparian canopy cover actually causes more juvenile trout, and by how much for a 10 % increase in canopy, not just whether they're correlated. Elevation, farmland in the catchment and stream width all affect both canopy and trout. I think shade works partly by keeping the water cool. I also measured periphyton, which depends on both shade and how many trout graze. Please do a proper causal analysis and give me a report with figures I can use in a paper.

Study design

ItemValue
n_reaches140
n_streams7
surveys_per_reach1
exposurecanopy_pct (continuous, %)
outcometrout_per_reach (count)
familynegative binomial (log link)
contrast+10 percentage points canopy
effectstotal and controlled direct (water temperature held fixed)
dag_nodes8
dag_arrows12
adjustment_set_totalelevation_m, fine_sediment_pct, wetted_width_m
adjustment_set_directfine_sediment_pct, water_temp_c, wetted_width_m
mediatorwater_temp_c
colliderperiphyton_chla
ci_methodunconditional (delta + covariate-distribution term)

True values used to simulate the example data

ItemValue
ate_canopy_pct1.954
rate_ratio_canopy_pct1.293
beta_canopy_pct0.02571
direct_ate_canopy_pct1.023
direct_rate_ratio_canopy_pct1.154
direct_beta_canopy_pct0.01429
interceptlog(5)
theta3
path_coefficientsstandardised; see modules/causal/example/README_data.md
seed2024
generatordev/causal/make_examples.R

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
ate_canopy_pct1.9541.9890.01810.951PASS
rate_ratio_canopy_pct1.2931.2950.00160.9451PASS
beta_canopy_pct0.025710.02569-0.00080.9451PASS
direct_ate_canopy_pct1.0231.050.02590.940.505PASS
direct_rate_ratio_canopy_pct1.1541.1560.00190.9550.595PASS
direct_beta_canopy_pct0.014290.01424-0.00320.9550.595PASS

Estimates from the example data

paramestimatelowerupper
ate_canopy_pct1.1810.2582.104
rate_ratio_canopy_pct1.1871.0541.338
beta_canopy_pct0.017180.005260.02909
direct_ate_canopy_pct0.5664-0.29611.429
direct_rate_ratio_canopy_pct1.090.96221.235
direct_beta_canopy_pct0.00864-0.003860.02114
whatif_crude__ate_canopy_pct1.7790.91252.646
whatif_omit_elevation_m__ate_canopy_pct2.1421.1713.113
whatif_omit_fine_sediment_pct__ate_canopy_pct1.7810.74932.813
whatif_omit_wetted_width_m__ate_canopy_pct0.5304-0.22621.287
whatif_add_mediator_water_temp_c__ate_canopy_pct0.5523-0.31581.42
whatif_add_collider_periphyton_chla__ate_canopy_pct1.5850.64412.526
whatif_alt_set_2__ate_canopy_pct1.3370.27552.398
whatif_all_measured__ate_canopy_pct1.1450.16552.125

Convergence and goodness of fit

ItemValue
convergedyes
engineMASS::glm.nb
n_rows140
dag_local_testsn_tests = 16; fisher_C = 31.4; df = 32; p = 0.498; contradicted = 0
dharmauniformity_p = 0.711; dispersion_p = 0.016; outliers_p = 1; flagged = dispersion; note = Correct-family negbin flags dispersion in 1.3% of datasets (VALIDATION.md calibration); this draw is heavy-tailed (max 68 trout). Bootstrap sensitivity fit: ATE 1.18 (0.03 to 2.52), rate ratio 1.19 (1.005 to 1.385).
e_valuepoint = 1.66; ci = 1.29

Interpretation from the report

Average causal effect: increasing riparian canopy cover by 10 percentage points at every site would change the expected number of juvenile trout per 100 m reach by 1.18 (95% CI 0.258 to 2.10), from 6.30 to 7.48 on average. As a ratio (rate ratio), 1.19 (1.05 to 1.34): a 19% increase.
Controlled direct effect (holding August water temperature fixed): 0.566 (95% CI -0.296 to 1.43) on the count scale. On the model scale about 50% of the total effect runs through the mediator(s) (1 - direct/total = 0.50), a rough split that ignores the uncertainty in both.
Strategies the DAG says are BIASED give: No adjustment (crude association) -> 1.78 (+51%); Omit elevation_m (a confounder) -> 2.14 (+81%); Omit wetted_width_m (a confounder) -> 0.530 (-55%); Also adjust for mediator water_temp_c (over-control) -> 0.552 (-53%); Also adjust for periphyton_chla (collider) -> 1.59 (+34%).
Sensitivity to unmeasured confounding (E-value): to fully explain away this effect, an unmeasured common cause would have to raise both riparian canopy cover and juvenile trout per 100 m reach by a factor of 1.66 (risk-ratio scale) beyond the adjusted variables; to make the 95% CI include no effect, a factor of 1.29.
Checking the DAG against the data: the DAG implies 16 conditional independencies that can be tested. None is contradicted by the data (Fisher's C = 31.4, df = 32, p = 0.50). Passing these tests does not prove the DAG.
Model check: the negbin outcome model shows problems (DHARMa dispersion p < 0.05); the effect estimate may be off. Check the residual plot; a single p < 0.05 among several checks also happens by chance in 1 of 20 good models.

Figures

Figure: What-if comparison: the same average causal effect estimated under different adjustment choices, with 95% confidence intervals.
adjustment_comparison. What-if comparison: the same average causal effect estimated under different adjustment choices, with 95% confidence intervals. Green circle and vertical line: the DAG's adjustment set (main estimate). Blue triangles: other sets the DAG says are valid. Orange squares: choices the DAG says are biased (omitting a confounder, adjusting for a mediator or a collider). Dashed line: no effect.
Figure: Causal diagram (DAG) assumed for the analysis.
dag. Causal diagram (DAG) assumed for the analysis. Exposure: riparian canopy cover (%) (orange); outcome: juvenile trout per 100 m reach (blue). Green nodes are the adjustment set used for the total effect (elevation, fine sediment, wetted width); white nodes are not adjusted for. Solid arrows lie on causal paths from the exposure to the outcome; dashed arrows are other assumed direct effects. Each missing arrow is an assumption of no direct effect.
Figure: Causal dose-response curve: average predicted juvenile trout per 100 m reach if every site were set to each value of riparian canopy cover (%), keeping each site's own values of the adjustment variables (elevation, fine sediment…
effect. Causal dose-response curve: average predicted juvenile trout per 100 m reach if every site were set to each value of riparian canopy cover (%), keeping each site's own values of the adjustment variables (elevation, fine sediment, wetted width; g-computation). Shaded band: 95% confidence interval (conditional on the sites sampled). Rug: observed values of riparian canopy cover (%). The curve spans the 2nd-98th percentiles of the observed exposure.
Figure: Testable implications of the DAG: partial correlations that the DAG says should be zero (A vs B given the variables after |), with 95% confidence intervals (dagitty::localTests).
implied_independencies. Testable implications of the DAG: partial correlations that the DAG says should be zero (A vs B given the variables after |), with 95% confidence intervals (dagitty::localTests). All 16 are consistent with the DAG (none contradicted after Holm correction). Consistency does not prove the DAG is right.
Figure: Outcome model check: DHARMa simulated quantile residuals of the outcome model plotted against uniform quantiles.
residuals. Outcome model check: DHARMa simulated quantile residuals of the outcome model plotted against uniform quantiles. Points should follow the dashed 1:1 line; S-shapes indicate over- or underdispersion.

Limits that matter at this design

recovery settings

ItemValue
nsim200
n_failed0
coverage_bound0.904
configmodules/causal/example/recovery.yaml
power_definitionshare of replicates whose 95% CI excludes the null (0 or ratio 1)

estimates bootstrap sensitivity

paramestimateloweruppertruth
ate_canopy_pct1.1810.030712.5191.954
rate_ratio_canopy_pct1.1871.0051.3851.293
beta_canopy_pct0.017180.000490.032570.02571
direct_ate_canopy_pct0.5664-0.36831.6751.023
direct_rate_ratio_canopy_pct1.090.93891.2711.154
direct_beta_canopy_pct0.00864-0.006310.023960.01429

Commands to reproduce

bin/ejob -c 1 -m 4 -t 0:20:00 -l logs/causal_make_examples.log -- bin/Rscript dev/causal/make_examples.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/causal_si_recover.log -- bin/Rscript core/run.R recover causal --config modules/causal/example/recovery.yaml --nsim 200 --cores 16 --out results/causal/si/recovery
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/causal_si_fit.log -- bin/Rscript core/run.R fit causal --config modules/causal/example/config.yaml --out results/causal/si/fit
bin/ejob -c 4 -m 16 -t 1:00:00 -l logs/causal_si_boot.log -- bin/Rscript core/run.R fit causal --config dev/causal/si_boot/config_bootstrap.yaml --out dev/causal/si_boot/fit

Step-by-step walkthrough: modules/causal/example/WALKTHROUGH.md.

S1.3 sem: Fire severity, vegetation and songbirds after a wildfire (piecewise SEM with a Poisson GLMM; simulated data with known truth)

OPEN

Question

How does wildfire severity affect breeding songbird detections, directly and indirectly through canopy loss and shrub regrowth, and does soil moisture affect birds through shrubs?

What the researcher typed

I have a CSV of 120 forest plots from 12 burn units after a wildfire (burned_forest_plots.csv). For each plot I have fire severity (dNBR), canopy cover, soil moisture, shrub cover and the number of birds detected in one point count. I think fire reduces canopy, less canopy means more shrubs, more shrubs means more birds, wetter soil means more shrubs, and fire might also reduce birds directly. Can you test this diagram, tell me how strong each link is, and how much of the fire effect on birds goes through the vegetation? Plots in the same burn unit are not independent. Please give me a report and figures for a paper.

Study design

ItemValue
n_plots120
n_burn_units12
plots_per_unit10
point_counts_per_plot1
n_variables5
componentscanopy ~ fire (Gaussian); shrub ~ canopy + moisture (Gaussian); birds ~ shrub + fire + (1|burn_unit) (Poisson, log)
enginepiecewise (lm, lme4::glmer)
ci_methodMonte Carlo, 4000 draws
survey_window2025-05-20 to 2025-06-14

True values used to simulate the example data

ItemValue
fire_to_canopy-0.055
canopy_to_shrub-0.35
moisture_to_shrub0.6
shrub_to_birds0.025
fire_to_birds-0.0006
int_canopy78
int_shrub45
int_birds1
sd_canopy9
sd_shrub7
re_sd_birds0.25
indirect_fire_to_birds0.0004813
total_fire_to_birds-0.0001187
indirect_moisture_to_birds0.015
indirect_fire_to_shrub0.01925
std_shrub_to_birds0.4526
std_fire_to_birds-0.2658
std_indirect_fire_to_birds0.2132
seed2024
generatordev/sem/make_example.R

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
direct_fire_severity_dnbr_to_bird_detections-0.0006-0.0006159-0.02650.9750.87PASS
indirect_fire_severity_dnbr_to_bird_detections0.00048130.00049620.03110.941PASS
indirect_fire_severity_dnbr_to_shrub_cover_pct0.019250.01922-0.00170.971PASS
indirect_soil_moisture_pct_to_bird_detections0.0150.015550.03670.951PASS
path_canopy_cover_pct_to_shrub_cover_pct-0.35-0.352-0.00560.951PASS
path_fire_severity_dnbr_to_bird_detections-0.0006-0.0006159-0.02650.970.87PASS
path_fire_severity_dnbr_to_canopy_cover_pct-0.055-0.054640.00650.9551PASS
path_shrub_cover_pct_to_bird_detections0.0250.025850.0340.9351PASS
path_soil_moisture_pct_to_shrub_cover_pct0.60.6020.00330.971PASS
std_canopy_cover_pct_to_shrub_cover_pct-0.5784-0.5806-0.00370.991PASS
std_direct_fire_severity_dnbr_to_bird_detections-0.2658-0.311-0.16990.9350.87FAIL
std_fire_severity_dnbr_to_bird_detections-0.2658-0.311-0.16990.9450.87FAIL
std_fire_severity_dnbr_to_canopy_cover_pct-0.8143-0.80880.006811PASS
std_indirect_fire_severity_dnbr_to_bird_detections0.21320.25020.17350.9351FAIL
std_indirect_fire_severity_dnbr_to_shrub_cover_pct0.4710.4698-0.00260.991PASS
std_indirect_soil_moisture_pct_to_bird_detections0.14560.17120.17560.9651FAIL
std_shrub_cover_pct_to_bird_detections0.45260.53160.17430.881FAIL
std_soil_moisture_pct_to_shrub_cover_pct0.32180.32240.00180.9651PASS
std_total_fire_severity_dnbr_to_bird_detections-0.05261-0.06079-0.15540.980.09PASS
std_total_fire_severity_dnbr_to_shrub_cover_pct0.4710.4698-0.00260.991PASS
std_total_soil_moisture_pct_to_bird_detections0.14560.17120.17560.9651FAIL
total_fire_severity_dnbr_to_bird_detections-0.0001187-0.0001197-0.00790.980.09PASS
total_fire_severity_dnbr_to_shrub_cover_pct0.019250.01922-0.00170.971PASS
total_soil_moisture_pct_to_bird_detections0.0150.015550.03670.951PASS

Estimates from the example data

paramestimatelowerupper
path_fire_severity_dnbr_to_canopy_cover_pct-0.05875-0.0661-0.0514
path_canopy_cover_pct_to_shrub_cover_pct-0.2631-0.3408-0.1853
path_soil_moisture_pct_to_shrub_cover_pct0.65720.42370.8907
path_shrub_cover_pct_to_bird_detections0.028620.018490.03874
path_fire_severity_dnbr_to_bird_detections-0.0009359-0.001351-0.0005209
std_fire_severity_dnbr_to_canopy_cover_pct-0.8245-0.9276-0.7213
std_canopy_cover_pct_to_shrub_cover_pct-0.4848-0.628-0.3416
std_soil_moisture_pct_to_shrub_cover_pct0.40310.25990.5463
std_shrub_cover_pct_to_bird_detections0.5680.3670.7689
std_fire_severity_dnbr_to_bird_detections-0.4804-0.6934-0.2674
rate_ratio_shrub_cover_pct_to_bird_detections1.0291.0191.04
rate_ratio_fire_severity_dnbr_to_bird_detections0.99910.99870.9995
direct_fire_severity_dnbr_to_bird_detections-0.0009359-0.001343-0.0004943
indirect_fire_severity_dnbr_to_bird_detections0.00044230.0002480.000665
total_fire_severity_dnbr_to_bird_detections-0.0004936-0.0008951-7.028e-05
indirect_soil_moisture_pct_to_bird_detections0.018810.010080.02928
total_soil_moisture_pct_to_bird_detections0.018810.010080.02928
indirect_fire_severity_dnbr_to_shrub_cover_pct0.015450.010680.02055
total_fire_severity_dnbr_to_shrub_cover_pct0.015450.010680.02055
std_direct_fire_severity_dnbr_to_bird_detections-0.4804-0.6892-0.2537
std_indirect_fire_severity_dnbr_to_bird_detections0.2270.12730.3413
std_total_fire_severity_dnbr_to_bird_detections-0.2534-0.4594-0.03607
std_indirect_soil_moisture_pct_to_bird_detections0.2290.12270.3564
std_total_soil_moisture_pct_to_bird_detections0.2290.12270.3564
std_indirect_fire_severity_dnbr_to_shrub_cover_pct0.39970.27610.5315
std_total_fire_severity_dnbr_to_shrub_cover_pct0.39970.27610.5315
rate_ratio_total_fire_severity_dnbr_to_bird_detections0.99950.99910.9999
rate_ratio_total_soil_moisture_pct_to_bird_detections1.0191.011.03

Convergence and goodness of fit

ItemValue
convergedyes
engine_notelikelihood fits; R-hat not applicable
fisher_C11.06
dsep_df8
dsep_p0.198
n_claims4
flagged_claimsoil_moisture_pct -> bird_detections P = 0.023 (false alarm: no such link in the truth)
r2canopy = 0.68; shrub = 0.39; birds = 0.23
bird_variance_to_mean1.29
overdispersion_flagno
recovery_nsim200
recovery_converged200
recovery_median_fit_s0.83
gate_pass18
gate_total24
std_count_diagnostictruth = 0.4526; module_conditional_eta = 0.5316; fixed_only_eta = 0.4625; true_eta = 0.4799; cor_y_fitted = 0.664; cor_y_true_mean = 0.623; file = results/sem/si/std_count_check.csv

Interpretation from the report

Global fit: Fisher's C = 11.06 (df = 8), P = 0.198: no evidence that the model leaves out a needed link. This supports, but does not prove, the causal structure drawn.
Fire severity -> canopy cover: an increase of 100 dNBR is associated with a difference of -5.87 (95% CI -6.61 to -5.14) % canopy cover.
Canopy cover -> shrub cover: an increase of 10 % canopy is associated with a difference of -2.63 (95% CI -3.41 to -1.85) % shrub cover.
Soil moisture -> shrub cover: an increase of 5 % moisture is associated with a difference of 3.29 (95% CI 2.12 to 4.45) % shrub cover.
Shrub cover -> bird detections: an increase of 10 % shrub is associated with expected bird detections multiplied by 1.33 (95% CI 1.20 to 1.47; +33%).
Fire severity -> bird detections (direct): an increase of 100 dNBR is associated with expected bird detections multiplied by 0.91 (95% CI 0.87 to 0.95; -9%).
Per 1-SD increase in fire severity (212 dNBR), the indirect route alone multiplies expected bird detections by 1.10 (95% CI 1.05 to 1.15); the total association corresponds to x0.90 (95% CI 0.83 to 0.99). Direct and indirect associations have opposite signs and partly cancel; a weak total does not mean the driver has little influence.
Soil moisture affects birds only indirectly through shrubs: x1.10 (95% CI 1.05 to 1.16) per 1 SD (5.02 %) of moisture.
Bird counts mix abundance with detectability; the SEM cannot separate an effect on birds from an effect on detecting them.
Paths are associations unless the diagram is causally complete; passing the d-sep test does not prove it.

Figures

Figure: Path diagram with standardised coefficients (piecewiseSEM conventions: SD scaling; latent-theoretic for binary, observation-empirical for count responses).
path_diagram. Path diagram with standardised coefficients (piecewiseSEM conventions: SD scaling; latent-theoretic for binary, observation-empirical for count responses). Arrow width is proportional to |coefficient|; colour gives the sign; dashed arrows have a 95% confidence interval that includes zero. Dotted arrows (labelled with P) are links the model omits but the d-separation test flags (P < 0.05).
Figure: Direct, indirect (summed over all mediated routes) and total standardised effects (points) with 95% Monte Carlo confidence intervals (lines); dashed line = no effect.
indirect_effects. Direct, indirect (summed over all mediated routes) and total standardised effects (points) with 95% Monte Carlo confidence intervals (lines); dashed line = no effect. Pairs with no direct path show only indirect and total (equal) effects.
Figure: d-separation tests (Shipley 2009): each row tests whether a link the model omits is needed, conditioning on both variables' parents (points = P values; highlighted triangles flag P < 0.05, circles are consistent with the model).
dsep. d-separation tests (Shipley 2009): each row tests whether a link the model omits is needed, conditioning on both variables' parents (points = P values; highlighted triangles flag P < 0.05, circles are consistent with the model). Fisher's C = 11.06, df = 8, P = 0.198. Dashed line P = 0.05.
Figure: Conditional effect of Fire severity (dNBR) on Canopy cover (%) (response scale; line) with 95% confidence band; other predictors of Canopy cover (%) held at their means.
partial_fire_severity_dnbr_to_canopy_cover_pct. Conditional effect of Fire severity (dNBR) on Canopy cover (%) (response scale; line) with 95% confidence band; other predictors of Canopy cover (%) held at their means. Points are partial residuals (observed value minus the fitted contribution of the other predictors).
Figure: Conditional effect of Canopy cover (%) on Shrub cover (%) (response scale; line) with 95% confidence band; other predictors of Shrub cover (%) held at their means.
partial_canopy_cover_pct_to_shrub_cover_pct. Conditional effect of Canopy cover (%) on Shrub cover (%) (response scale; line) with 95% confidence band; other predictors of Shrub cover (%) held at their means. Points are partial residuals (observed value minus the fitted contribution of the other predictors).
Figure: Conditional effect of Soil moisture (%) on Shrub cover (%) (response scale; line) with 95% confidence band; other predictors of Shrub cover (%) held at their means.
partial_soil_moisture_pct_to_shrub_cover_pct. Conditional effect of Soil moisture (%) on Shrub cover (%) (response scale; line) with 95% confidence band; other predictors of Shrub cover (%) held at their means. Points are partial residuals (observed value minus the fitted contribution of the other predictors).
Figure: Conditional effect of Shrub cover (%) on Birds per point count (response scale; line) with 95% confidence band; other predictors of Birds per point count held at their means, random effects at zero.
partial_shrub_cover_pct_to_bird_detections. Conditional effect of Shrub cover (%) on Birds per point count (response scale; line) with 95% confidence band; other predictors of Birds per point count held at their means, random effects at zero. Points are partial residuals: working residuals added to the conditional linear predictor and back-transformed to counts.
Figure: Conditional effect of Fire severity (dNBR) on Birds per point count (response scale; line) with 95% confidence band; other predictors of Birds per point count held at their means, random effects at zero.
partial_fire_severity_dnbr_to_bird_detections. Conditional effect of Fire severity (dNBR) on Birds per point count (response scale; line) with 95% confidence band; other predictors of Birds per point count held at their means, random effects at zero. Points are partial residuals: working residuals added to the conditional linear predictor and back-transformed to counts.
Figure: All path-level conditional effects on the response scale (panels as in the individual partial_ figures; same bands and points).
effects_panel. All path-level conditional effects on the response scale (panels as in the individual partial_ figures; same bands and points).

Limits that matter at this design

Commands to reproduce

bin/ejob -c 1 -m 4 -t 0:10:00 -l logs/sem_si_regen.log -- bin/Rscript dev/sem/si/make_example_check.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/sem_si_recover.log -- bin/Rscript core/run.R recover sem --config modules/sem/example/recovery.yaml --nsim 200 --cores 16 --out results/sem/si/recovery
bin/ejob -c 8 -m 16 -t 0:30:00 -l logs/sem_si_stdcheck.log -- bin/Rscript dev/sem/si/std_count_check.R
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/sem_si_fit.log -- bin/Rscript core/run.R fit sem --config modules/sem/example/config.yaml --out results/sem/si/fit
bin/Rscript core/run.R figures sem --fit results/sem/si/fit/sem_fit.rds --config modules/sem/example/config.yaml --out results/sem/si/fit

Step-by-step walkthrough: modules/sem/example/WALKTHROUGH.md.

Occupancy

S1.4 occu-single: Pileated woodpecker occupancy and forest cover (simulated call-playback surveys, 120 stands)

DONE

Question

Is pileated woodpecker occupancy of forest stands associated with forest cover and elevation, allowing for birds that were present but missed (detection varying with survey date and observer)?

What the researcher typed

I have pileated woodpecker call-playback surveys from 120 forest stands, up to 4 visits each in May-June 2025. The files are detections.csv (one row per visit: stand, visit number, date, day of year, observer, detected 1/0) and sites.csv (forest cover %, elevation in m, stand age). Does forest cover or elevation affect whether woodpeckers occupy a stand? Please account for birds we missed, and allow detection to change with date and observer. I need results and figures for a paper.

Study design

ItemValue
modelstatic
n_sites120
max_surveys4
surveys_done405
prop_missing0.156
visits_per_site4 = 72; 3 = 21; 2 = 27
n_observers3
n_detections52
n_sites_detected34
engineunmarked (maximum likelihood)

True values used to simulate the example data

ItemValue
occupancy_prob0.4061
detection_prob0.4025
psi_beta_forest_cover_pct1.05
psi_beta_elevation_m-0.475
p_beta_julian_day-0.5323
p_beta_observerJK-0.6
p_beta_observerMR0.4
prop_sites_occupied0.375
n_sites_occupied45
notesimulated; slopes are logit change per 1 SD of the covariate, intercepts are probabilities at mean covariates with observer AB

Planted-truth recovery at this design

runparamtruthmean_estrel_biascoveragepowerpass
A_module_recoverdetection_prob0.4020.40730.01320.95–PASS
A_module_recoveroccupancy_prob0.4060.4022-0.00930.945–PASS
A_module_recoverp_beta_effort-0.532-0.5462-0.02660.960.865PASS
A_module_recoverprop_sites_occupied0.42040.42220.00520.955–PASS
A_module_recoverpsi_beta_forest1.051.1130.06040.960.99PASS
B_full_example_modeldetection_prob0.39650.3933-0.00820.965–PASS
B_full_example_modeloccupancy_prob0.39840.40570.01910.965–PASS
B_full_example_modelp_beta_julian_day-0.5321-0.5476-0.02930.970.88PASS
B_full_example_modelp_beta_observerJK-0.6-0.6349-0.05810.9350.315PASS
B_full_example_modelp_beta_observerMR0.40.42760.06910.980.155PASS
B_full_example_modelprop_sites_occupied0.4210.43280.0280.975–PASS
B_full_example_modelpsi_beta_elevation_m-0.513-0.5438-0.06020.970.43PASS
B_full_example_modelpsi_beta_forest_cover_pct1.0171.1140.09580.960.975PASS

Estimates from the example data

paramestimateloweruppertruth
occupancy_prob0.33180.20240.49290.4061
psi_beta_forest_cover_pct1.0350.31141.7581.05
psi_beta_elevation_m-1.071-1.719-0.4226-0.475
detection_prob0.39390.26220.54310.4025
p_beta_julian_day-0.4924-0.8981-0.0866-0.5323
p_beta_observerJK-1.493-2.48-0.5068-0.6
p_beta_observerMR0.5033-0.43351.440.4
prop_sites_occupied0.38870.30830.48330.375

Convergence and goodness of fit

ItemValue
convergedyes
boundary_estimatesno
max_logit_se0.503
rhatnot applicable (maximum likelihood)
goftest = MacKenzie-Bailey chi-square, parametric bootstrap; n_boot = 500; chisq = 28.3; c_hat = 1.31; p = 0.138; verdict = no evidence of lack of fit
recovery_runsA = nsim = 200; converged = 200; failed = 0; all_pass = yes; B = nsim = 200; converged = 200; failed = 0; all_pass = yes

Interpretation from the report

The species was detected at least once at 34 of 120 sites (naive occupancy 0.28). Allowing for missed detections, the estimated probability that a site with average covariate values is occupied is 0.33 (95% CI 0.20 to 0.49).
Of the 120 surveyed sites, an estimated 47 (95% CI 37 to 58) were actually occupied (proportion 0.39 (95% CI 0.31 to 0.48)); this finite-sample estimate applies to these sites only, not to the wider landscape.
With the typical 4 surveys per site, an occupied site is detected at least once with probability 0.87 (95% CI 0.70 to 0.96), so about 13% of occupied sites go undetected with this survey effort.
Going from the 10th to the 90th percentile of forest cover (22 to 85.3%), occupancy changes from 0.09 (95% CI 0.03 to 0.28) to 0.62 (95% CI 0.36 to 0.81); each 10-unit increase multiplies the odds by 1.54.
Going from the 10th to the 90th percentile of elevation (361 to 1250 m), occupancy changes from 0.69 (95% CI 0.41 to 0.88) to 0.12 (95% CI 0.04 to 0.27).
Detection per survey by observer: AB 0.39 (95% CI 0.26 to 0.55); JK 0.13 (95% CI 0.05 to 0.26); MR 0.52 (95% CI 0.30 to 0.71).
These are associations from an observational design; they do not by themselves show that a covariate causes the change.
Goodness of fit (MacKenzie-Bailey test, 500 bootstrap replicates): c-hat = 1.31, p = 0.138. No evidence of lack of fit; this test has low power against unmodelled differences in detection among sites.

Figures

Figure: Occupancy probability versus Forest cover (%) (line: estimate; band: 95% confidence interval from 2000 draws of the asymptotic normal distribution of the maximum-likelihood estimates), holding Elevation (m) at its mean (834).
occupancy_forest_cover_pct. Occupancy probability versus Forest cover (%) (line: estimate; band: 95% confidence interval from 2000 draws of the asymptotic normal distribution of the maximum-likelihood estimates), holding Elevation (m) at its mean (834). Rug: observed Forest cover (%) values. Curves span the observed range of Forest cover (%).
Figure: Occupancy probability versus Elevation (m) (line: estimate; band: 95% confidence interval from 2000 draws of the asymptotic normal distribution of the maximum-likelihood estimates), holding Forest cover (%) at its mean (58.2).
occupancy_elevation_m. Occupancy probability versus Elevation (m) (line: estimate; band: 95% confidence interval from 2000 draws of the asymptotic normal distribution of the maximum-likelihood estimates), holding Forest cover (%) at its mean (58.2). Rug: observed Elevation (m) values. Curves span the observed range of Elevation (m).
Figure: Detection probability per survey versus Survey date (day of year) (line: estimate; band: 95% confidence interval from 2000 draws of the asymptotic normal distribution of the maximum-likelihood estimates)…
detection_julian_day. Detection probability per survey versus Survey date (day of year) (line: estimate; band: 95% confidence interval from 2000 draws of the asymptotic normal distribution of the maximum-likelihood estimates), holding Observer at its reference level (AB). Rug: observed Survey date (day of year) values for surveys done. Curves span the observed range of Survey date (day of year). This is an effect on detecting the species where it is present, not on where it occurs.
Figure: Detection probability per survey for each level of Observer (points: estimates; bars: 95% confidence intervals), holding Survey date (day of year) at its mean (142).
detection_observer. Detection probability per survey for each level of Observer (points: estimates; bars: 95% confidence intervals), holding Survey date (day of year) at its mean (142).
Figure: Odds ratios for every covariate effect, grouped by process; factor levels are relative to the reference level (points: estimates; bars: 95% confidence intervals; log scale).
coefficients. Odds ratios for every covariate effect, grouped by process; factor levels are relative to the reference level (points: estimates; bars: 95% confidence intervals; log scale). Dashed line: no effect (odds ratio 1). Numeric covariates were standardised, so each odds ratio is per 1 SD of the covariate (1 SD: Forest cover (%) 23.9; Elevation (m) 333; Survey date (day of year) 13.3).
Figure: Per-survey detection probability by visit number, averaged over the sites surveyed on that visit using each survey's own covariate values (points: estimates; bars: 95% confidence intervals).
detection_by_survey. Per-survey detection probability by visit number, averaged over the sites surveyed on that visit using each survey's own covariate values (points: estimates; bars: 95% confidence intervals). Surveys per visit number: visit 1: 120, visit 2: 120, visit 3: 93, visit 4: 72.
Figure: Goodness of fit (MacKenzie & Bailey 2004): histogram of the chi-square statistic for 500 data sets simulated from the fitted model and refitted (parametric bootstrap)…
gof. Goodness of fit (MacKenzie & Bailey 2004): histogram of the chi-square statistic for 500 data sets simulated from the fitted model and refitted (parametric bootstrap); vertical line: observed data (chi-square 28.3, c-hat 1.31, p = 0.138). A small p (< 0.05) or c-hat well above 1 means the detection histories vary more than the model allows.

Limits that matter at this design

Commands to reproduce

bin/Rscript dev/occu-single/make_example.R
bin/ejob -c 1 -m 4 -t 0:10:00 -l logs/occu-single_si_truth.log -- bin/Rscript dev/occu-single/si_truth.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/occu-single_si_recover.log -- bin/Rscript core/run.R recover occu-single --config modules/occu-single/example/recovery.yaml --nsim 200 --cores 16 --out results/occu-single/si/recovery
bin/ejob -c 16 -m 32 -t 1:00:00 -l logs/occu-single_si_fullrecover.log -- bin/Rscript dev/occu-single/si_full_recovery.R 200 16
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/occu-single_si_fit.log -- bin/Rscript core/run.R fit occu-single --config modules/occu-single/example/config.yaml --out results/occu-single/si/fit

Step-by-step walkthrough: modules/occu-single/example/WALKTHROUGH.md.

S1.5 occu-rota: Do gray foxes avoid coyotes, and does housing density change that? Multispecies occupancy with species interactions (Rota et al. 2016)

DONE

Question

Are gray foxes less likely to occupy camera sites where coyotes are present, and does that avoidance weaken with housing density, after allowing for imperfect detection and cameras that were down?

What the researcher typed

I have camera-trap data from 220 stations, 6 weekly occasions in June-July 2024. The files are camera_detections.csv (one row per camera and week: days the camera worked, and 1/0 for coyote, gray fox and bobcat) and camera_sites.csv (forest cover within 500 m, housing units per km2, whether the camera is on a trail). Are gray foxes less likely to occupy sites where coyotes are present, and does that change with housing density? Please account for animals the cameras missed and for cameras that were down. Detection probably depends on days active and on whether the camera faces a trail. I need results and figures for a paper.

Study design

ItemValue
species_modelledcoyote, gray_fox
species_in_datacoyote, gray_fox, bobcat
n_sites220
n_surveys6
survey_unitcamera-week
camera_weeks_surveyed1227
camera_weeks_not_surveyed93
prop_not_surveyed0.0705
occupancy_formula~ forest_pct + log(housing_per_km2)
interaction_formula~ log(housing_per_km2)
detection_formula~ days_active + on_trail
engineunmarked::occuMulti (maximum likelihood)

True values used to simulate the example data

ItemValue
occ_coyote_intercept0.4899
occ_coyote_beta_forest_pct-0.2434
occ_coyote_beta_log_housing_per_km20.1686
occ_gray_fox_intercept-0.6
occ_gray_fox_beta_forest_pct0.7
occ_gray_fox_beta_log_housing_per_km20.3
interaction_coyote_gray_fox-0.9
interaction_coyote_gray_fox_beta_log_housing_per_km20.6
detection_prob_coyote0.2498
p_coyote_beta_days_active0.3065
p_coyote_beta_on_trailyes0.8
detection_prob_gray_fox0.2936
p_gray_fox_beta_days_active0.3065
p_gray_fox_beta_on_trailyes-0.2
occupancy_prob_coyote0.5631
occupancy_prob_gray_fox0.2575
cooccurrence_prob_coyote_gray_fox0.1027
prob_coyote_given_gray_fox_present0.3989
prob_coyote_given_gray_fox_absent0.6201
prob_gray_fox_given_coyote_present0.1824
prob_gray_fox_given_coyote_absent0.3543
notesimulated with dev/occu-rota/make_example.R (set.seed(2025)) from a 3-species model; coyote first-order values are a linear approximation after summing bobcat out; derived quantities at forest 52.4%, housing 39.4/km2, 6.5 active days, off trail

Planted-truth recovery at this design

runparamtruthmean_estrel_biascoveragepowerpassapprox_truth
A_module_recover_nsim200cooccurrence_prob_coyote_gray_fox0.10270.1023-0.00420.975–PASS–
A_module_recover_nsim200detection_prob_coyote0.250.2483-0.00670.93–PASS–
A_module_recover_nsim200detection_prob_gray_fox0.290.289-0.00330.95–PASS–
A_module_recover_nsim200interaction_coyote_gray_fox-0.9-0.9721-0.08010.980.535PASS–
A_module_recover_nsim200interaction_coyote_gray_fox_beta_forest (= log housing)0.60.66190.10320.950.255PASS–
A_module_recover_nsim200occ_coyote_beta_forest (= log housing)0.170.17110.00640.9550.09PASS–
A_module_recover_nsim200occ_coyote_intercept0.490.5310.08370.95–PASS–
A_module_recover_nsim200occ_gray_fox_beta_forest (= log housing)0.30.2991-0.00290.9850.165PASS–
A_module_recover_nsim200occ_gray_fox_intercept-0.6-0.58120.03140.96–PASS–
A_module_recover_nsim200occupancy_prob_coyote0.56310.56780.00820.95–PASS–
A_module_recover_nsim200occupancy_prob_gray_fox0.25750.25770.00060.95–PASS–
A_module_recover_nsim200p_coyote_beta_effort (= days active)0.310.31910.02920.9450.915PASS–
A_module_recover_nsim200p_gray_fox_beta_effort (= days active)0.310.31630.02040.9350.695PASS–
A_module_recover_nsim200prob_coyote_given_gray_fox_absent0.62010.62740.01170.945–PASS–
A_module_recover_nsim200prob_coyote_given_gray_fox_present0.39890.3954-0.00880.995–PASS–
A_module_recover_nsim200prob_gray_fox_given_coyote_absent0.35430.36160.02050.96–PASS–
A_module_recover_nsim200prob_gray_fox_given_coyote_present0.18240.1801-0.01280.98–PASS–
B_full_example_model_nsim400_pooledcooccurrence_prob_coyote_gray_fox0.10270.10290.00190.961PASSno
B_full_example_model_nsim400_pooleddetection_prob_coyote0.25150.25370.00860.93251PASSno
B_full_example_model_nsim400_pooleddetection_prob_gray_fox0.29550.2921-0.01150.9451PASSno
B_full_example_model_nsim400_pooledinteraction_coyote_gray_fox-0.9-0.9552-0.06130.950.542PASSno
B_full_example_model_nsim400_pooledinteraction_coyote_gray_fox_beta_log_housing_per_km20.60.62330.03880.960.265PASSno
B_full_example_model_nsim400_pooledocc_coyote_beta_forest_pct-0.2434-0.2575-0.05810.95750.3PASSyes
B_full_example_model_nsim400_pooledocc_coyote_beta_log_housing_per_km20.16860.1682-0.00210.9650.1PASSyes
B_full_example_model_nsim400_pooledocc_coyote_intercept0.48990.52530.07220.97250.635PASSyes
B_full_example_model_nsim400_pooledocc_gray_fox_beta_forest_pct0.70.72120.03020.9450.927PASSno
B_full_example_model_nsim400_pooledocc_gray_fox_beta_log_housing_per_km20.30.32310.07710.950.215PASSno
B_full_example_model_nsim400_pooledocc_gray_fox_intercept-0.6-0.59260.01240.9650.47PASSno
B_full_example_model_nsim400_pooledoccupancy_prob_coyote0.56310.56790.00840.9651PASSno
B_full_example_model_nsim400_pooledoccupancy_prob_gray_fox0.25750.25790.00160.96251PASSno
B_full_example_model_nsim400_pooledp_coyote_beta_days_active0.29890.30220.00960.95750.86PASSno
B_full_example_model_nsim400_pooledp_coyote_beta_on_trailyes0.80.7842-0.01970.94250.978PASSno
B_full_example_model_nsim400_pooledp_gray_fox_beta_days_active0.29890.32730.09370.9450.537PASSno
B_full_example_model_nsim400_pooledp_gray_fox_beta_on_trailyes-0.2-0.2252-0.12590.93750.1PASSno
B_full_example_model_nsim400_pooledprob_coyote_given_gray_fox_absent0.62010.62680.01090.9751PASSno
B_full_example_model_nsim400_pooledprob_coyote_given_gray_fox_present0.39890.398-0.00230.961PASSno
B_full_example_model_nsim400_pooledprob_gray_fox_given_coyote_absent0.35430.35920.01360.9651PASSno
B_full_example_model_nsim400_pooledprob_gray_fox_given_coyote_present0.18240.1811-0.00710.95751PASSno

Estimates from the example data

paramestimateloweruppertruthcovers_truth
occ_coyote_intercept0.76590.25261.2790.4899yes
occ_coyote_beta_forest_pct-0.2484-0.61160.1148-0.2434yes
occ_coyote_beta_log_housing_per_km20.1245-0.31550.56450.1686yes
occ_gray_fox_intercept-0.3548-0.98680.2773-0.6yes
occ_gray_fox_beta_forest_pct0.61470.20341.0260.7yes
occ_gray_fox_beta_log_housing_per_km20.4752-0.08061.0310.3yes
interaction_coyote_gray_fox-1.4-2.381-0.418-0.9yes
interaction_coyote_gray_fox_beta_log_housing_per_km20.7212-0.15991.6020.6yes
detection_prob_coyote0.23430.18360.2940.2498yes
p_coyote_beta_days_active0.40080.19640.60530.3065yes
p_coyote_beta_on_trailyes0.8790.50141.2570.8yes
detection_prob_gray_fox0.29910.22340.38770.2936yes
p_gray_fox_beta_days_active0.47140.05530.88750.3065yes
p_gray_fox_beta_on_trailyes-0.5837-1.137-0.0305-0.2yes
occupancy_prob_coyote0.59730.50220.6860.5631yes
occupancy_prob_gray_fox0.25410.18310.34310.2575yes
cooccurrence_prob_coyote_gray_fox0.08810.04530.16580.1027yes
prob_coyote_given_gray_fox_present0.34660.18420.55280.3989yes
prob_coyote_given_gray_fox_absent0.68260.55840.78220.6201yes
prob_gray_fox_given_coyote_present0.14750.07850.27170.1824yes
prob_gray_fox_given_coyote_absent0.41220.2740.56870.3543yes

Convergence and goodness of fit

ItemValue
convergedyes
boundary_estimatesno
max_logit_se0.5
loglik-825.7
aic1679
rhatnot applicable (maximum likelihood)
goftest = parametric bootstrap chi-square (detection-frequency + co-detection); n_boot = 200; stat = 42.1; c_hat = 1.12; p = 0.25; verdict = no evidence of lack of fit
independent_routeshand-written likelihood: same loglik (-825.6936), coefficients within 1.3e-4 SE; Nimble posterior means within 0.22 SE (VALIDATION.md section 4)
recovery_runsA = nsim = 200; converged = 200; failed = 0; pass = 17/17; B = nsim = 400; batches = seeds 2026001-2026200: 20/21 (gray fox days-active detection slope +12.0% failed), seeds 2027001-2027200: 21/21; converged = 400; failed = 0; pass_pooled = 21/21

Interpretation from the report

Allowing for missed detections, the estimated probability that each species occupies a site with average covariate values is: coyote 0.60 (95% CI 0.50 to 0.69); gray fox 0.25 (95% CI 0.18 to 0.34).
At average covariate values, coyote and gray fox occur together less often than expected if they occurred independently (negative co-occurrence; this pattern alone does not show that one species avoids the other).
Where coyote is present, gray fox occupies a site with probability 0.15 (95% CI 0.08 to 0.27); where coyote is absent, 0.41 (95% CI 0.27 to 0.57).
The co-occurrence odds ratio is 0.25 (95% CI 0.09 to 0.66); a value of 1 would mean no association.
The coyote-gray fox co-occurrence odds ratio is multiplied by 2.06 (95% CI 0.85 to 4.96) per 1 SD (0.984) increase in log(housing_per_km2), i.e. by 1.66 (95% CI 0.89 to 3.09) per doubling of housing_per_km2 (the interval includes 1, so the data do not show that the association changes along this gradient).
At low housing_per_km2 (10th percentile), P(gray fox | coyote present) = 0.04 (95% CI 0.01 to 0.14) vs coyote absent 0.27 (95% CI 0.13 to 0.49); at high housing_per_km2 (90th percentile), 0.42 (95% CI 0.25 to 0.61) vs 0.55 (95% CI 0.32 to 0.77).
Across the observed range of forest_pct (10th percentile 15.8 to 90th percentile 87), marginal occupancy changes: coyote from 0.71 (95% CI 0.57 to 0.83) to 0.46 (95% CI 0.34 to 0.59); gray fox from 0.12 (95% CI 0.06 to 0.22) to 0.46 (95% CI 0.32 to 0.59). This is an association, not necessarily a causal effect.
Per-survey detection probability where the species is present (average survey conditions): coyote 0.23 (95% CI 0.18 to 0.29); gray fox 0.30 (95% CI 0.22 to 0.39). With 6 surveys, the chance of detecting a species at least once at an occupied site is coyote 0.80, gray fox 0.88.
Caution: co-occurrence is not proof of a species interaction (Blanchet et al. 2020).
Goodness of fit: no evidence of lack of fit (parametric bootstrap, p = 0.25, c-hat 1.12).

Figures

Figure: Conditional occupancy against Housing density (units per km²): each panel shows the probability that one species occupies a site where the other is present vs absent (other covariates held at Forest cover within 500 m (%) = 52.4…
conditional_occupancy. Conditional occupancy against Housing density (units per km²): each panel shows the probability that one species occupies a site where the other is present vs absent (other covariates held at Forest cover within 500 m (%) = 52.4 (mean)), with 95% confidence band (from the asymptotic normal distribution of the maximum-likelihood estimates). Co-occurrence is not evidence of an ecological interaction.
Figure: Probability that each species occupies a site at average covariate values (Forest cover within 500 m (%) = 52.4 (mean); Housing density (units per km²) = 39.4 (geometric mean…
conditional_occupancy_average. Probability that each species occupies a site at average covariate values (Forest cover within 500 m (%) = 52.4 (mean); Housing density (units per km²) = 39.4 (geometric mean, as the model uses its logarithm)): marginal (any state of the other species) and conditional on another species being absent or present ('A | B' = A given B). Points: estimates; bars: 95% confidence intervals.
Figure: Marginal occupancy probability of each species (line) against Forest cover within 500 m (%) (other covariates held at Housing density (units per km²) = 39.4 (geometric mean, as the model uses its logarithm))…
marginal_occupancy_forest_pct. Marginal occupancy probability of each species (line) against Forest cover within 500 m (%) (other covariates held at Housing density (units per km²) = 39.4 (geometric mean, as the model uses its logarithm)), with 95% confidence band (from the asymptotic normal distribution of the maximum-likelihood estimates). Rug: covariate values at the surveyed sites.
Figure: Probability that Coyote occupies a site where Gray fox is present vs absent, against Forest cover within 500 m (%) (other covariates held at Housing density (units per km²) = 39.4 (geometric mean, as the model uses its logarithm))…
conditional_coyote_given_gray_fox_forest_pct. Probability that Coyote occupies a site where Gray fox is present vs absent, against Forest cover within 500 m (%) (other covariates held at Housing density (units per km²) = 39.4 (geometric mean, as the model uses its logarithm)), with 95% confidence band (from the asymptotic normal distribution of the maximum-likelihood estimates). Diverging curves mean the co-occurrence association changes along the gradient; parallel curves on the logit scale mean it does not. Co-occurrence is not evidence of an ecological interaction. Rug: covariate values at the surveyed sites.
Figure: Probability that Gray fox occupies a site where Coyote is present vs absent, against Forest cover within 500 m (%) (other covariates held at Housing density (units per km²) = 39.4 (geometric mean, as the model uses its logarithm))…
conditional_gray_fox_given_coyote_forest_pct. Probability that Gray fox occupies a site where Coyote is present vs absent, against Forest cover within 500 m (%) (other covariates held at Housing density (units per km²) = 39.4 (geometric mean, as the model uses its logarithm)), with 95% confidence band (from the asymptotic normal distribution of the maximum-likelihood estimates). Diverging curves mean the co-occurrence association changes along the gradient; parallel curves on the logit scale mean it does not. Co-occurrence is not evidence of an ecological interaction. Rug: covariate values at the surveyed sites.
Figure: Marginal occupancy probability of each species (line) against Housing density (units per km²) (other covariates held at Forest cover within 500 m (%) = 52.4 (mean))…
marginal_occupancy_housing_per_km2. Marginal occupancy probability of each species (line) against Housing density (units per km²) (other covariates held at Forest cover within 500 m (%) = 52.4 (mean)), with 95% confidence band (from the asymptotic normal distribution of the maximum-likelihood estimates). Rug: covariate values at the surveyed sites.
Figure: Probability that Coyote occupies a site where Gray fox is present vs absent, against Housing density (units per km²) (other covariates held at Forest cover within 500 m (%) = 52.4 (mean))…
conditional_coyote_given_gray_fox_housing_per_km2. Probability that Coyote occupies a site where Gray fox is present vs absent, against Housing density (units per km²) (other covariates held at Forest cover within 500 m (%) = 52.4 (mean)), with 95% confidence band (from the asymptotic normal distribution of the maximum-likelihood estimates). Diverging curves mean the co-occurrence association changes along the gradient; parallel curves on the logit scale mean it does not. Co-occurrence is not evidence of an ecological interaction. Rug: covariate values at the surveyed sites.
Figure: Probability that Gray fox occupies a site where Coyote is present vs absent, against Housing density (units per km²) (other covariates held at Forest cover within 500 m (%) = 52.4 (mean))…
conditional_gray_fox_given_coyote_housing_per_km2. Probability that Gray fox occupies a site where Coyote is present vs absent, against Housing density (units per km²) (other covariates held at Forest cover within 500 m (%) = 52.4 (mean)), with 95% confidence band (from the asymptotic normal distribution of the maximum-likelihood estimates). Diverging curves mean the co-occurrence association changes along the gradient; parallel curves on the logit scale mean it does not. Co-occurrence is not evidence of an ecological interaction. Rug: covariate values at the surveyed sites.
Figure: Second-order natural parameter f_AB (Coyote & Gray fox) expressed as a co-occurrence odds ratio exp(f_AB) (log axis) against Housing density (units per km²)…
interaction_housing_per_km2. Second-order natural parameter f_AB (Coyote & Gray fox) expressed as a co-occurrence odds ratio exp(f_AB) (log axis) against Housing density (units per km²), with 95% confidence band (from the asymptotic normal distribution of the maximum-likelihood estimates). Dashed line: odds ratio 1 (species occur independently). Above 1: the pair occurs together more often than expected under independence; below 1: less often. Co-occurrence is not evidence of an ecological interaction. Rug: covariate values at the surveyed sites.
Figure: Change in each row species' occupancy probability where the column species is present vs absent, at average covariate values (Forest cover within 500 m (%) = 52.4 (mean)…
co_occurrence_matrix. Change in each row species' occupancy probability where the column species is present vs absent, at average covariate values (Forest cover within 500 m (%) = 52.4 (mean); Housing density (units per km²) = 39.4 (geometric mean, as the model uses its logarithm)): P(row | column present) - P(row | column absent), with 95% confidence intervals. Red: the species is more likely to occupy sites where the other is present; blue: less likely. Co-occurrence is not evidence of an ecological interaction.
Figure: Probability of detecting each species on one survey where it is present, against Camera-days active in the week (other detection covariates held at Camera on trail = no (reference level)), with 95% confidence intervals.
detection_days_active. Probability of detecting each species on one survey where it is present, against Camera-days active in the week (other detection covariates held at Camera on trail = no (reference level)), with 95% confidence intervals.
Figure: Probability of detecting each species on one survey where it is present, against Camera on trail (other detection covariates held at Camera-days active in the week = 6.52 (mean)), with 95% confidence intervals.
detection_on_trail. Probability of detecting each species on one survey where it is present, against Camera on trail (other detection covariates held at Camera-days active in the week = 6.52 (mean)), with 95% confidence intervals.
Figure: Detection probability per survey for each species against each detection covariate (in each panel, the other detection covariates held at Camera-days active in the week = 6.52 (mean)…
detection. Detection probability per survey for each species against each detection covariate (in each panel, the other detection covariates held at Camera-days active in the week = 6.52 (mean); Camera on trail = no (reference level)), with 95% confidence intervals.
Figure: Link-scale coefficients shown as odds ratios (log axis); dashed line = 1 (no effect).
coefficients. Link-scale coefficients shown as odds ratios (log axis); dashed line = 1 (no effect). Covariate effects are per 1 SD of the (transformed) covariate, or a factor level vs the reference level. Interaction intercepts are co-occurrence odds ratios at average covariate values; interaction slopes multiply that odds ratio per 1 SD. Bars: 95% Wald confidence intervals.
Figure: Goodness of fit (parametric bootstrap): histogram of the fit statistic (chi-square on the number of sites with 0, 1, 2, ... detections of each species + chi-square on the number of sites where each pair was detected together) for…
gof. Goodness of fit (parametric bootstrap): histogram of the fit statistic (chi-square on the number of sites with 0, 1, 2, ... detections of each species + chi-square on the number of sites where each pair was detected together) for data simulated from the fitted model; line = observed data. p = 0.25, c-hat = 1.12; p < 0.05 indicates lack of fit.

Limits that matter at this design

Commands to reproduce

bin/ejob -c 1 -m 4 -t 0:10:00 -l logs/occu-rota_si_truth.log -- bin/Rscript dev/occu-rota/si/si_truth.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/occu-rota_si_recover.log -- bin/Rscript core/run.R recover occu-rota --config modules/occu-rota/example/recovery.yaml --nsim 200 --cores 16 --out results/occu-rota/si/recovery
bin/ejob -c 16 -m 32 -t 1:00:00 -l logs/occu-rota_si_fullrecover.log -- bin/Rscript dev/occu-rota/si/si_full_recovery.R 200 16
bin/ejob -c 16 -m 32 -t 1:00:00 -l logs/occu-rota_si_fullrecover_s2027000.log -- bin/Rscript dev/occu-rota/si/si_full_recovery.R 200 16 2027000
bin/ejob -c 1 -m 4 -t 0:10:00 -l logs/occu-rota_si_fullrecover_pool.log -- bin/Rscript dev/occu-rota/si/pool_full.R
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/occu-rota_si_fit.log -- bin/Rscript core/run.R fit occu-rota --config modules/occu-rota/example/config.yaml --out results/occu-rota/si/fit
python3 dev/occu-rota/si/make_si_summary.py

Step-by-step walkthrough: modules/occu-rota/example/WALKTHROUGH.md.

S1.6 occu-waddle: Do invasive Cuban treefrogs push out native green treefrogs? Two-species conditional occupancy from PVC-pipe surveys (simulated data)

DONE

Question

Is green treefrog occupancy lower at sites where Cuban treefrogs occur, and is green treefrog detection lower on visits when Cuban treefrogs are found in the pipes, after allowing for both species being missed?

What the researcher typed

I have pipe-survey data for Cuban treefrogs and green treefrogs at 180 sites, 5 visits each, in pipe_surveys.csv, and site information (distance to road, canopy cover) in sites.csv. I want to know whether green treefrogs occupy fewer sites where Cuban treefrogs are present, and whether green treefrogs are harder to detect on visits when Cuban treefrogs are found. Cuban treefrog detection probably depends on air temperature. Please run the analysis and give me a report with figures I can use in a paper.

Study design

ItemValue
n_sites180
n_visits_per_site5
visits_done840
visits_missed60
prop_missing0.067
pipes_per_site10
site_covariateslog(dist_road_m) on psiA, canopy_pct on psiBA and psiBa
survey_covariatesair_temp_c on pA and pB
sites_cuban_detected90
sites_green_detected81
sites_both_detected23
data_simulatedyes
generatordev/occu-waddle/make_example.R, set.seed(2010)

True values used to simulate the example data

ItemValue
occ_dominant0.525
occ_dominant_beta_log_dist_road_m-0.9
occ_sub_given_dom_present0.2497
occ_sub_given_dom_present_beta_canopy_pct0.6
occ_sub_given_dom_absent0.69
occ_sub_given_dom_absent_beta_canopy_pct0.5
det_dominant_alone0.55
det_dominant_alone_beta_air_temp_c0.3782
det_sub_alone0.6
det_sub_alone_beta_air_temp_c0.2701
det_dominant_with_sub0.55
det_sub_with_dom_detected0.3
det_sub_with_dom_missed0.55
occ_subordinate0.4589
occ_both0.1311
species_interaction_factor0.5443
occ_log_odds_ratio_sub-1.9
det_log_odds_ratio_sub-1.048

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
det_dominant_alone0.550.5487-0.00240.965–PASS
det_dominant_alone_beta_effort0.3780.39430.04310.950.93PASS
det_dominant_with_sub0.550.5438-0.01130.965–PASS
det_log_odds_ratio_sub-1.048-1.0150.03170.9450.615PASS
det_sub_alone0.60.60590.00990.945–PASS
det_sub_alone_beta_effort0.270.27770.02860.940.575PASS
det_sub_with_dom_detected0.30.30510.01710.935–PASS
det_sub_with_dom_missed0.550.5403-0.01770.94–PASS
occ_both0.13110.1340.02250.94–PASS
occ_dominant0.5250.52720.00430.945–PASS
occ_dominant_beta_habitat-0.9-0.9403-0.04480.9551PASS
occ_log_odds_ratio_sub-1.9-1.947-0.02450.9651PASS
occ_sub_given_dom_absent0.690.69820.0120.96–PASS
occ_sub_given_dom_absent_beta_habitat0.50.50690.01370.940.39PASS
occ_sub_given_dom_present0.24970.25560.02350.96–PASS
occ_sub_given_dom_present_beta_habitat0.60.60760.01270.940.53PASS
occ_subordinate0.45880.46480.01290.955–PASS
species_interaction_factor0.54420.54990.01040.971PASS

Estimates from the example data

paramestimateloweruppertruth
occ_dominant0.52240.43960.60610.525
occ_dominant_beta_log_dist_road_m-0.9237-1.336-0.5626-0.9
occ_sub_given_dom_present0.30570.2080.42710.2497
occ_sub_given_dom_present_beta_canopy_pct0.1288-0.40150.68230.6
occ_sub_given_dom_absent0.67440.55780.78210.69
occ_sub_given_dom_absent_beta_canopy_pct0.75840.29941.2890.5
det_dominant_alone0.56040.49260.62530.55
det_dominant_alone_beta_air_temp_c0.58770.33840.86890.3782
det_sub_alone0.60290.53860.66450.6
det_sub_alone_beta_air_temp_c0.1923-0.06080.45230.2701
det_dominant_with_sub0.45710.34940.56670.55
det_sub_with_dom_detected0.23430.13060.36310.3
det_sub_with_dom_missed0.49870.35660.6370.55
occ_subordinate0.48230.40240.56750.4589
occ_both0.15920.10380.23180.1311
species_interaction_factor0.63690.46470.8130.5443
occ_log_odds_ratio_sub-1.549-2.311-0.8174-1.9
det_log_odds_ratio_sub-1.181-2.006-0.4038-1.048

Convergence and goodness of fit

ItemValue
enginenimble
chains3
niter6000
nburnin1000
rhat_max1
ess_bulk_min11939
convergedyes
gof_ndraws500
gof_p_codetection_pattern0.48
gof_p_site_detection_counts0.65

Interpretation from the report

Where Cuban treefrog is present, green treefrog occupies 0.31 (95% CrI 0.21 to 0.43) of sites; where Cuban treefrog is absent, 0.67 (95% CrI 0.56 to 0.78).
The odds of green treefrog occupying a site are 0.21 (95% CrI 0.10 to 0.44) times as high where Cuban treefrog is present.
The species interaction factor is 0.64 (95% CrI 0.46 to 0.81): at average conditions the two species co-occur less often than expected if they were distributed independently (a segregation pattern).
Occupancy of Cuban treefrog: the odds are multiplied by 0.40 (95% CrI 0.26 to 0.57) per 1 SD of log(dist_road_m); it decreases from 0.96 at 29 m to 0.09 at 5410 m.
Occupancy of green treefrog where Cuban treefrog is absent: the odds are multiplied by 2.13 (95% CrI 1.35 to 3.63) per 1 SD of canopy cover (from 0.33 at 3% to 0.89 at 89%); where Cuban treefrog is present there is no clear change (1.14, 95% CrI 0.67 to 1.98).
Where both occur, green treefrog is detected on 0.23 (95% CrI 0.13 to 0.36) of surveys that detected Cuban treefrog and on 0.50 (95% CrI 0.36 to 0.64) of surveys that missed it; log-odds ratio -1.18 (95% CrI -2.01 to -0.40). This is a detection effect, not an occupancy effect.
A difference between psiBA and psiBa, or an SIF away from 1, is a co-occurrence pattern, consistent with competition or predation but equally with both species responding to habitat features not in the model; it does not by itself show that Cuban treefrog excludes green treefrog.

Figures

Figure: (A) Occupancy at average covariate values (covariates held at Distance to nearest road (m) = 546 (geometric mean); Canopy cover (%) = 47.1 (mean)): Cuban treefrog, green treefrog overall…
conditional_occupancy. (A) Occupancy at average covariate values (covariates held at Distance to nearest road (m) = 546 (geometric mean); Canopy cover (%) = 47.1 (mean)): Cuban treefrog, green treefrog overall, and green treefrog conditional on Cuban treefrog being absent or present (point = posterior median; lines = 95% credible interval; inner band / thick line = 50%). (B) Occupancy of green treefrog where Cuban treefrog is present (long dashes) vs absent (short dashes) along Canopy cover (%), no other covariates in these formulas; bands = 95% credible intervals; inner band / thick line = 50%; rug = observed sites.
Figure: Species interaction factor SIF = P(both)/(P(Cuban treefrog) x P(green treefrog)) (MacKenzie et al. 2004); dashed line = 1 (the species occur independently)…
sif. Species interaction factor SIF = P(both)/(P(Cuban treefrog) x P(green treefrog)) (MacKenzie et al. 2004); dashed line = 1 (the species occur independently); < 1 = they co-occur less often than expected by chance. (A) At average covariate values (covariates held at Distance to nearest road (m) = 546 (geometric mean); Canopy cover (%) = 47.1 (mean)), point = posterior median with 95% credible interval; inner band / thick line = 50%. (B) Along Distance to nearest road (m) (log-scaled axis, as the covariate enters the model as a log), other covariates held at Canopy cover (%) = 47.1 (mean); line = posterior median; band = 95% credible interval; inner band / thick line = 50%; rug = observed sites. SIF depends on occupancy of Cuban treefrog, so report it with the log-odds ratio of psiBA vs psiBa.
Figure: Per-survey detection probabilities at average survey conditions (covariates held at Air temperature (°C) = 25 (mean); point = posterior median; lines = 95% credible intervals…
detection_interaction. Per-survey detection probabilities at average survey conditions (covariates held at Air temperature (°C) = 25 (mean); point = posterior median; lines = 95% credible intervals; inner band / thick line = 50%). rBA vs rBa compares detection of green treefrog, where both species occur, on surveys that did vs did not detect Cuban treefrog. pA vs rA and pB vs rBa compare detection where the other species is absent vs present. Parameters without their own formula are constrained equal and shown once.
Figure: Covariate effects as odds ratios per 1 SD of each numeric covariate (or vs the reference level for factors): point = posterior median, thin line = 95% credible interval; thick line = 50%; dashed line = no effect; log-scaled axis.
coefficients. Covariate effects as odds ratios per 1 SD of each numeric covariate (or vs the reference level for factors): point = posterior median, thin line = 95% credible interval; thick line = 50%; dashed line = no effect; log-scaled axis. Colour and shape = species whose probability the coefficient acts on. 1 SD: log(Distance to nearest road (m)) = 0.888; Canopy cover (%) = 23.1; Air temperature (°C) = 2.49. Parameter names follow Richmond et al. (2010): psiA (Cuban treefrog occupancy), psiBA / psiBa (green treefrog occupancy with Cuban treefrog present / absent), pA, pB, rA, rBA, rBa (detection).
Figure: Occupancy along Distance to nearest road (m) (log-scaled axis, as the covariate enters the model as a log) (other covariates held at Canopy cover (%) = 47.1 (mean)): Cuban treefrog…
occupancy_dist_road_m. Occupancy along Distance to nearest road (m) (log-scaled axis, as the covariate enters the model as a log) (other covariates held at Canopy cover (%) = 47.1 (mean)): Cuban treefrog, green treefrog overall (averaged over Cuban treefrog presence), and green treefrog with Cuban treefrog present / absent. Bands = 95% credible intervals; inner band / thick line = 50%; rug = observed sites. Curves that are flat do not depend on this covariate in the fitted model.
Figure: Occupancy along Canopy cover (%) (other covariates held at Distance to nearest road (m) = 546 (geometric mean)): green treefrog overall (averaged over Cuban treefrog presence)…
occupancy_canopy_pct. Occupancy along Canopy cover (%) (other covariates held at Distance to nearest road (m) = 546 (geometric mean)): green treefrog overall (averaged over Cuban treefrog presence), and green treefrog with Cuban treefrog present / absent. Bands = 95% credible intervals; inner band / thick line = 50%; rug = observed sites. Curves that are flat do not depend on this covariate in the fitted model.
Figure: Per-survey detection probability along Air temperature (°C) (no other covariates in these formulas); bands = 95% credible intervals; inner band / thick line = 50%; rug = surveys done.
detection_air_temp_c. Per-survey detection probability along Air temperature (°C) (no other covariates in these formulas); bands = 95% credible intervals; inner band / thick line = 50%; rug = surveys done. Only detection parameters whose formula includes this covariate are drawn.
Figure: Posterior Predictive Check of the number of sites in each co-detection class (neither, Cuban treefrog only, green treefrog only, both detected).
gof. Posterior Predictive Check of the number of sites in each co-detection class (neither, Cuban treefrog only, green treefrog only, both detected). Values right of the line mean replicated data fit worse than the observed data; p = 0.48 (extreme values near 0 or 1 indicate lack of fit).
Figure: MCMC traces of all coefficients on the logit scale (slopes per 1 SD of the covariate), one colour per chain; well-mixed chains overlap with no trend.
trace. MCMC traces of all coefficients on the logit scale (slopes per 1 SD of the covariate), one colour per chain; well-mixed chains overlap with no trend.
Figure: Posterior densities of the interaction quantities at average covariate values (all chains pooled).
posterior. Posterior densities of the interaction quantities at average covariate values (all chains pooled). Dashed lines = no interaction (SIF = 1, log-odds ratio = 0).

Limits that matter at this design

truth realised

ItemValue
sites_cuban_present93
sites_green_present88
sites_both_present29

recovery meta

ItemValue
nsim200
converged200
failed0
median_seconds_per_fit36
coverage_bound0.904
passed18/18
notemodule simulate() uses one shared standardised habitat covariate for all three occupancy probabilities; intercepts and slopes equal the example truth

estimates cover truth

18/18

Commands to reproduce

bin/ejob -c 1 -m 4 -t 0:15:00 -l logs/occu-waddle_si_truth.log -- bin/Rscript dev/occu-waddle/si_truth.R
bin/ejob -c 4 -m 8 -t 0:30:00 -l logs/occu-waddle_si_selftest.log -- bin/Rscript core/run.R selftest occu-waddle --config modules/occu-waddle/example/recovery.yaml --nsim 4 --cores 4 --out dev/occu-waddle/si_selftest
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/occu-waddle_si_recover.log -- bin/Rscript core/run.R recover occu-waddle --config modules/occu-waddle/example/recovery.yaml --nsim 200 --cores 16 --out results/occu-waddle/si/recovery
bin/ejob -c 1 -m 4 -t 0:10:00 -l logs/occu-waddle_si_mdtable.log -- bin/Rscript dev/occu-waddle/mdtable.R results/occu-waddle/si/recovery
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/occu-waddle_si_fit.log -- bin/Rscript core/run.R fit occu-waddle --config modules/occu-waddle/example/config.yaml --out results/occu-waddle/si/fit
bin/Rscript core/run.R figures occu-waddle --fit results/occu-waddle/si/fit/occu-waddle_fit.rds --config modules/occu-waddle/example/config.yaml

Step-by-step walkthrough: modules/occu-waddle/example/WALKTHROUGH.md.

S1.7 occu-spatial: Fisher occupancy, canopy cover and elevation with residual spatial clustering (simulated camera-trap survey, 160 stations)

DONE DONE for the estimands that answer the question (covariate effects, occupancy, detection, mean occupancy, proportion occupied): all pass planted truth at this design (100/100 converged), the real fit converged and passed the PPC; spatial variance and range fail recovery on bias and are reported descriptively only, not interpreted.

Question

Is fisher occupancy associated with canopy cover and elevation, allowing for missed detections and for residual spatial clustering, and where in the 30 x 30 km block are fishers likely to occur?

What the researcher typed

I have fisher camera-trap data from 160 stations in the western Cascades, summer 2024, up to 6 weekly occasions per camera (some cameras died early). fisher_detections.csv has one row per station-week (station, week, start date, days the camera worked, detected 1/0). camera_stations.csv has UTM coordinates, canopy cover (%), elevation (m) and ownership. prediction_grid_1km.csv is a 1-km grid with the same covariates. Is fisher occupancy related to canopy cover and elevation? Please account for fishers we missed and for spatial clustering, and make a map of predicted occupancy. I need results and figures for a paper.

Study design

ItemValue
modelspPGOcc (spatial single-species occupancy, NNGP 15 neighbours)
n_sites160
max_surveys6
surveys_done903
prop_missing0.059
surveys_per_site6 = 138; 5 = 4; 4 = 6; 3 = 7; 2 = 5
extent_km30
site_spacing_km1.0-40.3 (5% quantile 4.2)
n_detections140
n_sites_detected70
naive_occupancy0.4375
prediction_cells900
mcmc3 chains x 50000 iter, burn-in 20000, thin 20

True values used to simulate the example data

ItemValue
occupancy_prob0.4256
psi_beta_canopy_cover_pct0.9002
psi_beta_elevation_m-0.4
detection_prob0.285
p_beta_days_active0.38
mean_occupancy0.4833
prop_sites_occupied0.5125
spatial_variance1
effective_range_km8
notesimulated (dev/occu-spatial/make_example.R, set.seed(20251)); slopes are logit change per 1 SD; occupancy_prob/detection_prob at mean covariates with spatial effect 0; prop_sites_occupied is realised (82/160)

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
occupancy_prob0.4260.44780.05120.93–PASS
psi_beta_canopy_cover_pct0.90.97380.0820.990.97PASS
psi_beta_elevation_m-0.4-0.4458-0.11460.950.33PASS
detection_prob0.2850.2814-0.01270.96–PASS
p_beta_days_active0.380.38020.00050.90.91PASS
mean_occupancy0.44530.46110.03610.95–PASS
prop_sites_occupied0.45160.46060.02030.97–PASS
spatial_variance11.4810.48121–FAIL
effective_range_km89.7050.21311–FAIL

Estimates from the example data

paramestimateloweruppertruth
occupancy_prob0.50080.3560.6550.4256
psi_beta_canopy_cover_pct1.010.50141.660.9002
psi_beta_elevation_m-0.5508-1.139-0.0285-0.4
detection_prob0.30040.24940.35330.285
p_beta_days_active0.39690.1180.7450.38
mean_occupancy0.50870.42940.5920.4833
prop_sites_occupied0.5080.46250.56580.5125
spatial_variance0.95440.17393.8891
spatial_decay_per_km0.44230.10510.6944–
effective_range_km8.7794.3228.558

Convergence and goodness of fit

ItemValue
convergedyes
max_rhat1.006
min_ess_bulk672
max_rhat_covariate_effects1.002
min_ess_covariate_effects2190
runtime_s283
goftest = Freeman-Tukey posterior predictive check, site-level detection counts; bayesian_p = 0.55; verdict = no evidence of lack of fit
prior_checkspatial variance 95% CrI 0.17-3.89 vs prior-only 0.18-4.13: prior-dominated; range posterior overlaps its prior

Interpretation from the report

Occupancy probability at average covariate values and zero spatial effect is 0.50 (95% CrI 0.36 to 0.65).
Averaged over the 160 surveyed sites, mean occupancy probability is 0.51 (95% CrI 0.43 to 0.59), and the estimated proportion of surveyed sites that are occupied is 0.51 (95% CrI 0.46 to 0.57), compared with 0.44 of sites where the species was detected at least once (the difference is the correction for missed detections).
Occupancy and Canopy cover (%): each 1-SD increase (1 SD = 12.9 in original units) multiplies the odds of occupancy by 2.75 (95% CrI 1.65 to 5.26); predicted occupancy goes from 0.28 at 1 SD below the mean to 0.73 at 1 SD above it (other covariates at their means). Per 10-unit increase the odds of occupancy are multiplied by 2.19 (95% CrI 1.48 to 3.64).
Occupancy and Elevation (m): each 1-SD increase (1 SD = 246 in original units) multiplies the odds of occupancy by 0.58 (95% CrI 0.32 to 0.97); predicted occupancy goes from 0.63 at 1 SD below the mean to 0.37 at 1 SD above it. Per 200-unit increase the odds of occupancy are multiplied by 0.64 (95% CrI 0.40 to 0.98).
Detection: when the species is present, a single survey detects it with probability 0.30 (95% CrI 0.25 to 0.35) (at average survey conditions).
Detection and Days camera active in the week: per 1-unit increase the odds of detection are multiplied by 1.48 (95% CrI 1.12 to 2.09). This is a detection effect (how easily the species is found), not a habitat effect.
The residual spatial variance is 0.95 (95% CrI 0.17 to 3.89) on the logit scale; its prior alone gives a 95% interval of 0.18 to 4.13, so the data add little information: these numbers mostly restate the prior and do not show whether residual clustering is strong or weak.
Model check: posterior predictive p-values (Freeman-Tukey, by site) are 0.55; no sign of lack of fit.
All effects are associations from observational data, not causal effects.

Figures

Figure: Occupancy probability vs Canopy cover (%) (posterior mean, 95% and 50% credible bands), other covariates at their means and spatial effect at zero; rug = surveyed sites.
effect_canopy_cover_pct. Occupancy probability vs Canopy cover (%) (posterior mean, 95% and 50% credible bands), other covariates at their means and spatial effect at zero; rug = surveyed sites.
Figure: Occupancy probability vs Elevation (m) (posterior mean, 95% and 50% credible bands), other covariates at their means and spatial effect at zero; rug = surveyed sites.
effect_elevation_m. Occupancy probability vs Elevation (m) (posterior mean, 95% and 50% credible bands), other covariates at their means and spatial effect at zero; rug = surveyed sites.
Figure: Per-survey detection probability vs Days camera active in the week (posterior mean, 95% and 50% credible bands), other detection covariates at their means; rug = surveys.
detection_days_active. Per-survey detection probability vs Days camera active in the week (posterior mean, 95% and 50% credible bands), other detection covariates at their means; rug = surveys.
Figure: Occupancy (circles) and detection (triangles) coefficients on the logit scale (per 1 SD of the covariate): posterior means with 95% (thin) and 50% (thick) credible intervals; dashed line = no association.
coefficients. Occupancy (circles) and detection (triangles) coefficients on the logit scale (per 1 SD of the covariate): posterior means with 95% (thin) and 50% (thick) credible intervals; dashed line = no association.
Figure: Predicted occupancy probability (posterior mean, A) and its uncertainty (posterior SD, B) on the prediction grid; points = surveyed sites.
occupancy_map. Predicted occupancy probability (posterior mean, A) and its uncertainty (posterior SD, B) on the prediction grid; points = surveyed sites.
Figure: Posterior mean of the spatial random effect (logit scale) interpolated to the prediction grid: red = more occupied than the covariates predict, blue = less, white = as predicted; points = surveyed sites.
spatial_effect_map. Posterior mean of the spatial random effect (logit scale) interpolated to the prediction grid: red = more occupied than the covariates predict, blue = less, white = as predicted; points = surveyed sites.
Figure: Posterior of the effective spatial range (distance at which residual correlation falls to 0.05; filled) and the exact prior density implied by the uniform prior on phi (dashed), both on the prior's support.
range. Posterior of the effective spatial range (distance at which residual correlation falls to 0.05; filled) and the exact prior density implied by the uniform prior on phi (dashed), both on the prior's support. Overlap with the prior shows how little the data say about the range.
Figure: Posterior predictive check: Freeman-Tukey discrepancy of replicated vs observed site-level detection counts, one point per posterior draw; diagonal line = 1:1.
gof. Posterior predictive check: Freeman-Tukey discrepancy of replicated vs observed site-level detection counts, one point per posterior draw; diagonal line = 1:1. Points spread evenly around the line (Bayesian p near 0.5) indicate adequate fit (Bayesian p = 0.55).
Figure: MCMC traces per chain (post burn-in, thinned) for the main estimands; well-mixed chains overlap with no trend.
trace. MCMC traces per chain (post burn-in, thinned) for the main estimands; well-mixed chains overlap with no trend.

Limits that matter at this design

recovery settings

ItemValue
nsim100
converged100
failed0
seconds_per_fit_median77
configmodules/occu-spatial/example/recovery.yaml
notepower = share of reps whose 95% CrI excluded 0 (computed from the reps file); spatial_variance and effective_range_km fail bias and are descriptive only; elevation bias exceeds 10% but is within 3 MC SE

estimates nonspatial PGOcc

paramestimateloweruppertruth
occupancy_prob0.50490.40420.61470.4256
psi_beta_canopy_cover_pct0.86750.42571.3710.9002
psi_beta_elevation_m-0.4542-0.9179-0.0458-0.4
detection_prob0.30050.24880.35380.285
p_beta_days_active0.39740.1220.75860.38
mean_occupancy0.50840.42510.59650.4833
prop_sites_occupied0.5080.46250.56870.5125

Commands to reproduce

bin/ejob -c 1 -m 4 -t 0:20:00 -l logs/occu-spatial_make_example.log -- bin/Rscript dev/occu-spatial/make_example.R
bin/ejob -c 1 -m 4 -t 0:20:00 -l logs/occu-spatial_si_truth.log -- bin/Rscript dev/occu-spatial/si_truth.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/occu-spatial_si_recover.log -- bin/Rscript core/run.R recover occu-spatial --config modules/occu-spatial/example/recovery.yaml --nsim 100 --cores 16 --out results/occu-spatial/si/recovery
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/occu-spatial_si_fit.log -- bin/Rscript core/run.R fit occu-spatial --config modules/occu-spatial/example/config.yaml --out results/occu-spatial/si/fit
bin/ejob -c 4 -m 16 -t 1:00:00 -l logs/occu-spatial_si_fit_pgocc.log -- bin/Rscript core/run.R fit occu-spatial --config dev/occu-spatial/si_config_pgocc.yaml --out results/occu-spatial/si/fit_pgocc

Step-by-step walkthrough: modules/occu-spatial/example/WALKTHROUGH.md.

S1.8 abund-interactions: Abundance-mediated species interactions: pine marten abundance and red squirrel occupancy (simulated camera-trap example)

OPEN Planted truth at the example design (260 sites) fails for gamma0 (psi_beta_dominant_abundance): relative bias -11.0% (limit 10%; 3.2 MCSE) with coverage 0.95. Known limit 1 in VALIDATION.md. Convergence, GOF, cross-checks, negative control and reproducibility pass. Read the gamma0 interval, not its point estimate.

Question

Is red squirrel occupancy lower at sites used by more pine martens, and does that association depend on the share of native broadleaf woodland?

What the researcher typed

I have camera-trap data from 260 woodland sites in Northern Ireland: deployments.csv (camera start and end dates), records.csv (every photo, with species) and sites.csv (woodland cover and broadleaf share within 1 km). Is red squirrel occupancy lower where there are more pine martens, and does that depend on how much of the woodland is native broadleaf? Please give me a report with figures I can use in a paper.

Study design

ItemValue
n_sites260
n_occasions4
days_per_occasion7
camera_days_total6939
prop_site_occasions_effort_loss0.089
prop_site_occasions_no_effort0.03
habitat_interactionyes
interaction_modifierbroadleaf_pct
lambda_formula~ woodland_pct
psi_formula~ woodland_pct + broadleaf_pct
data_simulatedyes
data_seed2024
nsim_recovery100

True values used to simulate the example data

ItemValue
dominant_abundance1
lambda_beta_woodland0.5
dominant_detection_per_individual0.08
subordinate_occupancy_no_dominant0.6
psi_beta_woodland0.5
psi_beta_broadleaf0.3
psi_beta_dominant_abundance-0.6
psi_beta_dominant_abundance_x_broadleaf0.6
subordinate_detection0.15
interaction_at_low_broadleaf_pct-1.344
interaction_at_high_broadleaf_pct0.164
realised_dominant_total_abundance274
realised_dominant_prop_occupied0.592
realised_subordinate_prop_occupied0.504

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
dominant_detection_per_individual0.080.08140.01730.97–PASS
dominant_mean_abundance10.9862-0.01380.96–PASS
dominant_prop_occupied0.630.6287-0.00210.92–PASS
dominant_total_abundance293.6292.8-0.00280.98–PASS
lambda_beta_woodland0.50.50750.01510.941PASS
psi_beta_broadleaf0.30.36540.21810.950.34PASS
psi_beta_dominant_abundance-0.6-0.6659-0.10980.950.97FAIL
psi_beta_dominant_abundance_x_broadleaf0.60.65470.09120.960.92PASS
psi_beta_woodland0.50.5510.10210.920.86PASS
subordinate_detection0.150.15030.00180.95–PASS
subordinate_occupancy_no_dominant0.60.60960.0160.92–PASS
subordinate_prop_occupied0.46350.46460.00241–PASS

Estimates from the example data

paramestimatelowerupper
dominant_mean_abundance0.8530.6981.032
lambda_beta_woodland_pct0.53140.3860.6725
dominant_detection_per_individual0.08430.07090.0975
subordinate_occupancy_no_dominant0.62440.52730.7208
psi_beta_woodland_pct0.48750.16310.8294
psi_beta_broadleaf_pct0.0222-0.36650.3955
psi_beta_dominant_abundance-0.5301-0.933-0.1665
psi_beta_dominant_abundance_x_broadleaf_pct0.69020.30491.136
subordinate_detection0.15220.14040.1646
interaction_at_low_broadleaf_pct-1.386-2.159-0.7024
interaction_at_high_broadleaf_pct0.3488-0.16870.9295
dominant_total_abundance256.2224298
dominant_prop_occupied0.58220.55770.6115
subordinate_prop_occupied0.5130.50.5269

Convergence and goodness of fit

ItemValue
convergedyes
max_rhat1.001
min_ess_bulk3279
chains3
niter20000
nburnin5000
thin5
ppc_p_dominant0.51
ppc_p_subordinate0.32
gof_statisticFreeman-Tukey on site detection totals
recovery_replicates_converged100/100

Interpretation from the report

Each 1-SD increase in woodland_pct (1 SD = 17.4 units) is associated with 1.70 (95% CI 1.47 to 1.96) times the expected Pine marten abundance (a +70% change) (per 10 units: rate ratio 1.36 (95% CI 1.25 to 1.47)).
Interaction at average habitat: each additional Pine marten individual at a site is associated with 0.59 (95% CI 0.39 to 0.85) times the odds that Red squirrel occupies the site (odds ratio per individual); on the logit scale the coefficient is -0.53 (95% CI -0.93 to -0.17) per individual. The posterior probability that the association is negative is > 0.99.
Predicted Red squirrel occupancy at average habitat: 0.62 (0.52-0.72) at a site with no Pine marten, 0.50 (0.42-0.57) with 1, 0.37 (0.25-0.49) with 2 and 0.26 (0.12-0.44) with 3 individuals (posterior medians, 95% CI).
Habitat dependence: the interaction changes by 0.69 (95% CI 0.30 to 1.14) logit units per individual for each 1-SD (20.8 units) increase in broadleaf_pct; the 95% interval excludes zero, so the data support an interaction whose strength depends on habitat.
Where broadleaf_pct = 12.9 (10th percentile): odds ratio per Pine marten individual 0.25 (95% CI 0.12 to 0.50) (negative).
Where broadleaf_pct = 65.2 (90th percentile): odds ratio per Pine marten individual 1.42 (95% CI 0.84 to 2.53) (not clearly different from zero).
Comparison with the common two-step shortcut (estimate Pine marten abundance first, then use it as a fixed covariate): the shortcut gives -0.48 (95% CI -0.81 to -0.15), with an interval 86% as wide as the joint model's. The joint model carries the uncertainty in each site's abundance into the interaction; the shortcut treats estimated abundance as if it were known, and in simulations it is biased towards zero with too-narrow intervals.
Caution: this is an association between the dominant's estimated abundance and the subordinate's occupancy, not proof of predation or competition. Unmodelled habitat preferences shared (or opposed) by the two species produce the same signal, so include the main habitat drivers of both species. Royle-Nichols abundance assumes individuals are detected independently and abundance is Poisson among sites; absolute abundance is less reliable than relative differences. Simulation checks for this module (VALIDATION.md) recovered the interaction without bias at 600 sites (4 weekly occasions of daily records), including when the dominant's per-individual daily detection was as low as 0.03; in an independent check with 700 sites and a weaker interaction its size was overstated by about 12%, and with 150-300 sites by roughly 10-20% (credible intervals kept near-nominal coverage). With fewer than about 1000 sites, read the interval rather than the point estimate.

Figures

Figure: Red squirrel occupancy against Pine marten abundance at the 10th, 50th and 90th percentiles of Broadleaf share (%) (posterior median, 95% and 50% credible bands).
interaction_by_habitat. Red squirrel occupancy against Pine marten abundance at the 10th, 50th and 90th percentiles of Broadleaf share (%) (posterior median, 95% and 50% credible bands). Different slopes across panels mean the association between the species depends on habitat.
Figure: Predicted probability that Red squirrel occupies a site against the number of Pine marten individuals using it (posterior median, 95% and 50% credible bands…
subordinate_vs_dominant. Predicted probability that Red squirrel occupies a site against the number of Pine marten individuals using it (posterior median, 95% and 50% credible bands; full posterior uncertainty of all coefficients), other covariates at their means and habitat at its average. Rug: posterior mean Pine marten abundance at each surveyed site.
Figure: Strength of the abundance-mediated interaction across Broadleaf share (%) (logit scale; below the dashed line = fewer Red squirrel where there are more Pine marten).
interaction_strength_broadleaf_pct. Strength of the abundance-mediated interaction across Broadleaf share (%) (logit scale; below the dashed line = fewer Red squirrel where there are more Pine marten). Band: 95% credible interval; rug: surveyed sites.
Figure: Expected number of Pine marten individuals using a site against Woodland cover within 1 km (%) (posterior median with 95% and 50% credible bands), other covariates at their means.
dominant_abundance_woodland_pct. Expected number of Pine marten individuals using a site against Woodland cover within 1 km (%) (posterior median with 95% and 50% credible bands), other covariates at their means. Rug: surveyed sites.
Figure: Red squirrel occupancy against Woodland cover within 1 km (%) at sites with no Pine marten and with 2 (90th percentile of estimated site abundance); 95% credible bands; other covariates at their means.
subordinate_occupancy_woodland_pct. Red squirrel occupancy against Woodland cover within 1 km (%) at sites with no Pine marten and with 2 (90th percentile of estimated site abundance); 95% credible bands; other covariates at their means.
Figure: Posterior mean number of Pine marten individuals using each surveyed site (colour, viridis scale).
dominant_abundance_map. Posterior mean number of Pine marten individuals using each surveyed site (colour, viridis scale). Coordinates are the projected site coordinates divided by 1000 (assumed metres, shown as km).
Figure: Regression coefficients on the link scale (log for abundance, logit for occupancy and detection) with 95% credible intervals; dashed line = no effect.
coefficients. Regression coefficients on the link scale (log for abundance, logit for occupancy and detection) with 95% credible intervals; dashed line = no effect. Continuous covariates were standardised, so each slope is the change per 1 SD of that covariate (SD in original units in square brackets); factor levels are contrasts with the reference level. Interaction terms: change in Red squirrel log-odds of occupancy per Pine marten individual.
Figure: Interaction estimates from the joint model and from the two-step shortcut that plugs in estimated Pine marten abundance as if known (points: estimates; bars: 95% intervals).
joint_vs_twostep. Interaction estimates from the joint model and from the two-step shortcut that plugs in estimated Pine marten abundance as if known (points: estimates; bars: 95% intervals). The joint model propagates abundance uncertainty. Rows at the 10th and 90th percentiles give the slope at those habitat values; the 'x' row is the change in slope per 1 SD of the habitat variable. Interaction slopes are per Pine marten individual on the logit scale of Red squirrel occupancy.
Figure: Posterior predictive check: distribution of the Freeman-Tukey discrepancy of replicated minus observed site detection totals; values centred on 0 (line) indicate adequate fit.
gof. Posterior predictive check: distribution of the Freeman-Tukey discrepancy of replicated minus observed site detection totals; values centred on 0 (line) indicate adequate fit.
Figure: MCMC traces for the intercepts and interaction coefficients (link scale; one colour per chain).
trace. MCMC traces for the intercepts and interaction coefficients (link scale; one colour per chain). Well-mixed chains overlap with no trend.
Figure: Posterior densities (all chains pooled) of the intercepts and interaction coefficients on the link scale; dashed line = 0 (no interaction), drawn on the interaction panels only.
posterior. Posterior densities (all chains pooled) of the intercepts and interaction coefficients on the link scale; dashed line = 0 (no interaction), drawn on the interaction panels only.

Limits that matter at this design

Commands to reproduce

bin/ejob -c 1 -m 4 -t 0:20:00 -l logs/abund-interactions_make_example.log -- bin/Rscript dev/abund-interactions/make_example.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/abund-interactions_si_recover.log -- bin/Rscript core/run.R recover abund-interactions --config modules/abund-interactions/example/recovery.yaml --nsim 100 --cores 16 --out results/abund-interactions/si/recovery
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/abund-interactions_si_fit.log -- bin/Rscript core/run.R fit abund-interactions --config modules/abund-interactions/example/config.yaml --out results/abund-interactions/si/fit
../.venv/bin/python dev/abund-interactions/si/make_si_summary.py

Step-by-step walkthrough: modules/abund-interactions/example/WALKTHROUGH.md.

Abundance

S1.9 nmixture: Hermit warbler abundance from repeated point counts (static binomial N-mixture model)

DONE

Question

How many Hermit warblers are at 120 Coast Range survey points, allowing for birds present but not counted, and is abundance associated with canopy cover and elevation?

What the researcher typed

I have Hermit warbler point counts from 120 points, each visited up to 3 times between mid-May and mid-June. The counts are in point_counts.csv (one row per visit, with wind, day of year and observer). The habitat for each point is in points.csv (canopy cover and elevation). Please estimate how many warblers there are, allowing for birds we missed, and tell me whether abundance is related to canopy cover and elevation.

Study design

ItemValue
n_sites120
n_visits3
visits_done346
prop_missing0.039
observers3
abundance_distPoisson
modelstatic (closed) N-mixture
engineunmarked::pcount (maximum likelihood)

True values used to simulate the example data

ItemValue
abundance_at_average_site2.102
total_abundance273
mean_abundance_per_site2.275
detection_prob0.5529
lambda_beta_canopy_cover_pct0.4343
rate_ratio_canopy_cover_pct1.544
lambda_beta_elevation_m0.1763
rate_ratio_elevation_m1.193
p_beta_wind_beaufort-0.4963
odds_ratio_detection_wind_beaufort0.6088
p_beta_julian_day-0.2301
odds_ratio_detection_julian_day0.7945
p_beta_observerMLR0
odds_ratio_detection_observerMLR1
p_beta_observerSAT-0.4
odds_ratio_detection_observerSAT0.6703

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
abundance_at_average_site2.1022.1190.0078980.95–PASS
detection_prob0.5530.5491-0.0070210.96–PASS
lambda_beta_forest0.4340.4325-0.0033790.9651PASS
mean_abundance_per_site2.3062.3490.018720.985–PASS
odds_ratio_detection_wind0.6090.6085-0.00081570.97–PASS
p_beta_wind-0.496-0.5012-0.01040.971PASS
rate_ratio_forest1.5431.5440.00057390.9651PASS
total_abundance276.7281.90.018720.985–PASS

Estimates from the example data

paramestimateloweruppertruth
abundance_at_average_site2.0051.6862.3842.102
detection_prob0.51460.41460.61330.5529
lambda_beta_canopy_cover_pct0.46330.31740.60920.4343
rate_ratio_canopy_cover_pct1.5891.3731.8391.544
lambda_beta_elevation_m0.17790.048250.30750.1763
rate_ratio_elevation_m1.1951.0491.361.193
p_beta_wind_beaufort-0.7101-0.9055-0.5147-0.4963
odds_ratio_detection_wind_beaufort0.49160.40430.59770.6088
p_beta_julian_day-0.1841-0.3396-0.02858-0.2301
odds_ratio_detection_julian_day0.83190.71210.97180.7945
p_beta_observerMLR0.45150.027330.87570
odds_ratio_detection_observerMLR1.5711.0282.4011
p_beta_observerSAT-0.2856-0.71480.1436-0.4
odds_ratio_detection_observerSAT0.75160.48931.1540.6703
total_abundance271.7244308273
mean_abundance_per_site2.2642.0332.5672.275

Convergence and goodness of fit

ItemValue
convergedyes
enginemaximum likelihood; optimiser converged, all SEs finite, no boundary estimates (no R-hat/ESS)
K_values36, 54, 72
K_sensitivity_max_change_pct0
aicP = 836.5; NB = 838.5; ZIP = 838.5
gofnboot = 300; chisq = 397.3; c_hat = 1.17; p_chisq = 0.06; p_freeman_tukey = 0.143
recoverynsim = 200; n_failed = 0; coverage_bound = 0.904; all_pass = yes

Interpretation from the report

At a site with average covariate values the model expects 2.00 (95% CI 1.69 to 2.38) Hermit warblers.
Summed over the 120 surveyed sites, estimated abundance is 272 (95% CI 244 to 308) (an average of 2.26 (95% CI 2.03 to 2.57) per site).
The sum of the largest count at each site was 217, so the model infers that about 20% of the animals present were missed even on the visit with the highest count.
Each increase of 1 SD (19.74 units) in Canopy cover is associated with expected abundance being multiplied by 1.59 (95% CI 1.37 to 1.84), i.e. +59% (95% CI +37% to +84%).
Across the observed range (16.00 to 98.00) expected abundance per site goes from 0.71 to 4.90, other covariates held at their mean.
Each increase of 1 SD (293.79 units) in Elevation is associated with expected abundance being multiplied by 1.19 (95% CI 1.05 to 1.36), i.e. +19% (95% CI +5% to +36%).
Detection: on a visit with average covariate values (Observer 'JDK') each animal present had a 0.51 (95% CI 0.41 to 0.61) probability of being counted; over 3 such visits the probability of counting an animal at least once is 0.89 (0.80 to 0.94).
Each increase of 1 SD (1.10 units) in Wind multiplies the odds of detecting an animal by 0.49 (95% CI 0.40 to 0.60).
Model fit: no significant lack of fit at the 5% level, but the p-value is borderline (c-hat 1.17, smaller of the chi-square and Freeman-Tukey p-values = 0.06).
Relative differences among sites and covariate effects (rate ratios) are more robust than the absolute totals. All covariate relationships are associations, not demonstrated causes.

Figures

Figure: Expected abundance per site versus Canopy cover (line: estimate; outer and inner bands: 95% and 50% confidence intervals; other covariates at their mean or reference level; rug: observed values).
abundance_canopy_cover_pct. Expected abundance per site versus Canopy cover (line: estimate; outer and inner bands: 95% and 50% confidence intervals; other covariates at their mean or reference level; rug: observed values).
Figure: Expected abundance per site versus Elevation (line: estimate; outer and inner bands: 95% and 50% confidence intervals; other covariates at their mean or reference level; rug: observed values).
abundance_elevation_m. Expected abundance per site versus Elevation (line: estimate; outer and inner bands: 95% and 50% confidence intervals; other covariates at their mean or reference level; rug: observed values).
Figure: Detection probability per visit versus Wind (line: estimate; outer and inner bands: 95% and 50% confidence intervals; other covariates at their mean or reference level; rug: observed values, jittered slightly).
detection_wind_beaufort. Detection probability per visit versus Wind (line: estimate; outer and inner bands: 95% and 50% confidence intervals; other covariates at their mean or reference level; rug: observed values, jittered slightly). This is a detection effect: it changes how many animals are counted, not how many are there.
Figure: Detection probability per visit versus Day of year (line: estimate; outer and inner bands: 95% and 50% confidence intervals; other covariates at their mean or reference level; rug: observed values, jittered slightly).
detection_julian_day. Detection probability per visit versus Day of year (line: estimate; outer and inner bands: 95% and 50% confidence intervals; other covariates at their mean or reference level; rug: observed values, jittered slightly). This is a detection effect: it changes how many animals are counted, not how many are there.
Figure: Detection probability per visit versus Observer (point: estimate; thin and thick bars: 95% and 50% confidence intervals; other covariates at their mean or reference level).
detection_observer. Detection probability per visit versus Observer (point: estimate; thin and thick bars: 95% and 50% confidence intervals; other covariates at their mean or reference level). This is a detection effect: it changes how many animals are counted, not how many are there.
Figure: All covariate effects on expected abundance per site (panels A, B; same conventions as the single-effect figures: 95% and 50% confidence intervals, other covariates at their mean or reference level).
abundance_effects. All covariate effects on expected abundance per site (panels A, B; same conventions as the single-effect figures: 95% and 50% confidence intervals, other covariates at their mean or reference level).
Figure: All covariate effects on detection probability per visit (panels A, B, C; same conventions as the single-effect figures: 95% and 50% confidence intervals, other covariates at their mean or reference level).
detection_effects. All covariate effects on detection probability per visit (panels A, B, C; same conventions as the single-effect figures: 95% and 50% confidence intervals, other covariates at their mean or reference level).
Figure: Rate ratios (abundance, recruitment) and odds ratios (detection, survival) per 1 SD of each numeric covariate, or relative to the reference level of a categorical covariate (points: estimates…
coefficients. Rate ratios (abundance, recruitment) and odds ratios (detection, survival) per 1 SD of each numeric covariate, or relative to the reference level of a categorical covariate (points: estimates; thin and thick bars: 95% and 50% confidence intervals, Wald intervals on the log scale); log scale; dashed line = no effect (1).
Figure: Estimated abundance of Hermit warblers at each surveyed site (points; bars: 95% confidence intervals including parameter uncertainty; the per-site interval level is fixed at fit time) and the largest count made there (crosses).
abundance_by_site. Estimated abundance of Hermit warblers at each surveyed site (points; bars: 95% confidence intervals including parameter uncertainty; the per-site interval level is fixed at fit time) and the largest count made there (crosses). The gap between them is what the model attributes to imperfect detection.
Figure: Distribution of total abundance of Hermit warblers across the surveyed sites (draws from the sampling distribution of the parameters combined with the conditional distribution of each site's N).
total_abundance. Distribution of total abundance of Hermit warblers across the surveyed sites (draws from the sampling distribution of the parameters combined with the conditional distribution of each site's N). Solid line: estimate; dashed lines: 95% interval; shaded: 50% interval. Dot-dash line: sum of the largest count at each site (217), a minimum count.
Figure: Goodness of fit, parametric bootstrap: histogram of the chi-square statistic for data simulated from the fitted model; vertical line: observed data (c-hat 1.17, p = 0.06).
gof. Goodness of fit, parametric bootstrap: histogram of the chi-square statistic for data simulated from the fitted model; vertical line: observed data (c-hat 1.17, p = 0.06). Small p (< 0.05) means the counts vary more than the model allows.
Figure: Sensitivity of estimated total abundance to the upper bound K used to sum over possible abundances (Dennis et al. 2015); the model is refitted at each K and total abundance is the sum of each site's expected N given its counts at…
K_sensitivity. Sensitivity of estimated total abundance to the upper bound K used to sum over possible abundances (Dennis et al. 2015); the model is refitted at each K and total abundance is the sum of each site's expected N given its counts at the point estimates (a plug-in value, so it can differ slightly from the reported total, which also averages over parameter uncertainty). The y axis spans +/- 5% of the estimate; a flat line means K is large enough.

Limits that matter at this design

Commands to reproduce

bin/ejob -c 1 -m 4 -t 0:20:00 -l logs/nmixture_make_example.log -- bin/Rscript dev/nmixture/make_example.R
bin/ejob -c 1 -m 4 -t 0:20:00 -l logs/nmixture_si_truth.log -- bin/Rscript dev/nmixture/si_truth.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/nmixture_si_recover.log -- bin/Rscript core/run.R recover nmixture --config modules/nmixture/example/recovery.yaml --nsim 200 --cores 16 --out results/nmixture/si/recovery
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/nmixture_si_fit.log -- bin/Rscript core/run.R fit nmixture --config modules/nmixture/example/config.yaml --out results/nmixture/si/fit

Step-by-step walkthrough: modules/nmixture/example/WALKTHROUGH.md.

S1.10 distance: Mule deer density on a winter range from line-transect distance sampling, with shrub-cover and road-distance effects (simulated data)

OPEN All estimands that answer the question (density, abundance, per-unit density, detection, habitat rate ratio) pass planted truth at this design, the fit converged and both GOF checks pass; but the HDS density at an average transect (whose uncertainty also sets the bands on the conditional-effect curves and the map) under-covers (0.885 vs bound 0.904; VALIDATION.md Known limit 9, prepared fix not installed).

Question

How many mule deer are on the 360 km2 winter range (per km2 and in total, overall and in the north and south units), and is deer density higher where shrub cover is higher and farther from the highway?

What the researcher typed

I have a mule deer line-transect survey in modules/distance/example: a file of deer groups seen with the perpendicular distance from the line (m), group size, observer and date; a file of the 36 transects with their length, management unit (north or south, 180 km2 each), shrub cover and distance to the highway; and a 1 km2 grid of the whole 360 km2 winter range with the same two habitat values. Please estimate how many deer there are per km2 and in total, for each unit and overall, and tell me whether deer are more common where shrub cover is higher and farther from the road. Check that the method works for a survey like mine before you trust it, and give me a report and figures I can put in a paper.

Study design

ItemValue
modelconventional distance sampling (Distance::ds: half-normal / hazard-rate + cosine adjustments, AIC model-averaged, R2 variance) + hierarchical distance sampling (unmarked::distsamp) for habitat effects
surveyline transects, single visit, exact distances
transects36
transects_with_zero_detections1
line_length_km1.89-4.10 (mean 3.19)
total_line_km114.9
study_area_km2360
stratanorth 180 km2, south 180 km2
truncation_m400
detections146
detections_within_truncation145
deer_counted486
mean_group_size_observed3.33
observers2
density_covariatesshrub_cover_pct, road_dist_km
prediction_grid_cells360

True values used to simulate the example data

ItemValue
seed2025
generatordev/distance/make_example.R
density_per_km211.31
abundance4071
density_per_km2_north8.428
density_per_km2_south14.19
group_density_per_km23.326
mean_group_size3.4
detection_prob0.4557
esw_m182.3
sigma_m_observer_AB165
sigma_m_observer_JK135
sigma_equivalent_single_m146.4
shrub_rate_ratio_per_10pp1.649
road_rate_ratio_per_3km1.278
rate_ratio_shrub_cover_pct1.631
rate_ratio_road_dist_km1.25
density_at_average_site10.38

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowern_convergedn_rancoverage_boundpass
abundance41934149-0.01020.975–2002000.904PASS
density_at_average_site10.3710.32-0.00530.885–2002000.904FAIL
density_beta_habitat0.490.4881-0.0040.9512002000.904PASS
density_per_km211.6711.54-0.01020.975–2002000.904PASS
density_per_km2_S111.6211.47-0.01490.97–2002000.904PASS
density_per_km2_S211.7111.61-0.00540.985–2002000.904PASS
detection_prob0.45460.46550.02390.955–2002000.904PASS
esw_m181.9186.20.02390.955–2002000.904PASS
group_density_at_average_site3.053.038-0.00390.89–2002000.904FAIL
group_density_per_km23.433.4-0.00890.995–2002000.904PASS
mean_group_size3.43.394-0.00180.925–2002000.904PASS
rate_ratio_habitat1.6321.6350.00180.9512002000.904PASS
sigma_m146145.8-0.00140.972–1421420.895PASS

Estimates from the example data

paramestimateloweruppertruth
density_per_km211.989.24415.5411.31
abundance4314332855934071
density_per_km2_north7.9715.67911.198.428
abundance_north143510222014–
density_per_km2_south1611.6122.0414.19
abundance_south287920903967–
group_density_per_km23.5912.8164.583.326
mean_group_size3.3373.1233.5653.4
detection_prob0.43750.37760.49920.4557
esw_m175151.1199.7182.3
sigma_m138121.9156.3–
encounter_rate_per_km4.1913.3665.218–
density_at_average_site10.368.09112.9310.38
group_density_at_average_site3.12.4823.843–
density_beta_shrub_cover_pct0.62410.43260.8157–
rate_ratio_shrub_cover_pct1.8671.5412.2611.631
density_beta_road_dist_km0.3060.10640.5055–
rate_ratio_road_dist_km1.3581.1121.6581.25
abundance_hds439534295444–
density_per_km2_hds12.219.52515.12–
shrub_rate_ratio_per_10pp1.891.562.31.649
road_rate_ratio_per_3km1.41.121.741.278

Convergence and goodness of fit

ItemValue
convergedyes
engineds+hds
ds_keyhalf-normal (dAIC hazard-rate 1.94; Akaike weight 0.72)
hds_keyhalf-normal (dAIC hazard-rate 1.42)
cvm_W0.075
cvm_p0.72
hds_freeman_tukey_p0.315
hds_gof_nboot200
density_cv0.13
encounter_rate_cv0.11
ds_vs_hds_density11.98, 12.2
notes

Interpretation from the report

A group within 400 m of the line had probability 0.44 (95% CI 0.38 to 0.50) of being detected. Equivalently, the effective strip half-width is 175 m.
Density: 12.0 (95% CI 9.24 to 15.5) individuals per km2, which over the 360 km2 study area is 4,314 (95% CI 3,328 to 5,593) individuals.
This is 3.59 (95% CI 2.82 to 4.58) groups per km2 times a mean group size of 3.34 (95% CI 3.12 to 3.56).
By stratum: north 7.97 (95% CI 5.68 to 11.2) per km2; south 16.0 (95% CI 11.6 to 22.0) per km2.
Each increase of 10 percentage points in shrub cover multiplies expected density by 1.89 (95% CI 1.56 to 2.30), i.e. +89%.
Each increase of 3 km in distance from road multiplies expected density by 1.40 (95% CI 1.12 to 1.74), i.e. +40%.
This is an association from an observational survey, not proof that shrub cover causes the difference.
The hierarchical model's density over the study area (12.2 (95% CI 9.70 to 15.3) per km2) agrees with the design-based estimate above.
Goodness of fit: Cramer-von Mises test of the distances, p = 0.72. No evidence of lack of fit.

Figures

Figure: Expected mule deer density versus shrub cover from the hierarchical distance-sampling model (road distance at its mean), with 95% and 50% bands; points are rough per-transect densities.
density_shrub_cover_pct. Expected mule deer density versus shrub cover from the hierarchical distance-sampling model (road distance at its mean), with 95% and 50% bands; points are rough per-transect densities.
Figure: Fitted half-normal detection function (model-averaged with hazard-rate) with 95% and 50% confidence bands over the histogram of the 145 perpendicular distances within 400 m, scaled to detection probability.
detection_function. Fitted half-normal detection function (model-averaged with hazard-rate) with 95% and 50% confidence bands over the histogram of the 145 perpendicular distances within 400 m, scaled to detection probability.
Figure: Q-Q plot of the detection function; points on the dashed line mean the fitted distance distribution matches the data.
qq_gof. Q-Q plot of the detection function; points on the dashed line mean the fitted distance distribution matches the data. Cramer-von Mises W = 0.075, p = 0.72.
Figure: Expected mule deer density versus distance from the highway (shrub cover at its mean), with 95% and 50% bands; points are rough per-transect densities.
density_road_dist_km. Expected mule deer density versus distance from the highway (shrub cover at its mean), with 95% and 50% bands; points are rough per-transect densities.
Figure: Conditional effects of shrub cover (A) and road distance (B) on deer density.
effects_panel. Conditional effects of shrub cover (A) and road distance (B) on deer density.
Figure: Multiplicative change in deer density per 1 SD of each covariate (shrub cover 9.8 %, road distance 2.7 km) with 95% Wald confidence intervals; dashed line = no effect.
coefficients. Multiplicative change in deer density per 1 SD of each covariate (shrub cover 9.8 %, road distance 2.7 km) with 95% Wald confidence intervals; dashed line = no effect.
Figure: Design-based deer density in the north unit, south unit and whole 360 km2 winter range with 95% log-normal confidence intervals.
density_by_stratum. Design-based deer density in the north unit, south unit and whole 360 km2 winter range with 95% log-normal confidence intervals.
Figure: A: predicted deer density per km2 over the 1 km2 grid from the hierarchical model; white dots are the 36 transects.
density_map. A: predicted deer density per km2 over the 1 km2 grid from the hierarchical model; white dots are the 36 transects. B: its standard deviation. Cells with shrub cover outside 13.9-45.4 % are extrapolations.

Limits that matter at this design

recovery meta

ItemValue
nsim200
configmodules/distance/example/recovery.yaml
median_fit_s9.1
converged200/200
notedensity_at_average_site coverage 0.92 in the 142 replicates where a plain half-normal was AIC-best, 0.81 in the other 58 (VALIDATION.md Known limit 9).

Commands to reproduce

bin/Rscript -e 'source("core/R/env.R"); source("dev/distance/si/example_truth.R")'
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/distance_si_recover.log -- bin/Rscript core/run.R recover distance --config modules/distance/example/recovery.yaml --nsim 200 --cores 16 --out results/distance/si/recovery
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/distance_si_fit.log -- bin/Rscript core/run.R fit distance --config modules/distance/example/config.yaml --out results/distance/si/fit
python3 dev/distance/si/make_si_summary.py

Step-by-step walkthrough: modules/distance/example/WALKTHROUGH.md.

Spatial capture–recapture

S1.11 scr: Bobcat density from camera traps: closed spatial capture-recapture with a canopy-cover density covariate (simulated data)

DONE

Question

How many bobcats live in the study area (density per km2 and abundance), and is bobcat density higher where forest canopy cover is higher, allowing for cameras on trails detecting bobcats more often and for cameras that stopped working?

What the researcher typed

I have bobcat camera-trap data in modules/scr/example: a camera file with UTM coordinates, whether each camera was on a trail and which weeks it worked; a file of photo-detections of individually identified bobcats by week and camera; and a 400 m habitat grid with canopy cover and a flag for the reservoir. Please estimate bobcat density and how many bobcats live in the area, and tell me whether density is higher where canopy cover is higher. Check that the method works for a design like mine before you trust it, and give me a report and figures I can put in a paper.

Study design

ItemValue
modelclosed SCR, binomial detections, log-linear density in canopy cover, on-trail detection covariate
cameras48
camera_grid8 x 6
camera_spacing_m1600
mean_nearest_camera_distance_m1350
cameras_on_trail18
occasions_weeks8
camera_weeks_working354
camera_weeks_total384
detections114
individuals_detected33
individuals_at_more_than_one_camera25
spatial_recaptures53
mask_pixels_habitat2189
mask_spacing_m400
habitat_area_km2350.2
buffer_m5000
buffer_sigma3.8
nonhabitatreservoir, ~3% of the grid

True values used to simulate the example data

ItemValue
expected_density_per_km20.25
realised_abundance82
realised_density_per_km20.234
expected_abundance87.6
sigma_m1300
home_range_area_95_km231.8
baseline_detection_p0_offtrail0.12
detection_beta_on_trail1.1
density_beta_canopy_per_sd0.45
canopy_sd_pct14.7
elevation_effect0
seed20250601
generatordev/scr/make_example.R

Planted-truth recovery at this design

paramtruthmean_estrel_biasbias_mcsecoveragepowern_convergedn_rancoverage_boundpass
abundance96.798.430.01781.2650.948–961000.883PASS
baseline_detection0.120.12690.05720.00180.938–961000.883PASS
density_beta_canopy0.450.46530.0340.02120.9480.667961000.883PASS
density_per_km20.250.26060.04250.00430.948–961000.883PASS
detection_beta_on_trail1.11.059-0.03730.02020.9691961000.883PASS
home_range_area_9531.8131.55-0.00810.35620.948–961000.883PASS
sigma13001291-0.00697.2880.948–961000.883PASS

Estimates from the example data

paramestimateloweruppersdrhatess_bulk
density_per_km20.23660.15690.34150.04721.0041421
abundance82.665811815.361.0031565
baseline_detection0.11950.08230.16370.02081.0012081
sigma13261165151090.031.0011634
home_range_area_9533.2725.5542.924.5721.0011634
density_beta_canopy_cover_pct0.41210.05680.76310.18361.0031132
detection_beta_on_trail1.1630.64661.6820.26491.002992

Convergence and goodness of fit

ItemValue
enginenimble marginal (RW_block), 3 chains x 20000 iterations, 5000 burn-in
rhat_max1.004
ess_bulk_min992
convergedyes
fit_time_s278
ppc_pn_detected = 0.52; total_detections = 0.5; traps_per_individual = 0.41; disp_detections = 0.47; ft_trap_totals = 0.92
secr_vs_nimble_density_diff_pct-2.8
secr_vs_nimble_density_diff_posterior_sd-0.14
spacing_sigma1
buffer_sigma3.8
posterior_cv_density0.2

Interpretation from the report

Density was estimated at 0.24 (95% CrI 0.16 to 0.34) animals per km², i.e. 23.7 per 100 km2.
Over the 350 km² of habitat in the state space (the detector array plus a buffer), that is 82.7 (95% CrI 58.0 to 118) animals, of whom 33 (40%) were detected.
The spatial scale of detection, sigma, was 1326 (95% CrI 1165 to 1510) m; a home-range area of about 33 (95% CrI 26 to 43) km². Real home ranges are rarely circular, so treat this as an index of ranging scale.
'Camera on trail' (1 vs 0) multiplied the odds of detection by 3.2 (95% interval 1.9 to 5.4). Baseline detection was 0.30 (0.21 to 0.41) where Camera on trail = 1 versus 0.12 where it = 0. This is a detection effect (how easily animals are recorded), not a difference in where animals live.
Each 1 SD (15 units) higher Canopy cover (%) is associated with 51% higher density (rate ratio 1.5, 95% interval 1.1 to 2.1). Posterior probability that the association is positive: 0.99.
Expected density is 0.13 per km² (0.070 to 0.20) where Canopy cover (%) = 34.9 (10th percentile of the habitat) and 0.37 (0.19 to 0.62) where it = 72.6 (90th percentile).
This is a correlation between density and habitat across the state space, not proof that the habitat causes higher density.

Figures

Figure: Posterior mean realised bobcat density (per km2) over the habitat; white dots = cameras; orange crosses = most likely activity centre of each of the 33 detected cats; blank = reservoir (not habitat).
density_surface. Posterior mean realised bobcat density (per km2) over the habitat; white dots = cameras; orange crosses = most likely activity centre of each of the 33 detected cats; blank = reservoir (not habitat).
Figure: Expected density implied by the canopy-cover model alone; the denser canopy in the south-west predicts more bobcats.
density_expected_surface. Expected density implied by the canopy-cover model alone; the denser canopy in the south-west predicts more bobcats.
Figure: Expected bobcat density versus canopy cover (%) with 50% and 95% credible bands; rug = canopy values across the habitat.
density_canopy_cover_pct. Expected bobcat density versus canopy cover (%) with 50% and 95% credible bands; rug = canopy values across the habitat.
Figure: Weekly detection probability versus distance from a bobcat's activity centre to the camera, off-trail (solid) and on-trail (dashed) cameras, 50% and 95% bands; dashed vertical line = camera spacing.
detection_function. Weekly detection probability versus distance from a bobcat's activity centre to the camera, off-trail (solid) and on-trail (dashed) cameras, 50% and 95% bands; dashed vertical line = camera spacing.
Figure: Baseline weekly detection probability p0 for off-trail (0.12) and on-trail (0.30) cameras with 95% credible intervals.
detection_on_trail. Baseline weekly detection probability p0 for off-trail (0.12) and on-trail (0.30) cameras with 95% credible intervals.
Figure: Posterior distribution of the number of bobcats in the 350 km2 of habitat; dashed lines = 95% credible interval; dotted line = 33 bobcats detected.
abundance_posterior. Posterior distribution of the number of bobcats in the 350 km2 of habitat; dashed lines = 95% credible interval; dotted line = 33 bobcats detected.
Figure: Observed number of bobcats detected 1, 2, ... times (bars) versus posterior predictive means and 95% intervals (points).
captures_per_individual. Observed number of bobcats detected 1, 2, ... times (bars) versus posterior predictive means and 95% intervals (points).
Figure: Posterior predictive checks: individuals detected, total detections, cameras per individual, dispersion of detections per individual, Freeman-Tukey statistic of camera totals.
gof. Posterior predictive checks: individuals detected, total detections, cameras per individual, dispersion of detections per individual, Freeman-Tukey statistic of camera totals.
Figure: Canopy-cover effect on density (log scale, per SD) and trail effect on detection (logit scale) with 95% intervals; dashed line = no effect.
coefficients. Canopy-cover effect on density (log scale, per SD) and trail effect on detection (logit scale) with 95% intervals; dashed line = no effect.
Figure: Same data fitted with Nimble (Bayesian marginal likelihood) and secr (maximum likelihood): estimates and 95% intervals agree.
engine_comparison. Same data fitted with Nimble (Bayesian marginal likelihood) and secr (maximum likelihood): estimates and 95% intervals agree.
Figure: MCMC traces of the reported quantities, three chains.
trace. MCMC traces of the reported quantities, three chains.
Figure: Posterior densities of the reported quantities.
posterior. Posterior densities of the reported quantities.

Limits that matter at this design

recovery meta

ItemValue
configmodules/scr/example/recovery.yaml
nsim100
n_converged96
gatePASS (7/7 estimands)
reason_nsim_100one fit takes ~3-4 min at this design (4-replicate selftest: 7 min on 4 cores)
design_notemodule simulator uses a square 7 x 7 array (49 cameras, 1600 m) in average habitat; replicates detected ~46 bobcats on average (20-replicate check) vs 33 in the example, because the example array sits in below-average canopy (mean 44.5% near cameras vs 53.8% over the habitat). Recovery truth for abundance is the expected value in the larger rectangular simulated state space (96.7).
matched_n_runconfig = modules/scr/example/recovery_matched_n.yaml; density_truth = 0.17; mean_detected = 32; gate = PASS (7/7 estimands); n_converged = 96; recovery = param = abundance; truth = 66.08; mean_est = 67.42; rel_bias = 0.0209; bias_mcse = 0.9839; coverage = 0.969; power = –; n_converged = 96; n_ran = 100; coverage_bound = 0.883; pass = yes, param = baseline_detection; truth = 0.12; mean_est = 0.1269; rel_bias = 0.0577; bias_mcse = 0.0024; coverage = 0.948; power = –; n_converged = 96; n_ran = 100; coverage_bound = 0.883; pass = yes, param = density_beta_canopy; truth = 0.45; mean_est = 0.444; rel_bias = -0.0133; bias_mcse = 0.0255; coverage = 0.885; power = 0.51; n_converged = 96; n_ran = 100; coverage_bound = 0.883; pass = yes, param = density_per_km2; truth = 0.17; mean_est = 0.1789; rel_bias = 0.0524; bias_mcse = 0.0033; coverage = 0.948; power = –; n_converged = 96; n_ran = 100; coverage_bound = 0.883; pass = yes, param = detection_beta_on_trail; truth = 1.1; mean_est = 1.076; rel_bias = -0.022; bias_mcse = 0.0247; coverage = 0.969; power = 0.979; n_converged = 96; n_ran = 100; coverage_bound = 0.883; pass = yes, param = home_range_area_95; truth = 31.81; mean_est = 31.94; rel_bias = 0.004; bias_mcse = 0.3949; coverage = 0.948; power = –; n_converged = 96; n_ran = 100; coverage_bound = 0.883; pass = yes, param = sigma; truth = 1300; mean_est = 1298; rel_bias = -0.0019; bias_mcse = 8.026; coverage = 0.948; power = –; n_converged = 96; n_ran = 100; coverage_bound = 0.883; pass = yes

estimates secr

paramestimatelowerupper
density_per_km20.230.15130.3495
abundance80.5459.09119.6
baseline_detection0.11460.08060.1607
sigma132411641516
home_range_area_9533.0125.5143.26
density_beta_canopy_cover_pct0.40580.0410.7729
detection_beta_on_trail1.1910.66951.703

Commands to reproduce

bin/ejob -c 1 -m 8 -t 0:30:00 -- bin/Rscript dev/scr/make_example.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/scr_si_recover.log -- bin/Rscript core/run.R recover scr --config modules/scr/example/recovery.yaml --nsim 100 --cores 16 --out results/scr/si/recovery
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/scr_si_recover_matched.log -- bin/Rscript core/run.R recover scr --config modules/scr/example/recovery_matched_n.yaml --nsim 100 --cores 16 --out results/scr/si/recovery_matched_n
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/scr_si_fit.log -- bin/Rscript core/run.R fit scr --config modules/scr/example/config.yaml --out results/scr/si/fit
bin/ejob -c 1 -m 8 -t 0:30:00 -- bin/Rscript core/run.R figures scr --fit results/scr/si/fit/scr_fit.rds --config modules/scr/example/config.yaml
../.venv/bin/python dev/scr/make_si_summary.py

Step-by-step walkthrough: modules/scr/example/WALKTHROUGH.md.

S1.12 scr-smr: Fisher density from ear tags and trail cameras: generalized spatial mark-resight (simulated data)

DONE

Question

How many fishers live in the study area (density per km2 and abundance), does density rise with canopy cover, and do trail cameras photograph fishers more often, given that tagged fishers were caught only at box traps in the middle of the camera grid?

What the researcher typed

I've put my fisher data in a folder: box-trap captures and trap locations from May, trail camera locations and a photo log from June to August, GPS fixes from 9 collared fishers, and a habitat grid with canopy cover. Some photos show a readable ear tag, some a tag we couldn't read, and most no tag. Please estimate fisher density and abundance, tell me whether density rises with canopy cover, and whether trail cameras get more photos. The box traps were only in the middle of the camera grid. Please check the method works for a design like mine before you trust it, and give me a report and figures I can use in a paper.

Study design

ItemValue
modelgsmr
resight_modelpoisson
cameras49
camera_spacing_m1500
resight_occasions_weeks10
cameras_on_trail24
marking_traps25
marking_spacing_m1500
marking_occasions_nights5
marked_animals23
collared_animals9
gps_fixes_per_collar30
photo_events360
photos_tag_read194
photos_tag_unreadable54
photos_no_tag112
mask_pixels1156
mask_spacing_m500
state_space_km2289
buffer_m4000

True values used to simulate the example data

ItemValue
expected_density_per_km20.25
expected_abundance73
realised_abundance86
realised_density_per_km20.298
realised_marked_fraction0.267
sigma_m1000
home_range_area_95_km218.8
resight_rate_lambda00.3
detection_beta_on_trail0.7
id_probability_delta0.8
marking_detection_pm00.3
density_beta_canopy_per_sd0.5
seed2025

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
abundance73.0176.090.04590.96–PASS
density_beta_canopy0.50.50890.01780.970.77PASS
density_per_km20.25260.26330.04590.96–PASS
detection_beta_on_trail0.70.6856-0.02060.911PASS
home_range_area_9518.8218.860.00190.97–PASS
id_probability0.80.7967-0.00410.93–PASS
marked_fraction0.30230.2951-0.01430.96–PASS
marking_detection0.30.30770.02580.94–PASS
resight_rate0.30.30890.02960.93–PASS
sigma100010000.00040.97–PASS

Estimates from the example data

paramestimatelowerupper
density_per_km20.30130.23530.3772
abundance87.0768109
marked_fraction0.26790.2110.3382
abundance_unmarked64.074586
sigma1010965.71057
home_range_area_9519.217.5521.02
resight_rate0.25910.20540.3218
id_probability0.780.72650.8289
marking_detection0.27680.21060.3516
density_beta_canopy_cover_pct0.49390.1830.7952
detection_beta_on_trail0.83350.58271.085

Convergence and goodness of fit

ItemValue
convergencemax_rhat = 1.002; min_ess_bulk = 2310; chains = 3; iterations = 24000; burnin = 6000; thin = 4; augmentation_M = 145
gof_pppunmarked_total = 0.65; identified_total = 0.45; marked_resighted = 0.9; unidentified_total = 0.5; ft_unmarked_cameras = 0.75; ft_marked_individuals = 0.64
design_checkscamera_spacing_over_sigma = 1.5; buffer_over_sigma = 4
secr_crosschecksigma, lambda0, pm0 agree; secr abundance ~59 is lower, as expected (secr joint gSMR ~26% low in validation)

Interpretation from the report

Density was estimated at 0.30 (95% CrI 0.24 to 0.38) fishers per km² (30.1 per 100 km2).
Over the 289 km² state space (camera array plus buffer) that is 87.1 (95% CrI 68.0 to 109) fishers, of which the 23 marked animals are a fraction 0.27 (95% CrI 0.21 to 0.34).
Sigma, the spatial scale of space use, was 1010 (95% CrI 966 to 1057) m: circular home range of 19 (95% CrI 18 to 21) km².
Each 1 SD (12 units) higher canopy cover is associated with 64% higher density (rate ratio 1.6, 95% interval 1.2 to 2.2); expected density 0.15 per km² (0.082 to 0.24) at 36% canopy and 0.59 (0.36 to 0.87) at 69% canopy.
This is an association between density and habitat across the state space, not proof that the habitat causes higher density.
A camera on a trail multiplied the sighting rate by 2.3 (95% interval 1.8 to 3.0). This is a detection effect, not a difference in where animals live.
Because marking was modelled, marked animals are not assumed to be a random sample: animals living near the marking traps are more likely to carry marks, and the model accounts for that (generalized SMR).

Figures

Figure: Expected density versus Canopy cover (%) (other density covariates at their state-space mean), with 95% and 50% credible bands.
density_canopy_cover_pct. Expected density versus Canopy cover (%) (other density covariates at their state-space mean), with 95% and 50% credible bands. Rug: covariate values across the state space.
Figure: Posterior mean realised density (animals per km²): marked and unmarked activity centres combined, averaged over 300 posterior draws.
density_surface. Posterior mean realised density (animals per km²): marked and unmarked activity centres combined, averaged over 300 posterior draws. Circles: cameras, triangles: marking traps; orange crosses: posterior mean activity centres of the 23 marked animals.
Figure: Expected density surface implied by the habitat model (Canopy cover (%)), posterior mean.
density_expected_surface. Expected density surface implied by the habitat model (Canopy cover (%)), posterior mean.
Figure: Half-normal detection functions with 95% and 50% credible bands: expected number of camera sightings per occasion; and per-occasion capture probability at a marking trap.
detection_function. Half-normal detection functions with 95% and 50% credible bands: expected number of camera sightings per occasion; and per-occasion capture probability at a marking trap. Dashed line: camera spacing (recommended <= 2 sigma).
Figure: Posterior distribution of the number of animals in the 289 km² state space; dashed lines: 95% credible interval; dotted line: number of marked animals (23), the lower bound.
abundance_posterior. Posterior distribution of the number of animals in the 289 km² state space; dashed lines: 95% credible interval; dotted line: number of marked animals (23), the lower bound.
Figure: Posterior of the marked fraction m/N (m = 23 marked animals); dashed lines: 95% credible interval.
marked_fraction. Posterior of the marked fraction m/N (m = 23 marked animals); dashed lines: 95% credible interval.
Figure: Bars: observed number of marked animals identified 0, 1, 2, ... times on camera.
captures_per_individual. Bars: observed number of marked animals identified 0, 1, 2, ... times on camera. Points and lines: posterior predictive mean and 95% interval. Bars outside the intervals indicate unmodelled heterogeneity among marked animals.
Figure: Unmarked sightings at each camera: observed versus expected under the fitted model; horizontal lines: 95% posterior predictive interval for that camera; dashed: 1:1.
unmarked_by_camera. Unmarked sightings at each camera: observed versus expected under the fitted model; horizontal lines: 95% posterior predictive interval for that camera; dashed: 1:1.
Figure: Posterior predictive checks: histograms of statistics from data replicated under the fitted model (line = observed); scatter panels: Freeman-Tukey discrepancy of unmarked sightings by camera and of identified sightings by marked…
gof. Posterior predictive checks: histograms of statistics from data replicated under the fitted model (line = observed); scatter panels: Freeman-Tukey discrepancy of unmarked sightings by camera and of identified sightings by marked animal, observed vs replicated (points spread on both sides of the 1:1 line = consistent with the model).
Figure: Link-scale coefficients with 95% intervals: density covariates on the log scale per 1 SD (exp(beta) = multiplicative change in density); camera covariates on the log (Poisson) or logit (Bernoulli) scale (0/1 covariates: level 1 vs…
coefficients. Link-scale coefficients with 95% intervals: density covariates on the log scale per 1 SD (exp(beta) = multiplicative change in density); camera covariates on the log (Poisson) or logit (Bernoulli) scale (0/1 covariates: level 1 vs 0). Dashed line: no effect.
Figure: The same data fitted by the Bayesian data-augmentation model (Nimble) and by maximum pseudo-likelihood (secr mark-resight; Efford & Hunter 2018). secr estimates expected abundance and treats unmarked counts as independent Poisson…
engine_comparison. The same data fitted by the Bayesian data-augmentation model (Nimble) and by maximum pseudo-likelihood (secr mark-resight; Efford & Hunter 2018). secr estimates expected abundance and treats unmarked counts as independent Poisson counts with an overdispersion adjustment. For gSMR, secr's joint fit underestimated abundance by about 26% in validation simulations (VALIDATION.md section 8), so a lower secr abundance here is expected; compare sigma and detection rates.
Figure: MCMC traces of the reported quantities, one colour per chain (thinned for display).
trace. MCMC traces of the reported quantities, one colour per chain (thinned for display).
Figure: Posterior densities of the reported quantities.
posterior. Posterior densities of the reported quantities.

Limits that matter at this design

recovery meta

ItemValue
nsim100
n_converged100
coverage_bound0.885
reason_nsim_100one fit takes ~2-5 min at this design
gatePASS (10/10)
recovery_truth_noterecovery truth for N/density is the expected value per replicate (73); bias computed against each replicate's realised truth

Commands to reproduce

bin/ejob -c 1 -m 8 -t 0:30:00 -l logs/scr-smr_make_example.log -- bin/Rscript dev/scr-smr/make_example.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/scr-smr_si_recover.log -- bin/Rscript core/run.R recover scr-smr --config modules/scr-smr/example/recovery.yaml --nsim 100 --cores 16 --out results/scr-smr/si/recovery
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/scr-smr_si_fit.log -- bin/Rscript core/run.R fit scr-smr --config modules/scr-smr/example/config.yaml --out results/scr-smr/si/fit
bin/ejob -c 2 -m 8 -t 0:30:00 -l logs/scr-smr_si_figures.log -- bin/Rscript core/run.R figures scr-smr --config modules/scr-smr/example/config.yaml --out results/scr-smr/si/fit

Step-by-step walkthrough: modules/scr-smr/example/WALKTHROUGH.md.

DONE

Question

How many fishers live in the study area and at what density, is density higher where there is more forest, and do experienced dog teams find more scats per km searched?

What the researcher typed

I ran a scat-detection-dog survey for fishers in the western Oregon Cascades in summer 2025: 36 search routes in three monthly sessions, each logged by GPS (search_tracks_gps.csv), with a field sheet per route saying which dog team searched and whether it was one of our experienced teams (track_field_sheet.csv). The scats and their genotypes are in fisher_scats.csv (blank fisher_id = failed genotype). I also have forest cover on a 700 m grid (habitat_grid.csv). Please estimate fisher density and abundance, tell me whether density is related to forest cover, and whether experienced teams find more scats per km. I'd like a report and figures for a paper.

Study design

ItemValue
searched_region_km16 x 16
buffer_m6000
state_space_km2784
mask_spacing_m700
mask_pixels1600
n_occasions3
n_routes36
routes_per_occasion12
route_km4.0-10.7
total_km_searched246.7
km_experienced_teams100.5
km_newer_teams146.2
road_bias0.4
cov_road_corr0.3
cell_size_m1000
detector_cells158
search_units291
scats_collected116
scats_failed_genotype35
scats_genotyped81
individuals_identified22
individuals_spatially_recaptured20
enginenimble (3 chains x 40000 iter, 10000 burn-in); compare_engines secr_cells

True values used to simulate the example data

ItemValue
density_per_km20.1
abundance_realised63
density_realised_per_km20.0804
lambda0_per_km0.2
sigma1500
home_range_area_9542.35
samples_per_track_through_centre0.752
density_beta_forest0.5
detection_beta_experienced_team0.6
seed2025
generatordev/scr-search/make_example.R

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
density_per_km20.10.10480.04760.91–PASS
abundance78.6482.090.04340.94–PASS
lambda0_per_km0.20.20570.02870.95–PASS
sigma150015240.01620.96–PASS
home_range_area_9542.3544.140.04220.96–PASS
samples_per_track_through_centre0.7520.77540.03110.97–PASS
density_beta_forest0.50.5110.0220.970.57PASS
detection_beta_experienced_team0.60.5437-0.09390.930.66PASS

Estimates from the example data

paramestimateloweruppertruth
density_per_km20.07040.045380.10090.1
abundance54.693876–
lambda0_per_km0.18050.11270.2740.2
sigma1561134518281500
home_range_area_9546.1634.0562.8742.35
samples_per_track_through_centre0.69960.46911.0070.752
density_beta_forest_pct0.93680.46771.435–
detection_beta_experienced_team0.5010.041890.94610.6

Convergence and goodness of fit

ItemValue
rhat_max1.001
ess_bulk_min3250
convergedyes
ppc_pn_detected = 0.49; total_samples = 0.445; cells_per_individual = 0.45; ft_cell_totals = 0.815; disp_samples = 0.3
density_posterior_cv0.2
posterior_median_density0.0697
posterior_median_N54
cell_size_over_sigma0.64
buffer_over_sigma3.8
fit_time_s254

Interpretation from the report

Density was estimated at 0.070 (95% CrI 0.045 to 0.10) animals per km², i.e. 7.04 per 100 km2. Over the 784 km² state space (the searched area plus a buffer), that is 54.7 (95% CrI 38.0 to 76.0) animals, of which 22 (40%) were identified from samples.
The spatial scale of space use, sigma, was 1561 (95% CrI 1345 to 1828) m. If space use is a circular bivariate normal around each activity centre, 95% of an animal's activity falls within 3821 m of its centre, a home-range area of about 46 (95% CrI 34 to 63) km²; treat this as an index of ranging scale.
Encounter rate: a searcher covering 1 km right at an animal's activity centre finds on average 0.18 (95% CrI 0.11 to 0.27) of its samples (at the reference level of the detection covariates); a long straight search route passing through the activity centre would yield 0.70 (95% CrI 0.47 to 1.0) samples of that animal.
Detection: 'Experienced dog team' (1 vs 0) multiplied the number of samples found per km searched by 1.65 (95% interval 1.04 to 2.58); per-km encounter rate at the activity centre 0.30 with Experienced dog team = 1 versus 0.18 with Experienced dog team = 0. This is a detection (search efficiency) effect, not a difference in where animals live.
Density and Forest cover (%): each 1 SD (12 units) higher Forest cover (%) is associated with 155% higher density (rate ratio 2.55, 95% interval 1.60 to 4.20). Expected density is 0.015 per km² (0.0036 to 0.037) where Forest cover (%) = 39.6 (10th percentile of the state space) and 0.16 (0.10 to 0.23) where it = 71.6 (90th percentile).
This is a correlation between density and habitat across the state space, not proof that the habitat causes higher density. Because search effort was modelled explicitly (km searched per cell), more samples in heavily searched areas are not mistaken for higher density.

Figures

Figure: Expected density versus Forest cover (%) (other density covariates at their state-space mean), with 95% and 50% credible bands.
density_forest_pct. Expected density versus Forest cover (%) (other density covariates at their state-space mean), with 95% and 50% credible bands. Rug: covariate values across the state space.
Figure: Search effort: length of search track (km) inside each 1000 m detector cell (fill), GPS tracks (grey lines) and genotyped samples (orange points; 81 samples of 22 individuals).
effort_map. Search effort: length of search track (km) inside each 1000 m detector cell (fill), GPS tracks (grey lines) and genotyped samples (orange points; 81 samples of 22 individuals). Unsearched ground has no detector.
Figure: Posterior mean realised density (animals per km²): identified animals placed by their estimated activity centres plus the expected density of animals never sampled.
density_surface. Posterior mean realised density (animals per km²): identified animals placed by their estimated activity centres plus the expected density of animals never sampled. White lines: search tracks; orange crosses: posterior mean activity centres of the 22 identified individuals.
Figure: Expected density surface implied by the habitat model (Forest cover (%)).
density_expected_surface. Expected density surface implied by the habitat model (Forest cover (%)).
Figure: Posterior mean probability that an animal whose activity centre is in each pixel left at least one sample that was found, given the realised search effort.
detection_map. Posterior mean probability that an animal whose activity centre is in each pixel left at least one sample that was found, given the realised search effort. Low values: animals there are effectively unsampled, so density there rests on the habitat model and the buffer.
Figure: Expected number of an animal's samples found per km of search, versus the distance of the search from its activity centre: lambda0 exp(-d^2 / 2 sigma^2), with 95% and 50% credible bands, by Experienced dog team.
detection_function. Expected number of an animal's samples found per km of search, versus the distance of the search from its activity centre: lambda0 exp(-d^2 / 2 sigma^2), with 95% and 50% credible bands, by Experienced dog team. Dashed line: detector cell size.
Figure: Encounter rate lambda0 (samples found per km searched at an animal's activity centre) without (No) and with (Yes) experienced dog team, with 95% credible intervals.
detection_experienced_team. Encounter rate lambda0 (samples found per km searched at an animal's activity centre) without (No) and with (Yes) experienced dog team, with 95% credible intervals.
Figure: Posterior distribution of the number of activity centres in the 784 km² state space; dashed lines: 95% credible interval; dotted line: number of individuals identified (22).
abundance_posterior. Posterior distribution of the number of activity centres in the 784 km² state space; dashed lines: 95% credible interval; dotted line: number of individuals identified (22).
Figure: Bars: observed number of individuals with 1, 2, ... samples.
captures_per_individual. Bars: observed number of individuals with 1, 2, ... samples. Points and lines: posterior predictive mean and 95% interval from data simulated under the fitted model with the realised search effort. Bars far outside the intervals indicate unmodelled heterogeneity (e.g. sex differences, latrines producing clusters of scats).
Figure: Posterior predictive checks: histograms of statistics from data simulated under the fitted model, line = observed value; last panel: Freeman-Tukey discrepancy of samples per detector cell…
gof. Posterior predictive checks: histograms of statistics from data simulated under the fitted model, line = observed value; last panel: Freeman-Tukey discrepancy of samples per detector cell, observed vs replicated (points above the 1:1 line = data consistent with the model).
Figure: Log-scale coefficients: density covariates per 1 SD of the covariate; detection (encounter-rate) covariates per 1 SD, or level 1 vs 0 for 0/1 covariates. exp(coefficient) is the rate ratio.
coefficients. Log-scale coefficients: density covariates per 1 SD of the covariate; detection (encounter-rate) covariates per 1 SD, or level 1 vs 0 for 0/1 covariates. exp(coefficient) is the rate ratio. Dashed line: no effect.
Figure: The same data fitted with each engine: Bayesian marginal likelihood on detector cells (Nimble, local evaluation), maximum likelihood of the same cell model (secr_cells) and maximum likelihood with the tracks as continuous transect…
engine_comparison. The same data fitted with each engine: Bayesian marginal likelihood on detector cells (Nimble, local evaluation), maximum likelihood of the same cell model (secr_cells) and maximum likelihood with the tracks as continuous transect detectors and exact sample locations (secr_transect). Agreement indicates the result depends neither on the software nor on discretising the tracks into cells.
Figure: MCMC traces of the reported quantities, one colour per chain (thinned).
trace. MCMC traces of the reported quantities, one colour per chain (thinned).
Figure: Posterior densities of the reported quantities.
posterior. Posterior densities of the reported quantities.

Limits that matter at this design

recovery notes

nsim = 100 (one fit ~4 min); 100/100 ran and converged (max R-hat 1.008); gate: |bias| <= max(10%, 3 MC SE), coverage >= 0.885; abundance truth is the mean over replicates (78.6); N-hat/N median 1.02 (5-95%: 0.71-1.42).

estimates secr cells

ItemValue
density_per_km20.0679, 0.0442, 0.1043
abundance53.3, 39.7, 77.2
sigma1554, 1333, 1812
density_beta_forest_pct0.942, 0.467, 1.417
detection_beta_experienced_team0.529, 0.069, 0.988

Commands to reproduce

bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/scr-search_si_recover.log -- bin/Rscript core/run.R recover scr-search --config modules/scr-search/example/recovery.yaml --nsim 100 --cores 16 --out results/scr-search/si/recovery
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/scr-search_si_fit.log -- bin/Rscript core/run.R fit scr-search --config modules/scr-search/example/config.yaml --out results/scr-search/si/fit
bin/ejob -c 2 -m 8 -t 0:20:00 -- bin/Rscript core/run.R figures scr-search --fit results/scr-search/si/fit/scr-search_fit.rds --config modules/scr-search/example/config.yaml

Step-by-step walkthrough: modules/scr-search/example/WALKTHROUGH.md.

S1.14 scr-open: Pacific marten abundance, survival, recruitment and canopy association from five years of DNA hair snares (open-population spatial capture-recapture, simulated data with known truth)

DONE Planted truth 28/28 pass at this design; R-hat <= 1.005, ESS >= 1035; all posterior predictive p-values 0.39-0.64; NumPyro agrees with Nimble; module negative controls fail as required (VALIDATION.md); reproducible commands. Caveat: total abundance depends on the canopy model because the snares sample thin canopy.

Question

How many Pacific martens live in the study area each summer (2020-2024), is the population declining, what are annual apparent survival and recruitment, and is marten density higher under denser canopy?

What the researcher typed

I have five summers (2020-2024) of marten hair-snare data from 49 snares on a 1-km grid, each checked 5 times a summer. hair_snares.csv has the snare locations (UTM) and which checks each snare was working; marten_genotypes.csv has one row per genotyped sample with year, check, snare and marten ID; and habitat_grid.csv has canopy cover on a 400 m grid around the snares. I want to know how many martens there are each year, whether they are declining, annual survival and recruitment, and whether density is higher under denser canopy. Please give me a report with figures I can use in a paper.

Study design

ItemValue
n_detectors49
detector_layout7 x 7 grid, 1000 m spacing
n_periods5
years2020-2024
n_occasions5
buffer_m3000
mask_spacing_m400
n_mask_pixels900
state_space_km2144
snare_outages2/0/2/3/5 snares not working on every check in 2020-2024
n_individuals_detected95
detected_per_year32, 38, 39, 41, 48
detected_in_2plus_years48
n_detections598
density_covariatecanopy_cover_pct
enginenimble marginal (3 chains x 30000, burn-in 10000, thin 2)
data_augmentation_M570

True values used to simulate the example data

ItemValue
density_period1_expected0.8
baseline_detection0.3
sigma800
survival0.8
per_capita_recruitment_expected0.25
density_beta_canopy1
abundance2020 = 127; 2021 = 131; 2022 = 133; 2023 = 145; 2024 = 158
superpopulation_size262
recruits2021 = 26; 2022 = 31; 2023 = 35; 2024 = 43
per_capita_recruitment2021 = 0.205; 2022 = 0.237; 2023 = 0.263; 2024 = 0.297
home_range_area_95_km212.05
true_centre_oracle_beta1.18
seed2025
generatordev/scr-open/make_example.R

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
abundance_period_1114.4115.30.00640.98–PASS
abundance_period_2118.6120.10.01230.95–PASS
abundance_period_3124.5125.50.00940.91–PASS
abundance_period_4131.2132.60.01160.95–PASS
abundance_period_5139140.90.01580.98–PASS
baseline_detection0.30.30070.00230.91–PASS
density_beta_canopy11.010.00990.981PASS
density_per_km2_period_10.79440.80060.00640.97–PASS
density_per_km2_period_20.82370.83430.01230.94–PASS
density_per_km2_period_30.86450.87170.00940.91–PASS
density_per_km2_period_40.91110.92060.01160.95–PASS
density_per_km2_period_50.96510.97830.01580.98–PASS
growth_rate_period_21.0371.050.01330.94–PASS
growth_rate_period_31.051.0490.00060.98–PASS
growth_rate_period_41.0541.0610.00680.96–PASS
growth_rate_period_51.0591.0670.00770.98–PASS
home_range_area_9512.0512.070.00190.96–PASS
per_capita_recruitment_period_20.24030.25290.05270.96–PASS
per_capita_recruitment_period_30.25640.2531-0.00480.99–PASS
per_capita_recruitment_period_40.24960.26010.04140.93–PASS
per_capita_recruitment_period_50.25230.26370.04440.97–PASS
recruits_period_227.4628.220.02970.95–PASS
recruits_period_330.4229.85-0.00720.96–PASS
recruits_period_431.0431.950.02960.94–PASS
recruits_period_533.1834.230.03680.98–PASS
sigma800800.50.00060.96–PASS
superpopulation_size236.5239.50.01350.93–PASS
survival0.80.7979-0.00270.98–PASS

Estimates from the example data

paramestimatelowerupper
abundance_period_2020119.485160.5
abundance_period_2021143.5110187
abundance_period_2022151.3117.5194.5
abundance_period_2023161.7125.5206.5
abundance_period_2024186144238
density_per_km2_period_20200.82910.59031.115
density_per_km2_period_20210.99640.76391.299
density_per_km2_period_20221.0510.81581.351
density_per_km2_period_20231.1230.87141.434
density_per_km2_period_20241.29111.653
superpopulation_size277.3222341
recruits_period_202141.451972
recruits_period_202232.271260
recruits_period_202334.551462
recruits_period_202449.6525.4882
per_capita_recruitment_period_20210.35850.14030.6791
per_capita_recruitment_period_20220.23020.08460.4594
per_capita_recruitment_period_20230.23320.08780.4375
per_capita_recruitment_period_20240.31220.14740.5224
growth_rate_period_20211.2140.981.554
growth_rate_period_20221.0590.891.284
growth_rate_period_20231.0730.91881.273
growth_rate_period_20241.1540.98251.371
survival0.83920.7710.9052
baseline_detection0.31680.2820.3537
sigma802.9764.4845.9
home_range_area_9512.141113.47
density_beta_canopy_cover_pct1.3181.0621.612

Convergence and goodness of fit

ItemValue
rhat_max1.005
ess_bulk_min1035
convergedyes
nimble_time_s521
total_fit_time_s4433
ppc_pdetected_2020 = 0.47; detected_2021 = 0.49; detected_2022 = 0.55; detected_2023 = 0.64; detected_2024 = 0.52; n_detected = 0.53; detected_in_2plus_periods = 0.61; total_detections = 0.49; traps_per_individual_period = 0.46; gaps_in_histories = 0.39
spacing_over_sigma1.2
buffer_over_sigma3.7
habitat_extrapolationtrapped_canopy_sd_from_mean = -0.45; share_more_than_2sigma_from_traps = 0.72; density_ratio_statespace_vs_trapped = 1.94; warning = yes
engine_agreementnumpyro = abundance_2020 = 121, 87, 166; abundance_2024 = 187, 143, 240; superpopulation = 279; survival = 0.839; density_beta = 1.32; openCR_homogeneous = abundance_2020 = 71.7; abundance_2024 = 108; survival = 0.852; sigma = 788; per_capita_recruitment_2021 = 0.336

Interpretation from the report

Abundance in the 144 km² state space (traps plus buffer) was 119 (95% CrI 85.0 to 161) in period 2020 and 186 (95% CrI 144 to 238) in period 2024 (density 0.83 and 1.3 animals per km²).
Over the study the population changed by a factor of 1.58 (95% CrI 1.15 to 2.16); posterior probability of a decline from the first to the last period: < 0.01.
Apparent survival between consecutive periods was 0.84 (95% CrI 0.77 to 0.91): an animal alive in one period had an estimated 84% chance of still being alive and resident in the next. 'Apparent' because death and permanent emigration from the study area cannot be told apart.
Per-capita recruitment rates (recruits per animal alive in the previous period) were 2021: 0.36 (95% CrI 0.14 to 0.68); 2022: 0.23 (95% CrI 0.085 to 0.46); 2023: 0.23 (95% CrI 0.088 to 0.44); 2024: 0.31 (95% CrI 0.15 to 0.52).
In total 277 (95% CrI 222 to 341) different animals were alive in the state space at some point during the study (superpopulation), of whom 95 (34%) were ever detected.
A trap at an animal's activity centre detects it on a given occasion with probability 0.32 (95% CrI 0.28 to 0.35); the spatial scale sigma was 803 (95% CrI 764 to 846) m, so 95% of activity falls within 1966 m of the centre.
Each 1 SD (12) higher Canopy cover (%) is associated with 273% higher density (rate ratio 3.7, 95% CrI 2.9 to 5.0). This describes where animals' activity centres are, not proof that Canopy cover (%) causes higher density.
WARNING: the traps sample habitat of unrepresentative density (state-space average 1.94 x the trapped area), so total abundance rests on extrapolating the density covariate effect to habitat the traps did not cover.

Figures

Figure: Realised abundance per period (posterior mean, line) with 95% and 50% credible bands.
abundance_trajectory. Realised abundance per period (posterior mean, line) with 95% and 50% credible bands. Black points: number of individuals detected in each period (a minimum count). Density per km² = abundance / 144 km².
Figure: (A) Number of new animals entering the state space in each period and (B) per-capita recruitment (recruits per animal alive in the previous period); points are posterior means, thick and thin bars 50% and 95% credible intervals.
recruitment. (A) Number of new animals entering the state space in each period and (B) per-capita recruitment (recruits per animal alive in the previous period); points are posterior means, thick and thin bars 50% and 95% credible intervals.
Figure: Realised population growth rate between consecutive periods (posterior mean, 50% and 95% credible intervals); dashed line: stable population.
growth_rate. Realised population growth rate between consecutive periods (posterior mean, 50% and 95% credible intervals); dashed line: stable population.
Figure: Posterior distribution of apparent survival between consecutive periods (constant over time; Uniform(0,1) prior); dashed lines: 95% credible interval.
survival. Posterior distribution of apparent survival between consecutive periods (constant over time; Uniform(0,1) prior); dashed lines: 95% credible interval.
Figure: Posterior mean realised density (animals per km²) in each period: alive animals placed at their estimated activity centres, including animals never detected.
density_surface. Posterior mean realised density (animals per km²) in each period: alive animals placed at their estimated activity centres, including animals never detected. White circles: traps (200 posterior draws).
Figure: Expected density versus Canopy cover (%) in the first and last period (other covariates at their state-space mean), with 95% credible bands.
density_canopy_cover_pct. Expected density versus Canopy cover (%) in the first and last period (other covariates at their state-space mean), with 95% credible bands. Rug: covariate values across the state space.
Figure: Probability of detecting an animal at a trap on one occasion versus distance from its activity centre: half-normal p0 exp(-d^2 / 2 sigma^2), constant across periods, with 95% and 50% credible bands.
detection_function. Probability of detecting an animal at a trap on one occasion versus distance from its activity centre: half-normal p0 exp(-d^2 / 2 sigma^2), constant across periods, with 95% and 50% credible bands. Dashed line: trap spacing.
Figure: Bars: individuals detected in each period.
detection_by_period. Bars: individuals detected in each period. Points and bars: posterior predictive mean and 95% interval under the fitted model (constant p0 and sigma). Bars outside the intervals suggest detection varied between periods.
Figure: Posterior predictive checks: histograms of statistics computed from data simulated under the fitted model; line = observed value. 'Detected in 2+ periods' and 'missed periods' react to transients and temporary emigration…
gof. Posterior predictive checks: histograms of statistics computed from data simulated under the fitted model; line = observed value. 'Detected in 2+ periods' and 'missed periods' react to transients and temporary emigration; 'traps per individual-period' to the detection function.
Figure: Density covariate coefficients on the log scale per 1 SD of the covariate across the state space; dashed line: no association.
coefficients. Density covariate coefficients on the log scale per 1 SD of the covariate across the state space; dashed line: no association.
Figure: The same data fitted with each engine. openCR is maximum likelihood with a hazard half-normal detection function (its abundance is a point estimate from derived()…
engine_comparison. The same data fitted with each engine. openCR is maximum likelihood with a hazard half-normal detection function (its abundance is a point estimate from derived(); intervals not shown). openCR is fitted with homogeneous density, whereas the Bayesian fits include the habitat covariate: its abundance differs whenever the traps sample habitat of unrepresentative density (see the design notes); survival, recruitment and sigma remain comparable.
Figure: MCMC traces of key quantities, one colour per chain (thinned draws used for derived quantities).
trace. MCMC traces of key quantities, one colour per chain (thinned draws used for derived quantities).
Figure: Posterior densities of key quantities.
posterior. Posterior densities of key quantities.

Limits that matter at this design

recovery note

nsim = 100 (one fit takes ~7 min), module fast_settings; truth for realised quantities is the mean over replicates; 100/100 converged; gate 28/28 PASS

Commands to reproduce

bin/ejob -c 1 -m 4 -t 0:20:00 -l logs/scr-open_make_example.log -- bin/Rscript dev/scr-open/make_example.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/scr-open_si_recover.log -- bin/Rscript core/run.R recover scr-open --config modules/scr-open/example/recovery.yaml --nsim 100 --cores 16 --out results/scr-open/si/recovery
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/scr-open_si_fit.log -- bin/Rscript core/run.R fit scr-open --config modules/scr-open/example/config.yaml --out results/scr-open/si/fit
bin/ejob -c 1 -m 8 -t 0:30:00 -l logs/scr-open_si_figures.log -- bin/Rscript core/run.R figures scr-open --config modules/scr-open/example/config.yaml --fit results/scr-open/si/fit/scr-open_fit.rds
python3 dev/scr-open/make_si_summary.py

Step-by-step walkthrough: modules/scr-open/example/WALKTHROUGH.md.

Demography and population dynamics

S1.15 cjs: Adult song sparrow apparent survival from constant-effort banding (Cormack-Jolly-Seber, simulated data with known truth)

DONE

Question

What is annual apparent survival of adult song sparrows at a banding station, does it differ between sexes, and is it associated with winter cold and body mass, allowing for transient birds that never return?

What the researcher typed

I have nine years of song sparrow banding data from my station (2016 to 2024) in three files: sosp_captures.csv (every capture, with band number and date), sosp_birds.csv (sex and body mass of each bird when first banded) and sosp_years.csv (mean January minimum temperature for each winter). I want annual adult survival, whether it differs between males and females, and whether it is related to winter cold and body mass. Many birds are only caught once; I think some are migrants passing through. Please analyse this and give me a report with figures I can use in a paper.

Study design

ItemValue
n_occasions9
years2016-2024
n_intervals8
n_birds575
new_birds_per_year66-78 (mean 72) in 2016-2023
prop_male0.52
capture_rows1283
bird_seasons813
birds_recaptured158
occasion_covariatewinter_min_temp_c (8 winters used)
individual_covariatemass_g
groupsex (F reference)
enginemarked (maximum likelihood)
phi_formula~ tsm + sex + winter_min_temp_c + mass_g (fitted as ~ tsm * (sex + winter_min_temp_c + mass_g))
p_formula~ sex

True values used to simulate the example data

ItemValue
survival_female0.55
survival_male0.6226
phi_beta_sex_male0.3
phi_beta_winter_min_temp_per_sd0.4
phi_beta_mass_per_sd0.25
proportion_transient0.25
detection_female0.45
detection_male0.5743
p_beta_sex_male0.5
seed2031
generatordev/cjs/make_example.R

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
detection_female0.450.45160.00360.94–PASS
detection_male0.57430.5750.00120.96–PASS
p_beta_sex_male0.50.50260.00530.9650.365PASS
phi_beta_body_mass0.250.27430.09720.9650.51PASS
phi_beta_sex_male0.30.3020.00670.950.165PASS
phi_beta_winter_severity-0.4-0.4049-0.01240.9550.56PASS
proportion_transient_female0.250.2282-0.08720.96–PASS
proportion_transient_male0.250.248-0.00790.96–PASS
survival_female0.550.5482-0.00330.94–PASS
survival_male0.62260.6212-0.00230.96–PASS

Estimates from the example data

paramestimatelowerupper
survival_F0.54420.43090.6532
survival_M0.61630.5260.6992
detection_F0.40960.28440.5478
detection_M0.56540.47230.654
proportion_transient_F0.2594-0.12040.5281
proportion_transient_M0.31850.11330.4805
phi_beta_tsm_first-0.57-1.3530.2131
phi_beta_sex_M0.2963-0.28080.8734
phi_beta_winter_min_temp_c0.2656-0.09440.6256
phi_beta_mass_g0.1559-0.10470.4165
phi_beta_tsm_first_sex_M-0.2266-1.1780.725
phi_beta_tsm_first_winter_min_temp_c-0.1031-0.49640.2901
phi_beta_tsm_first_mass_g0.1404-0.25330.534
p_beta_sex_M0.6286-0.04191.299

Convergence and goodness of fit

ItemValue
convergencemarked ML: optimiser converged, Hessian invertible, no probability on a boundary (0.28-0.70), max logit SE 0.49; R-hat/ESS not applicable
gof_overallchisq = 41.4; df = 45; p = 0.624; chat = 0.92
test_3SRchisq = 25.8; df = 14; p = 0.027; signed_z = 2.45; note = transience detected; tsm in model
test_3SM_p0.986
test_2CT_p0.801
test_2CL_p0.783
gof_fitted_modelchisq = 15.6; df = 31; p = 0.99; chat = 0.5

Interpretation from the report

Apparent annual survival at average mean January minimum temperature and body mass of residents: Female 0.54 (95% CI 0.43-0.65); Male 0.62 (95% CI 0.53-0.70).
Apparent survival is the probability of surviving AND staying in the study area; animals that emigrate permanently are indistinguishable from deaths, so true survival is at least this high.
Sex: Male vs Female (apparent survival): odds ratio 1.34 (95% CI 0.76-2.40). The interval includes 1: the data do not show a clear difference.
Mean January minimum temperature: each 1 SD (2.04 deg C) increase multiplies the odds of apparent survival by 1.30 (95% CI 0.91-1.87); female survival 0.45 at -6.0 deg C vs 0.61 at -1.0 deg C. The interval includes no effect. This is an association, not proof of a causal effect.
Body mass: each 1 SD (1.66 g) increase multiplies the odds of apparent survival by 1.17 (95% CI 0.90-1.52); female survival 0.49 at 19.8 g vs 0.59 at 23.9 g. The interval includes no effect.
Transients: an estimated 0.26 (95% CI 0.00-0.53) (Female); 0.32 (95% CI 0.11-0.48) (Male) of newly marked animals were transients.
Detection (recapture) probability per occasion: Female 0.41 (95% CI 0.28-0.55); Male 0.57 (95% CI 0.47-0.65).
Goodness of fit: overall c-hat = 0.92 (p = 0.624). Test 3.SR detected transients (p = 0.027): the fitted model accounts for them (tsm). Excluding that component, c-hat = 0.50 (p = 0.990). No evidence of remaining lack of fit.

Figures

Figure: Conditional effects of all continuous covariates on apparent survival (line: estimate; bands: 50% and 95% confidence intervals); other covariates at their means.
survival_effects_panel. Conditional effects of all continuous covariates on apparent survival (line: estimate; bands: 50% and 95% confidence intervals); other covariates at their means.
Figure: Apparent survival versus mean January minimum temperature (°C) (line: maximum-likelihood estimate; dark band: 50%, light band: 95% confidence interval), one curve per Sex; other covariates at their means.
survival_winter_min_temp_c. Apparent survival versus mean January minimum temperature (°C) (line: maximum-likelihood estimate; dark band: 50%, light band: 95% confidence interval), one curve per Sex; other covariates at their means. Rug: observed mean January minimum temperature (°C) values (one per interval).
Figure: Apparent survival versus body mass (g) (line: maximum-likelihood estimate; dark band: 50%, light band: 95% confidence interval), one curve per Sex; other covariates at their means.
survival_mass_g. Apparent survival versus body mass (g) (line: maximum-likelihood estimate; dark band: 50%, light band: 95% confidence interval), one curve per Sex; other covariates at their means. Rug: observed body mass (g) values (one per individual).
Figure: Apparent survival per interval between occasions (points: estimates; thick bar: 50%, thin bar: 95% confidence interval); colours and symbols = Sex…
survival_time. Apparent survival per interval between occasions (points: estimates; thick bar: 50%, thin bar: 95% confidence interval); colours and symbols = Sex; values are predicted from mean January minimum temperature (°C) only (no separate year effect in the model).
Figure: Recapture probability by group (point: estimate; bar: 95% confidence interval).
detection_groups. Recapture probability by group (point: estimate; bar: 95% confidence interval).
Figure: Effects on the odds of apparent survival and of recapture: odds ratio per 1 SD for continuous covariates, versus the reference level for factors (point: estimate; bar: 95% confidence interval; log scale).
coefficients. Effects on the odds of apparent survival and of recapture: odds ratio per 1 SD for continuous covariates, versus the reference level for factors (point: estimate; bar: 95% confidence interval; log scale). Dashed line: no effect. Survival effects are for residents; first-interval (transient) deviations are in the estimates table.
Figure: Goodness-of-fit tests of the time-dependent CJS model (U-CARE components via R2ucare, summed over groups).
gof. Goodness-of-fit tests of the time-dependent CJS model (U-CARE components via R2ucare, summed over groups). Values well above 1 indicate lack of fit: 3.SR = transients, 2.CT = trap dependence. Overall c-hat = 0.92.
Figure: Individuals captured per occasion: newly marked (first capture) and recaptures of previously marked animals.
captures. Individuals captured per occasion: newly marked (first capture) and recaptures of previously marked animals.

Limits that matter at this design

recovery meta

ItemValue
nsim200
converged200/200
coverage_bound0.904
sec_per_fit4
notesimulator covariate is winter_severity (sign flipped vs winter_min_temp_c: -0.4 per SD severity = +0.4 per SD milder)

Commands to reproduce

bin/ejob -c 1 -m 4 -t 0:10:00 -l logs/cjs_make_example.log -- bin/Rscript dev/cjs/make_example.R
bin/ejob -c 4 -m 8 -t 0:30:00 -l logs/cjs_si_selftest.log -- bin/Rscript core/run.R selftest cjs --out dev/cjs/si_selftest
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/cjs_si_recover.log -- bin/Rscript core/run.R recover cjs --config modules/cjs/example/recovery.yaml --nsim 200 --cores 16 --out results/cjs/si/recovery
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/cjs_si_fit.log -- bin/Rscript core/run.R fit cjs --config modules/cjs/example/config.yaml --out results/cjs/si/fit
python3 dev/cjs/make_si_summary.py

Step-by-step walkthrough: modules/cjs/example/WALKTHROUGH.md.

S1.16 multistate: Chytrid (Bd) infection, survival and clearance in a PIT-tagged frog population (multievent capture-recapture, simulated data with known truth)

DONE

Question

Do infected frogs survive less well than uninfected frogs, how often do frogs become infected or clear Bd infection each year, is water temperature associated with infection and clearance, and do larger frogs survive better, when some swabs were lost or inconclusive?

What the researcher typed

I have eight years (2015-2022) of capture data for a PIT-tagged frog population in three files: frog_captures.csv (each capture with the frog's id, year and Bd swab result: uninfected, infected, or U when the swab was lost or inconclusive), frog_individuals.csv (snout-vent length of each frog) and survey_years.csv (mean water temperature and survey effort in person-hours for each year). I want to know whether infected frogs survive less well, how often frogs become infected or clear the infection each year, whether water temperature is related to infection and clearance, and whether bigger frogs survive better. Please analyse this and give me a report with figures I can use in a paper.

Study design

ItemValue
statesuninfected, infected
modelmultievent (Pradel 2005); U = swab lost/inconclusive
n_occasions8
years2015-2022
n_intervals7
n_frogs280
new_frogs_per_year40 in 2015-2021
capture_rows516
records_uninfected258
records_infected144
records_unknown114
frogs_recaptured141
survival_covariatesvl_mm (individual)
transition_covariatewater_temp_C (occasion; 7 values used)
detection_covariatesurvey_hours (occasion)
engineNIMBLE + nimbleEcology dDHMMo, 3 chains x 6000 iterations (2000 burn-in), slice samplers

True values used to simulate the example data

ItemValue
assignment_infected0.85
assignment_uninfected0.75
detection_beta_survey_hours0.4
detection_infected0.5
detection_uninfected0.6
initial_infected0.35
initial_uninfected0.65
stationary_infected0.4615
stationary_uninfected0.5385
survival_beta_svl_mm0.4
survival_infected0.55
survival_uninfected0.75
transition_beta_water_temp_C_infected_to_uninfected0.5
transition_beta_water_temp_C_uninfected_to_infected-0.7
transition_infected_to_uninfected0.35
transition_uninfected_to_infected0.3
seed2024
generatordev/multistate/make_example.R

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
assignment_infected0.850.8358-0.01680.95–PASS
assignment_uninfected0.750.7580.01070.94–PASS
detection_beta_survey_hours0.40.42480.06210.960.86PASS
detection_infected0.50.52110.04210.96–PASS
detection_uninfected0.60.61490.02490.93–PASS
initial_infected0.350.35890.02540.93–PASS
initial_uninfected0.650.6411-0.01370.93–PASS
stationary_infected0.46150.48340.04740.96–PASS
stationary_uninfected0.53850.5166-0.04060.96–PASS
survival_beta_svl_mm0.40.43630.09080.910.97PASS
survival_infected0.550.55060.00110.94–PASS
survival_uninfected0.750.75910.01220.93–PASS
transition_beta_water_temp_C_infected_to_uninfected0.50.54770.09530.970.26PASS
transition_beta_water_temp_C_uninfected_to_infected-0.7-0.67380.03740.940.76PASS
transition_infected_to_uninfected0.350.3469-0.00890.97–PASS
transition_uninfected_to_infected0.30.32140.07150.94–PASS

Estimates from the example data

paramestimateloweruppertruth
survival_uninfected0.83840.74660.95710.75
survival_infected0.49840.37040.6270.55
transition_uninfected_to_infected0.33370.1860.51670.3
transition_infected_to_uninfected0.33850.18210.54120.35
detection_uninfected0.60780.49070.74540.6
detection_infected0.38910.2290.63280.5
assignment_uninfected0.73750.67280.80570.75
assignment_infected0.86460.73440.98280.85
initial_uninfected0.6770.59860.74450.65
initial_infected0.3230.25550.40140.35
stationary_uninfected0.50230.31040.70890.5385
stationary_infected0.49770.29110.68960.4615
survival_beta_svl_mm0.56920.29060.91690.4
transition_beta_water_temp_C_uninfected_to_infected-0.51-0.9361-0.1244-0.7
transition_beta_water_temp_C_infected_to_uninfected0.92170.2061.7410.5
detection_beta_survey_hours0.43440.18730.69610.4

Convergence and goodness of fit

ItemValue
rhat_max1.003
ess_bulk_min788
convergedyes
ppc_p_freeman_tukey0.43
ppc_p_state_switches0.64
ppc_state_switches_observed49
ppc_state_switches_replicated_median53
ppc_p_never_recaptured0.6
ppc_never_recaptured_observed139
ppc_never_recaptured_replicated_median141
ucare_chi224.1
ucare_df52
ucare_p1
recovery_nsim100
recovery_converged100
recovery_gatePASS 16/16
recovery_median_seconds_per_fit328
all_truths_inside_95ciyes

Interpretation from the report

Survival over one year for an animal with average covariate values was 0.84 (95% credible interval 0.75-0.96) in state 'uninfected'; 0.50 (95% credible interval 0.37-0.63) in state 'infected'.
The difference in survival (uninfected minus infected) was 0.34 (95% interval 0.18 to 0.50); posterior probability that survival is higher in 'uninfected' = 1.00.
Transitions are probabilities of being in a new state at the next occasion, for animals that survive the year (at average transition covariates): from 'uninfected' to 'infected' 0.33 (95% credible interval 0.19-0.52); from 'infected' to 'uninfected' 0.34 (95% credible interval 0.18-0.54).
Expected number of years a surviving animal stays in a state before switching (1 / switching probability, median and 95% interval): 'uninfected' 3.1 (1.9-5.4); 'infected' 3.0 (1.8-5.5).
Survival and svl_mm: odds ratio per 1 SD (= 6) 1.77 (95% interval 1.34-2.50); P(effect > 0) = 1.00. Going from the 10th to the 90th percentile of svl_mm (44.5 to 59), predicted survival changes in 'uninfected' from 0.72 to 0.91, in 'infected' from 0.33 to 0.65.
Transitions and water_temp_C (from 14.6 to 19.1, 10th to 90th percentile): 'uninfected' to 'infected': 0.48 at the 10th percentile vs 0.23 at the 90th (difference -0.24, 95% interval -0.41 to -0.06); 'infected' to 'uninfected': 0.16 at the 10th percentile vs 0.56 at the 90th (difference 0.40, 95% interval 0.10 to 0.69). Associations only.
Detection (the chance that a live animal is caught or resighted at an occasion, at average detection covariates) was 0.61 (95% credible interval 0.49-0.75) in 'uninfected'; 0.39 (95% credible interval 0.23-0.63) in 'infected'. Low detection in a state means fewer data on that state, not fewer animals.
State uncertainty (multievent model): when a detected animal was in a given state, the probability that its state was recorded (rather than coded unknown) was 0.74 (95% credible interval 0.67-0.81) in 'uninfected'; 0.86 (95% credible interval 0.73-0.98) in 'infected'.
Goodness of fit: posterior predictive checks showed no clear misfit (Bayesian p = 0.43 sightings per occasion, 0.64 state switches, 0.60 animals never seen again).

Figures

Figure: Probability of switching state over one year (for survivors) against Mean water temperature (°C), one curve per transition; dark band = 50% and light band = 95% credible intervals.
transition_water_temp_C. Probability of switching state over one year (for survivors) against Mean water temperature (°C), one curve per transition; dark band = 50% and light band = 95% credible intervals. Rug = observed values.
Figure: State-specific survival (per year), detection, probability that a detected animal's state was recorded, and the state distribution at first capture, with posterior means and 95% credible intervals (at average covariate values).
vital_rates_by_state. State-specific survival (per year), detection, probability that a detected animal's state was recorded, and the state distribution at first capture, with posterior means and 95% credible intervals (at average covariate values).
Figure: Transition probabilities between states over one year for animals that survive it: posterior mean (95% credible interval).
transitions. Transition probabilities between states over one year for animals that survive it: posterior mean (95% credible interval). Rows sum to 1; off-diagonal cells are movement/switching, diagonal cells are staying. Evaluated at average transition covariates.
Figure: Estimated transition probabilities (points) with 95% credible intervals.
transition_estimates. Estimated transition probabilities (points) with 95% credible intervals.
Figure: Stationary state distribution implied by the transition matrix (posterior mean, 95% credible interval): the share of time a surviving animal would spend in each state if current transition probabilities persisted.
stationary. Stationary state distribution implied by the transition matrix (posterior mean, 95% credible interval): the share of time a surviving animal would spend in each state if current transition probabilities persisted. It ignores state differences in survival and recruitment.
Figure: Survival per year against Snout-vent length (mm), one curve per state (other covariates at their mean); dark band = 50% and light band = 95% credible intervals.
survival_svl_mm. Survival per year against Snout-vent length (mm), one curve per state (other covariates at their mean); dark band = 50% and light band = 95% credible intervals. Rug = values of the marked animals.
Figure: Detection probability against Survey effort (person-hours), one curve per state; dark band = 50% and light band = 95% credible intervals.
detection_survey_hours. Detection probability against Survey effort (person-hours), one curve per state; dark band = 50% and light band = 95% credible intervals. Rug = observed values.
Figure: Detection probability at each recapture occasion and state (posterior mean, 95% credible interval), driven by the occasion covariates.
detection_by_occasion. Detection probability at each recapture occasion and state (posterior mean, 95% credible interval), driven by the occasion covariates.
Figure: Covariate effects as odds ratios per 1 SD of the covariate (transitions: odds of moving relative to staying), log scale.
coefficients. Covariate effects as odds ratios per 1 SD of the covariate (transitions: odds of moving relative to staying), log scale. Dashed line = no effect.
Figure: Number of animals caught or resighted at each occasion, by recorded state (raw data).
captures_by_occasion. Number of animals caught or resighted at each occasion, by recorded state (raw data).
Figure: Posterior predictive checks (300 draws).
gof. Posterior predictive checks (300 draws). Histograms: replicated statistic; line: observed. A: Freeman-Tukey discrepancy of sightings per occasion and event, replicated minus observed (line at 0; p = 0.43). B: state switches between consecutive known-state sightings (p = 0.64). C: animals never seen after first capture (p = 0.60). p near 0 or 1 indicates misfit.
Figure: MCMC traces of survival and transition probabilities, one colour per chain (after burn-in).
trace. MCMC traces of survival and transition probabilities, one colour per chain (after burn-in). Chains should overlap like a 'hairy caterpillar'.
Figure: Posterior densities of all reported quantities.
posterior. Posterior densities of all reported quantities.

Limits that matter at this design

Commands to reproduce

bin/ejob -c 1 -m 4 -- bin/Rscript dev/multistate/make_example.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/multistate_si_recover.log -- bin/Rscript core/run.R recover multistate --config modules/multistate/example/recovery.yaml --nsim 100 --cores 16 --out results/multistate/si/recovery
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/multistate_si_fit.log -- bin/Rscript core/run.R fit multistate --config modules/multistate/example/config.yaml --out results/multistate/si/fit
bin/ejob -c 1 -m 8 -t 0:30:00 -- bin/Rscript core/run.R figures multistate --fit results/multistate/si/fit/multistate_fit.rds --config modules/multistate/example/config.yaml --out results/multistate/si/fit

Step-by-step walkthrough: modules/multistate/example/WALKTHROUGH.md.

S1.17 jolly-seber: Western pond turtle abundance, recruitment and survival from eight years of PIT-tag hoop-trapping (Jolly-Seber, simulated data with known truth)

DONE Every interpreted estimand passes planted truth at this design (42/45 overall; N_t rel. bias -2.5% to +2.8%, coverage 0.925-0.965; survival -0.6% / +0.1%, coverage 0.955 / 0.95); fit converged (R-hat 1.001, min ESS 2583); PPC p 0.52 / 0.62 and all R2ucare p > 0.5; module cross-checked against marked and latent Nimble, negative controls in VALIDATION.md. First-interval recruitment (entrants_2, entry_prob_2, recruitment_rate_1) fails the bias criterion and is excluded from interpretation.

Question

How many western pond turtles used the pond complex each year and over the whole study, how many new turtles joined each year, what share survive from year to year (and do males survive less well than females), and is the population declining?

What the researcher typed

I have eight summers (2015 to 2022) of hoop-trapping data for western pond turtles at one pond complex, in two files: turtle_captures.csv (every capture, with the turtle's ID, the season and its sex; U means we could not sex it) and turtle_seasons.csv (trap-nights of effort in each season). I want to know how many turtles were there each year and in total, how many new turtles joined each year, what share survive from year to year and whether males survive less well than females, and whether the population is declining. Please analyse this and give me a report with figures I can use in a paper.

Study design

ItemValue
n_occasions8
years2015-2022
interval_years1
n_turtles175
n_female100
n_male65
n_unknown_sex10
capture_rows459
turtle_seasons322
caught_per_season34, 23, 47, 55, 38, 44, 46, 35
new_per_season34, 17, 35, 27, 16, 15, 16, 15
turtles_caught_once88
trap_nights80-163 (mean 120)
occasion_covariatetrap_nights (capture probability)
groupsex (female reference; U = mixture)
enginenimble marginal (forward algorithm), 3 chains x 20000 iter, burn-in 5000, thin 5; marked ML POPAN as cross-check
M875

True values used to simulate the example data

ItemValue
superpopulation_size260
entry_prob_10.45
entry_prob_2_to_80.0786
survival_female0.82
survival_beta_male-0.4
survival_male0.7533
prop_male0.45
detection0.4
detection_beta_effort0.45
prop_sex_unknown0.06
abundance2015 = 97; 2016 = 100; 2017 = 101; 2018 = 109; 2019 = 102; 2020 = 107; 2021 = 105; 2022 = 107
entrants2016 = 23; 2017 = 16; 2018 = 31; 2019 = 17; 2020 = 28; 2021 = 21; 2022 = 27
growth_rate_mean1.014
seedjs_simulate seed 2024; set.seed(11) for field details
generatordev/jolly-seber/make_example.R

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
abundance_1117.8114.8-0.02510.945–PASS
abundance_2113.8116.30.02260.935–PASS
abundance_3109.9112.20.02140.96–PASS
abundance_4106.7108.70.01950.965–PASS
abundance_5104.9107.60.02610.94–PASS
abundance_6104.2105.70.01460.96–PASS
abundance_7102.6105.30.02780.94–PASS
abundance_8101.9104.30.02620.925–PASS
detection0.40.40090.00240.925–PASS
detection_beta_effort0.450.45810.01810.9750.99PASS
entrants_220.825.570.26230.975–FAIL
entrants_320.220.10.01660.975–PASS
entrants_419.6419.810.01130.985–PASS
entrants_520.4321.480.06090.975–PASS
entrants_620.4719.86-0.01550.955–PASS
entrants_720.1121.170.06710.95–PASS
entrants_820.5120.220.00810.98–PASS
entry_prob_10.450.4268-0.05150.955–PASS
entry_prob_20.07860.09870.25590.975–FAIL
entry_prob_30.07860.0781-0.00620.995–PASS
entry_prob_40.07860.0772-0.01760.98–PASS
entry_prob_50.07860.08310.05780.98–PASS
entry_prob_60.07860.0771-0.01920.965–PASS
entry_prob_70.07860.08170.03930.97–PASS
entry_prob_80.07860.0774-0.01520.97–PASS
growth_rate_10.9681.0420.07860.965–PASS
growth_rate_20.96660.97570.0110.985–PASS
growth_rate_30.97210.9790.0080.995–PASS
growth_rate_40.98550.99930.01520.98–PASS
growth_rate_50.99550.9921-0.0020.96–PASS
growth_rate_60.98611.0050.02120.965–PASS
growth_rate_70.99520.99810.00550.94–PASS
growth_rate_mean0.97950.98770.00850.925–PASS
prop_male0.45120.4495-0.00320.985–PASS
recruitment_rate_10.17830.25270.46670.97–FAIL
recruitment_rate_20.17880.18570.06830.975–PASS
recruitment_rate_30.18030.18840.04760.98–PASS
recruitment_rate_40.19350.20850.08940.985–PASS
recruitment_rate_50.19680.19710.01190.95–PASS
recruitment_rate_60.19480.21140.1050.95–PASS
recruitment_rate_70.2020.20310.03220.965–PASS
superpopulation_size2602630.01150.92–PASS
survival0.820.8153-0.00580.955–PASS
survival_beta_male-0.4-0.36630.08430.9750.265PASS
survival_male0.75330.75410.00110.95–PASS

Estimates from the example data

paramestimatelowerupper
superpopulation_size268.3236310
abundance_1108.376148
abundance_2100.770138
abundance_3113.792140
abundance_4110.492134
abundance_5111.793135
abundance_698.5781120
abundance_7104.585129.5
abundance_8112.287145
entrants_216.05046
entrants_334.744.47567
entrants_420.66242
entrants_523.83445
entrants_611.27029
entrants_724.65843
entrants_828.82657
entry_prob_10.39510.28410.5229
entry_prob_20.06150.00240.1709
entry_prob_30.1310.01680.263
entry_prob_40.0790.00920.1699
entry_prob_50.08950.01590.1771
entry_prob_60.04440.00230.1151
entry_prob_70.09270.02850.1698
entry_prob_80.10670.02420.2028
recruitment_rate_10.156800.4831
recruitment_rate_20.37580.03460.8618
recruitment_rate_30.18910.01590.4184
recruitment_rate_40.22230.02920.4486
recruitment_rate_50.104600.2814
recruitment_rate_60.25480.07480.4633
recruitment_rate_70.28270.05480.5773
growth_rate_10.93830.74791.263
growth_rate_21.1590.82131.653
growth_rate_30.97810.80491.209
growth_rate_41.0180.81821.245
growth_rate_50.88540.751.069
growth_rate_61.0650.87951.286
growth_rate_71.0790.84541.379
growth_rate_mean1.0060.95991.055
survival0.84540.78310.9021
survival_beta_male-0.9305-1.539-0.3382
prop_male0.43180.37770.4878
survival_male0.6850.58360.7823
detection0.37410.3090.4438
detection_beta_trap_nights0.37570.14230.6126

Convergence and goodness of fit

ItemValue
convergencemax_rhat = 1.001; min_bulk_ess = 2583; chains = 3; iterations = 20000; burnin = 5000; thin = 5
data_augmentationM = 875; q995_superpopulation = 328; limiting = no
ppccaptures_per_animal_p = 0.52; caught_per_occasion_p = 0.62; draws = 300
r2ucarefemale = test3SR_p = 0.665; test2CT_p = 0.853; overall_p = 0.878; male = test3SR_p = 0.903; test2CT_p = 0.729; overall_p = 0.97; unknown = test3SR_p = 0.626; test2CT_p = 1; overall_p = 0.526
cross_check_markedsuperpopulation_size = 263.6; abundance_2015 = 114.2; abundance_2018 = 108.3; abundance_2022 = 111.2; detection = 0.375; detection_beta_trap_nights = 0.388; survival_pooled = 0.794; note = marked drops the sex effect (10 unknown-sex turtles); survival pooled

Interpretation from the report

175 western pond turtles were caught at least once over 8 occasions (2015 to 2022); 87 (50%) were caught on more than one occasion, and 40.2 were caught per occasion on average.
Estimated abundance was 108 (95% CI 76 to 148) at the first occasion (2015) and 112 (95% CI 87 to 145) at the last (2022). Across the study the average growth rate was 1.006 (95% CI 0.960 to 1.055) per year, i.e. a change of +0.6% per year; the posterior probability that the population declined (growth rate < 1) is 0.39.
In total 268 (95% CI 236 to 310) western pond turtles are estimated to have used the study population at some time during the study (the superpopulation), of which 175 (65%) were ever caught.
Apparent survival per year was 0.85 (95% CI 0.78 to 0.90) for female and 0.68 (95% CI 0.58 to 0.78) for male. The odds of surviving were 0.39 times as high for male as for female (95% CI 0.21 to 0.71); posterior probability that male animals survive less well than female animals > 0.99.
'Apparent' survival means that death and permanent emigration cannot be told apart.
Capture probability of an animal present was 0.37 (95% CI 0.31 to 0.44) at average sampling effort. Capture probability rose from 0.29 to 0.47 between trapping effort (trap-nights) = 90 and 150 (one SD below to one SD above the mean; odds ratio per SD 1.46, 95% CI 1.15 to 1.85). This is a sampling (detection) effect, not a change in the population.
Agent caveat: the report's average per-capita recruitment (0.23, 95% CI 0.16-0.30) includes the 2015-2016 interval, which failed planted truth; read recruitment from 2016-17 onward (11-35 entrants per year).

Figures

Figure: Estimated abundance at each occasion (line and points: posterior mean; band: 95% credible interval (inner band 50%)).
abundance_trajectory. Estimated abundance at each occasion (line and points: posterior mean; band: 95% credible interval (inner band 50%)). Black points: number of turtles actually caught at each occasion (a minimum count).
Figure: Posterior distribution of the superpopulation size; dashed line = number of animals caught (175).
superpopulation. Posterior distribution of the superpopulation size; dashed line = number of animals caught (175). Data-augmentation limit M = 875; 99.5% posterior quantile 328, so M does not constrain the estimate.
Figure: Apparent survival per year by sex (points: posterior means; bars: 95% credible intervals, thick 50%).
survival_sex. Apparent survival per year by sex (points: posterior means; bars: 95% credible intervals, thick 50%).
Figure: Effects on the odds of apparent survival (survival_beta_*: male level vs reference) and of capture (detection_beta_*: per 1 SD of the covariate).
coefficients. Effects on the odds of apparent survival (survival_beta_*: male level vs reference) and of capture (detection_beta_*: per 1 SD of the covariate). Dashed line: no effect.
Figure: (A) Number of animals entering the population (births plus immigrants) that were first present at each occasion; (B) per-capita recruitment, entrants at t+1 divided by abundance at t, plotted at the midpoint of each interval.
recruitment. (A) Number of animals entering the population (births plus immigrants) that were first present at each occasion; (B) per-capita recruitment, entrants at t+1 divided by abundance at t, plotted at the midpoint of each interval. Points: posterior means; bars: 95% credible interval (thick bars 50%). The 2016 entrants and 2015-16 per-capita recruitment failed planted truth at this design (bias +26% and +47%) and are not interpreted.
Figure: Entry probabilities b_t: the share of all animals that ever used the population (the superpopulation) that entered at each occasion; the first value is the share already present at the start.
entry_probabilities. Entry probabilities b_t: the share of all animals that ever used the population (the superpopulation) that entered at each occasion; the first value is the share already present at the start. Bars: 95% credible intervals.
Figure: Realised population growth rate between consecutive occasions (points, 95% credible intervals); dashed line = no change (1).
growth_rate. Realised population growth rate between consecutive occasions (points, 95% credible intervals); dashed line = no change (1). Green line and shading: mean growth rate per year over the whole study with its 95% interval.
Figure: Capture probability of an animal present at each occasion (95% credible intervals), as predicted from trapping effort (trap-nights).
detection_time. Capture probability of an animal present at each occasion (95% credible intervals), as predicted from trapping effort (trap-nights).
Figure: Capture probability against trapping effort (trap-nights) (line: posterior mean; bands: 95% and 50% credible intervals).
detection_trap_nights. Capture probability against trapping effort (trap-nights) (line: posterior mean; bands: 95% and 50% credible intervals). Points: animals caught / estimated abundance at each occasion (a rough empirical check), plotted at that occasion's trapping effort (trap-nights).
Figure: Posterior predictive checks (Freeman-Tukey discrepancies, 300 posterior draws).
gof. Posterior predictive checks (Freeman-Tukey discrepancies, 300 posterior draws). Each histogram shows replicated minus observed discrepancy; the line at 0 should lie well inside the histogram (Bayesian p-values 0.52 and 0.62; extreme if < 0.025 or > 0.975). R2ucare tests: 3.SR (transients) [unknown sex] p = 0.63; 2.CT (trap dependence) [unknown sex] p = 1.00; overall CJS [unknown sex] p = 0.53; 3.SR (transients) [female] p = 0.67; 2.CT (trap dependence) [female] p = 0.85; overall CJS [female] p = 0.88; 3.SR (transients) [male] p = 0.90; 2.CT (trap dependence) [male] p = 0.73; overall CJS [male] p = 0.97.
Figure: MCMC traces of key quantities (thinned), one colour per chain; chains should overlap.
trace. MCMC traces of key quantities (thinned), one colour per chain; chains should overlap.
Figure: Posterior densities of key quantities (N = abundance; survival per time unit; effects on the logit scale).
posterior. Posterior densities of key quantities (N = abundance; survival per time unit; effects on the logit scale).
Figure: Estimates of the same quantities from each engine fitted to the same data. marked gives expected (not realised) abundance; its intervals come from simulating the coefficients' asymptotic normal distribution and are clipped to the…
engine_comparison. Estimates of the same quantities from each engine fitted to the same data. marked gives expected (not realised) abundance; its intervals come from simulating the coefficients' asymptotic normal distribution and are clipped to the panel when an entry probability lies on its boundary. Animals of unknown group were present, so the marked fit has no group effect and its survival is pooled over groups. The panel titled "Survival per year (female)" shows the Nimble female estimate; the marked value in it is pooled over sexes.

Limits that matter at this design

recovery meta

ItemValue
nsim200
converged200/200
max_rhat_any_rep1.016
coverage_bound0.904
sec_per_fit11
gate42/45 pass
seed1
configmodules/jolly-seber/example/recovery.yaml
settingsmodule fast_settings (3 chains, 6000 iter, 2000 burn-in, thin 2)
failuresentrants_2 (+26%), entry_prob_2 (+26%), recruitment_rate_1 (+47%): first-interval recruitment (VALIDATION Known limit 3); coverage 0.97-0.975, so intervals are honest but means are biased high; not interpreted

Commands to reproduce

bin/ejob -c 1 -m 4 -t 0:10:00 -- bin/Rscript dev/jolly-seber/make_example.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/jolly-seber_si_recover.log -- bin/Rscript core/run.R recover jolly-seber --config modules/jolly-seber/example/recovery.yaml --nsim 200 --cores 16 --out results/jolly-seber/si/recovery
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/jolly-seber_si_fit.log -- bin/Rscript core/run.R fit jolly-seber --config modules/jolly-seber/example/config.yaml --out results/jolly-seber/si/fit
bin/Rscript core/run.R figures jolly-seber --fit results/jolly-seber/si/fit/jolly-seber_fit.rds --config modules/jolly-seber/example/config.yaml
python3 dev/jolly-seber/make_si_summary.py

Step-by-step walkthrough: modules/jolly-seber/example/WALKTHROUGH.md.

S1.18 ipm: Red-backed shrike population dynamics from counts, ringing and nest monitoring (integrated population model, simulated data with known truth)

DONE

Question

How did the number of breeding female red-backed shrikes on a study plot change over 15 years, which vital rates (first-year survival, adult survival, fecundity, immigration) drove the changes, how many breeders are immigrants, and is first-year survival associated with Sahel rainfall?

What the researcher typed

I have 15 years (2006-2020) of data on red-backed shrikes from my study plot, in four files: shrike_counts.csv (breeding females counted each June; no count in 2013), shrike_captures.csv (every ringed bird each year it was caught, ringed as a nestling or as a breeding female), shrike_broods.csv (fledglings from each monitored nest, with the mother's age, yearling or older) and sahel_rainfall.csv (July-September rainfall in the Sahel each year). I want to know how the number of breeding females changed, which vital rates drove the ups and downs, how many breeders are immigrants, and whether first-year survival is higher after wet years in the Sahel. I only have data on females. Please analyse this and give me a report with figures I can use in a paper.

Study design

ItemValue
n_years15
years2006-2020
n_intervals14
counts14 of 15 years (no survey 2013); 99-209 females
nestlings_ringed50 per year 2006-2019 (700)
adults_ringed20 per year 2006-2019 (280)
rings980
capture_rows1309
rings_recaptured229
nestlings_recaptured127
nests_monitored1020
nests_yearling_mothers549
nests_older_mothers471
failed_nests47
prop_broods_monitored0.5
covariatesahel_rain_mm on juvenile survival (mean 420, SD 90 mm)
count_modelpoisson
enginenimble; 3 chains x 150,000 iterations, 30,000 burn-in, thin 30

True values used to simulate the example data

ItemValue
juvenile_survival0.25
adult_survival0.48
fecundity_yearling2.8
fecundity_adult3.6
recapture_prob0.6
juvenile_survival_beta_sahel_rain_mm0.4
immigration_rate0.1269
immigration_rate_median0.12
juvenile_survival_sd0.3
adult_survival_sd0.2
fecundity_yearling_sd0.15
fecundity_adult_sd0.15
immigration_sd0.3
N_first86
N_final136
N_mean137.3
lambda_geomean1.033
immigrants_mean17.5
ltre_juvenile_survival0.01914
ltre_immigration3.274e-05
var_lambda_explained0.02584
seed2024
generatordev/ipm/make_example.R

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
adult_survival0.480.48260.00550.9688–PASS
adult_survival_sd0.20.2330.16510.9688–FAIL
fecundity_adult3.63.6220.00620.9479–PASS
fecundity_adult_sd0.150.15410.02750.9583–PASS
fecundity_yearling2.82.795-0.0020.9062–PASS
fecundity_yearling_sd0.150.16120.07470.9375–PASS
immigrants_mean13.312.36-0.09650.9792–PASS
immigration_rate0.12710.118-0.07050.9583–PASS
immigration_rate_median0.120.103-0.14190.9688–FAIL
immigration_sd0.30.75081.5031–FAIL
juvenile_survival0.250.25410.01650.9792–PASS
juvenile_survival_beta_sahel_rain_mm0.40.3979-0.00520.97920.875PASS
juvenile_survival_sd0.30.30680.02250.9688–PASS
lambda_geomean1.0081.007-0.00120.9688–PASS
ltre_adult_survival0.0024960.0031265.3060.9792–PASS
ltre_fecundity_adult0.0010320.000920.68070.9896–PASS
ltre_fecundity_yearling0.0007060.0009520.66150.9688–PASS
ltre_immigration0.0015920.0073169.2710.9375–FAIL
ltre_juvenile_survival0.021260.023120.1270.9479–PASS
ltre_population_structure6.3e-050.0002641.6770.9792–FAIL
N_final112.6114.10.01330.9792–PASS
N_first89.8492.610.03250.9792–PASS
N_mean105.2105.3-0.00050.9375–PASS
recapture_prob0.60.5963-0.00620.9375–PASS
var_lambda_explained0.027150.035690.39050.9479–FAIL

Estimates from the example data

paramestimateloweruppertruth
juvenile_survival0.22470.1840.26850.25
adult_survival0.44810.3940.50170.48
fecundity_yearling2.892.6263.1692.8
fecundity_adult3.6613.3234.033.6
recapture_prob0.65440.58490.72160.6
juvenile_survival_sd0.14620.009780.41810.3
adult_survival_sd0.2170.016770.52890.2
fecundity_yearling_sd0.14460.068230.2520.15
fecundity_adult_sd0.15590.081910.26320.15
juvenile_survival_beta_sahel_rain_mm0.30480.022320.58550.4
immigration_rate0.20420.11520.29560.1269
immigration_rate_median0.14660.032360.31040.12
immigration_sd1.290.36062.6950.3
N_first107.89112786
N_final135.4116157136
N_mean136.4128.9144.8137.3
lambda_geomean1.01611.0331.033
immigrants_mean26.7715.7938.0717.5
ltre_juvenile_survival0.00750.000290.018680.01914
ltre_adult_survival0.00145-0.004430.00954–
ltre_immigration0.042240.003160.13183.274e-05
ltre_fecundity_yearling0.00073-0.002310.00441–
ltre_fecundity_adult0.00085-0.001550.00423–
ltre_population_structure0.00014-0.000670.00131–
var_lambda_explained0.052910.014070.14650.02584
N_total[2006]107.891127–
N_total[2007]111.794130–
N_total[2008]127.8108150–
N_total[2009]132.5115152–
N_total[2010]11195128–
N_total[2011]113.698130–
N_total[2012]121.9103143–
N_total[2013]166.4104251–
N_total[2014]186.5161214–
N_total[2015]198.9173226–
N_total[2016]159140179–
N_total[2017]123.1106141–
N_total[2018]107.390127–
N_total[2019]143.6123166–
N_total[2020]135.4116157–

Convergence and goodness of fit

ItemValue
rhat_max1.004
ess_bulk_min630
chains3
ppc_bayesian_pcounts = 0.56; productivity = 0.46; capture_recapture = 0.37
ppc_draws600
ipm_vs_separate_sd_changejuvenile_survival = -0.07; adult_survival = -0.22; fecundity_yearling = 0; fecundity_adult = -0.01; recapture_prob = -0.02

Interpretation from the report

The model estimates 108 (95% CrI 91-127) breeding females in 2006 and 135 (95% CrI 116-157) in 2020 (counts were 106 and 135). Over the 15 years the population changed on average by a factor of 1.016 (95% CrI 1.000-1.033) per year.
Apparent survival from one breeding season to the next (at average conditions) was 0.22 (95% CrI 0.18-0.27) for first-year birds and 0.45 (95% CrI 0.39-0.50) for adults. 'Apparent' means that animals which emigrate permanently are counted as dead.
Females breeding for the first time (yearlings, and immigrants) raised 2.89 (95% CrI 2.63-3.17) fledglings per year; older females raised 3.66 (95% CrI 3.32-4.03).
The estimated immigration rate, averaged over the study years, is 0.20 (95% CrI 0.12-0.30) new female breeders per female already present, i.e. on average 26.8 (95% CrI 15.8-38.1) immigrant breeding females per year, making up 17% (95% CrI 10-25%) of the breeders each year.
With the estimated survival and fecundity but no immigrants, the population would change by a factor of 0.81 per year (95% CrI 0.72-0.90): the local population behaves as a sink that is maintained by immigration.
Sahel rainfall (mm, Jul-Sep) was associated with juvenile survival: odds ratio 1.36 (95% CrI 1.02-1.80) per 1 SD (90 mm); P(effect > 0) = 0.98. Across the observed range (307 to 522 mm) expected juvenile survival goes from about 0.17 to 0.29. This is an association across 14 years, not proof of cause.
The immigration contribution in the LTRE (0.0422, 95% CrI 0.0032-0.1318) and therefore the total explained variance are NOT reliable; treat it as an upper bound. Among the rates with direct data, the largest contribution came from juvenile survival (0.0075, 95% CrI 0.0003-0.0187).
Compared with separate analyses of the capture-recapture and productivity data, the IPM reduced the posterior SD of juvenile survival by 7% and adult survival by 22%; fecundity and recapture were essentially unchanged.

Figures

Figure: Composition of the breeding population each year (posterior means): females recruited locally (born in the study area the year before), surviving adults and immigrants.
population_composition. Composition of the breeding population each year (posterior means): females recruited locally (born in the study area the year before), surviving adults and immigrants.
Figure: Estimated number of breeding females per year (line: posterior mean; bands: 95% and 50% credible intervals) with the observed counts (points).
population_trajectory. Estimated number of breeding females per year (line: posterior mean; bands: 95% and 50% credible intervals) with the observed counts (points).
Figure: Realised annual population growth rate between successive breeding seasons (points: posterior means plotted between the two years; thick and thin lines: 50% and 95% credible intervals); dashed line = no change.
growth_rate. Realised annual population growth rate between successive breeding seasons (points: posterior means plotted between the two years; thick and thin lines: 50% and 95% credible intervals); dashed line = no change.
Figure: Annual vital rates (posterior means with 50% [thick] and 95% [thin] credible intervals); dashed lines = mean rate.
vital_rates. Annual vital rates (posterior means with 50% [thick] and 95% [thin] credible intervals); dashed lines = mean rate. Survival and immigration refer to the interval from one breeding season to the next and are plotted between the two years. Fecundity: fledglings (both sexes) per breeding female, yearlings vs older adults.
Figure: Life-table response experiment: contribution of each vital rate and of population structure to the temporal variance of the population growth rate (bars: posterior means; thick and thin lines: 50% and 95% credible intervals).
ltre. Life-table response experiment: contribution of each vital rate and of population structure to the temporal variance of the population growth rate (bars: posterior means; thick and thin lines: 50% and 95% credible intervals). Read the ranking rather than the sizes: posterior means of contributions are biased upward, and the immigration contribution is overestimated, often severalfold, because immigration has no direct data (Paquet et al. 2021; VALIDATION.md).
Figure: Transient LTRE: contributions of each vital rate and of population structure to the change in population growth rate from one year to the next (bars, posterior means); white points = estimated change in growth rate.
transient_ltre. Transient LTRE: contributions of each vital rate and of population structure to the change in population growth rate from one year to the next (bars, posterior means); white points = estimated change in growth rate.
Figure: Precision of the integrated population model versus separate analyses of the capture-recapture and productivity data (same priors and year effects).
ipm_vs_separate. Precision of the integrated population model versus separate analyses of the capture-recapture and productivity data (same priors and year effects). Lines: 95% credible intervals; labels: coefficient of variation (posterior SD / mean).
Figure: Expected juvenile survival in relation to Sahel rainfall (mm, Jul-Sep) (line: posterior mean; bands: 95% and 50% credible intervals; year random effects at zero).
effect_sahel_rain_mm. Expected juvenile survival in relation to Sahel rainfall (mm, Jul-Sep) (line: posterior mean; bands: 95% and 50% credible intervals; year random effects at zero). Points: annual estimates from the IPM.
Figure: Posterior predictive checks (Schaub & Kery 2022, ch. 11): Freeman-Tukey discrepancy of the observed vs replicated data for each data set, one point per posterior draw.
gof. Posterior predictive checks (Schaub & Kery 2022, ch. 11): Freeman-Tukey discrepancy of the observed vs replicated data for each data set, one point per posterior draw. P = Bayesian p-value (share of points above the 1:1 line); values near 0 or 1 indicate lack of fit.
Figure: MCMC traces (thinned draws, one colour per chain) of the main estimands; chains should overlap without trends.
trace. MCMC traces (thinned draws, one colour per chain) of the main estimands; chains should overlap without trends.
Figure: Posterior densities of the main estimands.
posterior. Posterior densities of the main estimands.

Limits that matter at this design

recovery meta

ItemValue
nsim100
converged96/100
errors0
coverage_bound0.883
median_sec_per_fit408
settingsfast_settings: 3 chains x 35,000 iterations, 5,000 burn-in, thin 6
ltre_top_correct90/96
ltre_top_correct_excl_immigration96/96
interpreted_estimands_all_passyes
failing_not_interpretedadult_survival_sd, immigration_rate_median, immigration_sd, ltre_immigration, ltre_population_structure, var_lambda_explained
notereplicates have all 15 counts; the example file lacks the 2013 count

Commands to reproduce

bin/ejob -c 1 -m 4 -t 0:10:00 -l logs/ipm_make_example.log -- bin/Rscript dev/ipm/make_example.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/ipm_si_recover.log -- bin/Rscript core/run.R recover ipm --config modules/ipm/example/recovery.yaml --nsim 100 --cores 16 --out results/ipm/si/recovery
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/ipm_si_fit.log -- bin/Rscript core/run.R fit ipm --config modules/ipm/example/config.yaml --out results/ipm/si/fit
bin/ejob -c 1 -m 8 -t 0:20:00 -l logs/ipm_si_figures.log -- bin/Rscript core/run.R figures ipm --config modules/ipm/example/config.yaml --out results/ipm/si/fit
python3 dev/ipm/make_si_summary.py

Step-by-step walkthrough: modules/ipm/example/WALKTHROUGH.md.

S1.19 timeseries: Is a mule deer herd declining, and do deep-snow winters reduce its growth? (Bayesian state-space model, simulated data)

OPEN Estimand-specific. Trend, N_final, equilibrium_N and the snow effect pass planted truth (bias <= 4.2%, coverage 0.94-0.97), convergence (R-hat <= 1.006, ESS >= 684) and the PPC, and can be reported. Density dependence b (-59% bias), process SD (+23%) and observation SD (-13%) fail planted truth at this design, so the researcher's density-dependence question is not answered.

Question

Is the herd declining and by how much per year, how many deer are really there once counting error is removed, is growth density dependent, and do deep-snow winters reduce herd growth?

What the researcher typed

I've attached herd_counts.csv: aerial winter counts of our mule deer herd, 1994-2024, with mean winter snow depth from the snow course. Three winters weren't flown. Please tell me whether the herd is declining and by how much per year, how many deer there really are, whether growth is density dependent, and whether deep-snow winters reduce herd growth. I don't code, so please give me a report with figures I can use in a paper.

Study design

ItemValue
n_populations1
n_years31
first_year1994
last_year2024
years_counted28
years_not_flown3
missing_years2001, 2009, 2016
n_covariates1
covariatesnow_depth_cm
modelbayes (Gompertz density dependence + covariate on growth)
data_seed20

True values used to simulate the example data

ItemValue
density_dependence_b-0.3
equilibrium_N500
sd_process0.1
sd_observation0.15
growth_beta_snow_depth_cm-0.15
growth_effect_pct_snow_depth_cm-13.93
N_final643.3
realised_trend_pct_per_year0.0978

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
growth_beta_snow_depth_cm-0.15-0.1563-0.04220.9680.968PASS
growth_effect_pct_snow_depth_cm-13.93-14.42-0.03510.9680.968PASS
N_final517.3526.90.01630.957–PASS
equilibrium_N500503.80.00750.957–PASS
realised_trend_pct_per_year0.11770.1215-1.5590.935–PASS
density_dependence_b-0.3-0.4759-0.58640.892–FAIL
sd_process0.10.12310.23060.978–FAIL
sd_observation0.150.1299-0.13370.989–FAIL

Estimates from the example data

paramestimateloweruppertruth
density_dependence_b-0.5911-1.11-0.2892-0.3
equilibrium_N535.6477.8599.4500
sd_process0.09660.00370.26480.1
sd_observation0.18380.03320.27830.15
N_final614.2499.5768643.3
realised_trend_pct_per_year0.0703-1.4451.3110.0978
growth_beta_snow_depth_cm-0.1655-0.2506-0.0729-0.15
growth_effect_pct_snow_depth_cm-15.25-22.17-7.027-13.93

Convergence and goodness of fit

ItemValue
max_rhat1.006
min_ess_bulk684
convergedyes
mcmc4 chains x 40,000 iterations, 10,000 burn-in, thin 10
ppc_p_sd_change0.61
ppc_p_acf1_change0.75
gompertz_bootstrap_lrt_p0.585
gompertz_bootstrap_B199

Interpretation from the report

The estimated true population changed by +0.1% per year on average between 1994 and 2024 (95% credible interval -1.4% to +1.3%).
Estimated true abundance (on the scale of the animals counted) in 2024: 614 (95% credible interval 499 to 768). If counts miss a constant fraction of animals this is an index of abundance, not a census.
Equilibrium abundance (where growth averages zero, at average covariates): 536 (95% credible interval 478 to 599).
An increase of one standard deviation (20) in Mean winter snow depth (cm) is associated with a -15.3% change in the annual growth multiplier (95% credible interval -22.2% to -7.0%; P(effect > 0) = 0.00). At average abundance the population is expected to change by +19.9% in a year with snow depth at its 10th percentile (30.9 cm) vs -16.4% at its 90th percentile (74.5 cm). This is an association, not proof that snow depth causes the change.
Counting error (observation SD 0.18, 95% CI 0.03-0.28) is estimated to be larger than real year-to-year variation (process SD 0.10, 0.00-0.26), so single year-to-year changes in raw counts should not be read as real population changes.
Because the prior allows only b between -2 and 0, the credible interval for b can never include 0, so it is not evidence that density dependence exists; b from a single count series is overestimated (here -0.59 vs true -0.30).
Posterior predictive check: the variability (Bayesian p = 0.61) and lag-1 autocorrelation (p = 0.75) of year-to-year changes match the observed counts, so there is no sign of misfit.
Formal test for density dependence (Gompertz parametric-bootstrap likelihood ratio, 199 simulated series): p = 0.585; the counts are consistent with density-independent growth, but this test has little power.

Figures

Figure: Estimated true abundance (line, smoothed latent state) with 95% credible band (inner band 50%).
trajectory. Estimated true abundance (line, smoothed latent state) with 95% credible band (inner band 50%). Points are the observed animals counted; the gap between points and line is what the model attributes to observation error.
Figure: Estimated population trend in % per year with 95% credible interval; dashed line = no change.
trend. Estimated population trend in % per year with 95% credible interval; dashed line = no change. Realised trend = average annual change of the estimated true population between the first and last year.
Figure: Expected annual growth rate vs abundance (line, 95% credible band), covariates at their mean.
density_dependence. Expected annual growth rate vs abundance (line, 95% credible band), covariates at their mean. Points: growth computed naively from consecutive raw counts; observation error makes these points look more strongly density dependent than the true process (regression-to-the-mean), which is why the state-space fit is flatter. Where the line crosses 0 is the equilibrium abundance.
Figure: Expected annual growth multiplier (lambda; 1 = stable) vs Mean winter snow depth (cm), at average abundance; line = posterior median, bands = 95% and 50% credible intervals; rug = observed values.
growth_snow_depth_cm. Expected annual growth multiplier (lambda; 1 = stable) vs Mean winter snow depth (cm), at average abundance; line = posterior median, bands = 95% and 50% credible intervals; rug = observed values. Values below 1 mean decline.
Figure: Covariate effects per 1 standard deviation of each covariate with 95% credible intervals; dashed line = no effect.
coefficients. Covariate effects per 1 standard deviation of each covariate with 95% credible intervals; dashed line = no effect.
Figure: Process noise (year-to-year variation in true growth) and observation error (counting/sampling noise), both as SDs of log abundance, with 95% credible intervals. 0.1 on this scale is roughly 10% variation.
variances. Process noise (year-to-year variation in true growth) and observation error (counting/sampling noise), both as SDs of log abundance, with 95% credible intervals. 0.1 on this scale is roughly 10% variation.
Figure: Estimated abundance (solid) and 10-year forecast (dashed) with 95% posterior predictive band; the band widens because process noise accumulates.
forecast. Estimated abundance (solid) and 10-year forecast (dashed) with 95% posterior predictive band; the band widens because process noise accumulates. Covariates (if any) are held at their average. Forecasts assume the dynamics of the study period continue.
Figure: Power to detect the simulated trend (-5.0% per year) as a function of monitoring length: share of 200 simulated datasets per point whose 95% interval for the trend excludes 0; bars = +/- 2 Monte Carlo SE; dashed line = 80% power.
power_years. Power to detect the simulated trend (-5.0% per year) as a function of monitoring length: share of 200 simulated datasets per point whose 95% interval for the trend excludes 0; bars = +/- 2 Monte Carlo SE; dashed line = 80% power.
Figure: Posterior predictive check: histograms of each statistic in 1000 count series replicated from the fitted model; vertical line = observed counts. (A) variability of year-to-year changes…
ppc. Posterior predictive check: histograms of each statistic in 1000 count series replicated from the fitted model; vertical line = observed counts. (A) variability of year-to-year changes, (B) their lag-1 autocorrelation (counting error makes it negative). Bayesian p-values 0.61 and 0.75; values below 0.05 or above 0.95 indicate misfit.
Figure: MCMC traces per chain for the top-level parameters (should overlap like hairy caterpillars).
trace. MCMC traces per chain for the top-level parameters (should overlap like hairy caterpillars).
Figure: Posterior densities of the reported quantities.
posterior. Posterior densities of the reported quantities.

Limits that matter at this design

recovery notes

nsim 100 (one fit ~74 s > 1 min), 93/100 replicates converged under the gate rule; module fast MCMC settings (3 chains x 12,000). power = share of converged replicates whose 95% CI excludes 0 (computed by dev/timeseries/si/recovery_extra.R; core leaves it NA because the module power_params name the covariate winter_severity). realised_trend rel_bias is -1.56 only because its truth is ~0.12; absolute bias 0.004 points (MC SE 0.067), gate passes.

Commands to reproduce

bin/ejob -c 1 -m 4 -t 0:15:00 -l logs/timeseries_si_repro.log -- bin/Rscript dev/timeseries/si/check_example_repro.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/timeseries_si_recover.log -- bin/Rscript core/run.R recover timeseries --config modules/timeseries/example/recovery.yaml --nsim 100 --cores 16 --out results/timeseries/si/recovery
bin/ejob -c 1 -m 4 -t 0:10:00 -l logs/timeseries_si_recovery_extra.log -- bin/Rscript dev/timeseries/si/recovery_extra.R
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/timeseries_si_fit.log -- bin/Rscript core/run.R fit timeseries --config modules/timeseries/example/config.yaml --out results/timeseries/si/fit
bin/ejob -c 2 -m 8 -t 0:30:00 -l logs/timeseries_si_fit_gompertz.log -- bin/Rscript core/run.R fit timeseries --config modules/timeseries/example/config_gompertz.yaml --out results/timeseries/si/fit_gompertz
bin/ejob -c 1 -m 8 -t 0:20:00 -l logs/timeseries_si_figures.log -- bin/Rscript core/run.R figures timeseries --config modules/timeseries/example/config.yaml --fit results/timeseries/si/fit/timeseries_fit.rds

Step-by-step walkthrough: modules/timeseries/example/WALKTHROUGH.md.

S1.20 pva: Shorebird breeding-pair survey: count-based state-space PVA with counting error and missing years (simulated)

OPEN Growth, variances and current abundance pass planted truth and the fit is healthy, but the quasi-extinction point estimate (a primary estimand) fails the mean-bias gate at 10 years (Known limit 1); intervals are calibrated (coverage 0.985), so risk is reported as an interval only.

Question

Is the shorebird population really declining, and how likely is it to fall to 40 breeding pairs or fewer within 10 and 25 years?

What the researcher typed

I have 30 years of spring counts of breeding pairs for a shorebird (shorebird_breeding_pairs.csv; blank = no survey). The counts are surveys, so they're not exact. Please tell me whether the population is declining and how likely it is to drop to 40 breeding pairs or fewer within 10 and 25 years. I don't code, so please do the analysis and give me a report and figures I can use.

Study design

ItemValue
modelcount
methodstate_space
years_spanned30
years_surveyed25
years_missing1997, 2003, 2004, 2011, 2020
first_year1994
N0420
threshold40
horizons10, 25

True values used to simulate the example data

ItemValue
growth_rate_mu-0.04
lambda_stochastic0.9608
process_variance_sigma20.012
obs_variance_tau20.03
N_current66.01
p_qext_10yr0.4461
p_qext_25yr0.8816

Planted-truth recovery at this design

paramtruthmean_estrel_biasabs_biascoveragepowerpass
growth_rate_mu-0.04-0.0415-0.0382-0.00150.970.225PASS
lambda_stochastic0.96080.9595-0.0013-0.00120.970.225PASS
N_current149.5150.20.00450.76770.94–PASS
obs_variance_tau20.030.0288-0.041-0.00120.975–PASS
p_qext_10yr0.16220.238522.30.07630.985–FAIL
p_qext_25yr0.4630.4919-0.10260.02890.985–PASS
process_variance_sigma20.0120.0140.16460.0020.985–PASS

Estimates from the example data

paramestimateloweruppertruth
growth_rate_mu-0.0593-0.12940.0127-0.04
lambda_stochastic0.94240.87871.0130.9608
process_variance_sigma20.01880.0030.09710.012
obs_variance_tau20.02560.00030.07270.03
N_current78.9161.4899.9566.01
p_qext_10yr0.49460.06340.92380.4461
p_qext_25yr0.9040.309910.8816

Convergence and goodness of fit

ItemValue
engineexact grid posterior over REML likelihood (60x60), 4000 draws, no MCMC
convergedyes
rhat–
ess–
nimble_crosscheck_median_sd_diff0.03
lag1_autocorrelation_growth-0.31
density_dependence_slope-0.012
density_dependence_p0.874
shapiro_wilk_p_log_increments0.003
shapiro_notedriven by the 2008-2009 count drop (401 to 155); data simulated with normal errors, so a false alarm caused by counting error
share_lambda_below_10.96
horizon_warning10 and 25 yr exceed 20% of the 29-yr span

Interpretation from the report

the population was not clearly increasing or decreasing: the long-run (median) growth rate is lambda = 0.942 per year (95% CI 0.879 to 1.013), i.e. a typical change of -5.8% per year (95% CI -12.1% to +1.3%).
Year-to-year variability in the log growth rate (process variance sigma^2) is 0.0188 (95% CI 0.0030 to 0.0971).
Counting (observation) error variance on the log scale is 0.0256 (95% CI 0.0003 to 0.0727), equivalent to a coefficient of variation of roughly 16% in a single count. The model's estimate of the true current abundance is 79 breeding pairs (95% CI 61 to 100).
Probability that the population falls to or below the quasi-extinction threshold of 40 breeding pairs in at least one annual census within 10 years: 49% (95% CI 6% to 92%); 25 years: 90% (95% CI 31% to >99.9%).
Forecasts beyond about 20% of the monitoring span (here 6 years) are known to be very imprecise (Fieberg & Ellner 2000); use them to compare options, not as absolute predictions.

Figures

Figure: Cumulative probability that abundance falls to or below the quasi-extinction threshold (40 breeding pairs) by each year.
quasi_extinction. Cumulative probability that abundance falls to or below the quasi-extinction threshold (40 breeding pairs) by each year. Line: estimate; dark band: 50% and light band: 95% credible interval (posterior of growth rate, variance and current abundance).
Figure: Observed counts (points), state-space estimate of true abundance with 95% band (grey) and projected abundance: median (line), 50% and 95% of simulated futures (bands) including uncertainty in growth rate and variance.
trajectories. Observed counts (points), state-space estimate of true abundance with 95% band (grey) and projected abundance: median (line), 50% and 95% of simulated futures (bands) including uncertainty in growth rate and variance. Dashed line: quasi-extinction threshold.
Figure: Posterior distribution of the long-run growth rate.
lambda_distribution. Posterior distribution of the long-run growth rate. Solid line: estimate; dashed line: lambda = 1 (stable). Share of posterior draws below 1: 96%.
Figure: Model checks.
growth_checks. Model checks. A: annual log growth rates (per year of interval) with the estimated mu; no trend or strong autocorrelation expected (lag-1 r = -0.31). B: growth rate against log abundance; a clear negative slope (here -0.012, p = 0.874) suggests density dependence, which this model ignores.

Limits that matter at this design

recovery note

nsim 200, 0 failed. Truth for N_current and p_qext varies by replicate (mean shown). p_qext_10yr fails the bias gate (abs bias +0.076 > tolerance 0.029); rel_bias of 22.3 is a mean of per-replicate ratios inflated by tiny true risks. sigma2 (+16.5%) passes only via the Monte Carlo-error tolerance.

estimates vs truth

All 7 95% intervals contain the true value.

note

The SI example uses the simulated shorebird dataset with config_state_space.yaml; config.yaml (Yellowstone grizzly, real data) has no known truth and was left unchanged.

Commands to reproduce

bin/ejob -c 1 -m 4 -t 0:10:00 -l logs/pva_si_truth.log -- bin/Rscript dev/pva/si_truth.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/pva_si_recover.log -- bin/Rscript core/run.R recover pva --config modules/pva/example/recovery.yaml --nsim 200 --cores 16 --out results/pva/si/recovery
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/pva_si_fit.log -- bin/Rscript core/run.R fit pva --config modules/pva/example/config_state_space.yaml --out results/pva/si/fit

Step-by-step walkthrough: modules/pva/example/WALKTHROUGH.md.

Distribution and community

S1.21 sdm-presence-only: Pacific marten presence-only records: point-process species distribution model with road (observer-effort) bias correction (simulated example)

DONE

Question

Which habitat (forest cover, elevation) is Pacific marten occurrence associated with, and where in the study block are martens relatively most likely to occur, after allowing for most records coming from near roads?

What the researcher typed

I have marten sightings in presence_records.csv (UTM 10N, metres; the file also has a few fisher records) and a 1 km habitat grid in covariate_grid.csv with forest cover, elevation and distance to road. Which habitat are martens associated with, and where are they most likely to occur? Most records come from near roads, so please correct for that. I'd like a report and figures for a paper.

Study design

ItemValue
study_region_km23600
grid_cells3600
cell_km21
presence_records180
other_species_records_filtered12
habitat_covariatesforest_cover_pct, elevation_m
bias_covariatesdist_road_km (4 roads)
elevation_road_correlation0.67
engineppm (inhomogeneous Poisson point process, down-weighted Poisson regression)
record_years1995-2024
cv5-fold spatial block CV, 12 km blocks

True values used to simulate the example data

ItemValue
intensity_beta_forest_cover_pct0.9
intensity_beta_elevation_m0.4
bias_beta_dist_road_km-1.1
density_at_mean_covariates0.4
rate_ratio_forest_per_10pct1.441
rate_ratio_elevation_per_100m1.154
generatordev/sdm-presence-only/make_example.R, module$simulate() seed 2025; example/TRUTH.txt

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
bias_beta_dist_road_km-1.1-1.0950.00450.971PASS
intensity_beta_elevation_m0.40.396-0.010.9650.97PASS
intensity_beta_forest_cover_pct0.90.90790.00870.9551PASS

Estimates from the example data

paramestimateloweruppertruth
intensity_beta_forest_cover_pct1.0950.88231.3090.9
intensity_beta_elevation_m0.39230.19510.58950.4
bias_beta_dist_road_km-1.021-1.285-0.7574-1.1
rate_ratio_forest_per_SD2.992.423.7–
rate_ratio_forest_per_10pct1.561.431.71.441
rate_ratio_elevation_per_SD1.481.221.8–
rate_ratio_elevation_per_100m1.151.071.231.154
recording_rate_ratio_road_per_5km0.450.360.55–

Convergence and goodness of fit

ItemValue
convergedyes
recovery_nsim200
recovery_converged200
coverage_bound0.904
gof_block_pearson_dispersion0.94
gof_p0.69
gof_blocks25
gof_reps1000
quadrature_max_change_SEevery_2nd = 0.17; every_4th = 0.41; every_8th = 1
cv_habitat_map_auc0.67
cv_habitat_map_boyce0.68
cv_records_map_auc0.76
cv_records_map_boyce0.81
elevation_slope_if_bias_ignored-0.23
forest_slope_if_bias_ignored0.98

Interpretation from the report

Forest cover (%): holding the other covariates at their landscape means, each 1 SD increase (24.6 percentage points) is associated with a change in relative intensity of occurrence of x2.99 (95% CI 2.42 to 3.70; +199%); per 10 percentage points, x1.56 (95% CI 1.43 to 1.70). Across the observed range (7.6% to 98.3%) this is a 56.4-fold difference.
Elevation (m): holding the other covariates at their landscape means, each 1 SD increase (280 m) is associated with a change in relative intensity of occurrence of x1.48 (95% CI 1.22 to 1.80; +48%); per 100 m, x1.15 (95% CI 1.07 to 1.23).
Sampling bias, Distance to road (km): the rate at which records were made changed by x0.36 (95% CI 0.28 to 0.47; -64%) per 1 SD (6.34 km) and x0.45 (95% CI 0.36 to 0.55) per 5 km. This describes where people looked, not where the species lives.
For comparison, ignoring the bias covariate would give log-intensity slopes per SD of Forest cover (%) 0.98 instead of 1.10; Elevation (m) -0.23 instead of 0.39.
The map is RELATIVE: a value of 2 means twice the landscape-average intensity of occurrence, not a 2% or 20% chance of presence.
All effects are associations between covariates and where the species was recorded, after allowing for the stated sampling bias. They are not evidence that the covariate causes the pattern.

Figures

Figure: Response curves for all habitat covariates (y axis: relative intensity (1 = average)), others at their means, sampling bias removed; bands 95% and 50% confidence (parametric draws from the ML fit) intervals.
response_curves_panel. Response curves for all habitat covariates (y axis: relative intensity (1 = average)), others at their means, sampling bias removed; bands 95% and 50% confidence (parametric draws from the ML fit) intervals.
Figure: Relative intensity of occurrence (1 = landscape average; log colour scale) predicted from the habitat covariates with sampling bias removed; white points are the presence records, which also reflect where people looked.
intensity_map. Relative intensity of occurrence (1 = landscape average; log colour scale) predicted from the habitat covariates with sampling bias removed; white points are the presence records, which also reflect where people looked.
Figure: Estimated relative recording effort (sampling bias; 1 = landscape average, log colour scale) from the bias covariates, with the presence records.
bias_map. Estimated relative recording effort (sampling bias; 1 = landscape average, log colour scale) from the bias covariates, with the presence records.
Figure: Relative intensity of occurrence (1 = intensity at average conditions) vs forest cover (%), other covariates at their landscape means and sampling bias removed.
effect_forest_cover_pct. Relative intensity of occurrence (1 = intensity at average conditions) vs forest cover (%), other covariates at their landscape means and sampling bias removed. Line: estimate; bands: 95% and 50% confidence (parametric draws from the ML fit) intervals; rug: covariate value at each presence record.
Figure: Relative intensity of occurrence (1 = intensity at average conditions) vs elevation (m), other covariates at their landscape means and sampling bias removed.
effect_elevation_m. Relative intensity of occurrence (1 = intensity at average conditions) vs elevation (m), other covariates at their landscape means and sampling bias removed. Line: estimate; bands: 95% and 50% confidence (parametric draws from the ML fit) intervals; rug: covariate value at each presence record.
Figure: Sampling-bias (observer effort) effect: rate at which records are made relative to the mean of the bias covariate, habitat held constant.
bias_effect. Sampling-bias (observer effort) effect: rate at which records are made relative to the mean of the bias covariate, habitat held constant. Bands: 95% and 50% confidence (parametric draws from the ML fit) intervals; rug: values at presence records. This is a property of the observers, not the species.
Figure: Spatial block cross-validation (5 folds). (A) AUC and continuous Boyce index on held-out blocks for the habitat map (sampling bias removed), the records map (habitat x recording effort) and, if present…
evaluation. Spatial block cross-validation (5 folds). (A) AUC and continuous Boyce index on held-out blocks for the habitat map (sampling bias removed), the records map (habitat x recording effort) and, if present, held-out survey sites (detected vs not); grey points = folds, diamonds = mean, dashed = no skill. (B) Predicted-to-expected ratio of held-out records along the habitat-map gradient, one line per fold (Hirzel et al. 2006); a rising curve means more records than expected where the map predicts high intensity.
Figure: Habitat effects on the intensity of occurrence and sampling-bias effects on the recording rate, as multiplicative changes per 1 SD of each covariate (log scale) with 95% Wald confidence intervals; dashed line = no effect.
coefficients. Habitat effects on the intensity of occurrence and sampling-bias effects on the recording rate, as multiplicative changes per 1 SD of each covariate (log scale) with 95% Wald confidence intervals; dashed line = no effect.
Figure: Quadrature convergence (Renner et al. 2015): coefficient estimates as the quadrature grid is refined from every 8th cell to every cell.
quadrature_convergence. Quadrature convergence (Renner et al. 2015): coefficient estimates as the quadrature grid is refined from every 8th cell to every cell. Shaded band: full-grid estimate +/- 0.5 standard errors; points inside it at the right mean the integral is well approximated.
Figure: Goodness of fit: observed Pearson statistic (line) for record counts in 25 spatial blocks vs 1000 datasets simulated from the fitted model.
gof. Goodness of fit: observed Pearson statistic (line) for record counts in 25 spatial blocks vs 1000 datasets simulated from the fitted model. An observed value in the far right tail means records are more clustered than the model allows.

Limits that matter at this design

Commands to reproduce

bin/ejob -c 1 -m 4 -t 0:20:00 -l logs/sdm-presence-only_make_example.log -- bin/Rscript dev/sdm-presence-only/make_example.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/sdm-presence-only_si_recover.log -- bin/Rscript core/run.R recover sdm-presence-only --config modules/sdm-presence-only/example/recovery.yaml --nsim 200 --cores 16 --out results/sdm-presence-only/si/recovery
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/sdm-presence-only_si_fit.log -- bin/Rscript core/run.R fit sdm-presence-only --config modules/sdm-presence-only/example/config.yaml --out results/sdm-presence-only/si/fit

Step-by-step walkthrough: modules/sdm-presence-only/example/WALKTHROUGH.md.

S1.22 jsdm: Joint species distribution model (HMSC): forest breeding birds along temperature and canopy gradients (simulated)

OPEN OPEN, narrowly. Planted truth at this design (nsim 100, 98 converged): 153 of 156 interpreted rows pass the gate. All population-averaged responses (30/30), community averages (2/2), trait effects (3/3), prevalences (15/15) and richness (1/1) pass, but 3 of 105 latent residual-correlation rows fail, all for pairs whose true correlation is near zero (|r| < 0.05): two on coverage (0.878 vs threshold 0.884) and one on bias (+0.040, 3.2 MC SE). The gate requires every interpreted estimand to pass, and thresholds are not widened. The real-data fit converged (R-hat 1.004, ESS >= 1300) and passed the posterior predictive check. Treat individual weak residual associations as less reliable than their intervals suggest. Responses, trait effects and richness can be reported.

Question

How do 15 forest bird species respond to July temperature and canopy cover, does body size explain which species respond how, and which species co-occur more or less often than the habitat predicts?

What the researcher typed

I have bird point-count data in modules/jsdm/example/: bird_detections.csv (every detection, 3 visits per station), stations.csv (coordinates, July temperature, canopy cover) and bird_traits.csv (body mass and family for each species). How does each species respond to July temperature and canopy cover? Does body size explain who responds how? Which species occur together more or less than the habitat predicts? Please give me a report with figures I can put in a paper.

Study design

ItemValue
n_sites120
n_species15
n_visits3
n_covariates2
covariatesjuly_temp_c, canopy_cover_pct
covariate_correlation-0.27
n_traits1
traitlog(body_mass_g)
n_latent_factors_true2
responsepresence (probit)
taxonomyorder/family
detection_per_visit_true0.7

True values used to simulate the example data

ItemValue
comm_mean_intercept-0.4
comm_mean_july_temp_c0.5
comm_mean_canopy_cover_pct0.4
trait_log_body_mass_g_on_intercept0.35
trait_log_body_mass_g_on_july_temp_c-0.45
trait_log_body_mass_g_on_canopy_cover_pct0.3
species_sd0.5
loading_sd10.9
loading_sd20.6
comm_popavg_july_temp_c0.227
comm_popavg_canopy_cover_pct0.257
popavg_trait_log_body_mass_g_on_intercept0.327
popavg_trait_log_body_mass_g_on_july_temp_c-0.223
popavg_trait_log_body_mass_g_on_canopy_cover_pct0.245
richness_mean_env5.65
seed20261019

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpassinterpretedrows_passnote
comm_mean_forest0.40.43750.09380.95920.7653PASSno––
comm_mean_intercept-0.4-0.4389-0.09720.9592–PASSno––
comm_mean_temperature0.50.54420.08840.95920.8878PASSno––
comm_popavg_forest0.30110.2998-0.007790.9490.9694PASSyes––
comm_popavg_temperature0.37350.37840.007720.91841PASSyes––
popavg_trait_log_body_mass_on_forest0.22010.2238-0.0310.9490.8673PASSyes––
popavg_trait_log_body_mass_on_intercept0.26420.2761-0.01750.9694–PASSyes––
popavg_trait_log_body_mass_on_temperature-0.356-0.3624-0.01220.96940.9898PASSyes––
richness_mean_env5.935.928-0.0003920.9592–PASSyes––
trait_log_body_mass_on_forest0.30.32130.0710.9490.449PASSno––
trait_log_body_mass_on_intercept0.350.40510.1580.93880.602FAILno––
trait_log_body_mass_on_temperature-0.45-0.531-0.180.9490.8163FAILno––
popavg_* (class: 30 rows)––0.20.942–PASSyes30/30rel_bias = median |relative bias| over rows; coverage = mean over rows
latcor_* (class: 105 rows)––0.320.954–FAILyes102/105rel_bias = median |relative bias| over rows; coverage = mean over rows
prev_* (class: 15 rows)––0.0150.952–PASSyes15/15rel_bias = median |relative bias| over rows; coverage = mean over rows
beta_* (class: 45 rows)––0.440.953–FAILno32/45rel_bias = median |relative bias| over rows; coverage = mean over rows
rescor_* (class: 105 rows)––0.2040.76–FAILno0/105rel_bias = median |relative bias| over rows; coverage = mean over rows

Estimates from the example data

paramestimateloweruppertruth
comm_mean_intercept-0.632-1.253-0.1334-0.4
comm_mean_july_temp_c0.3739-0.0620.78490.5
comm_mean_canopy_cover_pct0.4345-0.059960.88430.4
trait_log_body_mass_g_on_intercept0.49710.11680.88440.35
trait_log_body_mass_g_on_july_temp_c-0.2611-0.54940.04381-0.45
trait_log_body_mass_g_on_canopy_cover_pct0.39220.062180.74780.3
comm_popavg_july_temp_c0.26420.19310.33380.227
comm_popavg_canopy_cover_pct0.30170.22540.37980.257
popavg_trait_log_body_mass_g_on_intercept0.32990.26450.39290.327
popavg_trait_log_body_mass_g_on_july_temp_c-0.1995-0.2671-0.1317-0.223
popavg_trait_log_body_mass_g_on_canopy_cover_pct0.24790.1780.31670.245
richness_mean_env5.2724.9425.625.65
phylo_signal_rho0.306900.96–

Convergence and goodness of fit

ItemValue
rhat_max1.004
ess_bulk_min1300
convergedyes
chains4
samples_per_chain1000
thin50
transient25000
mcmc_seconds952
latent_factors_retained5
ppc_p_richness_variance0.71
ppc_p_mean_cooccurrence0.67
observed_richness_variance4.52
tjur_r2_mean0.46
tjur_r2_range0.15, 0.66
auc_mean0.96
truth_coveragepopavg = 29/30; latcor = 99/105; prev = 14/15; beta = 43/45; gamma = 6/6; popavg_trait = 3/3; comm_popavg = 2/2; richness = 0/1

Interpretation from the report

July mean max. temperature (°C): 8 of 15 species respond positively and 0 negatively with at least 95% posterior support. The average response across these species is 0.26 per 1 SD (2.47 °C) on the population-averaged probit scale (95% CrI 0.19 to 0.33); for a species with average occurrence probability (0.35) that is a change to 0.45 (0.43 to 0.48) per SD.
Canopy cover (%): 9 of 15 species respond positively and 1 negatively with at least 95% posterior support; average response 0.30 per 1 SD (23 percentage points) (95% CrI 0.23 to 0.38).
The pool-level community means (Gamma) are 0.37 (95% CrI -0.06 to 0.78) for temperature and 0.43 (-0.06 to 0.88) for canopy: neither excludes zero, so a new species from the same pool could respond either way.
Expected species richness is 4.2 (95% CrI 3.7-4.7) at 15.5 °C and 7.1 (6.6-7.7) at 21.8 °C (10th and 90th percentiles of sites); 3.8 (3.3-4.3) at 31% canopy and 7.2 (6.7-7.7) at 90%. These are associations, not causal effects.
Larger species have higher baseline prevalence (0.33, 95% CrI 0.26 to 0.39; Gamma 0.50, 0.12 to 0.88) and more positive responses to canopy (0.25, 0.18 to 0.32; Gamma 0.39, 0.06 to 0.75); their more negative response to temperature (-0.20, -0.27 to -0.13) is not supported for the wider pool (Gamma -0.26, -0.55 to 0.04).
Variance partitioning: July temperature 17%, canopy cover 20%, residual associations (latent site factors) 63%.
Of 105 species pairs, 39 co-occur more and 37 less often than expected from the covariates (>= 95% support); strongest Hairy Woodpecker & Spotted Towhee (r = -0.71, 95% CrI -0.86 to -0.51). Residual correlations are not evidence of biotic interactions.
All responses describe where species were recorded, not true occurrence: HMSC assumes detection is perfect or constant within a species.

Figures

Figure: Species-specific responses (probit scale, population-averaged over the latent site factors, per 1 SD of each covariate).
species_responses. Species-specific responses (probit scale, population-averaged over the latent site factors, per 1 SD of each covariate). Coloured cells have at least 95% posterior support for a positive (red) or negative (blue) response; grey cells lack that support. Numbers are posterior means.
Figure: Residual species associations: posterior mean latent-scale residual correlations (after the covariates).
residual_associations. Residual species associations: posterior mean latent-scale residual correlations (after the covariates). Coloured cells have at least 95% posterior support for a positive (red) or negative (blue) association; grey = not supported, blank diagonal. Associations are not evidence of biotic interactions (Blanchet et al. 2020): unmeasured shared habitat preferences produce the same pattern.
Figure: Variance partitioning of the linear predictor for each species among covariates and residual associations (latent site factors).
variance_partitioning. Variance partitioning of the linear predictor for each species among covariates and residual associations (latent site factors). Community averages: July mean max. temperature (°C) 17%; Canopy cover (%) 20%; Residual associations (site latent factors) 63%.
Figure: Community-level parameters (population-averaged probit scale: species responses with latent site factors integrated out, regressed on traits…
trait_effects. Community-level parameters (population-averaged probit scale: species responses with latent site factors integrated out, regressed on traits; these describe the modelled species, and whether a trait effect extends to the wider species pool is judged from Hmsc's Gamma, reported in the text). Blue: average response across species (per 1 SD of the covariate); orange: change in species' responses per 1 SD of the trait (trait-environment interaction; 'baseline' = effect on prevalence/abundance at average conditions). Points are posterior means, thick and thin bars 50% and 95% credible intervals; dashed line = no effect.
Figure: Expected species richness along July mean max. temperature (°C), other covariates at their mean (line: posterior mean; bands: 95% and 50% credible intervals; latent site factors averaged out).
richness_july_temp_c. Expected species richness along July mean max. temperature (°C), other covariates at their mean (line: posterior mean; bands: 95% and 50% credible intervals; latent site factors averaged out). Points: observed richness per site.
Figure: Species-specific probability of occurrence along July mean max. temperature (°C) (other covariates at their mean, latent factors averaged out); bands are 95% and 50% credible intervals.
occurrence_july_temp_c. Species-specific probability of occurrence along July mean max. temperature (°C) (other covariates at their mean, latent factors averaged out); bands are 95% and 50% credible intervals.
Figure: Expected species richness along Canopy cover (%), other covariates at their mean (line: posterior mean; bands: 95% and 50% credible intervals; latent site factors averaged out).
richness_canopy_cover_pct. Expected species richness along Canopy cover (%), other covariates at their mean (line: posterior mean; bands: 95% and 50% credible intervals; latent site factors averaged out). Points: observed richness per site.
Figure: Species-specific probability of occurrence along Canopy cover (%) (other covariates at their mean, latent factors averaged out); bands are 95% and 50% credible intervals.
occurrence_canopy_cover_pct. Species-specific probability of occurrence along Canopy cover (%) (other covariates at their mean, latent factors averaged out); bands are 95% and 50% credible intervals.
Figure: In-sample explanatory power per species (Tjur R², including latent site factors) against prevalence.
model_fit. In-sample explanatory power per species (Tjur R², including latent site factors) against prevalence. Mean 0.46.
Figure: Posterior predictive check: variance of site richness in data replicated from the posterior at new sites (latent factors redrawn) vs the observed value (line).
ppc. Posterior predictive check: variance of site richness in data replicated from the posterior at new sites (latent factors redrawn) vs the observed value (line).
Figure: MCMC traces of the community-level parameters, one colour per chain (post burn-in, thinned).
trace. MCMC traces of the community-level parameters, one colour per chain (post burn-in, thinned).
Figure: Posterior densities of the community-level parameters.
posterior. Posterior densities of the community-level parameters.

Limits that matter at this design

recovery run

ItemValue
nsim100
converged98
settingsmodule fast_settings (3 chains x 250, thin 80, transient 20000)
interpreted_rows_pass153/156
median_seconds_per_replicate522

Commands to reproduce

bin/ejob -c 1 -m 4 -t 0:15:00 -l logs/jsdm_si_truth.log -- bin/Rscript dev/jsdm/si_truth.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/jsdm_si_recover.log -- bin/Rscript core/run.R recover jsdm --config modules/jsdm/example/recovery.yaml --nsim 100 --cores 16 --out results/jsdm/si/recovery
bin/ejob -c 1 -m 4 -t 0:15:00 -l logs/jsdm_si_recsumm.log -- bin/Rscript dev/jsdm/summ.R results/jsdm/si/recovery recover
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/jsdm_si_fit.log -- bin/Rscript core/run.R fit jsdm --config modules/jsdm/example/config.yaml --out results/jsdm/si/fit
bin/ejob -c 2 -m 8 -t 0:30:00 -l logs/jsdm_si_figs.log -- bin/Rscript core/run.R figures jsdm --fit results/jsdm/si/fit/jsdm_fit.rds --config modules/jsdm/example/config.yaml
bin/ejob -c 1 -m 4 -t 0:15:00 -l logs/jsdm_si_compare.log -- bin/Rscript dev/jsdm/si_compare.R
bin/ejob -c 1 -m 4 -t 0:15:00 -l logs/jsdm_si_summary.log -- bin/Rscript dev/jsdm/si_summary.R

Step-by-step walkthrough: modules/jsdm/example/WALKTHROUGH.md.

S1.23 community: Forest bird communities along elevation and canopy gradients and among stand types (simulated Oregon Cascades point counts)

OPEN Planted-truth gate at the example design: 10/11 estimands PASS; R2adj_shared FAILS on coverage (0.890 < 0.904) and the report prints an interval for it. All other gate steps pass (no MCMC; NMDS/DCA/CCA/db-RDA/PERMDISP checks clean; cross-check vs vegan/betapart to 3e-16 and negative controls in VALIDATION.md). Everything except the shared-fraction interval can be reported.

Question

How much of the variation in breeding-bird community composition among 60 stations goes with elevation versus canopy cover; do old growth, thinned and young plantation stands hold different communities (and differ in variability); is beta diversity turnover or nestedness; and which species indicate each stand type?

What the researcher typed

I have bird point counts from 60 forest stations (cascades_bird_counts.csv, one column per species) and a station table with stand type, elevation and canopy cover (cascades_stations.csv). How much of the variation in the bird community goes with elevation versus canopy cover, do old growth, thinned and young plantation stands hold different communities, is it turnover or nestedness, and which species are indicators of each stand type? Please give me a report and figures I can use in a paper.

Study design

ItemValue
n_sites60
n_species30
n_groups3
group_sizesold_growth = 22; thinned = 20; young_plantation = 18
n_gradients2
gradientselevation_m (407-1582), canopy_cover_pct (14-88)
env_cor0.4
visits_per_site1
data_typeabundance
total_birds1774

True values used to simulate the example data

ItemValue
R2adj_elevation_m0.252
R2adj_canopy_cover_pct0.1064
R2adj_unique_elevation_m0.2124
R2adj_unique_canopy_cover_pct0.0668
R2adj_shared0.0396
R2adj_env_total0.3188
beta_sor_pair_mean0.6187
beta_sim_pair_mean0.5168
beta_sne_pair_mean0.1019
turnover_share0.8353
R2adj_stand_type_permanova0.0504
simulation_settingsn_species = 30; abund_max = 4; abund_sd = 0.8; tol1 = 0.2; tol2 = 0.4; group_effect_sd = 0.9; site_noise_sd = 0.5; dispersion_mult = 1.4; env_cor = 0.4; effort = 1; seed = 2026

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
R2adj_elevation_m0.29290.2907-0.00760.955–PASS
R2adj_canopy_cover_pct0.10980.1092-0.00290.935–PASS
R2adj_unique_elevation_m0.24670.2451-0.0060.94–PASS
R2adj_unique_canopy_cover_pct0.06350.0636-0.00390.955–PASS
R2adj_shared0.04620.04560.02810.89–FAIL
R2adj_env_total0.35650.3543-0.00620.935–PASS
R2adj_stand_type_permanova0.09680.09960.03030.97–PASS
beta_sor_pair_mean0.52350.52510.00320.965–PASS
beta_sim_pair_mean0.44170.44410.00560.965–PASS
beta_sne_pair_mean0.08180.081-0.00970.925–PASS
turnover_share0.84260.84440.00220.955–PASS

Estimates from the example data

paramestimatelowerupperp_valuetruth
R2adj_elevation_m0.24580.20010.29150.0010.252
R2adj_canopy_cover_pct0.07680.02710.12650.0010.1064
R2adj_unique_elevation_m0.21660.15680.27640.0010.2124
R2adj_unique_canopy_cover_pct0.04760.02360.07150.0010.0668
R2adj_shared0.0292-0.01940.0779–0.0396
R2adj_env_total0.29340.24640.34040.0010.3188
R2adj_stand_type_permanova0.0390.00940.06860.0110.0504
beta_sor_pair_mean0.63440.60530.6635–0.6187
beta_sim_pair_mean0.53740.49920.5756–0.5168
beta_sne_pair_mean0.09690.07540.1185–0.1019
turnover_share0.84720.81160.8827–0.8353
dispersion_ratio_stand_type1.036––0.776–
nmds_stress0.1631––––
dca_axis1_length_sd4.638––––
cca_R2adj_env_total0.2393––0.001–
dbrda_R2adj_env_total0.3005––0.001–
beta_SOR_multisite0.9514––––
beta_SIM_multisite0.928––––
beta_SNE_multisite0.0234––––

Convergence and goodness of fit

ItemValue
convergedyes
mcmcnone (least squares + permutation tests)
nmds_stress0.163
nmds_best_solution_repeatedno
dca_axis1_length_sd4.64
rda_R2adj_total0.293
dbrda_R2adj_env_total0.3
cca_R2adj_env_total0.239
permdisp_p0.776
dispersion_ratio1.04
mean_dist_to_centroidold_growth = 0.525; thinned = 0.527; young_plantation = 0.509
permanova_p0.011
pairwise_permanova_holmold_growth_vs_thinned = R2 = 0.038; p = 0.124; old_growth_vs_young_plantation = R2 = 0.059; p = 0.04; thinned_vs_young_plantation = R2 = 0.07; p = 0.027
n_permutations999
truth_in_ci11/11

Interpretation from the report

Together the variables accounted for 29.3% (95% CI 24.6% to 34.0%) of the among-site variation (adjusted R2, p = 0.001), leaving 70.7% unexplained.
Elevation (m) alone 24.6% (95% CI 20.0% to 29.1%) (p = 0.001); elevation after accounting for the other variables 21.7% (95% CI 15.7% to 27.6%) (p = 0.001); Canopy cover (%) alone 7.7% (95% CI 2.7% to 12.6%) (p = 0.001); canopy cover after accounting for the other variables 4.8% (95% CI 2.4% to 7.2%) (p = 0.001).
The shared fraction, 2.9% (95% CI -1.9% to 7.8%), is variation that cannot be attributed to one variable because the variables are correlated with each other; it is not an interaction and has no test. [Agent note: its interval failed the planted-truth coverage gate at this design (0.890); report it as descriptive.]
The association is correlational: unmeasured variables that co-vary with elevation (m) could produce the same pattern.
Stand type groups differed in composition: group membership accounted for 3.9% (95% CI 0.9% to 6.9%) of the variation in Bray-Curtis dissimilarities (PERMANOVA adjusted R2, p = 0.011).
Because PERMDISP found no dispersion difference (p = 0.776), the PERMANOVA result is most consistent with a shift in average species composition (location). PERMDISP has limited power for modest differences in spread, though, so a smaller contribution from dispersion cannot be ruled out.
Golden-crowned Kinglet was an indicator of young plantation after false-discovery-rate correction (IndVal 0.78, A 0.83, B 0.72, p = 0.030).
Two sites differed on average by Sorensen dissimilarity 0.63 (95% CI 0.61 to 0.66); 85% (95% CI 81% to 88%) of this was turnover. Composition changes mainly by replacement.

Figures

Figure: Variation partitioning (RDA, hellinger transformation).
variance_partition. Variation partitioning (RDA, hellinger transformation). Bars: adjusted R2 of each fraction; error bars: 95% jackknife confidence intervals. 'Unique' = explained by that set after removing the others; 'Shared' = jointly explained and not attributable to either set (can be negative). Unexplained = 1 - adjusted R2 of all variables.
Figure: Non-metric multidimensional scaling of Bray-Curtis dissimilarities (stress 0.163).
ordination. Non-metric multidimensional scaling of Bray-Curtis dissimilarities (stress 0.163). Points are sites coloured by stand type; dashed ellipses enclose about 68% of each group's sites. Arrows: environmental variables fitted to the ordination (envfit), length proportional to correlation: Elevation (m) (r2 = 0.94, p = 0.001); Canopy cover (%) (r2 = 0.56, p = 0.001). Grey crosses and italic labels: weighted-average positions of the 8 species furthest from the centre.
Figure: Shepard diagram: each point is a pair of sites.
nmds_shepard. Shepard diagram: each point is a pair of sites. The red step line is the monotone fit; scatter around it is what stress measures (stress 0.163).
Figure: Redundancy analysis of hellinger-transformed species data constrained by Elevation (m), Canopy cover (%) (scaling 2: angles between arrows reflect correlations).
rda_triplot. Redundancy analysis of hellinger-transformed species data constrained by Elevation (m), Canopy cover (%) (scaling 2: angles between arrows reflect correlations). Points are sites; arrows are the environmental variables; italic labels are the 8 species best represented in this plane. Constrained axes together explain adjusted R2 = 29.3% of the variation.
Figure: Share of variation in community composition associated with each environmental set (RDA) and with the grouping factor (PERMANOVA).
effect_sizes. Share of variation in community composition associated with each environmental set (RDA) and with the grouping factor (PERMANOVA). Dashed line: no association. Points: adjusted R2; lines: jackknife confidence intervals.
Figure: Baselga (2010) partition of pairwise Sorensen dissimilarity into turnover (Simpson) and nestedness-resultant components.
beta_components. Baselga (2010) partition of pairwise Sorensen dissimilarity into turnover (Simpson) and nestedness-resultant components. Grey: distribution over all 1770 site pairs. Points and bars: mean over pairs with 95% jackknife CI. Turnover share = 85%.
Figure: Turnover and nestedness components of dissimilarity for every pair of sites against their difference in elevation (m).
distance_decay. Turnover and nestedness components of dissimilarity for every pair of sites against their difference in elevation (m). Lines: loess smooths with 95% confidence bands. Turnover rising with environmental distance indicates replacement of species along the gradient.
Figure: Multivariate dispersion (PERMDISP, betadisper on Bray-Curtis dissimilarity): distance of each site (points) to its group's centroid.
dispersion. Multivariate dispersion (PERMDISP, betadisper on Bray-Curtis dissimilarity): distance of each site (points) to its group's centroid. Boxes: quartiles; black points and bars: group means with 95% t confidence intervals. Permutation test of equal dispersion: p = 0.776. PERMANOVA cannot distinguish location from dispersion differences, so read it together with this figure.
Figure: Indicator species analysis (IndVal.g, 999 permutations).
indicator_species. Indicator species analysis (IndVal.g, 999 permutations). Each species is shown for the stand type it is most associated with; IndVal combines specificity (share of the species' abundance in that group) and fidelity (share of that group's sites occupied). Filled: significant after Benjamini-Hochberg correction; open: uncorrected p < 0.05 only.
Figure: Response curves of the 6 species whose occurrence or abundance is most strongly associated with elevation (m) (quadratic quasi-Poisson GLM; other numeric gradients held at their means).
species_response_elevation_m. Response curves of the 6 species whose occurrence or abundance is most strongly associated with elevation (m) (quadratic quasi-Poisson GLM; other numeric gradients held at their means). Lines: fitted expected count; bands: 95% confidence intervals; points: observed sites; rug: sampled values of elevation (m).
Figure: Response curves of the 6 species whose occurrence or abundance is most strongly associated with canopy cover (%) (quadratic quasi-Poisson GLM; other numeric gradients held at their means).
species_response_canopy_cover_pct. Response curves of the 6 species whose occurrence or abundance is most strongly associated with canopy cover (%) (quadratic quasi-Poisson GLM; other numeric gradients held at their means). Lines: fitted expected count; bands: 95% confidence intervals; points: observed sites; rug: sampled values of canopy cover (%).

Limits that matter at this design

recovery notes

nsim=200 at the example design (recovery.yaml), new species pool per replicate so truths are replicate means; coverage bound 0.904; 200/200 ran. 10/11 PASS; R2adj_shared FAIL on coverage (0.890), bias fine. Power not computed (power column NA in core summary for non-null truths).

Commands to reproduce

bin/ejob -c 1 -m 4 -- bin/Rscript dev/community/make_example.R
bin/ejob -c 1 -m 4 -l logs/community_si_check.log -- bin/Rscript dev/community/si/check_example.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/community_si_recover.log -- bin/Rscript core/run.R recover community --config modules/community/example/recovery.yaml --nsim 200 --cores 16 --out results/community/si/recovery
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/community_si_fit.log -- bin/Rscript core/run.R fit community --config modules/community/example/config.yaml --out results/community/si/fit

Step-by-step walkthrough: modules/community/example/WALKTHROUGH.md.

Movement

S1.24 movement-hmm: Behavioural states of GPS-collared elk with a hidden Markov model (simulated example)

OPEN 15/16 estimands pass planted-truth recovery at this design; tpm_2to1_tod_sin coverage 0.890 < bound 0.904 (bias -4.3%, within tolerance). Convergence and GOF pass. Conclusions on states, activity budget and forest association are supported; time-of-day intervals may be slightly narrow (VALIDATION.md Known limit 3).

Question

Do collared elk switch between an encamped (short-step) and a travelling (long-step) movement mode, how much time do they spend in each, and is switching associated with time of day and forest cover?

What the researcher typed

Here is a CSV of hourly GPS fixes from 5 elk (elk_gps.csv, times are Pacific time). I want to know whether they switch between resting and travelling, how much time they spend in each, and whether time of day and forest cover affect switching. Please analyse it and give me a report with figures I can use in a paper.

Study design

ItemValue
n_animals5
n_fixes_per_animal720
fix_interval_h1
fixes_in_file3416
regular_time_steps3600
missing_steps184
missing_prop0.05
jitter_min2
landscape_km20
nstates2
covariatesforest_cover_pct, time_of_day
time_zoneAmerica/Los_Angeles
seed2024

True values used to simulate the example data

ItemValue
step_mean_m_state160
step_mean_m_state2450
step_sd_m_state150
step_sd_m_state2300
turn_concentration_state10.5
turn_concentration_state22.5
tpm_1to2_intercept-1.667
tpm_2to1_intercept-1.133
tpm_1to2_tod_cos-0.9
tpm_2to1_tod_cos0.7
tpm_1to2_tod_sin0.4
tpm_2to1_tod_sin-0.3
tpm_1to2_forest_cover_pct-0.025
tpm_2to1_forest_cover_pct0.025
activity_budget_state10.5863
activity_budget_state20.4137

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
activity_budget_state10.59150.59250.00170.935–PASS
activity_budget_state20.40850.4075-0.00250.935–PASS
step_mean_m_state16060.150.00240.92–PASS
step_mean_m_state2450450.90.00190.935–PASS
step_sd_m_state15049.99-0.00030.955–PASS
step_sd_m_state2300299.7-0.00090.96–PASS
tpm_1to2_forest-0.025-0.026-0.04080.930.995PASS
tpm_1to2_intercept-1.683-1.688-0.00250.96–PASS
tpm_1to2_tod_cos-0.9-0.89480.00580.955–PASS
tpm_1to2_tod_sin0.40.4020.00510.915–PASS
tpm_2to1_forest0.0250.02510.00530.9651PASS
tpm_2to1_intercept-1.117-1.1110.00470.955–PASS
tpm_2to1_tod_cos0.70.70880.01250.955–PASS
tpm_2to1_tod_sin-0.3-0.313-0.04340.89–FAIL
turn_concentration_state10.50.4967-0.00650.945–PASS
turn_concentration_state22.52.5060.00240.92–PASS

Estimates from the example data

paramestimateloweruppertruth
step_mean_m_state159.7556.7762.7960
step_mean_m_state2453.7434.3472.7450
step_sd_m_state150.3547.1553.5650
step_sd_m_state2293.6278309.8300
turn_concentration_state10.49510.42810.56990.5
turn_concentration_state22.3252.1662.4942.5
tpm_1to2_intercept-1.633-1.782-1.477-1.667
tpm_1to2_tod_cos-0.9209-1.135-0.6963-0.9
tpm_1to2_tod_sin0.48040.26570.70240.4
tpm_1to2_forest_cover_pct-0.02645-0.03654-0.016-0.025
tpm_2to1_intercept-1.131-1.302-0.9593-1.133
tpm_2to1_tod_cos0.68040.42980.93970.7
tpm_2to1_tod_sin-0.4134-0.6308-0.2042-0.3
tpm_2to1_forest_cover_pct0.026390.015350.038130.025
activity_budget_state10.58160.54950.61120.5863
activity_budget_state20.41840.38880.45050.4137

Convergence and goodness of fit

ItemValue
optimiser_convergedyes
starts_at_best10
nstarts10
loglik-2.465e+04
hessianfull Hessian singular because the initial-state distribution (nuisance) is on a boundary; intervals condition on it
ks_p_step0.932
ks_p_angle0.745
lag1_acf_step-0.02
max_abs_acf_step0.043
acf_bound0.035
truth_in_95ci15/16 (miss: turn_concentration_state2 2.32 [2.17, 2.49] vs 2.5)

Interpretation from the report

Encamped (short steps): mean step 60 m per 1 h (95% CI 57-63 m), turning concentration 0.50 (0.43-0.57), i.e. little directional persistence (frequent sharp turns and reversals).
Travelling (long steps): mean step 454 m per 1 h (95% CI 434-473 m), turning concentration 2.32 (2.17-2.49), i.e. moderate directional persistence.
Activity budget (expected long-run share of time in each state, averaged over the 24-h cycle, at the average value of the habitat covariates): Encamped (short steps) 58% (95% CI 55-61%); Travelling (long steps) 42% (95% CI 39-45%).
Time of day: the probability that an animal is in Travelling (long steps) is highest around 11:00 at 71% (95% CI 67-76%) and lowest around 23:00 at 15% (12-19%), with habitat at its mean.
Each 1-SD increase in forest_cover_pct (14.9 units) multiplies the odds of switching from Encamped to Travelling (versus staying) per time step by 0.67 (95% CI 0.58-0.79); switching back from Travelling to Encamped changes by a factor 1.48 (1.26-1.76) per SD.
The model-predicted long-run share of time in Encamped (short steps) would be 41% (95% CI 36-47%) if forest_cover_pct were held at 32.5 (10th percentile of the fixes) and 73% (69-77%) if it were held at 72.8 (90th percentile). This is an association with the covariate measured at the animal's location, not proof that forest_cover_pct causes the behaviour.
States are statistical summaries of movement; labels such as 'resting/foraging' or 'travelling' are interpretations that should be checked against independent observations.

Figures

Figure: Long-run share of time in each state if Forest cover (%) were held at the value on the x-axis, other covariates at their mean, over the daily cycle of the time-of-day effect.
stationary_forest_cover_pct. Long-run share of time in each state if Forest cover (%) were held at the value on the x-axis, other covariates at their mean, over the daily cycle of the time-of-day effect. Lines: maximum-likelihood estimates; bands: 95% and 50% confidence intervals. Rug: covariate values at the fixes.
Figure: State-dependent distributions, each weighted by the long-run share of time in that state (activity budget): (A) gamma step-length densities, (B) von Mises turning-angle densities.
state_distributions. State-dependent distributions, each weighted by the long-run share of time in that state (activity budget): (A) gamma step-length densities, (B) von Mises turning-angle densities. Lines: maximum-likelihood estimates; bands: 95% and 50% confidence intervals from 400 draws of the asymptotic sampling distribution. Grey histograms: observed steps and turns; thin black line: the mixture of the states.
Figure: Probability of switching from one behavioural state to another in one time step against time of day (clock time zone America/Los_Angeles), other covariates at their mean.
transition_tod. Probability of switching from one behavioural state to another in one time step against time of day (clock time zone America/Los_Angeles), other covariates at their mean. Lines: maximum-likelihood estimates; bands: 95% and 50% confidence intervals from the asymptotic sampling distribution. Colour shows the state the animal leaves.
Figure: Probability of being in each state at each clock hour over the daily cycle (periodically stationary distribution of the fitted time-of-day model; Koslik et al. 2025), habitat covariates at their mean…
stationary_tod. Probability of being in each state at each clock hour over the daily cycle (periodically stationary distribution of the fitted time-of-day model; Koslik et al. 2025), habitat covariates at their mean; clock time zone America/Los_Angeles. Points: the fix times, joined by lines (maximum-likelihood estimates); bands: 95% and 50% confidence intervals.
Figure: Probability of switching from one behavioural state to another in one time step against Forest cover (%), other covariates at their mean, averaged over the 24-h cycle.
transition_forest_cover_pct. Probability of switching from one behavioural state to another in one time step against Forest cover (%), other covariates at their mean, averaged over the 24-h cycle. Lines: maximum-likelihood estimates; bands: 95% and 50% confidence intervals from the asymptotic sampling distribution. Colour shows the state the animal leaves. Rug: covariate values at the fixes.
Figure: Tracks coloured by the most likely state sequence (Viterbi algorithm) for each animal; coordinates in km relative to the first fix; each segment takes the colour of the state at its start.
decoded_track. Tracks coloured by the most likely state sequence (Viterbi algorithm) for each animal; coordinates in km relative to the first fix; each segment takes the colour of the state at its start. Decoded states are point estimates that ignore state uncertainty.
Figure: Pseudo-residual checks (Zucchini et al. 2016): (A, B) normal QQ plots of step-length and turning-angle pseudo-residuals (points) against a reference line through the quartiles (red), which they follow if the model is correct…
pseudo_residuals. Pseudo-residual checks (Zucchini et al. 2016): (A, B) normal QQ plots of step-length and turning-angle pseudo-residuals (points) against a reference line through the quartiles (red), which they follow if the model is correct; (C) autocorrelation of step pseudo-residuals with 95% bounds for white noise (dashed). Systematic curvature or strong autocorrelation means the model misses structure (more states, or covariates on the step distributions).
Figure: Transition-probability coefficients on the multinomial-logit scale (log-odds of switching versus staying), per SD for continuous covariates (the SD in original units is given in the label): points are maximum-likelihood estimates…
coefficients. Transition-probability coefficients on the multinomial-logit scale (log-odds of switching versus staying), per SD for continuous covariates (the SD in original units is given in the label): points are maximum-likelihood estimates, thin and thick bars 95% and 50% confidence intervals; colour shows the state the animal leaves. 'Time of day (cos)' and '(sin)' are the coefficients of cos(2π h/24) and sin(2π h/24), h = local clock hour. Dashed line: no effect.

Limits that matter at this design

recovery meta

ItemValue
nsim200
converged200
median_fit_s45.4
coverage_bound0.904
passed15
total16
settingsfast_settings (4 starts)
configmodules/movement-hmm/example/recovery.yaml
noteTruth for intercepts and activity budgets is the mean over replicate landscapes (depends on mean forest cover).

Commands to reproduce

bin/ejob -c 4 -m 16 -t 0:30:00 -l logs/movement-hmm_si_selftest.log -- bin/Rscript core/run.R selftest movement-hmm --config modules/movement-hmm/example/recovery.yaml --nsim 4 --cores 4 --out dev/movement-hmm/si/selftest
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/movement-hmm_si_recover.log -- bin/Rscript core/run.R recover movement-hmm --config modules/movement-hmm/example/recovery.yaml --nsim 200 --cores 16 --out results/movement-hmm/si/recovery
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/movement-hmm_si_fit.log -- bin/Rscript core/run.R fit movement-hmm --config modules/movement-hmm/example/config.yaml --out results/movement-hmm/si/fit
bin/ejob -c 2 -m 8 -t 0:30:00 -l logs/movement-hmm_si_figs.log -- bin/Rscript core/run.R figures movement-hmm --fit results/movement-hmm/si/fit/movement-hmm_fit.rds --config modules/movement-hmm/example/config.yaml

Step-by-step walkthrough: modules/movement-hmm/example/WALKTHROUGH.md.

S1.25 movement-ssf: Habitat selection of GPS-collared elk: integrated step-selection analysis (iSSA), RSF and home ranges (simulated example)

DONE

Question

Do elk select forest and avoid high elevation as they move, how strongly, do individual elk differ, and how large are their summer home ranges?

What the researcher typed

I have GPS collar data from 10 elk (elk_gps_2024.csv, one row per fix attempt, fixes every 2 hours, coordinates in UTM zone 11N) and two habitat maps of my study area: forest_cover.tif (% canopy) and elevation.tif (m). Please tell me whether elk select forest and avoid high elevation as they move, how strong that is, whether individual elk differ, and how large their summer home ranges are.

Study design

ItemValue
n_animals10
steps_per_animal540
fix_interval_hours2
fix_attempts5410
failed_fixes410
failed_fix_rate0.076
used_steps_after_regularisation3918
available_steps_per_used20
covariatesforest cover (%), elevation (m)
landscape_km16 x 16, 50-m cells, EPSG:32611
time_jitter_s120
simulation_seed2024
fix_loss_seed99

True values used to simulate the example data

ItemValue
sel_forest_mean0.8
sel_elevation_mean-0.5
sel_forest_sd0.4
sel_elevation_sd0.3
rss_forest_per_sd2.225
rss_elevation_per_sd0.6065
rss_forest_per_unit1.38
rss_elevation_per_unit0.8
step_shape2
step_scale_m120
step_mean_m240
turn_kappa1
home_attraction_per_km20.25

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
home_attraction_per_km20.250.29390.17560.72–FAIL
rss_elevation_per_sd0.60650.61220.00940.935–PASS
rss_forest_per_sd2.2252.2270.00050.92–PASS
sel_elevation_mean-0.5-0.49990.00020.9350.955PASS
sel_elevation_sd0.30.2942-0.01930.97–PASS
sel_forest_mean0.80.7912-0.01090.921PASS
sel_forest_sd0.40.3837-0.04080.975–PASS
step_mean_m240240.30.00130.955–PASS
step_scale_m120120.30.00240.93–PASS
step_shape21.999-0.00050.93–PASS
turn_kappa11.0010.0010.955–PASS

Estimates from the example data

paramestimatelowerupper
sel_forest_mean0.77710.42171.133
sel_elevation_mean-0.5006-0.8126-0.1885
sel_forest_sd0.5330.30990.9166
sel_elevation_sd0.42040.22150.7981
rss_forest_per_sd2.1751.5253.103
rss_forest_per_unit1.3691.1861.58
rss_elevation_per_sd0.60620.44370.8282
rss_elevation_per_unit0.79650.69120.9179
step_shape2.0982.0112.189
step_scale_m116.9111.1123
step_mean_m245.2239.4251.2
turn_kappa1.0180.96331.073
home_attraction_per_km20.30630.24150.3711
rsf_forest_mean0.72330.48720.9595
rsf_elevation_mean-0.2707-0.56240.0211
rsf_forest_sd0.36970.2330.5867
rsf_elevation_sd0.4650.29660.7292
hr_akde_km2_E014.6533.5535.899
hr_akde_km2_E0216.719.24926.35
hr_akde_km2_E0312.417.76118.14
hr_akde_km2_E0432.0714.3156.86
hr_akde_km2_E0549.4617.3498.12
hr_akde_km2_E069.6086.20713.74
hr_akde_km2_E074.4223.3995.578
hr_akde_km2_E0817.019.74726.26
hr_akde_km2_E0927.1912.5647.39
hr_akde_km2_E1041.3313.3484.87

Convergence and goodness of fit

ItemValue
convergedyes
convergence_criterionglmmTMB convergence code 0, positive-definite Hessian, finite SEs (likelihood fit; no R-hat)
gps_rows5410
rows_without_coordinates410
used_steps3918
tentative_kernelgamma_shape = 2.09; gamma_scale_m = 111; vonmises_kappa = 0.91
uhc_heldout_strata784
uhcforest = observed_mean = 66.9; predicted_mean = 67.2; pi_lower = 66.6; pi_upper = 67.9; inside = yes; elevation = observed_mean = 1143; predicted_mean = 1142; pi_lower = 1139; pi_upper = 1146; inside = yes
akde_median_effective_n15
truth_coveredn = 12; covered = 11; missed = step_shape (2.10, 2.01-2.19 vs 2.00)

Interpretation from the report

Elk selected locations with higher forest cover at the scale of one 2-h step (selection coefficient 0.78 per SD, 95% CI 0.42 to 1.13).
Per 10 percentage points of forest cover, RSS = 1.37 (1.19 to 1.58).
Elk avoided locations with higher elevation at the scale of one 2-h step (selection coefficient -0.50 per SD, 95% CI -0.81 to -0.19).
Per 100 m of elevation, RSS = 0.80 (0.69 to 0.92).
Individuals differ: the among-animal SD of the selection coefficient is 0.53 (95% CI 0.31 to 0.92) on the log-RSS scale per SD, so an estimated 93% of elk in this population would show positive selection (log-RSS > 0) for forest cover.
The among-animal SD for elevation is 0.42 (95% CI 0.22 to 0.80), so an estimated 12% of elk in this population would show positive selection for elevation.
After removing the effect of habitat selection, the selection-free step length has mean 245 m (95% CI 239 to 251) per 2 h; the turn-angle concentration is 1.02 (95% CI 0.96 to 1.07), i.e. directional persistence.
Home ranges (95% AKDE, which accounts for autocorrelation): median 16.9 km^2 across 10 elk (range 4.4 to 49.5 km^2); median KDE 14.7 km^2 and MCP 11.6 km^2.
These are associations between where animals stepped and the mapped covariates, conditional on what was reachable; they are not proof that the covariate causes the choice.

Figures

Figure: Step-selection coefficients (log-RSS per 1 SD of each covariate; 1 SD of forest cover = 24.7 %; 1 SD of elevation = 220.0 m).
selection_coefficients. Step-selection coefficients (log-RSS per 1 SD of each covariate; 1 SD of forest cover = 24.7 %; 1 SD of elevation = 220.0 m). Diamond: population mean with 95% confidence interval; dots: individual elk (population mean plus the animal's conditional random slope) with approximate 95% intervals. Dashed line: no selection.
Figure: Relative selection strength (Avgar et al. 2017) for forest cover: how many times more likely an elk is to end a step at a location with the value on the x axis than at an equally reachable location with the landscape-average value…
rss_forest. Relative selection strength (Avgar et al. 2017) for forest cover: how many times more likely an elk is to end a step at a location with the value on the x axis than at an equally reachable location with the landscape-average value (55.9), other covariates equal. Line: population-level (typical elk) estimate; band: 95% confidence interval; log scale, so the line is the log-RSS; dashed line = no selection (RSS = 1). Curve spans the 1st-99th percentile of the covariate at used and available steps. Rug: covariate at a random sample of up to 400 used step ends.
Figure: Relative selection strength (Avgar et al. 2017) for elevation: how many times more likely an elk is to end a step at a location with the value on the x axis than at an equally reachable location with the landscape-average value…
rss_elevation. Relative selection strength (Avgar et al. 2017) for elevation: how many times more likely an elk is to end a step at a location with the value on the x axis than at an equally reachable location with the landscape-average value (1250.0), other covariates equal. Line: population-level (typical elk) estimate; band: 95% confidence interval; log scale, so the line is the log-RSS; dashed line = no selection (RSS = 1). Curve spans the 1st-99th percentile of the covariate at used and available steps. Rug: covariate at a random sample of up to 400 used step ends.
Figure: Movement kernel.
movement_kernel. Movement kernel. A: step length; B: turn angle (0 = straight ahead). Grey histograms: observed steps. Dashed: tentative gamma (step) and von Mises (turn) distributions fitted to the observed steps and used to draw available steps; solid: selection-free (updated) distributions, which remove the effect of habitat selection on observed movement (Avgar et al. 2016). Point estimates; step lengths above the 99th percentile are not shown.
Figure: Distribution (kernel density) of each covariate at used step ends (solid: observed GPS steps) and at available step ends (dashed: 20 per used step, drawn from the tentative movement kernel).
used_available. Distribution (kernel density) of each covariate at used step ends (solid: observed GPS steps) and at available step ends (dashed: 20 per used step, drawn from the tentative movement kernel). A shift of the used curve relative to the available curve is the raw signal of selection; the y scale differs between panels because covariate units differ.
Figure: Used-habitat calibration (Fieberg et al. 2018) on 784 strata (about 20% of steps) held out from fitting.
uhc. Used-habitat calibration (Fieberg et al. 2018) on 784 strata (about 20% of steps) held out from fitting. Grey: covariate distributions at steps chosen by the fitted model (one line per parameter draw, 50 of 200 draws shown); solid colour: observed used steps; dashed: available steps. A well-calibrated model has the observed used curve inside the grey envelope.
Figure: 95% autocorrelated kernel density (AKDE) home range of each elk (solid) with the 95% confidence contours of that home range (dotted); grey points are the elk's GPS fixes.
home_ranges. 95% autocorrelated kernel density (AKDE) home range of each elk (solid) with the 95% confidence contours of that home range (dotted); grey points are the elk's GPS fixes. All panels share the same scale. Coordinates in km (EPSG:32611).
Figure: 95% home-range area per elk: AKDE (circles) with 95% confidence interval (ctmm), and KDE with reference bandwidth (triangles) and MCP (squares)…
hr_area. 95% home-range area per elk: AKDE (circles) with 95% confidence interval (ctmm), and KDE with reference bandwidth (triangles) and MCP (squares), which assume independent fixes and typically underestimate area for autocorrelated GPS data. KDE and MCP have no interval.

Limits that matter at this design

recovery meta

ItemValue
nsim200
n_failed0
n_converged200
coverage_bound0.904
seconds_per_fit37
notehome_attraction_per_km2 is a nuisance term (VALIDATION.md Known limit 1) and is not interpreted; all 10 interpreted estimands pass.

Commands to reproduce

bin/ejob -c 1 -m 8 -- bin/Rscript dev/movement-ssf/make_example.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/movement-ssf_si_recover.log -- bin/Rscript core/run.R recover movement-ssf --config modules/movement-ssf/example/recovery.yaml --nsim 200 --cores 16 --out results/movement-ssf/si/recovery
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/movement-ssf_si_fit.log -- bin/Rscript core/run.R fit movement-ssf --config modules/movement-ssf/example/config.yaml --out results/movement-ssf/si/fit
bin/Rscript core/run.R figures movement-ssf --fit results/movement-ssf/si/fit/movement-ssf_fit.rds --config modules/movement-ssf/example/config.yaml

Step-by-step walkthrough: modules/movement-ssf/example/WALKTHROUGH.md.

Conservation genetics

S1.26 popgen-structure: Genetic diversity and population structure of coastal tailed frogs in eight Oregon Coast Range streams (simulated microsatellites)

DONE

Question

How genetically diverse is each stream population, is any population inbred or isolated, how differentiated are the streams and does differentiation grow with distance, and how many genetic groups are there?

What the researcher typed

I have microsatellite genotypes for coastal tailed frogs from 8 streams (tailed_frog_microsats.csv, two columns per locus, 0 means missing) and the stream coordinates (tailed_frog_sites.csv). Please tell me how genetically diverse each stream is, whether any population is inbred or isolated, how different the streams are and whether that increases with distance, and how many genetic groups there are. I don't code, so please give me a report with figures and explain what it means for management.

Study design

ItemValue
n_pops8
n_individuals_total200
n_ind_per_popNFSIU = 30; LOBST = 24; FIVEM = 28; DRIFT = 18; MARYS = 32; ALSEA = 26; YACHT = 22; SMITH = 20
n_loci12
markermicrosatellite
missing_rate_realised0.026
distance_range_km6.2, 80.8
ibd_distancelog

True values used to simulate the example data

ItemValue
NeNFSIU = 150; LOBST = 150; FIVEM = 120; DRIFT = 30; MARYS = 150; ALSEA = 150; YACHT = 120; SMITH = 100
immigrant_fraction_per_generationDRIFT = 0.004; others = 0.05
dispersal_kernel_km12
mu0.0005
n_alleles14
T_gen150
selfing0
Fst_global_census0.06457
Fst_global_design_weighted0.09902
Fst_global_expected0.0858
Fis_global_census-0.00419
He_mean_census0.6731
He_DRIFT_census0.2197
ibd_slope_census0.05838
ibd_slope_design_weighted0.06853
noteSIMULATED (dev/popgen-structure/gen_example.R, seed 2026). census = all 1040 frogs at the 12 typed loci; design_weighted = census allele frequencies with streams weighted as sampled (the target of WC84 theta); full table results/popgen-structure/si/true_values_with_design.csv

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
Fis_global-0.00012-2e-053.4140.9650.03PASS
Fst_global0.07570.081170.0720.931PASS
Fst_P1_vs_P20.046930.04649-0.00830.91–PASS
Fst_P1_vs_P80.099110.09751-0.01570.965–PASS
He_mean0.74280.7430.00040.925–PASS
Ho_mean0.74290.74310.00010.94–PASS
ibd_slope0.06910.06822-0.01160.9650.995PASS

Estimates from the example data

paramestimatelowerupper
Fst_global0.09430.07490.1138
Fis_global0.0028-0.02850.0341
He_mean0.67770.62720.7282
Ho_mean0.67940.61830.7405
He_DRIFT0.25620.12620.3863
He_NFSIU0.75460.6940.8152
AR_DRIFT2.8032.1673.439
Fis_DRIFT-0.0747-0.0994-0.05
Fst_DRIFT_vs_SMITH0.36610.27580.4564
Fst_DRIFT_vs_MARYS0.24260.15840.3268
Fst_FIVEM_vs_NFSIU0.0072-0.00380.0181
ibd_slope0.05660.02170.0916
Nm_island_model2.41.9463.089

Convergence and goodness of fit

ItemValue
convergencenot applicable (closed-form estimators); fit reports converged; 12 loci, 0 monomorphic
shared_individual_variance_share_median0.08
hwe_deviations0 of 94 population x locus tests (BH q < 0.05)
Fis_global0.0028, -0.0285, 0.0341
mantel_r0.17
mantel_p0.24
dapc_K2
amova_PhiST0.164
amova_p0.001
truth_inside_95CIdesign-weighted truth inside the interval for 54 of 57 quantities

Interpretation from the report

Overall differentiation among the 8 sampled populations is FST = 0.094 (95% CI 0.075 to 0.114) (Weir & Cockerham theta). The interval excludes 0, so the samples do not come from one randomly mating population.
Pairwise FST ranges from 0.007 (95% CI -0.004 to 0.018) between FIVEM and NFSIU to 0.366 (95% CI 0.276 to 0.456) between DRIFT and SMITH; 27 of 28 pairs have intervals excluding 0.
Genetic diversity: mean expected heterozygosity is 0.678 (95% CI 0.627 to 0.728). It is lowest in DRIFT (0.256 (95% CI 0.126 to 0.386)) and highest in NFSIU (0.755).
Within populations, FIS = 0.003 (95% CI -0.028 to 0.034). Genotype proportions are consistent with random mating within populations.
Isolation by distance: FST/(1-FST) increases by 0.0566 (95% CI 0.0217 to 0.0916) per unit of log distance; Mantel r = 0.17, permutation P = 0.240. The evidence is mixed. ... Do not conclude that differentiation increases with distance; re-run without DRIFT (or with more populations) to check.
Clustering without using population labels (k-means on principal components, number of clusters K chosen by BIC) found K = 2 genetic clusters for 8 sampled populations.
If the populations behaved like Wright's idealised island model at equilibrium, this FST would correspond to about 2.4 effective migrants per generation (range 1.9 to 3.1 across the FST interval). Treat this only as an order of magnitude.

Figures

Figure: Pairwise FST (Weir & Cockerham 1984 theta) between sampled populations; lighter = more differentiated.
fst_matrix. Pairwise FST (Weir & Cockerham 1984 theta) between sampled populations; lighter = more differentiated. Cell labels give the estimate (leading zero dropped); 95% confidence intervals for every pair are in the estimates table (Fst_<pop1>_vs_<pop2>).
Figure: Genetic diversity per population: observed (Ho) and expected (He, Nei's unbiased gene diversity) heterozygosity and allelic richness rarefied to 32 gene copies.
diversity. Genetic diversity per population: observed (Ho) and expected (He, Nei's unbiased gene diversity) heterozygosity and allelic richness rarefied to 32 gene copies. Points are estimates averaged over loci; bars are 95% confidence intervals (estimate +/- t(L-1) x SE; SE from a jackknife over loci plus the shared-individual covariance).
Figure: Isolation by distance: pairwise FST/(1-FST) against geographic (log axis) distance (points = population pairs).
ibd. Isolation by distance: pairwise FST/(1-FST) against geographic (log axis) distance (points = population pairs). Line: least-squares fit (slope 0.0566, 95% CI 0.0217 to 0.0916 per unit log distance); band: 95% confidence band (jackknife over loci plus shared-individual covariance). Mantel r = 0.17, P = 0.240.
Figure: Principal component analysis of individual genotypes (centred allele frequencies, missing values replaced by the mean).
pca. Principal component analysis of individual genotypes (centred allele frequencies, missing values replaced by the mean). Each point is one individual; colour and symbol show the sampled population; percentages are the share of genetic variance on each axis.
Figure: BIC of k-means clustering on principal components for K = 1 to 16 clusters; the large orange point is the chosen K (2), from adegenet's 'diffNgroup' rule.
bic_k. BIC of k-means clustering on principal components for K = 1 to 16 clusters; the large orange point is the chosen K (2), from adegenet's 'diffNgroup' rule. A clear minimum or elbow indicates well-separated clusters; a flat curve indicates weak or continuous structure.
Figure: DAPC membership probabilities (one bar per individual, grouped by sampled population) for the K = 2 clusters found by k-means, using 1 principal component(s) (K - 1; Thia 2023).
dapc_assignment. DAPC membership probabilities (one bar per individual, grouped by sampled population) for the K = 2 clusters found by k-means, using 1 principal component(s) (K - 1; Thia 2023). A cluster made up mainly of one sampled population takes that population's colour (as in the PCA); a cluster shared by several populations is grey.
Figure: Sampled populations (longitude/latitude in decimal degrees): point fill = expected heterozygosity (He, Nei's unbiased gene diversity), point size = number of individuals genotyped.
sample_map. Sampled populations (longitude/latitude in decimal degrees): point fill = expected heterozygosity (He, Nei's unbiased gene diversity), point size = number of individuals genotyped. He intervals are in the diversity figure.

Limits that matter at this design

recovery notes

ItemValue
cli_gatecore/run.R recover with example/recovery.yaml (module simulator, 2-D stepping stone matched to the design), nsim 200, 0 failed, 7/7 PASS, coverage bound 0.904
exact_processdev/popgen-structure/si/si_design_truth.R: exact generating process (stream map, isolated DRIFT), 200 histories, truth design-weighted; 52/57 PASS, all |rel bias| < 6%; misses: Fst_ALSEA_vs_SMITH (coverage 0.89); Fst_FIVEM_vs_MARYS (coverage 0.9); Fst_LOBST_vs_FIVEM (coverage 0.9); Fst_LOBST_vs_SMITH (coverage 0.895); He_SMITH (coverage 0.885)
exact_process_key_rowsparam = Fis_global; truth = 2e-05; mean_est = 0.00032; rel_bias = -0.8403; coverage = 0.96; power = 0.045; pass = yes, param = Fst_DRIFT_vs_SMITH; truth = 0.2783; mean_est = 0.2813; rel_bias = 0.0101; coverage = 0.945; power = –; pass = yes, param = Fst_global; truth = 0.07162; mean_est = 0.07219; rel_bias = 0.0077; coverage = 0.97; power = 1; pass = yes, param = Fst_NFSIU_vs_DRIFT; truth = 0.2392; mean_est = 0.2426; rel_bias = 0.0148; coverage = 0.96; power = –; pass = yes, param = Fst_NFSIU_vs_FIVEM; truth = 0.02098; mean_est = 0.02148; rel_bias = 0.0239; coverage = 0.93; power = –; pass = yes, param = He_mean; truth = 0.661; mean_est = 0.6631; rel_bias = 0.0032; coverage = 0.935; power = –; pass = yes, param = Ho_mean; truth = 0.6612; mean_est = 0.6632; rel_bias = 0.0031; coverage = 0.945; power = –; pass = yes, param = ibd_slope; truth = 0.04448; mean_est = 0.0453; rel_bias = 0.0189; coverage = 0.97; power = 0.99; pass = yes
census_weighted_truthAgainst census-weighted truth global FST rel bias +47%, coverage 0.240 (si_exact_recovery.R): the estimator weights populations by sample size, not census size

Commands to reproduce

bin/ejob -c 2 -m 8 -t 0:30:00 -l logs/popgen-structure_si_truth.log -- bin/Rscript dev/popgen-structure/si/si_truth.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/popgen-structure_si_recover.log -- bin/Rscript core/run.R recover popgen-structure --config modules/popgen-structure/example/recovery.yaml --nsim 200 --cores 16 --out results/popgen-structure/si/recovery
bin/ejob -c 16 -m 32 -t 1:00:00 -l logs/popgen-structure_si_design.log -- bin/Rscript dev/popgen-structure/si/si_design_truth.R 200 16
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/popgen-structure_si_fit.log -- bin/Rscript core/run.R fit popgen-structure --config modules/popgen-structure/example/config.yaml --out results/popgen-structure/si/fit

Step-by-step walkthrough: modules/popgen-structure/example/WALKTHROUGH.md.

S1.27 popgen-ne: Effective population size and relatedness of a bull trout spawning population from two microsatellite samples (simulated data with known truth)

OPEN Planted truth at this design: temporal het_loss (+1.6%, coverage 0.92) and full-sib relatedness (LR -2.1%, QG +3.9%) PASS; single-sample LD het_loss FAILS the 10% bias rule in both years (-13.1%, -11.5%; Ne overstated ~15%) because each sample is 42% of the population. Report temporal Ne 122 (55-407) as the answer; LD estimates are supporting, upward-leaning evidence only.

Question

How large is the genetically effective population (Ne) of the Upper Elk Creek bull trout, how fast is it losing heterozygosity, and can 16 microsatellites identify close relatives?

What the researcher typed

I have microsatellite genotypes for bull trout from Upper Elk Creek in bulltrout_microsats.csv: 50 adults sampled in 2014 and 50 in 2024, 16 loci, two columns per locus, 0 = missing. There are also 12 juveniles from 2024, two from each of six redds; known_relationships.csv lists the nest-mate pairs. Generation time is about 5 years and redd counts suggest about 120 adults. Please estimate the effective population size and how fast the population is losing genetic diversity, and tell me whether the markers can identify relatives. I'd like a report with figures for a paper.

Study design

ItemValue
speciesbull trout (Salvelinus confluentus)
populationUpper Elk Creek
markermicrosatellite
n_loci16
alleles_per_locus_observed5-9
n_samples2
sample_years2014, 2024
adults_per_sample50
juveniles_known_fullsib12
known_fullsib_pairs6
total_individuals112
missing_genotype_rate0.032
generation_time_years5
generations_between2
census_N_first_sample120
sampling_planI
pcrit0.02
formattwo_column

True values used to simulate the example data

ItemValue
Ne120
het_loss_per_generation0.004167
census_N120
generations_between2
relatedness_fullsib_realised0.4647
relatedness_fullsib_expected0.5
seed2024
allele_label_seed7
generatordev/popgen-ne/make_example.R
checkdev/popgen-ne/si_truth.R (byte-for-byte identical)

Planted-truth recovery at this design

paramtruthmean_estrel_biasbias_mcse_relcoveragepowerpass
het_loss_LD_early0.0041670.003619-0.13140.01760.960.925FAIL
het_loss_LD_late0.0041670.003688-0.11490.01830.9550.925FAIL
het_loss_temporal0.0041670.0042340.01620.0340.920.835PASS
relatedness_fullsib_LR0.46940.4593-0.02130.01020.975–PASS
relatedness_fullsib_QG0.46940.48730.03880.00860.96–PASS

Estimates from the example data

paramestimatelowerupper
Ne_LD_UpperElkCreek_2014120.674.41270.5
het_loss_LD_UpperElkCreek_20140.004140.001850.00672
Ho_UpperElkCreek_20140.760.70920.8109
He_UpperElkCreek_20140.78170.76230.8011
FIS_UpperElkCreek_20140.02772-0.025880.08133
Ne_LD_UpperElkCreek_2024138.676500.2
het_loss_LD_UpperElkCreek_20240.003610.0010.00658
Ho_UpperElkCreek_20240.77360.73820.809
He_UpperElkCreek_20240.77640.74980.803
FIS_UpperElkCreek_20240.00356-0.024790.0319
Ne_temporal12255.38406.6
het_loss_temporal0.00410.001230.00903
Ne_temporal_NT127.265.09327.5
het_loss_temporal_NT0.003930.001530.00768
Ne_temporal_Pollak123.863.86310.9
het_loss_temporal_Pollak0.004040.001610.00783
relatedness_fullsib_QG0.51570.37950.6519
relatedness_fullsib_LR0.49440.29550.6933

Convergence and goodness of fit

ItemValue
numericalconverged; all estimates and CIs finite, no boundary values (moment estimators, no MCMC)
FIS_2014estimate = 0.0277; lower = -0.0259; upper = 0.0813
FIS_2024estimate = 0.0036; lower = -0.0248; upper = 0.0319
hwe_checkF_IS CI includes 0 in both years: consistent with random mating
known_fullsib_r_LRestimate = 0.494; lower = 0.296; upper = 0.693; expected = 0.5
pcrit_sensitivity_LD_NeUpperElkCreek_2014 = 64.3, 177; UpperElkCreek_2024 = 137, 191
temporal_estimator_agreementJordeRyman = 122; NeiTajima = 127.2; Pollak = 123.8
kin_misclassificationunrelated_called_kin_2014 = 0.057; unrelated_called_kin_2024 = 0.07; fullsib_correct = 0.8; halfsib_correct = 0.46

Interpretation from the report

Temporal method (2014 and 2024, 2.0 generations apart, sampling plan I, census N = 120): Jorde & Ryman's Fs' = 0.0082 gives Ne = 122 (95% CI 55.4 to 407). Nei-Tajima and Pollak estimators give 127 and 124.
Sample 2014 (50 individuals, 16 loci): the linkage-disequilibrium estimate of Ne is 121 (95% CI 74.4 to 271). An Ne of this size loses about 0.41% of its heterozygosity per generation, about 4.1% over 10 generations, unless immigration or mutation replaces it.
Sample 2024: the linkage-disequilibrium estimate of Ne is 139 (95% CI 76.0 to 500).
The interval lies above 50 but reaches below 100: the population passes the classic short-term threshold (50) but not clearly the revised one (100; Frankham et al. 2014).
Relatedness in sample 2024 (1891 pairs): 15 pairs have r >= 0.354 (likely first-degree) and 86 have 0.177 <= r < 0.354 (likely second-degree); about 7.0% of truly unrelated pairs would be called second-degree or closer; 80% of full sibs and 46% of half sibs fall in their own class.
Known fullsib pairs (n = 6) have mean r = 0.494 (95% CI 0.296 to 0.693), against a pedigree expectation of 0.50.
F_IS = 0.028 (95% CI -0.026 to 0.081) in 2014 and 0.004 (-0.025 to 0.032) in 2024: consistent with random mating.
Ne is not census size; with separate sexes LD estimates ran about 5-25% above the true Ne in validation, whereas the temporal estimate was within 6%; treat a single LD estimate as slightly optimistic.

Figures

Figure: Effective population size by sample and method, with 95% confidence intervals (LD: jackknife over individuals; Jorde-Ryman: jackknife over loci; Nei-Tajima and Pollak: chi-square).
ne_estimates. Effective population size by sample and method, with 95% confidence intervals (LD: jackknife over individuals; Jorde-Ryman: jackknife over loci; Nei-Tajima and Pollak: chi-square). Colour and symbol show the method. Dashed lines: 50 and 500 (Franklin 1980); dotted lines: the revised 100 and 1,000 (Frankham et al. 2014). An arrow (>) marks an infinite upper limit; infinite point estimates are drawn at the right edge.
Figure: Sensitivity of the LD estimate of Ne to the minimum allele frequency Pcrit, with 95% jackknife confidence intervals (points: estimates; one line per sample).
ne_by_maf. Sensitivity of the LD estimate of Ne to the minimum allele frequency Pcrit, with 95% jackknife confidence intervals (points: estimates; one line per sample). Rare alleles inflate LD estimates when Pcrit is too low (Waples & Do 2010). Values at the top ('infinite') have an infinite estimate or limit.
Figure: Distribution of pairwise relatedness among sampled pairs of unknown relationship (bars), one panel per sample.
relatedness_distribution. Distribution of pairwise relatedness among sampled pairs of unknown relationship (bars), one panel per sample. Grey dashed lines: pedigree expectations for unrelated (0), half-sib (0.25) and full-sib/parent-offspring (0.5) pairs; Red lines: thresholds used to call second- (r >= 0.177) and first-degree (r >= 0.354) relatives. Ticks below the axis: pairs of known relationship (Full-sib).
Figure: How well these markers separate relationship classes: densities of relatedness estimates for pairs simulated from the sample's allele frequencies (unlinked loci, Hardy-Weinberg), by true class.
kin_resolution. How well these markers separate relationship classes: densities of relatedness estimates for pairs simulated from the sample's allele frequencies (unlinked loci, Hardy-Weinberg), by true class. Overlap between classes is the misclassification rate; red lines are the calling thresholds (0.177 and 0.354).
Figure: Putative close kin: 35 individuals (points, on a circle) joined when their estimated relatedness is at least 0.354 (first-degree relatives only; second-degree links were too many to draw).
kin_network. Putative close kin: 35 individuals (points, on a circle) joined when their estimated relatedness is at least 0.354 (first-degree relatives only; second-degree links were too many to draw). Line width is proportional to r. All samples are drawn together. Check the misclassification rates (kin_resolution) before acting on single links.
Figure: Precision of the LD estimate by design, from simulated Wright-Fisher populations (ecotools validation, microsatellites): coefficient of variation of 1/Ne (the quantity LDNe estimates nearly without bias) against the number of…
design_precision. Precision of the LD estimate by design, from simulated Wright-Fisher populations (ecotools validation, microsatellites): coefficient of variation of 1/Ne (the quantity LDNe estimates nearly without bias) against the number of individuals sampled, for several numbers of loci (colour, symbol, line type) and true Ne (panels). Dotted lines: CV 0.2 and 0.5. Red dashed line: this study's sample size (50 individuals, 16 loci after filtering).

Limits that matter at this design

recovery meta

ItemValue
nsim200
failed0
converged200/200
coverage_bound0.904
sec_per_fit0.2
configmodules/popgen-ne/example/recovery.yaml
noterelatedness truth in recovery is the per-replicate realised pedigree relatedness (mean 0.469). LD het_loss bias -13.1%/-11.5% (MC SE 1.8%) means Ne overstated ~15% (harmonic mean ~137 vs 120); S/N = 50/120.

Commands to reproduce

bin/ejob -c 1 -m 4 -t 0:20:00 -l logs/popgen-ne_si_truth.log -- bin/Rscript dev/popgen-ne/si_truth.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/popgen-ne_si_recover.log -- bin/Rscript core/run.R recover popgen-ne --config modules/popgen-ne/example/recovery.yaml --nsim 200 --cores 16 --out results/popgen-ne/si/recovery
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/popgen-ne_si_fit.log -- bin/Rscript core/run.R fit popgen-ne --config modules/popgen-ne/example/config.yaml --out results/popgen-ne/si/fit

Step-by-step walkthrough: modules/popgen-ne/example/WALKTHROUGH.md.

Fisheries

S1.28 fisheries-growth: Do female and male walleye differ in growth and condition? (simulated autumn 2014 gill-net survey)

DONE

Question

Do females and males differ in how large they get, how fast they grow, and in condition (weight at length)?

What the researcher typed

I have age, length, weight and sex for 1,000 walleye from an October 2014 gill-net survey (sim_walleye_2014.csv). Do females and males differ in growth and in condition? I'd like a report and figures I can put in a paper (CJFAS format).

Study design

ItemValue
n_groups2
groupsfemale (reference), male
n_female530
n_male470
n_fish1000
otolith_age_range1, 16
age_offset_years0.5
total_mortality_Z0.55
prop_weighed1
years1
errormultiplicative (lognormal)
enginenls (Kimura LRT)

True values used to simulate the example data

ItemValue
Linf_female680
K_female0.31
t0_female-1
age_at_90pct_Linf_female6.428
Linf_male560
K_male0.39
t0_male-1.1
age_at_90pct_Linf_male4.804
Linf_diff_male_vs_female-120
K_diff_male_vs_female0.08
t0_diff_male_vs_female-0.1
condition_ratio_male_vs_female1.02
residual_sd0.05
lw_b3.34
lw_a1.2e-06
lw_residual_sd0.09
mean_weight_at_500_female1246

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
age_at_90pct_Linf_female6.4286.4650.005790.94–PASS
age_at_90pct_Linf_male4.8044.801-0.000630.94–PASS
condition_ratio_male_vs_female1.021.02-0.000320.9450.925PASS
K_female0.310.3092-0.002450.93–PASS
K_male0.390.39180.004530.965–PASS
K_diff_male_vs_female0.080.082530.031590.9350.805PASS
Linf_female6806810.001510.95–PASS
Linf_male560559.5-0.000920.945–PASS
Linf_diff_male_vs_female-120-121.5-0.012890.9551PASS
lw_a1.2e-061.198e-06-0.001340.96–PASS
lw_b3.343.3410.000290.965–PASS
lw_residual_sd0.090.08968-0.00360.94–PASS
mean_weight_at_500_female124612460.000210.955–PASS
residual_sd0.050.050060.001130.93–PASS
t0_female-1-1.006-0.006340.925–PASS
t0_male-1.1-1.102-0.001950.96–PASS
t0_diff_male_vs_female-0.1-0.095810.041920.930.095PASS

Estimates from the example data

paramestimateloweruppertruth
Linf_female685.1664.9706680
K_female0.30160.27160.33510.31
t0_female-1.036-1.21-0.8625-1
age_at_90pct_Linf_female6.5975.9597.2356.428
Linf_male560.9547575.3560
K_male0.38520.33930.43740.39
t0_male-1.137-1.381-0.8919-1.1
age_at_90pct_Linf_male4.8414.3155.3674.804
Linf_diff_male_vs_female-124.2-149.1-99.24-120
K_diff_male_vs_female0.083570.025270.14190.08
t0_diff_male_vs_female-0.1002-0.40050.2001-0.1
residual_sd0.050440.048320.052760.05
lw_b3.343.3083.3723.34
lw_a1.192e-069.802e-071.448e-061.2e-06
lw_residual_sd0.09010.086310.094230.09
mean_weight_at_500_female1240122912501246
condition_ratio_male_vs_female1.0211.0091.0331.02

Convergence and goodness of fit

ItemValue
optimiser_convergedyes
optimiser_messagerelative convergence (4)
all_se_finiteyes
growth_residual_sd0.0503
growth_residual_mean0
growth_resid_loess_max_abs0.0052
growth_resid_shapiro_p0.158
lw_resid_shapiro_p0.122
lw_common_slope_F0.001
lw_common_slope_df1, 996
lw_common_slope_p0.974
lw_outliers_gt4sdSIM14-F-0433 (4.3 SD; chance value in simulated data, kept)
kimuracommon_Linf = chisq = 81.7; df = 1; p = 1.6e-19; common_K = chisq = 8.25; df = 1; p = 0.0041; common_t0 = chisq = 0.43; df = 1; p = 0.51; all_common = chisq = 448.5; df = 3; p = 7e-97
Wr_meanfemale = 90.2, 89.5, 91; male = 91.1, 90.4, 91.9
old_fish_beyond_age90female = 19; male = 54
rhat_essnot applicable (likelihood fit)

Interpretation from the report

female: fish approach an asymptotic length (Linf) of 685 mm (95% CI 665 to 706) and grow toward it at K = 0.302 (95% CI 0.272 to 0.335) per year. They reach 90% of Linf (about 617 mm) at age 6.6 (95% CI 6.0 to 7.2) years.
male: fish approach an asymptotic length (Linf) of 561 mm (95% CI 547 to 575) and grow toward it at K = 0.385 (95% CI 0.339 to 0.437) per year. They reach 90% of Linf (about 505 mm) at age 4.8 (95% CI 4.3 to 5.4) years.
Linf in male is smaller than in female by 124 mm (95% CI 99 to 149). K in male is larger than in female by 0.084 per year (95% CI 0.025 to 0.142).
Kimura (1980) likelihood-ratio tests: common linf chi-square = 81.7, df = 1, p < 0.0001; common k chi-square = 8.3, df = 1, p = 0.0041; common t0 chi-square = 0.4, df = 1, p = 0.51; all parameters common chi-square = 448.5, df = 3, p < 0.0001.
Length-weight (1000 weighed fish): W = 1.19e-06 x L^3.340, with b 95% CI 3.308 to 3.372; this is positive allometry.
At the same length, fish in male weigh 2.1% more than fish in female (95% CI +0.9% to +3.3%).
Relative weight Wr by group: female 90.2 (95% CI 89.5-91.0, n = 530); male 91.1 (95% CI 90.4-91.9, n = 470).

Figures

Figure: Length at age with the fitted von Bertalanffy curve per group (line: median length at age, drawn over each group's observed ages), 95% confidence band for the curve (shaded) and 95% prediction interval for individual fish (dotted).
growth_curves. Length at age with the fitted von Bertalanffy curve per group (line: median length at age, drawn over each group's observed ages), 95% confidence band for the curve (shaded) and 95% prediction interval for individual fish (dotted). Points are individual fish (ages jittered).
Figure: Growth parameters by group (panel titles give units): estimate with 95% Wald confidence interval.
parameter_comparison. Growth parameters by group (panel titles give units): estimate with 95% Wald confidence interval. Linf, K and t0 are strongly correlated; compare whole curves and age at 90% Linf rather than one parameter alone.
Figure: Growth-model residuals (log observed minus log fitted length).
residuals. Growth-model residuals (log observed minus log fitted length). A: against fitted length; points are individual fish, line is a loess smooth (a trend means the curve shape is wrong). B: by age; boxes show median and quartiles, whiskers 1.5 x IQR (boxes should centre on zero with similar spread; a funnel means the error model is wrong). Ages with one fish appear as a single bar.
Figure: Length-weight relationship on log-log axes: mean weight at length (bias-corrected back-transform; line, drawn over each group's observed lengths) with 95% confidence band, common slope b = 3.340 with group-specific intercepts.
length_weight. Length-weight relationship on log-log axes: mean weight at length (bias-corrected back-transform; line, drawn over each group's observed lengths) with 95% confidence band, common slope b = 3.340 with group-specific intercepts. Points are weighed fish.
Figure: Relative weight Wr by group: mean (large symbol) with 95% confidence interval (vertical line; may be shorter than the symbol when n is large; n = 530, 470 fish).
condition. Relative weight Wr by group: mean (large symbol) with 95% confidence interval (vertical line; may be shorter than the symbol when n is large; n = 530, 470 fish). Small points are individual fish. Dashed line: Wr = 100, the standard weight for the fish's length (Walleye standard weight equation (Murphy et al. (1990), RLP method; via FSA::wsVal)).

Limits that matter at this design

recovery settings

ItemValue
nsim200
n_failed0
n_converged200
gatePASS for all 17 quantities
seconds_per_fit~0.2

Commands to reproduce

bin/ejob -c 1 -m 4 -t 0:10:00 -l logs/fisheries-growth_si_make.log -- bin/Rscript dev/fisheries-growth/make_si_example.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/fisheries-growth_si_recover.log -- bin/Rscript core/run.R recover fisheries-growth --config modules/fisheries-growth/example/recovery.yaml --nsim 200 --cores 16 --out results/fisheries-growth/si/recovery
bin/ejob -c 4 -m 16 -t 2:00:00 -l logs/fisheries-growth_si_fit.log -- bin/Rscript core/run.R fit fisheries-growth --config modules/fisheries-growth/example/config_si.yaml --out results/fisheries-growth/si/fit

Step-by-step walkthrough: modules/fisheries-growth/example/WALKTHROUGH.md.

S1.29 fisheries-stock: Walleye catch curve: total annual mortality from fall gill-net ages (simulated)

DONE Every interpreted estimand (Z, annual survival and annual mortality from the default Bayesian catch curve) passes planted-truth recovery at this design (bias +1.0%, -0.2%, +0.3%; coverage 0.960 vs bound 0.904; 200/200 converged); the real-data fit converged (R-hat 1.001, ESS 2,901); the overdispersion found by the goodness-of-fit check (c-hat 2.97) is the year-class variability the model includes; the likelihood GLMM agrees; negative controls fail as intended. Chapman-Robson (coverage 0.850) and the weighted regression (0.900) still fail coverage and are reported only as cross-checks, not interpreted. Independent verification (VALIDATION.md section 6, own simulator, 4 single-year designs at Z 0.4/0.9 with 200/600 fish) confirmed the Bayesian default passes when aged fish are a simple random sample (bias +1.6% to +5.3%, coverage 0.953-0.983). The example data were simulated that way; real gill-net ages come from net sets, and with cluster sampling (20 hauls, intra-haul correlation 0.2) the Bayesian Z was biased +15% (fails), so for real data compare the Bayesian, GLMM and Chapman-Robson estimates.

Question

What is the total annual mortality (and survival) of adult walleye in the lake?

What the researcher typed

Here are otolith ages from our fall walleye gill-net survey (walleye_fall_gillnet_ages.csv). I want to know the total annual mortality and survival of adult walleye. Please do the analysis and give me a report with figures I can use.

Study design

ItemValue
modelcatch_curve
n_fish_sampled350
n_fish_aged348
ages_observed1-13
max_age20
basins2
gearexperimental gill net

True values used to simulate the example data

ItemValue
Z0.55
annual_survival0.577
annual_mortality0.423
recruit_sd_cc0.4
sel_age502.2
sel_slope3

Planted-truth recovery at this design

paramtruthmean_estrel_biascoveragepowerpass
annual_mortality0.42310.42450.00330.96–PASS
annual_survival0.57690.5755-0.00240.96–PASS
total_mortality_Z0.550.55580.01050.96–PASS
Z_bayes0.550.55580.01050.96–PASS
Z_glmm0.550.5372-0.02320.93–PASS
Z_chapman_robson0.550.5249-0.04560.85–FAIL
Z_weighted_regression0.550.547-0.00540.9–FAIL

Estimates from the example data

paramestimatelowerupper
total_mortality_Z0.5260.38760.7392
annual_survival0.59090.47750.6787
annual_mortality0.40910.32130.5225
Z_bayes0.5260.38760.7392
Z_glmm0.50350.34510.6619
Z_chapman_robson0.49710.32950.6646
Z_weighted_regression0.52640.32810.7248
yearclass_sd0.54070.16371.243

Convergence and goodness of fit

ItemValue
convergenceBayesian catch curve (primary): 3 chains x 40,000 iterations (10,000 burn-in, thin 10); R-hat 1.001, minimum bulk ESS 2,901 (Z and year-class SD); traces overlap
recovery_reps_ok200/200
chat_chapman_robson2.97
pearson_chisq23.8
pearson_df8
pearson_p0.002
yearclass_sd_posterior0.54 (95% CI 0.16-1.24) on the log scale
ages_used_regression3-13 (10 nonzero ages)
ages_used_chapman_robson4-13 (n = 142)
ages_used_bayes_glmm4-13 plus zero catches at ages 14-18
recovery_mean_reported_sd_Z0.084
recovery_empirical_sd_Z0.083
independent_routeglmmTMB GLMM (REML + t): Z = 0.50 (0.35-0.66) vs Bayesian 0.53 (0.39-0.74)
negative_controlsunmodelled recruitment trend: Bayes +32% bias, coverage 0.455 (FAIL as intended); year-class SD forced to 0: coverage 0.650 (FAIL as intended)

Interpretation from the report

Total instantaneous mortality of fully recruited walleye (ages 4 and older) is Z = 0.53 per year (95% credible interval 0.39 to 0.74; Bayesian Poisson-lognormal catch curve).
Equivalently, about 59% (48% to 68%) of fully recruited fish survive each year and 41% (32% to 52%) die from all causes combined (fishing plus natural mortality).
For comparison, the other estimators give Z = 0.50 (0.33 to 0.66; Chapman-Robson); Z = 0.53 (0.33 to 0.72; weighted regression); Z = 0.50 (0.35 to 0.66; Poisson-lognormal GLMM).
The intervals of Chapman-Robson, weighted regression and Poisson-lognormal GLMM were too narrow (below the 95% coverage limit) in some of this module's simulations with variable year classes (VALIDATION.md), so they are shown only as a cross-check of the estimate.
All estimators agree within their uncertainty.
Real fish populations have strong and weak year classes, so the counts at age scatter around the straight line.
Here the scatter is much larger than what constant recruitment would give (Chapman-Robson c-hat = 2.97); the estimated year-class SD is 0.54 on the log scale, i.e. a typical year class is about 72% stronger or 42% weaker than average.
The Bayesian Poisson-lognormal catch curve treats each year class as a random draw and carries that variability into its interval; in this module's simulations with variable year classes its 95% intervals covered the true Z in 95-98% of samples, as they should.
A catch curve assumes no trend in recruitment over the year classes sampled, constant mortality over the ages used and full, equal vulnerability of every age from the first age used onwards.
It also assumes the aged fish are a random sample of the population's fully recruited fish.
If the fish came from a few net sets, hauls or sites that each caught a different mix of ages (cluster sampling), the age composition is noisier than the model allows: in this module's verification with 20 hauls the default Bayesian Z was biased +8% (intra-haul correlation 0.1) to +15% (correlation 0.2, which fails the module's 10% bias limit), the GLMM +2% to +8% and Chapman-Robson -2% to -3%, so with such data treat the Bayesian Z as possibly too high and compare it with the GLMM and Chapman-Robson estimates (Nelson 2019).
Z mixes fishing and natural mortality; separating them needs an independent estimate of natural mortality M (F = Z - M).

Figures

Figure: Number of walleye caught at each age (log scale).
catch_curve. Number of walleye caught at each age (log scale). Filled circles = ages used by Chapman-Robson, the GLMM and the Bayesian model; open square = regression only; crosses = not fully recruited (ages 1-2). Solid line: Chapman-Robson (Z = 0.50); dashed line and band: weighted regression with 95% confidence band (Z = 0.53); dotted line: Bayesian primary estimate for an average year class (Z = 0.53).
Figure: Total mortality Z (per year) with 95% intervals from Chapman-Robson, weighted regression, the Poisson-lognormal GLMM (REML + t) and the Bayesian catch curve; dashed line = primary (Bayesian) estimate.
mortality_estimates. Total mortality Z (per year) with 95% intervals from Chapman-Robson, weighted regression, the Poisson-lognormal GLMM (REML + t) and the Bayesian catch curve; dashed line = primary (Bayesian) estimate.
Figure: MCMC traces of Z and the year-class SD for the three chains of the Bayesian catch curve.
trace. MCMC traces of Z and the year-class SD for the three chains of the Bayesian catch curve.

Limits that matter at this design

Commands to reproduce

bin/ejob -c 1 -m 4 -t 0:20:00 -l logs/fisheries-stock_si_make.log -- bin/Rscript dev/fisheries-stock/make_examples.R
bin/ejob -c 16 -m 32 -t 3:00:00 -l logs/fisheries-stock_si_recover.log -- bin/Rscript core/run.R recover fisheries-stock --config modules/fisheries-stock/example/recovery.yaml --nsim 200 --cores 16 --out results/fisheries-stock/si/recovery
bin/ejob -c 4 -m 16 -t 1:00:00 -l logs/fisheries-stock_si_fit.log -- bin/Rscript core/run.R fit fisheries-stock --config modules/fisheries-stock/example/config.yaml --out results/fisheries-stock/si/fit

Step-by-step walkthrough: modules/fisheries-stock/example/WALKTHROUGH.md.