13  Ruimtelijke groei

Zoals je nu wel hebt begrepen, modellen maken vaak vele aannames. Hoewel we tot nu toe veel aannames expliciet hebben benoemd (goed gemengd systeem, parameters zijn constant, etc.), zijn er soms ook aannames die je misschien niet onmiddellijk zijn opgevallen. Zo hebben we het bijvoorbeeld gehad over dichtheidsafhankelijke groei, maar daarbij altijd aangenomen dat alle individuen deze dichtheidseffecten op dezelfde manier ervaren. Maar een bos kan zich vooral aan de rand uitbreiden: daar hebben de individuen toegang tot lege plekjes met veel licht. Hetzelfde geldt voor bacteriën op een agarplaat (aan de rand zijn meer nutriënten beschikbaar) of een groeiende tumor (voor cellen in het midden schieten zuurstof en voedingsstoffen tekort).

In de bovenstaande scenario’s is het steeds het geval dat de individuen/cellen aan de rand een lagere dichtheid ervaren dan individuen in het midden. Met andere woorden: niet ieder individu ondervindt dezelfde dichtheidseffecten, wat in onze eerdere modellen wel aangenomen werd! Sterker nog, tot nu toe spraken we helemaal niet over individuen, want we omschreven steeds slechts de totale populatiegrootte.

Afbeelding gegenereerd met ChatGPT4-o

Afbeelding gegenereerd met ChatGPT4-o

13.1 Leerdoelen

In dit hoofdstuk, gaan we na denken over hoe populaties (of het nu bomen, bacteriën, of tumorcellen zijn) groeien in de ruimte. Dit doen we door kennis te maken met individual-based modelling, wat aanneemt dat organismen discrete individuen zijn, eventueel met hun eigen omgeving en gedrag. Aan het eind van dit hoofdstuk, moet je begrijpen:

  • Wat er bedoelt wordt met ‘omschrijvingsniveau’.
  • Dat je naast populatiegroottes ook vanuit het individu kan denken.
  • Dat interacties lokaal zijn, dus dat de posities van individuen ertoe kunnen doen.
  • Hoe het komt dat sommige ruimtelijke modellen een “ingebouwd” draagvermogen hebben.

13.2 Wat is individual-based modelling?

Individual-based modelling (IBMs, ook wel agent-based modelling of ABMs genoemd), is een modeltechniek waarbij organismen als discrete entiteiten (individuen) worden beschouwd. Hierdoor kunnen we niet louter en alleen populatiegroottes bestuderen, maar ook de eigenschappen en gedragingen van individuen binnen de populatie. Formeler gezegd kunnen we stellen dat individual-based modellen een ander omschrijvingsniveau hebben dan ODEs/differentievergelijkingen. Dit omschrijvingsniveau bepaalt ook welke modeluitkomsten we kunnen verwachten: als we alleen de populatiegroottes bestuderen, kunnen we geen inzichten over individuele verschillen verwachten. Laten we hiermee kennis maken door te denken aan een bacteriekolonie die zich over een agarplaat verspreidt.

13.3 Individuen en hun posities

Stel je voor dat in het midden van een agarplaat een enkele (paarse) bacteriecel begint met delen (zie Figuur 13.1). Deze cel groeit met een bepaalde snelheid, en kan op een bepaald moment delen. Maar reproductie is (meestal) een lokaal proces, dat wil zeggen, de dochtercel zal naast de oudercel geplaatst worden. We kunnen ons dus voorstellen dat, wanneer dit proces stap voor stap doorspeelt, de kolonie bij benadering in een cirkelvorm zal uitgroeien. Als er ook een kans is dat de dochtercel een mutatie heeft (waardoor deze bijvoorbeeld geel wordt), dan ontstaat er over de tijd zelfs een interessant patroon (zie Figuur 13.1, rechter zijde). Door het perspectief in te nemen van de cel (in plaats van de totale populatie), kunnen we dus gaan nadenken over individuele verschillen in positie, kleur, groeisnelheid, etc.

Code (voor de leuk, dit is geen leerstof)
# Functie om het grid te visualiseren als punten
plot_grid <- function(grid) {
  par(mar = c(1, 1, 1, 1))
  plot(1, 1, type = "n", xlim = c(1, nrow(grid)), ylim = c(1, ncol(grid)), xlab = "", ylab = "", axes = FALSE, asp = 1)
  
  points(which(grid == 1, arr.ind = TRUE), col = "black", bg = "purple", pch = 21, lwd=0.2, cex = 0.5)
  points(which(grid == 2, arr.ind = TRUE), col = "black", bg = "gold", pch = 21,lwd=0.2, cex = 0.5)
}

