Skip to content

Commit 20eec74

Browse files
committed
Draw by motivation and remove adjustment of radius
1 parent 57b17a1 commit 20eec74

File tree

5 files changed

+72
-104
lines changed

5 files changed

+72
-104
lines changed

files/base.json

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"fps": 5,
2020
"time_step": 0.01,
2121
"number_agents": 35,
22-
"simulation_time": 100,
22+
"simulation_time": 99,
2323
"open_door_time": 100
2424
},
2525
"measurement_line": {
@@ -55,31 +55,26 @@
5555
]
5656
},
5757
"motivation_parameters": {
58-
"motivation_mode": "P",
58+
"motivation_mode": "PVE",
5959
"normal_v_0": 1.2,
6060
"normal_time_gap": 1.0,
61-
"width": 2,
62-
"height": 0.0,
61+
"width": 10,
62+
"height": 1.0,
6363
"seed": 12.0,
6464
"max_value_high": 1.8,
6565
"min_value_high": 1.5,
66-
"max_value_low": 1.0,
66+
"max_value_low": 1.3,
6767
"min_value_low": 1.0,
68-
"number_high_value": 0,
68+
"number_high_value": 15,
6969
"agent_buffer": 0.5,
7070
"do_adjust_buffer": false,
7171
"value_probability_sorting": false,
7272
"payoff": {
73-
"k": 8.0,
73+
"k": 2,
7474
"q0": 0.5,
7575
"rank_tie_tolerance_m": 0.001,
7676
"update_interval_s": 1.0
7777
},
78-
"do_adjust_radius": false,
79-
"adjust_radius_y_max": 19,
80-
"adjust_radius_y_min": 1,
81-
"min_radius": 0.1,
82-
"max_radius": 0.5,
8378
"mapping_function": "logistic",
8479
"motivation_min": 0.0,
8580
"inflection_target": 0.5,

files/base_high.json

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,6 @@
7373
"rank_tie_tolerance_m": 0.001,
7474
"update_interval_s": 1.0
7575
},
76-
"do_adjust_radius": false,
77-
"adjust_radius_y_max": 19,
78-
"adjust_radius_y_min": 1,
79-
"min_radius": 0.1,
80-
"max_radius": 0.5,
8176
"mapping_function": "logistic",
8277
"motivation_min": 0.0,
8378
"inflection_target": 0.5,

files/base_low.json

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,6 @@
7373
"rank_tie_tolerance_m": 0.001,
7474
"update_interval_s": 1.0
7575
},
76-
"do_adjust_radius": false,
77-
"adjust_radius_y_max": 19,
78-
"adjust_radius_y_min": 1,
79-
"min_radius": 0.1,
80-
"max_radius": 0.5,
8176
"mapping_function": "logistic",
8277
"motivation_min": 0.0,
8378
"inflection_target": 0.5,

simulation.py

