Вы находитесь на странице: 1из 11

GRADIENTE HIDRÁULICO CON PYTHON

Dennis O. VENTURA HUAMAN


vehude.15061996@gmail.com
Huancavelica - Perú

26 de septiembre de 2018

Resumen
Esta es una breve explicación del método de Gradiente Hidráulico propuesta por Todini y Pilati
(1987), mediante la programación en el Lenguaje PYTHON 3.X, con el fin de compartirles y expandir
el conocimiento sobre la programación orientada a la Ingeniería.

1. Introducción
La curiosidad de conocer y entrar en el inmenso mundo de la tecnología, hicieron que el autor se en-
camine en el aprendizaje a nuevos conocimientos de la programación, y el pequeño estudio de Ingeniería
en el campo de la Hidráulica, hicieron posible este trabajo.

La iniciativa de realizar este tipo de trabajo, es la necesidad de compartir y expandir los conocimientos
acerca de la programación orientado a temas de interés ingenieril, en esta ocasión al diseño de redes de
tubería de abastecimiento de Agua con el método del GRADIENTE HIDRÁULICO.

Deseando de que este trabajo sea de gran utilidad para estudiantes y profesionales de las carreras
afines a este tema.

“Imaginar un mundo donde cada uno de nosotros compartamos lo poco que conocemos, un sueño donde
todos somos hermanos.”

2. LENGUAJE DE PROGRAMACIÓN PYTHON 3.X


2.1. ¿Qué es Python?, ¿Qué debo de saber?
Lenguaje de programación interpretado, creado a finales de los ochentas ?por Guido van Rossum
en el Centro para las Matemáticas y la Informática (Países Bajos), como un sucesor del lenguaje de
programación ABC.
Este lenguaje es de fácil comprensión y sencillo de aprender, gracias a la simplicidad en su sintaxis,
solo se necesita las ganas de aprender.

Para poder entender el código descrito en este trabajo, es necesario comprender este lenguaje a nivel
intermedio (Funciones, clases y Programación orientada a objetos). Se necesita también conocimientos
básicos de Mecánica de Fluidos, así como el método en mención.

3. PYTHON APLICADO A OPERACIONES CON MATRICES


3.1. PAQUETE CREADO EN PYTHON: Matrix.py
Existen varias librerías y paquetes para la manipulación de este tipo de objeto, como por ejemplo
Numpy, sin embargo, queremos saber como funcionan las operaciones detrás de nuestro código, por eso
crearemos nuestra propia librería.

1
1 from __future__ import pr int_fu nction
2 import ast
3
4
5 def zeros (w , h ) :
6 return Matrix ([[0 * i * j for i in range ( w ) ] for j in range ( h ) ])
7
8
9 def s t r i n g _ t o _ m a t r i x ( data ) :
10 """ Code extracted from package Numpy """
11 for char in ’ [] ’:
12 data = data . replace ( char , ’ ’)
13
14 rows = data . split ( ’; ’)
15 new_data = []
16 count = 0
17 n_cols = 0
18 for row in rows :
19 trow = row . split ( ’ , ’)
20 new_row = []
21 for col in trow :
22 temp = col . split ()
23 new_row . extend ( map ( ast . literal_eval , temp ) )
24 if count == 0:
25 n_cols = len ( new_row )
26 elif len ( new_row ) != n_cols :
27 raise ValueError ( " Rows ␣ not ␣ the ␣ same ␣ size . " )
28 count += 1
29 new_data . append ( new_row )
30 return new_data
31
32
33 def m a t r i x _ t o _ s t r i n g ( matrix ) :
34 return [[ str ( i ) for i in j ] for j in matrix ]
35
36
37 def check_matrix ( matrix ) :
38 data = []
39 row = matrix [0]
40 for i in matrix :
41 n_cols = len ( i )
42 data . append ( n_cols == len ( row ) )
43 return all ( data )
44
45
46 def equals_size ( m1 , m_2 ) :
47 if check_matrix ( m1 ) and check_matrix ( m_2 ) :
48 if len ( m1 ) == len ( m_2 ) :
49 if len ( m1 [0]) == len ( m_2 [0]) :
50 return True
51 else :
52 return False
53 else :
54 return False
55 else :
56 return False
57
58
59 def mul_m ( m_1 , other ) :
60 if isinstance ( other , list ) :
61 if len ( m_1 [0]) == len ( other ) :
62 m1 = zeros ( len ( other [0]) , len ( m_1 ) )
63 for i in range ( len ( m_1 ) ) :
64 for j in range ( len ( other [0]) ) :
65 for k in range ( len ( other ) ) :
66 m1 [ i ][ j ] = m1 [ i ][ j ] + m_1 [ i ][ k ] * other [ k ][ j ]
67 return Matrix ( m1 )
68 else :
69 raise IndexError ( ’ Invalid ␣ Dimension ’)
70 elif isinstance ( other , float ) or isinstance ( other , int ) :
71 return Matrix ([[ i * other for i in j ] for j in m_1 ])
72 else :
73 raise ValueError ( ’ Invalid ␣ value ’)

