Skip to content

Commit 7a73c87

Browse files
committed
Implements Chahan's comments
1 parent e55a481 commit 7a73c87

5 files changed

Lines changed: 50 additions & 17 deletions

File tree

climada/test/common_test_fixtures.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,4 +202,4 @@ def reusable_snapshot(
202202
)
203203
hazard = reusable_minimal_hazard(intensity_factor=hazard_intensity_increase_factor)
204204
impfset = reusable_minimal_impfset()
205-
return Snapshot(exposure=exposures, hazard=hazard, impfset=impfset, date=date)
205+
return Snapshot(exposure=exposures, hazard=hazard, impfset=impfset, date=str(date))

climada/test/test_trajectories.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ def setUp(self) -> None:
6868
self.expected_future_imp = ImpactCalc(
6969
**self.future_snapshot.impact_calc_data
7070
).impact()
71-
# self.group_vector = self.base_snapshot.exposure.gdf[GROUP_ID_COL_NAME]
7271
self.expected_base_return_period_impacts = {
7372
rp: imp
7473
for rp, imp in zip(

climada/trajectories/calc_risk_metrics.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ def __init__(
140140
141141
"""
142142

143-
self._reset_impact_data()
143+
self._init_impact_data()
144144
self.snapshots = snapshots
145145
self.impact_computation_strategy = impact_computation_strategy
146146
self._date_idx = pd.DatetimeIndex(
@@ -162,8 +162,10 @@ def __init__(
162162
error_message = str(exc).lower()
163163
if "need at least one array to concatenate" in error_message:
164164
self._group_id = np.array([])
165+
else:
166+
raise
165167

166-
def _reset_impact_data(self):
168+
def _init_impact_data(self):
167169
"""Util method that resets computed data, for instance when
168170
changing the computation strategy.
169171
@@ -173,6 +175,8 @@ def _reset_impact_data(self):
173175
self._per_date_eai = None
174176
self._per_date_aai = None
175177

178+
_reset_impact_data = _init_impact_data
179+
176180
@property
177181
def impact_computation_strategy(self) -> ImpactComputationStrategy:
178182
"""The method used to calculate the impact from the (Haz,Exp,Vul)
@@ -184,7 +188,9 @@ def impact_computation_strategy(self) -> ImpactComputationStrategy:
184188
@impact_computation_strategy.setter
185189
def impact_computation_strategy(self, value, /):
186190
if not isinstance(value, ImpactComputationStrategy):
187-
raise ValueError("Not an impact computation strategy")
191+
raise ValueError(
192+
"The provided value is not an ImpactComputationStrategy object. See the trajectory module documentation for more information on how to define your own impact computation strategies."
193+
)
188194

189195
self._impact_computation_strategy = value
190196
self._reset_impact_data()
@@ -332,9 +338,12 @@ def calc_return_periods_metric(self, return_periods: list[int]) -> pd.DataFrame:
332338
return rp_df
333339

334340
def apply_measure(self, measure: Measure) -> "CalcRiskMetricsPoints":
335-
"""Creates a new `CalcRiskMetricsPoints` object with a measure.
341+
"""Creates a new `CalcRiskMetricsPoints` object by applying the effects
342+
of the given measure.
336343
337-
The given measure is applied to both snapshot of the risk period.
344+
The effects of the measure are applied to all the snapshots contained
345+
in the initial `CalcRiskMetricsPoints` and a new `CalcRiskMetricsPoints`
346+
containing the modified snapshots is returned.
338347
339348
Parameters
340349
----------
@@ -344,7 +353,7 @@ def apply_measure(self, measure: Measure) -> "CalcRiskMetricsPoints":
344353
Returns
345354
-------
346355
347-
CalcRiskPeriod
356+
CalcRiskMetricsPoints
348357
The risk period with given measure applied.
349358
350359
"""

climada/trajectories/static_trajectory.py

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,16 @@
5959

6060

6161
class StaticRiskTrajectory(RiskTrajectory):
62-
"""This class implements static risk trajectories, objects that
62+
"""This class implements static risk trajectories: objects that
6363
regroup impacts computations for multiple dates.
6464
65-
This class computes risk metrics over a series of snapshots,
66-
optionally applying risk discounting. It does not interpolate risk
67-
between the snapshot and only provides results for each snapshot.
65+
This class computes risk metrics over a series of `Snapshot` objects,
66+
optionally applying risk discounting, and offers access to the results
67+
in tidy formatted pandas DataFrames.
68+
69+
Contrary to InterpolatedRiskTrajectories, it does not interpolate risk
70+
between the snapshot and only provides results at each snapshot specific
71+
date.
6872
6973
"""
7074

@@ -115,7 +119,7 @@ def __init__(
115119
The discount rate to apply to future risk. Defaults to None.
116120
impact_computation_strategy: ImpactComputationStrategy, optional
117121
The method used to calculate the impact from the (Haz,Exp,Vul)
118-
of the two snapshots. Defaults to :class:`ImpactCalcComputation`.
122+
for each snapshot. Defaults to :class:`ImpactCalcComputation`.
119123
120124
"""
121125
super().__init__(
@@ -137,7 +141,11 @@ def impact_computation_strategy(self) -> ImpactComputationStrategy:
137141
@impact_computation_strategy.setter
138142
def impact_computation_strategy(self, value, /):
139143
if not isinstance(value, ImpactComputationStrategy):
140-
raise ValueError("Not an interpolation strategy")
144+
raise ValueError(
145+
"The provided impact computation strategy is not an ImpactComputationStrategy, "
146+
"please refer to the documentation to define your own strategies or stick to the "
147+
"default one"
148+
)
141149

142150
self._reset_metrics()
143151
self._risk_metrics_calculators.impact_computation_strategy = value
@@ -174,6 +182,15 @@ def _generic_metrics(
174182
A tidy formatted dataframe of the risk metric computed for the
175183
different snapshots.
176184
185+
Notes
186+
-----
187+
188+
The computation checks that there are no duplicated rows of results
189+
for the same tuples (Date, Group, Measure, Metric,
190+
[Coordinates for metrics on that level]) and takes the first row in
191+
this case.
192+
193+
177194
Raises
178195
------
179196
NotImplementedError
@@ -211,7 +228,12 @@ def _generic_metrics(
211228
# When more than 2 snapshots, there might be duplicated rows, we need to remove them.
212229
# Should not be the case in static trajectory, but in any case we really don't want
213230
# duplicated rows, which would mess up some dataframe manipulation down the road.
214-
tmp = tmp[~tmp.index.duplicated(keep="first")]
231+
if tmp.index.duplicated().any():
232+
LOGGER.warning(
233+
"Duplicated rows were found in the results. Will keep the first one."
234+
)
235+
tmp = tmp[~tmp.index.duplicated(keep="first")]
236+
215237
tmp = tmp.reset_index()
216238
if self._all_groups_name not in tmp[GROUP_COL_NAME].cat.categories:
217239
tmp[GROUP_COL_NAME] = tmp[GROUP_COL_NAME].cat.add_categories(
@@ -236,7 +258,8 @@ def eai_metrics(self, **kwargs) -> pd.DataFrame:
236258
Notes
237259
-----
238260
239-
This computation may become quite expensive for big areas with high resolution.
261+
This computation may become quite expensive for exposures with many points
262+
(e.g., big areas with high resolution).
240263
241264
"""
242265
metric_df = self._compute_metrics(

climada/trajectories/trajectory.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,9 @@ def risk_disc_rates(self) -> DiscRates | None:
172172
@risk_disc_rates.setter
173173
def risk_disc_rates(self, value, /):
174174
if value is not None and not isinstance(value, (DiscRates)):
175-
raise ValueError("Risk discount needs to be a `DiscRates` object.")
175+
raise ValueError(
176+
"The discount rate applied to risk values needs to be a `DiscRates` object."
177+
)
176178

177179
self._reset_metrics()
178180
self._risk_disc_rates = value

0 commit comments

Comments
 (0)