wolfhece 2.1.99__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 +220 -29
- wolfhece/PyGui.py +1039 -53
- wolfhece/PyVertexvectors.py +2 -2
- wolfhece/Results2DGPU.py +37 -13
- wolfhece/acceptability/Parallels.py +2 -2
- wolfhece/acceptability/_add_path.py +23 -0
- wolfhece/acceptability/acceptability.py +594 -563
- wolfhece/acceptability/acceptability_gui.py +564 -331
- wolfhece/acceptability/cli.py +307 -120
- wolfhece/acceptability/func.py +1754 -1597
- wolfhece/apps/version.py +1 -1
- wolfhece/bernoulli/losses.py +76 -23
- wolfhece/bernoulli/losses_jax.py +143 -0
- wolfhece/bernoulli/pipe.py +7 -2
- wolfhece/gpuview.py +4 -1
- wolfhece/libs/__init__.py +11 -10
- wolfhece/libs/wolfogl.cp310-win_amd64.pyd +0 -0
- wolfhece/math_parser/__init__.py +4 -4
- wolfhece/math_parser/calculator.py +51 -9
- wolfhece/mesh2d/bc_manager.py +25 -2
- wolfhece/mesh2d/gpu_2d.py +644 -0
- wolfhece/mesh2d/simple_2d.py +2817 -0
- wolfhece/mesh2d/wolf2dprev.py +5 -2
- wolfhece/pidcontroller.py +131 -0
- wolfhece/pywalous.py +7 -7
- wolfhece/scenario/config_manager.py +98 -21
- wolfhece/wolf_array.py +391 -176
- wolfhece/wolf_vrt.py +108 -7
- wolfhece/wolfresults_2D.py +113 -6
- wolfhece/xyz_file.py +91 -51
- {wolfhece-2.1.99.dist-info → wolfhece-2.1.101.dist-info}/METADATA +3 -1
- {wolfhece-2.1.99.dist-info → wolfhece-2.1.101.dist-info}/RECORD +35 -30
- {wolfhece-2.1.99.dist-info → wolfhece-2.1.101.dist-info}/WHEEL +1 -1
- {wolfhece-2.1.99.dist-info → wolfhece-2.1.101.dist-info}/entry_points.txt +0 -0
- {wolfhece-2.1.99.dist-info → wolfhece-2.1.101.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,2817 @@
|
|
1
|
+
import numpy as np
|
2
|
+
from matplotlib import pyplot as plt
|
3
|
+
from tqdm import tqdm
|
4
|
+
from numba import jit
|
5
|
+
from scipy.optimize import root_scalar
|
6
|
+
from typing import Literal
|
7
|
+
from enum import Enum
|
8
|
+
import logging
|
9
|
+
|
10
|
+
"""
|
11
|
+
Calcul des equations shallow water en 1D section rectangulaire avec frottement selon Manning
|
12
|
+
|
13
|
+
Continuity : dh/dt + d(q)/dx = 0
|
14
|
+
Momentum : dq/dt + d(q^2/h + 1/2 g h^2)/dx + g h dz/dx = -g h J
|
15
|
+
Friction Slope : J = n^2 (q/h)^2 / h^(4/3)
|
16
|
+
|
17
|
+
Discretisation :
|
18
|
+
|
19
|
+
J = n^2 q_t2 q_t1 / h^(10/3)
|
20
|
+
ghJ = q_t2 (g n^2 q_t1 / h^(7/3))
|
21
|
+
|
22
|
+
h_t2 = h_t1 - dt/dx (q_t,r - q_t,l)
|
23
|
+
q_t2 = 1/(1 + dt g n^2 q_t1 / h^(7/3)) * (q_t1 - dt/dx (q_t,r^2/h_t,r - q_t,l^2/h_t,l + 1/2 g (h_t,r^2 - h_t,l^2) + g h_center_mean (z_t,r - z_t,l))
|
24
|
+
|
25
|
+
"""
|
26
|
+
|
27
|
+
class Scenarios(Enum):
|
28
|
+
unsteady_downstream_bc = 0
|
29
|
+
hydrograph = 1
|
30
|
+
hydrograph_2steps = 2
|
31
|
+
Gauss = 3
|
32
|
+
water_lines = 4
|
33
|
+
|
34
|
+
def domain(length:float, dx:float, slope:float) -> np.ndarray:
|
35
|
+
""" Create the domain
|
36
|
+
|
37
|
+
:param length: Length of the domain
|
38
|
+
:param dx: Space step
|
39
|
+
:param slope: Slope of the domain
|
40
|
+
"""
|
41
|
+
|
42
|
+
nb = int(length/dx)
|
43
|
+
dom = np.zeros(nb+2)
|
44
|
+
x = [-dx/2.] + [(float(i)+.5)*dx for i in range(0,nb)] + [length + dx/2.]
|
45
|
+
z = -slope * np.array(x)
|
46
|
+
return dom, x, z
|
47
|
+
|
48
|
+
def _init_conditions(dom:np.ndarray, h0:float, q0:float) -> np.ndarray:
|
49
|
+
""" Initial conditions
|
50
|
+
|
51
|
+
:param dom: Domain
|
52
|
+
:param h0: Initial water depth [m]
|
53
|
+
:param q0: Initial discharge [m^2/s]
|
54
|
+
"""
|
55
|
+
|
56
|
+
h = np.zeros_like(dom)
|
57
|
+
h[1:-1] = h0
|
58
|
+
q = np.zeros_like(dom)
|
59
|
+
q[1:-1] = q0
|
60
|
+
return h, q
|
61
|
+
|
62
|
+
def get_friction_slope_2D_Manning(q:float, h:float, n:float) -> float:
|
63
|
+
""" Friction slope based on Manning formula
|
64
|
+
|
65
|
+
:param q: Discharge [m^2/s]
|
66
|
+
:param h: Water depth [m]
|
67
|
+
:param n: Manning coefficient [m^(1/3)/s]
|
68
|
+
"""
|
69
|
+
return n**2 * q**2 / h**(10/3)
|
70
|
+
|
71
|
+
def compute_dt(dx:float, h:np.ndarray, q:np.ndarray, CN:float) -> float:
|
72
|
+
""" Compute the time step according to the Courant number anf the maximum velocity
|
73
|
+
|
74
|
+
:param dx: Space step
|
75
|
+
:param h: Water depth
|
76
|
+
:param q: Discharge
|
77
|
+
:param CN: Courant number
|
78
|
+
"""
|
79
|
+
|
80
|
+
h_pos = np.where(h > 0)[0]
|
81
|
+
dt = CN * dx / (np.max(np.abs(q[h_pos]/h[h_pos]) + np.sqrt(h[h_pos]*9.81)))
|
82
|
+
return dt
|
83
|
+
|
84
|
+
def all_unk_border(dom:np.ndarray, h0:float, q0:float) -> tuple[np.ndarray]:
|
85
|
+
""" Initialize all arrays storing unknowns at center and borders
|
86
|
+
|
87
|
+
:param dom: Domain
|
88
|
+
:param h0: Initial water depth
|
89
|
+
:param q0: Initial discharge
|
90
|
+
"""
|
91
|
+
|
92
|
+
h, q = _init_conditions(dom, h0, q0)
|
93
|
+
h_pred = np.zeros_like(dom)
|
94
|
+
h_corr = np.zeros_like(dom)
|
95
|
+
q_pred = np.zeros_like(dom)
|
96
|
+
q_corr = np.zeros_like(dom)
|
97
|
+
|
98
|
+
q_border = np.zeros((len(dom), 2))
|
99
|
+
h_border = np.zeros((len(dom), 2))
|
100
|
+
z_border = np.zeros((len(dom), 2))
|
101
|
+
|
102
|
+
u_border = np.zeros(len(dom))
|
103
|
+
h_center = np.zeros(len(dom)-2)
|
104
|
+
u_center = np.zeros(len(dom)-2)
|
105
|
+
|
106
|
+
return h, q, h_pred, q_pred, h_corr, q_corr, q_border, h_border, z_border, u_border, h_center, u_center
|
107
|
+
|
108
|
+
def uniform_waterdepth(slope:float, q:float, n:float):
|
109
|
+
""" Compute the uniform water depth for a given slope, discharge and Manning coefficient
|
110
|
+
|
111
|
+
:param slope: Slope
|
112
|
+
:param q: Discharge [m^2/s]
|
113
|
+
:param n: Manning coefficient
|
114
|
+
"""
|
115
|
+
|
116
|
+
if n==0. or slope==0.:
|
117
|
+
logging.error("Manning coefficient or slope cannot be null")
|
118
|
+
logging.warning("Return 99999.")
|
119
|
+
return 99999.
|
120
|
+
|
121
|
+
return root_scalar(lambda h: slope - get_friction_slope_2D_Manning(q, h, n), bracket=[0.1, 100.]).root
|
122
|
+
|
123
|
+
# -----------------
|
124
|
+
# LOSS Coefficients
|
125
|
+
# -----------------
|
126
|
+
|
127
|
+
def k_abrupt_enlargment(asmall:float, alarge:float) -> float:
|
128
|
+
""" Compute the local head loss coefficient of the abrupt enlargment
|
129
|
+
|
130
|
+
:params asmall: float, area of the section 1 -- smaller section
|
131
|
+
:params alarge: float, area of the section 2 -- larger section
|
132
|
+
"""
|
133
|
+
|
134
|
+
return (1 - asmall/alarge)**2
|
135
|
+
|
136
|
+
def k_abrupt_contraction(alarge:float, asmall:float) -> float:
|
137
|
+
""" Compute the local head loss coefficient of the abrupt contraction
|
138
|
+
|
139
|
+
:params alarge: float, area of the section 1 -- larger section
|
140
|
+
:params asmall: float, area of the section 2 -- smaller section
|
141
|
+
"""
|
142
|
+
|
143
|
+
return .5*(1 - asmall/alarge)
|
144
|
+
|
145
|
+
def head_loss_enlargment(q:float, asmall:float, alarge:float) -> float:
|
146
|
+
""" Compute the head loss of the enlargment.
|
147
|
+
|
148
|
+
Reference velocity is the velocity in the smaller section.
|
149
|
+
|
150
|
+
:params q: float, discharge
|
151
|
+
:params asmall: float, area of the section 1 -- smaller section
|
152
|
+
:params alarge: float, area of the section 2 -- larger section
|
153
|
+
"""
|
154
|
+
|
155
|
+
return k_abrupt_enlargment(asmall, alarge) * (q/asmall)**2 / 2 / 9.81
|
156
|
+
|
157
|
+
def head_loss_contraction(q:float, alarge:float, asmall:float) -> float:
|
158
|
+
""" Compute the head loss of the contraction.
|
159
|
+
|
160
|
+
Reference velocity is the velocity in the smaller section.
|
161
|
+
|
162
|
+
:params q: float, discharge
|
163
|
+
:params alarge: float, area of the section 1 -- larger section
|
164
|
+
:params asmall: float, area of the section 2 -- smaller section
|
165
|
+
"""
|
166
|
+
|
167
|
+
return k_abrupt_contraction(alarge, asmall) * (q/asmall)**2 / 2 / 9.81
|
168
|
+
|
169
|
+
def head_loss_contract_enlarge(q:float, a_up:float, asmall:float, a_down:float) -> float:
|
170
|
+
""" Compute the head loss of the contraction/enlargment.
|
171
|
+
|
172
|
+
Reference velocity is the velocity in the smaller section.
|
173
|
+
|
174
|
+
:params q: float, discharge
|
175
|
+
:params a_up: float, area of the section 1 -- larger section
|
176
|
+
:params asmall: float, area of the section 2 -- smaller section
|
177
|
+
:params a_down: float, area of the section 3 -- larger section
|
178
|
+
"""
|
179
|
+
|
180
|
+
return (k_abrupt_enlargment(asmall, a_down) + k_abrupt_contraction(a_up, asmall)) * (q/asmall)**2 / 2 / 9.81
|
181
|
+
|
182
|
+
# ----------------------------
|
183
|
+
# START JIT compiled functions
|
184
|
+
# ----------------------------
|
185
|
+
|
186
|
+
@jit(nopython=True)
|
187
|
+
def get_friction_slope_2D_Manning_semi_implicit(u:np.ndarray, h:np.ndarray, n:float) -> np.ndarray:
|
188
|
+
""" Friction slope based on Manning formula -- Only semi-implicit formulea for the friction slope
|
189
|
+
|
190
|
+
:param u: Velocity [m/s]
|
191
|
+
:param h: Water depth [m]
|
192
|
+
:param n: Manning coefficient [m^(1/3)/s]
|
193
|
+
"""
|
194
|
+
|
195
|
+
return n**2 * np.abs(u) / h**(7/3)
|
196
|
+
|
197
|
+
@jit(nopython=True)
|
198
|
+
def Euler_RK(h_t1:np.ndarray, h_t2:np.ndarray,
|
199
|
+
q_t1:np.ndarray, q_t2:np.ndarray,
|
200
|
+
h:np.ndarray, q:np.ndarray,
|
201
|
+
h_border:np.ndarray, q_border:np.ndarray,
|
202
|
+
z:np.ndarray, z_border:np.ndarray,
|
203
|
+
dt:float, dx:float,
|
204
|
+
CL_h:float, CL_q:float,
|
205
|
+
n:float, u_border:np.ndarray,
|
206
|
+
h_center:np.ndarray, u_center:np.ndarray) -> None:
|
207
|
+
""" Solve the mass and momentum equations using a explicit Euler/Runge-Kutta scheme (only 1 step)
|
208
|
+
|
209
|
+
:param h_t1: Water depth at time t
|
210
|
+
:param h_t2: Water depth at time t+dt (or t_star or t_doublestar if RK)
|
211
|
+
:param q_t1: Discharge at time t
|
212
|
+
:param q_t2: Discharge at time t+dt (or t_star or t_doublestar if RK)
|
213
|
+
:param h: Water depth at the mesh center
|
214
|
+
:param q: Discharge at the mesh center
|
215
|
+
:param h_border: Water depth at the mesh border
|
216
|
+
:param q_border: Discharge at the mesh border
|
217
|
+
:param z: Bed elevation
|
218
|
+
:param z_border: Bed elevation at the mesh border
|
219
|
+
:param dt: Time step
|
220
|
+
:param dx: Space step
|
221
|
+
:param CL_h: Downstream boudary condition for water depth
|
222
|
+
:param CL_q: Upstream boundary condition for discharge
|
223
|
+
:param n: Manning coefficient
|
224
|
+
:param u_border: Velocity at the mesh border
|
225
|
+
:param h_center: Water depth at the mesh center
|
226
|
+
:param u_center: Velocity at the mesh center
|
227
|
+
"""
|
228
|
+
|
229
|
+
g = 9.81
|
230
|
+
|
231
|
+
slice_mesh = slice(1,-1)
|
232
|
+
slice_right_border = slice(2,None)
|
233
|
+
slice_left_border = slice(1,-1)
|
234
|
+
|
235
|
+
up = 0
|
236
|
+
do = 1
|
237
|
+
|
238
|
+
# valeur à gauche du bord
|
239
|
+
q_border[slice_right_border, up] = q[1:-1]
|
240
|
+
q_border[1,up] = CL_q
|
241
|
+
|
242
|
+
h_border[slice_right_border, up] = h[1:-1]
|
243
|
+
h_border[1,up] = h[1]
|
244
|
+
|
245
|
+
z_border[slice_right_border, up] = z[1:-1]
|
246
|
+
z_border[1,up] = z[1]
|
247
|
+
|
248
|
+
# valeur à droite du bord
|
249
|
+
q_border[slice_left_border, do] = q[1:-1]
|
250
|
+
q_border[-1,do] = q[-2]
|
251
|
+
|
252
|
+
h_border[slice_left_border, do] = h[1:-1]
|
253
|
+
h_border[-1,do] = CL_h
|
254
|
+
|
255
|
+
z_border[slice_left_border, do] = z[1:-1]
|
256
|
+
z_border[-1,do] = z[-2]
|
257
|
+
|
258
|
+
u_border[1:] = q_border[1:,up]/h_border[1:,up]
|
259
|
+
|
260
|
+
h_center = (h_border[slice_right_border,do] + h_border[slice_left_border,do])/2.
|
261
|
+
u_center = q[slice_mesh]/h[slice_mesh]
|
262
|
+
|
263
|
+
#Continuity
|
264
|
+
h_t2[slice_mesh] = h_t1[slice_mesh] - dt/dx * (q_border[slice_right_border,up] - q_border[slice_left_border,up])
|
265
|
+
|
266
|
+
# Momentum
|
267
|
+
|
268
|
+
J = get_friction_slope_2D_Manning_semi_implicit(u_center, h[slice_mesh], n)
|
269
|
+
qm_right = u_border[slice_right_border]*q_border[slice_right_border,up]
|
270
|
+
qm_left = u_border[slice_left_border]*q_border[slice_left_border,up]
|
271
|
+
|
272
|
+
press_right = 0.5 * g * h_border[slice_right_border,do]**2
|
273
|
+
press_left = 0.5 * g * h_border[slice_left_border,do]**2
|
274
|
+
|
275
|
+
bed_right = g * h_center * z_border[slice_right_border,do]
|
276
|
+
bed_left = g * h_center * z_border[slice_left_border,do]
|
277
|
+
|
278
|
+
q_t2[slice_mesh] = 1./(1. + dt * g *h[slice_mesh] * J) * (q_t1[slice_mesh] - dt/dx * (qm_right - qm_left + press_right - press_left + bed_right - bed_left))
|
279
|
+
|
280
|
+
limit_h_q(h_t2, q_t2, hmin=1e-3, Froudemax=3.)
|
281
|
+
|
282
|
+
@jit(nopython=True)
|
283
|
+
def Euler_RK_hedge(h_t1:np.ndarray, h_t2:np.ndarray,
|
284
|
+
q_t1:np.ndarray, q_t2:np.ndarray,
|
285
|
+
h:np.ndarray, q:np.ndarray,
|
286
|
+
h_border:np.ndarray, q_border:np.ndarray,
|
287
|
+
z:np.ndarray, z_border:np.ndarray,
|
288
|
+
dt:float, dx:float,
|
289
|
+
CL_h:float, CL_q:float,
|
290
|
+
n:float, u_border:np.ndarray,
|
291
|
+
h_center:np.ndarray, u_center:np.ndarray,
|
292
|
+
theta:np.ndarray, theta_border:np.ndarray) -> None:
|
293
|
+
""" Solve the mass and momentum equations using a explicit Euler/Runge-Kutta scheme (only 1 step)
|
294
|
+
|
295
|
+
:param h_t1: Water depth at time t
|
296
|
+
:param h_t2: Water depth at time t+dt (or t_star or t_doublestar if RK)
|
297
|
+
:param q_t1: Discharge at time t
|
298
|
+
:param q_t2: Discharge at time t+dt (or t_star or t_doublestar if RK)
|
299
|
+
:param h: Water depth at the mesh center
|
300
|
+
:param q: Discharge at the mesh center
|
301
|
+
:param h_border: Water depth at the mesh border
|
302
|
+
:param q_border: Discharge at the mesh border
|
303
|
+
:param z: Bed elevation
|
304
|
+
:param z_border: Bed elevation at the mesh border
|
305
|
+
:param dt: Time step
|
306
|
+
:param dx: Space step
|
307
|
+
:param CL_h: Downstream boudary condition for water depth
|
308
|
+
:param CL_q: Upstream boundary condition for discharge
|
309
|
+
:param n: Manning coefficient
|
310
|
+
:param u_border: Velocity at the mesh border
|
311
|
+
:param h_center: Water depth at the mesh center
|
312
|
+
:param u_center: Velocity at the mesh center
|
313
|
+
"""
|
314
|
+
|
315
|
+
g = 9.81
|
316
|
+
|
317
|
+
slice_mesh = slice(1,-1)
|
318
|
+
slice_right_border = slice(2,None)
|
319
|
+
slice_left_border = slice(1,-1)
|
320
|
+
|
321
|
+
up = 0
|
322
|
+
do = 1
|
323
|
+
|
324
|
+
# valeur à gauche du bord
|
325
|
+
q_border[slice_right_border, up] = q[1:-1]
|
326
|
+
q_border[1,up] = CL_q
|
327
|
+
|
328
|
+
h_border[slice_right_border, up] = h[1:-1]
|
329
|
+
h_border[1,up] = h[1]
|
330
|
+
|
331
|
+
z_border[slice_right_border, up] = z[1:-1]
|
332
|
+
z_border[1,up] = z[1]
|
333
|
+
|
334
|
+
theta_border[slice_right_border, up] = theta[1:-1]
|
335
|
+
theta_border[1,up] = theta[1]
|
336
|
+
|
337
|
+
# valeur à droite du bord
|
338
|
+
q_border[slice_left_border, do] = q[1:-1]
|
339
|
+
q_border[-1,do] = q[-2]
|
340
|
+
|
341
|
+
h_border[slice_left_border, do] = h[1:-1]
|
342
|
+
h_border[-1,do] = CL_h
|
343
|
+
|
344
|
+
z_border[slice_left_border, do] = z[1:-1]
|
345
|
+
z_border[-1,do] = z[-2]
|
346
|
+
|
347
|
+
theta_border[slice_left_border, do] = theta[1:-1]
|
348
|
+
theta_border[-1,do] = theta[-2]
|
349
|
+
|
350
|
+
|
351
|
+
u_border[1:] = q_border[1:,up]/(h_border[1:,up] * theta_border[1:,up])
|
352
|
+
|
353
|
+
h_center = (theta_border[slice_right_border,do] * h_border[slice_right_border,do] + theta_border[slice_left_border,do] * h_border[slice_left_border,do])/2.
|
354
|
+
u_center = q[slice_mesh]/(h[slice_mesh]*theta[slice_mesh])
|
355
|
+
|
356
|
+
#Continuity
|
357
|
+
h_t2[slice_mesh] = h_t1[slice_mesh] - dt/dx * (q_border[slice_right_border,up] - q_border[slice_left_border,up])
|
358
|
+
|
359
|
+
# Momentum
|
360
|
+
|
361
|
+
J = get_friction_slope_2D_Manning_semi_implicit(u_center, h[slice_mesh], n)
|
362
|
+
qm_right = u_border[slice_right_border]*q_border[slice_right_border,up]
|
363
|
+
qm_left = u_border[slice_left_border ]*q_border[slice_left_border,up]
|
364
|
+
|
365
|
+
press_right = 0.5 * g * (theta_border[slice_right_border,do] * h_border[slice_right_border,do])**2
|
366
|
+
press_left = 0.5 * g * (theta_border[slice_left_border ,do] * h_border[slice_left_border ,do])**2
|
367
|
+
|
368
|
+
bed_right = g * h_center * (z_border[slice_right_border,do] + (1-theta_border[slice_right_border,do]) * h_border[slice_right_border,do])
|
369
|
+
bed_left = g * h_center * (z_border[slice_left_border,do] + (1-theta_border[slice_left_border,do]) * h_border[slice_left_border,do])
|
370
|
+
|
371
|
+
q_t2[slice_mesh] = 1./(1. + dt * g *h[slice_mesh] * J) * (q_t1[slice_mesh] - dt/dx * (qm_right - qm_left + press_right - press_left + bed_right - bed_left))
|
372
|
+
|
373
|
+
limit_h_q(h_t2, q_t2, hmin=1e-3, Froudemax=3.)
|
374
|
+
|
375
|
+
|
376
|
+
@jit(nopython=True)
|
377
|
+
def splitting(q_left:np.float64, q_right:np.float64,
|
378
|
+
h_left:np.float64, h_right:np.float64,
|
379
|
+
z_left:np.float64, z_right:np.float64,
|
380
|
+
z_bridge_left:np.float64, z_bridge_right:np.float64) -> np.ndarray:
|
381
|
+
""" Splitting of the unknowns at border between two nodes
|
382
|
+
-- Based on the WOLF HECE original scheme
|
383
|
+
"""
|
384
|
+
|
385
|
+
prod_q = q_left * q_right
|
386
|
+
sum_q = q_left + q_right
|
387
|
+
|
388
|
+
if prod_q > 0.:
|
389
|
+
if q_left > 0.:
|
390
|
+
return np.asarray([q_left, min(h_left, z_bridge_left-z_left), h_right, z_right, z_bridge_right], dtype=np.float64)
|
391
|
+
else:
|
392
|
+
return np.asarray([q_right, min(h_right, z_bridge_right-z_right), h_left, z_left, z_bridge_left], dtype=np.float64)
|
393
|
+
elif prod_q < 0.:
|
394
|
+
if sum_q > 0.:
|
395
|
+
return np.asarray([q_left, min(h_left, z_bridge_left-z_left), h_right, z_right, z_bridge_right], dtype=np.float64)
|
396
|
+
elif sum_q < 0.:
|
397
|
+
return np.asarray([q_right, min(h_right, z_bridge_right-z_right), h_left, z_left, z_bridge_left], dtype=np.float64)
|
398
|
+
else:
|
399
|
+
return np.asarray([0., 1., (h_left + h_right) / 2., (z_left + z_right) / 2., (z_bridge_left + z_bridge_right) / 2.], dtype=np.float64)
|
400
|
+
else:
|
401
|
+
if q_left<0.:
|
402
|
+
return np.asarray([np.float64(0.), np.float64(1.), h_left, z_left, z_bridge_left], dtype=np.float64)
|
403
|
+
elif q_right<0.:
|
404
|
+
return np.asarray([np.float64(0.), np.float64(1.), h_right, z_right, z_bridge_right], dtype=np.float64)
|
405
|
+
else:
|
406
|
+
return np.asarray([sum_q / 2., # q
|
407
|
+
(min(h_left, z_bridge_left-z_left) + min(h_right, z_bridge_right-z_right)) / 2., # h_vel
|
408
|
+
(h_left + h_right) / 2., # h
|
409
|
+
(z_left + z_right) / 2., # z
|
410
|
+
(z_bridge_left + z_bridge_right) / 2.], dtype=np.float64) # z_bridge
|
411
|
+
|
412
|
+
|
413
|
+
@jit(nopython=True)
|
414
|
+
def Euler_RK_bridge(h_t1:np.ndarray, h_t2:np.ndarray,
|
415
|
+
q_t1:np.ndarray, q_t2:np.ndarray,
|
416
|
+
h:np.ndarray, q:np.ndarray,
|
417
|
+
h_border:np.ndarray, q_border:np.ndarray,
|
418
|
+
z:np.ndarray, z_border:np.ndarray,
|
419
|
+
dt:float, dx:float,
|
420
|
+
CL_h:float, CL_q:float,
|
421
|
+
n:float, u_border:np.ndarray,
|
422
|
+
h_center:np.ndarray, u_center:np.ndarray,
|
423
|
+
z_bridge:np.ndarray, z_bridge_border:np.ndarray,
|
424
|
+
press_mode:int=0,
|
425
|
+
infil_exfil=None) -> None:
|
426
|
+
"""
|
427
|
+
Solve the mass and momentum equations using a explicit Euler/Runge-Kutta scheme (only 1 step)
|
428
|
+
applying source terms for infiltration/exfiltration and pressure at the roof.
|
429
|
+
"""
|
430
|
+
g = 9.81
|
431
|
+
|
432
|
+
slice_mesh = slice(1,-1)
|
433
|
+
slice_right_border = slice(2,None)
|
434
|
+
slice_left_border = slice(1,-1)
|
435
|
+
|
436
|
+
up = 0
|
437
|
+
do = 1
|
438
|
+
|
439
|
+
# valeur à gauche du bord
|
440
|
+
z_border[slice_right_border, up] = z[1:-1]
|
441
|
+
z_border[1,up] = z[1]
|
442
|
+
|
443
|
+
z_bridge_copy = z_bridge.copy()
|
444
|
+
|
445
|
+
fs_cells = np.where(h <= z_bridge - z)[0]
|
446
|
+
press_cells = np.where(h > z_bridge - z)[0]
|
447
|
+
|
448
|
+
z_bridge_copy[fs_cells] = z[fs_cells] + h[fs_cells]
|
449
|
+
|
450
|
+
h_border[slice_right_border, up] = h[1:-1]
|
451
|
+
h_border[1,up] = h[1]
|
452
|
+
|
453
|
+
q_border[slice_right_border, up] = q[1:-1]
|
454
|
+
q_border[1,up] = CL_q
|
455
|
+
|
456
|
+
# valeur à droite du bord
|
457
|
+
z_border[slice_left_border, do] = z[1:-1]
|
458
|
+
z_border[-1,do] = z[-2]
|
459
|
+
|
460
|
+
z_bridge_border[slice_right_border, up] = z_bridge_copy[1:-1]
|
461
|
+
z_bridge_border[1,up] = z_bridge_copy[1]
|
462
|
+
|
463
|
+
z_bridge_border[slice_left_border, do] = z_bridge_copy[1:-1]
|
464
|
+
z_bridge_border[-1,do] = z_bridge_copy[-2]
|
465
|
+
|
466
|
+
h_border[slice_left_border, do] = h[1:-1]
|
467
|
+
h_border[-1,do] = CL_h
|
468
|
+
|
469
|
+
q_border[slice_left_border, do] = q[1:-1]
|
470
|
+
q_border[-1,do] = q[-2]
|
471
|
+
|
472
|
+
|
473
|
+
|
474
|
+
for i in range(1, len(h)-1):
|
475
|
+
|
476
|
+
qc_right, h4u_right, hc_right, zc_right, zbc_right = splitting(q_border[i+1,up], q_border[i+1, do], h_border[i+1,up], h_border[i+1,do], z_border[i+1,up], z_border[i+1,do], z_bridge_border[i+1,up], z_bridge_border[i+1,do])
|
477
|
+
qc_left, h4u_left, hc_left, zc_left, zbc_left = splitting(q_border[i,up], q_border[i, do], h_border[i,up], h_border[i,do], z_border[i,up], z_border[i,do], z_bridge_border[i,up], z_bridge_border[i,do])
|
478
|
+
|
479
|
+
# Continuity
|
480
|
+
# ++++++++++
|
481
|
+
|
482
|
+
h_t2[i] = h_t1[i] - dt/dx * (qc_right - qc_left)
|
483
|
+
|
484
|
+
# Momentum
|
485
|
+
# ++++++++
|
486
|
+
|
487
|
+
# Limited section at the right border and at the left border -- decentred downstream
|
488
|
+
d_right = zbc_right - zc_right
|
489
|
+
d_left = zbc_left - zc_left
|
490
|
+
|
491
|
+
# Pressure on the roof -- 0. if free surface
|
492
|
+
press_roof_right = hc_right - d_right
|
493
|
+
press_roof_left = hc_left - d_left
|
494
|
+
|
495
|
+
# Pressure integral at the right border and at the left border
|
496
|
+
press_right = 0.5 * g * (hc_right**2. - press_roof_right**2)
|
497
|
+
press_left = 0.5 * g * (hc_left**2. - press_roof_left**2)
|
498
|
+
|
499
|
+
# Friction slope based on center values
|
500
|
+
u_center = q[i] / (z_bridge_copy[i] - z[i])
|
501
|
+
# Number of surfaces
|
502
|
+
nb_frott = 2. if h[i] > z_bridge[i] - z[i] else 1.
|
503
|
+
# Integration water depth
|
504
|
+
h_frott = min(h[i], z_bridge[i] - z[i])
|
505
|
+
# Slope
|
506
|
+
J = get_friction_slope_2D_Manning_semi_implicit(u_center, h_frott/nb_frott, n)
|
507
|
+
|
508
|
+
# Velocity at the right border and at the left border -- decentred upstream
|
509
|
+
u_right = qc_right / h4u_right
|
510
|
+
u_left = qc_left / h4u_left
|
511
|
+
|
512
|
+
# Momentum at the right border and at the left border
|
513
|
+
qm_right = u_right * qc_right
|
514
|
+
qm_left = u_left * qc_left
|
515
|
+
|
516
|
+
# Mean pressure impacting bed reaction
|
517
|
+
h_mean = (hc_right + hc_left)/2.
|
518
|
+
bed_right = g * h_mean * zc_right
|
519
|
+
bed_left = g * h_mean * zc_left
|
520
|
+
|
521
|
+
# Mean pressure impacting roof reaction
|
522
|
+
h_roof_right = max(hc_right + zc_right - zbc_right, 0.)
|
523
|
+
h_roof_left = max(hc_left + zc_left - zbc_left , 0.)
|
524
|
+
h_roof_mean = (h_roof_right + h_roof_left) / 2.
|
525
|
+
|
526
|
+
roof_right = g * h_roof_mean * zbc_right
|
527
|
+
roof_left = g * h_roof_mean * zbc_left
|
528
|
+
|
529
|
+
rhs = (qm_right - qm_left + press_right - press_left + bed_right - bed_left - roof_right + roof_left)
|
530
|
+
|
531
|
+
if rhs !=0.:
|
532
|
+
pass
|
533
|
+
|
534
|
+
q_t2[i] = 1./(1. + dt * g * h_frott * J) * (q_t1[i] - dt/dx * rhs)
|
535
|
+
|
536
|
+
if infil_exfil is not None:
|
537
|
+
idx_up, idx_do, q_infil_exfil, u_infil_exfil, pond, k = infil_exfil
|
538
|
+
|
539
|
+
i = idx_up
|
540
|
+
|
541
|
+
qc_right, h4u_right, hc_right, zc_right, zbc_right = splitting(q_border[i+1,up], q_border[i+1, do], h_border[i+1,up], h_border[i+1,do], z_border[i+1,up], z_border[i+1,do], z_bridge_border[i+1,up], z_bridge_border[i+1,do])
|
542
|
+
qc_left, h4u_left, hc_left, zc_left, zbc_left = splitting(q_border[i,up], q_border[i, do], h_border[i,up], h_border[i,do], z_border[i,up], z_border[i,do], z_bridge_border[i,up], z_bridge_border[i,do])
|
543
|
+
|
544
|
+
# Limited section at the right border and at the left border -- decentred downstream
|
545
|
+
d_right = zbc_right - zc_right
|
546
|
+
d_left = zbc_left - zc_left
|
547
|
+
|
548
|
+
# Pressure on the roof -- 0. if free surface
|
549
|
+
press_roof_right = hc_right - d_right
|
550
|
+
press_roof_left = hc_left - d_left
|
551
|
+
|
552
|
+
# Pressure integral at the right border and at the left border
|
553
|
+
press_right = 0.5 * g * (hc_right**2. - press_roof_right**2)
|
554
|
+
press_left = 0.5 * g * (hc_left**2. - press_roof_left**2)
|
555
|
+
|
556
|
+
# Friction slope based on center values
|
557
|
+
u_center = q[i] / (z_bridge_copy[i] - z[i])
|
558
|
+
# Number of surfaces
|
559
|
+
nb_frott = 2. if h[i] > z_bridge[i] - z[i] else 1.
|
560
|
+
# Integration water depth
|
561
|
+
h_frott = min(h[i], z_bridge[i] - z[i])
|
562
|
+
# Slope
|
563
|
+
J = get_friction_slope_2D_Manning_semi_implicit(u_center, h_frott/nb_frott, n)
|
564
|
+
|
565
|
+
# Velocity at the right border and at the left border -- decentred upstream
|
566
|
+
u_right = qc_right / h4u_right
|
567
|
+
u_left = qc_left / h4u_left
|
568
|
+
|
569
|
+
# Momentum at the right border and at the left border
|
570
|
+
qm_right = u_right * qc_right
|
571
|
+
qm_left = u_left * qc_left
|
572
|
+
|
573
|
+
# Mean pressure impacting bed reaction
|
574
|
+
h_mean = (hc_right + hc_left)/2.
|
575
|
+
bed_right = g * h_mean * zc_right
|
576
|
+
bed_left = g * h_mean * zc_left
|
577
|
+
|
578
|
+
# Mean pressure impacting roof reaction
|
579
|
+
h_roof_right = max(hc_right + zc_right - zbc_right, 0.)
|
580
|
+
h_roof_left = max(hc_left + zc_left - zbc_left , 0.)
|
581
|
+
h_roof_mean = (h_roof_right + h_roof_left) / 2.
|
582
|
+
|
583
|
+
roof_right = g * h_roof_mean * zbc_right
|
584
|
+
roof_left = g * h_roof_mean * zbc_left
|
585
|
+
|
586
|
+
h_t2[i] = h_t1[i] - dt/dx * (qc_right - qc_left + q_infil_exfil)
|
587
|
+
q_t2[i] = 1./(1. + dt * g * h_frott * J) * (q_t1[i] - dt/dx * (qm_right - qm_left + \
|
588
|
+
press_right - press_left + \
|
589
|
+
bed_right - bed_left - \
|
590
|
+
roof_right + roof_left + \
|
591
|
+
u_infil_exfil * q_infil_exfil))
|
592
|
+
|
593
|
+
i = idx_do
|
594
|
+
|
595
|
+
qc_right, h4u_right, hc_right, zc_right, zbc_right = splitting(q_border[i+1,up], q_border[i+1, do], h_border[i+1,up], h_border[i+1,do], z_border[i+1,up], z_border[i+1,do], z_bridge_border[i+1,up], z_bridge_border[i+1,do])
|
596
|
+
qc_left, h4u_left, hc_left, zc_left, zbc_left = splitting(q_border[i,up], q_border[i, do], h_border[i,up], h_border[i,do], z_border[i,up], z_border[i,do], z_bridge_border[i,up], z_bridge_border[i,do])
|
597
|
+
|
598
|
+
# Limited section at the right border and at the left border -- decentred downstream
|
599
|
+
d_right = zbc_right - zc_right
|
600
|
+
d_left = zbc_left - zc_left
|
601
|
+
|
602
|
+
# Pressure on the roof -- 0. if free surface
|
603
|
+
press_roof_right = hc_right - d_right
|
604
|
+
press_roof_left = hc_left - d_left
|
605
|
+
|
606
|
+
# Pressure integral at the right border and at the left border
|
607
|
+
press_right = 0.5 * g * (hc_right**2. - press_roof_right**2)
|
608
|
+
press_left = 0.5 * g * (hc_left**2. - press_roof_left**2)
|
609
|
+
|
610
|
+
# Friction slope based on center values
|
611
|
+
u_center = q[i] / (z_bridge_copy[i] - z[i])
|
612
|
+
# Number of surfaces
|
613
|
+
nb_frott = 2. if h[i] > z_bridge[i] - z[i] else 1.
|
614
|
+
# Integration water depth
|
615
|
+
h_frott = min(h[i], z_bridge[i] - z[i])
|
616
|
+
# Slope
|
617
|
+
J = get_friction_slope_2D_Manning_semi_implicit(u_center, h_frott/nb_frott, n)
|
618
|
+
|
619
|
+
# Velocity at the right border and at the left border -- decentred upstream
|
620
|
+
u_right = qc_right / h4u_right
|
621
|
+
u_left = qc_left / h4u_left
|
622
|
+
|
623
|
+
# Momentum at the right border and at the left border
|
624
|
+
qm_right = u_right * qc_right
|
625
|
+
qm_left = u_left * qc_left
|
626
|
+
|
627
|
+
# Mean pressure impacting bed reaction
|
628
|
+
h_mean = (hc_right + hc_left)/2.
|
629
|
+
bed_right = g * h_mean * zc_right
|
630
|
+
bed_left = g * h_mean * zc_left
|
631
|
+
|
632
|
+
# Mean pressure impacting roof reaction
|
633
|
+
h_roof_right = max(hc_right + zc_right - zbc_right, 0.)
|
634
|
+
h_roof_left = max(hc_left + zc_left - zbc_left , 0.)
|
635
|
+
h_roof_mean = (h_roof_right + h_roof_left) / 2.
|
636
|
+
|
637
|
+
roof_right = g * h_roof_mean * zbc_right
|
638
|
+
roof_left = g * h_roof_mean * zbc_left
|
639
|
+
|
640
|
+
h_t2[i] = h_t1[i] - dt/dx * (qc_right - qc_left - q_infil_exfil)
|
641
|
+
q_t2[i] = 1./(1. + dt * g * h_frott * J) * (q_t1[i] - dt/dx * (qm_right - qm_left + \
|
642
|
+
press_right - press_left + \
|
643
|
+
bed_right - bed_left - \
|
644
|
+
roof_right + roof_left -\
|
645
|
+
u_infil_exfil * q_infil_exfil))
|
646
|
+
|
647
|
+
limit_h_q(h_t2, q_t2, hmin=1e-3, Froudemax=3.)
|
648
|
+
|
649
|
+
@ jit(nopython=True)
|
650
|
+
def limit_h_q(h:np.ndarray, q:np.ndarray, hmin:float = 0., Froudemax:float = 3.) -> None:
|
651
|
+
""" Limit the water depth and the discharge
|
652
|
+
|
653
|
+
:param h: Water depth [m]
|
654
|
+
:param q: Discharge [m^2/s]
|
655
|
+
:param hmin: Minimum water depth [m]
|
656
|
+
:param Froudemax: Maximum Froude number [-]
|
657
|
+
"""
|
658
|
+
|
659
|
+
# retrieve positive and negative values
|
660
|
+
hpos = np.where(h > hmin)
|
661
|
+
hneg = np.where(h <= hmin)
|
662
|
+
|
663
|
+
# limit water depth
|
664
|
+
h[hneg] = hmin
|
665
|
+
q[hneg] = 0.
|
666
|
+
|
667
|
+
# limit discharge based on Froude number
|
668
|
+
Fr = np.zeros_like(h)
|
669
|
+
Fr[hpos] = np.abs(q[hpos]) / h[hpos] / np.sqrt(9.81 * h[hpos])
|
670
|
+
q[Fr > Froudemax] = Froudemax * np.sqrt(9.81 * h[Fr > Froudemax]) * h[Fr > Froudemax] * np.sign(q[Fr > Froudemax])
|
671
|
+
|
672
|
+
# --------------------------
|
673
|
+
# END JIT compiled functions
|
674
|
+
# --------------------------
|
675
|
+
|
676
|
+
# ----------------------
|
677
|
+
# START Problems section
|
678
|
+
# ----------------------
|
679
|
+
|
680
|
+
def problem(dom:np.ndarray, z:np.ndarray, h0:float, q0:float, dx:float, CN:float, n:float):
|
681
|
+
""" Solve the mass and momentum equations using a explicit Runge-Kutta scheme (2 steps - 2nd order)
|
682
|
+
|
683
|
+
**NO BRIDGE**
|
684
|
+
"""
|
685
|
+
|
686
|
+
h, q, h_pred, q_pred, h_corr, q_corr, q_border, h_border, z_border, u_border, h_center, u_center = all_unk_border(dom, h0, q0)
|
687
|
+
|
688
|
+
totaltime = 4*3600
|
689
|
+
eps=1.
|
690
|
+
|
691
|
+
with tqdm(total=totaltime) as pbar:
|
692
|
+
t = 0.
|
693
|
+
while eps > 1e-12:
|
694
|
+
dt = compute_dt(dx, h, q, CN)
|
695
|
+
# Predictor step
|
696
|
+
Euler_RK(h, h_pred, q, q_pred, h, q, h_border, q_border, z, z_border, dt, dx, h0, q0, n, u_border, h_center, u_center)
|
697
|
+
# Corrector step
|
698
|
+
Euler_RK(h, h_corr, q, q_corr, h_pred, q_pred, h_border, q_border, z, z_border, dt, dx, h0, q0, n, u_border, h_center, u_center)
|
699
|
+
|
700
|
+
# Update -- Mean for second order in time
|
701
|
+
h = (h_pred + h_corr)/2.
|
702
|
+
q = (q_pred + q_corr)/2.
|
703
|
+
t+=dt
|
704
|
+
|
705
|
+
eps = np.sum(np.abs(q - q_pred))
|
706
|
+
|
707
|
+
pbar.update(dt)
|
708
|
+
|
709
|
+
print("Total time : ", t)
|
710
|
+
print("Residual : ", eps)
|
711
|
+
|
712
|
+
return h, q
|
713
|
+
|
714
|
+
def problem_hedge(dom:np.ndarray, z:np.ndarray, h0:float, q0:float, dx:float, CN:float, n:float):
|
715
|
+
""" Solve the mass and momentum equations using a explicit Runge-Kutta scheme (2 steps - 2nd order)
|
716
|
+
|
717
|
+
**NO BRIDGE bur HEDGE in the middle**
|
718
|
+
"""
|
719
|
+
|
720
|
+
h, q, h_pred, q_pred, h_corr, q_corr, q_border, h_border, z_border, u_border, h_center, u_center = all_unk_border(dom, h0, q0)
|
721
|
+
|
722
|
+
theta = np.ones_like(h)
|
723
|
+
theta_border = np.ones_like(h_border)
|
724
|
+
|
725
|
+
slice_hedge = slice(len(h) // 2-1, len(h) // 2+2)
|
726
|
+
theta_val = 0.5
|
727
|
+
theta[slice_hedge] = theta_val
|
728
|
+
|
729
|
+
totaltime = 4*3600
|
730
|
+
eps=1.
|
731
|
+
|
732
|
+
with tqdm(total=totaltime) as pbar:
|
733
|
+
t = 0.
|
734
|
+
while eps > 1e-12:
|
735
|
+
dt = compute_dt(dx, h, q, CN)
|
736
|
+
# Predictor step
|
737
|
+
Euler_RK_hedge(h, h_pred, q, q_pred, h, q, h_border, q_border, z, z_border, dt, dx, h0, q0, n, u_border, h_center, u_center, theta, theta_border)
|
738
|
+
# Corrector step
|
739
|
+
Euler_RK_hedge(h, h_corr, q, q_corr, h_pred, q_pred, h_border, q_border, z, z_border, dt, dx, h0, q0, n, u_border, h_center, u_center, theta, theta_border)
|
740
|
+
|
741
|
+
# Update -- Mean for second order in time
|
742
|
+
h = (h_pred + h_corr)/2.
|
743
|
+
q = (q_pred + q_corr)/2.
|
744
|
+
t+=dt
|
745
|
+
|
746
|
+
eps = np.sum(np.abs(q - q_pred))
|
747
|
+
|
748
|
+
pbar.update(dt)
|
749
|
+
|
750
|
+
print("Total time : ", t)
|
751
|
+
print("Residual : ", eps)
|
752
|
+
|
753
|
+
return h, q, theta
|
754
|
+
|
755
|
+
def problem_bridge(dom:np.ndarray, z:np.ndarray, z_bridge:np.ndarray,
|
756
|
+
h0:float, q0:float,
|
757
|
+
dx:float, CN:float, n:float,
|
758
|
+
press_mode:int = 4,
|
759
|
+
h_ini:np.ndarray = None, q_ini:np.ndarray = None) -> tuple[np.ndarray]:
|
760
|
+
""" Solve the mass and momentum equations using a explicit Rung-Kutta scheme (2 steps - 2nd order)
|
761
|
+
|
762
|
+
**WITH BRIDGE and NO OVERFLOW**
|
763
|
+
"""
|
764
|
+
|
765
|
+
h, q, h_pred, q_pred, h_corr, q_corr, q_border, h_border, z_border, u_border, h_center, u_center = all_unk_border(dom, h0, q0)
|
766
|
+
z_bridge_border = np.zeros_like(z_border)
|
767
|
+
|
768
|
+
if h_ini is not None:
|
769
|
+
h[:] = h_ini[:]
|
770
|
+
if q_ini is not None:
|
771
|
+
q[:] = q_ini[:]
|
772
|
+
|
773
|
+
totaltime = 4*3600
|
774
|
+
eps=1.
|
775
|
+
|
776
|
+
with tqdm(total=totaltime) as pbar:
|
777
|
+
t = 0.
|
778
|
+
while eps > 1e-7:
|
779
|
+
dt = compute_dt(dx, h, q, CN)
|
780
|
+
# Predictor step
|
781
|
+
Euler_RK_bridge(h, h_pred, q, q_pred, h, q, h_border, q_border, z, z_border, dt, dx, h0, q0, n, u_border, h_center, u_center, z_bridge, z_bridge_border, press_mode)
|
782
|
+
# Corrector step
|
783
|
+
Euler_RK_bridge(h, h_corr, q, q_corr, h_pred, q_pred, h_border, q_border, z, z_border, dt, dx, h0, q0, n, u_border, h_center, u_center, z_bridge, z_bridge_border, press_mode)
|
784
|
+
|
785
|
+
# Update -- Mean for second order in time
|
786
|
+
h = (h_pred + h_corr)/2.
|
787
|
+
q = (q_pred + q_corr)/2.
|
788
|
+
t+=dt
|
789
|
+
|
790
|
+
eps = np.sum(np.abs(q - q_pred))
|
791
|
+
|
792
|
+
pbar.update(dt)
|
793
|
+
|
794
|
+
print("Total time : ", t)
|
795
|
+
print("Residual : ", eps)
|
796
|
+
|
797
|
+
return h, q
|
798
|
+
|
799
|
+
def problem_bridge_multiple_steadystates(dom:np.ndarray, z:np.ndarray, z_bridge:np.ndarray,
|
800
|
+
h0:float, qmin:float, qmax:float,
|
801
|
+
dx:float, CN:float, n:float,
|
802
|
+
press_mode:int = 4) -> list[tuple[float, np.ndarray, np.ndarray]]:
|
803
|
+
""" Solve multiple steady states for a given discharge range """
|
804
|
+
|
805
|
+
all_q = np.arange(qmin, qmax+.1, (qmax-qmin)/10)
|
806
|
+
|
807
|
+
ret = []
|
808
|
+
h = None
|
809
|
+
for curq in all_q:
|
810
|
+
h, q = problem_bridge(dom, z, z_bridge, h0, curq, dx, CN, n, press_mode, h_ini=h, q_ini=None)
|
811
|
+
ret.append((0., h.copy(), q.copy()))
|
812
|
+
|
813
|
+
return ret
|
814
|
+
|
815
|
+
def problem_bridge_unsteady(dom:np.ndarray, z:np.ndarray, z_bridge:np.ndarray,
|
816
|
+
h0:float, q0:float,
|
817
|
+
dx:float, CN:float, n:float,
|
818
|
+
press_mode:int = 4):
|
819
|
+
""" Solve the mass and momentum equations using a explicit Runge-Kutta scheme (2 steps - 2nd order).
|
820
|
+
|
821
|
+
**WITH BRIDGE and NO OVERFLOW**
|
822
|
+
|
823
|
+
The downstream boundary condition rises temporarily.
|
824
|
+
|
825
|
+
Firstly, we stabilize the flow with a constant downstream boundary condition.
|
826
|
+
Then, we increase the downstream boundary condition.
|
827
|
+
|
828
|
+
"""
|
829
|
+
|
830
|
+
h, q, h_pred, q_pred, h_corr, q_corr, q_border, h_border, z_border, u_border, h_center, u_center = all_unk_border(dom, h0, q0)
|
831
|
+
z_bridge_border = np.zeros_like(z_border)
|
832
|
+
|
833
|
+
totaltime = 4*3600
|
834
|
+
eps=1.
|
835
|
+
|
836
|
+
# Compute steady state
|
837
|
+
with tqdm(total=totaltime) as pbar:
|
838
|
+
t = 0.
|
839
|
+
while eps > 1e-7:
|
840
|
+
dt = compute_dt(dx, h, q, CN)
|
841
|
+
# Predictor step
|
842
|
+
Euler_RK_bridge(h, h_pred, q, q_pred, h, q, h_border, q_border, z, z_border, dt, dx, h0, q0, n, u_border, h_center, u_center, z_bridge, z_bridge_border, press_mode)
|
843
|
+
# Corrector step
|
844
|
+
Euler_RK_bridge(h, h_corr, q, q_corr, h_pred, q_pred, h_border, q_border, z, z_border, dt, dx, h0, q0, n, u_border, h_center, u_center, z_bridge, z_bridge_border, press_mode)
|
845
|
+
|
846
|
+
# Update -- Mean for second order in time
|
847
|
+
h = (h_pred + h_corr)/2.
|
848
|
+
q = (q_pred + q_corr)/2.
|
849
|
+
t+=dt
|
850
|
+
|
851
|
+
eps = np.sum(np.abs(q - q_pred))
|
852
|
+
|
853
|
+
pbar.update(dt)
|
854
|
+
|
855
|
+
print("Total time : ", t)
|
856
|
+
print("Residual : ", eps)
|
857
|
+
|
858
|
+
res = []
|
859
|
+
|
860
|
+
totaltime = 2*3600
|
861
|
+
k=0
|
862
|
+
with tqdm(total=totaltime) as pbar:
|
863
|
+
t = 0.
|
864
|
+
while t < totaltime:
|
865
|
+
|
866
|
+
dt = compute_dt(dx, h, q, CN)
|
867
|
+
|
868
|
+
if t < totaltime/2:
|
869
|
+
h_cl = h0 + 7. * t/totaltime*2
|
870
|
+
else:
|
871
|
+
h_cl = h0 + 7. - 7. * (t - totaltime/2)/totaltime*2
|
872
|
+
|
873
|
+
# Predictor step
|
874
|
+
Euler_RK_bridge(h, h_pred, q, q_pred, h, q, h_border, q_border, z, z_border, dt, dx, h_cl, q0, n, u_border, h_center, u_center, z_bridge, z_bridge_border, press_mode)
|
875
|
+
# Corrector step
|
876
|
+
Euler_RK_bridge(h, h_corr, q, q_corr, h_pred, q_pred, h_border, q_border, z, z_border, dt, dx, h_cl, q0, n, u_border, h_center, u_center, z_bridge, z_bridge_border, press_mode)
|
877
|
+
|
878
|
+
# Update -- Mean for second order in time
|
879
|
+
h = (h_pred + h_corr)/2.
|
880
|
+
q = (q_pred + q_corr)/2.
|
881
|
+
|
882
|
+
if t > 300*k:
|
883
|
+
res.append((t, h.copy(), q.copy()))
|
884
|
+
k+=1
|
885
|
+
|
886
|
+
t+=dt
|
887
|
+
pbar.update(dt)
|
888
|
+
|
889
|
+
|
890
|
+
return res
|
891
|
+
|
892
|
+
def problem_bridge_unsteady_topo(dom:np.ndarray, z:np.ndarray,
|
893
|
+
z_roof:np.ndarray, z_deck:np.ndarray, z_roof_null:float,
|
894
|
+
h0:float, q0:float,
|
895
|
+
dx:float, CN:float, n:float,
|
896
|
+
press_mode:int = 0,
|
897
|
+
motion_duration:float = 300.,
|
898
|
+
scenario_bc:Literal['unsteady_downstream_bc',
|
899
|
+
'hydrograph',
|
900
|
+
'hydrograph_2steps',
|
901
|
+
'Gauss'] = 'unsteady_downstream_bc',
|
902
|
+
min_overflow:float = 0.05,
|
903
|
+
updating_time_interval:float = 0.
|
904
|
+
):
|
905
|
+
""" Solve the mass and momentum equations using a explicit Rung-Kutta scheme (2 steps - 2nd order).
|
906
|
+
|
907
|
+
**WITH BRIDGE and OVERFLOW**
|
908
|
+
"""
|
909
|
+
|
910
|
+
h, q, h_pred, q_pred, h_corr, q_corr, q_border, h_border, z_border, u_border, h_center, u_center = all_unk_border(dom, h0, q0)
|
911
|
+
z_roof_border = np.zeros_like(z_border)
|
912
|
+
|
913
|
+
totaltime = 3600 #4*3600
|
914
|
+
eps=1.
|
915
|
+
|
916
|
+
# Compute steady state
|
917
|
+
with tqdm(total=totaltime) as pbar:
|
918
|
+
t = 0.
|
919
|
+
while eps > 1e-7:
|
920
|
+
dt = compute_dt(dx, h, q, CN)
|
921
|
+
# Predictor step
|
922
|
+
Euler_RK_bridge(h, h_pred, q, q_pred, h, q, h_border, q_border, z, z_border, dt, dx, h0, q0, n, u_border, h_center, u_center, z_roof, z_roof_border, press_mode)
|
923
|
+
# Corrector step
|
924
|
+
Euler_RK_bridge(h, h_corr, q, q_corr, h_pred, q_pred, h_border, q_border, z, z_border, dt, dx, h0, q0, n, u_border, h_center, u_center, z_roof, z_roof_border, press_mode)
|
925
|
+
|
926
|
+
# Update -- Mean for second order in time
|
927
|
+
h = (h_pred + h_corr)/2.
|
928
|
+
q = (q_pred + q_corr)/2.
|
929
|
+
t+=dt
|
930
|
+
|
931
|
+
eps = np.sum(np.abs(q - q_pred))
|
932
|
+
|
933
|
+
pbar.update(dt)
|
934
|
+
|
935
|
+
print("Total time : ", t)
|
936
|
+
print("Residual : ", eps)
|
937
|
+
|
938
|
+
g = 9.81
|
939
|
+
|
940
|
+
res = []
|
941
|
+
|
942
|
+
# Functions to evaluate the head and the local head loss coefficient
|
943
|
+
def compute_head(z,h,q):
|
944
|
+
return z+h+(q/h)**2/2/g
|
945
|
+
|
946
|
+
def compute_delta_head(zup,hup,qup,zdo,hdo,qdo):
|
947
|
+
return compute_head(zup,hup,qup) - compute_head(zdo,hdo,qdo)
|
948
|
+
|
949
|
+
def compute_k_mean(zup,hup,qup,zdo,hdo,qdo,A_bridge):
|
950
|
+
delta = compute_delta_head(zup,hup,qup,zdo,hdo,qdo)
|
951
|
+
q_mean = (qup+qdo)/2
|
952
|
+
return delta/((q_mean/A_bridge)**2/2/g)
|
953
|
+
|
954
|
+
def compute_losses(q, A_bridge, k):
|
955
|
+
""" Compute the losses based on the flow rate and the local head loss coefficient
|
956
|
+
|
957
|
+
:return: k * |Q| * Q / A^2 / 2 / g
|
958
|
+
:unit: [m]
|
959
|
+
"""
|
960
|
+
return k * q * np.abs(q) / A_bridge**2. /2. / g
|
961
|
+
|
962
|
+
def compute_losses_semi_implicit(q, A_bridge, k):
|
963
|
+
""" Compute part of the losses based on the flow rate and the local head loss coefficient
|
964
|
+
to use in the semi-implicit scheme.
|
965
|
+
|
966
|
+
:return: k * |Q| / A / 2.
|
967
|
+
:unit: [s/m²]
|
968
|
+
"""
|
969
|
+
return k * np.abs(q) / A_bridge /2.
|
970
|
+
|
971
|
+
def compute_q_wo_inertia(zup,hup,qup,zdo,hdo,qdo,A_bridge,k):
|
972
|
+
""" Compute the flow rate based on Bernoulli equation
|
973
|
+
without inertia term """
|
974
|
+
|
975
|
+
delta = compute_delta_head(zup,hup,qup,zdo,hdo,qdo)
|
976
|
+
return np.sqrt(2*g*np.abs(delta)/k)*A_bridge*np.sign(delta), delta
|
977
|
+
|
978
|
+
def compute_q_w_inertia(zup:float, hup:float, qup:float,
|
979
|
+
zdo:float, hdo:float, qdo:float,
|
980
|
+
A_bridge:float, k:float, q_prev:float,
|
981
|
+
dt:float, length:float):
|
982
|
+
""" Compute the flow rate based on Bernoulli equation
|
983
|
+
with inertia term
|
984
|
+
|
985
|
+
$ \frac{\partial Q}{\partial t} + \frac {g A}{L} (Head_do - Head_up + Losses) = 0 $
|
986
|
+
|
987
|
+
$ Losses = k \frac {U^2}{2 g} = k \frac {Q |Q|}{A^2 2 g} $
|
988
|
+
"""
|
989
|
+
|
990
|
+
# new_q, delta = compute_q_wo_inertia(zup,hup,qup,zdo,hdo,qdo,A_bridge,k)
|
991
|
+
|
992
|
+
delta = compute_delta_head(zup,hup,qup,zdo,hdo,qdo)
|
993
|
+
|
994
|
+
if delta > 1.:
|
995
|
+
pass
|
996
|
+
|
997
|
+
inv_dt = 1./ dt
|
998
|
+
return (inv_dt * q_prev + g * A_bridge * delta / length) / (inv_dt + compute_losses_semi_implicit(q_prev, A_bridge, k) / length)
|
999
|
+
|
1000
|
+
def _update_top(z_start:np.ndarray, z_end:np.ndarray, move_time:float, move_totaltime:float, reverse:bool=False):
|
1001
|
+
|
1002
|
+
if reverse:
|
1003
|
+
pond = (move_totaltime - move_time) / move_totaltime
|
1004
|
+
else:
|
1005
|
+
pond = move_time / move_totaltime
|
1006
|
+
|
1007
|
+
loc_z = z_end * pond + z_start * (1.-pond)
|
1008
|
+
|
1009
|
+
return pond, loc_z
|
1010
|
+
|
1011
|
+
def update_top_q(z:np.ndarray, h:np.ndarray, q:np.ndarray, z_bridge:np.ndarray,
|
1012
|
+
idx_up:int, idx_do:int,
|
1013
|
+
survey_up:int, survey_do:int,
|
1014
|
+
A:float, k:float, q_prev:float, dt:float,
|
1015
|
+
move_time:float, move_totaltime:float, move_restore:bool,
|
1016
|
+
z_roof_start:np.ndarray, z_roof_end:np.ndarray,
|
1017
|
+
z_bath_start:np.ndarray, z_bath_end:np.ndarray,
|
1018
|
+
update_top:bool=True, stop_motion:bool = False):
|
1019
|
+
|
1020
|
+
if stop_motion:
|
1021
|
+
move_time = move_totaltime
|
1022
|
+
|
1023
|
+
zup = z[survey_up]
|
1024
|
+
zdo = z[survey_do]
|
1025
|
+
|
1026
|
+
hup = h[survey_up]
|
1027
|
+
hdo = h[survey_do]
|
1028
|
+
|
1029
|
+
qup = q[survey_up]
|
1030
|
+
qdo = q[survey_do]
|
1031
|
+
|
1032
|
+
# Update the flow rate considering inertia (generalized Bernoulli)
|
1033
|
+
qtot_infil_exfil = compute_q_w_inertia(zup, hup, qup,
|
1034
|
+
zdo, hdo, qdo,
|
1035
|
+
A, k, q_prev, dt,
|
1036
|
+
length=dx *(idx_do-idx_up-1))
|
1037
|
+
|
1038
|
+
if update_top:
|
1039
|
+
|
1040
|
+
pond, z_bridge[bridge] = _update_top(z_roof_start, z_roof_end, move_time, move_totaltime, move_restore)
|
1041
|
+
pond, z[bridge] = _update_top(z_bath_start, z_bath_end, move_time, move_totaltime, move_restore)
|
1042
|
+
|
1043
|
+
# if move_restore:
|
1044
|
+
# zref_up = zup + hup - .15
|
1045
|
+
# z[bridge] = np.minimum(z[bridge], zref_up)
|
1046
|
+
|
1047
|
+
else:
|
1048
|
+
pond = 0. if move_restore else 1.
|
1049
|
+
|
1050
|
+
|
1051
|
+
if stop_motion and move_restore:
|
1052
|
+
infil_exfil = None
|
1053
|
+
else:
|
1054
|
+
# Applying the infiltration/exfiltration linearly according to the topo-bathymetry evolution
|
1055
|
+
q_infil_exfil = qtot_infil_exfil * pond
|
1056
|
+
infil_exfil = (idx_up, idx_do, q_infil_exfil, qup/hup, pond, k)
|
1057
|
+
|
1058
|
+
return infil_exfil, z_bridge, z, qtot_infil_exfil
|
1059
|
+
|
1060
|
+
bridge = np.where(z_roof != z_roof_null)[0]
|
1061
|
+
|
1062
|
+
idx_up = bridge[0]-1
|
1063
|
+
idx_do = bridge[-1]+1
|
1064
|
+
|
1065
|
+
survey_up = idx_up-1
|
1066
|
+
survey_do = idx_do+1
|
1067
|
+
|
1068
|
+
z_overflow = z_deck[bridge].max() + min_overflow
|
1069
|
+
|
1070
|
+
totaltime = 2*3600
|
1071
|
+
total_compute = totaltime + 1800 + 2.
|
1072
|
+
|
1073
|
+
infil_exfil = None
|
1074
|
+
|
1075
|
+
bridge_in_motion = False
|
1076
|
+
filled_bridge = False
|
1077
|
+
emptying_bridge = False
|
1078
|
+
motion_completed = True
|
1079
|
+
local_motion_time = 0.
|
1080
|
+
total_motion_time = motion_duration
|
1081
|
+
|
1082
|
+
q_infil_t_current = 0.
|
1083
|
+
|
1084
|
+
delta_res_time_def = 30.
|
1085
|
+
|
1086
|
+
if scenario_bc == 'unsteady_downstream_bc':
|
1087
|
+
dh_cl = 7.
|
1088
|
+
dq_cl = 0.
|
1089
|
+
|
1090
|
+
elif scenario_bc == 'unsteady_downstream_bc_culvert':
|
1091
|
+
dh_cl = 2.
|
1092
|
+
dq_cl = 0.5
|
1093
|
+
|
1094
|
+
elif scenario_bc == 'hydrograph_culvert':
|
1095
|
+
dh_cl = 1.
|
1096
|
+
dq_cl = 3.
|
1097
|
+
|
1098
|
+
elif scenario_bc == 'hydrograph':
|
1099
|
+
dh_cl = 2.
|
1100
|
+
dq_cl = 8.
|
1101
|
+
|
1102
|
+
elif scenario_bc == 'hydrograph_2steps':
|
1103
|
+
dh_cl = 2.
|
1104
|
+
dq_cl = 8.
|
1105
|
+
|
1106
|
+
elif scenario_bc == 'hydrograph_2steps_culvert':
|
1107
|
+
dh_cl = 1.
|
1108
|
+
dq_cl = 10.
|
1109
|
+
|
1110
|
+
elif scenario_bc == 'Gauss':
|
1111
|
+
dh_cl = 2.
|
1112
|
+
dq_cl = 8.
|
1113
|
+
|
1114
|
+
with tqdm(total=total_compute, desc=scenario_bc) as pbar:
|
1115
|
+
t = 0.
|
1116
|
+
|
1117
|
+
res_time = 0.
|
1118
|
+
update_time = 0.
|
1119
|
+
|
1120
|
+
delta_res_time = delta_res_time_def
|
1121
|
+
|
1122
|
+
z_roof_start = None
|
1123
|
+
z_roof_end = None
|
1124
|
+
z_bath_start = None
|
1125
|
+
z_bath_end = None
|
1126
|
+
|
1127
|
+
while t < total_compute:
|
1128
|
+
|
1129
|
+
dt = compute_dt(dx, h, q, CN)
|
1130
|
+
|
1131
|
+
if scenario_bc == 'unsteady_downstream_bc' or scenario_bc == 'unsteady_downstream_bc_culvert':
|
1132
|
+
# The downstream boundary condition evolves linearly
|
1133
|
+
# from h0 to h0 + dh_cl in totaltime/2 seconds
|
1134
|
+
# keeps the value h0 + dh_cl during 1000 seconds
|
1135
|
+
# and then from h0 + dh_cl to h0 in totaltime/2 seconds
|
1136
|
+
#
|
1137
|
+
# ____
|
1138
|
+
# / \
|
1139
|
+
# / \
|
1140
|
+
# ------ / \
|
1141
|
+
# _/ \____
|
1142
|
+
|
1143
|
+
if t < totaltime/2:
|
1144
|
+
h_cl = h0 + dh_cl * t/totaltime*2
|
1145
|
+
q_cl = q0 + dq_cl * t/totaltime*2
|
1146
|
+
else:
|
1147
|
+
if t < totaltime/2 + 1000.:
|
1148
|
+
h_cl = h0 + dh_cl
|
1149
|
+
q_cl = q0 + dq_cl
|
1150
|
+
else:
|
1151
|
+
h_cl = h0 + dh_cl - dh_cl * (t - (totaltime/2+1000.))/(totaltime/2 - 1000.)
|
1152
|
+
q_cl = q0 + dq_cl - dq_cl * (t - (totaltime/2+1000.))/(totaltime/2 - 1000.)
|
1153
|
+
|
1154
|
+
elif scenario_bc == 'hydrograph' or scenario_bc == 'hydrograph_culvert':
|
1155
|
+
# The downstream boundary condition evolves linearly
|
1156
|
+
# from h0 to h0 + dh_cl in totaltime/2 seconds
|
1157
|
+
# keeps the value h0 + dh_cl during 1000 seconds
|
1158
|
+
# and then from h0 + dh_cl to h0 - dh_cl/2 in totaltime/2 seconds
|
1159
|
+
#
|
1160
|
+
# The upstream boundary condition evolves linearly
|
1161
|
+
# from q0 to q0 + dq_cl in totaltime/2 seconds
|
1162
|
+
# keeps the value q0 + dq_cl during 1000 seconds
|
1163
|
+
# and then from q0 + dq_cl to q0 - dq_cl/2 in totaltime/2 seconds
|
1164
|
+
#
|
1165
|
+
# _____ ____
|
1166
|
+
# / \ / \
|
1167
|
+
# / \ / \
|
1168
|
+
# / \ / \
|
1169
|
+
# _/ \ __/ \
|
1170
|
+
# \ \
|
1171
|
+
# \______ \____
|
1172
|
+
|
1173
|
+
if t < totaltime/2:
|
1174
|
+
h_cl = h0 + dh_cl * t/totaltime*2
|
1175
|
+
q_cl = q0 + dq_cl * t/totaltime*2
|
1176
|
+
else:
|
1177
|
+
if t < totaltime/2 + 1000.:
|
1178
|
+
h_cl = h0 + dh_cl
|
1179
|
+
q_cl = q0 + dq_cl
|
1180
|
+
elif t < totaltime:
|
1181
|
+
h_cl = h0 + dh_cl - dh_cl * (t - (totaltime/2+1000.))/(totaltime/2 - 1000.) * 1.5
|
1182
|
+
q_cl = q0 + dq_cl - dq_cl * (t - (totaltime/2+1000.))/(totaltime/2 - 1000.) * 1.5
|
1183
|
+
else:
|
1184
|
+
h_cl = h0 - dh_cl / 2.
|
1185
|
+
q_cl = q0 - dq_cl / 2.
|
1186
|
+
|
1187
|
+
elif scenario_bc == 'hydrograph_2steps' or scenario_bc == 'hydrograph_2steps_culvert':
|
1188
|
+
# Same as hydrograph but the downstream boundary condition
|
1189
|
+
# evolves linearly a second time during peek flow
|
1190
|
+
|
1191
|
+
if t < totaltime/2:
|
1192
|
+
h_cl = h0 + dh_cl * t/totaltime*2
|
1193
|
+
q_cl = q0 + dq_cl * t/totaltime*2
|
1194
|
+
else:
|
1195
|
+
if t < totaltime/2 + 500.:
|
1196
|
+
h_cl = h0 + dh_cl + dh_cl * (t - (totaltime/2))/(500.)
|
1197
|
+
q_cl = q0 + dq_cl
|
1198
|
+
elif t < totaltime/2 + 1000.:
|
1199
|
+
h_cl = h0 + 2* dh_cl - dh_cl * (t - (totaltime/2+500.))/(500.)
|
1200
|
+
q_cl = q0 + dq_cl
|
1201
|
+
elif t < totaltime:
|
1202
|
+
h_cl = h0 + dh_cl - dh_cl * (t - (totaltime/2+1000.))/(totaltime/2 - 1000.) * 1.5
|
1203
|
+
q_cl = q0 + dq_cl - dq_cl * (t - (totaltime/2+1000.))/(totaltime/2 - 1000.) * 1.5
|
1204
|
+
else:
|
1205
|
+
h_cl = h0 - dh_cl / 2.
|
1206
|
+
q_cl = q0 - dq_cl / 2.
|
1207
|
+
|
1208
|
+
elif scenario_bc == 'Gauss':
|
1209
|
+
# The downstream and upstream boundary conditions evolve
|
1210
|
+
# according to a Gaussian function
|
1211
|
+
|
1212
|
+
h_cl = h0 + dh_cl * np.exp(-((t-totaltime/2)**.5)/3600)
|
1213
|
+
q_cl = q0 + dq_cl * np.exp(-((t-totaltime/2)**.5)/3600)
|
1214
|
+
|
1215
|
+
# Predictor step
|
1216
|
+
Euler_RK_bridge(h, h_pred, q, q_pred, h, q, h_border, q_border, z, z_border,
|
1217
|
+
dt, dx, h_cl, q_cl,
|
1218
|
+
n, u_border, h_center, u_center, z_roof, z_roof_border,
|
1219
|
+
press_mode, infil_exfil)
|
1220
|
+
|
1221
|
+
# Corrector step
|
1222
|
+
Euler_RK_bridge(h, h_corr, q, q_corr, h_pred, q_pred, h_border, q_border, z, z_border,
|
1223
|
+
dt, dx, h_cl, q_cl,
|
1224
|
+
n, u_border, h_center, u_center, z_roof, z_roof_border,
|
1225
|
+
press_mode, infil_exfil)
|
1226
|
+
|
1227
|
+
# Update -- Mean for second order in time
|
1228
|
+
h = (h_pred + h_corr)/2.
|
1229
|
+
q = (q_pred + q_corr)/2.
|
1230
|
+
|
1231
|
+
if t >= res_time:
|
1232
|
+
res.append((t, h.copy(), q.copy(), z.copy(), z_roof.copy(), infil_exfil if infil_exfil is not None else (idx_up, idx_do, 0., 0., 0., 0.)))
|
1233
|
+
res_time += delta_res_time
|
1234
|
+
|
1235
|
+
if updating_time_interval == 0. or t> update_time:
|
1236
|
+
update_time += updating_time_interval
|
1237
|
+
|
1238
|
+
if z[survey_up] + h[survey_up] > z_overflow:
|
1239
|
+
# Overflow
|
1240
|
+
|
1241
|
+
# Convert Bridge into topography
|
1242
|
+
# add infiltration/exfiltration
|
1243
|
+
if not bridge_in_motion and motion_completed and not filled_bridge:
|
1244
|
+
|
1245
|
+
# Movement must be initiated...
|
1246
|
+
|
1247
|
+
# Decreasing the interval of time for the
|
1248
|
+
# saving to be more precise when plotting
|
1249
|
+
delta_res_time = delta_res_time_def / 5.
|
1250
|
+
|
1251
|
+
bridge_in_motion = True
|
1252
|
+
emptying_bridge = False
|
1253
|
+
motion_completed = False
|
1254
|
+
|
1255
|
+
local_motion_time = 0.
|
1256
|
+
starting_time = t
|
1257
|
+
|
1258
|
+
# Keeping the old values -- Can be useful when restoring
|
1259
|
+
old_z_roof = z_roof.copy()
|
1260
|
+
old_z = z.copy()
|
1261
|
+
|
1262
|
+
# Reference section of the bridge...
|
1263
|
+
# Keeping the minimum distance between the bridge and the floor
|
1264
|
+
A_bridge = np.min(z_roof[bridge] - z[bridge])
|
1265
|
+
|
1266
|
+
|
1267
|
+
# Computing global head loss coefficient associated to the bridge and the reference section
|
1268
|
+
k_bridge = compute_k_mean(z[survey_up], h[survey_up], q[survey_up],
|
1269
|
+
z[survey_do], h[survey_do], q[survey_do],
|
1270
|
+
A_bridge)
|
1271
|
+
|
1272
|
+
# Starting the motion...
|
1273
|
+
# - the bridge's roof is going up
|
1274
|
+
# - the bridge's floor is going up
|
1275
|
+
|
1276
|
+
z_roof_start = old_z_roof[bridge]
|
1277
|
+
z_roof_end = z_roof_null
|
1278
|
+
z_bath_start = old_z[bridge]
|
1279
|
+
z_bath_end = z_deck[bridge]
|
1280
|
+
|
1281
|
+
# Mean Flow rate under the bridge
|
1282
|
+
q_infil_t_current = np.mean(q[bridge])
|
1283
|
+
|
1284
|
+
infil_exfil, z_roof, z, q_infil_t_current = update_top_q(z, h, q, z_roof,
|
1285
|
+
idx_up, idx_do,
|
1286
|
+
survey_up, survey_do,
|
1287
|
+
A_bridge, k_bridge, q_infil_t_current,
|
1288
|
+
dt,
|
1289
|
+
local_motion_time, total_motion_time,
|
1290
|
+
emptying_bridge,
|
1291
|
+
z_roof_start, z_roof_end, z_bath_start, z_bath_end)
|
1292
|
+
|
1293
|
+
else:
|
1294
|
+
if not motion_completed:
|
1295
|
+
# Movement is initiated but not finished...
|
1296
|
+
|
1297
|
+
# Updating the local time
|
1298
|
+
# local_motion_time += dt
|
1299
|
+
local_motion_time = t - starting_time
|
1300
|
+
|
1301
|
+
if local_motion_time > total_motion_time:
|
1302
|
+
# Total time is reached...
|
1303
|
+
# ... so terminate the movement
|
1304
|
+
|
1305
|
+
delta_res_time = delta_res_time_def
|
1306
|
+
|
1307
|
+
bridge_in_motion = False
|
1308
|
+
motion_completed = True
|
1309
|
+
filled_bridge = not filled_bridge
|
1310
|
+
|
1311
|
+
infil_exfil, z_roof, z, q_infil_t_current = update_top_q(z, h, q, z_roof,
|
1312
|
+
idx_up, idx_do,
|
1313
|
+
survey_up, survey_do,
|
1314
|
+
A_bridge, k_bridge, q_infil_t_current, dt,
|
1315
|
+
local_motion_time, total_motion_time, emptying_bridge,
|
1316
|
+
z_roof_start, z_roof_end, z_bath_start, z_bath_end,
|
1317
|
+
stop_motion= True)
|
1318
|
+
|
1319
|
+
local_motion_time = 0.
|
1320
|
+
else:
|
1321
|
+
# Total time is not reached...
|
1322
|
+
# ... so continue the movement
|
1323
|
+
|
1324
|
+
infil_exfil, z_roof, z, q_infil_t_current = update_top_q(z, h, q, z_roof,
|
1325
|
+
idx_up, idx_do,
|
1326
|
+
survey_up, survey_do,
|
1327
|
+
A_bridge, k_bridge, q_infil_t_current, dt,
|
1328
|
+
local_motion_time, total_motion_time, emptying_bridge,
|
1329
|
+
z_roof_start, z_roof_end, z_bath_start, z_bath_end)
|
1330
|
+
else:
|
1331
|
+
# Movement is done...
|
1332
|
+
|
1333
|
+
if infil_exfil is not None:
|
1334
|
+
|
1335
|
+
# Updating the infiltration discharge according to head difference
|
1336
|
+
infil_exfil, z_roof, z, q_infil_t_current = update_top_q(z, h, q, z_roof,
|
1337
|
+
idx_up, idx_do,
|
1338
|
+
survey_up, survey_do,
|
1339
|
+
A_bridge, k_bridge, q_infil_t_current, dt,
|
1340
|
+
local_motion_time, total_motion_time, emptying_bridge,
|
1341
|
+
z_roof_start, z_roof_end, z_bath_start, z_bath_end,
|
1342
|
+
update_top=False)
|
1343
|
+
|
1344
|
+
|
1345
|
+
else:
|
1346
|
+
# No overflow
|
1347
|
+
|
1348
|
+
if bridge_in_motion:
|
1349
|
+
# But movement is initiated...
|
1350
|
+
# local_motion_time += dt
|
1351
|
+
local_motion_time = t - starting_time
|
1352
|
+
|
1353
|
+
if local_motion_time > total_motion_time:
|
1354
|
+
|
1355
|
+
delta_res_time = delta_res_time_def
|
1356
|
+
|
1357
|
+
# Total time is reached...
|
1358
|
+
# ... so terminate the movement
|
1359
|
+
|
1360
|
+
bridge_in_motion = False
|
1361
|
+
motion_completed = True
|
1362
|
+
filled_bridge = not filled_bridge
|
1363
|
+
|
1364
|
+
infil_exfil, z_roof, z, q_infil_t_current = update_top_q(z, h, q, z_roof,
|
1365
|
+
idx_up, idx_do,
|
1366
|
+
survey_up, survey_do,
|
1367
|
+
A_bridge, k_bridge, q_infil_t_current, dt,
|
1368
|
+
local_motion_time, total_motion_time, emptying_bridge,
|
1369
|
+
z_roof_start, z_roof_end, z_bath_start, z_bath_end,
|
1370
|
+
stop_motion= True)
|
1371
|
+
|
1372
|
+
local_motion_time = 0.
|
1373
|
+
|
1374
|
+
else:
|
1375
|
+
# Total time is not reached...
|
1376
|
+
# ... so continue the movement
|
1377
|
+
|
1378
|
+
infil_exfil, z_roof, z, q_infil_t_current = update_top_q(z, h, q, z_roof,
|
1379
|
+
idx_up, idx_do,
|
1380
|
+
survey_up, survey_do,
|
1381
|
+
A_bridge, k_bridge, q_infil_t_current, dt,
|
1382
|
+
local_motion_time, total_motion_time, emptying_bridge,
|
1383
|
+
z_roof_start, z_roof_end, z_bath_start, z_bath_end)
|
1384
|
+
|
1385
|
+
else:
|
1386
|
+
|
1387
|
+
if infil_exfil is not None:
|
1388
|
+
|
1389
|
+
if motion_completed:
|
1390
|
+
# The bridge is not moving and the infiltration/exfiltration exists
|
1391
|
+
|
1392
|
+
# We can start to restore the bridge as it was before the overflow...
|
1393
|
+
|
1394
|
+
delta_res_time = delta_res_time_def / 5.
|
1395
|
+
|
1396
|
+
bridge_in_motion = True
|
1397
|
+
local_motion_time = 0.
|
1398
|
+
motion_completed = False
|
1399
|
+
|
1400
|
+
emptying_bridge = True
|
1401
|
+
starting_time = t
|
1402
|
+
|
1403
|
+
infil_exfil, z_roof, z, q_infil_t_current = update_top_q(z, h, q, z_roof,
|
1404
|
+
idx_up, idx_do,
|
1405
|
+
survey_up, survey_do,
|
1406
|
+
A_bridge, k_bridge, q_infil_t_current, dt,
|
1407
|
+
local_motion_time, total_motion_time, emptying_bridge,
|
1408
|
+
z_roof_start, z_roof_end, z_bath_start, z_bath_end,
|
1409
|
+
)
|
1410
|
+
|
1411
|
+
t+=dt
|
1412
|
+
pbar.update(dt)
|
1413
|
+
|
1414
|
+
|
1415
|
+
return res
|
1416
|
+
|
1417
|
+
|
1418
|
+
# --------------------
|
1419
|
+
# END Problems section
|
1420
|
+
# --------------------
|
1421
|
+
|
1422
|
+
|
1423
|
+
# ----------------
|
1424
|
+
# PLOTTING SECTION
|
1425
|
+
# ----------------
|
1426
|
+
import matplotlib.animation as animation
|
1427
|
+
|
1428
|
+
def plot_bridge(ax:plt.Axes, x:np.ndarray,
|
1429
|
+
h1:np.ndarray, h2:np.ndarray,
|
1430
|
+
q1:np.ndarray, q2:np.ndarray,
|
1431
|
+
z:np.ndarray, z_bridge:np.ndarray,
|
1432
|
+
hu:float):
|
1433
|
+
|
1434
|
+
u1=np.zeros_like(q1)
|
1435
|
+
u2=np.zeros_like(q1)
|
1436
|
+
|
1437
|
+
u1[1:-1] = q1[1:-1]/h1[1:-1]
|
1438
|
+
u2[1:-1] = q2[1:-1]/np.minimum(h2[1:-1],z_bridge[1:-1]-z[1:-1])
|
1439
|
+
|
1440
|
+
ax.plot(x[1:-1], z[1:-1], label = 'z')
|
1441
|
+
ax.plot(x[1:-1], z_bridge[1:-1], label = 'bridge')
|
1442
|
+
|
1443
|
+
ax.plot(x[1:-1], z[1:-1] + h1[1:-1], label = 'z + h1')
|
1444
|
+
ax.plot(x[1:-1], z[1:-1] + h2[1:-1], label = 'z + h2')
|
1445
|
+
|
1446
|
+
ax.plot(x[1:-1], q1[1:-1], label = 'q')
|
1447
|
+
|
1448
|
+
under_bridge = np.where(h2 > z_bridge - z)[0]
|
1449
|
+
free_surface = np.where(h2 <= z_bridge - z)[0]
|
1450
|
+
|
1451
|
+
ax.plot(x[1:-1], z[1:-1] + h1[1:-1] + u1[1:-1]**2/2/9.81, label = 'head1')
|
1452
|
+
|
1453
|
+
ax.plot(x[1:-1], z[1:-1] + h2[1:-1] + u2[1:-1]**2/2/9.81, label = 'head2')
|
1454
|
+
# ax.plot(x[free_surface], (z[free_surface] + h2[free_surface] + u2[free_surface]**2/2/9.81) * h2[free_surface], label = 'head2 free surface')
|
1455
|
+
|
1456
|
+
if hu != 99999.:
|
1457
|
+
ax.plot(x[1:-1], z[1:-1]+hu, linestyle='--', label = 'h uniform')
|
1458
|
+
ax.legend()
|
1459
|
+
|
1460
|
+
def plot_hedge(ax:plt.Axes, x:np.ndarray,
|
1461
|
+
h1:np.ndarray, h2:np.ndarray,
|
1462
|
+
q1:np.ndarray, q2:np.ndarray,
|
1463
|
+
z:np.ndarray, hu:float,
|
1464
|
+
theta:np.ndarray):
|
1465
|
+
|
1466
|
+
u1=np.zeros_like(q1)
|
1467
|
+
u2=np.zeros_like(q1)
|
1468
|
+
|
1469
|
+
u1[1:-1] = q1[1:-1]/h1[1:-1]
|
1470
|
+
u2[1:-1] = q2[1:-1]/(h2[1:-1]*theta[1:-1])
|
1471
|
+
|
1472
|
+
ax.plot(x[1:-1], z[1:-1], label = 'z')
|
1473
|
+
|
1474
|
+
ax.plot(x[1:-1], z[1:-1] + h1[1:-1], label = 'z + h1')
|
1475
|
+
ax.plot(x[1:-1], z[1:-1] + h2[1:-1], label = 'z + h2')
|
1476
|
+
|
1477
|
+
ax.plot(x[1:-1], u1[1:-1], label = 'u1')
|
1478
|
+
ax.plot(x[1:-1], u2[1:-1], label = 'u2')
|
1479
|
+
|
1480
|
+
# ax.plot(x[1:-1], z[1:-1] + h1[1:-1] + u1[1:-1]**2/2/9.81, label = 'head1')
|
1481
|
+
# ax.plot(x[1:-1], z[1:-1] + h2[1:-1] + u2[1:-1]**2/2/9.81, label = 'head2')
|
1482
|
+
|
1483
|
+
ax.plot(x[1:-1], z[1:-1]+hu, linestyle='--', label = 'h uniform')
|
1484
|
+
ax.legend()
|
1485
|
+
|
1486
|
+
|
1487
|
+
def animate_bridge_unsteady_topo(dom, poly_bridge_x, poly_bridge_y, res:list[float, np.ndarray, np.ndarray, np.ndarray, np.ndarray, tuple[int,int,float,float,float]],
|
1488
|
+
x:np.ndarray, z_ini:np.ndarray, hu:float, z_null:float, length:float, title:str= "Bridge", motion_duration=300.):
|
1489
|
+
fig, axes = plt.subplots(2,1)
|
1490
|
+
|
1491
|
+
all_q_middle = [cur[2][len(dom)//2] for cur in res]
|
1492
|
+
all_q_inf_ex = [cur[5][2] for cur in res]
|
1493
|
+
|
1494
|
+
all_q_up = [cur[2][1] for cur in res]
|
1495
|
+
all_q_down = [cur[2][-2] for cur in res]
|
1496
|
+
|
1497
|
+
all_times = [cur[0] for cur in res]
|
1498
|
+
idx_Froude = [int(len(dom)*cur) for cur in np.linspace(0,100,11,True)/100]
|
1499
|
+
idx_Froude[0] += 5
|
1500
|
+
idx_Froude[-1] -= 5
|
1501
|
+
x_Froude = x[idx_Froude]
|
1502
|
+
Froude = np.zeros_like(x_Froude)
|
1503
|
+
|
1504
|
+
def update(frame):
|
1505
|
+
ax:plt.Axes
|
1506
|
+
ax = axes[0]
|
1507
|
+
ax.clear()
|
1508
|
+
|
1509
|
+
z:np.ndarray
|
1510
|
+
t, h, q, z, z_roof, inf_ex = res[frame]
|
1511
|
+
|
1512
|
+
for i, idx in enumerate(idx_Froude):
|
1513
|
+
if h[idx]==0.:
|
1514
|
+
Froude[i] = 0.
|
1515
|
+
else:
|
1516
|
+
Froude[i] = q[idx] / h[idx] /np.sqrt(9.81*h[idx])
|
1517
|
+
|
1518
|
+
ax.fill_between(x[1:-1], z[1:-1], z[1:-1] + h[1:-1], color='blue', alpha=0.5)
|
1519
|
+
ax.plot(x[1:-1], z[1:-1] + h[1:-1], label='water level [m]', color='blue')
|
1520
|
+
|
1521
|
+
ax.fill_between(x[1:-1], np.ones(z.shape)[1:-1] * z.min(), z[1:-1], color='brown', alpha=0.5)
|
1522
|
+
ax.plot(x[1:-1], z[1:-1], label='bottom level [m]', color='brown')
|
1523
|
+
|
1524
|
+
slice_roof = z_roof != z_null
|
1525
|
+
ax.fill_between(x[slice_roof], z_roof[slice_roof], np.ones(z.shape)[slice_roof] * z_null, color='grey', alpha=0.5)
|
1526
|
+
ax.plot(x[slice_roof], z_roof[slice_roof], label='roof level [m]', color='grey')
|
1527
|
+
|
1528
|
+
# ax.plot(x[1:-1], z_ini[1:-1] + hu, linestyle='--', label='h uniform')
|
1529
|
+
ax.plot(x[1:-1], q[1:-1], linestyle='-', label='flow rate [$m^2/s$]', color='black', linewidth=1.5)
|
1530
|
+
ax.legend(loc='upper right')
|
1531
|
+
|
1532
|
+
ax.fill(poly_bridge_x, poly_bridge_y, color='black', alpha=0.8)
|
1533
|
+
|
1534
|
+
q_middle = q[len(dom)//2]
|
1535
|
+
q_inf_ex = inf_ex[2]
|
1536
|
+
|
1537
|
+
txt = f'Total flow rate {q_middle+q_inf_ex:.2f} $m^2/s$'
|
1538
|
+
txt += f'\nOverflow = {q_middle:.2f} $m^2/s$ - {q_middle/(q_inf_ex+q_middle)*100:.2f} %'
|
1539
|
+
txt += f'\nUnderflow = {q_inf_ex:.2f} $m^2/s$ - {q_inf_ex/(q_inf_ex+q_middle)*100:.2f} %'
|
1540
|
+
|
1541
|
+
in_txt = '$k_{loss}$ ='
|
1542
|
+
txt += f'\n\nMotion time = {motion_duration:.1f} s -- {in_txt} {inf_ex[-1]:.2f}'
|
1543
|
+
|
1544
|
+
ax.text(x[len(dom)//2+8], 11., txt, fontsize=9)
|
1545
|
+
|
1546
|
+
for posFroude, curFroude in zip(x_Froude, Froude):
|
1547
|
+
ax.text(posFroude, 8., f'Fr = {curFroude:.2f}', fontsize=9, horizontalalignment='center')
|
1548
|
+
|
1549
|
+
ax.set_xlim(0, 500)
|
1550
|
+
ax.set_xticks(np.arange(0, 501, 50))
|
1551
|
+
|
1552
|
+
ax.grid(axis='x')
|
1553
|
+
|
1554
|
+
ax.set_ylim(0, 20)
|
1555
|
+
ax.set_title(f'{title} - Length = {length:.1f} m - Time = {t:.1f} s')
|
1556
|
+
|
1557
|
+
ax = axes[1]
|
1558
|
+
ax.clear()
|
1559
|
+
|
1560
|
+
ax.plot(all_times[:frame], all_q_middle[:frame], label='Overflow', color='blue')
|
1561
|
+
ax.plot(all_times[:frame], all_q_inf_ex[:frame], label='Underflow', color='red')
|
1562
|
+
ax.plot(all_times[:frame], [qinf + qmiddle for qinf, qmiddle in zip(all_q_inf_ex[:frame], all_q_middle[:frame])], label='Total', color='black')
|
1563
|
+
|
1564
|
+
ax.plot(all_times[:frame], all_q_up[:frame], label='Upstream', color='black', linestyle='--', linewidth=1.)
|
1565
|
+
ax.plot(all_times[:frame], all_q_down[:frame], label='Downstream', color='black', linestyle='-.', linewidth=1.)
|
1566
|
+
|
1567
|
+
ax.legend(loc='upper right')
|
1568
|
+
ax.set_title('Flow rate')
|
1569
|
+
ax.set_xlabel('Time [s]')
|
1570
|
+
ax.set_ylabel('Flow rate [$m^2/s$]')
|
1571
|
+
|
1572
|
+
ax.set_ylim(0, 20)
|
1573
|
+
ax.set_xlim(0, all_times[-1])
|
1574
|
+
ax.set_xticks(np.arange(0, all_times[-1]+10, 900))
|
1575
|
+
ax.grid()
|
1576
|
+
|
1577
|
+
fig.set_size_inches(20,8)
|
1578
|
+
update(0)
|
1579
|
+
fig.tight_layout()
|
1580
|
+
|
1581
|
+
ani = animation.FuncAnimation(fig, update, frames=len(res), repeat=True)
|
1582
|
+
|
1583
|
+
return ani
|
1584
|
+
|
1585
|
+
|
1586
|
+
# -------------
|
1587
|
+
# REAL PROBLEMS
|
1588
|
+
# -------------
|
1589
|
+
|
1590
|
+
def lake_at_rest():
|
1591
|
+
""" Compute Lake at rest problem
|
1592
|
+
|
1593
|
+
The problem is a simple steady state problem with a bridge in the middle of the domain.
|
1594
|
+
The bridge is a simple flat bridge with a height of 2 m.
|
1595
|
+
|
1596
|
+
No discharge and no water movement is expected.
|
1597
|
+
"""
|
1598
|
+
|
1599
|
+
length = 500.
|
1600
|
+
dx = 1.
|
1601
|
+
CN = 0.4
|
1602
|
+
h0 = 4. # Initial water depth
|
1603
|
+
q0 = 0. # Initial discharge
|
1604
|
+
n = 0.025
|
1605
|
+
slope = 0 #1e-4
|
1606
|
+
press_mode = 4
|
1607
|
+
|
1608
|
+
hu = 0
|
1609
|
+
|
1610
|
+
dom, x, z = domain(length, dx, slope)
|
1611
|
+
x = np.array(x)
|
1612
|
+
|
1613
|
+
# Bridge roof level is 10 m everywhere except in the middle of the domain
|
1614
|
+
z_bridge = np.ones_like(z) * 10.
|
1615
|
+
z_bridge[len(dom)//2-5:len(dom)//2+5] = z[len(dom)//2-5:len(dom)//2+5] + 2.
|
1616
|
+
|
1617
|
+
fig, axes = plt.subplots(3,1)
|
1618
|
+
|
1619
|
+
# free surface flow
|
1620
|
+
h1, q1 = problem(dom, z, h0, q0, dx, CN, n)
|
1621
|
+
# partially pressurized flow
|
1622
|
+
h2, q2 = problem_bridge(dom, z, z_bridge, h0, q0, dx, CN, n, press_mode=press_mode)
|
1623
|
+
|
1624
|
+
assert np.allclose(h1[1:-1], h0), 'Free surface flow is not steady state'
|
1625
|
+
assert np.allclose(q1[1:-1], q0), 'Free surface flow is not steady state'
|
1626
|
+
assert np.allclose(h2[1:-1], h0), 'Partially pressurized flow is not steady state'
|
1627
|
+
assert np.allclose(q2[1:-1], q0), 'Partially pressurized flow is not steady state'
|
1628
|
+
|
1629
|
+
plot_bridge(axes[0], x, h1, h2, q1, q2, z, z_bridge, hu)
|
1630
|
+
|
1631
|
+
# increasing water depth
|
1632
|
+
h0 += 1.
|
1633
|
+
|
1634
|
+
# free surface flow
|
1635
|
+
h1, q1 = problem(dom, z, h0+1., q0, dx, CN, n)
|
1636
|
+
# partially pressurized flow
|
1637
|
+
h2, q2 = problem_bridge(dom, z, z_bridge, h0, q0, dx, CN, n, press_mode=press_mode)
|
1638
|
+
|
1639
|
+
assert np.allclose(h1[1:-1], h0+1.), 'Free surface flow is not steady state'
|
1640
|
+
assert np.allclose(q1[1:-1], q0), 'Free surface flow is not steady state'
|
1641
|
+
assert np.allclose(h2[1:-1], h0), 'Partially pressurized flow is not steady state'
|
1642
|
+
assert np.allclose(q2[1:-1], q0), 'Partially pressurized flow is not steady state'
|
1643
|
+
|
1644
|
+
plot_bridge(axes[1], x, h1, h2, q1, q2, z, z_bridge, hu)
|
1645
|
+
|
1646
|
+
# increasing water depth
|
1647
|
+
h0 += 1.
|
1648
|
+
|
1649
|
+
# free surface flow
|
1650
|
+
h1, q1 = problem(dom, z, h0+2., q0, dx, CN, n)
|
1651
|
+
# partially pressurized flow
|
1652
|
+
h2, q2 = problem_bridge(dom, z, z_bridge, h0, q0, dx, CN, n, press_mode=press_mode)
|
1653
|
+
|
1654
|
+
assert np.allclose(h1[1:-1], h0+2.), 'Free surface flow is not steady state'
|
1655
|
+
assert np.allclose(q1[1:-1], q0), 'Free surface flow is not steady state'
|
1656
|
+
assert np.allclose(h2[1:-1], h0), 'Partially pressurized flow is not steady state'
|
1657
|
+
assert np.allclose(q2[1:-1], q0), 'Partially pressurized flow is not steady state'
|
1658
|
+
|
1659
|
+
plot_bridge(axes[2], x, h1, h2, q1, q2, z, z_bridge, hu)
|
1660
|
+
|
1661
|
+
fig.set_size_inches(15, 10)
|
1662
|
+
fig.tight_layout()
|
1663
|
+
|
1664
|
+
return fig, axes
|
1665
|
+
|
1666
|
+
|
1667
|
+
def water_line():
|
1668
|
+
""" Compute Water line problems
|
1669
|
+
|
1670
|
+
Length = 500 m
|
1671
|
+
dx = 1 m
|
1672
|
+
CN = 0.4
|
1673
|
+
h0 = 4 m
|
1674
|
+
q0 = 7 m^2/s
|
1675
|
+
n = 0.025
|
1676
|
+
slope = 1e-4
|
1677
|
+
"""
|
1678
|
+
|
1679
|
+
length = 500.
|
1680
|
+
dx = 1.
|
1681
|
+
CN = 0.4
|
1682
|
+
h0 = 4.
|
1683
|
+
q0 = 7.
|
1684
|
+
n = 0.025
|
1685
|
+
slope = 1e-4
|
1686
|
+
press_mode = 4
|
1687
|
+
|
1688
|
+
dom, x, z = domain(length, dx, slope)
|
1689
|
+
x = np.array(x)
|
1690
|
+
|
1691
|
+
hu = uniform_waterdepth(slope, q0, n)
|
1692
|
+
|
1693
|
+
# bridge roof level is 10 m everywhere except in the middle of the domain
|
1694
|
+
# where the bridge is located.
|
1695
|
+
# The bridge is a flat bridge with a height of 2 m.
|
1696
|
+
z_bridge = np.ones_like(z) * 10.
|
1697
|
+
z_bridge[len(dom)//2-5:len(dom)//2+5] = z[len(dom)//2-5:len(dom)//2+5] + 2.
|
1698
|
+
|
1699
|
+
fig, axes = plt.subplots(3,1)
|
1700
|
+
|
1701
|
+
h1, q1 = problem(dom, z, h0, q0, dx, CN, n)
|
1702
|
+
h2, q2 = problem_bridge(dom, z, z_bridge, h0, q0, dx, CN, n, press_mode=press_mode)
|
1703
|
+
|
1704
|
+
plot_bridge(axes[0], x, h1, h2, q1, q2, z, z_bridge, hu)
|
1705
|
+
|
1706
|
+
h1, q1 = problem(dom, z, h0+1., q0, dx, CN, n)
|
1707
|
+
h2, q2 = problem_bridge(dom, z, z_bridge, h0+1., q0, dx, CN, n, press_mode=press_mode)
|
1708
|
+
|
1709
|
+
plot_bridge(axes[1], x, h1, h2, q1, q2, z, z_bridge, hu)
|
1710
|
+
|
1711
|
+
h1, q1 = problem(dom, z, h0+2., q0, dx, CN, n)
|
1712
|
+
h2, q2 = problem_bridge(dom, z, z_bridge, h0+2., q0, dx, CN, n, press_mode=press_mode)
|
1713
|
+
|
1714
|
+
plot_bridge(axes[2], x, h1, h2, q1, q2, z, z_bridge, hu)
|
1715
|
+
|
1716
|
+
fig.set_size_inches(20, 10)
|
1717
|
+
fig.tight_layout()
|
1718
|
+
|
1719
|
+
return fig, axes
|
1720
|
+
|
1721
|
+
def water_line_noloss_noslope():
|
1722
|
+
""" Compute Water line problems
|
1723
|
+
|
1724
|
+
Length = 500 m
|
1725
|
+
dx = 1 m
|
1726
|
+
CN = 0.4
|
1727
|
+
h0 = 4 m
|
1728
|
+
q0 = 7 m^2/s
|
1729
|
+
n = 0.0
|
1730
|
+
slope = 0.0
|
1731
|
+
"""
|
1732
|
+
|
1733
|
+
length = 500.
|
1734
|
+
dx = 1.
|
1735
|
+
CN = 0.4
|
1736
|
+
h0 = 4.
|
1737
|
+
q0 = 7.
|
1738
|
+
n = 0.
|
1739
|
+
slope = 0.
|
1740
|
+
press_mode = 4
|
1741
|
+
|
1742
|
+
dom, x, z = domain(length, dx, slope)
|
1743
|
+
x = np.array(x)
|
1744
|
+
|
1745
|
+
hu = uniform_waterdepth(slope, q0, n)
|
1746
|
+
|
1747
|
+
# bridge roof level is 10 m everywhere except in the middle of the domain
|
1748
|
+
# where the bridge is located.
|
1749
|
+
# The bridge is a flat bridge with a height of 2 m.
|
1750
|
+
z_bridge = np.ones_like(z) * 10.
|
1751
|
+
z_bridge[len(dom)//2-5:len(dom)//2+5] = z[len(dom)//2-5:len(dom)//2+5] + 2.
|
1752
|
+
|
1753
|
+
fig, axes = plt.subplots(3,1)
|
1754
|
+
|
1755
|
+
h1, q1 = problem(dom, z, h0, q0, dx, CN, n)
|
1756
|
+
h2, q2 = problem_bridge(dom, z, z_bridge, h0, q0, dx, CN, n, press_mode=press_mode)
|
1757
|
+
|
1758
|
+
plot_bridge(axes[0], x, h1, h2, q1, q2, z, z_bridge, hu)
|
1759
|
+
|
1760
|
+
h1, q1 = problem(dom, z, h0+1., q0, dx, CN, n)
|
1761
|
+
h2, q2 = problem_bridge(dom, z, z_bridge, h0+1., q0, dx, CN, n, press_mode=press_mode)
|
1762
|
+
|
1763
|
+
plot_bridge(axes[1], x, h1, h2, q1, q2, z, z_bridge, hu)
|
1764
|
+
|
1765
|
+
h1, q1 = problem(dom, z, h0+2., q0, dx, CN, n)
|
1766
|
+
h2, q2 = problem_bridge(dom, z, z_bridge, h0+2., q0, dx, CN, n, press_mode=press_mode)
|
1767
|
+
|
1768
|
+
plot_bridge(axes[2], x, h1, h2, q1, q2, z, z_bridge, hu)
|
1769
|
+
|
1770
|
+
fig.set_size_inches(20, 10)
|
1771
|
+
fig.tight_layout()
|
1772
|
+
|
1773
|
+
return fig, axes
|
1774
|
+
|
1775
|
+
def water_lines():
|
1776
|
+
""" Compute multiple water lines problems.
|
1777
|
+
|
1778
|
+
Evaluate the head loss due to the bridge and compare
|
1779
|
+
to theoretical fomula.
|
1780
|
+
"""
|
1781
|
+
|
1782
|
+
length = 500.
|
1783
|
+
dx = 1.
|
1784
|
+
CN = 0.4
|
1785
|
+
h0 = 4.
|
1786
|
+
q0 = 7.
|
1787
|
+
n = 0. #0.025
|
1788
|
+
slope = 0 #1e-4
|
1789
|
+
press_mode = 4
|
1790
|
+
|
1791
|
+
dom, x, z = domain(length, dx, slope)
|
1792
|
+
x = np.array(x)
|
1793
|
+
|
1794
|
+
hu = 0. #uniform_waterdepth(slope, q0, n)
|
1795
|
+
|
1796
|
+
b_bridge = 2.
|
1797
|
+
|
1798
|
+
z_bridge = np.ones_like(z) * 10.
|
1799
|
+
z_bridge[len(dom)//2-5:len(dom)//2+5] = z[len(dom)//2-5:len(dom)//2+5] + b_bridge
|
1800
|
+
|
1801
|
+
idx_before_bridge = len(dom)//2-5 -2
|
1802
|
+
idx_after_bridge = len(dom)//2+5 +2
|
1803
|
+
idx_bridge = len(dom)//2
|
1804
|
+
|
1805
|
+
h0 = 4.5
|
1806
|
+
res = problem_bridge_multiple_steadystates(dom, z, z_bridge, h0, 3.5, 20., dx, CN, n, press_mode=press_mode)
|
1807
|
+
|
1808
|
+
fig, axes = plt.subplots(2,1)
|
1809
|
+
|
1810
|
+
ax:plt.Axes
|
1811
|
+
|
1812
|
+
ax = axes[0]
|
1813
|
+
for cur in res:
|
1814
|
+
ax.plot(x[1:-1], z[1:-1]+cur[1][1:-1], label = f't = {cur[0]:.1f}')
|
1815
|
+
ax.plot(x[1:-1], z[1:-1]+hu, linestyle='--', label = 'h uniform')
|
1816
|
+
ax.plot(x[1:-1], z_bridge[1:-1], label = 'bridge')
|
1817
|
+
ax.plot(x[1:-1], z[1:-1], label = 'z')
|
1818
|
+
ax.legend()
|
1819
|
+
|
1820
|
+
|
1821
|
+
# Head losses
|
1822
|
+
|
1823
|
+
# pressure before, after and at the bridge
|
1824
|
+
press_before = [cur[1][idx_before_bridge] for cur in res]
|
1825
|
+
press_after = [cur[1][idx_after_bridge] for cur in res]
|
1826
|
+
press_bridge = [cur[1][idx_bridge] for cur in res]
|
1827
|
+
|
1828
|
+
h_bridge = np.minimum(press_bridge, z_bridge[idx_bridge] - z[idx_bridge])
|
1829
|
+
|
1830
|
+
# flow rate before, after and at the bridge
|
1831
|
+
q_before = [cur[2][idx_before_bridge] for cur in res]
|
1832
|
+
q_after = [cur[2][idx_after_bridge] for cur in res]
|
1833
|
+
q_bridge = [cur[2][idx_bridge] for cur in res]
|
1834
|
+
|
1835
|
+
# velocity before, after and at the bridge
|
1836
|
+
u_before = [q/h for q,h in zip(q_before, press_before)]
|
1837
|
+
u_after = [q/h for q,h in zip(q_after, press_after)]
|
1838
|
+
u_bridge = [q/h for q,h in zip(q_bridge, h_bridge)]
|
1839
|
+
|
1840
|
+
# head before, after and at the bridge
|
1841
|
+
head_before = [z[idx_before_bridge] + press_before[i] + u_before[i]**2/2/9.81 for i in range(len(res))]
|
1842
|
+
head_after = [z[idx_after_bridge] + press_after[i] + u_after[i]**2/2/9.81 for i in range(len(res))]
|
1843
|
+
head_bridge = [z[idx_bridge] + press_bridge[i] + u_bridge[i]**2/2/9.81 for i in range(len(res))]
|
1844
|
+
|
1845
|
+
# head losses
|
1846
|
+
delta_head_total = [head_before[i] - head_after[i] for i in range(len(res))]
|
1847
|
+
delta_head_up = [head_before[i] - head_bridge[i] for i in range(len(res))]
|
1848
|
+
delta_head_do = [head_bridge[i] - head_after[i] for i in range(len(res))]
|
1849
|
+
|
1850
|
+
ax = axes[1]
|
1851
|
+
|
1852
|
+
ax.plot(delta_head_up, [head_loss_contraction(q, h1, h2) for q,h1,h2 in zip(q_bridge, press_before, h_bridge)], marker='*', label = 'Contraction Loss')
|
1853
|
+
ax.plot(delta_head_do, [head_loss_enlargment(q, h1, h2) for q,h1,h2 in zip(q_bridge, h_bridge, press_after)], marker='o', label = 'Enlargment Loss')
|
1854
|
+
ax.plot(delta_head_total, [head_loss_contract_enlarge(q,h1,h2,h3) for q,h1,h2,h3 in zip(q_bridge, press_before, h_bridge, press_after)], marker='x', label = 'Total Loss')
|
1855
|
+
|
1856
|
+
ax.set_xlabel('Computed $\Delta H$ [m]')
|
1857
|
+
ax.set_ylabel('Theoretical $\Delta H$ [m]')
|
1858
|
+
|
1859
|
+
ax.plot([0,1],[0,1], linestyle='-', linewidth=2, color='black')
|
1860
|
+
ax.set_aspect('equal')
|
1861
|
+
ax.legend()
|
1862
|
+
|
1863
|
+
fig.set_size_inches(20, 10)
|
1864
|
+
fig.tight_layout()
|
1865
|
+
|
1866
|
+
return fig, axes
|
1867
|
+
|
1868
|
+
|
1869
|
+
def unsteady_without_bedmotion():
|
1870
|
+
"""
|
1871
|
+
Compute unsteady problem without bed motion.
|
1872
|
+
|
1873
|
+
The downstream boundary condition rises and decreases.
|
1874
|
+
"""
|
1875
|
+
|
1876
|
+
length = 500.
|
1877
|
+
dx = 1.
|
1878
|
+
CN = 0.4
|
1879
|
+
h0 = 4.
|
1880
|
+
q0 = 7.
|
1881
|
+
n = 0. #0.025
|
1882
|
+
slope = 0 #1e-4
|
1883
|
+
press_mode = 4
|
1884
|
+
|
1885
|
+
dom, x, z = domain(length, dx, slope)
|
1886
|
+
x = np.array(x)
|
1887
|
+
|
1888
|
+
hu = 0. #uniform_waterdepth(slope, q0, n)
|
1889
|
+
|
1890
|
+
b_bridge = 2.
|
1891
|
+
|
1892
|
+
z_bridge = np.ones_like(z) * 10.
|
1893
|
+
z_bridge[len(dom)//2-5:len(dom)//2+5] = z[len(dom)//2-5:len(dom)//2+5] + b_bridge
|
1894
|
+
|
1895
|
+
idx_before_bridge = len(dom)//2-5 -2
|
1896
|
+
idx_after_bridge = len(dom)//2+5 +2
|
1897
|
+
idx_bridge = len(dom)//2
|
1898
|
+
|
1899
|
+
h0 = 1.5
|
1900
|
+
res = problem_bridge_unsteady(dom, z, z_bridge, h0, q0, dx, CN, n, press_mode=press_mode)
|
1901
|
+
|
1902
|
+
fig, axes = plt.subplots(2,1)
|
1903
|
+
|
1904
|
+
ax:plt.Axes
|
1905
|
+
|
1906
|
+
ax = axes[0]
|
1907
|
+
for cur in res:
|
1908
|
+
ax.plot(x[1:-1], z[1:-1]+cur[1][1:-1], label = f't = {cur[0]:.1f}')
|
1909
|
+
ax.plot(x[1:-1], z[1:-1]+hu, linestyle='--', label = 'h uniform')
|
1910
|
+
ax.plot(x[1:-1], z_bridge[1:-1], label = 'bridge')
|
1911
|
+
ax.plot(x[1:-1], z[1:-1], label = 'z')
|
1912
|
+
ax.legend()
|
1913
|
+
|
1914
|
+
press_before = [cur[1][idx_before_bridge] for cur in res]
|
1915
|
+
press_after = [cur[1][idx_after_bridge] for cur in res]
|
1916
|
+
press_bridge = [cur[1][idx_bridge] for cur in res]
|
1917
|
+
|
1918
|
+
h_bridge = np.minimum(press_bridge, z_bridge[idx_bridge] - z[idx_bridge])
|
1919
|
+
|
1920
|
+
q_before = [cur[2][idx_before_bridge] for cur in res]
|
1921
|
+
q_after = [cur[2][idx_after_bridge] for cur in res]
|
1922
|
+
q_bridge = [cur[2][idx_bridge] for cur in res]
|
1923
|
+
|
1924
|
+
u_before = [q/h for q,h in zip(q_before, press_before)]
|
1925
|
+
u_after = [q/h for q,h in zip(q_after, press_after)]
|
1926
|
+
u_bridge = [q/h for q,h in zip(q_bridge, h_bridge)]
|
1927
|
+
|
1928
|
+
head_before = [z[idx_before_bridge] + press_before[i] + u_before[i]**2/2/9.81 for i in range(len(res))]
|
1929
|
+
head_after = [z[idx_after_bridge] + press_after[i] + u_after[i]**2/2/9.81 for i in range(len(res))]
|
1930
|
+
head_bridge = [z[idx_bridge] + press_bridge[i] + u_bridge[i]**2/2/9.81 for i in range(len(res))]
|
1931
|
+
|
1932
|
+
delta_head_total = [head_before[i] - head_after[i] for i in range(len(res))]
|
1933
|
+
delta_head_up = [head_before[i] - head_bridge[i] for i in range(len(res))]
|
1934
|
+
delta_head_do = [head_bridge[i] - head_after[i] for i in range(len(res))]
|
1935
|
+
|
1936
|
+
ax = axes[1]
|
1937
|
+
|
1938
|
+
ax.plot(delta_head_up, [head_loss_contraction(q, h1, h2) for q,h1,h2 in zip(q_bridge, press_before, h_bridge)], marker='*', label = 'Contraction Loss')
|
1939
|
+
ax.plot(delta_head_do, [head_loss_enlargment(q, h1, h2) for q,h1,h2 in zip(q_bridge, h_bridge, press_after)], marker='o', label = 'Enlargment Loss')
|
1940
|
+
ax.plot(delta_head_total, [head_loss_contract_enlarge(q,h1,h2,h3) for q,h1,h2,h3 in zip(q_bridge, press_before, h_bridge, press_after)], marker='x', label = 'Total Loss')
|
1941
|
+
|
1942
|
+
ax.set_xlabel('Computed $\Delta H$ [m]')
|
1943
|
+
ax.set_ylabel('Theoretical $\Delta H$ [m]')
|
1944
|
+
|
1945
|
+
ax.plot([0,1],[0,1], linestyle='-', linewidth=2, color='black')
|
1946
|
+
ax.set_aspect('equal')
|
1947
|
+
ax.legend()
|
1948
|
+
|
1949
|
+
fig.set_size_inches(20, 10)
|
1950
|
+
fig.tight_layout()
|
1951
|
+
|
1952
|
+
return fig, axes
|
1953
|
+
|
1954
|
+
|
1955
|
+
def unsteady_with_bedmotion(problems:list[int], save_video:bool = False) -> list[animation.FuncAnimation]:
|
1956
|
+
"""
|
1957
|
+
Unsteady problem with bed motion if overflowing occurs.
|
1958
|
+
|
1959
|
+
:param problems: list of problems to solve
|
1960
|
+
|
1961
|
+
Problems :
|
1962
|
+
2 - Rectangular bridge - Length = 20 m (will compute 21, 22 and 23)
|
1963
|
+
6 - Rectangular bridge - Length = 60 m (will compute 61, 62 and 63)
|
1964
|
+
7 - V-shape bridge - Length = 20 m (will compute 71, 72 and 73)
|
1965
|
+
8 - U-shape bridge - Length = 20 m (will compute 81, 82 and 83)
|
1966
|
+
9 - Culvert - Length = 100 m (will compute 91, 92 and 93)
|
1967
|
+
|
1968
|
+
21 - Rectangular bridge - Length = 20 m - Unsteady downstream bc
|
1969
|
+
22 - Rectangular bridge - Length = 20 m - Hydrograph
|
1970
|
+
23 - Rectangular bridge - Length = 20 m - Hydrograph 2 steps
|
1971
|
+
|
1972
|
+
61 - Rectangular bridge - Length = 60 m - Unsteady downstream bc
|
1973
|
+
62 - Rectangular bridge - Length = 60 m - Hydrograph
|
1974
|
+
63 - Rectangular bridge - Length = 60 m - Hydrograph 2 steps
|
1975
|
+
|
1976
|
+
71 - V-shape bridge - Length = 20 m - Unsteady downstream bc
|
1977
|
+
72 - V-shape bridge - Length = 20 m - Hydrograph
|
1978
|
+
73 - V-shape bridge - Length = 20 m - Hydrograph 2 steps
|
1979
|
+
|
1980
|
+
81 - U-shape bridge - Length = 20 m - Unsteady downstream bc
|
1981
|
+
82 - U-shape bridge - Length = 20 m - Hydrograph
|
1982
|
+
83 - U-shape bridge - Length = 20 m - Hydrograph 2 steps
|
1983
|
+
|
1984
|
+
91 - Culvert - Length = 100 m - Unsteady downstream bc
|
1985
|
+
92 - Culvert - Length = 100 m - Hydrograph
|
1986
|
+
93 - Culvert - Length = 100 m - Hydrograph 2 steps
|
1987
|
+
|
1988
|
+
"""
|
1989
|
+
length = 500.
|
1990
|
+
dx = 1.
|
1991
|
+
CN = 0.4
|
1992
|
+
h0 = 4.
|
1993
|
+
q0 = 7.
|
1994
|
+
n = 0.025
|
1995
|
+
slope = 0 #1e-4
|
1996
|
+
press_mode = 4
|
1997
|
+
|
1998
|
+
dom, x, z = domain(length, dx, slope)
|
1999
|
+
x = np.array(x)
|
2000
|
+
|
2001
|
+
hu = uniform_waterdepth(slope, q0, n)
|
2002
|
+
|
2003
|
+
anims=[]
|
2004
|
+
|
2005
|
+
if 2 in problems or 21 in problems or 22 in problems or 23 in problems or 24 in problems:
|
2006
|
+
# Rectangular bridge - Lenght = 20 m
|
2007
|
+
|
2008
|
+
CN = 0.4
|
2009
|
+
|
2010
|
+
if 2 in problems:
|
2011
|
+
scenarios = ['unsteady_downstream_bc',
|
2012
|
+
'hydrograph',
|
2013
|
+
'hydrograph_2steps',
|
2014
|
+
# 'Gauss',
|
2015
|
+
]
|
2016
|
+
elif 21 in problems:
|
2017
|
+
scenarios = ['unsteady_downstream_bc']
|
2018
|
+
elif 22 in problems:
|
2019
|
+
scenarios = ['hydrograph']
|
2020
|
+
elif 23 in problems:
|
2021
|
+
scenarios = ['hydrograph_2steps']
|
2022
|
+
elif 24 in problems:
|
2023
|
+
scenarios = ['Gauss']
|
2024
|
+
|
2025
|
+
for scenario in scenarios:
|
2026
|
+
|
2027
|
+
# UNSTEADY WITH TOPOGRAPHY ADAPTATION
|
2028
|
+
motion_duration = 300.
|
2029
|
+
len_bridge = 20
|
2030
|
+
z_roof_null = 10.
|
2031
|
+
min_overflow = 0.25
|
2032
|
+
|
2033
|
+
h0 = 1.5
|
2034
|
+
|
2035
|
+
h_under_bridge = 3.5
|
2036
|
+
h_deck_bridge = 0.75
|
2037
|
+
|
2038
|
+
slice_bridge = slice(int(len(dom)//2-len_bridge//2),int(len(dom)//2+len_bridge//2))
|
2039
|
+
slice_bridge_up = slice(int(len(dom)//2+(len_bridge//2-1)),int(len(dom)//2-(len_bridge//2+1)),-1)
|
2040
|
+
|
2041
|
+
z_bridge = np.ones_like(z) * z_roof_null
|
2042
|
+
z_deck = np.ones_like(z) * z_roof_null
|
2043
|
+
|
2044
|
+
for idx in range(len(dom)//2-len_bridge//2,len(dom)//2+len_bridge//2):
|
2045
|
+
z_bridge[idx] = z[idx] + h_under_bridge
|
2046
|
+
z_deck[idx] = z_bridge[idx] + h_deck_bridge
|
2047
|
+
|
2048
|
+
poly_bridge_x = np.concatenate((x[slice_bridge], x[slice_bridge_up]))
|
2049
|
+
poly_bridge_y = np.concatenate((z_bridge[slice_bridge], z_deck[slice_bridge_up]))
|
2050
|
+
|
2051
|
+
z_ini = z.copy()
|
2052
|
+
|
2053
|
+
res = problem_bridge_unsteady_topo(dom, z,
|
2054
|
+
z_bridge, z_deck, z_roof_null,
|
2055
|
+
h0, q0, dx, CN, n,
|
2056
|
+
press_mode= press_mode,
|
2057
|
+
motion_duration= motion_duration,
|
2058
|
+
scenario_bc= scenario,
|
2059
|
+
min_overflow= min_overflow)
|
2060
|
+
|
2061
|
+
ani = animate_bridge_unsteady_topo(dom, poly_bridge_x, poly_bridge_y, res, x, z_ini, hu, z_roof_null, len_bridge, motion_duration=motion_duration)
|
2062
|
+
|
2063
|
+
if save_video:
|
2064
|
+
update_func = lambda _i, _n: progress_bar.update(1)
|
2065
|
+
with tqdm(total=len(res), desc='Saving video') as progress_bar:
|
2066
|
+
ani.save(f'bridge_L20_{scenario}.mp4',
|
2067
|
+
writer='ffmpeg', fps=5,
|
2068
|
+
progress_callback=update_func)
|
2069
|
+
|
2070
|
+
anims.append(ani)
|
2071
|
+
|
2072
|
+
if 6 in problems or 61 in problems or 62 in problems or 63 in problems or 64 in problems:
|
2073
|
+
# Rectangular bridge - Lenght = 60 m
|
2074
|
+
|
2075
|
+
CN = 0.2
|
2076
|
+
|
2077
|
+
if 6 in problems:
|
2078
|
+
scenarios = ['unsteady_downstream_bc',
|
2079
|
+
'hydrograph',
|
2080
|
+
'hydrograph_2steps',
|
2081
|
+
# 'Gauss',
|
2082
|
+
]
|
2083
|
+
|
2084
|
+
elif 61 in problems:
|
2085
|
+
scenarios = ['unsteady_downstream_bc']
|
2086
|
+
elif 62 in problems:
|
2087
|
+
scenarios = ['hydrograph']
|
2088
|
+
elif 63 in problems:
|
2089
|
+
scenarios = ['hydrograph_2steps']
|
2090
|
+
elif 64 in problems:
|
2091
|
+
scenarios = ['Gauss']
|
2092
|
+
|
2093
|
+
for scenario in scenarios:
|
2094
|
+
|
2095
|
+
# UNSTEADY WITH TOPOGRAPHY ADAPTATION
|
2096
|
+
motion_duration = 300.
|
2097
|
+
z_roof_null = 10.
|
2098
|
+
min_overflow = 0.25
|
2099
|
+
|
2100
|
+
h_under_bridge = 3.5
|
2101
|
+
h_deck_bridge = 0.75
|
2102
|
+
len_bridge = 60
|
2103
|
+
q0 = 6.
|
2104
|
+
h0 = 1.5
|
2105
|
+
|
2106
|
+
slice_bridge = slice(int(len(dom)//2-len_bridge//2),int(len(dom)//2+len_bridge//2))
|
2107
|
+
slice_bridge_up = slice(int(len(dom)//2+(len_bridge//2-1)),int(len(dom)//2-(len_bridge//2+1)),-1)
|
2108
|
+
|
2109
|
+
z_bridge = np.ones_like(z) * z_roof_null
|
2110
|
+
z_deck = np.ones_like(z) * z_roof_null
|
2111
|
+
|
2112
|
+
for idx in range(len(dom)//2-len_bridge//2,len(dom)//2+len_bridge//2):
|
2113
|
+
z_bridge[idx] = z[idx] + h_under_bridge
|
2114
|
+
z_deck[idx] = z_bridge[idx] + h_deck_bridge
|
2115
|
+
|
2116
|
+
poly_bridge_x = np.concatenate((x[slice_bridge], x[slice_bridge_up]))
|
2117
|
+
poly_bridge_y = np.concatenate((z_bridge[slice_bridge], z_deck[slice_bridge_up]))
|
2118
|
+
|
2119
|
+
z_ini = z.copy()
|
2120
|
+
|
2121
|
+
res = problem_bridge_unsteady_topo(dom, z, z_bridge,
|
2122
|
+
z_deck, z_roof_null,
|
2123
|
+
h0, q0, dx, CN, n,
|
2124
|
+
press_mode=press_mode,
|
2125
|
+
motion_duration=motion_duration,
|
2126
|
+
scenario_bc=scenario,
|
2127
|
+
min_overflow=min_overflow)
|
2128
|
+
|
2129
|
+
ani = animate_bridge_unsteady_topo(dom, res, x, z_ini, hu, z_roof_null, len_bridge, motion_duration=motion_duration)
|
2130
|
+
|
2131
|
+
if save_video:
|
2132
|
+
update_func = lambda _i, _n: progress_bar.update(1)
|
2133
|
+
with tqdm(total=len(res), desc='Saving video') as progress_bar:
|
2134
|
+
ani.save(f'bridge_L60{scenario}.mp4',
|
2135
|
+
writer='ffmpeg', fps=5,
|
2136
|
+
progress_callback=update_func)
|
2137
|
+
|
2138
|
+
anims.append(ani)
|
2139
|
+
|
2140
|
+
if 9 in problems or 91 in problems or 92 in problems or 93 in problems or 94 in problems:
|
2141
|
+
# Culvert
|
2142
|
+
|
2143
|
+
CN = 0.4
|
2144
|
+
|
2145
|
+
if 9 in problems:
|
2146
|
+
scenarios = ['unsteady_downstream_bc_culvert',
|
2147
|
+
'hydrograph_culvert',
|
2148
|
+
'hydrograph_2steps_culvert',
|
2149
|
+
# 'Gauss',
|
2150
|
+
]
|
2151
|
+
|
2152
|
+
elif 91 in problems:
|
2153
|
+
scenarios = ['unsteady_downstream_bc_culvert']
|
2154
|
+
elif 92 in problems:
|
2155
|
+
scenarios = ['hydrograph_culvert']
|
2156
|
+
elif 93 in problems:
|
2157
|
+
scenarios = ['hydrograph_2steps_culvert']
|
2158
|
+
|
2159
|
+
for scenario in scenarios:
|
2160
|
+
|
2161
|
+
# UNSTEADY WITH TOPOGRAPHY ADAPTATION
|
2162
|
+
motion_duration = 300.
|
2163
|
+
z_roof_null = 10.
|
2164
|
+
min_overflow = 0.25
|
2165
|
+
|
2166
|
+
h_under_bridge = 1.5
|
2167
|
+
h_deck_bridge = 4.0
|
2168
|
+
len_bridge = 100
|
2169
|
+
h0 = 0.8
|
2170
|
+
q0 = 1.
|
2171
|
+
|
2172
|
+
slice_bridge = slice(int(len(dom)//2-len_bridge//2),int(len(dom)//2+len_bridge//2))
|
2173
|
+
slice_bridge_up = slice(int(len(dom)//2+(len_bridge//2-1)),int(len(dom)//2-(len_bridge//2+1)),-1)
|
2174
|
+
|
2175
|
+
z_bridge = np.ones_like(z) * z_roof_null
|
2176
|
+
z_deck = np.ones_like(z) * z_roof_null
|
2177
|
+
|
2178
|
+
for idx in range(len(dom)//2-len_bridge//2,len(dom)//2+len_bridge//2):
|
2179
|
+
z_bridge[idx] = z[idx] + h_under_bridge
|
2180
|
+
z_deck[idx] = z_bridge[idx] + h_deck_bridge
|
2181
|
+
|
2182
|
+
poly_bridge_x = np.concatenate((x[slice_bridge], x[slice_bridge_up]))
|
2183
|
+
poly_bridge_y = np.concatenate((z_bridge[slice_bridge], z_deck[slice_bridge_up]))
|
2184
|
+
|
2185
|
+
z_ini = z.copy()
|
2186
|
+
|
2187
|
+
res = problem_bridge_unsteady_topo(dom, z, z_bridge,
|
2188
|
+
z_deck, z_roof_null,
|
2189
|
+
h0, q0, dx, CN, n,
|
2190
|
+
press_mode=press_mode,
|
2191
|
+
motion_duration=motion_duration,
|
2192
|
+
scenario_bc=scenario,
|
2193
|
+
min_overflow=min_overflow)
|
2194
|
+
|
2195
|
+
ani = animate_bridge_unsteady_topo(dom, poly_bridge_x, poly_bridge_y, res, x, z_ini, hu, z_roof_null, len_bridge, title='Culvert', motion_duration=motion_duration)
|
2196
|
+
|
2197
|
+
if save_video:
|
2198
|
+
update_func = lambda _i, _n: progress_bar.update(1)
|
2199
|
+
with tqdm(total=len(res), desc='Saving video') as progress_bar:
|
2200
|
+
ani.save(f'culvert_{scenario}.mp4',
|
2201
|
+
writer='ffmpeg', fps=5,
|
2202
|
+
progress_callback=update_func)
|
2203
|
+
|
2204
|
+
anims.append(ani)
|
2205
|
+
|
2206
|
+
if 7 in problems or 71 in problems or 72 in problems or 73 in problems or 74 in problems:
|
2207
|
+
# V-shape Bridge
|
2208
|
+
|
2209
|
+
CN = 0.4
|
2210
|
+
|
2211
|
+
if 7 in problems:
|
2212
|
+
scenarios = ['unsteady_downstream_bc',
|
2213
|
+
'hydrograph',
|
2214
|
+
'hydrograph_2steps',
|
2215
|
+
# 'Gauss',
|
2216
|
+
]
|
2217
|
+
elif 71 in problems:
|
2218
|
+
scenarios = ['unsteady_downstream_bc']
|
2219
|
+
elif 72 in problems:
|
2220
|
+
scenarios = ['hydrograph']
|
2221
|
+
elif 73 in problems:
|
2222
|
+
scenarios = ['hydrograph_2steps']
|
2223
|
+
elif 74 in problems:
|
2224
|
+
scenarios = ['Gauss']
|
2225
|
+
|
2226
|
+
for scenario in scenarios:
|
2227
|
+
|
2228
|
+
# UNSTEADY WITH TOPOGRAPHY ADAPTATION
|
2229
|
+
motion_duration = 300.
|
2230
|
+
z_roof_null = 10.
|
2231
|
+
min_overflow = 0.25
|
2232
|
+
|
2233
|
+
h_under_bridge = 3.5
|
2234
|
+
h_deck_bridge = 0.75
|
2235
|
+
len_bridge = 20
|
2236
|
+
|
2237
|
+
h0 = 1.5
|
2238
|
+
|
2239
|
+
z_bridge = np.ones_like(z) * z_roof_null
|
2240
|
+
z_deck = np.ones_like(z) * z_roof_null
|
2241
|
+
|
2242
|
+
slice_bridge = slice(len(dom)//2-len_bridge//2,len(dom)//2+len_bridge//2)
|
2243
|
+
slice_bridge_up = slice(len(dom)//2+(len_bridge//2-1),len(dom)//2-(len_bridge//2+1),-1)
|
2244
|
+
|
2245
|
+
for idx in range(len(dom)//2-len_bridge//2,len(dom)//2+len_bridge//2):
|
2246
|
+
decal = abs(idx - (len(dom)//2))
|
2247
|
+
z_bridge[idx] = z[idx] + h_under_bridge + 0.05 * decal
|
2248
|
+
z_deck[idx] = h_under_bridge + h_deck_bridge
|
2249
|
+
|
2250
|
+
poly_bridge_x = np.concatenate((x[slice_bridge], x[slice_bridge_up]))
|
2251
|
+
poly_bridge_y = np.concatenate((z_bridge[slice_bridge], z_deck[slice_bridge_up]))
|
2252
|
+
|
2253
|
+
z_ini = z.copy()
|
2254
|
+
|
2255
|
+
res = problem_bridge_unsteady_topo(dom, z,
|
2256
|
+
z_bridge, z_deck, z_roof_null,
|
2257
|
+
h0, q0, dx, CN, n,
|
2258
|
+
press_mode=press_mode,
|
2259
|
+
motion_duration=motion_duration,
|
2260
|
+
scenario_bc=scenario,
|
2261
|
+
min_overflow= min_overflow)
|
2262
|
+
|
2263
|
+
ani = animate_bridge_unsteady_topo(dom, poly_bridge_x, poly_bridge_y, res, x, z_ini, hu, z_roof_null, len_bridge, motion_duration=motion_duration)
|
2264
|
+
|
2265
|
+
if save_video:
|
2266
|
+
update_func = lambda _i, _n: progress_bar.update(1)
|
2267
|
+
with tqdm(total=len(res), desc='Saving video') as progress_bar:
|
2268
|
+
ani.save(f'bridge_Vshape{scenario}.mp4',
|
2269
|
+
writer='ffmpeg', fps=5,
|
2270
|
+
progress_callback=update_func)
|
2271
|
+
|
2272
|
+
anims.append(ani)
|
2273
|
+
|
2274
|
+
if 8 in problems or 81 in problems or 82 in problems or 83 in problems or 84 in problems:
|
2275
|
+
# U-shape Bridge
|
2276
|
+
|
2277
|
+
CN = 0.4
|
2278
|
+
|
2279
|
+
if 8 in problems:
|
2280
|
+
scenarios = ['unsteady_downstream_bc',
|
2281
|
+
'hydrograph',
|
2282
|
+
'hydrograph_2steps',
|
2283
|
+
# 'Gauss',
|
2284
|
+
]
|
2285
|
+
elif 81 in problems:
|
2286
|
+
scenarios = ['unsteady_downstream_bc']
|
2287
|
+
elif 82 in problems:
|
2288
|
+
scenarios = ['hydrograph']
|
2289
|
+
elif 83 in problems:
|
2290
|
+
scenarios = ['hydrograph_2steps']
|
2291
|
+
elif 84 in problems:
|
2292
|
+
scenarios = ['Gauss']
|
2293
|
+
|
2294
|
+
for scenario in scenarios:
|
2295
|
+
|
2296
|
+
# UNSTEADY WITH TOPOGRAPHY ADAPTATION
|
2297
|
+
motion_duration = 300.
|
2298
|
+
z_roof_null = 10.
|
2299
|
+
min_overflow = 0.25
|
2300
|
+
|
2301
|
+
h_under_bridge = 3.5
|
2302
|
+
h_deck_bridge = 0.4
|
2303
|
+
len_bridge = 20
|
2304
|
+
|
2305
|
+
h0 = 1.5
|
2306
|
+
|
2307
|
+
z_bridge = np.ones_like(z) * z_roof_null
|
2308
|
+
z_deck = np.ones_like(z) * z_roof_null
|
2309
|
+
|
2310
|
+
slice_bridge = slice(len(dom)//2-len_bridge//2,len(dom)//2+len_bridge//2)
|
2311
|
+
slice_bridge_up = slice(len(dom)//2+(len_bridge//2-1),len(dom)//2-(len_bridge//2+1),-1)
|
2312
|
+
|
2313
|
+
z_bridge[slice_bridge] = z[slice_bridge] + h_under_bridge
|
2314
|
+
z_deck[slice_bridge] = z_bridge[slice_bridge] + h_deck_bridge
|
2315
|
+
|
2316
|
+
idx_up = len(dom)//2-len_bridge//2
|
2317
|
+
idx_down = len(dom)//2+len_bridge//2-1
|
2318
|
+
|
2319
|
+
z_bridge[idx_up] -= .4
|
2320
|
+
z_bridge[idx_up+1] -= .4
|
2321
|
+
|
2322
|
+
z_bridge[idx_down] -= .4
|
2323
|
+
z_bridge[idx_down-1] -= .4
|
2324
|
+
|
2325
|
+
poly_bridge_x = np.concatenate((x[slice_bridge], x[slice_bridge_up]))
|
2326
|
+
poly_bridge_y = np.concatenate((z_bridge[slice_bridge], z_deck[slice_bridge_up]))
|
2327
|
+
|
2328
|
+
z_ini = z.copy()
|
2329
|
+
|
2330
|
+
res = problem_bridge_unsteady_topo(dom, z,
|
2331
|
+
z_bridge, z_deck, z_roof_null,
|
2332
|
+
h0, q0, dx, CN, n,
|
2333
|
+
press_mode=press_mode,
|
2334
|
+
motion_duration=motion_duration,
|
2335
|
+
scenario_bc=scenario,
|
2336
|
+
min_overflow= min_overflow)
|
2337
|
+
|
2338
|
+
ani = animate_bridge_unsteady_topo(dom, poly_bridge_x, poly_bridge_y, res, x, z_ini, hu, z_roof_null, len_bridge, motion_duration=motion_duration)
|
2339
|
+
|
2340
|
+
if save_video:
|
2341
|
+
update_func = lambda _i, _n: progress_bar.update(1)
|
2342
|
+
with tqdm(total=len(res), desc='Saving video') as progress_bar:
|
2343
|
+
ani.save(f'bridge_Ushape{scenario}.mp4',
|
2344
|
+
writer='ffmpeg', fps=5,
|
2345
|
+
progress_callback=update_func)
|
2346
|
+
|
2347
|
+
anims.append(ani)
|
2348
|
+
|
2349
|
+
return anims
|
2350
|
+
|
2351
|
+
def unsteady_with_bedmotion_interval(problems:list[int], save_video:bool = False, update_interval:float = 0., motion_duration:float = 300.) -> list[animation.FuncAnimation]:
|
2352
|
+
"""
|
2353
|
+
Unsteady problem with bed motion if overflowing occurs.
|
2354
|
+
|
2355
|
+
:param problems: list of problems to solve
|
2356
|
+
|
2357
|
+
Problems :
|
2358
|
+
2 - Rectangular bridge - Length = 20 m (will compute 21, 22 and 23)
|
2359
|
+
6 - Rectangular bridge - Length = 60 m (will compute 61, 62 and 63)
|
2360
|
+
7 - V-shape bridge - Length = 20 m (will compute 71, 72 and 73)
|
2361
|
+
8 - U-shape bridge - Length = 20 m (will compute 81, 82 and 83)
|
2362
|
+
9 - Culvert - Length = 100 m (will compute 91, 92 and 93)
|
2363
|
+
|
2364
|
+
21 - Rectangular bridge - Length = 20 m - Unsteady downstream bc
|
2365
|
+
22 - Rectangular bridge - Length = 20 m - Hydrograph
|
2366
|
+
23 - Rectangular bridge - Length = 20 m - Hydrograph 2 steps
|
2367
|
+
|
2368
|
+
61 - Rectangular bridge - Length = 60 m - Unsteady downstream bc
|
2369
|
+
62 - Rectangular bridge - Length = 60 m - Hydrograph
|
2370
|
+
63 - Rectangular bridge - Length = 60 m - Hydrograph 2 steps
|
2371
|
+
|
2372
|
+
71 - V-shape bridge - Length = 20 m - Unsteady downstream bc
|
2373
|
+
72 - V-shape bridge - Length = 20 m - Hydrograph
|
2374
|
+
73 - V-shape bridge - Length = 20 m - Hydrograph 2 steps
|
2375
|
+
|
2376
|
+
81 - U-shape bridge - Length = 20 m - Unsteady downstream bc
|
2377
|
+
82 - U-shape bridge - Length = 20 m - Hydrograph
|
2378
|
+
83 - U-shape bridge - Length = 20 m - Hydrograph 2 steps
|
2379
|
+
|
2380
|
+
91 - Culvert - Length = 100 m - Unsteady downstream bc
|
2381
|
+
92 - Culvert - Length = 100 m - Hydrograph
|
2382
|
+
93 - Culvert - Length = 100 m - Hydrograph 2 steps
|
2383
|
+
|
2384
|
+
"""
|
2385
|
+
length = 500.
|
2386
|
+
dx = 1.
|
2387
|
+
CN = 0.4
|
2388
|
+
h0 = 4.
|
2389
|
+
q0 = 7.
|
2390
|
+
n = 0.025
|
2391
|
+
slope = 0 #1e-4
|
2392
|
+
press_mode = 4
|
2393
|
+
|
2394
|
+
dom, x, z = domain(length, dx, slope)
|
2395
|
+
x = np.array(x)
|
2396
|
+
|
2397
|
+
hu = uniform_waterdepth(slope, q0, n)
|
2398
|
+
|
2399
|
+
anims=[]
|
2400
|
+
|
2401
|
+
if 2 in problems or 21 in problems or 22 in problems or 23 in problems or 24 in problems:
|
2402
|
+
# Rectangular bridge - Lenght = 20 m
|
2403
|
+
|
2404
|
+
CN = 0.4
|
2405
|
+
|
2406
|
+
if 2 in problems:
|
2407
|
+
scenarios = ['unsteady_downstream_bc',
|
2408
|
+
'hydrograph',
|
2409
|
+
'hydrograph_2steps',
|
2410
|
+
# 'Gauss',
|
2411
|
+
]
|
2412
|
+
elif 21 in problems:
|
2413
|
+
scenarios = ['unsteady_downstream_bc']
|
2414
|
+
elif 22 in problems:
|
2415
|
+
scenarios = ['hydrograph']
|
2416
|
+
elif 23 in problems:
|
2417
|
+
scenarios = ['hydrograph_2steps']
|
2418
|
+
elif 24 in problems:
|
2419
|
+
scenarios = ['Gauss']
|
2420
|
+
|
2421
|
+
for scenario in scenarios:
|
2422
|
+
|
2423
|
+
# UNSTEADY WITH TOPOGRAPHY ADAPTATION
|
2424
|
+
len_bridge = 20
|
2425
|
+
z_roof_null = 10.
|
2426
|
+
min_overflow = 0.25
|
2427
|
+
|
2428
|
+
h0 = 1.5
|
2429
|
+
|
2430
|
+
h_under_bridge = 3.5
|
2431
|
+
h_deck_bridge = 0.75
|
2432
|
+
|
2433
|
+
slice_bridge = slice(int(len(dom)//2-len_bridge//2),int(len(dom)//2+len_bridge//2))
|
2434
|
+
slice_bridge_up = slice(int(len(dom)//2+(len_bridge//2-1)),int(len(dom)//2-(len_bridge//2+1)),-1)
|
2435
|
+
|
2436
|
+
z_bridge = np.ones_like(z) * z_roof_null
|
2437
|
+
z_deck = np.ones_like(z) * z_roof_null
|
2438
|
+
|
2439
|
+
for idx in range(len(dom)//2-len_bridge//2,len(dom)//2+len_bridge//2):
|
2440
|
+
z_bridge[idx] = z[idx] + h_under_bridge
|
2441
|
+
z_deck[idx] = z_bridge[idx] + h_deck_bridge
|
2442
|
+
|
2443
|
+
poly_bridge_x = np.concatenate((x[slice_bridge], x[slice_bridge_up]))
|
2444
|
+
poly_bridge_y = np.concatenate((z_bridge[slice_bridge], z_deck[slice_bridge_up]))
|
2445
|
+
|
2446
|
+
z_ini = z.copy()
|
2447
|
+
|
2448
|
+
res = problem_bridge_unsteady_topo(dom, z,
|
2449
|
+
z_bridge, z_deck, z_roof_null,
|
2450
|
+
h0, q0, dx, CN, n,
|
2451
|
+
press_mode= press_mode,
|
2452
|
+
motion_duration= motion_duration,
|
2453
|
+
scenario_bc= scenario,
|
2454
|
+
min_overflow= min_overflow,
|
2455
|
+
updating_time_interval=update_interval)
|
2456
|
+
|
2457
|
+
ani = animate_bridge_unsteady_topo(dom, poly_bridge_x, poly_bridge_y, res, x, z_ini, hu, z_roof_null, len_bridge, motion_duration=motion_duration)
|
2458
|
+
|
2459
|
+
if save_video:
|
2460
|
+
update_func = lambda _i, _n: progress_bar.update(1)
|
2461
|
+
with tqdm(total=len(res), desc='Saving video') as progress_bar:
|
2462
|
+
ani.save(f'bridge_L20_{scenario}.mp4',
|
2463
|
+
writer='ffmpeg', fps=5,
|
2464
|
+
progress_callback=update_func)
|
2465
|
+
|
2466
|
+
anims.append(ani)
|
2467
|
+
|
2468
|
+
if 6 in problems or 61 in problems or 62 in problems or 63 in problems or 64 in problems:
|
2469
|
+
# Rectangular bridge - Lenght = 60 m
|
2470
|
+
|
2471
|
+
CN = 0.2
|
2472
|
+
|
2473
|
+
if 6 in problems:
|
2474
|
+
scenarios = ['unsteady_downstream_bc',
|
2475
|
+
'hydrograph',
|
2476
|
+
'hydrograph_2steps',
|
2477
|
+
# 'Gauss',
|
2478
|
+
]
|
2479
|
+
|
2480
|
+
elif 61 in problems:
|
2481
|
+
scenarios = ['unsteady_downstream_bc']
|
2482
|
+
elif 62 in problems:
|
2483
|
+
scenarios = ['hydrograph']
|
2484
|
+
elif 63 in problems:
|
2485
|
+
scenarios = ['hydrograph_2steps']
|
2486
|
+
elif 64 in problems:
|
2487
|
+
scenarios = ['Gauss']
|
2488
|
+
|
2489
|
+
for scenario in scenarios:
|
2490
|
+
|
2491
|
+
# UNSTEADY WITH TOPOGRAPHY ADAPTATION
|
2492
|
+
z_roof_null = 10.
|
2493
|
+
min_overflow = 0.25
|
2494
|
+
|
2495
|
+
h_under_bridge = 3.5
|
2496
|
+
h_deck_bridge = 0.75
|
2497
|
+
len_bridge = 60
|
2498
|
+
q0 = 6.
|
2499
|
+
h0 = 1.5
|
2500
|
+
|
2501
|
+
slice_bridge = slice(int(len(dom)//2-len_bridge//2),int(len(dom)//2+len_bridge//2))
|
2502
|
+
slice_bridge_up = slice(int(len(dom)//2+(len_bridge//2-1)),int(len(dom)//2-(len_bridge//2+1)),-1)
|
2503
|
+
|
2504
|
+
z_bridge = np.ones_like(z) * z_roof_null
|
2505
|
+
z_deck = np.ones_like(z) * z_roof_null
|
2506
|
+
|
2507
|
+
for idx in range(len(dom)//2-len_bridge//2,len(dom)//2+len_bridge//2):
|
2508
|
+
z_bridge[idx] = z[idx] + h_under_bridge
|
2509
|
+
z_deck[idx] = z_bridge[idx] + h_deck_bridge
|
2510
|
+
|
2511
|
+
poly_bridge_x = np.concatenate((x[slice_bridge], x[slice_bridge_up]))
|
2512
|
+
poly_bridge_y = np.concatenate((z_bridge[slice_bridge], z_deck[slice_bridge_up]))
|
2513
|
+
|
2514
|
+
z_ini = z.copy()
|
2515
|
+
|
2516
|
+
res = problem_bridge_unsteady_topo(dom, z, z_bridge,
|
2517
|
+
z_deck, z_roof_null,
|
2518
|
+
h0, q0, dx, CN, n,
|
2519
|
+
press_mode=press_mode,
|
2520
|
+
motion_duration=motion_duration,
|
2521
|
+
scenario_bc=scenario,
|
2522
|
+
min_overflow=min_overflow,
|
2523
|
+
updating_time_interval=update_interval)
|
2524
|
+
|
2525
|
+
ani = animate_bridge_unsteady_topo(dom, res, x, z_ini, hu, z_roof_null, len_bridge, motion_duration=motion_duration)
|
2526
|
+
|
2527
|
+
if save_video:
|
2528
|
+
update_func = lambda _i, _n: progress_bar.update(1)
|
2529
|
+
with tqdm(total=len(res), desc='Saving video') as progress_bar:
|
2530
|
+
ani.save(f'bridge_L60{scenario}.mp4',
|
2531
|
+
writer='ffmpeg', fps=5,
|
2532
|
+
progress_callback=update_func)
|
2533
|
+
|
2534
|
+
anims.append(ani)
|
2535
|
+
|
2536
|
+
if 9 in problems or 91 in problems or 92 in problems or 93 in problems or 94 in problems:
|
2537
|
+
# Culvert
|
2538
|
+
|
2539
|
+
CN = 0.4
|
2540
|
+
|
2541
|
+
if 9 in problems:
|
2542
|
+
scenarios = ['unsteady_downstream_bc_culvert',
|
2543
|
+
'hydrograph_culvert',
|
2544
|
+
'hydrograph_2steps_culvert',
|
2545
|
+
# 'Gauss',
|
2546
|
+
]
|
2547
|
+
|
2548
|
+
elif 91 in problems:
|
2549
|
+
scenarios = ['unsteady_downstream_bc_culvert']
|
2550
|
+
elif 92 in problems:
|
2551
|
+
scenarios = ['hydrograph_culvert']
|
2552
|
+
elif 93 in problems:
|
2553
|
+
scenarios = ['hydrograph_2steps_culvert']
|
2554
|
+
|
2555
|
+
for scenario in scenarios:
|
2556
|
+
|
2557
|
+
# UNSTEADY WITH TOPOGRAPHY ADAPTATION
|
2558
|
+
z_roof_null = 10.
|
2559
|
+
min_overflow = 0.25
|
2560
|
+
|
2561
|
+
h_under_bridge = 1.5
|
2562
|
+
h_deck_bridge = 4.0
|
2563
|
+
len_bridge = 100
|
2564
|
+
h0 = 0.8
|
2565
|
+
q0 = 1.
|
2566
|
+
|
2567
|
+
slice_bridge = slice(int(len(dom)//2-len_bridge//2),int(len(dom)//2+len_bridge//2))
|
2568
|
+
slice_bridge_up = slice(int(len(dom)//2+(len_bridge//2-1)),int(len(dom)//2-(len_bridge//2+1)),-1)
|
2569
|
+
|
2570
|
+
z_bridge = np.ones_like(z) * z_roof_null
|
2571
|
+
z_deck = np.ones_like(z) * z_roof_null
|
2572
|
+
|
2573
|
+
for idx in range(len(dom)//2-len_bridge//2,len(dom)//2+len_bridge//2):
|
2574
|
+
z_bridge[idx] = z[idx] + h_under_bridge
|
2575
|
+
z_deck[idx] = z_bridge[idx] + h_deck_bridge
|
2576
|
+
|
2577
|
+
poly_bridge_x = np.concatenate((x[slice_bridge], x[slice_bridge_up]))
|
2578
|
+
poly_bridge_y = np.concatenate((z_bridge[slice_bridge], z_deck[slice_bridge_up]))
|
2579
|
+
|
2580
|
+
z_ini = z.copy()
|
2581
|
+
|
2582
|
+
res = problem_bridge_unsteady_topo(dom, z, z_bridge,
|
2583
|
+
z_deck, z_roof_null,
|
2584
|
+
h0, q0, dx, CN, n,
|
2585
|
+
press_mode=press_mode,
|
2586
|
+
motion_duration=motion_duration,
|
2587
|
+
scenario_bc=scenario,
|
2588
|
+
min_overflow=min_overflow,
|
2589
|
+
updating_time_interval=update_interval)
|
2590
|
+
|
2591
|
+
ani = animate_bridge_unsteady_topo(dom, poly_bridge_x, poly_bridge_y, res, x, z_ini, hu, z_roof_null, len_bridge, title='Culvert', motion_duration=motion_duration)
|
2592
|
+
|
2593
|
+
if save_video:
|
2594
|
+
update_func = lambda _i, _n: progress_bar.update(1)
|
2595
|
+
with tqdm(total=len(res), desc='Saving video') as progress_bar:
|
2596
|
+
ani.save(f'culvert_{scenario}.mp4',
|
2597
|
+
writer='ffmpeg', fps=5,
|
2598
|
+
progress_callback=update_func)
|
2599
|
+
|
2600
|
+
anims.append(ani)
|
2601
|
+
|
2602
|
+
if 7 in problems or 71 in problems or 72 in problems or 73 in problems or 74 in problems:
|
2603
|
+
# V-shape Bridge
|
2604
|
+
|
2605
|
+
CN = 0.4
|
2606
|
+
|
2607
|
+
if 7 in problems:
|
2608
|
+
scenarios = ['unsteady_downstream_bc',
|
2609
|
+
'hydrograph',
|
2610
|
+
'hydrograph_2steps',
|
2611
|
+
# 'Gauss',
|
2612
|
+
]
|
2613
|
+
elif 71 in problems:
|
2614
|
+
scenarios = ['unsteady_downstream_bc']
|
2615
|
+
elif 72 in problems:
|
2616
|
+
scenarios = ['hydrograph']
|
2617
|
+
elif 73 in problems:
|
2618
|
+
scenarios = ['hydrograph_2steps']
|
2619
|
+
elif 74 in problems:
|
2620
|
+
scenarios = ['Gauss']
|
2621
|
+
|
2622
|
+
for scenario in scenarios:
|
2623
|
+
|
2624
|
+
# UNSTEADY WITH TOPOGRAPHY ADAPTATION
|
2625
|
+
z_roof_null = 10.
|
2626
|
+
min_overflow = 0.25
|
2627
|
+
|
2628
|
+
h_under_bridge = 3.5
|
2629
|
+
h_deck_bridge = 0.75
|
2630
|
+
len_bridge = 20
|
2631
|
+
|
2632
|
+
h0 = 1.5
|
2633
|
+
|
2634
|
+
z_bridge = np.ones_like(z) * z_roof_null
|
2635
|
+
z_deck = np.ones_like(z) * z_roof_null
|
2636
|
+
|
2637
|
+
slice_bridge = slice(len(dom)//2-len_bridge//2,len(dom)//2+len_bridge//2)
|
2638
|
+
slice_bridge_up = slice(len(dom)//2+(len_bridge//2-1),len(dom)//2-(len_bridge//2+1),-1)
|
2639
|
+
|
2640
|
+
for idx in range(len(dom)//2-len_bridge//2,len(dom)//2+len_bridge//2):
|
2641
|
+
decal = abs(idx - (len(dom)//2))
|
2642
|
+
z_bridge[idx] = z[idx] + h_under_bridge + 0.05 * decal
|
2643
|
+
z_deck[idx] = h_under_bridge + h_deck_bridge
|
2644
|
+
|
2645
|
+
poly_bridge_x = np.concatenate((x[slice_bridge], x[slice_bridge_up]))
|
2646
|
+
poly_bridge_y = np.concatenate((z_bridge[slice_bridge], z_deck[slice_bridge_up]))
|
2647
|
+
|
2648
|
+
z_ini = z.copy()
|
2649
|
+
|
2650
|
+
res = problem_bridge_unsteady_topo(dom, z,
|
2651
|
+
z_bridge, z_deck, z_roof_null,
|
2652
|
+
h0, q0, dx, CN, n,
|
2653
|
+
press_mode=press_mode,
|
2654
|
+
motion_duration=motion_duration,
|
2655
|
+
scenario_bc=scenario,
|
2656
|
+
min_overflow= min_overflow,
|
2657
|
+
updating_time_interval=update_interval)
|
2658
|
+
|
2659
|
+
ani = animate_bridge_unsteady_topo(dom, poly_bridge_x, poly_bridge_y, res, x, z_ini, hu, z_roof_null, len_bridge, motion_duration=motion_duration)
|
2660
|
+
|
2661
|
+
if save_video:
|
2662
|
+
update_func = lambda _i, _n: progress_bar.update(1)
|
2663
|
+
with tqdm(total=len(res), desc='Saving video') as progress_bar:
|
2664
|
+
ani.save(f'bridge_Vshape{scenario}.mp4',
|
2665
|
+
writer='ffmpeg', fps=5,
|
2666
|
+
progress_callback=update_func)
|
2667
|
+
|
2668
|
+
anims.append(ani)
|
2669
|
+
|
2670
|
+
if 8 in problems or 81 in problems or 82 in problems or 83 in problems or 84 in problems:
|
2671
|
+
# U-shape Bridge
|
2672
|
+
|
2673
|
+
CN = 0.4
|
2674
|
+
|
2675
|
+
if 8 in problems:
|
2676
|
+
scenarios = ['unsteady_downstream_bc',
|
2677
|
+
'hydrograph',
|
2678
|
+
'hydrograph_2steps',
|
2679
|
+
# 'Gauss',
|
2680
|
+
]
|
2681
|
+
elif 81 in problems:
|
2682
|
+
scenarios = ['unsteady_downstream_bc']
|
2683
|
+
elif 82 in problems:
|
2684
|
+
scenarios = ['hydrograph']
|
2685
|
+
elif 83 in problems:
|
2686
|
+
scenarios = ['hydrograph_2steps']
|
2687
|
+
elif 84 in problems:
|
2688
|
+
scenarios = ['Gauss']
|
2689
|
+
|
2690
|
+
for scenario in scenarios:
|
2691
|
+
|
2692
|
+
# UNSTEADY WITH TOPOGRAPHY ADAPTATION
|
2693
|
+
z_roof_null = 10.
|
2694
|
+
min_overflow = 0.25
|
2695
|
+
|
2696
|
+
h_under_bridge = 3.5
|
2697
|
+
h_deck_bridge = 0.4
|
2698
|
+
len_bridge = 20
|
2699
|
+
|
2700
|
+
h0 = 1.5
|
2701
|
+
|
2702
|
+
z_bridge = np.ones_like(z) * z_roof_null
|
2703
|
+
z_deck = np.ones_like(z) * z_roof_null
|
2704
|
+
|
2705
|
+
slice_bridge = slice(len(dom)//2-len_bridge//2,len(dom)//2+len_bridge//2)
|
2706
|
+
slice_bridge_up = slice(len(dom)//2+(len_bridge//2-1),len(dom)//2-(len_bridge//2+1),-1)
|
2707
|
+
|
2708
|
+
z_bridge[slice_bridge] = z[slice_bridge] + h_under_bridge
|
2709
|
+
z_deck[slice_bridge] = z_bridge[slice_bridge] + h_deck_bridge
|
2710
|
+
|
2711
|
+
idx_up = len(dom)//2-len_bridge//2
|
2712
|
+
idx_down = len(dom)//2+len_bridge//2-1
|
2713
|
+
|
2714
|
+
z_bridge[idx_up] -= .4
|
2715
|
+
z_bridge[idx_up+1] -= .4
|
2716
|
+
|
2717
|
+
z_bridge[idx_down] -= .4
|
2718
|
+
z_bridge[idx_down-1] -= .4
|
2719
|
+
|
2720
|
+
poly_bridge_x = np.concatenate((x[slice_bridge], x[slice_bridge_up]))
|
2721
|
+
poly_bridge_y = np.concatenate((z_bridge[slice_bridge], z_deck[slice_bridge_up]))
|
2722
|
+
|
2723
|
+
z_ini = z.copy()
|
2724
|
+
|
2725
|
+
res = problem_bridge_unsteady_topo(dom, z,
|
2726
|
+
z_bridge, z_deck, z_roof_null,
|
2727
|
+
h0, q0, dx, CN, n,
|
2728
|
+
press_mode=press_mode,
|
2729
|
+
motion_duration=motion_duration,
|
2730
|
+
scenario_bc=scenario,
|
2731
|
+
min_overflow= min_overflow,
|
2732
|
+
updating_time_interval=update_interval)
|
2733
|
+
|
2734
|
+
ani = animate_bridge_unsteady_topo(dom, poly_bridge_x, poly_bridge_y, res, x, z_ini, hu, z_roof_null, len_bridge, motion_duration=motion_duration)
|
2735
|
+
|
2736
|
+
if save_video:
|
2737
|
+
update_func = lambda _i, _n: progress_bar.update(1)
|
2738
|
+
with tqdm(total=len(res), desc='Saving video') as progress_bar:
|
2739
|
+
ani.save(f'bridge_Ushape{scenario}.mp4',
|
2740
|
+
writer='ffmpeg', fps=5,
|
2741
|
+
progress_callback=update_func)
|
2742
|
+
|
2743
|
+
anims.append(ani)
|
2744
|
+
|
2745
|
+
return anims
|
2746
|
+
|
2747
|
+
|
2748
|
+
|
2749
|
+
def hedge():
|
2750
|
+
""" Compute Water line problems with hedge
|
2751
|
+
|
2752
|
+
Length = 500 m
|
2753
|
+
dx = 1 m
|
2754
|
+
CN = 0.4
|
2755
|
+
h0 = 4 m
|
2756
|
+
q0 = 7 m^2/s
|
2757
|
+
n = 0.025
|
2758
|
+
slope = 1e-4
|
2759
|
+
"""
|
2760
|
+
|
2761
|
+
length = 500.
|
2762
|
+
dx = 1.
|
2763
|
+
CN = 0.4
|
2764
|
+
h0 = 4.
|
2765
|
+
q0 = 7.
|
2766
|
+
n = 0.025
|
2767
|
+
slope = 1e-4
|
2768
|
+
|
2769
|
+
dom, x, z = domain(length, dx, slope)
|
2770
|
+
x = np.array(x)
|
2771
|
+
|
2772
|
+
hu = uniform_waterdepth(slope, q0, n)
|
2773
|
+
|
2774
|
+
# bridge roof level is 10 m everywhere except in the middle of the domain
|
2775
|
+
# where the bridge is located.
|
2776
|
+
# The bridge is a flat bridge with a height of 2 m.
|
2777
|
+
z_bridge = np.ones_like(z) * 10.
|
2778
|
+
z_bridge[len(dom)//2-5:len(dom)//2+5] = z[len(dom)//2-5:len(dom)//2+5] + 2.
|
2779
|
+
|
2780
|
+
fig, axes = plt.subplots(3,1)
|
2781
|
+
|
2782
|
+
h1, q1 = problem(dom, z, h0, q0, dx, CN, n)
|
2783
|
+
h2, q2, theta = problem_hedge(dom, z, h0, q0, dx, CN, n)
|
2784
|
+
|
2785
|
+
plot_hedge(axes[0], x, h1, h2, q1, q2, z, hu, theta)
|
2786
|
+
|
2787
|
+
h1, q1 = problem(dom, z, h0+1., q0, dx, CN, n)
|
2788
|
+
h2, q2, theta = problem_hedge(dom, z, h0+1., q0, dx, CN, n)
|
2789
|
+
|
2790
|
+
plot_hedge(axes[1], x, h1, h2, q1, q2, z, hu, theta)
|
2791
|
+
|
2792
|
+
h1, q1 = problem(dom, z, h0+2., q0, dx, CN, n)
|
2793
|
+
h2, q2, theta = problem_hedge(dom, z, h0+2., q0, dx, CN, n)
|
2794
|
+
|
2795
|
+
plot_hedge(axes[2], x, h1, h2, q1, q2, z, hu, theta)
|
2796
|
+
|
2797
|
+
fig.set_size_inches(20, 10)
|
2798
|
+
fig.tight_layout()
|
2799
|
+
|
2800
|
+
return fig, axes
|
2801
|
+
|
2802
|
+
if __name__ == '__main__':
|
2803
|
+
|
2804
|
+
# anim = steady()
|
2805
|
+
# anim = water_line()
|
2806
|
+
# anim = water_lines()
|
2807
|
+
# anim = unsteady_without_bedmotion()
|
2808
|
+
# anim = unteaady_with_bedmotion([2, 6, 7, 8, 9])
|
2809
|
+
anim = hedge()
|
2810
|
+
# anim = water_line_noloss_noslope()
|
2811
|
+
|
2812
|
+
# anim1 = unsteady_with_bedmotion([2])
|
2813
|
+
# anim2 = unsteady_with_bedmotion_interval([21], update_interval=2., motion_duration=300.)
|
2814
|
+
|
2815
|
+
plt.show()
|
2816
|
+
|
2817
|
+
pass
|