Skip to content

Commit

Permalink
Support historical scenario for score-based risk measures.
Browse files Browse the repository at this point in the history
Signed-off-by: Joe Moorhouse <[email protected]>
  • Loading branch information
joemoorhouse committed Dec 18, 2024
1 parent 7be265b commit 7b8c3be
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 26 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "physrisk-lib"
# Could test changing the below to be sourced "dynamically"
# dynamic = ['version']
version = "0.41.0"
version = "0.42.0"
description = "OS-Climate Physical Risk Library"
authors = [
{name = "Joe Moorhouse",email = "[email protected]"},
Expand Down
12 changes: 7 additions & 5 deletions src/physrisk/data/pregenerated_hazard_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,19 +138,21 @@ def _get_hazard_data_batch(
)
except Exception as err:
# e.g. the requested data is unavailable
for _i, req in enumerate(batch):
for _, req in enumerate(batch):
failed_response = HazardDataFailedResponse(err)
responses[req] = failed_response
failures.append(failed_response)

if any(failures):
logger.error(
f"{len(failures)} errors in batch (hazard_type={hazard_type.__name__}, indicator_id={indicator_id}, "
# only a warning: perhaps the caller does not expect data to be present for all
# year/scenario combinations.
logger.warning(
f"{len(failures)} requests failed in batch (hazard_type={hazard_type.__name__}, indicator_id={indicator_id}, "
f"scenario={scenario}, year={year}): (logs limited to first 3)"
)
errors = (str(i.error) for i in failures)
for _ in range(3):
logger.error(next(errors))
for _ in range(min(len(failures), 3)):
logger.warning(next(errors))
return


Expand Down
34 changes: 18 additions & 16 deletions src/physrisk/kernel/risk.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def _calculate_single_impact(
class MeasureKey(NamedTuple):
asset: Asset
prosp_scen: str # prospective scenario
year: int
year: Optional[int]
hazard_type: type


Expand Down Expand Up @@ -238,19 +238,19 @@ def get_measure_id(
return measure_ids_for_hazard, measure_id_lookup

def calculate_risk_measures(
self, assets: Sequence[Asset], prosp_scens: Sequence[str], years: Sequence[int]
self, assets: Sequence[Asset], scenarios: Sequence[str], years: Sequence[int]
):
impacts = self._calculate_all_impacts(
assets, prosp_scens, years, include_histo=True
assets, scenarios, years, include_histo=True
)
measures: Dict[MeasureKey, Measure] = {}
aggregated_measures: Dict[MeasureKey, Measure] = {}
for asset in assets:
if type(asset) not in self._measure_calculators:
continue
measure_calc = self._measure_calculators[type(asset)]
for prosp_scen in prosp_scens:
for year in years:
for scenario in scenarios:
for year in [None] if scenario == "historical" else years:
for hazard_type in measure_calc.supported_hazards():
base_impacts = impacts.get(
ImpactKey(
Expand All @@ -260,33 +260,35 @@ def calculate_risk_measures(
key_year=None,
)
)
prosp_impacts = impacts.get(
# the future impact might also be the historical if that is also specified
fut_impacts = impacts.get(
ImpactKey(
asset=asset,
hazard_type=hazard_type,
scenario=prosp_scen,
scenario=scenario,
key_year=year,
)
)
if base_impacts is None or fut_impacts is None:
# should only happen if we are working with limited hazard scope
continue
risk_inds = [
measure_calc.calc_measure(
hazard_type, base_impact, prosp_impact
)
for base_impact, prosp_impact in zip(
base_impacts, prosp_impacts
base_impacts, fut_impacts
)
]
risk_ind = [
risk_ind for risk_ind in risk_inds if risk_ind is not None
]
if len(risk_ind) > 0:
# TODO: Aggregate measures instead of picking the first value.
measures[
MeasureKey(asset, prosp_scen, year, hazard_type)
] = risk_ind[0]
aggregated_measures.update(
measure_calc.aggregate_risk_measures(
measures, assets, prosp_scens, years
)
)
measures[MeasureKey(asset, scenario, year, hazard_type)] = (
risk_ind[0]
)
aggregated_measures.update(
measure_calc.aggregate_risk_measures(measures, assets, scenarios, years)
)
return impacts, aggregated_measures
2 changes: 1 addition & 1 deletion src/physrisk/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ def _create_risk_measures(
measures_for_assets: List[RiskMeasuresForAssets] = []
for hazard_type in hazard_types:
for scenario_id in scenarios:
for year in years:
for year in [None] if scenario_id == "historical" else years:
# we calculate and tag results for each scenario, year and hazard
score_key = RiskMeasureKey(
hazard_type=hazard_type.__name__,
Expand Down
6 changes: 3 additions & 3 deletions tests/risk_models/risk_models_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def test_risk_indicator_model(self):
)
measure_ids_for_asset, definitions = model.populate_measure_definitions(assets)
_, measures = model.calculate_risk_measures(
assets, prosp_scens=scenarios, years=years
assets, scenarios=scenarios, years=years
)

# how to get a score using the MeasureKey
Expand Down Expand Up @@ -293,7 +293,7 @@ def sp_precipitation(scenario, year):
)

def test_via_requests(self):
scenarios = ["ssp585"]
scenarios = ["ssp585", "historical"]
years = [2050]

assets = self._create_assets()
Expand Down Expand Up @@ -386,7 +386,7 @@ def test_generic_model(self):
)
measure_ids_for_asset, definitions = model.populate_measure_definitions(assets)
_, measures = model.calculate_risk_measures(
assets, prosp_scens=scenarios, years=years
assets, scenarios=scenarios, years=years
)
np.testing.assert_approx_equal(
measures[MeasureKey(assets[0], scenarios[0], years[0], Wind)].measure_0,
Expand Down

0 comments on commit 7b8c3be

Please sign in to comment.