{ "cells": [ { "cell_type": "markdown", "id": "0875d8ca", "metadata": {}, "source": [ "# Multi Link Redundancy" ] }, { "cell_type": "markdown", "id": "74529aa4", "metadata": {}, "source": [ "The multi-link redundancy analysis returns the same types of results as the single-link redundancy analysis, but it considers multiple links failing simultaneously. This is particularly useful for assessing the resilience of a network to natural disasters that may affect several links at once." ] }, { "cell_type": "markdown", "id": "766d5fd3", "metadata": {}, "source": [ "## Run Multi-Link Redundancy Analysis\n", "\n", "The workflow is therefore very similar to the single-link redundancy analysis, with the difference being that a hazard map must be specified. See the [Single Link Redundancy](../tutorials/criticality_single_link_redundancy.html) tutorial for more details on the workflow.\n", "\n", "We select the analysis type as [AnalysisLossesEnum.MULTI_LINK_REDUNDANCY](../api/ra2ce.analysis.analysis_config_data.enums.analysis_losses_enum.html#ra2ce.analysis.analysis_config_data.enums.analysis_losses_enum.AnalysisLossesEnum.MULTI_LINK_REDUNDANCY){.api-ref}, for which we can also set a threshold for the water depth. The threshold defines the hazard value above which a link is considered impassable/disrupted." ] }, { "cell_type": "markdown", "id": "c5ac3816", "metadata": {}, "source": [ "## Step 1: Import Libraries and Set Paths\n", "\n", "We start by importing the required libraries and defining the root directory and network path." ] }, { "cell_type": "code", "execution_count": 1, "id": "180a1ba9", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "c:\\Users\\hauth\\miniforge3\\envs\\ra2ce_env\\Lib\\site-packages\\tqdm\\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", " from .autonotebook import tqdm as notebook_tqdm\n" ] } ], "source": [ "from pathlib import Path\n", "import geopandas as gpd\n", "from IPython.core.display_functions import display\n", "\n", "from ra2ce.analysis.analysis_config_data.analysis_config_data import AnalysisSectionLosses, AnalysisConfigData\n", "from ra2ce.analysis.analysis_config_data.enums.analysis_losses_enum import AnalysisLossesEnum\n", "from ra2ce.analysis.analysis_config_data.enums.weighing_enum import WeighingEnum\n", "from ra2ce.network.network_config_data.enums.aggregate_wl_enum import AggregateWlEnum\n", "from ra2ce.network.network_config_data.network_config_data import NetworkSection, NetworkConfigData, HazardSection\n", "from ra2ce.network.network_config_data.enums.source_enum import SourceEnum\n", "from ra2ce.ra2ce_handler import Ra2ceHandler\n", "\n", "root_dir = Path('data', 'multi_link_redundancy')\n", "\n", "network_path = root_dir / \"network\"\n", "hazard_path = root_dir / \"hazard\"\n" ] }, { "cell_type": "markdown", "id": "71052422", "metadata": {}, "source": [ "## Step 2: Define Network and Analysis Configuration" ] }, { "cell_type": "code", "execution_count": 3, "id": "6c1c6143", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "100%|██████████| 4217/4217 [00:00<00:00, 370052.09it/s]\n", "2025-10-01 05:04:27 PM - [avg_speed_calculator.py:175] - root - WARNING - No valid file found with average speeds data\\multi_link_redundancy\\static\\output_graph\\avg_speed.csv, calculating and saving them instead.\n", "2025-10-01 05:04:27 PM - [avg_speed_calculator.py:175] - root - WARNING - No valid file found with average speeds data\\multi_link_redundancy\\static\\output_graph\\avg_speed.csv, calculating and saving them instead.\n", "2025-10-01 05:04:27 PM - [avg_speed_calculator.py:150] - root - WARNING - Default speed have been assigned to road type []. Please check the average speed CSV, enter the right average speed for this road type and run RA2CE again.\n", "2025-10-01 05:04:27 PM - [avg_speed_calculator.py:150] - root - WARNING - Default speed have been assigned to road type []. Please check the average speed CSV, enter the right average speed for this road type and run RA2CE again.\n", "2025-10-01 05:04:27 PM - [avg_speed_calculator.py:150] - root - WARNING - Default speed have been assigned to road type []. Please check the average speed CSV, enter the right average speed for this road type and run RA2CE again.\n", "2025-10-01 05:04:27 PM - [avg_speed_calculator.py:150] - root - WARNING - Default speed have been assigned to road type []. Please check the average speed CSV, enter the right average speed for this road type and run RA2CE again.\n", "2025-10-01 05:04:29 PM - [hazard_overlay.py:380] - root - WARNING - Hazard crs EPSG:32736 and graph crs EPSG:4326 are inconsistent, we try to reproject the graph crs\n", "2025-10-01 05:04:29 PM - [hazard_overlay.py:380] - root - WARNING - Hazard crs EPSG:32736 and graph crs EPSG:4326 are inconsistent, we try to reproject the graph crs\n", "Graph hazard overlay with max_flood_depth: 100%|██████████| 2109/2109 [00:02<00:00, 785.28it/s]\n", "Graph fraction with hazard overlay with max_flood_depth: 100%|██████████| 2109/2109 [00:29<00:00, 71.65it/s] \n", "2025-10-01 05:05:02 PM - [hazard_overlay.py:461] - root - WARNING - Hazard crs EPSG:32736 and gdf crs EPSG:4326 are inconsistent, we try to reproject the gdf crs\n", "2025-10-01 05:05:02 PM - [hazard_overlay.py:461] - root - WARNING - Hazard crs EPSG:32736 and gdf crs EPSG:4326 are inconsistent, we try to reproject the gdf crs\n", "2025-10-01 05:05:02 PM - [hazard_intersect_builder_for_tif.py:225] - root - WARNING - Some geometries have NoneType objects (no coordinate information), namely: Empty GeoDataFrame\n", "Columns: [link_id, ID, highway, avgspeed, geometry, lanes, length, maxspeed, bridge, node_A, node_B, edge_fid, rfid_c, rfid, time]\n", "Index: [].This could be due to segmentation, and might cause an exception in hazard overlay\n", "2025-10-01 05:05:02 PM - [hazard_intersect_builder_for_tif.py:225] - root - WARNING - Some geometries have NoneType objects (no coordinate information), namely: Empty GeoDataFrame\n", "Columns: [link_id, ID, highway, avgspeed, geometry, lanes, length, maxspeed, bridge, node_A, node_B, edge_fid, rfid_c, rfid, time]\n", "Index: [].This could be due to segmentation, and might cause an exception in hazard overlay\n", "Network hazard overlay with max_flood_depth: 100%|██████████| 2121/2121 [00:01<00:00, 1092.98it/s]\n", "Network fraction with hazard overlay with max_flood_depth: 100%|██████████| 2121/2121 [00:37<00:00, 57.18it/s] \n" ] }, { "data": { "text/plain": [ "[AnalysisResultWrapper(results_collection=[AnalysisResult(analysis_result= u v link_id ID highway avgspeed \\\n", " 0 0 1 None None tertiary 60.0 \n", " 1 0 2 None None tertiary 58.0 \n", " 2 0 3 None None tertiary 58.0 \n", " 3 1 465 None None tertiary 60.0 \n", " 4 1 663 None None residential 60.0 \n", " ... ... ... ... ... ... ... \n", " 4213 1481 1482 None None residential 60.0 \n", " 4214 1481 1483 None None residential 60.0 \n", " 4215 1481 1484 None None residential 60.0 \n", " 4216 1508 1512 None None residential 60.0 \n", " 4217 1513 1514 None None residential 60.0 \n", " \n", " geometry lanes length_x \\\n", " 0 LINESTRING (34.87673 -19.85047, 34.87737 -19.8... nan 70.0 \n", " 1 LINESTRING (34.87673 -19.85047, 34.87642 -19.8... nan 70.0 \n", " 2 LINESTRING (34.87606 -19.85055, 34.87628 -19.8... nan 71.0 \n", " 3 LINESTRING (34.87780 -19.85016, 34.87737 -19.8... nan 47.0 \n", " 4 LINESTRING (34.87717 -19.84969, 34.87737 -19.8... nan 69.0 \n", " ... ... ... ... \n", " 4213 LINESTRING (34.85976 -19.83977, 34.86006 -19.8... nan 113.0 \n", " 4214 LINESTRING (34.86077 -19.84001, 34.86071 -19.8... nan 68.0 \n", " 4215 LINESTRING (34.86003 -19.83896, 34.86014 -19.8... nan 78.0 \n", " 4216 LINESTRING (34.88623 -19.83527, 34.88641 -19.8... nan 139.0 \n", " 4217 LINESTRING (34.85359 -19.83575, 34.85383 -19.8... nan 55.0 \n", " \n", " maxspeed ... rfid time EV1_mi EV1_fr alt_length alt_nodes \\\n", " 0 60 ... 4 0.001 0.000000 0.000000 NaN nan \n", " 1 nan ... 7 0.001 0.000000 0.000000 NaN nan \n", " 2 nan ... 10 0.001 0.000000 0.000000 NaN nan \n", " 3 60 ... 1470 0.001 0.000000 0.000000 NaN nan \n", " 4 nan ... 2066 0.001 0.000000 0.000000 NaN nan \n", " ... ... ... ... ... ... ... ... ... \n", " 4213 nan ... 4175 0.002 0.000000 0.000000 NaN nan \n", " 4214 nan ... 4176 0.001 0.000000 0.000000 NaN nan \n", " 4215 nan ... 4177 0.001 0.000000 0.000000 NaN nan \n", " 4216 nan ... 4209 0.002 0.056350 0.983086 NaN nan \n", " 4217 nan ... 4213 0.001 0.180663 0.167520 NaN nan \n", " \n", " diff_length connected length_y hazard \n", " 0 NaN nan NaN EV1_mi \n", " 1 NaN nan NaN EV1_mi \n", " 2 NaN nan NaN EV1_mi \n", " 3 NaN nan NaN EV1_mi \n", " 4 NaN nan NaN EV1_mi \n", " ... ... ... ... ... \n", " 4213 NaN nan NaN EV1_mi \n", " 4214 NaN nan NaN EV1_mi \n", " 4215 NaN nan NaN EV1_mi \n", " 4216 NaN nan NaN EV1_mi \n", " 4217 NaN nan NaN EV1_mi \n", " \n", " [4218 rows x 25 columns], analysis_config=AnalysisSectionLosses(name='tutorial_multi_link_redundancy', save_gpkg=True, save_csv=True, analysis=, weighing=, production_loss_per_capita_per_hour=nan, traffic_period=, hours_per_traffic_period=0, trip_purposes=[], resilience_curves_file=None, traffic_intensities_file=None, values_of_time_file=None, threshold=0.3, threshold_destinations=nan, equity_weight='', calculate_route_without_disruption=False, buffer_meters=nan, category_field_name='', save_traffic=False, event_type=, risk_calculation_mode=, risk_calculation_year=0), output_path=WindowsPath('data/multi_link_redundancy/output'), _custom_name='')])]" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "network_section = NetworkSection(\n", " source=SourceEnum.SHAPEFILE,\n", " primary_file=network_path.joinpath(\"base_shapefile.shp\"),\n", " file_id=\"ID\",\n", " save_gpkg=True)\n", "\n", "hazard_section = HazardSection(\n", " hazard_map=[hazard_path.joinpath(\"max_flood_depth.tif\")],\n", " hazard_id='Flood',\n", " hazard_field_name=\"waterdepthtt\",\n", " aggregate_wl=AggregateWlEnum.MIN,\n", " hazard_crs=\"EPSG:32736\",\n", " )\n", "\n", "network_config_data = NetworkConfigData(\n", " root_path= root_dir,\n", " static_path=root_dir.joinpath('static'),\n", " network=network_section,\n", " hazard=hazard_section,\n", " )\n", "\n", "analyse_section = AnalysisSectionLosses(\n", " name=\"tutorial_multi_link_redundancy\",\n", " analysis=AnalysisLossesEnum.MULTI_LINK_REDUNDANCY,\n", " threshold=0.3, # roads with a flood depth above this value are considered impassable\n", " weighing=WeighingEnum.LENGTH,\n", " save_csv=True,\n", " save_gpkg=True,\n", ")\n", "\n", "analysis_config_data = AnalysisConfigData(\n", " output_path=root_dir.joinpath(\"output\"),\n", " static_path=root_dir.joinpath('static'),\n", " analyses=[analyse_section],\n", " aggregate_wl=AggregateWlEnum.MIN,\n", ")\n", "\n", "handler = Ra2ceHandler.from_config(network=network_config_data, analysis=analysis_config_data)\n", "handler.configure()\n", "handler.run_analysis()" ] }, { "cell_type": "markdown", "id": "ede5df12", "metadata": {}, "source": [ "## Inspect Results" ] }, { "cell_type": "code", "execution_count": null, "id": "fabde810", "metadata": {}, "outputs": [], "source": [ "analysis_output_folder = root_dir.joinpath(\"output\", \"multi_link_redundancy\")\n", "redundancy_gdf = gpd.read_file(analysis_output_folder/\"tutorial_multi_link_redundancy.gpkg\") # specify the name of the geopackage holding your results (can be found in the analysis output folder)\n", "redundancy_gdf.head() # display the attributes of the file\n", "\n", "import matplotlib.pyplot as plt\n", "\n", "fig, ax = plt.subplots(figsize=(10, 10))\n", "redundancy_gdf.plot(column='alt_length', ax=ax, legend=False, cmap='viridis')\n", "plt.title('Multi Link Redundancy Analysis Results')\n", "plt.xlabel('Longitude')\n", "plt.ylabel('Latitude')\n", "plt.grid(True)\n", "plt.show()" ] } ], "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 }