Skip to main content

Mesoscopic (individual-vehicle) Link Transmission Model for traffic flow on general networks

Project description

mesoLTM

A mesoscopic (individual-vehicle) Link Transmission Model for traffic flow on general road networks, distributed as the pip package mesoltm.

mesoltm implements the discrete LTM of de Souza, Verbas, Auld & Tampère — a computationally efficient macroscopic-style model that nonetheless tracks every vehicle individually, so each vehicle carries its own (re-routable) path. It runs on arbitrary graphs and grids, supports parallel links (fast/slow lanes and detours), and exposes clean interfaces for external routing and per-step simulation plugins.

Requirements

  • Python 3.11+

Install

pip install mesoltm

For plotting support, install the plot extra:

pip install "mesoltm[plot]"

From source (editable, for development)

python3.11 -m venv venv && source venv/bin/activate
pip install -e ".[dev,plot]"     # core + dev tooling + plotting

Extras: plot (matplotlib visualisations), ui (network editor, optional), calib (scipy, for calibration examples), dev (pytest, pylint, black, mypy, build).

Quick start

from mesoltm import Vehicle, grid_network, ShortestPathPolicy

# A 4x4 grid where every node can be an origin or a destination.
net = grid_network(4, 4, link_length=200.0, all_nodes_od=True)
net.set_origin((0, 0), vehicles=[
    Vehicle(vehicle_id=k, start=float(k), origin=(0, 0), destination=(3, 3))
    for k in range(50)
])

sim = net.compile(time_step=1.0, total_time=400.0,
                  routing_policy=ShortestPathPolicy(dynamic=True))
sim.run()
print(sum(len(n.get_arrived_trips()) for n in sim.nodes), "vehicles arrived")

Or run a JSON scenario from the command line:

python -m mesoltm examples/scenario.json     # writes link/trip CSVs

Examples

