Corridor¶
We want to qualitatively study the impact of non-standard Social Force potentials.
def initial_state_corridor(n):
_ = torch.manual_seed(42)
# first n people go right, second n people go left
state = torch.zeros((n * 2, 6))
# positions
state[:n, 0:2] = ((torch.rand((n, 2)) - 0.5) * 2.0) * torch.tensor([25.0, 4.5])
state[n:, 0:2] = ((torch.rand((n, 2)) - 0.5) * 2.0) * torch.tensor([25.0, 4.5])
# velocity
state[:n, 2] = torch.normal(torch.full((n,), 1.34), 0.26)
state[n:, 2] = torch.normal(torch.full((n,), -1.34), 0.26)
# x destination
state[:n, 4] = 100.0
state[n:, 4] = -100.0
return state
initial_state = initial_state_corridor(60)
The space is just two walls at y=5.0m and y=−5.0m. To avoid boundary effects, the walls extend beyond the periodic boundaries at x=−25m and x=25m.
upper_wall = torch.stack([torch.linspace(-30, 30, 600), torch.full((600,), 5)], -1)
lower_wall = torch.stack([torch.linspace(-30, 30, 600), torch.full((600,), -5)], -1)
ped_space = socialforce.potentials.PedSpacePotential([upper_wall, lower_wall])
Reference Potential¶
Standard SF:
ped_ped = socialforce.potentials.PedPedPotential()
# HIDE CODE
simulator = socialforce.Simulator(ped_ped=ped_ped, ped_space=ped_space,
oversampling=2, delta_t=0.08)
simulator.integrator = socialforce.simulator.PeriodicBoundary(
simulator.integrator, x_boundary=[-25.0, 25.0])
with torch.no_grad():
states_sf = simulator.run(initial_state, 250)
with socialforce.show.track_canvas(ncols=2, figsize=(12, 2), tight_layout=False) as (ax1, ax2):
socialforce.show.states(ax1, states_sf[0:1], monochrome=True)
socialforce.show.space(ax1, ped_space)
ax1.text(0.1, 0.1, '$t = 0s$', transform=ax1.transAxes)
ax1.set_xlim(-25, 25)
socialforce.show.states(ax2, states_sf[249:250], monochrome=True)
socialforce.show.space(ax2, ped_space)
ax2.text(0.1, 0.1, '$t = 20s$', transform=ax2.transAxes)
ax2.set_xlim(-25, 25)

# HIDE CODE
with socialforce.show.track_canvas(figsize=(6, 2), tight_layout=False, show=False, dpi=130) as ax:
ax.set_xlim(-25, 25)
socialforce.show.space(ax, ped_space)
video = socialforce.show.state_animation(ax, states_sf, delta_t=0.08).to_html5_video()
IPython.display.HTML(video)
Diamond Potential¶
ped_ped = socialforce.potentials.PedPedPotentialDiamond(sigma=0.5)
# HIDE CODE
simulator = socialforce.Simulator(ped_ped=ped_ped, ped_space=ped_space,
oversampling=2, delta_t=0.08)
simulator.integrator = socialforce.simulator.PeriodicBoundary(
simulator.integrator, x_boundary=[-25.0, 25.0])
with torch.no_grad():
states_diamond = simulator.run(initial_state, 250)
with socialforce.show.track_canvas(ncols=2, figsize=(12, 2), tight_layout=False) as (ax1, ax2):
socialforce.show.states(ax1, states_diamond[0:1], monochrome=True)
socialforce.show.space(ax1, ped_space)
ax1.text(0.1, 0.1, '$t = 0s$', transform=ax1.transAxes)
ax1.set_xlim(-25, 25)
socialforce.show.states(ax2, states_diamond[249:250], monochrome=True)
socialforce.show.space(ax2, ped_space)
ax2.text(0.1, 0.1, '$t = 20s$', transform=ax2.transAxes)
ax2.set_xlim(-25, 25)

