Asset-level impact calculations#

Here ‘asset-level’ impacts means the impact of hazards on each asset in a portfolio, taken in isolation. This is, as opposed to portfolio-level impacts where the asset impacts are aggregated together – a topic for another notebook.

Obtaining impact distributions for a portfolio of assets#

[1]:
# pip install nbformat pandas plotly requests
[2]:
import pprint as pp
from typing import NamedTuple
import requests

import plotly.graph_objs as go
import plotly.io
from plotly.subplots import make_subplots
plotly.io.renderers.default = "notebook"
[3]:
base_url = "https://physrisk-api2-sandbox.apps.odh-cl1.apps.os-climate.org/api/"

portfolio = {
    "items": [
        {
            "asset_class": "RealEstateAsset",
            "type": "Buildings/Industrial",
            "location": "Asia",
            "latitude": 24.0426,
            "longitude": 91.0158,
        },
        {
            "asset_class": "RealEstateAsset",
            "type": "Buildings/Industrial",
            "location": "Asia",
            "latitude": 22.6588,
            "longitude": 90.3373,
        },
    ]
}
request = {
    "assets": portfolio,
    "include_asset_level": True,
    "include_calc_details": True,
    "include_measures": True,
    "years": [2050],
    "scenario": "ssp585",
}

url = base_url + "get_asset_impact"
response = requests.post(url, json=request).json()
[4]:
asset0_impacts = response["asset_impacts"][1]["impacts"]


class Key(NamedTuple):
    hazard_type: str
    scenario_id: str
    year: str


asset0_impact_dict = {}
for i in asset0_impacts:
    key = i["key"]
    asset0_impact_dict[Key(key["hazard_type"], key["scenario_id"], key["year"])] = i

hazard_types = set(k.hazard_type for k in asset0_impact_dict.keys())
wind_impact_histo = asset0_impact_dict[Key("Wind", "historical", "None")]
wind_impact_ssp585 = asset0_impact_dict[Key("Wind", "ssp585", "2050")]
[5]:
exceedance_histo = wind_impact_histo["impact_exceedance"]
exceedance_ssp585 = wind_impact_ssp585["impact_exceedance"]

fig1 = make_subplots(rows=1, cols=1)

fig1.add_scatter(x=exceedance_histo["exceed_probabilities"], y=exceedance_histo["values"], name="baseline wind", row=1, col=1)
fig1.add_scatter(x=exceedance_ssp585["exceed_probabilities"], y=exceedance_ssp585["values"], name="wind SSP585", row=1, col=1)
fig1.update_xaxes(title="Annual exceedance probability", title_font={"size": 14}, row=1, col=1, type="log", autorange="reversed")
fig1.update_yaxes(title="Damage as fraction of insurable value", title_font={"size": 14}, row=1, col=1)

Making impacts actionable: score-based risk measures#

The main outputs of impact calculations are probability distributions of impacts, such as damage, but how do analysts make use of this data? Often it is desirable to categorize assets within a portfolio, for example identifying which are vulnerable to the physical effects of climate change and which are not. It may therefore be desirable to assign scores to assets, the score being meaningful for a particular analysis or work-flow. Two important points:

  1. These are risk scores, not exposure scores. Pure exposure scores take into account only the exposure of an asset to climate hazards, typically as a result of its location, but do not say anything about vulnerability. This makes exposure scores unsuitable for many use-cases. For example an asset that is exposed to a hazard that becomes more intense under certain climate change scenarios may still be low risk (under that scenario) if it is not vulnerable to the hazard in question.

  2. The definition of scores are in principle unique to a particular type of user/analyst. The scores that are most useful for the manager of a portfolio of assets may be different to those that are useful to a lender providing finance for a new project.

[6]:
asset_measures = response["risk_measures"]["measures_for_assets"]


class Key(NamedTuple):
    hazard_type: str
    measure_id: str
    scenario_id: str
    year: str


asset_measures_dict = {}
for i in asset_measures:
    key = i["key"]
    asset_measures_dict[Key(key["hazard_type"], key["measure_id"], key["scenario_id"], key["year"])] = i

wind_impact_scores = asset_measures_dict[Key("Wind", "measure_set_0", "ssp585", "2050")]

scores = wind_impact_scores["scores"]
print(f"The scores for the assets are: {scores}.")
print(f"The scores for the assets are: {scores}.")
The scores for the assets are: [1, 3].
The scores for the assets are: [1, 3].
[7]:
pp.pprint(response["risk_measures"]["score_based_measure_set_defn"]["score_definitions"]["measure_1"])
{'hazard_types': ['RiverineInundation', 'CoastalInundation', 'Wind'],
 'underlying_measures': [{'description': '1-in-100 year loss as fraction of '
                                         'asset insured value.',
                          'label': '1-in-100 year annual loss.',
                          'measure_id': 'measures_0'}],
 'values': [{'description': 'Projected 1-in-100 year annual loss is more than '
                            '10% and increases by more than 3% of asset value '
                            'over historical baseline.',
             'label': 'The asset is very significantly impacted and the impact '
                      'will increase as a result of climate change.',
             'value': 4},
            {'description': 'Projected 1-in-100 year annual loss is more than '
                            '3% and increases by more than 3% of asset value '
                            'over historical baseline.',
             'label': 'The asset is materially impacted and the impact will '
                      'increase as a result of climate change.',
             'value': 3},
            {'description': 'Projected 1-in-100 year annual loss is more than '
                            '3% but increases by less than 3% of asset value '
                            'over historical baseline.',
             'label': 'The asset is materially impacted but the impact will '
                      'not significantly increase as a result of climate '
                      'change.',
             'value': 2},
            {'description': 'Projected 1-in-100 year annual loss is less than '
                            '3% of asset value.',
             'label': 'No material impact.',
             'value': 1},
            {'description': 'No data.', 'label': 'No data.', 'value': 0}]}

Running impacts through physrisk directly#

Just as for obtaining hazard indicators, it is possible to run the same calculations using physrisk directly, as long as the necessary API keys are present in a credentials.env file.

For developers who are focussed on using existing hazard models but building new vulnerability models or risk models, it is desirable to be able to develop these components locally while making use of hazard APIs. This is functionality which will be provided in a future version.

[8]:
from dotenv import load_dotenv
from physrisk.container import Container
[9]:
load_dotenv("../../credentials.env")
# the container is a dependency injection container,
# which allows the calculation to be configured to a particular use-case
container = Container()
# the requester is used to run calculations using the API.
# At this point, we can of course debug into the code and modify as required.
requester = container.requester()
result = requester.get(request_id="get_asset_impact", request_dict=request)