Executable scripts under examples/ (run with python examples/<name>.py). Each writes its figures (and any CSVs) to its own subdirectory examples/output/<script_name>/, so results are easy to tell apart.

  • freeway_onramp.py — a freeway on-ramp merge on a calibrated topology with a synthetic demand profile.
  • grid_demo.py — a partial grid with shortest-path routing.
  • rerouting_demo.py — manual per-vehicle rerouting: dynamic routing is off (static route-following), and a plugin hand-picks specific vehicles and rewrites their routes onto a detour mid-run (no closed links, no shortest-path search).
  • adaptive_rerouting_intersection.py — the most basic 2-in/2-out uncontrolled ("no-way-stop") intersection (a general node); agents are re-checked every step against the live shortest path from their current link onward (no U-turns), reroutes are versioned, and a few agents' initial-vs-final plans are plotted.
  • parallel_links_demo.py — fast lane, slow lane and an inflated-length detour, run twice: free-flow routing (everyone piles on the fast lane until it closes) vs congestion-aware routing (a cost that grows with each link's load spreads traffic onto the slow lane and detour).
  • vehicle_metrics_demo.py — collect per-vehicle travel times (overall and per link) with mesoltm.metrics and plot the travel-time distribution, per-link means, and a per-link travel-time time series showing congestion building up.
  • bottleneck_access_policy.py — a random bottleneck access policy driven with Simulation.start/step/inject: vehicles are released toward a goal via a fast bottleneck, and a ReroutingPlugin tosses a coin as each one approaches to admit it or divert it onto a slower parallel path (one toss per access). Plots each of four vehicles' route before the toss, after it, and as actually driven, and records the run as a video (plus per-step frames) of the vehicles moving link-to-link — blue while planning the bottleneck, then green (admitted) or orange (diverted).
  • congestion_aware_routing.py — a ReroutingPlugin that balances a burst of traffic across a short and a long route using a shortest-path cost that combines link length (free-flow time) with current load (state.occupancy).
  • grid_visualization.py — grids under congestion-aware route-based rerouting: a DensityRerouter plugin re-plans each vehicle (shortest path on free-flow time + a linear density penalty) at every node and writes the plan onto vehicle.route, so the recorded log is exactly the route that ran. Two scenarios: a tiny 2x2 grid (few vehicles, short horizon) whose per-step PNGs + JSON log can be checked by hand, and a dense 7x7 grid (with holes) carrying many vehicles between random OD pairs. Each records a video of the agents moving, coloured by the link each takes next — showing the animation stays readable on a dense scenario (sizes scale to the network, per-agent detail auto-drops but is available on request). One still is coloured by a custom function of each vehicle's props metadata (a vehicle class) to show color_by is fully overridable.

Key concepts

  • Network builder (mesoltm.Network, grid_network, corridor_network): add nodes/links, mark any node an origin/destination, compile() to a simulation.
  • Routing (RoutingPolicy): per-vehicle, mutable mid-run; StaticRoutePolicy (follow vehicle.route) or ShortestPathPolicy, or your own.
  • Plugins (Plugin): per-step loop hooks that run first each step to inspect NetworkState and change the simulation — reroute vehicles (each vehicle carries its own route, which the network merely propagates), gate/close links, run dispatchers or local auctions. ReroutingPlugin is the minimal rerouting form.
  • Visualisations (mesoltm.visualizations, needs [plot]): cumulative curves, flow over time (plot_link_flow sums links into a cut; plot_link_flows draws one labelled line per link), per-link travel time over time (plot_link_time_series, to see congestion build up), and network maps (plot_network, colour links by flow/occupancy/…, optionally label each link and fan out parallel links).
  • Movement video (mesoltm.visualizations + record_history=True): capture a per-step history (Network.compile(record_history=True[, history_path=…]), off by default; exposed as Simulation.history, JSON-serialisable) and render it to an MP4/GIF (save_animation, default 25 fps, subsample sets playback speed) and/or per-step PNGs (save_frames) of agents moving link-to-link — with next-link cues and a count badge on each node for agents waiting to enter. color_by chooses what a dot's colour means: "category", "next_link", None (uniform), or a custom callable fn(snapshot) -> str colouring by anything on the snapshot — most usefully each vehicle's free-form Vehicle(props=…) metadata, which travels with the vehicle and round-trips through the log. The log records each agent's remaining route straight from vehicle.route (never recomputed), so it always matches the simulation. The saved JSON log is self-describing (each agent/waiting entry is a keyed object). Scales from a small bottleneck to a dense grid.

Development

pytest                        # tests (includes a numeric regression vs. the reference)
pylint src/mesoltm examples   # lint
black --check src examples    # format check
mypy src                      # types
python -m build               # sdist + wheel

venv/ and build artefacts are git-ignored.

Release

Releases are automated. Pushing a v*.*.* tag triggers the release workflow, which validates versions, generates the changelog with git-cliff (config in cliff.toml), builds the distribution, publishes to PyPI, and creates a GitHub Release. The changelog is derived from conventional commit messages, so nothing in CHANGELOG.md needs to be edited by hand. Make sure all tests and builds are passing, then follow these steps.

0. Prerequisites (important!)

Switch to master and make sure it has all the changes that should be in the release:

git checkout master
git pull origin master

You also need permission to push tags, and a PYPI_TOKEN repository secret must be configured (a PyPI API token) for the publish step.

1. Update the version in pyproject.toml

Set the version in pyproject.toml to the next release version according to the conventional-commit history. To see what git-cliff computes as the next version, run:

git-cliff --bump --unreleased

⚠️ Do not commit any CHANGELOG.md changes — the release workflow regenerates and commits the changelog automatically. Commit only the version bump in pyproject.toml. If the pyproject.toml version and the git-cliff-computed version disagree, the release workflow fails.

2. Commit the version change

git checkout master                     # safeguard: ensure you are on master
git commit -am "chore(release): v0.1.0"  # replace v0.1.0 with the release version
git push origin master

3. Create and push the tag (this triggers the workflow)

git checkout master                                   # safeguard: ensure you are on master
git tag -a v0.1.0 -m "chore(release): version 0.1.0"  # replace v0.1.0 with the release version
git push origin v0.1.0                                # push the tag to trigger the release workflow

4. GitHub Actions then automatically

  • Validates that the tag, pyproject.toml, changelog, and built wheel all agree on the version
  • Generates CHANGELOG.md with git-cliff and commits it back to master
  • Builds the sdist and wheel
  • Publishes to PyPI
  • Creates a GitHub Release with the changelog notes

Attribution and citation

If you use mesoltm in academic or other work, please cite this repository. A machine-readable entry is provided in CITATION.cff:

J. Schlapbach, mesoLTM: a mesoscopic (individual-vehicle) Link Transmission Model. Software, https://github.com/sjschlapbach/mesoLTM

As a secondary reference, please also cite the paper whose model mesoltm implements, and whose abmmeso package (by Felipe de Souza, AGPL-3.0) it adapts (see NOTICE):

F. de Souza, O. Verbas, J. Auld, C. M. J. Tampère, "A mesoscopic link-transmission-model able to track individual vehicles", Simulation Modelling Practice and Theory 140 (2025) 103088. DOI: 10.1016/j.simpat.2025.103088

Deviations from the paper's formulation are documented on the Deviations from the paper page of the documentation.

License

mesoltm is distributed under the GNU Affero General Public License v3.0 or later — see LICENSE and NOTICE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mesoltm-0.1.0.tar.gz (197.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mesoltm-0.1.0-py3-none-any.whl (137.7 kB view details)

Uploaded Python 3

File details

Details for the file mesoltm-0.1.0.tar.gz.

File metadata

  • Download URL: mesoltm-0.1.0.tar.gz
  • Upload date:
  • Size: 197.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for mesoltm-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e45eb62b2da809a38d97f0b577bdb04363fbc2b2f7e0c4cbbe4f50a3a8a0399b
MD5 948ef2350608ef01c40f1a13e4a16a11
BLAKE2b-256 3cfd50c800a599bc07383150793a36488f98d6a7a68fae50c1ac8f415dd352cc

See more details on using hashes here.

File details

Details for the file mesoltm-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: mesoltm-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 137.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for mesoltm-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5c8b82115efe7759256917dbd21e17bc206248b6fe1eedbba3d2ecfcd570cc90
MD5 14dd202c7e4a4c0f23357049c78c7b51
BLAKE2b-256 8820f7b4d6f653ffa628e95134adec866d6fabf04cc1b54c5cbd5d3712aae46a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page