Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Combining several interpolation functions using a new util function #918

Merged
merged 67 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
fe3becc
first draft general fit method
ValentinGebhart Jul 5, 2024
eab38ac
updated fit func and new loc_exceedance func
ValentinGebhart Jul 11, 2024
316ca45
added local_rp fct and stepfunction fit
ValentinGebhart Jul 12, 2024
7f9649d
update local_exceedance_imp func
ValentinGebhart Jul 15, 2024
4167295
Merge branch 'develop' into feature/restructure_fitfuncs_exceedance
ValentinGebhart Jul 15, 2024
482a207
change fcts to return gdfs
ValentinGebhart Jul 15, 2024
05b2800
prepare to merge with develop
ValentinGebhart Jul 16, 2024
a3efe90
Merge branch 'develop' into feature/restructure_fitfuncs_exceedance
ValentinGebhart Jul 16, 2024
9ba4ddb
merged develop into branch
ValentinGebhart Jul 16, 2024
74b4b81
update plot local impact exceedance
ValentinGebhart Jul 16, 2024
acf3664
made function calls consistent with new structure
ValentinGebhart Jul 16, 2024
1e0d238
plot NaNs in gray in geo_im_from_array
ValentinGebhart Jul 17, 2024
332b0ab
added method options for exceed funcs
ValentinGebhart Jul 18, 2024
f0bf633
fixed bug when y_scale is log
ValentinGebhart Jul 18, 2024
b09a7c6
added some tests for fit function
ValentinGebhart Jul 18, 2024
0c6377c
group values with same inten/impact
ValentinGebhart Jul 19, 2024
0fca30b
updated tests
ValentinGebhart Jul 19, 2024
2790fdd
added util function to group frequencies
ValentinGebhart Jul 22, 2024
5c29173
changed default settings, added old functions
ValentinGebhart Jul 23, 2024
23f7f5d
updated tests
ValentinGebhart Jul 23, 2024
199f8e2
added deprecation warnings and changed sorting
ValentinGebhart Jul 24, 2024
adfc6e0
new asymptotic and small-input behaviour of funcs
ValentinGebhart Jul 24, 2024
0e6ed2c
added docstrings
ValentinGebhart Jul 24, 2024
97d1c68
more thorough tests of exceedance and rp funcs
ValentinGebhart Jul 29, 2024
6ede419
Merge branch 'develop' into feature/restructure_fitfuncs_exceedance
ValentinGebhart Jul 29, 2024
db823e5
fixed pylint issues
ValentinGebhart Jul 29, 2024
b7601a5
moved plot func changes to separate PR
ValentinGebhart Jul 30, 2024
93b9b51
split tests into unit and integration tests
ValentinGebhart Jul 30, 2024
9c1af91
refactor util function in smaller functions
ValentinGebhart Jul 31, 2024
a1b1b97
Merge branch 'develop' into feature/restructure_fitfuncs_exceedance
ValentinGebhart Aug 22, 2024
b2c85ad
adapt functions to switch to boolean input parameters
ValentinGebhart Aug 22, 2024
b62af52
fixed docstrings and delete old files
ValentinGebhart Aug 23, 2024
de81342
deleted obsolete subfunctions
ValentinGebhart Aug 26, 2024
19c482a
implemented changes suggested by Sarah H
ValentinGebhart Aug 29, 2024
5d11f75
Merge branch 'develop' into feature/restructure_fitfuncs_exceedance
ValentinGebhart Sep 28, 2024
0cfe35c
update interpolate util module to add constant extrapolation option
ValentinGebhart Sep 28, 2024
55c033f
added method "extrapolate_constant" and changed behaviour of "interpo…
ValentinGebhart Sep 28, 2024
d059b3e
Update CHANGELOG.md
ValentinGebhart Sep 28, 2024
d9b58b3
adapt hazard tutorial
ValentinGebhart Sep 28, 2024
eb49fe3
Merge branch 'feature/restructure_fitfuncs_exceedance' of github.com:…
ValentinGebhart Sep 28, 2024
d658bbc
rerun hazard tutorial
ValentinGebhart Sep 28, 2024
e44b9f0
refactorize methods by introducing new interpolate wrapper function a…
ValentinGebhart Oct 1, 2024
9f343cb
restructured unit and integration tests
ValentinGebhart Oct 1, 2024
043a15c
added tests for two new util functions
ValentinGebhart Oct 1, 2024
e608755
update doc
ValentinGebhart Oct 1, 2024
9edac4d
immproved inefficiency in fct group_frequency
ValentinGebhart Oct 4, 2024
efb9921
Merge branch 'develop' into feature/restructure_fitfuncs_exceedance
emanuel-schmid Oct 4, 2024
822c7f1
format
emanuel-schmid Oct 20, 2024
1b78bdf
import Impact from climada.engine.impact
emanuel-schmid Oct 20, 2024
87cb6fd
avoid circular imports
emanuel-schmid Oct 20, 2024
b9be992
Merge branch 'develop' into develop-black
emanuel-schmid Oct 20, 2024
5143b99
pre-commit run --all-files
emanuel-schmid Oct 20, 2024
bc60010
setup: DEPS_TEST update
emanuel-schmid Oct 20, 2024
3c5fc8f
avoid circular imports
emanuel-schmid Oct 20, 2024
aa0615f
Merge branch 'develop-white' of https://github.com/CLIMADA-project/cl…
emanuel-schmid Oct 20, 2024
dcbe2c5
format exceptions
emanuel-schmid Oct 21, 2024
13dfc8e
added tutorial about new functionalities
ValentinGebhart Oct 21, 2024
d9d600d
Merge branch 'develop-white' into feature/restructure_fitfuncs_exceed…
ValentinGebhart Oct 23, 2024
81695f4
blacked my feature branch
ValentinGebhart Oct 23, 2024
e0ccfa0
Merge branch 'develop-black' into feature/restructure_fitfuncs_exceed…
ValentinGebhart Oct 23, 2024
f76723c
Merge branch 'develop' into feature/restructure_fitfuncs_exceedance
ValentinGebhart Oct 23, 2024
928f24e
removed tutorial for future PR
ValentinGebhart Oct 24, 2024
685b6c8
Apply suggestions from code review
ValentinGebhart Nov 4, 2024
bfef378
changed deprecation warning to decorators
ValentinGebhart Nov 4, 2024
386730b
changelog: amend deprecated section
emanuel-schmid Nov 4, 2024
4b88cb0
update changelog with three more deprecated entries
ValentinGebhart Nov 4, 2024
4d29cbf
moved time frequency conversion to util dates_times
ValentinGebhart Nov 4, 2024
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Code freeze date: YYYY-MM-DD

