wolfhece 2.2.38__py3-none-any.whl → 2.2.39__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 (49) hide show
  1. wolfhece/Coordinates_operations.py +5 -0
  2. wolfhece/GraphNotebook.py +72 -1
  3. wolfhece/GraphProfile.py +1 -1
  4. wolfhece/MulticriteriAnalysis.py +1579 -0
  5. wolfhece/PandasGrid.py +62 -1
  6. wolfhece/PyCrosssections.py +194 -43
  7. wolfhece/PyDraw.py +891 -73
  8. wolfhece/PyGui.py +913 -72
  9. wolfhece/PyGuiHydrology.py +528 -74
  10. wolfhece/PyPalette.py +26 -4
  11. wolfhece/PyParams.py +33 -0
  12. wolfhece/PyPictures.py +2 -2
  13. wolfhece/PyVertex.py +25 -0
  14. wolfhece/PyVertexvectors.py +94 -28
  15. wolfhece/PyWMS.py +52 -36
  16. wolfhece/acceptability/acceptability.py +15 -8
  17. wolfhece/acceptability/acceptability_gui.py +507 -360
  18. wolfhece/acceptability/func.py +80 -183
  19. wolfhece/apps/version.py +1 -1
  20. wolfhece/compare_series.py +480 -0
  21. wolfhece/drawing_obj.py +12 -1
  22. wolfhece/hydrology/Catchment.py +228 -162
  23. wolfhece/hydrology/Internal_variables.py +43 -2
  24. wolfhece/hydrology/Models_characteristics.py +69 -67
  25. wolfhece/hydrology/Optimisation.py +893 -182
  26. wolfhece/hydrology/PyWatershed.py +267 -165
  27. wolfhece/hydrology/SubBasin.py +185 -140
  28. wolfhece/hydrology/cst_exchanges.py +76 -1
  29. wolfhece/hydrology/forcedexchanges.py +413 -49
  30. wolfhece/hydrology/read.py +65 -5
  31. wolfhece/hydrometry/kiwis.py +14 -7
  32. wolfhece/insyde_be/INBE_func.py +746 -0
  33. wolfhece/insyde_be/INBE_gui.py +1776 -0
  34. wolfhece/insyde_be/__init__.py +3 -0
  35. wolfhece/interpolating_raster.py +366 -0
  36. wolfhece/irm_alaro.py +1457 -0
  37. wolfhece/irm_qdf.py +889 -57
  38. wolfhece/lifewatch.py +6 -3
  39. wolfhece/picc.py +124 -8
  40. wolfhece/pyLandUseFlanders.py +146 -0
  41. wolfhece/pydownloader.py +2 -1
  42. wolfhece/pywalous.py +225 -31
  43. wolfhece/toolshydrology_dll.py +149 -0
  44. wolfhece/wolf_array.py +63 -25
  45. {wolfhece-2.2.38.dist-info → wolfhece-2.2.39.dist-info}/METADATA +3 -1
  46. {wolfhece-2.2.38.dist-info → wolfhece-2.2.39.dist-info}/RECORD +49 -40
  47. {wolfhece-2.2.38.dist-info → wolfhece-2.2.39.dist-info}/WHEEL +0 -0
  48. {wolfhece-2.2.38.dist-info → wolfhece-2.2.39.dist-info}/entry_points.txt +0 -0
  49. {wolfhece-2.2.38.dist-info → wolfhece-2.2.39.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,480 @@
1
+ import numpy as np
2
+ import logging
3
+ from pathlib import Path
4
+ import pandas as pd
5
+
6
+ """
7
+ Reference : https://hess.copernicus.org/articles/27/2397/2023/hess-27-2397-2023.html - "When best is the enemy of good – critical evaluation of performance criteria in hydrological models"
8
+
9
+ Definitions :
10
+ - beta = mean(simulated) / mean(observed)
11
+ - beta_n = (mean(simulated) - mean(observed)) / standard_deviation(observed)
12
+ - alpha = standard_deviation(simulated) / standard_deviation(observed)
13
+ - CV = standard_deviation / mean
14
+ - gamma = CV(simulated) / CV(observed)
15
+ - B_rel = (FDC_simulated - FDC_observed) / FDC_observed
16
+ - B_rel_mean = mean(B_rel)
17
+ - B_res = B_rel - B_rel_mean
18
+ - B_area = integral(B_res)
19
+ - r = correlation coefficient between observed and simulated data
20
+ - r_s = Spearman rank correlation coefficient between observed and simulated data
21
+ """
22
+
23
+ def Nash_Sutcliffe_efficiency(observed, simulated):
24
+ """
25
+ Calculate the Nash-Sutcliffe efficiency coefficient (NSE) between observed and simulated data.
26
+
27
+ :param observed: Array-like structure containing observed data values.
28
+ :param simulated: Array-like structure containing simulated data values.
29
+ :raises ValueError: If the lengths of observed and simulated data do not match.
30
+ :return: The Nash-Sutcliffe efficiency coefficient.
31
+ """
32
+
33
+ if isinstance(observed, pd.Series):
34
+ observed = observed.values
35
+
36
+ if isinstance(simulated, pd.Series):
37
+ simulated = simulated.values
38
+
39
+ if len(observed) != len(simulated):
40
+ raise ValueError("Observed and simulated data must have the same length.")
41
+
42
+ # Convert to numpy arrays for calculations
43
+ observed = np.array(observed)
44
+ simulated = np.array(simulated)
45
+
46
+ # Calculate the numerator and denominator for the NSE
47
+ numerator = np.sum((observed - simulated) ** 2)
48
+ denominator = np.sum((observed - np.mean(observed)) ** 2)
49
+
50
+ # Calculate and return the NSE
51
+ nse = 1 - (numerator / denominator) if denominator != 0 else np.nan
52
+
53
+ return nse
54
+
55
+ def Kling_Gupta_efficiency(observed, simulated):
56
+ """
57
+ Calculate the Kling-Gupta efficiency coefficient (KGE) between observed and simulated data.
58
+
59
+ :param observed: Array-like structure containing observed data values.
60
+ :param simulated: Array-like structure containing simulated data values.
61
+ :raises ValueError: If the lengths of observed and simulated data do not match.
62
+ :return: The Kling-Gupta efficiency coefficient.
63
+ """
64
+
65
+ if isinstance(observed, pd.Series):
66
+ observed = observed.values
67
+
68
+ if isinstance(simulated, pd.Series):
69
+ simulated = simulated.values
70
+
71
+ if len(observed) != len(simulated):
72
+ raise ValueError("Observed and simulated data must have the same length.")
73
+
74
+ # Convert to numpy arrays for calculations
75
+ observed = np.array(observed)
76
+ simulated = np.array(simulated)
77
+
78
+ # Calculate the components for the KGE
79
+ r = np.corrcoef(observed, simulated)[0, 1]
80
+ alpha = np.std(simulated) / np.std(observed)
81
+ beta = np.mean(simulated) / np.mean(observed)
82
+
83
+ # Calculate and return the KGE
84
+ kge = 1 - np.sqrt((r - 1) ** 2 + (alpha - 1) ** 2 + (beta - 1) ** 2)
85
+ return kge
86
+
87
+ def modified_Kling_Gupta_efficiency(observed, simulated):
88
+ """
89
+ Calculate the modified Kling-Gupta efficiency coefficient (KGE') between observed and simulated data.
90
+
91
+ A modified Kling-Gupta efficiency was proposed by Kling et al. (2012).
92
+ The coefficient of variation is used instead of the standard deviation
93
+ to ensure that bias and variability are not cross-correlated
94
+
95
+ :param observed: Array-like structure containing observed data values.
96
+ :param simulated: Array-like structure containing simulated data values.
97
+ :raises ValueError: If the lengths of observed and simulated data do not match.
98
+ :return: The modified Kling-Gupta efficiency coefficient.
99
+ """
100
+
101
+ if isinstance(observed, pd.Series):
102
+ observed = observed.values
103
+
104
+ if isinstance(simulated, pd.Series):
105
+ simulated = simulated.values
106
+
107
+ if len(observed) != len(simulated):
108
+ raise ValueError("Observed and simulated data must have the same length.")
109
+
110
+ # Convert to numpy arrays for calculations
111
+ observed = np.array(observed)
112
+ simulated = np.array(simulated)
113
+
114
+ # Calculate the components for the modified KGE
115
+ r = np.corrcoef(observed, simulated)[0, 1]
116
+ # alpha = np.std(simulated) / np.std(observed)
117
+ beta = np.mean(simulated) / np.mean(observed)
118
+ cv_observed = np.std(observed) / np.mean(observed)
119
+ cv_simulated = np.std(simulated) / np.mean(simulated)
120
+
121
+ # Calculate and return the modified KGE
122
+ kge_prime = 1 - np.sqrt((r - 1) ** 2 + (beta - 1) ** 2 + (cv_simulated / cv_observed - 1) ** 2)
123
+ return kge_prime
124
+
125
+ def modified_Kling_Gupta_efficiency_Spearman(observed, simulated):
126
+ """
127
+ Calculate the modified Kling-Gupta efficiency coefficient (KGE') between observed and simulated data.
128
+
129
+ A modified Kling-Gupta efficiency was proposed by Kling et al. (2012).
130
+ The coefficient of variation is used instead of the standard deviation
131
+ to ensure that bias and variability are not cross-correlated
132
+
133
+ :param observed: Array-like structure containing observed data values.
134
+ :param simulated: Array-like structure containing simulated data values.
135
+ :raises ValueError: If the lengths of observed and simulated data do not match.
136
+ :return: The modified Kling-Gupta efficiency coefficient.
137
+ """
138
+
139
+ if isinstance(observed, pd.Series):
140
+ observed = observed.values
141
+
142
+ if isinstance(simulated, pd.Series):
143
+ simulated = simulated.values
144
+
145
+ if len(observed) != len(simulated):
146
+ raise ValueError("Observed and simulated data must have the same length.")
147
+
148
+ # Convert to numpy arrays for calculations
149
+ observed = np.array(observed)
150
+ simulated = np.array(simulated)
151
+
152
+ # Calculate the components for the modified KGE
153
+ r = Spearman_Rank_Correlation_Coefficient(observed, simulated)
154
+ # alpha = np.std(simulated) / np.std(observed)
155
+ beta = np.mean(simulated) / np.mean(observed)
156
+ cv_observed = np.std(observed) / np.mean(observed)
157
+ cv_simulated = np.std(simulated) / np.mean(simulated)
158
+
159
+ # Calculate and return the modified KGE
160
+ kge_prime_sp = 1 - np.sqrt((r - 1) ** 2 + (beta - 1) ** 2 + (cv_simulated / cv_observed - 1) ** 2)
161
+ return kge_prime_sp
162
+
163
+ def Normalised_Diagnostic_efficiency(observed, simulated):
164
+ """
165
+ Calculate the Diagnostic efficiency coefficient (DE) between observed and simulated data.
166
+
167
+ Schwemmle et al. (2021) used Flow Duration Curve (FDC)-based parameters to account
168
+ for variability and bias in another KGE variant: the diagnostic efficiency.
169
+ This criterion is based on constant, dynamic, and timing errors and aims to provide
170
+ a stronger link to hydrological processes (Schwemmle et al., 2021)
171
+
172
+ :param observed: Array-like structure containing observed data values.
173
+ :param simulated: Array-like structure containing simulated data values.
174
+ :raises ValueError: If the lengths of observed and simulated data do not match.
175
+ :return: The Diagnostic efficiency coefficient.
176
+ """
177
+
178
+ if isinstance(observed, pd.Series):
179
+ observed = observed.values
180
+
181
+ if isinstance(simulated, pd.Series):
182
+ simulated = simulated.values
183
+
184
+ if len(observed) != len(simulated):
185
+ raise ValueError("Observed and simulated data must have the same length.")
186
+
187
+ # Convert to numpy arrays for calculations
188
+ observed = np.array(observed)
189
+ simulated = np.array(simulated)
190
+
191
+ FDC_observed = np.sort(observed)
192
+ FDC_simulated = np.sort(simulated)
193
+
194
+ r = np.corrcoef(FDC_observed, FDC_simulated)[0, 1]
195
+
196
+ B_rel = (FDC_simulated - FDC_observed) / FDC_observed
197
+ B_rel_mean = np.mean(B_rel)
198
+ B_res = B_rel - B_rel_mean
199
+ B_area = np.trapz(B_res, dx=1) # Assuming uniform spacing for simplicity
200
+
201
+ de = 1 - np.sqrt(B_rel_mean ** 2 + (r - 1) ** 2 + B_area ** 2)
202
+
203
+ return de
204
+
205
+ def Liu_mean_efficiency(observed, simulated):
206
+ """
207
+ Calculate the Liu mean efficiency coefficient (LME) between observed and simulated data.
208
+
209
+ The Liu mean efficiency is a variant of the Nash-Sutcliffe efficiency that
210
+ accounts for the mean of the observed data.
211
+
212
+ :param observed: Array-like structure containing observed data values.
213
+ :param simulated: Array-like structure containing simulated data values.
214
+ :raises ValueError: If the lengths of observed and simulated data do not match.
215
+ :return: The Liu mean efficiency coefficient.
216
+ """
217
+
218
+ if isinstance(observed, pd.Series):
219
+ observed = observed.values
220
+
221
+ if isinstance(simulated, pd.Series):
222
+ simulated = simulated.values
223
+
224
+ if len(observed) != len(simulated):
225
+ raise ValueError("Observed and simulated data must have the same length.")
226
+
227
+ # Convert to numpy arrays for calculations
228
+ observed = np.array(observed)
229
+ simulated = np.array(simulated)
230
+
231
+ r = np.corrcoef(observed, simulated)[0, 1]
232
+ alpha = np.std(simulated) / np.std(observed)
233
+ beta = np.mean(simulated) / np.mean(observed)
234
+
235
+ lme = 1 - np.sqrt((r*alpha - 1) ** 2 + (beta - 1) ** 2)
236
+
237
+ return lme
238
+
239
+ def Lee_Choi_mean_efficiency(observed, simulated):
240
+ """
241
+ Calculate the Lee-Choi mean efficiency coefficient (LCME) between observed and simulated data.
242
+
243
+ The Lee-Choi mean efficiency is a variant of the Nash-Sutcliffe efficiency that
244
+ accounts for the mean of the observed data and is less sensitive to outliers.
245
+
246
+ :param observed: Array-like structure containing observed data values.
247
+ :param simulated: Array-like structure containing simulated data values.
248
+ :raises ValueError: If the lengths of observed and simulated data do not match.
249
+ :return: The Lee-Choi mean efficiency coefficient.
250
+ """
251
+
252
+ if isinstance(observed, pd.Series):
253
+ observed = observed.values
254
+
255
+ if isinstance(simulated, pd.Series):
256
+ simulated = simulated.values
257
+
258
+ if len(observed) != len(simulated):
259
+ raise ValueError("Observed and simulated data must have the same length.")
260
+
261
+ # Convert to numpy arrays for calculations
262
+ observed = np.array(observed)
263
+ simulated = np.array(simulated)
264
+
265
+ r = np.corrcoef(observed, simulated)[0, 1]
266
+ alpha = np.std(simulated) / np.std(observed)
267
+ beta = np.mean(simulated) / np.mean(observed)
268
+
269
+ lcme = 1 - np.sqrt((r*alpha - 1) ** 2 + (r / alpha -1) ** 2 + (beta - 1) ** 2)
270
+
271
+ return lcme
272
+
273
+ def Dynamic_Time_Warping_distance(series1, series2):
274
+ """
275
+ Calculate the Dynamic Time Warping (DTW) distance between two time series.
276
+
277
+ The time series can be of different lengths, and DTW finds the optimal alignment
278
+ between them by minimizing the distance.
279
+
280
+ :param series1: First time series as a list or numpy array.
281
+ :param series2: Second time series as a list or numpy array.
282
+ :return: The DTW distance between the two time series.
283
+ """
284
+ from dtaidistance import dtw
285
+
286
+ if isinstance(series1, pd.Series):
287
+ series1 = series1.values
288
+
289
+ if isinstance(series2, pd.Series):
290
+ series2 = series2.values
291
+
292
+ return dtw.distance_fast(series1, series2)
293
+
294
+ def Dynamic_Time_Warping_distance_normalized(series1, series2):
295
+ """
296
+ Calculate the normalized Dynamic Time Warping (DTW) distance between two time series.
297
+
298
+ The DTW distance is normalized by the length of the path to provide a relative measure.
299
+
300
+ :param series1: First time series as a list or numpy array.
301
+ :param series2: Second time series as a list or numpy array.
302
+ :return: The normalized DTW distance between the two time series.
303
+ """
304
+ from dtaidistance import dtw
305
+
306
+ if isinstance(series1, pd.Series):
307
+ series1 = series1.values
308
+
309
+ if isinstance(series2, pd.Series):
310
+ series2 = series2.values
311
+
312
+ path, distance = dtw.warping_path_fast(series1, series2, include_distance=True)
313
+
314
+ if len(path) == 0:
315
+ return 0.0
316
+
317
+ return distance / len(path)
318
+
319
+
320
+ def Root_Mean_Square_Error(observed, simulated):
321
+ """
322
+ Calculate the Root Mean Square Error (RMSE) between observed and simulated data.
323
+
324
+ :param observed: Array-like structure containing observed data values.
325
+ :param simulated: Array-like structure containing simulated data values.
326
+ :raises ValueError: If the lengths of observed and simulated data do not match.
327
+ :return: The RMSE value.
328
+ """
329
+
330
+ if isinstance(observed, pd.Series):
331
+ observed = observed.values
332
+
333
+ if isinstance(simulated, pd.Series):
334
+ simulated = simulated.values
335
+
336
+ if len(observed) != len(simulated):
337
+ raise ValueError("Observed and simulated data must have the same length.")
338
+
339
+ # Convert to numpy arrays for calculations
340
+ observed = np.array(observed)
341
+ simulated = np.array(simulated)
342
+
343
+ # Calculate RMSE
344
+ rmse = np.sqrt(np.mean((observed - simulated) ** 2))
345
+
346
+ return rmse
347
+
348
+ def Mean_Absolute_Error(observed, simulated):
349
+ """
350
+ Calculate the Mean Absolute Error (MAE) between observed and simulated data.
351
+
352
+ :param observed: Array-like structure containing observed data values.
353
+ :param simulated: Array-like structure containing simulated data values.
354
+ :raises ValueError: If the lengths of observed and simulated data do not match.
355
+ :return: The MAE value.
356
+ """
357
+
358
+ if isinstance(observed, pd.Series):
359
+ observed = observed.values
360
+
361
+ if isinstance(simulated, pd.Series):
362
+ simulated = simulated.values
363
+
364
+ if len(observed) != len(simulated):
365
+ raise ValueError("Observed and simulated data must have the same length.")
366
+
367
+ # Convert to numpy arrays for calculations
368
+ observed = np.array(observed)
369
+ simulated = np.array(simulated)
370
+
371
+ # Calculate MAE
372
+ mae = np.mean(np.abs(observed - simulated))
373
+
374
+ return mae
375
+
376
+ def Mean_Absolute_Percentage_Error(observed, simulated):
377
+ """
378
+ Calculate the Mean Absolute Percentage Error (MAPE) between observed and simulated data.
379
+
380
+ :param observed: Array-like structure containing observed data values.
381
+ :param simulated: Array-like structure containing simulated data values.
382
+ :raises ValueError: If the lengths of observed and simulated data do not match.
383
+ :return: The MAPE value.
384
+ """
385
+
386
+ if isinstance(observed, pd.Series):
387
+ observed = observed.values
388
+
389
+ if isinstance(simulated, pd.Series):
390
+ simulated = simulated.values
391
+
392
+ if len(observed) != len(simulated):
393
+ raise ValueError("Observed and simulated data must have the same length.")
394
+
395
+ # Convert to numpy arrays for calculations
396
+ observed = np.array(observed)
397
+ simulated = np.array(simulated)
398
+
399
+ # Calculate MAPE
400
+ mape = np.mean(np.abs((observed - simulated) / observed)) * 100
401
+
402
+ return mape
403
+
404
+ def Pearson_Correlation_Coefficient(observed, simulated):
405
+ """
406
+ Calculate the Pearson correlation coefficient between observed and simulated data.
407
+
408
+ :param observed: Array-like structure containing observed data values.
409
+ :param simulated: Array-like structure containing simulated data values.
410
+ :raises ValueError: If the lengths of observed and simulated data do not match.
411
+ :return: The Pearson correlation coefficient.
412
+ """
413
+
414
+ if isinstance(observed, pd.Series):
415
+ observed = observed.values
416
+
417
+ if isinstance(simulated, pd.Series):
418
+ simulated = simulated.values
419
+
420
+ if len(observed) != len(simulated):
421
+ raise ValueError("Observed and simulated data must have the same length.")
422
+
423
+ # Convert to numpy arrays for calculations
424
+ observed = np.array(observed)
425
+ simulated = np.array(simulated)
426
+
427
+ # Calculate Pearson correlation coefficient
428
+ r = np.corrcoef(observed, simulated)[0, 1]
429
+
430
+ return r
431
+
432
+ def Spearman_Rank_Correlation_Coefficient(observed, simulated):
433
+ """
434
+ Calculate the Spearman rank correlation coefficient between observed and simulated data.
435
+
436
+ :param observed: Array-like structure containing observed data values.
437
+ :param simulated: Array-like structure containing simulated data values.
438
+ :raises ValueError: If the lengths of observed and simulated data do not match.
439
+ :return: The Spearman rank correlation coefficient.
440
+ """
441
+
442
+ if isinstance(observed, pd.Series):
443
+ observed = observed.values
444
+
445
+ if isinstance(simulated, pd.Series):
446
+ simulated = simulated.values
447
+
448
+ if len(observed) != len(simulated):
449
+ raise ValueError("Observed and simulated data must have the same length.")
450
+
451
+ # Convert to numpy arrays for calculations
452
+ observed = np.array(observed)
453
+ simulated = np.array(simulated)
454
+
455
+ # Calculate Spearman rank correlation coefficient
456
+ from scipy.stats import spearmanr
457
+ r, _ = spearmanr(observed, simulated)
458
+
459
+ return r
460
+
461
+ def normalize_series(series):
462
+ """
463
+ Normalize a time series to the range [0, 1].
464
+
465
+ :param series: Array-like structure containing the time series data.
466
+ :return: Normalized time series as a numpy array.
467
+ """
468
+ if isinstance(series, pd.Series):
469
+ series = series.values
470
+
471
+ series = np.array(series)
472
+ min_val = np.min(series)
473
+ max_val = np.max(series)
474
+
475
+ if max_val - min_val == 0:
476
+ return np.zeros_like(series) # Avoid division by zero
477
+
478
+ normalized_series = (series - min_val) / (max_val - min_val)
479
+
480
+ return normalized_series
wolfhece/drawing_obj.py CHANGED
@@ -41,7 +41,11 @@ class Element_To_Draw:
41
41
  self.mapviewer = mapviewer # WolfMapViewer instance attached to the object
42
42
  self.wx_exists = App.Get() is not None # test if wx App is running
43
43
 
44
+ # *********************************
45
+ # For specific objects
44
46
  self._filename_vector:str = ''
47
+ self._filename_points:str = ''
48
+ # *********************************
45
49
 
46
50
  if need_for_wx and (not self.wx_exists):
47
51
  raise NameError(_('wx App is not running or you need it --> check your code and retry !'))
@@ -134,4 +138,11 @@ class Element_To_Draw:
134
138
  if self.mapviewer is None:
135
139
  return False
136
140
 
137
- return self.mapviewer.SetCurrentContext()
141
+ return self.mapviewer.SetCurrentContext()
142
+
143
+ def reset_listogl(self):
144
+ """
145
+ Reset the OpenGL list of the object
146
+ """
147
+
148
+ pass