Skip to content

Commit d2b0f6b

Browse files
committed
refactor(impact strat): Clarifies/Simplified computation
1 parent 3db32ca commit d2b0f6b

File tree

1 file changed

+45
-57
lines changed

1 file changed

+45
-57
lines changed

climada/trajectories/impact_calc_strat.py

Lines changed: 45 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,11 @@ def compute_impacts(
3838
self,
3939
snapshot0: Snapshot,
4040
snapshot1: Snapshot,
41+
future: tuple[int, int, int],
4142
risk_transf_attach: float | None,
4243
risk_transf_cover: float | None,
4344
calc_residual: bool,
44-
) -> tuple:
45+
) -> Impact:
4546
pass
4647

4748

@@ -52,47 +53,40 @@ def compute_impacts(
5253
self,
5354
snapshot0: Snapshot,
5455
snapshot1: Snapshot,
56+
future: tuple[int, int, int],
5557
risk_transf_attach: float | None,
5658
risk_transf_cover: float | None,
5759
calc_residual: bool = False,
5860
):
59-
impacts = self._calculate_impacts_for_snapshots(snapshot0, snapshot1)
61+
impact = self.compute_impacts_pre_transfer(snapshot0, snapshot1, future)
6062
self._apply_risk_transfer(
61-
impacts, risk_transf_attach, risk_transf_cover, calc_residual
63+
impact, risk_transf_attach, risk_transf_cover, calc_residual
6264
)
63-
return impacts
65+
return impact
6466

65-
def _calculate_impacts_for_snapshots(
66-
self, snapshot0: Snapshot, snapshot1: Snapshot
67-
):
68-
"""Calculate impacts for the given snapshots and impact function set."""
69-
imp_E0H0 = ImpactCalc(
70-
snapshot0.exposure, snapshot0.impfset, snapshot0.hazard
71-
).impact()
72-
imp_E1H0 = ImpactCalc(
73-
snapshot1.exposure, snapshot1.impfset, snapshot0.hazard
74-
).impact()
75-
imp_E0H1 = ImpactCalc(
76-
snapshot0.exposure, snapshot0.impfset, snapshot1.hazard
77-
).impact()
78-
imp_E1H1 = ImpactCalc(
79-
snapshot1.exposure, snapshot1.impfset, snapshot1.hazard
80-
).impact()
81-
return imp_E0H0, imp_E1H0, imp_E0H1, imp_E1H1
67+
def compute_impacts_pre_transfer(
68+
self,
69+
snapshot0: Snapshot,
70+
snapshot1: Snapshot,
71+
future: tuple[int, int, int],
72+
) -> Impact:
73+
exp = snapshot1.exposure if future[0] else snapshot0.exposure
74+
haz = snapshot1.hazard if future[1] else snapshot0.hazard
75+
vul = snapshot1.impfset if future[2] else snapshot0.impfset
76+
return ImpactCalc(exposures=exp, impfset=vul, hazard=haz).impact()
8277

8378
def _apply_risk_transfer(
8479
self,
85-
impacts: tuple[Impact, Impact, Impact, Impact],
80+
impact: Impact,
8681
risk_transf_attach: float | None,
8782
risk_transf_cover: float | None,
8883
calc_residual: bool,
8984
):
9085
"""Apply risk transfer to the calculated impacts."""
9186
if risk_transf_attach is not None and risk_transf_cover is not None:
92-
for imp in impacts:
93-
imp.imp_mat = self.calculate_residual_or_risk_transfer_impact_matrix(
94-
imp.imp_mat, risk_transf_attach, risk_transf_cover, calc_residual
95-
)
87+
impact.imp_mat = self.calculate_residual_or_risk_transfer_impact_matrix(
88+
impact.imp_mat, risk_transf_attach, risk_transf_cover, calc_residual
89+
)
9690

9791
def calculate_residual_or_risk_transfer_impact_matrix(
9892
self, imp_mat, risk_transf_attach, risk_transf_cover, calc_residual
@@ -111,9 +105,9 @@ def calculate_residual_or_risk_transfer_impact_matrix(
111105
----------
112106
imp_mat : scipy.sparse.csr_matrix
113107
The original impact matrix to be scaled.
114-
attachment : float, optional
108+
attachment : float
115109
The attachment point for the risk layer.
116-
cover : float, optional
110+
cover : float
117111
The maximum coverage for the risk layer.
118112
calc_residual : bool, default=True
119113
Determines if the function calculates the residual (if True) or the
@@ -125,36 +119,30 @@ def calculate_residual_or_risk_transfer_impact_matrix(
125119
The adjusted impact matrix, either residual or risk transfer.
126120
127121
"""
122+
imp_mat = copy.deepcopy(imp_mat)
123+
# Calculate the total impact per event
124+
total_at_event = imp_mat.sum(axis=1).A1
125+
# Risk layer at event
126+
transfer_at_event = np.minimum(
127+
np.maximum(total_at_event - risk_transf_attach, 0), risk_transf_cover
128+
)
129+
residual_at_event = np.maximum(total_at_event - transfer_at_event, 0)
128130

129-
if risk_transf_attach and risk_transf_cover:
130-
imp_mat = copy.deepcopy(imp_mat)
131-
# Calculate the total impact per event
132-
total_at_event = imp_mat.sum(axis=1).A1
133-
# Risk layer at event
134-
transfer_at_event = np.minimum(
135-
np.maximum(total_at_event - risk_transf_attach, 0), risk_transf_cover
136-
)
137-
residual_at_event = np.maximum(total_at_event - transfer_at_event, 0)
138-
139-
# Calculate either the residual or transfer impact matrix
140-
# Choose the denominator to rescale the impact values
141-
if calc_residual:
142-
numerator = residual_at_event
143-
else:
144-
numerator = transfer_at_event
145-
146-
rescale_impact_values = np.divide(
147-
numerator,
148-
total_at_event,
149-
out=np.zeros_like(numerator, dtype=float),
150-
where=total_at_event != 0,
151-
)
152-
153-
# The multiplication is broadcasted across the columns for each row
154-
result_matrix = imp_mat.multiply(rescale_impact_values[:, np.newaxis])
131+
# Calculate either the residual or transfer impact matrix
132+
# Choose the denominator to rescale the impact values
133+
if calc_residual:
134+
numerator = residual_at_event
135+
else:
136+
numerator = transfer_at_event
155137

156-
return result_matrix
138+
rescale_impact_values = np.divide(
139+
numerator,
140+
total_at_event,
141+
out=np.zeros_like(numerator, dtype=float),
142+
where=total_at_event != 0,
143+
)
157144

158-
else:
145+
# The multiplication is broadcasted across the columns for each row
146+
result_matrix = imp_mat.multiply(rescale_impact_values[:, np.newaxis])
159147

160-
return imp_mat
148+
return result_matrix

0 commit comments

Comments
 (0)