Random walk among obstacles

Solid obstacles are described by signed distance functions and grouped in Obstacles sets; each set defines what happens when a microbe touches its surface (its contact rule). Sets are passed as a Tuple in the :obstacles model property, and the domain boundaries can be made solid with Walls.

Here we generate a random packing of disks, on which bacteria slide, inside a box with reflecting walls. Unlike the pathfinder approach, surfaces are exact (no discretization).

using MicrobeAgents
using Random
using Plots

dt = 0.1 # s
L = 300.0 # μm
space = ContinuousSpace((L, L); periodic = false)

# random sequential addition of non-overlapping disks
function disk_packing(rng, L, φ, rmin, rmax; maxtries = 100_000)
    disks = ObstacleSphere{2}[]
    area = 0.0
    for _ in 1:maxtries
        area ≥ φ * L^2 && break
        r = rmin + (rmax - rmin) * rand(rng)
        c = SVector(rand(rng) * L, rand(rng) * L)
        any(d -> sdf(d, c) < r, disks) && continue
        push!(disks, ObstacleSphere(c, r))
        area += π * r^2
    end
    disks
end
rng = Xoshiro(1)
disks = disk_packing(rng, L, 0.4, 10.0, 20.0)

obstacle_sets = (
    Obstacles(space, disks; contact = Slide()),
    Walls(space; contact = Reflect()),
)
model = StandardABM(Microbe{2}, space, dt; rng, container = Vector,
    properties = Dict(:obstacles => obstacle_sets))

motility = RunTumble(run_speed = [20.0], run_duration = 1.0, angle = Isotropic(2))
for _ in 1:10
    # sample initial positions outside the obstacles
    pos = random_free_position(model; radius = 0.5)
    add_agent!(pos, model; motility, radius = 0.5, rotational_diffusivity = 0.035)
end
adf, _ = run!(model, 1000; adata = [position])
traj = Analysis.adf_to_matrix(adf, :position)

circle(d) = Shape(
    [d.center[1] + d.radius * cos(t) for t in range(0, 2π, 64)],
    [d.center[2] + d.radius * sin(t) for t in range(0, 2π, 64)],
)
plot(xlims = (0, L), ylims = (0, L), ratio = 1, axis = false, grid = false, leg = false)
foreach(d -> plot!(circle(d), c = :gray, lw = 0), disks)
plot!(first.(traj), last.(traj))
Example block output