# Functie om de groei-regels over het hele grid toe te passen. Deze regel werkt zo:
# Voor elk lege punt (0), pak een 
update_grid <- function(grid) {
  size <- nrow(grid)
  new_grid <- grid
  
  for (i in 1:size) {
    for (j in 1:size) {
      if (grid[i, j] == 1 || grid[i, j] == 2) {
        neighbors <- cbind(c(i-1, i+1, i, i), c(j, j, j-1, j+1))
        for (k in 1:nrow(neighbors)) {
          ni <- neighbors[k, 1]
          nj <- neighbors[k, 2]
          if (ni > 0 && ni <= size && nj > 0 && nj <= size && grid[ni, nj] == 0) {
            if (runif(1) < 0.5) {  # Geboortekans van 50%
              new_grid[ni, nj] <- grid[i, j]  # Kleur wordt overgedragen
              if(runif(1) < 0.01) grid[i,j] <- 2
            }
          }
        }
      }
    }
  }
  
  return(new_grid)
}

# Maak een grid van 0-en met één 1tje in het midden
grid <- matrix(0, nrow = 100, ncol = 100)
grid[50,50] <- 1
set.seed(59)

# Loop om het grid bij te werken en te visualiseren
layout(matrix(c(1,2,2,3,3,4,4),nrow=1))
for (t in 1:75) {
  if(t==2 || t%%22==0) plot_grid(grid)
  if(t==2) arrows(20,20,40,40,length=0.06,lwd=2)
  grid <- update_grid(grid)
  
  Sys.sleep(0.1)  # Korte vertraging om de veranderingen zichtbaar te maken
}
title("Een groeiende bacteriekolonie met (gele) mutanten", cex.main=2,line = -2, outer = TRUE)
Figuur 13.1: Paarse stippen staan voor wildtype bacteriën, terwijl gele stippen bacteriën zijn met een mutatie. Door lokale celdeling onstaat er een “taartpunt” van mutanten, zoals waargenomen in Fusco et. al (2016)

De ruimtelijke structuur die in de IBM van Figuur 13.1 ontstaat is een geheel nieuw type model-resultaat, en staat ons toe om vele nieuwe vragen te stellen: hoe verspreiden mutaties zich in een bacteriekolonie? Hoe belangrijk is zuurstof-beperking voor de groei van een tumor? Hoe behouden we diverse ecosystemen wanneer bossen de heide overgroeien? Hoewel IBMs ook zonder ruimtelijke structuur gemodelleerd kunnen worden, is een dergelijke structuur natuurlijk wel een belangrijk component van biologische systemen! Maar hoe pakken we dat dan aan, individuen in de ruimte modelleren?

13.4 Geboorte in “lege hokjes”

Nu we het belang inzien van individuen en hun positie, hoe verwerken we dit dan in een model? De meest eenvoudig vorm is wellicht een 2-dimensionale ruimte, waarin elk individu een x- en een y-coordinaat heeft. We kunnen bijvoorbeeld een dataframe maken met daarin twee individuen:

# Maak twee individuen met een positie en een kleur
individual1 <- data.frame(x=6,y=6,col="brown")
individual2 <- data.frame(x=7,y=6,col="orange")
# Zet ze samen in een dataframe als 'beginpopulatie'
population <- rbind(individual1, individual2)
population
  x y    col
1 6 6  brown
2 7 6 orange

Om het extra simpel te houden, nemen we aan dat de x-y coordinaten altijd gehele getallen zijn (\(x=1,2,3,\dots,W\) en \(y=1,2,3,\dots,H\)), zodat we ons de volledige ruimte kunnen voorstellen als een simpel grid dat \(W\) breed is en \(H\) hoog (een soort schaakbord dus, maar dan zonder die oneindige berg rijst). Nu zouden we elk individu in deze lijst “regels” kunnen geven voor hun voortplanting. Elk individu zou bijvoorbeeld zich in een leeg buur-hokje kunnen voortplanten met een kans van 60%, en kunnen sterven met een kans van 5%. Laten we even stellen dat de kleur van het individu niet uitmaakt voor deze regels: deze is alleen voor de visualisatie. Als we dit simuleren in R, zouden we zoiets kunnen zien:

