diff --git a/README.md b/README.md
index 90df23b5c..839742de8 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# MATLAB Fall 2014 – Research Plan (Template)
+# MATLAB Fall 2017 – Research Plan (Template)
(text between brackets to be removed)
> * Group Name: (be creative!)
diff --git a/code.m b/code.m
new file mode 100644
index 000000000..892a70c3b
--- /dev/null
+++ b/code.m
@@ -0,0 +1,100 @@
+%{
+GENERAL NOTES
+=============
+
+Each function should be defined in a separate file according
+to MATLAB requirements. Upload these files to the code folder
+in the repository.
+When iterating over the matrix, if possible, parallelize the
+accesses using parfor to increase efficiency. To iterate over
+the people inside of one sector, use the following piece of
+code:
+
+itr = matrix(i, j).iterator();
+
+while itr.hasNext()
+ person = itr.next();
+ % Do something with that person
+end
+
+Inside the matrix, the position of the individual is represented in
+absolute terms (i.e. relative to the entire matrix, not the sector). For
+precision reasons, the coordinates range from 0 to 10 * resolution (for
+now, we can always make it finer-grained by changing the SECTOR_SIZE
+global).
+
+To convert coordinates to a sector, use the function
+sectorForCoords(individual). You can also pass pure coordinates to this
+function.
+
+Define all globals in the runSimulation.m file. This way, the parameters of
+the simulation are easy to find and change.
+
+=============
+%}
+
+% Definition of individual
+
+%{
+An individual is a vector with
+- positionX
+- positionY
+- velocityX
+- velocityY
+- isParticipating in moshpit
+%}
+
+%{
+Initializes the position matrix. The ground covered by the people
+attending the concert is divided into sectors. The people in
+each sector are represented with a java.util.LinkedList.
+The coordinates of each person are given as absolute coordinates,
+i.e. not relative to the sector, but to the entire matrix.
+%}
+function initializeMatrix()
+end
+
+% Gets the position of the given individual
+function [position] = getPosition(individual)
+end
+
+% Gets the velocity of the given individual
+function [velocity] = getVelocity(individual)
+end
+
+% Returns true if the given individual is participating in the circle pit
+function [isParticipating] = isParticipating(individual)
+end
+
+% Returns the distance between two individuals
+function [distance] = distance(individual1, individual2)
+end
+
+%{
+Returns the neighbors of the given individual as a matrix where each column
+is an individual.
+%}
+function [neighbors] = getNeighbors(individual)
+end
+
+% TODO
+%{
+Main loop that iterates through the individuals and updates all their
+positions, returning the modified main matrix.
+%}
+function runOneTimestep(matrix)
+end
+
+% TODO
+%{
+Runs the simulation.
+%}
+function runSimulation()
+ initializeMatrix();
+ for i = 1:MAX
+ runOneTimestep(matrix);
+ end
+end
+
+
+
diff --git a/code/README.md b/code/README.md
index cf73f2a80..d85664519 100644
--- a/code/README.md
+++ b/code/README.md
@@ -1,3 +1,6 @@
# Code Folder
-Your code goes here. You could also replace the content of this file with something more meaningful
+Contains the code for the MATLAB implementation of the project.
+The structure of the code is laid out in the `code.m` file in the root directory of the repository.
+
+__WARNING__: The MATLAB version was retired on November 17, 2017 and is obsolete. We have moved to Java for speed reasons. See the `java_code` folder for the most recent version.
diff --git a/code/createIndividual.m b/code/createIndividual.m
new file mode 100644
index 000000000..220b7eaac
--- /dev/null
+++ b/code/createIndividual.m
@@ -0,0 +1,8 @@
+function [individual] = createIndividual(coordinates, velocity, isParticipating)
+%CREATEINDIVIDUAL Creates a new individual
+% Creates a new vector representing an individual with the specified
+% properties.
+ individual = [coordinates(1); coordinates(2); velocity(1); velocity(2); isParticipating];
+
+end
+
diff --git a/code/distance.m b/code/distance.m
new file mode 100644
index 000000000..b951e535c
--- /dev/null
+++ b/code/distance.m
@@ -0,0 +1,12 @@
+function distance = distance(individual1, individual2)
+%DISTANCE Gets the distance between two individuals.
+ x1 = individual1(1);
+ y1 = individual1(2);
+ x2 = individual2(1);
+ y2 = individual2(2);
+
+ dx = x1 - x2;
+ dy = y1 - y2;
+
+ distance = sqrt(dx*dx + dy*dy);
+end
diff --git a/code/getNeighbors.m b/code/getNeighbors.m
new file mode 100644
index 000000000..7969f2b70
--- /dev/null
+++ b/code/getNeighbors.m
@@ -0,0 +1,69 @@
+function [individuals] = getNeighbors(individual, radius)
+%GETNEIGHBORS Gets the neighbors of the given individual
+% Gets the neighbors of an individual in the radius specified by the
+% NEIGHBOR_SEARCH_RADIUS global. Returns these individuals as columns in
+% a matrix.
+
+ individuals = [];
+
+ global matrix;
+
+ % Get location of the individual
+ coords = getPosition(individual);
+ sector = sectorForCoords(coords);
+
+ % Get the sectors where we need to search
+ sectorsToSearch = sector;
+ northSector = sectorForCoords(coords - [0; radius]);
+ if ~isequal(northSector, sector)
+ sectorsToSearch = [sectorsToSearch, northSector];
+ end
+
+ southSector = sectorForCoords(coords + [0; radius]);
+ if ~isequal(southSector, sector)
+ sectorsToSearch = [sectorsToSearch, southSector];
+ end
+
+ westSector = sectorForCoords(coords - [radius; 0]);
+ if ~isequal(westSector, sector)
+ sectorsToSearch = [sectorsToSearch, westSector];
+ end
+
+ eastSector = sectorForCoords(coords + [radius; 0]);
+ if ~isequal(eastSector, sector)
+ sectorsToSearch = [sectorsToSearch, eastSector];
+ end
+
+ northEastSector = sectorForCoords(coords + [radius; -radius]);
+ if ~isequal(northEastSector, sector)
+ sectorsToSearch = [sectorsToSearch, northEastSector];
+ end
+
+ northWestSector = sectorForCoords(coords + [-radius; -radius]);
+ if ~isequal(northWestSector, sector)
+ sectorsToSearch = [sectorsToSearch, northWestSector];
+ end
+
+ southEastSector = sectorForCoords(coords + [radius; radius]);
+ if ~isequal(southEastSector, sector)
+ sectorsToSearch = [sectorsToSearch, southEastSector];
+ end
+
+ southWestSector = sectorForCoords(coords + [-radius; radius]);
+ if ~isequal(southWestSector, sector)
+ sectorsToSearch = [sectorsToSearch, southWestSector];
+ end
+
+ % Search over those vectors
+ for k = 1:size(sectorsToSearch, 2)
+ i = sectorsToSearch(1, k);
+ j = sectorsToSearch(2, k);
+ itr = matrix(i, j).iterator();
+ while itr.hasNext()
+ person = itr.next();
+ if distance(individual, person) < radius
+ individuals = [individuals, person];
+ end
+ end
+ end
+end
diff --git a/code/getPosition.m b/code/getPosition.m
new file mode 100644
index 000000000..a4a4760eb
--- /dev/null
+++ b/code/getPosition.m
@@ -0,0 +1,5 @@
+function [position] = getPosition(individual)
+%GETPOSITION Gets the position of the given individual.
+ position = [individual(1); individual(2)];
+end
+
diff --git a/code/getVelocity.m b/code/getVelocity.m
new file mode 100644
index 000000000..25f9a9cf9
--- /dev/null
+++ b/code/getVelocity.m
@@ -0,0 +1,4 @@
+function [velocity] = getVelocity(individual)
+%GETVELOCITY Gets the velocity of the given individual.
+ velocity = [individual(3); individual(4)];
+end
diff --git a/code/getXY.m b/code/getXY.m
new file mode 100644
index 000000000..f4c99021d
--- /dev/null
+++ b/code/getXY.m
@@ -0,0 +1,29 @@
+function [X, Y] = getXY()
+%GETXY Gets the x and y coordinates of all the individuals for plotting.
+% Stores the x coordinates of all the individuals in X and the
+% corresponding y coordinates in Y.
+% TODO: Find a way to separate the people based on isParticipating
+
+ global matrix;
+ global NUMBER_OF_PEOPLE;
+
+ X = zeros(NUMBER_OF_PEOPLE, 1);
+ Y = zeros(NUMBER_OF_PEOPLE, 1);
+
+ k = 1;
+
+ for i = 1:matrix.length
+ for j = 1:matrix(i).length
+ itr = matrix(i, j).iterator();
+ while itr.hasNext()
+ individual = itr.next();
+ position = getPosition(individual);
+ X(k) = position(1);
+ Y(k) = position(2);
+ k = k + 1;
+ end
+ end
+ end
+
+end
+
diff --git a/code/initializeMatrix.m b/code/initializeMatrix.m
new file mode 100644
index 000000000..fd66122e3
--- /dev/null
+++ b/code/initializeMatrix.m
@@ -0,0 +1,46 @@
+
+function [matrix] = initializeMatrix(resolution, numberOfPeople)
+%INITIALIZEMATRIX Initializes the position matrix used by the simulation.
+% The matrix is a low-resolution representation of the people at the
+% concert and is divided into "sectors". Each sector can contain several
+% people (whose position is defined by their x and y coordinates). The
+% matrix initially contains numberOfPeople people. Each sector is a
+% reference to a java.util.ArrayList which contains a list of the people
+% currently in that sector.
+
+ % Initialize a matrix of the proper size
+ width = resolution(1);
+ height = resolution(2);
+
+ global SECTOR_SIZE;
+
+ % We have to use a Java array because MATLAB matrices cannot store Java
+ % objects
+ matrix = javaArray('java.util.LinkedList', width, height);
+
+ for i = 1:width
+ for j = 1:height
+ matrix(i, j) = javaObject('java.util.LinkedList');
+ end
+ end
+
+ for i = 1:numberOfPeople
+ % Generate random coordinates
+ coords(1) = rand() * width * SECTOR_SIZE;
+ coords(2) = rand() * height * SECTOR_SIZE;
+
+ % Generate random velocity
+ % TODO: Generate more sensible velocity
+ velocity = [rand() - 0.5; rand() - 0.5];
+
+ % TODO: Decide whether individual is participating
+ isParticipating = false;
+
+ individual = createIndividual(coords, velocity, isParticipating);
+
+ % Add individual to appropriate sector
+ sector = sectorForCoords(coords);
+ matrix(sector(1), sector(2)).add(individual);
+ end
+
+return;
diff --git a/code/isParticipating.m b/code/isParticipating.m
new file mode 100644
index 000000000..e6263496d
--- /dev/null
+++ b/code/isParticipating.m
@@ -0,0 +1,6 @@
+function [isParticipating] = isParticipating(individual)
+%ISPARTICIPATING Returns true if the given individual is participating in
+%the cirle pit.
+ isParticipating = individual(5);
+end
+
diff --git a/code/plotMatrix.m b/code/plotMatrix.m
new file mode 100644
index 000000000..cf9c8b6a8
--- /dev/null
+++ b/code/plotMatrix.m
@@ -0,0 +1,39 @@
+global matrix;
+global INDIVIDUAL_RADIUS;
+global SECTOR_SIZE;
+global MATRIX_SIZE;
+
+% try
+ close all
+ hfig = figure('NumberTitle','off','name','Moshpit simulation','MenuBar','none');
+ axis([0, SECTOR_SIZE * MATRIX_SIZE, 0, SECTOR_SIZE * MATRIX_SIZE]);
+ axis off %do not show the coordinator
+
+% while 1
+ for i = 1:matrix.length
+ for j = 1:matrix(i).length
+ disp('Position: ');
+ disp([i, j]);
+ list = matrix(i, j);
+ itr = list.iterator();
+ while itr.hasNext()
+ individual = itr.next();
+ position = getPosition(individual);
+ x0 = position(1);
+ y0 = position(2);
+ if(isParticipating(individual))
+ %erase mode, if the individual is participating, then
+ %we draw a red dot, otherwise it's black
+ head = line(x0, y0, 'color', 'r', 'Marker', '.', 'erasemode', 'xor', 'markersize', INDIVIDUAL_RADIUS * 10);
+ else
+ head = line(x0, y0, 'color', 'k', 'Marker', '.', 'erasemode', 'xor', 'markersize', INDIVIDUAL_RADIUS * 10);
+ end
+ end
+ end
+ end
+ drawnow; %refresh the screen
+% end
+
+% catch
+% return
+% end
diff --git a/code/runOneTimestep.m b/code/runOneTimestep.m
new file mode 100644
index 000000000..2a59ae33c
--- /dev/null
+++ b/code/runOneTimestep.m
@@ -0,0 +1,98 @@
+function runOneTimestep()
+%RUNONETIMESTEP Runs one timestep of the simulation.
+% Updates all the individuals in the position matrix according to the
+% model from the paper.
+
+ global matrix;
+ global INDIVIDUAL_RADIUS;
+ global FLOCK_RADIUS;
+ global EPSILON;
+ global ALPHA;
+ global MU;
+
+ % TODO: Implement equations from model
+
+ % Basic skeleton for updating the individuals
+ for i = 1:matrix.length
+ for j = 1:matrix(i).length
+ itr = matrix(i, j).iterator();
+ while itr.hasNext()
+ individual = itr.next();
+
+ % Since MATLAB has no support for pass-by-reference, our
+ % only choice is to remove the individual from the
+ % LinkedList and then add it back again. Luckily this is
+ % O(1) using the iterator.
+ itr.remove();
+
+ % ==================== INITIALIZATION ====================
+ F = zeros(2, 1); % sum over forces
+ sumOverVelocities = zeros(2, 1); % For calculating the flocking effect
+ neighbours = getNeighbors(individual, FLOCK_RADIUS);
+ position = getPosition(individual);
+ velocity = getVelocity(individual);
+ r0 = INDIVIDUAL_RADIUS;
+ dt = 0.1;
+
+ % ****** definition of the forces ******
+ % ================ CALCULATING THE FORCES ================
+ for k = 1:size(neighbours, 2)
+ neighbour = neighbours(:, k);
+ positionNeighbour = getPosition(neighbour);
+ velocityNeighbour = getVelocity(neighbour);
+
+ distance1 = distance(individual, neighbour);
+
+ % Repulsive Force
+ % We only use neighbors within a radius of 2 * r0
+ if distance1 < 2 * r0
+ F = F + EPSILON * (1 - distance1 / (2*r0))^(5/2) * (position - positionNeighbour) / distance1;
+ end
+
+ % Velocity summation
+ sumOverVelocities = sumOverVelocities + velocityNeighbour;
+ end
+
+ % Propulsion
+ %
+ % TODO: v0 is the "preferred speed", vi is the
+ % "instantaneous speed"
+% F = F + MU * dot(velocity - velocityNeighbour, velocityNeighbour / length(velocityNeighbour));
+
+ % Flocking
+ if ~isequal(sumOverVelocities, [0; 0])
+ F = F + ALPHA * sumOverVelocities / norm(sumOverVelocities);
+ end
+ % Add noise
+ F = F + 0;
+
+ % ****** calculate timestep ******
+ % using the leap-frog method to integrate the differential
+ % equation
+ % differential equation d^2y/dt^2=rhs(y)
+
+ % shifted initial velocity for leap-frog
+ v_temp = velocity + 0.5*dt*F;
+ % timestep
+%
+ individual(1:2) = position + dt*v_temp;
+ individual(3:4) = v_temp + dt*F/2;
+
+ % TEST
+% individual(1:2) = individual(1:2) + individual(3:4);
+
+ % We need to add the individual to the appropriate sector
+ % Check if the sector has changed
+ newSector = sectorForCoords(individual);
+% disp(newSector);
+ % If it has, add the individual to the new sector
+ if ~isequal([i; j], newSector)
+ matrix(newSector(1), newSector(2)).add(individual);
+ % Else, just add it back to the same sector
+ else
+ itr.add(individual);
+ end
+ end
+ end
+ end
+end
diff --git a/code/runSimulation.m b/code/runSimulation.m
new file mode 100644
index 000000000..7ab7ed315
--- /dev/null
+++ b/code/runSimulation.m
@@ -0,0 +1,86 @@
+function runSimulation()
+%RUNSIMULATION Runs the simulation.
+% Execute this function to start running the simulation
+
+ % Size of a vector that represents one individual
+ global INDIVIDUAL_SIZE;
+ INDIVIDUAL_SIZE = 5;
+
+ % Size of the matrix
+ global MATRIX_SIZE;
+ MATRIX_SIZE = 2;
+
+ % Coordinate space of one sector of the position matrix
+ global SECTOR_SIZE;
+ SECTOR_SIZE = 10;
+
+ % The size of one individual
+ global INDIVIDUAL_RADIUS;
+ INDIVIDUAL_RADIUS = 2;
+
+ % The number of people at the concert
+ global NUMBER_OF_PEOPLE;
+ NUMBER_OF_PEOPLE = 50;
+
+ % The radius in which to search for neighbors
+ global FLOCK_RADIUS;
+ FLOCK_RADIUS = 10;
+
+ % ===================== PARAMETERS FROM THE PAPER =====================
+ % TODO: Set these variables
+ global EPSILON;
+ EPSILON = 5;
+
+ global MU;
+ MU = 1;
+
+ global ALPHA;
+ ALPHA = 1;
+
+ % Initialize the initial conditions of the simulation
+ % We make the matrix a global variable to simulate pass-by-reference
+ global matrix;
+ matrix = initializeMatrix([MATRIX_SIZE, MATRIX_SIZE], NUMBER_OF_PEOPLE);
+
+ % =============================== TEST ===============================
+
+ % This is a temporary way to plot the data
+
+ [X, Y] = getXY();
+
+ p = scatter(X, Y);
+ axis([0, SECTOR_SIZE * MATRIX_SIZE, 0, SECTOR_SIZE * MATRIX_SIZE]);
+
+ axis off;
+
+ % We run the simulation endlessly
+ while true
+ runOneTimestep();
+ [X, Y] = getXY();
+ set(p, 'XData', X, 'YData', Y);
+ % TODO: Find a better way of drawing the matrix
+ drawnow;
+ end
+
+ % ====================================================================
+
+ % TEST (old)
+
+% runOneTimestep();
+%
+% for i = 1:matrix.length
+% for j = 1:matrix(i).length
+% disp('Position: ');
+% disp([i, j]);
+% list = matrix(i, j);
+% itr = list.iterator();
+% while itr.hasNext()
+% individual = itr.next();
+% disp(individual');
+% end
+% end
+% end
+
+
+end
+
diff --git a/code/sectorForCoords.m b/code/sectorForCoords.m
new file mode 100644
index 000000000..97e407205
--- /dev/null
+++ b/code/sectorForCoords.m
@@ -0,0 +1,25 @@
+function [sector] = sectorForCoords(individual)
+%SECTORFORCOORDS Gets which sector an individual is in based on coords.
+
+ global SECTOR_SIZE;
+ global MATRIX_SIZE;
+
+ x = individual(1) / SECTOR_SIZE;
+ y = individual(2) / SECTOR_SIZE;
+
+ if x < 0
+ x = 0;
+ elseif x >= MATRIX_SIZE
+ x = MATRIX_SIZE - 1;
+ end
+
+ if y < 0
+ y = 0;
+ elseif y >= MATRIX_SIZE
+ y = MATRIX_SIZE - 1;
+ end
+
+ sector = floor([x; y]);
+ sector = sector + [1; 1];
+end
+
diff --git a/doc/report.pdf b/doc/report.pdf
new file mode 100644
index 000000000..63f5d6c20
Binary files /dev/null and b/doc/report.pdf differ
diff --git a/flashtalk/flash_talk.pdf b/flashtalk/flash_talk.pdf
new file mode 100644
index 000000000..9ada6bba2
Binary files /dev/null and b/flashtalk/flash_talk.pdf differ
diff --git a/java_code/.classpath b/java_code/.classpath
new file mode 100644
index 000000000..c751861a6
--- /dev/null
+++ b/java_code/.classpath
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/java_code/.idea/.name b/java_code/.idea/.name
new file mode 100644
index 000000000..debb33621
--- /dev/null
+++ b/java_code/.idea/.name
@@ -0,0 +1 @@
+MSSSM
\ No newline at end of file
diff --git a/java_code/.idea/kotlinc.xml b/java_code/.idea/kotlinc.xml
new file mode 100644
index 000000000..1c24f9a8d
--- /dev/null
+++ b/java_code/.idea/kotlinc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/java_code/.idea/misc.xml b/java_code/.idea/misc.xml
new file mode 100644
index 000000000..5fdad115f
--- /dev/null
+++ b/java_code/.idea/misc.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/java_code/.idea/modules.xml b/java_code/.idea/modules.xml
new file mode 100644
index 000000000..89e5730da
--- /dev/null
+++ b/java_code/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/java_code/.idea/workspace.xml b/java_code/.idea/workspace.xml
new file mode 100644
index 000000000..4379f5081
--- /dev/null
+++ b/java_code/.idea/workspace.xml
@@ -0,0 +1,1629 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ E-5
+ E-6
+ E-7
+ E-8
+ runOne
+ 46.539
+ random
+ counter
+ counter.py
+ e
+ E
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ DEFINITION_ORDER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $PROJECT_DIR$/timeEvolution.py
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ project
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $USER_HOME$/.subversion
+
+
+
+
+ 1510786148795
+
+
+ 1510786148795
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1510873844677
+
+
+
+ 1510873844677
+
+
+ 1510957707295
+
+
+
+ 1510957707295
+
+
+ 1511046476633
+
+
+
+ 1511046476633
+
+
+ 1511194413391
+
+
+
+ 1511194413391
+
+
+ 1511376286791
+
+
+
+ 1511376286791
+
+
+ 1511377363968
+
+
+
+ 1511377363968
+
+
+ 1511433114434
+
+
+
+ 1511433114434
+
+
+ 1512207256811
+
+
+
+ 1512207256811
+
+
+ 1512211346969
+
+
+
+ 1512211346969
+
+
+ 1512214896712
+
+
+
+ 1512214896712
+
+
+ 1512215705641
+
+
+
+ 1512215705641
+
+
+ 1512225195799
+
+
+
+ 1512225195799
+
+
+ 1512225700228
+
+
+
+ 1512225700228
+
+
+ 1512226953164
+
+
+
+ 1512226953164
+
+
+ 1512229811506
+
+
+
+ 1512229811506
+
+
+ 1512234993725
+
+
+
+ 1512234993725
+
+
+ 1512727044322
+
+
+
+ 1512727044323
+
+
+ 1512730512569
+
+
+
+ 1512730512569
+
+
+ 1512731822121
+
+
+
+ 1512731822121
+
+
+ 1512748060241
+
+
+
+ 1512748060241
+
+
+ 1512750491931
+
+
+
+ 1512750491931
+
+
+ 1512752177197
+
+
+
+ 1512752177202
+
+
+ 1512831991421
+
+
+
+ 1512831991421
+
+
+ 1512861675748
+
+
+
+ 1512861675748
+
+
+ 1513011959520
+
+
+
+ 1513011959520
+
+
+ 1513012403809
+
+
+
+ 1513012403809
+
+
+ 1513015570254
+
+
+
+ 1513015570254
+
+
+ 1513017212602
+
+
+
+ 1513017212602
+
+
+ 1513081885309
+
+
+
+ 1513081885310
+
+
+ 1513440914134
+
+
+
+ 1513440914134
+
+
+ 1513443130995
+
+
+
+ 1513443130995
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Python
+
+
+
+
+
+
+
+
+
+
+
+ Python 2.7.10 (/usr/bin/python) interpreter library
+
+
+
+
+
+
+
+
+
+
+
+ Python 3.6.3 (/usr/local/bin/python3)
+
+
+
+
+
+
+
+
+
+
+
+ Python|MSSSM
+
+
+
+
+
+
+
+
+
+
+
+ Python 2.7.10 (/usr/bin/python)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/java_code/.project b/java_code/.project
new file mode 100644
index 000000000..7d7a21d22
--- /dev/null
+++ b/java_code/.project
@@ -0,0 +1,23 @@
+
+
+ MSSSM
+
+
+
+
+
+ org.python.pydev.PyDevBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.python.pydev.pythonNature
+
+
diff --git a/java_code/.pydevproject b/java_code/.pydevproject
new file mode 100644
index 000000000..baf7d0d60
--- /dev/null
+++ b/java_code/.pydevproject
@@ -0,0 +1,5 @@
+
+
+Default
+python interpreter
+
diff --git a/java_code/.settings/org.eclipse.core.resources.prefs b/java_code/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 000000000..0dbcdb82e
--- /dev/null
+++ b/java_code/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/data_analysis.py=utf-8
diff --git a/java_code/MSSSM.eml b/java_code/MSSSM.eml
new file mode 100644
index 000000000..b8f1f3be1
--- /dev/null
+++ b/java_code/MSSSM.eml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/java_code/MSSSM.iml b/java_code/MSSSM.iml
new file mode 100644
index 000000000..86f903cfa
--- /dev/null
+++ b/java_code/MSSSM.iml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/java_code/MSSSM.userlibraries b/java_code/MSSSM.userlibraries
new file mode 100644
index 000000000..ac69dbabc
--- /dev/null
+++ b/java_code/MSSSM.userlibraries
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java_code/README.md b/java_code/README.md
new file mode 100644
index 000000000..cbc6d10a8
--- /dev/null
+++ b/java_code/README.md
@@ -0,0 +1,3 @@
+# Java Code Folder
+
+Contains an IntelliJ/Eclipse project with a Java port of the MATLAB code (as of November 17, 2017). The goal is transition away from MATLAB (for speed reasons) and move completely to Java.
diff --git a/java_code/__pycache__/out.cpython-36.pyc b/java_code/__pycache__/out.cpython-36.pyc
new file mode 100644
index 000000000..e737d8c8e
Binary files /dev/null and b/java_code/__pycache__/out.cpython-36.pyc differ
diff --git a/java_code/__pycache__/out0.cpython-36.pyc b/java_code/__pycache__/out0.cpython-36.pyc
new file mode 100644
index 000000000..9e1234165
Binary files /dev/null and b/java_code/__pycache__/out0.cpython-36.pyc differ
diff --git a/java_code/__pycache__/out1.cpython-36.pyc b/java_code/__pycache__/out1.cpython-36.pyc
new file mode 100644
index 000000000..5963b24bb
Binary files /dev/null and b/java_code/__pycache__/out1.cpython-36.pyc differ
diff --git a/java_code/__pycache__/out2.cpython-36.pyc b/java_code/__pycache__/out2.cpython-36.pyc
new file mode 100644
index 000000000..2e7cb22db
Binary files /dev/null and b/java_code/__pycache__/out2.cpython-36.pyc differ
diff --git a/java_code/__pycache__/out3.cpython-36.pyc b/java_code/__pycache__/out3.cpython-36.pyc
new file mode 100644
index 000000000..18cdff112
Binary files /dev/null and b/java_code/__pycache__/out3.cpython-36.pyc differ
diff --git a/java_code/__pycache__/out4.cpython-36.pyc b/java_code/__pycache__/out4.cpython-36.pyc
new file mode 100644
index 000000000..f5d832cc2
Binary files /dev/null and b/java_code/__pycache__/out4.cpython-36.pyc differ
diff --git a/java_code/configs.sim b/java_code/configs.sim
new file mode 100644
index 000000000..4787eb920
--- /dev/null
+++ b/java_code/configs.sim
@@ -0,0 +1,6 @@
+List the names of the configs to test below (do not remove this comment).
+# Insert your configurations here (and remove all lines starting with '#')
+# Example:
+# verticalLine
+# circle
+# cross
\ No newline at end of file
diff --git a/java_code/configs/C_shape.config b/java_code/configs/C_shape.config
new file mode 100644
index 000000000..61c3775cc
--- /dev/null
+++ b/java_code/configs/C_shape.config
@@ -0,0 +1,29 @@
+A policeman configuration resembling a 'C'. Policemen are added after 5 seconds.
+epsilon: 2
+mu: 10
+alpha: 700
+gamma: 600
+numberOfPeople: 500
+flockRadius: 8
+dt: 0.01
+percentParticipating: 0.5
+rParticipating: 6
+minCirclePitSize: 1
+minParticipatingNeighbors: 4
+dataCollectionInterval: 1000
+insertPoliceAfter: 100
+collectDataThisManyTimes: 300
+useThisManySeeds: 50
+policeConfig:
+ __________
+| xxx |
+| xx |
+| xx |
+| xxx |
+| |
+| |
+| |
+| |
+| |
+| |
+ ----------
\ No newline at end of file
diff --git a/java_code/configs/U_shape.config b/java_code/configs/U_shape.config
new file mode 100644
index 000000000..4e126ccc1
--- /dev/null
+++ b/java_code/configs/U_shape.config
@@ -0,0 +1,29 @@
+A configuration of police officers resembling a 'U' at the top center of the arena. Policemen are added after 5 seconds.
+epsilon: 2
+mu: 10
+alpha: 700
+gamma: 600
+numberOfPeople: 500
+flockRadius: 8
+dt: 0.01
+percentParticipating: 0.5
+rParticipating: 6
+minCirclePitSize: 1
+minParticipatingNeighbors: 4
+dataCollectionInterval: 1000
+insertPoliceAfter: 100
+collectDataThisManyTimes: 300
+useThisManySeeds: 50
+policeConfig:
+ __________
+| x x |
+| x x |
+| xxxxxx |
+| |
+| |
+| |
+| |
+| |
+| |
+| |
+ ----------
\ No newline at end of file
diff --git a/java_code/configs/arrow.config b/java_code/configs/arrow.config
new file mode 100644
index 000000000..58a7169e3
--- /dev/null
+++ b/java_code/configs/arrow.config
@@ -0,0 +1,29 @@
+A policeman configuration in the shape of a left-pointing arrow. Policemen are added after 5 seconds.
+epsilon: 2
+mu: 10
+alpha: 700
+gamma: 600
+numberOfPeople: 500
+flockRadius: 8
+dt: 0.01
+percentParticipating: 0.5
+rParticipating: 6
+minCirclePitSize: 1
+minParticipatingNeighbors: 4
+dataCollectionInterval: 1000
+insertPoliceAfter: 100
+collectDataThisManyTimes: 300
+useThisManySeeds: 50
+policeConfig:
+ __________
+| xx |
+| xx |
+| xx |
+| xx |
+| xx |
+| |
+| |
+| |
+| |
+| |
+ ----------
\ No newline at end of file
diff --git a/java_code/configs/bigCircle.config b/java_code/configs/bigCircle.config
new file mode 100644
index 000000000..233d00d15
--- /dev/null
+++ b/java_code/configs/bigCircle.config
@@ -0,0 +1,29 @@
+A "circle" of policemen larger than the 'circle' config file. Policemen are added after 5 seconds.
+epsilon: 2
+mu: 10
+alpha: 700
+gamma: 600
+numberOfPeople: 500
+flockRadius: 8
+dt: 0.01
+percentParticipating: 0.5
+rParticipating: 6
+minCirclePitSize: 1
+minParticipatingNeighbors: 4
+dataCollectionInterval: 1000
+insertPoliceAfter: 100
+collectDataThisManyTimes: 300
+useThisManySeeds: 50
+policeConfig:
+ __________
+| |
+| |
+| x x x |
+| |
+| x x |
+| x x |
+| |
+| x x x |
+| |
+| |
+ ----------
\ No newline at end of file
diff --git a/java_code/configs/center.config b/java_code/configs/center.config
new file mode 100644
index 000000000..de1ca0bcd
--- /dev/null
+++ b/java_code/configs/center.config
@@ -0,0 +1,29 @@
+A configuration with all the policemen grouped in the center of the arena. Policemen are added after 5 seconds.
+epsilon: 2
+mu: 10
+alpha: 700
+gamma: 600
+numberOfPeople: 500
+flockRadius: 8
+dt: 0.01
+percentParticipating: 0.5
+rParticipating: 6
+minCirclePitSize: 1
+minParticipatingNeighbors: 4
+dataCollectionInterval: 1000
+insertPoliceAfter: 100
+collectDataThisManyTimes: 300
+useThisManySeeds: 50
+policeConfig:
+ __________
+| |
+| |
+| |
+| xxx |
+| xxx |
+| xxx |
+| x |
+| |
+| |
+| |
+ ----------
\ No newline at end of file
diff --git a/java_code/configs/circle.config b/java_code/configs/circle.config
new file mode 100644
index 000000000..98e5c2226
--- /dev/null
+++ b/java_code/configs/circle.config
@@ -0,0 +1,29 @@
+A "circle" of policemen in the center of the arena. Policemen are added after 5 seconds.
+epsilon: 2
+mu: 10
+alpha: 700
+gamma: 600
+numberOfPeople: 500
+flockRadius: 8
+dt: 0.01
+percentParticipating: 0.5
+rParticipating: 6
+minCirclePitSize: 1
+minParticipatingNeighbors: 4
+dataCollectionInterval: 1000
+insertPoliceAfter: 100
+collectDataThisManyTimes: 300
+useThisManySeeds: 50
+policeConfig:
+ __________
+| |
+| |
+| |
+| xxx |
+| x x |
+| x x |
+| xxx |
+| |
+| |
+| |
+ ----------
\ No newline at end of file
diff --git a/java_code/configs/configGuide.config b/java_code/configs/configGuide.config
new file mode 100644
index 000000000..4dab469ca
--- /dev/null
+++ b/java_code/configs/configGuide.config
@@ -0,0 +1,45 @@
+# This is a guide to show how to write a config file. In a real config file,
+# all lines starting with '#' MUST be removed.
+# Have a look at Appendix C to see a real config file.
+# Each config file must start with a one-line comment:
+This comment briefly explains the configuration.
+# These next lines are fairly self-explanatory, they are the same as in the
+# Simulation class.
+epsilon: 2 # Strength of repulsive force
+mu: 10 # Strength of propulsive force
+alpha: 700 # Strength of flocking force
+gamma: 600 # Strength of centripetal force
+numberOfPeople: 500 # Initial number of people in the arena
+flockRadius: 8 # r_flock (radius in which to search for
+ # neighbors for the flocking force
+dt: 0.01 # Timestep
+percentParticipating: 0.5 # Proportion of people initially participating
+ # in the circle pit
+rParticipating: 6 # Radius in which to search for participating
+ # neighbors
+minCirclePitSize: 1 # Min. number of neighbors needed to continue
+ # participating in the circle pit
+minParticipatingNeighbors: 3 # Min. number of neighbors needed to join in
+ # circle pit
+dataCollectionInterval: 2000 # After how many milliseconds to collect data
+insertPoliceAfter: 0 # After how many timesteps (not milliseconds!)
+ # police should be inserted.
+collectDataThisManyTimes: 3 # How many times to collect data
+useThisManySeeds: 2 # How many seeds to test
+# The next section is a "graphical" representation of where the policemen are
+# located. Each policeman is denoted by an 'x'. The representation below must
+# include the borders of the matrix and should be 10 spaces wide and 10 lines
+# long.
+policeConfig:
+ __________
+| x |
+| x |
+| x |
+| x |
+| x |
+| x |
+| x |
+| x |
+| x |
+| x |
+ ----------
\ No newline at end of file
diff --git a/java_code/configs/corner.config b/java_code/configs/corner.config
new file mode 100644
index 000000000..59a811a1f
--- /dev/null
+++ b/java_code/configs/corner.config
@@ -0,0 +1,29 @@
+A line of policemen completely blocking off one corner of the arena. Policemen are added after 5 seconds.
+epsilon: 2
+mu: 10
+alpha: 700
+gamma: 600
+numberOfPeople: 500
+flockRadius: 8
+dt: 0.01
+percentParticipating: 0.5
+rParticipating: 6
+minCirclePitSize: 1
+minParticipatingNeighbors: 4
+dataCollectionInterval: 1000
+insertPoliceAfter: 100
+collectDataThisManyTimes: 300
+useThisManySeeds: 50
+policeConfig:
+ __________
+| x |
+| x |
+| x |
+| x |
+| xxxxxx|
+| |
+| |
+| |
+| |
+| |
+ ----------
\ No newline at end of file
diff --git a/java_code/configs/cross.config b/java_code/configs/cross.config
new file mode 100644
index 000000000..82d80f07e
--- /dev/null
+++ b/java_code/configs/cross.config
@@ -0,0 +1,29 @@
+Policemen resembling a cross in the center of the arena. Policemen are added after 5 seconds.
+epsilon: 2
+mu: 10
+alpha: 700
+gamma: 600
+numberOfPeople: 500
+flockRadius: 8
+dt: 0.01
+percentParticipating: 0.5
+rParticipating: 6
+minCirclePitSize: 1
+minParticipatingNeighbors: 4
+dataCollectionInterval: 1000
+insertPoliceAfter: 100
+collectDataThisManyTimes: 300
+useThisManySeeds: 50
+policeConfig:
+ __________
+| |
+| |
+| x x |
+| x x |
+| x |
+| x |
+| x x |
+| x x |
+| |
+| |
+ ----------
\ No newline at end of file
diff --git a/java_code/configs/diagonal.config b/java_code/configs/diagonal.config
new file mode 100644
index 000000000..3d0960006
--- /dev/null
+++ b/java_code/configs/diagonal.config
@@ -0,0 +1,29 @@
+A diagonal line of policemen from upper left to lower right. Policemen are added after 5 seconds.
+epsilon: 2
+mu: 10
+alpha: 700
+gamma: 600
+numberOfPeople: 500
+flockRadius: 8
+dt: 0.01
+percentParticipating: 0.5
+rParticipating: 6
+minCirclePitSize: 1
+minParticipatingNeighbors: 4
+dataCollectionInterval: 1000
+insertPoliceAfter: 100
+collectDataThisManyTimes: 300
+useThisManySeeds: 50
+policeConfig:
+ __________
+|x |
+| x |
+| x |
+| x |
+| x |
+| x |
+| x |
+| x |
+| x |
+| x|
+ ----------
\ No newline at end of file
diff --git a/java_code/configs/doubleHalfLine.config b/java_code/configs/doubleHalfLine.config
new file mode 100644
index 000000000..9873d36e9
--- /dev/null
+++ b/java_code/configs/doubleHalfLine.config
@@ -0,0 +1,29 @@
+A double half-line of policemen at the top center of the arena. Policemen are added after 5 seconds.
+epsilon: 2
+mu: 10
+alpha: 700
+gamma: 600
+numberOfPeople: 500
+flockRadius: 8
+dt: 0.01
+percentParticipating: 0.5
+rParticipating: 6
+minCirclePitSize: 1
+minParticipatingNeighbors: 4
+dataCollectionInterval: 1000
+insertPoliceAfter: 100
+collectDataThisManyTimes: 300
+useThisManySeeds: 50
+policeConfig:
+ __________
+| xx |
+| xx |
+| xx |
+| xx |
+| xx |
+| |
+| |
+| |
+| |
+| |
+ ----------
\ No newline at end of file
diff --git a/java_code/configs/no.config b/java_code/configs/no.config
new file mode 100644
index 000000000..8ab0b0bc6
--- /dev/null
+++ b/java_code/configs/no.config
@@ -0,0 +1,29 @@
+A configuration with no policemen.
+epsilon: 2
+mu: 10
+alpha: 700
+gamma: 600
+numberOfPeople: 500
+flockRadius: 8
+dt: 0.01
+percentParticipating: 0.5
+rParticipating: 6
+minCirclePitSize: 1
+minParticipatingNeighbors: 4
+dataCollectionInterval: 1000
+insertPoliceAfter: 100
+collectDataThisManyTimes: 300
+useThisManySeeds: 50
+policeConfig:
+ __________
+| |
+| |
+| |
+| |
+| |
+| |
+| |
+| |
+| |
+| |
+ ----------
\ No newline at end of file
diff --git a/java_code/configs/verticalLine.config b/java_code/configs/verticalLine.config
new file mode 100644
index 000000000..93ea799cc
--- /dev/null
+++ b/java_code/configs/verticalLine.config
@@ -0,0 +1,29 @@
+A vertical line of policemen in the center of the arena. Policemen are added after 5 seconds.
+epsilon: 2
+mu: 10
+alpha: 700
+gamma: 600
+numberOfPeople: 500
+flockRadius: 8
+dt: 0.01
+percentParticipating: 0.5
+rParticipating: 6
+minCirclePitSize: 1
+minParticipatingNeighbors: 4
+dataCollectionInterval: 1000
+insertPoliceAfter: 100
+collectDataThisManyTimes: 300
+useThisManySeeds: 50
+policeConfig:
+ __________
+| x |
+| x |
+| x |
+| x |
+| x |
+| x |
+| x |
+| x |
+| x |
+| x |
+ ----------
\ No newline at end of file
diff --git a/java_code/data_analysis.py b/java_code/data_analysis.py
new file mode 100644
index 000000000..d2e5df79f
--- /dev/null
+++ b/java_code/data_analysis.py
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Sat Dec 2 16:10:23 2017
+
+@author: Johanna
+"""
+
+
+from numpy import *
+from matplotlib.pylab import *
+from counter import n
+
+
+
+
+def analysis1(isParticipating,r,density):
+ figure()
+ for k in arange(len(x)):
+ if(isParticipating[k]==1):
+
+ plot(r[k],density[k],'ro')
+ else:
+ plot(r[k],density[k],'bo')
+ xlabel('distance to center')
+ ylabel('danger caused by high density')
+ title('Density')
+ #show()
+
+def densityAnalysis(r,density):
+ figure()
+ plot(r,density,'ro')
+ xlabel('distance to center')
+ ylabel('danger caused by density')
+ title('Density')
+ #show()
+
+def analysis2(r,isParticipating,F):
+ figure()
+ for k in arange(len(x)):
+ if(isParticipating[k]==1):
+
+ plot(r[k],F[k],'ro')
+ else:
+ plot(r[k],F[k],'bo')
+ xlabel('distance to center')
+ ylabel('danger caused by high forces')
+ title('Force')
+ #show()
+
+def forceAnalysis(r,F):
+ figure()
+ plot(r,F,'ro')
+ xlabel('distance to center')
+ ylabel('danger caused by forces')
+ title('Force')
+ #show()
+def isParticipatingAnalysis(r,isParticipating,density,F):
+ figure()
+ plot(isParticipating,density,'ro')
+ xlabel('Participating')
+ ylabel('danger caused by high density')
+ title('Density')
+ #show()
+ figure()
+ plot(isParticipating,F,'ro')
+ xlabel('Participating')
+ ylabel('danger caused by forces')
+ title('Force')
+ show()
+def analyse():
+ for k in range(0,n):
+ filename='out%s' % k
+ exec("from %s import *" %filename, globals())
+
+
+ r=sqrt((x-50)**2+(y-50)**2)
+
+ densityAnalysis(r,density)
+ analysis1(isParticipating,r,density)
+ forceAnalysis(r,F)
+ analysis2(r,isParticipating,F)
+ isParticipatingAnalysis(r,isParticipating,density,F)
+ print (k)
+analyse()
diff --git a/java_code/phase_diagram.py b/java_code/phase_diagram.py
new file mode 100644
index 000000000..622046d07
--- /dev/null
+++ b/java_code/phase_diagram.py
@@ -0,0 +1,62 @@
+
+
+from numpy import *
+from matplotlib.pylab import *
+from scipy import interpolate
+
+
+# This program shows density's and force's levels in a phase
+# diagram of a single 'out#.py' file
+
+def phaseDiagram(x, y, density, F):
+
+ # levels to be considerated safe/dangerous
+ safeDensity = 10;
+ density1 = 25;
+ density2 = 40;
+
+ safeForce = 1000;
+ force1 = 2500;
+ force2 = 4000;
+
+ # interpolates the data to get a full grid
+ grid_x, grid_y = mgrid[0:99:200j, 0:99:200j]
+ points = (x, y)
+ grid_density = interpolate.griddata(points, density, (grid_x, grid_y),method='cubic')
+ grid_F = interpolate.griddata(points, F, (grid_x, grid_y),method='cubic')
+
+ figure()
+ # plots density diagram
+ subplot(121)
+ subplots_adjust(wspace=0.5)
+ imD = imshow(grid_density, extent=(0,99,0,99), origin='upper', cmap='hot', vmin=safeDensity, vmax=density2+10)
+ axis('off')
+ cbarD = colorbar(imD, fraction=0.046, pad=0.04, orientation='vertical', ticks=[safeDensity, density1, density2])
+ cbarD.ax.set_yticklabels(['Low', 'Medium', 'Death'])
+ title('Density danger')
+
+ # plots force diagram
+ subplot(122)
+ imF = imshow(grid_F, extent=(0,99,0,99), origin='upper', cmap='hot', vmin=safeForce, vmax=force2+1000)
+ axis('off')
+ cbarD = colorbar(imF, fraction=0.046, pad=0.04, orientation='vertical', ticks=[safeForce, force1, force2])
+ cbarD.ax.set_yticklabels(['Low', 'Medium', 'Death'])
+
+ title('Force danger')
+
+ show()
+
+
+def analyse(num):
+ # get the file and run the diagramPhase function
+ filename='out%s' % num
+ exec("from %s import *" %filename, globals())
+ phaseDiagram(x, y, density, F)
+
+# user's interface
+k = input('Which out to import?\n-> ')
+analyse(k)
+while k != 0:
+ k = input('and now?\n-> ')
+ analyse(k)
+
diff --git a/java_code/phase_diagram_multi.py b/java_code/phase_diagram_multi.py
new file mode 100644
index 000000000..416a9d42f
--- /dev/null
+++ b/java_code/phase_diagram_multi.py
@@ -0,0 +1,80 @@
+import numpy as np
+import matplotlib.pylab as plt
+from scipy import interpolate
+
+
+def phase_diagram(x, y, danger):
+ # levels to be considered safe/dangerous
+ safe_danger = 0.4
+ danger1 = 0.9
+ danger2 = 1.4
+
+ # interpolates the data to get a full grid
+ grid_x, grid_y = mgrid[0:99:200j, 0:99:200j]
+ points = (x, y)
+ grid_danger = interpolate.griddata(points, danger, (grid_x, grid_y),
+ method='cubic')
+
+ plt.figure()
+ # plots danger diagram
+ im_d = plt.imshow(grid_danger, extent=(0, 99, 0, 99), origin='upper',
+ cmap='hot', vmin=safe_danger, vmax=danger2 + 0.2)
+ plt.axis('off')
+ cbar_d = plt.colorbar(im_d, fraction=0.046, pad=0.04, orientation='vertical',
+ ticks=[safe_danger, danger1, danger2])
+ cbar_d.ax.set_yticklabels(['Low', 'Medium', 'High'])
+ plt.title('Danger Level')
+
+ plt.show()
+
+
+# This program shows danger levels in a phase
+# diagram as an average of a set of 'out.py' files
+
+# Average function which looks for two equals points
+def average_(points2, d2):
+ global continuous_danger_level_
+ global points
+ continuous_danger_level_ = np.append(continuous_danger_level_, d2)
+ points_[0] = np.append(points_[0], points2[0])
+ points_[1] = np.append(points_[1], points2[1])
+
+
+# Imports and averages the data-set from the out files
+def analyse2(test_set, time):
+
+ # Import the data from the out.py files
+ to_do = "from %s.counter import *" % test_set
+ exec(to_do, globals())
+
+ global points_
+ global continuous_danger_level_
+ exec("from %s.out_0_0 import *" % (test_set), globals())
+ points_ = [x, y]
+ continuous_danger_level_ = continuousDangerLevel
+
+ # Iterate over the seeds
+ for i in range(0, m):
+ try:
+ filename_ = 'out_%s_%s' % (i, time)
+ exec("from %s.%s import *" % (test_set, filename_), globals())
+ except ModuleNotFoundError:
+ break
+
+ # Average over the seeds
+ average_((x, y), continuousDangerLevel)
+
+ phase_diagram(points_[0], points_[1], continuous_danger_level_)
+
+
+if __name__ == '__main__' and __package__ is None:
+ import sys, os.path as path
+
+ sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
+
+ # Iterate over all the config files in configs.sim
+ with open("configs.sim") as f:
+ next(f)
+ for test_set in f:
+ time = int(input('Choose time -> '))
+ analyse2(test_set.strip(), time)
diff --git a/java_code/policeman.png b/java_code/policeman.png
new file mode 100644
index 000000000..be36acd74
Binary files /dev/null and b/java_code/policeman.png differ
diff --git a/java_code/src/AutomaticSimulator.java b/java_code/src/AutomaticSimulator.java
new file mode 100644
index 000000000..f49f1d988
--- /dev/null
+++ b/java_code/src/AutomaticSimulator.java
@@ -0,0 +1,166 @@
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Scanner;
+
+/**
+ * An object that reads the configs given in configs.sim and
+ * executes the corresponding simulations while dumping data for analysis.
+ */
+public class AutomaticSimulator {
+
+ private Queue configNames = new LinkedList();
+ // The configs to simulate
+ private Simulation simulation;
+
+ public AutomaticSimulator() throws FileNotFoundException {
+ readConfigNames();
+ }
+
+ /**
+ * Runs the automatic simulation.
+ *
+ * @throws FileNotFoundException either if configs.sim could
+ * not be found or if a configuration
+ * specified in configs.sim could
+ * not be found.
+ */
+ public void run() throws FileNotFoundException {
+ // Keep going while not all configurations have been tested
+ while (!configNames.isEmpty()) {
+ String config = configNames.poll();
+ Config c = readConfigFile(config);
+ newSimulation(c);
+ // Poll the simulation to see if it is done yet (really ugly but
+ // oh well...)
+ while (!simulation.isCurrentIterationFinished) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ simulation.isCurrentIterationFinished = false;
+ }
+ System.exit(0);
+ }
+
+ // Reads the configurations to simulate from configs.sim
+ private void readConfigNames() throws FileNotFoundException {
+ Scanner scanner = new Scanner(new File("configs.sim"));
+ scanner.nextLine();
+ while (scanner.hasNext()) {
+ configNames.add(scanner.next());
+ }
+ System.out.println("Starting simulation with configs: " + configNames);
+ }
+
+ // Reads a configuration file
+ private Config readConfigFile(String config) throws FileNotFoundException {
+ Scanner scanner =
+ new Scanner(new File("configs/" + config + ".config"));
+ scanner.nextLine(); // Skip comment on first line
+ double[] data = new double[15];
+ Config c = new Config();
+ c.name = config;
+ for (int i = 0; i < data.length;
+ i++) { // Read parameters from config file
+ scanner.next();
+ data[i] = scanner.nextDouble();
+ }
+ c.readNumbersFromArray(data);
+ scanner.nextLine(); // Move to line after all the number values
+ scanner.nextLine(); // Move over line with "policeSectors: "
+ scanner.nextLine(); // Move over upper boundary of ASCII-based
+ // representation of matrix
+ for (int i = 0; i < 10; i++) {
+ String line = scanner.nextLine();
+ for (int j = 0; j < 10; j++) {
+ if (line.charAt(j + 1) ==
+ 'x') { // j+1 because of leading |, 'x' means there
+ // is a policeman there
+ c.policeSectors[j][i] = true;
+ }
+ }
+ }
+ System.out.println("Current config: " + config);
+ System.out.println(" data = " + Arrays.toString(data));
+ System.out.println(" policeSectors = ");
+ for (int i = 0; i < c.policeSectors.length; i++) {
+ System.out.println(" " + Arrays.toString(c.policeSectors[i]));
+ }
+ return c;
+ }
+
+ private void newSimulation(Config c) {
+ if (simulation == null) {
+ // Initialize the simulation with data from the config file
+ simulation = new Simulation(c.epsilon, c.mu, c.alpha, c.gamma,
+ c.numberOfPeople, c.flockRadius, c.dt,
+ c.percentParticipating,
+ c.rParticipating, c.minCirclePitSize,
+ c.minParticipatingNeighbors);
+ simulation.createWindow();
+ simulation.createNewTimer(new DataCollector(simulation, c.name,
+ c.dataCollectionInterval,
+ c.insertPoliceAfter,
+ c.amountOfSeeds,
+ c.collectionTimes,
+ c.policeSectors));
+ simulation.start();
+ } else {
+ // Reinitialize all the parameters with data from the config file
+ simulation.stop();
+ simulation.epsilon = c.epsilon;
+ simulation.alpha = c.alpha;
+ simulation.mu = c.mu;
+ simulation.gamma = c.gamma;
+ simulation.numberOfPeople = c.numberOfPeople;
+ simulation.flockRadius = c.flockRadius;
+ simulation.dt = c.dt;
+ simulation.percentParticipating = c.percentParticipating;
+ simulation.rParticipating = c.rParticipating;
+ simulation.minCirclePitSize = c.minCirclePitSize;
+ simulation.minParticipatingNeighbors = c.minParticipatingNeighbors;
+ simulation.createNewTimer(new DataCollector(simulation, c.name,
+ c.dataCollectionInterval,
+ c.insertPoliceAfter,
+ c.amountOfSeeds,
+ c.collectionTimes,
+ c.policeSectors));
+ simulation.basicReset();
+ simulation.start();
+ }
+ }
+
+ // A class that stores all the parameters from a config file
+ private class Config {
+ String name;
+ double epsilon, alpha, mu, gamma, dt, percentParticipating;
+ int numberOfPeople, flockRadius, rParticipating, minCirclePitSize,
+ minParticipatingNeighbors, dataCollectionInterval,
+ insertPoliceAfter, collectionTimes, amountOfSeeds;
+ boolean[][] policeSectors = new boolean[10][10];
+
+ private void readNumbersFromArray(double[] array) {
+ assert array.length == 15;
+ epsilon = array[0];
+ mu = array[1];
+ alpha = array[2];
+ gamma = array[3];
+ numberOfPeople = (int) array[4];
+ flockRadius = (int) array[5];
+ dt = array[6];
+ percentParticipating = array[7];
+ rParticipating = (int) array[8];
+ minCirclePitSize = (int) array[9];
+ minParticipatingNeighbors = (int) array[10];
+ dataCollectionInterval = (int) array[11];
+ insertPoliceAfter = (int) array[12];
+ collectionTimes = (int) array[13];
+ amountOfSeeds = (int) array[14];
+ }
+ }
+}
diff --git a/java_code/src/ControlPanel.java b/java_code/src/ControlPanel.java
new file mode 100644
index 000000000..7ca390a69
--- /dev/null
+++ b/java_code/src/ControlPanel.java
@@ -0,0 +1,288 @@
+import javax.swing.*;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+public class ControlPanel extends JPanel
+ implements PropertyChangeListener, ChangeListener {
+
+ private Simulation simulation;
+ private SimulationPanel simulationpanel;
+ private JButton startPauseButton;
+ private JButton restartButton;
+ private JButton exportDataButton;
+ private JCheckBox enableDensity;
+ private JCheckBox enableForce;
+ private JCheckBox showParticipants;
+ private JLabel epsilonLabel, muLabel, alphaLabel, flockRadiusLabel,
+ gammaLabel, initialParticipantsLabel, percLabel, rPartLabel,
+ sizeLabel, minNeighborsLabel;
+ private JFormattedTextField epsilonField, muField, alphaField, gammaField,
+ initialParticipantsField, percField, sizeField, minNeighborsField;
+ private JSlider rPartSlider, flockRadiusSlider;
+
+ private boolean paused = true;
+
+ public ControlPanel(Simulation simulation,
+ SimulationPanel simulationpanel) {
+ this.simulation = simulation;
+ this.simulationpanel = simulationpanel;
+ setPreferredSize(new Dimension(500, 230));
+ setBackground(Color.WHITE);
+ setLayout(new GridLayout(13, 2));
+
+ initComponents();
+ addListeners();
+ addComponents();
+ }
+
+ private void initComponents() {
+ startPauseButton = new JButton("Start");
+ restartButton = new JButton("Reinitialize");
+ showParticipants = new JCheckBox("Show Participants");
+ showParticipants.setSelected(true);
+ exportDataButton = new JButton("Export Data for Analysis");
+
+ enableDensity = new JCheckBox("Density is a Danger Factor");
+ enableDensity.setSelected(true);
+ enableForce = new JCheckBox("Force is a Danger Factor");
+ enableForce.setSelected(true);
+
+ epsilonLabel = new JLabel("Repulsion Strength (\u03b5)");
+
+ epsilonField = new JFormattedTextField();
+ epsilonField.setValue(simulation.epsilon);
+ epsilonField.setColumns(10);
+
+ muLabel = new JLabel("Propulsion Strength (\u03bc)");
+
+ muField = new JFormattedTextField();
+ muField.setValue(simulation.mu);
+ muField.setColumns(10);
+
+ alphaLabel = new JLabel("Flocking Force Strength (\u03b1)");
+
+ alphaField = new JFormattedTextField();
+ alphaField.setValue(simulation.alpha);
+ alphaField.setColumns(10);
+
+ flockRadiusLabel = new JLabel("Flocking Force Radius");
+ flockRadiusSlider = new JSlider();
+ flockRadiusSlider.setValue((int) simulation.flockRadius);
+ configureSlider(flockRadiusSlider, 1, 5, 5, 2 * Simulation.SECTOR_SIZE);
+
+ gammaLabel = new JLabel("Centripetal Force Strength (\u03b3)");
+
+ gammaField = new JFormattedTextField();
+ gammaField.setValue(simulation.gamma);
+ gammaField.setColumns(10);
+
+ initialParticipantsLabel = new JLabel("Initial Size of Crowd");
+
+ initialParticipantsField = new JFormattedTextField();
+ initialParticipantsField.setValue(simulation.numberOfPeople);
+ initialParticipantsField.setColumns(10);
+
+ percLabel = new JLabel("Percentage of Initial Participants");
+
+ percField = new JFormattedTextField();
+ percField.setValue(simulation.percentParticipating);
+ percField.setColumns(10);
+
+ rPartLabel = new JLabel("Search Radius for Part. Neighbors");
+
+ rPartSlider = new JSlider();
+ rPartSlider.setValue((int) simulation.rParticipating);
+ configureSlider(rPartSlider, 1, 10, 0, 2 * Simulation.SECTOR_SIZE);
+
+ sizeLabel = new JLabel("Neighbors Needed to Continue Participating");
+
+ String fontFamily = sizeLabel.getFont().getFamily();
+ sizeLabel.setFont(new Font(fontFamily, Font.PLAIN, 11));
+
+
+ sizeField = new JFormattedTextField();
+ sizeField.setValue(simulation.minCirclePitSize);
+ sizeField.setColumns(10);
+
+ minNeighborsLabel = new JLabel(
+ "Neighbors Needed to Join in Circle Pit");
+
+ minNeighborsField = new JFormattedTextField();
+ minNeighborsField.setValue(simulation.minParticipatingNeighbors);
+ minNeighborsField.setColumns(10);
+
+ }
+
+ private void configureSlider(JSlider slider, int minorSpacing,
+ int majorSpacing, int lowerLimit,
+ int upperLimit) {
+ slider.setMajorTickSpacing(majorSpacing);
+ slider.setMinorTickSpacing(minorSpacing);
+ slider.setMinimum(lowerLimit);
+ slider.setMaximum(upperLimit);
+ slider.setPaintLabels(true);
+ slider.setPaintTicks(true);
+ }
+
+ private void addListeners() {
+ startPauseButton.addActionListener(new ActionListener() {
+ /* @Override */
+ public void actionPerformed(ActionEvent e) {
+ if (paused) {
+ simulation.getSimulationTimer().start();
+ startPauseButton.setText("Pause");
+ } else {
+ simulation.getSimulationTimer().stop();
+ startPauseButton.setText("Start");
+ }
+ paused = !paused;
+ }
+ });
+
+ restartButton.addActionListener(new ActionListener() {
+ /* @Override */
+ public void actionPerformed(ActionEvent e) {
+ startPauseButton.setText("Start");
+ paused = true;
+ simulation.resetMatrix();
+ }
+ });
+
+ showParticipants.addActionListener(new ActionListener() {
+ /* @Override */
+ public void actionPerformed(ActionEvent e) {
+ simulationpanel.shouldShowParticipants =
+ !simulationpanel.shouldShowParticipants;
+ getParent().repaint();
+ }
+ });
+
+ exportDataButton.addActionListener(new ActionListener() {
+ /* @Override */
+ public void actionPerformed(ActionEvent e) {
+ simulation.exportData();
+ }
+ });
+
+ enableDensity.addActionListener(new ActionListener() {
+ /* @Override */
+ public void actionPerformed(ActionEvent e) {
+ if (!simulation.enableDensity) {
+ simulation.enableDensity = true;
+ } else {
+ simulation.enableDensity = false;
+ for (Individual individual : simulation.getMatrix()
+ .getIndividuals()) {
+ individual.dangerLevel = 0;
+ }
+ }
+ }
+ });
+
+ enableForce.addActionListener(new ActionListener() {
+ /* @Override */
+ public void actionPerformed(ActionEvent e) {
+ if (!simulation.enableForce) {
+ simulation.enableForce = true;
+ } else {
+ simulation.enableForce = false;
+ for (Individual individual : simulation.getMatrix()
+ .getIndividuals()) {
+ individual.dangerLevel = 0;
+ }
+ }
+ }
+ });
+
+ epsilonField.addPropertyChangeListener("value", this);
+ alphaField.addPropertyChangeListener("value", this);
+ flockRadiusSlider.addChangeListener(this);
+ muField.addPropertyChangeListener("value", this);
+ gammaField.addPropertyChangeListener("value", this);
+ initialParticipantsField.addPropertyChangeListener("value", this);
+ percField.addPropertyChangeListener("value", this);
+ rPartSlider.addChangeListener(this);
+ sizeField.addPropertyChangeListener("value", this);
+ minNeighborsField.addPropertyChangeListener("value", this);
+ }
+
+ private void addComponents() {
+ add(startPauseButton);
+ add(restartButton);
+ add(showParticipants);
+ add(exportDataButton);
+ add(enableDensity);
+ add(enableForce);
+ add(epsilonLabel);
+ add(epsilonField);
+ add(muLabel);
+ add(muField);
+ add(alphaLabel);
+ add(alphaField);
+ add(flockRadiusLabel);
+ add(flockRadiusSlider);
+ add(gammaLabel);
+ add(gammaField);
+ add(initialParticipantsLabel);
+ add(initialParticipantsField);
+ add(percLabel);
+ add(percField);
+ add(rPartLabel);
+ add(rPartSlider);
+ add(sizeLabel);
+ add(sizeField);
+ add(minNeighborsLabel);
+ add(minNeighborsField);
+
+ setVisible(true);
+ }
+
+ /**
+ * Called when a field's "value" property changes.
+ */
+ /* @Override */
+ public void propertyChange(PropertyChangeEvent e) {
+ Object source = e.getSource();
+ if (source == epsilonField) {
+ simulation.epsilon =
+ ((Number) epsilonField.getValue()).doubleValue();
+ } else if (source == muField) {
+ simulation.mu = ((Number) muField.getValue()).doubleValue();
+ } else if (source == alphaField) {
+ simulation.alpha = ((Number) alphaField.getValue()).doubleValue();
+ } else if (source == gammaField) {
+ simulation.gamma = ((Number) gammaField.getValue()).doubleValue();
+ } else if (source == initialParticipantsField) {
+ simulation.numberOfPeople =
+ ((Number) initialParticipantsField.getValue()).intValue();
+ } else if (source == percField) {
+ simulation.percentParticipating =
+ ((Number) percField.getValue()).doubleValue();
+ } else if (source == rPartSlider) {
+ simulation.rParticipating =
+ ((Number) rPartSlider.getValue()).doubleValue();
+ } else if (source == sizeField) {
+ simulation.minCirclePitSize =
+ ((Number) sizeField.getValue()).intValue();
+ } else if (source == minNeighborsField) {
+ simulation.minParticipatingNeighbors =
+ ((Number) minNeighborsField.getValue()).intValue();
+ }
+ }
+
+ /* @Override */
+ public void stateChanged(ChangeEvent e) {
+ JSlider source = (JSlider) e.getSource();
+ if (source == rPartSlider && !source.getValueIsAdjusting()) {
+ simulation.rParticipating = (double) rPartSlider.getValue();
+ } else if (source == flockRadiusSlider &&
+ !source.getValueIsAdjusting()) {
+ simulation.flockRadius = (double) flockRadiusSlider.getValue();
+ }
+ }
+}
diff --git a/java_code/src/DataCollector.java b/java_code/src/DataCollector.java
new file mode 100644
index 000000000..3b31fdf78
--- /dev/null
+++ b/java_code/src/DataCollector.java
@@ -0,0 +1,296 @@
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class that automatically runs the simulation for one police configuration and
+ * harvests data from it.
+ */
+public class DataCollector implements ActionListener {
+
+ private final int MAX_TIME; // Max amount of timepoints to dump data for
+ private final int MAX_SEEDS; // Max amount of seeds to test
+ private final int dataCollectionInterval; // How often to collect data
+ public boolean hasInsertedPolice = false; // True if police inserted
+ private Simulation simulation; // Simulation for which to collect data
+ private PrintWriter fileCounterWriter; // Writes number of timepoints and
+ // number of seeds
+ private PrintWriter outWriter; // Writes data
+ private int seedCounter = 0; // Counts how many seeds have already been
+ // tested
+ private int timeCounter = 0; // Counts how many timepoints we have
+ // already dumped data for
+ private int realTimeElapsed = 0; // Amount of timesteps of the simulation
+ // elapsed
+ private int insertPoliceAfterCounter = 0; // Counter to test if we should
+ // insert police
+ private boolean stillWaitingToInsertPolice = true; // True if police not
+ // inserted yet
+ private int insertPoliceAfter; // How many timesteps to wait before
+ // inserting police
+ private boolean[][] policeSectors = new boolean[10][10]; // Sectors with
+ // police
+
+ private String configurationName; // Name of the configuration we are
+ // currently testing
+
+ public DataCollector(Simulation simulation, String configurationName,
+ int dataCollectionInterval, int insertPoliceAfter,
+ int maxSeeds, int maxTime, boolean[][] policeSectors) {
+ this.simulation = simulation;
+ this.dataCollectionInterval = dataCollectionInterval;
+ this.insertPoliceAfter = insertPoliceAfter;
+ this.policeSectors = policeSectors;
+ MAX_TIME = maxTime;
+ MAX_SEEDS = maxSeeds;
+ // Files are named as out_[seed#]_[time#].py in a subfolder for this
+ // configuration
+ File file = new File(configurationName + "/out_0_0.py");
+ file.getParentFile().mkdirs();
+ try {
+ fileCounterWriter = new PrintWriter(
+ configurationName + "/counter.py");
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+ try {
+ outWriter = new PrintWriter(configurationName + "/out_0_0.py",
+ "UTF-8");
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ this.configurationName = configurationName;
+ File initFile = new File(configurationName + "/__init__.py");
+ try {
+ initFile.createNewFile();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Iterates over the given list and, for each element of that list, adds the
+ * value of the field with the given name to a numpy array that is written
+ * to a file using the provided PrintWriter. The resulting array is named
+ * description.
+ *
+ * @param list The list from which to gather the data
+ * @param propertyName The property that we want to output
+ * @param writer The writer with which to write the data
+ * @param description The name of the numpy array
+ */
+ public static void writeNumPyArray(List list, String propertyName,
+ PrintWriter writer, String description) {
+ writer.print(description + " = array([");
+ boolean firstTime = true;
+ try {
+ for (Object object : list) {
+ Object value = object.getClass().getField(propertyName).get(
+ object);
+ if (firstTime) writer.print(value);
+ else writer.print(", " + value);
+ firstTime = false;
+ }
+ writer.println("])");
+ writer.flush();
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /*@Override*/
+ public void actionPerformed(ActionEvent e) {
+ PositionMatrix matrix = simulation.getMatrix();
+ realTimeElapsed +=
+ Simulation.TIMESTEP; // Check how much time has elapsed to
+ // see if we should dump data
+ if (!simulation.isCurrentIterationFinished) {
+ simulation.runOneTimestep();
+ simulation.repaint();
+ if (stillWaitingToInsertPolice) {
+ insertPoliceAfterCounter++;
+ }
+ if (insertPoliceAfterCounter >=
+ insertPoliceAfter) { // Check if the appropriate amount
+ // of time before inserting police
+ // has elapsed
+ stillWaitingToInsertPolice = false;
+ }
+ if (!stillWaitingToInsertPolice &&
+ !hasInsertedPolice) { // Insert the police
+ simulation.setMonitoredSectors(policeSectors);
+ this.hasInsertedPolice = true;
+ }
+ }
+ // Dump data if now is the right time
+ if (realTimeElapsed % dataCollectionInterval == 0 &&
+ !simulation.isCurrentIterationFinished) {
+ realTimeElapsed = 0;
+
+ outWriter.println("from numpy import *");
+ outWriter.flush();
+
+ List individuals = matrix.getIndividuals();
+
+ // Write data on positions of individuals
+ writeNumPyArray(individuals, "x", outWriter, "x");
+ writeNumPyArray(individuals, "y", outWriter, "y");
+
+ // Write data on danger levels of individuals
+ writeNumPyArray(individuals, "dangerLevel", outWriter,
+ "dangerLevel");
+ writeNumPyArray(individuals, "continuousDangerLevel", outWriter,
+ "continuousDangerLevel");
+
+ writeIsParticipatingData(
+ matrix); // Write data on which individuals are
+ // participating
+ writeNumPyArray(individuals, "f", outWriter,
+ "F"); // Write data on force acting on individuals
+ writeNumPyArray(individuals, "density", outWriter,
+ "density"); // Write data on density surrounding
+ // individuals
+ writeAverageDanger(matrix);
+ writeMaxDanger(matrix);
+ writeMedianDanger(matrix);
+
+ // If we have dumped data enough times, restart with a new seed
+ if (timeCounter >= MAX_TIME) {
+ timeCounter = 0;
+ simulation.setSeed(seedCounter);
+ seedCounter++;
+ simulation.restartSimulation();
+ hasInsertedPolice = false;
+ stillWaitingToInsertPolice = true;
+ insertPoliceAfterCounter = 0;
+ }
+ // If we have tested enough seeds, finish the simulation
+ if (seedCounter >= MAX_SEEDS) {
+ fileCounterWriter.println("n = " + MAX_TIME);
+ fileCounterWriter.println("m = " + MAX_SEEDS);
+ fileCounterWriter.flush();
+ fileCounterWriter.close();
+ outWriter.flush();
+ outWriter.close();
+ simulation.isCurrentIterationFinished = true;
+ } else {
+ resetWriters(configurationName + "/out_" + seedCounter + "_" +
+ timeCounter + ".py");
+ timeCounter++;
+ }
+ }
+ }
+
+ // Writes 1 to a numpy array if individual is participating, else 0
+ private void writeIsParticipatingData(PositionMatrix matrix) {
+ outWriter.print("isParticipating = array([");
+ boolean firstTime = true;
+ for (Individual individual : matrix.getIndividuals()) {
+ if (firstTime) outWriter.print(
+ (individual.isParticipating ? 1 : 0));
+ else outWriter.print(", " + (individual.isParticipating ? 1 : 0));
+ firstTime = false;
+ }
+ outWriter.println("])");
+ outWriter.flush();
+ }
+
+ // Writes the average danger of all the individuals
+ private void writeAverageDanger(PositionMatrix matrix) {
+ outWriter.print("averageDanger = ");
+ double averageDanger = 0;
+ for (Individual individual : matrix.getIndividuals()) {
+ averageDanger += individual.f / 10000 + individual.density / 50;
+ }
+ averageDanger /= matrix.getIndividuals().size();
+ outWriter.println(averageDanger);
+ outWriter.flush();
+ }
+
+ // Writes the max danger of all the individuals
+ private void writeMaxDanger(PositionMatrix matrix) {
+ outWriter.print("maxDanger = ");
+ double maxDanger = Double.MIN_VALUE;
+ for (Individual individual : matrix.getIndividuals()) {
+ maxDanger = Math.max(maxDanger, individual.f / 10000 +
+ individual.density / 50);
+ }
+ outWriter.println(maxDanger);
+ outWriter.flush();
+ }
+
+ private void writeMedianDanger(PositionMatrix matrix) {
+ outWriter.print("medianDanger = ");
+ // Check if there is an even amount of individuals
+ ArrayList individuals =
+ (ArrayList) matrix.getIndividuals();
+ int nOver2 = individuals.size() / 2;
+
+ double median = (individuals.size() % 2 == 0) ?
+ (getNthSmallestContinuousDangerLevel(individuals, nOver2) +
+ getNthSmallestContinuousDangerLevel(individuals,
+ nOver2 + 1)) / 2 :
+ getNthSmallestContinuousDangerLevel(individuals, nOver2);
+
+ outWriter.println(median);
+ outWriter.flush();
+ }
+
+ // QuickSelect algorithm
+ private static double getNthSmallestContinuousDangerLevel(
+ ArrayList individuals, int n) {
+ double result;
+ double pivot;
+
+ // 3 ArrayLists for elements smaller than pivot, equal to pivot,
+ // larger than pivot
+ ArrayList lessThanPivot = new ArrayList();
+ ArrayList greaterThanPivot = new ArrayList();
+ ArrayList equalToPivot = new ArrayList();
+
+ // Select a random pivot
+ pivot = individuals.get((int) (Math.random() *
+ individuals.size())).continuousDangerLevel;
+
+ // Add each element of the given list to the appropriate category
+ for (Individual individual : individuals) {
+ if (individual.continuousDangerLevel < pivot) {
+ lessThanPivot.add(individual);
+ } else if (individual.continuousDangerLevel > pivot) {
+ greaterThanPivot.add(individual);
+ } else {
+ equalToPivot.add(individual);
+ }
+ }
+
+ // Recurse into the appropriate category or return the pivot
+ if (n < lessThanPivot.size()) {
+ result = getNthSmallestContinuousDangerLevel(lessThanPivot, n);
+ } else if (n < lessThanPivot.size() + equalToPivot.size()) {
+ result = pivot;
+ } else {
+ result = getNthSmallestContinuousDangerLevel(greaterThanPivot, n -
+ lessThanPivot.size() - equalToPivot.size());
+ }
+
+ return result;
+ }
+
+ // Make sure we are writing to the appropriate file
+ private void resetWriters(String newOutFileName) {
+ try {
+ outWriter.close();
+ outWriter = new PrintWriter(newOutFileName, "UTF-8");
+ } catch (FileNotFoundException e3) {
+ e3.printStackTrace();
+ } catch (UnsupportedEncodingException e3) {
+ e3.printStackTrace();
+ }
+ }
+}
diff --git a/java_code/src/Individual.java b/java_code/src/Individual.java
new file mode 100644
index 000000000..a1735a4f9
--- /dev/null
+++ b/java_code/src/Individual.java
@@ -0,0 +1,94 @@
+/**
+ * Represents an individual.
+ */
+public class Individual {
+ /**
+ * The x position of this individual.
+ */
+ public double x;
+ /**
+ * The y position of this individual.
+ */
+ public double y;
+ /**
+ * The x velocity of this individual.
+ */
+ public double vx;
+ /**
+ * The y velocity of this individual.
+ */
+ public double vy;
+ /**
+ * True if the individual is participating in the circle pit.
+ */
+ public boolean isParticipating;
+ /**
+ * The size of the individual.
+ */
+ public double radius = 2;
+ /**
+ * The preferred speed of the individual.
+ */
+ public double preferredSpeed = 30;
+ /**
+ * The danger level that the individual is currently at. Ranges from 0 to 6.
+ */
+ public int dangerLevel;
+ /**
+ * The norm of the force currently acting on the individual.
+ */
+ public double f;
+ /**
+ * Number of neighbors of the individual.
+ */
+ public double density;
+ /**
+ * Continuous (rather than discrete) measure of the danger level of an
+ * individual.
+ */
+ public double continuousDangerLevel;
+
+ public Individual(double x, double y, double vx, double vy,
+ boolean isParticipating, int dangerLevel) {
+ this.x = x;
+ this.y = y;
+ this.vx = vx;
+ this.vy = vy;
+ this.isParticipating = isParticipating;
+ this.dangerLevel = dangerLevel;
+ }
+
+ public Individual(double[] position, double[] velocity,
+ boolean isParticipating, int dangerLevel) {
+ this(position[0], position[1], velocity[0], velocity[1],
+ isParticipating, dangerLevel);
+ }
+
+ public double[] getPosition() {
+ return new double[]{x, y};
+ }
+
+ public double[] getVelocity() {
+ return new double[]{vx, vy};
+ }
+
+ public double distanceTo(Individual other) {
+ double dx = Math.abs(x - other.x);
+ double dy = Math.abs(y - other.y);
+
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+
+ public double distanceTo(double[] point) {
+ double dx = Math.abs(x - point[0]);
+ double dy = Math.abs(y - point[1]);
+
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+
+ @Override
+ public String toString() {
+ return "Individual: position = (" + x + ", " + y + "), velocity = (" +
+ vx + ", " + vy + "), isParticipating = " + isParticipating;
+ }
+}
diff --git a/java_code/src/Main.java b/java_code/src/Main.java
new file mode 100644
index 000000000..83aa713ad
--- /dev/null
+++ b/java_code/src/Main.java
@@ -0,0 +1,14 @@
+import java.io.FileNotFoundException;
+
+public class Main {
+ public static void main(String[] args) throws FileNotFoundException {
+ // Run a manual simulation
+ // Simulation simulation = new Simulation(2, 10, 700, 600,500, 8,
+ // 0.01, 0.5, 6, 1, 3);
+ // simulation.runManualSimulation();
+
+ // Run an automatic simulation
+ AutomaticSimulator test = new AutomaticSimulator();
+ test.run();
+ }
+}
diff --git a/java_code/src/PositionMatrix.java b/java_code/src/PositionMatrix.java
new file mode 100644
index 000000000..a0831b34e
--- /dev/null
+++ b/java_code/src/PositionMatrix.java
@@ -0,0 +1,224 @@
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Data structure representing the position matrix in the simulation.
+ */
+public class PositionMatrix {
+
+ /**
+ * The width of the matrix
+ */
+ public final int width;
+ /**
+ * The height of the matrix
+ */
+ public final int height;
+ /**
+ * The size of one sector
+ */
+ public final int sectorSize;
+ /**
+ * A boolean matrix to indicate whether sector (i, j) is under police
+ * surveillance
+ */
+ public boolean[][] isPoliceAtSector;
+ // The actual matrix
+ private LinkedList[][] matrix;
+ // A List containing all the individuals, makes iterating over them easier
+ private ArrayList individuals;
+
+ /**
+ * Creates a new PositionMatrix
+ *
+ * @param width The desired width of the matrix
+ * @param height The desired height of the matrix
+ * @param sectorSize The desired sector size
+ */
+ public PositionMatrix(int width, int height, int sectorSize) {
+ this.height = height;
+ this.width = width;
+ this.sectorSize = sectorSize;
+
+ // Initialize the matrix
+ matrix = (LinkedList[][]) new LinkedList[width][height];
+ for (int i = 0; i < width; i++) {
+ for (int j = 0; j < height; j++) {
+ matrix[i][j] = new LinkedList();
+ }
+ }
+
+ individuals = new ArrayList();
+ isPoliceAtSector = new boolean[width][height];
+ }
+
+ /**
+ * Gets an individual at position (i, j) in the matrix.
+ *
+ * @param i The row of the individual
+ * @param j The column of the individual
+ * @return The individual at (i, j)
+ */
+ public List get(int i, int j) {
+ return matrix[i][j];
+ }
+
+ /**
+ * Gets an individual at the specified sector in the matrix.
+ *
+ * @param sector The sector that the individual is in.
+ * @return The individual at the given sector.
+ */
+ public List get(Sector sector) {
+ return matrix[sector.row][sector.col];
+ }
+
+ /**
+ * Gets a list of all the individuals.
+ *
+ * @return The list of the individuals.
+ */
+ public List getIndividuals() {
+ return individuals;
+ }
+
+ /**
+ * Adds a new individual to the matrix at the proper position.
+ *
+ * @param individual The individual to be added
+ */
+ public void add(Individual individual) {
+ Sector sector = getSectorForCoords(individual);
+ matrix[sector.row][sector.col].add(individual);
+ individuals.add(individual);
+ }
+
+ public void removeAndAdd(Individual individual, Sector oldSector,
+ Sector newSector) {
+ matrix[oldSector.row][oldSector.col].remove(individual);
+ matrix[newSector.row][newSector.col].add(individual);
+ }
+
+ /**
+ * Gets the neighbors of an individual.
+ *
+ * @param individual The individual for whom to search for neighbors
+ * @param radius The radius in which to search
+ * @return A java.util.List of the neighbors.
+ */
+ public List getNeighborsFor(Individual individual,
+ double radius) {
+ ArrayList neighbors = new ArrayList(10);
+ ArrayList sectorsToSearch = new ArrayList(9);
+ Sector sector = getSectorForCoords(individual);
+ sectorsToSearch.add(sector);
+
+ // Look around the current sector
+ for (int i = -1; i <= 1; i++) {
+ for (int j = -1; j <= 1; j++) {
+ Sector newSector = getSectorForCoords(individual.x + i * radius,
+ individual.y +
+ i * radius);
+ if (!sector.equals(newSector)) {
+ sectorsToSearch.add(newSector);
+ }
+ }
+ }
+
+ // Look for neighbors at the appropriate distance in the sectors to
+ // search
+ for (Sector sectorToSearch : sectorsToSearch) {
+ List possibleNeighbors = get(sectorToSearch);
+ for (Individual neighbor : possibleNeighbors) {
+ if (individual.distanceTo(neighbor) < radius) {
+ neighbors.add(neighbor);
+ }
+ }
+ }
+
+ return neighbors;
+ }
+
+ /**
+ * Gets the sector for the given coordinates.
+ *
+ * @param x The x coordinate
+ * @param y The y coordinate
+ * @return A Sector object corresponding the the given
+ * coordinates.
+ */
+ public Sector getSectorForCoords(double x, double y) {
+ int sectorX = (int) x / sectorSize;
+ int sectorY = (int) y / sectorSize;
+
+ // Make sure the sector is not out of bounds
+ if (sectorX < 0) sectorX = 0;
+ else if (sectorX >= width) sectorX = width - 1;
+
+ if (sectorY < 0) sectorY = 0;
+ else if (sectorY >= height) sectorY = height - 1;
+
+ return new Sector(sectorX, sectorY);
+ }
+
+ /**
+ * Gets the sector that the given individual is in.
+ *
+ * @param individual The individual for whom to get the sector
+ * @return The sector that the individual is in.
+ * @see PositionMatrix#getSectorForCoords(double, double)
+ */
+ public Sector getSectorForCoords(Individual individual) {
+ return getSectorForCoords(individual.x, individual.y);
+ }
+
+ /**
+ * Gets the sector that the given individual is in given an array of {x, y}
+ * coordinates.
+ *
+ * @param position The array of coordinates
+ * @return The sector corresponding to position
+ * @see PositionMatrix#getSectorForCoords(double, double)
+ */
+ public Sector getSectorForCoords(double[] position) {
+ return getSectorForCoords(position[0], position[1]);
+ }
+
+ /**
+ * Checks if the given sector is monitored by the police.
+ */
+ public boolean isSectorMonitored(Sector sector) {
+ return isPoliceAtSector[sector.row][sector.col];
+ }
+
+ /**
+ * Adds the given list of sectors to be monitored by the police.
+ *
+ * @param policeSectors A comma separated list of sectors, e.g. 0, 0, 1, 1,
+ * 2, 2
+ */
+ public void setMonitoredSectors(int... policeSectors) {
+ for (int i = 0; i < policeSectors.length; i += 2) {
+ isPoliceAtSector[policeSectors[i]][policeSectors[i + 1]] = true;
+ }
+ }
+
+ /**
+ * An inner class that represents one sector at a particular location in the
+ * matrix.
+ */
+ public class Sector {
+ int row; // Row of the matrix
+ int col; // Column of the matrix
+
+ public Sector(int row, int col) {
+ this.row = row;
+ this.col = col;
+ }
+
+ public boolean equals(Sector other) {
+ return row == other.row && col == other.col;
+ }
+ }
+}
diff --git a/java_code/src/Simulation.java b/java_code/src/Simulation.java
new file mode 100644
index 000000000..c58641991
--- /dev/null
+++ b/java_code/src/Simulation.java
@@ -0,0 +1,683 @@
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.FileNotFoundException;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * Class representing one or multiple simulations of a circle pit.
+ */
+public class Simulation {
+
+ /**
+ * Size of one sector of the matrix
+ */
+ public static final int SECTOR_SIZE = 10;
+ /**
+ * The duration of one timestep (in milliseconds)
+ */
+ public final static int TIMESTEP = 50;
+ /**
+ * Strength of repulsive force
+ */
+ public double epsilon;
+ /**
+ * Strength of propulsion
+ */
+ public double mu;
+ /**
+ * Strength of flocking force
+ */
+ public double alpha;
+ /**
+ * Strength of the centripetal force
+ */
+ public double gamma;
+ /**
+ * Number of people in the simulation
+ */
+ public double numberOfPeople;
+ /**
+ * Radius within which velocity of neighbors has an effect on the flocking
+ * force
+ */
+ public double flockRadius;
+ /**
+ * Timestep of the simulation
+ */
+ public double dt;
+ /**
+ * Percentage of people initially participating in the circle pit
+ */
+ public double percentParticipating;
+ /**
+ * Radius within which the 'isParticipating' of neighbors affects the
+ * individual
+ */
+ public double rParticipating;
+ /**
+ * Minimum amount of people necessary to constitute a circle pit
+ */
+ public int minCirclePitSize;
+ /**
+ * Necessary number of neighbors participating to start participating
+ */
+ public int minParticipatingNeighbors;
+ /**
+ * Center of the matrix
+ */
+ public double[] center;
+ /**
+ * Window with the simulation
+ */
+ public SimulationGUI window;
+ /**
+ * Safe density level
+ */
+ public int safeDensity = 10;
+ /**
+ * Density danger level 1
+ */
+ public int density1 = 20;
+ /**
+ * Density danger level 2
+ */
+ public int density2 = 40;
+ /**
+ * safe Force danger level
+ */
+ public int safeForce = 1000;
+ /**
+ * Force danger level 1
+ */
+ public int force1 = 3000;
+ /**
+ * Density danger level 2
+ */
+ public int force2 = 4000;
+ /**
+ * True if force is considered to be a danger factor
+ */
+ public boolean enableForce = true;
+ /**
+ * True if density is considered to be a danger factor
+ */
+ public boolean enableDensity = true;
+ /**
+ * False while the current iteration of the simulation is running (used for
+ * automation)
+ */
+ public boolean isCurrentIterationFinished = false;
+
+ private PrintWriter writer; // Writes analysis data to a file
+
+ private double maxX; // Right-hand border of the terrain
+ private double maxY; // Bottom border of the terrain
+ private Timer timer; // Timer to run the simulation
+
+ private Random random = new Random(42); // To generate random numbers
+ private int fileCounter = 0; // Counts how many files were written
+ private PrintWriter fileCounterWriter;
+ // Writes information about how many files were written to a file
+
+ private PositionMatrix matrix;
+
+ /**
+ * Creates a new Simulation with the specified parameters.
+ *
+ * @param epsilon Strength of the repulsive force
+ * @param mu Strength of the propulsive force
+ * @param alpha Strength of the flocking force
+ * @param gamma Strength of the centripetal force
+ * @param numberOfPeople Number of people at the concert
+ * @param flockRadius Radius in which to look for neighbors
+ * for the flocking force
+ * @param dt Duration of one timestep
+ * @param percentParticipating Proportion of people initially
+ * participating in the circle pit
+ * @param rParticipating Radius in which to search for
+ * participating neighbors
+ * @param minCirclePitSize Minimum number of participating
+ * neighbors needed to continue
+ * participating in the circle pit
+ * @param minParticipatingNeighbors Minimum number of participating
+ * neighbors needed to join in the circle
+ * pit
+ */
+ public Simulation(double epsilon, double mu, double alpha, double gamma,
+ double numberOfPeople, double flockRadius, double dt,
+ double percentParticipating, double rParticipating,
+ int minCirclePitSize, int minParticipatingNeighbors) {
+ this.epsilon = epsilon;
+ this.mu = mu;
+ this.alpha = alpha;
+ this.gamma = gamma;
+ this.numberOfPeople = numberOfPeople;
+ this.flockRadius = flockRadius;
+ this.dt = dt;
+ this.percentParticipating = percentParticipating;
+ this.rParticipating = rParticipating;
+ this.minCirclePitSize = minCirclePitSize;
+ this.minParticipatingNeighbors = minParticipatingNeighbors;
+ try {
+ fileCounterWriter = new PrintWriter("special_counter.py");
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+ initializeMatrix();
+ }
+
+ // Initializes the matrix with individuals with random velocity and
+ // position.
+ private void initializeMatrix() {
+ int matrixSize = 10;
+
+ // The maximum x and y values that an individual can have
+ maxX = matrixSize * SECTOR_SIZE;
+ maxY = matrixSize * SECTOR_SIZE;
+
+ center = new double[]{maxX / 2, maxY / 2};
+
+ matrix = new PositionMatrix(matrixSize, matrixSize,
+ SECTOR_SIZE);
+
+ for (int i = 0; i < numberOfPeople; i++) {
+ // Generate random coordinates
+ double[] coords = new double[2];
+ coords[0] = random.nextDouble() * SECTOR_SIZE * matrixSize;
+ coords[1] = random.nextDouble() * SECTOR_SIZE * matrixSize;
+
+ // Generate random velocity
+ double[] velocity = new double[]{random.nextDouble() - 0.5,
+ random.nextDouble() - 0.5};
+
+ // Decide whether individual is initially participating
+ boolean isParticipating =
+ random.nextDouble() < percentParticipating;
+
+ //levels of danger, 0 is safe, by default it's safe
+ int dangerLevel = 0;
+
+ Individual individual = new Individual(coords, velocity,
+ isParticipating,
+ dangerLevel);
+
+ // Add individual to appropriate sector
+ matrix.add(individual);
+ }
+ }
+
+ /**
+ * Resets the matrix of the simulation.
+ */
+ public void resetMatrix() {
+ stop();
+ basicReset();
+ }
+
+ /**
+ * Restarts the simulation.
+ */
+ public void restartSimulation() {
+ stop();
+ basicReset();
+ start();
+ }
+
+ /**
+ * Performs a basic reset of the simulation back to its initial state.
+ */
+ public void basicReset() {
+ initializeMatrix();
+ window.resetSimulationPanel();
+ window.repaint();
+ }
+
+ /**
+ * Stops the simulation.
+ */
+ public void stop() {
+ timer.stop();
+ }
+
+ /**
+ * Starts the simulation.
+ */
+ public void start() {
+ timer.start();
+ }
+
+ /**
+ * Creates a new Timer to run the simulation
+ *
+ * @param listener The ActionListener the new
+ * Timer should be based on
+ */
+ public void createNewTimer(ActionListener listener) {
+ timer = new Timer(TIMESTEP, listener);
+ }
+
+ /**
+ * Redraws the simulation.
+ */
+ public void repaint() {
+ window.repaint();
+ }
+
+ /**
+ * Sets the seed of the Random object used during the
+ * simulation.
+ *
+ * @param seed The seed to set the Random object to
+ */
+ public void setSeed(int seed) {
+ random = new Random(seed);
+ }
+
+ // Checks if the given neighbor at the given distance is participating
+ private boolean isNeighborParticipating(Individual neighbor,
+ double distance) {
+ return neighbor.isParticipating && distance < rParticipating;
+ }
+
+ /**
+ * Runs the simulation manually (so that the user can interact with it).
+ */
+ public void runManualSimulation() {
+ window = new SimulationGUI(this);
+
+ // Run a new frame every 50 milliseconds
+ timer = new Timer(50, new ActionListener() {
+ /*@Override*/
+ public void actionPerformed(ActionEvent e) {
+ runOneTimestep();
+ window.repaint();
+ }
+ });
+
+ window.setVisible(true);
+ }
+
+ /**
+ * Creates a new window that displays and animates the simulation.
+ */
+ public void createWindow() {
+ window = new SimulationGUI(this);
+ window.setVisible(true);
+ }
+
+ /**
+ * Runs the simulation automatically (for use for automatic data
+ * collection).
+ *
+ * @param name The name of the folder in which to put
+ * generated data.
+ * @param dataCollectionInterval How often to collect data (in
+ * milliseconds)
+ * @param insertPoliceAfter The amount of time after which police
+ * should be inserted, if any
+ * @param amountOfSeeds How many random seeds to test
+ * @param collectionTimes How many times to collect data per seed
+ */
+ public void runAutomaticSimulation(String name, int dataCollectionInterval,
+ int insertPoliceAfter, int amountOfSeeds,
+ int collectionTimes) {
+ window = new SimulationGUI(this);
+
+ DataCollector collector = new DataCollector(this, name,
+ dataCollectionInterval,
+ insertPoliceAfter,
+ amountOfSeeds,
+ collectionTimes,
+ new boolean[10][10]);
+ timer = new Timer(TIMESTEP, collector);
+ timer.start();
+ window.setVisible(true);
+ }
+
+ /**
+ * Runs one timestep of the simulation.
+ */
+ public void runOneTimestep() {
+
+ // List of all the individuals in the matrix
+ List individuals = matrix.getIndividuals();
+
+ // Iterate over each individual
+ for (Individual individual : individuals) {
+ // Sector where the individual is before updating position
+ PositionMatrix.Sector initialSector = matrix.getSectorForCoords(
+ individual);
+ // Amount of neighbors participating with the radius rParticipating
+ int sumParticipating = 0;
+ // Forces acting upon individual
+ double[] F = {0.0, 0.0};
+ // Sum of the neighbor velocities
+ double[] sumOverVelocities = {0.0, 0.0};
+ // List of neighbors
+ List neighbors = matrix.getNeighborsFor(individual,
+ flockRadius);
+ // Position and velocity of individual
+ double[] position = individual.getPosition();
+ double[] velocity = individual.getVelocity();
+ double r0 = 2 * individual.radius;
+
+ individual.dangerLevel = 0;
+ // Calculate the danger level
+ int numNeighbors = neighbors.size();
+
+ // We use the number of people in the neighbor list to represent
+ // density
+ if (enableDensity) {
+ if (numNeighbors > density2)
+ individual.dangerLevel = 3;
+ else if (numNeighbors > density1)
+ individual.dangerLevel = 2;
+ else if (numNeighbors > safeDensity)
+ individual.dangerLevel = 1;
+ else if (numNeighbors < safeDensity)
+ individual.dangerLevel = 0;
+ }
+
+ // ================= CALCULATION OF THE FORCES =====================
+ for (Individual neighbor : neighbors) {
+ // Make sure we are not using the individual him/herself
+ if (neighbor == individual) {
+ continue;
+ }
+ double[] positionNeighbor = neighbor.getPosition();
+ double[] velocityNeighbor = neighbor.getVelocity();
+
+ double distance = individual.distanceTo(neighbor);
+
+ sumParticipating += isNeighborParticipating(neighbor,
+ distance) ? 1 : 0;
+
+ // Repulsive force
+ // We only use neighbors within a radius of 2 * r0
+
+ if (distance < 2 * individual.radius) {
+ F[0] += epsilon * 500 * (individual.x - neighbor.x) /
+ distance;
+ F[1] += epsilon * 500 * (individual.y - neighbor.y) /
+ distance;
+ } else if (distance < 2 * r0) {
+ F[0] += -epsilon * ((1 / (distance - 2 * r0)) *
+ (position[0] - positionNeighbor[0])) / distance;
+ F[1] += -epsilon * ((1 / (distance - 2 * r0)) *
+ (position[1] - positionNeighbor[1])) / distance;
+ }
+
+ sumOverVelocities[0] += velocityNeighbor[0];
+ sumOverVelocities[1] += velocityNeighbor[1];
+ }
+
+ // Calculate the norm of the force
+ double jointForce = norm(F);
+
+ if (enableForce) {
+ if (jointForce > force2)
+ individual.dangerLevel += 3;
+ else if (jointForce > force1)
+ individual.dangerLevel += 2;
+ else if (jointForce > safeForce)
+ individual.dangerLevel += 1;
+ else if (jointForce < safeForce)
+ individual.dangerLevel += 0;
+ }
+
+ // Adjust the danger level if only one of the two options is enabled
+ if (enableForce ^ enableDensity) {
+ individual.dangerLevel *= 2;
+ }
+
+ // Decide if the individual is participating or not
+ if (sumParticipating >= minParticipatingNeighbors) {
+ individual.isParticipating = true;
+ }
+
+ if (sumParticipating < minCirclePitSize) {
+ individual.isParticipating = false;
+ }
+
+ if (matrix.isSectorMonitored(
+ matrix.getSectorForCoords(individual))) {
+ individual.isParticipating = false;
+ }
+
+ // Set preferred speed accordingly
+ individual.preferredSpeed =
+ individual.isParticipating ? 30 : 5 * random.nextDouble();
+
+ // Propulsion
+ // Makes the individual want to travel at their preferred speed
+ double vi = individual.preferredSpeed;
+ F[0] += -mu * (norm(velocity) - vi) * velocity[0] / norm(velocity);
+ F[1] += -mu * (norm(velocity) - vi) * velocity[1] / norm(velocity);
+
+ // Flocking
+ if (individual.isParticipating &&
+ !(sumOverVelocities[0] == 0 && sumOverVelocities[1] == 0)) {
+ double norm = norm(sumOverVelocities);
+ F[0] += alpha * sumOverVelocities[0] / norm;
+ F[1] += alpha * sumOverVelocities[1] / norm;
+ }
+
+ // Centripetal Force
+ if (individual.isParticipating) {
+ double distanceToCenter = individual.distanceTo(center);
+
+ // Normalized vector from center to individual
+ double[] r = new double[]{center[0] - individual.x,
+ center[1] - individual.y};
+ r[0] /= distanceToCenter;
+ r[1] /= distanceToCenter;
+
+ F[0] += gamma * r[0];
+ F[1] += gamma * r[1];
+ }
+
+ // Add noise
+ // TODO: Generate noise
+
+ // Make sure that F does not become too large to fit into a double
+ double normOfF = norm(F);
+
+ if (normOfF > Long.MAX_VALUE) {
+ F[0] /= normOfF * Long.MAX_VALUE;
+ F[1] /= normOfF * Long.MAX_VALUE;
+ }
+
+ // ====================== CALCULATE TIMESTEP ======================
+ // Using the leap-frog method to integrate the differential equation
+ // d^2y/dt^2 = rhs(y)
+
+ // Shifted initial velocity for leap-frog
+ double[] v_temp = new double[2];
+ v_temp[0] = velocity[0] + 0.5 * dt * F[0];
+ v_temp[1] = velocity[1] + 0.5 * dt * F[1];
+
+ // New position of the individual
+ double newX = position[0] + dt * v_temp[0];
+ double newY = position[1] + dt * v_temp[1];
+
+ // New velocity of the individual
+ double newVx = v_temp[0] + dt * F[0] / 2;
+ double newVy = v_temp[1] + dt * F[1] / 2;
+
+ // Make sure individuals rebound off the edges of the space
+ if (newX < 0 || newX > maxX) {
+ newVx = -newVx;
+ F[0] = -F[0];
+ }
+ if (newY < 0 || newY > maxY) {
+ newVy = -newVy;
+ F[1] = -F[1];
+ }
+
+ // Make sure they don't get stuck in an out-of-bounds area
+ if (newX >= 0 && newX <= maxX)
+ individual.x = newX;
+ if (newY >= 0 && newY <= maxY)
+ individual.y = newY;
+
+ individual.vx = newVx;
+ individual.vy = newVy;
+
+ // Add the individual to the correct sector
+ PositionMatrix.Sector newSector = matrix.getSectorForCoords(
+ individual);
+ if (!newSector.equals(initialSector)) {
+ matrix.removeAndAdd(individual, initialSector, newSector);
+ }
+
+ // Set the force acting on this individual and the amount of
+ // neighbors so that the danger level can be assessed
+ individual.f = norm(F);
+ individual.density = neighbors.size();
+ individual.continuousDangerLevel =
+ individual.f / 10000 + individual.density / 50;
+ }
+ }
+
+ /**
+ * Writes a small Python/Numpy script to allow analysis of the current
+ * situation.
+ */
+ public void exportData() {
+ try {
+ writer.close();
+ writer = new PrintWriter("special" + fileCounter + ".py", "UTF-8");
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ } catch (NullPointerException e) {
+ try {
+ writer = new PrintWriter("special" + fileCounter + ".py",
+ "UTF-8");
+ } catch (FileNotFoundException e1) {
+ e1.printStackTrace();
+ } catch (UnsupportedEncodingException e1) {
+ e1.printStackTrace();
+ }
+ }
+ try {
+ fileCounterWriter.close();
+ fileCounterWriter = new PrintWriter("special_counter.py");
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+ writer.println("from numpy import *");
+ writer.print("x = array([");
+ boolean firstTime = true;
+ for (Individual individual : matrix.getIndividuals()) {
+ if (firstTime) writer.print(individual.x);
+ else writer.print(", " + individual.x);
+ firstTime = false;
+ }
+ writer.println("])");
+ writer.flush();
+
+ writer.print("y = array([");
+ firstTime = true;
+ for (Individual individual : matrix.getIndividuals()) {
+ if (firstTime) writer.print(individual.y);
+ else writer.print(", " + individual.y);
+ firstTime = false;
+ }
+ writer.println("])");
+ writer.flush();
+
+ writer.print("dangerLevel = array([");
+ firstTime = true;
+ for (Individual individual : matrix.getIndividuals()) {
+ if (firstTime) writer.print(individual.dangerLevel);
+ else writer.print(", " + individual.dangerLevel);
+ firstTime = false;
+ }
+ writer.println("])");
+ writer.flush();
+
+ writer.print("isParticipating = array([");
+ firstTime = true;
+ for (Individual individual : matrix.getIndividuals()) {
+ if (firstTime) writer.print((individual.isParticipating ? 1 : 0));
+ else writer.print(", " + (individual.isParticipating ? 1 : 0));
+ firstTime = false;
+ }
+ writer.println("])");
+ writer.flush();
+
+ writer.print("F = array([");
+ firstTime = true;
+ for (Individual individual : matrix.getIndividuals()) {
+ if (firstTime) writer.print(individual.f);
+ else writer.print(", " + individual.f);
+ firstTime = false;
+ }
+ writer.println("])");
+ writer.flush();
+
+ writer.print("density = array([");
+ firstTime = true;
+ for (Individual individual : matrix.getIndividuals()) {
+ if (firstTime) writer.print(individual.density);
+ else writer.print(", " + individual.density);
+ firstTime = false;
+ }
+ writer.println("])");
+ writer.flush();
+ fileCounter++;
+ fileCounterWriter.println("n = " + fileCounter);
+ fileCounterWriter.flush();
+ }
+
+ // Calculates the norm of the given vector.
+ private double norm(double[] vector) {
+ return Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1]);
+ }
+
+ /**
+ * Gets the matrix associated with this object.
+ *
+ * @return The PositionMatrix object the individuals are stored
+ * in.
+ */
+ public PositionMatrix getMatrix() {
+ return matrix;
+ }
+
+ /**
+ * Gets the Timer that is running this simulation.
+ *
+ * @return
+ */
+ public Timer getSimulationTimer() {
+ return timer;
+ }
+
+ /**
+ * Sets which sectors are monitored by the police.
+ *
+ * @param sectors A comma-separated list of comma-separated pairs of numbers
+ * representing sectors monitored by the police
+ */
+ public void setMonitoredSectors(int... sectors) {
+ matrix.setMonitoredSectors(sectors);
+ }
+
+ /**
+ * Sets which sectors are monitored by the police.
+ *
+ * @param sectors A boolean[][] array containing
+ * true at position (i, j) if a policeman is in
+ * that sector
+ */
+ public void setMonitoredSectors(boolean[][] sectors) {
+ matrix.isPoliceAtSector = sectors;
+ }
+}
diff --git a/java_code/src/SimulationGUI.java b/java_code/src/SimulationGUI.java
new file mode 100644
index 000000000..9bc8446a2
--- /dev/null
+++ b/java_code/src/SimulationGUI.java
@@ -0,0 +1,55 @@
+import javax.swing.*;
+import java.awt.*;
+
+public class SimulationGUI extends JFrame {
+
+ private SimulationPanel simulationPanel;
+ private ControlPanel controlPanel;
+ private Simulation simulation;
+
+ public SimulationGUI(Simulation simulation) {
+ this.simulation = simulation;
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ } catch (InstantiationException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (UnsupportedLookAndFeelException e) {
+ e.printStackTrace();
+ }
+ setTitle("Circle Pit Simulation");
+ setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+ setLayout(new BorderLayout());
+ setResizable(false);
+
+ initComponents();
+ addComponents();
+ pack();
+ setLocationRelativeTo(null);
+ }
+
+ private void initComponents() {
+ PositionMatrix matrix = simulation.getMatrix();
+ simulationPanel = new SimulationPanel(500, 500, simulation,
+ matrix.width * matrix.sectorSize,
+ matrix.height *
+ matrix.sectorSize);
+
+ controlPanel = new ControlPanel(simulation, simulationPanel);
+ }
+
+ private void addComponents() {
+ add(simulationPanel, BorderLayout.CENTER);
+ add(controlPanel, BorderLayout.EAST);
+ }
+
+ /**
+ * Resets the simulation panel.
+ */
+ public void resetSimulationPanel() {
+ simulationPanel.setIndividuals(simulation.getMatrix().getIndividuals());
+ }
+}
diff --git a/java_code/src/SimulationPanel.java b/java_code/src/SimulationPanel.java
new file mode 100644
index 000000000..2697a1c7d
--- /dev/null
+++ b/java_code/src/SimulationPanel.java
@@ -0,0 +1,166 @@
+import javax.imageio.ImageIO;
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Draws the matrix into a JPanel.
+ */
+public class SimulationPanel extends JPanel {
+
+ public boolean shouldShowParticipants = true;
+ private java.util.List individuals;
+ private double xScalingFactor, yScalingFactor;
+ private Simulation simulation;
+ private BufferedImage image;
+
+ public SimulationPanel(int width, int height, Simulation simulation,
+ int matrixWidth, int matrixHeight) {
+ this.individuals = simulation.getMatrix().getIndividuals();
+ xScalingFactor = width / matrixWidth;
+ yScalingFactor = height / matrixHeight;
+ this.simulation = simulation;
+ try {
+ image = ImageIO.read(new File("policeman.png"));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ this.setSize(new Dimension(width, height));
+ this.setPreferredSize(new Dimension(width, height));
+ this.setMinimumSize(new Dimension(width, height));
+ this.setBackground(Color.WHITE);
+ addListeners();
+ setFocusable(false);
+ }
+
+ private void addListeners() {
+ // Add a policeman on mouse click
+ this.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ double x = e.getX() / xScalingFactor;
+ double y = e.getY() / yScalingFactor;
+ PositionMatrix.Sector sector =
+ simulation.getMatrix().getSectorForCoords(x, y);
+ simulation
+ .getMatrix().isPoliceAtSector[sector.row][sector.col] =
+ !(simulation
+ .getMatrix().isPoliceAtSector[sector
+ .row][sector.col]);
+ getParent().repaint();
+ }
+ });
+ }
+
+ /**
+ * Sets the individuals list to the given parameter.
+ */
+ public void setIndividuals(java.util.List individuals) {
+ this.individuals = individuals;
+ }
+
+ // Increases the rendering quality of the simulation
+ private void increaseRenderingQuality(Graphics2D g2d) {
+ g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+ RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ g2d.setRenderingHint(RenderingHints.KEY_DITHERING,
+ RenderingHints.VALUE_DITHER_ENABLE);
+ g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
+ RenderingHints.VALUE_RENDER_QUALITY);
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
+ RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+ g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
+ RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
+ g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
+ RenderingHints.VALUE_COLOR_RENDER_QUALITY);
+ g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
+ RenderingHints.VALUE_STROKE_PURE);
+ }
+
+ @Override
+ public void paintComponent(Graphics g) {
+ super.paintComponent(g);
+ int sumDanger = 0;
+ Graphics2D graphics2D = (Graphics2D) g.create();
+ increaseRenderingQuality(graphics2D); // Comment this out to
+ // potentially make animation
+ // smoother (if laggy)
+
+ // Draw each individual
+ for (Individual individual : individuals) {
+ double[] coords = individual.getPosition();
+ coords[0] *= xScalingFactor;
+ coords[1] *= yScalingFactor;
+
+ // Set the color depending on the danger level of the individual
+ int dangerLevel = individual.dangerLevel;
+ if (dangerLevel == 0) {
+ graphics2D.setColor(new Color(204, 229, 255));
+ } else if (dangerLevel == 1) {
+ graphics2D.setColor(new Color(154, 204, 255));
+ } else if (dangerLevel == 2) {
+ graphics2D.setColor(new Color(102, 178, 255));
+ } else if (dangerLevel == 3) {
+ sumDanger++;
+ graphics2D.setColor(new Color(51, 153, 255));
+ } else if (dangerLevel == 4) {
+ sumDanger += 2;
+ graphics2D.setColor(new Color(0, 128, 255));
+ } else if (dangerLevel == 5) {
+ sumDanger += 3;
+ graphics2D.setColor(new Color(0, 102, 204));
+ } else if (dangerLevel == 6) {
+ sumDanger += 4;
+ graphics2D.setColor(new Color(255, 51, 51));
+ }
+
+ graphics2D.fill(new Ellipse2D.Double(coords[0], coords[1],
+ individual.radius *
+ xScalingFactor,
+ individual.radius *
+ yScalingFactor));
+
+ // Fill the individual with a white circle if not participating
+ if (shouldShowParticipants) {
+ if (!individual.isParticipating) {
+ graphics2D.setColor(Color.WHITE);
+ graphics2D.fill(new Ellipse2D.Double(
+ coords[0] + individual.radius * xScalingFactor / 4,
+ coords[1] + individual.radius * yScalingFactor / 4,
+ individual.radius * xScalingFactor / 2,
+ individual.radius * yScalingFactor / 2));
+
+ }
+ }
+ }
+
+ // General Danger indicator
+ graphics2D.setColor(new Color(102, 102, 0));
+ graphics2D.fill(new Rectangle2D.Double(0, 10, 13, sumDanger / 5));
+ graphics2D.setColor(new Color(204, 204, 0));
+ graphics2D.fill(new Rectangle2D.Double(1, 11, 11, sumDanger / 5 - 2));
+
+ // Drawing the policemen
+ boolean[][] monitoredSectors = simulation.getMatrix().isPoliceAtSector;
+ for (int i = 0; i < monitoredSectors.length; i++) {
+ for (int j = 0; j < monitoredSectors[i].length; j++) {
+ if (monitoredSectors[i][j]) {
+ graphics2D.drawImage(image,
+ (int) ((i * 10 + 4) * xScalingFactor),
+ (int) ((j * 10 + 4) * yScalingFactor),
+ (int) (3 * xScalingFactor),
+ (int) (3 * yScalingFactor), null);
+ }
+ }
+ }
+ g.dispose();
+ }
+}
diff --git a/java_code/timeEvolution.py b/java_code/timeEvolution.py
new file mode 100644
index 000000000..d6a2beb41
--- /dev/null
+++ b/java_code/timeEvolution.py
@@ -0,0 +1,94 @@
+# -*- coding: utf-8 -*-
+from matplotlib.pylab import *
+from numpy import *
+
+colors = array(
+ ['dodgerblue', 'darkorange', 'g', 'red', 'purple', 'brown', 'violet',
+ 'grey', 'y', 'lightskyblue', 'black',
+ 'magenta'])
+
+
+def analyse_median_danger(test_set, i):
+ to_do = "from %s.counter import *" % test_set
+
+ exec(to_do, globals())
+
+ median_danger_time_evolution = zeros((n - 5, m))
+
+ t = linspace(0, 1, n - 5)
+ title('Time Evolution of Average of Median Danger')
+
+ for j in range(0, m): # iterating over different seeds
+ for k in range(0, n - 5): # iterating over time steps
+ filename = 'out_%s_%s' % (j, k)
+ exec("from %s.%s import *" % (test_set, filename),
+ globals()) # importing data for given seed and time steps
+ median_danger_time_evolution[k, j] += medianDanger
+ y = average(median_danger_time_evolution, axis=1)
+ ylabel('Median Danger')
+ ymax = max(y)
+ if (test_set == 'control'):
+ linewidth_ = 2
+ else:
+ linewidth_ = 1.2
+ plot(t, y / ymax, colors[i], linewidth=linewidth_, label=test_set)
+
+
+def analyse_is_participating(test_set, i):
+ toDo = "from %s.counter import *" % test_set
+
+ exec(toDo, globals())
+
+ is_participating_time_evolution = zeros(n - 5)
+ t = linspace(0, 1, n - 5)
+ ylim(0, 1)
+ title('Time Evolution of Participation Rate')
+ for j in range(0, m): # iterating over different seeds
+ for k in range(0, n - 5): # iterating over time steps
+ filename = 'out_%s_%s' % (j, k)
+ exec("from %s.%s import *" % (test_set, filename),
+ globals()) # importing data for given seed and time steps
+ is_participating_time_evolution[k] += sum(isParticipating) / (
+ 500 * 50)
+
+ if (test_set == 'control'):
+ linewidth_ = 2
+ else:
+ linewidth_ = 1.2
+
+ plot(t, is_participating_time_evolution, colors[i], linewidth=linewidth_,
+ label=test_set)
+ ylabel('Participation Rate')
+
+
+if __name__ == '__main__' and __package__ is None:
+ import sys, os.path as path
+
+ # Make sure we can import the out.py files
+ sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
+
+ # isParticipating: iterate over the configs listed in configs.sim
+ with open("configs.sim") as f:
+ next(f)
+ figure(figsize=(7, 5))
+ k = 0
+ for test_set in f:
+ analyse_is_participating(test_set.strip(), k)
+ k += 1
+
+ legend(prop={'size': 8}, fancybox=True, ncol=3, loc=1)
+ xlabel('Time')
+ savefig('isParticipating_timeEvolution.png', dpi=600)
+
+ # Median Danger: iterate over the configs listed in configs.sim
+ with open("configs.sim") as f:
+ next(f)
+ figure(figsize=(7, 5))
+ k = 0
+ for test_set in f:
+ analyse_median_danger(test_set.strip(), k)
+ k += 1
+
+ legend(prop={'size': 8}, fancybox=True, ncol=3, loc=1)
+ xlabel('Time')
+ savefig('medianDanger_timeEvolution.png', dpi=600)
diff --git a/research_proposal.pdf b/research_proposal.pdf
new file mode 100644
index 000000000..e972179af
Binary files /dev/null and b/research_proposal.pdf differ