Comparative Analysis of Pedestrian Dynamics Models#

Objective#

This notebook compares four pedestrian dynamics models by simulating agent behavior in a
structured environment. Using simplified scenarios, we analyze how each model handles
navigation, obstacle avoidance, and agent interactions. This comparison reveals the strengths
and weaknesses of each approach, helping inform model selection when using JuPedSim.

When choosing a pedestrian dynamics model in JuPedSim, the decision largely depends on the
specific scenario you want to simulate or the behavior you want to reproduce. The available
models can be divided into two main categories: force-based and velocity-based models,
each with their own strengths and limitations.

Force-Based Models#

Force-based models, which include the Social Force Model (SFM) and the Generalized
Centrifugal Force Model (GCFM)
, excel at simulating physical interactions between pedestrians.
These models are particularly effective at capturing pushing behavior in dense crowds, making
them ideal for evacuation scenarios or situations where physical contact between pedestrians
is common. The GCFM offers some improvements over the basic SFM, particularly in handling
body shape effects.

Velocity-Based Models#

On the other hand, velocity-based models like the Collision-Free Model (CFM) and the
Anticipation Velocity Model (AVM) are better suited for normal walking situations where
collision avoidance is the primary concern. These models typically produce smoother, more
realistic trajectories in regular-density scenarios. The AVM, in particular, stands out for
its superior collision avoidance capabilities and ability to reproduce lane formation behavior,
as demonstrated in recent research.

Computational Efficiency#

When it comes to computational efficiency, velocity-based models generally have an advantage.
The CFM offers the fastest execution times, while the AVM provides a good balance between
computational efficiency and realistic behavior simulation. Force-based models, while more
computationally intensive, are necessary when accurate physical interaction modeling is crucial.

Model Selection Guidance#

The choice of model ultimately comes down to your specific requirements:

  • Force-based models (SFM, GCFM): Best for emergency evacuations or crowded environments
    with significant physical interactions.

  • Velocity-based models (AVM): Ideal for typical pedestrian scenarios requiring smooth
    navigation and realistic avoidance behavior.

  • Collision-Free Model (CFM): Suitable when computational resources are limited and
    physical interactions are not critical.

The key is to understand that no single model is universally superior—each has its place
depending on the specific requirements of your simulation scenario.

So as a final facit, which model to use? The answer is: it depends.

Models Under Investigation#

In this notebooks the models compared are:

  1. Collision-Free Speed Model (CSM):
    A velocity-based model focused on ensuring agents move without collisions
    by dynamically adjusting their speeds.

  2. Anticipation Velocity Model (AVM):
    A model that incorporates anticipation and reaction times, allowing agents
    to predict and avoid potential collisions.

  3. Social Force Model (SFM): A force-based model where agents are influenced
    by attractive forces toward goals and repulsive forces from obstacles and other agents.

  4. Generalized Centrifugal Force Model (GCFM):
    An enhanced force-based model where agents experience centrifugal forces
    to better simulate realistic avoidance behavior.

Note:
All models are utilized with their default parameter settings as defined in JuPedSim.

Hide code cell source
import pathlib

import jupedsim as jps
import matplotlib.pyplot as plt
import numpy as np
import pedpy
from jupedsim.internal.notebook_utils import animate, read_sqlite_file
from shapely import Polygon
from shapely.geometry import Point
from shapely.ops import unary_union


def initialize_simulation(
    model, agent_parameters, geometry, goals, positions, speeds, trajectory_file
):
    simulation = jps.Simulation(
        model=model,
        geometry=geometry,
        dt=0.01,
        trajectory_writer=jps.SqliteTrajectoryWriter(
            output_file=pathlib.Path(trajectory_file), every_nth_frame=5
        ),
    )

    exit_ids = [simulation.add_exit_stage(goal) for goal in goals]
    journey = jps.JourneyDescription(exit_ids)
    journey_id = simulation.add_journey(journey)
    centroids = [polygon.centroid.coords[0] for polygon in goals]
    orientations = [
        np.array(centroid) - np.array(position)
        for centroid, position in zip(centroids, positions)
    ]
    for pos, v0, exit_id, orientation in zip(
        positions, speeds, exit_ids, orientations
    ):
        if agent_parameters == jps.AnticipationVelocityModelAgentParameters:
            simulation.add_agent(
                agent_parameters(
                    journey_id=journey_id,
                    stage_id=exit_id,
                    desired_speed=v0,
                    position=pos,
                    anticipation_time=1,
                    reaction_time=0.3,
                )
            )
        elif agent_parameters == jps.SocialForceModelAgentParameters:
            simulation.add_agent(
                agent_parameters(
                    journey_id=journey_id,
                    stage_id=exit_id,
                    desiredSpeed=v0,
                    position=pos,
                    orientation=orientation,
                )
            )
        elif (
            agent_parameters
            == jps.GeneralizedCentrifugalForceModelAgentParameters
        ):
            simulation.add_agent(
                agent_parameters(
                    journey_id=journey_id,
                    stage_id=exit_id,
                    desired_speed=v0,
                    position=pos,
                    orientation=orientation,
                )
            )
        else:
            simulation.add_agent(
                agent_parameters(
                    journey_id=journey_id,
                    stage_id=exit_id,
                    position=pos,
                    desired_speed=v0,
                )
            )

    return simulation


