wolfhece 2.0.54__py3-none-any.whl → 2.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wolfhece/PyDraw.py +890 -295
- wolfhece/PyGui.py +1924 -661
- wolfhece/PyPalette.py +47 -0
- wolfhece/PyParams.py +377 -76
- wolfhece/PyVertex.py +14 -1
- wolfhece/PyVertexvectors.py +45 -18
- wolfhece/Results2DGPU.py +1 -2
- wolfhece/apps/version.py +2 -2
- wolfhece/bernoulli/__init__.py +0 -0
- wolfhece/bernoulli/chamber.py +93 -0
- wolfhece/bernoulli/fluids.py +10 -0
- wolfhece/bernoulli/losses.py +100 -0
- wolfhece/bernoulli/network.py +128 -0
- wolfhece/bernoulli/pipe.py +194 -0
- wolfhece/lagrangian/example_domain.py +1 -1
- wolfhece/mesh2d/bc_manager.py +66 -5
- wolfhece/mesh2d/config_manager.py +1 -1
- wolfhece/mesh2d/cst_2D_boundary_conditions.py +59 -2
- wolfhece/mesh2d/wolf2dprev.py +11603 -2676
- wolfhece/models/walous_niv1.pal +29 -0
- wolfhece/models/walous_niv2.pal +77 -0
- wolfhece/pywalous.py +400 -46
- wolfhece/scenario/config_manager.py +14 -5
- wolfhece/wolf_array.py +1487 -458
- wolfhece/wolf_vrt.py +31 -8
- wolfhece/wolfresults_2D.py +230 -91
- {wolfhece-2.0.54.dist-info → wolfhece-2.1.0.dist-info}/METADATA +3 -2
- {wolfhece-2.0.54.dist-info → wolfhece-2.1.0.dist-info}/RECORD +31 -23
- {wolfhece-2.0.54.dist-info → wolfhece-2.1.0.dist-info}/WHEEL +0 -0
- {wolfhece-2.0.54.dist-info → wolfhece-2.1.0.dist-info}/entry_points.txt +0 -0
- {wolfhece-2.0.54.dist-info → wolfhece-2.1.0.dist-info}/top_level.txt +0 -0
wolfhece/PyVertex.py
CHANGED
@@ -169,6 +169,19 @@ class wolfvertex:
|
|
169
169
|
self.y = max(self.y, bounds[1][0])
|
170
170
|
self.y = min(self.y, bounds[1][1])
|
171
171
|
|
172
|
+
def is_like(self, v:"wolfvertex", tol:float=1.e-6):
|
173
|
+
"""
|
174
|
+
Return True if the vertex is close to another one
|
175
|
+
|
176
|
+
:param v: vertex to compare
|
177
|
+
:param tol: tolerance
|
178
|
+
"""
|
179
|
+
|
180
|
+
if abs(self.x - v.x) < tol and abs(self.y - v.y) < tol and abs(self.z - v.z) < tol:
|
181
|
+
return True
|
182
|
+
else:
|
183
|
+
return False
|
184
|
+
|
172
185
|
class cloudproperties:
|
173
186
|
"""
|
174
187
|
Properties of a cloud of vertices
|
@@ -854,7 +867,7 @@ class cloud_vertices(Element_To_Draw):
|
|
854
867
|
curvert = self.myvertices[item]['vertex']
|
855
868
|
|
856
869
|
if curvert.x > xmin and curvert.x < xmax and curvert.y > ymin and curvert.y < ymax:
|
857
|
-
|
870
|
+
|
858
871
|
r,g,b = getRGBfromI(self.myprop.legendcolor)
|
859
872
|
|
860
873
|
curtxt_infos = Text_Infos(self.myprop.legendpriority,
|
wolfhece/PyVertexvectors.py
CHANGED
@@ -911,11 +911,14 @@ class vector:
|
|
911
911
|
|
912
912
|
def __init__(self, lines:list=[], is2D=True, name='NoName', parentzone:"zone"=None, fromshapely=None) -> None:
|
913
913
|
"""
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
914
|
+
|
915
|
+
:param lines: utile pour lecture de fichier
|
916
|
+
:param is2D: on interprète les 'vertices' comme 2D même si chaque 'wolfvertex' contient toujours x, y et z
|
917
|
+
:param name: nom du vecteur
|
918
|
+
:param parentzone: instance de type 'zone' qui contient le 'vector'
|
919
|
+
|
918
920
|
"""
|
921
|
+
|
919
922
|
self.myname=''
|
920
923
|
self.is2D = is2D
|
921
924
|
self.closed=False
|
@@ -1367,12 +1370,12 @@ class vector:
|
|
1367
1370
|
# again checks that the vector is not closed; in the case where
|
1368
1371
|
# two vertices are not the same one but have the same coordinates)
|
1369
1372
|
|
1370
|
-
is_open = self.myvertices[-1] is
|
1371
|
-
(self.myvertices[-1].x
|
1372
|
-
self.myvertices[-1].y
|
1373
|
+
is_open = not((self.myvertices[-1] is self.myvertices[0]) or \
|
1374
|
+
(self.myvertices[-1].x==self.myvertices[0].x and \
|
1375
|
+
self.myvertices[-1].y==self.myvertices[0].y))
|
1373
1376
|
|
1374
1377
|
if not self.is2D :
|
1375
|
-
is_open = is_open
|
1378
|
+
is_open = is_open or self.myvertices[-1].z!=self.myvertices[0].z
|
1376
1379
|
|
1377
1380
|
if is_open:
|
1378
1381
|
self.add_vertex(self.myvertices[0])
|
@@ -1800,10 +1803,10 @@ class vector:
|
|
1800
1803
|
|
1801
1804
|
if length<1:
|
1802
1805
|
length*=1000.
|
1803
|
-
alls = np.linspace(0,
|
1806
|
+
alls = np.linspace(0, length, nb)
|
1804
1807
|
alls/=1000.
|
1805
1808
|
else:
|
1806
|
-
alls = np.linspace(0,
|
1809
|
+
alls = np.linspace(0, length, nb, endpoint=True)
|
1807
1810
|
|
1808
1811
|
pts = [myls.interpolate(curs) for curs in alls]
|
1809
1812
|
# pts = [(curpt.x, curpt.y) for curpt in pts]
|
@@ -2147,16 +2150,28 @@ class vector:
|
|
2147
2150
|
|
2148
2151
|
if name is None:
|
2149
2152
|
name = self.myname + "_copy"
|
2150
|
-
if parentzone:
|
2151
|
-
copied_vector = vector(name=name,parentzone=parentzone)
|
2152
|
-
else:
|
2153
|
-
copied_vector = vector(name=name)
|
2154
2153
|
|
2155
|
-
|
2156
|
-
|
2154
|
+
if parentzone:
|
2155
|
+
copied_vector = vector(name=name,parentzone=parentzone)
|
2156
|
+
else:
|
2157
|
+
copied_vector = vector(name=name)
|
2158
|
+
|
2159
|
+
copied_vector.myvertices = copy.deepcopy(self.myvertices)
|
2160
|
+
|
2161
|
+
return copied_vector
|
2162
|
+
|
2163
|
+
def set_legend_to_centroid(self, text:str='', visible:bool=True):
|
2164
|
+
"""
|
2165
|
+
Positionne la légende au centre du vecteur
|
2166
|
+
"""
|
2167
|
+
self.myprop.legendvisible = visible
|
2157
2168
|
|
2158
|
-
|
2169
|
+
ls = self.asshapely_pol()
|
2170
|
+
centroid = ls.centroid
|
2159
2171
|
|
2172
|
+
self.myprop.legendx = centroid.x
|
2173
|
+
self.myprop.legendy = centroid.y
|
2174
|
+
self.myprop.legendtext = text if text else self.myname
|
2160
2175
|
|
2161
2176
|
class zone:
|
2162
2177
|
"""
|
@@ -3657,6 +3672,14 @@ class zone:
|
|
3657
3672
|
if self.parent.mapviewer is not None:
|
3658
3673
|
self.prep_listogl()
|
3659
3674
|
self.parent.mapviewer.Refresh()
|
3675
|
+
|
3676
|
+
def set_legend_to_centroid(self):
|
3677
|
+
"""
|
3678
|
+
Set the legend to the centroid of the zone
|
3679
|
+
"""
|
3680
|
+
for curvec in self.myvectors:
|
3681
|
+
curvec.set_legend_to_centroid()
|
3682
|
+
|
3660
3683
|
class Zones(wx.Frame, Element_To_Draw):
|
3661
3684
|
"""
|
3662
3685
|
Objet de gestion d'informations vectorielles
|
@@ -5661,7 +5684,11 @@ class Zones(wx.Frame, Element_To_Draw):
|
|
5661
5684
|
elif object.nbvectors>0:
|
5662
5685
|
self.Activate_vector(object.myvectors[0])
|
5663
5686
|
|
5664
|
-
self.
|
5687
|
+
if self.active_vector is None:
|
5688
|
+
logging.warning(_('No vector in the active zone'))
|
5689
|
+
else:
|
5690
|
+
self.labelactvect.SetLabel(self.active_vector.myname)
|
5691
|
+
|
5665
5692
|
self.labelactzone.SetLabel(self.active_zone.myname)
|
5666
5693
|
self.Layout()
|
5667
5694
|
|
wolfhece/Results2DGPU.py
CHANGED
wolfhece/apps/version.py
CHANGED
File without changes
|
@@ -0,0 +1,93 @@
|
|
1
|
+
import numpy as np
|
2
|
+
from math import pi
|
3
|
+
|
4
|
+
class chamber():
|
5
|
+
|
6
|
+
def __init__(self) -> None:
|
7
|
+
|
8
|
+
self.area = 10. # m^2
|
9
|
+
self.elevation = 0. # m
|
10
|
+
self._volume = 100. # m^3
|
11
|
+
self._height = 10. # m
|
12
|
+
|
13
|
+
self.q_in = []
|
14
|
+
self.q_out = []
|
15
|
+
|
16
|
+
self.is_bc = False
|
17
|
+
self.bc_value = 0.
|
18
|
+
|
19
|
+
def reset_q(self):
|
20
|
+
self.q_in = []
|
21
|
+
self.q_out = []
|
22
|
+
|
23
|
+
def add_qin(self, q):
|
24
|
+
self.q_in.append(q)
|
25
|
+
|
26
|
+
def add_qout(self, q):
|
27
|
+
self.q_out.append(q)
|
28
|
+
|
29
|
+
@property
|
30
|
+
def volume(self):
|
31
|
+
return self._volume
|
32
|
+
|
33
|
+
@volume.setter
|
34
|
+
def volume(self, value):
|
35
|
+
self._volume = value
|
36
|
+
self.solve_height()
|
37
|
+
|
38
|
+
@property
|
39
|
+
def height(self):
|
40
|
+
return self._height
|
41
|
+
|
42
|
+
@height.setter
|
43
|
+
def height(self, value):
|
44
|
+
self._height = value
|
45
|
+
self.solve_volume()
|
46
|
+
|
47
|
+
def solve_volume(self):
|
48
|
+
self._volume = self.area * self.height
|
49
|
+
return self._volume
|
50
|
+
|
51
|
+
def solve_height(self):
|
52
|
+
self._height = self.volume / self.area
|
53
|
+
return self._height
|
54
|
+
|
55
|
+
def update(self, dt:float):
|
56
|
+
|
57
|
+
if self.is_bc:
|
58
|
+
self.head = self.bc_value
|
59
|
+
else:
|
60
|
+
self.volume += (np.sum(np.asarray(self.q_in)) - np.sum(np.asarray(self.q_out))) * dt
|
61
|
+
self.solve_height()
|
62
|
+
|
63
|
+
@property
|
64
|
+
def head(self):
|
65
|
+
return self.elevation + self.height
|
66
|
+
|
67
|
+
@head.setter
|
68
|
+
def head(self, value):
|
69
|
+
self.height = value - self.elevation
|
70
|
+
self.solve_volume()
|
71
|
+
|
72
|
+
class junction(chamber):
|
73
|
+
|
74
|
+
def __init__(self) -> None:
|
75
|
+
super().__init__()
|
76
|
+
self.area = 1.e-2
|
77
|
+
self.volume = 0.
|
78
|
+
self.height = 0.
|
79
|
+
self.elevation = 0.
|
80
|
+
|
81
|
+
self._head = 0.
|
82
|
+
|
83
|
+
@property
|
84
|
+
def head(self):
|
85
|
+
return self._head
|
86
|
+
|
87
|
+
@head.setter
|
88
|
+
def head(self, value):
|
89
|
+
self._head = value
|
90
|
+
|
91
|
+
def update(self, dt:float):
|
92
|
+
|
93
|
+
self.head += (np.sum(np.asarray(self.q_in)) - np.sum(np.asarray(self.q_out))) * dt
|
@@ -0,0 +1,100 @@
|
|
1
|
+
import numpy as np
|
2
|
+
from math import pi
|
3
|
+
from scipy.optimize import fsolve, newton, root, root_scalar
|
4
|
+
import matplotlib.pyplot as plt
|
5
|
+
from jax import grad, jit, numpy as jnp
|
6
|
+
import timeit
|
7
|
+
|
8
|
+
@jit
|
9
|
+
def _colebrook_white(f, k, diameter, reynolds):
|
10
|
+
"""
|
11
|
+
Colebrook-White equation for friction factor
|
12
|
+
|
13
|
+
@param f: float, friction factor [-]
|
14
|
+
@param k: float, roughness of the pipe [m]
|
15
|
+
@param diameter: float, diameter of the pipe [m]
|
16
|
+
@param reynolds: float, Reynolds number [-]
|
17
|
+
"""
|
18
|
+
return 1. / jnp.sqrt(f) + 2. * jnp.log10(k / (3.7 * diameter) + 2.51 / (reynolds * jnp.sqrt(f)))
|
19
|
+
|
20
|
+
""" Gradient of the Colebrook-White equation """
|
21
|
+
grad_colebrook_white = jit(grad(_colebrook_white))
|
22
|
+
""" Second derivative of the Colebrook-White equation """
|
23
|
+
grad2_colebrook_white = jit(grad(grad(_colebrook_white)))
|
24
|
+
|
25
|
+
def f_colebrook_white(f, k, diameter, reynolds):
|
26
|
+
"""
|
27
|
+
Solve the Colebrook-White equation using Newton's method
|
28
|
+
|
29
|
+
@param f: float, initial guess for the friction factor [-]
|
30
|
+
@param k: float, roughness of the pipe [m]
|
31
|
+
@param diameter: float, diameter of the pipe [m]
|
32
|
+
@param reynolds: float, Reynolds number [-]
|
33
|
+
"""
|
34
|
+
f_sol = newton(_colebrook_white, f, grad_colebrook_white, args=(k, diameter, reynolds), rtol=1e-6)
|
35
|
+
return f_sol.item()
|
36
|
+
|
37
|
+
|
38
|
+
# Test multiple solvers
|
39
|
+
def test_colebrook_fsolve():
|
40
|
+
""" Test the Colebrook-White equation using Scipy fsolve """
|
41
|
+
|
42
|
+
k= 1.e-4
|
43
|
+
diam = .5
|
44
|
+
viscosity = 1.e-6
|
45
|
+
area = pi * (diam/2.)**2.
|
46
|
+
discharge = 1.
|
47
|
+
velocity = discharge / area
|
48
|
+
reynolds = velocity * diam / viscosity
|
49
|
+
|
50
|
+
f_guess = 0.02 # Initial guess for the friction factor
|
51
|
+
f_sol = fsolve(_colebrook_white, f_guess, args=(k, diam, reynolds), xtol=1e-14)
|
52
|
+
return f_sol[0]
|
53
|
+
|
54
|
+
def test_colebrook_root_scalar():
|
55
|
+
""" Test the Colebrook-White equation using Scipy root_scalar """
|
56
|
+
|
57
|
+
k= 1.e-4
|
58
|
+
diam = .5
|
59
|
+
viscosity = 1.e-6
|
60
|
+
area = pi * (diam/2.)**2.
|
61
|
+
discharge = 1.
|
62
|
+
velocity = discharge / area
|
63
|
+
reynolds = velocity * diam / viscosity
|
64
|
+
|
65
|
+
f_guess = 0.02 # Initial guess for the friction factor
|
66
|
+
f_sol = root_scalar(_colebrook_white, method='brentq', bracket=[0.,10.], x0 = f_guess, args=(k, diam, reynolds)) #, fprime = grad_colebrook_white, fprime2 = grad2_colebrook_white, xtol=1e-6)
|
67
|
+
return f_sol.root
|
68
|
+
|
69
|
+
def test_colebrook_newton():
|
70
|
+
""" Test the Colebrook-White equation using Scipy newton """
|
71
|
+
|
72
|
+
k= 1.e-4
|
73
|
+
diam = .5
|
74
|
+
viscosity = 1.e-6
|
75
|
+
area = pi * (diam/2.)**2.
|
76
|
+
discharge = 1.
|
77
|
+
velocity = discharge / area
|
78
|
+
reynolds = velocity * diam / viscosity
|
79
|
+
|
80
|
+
f_guess = 0.02 # Initial guess for the friction factor
|
81
|
+
|
82
|
+
f_sol = newton(_colebrook_white, f_guess, grad_colebrook_white, args=(k, diam, reynolds), rtol=1e-6)
|
83
|
+
return f_sol.item()
|
84
|
+
|
85
|
+
|
86
|
+
if __name__ == '__main__':
|
87
|
+
|
88
|
+
trootscalar = timeit.timeit(test_colebrook_root_scalar, number = 1000)
|
89
|
+
tfsolve = timeit.timeit(test_colebrook_fsolve, number = 1000)
|
90
|
+
tnewton = timeit.timeit(test_colebrook_newton, number = 1000)
|
91
|
+
|
92
|
+
trootscalar = test_colebrook_root_scalar()
|
93
|
+
tfsolve = test_colebrook_fsolve()
|
94
|
+
tnewton = test_colebrook_newton()
|
95
|
+
|
96
|
+
sol_newton = f_colebrook_white(.02, 1.e-4, .5, 1/(pi*(.5/2.)**2.)*.5/1.e-6)
|
97
|
+
|
98
|
+
assert sol_newton == tnewton
|
99
|
+
|
100
|
+
pass
|
@@ -0,0 +1,128 @@
|
|
1
|
+
|
2
|
+
import numpy as np
|
3
|
+
import matplotlib.pyplot as plt
|
4
|
+
|
5
|
+
from .pipe import pipe
|
6
|
+
from .chamber import chamber, junction
|
7
|
+
|
8
|
+
class network():
|
9
|
+
|
10
|
+
def __init__(self) -> None:
|
11
|
+
|
12
|
+
self.chambers:list[chamber] = []
|
13
|
+
self.pipes:list[pipe] = []
|
14
|
+
self.links:list[tuple[chamber,chamber,pipe]] = []
|
15
|
+
|
16
|
+
def add_chamber(self, chamber):
|
17
|
+
self.chambers.append(chamber)
|
18
|
+
|
19
|
+
def add_pipe(self, pipe):
|
20
|
+
self.pipes.append(pipe)
|
21
|
+
|
22
|
+
def link(self, chamber1, chamber2, pipe):
|
23
|
+
self.links.append((chamber1, chamber2, pipe))
|
24
|
+
|
25
|
+
def update(self, dt:float):
|
26
|
+
|
27
|
+
for chamber in self.chambers:
|
28
|
+
chamber.reset_q()
|
29
|
+
|
30
|
+
for chamber1, chamber2, pipe in self.links:
|
31
|
+
pipe.head_up = chamber1.head
|
32
|
+
pipe.head_down = chamber2.head
|
33
|
+
pipe.solve_flowrate()
|
34
|
+
|
35
|
+
chamber1.add_qout(pipe.flowrate)
|
36
|
+
chamber2.add_qin(pipe.flowrate)
|
37
|
+
|
38
|
+
for chamber in self.chambers:
|
39
|
+
chamber.update(dt)
|
40
|
+
|
41
|
+
if __name__ == "__main__":
|
42
|
+
|
43
|
+
def test_simplenetwork():
|
44
|
+
|
45
|
+
chamber1 = chamber()
|
46
|
+
chamber2 = chamber()
|
47
|
+
pipe1 = pipe()
|
48
|
+
|
49
|
+
net = network()
|
50
|
+
net.add_chamber(chamber1)
|
51
|
+
net.add_chamber(chamber2)
|
52
|
+
net.add_pipe(pipe1)
|
53
|
+
net.link(chamber1, chamber2, pipe1)
|
54
|
+
|
55
|
+
chamber1.elevation = 0.
|
56
|
+
chamber2.elevation = 0.
|
57
|
+
chamber1.area = 1.
|
58
|
+
chamber2.area = 1.
|
59
|
+
|
60
|
+
chamber1.head = 10.
|
61
|
+
chamber2.head = 0.
|
62
|
+
|
63
|
+
pipe1.viscosity = 1.e-6
|
64
|
+
pipe1.density = 1000.
|
65
|
+
pipe1.gravity = 9.81
|
66
|
+
|
67
|
+
pipe1.length = 100.
|
68
|
+
pipe1.diameter = 0.5
|
69
|
+
|
70
|
+
pipe1.k = 0.0001
|
71
|
+
|
72
|
+
net.update(1.)
|
73
|
+
|
74
|
+
def test_simplenetwork_w_junction(dt:float = 1.):
|
75
|
+
|
76
|
+
chamber1 = chamber()
|
77
|
+
chamber2 = chamber()
|
78
|
+
junc = junction()
|
79
|
+
pipe1 = pipe()
|
80
|
+
pipe2 = pipe()
|
81
|
+
|
82
|
+
net = network()
|
83
|
+
net.add_chamber(chamber1)
|
84
|
+
net.add_chamber(chamber2)
|
85
|
+
net.add_chamber(junc)
|
86
|
+
|
87
|
+
net.add_pipe(pipe1)
|
88
|
+
net.add_pipe(pipe2)
|
89
|
+
|
90
|
+
net.link(chamber1, junc, pipe1)
|
91
|
+
net.link(junc, chamber2, pipe2)
|
92
|
+
|
93
|
+
chamber1.elevation = 0.
|
94
|
+
chamber2.elevation = 0.
|
95
|
+
|
96
|
+
chamber1.area = 1.
|
97
|
+
chamber2.area = 1.
|
98
|
+
|
99
|
+
chamber1.is_bc = True
|
100
|
+
chamber1.bc_value = 10.
|
101
|
+
|
102
|
+
chamber2.is_bc = True
|
103
|
+
chamber2.bc_value = 0.
|
104
|
+
|
105
|
+
chamber1.head = 10.
|
106
|
+
chamber2.head = 0.
|
107
|
+
junc.head = 4.
|
108
|
+
|
109
|
+
for curpipe in [pipe1, pipe2]:
|
110
|
+
|
111
|
+
curpipe.viscosity = 1.e-6
|
112
|
+
curpipe.density = 1000.
|
113
|
+
curpipe.gravity = 9.81
|
114
|
+
|
115
|
+
curpipe.length = 50.
|
116
|
+
curpipe.diameter = 0.5
|
117
|
+
|
118
|
+
curpipe.k = 0.0001
|
119
|
+
|
120
|
+
evol = [junc.head]
|
121
|
+
old_head = 4.1
|
122
|
+
while abs(junc.head - old_head) > 1e-6:
|
123
|
+
old_head = junc.head
|
124
|
+
net.update(dt)
|
125
|
+
evol.append(junc.head)
|
126
|
+
|
127
|
+
plt.plot(evol)
|
128
|
+
plt.show()
|
@@ -0,0 +1,194 @@
|
|
1
|
+
import numpy as np
|
2
|
+
from math import pi
|
3
|
+
from scipy.optimize import fsolve
|
4
|
+
|
5
|
+
from .losses import f_colebrook_white
|
6
|
+
from .fluids import Water
|
7
|
+
|
8
|
+
GRAVITY = 9.81 # m/s^2
|
9
|
+
class pipe():
|
10
|
+
""" Pipe class for Bernoulli's equation """
|
11
|
+
|
12
|
+
def __init__(self) -> None:
|
13
|
+
|
14
|
+
self._head_up:float = 0. # upstream head [m]
|
15
|
+
self._head_down:float = 0. # downstream head [m]
|
16
|
+
self._flowrate:float = 0. # flowrate [$m^3s^{-1}$]
|
17
|
+
self._k:float = 0. # roughness of the pipe [m]
|
18
|
+
|
19
|
+
self.length:float = 0. # Length of the pipe [m]
|
20
|
+
self.diameter:float = 0. # Diameter of the pipe [m]
|
21
|
+
|
22
|
+
self.fluid = Water()
|
23
|
+
|
24
|
+
self.f = 0.02 # Initial guess for the friction factor
|
25
|
+
|
26
|
+
@property
|
27
|
+
def head_up(self):
|
28
|
+
return self._head_up
|
29
|
+
|
30
|
+
@head_up.setter
|
31
|
+
def head_up(self, value):
|
32
|
+
self._head_up = value
|
33
|
+
|
34
|
+
@property
|
35
|
+
def head_down(self):
|
36
|
+
return self._head_down
|
37
|
+
|
38
|
+
@head_down.setter
|
39
|
+
def head_down(self, value):
|
40
|
+
self._head_down = value
|
41
|
+
|
42
|
+
@property
|
43
|
+
def flowrate(self):
|
44
|
+
return self._flowrate
|
45
|
+
|
46
|
+
@flowrate.setter
|
47
|
+
def flowrate(self, value):
|
48
|
+
self._flowrate = value
|
49
|
+
self._solve_friction_factor()
|
50
|
+
|
51
|
+
@property
|
52
|
+
def k(self):
|
53
|
+
return self._k
|
54
|
+
|
55
|
+
@k.setter
|
56
|
+
def k(self, value):
|
57
|
+
self._k = value
|
58
|
+
self._solve_friction_factor()
|
59
|
+
|
60
|
+
@property
|
61
|
+
def area(self):
|
62
|
+
return pi * (self.diameter/2.)**2.
|
63
|
+
|
64
|
+
@property
|
65
|
+
def velocity(self):
|
66
|
+
return self.flowrate / self.area
|
67
|
+
|
68
|
+
@property
|
69
|
+
def perimeter(self):
|
70
|
+
return pi * self.diameter
|
71
|
+
|
72
|
+
@property
|
73
|
+
def epsilon(self):
|
74
|
+
return self.k / self.diameter
|
75
|
+
|
76
|
+
@property
|
77
|
+
def reynolds(self):
|
78
|
+
return self.velocity * self.diameter / self.fluid.nu
|
79
|
+
|
80
|
+
@property
|
81
|
+
def head_loss_k(self):
|
82
|
+
return self.length / self.diameter * self.friction_factor
|
83
|
+
|
84
|
+
@property
|
85
|
+
def head_loss(self):
|
86
|
+
return self.head_loss_k * self.velocity**2. / (2. * GRAVITY)
|
87
|
+
|
88
|
+
def _solve_friction_factor(self):
|
89
|
+
""" Update the friction factor using the Colebrook-White equation """
|
90
|
+
|
91
|
+
self.f = f_colebrook_white(self.f, self.k, self.diameter, self.reynolds)
|
92
|
+
|
93
|
+
return self.f
|
94
|
+
|
95
|
+
@property
|
96
|
+
def friction_factor(self):
|
97
|
+
return self.f
|
98
|
+
|
99
|
+
@property
|
100
|
+
def bernoulli_error(self):
|
101
|
+
return self.head_up - self.head_down - self.head_loss
|
102
|
+
|
103
|
+
def solve_flowrate(self):
|
104
|
+
|
105
|
+
def loc_bernoulli(flowrate):
|
106
|
+
self.flowrate = flowrate
|
107
|
+
return self.bernoulli_error
|
108
|
+
|
109
|
+
flowrate_solution = fsolve(loc_bernoulli, self.flowrate)
|
110
|
+
|
111
|
+
self.flowrate = flowrate_solution[0]
|
112
|
+
|
113
|
+
return self.flowrate
|
114
|
+
|
115
|
+
def solve_head_up(self):
|
116
|
+
|
117
|
+
def loc_bernoulli(head_up):
|
118
|
+
self.head_up = head_up
|
119
|
+
return self.bernoulli_error
|
120
|
+
|
121
|
+
head_up_solution = fsolve(loc_bernoulli, self.head_up)
|
122
|
+
|
123
|
+
self.head_up = head_up_solution[0]
|
124
|
+
|
125
|
+
return self.head_up
|
126
|
+
|
127
|
+
def solve_head_down(self):
|
128
|
+
|
129
|
+
def loc_bernoulli(head_down):
|
130
|
+
self.head_down = head_down
|
131
|
+
return self.bernoulli_error
|
132
|
+
|
133
|
+
head_down_solution = fsolve(loc_bernoulli, self.head_down)
|
134
|
+
|
135
|
+
self.head_down = head_down_solution[0]
|
136
|
+
|
137
|
+
return self.head_down
|
138
|
+
|
139
|
+
def solve_k(self):
|
140
|
+
|
141
|
+
def loc_bernoulli(k):
|
142
|
+
self.k = k
|
143
|
+
return self.bernoulli_error
|
144
|
+
|
145
|
+
k_solution = fsolve(loc_bernoulli, self.k)
|
146
|
+
|
147
|
+
self.k = k_solution[0]
|
148
|
+
|
149
|
+
return self.k
|
150
|
+
|
151
|
+
|
152
|
+
if __name__ == '__main__':
|
153
|
+
|
154
|
+
|
155
|
+
def test_pipe():
|
156
|
+
pipe1 = pipe()
|
157
|
+
|
158
|
+
pipe1.head_up = 10.
|
159
|
+
pipe1.head_down = 0.
|
160
|
+
pipe1.length = 100.
|
161
|
+
pipe1.diameter = 0.5
|
162
|
+
|
163
|
+
pipe1.k = 0.0001
|
164
|
+
pipe1.flowrate = 1.
|
165
|
+
|
166
|
+
print(pipe1.reynolds)
|
167
|
+
|
168
|
+
print(pipe1.head_loss)
|
169
|
+
|
170
|
+
assert abs(pipe1.head_loss - 3.737978364) < 1e-6
|
171
|
+
|
172
|
+
print(pipe1.solve_flowrate())
|
173
|
+
assert abs(pipe1.flowrate - 1.644579263) < 1e-6
|
174
|
+
|
175
|
+
pipe1.flowrate = 1.
|
176
|
+
pipe1.head_up = 10.
|
177
|
+
print(pipe1.solve_head_down())
|
178
|
+
|
179
|
+
assert abs(pipe1.head_down - 6.262021636) < 1e-6
|
180
|
+
|
181
|
+
pipe1.flowrate = 1.
|
182
|
+
pipe1.head_down = 0.
|
183
|
+
print(pipe1.solve_head_up())
|
184
|
+
|
185
|
+
assert abs(pipe1.head_up - 3.737978364) < 1e-6
|
186
|
+
|
187
|
+
pipe1.flowrate = 1.
|
188
|
+
pipe1.head_up = 10.
|
189
|
+
pipe1.head_down = 0.
|
190
|
+
print(pipe1.solve_k())
|
191
|
+
|
192
|
+
assert abs(pipe1.k - 4.95827141E-03) < 1e-9
|
193
|
+
|
194
|
+
pass
|
@@ -93,7 +93,7 @@ def circle_velocity_field(size:int=201, oxoy:tuple[float]=(0.,0.), dxdy:tuple[fl
|
|
93
93
|
|
94
94
|
return ps, t_total
|
95
95
|
|
96
|
-
def labyrinth(filename:str=r'
|
96
|
+
def labyrinth(filename:str=r'docs\source\_static\examples\labyrinth\lab_uv.npz', nb_particles:int=100, every:float=100.) -> tuple[Particle_system, float]:
|
97
97
|
"""
|
98
98
|
Load a labyrinth velocity field from file.
|
99
99
|
|