Skip to content

Commit 55c033f

Browse files
added method "extrapolate_constant" and changed behaviour of "interpolate"
1 parent 0cfe35c commit 55c033f

File tree

5 files changed

+77
-29
lines changed

5 files changed

+77
-29
lines changed

climada/engine/impact.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,9 @@ def local_exceedance_impact(
488488
locally (at each centroid). Defaults to (25, 50, 100, 250).
489489
method : str
490490
Method to interpolate to new return periods. Currently available are "interpolate",
491-
"extrapolate" and "stepfunction". If set to "interpolate" or "stepfunction",
491+
"extrapolate", "extrapolate_constant" and "stepfunction". If set to "interpolate",
492+
return periods outside the range of the Impact object's observed local return periods
493+
will be assigned NaN. If set to "extrapolate_constant" or "stepfunction",
492494
return periods larger than the Impact object's observed local return periods will be
493495
assigned the largest local impact, and return periods smaller than the Impact object's
494496
observed local return periods will be assigned 0. If set to "extrapolate", local
@@ -551,14 +553,15 @@ def local_exceedance_impact(
551553
frequency = np.cumsum(frequency[::-1])[::-1]
552554
if method == 'stepfunction':
553555
imp_stats[:,i] = u_interp.stepfunction_ev(
554-
1/np.array(return_periods), frequency[::-1], impact[::-1], y_threshold=min_impact,
555-
y_asymptotic=0.
556+
1/np.array(return_periods), frequency[::-1], impact[::-1],
557+
y_threshold=min_impact, y_asymptotic=0.
556558
)
557-
elif method == 'extrapolate' or method == 'interpolate':
558-
extrapolation = (method == 'extrapolate')
559+
elif method in ['interpolate', 'extrapolate', 'extrapolate_constant']:
560+
extrapolation = None if method == 'interpolate' else method
559561
imp_stats[:,i] = u_interp.interpolate_ev(
560-
1/np.array(return_periods), frequency[::-1], impact[::-1], logx=log_frequency,
561-
logy=log_impact, y_threshold=min_impact, extrapolation=extrapolation, y_asymptotic=0.
562+
1/np.array(return_periods), frequency[::-1], impact[::-1],
563+
logx=log_frequency, logy=log_impact, y_threshold=min_impact,
564+
extrapolation=extrapolation, y_asymptotic=0.
562565
)
563566
else:
564567
raise ValueError(f"Unknown method: {method}")

climada/hazard/base.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,9 @@ def local_exceedance_intensity(
467467
locally (at each centroid). Defaults to (25, 50, 100, 250).
468468
method : str
469469
Method to interpolate to new return periods. Currently available are "interpolate",
470-
"extrapolate" and "stepfunction". If set to "interpolate" or "stepfunction", return
470+
"extrapolate", "extrapolate_constant" and "stepfunction". If set to "interpolate",
471+
return periods outside the range of the Hazard object's observed local return periods
472+
will be assigned NaN. If set to "extrapolate_constant" or "stepfunction", return
471473
periods larger than the Hazard object's observed local return periods will be assigned
472474
the largest local intensity, and return periods smaller than the Hazard object's
473475
observed local return periods will be assigned 0. If set to "extrapolate", local
@@ -528,14 +530,15 @@ def local_exceedance_intensity(
528530
frequency = np.cumsum(frequency[::-1])[::-1]
529531
if method == 'stepfunction':
530532
inten_stats[:,i] = u_interp.stepfunction_ev(
531-
1/np.array(return_periods), frequency[::-1], intensity[::-1], y_threshold=min_intensity,
532-
y_asymptotic=0.
533+
1/np.array(return_periods), frequency[::-1], intensity[::-1],
534+
y_threshold=min_intensity, y_asymptotic=0.
533535
)
534-
elif method == 'interpolate' or method == 'extrapolate':
535-
extrapolation = (method == 'extrapolate')
536+
elif method in ['interpolate', 'extrapolate', 'extrapolate_constant']:
537+
extrapolation = None if method == 'interpolate' else method
536538
inten_stats[:,i] = u_interp.interpolate_ev(
537-
1/np.array(return_periods), frequency[::-1], intensity[::-1], logx=log_frequeny,
538-
logy=log_intensity, y_threshold=min_intensity, y_asymptotic=0., extrapolation=extrapolation
539+
1/np.array(return_periods), frequency[::-1], intensity[::-1],
540+
logx=log_frequeny, logy=log_intensity, y_threshold=min_intensity,
541+
extrapolation=extrapolation, y_asymptotic=0.
539542
)
540543
else:
541544
raise ValueError(f"Unknown method: {method}")
@@ -587,7 +590,9 @@ def local_return_period(
587590
locally (at each centroid). Defaults to (10, 20)
588591
method : str
589592
Method to interpolate to new threshold intensities. Currently available are
590-
"interpolate", "extrapolate" and "stepfunction". If set to "interpolate" or
593+
"interpolate", "extrapolate", "extrapolate_constant" and "stepfunction". If set to
594+
"interpolate", threshold intensities outside the range of the Hazard object's local
595+
intensities will be assigned NaN. If set to "extrapolate_constant" or
591596
"stepfunction", threshold intensities larger than the Hazard object's local
592597
intensities will be assigned NaN, and threshold intensities smaller than the Hazard
593598
object's local intensities will be assigned the smallest observed local return period.
@@ -653,11 +658,12 @@ def local_return_period(
653658
return_periods[:,i] = u_interp.stepfunction_ev(
654659
threshold_intensities, intensity, frequency, x_threshold=min_intensity
655660
)
656-
elif method == 'interpolate' or method == "extrapolate":
657-
extrapolation = (method == "extrapolate")
661+
elif method in ['interpolate', 'extrapolate', 'extrapolate_constant']:
662+
extrapolation = None if method == 'interpolate' else method
658663
return_periods[:,i] = u_interp.interpolate_ev(
659664
threshold_intensities, intensity, frequency, logx=log_intensity,
660-
logy=log_frequency, x_threshold=min_intensity, extrapolation=extrapolation, y_asymptotic=np.nan
665+
logy=log_frequency, x_threshold=min_intensity, extrapolation=extrapolation,
666+
y_asymptotic=np.nan
661667
)
662668
else:
663669
raise ValueError(f"Unknown method: {method}")

climada/hazard/test/test_base.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,7 +1032,7 @@ def test_degenerate_pass(self):
10321032
return_period = np.array([25, 50, 100, 250])
10331033
haz.intensity = sparse.csr_matrix(np.zeros(haz.intensity.shape))
10341034
inten_stats = haz.local_exceedance_intensity(return_period)[0].values[:, 1:].T.astype(float)
1035-
self.assertTrue(np.array_equal(inten_stats, np.zeros((4, 100))))
1035+
np.testing.assert_allclose(inten_stats, np.full((4, 100), np.nan))
10361036

10371037
def test_local_exceedance_intensity(self):
10381038
"""Test local exceedance frequencies with lin lin interpolation"""
@@ -1049,7 +1049,7 @@ def test_local_exceedance_intensity(self):
10491049
# third centroid has intensities 1 with cum frequencies 1
10501050
# testing at frequencies 2, 1.5, 1
10511051
inten_stats, _, _ = haz.local_exceedance_intensity(
1052-
return_period, log_frequeny=False, log_intensity=False)
1052+
return_period, log_frequeny=False, log_intensity=False, method='extrapolate_constant')
10531053
np.testing.assert_allclose(
10541054
inten_stats[inten_stats.columns[1:]].values,
10551055
np.array([
@@ -1073,7 +1073,8 @@ def test_local_return_period(self):
10731073
# third centroid has intensities 1 with cum frequencies 1 (0 intensity is neglected)
10741074
# testing at intensities 1, 2, 3
10751075
return_stats, _, _ = haz.local_return_period(
1076-
threshold_intensities, log_frequency=False, log_intensity=False, min_intensity=0)
1076+
threshold_intensities, log_frequency=False, log_intensity=False, min_intensity=0,
1077+
method='extrapolate_constant')
10771078
np.testing.assert_allclose(
10781079
return_stats[return_stats.columns[1:]].values,
10791080
np.array([

climada/test/test_engine.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -335,9 +335,9 @@ def test_local_exceedance_impact_methods(self):
335335
]),
336336
rtol=0.8)
337337

338-
# test log log interpolation and no extrapolation
338+
# test log log interpolation and extrapolation with constant
339339
impact_stats, _, _ = impact.local_exceedance_impact(
340-
return_periods=(1000, 30, .1))
340+
return_periods=(1000, 30, .1), method = "extrapolate_constant")
341341
np.testing.assert_allclose(
342342
impact_stats.values[:,1:].astype(float),
343343
np.array([
@@ -348,9 +348,22 @@ def test_local_exceedance_impact_methods(self):
348348
]),
349349
rtol=0.8)
350350

351+
# test log log interpolation and no extrapolation
352+
impact_stats, _, _ = impact.local_exceedance_impact(
353+
return_periods=(1000, 30, .1))
354+
np.testing.assert_allclose(
355+
impact_stats.values[:,1:].astype(float),
356+
np.array([
357+
[np.nan, np.nan, np.nan],
358+
[np.nan, np.nan, np.nan],
359+
[np.nan, 1e2, np.nan],
360+
[np.nan, 300, np.nan]
361+
]),
362+
rtol=0.8)
363+
351364
# test lin lin interpolation with no extrapolation
352365
impact_stats, _, _ = impact.local_exceedance_impact(
353-
return_periods=(1000, 30, .1),
366+
return_periods=(1000, 30, .1), method = "extrapolate_constant",
354367
log_frequency=False, log_impact=False)
355368
np.testing.assert_allclose(
356369
impact_stats.values[:,1:].astype(float),

climada/test/test_hazard.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -432,9 +432,9 @@ def test_local_exceedance_intensity_methods(self):
432432
]),
433433
rtol=0.8)
434434

435-
# test log log interpolation and no extrapolation
435+
# test log log interpolation and extrapolation with constant
436436
inten_stats, _, _ = haz.local_exceedance_intensity(
437-
return_periods=(1000, 30, .1))
437+
return_periods=(1000, 30, .1), method='extrapolate_constant')
438438
np.testing.assert_allclose(
439439
inten_stats.values[:,1:].astype(float),
440440
np.array([
@@ -444,9 +444,22 @@ def test_local_exceedance_intensity_methods(self):
444444
]),
445445
rtol=0.8)
446446

447+
# test log log interpolation and no extrapolation
448+
inten_stats, _, _ = haz.local_exceedance_intensity(
449+
return_periods=(1000, 30, .1))
450+
np.testing.assert_allclose(
451+
inten_stats.values[:,1:].astype(float),
452+
np.array([
453+
[np.nan, np.nan, np.nan],
454+
[np.nan, 1e2, np.nan],
455+
[np.nan, 300, np.nan]
456+
]),
457+
rtol=0.8)
458+
447459
# test lin lin interpolation without extrapolation
448460
inten_stats, _, _ = haz.local_exceedance_intensity(
449-
return_periods=(1000, 30, .1), log_frequeny=False, log_intensity=False)
461+
return_periods=(1000, 30, .1), log_frequeny=False, log_intensity=False,
462+
method='extrapolate_constant')
450463
np.testing.assert_allclose(
451464
inten_stats.values[:,1:].astype(float),
452465
np.array([
@@ -495,9 +508,9 @@ def test_local_return_period_methods(self):
495508
]),
496509
rtol=0.8)
497510

498-
# test log log interpolation and no extrapolation
511+
# test log log interpolation and extrapolation with constant
499512
return_stats, _, _ = haz.local_return_period(
500-
threshold_intensities=(.1, 300, 1e5))
513+
threshold_intensities=(.1, 300, 1e5), method='extrapolate_constant')
501514
np.testing.assert_allclose(
502515
return_stats.values[:,1:].astype(float),
503516
np.array([
@@ -507,6 +520,18 @@ def test_local_return_period_methods(self):
507520
]),
508521
rtol=0.8)
509522

523+
# test log log interpolation and no extrapolation
524+
return_stats, _, _ = haz.local_return_period(
525+
threshold_intensities=(.1, 300, 1e5))
526+
np.testing.assert_allclose(
527+
return_stats.values[:,1:].astype(float),
528+
np.array([
529+
[np.nan, np.nan, np.nan],
530+
[np.nan, 30, np.nan],
531+
[np.nan, 30, np.nan]
532+
]),
533+
rtol=0.8)
534+
510535
# Execute Tests
511536
if __name__ == "__main__":
512537
TESTS = unittest.TestLoader().loadTestsFromTestCase(TestCentroids)

0 commit comments

Comments
 (0)