Code (geen leerstof!)
# Maak een 12x12 grid
grid_size <- 12
grid <- matrix(0, nrow = grid_size, ncol = grid_size)
# Maak twee individuen met een positie en een kleur
individual1 <- data.frame(x=6,y=6,col="brown")
individual2 <- data.frame(x=7,y=6,col="orange")
# Zet ze samen in een dataframe als 'beginpopulatie'
population <- rbind(individual1, individual2)
grid[6, 6] <- 1 # 6,6 zit vol
grid[6, 7] <- 1 # 7,6 zit vol (let op dat row=y en col=x)

# Groei-simulatie functie
simulate_growth <- function(geboorte = 0.6, sterfte=0.1) {
  deaths <- c() # Houd bij wie er dood gaan, zodat deze aan het einde uit de populatie gehaald kunnen worden
  for (i in 1:nrow(population)) {
    ind <- population[i,]
    if(runif(1) < geboorte){
      new_x <- ind$x + sample(c(-1:1),1)
      new_y <- ind$y + sample(c(-1:1),1)
      if(new_x<1 || new_x > grid_size || new_y < 1 || new_y > grid_size) next
      if(grid[new_y,new_x] == 0){
        grid[new_y,new_x] <<- 1
        population <<- rbind(population,data.frame(x=new_x,y=new_y,col=ind$col))
      }
    }
    if(runif(1) < sterfte){
      grid[ind$y,ind$x] <<- 0
      deaths <- c(deaths, i)
    }
  }
  if(length(deaths) > 0) population <<- population[-deaths,]
}

# Functie om het grid als bruine stipjes op een grid te plotten. 
plot_grid <- function(grid, time) {
  plot(1:grid_size, 1:grid_size, type = "n", xlab = "", ylab = "", axes = FALSE)
  # Grijze lijntjes
  for (i in 0:(grid_size)+1) {
    abline(h = i-0.5, col = "grey", lty = 1)
    abline(v = i-0.5, col = "grey", lty = 1)
  }
  # Bruine stipjes
  for (i in 1:nrow(population)) {
    ind <- population[i,]
    points(ind$x, ind$y, pch = 16, col = ind$col)
  }
  title(paste("Tijdstap",time))
}

# Start een random nummer generator (gerandeert reproduceerbaarheid)
#set.seed(591)

par(mfrow=c(3,5),mar=c(1,1,2,2))
# Simuleer een x-aantal tijdstappen (x=iterations)
iterations <- 28
plot_grid(grid,0)
for (i in 1:iterations) {
  if(i%%2==0) plot_grid(grid,i)
  simulate_growth(0.6, 0.1)
}
Figuur 13.2: Simulatie van groei op een grid, waarbij “individuen” kunnen reproduceren in lege buur-hokjes met een kans van 60%, en sterven met een vaste kans van 5%. De kleur heeft hier geen invloed op, en dient alleen ter illustratie.

Hoewel het R-script geen dichtheidsafhankelijke afname van de geboortekans gebruikt (deze blijft altijd 60%), zal de populatie toch niet meer toenemen zodra het grid vol zit. De reden dat er toch een draagvlak aanwezig is, is simpelweg doordat individuen alleen kunnen voortplanten in lege hokjes. De daadwerkelijke geboortekans is dus helemaal niet constant, want op een vol grid is die veel kleiner dan op een leeg grid! Als we hadden aangenomen dat individuen ook kunnen voortplanten in bezette hokjes, dan zou de populatie inderdaad exponentiëel blijven groeien.

Is ruimte beperkend voor groei?

De aanname dat ruimte een intrinsieke beperking is voor groei hangt sterk af van het biologische scenario: voor planten die licht moeten opvangen geldt dit waarschijnlijk wel, maar voor de grazers die deze planten eten wellicht niet. Vergelijkbaar hebben bacteriën op een agarplaat of tumorcellen alleen voedingsstoffen aan de rand, wat een vergelijkbaar effect oplevert waarbij er alleen in “lege ruimte” groei mogelijk is. Dergelijke overwegingen zijn heel belangrijk als we biologische systemen goed willen kunnen voorspellen!

Een ander belangrijk verschil met onze eerdere (wiskundige) modellen is dat we nu gebruik maken van stochasticiteit, dat wil zeggen kansprocessen. Specifieker zijn birth en death geen snelheden meer, maar kansprocessen. Als in deze simulatie birth veel hoger is dan death (\(b\gg d\)), zal de populatie natuurlijk gewoon uitgroeien totdat een groot deel van het grid vol zit (Figuur 13.3 (a)). Daarna zal de populatie een beetje rond een evenwicht fluctueren, waarbij death wordt gecompenseerd door birth.

