{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Uncertainty in vulnerability functions\n", "Uncertainty in vulnerability functions can be specified in the vulnerability configuration.\n", "\n", "### Deterministic case\n", "In the deterministic case, that is when there is no uncertainty, the vulnerability function is simply a curve. The hazard indicator values, $x_i$ $i \\in [1 \\dots n]$ are provided with the corresponding impacts (damage/disruption) $y_i$.\n", "\n", "### General case\n", "In the general case, the hazard indicator values are provided in exactly the same way, but instead of a single impact for each value $x_i$, a cumulative probability density function (CDF) is specified. For a hazard indicator value $x$ that lies between two 'pillar values', the impact would be found in the deterministic case by linear interpolation. In the general case, it is the *CDFs* that are interpolated. \n", "\n", "The CDFs are specified in a non-parametric way with the cumulative probabilities provided for hazard indicator value $x_i$ for a number of impact pillar values $y_j$.\n", "\n", "$F_i(y) = \\mathbb{P}(Y \\leq y|x_i)$\n", "\n", "The CDF, $F_i(y)$, is given for points $y_j$, $j \\in [1 \\dots m]$.\n", "$F_{ij} = \\mathbb{P}(Y \\leq y_j|x_i)$\n", "\n", "$x = [x_1, x_2, \\dots, x_n ]$ \n", "$y = [y_1, y_2, \\dots, y_m ]$ \n", "$z = [[F_{11}, F_{12}, \\dots, F_{1m}], [F_{21}, F_{12}, \\dots, F_{2m}], \\dots, [F_{n1}, F_{n2}, \\dots, F_{nm}]]$\n", "\n", "Note that in this scheme the impact pillar values $y_j$ determine the granularity of the impacts that apply across all CDFs. The granularity should be fine enough that the uncertainty is dominated by the CDFs so that the discretization error does not materially affect the calculation. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Generating CDFs\n", "CDFs can be inferred directly from historical data or from ensembles of damage curves derived for different properties for which the precise building specification and situation is known. In some cases however, perhaps only an estimate of the uncertainty around a mean impact is available in the form of a standard deviation. In such cases a parametric model is used whereby the CDFs are modelled as beta or truncated gaussian distributions. In physrisk, discretized non-parametric CDFs are derived for these parametric distributions so that these can then treated identically.\n", "\n", "An example is given for the case where a beta distribution is used." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "from physrisk.vulnerability_models.config_cdf_based_vuln_function import CDFBasedVulnerabilityFunction\n", "\n", "hazard_indicator = np.array([0.0, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0, 6.0])\n", "impact_mean = np.array([0.0, 0.327, 0.494, 0.617, 0.721, 0.870, 0.931, 0.984, 1.0])\n", "impact_stddev = np.array([0.0, 0.12, 0.11, 0.10, 0.10, 0.08, 0.06, 0.02, 0.0])\n", "vuln = CDFBasedVulnerabilityFunction(hazard_indicator, impact_mean, impact_stddev, kind=\"beta\")" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ " \n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import plotly.graph_objects as go\n", "import plotly.io\n", "plotly.io.renderers.default = \"notebook\"\n", "\n", "fig = go.Figure()\n", "for i in [0, 2, 4, 6, 8]:\n", " fig.add_scatter(x=vuln.cdf[i, :], y=vuln.impact, name=f\"Flood depth {hazard_indicator[i]}m\")\n", "# also interpolate for a depth of 0.6m and display\n", "interp = vuln.interpolate_cdfs(np.array([0.6]))\n", "fig.add_scatter(x=interp[0, :], y=vuln.impact, name=f\"Interpolated depth 0.6m\")\n", "fig.update_xaxes(title=\"Cumulative probability\", title_font={\"size\": 14})\n", "fig.update_yaxes(title=\"Fractional damage\", title_font={\"size\": 14})\n", "fig.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Probability bins are an alternative way to visualize the probability distributions." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig = go.Figure()\n", "impact_bin_centres = (vuln.impact[0:-1] + vuln.impact[1:]) / 2\n", "impact_bin_width = vuln.impact[1:] - vuln.impact[0:-1]\n", "for i in [2, 4, 6]:\n", " probs = vuln.cdf[i, 1:] - vuln.cdf[i, 0:-1]\n", " fig.add_bar(x=impact_bin_centres, y=probs, width=impact_bin_width, name=f\"Flood depth {hazard_indicator[i]}m\", \n", " opacity=0.7)\n", "fig.update_xaxes(title=\"Fractional damage\", title_font={\"size\": 14})\n", "fig.update_yaxes(title=\"Probability\", title_font={\"size\": 14})\n", "fig.show()" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Standard deviation is 0.114m for flood depth 1.0\n" ] } ], "source": [ "# we can do a sanity test say for the 1.0m flood depth case: is the standard deviation of the distribution as specified above (0.11 m)\n", "i = 2\n", "probs = vuln.cdf[i, 1:] - vuln.cdf[i, 0:-1]\n", "mean = np.sum(probs * impact_bin_centres)\n", "std = np.sqrt(np.sum(probs * impact_bin_centres * impact_bin_centres) - mean * mean)\n", "print(f\"Standard deviation is {std:0.3}m for flood depth {hazard_indicator[i]}\")" ] } ], "metadata": { "kernelspec": { "display_name": ".venv", "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.15" } }, "nbformat": 4, "nbformat_minor": 2 }