Giter Club home page Giter Club logo

uxsim's Introduction

UXsim: Network traffic flow simulator in pure Python

PyPi Demo in Colab arXiv Static Badge Static Badge

UXsim is a free, open-source macroscopic and mesoscopic network traffic flow simulator written in Python. It simulates the movements of car travelers and traffic congestion in road networks. It is suitable for simulating large-scale (e.g., city-scale) traffic phenomena. UXsim is especially useful for scientific and educational purposes because of its simple, lightweight, and customizable features, but users are free to use UXsim for any purpose.

If you are interested, please see:

Main Features

  • Simple, lightweight, and easy-to-use Python implementation of modern standard models of dynamic network traffic flow
  • Macroscopic traffic simulation: Simulating over 60000 vehicles in a city in 30 seconds
  • Dynamic traffic assignment: Traffic flow simulation with a given network and time-dependent OD demand
  • Theoretically valid models commonly used in academic/professional transportation research
  • Implementation of traffic control/management schemes such as taxi/shared-mobility, traffic signals, road pricing, and so on
  • Basic analysis of simulation results and their export to pandas.DataFrame and CSV files
  • Visualization of simulation results using matplotlib; interactive GUI is available
  • Flexible and customizable thanks to pure Python implementation; can also be directly integrated with other Python-based frameworks, such as PyTorch for deep reinforcement learning traffic control
  • The main code uxsim.py is only about 1800 lines of code. Users may easily understand and customize it

Simulation Examples

Large-scale scenario

Below are simulation results where approximately 60000 vehicles pass through a 10km x 10km grid network in 2 hours. The computation time was about 30 seconds on a standard desktop PC.

Visualization of link traffic states (thicker lines mean more vehicles, darker colors mean slower speeds) and some vehicle trajectories:

Vehicle trajectory diagram on a corridor of the above network:

Deep reinforcement learning signal control using PyTorch

A traffic signal controller is trained by deep reinforcement learning (DRL) using PyTorch. The left (or upper) scenario shows no control with fixed signal timing; the traffic demand exceeds the network capacity with the naive signal setting, and a gridlock occurs. The right (or bottom) scenario shows DRL control, where the traffic signal can be changed by observing queue length; although the demand level is the same, traffic flows smoothly. A Jupyter Notebook of this example is available.

Interactive GUI for exploring a simulation result

resultGUIviewer_cut.mp4

Install

Using pip

The simplest way is to use pip to install from PyPI:

pip install uxsim
Alternative methods for advanced users (click to see)

Using pip with custom configuration

You can also use pip to install the GitHub version:

pip install -U -e git+https://github.com/toruseo/uxsim@main#egg=uxsim

Or any other (development) branch on this repo or your own fork:

pip install -U -e git+https://github.com/YOUR_FORK/uxsim@YOUR_BRANCH#egg=uxsim

Manual install

Download the uxsim directory from this Github repo or the latest release and place it in your local directory as follows:

your_project_directory/
├── uxsim/ 	# The uxsim directory
│ ├── uxsim.py 	# The main code of UXsim. You can customize this as you wish
│ └── ... 	# Other files and directories in uxsim
├── your_simulation_code.py 		# Your code if necessary
├── your_simulation_notebook.ipynb 	# Your Jupyter notebook if necessary
├── ... 	# Other files if necessary

This way, you can flexibly customize UXsim on your own.

Getting Started

As a simple example, the following code will simulate traffic flow in a Y-shaped network.

from uxsim import *

# Define the main simulation
# Units are standardized to seconds (s) and meters (m)
W = World(
    name="",    # Scenario name
    deltan=5,   # Simulation aggregation unit delta n
    tmax=1200,  # Total simulation time (s)
    print_mode=1, save_mode=1, show_mode=0,    # Various options
    random_seed=0    # Set the random seed
)

