23
23
simp = data to correct (predicted simulated data) ($T_{sim,p}$) \
24
24
\
25
25
\
26
- F = Cummulative Distribution Function \
26
+ F = Cumulative Distribution Function \
27
27
\mu = mean \
28
28
\sigma = standard deviation \
29
29
i = index \
@@ -46,9 +46,14 @@ def __init__(self, method: str, available_methods: list):
46
46
47
47
SCALING_METHODS = ['linear_scaling' , 'variance_scaling' , 'delta_method' ]
48
48
DISTRIBUTION_METHODS = ['quantile_mapping' , 'quantile_delta_mapping' ]
49
+
49
50
CUSTOM_METHODS = SCALING_METHODS + DISTRIBUTION_METHODS
51
+
50
52
METHODS = CUSTOM_METHODS #+ XCLIM_SDBA_METHODS
51
53
54
+ ADDITIVE = ['+' , 'add' ]
55
+ MULTIPLICATIVE = ['*' , 'mult' ]
56
+
52
57
def __init__ (self ):
53
58
pass
54
59
@@ -68,7 +73,7 @@ def get_function(cls, method: str):
68
73
else : raise UnknownMethodError (method , cls .METHODS )
69
74
70
75
@classmethod
71
- def adjust_2d (cls ,
76
+ def adjust_3d (cls ,
72
77
method : str ,
73
78
obs : xr .core .dataarray .DataArray ,
74
79
simh : xr .core .dataarray .DataArray ,
@@ -104,9 +109,9 @@ def adjust_2d(cls,
104
109
> simh = xarray.open_dataset('path/to/simulated/data.nc')
105
110
> obs = xarray.open_dataset('path/to/observed/data.nc')
106
111
> simp = xarray.open_dataset('path/to/simulated_future/data.nc')
107
- > variable = 'temperature '
112
+ > variable = 'tas '
108
113
109
- > adjusted_data = CMethods().adjust_2d (
114
+ > adjusted_data = CMethods().adjust_3d (
110
115
method = 'quantile_delta_mapping',
111
116
obs = obs[variable],
112
117
simh = simh[variable],
@@ -121,7 +126,7 @@ def adjust_2d(cls,
121
126
simh = simh .transpose ('lat' , 'lon' , 'time' )
122
127
simp = simp .transpose ('lat' , 'lon' , 'time' )
123
128
124
- if group == None and method in SCALING_METHODS : group = 'time.month'
129
+ if group == None and method in cls . SCALING_METHODS : group = 'time.month'
125
130
126
131
result = simp .copy (deep = True ).load ()
127
132
len_lat , len_lon = len (obs .lat ), len (obs .lon )
@@ -160,7 +165,7 @@ def adjust_2d(cls,
160
165
@classmethod
161
166
def pool_adjust (cls , params ) -> xr .core .dataarray .DataArray :
162
167
''' Adjustment along longitude for one specific latitude
163
- used by cls.adjust_2d as callbackfunction for multiprocessing.Pool
168
+ used by cls.adjust_3d as callbackfunction for multiprocessing.Pool
164
169
'''
165
170
166
171
method = params ['method' ]
@@ -249,7 +254,7 @@ def linear_scaling(cls,
249
254
simh (xarray.core.dataarray.DataArray): simulated historical Data
250
255
simp (xarray.core.dataarray.DataArray): future simulated Data
251
256
group (str): [optional] Group / Period (e.g.: 'time.month')
252
- kind (str): '+' or '*', default: '+'
257
+ kind (str): [optional] '+' or '*', default: '+'
253
258
254
259
----- R E T U R N -----
255
260
@@ -259,13 +264,13 @@ def linear_scaling(cls,
259
264
> obs = xarray.open_dataset('path/to/observed/data.nc')
260
265
> simh = xarray.open_dataset('path/to/simulated/data.nc')
261
266
> simp = xarray.open_dataset('path/to/predicted/data.nc')
262
- > variable = 'temperature '
267
+ > variable = 'tas '
263
268
264
269
> result = CMethods().linear_scaling(
265
270
> obs=obs[variable],
266
271
> simh=simh[variable],
267
272
> simp=simp[variable],
268
- > group='time.month'
273
+ > group='time.month' # optional
269
274
>)
270
275
271
276
----- E Q U A T I O N S -----
@@ -281,11 +286,10 @@ def linear_scaling(cls,
281
286
https://doi.org/10.1016/j.jhydrol.2012.05.052
282
287
283
288
'''
284
-
285
289
if group != None : return cls .grouped_correction (method = 'linear_scaling' , obs = obs , simh = simh , simp = simp , group = group , kind = kind , ** kwargs )
286
290
else :
287
- if kind == '+' : return np .array (simp ) + (np .nanmean (obs ) - np .nanmean (simh )) # Eq. 1
288
- elif kind == '*' : return np .array (simp ) * (np .nanmean (obs ) / np .nanmean (simh )) # Eq. 2
291
+ if kind in cls . ADDITIVE : return np .array (simp ) + (np .nanmean (obs ) - np .nanmean (simh )) # Eq. 1
292
+ elif kind in cls . MULTIPLICATIVE : return np .array (simp ) * (np .nanmean (obs ) / np .nanmean (simh )) # Eq. 2
289
293
else : raise ValueError ('Scaling type invalid. Valid options for param kind: "+" and "*"' )
290
294
291
295
# ? -----========= V A R I A N C E - S C A L I N G =========------
@@ -306,7 +310,7 @@ def variance_scaling(cls,
306
310
simh (xarray.core.dataarray.DataArray): simulated historical Data
307
311
simp (xarray.core.dataarray.DataArray): future simulated Data
308
312
group (str): [optional] Group / Period (e.g.: 'time.month')
309
- kind (str): '+' or '*', default: '+'
313
+ kind (str): '+' or '*', default: '+' # '*' is not implemented
310
314
311
315
----- R E T U R N -----
312
316
@@ -316,7 +320,7 @@ def variance_scaling(cls,
316
320
> obs = xarray.open_dataset('path/to/observed/data.nc')
317
321
> simh = xarray.open_dataset('path/to/simulated/data.nc')
318
322
> simp = xarray.open_dataset('path/to/predicted/data.nc')
319
- > variable = 'temperature '
323
+ > variable = 'tas '
320
324
321
325
> result = CMethods().variance_scaling(obs=obs[variable], simh=simh[variable], simp=simp[variable] group='time.dayofyear')
322
326
@@ -341,8 +345,8 @@ def variance_scaling(cls,
341
345
'''
342
346
if group != None : return cls .grouped_correction (method = 'variance_scaling' , obs = obs , simh = simh , simp = simp , group = group , kind = kind , ** kwargs )
343
347
else :
344
- LS_simh = cls .linear_scaling (obs , simh , simh ) # Eq. 1
345
- LS_simp = cls .linear_scaling (obs , simh , simp ) # Eq. 2
348
+ LS_simh = cls .linear_scaling (obs , simh , simh , group = None ) # Eq. 1
349
+ LS_simp = cls .linear_scaling (obs , simh , simp , group = None ) # Eq. 2
346
350
347
351
VS_1_simh = LS_simh - np .nanmean (LS_simh ) # Eq. 3
348
352
VS_1_simp = LS_simp - np .nanmean (LS_simp ) # Eq. 4
@@ -379,7 +383,7 @@ def delta_method(cls,
379
383
> obs = xarray.open_dataset('path/to/observed/data.nc')
380
384
> simh = xarray.open_dataset('path/to/simulated/data.nc')
381
385
> simp = xarray.open_dataset('path/to/predicted/data.nc')
382
- > variable = 'temperature '
386
+ > variable = 'tas '
383
387
384
388
> result = CMethods().delta_method(obs=obs[variable], simh=simh[variable], group='time.month')
385
389
@@ -399,8 +403,8 @@ def delta_method(cls,
399
403
'''
400
404
if group != None : return cls .grouped_correction (method = 'delta_method' , obs = obs , simh = simh , simp = simp , group = group , kind = kind , ** kwargs )
401
405
else :
402
- if kind == '+' : return np .array (obs ) + (np .nanmean (simp ) - np .nanmean (simh )) # Eq. 1
403
- elif kind == '*' : return np .array (obs ) * (np .nanmean (simp ) / np .nanmean (simh )) # Eq. 2
406
+ if kind in cls . ADDITIVE : return np .array (obs ) + (np .nanmean (simp ) - np .nanmean (simh )) # Eq. 1
407
+ elif kind in cls . MULTIPLICATIVE : return np .array (obs ) * (np .nanmean (simp ) / np .nanmean (simh )) # Eq. 2
404
408
else : raise ValueError (f'{ kind } not implemented! Use "+" or "*" instead.' )
405
409
406
410
@@ -468,7 +472,7 @@ def quantile_mapping(cls,
468
472
cdf_obs = cls .get_cdf (obs , xbins )
469
473
cdf_simh = cls .get_cdf (simh , xbins )
470
474
471
- if kwargs .get ('detrended' , False ) or kind in [ '*' , 'mult' ] :
475
+ if kwargs .get ('detrended' , False ) or kind in cls . MULTIPLICATIVE :
472
476
'''detrended => shift mean of $X_{sim,p}$ to range of $X_{sim,h}$ to adjust extremes'''
473
477
for month , idxs in res .groupby ('time.month' ).groups .items ():
474
478
m_simh , m_simp = [], []
@@ -481,7 +485,7 @@ def quantile_mapping(cls,
481
485
m_simh_mean = np .nanmean (m_simh )
482
486
m_simp_mean = np .nanmean (m_simp )
483
487
484
- if kind == '+' :
488
+ if kind in cls . ADDITIVE :
485
489
epsilon = np .interp (m_simp - m_simp_mean + m_simh_mean , xbins , cdf_simh ) # Eq. 1
486
490
X = cls .get_inverse_of_cdf (cdf_obs , epsilon , xbins ) + m_simp_mean - m_simh_mean # Eq. 1
487
491
else :
@@ -490,7 +494,7 @@ def quantile_mapping(cls,
490
494
#x = cm.get_inverse_of_cdf(cdf_obs, epsilon, xbins) * (m_simp_mean / m_simh_mean)
491
495
for i , idx in enumerate (idxs ): res .values [idx ] = X [i ]
492
496
return res
493
- elif kind in [ '+' , 'add' ] : # additive, no detrend
497
+ elif kind in cls . ADDITIVE : # additive, no detrend
494
498
epsilon = np .interp (simp , xbins , cdf_simh ) # Eq. 1
495
499
res .values = cls .get_inverse_of_cdf (cdf_obs , epsilon , xbins ) # Eq. 1
496
500
return res
@@ -527,7 +531,7 @@ def empirical_quantile_mapping(cls,
527
531
> obs = xarray.open_dataset('path/to/observed/data.nc')
528
532
> simh = xarray.open_dataset('path/to/simulated/data.nc')
529
533
> simp = xarray.open_dataset('path/to/future/data.nc')
530
- > variable = 'temperature '
534
+ > variable = 'tas '
531
535
> result = CMethods().empirical_quantile_mapping(
532
536
> obs=obs[variable],
533
537
> simh=simh[variable],
@@ -613,7 +617,8 @@ def quantile_delta_mapping(cls,
613
617
'''
614
618
615
619
if group != None : return cls .grouped_correction (method = 'quantile_delta_mapping' , obs = obs , simh = simh , simp = simp , group = group , n_quantiles = n_quantiles , kind = kind , ** kwargs )
616
- elif kind == '+' :
620
+ elif kind in cls .ADDITIVE :
621
+ res = simp .copy (deep = True )
617
622
obs , simh , simp = np .array (obs ), np .array (simh ), np .array (simp ) # to achieve higher accuracy
618
623
global_max = max (np .amax (obs ), np .amax (simh ))
619
624
global_min = min (np .amin (obs ), np .amin (simh ))
@@ -628,9 +633,11 @@ def quantile_delta_mapping(cls,
628
633
epsilon = np .interp (simp , xbins , cdf_simp ) # Eq. 1.1
629
634
QDM1 = cls .get_inverse_of_cdf (cdf_obs , epsilon , xbins ) # Eq. 1.2
630
635
delta = simp - cls .get_inverse_of_cdf (cdf_simh , epsilon , xbins ) # Eq. 1.3
631
- return QDM1 + delta # Eq. 1.4
636
+ res .values = QDM1 + delta # Eq. 1.4
637
+ return res
632
638
633
- elif kind == '*' :
639
+ elif kind in cls .MULTIPLICATIVE :
640
+ res = simp .copy (deep = True )
634
641
obs , simh , simp = np .array (obs ), np .array (simh ), np .array (simp )
635
642
global_max = max (np .amax (obs ), np .amax (simh ))
636
643
wide = global_max / n_quantiles
@@ -643,8 +650,8 @@ def quantile_delta_mapping(cls,
643
650
epsilon = np .interp (simp , xbins , cdf_simp ) # Eq. 1.1
644
651
QDM1 = cls .get_inverse_of_cdf (cdf_obs , epsilon , xbins ) # Eq. 1.2
645
652
delta = simp / cls .get_inverse_of_cdf (cdf_simh , epsilon , xbins ) # Eq. 2.3
646
- return QDM1 * delta # Eq. 2.4
647
-
653
+ res . values = QDM1 * delta # Eq. 2.4
654
+ return res
648
655
else : raise ValueError (f'Unknown kind { kind } !' )
649
656
650
657
# * -----========= G E N E R A L =========------
0 commit comments