---
title: Railways
---

This page lists tools that are useful for [railway simulation](../Simulation/Railways.md).

# generateRailSignalConstraints.py

Generate [constraints that enforce a given railway schedule](../Simulation/Railways.md#schedule_constraints).
Example:

```
<SUMO_HOME>/tools/generateRailSignalConstraints.py -r <input-route-file> -n <input-net-file> -a <input-stop-file> -o <output-file>
```

## Generated Constraints

Different types of constraints are generated in different cases:

### 1. predecessor
When two vehicles stop subsequently at the same busStop (trainStop) and they reach that stop
via different routes, the switch where both routes merge is identified and a
constraint is created for the rail signals that guard this merging switch:
    The vehicle B that arrives at the stop later, must wait (at its signal Y)
    for the vehicle A that arrives first (to pass its respective signal X)
    This uses the 'arrival' attribute of the vehicle stops

A complication arises if the signal of the first vehicle is passed by other
trains which are en route to another stop. This makes it necessary to record a
larger number of passing vehicles within the simulation (controlled by the
limit attribute). The script attempts to determine the necessary limit value by
identifying all vehicles that pass the signal X en route to other stops between
the time A and B reach their respective signals (counting backwards from the
next stop based on "arrival"). To account for delays the
options --delay and --limit can be used to override the limit values

A more complicated case arises when the next stop after the merging switch differs for
both trains even though their routes are the same. In this case the ordering of
the trains must be deduced from their next common stop and the algorithm adds
a "virtual" intermediateStop directly after the switch to "normalize" the input.

### 2. insertionPredecessor
Whenever a vehicle B departs at a stop (assumed to coincide with the "until"
attribute of its first stop), the prior train A that leaves this stop is
identified (also based on "until"). Then a constraint is created that prevents
insertion of B until train A has passed the next signal that lies beyond the
stop.

These constraints are also needed in the context of parking-stops because these
have the potential to alter train ordering:

If vehicle A has a parking stop with 'ended' time and vehicle B has a
parking stop at the same location without 'ended' (only an 'until' time),
an insertionPredecessor constraint is created for B to ensure that A leaves
first. This is because availability of an 'ended' value implies that the even is
in the past whereas the lack of the value indicates that the stop is still in
the future.

In the case where an intermediateStop (see above) is also a parking stop, an
insertionPredecessor constraint is added if the parking vehicle is scheduled to
go second.

### 3. foeInsertion
Whenever a vehicle A departs at a stop (assumed to coincide with the "until"
attribute of its first stop), the latter train B that enters this stop is
identified (also based on "until"). Then a constraint is created that prevents
B from entering the section with the stop until A has passed the next signal that lies beyond the
stop.

### 4. insertionOrder
Whenever two vehicles depart at the same stop and their until/ended times at that stop
are in a different order from their departure times, an insertionOrder constraint
is added the delays insertion to achieve the desired order.
This may happen if departure times reflect the schedule
but until/ended times reflect post-facto timing (see below)

### 5. bidiPredecessor
Whenever two trains approach the same track section from different directions, a bidiPredecessor
constraint may optionally be generated to enforce the order of entering that section based on the
stop arrival times that follow the section on the respective side.
(stop arrival times must be corrected for the estimated travel time between the end of the conflict section
and the stop)

## Inconsistencies

Inconsistent constraints may arise from inconsistent input and cause simulation
deadlock. To avoid this, the option --abort-unordered can be used to avoid
generating constraints that are likely to be inconsistent.
When the option is set the ordering of vehicles is cross-checked with regard to
arrival and until times:

Given two vehicles A and B which stop at the same location, if A arrives at the
stop later than B, but A also leaves earlier than B, then B is "overtaken" by A.
All subsequent stops of B are marked as invalid and will not
participate in constraint generation. If the stop where overtaking took place
doesn't have a 'started' value (which implies that the original schedule is
inconsistent), then this stop is also marked as invalid.

If two vehicles have a 'parking'-stop with the same 'until' time at the same
location, their stops will also be marked as invalid since the simulation cannot
enforce an order in this case (and local desired order is ambiguous).

