Skip to content
Storm Ledger

About the model · v1.0.0

How Storm Ledger estimates damage

For every building and event the model estimates the gust at roof height, how exposed and how vulnerable the building is, the probability of any damage and the expected repair cost. It then compares that cost with the building's value. It is a model estimate calibrated on fire brigade calls, not on insurer claims.

Calibration

Spatial pattern checked against emergency calls (P2000, NL). Loss level is a model estimate; with your claims data it becomes a calibrated figure. That is the pilot. Fire brigade calls catch only part of the damage: people call insurers, not 112, for a leaking roof or a flooded shed. Expected loss is therefore shown as a band for reporting rates of 2% to 20% of damaged buildings producing a call, around the central 10%.

AUC Ciara, CV by buurt0.603
AUC all events0.647
Logistic benchmark0.639
Fitted k1147
Buildings · segments · with calls107,923 · 4,119 · 312
Eventsstorm-ciara-2020-02-09, storm-2018-01-18
Fitted on2026-10-17

Unit: street segment within a buurt (4119 segments, 107,923 buildings, 312 with a storm call). P(call) = 1 − exp(−ρ·Σ P_i) with ρ = 0.1 fixed (calls per damaged building; not identifiable from calls alone). AUC is pooled out-of-fold, leave-one-buurt-out. Ciara-only AUC 0.603; logistic benchmark (log Σ MDD_adj, log n) 0.639. P2000 coverage: see data/p2000/SOURCES.md. treePer was fitted to 0 but is kept at its 0.06 prior: Overpass was unavailable for many study buurten (58 mirror failures in this run), so most buurten outside Amsterdam had no tree data and the fit could not see a tree effect. P2000 windows: Ciara 9 Feb 2020 00:00–21:00 (1,378 geocoded incidents); 18 Jan 2018 10:00–18:00 (2,459), so the morning landfall in the west is missing and calls there are under-counted. Some regions are barely present in the archive (Noord-Holland Noord in 2020; the northern provinces in 2018); control buurten drawn there look undamaged when they were only unobserved, which pulls k down and the AUC with it. Half of the study buurten were chosen because they had calls (case-control sampling), which inflates the absolute call rate and so k; the AUC (ranking) is not affected. Treat absolute P(damage) as indicative.