Wanneer het verschil tussen \(b\) en \(d\) veel kleiner is, groeit het grid minder vol. Ook zie je dat de fluctuaties rond het evenwicht wat sterker zijn geworden (Figuur 13.3 (b)). Daarnaast zie je in deze simulatie dat er aan het einde, door toeval, alleen nog oranje individuen over zijn!

Als \(b\) slechts een klein beetje groter is dan \(d\) (Figuur 13.3 (c)), zien we zelfs dat de kleine start-populatie van 2 cellen door stomme pech uit zou kunnen sterven. Ook dit was niet mogelijk in de ODEs, waar \(b>d\) altijd exponentiële groei geeft.

Code
# Maak een 12x12 grid
grid_size <- 32
grid <- matrix(0, nrow = grid_size, ncol = grid_size)
# Maak twee individuen met een positie en een kleur
individual1 <- data.frame(x=16,y=16,col="brown")
individual2 <- data.frame(x=17,y=16,col="orange")
# Zet ze samen in een dataframe als 'mbeginpopulatie'
population <- rbind(individual1, individual2)
grid[16, 16] <- 1 # 6,6 zit vol
grid[16, 17] <- 1 # 7,6 zit vol (let op dat row=y en col=x)

# Groei-simulatie functie
simulate_growth <- function(geboorte = 0.6, sterfte=0.1) {
  deaths <- c() # Houd bij wie er dood gaan, zodat deze aan het einde uit de populatie gehaald kunnen worden
  for (i in 1:nrow(population)) {
    ind <- population[i,]
    if(runif(1) < geboorte){
      new_x <- ind$x + sample(c(-1:1),1)
      new_y <- ind$y + sample(c(-1:1),1)
      if(new_x<1 || new_x > grid_size || new_y < 1 || new_y > grid_size) next
      if(grid[new_y,new_x] == 0){
        grid[new_y,new_x] <<- 1
        population <<- rbind(population,data.frame(x=new_x,y=new_y,col=ind$col))
      }
    }
    if(runif(1) < sterfte){
      grid[ind$y,ind$x] <<- 0
      deaths <- c(deaths, i)
    }
  }
  if(length(deaths) > 0) population <<- population[-deaths,]
}

# Functie om het grid als bruine stipjes op een grid te plotten. 
plot_grid <- function(grid, time) {
  plot(1:grid_size, 1:grid_size, type = "n", xlab = "", ylab = "", axes = FALSE)
  # Grijze lijntjes
  for (i in 0:(grid_size)+1) {
    abline(h = i-0.5, col = "grey", lty = 1)
    abline(v = i-0.5, col = "grey", lty = 1)
  }
  # Bruine stipjes
  for (i in 1:nrow(population)) {
    ind <- population[i,]
    points(ind$x, ind$y, pch = 16, col = ind$col,cex = 1)
  }
  title(paste0("Grid op t=",time))
}

# Start een random nummer generator (gerandeert reproduceerbaarheid)
set.seed(596)
#par(mfrow=c(1,2),mar=c(3,3,1,1))
layout.matrix <- matrix(c(1, 2), nrow = 1, ncol = 2)
layout(mat = layout.matrix, widths=c(2.5,1))
par(mar=c(4,4,1,1))
population <- rbind(individual1, individual2)
grid <- matrix(0, nrow = grid_size, ncol = grid_size)
grid[16, 16] <- 1 # 6,6 zit vol
grid[16, 17] <- 1 # 7,6 zit vol (let op dat row=y en col=x)
# Simuleer een x-aantal tijdstappen (x=iterations)
iterations <- 300
popsize <- nrow(population)
for (i in 1:iterations) {
  simulate_growth(0.6, 0.1)
  popsize[i+1] <- nrow(population)
}
ts.plot(popsize, xlab="Tijd", ylab="Populatiegrootte", lwd=2, main="")
par(mar=c(1,1,1,1))
plot_grid(population,300)

