Skip to content

Commit 28e5136

Browse files
author
Sami Hatna
committed
Merge branch 'dummy' into 'Tadej-Review'
Code review See merge request sami.hatna/crowd-simulation!10
2 parents 1079c3f + 7d4fd18 commit 28e5136

31 files changed

+2838
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/.vscode
2+
/build

CMakeLists.txt

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Copyright (C) 2022 Codeplay Software Ltd.
2+
cmake_minimum_required (VERSION 3.21.0)
3+
4+
set(CMAKE_CXX_STANDARD 17)
5+
set(CMAKE_CXX_STANDARD_REQUIRED True)
6+
7+
project(crowd-simulation)
8+
9+
OPTION(PROFILING_MODE "Enable profiling" off)
10+
if(PROFILING_MODE)
11+
add_definitions(-DPROFILING_MODE)
12+
else()
13+
find_package(SDL2 REQUIRED)
14+
include_directories(${SDL2_INCLUDE_DIRS})
15+
endif()
16+
17+
OPTION(STATS "Run in stats mode" off)
18+
if (STATS)
19+
add_definitions(-DSTATS)
20+
endif()
21+
22+
set(SYCL_BACKEND "SYCL_BACKEND" CACHE STRING "Backend chosen by the user at CMake configure time")
23+
set_property(CACHE SYCL_BACKEND PROPERTY STRINGS spir cuda hip)
24+
25+
if(SYCL_BACKEND STREQUAL hip)
26+
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsycl -fsycl-targets=amdgcn-amd-amdhsa")
27+
elseif(SYCL_BACKEND STREQUAL cuda)
28+
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsycl -fsycl-targets=nvptx64-nvidia-cuda")
29+
else()
30+
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsycl -fsycl-targets=spir64")
31+
endif()
32+
33+
find_package(Python QUIET)
34+
if(Python_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/scripts/InputFileGenerator.py")
35+
execute_process(COMMAND ${Python_EXECUTABLE} ../scripts/InputFileGenerator.py)
36+
else()
37+
message(WARNING "Unable to generate input configuration files")
38+
endif()
39+
40+
add_executable(crowdsim src/main.cpp)
41+
42+
add_subdirectory(external)
43+
44+
if (PROFILING_MODE)
45+
target_link_libraries(crowdsim PUBLIC external)
46+
else()
47+
target_link_libraries(crowdsim PUBLIC ${SDL2_LIBRARIES} external)
48+
endif()
49+
target_include_directories(crowdsim PUBLIC "${PROJECT_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/external")

LICENSE.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Copyright 2022 Codeplay Software Ltd.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use these files except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.

README.md

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# SYCL-Crowd-Simulation
2+
3+
SYCL GPU-accelerated crowd simulation engine based on Helbing et. al.'s social force model.
4+
5+
Dirk Helbing introduced the social force model in a paper in 1995, aimed at modelling the behaviour of crowds using Langevin equations. He proposed a refined model in a 2000 paper, "Simulating Dynamical Features of Escape Panic". Helbing posits that human behaviour in large crowds is determined by three component forces: A personal impulse towards one's destination, the cumulative force exerted by neighbouring people, and the repulsive force of any nearby walls. Together, these forces form the basis of a differential equation which can subsequently be integrated in order to calculate the actor's velocity.
6+
7+
## Features
8+
9+
- Performantly simulate tens of thousands of actors in real time
10+
- Define different crowds with different characteristics and different destinations
11+
- Define rooms and obstacles
12+
- Fully configurable environments (see [Input Format](#input-format))
13+
- Record and graph simulation metrics
14+
- Target and build for multiple SYCL supported backends
15+
- Apply a force heatmap across actors
16+
- The simulation kernels may be used separately from the GUI
17+
18+
## Dependencies
19+
20+
- The [DPC++ compiler](https://intel.github.io/llvm-docs/GetStartedGuide.html) is required to compile SYCL code
21+
- If targeting the DPC++ CUDA backend, the [CUDA runtime](https://intel.github.io/llvm-docs/GetStartedGuide.html#build-dpc-toolchain-with-support-for-nvidia-cuda) is required
22+
- If targeting the DPC++ OpenCL backend, an [OpenCL runtime](https://intel.github.io/llvm-docs/GetStartedGuide.html#install-low-level-runtime) is required
23+
- Graphics are rendered with [SDL2](https://lazyfoo.net/tutorials/SDL/01_hello_SDL/linux/index.php), installed with apt: `$ apt install libsdl2-dev`
24+
- Input files are parsed using [RapidJSON](https://rapidjson.org/index.html)
25+
RapidJSON is a header-only library, so can be installed by simply copying the directory `include/rapidjson` into your system include path
26+
- Python is needed to run scripts
27+
- Graphs are plotted using matplotlib, installed via pip: `$ pip install matplotlib`
28+
- To run simulations in headless mode and record video output, install [xvfb](https://www.x.org/releases/X11R7.6/doc/man/man1/Xvfb.1.xhtml) and [ffmpeg](https://ffmpeg.org/download.html) using apt
29+
30+
## Building
31+
32+
Build configuration is carried out using CMake.
33+
34+
The option `-DSYCL_BACKEND` allows you to select which backend to build for (spir, cuda or hip). By default, it builds for spir.
35+
36+
When enabled, the `-DPROFILING_MODE` option builds a headless version which can be run without the SDL dependency.
37+
38+
When enabled, the `-DSTATS` option will collect metrics whilst the simulation is running. Results are written to `output/outputStats`.txt. Graphs can be produced from these metrics by running the python script [PlotGraphs.py](scripts/PlotGraphs.py).
39+
40+
By default, CMake should generate example input files by running [InputFileGenerator.py](scripts/InputFileGenerator.py) when generating the project makefiles.
41+
42+
The `crowdsim` executable takes an input configuration JSON as a command line argument.
43+
44+
```
45+
$ git clone https://[repo link]
46+
$ cd crowd-simulation
47+
$ mkdir build && cd build
48+
$ cmake -DCMAKE_CXX_COMPILER=path/to/llvm/build/bin/clang++ -DSYCL_BACKEND=spir -DPROFILING_MODE=off -DSTATS=on ..
49+
$ cmake --build .
50+
$ ./crowdsim ../input/evacuateRoom.json
51+
```
52+
53+
## Input Format
54+
55+
Below is an annotated example input file which creates a room containing two actors with two different destinations.
56+
57+
```
58+
{
59+
"config": { <-- Configure environment
60+
"width": 9,
61+
"height": 9,
62+
"scale": 100,
63+
"delay": 0,
64+
"bgColor": [0, 0, 0],
65+
"wallColor": [255, 255, 255],
66+
"heatmapEnabled": true <-- Flag denoting whether
67+
}, the heatmap should be
68+
applied to actors
69+
"room": {
70+
"walls": [
71+
[0.5, 0.5, 8.5, 0.5], <-- Walls are defined via their
72+
[8.5, 0.5, 8.5, 8.5], start and end points
73+
[8.5, 8.5, 0.5, 8.5],
74+
[0.5, 8.5, 0.5, 0.5]
75+
]
76+
},
77+
78+
"actors": [ <-- Populate environment with
79+
{ actors
80+
"pos": [3.4, 5.6],
81+
"velocity": [0.0123, 0.0567],
82+
"desiredSpeed": 0.6,
83+
"pathId": 0,
84+
"mass": 50,
85+
"radius": 0.05,
86+
"atDestination": false,
87+
"color": [255, 0, 0],
88+
"heatmapEnabled": true
89+
},
90+
{
91+
"pos": [0.7, 7.3],
92+
"velocity": [0.0789, 0.0444],
93+
"desiredSpeed": 0.6,
94+
"pathId": 1,
95+
"mass": 45,
96+
"radius": 0.06,
97+
"atDestination": false,
98+
"color": [0, 255, 0],
99+
"heatmapEnabled": true
100+
}
101+
],
102+
103+
"paths": [
104+
{
105+
"id": 0, <-- Each path has a unique id,
106+
"checkpoints": [[[7.9, 5.6], [8.1, 5.8]]] referenced by any actor which
107+
}, takes that path
108+
{
109+
"id": 1,
110+
"checkpoints": [[[7.9, 5.6], [8.1, 5.8]], <-- Paths consist of checkpoints
111+
[[1.5, 2], [1.7, 2.2]]] Each checkpoint is a rectangular
112+
} region defined as:
113+
] [[minX, minY], [maxX, maxY]]
114+
}
115+
```
116+
117+
Larger input configurations can be generated with python scripts, as demonstrated in [InputFileGenerator.py](scripts/InputFileGenerator.py).
118+
119+
The social force model itself can be tweaked by altering the constexprs defined in [DifferentialEq.hpp](external/DifferentialEq.hpp). For example, in simulations involving large numbers of actors (10,000+), the values `WALLAi` and `PEOPLEAi` will need to be increased to prevent any clipping issues.
120+
121+
## Benchmarks
122+
123+
## Citations
124+
125+
- Helbing, D., Farkas, I. & Vicsek, T. Simulating dynamical features of escape panic. Nature 407, 487–490 (2000). https://doi.org/10.1038/35035023
126+
- Marsaglia, G. (2003). Xorshift RNGs. Journal of Statistical Software, 8(14), 1–6. https://doi.org/10.18637/jss.v008.i14

external/Actor.cpp

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/***************************************************************************
2+
*
3+
* Copyright (C) 2022 Codeplay Software Ltd.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
* Codeplay's crowd-simulation
18+
*
19+
* Actor.cpp
20+
*
21+
* Description:
22+
* Class denoting an actor in social force model
23+
*
24+
**************************************************************************/
25+
26+
#include "Actor.hpp"
27+
28+
Actor::Actor(sycl::float2 pPos, sycl::float2 pVelocity, float pDesiredSpeed,
29+
int pPathId, float pMass, float pRadius, bool pAtDestination,
30+
std::array<int, 3> pColor)
31+
: pos(pPos), velocity(pVelocity), desiredSpeed(pDesiredSpeed),
32+
pathId(pPathId), mass(pMass), radius(pRadius),
33+
atDestination(pAtDestination), color(pColor), destinationIndex(0),
34+
bBox({0, 0}) {}
35+
36+
SYCL_EXTERNAL sycl::float2 Actor::getPos() const { return pos; }
37+
38+
SYCL_EXTERNAL sycl::float2 Actor::getVelocity() const { return velocity; }
39+
40+
SYCL_EXTERNAL float Actor::getDesiredSpeed() const { return desiredSpeed; }
41+
42+
SYCL_EXTERNAL int Actor::getPathId() const { return pathId; }
43+
44+
SYCL_EXTERNAL int Actor::getDestinationIndex() const {
45+
return destinationIndex;
46+
}
47+
48+
SYCL_EXTERNAL float Actor::getMass() const { return mass; }
49+
50+
SYCL_EXTERNAL float Actor::getRadius() const { return radius; }
51+
52+
SYCL_EXTERNAL bool Actor::getAtDestination() const { return atDestination; }
53+
54+
SYCL_EXTERNAL std::array<int, 3> Actor::getColor() const { return color; }
55+
56+
SYCL_EXTERNAL std::array<int, 2> Actor::getBBox() const { return bBox; }
57+
58+
SYCL_EXTERNAL uint Actor::getSeed() const { return seed; }
59+
60+
SYCL_EXTERNAL float Actor::getForce() const { return force; }
61+
62+
SYCL_EXTERNAL void Actor::setPos(sycl::float2 newPos) { pos = newPos; }
63+
64+
SYCL_EXTERNAL void Actor::setVelocity(sycl::float2 newVelocity) {
65+
velocity = newVelocity;
66+
}
67+
68+
SYCL_EXTERNAL void Actor::setDesiredSpeed(float newDesiredSpeed) {
69+
desiredSpeed = newDesiredSpeed;
70+
}
71+
72+
SYCL_EXTERNAL void Actor::setAtDestination(bool param) {
73+
atDestination = param;
74+
}
75+
76+
SYCL_EXTERNAL void Actor::setColor(std::array<int, 3> newColor) {
77+
color = newColor;
78+
}
79+
80+
SYCL_EXTERNAL void Actor::setBBox(std::array<int, 2> newBBox) {
81+
bBox = newBBox;
82+
}
83+
84+
SYCL_EXTERNAL void Actor::setSeed(uint newSeed) { seed = newSeed; }
85+
86+
SYCL_EXTERNAL void Actor::setForce(float newForce) { force = newForce; }
87+
88+
SYCL_EXTERNAL void
89+
Actor::checkAtDestination(std::array<sycl::float2, 2> destination,
90+
int pathSize) {
91+
// Destinations are defined as rectangular regions
92+
if (pos[0] >= destination[0][0] && pos[0] <= destination[1][0] &&
93+
pos[1] >= destination[0][1] && pos[1] <= destination[1][1]) {
94+
if (destinationIndex >= PATHALLOCATIONSIZE - 1 ||
95+
destinationIndex >= pathSize - 1) {
96+
this->setAtDestination(true);
97+
} else {
98+
destinationIndex++;
99+
}
100+
}
101+
}

external/Actor.hpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/***************************************************************************
2+
*
3+
* Copyright (C) 2022 Codeplay Software Ltd.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
* Codeplay's crowd-simulation
18+
*
19+
* Actor.hpp
20+
*
21+
* Description:
22+
* Class denoting an actor in social force model
23+
*
24+
**************************************************************************/
25+
26+
#ifndef Actor_hpp
27+
#define Actor_hpp
28+
29+
#include "Path.hpp"
30+
#include "RandomNumber.hpp"
31+
#include <array>
32+
#include <iostream>
33+
#include <random>
34+
#include <sycl/sycl.hpp>
35+
#include <vector>
36+
37+
class Actor {
38+
private:
39+
std::array<int, 3> color;
40+
sycl::float2 pos;
41+
sycl::float2 velocity;
42+
std::array<int, 2> bBox;
43+
float desiredSpeed;
44+
int pathId;
45+
int destinationIndex;
46+
float mass;
47+
float radius;
48+
uint seed;
49+
float force;
50+
bool atDestination;
51+
52+
public:
53+
Actor(sycl::float2 pPos, sycl::float2 pVelocity, float pdesiredSpeed,
54+
int pPathId, float pMass, float pRadius, bool pAtDestination,
55+
std::array<int, 3> pColor);
56+
57+
SYCL_EXTERNAL sycl::float2 getPos() const;
58+
SYCL_EXTERNAL sycl::float2 getVelocity() const;
59+
SYCL_EXTERNAL float getDesiredSpeed() const;
60+
SYCL_EXTERNAL int getPathId() const;
61+
SYCL_EXTERNAL int getDestinationIndex() const;
62+
SYCL_EXTERNAL float getMass() const;
63+
SYCL_EXTERNAL float getRadius() const;
64+
SYCL_EXTERNAL bool getAtDestination() const;
65+
SYCL_EXTERNAL std::array<int, 3> getColor() const;
66+
SYCL_EXTERNAL std::array<int, 2> getBBox() const;
67+
SYCL_EXTERNAL uint getSeed() const;
68+
SYCL_EXTERNAL float getForce() const;
69+
70+
SYCL_EXTERNAL void setPos(sycl::float2 newPos);
71+
SYCL_EXTERNAL void setVelocity(sycl::float2 newVelocity);
72+
SYCL_EXTERNAL void setDesiredSpeed(float newDesiredSpeed);
73+
SYCL_EXTERNAL void setAtDestination(bool param);
74+
SYCL_EXTERNAL void setColor(std::array<int, 3> newColor);
75+
SYCL_EXTERNAL void setBBox(std::array<int, 2> newBBox);
76+
SYCL_EXTERNAL void setSeed(uint newSeed);
77+
SYCL_EXTERNAL void setForce(float newForce);
78+
79+
SYCL_EXTERNAL void
80+
checkAtDestination(std::array<sycl::float2, 2> destination, int pathSize);
81+
};
82+
83+
#endif

external/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Copyright (C) 2022 Codeplay Software Ltd.
2+
3+
add_library(external Actor.cpp
4+
Room.cpp
5+
Path.cpp
6+
MathHelper.cpp
7+
DifferentialEq.cpp
8+
Heatmap.cpp
9+
ParseInputFile.cpp
10+
RandomNumber.cpp
11+
Stats.cpp
12+
)

0 commit comments

Comments
 (0)