Vulnerability models

Programmatic models and configuration

Vulnerability models can either be created in code — these are’programmatic models’ — or specified via lines configuration.

Programmatic models are appropriate when there is complex logic to be captured, best expressed in code. For example assigning damage curves to assets for the modelling of flood hazards may be based on attributes such as the building’s number of storeys and there may be rules about how curves are modified to take account of the height of the first floor.

In other cases it is desirable to assign curves to broad families of assets; a model of productivity loss might specify curves depending on the industrial sector, reflecting of the nature of labour within the sectors. For such cases specificaiton via configuration can be more transparent and convenient.

The principle of configuration is that human-readable lines in a file can be used to relate a hazard indicator value (e.g. flood depth or number of days per year above a certain temperature) to damage or disruption.

Specification of assets

The default behaviour of physrisk is as follows:

  1. Assets can be specified using physrisk asset classes, e.g. RealEstateAsset, ManufacturingAsset, which inherit from Asset or by Open Exposure Data (OED) attributes, e.g. occupancy code.

  2. For assets specified only by OED attributes, physrisk will map these onto physrisk asset classes, potentially with an additional type attribute, using a configuration — which users can customize — whilst also retaining the OED attributes. This is done so that vulnerability models can make use of either OED properties or asset class and type. For example, OED occupancy codes from 1050 to 1099 will be used to create instances of RealEstateAsset with type “Buildings/Residential”. This serves as text that can be matched to vulnerability configuration.

    Why is this done? Some vulnerability models are fine-grained and make full use of asset attributes, an example being the vulnerability functions for flood which may depend on occupancy, number of storeys elevation of the first finished floor etc. Other vulnerability models are sectorial in nature — that is, the vulnerability depends on the sector to which the asset belongs. An example is a model of change in productivity associated with chronic heat (change in temperature extremes) where the vulnerability is more a function of the sector to which the asset belongs.

Specification of vulnerability models

For any type of asset, e.g. RealEstateAsset, multiple vulnerability models are assigned which are uniquely specified by:

  • Hazard type, e.g. Wind, RiverineInundation, ChronicHeat etc

  • Hazard indicator identifier, e.g. ‘flood_depth’, ‘days_wbgt_above’ (number of days with wet bulb globe temperature above different thresholds)

  • Impact type: ‘damage’ (to asset structure, contents or inventory) or ‘disruption’ (to revenue generation)

Some hazards may have just a single mechanism for loss, e.g. riverine inundation depends on flood depth; others, e.g. chronic heat has multiple mechanisms, with different indicators.

Vulnerability models are defined in two steps: 1) For specific asset types, programmatic vulnerability models are assigned.

  1. Vulnerability models are created and assigned based on the vulnerability configuration.

The rule is that the models of step 2 do not replace those of step 1; if a programmatic model exists for RiverineInundation and RealEstateAssets that models damage based on flood depth, this is not replaced by such a model defined in configuration. The reason for this is that vulnerability configuration can be specified that is generic in that it applies to all asset types.

By default in step 1, programmatic models are assigned to power generating assets and programmatic inundation and wind models are assigned to all other asset types. These select damage curves from FEMA Hazus, based on Open Exposure Data attributes of the asset.

Vulnerability configuration

Types of curve

The configuration comprises two types of vulnerability curve: 1) Damage curves
For acute risks, this specifies the fractional damage or disruption, given the occurrence of a hazard with a given indicator value. Damage means damage to the asset (structure, contents and inventory) as a fraction of the total insurable value. Disruption is disruption to revenue (as a fraction of the revenue generation assigned to that asset); disruption may be from downtime associated with asset damage, or other effects (e.g. productivity loss). curve_type: indicator/piecewise_linear.
e.g. for riverine flood, the curve \(x\) values are depth in metres and the curve \(y\) values are damage as fraction of total insurable value.
  1. Threshold curves For chronic risks, this specifies the fractional damage or disruption that occurs for hazard indicator threshold values. This is for hazard indicators that give the mean amount of time per year for which an indicator is greater than a threshold value. curve_type: threshold/piecewise_linear. e.g. for chronic heat, the indicator might be the number of days per year for which the maximum near-surface air temperature is greater than \(t\) degrees, \(t\) being the threshold values. The curve \(x\) values are the thresholds in degrees Celsius and the curve \(y\) values are the losses in production that occur for each day for which the maximum temperature is at that value.

