cavapy 0.1.3__py3-none-any.whl → 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cavapy might be problematic. Click here for more details.
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: cavapy
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: CAVA Python package. Retrive and analyze climate data.
|
|
5
|
-
Home-page: https://github.com/Risk-Team/cavapy
|
|
6
5
|
License: MIT
|
|
7
6
|
Author: Riccardo Soldan
|
|
8
7
|
Author-email: riccardosoldan@hotmail.it
|
|
@@ -23,7 +22,27 @@ Requires-Dist: xclim (>=0.53.2,<0.54.0)
|
|
|
23
22
|
Project-URL: Repository, https://github.com/Risk-Team/cavapy
|
|
24
23
|
Description-Content-Type: text/markdown
|
|
25
24
|
|
|
26
|
-
|
|
25
|
+
<h1 align="center">
|
|
26
|
+
<br>
|
|
27
|
+
<h2 align="center">cavapy: CORDEX-CORE Climate Data Access Simplified</h2>
|
|
28
|
+
<br>
|
|
29
|
+
<div align="center">
|
|
30
|
+
<img src="https://img.shields.io/pepy/dt/cavapy?style=plastic&label=Total%20Downloads" alt="Total downloads">
|
|
31
|
+
<img src="https://img.shields.io/pypi/dw/cavapy?label=Weekly%20Downloads" alt="Weekly downloads">
|
|
32
|
+
<img src="https://img.shields.io/pypi/v/cavapy?label=pypi%20package" alt="version" style="display: inline-block;">
|
|
33
|
+
<img src="https://shields.io/badge/dependencies-Python_3.11-blue" alt="version" style="display: inline-block;">
|
|
34
|
+
</div>
|
|
35
|
+
</h1
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
--------------------------------------------------------------------------------------------------
|
|
40
|
+
**Check GitHub issues for known servers' downtimes**
|
|
41
|
+
|
|
42
|
+
**We will release bias-corrected CORDEX-CORE simulations with the ISIMIP methodology in 2025. This will allow non-expert users to directly use these datasets and avoid the need for custom bias-correction**
|
|
43
|
+
|
|
44
|
+
--------------------------------------------------------------------------------------------------
|
|
45
|
+
|
|
27
46
|
|
|
28
47
|
## Introduction
|
|
29
48
|
|
|
@@ -31,22 +50,18 @@ Description-Content-Type: text/markdown
|
|
|
31
50
|
|
|
32
51
|
With `cavapy`, users can efficiently integrate CORDEX-CORE data into their workflows, making it an ideal resource for hydrological and crop modeling, among other climate-sensitive analyses. Additionally, `cavapy` enables bias correction, potentially enhancing the precision and usability of the data for a wide range of applications.
|
|
33
52
|
|
|
34
|
-
---
|
|
35
53
|
|
|
36
54
|
## Data Source
|
|
37
55
|
|
|
38
56
|
The climate data provided by `cavapy` is hosted on the THREDDS data server of the University of Cantabria as part of the CAVA project. CAVA is a collaborative effort by FAO, the University of Cantabria, the University of Cape Town, and Predictia, aimed at democratising accessibility and usability of climate information.
|
|
39
57
|
|
|
40
|
-
###
|
|
58
|
+
### Available Datasets via capapy:
|
|
41
59
|
- **CORDEX-CORE Simulations**: Dynamically downscaled high-resolution (25 km) climate models, used in the IPCC AR5 report, featuring simulations from:
|
|
42
60
|
- 3 Global Climate Models (GCMs)
|
|
43
61
|
- 2 Regional Climate Models (RCMs)
|
|
44
|
-
- Two Representative Concentration Pathways (RCPs:
|
|
45
|
-
- **Reanalyses
|
|
46
|
-
- ERA5
|
|
47
|
-
- W5E5 v2
|
|
48
|
-
|
|
49
|
-
These datasets provide robust inputs for climate and environmental modeling, supporting scientific and policy-driven decision-making.
|
|
62
|
+
- Two Representative Concentration Pathways (RCPs: RCP2.6 and RCP8.5)
|
|
63
|
+
- **Reanalyses Dataset**:
|
|
64
|
+
- ERA5 (used for the optional bias correction of the CORDEX-CORE projections)
|
|
50
65
|
|
|
51
66
|
---
|
|
52
67
|
|
|
@@ -81,23 +96,24 @@ The get_climate_data function performs automatically:
|
|
|
81
96
|
|
|
82
97
|
## Example usage
|
|
83
98
|
|
|
84
|
-
Depending on the interest, downloading climate data can be done in a few different ways. Note that GCM stands for General Circulation Model while
|
|
99
|
+
Depending on the interest, downloading climate data can be done in a few different ways. Note that GCM stands for General Circulation Model while RCM stands for Regional Climate Model. As the climate data comes from the CORDEX-CORE initiative, users can choose between 3 different GCMs downscaled with two RCMs. In total, there are six simulations for any given domain (except for CAS-22 where only three are available).
|
|
85
100
|
Since bias-correction requires both the historical run of the CORDEX model and the observational dataset (in this case ERA5), even when the historical argument is set to False, the historical run will be used for learning the bias correction factor.
|
|
86
101
|
|
|
87
|
-
It takes about 10 minutes to run each of the tasks below. For bigger areas/country, the computational time increases.
|
|
102
|
+
It takes about 10 minutes to run each of the tasks below. For bigger areas/country, the computational time increases.
|
|
88
103
|
|
|
89
104
|
### Bias-corrected climate projections
|
|
90
105
|
**By default all available climate variables are used. You can specify a subset with the variable argument**
|
|
91
106
|
|
|
107
|
+
Note that bias correction is automatically performed with empirical quantile mapping on a monthly basis to account for seasonality.
|
|
92
108
|
```
|
|
93
109
|
import cavapy
|
|
94
|
-
Togo_climate_data = cavapy.get_climate_data(country="Togo", cordex_domain="AFR-22", rcp="rcp26", gcm="MPI", rcm="REMO", years_up_to=2030, obs=False, bias_correction=True, historical=False)
|
|
110
|
+
Togo_climate_data = cavapy.get_climate_data(country="Togo", variables=["tasmax", "pr"], cordex_domain="AFR-22", rcp="rcp26", gcm="MPI", rcm="REMO", years_up_to=2030, obs=False, bias_correction=True, historical=False)
|
|
95
111
|
```
|
|
96
112
|
### Non bias-corrected climate projections
|
|
97
113
|
|
|
98
114
|
```
|
|
99
115
|
import cavapy
|
|
100
|
-
Togo_climate_data = cavapy.get_climate_data(country="Togo", cordex_domain="AFR-22", rcp="rcp26", gcm="MPI", rcm="REMO", years_up_to=2030, obs=False, bias_correction=False, historical=False)
|
|
116
|
+
Togo_climate_data = cavapy.get_climate_data(country="Togo",variables=["tasmax", "pr"], cordex_domain="AFR-22", rcp="rcp26", gcm="MPI", rcm="REMO", years_up_to=2030, obs=False, bias_correction=False, historical=False)
|
|
101
117
|
```
|
|
102
118
|
### Bias-corrected climate projections plus the historical run
|
|
103
119
|
|
|
@@ -105,12 +121,12 @@ This is useful when assessing changes in crop yield from the historical period.
|
|
|
105
121
|
|
|
106
122
|
```
|
|
107
123
|
import cavapy
|
|
108
|
-
Togo_climate_data = cavapy.get_climate_data(country="Togo", cordex_domain="AFR-22", rcp="rcp26", gcm="MPI", rcm="REMO", years_up_to=2030, obs=False, bias_correction=True, historical=True)
|
|
124
|
+
Togo_climate_data = cavapy.get_climate_data(country="Togo", variables=["tasmax", "pr"], cordex_domain="AFR-22", rcp="rcp26", gcm="MPI", rcm="REMO", years_up_to=2030, obs=False, bias_correction=True, historical=True)
|
|
109
125
|
```
|
|
110
126
|
### Observations only (ERA5)
|
|
111
127
|
|
|
112
128
|
```
|
|
113
129
|
import cavapy
|
|
114
|
-
Togo_climate_data = cavapy.get_climate_data(country="Togo", cordex_domain="AFR-22", rcp="rcp26", gcm="MPI", rcm="REMO", years_up_to=2030, obs=True, bias_correction=True, historical=True, years_obs=range(1980,2019))
|
|
130
|
+
Togo_climate_data = cavapy.get_climate_data(country="Togo", cordex_domain="AFR-22",variables=["tasmax", "pr"], rcp="rcp26", gcm="MPI", rcm="REMO", years_up_to=2030, obs=True, bias_correction=True, historical=True, years_obs=range(1980,2019))
|
|
115
131
|
```
|
|
116
132
|
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
cavapy.py,sha256=LxsUXZoe_bIQ8rXXrf_GRhvC-RxTVTjLddgrIU8n4qY,26848
|
|
2
|
+
cavapy-0.2.0.dist-info/LICENSE,sha256=1etyG4_n-Tb3yoNMwQ38g_WxXFQ4E_ZCjZc-AGYPc9U,1151
|
|
3
|
+
cavapy-0.2.0.dist-info/METADATA,sha256=byD0GIxS5D_mT-BDxehvV6Vjf_U6d8tgiYcrBLppbcM,7068
|
|
4
|
+
cavapy-0.2.0.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
|
5
|
+
cavapy-0.2.0.dist-info/RECORD,,
|
cavapy.py
CHANGED
|
@@ -72,15 +72,15 @@ DEFAULT_YEARS_OBS = range(1980, 2006)
|
|
|
72
72
|
def get_climate_data(
|
|
73
73
|
*,
|
|
74
74
|
country: str | None,
|
|
75
|
-
cordex_domain: str,
|
|
76
|
-
rcp: str,
|
|
77
|
-
gcm: str,
|
|
78
|
-
rcm: str,
|
|
79
|
-
years_up_to: int,
|
|
80
75
|
years_obs: range | None = None,
|
|
76
|
+
obs: bool = False,
|
|
77
|
+
cordex_domain: str | None = None,
|
|
78
|
+
rcp: str | None = None,
|
|
79
|
+
gcm: str | None = None,
|
|
80
|
+
rcm: str | None = None,
|
|
81
|
+
years_up_to: int | None = None,
|
|
81
82
|
bias_correction: bool = False,
|
|
82
83
|
historical: bool = False,
|
|
83
|
-
obs: bool = False,
|
|
84
84
|
buffer: int = 0,
|
|
85
85
|
xlim: tuple[float, float] | None = None,
|
|
86
86
|
ylim: tuple[float, float] | None = None,
|
|
@@ -96,18 +96,24 @@ def get_climate_data(
|
|
|
96
96
|
Args:
|
|
97
97
|
country (str): Name of the country for which data is to be processed.
|
|
98
98
|
Use None if specifying a region using xlim and ylim.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
99
|
+
years_obs (range): Range of years for observational data (ERA5 only). Required when obs is True. (default: None).
|
|
100
|
+
obs (bool): Flag to indicate if processing observational data (default: False).
|
|
101
|
+
When True, only years_obs is required. CORDEX parameters are optional.
|
|
102
|
+
cordex_domain (str): CORDEX domain of the climate data. One of {VALID_DOMAINS}.
|
|
103
|
+
Required when obs is False. (default: None).
|
|
104
|
+
rcp (str): Representative Concentration Pathway. One of {VALID_RCPS}.
|
|
105
|
+
Required when obs is False. (default: None).
|
|
106
|
+
gcm (str): GCM name. One of {VALID_GCM}.
|
|
107
|
+
Required when obs is False. (default: None).
|
|
108
|
+
rcm (str): RCM name. One of {VALID_RCM}.
|
|
109
|
+
Required when obs is False. (default: None).
|
|
103
110
|
years_up_to (int): The ending year for the projected data. Projections start in 2006 and ends in 2100.
|
|
104
111
|
Hence, if years_up_to is set to 2030, data will be downloaded for the 2006-2030 period.
|
|
105
|
-
|
|
112
|
+
Required when obs is False. (default: None).
|
|
106
113
|
bias_correction (bool): Whether to apply bias correction (default: False).
|
|
107
114
|
historical (bool): Flag to indicate if processing historical data (default: False).
|
|
108
115
|
If True, historical data is provided together with projections.
|
|
109
116
|
Historical simulation runs for CORDEX-CORE initiative are provided for the 1980-2005 time period.
|
|
110
|
-
obs (bool): Flag to indicate if processing observational data (default: False).
|
|
111
117
|
buffer (int): Buffer distance to expand the region of interest (default: 0).
|
|
112
118
|
xlim (tuple or None): Longitudinal bounds of the region of interest. Use only when country is None (default: None).
|
|
113
119
|
ylim (tuple or None): Latitudinal bounds of the region of interest. Use only when country is None (default: None).
|
|
@@ -119,8 +125,17 @@ def get_climate_data(
|
|
|
119
125
|
|
|
120
126
|
Returns:
|
|
121
127
|
dict: A dictionary containing processed climate data for each variable as an xarray object.
|
|
128
|
+
|
|
129
|
+
Examples:
|
|
130
|
+
# For observations only:
|
|
131
|
+
data = get_climate_data(country="Togo", obs=True, years_obs=range(1990, 2011))
|
|
132
|
+
|
|
133
|
+
# For CORDEX projections:
|
|
134
|
+
data = get_climate_data(country="Togo", cordex_domain="AFR-22", rcp="rcp26",
|
|
135
|
+
gcm="MPI", rcm="Reg", years_up_to=2030)
|
|
122
136
|
"""
|
|
123
137
|
|
|
138
|
+
# Validation for basic parameters
|
|
124
139
|
if xlim is None and ylim is not None or xlim is not None and ylim is None:
|
|
125
140
|
raise ValueError(
|
|
126
141
|
"xlim and ylim mismatch: they must be both specified or both unspecified"
|
|
@@ -129,27 +144,46 @@ def get_climate_data(
|
|
|
129
144
|
raise ValueError("You must specify a country or (xlim, ylim)")
|
|
130
145
|
if country is not None and xlim is not None:
|
|
131
146
|
raise ValueError("You must specify either country or (xlim, ylim), not both")
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
147
|
+
|
|
148
|
+
# Conditional validation based on obs flag
|
|
149
|
+
if obs:
|
|
150
|
+
# When obs=True, only years_obs is required
|
|
151
|
+
if years_obs is None:
|
|
152
|
+
raise ValueError("years_obs must be provided when obs is True")
|
|
153
|
+
if not (1980 <= min(years_obs) <= max(years_obs) <= 2020):
|
|
154
|
+
raise ValueError("Years in years_obs must be within the range 1980 to 2020")
|
|
155
|
+
|
|
156
|
+
# Set default values for CORDEX parameters (not used but needed for function calls)
|
|
157
|
+
cordex_domain = cordex_domain or "AFR-22" # dummy value
|
|
158
|
+
rcp = rcp or "rcp26" # dummy value
|
|
159
|
+
gcm = gcm or "MPI" # dummy value
|
|
160
|
+
rcm = rcm or "Reg" # dummy value
|
|
161
|
+
years_up_to = years_up_to or 2030 # dummy value
|
|
162
|
+
else:
|
|
163
|
+
# When obs=False, CORDEX parameters are required
|
|
164
|
+
required_params = {
|
|
165
|
+
"cordex_domain": VALID_DOMAINS,
|
|
166
|
+
"rcp": VALID_RCPS,
|
|
167
|
+
"gcm": VALID_GCM,
|
|
168
|
+
"rcm": VALID_RCM,
|
|
169
|
+
}
|
|
170
|
+
for param_name, valid_values in required_params.items():
|
|
171
|
+
param_value = locals()[param_name]
|
|
172
|
+
if param_value is None:
|
|
173
|
+
raise ValueError(f"{param_name} is required when obs is False")
|
|
174
|
+
if param_value not in valid_values:
|
|
175
|
+
raise ValueError(
|
|
176
|
+
f"Invalid {param_name}={param_value}. Must be one of {valid_values}"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
if years_up_to is None:
|
|
180
|
+
raise ValueError("years_up_to is required when obs is False")
|
|
181
|
+
if years_up_to <= 2006:
|
|
182
|
+
raise ValueError("years_up_to must be greater than 2006")
|
|
183
|
+
|
|
184
|
+
# Set default years_obs when not processing observations
|
|
185
|
+
if years_obs is None:
|
|
186
|
+
years_obs = DEFAULT_YEARS_OBS
|
|
153
187
|
|
|
154
188
|
# Validate variables if provided
|
|
155
189
|
if variables is not None:
|
|
@@ -163,7 +197,7 @@ def get_climate_data(
|
|
|
163
197
|
|
|
164
198
|
_validate_urls(gcm, rcm, rcp, remote, cordex_domain, obs, historical, bias_correction)
|
|
165
199
|
|
|
166
|
-
bbox = _geo_localize(country, xlim, ylim, buffer, cordex_domain)
|
|
200
|
+
bbox = _geo_localize(country, xlim, ylim, buffer, cordex_domain, obs)
|
|
167
201
|
|
|
168
202
|
with mp.Pool(processes=min(num_processes, len(variables))) as pool:
|
|
169
203
|
futures = []
|
|
@@ -257,6 +291,7 @@ def _geo_localize(
|
|
|
257
291
|
ylim: tuple[float, float] = None,
|
|
258
292
|
buffer: int = 0,
|
|
259
293
|
cordex_domain: str = None,
|
|
294
|
+
obs: bool = False,
|
|
260
295
|
) -> dict[str, tuple[float, float]]:
|
|
261
296
|
if country:
|
|
262
297
|
if xlim or ylim:
|
|
@@ -267,7 +302,12 @@ def _geo_localize(
|
|
|
267
302
|
world = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))
|
|
268
303
|
country_shp = world[world.name == country]
|
|
269
304
|
if country_shp.empty:
|
|
270
|
-
|
|
305
|
+
# Check if it's a capitalization issue
|
|
306
|
+
if country and country[0].islower():
|
|
307
|
+
capitalized = country.capitalize()
|
|
308
|
+
raise ValueError(f"Country '{country}' not found. Try capitalizing the first letter: '{capitalized}'")
|
|
309
|
+
else:
|
|
310
|
+
raise ValueError(f"Country '{country}' is unknown.")
|
|
271
311
|
bounds = country_shp.total_bounds # [minx, miny, maxx, maxy]
|
|
272
312
|
xlim, ylim = (bounds[0], bounds[2]), (bounds[1], bounds[3])
|
|
273
313
|
elif not (xlim and ylim):
|
|
@@ -279,8 +319,9 @@ def _geo_localize(
|
|
|
279
319
|
xlim = (xlim[0] - buffer, xlim[1] + buffer)
|
|
280
320
|
ylim = (ylim[0] - buffer, ylim[1] + buffer)
|
|
281
321
|
|
|
282
|
-
#
|
|
283
|
-
|
|
322
|
+
# Only validate CORDEX domain when processing non-observational data
|
|
323
|
+
# Skip validation for observations or when using dummy values
|
|
324
|
+
if not obs and cordex_domain:
|
|
284
325
|
_validate_cordex_domain(xlim, ylim, cordex_domain)
|
|
285
326
|
|
|
286
327
|
return {"xlim": xlim, "ylim": ylim}
|
|
@@ -653,16 +694,25 @@ def _download_data(
|
|
|
653
694
|
|
|
654
695
|
|
|
655
696
|
if __name__ == "__main__":
|
|
656
|
-
data
|
|
697
|
+
# Example 1: Get observational data (simplified syntax)
|
|
698
|
+
print("Getting observational data...")
|
|
699
|
+
obs_data = get_climate_data(
|
|
700
|
+
country="Togo",
|
|
701
|
+
obs=True,
|
|
702
|
+
years_obs=range(1990, 2011),
|
|
703
|
+
variables=["pr", "tasmax"]
|
|
704
|
+
)
|
|
705
|
+
print("Observational data keys:", list(obs_data.keys()))
|
|
706
|
+
|
|
707
|
+
# Example 2: Get CORDEX projection data
|
|
708
|
+
print("\nGetting CORDEX projection data...")
|
|
709
|
+
proj_data = get_climate_data(
|
|
657
710
|
country="Togo",
|
|
658
|
-
variables=["
|
|
711
|
+
variables=["tasmax", "tasmin"],
|
|
659
712
|
cordex_domain="AFR-22",
|
|
660
713
|
rcp="rcp26",
|
|
661
714
|
gcm="MPI",
|
|
662
715
|
rcm="Reg",
|
|
663
716
|
years_up_to=2030,
|
|
664
|
-
obs=False,
|
|
665
|
-
bias_correction=False,
|
|
666
|
-
historical=False,
|
|
667
717
|
)
|
|
668
|
-
print(data)
|
|
718
|
+
print("Projection data keys:", list(proj_data.keys()))
|
cavapy-0.1.3.dist-info/RECORD
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
cavapy.py,sha256=i9ULBOrL4NrtG13KFl7g9JEytsXJkF0Vepudebw7MEY,24377
|
|
2
|
-
cavapy-0.1.3.dist-info/LICENSE,sha256=1etyG4_n-Tb3yoNMwQ38g_WxXFQ4E_ZCjZc-AGYPc9U,1151
|
|
3
|
-
cavapy-0.1.3.dist-info/METADATA,sha256=M2KwoqRuQFd7SAubXRnwFKSJaVci1HfU1Q-BwOoT9Vo,6002
|
|
4
|
-
cavapy-0.1.3.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
|
|
5
|
-
cavapy-0.1.3.dist-info/RECORD,,
|
|
File without changes
|