Skip to content

Commit

Permalink
Add different exits
Browse files Browse the repository at this point in the history
  • Loading branch information
chraibi committed Apr 3, 2024
1 parent 5e43171 commit 73538d2
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 41 deletions.
76 changes: 49 additions & 27 deletions simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@
import json
import logging
import pathlib
import sys
import time
from typing import Any, Dict, Iterator, List, Tuple, TypeAlias

import sys
import _io
import jupedsim as jps
from jupedsim.distributions import distribute_by_number
Expand All @@ -21,7 +20,6 @@
parse_distribution_polygons,
parse_fps,
parse_motivation_doors,
parse_motivation_parameter,
parse_motivation_strategy,
parse_normal_time_gap,
parse_normal_v_0,
Expand Down Expand Up @@ -60,9 +58,9 @@ def init_motivation_model(
_data: Dict[str, Any], ped_ids: List[int]
) -> mm.MotivationModel:
"""Init motuvation model based on parsed streategy."""
width = parse_motivation_parameter(_data, "width")
height = parse_motivation_parameter(_data, "height")
seed = parse_motivation_parameter(_data, "seed")
width = _data["motivation_parameters"]["width"]
height = _data["motivation_parameters"]["height"]
seed = _data["motivation_parameters"]["seed"]
motivation_doors = parse_motivation_doors(_data)
if not motivation_doors:
log_error("json file does not contain any motivation door")
Expand All @@ -81,6 +79,7 @@ def init_motivation_model(
if choose_motivation_strategy == "default":
motivation_strategy = mm.DefaultMotivationStrategy(width=width, height=height)
if choose_motivation_strategy == "EVC":
logging.info(f"init EVC with {width = }, {height = }")
motivation_strategy = mm.EVCStrategy(
width=width,
height=height,
Expand Down Expand Up @@ -201,8 +200,6 @@ def run_simulation(
and simulation.elapsed_time() < _simulation_time
):
simulation.iterate()

# msg.code(f"Agents in the simulation: {simulation.agent_count()}")
if simulation.iteration_count() % 100 == 0:
number_agents_in_simulation = simulation.agent_count()
for agent in simulation.agents():
Expand Down Expand Up @@ -255,13 +252,13 @@ def main(
way_points = parse_way_points(_data)
destinations_dict = parse_destinations(_data)
destinations = list(destinations_dict.values())
journey_id, stage_id = init_journey(simulation, way_points, destinations[0])
journey_id, exit_ids = init_journey(simulation, way_points, destinations)
distribution_polygons = parse_distribution_polygons(_data)
positions = []

total_agents = _number_agents
for s_polygon in distribution_polygons.values():
logging.info(f"Distribute {total_agents} agents in {s_polygon}")
logging.info(f"Distribute {total_agents} agents")
pos = distribute_by_number(
polygon=s_polygon,
number_of_agents=total_agents,
Expand All @@ -277,16 +274,21 @@ def main(
normal_v_0 = parse_normal_v_0(_data)
normal_time_gap = parse_normal_time_gap(_data)
radius = parse_radius(_data)
agent_parameters = jps.CollisionFreeSpeedModelAgentParameters(
journey_id=journey_id,
stage_id=stage_id,
radius=radius,
v0=normal_v_0,
time_gap=normal_time_gap,
)
ped_ids = distribute_and_add_agents(simulation, agent_parameters, positions)
agent_parameters_list = []
for exit_id in exit_ids:
agent_parameters = jps.CollisionFreeSpeedModelAgentParameters(
journey_id=journey_id,
stage_id=exit_id,
radius=radius,
v0=normal_v_0,
time_gap=normal_time_gap,
)
agent_parameters_list.append(agent_parameters)

ped_ids = distribute_and_add_agents(simulation, agent_parameters_list, positions)
motivation_model = init_motivation_model(_data, ped_ids)
logging.info(f"Running simulation for {len(ped_ids)} agents:")
logging.info(f"{motivation_model.motivation_strategy.width = }")
run_simulation(simulation, motivation_model, _simulation_time, ped_ids, msg)
logging.info(
f"Simulation completed after {simulation.iteration_count()} iterations"
Expand Down Expand Up @@ -319,32 +321,52 @@ def start_simulation(config_path, output_path):

def modify_and_save_config(base_config, modification_dict, new_config_path):
"""Modify base configuration and save as a new JSON file."""
config = base_config.copy()
config = json.loads(json.dumps(base_config)) # Deep copy
for key, value in modification_dict.items():
config[key] = value
nested_keys = key.split("/")
last_key = nested_keys.pop()
temp = config
for nk in nested_keys:
temp = temp[nk]
temp[last_key] = value
with open(new_config_path, "w", encoding="utf8") as f:
json.dump(config, f, ensure_ascii=False, indent=4)


if __name__ == "__main__":
init_logger()
base_config = "files/bottleneck.json"
base_config = "files/inifile.json"
# Load base configuration
with open(base_config, "r", encoding="utf8") as f:
base_config = json.load(f)

variations = [
{"number_agents": 10, "fps": 30},
{"number_agents": 20, "fps": 30},
{"motivation_parameters/width": 0.5, "motivation_parameters/seed": 1.0},
{"motivation_parameters/width": 0.5, "motivation_parameters/seed": 300.0},
{"motivation_parameters/height": 0.5, "motivation_parameters/seed": 300.0},
{"motivation_parameters/width": 0.1, "motivation_parameters/seed": 1.0},
{"motivation_parameters/width": 0.1, "motivation_parameters/seed": 300.0},
{"motivation_parameters/width": 1.0, "motivation_parameters/seed": 1.0},
{"motivation_parameters/width": 1.0, "motivation_parameters/seed": 300.0},
{"motivation_parameters/width": 1.5, "motivation_parameters/seed": 200.0},
{"motivation_parameters/width": 1.5, "motivation_parameters/seed": 300.0},
{"motivation_parameters/width": 2.0, "motivation_parameters/seed": 200.0},
{"motivation_parameters/width": 2.0, "motivation_parameters/seed": 300.0},
{"motivation_parameters/width": 1.2, "motivation_parameters/seed": 300.0},
]
file_path = "files/variations/variations.json"

# Write the list of dictionaries to a JSON file
with open(file_path, "w") as f:
json.dump(variations, f, indent=4)
# Run simulations with variations
for i, variation in enumerate(variations, start=1):
logging.info(f"running simulation with {i}: {variation}")
new_config_path = f"config_variation_{i}.json"
output_path = f"trajectory_variation_{i}.sqlite"
logging.info(f"running variation {i:03d}: {variation}")
new_config_path = f"config_variation_{i:03d}.json"
output_path = f"files/trajectory_variation_{i:03d}.sqlite"

# Modify and save the new configuration
modify_and_save_config(base_config, variation, new_config_path)

evac_time = start_simulation(new_config_path, output_path)
print(f"Variation {i}: {evac_time = }")
logging.info(f"Variation {i:03d}: {evac_time = }")
1 change: 1 addition & 0 deletions src/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def plot_density_time_series(df_data: pd.DataFrame) -> None:
xaxis_title="Time Steps",
yaxis_title="Density (1/m/m)",
)
fig_density.update_yaxes(range=[0, 12])

st.plotly_chart(fig_density)

Expand Down
60 changes: 46 additions & 14 deletions src/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import json
import os
from pathlib import Path
from typing import Any, Dict, List, Tuple, TypeAlias
from typing import Any, Dict, List, Tuple, TypeAlias, Union
from types import SimpleNamespace

import jupedsim as jps
import numpy as np
Expand All @@ -16,12 +17,38 @@
from scipy import stats
from shapely import GeometryCollection, Polygon
from shapely.ops import unary_union

from .logger_config import log_error, log_info

Point: TypeAlias = Tuple[float, float]


def parse(data: Union[List, Dict, Any]) -> Union[List, SimpleNamespace, Any]:
"""
Recursively converts a nested structure of lists and dictionaries into
a structure of lists and SimpleNamespace objects. Other data types are left unchanged.
Parameters:
- data (Union[List, Dict, Any]): The input data to parse. This can be a list,
dictionary, or any other data type. If it's a list or dictionary, the function
will recursively parse its content.
Returns:
- Union[List, SimpleNamespace, Any]: The parsed data where dictionaries are
converted to SimpleNamespace objects, lists are recursively parsed, and
other data types are returned unchanged.
"""
if isinstance(data, list):
return list(map(parse, data))
elif isinstance(data, dict):
sns = SimpleNamespace()
for key, value in data.items():
setattr(sns, key, parse(value))
return sns
else:
return data


def delete_txt_files() -> None:
"""Delete all *.sqlite files in the current directory."""
files = glob.glob("files/*.sqlite")
Expand Down Expand Up @@ -82,24 +109,27 @@ def init_journey(
wp_ids.append(wp_id)
journey.add(wp_id)

exit_id = simulation.add_exit_stage(exits)
exit_ids.append(exit_id)
journey.add(exit_id)
for e in exits:
exit_id = simulation.add_exit_stage(e)
exit_ids.append(exit_id)
journey.add(exit_id)

# todo: using only one exit here
stage_id = exit_ids[0]
for wp_id in wp_ids:
journey.set_transition_for_stage(
wp_id, jps.Transition.create_fixed_transition(stage_id)
)
# chosen_id = random.choice(exit_ids)
# logging.info(f"{chosen_id}, {exit_ids}")
# stage_id = chosen_id
# # todo these wp id are not needed and not properly initialized
# for wp_id in wp_ids:
# journey.set_transition_for_stage(
# wp_id, jps.Transition.create_fixed_transition(stage_id)
# )

journey_id = int(simulation.add_journey(journey))
return journey_id, stage_id
return journey_id, exit_ids


def distribute_and_add_agents(
simulation: jps.Simulation,
agent_parameters: jps.CollisionFreeSpeedModelAgentParameters,
agent_parameters_list: List[jps.CollisionFreeSpeedModelAgentParameters],
positions: List[Point],
) -> List[int]:
"""Initialize positions of agents and insert them into the simulation.
Expand All @@ -112,7 +142,9 @@ def distribute_and_add_agents(
"""
# log_info("Distribute and Add Agent")
ped_ids = []
for pos_x, pos_y in positions:
size = len(agent_parameters_list)
for i, (pos_x, pos_y) in enumerate(positions):
agent_parameters = agent_parameters_list[i % size]
agent_parameters.position = (pos_x, pos_y)
ped_id = simulation.add_agent(agent_parameters)
ped_ids.append(ped_id)
Expand Down

0 comments on commit 73538d2

Please sign in to comment.