AUC by buurt fold (160)
Event : buurtBuildingsSegments with callsAUC
storm-ciara-2020-02-09:BU0518382683940.838
storm-ciara-2020-02-09:BU19260101149040.804
storm-ciara-2020-02-09:BU06290103154250.789
storm-ciara-2020-02-09:BU0363MA098830.389
storm-ciara-2020-02-09:BU05182811120930.774
storm-ciara-2020-02-09:BU0363KH025610.875
storm-ciara-2020-02-09:BU0363KF0150040.250
storm-ciara-2020-02-09:BU0106000323410.158
storm-ciara-2020-02-09:BU0216010056510.923
storm-ciara-2020-02-09:BU1959139110–
storm-ciara-2020-02-09:BU0363MQ058920.813
storm-ciara-2020-02-09:BU0503110478230.696
storm-ciara-2020-02-09:BU1992040184740.419
storm-ciara-2020-02-09:BU0363EB1011620.900
storm-ciara-2020-02-09:BU0363AC0418320.938
storm-ciara-2020-02-09:BU02000603166920.867
storm-ciara-2020-02-09:BU0363KG0133320.393
storm-ciara-2020-02-09:BU028905042611.000
storm-ciara-2020-02-09:BU0363KL0237830.467
storm-ciara-2020-02-09:BU1930120413320.318
storm-ciara-2020-02-09:BU1525140546620.400
storm-ciara-2020-02-09:BU1948043222430.758
storm-ciara-2020-02-09:BU0489081739010.700
storm-ciara-2020-02-09:BU1942000047920.978
storm-ciara-2020-02-09:BU0441170145211.000
storm-ciara-2020-02-09:BU0202010128220.536
storm-ciara-2020-02-09:BU0363KQ0434720.977
storm-ciara-2020-02-09:BU0228040280020.341
storm-ciara-2020-02-09:BU0363KE0484860.483
storm-ciara-2020-02-09:BU0232020354520.952
storm-ciara-2020-02-09:BU0484701162220.875
storm-ciara-2020-02-09:BU1892040468810.947
storm-ciara-2020-02-09:BU0289070162620.400
storm-ciara-2020-02-09:BU0267010566420.842
storm-ciara-2020-02-09:BU0402050580120.923
storm-ciara-2020-02-09:BU05130604141130.676
storm-ciara-2020-02-09:BU0363MM0871020.514
storm-ciara-2020-02-09:BU19311202152420.551
storm-ciara-2020-02-09:BU0629010289310.000
storm-ciara-2020-02-09:BU062901005240–
storm-ciara-2020-02-09:BU0629011021810.167
storm-ciara-2020-02-09:BU0629010468910.026
storm-ciara-2020-02-09:BU1926010214490–
storm-ciara-2020-02-09:BU1926010413550–
storm-ciara-2020-02-09:BU192601059260–
storm-ciara-2020-02-09:BU1926010710380–
storm-ciara-2020-02-09:BU192601101460–
storm-ciara-2020-02-09:BU192601143560–
storm-ciara-2020-02-09:BU19260115940–
storm-ciara-2020-02-09:BU192601161670–
storm-ciara-2020-02-09:BU0518271893810.800
storm-ciara-2020-02-09:BU0518381922510.773
storm-ciara-2020-02-09:BU051838222840–
storm-ciara-2020-02-09:BU05183825141420.618
storm-ciara-2020-02-09:BU060301115650–
storm-ciara-2020-02-09:BU060302218680–
storm-ciara-2020-02-09:BU060301128860–
storm-ciara-2020-02-09:BU060302238710.600
storm-ciara-2020-02-09:BU1916110063310.591
storm-ciara-2020-02-09:BU191612027490–
storm-ciara-2020-02-09:BU191612008990–
storm-ciara-2020-02-09:BU0518044853010.813
storm-ciara-2020-02-09:BU0518054617670–
storm-ciara-2020-02-09:BU051810411750–
storm-ciara-2020-02-09:BU0518211012220–
storm-ciara-2020-02-09:BU05182144175610.875
storm-ciara-2020-02-09:BU051823475490–
storm-ciara-2020-02-09:BU0518281211030–
storm-ciara-2020-02-09:BU05182814144210.926
storm-ciara-2020-02-09:BU0518291613810–
storm-ciara-2020-02-09:BU0518291516760–
storm-ciara-2020-02-09:BU051830324850–
storm-ciara-2020-02-09:BU051829178550–
storm-ciara-2020-02-09:BU0363AK053020–
storm-ciara-2020-02-09:BU051830336240–
storm-ciara-2020-02-09:BU0363AK06280–
storm-ciara-2020-02-09:BU0363MA063620–
storm-ciara-2020-02-09:BU0363MA072710.429
storm-ciara-2020-02-09:BU0502077622610.538
storm-ciara-2020-02-09:BU0505020633830.778
storm-2018-01-18:BU0150080170340.542
storm-2018-01-18:BU09882201138650.538
storm-2018-01-18:BU02283001140170.725
storm-2018-01-18:BU0301000190360.712
storm-2018-01-18:BU02021993126870.832
storm-2018-01-18:BU01931310171250.832
storm-2018-01-18:BU0150010191540.882
storm-2018-01-18:BU0150030660650.787
storm-2018-01-18:BU1783090295450.642
storm-2018-01-18:BU02000101118290.624
storm-2018-01-18:BU02000801108150.960
storm-2018-01-18:BU01500401107660.567
storm-2018-01-18:BU037601055730.778
storm-2018-01-18:BU0232000589530.798
storm-2018-01-18:BU02281003135660.573
storm-2018-01-18:BU0243100150940.947
storm-2018-01-18:BU0222020565940.611
storm-2018-01-18:BU0988120196350.627
storm-2018-01-18:BU09831403101540.686
storm-2018-01-18:BU09832101148660.459
storm-2018-01-18:BU02940000142170.542
storm-2018-01-18:BU02283003140080.566
storm-2018-01-18:BU0150050254250.283
storm-2018-01-18:BU0262050134550.360
storm-2018-01-18:BU0243010245830.865
storm-2018-01-18:BU1942030430960.417
storm-2018-01-18:BU1942030033940.375
storm-2018-01-18:BU0518256989150.391
storm-2018-01-18:BU0289070162640.750
storm-2018-01-18:BU0228120269930.646
storm-2018-01-18:BU1734020338530.489
storm-2018-01-18:BU0274120323540.786
storm-2018-01-18:BU0150090262830.524
storm-2018-01-18:BU02281101123830.648
storm-2018-01-18:BU0177010313841.000
storm-2018-01-18:BU0988130174840.625
storm-2018-01-18:BU0150060476530.719
storm-2018-01-18:BU0150080284130.492
storm-2018-01-18:BU0363SD0399940.777
storm-2018-01-18:BU030713013230–
storm-2018-01-18:BU020218846540–
storm-2018-01-18:BU020218866570–
storm-2018-01-18:BU020218851280–
storm-2018-01-18:BU020219893670–
storm-2018-01-18:BU020223193040–
storm-2018-01-18:BU020218872730–
storm-2018-01-18:BU0988230188410.944
storm-2018-01-18:BU015008036330–
storm-2018-01-18:BU0202231714970–
storm-2018-01-18:BU0150100115710.769
storm-2018-01-18:BU01500901107710.050
storm-2018-01-18:BU015010075070–
storm-2018-01-18:BU030101013450–
storm-2018-01-18:BU0150100542910.143
storm-2018-01-18:BU0301010222210.000
storm-2018-01-18:BU030101046210–
storm-2018-01-18:BU0301020157420.269
storm-2018-01-18:BU0150010230210.706
storm-2018-01-18:BU030101035280–
storm-2018-01-18:BU0150010330510.174
storm-2018-01-18:BU015001041200–
storm-2018-01-18:BU015001062470–
storm-2018-01-18:BU015001074540–
storm-2018-01-18:BU0150030144121.000
storm-2018-01-18:BU015003037230–
storm-2018-01-18:BU0150010527810.654
storm-2018-01-18:BU0150040344720.667
storm-2018-01-18:BU0285010611920.500
storm-2018-01-18:BU0150040476511.000
storm-2018-01-18:BU1783090137410.700
storm-2018-01-18:BU019313005020–
storm-2018-01-18:BU178309037110–
storm-2018-01-18:BU019350004710–
storm-2018-01-18:BU01931320123720.522
storm-2018-01-18:BU019350103600–
storm-2018-01-18:BU0193120011770–
storm-2018-01-18:BU019350205210–
storm-2018-01-18:BU019351302340–
storm-2018-01-18:BU0193503011330–
storm-2018-01-18:BU0150060147830.867

