Skip to content

Commit 37c65d9

Browse files
committed
Merge branch 'develop' into calibrate-impact-functions
2 parents 096a8d4 + a60241a commit 37c65d9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1558
-707
lines changed

.jenkins_install_env.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ mamba remove --name climada_env --all
44
mamba env create -f requirements/env_climada.yml --name climada_env
55

66
source activate climada_env
7+
python -m pip install -e "./[test]"
78
make install_test
89
conda deactivate

.pylintrc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ confidence=
5050
# --enable=similarities". If you want to run only the classes checker, but have
5151
# no Warning level messages displayed, use"--disable=all --enable=classes
5252
# --disable=W"
53-
disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,W0201
53+
disable=raw-checker-failed,bad-inline-option,locally-disabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,W0201
5454

5555
# Enable the message, report, category or checker with the given id(s). You can
5656
# either give multiple identifier separated by comma (,) or put this option
@@ -388,4 +388,4 @@ min-public-methods=2
388388

389389
# Exceptions that will emit a warning when being caught. Defaults to
390390
# "Exception"
391-
overgeneral-exceptions=Exception
391+
overgeneral-exceptions=builtins.Exception

.readthedocs.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,12 @@ build:
88
conda:
99
environment: requirements/env_docs.yml
1010

11+
python:
12+
install:
13+
- method: pip
14+
path: .
15+
extra_requirements:
16+
- doc
17+
1118
formats:
1219
- pdf

AUTHORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@
2828
* Lukas Riedel
2929
* Raphael Portmann
3030
* Nicolas Colombi
31+
* Leonie Villiger

CHANGELOG.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,17 @@ Added:
1313
Changed:
1414

