smashbox.init.multimodel_statistics
Created on Tue Nov 4 13:23:42 2025
@author: maxime
1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3""" 4Created on Tue Nov 4 13:23:42 2025 5 6@author: maxime 7""" 8 9from smashbox.stats import mystats 10import numpy as np 11 12 13class multimodel_statistics: 14 """ 15 Class which handle computation of statistics for multi-model containers. Statistics for each model container must be calculated first. Mean, median, variance, min, max and the distribution of every scores of each model containers are computed. 16 """ 17 18 def __init__(self, parent_class): 19 self._parent_class = parent_class 20 """_parent_class attribute stores the parent_class src.init.smashbox.SmashBox() 21 to be able to access to the result of any model""" 22 23 self.multimodel_misfit_stats = _copy_stats_attr(mystats.misfit_results()) 24 """Attribute misfit_stats_results stores the results of the multimodel statistics for the misfit.""" 25 26 self.multimodel_quantile_stats = None 27 """Attribute quantile_stats_results store the results of the multimodel statistics for the spatial quantile""" 28 29 self.multimodel_spatial_stats = _copy_stats_attr(mystats.spatial_stats_results()) 30 """Atrribute spatial_stats_results store the results of the multimodel statistics for the spatial results""" 31 32 self.multimodel_outlets_stats_sim = _copy_stats_attr( 33 mystats.outlets_stats_results() 34 ) 35 """Atrribute outlets_stats store the resutls of the multimodel statistics for the simulted outlets stats""" 36 37 self.multimodel_outlets_stats_obs = _copy_stats_attr( 38 mystats.outlets_stats_results() 39 ) 40 """Atrribute outlets_stats store the resutls of the multimodel statistics for the observed outlets stats""" 41 42 def _get_model_list(self): 43 44 model_list = list() 45 46 for key, attr in self._parent_class.__dict__.items(): 47 48 if hasattr(attr, "mysmashmodel"): 49 50 current_model = getattr(self._parent_class, key) 51 52 if ( 53 current_model._myparam.param.bbox 54 == self._parent_class.myparam.param.bbox 55 ): 56 model_list.append(key) 57 58 return model_list 59 60 def compute_multimodel_statistics(self, model_list=None): 61 """ 62 Compute the multimodel statistics: mean, median, variance, min, max and the distribution. These statistics 63 are computed over all models containers which contains statistics and match the bounding box in object myparam. 64 65 :param model_list: list of the model container, defaults to None 66 :type model_list: list, optional 67 68 """ 69 70 if model_list is None: 71 model_list = self._get_model_list() 72 73 self.compute_multimodel_statistics_misfit() 74 self.compute_multimodel_statistics_outlets() 75 self.compute_multimodel_statistics_outlets(obs=False) 76 self.compute_multimodel_statistics_outlets(obs=True) 77 self.compute_multimodel_statistics_spatial() 78 self.compute_multimodel_statistics_quantile() 79 80 def compute_multimodel_statistics_misfit(self, model_list=None): 81 """ 82 Compute the multimodel statistics for the misfit criteria. 83 """ 84 if model_list is None: 85 model_list = self._get_model_list() 86 87 dict_results = {} 88 for model in model_list: 89 current_model = getattr(self._parent_class, model) 90 91 misfit_list = current_model.mystats.misfit_stats.results.__dict__ 92 93 for misfit, results in misfit_list.items(): 94 95 if results is None: 96 97 results = ( 98 np.zeros(shape=(len(current_model.mymesh.mesh["code"]))) * np.nan 99 ) 100 print(f"</> Warning misfit {misfit} is None for model {model}.") 101 102 if misfit in dict_results.keys(): 103 dict_results[misfit] = np.stack( 104 (dict_results[misfit], np.array(results)) 105 ) 106 else: 107 dict_results.update({misfit: np.array(results)}) 108 109 for key, values in dict_results.items(): 110 stats = getattr(self.multimodel_misfit_stats, key) 111 stats._fill_stats_attributes(values) 112 113 def compute_multimodel_statistics_outlets(self, model_list=None, obs=False): 114 """ 115 Compute the multimodel statistics for the outlets criteria. 116 """ 117 if model_list is None: 118 model_list = self._get_model_list() 119 120 dict_results = {} 121 for model in model_list: 122 current_model = getattr(self._parent_class, model) 123 124 if obs is False: 125 misfit_list = current_model.mystats.outlets_stats.results_sim.__dict__ 126 else: 127 misfit_list = current_model.mystats.outlets_stats.results_obs.__dict__ 128 129 for misfit, results in misfit_list.items(): 130 131 if results is None: 132 133 results = ( 134 np.zeros(shape=(len(current_model.mymesh.mesh["code"]))) * np.nan 135 ) 136 print(f"</> Warning misfit {misfit} is None for model {model}.") 137 138 if misfit in dict_results.keys(): 139 dict_results[misfit] = np.stack( 140 (dict_results[misfit], np.array(results)) 141 ) 142 else: 143 dict_results.update({misfit: np.array(results)}) 144 145 for key, values in dict_results.items(): 146 if obs is False: 147 stats = getattr(self.multimodel_outlets_stats_sim, key) 148 else: 149 stats = getattr(self.multimodel_outlets_stats_obs, key) 150 stats._fill_stats_attributes(values) 151 152 def compute_multimodel_statistics_spatial(self, model_list=None): 153 """ 154 Compute the multimodel statistics for the spatial statisctics. 155 """ 156 if model_list is None: 157 model_list = self._get_model_list() 158 159 dict_results = {} 160 for model in model_list: 161 current_model = getattr(self._parent_class, model) 162 163 stats_list = current_model.mystats.spatial_stats.results.__dict__ 164 165 for stats, results in stats_list.items(): 166 167 if results is None: 168 169 results = ( 170 np.zeros( 171 shape=( 172 ( 173 current_model.mymesh.mesh["nrow"], 174 current_model.mymesh.mesh["ncol"], 175 ) 176 ) 177 ) 178 * np.nan 179 ) 180 print(f"</> Warning stats {stats} is None for model {model}.") 181 182 if stats in dict_results.keys(): 183 dict_results[stats] = np.stack( 184 (dict_results[stats], np.array(results)) 185 ) 186 else: 187 dict_results.update({stats: np.array(results)}) 188 189 for key, values in dict_results.items(): 190 stats = getattr(self.multimodel_spatial_stats, key) 191 stats._fill_stats_attributes(values) 192 193 def compute_multimodel_statistics_quantile(self, model_list=None): 194 """ 195 Compute the multimodel statistics for the quantile statistic. 196 """ 197 if model_list is None: 198 model_list = self._get_model_list() 199 200 quantile_matrix_dict_results = {} 201 spatial_dict_results = {} 202 vector_dict_results = {} 203 204 self.multimodel_quantile_stats = None 205 206 for model in model_list: 207 208 current_model = getattr(self._parent_class, model) 209 210 if self.multimodel_quantile_stats is None: 211 self.multimodel_quantile_stats = _copy_quantile_attr( 212 current_model.mystats.quantile_stats 213 ) 214 215 all_quantile_results = current_model.mystats.quantile_stats.__dict__ 216 217 quantile_matrix_results = dict( 218 filter( 219 lambda key: not key[0].startswith("Quantile_"), 220 all_quantile_results.items(), 221 ) 222 ) 223 224 quantile_xxh_results = dict( 225 filter( 226 lambda key: key[0].startswith("Quantile_"), 227 all_quantile_results.items(), 228 ) 229 ) 230 231 for key, quantile_matrix in quantile_matrix_results.items(): 232 233 # if not key in quantile_matrix_dict_results.keys(): 234 # quantile_matrix_dict_results.update({key: {}}) 235 236 if quantile_matrix is None: 237 238 quantile_matrix = np.array([np.nan]) 239 print(f"</> Warning quantile attr {key} is None for model {model}.") 240 241 if key in quantile_matrix_dict_results.keys(): 242 quantile_matrix_dict_results[key] = np.concat( 243 ( 244 quantile_matrix_dict_results[key], 245 np.array(quantile_matrix)[np.newaxis, :], 246 ), 247 axis=0, 248 ) 249 else: 250 quantile_matrix_dict_results.update( 251 {key: np.array(quantile_matrix)[np.newaxis, :]} 252 ) 253 254 for key, quantile_xxh in quantile_xxh_results.items(): 255 256 if not key in spatial_dict_results.keys(): 257 spatial_dict_results.update({key: {}}) 258 259 if not key in vector_dict_results.keys(): 260 vector_dict_results.update({key: {}}) 261 262 spatial_attr_list = [ 263 "Q_th", 264 "maxima", 265 "Umin", 266 "Umax", 267 "fit_shape", 268 "fit_scale", 269 "fit_loc", 270 ] 271 272 for attr in spatial_attr_list: 273 274 results = getattr(quantile_xxh, attr) 275 276 if results is None: 277 278 results = ( 279 np.zeros( 280 shape=( 281 ( 282 current_model.mymesh.mesh["nrow"], 283 current_model.mymesh.mesh["ncol"], 284 ) 285 ) 286 ) 287 * np.nan 288 ) 289 print( 290 f"</> Warning quantile attr {attr} is None for model {model}." 291 ) 292 293 if attr in spatial_dict_results[key].keys(): 294 spatial_dict_results[key][attr] = np.concat( 295 ( 296 spatial_dict_results[key][attr], 297 np.array(results)[np.newaxis, :], 298 ), 299 axis=0, 300 ) 301 else: 302 spatial_dict_results[key].update( 303 {attr: np.array(results)[np.newaxis, :]} 304 ) 305 306 vector_attr = ["T", "T_emp", "nb_chunks", "chunk_size", "fit", "duration"] 307 308 for attr in vector_attr: 309 310 results = getattr(quantile_xxh_results[key], attr) 311 312 if results is None: 313 314 results = np.array([np.nan]) 315 print(f"</> Warning attr {attr} is None for model {model}.") 316 317 if isinstance(results, str | int | float): 318 results = [results] 319 320 if attr in vector_dict_results[key].keys(): 321 vector_dict_results[key][attr] = np.concat( 322 ( 323 vector_dict_results[key][attr], 324 np.array(results)[np.newaxis, :], 325 ), 326 axis=0, 327 ) 328 else: 329 vector_dict_results[key].update( 330 {attr: np.array(results)[np.newaxis, :]} 331 ) 332 333 for key, values in quantile_matrix_dict_results.items(): 334 335 if np.any(values != np.nan): 336 stats = getattr(self.multimodel_quantile_stats, key) 337 stats._fill_stats_attributes(values) 338 339 for key, quantile in quantile_xxh_results.items(): 340 341 quantileXXh = getattr(self.multimodel_quantile_stats, key) 342 343 for var_name, values in spatial_dict_results[key].items(): 344 stats = getattr(quantileXXh, var_name) 345 stats._fill_stats_attributes(values) 346 347 for var_name, values in vector_dict_results[key].items(): 348 # stats = getattr(quantileXXh, var_name) 349 # stats = values 350 setattr(quantileXXh, var_name, values) 351 352 353class _copy_stats_attr: 354 355 def __init__(self, example_class): 356 357 for key in example_class.__dict__.keys(): 358 setattr(self, key, _statistics()) 359 360 361class _copy_quantile_attr: 362 363 def __init__(self, quantile_class): 364 365 for key in quantile_class.__dict__.keys(): 366 if key.startswith("Quantile_"): 367 setattr(self, key, _copy_stats_attr(getattr(quantile_class, key))) 368 else: 369 setattr(self, key, _statistics()) 370 371 372class _statistics: 373 """ 374 Class statistics for every statistics used for the multimodel statistics: mean, median, variance, min, max and data (the distribution) 375 """ 376 377 def __init__(self): 378 379 self.mean = None 380 381 self.median = None 382 383 self.variance = None 384 385 self.min = None 386 387 self.max = None 388 389 self.data = None 390 391 def _fill_stats_attributes(self, distrib): 392 self.mean = np.mean(distrib, axis=0) 393 self.median = np.median(distrib, axis=0) 394 self.variance = np.var(distrib, axis=0) 395 self.min = np.min(distrib, axis=0) 396 self.max = np.max(distrib, axis=0) 397 self.data = distrib 398 399 # def _fill_spatial_stats_attributes(self, matrix): 400 # self.mean = np.mean(matrix, axis=0) 401 # self.median = np.median(matrix, axis=0) 402 # self.variance = np.var(matrix, axis=0) 403 # self.min = np.min(matrix, axis=0) 404 # self.max = np.max(matrix, axis=0) 405 # self.data = matrix
14class multimodel_statistics: 15 """ 16 Class which handle computation of statistics for multi-model containers. Statistics for each model container must be calculated first. Mean, median, variance, min, max and the distribution of every scores of each model containers are computed. 17 """ 18 19 def __init__(self, parent_class): 20 self._parent_class = parent_class 21 """_parent_class attribute stores the parent_class src.init.smashbox.SmashBox() 22 to be able to access to the result of any model""" 23 24 self.multimodel_misfit_stats = _copy_stats_attr(mystats.misfit_results()) 25 """Attribute misfit_stats_results stores the results of the multimodel statistics for the misfit.""" 26 27 self.multimodel_quantile_stats = None 28 """Attribute quantile_stats_results store the results of the multimodel statistics for the spatial quantile""" 29 30 self.multimodel_spatial_stats = _copy_stats_attr(mystats.spatial_stats_results()) 31 """Atrribute spatial_stats_results store the results of the multimodel statistics for the spatial results""" 32 33 self.multimodel_outlets_stats_sim = _copy_stats_attr( 34 mystats.outlets_stats_results() 35 ) 36 """Atrribute outlets_stats store the resutls of the multimodel statistics for the simulted outlets stats""" 37 38 self.multimodel_outlets_stats_obs = _copy_stats_attr( 39 mystats.outlets_stats_results() 40 ) 41 """Atrribute outlets_stats store the resutls of the multimodel statistics for the observed outlets stats""" 42 43 def _get_model_list(self): 44 45 model_list = list() 46 47 for key, attr in self._parent_class.__dict__.items(): 48 49 if hasattr(attr, "mysmashmodel"): 50 51 current_model = getattr(self._parent_class, key) 52 53 if ( 54 current_model._myparam.param.bbox 55 == self._parent_class.myparam.param.bbox 56 ): 57 model_list.append(key) 58 59 return model_list 60 61 def compute_multimodel_statistics(self, model_list=None): 62 """ 63 Compute the multimodel statistics: mean, median, variance, min, max and the distribution. These statistics 64 are computed over all models containers which contains statistics and match the bounding box in object myparam. 65 66 :param model_list: list of the model container, defaults to None 67 :type model_list: list, optional 68 69 """ 70 71 if model_list is None: 72 model_list = self._get_model_list() 73 74 self.compute_multimodel_statistics_misfit() 75 self.compute_multimodel_statistics_outlets() 76 self.compute_multimodel_statistics_outlets(obs=False) 77 self.compute_multimodel_statistics_outlets(obs=True) 78 self.compute_multimodel_statistics_spatial() 79 self.compute_multimodel_statistics_quantile() 80 81 def compute_multimodel_statistics_misfit(self, model_list=None): 82 """ 83 Compute the multimodel statistics for the misfit criteria. 84 """ 85 if model_list is None: 86 model_list = self._get_model_list() 87 88 dict_results = {} 89 for model in model_list: 90 current_model = getattr(self._parent_class, model) 91 92 misfit_list = current_model.mystats.misfit_stats.results.__dict__ 93 94 for misfit, results in misfit_list.items(): 95 96 if results is None: 97 98 results = ( 99 np.zeros(shape=(len(current_model.mymesh.mesh["code"]))) * np.nan 100 ) 101 print(f"</> Warning misfit {misfit} is None for model {model}.") 102 103 if misfit in dict_results.keys(): 104 dict_results[misfit] = np.stack( 105 (dict_results[misfit], np.array(results)) 106 ) 107 else: 108 dict_results.update({misfit: np.array(results)}) 109 110 for key, values in dict_results.items(): 111 stats = getattr(self.multimodel_misfit_stats, key) 112 stats._fill_stats_attributes(values) 113 114 def compute_multimodel_statistics_outlets(self, model_list=None, obs=False): 115 """ 116 Compute the multimodel statistics for the outlets criteria. 117 """ 118 if model_list is None: 119 model_list = self._get_model_list() 120 121 dict_results = {} 122 for model in model_list: 123 current_model = getattr(self._parent_class, model) 124 125 if obs is False: 126 misfit_list = current_model.mystats.outlets_stats.results_sim.__dict__ 127 else: 128 misfit_list = current_model.mystats.outlets_stats.results_obs.__dict__ 129 130 for misfit, results in misfit_list.items(): 131 132 if results is None: 133 134 results = ( 135 np.zeros(shape=(len(current_model.mymesh.mesh["code"]))) * np.nan 136 ) 137 print(f"</> Warning misfit {misfit} is None for model {model}.") 138 139 if misfit in dict_results.keys(): 140 dict_results[misfit] = np.stack( 141 (dict_results[misfit], np.array(results)) 142 ) 143 else: 144 dict_results.update({misfit: np.array(results)}) 145 146 for key, values in dict_results.items(): 147 if obs is False: 148 stats = getattr(self.multimodel_outlets_stats_sim, key) 149 else: 150 stats = getattr(self.multimodel_outlets_stats_obs, key) 151 stats._fill_stats_attributes(values) 152 153 def compute_multimodel_statistics_spatial(self, model_list=None): 154 """ 155 Compute the multimodel statistics for the spatial statisctics. 156 """ 157 if model_list is None: 158 model_list = self._get_model_list() 159 160 dict_results = {} 161 for model in model_list: 162 current_model = getattr(self._parent_class, model) 163 164 stats_list = current_model.mystats.spatial_stats.results.__dict__ 165 166 for stats, results in stats_list.items(): 167 168 if results is None: 169 170 results = ( 171 np.zeros( 172 shape=( 173 ( 174 current_model.mymesh.mesh["nrow"], 175 current_model.mymesh.mesh["ncol"], 176 ) 177 ) 178 ) 179 * np.nan 180 ) 181 print(f"</> Warning stats {stats} is None for model {model}.") 182 183 if stats in dict_results.keys(): 184 dict_results[stats] = np.stack( 185 (dict_results[stats], np.array(results)) 186 ) 187 else: 188 dict_results.update({stats: np.array(results)}) 189 190 for key, values in dict_results.items(): 191 stats = getattr(self.multimodel_spatial_stats, key) 192 stats._fill_stats_attributes(values) 193 194 def compute_multimodel_statistics_quantile(self, model_list=None): 195 """ 196 Compute the multimodel statistics for the quantile statistic. 197 """ 198 if model_list is None: 199 model_list = self._get_model_list() 200 201 quantile_matrix_dict_results = {} 202 spatial_dict_results = {} 203 vector_dict_results = {} 204 205 self.multimodel_quantile_stats = None 206 207 for model in model_list: 208 209 current_model = getattr(self._parent_class, model) 210 211 if self.multimodel_quantile_stats is None: 212 self.multimodel_quantile_stats = _copy_quantile_attr( 213 current_model.mystats.quantile_stats 214 ) 215 216 all_quantile_results = current_model.mystats.quantile_stats.__dict__ 217 218 quantile_matrix_results = dict( 219 filter( 220 lambda key: not key[0].startswith("Quantile_"), 221 all_quantile_results.items(), 222 ) 223 ) 224 225 quantile_xxh_results = dict( 226 filter( 227 lambda key: key[0].startswith("Quantile_"), 228 all_quantile_results.items(), 229 ) 230 ) 231 232 for key, quantile_matrix in quantile_matrix_results.items(): 233 234 # if not key in quantile_matrix_dict_results.keys(): 235 # quantile_matrix_dict_results.update({key: {}}) 236 237 if quantile_matrix is None: 238 239 quantile_matrix = np.array([np.nan]) 240 print(f"</> Warning quantile attr {key} is None for model {model}.") 241 242 if key in quantile_matrix_dict_results.keys(): 243 quantile_matrix_dict_results[key] = np.concat( 244 ( 245 quantile_matrix_dict_results[key], 246 np.array(quantile_matrix)[np.newaxis, :], 247 ), 248 axis=0, 249 ) 250 else: 251 quantile_matrix_dict_results.update( 252 {key: np.array(quantile_matrix)[np.newaxis, :]} 253 ) 254 255 for key, quantile_xxh in quantile_xxh_results.items(): 256 257 if not key in spatial_dict_results.keys(): 258 spatial_dict_results.update({key: {}}) 259 260 if not key in vector_dict_results.keys(): 261 vector_dict_results.update({key: {}}) 262 263 spatial_attr_list = [ 264 "Q_th", 265 "maxima", 266 "Umin", 267 "Umax", 268 "fit_shape", 269 "fit_scale", 270 "fit_loc", 271 ] 272 273 for attr in spatial_attr_list: 274 275 results = getattr(quantile_xxh, attr) 276 277 if results is None: 278 279 results = ( 280 np.zeros( 281 shape=( 282 ( 283 current_model.mymesh.mesh["nrow"], 284 current_model.mymesh.mesh["ncol"], 285 ) 286 ) 287 ) 288 * np.nan 289 ) 290 print( 291 f"</> Warning quantile attr {attr} is None for model {model}." 292 ) 293 294 if attr in spatial_dict_results[key].keys(): 295 spatial_dict_results[key][attr] = np.concat( 296 ( 297 spatial_dict_results[key][attr], 298 np.array(results)[np.newaxis, :], 299 ), 300 axis=0, 301 ) 302 else: 303 spatial_dict_results[key].update( 304 {attr: np.array(results)[np.newaxis, :]} 305 ) 306 307 vector_attr = ["T", "T_emp", "nb_chunks", "chunk_size", "fit", "duration"] 308 309 for attr in vector_attr: 310 311 results = getattr(quantile_xxh_results[key], attr) 312 313 if results is None: 314 315 results = np.array([np.nan]) 316 print(f"</> Warning attr {attr} is None for model {model}.") 317 318 if isinstance(results, str | int | float): 319 results = [results] 320 321 if attr in vector_dict_results[key].keys(): 322 vector_dict_results[key][attr] = np.concat( 323 ( 324 vector_dict_results[key][attr], 325 np.array(results)[np.newaxis, :], 326 ), 327 axis=0, 328 ) 329 else: 330 vector_dict_results[key].update( 331 {attr: np.array(results)[np.newaxis, :]} 332 ) 333 334 for key, values in quantile_matrix_dict_results.items(): 335 336 if np.any(values != np.nan): 337 stats = getattr(self.multimodel_quantile_stats, key) 338 stats._fill_stats_attributes(values) 339 340 for key, quantile in quantile_xxh_results.items(): 341 342 quantileXXh = getattr(self.multimodel_quantile_stats, key) 343 344 for var_name, values in spatial_dict_results[key].items(): 345 stats = getattr(quantileXXh, var_name) 346 stats._fill_stats_attributes(values) 347 348 for var_name, values in vector_dict_results[key].items(): 349 # stats = getattr(quantileXXh, var_name) 350 # stats = values 351 setattr(quantileXXh, var_name, values)
Class which handle computation of statistics for multi-model containers. Statistics for each model container must be calculated first. Mean, median, variance, min, max and the distribution of every scores of each model containers are computed.
19 def __init__(self, parent_class): 20 self._parent_class = parent_class 21 """_parent_class attribute stores the parent_class src.init.smashbox.SmashBox() 22 to be able to access to the result of any model""" 23 24 self.multimodel_misfit_stats = _copy_stats_attr(mystats.misfit_results()) 25 """Attribute misfit_stats_results stores the results of the multimodel statistics for the misfit.""" 26 27 self.multimodel_quantile_stats = None 28 """Attribute quantile_stats_results store the results of the multimodel statistics for the spatial quantile""" 29 30 self.multimodel_spatial_stats = _copy_stats_attr(mystats.spatial_stats_results()) 31 """Atrribute spatial_stats_results store the results of the multimodel statistics for the spatial results""" 32 33 self.multimodel_outlets_stats_sim = _copy_stats_attr( 34 mystats.outlets_stats_results() 35 ) 36 """Atrribute outlets_stats store the resutls of the multimodel statistics for the simulted outlets stats""" 37 38 self.multimodel_outlets_stats_obs = _copy_stats_attr( 39 mystats.outlets_stats_results() 40 ) 41 """Atrribute outlets_stats store the resutls of the multimodel statistics for the observed outlets stats"""
Attribute misfit_stats_results stores the results of the multimodel statistics for the misfit.
Attribute quantile_stats_results store the results of the multimodel statistics for the spatial quantile
Atrribute spatial_stats_results store the results of the multimodel statistics for the spatial results
Atrribute outlets_stats store the resutls of the multimodel statistics for the simulted outlets stats
Atrribute outlets_stats store the resutls of the multimodel statistics for the observed outlets stats
61 def compute_multimodel_statistics(self, model_list=None): 62 """ 63 Compute the multimodel statistics: mean, median, variance, min, max and the distribution. These statistics 64 are computed over all models containers which contains statistics and match the bounding box in object myparam. 65 66 :param model_list: list of the model container, defaults to None 67 :type model_list: list, optional 68 69 """ 70 71 if model_list is None: 72 model_list = self._get_model_list() 73 74 self.compute_multimodel_statistics_misfit() 75 self.compute_multimodel_statistics_outlets() 76 self.compute_multimodel_statistics_outlets(obs=False) 77 self.compute_multimodel_statistics_outlets(obs=True) 78 self.compute_multimodel_statistics_spatial() 79 self.compute_multimodel_statistics_quantile()
Compute the multimodel statistics: mean, median, variance, min, max and the distribution. These statistics are computed over all models containers which contains statistics and match the bounding box in object myparam.
Parameters
- model_list: list of the model container, defaults to None
81 def compute_multimodel_statistics_misfit(self, model_list=None): 82 """ 83 Compute the multimodel statistics for the misfit criteria. 84 """ 85 if model_list is None: 86 model_list = self._get_model_list() 87 88 dict_results = {} 89 for model in model_list: 90 current_model = getattr(self._parent_class, model) 91 92 misfit_list = current_model.mystats.misfit_stats.results.__dict__ 93 94 for misfit, results in misfit_list.items(): 95 96 if results is None: 97 98 results = ( 99 np.zeros(shape=(len(current_model.mymesh.mesh["code"]))) * np.nan 100 ) 101 print(f"</> Warning misfit {misfit} is None for model {model}.") 102 103 if misfit in dict_results.keys(): 104 dict_results[misfit] = np.stack( 105 (dict_results[misfit], np.array(results)) 106 ) 107 else: 108 dict_results.update({misfit: np.array(results)}) 109 110 for key, values in dict_results.items(): 111 stats = getattr(self.multimodel_misfit_stats, key) 112 stats._fill_stats_attributes(values)
Compute the multimodel statistics for the misfit criteria.
114 def compute_multimodel_statistics_outlets(self, model_list=None, obs=False): 115 """ 116 Compute the multimodel statistics for the outlets criteria. 117 """ 118 if model_list is None: 119 model_list = self._get_model_list() 120 121 dict_results = {} 122 for model in model_list: 123 current_model = getattr(self._parent_class, model) 124 125 if obs is False: 126 misfit_list = current_model.mystats.outlets_stats.results_sim.__dict__ 127 else: 128 misfit_list = current_model.mystats.outlets_stats.results_obs.__dict__ 129 130 for misfit, results in misfit_list.items(): 131 132 if results is None: 133 134 results = ( 135 np.zeros(shape=(len(current_model.mymesh.mesh["code"]))) * np.nan 136 ) 137 print(f"</> Warning misfit {misfit} is None for model {model}.") 138 139 if misfit in dict_results.keys(): 140 dict_results[misfit] = np.stack( 141 (dict_results[misfit], np.array(results)) 142 ) 143 else: 144 dict_results.update({misfit: np.array(results)}) 145 146 for key, values in dict_results.items(): 147 if obs is False: 148 stats = getattr(self.multimodel_outlets_stats_sim, key) 149 else: 150 stats = getattr(self.multimodel_outlets_stats_obs, key) 151 stats._fill_stats_attributes(values)
Compute the multimodel statistics for the outlets criteria.
153 def compute_multimodel_statistics_spatial(self, model_list=None): 154 """ 155 Compute the multimodel statistics for the spatial statisctics. 156 """ 157 if model_list is None: 158 model_list = self._get_model_list() 159 160 dict_results = {} 161 for model in model_list: 162 current_model = getattr(self._parent_class, model) 163 164 stats_list = current_model.mystats.spatial_stats.results.__dict__ 165 166 for stats, results in stats_list.items(): 167 168 if results is None: 169 170 results = ( 171 np.zeros( 172 shape=( 173 ( 174 current_model.mymesh.mesh["nrow"], 175 current_model.mymesh.mesh["ncol"], 176 ) 177 ) 178 ) 179 * np.nan 180 ) 181 print(f"</> Warning stats {stats} is None for model {model}.") 182 183 if stats in dict_results.keys(): 184 dict_results[stats] = np.stack( 185 (dict_results[stats], np.array(results)) 186 ) 187 else: 188 dict_results.update({stats: np.array(results)}) 189 190 for key, values in dict_results.items(): 191 stats = getattr(self.multimodel_spatial_stats, key) 192 stats._fill_stats_attributes(values)
Compute the multimodel statistics for the spatial statisctics.
194 def compute_multimodel_statistics_quantile(self, model_list=None): 195 """ 196 Compute the multimodel statistics for the quantile statistic. 197 """ 198 if model_list is None: 199 model_list = self._get_model_list() 200 201 quantile_matrix_dict_results = {} 202 spatial_dict_results = {} 203 vector_dict_results = {} 204 205 self.multimodel_quantile_stats = None 206 207 for model in model_list: 208 209 current_model = getattr(self._parent_class, model) 210 211 if self.multimodel_quantile_stats is None: 212 self.multimodel_quantile_stats = _copy_quantile_attr( 213 current_model.mystats.quantile_stats 214 ) 215 216 all_quantile_results = current_model.mystats.quantile_stats.__dict__ 217 218 quantile_matrix_results = dict( 219 filter( 220 lambda key: not key[0].startswith("Quantile_"), 221 all_quantile_results.items(), 222 ) 223 ) 224 225 quantile_xxh_results = dict( 226 filter( 227 lambda key: key[0].startswith("Quantile_"), 228 all_quantile_results.items(), 229 ) 230 ) 231 232 for key, quantile_matrix in quantile_matrix_results.items(): 233 234 # if not key in quantile_matrix_dict_results.keys(): 235 # quantile_matrix_dict_results.update({key: {}}) 236 237 if quantile_matrix is None: 238 239 quantile_matrix = np.array([np.nan]) 240 print(f"</> Warning quantile attr {key} is None for model {model}.") 241 242 if key in quantile_matrix_dict_results.keys(): 243 quantile_matrix_dict_results[key] = np.concat( 244 ( 245 quantile_matrix_dict_results[key], 246 np.array(quantile_matrix)[np.newaxis, :], 247 ), 248 axis=0, 249 ) 250 else: 251 quantile_matrix_dict_results.update( 252 {key: np.array(quantile_matrix)[np.newaxis, :]} 253 ) 254 255 for key, quantile_xxh in quantile_xxh_results.items(): 256 257 if not key in spatial_dict_results.keys(): 258 spatial_dict_results.update({key: {}}) 259 260 if not key in vector_dict_results.keys(): 261 vector_dict_results.update({key: {}}) 262 263 spatial_attr_list = [ 264 "Q_th", 265 "maxima", 266 "Umin", 267 "Umax", 268 "fit_shape", 269 "fit_scale", 270 "fit_loc", 271 ] 272 273 for attr in spatial_attr_list: 274 275 results = getattr(quantile_xxh, attr) 276 277 if results is None: 278 279 results = ( 280 np.zeros( 281 shape=( 282 ( 283 current_model.mymesh.mesh["nrow"], 284 current_model.mymesh.mesh["ncol"], 285 ) 286 ) 287 ) 288 * np.nan 289 ) 290 print( 291 f"</> Warning quantile attr {attr} is None for model {model}." 292 ) 293 294 if attr in spatial_dict_results[key].keys(): 295 spatial_dict_results[key][attr] = np.concat( 296 ( 297 spatial_dict_results[key][attr], 298 np.array(results)[np.newaxis, :], 299 ), 300 axis=0, 301 ) 302 else: 303 spatial_dict_results[key].update( 304 {attr: np.array(results)[np.newaxis, :]} 305 ) 306 307 vector_attr = ["T", "T_emp", "nb_chunks", "chunk_size", "fit", "duration"] 308 309 for attr in vector_attr: 310 311 results = getattr(quantile_xxh_results[key], attr) 312 313 if results is None: 314 315 results = np.array([np.nan]) 316 print(f"</> Warning attr {attr} is None for model {model}.") 317 318 if isinstance(results, str | int | float): 319 results = [results] 320 321 if attr in vector_dict_results[key].keys(): 322 vector_dict_results[key][attr] = np.concat( 323 ( 324 vector_dict_results[key][attr], 325 np.array(results)[np.newaxis, :], 326 ), 327 axis=0, 328 ) 329 else: 330 vector_dict_results[key].update( 331 {attr: np.array(results)[np.newaxis, :]} 332 ) 333 334 for key, values in quantile_matrix_dict_results.items(): 335 336 if np.any(values != np.nan): 337 stats = getattr(self.multimodel_quantile_stats, key) 338 stats._fill_stats_attributes(values) 339 340 for key, quantile in quantile_xxh_results.items(): 341 342 quantileXXh = getattr(self.multimodel_quantile_stats, key) 343 344 for var_name, values in spatial_dict_results[key].items(): 345 stats = getattr(quantileXXh, var_name) 346 stats._fill_stats_attributes(values) 347 348 for var_name, values in vector_dict_results[key].items(): 349 # stats = getattr(quantileXXh, var_name) 350 # stats = values 351 setattr(quantileXXh, var_name, values)
Compute the multimodel statistics for the quantile statistic.