Abelian Sandpile

using EasyABM

Step 1: Create Model

In this model, we work with patches only. We set grid_size to (50,50), set space_type to NPeriodic and define an additional model parameter threshold whose value is set to 4.

model = create_2d_model(size = (50,50), space_type=NPeriodic, threshold = 4)

Step 2: Initialise the model

Initially, we set the amount of sand on all patches equal to 2 except for the patch (25,25) where we set the sand amount to value 2000. The color attribute of patches is set according to the amount of sand they carry. If the sand amound on a patch is >=4 then its color is blue, otherwise the color is set according to dictionary coldict.

const coldict = Dict(0=>cl"white", 1=>cl"yellow", 2=>cl"green", 3=> cl"orange", 4=>cl"red")

function initialiser!(model)
    for j in 1:model.size[2]
        for i in 1:model.size[1]
            model.patches[i,j].sand = 2
            model.patches[i,j].color= coldict[2]
        end
    end
    model.patches[25,25].sand = 2000
    model.patches[25,25].color= cl"blue"
end

init_model!(model, initialiser = initialiser!, props_to_record = Dict("patches" => Set([:color,:sand])))

Step 3: Defining the step_rule! and running the model

In the step function we loop over all the patches and if a patch has sand >= 4, we topple that patch which means that i) We reduce the amount of sand on that patch by 4 ii) We increase the amount of sand on its Von Neumann neighboring patches by 1.


function topple!(patch_loc, model, threshold)
    nbr_patch_locs = neighbor_patches_neumann(patch_loc, model, 1)
    for p in nbr_patch_locs
        pth_patch = model.patches[p...]
        sand = pth_patch.sand + 1
        pth_patch.sand = sand
        pth_patch.color = sand <= 4 ? coldict[sand] : cl"blue" 
    end
    patch = model.patches[patch_loc...]
    sand = patch.sand-threshold
    patch.sand = sand
    patch.color = sand <= 4 ? coldict[sand] : cl"blue" 
end

function step_rule!(model)
    threshold = model.properties.threshold
    for j in 1:model.size[2]
        for i in 1:model.size[1]
            if model.patches[i,j].sand>=threshold
                topple!((i,j),model, threshold)
            end
        end
    end
end

run_model!(model, steps = 1000, step_rule = step_rule!)

Step 4: Visualisation

In order to draw the model at a specific frame, say 4th, one can use draw_frame(model, frame = 4 ). If one wants to see the animation of the model run, it can be done as

animate_sim(model)

png

After defining the step_rule! function we can also choose to create an interactive application (which currently works in Jupyter with WebIO installation) as shown below. It is recommended to define a fresh model and not initialise it with init_model! or run with run_model! before creating interactive app.

model = create_2d_model(size = (50,50), space_type=NPeriodic, threshold = 4) 

create_interactive_app(model, initialiser= initialiser!,
    props_to_record = Dict("patches" => Set([:color])),
    model_controls = [(:threshold, "slider", 1:10)],
    step_rule= step_rule!,frames=500, show_patches=true) 

png

Step 5: Fetch Data

It is easy to fetch any recorded data after running the model. For example, the numbers of patches with different amounts of sand at all timesteps can be got as follows

df = get_nums_patches(model, 
    patch-> patch.sand == 0, 
    patch-> patch.sand == 1, 
    patch-> patch.sand == 2, 
    patch-> patch.sand == 3,
    labels=["sand=0","sand=1","sand=2","sand=3"], plot_result=true)

png

References

1.) https://en.wikipedia.org/wiki/Abeliansandpilemodel