Skip to content

Commit f88ecbd

Browse files
authored
Catch case where new Hazard fraction is unintentionally zero (#869)
* Catch case where new Hazard fraction is unintentionally zero * Eliminate zeros in fraction matrix before selecting * Update CHANGELOG.md
1 parent 37b1e5e commit f88ecbd

File tree

3 files changed

+38
-0
lines changed

3 files changed

+38
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Code freeze date: YYYY-MM-DD
1717

1818
### Fixed
1919

20+
- Avoid an issue where a Hazard subselection would have a fraction matrix with only zeros as entries by throwing an error [#866](https://github.com/CLIMADA-project/climada_python/pull/866)
21+
2022
### Added
2123

2224
- climada.hazard.centroids.centr.Centroids.get_area_pixel

climada/hazard/base.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,6 +1197,10 @@ def select(self, event_names=None, event_id=None, date=None, orig=None,
11971197
LOGGER.info('No hazard centroids within extent and region')
11981198
return None
11991199

1200+
# Sanitize fraction, because we check non-zero entries later
1201+
self.fraction.eliminate_zeros()
1202+
1203+
# Perform attribute selection
12001204
for (var_name, var_val) in self.__dict__.items():
12011205
if isinstance(var_val, np.ndarray) and var_val.ndim == 1 \
12021206
and var_val.size > 0:
@@ -1227,6 +1231,18 @@ def select(self, event_names=None, event_id=None, date=None, orig=None,
12271231
dt.datetime.fromordinal(haz.date.min()).year) + 1
12281232
haz.frequency = haz.frequency * year_span_old / year_span_new
12291233

1234+
# Check if new fraction is zero everywhere
1235+
if self._get_fraction() is not None and haz._get_fraction() is None:
1236+
raise RuntimeError(
1237+
"Your selection created a Hazard object where the fraction matrix is "
1238+
"zero everywhere. This hazard will have zero impact everywhere. "
1239+
"We are catching this condition because of an implementation detail: "
1240+
"A fraction matrix without nonzero-valued entries will be completely "
1241+
"ignored. This is surely not what you intended. If you really want to, "
1242+
"you can circumvent this error by setting your original fraction "
1243+
"matrix to zero everywhere, but there probably is no point in doing so."
1244+
)
1245+
12301246
haz.sanitize_event_ids()
12311247
return haz
12321248

climada/hazard/test/test_base.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,26 @@ def test_select_tight_pass(self):
595595
self.assertIsInstance(sel_haz.intensity, sparse.csr_matrix)
596596
self.assertIsInstance(sel_haz.fraction, sparse.csr_matrix)
597597

598+
def test_select_new_fraction_zero(self):
599+
"""Check if a new fraction of only zeros is handled correctly"""
600+
hazard = dummy_hazard()
601+
hazard.centroids.gdf["region_id"] = [1, 1, 2]
602+
603+
# Select a part of the hazard where fraction is zero only
604+
with self.assertRaisesRegex(
605+
RuntimeError,
606+
"Your selection created a Hazard object where the fraction matrix is zero "
607+
"everywhere"
608+
):
609+
hazard.select(event_id=[3, 4], reg_id=[2])
610+
611+
# Error should not be thrown if we set everything to zero
612+
# NOTE: Setting the values of `data` to zero instead of the matrix values will
613+
# add explicitly stored zeros. Therefore, this test explicitly checks if
614+
# `eliminate_zeros` is called on `fraction` during `select`.
615+
hazard.fraction.data[...] = 0
616+
selection = hazard.select(event_id=[3, 4], reg_id=[2])
617+
np.testing.assert_array_equal(selection.fraction.toarray(), [[0], [0]])
598618

599619
class TestAppend(unittest.TestCase):
600620
"""Test append method."""

0 commit comments

Comments
 (0)