2
74
75
76 def transpose ( matrix ) :
77 return Matrix ([[ matrix [ i ][ j ] for i in range ( len ( matrix ) ) ] for j in range ( len ( matrix
[0]) ) ])
78
79
80 def diagonal ( data , size =2) :
81 if isinstance ( data , float ) or isinstance ( data , int ) :
82 new_data = zeros ( size , size )
83 for i in range ( size ) :
84 for j in range ( size ) :
85 if i == j :
86 new_data [ i ][ j ] = data
87 return new_data
88 elif isinstance ( data , list ) :
89 new_data = zeros ( len ( data ) , len ( data ) )
90 for i in range ( len ( data ) ) :
91 for j in range ( len ( data ) ) :
92 if i == j :
93 new_data [ i ][ j ] = data [ i ]
94 return new_data
95
96
97 def matrix_solve (m , column ) :
98 """
99 : param m : Matrix , system equation .
100 : param column : Column Matrix , system equation .
101 : return : Column matrix , result of system equation .
102 For L . Code by : Michael Halls - Moore """
103 size = len ( m )
104 l_1 = zeros ( size , size )
105 for i in range ( size ) :
106 for k in range ( i + 1) :
107 tmp_sum = sum ( l_1 [ i ][ j ] * l_1 [ k ][ j ] for j in range ( k ) )
108
109 if i == k :
110 l_1 [ i ][ k ] = ( m [ i ][ i ] - tmp_sum ) ** 0.5
111 else :
112 l_1 [ i ][ k ] = (1.0 / l_1 [ k ][ k ] * ( m [ i ][ k ] - tmp_sum ) )
113 z = zeros (1 , size )
114 for i in range ( size ) :
115 sum1 = 0
116 for k in range ( i ) :
117 sum1 = sum1 + l_1 [ i ][ k ] * z [ k ][0]
118 z [ i ][0] = ( column [ i ][0] - sum1 ) / l_1 [ i ][ i ]
119 x = zeros (1 , size )
120 for i in range ( size - 1 , -1 , -1) :
121 sum1 = 0
122 for k in range ( i + 1 , size ) :
123 sum1 = sum1 + l_1 [ k ][ i ] * x [ k ][0]
124
125 x [ i ][0] = ( z [ i ][0] - sum1 ) / l_1 [ i ][ i ]
126 return x
127
128
129 def m a t r i x _ s o l v e _ m a t r i x (m , m2 ) :
130 m_f = [[ i *0 for i in j ] for j in m2 ]
131 m3 = Matrix ([[ i for i in j ] for j in m2 ]) . T
132 l_c = []
133 for i in range ( len ( m3 ) ) :
134 l_c . append ( Matrix ([ m3 [ i ]]) . T )
135 l_r = []
136 for i in l_c :
137 column = matrix_solve (m , i )
138 l_r . append ( column )
139 for i in range ( len ( m_f ) ) :
140 for j in range ( len ( m_f [0]) ) :
141 m_f [ i ][ j ] = l_r [ j ][ i ][0]
142 return Matrix ( m_f )
143
144
145 def norm ( matrix ) :