Check against insured losses

The probability ranking is calibrated; the euro amounts are not. A rough outside check uses what Dutch insurers reported for the two calibration storms:

  • Storm of 18 January 2018: first Verbond van Verzekeraars estimate about €90 m for homes and cars, later reported at about €436–450 m in total; together with the storm of 3 January insurers handled close to 300,000 claims (Hart van Nederland, NOS, ESB).
  • Storm Ciara, 9 February 2020: first Verbond estimate about €150 m, mainly homes and cars (report).

That puts the average claim at roughly €1,500 (including cars). In the five demo areas the model's typical repair given that a building is damaged is €180–1,300 (median per area), and a building with many dwellings would usually produce several claims. Two separate questions follow.

How many buildings are damaged is set by k = 1147, fitted on fire-brigade calls with a fixed share ρ = 0.1 of damaged buildings producing a call. A few thousand P2000 calls against several hundred thousand claims suggests ρ is nearer 0.01, which would mean many more damaged buildings than shown, each with a smaller loss: with P = 1 − exp(−k·MDDadj) the loss of a damaged building averages about 1/k of rebuild cost (0.09% now). That split is a modelling assumption, not data.

How much money in total is Σ MDDadj × rebuild cost. It does not depend on k: it comes straight from the Schwierz et al. (2010) curve and the €/m³ rule, and has not yet been compared with the national insured totals above. The next calibration step is to run the model for the whole country for these two storms and scale the curve to the insured totals. Until then, read euro amounts as indicative and use P(damage) for ranking.

