2323 simp = data to correct (predicted simulated data) ($T_{sim,p}$) \
2424 \
2525 \
26- F = Cummulative Distribution Function \
26+ F = Cumulative Distribution Function \
2727 \mu = mean \
2828 \sigma = standard deviation \
2929 i = index \
@@ -46,9 +46,14 @@ def __init__(self, method: str, available_methods: list):
4646
4747 SCALING_METHODS = ['linear_scaling' , 'variance_scaling' , 'delta_method' ]
4848 DISTRIBUTION_METHODS = ['quantile_mapping' , 'quantile_delta_mapping' ]
49+
4950 CUSTOM_METHODS = SCALING_METHODS + DISTRIBUTION_METHODS
51+
5052 METHODS = CUSTOM_METHODS #+ XCLIM_SDBA_METHODS
5153
54+ ADDITIVE = ['+' , 'add' ]
55+ MULTIPLICATIVE = ['*' , 'mult' ]
56+
5257 def __init__ (self ):
5358 pass
5459
@@ -68,7 +73,7 @@ def get_function(cls, method: str):
6873 else : raise UnknownMethodError (method , cls .METHODS )
6974
7075 @classmethod
71- def adjust_2d (cls ,
76+ def adjust_3d (cls ,
7277 method : str ,
7378 obs : xr .core .dataarray .DataArray ,
7479 simh : xr .core .dataarray .DataArray ,
@@ -104,9 +109,9 @@ def adjust_2d(cls,
104109 > simh = xarray.open_dataset('path/to/simulated/data.nc')
105110 > obs = xarray.open_dataset('path/to/observed/data.nc')
106111 > simp = xarray.open_dataset('path/to/simulated_future/data.nc')
107- > variable = 'temperature '
112+ > variable = 'tas '
108113
109- > adjusted_data = CMethods().adjust_2d (
114+ > adjusted_data = CMethods().adjust_3d (
110115 method = 'quantile_delta_mapping',
111116 obs = obs[variable],
112117 simh = simh[variable],
@@ -121,7 +126,7 @@ def adjust_2d(cls,
121126 simh = simh .transpose ('lat' , 'lon' , 'time' )
122127 simp = simp .transpose ('lat' , 'lon' , 'time' )
123128
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'
125130
126131 result = simp .copy (deep = True ).load ()
127132 len_lat , len_lon = len (obs .lat ), len (obs .lon )
@@ -160,7 +165,7 @@ def adjust_2d(cls,
160165 @classmethod
161166 def pool_adjust (cls , params ) -> xr .core .dataarray .DataArray :
162167 ''' 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
164169 '''
165170
166171 method = params ['method' ]
@@ -249,7 +254,7 @@ def linear_scaling(cls,
249254 simh (xarray.core.dataarray.DataArray): simulated historical Data
250255 simp (xarray.core.dataarray.DataArray): future simulated Data
251256 group (str): [optional] Group / Period (e.g.: 'time.month')
252- kind (str): '+' or '*', default: '+'
257+ kind (str): [optional] '+' or '*', default: '+'
253258
254259 ----- R E T U R N -----
255260
@@ -259,13 +264,13 @@ def linear_scaling(cls,
259264 > obs = xarray.open_dataset('path/to/observed/data.nc')
260265 > simh = xarray.open_dataset('path/to/simulated/data.nc')
261266 > simp = xarray.open_dataset('path/to/predicted/data.nc')
262- > variable = 'temperature '
267+ > variable = 'tas '
263268
264269 > result = CMethods().linear_scaling(
265270 > obs=obs[variable],
266271 > simh=simh[variable],
267272 > simp=simp[variable],
268- > group='time.month'
273+ > group='time.month' # optional
269274 >)
270275
271276 ----- E Q U A T I O N S -----
@@ -281,11 +286,10 @@ def linear_scaling(cls,
281286 https://doi.org/10.1016/j.jhydrol.2012.05.052
282287
283288 '''
284-
285289 if group != None : return cls .grouped_correction (method = 'linear_scaling' , obs = obs , simh = simh , simp = simp , group = group , kind = kind , ** kwargs )
286290 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
289293 else : raise ValueError ('Scaling type invalid. Valid options for param kind: "+" and "*"' )
290294
291295 # ? -----========= V A R I A N C E - S C A L I N G =========------
@@ -306,7 +310,7 @@ def variance_scaling(cls,
306310 simh (xarray.core.dataarray.DataArray): simulated historical Data
307311 simp (xarray.core.dataarray.DataArray): future simulated Data
308312 group (str): [optional] Group / Period (e.g.: 'time.month')
309- kind (str): '+' or '*', default: '+'
313+ kind (str): '+' or '*', default: '+' # '*' is not implemented
310314
311315 ----- R E T U R N -----
312316
@@ -316,7 +320,7 @@ def variance_scaling(cls,
316320 > obs = xarray.open_dataset('path/to/observed/data.nc')
317321 > simh = xarray.open_dataset('path/to/simulated/data.nc')
318322 > simp = xarray.open_dataset('path/to/predicted/data.nc')
319- > variable = 'temperature '
323+ > variable = 'tas '
320324
321325 > result = CMethods().variance_scaling(obs=obs[variable], simh=simh[variable], simp=simp[variable] group='time.dayofyear')
322326
@@ -341,8 +345,8 @@ def variance_scaling(cls,
341345 '''
342346 if group != None : return cls .grouped_correction (method = 'variance_scaling' , obs = obs , simh = simh , simp = simp , group = group , kind = kind , ** kwargs )
343347 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
346350
347351 VS_1_simh = LS_simh - np .nanmean (LS_simh ) # Eq. 3
348352 VS_1_simp = LS_simp - np .nanmean (LS_simp ) # Eq. 4
@@ -379,7 +383,7 @@ def delta_method(cls,
379383 > obs = xarray.open_dataset('path/to/observed/data.nc')
380384 > simh = xarray.open_dataset('path/to/simulated/data.nc')
381385 > simp = xarray.open_dataset('path/to/predicted/data.nc')
382- > variable = 'temperature '
386+ > variable = 'tas '
383387
384388 > result = CMethods().delta_method(obs=obs[variable], simh=simh[variable], group='time.month')
385389
@@ -399,8 +403,8 @@ def delta_method(cls,
399403 '''
400404 if group != None : return cls .grouped_correction (method = 'delta_method' , obs = obs , simh = simh , simp = simp , group = group , kind = kind , ** kwargs )
401405 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
404408 else : raise ValueError (f'{ kind } not implemented! Use "+" or "*" instead.' )
405409
406410
@@ -468,7 +472,7 @@ def quantile_mapping(cls,
468472 cdf_obs = cls .get_cdf (obs , xbins )
469473 cdf_simh = cls .get_cdf (simh , xbins )
470474
471- if kwargs .get ('detrended' , False ) or kind in [ '*' , 'mult' ] :
475+ if kwargs .get ('detrended' , False ) or kind in cls . MULTIPLICATIVE :
472476 '''detrended => shift mean of $X_{sim,p}$ to range of $X_{sim,h}$ to adjust extremes'''
473477 for month , idxs in res .groupby ('time.month' ).groups .items ():
474478 m_simh , m_simp = [], []
@@ -481,7 +485,7 @@ def quantile_mapping(cls,
481485 m_simh_mean = np .nanmean (m_simh )
482486 m_simp_mean = np .nanmean (m_simp )
483487
484- if kind == '+' :
488+ if kind in cls . ADDITIVE :
485489 epsilon = np .interp (m_simp - m_simp_mean + m_simh_mean , xbins , cdf_simh ) # Eq. 1
486490 X = cls .get_inverse_of_cdf (cdf_obs , epsilon , xbins ) + m_simp_mean - m_simh_mean # Eq. 1
487491 else :
@@ -490,7 +494,7 @@ def quantile_mapping(cls,
490494 #x = cm.get_inverse_of_cdf(cdf_obs, epsilon, xbins) * (m_simp_mean / m_simh_mean)
491495 for i , idx in enumerate (idxs ): res .values [idx ] = X [i ]
492496 return res
493- elif kind in [ '+' , 'add' ] : # additive, no detrend
497+ elif kind in cls . ADDITIVE : # additive, no detrend
494498 epsilon = np .interp (simp , xbins , cdf_simh ) # Eq. 1
495499 res .values = cls .get_inverse_of_cdf (cdf_obs , epsilon , xbins ) # Eq. 1
496500 return res
@@ -527,7 +531,7 @@ def empirical_quantile_mapping(cls,
527531 > obs = xarray.open_dataset('path/to/observed/data.nc')
528532 > simh = xarray.open_dataset('path/to/simulated/data.nc')
529533 > simp = xarray.open_dataset('path/to/future/data.nc')
530- > variable = 'temperature '
534+ > variable = 'tas '
531535 > result = CMethods().empirical_quantile_mapping(
532536 > obs=obs[variable],
533537 > simh=simh[variable],
@@ -613,7 +617,8 @@ def quantile_delta_mapping(cls,
613617 '''
614618
615619 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 )
617622 obs , simh , simp = np .array (obs ), np .array (simh ), np .array (simp ) # to achieve higher accuracy
618623 global_max = max (np .amax (obs ), np .amax (simh ))
619624 global_min = min (np .amin (obs ), np .amin (simh ))
@@ -628,9 +633,11 @@ def quantile_delta_mapping(cls,
628633 epsilon = np .interp (simp , xbins , cdf_simp ) # Eq. 1.1
629634 QDM1 = cls .get_inverse_of_cdf (cdf_obs , epsilon , xbins ) # Eq. 1.2
630635 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
632638
633- elif kind == '*' :
639+ elif kind in cls .MULTIPLICATIVE :
640+ res = simp .copy (deep = True )
634641 obs , simh , simp = np .array (obs ), np .array (simh ), np .array (simp )
635642 global_max = max (np .amax (obs ), np .amax (simh ))
636643 wide = global_max / n_quantiles
@@ -643,8 +650,8 @@ def quantile_delta_mapping(cls,
643650 epsilon = np .interp (simp , xbins , cdf_simp ) # Eq. 1.1
644651 QDM1 = cls .get_inverse_of_cdf (cdf_obs , epsilon , xbins ) # Eq. 1.2
645652 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
648655 else : raise ValueError (f'Unknown kind { kind } !' )
649656
650657 # * -----========= G E N E R A L =========------
0 commit comments