14
14
logger = logging .getLogger (__name__ )
15
15
16
16
def skeletonize (wn , pipe_diameter_threshold , branch_trim = True , series_pipe_merge = True ,
17
- parallel_pipe_merge = True , max_cycles = None , use_epanet = True ,
17
+ parallel_pipe_merge = True , max_cycles = None , use_epanet = True ,
18
+ pipes_to_exclude :list = [], junctions_to_exclude :list = [],
18
19
return_map = False , return_copy = True ):
19
20
"""
20
21
Perform network skeletonization using branch trimming, series pipe merge,
@@ -43,6 +44,10 @@ def skeletonize(wn, pipe_diameter_threshold, branch_trim=True, series_pipe_merge
43
44
use_epanet: bool, optional
44
45
If True, use the EpanetSimulator to compute headloss in pipes.
45
46
If False, use the WNTRSimulator to compute headloss in pipes.
47
+ pipes_to_exclude: list, optional
48
+ List of pipe names to exclude from skeletonization
49
+ junctions_to_exclude: list, optional
50
+ List of junction names to exclude from skeletonization
46
51
return_map: bool, optional
47
52
If True, return a skeletonization map. The map is a dictionary
48
53
that includes original nodes as keys and a list of skeletonized nodes
@@ -60,7 +65,12 @@ def skeletonize(wn, pipe_diameter_threshold, branch_trim=True, series_pipe_merge
60
65
nodes as keys and a list of skeletonized nodes that were merged into
61
66
each original node as values.
62
67
"""
63
- skel = _Skeletonize (wn , use_epanet , return_copy )
68
+ if len (pipes_to_exclude ) > 0 :
69
+ assert len (set (pipes_to_exclude ) - set (wn .pipe_name_list )) == 0
70
+ if len (junctions_to_exclude ) > 0 :
71
+ assert len (set (junctions_to_exclude ) - set (wn .junction_name_list )) == 0
72
+
73
+ skel = _Skeletonize (wn , use_epanet , return_copy , pipes_to_exclude , junctions_to_exclude )
64
74
65
75
skel .run (pipe_diameter_threshold , branch_trim , series_pipe_merge ,
66
76
parallel_pipe_merge , max_cycles )
@@ -73,7 +83,7 @@ def skeletonize(wn, pipe_diameter_threshold, branch_trim=True, series_pipe_merge
73
83
74
84
class _Skeletonize (object ):
75
85
76
- def __init__ (self , wn , use_epanet , return_copy ):
86
+ def __init__ (self , wn , use_epanet , return_copy , pipes_to_exclude , junctions_to_exclude ):
77
87
78
88
if return_copy :
79
89
# Get a copy of the WaterNetworkModel
@@ -93,6 +103,7 @@ def __init__(self, wn, use_epanet, return_copy):
93
103
self .skeleton_map = skel_map
94
104
95
105
# Get a list of junction and pipe names that are associated with controls
106
+ # Add them to junctions and pipes to exclude
96
107
junc_with_controls = []
97
108
pipe_with_controls = []
98
109
for name , control in self .wn .controls ():
@@ -101,8 +112,10 @@ def __init__(self, wn, use_epanet, return_copy):
101
112
junc_with_controls .append (req .name )
102
113
elif isinstance (req , Pipe ):
103
114
pipe_with_controls .append (req .name )
104
- self .junc_with_controls = list (set (junc_with_controls ))
105
- self .pipe_with_controls = list (set (pipe_with_controls ))
115
+ self .junc_to_exclude = list (set (junc_with_controls ))
116
+ self .junc_to_exclude .extend (junctions_to_exclude )
117
+ self .pipe_to_exclude = list (set (pipe_with_controls ))
118
+ self .pipe_to_exclude .extend (pipes_to_exclude )
106
119
107
120
# Calculate pipe headloss using a single period EPANET simulation
108
121
duration = self .wn .options .time .duration
@@ -163,7 +176,7 @@ def branch_trim(self, pipe_threshold):
163
176
patterns) to the neighboring junction.
164
177
"""
165
178
for junc_name in self .wn .junction_name_list :
166
- if junc_name in self .junc_with_controls :
179
+ if junc_name in self .junc_to_exclude :
167
180
continue
168
181
neighbors = list (nx .neighbors (self .G ,junc_name ))
169
182
if len (neighbors ) > 1 :
@@ -181,7 +194,7 @@ def branch_trim(self, pipe_threshold):
181
194
pipe = self .wn .get_link (pipe_name )
182
195
if not ((isinstance (pipe , Pipe )) and \
183
196
(pipe .diameter <= pipe_threshold ) and \
184
- pipe_name not in self .pipe_with_controls ):
197
+ pipe_name not in self .pipe_to_exclude ):
185
198
continue
186
199
187
200
logger .info ('Branch trim: ' + str (junc_name ) + str (neighbors ))
@@ -215,7 +228,7 @@ def series_pipe_merge(self, pipe_threshold):
215
228
to the nearest junction.
216
229
"""
217
230
for junc_name in self .wn .junction_name_list :
218
- if junc_name in self .junc_with_controls :
231
+ if junc_name in self .junc_to_exclude :
219
232
continue
220
233
neighbors = list (nx .neighbors (self .G ,junc_name ))
221
234
if not (len (neighbors ) == 2 ):
@@ -239,8 +252,8 @@ def series_pipe_merge(self, pipe_threshold):
239
252
(isinstance (pipe1 , Pipe )) and \
240
253
((pipe0 .diameter <= pipe_threshold ) and \
241
254
(pipe1 .diameter <= pipe_threshold )) and \
242
- pipe_name0 not in self .pipe_with_controls and \
243
- pipe_name1 not in self .pipe_with_controls ):
255
+ pipe_name0 not in self .pipe_to_exclude and \
256
+ pipe_name1 not in self .pipe_to_exclude ):
244
257
continue
245
258
# Find closest neighbor junction
246
259
if (isinstance (neigh_junc0 , Junction )) and \
@@ -305,7 +318,7 @@ def parallel_pipe_merge(self, pipe_threshold):
305
318
"""
306
319
307
320
for junc_name in self .wn .junction_name_list :
308
- if junc_name in self .junc_with_controls :
321
+ if junc_name in self .junc_to_exclude :
309
322
continue
310
323
neighbors = nx .neighbors (self .G ,junc_name )
311
324
for neighbor in [n for n in neighbors ]:
@@ -322,8 +335,8 @@ def parallel_pipe_merge(self, pipe_threshold):
322
335
(isinstance (pipe1 , Pipe )) and \
323
336
((pipe0 .diameter <= pipe_threshold ) and \
324
337
(pipe1 .diameter <= pipe_threshold )) and \
325
- pipe_name0 not in self .pipe_with_controls and \
326
- pipe_name1 not in self .pipe_with_controls ):
338
+ pipe_name0 not in self .pipe_to_exclude and \
339
+ pipe_name1 not in self .pipe_to_exclude ):
327
340
continue
328
341
329
342
logger .info ('Parallel pipe merge: ' + str (junc_name ) + str ((pipe_name0 , pipe_name1 )))
0 commit comments