Stochastic Hunter-Prey model in 2D

This script is a model of two species, one hunter and one prey. The prey can reproduce and die naturally, and both the hunter and prey occupy a physical location in 2D. Both the hunter and prey move according to Browninan motion and if the hunter occupies the same space as the prey it is considered to have 'eaten' them. The prey are an example of branching diffusion. The hunter is an example of a diffusion with lingering effects so that if the hunter eats, it slows down to "look around". There is also a background current to mimic a passing internal wave.

Contents

clear all,close all

The maximum humber of particles.

numparts=1000;

Number of particles to start with.

numactive=500;

Parameters for domain size

L=20;
H=10;

Brownian motion parameters

dt=1e-3;
dtrt=sqrt(dt);
sigx=1e-2*H;
sigz=1e-2*H;

Birth process parameters

Uniform random number larger than this gives birth.

birth_thresh=0.975;

Uniform random number larger than this gives death.

death_thresh=0.97575;

Hunter parameters

hunter_rad=0.05*min(L,H);
hunter_sigx0=2e-1*H;
hunter_sigz0=2e-1*H;
hunter_sigx=hunter_sigx0;
hunter_sigz=hunter_sigz0;
xhunter=0.25*L;
zhunter=0.5*H;

How many did I have to eat to slow down and eat more.

eattostop=10;

The number of time steps to slowdown for.

lengthstop=200;
whatiate=0;
eating=0;

Deterministic motion parameters

Mode number.

modenum=1;

Wave number.

k=2*pi/L;

Vertical wave number.

m=modenum*pi/H;

Buoyancy frequency.

N0=2e-2;

Buoyancy frequency squared.

N02=N0^2;

Frequency.

sigma=(N0*k*H)/sqrt(modenum^2*pi^2+k*H*k*H);

Period.

myper=2*pi/sigma;

Wave amplitude.

amp=0.025*100;

Flow solution to Internal Wave problem.

psi=@(x,z,t) amp*cos(k*x).*sin(m*z)*cos(sigma*t);
u=@(x,z,t) amp*cos(k*x).*cos(m*z)*m*cos(sigma*t);
w=@(x,z,t) amp*k*sin(k*x).*sin(m*z)*cos(sigma*t);

Time stepping parameters

numsteps=20;
numouts=20;

Allocate and Initialize

Allocate arrays particles.

x=-1e4*ones(numparts,1);
z=-1e4*ones(numparts,1);
alive=zeros(numparts,1);

Initialize particles.

x(1:numactive,1)=L*rand(numactive,1);
z(1:numactive,1)=H*rand(numactive,1);
alive(1:numactive)=1;

Grid for velocity field pictures.

myxs=linspace(0,1*L,1000);
myzs=linspace(0,H,100);
[xx ,zz]=meshgrid(myxs,myzs);
t=0;
totdead=zeros(numouts);
totborn=zeros(numouts);
toteaten=zeros(numouts);

Primary Loop

for ii=1:numouts
    totdead(ii)=0;
    totborn(ii)=0;
    toteaten(ii)=0;
    for jj=1:numsteps

Advect and diffuse the active particles.

        pertx=sigx*randn(numactive,1);
        pertz=sigz*randn(numactive,1);
        x(1:numactive,1)=mod(x(1:numactive,1)+alive(1:numactive).*(dt*u(x(1:numactive,1),z(1:numactive,1),t)+dtrt*pertx),L);
        z(1:numactive,1)=z(1:numactive,1)+alive(1:numactive).*(dt*w(x(1:numactive,1),z(1:numactive,1),t)+dtrt*pertz);
        z(1:numactive,1)=H-abs(z(1:numactive,1)-H);
        perthunterx=hunter_sigx*randn(1,1);
        perthunterz=hunter_sigz*randn(1,1);
        xhunter=mod(xhunter+dt*u(xhunter,zhunter,t)+dtrt*perthunterx,L);
        zhunter=zhunter+dt*w(xhunter,zhunter,t)+dtrt*perthunterz;
        zhunter=H-abs(zhunter-H);
        t=t+dt;

