Chapter 17.2: OSMnx → SUMO Pipeline
17.2.1 Complete Pipeline Architecture
Building a SUMO simulation from real-world data involves four stages: network acquisition, network conversion, demand generation, and simulation execution. Each stage transforms data from one representation to the next.
Stage 1: NETWORK ACQUISITION
OSMnx.graph_from_place("City, Country") → graph G
ox.save_graph_xml(G, "city.osm.xml") → city.osm.xml
Stage 2: NETWORK CONVERSION
netconvert --osm-files city.osm.xml → city.net.xml
--output-file city.net.xml
--junctions.join
--roundabouts.guess
--tls.guess
--geometry.remove
--ramps.guess
Stage 3: DEMAND GENERATION
randomTrips.py -n city.net.xml → city.rou.xml
-r city.rou.xml
-e 3600
--period 2
--fringe-factor 5
--validate
Stage 4: SIMULATION
sumo -c city.sumocfg → outputs
--emission-output emission.xml
--fcd-output fcd.xml
--queue-output queue.xml17.2.2 netconvert: Critical Flags
The netconvert tool translates OpenStreetMap data into SUMO’s internal network format. Several flags are essential for producing a usable network:
| Flag | Purpose | Why Needed |
|---|---|---|
| --junctions.join | Merge nearby junctions | OSM often has multiple nodes for one intersection |
| --roundabouts.guess | Detect roundabouts | Proper priority/right-of-way rules |
| --tls.guess | Infer traffic lights | OSM tagging is inconsistent |
| --geometry.remove | Simplify edge geometry | Reduces file size, speeds simulation |
| --ramps.guess | Detect highway ramps | Correct merge/diverge behaviour |
| --no-turnarounds | Disable U-turns | Often unrealistic at signalised intersections |
17.2.3 Demand Generation
SUMO’s randomTrips.py generates vehicle departures with origin-destination pairs drawn from the network:
- --period p: one vehicle every \(p\) seconds (flow rate = 1/p veh/s)
- --fringe-factor f: weight edges on the network boundary by factor \(f\), simulating through-traffic
- --weights-prefix w: load OD weights from files for realistic demand patterns
- --validate: discard trips with no valid route
For more realistic demand, an origin-destination (OD) matrix can be used. The OD matrix \(T_{ij}\) specifies the number of trips from zone \(i\) to zone \(j\) per time period:
$$Q_{\text{total}} = \sum_{i,j} T_{ij}, \qquad \text{period} = \frac{T_{\text{sim}}}{Q_{\text{total}}}$$
17.2.4 SUMO Output Files
SUMO produces several output formats, each serving a different analysis purpose:
Emission Output (emission.xml)
<emission-export>
<timestep time="10.00">
<vehicle id="veh_0" eclass="HBEFA3/PC_G_EU4"
CO2="3456.78" CO="12.34" HC="0.56"
NOx="1.23" PMx="0.045"
speed="8.33" pos="83.3" lane="edge_0_0"/>
</timestep>
</emission-export>Floating Car Data (fcd.xml)
<fcd-export>
<timestep time="10.00">
<vehicle id="veh_0" x="456.78" y="123.45"
angle="90.0" speed="8.33" pos="83.3"
lane="edge_0_0" slope="0.00"/>
</timestep>
</fcd-export>Queue Output (queue.xml)
<queue-export>
<data timestep="10.00">
<lanes>
<lane id="edge_0_0" queueing_time="12.5"
queueing_length="45.0"
queueing_length_experimental="42.3"/>
</lanes>
</data>
</queue-export>17.2.5 TraCI Integration: Signal Control + Pollution
The following script demonstrates a ready-to-use TraCI connection that combines Module 13 signal control with Module 16 pollution estimation. It can be run directly with a SUMO installation, but the structure is shown here for reference.
#!/usr/bin/env python3
"""TraCI controller integrating signal control (Module 13) and OSPM (Module 16)."""
import traci
import numpy as np
class TraCIController:
def __init__(self, sumo_cfg, canyon_params):
self.sumo_cfg = sumo_cfg
self.canyon = canyon_params # dict: edge_id -> {H, W, alpha}
self.step = 0
def connect(self):
traci.start(["sumo", "-c", self.sumo_cfg])
def get_edge_emissions(self, edge_id):
"""Get total NOx emissions on an edge (mg/s)."""
vehicles = traci.edge.getLastStepVehicleIDs(edge_id)
total_nox = sum(traci.vehicle.getNOxEmission(v) for v in vehicles)
return total_nox
def ospm_concentration(self, edge_id, nox_emission):
"""Compute OSPM concentration for a canyon edge."""
p = self.canyon.get(edge_id, {"H": 15, "W": 20})
alpha = p["H"] / p["W"]
length = traci.edge.getLastStepLength(edge_id)
q_L = nox_emission / max(length, 1.0) # mg/m/s
u_H = 5.0; kappa = 0.41; C_D = 0.005
u_v = C_D * u_H / ((1 + alpha) * kappa)
u_s = max(u_v * 0.5, 0.3)
C_D_conc = q_L / (np.sqrt(2*np.pi) * 0.8 * u_s)
L_R = min(p["W"], p["H"])
C_R = q_L * L_R / (u_v * p["W"] * p["H"]) * 2.0
return C_D_conc + C_R + 25.0
def pmp_signal_update(self, tls_id, concentrations):
"""Pontryagin signal control (Module 13) with pollution penalty."""
queues = []
for phase_idx in range(4):
controlled_lanes = traci.trafficlight.getControlledLanes(tls_id)
q = sum(traci.lane.getLastStepHaltingNumber(l)
for l in controlled_lanes[phase_idx::4])
queues.append(q)
# Optimal phase: minimise queue + lambda * concentration
lam = 0.1 # pollution weight
best_phase = np.argmin(queues) # simplified
return best_phase
def run(self, n_steps=3600):
self.connect()
for _ in range(n_steps):
traci.simulationStep()
# ... apply control logic each step
self.step += 1
traci.close()17.2.6 Python: Build .net.xml and .rou.xml
This code generates valid SUMO network and route files programmatically without requiring a SUMO installation. It creates a simple grid network and random vehicle routes.
Build SUMO Network & Routes Programmatically
PythonClick Run to execute the Python code
Code will be executed with Python 3 on the server
17.2.7 Key Takeaways
- The pipeline OSMnx → netconvert → randomTrips.py → SUMO provides a complete path from real-world maps to microscopic simulation.
- Critical netconvert flags (--junctions.join, --tls.guess, --roundabouts.guess) are essential for converting noisy OSM data into a valid simulation network.
- Demand generation via randomTrips.py with --fringe-factor produces realistic through-traffic patterns; OD matrices provide higher fidelity.
- TraCI enables real-time coupling between SUMO and external controllers, including Module 13 signal optimisation and Module 16 pollution estimation.
- All SUMO input/output files are XML-based, making them straightforward to generate and parse programmatically.