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.
- smashbox/.spyproject/config/backups/codestyle.ini.bak +8 -0
- smashbox/.spyproject/config/backups/encoding.ini.bak +6 -0
- smashbox/.spyproject/config/backups/vcs.ini.bak +7 -0
- smashbox/.spyproject/config/backups/workspace.ini.bak +12 -0
- smashbox/.spyproject/config/codestyle.ini +8 -0
- smashbox/.spyproject/config/defaults/defaults-codestyle-0.2.0.ini +5 -0
- smashbox/.spyproject/config/defaults/defaults-encoding-0.2.0.ini +3 -0
- smashbox/.spyproject/config/defaults/defaults-vcs-0.2.0.ini +4 -0
- smashbox/.spyproject/config/defaults/defaults-workspace-0.2.0.ini +6 -0
- smashbox/.spyproject/config/encoding.ini +6 -0
- smashbox/.spyproject/config/vcs.ini +7 -0
- smashbox/.spyproject/config/workspace.ini +12 -0
- smashbox/__init__.py +8 -0
- smashbox/asset/flwdir/flowdir_fr_1000m.tif +0 -0
- smashbox/asset/outlets/.Rhistory +0 -0
- smashbox/asset/outlets/db_bnbv_fr.csv +142704 -0
- smashbox/asset/outlets/db_bnbv_light.csv +42084 -0
- smashbox/asset/outlets/db_sites.csv +8700 -0
- smashbox/asset/outlets/db_stations.csv +2916 -0
- smashbox/asset/outlets/db_stations_example.csv +19 -0
- smashbox/asset/outlets/edit_database.py +185 -0
- smashbox/asset/outlets/readme.txt +5 -0
- smashbox/asset/params/ci.tif +0 -0
- smashbox/asset/params/cp.tif +0 -0
- smashbox/asset/params/ct.tif +0 -0
- smashbox/asset/params/kexc.tif +0 -0
- smashbox/asset/params/kmlt.tif +0 -0
- smashbox/asset/params/llr.tif +0 -0
- smashbox/asset/setup/setup_rhax_gr4_dt3600.yaml +15 -0
- smashbox/asset/setup/setup_rhax_gr4_dt900.yaml +15 -0
- smashbox/asset/setup/setup_rhax_gr5_dt3600.yaml +15 -0
- smashbox/asset/setup/setup_rhax_gr5_dt900.yaml +15 -0
- smashbox/init/README.md +3 -0
- smashbox/init/__init__.py +3 -0
- smashbox/init/multimodel_statistics.py +405 -0
- smashbox/init/param.py +799 -0
- smashbox/init/smashbox.py +186 -0
- smashbox/model/__init__.py +1 -0
- smashbox/model/atmos_data_connector.py +518 -0
- smashbox/model/mesh.py +185 -0
- smashbox/model/model.py +829 -0
- smashbox/model/setup.py +109 -0
- smashbox/plot/__init__.py +1 -0
- smashbox/plot/myplot.py +1133 -0
- smashbox/plot/plot.py +1662 -0
- smashbox/read_inputdata/__init__.py +1 -0
- smashbox/read_inputdata/read_data.py +1229 -0
- smashbox/read_inputdata/smashmodel.py +395 -0
- smashbox/stats/__init__.py +1 -0
- smashbox/stats/mystats.py +1632 -0
- smashbox/stats/stats.py +2022 -0
- smashbox/test.py +532 -0
- smashbox/test_average_stats.py +122 -0
- smashbox/test_mesh.r +8 -0
- smashbox/test_mesh_from_graffas.py +69 -0
- smashbox/tools/__init__.py +1 -0
- smashbox/tools/geo_toolbox.py +1028 -0
- smashbox/tools/tools.py +461 -0
- smashbox/tutorial_R.r +182 -0
- smashbox/tutorial_R_graffas.r +88 -0
- smashbox/tutorial_R_graffas_local.r +33 -0
- smashbox/tutorial_python.py +102 -0
- smashbox/tutorial_readme.py +261 -0
- smashbox/tutorial_report.py +58 -0
- smashbox/tutorials/Python_tutorial.md +124 -0
- smashbox/tutorials/R_Graffas_tutorial.md +153 -0
- smashbox/tutorials/R_tutorial.md +121 -0
- smashbox/tutorials/__init__.py +6 -0
- smashbox/tutorials/generate_doc.md +7 -0
- smashbox-1.0.dist-info/METADATA +998 -0
- smashbox-1.0.dist-info/RECORD +73 -0
- smashbox-1.0.dist-info/WHEEL +5 -0
- 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
|