# Define the scenario
W.addNode("orig1", 0, 0) # Create a node
W.addNode("orig2", 0, 2)
W.addNode("merge", 1, 1)
W.addNode("dest", 2, 1)
W.addLink("link1", "orig1", "merge", length=1000, free_flow_speed=20) # Create a link
W.addLink("link2", "orig2", "merge", length=1000, free_flow_speed=20)
W.addLink("link3", "merge", "dest", length=1000, free_flow_speed=20)
W.adddemand("orig1", "dest", 0, 1000, 0.45) # Create OD traffic demand
W.adddemand("orig2", "dest", 400, 1000, 0.6)

# Run the simulation to the end
W.exec_simulation()

# Print summary of simulation result
W.analyzer.print_simple_stats()

# Visualize snapshots of network traffic state for several timesteps
W.analyzer.network(100, detailed=1, network_font_size=12)
W.analyzer.network(600, detailed=1, network_font_size=12)
W.analyzer.network(800, detailed=1, network_font_size=12)

It will output text to the terminal and images to the out directory like below:

simulation setting:
 scenario name:
 simulation duration:    1200 s
 number of vehicles:     810 veh
 total road length:      3000 m
 time discret. width:    5 s
 platoon size:           5 veh
 number of timesteps:    240
 number of platoons:     162
 number of links:        3
 number of nodes:        4
 setup time:             0.00 s
simulating...
      time| # of vehicles| ave speed| computation time
       0 s|        0 vehs|   0.0 m/s|     0.00 s
     600 s|      130 vehs|  13.7 m/s|     0.03 s
    1195 s|       75 vehs|  12.3 m/s|     0.06 s
 simulation finished
results:
 average speed:  11.6 m/s
 number of completed trips:      735 / 810
 average travel time of trips:   162.6 s
 average delay of trips:         62.6 s
 delay ratio:                    0.385

Further Reading

To learn more about UXsim, please see:

Main Files

  • uxsim directory: UXsim main package
    • uxsim/uxsim.py: UXsim main code
  • demos_and_examples directory: Tutorials and examples of UXsim
  • dat directory: Sample scenario files

Terms of Use & License

UXsim is released under the MIT License. You are free to use it as long as the source is acknowledged.

When publishing works based on UXsim, please cite:

  • Toru Seo. Macroscopic Traffic Flow Simulation: Fundamental Mathematical Theory and Python Implementation. Corona Publishing Co., Ltd., 2023.
  • Toru Seo. UXsim: An open source macroscopic and mesoscopic traffic simulator in Python-a technical overview. arXiv preprint arXiv: 2309.17114, 2023

Contributing and Discussion

Contributions are welcome! Please see the Contributing Guideline.

If you have any questions or suggestions, please post them to the Issues or Discussions (in English or Japanese).

I (Toru Seo) work on this project in my spare time. Please understand that my response may be delayed.

Acknowledgments

UXsim is based on various works in traffic flow theory and related fields. We acknowledge the contributions of the research community in advancing this field. Specifically, UXsim directly uses the following works:

Related Links

uxsim's People

Contributors

ewouth avatar toruseo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

uxsim's Issues

Future Plan: Refine visualization methods

  • Flow-based visualization. The current network visualization is based on density and speed. Although it is intuitive, they are strongly correlated, so it is not very informative.
  • Explicit support for mulitlane traffic
  • Vehicle trajectory tracking in network using GUI

Future Plan: multi-lane link

The current model assumes that all links are 1 lane. Furthermore, the reaction time of all drivers are the same. These mean that all links have more or less the same capacity. It is not possible to model multi-lane links that have 2 or 3 times the capacity of 1-lane links. This is a theoretical limitation of the underlying model.

I plan to implement multi-lane with FIFO (no overtaking) in the future.

Workarounds for the current model:

  • Create multiple links between same node pair; each link corresponds to each lane between the nodes. This is a reasonable solution. However, the analysis becomes tedious.
  • Reduce capacity_out parameter of Link. In this way, we can place a bottleneck to the end of a link, so that capacities of links can vary significantly. However, it only reduce the capacity. Also, the jam propagation speed becomes too fast or slow.

TypeError: unhashable type: 'list' in signal control examples