def plot_simulation_configuration(geometry, starting_positions, exit_areas):
    """Plot setup for visual inspection."""
    walkable_area = pedpy.WalkableArea(geometry)
    axes = pedpy.plot_walkable_area(walkable_area=walkable_area)
    for exit_area in exit_areas:
        axes.fill(*exit_area.exterior.xy, color="indianred")

    axes.scatter(*zip(*starting_positions), label="Starting Position")
    axes.set_xlabel("x/m")
    axes.set_ylabel("y/m")
    axes.set_aspect("equal")
    axes.grid(True, alpha=0.3)


def plot_evacuation_times(times_dict, figsize=(10, 6)):
    """
    Plot evacuation times for different pedestrian models.
    """
    fig = plt.figure(figsize=figsize)

    bars = plt.bar(list(times_dict.keys()), list(times_dict.values()))

    plt.title("Evacuation Times by Model")
    plt.ylabel("Time (seconds)")
    plt.grid(axis="y", linestyle="--", alpha=0.3)

    # Add value labels on top of each bar
    for bar in bars:
        height = bar.get_height()
        plt.text(
            bar.get_x() + bar.get_width() / 2.0,
            height,
            f"{height:.1f}s",
            ha="center",
            va="bottom",
        )

    plt.tight_layout()
    return fig


def run_simulation(simulation, max_iterations=4000):
    while (
        simulation.agent_count() > 0
        and simulation.iteration_count() < max_iterations
    ):
        simulation.iterate()
    print(f"Evacuation time: {simulation.elapsed_time():.2f} s")
    return simulation.elapsed_time()


width = 600
height = 600

Scenario 1: Crossing Paths in Rooms#

Four agents navigate between interconnected rooms with obstacles. Each agent aims to reach the diagonally opposite goal. Agents are expected to plan paths around obstacles while interacting with other agents in the corridors.

Hide code cell source
def create_geometry_scenario1():
    outer_boundary = Polygon([(0, 0), (10, 0), (10, 10), (0, 10)])
    corridor_walls = [
        Polygon([(4.9, 0), (5.1, 0), (5.1, 3.8), (4.9, 3.8)]),
        Polygon([(4.9, 6.2), (5.1, 6.2), (5.1, 10), (4.9, 10)]),
        Polygon([(0, 4.9), (3.8, 4.9), (3.8, 5.1), (0, 5.1)]),
        Polygon([(6.2, 4.9), (10, 4.9), (10, 5.1), (6.2, 5.1)]),
    ]

    radius = 1.0
    circular_obstacles = [
        Point(2.5, 2.5).buffer(radius - 0.4),
        Point(7.5, 2.5).buffer(radius),
        Point(2.5, 7.5).buffer(radius + 0.35),
        Point(7.5, 7.5).buffer(radius - 0.2),
    ]

    all_obstacles = corridor_walls + circular_obstacles

    geometry = outer_boundary.difference(unary_union(all_obstacles))
    return geometry


def define_positions_scenario1():
    """Define initial positions and desired speeds."""
    positions = [(1, 1), (9, 9), (1, 9), (9, 1)]
    speeds = [1.0, 1.0, 1.0, 1.0]
    return positions, speeds


def define_goals_scenario1():
    """Define goal polygons."""
    goals = [
        Polygon([(8.5, 8.5), (9.5, 8.5), (9.5, 9.5), (8.5, 9.5)]),
        Polygon([(0.5, 0.5), (1.5, 0.5), (1.5, 1.5), (0.5, 1.5)]),
        Polygon([(8.5, 0.5), (9.5, 0.5), (9.5, 1.5), (8.5, 1.5)]),
        Polygon([(0.5, 8.5), (1.5, 8.5), (1.5, 9.5), (0.5, 9.5)]),
    ]
    return goals


geometry = create_geometry_scenario1()
goals = define_goals_scenario1()
positions, speeds = define_positions_scenario1()
plot_simulation_configuration(geometry, positions, goals)
times_dict = {}
../_images/133be01aaa59a714bd745ea96c970f442f229d91ffbca3cdbfb84abe7870313e.png

CSM Simulation#

model = "CFM"
trajectory_file = f"{model}.sqlite"
simulation = initialize_simulation(
    jps.CollisionFreeSpeedModelV2(),
    jps.CollisionFreeSpeedModelV2AgentParameters,
    geometry,
    goals,
    positions,
    speeds,
    trajectory_file,
)
times_dict[model] = run_simulation(simulation, max_iterations=5000)
trajectories, walkable_area = read_sqlite_file(trajectory_file)
animate(
    trajectories,
    walkable_area,
    title_note=model,
    every_nth_frame=5,
    width=width,
    height=height,
)
Evacuation time: 12.92 s