par(mar=c(4,4,1,1))
population <- rbind(individual1, individual2)
grid <- matrix(0, nrow = grid_size, ncol = grid_size)
grid[16, 16] <- 1 # 6,6 zit vol
grid[16, 17] <- 1 # 7,6 zit vol (let op dat row=y en col=x)
# Simuleer een x-aantal tijdstappen (x=iterations)
iterations <- 300
popsize <- nrow(population)
for (i in 1:iterations) {
  simulate_growth(0.3, 0.1)
  popsize[i+1] <- nrow(population)
}
ts.plot(popsize, xlab="Tijd", ylab="Populatiegrootte", lwd=2, main="")
par(mar=c(1,1,1,1))
plot_grid(population,300)

par(mar=c(4,4,1,1))
population <- rbind(individual1, individual2)
grid <- matrix(0, nrow = grid_size, ncol = grid_size)
grid[16, 16] <- 1 # 6,6 zit vol
grid[16, 17] <- 1 # 7,6 zit vol (let op dat row=y en col=x)
# Simuleer een x-aantal tijdstappen (x=iterations)
iterations <- 300
popsize <- nrow(population)
for (i in 1:iterations) {
  simulate_growth(0.12, 0.1)
  popsize[i+1] <- nrow(population)
  if(popsize[i+1]==0) break
}
ts.plot(popsize, xlab="Tijd", ylab="Populatiegrootte", lwd=2, main="")
par(mar=c(1,1,1,1))
plot_grid(population,300)
(a) Simulatie met b=0.6, d=0.1
(b) Simulatie met b=0.3, d=0.1
(c) Simulatie met b=0.12, d=0.1
Figuur 13.3: Simulaties van groei op een grid met verschillende birth rates (en dezelfde death rates).

13.5 Lokale interacties en samenwerken

In de biologie is vaak sprake van samenwerking (ook wel coöperatie genoemd). Wolven jagen samen, planten zenden chemische signalen uit om anderen te waarschuwen voor herbivoren, en bacteriën scheiden enzymen uit die suikers beschikbaar maken voor nabijgelegen bacteriën. Dergelijke samenwerkingen zouden we kunnen verwerken in onze simulatie in een vorm van dichtheidsafhankelijkheid.

Als we positieve dichtheidsafhankelijke effecten willen gebruiken in een IBM op een grid, zouden we de totaalpopulatie kunnen meten en de kans op geboorte (\(b\)) hiermee aan kunnen aanpassen. Echter hoeft het helemaal niet zo te zijn dat iedereen de vruchten plukt van samenwerkingen. Als een individu in grid-punt (10,10) anderen helpt (bijvoorbeeld de bacterie maakt suikers vrij), zal een individu in gridpunt (25,20) daar geen direct voordeel van hebben. In plaats daarvan, zouden we bijvoorbeeld de geboortekans van de 8 buren van (10,10) kunnen verhogen. Dit noemen we een lokale interactie. Bijvoorbeeld, de oranje en rode individuen kunnen de volgende geboortekansen krijgen:

\[ \text{Geboortekans({\color{red}rood})} = b+c\cdot \left(\sum{\text{aantal \color{orange}oranje buren}}\right)\] \[\text{Geboortekans({\color{orange}oranje})} = b+c\cdot \left(\sum{\text{aantal \color{red} rode buren}}\right)\]

Een voorbeeld van de bovenstaande regels zouden bacteriën kunnen zijn die van elkaar afhankelijk zijn voor de productie van essentiële aminozuren1. Dergelijke cross-feeding komt veel voor in de microbiële wereld, maar ook dieren, planten, en andere organismen kunnen vergelijkbare afhankelijkheden hebben.

Hieronder zie je een interactieve simulatie van het systeem (je moet nog wel even op start drukken), waarbij je de parameters \(b\), \(c\), en \(d\), en de begin-dichtheid kan instellen. De parameters zijn zo ingesteld dat \(b\) maar een klein beetje groter is dan \(d\), maar doordat de individuen elkaar helpen groeien ze toch prima uit totdat het hele grid vol is.

Wat opvalt aan de bovenstaande simulatie is dat de populatie uitgroeit, maar dat als we naar de grafiek kijken, dit niet exponentieel lijkt te beginnen (met andere woorden, we zien geen duidelijke sigmoïde curve). Dit zou kunnen komen doordat we met een vrij hoge dichtheid van cellen beginnen, waardoor we onmiddellijk al in het steile deel van de groeicurve zitten. In het werkcollege zul je deze simulatie verder bestuderen.

13.6 De parasiet

