{ "cells": [ { "cell_type": "markdown", "id": "81af42bc", "metadata": {}, "source": [ "# Expected Annual Damage (EAD) Tutorial\n", "\n", "This tutorial demonstrates how to run a **risk-based damage analysis** in RA2CE,\n", "calculating the **Expected Annual Damage (EAD)** to road infrastructures.\n", "\n", "Unlike the event-based analysis (where damages are computed for a single hazard event),\n", "the EAD approach integrates damages across multiple hazard scenarios with different\n", "return period. This provides a long-term measure of *average annual risk*." ] }, { "cell_type": "markdown", "id": "0a6f003e", "metadata": {}, "source": [ "## What is EAD?\n", "\n", "The **Expected Annual Damage (EAD)** represents the average yearly damage that can\n", "be expected due to hazards, accounting for their frequency of occurrence.\n", "\n", "The workflow follows the same steps as the event-based analysis, with the key\n", "difference being:\n", "\n", "- **Hazard input** consists of maps corresponding to different return periods\n", " (e.g., 10-year, 100-year, 1000-year floods).\n", "- RA2CE combines the **damage per event** with the **annual exceedance probability (AEP)**\n", " of each event.\n", "- Damages are integrated across probabilities to estimate the **EAD**." ] }, { "cell_type": "markdown", "id": "9cfe5da0", "metadata": {}, "source": [ "This tutorial is mostly based on the tutorial about reference damage curves. For details on\n", "the road network setup and hazard input, please refer to the :doc:`Reference damage curves ` tutorial." ] }, { "cell_type": "markdown", "id": "1ed8cfa8", "metadata": {}, "source": [ "## Step 1: Define project paths\n", "\n", "We first set up the project folder structure:" ] }, { "cell_type": "code", "execution_count": null, "id": "57a5187b", "metadata": {}, "outputs": [], "source": [ "from pathlib import Path\n", "\n", "root_dir = Path(\"data\", \"damages_EAD\")\n", "assert root_dir.exists(), \"root_dir not found.\"\n", "\n", "static_path = root_dir.joinpath(\"static\")\n", "hazard_path = static_path.joinpath(\"hazard\")\n", "network_path = static_path.joinpath(\"network\")\n", "output_path = root_dir.joinpath(\"output\")" ] }, { "cell_type": "markdown", "id": "04131cb6", "metadata": {}, "source": [ "## Step 2: Configure the road network\n", "\n", "The road network is downloaded from **OpenStreetMap (OSM)** and clipped to\n", "a region polygon (`polygon.geojson`). We select which road types should be\n", "included in the analysis." ] }, { "cell_type": "code", "execution_count": null, "id": "b98d5c16", "metadata": {}, "outputs": [], "source": [ "from ra2ce.network.network_config_data.enums.road_type_enum import RoadTypeEnum\n", "from ra2ce.network.network_config_data.enums.source_enum import SourceEnum\n", "from ra2ce.network.network_config_data.enums.network_type_enum import NetworkTypeEnum\n", "from ra2ce.network.network_config_data.network_config_data import NetworkSection\n", "from ra2ce.ra2ce_handler import Ra2ceHandler\n", "\n", "\n", "network_section = NetworkSection(\n", " network_type=NetworkTypeEnum.DRIVE,\n", " source=SourceEnum.OSM_DOWNLOAD,\n", " polygon=static_path.joinpath(\"polygon.geojson\"),\n", " save_gpkg=True,\n", " road_types=[\n", " RoadTypeEnum.SECONDARY,\n", " RoadTypeEnum.SECONDARY_LINK,\n", " RoadTypeEnum.PRIMARY,\n", " RoadTypeEnum.PRIMARY_LINK,\n", " RoadTypeEnum.TRUNK,\n", " RoadTypeEnum.MOTORWAY,\n", " RoadTypeEnum.MOTORWAY_LINK,\n", " ],\n", ")" ] }, { "cell_type": "markdown", "id": "d26c3faa", "metadata": {}, "source": [ "Hazard maps are provided as **GeoTIFF raster files** for different return periods\n", "(e.g., 10-year, 100-year, 1000-year). RA2CE will use these to compute damages\n", "for each event.\n", "\n", "**Warning:** Hazard maps must follow the naming convention `RP_.tif`\n", "(e.g. `RP_10.tif`, `RP_100.tif`, `RP_1000.tif`).\n", "Otherwise, RA2CE will not be able to assign exceedance probabilities." ] }, { "cell_type": "code", "execution_count": null, "id": "9546c0af", "metadata": {}, "outputs": [], "source": [ "from ra2ce.network.network_config_data.enums.aggregate_wl_enum import AggregateWlEnum\n", "from ra2ce.network.network_config_data.network_config_data import HazardSection\n", "\n", "hazard_section = HazardSection(\n", " hazard_map=[Path(file) for file in hazard_path.glob(\"*.tif\")],\n", " aggregate_wl=AggregateWlEnum.MEAN,\n", " hazard_crs=\"EPSG:4326\",\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "d1a6ac46", "metadata": {}, "outputs": [], "source": [ "from ra2ce.network.network_config_data.network_config_data import NetworkConfigData\n", "\n", "network_config_data = NetworkConfigData(\n", " root_path=root_dir,\n", " static_path=static_path,\n", " network=network_section,\n", " hazard=hazard_section\n", ")\n", "network_config_data.network.save_gpkg = True" ] }, { "cell_type": "markdown", "id": "fc33b4c3", "metadata": {}, "source": [ "## Step 3: Define the damage analysis\n", "\n", "We now configure the analysis to compute **risk-based damages** with the analysis section class\n", "[AnalysisSectionDamages](../api/ra2ce.analysis.analysis_config_data.html#ra2ce.analysis.analysis_config_data.analysis_config_data.AnalysisSectionDamages){.api-ref}.\n", "The Expected Annual Damage (EAD) is calculated by integrating damages across multiple return periods —\n", "this is essentially the area under the Exceedance Probability (EP) curve.\n", "\n", "For a risk analysis, two additional attributes must be specified:\n", "\n", "- `risk_calculation_mode` → defines how the area under the EP curve is approximated.\n", " Available options are provided by [RiskCalculationModeEnum](../api/ra2ce.analysis.analysis_config_data.enums.html#ra2ce.analysis.analysis_config_data.enums.risk_calculation_mode_enum.RiskCalculationModeEnum){.api-ref}.\n", "- `risk_calculation_year` → only required for the **Triangle to Null Year** mode.\n", " It specifies a synthetic minimum return period (in years) at which damages are assumed to be zero.\n", " This extends the EP curve towards the y-axis and ensures integration includes frequent (low-return period) events.\n", "\n", "RA2CE allows for several modes of calculating the EAD.\n", "In this tutorial, we use the **Triangle to Null Year** method, which linearly approximates the\n", "area under the EP curve from the lowest available hazard map down to the defined `risk_calculation_year`.\n", "\n", "In this example, we set `risk_calculation_year=5` to include frequent events\n", "with return periods down to 5 years in the EAD computation." ] }, { "cell_type": "code", "execution_count": null, "id": "ec4b5829", "metadata": {}, "outputs": [], "source": [ "from ra2ce.analysis.damages.damages import AnalysisSectionDamages\n", "from ra2ce.analysis.analysis_config_data.enums.analysis_damages_enum import AnalysisDamagesEnum\n", "from ra2ce.analysis.analysis_config_data.enums.event_type_enum import EventTypeEnum\n", "from ra2ce.analysis.analysis_config_data.enums.damage_curve_enum import DamageCurveEnum\n", "from ra2ce.analysis.analysis_config_data.analysis_config_data import AnalysisConfigData\n", "from ra2ce.analysis.analysis_config_data.enums.risk_calculation_mode_enum import RiskCalculationModeEnum\n", "\n", "\n", "damages_analysis = [AnalysisSectionDamages(\n", " name='damages_risk',\n", " analysis=AnalysisDamagesEnum.DAMAGES,\n", " event_type=EventTypeEnum.RETURN_PERIOD, # risk-based analysis\n", " damage_curve=DamageCurveEnum.HZ, # use Huizinga reference curves\n", " risk_calculation_mode=RiskCalculationModeEnum.TRIANGLE_TO_NULL_YEAR,\n", " risk_calculation_year=5, # include frequent events\n", " save_csv=True,\n", " save_gpkg=True,\n", ")]\n", "\n", "analysis_config_data = AnalysisConfigData(\n", " analyses=damages_analysis,\n", " output_path=output_path,\n", ")" ] }, { "cell_type": "markdown", "id": "90a66f5a", "metadata": {}, "source": [ "## Step 4: Run the analysis\n", "\n", "Finally, we run the analysis:" ] }, { "cell_type": "code", "execution_count": null, "id": "14cf8fc6", "metadata": {}, "outputs": [], "source": [ "from ra2ce.ra2ce_handler import Ra2ceHandler\n", "\n", "Ra2ceHandler.run_with_config_data(network_config_data, analysis_config_data)" ] }, { "cell_type": "markdown", "id": "06c87389", "metadata": {}, "source": [ "## Output\n", "\n", "The results are written to **GeoPackage (GPKG)** and CSV files in the `output` folder.\n", "\n", "Typical outputs include:\n", "\n", "- **damages_risk_link_based.gpkg** – damages per network link (node to node).\n", "- **damages_risk_segment.gpkg** – damages per 100m segment.\n", "\n", "Attributes of interest include:\n", "\n", "- `dam_RP100_HZ` – estimated damage for the 100-year return period (Huizinga).\n", "- `dam_RP1000_HZ` – estimated damage for the 1000-year return period (Huizinga).\n", "- `risk_HZ` – Expected Annual Damage, aggregated across return periods.\n", "\n", "You can load the results with **GeoPandas** for inspection and plotting:" ] }, { "cell_type": "code", "execution_count": null, "id": "739fc2f4", "metadata": {}, "outputs": [], "source": [ "import geopandas as gpd\n", "\n", "link_based = gpd.read_file(output_path / \"damages\" / \"damages_risk_link_based.gpkg\")\n", "print(link_based[[\"dam_RP100_HZ\", \"dam_RP1000_HZ\", \"risk_HZ\"]].head())" ] }, { "cell_type": "markdown", "id": "0ff9a274", "metadata": {}, "source": [ "## Important Note\n", "\n", "The accuracy of the EAD strongly depends on the **set of return period hazard maps** provided.\n", "Ensure that you cover a sufficient range (e.g., frequent, moderate, and extreme events)\n", "to avoid underestimating or overestimating the risk." ] } ], "metadata": { "kernelspec": { "display_name": "ra2ce_env", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.13" } }, "nbformat": 4, "nbformat_minor": 5 }