smashbox 1.0__py2.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.
Files changed (73) hide show
  1. smashbox/.spyproject/config/backups/codestyle.ini.bak +8 -0
  2. smashbox/.spyproject/config/backups/encoding.ini.bak +6 -0
  3. smashbox/.spyproject/config/backups/vcs.ini.bak +7 -0
  4. smashbox/.spyproject/config/backups/workspace.ini.bak +12 -0
  5. smashbox/.spyproject/config/codestyle.ini +8 -0
  6. smashbox/.spyproject/config/defaults/defaults-codestyle-0.2.0.ini +5 -0
  7. smashbox/.spyproject/config/defaults/defaults-encoding-0.2.0.ini +3 -0
  8. smashbox/.spyproject/config/defaults/defaults-vcs-0.2.0.ini +4 -0
  9. smashbox/.spyproject/config/defaults/defaults-workspace-0.2.0.ini +6 -0
  10. smashbox/.spyproject/config/encoding.ini +6 -0
  11. smashbox/.spyproject/config/vcs.ini +7 -0
  12. smashbox/.spyproject/config/workspace.ini +12 -0
  13. smashbox/__init__.py +8 -0
  14. smashbox/asset/flwdir/flowdir_fr_1000m.tif +0 -0
  15. smashbox/asset/outlets/.Rhistory +0 -0
  16. smashbox/asset/outlets/db_bnbv_fr.csv +142704 -0
  17. smashbox/asset/outlets/db_bnbv_light.csv +42084 -0
  18. smashbox/asset/outlets/db_sites.csv +8700 -0
  19. smashbox/asset/outlets/db_stations.csv +2916 -0
  20. smashbox/asset/outlets/db_stations_example.csv +19 -0
  21. smashbox/asset/outlets/edit_database.py +185 -0
  22. smashbox/asset/outlets/readme.txt +5 -0
  23. smashbox/asset/params/ci.tif +0 -0
  24. smashbox/asset/params/cp.tif +0 -0
  25. smashbox/asset/params/ct.tif +0 -0
  26. smashbox/asset/params/kexc.tif +0 -0
  27. smashbox/asset/params/kmlt.tif +0 -0
  28. smashbox/asset/params/llr.tif +0 -0
  29. smashbox/asset/setup/setup_rhax_gr4_dt3600.yaml +15 -0
  30. smashbox/asset/setup/setup_rhax_gr4_dt900.yaml +15 -0
  31. smashbox/asset/setup/setup_rhax_gr5_dt3600.yaml +15 -0
  32. smashbox/asset/setup/setup_rhax_gr5_dt900.yaml +15 -0
  33. smashbox/init/README.md +3 -0
  34. smashbox/init/__init__.py +3 -0
  35. smashbox/init/multimodel_statistics.py +405 -0
  36. smashbox/init/param.py +799 -0
  37. smashbox/init/smashbox.py +186 -0
  38. smashbox/model/__init__.py +1 -0
  39. smashbox/model/atmos_data_connector.py +518 -0
  40. smashbox/model/mesh.py +185 -0
  41. smashbox/model/model.py +829 -0
  42. smashbox/model/setup.py +109 -0
  43. smashbox/plot/__init__.py +1 -0
  44. smashbox/plot/myplot.py +1133 -0
  45. smashbox/plot/plot.py +1662 -0
  46. smashbox/read_inputdata/__init__.py +1 -0
  47. smashbox/read_inputdata/read_data.py +1229 -0
  48. smashbox/read_inputdata/smashmodel.py +395 -0
  49. smashbox/stats/__init__.py +1 -0
  50. smashbox/stats/mystats.py +1632 -0
  51. smashbox/stats/stats.py +2022 -0
  52. smashbox/test.py +532 -0
  53. smashbox/test_average_stats.py +122 -0
  54. smashbox/test_mesh.r +8 -0
  55. smashbox/test_mesh_from_graffas.py +69 -0
  56. smashbox/tools/__init__.py +1 -0
  57. smashbox/tools/geo_toolbox.py +1028 -0
  58. smashbox/tools/tools.py +461 -0
  59. smashbox/tutorial_R.r +182 -0
  60. smashbox/tutorial_R_graffas.r +88 -0
  61. smashbox/tutorial_R_graffas_local.r +33 -0
  62. smashbox/tutorial_python.py +102 -0
  63. smashbox/tutorial_readme.py +261 -0
  64. smashbox/tutorial_report.py +58 -0
  65. smashbox/tutorials/Python_tutorial.md +124 -0
  66. smashbox/tutorials/R_Graffas_tutorial.md +153 -0
  67. smashbox/tutorials/R_tutorial.md +121 -0
  68. smashbox/tutorials/__init__.py +6 -0
  69. smashbox/tutorials/generate_doc.md +7 -0
  70. smashbox-1.0.dist-info/METADATA +998 -0
  71. smashbox-1.0.dist-info/RECORD +73 -0
  72. smashbox-1.0.dist-info/WHEEL +5 -0
  73. smashbox-1.0.dist-info/licenses/LICENSE +100 -0
@@ -0,0 +1,405 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created on Tue Nov 4 13:23:42 2025
5
+
6
+ @author: maxime
7
+ """
8
+
9
+ from smashbox.stats import mystats
10
+ import numpy as np
11
+
12
+
13
+ class 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
+
353
+ class _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
+
361
+ class _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
+
372
+ class _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