NetLogo Project Prototype: Exit II
From Backspaces Wiki
| NetLogo Tutorial |
In this module, we'll introduce the interactive procedure "go", adding the behavior to our model.
The turtles will be given the goal of exiting the "inside" of our landscape. Initially the goal will be the closest exit. But we'll also add a variation where the turtle will randomly choose an exit. The reason for this is an interesting aspect of crowd behavior observed in real-world panic situations: under stress, people much prefer exiting the way they entered the site. Due to mingling, this exit is seldom the closest one.
We will also make two modifications to the patches:
- Make the exits more realistically spread out by insuring they are not within a certain distance of each other.
- Add obstacles to the patches to mimic the Zozobra event's booths (and potentially injured people).
Contents |
Go: Basic Structure
As in our earlier models, add a "go" and "step" button, both of which call the go procedure, with the"go button using the "forever" checkbox.
Insert this go procedure just below the setup procedure. It uses the ticks counter, asks the turtles to move, and recalculates the population global variable to be the current number of turtles inside the walls. This is the basic structure of our model: ask the turtles to move towards their exit, and monitor the current population still inside.
Insert an empty "move" procedure just under our earlier setup-turtles procedure.
to setup ... end to go tick ask turtles [move] set population count turtles with [inside?] end ... to setup-turtles ... end to move end
You'll probably need to rearrange the UI a bit to get everything to fit. I moved the View a bit to the right, and resized the sliders to match the three buttons. Click the go and step buttons to make sure the tick counter advances as expected.
UI: Add Plot & Monitor
Next we'll add UI elements to watch the decrease in the population, or indirectly, the number of turtles who have successfully exited.
First, add a Plot UI component. Label it Population. Then add a Monitor, with "population" as its Reporter. We used a similar pair in the buttons model. The monitor gives the exact value of population, and the plot shows its change over time.
Add the following code for the plot. We set the plot ranges because it makes the plot much easier to read, as well as nicer looking. We add a fake move procedure to simulate the turtle's exiting (See Notes section):
to setup ... set-plot-y-range 0 population end to go ... plot population if not any? turtles [set-plot-x-range 0 ticks stop] end to move if (random population) = 0 [ask one-of turtles [die]] end
Lookup: set-plot-y-range/set-plot-y-range, plot, any?, random, die.
| | |
Move
We want the turtles to behave in a "rational" manner:
- Remove ourselves if we are at the exit. (See Notes for subtlety on where "if exit?" occurs.)
- Move toward exit .. i.e. reduce our distance to our exit.
- Don't move to an occupied patch.
- If no move is possible, skip this turn.
to move if exit? [die] let d distance exit let n neighbors with [ (not any? turtles-here) and (inside? or exit?) and (distance [exit] of myself < d)] if any? n [move-to one-of n] end
Lookup: turtles-here, move-to.
Now run this several times. We'll discover a few interesting things, even with the model this simple:
- The plot shows us a non-linear decrease in the population. This means choosing the closest exit is inefficient! By this I mean that, if each exit was used each tick, with 10 exits and an initial population of 1800 as we have here, we should be done at tick 180.
|
|
- The inefficiency is caused by some exits having more turtles using them than others. (This is obvious just after setup: the turtles are not uniformly distributed .. some color clusters are much larger than others.) This behavior is actually seen in the Zozobra crowd, and savvy attendees do indeed use less-used exits.
- Stalemates occur where turtles get in each other's way, and the current move algorithm fails to resolve the conflict. The image below shows two clusters of turtles unable to move due to being in each other's way.
Turtles Shapes and Outside
While showing the exit prototype to clients, we discovered that "dots on the wall" (i.e. showing the model with a projector) revealed a need for a bit more "reality" in the model. It was difficult for clients to think of the circular agents moving in a rectangle as people leaving the event site.
One way to making the prototype more understandable to clients was letting the turtles "escape" the inside by continuing out the exit rather than dying at the exit. This required re-structuring move to have different behavior for inside and outside turtles:
- Inside: same as earlier move with one exception. Rather than just moving to the new patch, the agent faces it then moves to the patch.
- Outside: Just move ahead unless you are at the edge (i.e. there are no patches ahead of you)
to move
ifelse inside?
[ let d distance exit
let n neighbors with
[ (not any? turtles-here) and (inside? or exit?) and (distance [exit] of myself < d)]
if any? n [face one-of n move-to patch-ahead 1] ]
[ ifelse patch-ahead 1 = nobody [die] [move-to patch-ahead 1] ]
end
Lookup: move-to, face, patch-ahead.
A second improvement is to use other turtle shapes, see the Shape Editor Guide and the shapes section of the Programming Guide. We first tried the "person" shape, but our prototype needed small patches, and the "person" shape did not show up well (see left, below). This was fixed in setup-turtles by changing the size of the turtles to be between 1.5 and 2, fractional sizes are OK (see right, below) See Notes for 3D person shape example.
| | |
To make it simple to change shapes and sizes, we added two new UI items: an agent-shape "chooser", and an agent-size slider. The slider setup: Global variable: agent-size; Min, Increment, Max: .25, .25, 3; Value: 1. The chooser setup: Global variable: agent-shape; Choices: "circle" "person" "default". Here is the new setup-turtles with these global variables:
to setup-turtles
set-default-shape turtles agent-shape
ask n-of population inside [ sprout 1
[ set exit min-one-of exits [distance myself]
set color [pcolor] of exit
set size agent-size]]
end
| | |
Random Exits
To choose a random exit rather than the closest, we add a Switch UI item (Global variable: random-exit?) and make a minor change to setup-turtles.
to setup-turtles
set-default-shape turtles agent-shape
ask n-of population inside [ sprout 1
[ ifelse random-exit?
[ set exit one-of exits ]
[ set exit min-one-of exits [distance myself] ]
set color [pcolor] of exit
set size agent-size]]
end
The main impact on the model is that the crowd always ends up in a huge stalemate! This can happen, as shown in the Move section above, with the nearest-exit setup, but is hugely magnified in the random setup.
| | |
Exit Spacing
Our current method for choosing random exits:
ask n-of num-exits patches with [pcolor = grey] [ set exit? true set pcolor (grey + 10 * count exits)]
.. has the advantage of being very simple, but the disadvantage of choosing very unrealistic layouts. The one on the left below is an extreme example with 4 exits crowded together on the top-right corner.
| | |
Replace the current method with one requiring a minimum distance between exits. Here we calculate the mean distance between exits, and use a fraction of that (the .5 multiple) for the min-dist between exits. We then randomly place the exits one at a time to obey our minimum distance requirement. This produces the more reasonable spread above, right. (See Notes for testing the min-dist multiplying factor choice.)
let min-dist .5 * (count patches with [pcolor = grey]) / num-exits repeat num-exits [ ask one-of patches with [pcolor = grey and not any? patches in-radius min-dist with [exit?]] [ set exit? true set pcolor (grey + 10 * count exits) ] ]
Obstacles
To simulate obstacles, all we need to do is to change some of the inside patches to not be inside. We add a slider to specify the number of obstacles, and make a minor change to the end of setup-patches. The Slider settings: Global variable: obstacles; Min, Increment, Max: 0, 50, 500; Value: 250).
We use a fairly complicated "ask" command:
- n-of obstacles inside: This chooses "obstacles" inside patches ..
- with [not any? neighbors4 with [exit?]]: where the obstacles do not block an exit
- ask: Uses these patches as obstacles by setting them to be not inside, and setting their color grey (like the wall).
to setup-patches ... ask n-of obstacles inside with [not any? neighbors4 with [exit?]] [ set pcolor grey set inside? false ] end
Run this several times, in the random-exit? set false. Generally some turtles are trapped by obstacles:
Summary
We've completed the basic model: Setting up the patches and turtles (previous module) and completing the go procedure for exiting the inside/walled area, with several additions such as random exits, obstacles, shapes and enhanced UI including a plot of the exit progress. We've seen areas we need to understand such as how to avoid obstacles and to resolve the stalemate of opposed motion of the turtles. We'll stop here, completing the prototypal investigation in our next module.
patches-own [exit? inside?]
globals [population]
turtles-own [exit]
to setup
ca
setup-patches
set population int (( %-population * count inside ) / 100)
setup-turtles
set-plot-y-range 0 population
end
to go
tick
ask turtles [move]
set population count turtles with [inside?]
plot population
if not any? turtles [set-plot-x-range 0 ticks stop]
end
to setup-patches
ask patches
[ set exit? false
set inside? (abs pycor < (.7 * max-pycor)) and (abs pxcor < (.7 * max-pxcor)) ]
ask inside [ ask neighbors4 with [not inside?] [set pcolor grey] ]
let min-dist .5 * (count patches with [pcolor = grey]) / num-exits
repeat num-exits
[ ask one-of patches with [pcolor = grey and not any? patches in-radius min-dist with [exit?]]
[ set exit? true set pcolor (grey + 10 * count exits) ] ]
ask n-of obstacles inside with [not any? neighbors4 with [exit?]]
[ set pcolor grey set inside? false ]
end
to setup-turtles
set-default-shape turtles agent-shape
ask n-of population inside [ sprout 1
[ ifelse random-exit?
[ set exit one-of exits ]
[ set exit min-one-of exits [distance myself] ]
set color [pcolor] of exit
set size agent-size ]]
end
to move
ifelse inside?
[ let d distance exit
let n neighbors with
[ (not any? turtles-here) and (inside? or exit?) and (distance [exit] of myself < d)]
if any? n [face one-of n move-to patch-ahead 1] ]
[ ifelse patch-ahead 1 = nobody [die] [move-to patch-ahead 1] ]
end
;; Simple utilities
to-report inside report patches with [inside?] end
to-report exits report patches with [exit?] end
Notes
- Fake move: The fake move command is called for each turtle every tick. If the "if random .." were not included, the program would stop almost immediately. A simpler solution would be to insert the "ask one-of .." command in the go loop, avoiding the multiple calls per tick. But this gives a more realistic, "stochastic" feel.
- Exit behavior: There is a subtle difference between testing for being at the exit at the top of move vs at the bottom. In other words, we could easily have used this instead:
to move let d distance exit let n neighbors with [ (not any? turtles-here) and (inside? or exit?) and (distance [exit] of myself < d)] if any? n [move-to one-of n] if exit? [die] end
The difference is that the exit test on top, as we used in the model, blocks the exit for that tick. In other words, once a turtle is in the exit during a move, it stays there until removed by the next tick. If we instead use the test at the bottom, shown here, multiple turtles can exit in a single tick. We chose the top test because exit blocking is seen in real crowd behavior. Here are the plots for bottom exiting:
|
|
- Person shape: It did turn out useful to use the person shape while using the 3D View. The visual effect was much more effective:
- Default shape: we included the default, arrow-like shape in the agent-shape Chooser. This has the advantage of showing the heading. Run the model using the default shape, setting the size to 2.0. Notice the headings takes by the agents as they attempt to get closer to their exit.
- 3D View: See 2D & 3D Views, especially the Manipulating the 3D View section. Run the model using the 3D View for each of the shapes: circle, person, default.
- min-dist factor: Due to the random element of exit choices, we cannot set the multiplying factor too high. Setting it at 1, for example, would attempt a completely uniform distribution, and fails with:
To test with various factors, set the multiple to the desired value (.6 say) and run this in the Command Center:
observer> repeat 1000 [ca setup-patches]
Set the View menu to be "continuous" rather than "on ticks" if you want to see the various attempts. Experimentation found .5 to be safe.
- Size: again, notice that the program remains fairly small even with considerable additional functionality.
- See ExitTutGo.nlogo in the NetLogoTut download folder.




