Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add notebook for direct steering #1398

Merged
merged 5 commits into from
Sep 19, 2024
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
385 changes: 385 additions & 0 deletions notebooks/direct_steering.ipynb
chraibi marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simulation cell:
Currently you iterate multiple times over all agents, is there a better way to do it?

For example:

while simulation.agent_count() > 0:
    # Find leader's position
    if leader_id in simulation.removed_agents():
        leader_id = None
    if leader_id:
        position_leader = simulation.agent(leader_id).position

    # Move followers towards leader
    for agent in simulation.agents():
        if agent.id == leader_id:
            continue

        # Define a target position near the leader with some randomness
        near_leader = (
            position_leader[0] + random.normalvariate(1, 0.1),
            position_leader[1] + random.normalvariate(1, 0.1),
        )
        near_leader_point = Point(near_leader[0], near_leader[1])

        # If the target position is inside the walkable area, set it as the agent's target
        target = (
            near_leader
            if any(geom.contains(near_leader_point) for geom in area.geoms)
            else position_leader
        )
        agent.target = target

        # Check if the agent reached the exit and mark it for removal if so
        if Point(agent.position).distance(exit_area.centroid) < 1:
            simulation.mark_agent_for_removal(agent.id)

    simulation.iterate()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

chraibi marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,385 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "4aee4651",
"metadata": {},
"source": [
"# Direct steering\n",
"\n",
"This notebook can be directly downloaded {download}`here <./direct_steering.ipynb>` to run it locally.\n",
"\n",
"It demonstrates the use of [direct steering](https://www.jupedsim.org/stable/concepts/routing.html#direct-steering). of agents.\n",
"\n",
"Am agent (leader) embarks on a journey defined by specific waypoints and a final destination. Meanwhile, the remaining agents trail behind, constantly adjusting their course to align with the leader's current position."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a6d4f847-92e0-4905-b52b-a9e61aa2355f",
"metadata": {
"editable": true,
"slideshow": {
"slide_type": ""
},
"tags": []
},
"outputs": [],
"source": [
"import pathlib\n",
"import random\n",
"\n",
"import jupedsim as jps\n",
"import pedpy\n",
"from matplotlib.patches import Circle\n",
"from shapely import GeometryCollection, Point, Polygon"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d3087364-73e8-4b35-8a5e-2222df89f1fe",
"metadata": {
"editable": true,
"slideshow": {
"slide_type": ""
},
"tags": []
},
"outputs": [],
"source": [
"area = GeometryCollection(Polygon([(0, 0), (28, 0), (28, 10), (0, 10)]))\n",
"walkable_area = pedpy.WalkableArea(area.geoms[0])"
]
},
{
"cell_type": "markdown",
"id": "c9f63836-0f81-4684-b99e-abdf664c9d53",
"metadata": {
"editable": true,
"slideshow": {
"slide_type": ""
},
"tags": []
},
"source": [
"## Definition of Start Positions and Exit\n",
"\n",
"Now we define the spawning area and way points for the leader to follow."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5dec36fb-55f2-4225-aac7-32be899c9254",
"metadata": {
"editable": true,
"slideshow": {
"slide_type": ""
},
"tags": []
},
"outputs": [],
"source": [
"num_agents = 5\n",
"spawning_area = Polygon([(0, 0), (2, 0), (2, 10), (0, 10)])\n",
"pos_in_spawning_area = jps.distributions.distribute_by_number(\n",
" polygon=spawning_area,\n",
" number_of_agents=num_agents,\n",
" distance_to_agents=0.8,\n",
" distance_to_polygon=0.15,\n",
" seed=1,\n",
")\n",
"exit_area = Polygon([(27, 4.5), (28, 4.5), (28, 5.5), (27, 5.5)])\n",
"waypoints = [\n",
" (8, 8),\n",
" (8, 2),\n",
" (4, 2),\n",
" (4, 8),\n",
" (18, 2),\n",
" (18, 8),\n",
" (23, 2),\n",
" (23, 8),\n",
"]\n",
"distance_to_waypoints = 0.5"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "220d8141-614e-464d-9dcc-fc5ea8d1a6af",
"metadata": {
"editable": true,
"slideshow": {
"slide_type": ""
},
"tags": [
"hide-input"
]
},
"outputs": [],
"source": [
"def plot_simulation_configuration(\n",
" walkable_area, spawning_area, starting_positions, exit_area\n",
"):\n",
" axes = pedpy.plot_walkable_area(walkable_area=walkable_area)\n",
" axes.fill(*exit_area.exterior.xy, color=\"indianred\")\n",
" axes.scatter(*zip(*starting_positions), s=1)\n",
" axes.set_xlabel(\"x/m\")\n",
" axes.set_ylabel(\"y/m\")\n",
" axes.set_aspect(\"equal\")\n",
" for idx, waypoint in enumerate(waypoints):\n",
" axes.plot(waypoint[0], waypoint[1], \"ro\")\n",
" axes.annotate(\n",
" f\"WP {idx+1}\",\n",
" (waypoint[0], waypoint[1]),\n",
" textcoords=\"offset points\",\n",
" xytext=(10, -15),\n",
" ha=\"center\",\n",
" )\n",
" circle = Circle(\n",
" (waypoint[0], waypoint[1]),\n",
" distance_to_waypoints,\n",
" fc=\"red\",\n",
" ec=\"red\",\n",
" alpha=0.1,\n",
" )\n",
" axes.add_patch(circle)\n",
"\n",
"\n",
"plot_simulation_configuration(\n",
" walkable_area, spawning_area, pos_in_spawning_area, exit_area\n",
")"
]
},
{
"cell_type": "markdown",
"id": "2b990c43-7c81-4f19-92d6-97280974c300",
"metadata": {
"editable": true,
"slideshow": {
"slide_type": ""
},
"tags": []
},
"source": [
"## Specification of Parameters und Running the Simulation\n",
"\n",
"Now we just need to define the details of the operational model as well as the exit."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6a9b725e-cf77-4589-9023-3105665684ea",
"metadata": {
"editable": true,
"slideshow": {
"slide_type": ""
},
"tags": []
},
"outputs": [],
"source": [
"trajectory_file = \"output.sqlite\" # output file\n",
"simulation = jps.Simulation(\n",
" model=jps.GeneralizedCentrifugalForceModel(\n",
" max_neighbor_repulsion_force=10,\n",
" max_neighbor_interaction_distance=2,\n",
" max_neighbor_interpolation_distance=0.1,\n",
" strength_neighbor_repulsion=0.3,\n",
" max_geometry_repulsion_force=3,\n",
" ),\n",
" geometry=area,\n",
" trajectory_writer=jps.SqliteTrajectoryWriter(\n",
" output_file=pathlib.Path(trajectory_file)\n",
" ),\n",
")\n",
"exit_id = simulation.add_exit_stage(exit_area.exterior.coords[:-1])"
]
},
{
"cell_type": "markdown",
"id": "015995f0",
"metadata": {},
"source": [
"## Define Journey for leader"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "17f4ba2f",
"metadata": {},
"outputs": [],
"source": [
"waypoint_ids = [\n",
" simulation.add_waypoint_stage(waypoint, distance_to_waypoints)\n",
" for waypoint in waypoints\n",
"]\n",
"journey_leader = jps.JourneyDescription([*waypoint_ids, exit_id])\n",
"for i, waypoint_id in enumerate(waypoint_ids):\n",
" journey_leader.set_transition_for_stage(\n",
" waypoint_id,\n",
" jps.Transition.create_fixed_transition(\n",
" waypoint_ids[i + 1] if i + 1 < len(waypoint_ids) else exit_id\n",
" ),\n",
" )\n",
"journey_id = simulation.add_journey(journey_leader)"
]
},
{
"cell_type": "markdown",
"id": "61413b86",
"metadata": {},
"source": [
"## Define Journey for followers"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1a65b40e",
"metadata": {},
"outputs": [],
"source": [
"direct_steering_stage = simulation.add_direct_steering_stage()\n",
"direct_steering_journey = jps.JourneyDescription([direct_steering_stage])\n",
"direct_steering_journey_id = simulation.add_journey(direct_steering_journey)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "335348ab",
"metadata": {},
"outputs": [],
"source": [
"leader_id = simulation.add_agent(\n",
" jps.GeneralizedCentrifugalForceModelAgentParameters(\n",
" journey_id=journey_id,\n",
" stage_id=waypoint_ids[0],\n",
" position=pos_in_spawning_area[0],\n",
" v0=1.0,\n",
" b_min=0.1,\n",
" b_max=0.2,\n",
" a_min=0.1,\n",
" a_v=0.2,\n",
" orientation=(1, 0),\n",
" )\n",
")\n",
"# Followers\n",
"followers_ids = set(\n",
" [\n",
" simulation.add_agent(\n",
" jps.GeneralizedCentrifugalForceModelAgentParameters(\n",
" journey_id=direct_steering_journey_id,\n",
" stage_id=direct_steering_stage,\n",
" position=pos,\n",
" v0=0.8,\n",
" b_min=0.1,\n",
" b_max=0.2,\n",
" a_min=0.1,\n",
" a_v=0.2,\n",
" orientation=(1, 0),\n",
" )\n",
" )\n",
" for pos in pos_in_spawning_area[1:]\n",
" ]\n",
")\n",
"while simulation.agent_count() > 0:\n",
" # Find leader's position\n",
" for agent in simulation.agents():\n",
" if agent.id == leader_id:\n",
" position_leader = agent.position\n",
"\n",
" # Move followers towards leader\n",
" for follower_id in followers_ids:\n",
" for agent in simulation.agents():\n",
" if agent.id == follower_id:\n",
" # Define a target position near the leader with some randomness\n",
" near_leader = (\n",
" position_leader[0] + random.normalvariate(1, 0.1),\n",
" position_leader[1] + random.normalvariate(1, 0.1),\n",
" )\n",
" near_leader_point = Point(near_leader[0], near_leader[1])\n",
"\n",
" # If the target position is inside the walkable area, set it as the agent's target\n",
" target = (\n",
" near_leader\n",
" if any(\n",
" geom.contains(near_leader_point) for geom in area.geoms\n",
" )\n",
" else position_leader\n",
" )\n",
" agent.target = target\n",
"\n",
" # Check if the agent reached the exit and mark it for removal if so\n",
" if Point(agent.position).distance(exit_area.centroid) < 1:\n",
" simulation.mark_agent_for_removal(follower_id)\n",
"\n",
" simulation.iterate()"
]
},
{
"cell_type": "markdown",
"id": "77d7e165-1c0d-4aca-a5fa-d88d0625e8f4",
"metadata": {
"editable": true,
"slideshow": {
"slide_type": ""
},
"tags": []
},
"source": [
"## Visualization\n",
"\n",
"Let's have a look at the visualization of the simulated trajectories:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7a4455d6-3f11-4312-806a-d6d7ad6e1510",
"metadata": {
"editable": true,
"pycharm": {
"name": "#%%\n"
},
"slideshow": {
"slide_type": ""
},
"tags": []
},
"outputs": [],
"source": [
"from jupedsim.internal.notebook_utils import animate, read_sqlite_file\n",
"\n",
"trajectory_data, walkable_area = read_sqlite_file(trajectory_file)\n",
"animate(trajectory_data, walkable_area, every_nth_frame=10)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.14"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Loading