wolfhece 2.1.100__py3-none-any.whl → 2.1.101__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.
- wolfhece/PyDraw.py +200 -16
- wolfhece/PyGui.py +1039 -53
- wolfhece/Results2DGPU.py +37 -13
- wolfhece/acceptability/func.py +43 -32
- wolfhece/apps/version.py +1 -1
- wolfhece/bernoulli/losses.py +3 -3
- wolfhece/gpuview.py +4 -1
- wolfhece/libs/__init__.py +11 -10
- wolfhece/libs/wolfogl.cp310-win_amd64.pyd +0 -0
- wolfhece/math_parser/calculator.py +5 -4
- wolfhece/mesh2d/bc_manager.py +25 -2
- wolfhece/mesh2d/gpu_2d.py +644 -0
- wolfhece/mesh2d/simple_2d.py +581 -163
- wolfhece/mesh2d/wolf2dprev.py +4 -1
- wolfhece/scenario/config_manager.py +97 -20
- wolfhece/wolf_array.py +235 -73
- wolfhece/wolfresults_2D.py +53 -20
- {wolfhece-2.1.100.dist-info → wolfhece-2.1.101.dist-info}/METADATA +3 -1
- {wolfhece-2.1.100.dist-info → wolfhece-2.1.101.dist-info}/RECORD +22 -21
- {wolfhece-2.1.100.dist-info → wolfhece-2.1.101.dist-info}/WHEEL +1 -1
- {wolfhece-2.1.100.dist-info → wolfhece-2.1.101.dist-info}/entry_points.txt +0 -0
- {wolfhece-2.1.100.dist-info → wolfhece-2.1.101.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,644 @@
|
|
1
|
+
import logging
|
2
|
+
from pathlib import Path
|
3
|
+
import numpy as np
|
4
|
+
from typing import Union, Literal
|
5
|
+
import matplotlib.pyplot as plt
|
6
|
+
|
7
|
+
from ..wolf_array import WOLF_ARRAY_FULL_LOGICAL, WOLF_ARRAY_FULL_SINGLE, WOLF_ARRAY_FULL_INTEGER, WOLF_ARRAY_FULL_INTEGER8, WOLF_ARRAY_FULL_UINTEGER8
|
8
|
+
from ..wolf_array import WolfArray, header_wolf
|
9
|
+
from ..PyTranslate import _
|
10
|
+
from ..PyVertexvectors import vector, zone, Zones
|
11
|
+
from wolfgpu.simple_simulation import SimpleSimulation
|
12
|
+
|
13
|
+
class infiltration_GPU():
|
14
|
+
def __init__(self, parent:"Sim_2D_GPU") -> None:
|
15
|
+
self.parent:"Sim_2D_GPU" = parent
|
16
|
+
|
17
|
+
@property
|
18
|
+
def infiltrations_chronology(self) -> list[float]:
|
19
|
+
chronos = self.parent.sim.infiltrations_chronology
|
20
|
+
if len(chronos) == 0:
|
21
|
+
return []
|
22
|
+
else:
|
23
|
+
return [[cur[0]]+cur[1] for cur in chronos]
|
24
|
+
|
25
|
+
@infiltrations_chronology.setter
|
26
|
+
def infiltrations_chronology(self, value:np.ndarray) -> None:
|
27
|
+
|
28
|
+
simple_chronology = [(cur[0], list(cur[1:])) for cur in value]
|
29
|
+
self.parent.sim.infiltrations_chronology = simple_chronology
|
30
|
+
|
31
|
+
@property
|
32
|
+
def nb_steps(self) -> int:
|
33
|
+
chronos = self.parent.sim.infiltrations_chronology
|
34
|
+
if len(chronos) == 0:
|
35
|
+
return 0
|
36
|
+
else:
|
37
|
+
return len(chronos)
|
38
|
+
|
39
|
+
@property
|
40
|
+
def nb_zones(self) -> Zones:
|
41
|
+
chronos = self.parent.sim.infiltrations_chronology
|
42
|
+
if len(chronos) == 0:
|
43
|
+
return 0
|
44
|
+
else:
|
45
|
+
if len(chronos[0]) == 0:
|
46
|
+
return 0
|
47
|
+
else:
|
48
|
+
return len(chronos[0][1])
|
49
|
+
|
50
|
+
def plot_plt(self, figax=None, show=True):
|
51
|
+
""" Plot the infiltration data """
|
52
|
+
|
53
|
+
if figax is None:
|
54
|
+
fig, ax = plt.subplots(1, 1)
|
55
|
+
else:
|
56
|
+
fig,ax = figax
|
57
|
+
|
58
|
+
chronos = self.parent.sim.infiltrations_chronology
|
59
|
+
times = [cur[0] for cur in chronos]
|
60
|
+
|
61
|
+
for zone in range(self.nb_zones):
|
62
|
+
ax.plot(times, [cur[1][zone] for cur in chronos], label=f'Zone {zone+1}')
|
63
|
+
|
64
|
+
ax.set_xlabel(_('Time [s]'))
|
65
|
+
ax.set_ylabel(_('Infiltration [$m^3/s$]'))
|
66
|
+
ax.legend()
|
67
|
+
fig.tight_layout()
|
68
|
+
|
69
|
+
if show:
|
70
|
+
fig.show()
|
71
|
+
|
72
|
+
return fig,ax
|
73
|
+
|
74
|
+
|
75
|
+
class Sim_2D_GPU():
|
76
|
+
""" Simulation 2D GPU -- Interface """
|
77
|
+
|
78
|
+
def __init__(self, directory:Union[str,Path] = '') -> None:
|
79
|
+
|
80
|
+
try:
|
81
|
+
from wolfgpu.simple_simulation import SimpleSimulation
|
82
|
+
except:
|
83
|
+
logging.error(_("Unable to import wolfgpu.simple_simulation.SimpleSimulation. Please install wolfgpu package or add a symlink to the wolfgpu package in the wolfhece directory"))
|
84
|
+
|
85
|
+
self.dir = Path(directory)
|
86
|
+
self._sim = None
|
87
|
+
self._cached_arrays = {}
|
88
|
+
self.magnetic_grid:header_wolf = None
|
89
|
+
|
90
|
+
if (self.dir /'parameters.json').exists():
|
91
|
+
self._sim = SimpleSimulation.load(self.dir)
|
92
|
+
self.infiltration = infiltration_GPU(self)
|
93
|
+
|
94
|
+
# Fine arrays with type
|
95
|
+
self.files_array={'Characteristics':[
|
96
|
+
('nap','Mask [-]',WOLF_ARRAY_FULL_UINTEGER8),
|
97
|
+
('bathymetry','Bed Elevation [m]',WOLF_ARRAY_FULL_SINGLE),
|
98
|
+
('manning','Roughness coefficient [law dependent]',WOLF_ARRAY_FULL_SINGLE),
|
99
|
+
('infiltration_zones','Infiltration zone [-]',WOLF_ARRAY_FULL_INTEGER),
|
100
|
+
('h','Initial water depth [m]',WOLF_ARRAY_FULL_SINGLE),
|
101
|
+
('qx','Initial discharge along X [m^2/s]',WOLF_ARRAY_FULL_SINGLE),
|
102
|
+
('qy','Initial discharge along Y [m^2/s]',WOLF_ARRAY_FULL_SINGLE),
|
103
|
+
]}
|
104
|
+
|
105
|
+
self.files_ic=['Initial water depth [m]','Initial discharge along X [m^2/s]','Initial discharge along Y [m^2/s]']
|
106
|
+
|
107
|
+
# Files for the simulation
|
108
|
+
self.files_others={'Generic file':[
|
109
|
+
('parameters.json','Parametric file'),
|
110
|
+
]}
|
111
|
+
|
112
|
+
pass
|
113
|
+
|
114
|
+
@property
|
115
|
+
def boundary_condition(self):
|
116
|
+
return self.sim.boundary_condition
|
117
|
+
|
118
|
+
@property
|
119
|
+
def is_loaded(self) -> bool:
|
120
|
+
return self.sim is not None
|
121
|
+
|
122
|
+
def unload(self) -> None:
|
123
|
+
""" Unload the simulation """
|
124
|
+
if self.is_loaded:
|
125
|
+
del self._sim
|
126
|
+
self._sim = None
|
127
|
+
|
128
|
+
@property
|
129
|
+
def sim(self) -> SimpleSimulation:
|
130
|
+
return self._sim
|
131
|
+
|
132
|
+
@sim.setter
|
133
|
+
def sim(self, value:SimpleSimulation) -> None:
|
134
|
+
self._sim = value
|
135
|
+
|
136
|
+
def __str__(self) -> str:
|
137
|
+
ret = f"Simulation 2D GPU: {self.dir.name}\n"
|
138
|
+
if self.is_loaded:
|
139
|
+
ret += str(self.sim)
|
140
|
+
return ret
|
141
|
+
|
142
|
+
def __repr__(self) -> str:
|
143
|
+
return self.__str__()
|
144
|
+
|
145
|
+
def _get_name_arrays(self) -> list[str]:
|
146
|
+
""" Get the name of the arrays """
|
147
|
+
return [cur[0] for cur in self.files_array['Characteristics']]
|
148
|
+
|
149
|
+
def _get_description_arrays(self) -> list[str]:
|
150
|
+
""" Get the description of the arrays """
|
151
|
+
return [cur[1] for cur in self.files_array['Characteristics']]
|
152
|
+
|
153
|
+
def get_header(self) -> header_wolf:
|
154
|
+
""" Get the header of the simulation """
|
155
|
+
if self.is_loaded:
|
156
|
+
new_header = header_wolf()
|
157
|
+
new_header.nbx = self.sim.param_nx
|
158
|
+
new_header.nby = self.sim.param_ny
|
159
|
+
new_header.dx = self.sim.param_dx
|
160
|
+
new_header.dy = self.sim.param_dy
|
161
|
+
new_header.origx = self.sim.param_base_coord_ll_x
|
162
|
+
new_header.origy = self.sim.param_base_coord_ll_y
|
163
|
+
|
164
|
+
return new_header
|
165
|
+
else:
|
166
|
+
return None
|
167
|
+
|
168
|
+
def __getitem__(self, key:Literal['nap', 'bathymetry', 'manning', 'infiltrations_zones', 'h', 'qx', 'qy']) -> WolfArray:
|
169
|
+
""" Get an array from the simulation """
|
170
|
+
|
171
|
+
nullvalues = {'nap':0, 'bathymetry':99999, 'manning':0, 'infiltration_zones':0, 'h':0, 'qx':0, 'qy':0}
|
172
|
+
|
173
|
+
if self.is_loaded:
|
174
|
+
if key in self._get_name_arrays():
|
175
|
+
descr = self._get_description_arrays()[self._get_name_arrays().index(key)]
|
176
|
+
|
177
|
+
if key not in self._cached_arrays:
|
178
|
+
locarray = WolfArray(srcheader=self.get_header(),
|
179
|
+
np_source=self.sim.__getattribute__(key),
|
180
|
+
idx= descr,
|
181
|
+
nullvalue=nullvalues[key],
|
182
|
+
whichtype=self.files_array['Characteristics'][self._get_name_arrays().index(key)][2],
|
183
|
+
masknull=False)
|
184
|
+
locarray.loaded = True
|
185
|
+
locarray.filename = str(self.dir / f"{key}.npy")
|
186
|
+
|
187
|
+
self._cached_arrays[key] = locarray
|
188
|
+
return locarray
|
189
|
+
else:
|
190
|
+
return self._cached_arrays[key]
|
191
|
+
else:
|
192
|
+
return None
|
193
|
+
else:
|
194
|
+
return None
|
195
|
+
|
196
|
+
def get_arraysasdict(self) -> dict[str,WolfArray]:
|
197
|
+
""" Get all the arrays from the simulation """
|
198
|
+
|
199
|
+
ret= {key:self[key] for key in self._get_name_arrays()}
|
200
|
+
self.mimic_mask(ret['nap'], [cur for key,cur in ret.items() if key != 'nap'])
|
201
|
+
|
202
|
+
return ret
|
203
|
+
|
204
|
+
|
205
|
+
def mimic_mask(self, source:WolfArray, dest:list[WolfArray]):
|
206
|
+
""" Mimic the mask """
|
207
|
+
|
208
|
+
for cur in dest:
|
209
|
+
cur.array.mask[:,:] = source.array.mask[:,:]
|
210
|
+
cur.set_nullvalue_in_mask()
|
211
|
+
|
212
|
+
def create_arrays_from(self, source:WolfArray):
|
213
|
+
""" Create arrays from a source """
|
214
|
+
|
215
|
+
if self.is_loaded:
|
216
|
+
logging.error(_("Simulation exists, cannot create arrays from source or delete simulation first !"))
|
217
|
+
else:
|
218
|
+
try:
|
219
|
+
self._sim = SimpleSimulation(source.nbx, source.nby)
|
220
|
+
self._sim.param_dx = source.dx
|
221
|
+
self._sim.param_dy = source.dy
|
222
|
+
self._sim.param_base_coord_ll_x = source.origx
|
223
|
+
self._sim.param_base_coord_ll_y = source.origy
|
224
|
+
self.infiltration = infiltration_GPU(self)
|
225
|
+
except Exception as e:
|
226
|
+
logging.error(_("Unable to create simulation -- {e}"))
|
227
|
+
return
|
228
|
+
|
229
|
+
# Float32 arrays
|
230
|
+
loc_array = np.zeros((source.nbx, source.nby), dtype=np.float32)
|
231
|
+
self.sim.h = loc_array.copy()
|
232
|
+
self.sim.qx = loc_array.copy()
|
233
|
+
self.sim.qy = loc_array.copy()
|
234
|
+
|
235
|
+
self.sim.manning = loc_array.copy()
|
236
|
+
self.sim.manning[np.logical_not(source.array.mask)] = 0.04
|
237
|
+
|
238
|
+
loc_array[source.array.mask] = 99999.
|
239
|
+
self.sim.bathymetry = loc_array.copy()
|
240
|
+
|
241
|
+
# UInteger8 arrays
|
242
|
+
loc_array = np.ones((source.nbx, source.nby), dtype=np.uint8)
|
243
|
+
loc_array[source.array.mask] = 0
|
244
|
+
self.sim.nap = loc_array.copy()
|
245
|
+
|
246
|
+
# Integer arrays
|
247
|
+
loc_array = np.zeros((source.nbx, source.nby), dtype=np.int32)
|
248
|
+
self.sim.infiltration_zones = loc_array.copy()
|
249
|
+
|
250
|
+
|
251
|
+
def create_from_vector(self, vector:vector, dx:float, dy:float):
|
252
|
+
""" Create a simulation from a vector """
|
253
|
+
|
254
|
+
if vector is None:
|
255
|
+
logging.warning(_("Vector is None"))
|
256
|
+
return None
|
257
|
+
elif self.magnetic_grid is None:
|
258
|
+
logging.error(_("Magnetic grid not set"))
|
259
|
+
return None
|
260
|
+
else:
|
261
|
+
vector.find_minmax()
|
262
|
+
xmin, ymin = vector.xmin, vector.ymin
|
263
|
+
xmax, ymax = vector.xmax, vector.ymax
|
264
|
+
|
265
|
+
xmin, ymin = self.align2grid(xmin, ymin)
|
266
|
+
xmax, ymax = self.align2grid(xmax, ymax)
|
267
|
+
|
268
|
+
xmin -= 2*dx
|
269
|
+
ymin -= 2*dy
|
270
|
+
xmax += 2*dx
|
271
|
+
ymax += 2*dy
|
272
|
+
|
273
|
+
src_header = header_wolf()
|
274
|
+
src_header.dx = dx
|
275
|
+
src_header.dy = dy
|
276
|
+
src_header.origx = xmin
|
277
|
+
src_header.origy = ymin
|
278
|
+
src_header.nbx = int((xmax-xmin)/src_header.dx)
|
279
|
+
src_header.nby = int((ymax-ymin)/src_header.dy)
|
280
|
+
|
281
|
+
tmp_array = WolfArray(srcheader=src_header)
|
282
|
+
ij = tmp_array.get_ij_inside_polygon(vector, usemask=False)
|
283
|
+
|
284
|
+
tmp_array.mask_reset()
|
285
|
+
tmp_array.mask_outsidepoly(vector)
|
286
|
+
self.create_arrays_from(tmp_array)
|
287
|
+
|
288
|
+
def create_from_array(self, array:WolfArray):
|
289
|
+
""" Create a simulation from an array """
|
290
|
+
if array is None:
|
291
|
+
logging.warning(_("Array is None"))
|
292
|
+
return None
|
293
|
+
else:
|
294
|
+
self.create_arrays_from(array)
|
295
|
+
|
296
|
+
def create_from_header(self, header:header_wolf) -> 'Sim_2D_GPU':
|
297
|
+
""" Create a simulation from a header """
|
298
|
+
if header is None:
|
299
|
+
logging.warning(_("Header is None"))
|
300
|
+
return None
|
301
|
+
else:
|
302
|
+
tmp_array = WolfArray(srcheader=header)
|
303
|
+
tmp_array.array[:,0] = 0
|
304
|
+
tmp_array.array[0,:] = 0
|
305
|
+
tmp_array.array[-1,:] = 0
|
306
|
+
tmp_array.array[:,-1] = 0
|
307
|
+
tmp_array.masknull()
|
308
|
+
self.create_arrays_from(tmp_array)
|
309
|
+
|
310
|
+
def set_mesh_size(self, dx, dy):
|
311
|
+
""" Set the mesh size """
|
312
|
+
if self.is_loaded:
|
313
|
+
self.sim.param_dx = dx
|
314
|
+
self.sim.param_dy = dy
|
315
|
+
else:
|
316
|
+
logging.error(_("Simulation not loaded"))
|
317
|
+
|
318
|
+
def set_magnetic_grid(self, dx:float, dy:float, origx:float, origy:float):
|
319
|
+
"""
|
320
|
+
Définition de la grille magnétique
|
321
|
+
|
322
|
+
:param dx: taille de maille selon X
|
323
|
+
:type dx: float
|
324
|
+
:param dy: taille de maille selon Y
|
325
|
+
:type dy: float
|
326
|
+
:param origx: origine selon X (coordonnée du noeud d'intersection)
|
327
|
+
:type origx: float
|
328
|
+
:param origy: origine selon Y (coordonnée du noeud d'intersection)
|
329
|
+
:type origy: float
|
330
|
+
"""
|
331
|
+
|
332
|
+
self.magnetic_grid = header_wolf()
|
333
|
+
self.magnetic_grid.dx = dx
|
334
|
+
self.magnetic_grid.dy = dy
|
335
|
+
|
336
|
+
self.magnetic_grid.origx = origx
|
337
|
+
self.magnetic_grid.origy = origy
|
338
|
+
|
339
|
+
def align2grid(self, x:float, y:float):
|
340
|
+
""" Alignement sur la grille magnétique """
|
341
|
+
|
342
|
+
if self.magnetic_grid is None:
|
343
|
+
return x,y
|
344
|
+
|
345
|
+
x, y = self.magnetic_grid.align2grid(x, y)
|
346
|
+
|
347
|
+
return x,y
|
348
|
+
|
349
|
+
def verify_files(self):
|
350
|
+
""" Verify the files """
|
351
|
+
|
352
|
+
nullvalues = {'nap':0, 'bathymetry':99999, 'manning':99999, 'infiltration_zones':99999, 'h':99999, 'qx':99999, 'qy':99999}
|
353
|
+
|
354
|
+
if self.is_loaded:
|
355
|
+
header = self.get_header()
|
356
|
+
ref_mask= self.sim.nap == 0
|
357
|
+
for cur in self.files_array['Characteristics']:
|
358
|
+
tmparray = self.sim.__getattribute__(cur[0])
|
359
|
+
if tmparray is None:
|
360
|
+
logging.error(_("Missing array: {0}".format(cur[0])))
|
361
|
+
return False
|
362
|
+
if tmparray.shape != (header.nbx, header.nby):
|
363
|
+
logging.error(_("Bad shape for array {0}".format(cur[0])))
|
364
|
+
return False
|
365
|
+
if np.any(tmparray[np.logical_not(ref_mask)] == nullvalues[cur[0]]):
|
366
|
+
logging.error(_("Null value found in array {0}".format(cur[0])))
|
367
|
+
return False
|
368
|
+
return True
|
369
|
+
else:
|
370
|
+
return False
|
371
|
+
|
372
|
+
|
373
|
+
def get_wizard_text(self, lang:str = 'en') -> str:
|
374
|
+
""" Get the wizard text """
|
375
|
+
|
376
|
+
wizard_steps_page1 =[
|
377
|
+
'',
|
378
|
+
'',
|
379
|
+
'',
|
380
|
+
_('Welcome to the wizard'),
|
381
|
+
'',
|
382
|
+
'',
|
383
|
+
'',
|
384
|
+
_('This wizard will guide you through the creation\nof a new simple GPU WOLF2D model'),
|
385
|
+
'',
|
386
|
+
]
|
387
|
+
|
388
|
+
wizard_steps_page2 = [
|
389
|
+
_('First of all, you need to define the model domain'),
|
390
|
+
'',
|
391
|
+
_('You can create a new polygon or select an existing one'),
|
392
|
+
'',
|
393
|
+
_('You can also create a polygon from a footprint by defining : \n - the origin (ox, oy)\n - the resolution (dx, dy)\n - the number of nodes along X and Y (nbx, nby)'),
|
394
|
+
'',
|
395
|
+
_('Or you can use a mask from the active array (e.g. a topography array)'),
|
396
|
+
"",
|
397
|
+
_('Remember that the extrnal contour cells will be forced as masked'),
|
398
|
+
]
|
399
|
+
|
400
|
+
|
401
|
+
wizard_steps_page3 = [
|
402
|
+
_('If you are working with a polygon, you must set the magnetic grid'),
|
403
|
+
'',
|
404
|
+
_('The magnetic grid is a virtual grid on which the array bounds are aligned'),
|
405
|
+
'',
|
406
|
+
_('The xmin, ymin, xmax, ymax of the polygon will be aligned on the magnetic grid'),
|
407
|
+
'',
|
408
|
+
_('It could be useful to have consistent boundaries between different simulations\n(e.g. successive river reaches)'),
|
409
|
+
]
|
410
|
+
|
411
|
+
|
412
|
+
wizard_steps_page4 = [
|
413
|
+
_('Then the model will be meshed and the arrays will be created'),
|
414
|
+
'',
|
415
|
+
_('Meshing is the process of creating the mesh of the model'),
|
416
|
+
'',
|
417
|
+
_('The mesh is the grid of nodes and elements on which the model will be solved'),
|
418
|
+
'',
|
419
|
+
_('Resulting mesh is stored in the NAP.npy file'),
|
420
|
+
'',
|
421
|
+
_('1 is an active cell and 0 is an inactive cell'),
|
422
|
+
]
|
423
|
+
|
424
|
+
wizard_steps_page5 = [
|
425
|
+
_('Then you can modify the arrays'),
|
426
|
+
'',
|
427
|
+
_('Arrays are the main data of the model'),
|
428
|
+
'',
|
429
|
+
_('They are created from the meshing results (bathymetry, manning, h, qx, qy, infiltration_zones)'),
|
430
|
+
'',
|
431
|
+
_('They are stored in the binary files\nExtensions .npy'),
|
432
|
+
'',
|
433
|
+
_('Specific types are used for each array :'),
|
434
|
+
_(' - nap : Unsigned integer - 8 bits'),
|
435
|
+
_(' - bathymetry, manning, h, qx, qy : Float 32 bits (Single precision)'),
|
436
|
+
_(' - infiltration_zones : Signed integer - 16 bits'),
|
437
|
+
'',
|
438
|
+
_('Arrays can be edited in the GUI'),
|
439
|
+
]
|
440
|
+
|
441
|
+
wizard_steps_page6 = [
|
442
|
+
_('Set the boundary conditions'),
|
443
|
+
'',
|
444
|
+
_('You can set the boundary conditions for the model'),
|
445
|
+
'',
|
446
|
+
_('Borders of the NAP array are identified as boundaries'),
|
447
|
+
'',
|
448
|
+
_('By mouse, you can select borders one by one (right click), or by using dynamic rectangle (right click and drag)'),
|
449
|
+
'',
|
450
|
+
_('Select type and values for the selected borders in the BC Manager associated to the simulation'),
|
451
|
+
]
|
452
|
+
|
453
|
+
wizard_steps_page7 = [
|
454
|
+
_('Set the infiltrations'),
|
455
|
+
'',
|
456
|
+
_('Infiltrations must be defined spatially and temporally'),
|
457
|
+
'',
|
458
|
+
_('Spatially, you must edit the infiltration zones array and set an index for the cells in each zone'),
|
459
|
+
'',
|
460
|
+
_('Temporally, you must define the chronology of the infiltrations of each zone'),
|
461
|
+
'',
|
462
|
+
_('The discharge is defined in m3/s'),
|
463
|
+
|
464
|
+
]
|
465
|
+
|
466
|
+
wizard_steps_page8 = [
|
467
|
+
_('Set the parameters'),
|
468
|
+
'',
|
469
|
+
_('You can set the parameters for the model'),
|
470
|
+
]
|
471
|
+
|
472
|
+
wizard_steps_page9 = [
|
473
|
+
_('Check errors and write the files'),
|
474
|
+
'',
|
475
|
+
_('The warnings and errors are displayed in the text area'),
|
476
|
+
'',
|
477
|
+
_('You can write the files if no errors are found'),
|
478
|
+
]
|
479
|
+
|
480
|
+
wizard_steps_page10 = [
|
481
|
+
_('Run the code'),
|
482
|
+
'',
|
483
|
+
_('You can run the code in a subprocess or manually (more flexible to choose cli options)'),
|
484
|
+
]
|
485
|
+
|
486
|
+
wizard_steps_page11 = [
|
487
|
+
_('View/Check the results'),
|
488
|
+
]
|
489
|
+
|
490
|
+
wizard_steps_page12 = [
|
491
|
+
_('That\'s all folks !'),
|
492
|
+
]
|
493
|
+
|
494
|
+
return [wizard_steps_page1, wizard_steps_page2, wizard_steps_page3, wizard_steps_page4, wizard_steps_page5, wizard_steps_page6, wizard_steps_page7, wizard_steps_page8, wizard_steps_page9, wizard_steps_page10, wizard_steps_page11, wizard_steps_page12]
|
495
|
+
|
496
|
+
def bc2txt(self) -> str:
|
497
|
+
"""" Get the text for the boundary conditions Manager """
|
498
|
+
|
499
|
+
txt = str(len(self.boundary_condition)) +"\n"
|
500
|
+
for curbc in self.boundary_condition:
|
501
|
+
txt += f"{curbc.i}\t{curbc.j}\t{curbc.direction.value}\t{curbc.ntype.value}\t{curbc.val}\n"
|
502
|
+
|
503
|
+
return txt
|
504
|
+
|
505
|
+
def check_infiltration(self) -> str:
|
506
|
+
"""
|
507
|
+
Informations sur les zones d'infiltration :
|
508
|
+
- nombre de zones dans la simulation
|
509
|
+
- nombre de cellules de chaque zone
|
510
|
+
- première maille de chaque zone
|
511
|
+
- nombre de temps énumérés dans le fichier .fil
|
512
|
+
- Warning si le nombre de zones est différent entre les fichiers .inf et .fil
|
513
|
+
|
514
|
+
"""
|
515
|
+
|
516
|
+
ret = _('inside file') + '\n'
|
517
|
+
ret += ('-----------') + '\n'
|
518
|
+
|
519
|
+
inf = self.sim.infiltration_zones
|
520
|
+
|
521
|
+
maxinf = inf.max()
|
522
|
+
ret += _('Maximum infiltration zone : ') + str(maxinf) + '\n'
|
523
|
+
for i in range(1,maxinf+1):
|
524
|
+
|
525
|
+
nb = np.sum(inf == i)
|
526
|
+
if nb>0:
|
527
|
+
indices = np.where(inf == i)
|
528
|
+
ret += f"Zone {i} : {nb} cells -- Indices (i,j) of the zone's first cell ({indices[0][0]+1} ; {indices[1][0]+1}) (1-based)\n"
|
529
|
+
else:
|
530
|
+
ret += f"Zone {i} : 0 cells\n"
|
531
|
+
|
532
|
+
ret += '\n'
|
533
|
+
|
534
|
+
ret += _('inside chronology') + '\n'
|
535
|
+
ret += ('-----------------') + '\n'
|
536
|
+
|
537
|
+
ret += f"Zones : {self.infiltration.nb_zones}" + '\n'
|
538
|
+
ret += f"Time steps : {self.infiltration.nb_steps}" + '\n'
|
539
|
+
|
540
|
+
if maxinf != self.infiltration.nb_zones:
|
541
|
+
ret += _('Warning : number of zones in chronology and array are different') + '\n'
|
542
|
+
|
543
|
+
return ret
|
544
|
+
|
545
|
+
def check_environment(self) -> list[str]:
|
546
|
+
# Info on Python Environment and wolfgpu Path and version
|
547
|
+
# -------------------------------------------------------
|
548
|
+
|
549
|
+
import sys
|
550
|
+
# Python Environment
|
551
|
+
ret = []
|
552
|
+
ret.append(' - Python version : {}'.format(sys.version))
|
553
|
+
ret.append(' - Python path : {}'.format(sys.executable))
|
554
|
+
ret.append(' - Python version info : {}'.format(sys.version_info))
|
555
|
+
|
556
|
+
# Test if wolfgpu.exe exists in script directory
|
557
|
+
# wolfgpu Path and version
|
558
|
+
PythonPath = Path(sys.executable)
|
559
|
+
site_packages = PythonPath.parent.parent / 'Lib' / 'site-packages'
|
560
|
+
wolfgpu_path = PythonPath.parent / 'wolfgpu.exe'
|
561
|
+
if wolfgpu_path.exists():
|
562
|
+
ret.append(' - Wolfgpu.exe found in : {}'.format(wolfgpu_path))
|
563
|
+
else:
|
564
|
+
ret.append(' - Wolfgpu.exe not found !')
|
565
|
+
|
566
|
+
if (site_packages / 'wolfgpu').exists():
|
567
|
+
ret.append(' - Wolfgpu package found in : {}'.format(site_packages / 'wolfgpu'))
|
568
|
+
else:
|
569
|
+
ret.append(' - Wolfgpu package not found in : {}!'.format(site_packages))
|
570
|
+
|
571
|
+
return ret
|
572
|
+
|
573
|
+
def run(self, limit_dryuploops:int= -1):
|
574
|
+
""" run the simulation in a subprocess """
|
575
|
+
from subprocess import run, Popen
|
576
|
+
|
577
|
+
if self.is_loaded:
|
578
|
+
if limit_dryuploops > 0:
|
579
|
+
Popen(['wolfgpu', '-quickrun', str(self.dir), '-limit_dryuploops', str(limit_dryuploops)], shell=False)
|
580
|
+
else:
|
581
|
+
Popen(['wolfgpu', '-quickrun', str(self.dir)], shell=False)
|
582
|
+
pass
|
583
|
+
else:
|
584
|
+
logging.error(_("Simulation not loaded"))
|
585
|
+
|
586
|
+
def write_initial_condition_from_record(self, recpath:Path = None, id_rec:int = None, destpath:Path = None):
|
587
|
+
""" Write the initial condition from a record
|
588
|
+
|
589
|
+
:param recpath: the path to the records. if None, the default path is used and 'simul_gpu_results' as result directory.
|
590
|
+
:param id_rec: the index of the record you want to start from.
|
591
|
+
:param destpath: the path where to save the initial condition. If None, the current path is used.
|
592
|
+
|
593
|
+
"""
|
594
|
+
|
595
|
+
if self.is_loaded:
|
596
|
+
self.sim.write_initial_condition_from_record(recpath, id_rec, destpath)
|
597
|
+
else:
|
598
|
+
logging.error(_("Simulation not loaded"))
|
599
|
+
|
600
|
+
def copy2dir(self, destpath:Path):
|
601
|
+
""" Copy the simulation to a directory """
|
602
|
+
|
603
|
+
if self.is_loaded:
|
604
|
+
try:
|
605
|
+
self.sim.save(destpath)
|
606
|
+
except Exception as e:
|
607
|
+
logging.error(_("Unable to copy simulation -- {e}"))
|
608
|
+
else:
|
609
|
+
logging.error(_("Simulation not loaded"))
|
610
|
+
|
611
|
+
|
612
|
+
def reload_ic(self):
|
613
|
+
""" Reload the initial conditions from the disk and store ir in the same memory space. """
|
614
|
+
tmp = np.load(self.dir / "h.npy")
|
615
|
+
self.sim._h[:,:]= tmp[:,:]
|
616
|
+
|
617
|
+
tmp = np.load(self.dir / "qx.npy")
|
618
|
+
self.sim._qx[:,:]= tmp[:,:]
|
619
|
+
|
620
|
+
tmp = np.load(self.dir / "qy.npy")
|
621
|
+
self.sim._qy[:,:]= tmp[:,:]
|
622
|
+
|
623
|
+
def reload_all(self):
|
624
|
+
""" Reload all the data from the disk and store them in the same memory space. """
|
625
|
+
tmp = np.load(self.dir / "h.npy")
|
626
|
+
self.sim._h[:,:] = tmp[:,:]
|
627
|
+
|
628
|
+
tmp = np.load(self.dir / "qx.npy")
|
629
|
+
self.sim._qx[:,:] = tmp[:,:]
|
630
|
+
|
631
|
+
tmp = np.load(self.dir / "qy.npy")
|
632
|
+
self.sim._qy[:,:]= tmp[:,:]
|
633
|
+
|
634
|
+
tmp = np.load(self.dir / "bathymetry.npy")
|
635
|
+
self.sim._bathymetry[:,:]= tmp[:,:]
|
636
|
+
|
637
|
+
tmp = np.load(self.dir / "manning.npy")
|
638
|
+
self.sim._manning[:,:]= tmp[:,:]
|
639
|
+
|
640
|
+
tmp = np.load(self.dir / "infiltration_zones.npy")
|
641
|
+
self.sim._infiltration_zones[:,:]= tmp[:,:]
|
642
|
+
|
643
|
+
tmp = np.load(self.dir / "NAP.npy")
|
644
|
+
self.sim._nap[:,:]= tmp[:,:]
|