Als we het hebben over samenwerking, kunnen we ons afvragen wat er zou gebeuren als iemand valsspeelt. Wat nu als er bijvoorbeeld een derde bacteriesoort is die energieke kosten bespaart op de productie van aminozuren, maar daardoor afhankelijk is van de andere soorten? Laten we de bovenstaande simulaties eens uitbreiden met een derde soort: die we voor de eenvoud de parasiet zullen noemen. In het Engels worden samenwerkers vaak cooperators worden genoemd, en heten de parasieten vaak cheaters of defectors. We nemen aan dat de parasiet geen hulp geeft, maar wordt geholpen door zowel de rode als oranje individuen:

\[ \text{Geboortekans({\color{red}rood})} = b+c\cdot \left(\sum{\text{aantal {\color{orange}oranje} buren}}\right)\] \[\text{Geboortekans({\color{orange}oranje})} = b+c\cdot \left(\sum{\text{aantal {\color{red} rode} buren}}\right)\] \[\text{Geboortekans({\color{#2a53f7}blauw})} = b+c\cdot \left(\sum{\text{aantal {\color{red} rode} plus {\color{orange}oranje} buren}}\right)\]

Dit levert de volgende dynamica op:

Zoals je ziet heeft deze verandering een enorme impact! Waar eerst de simulatie niet veel meer veranderde nadat het grid was volgegroeid, zien we nu dat het systeem alsmaar in beweging blijft. De cheaters overgroeien steeds de cooperators, maar omdat ze daarna zichzelf niet helpen sterven ze lokaal uit. Overgebleven cooperators kunnen de “lege ruimte” die daardoor is ontstaan weer veroveren, waarna er weer cheaters komen, etc.. Zo gaat de simulatie alsmaar door. Als je echter na iedere stap alle individuen op een willekeurige plek plaatst (dat gebeurt met het vinkje ‘mengen’, je roert als het ware het systeem heel goed door), zul je zien dat er iets heel anders gebeurt: de cheaters nemen de hele simulatie over en daarna sterft alles uit. Als alles is uitgestorven, is het natuurlijk game over.

13.7 De eindeloze mogelijkheden van IBMs

Nu je een klein beetje een beeld hebt gekregen van individual-based modelling, kun je je misschien voorstellen dat de mogelijkheden eindeloos zijn. Hokjes kunnen namelijk niet alleen individuen bevatten, maar ook voedsel, antibiotica, andere organismen, uitgescheiden eiwitten, windrichtingen en noem zo maar op. Bovendien hoeven individuen natuurlijk helemaal niet in hokjes te zitten, maar zouden ze vrij door een continue ruimte kunnen lopen, zoals de mieren in de simulatie hieronder:

Simulatie van mieren die foerageren voor voedsel. De witte cirkel is voedsel (“suiker”), en de grijze cirkel het nest waarin wordt weergegeven hoeveel suiker er is verzameld. De rode en blauwe paden zijn feromonen waarmee de mieren signaleren naar elkaar waar het nest en het voedsel te vinden is. We zullen deze simulatie in een later hoofdstuk ook nog bespreken.

Je begrijpt nu wellicht dat je met IBMs allerlei dingen simuleren: (“the sky is the limit!”)! Maar dat is misschien niet altijd even wenselijk. Met modellen proberen we natuurlijk (zoals in de introductie uitgelegd) de biologie enigszins te versimpelen, dus het is de kunst om de modellen niet te complex te maken. Aan de andere kant kunnen modellen die te simpel zijn de plank enorm misslaan. De balans tussen een simpel en een complex model is helemaal niet eenvoudig op te maken. Albert Einstein begreep dit ook:

“A model should be as simple as possible, but no simpler”
– Albert Einstein2

13.8 Opgaven

Oefening 13.1 (Samenwerken en het Allee effect)

We bestuderen in deze opgave de simulatie van samenwerkende individuen nog wat verder.

Zoals je kunt zien, laat deze populatie geen duidelijk logistische groei zien (er is geen duidelijke S-curve). Wellicht komt dit doordat we met een te hoge initiële dichtheid zijn begonnen.

  1. Pas met de sliders de begindichtheid aan. Laat de andere parameters op hun standaard waarde staan (\(b=0.11\), \(d=0.10\), en \(c=0.3\)). Herstart de simulatie een aantal keer. Vind je nu wel logistische groei?
  2. Wat valt je op bij hele lage begin-dichtheden (\(<0.002\))?
  3. Gebruik een begin-dichtheid van \(0.002\), en herhaal je experiment 20 keer. Houd voor iedere keer bij of het de populatie lukt om uit te groeien (ja/nee).
  4. Activeer “mengen”, en herhaal je experiment uit b nogmaals 20 keer. Houd wederom bij of de populatie succesvol kan uitgroeien
  5. Heb je een verschil gevonden? Zou dit verschil misschien toeval kunnen zijn?

Oefening 13.2 (De simpelste ODE met coöperatie)

In een eerder hoofdstuk hebben we geleerd dat we in ODEs de birth- of death-rates afhankelijk kunnen maken van de dichtheid. In dit hoofdstuk hebben we kennis gemaakt met coöperatie: groei die juist bevorderd wordt door een hogere dichtheid. Dit zouden we in een simpele ODE kunnen verwerken als een een birth rate die kwadratisch afhangt van de dichtheid:

\[\begin{align} \mathchoice{\frac{\mathrm{d}N} {\mathrm{d}t}}{\mathrm{d}N/\mathrm{d}t} {\mathrm{d}N/\mathrm{d}t} {\mathrm{d}N/\mathrm{d}t} &= bN^2 - dN \end{align}\]

  1. Bereken bij welke dichtheden \(N\) er sprake is van evenwicht.
  2. Schets \( \mathchoice{\frac{\mathrm{d}N} {\mathrm{d}t}}{\mathrm{d}N/\mathrm{d}t} {\mathrm{d}N/\mathrm{d}t} {\mathrm{d}N/\mathrm{d}t} \) als een functie van \(N\). Bepaal met behulp van dit faseportret de stabiliteit van de evenwichten.
  3. Schets oplossingen voor de initiële conditie waar \(N\) klein is, en de initiele conditie waar \(N\) groot is. Wat valt je op?
  4. Waarom was het fenomeen uit vraag c. geen probleem in het individual-based model?

Oefening 13.3 (Logistische groei met sexuele reproductie)

Je hebt geleerd dat logistische groei in eerste instantie exponentiëel is, waarna het afvlakt tot een plateau. In de cooperatie-vragen heb je gezien dat hele lage dichtheden een probleem kunnen opleveren. Ditzelfde geldt voor sexuele reproductie: bij lage dichtheden is het moeilijk een paringspartner te vinden. Beschouw de volgende ODE vergelijking:

\[\begin{align} \mathchoice{\frac{\mathrm{d}N} {\mathrm{d}t}}{\mathrm{d}N/\mathrm{d}t} {\mathrm{d}N/\mathrm{d}t} {\mathrm{d}N/\mathrm{d}t} &= bN^c(1-\frac{N}{K}) - dN \end{align}\]

Dit model lijkt erg op vergelijkingen die we al hebben gezien voor logistische groei: \(b\) staat voor de (maximale) geboortesnelheid, \(k\) schaalt de dichtheidsafhankelijke afname van de geboorte, en \(d\) geeft een constante sterfte. Maar er staat ook een nieuwe parameter (\(c\)) in de vergelijking, die staat voor het coöperatie-effect (dit kan staan voor zowel sex als andere vormen van samenwerking). Hoe werkt deze parameter precies? Laten we eerst aannemen dat \(c=1\). Omdat \(N^1\) gewoon \(N\) is, blijft de ODE dan gelijk aan de groeimodellen die we al kennen.

  1. Schets de groeisnelheid \( \mathchoice{\frac{\mathrm{d}N} {\mathrm{d}t}}{\mathrm{d}N/\mathrm{d}t} {\mathrm{d}N/\mathrm{d}t} {\mathrm{d}N/\mathrm{d}t} \) als een functie van \(N\). Teken onder je schets een faseportret met pijltjes om aan te geven bij welke dichtheden de populatie kan groeien, en bij welke de populatie zal krimpen.

Nu nemen we aan dat \(c=2\). De functie krijgt nu de vorm \(bN^2 - \frac{bN^3}{K} - dN\), die wat lastiger te schetsen is. We kunnen de \(N\) buiten haakjes halen, en dan de ABC-formule kunnen gebruiken om de nulpunten van het deel binnen de haakjes uit te rekenen… Maar we kunnen ook een stukje R-code schrijven om de grafiek te plotten, of de grafiek plotten in Desmos (beide opties staan hieronder weergegeven).

Code voor het tekenen van de functie met R
b=0.2
K=10
d=0.1
c=2

fN <- function(N){
 return(b*N^c*(1-N/K) - d*N)
}

x <- seq(0,11,by=0.01)
y <- fN(x)

plot(x,y, type='l',lwd=3,col='seagreen', ylim=c(-0.1,3),
       ylab="dN/dt",xlab="N",
       main="dN/dt als een functie van N")
abline(h=0)
  1. Neem de grafiek uit R of Desmos over op papier, en schets opnieuw een faseportret met pijltjes eronder. Geef met open of gesloten cirkels respectievelijk instabiele en stabiele evenwichten aan.

  2. Schets in 1 figuur hoe de populatie door de tijd zal groeien voor verschillende begin-waarden van \(N\). Schets elke kwalitatief verschillende oplossing (er zijn drie mogelijkheden).

Oefening 13.4 (Het mengen van een kringloop)  

Gestern, heute und morgen folgen nicht aufeinander. Sie sind in einem ewigen Kreis miteinander verbunden. Alles ist miteinander verbunden.

Gestern, heute und morgen folgen nicht aufeinander. Sie sind in einem ewigen Kreis miteinander verbunden. Alles ist miteinander verbunden.

In dit hoofdstuk hebben we een voorbeeld gezien van een “cheater”, die wanneer het systeem goed gemengd is kan leiden tot grote problemen voor de cooperators. Maar wat nu als de cooperators “terug cheaten”? Of wat als er meer complexe afhankelijkheden ontstaan, zoals weergegeven in de cyclus in bovenstaande figuur? De geboortekansen volgens deze kringloop kunnen we definiëren als:

\[\begin{align} {Geboortekans({\color{red}rood})} = b+c\cdot \left(\sum{\text{aantal {\color{orange}oranje} buren}}\right) \\ {Geboortekans({\color{#2a53f7}blauw})} = b+c\cdot \left(\sum{\text{aantal {\color{red}rode} buren}}\right) \\ {Geboortekans({\color{orange}oranje})} = b+c\cdot \left(\sum{\text{aantal {\color{#2a53f7}blauwe} buren}}\right) \end{align}\]

Een simulatie met de bovenstaande interacties vind je hieronder.

  1. Bestudeer het model voor de standaardparameters \(b=0.13, c=0.11, d=0.1\), en beschrijf in biologische begrippen hoe dit systeem reageert op meer/minder mengen. Contrasteer je bevindingen met wat we gezien hebben voor het “cheater-cooperator” model.

In de onderstaande simulatie zijn er niet 3, maar 6 soorten die elkaar in een vergelijkbare cyclus helpen met reproduceren.

  1. Omschrijf het ruimtelijke patroon wat ontstaat en de dynamica van het aantal individuen per type.
  2. Heeft mengen altijd een positieve invloed op een cyclus?

13.9 Terminologie

Nederlands Engels Beschrijving
Individual-based modellen Individual-based models Modellen waarbij de eigenschappen en het gedrag van individuen wordt beschreven.
Omschrijvingsniveau Level of description Het belangrijkste aspect dat een model omschrijft wordt vaak het omschrijvingsniveau genoemd. Voor modellen van groei (bijvoorbeeld ODEs) is vaak de populatiegrootte het omschrijvingsniveau, terwijl bij een individual-based model het individu het omschrijvingsniveau is.
Modeluitkomsten Model outcomes Het omschrijvingsniveau bepaalt sterk welke uitkomsten een model kan hebben: een model dat alleen populatiegroottes omschrijft, kan geen inzichten geven in individuele verschillen.
Stochasticiteit Stochasticity Stochastischiteit verwijst naar de mate van willekeur of onzekerheid in een proces of in een systeem. Zodoende zijn de uitkomsten niet volledig voorspelbaar, maar variëren door toeval of willekeurige invloeden. In dit hoofdstuk gebruiken we geboorte- en sterfte-kansen, waardoor bijvoorbeeld groeiende populaties ook door domme pech uit kunnen sterven!
Lokale interactie Local interaction Interacties tussen individuen die alleen plaatsvinden wanneer zij zich binnen een bepaalde nabije afstand van elkaar bevinden.

  1. Dal Co, A., van Vliet, S., Kiviet, D.J. et al. Short-range interactions govern the dynamics and functions of microbial communities. Nat Ecol Evol 4, 366–375 (2020). https://doi.org/10.1038/s41559-019-1080-2↩︎

  2. Eigenlijk is dit helemaal niet een werkelijke citaat van Einstein, maar wel de boodschap achter een vrij complex relaas over irreducible basic elements en adequate representations, wat toch iets minder catchy bleek te zijn.↩︎