3
146 return ( sum ([ sum ([ i **2 for i in j ]) for j in matrix ]) ) **.5
147
148
149 class Matrix :
150 def __init__ ( self , data ) :
151 if isinstance ( data , Matrix ) :
152 self . m = data . m
153 if isinstance ( data , str ) :
154 self . m = s t r i n g _ t o _ m a t r i x ( data )
155 if isinstance ( data , list ) :
156 if check_matrix ( data ) :
157 self . m = data
158 else :
159 raise ValueError ( " Rows ␣ not ␣ the ␣ same ␣ size . " )
160 if isinstance ( data , float ) :
161 raise ValueError ( " Could ␣ not ␣ convert ␣ float ␣ to ␣ matrix " )
162
163 def __str__ ( self ) :
164 tr = m a t r i x _ t o _ s t r i n g ( self . m )
165 trn_tr = transpose ( tr )
166 n_str = [ max ([ len ( i ) for i in j ]) for j in trn_tr ]
167 tr = [[ i . center ( n_str [ j ]) for (j , i ) in enumerate ( k ) ] for k in tr ]
168 return ’ Matrix ␣ ( ’+ str ( len ( self . m ) ) + ’ , ’+ str ( len ( self . m [0]) ) + ’) : ␣ \ n ’ + ’\ n ’. join ([ ’
\ t ’. join ( i ) for i in tr ])
169
170 def __add__ ( self , other ) :
171 if equals_size ( self .m , other . m ) :
172 return Matrix ([[ i + j for (i , j ) in zip (k , l ) ] for (k , l ) in zip ( self .m , other .
m ) ])
173 elif isinstance ( other , float ) :
174 raise ValueError ( " Could ␣ not ␣ convert ␣ float ␣ to ␣ matrix " )
175 else :
176 raise ValueError ( " Invalid ␣ dimension " )
177
178 def __sub__ ( self , other ) :
179 if equals_size ( self .m , other . m ) :
180 return Matrix ([[ i - j for (i , j ) in zip (k , l ) ] for (k , l ) in zip ( self .m , other .
m ) ])
181 else :
182 raise ValueError ( " Could ␣ not ␣ convert ␣ float / int ␣ to ␣ matrix " )
183
184 def __mul__ ( self , other ) :
185 if isinstance ( other , float ) or isinstance ( other , int ) :
186 return mul_m ( self .m , other )
187 elif isinstance ( other , Matrix ) :
188 return mul_m ( self .m , other . m )
189
190 def __rmul__ ( self , other ) :
191 return mul_m ( self .m , other )
192
193 def __floordiv__ ( self , other ) :
194 if len ( other . m [0]) < 2:
195 return matrix_solve ( self .m , other . m )
196 else :
197 return m a t r i x _ s o l v e _ m a t r i x ( self .m , other . m )
198
199 def __getitem__ ( self , item ) :
200 if isinstance ( item , tuple ) :
201 return self . m [ item [0]][ item [1]]
202 elif isinstance ( item , int ) :
203 return self . m [ item ]
204 else :
205 raise TypeError ( ’ Invalid ␣ Item ␣ Type ’)
206
207 def __len__ ( self ) :
208 return len ( self . m )
209
210 def __neg__ ( self ) :
211 return Matrix ([[ - i for i in j ] for j in self . m ])
212
213 def __abs__ ( self ) :
214 return Matrix ([[ abs ( i ) for i in j ] for j in self . m ])
215

4
216 def __copy__ ( self ) :
217 return Matrix ([[ i * 1 for i in j ] for j in self . m ])
218
219 def __round__ ( self , decimals =0) :
220 return Matrix ([[ round (i , decimals ) for i in j ] for j in self . m ])
221
222 def copy ( self ) :
223 return Matrix ([[ i for i in j ] for j in self . m ])
224
225 def del_col ( self , n ) :
226 m1 = [[ i for i in j ] for j in self . m ]
227 for i in m1 :
228 i . pop ( n )
229 return Matrix ( m1 )
230
231 def get_col ( self , l ) :
232 m1 = [[0 * i * j for j in range ( len ( l ) ) ] for i in range ( len ( self . m ) ) ]
233 for i in range ( len ( self . m ) ) :
234 for j in range ( len ( l ) ) :
235 m1 [ i ][ j ] = self . m [ i ][ l [ j ]]
236 return Matrix ( m1 )
237
238 @property
239 def tolist ( self ) :
240 return self . m
241
242 T = property ( lambda self : transpose ( self ) , lambda self , v : None , lambda self : None )
243 norm = property ( lambda self : norm ( self ) , lambda self , v : None , lambda self : None )

Listing 1: Matrix.py

4. GRADIENTE HIDRÁULICO
4.1. PROGRAMA CREADO EN PYTHON: WaterHID.py
Para ayudar al ordenador en el cálculo de algunas constantes, éstas se declararon anticipadamente
(Lineas: 7-21), algunas de estas son utilizadas en el cálculo del factor de fricción por ecuaciones empíricas.
(Linea: 24-48)

Utilizando la programación orientada a objetos, se declararon tres tipos de objeto: Reservoir", "Node 2

