First
This commit is contained in:
BIN
archive/SRS_evac_path/SRS_evac.sqlite
Normal file
BIN
archive/SRS_evac_path/SRS_evac.sqlite
Normal file
Binary file not shown.
BIN
archive/SRS_evac_path/SRS_evac_2025-11-24_00-23-22.sqlite
Normal file
BIN
archive/SRS_evac_path/SRS_evac_2025-11-24_00-23-22.sqlite
Normal file
Binary file not shown.
BIN
archive/SRS_evac_path/SRS_evac_2025-11-24_00-41-16.sqlite
Normal file
BIN
archive/SRS_evac_path/SRS_evac_2025-11-24_00-41-16.sqlite
Normal file
Binary file not shown.
BIN
archive/SRS_evac_path/SRS_evac_2025-11-24_00-42-15.sqlite
Normal file
BIN
archive/SRS_evac_path/SRS_evac_2025-11-24_00-42-15.sqlite
Normal file
Binary file not shown.
BIN
archive/SRS_evac_path/SRS_evac_2025-11-24_00-45-35.sqlite
Normal file
BIN
archive/SRS_evac_path/SRS_evac_2025-11-24_00-45-35.sqlite
Normal file
Binary file not shown.
BIN
archive/SRS_evac_path/SRS_evac_2025-11-24_00-51-43.sqlite
Normal file
BIN
archive/SRS_evac_path/SRS_evac_2025-11-24_00-51-43.sqlite
Normal file
Binary file not shown.
BIN
archive/SRS_evac_path/SRS_evac_2025-11-24_00-52-52.sqlite
Normal file
BIN
archive/SRS_evac_path/SRS_evac_2025-11-24_00-52-52.sqlite
Normal file
Binary file not shown.
BIN
archive/SRS_evac_path/SRS_evac_2025-11-24_00-54-40.sqlite
Normal file
BIN
archive/SRS_evac_path/SRS_evac_2025-11-24_00-54-40.sqlite
Normal file
Binary file not shown.
BIN
archive/SRS_evac_path/SRS_evac_2025-11-24_01-01-57.sqlite
Normal file
BIN
archive/SRS_evac_path/SRS_evac_2025-11-24_01-01-57.sqlite
Normal file
Binary file not shown.
BIN
archive/SRS_evac_path/SRS_evac_2025-11-30_19-35-45.sqlite
Normal file
BIN
archive/SRS_evac_path/SRS_evac_2025-11-30_19-35-45.sqlite
Normal file
Binary file not shown.
BIN
archive/SRS_evac_path/SRS_evac_2025-11-30_19-37-01.sqlite
Normal file
BIN
archive/SRS_evac_path/SRS_evac_2025-11-30_19-37-01.sqlite
Normal file
Binary file not shown.
286
archive/SRS_modeling_2025-11-09.py
Normal file
286
archive/SRS_modeling_2025-11-09.py
Normal file
@@ -0,0 +1,286 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Sat Nov 8 22:59:23 2025
|
||||
|
||||
@author: ethan
|
||||
"""
|
||||
|
||||
#! /usr/bin/env python3
|
||||
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import pathlib
|
||||
import jupedsim as jps
|
||||
from shapely import Polygon
|
||||
from shapely.plotting import plot_polygon
|
||||
from collections import deque
|
||||
|
||||
def main():
|
||||
grades = {
|
||||
# mean and standard deviation for
|
||||
# average population size
|
||||
# and average speed by grade levels
|
||||
"Kindergarden":np.array([31.43,5.65,1.21,0.24]),
|
||||
"Grade 1":np.array([32.57,6.27,1.35,0.26]),
|
||||
"Grade 2":np.array([34.43,6.80,1.42,0.28]),
|
||||
"Grade 3":np.array([35.43,5.19,1.48,0.23]),
|
||||
"Grade 4":np.array([34.86,6.77,1.58,0.26]),
|
||||
"Grade 5":np.array([36.71,7.09,1.59,0.24]),
|
||||
"Grade 6":np.array([37.71,6.99,1.65,0.24]),
|
||||
"Grade 7":np.array([40.43,6.02,1.61,0.25]),
|
||||
"Grade 8":np.array([40.43,5.50,1.66,0.24]),
|
||||
"Grade 9":np.array([44.14,4.85,1.60,0.24]),
|
||||
"Grade 10":np.array([46.29,6.29,1.57,0.23]),
|
||||
"Grade 11":np.array([48.29,3.30,1.51,0.22]),
|
||||
"Grade 12":np.array([43.71,6.02,1.54,0.23])
|
||||
}
|
||||
df=pd.DataFrame({
|
||||
"Grade Level":(
|
||||
list(grades.keys())),
|
||||
"Pop Mean":[
|
||||
grades[j][0] for j in grades],
|
||||
"Pop Std Dev":[
|
||||
grades[j][1] for j in grades],
|
||||
"Speed Mean":[
|
||||
grades[j][2] for j in grades],
|
||||
"Speed Std Dev":[
|
||||
grades[j][3] for j in grades]})
|
||||
rng = np.random.default_rng(seed=42)
|
||||
A_crosswalk=Polygon([
|
||||
(-1,1.499),(-1,3.327),
|
||||
(0,3.327),(11.214, 3.327),
|
||||
(11.214,1.499),(0,1.499)])
|
||||
B_queue=Polygon([
|
||||
(11.214, 0),(22.163, 0),
|
||||
(22.163, 4.826),(11.214, 4.826)])
|
||||
C_road_adj_path=Polygon([
|
||||
(21.787,4.826),(24.214,4.826),
|
||||
(24.214,40.431),(29.179,40.431),
|
||||
(29.179,42.511),(24.214,42.511),
|
||||
(21.787,42.511)])
|
||||
D_path_k_3=Polygon([
|
||||
(26.45,42.511),(26.45,52.84),
|
||||
(26.45,53.84),(29.179,53.84),
|
||||
(29.179,52.84),(29.179,42.511)])
|
||||
E_path_4_6=Polygon([
|
||||
(29.179,42.511),(54.351,42.511),
|
||||
(60.406,48.842),(60.406,51.22),
|
||||
(60.406,52.22),(63.49,52.22),
|
||||
(63.49,51.22),(63.49,47.866),
|
||||
(56.381,40.431),(29.179,40.431)])
|
||||
F_path_7_12=Polygon([
|
||||
(22.163, 0),(39.227, 5.516),
|
||||
(39.631, 4.267),(39.939,3.315),
|
||||
(45.099,4.983),(44.792,5.935),
|
||||
(43.169,10.954),(24.214,4.826),
|
||||
(22.163,4.826)])
|
||||
G_extended_queue=Polygon([
|
||||
(11.214,0),(12.924,0),
|
||||
(12.924,-4.569),(11.214,-4.569)])
|
||||
H_angled_path=Polygon([
|
||||
(21.787,13.192),(21.787,10.527),
|
||||
(17,4.826),(14.767,4.826)])
|
||||
enter_k_3=Polygon([
|
||||
(26.45,52.84),(29.179,52.84),
|
||||
(29.179,53.84),(26.45,53.84)])
|
||||
enter_4_6=Polygon([
|
||||
(60.406,51.22),(60.406,52.22),
|
||||
(63.49,52.22),(63.49,51.22)])
|
||||
enter_7_12=Polygon([
|
||||
(39.631, 4.267),(39.939,3.315),
|
||||
(45.099,4.983),(44.792,5.935)])
|
||||
exit_polygon=Polygon([
|
||||
(0,1.499),(0,3.327),
|
||||
(-1,3.327),(-1,1.499)])
|
||||
plot_polygon(
|
||||
A_crosswalk,color="black",add_points=False)
|
||||
plot_polygon(
|
||||
B_queue,color="black",add_points=False)
|
||||
plot_polygon(
|
||||
C_road_adj_path, color="blue",add_points=False)
|
||||
plot_polygon(
|
||||
D_path_k_3, color="blue",add_points=False)
|
||||
plot_polygon(
|
||||
E_path_4_6, color="blue",add_points=False)
|
||||
plot_polygon(
|
||||
F_path_7_12, color="blue",add_points=False)
|
||||
plot_polygon(
|
||||
G_extended_queue, color="black",add_points=False)
|
||||
plot_polygon(
|
||||
H_angled_path, color="black",add_points=False)
|
||||
plot_polygon(
|
||||
enter_k_3, color="darkgreen",add_points=False)
|
||||
plot_polygon(
|
||||
enter_4_6, color="darkgreen",add_points=False)
|
||||
plot_polygon(
|
||||
enter_7_12, color="darkgreen",add_points=False)
|
||||
plot_polygon(
|
||||
exit_polygon, color="orangered",add_points=False)
|
||||
geometry = (A_crosswalk.union(
|
||||
B_queue).union(
|
||||
C_road_adj_path).union(
|
||||
D_path_k_3).union(
|
||||
E_path_4_6).union(
|
||||
F_path_7_12).union(
|
||||
G_extended_queue).union(
|
||||
H_angled_path))
|
||||
trajectory_file = "SRS_evac.sqlite"
|
||||
simulation = jps.Simulation(
|
||||
model=jps.AnticipationVelocityModel(),
|
||||
geometry=geometry,
|
||||
trajectory_writer=jps.SqliteTrajectoryWriter(
|
||||
output_file=pathlib.Path(trajectory_file)))
|
||||
exit_id = simulation.add_exit_stage(exit_polygon)
|
||||
journey = jps.JourneyDescription([exit_id])
|
||||
journey_id = simulation.add_journey(journey)
|
||||
grade_pop = {}
|
||||
door = {}
|
||||
door_polygon = {
|
||||
"K-3":enter_k_3,
|
||||
"4-6":enter_4_6,
|
||||
"7-12":enter_7_12,
|
||||
}
|
||||
platoon_agents = {}
|
||||
for i, grade in enumerate(df["Grade Level"]):
|
||||
grade_sample=rng.normal(
|
||||
loc=df["Pop Mean"][i],
|
||||
scale=df["Pop Std Dev"][i],size=1)
|
||||
grade_pop[grade] = int(np.ceil(grade_sample[0]))
|
||||
x = grade_pop[grade]
|
||||
if i < 4:
|
||||
door[grade] = "K-3"
|
||||
elif i <7:
|
||||
door[grade] = "4-6"
|
||||
else:
|
||||
door[grade] = "7-12"
|
||||
platoon_a_size = int(x/2)
|
||||
platoon_b_size = x - platoon_a_size
|
||||
platoon_a_id = (2*(i+1))-1
|
||||
platoon_b_id = (2*(i+1))
|
||||
platoon_agents[platoon_a_id] ={
|
||||
"Grade Level": grade,
|
||||
"Platoon Size": platoon_a_size,
|
||||
"Entry Door":door_polygon[door[grade]]
|
||||
}
|
||||
platoon_agents[platoon_b_id] ={
|
||||
"Grade Level": grade,
|
||||
"Platoon Size": platoon_b_size,
|
||||
"Entry Door":door_polygon[door[grade]]
|
||||
}
|
||||
spawned_total=0
|
||||
#============================================================
|
||||
agent_set = []
|
||||
for platoon_id, platoon_data in platoon_agents.items():
|
||||
spawn_time=float(
|
||||
rng.uniform(5,15)+rng.uniform(0,120))
|
||||
spawn_time=min(spawn_time,120)
|
||||
remaining=int(platoon_data["Platoon Size"])
|
||||
attempts = 0
|
||||
max_attempts = 50
|
||||
time_delay = 1.0
|
||||
batch_size=max(1,min(10,remaining))
|
||||
while remaining>0 and attempts<max_attempts:
|
||||
n_try = min(batch_size,remaining)
|
||||
try:
|
||||
positions = jps.distribute_by_number(
|
||||
polygon=platoon_data["Entry Door"],
|
||||
number_of_agents=n_try,
|
||||
distance_to_agents=0.45,
|
||||
distance_to_polygon=0.3,
|
||||
max_iterations=1500)
|
||||
placed_count = len(positions)
|
||||
if placed_count ==0:
|
||||
attempts +=1
|
||||
spawn_time+=time_delay
|
||||
batch_size=max(1,batch_size//2)
|
||||
continue
|
||||
offset=0.1
|
||||
for k, pos in enumerate(positions):
|
||||
speed=float(rng.normal(
|
||||
loc=df["Speed Mean"][i],
|
||||
scale=df["Speed Std Dev"][i],
|
||||
size=1)[0])
|
||||
agent = {
|
||||
"Grade Level":
|
||||
platoon_data["Grade Level"],
|
||||
"Entry Point":
|
||||
(door[platoon_data["Grade Level"]]),
|
||||
"Platoon":platoon_id,
|
||||
"Position":(
|
||||
float(pos[0]),float(pos[1])),
|
||||
"Speed":speed,
|
||||
"Spawn Time":float(
|
||||
spawn_time+(k*offset))}
|
||||
agent_set.append(agent)
|
||||
remaining-=placed_count
|
||||
if remaining>0:
|
||||
attempts+=1
|
||||
spawn_time+=time_delay
|
||||
attempts=0
|
||||
batch_size=max(1,min(10,remaining))
|
||||
except Exception as e:
|
||||
print(
|
||||
f"Error placing platoon {platoon_id}: {e}")
|
||||
print("Reducing batch and retrying")
|
||||
attempts+=1
|
||||
batch_size=max(1,batch_size//2)
|
||||
spawn_time+=time_delay
|
||||
spawned_total+=placed_count
|
||||
#=========================================
|
||||
pending=sorted(agent_set,key=lambda a:a["Spawn Time"])
|
||||
pending=deque(pending)
|
||||
max_iterations=20000
|
||||
max_agents_per_step=50
|
||||
spawn_tolerance=1e-8
|
||||
while ((simulation.agent_count()>0 or len(pending)>0)
|
||||
and simulation.iteration_count()<max_iterations):
|
||||
current_time=simulation.elapsed_time()
|
||||
agents_this_step=0
|
||||
while (pending and (pending[0]["Spawn Time"]<=(
|
||||
current_time+spawn_tolerance))
|
||||
and agents_this_step<max_agents_per_step):
|
||||
a = pending.popleft()
|
||||
pos=tuple(a["Position"])
|
||||
v0 = float(a["Speed"])
|
||||
v0 = float(np.clip(v0,0.2,2.5))
|
||||
agent_params = (
|
||||
jps.AnticipationVelocityModelAgentParameters(
|
||||
journey_id=journey_id,
|
||||
stage_id=exit_id,
|
||||
position=pos,
|
||||
radius=0.25,
|
||||
desired_speed=v0,
|
||||
anticipation_time=0.5,
|
||||
reaction_time=0.3,
|
||||
wall_buffer_distance=0.08))
|
||||
retry=0
|
||||
max_retry=25
|
||||
while retry < max_retry:
|
||||
try:
|
||||
simulation.add_agent(agent_params)
|
||||
spawned_total +=1
|
||||
agents_this_step+=1
|
||||
break
|
||||
except Exception as e:
|
||||
print("Failed: add_agent")
|
||||
print(f"For: pos={pos}, speed={v0}")
|
||||
print(f"{e}: Rescheduling...")
|
||||
retry +=1
|
||||
if retry >= max_retry:
|
||||
print(f"\n\nMax Retries:{max_retry}")
|
||||
break
|
||||
adj_pos=(pos[0]+rng.uniform(-0.1,0.1),
|
||||
pos[1]+rng.uniform(-0.1,0.1))
|
||||
agent_params.position =adj_pos
|
||||
simulation.iterate()
|
||||
iter_count = simulation.iteration_count()
|
||||
print(f"\nTime Step: {iter_count}")
|
||||
print(f"Total Agents: {spawned_total}")
|
||||
print(f"Platoon: {platoon_agents.items()}")
|
||||
print("\nSimulation Completed!")
|
||||
print(f"Total Time Steps: {simulation.iteration_count()}")
|
||||
print(f"Elapsed Time: {simulation.elapsed_time()}")
|
||||
print(f"{trajectory_file = }")
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
349
archive/SRS_modeling_2025-11-10.py
Normal file
349
archive/SRS_modeling_2025-11-10.py
Normal file
@@ -0,0 +1,349 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Mon Nov 10 01:02:31 2025
|
||||
|
||||
@author: ethan
|
||||
"""
|
||||
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import pathlib
|
||||
import jupedsim as jps
|
||||
from shapely import Polygon
|
||||
from shapely.plotting import plot_polygon
|
||||
from collections import deque
|
||||
|
||||
def main():
|
||||
grades = {
|
||||
# mean and standard deviation for
|
||||
# average population size
|
||||
# and average speed by grade levels
|
||||
"Kindergarden":np.array([31.43,5.65,1.21,0.24]),
|
||||
"Grade 1":np.array([32.57,6.27,1.35,0.26]),
|
||||
"Grade 2":np.array([34.43,6.80,1.42,0.28]),
|
||||
"Grade 3":np.array([35.43,5.19,1.48,0.23]),
|
||||
"Grade 4":np.array([34.86,6.77,1.58,0.26]),
|
||||
"Grade 5":np.array([36.71,7.09,1.59,0.24]),
|
||||
"Grade 6":np.array([37.71,6.99,1.65,0.24]),
|
||||
"Grade 7":np.array([40.43,6.02,1.61,0.25]),
|
||||
"Grade 8":np.array([40.43,5.50,1.66,0.24]),
|
||||
"Grade 9":np.array([44.14,4.85,1.60,0.24]),
|
||||
"Grade 10":np.array([46.29,6.29,1.57,0.23]),
|
||||
"Grade 11":np.array([48.29,3.30,1.51,0.22]),
|
||||
"Grade 12":np.array([43.71,6.02,1.54,0.23])
|
||||
}
|
||||
df=pd.DataFrame({
|
||||
"Grade Level":(
|
||||
list(grades.keys())),
|
||||
"Pop Mean":[
|
||||
grades[j][0] for j in grades],
|
||||
"Pop Std Dev":[
|
||||
grades[j][1] for j in grades],
|
||||
"Speed Mean":[
|
||||
grades[j][2] for j in grades],
|
||||
"Speed Std Dev":[
|
||||
grades[j][3] for j in grades]})
|
||||
rng = np.random.default_rng(seed=42)
|
||||
A_crosswalk=Polygon([
|
||||
(-1,1.499),(-1,3.327),
|
||||
(0,3.327),(11.214, 3.327),
|
||||
(11.214,1.499),(0,1.499)])
|
||||
B_queue=Polygon([
|
||||
(11.214, 0),(22.163, 0),
|
||||
(22.163, 4.826),(11.214, 4.826)])
|
||||
C_road_adj_path=Polygon([
|
||||
(21.787,4.826),(24.214,4.826),
|
||||
(24.214,40.431),(29.179,40.431),
|
||||
(29.179,42.511),(24.214,42.511),
|
||||
(21.787,42.511)])
|
||||
D_path_k_3=Polygon([
|
||||
(26.45,42.511),(26.45,52.84),
|
||||
(26.45,53.84),(29.179,53.84),
|
||||
(29.179,52.84),(29.179,42.511)])
|
||||
E_path_4_6=Polygon([
|
||||
(29.179,42.511),(54.351,42.511),
|
||||
(60.406,48.842),(60.406,51.22),
|
||||
(60.406,52.22),(63.49,52.22),
|
||||
(63.49,51.22),(63.49,47.866),
|
||||
(56.381,40.431),(29.179,40.431)])
|
||||
F_path_7_12=Polygon([
|
||||
(22.163, 0),(39.227, 5.516),
|
||||
(39.631, 4.267),(39.939,3.315),
|
||||
(45.099,4.983),(44.792,5.935),
|
||||
(43.169,10.954),(24.214,4.826),
|
||||
(22.163,4.826)])
|
||||
G_extended_queue=Polygon([
|
||||
(11.214,0),(12.924,0),
|
||||
(12.924,-4.569),(11.214,-4.569)])
|
||||
H_angled_path=Polygon([
|
||||
(21.787,13.192),(21.787,10.527),
|
||||
(17,4.826),(14.767,4.826)])
|
||||
enter_k_3=Polygon([
|
||||
(26.45,52.84),(29.179,52.84),
|
||||
(29.179,53.84),(26.45,53.84)])
|
||||
enter_4_6=Polygon([
|
||||
(60.406,51.22),(60.406,52.22),
|
||||
(63.49,52.22),(63.49,51.22)])
|
||||
enter_7_12=Polygon([
|
||||
(39.631, 4.267),(39.939,3.315),
|
||||
(45.099,4.983),(44.792,5.935)])
|
||||
exit_polygon=Polygon([
|
||||
(0,1.499),(0,3.327),
|
||||
(-1,3.327),(-1,1.499)])
|
||||
plot_polygon(
|
||||
A_crosswalk,color="black",add_points=False)
|
||||
plot_polygon(
|
||||
B_queue,color="black",add_points=False)
|
||||
plot_polygon(
|
||||
C_road_adj_path, color="blue",add_points=False)
|
||||
plot_polygon(
|
||||
D_path_k_3, color="blue",add_points=False)
|
||||
plot_polygon(
|
||||
E_path_4_6, color="blue",add_points=False)
|
||||
plot_polygon(
|
||||
F_path_7_12, color="blue",add_points=False)
|
||||
plot_polygon(
|
||||
G_extended_queue, color="black",add_points=False)
|
||||
plot_polygon(
|
||||
H_angled_path, color="black",add_points=False)
|
||||
plot_polygon(
|
||||
enter_k_3, color="darkgreen",add_points=False)
|
||||
plot_polygon(
|
||||
enter_4_6, color="darkgreen",add_points=False)
|
||||
plot_polygon(
|
||||
enter_7_12, color="darkgreen",add_points=False)
|
||||
plot_polygon(
|
||||
exit_polygon, color="orangered",add_points=False)
|
||||
geometry = (A_crosswalk.union(
|
||||
B_queue).union(
|
||||
C_road_adj_path).union(
|
||||
D_path_k_3).union(
|
||||
E_path_4_6).union(
|
||||
F_path_7_12).union(
|
||||
G_extended_queue).union(
|
||||
H_angled_path))
|
||||
trajectory_file = "SRS_evac.sqlite"
|
||||
simulation = jps.Simulation(
|
||||
model=jps.AnticipationVelocityModel(),
|
||||
geometry=geometry,
|
||||
trajectory_writer=jps.SqliteTrajectoryWriter(
|
||||
output_file=pathlib.Path(trajectory_file)))
|
||||
exit_id = simulation.add_exit_stage(exit_polygon)
|
||||
journey = jps.JourneyDescription([exit_id])
|
||||
journey_id = simulation.add_journey(journey)
|
||||
grade_pop = {}
|
||||
door = {}
|
||||
door_polygon = {
|
||||
"K-3":enter_k_3,
|
||||
"4-6":enter_4_6,
|
||||
"7-12":enter_7_12,
|
||||
}
|
||||
platoon_agents = {}
|
||||
for i, grade in enumerate(df["Grade Level"]):
|
||||
grade_sample=rng.normal(
|
||||
loc=df["Pop Mean"][i],
|
||||
scale=df["Pop Std Dev"][i],size=1)
|
||||
grade_pop[grade] = int(np.ceil(grade_sample[0]))
|
||||
x = grade_pop[grade]
|
||||
if i < 4:
|
||||
door[grade] = "K-3"
|
||||
elif i <7:
|
||||
door[grade] = "4-6"
|
||||
else:
|
||||
door[grade] = "7-12"
|
||||
platoon_a_size = int(x/2)
|
||||
platoon_b_size = x - platoon_a_size
|
||||
platoon_a_id = (2*(i+1))-1
|
||||
platoon_b_id = (2*(i+1))
|
||||
platoon_agents[platoon_a_id] ={
|
||||
"Grade Level": grade,
|
||||
"Platoon Size": platoon_a_size,
|
||||
"Entry Door":door_polygon[door[grade]]
|
||||
}
|
||||
platoon_agents[platoon_b_id] ={
|
||||
"Grade Level": grade,
|
||||
"Platoon Size": platoon_b_size,
|
||||
"Entry Door":door_polygon[door[grade]]
|
||||
}
|
||||
#================================================
|
||||
#================================================
|
||||
#================================================
|
||||
#================================================
|
||||
agent_set = []
|
||||
for platoon_id, platoon_data in platoon_agents.items():
|
||||
spawn_time=float(
|
||||
rng.uniform(5,15)+rng.uniform(0,120))
|
||||
spawn_time=min(spawn_time,120)
|
||||
remaining=int(platoon_data["Platoon Size"])
|
||||
attempts = 0
|
||||
max_attempts = 10
|
||||
time_delay = 1.0
|
||||
batch_size=max(1,min(10,remaining))
|
||||
while remaining>0 and attempts<max_attempts:
|
||||
n_try = min(batch_size,remaining)
|
||||
try:
|
||||
positions = jps.distribute_by_number(
|
||||
polygon=platoon_data["Entry Door"],
|
||||
number_of_agents=n_try,
|
||||
distance_to_agents=0.45,
|
||||
distance_to_polygon=0.3,
|
||||
max_iterations=1500)
|
||||
placed_count = len(positions)
|
||||
if placed_count ==0:
|
||||
attempts +=1
|
||||
spawn_time+=time_delay
|
||||
batch_size=max(1,batch_size//2)
|
||||
continue
|
||||
offset=0.1
|
||||
for k, pos in enumerate(positions):
|
||||
speed=float(rng.normal(
|
||||
loc=df["Speed Mean"][i],
|
||||
scale=df["Speed Std Dev"][i],
|
||||
size=1)[0])
|
||||
agent = {
|
||||
"Grade Level":
|
||||
platoon_data["Grade Level"],
|
||||
"Entry Point":
|
||||
(door[platoon_data["Grade Level"]]),
|
||||
"Platoon":platoon_id,
|
||||
"Position":(
|
||||
float(pos[0]),float(pos[1])),
|
||||
"Speed":speed,
|
||||
"Spawn Time":float(
|
||||
spawn_time+(k*offset))}
|
||||
agent_set.append(agent)
|
||||
|
||||
remaining-=placed_count
|
||||
if remaining>0:
|
||||
attempts+=1
|
||||
spawn_time+=time_delay
|
||||
attempts=0
|
||||
batch_size=max(1,min(10,remaining))
|
||||
except Exception as e:
|
||||
print(
|
||||
f"Error placing platoon {platoon_id}: {e}")
|
||||
print("Reducing batch and retrying")
|
||||
attempts+=1
|
||||
batch_size=max(1,batch_size//2)
|
||||
spawn_time+=time_delay
|
||||
|
||||
#================================================
|
||||
#================================================
|
||||
#================================================
|
||||
#================================================
|
||||
# Group platoons by entry door first
|
||||
door_platoons = {}
|
||||
for platoon_id, platoon_data in platoon_agents.items():
|
||||
door = platoon_data["Entry Door"]
|
||||
if door not in door_platoons:
|
||||
door_platoons[door] = []
|
||||
door_platoons[door].append((platoon_id, platoon_data))
|
||||
|
||||
# Process each door sequentially
|
||||
agent_set = []
|
||||
for door_poly, platoon_list in door_platoons.items():
|
||||
# Calculate total agents for this door
|
||||
total_agents = sum(data["Platoon Size"] for _, data in platoon_list)
|
||||
|
||||
# Generate all positions for this door at once
|
||||
try:
|
||||
all_positions = jps.distribute_by_number(
|
||||
polygon=door_poly,
|
||||
number_of_agents=total_agents,
|
||||
distance_to_agents=0.6, # Increased for safety
|
||||
distance_to_polygon=0.3,
|
||||
max_iterations=1500
|
||||
)
|
||||
|
||||
# Distribute positions to platoons
|
||||
position_index = 0
|
||||
for platoon_id, platoon_data in platoon_list:
|
||||
platoon_size = platoon_data["Platoon Size"]
|
||||
platoon_positions = all_positions[position_index:position_index + platoon_size]
|
||||
position_index += platoon_size
|
||||
|
||||
# Create agents for this platoon
|
||||
spawn_time = float(rng.uniform(5,15) + rng.uniform(0,120))
|
||||
spawn_time = min(spawn_time, 120)
|
||||
offset = 0.1
|
||||
|
||||
for k, pos in enumerate(platoon_positions):
|
||||
speed = float(rng.normal(
|
||||
loc=df["Speed Mean"][platoon_data["Grade Index"]], # You'll need to store grade index
|
||||
scale=df["Speed Std Dev"][platoon_data["Grade Index"]],
|
||||
size=1
|
||||
)[0])
|
||||
|
||||
agent = {
|
||||
"Grade Level": platoon_data["Grade Level"],
|
||||
"Entry Point": door_poly, # Or door name if you prefer
|
||||
"Platoon": platoon_id,
|
||||
"Position": (float(pos[0]), float(pos[1])),
|
||||
"Speed": speed,
|
||||
"Spawn Time": float(spawn_time + (k * offset))
|
||||
}
|
||||
agent_set.append(agent)
|
||||
except Exception as e:
|
||||
print(f"Error generating positions for door: {e}")
|
||||
# Fallback: use your original per-platoon approach for this door
|
||||
#================================================
|
||||
#================================================
|
||||
#================================================
|
||||
#================================================
|
||||
pending=sorted(agent_set,key=lambda a:a["Spawn Time"])
|
||||
pending=deque(pending)
|
||||
max_iterations=1500
|
||||
spawned_total=0
|
||||
max_agents_per_step=25
|
||||
spawn_tolerance=1e-8
|
||||
while ((simulation.agent_count()>0 or len(pending)>0)
|
||||
and simulation.iteration_count()<max_iterations):
|
||||
current_time=simulation.elapsed_time()
|
||||
agents_this_step=0
|
||||
while (pending and (pending[0]["Spawn Time"]<=(
|
||||
current_time+spawn_tolerance))
|
||||
and agents_this_step<max_agents_per_step):
|
||||
a = pending.popleft()
|
||||
pos=tuple(a["Position"])
|
||||
v0 = float(a["Speed"])
|
||||
v0 = float(np.clip(v0,0.2,2.5))
|
||||
agent_params = (
|
||||
jps.AnticipationVelocityModelAgentParameters(
|
||||
journey_id=journey_id,
|
||||
stage_id=exit_id,
|
||||
position=pos,
|
||||
radius=0.25,
|
||||
desired_speed=v0,
|
||||
anticipation_time=0.5,
|
||||
reaction_time=0.3,
|
||||
wall_buffer_distance=0.08))
|
||||
retry=0
|
||||
max_retry=10
|
||||
while retry < max_retry:
|
||||
try:
|
||||
simulation.add_agent(agent_params)
|
||||
spawned_total +=1
|
||||
agents_this_step+=1
|
||||
break
|
||||
except Exception as e:
|
||||
print("Failed: add_agent")
|
||||
print(f"For: pos={pos}, speed={v0}")
|
||||
print(f"{e}: Rescheduling...")
|
||||
retry +=1
|
||||
if retry >= max_retry:
|
||||
print(f"\n\nMax Retries:{max_retry}")
|
||||
break
|
||||
adj_pos=(pos[0]+rng.uniform(-0.1,0.1),
|
||||
pos[1]+rng.uniform(-0.1,0.1))
|
||||
agent_params.position =adj_pos
|
||||
simulation.iterate()
|
||||
iter_count = simulation.iteration_count()
|
||||
print(f"Iteration Complete: {iter_count}")
|
||||
print("Simulation Completed!")
|
||||
print(f"Iterations: {simulation.iteration_count()}")
|
||||
print(f"Elapsed Time: {simulation.elapsed_time()}")
|
||||
print(f"{trajectory_file = }")
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
314
archive/SRS_modeling_2025-11-22.py
Normal file
314
archive/SRS_modeling_2025-11-22.py
Normal file
@@ -0,0 +1,314 @@
|
||||
"""
|
||||
Created on Sat Nov 22 14:42:45 2025
|
||||
|
||||
@author: ethan
|
||||
"""
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import pathlib
|
||||
import jupedsim as jps
|
||||
from shapely import Polygon
|
||||
from shapely.plotting import plot_polygon
|
||||
from collections import deque
|
||||
from datetime import datetime
|
||||
|
||||
def main():
|
||||
grades = {
|
||||
"Kindergarden":np.array([31.43,5.65,1.21,0.24]),
|
||||
"Grade 1":np.array([32.57,6.27,1.35,0.26]),
|
||||
"Grade 2":np.array([34.43,6.80,1.42,0.28]),
|
||||
"Grade 3":np.array([35.43,5.19,1.48,0.23]),
|
||||
"Grade 4":np.array([34.86,6.77,1.58,0.26]),
|
||||
"Grade 5":np.array([36.71,7.09,1.59,0.24]),
|
||||
"Grade 6":np.array([37.71,6.99,1.65,0.24]),
|
||||
"Grade 7":np.array([40.43,6.02,1.61,0.25]),
|
||||
"Grade 8":np.array([40.43,5.50,1.66,0.24]),
|
||||
"Grade 9":np.array([44.14,4.85,1.60,0.24]),
|
||||
"Grade 10":np.array([46.29,6.29,1.57,0.23]),
|
||||
"Grade 11":np.array([48.29,3.30,1.51,0.22]),
|
||||
"Grade 12":np.array([43.71,6.02,1.54,0.23])
|
||||
}
|
||||
df=pd.DataFrame({
|
||||
"Grade Level":(
|
||||
list(grades.keys())),
|
||||
"Pop Mean":[
|
||||
grades[j][0] for j in grades],
|
||||
"Pop Std Dev":[
|
||||
grades[j][1] for j in grades],
|
||||
"Speed Mean":[
|
||||
grades[j][2] for j in grades],
|
||||
"Speed Std Dev":[
|
||||
grades[j][3] for j in grades]})
|
||||
rng = np.random.default_rng(seed=42)
|
||||
A_crosswalk=Polygon([
|
||||
(-1,1.499),(-1,3.327),
|
||||
(0,3.327),(11.214, 3.327),
|
||||
(11.214,1.499),(0,1.499)])
|
||||
B_queue=Polygon([
|
||||
(11.214, 0),(22.163, 0),
|
||||
(22.163, 4.826),(11.214, 4.826)])
|
||||
C_road_adj_path=Polygon([
|
||||
(21.787,4.826),(24.214,4.826),
|
||||
(24.214,40.431),(29.179,40.431),
|
||||
(29.179,42.511),(24.214,42.511),
|
||||
(21.787,42.511)])
|
||||
D_path_k_3=Polygon([
|
||||
(26.45,42.511),(26.45,52.84),
|
||||
(26.45,53.84),(29.179,53.84),
|
||||
(29.179,52.84),(29.179,42.511)])
|
||||
E_path_4_6=Polygon([
|
||||
(29.179,42.511),(54.351,42.511),
|
||||
(60.406,48.842),(60.406,51.22),
|
||||
(60.406,52.22),(63.49,52.22),
|
||||
(63.49,51.22),(63.49,47.866),
|
||||
(56.381,40.431),(29.179,40.431)])
|
||||
F_path_7_12=Polygon([
|
||||
(22.163, 0),(39.227, 5.516),
|
||||
(39.631, 4.267),(39.939,3.315),
|
||||
(45.099,4.983),(44.792,5.935),
|
||||
(43.169,10.954),(24.214,4.826),
|
||||
(22.163,4.826)])
|
||||
G_extended_queue=Polygon([
|
||||
(11.214,0),(12.924,0),
|
||||
(12.924,-4.569),(11.214,-4.569)])
|
||||
H_angled_path=Polygon([
|
||||
(21.787,13.192),(21.787,10.527),
|
||||
(17,4.826),(14.767,4.826)])
|
||||
enter_k_3=Polygon([
|
||||
(26.45,52.84),(29.179,52.84),
|
||||
(29.179,53.84),(26.45,53.84)])
|
||||
enter_4_6=Polygon([
|
||||
(60.406,51.22),(60.406,52.22),
|
||||
(63.49,52.22),(63.49,51.22)])
|
||||
enter_7_12=Polygon([
|
||||
(39.631, 4.267),(39.939,3.315),
|
||||
(45.099,4.983),(44.792,5.935)])
|
||||
exit_polygon=Polygon([
|
||||
(0,1.499),(0,3.327),
|
||||
(-1,3.327),(-1,1.499)])
|
||||
plot_polygon(
|
||||
A_crosswalk,color="black",add_points=False)
|
||||
plot_polygon(
|
||||
B_queue,color="black",add_points=False)
|
||||
plot_polygon(
|
||||
C_road_adj_path, color="blue",add_points=False)
|
||||
plot_polygon(
|
||||
D_path_k_3, color="blue",add_points=False)
|
||||
plot_polygon(
|
||||
E_path_4_6, color="blue",add_points=False)
|
||||
plot_polygon(
|
||||
F_path_7_12, color="blue",add_points=False)
|
||||
plot_polygon(
|
||||
G_extended_queue, color="black",add_points=False)
|
||||
plot_polygon(
|
||||
H_angled_path, color="black",add_points=False)
|
||||
plot_polygon(
|
||||
enter_k_3, color="darkgreen",add_points=False)
|
||||
plot_polygon(
|
||||
enter_4_6, color="darkgreen",add_points=False)
|
||||
plot_polygon(
|
||||
enter_7_12, color="darkgreen",add_points=False)
|
||||
plot_polygon(
|
||||
exit_polygon, color="orangered",add_points=False)
|
||||
geometry = (A_crosswalk.union(
|
||||
B_queue).union(
|
||||
C_road_adj_path).union(
|
||||
D_path_k_3).union(
|
||||
E_path_4_6).union(
|
||||
F_path_7_12).union(
|
||||
G_extended_queue).union(
|
||||
H_angled_path))
|
||||
current_time = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
|
||||
trajectory_file = f"SRS_evac_{current_time}.sqlite"
|
||||
simulation = jps.Simulation(
|
||||
model=jps.AnticipationVelocityModel(),
|
||||
geometry=geometry,
|
||||
trajectory_writer=jps.SqliteTrajectoryWriter(
|
||||
output_file=pathlib.Path(trajectory_file)))
|
||||
exit_id = simulation.add_exit_stage(exit_polygon)
|
||||
journey = jps.JourneyDescription([exit_id])
|
||||
journey_id = simulation.add_journey(journey)
|
||||
grade_pop = {}
|
||||
door = {}
|
||||
door_polygon = {
|
||||
"K-3":enter_k_3,
|
||||
"4-6":enter_4_6,
|
||||
"7-12":enter_7_12,
|
||||
}
|
||||
platoon_agents = {}
|
||||
for i, grade in enumerate(df["Grade Level"]):
|
||||
grade_sample=rng.normal(
|
||||
loc=df["Pop Mean"][i],
|
||||
scale=df["Pop Std Dev"][i],size=1)
|
||||
grade_pop[grade] = int(np.ceil(grade_sample[0]))
|
||||
x = grade_pop[grade]
|
||||
if i < 4:
|
||||
door[grade] = "K-3"
|
||||
elif i <7:
|
||||
door[grade] = "4-6"
|
||||
else:
|
||||
door[grade] = "7-12"
|
||||
platoon_a_size = int(x/2)
|
||||
platoon_b_size = x - platoon_a_size
|
||||
platoon_a_id = (2*(i+1))-1
|
||||
platoon_b_id = (2*(i+1))
|
||||
platoon_agents[platoon_a_id] ={
|
||||
"Grade Level": grade,
|
||||
"Platoon Size": platoon_a_size,
|
||||
"Entry Door":door_polygon[door[grade]]
|
||||
}
|
||||
platoon_agents[platoon_b_id] ={
|
||||
"Grade Level": grade,
|
||||
"Platoon Size": platoon_b_size,
|
||||
"Entry Door":door_polygon[door[grade]]
|
||||
}
|
||||
|
||||
#================================================
|
||||
interval = 50
|
||||
try:
|
||||
max_iterations = int(input("Number of steps?"))
|
||||
if max_iterations<=0:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
print("Please enter a positive integer")
|
||||
return
|
||||
agent_set = []
|
||||
next_planned_id = 0
|
||||
for platoon_id, platoon_data in platoon_agents.items():
|
||||
spawn_time=float(
|
||||
rng.uniform(5,15)+rng.uniform(0,120))
|
||||
spawn_time=min(spawn_time,120)
|
||||
remaining=int(platoon_data["Platoon Size"])
|
||||
attempts = 0
|
||||
max_attempts = 10
|
||||
time_delay = 1.0
|
||||
batch_size=max(1,min(10,remaining))
|
||||
while remaining>0 and attempts<max_attempts:
|
||||
n_try = min(batch_size,remaining)
|
||||
try:
|
||||
positions = jps.distribute_by_number(
|
||||
polygon=platoon_data["Entry Door"],
|
||||
number_of_agents=n_try,
|
||||
distance_to_agents=0.45,
|
||||
distance_to_polygon=0.3,
|
||||
max_iterations=1500)
|
||||
placed_count = len(positions)
|
||||
if placed_count ==0:
|
||||
attempts +=1
|
||||
spawn_time+=time_delay
|
||||
batch_size=max(1,batch_size//2)
|
||||
continue
|
||||
offset=0.1
|
||||
for k, pos in enumerate(positions):
|
||||
speed=float(rng.normal(
|
||||
loc=df["Speed Mean"][i],
|
||||
scale=df["Speed Std Dev"][i],
|
||||
size=1)[0])
|
||||
agent = {
|
||||
"Grade Level":
|
||||
platoon_data["Grade Level"],
|
||||
"Entry Point":
|
||||
(door[platoon_data["Grade Level"]]),
|
||||
"Platoon":platoon_id,
|
||||
"Position":(
|
||||
float(pos[0]),float(pos[1])),
|
||||
"Speed":speed,
|
||||
"Spawn Time":float(
|
||||
spawn_time+(k*offset))}
|
||||
next_planned_id +=1
|
||||
agent['PlannedID'] = next_planned_id
|
||||
agent_set.append(agent)
|
||||
|
||||
remaining-=placed_count
|
||||
if remaining>0:
|
||||
attempts+=1
|
||||
spawn_time+=time_delay
|
||||
attempts=0
|
||||
batch_size=max(1,min(10,remaining))
|
||||
except Exception as e:
|
||||
print(
|
||||
f"Error placing platoon {platoon_id}: {e}")
|
||||
print("Reducing batch and retrying")
|
||||
attempts+=1
|
||||
batch_size=max(1,batch_size//2)
|
||||
spawn_time+=time_delay
|
||||
total_agents = next_planned_id
|
||||
|
||||
#================================================
|
||||
pending=sorted(agent_set,key=lambda a:a["Spawn Time"])
|
||||
pending=deque(pending)
|
||||
sim_to_planned = {}
|
||||
max_agents_per_step=25
|
||||
spawned_total = 0
|
||||
spawn_tolerance=1e-8
|
||||
while ((simulation.agent_count()>0 or len(pending)>0)
|
||||
and simulation.iteration_count()<max_iterations):
|
||||
current_time=simulation.elapsed_time()
|
||||
agents_this_step=0
|
||||
while (pending and (pending[0]["Spawn Time"]<=(
|
||||
current_time+spawn_tolerance))
|
||||
and agents_this_step<max_agents_per_step):
|
||||
a = pending.popleft()
|
||||
pos=tuple(a["Position"])
|
||||
v0 = float(a["Speed"])
|
||||
v0 = float(np.clip(v0,0.2,2.5))
|
||||
agent_params = (
|
||||
jps.AnticipationVelocityModelAgentParameters(
|
||||
journey_id=journey_id,
|
||||
stage_id=exit_id,
|
||||
position=pos,
|
||||
radius=0.25,
|
||||
desired_speed=v0,
|
||||
anticipation_time=0.5,
|
||||
reaction_time=0.3,
|
||||
wall_buffer_distance=0.08))
|
||||
try:
|
||||
add_result = simulation.add_agent(agent_params)
|
||||
internal_id = None
|
||||
if add_result is not None:
|
||||
try:
|
||||
internal_id = int(add_result)
|
||||
except Exception:
|
||||
internal_id = None
|
||||
if internal_id is not None:
|
||||
sim_to_planned[internal_id] = a
|
||||
print(f"Added planned={a['PlannedID']}")
|
||||
print(f"internal={internal_id}")
|
||||
print(f"time={current_time:.2f}")
|
||||
spawned_total +=1
|
||||
else:
|
||||
print(f"Added planned={a['PlannedID']}")
|
||||
print("(no internal_id returned)")
|
||||
print(f"time={current_time:.2f}")
|
||||
agents_this_step+=1
|
||||
break
|
||||
except Exception as e:
|
||||
pending_for_door = sum(
|
||||
1 for x in pending if (
|
||||
x['Entry Point']==a["Entry Point"]))
|
||||
print("\nadd_agent FAILED")
|
||||
print(f"planned={a['PlannedID']}")
|
||||
print(f"pos={pos}")
|
||||
print(f"speed={v0:.2f}")
|
||||
print(f"time={current_time:.2f}")
|
||||
print(f"pending_for_door={pending_for_door}")
|
||||
print(f"\n\nerror={e}")
|
||||
retry_delay = 0.1
|
||||
a["Spawn Time"] = current_time+retry_delay
|
||||
pending.appendleft(a)
|
||||
break
|
||||
simulation.iterate()
|
||||
iter_count = simulation.iteration_count()
|
||||
if iter_count % interval ==0:
|
||||
print(f"\nIteration: {iter_count}")
|
||||
print(f"time={simulation.elapsed_time():.2f}")
|
||||
print(f"active={simulation.agent_count()}")
|
||||
print(f"pending={len(pending)}")
|
||||
print(f"spawned={spawned_total}/{total_agents}")
|
||||
print("Simulation Completed!")
|
||||
print(f"Iterations: {simulation.iteration_count()}")
|
||||
print(f"Elapsed Time: {simulation.elapsed_time()}")
|
||||
print(f"Total Agents: {total_agents}")
|
||||
print(f"{trajectory_file = }")
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
323
archive/SRS_modeling_2025-11-30.py
Normal file
323
archive/SRS_modeling_2025-11-30.py
Normal file
@@ -0,0 +1,323 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Sun Nov 30 18:48:13 2025
|
||||
|
||||
@author: ethan
|
||||
"""
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import pathlib
|
||||
import jupedsim as jps
|
||||
from shapely import Polygon
|
||||
from shapely.plotting import plot_polygon
|
||||
from collections import deque
|
||||
from datetime import datetime
|
||||
from jupedsim.internal.notebook_utils import animate, read_sqlite_file
|
||||
import pedpy
|
||||
|
||||
def main():
|
||||
grades = {
|
||||
"Kindergarden":np.array([31.43,5.65,1.21,0.24]),
|
||||
"Grade 1":np.array([32.57,6.27,1.35,0.26]),
|
||||
"Grade 2":np.array([34.43,6.80,1.42,0.28]),
|
||||
"Grade 3":np.array([35.43,5.19,1.48,0.23]),
|
||||
"Grade 4":np.array([34.86,6.77,1.58,0.26]),
|
||||
"Grade 5":np.array([36.71,7.09,1.59,0.24]),
|
||||
"Grade 6":np.array([37.71,6.99,1.65,0.24]),
|
||||
"Grade 7":np.array([40.43,6.02,1.61,0.25]),
|
||||
"Grade 8":np.array([40.43,5.50,1.66,0.24]),
|
||||
"Grade 9":np.array([44.14,4.85,1.60,0.24]),
|
||||
"Grade 10":np.array([46.29,6.29,1.57,0.23]),
|
||||
"Grade 11":np.array([48.29,3.30,1.51,0.22]),
|
||||
"Grade 12":np.array([43.71,6.02,1.54,0.23])
|
||||
}
|
||||
df=pd.DataFrame({
|
||||
"Grade Level":(
|
||||
list(grades.keys())),
|
||||
"Pop Mean":[
|
||||
grades[j][0] for j in grades],
|
||||
"Pop Std Dev":[
|
||||
grades[j][1] for j in grades],
|
||||
"Speed Mean":[
|
||||
grades[j][2] for j in grades],
|
||||
"Speed Std Dev":[
|
||||
grades[j][3] for j in grades]})
|
||||
rng = np.random.default_rng(seed=42)
|
||||
A_crosswalk=Polygon([
|
||||
(-1,1.499),(-1,3.327),
|
||||
(0,3.327),(11.214, 3.327),
|
||||
(11.214,1.499),(0,1.499)])
|
||||
B_queue=Polygon([
|
||||
(11.214, 0),(22.163, 0),
|
||||
(22.163, 4.826),(11.214, 4.826)])
|
||||
C_road_adj_path=Polygon([
|
||||
(21.787,4.826),(24.214,4.826),
|
||||
(24.214,40.431),(29.179,40.431),
|
||||
(29.179,42.511),(24.214,42.511),
|
||||
(21.787,42.511)])
|
||||
D_path_k_3=Polygon([
|
||||
(26.45,42.511),(26.45,52.84),
|
||||
(26.45,53.84),(29.179,53.84),
|
||||
(29.179,52.84),(29.179,42.511)])
|
||||
E_path_4_6=Polygon([
|
||||
(29.179,42.511),(54.351,42.511),
|
||||
(60.406,48.842),(60.406,51.22),
|
||||
(60.406,52.22),(63.49,52.22),
|
||||
(63.49,51.22),(63.49,47.866),
|
||||
(56.381,40.431),(29.179,40.431)])
|
||||
F_path_7_12=Polygon([
|
||||
(22.163, 0),(39.227, 5.516),
|
||||
(39.631, 4.267),(39.939,3.315),
|
||||
(45.099,4.983),(44.792,5.935),
|
||||
(43.169,10.954),(24.214,4.826),
|
||||
(22.163,4.826)])
|
||||
G_extended_queue=Polygon([
|
||||
(11.214,0),(12.924,0),
|
||||
(12.924,-4.569),(11.214,-4.569)])
|
||||
H_angled_path=Polygon([
|
||||
(21.787,13.192),(21.787,10.527),
|
||||
(17,4.826),(14.767,4.826)])
|
||||
enter_k_3=Polygon([
|
||||
(26.45,52.84),(29.179,52.84),
|
||||
(29.179,53.84),(26.45,53.84)])
|
||||
enter_4_6=Polygon([
|
||||
(60.406,51.22),(60.406,52.22),
|
||||
(63.49,52.22),(63.49,51.22)])
|
||||
enter_7_12=Polygon([
|
||||
(39.631, 4.267),(39.939,3.315),
|
||||
(45.099,4.983),(44.792,5.935)])
|
||||
exit_polygon=Polygon([
|
||||
(0,1.499),(0,3.327),
|
||||
(-1,3.327),(-1,1.499)])
|
||||
plot_polygon(
|
||||
A_crosswalk,color="black",add_points=False)
|
||||
plot_polygon(
|
||||
B_queue,color="black",add_points=False)
|
||||
plot_polygon(
|
||||
C_road_adj_path, color="blue",add_points=False)
|
||||
plot_polygon(
|
||||
D_path_k_3, color="blue",add_points=False)
|
||||
plot_polygon(
|
||||
E_path_4_6, color="blue",add_points=False)
|
||||
plot_polygon(
|
||||
F_path_7_12, color="blue",add_points=False)
|
||||
plot_polygon(
|
||||
G_extended_queue, color="black",add_points=False)
|
||||
plot_polygon(
|
||||
H_angled_path, color="black",add_points=False)
|
||||
plot_polygon(
|
||||
enter_k_3, color="darkgreen",add_points=False)
|
||||
plot_polygon(
|
||||
enter_4_6, color="darkgreen",add_points=False)
|
||||
plot_polygon(
|
||||
enter_7_12, color="darkgreen",add_points=False)
|
||||
plot_polygon(
|
||||
exit_polygon, color="orangered",add_points=False)
|
||||
geometry = (A_crosswalk.union(
|
||||
B_queue).union(
|
||||
C_road_adj_path).union(
|
||||
D_path_k_3).union(
|
||||
E_path_4_6).union(
|
||||
F_path_7_12).union(
|
||||
G_extended_queue).union(
|
||||
H_angled_path))
|
||||
current_time = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
|
||||
trajectory_file = f"SRS_evac_{current_time}.sqlite"
|
||||
simulation = jps.Simulation(
|
||||
model=jps.AnticipationVelocityModel(),
|
||||
geometry=geometry,
|
||||
trajectory_writer=jps.SqliteTrajectoryWriter(
|
||||
output_file=pathlib.Path(trajectory_file)))
|
||||
exit_id = simulation.add_exit_stage(exit_polygon)
|
||||
journey = jps.JourneyDescription([exit_id])
|
||||
journey_id = simulation.add_journey(journey)
|
||||
grade_pop = {}
|
||||
door = {}
|
||||
door_polygon = {
|
||||
"K-3":enter_k_3,
|
||||
"4-6":enter_4_6,
|
||||
"7-12":enter_7_12,
|
||||
}
|
||||
platoon_agents = {}
|
||||
for i, grade in enumerate(df["Grade Level"]):
|
||||
grade_sample=rng.normal(
|
||||
loc=df["Pop Mean"][i],
|
||||
scale=df["Pop Std Dev"][i],size=1)
|
||||
grade_pop[grade] = int(np.ceil(grade_sample[0]))
|
||||
x = grade_pop[grade]
|
||||
if i < 4:
|
||||
door[grade] = "K-3"
|
||||
elif i <7:
|
||||
door[grade] = "4-6"
|
||||
else:
|
||||
door[grade] = "7-12"
|
||||
platoon_a_size = int(x/2)
|
||||
platoon_b_size = x - platoon_a_size
|
||||
platoon_a_id = (2*(i+1))-1
|
||||
platoon_b_id = (2*(i+1))
|
||||
platoon_agents[platoon_a_id] ={
|
||||
"Grade Level": grade,
|
||||
"Platoon Size": platoon_a_size,
|
||||
"Entry Door":door_polygon[door[grade]]
|
||||
}
|
||||
platoon_agents[platoon_b_id] ={
|
||||
"Grade Level": grade,
|
||||
"Platoon Size": platoon_b_size,
|
||||
"Entry Door":door_polygon[door[grade]]
|
||||
}
|
||||
|
||||
#================================================
|
||||
interval = 50
|
||||
try:
|
||||
max_iterations = int(input("Number of steps?"))
|
||||
if max_iterations<=0:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
print("Please enter a positive integer")
|
||||
return
|
||||
agent_set = []
|
||||
next_planned_id = 0
|
||||
for platoon_id, platoon_data in platoon_agents.items():
|
||||
spawn_time=float(
|
||||
rng.uniform(5,15)+rng.uniform(0,120))
|
||||
spawn_time=min(spawn_time,120)
|
||||
remaining=int(platoon_data["Platoon Size"])
|
||||
attempts = 0
|
||||
max_attempts = 10
|
||||
time_delay = 1.0
|
||||
batch_size=max(1,min(10,remaining))
|
||||
while remaining>0 and attempts<max_attempts:
|
||||
n_try = min(batch_size,remaining)
|
||||
try:
|
||||
positions = jps.distribute_by_number(
|
||||
polygon=platoon_data["Entry Door"],
|
||||
number_of_agents=n_try,
|
||||
distance_to_agents=0.45,
|
||||
distance_to_polygon=0.3,
|
||||
max_iterations=1500)
|
||||
placed_count = len(positions)
|
||||
if placed_count ==0:
|
||||
attempts +=1
|
||||
spawn_time+=time_delay
|
||||
batch_size=max(1,batch_size//2)
|
||||
continue
|
||||
offset=0.1
|
||||
for k, pos in enumerate(positions):
|
||||
speed=float(rng.normal(
|
||||
loc=df["Speed Mean"][i],
|
||||
scale=df["Speed Std Dev"][i],
|
||||
size=1)[0])
|
||||
agent = {
|
||||
"Grade Level":
|
||||
platoon_data["Grade Level"],
|
||||
"Entry Point":
|
||||
(door[platoon_data["Grade Level"]]),
|
||||
"Platoon":platoon_id,
|
||||
"Position":(
|
||||
float(pos[0]),float(pos[1])),
|
||||
"Speed":speed,
|
||||
"Spawn Time":float(
|
||||
spawn_time+(k*offset))}
|
||||
next_planned_id +=1
|
||||
agent['PlannedID'] = next_planned_id
|
||||
agent_set.append(agent)
|
||||
|
||||
remaining-=placed_count
|
||||
if remaining>0:
|
||||
attempts+=1
|
||||
spawn_time+=time_delay
|
||||
attempts=0
|
||||
batch_size=max(1,min(10,remaining))
|
||||
except Exception as e:
|
||||
print(
|
||||
f"Error placing platoon {platoon_id}: {e}")
|
||||
print("Reducing batch and retrying")
|
||||
attempts+=1
|
||||
batch_size=max(1,batch_size//2)
|
||||
spawn_time+=time_delay
|
||||
total_agents = next_planned_id
|
||||
|
||||
#================================================
|
||||
pending=sorted(agent_set,key=lambda a:a["Spawn Time"])
|
||||
pending=deque(pending)
|
||||
sim_to_planned = {}
|
||||
max_agents_per_step=25
|
||||
spawned_total = 0
|
||||
spawn_tolerance=1e-8
|
||||
while ((simulation.agent_count()>0 or len(pending)>0)
|
||||
and simulation.iteration_count()<max_iterations):
|
||||
current_time=simulation.elapsed_time()
|
||||
agents_this_step=0
|
||||
while (pending and (pending[0]["Spawn Time"]<=(
|
||||
current_time+spawn_tolerance))
|
||||
and agents_this_step<max_agents_per_step):
|
||||
a = pending.popleft()
|
||||
pos=tuple(a["Position"])
|
||||
v0 = float(a["Speed"])
|
||||
v0 = float(np.clip(v0,0.2,2.5))
|
||||
agent_params = (
|
||||
jps.AnticipationVelocityModelAgentParameters(
|
||||
journey_id=journey_id,
|
||||
stage_id=exit_id,
|
||||
position=pos,
|
||||
radius=0.25,
|
||||
desired_speed=v0,
|
||||
anticipation_time=0.5,
|
||||
reaction_time=0.3,
|
||||
wall_buffer_distance=0.08))
|
||||
try:
|
||||
add_result = simulation.add_agent(agent_params)
|
||||
internal_id = None
|
||||
if add_result is not None:
|
||||
try:
|
||||
internal_id = int(add_result)
|
||||
except Exception:
|
||||
internal_id = None
|
||||
if internal_id is not None:
|
||||
sim_to_planned[internal_id] = a
|
||||
print(f"Added planned={a['PlannedID']}")
|
||||
print(f"internal={internal_id}")
|
||||
print(f"time={current_time:.2f}")
|
||||
spawned_total +=1
|
||||
else:
|
||||
print(f"Added planned={a['PlannedID']}")
|
||||
print("(no internal_id returned)")
|
||||
print(f"time={current_time:.2f}")
|
||||
agents_this_step+=1
|
||||
break
|
||||
except Exception as e:
|
||||
pending_for_door = sum(
|
||||
1 for x in pending if (
|
||||
x['Entry Point']==a["Entry Point"]))
|
||||
print("\nadd_agent FAILED")
|
||||
print(f"planned={a['PlannedID']}")
|
||||
print(f"pos={pos}")
|
||||
print(f"speed={v0:.2f}")
|
||||
print(f"time={current_time:.2f}")
|
||||
print(f"pending_for_door={pending_for_door}")
|
||||
print(f"\n\nerror={e}")
|
||||
retry_delay = 0.1
|
||||
a["Spawn Time"] = current_time+retry_delay
|
||||
pending.appendleft(a)
|
||||
break
|
||||
simulation.iterate()
|
||||
iter_count = simulation.iteration_count()
|
||||
if iter_count % interval ==0:
|
||||
print(f"\nIteration: {iter_count}")
|
||||
print(f"time={simulation.elapsed_time():.2f}")
|
||||
print(f"active={simulation.agent_count()}")
|
||||
print(f"pending={len(pending)}")
|
||||
print(f"spawned={spawned_total}/{total_agents}")
|
||||
print("Simulation Completed!")
|
||||
print(f"Iterations: {simulation.iteration_count()}")
|
||||
print(f"Elapsed Time: {simulation.elapsed_time()}")
|
||||
print(f"Total Agents: {total_agents}")
|
||||
print(f"{trajectory_file = }")
|
||||
trajectory_data,walkable_area = read_sqlite_file(trajectory_file)
|
||||
speed=pedpy.compute_individual_speed(traj_data=trajectory_data,frame_step=10)
|
||||
speed=speed.merge(trajectory_data.data,on=["id","frame"],how="left")
|
||||
animate(trajectory_data,walkable_area,title_note="Evac",every_nth_frame=5)
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
BIN
archive/full-geo-current.png
Normal file
BIN
archive/full-geo-current.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
BIN
archive/geo-setup.png
Normal file
BIN
archive/geo-setup.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
96
archive/geometry.py
Normal file
96
archive/geometry.py
Normal file
@@ -0,0 +1,96 @@
|
||||
import sys
|
||||
import matplotlib
|
||||
matplotlib.use('QtAgg')
|
||||
import matplotlib.pyplot as plt
|
||||
from shapely import Polygon
|
||||
from shapely.plotting import plot_polygon
|
||||
|
||||
def current():
|
||||
queue = Polygon([
|
||||
(18.767,9.395),
|
||||
(15.214,9.395),
|
||||
(15.214,4.569),
|
||||
(15.214,0),
|
||||
(16.924,0),
|
||||
(16.924,4.569),
|
||||
(25.0,4.569),
|
||||
(25.0,16.823),
|
||||
#(26.163,4.569),
|
||||
#(28.214,5.07),
|
||||
#(28.214,17.761),
|
||||
#(25.787,17.761),
|
||||
])
|
||||
crosswalk = Polygon([
|
||||
(4,6.068),
|
||||
(4,7.896),
|
||||
(4,7.896),
|
||||
(15.214,7.896),
|
||||
(15.214,6.068),
|
||||
(4,6.068)
|
||||
])
|
||||
grass = Polygon([
|
||||
(4,0),
|
||||
(0,0),
|
||||
(0,17.761),
|
||||
(4,17.761)
|
||||
])
|
||||
plot_polygon(queue,color="blue",add_points=False)
|
||||
plot_polygon(crosswalk,color="red",add_points=False)
|
||||
plot_polygon(grass,color="blue",add_points=False)
|
||||
|
||||
def new():
|
||||
new_queue = Polygon([
|
||||
(19.531,10.306),
|
||||
(13.88,10.306),
|
||||
(12.98,9.896),
|
||||
(12.98,4.569),
|
||||
(12.98,0),
|
||||
(16.924,0),
|
||||
(16.924,4.569),
|
||||
(25.0,4.569),
|
||||
(25.0,16.823),
|
||||
#(26.163,4.569),
|
||||
#(28.214,5.07),
|
||||
#(28.214,17.761),
|
||||
#(25.787,17.761),
|
||||
])
|
||||
new_crosswalk = Polygon([
|
||||
(6.23,4.982),
|
||||
(6.23,8.982),
|
||||
(12.98,8.982),
|
||||
(12.98,4.982),
|
||||
])
|
||||
new_grass = Polygon([
|
||||
(6.23,0),
|
||||
(0,0),
|
||||
(0,17.761),
|
||||
(4,17.761),
|
||||
(4,10.306),
|
||||
(5.33,10.306),
|
||||
(6.23,9.896)
|
||||
])
|
||||
plot_polygon(new_queue,color="blue",add_points=False)
|
||||
plot_polygon(new_crosswalk,color="red",add_points=False)
|
||||
plot_polygon(new_grass,color="blue",add_points=False)
|
||||
return
|
||||
|
||||
def spawn():
|
||||
spawn_area = Polygon([
|
||||
(25.0,16.823),
|
||||
(25.0,4.569),
|
||||
(26.163,4.569),
|
||||
(28.214,5.07),
|
||||
(28.214,17.761),
|
||||
(25.787,17.761),
|
||||
])
|
||||
plot_polygon(spawn_area,color="green",add_points=False)
|
||||
return spawn_area
|
||||
|
||||
if __name__ == "__main__":
|
||||
from PyQt6 import QtWidgets
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
new()
|
||||
current()
|
||||
spawn()
|
||||
plt.show(block=False)
|
||||
sys.exit(app.exec())
|
||||
1728
archive/prompt_full-run-sim.txt
Normal file
1728
archive/prompt_full-run-sim.txt
Normal file
File diff suppressed because it is too large
Load Diff
557
archive/prompt_full-run-sim1.txt
Normal file
557
archive/prompt_full-run-sim1.txt
Normal file
@@ -0,0 +1,557 @@
|
||||
I'm creating a simulation using JuPedSim to see how pedestrians interact with a crosswalk system. The crosswalk system will have a user-defined "active" interval, and will be activated by agents being within a predefined distance. All agents will spawn in a specified spawn area, and are attempting to get from one side of the road to the other. They may only use the crosswalk to cross, and can only cross when the crosswalk is "active". Below are provided 4 separate files to create the JuPedSim simulation model:
|
||||
|
||||
============================
|
||||
(1.1)
|
||||
============================
|
||||
=>geometry_setup.py(file):
|
||||
class GeometrySetup(current_setup:bool)
|
||||
spawn:defines the Polygon for the spawn_area
|
||||
queue:defines the Polygon for the queue_area
|
||||
trigger:defines the Polygon for the trigger_area
|
||||
crosswalk:defines the Polygon for the crosswalk_area
|
||||
grass:defines the Polygon for the grass_area
|
||||
|
||||
============================
|
||||
(1.2)
|
||||
============================
|
||||
=>spawning.py(file):
|
||||
class SpawnManager(spawn_area:Polygon,min_spacing:float):
|
||||
__init__:
|
||||
spawn_area: area for valid spawns
|
||||
min_spacing: minimum spacing between spawn points
|
||||
spawn_coords: all coordinates for spawning agents
|
||||
filled_coords: spawn points currently occupied by agents
|
||||
spawned_agents: set of agent ids already spawned
|
||||
agent_pos: dictionary which connects agent ids to a spawn point
|
||||
generate_coords:
|
||||
uses Poisson disk method with CDTree from scipy.spatial for all spawn points
|
||||
get_coords:
|
||||
provides a tuple[float,float] or None based on if there is room to spawn agents
|
||||
spawn_agent:
|
||||
provides AgentSetup object or None depending on if there is room to spawn and there are agents left to spawn
|
||||
unfill_coords:
|
||||
returns None, used to indicate a spawn point has been made available by an agent moving
|
||||
get_agent_pos;
|
||||
returns (0,0) or the spawn coordinates of agents if they are in agent_pos
|
||||
check_spawn_complete:
|
||||
checks whether the number of agents spawned is the same as all_agents list, and if all spawn points are empty.
|
||||
|
||||
============================
|
||||
(1.3)
|
||||
============================
|
||||
=>agents(folder):
|
||||
|>agent_data.py(file):
|
||||
| dictionary with group keys and values
|
||||
|>agent_setup.py(file):
|
||||
defines the AgentSetup class and computes list of all_agents:
|
||||
"""
|
||||
@dataclass
|
||||
class AgentSetup:
|
||||
id:int
|
||||
grade:str
|
||||
speed:float
|
||||
radius:float
|
||||
"""
|
||||
|
||||
============================
|
||||
(1.4)
|
||||
============================
|
||||
=>crosswalk_setup.py(file):
|
||||
class CrosswalkStatus(Enum):
|
||||
INACTIVE
|
||||
ACTIVE
|
||||
COOLDOWN
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CrosswalkConfig:
|
||||
trigger_dist:float
|
||||
activation_time:float
|
||||
cooldown_time:float
|
||||
min_agents_activation:int
|
||||
activation_delay:float
|
||||
crosswalk_area:Polygon
|
||||
trigger_area:Polygon
|
||||
|
||||
@dataclass
|
||||
class CrosswalkState:
|
||||
status:CrosswalkStatus
|
||||
is_active:bool
|
||||
time_active:float
|
||||
time_remaining:float
|
||||
agents_in_trigger:int
|
||||
agents_waiting:int
|
||||
activation_count:int
|
||||
|
||||
class CrosswalkController:
|
||||
__init__(self,config:CrosswalkConfig,current_setup:bool):
|
||||
update: calls the following methods, then returns get_state()
|
||||
update_agents_in_trigger
|
||||
update_state
|
||||
update_statistics
|
||||
update_agents_in_trigger: updates what agents are in the trigger_area for the crosswalk
|
||||
@staticmethod
|
||||
points_in_area:finding what points lie in a given area
|
||||
update_state:updates crosswalk state to be COOLDOWN,ACTIVE or INACTIVE based on specified parameters
|
||||
activate:changes the system to the ACTIVE state
|
||||
deactivate:changes the system to the COOLDOWN state
|
||||
update_statistics:updates info on crosswalks if status is ACTIVE
|
||||
get_state: provides the state based on the current time in relation to the activation time, then updates the system
|
||||
can_agent_cross: checks whether ACTIVE or INACTIVE to either let agent pass or add agent to waiting group
|
||||
@property
|
||||
is_active: provides a boolean response whether the system is ACTIVE or not
|
||||
get_statistics:provides stats from the system at the current time
|
||||
|
||||
|
||||
============
|
||||
here is the code:
|
||||
|
||||
|
||||
============================
|
||||
(2.1) (geometry_setup.py)
|
||||
============================
|
||||
|
||||
|
||||
import sys
|
||||
import matplotlib
|
||||
matplotlib.use('QtAgg')
|
||||
import matplotlib.pyplot as plt
|
||||
from shapely import Polygon
|
||||
from shapely.plotting import plot_polygon
|
||||
|
||||
class GeometrySetup:
|
||||
def __init__(self,current_setup:bool):
|
||||
self.current_setup = current_setup
|
||||
self.spawn()
|
||||
self.queue()
|
||||
self.trigger()
|
||||
self.crosswalk()
|
||||
self.grass()
|
||||
|
||||
def spawn(self)->Polygon:
|
||||
spawn_area = Polygon([
|
||||
(25.0,16.823),
|
||||
(25.0,4.569),
|
||||
(26.163,4.569),
|
||||
(28.214,5.07),
|
||||
(28.214,17.761),
|
||||
(25.787,17.761),
|
||||
])
|
||||
plot_polygon(spawn_area,color="purple",add_points=False)
|
||||
return spawn_area
|
||||
|
||||
def queue(self)->Polygon:
|
||||
if self.current_setup is True:
|
||||
queue_area = Polygon([
|
||||
(18.767,9.395),
|
||||
(16.924,9.395),
|
||||
(16.924,4.569),
|
||||
(25.0,4.569),
|
||||
(25.0,16.823)
|
||||
])
|
||||
else:
|
||||
queue_area = Polygon([
|
||||
(19.531,10.306),
|
||||
(15.214,10.306),
|
||||
(15.214,0),
|
||||
(16.924,0),
|
||||
(16.924,4.569),
|
||||
(25.0,4.569),
|
||||
(25.0,16.823)
|
||||
])
|
||||
plot_polygon(queue_area,color="blue",add_points=False)
|
||||
return queue_area
|
||||
|
||||
def trigger(self)->Polygon:
|
||||
if self.current_setup is True:
|
||||
trigger_area = Polygon([
|
||||
(15.214,0),
|
||||
(15.214,9.395),
|
||||
(16.924,9.395),
|
||||
(16.924,0)
|
||||
])
|
||||
else:
|
||||
trigger_area = Polygon([
|
||||
(15.214,10.306),
|
||||
(15.214,0),
|
||||
(12.98,0),
|
||||
(12.98,9.896),
|
||||
(13.88,10.306)
|
||||
])
|
||||
plot_polygon(trigger_area,color="green",add_points=False)
|
||||
return trigger_area
|
||||
|
||||
def crosswalk(self)->Polygon:
|
||||
if self.current_setup is True:
|
||||
crosswalk_area = Polygon([
|
||||
(4,6.068),
|
||||
(4,7.896),
|
||||
(4,7.896),
|
||||
(15.214,7.896),
|
||||
(15.214,6.068),
|
||||
(4,6.068)
|
||||
])
|
||||
else:
|
||||
crosswalk_area = Polygon([
|
||||
(6.23,4.982),
|
||||
(6.23,8.982),
|
||||
(12.98,8.982),
|
||||
(12.98,4.982)
|
||||
])
|
||||
plot_polygon(crosswalk_area,color="red",add_points=False)
|
||||
return crosswalk_area
|
||||
|
||||
def grass(self)->Polygon:
|
||||
if self.current_setup is True:
|
||||
grass_area = Polygon([
|
||||
(4,0),
|
||||
(0,0),
|
||||
(0,17.761),
|
||||
(4,17.761)
|
||||
])
|
||||
else:
|
||||
grass_area = Polygon([
|
||||
(6.23,0),
|
||||
(0,0),
|
||||
(0,17.761),
|
||||
(4,17.761),
|
||||
(4,10.306),
|
||||
(5.33,10.306),
|
||||
(6.23,9.896)
|
||||
])
|
||||
plot_polygon(grass_area,color="blue",add_points=False)
|
||||
return grass_area
|
||||
|
||||
if __name__ == "__main__":
|
||||
from PyQt6 import QtWidgets
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
geo_map = GeometrySetup(False)
|
||||
plt.show(block=False)
|
||||
sys.exit(app.exec())
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
============================
|
||||
(2.2) (spawning.py)
|
||||
============================
|
||||
|
||||
from shapely.geometry import Polygon,Point
|
||||
from typing import Tuple, List, Dict, Set
|
||||
from scipy.spatial import cKDTree
|
||||
import sys
|
||||
import math
|
||||
import numpy as np
|
||||
import config
|
||||
sys.path.insert(0,str(config.AGENTS_DIR))
|
||||
from agents.agent_setup import AgentSetup
|
||||
|
||||
|
||||
class SpawnManager:
|
||||
def __init__(self,spawn_area:Polygon,min_spacing:float=0.55):
|
||||
"""
|
||||
self.spawn_area: geometry where agents may spawn
|
||||
self.min_spacing: minimum spacing for spawn_points
|
||||
self.spawn_coords: all spawn points available
|
||||
self.filled_coords: spawn points currently filled by agents
|
||||
self.spawned_agents: all agents already spawned in sim
|
||||
self.agent_pos: connects agent_id to spawn_index
|
||||
self.rng: random number generator object
|
||||
"""
|
||||
|
||||
self.spawn_area = spawn_area
|
||||
self.min_spacing = min_spacing
|
||||
self.spawn_coords: np.ndarray = np.array([])
|
||||
self.filled_coords: np.ndarray = np.array([])
|
||||
self.spawned_agents: set = set()
|
||||
self.agent_pos:dict={}
|
||||
self.rng = np.random.default_rng()
|
||||
|
||||
def generate_coords(self,max_samples:int=1000)->None:
|
||||
min_x,min_y,max_x,max_y = self.spawn_area.bounds
|
||||
points = []
|
||||
while len(points) ==0:
|
||||
x = self.rng.uniform(min_x,max_x)
|
||||
y = self.rng.uniform(min_y,max_y)
|
||||
if self.spawn_area.contains(Point(x,y)):
|
||||
points.append([x,y])
|
||||
for _ in range(max_samples):
|
||||
idx = self.rng.integers(0,len(points),endpoint=True)
|
||||
base = points[idx]
|
||||
for _ in range(25):
|
||||
angle = self.rng.uniform(0,2*np.pi)
|
||||
radius = self.rng.uniform(self.min_spacing,2*self.min_spacing)
|
||||
x = base[0]+radius*np.cos(angle)
|
||||
y = base[1]+radius*np.sin(angle)
|
||||
if not self.spawn_area.contains(Point(x,y)):
|
||||
continue
|
||||
if len(points)>0:
|
||||
tree = cKDTree(points)
|
||||
distance,_ = tree.query([[x,y]],k=1)
|
||||
if distance[0]<self.min_spacing:
|
||||
continue
|
||||
points.append([x,y])
|
||||
break
|
||||
self.spawn_coords = np.array(points)
|
||||
self.filled_coords = np.zeros(len(points),dtype=bool)
|
||||
|
||||
|
||||
def get_coords(self)->Tuple[float,float]|None:
|
||||
'''
|
||||
points = [
|
||||
pt for pt in self.generate_coords if pt \
|
||||
not in self.filled_coords.values()
|
||||
]
|
||||
return self.rng.choice(points) if points else None
|
||||
'''
|
||||
free_idx = np.where(~self.filled_coords)[0]
|
||||
if len(free_idx) == 0:
|
||||
return None
|
||||
idx = self.rng.choice(free_idx)
|
||||
return tuple(self.spawn_coords[idx])
|
||||
|
||||
|
||||
def spawn_agent(self,all_agents:List[AgentSetup])->AgentSetup|None:
|
||||
if len(self.spawned_agents) >= len(all_agents):
|
||||
return None
|
||||
spawn_point = self.get_coords()
|
||||
if not spawn_point:
|
||||
return None
|
||||
free_agents = [
|
||||
agent for agent in all_agents \
|
||||
if agent.id not in self.spawned_agents
|
||||
]
|
||||
if not free_agents:
|
||||
return None
|
||||
agent = self.rng.choice(free_agents)
|
||||
self.spawned_agents.add(agent.id)
|
||||
distances = np.linalg.norm(self.spawn_coords-spawn_point,axis=1)
|
||||
spawn_idx = np.argmin(distances)
|
||||
self.filled_coords[spawn_idx] = True
|
||||
self.agent_pos[agent.id] = spawn_idx
|
||||
return agent
|
||||
|
||||
def unfill_coords(self,agent_id:int)->None:
|
||||
if agent_id in self.agent_pos:
|
||||
spawn_idx = self.agent_pos[agent_id]
|
||||
self.filled_coords[spawn_idx] = False
|
||||
del self.agent_pos[agent_id]
|
||||
self.spawned_agents.discard(agent_id)
|
||||
|
||||
def get_agent_pos(self,agent_id:int)->Tuple[float,float]:
|
||||
if agent_id in self.agent_pos:
|
||||
spawn_idx = self.agent_pos[agent_id]
|
||||
return tuple(self.spawn_coords[spawn_idx])
|
||||
return (0,0)
|
||||
|
||||
def check_spawn_complete(self,all_agents:List[AgentSetup])->bool:
|
||||
return (len(self.spawned_agents)<len(all_agents) and\
|
||||
np.sum(~self.filled_coords) > 0)
|
||||
|
||||
|
||||
============================
|
||||
(2.3) (agent_setup.py)
|
||||
============================
|
||||
|
||||
from agent_data import grade_data
|
||||
from dataclasses import dataclass
|
||||
import numpy as np
|
||||
from typing import List
|
||||
|
||||
@dataclass
|
||||
class AgentSetup:
|
||||
id:int
|
||||
grade:str
|
||||
speed:float
|
||||
radius:float
|
||||
|
||||
def AgentConfig()->List[List[AgentSetup],List[int]]:
|
||||
agent_id = 1
|
||||
pop_list = []
|
||||
all_agents = []
|
||||
for idx,key in enumerate(grade_data.keys()):
|
||||
grade = grade_data[key]
|
||||
pop_list.append(grade["Pop Current"])
|
||||
for i in range(pop_list[idx]):
|
||||
rng = np.random.default_rng()
|
||||
agent = AgentSetup(
|
||||
id=agent_id,
|
||||
grade=key,
|
||||
speed=rng.normal(
|
||||
grade["Speed Mean"],
|
||||
grade["Speed Std Dev"]
|
||||
),
|
||||
radius=grade["Radius"]
|
||||
)
|
||||
all_agents.append(agent)
|
||||
agent_id +=1
|
||||
return all_agents, pop_list
|
||||
|
||||
|
||||
============================
|
||||
(2.4) (crosswalk_setup.py)
|
||||
============================
|
||||
|
||||
from dataclasses import dataclass,field
|
||||
from enum import Enum
|
||||
from typing import List,Dict,Tuple,Set
|
||||
from shapely import Polygon,Point
|
||||
from geometry_setup import GeometrySetup
|
||||
import shapely
|
||||
import numpy as np
|
||||
|
||||
class CrosswalkStatus(Enum):
|
||||
INACTIVE = "inactive"
|
||||
ACTIVE = "active"
|
||||
COOLDOWN = "cooldown"
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CrosswalkConfig:
|
||||
trigger_dist:float
|
||||
activation_time:float
|
||||
cooldown_time:float
|
||||
min_agents_activation:int
|
||||
activation_delay:float
|
||||
crosswalk_area:Polygon
|
||||
trigger_area:Polygon
|
||||
|
||||
@dataclass
|
||||
class CrosswalkState:
|
||||
status:CrosswalkStatus
|
||||
is_active:bool
|
||||
time_active:float
|
||||
time_remaining:float
|
||||
agents_in_trigger:int
|
||||
agents_waiting:int
|
||||
activation_count:int
|
||||
|
||||
class CrosswalkController:
|
||||
def __init__(self,config:CrosswalkConfig,current_setup:bool):
|
||||
self.config = config
|
||||
self.crosswalk_area = config.crosswalk_area
|
||||
self.trigger_area = config.trigger_area
|
||||
self.status = CrosswalkStatus.INACTIVE
|
||||
self.state_start_time = 0.0
|
||||
self.current_time = 0.0
|
||||
self.activation_count = 0
|
||||
self.agents_in_trigger: Set[int] = set()
|
||||
self.agents_waiting: Set[int] = set()
|
||||
self.total_active_time = 0.0
|
||||
self.agents_served = 0
|
||||
|
||||
def update(
|
||||
self,
|
||||
agent_pos:Dict[int,Tuple[float,float]],
|
||||
time_step:float,
|
||||
current_time:float=None
|
||||
)->CrosswalkState:
|
||||
if current_time is not None:
|
||||
self.current_time = current_time
|
||||
else:
|
||||
self.current_time +=time_step
|
||||
self.update_agents_in_trigger(agent_pos)
|
||||
self.update_state(time_step)
|
||||
self.update_statistics(time_step)
|
||||
return self.get_state()
|
||||
|
||||
def update_agents_in_trigger(
|
||||
self,
|
||||
agent_pos:Dict[int,Tuple[float,float]]
|
||||
)->None:
|
||||
self.agents_in_trigger.clear()
|
||||
if not agent_pos:
|
||||
return
|
||||
agent_ids = list(agent_pos.keys())
|
||||
positions = np.array(list(agent_pos.values()),dtype=np.float32)
|
||||
in_trigger = self.points_in_area(positions,self.trigger_area)
|
||||
for i, agent_id in enumerate(agent_ids):
|
||||
if in_trigger[i]:
|
||||
self.agents_in_trigger.add(agent_id)
|
||||
|
||||
@staticmethod
|
||||
def points_in_area(points:np.ndarray,polygon:Polygon)->np.ndarray:
|
||||
if len(points) ==0:
|
||||
return np.array([],dtype=bool)
|
||||
x,y = points[:,0],points[:,1]
|
||||
vertices = shapely.get_coordinates(polygon)
|
||||
n = len(vertices)
|
||||
inside = np.zeros(len(points),dtype=bool)
|
||||
j = n-1
|
||||
for i in range(n):
|
||||
xi, yi = vertices[i]
|
||||
xj, yj = vertices[j]
|
||||
mask = ((yi>y) != (yj>y)) & (x<(xj-xi)*(y-yi)/(yj-yi)+xi)
|
||||
inside ^= mask
|
||||
j = i
|
||||
return inside
|
||||
|
||||
def update_state(self,time_step:float)->None:
|
||||
elapsed = self.current_time - self.state_start_time
|
||||
if self.status == CrosswalkStatus.ACTIVE:
|
||||
if elapsed >= self.config.activation_time:
|
||||
self.deactivate()
|
||||
elif self.status == CrosswalkStatus.COOLDOWN:
|
||||
if elapsed >= self.config.cooldown_time:
|
||||
self.status = CrosswalkStatus.INACTIVE
|
||||
self.state_start_time = self.current_time
|
||||
elif self.status ==CrosswalkStatus.INACTIVE:
|
||||
if (len(self.agents_in_trigger)>=self.config.min_agents_activation and \
|
||||
elapsed >= self.config.activation_delay):
|
||||
self.activate()
|
||||
|
||||
def activate(self)->None:
|
||||
self.status = CrosswalkStatus.ACTIVE
|
||||
self.state_start_time = self.current_time
|
||||
self.activation_count +=1
|
||||
self.agents_served += len(self.agents_waiting)
|
||||
self.agents_waiting.clear()
|
||||
|
||||
def deactivate(self)->None:
|
||||
self.status = CrosswalkStatus.COOLDOWN
|
||||
self.state_start_time = self.current_time
|
||||
|
||||
def update_statistics(self,time_step:float)->None:
|
||||
if self.status == CrosswalkStatus.ACTIVE:
|
||||
self.total_active_time += time_step
|
||||
|
||||
def get_state(self)->CrosswalkState:
|
||||
elapsed = self.current_time-self.state_start_time
|
||||
if self.status == CrosswalkStatus.ACTIVE:
|
||||
time_remaining = max(0.0,self.config.activation_time-elapsed)
|
||||
elif self.status == CrosswalkStatus.COOLDOWN:
|
||||
time_remaining = max(0.0,self.config.cooldown_duration-elapsed)
|
||||
else:
|
||||
time_remaining = 0.0
|
||||
return CrosswalkState(
|
||||
status=self.status,
|
||||
is_active=(self.status == CrosswalkStatus.ACTIVE),
|
||||
time_active=elapsed if self.status == CrosswalkStatus.ACTIVE else 0.0,
|
||||
time_remaining=time_remaining,
|
||||
agents_in_trigger=len(self.agents_in_trigger),
|
||||
agents_waiting=len(self.agents_waiting),
|
||||
activation_count = self.activation_count
|
||||
)
|
||||
def can_agent_cross(self,agent_id:int)->bool:
|
||||
if self.status == CrosswalkStatus.ACTIVE:
|
||||
return True
|
||||
else:
|
||||
if agent_id in self.agents_in_trigger:
|
||||
self.agents_waiting.add(agent_id)
|
||||
return False
|
||||
|
||||
@property
|
||||
def is_active(self)->bool:
|
||||
return self.status == CrosswalkStatus.ACTIVE
|
||||
|
||||
def get_statistics(self)->Dict[str,float]:
|
||||
return {
|
||||
"total_activations":self.activation_count,
|
||||
"total_active_time":self.total_active_time,
|
||||
"agents_served":self.agents_served,
|
||||
"current_agents_in_trigger":len(self.agents_in_trigger),
|
||||
"current_agents_waiting":len(self.agents_waiting)
|
||||
}
|
||||
|
||||
=========================
|
||||
The last part which needs to be done is using the JuPedSim module to create a full simulation using all these pieces;
|
||||
|
||||
690
archive/prompt_full-run-sim2.txt
Normal file
690
archive/prompt_full-run-sim2.txt
Normal file
@@ -0,0 +1,690 @@
|
||||
The text file includes all the files which makeup my simulation configuration. could you please run through them and fix any potential errors, delete any unused or unnecessary variables?
|
||||
|
||||
|
||||
|
||||
===================
|
||||
(geometry_setup.py)
|
||||
===================
|
||||
|
||||
import sys
|
||||
import matplotlib
|
||||
matplotlib.use('QtAgg')
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.figure import Figure
|
||||
from matplotlib.axes import Axes
|
||||
from shapely import Polygon
|
||||
from shapely.plotting import plot_polygon
|
||||
from typing import Tuple
|
||||
|
||||
class GeometrySetup:
|
||||
def __init__(self,current_setup:bool):
|
||||
self.current_setup = current_setup
|
||||
self.spawn_area = self.spawn()
|
||||
self.queue_area = self.queue()
|
||||
self.grass_area = self.grass()
|
||||
self.crosswalk_area = self.crosswalk()
|
||||
self.entry_area = self.entry_polygon()
|
||||
self.exit_area = self.exit_polygon()
|
||||
|
||||
def spawn(self)->Polygon:
|
||||
spawn_area = Polygon([
|
||||
(25.0,16.823),
|
||||
(25.0,4.569),
|
||||
(26.163,4.569),
|
||||
(28.214,5.07),
|
||||
(28.214,17.761),
|
||||
(25.787,17.761),
|
||||
])
|
||||
return spawn_area
|
||||
|
||||
def queue(self)->Polygon:
|
||||
if self.current_setup is True:
|
||||
queue_area = Polygon([
|
||||
(18.767,9.395),
|
||||
(16.924,9.395),
|
||||
(15.214,9.395), #prev trigger area
|
||||
(15.214,0), # ||
|
||||
(16.924,0), # ||
|
||||
(16.924,4.569),
|
||||
(25.0,4.569),
|
||||
(25.0,16.823)
|
||||
])
|
||||
else:
|
||||
queue_area = Polygon([
|
||||
(19.531,10.306),
|
||||
(15.214,10.306),
|
||||
(13.88,10.306), #prev trigger area
|
||||
(12.98,9.896), # ||
|
||||
(12.98,0), # ||
|
||||
(15.214,0), #
|
||||
(15.214,0),
|
||||
(16.924,0),
|
||||
(16.924,4.569),
|
||||
(25.0,4.569),
|
||||
(25.0,16.823)
|
||||
])
|
||||
return queue_area
|
||||
|
||||
def grass(self)->Polygon:
|
||||
if self.current_setup is True:
|
||||
grass_area = Polygon([
|
||||
(4,0),
|
||||
(0,0),
|
||||
(0,17.761),
|
||||
(4,17.761)
|
||||
])
|
||||
else:
|
||||
grass_area = Polygon([
|
||||
(6.23,0),
|
||||
(0,0),
|
||||
(0,17.761),
|
||||
(4,17.761),
|
||||
(4,10.306),
|
||||
(5.33,10.306),
|
||||
(6.23,9.896)
|
||||
])
|
||||
return grass_area
|
||||
|
||||
def crosswalk(self)->Polygon:
|
||||
if self.current_setup is True:
|
||||
crosswalk_area = Polygon([
|
||||
(4,6.068),
|
||||
(4,7.896),
|
||||
(4,7.896),
|
||||
(15.214,7.896),
|
||||
(15.214,6.068),
|
||||
(4,6.068)
|
||||
])
|
||||
else:
|
||||
crosswalk_area = Polygon([
|
||||
(6.23,4.982),
|
||||
(6.23,8.982),
|
||||
(12.98,8.982),
|
||||
(12.98,4.982)
|
||||
])
|
||||
return crosswalk_area
|
||||
|
||||
def entry_polygon(self)->Polygon:
|
||||
if self.current_setup is True:
|
||||
entry_area = Polygon([ # x: 2.9m, y: 3.428m
|
||||
(15.314,5.268), # dx: 0.1m, dy: 0.8m
|
||||
(15.314,8.696),
|
||||
(18.214,8.696),
|
||||
(18.214,5.268)
|
||||
])
|
||||
else:
|
||||
entry_area = Polygon([ # x: 2.9m, y: 5.6m
|
||||
(15.98,9.782),
|
||||
(15.98,4.182),
|
||||
(13.08,4.182),
|
||||
(13.08,9.782)
|
||||
])
|
||||
return entry_area
|
||||
|
||||
def exit_polygon(self)->Polygon:
|
||||
if self.current_setup is True:
|
||||
exit_area = Polygon([ # x: 2.9m, y: 3.428m
|
||||
(1,5.268),
|
||||
(1,8.696),
|
||||
(3.9,8.696),
|
||||
(3.9,5.268)
|
||||
])
|
||||
else:
|
||||
exit_area = Polygon([ # x: 2.9m, y: 5.6m
|
||||
(3.23,4.182),
|
||||
(3.23,9.782),
|
||||
(6.13,9.782),
|
||||
(6.13,4.182)
|
||||
])
|
||||
return exit_area
|
||||
|
||||
def plot_all(self)->Tuple[Figure,Axes]:
|
||||
plot_polygon(self.spawn_area,color="green",add_points=False)
|
||||
plot_polygon(self.queue_area,color="blue",add_points=False)
|
||||
plot_polygon(self.grass_area,color="blue",add_points=False)
|
||||
plot_polygon(self.crosswalk_area,color="red",add_points=False)
|
||||
plot_polygon(self.entry_area,color="black",add_points=False)
|
||||
plot_polygon(self.exit_area,color="black",add_points=False)
|
||||
return
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from PyQt6 import QtWidgets
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
GeometrySetup(False).plot_all()
|
||||
plt.show(block=False)
|
||||
sys.exit(app.exec())
|
||||
|
||||
===================
|
||||
(agent_setup.py)
|
||||
===================
|
||||
from agent_data import grade_data
|
||||
from dataclasses import dataclass
|
||||
import numpy as np
|
||||
from typing import List
|
||||
|
||||
@dataclass
|
||||
class AgentSetup:
|
||||
id:int
|
||||
grade:str
|
||||
speed:float
|
||||
radius:float
|
||||
|
||||
def AgentConfig()->List[List[AgentSetup],List[int]]:
|
||||
agent_id = 1
|
||||
pop_list = []
|
||||
all_agents = []
|
||||
for idx,key in enumerate(grade_data.keys()):
|
||||
grade = grade_data[key]
|
||||
pop_list.append(grade["Pop Current"])
|
||||
for i in range(pop_list[idx]):
|
||||
rng = np.random.default_rng()
|
||||
agent = AgentSetup(
|
||||
id=agent_id,
|
||||
grade=key,
|
||||
speed=rng.normal(
|
||||
grade["Speed Mean"],
|
||||
grade["Speed Std Dev"]
|
||||
),
|
||||
radius=grade["Radius"]
|
||||
)
|
||||
all_agents.append(agent)
|
||||
agent_id +=1
|
||||
return all_agents, pop_list
|
||||
|
||||
|
||||
===================
|
||||
(crosswalk_setup.py)
|
||||
===================
|
||||
|
||||
from dataclasses import dataclass,field
|
||||
from enum import Enum
|
||||
from typing import List,Dict,Tuple,Set
|
||||
from shapely import Polygon,Point
|
||||
from geometry_setup import GeometrySetup
|
||||
import shapely
|
||||
import numpy as np
|
||||
|
||||
class CrosswalkStatus(Enum):
|
||||
INACTIVE = "inactive"
|
||||
ACTIVE = "active"
|
||||
COOLDOWN = "cooldown"
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CrosswalkConfig:
|
||||
trigger_dist:float
|
||||
activation_time:float
|
||||
cooldown_time:float
|
||||
min_agents_activation:int
|
||||
activation_delay:float
|
||||
crosswalk_area:Polygon
|
||||
trigger_area:Polygon
|
||||
|
||||
@dataclass
|
||||
class CrosswalkState:
|
||||
status:CrosswalkStatus
|
||||
is_active:bool
|
||||
time_active:float
|
||||
time_remaining:float
|
||||
agents_in_trigger:int
|
||||
agents_waiting:int
|
||||
activation_count:int
|
||||
|
||||
class CrosswalkController:
|
||||
def __init__(self,config:CrosswalkConfig,current_setup:bool):
|
||||
self.config = config
|
||||
self.crosswalk_area = config.crosswalk_area
|
||||
self.trigger_area = config.trigger_area
|
||||
self.status = CrosswalkStatus.INACTIVE
|
||||
self.state_start_time = 0.0
|
||||
self.current_time = 0.0
|
||||
self.activation_count = 0
|
||||
self.agents_in_trigger: Set[int] = set()
|
||||
self.agents_waiting: Set[int] = set()
|
||||
self.total_active_time = 0.0
|
||||
self.agents_served = 0
|
||||
|
||||
def update(
|
||||
self,
|
||||
agent_pos:Dict[int,Tuple[float,float]],
|
||||
time_step:float,
|
||||
current_time:float=None
|
||||
)->CrosswalkState:
|
||||
if current_time is not None:
|
||||
self.current_time = current_time
|
||||
else:
|
||||
self.current_time +=time_step
|
||||
self.update_agents_in_trigger(agent_pos)
|
||||
self.update_state(time_step)
|
||||
self.update_statistics(time_step)
|
||||
return self.get_state()
|
||||
|
||||
def update_agents_in_trigger(
|
||||
self,
|
||||
agent_pos:Dict[int,Tuple[float,float]]
|
||||
)->None:
|
||||
self.agents_in_trigger.clear()
|
||||
if not agent_pos:
|
||||
return
|
||||
agent_ids = list(agent_pos.keys())
|
||||
positions = np.array(list(agent_pos.values()),dtype=np.float32)
|
||||
in_trigger = self.points_in_area(positions,self.trigger_area)
|
||||
for i, agent_id in enumerate(agent_ids):
|
||||
if in_trigger[i]:
|
||||
self.agents_in_trigger.add(agent_id)
|
||||
|
||||
@staticmethod
|
||||
def points_in_area(points:np.ndarray,polygon:Polygon)->np.ndarray:
|
||||
if len(points) ==0:
|
||||
return np.array([],dtype=bool)
|
||||
x,y = points[:,0],points[:,1]
|
||||
vertices = shapely.get_coordinates(polygon)
|
||||
n = len(vertices)
|
||||
inside = np.zeros(len(points),dtype=bool)
|
||||
j = n-1
|
||||
for i in range(n):
|
||||
xi, yi = vertices[i]
|
||||
xj, yj = vertices[j]
|
||||
mask = ((yi>y) != (yj>y)) & (x<(xj-xi)*(y-yi)/(yj-yi)+xi)
|
||||
inside ^= mask
|
||||
j = i
|
||||
return inside
|
||||
|
||||
def update_state(self,time_step:float)->None:
|
||||
elapsed = self.current_time - self.state_start_time
|
||||
if self.status == CrosswalkStatus.ACTIVE:
|
||||
if elapsed >= self.config.activation_time:
|
||||
self.deactivate()
|
||||
elif self.status == CrosswalkStatus.COOLDOWN:
|
||||
if elapsed >= self.config.cooldown_time:
|
||||
self.status = CrosswalkStatus.INACTIVE
|
||||
self.state_start_time = self.current_time
|
||||
elif self.status ==CrosswalkStatus.INACTIVE:
|
||||
if (len(self.agents_in_trigger)>=self.config.min_agents_activation and \
|
||||
elapsed >= self.config.activation_delay):
|
||||
self.activate()
|
||||
|
||||
def activate(self)->None:
|
||||
self.status = CrosswalkStatus.ACTIVE
|
||||
self.state_start_time = self.current_time
|
||||
self.activation_count +=1
|
||||
self.agents_served += len(self.agents_waiting)
|
||||
self.agents_waiting.clear()
|
||||
|
||||
def deactivate(self)->None:
|
||||
self.status = CrosswalkStatus.COOLDOWN
|
||||
self.state_start_time = self.current_time
|
||||
|
||||
def update_statistics(self,time_step:float)->None:
|
||||
if self.status == CrosswalkStatus.ACTIVE:
|
||||
self.total_active_time += time_step
|
||||
|
||||
def get_state(self)->CrosswalkState:
|
||||
elapsed = self.current_time-self.state_start_time
|
||||
if self.status == CrosswalkStatus.ACTIVE:
|
||||
time_remaining = max(0.0,self.config.activation_time-elapsed)
|
||||
elif self.status == CrosswalkStatus.COOLDOWN:
|
||||
time_remaining = max(0.0,self.config.cooldown_duration-elapsed)
|
||||
else:
|
||||
time_remaining = 0.0
|
||||
return CrosswalkState(
|
||||
status=self.status,
|
||||
is_active=(self.status == CrosswalkStatus.ACTIVE),
|
||||
time_active=elapsed if self.status == CrosswalkStatus.ACTIVE else 0.0,
|
||||
time_remaining=time_remaining,
|
||||
agents_in_trigger=len(self.agents_in_trigger),
|
||||
agents_waiting=len(self.agents_waiting),
|
||||
activation_count = self.activation_count
|
||||
)
|
||||
def can_agent_cross(self,agent_id:int)->bool:
|
||||
if self.status == CrosswalkStatus.ACTIVE:
|
||||
return True
|
||||
else:
|
||||
if agent_id in self.agents_in_trigger:
|
||||
self.agents_waiting.add(agent_id)
|
||||
return False
|
||||
|
||||
@property
|
||||
def is_active(self)->bool:
|
||||
return self.status == CrosswalkStatus.ACTIVE
|
||||
|
||||
def get_statistics(self)->Dict[str,float]:
|
||||
return {
|
||||
"total_activations":self.activation_count,
|
||||
"total_active_time":self.total_active_time,
|
||||
"agents_served":self.agents_served,
|
||||
"current_agents_in_trigger":len(self.agents_in_trigger),
|
||||
"current_agents_waiting":len(self.agents_waiting)
|
||||
}
|
||||
|
||||
===================
|
||||
(spawning.py)
|
||||
===================
|
||||
from shapely.geometry import Polygon,Point
|
||||
from typing import Tuple, List, Dict, Set
|
||||
from scipy.spatial import cKDTree
|
||||
import sys
|
||||
import math
|
||||
import numpy as np
|
||||
import config
|
||||
sys.path.insert(0,str(config.AGENTS_DIR))
|
||||
from agents.agent_setup import AgentSetup
|
||||
|
||||
|
||||
class SpawnManager:
|
||||
def __init__(self,spawn_area:Polygon,min_spacing:float=0.55):
|
||||
"""
|
||||
self.spawn_area: geometry where agents may spawn
|
||||
self.min_spacing: minimum spacing for spawn_points
|
||||
self.spawn_coords: all spawn points available
|
||||
self.filled_coords: spawn points currently filled by agents
|
||||
self.spawned_agents: all agents already spawned in sim
|
||||
self.agent_pos: connects agent_id to spawn_index
|
||||
self.rng: random number generator object
|
||||
"""
|
||||
|
||||
self.spawn_area = spawn_area
|
||||
self.min_spacing = min_spacing
|
||||
self.spawn_coords: np.ndarray = np.array([])
|
||||
self.filled_coords: np.ndarray = np.array([])
|
||||
self.spawned_agents: set = set()
|
||||
self.agent_pos:dict={}
|
||||
self.rng = np.random.default_rng()
|
||||
|
||||
def generate_coords(self,max_samples:int=1000)->None:
|
||||
min_x,min_y,max_x,max_y = self.spawn_area.bounds
|
||||
points = []
|
||||
while len(points) ==0:
|
||||
x = self.rng.uniform(min_x,max_x)
|
||||
y = self.rng.uniform(min_y,max_y)
|
||||
if self.spawn_area.contains(Point(x,y)):
|
||||
points.append([x,y])
|
||||
for _ in range(max_samples):
|
||||
idx = self.rng.integers(0,len(points),endpoint=True)
|
||||
base = points[idx]
|
||||
for _ in range(25):
|
||||
angle = self.rng.uniform(0,2*np.pi)
|
||||
radius = self.rng.uniform(self.min_spacing,2*self.min_spacing)
|
||||
x = base[0]+radius*np.cos(angle)
|
||||
y = base[1]+radius*np.sin(angle)
|
||||
if not self.spawn_area.contains(Point(x,y)):
|
||||
continue
|
||||
if len(points)>0:
|
||||
tree = cKDTree(points)
|
||||
distance,_ = tree.query([[x,y]],k=1)
|
||||
if distance[0]<self.min_spacing:
|
||||
continue
|
||||
points.append([x,y])
|
||||
break
|
||||
self.spawn_coords = np.array(points)
|
||||
self.filled_coords = np.zeros(len(points),dtype=bool)
|
||||
#return points
|
||||
|
||||
|
||||
|
||||
def get_coords(self)->Tuple[float,float]|None:
|
||||
'''
|
||||
points = [
|
||||
pt for pt in self.generate_coords if pt \
|
||||
not in self.filled_coords.values()
|
||||
]
|
||||
return self.rng.choice(points) if points else None
|
||||
'''
|
||||
free_idx = np.where(~self.filled_coords)[0]
|
||||
if len(free_idx) == 0:
|
||||
return None
|
||||
idx = self.rng.choice(free_idx)
|
||||
return tuple(self.spawn_coords[idx])
|
||||
|
||||
|
||||
def spawn_agent(self,all_agents:List[AgentSetup])->AgentSetup|None:
|
||||
if len(self.spawned_agents) >= len(all_agents):
|
||||
return None
|
||||
spawn_point = self.get_coords()
|
||||
if not spawn_point:
|
||||
return None
|
||||
free_agents = [
|
||||
agent for agent in all_agents \
|
||||
if agent.id not in self.spawned_agents
|
||||
]
|
||||
if not free_agents:
|
||||
return None
|
||||
agent = self.rng.choice(free_agents)
|
||||
self.spawned_agents.add(agent.id)
|
||||
distances = np.linalg.norm(self.spawn_coords-spawn_point,axis=1)
|
||||
spawn_idx = np.argmin(distances)
|
||||
self.filled_coords[spawn_idx] = True
|
||||
self.agent_pos[agent.id] = spawn_idx
|
||||
return agent
|
||||
|
||||
def unfill_coords(self,agent_id:int)->None:
|
||||
if agent_id in self.agent_pos:
|
||||
spawn_idx = self.agent_pos[agent_id]
|
||||
self.filled_coords[spawn_idx] = False
|
||||
del self.agent_pos[agent_id]
|
||||
self.spawned_agents.discard(agent_id)
|
||||
|
||||
def get_agent_pos(self,agent_id:int)->Tuple[float,float]:
|
||||
if agent_id in self.agent_pos:
|
||||
spawn_idx = self.agent_pos[agent_id]
|
||||
return tuple(self.spawn_coords[spawn_idx])
|
||||
return (0,0)
|
||||
|
||||
def check_spawn_complete(self,all_agents:List[AgentSetup])->bool:
|
||||
return (len(self.spawned_agents)<len(all_agents) and\
|
||||
np.sum(~self.filled_coords) > 0)
|
||||
|
||||
|
||||
===================
|
||||
(simulation.py)
|
||||
===================
|
||||
|
||||
from typing import Tuple,List,Dict
|
||||
import sys
|
||||
import matplotlib
|
||||
matplotlib.use('QtAgg')
|
||||
import matplotlib.pyplot as plt
|
||||
from shapely import Polygon,Point,GeometryCollection,get_coordinates
|
||||
from shapely.plotting import plot_polygon
|
||||
import jupedsim as jps
|
||||
import numpy as np
|
||||
import pathlib
|
||||
from geometry_setup import GeometrySetup
|
||||
from spawning import SpawnManager
|
||||
from crosswalk_setup import CrosswalkStatus,CrosswalkController,CrosswalkState,CrosswalkConfig
|
||||
from agents.agent_setup import AgentConfig
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class SimulationSetup:
|
||||
simulation_time:float=200.0
|
||||
time_step:float=0.01
|
||||
max_iterations:int=50000
|
||||
trajectory_file:str="crosswalk_sim.sqlite"
|
||||
current_setup:bool=True
|
||||
trigger_dist:float=1.0
|
||||
activation_time:float=30.0
|
||||
cooldown_time:float=10.0
|
||||
min_agents_activation:int=1
|
||||
activation_delay:float=2.0
|
||||
|
||||
class CrosswalkSimulation:
|
||||
def __init__(self,config:SimulationSetup):
|
||||
self.config = config
|
||||
|
||||
print("\nInitializing Geometry...")
|
||||
self.geo = GeometrySetup(self.config.current_setup)
|
||||
self.spawn_area = self.geo.spawn()
|
||||
self.queue_area = self.geo.queue()
|
||||
self.grass_area = self.geo.grass()
|
||||
self.crosswalk_area = self.geo.crosswalk()
|
||||
self.entry_area = self.geo.entry_polygon()
|
||||
self.exit_area = self.geo.exit_polygon()
|
||||
self.walkable_area = GeometryCollection([
|
||||
self.spawn_area,
|
||||
self.queue_area,
|
||||
self.grass_area,
|
||||
self.crosswalk_area,
|
||||
]).unary_union
|
||||
print("Geometry Configuration Complete!")
|
||||
|
||||
print("\nInitializing Spawn Manager...")
|
||||
self.spawn_manager = SpawnManager(self.spawn_area,min_spacing=0.55)
|
||||
self.spawn_manager.generate_coords()
|
||||
print("Spawn Manager Setup Complete!")
|
||||
|
||||
print("\nInitializing Crosswalk Controller...")
|
||||
self.crosswalk_controller = CrosswalkController(
|
||||
CrosswalkConfig(
|
||||
trigger_dist=self.config.trigger_dist,
|
||||
activation_time=self.config.activation_time,
|
||||
cooldown_time=self.config.cooldown_time,
|
||||
min_agents_activation=self.config.min_agents_activation,
|
||||
activation_delay=self.config.activation_delay,
|
||||
crosswalk_area=self.crosswalk_area,
|
||||
trigger_area=self.entry_area
|
||||
),
|
||||
self.config.current_setup
|
||||
)
|
||||
print("Crosswalk Controller Setup Complete!")
|
||||
|
||||
print("\nInitializing Agent Setup...")
|
||||
self.all_agents, pop_list = AgentConfig()
|
||||
self.total_agents = len(self.all_agents)
|
||||
print(f"Created {self.total_agents} Agents...")
|
||||
print("Agent Setup Complete!")
|
||||
|
||||
print("\nInitializing JuPedSim Model...")
|
||||
self.trajectory_file = self.config.trajectory_file
|
||||
self.simulation = jps.Simulation(
|
||||
model=jps.CollisionFreeSpeedModel(),
|
||||
geometry=self.walkable_area,
|
||||
trajectory_writer=jps.SqliteTrajectoryWriter(
|
||||
output_file=pathlib.Path(self.trajectory_file)
|
||||
),
|
||||
dt=self.config.time_step
|
||||
)
|
||||
self.journey_setup()
|
||||
self.jps_agent_ids = {}
|
||||
# unsure whether these are necessary
|
||||
#
|
||||
#self.agent_targets = {}
|
||||
#self.active_agents = {}
|
||||
self.iteration_count = 0
|
||||
self.current_time = 0.0
|
||||
print(f"\nJuPedSim Model Initialized with:")
|
||||
print(f"\tTime Step: {self.config.time_step} s")
|
||||
print(f"\tMax Iterations: {self.config.max_iterations}")
|
||||
print(f"\tCrosswalk Activation Length: {self.config.activation_time} s")
|
||||
print(f"\tCrosswalk Cooldown Length: {self.config.cooldown_time} s")
|
||||
|
||||
|
||||
def journey_setup(self):
|
||||
self.queue_waiting_coords = self.waiting_coords(
|
||||
self.queue_area,self.spawn_manager.min_spacing
|
||||
)
|
||||
self.queue_stage_id = self.simulation.add_waiting_set_stage(
|
||||
self.queue_waiting_coords
|
||||
)
|
||||
self.queue_stage = self.simulation.get_stage(self.queue_stage_id)
|
||||
self.queue_stage.state = jps.WaitingSetState.ACTIVE
|
||||
self.crosswalk_entry_id = self.simulation.add_waypoint_stage(
|
||||
self.entry_area,
|
||||
self.spawn_manager.min_spacing
|
||||
)
|
||||
self.crosswalk_exit_id = self.simulation.add_waypoint_stage(
|
||||
self.exit_area,
|
||||
self.spawn_manager.min_spacing
|
||||
)
|
||||
self.journey = jps.JourneyDescription([
|
||||
self.queue_stage_id,
|
||||
self.crosswalk_entry_id,
|
||||
self.crosswalk_exit_id,
|
||||
])
|
||||
self.journey.set_transition_for_stage(
|
||||
self.queue_stage_id,
|
||||
jps.Transition.create_fixed_transition(
|
||||
self.crosswalk_entry_id
|
||||
))
|
||||
self.journey.set_transition_for_stage(
|
||||
self.crosswalk_entry_id,
|
||||
jps.Transition.create_fixed_transition(
|
||||
self.crosswalk_exit_id
|
||||
))
|
||||
self.journey_id = self.simulation.add_journey(
|
||||
self.journey)
|
||||
|
||||
def waiting_coords(self,area:Polygon,spacing:float)->List[Tuple[float,float]]:
|
||||
min_x,min_y,max_x,max_y = area.bounds
|
||||
points = []
|
||||
x = (min_x+spacing)/2
|
||||
while x<max_x:
|
||||
y = (min_y+spacing)/2
|
||||
while y < max_y:
|
||||
if area.contains(Point(x, y)):
|
||||
points.append((x,y))
|
||||
y += spacing
|
||||
x += spacing
|
||||
return points if points else [(min_x+0.5, min_y+0.5)]
|
||||
|
||||
def run(self,max_iterations:int):
|
||||
print("\n\nStarting Simulation")
|
||||
print("Target Agents: {len(self.all_agents)}")
|
||||
while self.iteration_count < max_iterations:
|
||||
if self.spawn_manager.check_spawn_complete(self.all_agents):
|
||||
new_agent = self.spawn_manager.spawn_agent(self.all_agents)
|
||||
if new_agent:
|
||||
jps_agent_params = jps.CollisionFreeSpeedModelAgentParameters(
|
||||
journey_id=self.journey_id,
|
||||
stage_id=self.queue_stage_id,
|
||||
position=self.spawn_manager.get_agent_pos(new_agent.id),
|
||||
v0=new_agent.speed,
|
||||
radius=new_agent.radius
|
||||
)
|
||||
jps_agent_id = self.simulation.add_agent(jps_agent_params)
|
||||
self.jps_agent_ids[new_agent.id] = jps_agent_id
|
||||
# unsure whether this is necessary
|
||||
#
|
||||
# self.agent_targets[new_agent.id] = None
|
||||
print(f"Iter {self.iteration_count:05d}: Spawned agent {new_agent.id} (JPS-ID: {jps_agent_id})")
|
||||
current_agent_pos = {}
|
||||
for spawn_id,jps_id in self.jps_agent_ids.items():
|
||||
agent = self.simulation.agent(jps_id)
|
||||
current_agent_pos[spawn_id] = (agent.position[0],agent.position[1])
|
||||
crosswalk_state = self.crosswalk_controller.update(
|
||||
current_agent_pos,self.config.time_step,self.current_time
|
||||
)
|
||||
if crosswalk_state.is_active:
|
||||
if self.queue_stage.stage != jps.WaitingSetState.INACTIVE:
|
||||
self.queue_stage.stage = jps.WaitingSetState.INACTIVE
|
||||
print(f"Iter {self.iteration_count:05d}: Crosswalk ACTIVATED, releasing queue.")
|
||||
else:
|
||||
if self.queue_stage.stage != jps.WaitingSetState.ACTIVE:
|
||||
self.queue_stage.stage = jps.WaitingSetState.INACTIVE
|
||||
print(f"Iter {self.iteration_count:05d}: Crosswalk INACTIVE, holding agents.")
|
||||
self.simulation.iterate()
|
||||
self.current_time += self.config.time_step
|
||||
self.iteration_count +=1
|
||||
agents_to_remove = []
|
||||
for spawn_id, jps_id in list(self.jps_agent_ids.items()):
|
||||
try:
|
||||
_ = self.simulation.agent(jps_id)
|
||||
except RuntimeError:
|
||||
agents_to_remove.append(spawn_id)
|
||||
self.spawn_manager.unfill_coords(spawn_id)
|
||||
for spawn_id in agents_to_remove:
|
||||
del self.jps_agent_ids[spawn_id]
|
||||
print(f"Iter {self.iteration_count:05d}: Agent {spawn_id} reached exit and was removed.")
|
||||
if (len(self.jps_agent_ids) ==0 and not self.spawn_manager.check_spawn_complete(self.all_agents)):
|
||||
print(f"\nSimulation Completed at Iteration: {self.iteration_count}")
|
||||
print(f"Total Simulation Time: {self.current_time:.2f} seconds.")
|
||||
break
|
||||
print("\n" + "="*50)
|
||||
print("Simulation finished.")
|
||||
stats = self.crosswalk_controller.get_statistics()
|
||||
print(f"Crosswalk was activated {stats['total_activations']} times.")
|
||||
print(f"Agents served by crosswalk: {stats['agents_served']}")
|
||||
print(f"Trajectory saved to: {self.trajectory_file.absolute()}")
|
||||
|
||||
|
||||
BIN
archive/source/__pycache__/config.cpython-313.pyc
Normal file
BIN
archive/source/__pycache__/config.cpython-313.pyc
Normal file
Binary file not shown.
17
archive/source/sim_agents/config.py
Normal file
17
archive/source/sim_agents/config.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
E.Drake - ENGN-2220
|
||||
|
||||
Thu Jan 22 23:48:50 2026
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).parent.parent.parent
|
||||
SOURCE_DIR = ROOT/"source"
|
||||
ARCHIVE_DIR = ROOT/"archive"
|
||||
PATH_DIR = ROOT/"path"
|
||||
AGENTS_DIR = ROOT/SOURCE_DIR/"sim_agents"
|
||||
GEO_DIR = ROOT/SOURCE_DIR/"sim_geometry"
|
||||
TEST_DIR = ROOT/SOURCE_DIR/"test"
|
||||
|
||||
|
||||
72
archive/source/sim_agents/traits.py
Normal file
72
archive/source/sim_agents/traits.py
Normal file
@@ -0,0 +1,72 @@
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
grades = {
|
||||
"Kindergarden":np.array(
|
||||
[31.43,5.65,1.21,0.24]
|
||||
),
|
||||
"Grade 1":np.array(
|
||||
[32.57,6.27,1.35,0.26]
|
||||
),
|
||||
"Grade 2":np.array(
|
||||
[34.43,6.80,1.42,0.28]
|
||||
),
|
||||
"Grade 3":np.array(
|
||||
[35.43,5.19,1.48,0.23]
|
||||
),
|
||||
"Grade 4":np.array(
|
||||
[34.86,6.77,1.58,0.26]
|
||||
),
|
||||
"Grade 5":np.array(
|
||||
[36.71,7.09,1.59,0.24]
|
||||
),
|
||||
"Grade 6":np.array(
|
||||
[37.71,6.99,1.65,0.24]
|
||||
),
|
||||
"Grade 7":np.array(
|
||||
[40.43,6.02,1.61,0.25]
|
||||
),
|
||||
"Grade 8":np.array(
|
||||
[40.43,5.50,1.66,0.24]
|
||||
),
|
||||
"Grade 9":np.array(
|
||||
[44.14,4.85,1.60,0.24]
|
||||
),
|
||||
"Grade 10":np.array(
|
||||
[46.29,6.29,1.57,0.23]
|
||||
),
|
||||
"Grade 11":np.array(
|
||||
[48.29,3.30,1.51,0.22]
|
||||
),
|
||||
"Grade 12":np.array(
|
||||
[43.71,6.02,1.54,0.23]
|
||||
)}
|
||||
|
||||
df_srs_data=pd.DataFrame({
|
||||
"Grade Level":(
|
||||
list(grades.keys())),
|
||||
"Pop Mean":[
|
||||
grades[j][0] for j in grades],
|
||||
"Pop Std Dev":[
|
||||
grades[j][1] for j in grades],
|
||||
"Speed Mean":[
|
||||
grades[j][2] for j in grades],
|
||||
"Speed Std Dev":[
|
||||
grades[j][3] for j in grades]})
|
||||
|
||||
@dataclass
|
||||
class AgentConfig:
|
||||
id:int
|
||||
grade:str
|
||||
door:str
|
||||
speed:float
|
||||
radius:float
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
91
archive/source/sim_agents/traits_current.py
Normal file
91
archive/source/sim_agents/traits_current.py
Normal file
@@ -0,0 +1,91 @@
|
||||
import numpy as np
|
||||
from dataclasses import dataclass
|
||||
from typing import List, Dict, Optional
|
||||
from collections import defaultdict
|
||||
|
||||
##https://censusatschool.ca/data-results/2017-2018/average-height-by-age/
|
||||
@dataclass
|
||||
class AgentConfig:
|
||||
id:int
|
||||
grade:str
|
||||
door:int
|
||||
speed:float
|
||||
radius:float
|
||||
|
||||
def agent_params():
|
||||
gr_data = {
|
||||
# [0]: number of students
|
||||
# [1]: door number
|
||||
# [2]: speed mean
|
||||
# [3]: speed standard deviation
|
||||
# [4]: radius mean
|
||||
"Kindergarden":np.array(
|
||||
[34,0,1.21,0.24,0.407]
|
||||
),
|
||||
"Grade 1":np.array(
|
||||
[26,0,1.35,0.26,0.407]
|
||||
),
|
||||
"Grade 2":np.array(
|
||||
[42,0,1.42,0.28,0.407]
|
||||
),
|
||||
"Grade 3":np.array(
|
||||
[39,0,1.48,0.23,0.407]
|
||||
),
|
||||
"Grade 4":np.array(
|
||||
[30,1,1.58,0.26,0.417]
|
||||
),
|
||||
"Grade 5":np.array(
|
||||
[43,1,1.59,0.24,0.434]
|
||||
),
|
||||
"Grade 6":np.array(
|
||||
[29,1,1.65,0.24,0.454]
|
||||
),
|
||||
"Grade 7":np.array(
|
||||
[45,2,1.61,0.25,0.471]
|
||||
),
|
||||
"Grade 8":np.array(
|
||||
[36,2,1.66,0.24,0.488]
|
||||
),
|
||||
"Grade 9":np.array(
|
||||
[44,2,1.60,0.24,0.500]
|
||||
),
|
||||
"Grade 10":np.array(
|
||||
[36,2,1.57,0.23,0.507]
|
||||
),
|
||||
"Grade 11":np.array(
|
||||
[54,2,1.51,0.22,0.515]
|
||||
),
|
||||
"Grade 12":np.array(
|
||||
[46,2,1.54,0.23,0.520]
|
||||
)}
|
||||
agent_id = 1
|
||||
rng = np.random.default_rng(seed=42)
|
||||
all_agents = []
|
||||
gr_agents = []
|
||||
for grade in gr_data:
|
||||
for num in range(int(gr_data[grade][0])):
|
||||
door = gr_data[grade][1]
|
||||
speed = rng.normal(
|
||||
loc=gr_data[grade][2],
|
||||
scale=gr_data[grade][3],
|
||||
size=1)
|
||||
radius = gr_data[grade][4]
|
||||
gr_agents.append(
|
||||
AgentConfig(
|
||||
id=agent_id,
|
||||
grade=grade,
|
||||
door=door,
|
||||
speed=speed,
|
||||
radius = radius
|
||||
))
|
||||
agent_id += 1
|
||||
all_agents.append(gr_agents)
|
||||
gr_agents = []
|
||||
#for grade in all_agents:
|
||||
# for agent in grade:
|
||||
# print(agent)
|
||||
return all_agents
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
archive/source/sim_geometry/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
archive/source/sim_geometry/__pycache__/__init__.cpython-313.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
17
archive/source/sim_geometry/config.py
Normal file
17
archive/source/sim_geometry/config.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
E.Drake - ENGN-2220
|
||||
|
||||
Thu Jan 22 23:48:50 2026
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).parent.parent.parent
|
||||
SOURCE_DIR = ROOT/"source"
|
||||
ARCHIVE_DIR = ROOT/"archive"
|
||||
PATH_DIR = ROOT/"path"
|
||||
AGENTS_DIR = ROOT/SOURCE_DIR/"sim_agents"
|
||||
GEO_DIR = ROOT/SOURCE_DIR/"sim_geometry"
|
||||
TEST_DIR = ROOT/SOURCE_DIR/"test"
|
||||
|
||||
|
||||
147
archive/source/sim_geometry/geo_current.py
Normal file
147
archive/source/sim_geometry/geo_current.py
Normal file
@@ -0,0 +1,147 @@
|
||||
import sys
|
||||
import matplotlib
|
||||
matplotlib.use('QtAgg')
|
||||
import matplotlib.pyplot as plt
|
||||
from shapely import Polygon
|
||||
from shapely.plotting import plot_polygon
|
||||
|
||||
def geo_current(full_plot:bool=False):
|
||||
A_crosswalk=Polygon([
|
||||
(-1,1.499),
|
||||
(-1,3.327),
|
||||
(0,3.327),
|
||||
(11.214, 3.327),
|
||||
(11.214,1.499),
|
||||
(0,1.499)
|
||||
])
|
||||
B_queue=Polygon([
|
||||
(11.214, 0),
|
||||
(22.163, 0),
|
||||
(22.163, 4.826),
|
||||
(11.214, 4.826)
|
||||
])
|
||||
C_road_adj_path=Polygon([
|
||||
(21.787,4.826),
|
||||
(24.214,4.826),
|
||||
(24.214,40.431),
|
||||
(29.179,40.431),
|
||||
(29.179,42.511),
|
||||
(24.214,42.511),
|
||||
(21.787,42.511)
|
||||
])
|
||||
D_path_k_3=Polygon([
|
||||
(26.45,42.511),
|
||||
(26.45,52.84),
|
||||
(26.45,53.84),
|
||||
(29.179,53.84),
|
||||
(29.179,52.84),
|
||||
(29.179,42.511)
|
||||
])
|
||||
E_path_4_6=Polygon([
|
||||
(29.179,42.511),
|
||||
(54.351,42.511),
|
||||
(60.406,48.842),
|
||||
(60.406,51.22),
|
||||
(60.406,52.22),
|
||||
(63.49,52.22),
|
||||
(63.49,51.22),
|
||||
(63.49,47.866),
|
||||
(56.381,40.431),
|
||||
(29.179,40.431)
|
||||
])
|
||||
F_path_7_12=Polygon([
|
||||
(22.163, 0),
|
||||
(39.227, 5.516),
|
||||
(39.631, 4.267),
|
||||
(39.939,3.315),
|
||||
(45.099,4.983),
|
||||
(44.792,5.935),
|
||||
(43.169,10.954),
|
||||
(24.214,4.826),
|
||||
(22.163,4.826)
|
||||
])
|
||||
G_extended_queue=Polygon([
|
||||
(11.214,0),
|
||||
(12.924,0),
|
||||
(12.924,-4.569),
|
||||
(11.214,-4.569)
|
||||
])
|
||||
H_angled_path=Polygon([
|
||||
(21.787,13.192),
|
||||
(21.787,10.527),
|
||||
(17,4.826),
|
||||
(14.767,4.826)
|
||||
])
|
||||
enter_k_3=Polygon([
|
||||
(26.45,52.84),
|
||||
(29.179,52.84),
|
||||
(29.179,53.84),
|
||||
(26.45,53.84)
|
||||
])
|
||||
enter_4_6=Polygon([
|
||||
(60.406,51.22),
|
||||
(60.406,52.22),
|
||||
(63.49,52.22),
|
||||
(63.49,51.22)
|
||||
])
|
||||
enter_7_12=Polygon([
|
||||
(39.631, 4.267),
|
||||
(39.939,3.315),
|
||||
(45.099,4.983),
|
||||
(44.792,5.935)
|
||||
])
|
||||
exit_polygon=Polygon([
|
||||
(0,1.499),
|
||||
(0,3.327),
|
||||
(-1,3.327),
|
||||
(-1,1.499)
|
||||
])
|
||||
|
||||
geometry = (
|
||||
A_crosswalk.union(
|
||||
B_queue).union(
|
||||
C_road_adj_path).union(
|
||||
D_path_k_3).union(
|
||||
E_path_4_6).union(
|
||||
F_path_7_12).union(
|
||||
G_extended_queue).union(
|
||||
H_angled_path)
|
||||
)
|
||||
doors = [
|
||||
enter_k_3,
|
||||
enter_4_6,
|
||||
enter_7_12,
|
||||
exit_polygon
|
||||
]
|
||||
|
||||
if full_plot is False:
|
||||
plot_polygon(A_crosswalk,color="black",add_points=False)
|
||||
plot_polygon(B_queue,color="black",add_points=False)
|
||||
plot_polygon(C_road_adj_path, color="blue",add_points=False)
|
||||
plot_polygon(D_path_k_3, color="blue",add_points=False)
|
||||
plot_polygon(E_path_4_6, color="blue",add_points=False)
|
||||
plot_polygon(F_path_7_12, color="blue",add_points=False)
|
||||
plot_polygon(G_extended_queue, color="black",add_points=False)
|
||||
plot_polygon(H_angled_path, color="black",add_points=False)
|
||||
|
||||
plot_polygon(enter_k_3, color="darkgreen",add_points=False)
|
||||
plot_polygon(enter_4_6, color="darkgreen",add_points=False)
|
||||
plot_polygon(enter_7_12, color="darkgreen",add_points=False)
|
||||
|
||||
plot_polygon(exit_polygon, color="orangered",add_points=False)
|
||||
|
||||
else:
|
||||
plot_polygon(geometry,color="blue",add_points=False)
|
||||
plot_polygon(enter_k_3,color="red",add_points=False)
|
||||
plot_polygon(enter_4_6,color="red",add_points=False)
|
||||
plot_polygon(enter_7_12,color="red",add_points=False)
|
||||
|
||||
return geometry, doors
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from PyQt6 import QtWidgets
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
geometry,doors = geo_current(True)
|
||||
plt.show(block=False)
|
||||
sys.exit(app.exec())
|
||||
71
archive/source/test/_1_testing.py
Normal file
71
archive/source/test/_1_testing.py
Normal file
@@ -0,0 +1,71 @@
|
||||
"""
|
||||
E.Drake - ENGN 2220
|
||||
Jan 21, 2026
|
||||
|
||||
TESTING GEOMETRY
|
||||
"""
|
||||
import matplotlib
|
||||
matplotlib.use('QtAgg')
|
||||
import matplotlib.pyplot as plt
|
||||
from PyQt6 import QtWidgets
|
||||
import sys
|
||||
import config
|
||||
#print(str(config.GEO_DIR))
|
||||
sys.path.insert(0,str(config.GEO_DIR))
|
||||
sys.path.insert(0,str(config.PATH_DIR))
|
||||
from geo_current import geo_current
|
||||
|
||||
import jupedsim as jps
|
||||
from matplotlib.patches import Circle
|
||||
|
||||
def main_loop():
|
||||
geometry,doors = geo_current(full_plot = True)
|
||||
dk_3, d4_6, d7_12, d_exit = doors
|
||||
|
||||
model = jps.CollisionFreeSpeedModel()
|
||||
sim = jps.Simulation(model=model,geometry=geometry)
|
||||
exit_id = sim.add_exit_stage(d_exit)
|
||||
journey = jps.JourneyDescription([exit_id])
|
||||
journey_id = sim.add_journey(journey)
|
||||
total_sim_time = 60.0
|
||||
|
||||
doorways = {
|
||||
0: dk_3,
|
||||
1: d4_6,
|
||||
2: d7_12,
|
||||
}
|
||||
|
||||
# Spawn times for each door (seconds)
|
||||
spawn_schedule = {
|
||||
"door_1": [0.0, 5.0, 10.0], # Agents at t=0, 5, 10
|
||||
"door_2": [2.0, 7.0],
|
||||
"door_3": [3.0],
|
||||
}
|
||||
events = []
|
||||
for door_name, times in spawn_schedule.items():
|
||||
for t in times:
|
||||
events.append((t, doors[door_name]))
|
||||
events.sort(key=lambda x: x[0])
|
||||
|
||||
event_index = 0
|
||||
while sim.elapsed_time() < total_sim_time:
|
||||
current_time = sim.elapsed_time()
|
||||
# Process all events whose time has come
|
||||
while event_index < len(events) and events[event_index][0] <= current_time:
|
||||
_, door_pos = events[event_index]
|
||||
agent_params = jps.CollisionFreeSpeedModelAgentParameters(
|
||||
position=door_pos,
|
||||
journey_id=journey_id,
|
||||
stage_id=exit_id,
|
||||
radius=0.2,
|
||||
)
|
||||
sim.add_agent(agent_params)
|
||||
event_index += 1
|
||||
sim.iterate()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
main_loop()
|
||||
plt.show(block=False)
|
||||
sys.exit(app.exec())
|
||||
386
archive/source/test/_2_testing.py
Normal file
386
archive/source/test/_2_testing.py
Normal file
@@ -0,0 +1,386 @@
|
||||
import jupedsim as jps
|
||||
import shapely
|
||||
from dataclasses import dataclass
|
||||
from typing import List, Dict, Tuple
|
||||
import numpy as np
|
||||
import matplotlib
|
||||
matplotlib.use('QtAgg')
|
||||
import matplotlib.pyplot as plt
|
||||
from PyQt6 import QtWidgets
|
||||
import sys
|
||||
import config
|
||||
sys.path.insert(0,str(config.GEO_DIR))
|
||||
from geo_current import geo_current
|
||||
|
||||
@dataclass
|
||||
class AgentSetup:
|
||||
id:int
|
||||
grade:str
|
||||
door:int
|
||||
speed:float
|
||||
radius:float
|
||||
spawn:Tuple[float,float]
|
||||
|
||||
@dataclass
|
||||
class SimSetup:
|
||||
doorways:Dict[int,shapely.Polygon]
|
||||
grades:Dict[str,Dict]
|
||||
min_spacing:float=0.6
|
||||
total_sim_time:float=200.0
|
||||
door_capacity:int=10
|
||||
walkable_area:shapely.Polygon
|
||||
exit_area:shapely.Polygon
|
||||
|
||||
class EvacSim:
|
||||
def __init__(self,setup:SimSetup):
|
||||
self.setup = setup
|
||||
self.all_agents = []
|
||||
self.all_spawn_events = []
|
||||
self.simulation = None
|
||||
self.exit_id = None
|
||||
self.doorway_system = {}
|
||||
|
||||
def run(self):
|
||||
self.all_agents = self.agent_params()
|
||||
self.setup_sim_env()
|
||||
self.spawn_events = self.get_spawn_events()
|
||||
self.run_sim()
|
||||
|
||||
def agent_params(self)->List[AgentSetup]:
|
||||
agent_id = 1
|
||||
rng = np.random.default_rng(seed=42)
|
||||
all_agents = []
|
||||
for grade in self.setup.grades.keys():
|
||||
spawn_time = rng.uniform(0.0,115.0)
|
||||
self.setup.grades[grade]["Spawn Time"] = spawn_time
|
||||
gr_agent_num = int(self.setup.grades[grade]["Pop Current"])
|
||||
door = int(self.setup.grades[grade]["Door"])
|
||||
current_agent = 0
|
||||
for num in range(gr_agent_num):
|
||||
speed = rng.normal(
|
||||
loc=self.setup.grades[grade]["Speed Mean"],
|
||||
scale=self.setup.grades[grade]["Speed Std Dev"],
|
||||
size=1)
|
||||
radius = self.setup.grades[grade]["Radius"]
|
||||
new_agent = AgentSetup(
|
||||
id=agent_id,
|
||||
grade=grade,
|
||||
door=door,
|
||||
speed=speed,
|
||||
radius = radius,
|
||||
)
|
||||
all_agents.append(new_agent)
|
||||
agent_id += 1
|
||||
current_agent += 1
|
||||
return all_agents
|
||||
|
||||
def setup_sim_env(self):
|
||||
walkable_area = self.setup.walkable_area
|
||||
model = jps.CollisionFreeSpeedModel()
|
||||
self.simulation = jps.Simulation(
|
||||
model=model,geometry=walkable_area)
|
||||
self.exit_id = self.simulation.add_exit_stage(
|
||||
self.setup.exit_polygon)
|
||||
def doorway_system(self, door_id: int, door_polygon: shapely.Polygon):
|
||||
def get_waiting_area(self,door_polygon:shapely.Polygon)->shapely.Polygon:
|
||||
waiting_area = door_polygon.buffer(2.0, join_style=2)
|
||||
waiting_area = waiting_area.difference(door_polygon)
|
||||
|
||||
if waiting_area.geom_type == 'MultiPolygon':
|
||||
waiting_area = max(waiting_area.geoms, key=lambda p: p.area)
|
||||
return waiting_area
|
||||
|
||||
waiting_area = get_waiting_area(door_polygon)
|
||||
waiting_set_id = self.simulation.add_waiting_set_stage(waiting_area)
|
||||
|
||||
door_centroid = door_polygon.centroid
|
||||
queue_waypoints = [
|
||||
self.simulation.add_waypoint_stage((door_centroid.x, door_centroid.y - 1.0), 0.5),
|
||||
self.simulation.add_waypoint_stage((door_centroid.x, door_centroid.y), 0.5),
|
||||
self.simulation.add_waypoint_stage((door_centroid.x, door_centroid.y + 1.0), 0.5)
|
||||
]
|
||||
journey_stages = [waiting_set_id] + queue_waypoints + [self.exit_id]
|
||||
journey = jps.JourneyDescription(journey_stages)
|
||||
journey_id = self.simulation.add_journey(journey)
|
||||
|
||||
self.doorway_info[door_id] = {
|
||||
"waiting_area": waiting_area,
|
||||
"waiting_set_id": waiting_set_id,
|
||||
"queue_waypoints": queue_waypoints,
|
||||
"journey_id": journey_id,
|
||||
"door_polygon": door_polygon
|
||||
}
|
||||
for door_id, door_polygon in self.setup.doorways.items():
|
||||
self.doorway_system(door_id, door_polygon)
|
||||
|
||||
def get_spawn_events(self)->List[Dict]:
|
||||
events = []
|
||||
agents_by_grade = {}
|
||||
def get_spawn_point(self,door:int,num_points:int)->List[Tuple[float,float]]:
|
||||
polygon = self.setup.doorways[door]
|
||||
min_x,min_y,max_x,max_y = polygon.bounds
|
||||
points = []
|
||||
attempts = 0
|
||||
max_attempts = num_points * 100
|
||||
while len(points) < num_points and attempts < max_attempts:
|
||||
x = random.uniform(min_x, max_x)
|
||||
y = random.uniform(min_y, max_y)
|
||||
point = shapely.Point(x, y)
|
||||
if polygon.contains(point):
|
||||
too_close = False
|
||||
for existing in points:
|
||||
if np.sqrt((x - existing[0])**2 + (y - existing[1])**2) < self.setup.min_spacing:
|
||||
too_close = True
|
||||
break
|
||||
if not too_close:
|
||||
points.append((x, y))
|
||||
attempts += 1
|
||||
return points[:num_points]
|
||||
for agent in self.all_agents:
|
||||
for grade_name, grade_info in self.setup.grades.items():
|
||||
if agent.door == grade_info["Door"]:
|
||||
if grade_name not in agents_by_grade:
|
||||
agents_by_grade[grade_name] = []
|
||||
agents_by_grade[grade_name].append(agent)
|
||||
break
|
||||
for grade_name, grade_info in self.setup.grades.items():
|
||||
door_id = grade_info["Door"]
|
||||
spawn_time = grade_info["Spawn Time"]
|
||||
grade_agents = agents_by_group.get(grade_name, [])
|
||||
if not grade_agents:
|
||||
continue
|
||||
door_polygon = self.setup.doorways[door_id]
|
||||
spawn_positions = self.get_spawn_point(
|
||||
door_polygon,
|
||||
len(group_agents))
|
||||
for agent, position in zip(group_agents, spawn_positions):
|
||||
events.append({
|
||||
"time": spawn_time,
|
||||
"agent": agent,
|
||||
"position": position,
|
||||
"grade": grade_name,
|
||||
"door": door_id
|
||||
})
|
||||
events.sort(key=lambda x: x["time"])
|
||||
return events
|
||||
|
||||
def run_sim(self):
|
||||
spawned_event_indices = set()
|
||||
agents_in_door_area = {door_id: 0 for door_id in self.config.door_polygons.keys()}
|
||||
event_index = 0
|
||||
|
||||
print("\nStarting Simulation Loop...")
|
||||
print(f"Total Simulation Time: {self.config.total_simulation_time}s")
|
||||
print(f"Door Capacity: {self.config.door_capacity} agents per door")
|
||||
|
||||
while self.simulation.elapsed_time() < self.config.total_simulation_time:
|
||||
current_time = self.simulation.elapsed_time()
|
||||
self._process_spawn_events(
|
||||
current_time,
|
||||
event_index,
|
||||
spawned_event_indices,
|
||||
agents_in_door_area)
|
||||
while (event_index < len(self.spawn_events) and \
|
||||
self.spawn_events[event_index]["time"] <= current_time and \
|
||||
event_index in spawned_event_indices):
|
||||
event_index += 1
|
||||
self.simulation.iterate()
|
||||
|
||||
print(f"\nSimulation completed at {self.simulation.elapsed_time():.2f} seconds")
|
||||
|
||||
def process_spawn_events(
|
||||
self,
|
||||
current_time: float,
|
||||
event_index: int,
|
||||
spawned_events: set,
|
||||
agents_in_door_area: Dict
|
||||
):
|
||||
while (event_idx < len(self.spawn_events) and \
|
||||
self.spawn_events[event_idx]["time"] <= current_time and \
|
||||
event_idx not in spawned_events):
|
||||
event = self.spawn_events[event_idx]
|
||||
door_id = event["door"]
|
||||
agent = event["agent"]
|
||||
if agents_in_door_area[door_id] < self.setup.door_capacity:
|
||||
self.spawn_agent(event,door_id,agent)
|
||||
agents_in_door_area[door_id] += 1
|
||||
spawned_events.add(event_idx)
|
||||
event_index += 1
|
||||
|
||||
def spawn_agent(self,event:Dict,door_id:int,agent:AgentSetup):
|
||||
journey_id = self.doorway_systems[door_id]["journey_id"]
|
||||
|
||||
agent_params = jps.CollisionFreeSpeedModelAgentParameters(
|
||||
position=event["position"],
|
||||
journey_id=journey_id,
|
||||
stage_id=self.doorway_system[door_id]["waiting_set_id"],
|
||||
radius=agent.radius,
|
||||
v0=agent.speed,
|
||||
)
|
||||
|
||||
agent_id = self.simulation.add_agent(agent_params)
|
||||
|
||||
# Optional: Log spawning
|
||||
if agent_id % 50 == 0: # Log every 50th agent
|
||||
print(f" Spawned agent {agent_id} (group: {event['group']}, door: {door_id})")
|
||||
|
||||
|
||||
def start_sim_run():
|
||||
print("Evacuation Simulation")
|
||||
print("-" * 40)
|
||||
geometry,[door0,door1,door2,exit_door] = geo_current(full_plot = True)
|
||||
door_polygons = {
|
||||
1: door0,
|
||||
2: door1,
|
||||
3: door2
|
||||
}
|
||||
grade_data = {
|
||||
"Kindergarden":{
|
||||
"Door":0,
|
||||
"Pop Current":34,
|
||||
"Pop Mean":31.43,
|
||||
"Pop Std Dev":5.65,
|
||||
"Speed Mean":1.21,
|
||||
"Speed Std Dev":0.24,
|
||||
"Radius":0.407,
|
||||
"Spawn Time":None
|
||||
},
|
||||
"Grade 1":{
|
||||
"Door":0,
|
||||
"Pop Current":26,
|
||||
"Pop Mean":32.57,
|
||||
"Pop Std Dev":6.27,
|
||||
"Speed Mean":1.35,
|
||||
"Speed Std Dev":0.26,
|
||||
"Radius":0.407,
|
||||
"Spawn Time":None
|
||||
},
|
||||
"Grade 2":{
|
||||
"Door":0,
|
||||
"Pop Current":42,
|
||||
"Pop Mean":34.43,
|
||||
"Pop Std Dev":6.80,
|
||||
"Speed Mean":1.42,
|
||||
"Speed Std Dev":0.28,
|
||||
"Radius":0.407,
|
||||
"Spawn Time":None
|
||||
},
|
||||
"Grade 3":{
|
||||
"Door":0,
|
||||
"Pop Current":39,
|
||||
"Pop Mean":35.43,
|
||||
"Pop Std Dev":5.19,
|
||||
"Speed Mean":1.48,
|
||||
"Speed Std Dev":0.23,
|
||||
"Radius":0.407,
|
||||
"Spawn Time":None
|
||||
},
|
||||
"Grade 4":{
|
||||
"Door":1,
|
||||
"Pop Current":30,
|
||||
"Pop Mean":34.86,
|
||||
"Pop Std Dev":6.77,
|
||||
"Speed Mean":1.58,
|
||||
"Speed Std Dev":0.26,
|
||||
"Radius":0.417,
|
||||
"Spawn Time":None
|
||||
},
|
||||
"Grade 5":{
|
||||
"Door":1,
|
||||
"Pop Current":43,
|
||||
"Pop Mean":36.71,
|
||||
"Pop Std Dev":7.09,
|
||||
"Speed Mean":1.59,
|
||||
"Speed Std Dev":0.24,
|
||||
"Radius":0.434,
|
||||
"Spawn Time":None
|
||||
},
|
||||
"Grade 6":{
|
||||
"Door":1,
|
||||
"Pop Current":29,
|
||||
"Pop Mean":37.71,
|
||||
"Pop Std Dev":6.99,
|
||||
"Speed Mean":1.65,
|
||||
"Speed Std Dev":0.24,
|
||||
"Radius":0.454,
|
||||
"Spawn Time":None
|
||||
},
|
||||
"Grade 7":{
|
||||
"Door":2,
|
||||
"Pop Current":45,
|
||||
"Pop Mean":40.43,
|
||||
"Pop Std Dev":6.02,
|
||||
"Speed Mean":1.61,
|
||||
"Speed Std Dev":0.25,
|
||||
"Radius":0.471,
|
||||
"Spawn Time":None
|
||||
},
|
||||
"Grade 8":{
|
||||
"Door":2,
|
||||
"Pop Current":36,
|
||||
"Pop Mean":40.43,
|
||||
"Pop Std Dev":5.50,
|
||||
"Speed Mean":1.66,
|
||||
"Speed Std Dev":0.24,
|
||||
"Radius":0.488,
|
||||
"Spawn Time":None
|
||||
},
|
||||
"Grade 9":{
|
||||
"Door":2,
|
||||
"Pop Current":44,
|
||||
"Pop Mean":44.14,
|
||||
"Pop Std Dev":4.85,
|
||||
"Speed Mean":1.60,
|
||||
"Speed Std Dev":0.24,
|
||||
"Radius":0.500,
|
||||
"Spawn Time":None
|
||||
},
|
||||
"Grade 10":{
|
||||
"Door":2,
|
||||
"Pop Current":36,
|
||||
"Pop Mean":46.29,
|
||||
"Pop Std Dev":6.29,
|
||||
"Speed Mean":1.57,
|
||||
"Speed Std Dev":0.23,
|
||||
"Radius":0.507,
|
||||
"Spawn Time":None
|
||||
},
|
||||
"Grade 11":{
|
||||
"Door":2,
|
||||
"Pop Current":54,
|
||||
"Pop Mean":48.29,
|
||||
"Pop Std Dev":3.30,
|
||||
"Speed Mean":1.51,
|
||||
"Speed Std Dev":0.22,
|
||||
"Radius":0.515,
|
||||
"Spawn Time":None
|
||||
},
|
||||
"Grade 12":{
|
||||
"Door":2,
|
||||
"Pop Current":46,
|
||||
"Pop Mean":43.71,
|
||||
"Pop Std Dev":6.02,
|
||||
"Speed Mean":1.54,
|
||||
"Speed Std Dev":0.23,
|
||||
"Radius":0.520,
|
||||
"Spawn Time":None
|
||||
}}
|
||||
|
||||
config = SimSetup(
|
||||
doorways=door_polygons,
|
||||
grades=grade_data,
|
||||
total_simulation_time=180.0,
|
||||
door_capacity=10,
|
||||
walkable_area=geometry,
|
||||
exit_area=exit_door
|
||||
)
|
||||
|
||||
sim = EvacSim(config)
|
||||
return sim.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
simulation = start_sim_run()
|
||||
print(f"\nFinal simulation state:")
|
||||
print(f" Elapsed time: {simulation.elapsed_time():.2f}s")
|
||||
|
||||
BIN
archive/source/test/__pycache__/config.cpython-310.pyc
Normal file
BIN
archive/source/test/__pycache__/config.cpython-310.pyc
Normal file
Binary file not shown.
BIN
archive/source/test/__pycache__/config.cpython-312.pyc
Normal file
BIN
archive/source/test/__pycache__/config.cpython-312.pyc
Normal file
Binary file not shown.
BIN
archive/source/test/__pycache__/config.cpython-313.pyc
Normal file
BIN
archive/source/test/__pycache__/config.cpython-313.pyc
Normal file
Binary file not shown.
388
archive/source/test/_test_example_.py
Normal file
388
archive/source/test/_test_example_.py
Normal file
@@ -0,0 +1,388 @@
|
||||
import jupedsim as jps
|
||||
import shapely
|
||||
import random
|
||||
from dataclasses import dataclass
|
||||
from typing import List, Dict, Tuple, Optional
|
||||
import numpy as np
|
||||
|
||||
@dataclass
|
||||
class AgentConfig:
|
||||
id: int
|
||||
grade: str
|
||||
door: int
|
||||
speed: float
|
||||
radius: float
|
||||
|
||||
@dataclass
|
||||
class SimulationConfig:
|
||||
door_polygons: Dict[int, shapely.Polygon]
|
||||
groups: Dict[str, Dict]
|
||||
total_simulation_time: float = 300.0
|
||||
door_capacity: int = 10
|
||||
min_spacing: float = 0.6
|
||||
|
||||
"""
|
||||
def __post_init__(self):
|
||||
'''Set default walkable area and exit polygon if not provided.'''
|
||||
if self.walkable_area_coords is None:
|
||||
self.walkable_area_coords = [(0, 0), (50, 0), (50, 30), (0, 30)]
|
||||
if self.exit_polygon_coords is None:
|
||||
self.exit_polygon_coords = [(45, 10), (48, 10), (48, 20), (45, 20)]
|
||||
"""
|
||||
|
||||
class PedestrianSimulation:
|
||||
"""
|
||||
Main class for running pedestrian simulations with door queues and scheduled spawning.
|
||||
|
||||
Architecture Flow:
|
||||
1. Configuration Setup
|
||||
↓
|
||||
2. Agent Configuration Generation
|
||||
↓
|
||||
3. Geometry Preparation (Walkable area, Doors, Exit)
|
||||
↓
|
||||
4. Door System Setup (Waiting areas, Queues, Journeys)
|
||||
↓
|
||||
5. Spawn Event Precomputation
|
||||
↓
|
||||
6. Simulation Execution with Dynamic Spawning
|
||||
↓
|
||||
7. Results Analysis/Visualization
|
||||
"""
|
||||
|
||||
def __init__(self, config: SimulationConfig):
|
||||
self.config = config
|
||||
self.simulation = None
|
||||
self.door_systems = {}
|
||||
self.all_agents = []
|
||||
self.spawn_events = []
|
||||
self.exit_id = None
|
||||
|
||||
def run(self) -> jps.Simulation:
|
||||
"""
|
||||
Main orchestrator: Run the complete simulation.
|
||||
|
||||
Steps:
|
||||
1. Create agent configurations
|
||||
2. Setup simulation environment
|
||||
3. Precompute spawn events
|
||||
4. Execute simulation with dynamic spawning
|
||||
5. Return completed simulation object
|
||||
"""
|
||||
print("=" * 60)
|
||||
print("PEDESTRIAN SIMULATION STARTING")
|
||||
print("=" * 60)
|
||||
|
||||
self.all_agents = self._create_agent_configurations()
|
||||
print(f"Created {len(self.all_agents)} agent configurations")
|
||||
|
||||
self._setup_simulation_environment()
|
||||
print("Simulation environment setup complete")
|
||||
|
||||
self.spawn_events = self._precompute_spawn_events()
|
||||
print(f"Precomputed {len(self.spawn_events)} spawn events")
|
||||
|
||||
self._execute_simulation()
|
||||
print("Simulation execution complete")
|
||||
return self.simulation
|
||||
|
||||
def _create_agent_configurations(self) -> List[AgentConfig]:
|
||||
"""Create AgentConfig objects for all agents in all groups."""
|
||||
all_agents = []
|
||||
agent_id = 0
|
||||
|
||||
for group_name, group_info in self.config.groups.items():
|
||||
door = group_info["door"]
|
||||
size = group_info["size"]
|
||||
|
||||
for i in range(size):
|
||||
grade = random.choice(["A", "B", "C", "D", "F"])
|
||||
speed = random.uniform(1.0, 1.5) # m/s
|
||||
radius = random.uniform(0.2, 0.3) # meters
|
||||
|
||||
all_agents.append(AgentConfig(
|
||||
id=agent_id,
|
||||
grade=grade,
|
||||
door=door,
|
||||
speed=speed,
|
||||
radius=radius
|
||||
))
|
||||
agent_id += 1
|
||||
|
||||
return all_agents
|
||||
# includes id, grade, door, speed, and radius
|
||||
|
||||
def _generate_spawn_points(self, polygon: shapely.Polygon,num_points: int) -> List[Tuple[float, float]]:
|
||||
"""Generate non-overlapping spawn points within a polygon."""
|
||||
points = []
|
||||
min_x, min_y, max_x, max_y = polygon.bounds
|
||||
|
||||
attempts = 0
|
||||
max_attempts = num_points * 100
|
||||
|
||||
while len(points) < num_points and attempts < max_attempts:
|
||||
x = random.uniform(min_x, max_x)
|
||||
y = random.uniform(min_y, max_y)
|
||||
point = shapely.Point(x, y)
|
||||
|
||||
if polygon.contains(point):
|
||||
too_close = False
|
||||
for existing in points:
|
||||
if np.sqrt((x - existing[0])**2 + (y - existing[1])**2) < self.config.min_spacing:
|
||||
too_close = True
|
||||
break
|
||||
|
||||
if not too_close:
|
||||
points.append((x, y))
|
||||
|
||||
attempts += 1
|
||||
return points[:num_points]
|
||||
# get list of spawn point tuples to provide to agents
|
||||
|
||||
def _create_waiting_area(self, door_polygon: shapely.Polygon) -> shapely.Polygon:
|
||||
"""Create a waiting area adjacent to the door polygon."""
|
||||
waiting_area = door_polygon.buffer(2.0, join_style=2)
|
||||
waiting_area = waiting_area.difference(door_polygon)
|
||||
|
||||
if waiting_area.geom_type == 'MultiPolygon':
|
||||
waiting_area = max(waiting_area.geoms, key=lambda p: p.area)
|
||||
|
||||
return waiting_area
|
||||
|
||||
def _setup_simulation_environment(self):
|
||||
"""Setup the simulation with door queues and waiting areas."""
|
||||
# Create walkable area geometry
|
||||
walkable_area = shapely.Polygon(self.config.walkable_area_coords)
|
||||
|
||||
# Create model and simulation
|
||||
model = jps.CollisionFreeSpeedModel()
|
||||
self.simulation = jps.Simulation(model=model, geometry=walkable_area)
|
||||
|
||||
# Define exit zone
|
||||
exit_polygon = shapely.Polygon(self.config.exit_polygon_coords)
|
||||
self.exit_id = self.simulation.add_exit_stage(exit_polygon)
|
||||
|
||||
# Create door systems
|
||||
for door_id, door_polygon in self.config.door_polygons.items():
|
||||
self._setup_door_system(door_id, door_polygon)
|
||||
|
||||
def _setup_door_system(self, door_id: int, door_polygon: shapely.Polygon):
|
||||
"""Setup queue system for a specific door."""
|
||||
# Create waiting area
|
||||
waiting_area = self._create_waiting_area(door_polygon)
|
||||
waiting_set_id = self.simulation.add_waiting_set_stage(waiting_area)
|
||||
|
||||
# Create queue waypoints
|
||||
door_centroid = door_polygon.centroid
|
||||
queue_waypoints = [
|
||||
self.simulation.add_waypoint_stage((door_centroid.x, door_centroid.y - 1.0), 0.5),
|
||||
self.simulation.add_waypoint_stage((door_centroid.x, door_centroid.y), 0.5),
|
||||
self.simulation.add_waypoint_stage((door_centroid.x, door_centroid.y + 1.0), 0.5)
|
||||
]
|
||||
|
||||
# Create journey
|
||||
journey_stages = [waiting_set_id] + queue_waypoints + [self.exit_id]
|
||||
journey = jps.JourneyDescription(journey_stages)
|
||||
journey_id = self.simulation.add_journey(journey)
|
||||
|
||||
# Store door system
|
||||
self.door_systems[door_id] = {
|
||||
"waiting_area": waiting_area,
|
||||
"waiting_set_id": waiting_set_id,
|
||||
"queue_waypoints": queue_waypoints,
|
||||
"journey_id": journey_id,
|
||||
"door_polygon": door_polygon
|
||||
}
|
||||
|
||||
def _precompute_spawn_events(self) -> List[Dict]:
|
||||
"""Precompute all spawn events with positions and agent configurations."""
|
||||
events = []
|
||||
|
||||
# Group agents by their assigned group
|
||||
agents_by_group = {}
|
||||
for agent in self.all_agents:
|
||||
for group_name, group_info in self.config.groups.items():
|
||||
if agent.door == group_info["door"]:
|
||||
if group_name not in agents_by_group:
|
||||
agents_by_group[group_name] = []
|
||||
agents_by_group[group_name].append(agent)
|
||||
break
|
||||
|
||||
# Create events for each group
|
||||
for group_name, group_info in self.config.groups.items():
|
||||
door_id = group_info["door"]
|
||||
spawn_time = group_info["spawn_time"]
|
||||
group_agents = agents_by_group.get(group_name, [])
|
||||
|
||||
if not group_agents:
|
||||
continue
|
||||
|
||||
# Generate spawn positions
|
||||
door_polygon = self.config.door_polygons[door_id]
|
||||
spawn_positions = self._generate_spawn_points(
|
||||
door_polygon,
|
||||
len(group_agents)
|
||||
)
|
||||
|
||||
# Create events
|
||||
for agent, position in zip(group_agents, spawn_positions):
|
||||
events.append({
|
||||
"time": spawn_time,
|
||||
"agent_config": agent,
|
||||
"position": position,
|
||||
"group": group_name,
|
||||
"door": door_id
|
||||
})
|
||||
|
||||
# Sort events by time
|
||||
events.sort(key=lambda x: x["time"])
|
||||
return events
|
||||
|
||||
def _execute_simulation(self):
|
||||
"""Execute the simulation with dynamic spawning."""
|
||||
spawned_event_indices = set()
|
||||
agents_in_door_area = {door_id: 0 for door_id in self.config.door_polygons.keys()}
|
||||
event_index = 0
|
||||
'''
|
||||
print("\nStarting simulation loop...")
|
||||
print(f"Total simulation time: {self.config.total_simulation_time}s")
|
||||
print(f"Door capacity: {self.config.door_capacity} agents per door")
|
||||
'''
|
||||
while self.simulation.elapsed_time() < self.config.total_simulation_time:
|
||||
current_time = self.simulation.elapsed_time()
|
||||
|
||||
# Process spawn events
|
||||
self._process_spawn_events(current_time, event_index, spawned_event_indices,
|
||||
agents_in_door_area)
|
||||
|
||||
# Update event index
|
||||
while (event_index < len(self.spawn_events) and
|
||||
self.spawn_events[event_index]["time"] <= current_time and
|
||||
event_index in spawned_event_indices):
|
||||
event_index += 1
|
||||
|
||||
# Iterate simulation
|
||||
self.simulation.iterate()
|
||||
|
||||
print(f"\nSimulation completed at {self.simulation.elapsed_time():.2f} seconds")
|
||||
|
||||
def _process_spawn_events(self, current_time: float, event_index: int,
|
||||
spawned_event_indices: set, agents_in_door_area: Dict):
|
||||
"""Process all spawn events that should occur at the current time."""
|
||||
while (event_index < len(self.spawn_events) and
|
||||
self.spawn_events[event_index]["time"] <= current_time and
|
||||
event_index not in spawned_event_indices):
|
||||
|
||||
event = self.spawn_events[event_index]
|
||||
door_id = event["door"]
|
||||
agent_config = event["agent_config"]
|
||||
|
||||
# Check door capacity
|
||||
if agents_in_door_area[door_id] < self.config.door_capacity:
|
||||
self._spawn_agent(event, door_id, agent_config)
|
||||
agents_in_door_area[door_id] += 1
|
||||
spawned_event_indices.add(event_index)
|
||||
|
||||
# Move to next event
|
||||
event_index += 1
|
||||
|
||||
def _spawn_agent(self, event: Dict, door_id: int, agent_config: AgentConfig):
|
||||
"""Spawn a single agent into the simulation."""
|
||||
journey_id = self.door_systems[door_id]["journey_id"]
|
||||
|
||||
agent_params = jps.CollisionFreeSpeedModelAgentParameters(
|
||||
position=event["position"],
|
||||
journey_id=journey_id,
|
||||
stage_id=self.door_systems[door_id]["waiting_set_id"],
|
||||
radius=agent_config.radius,
|
||||
v0=agent_config.speed,
|
||||
)
|
||||
|
||||
agent_id = self.simulation.add_agent(agent_params)
|
||||
|
||||
# Optional: Log spawning
|
||||
if agent_id % 50 == 0: # Log every 50th agent
|
||||
print(f" Spawned agent {agent_id} (group: {event['group']}, door: {door_id})")
|
||||
|
||||
|
||||
# Example usage function
|
||||
def create_and_run_simulation() -> PedestrianSimulation:
|
||||
"""
|
||||
Example function to create and run a complete simulation.
|
||||
|
||||
Returns:
|
||||
PedestrianSimulation: The completed simulation object
|
||||
"""
|
||||
# Define door polygons
|
||||
door_polygons = {
|
||||
1: shapely.Polygon([(5, 5), (10, 5), (10, 15), (5, 15)]),
|
||||
2: shapely.Polygon([(20, 5), (25, 5), (25, 15), (20, 15)]),
|
||||
3: shapely.Polygon([(35, 5), (40, 5), (40, 15), (35, 15)]),
|
||||
}
|
||||
|
||||
# Define groups (example with 4 groups, extend to 13 as needed)
|
||||
groups = {
|
||||
"group_1": {"door": 1, "spawn_time": 0.0, "size": 40},
|
||||
"group_2": {"door": 2, "spawn_time": 5.0, "size": 35},
|
||||
"group_3": {"door": 3, "spawn_time": 10.0, "size": 30},
|
||||
"group_4": {"door": 1, "spawn_time": 15.0, "size": 25},
|
||||
# Add 9 more groups to reach 13 total
|
||||
}
|
||||
|
||||
# Create simulation configuration
|
||||
config = SimulationConfig(
|
||||
door_polygons=door_polygons,
|
||||
groups=groups,
|
||||
total_simulation_time=200.0, # Adjust as needed
|
||||
door_capacity=10,
|
||||
min_spacing=0.6
|
||||
)
|
||||
|
||||
# Create and run simulation
|
||||
sim_runner = PedestrianSimulation(config)
|
||||
simulation = sim_runner.run()
|
||||
|
||||
return sim_runner
|
||||
|
||||
|
||||
# Quick execution function
|
||||
def run_simulation_quickstart():
|
||||
"""Quickstart function for running a basic simulation."""
|
||||
print("Pedestrian Simulation Quickstart")
|
||||
print("-" * 40)
|
||||
|
||||
# You can modify these parameters
|
||||
door_polygons = {
|
||||
1: shapely.Polygon([(2, 2), (6, 2), (6, 8), (2, 8)]),
|
||||
2: shapely.Polygon([(10, 2), (14, 2), (14, 8), (10, 8)]),
|
||||
3: shapely.Polygon([(18, 2), (22, 2), (22, 8), (18, 8)]),
|
||||
}
|
||||
|
||||
groups = {
|
||||
"class_a": {"door": 1, "spawn_time": 0.0, "size": 30},
|
||||
"class_b": {"door": 2, "spawn_time": 10.0, "size": 25},
|
||||
"class_c": {"door": 3, "spawn_time": 20.0, "size": 20},
|
||||
}
|
||||
|
||||
config = SimulationConfig(
|
||||
door_polygons=door_polygons,
|
||||
groups=groups,
|
||||
total_simulation_time=100.0,
|
||||
door_capacity=8
|
||||
)
|
||||
|
||||
sim = PedestrianSimulation(config)
|
||||
return sim.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Option 1: Use the example function
|
||||
# sim_runner = create_and_run_simulation()
|
||||
|
||||
# Option 2: Use quickstart for testing
|
||||
simulation = run_simulation_quickstart()
|
||||
|
||||
# You can now analyze the simulation results
|
||||
print(f"\nFinal simulation state:")
|
||||
print(f" Elapsed time: {simulation.elapsed_time():.2f}s")
|
||||
# Additional analysis can be added here
|
||||
17
archive/source/test/config.py
Normal file
17
archive/source/test/config.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
E.Drake - ENGN-2220
|
||||
|
||||
Thu Jan 22 23:48:50 2026
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).parent.parent.parent
|
||||
SOURCE_DIR = ROOT/"source"
|
||||
ARCHIVE_DIR = ROOT/"archive"
|
||||
PATH_DIR = ROOT/"path"
|
||||
AGENTS_DIR = ROOT/SOURCE_DIR/"sim_agents"
|
||||
GEO_DIR = ROOT/SOURCE_DIR/"sim_geometry"
|
||||
TEST_DIR = ROOT/SOURCE_DIR/"test"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user