Dataslope logoDataslope

Capstone Simulation

A complete predator–prey + parameter-sweep mini-project tying it all together

This capstone is a complete scientific computing project compressed into a single page. We will:

  • Build a multi-file simulation of a Lotka–Volterra predator–prey ecosystem
  • Solve the ODE with solve_ivp and detect extinction events
  • Run a parameter sweep over predation rates
  • Visualize with small multiples and a phase portrait
  • Quantify uncertainty by repeating with multiple seeds

By the end you will have used every skill from the course in a single, coherent workflow.

The model

A classic Lotka–Volterra system with logistic prey growth:

x˙=rx(1x/K)axyy˙=eaxymy\begin{aligned} \dot x &= r\,x\,(1 - x/K) - a\,x\,y \\ \dot y &= e\,a\,x\,y - m\,y \end{aligned}
  • xx = prey population (e.g. rabbits)
  • yy = predator population (e.g. foxes)
  • rr = prey intrinsic growth rate
  • KK = prey carrying capacity
  • aa = attack rate (how often predators catch prey)
  • ee = conversion efficiency
  • mm = predator mortality

Pipeline overview

The simulation module

Code Block
Python 3.13.2

What this little project demonstrates:

  • Modeling. Translating a biological story into a system of ODEs with parameters that have physical meaning.
  • Stable numerical integration. Using solve_ivp with dense_output and max_step to get smooth, controllable output.
  • Event detection. Catching the extinction moment exactly.
  • Reproducible stochasticity. A per-run default_rng(seed) so every replicate is exactly repeatable.
  • Parameter sweeps. A clean loop over a grid of attack rates and seeds.
  • Aggregation. Grouping replicates and computing summary statistics.
  • Visualization. Small multiples that let your eye compare parameter regimes at a glance.

A phase portrait

The classical way to look at a predator–prey system is in phase space — predator on one axis, prey on the other. Closed orbits mean sustained oscillations; spirals mean damped or growing oscillations; runaway escape means extinction.

Code Block
Python 3.13.2

Different starting populations spiral into the same equilibrium — a behavior driven entirely by the prey's logistic carrying capacity. Without that term the orbits would be perfect closed loops (the classic Lotka–Volterra cycle).

Quantifying sensitivity

A useful question: how sensitive is extinction probability to the attack rate aa? A small Monte Carlo over many seeds gives us an answer with confidence bars.

Code Block
Python 3.13.2

The survival probability falls as predation intensifies, and binomial standard errors quantify how confident we are in each estimate. This is the output of a real computational science project: not just a number, but a number with an uncertainty.

What you just used

A non-exhaustive list of techniques from this course that appear in the capstone:

TechniqueWhere
Vectorized NumPythe entire RHS
Adaptive ODE integrationsolve_ivp with RK45
Event detectionextinction at y=0.5y = 0.5
Reproducible randomnessdefault_rng(seed) per run
Multi-file project layoutsimulate / aggregate / plot
Parameter sweepnested loops over a and seed
Small-multiples visualizationplot.small_multiples
Monte Carlo uncertaintysurvival probability ± SE
Phase-portrait analysispredator–prey trajectories

Scientific computing is rarely a single algorithm. It is a pipeline of choices, each grounded in numerical understanding, glued together by reproducible code.

Check your understanding

QuestionSelect one

The capstone uses solve_ivp(..., events=extinct, dense_output=True, max_step=0.5). Why max_step=0.5 rather than letting the solver pick freely?

To slow down the simulation for visualization

An adaptive solver may take huge steps over slow dynamics and miss short-lived events; capping the step size forces the solver to evaluate the event function frequently enough to detect a fast extinction transient

It changes the order of the integrator

It enables GPU acceleration

QuestionSelect one

Why does the capstone summary report both mean_peak_prey and p_extinction per parameter setting, rather than just the population trajectory of one representative run?

For aesthetic reasons

A single trajectory hides stochastic variability. Aggregated quantities (means and probabilities) over many seeds report a property of the parameter setting, not of one lucky draw — and they come with quantifiable uncertainty

It is required by the language

The CPU is faster that way

On this page