# HIDE CODE
with socialforce.show.track_canvas(figsize=(6, 2), tight_layout=False, show=False, dpi=130) as ax:
ax.set_xlim(-25, 25)
socialforce.show.space(ax, ped_space)
video = socialforce.show.state_animation(ax, states_diamond, delta_t=0.08).to_html5_video()
IPython.display.HTML(video)
Asymmetric Diamond¶
ped_ped = socialforce.potentials.PedPedPotentialDiamond(sigma=0.5, asymmetry_angle=-20.0)
# HIDE CODE
simulator = socialforce.Simulator(ped_ped=ped_ped, ped_space=ped_space,
oversampling=2, delta_t=0.08)
simulator.integrator = socialforce.simulator.PeriodicBoundary(
simulator.integrator, x_boundary=[-25.0, 25.0])
with torch.no_grad():
states_diamond_sd = simulator.run(initial_state, 500)
with socialforce.show.track_canvas(ncols=2, figsize=(12, 2), tight_layout=False) as (ax1, ax2):
socialforce.show.states(ax1, states_diamond_sd[0:1], monochrome=True)
socialforce.show.space(ax1, ped_space)
ax1.text(0.1, 0.1, '$t = 0s$', transform=ax1.transAxes)
ax1.set_xlim(-25, 25)
socialforce.show.states(ax2, states_diamond_sd[499:500], monochrome=True)
socialforce.show.space(ax2, ped_space)
ax2.text(0.1, 0.1, '$t = 40s$', transform=ax2.transAxes)
ax2.set_xlim(-25, 25)

# HIDE CODE
with socialforce.show.track_canvas(figsize=(6, 2), tight_layout=False, show=False, dpi=130) as ax:
ax.set_xlim(-25, 25)
socialforce.show.space(ax, ped_space)
video = socialforce.show.state_animation(ax, states_diamond_sd, delta_t=0.08).to_html5_video()
IPython.display.HTML(video)
Speed Analysis¶
# HIDE CODE
def relative_speeds(states):
speeds = np.linalg.norm(states[:, :, 2:4], axis=-1)
preferred = states[:, :, 9]
relative = speeds / preferred
# ignore the first 50
relative = relative[50:]
return relative.reshape(-1)
def median_speed(states):
speeds = np.linalg.norm(states[:, :, 2:4], axis=-1)
# ignore the first 50
speeds = speeds[50:]
return np.median(speeds)
with socialforce.show.canvas() as ax:
r_sf = relative_speeds(states_sf)
r_diamond = relative_speeds(states_diamond)
r_diamond_sd = relative_speeds(states_diamond_sd)
ax.hist([r_sf, r_diamond, r_diamond_sd], bins=30, range=(0.8, 1.35), density=True,
label=[f'Social Force, $v_{{median}}$ = {median_speed(states_sf):.2f}m/s',
f'diamond, $v_{{median}}$ = {median_speed(states_diamond):.2f}m/s',
f'speed-dependent diamond, $v_{{median}}$ = {median_speed(states_diamond_sd):.2f}m/s'])
ax.legend()
ax.set_xlabel('$v / v_{preferred}$ [m/s]')

The simulation with standard social force potential leads to pedestrians that are above their preferred speed whereas in the simulation with the diamond potential the median speed as at the preferred speed of 1.34m/s. This is a consequence of the asymmetric nature of the Social Force: the force experianced by pedestrian α due β is different (not just opposite) from the force experience by β from α. When pedestrian α walks in front of β, β will feel almost no force to slow down as the potential of α is shifted more towards the front. Pedestrian α however will be in the range of the potential from β who is behind. That force will be halfed by the field-of-view modulation, but that is still a stronger force than what β experiences.
In this corridor example with the Social Force pedestrian-pedestrian potential, pedestrians that are in front tend to get pushed to accelerate more than the pedestrians behind to slow down. There is no such asymmetry in the diamond potential.
Asymmetry Analysis¶
# HIDE CODE
def x2(states):
x2_coordinates = np.copy(states[:, :, 1])
x2_coordinates[states[:, :, 6] < 0.0] *= -1.0
# only take last ones
x2_coordinates = x2_coordinates[-1]
return x2_coordinates.reshape(-1)
def mean_x2(states):
return np.mean(x2(states))
with socialforce.show.canvas() as ax:
x2_sf = x2(states_sf)
x2_diamond = x2(states_diamond)
x2_diamond_sd = x2(states_diamond_sd)
ax.hist([x2_sf, x2_diamond, x2_diamond_sd], bins=6, range=(-5.0, 5.0), density=True,
label=[f'Social Force, $\\overline{{x}}_2$ = {mean_x2(states_sf):.1f}m',
f'diamond, $\\overline{{x}}_2$ = {mean_x2(states_diamond):.1f}m',
f'speed-dependent diamond, $\\overline{{x}}_2$ = {mean_x2(states_diamond_sd):.1f}m'],
orientation='horizontal')
ax.legend()
ax.set_ylabel('$x_2$ [m]')