"Pipe"(Reservorio, Conexión y Tubería). Se desarrolló de esta manera teniendo en cuenta que estos ele-
mentos dentro de una red de Abastecimiento poseen propiedades propias, como por ejemplo un Reservorio
tiene un Nivel de Agua, coordenadas, etc. (Linea: 51-58).
Otro ejemplo es la conexión de tuberías o nodo, el cual posee características como el Nivel Topográfico,
la Altura Piezométrica, la Presión, entre otros. (Linea: 61-72) Y las tuberías, quienes son elementos más
complejos dentro de la red.(Linea: 78-131)

El método matricial del Gradiente Hidráulico, utiliza algunas constantes en forma matricial (Matriz
A12 , A21 , A10 , etc.), estas se determinan a partir de las características de cada elemento (Linea: 134-163).
A continuación, utilizando las constantes determinadas anteriormente, se pasa a un proceso iterativo en
el cual se busca la convergencia hasta lograr un error mínimo. (Linea: 166-190)
Finalmente se retorna los resultados si la convergencia ha resultado y se ha logrado el error mínimo
deseado.
Muy aparte del proceso descrito, se elaboró (Aún en fase de desarrollo), un programa para el diseño
y determinación de diámetros óptimos mediante los Algoritmos Genéticos (Linea: 248-337)
En la parte baja del código se describe un ejemplo, solo basta con borrar las comillas que lo encierran
y ejecutar el programa.

5
1 from __future__ import pr int_fu nction
2 from math import log
3 from Matrix import *
4 from random import randint , sample , random
5
6
7 pi = 3.14159265359
8 A1 = 0.314 159265 359 e04 # * 1000* PI
9 A2 = 0.157 079632 679 e04 # * 500* PI
10 A3 = 0.502 654824 574 e02 # * 16* PI
11 A4 = 6.283185307 # * 2* PI
12 A5 = 1.27323954474 # 4/ PI
13 A8 = 4.61841319859 # 5.74*( PI /4) ^.9
14 A9 = -8.685889638 e -01 # -2/ ln (10)
15 AA = -1.5634601348 # -2*.9*2/ ln (10)
16 AB = 3.28895476345 e -03 # 5.74/( 4000^. 9)
17 AC = -5.14214965799 e -03 # AA * AB
18 G = 9.81 # GRAVITY
19 G2 = 19.62 # 2*9.81
20 G2_1 = 5.0968399592 e -02 # 1/( G2 )
21 G3 = 0.0826268 # CTE 3
22
23
24 def d_w ( flow , ks , d , vis ) :
25 q = abs ( flow )
26 s = vis * d
27 w = q/s
28 if w >= A1 :
29 y1 = A8 / pow (w , 0.9)
30 y2 = ks / (3.7 * d ) + y1
31 y3 = A9 * log ( y2 )
32 f = 1 / y3 **2
33 elif w > A2 :
34 y2 = ks / (3.7 * d ) + AB
35 y3 = A9 * log ( y2 )
36 fa = 1.0 / y3 **2
37 fb = (2.0 + AC / ( y2 * y3 ) ) * fa
38 r = w / A2
39 x1 = 7.0 * fa - fb
40 x2 = 0.128 - 17.0 * fa + 2.5 * fb
41 x3 = -0.128 + 13.0 * fa - ( fb + fb )
42 x4 = r * (0.032 - 3.0 * fa + 0.5 * fb )
43 f = x1 + r * ( x2 + r * ( x3 + x4 ) )
44 elif w > A4 :
45 f = A3 * s / q
46 else :
47 f = 8.0
48 return f
49
50
51 class Reservoir ( object ) :
52 level = 0.0
53 cond = True
54 name = ’ ’
55 t_level = ’ ’
56 item = None
57 x = 0
58 y = 0
59
60
61 class Node ( object ) :
62 demand = 0.0
63 level = 0.0
64 height = 0.0
65 cond = True
66 name = ’ ’
67 t_pressure = ’ ’
68 t_level = ’ ’
69 t_height = ’ ’
70 item = None
71 x = 0
72 y = 0
73

