Skip to content

Commit 36d1d9f

Browse files
committed
Generate emissions.txt for hbg6 feed
1 parent 842869d commit 36d1d9f

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ data/gtfs/%.merged.with_flex.gtfs: data/gtfs/%.merged.gtfs.zip
127127
$(info patching GTFS-Flex data into the GTFS feed)
128128
# todo: pick flex rules file based on GTFS feed
129129
docker run -i --rm -v $(HOST_MOUNT)/data/gtfs/$(@F):/gtfs derhuerst/generate-gtfs-flex:4 stadtnavi-herrenberg-flex-rules.js
130+
$(info generating emissions.txt)
131+
python3 scripts/generate_emissions_file.py $@
130132

131133
data/gtfs/%.merged.with_flex.gtfs.zip: data/gtfs/%.merged.with_flex.gtfs
132134
rm -f $@

scripts/generate_emissions_file.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import csv
2+
import sys
3+
from argparse import ArgumentParser
4+
from pathlib import Path
5+
6+
emissions_per_route_type = {
7+
3: {"avg_co2_per_vehicle_per_km": 85, "avg_passenger_count": 1}, # Bus
8+
0: {"avg_co2_per_vehicle_per_km": 37.7, "avg_passenger_count": 1}, # Interpretiere Tram, Streetcar, Light rail wie S-Bahn
9+
109: {"avg_co2_per_vehicle_per_km": 37.7, "avg_passenger_count": 1}, # S-Bahn
10+
2: {"avg_co2_per_vehicle_per_km": 54, "avg_passenger_count": 1}, # Intepretiere Rails (Long Distance) wie Regionalbahn
11+
106: {"avg_co2_per_vehicle_per_km": 54, "avg_passenger_count": 1}, # Regionalbahn
12+
1: {"avg_co2_per_vehicle_per_km": 2.6, "avg_passenger_count": 1}, # interpretiere Subway, Metro wie Stadtbahn
13+
403: {"avg_co2_per_vehicle_per_km": 2.6, "avg_passenger_count": 1}, # Stadtbahn
14+
4: {"avg_co2_per_vehicle_per_km": 2600, "avg_passenger_count": 1.4}, # Ferries
15+
7: {"avg_co2_per_vehicle_per_km": 2.6, "avg_passenger_count": 1}, # Funicular, Übernahme Wert Stadtbahn
16+
}
17+
18+
# Estimating CO2 emissions for funiculars:
19+
# VVS does not provide numbers neither for Seilbahn ("Außerhalb Tarifgebiet")
20+
# nor Zahnradbahn ("1.2km Fußweg (while it's 2.4km [1] or 1.6 fly distance)")
21+
# We assume it is approximately the Stadtbahn.
22+
# [1] https://herrenberg.stadtnavi.de/reiseplan/Marienplatz%2C%20Stuttgart%3A%3A48.7642519%2C9.1681266/Degerloch%2C%20Stuttgart%3A%3A48.7485636%2C9.1682656/walk?time=1731217647
23+
24+
# Estimating CO2 emissions for ferries:
25+
# CO2 emissions for ferries are barely available. We deduced them from a single datapoint
26+
# we found: 2.8l per car for the Horgener Zürichsee-Ferry [1]. As the distance between Horgen
27+
# and Meilen is, according to OSM exactly 2.8km, we assume it's 1l/km. As 1l Diesel
28+
# corresponds to 2.6kg CO2 [3], that corresponds to 1l/PKWkm*2600g => 2600g/km.
29+
# Per car we assume a medium occupancy of 1.4
30+
# [1] https://www.tagesanzeiger.ch/die-faehre-verbraucht-einen-liter-fuer-2-8-kilometer-pro-auto-737265054748
31+
# [2] https://www.openstreetmap.org/directions?engine=graphhopper_foot&route=47.25919%2C8.60453%3B47.26770%2C8.63839
32+
# [3] https://www.econologie.de/Emissions-co2-Liter-Kraftstoff-Benzin-oder-Diesel-gpl/
33+
34+
35+
36+
def eprint(*args, **kwargs):
37+
print(*args, file=sys.stderr, **kwargs)
38+
39+
def map_to_standard_route_type(extended_route_type: int) -> int:
40+
if extended_route_type < 15:
41+
return extended_route_type
42+
if extended_route_type >= 400 and extended_route_type < 500:
43+
return 1
44+
if extended_route_type >= 100 and extended_route_type < 200:
45+
return 2
46+
if extended_route_type >= 700 and extended_route_type < 800:
47+
return 3
48+
if extended_route_type >= 1400 and extended_route_type < 1500:
49+
return 7
50+
eprint(f"WARN: no mapping to standard route_type for {extended_route_type}")
51+
return extended_route_type
52+
53+
def print_mappings(used_route_types: set[int]):
54+
eprint("The following co2 emissions per route type where used:")
55+
eprint(f'route_type|avg_co2_per_vehicle_per_km|avg_passenger_count')
56+
eprint(f'----------|--------------------------|-------------------')
57+
58+
for route_type in used_route_types:
59+
mapped_route_type = map_to_standard_route_type(route_type)
60+
emissions = emissions_per_route_type[mapped_route_type]
61+
avg_co2_per_vehicle_per_km = emissions['avg_co2_per_vehicle_per_km']
62+
avg_passenger_count = emissions['avg_passenger_count']
63+
eprint(f'{route_type: 10}|{avg_co2_per_vehicle_per_km: 26}|{avg_passenger_count: 19}')
64+
65+
def generate_emissions_file(routes_file_path: str, emissions_file_path: str) -> None:
66+
used_route_types = set()
67+
with open(routes_file_path) as f:
68+
reader = csv.DictReader(f)
69+
70+
emissions = []
71+
for route in reader:
72+
route_type = int(route["route_type"])
73+
used_route_types.add(route_type)
74+
standard_route_type = map_to_standard_route_type(route_type)
75+
route_id = route["route_id"]
76+
route_type_emissions = emissions_per_route_type.get(route_type, emissions_per_route_type.get(standard_route_type))
77+
if not route_type_emissions:
78+
eprint(f"Error: no emissions defined for route_type {route_type} or route {route_id}")
79+
else:
80+
route_emission= {}
81+
route_emission["route_id"] = route_id
82+
route_emission["avg_co2_per_vehicle_per_km"] = route_type_emissions['avg_co2_per_vehicle_per_km']
83+
route_emission["avg_passenger_count"] = route_type_emissions['avg_passenger_count']
84+
emissions.append(route_emission)
85+
86+
with open(emissions_file_path, 'w') as f:
87+
fieldnames = ['route_id', 'avg_co2_per_vehicle_per_km', 'avg_passenger_count' ]
88+
writer = csv.DictWriter(f, fieldnames=fieldnames)
89+
90+
writer.writeheader()
91+
for route_emisions in emissions:
92+
writer.writerow(route_emisions)
93+
94+
print_mappings(used_route_types)
95+
96+
if __name__ == "__main__":
97+
parser = ArgumentParser(prog='generate_emissions_file')
98+
parser.add_argument('gtfs_dir', help='Path to GTFS directory')
99+
args = parser.parse_args()
100+
generate_emissions_file(Path(args.gtfs_dir, 'routes.txt'), Path(args.gtfs_dir, 'emissions.txt'))
101+
102+

0 commit comments

Comments
 (0)