Natural death, do this first so you're not always killing the newborns.

        deathpert=rand(numactive,1);
        deathcheck=(deathpert>death_thresh);
        numdead=sum(deathcheck);
        numactive=numactive-numdead;
        totdead(ii)=totdead(ii)+numdead;

Birth new particles.

        birthpert=rand(numactive,1);
        birthcheck=(birthpert>birth_thresh);
        numborn=sum(birthcheck);
        totborn(ii)=totborn(ii)+numborn;

Get born next to parent where parents are automatically at the end Put the newborns at the front of the queue so they are not the first to die.

        dummyx=x(1:numactive);
        dummyz=z(1:numactive);
        x(1:numborn)=x(numactive-numborn+1:numactive);
        z(1:numborn)=z(numactive-numborn+1:numactive);
        x(numborn+1:numactive+numborn)=dummyx;
        z(numborn+1:numactive+numborn)=dummyz;
        numactive=numactive+numborn;
        alive=zeros(numparts,1);
        alive(1:numactive)=1;

Can you eat it?

        huntdist=sqrt((x(1:numactive,1)-xhunter*ones(numactive,1)).^2+(z(1:numactive,1)-zhunter*ones(numactive,1)).^2);
        eaten=find(huntdist<hunter_rad);
        toteaten(ii)=toteaten(ii)+length(eaten);
        alive(eaten)=0;
        x(eaten,1)=-1e10;
        z(eaten,1)=-1e10;
        deadind=find(alive==0);
        didIeat=length(eaten);
        whatiate=whatiate+didIeat;
        eating=eating*(didIeat<eattostop+1)+lengthstop*(didIeat>eattostop);
        sigfactor=0.01*(eating>0)+1*(eating==0);

If the hunter has just eaten it will stop to look around. This is achieved by lowering its standard deviation.

        hunter_sigx=hunter_sigx0*sigfactor;
        hunter_sigz=hunter_sigz0*sigfactor;
        eating=max(eating-1,0);
    end

Plot

    figure(1)
    set(gcf,'DefaultLineLineWidth',1,'DefaultTextFontSize',14,...
        'DefaultAxesFontSize',14);
    clf
    diagfact=1/sqrt(2);
    pcolor(xx,zz,psi(xx,zz,t)/amp),shading flat
    hold on
    plot(x(1:numactive,1),z(1:numactive,1),'k.','Markersize',4)
    plot(xhunter,zhunter,'ko','Markersize',8)
    plot(mod(xhunter+hunter_rad,L),(zhunter),'ko','Markersize',4)
    plot(mod(xhunter-hunter_rad,L),(zhunter),'ko','Markersize',4)
    plot(mod(xhunter,L),(zhunter+hunter_rad),'ko','Markersize',4)
    plot(mod(xhunter,L),(zhunter-hunter_rad),'ko','Markersize',4)
    plot(mod(xhunter+diagfact*hunter_rad,L),(zhunter-diagfact*hunter_rad),'ko','Markersize',4)
    plot(mod(xhunter-diagfact*hunter_rad,L),(zhunter-diagfact*hunter_rad),'ko','Markersize',4)
    plot(mod(xhunter-diagfact*hunter_rad,L),(zhunter+diagfact*hunter_rad),'ko','Markersize',4)
    plot(mod(xhunter+diagfact*hunter_rad,L),(zhunter+diagfact*hunter_rad),'ko','Markersize',4)
    myindalive=(alive(1:numactive)==1);
    title(['Number of active prey ' int2str(sum(myindalive))])
    drawnow

Update

Now remove the eaten particles.

    livingind=find(alive==1);
    dummyx=x(livingind);
    dummyz=z(livingind);
    numactive=length(dummyx);

Allocate arrays particles.

    x=-1e4*ones(numparts,1);
    z=-1e4*ones(numparts,1);
    alive=zeros(numparts,1);
    alive(1:numactive)=1;
    x(1:numactive)=dummyx;
    z(1:numactive)=dummyz;
end