Agent Based Model Practical 7

1. Introduction and Preparation

In this practical matplotlib.animation.FuncAnimation will be used to animate the model in a separate window. Some stopping conditions will be added to halt the model and exit.

In your local code repository 'src' directory duplicate your 'abm6' directory and call the new directory 'abm7'.

2. Animation

Open the new 'model.py' file from the 'abm7' directory in Spyder.

Add the following import statement:

import matplotlib.animation as anim

After initialising agents add the following code block:

# Animate
# Initialise fig and carry_on
fig = matplotlib.pyplot.figure(figsize=(7, 7))
ax = fig.add_axes([0, 0, 1, 1])
carry_on = True
data_written = False
animation = anim.FuncAnimation(fig, update, init_func=plot, frames=gen_function, repeat=False)

Define a new function called 'plot' to contain the 'Plot agents' code. Add a line to clear fig at the start of the function and specify 'ite' as a global variable before it is used:

def plot():
fig.clear()
plt.ylim(y_min, y_max)
plt.xlim(x_min, x_max)
plt.imshow(environment)
for i in range(n_agents):
    plt.scatter(agents[i].x, agents[i].y, color='black')
# Plot the coordinate with the largest x red
lx = max(agents, key=operator.attrgetter('x'))
plt.scatter(lx.x, lx.y, color='red')
# Plot the coordinate with the smallest x blue
sx = min(agents, key=operator.attrgetter('x'))
plt.scatter(sx.x, sx.y, color='blue')
# Plot the coordinate with the largest y yellow
ly = max(agents, key=operator.attrgetter('y'))
plt.scatter(ly.x, ly.y, color='yellow')
# Plot the coordinate with the smallest y green
sy = min(agents, key=operator.attrgetter('y'))
plt.scatter(sy.x, sy.y, color='green')
global ite
filename = '../../data/output/images/image' + str(ite) + '.png'
plt.savefig(filename)
images.append(imageio.imread(filename))
plt.show()

Change the 'main simulation loop' code block into a function called 'update' that has a parameter called 'frames'. At the end of this call the 'plot' function. Specify 'carry_on' as a global variable and add a random stopping condition as follows:

def update(frames):
    # Model loop
    #for ite in range(1, n_iterations + 1):
    print("Iteration", frames)
    # Move agents
    print("Move and eat")
    for i in range(n_agents):
        agents[i].move(x_min, y_min, x_max, y_max)
        agents[i].eat()
        #print(agents[i])
    # Share store
    print("Share")
    # Distribute shares
    for i in range(n_agents):
        agents[i].share(neighbourhood)
    # Add store_shares to store and set store_shares back to zero
    for i in range(n_agents):
        #print(agents[i])
        agents[i].store = agents[i].store_shares
        agents[i].store_shares = 0
    #print(agents)
    # Print the maximum distance between all the agents
    print("Maximum distance between all the agents", get_max_distance())
    # Print the total amount of resource
    sum_as = sum_agent_stores()
    print("sum_agent_stores", sum_as)
    sum_e = sum_environment()
    print("sum_environment", sum_e)
    print("total resource", (sum_as + sum_e))

    # Stopping condition
    global carry_on
    # Random
    if random.random() < 0.1:
        #if sum_as / n_agents > 80:
        carry_on = False
        print("stopping condition")

    # Plot
    plot()

Define a function called 'gen_function' as follows:

def gen_function():
    global ite
    global carry_on
    while (ite <= n_iterations) & (carry_on) :
        yield ite # Returns control and waits next call.
        ite = ite + 1
    global data_written
    if data_written == False:
        # Write data
        print("write data")
        io.write_data('../../data/output/out.txt', environment)
        imageio.mimsave('../../data/output/out.gif', images, fps=3)
        data_written = True

Before running the code, issue the following magic command in the Spyder console so that rather than the plot being directed to the plots pane (where animation does not work), it is directed to a pop-up window:

%matplotlib qt

If you want to revert this change so that plots are added to the plot plane again issue the following magic command:

%matplotlib inline

The keyword 'yield' is used to pass the value of the variable 'ite' back from 'gen_function' whilst continuing to run the while loop. The '# Write data' code block is included in 'gen_function' and runs only once after the model has stopped.

Commit your code to your local repository and assuming you are using GitHub - push your changes to GitHub.

3. Code and Model Review

Most of your code should now be in functions and organised into modules.

The model simulation runs in a loop until some condition is reached, or until a predefined number of iterations 'n_iterations' is reached.

As yet, the model cannot be re-started. Some data is written to file that could be used to restart the model, but this is incomplete/insufficient. The ability to be able to stop and restart a model can be useful and is often called 'check pointing'. It would be good if the model could be run for 'n' iterations and then run for a further 'm' iterations and for this to produce the same results as a run of 'm + n' iterations. The 'random.getstate()' and 'random.setstate(state)' methods could be used to checkpoint random to help get this to work.

The simple agents in the model are not learning or adapting their behaviour based on interaction or the state of the environment. The model is mostly random, so observing complex, adaptive/emergent behaviour from this model should not be expected.

Whilst the model has been framed as an ecological model, the agents could represent other things, they don't necessarily have to communicate by sharing resources, they could share something else, and they don't have to 'eat' the environment.

Some ideas for a more realistic ecological model are:

4. Further Assignment 1 Coding Task

Alter the stopping condition so that the model stops when the average agent store is greater than 80.

Commit your code to your local repository and assuming you are using GitHub - push your changes to GitHub.