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,1028 @@
1
+ import numpy as np
2
+ from scipy.ndimage import zoom
3
+ import rasterio
4
+
5
+
6
+ # Convert coordinates to mesh matrix row-col (from smash)
7
+ def xy_to_rowcol(x, y, xmin, ymax, xres, yres):
8
+ row = int((ymax - y) / yres)
9
+ col = int((x - xmin) / xres)
10
+ return row, col
11
+
12
+
13
+ # Convert mesh matrix row-col to geographic coordinates (from smash)
14
+ def rowcol_to_xy(row, col, xmin, ymax, xres, yres):
15
+ x = int(col * xres + xmin)
16
+ y = int(ymax - row * yres)
17
+ return x, y
18
+
19
+
20
+ def get_bbox_from_smash_mesh(mesh):
21
+ """
22
+ Description
23
+ -----------
24
+ Compute the bbox from a Smash mesh dictionary
25
+ Parameters
26
+ ----------
27
+ mesh: dict
28
+ dict of smash mesh
29
+ return
30
+ ------
31
+ dict()
32
+ the bounding box of the smash mesh
33
+ """
34
+
35
+ if "xres" in mesh and "yres" in mesh:
36
+ dx = mesh["xres"]
37
+ dy = mesh["yres"]
38
+ else:
39
+ dx = np.mean(mesh["dx"])
40
+ dy = np.mean(mesh["dy"])
41
+
42
+ if "ncol" in mesh:
43
+ ncol = mesh["ncol"]
44
+ nrow = mesh["nrow"]
45
+ else:
46
+ nrow = mesh["active_cell"].shape[0]
47
+ ncol = mesh["active_cell"].shape[1]
48
+
49
+ left = mesh["xmin"]
50
+ right = mesh["xmin"] + ncol * dx
51
+ bottom = mesh["ymax"] - nrow * dy
52
+ top = mesh["ymax"]
53
+ bbox = {"left": left, "bottom": bottom, "right": right, "top": top}
54
+
55
+ return bbox
56
+
57
+
58
+ def get_bbox_from_ascii_data(ascii_data):
59
+ """
60
+
61
+ Description
62
+ -----------
63
+
64
+ Compute the boundingbox from ascii-data stored in a dictionnary (must contain the header)
65
+
66
+ Parameters
67
+ ----------
68
+
69
+ ascii_data: dict()
70
+ Un dictionnaire contenant un format ascii: {ascii_data,xllcorner,yllcorner,ncol,nrows,cellsize}, la clé ascii_data contient un sous dictionnaire contenant des clés associés a des sources de données {clé:numpy_array}
71
+
72
+ return
73
+ ------
74
+
75
+ dict()
76
+ Un dictionnaire contenant la boundingbox (coordonnées): {left, bottom, right, top}
77
+
78
+ """
79
+ ascii_data_l = {}
80
+ for key, value in ascii_data.items():
81
+ ascii_data_l.update({key.lower(): value})
82
+
83
+ bbox = {
84
+ "left": ascii_data_l["xllcorner"],
85
+ "bottom": ascii_data_l["yllcorner"],
86
+ "right": ascii_data_l["xllcorner"]
87
+ + ascii_data_l["ncols"] * ascii_data_l["cellsize"],
88
+ "top": ascii_data_l["yllcorner"]
89
+ + ascii_data_l["nrows"] * ascii_data_l["cellsize"],
90
+ }
91
+
92
+ return bbox
93
+
94
+
95
+ def check_bbox_consistency(bbox_model_active_cell, bbox_param):
96
+
97
+ if bbox_model_active_cell["left"] < bbox_param["left"]:
98
+ print(
99
+ f"Warning: Model domain is larger than the domain of the parameter. {bbox_model_active_cell['left']}<{bbox_param['left']} (bbox model left < bbox param left). Expect lacuna (-99.) in model parameters"
100
+ )
101
+
102
+ if bbox_model_active_cell["right"] > bbox_param["right"]:
103
+ print(
104
+ f"Warning: Model domain is larger than the domain of the parameter. {bbox_model_active_cell['right']}>{bbox_param['right']} (bbox model left < bbox param left). Expect lacuna (-99.) in model parameters"
105
+ )
106
+
107
+ if bbox_model_active_cell["bottom"] < bbox_param["bottom"]:
108
+ print(
109
+ f"Warning: Model domain is larger than the domain of the parameter. {bbox_model_active_cell['bottom']}<{bbox_param['bottom']} (bbox model left < bbox param left). Expect lacuna (-99.) in model parameters"
110
+ )
111
+
112
+ if bbox_model_active_cell["top"] < bbox_param["top"]:
113
+ print(
114
+ f"Warning: Model domain is larger than the domain of the parameter. {bbox_model_active_cell['top']}>{bbox_param['top']} (bbox model left < bbox param left). Expect lacuna (-99.) in model parameters"
115
+ )
116
+
117
+
118
+ def intersection_bbox(bbox1, bbox2):
119
+ """
120
+
121
+ Description
122
+ -----------
123
+
124
+ Function which compute the bounding boxes intersection of 2 input bbox. It return the working bbox
125
+
126
+ Parameters
127
+ ----------
128
+
129
+ bbox1: dict()
130
+ containing the first bbox informations
131
+ bbox2 : dict()
132
+ containing the second bbox informations
133
+
134
+ returns
135
+ ----------
136
+
137
+ dict()
138
+ containing the bbox union
139
+
140
+ Examples
141
+ ----------
142
+
143
+ dataset=gdal_raster_open(filename)
144
+ possible_bbox=intersection_bbox(bbox,bbox_dataset)
145
+
146
+ """
147
+ left = max(bbox1["left"], bbox2["left"])
148
+ bottom = max(bbox1["bottom"], bbox2["bottom"])
149
+ right = min(bbox1["right"], bbox2["right"])
150
+ top = min(bbox1["top"], bbox2["top"])
151
+ if (left < right) and (bottom < top):
152
+ bbox_intersection = {"left": left, "bottom": bottom, "right": right, "top": top}
153
+ return bbox_intersection
154
+ else:
155
+ print("Impossible bounding boxes intersection")
156
+ return {"left": 0, "bottom": 0, "right": 0, "top": 0}
157
+
158
+
159
+ def get_window_from_bbox(mesh, bbox):
160
+ """
161
+ Function to get the mesh window from a defined bbox
162
+
163
+ Parameters
164
+ ----------
165
+ dataset: gdal object
166
+ bbox : dict containing the bbox
167
+ ----------
168
+ returns
169
+ dic containing the computed windows
170
+
171
+ Examples
172
+ ----------
173
+ dataset=gdal_raster_open(filename)
174
+ bbox_dataset=get_bbox(dataset)
175
+ window=get_window_from_bbox(dataset,bbox_dataset)
176
+
177
+ """
178
+
179
+ if "xres" in mesh and "yres" in mesh:
180
+ dx = mesh["xres"]
181
+ dy = mesh["yres"]
182
+ else:
183
+ dx = np.mean(mesh["dx"])
184
+ dy = np.mean(mesh["dy"])
185
+
186
+ col_off = (bbox["left"] - mesh["xmin"]) / dx
187
+ row_off = (mesh["ymax"] - bbox["top"]) / dy
188
+ ncols = (bbox["right"] - bbox["left"]) / dx
189
+ nrows = (bbox["top"] - bbox["bottom"]) / dy
190
+
191
+ if (col_off < 0) or (row_off < 0):
192
+ raise Exception(
193
+ "The requested bounding box exceeds the limits of the raster domain."
194
+ )
195
+
196
+ window = {
197
+ "row_off": int(row_off),
198
+ "col_off": int(col_off),
199
+ "nrows": int(nrows),
200
+ "ncols": int(ncols),
201
+ }
202
+
203
+ return window
204
+
205
+
206
+ def get_cropped_window_from_bbox_intersection(bbox_intersection, bbox_origin, dx, dy):
207
+ """
208
+
209
+ Description
210
+ -----------
211
+
212
+ Function to compute the domain to crop between a bbox intersection (included into bbox_origin) and the origin bbox. This function return a window such as the domain with bbox_intersection can be cropped using the retruned window according the bbox_origin
213
+
214
+ Parameters
215
+ ----------
216
+
217
+ bbox_intersection: dict
218
+ A bbox that intersect bbox_origin
219
+
220
+ bbox_origin: dict
221
+ a bbox from which we want to extract data
222
+
223
+ dx: float
224
+ size of the grid in the x direction
225
+
226
+ dy: float
227
+ size of the grid in the y direction
228
+
229
+ Return
230
+ ------
231
+
232
+ dict()
233
+ a window dictionnary containing information to crop a matrix: {row_off, col_off, nrows, ncols}
234
+
235
+
236
+ """
237
+ if (
238
+ (bbox_intersection["left"] < bbox_origin["left"])
239
+ or (bbox_intersection["bottom"] < bbox_origin["bottom"])
240
+ or (bbox_intersection["right"] > bbox_origin["right"])
241
+ or (bbox_intersection["top"] > bbox_origin["top"])
242
+ ):
243
+ print("The domain of bbox_intersection is not included in the domain of bbox_out")
244
+ window = {"row_off": 0, "col_off": 0, "nrows": 0, "ncols": 0}
245
+ return window
246
+
247
+ col_off = (bbox_intersection["left"] - bbox_origin["left"]) / dx
248
+ row_off = (bbox_origin["top"] - bbox_intersection["top"]) / dy
249
+
250
+ ncols = (bbox_intersection["right"] - bbox_intersection["left"]) / dx
251
+ nrows = (bbox_intersection["top"] - bbox_intersection["bottom"]) / dy
252
+
253
+ window = {
254
+ "row_off": int(row_off),
255
+ "col_off": int(col_off),
256
+ "nrows": int(nrows),
257
+ "ncols": int(ncols),
258
+ }
259
+
260
+ return window
261
+
262
+
263
+ def write_array_to_geotiff(filename, array, xmin, ymax, xres, yres):
264
+
265
+ metadata = {
266
+ "driver": "GTiff",
267
+ "dtype": "float64",
268
+ "nodata": None,
269
+ "width": array.shape[1],
270
+ "height": array.shape[0],
271
+ "count": 1,
272
+ "crs": None,
273
+ "transform": rasterio.Affine(xres, 0.0, xmin, 0.0, -yres, ymax),
274
+ }
275
+
276
+ rasterio_write_tiff(filename=filename, matrix=array, metadata=metadata)
277
+
278
+
279
+ def rasterio_write_tiff(filename="test.tif", matrix=np.zeros(10), metadata={}):
280
+
281
+ with rasterio.Env():
282
+ with rasterio.open(filename, "w", compress="lzw", **metadata) as dst:
283
+ dst.write(matrix, 1)
284
+
285
+
286
+ def crop_array(
287
+ array,
288
+ bbox_in,
289
+ res_in,
290
+ bbox_out,
291
+ res_out,
292
+ order=0,
293
+ cval=-99.0,
294
+ grid_mode=True,
295
+ ):
296
+ """
297
+
298
+ Description
299
+ --------------
300
+
301
+ Crop a part of a numpy array with an input bbox and resolution to a new bbox with a new resolution
302
+
303
+ Parameters
304
+ ----------
305
+
306
+ array : numpy.array()
307
+ Input gridded numpy array shape=(n,m)
308
+
309
+ bbox_in : dict()
310
+ bounding box of the input array. Dictionnary {"left":,"top":,"right":,"bottom":}
311
+
312
+ res_in : dict()
313
+ resolution of the input array in x and y direction. Disctionnary {"dx":, "dy":}
314
+
315
+ bbox_out : dict()
316
+ bounding box of the output array. Dictionnary {"left":,"top":,"right":,"bottom":}
317
+
318
+ res_out : dict()
319
+ resolution of the output array in x and y direction. Disctionnary {"dx":, "dy":}
320
+
321
+ order : int()
322
+ order of the resampling cubic interpolation
323
+
324
+ cval : float() | np.nan
325
+ fill value for the extended boundaries
326
+
327
+ grid_mode : bool()
328
+ True | False. if True coordinate start from the edge of the cell. If False coordinate starts from the center of the cell.
329
+
330
+ Return
331
+ ------
332
+
333
+ numpy.array()
334
+ Cropped and resampled array according bbox_out and res_out
335
+
336
+ """
337
+
338
+ # intersection bbox
339
+ bbox_intersection = intersection_bbox(bbox_in, bbox_out)
340
+
341
+ # ---------------------- fait une découpe grossière du domaine -------
342
+
343
+ # 1- crop array on bbox_intersection+-res_in at res in: shrink the domain, speed up futur resampling on large domain ?
344
+ if res_in["dx"] >= res_out["dx"] and res_in["dy"] >= res_out["dy"]:
345
+ res_shrinked = {"dx": res_in["dx"], "dy": res_in["dy"]}
346
+ elif res_in["dx"] < res_out["dx"] and res_in["dy"] < res_out["dy"]:
347
+ res_shrinked = {"dx": res_out["dy"], "dy": res_out["dy"]}
348
+ elif res_in["dx"] < res_out["dx"] and res_in["dy"] >= res_out["dy"]:
349
+ res_shrinked = {"dx": res_out["dx"], "dy": res_in["dy"]}
350
+ elif res_in["dx"] >= res_out["dx"] and res_in["dy"] < res_out["dy"]:
351
+ res_shrinked = {"dx": res_in["dx"], "dy": res_out["dy"]}
352
+
353
+ bbox_in_shrinked = {
354
+ "left": bbox_in["left"]
355
+ + int(max(bbox_intersection["left"] - bbox_in["left"], 0) / res_shrinked["dx"])
356
+ * res_shrinked["dx"],
357
+ "right": bbox_in["right"]
358
+ - int(max(bbox_in["right"] - bbox_intersection["right"], 0) / res_shrinked["dx"])
359
+ * res_shrinked["dx"],
360
+ "bottom": bbox_in["bottom"]
361
+ + int(
362
+ max(bbox_intersection["bottom"] - bbox_in["bottom"], 0) / res_shrinked["dy"]
363
+ )
364
+ * res_shrinked["dy"],
365
+ "top": bbox_in["top"]
366
+ - int(max(bbox_in["top"] - bbox_intersection["top"], 0) / res_shrinked["dy"])
367
+ * res_shrinked["dy"],
368
+ }
369
+ bbox_intersection_shrinked = intersection_bbox(bbox_in, bbox_in_shrinked)
370
+
371
+ windows_wrap = get_window_from_bbox(
372
+ mesh={
373
+ "xmin": bbox_in["left"],
374
+ "ymax": bbox_in["top"],
375
+ "xres": res_shrinked["dx"],
376
+ "yres": res_shrinked["dy"],
377
+ },
378
+ bbox=bbox_intersection_shrinked,
379
+ )
380
+
381
+ # Erase input array and bbox_in
382
+ array = array[
383
+ windows_wrap["row_off"] : windows_wrap["row_off"] + windows_wrap["nrows"],
384
+ windows_wrap["col_off"] : windows_wrap["col_off"] + windows_wrap["ncols"],
385
+ ]
386
+
387
+ bbox_in = bbox_intersection_shrinked
388
+
389
+ # ---------------------------------------------------------------------------------------
390
+
391
+ # 2- resample the array to res_out
392
+ resampled_array = resample_array(
393
+ array,
394
+ res_in=res_in,
395
+ res_out=res_out,
396
+ order=order,
397
+ cval=cval,
398
+ grid_mode=grid_mode,
399
+ )
400
+
401
+ # 3- crop the array on the intersection of bbox_in and bbox_out
402
+ # window of bbox_intersection in the domain of bbox_in (bbox_prcp, matrix to read)
403
+ window_intersection = get_cropped_window_from_bbox_intersection(
404
+ bbox_intersection, bbox_in, res_out["dx"], res_out["dy"]
405
+ )
406
+
407
+ # reading the part of the matrix (array_in)
408
+ cropped_array = resampled_array[
409
+ window_intersection["row_off"] : window_intersection["row_off"]
410
+ + window_intersection["nrows"],
411
+ window_intersection["col_off"] : window_intersection["col_off"]
412
+ + window_intersection["ncols"],
413
+ ]
414
+
415
+ # allocate out array: shape of bbox_out
416
+ array_out = (
417
+ np.zeros(
418
+ shape=(
419
+ int((bbox_out["top"] - bbox_out["bottom"]) / res_out["dx"]),
420
+ int((bbox_out["right"] - bbox_out["left"]) / res_out["dy"]),
421
+ )
422
+ )
423
+ - 99.0
424
+ )
425
+
426
+ # window of bbox_intersection in the domain of bbox_smash
427
+ window_intersection_out = get_cropped_window_from_bbox_intersection(
428
+ bbox_intersection, bbox_out, res_out["dx"], res_out["dy"]
429
+ )
430
+
431
+ # copy crop_array (input matrix cropped) in array_out
432
+ array_out[
433
+ window_intersection_out["row_off"] : window_intersection_out["row_off"]
434
+ + window_intersection_out["nrows"],
435
+ window_intersection_out["col_off"] : window_intersection_out["col_off"]
436
+ + window_intersection_out["ncols"],
437
+ ] = cropped_array
438
+
439
+ return array_out
440
+
441
+
442
+ def resample_array(
443
+ array,
444
+ res_in={"dx": 1, "dy": 1},
445
+ res_out={"dx": 1, "dy": 1},
446
+ order=0,
447
+ cval=-99.0,
448
+ grid_mode=True,
449
+ ):
450
+ """
451
+
452
+ Parameters
453
+ ----------
454
+
455
+ array: numpy.array()
456
+ Input gridded numpy array shape=(n,m)
457
+
458
+ res_in: dict()
459
+ resolution of the input array in x and y direction. Disctionnary {"dx":, "dy":}
460
+
461
+ res_out: dict()
462
+ resolution of the output array in x and y direction. Disctionnary {"dx":, "dy":}
463
+
464
+ order: int()
465
+ order of the resampling cubic interpolation
466
+
467
+ cval: float() | np.nan
468
+ fill value for the extended boundaries
469
+
470
+ grid_mode: bool()
471
+ True | False. if True coordinate start from the edge of the cell. If False coordinate starts from the center of the cell.
472
+
473
+ Return
474
+ ------
475
+
476
+ numpy.array()
477
+ Cropped and resampled array according bbox_out and res_out
478
+
479
+ """
480
+
481
+ ratio_x = res_in["dx"] / res_out["dx"]
482
+ ratio_y = res_in["dy"] / res_out["dy"]
483
+ resampled_array = zoom(
484
+ array,
485
+ (ratio_y, ratio_x),
486
+ order=order,
487
+ mode="grid-constant",
488
+ cval=-99.0,
489
+ grid_mode=True,
490
+ )
491
+
492
+ return resampled_array
493
+
494
+
495
+ # def read_geotiff_to_ascii(path=""):
496
+
497
+ # if not os.path.exists(path):
498
+ # raise ValueError(f"{path} does not exist.")
499
+
500
+ # with rasterio.open(path) as ds:
501
+ # transform = ds.get_transform()
502
+ # xmin = transform[0]
503
+ # ymax = transform[3]
504
+ # xres = transform[1]
505
+ # yres = -transform[5]
506
+
507
+ # ascii_data = {
508
+ # "ncols": ds.width,
509
+ # "nrows": ds.height,
510
+ # "cellsize": xres,
511
+ # "xllcorner": xmin,
512
+ # "yllcorner": ymax - ds.height * yres,
513
+ # "nodata_value": ds.nodata,
514
+ # "data": ds.read(indexes=1),
515
+ # }
516
+
517
+ # return ascii_data
518
+
519
+
520
+ # def write_smashparam_to_geotiff(model, path):
521
+
522
+ # if not os.path.exists(path):
523
+ # os.mkdir(path)
524
+
525
+ # list_param = list(model.rr_parameters.keys)
526
+
527
+ # for param in list_param:
528
+
529
+ # array = model.rr_parameters.values[:, :, list_param.index(param)]
530
+
531
+ # write_array_to_geotiff(
532
+ # os.path.join(path, param + ".tif"),
533
+ # array,
534
+ # model.mesh.xmin,
535
+ # model.mesh.ymax,
536
+ # model.mesh.xres,
537
+ # model.mesh.yres,
538
+ # )
539
+
540
+
541
+ # # format standart smashop ?
542
+ # # faire une fonction qui extrait des params depuis smash vers un dict_ascii_format ?
543
+ # def load_param_from_tiffformat(
544
+ # model=None, path_to_parameters="", bounding_condition=False
545
+ # ):
546
+
547
+ # # check metadata first
548
+
549
+ # list_param = model.rr_parameters.keys
550
+
551
+ # mesh_out = object_handler.read_object_as_dict(model.mesh)
552
+
553
+ # bbox_out = get_bbox_from_smash_mesh(mesh_out)
554
+ # res_out = {"dx": np.mean(mesh_out["dx"]), "dy": np.mean(mesh_out["dy"])}
555
+
556
+ # for param in list_param:
557
+
558
+ # if os.path.exists(os.path.join(path_to_parameters, param + ".tif")):
559
+
560
+ # ascii_data = read_geotiff_to_ascii(
561
+ # os.path.join(path_to_parameters, param + ".tif")
562
+ # )
563
+
564
+ # bbox_in = get_bbox_from_ascii_data(ascii_data)
565
+
566
+ # check_bbox_consistency(bbox_out, bbox_in)
567
+
568
+ # res_in = {"dx": ascii_data["cellsize"], "dy": ascii_data["cellsize"]}
569
+
570
+ # print(f"</> In read_param_from_asciiformat, reading param {param}")
571
+
572
+ # cropped_param = crop_array(
573
+ # ascii_data["data"],
574
+ # bbox_in,
575
+ # res_in,
576
+ # bbox_out,
577
+ # res_out,
578
+ # resampling_method="scipy-zoom",
579
+ # order=0,
580
+ # cval=-99.0,
581
+ # grid_mode=True,
582
+ # )
583
+
584
+ # pos = np.where(list_param == param)[0][0]
585
+ # model.rr_parameters.values[:, :, pos] = cropped_param
586
+
587
+ # print("</> Removing values lower than 0")
588
+ # model.rr_parameters.values[:, :, pos] = np.where(
589
+ # model.rr_parameters.values[:, :, pos] < 0,
590
+ # 0,
591
+ # model.rr_parameters.values[:, :, pos],
592
+ # )
593
+
594
+ # else:
595
+
596
+ # print(
597
+ # f"</> Error: in load_param_from_tiffformat, missing parameter {param} in {path_to_parameters}"
598
+ # )
599
+
600
+
601
+ # # format standart smashop ?
602
+ # # faire une fonction qui extrait des params depuis smash vers un dict_ascii_format ?
603
+ # def load_param_from_asciiformat(model, dict_ascii_parameters, bounding_condition=False):
604
+
605
+ # list_param = model.rr_parameters.keys
606
+
607
+ # mesh_out = object_handler.read_object_as_dict(model.mesh)
608
+
609
+ # bbox_in = get_bbox_from_ascii_data(dict_ascii_parameters)
610
+ # res_in = {
611
+ # "dx": dict_ascii_parameters["cellsize"],
612
+ # "dy": dict_ascii_parameters["cellsize"],
613
+ # }
614
+
615
+ # bbox_out = get_bbox_from_smash_mesh(mesh_out)
616
+ # res_out = {"dx": np.mean(mesh_out["dx"]), "dy": np.mean(mesh_out["dy"])}
617
+
618
+ # check_bbox_consistency(bbox_out, bbox_in)
619
+
620
+ # for param in list_param:
621
+
622
+ # if param in dict_ascii_parameters["ascii_data"].keys():
623
+
624
+ # print(f"</> In read_param_from_asciiformat, reading param {param}")
625
+
626
+ # cropped_param = crop_array(
627
+ # param,
628
+ # bbox_in,
629
+ # res_in,
630
+ # bbox_out,
631
+ # res_out,
632
+ # resampling_method="scipy-zoom",
633
+ # order=0,
634
+ # cval=-99.0,
635
+ # grid_mode=True,
636
+ # )
637
+
638
+ # pos = np.where(list_param == param)[0][0]
639
+ # model.rr_parameters.values[:, :, pos] = cropped_param
640
+ # else:
641
+ # print(
642
+ # f"</> In read_param_from_asciiformat, skipping missing parameter {param}"
643
+ # )
644
+
645
+
646
+ # def transfert_params_to_model(
647
+ # from_mesh=dict(), with_param=(dict | object), to_model=None
648
+ # ):
649
+
650
+ # if isinstance(with_param, dict):
651
+ # pass
652
+ # else:
653
+ # with_param = object_handler.read_object_as_dict(with_param)
654
+
655
+ # structure = to_model.setup.structure
656
+ # structure_parameters = smash._constant.STRUCTURE_RR_PARAMETERS.copy()
657
+ # # copy() obligatoire car la liste contenu dans la copie du dictionnaire n'est pas une copy mais un pointeur ...
658
+ # parameters_list = structure_parameters[structure].copy()
659
+
660
+ # mesh_out = object_handler.read_object_as_dict(to_model.mesh)
661
+
662
+ # bbox_in = get_bbox_from_smash_mesh(from_mesh)
663
+
664
+ # if "xres" in from_mesh and "yres" in from_mesh:
665
+ # dx = from_mesh["xres"]
666
+ # dy = from_mesh["yres"]
667
+ # else:
668
+ # dx = np.mean(from_mesh["dx"])
669
+ # dy = np.mean(from_mesh["dy"])
670
+
671
+ # res_in = {
672
+ # "dx": dx,
673
+ # "dy": dy,
674
+ # }
675
+
676
+ # bbox_out = get_bbox_from_smash_mesh(mesh_out)
677
+
678
+ # if "xres" in mesh_out and "yres" in mesh_out:
679
+ # dx = mesh_out["xres"]
680
+ # dy = mesh_out["yres"]
681
+ # else:
682
+ # dx = np.mean(mesh_out["dx"])
683
+ # dy = np.mean(mesh_out["dy"])
684
+
685
+ # res_out = {
686
+ # "dx": dx,
687
+ # "dy": dy,
688
+ # }
689
+
690
+ # for i in range(len(parameters_list)):
691
+
692
+ # if "values" in with_param:
693
+ # param = with_param["values"][:, :, i]
694
+ # pos = i
695
+ # else:
696
+ # param = with_param[parameters_list[i]]
697
+ # pos = np.where(to_model.rr_parameters.keys == parameters_list[i])[0][0]
698
+
699
+ # cropped_param = crop_array(
700
+ # param,
701
+ # bbox_in,
702
+ # res_in,
703
+ # bbox_out,
704
+ # res_out,
705
+ # resampling_method="scipy-zoom",
706
+ # order=0,
707
+ # cval=-99.0,
708
+ # grid_mode=True,
709
+ # )
710
+
711
+ # to_model.rr_parameters.values[:, :, pos] = cropped_param
712
+
713
+
714
+ # def resample_array(
715
+ # array,
716
+ # res_in={"dx": 1, "dy": 1},
717
+ # res_out={"dx": 1, "dy": 1},
718
+ # # resampling_method="scipy-zoom",
719
+ # order=3,
720
+ # cval=-99.0,
721
+ # grid_mode=True,
722
+ # ):
723
+ # """
724
+
725
+ # Description
726
+ # -----------
727
+
728
+ # Resample an array with input resolution to the output resolution. It use zoom function form scipy package.
729
+
730
+ # Parameters
731
+ # ----------
732
+
733
+ # array: numpy.array()
734
+ # Input gridded numpy array shape=(n,m)
735
+
736
+ # res_in: dict()
737
+ # resolution of the input array in x and y direction. Disctionnary {"dx":, "dy":}
738
+
739
+ # res_out: dict()
740
+ # resolution of the output array in x and y direction. Disctionnary {"dx":, "dy":}
741
+
742
+ # resampling_method: str()
743
+ # scipy-zoom | numpy ; scipy-zoom use the zoom function from scipy (see function resample_array_scipy_zoom for other input arg). numpy only resample using basic function np.repeat ans basic calculation (not suitable for every case).
744
+
745
+ # Return
746
+ # ------
747
+
748
+ # numpy.array()
749
+ # Resampled array according res_out
750
+
751
+ # """
752
+ # if resampling_method == "numpy":
753
+ # resampled_array = resample_array_numpy(array, res_in=res_in, res_out=res_out)
754
+
755
+ # if resampled_array is None:
756
+ # print("</>Fallback to scipy-zoom resampling (scipy.ndimage.zoom method)")
757
+ # resampling_method = "scipy-zoom"
758
+
759
+ # if resampling_method == "scipy-zoom":
760
+ # resampled_array = resample_array_scipy_zoom(
761
+ # array, res_in, res_out, order=0, cval=-99.0, grid_mode=True
762
+ # )
763
+
764
+ # return resampled_array
765
+
766
+
767
+ # def resample_array_numpy(array, res_in={"dx": 1, "dy": 1}, res_out={"dx": 1, "dy": 1}):
768
+ # """
769
+
770
+ # Description
771
+ # -----------
772
+
773
+ # resample an array with input resolution to the output resolution. It simpy use numpy functions.
774
+
775
+ # Parameters
776
+ # ----------
777
+
778
+ # array: numpy.array()
779
+ # Input gridded numpy array shape=(n,m)
780
+
781
+ # res_in: dict()
782
+ # resolution of the input array in x and y direction. Disctionnary {"dx":, "dy":}
783
+
784
+ # res_out: dict()
785
+ # resolution of the output array in x and y direction. Disctionnary {"dx":, "dy":}
786
+
787
+ # Return
788
+ # ------
789
+
790
+ # numpy.array()
791
+ # Resampled array according res_out
792
+
793
+ # """
794
+ # # 1Resampling
795
+ # if (res_in["dx"] >= res_out["dx"]) and (res_in["dy"] >= res_out["dy"]):
796
+ # ratio_x = int(res_in["dx"] / res_out["dx"])
797
+ # ratio_y = int(res_in["dy"] / res_out["dy"])
798
+ # # resampling input matrix to dx,dy smash si résolution demandée est inférieur
799
+ # resampled_array = np.repeat(np.repeat(array, ratio_x, axis=0), ratio_y, axis=1)
800
+
801
+ # elif (res_in["dx"] < res_out["dx"]) and (res_in["dy"] < res_out["dy"]):
802
+
803
+ # ratio_x = int(res_out["dx"] / res_in["dx"])
804
+ # ratio_y = int(res_out["dy"] / res_in["dy"])
805
+ # # resampling input matrix si résolution demandée est supérieur:
806
+ # xsize = int(np.ceil(array.shape[0] / ratio_x))
807
+ # ysize = int(np.ceil(array.shape[1] / ratio_y))
808
+ # resampled_array = np.full(shape=(xsize, ysize), fill_value=0)
809
+
810
+ # xr = 0
811
+ # for x in range(0, xsize):
812
+ # yr = 0
813
+ # for y in range(0, ysize):
814
+ # buffer = array[xr : xr + ratio_x, yr : yr + ratio_y]
815
+ # average = np.mean(buffer, axis=(0, 1))
816
+ # resampled_array[x, y, :] = average
817
+ # yr = yr + ratio_y
818
+ # xr = xr + ratio_x
819
+ # else:
820
+ # print(
821
+ # "</> average resampling method impossible, different resampling resolution in x and y axis."
822
+ # )
823
+ # return None
824
+
825
+ # return resampled_array
826
+
827
+
828
+ # def import_parameters(model: Model, path_to_parameters: FilePath):
829
+ # """
830
+ # Description
831
+ # -----------
832
+ # Read a geotif, resample if necessarry then clip it on the bouning box of the smash mesh
833
+
834
+ # Parameters
835
+ # ----------
836
+ # model: object
837
+ # SMASH model object
838
+ # path_to_parameters: str
839
+ # Path to the directory which contain the geotiff files (parameters)
840
+
841
+ # return
842
+ # ------
843
+ # np.ndarray
844
+ # The data clipped on the SMASH bounding box
845
+ # """
846
+ # list_param = model.rr_parameters.keys
847
+
848
+ # for param in list_param:
849
+ # if os.path.exists(os.path.join(path_to_parameters, param + ".tif")):
850
+ # cropped_param = _rasterio_read_param2(
851
+ # path=os.path.join(path_to_parameters, param + ".tif"), mesh=model.mesh
852
+ # )
853
+
854
+ # pos = np.argwhere(list_param == param).item()
855
+ # model.rr_parameters.values[:, :, pos] = cropped_param
856
+
857
+ # else:
858
+ # raise ValueError(f"Missing parameter {param} in {path_to_parameters}")
859
+
860
+
861
+ # def _rasterio_read_param(path: FilePath, mesh: MeshDT):
862
+ # """
863
+ # Description
864
+ # -----------
865
+ # Read a geotif, resample if necessarry then clip it on the bouning box of the smash mesh
866
+
867
+ # Parameters
868
+ # ----------
869
+ # path: str
870
+ # Path to a geotiff file.
871
+ # mesh: object
872
+ # object of the smash mesh
873
+
874
+ # return
875
+ # ------
876
+ # np.ndarray
877
+ # The data clipped on the SMASH bounding box
878
+ # """
879
+ # bounds = get_bbox_from_smash_mesh(mesh)
880
+ # xres = mesh.xres
881
+ # yres = mesh.yres
882
+
883
+ # # Open the larger raster
884
+ # with rasterio.open(path) as dataset:
885
+ # x_scale_factor = dataset.res[0] / xres
886
+ # y_scale_factor = dataset.res[1] / yres
887
+
888
+ # # resampling first to avoid spatial shifting of the parameters
889
+ # data = dataset.read(
890
+ # out_shape=(
891
+ # dataset.count,
892
+ # int(dataset.height * y_scale_factor),
893
+ # int(dataset.width * x_scale_factor),
894
+ # ),
895
+ # resampling=Resampling.nearest,
896
+ # )
897
+
898
+ # bbox_dataset = {
899
+ # "left": dataset.bounds.left,
900
+ # "bottom": dataset.bounds.bottom,
901
+ # "right": dataset.bounds.right,
902
+ # "top": dataset.bounds.top,
903
+ # }
904
+
905
+ # bbox_intersection = intersection_bbox(bbox_dataset, bounds)
906
+
907
+ # window_intersection = get_cropped_window_from_bbox_intersection(
908
+ # bbox_intersection, bbox_dataset, xres, yres
909
+ # )
910
+
911
+ # cropped_array = data[
912
+ # 0,
913
+ # window_intersection["row_off"] : window_intersection["row_off"]
914
+ # + window_intersection["nrows"],
915
+ # window_intersection["col_off"] : window_intersection["col_off"]
916
+ # + window_intersection["ncols"],
917
+ # ]
918
+
919
+ # # allocate out array: shape of bbox_out
920
+ # array_out = np.zeros(
921
+ # shape=(
922
+ # int((bounds["top"] - bounds["bottom"]) / xres),
923
+ # int((bounds["right"] - bounds["left"]) / yres),
924
+ # )
925
+ # )
926
+
927
+ # # window of bbox_intersection in the domain of bbox_smash
928
+ # window_intersection_out = get_cropped_window_from_bbox_intersection(
929
+ # bbox_intersection, bounds, xres, yres
930
+ # )
931
+
932
+ # # copy crop_array (input matrix cropped) in array_out
933
+ # array_out[
934
+ # window_intersection_out["row_off"] : window_intersection_out["row_off"]
935
+ # + window_intersection_out["nrows"],
936
+ # window_intersection_out["col_off"] : window_intersection_out["col_off"]
937
+ # + window_intersection_out["ncols"],
938
+ # ] = cropped_array
939
+
940
+ # return array_out
941
+
942
+
943
+ # def _rasterio_read_param2(path: FilePath, mesh: MeshDT):
944
+ # """
945
+ # Description
946
+ # -----------
947
+ # Read a geotif, resample if necessarry then clip it on the bouning box of the smash mesh
948
+
949
+ # Parameters
950
+ # ----------
951
+ # path: str
952
+ # Path to a geotiff file.
953
+ # mesh: object
954
+ # object of the smash mesh
955
+
956
+ # return
957
+ # ------
958
+ # np.ndarray
959
+ # The data clipped on the SMASH bounding box
960
+ # """
961
+ # input_bbox = get_bbox_from_smash_mesh(mesh)
962
+
963
+ # xres = mesh.xres
964
+ # yres = mesh.yres
965
+
966
+ # output_crs = rasterio.CRS.from_epsg(mesh.epsg)
967
+
968
+ # # Open the larger raster
969
+ # with rasterio.open(path) as dataset:
970
+
971
+ # x_scale_factor = dataset.res[0] / xres
972
+ # y_scale_factor = dataset.res[1] / yres
973
+
974
+ # transform = dataset.transform
975
+ # height = dataset.height
976
+ # width = dataset.width
977
+ # crs = dataset.crs
978
+
979
+ # # resampling first to avoid spatial shifting of the parameters
980
+ # data = dataset.read(
981
+ # out_shape=(
982
+ # dataset.count,
983
+ # int(dataset.height * y_scale_factor),
984
+ # int(dataset.width * x_scale_factor),
985
+ # ),
986
+ # resampling=Resampling.nearest,
987
+ # )
988
+
989
+ # # Use a memory dataset
990
+ # with rasterio.io.MemoryFile() as memfile:
991
+
992
+ # with memfile.open(
993
+ # driver="GTiff",
994
+ # height=height,
995
+ # width=width,
996
+ # count=1,
997
+ # dtype=data.dtype,
998
+ # transform=transform,
999
+ # crs=crs,
1000
+ # ) as dataset:
1001
+ # dataset.write(data[0, :, :], 1)
1002
+
1003
+ # new_width = int((input_bbox["right"] - input_bbox["left"]) / yres)
1004
+ # new_height = int((input_bbox["top"] - input_bbox["bottom"]) / xres)
1005
+ # new_transform = rasterio.transform.from_bounds(
1006
+ # west=input_bbox["left"],
1007
+ # south=input_bbox["bottom"],
1008
+ # east=input_bbox["right"],
1009
+ # north=input_bbox["top"],
1010
+ # width=new_width,
1011
+ # height=new_height,
1012
+ # )
1013
+
1014
+ # # Target array
1015
+ # new_array = np.empty((new_height, new_width), dtype=np.float32)
1016
+
1017
+ # # reproject dataset
1018
+ # rasterio.warp.reproject(
1019
+ # source=rasterio.band(dataset, 1),
1020
+ # destination=new_array,
1021
+ # src_transform=transform,
1022
+ # src_crs=crs,
1023
+ # dst_transform=new_transform,
1024
+ # dst_crs=output_crs,
1025
+ # resampling=Resampling.nearest,
1026
+ # )
1027
+
1028
+ # return new_array