{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "# RA2CE feature: Damages analysis (Huizinga)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Three types of damage curves can be introduced to this analysis:\n", "- Huizinga\n", "- OSdaMage \n", "- User defined" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## The Huizinga damage functions" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "This type of damage functions are initially developed for grid-based models, and generates damage per m2. For use in raster-based models, Huizinga (2007) developed a set of damage functions for diverse land use classes including transport infrastructure, initially for the European Union and later generalized worldwide (Huizinga et al., 2017). ‘Infrastructure’ is defined as physical damage to “roads and railroads as a result of contact with (fast flowing) water” (Huizinga et al., 2017, p.96). \n", "\n", "This type is adapted by Van Ginkel et al. (2021) for use object-based models such as RA2CE, which can be implemented easily across the globe. The grid-based Huizinga (2007, 2017) infrastructure damage function is expressed in euros damage per inundated area (€/m2). The maximum damage for road infrastructure is 25 €/m2. To apply this function in the object-based model, they are multiplied by typical road widths (m) to obtain damage functions per unit road length\n", "\n", "It is good to mention that this method is known to (strongly) underestimate damage to high-end road infrastructure such as motorways with street lighting (Van Ginkel et al., 2021); (strongly) overestimate damage to cheap roads in the underlying road networks, such small residential roads, unpaved roads and tracks; underestimate damage to bridges (Jongman et al., 2012).\n" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## An example for the Huizinga damage function" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "In this notebook, we provide an example for an event-based object-oriented Huizinga analysis." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import geopandas as gpd\n", "import matplotlib.pyplot as plt\n", "from pathlib import Path\n", "import numpy as np\n", "import rasterio\n", "\n", "root_dir = Path(\"data\", \"damages_analysis_huizinga\")\n", "assert root_dir.exists(), \"root_dir not found.\"" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "#### Introducing a hazardous event" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "To use the flood map with RA2CE, we need to fill in the **[hazard]** section in the network.ini. \n", "\n", "Specify the flood map name in the **hazard_map** parameter in network.ini. RA2CE expects the flood map to be located in the *hazard* folder. The **aggregate_wl** parameter in analysis.ini can be set to either 'max', 'min' or 'mean' to take the maximum, minimum or mean water depth per road segment when the exposure of the roads to a certain hazard (map) is determined.
\n", "\n", "Set the right CRS for the flood map in the **hazard_crs** parameter. This CRS can be different from the origins, destinations and road network. RA2CE will reproject the network to the CRS of the flood map and will reproject the road back to the original CRS when the CRS differs." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "hazard_folder = root_dir / \"static\" / \"hazard\" # find the hazard folder where you locate your floo dmap\n", "hazard_map = hazard_folder / \"max_flood_depth.tif\" # set the location of the hazard map\n", "\n", "# Open the TIF file using rasterio\n", "with rasterio.open(hazard_map) as src:\n", " # Read the TIF file as a numpy array\n", " tif_array = src.read(1) # Change the band index (1) if necessary\n", "\n", "plt.figure(figsize=(10, 10))\n", "plt.imshow(tif_array, cmap='Blues') # Change the colormap if desired\n", "plt.colorbar(label='Pixel Values')\n", "plt.title('Flood map')\n", "plt.show()\n" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "#### Specifying the .ini files" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "**Network.ini content**\n", "
\n", "
\n", "> [project]
\n", "name = beira
\n", "
\n", "[network]
\n", "directed = False
\n", "source = OSM download
\n", "primary_file = None
\n", "diversion_file = None
\n", "file_id = rfid_c
\n", "polygon = region_polygon.geojson
\n", "network_type = drive
\n", "road_types = motorway,motorway_link,primary,primary_link,secondary,secondary_link,tertiary,tertiary_link,residential
\n", "save_gpkg = True\n", "
\n", "[origins_destinations]
\n", "origins = None
\n", "destinations = None
\n", "origins_names = None
\n", "destinations_names = None
\n", "id_name_origin_destination = None
\n", "origin_count = None
\n", "origin_out_fraction = None
\n", "category = categorybr>\n", "
\n", "[hazard]
\n", "hazard_map = max_flood_depth.tif
\n", "hazard_id = None
\n", "hazard_field_name = waterdepth
\n", "aggregate_wl = max
\n", "hazard_crs = EPSG:32736br>\n", "
\n", "[cleanup]
\n", "snapping_threshold = None
\n", "segmentation_length = 100
\n", "merge_lines = True
\n", "merge_on_id = False
\n", "cut_at_intersections = False
" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "We now need to update our analysis initialisation files using the preferred OD-analysis (there are multiple). We will consider the **damages** analysis. With the **aggregate_wl** parameter, the user can choose which type of aggregation of the water level on the road segment (max, mean, min) the analysis should consider. For the damages analysis, the **aggregate_wl=mean** makes sense. \n", "\n", "The **damage_curve** defines the damage curve type. ‘HZ’ to use the Huizinga damage function, ‘OSD’ to use the OSdaMage functions, and ‘MAN’ to use damage functions from manually inserted files. The **event_type** defines the type of the hazardous event, which is either 'event', or 'return_period'. The former is an one-time event, while the later will be applied for the events witha probability of occurance." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "**[analysis1]**\n", "
\n", "
\n", "name = Huizinga_damages_event
\n", "analysis = damages
\n", "event_type = event
\n", "damage_curve = HZ
\n", "save_csv = True
\n", "save_gpkg =True
" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Set the paths to the initialization files and check if the files exist." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from ra2ce.ra2ce_handler import Ra2ceHandler\n", "from ra2ce.network.network_config_data.network_config_data_reader import NetworkConfigDataReader\n", "from ra2ce.analysis.analysis_config_data.analysis_config_data_reader import AnalysisConfigDataReader\n", "\n", "# Load network data.\n", "_network_config_data = NetworkConfigDataReader().read(root_dir.joinpath(\"network.ini\"))\n", "\n", "# Load analysis data.\n", "_analysis_config_data = AnalysisConfigDataReader().read(root_dir.joinpath(\"analysis.ini\"))\n", "\n", "_analysis_config_data.input_path = root_dir.joinpath(\"input_analysis_data\")" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Run RA2CE." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "handler = Ra2ceHandler.from_config(_network_config_data, _analysis_config_data)\n", "\n", "handler.configure()\n", "handler.run_analysis()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "#### Visualising the results" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "analysis_output_path = root_dir / \"output\" / \"damages\"\n", "damage_gdf = gpd.read_file(analysis_output_path / 'Huizinga_damages_event_segmented.gpkg')\n", "damage_gdf.head() #show the origins" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "null_mask = damage_gdf['dam_EV1_HZ'].isnull()\n", "damage_gdf.loc[null_mask, 'dam_EV1_HZ'] = damage_gdf.loc[null_mask, 'dam_EV1_HZ'].replace({np.nan: 0})\n", "\n", "\n", "import folium\n", "from branca.colormap import LinearColormap\n", "\n", "# Create a colormap\n", "colormap = LinearColormap(['yellow', 'orange', 'red'], vmin=0, vmax=damage_gdf['dam_EV1_HZ'].max(), caption='dam_EV1_HZ')\n", "\n", "# Create a Folium map centered around the mean of the geometry\n", "center = [damage_gdf['geometry'].centroid.y.mean(), damage_gdf['geometry'].centroid.x.mean()]\n", "m = folium.Map(location=center, zoom_start=12, control_scale=True, tiles=\"CartoDB dark_matter\")\n", "\n", "# Create the color strip legend with white font color\n", "colormap.caption = 'dam_EV1_HZ'\n", "colormap.add_to(m)\n", "colormap._repr_html_ = colormap._repr_html_().replace(\n", " 'background-color: #000', 'background-color: #000; color: #000'\n", ")\n", "\n", "# Add edges to the map\n", "for idx, row in damage_gdf.iterrows():\n", " color = 'darkgray' if row['dam_EV1_HZ'] == 0 else colormap(row['dam_EV1_HZ'])\n", " \n", " # Extracting coordinates from LineString\n", " coordinates = [(coord[1], coord[0]) for coord in row['geometry'].coords]\n", "\n", " # Create a popup with data\n", " popup_content = f\"dam_EV1_HZ: {row['dam_EV1_HZ']}\"\n", " popup = folium.Popup(popup_content, max_width=300)\n", " \n", " folium.PolyLine(\n", " locations=coordinates,\n", " color=color,\n", " weight=2,\n", " opacity=1,\n", " popup=popup\n", " ).add_to(m)\n", "\n", "# Add colormap to the map\n", "colormap.add_to(m)\n", "\n", "# Display the map\n", "m" ] } ], "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.10.13" } }, "nbformat": 4, "nbformat_minor": 2 }