Initial: Mesh-Configs vom 03.09.2026 01:23
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
# GTFS-Build-Notizen (aus echtem Lauf 2026-08, Urlaub-Webseite)
|
||||
|
||||
Konkrete SQL/Schema/Logik, die in dieser Session verifiziert funktioniert haben.
|
||||
|
||||
## SQLite-Schema (eine DB, 3 Tabellen + Indizes)
|
||||
|
||||
```sql
|
||||
CREATE TABLE stops(stop_id TEXT PRIMARY KEY, stop_name TEXT, stop_lat REAL, stop_lon REAL);
|
||||
CREATE TABLE trips(trip_id TEXT PRIMARY KEY, route_id TEXT, service_id TEXT);
|
||||
CREATE TABLE st(stop_id TEXT, trip_id TEXT, seq INT, arr TEXT, dep TEXT);
|
||||
CREATE INDEX idx_st_stop ON st(stop_id);
|
||||
CREATE INDEX idx_st_trip ON st(trip_id);
|
||||
CREATE INDEX idx_st_seq ON st(trip_id, seq);
|
||||
```
|
||||
|
||||
Echte Mengen aus `r.und.s.bahnen.zip` (Regional+S-Bahn, kein ICE):
|
||||
- stops.txt: 16.310 Haltestellen → DB 15.083 (dedupliziert)
|
||||
- trips.txt: 110.087 Rohzeilen → DB 964 (trips.txt hat nur selten-service; st ist die Wahrheit)
|
||||
- stop_times.txt: 82 MB → st 1.591.002 Zeilen, 110.087 eindeutige trip_id, 8.558 eindeutige stop_id
|
||||
|
||||
## Spaltenreihenfolgen (GTFS ist NICHT standardisiert was Namen angeht — Header lesen!)
|
||||
|
||||
- **stops.txt:** `stop_name, parent_station, stop_id, stop_lat, stop_lon, location_type, platform_code`
|
||||
→ stop_id = Spalte 2; parent_station = Spalte 1 (Gruppen-ID). Viele Stops haben leeres parent_station.
|
||||
Import-Fallback: `sid = p[2] if p[2] else p[1]` (bevorzugt stop_id, sonst parent_station).
|
||||
- **trips.txt:** `route_id, service_id, trip_id` → trip_id = Spalte 2.
|
||||
- **stop_times.txt:** `trip_id, arrival_time, departure_time, stop_id, stop_sequence, ...`
|
||||
→ stop_id = Spalte 3, arr = 1, dep = 2, seq = 4.
|
||||
|
||||
## Bahnhofs-Alias (kritisch)
|
||||
|
||||
Ein Bahnhof kann mehrere stop_id-Zeilen haben (z.B. `Köln Hbf` = 222681 UND 452576). Nur EINE ist in
|
||||
`stop_times` aktiv. Suche-Methode:
|
||||
```sql
|
||||
-- aktive ID ermitteln
|
||||
SELECT stop_id, stop_name FROM stops WHERE stop_name = '<Name>';
|
||||
-- dann je Kandidat:
|
||||
SELECT COUNT(*) FROM st WHERE stop_id = '<id>'; -- >0 => aktiv
|
||||
```
|
||||
Beispiel: Aachen Hbf → 548582 (aktiv), Köln Hbf → 452576 (aktiv; 222681 tot). Saarbrücken Hbf hat 10 IDs, davon 9 aktiv.
|
||||
|
||||
## Zeit-basierter Dijkstra (Kern)
|
||||
|
||||
Vorladen (einmal):
|
||||
```python
|
||||
from collections import defaultdict
|
||||
deps_by_stop = defaultdict(list) # stop_id -> [(dep_sec, trip_id, seq)] sortiert
|
||||
stops_by_trip = defaultdict(list) # trip_id -> [(seq, stop_id, arr_sec, dep_sec)] sortiert
|
||||
# Befülle beide in einem Durchlauf über st; sortiere jede Liste.
|
||||
```
|
||||
|
||||
Suche:
|
||||
```python
|
||||
INF = float('inf')
|
||||
dist = defaultdict(lambda: INF); dist[von_id] = dep0
|
||||
heap = [(dep0, von_id)]
|
||||
while heap:
|
||||
t, stop = heapq.heappop(heap)
|
||||
if t != dist[stop]: continue
|
||||
if stop == nach_id: break
|
||||
for dep_s, tid, seq in deps_by_stop[stop]:
|
||||
if dep_s < t: continue
|
||||
for (sseq, sid, arr_s, dep2) in stops_by_trip[tid]:
|
||||
if sseq <= seq: continue
|
||||
if arr_s < dist[sid]:
|
||||
dist[sid] = arr_s; heapq.heappush(heap, (arr_s, sid))
|
||||
# Ziel-Abbruch + dist[stop]-Guard sind ESSENZIELL für 110k Trips.
|
||||
```
|
||||
|
||||
## Verifikations-Referenz (echte GTFS-Ergebnisse 2026-08)
|
||||
|
||||
- Aachen Hbf → Köln Hbf: **1h 12min, 1 Umstieg, 09:00 → 10:12** ✅ (real plausibel)
|
||||
- Trier Hbf → Saarbrücken Hbf: nur direkt via trips, keine aktiven stops-Zuordnung nötig
|
||||
|
||||
## Wichtige Erkenntnis zur Datenlage
|
||||
|
||||
Diese GTFS („R- und S-Bahnen") deckt Bahn-Knoten ab, aber **nicht alle**: Remscheid-Lennep Bf und
|
||||
Frankfurt (Main) Hauptbahnhof hatten in der `st`-Tabelle 0 aktive Trips → müssen per Alias oder
|
||||
Alternativ-Bahnhof (nächster aktiver) aufgelöst werden, oder liegen außerhalb des Feeds. Vor dem
|
||||
Neuberechnen ALLER Ziele: prüfen welche Kern-Bahnhöfe aktiv sind, fehlende via Nachbar-Bahnhof mappen.
|
||||
@@ -0,0 +1,39 @@
|
||||
# GTFS-Neuberechnung — harte Lehren aus urlaub.perfekt-ohne-en.de (2026-08-19)
|
||||
|
||||
Ergänzung zum main SKILL.md. Diese Notes stammen aus dem echten Großumbau der
|
||||
Fahrzeiten auf der Zugverbindungs-Webseite und sind die Dinge, die NICHT sofort
|
||||
ersichtlich sind. (Haupt-SKILL.md-Patch war durch eine Schreib-Sperre blockiert;
|
||||
diese Erkenntnisse gehören trotzdem zu diesem Umbrella.)
|
||||
|
||||
## Die 3 Teambefunde, die den Dijkstra erst korrekt machten
|
||||
|
||||
1. **Geo-Stop-Merging** — Ein Bahnhof hat MEHRERE aktive stop_ids in der st-Tabelle
|
||||
(Saarbrücken Hbf: 6 IDs = Plattform-/Gleis-Stops). `stops.txt` stop_id ist nicht
|
||||
eindeutig. Fix: Stops < ~350m Luftlinie zu einer Gruppe zusammenfassen; der Router
|
||||
expandiert von/zu allen Gruppen-IDs.
|
||||
2. **Umstiegsbuffer** — Ohne min ~4min Transfer-Puffer erlaubt Dijkstra physisch
|
||||
unmögliche Anschlüsse (Ankunft 10:05 → Abfahrt 10:04) → zu optimistische Zeiten.
|
||||
Buffer NUR beim Umstieg, nicht beim Start: `dep_s < t + (BUFFER if t>dep0 else 0)`.
|
||||
3. **Profil-Query (Min)** — Feste Abfahrtszeit (09:00) liefert systematisch zu
|
||||
langsame Werte, wenn die früheste Verbindung zufällig viele Umstiege hat.
|
||||
Abfahrten über den Tag scannen (z.B. stündlich 06-22) und MIN(Fahrzeit) nehmen.
|
||||
|
||||
## Performance: EIN Dijkstra je Start statt je Verbindung
|
||||
|
||||
- Naiv: 12.201 Verbindungen × ~17 Abfahrtsstichproben = ~207k Dijkstra-Läufe → ~18h.
|
||||
- Korrekt: EIN Dijkstra je eindeutigen Start (191 Starts), der ALLE Ziele gleichzeitig
|
||||
erreicht (`spread(start_ids)` → dict stop→ankunft). Danach Werte ablesen → ~10 Min.
|
||||
- Commit NUR am Ende, und nur markierte Ziele (0.0h / mehrdeutig) neu verteilen.
|
||||
|
||||
## Start ohne Bahnhof (z.B. Radevormwald)
|
||||
|
||||
Städte ohne eigene Bahnhofs-ID matchen in stops nicht. Löse über den nächstgelegenen
|
||||
Bahnhof (Radevormwald → Remscheid-Lennep Bf) und addiere die Bus-Anreise (~20min):
|
||||
`Gesamtzeit = BUS_MIN + Dijkstra(Bahnhof → Ziel)`.
|
||||
|
||||
## Ziel-Eindeutigkeit: Berlin-Falle
|
||||
|
||||
Mehrdeutige Zielnamen (z.B. "Berlin") matchen falsche/lokalnahe Stops → ungenaue
|
||||
oder sogar 0.0h-Zeiten. Abbilden auf eindeutiges "… Hbf":
|
||||
`UPDATE verkehr SET nach='Berlin Hbf' WHERE nach='Berlin';`
|
||||
0.0h-Zeilen sind als Fehler zu behandeln und neu zu berechnen, nicht zu akzeptieren.
|
||||
Reference in New Issue
Block a user