Skip to content

Commit 461177c

Browse files
Merge branch 'develop'
# Conflicts: # CHANGELOG.md # climada/_version.py # setup.py Resolved using 'develop'
2 parents e412222 + e5746b6 commit 461177c

65 files changed

Lines changed: 5161 additions & 2353 deletions

Some content is hidden

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

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
steps:
2727
-
2828
name: Checkout Repo
29-
uses: actions/checkout@v3
29+
uses: actions/checkout@v4
3030
-
3131
# Store the current date to use it as cache key for the environment
3232
name: Get current date
@@ -64,7 +64,7 @@ jobs:
6464
-
6565
name: Upload Coverage Reports
6666
if: always()
67-
uses: actions/upload-artifact@v3
67+
uses: actions/upload-artifact@v4
6868
with:
6969
name: coverage-report-unittests-py${{ matrix.python-version }}
7070
path: coverage/

AUTHORS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,6 @@
2929
* Raphael Portmann
3030
* Nicolas Colombi
3131
* Leonie Villiger
32+
* Kam Lam Yeung
33+
* Sarah Hülsen
34+
* Timo Schmid

CHANGELOG.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,71 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
Release date: YYYY-MM-DD
6+
7+
Code freeze date: YYYY-MM-DD
8+
9+
### Description
10+
11+
### Dependency Changes
12+
13+
Added:
14+
15+
- `pyproj` >=3.5
16+
- `numexpr` >=2.9
17+
18+
Updated:
19+
20+
- `contextily` >=1.3 → >=1.5
21+
- `dask` >=2023 → >=2024
22+
- `numba` >=0.57 → >=0.59
23+
- `pandas` >=2.1 &rarr; >=2.1,<2.2
24+
- `pint` >=0.22 &rarr; >=0.23
25+
- `scikit-learn` >=1.3 &rarr; >=1.4
26+
- `scipy` >=1.11 &rarr; >=1.12
27+
- `sparse` >=0.14 &rarr; >=0.15
28+
- `xarray` >=2023.8 &rarr; >=2024.1
29+
- `overpy` =0.6 &rarr; =0.7
30+
- `peewee` =3.16.3 &rarr; =3.17.1
31+
32+
Removed:
33+
34+
- `proj` (in favor of `pyproj`)
35+
36+
### Added
37+
38+
- Convenience method `api_client.Client.get_dataset_file`, combining `get_dataset_info` and `download_dataset`, returning a single file objet. [#821](https://github.com/CLIMADA-project/climada_python/pull/821)
39+
- Read and Write methods to and from csv files for the `DiscRates` class. [#818](ttps://github.com/CLIMADA-project/climada_python/pull/818)
40+
- Add `CalcDeltaClimate` to unsequa module to allow uncertainty and sensitivity analysis of impact change calculations [#844](https://github.com/CLIMADA-project/climada_python/pull/844)
41+
- Add function `safe_divide` in util which handles division by zero and NaN values in the numerator or denominator [#844](https://github.com/CLIMADA-project/climada_python/pull/844)
42+
- Add reset_frequency option for the impact.select() function. [#847](https://github.com/CLIMADA-project/climada_python/pull/847)
43+
44+
### Changed
45+
46+
- Update Developer and Installation Guides for easier accessibility by new developers. [808](https://github.com/CLIMADA-project/climada_python/pull/808)
47+
- Add `shapes` argument to `geo_im_from_array` to allow flexible turning on/off of plotting coastline in `plot_intensity`. [#805](https://github.com/CLIMADA-project/climada_python/pull/805)
48+
- Update `CONTRIBUTING.md` to better explain types of contributions to this repository [#797](https://github.com/CLIMADA-project/climada_python/pull/797)
49+
- The default tile layer in Exposures maps is not Stamen Terrain anymore, but [CartoDB Positron](https://github.com/CartoDB/basemap-styles). Affected methods are `climada.engine.Impact.plot_basemap_eai_exposure`,`climada.engine.Impact.plot_basemap_impact_exposure` and `climada.entity.Exposures.plot_basemap`. [#798](https://github.com/CLIMADA-project/climada_python/pull/798)
50+
- Recommend using Mamba instead of Conda for installing CLIMADA [#809](https://github.com/CLIMADA-project/climada_python/pull/809)
51+
- `Hazard.from_xarray_raster` now allows arbitrary values as 'event' coordinates [#837](https://github.com/CLIMADA-project/climada_python/pull/837)
52+
- `climada.test.get_test_file` now compares the version of the requested test dataset with the version of climada itself and selects the most appropriate dataset. In this way a test file can be updated without the need of changing the code of the unittest. [#822](https://github.com/CLIMADA-project/climada_python/pull/822)
53+
- Explicitly require `pyproj` instead of `proj` (the latter is now implicitly required) [#845](https://github.com/CLIMADA-project/climada_python/pull/845)
54+
55+
### Fixed
56+
57+
- `Hazard.from_xarray_raster` now stores strings as default values for `Hazard.event_name` [#795](https://github.com/CLIMADA-project/climada_python/pull/795)
58+
- Fix the dist_approx util function when used with method="geosphere" and log=True and points that are very close. [#792](https://github.com/CLIMADA-project/climada_python/pull/792)
59+
- `climada.util.yearsets.sample_from_poisson`: fix a bug ([#819](https://github.com/CLIMADA-project/climada_python/issues/819)) and inconsistency that occurs when lambda events per year (`lam`) are set to 1. [[#823](https://github.com/CLIMADA-project/climada_python/pull/823)]
60+
- In the TropCyclone class in the Holland model 2008 and 2010 implementation, a doublecounting of translational velocity is removed [#833](https://github.com/CLIMADA-project/climada_python/pull/833)
61+
- `climada.util.test.test_finance` and `climada.test.test_engine` updated to recent input data from worldbank [#841](https://github.com/CLIMADA-project/climada_python/pull/841)
62+
- Set `nodefaults` in Conda environment specs because `defaults` are not compatible with conda-forge [#845](https://github.com/CLIMADA-project/climada_python/pull/845)
63+
- Avoid redundant calls to `np.unique` in `Impact.impact_at_reg` [#848](https://github.com/CLIMADA-project/climada_python/pull/848)
64+
65+
### Deprecated
66+
67+
### Removed
68+
369
## 4.0.1
470

571
Release date: 2023-09-27

CONTRIBUTING.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,26 @@
11
# CLIMADA Contribution Guide
22

3-
Thank you for contributing to CLIMADA!
3+
We welcome any contribution to CLIMADA and want to express our thanks to everybody who contributes.
44

5-
## Overview
5+
## What Warrants a Contribution?
6+
7+
Anything!
8+
For orientation, these are some categories of possible contributions we can think of:
9+
10+
* **Technical problems and bugs:** Did you encounter a problem when using CLIMADA? Raise an [issue](https://github.com/CLIMADA-project/climada_python/issues) in our repository, providing a description or ideally a code replicating the error. Did you already find a solution to the problem? Please raise a pull request to help us resolve the issue!
11+
* **Documentation and Tutorial Updates:** Found a typo in the documentation? Is a tutorial lacking some information you find important? Simply fix a line, or add a paragraph. We are happy to incorporate you additions! Please raise a pull request!
12+
* **New Modules and Utility Functions:** Did you create a function or an entire module you find useful for your work? Maybe you are not the only one! Feel free to simply raise a pull request for functions that improve, e.g., plotting or data handling. As an entire module has to be carefully integrated into the framework, it might help if you talk to us first so we can design the module and plan the next steps. You can do that by raising an issue or starting a [discussion](https://github.com/CLIMADA-project/climada_python/discussions) on GitHub.
13+
14+
A good place to start a personal discussion is our monthly CLIMADA developers call.
15+
Please contact the [lead developers](https://wcr.ethz.ch/research/climada.html) if you want to join.
16+
17+
## Why Should You Contribute?
18+
19+
* You will be listed as author of the CLIMADA repository in the [AUTHORS](AUTHORS.md) file.
20+
* You will improve the quality of the CLIMADA software for you and for everybody else using it.
21+
* You will gain insights into scientific software development.
22+
23+
## Minimal Steps to Contribute
624

725
Before you start, please have a look at our [Developer Guide][devguide].
826

README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,14 @@ This is the Python (3.9+) version of CLIMADA - please see [here](https://github.
2121
## Getting started
2222

2323
CLIMADA runs on Windows, macOS and Linux.
24-
The released versions of the CLIMADA core can be installed directly through Anaconda:
24+
The released versions of CLIMADA are available from [conda-forge](https://anaconda.org/conda-forge/climada).
25+
Use the [Mamba](https://mamba.readthedocs.io/en/latest/) package manager to install it:
2526

2627
```shell
27-
conda install -c conda-forge climada
28+
mamba install -c conda-forge climada
2829
```
2930

30-
It is **highly recommended** to install CLIMADA into a **separate** Anaconda environment.
31+
It is **highly recommended** to install CLIMADA into a **separate** Conda environment.
3132
See the [installation guide](https://climada-python.readthedocs.io/en/latest/guide/install.html) for further information.
3233

3334
Follow the [tutorials](https://climada-python.readthedocs.io/en/stable/tutorial/1_main_climada.html) in a Jupyter Notebook to see what can be done with CLIMADA and how.
@@ -61,7 +62,9 @@ Please use the following logo if you are presenting results obtained with or thr
6162

6263
## Contributing
6364

64-
See the [Contribution Guide](CONTRIBUTING.md).
65+
We welcome any contribution to this repository, be it bugfixes and other code changes and additions, documentation improvements, or tutorial updates.
66+
67+
If you would like to contribute, please refer to our [Contribution Guide](CONTRIBUTING.md).
6568

6669
## Versioning
6770

climada/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '4.0.1'
1+
__version__ = '4.0.2-dev'

climada/engine/impact.py

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -451,12 +451,12 @@ def impact_at_reg(self, agg_regions=None):
451451
at_reg_event = np.hstack(
452452
[
453453
self.imp_mat[:, np.where(agg_regions == reg)[0]].sum(1)
454-
for reg in np.unique(agg_reg_unique)
454+
for reg in agg_reg_unique
455455
]
456456
)
457457

458458
at_reg_event = pd.DataFrame(
459-
at_reg_event, columns=np.unique(agg_reg_unique), index=self.event_id
459+
at_reg_event, columns=agg_reg_unique, index=self.event_id
460460
)
461461

462462
return at_reg_event
@@ -673,7 +673,7 @@ def plot_raster_eai_exposure(self, res=None, raster_res=None, save_tiff=None,
673673

674674
def plot_basemap_eai_exposure(self, mask=None, ignore_zero=False, pop_name=True,
675675
buffer=0.0, extend='neither', zoom=10,
676-
url=ctx.providers.Stamen.Terrain,
676+
url=ctx.providers.CartoDB.Positron,
677677
axis=None, **kwargs):
678678
"""Plot basemap expected impact of each exposure within a period of 1/frequency_unit.
679679
@@ -694,7 +694,7 @@ def plot_basemap_eai_exposure(self, mask=None, ignore_zero=False, pop_name=True,
694694
zoom : int, optional
695695
zoom coefficient used in the satellite image
696696
url : str, optional
697-
image source, e.g. ctx.providers.OpenStreetMap.Mapnik
697+
image source, default: ctx.providers.CartoDB.Positron
698698
axis : matplotlib.axes.Axes, optional
699699
axis to use
700700
kwargs : dict, optional
@@ -764,7 +764,7 @@ def plot_hexbin_impact_exposure(self, event_id=1, mask=None, ignore_zero=False,
764764

765765
def plot_basemap_impact_exposure(self, event_id=1, mask=None, ignore_zero=False,
766766
pop_name=True, buffer=0.0, extend='neither', zoom=10,
767-
url=ctx.providers.Stamen.Terrain,
767+
url=ctx.providers.CartoDB.Positron,
768768
axis=None, **kwargs):
769769
"""Plot basemap impact of an event at each exposure.
770770
Requires attribute imp_mat.
@@ -789,7 +789,7 @@ def plot_basemap_impact_exposure(self, event_id=1, mask=None, ignore_zero=False,
789789
zoom : int, optional
790790
zoom coefficient used in the satellite image
791791
url : str, optional
792-
image source, e.g. ctx.providers.OpenStreetMap.Mapnik
792+
image source, default: ctx.providers.CartoDB.Positron
793793
axis : matplotlib.axes.Axes, optional
794794
axis to use
795795
kwargs : dict, optional
@@ -1475,9 +1475,14 @@ def _cen_return_imp(imp, freq, imp_th, return_periods):
14751475

14761476
return imp_fit
14771477

1478-
def select(self,
1479-
event_ids=None, event_names=None, dates=None,
1480-
coord_exp=None):
1478+
def select(
1479+
self,
1480+
event_ids=None,
1481+
event_names=None,
1482+
dates=None,
1483+
coord_exp=None,
1484+
reset_frequency=False
1485+
):
14811486
"""
14821487
Select a subset of events and/or exposure points from the impact.
14831488
If multiple input variables are not None, it returns all the impacts
@@ -1509,6 +1514,9 @@ def select(self,
15091514
coord_exp : np.array, optional
15101515
Selection of exposures coordinates [lat, lon] (in degrees)
15111516
The default is None.
1517+
reset_frequency : bool, optional
1518+
Change frequency of events proportional to difference between first and last
1519+
year (old and new). Assumes annual frequency values. Default: False.
15121520
15131521
Raises
15141522
------
@@ -1580,6 +1588,19 @@ def select(self,
15801588
LOGGER.info("The total value cannot be re-computed for a "
15811589
"subset of exposures and is set to None.")
15821590

1591+
# reset frequency if date span has changed (optional):
1592+
if reset_frequency:
1593+
if self.frequency_unit not in ['1/year', 'annual', '1/y', '1/a']:
1594+
LOGGER.warning("Resetting the frequency is based on the calendar year of given"
1595+
" dates but the frequency unit here is %s. Consider setting the frequency"
1596+
" manually for the selection or changing the frequency unit to %s.",
1597+
self.frequency_unit, DEF_FREQ_UNIT)
1598+
year_span_old = np.abs(dt.datetime.fromordinal(self.date.max()).year -
1599+
dt.datetime.fromordinal(self.date.min()).year) + 1
1600+
year_span_new = np.abs(dt.datetime.fromordinal(imp.date.max()).year -
1601+
dt.datetime.fromordinal(imp.date.min()).year) + 1
1602+
imp.frequency = imp.frequency * year_span_old / year_span_new
1603+
15831604
# cast frequency vector into 2d array for sparse matrix multiplication
15841605
freq_mat = imp.frequency.reshape(len(imp.frequency), 1)
15851606
# .A1 reduce 1d matrix to 1d array

climada/engine/test/test_cost_benefit.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
from climada.test import get_test_file
3636

3737

38-
HAZ_TEST_MAT = get_test_file('atl_prob_no_name')
38+
HAZ_TEST_MAT = get_test_file('atl_prob_no_name', file_format='matlab')
3939
ENT_TEST_MAT = get_test_file('demo_today', file_format='MAT-file')
4040

4141

climada/engine/test/test_impact.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import h5py
2828
from pyproj import CRS
2929
from rasterio.crs import CRS as rCRS
30+
import datetime as dt
3031

3132
from climada.entity.entity_def import Entity
3233
from climada.hazard.base import Hazard
@@ -67,6 +68,24 @@ def dummy_impact():
6768
haz_type="TC",
6869
)
6970

71+
def dummy_impact_yearly():
72+
"""Return an impact containing events in multiple years"""
73+
imp = dummy_impact()
74+
75+
years = np.arange(2010,2010+len(imp.date))
76+
77+
# Edit the date and frequency
78+
imp.date = np.array([dt.date(year,1,1).toordinal() for year in years])
79+
imp.frequency_unit = "1/year"
80+
imp.frequency = np.ones(len(years))/len(years)
81+
82+
# Calculate the correct expected annual impact
83+
freq_mat = imp.frequency.reshape(len(imp.frequency), 1)
84+
imp.eai_exp = imp.imp_mat.multiply(freq_mat).sum(axis=0).A1
85+
imp.aai_agg = imp.eai_exp.sum()
86+
87+
return imp
88+
7089

7190
class TestImpact(unittest.TestCase):
7291
""""Test initialization and more"""
@@ -868,6 +887,22 @@ def test_select_imp_map_fail(self):
868887
with self.assertRaises(ValueError):
869888
imp.select(event_ids=[0], event_names=[1, 'two'], dates=(0, 2))
870889

890+
def test_select_reset_frequency(self):
891+
"""Test that reset_frequency option works correctly"""
892+
893+
imp = dummy_impact_yearly() # 6 events, 1 per year
894+
895+
# select first 4 events
896+
n_yr = 4
897+
sel_imp = imp.select(dates=(imp.date[0],imp.date[n_yr-1]), reset_frequency=True)
898+
899+
# check frequency-related attributes
900+
np.testing.assert_array_equal(sel_imp.frequency, [1/n_yr]*n_yr)
901+
self.assertEqual(sel_imp.aai_agg,imp.at_event[0:n_yr].sum()/n_yr)
902+
np.testing.assert_array_equal(sel_imp.eai_exp,
903+
imp.imp_mat[0:n_yr,:].todense().sum(axis=0).A1/n_yr)
904+
905+
871906
class TestConvertExp(unittest.TestCase):
872907
def test__build_exp(self):
873908
"""Test that an impact set can be converted to an exposure"""

climada/engine/unsequa/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@
2222
from .calc_base import *
2323
from .calc_impact import *
2424
from .calc_cost_benefit import *
25+
from .calc_delta_climate import *

0 commit comments

Comments
 (0)