Another kind of inconsistency is indicated by 'ended' times that lie ahead of
the 'until' time of the respective stop by a significant margin (--.
This situation may correspond to the actions of
a real-life dispatcher. In such a case, the must not be constraint any further
since it is no longer running according to the schedule.

## Post-Facto Stop Timings

When simulating the past (i.e. to predict the future), additional timing data
besides the scheduled arrival and until times may be available and included in
the 'started' and 'ended' attributes for each stop.
They can be used to detect changes in train order that occurred during the actual
train operation and which must be taken into account during constraint
generation to avoid deadlock.
If train A has 'started' information for a
stop while train B has not, this implies that A has reached the stop ahead of B.
Likewise, both trains may have 'started' information but in the reverse order
compared to the schedule.
For all stops with complete started,ended information, those times can be used
as an updated schedule (replacing arrival and until). However, if an order
reversal was detected for a train, no constraints based on the old schedule
should be generated anymore (stops are ignored after started,ended information ends)

## Further Options
If constraints shall be modified during the simulation (traci.trafficlight.swapConstraints)
it may be useful to add additional constraints which would otherwise be
redundant. This can be accomplished by setting option --redundant with a time
range. When set, trains that follow a constrained train within the given time
range (and which would normally be constrained implicitly by their leading
train) will also receive a constraint. In this case option --limit must be used
to ensure that all constraint foe vehicles are recorded during the simulation.



# scheduleStats.py

Compare arrival and departure at stops between an input schedule (route-file) and
simulation output (stop-output). The results will be printed on the command line.

Example:
```
<SUMO_HOME>/tools/output/scheduleStats.py -r <input-route-file> -s <stop-file>
```

Options:

- **--xml-output FILE** (**-o**): write statistics to FILE in xml format
- **--statistic-type** (**-t**): select among statistics to be computed
  - 'd' : stop depart delay
  - 'a' : stop arrival delay
  - 's' : stop duration difference
  - 'de' : stop depart delay compared to 'ended' in input
  - 'as' : stop arrival delay compared to recorded 'started' in input
  - 't'  : traveltime according to schedule versus traveltime in simulation (between stops)
  - 'T'  : traveltime according to recording versus traveltime in simulation (between stops)

- **--group-by** (**-g**): group results by one or more attributes (vehID,tripId,stopID,priorStop)
- **--group-statistic-type** (**-T**): select among statistics over the group values (i.e. to compare the groups by their mean depart delay). permitted values are mean, median, min, max
- **--histogram FLOAT** (**-i**): add a histogram with the given bin width
- **--group-histogram FLOAT** (**-I**): add a histogram over the group values (when using **-g**) with the given bin width

Examples:
```
<SUMO_HOME>/tools/output/scheduleStats.py -r <input-route-file> -s <stop-file> -t d -i 50
<SUMO_HOME>/tools/output/scheduleStats.py -r <input-route-file> -s <stop-file> -t a -g stopID -T median -I 10
```

# checkReversals.py

This tool counts the number of reversals per vehicle and also the number of reverals that occur per edge.

Example:
```
<SUMO_HOME>/tools/route/checkReversals.py -n <input-net-file> -r <input-route-file> -o reversals.xml
```

# plotStops.py

Plot a public transport schedule (either planned or actual timings). This script is a wrapper around [plotXMLAttributes.py](Visualization.md#public_transport_schedule) with the main advantage of defining the ordering of stops along a specified line and aggregating data by the human-readable stop name rather than track-specific stop positions.
Several options are passed directly to [plotXMLAttributes.py](Visualization.md#plotxmlattributespy)

The following examples show how to work with files created by [osmWebWizard.py](../Tutorials/OSMWebWizard.md) (using [ptlines2fows.py](Misc.md#ptlines2flowspy) in the background). The input files can be bound in the [SUMO 2025 User Conference Tutorial](https://sumo.dlr.de/daily/sumo2025_tutorial.zip).

The following arguments are necessary:

- **-r, --route-file**: a file that defines the ordering of the stops along the x-axis
- **-i, --veh-id**: the id of a vehicle, trip or flow from the route-file to select which route shall be plotted

Also recommended is setting option **-a**,--stop-file** with the definition of public transport stops for reading their names.

Example: loading simulation inputs
```
<SUMO_HOME>/tools/visualization/plotStops.py -r osm_pt.rou.xml -a osm_stops.add.xml -i pt_light_rail_S46:1 -v --legend --filter-ids \*S46\*
```
<img src="../images//S46_input_flows.png" width="800px"/>


Example: after running the simulation with **--vehroute-output vehroutes.xml**
```
<SUMO_HOME>/tools/visualization/plotStops.py -r vehroutes.xml -a osm_stops.add.xml -i pt_light_rail_S46:1.0 -v --legend --filter-ids \*S46\*
```
!!! note
    Here, option **-i** references a vehicle id rather than a flow id as in the prior example

<img src="../images/S46.png" width="800px"/>

Example: after running the simulation with **--stop-output stopinfos.xml** for reading actual timing.
Such a file is loaded by adding the option **-s, --stopinfo-file** to the options from the previous example.
```
<SUMO_HOME>/tools/visualization/plotStops.py -r vehroutes.xml -a osm_stops.add.xml -i pt_light_rail_S46:1.0 -s stopinfos.xml -v --legend --filter-ids \*S46\*
```

<img src="../images/S46_actual.png" width="800px"/>

# createOvertakingReroutes.py

Parses a network and routefile to find overtaking locations and create <overtakingReroute> elements
This tool is meant to generate rerouter definitions for automated and dynamic [train-overtaking](../Simulation/Rerouter.md#rerouting_to_a_railroad_siding_to_be_overtaken_by_a_faster_train).

Example call
```
<SUMO_HOME>/tools/trigger/createOvertakingReroutes.py -n net.net.xml -r input_routes.rou.xml -o out.add.xml
```

The tool analyzes the rail network along loaded routes to find passing loops (sidings) that match a range of criteria:

- there must be a signal that guards the exit of the siding
- the total length of the siding may not exceed a configurable threshold (**--max-length**)
- the length of the siding before the signal must have a minimum track length (**----min-length**)
- the may not be used by oncoming traffic (configurable with **--exclude-reverse-usage**)
- they may not be used heavily by the loaded routes (configurable with **--exclude-usage**)
- the sequence of tracks that form the siding may not include a train reversal (configurable with **--reversal-penalty**)

For every siding that is found an new rerouter element is created. Since trains that can be overtaken may elect to wait at downstream siding, each rerouter may have more than one `<overtakingReroute>`-definition. This permits a runtime choice of using the current or a later siding (which may again present another choice).

# patchRailConflicts.py

This tool modifies junction types, edge offsets and connection attributes in a network to ensure that conflicts between different tracks are guarded by rail signals. It's main use is for patching tram networks where real-world data on signal infrastructure is often lacking.
The tool works by identifiyng conflict junctions (i.e. switches and crossings) and change their type `rail_signal` and optionally shifting the waiting position to be somewhat ahead of the conflict.

!!! caution
    When using this tool for convential rail operations, option **--split-offset** should be set to ensure that signals are created well in advance of switches and crossings to account for overrun distance (*Durchrutschweg*).

Example call
```
<SUMO_HOME>/tools/net/patchRailConflicts.py -n input_net.net.xml -o output_net.net.xml
```

The following options are available

- **--vclass** (default *tram*): defines which conflict points are considered for patching
- **-k**, **--keep-junction-type** (default *traffic_light,traffic_light_unregulated,rail_signal*): defines which junctions are to be kept unmodified
- **-e**, **--end-offset** (default *0*): If set, the waiting position of trains will be moved back from the conflict point by setting [edge attribute `endOffset`](../Networks/PlainXML.md#edge_descriptions).
- **-j**, **--join-distance** (default *200*): Identifies clusters of conflict points within the given range and only guards connections that enter the cluster from the outside

# patchRailPriorities.py

Identifies single-track rail lines that are used in both directions and attempts to find sidings for passing in
opposite directions. For found sidings
- the routingType and priorities in the network are patched so that trains prefer driving on the right
- if there is a ptStop on the main line but not on the siding, a new ptStop is added
- if the new stop is not guarded by rail signals, new signals are added to the network

Example call
```
<SUMO_HOME>/tools/net/patchRailConflicts.py -n input_net.net.xml -r input_routes.rou.xml -s input_stops.add.xml -o output_net.net.xml -O output_stops.add.xml --add-stop-signals
```

The algorithm for finding and filtering sidings uses the same options as [createOvertakingReroutes.py](#createovertakingreroutespy). If option **--add-stop-signals** is set, sidings are also accepted if they do not have a signal yet.

# abstractRail.py

Converts a geodetical rail network into an abstract (schematic) rail network. See [full documentation](Net.md#abstractrailpy).