Several Python scripts within the demos_and_examples directory are failing due to a TypeError related to hashability. Specifically, the scripts attempt to use a list as a key in a dictionary, which is not permitted in Python as lists are mutable and thus unhashable.

Affected Files:

  1. example_08_signal_reactive_control.py
  2. example_08en_signal_reactive_control.py
  3. example_11en_signal_4legged_intersection_reactive_control.py

Steps to Reproduce:

  1. Execute the scripts individually or through a test runner like pytest.
  2. Observe the TypeError that occurs when attempting to use a list as a dictionary key.

Expected Behavior:
The scripts should run without errors, managing signal control as designed.

Actual Behavior:
When running the scripts, they fail with the following error output:

TypeError: unhashable type: 'list'

The error is thrown in the following context for each script:

  • In example_08_signal_reactive_control.py and example_08en_signal_reactive_control.py at line 37:
    vehicles_per_links[l.signal_group] = l.num_vehicles
  • In example_11en_signal_4legged_intersection_reactive_control.py at line 45:
    vehicles_per_links = {l.signal_group: 0 for l in II.inlinks.values()}

Error Log:

For example_08_signal_reactive_control.py:

simulation setting:
...
simulating...
      time| # of vehicles| ave speed| computation time
       0 s|        0 vehs|   0.0 m/s|     0.00 s

Traceback (most recent call last):
  File "/path/to/example_08_signal_reactive_control.py", line 37, in <module>
    vehicles_per_links[l.signal_group] = l.num_vehicles
TypeError: unhashable type: 'list'

Similar errors are observed for the other affected files.

Suggested Fix:
A review and potential redesign of the data structure used to track vehicles per link is needed. If l.signal_group is indeed a list and meant to be used as a key, one could consider converting it to a tuple, which is hashable, provided the list's contents are also hashable. Otherwise, restructure the code to avoid using a list as a dictionary key.

Speed up `route_search_all` by using priority queue optimized Dijkstra's

After some benchmarks, I discovered the route_search_all takes up a majority (~80% of runtime) in my simulation. This feature request proposes optimizing the route search algorithm, specifically by replacing the current implementation with a more efficient algorithm suited for sparse graphs that are often encountered in real-world road networks.

Issue:
The Floyd-Warshall algorithm, while comprehensive in determining the shortest distances between all pairs of vertices, does not inherently provide the immediate next step in the shortest path from one node to another. The manual computation of this next matrix, especially in a graph of this scale and sparsity, is inefficient and time-consuming, as indicated by execution timings: next matrix computed in 19.861 sec.

UXsim/uxsim/uxsim.py

Lines 992 to 999 in 584b5d7

for i in range(n_vertices):
for j in range(n_vertices):
# iからjへの最短経路を逆にたどる... -> todo: 起終点を逆にした最短経路探索にすればよい
if i != j:
prev = j
while s.pred[i, prev] != i and s.pred[i, prev] != -9999:
prev = s.pred[i, prev]
s.next[i, j] = prev

Proposed Solution:
Adopt Dijkstra's algorithm, with a priority queue, for the computation of shortest paths. Dijkstra's algorithm is more suited to sparse graphs and inherently provides the immediate next node on the shortest path as part of its output, thus eliminating the need for the currently cumbersome post-processing step.

Technical Justification:

  • Efficiency in Sparse Graphs: Dijkstra's algorithm scales better with sparse graphs, operating at (O((V + E) \log V)) complexity, where (V) is the number of vertices and (E) is the number of edges. This is a significant improvement over the Floyd-Warshall’s (O(V^3)) complexity, making Dijkstra's algorithm particularly suitable for our graph's sparse nature.
  • Direct Path Reconstruction: Unlike Floyd-Warshall, Dijkstra’s algorithm directly provides the next node in the shortest path from the source to every other node. This feature simplifies the routing module by eliminating the need for additional calculations to determine the next steps in paths.
  • Optimization Potential: Shifting to Dijkstra's algorithm with a priority queue not only addresses the current bottleneck but also opens up opportunities for further optimizations, including potentially leveraging parallel computations for running Dijkstra's from multiple sources simultaneously.