Equations

  1. Gust at the building. g10 = inverse-distance-weighted (power 2) event peak of hourly max gust FX at the 4 nearest KNMI land stations. g(h) = g10 · (h/10)^α, α = 0.22 where built-up share within 100 m exceeds 0.15, else 0.14. h is the 70th-percentile roof height above ground (min 3 m).
  2. Exposure E = clamp(0.6, 1.4, 1 + 0.25·log₂(clamp(h/h̄up, 0.5, 2)) + 0.5·(fetch/200 − 0.5) + 0.2·corner + 0.05·detached). h̄up is the mean roof height of buildings within 60 m upwind (±30°). Fetch is the upwind distance to the nearest building; water and parks hold no buildings, so they count as open.
  3. Vulnerability V = roof type × face orientation (area-weighted: windward 0.85, edge 1.15, leeward 1.3, flat 1) × slope band × build-year band × floors band × (1 + 0.06·min(ntrees, 6)), where ntrees counts trees taller than their distance to the facade.
  4. Mean damage degree MDD = min(1, a·max(0, g − g0)^b) with a = 1.3415e-13, b = 5.2874, g0 = 72 km/h, fitted to the Schwierz et al. (2010) curve (PAA × MDD). MDD_adj = min(1, MDD · E · V).
  5. Damage probability P = 1 − exp(−k · MDD_adj). Given damage, the damage ratio is exponential with mean MDD_adj/P, which splits P into minor (< 1% of reconstruction cost), moderate (< 8%) and severe. Expected state: none if P < 5%, else severe if MDD_adj ≥ 0.03, moderate if ≥ 0.004, otherwise minor.
  6. Value impact repair = MDD_adj × reconstruction cost, reconstruction = 3DBAG LoD 2.2 volume × €/m³ by class. Value decrease % = expected repair ÷ value × 100. P10 and P90 are quantiles of the same damage distribution. This is repair cost relative to value, not a market price effect.
  7. Value from the CSV when given; otherwise CBS mean WOZ × dwellings in the buurt, shared by floor area (area view), or, in the portfolio, the buurt mean WOZ scaled by the addressor the buurt mean WOZ per address (portfolio, which carries its floor-area share of the building's repair cost)apos;s usable area relative to a 100 m² dwelling; the address carries its floor-area share of the building's repair cost.

Every parameter

ParameterValue
version1.0.0
idwStations4
idwPower2
alphaUrban0.22
alphaOpen0.14
urbanDensity0.15
urbanRadiusM100
minHeightM3
shelterRadiusM60
sectorHalfDeg30
fetchMaxM200
wShelter0.25
wFetch0.5
wCorner0.2
wDetached0.05
exposureMin0.6
exposureMax1.4
roofTypeslanted: 1.1, multiple horizontal: 0.9, single horizontal: 0.85, horizontal: 0.85, unknown: 1
faceWindward0.85
faceEdge1.15
faceLeeward1.3
faceFlat1
slopeBandsmax 10 → f 0.9; max 15 → f 1; max 35 → f 1.25; max 50 → f 1.1; max 91 → f 1
yearBandsbefore 1945 → f 1.3; before 1975 → f 1.15; before 2000 → f 1; before 9999 → f 0.8
yearUnknown1.1
floorBandsmax 3 → f 1; max 6 → f 1.08; max 999 → f 1.15
treePer0.06
treeCap6
treeSearchM30
treeDefaultHeightM10
mddA1.3415e-13
mddB5.2874
mddG072
k1147
pVisible0.05
tModerate0.004
tSevere0.03
ratioMinorMax0.01
ratioModerateMax0.08
eurPerM3house: 450, apartment: 400, large: 280, annex: 180
refDwellingM2100
reportingRate0.1

Defined in model/params.ts; fitted values come from model/calibration.json, written by scripts/calibrate.ts.

Sources and licences

NeedSourceLicence
Buildings, heights, roof faces3DBAG (TU Delft 3D geoinformation), LoD 2.2, api.3dbag.nlCC BY 4.0
Streets, water, parks, treesOpenStreetMap via Overpass APIODbL
Street trees with height classGemeente Amsterdam, Bomen (stamgegevens), api.data.amsterdam.nl; elsewhere OSM natural=treeCC0 / ODbL
Place search, address → buildingPDOK Locatieserver v3.1; Kadaster BAG OGC API v2 (verblijfsobject → pand)CC0
Buurt and wijk boundaries, mean WOZ value, dwellingsCBS Wijk- en buurtkaart 2024 via PDOKCC BY 4.0
Province and municipality outlinesCBS Gebiedsindelingen (generalised) via PDOKCC BY 4.0
Wind gusts (FX) and direction (DD)KNMI hourly station data (uurgegevens)CC BY 4.0
Wind gusts, GermanyDWD Climate Data Center, 10-minute extreme wind (FX_10, DX_10), 26 eventsCC BY 4.0
Buildings, streets and water, GermanyOpenStreetMap via OpenFreeMap vector tiles (render height; lower geometric detail, no roof faces)ODbL
Place search and addresses, GermanyPhoton (komoot), OpenStreetMap dataODbL
Forecasts in the sales demoNOAA GFS 0.5°, NCEI archive, runs of 6, 7 and 8 February 2020Public domain
Event catalogueKNMI code orange/red archive and event factsheets, checked against station dataCC BY 4.0
Damage curveSchwierz et al. (2010), Climatic Change 101:485–514, doi:10.1007/s10584-009-9712-1; table as in CLIMADA ImpfStormEurope.from_schwierzPublished
Ground truthP2000 fire brigade storm calls (public archive), geocoded with PDOKSee data/p2000/SOURCES.md

What is approximated, and what would replace it

ApproximationBetter data
Calibrated on fire brigade calls, which capture a small, unknown share of damage and are geocoded to street level.Insurer claims per address (Verbond van Verzekeraars / individual insurers), with claim amount.
Roof covering is inferred from roof type and slope (tiles assumed on pitched roofs).Roof material per building (aerial imagery classification or municipal roof registers).
Building value is a buurt mean WOZ shared by floor area.WOZ value per address (WOZ-waardeloket / Basisregistratie WOZ).
Reconstruction cost is volume × a €/m³ rule of thumb by class.Herbouwwaarde per building from insurers or taxation reports.
Gusts are interpolated from about 45 KNMI stations; convective gusts between stations are missed.ERA5 fg10 or HARMONIE-AROME gust grids; radar-derived downburst tracks.
Wind direction per building is the station direction at its peak hour.Gridded wind field at the hour of the local peak.
Tree heights come from Amsterdam's register; elsewhere OSM trees, usually without height (default 10 m).AHN-derived tree crowns and heights or other municipal tree registers.
Hail, rain and flood are listed but not modelled.KNMI hail and radar products, flood footprints with depth, and fragility curves.