Identifying assets

Assets are identified by: - Asset class. This is the broad class of asset e.g. real estate assets or power generating assets within which asset vulnerabilities tend to be modelled in a similar way and which tend to have a common set of attributes. The set of valid asset classes is defined within physrisk itself. - A number of asset attributes. Specifying the asset class is optional in that vulnerability curves can be defined for the parent Asset type, in which case only asset attributes are relevant.

Identifying assets within the configuration

The vulnerability function is associated to an asset by specification of the asset class and by a set of attribute key/value pairs in the form of a comma-separated string: ‘=<attribute1_value,=,…’. The attributes are matched to those of the asset.

Example 1: simple type/location model

We define two special attribute names: type and location. These are particularly suited for sectorial modelling applications or similar where little is known about the asset other than its class, some information about the type within the class and its location. For example, configuration might be provided for real estate assets in the form ‘type=Buildings/Commercial,location=Europe’. For sectorial analyses, type is based around industry classifications (e.g. NACE codes).

Example 2: occupancy identifier and attributes

Occupancy classifications are used to group assets with similar characteristics related to valuation and damage, or disruption characteristics. There are a number of important occupancy schemes, for example Open Exposure Data (OED). Assets can be identified via, occupancy_scheme, occupancy_id and a set of attributes needed to refine the selection, e.g. number of storeys within a particular occupancy identifier.

Example 3: explicit specification of curve

For families of vulnerability functions, we can define a set of curves by, e.g. ‘hazus_flood_curve_id=43’.

In all cases, logic in the code maps an asset’s attributes onto the attributes that define the vulnerability function.

Damage/disruption function specification

The scheme is designed to allow uncertainly in damage/disruption functions to be specified as well as the deterministic case comprising hazard indicator (\(x\)) values and the corresponding impact (damage/disruption) (\(y\)) values. This can be captured by \(x\) and \(y\) fields each containing an array. A third \(z\) field to capture information about the uncertainty in the vulnerability functions.

Case 1: deterministic damage curve provided

The hazard indicator values, \(x_i\), are given, \(i \in [1 \dots n]\) and the corresponding impacts \(y_i\).

\(x = [x_1, x_2, \dots, x_n]\)
\(y = [y_1, y_2, \dots, y_n]\)
\(z\) is empty

Case 2: mean and standard deviation provided

The hazard indicator values, \(x_i\), are given, \(i \in [1 \dots n]\).

\(f_i(y) = \mathbb{P}(Y=y|x_i)\)
\(\mu_i = \int f_i(y) y dy\)
\(\sigma_i^2 = \int f_i(y) y^2 dy - \mu_i^2\)

The means are given in \(y\) and the standard deviations in \(z\).

\(x = [x_1, x_2, \dots, x_n ]\)
\(y = [\mu_1, \mu_2, \dots, \mu_n ]\)
\(z = [\sigma_1, \sigma_2, \dots, \sigma_n ]\)

Case 3: discrete piece-wise linear cumulative density function (CDF) provided

The hazard indicator values, \(x_i\), are given, \(i \in [1 \dots n]\).

\(F_i(y) = \mathbb{P}(Y \leq y|x_i)\)

The CDF, \(F_i(y)\), is given for points \(y_j\), \(j \in [1 \dots m]\). \(F_{ij} = \mathbb{P}(Y \leq y_j|x_i)\)

\(x = [x_1, x_2, \dots, x_n ]\)
\(y = [y_1, y_2, \dots, y_m ]\)
\(z = [[F_{11}, F_{12}, \dots, F_{1m}], [F_{21}, F_{12}, \dots, F_{2m}], \dots, [F_{n1}, F_{n2}, \dots, F_{nm}]]\)

Example configuration: displaying

