Commit 25b921f8 authored by Paul Rougieux's avatar Paul Rougieux
Browse files

Specification road closure

parent 92b64eb4
Loading
Loading
Loading
Loading
Loading
+89 −0
Changes for events/20261021/spec_road_closure_cost.md: 89 added lines, 0 removed lines.
Original line number Diff line number Diff line
# Specification: cost of closing the B19 Kocher bridge

Background: Johannes Bleher, *Road Closure Costs*
(https://johannes-bleher.de/projects/RoadClosureCosts/). This is a simplified
first implementation for the 2026-10-21 event.

## Question

What is the aggregate cost of the extra travel time when the B19 Kocher
bridge is closed?

## Scenario

- Full closure of both directions for 365 days. Also report the cost per day
  so other durations can be scaled.
- Every trip that used the bridge takes the shortest alternative route. We
  assume free-flow speeds, no congestion on the detour and no cancelled trips.
  The result is therefore a **lower bound**.

## Data

| Input | Source | Note |
|---|---|---|
| Traffic counts | BASt 2023 hourly counts, `2023_B_S.zip` (in `open_data/road_data/data/`, git ignored) | `;` separated, values padded with spaces, `-1` with flag `x` means missing |
| Count station location | BASt Zählstellenverzeichnis (station list with coordinates) | Still to download and join on `TKNR` |
| Road network | OpenStreetMap via OSMnx | Drive network in a buffer around the bridge |
| Population | Municipality population and centroids (Destatis / BKG VG250) | For the OD weights |

## Method

1. **Locate** the bridge (a node or edge in OSM) and the nearest BASt station
   on the B19. Compute the annual average daily traffic (DTV) for each
   direction from the hourly file, split into Pkw and Lkw.
2. **OD pairs.** Take municipality centroids within a buffer (default 30 km)
   and snap them to the network. Keep the pairs whose shortest route uses the
   bridge. Weight each pair with a gravity model,
   w_ij = pop_i · pop_j / d_ij². This is one solution made up as a starting
   point; we do not explore alternatives.
3. **Routing** with networkx. For each kept pair compute the travel time with
   the bridge (t⁰) and without it (t¹), plus the distances d⁰ and d¹.
   Speeds come from OSM `maxspeed`, or a default per road type when it is
   missing.
4. **Scale** the station DTV across the pairs in proportion to w_ij. This
   gives the vehicles per day on each pair, split Pkw/Lkw.
5. **Cost per day** = Σ_ij vehicles_ij · (t¹ − t⁰) · VoT, computed per
   vehicle class. Multiply by 365 for the annual cost.

## Cost parameters (the user chooses)

The value of time (VoT) is set in a configuration file. There are two
implementations, and the user picks one:

- **Simple:** round values, Pkw €10/h and Lkw €40/h, with low and high
  values for the sensitivity analysis.
- **BVWP 2030:** official German rates by vehicle class and trip purpose.

Optional additional costs (off by default, to be switched on later):

- distance-based vehicle operating cost (fuel, wear) on the extra km
  (d¹ − d⁰), € per km for Pkw and Lkw;
- a congestion factor on detour times;
- CO₂ cost of the extra km.

## Outputs

An HTML page in `events/20261021/`, linked from the site built by
`scripts/build_site.py`, showing:

- a **map** (Folium/Leaflet) of the bridge, the count station and the main
  OD routes with and without the bridge;
- **headline numbers**: extra vehicle-hours per day, € per day and € per
  year, split Pkw/Lkw;
- a **sensitivity table** covering low, central and high VoT, BVWP versus
  simple rates, and buffer sizes of 20, 30 and 50 km.

## Code layout

Python scripts in `events/20261021/`, run in order:
`01_counts.py` → `02_network_od.py` → `03_routing.py` → `04_cost.py` →
`05_page.py`. Parameters live in one `config.yaml` (buffer, VoT set, optional
costs).

## Open questions

- The exact bridge location and the BASt station ID on the B19 near it.
- How to read `Fahrtzw` (s/u/w) and the flags `s` and `a`; check the BASt
  documentation. Should the DTV use all days, or workdays only?
- Is the gravity weight good enough, or should we later calibrate it with
  counts from other stations (the extension in Bleher's paper)?