Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
7da50f1
Return impactForecast object in _return_impact
luseverin Dec 8, 2025
bd3502f
Return impactForecast object in _return_empty
luseverin Dec 8, 2025
dfa0198
Add full impactcalc test for impactForecast
luseverin Dec 8, 2025
59c0e5b
Correct mistakes in _return_empty and _return_impact
luseverin Dec 8, 2025
4b5ae95
Raise value error when computing impact with impact forecast without …
luseverin Dec 8, 2025
9a516e1
Cosmetics: Improve error message, move test to own class
Dec 8, 2025
d571bb7
Merge branch 'forecast-class' into impactCalc_block_nonsense_attrs
luseverin Dec 9, 2025
6fe29f0
Merge branch 'impactCalc_return_impactForecast' into impactCalc_block…
luseverin Dec 9, 2025
899d8f0
add test to check that eai_exp and aai_agg are nan for forecasts
luseverin Dec 9, 2025
db32170
Write nans for eai_exp and aai_agg when forecast is used
luseverin Dec 9, 2025
d2f035f
update tests using pytest
luseverin Dec 9, 2025
c10a4b3
Fix error in test fixtures
luseverin Dec 9, 2025
d3a5642
Returns nans for eai_exp and aai_agg when exposures is empty
luseverin Dec 9, 2025
d43a46c
add warning when at_event is used with forecast
luseverin Dec 9, 2025
e197566
Update ImpactCalc tests for forecasts
peanutfun Dec 9, 2025
0a324b2
Merge branch 'impactCalc_return_impactForecast' of https://github.com…
peanutfun Dec 9, 2025
554cfc8
Review ImpactCalc forecast handling
peanutfun Dec 9, 2025
30ed14d
Block local_exceedance_impact
luseverin Dec 9, 2025
f3ab44a
Fix bug in test
peanutfun Dec 9, 2025
612a53c
Merge branch 'impactCalc_return_impactForecast' of https://github.com…
peanutfun Dec 9, 2025
9e4f2bb
Block return_period and exceedance_freq_curve
luseverin Dec 9, 2025
727357e
Log warning for at_event getter
luseverin Dec 9, 2025
31f0ca7
Update docstrings
peanutfun Dec 9, 2025
0593a86
Merge branch 'forecast-class' into impactCalc_return_impactForecast
peanutfun Dec 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 43 additions & 6 deletions climada/engine/impact_calc.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@

from climada import CONFIG
from climada.engine.impact import Impact
from climada.engine.impact_forecast import ImpactForecast
from climada.hazard.forecast import HazardForecast

LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -217,7 +219,7 @@ def _return_impact(self, imp_mat_gen, save_mat):

Returns
-------
Impact
Impact or ImpactForecast
Impact Object initialize from the impact matrix

See Also
Expand All @@ -230,12 +232,31 @@ def _return_impact(self, imp_mat_gen, save_mat):
at_event, eai_exp, aai_agg = self.risk_metrics(
imp_mat, self.hazard.frequency
)
if isinstance(self.hazard, HazardForecast):
eai_exp = np.full_like(eai_exp, np.nan, dtype=eai_exp.dtype)
aai_agg = np.full_like(aai_agg, np.nan, dtype=aai_agg.dtype)
LOGGER.warning(
"eai_exp and aai_agg are undefined with forecasts. "
"Setting them to NaN arrays."
)

else:
if isinstance(self.hazard, HazardForecast):
raise ValueError(
"Saving impact matrix is required when using HazardForecast."
"Please set save_mat=True."
)
imp_mat = None
at_event, eai_exp, aai_agg = self.stitch_risk_metrics(imp_mat_gen)
return Impact.from_eih(

impact = Impact.from_eih(
self.exposures, self.hazard, at_event, eai_exp, aai_agg, imp_mat
)
if isinstance(self.hazard, HazardForecast):
return ImpactForecast.from_impact(
impact, self.hazard.lead_time, self.hazard.member
)
return impact

def _return_empty(self, save_mat):
"""
Expand All @@ -248,21 +269,37 @@ def _return_empty(self, save_mat):

Returns
-------
Impact
Impact or ImpactForecast
Empty impact object with correct array sizes.
"""
at_event = np.zeros(self.n_events)
eai_exp = np.zeros(self.n_exp_pnt)
aai_agg = 0.0
if isinstance(self.hazard, HazardForecast):
eai_exp = np.full(self.n_exp_pnt, np.nan)
aai_agg = np.nan
else:
eai_exp = np.zeros(self.n_exp_pnt)
aai_agg = 0.0

if save_mat:
imp_mat = sparse.csr_matrix(
(self.n_events, self.n_exp_pnt), dtype=np.float64
)
else:
if isinstance(self.hazard, HazardForecast):
raise ValueError(
"Saving impact matrix is required when using HazardForecast. "
"Please set save_mat=True."
)
imp_mat = None
return Impact.from_eih(

impact = Impact.from_eih(
self.exposures, self.hazard, at_event, eai_exp, aai_agg, imp_mat
)
if isinstance(self.hazard, HazardForecast):
return ImpactForecast.from_impact(
impact, self.hazard.lead_time, self.hazard.member
)
return impact

def minimal_exp_gdf(
self, impf_col, assign_centroids, ignore_cover, ignore_deductible
Expand Down
82 changes: 82 additions & 0 deletions climada/engine/impact_forecast.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,88 @@ def from_impact(
haz_type=impact.haz_type,
)

@property
def at_event(self):
"""Get the total impact for each member/lead_time combination."""
LOGGER.warning(
"at_event gives the total impact for one specific combination of member and "
"lead_time."
)
return self._at_event

@at_event.setter
def at_event(self, value):
"""Set the total impact for each member/lead_time combination."""
self._at_event = value

def local_exceedance_impact(
self,
return_periods=(25, 50, 100, 250),
method="interpolate",
min_impact=0,
log_frequency=True,
log_impact=True,
bin_decimals=None,
):
"""Compution of local exceedance impact for given return periods is not
implemented for ImpactForecast.

See Also
--------
See :py:meth:`~climada.engine.impact.Impact.local_exceedance_impact`

Raises
------
NotImplementedError
"""

LOGGER.error("local_exceedance_impact is not defined for ImpactForecast")
raise NotImplementedError(
"local_exceedance_impact is not defined for ImpactForecast"
)

def local_return_period(
self,
threshold_impact=(1000.0, 10000.0),
method="interpolate",
min_impact=0,
log_frequency=True,
log_impact=True,
bin_decimals=None,
):
"""Compution of local return period for given impact thresholds is not
implemented for ImpactForecast.

See Also
--------
See :py:meth:`~climada.engine.impact.Impact.local_return_period`

Raises
-------
NotImplementedError
"""

LOGGER.error("local_return_period is not defined for ImpactForecast")
raise NotImplementedError(
"local_return_period is not defined for ImpactForecast"
)

def calc_freq_curve(self, return_per=None):
"""Computation of the impact exceedance frequency curve is not
implemented for ImpactForecast.

See Also
--------
See :py:meth:`~climada.engine.impact.Impact.calc_freq_curve`

Raises
------
NotImplementedError
"""

LOGGER.error("calc_freq_curve is not defined for ImpactForecast")
raise NotImplementedError("calc_freq_curve is not defined for ImpactForecast")

def _check_sizes(self):
"""Check sizes of forecast data vs. impact data.

Expand Down
Loading
Loading