[1]:
# pip install nbformat pandas plotly requests
from io import StringIO
from physrisk.vulnerability_models.config_based_impact_curves import (
    config_items_from_csv,
    config_items_to_df,
)
import plotly.io
from plotly.subplots import make_subplots

plotly.io.renderers.default = "notebook"
[2]:
# Rainbow CSV is a useful add-in for dealing with vulnerability config as CSV.
# Here we paste in a couple of lines.

config_lines = """
hazard_class,asset_class,asset_identifier,indicator_id,indicator_units,impact_id,impact_units,curve_type,points_x,points_y,cap_of_points_x,cap_of_points_y,activation_of_points_x
"CoastalInundation,PluvialInundation,RiverineInundation,",RealEstateAsset,"type=Buildings/Residential,location=Europe",flood_depth,metres,damage,,indicator/piecewise_linear,"[0.05, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0, 6.0]","[0.0, 0.25, 0.4, 0.5, 0.6, 0.75, 0.85, 0.95, 1.0]",,,
ChronicHeat,ManufacturingAsset,"type=Chemical,location=Generic",days_tas/above/{temp_c}c,days/year,disruption,,threshold/piecewise_linear,"[15.0, 25.0, 35.0, 45.0, 55.0, 65.0]","[0.0, 0.1, 0.25, 0.5, 0.8, 1.0]",,,
"""
[3]:
config_items = config_items_from_csv(StringIO(config_lines))
df = config_items_to_df(config_items)
display(df)
hazard_class asset_class asset_identifier indicator_id indicator_units impact_id impact_units curve_type points_x points_y points_z points_kind cap_of_points_x cap_of_points_y activation_of_points_x
0 ChronicHeat ManufacturingAsset type=Chemical,location=Generic days_tas/above/{temp_c}c days/year disruption None threshold/piecewise_linear [15.0, 25.0, 35.0, 45.0, 55.0, 65.0] [0.0, 0.1, 0.25, 0.5, 0.8, 1.0] None None None None None
1 CoastalInundation RealEstateAsset type=Buildings/Residential,location=Europe flood_depth metres damage None indicator/piecewise_linear [0.05, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0, 6.0] [0.0, 0.25, 0.4, 0.5, 0.6, 0.75, 0.85, 0.95, 1.0] None None None None None
2 PluvialInundation RealEstateAsset type=Buildings/Residential,location=Europe flood_depth metres damage None indicator/piecewise_linear [0.05, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0, 6.0] [0.0, 0.25, 0.4, 0.5, 0.6, 0.75, 0.85, 0.95, 1.0] None None None None None
3 RiverineInundation RealEstateAsset type=Buildings/Residential,location=Europe flood_depth metres damage None indicator/piecewise_linear [0.05, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0, 6.0] [0.0, 0.25, 0.4, 0.5, 0.6, 0.75, 0.85, 0.95, 1.0] None None None None None
[4]:
c1 = next(
    c
    for c in config_items
    if c.asset_class == "RealEstateAsset" and c.indicator_id == "flood_depth"
)
c2 = next(
    c
    for c in config_items
    if c.asset_class == "ManufacturingAsset"
    and c.indicator_id == "days_tas/above/{temp_c}c"
)

fig1 = make_subplots(rows=1, cols=2)
fig1.add_scatter(
    x=c1.points_x, y=c1.points_y, name="Example damage curve", row=1, col=1
)
fig1.add_scatter(
    x=c2.points_x, y=c2.points_y, name="Example threshold curve", row=1, col=2
)
fig1.update_xaxes(title="Flood depth (m)", title_font={"size": 14}, row=1, col=1)
fig1.update_xaxes(title="Threshold (°C)", title_font={"size": 14}, row=1, col=2)
fig1.update_yaxes(title="Damage as fraction of insurable value", row=1, col=1)
fig1.update_yaxes(title="Fractional loss of production", row=1, col=2)
fig1.update_layout(legend=dict(orientation="h", y=-0.15))
# fig1.update_layout(legend=dict(yanchor="top", y=0.99, xanchor="left", x=0.01))
fig1.update_layout(margin=dict(l=20, r=20, t=20, b=20))