6
74 def pressure ( self ) :
75 return self . height - self . level
76
77
78 class Pipe ( object ) :
79 n_i = None
80 n_f = None
81 diam = 0.0
82 long = 0.0
83 ks = 0.0
84 C = 0.0
85 n_m = 0.0
86 kl = 0.0
87 flow = 0.0
88 vis = 0.0
89 t = 0.0
90 v_t = True # True - > Vis , False - > Temperature
91 bomb_a = 0.0
92 bomb_b = 0.0
93 bomb_c = 0.0
94 f = 0.0
95 cond = ’ Open ’
96 name = ’ ’
97 t_flow = ’ ’
98 t_speed = ’ ’
99 t_long = ’ ’
100 t_hf = ’ ’
101 item = None
102
103 @property
104 def area ( self ) :
105 return pi * self . diam * self . diam /4
106
107 @property
108 def speed ( self ) :
109 return self . flow / self . area
110
111 @property
112 def reynolds ( self ) :
113 return A5 * self . flow /( self . diam * self . vis )
114
115 def alpha ( self , eq : str ) :
116 if eq == ’d - w ’:
117 self . vis = self . vis if self . v_t else (1.14 -0.031*( self .t -15) +0.00068*( self .t
-15) **2) *.000001
118 self . f = d_w ( self . flow , self . ks , self . diam , self . vis )
119 return G3 * self . f * self . long / self . diam **5
120 elif eq == ’c - m ’:
121 return 10.294 * self . n_m ** 2 * self . long / self . diam ** 5.33
122 elif eq == ’h - w ’:
123 return 10.674 * self . long / ( self . C ** 1.85 * self . diam ** 4.78)
124
125 @property
126 def beta ( self ) :
127 return G3 * self . flow * self . kl / self . diam ** 4
128
129 @property
130 def lamb ( self ) :
131 return self . bomb_a * self . flow * self . flow + self . bomb_b * self . flow + self . bomb_c
132
133
134 def calc_cte ( l_pipes , l_nodes , l_reservoir , eq = ’D - W ’) :
135 n_p = len ( l_pipes )
136 n_n = len ( l_nodes )
137 n_r = len ( l_reservoir )
138 n_t = n_n + n_r
139 a_t = zeros ( n_t , n_p )
140 l_t = l_reservoir + l_nodes
141 co_m = 2
142 equation = eq . lower ()
143 if equation == ’d - w ’:
144 co_m = 2
145 elif equation == ’c - m ’:

