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) withmesoltm.metricsand 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 withSimulation.start/step/inject: vehicles are released toward a goal via a fast bottleneck, and aReroutingPlugintosses 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— aReroutingPluginthat 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: aDensityRerouterplugin re-plans each vehicle (shortest path on free-flow time + a linear density penalty) at every node and writes the plan ontovehicle.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'spropsmetadata (a vehicle class) to showcolor_byis 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(followvehicle.route) orShortestPathPolicy, or your own. - Plugins (
Plugin): per-step loop hooks that run first each step to inspectNetworkStateand change the simulation — reroute vehicles (each vehicle carries its ownroute, which the network merely propagates), gate/close links, run dispatchers or local auctions.ReroutingPluginis the minimal rerouting form. - Visualisations (
mesoltm.visualizations, needs[plot]): cumulative curves, flow over time (plot_link_flowsums links into a cut;plot_link_flowsdraws 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 asSimulation.history, JSON-serialisable) and render it to an MP4/GIF (save_animation, default 25 fps,subsamplesets 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_bychooses what a dot's colour means:"category","next_link",None(uniform), or a custom callablefn(snapshot) -> strcolouring by anything on the snapshot — most usefully each vehicle's free-formVehicle(props=…)metadata, which travels with the vehicle and round-trips through the log. The log records each agent's remaining route straight fromvehicle.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.mdwith git-cliff and commits it back tomaster - 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e45eb62b2da809a38d97f0b577bdb04363fbc2b2f7e0c4cbbe4f50a3a8a0399b
|
|
| MD5 |
948ef2350608ef01c40f1a13e4a16a11
|
|
| BLAKE2b-256 |
3cfd50c800a599bc07383150793a36488f98d6a7a68fae50c1ac8f415dd352cc
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c8b82115efe7759256917dbd21e17bc206248b6fe1eedbba3d2ecfcd570cc90
|
|
| MD5 |
14dd202c7e4a4c0f23357049c78c7b51
|
|
| BLAKE2b-256 |
8820f7b4d6f653ffa628e95134adec866d6fabf04cc1b54c5cbd5d3712aae46a
|