Lines changed: 42 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ def export_trajectory_to_txt(
151151
motivation_model: mm.MotivationModel,
152152
output_file="output.txt",
153153
geometry_file="geometry.xml",
154+
motivation_csv: pathlib.Path | None = None,
154155
df=10,
155156
v0=1.2,
156157
radius=0.18,
@@ -174,14 +175,10 @@ def export_trajectory_to_txt(
174175
# Sort by frame within each trajectory
175176
group = group.sort_values(by="frame")
176177
traj = group[["x", "y"]].values
177-
agent_value = motivation_model.motivation_strategy.get_value(agent_id=traj_id)
178178

179179
# Calculate speed for this trajectory
180180
speed = compute_speed(traj, df, fps)
181-
# if agent_value > 1.0:#green
182-
values.extend([-1] * len(speed))
183-
# else:#blue
184-
# values.extend([10]*len(speed))
181+
values.extend([0.0] * len(speed))
185182

186183
# Store speed and corresponding frame indices
187184
speeds.extend(speed)
@@ -194,9 +191,42 @@ def export_trajectory_to_txt(
194191
df_data.loc[frame_indices, "speed"] = speed_series
195192
df_data["color"] = (df_data["speed"] / v0 * 255).clip(0, 255).astype(int)
196193
else:
197-
value_series = pd.Series(values, index=frame_indices)
198-
df_data.loc[frame_indices, "value"] = value_series
199-
df_data["color"] = df_data["value"]
194+
if motivation_csv is not None and motivation_csv.exists():
195+
motivation_df = pd.read_csv(motivation_csv)
196+
if not ("frame" in motivation_df.columns and "id" in motivation_df.columns):
197+
motivation_df = pd.read_csv(
198+
motivation_csv,
199+
names=[
200+
"frame",
201+
"id",
202+
"time",
203+
"motivation",
204+
"x",
205+
"y",
206+
"value",
207+
"rank_abs",
208+
"rank_q",
209+
"payoff_p",
210+
"rank_update_flag",
211+
],
212+
)
213+
motivation_slice = motivation_df[["frame", "id", "motivation"]].copy()
214+
df_data = df_data.merge(
215+
motivation_slice,
216+
on=["frame", "id"],
217+
how="left",
218+
suffixes=("", "_m"),
219+
)
220+
if "motivation_m" in df_data.columns:
221+
df_data["motivation"] = df_data["motivation"].fillna(
222+
df_data["motivation_m"]
223+
)
224+
df_data.drop(columns=["motivation_m"], inplace=True)
225+
df_data["motivation"] = df_data["motivation"].fillna(0.0)
226+
else:
227+
value_series = pd.Series(values, index=frame_indices)
228+
df_data.loc[frame_indices, "motivation"] = value_series
229+
df_data["color"] = (df_data["motivation"] * 255).clip(0, 255).astype(int)
200230

201231
# Write the formatted data to the output file
202232
with open(output_file, "w") as f:
@@ -430,52 +460,6 @@ def init_simulation(
430460
return simulation, geometry_open
431461

432462

433-
def adjust_radius_with_distance(
434-
position_y: float,
435-
motivation_i: float,
436-
min_value: float = 0.1,
437-
max_value: float = 0.5,
438-
y_min: float = -1, # Start reducing radius from this y position
439-
y_max: float = 19, # Exit position where radius should be min_value
440-
min_motivation: float = 1,
441-
) -> float:
442-
"""
443-
Adjust the radius based on agent's motivation level and distance to exit.
444-
445-
:param position_y: The pedestrian's current y position.
446-
:param motivation_i: The agent's motivation level (1 <= motivation_i <= 3).
447-
:param min_value: Minimum radius near the exit (y_max).
448-
:param max_value: Maximum radius when far from the exit.
449-
:param y_min: Position where radius starts decreasing.
450-
:param y_max: Position where radius is minimal.
451-
:return: Adjusted radius.
452-
"""
453-
max_motivation = 3.6 / 1.2
454-
# Ensure position_y is within the defined range
455-
position_y = max(min(position_y, y_max), y_min)
456-
457-
# Compute distance-based factor (1 when far, 0 when at exit)
458-
distance_factor = (y_max - position_y) / (y_max - y_min)
459-
460-
# Compute motivation-dependent base radius (inverse relationship)
461-
motivation_radius = max_value - (max_value - min_value) * (
462-
motivation_i - min_motivation
463-
) / (max_motivation - min_motivation)
464-
# print("-----------------------")
465-
# print(f"{y_min = }, {y_max = }")
466-
# print(f"{min_value = }, {max_value = }")
467-
# print(
468-
# f"{position_y = }, {motivation_i = }, {min_motivation = }, {motivation_radius = } "
469-
# )
470-
# print(
471-
# f"{min_value = }, {motivation_radius = }, {distance_factor = }, --> {min_value + (motivation_radius - min_value) * distance_factor}"
472-
# )
473-
# input()
474-
475-
# Scale radius based on distance factor
476-
return min_value + (motivation_radius - min_value) * distance_factor
477-
478-
479463
def process_agent(
480464
agent: jps.Agent,
481465
door: Point,
@@ -528,30 +512,7 @@ def process_agent(
528512
motivation_i
529513
)
530514

531-
# Usage in the agent model
532-
do_adjust_radius = False
533-
if "do_adjust_radius" in _data["motivation_parameters"]:
534-
do_adjust_radius = _data["motivation_parameters"]["do_adjust_radius"]
535-
536-
if do_adjust_radius: # Adjust radius based on distance to exit
537-
min_value_y = _data["motivation_parameters"]["adjust_radius_y_min"]
538-
max_value_y = _data["motivation_parameters"]["adjust_radius_y_max"]
539-
min_value_radius = _data["motivation_parameters"]["min_radius"]
540-
max_value_radius = _data["motivation_parameters"]["max_radius"]
541-
min_motivation = _data["motivation_parameters"]["min_value_low"]
542-
agent.model.radius = adjust_radius_with_distance(
543-
position_y=position[1],
544-
motivation_i=motivation_i,
545-
min_value=min_value_radius, # Smallest radius near the exit
546-
max_value=max_value_radius, # Largest radius when far away
547-
y_min=min_value_y, # Start decreasing radius here
548-
y_max=max_value_y, # Minimum radius at exit
549-
min_motivation=min_motivation,
550-
)
551-
else:
552-
agent.model.radius = _data["velocity_init_parameters"][
553-
"radius"
554-
] # Fixed radius at the exit
515+
agent.model.radius = _data["velocity_init_parameters"]["radius"]
555516

556517
# 0,3
557518
# 1,6
@@ -1057,16 +1018,18 @@ def main(
10571018
trajectory_data, walkable_area = read_sqlite_file(output_path)
10581019
output_file = "jpsvis_files" + pathlib.Path(output_path).stem + ".txt"
10591020
geometry_file = pathlib.Path(output_path).stem + "_geometry.xml"
1021+
motivation_csv = output_path.with_name(output_path.stem + "_motivation.csv")
10601022
logging.info(f"Using: {geometry_file} ")
10611023
v0_mean = 1.2
10621024
export_trajectory_to_txt(
10631025
trajectory_data,
10641026
motivation_model,
10651027
output_file=output_file,
10661028
geometry_file=geometry_file,
1029+
motivation_csv=motivation_csv,
10671030
df=10,
10681031
v0=v0_mean,
1069-
by_speed=True,
1032+
by_speed=False,
10701033
)
10711034

10721035
polygon_to_xml(walkable_area=walkable_area, output_file=geometry_file)

src/analysis.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,21 @@ def plot_distance_to_entrance(
452452
unit_text: str,
453453
) -> matplotlib_fig:
454454
"""Plot the distance to entrance with speed or motivation coloring."""
455+
if df_time_distance.empty or speed.empty:
456+
fig, ax = plt.subplots()
457+
ax.set_title("Distance to entrance/Time to entrance")
458+
ax.set_xlabel("Distance / m")
459+
ax.set_ylabel("Time / s")
460+
ax.text(
461+
0.5,
462+
0.5,
463+
"No trajectory data available for selected input.",
464+
ha="center",
465+
va="center",
466+
transform=ax.transAxes,
467+
)
468+
return fig
469+
455470
norm = Normalize(speed["speed"].min(), speed["speed"].max())
456471
# cmap = cm.jet
457472
cmap = cm.get_cmap("jet")
@@ -460,8 +475,11 @@ def plot_distance_to_entrance(
460475

461476
# Plot each trajectory
462477
trajectory_ids = df_time_distance[ID_COL].unique()
478+
line = None
463479
for traj_id in trajectory_ids:
464480
traj_data = df_time_distance[df_time_distance[ID_COL] == traj_id]
481+
if len(traj_data) < 2:
482+
continue
465483
speed_id = speed[speed[ID_COL] == traj_id]["speed"].to_numpy()
466484
points = traj_data[["distance", "time_seconds"]].to_numpy()
467485
segments = [
@@ -484,8 +502,9 @@ def plot_distance_to_entrance(
484502
)
485503

486504
# Add colorbar and labels
487-
cbar = fig.colorbar(line, ax=ax)
488-
cbar.set_label(unit_text)
505+
if line is not None:
506+
cbar = fig.colorbar(line, ax=ax)
507+
cbar.set_label(unit_text)
489508

490509
# Set plot properties
491510
ax.autoscale()
@@ -495,7 +514,8 @@ def plot_distance_to_entrance(
495514
ax.set_xlabel("Distance / m")
496515
ax.set_ylabel("Time / s")
497516
ax.set_ylim(top=yaxis_max)
498-
line.set_clim(vmax=colorbar_max)
517+
if line is not None:
518+
line.set_clim(vmax=colorbar_max)
499519

500520
return fig
501521

0 commit comments

Comments
 (0)