|
54 | 54 | from climada.entity import Exposures |
55 | 55 | from climada.util.constants import CMAP_IMPACT, DEF_CRS, DEF_FREQ_UNIT |
56 | 56 | from climada.util.select import get_attributes_with_matching_dimension |
| 57 | +from climada.util.value_representation import safe_divide |
57 | 58 |
|
58 | 59 | LOGGER = logging.getLogger(__name__) |
59 | 60 |
|
@@ -499,7 +500,7 @@ def local_exceedance_impact( |
499 | 500 | ): |
500 | 501 | """Compute local exceedance impact for given return periods. The default method |
501 | 502 | is fitting the ordered impacts per centroid to the corresponding cummulated |
502 | | - frequency with by linear interpolation on log-log scale. |
| 503 | + frequency with linear interpolation on log-log scale. |
503 | 504 |
|
504 | 505 | Parameters |
505 | 506 | ---------- |
@@ -610,6 +611,113 @@ def local_exceedance_imp(self, return_periods=(25, 50, 100, 250)): |
610 | 611 | .T.astype(float) |
611 | 612 | ) |
612 | 613 |
|
| 614 | + def local_return_period( |
| 615 | + self, |
| 616 | + threshold_impact=(1000.0, 10000.0), |
| 617 | + method="interpolate", |
| 618 | + min_impact=0, |
| 619 | + log_frequency=True, |
| 620 | + log_impact=True, |
| 621 | + ): |
| 622 | + """Compute local return periods for given threshold impacts. The default method |
| 623 | + is fitting the ordered impacts per centroid to the corresponding cummulated |
| 624 | + frequency with linear interpolation on log-log scale. |
| 625 | +
|
| 626 | + Parameters |
| 627 | + ---------- |
| 628 | + threshold_impact : array_like |
| 629 | + User-specified impact values for which the return period should be calculated |
| 630 | + locally (at each centroid). Defaults to (1000, 10000) |
| 631 | + method : str |
| 632 | + Method to interpolate to new threshold impacts. Currently available are |
| 633 | + "interpolate", "extrapolate", "extrapolate_constant" and "stepfunction". If set to |
| 634 | + "interpolate", threshold impacts outside the range of the Impact object's local |
| 635 | + impacts will be assigned NaN. If set to "extrapolate_constant" or |
| 636 | + "stepfunction", threshold impacts larger than the Impacts object's local |
| 637 | + impacts will be assigned NaN, and threshold impacts smaller than the Impact |
| 638 | + object's local impacts will be assigned the smallest observed local return period. |
| 639 | + If set to "extrapolate", local return periods will be extrapolated (and interpolated). |
| 640 | + Defaults to "interpolate". |
| 641 | + min_impacts : float, optional |
| 642 | + Minimum threshold to filter the impact. Defaults to 0. |
| 643 | + log_frequency : bool, optional |
| 644 | + This parameter is only used if method is set to "interpolate". If set to True, |
| 645 | + (cummulative) frequency values are converted to log scale before inter- and |
| 646 | + extrapolation. Defaults to True. |
| 647 | + log_impact : bool, optional |
| 648 | + This parameter is only used if method is set to "interpolate". If set to True, |
| 649 | + impact values are converted to log scale before inter- and extrapolation. |
| 650 | + Defaults to True. |
| 651 | +
|
| 652 | + Returns |
| 653 | + ------- |
| 654 | + gdf : gpd.GeoDataFrame |
| 655 | + GeoDataFrame containing return periods for given threshold impacts. Each column |
| 656 | + corresponds to a threshold_impact value, each row corresponds to a centroid. Values |
| 657 | + in the gdf correspond to the return period for the given centroid and |
| 658 | + threshold_impact value |
| 659 | + label : str |
| 660 | + GeoDataFrame label, for reporting and plotting |
| 661 | + column_label : function |
| 662 | + Column-label-generating function, for reporting and plotting |
| 663 | + """ |
| 664 | + |
| 665 | + LOGGER.info("Computing return period map for impacts: %s", threshold_impact) |
| 666 | + if self.imp_mat.size == 0: |
| 667 | + raise ValueError( |
| 668 | + "Attribute imp_mat is empty. Recalculate Impact" |
| 669 | + "instance with parameter save_mat=True" |
| 670 | + ) |
| 671 | + |
| 672 | + # check frequency unit |
| 673 | + return_period_unit = u_dt.convert_frequency_unit_to_time_unit( |
| 674 | + self.frequency_unit |
| 675 | + ) |
| 676 | + |
| 677 | + # check method |
| 678 | + if method not in [ |
| 679 | + "interpolate", |
| 680 | + "extrapolate", |
| 681 | + "extrapolate_constant", |
| 682 | + "stepfunction", |
| 683 | + ]: |
| 684 | + raise ValueError(f"Unknown method: {method}") |
| 685 | + |
| 686 | + # calculate local return periods |
| 687 | + return_periods = np.array( |
| 688 | + [ |
| 689 | + u_interp.preprocess_and_interpolate_ev( |
| 690 | + None, |
| 691 | + np.array(threshold_impact), |
| 692 | + self.frequency, |
| 693 | + self.imp_mat.getcol(i_centroid).toarray().flatten(), |
| 694 | + log_frequency=log_frequency, |
| 695 | + log_values=log_impact, |
| 696 | + value_threshold=min_impact, |
| 697 | + method=method, |
| 698 | + y_asymptotic=np.nan, |
| 699 | + ) |
| 700 | + for i_centroid in range(self.imp_mat.shape[1]) |
| 701 | + ] |
| 702 | + ) |
| 703 | + return_periods = safe_divide(1.0, return_periods) |
| 704 | + |
| 705 | + # create the output GeoDataFrame |
| 706 | + gdf = gpd.GeoDataFrame( |
| 707 | + geometry=gpd.points_from_xy(self.coord_exp[:, 1], self.coord_exp[:, 0]), |
| 708 | + crs=self.crs, |
| 709 | + ) |
| 710 | + col_names = [f"{thresh_impact}" for thresh_impact in threshold_impact] |
| 711 | + gdf[col_names] = return_periods |
| 712 | + |
| 713 | + # create label and column_label |
| 714 | + label = f"Return Periods ({return_period_unit})" |
| 715 | + column_label = lambda column_names: [ |
| 716 | + f"Impact: {col} {self.unit}" for col in column_names |
| 717 | + ] |
| 718 | + |
| 719 | + return gdf, label, column_label |
| 720 | + |
613 | 721 | def calc_freq_curve(self, return_per=None): |
614 | 722 | """Compute impact exceedance frequency curve. |
615 | 723 |
|
|
0 commit comments