7
146 co_m = 2
147 elif equation == ’h - w ’:
148 co_m = 1.85
149 for i in range ( n_p ) :
150 a_t [ i ][ l_t . index ( l_pipes [ i ]. n_i ) ] = -1
151 a_t [ i ][ l_t . index ( l_pipes [ i ]. n_f ) ] = 1
152 n_c_d = [ i + n_r for i in range ( n_n ) if l_nodes [ i ]. cond ]
153 a_12 = a_t . get_col ( n_c_d )
154 n_c_c = [ i for i in range ( n_r ) if l_reservoir [ i ]. cond ]
155 a_10 = a_t . get_col ( n_c_c )
156 a_21 = a_12 . T
157 n_d = diagonal ( co_m , n_p )
158 ide = diagonal (1 , n_p )
159 h_o = Matrix ([[ i . level ] for i in l_reservoir ])
160 q_d = Matrix ([[ i . demand ] for i in l_nodes ])
161 q_o = Matrix ([[ i . flow ] for i in l_pipes ])
162 return equation , co_m , a_21 , n_d , a_12 , a_10 , h_o , q_d , q_o , { ’ n_p ’: n_p , ’ n_n ’: n_n ,
’ n_r ’: n_r , ’ n_t ’: n_t , ’ a_t ’: a_t , ’ a_12 ’: a_12 ,
163 ’ a_21 ’: a_21 , ’ a_10 ’:
a_10 , ’ n_d ’: n_d , ’ ide ’: ide }
164
165
166 def iterate_w ( l_pipes , equation , co_m , a_21 , a_12 , a_10 , n_d , q_o , h_o , q_d , ide , error ,
i_max ) :
167 cont = 0
168 while cont < i_max :
169 l_a11 = []
170 for i in l_pipes :
171 l_a11 . append ( i . alpha ( equation ) * i . flow ** ( co_m - 1) + i . beta + i . lamb / i .
flow )
172 a_11 = diagonal ( l_a11 )
173 h_nxt = -( a_21 * ( n_d * a_11 // a_12 ) ) // ( a_21 * ( n_d // ( q_o + a_11 // a_10 *
h_o ) ) + q_d - a_21 * q_o )
174 q_nxt = ide * q_o - n_d // q_o - ( n_d * a_11 ) // ( a_12 * h_nxt + a_10 * h_o )
175 if isinstance ( h_nxt [0][0] , complex ) or isinstance ( q_nxt [0][0] , complex ) :
176 if h_nxt [0][0]. imag < 1e -3 or h_nxt [0][0]. imag < 1e -3:
177 h_nxt = Matrix ([[ i . real for i in j ] for j in h_nxt ])
178 q_nxt = Matrix ([[ i . real for i in j ] for j in q_nxt ])
179 else :
180 return False , dict
181 pres = ( abs ( q_o ) - abs ( q_nxt ) ) . norm
182 if pres < error :
183 break
184 q_o = abs ( q_nxt )
185 for i , j in enumerate ( l_pipes ) :
186 j . flow = q_o [ i ][0]
187 cont += 1
188 else :
189 return False , dict
190 return True , { ’q ’: q_nxt , ’h ’: h_nxt , ’ a_11 ’: a_11 }
191
192
193 def water_net ( l_pipes , l_nodes , l_reservoir , eq = ’D - W ’ , error =1 e -4 , i_max =20) :
194 """
195 EXAMPLE :
196 node1 = Node ()
197 node1 . demand , node1 . level = .06 , 0.0
198 node2 = Node ()
199 node2 . demand , node2 . level = .04 , 0.0
200 node3 = Node ()
201 node3 . demand , node3 . level = .03 , 0.0
202 node4 = Node ()
203 node4 . demand , node4 . level = .03 , 0.0
204 node5 = Node ()
205 node5 . demand , node5 . level = .04 , 0.0
206 l_n = [ node1 , node2 , node3 , node4 , node5 ]
207 res1 = Reservoir ()
208 res1 . level = 100
209 l_r = [ res1 ]
210 pipe1 = Pipe ()
211 pipe1 . n_i , pipe1 . n_f , pipe1 . flow , pipe1 . diam , pipe1 . long , pipe1 . vis , pipe1 . ks =
212 res1 , node1 ,.1 , .254 , 500 , 1.14 E -6 , 6E -5
213 pipe2 = Pipe ()

8
214 pipe2 . n_i , pipe2 . n_f , pipe2 . flow , pipe2 . diam , pipe2 . long , pipe2 . vis , pipe2 . ks , pipe2 .
kl =
215 node1 , node2 , .1 , .1524 , 400 , 1.14 E -6 , 6E -5 , 10
216 pipe3 = Pipe ()
217 pipe3 . n_i , pipe3 . n_f , pipe3 . flow , pipe3 . diam , pipe3 . long , pipe3 . vis , pipe3 . ks =
218 node3 , node2 , .1 , .1016 , 200 , 1.14 E -6 , 6E -5
219 pipe4 = Pipe ()
220 pipe4 . n_i , pipe4 . n_f , pipe4 . flow , pipe4 . diam , pipe4 . long , pipe4 . vis , pipe4 . ks =
221 node4 , node3 , .1 , .1524 , 400 , 1.14 E -6 , 6E -5
222 pipe5 = Pipe ()
223 pipe5 . n_i , pipe5 . n_f , pipe5 . flow , pipe5 . diam , pipe5 . long , pipe5 . vis , pipe5 . ks =
224 node1 , node4 , .1 , .1016 , 200 , 1.14 E -6 , 6E -5
225 pipe6 = Pipe ()
226 pipe6 . n_i , pipe6 . n_f , pipe6 . flow , pipe6 . diam , pipe6 . long , pipe6 . vis , pipe6 . ks =
227 node5 , node4 , .1 , .2032 , 600 , 1.14 E -6 , 6E -5
228 pipe7 = Pipe ()
229 pipe7 . n_i , pipe7 . n_f , pipe7 . flow , pipe7 . diam , pipe7 . long , pipe7 . vis , pipe7 . ks =
230 res1 , node5 , .1 , .254 , 300 , 1.14 E -6 , 6E -5
231 l_p = [ pipe1 , pipe2 , pipe3 , pipe4 , pipe5 , pipe6 , pipe7 ]
232 water_net ( l_p , l_n , l_r , i_max =45) """
233 equation , co_m , a_21 , n_d , a_12 , a_10 , h_o , q_d , q_o , di = calc_cte ( l_pipes , l_nodes ,
l_reservoir , eq )
234 ide = di [ ’ ide ’]
235 cond , res = iterate_w ( l_pipes , equation , co_m , a_21 , a_12 , a_10 , n_d , q_o , h_o , q_d ,
ide , error , i_max )
236 if cond :
237 q_nxt = res [ ’q ’]
238 h_nxt = res [ ’h ’]
239 for i , j in enumerate ( l_pipes ) :
240 j . flow = q_nxt [ i ][0]
241 for i , j in enumerate ( l_nodes ) :
242 j . height = h_nxt [ i ][0]
243 return True , dict ( res , ** di )
244 else :
245 return False , dict
246
247
248 def copy_of ( l_i ) :
249 l_i2 = []
250 for i in l_i :
251 new_item = i
252 l_i2 . append ( new_item )
253 return l_i2
254
255
256 def individual ( diam : dict , l_pipes ) :
257 return [ list ( diam . keys () ) [ randint (0 , len ( diam ) -1) ] for i in range ( l_pipes ) ]
258
259
260 def population ( num , diam , l_pipes ) :
261 return [ individual ( diam , l_pipes ) for i in range ( num ) ]
262
263
264 def weight ( l_d , l_pipes , l_nodes , l_reservoir , h_v , diam ) :
265 k = 2 e5
266 l_pipes2 = copy_of ( l_pipes )
267 for i , j in enumerate ( l_pipes2 ) :
268 j . diam = l_d [ i ]
269 cond , _ = water_net ( l_pipes2 , l_nodes , l_reservoir )
270 if cond :
271 f_p = 0
272 cost = 0
273 for i in l_nodes :
274 f_p += abs (( i . pressure () - h_v [ ’ h_max ’ ]) / h_v [ ’ h_max ’ ]) + abs (( i . pressure () -
h_v [ ’ h_min ’ ]) / h_v [ ’ h_min ’ ])
275 for i in l_pipes2 :
276 f_p += abs (( i . speed - h_v [ ’ v_max ’ ]) / h_v [ ’ v_max ’ ]) + abs (( i . speed - h_v [ ’ v_min ’ ]) /
h_v [ ’ v_min ’ ])
277 cost += i . long * diam [ i . diam ]
278 if k - f_p * cost > 0:
279 return k - f_p * cost
280 else :
281 return 0

