tilupy 2.0.0__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.
@@ -0,0 +1,665 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import warnings
4
+ import numpy as np
5
+ import os
6
+ import shutil
7
+
8
+ from scipy.interpolate import RegularGridInterpolator
9
+
10
+ import tilupy.raster
11
+
12
+
13
+ def make_edges_matrices(nx: int, ny: int) -> list[np.ndarray, np.ndarray]:
14
+ """Numbering edges for a regular rectangular grid.
15
+
16
+ Considering a matrix M with whape (ny, nx),the convention is that
17
+ M[0, 0] corresponds to the lower left corner of the matrix, M[0, -1]
18
+ to the lower right corner, M[-1, 0] to the upper left and M[-1, -1] to
19
+ the upper right. Edges are numbered cell by cell, counter clockwise :
20
+ bottom, right, up, left. The first cell is M[0, 0], then cells are
21
+ processed line by line.
22
+
23
+ Parameters
24
+ ----------
25
+ nx : int
26
+ Number of faces in the X direction
27
+ ny : int
28
+ Number of faces in the Y direction
29
+
30
+ Returns
31
+ -------
32
+ h_edges : numpy.ndarray
33
+ Matrix containing the global edge indices of all horizontal edges
34
+ (bottom and top edges of the cells). Rows correspond to y-levels,
35
+ columns to x-positions.
36
+ v_edges : numpy.ndarray
37
+ Matrix containing the global edge indices of all vertical edges
38
+ (left and right edges of the cells). Rows correspond to y-levels,
39
+ columns to x-positions.
40
+ """
41
+ # Numbers of horizontal edges
42
+ h_edges = np.zeros((ny + 1, nx))
43
+ # Numbers of vertical edges
44
+ v_edges = np.zeros((ny, nx + 1))
45
+
46
+ # Number of edges on first completed line
47
+ n_edges_l1 = 4 + 3 * (nx - 1)
48
+ # Number of edges on folowwing lines
49
+ n_edges_l = 3 + 2 * (nx - 1)
50
+
51
+ # Fill first line of h_edges
52
+ h_edges[0, 0] = 1
53
+ h_edges[0, 1:] = np.arange(nx - 1) * 3 + 5
54
+ # Fill second line of h_edges
55
+ h_edges[1, :] = h_edges[0, :] + 2
56
+
57
+ try:
58
+ # Fill first column of h_edges
59
+ h_edges[2:, 0] = np.arange(ny - 1) * n_edges_l + n_edges_l1 + 2
60
+ # Fill the rest of the table
61
+ tmp = np.concatenate(([3], np.arange(nx - 2) * 2 + 5))
62
+ h_edges[2:, 1:] = h_edges[2:, 0][:, np.newaxis] + tmp[np.newaxis, :]
63
+ except IndexError:
64
+ pass
65
+
66
+ # Fill first 2 columns of v_edges
67
+ v_edges[0, 0] = 4
68
+ try:
69
+ v_edges[1:, 0] = np.arange(ny - 1) * n_edges_l + n_edges_l1 + 3
70
+ except IndexError:
71
+ pass
72
+ v_edges[:, 1] = v_edges[:, 0] - 2
73
+ # Fill the rest of v_edges
74
+ try:
75
+ v_edges[0, 2:] = 2 + np.concatenate(([4], np.arange(nx - 2) * 3 + 7))
76
+ tmp = np.concatenate(([3], np.arange(nx - 2) * 2 + 5))
77
+ v_edges[1:, 2:] = v_edges[1:, 1][:, np.newaxis] + tmp[np.newaxis, :]
78
+ except IndexError:
79
+ pass
80
+
81
+ h_edges = np.flip(h_edges, axis=0).astype(int)
82
+ v_edges = np.flip(v_edges, axis=0).astype(int)
83
+ return h_edges, v_edges
84
+
85
+
86
+ class ModellingDomain:
87
+ """Mesh of simulation topography
88
+
89
+ This class represents a structured 2D mesh built either from a raster
90
+ or from user-specified dimensions and spacing.
91
+ It stores the topographic data (z), the grid geometry (x, y, dx, dy, nx, ny),
92
+ and the numbering of edges used for discretization of the domain.
93
+
94
+ Parameters
95
+ ----------
96
+ raster : numpy.ndarray, str, or None, optional
97
+ - If numpy.ndarray: used directly as the elevation grid (z).
98
+ - If str: path to a raster file readable by :func:`tilupy.raster.read_raster`.
99
+ - If None: grid is generated from :data:`nx`, :data:`ny`, :data:`dx`, :data:`dy`.
100
+ xmin : float, optional
101
+ Minimum X coordinate of the grid, used if :data:`raster` is None,
102
+ by default 0.0.
103
+ ymin : float, optional
104
+ Minimum Y coordinate of the grid, used if :data:`raster` is None,
105
+ by default 0.0.
106
+ nx : int, optional
107
+ Number of grid points in the X direction, used if :data:`raster` is None,
108
+ by default None.
109
+ ny : int, optional
110
+ Number of grid points in the Y direction, used if :data:`raster` is None,
111
+ by default None.
112
+ dx : float, optional
113
+ Grid spacing along X, by default 1.0.
114
+ dy : float, optional
115
+ Grid spacing along Y, by default 1.0.
116
+
117
+ Attributes
118
+ ----------
119
+ _z : numpy.ndarray
120
+ Elevation values of the mesh nodes ([ny, nx]).
121
+ _nx : int
122
+ Number of grid points along the X direction.
123
+ _ny : int
124
+ Number of grid points along the Y direction.
125
+ _dx : float
126
+ Grid resolution in the X direction.
127
+ _dy : float
128
+ Grid resolution in the Y direction.
129
+ _x : numpy.ndarray
130
+ Array of X coordinates.
131
+ _y : numpy.ndarray
132
+ Array of Y coordinates.
133
+ _h_edges : numpy.ndarray
134
+ Matrix of horizontal edge numbers ([ny, nx-1]).
135
+ _v_edges : numpy.ndarray
136
+ Matrix of vertical edge numbers ([ny-1, nx]).
137
+ """
138
+ def __init__(self,
139
+ raster: np.ndarray = None,
140
+ xmin: float = 0,
141
+ ymin: float = 0,
142
+ nx: int = None,
143
+ ny: int = None,
144
+ dx: float = 1,
145
+ dy: float = 1,
146
+ ):
147
+ if raster is not None:
148
+ if isinstance(raster, np.ndarray):
149
+ self._z = raster
150
+ self._nx = raster.shape[1]
151
+ self._ny = raster.shape[0]
152
+ self._dx = dx
153
+ self._dy = dy
154
+ self._x = np.arange(xmin,
155
+ xmin + (self._nx - 1) * self._dx + self._dx / 2,
156
+ self._dx)
157
+ self._y = np.arange(ymin,
158
+ ymin + (self._ny - 1) * self._dy + self._dy / 2,
159
+ self._dy)
160
+
161
+ if isinstance(raster, str):
162
+ self._x, self._y, self._z = tilupy.raster.read_raster(raster)
163
+ self._nx = len(self._x)
164
+ self._ny = len(self._y)
165
+ self._dx = self._x[1] - self._x[0]
166
+ self._dy = self._y[1] - self._y[0]
167
+ else:
168
+ self._z = raster
169
+ self._nx = nx
170
+ self._ny = ny
171
+ self._dx = dx
172
+ self._dy = dy
173
+ if (xmin is not None
174
+ and ymin is not None
175
+ and nx is not None
176
+ and ny is not None
177
+ and dx is not None
178
+ and dy is not None
179
+ ):
180
+ self._x = np.arange(xmin, xmin + dx * nx + dx / 2, dx)
181
+ self._y = np.arange(ymin, ymin + dy * ny + dy / 2, dy)
182
+
183
+ self._h_edges = None
184
+ self._v_edges = None
185
+
186
+ if self._nx is not None and self._ny is not None:
187
+ self.set_edges()
188
+
189
+
190
+ def set_edges(self) -> None:
191
+ """Compute and assign horizontal and vertical edge number.
192
+
193
+ Calls :func:`tilupy.initsimus.make_edges_matrices` to build the edge numbering
194
+ for the grid defined by nx and ny.
195
+ Results are stored in attributes :attr:`_h_edges` and :attr:`_v_edges`.
196
+ """
197
+ self._h_edges, self._v_edges = make_edges_matrices(self._nx - 1, self._ny - 1)
198
+
199
+
200
+ def get_edge(self, xcoord: float, ycoord: float, cardinal: str) -> int:
201
+ """Get edge number for given coordinates and cardinal direction
202
+
203
+ Parameters
204
+ ----------
205
+ xcoord : float
206
+ X coordinate of the point.
207
+ ycoord : float
208
+ Y coordinate of the point.
209
+ cardinal : str
210
+ Cardinal direction of the edge ('N', 'S', 'E', 'W'):
211
+
212
+ - 'N': top edge of the cell
213
+ - 'S': bottom edge of the cell
214
+ - 'E': right edge of the cell
215
+ - 'W': left edge of the cell
216
+
217
+ Returns
218
+ -------
219
+ int
220
+ Edge number corresponding to the requested location and direction.
221
+
222
+ Raises
223
+ ------
224
+ AssertionError
225
+ If :meth:`set_edges` has not been called before (i.e. :attr:`_h_edges` and :attr:`_v_edges` are None).
226
+ """
227
+ assert (self._h_edges is not None) and (self._v_edges is not None), "h_edges and v_edges must be computed to get edge number"
228
+ ix = np.argmin(np.abs(self._x[:-1] + self._dx / 2 - xcoord))
229
+ iy = np.argmin(np.abs(self._y[:-1] + self._dx / 2 - ycoord))
230
+ if cardinal == "S":
231
+ return self._h_edges[-iy - 1, ix]
232
+ elif cardinal == "N":
233
+ return self._h_edges[-iy - 2, ix]
234
+ elif cardinal == "W":
235
+ return self._v_edges[-iy - 1, ix]
236
+ elif cardinal == "E":
237
+ return self._v_edges[-iy - 1, ix + 1]
238
+
239
+
240
+ def get_edges(self, xcoords: np.ndarray, ycoords: np.ndarray, cardinal: str, from_extremities: bool=True) -> dict[str: list[int]]:
241
+ """Get edges numbers for a set of coordinates and cardinals direction.
242
+
243
+ If :data:`from_extremities` is True, xcoords and ycoords are treated as the extremities of a segment.
244
+
245
+ Parameters
246
+ ----------
247
+ xcoords : np.ndarray or list
248
+ X coordinates of points. If :data:`from_extremities` is True, indicated (xmin, xmax).
249
+ ycoords : np.ndarray or list
250
+ Y coordinates of points. If :data:`from_extremities` is True, indicated (ymin, ymax).
251
+ cardinal : str
252
+ Cardinal directions to extract, any combination of {'N', 'S', 'E', 'W'}.
253
+ Example: "NS" will return both north and south edges.
254
+ from_extremities : bool, optional
255
+ If True, :data:`xcoords` and :data:`ycoords` are considered as the endpoints
256
+ of a line, by default True
257
+
258
+ Returns
259
+ -------
260
+ dict[str: list[int]]
261
+ Dictionary where keys are the requested cardinals and values are
262
+ sorted lists of unique edge numbers.
263
+ """
264
+ if from_extremities:
265
+ d = np.sqrt((xcoords[1] - xcoords[0]) ** 2 + (ycoords[1] - ycoords[0]) ** 2)
266
+ npts = int(np.ceil(d / min(self._dx, self._dy)))
267
+ xcoords = np.linspace(xcoords[0], xcoords[1], npts + 1)
268
+ ycoords = np.linspace(ycoords[0], ycoords[1], npts + 1)
269
+
270
+ if self._h_edges is None or self._v_edges is None:
271
+ self.set_edges
272
+
273
+ res = dict()
274
+
275
+ # cardinal is a string with any combination of cardinal directions
276
+ for card in cardinal:
277
+ edges_num = []
278
+ for xcoord, ycoord in zip(xcoords, ycoords):
279
+ edges_num.append(self.get_edge(xcoord, ycoord, card))
280
+ res[card] = list(set(edges_num)) # Duplicate edges are removed
281
+ res[card].sort()
282
+
283
+ return res
284
+
285
+
286
+ class Simu:
287
+ """Simulation configuration and input file generator.
288
+
289
+ This class manages the setup of lave2D. It creates the necessary input files (topography, numeric
290
+ parameters, rheology, boundary conditions, initial mass) that will be read by lave2D.
291
+
292
+ Parameters
293
+ ----------
294
+ folder : str
295
+ Directory where simulation files are written. Created if it does not exist.
296
+ name : str
297
+ Base name of the simulation (used as file prefix).
298
+
299
+ Attributes
300
+ ----------
301
+ _folder : str
302
+ Path to the directory where simulation input and output files are stored.
303
+ _name : str
304
+ Base name of the simulation, used as a prefix for generated files. Must have 8 characters.
305
+ _x : numpy.ndarray
306
+ Array of X coordinates of the topography grid.
307
+ _y : numpy.ndarray
308
+ Array of Y coordinates of the topography grid.
309
+ _z : numpy.ndarray
310
+ 2D array of topographic elevations.
311
+ _tmax : float
312
+ Maximum simulation time.
313
+ _dtsorties : float
314
+ Time step for output results.
315
+ """
316
+ def __init__(self, folder: str, name: str):
317
+ os.makedirs(folder, exist_ok=True)
318
+ self._folder = folder
319
+ self._name = name
320
+ self._x = None
321
+ self._y = None
322
+ self._z = None
323
+
324
+
325
+ def set_topography(self, z: np.ndarray | str,
326
+ x: np.ndarray=None,
327
+ y: np.ndarray=None,
328
+ file_out: str=None
329
+ ) -> None:
330
+ """Set simulation topography and write it as an ASCII grid.
331
+
332
+ Parameters
333
+ ----------
334
+ z : ndarray or str
335
+ Topography values as a 2D NumPy array, or path to a raster file.
336
+ x : ndarray, optional
337
+ X coordinates of the grid, ignored if :data:`z` is a file path.
338
+ y : ndarray, optional
339
+ Y coordinates of the grid, ignored if :data:`z` is a file path.
340
+ file_out : str, optional
341
+ Output filename (add ".asc"), by defaults "toposimu.asc".
342
+ Filenames are truncated or padded to 8 characters.
343
+
344
+ Returns
345
+ -------
346
+ None
347
+ """
348
+ if isinstance(z, str):
349
+ self._x, self._y, self._z = tilupy.raster.read_raster(z)
350
+ else:
351
+ self._x, self._y, self._z = x, y, z
352
+
353
+ if file_out is None:
354
+ file_out = "toposimu.asc"
355
+ else:
356
+ fname = file_out.split(".")[0]
357
+ if len(fname) > 8:
358
+ warnings.warns("""Topography file name is too long,
359
+ only 8 first characters are retained"""
360
+ )
361
+ fname = fname[:8]
362
+ elif len(fname) < 8:
363
+ warnings.warns("""Topography file name is too short and is adapted,
364
+ exactly 8 characters needed"""
365
+ )
366
+ fname = fname.ljust(8, "0")
367
+ file_out = fname + ".asc"
368
+
369
+ tilupy.raster.write_ascii(self._x,
370
+ self._y,
371
+ self._z,
372
+ os.path.join(self._folder, file_out))
373
+
374
+
375
+ def set_numeric_params(self,
376
+ tmax: float,
377
+ dtsorties: float,
378
+ paray: float=0.00099,
379
+ dtinit: float=0.01,
380
+ cfl_const: int=1,
381
+ CFL: float=0.2,
382
+ alpha_cor_pente: float=1.0,
383
+ ) -> None:
384
+ """Set numerical simulation parameters and write them to file.
385
+
386
+ Parameters
387
+ ----------
388
+ tmax : float
389
+ Maximum simulation time.
390
+ dtsorties : float
391
+ Time step for output results.
392
+ paray : float, optional
393
+ Hydraulic roughness parameter, by default 0.00099.
394
+ dtinit : float, optional
395
+ Initial time step, by default 0.01.
396
+ cfl_const : int, optional
397
+ If 1, CFL condition is constant, by default 1.
398
+ CFL : float, optional
399
+ Courant-Friedrichs-Lewy number, by default 0.2.
400
+ alpha_cor_pente : float, optional
401
+ Slope correction coefficient, by default 1.0.
402
+
403
+ Returns
404
+ -------
405
+ None
406
+ """
407
+ self._tmax = tmax
408
+ self._dtsorties = dtsorties
409
+
410
+ with open(os.path.join(self._folder, "DONLEDD1.DON"), "w") as fid:
411
+ fid.write("paray".ljust(34, " ") + "{:.12f}\n".format(paray).lstrip("0"))
412
+ fid.write("tmax".ljust(34, " ") + "{:.12f}\n".format(tmax))
413
+ fid.write("dtinit".ljust(34, " ") + "{:.12f}\n".format(dtinit))
414
+ fid.write("cfl constante ?".ljust(34, " ") + "{:.0f}\n".format(cfl_const))
415
+ fid.write("CFL".ljust(34, " ") + "{:.12f}\n".format(CFL))
416
+ fid.write("Go,VaLe1,VaLe2".ljust(34, " ") + "{:.0f}\n".format(3))
417
+ fid.write("secmbr0/1".ljust(34, " ") + "{:.0f}\n".format(1))
418
+ fid.write("CL variable (si=0) ?".ljust(34, " ") + "{:d}\n".format(0))
419
+ fid.write("dtsorties".ljust(34, " ") + "{:.12f}\n".format(dtsorties))
420
+ fid.write("alpha cor pentes".ljust(34, " ") + "{:.12f}".format(alpha_cor_pente))
421
+
422
+
423
+ def set_rheology(self, tau_rho: float, K_tau: float=0.3) -> None:
424
+ r"""Set Herschel-Bulkley rheology parameters
425
+
426
+ Rheological parameters are tau/rho and K/tau. See :
427
+
428
+ - Coussot, P., 1994. Steady, laminar, flow of concentrated mud suspensions in open channel. Journal of Hydraulic Research 32, 535-559. doi.org/10.1080/00221686.1994.9728354
429
+ --> Eq 8 and text after eq 22 for the default value of K/tau
430
+ - Rickenmann, D. et al., 2006. Comparison of 2D debris-flow simulation models with field events. Computational Geosciences 10, 241-264. doi.org/10.1007/s10596-005-9021-3
431
+ --> Eq 9
432
+
433
+ tau_rho : float
434
+ Yield stress divided by density (:math:`\tau/\rho`).
435
+ K_tau : float, optional
436
+ Consistency index divided by yield stress (:math:`K/\tau`).
437
+ By default 0.3, following Rickenmann (2006).
438
+
439
+ Returns
440
+ -------
441
+ None
442
+ """
443
+ with open(os.path.join(self._folder, self._name + ".rhe"), "w") as fid:
444
+ fid.write("{:.3f}\n".format(tau_rho))
445
+ fid.write("{:.3f}".format(K_tau))
446
+
447
+
448
+ def set_boundary_conditions(self,
449
+ xcoords: list,
450
+ ycoords: list,
451
+ cardinal: str,
452
+ discharges: list | float,
453
+ times: list=None,
454
+ thicknesses: list=None,
455
+ tmax: float=9999,
456
+ discharge_from_volume: bool=False,
457
+ ) -> None:
458
+ r"""Define and write inflow hydrograph boundary conditions.
459
+
460
+ Parameters
461
+ ----------
462
+ xcoords : list
463
+ X coordinates of boundary location (two values for segment ends).
464
+ ycoords : list
465
+ Y coordinates of boundary location (two values for segment ends).
466
+ cardinal : str
467
+ Boundary orientation ('N', 'S', 'E', 'W').
468
+ discharges : list or float
469
+ If :data:`times` is None: interpreted as inflow volume (:math:`m^3`).
470
+ Else: Interpreted as discharge values (:math:`m^3/s`) at each time step.
471
+ times : list, optional
472
+ Time vector associated with discharges. If None, a synthetic
473
+ hydrograph is built from volume. By default None.
474
+ thicknesses : list, optional
475
+ Flow thicknesses for each time step. If None, put 1m everywhere. By default None.
476
+ tmax : float, optional
477
+ Maximum time for synthetic hydrograph generation, by default 9999.
478
+ discharge_from_volume : bool, optional
479
+ If True, discharges are computed from inflow volume, by default False. Not used.
480
+
481
+ Returns
482
+ -------
483
+ None
484
+
485
+ Raises
486
+ ------
487
+ AttributeError
488
+ If no topography not been set.
489
+ """
490
+ try:
491
+ modelling_domain = ModellingDomain(self._z,
492
+ self._x[0],
493
+ self._y[0],
494
+ dx=self._x[1] - self._x[0],
495
+ dy=self._y[1] - self._y[0])
496
+ except AttributeError:
497
+ print("Simulation topography has not been set")
498
+ raise
499
+
500
+ edges = modelling_domain.get_edges(xcoords,
501
+ ycoords,
502
+ cardinal,
503
+ from_extremities=True)
504
+ edges = edges[cardinal]
505
+
506
+ if times is None:
507
+ # If no time vector is given, discharges is interpreted as a volume
508
+ # from which an empirical peak discharge is computed
509
+ peak_discharge = 0.0188 * discharges**0.79
510
+ times = [0, 2 * discharges / peak_discharge, tmax]
511
+ discharges = [peak_discharge, 0, 0]
512
+
513
+ n_times = len(times)
514
+ n_edges = len(edges)
515
+
516
+ assert n_times == len(discharges), "discharges and time vectors must be the same length"
517
+
518
+ if thicknesses is None:
519
+ thicknesses = [1 for i in range(n_times)]
520
+
521
+ if cardinal in ["W", "E"]:
522
+ dd = self._y[1] - self._y[0]
523
+ else:
524
+ dd = self._x[1] - self._x[0]
525
+
526
+ with open(os.path.join(self._folder, self._name + ".cli"), "w") as fid:
527
+ fid.write("{:d}\n".format(n_times)) # Number of time steps in the hydrogram
528
+ for i, time in enumerate(times):
529
+ fid.write("{:.4f}\n".format(time)) # Write time
530
+ fid.write("{:d}\n".format(n_edges)) # Write n_edges
531
+ qn = discharges[i] / (n_edges * dd)
532
+ qt = 0
533
+ for i_edge, edge in enumerate(edges):
534
+ fid.write("\t{:d} {:.7E} {:.7E} {:.7E}\n".format(edge,
535
+ thicknesses[i],
536
+ qn,
537
+ qt))
538
+
539
+
540
+ def set_init_mass(self, mass_raster: str, h_min: float=0.01) -> None:
541
+ """Set initial debris-flow mass from a raster file.
542
+
543
+ Reads an ASCII raster of initial thickness and interpolates it onto
544
+ the simulation grid cell centers.
545
+
546
+ Parameters
547
+ ----------
548
+ mass_raster : str
549
+ Path to raster file containing initial mass thickness.
550
+ h_min : float, optional
551
+ Minimum non-zero thickness assigned to the grid. Default is 0.01.
552
+
553
+ Returns
554
+ -------
555
+ None
556
+ """
557
+ x, y, m = tilupy.raster.read_ascii(mass_raster)
558
+ # The input raster is given as the topography for the grid corners,
559
+ # but results are then written on grid cell centers
560
+ x2 = x[1:] - (x[1] - x[0]) / 2
561
+ y2 = y[1:] - (y[1] - y[0]) / 2
562
+
563
+ y2 = y2[::-1]
564
+
565
+ fm = RegularGridInterpolator((y, x),
566
+ m,
567
+ method="linear",
568
+ bounds_error=False,
569
+ fill_value=None)
570
+ x_mesh, y_mesh = np.meshgrid(x2, y2)
571
+ m2 = fm((y_mesh, x_mesh))
572
+ m2[m2 < h_min] = h_min
573
+ np.savetxt(os.path.join(self._folder, self._name + ".cin"),
574
+ m2.flatten(),
575
+ header="0.000000E+00",
576
+ comments="",
577
+ fmt="%.10E")
578
+
579
+
580
+ def write_simu(raster_topo: str,
581
+ raster_mass: str,
582
+ tmax: float,
583
+ dt_im: float,
584
+ simulation_name: str,
585
+ lave2D_exe_folder: str,
586
+ rheology_type: str,
587
+ rheology_params: dict,
588
+ folder_out: str = None,
589
+ ) -> None:
590
+ """
591
+ Prepares all input files required for a Lave2D simulation and saves them in a dedicated folder.
592
+
593
+ Parameters
594
+ ----------
595
+ raster_topo : str
596
+ Name of the ASCII topography file.
597
+ raster_mass : str
598
+ Name of the ASCII initial mass file.
599
+ tmax : float
600
+ Maximum simulation time.
601
+ dt_im : float
602
+ Output image interval (in time steps).
603
+ simulation_name : str
604
+ Simulation/project name.
605
+ lave2D_exe_folder : str
606
+ Path to the folder containing "Lave2_Arc.exe" and "vf2marc.exe".
607
+ rheology_type : str
608
+ Rheology to use for the simulation.
609
+ rheology_params : dict
610
+ Necessary parameters for the rheology. For this case:
611
+ - tau_rho
612
+ - K_tau
613
+ folder_out : str, optional
614
+ Output folder where simulation inputs will be stored.
615
+
616
+ Returns
617
+ -------
618
+ None
619
+
620
+ Raises
621
+ ------
622
+ ValueError
623
+ If the rheology isn't Herschel_Bulkley.
624
+ """
625
+ if folder_out is None:
626
+ folder_out = "."
627
+
628
+ if rheology_type != "Herschel_Bulkley":
629
+ raise ValueError("Rheology type must be 'Herschel_Bulkley'.")
630
+
631
+ # output_file = os.path.join(folder_out, "lave2D")
632
+
633
+ os.makedirs(folder_out, exist_ok=True)
634
+
635
+ shutil.copy2(os.path.join(lave2D_exe_folder, "Lave2_Arc.exe"),
636
+ folder_out)
637
+ shutil.copy2(os.path.join(lave2D_exe_folder, "vf2marc.exe"),
638
+ folder_out)
639
+
640
+ simu_lave2D = Simu(folder_out, simulation_name)
641
+ simu_lave2D.set_topography(raster_topo)
642
+ simu_lave2D.set_init_mass(raster_mass)
643
+ simu_lave2D.set_rheology(rheology_params["tau_rho"], rheology_params["K_tau"])
644
+ simu_lave2D.set_numeric_params(tmax, dt_im)
645
+
646
+ ## Not used in simulation, but the .cli file is needed
647
+ simu_lave2D.set_boundary_conditions([0, 0], # X min and max coords for input flux
648
+ [1, 2], # Y min and max coord for input flux
649
+ "W", # Cardinal direction (Flow from East to West)
650
+ [0, 0], # Discharge hydrogram
651
+ times=[0, tmax + 1], # Corresponding times
652
+ thicknesses=[0, 0], # Thickness hydrogramm
653
+ )
654
+
655
+
656
+ """
657
+ if __name__ == "__main__":
658
+ h_edges, v_edges = make_edges_matrices(1, 1)
659
+
660
+
661
+ if __name__ == "__main__":
662
+ domain = ModellingDomain(xmin=0, ymin=0, nx=4, ny=3, dx=1, dy=1)
663
+ domain.set_edges()
664
+ res = domain.get_edges([1.5, 2.5], [0, 0], "S")
665
+ """