Modeling and Simulation
Build computer simulations of population growth and discover how scientists predict the future.
Materials for this lesson
- Laptop (charged)
- Whiteboard and markers
Warm-Up: The Power of One Tree
There are roughly 8 billion people on Earth. What would happen if every single person planted one tree today? How much CO2 would those trees absorb? How much land would they need? Take 3 minutes to estimate before revealing the answer.
Think about:
- How much space does one tree need?
- How much CO2 does one tree absorb per year?
- How much CO2 does humanity produce per year?
Core Lesson: What Is a Model?
Models Are Everywhere
A model is a simplified representation of something real. Scientists, engineers, economists, and game designers all use models. The purpose of a model is to help us understand, predict, and explore systems that are too complex, too large, too small, or too dangerous to study directly.
| Type of Model | Example | What it simplifies | |---------------|---------|-------------------| | Physical model | Globe of the Earth | Shrinks the planet to something you can hold | | Conceptual model | Food web diagram | Shows relationships without every detail | | Mathematical model | E = mc^2 | Describes physics with equations | | Computer simulation | Weather forecast | Runs a mathematical model millions of times |
"All models are wrong, but some are useful." — George Box, statistician. Every model leaves things out. The skill is deciding what to include and what to simplify so that the model is still useful for answering your specific question.
The Simulation Loop
A computer simulation works by stepping through time in small increments. At each step, it applies rules to update the state of the system. The basic structure is:
1. Set initial conditions
2. For each time step:
a. Apply the rules (equations)
b. Update the state
c. Record the results
3. Analyze and visualize
This is exactly what we will build today.
Population Growth: Two Models
Model 1: Exponential Growth
If a population grows by a fixed percentage each time step, you get exponential growth:
N(t+1) = N(t) + r * N(t)
Where:
N(t)= population at time tr= growth rate (e.g., 0.1 = 10% growth per time step)
This can also be written as: N(t+1) = N(t) * (1 + r)
Exponential growth starts slow, then explodes. A population of 100 growing at 10% per step becomes: 100, 110, 121, 133, 146, 161, ... After 50 steps it reaches 11,739. After 100 steps: 1,378,061. This is why exponential growth is unsustainable — nothing in nature grows exponentially forever.
Model 2: Logistic Growth (with Carrying Capacity)
In reality, every environment has a limit to how many organisms it can support. This limit is called the carrying capacity (K). As the population approaches K, growth slows down and eventually stops.
N(t+1) = N(t) + r * N(t) * (1 - N(t) / K)
The new term (1 - N(t) / K) acts like a brake:
- When N is small compared to K, the brake is weak (nearly 1), and growth is fast.
- When N is close to K, the brake is strong (nearly 0), and growth stalls.
- When N equals K, growth stops completely.
This produces an S-shaped curve (sigmoid), which is how most real populations grow.
Population Growth — Crash Course Ecology
In the logistic growth equation, what happens when the population N equals the carrying capacity K?
Which of the following shows exponential growth?
Hands-On Lab: Building Simulations in Python
Simulation 1: Exponential Growth
# Exponential Growth Simulation
# ----------------------------------
# A bacteria colony doubles every hour.
# Starting population: 100 bacteria
# Growth rate: 100% per hour (r = 1.0)
population = 100
growth_rate = 1.0
time_steps = 24 # simulate 24 hours
# Store results for display
times = []
populations = []
print("Hour | Population")
print("-" * 30)
for t in range(time_steps + 1):
times.append(t)
populations.append(population)
print(f" {t:2d} | {population:,.0f}")
population = population + growth_rate * population
print(f"\nAfter {time_steps} hours: {populations[-1]:,.0f} bacteria")
print(f"That's a {populations[-1] / populations[0]:,.0f}x increase!")
Try changing the growth rate. What happens with growth_rate = 0.1 (10% per hour)? What about growth_rate = 0.5? A higher growth rate means faster explosion, but ALL exponential growth eventually becomes enormous — it is only a question of when.
Simulation 2: Logistic Growth
Now let's add a carrying capacity to make the model more realistic.
# Logistic Growth Simulation
# ----------------------------------
# Same bacteria, but now the petri dish can only sustain 10,000 bacteria.
population = 100.0
growth_rate = 0.5
carrying_capacity = 10000
time_steps = 50
times = []
populations = []
print("Step | Population | Growth Rate (effective)")
print("-" * 55)
for t in range(time_steps + 1):
times.append(t)
populations.append(population)
# Effective growth rate slows as population approaches K
effective_rate = growth_rate * (1 - population / carrying_capacity)
print(f" {t:2d} | {population:8.1f} | {effective_rate:.4f}")
# Logistic growth equation
population = population + growth_rate * population * (1 - population / carrying_capacity)
print(f"\nCarrying capacity: {carrying_capacity}")
print(f"Final population: {populations[-1]:.1f}")
Simulation 3: Plotting Both Models Together
# Compare Exponential vs Logistic Growth
# Requires matplotlib — run: pip install matplotlib
import matplotlib.pyplot as plt
# Parameters
initial_pop = 100
growth_rate = 0.3
carrying_capacity = 10000
time_steps = 60
# Simulate exponential growth
exp_pop = initial_pop
exp_populations = []
for t in range(time_steps):
exp_populations.append(exp_pop)
exp_pop = exp_pop * (1 + growth_rate)
# Simulate logistic growth
log_pop = float(initial_pop)
log_populations = []
for t in range(time_steps):
log_populations.append(log_pop)
log_pop = log_pop + growth_rate * log_pop * (1 - log_pop / carrying_capacity)
# Plot
plt.figure(figsize=(10, 6))
plt.plot(range(time_steps), exp_populations, label="Exponential Growth", color="red", linewidth=2)
plt.plot(range(time_steps), log_populations, label="Logistic Growth", color="blue", linewidth=2)
plt.axhline(y=carrying_capacity, color="green", linestyle="--", label=f"Carrying Capacity (K={carrying_capacity})")
plt.xlabel("Time Steps", fontsize=12)
plt.ylabel("Population", fontsize=12)
plt.title("Exponential vs. Logistic Growth", fontsize=14)
plt.legend(fontsize=11)
plt.grid(True, alpha=0.3)
plt.ylim(0, carrying_capacity * 1.5)
plt.tight_layout()
plt.savefig("growth_comparison.png", dpi=150)
plt.show()
print("Graph saved as growth_comparison.png")
Experiment with parameters! Try these and observe how the logistic curve changes shape:
- Higher
growth_rate: The S-curve reaches the ceiling faster, and may overshoot and oscillate. - Lower
carrying_capacity: The curve flattens earlier. - Higher
initial_pop: The curve starts closer to K and flattens almost immediately.
Write down your predictions BEFORE changing the parameter, then run it. Were you right?
Challenge: Predator-Prey Dynamics
The Lotka-Volterra Model: In real ecosystems, species interact. Predators eat prey, which limits the prey population — but if prey declines, predators starve too, and their population drops, which lets prey recover... creating a fascinating cycle.
Your challenge: Modify the simulation to model two species — rabbits (prey) and foxes (predators) — and see what patterns emerge.
The equations are:
- Rabbits:
R(t+1) = R(t) + a*R(t) - b*R(t)*F(t)- Rabbits grow naturally at rate
a, but are eaten at a rate proportional to how many foxes there are.
- Rabbits grow naturally at rate
- Foxes:
F(t+1) = F(t) + c*R(t)*F(t) - d*F(t)- Foxes grow based on how many rabbits they can eat, but die at rate
dwithout food.
- Foxes grow based on how many rabbits they can eat, but die at rate
In a predator-prey model, what happens to the predator population shortly AFTER the prey population crashes?
Resources
- NetLogo Web — run agent-based simulations right in your browser (try the Wolf-Sheep Predation model)
- PhET Simulations — Natural Selection — interactive evolution simulation from the University of Colorado
- Matplotlib Documentation — reference for Python plotting
- 3Blue1Brown: Epidemic Simulations — beautifully animated video on how simulations model disease spread
- Complexity Explorer — Santa Fe Institute — free courses on modeling complex systems