Feature requrest: Estimate and record trip travel times

It would be a very useful feature for me to be able to estimate and record travel times of trips in UXsim.

  • Estimate the expected travel time based on the current state of the network.
  • Record the final travel time a trip took.

The first one can be used to make decisions on (for agents making a mode choice for example), the second can be usefull as metric / KPI.

`record_log` takes too much time for medium - large scale simulation

I also did some benchmarks using example_04en_automatic_network_generation.py (440 links, 12100 platoons, 1440 timesteps) and surprised that Vehicle.record_log takes long time (~50% of simulation) considering its simple task. I suspect too many use of append is the reason.

Since I won't be able to work on it for a while, I'll keep a record of it for later update.

with record_log
image

without record_log
image

Question: direct link between time step size and platoon size

I noticed that the time step size (DELTAT) is directly linked to the platoon size (DELTAN) through the reaction time (REACTION_TIME), as shown in the initialization DELTAT = REACTION_TIME * DELTAN.

I'm curious why this is modelled this way, could you clarify the rationale behind this direct linkage between time step size and platoon size?

Installation failure due to early import of external dependencies

When attempting to install uxsim using pip install . or pip install -e ., the installation process fails during the phase where pip tries to get the requirements to build the wheel. This issue arises because the setup.py script indirectly imports the uxsim package, which in turn imports external dependencies such as numpy. Since these external dependencies are not yet installed at the point when setup.py is executed to determine the installation requirements, this results in a ModuleNotFoundError.

Steps to Reproduce

  1. Clone the uxsim repository or download the source code.
  2. Ensure that the environment does not have the dependencies (numpy, matplotlib, etc.) already installed.
  3. Run pip install . or pip install -e . from the root directory of the uxsim project.

You can also directly run:

pip install -U -e git+https://github.com/toruseo/uxsim@main#egg=uxsim

Expected Behavior

The pip install command should successfully install the uxsim package along with its specified dependencies without requiring them to be installed beforehand.

Actual Behavior

The installation process fails with a ModuleNotFoundError, indicating that one of the external packages (numpy is mentioned specifically) could not be found. This error is traced back to an import statement in the uxsim package that is executed as part of the setup.py script's execution.

Impact

This issue prevents the package from being installed in environments where the dependencies are not already present. It affects both development environments and end-users attempting to install uxsim for the first time, potentially limiting the adoption and usability of the package.

Workaround

A temporary workaround involves manually installing the dependencies listed in INSTALL_REQUIRES from the setup.py file before attempting to install uxsim. However, this approach is not ideal as it circumvents the automated dependency resolution and installation process provided by pip.

Suggested Fix

To resolve this issue, it is recommended to refactor the setup.py script and the package initialization process to avoid importing the package or any modules that require external dependencies. Instead, consider one of the following approaches:

  • Directly specify the version and other metadata in setup.py without importing them from within the package.
  • Use a separate file to store the version and other metadata that can be read by setup.py without executing import statements that depend on external packages.
  • Utilize a build-time dependency management tool that supports dynamic versioning without requiring the package itself to be imported during installation.

Additional Information

This issue persists even when the dependencies are installed beforehand, indicating that the version fetching mechanism is inherently flawed and requires attention regardless of the installation environment.

You can see the full error message also here: https://github.com/EwoutH/UXsim/actions/runs/8110064753/job/22166521983

Related:

Future Plan: taxi and shared mobility

Currently, a vehicle in UXsim just travel from A to B and disappear. This is like a private owned vehicle.

In the future, in order to model taxi and shared mobility, specific vehicles can travel through a network by passing through specific nodes that are dynamically updated.

Create network from OSMnx graph

I was curious if it's possible to import a road network from OSMnx.

For the links, the start_node, end_node, length, free_flow_speed could all be determined from OSMnx itself. Then, you could add a function to infer jam_density based on the number of lanes, maximum speed and road type.

For the nodes x and y could be determined from the OSMnx graph, while the signal could be inferred from the intersection type (or left to default).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.