9
282 else :
283 return 0
284
285
286 def sel_and_rep ( new_pop , l_pipes , l_nodes , l_res , cond , diam ) :
287 l_w = []
288 for j in new_pop :
289 l_w . append ( weight (j , l_pipes , l_nodes , l_res , cond , diam ) )
290 d_l = [( l_w [ i ] , new_pop [ i ]) for i in range ( len ( new_pop ) ) ]
291 punt = [ i [1] for i in sorted ( d_l , reverse = True ) ]
292 pop = [[ i for i in j ] for j in punt ]
293 selected = punt [ int ( len ( d_l ) / 2) :]
294 for i in range ( int ( len ( d_l ) /2) ) :
295 point = randint (1 , len ( l_pipes ) - 1) # Se elige un punto para hacer el
intercambio
296 padre = sample ( selected , 2) # Se eligen dos padres
297 pop [1][: point ] = padre [0][: point ] # Se mezcla el material genetico de los padres
en cada nuevo individuo
298 pop [1][ point :] = padre [1][ point :]
299 return pop
300
301
302 def mutation ( n_pop , l_pipes , l_nodes , l_res , h_v , d_di , n_p ) :
303 pop = copy_of ( n_pop )
304 for i in range ( len ( n_pop ) ) :
305 if random () <= 1: # Cada individuo de la poblacion ( menos los padres ) tienen una
probabilidad de mutar
306 point = randint (0 , len ( l_pipes ) - 1) # Se elgie un punto al azar
307 diam = n_pop [ i ]
308 n_l_pipes = copy_of ( l_pipes )
309 for j , k in enumerate ( diam ) :
310 n_l_pipes [ j ]. diam = k
311 cond , _ = water_net ( n_l_pipes , l_nodes , l_res )
312 l_diams = list ( d_di . keys () )
313 if cond :
314 ind = l_diams . index ( n_l_pipes [ point ]. diam )
315 if n_l_pipes [ point ]. speed < h_v [ ’ v_min ’ ]:
316 if ind < ( len ( l_diams ) - 1) :
317 pop [ i ][ point ] = l_diams [ ind +1]
318 elif n_l_pipes [ point ]. speed > h_v [ ’ v_max ’ ]:
319 if ind > 0:
320 pop [ i ][ point ] = l_diams [ ind -1]
321 else :
322 pop = population ( n_p , d_di , len ( l_pipes ) )
323 return pop
324
325
326 def designer_e_g ( l_pipes , l_nodes , l_res , diam , cond , ge =10 , n_p =10 , bar = None ) :
327 pop = population ( n_p , diam , len ( l_pipes ) )
328 n_pop = [[ i for i in j ] for j in pop ]
329 if bar is not None :
330 bar . setMinimum (0)
331 bar . setMaximum ( ge )
332 for i in range ( ge ) :
333 if bar is not None :
334 bar . setValue ( i )
335 n_pop = sel_and_rep ( n_pop , l_pipes , l_nodes , l_res , cond , diam )
336 n_pop = mutation ( n_pop , l_pipes , l_nodes , l_res , cond , diam , n_p )
337 return n_pop
338
339
340 """
341 node1 = Node ()
342 node1 . demand , node1 . level = .06 , 0.0
343 node2 = Node ()
344 node2 . demand , node2 . level = .04 , 0.0
345 node3 = Node ()
346 node3 . demand , node3 . level = .03 , 0.0
347 node4 = Node ()
348 node4 . demand , node4 . level = .03 , 0.0
349 node5 = Node ()
350 node5 . demand , node5 . level = .04 , 0.0
351 l_n = [ node1 , node2 , node3 , node4 , node5 ]

10
352 res1 = Reservoir ()
353 res1 . level = 100
354 l_r = [ res1 ]
355 pipe1 = Pipe ()
356 pipe1 . n_i , pipe1 . n_f , pipe1 . flow , pipe1 . diam , pipe1 . long , pipe1 . vis , pipe1 . ks = res1 ,
node1 ,.1 , .254 , 500 , 1.14 E -6 , 6E -5
357 pipe2 = Pipe ()
358 pipe2 . n_i , pipe2 . n_f , pipe2 . flow , pipe2 . diam , pipe2 . long , pipe2 . vis , pipe2 . ks , pipe2 . kl =
node1 , node2 , .1 , .1524 , 400 , 1.14 E -6 , 6E -5 , 10
359 pipe3 = Pipe ()
360 pipe3 . n_i , pipe3 . n_f , pipe3 . flow , pipe3 . diam , pipe3 . long , pipe3 . vis , pipe3 . ks = node3 ,
node2 , .1 , .1016 , 200 , 1.14 E -6 , 6E -5
361 pipe4 = Pipe ()
362 pipe4 . n_i , pipe4 . n_f , pipe4 . flow , pipe4 . diam , pipe4 . long , pipe4 . vis , pipe4 . ks = node4 ,
node3 , .1 , .1524 , 400 , 1.14 E -6 , 6E -5
363 pipe5 = Pipe ()
364 pipe5 . n_i , pipe5 . n_f , pipe5 . flow , pipe5 . diam , pipe5 . long , pipe5 . vis , pipe5 . ks = node1 ,
node4 , .1 , .1016 , 200 , 1.14 E -6 , 6E -5
365 pipe6 = Pipe ()
366 pipe6 . n_i , pipe6 . n_f , pipe6 . flow , pipe6 . diam , pipe6 . long , pipe6 . vis , pipe6 . ks = node5 ,
node4 , .1 , .2032 , 600 , 1.14 E -6 , 6E -5
367 pipe7 = Pipe ()
368 pipe7 . n_i , pipe7 . n_f , pipe7 . flow , pipe7 . diam , pipe7 . long , pipe7 . vis , pipe7 . ks = res1 ,
node5 , .1 , .254 , 300 , 1.14 E -6 , 6E -5
369 l_p = [ pipe1 , pipe2 , pipe3 , pipe4 , pipe5 , pipe6 , pipe7 ]
370 water_net ( l_p , l_n , l_r , i_max =45)
371
372 l_d_c = {.5: 2.5 , .254: 1.3 , .2032: 0.9 , .1524: 0.7 , .1016: 0.4} # major to minor
373 cnd = { ’ v_min ’: .6 , ’ v_max ’: 3 , ’ h_min ’: 10 , ’ h_max ’: 50}
374 a = designer_e_g ( l_p , l_n , l_r , l_d_c , cnd )
375 l = a [0]
376 for i , j in enumerate ( l_p ) :
377 j . diam = l [ i ]
378 cond , a = water_net ( l_p , l_n , l_r )
379 for i in l_p :
380 print ( i . speed )
381 print ( a [ ’ a_11 ’]) """

Listing 2: WaterHID.py

11