### Added

- `Hazard.local_exceedance_intensity`, `Hazard.local_return_period` and `Impact.local_exceedance_impact`, that all use the `climada.util.interpolation` module [#918](https://github.com/CLIMADA-project/climada_python/pull/918)
- `climada.util.interpolation` module for inter- and extrapolation util functions used in local exceedance intensity and return period functions [#930](https://github.com/CLIMADA-project/climada_python/pull/930)
- `climada.exposures.exposures.Exposures.geometry` property
- `climada.exposures.exposures.Exposures.latitude` property
Expand All @@ -28,6 +29,7 @@ Code freeze date: YYYY-MM-DD
- Improved scaling factors implemented in `climada.hazard.trop_cyclone.apply_climate_scenario_knu` to model the impact of climate changes to tropical cyclones [#734](https://github.com/CLIMADA-project/climada_python/pull/734)
- In `climada.util.plot.geo_im_from_array`, NaNs are plotted in gray while cells with no centroid are not plotted [#929](https://github.com/CLIMADA-project/climada_python/pull/929)
- Renamed `climada.util.plot.subplots_from_gdf` to `climada.util.plot.plot_from_gdf` [#929](https://github.com/CLIMADA-project/climada_python/pull/929)
- `Hazard.local_exceedance_inten`, `Hazard.local_return_period`, and `Impact.local_exceedance_imp` call the corresponding new functions and a deprecation warning is added [#918](https://github.com/CLIMADA-project/climada_python/pull/918). Some inconsistencies in the previous versions are removed and the default method is changed. To reconstruct results from the previous versions, use CLIMADA v5.0.0 or less.
- Exposures complete overhaul. Notably
- the _geometry_ column of the inherent `GeoDataFrame` is set up at initialization
- latitude and longitude column are no longer present there (the according arrays can be retrieved as properties of the Exposures object: `exp.latitude` instead of `exp.gdf.latitude.values`).
Expand All @@ -44,6 +46,10 @@ Code freeze date: YYYY-MM-DD
- `climada.entity.exposures.Exposures.meta` attribute
- `climada.entity.exposures.Exposures.set_lat_lon` method
- `climada.entity.exposures.Exposures.set_geometry_points` method
- `climada.hazard.Hazard.local_exceedance_inten` method
- `climada.hazard.Hazard.plot_rp_intensity` method
- `climada.engine.impact.Impact.local_exceedance_imp` method
- `climada.engine.impact.Impact.plot_rp_imp` method

### Removed

Expand Down
217 changes: 119 additions & 98 deletions climada/engine/impact.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import csv
import datetime as dt
import logging
import warnings

Check warning on line 28 in climada/engine/impact.py

View check run for this annotation

Jenkins - WCR / Pylint

unused-import

NORMAL: Unused import warnings
Raw output
Used when an imported module or variable is not used.
from collections.abc import Collection
from dataclasses import dataclass, field
from itertools import zip_longest
Expand All @@ -33,21 +33,24 @@
from typing import Any, Iterable, Union

import contextily as ctx
import geopandas as gpd
import h5py
import matplotlib.animation as animation

Check warning on line 38 in climada/engine/impact.py

View check run for this annotation

Jenkins - WCR / Pylint

consider-using-from-import

LOW: Use 'from matplotlib import animation' instead
Raw output
no description found
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import xlsxwriter
from deprecation import deprecated
from pyproj import CRS as pyprojCRS
from rasterio.crs import CRS as rasterioCRS # pylint: disable=no-name-in-module
from scipy import sparse
from tqdm import tqdm

import climada.util.coordinates as u_coord
import climada.util.dates_times as u_dt
import climada.util.interpolation as u_interp
import climada.util.plot as u_plot
from climada import CONFIG

Check warning on line 53 in climada/engine/impact.py

View check run for this annotation

Jenkins - WCR / Pylint

unused-import

NORMAL: Unused CONFIG imported from climada
Raw output
Used when an imported module or variable is not used.
from climada.entity import Exposures
from climada.util.constants import CMAP_IMPACT, DEF_CRS, DEF_FREQ_UNIT
from climada.util.select import get_attributes_with_matching_dimension
Expand Down Expand Up @@ -486,20 +489,54 @@
)
return self.impact_per_year(all_years=all_years, year_range=year_range)

# TODO: rewrite and deprecate method
def local_exceedance_imp(self, return_periods=(25, 50, 100, 250)):
"""Compute exceedance impact map for given return periods.
Requires attribute imp_mat.
def local_exceedance_impact(

Check warning on line 492 in climada/engine/impact.py

View check run for this annotation

Jenkins - WCR / Pylint

too-many-positional-arguments

LOW: Too many positional arguments (6/5)
Raw output
no description found
self,
return_periods=(25, 50, 100, 250),
method="interpolate",
min_impact=0,
log_frequency=True,
log_impact=True,
):
"""Compute local exceedance impact for given return periods. The default method
is fitting the ordered impacts per centroid to the corresponding cummulated
frequency with by linear interpolation on log-log scale.

Parameters
----------
return_periods : Any, optional
return periods to consider
Dafault is (25, 50, 100, 250)
return_periods : array_like
User-specified return periods for which the exceedance intensity should be calculated
locally (at each centroid). Defaults to (25, 50, 100, 250).
method : str
Method to interpolate to new return periods. Currently available are "interpolate",
"extrapolate", "extrapolate_constant" and "stepfunction". If set to "interpolate",
return periods outside the range of the Impact object's observed local return periods
will be assigned NaN. If set to "extrapolate_constant" or "stepfunction",
return periods larger than the Impact object's observed local return periods will be
assigned the largest local impact, and return periods smaller than the Impact object's
observed local return periods will be assigned 0. If set to "extrapolate", local
exceedance impacts will be extrapolated (and interpolated). Defauls to "interpolate".
min_impact : float, optional
Minimum threshold to filter the impact. Defaults to 0.
log_frequency : bool, optional
This parameter is only used if method is set to "extrapolate" or "interpolate". If set
to True, (cummulative) frequency values are converted to log scale before inter- and
extrapolation. Defaults to True.
log_impact : bool, optional
This parameter is only used if method is set to "extrapolate" or "interpolate". If set
to True, impact values are converted to log scale before inter- and extrapolation.
Defaults to True.

Returns
-------
np.array
gdf : gpd.GeoDataFrame
GeoDataFrame containing exeedance impacts for given return periods. Each column
corresponds to a return period, each row corresponds to a centroid. Values
in the gdf correspond to the exceedance impact for the given centroid and
return period
label : str
GeoDataFrame label, for reporting and plotting
column_label : function
Column-label-generating function, for reporting and plotting
"""
LOGGER.info(
"Computing exceedance impact map for return periods: %s", return_periods
Expand All @@ -509,29 +546,69 @@
"Attribute imp_mat is empty. Recalculate Impact"
"instance with parameter save_mat=True"
)
num_cen = self.imp_mat.shape[1]
imp_stats = np.zeros((len(return_periods), num_cen))
cen_step = CONFIG.max_matrix_size.int() // self.imp_mat.shape[0]
if not cen_step:
raise ValueError(
"Increase max_matrix_size configuration parameter to > "
f"{self.imp_mat.shape[0]}"
)
# separte in chunks
chk = -1
for chk in range(int(num_cen / cen_step)):
self._loc_return_imp(
np.array(return_periods),
self.imp_mat[:, chk * cen_step : (chk + 1) * cen_step].toarray(),
imp_stats[:, chk * cen_step : (chk + 1) * cen_step],
)
self._loc_return_imp(
np.array(return_periods),
self.imp_mat[:, (chk + 1) * cen_step :].toarray(),
imp_stats[:, (chk + 1) * cen_step :],

# check frequency unit
return_period_unit = u_dt.convert_frequency_unit_to_time_unit(
self.frequency_unit
)

return imp_stats
# check method
if method not in [
"interpolate",
"extrapolate",
"extrapolate_constant",
"stepfunction",
]:
raise ValueError(f"Unknown method: {method}")

Check warning on line 562 in climada/engine/impact.py

View check run for this annotation

Jenkins - WCR / Code Coverage

Not covered line

Line 562 is not covered by tests

# calculate local exceedance impact
test_frequency = 1 / np.array(return_periods)
exceedance_impact = np.array(
[
u_interp.preprocess_and_interpolate_ev(
test_frequency,
None,
self.frequency,
self.imp_mat.getcol(i_centroid).toarray().flatten(),
log_frequency=log_frequency,
log_values=log_impact,
value_threshold=min_impact,
method=method,
y_asymptotic=0.0,
)
for i_centroid in range(self.imp_mat.shape[1])
]
)

# create the output GeoDataFrame
gdf = gpd.GeoDataFrame(
geometry=gpd.points_from_xy(self.coord_exp[:, 1], self.coord_exp[:, 0]),
crs=self.crs,
)
col_names = [f"{ret_per}" for ret_per in return_periods]
gdf[col_names] = exceedance_impact
# create label and column_label
label = f"Impact ({self.unit})"
column_label = lambda column_names: [

Check warning on line 592 in climada/engine/impact.py

View check run for this annotation

Jenkins - WCR / Pylint

unnecessary-lambda-assignment

LOW: Lambda expression assigned to a variable. Define a function using the "def" keyword instead.
Raw output
no description found
f"Return Period: {col} {return_period_unit}" for col in column_names
]

return gdf, label, column_label

@deprecated(
details="The use of Impact.local_exceedance_imp is deprecated. Use "
"Impact.local_exceedance_impact instead. Some errors in the previous calculation "
"in Impact.local_exceedance_imp have been corrected. To reproduce data with the "
"previous calculation, use CLIMADA v5.0.0 or less."
)
def local_exceedance_imp(self, return_periods=(25, 50, 100, 250)):
"""This function is deprecated, use Impact.local_exceedance_impact instead."""

return (

Check warning on line 607 in climada/engine/impact.py

View check run for this annotation

Jenkins - WCR / Code Coverage

Not covered line

Line 607 is not covered by tests
self.local_exceedance_impact(return_periods)[0]
.values[:, 1:]
.T.astype(float)
)

def calc_freq_curve(self, return_per=None):
"""Compute impact exceedance frequency curve.
Expand Down Expand Up @@ -924,6 +1001,10 @@

return axis

@deprecated(
details="The use of Impact.plot_rp_imp is deprecated."
"Use Impact.local_exceedance_impact and util.plot.plot_from_gdf instead."
)
def plot_rp_imp(
self,
return_periods=(25, 50, 100, 250),
Expand All @@ -932,7 +1013,11 @@
axis=None,
**kwargs,
):
"""Compute and plot exceedance impact maps for different return periods.
"""
This function is deprecated, use Impact.local_exceedance_impact and
util.plot.plot_from_gdf instead.

Compute and plot exceedance impact maps for different return periods.
Calls local_exceedance_imp.

Parameters
Expand All @@ -953,7 +1038,10 @@
imp_stats : np.array
return_periods.size x num_centroids
"""
imp_stats = self.local_exceedance_imp(np.array(return_periods))
imp_stats = (
self.local_exceedance_impact(np.array(return_periods))[0].values[:, 1:].T
)
imp_stats = imp_stats.astype(float)

Check warning on line 1044 in climada/engine/impact.py

View check run for this annotation

Jenkins - WCR / Code Coverage

Not covered lines

Lines 1041-1044 are not covered by tests
if imp_stats.size == 0:
raise ValueError(
"Error: Attribute imp_mat is empty. Recalculate Impact"
Expand Down Expand Up @@ -1593,36 +1681,6 @@

return imp_list

# TODO: rewrite and deprecate method
def _loc_return_imp(self, return_periods, imp, exc_imp):
ValentinGebhart marked this conversation as resolved.
Show resolved Hide resolved
"""Compute local exceedence impact for given return period.

Parameters
----------
return_periods : np.array
return periods to consider
cen_pos :int
centroid position

Returns
-------
np.array
"""
# sorted impacts
sort_pos = np.argsort(imp, axis=0)[::-1, :]
columns = np.ones(imp.shape, int)
# pylint: disable=unsubscriptable-object # pylint/issues/3139
columns *= np.arange(columns.shape[1])
imp_sort = imp[sort_pos, columns]
# cummulative frequency at sorted intensity
freq_sort = self.frequency[sort_pos]
np.cumsum(freq_sort, axis=0, out=freq_sort)

for cen_idx in range(imp.shape[1]):
exc_imp[:, cen_idx] = self._cen_return_imp(
imp_sort[:, cen_idx], freq_sort[:, cen_idx], 0, return_periods
)

def _build_exp(self):
return Exposures(
data={
Expand Down Expand Up @@ -1657,44 +1715,7 @@
meta=None,
)

@staticmethod
def _cen_return_imp(imp, freq, imp_th, return_periods):
"""From ordered impact and cummulative frequency at centroid, get
exceedance impact at input return periods.

Parameters
----------
imp : np.array
sorted impact at centroid
freq : np.array
cummulative frequency at centroid
imp_th : float
impact threshold
return_periods : np.array
return periods

Returns
-------
np.array
"""
imp_th = np.asarray(imp > imp_th).squeeze()
imp_cen = imp[imp_th]
freq_cen = freq[imp_th]
if not imp_cen.size:
return np.zeros((return_periods.size,))
try:
with warnings.catch_warnings():
warnings.simplefilter("ignore")
pol_coef = np.polyfit(np.log(freq_cen), imp_cen, deg=1)
except ValueError:
pol_coef = np.polyfit(np.log(freq_cen), imp_cen, deg=0)
imp_fit = np.polyval(pol_coef, np.log(1 / return_periods))
wrong_inten = (return_periods > np.max(1 / freq_cen)) & np.isnan(imp_fit)
imp_fit[wrong_inten] = 0.0

return imp_fit

def select(

Check warning on line 1718 in climada/engine/impact.py

View check run for this annotation

Jenkins - WCR / Pylint

too-complex

LOW: 'select' is too complex. The McCabe rating is 12
Raw output
no description found

Check warning on line 1718 in climada/engine/impact.py

View check run for this annotation

Jenkins - WCR / Pylint

too-many-positional-arguments

LOW: Too many positional arguments (6/5)
Raw output
no description found

Check warning on line 1718 in climada/engine/impact.py

View check run for this annotation

Jenkins - WCR / Pylint

too-many-locals

LOW: Too many local variables (16/15)
Raw output
Used when a function or method has too many local variables.

Check warning on line 1718 in climada/engine/impact.py

View check run for this annotation

Jenkins - WCR / Pylint

too-many-branches

LOW: Too many branches (13/12)
Raw output
Used when a function or method has too many branches, making it hard tofollow.
self,
event_ids=None,
event_names=None,
Expand Down
Loading