This section describes the data sources, models, and assumptions behind the analysis presented in each dashboard.
pvmt.toml.The exact sources and endpoints used for a given example are listed in that example's Config tab.
Each road classification decays independently via
PCI(t) = PCI₀ · exp(−k · t)
where k is an annual decay constant that depends on the road
classification. Higher-class roads (motorway, trunk, primary) decay more
slowly than lower-class roads (residential, service) because they are
built to thicker, more rigorous design standards and typically receive
more frequent maintenance. Default values are derived from LTPP data
reported in FHWA-RD-01-156, Long-Term Pavement Performance and
ship as part of the forecast package; they are continental-US
averages and do not account for local climate, traffic, or
construction quality. A config may set a per-city decay_rate to tune
for local conditions (e.g. freeze/thaw or road salt); that override is
applied as the rate for a typical road and scales every road class
proportionally, so the per-class ordering (higher classes decay slower)
is preserved rather than flattened. Sidewalks
decay on a separate, slower track and are not treated as a highway class.
Treatment costs are banded by PCI: each band has a representative
$/sq m value, and costs between bands are linearly interpolated at the
tier midpoints, so the cost-versus-PCI curve is smooth rather than
step-shaped. Above the highest anchor (the midpoint of the preventive
tier) and below the lowest anchor (the midpoint of the reconstruction
tier), the cost is clamped to that anchor's value rather than
extrapolated. Default cost tiers are expressed in $/sq m and sourced
from FHWA treatment-selection guidance; they are calibration inputs, not
measurements, and local bid prices will differ. Roads and sidewalks use
independent cost tiers because the treatment economics differ
substantially.
PVMT ships with three comparison runs driven by annual funding level, all using the worst-first allocation strategy (budget is spent on the lowest-PCI segments first):
A do-nothing baseline (no spend, uncontrolled decay) is shown alongside the funded runs for comparison.
The forecast library also implements a preventive-first strategy (prioritize highest-PCI segments that are still in the preservation window), but the default UI comparisons do not exercise it. Preventive vs. worst-first allocation is governed by per-strategy efficiency multipliers; those multipliers are illustrative calibration constants chosen to reflect the direction and sign of the effect reported in FHWA-HIF-12-042, Pavement Preservation: Preserving our Investment — that $1 of preventive maintenance is reported to avoid $6–$10 of future reconstruction — not to reproduce that benefit-cost ratio as a single-year spending efficiency.
Optional compound annual growth applies to pavement area each year:
Area(y) = Area₀ · (1 + g)^y
where g is configured per city (default zero). This lets an example
model a city that is still expanding its street network; it does not
model demolition or removal.
The dashboard's Financials headline and the cross-city leaderboard report three solvency figures. They are computed on the roads/streets cohort only — the aggregate scenarios blend roads, parking, and sidewalks but cost the blend at road tiers, which would mis-price sidewalks, so an absolute dollar claim must be roads-only. They are derived from a worst-first run at the city's configured annual budget.
Insolvency year — the first forecast year in which the cumulative deferred backlog reaches one full year of network-treatment need (the year-1 need: the cost to treat the entire network once). Because the deferred backlog is a monotonically non-decreasing accumulator (see below), once a city is a whole network-treatment behind it does not recover within the model, so this is the "unrecoverable" threshold. A city whose backlog never reaches it is reported as solvent through the horizon. This is deliberately not "the first year need exceeds spend": year-1 need is the cost to treat the entire network, far above any real budget, so that test trips in year 1 for virtually every city and cannot distinguish a slightly-underfunded city from a badly- underfunded one. Reported only when a current budget is configured.
Hold-steady (break-even) budget — the smallest constant annual budget whose final deferred backlog is within a small relative tolerance (a fraction of year-1 need) of zero. Found by bisection over budget; the search's upper bound is the peak do-nothing annual need over the horizon, which is sufficient to fully fund every year.
Funding gap — (break-even − current budget) / current budget,
the primary cross-city ranking metric. Negative when a city already
budgets at or above its hold-steady level. Reported only when a current
budget is configured.
Three caveats apply to these figures specifically:
annual_spend series can exceed the configured budget. The
allocator routes leftover budget on a fully-funded cohort into extra
PCI recovery (a surplus branch), and that extra is counted as spend.
So an annual_spend above current_budget in early years is expected,
not an error.cost_tiers curve that violates this could make
the bisection overstate the break-even budget — a conservative
direction (it never understates the gap).docs/architecture.md
for the ingest and compute pipeline.# Denver Metro, CO — fast-growing Front Range with freeze/thaw climate
#
# The Denver metro's high-altitude freeze/thaw cycles accelerate pavement
# deterioration (higher decay_rate), while the region's rapid population
# growth expands the road network year over year (positive growth_rate).
#
# Techniques demonstrated:
# - Climate-tuned decay_rate (0.06) for freeze/thaw.
# - growth_rate (0.015) models an expanding network in the forecast.
# - boundary_relation_id for Denver, whose admin boundary Nominatim
# returns only as a place=city node (see the [[cities]] note below).
#
# Overpass-only. Expect ~8 Nominatim + Overpass pulls for `pvmt all ingest`.
config_id = "denver-metro-co"
[grid]
hex_edge_m = 100
[forecast]
decay_rate = 0.06
growth_rate = 0.015
years = 15
[export]
title = "Denver Metro Pavement Analysis"
[[cities]]
name = "Denver, CO"
#@cite CAPA 2025 Transportation Infrastructure Summary
#@cite https://capa.memberclicks.net/assets/docs/Transportation%20Infrastructure%20Summary%202025.pdf (accessed 2026-06-14)
forecast.initial_pci = 76
#@cite CAPA 2025 annual asphalt program $23,700,000; roads-only
#@cite https://capa.memberclicks.net/assets/docs/Transportation%20Infrastructure%20Summary%202025.pdf (accessed 2026-06-14)
forecast.current_budget = 23700000.0
overpass = true
# Nominatim returns a place=city node (Point geometry) for Denver; the
# admin_level=6 City-and-County boundary lives only as an OSM relation.
boundary_relation_id = 1411339
[[cities]]
name = "Aurora, CO"
#@cite CAPA 2025 Transportation Infrastructure Summary
#@cite https://capa.memberclicks.net/assets/docs/Transportation%20Infrastructure%20Summary%202025.pdf (accessed 2026-06-14)
forecast.initial_pci = 73
#@cite CAPA 2025 annual asphalt program $23,000,000; roads-only
#@cite https://capa.memberclicks.net/assets/docs/Transportation%20Infrastructure%20Summary%202025.pdf (accessed 2026-06-14)
forecast.current_budget = 23000000.0
overpass = true
[[cities]]
name = "Lakewood, CO"
#@cite CAPA 2025 Transportation Infrastructure Summary
#@cite https://capa.memberclicks.net/assets/docs/Transportation%20Infrastructure%20Summary%202025.pdf (accessed 2026-06-14)
forecast.initial_pci = 76
#@cite CAPA 2025 annual asphalt program $7,638,144; roads-only
#@cite https://capa.memberclicks.net/assets/docs/Transportation%20Infrastructure%20Summary%202025.pdf (accessed 2026-06-14)
forecast.current_budget = 7638144.0
overpass = true
[[cities]]
name = "Arvada, CO"
#@cite CAPA 2025 Transportation Infrastructure Summary, PCI 44
#@cite https://capa.memberclicks.net/assets/docs/Transportation%20Infrastructure%20Summary%202025.pdf (accessed 2026-06-14)
forecast.initial_pci = 44
#@cite CAPA 2025 annual asphalt program $10,000,000; roads-only
#@cite https://capa.memberclicks.net/assets/docs/Transportation%20Infrastructure%20Summary%202025.pdf (accessed 2026-06-14)
forecast.current_budget = 10000000.0
overpass = true
[[cities]]
name = "Westminster, CO"
#@cite CAPA 2025 Transportation Infrastructure Summary, PCI 54
#@cite https://capa.memberclicks.net/assets/docs/Transportation%20Infrastructure%20Summary%202025.pdf (accessed 2026-06-14)
forecast.initial_pci = 54
overpass = true
[[cities]]
name = "Centennial, CO"
#@cite CAPA 2025 Transportation Infrastructure Summary
#@cite https://capa.memberclicks.net/assets/docs/Transportation%20Infrastructure%20Summary%202025.pdf (accessed 2026-06-14)
forecast.initial_pci = 69
#@cite CAPA 2025 annual asphalt program $8,350,000; roads-only
#@cite https://capa.memberclicks.net/assets/docs/Transportation%20Infrastructure%20Summary%202025.pdf (accessed 2026-06-14)
forecast.current_budget = 8350000.0
overpass = true
[[cities]]
name = "Boulder, CO"
#@cite CAPA 2025 Transportation Infrastructure Summary, 2023 data
#@cite https://capa.memberclicks.net/assets/docs/Transportation%20Infrastructure%20Summary%202025.pdf (accessed 2026-06-14)
forecast.initial_pci = 77
#@cite CAPA 2025 annual asphalt program $4,000,000; roads-only
#@cite https://capa.memberclicks.net/assets/docs/Transportation%20Infrastructure%20Summary%202025.pdf (accessed 2026-06-14)
forecast.current_budget = 4000000.0
overpass = true
[[cities]]
name = "Thornton, CO"
overpass = true
[grid]
hex_edge_m = 100.0
[display]
units = "imperial"
min_hex_area = 100.0
[export]
title = "Denver Metro Pavement Analysis"
coordinate_decimals = 0
[forecast]
initial_pci = 85.0
decay_rate = 0.06
growth_rate = 0.015
years = 15
[[forecast.cost_tiers]]
min_pci = 70.0
max_pci = 101.0
cost_per_sqm = 5.0
label = "preventive"
[[forecast.cost_tiers]]
min_pci = 40.0
max_pci = 70.0
cost_per_sqm = 50.0
label = "rehab"
[[forecast.cost_tiers]]
min_pci = 0.0
max_pci = 40.0
cost_per_sqm = 150.0
label = "reconstruction"
[[cities]]
name = "Denver, CO"
overpass = true
arcgis_url = ""
hex_edge_m = 0.0
boundary_relation_id = 1411339
allow_private_arcgis = false
[cities.forecast]
initial_pci = 76.0
decay_rate = 0.0
growth_rate = 0.0
years = 0
current_budget = 2.37e+07
[[cities]]
name = "Aurora, CO"
overpass = true
arcgis_url = ""
hex_edge_m = 0.0
boundary_relation_id = 0
allow_private_arcgis = false
[cities.forecast]
initial_pci = 73.0
decay_rate = 0.0
growth_rate = 0.0
years = 0
current_budget = 2.3e+07
[[cities]]
name = "Lakewood, CO"
overpass = true
arcgis_url = ""
hex_edge_m = 0.0
boundary_relation_id = 0
allow_private_arcgis = false
[cities.forecast]
initial_pci = 76.0
decay_rate = 0.0
growth_rate = 0.0
years = 0
current_budget = 7.638144e+06
[[cities]]
name = "Arvada, CO"
overpass = true
arcgis_url = ""
hex_edge_m = 0.0
boundary_relation_id = 0
allow_private_arcgis = false
[cities.forecast]
initial_pci = 44.0
decay_rate = 0.0
growth_rate = 0.0
years = 0
current_budget = 1e+07
[[cities]]
name = "Westminster, CO"
overpass = true
arcgis_url = ""
hex_edge_m = 0.0
boundary_relation_id = 0
allow_private_arcgis = false
[cities.forecast]
initial_pci = 54.0
decay_rate = 0.0
growth_rate = 0.0
years = 0
[[cities]]
name = "Centennial, CO"
overpass = true
arcgis_url = ""
hex_edge_m = 0.0
boundary_relation_id = 0
allow_private_arcgis = false
[cities.forecast]
initial_pci = 69.0
decay_rate = 0.0
growth_rate = 0.0
years = 0
current_budget = 8.35e+06
[[cities]]
name = "Boulder, CO"
overpass = true
arcgis_url = ""
hex_edge_m = 0.0
boundary_relation_id = 0
allow_private_arcgis = false
[cities.forecast]
initial_pci = 77.0
decay_rate = 0.0
growth_rate = 0.0
years = 0
current_budget = 4e+06
[[cities]]
name = "Thornton, CO"
overpass = true
arcgis_url = ""
hex_edge_m = 0.0
boundary_relation_id = 0
allow_private_arcgis = false