1515
Removed:
16+
- `nbsphinx` [#712](https://github.com/CLIMADA-project/climada_python/pull/712)
17+
- `pandoc` [#712](https://github.com/CLIMADA-project/climada_python/pull/712)
1618

1719
### Added
1820

1921
- `Impact.impact_at_reg` method for aggregating impacts per country or custom region [#642](https://github.com/CLIMADA-project/climada_python/pull/642)
2022
- `Impact.match_centroids` convenience method for matching (hazard) centroids to impact objects [#602](https://github.com/CLIMADA-project/climada_python/pull/602)
2123
- `climada.util.coordinates.match_centroids` method for matching (hazard) centroids to GeoDataFrames [#602](https://github.com/CLIMADA-project/climada_python/pull/602)
24+
- 'Extra' requirements `doc`, `test`, and `dev` for Python package [#712](https://github.com/CLIMADA-project/climada_python/pull/712)
25+
- Added method `Exposures.centroids_total_value` to replace the functionality of `Exposures.affected_total_value`. This method is temporary and deprecated. [#702](https://github.com/CLIMADA-project/climada_python/pull/702)
26+
2227

2328
### Changed
2429

@@ -29,15 +34,32 @@ Removed:
2934
- Modified the method to disaggregate lines in the `lines_polys_handler` utility module in order to better conserve the total length of all lines on average [#679](https://github.com/CLIMADA-project/climada_python/pull/679).
3035
- Added test for non-default impact function id in the `lines_polys_handler` [#676](https://github.com/CLIMADA-project/climada_python/pull/676)
3136
- The sigmoid and step impact functions now require the user to define the hazard type. [#675](https://github.com/CLIMADA-project/climada_python/pull/675)
37+
- Improved error messages produced by `ImpactCalc.impact()` in case hazard type is not found in exposures/impf_set [#691](https://github.com/CLIMADA-project/climada_python/pull/691)
38+
- Tests with long runtime were moved to integration tests in `climada/test` [#709](https://github.com/CLIMADA-project/climada_python/pull/709)
39+
- Use `myst-nb` for parsing Jupyter Notebooks for the documentation instead of `nbsphinx` [#712](https://github.com/CLIMADA-project/climada_python/pull/712)
40+
- Installation guide now recommends installing CLIMADA directly via `conda install` [#714](https://github.com/CLIMADA-project/climada_python/pull/714)
41+
- `Exposures.affected_total_value` now takes a hazard intensity threshold as argument. Affected values are only those for which at least one event exceeds the threshold. (previously, all exposures points with an assigned centroid were considered affected). By default the centroids are reassigned. [#702](https://github.com/CLIMADA-project/climada_python/pull/702) [#730](https://github.com/CLIMADA-project/climada_python/pull/730)
42+
- Add option to pass region ID to `LitPop.from_shape` [#720](https://github.com/CLIMADA-project/climada_python/pull/720)
43+
- Slightly improved performance on `LitPop`-internal computations [#720](https://github.com/CLIMADA-project/climada_python/pull/720)
44+
- Users can opt-out of the climada specific logging definitions and freely configure logging to their will, by setting the config value `logging.managed` to `false`. [#724](https://github.com/CLIMADA-project/climada_python/pull/724)
45+
- Add option to read additional variables from IBTrACS when using `TCTracks.from_ibtracs_netcdf` [#728](https://github.com/CLIMADA-project/climada_python/pull/728)
3246

3347
### Fixed
3448

3549
- `util.lines_polys_handler` solve polygon disaggregation issue in metre-based projection [#666](https://github.com/CLIMADA-project/climada_python/pull/666)
50+
- Problem with `pyproj.CRS` as `Impact` attribute, [#706](https://github.com/CLIMADA-project/climada_python/issues/706). Now CRS is always stored as `str` in WKT format.
3651

3752
### Deprecated
3853

54+
- `Centroids.from_geodataframe` and `Centroids.from_pix_bounds` [#721](https://github.com/CLIMADA-project/climada_python/pull/721)
55+
- `Impact.tot_value`: Use `Exposures.affected_total_value` to compute the total value affected by a hazard intensity above a custom threshold [#702](https://github.com/CLIMADA-project/climada_python/pull/702)
56+
3957
### Removed
4058

59+
- `Centroids.set_raster_from_pix_bounds` [#721](https://github.com/CLIMADA-project/climada_python/pull/721)
60+
61+
- `requirements/env_developer.yml` environment specs. Use 'extra' requirements when installing the Python package instead [#712](https://github.com/CLIMADA-project/climada_python/pull/712)
62+
4163
## v3.3.2
4264

4365
Release date: 2023-03-02

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@ This is the Python (3.8+) version of CLIMADA - please see https://github.com/dav
1919

2020
## Getting started
2121

22-
CLIMADA runs on Windows, macOS and Linux. It can be installed from sources or - in case of climada_python - directly with pip. See the [installation guide](https://climada-python.readthedocs.io/en/latest/guide/install.html) for instructions.
22+
CLIMADA runs on Windows, macOS and Linux.
23+
The released versions of the CLIMADA core can be installed directly through Anaconda:
24+
```shell
25+
conda install -c conda-forge climada
26+
```
27+
It is **highly recommended** to install CLIMADA into a **separate** Anaconda environment.
28+
See the [installation guide](https://climada-python.readthedocs.io/en/latest/guide/install.html) for further information.
2329

2430
Follow the [tutorial](https://climada-python.readthedocs.io/en/latest/tutorial/1_main_climada.html) `climada_python-x.y.z/doc/tutorial/1_main_climada.ipynb` in a Jupyter Notebook to see what can be done with CLIMADA and how.
2531

climada/conf/climada.conf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@
5757
}
5858
},
5959
"log_level": "WARNING",
60+
"logging": {
61+
"managed": true
62+
},
6063
"max_matrix_size": 1000000000,
6164
"data_api": {
6265
"url": "https://climada.ethz.ch/data-api/v2/",

climada/engine/calibration_opt.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
from climada.engine import ImpactCalc
3333
from climada.entity import ImpactFuncSet, ImpfTropCyclone, impact_funcs
34-
from climada.engine.impact_data import emdat_impact_yearlysum, emdat_impact_event
34+
from climada.engine.impact_data import emdat_impact_yearlysum #, emdat_impact_event
3535

3636
LOGGER = logging.getLogger(__name__)
3737

@@ -261,7 +261,7 @@ def init_impact_data(hazard_type,
261261
reference_year=reference_year)
262262
else:
263263
raise ValueError('init_impact_data not yet implemented for yearly_impact = False.')
264-
em_data = emdat_impact_event(source_file)
264+
#em_data = emdat_impact_event(source_file)
265265
else:
266266
raise ValueError('init_impact_data not yet implemented for other impact_data_sources '
267267
'than emdat.')

climada/engine/impact.py

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
import xlsxwriter
4242
from tqdm import tqdm
4343
import h5py
44+
from pyproj import CRS as pyprojCRS
45+
from rasterio.crs import CRS as rasterioCRS # pylint: disable=no-name-in-module
4446

4547
from climada.entity import Exposures, Tag
4648
from climada.hazard import Tag as TagHaz
@@ -72,6 +74,8 @@ class Impact():
7274
ordinal 1 (ordinal format of datetime library)
7375
coord_exp : np.array
7476
exposures coordinates [lat, lon] (in degrees)
77+
crs : str
78+
WKT string of the impact's crs
7579
eai_exp : np.array
7680
expected impact for each exposure within a period of 1/frequency_unit
7781
at_event : np.array
@@ -80,8 +84,6 @@ class Impact():
8084
frequency of event
8185
frequency_unit : str
8286
frequency unit used (given by hazard), default is '1/year'
83-
tot_value : float
84-
total exposure value affected
8587
aai_agg : float
8688
average impact within a period of 1/frequency_unit (aggregated)
8789
unit : str
@@ -126,7 +128,8 @@ def __init__(self,
126128
coord_exp : np.array, optional
127129
exposures coordinates [lat, lon] (in degrees)
128130
crs : Any, optional
129-
coordinate reference system
131+
Coordinate reference system. CRS instances from ``pyproj`` and ``rasterio``
132+
will be transformed into WKT. Other types are not handled explicitly.
130133
eai_exp : np.array, optional
131134
expected impact for each exposure within a period of 1/frequency_unit
132135
at_event : np.array, optional
@@ -149,12 +152,12 @@ def __init__(self,
149152
self.event_name = [] if event_name is None else event_name
150153
self.date = np.array([], int) if date is None else date
151154
self.coord_exp = np.array([], float) if coord_exp is None else coord_exp
152-
self.crs = crs
155+
self.crs = crs.to_wkt() if isinstance(crs, (pyprojCRS, rasterioCRS)) else crs
153156
self.eai_exp = np.array([], float) if eai_exp is None else eai_exp
154157
self.at_event = np.array([], float) if at_event is None else at_event
155158
self.frequency = np.array([],float) if frequency is None else frequency
156159
self.frequency_unit = frequency_unit
157-
self.tot_value = tot_value
160+
self._tot_value = tot_value
158161
self.aai_agg = aai_agg
159162
self.unit = unit
160163

@@ -246,7 +249,7 @@ def from_eih(cls, exposures, impfset, hazard,
246249
axis=1),
247250
crs = exposures.crs,
248251
unit = exposures.value_unit,
249-
tot_value = exposures.affected_total_value(hazard),
252+
tot_value = exposures.centroids_total_value(hazard),
250253
eai_exp = eai_exp,
251254
at_event = at_event,
252255
aai_agg = aai_agg,
@@ -257,6 +260,29 @@ def from_eih(cls, exposures, impfset, hazard,
257260
}
258261
)
259262

263+
@property
264+
def tot_value(self):
265+
"""Return the total exposure value close to a hazard
266+
267+
.. deprecated:: 3.3
268+
Use :py:meth:`climada.entity.exposures.base.Exposures.affected_total_value`
269+
instead.
270+
"""
271+
LOGGER.warning("The Impact.tot_value attribute is deprecated."
272+
"Use Exposures.affected_total_value to calculate the affected "
273+
"total exposure value based on a specific hazard intensity "
274+
"threshold")
275+
return self._tot_value
276+
277+
@tot_value.setter
278+
def tot_value(self, value):
279+
"""Set the total exposure value close to a hazard"""
280+
LOGGER.warning("The Impact.tot_value attribute is deprecated."
281+
"Use Exposures.affected_total_value to calculate the affected "
282+
"total exposure value based on a specific hazard intensity "
283+
"threshold")
284+
self._tot_value = value
285+
260286
def transfer_risk(self, attachment, cover):
261287
"""Compute the risk transfer for the full portfolio. This is the risk
262288
of the full portfolio summed over all events. For each
@@ -860,7 +886,7 @@ def write_csv(self, file_name):
860886
[self.tag['haz'].description]],
861887
[[self.tag['exp'].file_name], [self.tag['exp'].description]],
862888
[[self.tag['impf_set'].file_name], [self.tag['impf_set'].description]],
863-
[self.unit], [self.tot_value], [self.aai_agg],
889+
[self.unit], [self._tot_value], [self.aai_agg],
864890
self.event_id, self.event_name, self.date,
865891
self.frequency, [self.frequency_unit], self.at_event,
866892
self.eai_exp, self.coord_exp[:, 0], self.coord_exp[:, 1],
@@ -901,7 +927,7 @@ def write_col(i_col, imp_ws, xls_data):
901927
data = [str(self.tag['impf_set'].file_name), str(self.tag['impf_set'].description)]
902928
write_col(2, imp_ws, data)
903929
write_col(3, imp_ws, [self.unit])
904-
write_col(4, imp_ws, [self.tot_value])
930+
write_col(4, imp_ws, [self._tot_value])
905931
write_col(5, imp_ws, [self.aai_agg])
906932
write_col(6, imp_ws, self.event_id)
907933
write_col(7, imp_ws, self.event_name)
@@ -1030,8 +1056,9 @@ def write_csr(group, name, value):
10301056
with h5py.File(file_path, "w") as file:
10311057

10321058
# Now write all attributes
1059+
# NOTE: Remove leading underscore to write '_tot_value' as regular attribute
10331060
for name, value in self.__dict__.items():
1034-
write(file, name, value)
1061+
write(file, name.lstrip("_"), value)
10351062

10361063
def write_sparse_csr(self, file_name):
10371064
"""Write imp_mat matrix in numpy's npz format."""

climada/engine/impact_calc.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,22 @@ def impact(self, save_mat=True, assign_centroids=True,
112112
apply_deductible_to_mat : apply deductible to impact matrix
113113
apply_cover_to_mat : apply cover to impact matrix
114114
"""
115+
# check for compability of exposures and hazard type
116+
if all(name not in self.exposures.gdf.columns for
117+
name in ['if_', f'if_{self.hazard.haz_type}',
118+
'impf_', f'impf_{self.hazard.haz_type}']):
119+
raise AttributeError(
120+
"Impact calculation not possible. No impact functions found "
121+
f"for hazard type {self.hazard.haz_type} in exposures."
122+
)
123+
124+
# check for compability of impact function and hazard type
125+
if not self.impfset.get_func(haz_type=self.hazard.haz_type):
126+
raise AttributeError(
127+
"Impact calculation not possible. No impact functions found "
128+
f"for hazard type {self.hazard.haz_type} in impf_set."
129+
)
130+
115131
impf_col = self.exposures.get_impf_column(self.hazard.haz_type)
116132
exp_gdf = self.minimal_exp_gdf(impf_col, assign_centroids, ignore_cover, ignore_deductible)
117133
if exp_gdf.size == 0:

0 commit comments

Comments
 (0)