RunSim <- function(model, params, max.time=1000, sampling.interval=0.1,
B0=Biomass(params$community))
{
# A testing helper that run a model and returns the resulting time series.
simulation <- ODESimulation(model=model,
params=params,
sampling.interval=sampling.interval,
extinction.threshold=1e-20)
# Collect simulation results in memory
collector <- CollectChunksObserver()
res <- RunSimulation(initial.state=B0,
simulation=simulation,
controller=MaxTimeController(max.time=max.time),
observers=list(collector))
return (GetTimeSeries(collector))
}
TestGrowthModel <- function()
{
# Test R and C growth model implementations
GrowthDyDt <- function(time, y, params)
{
# Two producer growth model implementation
R1 <- y[1]
R2 <- y[2]
with(params,
{
return (list(c(R1=rho1 * R1 * (1-(a11*R1 + a21*R2)/K),
R2=rho2 * R2 * (1-(a12*R1 + a22*R2)/K)),
globals=NULL))
})
}
# SCENARIO 1 - all competition coefficients equal
# Run simulation using noddy implementation
community <- Community(nodes=data.frame(node=c('R1','R2'), M=c(1,1),
N=c(150,100),
category=rep('producer', 2)),
properties=list(title='Two producers motif',
M.units='kg', N.units='m^-2'))
params <- list(rho1=1, rho2=1, a11=1, a12=1, a21=1, a22=1, K=500,
community=community)
tseries1 <- RunSim(GrowthDyDt, params)
# Run simulation using YodzisInnes C implementation
spec <- ModelParamsSpec()
params <- IntermediateModelParams(community, spec)
params <- BuildModelParams(community, params) # containing rho,x,z etc
tseries2 <- RunSim(YodzisInnesDyDt, params)
# Run simulation using YodzisInnes R implementation
tseries3 <- RunSim(YodzisInnesDyDt_R, params)
stopifnot(isTRUE(all.equal(tseries1, tseries2)))
stopifnot(isTRUE(all.equal(tseries1, tseries3)))
# SCENARIO 2 - advantage for R1
# Run simulation using noddy implementation
params <- list(rho1=1, rho2=1, a11=1, a12=1.1, a21=1, a22=1, K=500,
community=community)
tseries1 <- RunSim(GrowthDyDt, params)
# Run simulation using YodzisInnes C implementation
spec <- ModelParamsSpec()
params <- IntermediateModelParams(community, spec)
params <- BuildModelParams(community, params) # containing rho,x,z etc
params$a['R2','R1'] <- 1.1
tseries2 <- RunSim(YodzisInnesDyDt, params)
# Run simulation using YodzisInnes R implementation
tseries3 <- RunSim(YodzisInnesDyDt_R, params)
stopifnot(isTRUE(all.equal(tseries1, tseries2)))
stopifnot(isTRUE(all.equal(tseries1, tseries3)))
# SCENARIO 3 - advantage for R1 with a different order of producers.
# This is to test the matrix multiplication stuff in the C implementation.
community <- Community(nodes=data.frame(node=c('R2','R1'), M=c(1,1),
N=c(100,150),
category=rep('producer', 2)),
properties=list(title='Two producers motif',
M.units='kg', N.units='m^-2'))
# Run simulation using YodzisInnes C implementation
spec <- ModelParamsSpec()
params <- IntermediateModelParams(community, spec)
params <- BuildModelParams(community, params) # containing rho,x,z etc
params$a['R2','R1'] <- 1.1
tseries2 <- RunSim(YodzisInnesDyDt, params)
# Run simulation using YodzisInnes R implementation
tseries3 <- RunSim(YodzisInnesDyDt_R, params)
stopifnot(isTRUE(all.equal(tseries1, tseries2[,c('time','R1','R2')])))
stopifnot(isTRUE(all.equal(tseries1, tseries3[,c('time','R1','R2')])))
# SCENARIO 4 - advantage for R1 with some non-connected consumers and a
# different order of producers. This is to test the matrix multiplication
# stuff in the C implementation.
community <- Community(nodes=data.frame(node=c('C1','R2','C2','R1','C3'),
M=rep(1, 5),
N=c(1,100,2,150,3),
category=c('invertebrate',
'producer',
'invertebrate',
'producer',
'invertebrate')),
properties=list(title='Two producers motif',
M.units='kg', N.units='m^-2'))
# Run simulation using YodzisInnes C implementation
spec <- ModelParamsSpec()
params <- IntermediateModelParams(community, spec)
params <- BuildModelParams(community, params) # containing rho,x,z etc
params$a['R2','R1'] <- 1.1
tseries2 <- RunSim(YodzisInnesDyDt, params)
# Run simulation using YodzisInnes R implementation
tseries3 <- RunSim(YodzisInnesDyDt_R, params)
stopifnot(isTRUE(all.equal(tseries1[,], tseries2[,c('time','R1','R2')])))
stopifnot(isTRUE(all.equal(tseries1[,], tseries3[,c('time','R1','R2')])))
}
TestYodzisInnesModelMotifs <- function()
{
# Ensures that the R and C model implementations both give the same time
# series for a number of motifs.
SingleProducer <- function()
{
community <- Community(nodes=data.frame(node='R', category='producer',
M=10, N=10),
properties=list(title='Single producer',
M.units='kg', N.units='m^-2'))
# Model parameters
spec <- ModelParamsSpec()
params <- IntermediateModelParams(community, spec)
params <- BuildModelParams(community, params) # containing rho,x,z etc
equilibria <- c(R=params$K)
return (list(params=params, equilibria=equilibria))
}
TwoProducer <- function()
{
community <- Community(nodes=data.frame(node=c('R1','R2'), M=c(1,1),
N=c(150,100),
category=rep('producer', 2)),
properties=list(title='Two producers motif',
M.units='kg', N.units='m^-2'))
# Model parameters
spec <- ModelParamsSpec()
params <- IntermediateModelParams(community, spec)
params <- BuildModelParams(community, params) # containing rho,x,z etc
# as.numeric() to get rid of names
aR1R1 <- with(params, a['R1','R1'])
aR1R2 <- with(params, a['R1','R2'])
aR2R1 <- with(params, a['R2','R1'])
aR2R2 <- with(params, a['R2','R2'])
rhoR1 <- with(params, as.numeric(rho['R1']))
rhoR2 <- with(params, as.numeric(rho['R2']))
K <- with(params, K)
# Equilibria calculated by Mathematica 8 - silly
equilibria <- c(R1e=-(-aR2R1*K+aR2R2*K) / (aR1R2*aR2R1-aR1R1*aR2R2),
R2e=-( aR1R1*K-aR1R2*K) / (aR1R2*aR2R1-aR1R1*aR2R2))
N <- NP(community, 'N')
Ntot <- unname(N['R1'] + N['R2'])
ratio <- unname(N['R1'] / Ntot)
equilibria <- c(R1e=params$K * unname(N['R1']) / Ntot,
R2e=params$K * unname(N['R2']) / Ntot)
return (list(params=params, equilibria=equilibria))
}
ResourceConsumer <- function()
{
community <- Community(nodes=data.frame(node=c('R','C'),
M=c(1,5),
N=c(150,50),
category=c('producer',
'invertebrate')),
trophic.links=data.frame(resource='R',
consumer='C'),
properties=list(title='Resource-consumer motif',
M.units='kg', N.units='m^-2'))
# Model parameters
spec <- ModelParamsSpec(f.constants=AllFConstantsEqual())
params <- IntermediateModelParams(community, spec)
params <- BuildModelParams(community, params) # containing rho,x,z etc
# as.numeric() to get rid of names
rhoR <- with(params, as.numeric(rho['R']))
K <- with(params, K)
xC <- with(params, as.numeric(x['C']))
yRC <- with(params, as.numeric(y['R','C']))
feRC <- with(params, as.numeric(fe['R','C']))
eRC <- with(params, as.numeric(e['R','C']))
WRC <- with(params, as.numeric(W['R','C']))
q <- with(params, as.numeric(q))
# Equilibria: eqns 12 and 13 of Yodzis and Innes (1992) on p.1160
# using x and y given in eqns 10 and 11, p 1156.
Re <- WRC / (yRC-1)
yi.equilibria <- c(Re=Re,
Ce=(feRC*eRC / xC) * Re * (1-Re/K))
# Equilibria calculated by Mathematica 8.
equilibria <- c(Re=WRC*(1/(-1+yRC)) ^ (1/(1+q)),
Ce=-WRC*eRC*feRC*rhoR *
(-K + WRC*(-1/(1-yRC))^(1/(1+q))) *
(-1/(1-yRC))^(1/(1+q)) / (K*xC) )
# Equilibria from Rall et al 2008 Oikos, equations 7 and 8?
stopifnot(isTRUE(all.equal(equilibria, yi.equilibria)))
return (list(params=params, equilibria=equilibria))
}
ThreeSpeciesChain <- function()
{
community <- Community(nodes=data.frame(node=c('R','C1','C2'),
M=c(1,5,100),
N=c(200,20,1),
category=c('producer',
rep('invertebrate', 2))),
trophic.links=data.frame(resource=c( 'R', 'C1'),
consumer=c('C1', 'C2')),
properties=list(title='Three-species chain motif',
M.units='kg', N.units='m^-2'))
# Model parameters
spec <- ModelParamsSpec(f.constants=AllFConstantsEqual())
params <- IntermediateModelParams(community, spec)
params <- BuildModelParams(community, params) # containing rho,x,z etc
# Link-specific deviations that will be seen in equilibria
params$W['R','C1'] <- 5000
params$fe['R','C1'] <- 0.6
# Equilibria calculated by Mathematica 8.
# as.numeric() to get rid of names
rhoR <- with(params, as.numeric(rho['R']))
K <- with(params, K)
xC1 <- with(params, as.numeric(x['C1']))
xC2 <- with(params, as.numeric(x['C2']))
yRC1 <- with(params, as.numeric(y['R', 'C1']))
yC1C2 <- with(params, as.numeric(y['C1','C2']))
feRC1 <- with(params, as.numeric(fe['R', 'C1']))
feC1C2 <- with(params, as.numeric(fe['C1','C2']))
eRC1 <- with(params, as.numeric(e['R', 'C1']))
eC1C2 <- with(params, as.numeric(e['C1','C2']))
WRC1 <- with(params, as.numeric(W['R', 'C1']))
WC1C2 <- with(params, as.numeric(W['C1','C2']))
q <- with(params, as.numeric(q))
equilibria <- c(Re=WRC1/(-1 + yRC1),
C1e=-((WRC1*eRC1*feRC1*rhoR*(WRC1 + K - K*yRC1)) /
(K*xC1*(-1 + yRC1)^2)),
C2e=0)
return (list(params=params, equilibria=equilibria))
}
IGP <- function()
{
community <- Community(nodes=data.frame(node=c('R','C1','C2'),
M=c(1,5,10),
N=c(150,50,1),
category=c('producer',
rep('invertebrate', 2))),
trophic.links=data.frame(resource=c( 'R', 'R','C1'),
consumer=c('C1','C2','C2')),
properties=list(title='IGP motif',
M.units='kg', N.units='m^-2'))
# Model parameters
spec <- ModelParamsSpec()
params <- IntermediateModelParams(community, spec)
params <- BuildModelParams(community, params) # containing rho,x,z etc
# Link-specific deviations that will be seen in equilibria
params$W['R','C1'] <- 5000
params$W['R','C2'] <- 500
params$fe['R','C2'] <- 0.6
# Equilibria calculated by Mathematica 8.
# q and d must be 0.
# as.numeric() to get rid of names
rhoR <- with(params, as.numeric(rho['R']))
K <- with(params, K)
xC1 <- with(params, as.numeric(x['C1']))
xC2 <- with(params, as.numeric(x['C2']))
yRC1 <- with(params, y['R', 'C1'])
yRC2 <- with(params, y['R', 'C2'])
yC1C2 <- with(params, y['C1','C2'])
WRC1 <- with(params, W['R', 'C1'])
WRC2 <- with(params, W['R', 'C2'])
WC1C2 <- with(params, W['C2','C2'])
eRC1 <- with(params, e['R', 'C1'])
eRC2 <- with(params, e['R', 'C2'])
eC1C2 <- with(params, e['C1','C2'])
feRC1 <- with(params, fe['R', 'C1'])
feRC2 <- with(params, fe['R', 'C2'])
feC1C2 <- with(params, fe['C1','C2'])
equilibria <- c(Re=WRC2 / (-1+yRC2),
C1e=0,
C2e=-((WRC2*eRC2*feRC2*rhoR*(WRC2 + K - K*yRC2)) /
(K*xC2*(-1 + yRC2)^2)) )
return (list(params=params, equilibria=equilibria))
}
ExploitativeCompetition <- function()
{
community <- Community(nodes=data.frame(node=c('R','C1','C2'),
M=c(1,5,10),
N=c(150,50,1),
category=c('producer',
rep('invertebrate', 2))),
trophic.links=data.frame(resource=c( 'R', 'R'),
consumer=c('C1','C2')),
properties=list(title='Exploitative competition motif',
M.units='kg', N.units='m^-2'))
# Model parameters
spec <- ModelParamsSpec()
params <- IntermediateModelParams(community, spec)
params <- BuildModelParams(community, params) # containing rho,x,z etc
# Link-specific deviations that will be seen in equilibria
params$W['R','C1'] <- 5000
params$W['R','C2'] <- 500
params$fe['R','C2'] <- 0.6
# Equilibria calculated by Mathematica 8.
# q and d must be 0.
# as.numeric() to get rid of names
rhoR <- with(params, as.numeric(rho['R']))
K <- with(params, K)
xC1 <- with(params, as.numeric(x['C1']))
xC2 <- with(params, as.numeric(x['C2']))
yRC1 <- with(params, y['R', 'C1'])
yRC2 <- with(params, y['R', 'C2'])
WRC1 <- with(params, W['R', 'C1'])
WRC2 <- with(params, W['R', 'C2'])
eRC1 <- with(params, e['R', 'C1'])
eRC2 <- with(params, e['R', 'C2'])
feRC1 <- with(params, fe['R', 'C1'])
feRC2 <- with(params, fe['R', 'C2'])
equilibria <- c(Re=WRC2 / (-1+yRC2),
C1e=0,
C2e=-((WRC2*eRC2*feRC2*rhoR*(WRC2 + K - K*yRC2)) /
(K*xC2*(-1 + yRC2)^2)) )
return (list(params=params, equilibria=equilibria))
}
ApparentCompetition <- function()
{
community <- Community(nodes=data.frame(node=c('R1','R2','C'),
M=c(1,5,10),
N=c(150,150,20),
category=c(rep('producer', 2),
'invertebrate')),
trophic.links=data.frame(resource=c('R1', 'R2'),
consumer=c('C', 'C')),
properties=list(title='Apparent competition motif',
M.units='kg', N.units='m^-2'))
spec <- ModelParamsSpec()
params <- IntermediateModelParams(community, spec)
params <- BuildModelParams(community, params) # containing rho,x,z etc
# Link-specific deviations that will be seen in equilibria
params$W['R1','C'] <- 1100
params$W['R2','C'] <- 900
params$fe['R2','C'] <- 0.6
# Equilibria calculated by Mathematica 8.
# q and d must be 0.
# as.numeric() to get rid of names
aR1R1 <- with(params, a['R1','R1'])
aR1R2 <- with(params, a['R1','R2'])
aR2R1 <- with(params, a['R2','R1'])
aR2R2 <- with(params, a['R2','R2'])
rhoR1 <- with(params, as.numeric(rho['R1']))
rhoR2 <- with(params, as.numeric(rho['R2']))
rhoR1 <- with(params, as.numeric(rho['R1']))
rhoR2 <- with(params, as.numeric(rho['R2']))
K <- with(params, K)
xC <- with(params, as.numeric(x['C']))
yR1C <- with(params, y['R1','C'])
yR2C <- with(params, y['R2','C'])
WR1C <- with(params, W['R1','C'])
WR2C <- with(params, W['R2','C'])
eR1C <- with(params, e['R1','C'])
eR2C <- with(params, e['R2','C'])
feR1C <- with(params, fe['R1','C'])
feR2C <- with(params, fe['R2','C'])
equilibria <-c(R1e=WR1C/(-1 + yR1C),
R2e=0,
Ce=-((WR1C*eR1C*feR1C*rhoR1*(aR1R1*WR1C + K - K*yR1C))/
(K*xC*(-1 + yR1C)^2)) )
return (list(params=params, equilibria=equilibria))
}
ExploitativeAndApparentCompetition <- function()
{
community <- Community(nodes=data.frame(node=c('R','C1', 'C2', 'C3'),
M=c(1,2,10,100),
N=c(150,50,50,1),
category=c('producer',
rep('invertebrate', 3))),
trophic.links=data.frame(resource=c( 'R', 'R', 'C1', 'C2'),
consumer=c('C1','C2', 'C3', 'C3')),
properties=list(title='Exploitative and apparent competition motif',
M.units='kg', N.units='m^-2'))
# Model parameters
spec <- ModelParamsSpec()
params <- IntermediateModelParams(community, spec)
params <- BuildModelParams(community, params) # containing rho,x,z etc
# Link-specific deviations that will be seen in equilibria
params$W['R','C2'] <- 900
params$fe['R','C2'] <- 0.9
# Equilibria calculated by Mathematica 8.
# q and d must be 0.
# as.numeric() to get rid of names
rhoR <- with(params, as.numeric(rho['R']))
K <- with(params, K)
xC1 <- with(params, as.numeric(x['C1']))
xC2 <- with(params, as.numeric(x['C2']))
xC3 <- with(params, as.numeric(x['C3']))
yRC1 <- with(params, y['R', 'C1'])
yRC2 <- with(params, y['R', 'C2'])
yC1C3 <- with(params, y['C1','C3'])
yC2C3 <- with(params, y['C2','C3'])
WRC1 <- with(params, W['R', 'C1'])
WRC2 <- with(params, W['R', 'C2'])
WC1C3 <- with(params, W['C1', 'C3'])
WC2C3 <- with(params, W['C2', 'C3'])
eRC1 <- with(params, e['R', 'C1'])
eRC2 <- with(params, e['R', 'C2'])
eC1C3 <- with(params, e['C1', 'C3'])
eC2C3 <- with(params, e['C2', 'C3'])
feRC1 <- with(params, fe['R', 'C1'])
feRC2 <- with(params, fe['R', 'C2'])
feC1C3 <- with(params, fe['C1', 'C3'])
feC2C3 <- with(params, fe['C2', 'C3'])
equilibria <- c(Re=WRC2/(-1 + yRC2),
C1e=0,
C2e=-((WRC2*eRC2*feRC2*rhoR*(WRC2 + K - K*yRC2)) /
(K*xC2*(-1 + yRC2)^2)),
C3e=0)
return (list(params=params, equilibria=equilibria))
}
tests <- ls()
tests <- tests[sapply(tests, function(t) is.function(eval(parse(text=t))))]
for(test in tests)
{
cat(' TestModel running [', test, ']\n', sep='')
t <- do.call(test, args=list())
tseriesC <- RunSim(YodzisInnesDyDt, t$params)
tseriesR <- RunSim(YodzisInnesDyDt_R, t$params)
# TODO Why do some tests require this higher tolerance?
if(!isTRUE(all.equal(tseriesC, tseriesR)))
{
cat(' Fails at default tolerance\n')
stopifnot(isTRUE(all.equal(tseriesC, tseriesR, tolerance=1e-6)))
cat(' Succeeds at lower tolerance\n')
}
Bfinal <- as.vector(tail(tseriesC, 1)[,-1])
stopifnot(isTRUE(all.equal(as.numeric(t$equilibria),
as.numeric(Bfinal))))
}
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.