In this post we will discuss the implementation of Social Forces in crowd simulations using SteerLite. The projects were created by a team of 3 as part of a class project for Introduction to Computer Graphics at Rutgers University.

## Demonstration

### Bottle Neck

**Info**
In this simulation a crowd of agents needs to pass through a narrow opening of
the room. The situation leads to many agents shoving each other to leave the
room.

Bench Scores:

1
2
3
4
5
6
7
8
9
10

$ ./steerbench Bottle_Neck.rec -detail -technique composite02
total number of agents: 200
avg. number of collisions per agent: 18.25
average time spent by one agent: 99.929
average energy spent by one agent: 1306.86
sum of instantaneous accelerations: 3230.26
(alpha, beta, gamma, delta) weights: (50,1,1,1)
weighted sum: 50*18.25 + 1*99.929 + 1*1306.86 + 1*3230.26 = 5549.54
final score: 5549.54

### One Way Hallway

**Info**
In this simulation a crowd of agents needs to pass through a hallway. The
agents are all traveling one direction.
room.

Bench Scores:

1
2
3
4
5
6
7
8
9
10

$ ./steerbench One_Way.rec -detail -technique composite02
total number of agents: 200
avg. number of collisions per agent: 0
average time spent by one agent: 84.3483
average energy spent by one agent: 1502.96
sum of instantaneous accelerations: 12.0091
(alpha, beta, gamma, delta) weights: (50,1,1,1)
weighted sum: 50*0 + 1*84.3483 + 1*1502.96 + 1*12.0091 = 1599.32
final score: 1599.32

### Two Way Hallway

**Info**
In this simulation a crowd of agents needs to pass through a hallway. The
agents are traveling in both directions.
room.

Bench Scores:

1
2
3
4
5
6
7
8
9
10

$ ./steerbench Two_Way.rec -detail -technique composite02
total number of agents: 200
avg. number of collisions per agent: 0
average time spent by one agent: 70.4994
average energy spent by one agent: 1220.02
sum of instantaneous accelerations: 220.666
(alpha, beta, gamma, delta) weights: (50,1,1,1)
weighted sum: 50*0 + 1*70.4994 + 1*1220.02 + 1*220.666 = 1511.18
final score: 1511.18

### Four Way Hallway

**Info**
In this simulation a crowd of agents need to pass through a four way
intersection.

Bench Scores:

1
2
3
4
5
6
7
8
9
10

$ ./steerbench Four_Way.rec -detail -technique composite02
total number of agents: 400
avg. number of collisions per agent: 0.015
average time spent by one agent: 76.1899
average energy spent by one agent: 1291.71
sum of instantaneous accelerations: 414.429
(alpha, beta, gamma, delta) weights: (50,1,1,1)
weighted sum: 50*0.015 + 1*76.1899 + 1*1291.71 + 1*414.429 = 1783.08
final score: 1783.08

# Implementation

#### Sum of Forces:

\[m_i\frac{dv_i}{dt} = F_{goal} + F_{agents} + F_{walls}\]This is the sum of all the forces that make up the Social Force.

1

Util::Vector acceleration = (prefForce + repulsionForce + proximityForce) / AGENT_MASS;

#### Goal Directed Force:

\[F_{goal} = m_i\frac{v_i^0(t)e^0_i(t) - v_i(t)}{\tau_i}\]This Force changes the speed and direction according to the direction of the goal.

1
2
3
4
5
6

Vector SocialForcesAgent::calcGoalForce(Vector _goalDirection, float _dt)
{
Util::Vector goalForce = (((_goalDirection * PREFERED_SPEED) - velocity()) / _dt)/5;
return goalForce;
}

We choose to divide the goal force by 5 so that it does not overpower other collision avoiding forces during cases such as the bottleneck test case. Here is a print out of the results before goal force was divided. We can see that the magnitude is roughly equal to the repulsion force. This is not good.

1
2
3
4
5

...
agent198 repulsion force (71.9985,0,-0.630486)
agent198 proximity force (6.77865,0,-14.0264)
agent198 pref force (-38.7242,0,-62.2515)
...

#### Agent Collision Avoidance Force:

\[F_{agents} = \sum_{j \ne i }F_{ij}\] \[F_{ij} = (A_ie^{\frac{r_{ij}-d_{ij}}{B_i}} + kg(r_{ij} - d_{ij}))n_{ij} + kg(r_{ij}-d_{ij})\Delta v^t_{ji}t_{ij}\]$ F_{ij} $ is the sum of forces of agent j on agent i

R is the Radii

d is the distance between centers of mass

A and B are constants

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Util::Vector SocialForcesAgent::calcAgentRepulsionForce(float dt)
{
...
for(std::set<SteerLib::SpatialDatabaseItemPtr>::iterator neighbor = _neighbors.begin(); neighbor != _neighbors.end(); neighbor++)
{
if( (*neighbor)->isAgent() )
tempAgent = dynamic_cast<SteerLib::AgentInterface *> (*neighbor);
else
continue;
if( (id() != tempAgent->id() ) && (tempAgent->computePenetration(this->position(),this->radius()) > 0.000001))
{
agent_repulsion_force = agent_repulsion_force + ( tempAgent->computePenetration(this->position(),this->radius()) * _SocialForcesParams.sf_agent_body_force * dt) * normalize(position() - tempAgent->position());
}
}
...
}

#### Wall Collision Avoidance Force:

\[F_{walls} = \sum_{j \ne i}F_{iW}\] \[F_{iW} = (A_ie^{\frac{r_{i}-d_{iW}}{B_i}} + kg(r_{i} - d_{iW}))n_{iW} - kg(r_{i}-d_{iW})(v_i * t_{iW})t_{iW}\]$ F_{iW} $ is the sum of forces of wall W on agent i

R is the Radii

d is the distance between centers of mass

A and B are constants

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

Util::Vector SocialForcesAgent::calcWallRepulsionForce(float dt)
{
...
for (std::set<SteerLib::SpatialDatabaseItemPtr>::iterator neighbor = _neighbors.begin(); neighbor!=_neighbors.end(); neighbor++)
{
if(!(*neighbor)->isAgent())
tmp_ob = dynamic_cast<SteerLib::ObstacleInterface *>(*neighbor);
else
continue;
if(tmp_ob->computePenetration(this->position(), this->radius()) > 0.000001)
{
Util::Vector wallNormal = calcWallNormal(tmp_ob);
std::pair<Util::Point,Util::Point> line = calcWallPointsFromNormal(tmp_ob, wallNormal);
std::pair<float, Util::Point> min_stuff = minimum_distance(line.first, line.second, this->position());
wall_repulsion_force = wall_repulsion_force + wallNormal * (min_stuff.first + this->radius()) * _SocialForcesParams.sf_body_force*dt;
}
}
...
}

Github Link: Here