My code takes only one center point, so only circles can be obtained. Apart from turtle location plot given in NetLogo implementation I added:
- plot showing maximal difference between turtle distance and target distance;
- decreasing turtle step size.
Below is the code generating the simulation:
# n: number of turtles # p.x, p.y: location of center # range: turtles have random position from [0,range] # and will move in random angle a # step: how fast turtles move # target: target distance from center # time: simulation time init <- function(n, p.x, p.y, range, step, target, time) { sim <- list( turtles = data.frame(x = runif(n, max = range), y = runif(n, max = range), a = runif(n, max = 2 * pi)), p.x = p.x, p.y = p.y, step = step, target = target, time = time, max.dist = rep(NA, time)) # Calculate turtle distance from center sim$turtles$dist <- sqrt((sim$turtles$x - p.x) ^ 2 + (sim$turtles$y - p.y) ^ 2) return(sim) } step <- function(sim) { x <- sim$turtles$x y <- sim$turtles$y # Remember last distance and save current distance o.dist <- sim$turtles$dist n.dist <- sqrt((x - sim$p.x) ^ 2 + (y - sim$p.y) ^ 2) sim$turtles$dist <- n.dist # For turtles that are too far and are moving out # or too close and are moving in randomly change direction w.dist <- ((n.dist < o.dist) & (n.dist < sim$target)) | ((n.dist > o.dist) & (n.dist > sim$target)) sim$turtles$a[w.dist] <- runif(sum(w.dist), max = 2 * pi) sim$turtles$x <- x + sin(sim$turtles$a) * sim$step sim$turtles$y <- y + cos(sim$turtles$a) * sim$step return(sim) } do.plot <- function(sim) { rng <- quantile(c(sim$turtles$x, sim$turtles$y), c(0.05, 0.95)) rng <- round(rng, -1) + c(-10, 10) par(mai = rep(0.5, 4), mfrow = c(1, 2)) plot(sim$turtles$x, sim$turtles$y, pch = ".", xlim = rng, ylim = rng, xlab = "", ylab = "", main = "Turtle location") points(sim$p.x, sim$p.y, col = "red", pch = 20, cex = 2) plot(sim$max.dist, type = "l", ylim = c(0, max(sim$max.dist, na.rm = TRUE) + 5), xlab = "", ylab = "", main = "Max difference from target") } run <- function(sim) { for (i in 1:sim$time) { sim <- step(sim) sim$step <- sim$step * 127 / 128 sim$max.dist[i] <- max(sim$turtles$dist) - sim$target do.plot(sim) } } sim <- init(4096, 128, 128, 256, 2, 128, 512) set.seed(0) run(sim)
Very fun to run and watch!
ReplyDeleteYou are decreasing the step size at a constant rate: the new step is (127/128) of the previous. For some initial conditions this might be too slow or too fast. I wonder if you can tie the rate to the number of simulations? For example, if you use
r <- (1e-2)**(1/sim$time)
...
sim$step <- sim$step * r
then the step is getting very small at about the same time that the simulation ends.
Another option is to use adaptive step size:
ReplyDeletesim$step <- (max(sim$turtles$dist) - sim$target) / 16
Interestingly for small divisors (for given parameters treshold seems to be around 10) the process diverges due to randomness of angle.