Skip to content

Commit 6f5cd4e

Browse files
added notebook; main script; main adjustment class and example datasets; edited README.md
1 parent 41c1837 commit 6f5cd4e

File tree

9 files changed

+1260
-1
lines changed

9 files changed

+1260
-1
lines changed

.DS_Store

6 KB
Binary file not shown.

CMethods.py

Lines changed: 755 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,44 @@
1-
# Bias-Adjustment-Python
1+
# Bias-Adjustment-Python
2+
3+
Collection of different scale- and distribution-based bias adjustments for climatic research. This methods are part of the bachelor thesis of Benjamin T. Schwertfeger.
4+
During this thesis, many of these methods have also been implemented in C++.
5+
This can be found here: [https://github.com/btschwertfeger/Bias-Adjustment-Cpp](https://github.com/btschwertfeger/Bias-Adjustment-Cpp).
6+
7+
There is also a Jupyter Notebook that serves as example.
8+
____
9+
## Run adjustment:
10+
```bash
11+
python3 do_bias_correction.py \
12+
--obs input_data/obs.nc \
13+
--contr input_data/contr.nc \
14+
--scen input_data/scen.nc \
15+
--method linear_scaling \
16+
--variable tas \
17+
--unit '°C' \
18+
--group time.month \
19+
--kind +
20+
```
21+
____
22+
## Methods implemented by Benjamin T. Schwertfeger:
23+
|Method| `--method` parameter|
24+
|-----|-----|
25+
|Linear Scaling| linear_scaling|
26+
|Variance Scaling|variance_scaling|
27+
|Delta Method|delta_method|
28+
|Quantile Mapping|quantile_mapping|
29+
|Quantile Delta Mapping|quantile_delta_mapping|
30+
31+
## Methods adapted from [xclim](https://xclim.readthedocs.io/en/stable/sdba.html):
32+
|Method| `--method` parameter|
33+
|-----|-----|
34+
|Empirical Quantile Mapping|xclim_eqm|
35+
|Detrended Quantile Mapping|xclim_dqm|
36+
|Quantile Delta Mapping|xclime_qdm|
37+
38+
39+
____
40+
# Notes:
41+
- Linear and variance, as well as delta change method require `--group time.month` as argument.
42+
- Adjustment methods that apply changes in distributional biasses (QM. QDM, DQM; EQM, ...) need the `--nquantiles` argument set to some integer.
43+
- Data sets should have the same spatial resolutions.
44+
- Computation in Python takes some time, so this is only for demonstration. When adjusting large datasets, its best to the C++ implementation mentioned above.

do_bias_correction.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#!/bin/python3
2+
3+
__descrption__ = 'Script to adjust climate biases in 3D Climate data'
4+
__author__ = 'Benjamin Thomas Schwertfeger'
5+
__copyright__ = __author__
6+
__email__ = '[email protected]'
7+
__link__ = 'https://b-schwertfeger.de'
8+
__github__ = 'https://github.com/btschwertfeger/Bias-Adjustment-Python';
9+
10+
import argparse
11+
import logging, sys
12+
import xarray as xr
13+
14+
from CMethods import CMethods
15+
16+
# * ----- L O G G I N G -----
17+
formatter = logging.Formatter(
18+
fmt='%(asctime)s %(module)s,line: %(lineno)d %(levelname)8s | %(message)s',
19+
datefmt='%Y-%m-%d %H:%M:%S'
20+
)
21+
22+
log = logging.getLogger()
23+
log.setLevel(logging.INFO)
24+
screen_handler = logging.StreamHandler(stream=sys.stdout)
25+
screen_handler.setFormatter(formatter)
26+
logging.getLogger().addHandler(screen_handler)
27+
28+
# * ----- I N P U T - H A N D L I N G -----
29+
parser = argparse.ArgumentParser(description='Adjust climate data based on bias correction algorithms and magic.')
30+
parser.add_argument('--obs', '--observation', dest='obs_fpath', type=str, help='Observation dataset')
31+
parser.add_argument('--contr', '--control', dest='contr_fpath', type=str, help='Control dataset')
32+
parser.add_argument('--scen', '--scenario', dest='scen_fpath', type=str, help='Scenario dataset (data to adjust)')
33+
34+
parser.add_argument('-m', '--method', dest='method', type=str, help='Correction method')
35+
parser.add_argument('-v', '--variable', dest='var', type=str, default='tas', help='Variable to adjust')
36+
parser.add_argument('-u', '--unit', dest='unit', type=str, default='°C', help='Unit of the varible')
37+
38+
parser.add_argument('-g', '--group', dest='group', type=str, default=None, help='Value grouping, default: time, (options: time.month, time.dayofyear, time.year')
39+
parser.add_argument('-k', '--kind', dest='kind', type=str, default='+', help='+ or *, default: +')
40+
parser.add_argument('-w', '--window', dest='window', type=int, default=1, help='Window of grouping')
41+
parser.add_argument('-n', '--nquantiles', dest='n_quantiles', type=int, default=100, help='Nr. of Quantiles to use')
42+
43+
parser.add_argument('-p', '--processes', dest='p', type=int, default=1, help='Multiprocessing with n processes, default: 1')
44+
params = vars(parser.parse_args())
45+
46+
obs_fpath = params['obs_fpath']
47+
contr_fpath = params['contr_fpath']
48+
scen_fpath = params['scen_fpath']
49+
50+
method = params['method']
51+
var = params['var']
52+
unit = params['unit']
53+
group = params['group']
54+
kind = params['kind']
55+
window = params['window']
56+
n_quantiles = params['n_quantiles']
57+
n_jobs = params['p']
58+
59+
# * ----- ----- -----M A I N ----- ----- -----
60+
def main() -> None:
61+
cm = CMethods()
62+
63+
if method not in cm.get_available_methods(): raise ValueError(f'Unknown method {method}. Available methods: {cm.get_available_methods()}')
64+
65+
ds_obs = xr.open_dataset(obs_fpath)[var]
66+
ds_simh = xr.open_dataset(contr_fpath)[var]
67+
ds_simp = xr.open_dataset(scen_fpath)[var]
68+
log.info('Data Loaded')
69+
70+
ds_obs.attrs['unit'] = unit
71+
ds_simh.attrs['unit'] = unit
72+
ds_simp.attrs['unit'] = unit
73+
74+
start_date: str = ds_simp['time'][0].dt.strftime('%Y%m%d').values.ravel()[0]
75+
end_date: str = ds_simp['time'][-1].dt.strftime('%Y%m%d').values.ravel()[0]
76+
77+
descr1, descr2 = '', ''
78+
if method in cm.XCLIM_SDBA_METHODS or method in ['quantile_mapping', 'quantile_delta_mapping']:
79+
descr1 = f'_quantiles-{n_quantiles}'
80+
descr2 = f'_window-{window}'
81+
82+
# ----- Adjustment -----
83+
log.info(f'Starting {method} adjustment')
84+
result = cm.adjust_2d(
85+
method = method,
86+
obs = ds_obs,
87+
simh = ds_simh,
88+
simp = ds_simp,
89+
n_quantiles = n_quantiles,
90+
kind = kind,
91+
group = group,
92+
window = window,
93+
n_jobs = n_jobs
94+
)
95+
log.info('Saving now')
96+
result.name = var
97+
result['time'] = ds_simp['time']
98+
result.to_netcdf(f'{method}_result_var-{var}{descr1}_kind-{kind}_group-{group}{descr2}_{start_date}_{end_date}.nc')
99+
log.info('Done')
100+
101+
102+
if __name__ == '__main__':
103+
main()
104+
105+
106+
# * ----- ----- E O F ----- -----

examples.ipynb

Lines changed: 350 additions & 0 deletions
Large diffs are not rendered by default.

input_data/contr.nc

779 KB
Binary file not shown.

input_data/obs.nc

779 KB
Binary file not shown.

input_data/scen.nc

779 KB
Binary file not shown.

requirements.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
numpy
2+
xarray
3+
xclim
4+
scipy
5+
tqdm

0 commit comments

Comments
 (0)