Coverage for test/unit/elements/aggregation/test_pipestrand.py: 91%
217 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-03-12 17:09 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-03-12 17:09 +0000
1import unittest
3import bim2sim.elements.aggregation.hvac_aggregations
4from bim2sim.elements import aggregation
5from bim2sim.elements import hvac_elements as hvac
6from bim2sim.elements.graphs.hvac_graph import HvacGraph
7from bim2sim.elements.mapping.units import ureg
8from test.unit.elements.helper import SetupHelperHVAC
11class StrandHelper(SetupHelperHVAC):
13 def get_setup_strand1(self):
14 """simple strait strand"""
15 flags = {}
16 with self.flag_manager(flags):
17 # generator circuit
18 strand = [self.element_generator(
19 hvac.Pipe, length=100, diameter=30) for i in range(10)]
21 # connect
22 self.connect_strait(strand)
24 # full system
25 gen_circuit = [
26 *strand
27 ]
29 flags['connect'] = [strand[0], strand[-1]]
31 graph = HvacGraph(gen_circuit)
32 flags['edge_ports'] = [v for v, d in graph.degree() if d == 1]
34 return graph, flags
36 def get_setup_strand2(self):
37 """simple strait strand with various diameters"""
38 flags = {}
39 with self.flag_manager(flags):
40 # generator circuit
41 strand1 = [self.element_generator(
42 hvac.Pipe, length=100, diameter=30) for i in range(2)]
43 strand2 = [self.element_generator(
44 hvac.Pipe, length=200, diameter=50) for i in range(2)]
45 strand3 = [self.element_generator(
46 hvac.Pipe, length=100, diameter=30) for i in range(2)]
47 strand4 = [self.element_generator(
48 hvac.Pipe, length=50, diameter=15) for i in range(2)]
50 strand = [*strand1, *strand2, *strand3, *strand4]
51 # connect
52 self.connect_strait(strand)
54 # full system
55 gen_circuit = [
56 *strand
57 ]
59 flags['connect'] = [strand[0], strand[-1]]
61 graph = HvacGraph(gen_circuit)
62 return graph, flags
64 def get_setup_strait_with_valve(self):
65 """simple strait strand with valve"""
66 flags = {}
67 with self.flag_manager(flags):
68 # generator circuit
69 strand1 = [self.element_generator(
70 hvac.Pipe, flags=['pipes'], length=100, diameter=30) for i in range(3)]
71 strand2 = [self.element_generator(
72 hvac.Pipe, flags=['pipes'], length=100, diameter=30) for i in range(3)]
73 valve = self.element_generator(hvac.Valve, flags=['valve'], diameter=30)
75 strand = [*strand1, valve, *strand2]
76 # connect
77 self.connect_strait(strand)
79 # full system
80 gen_circuit = [
81 *strand
82 ]
84 flags['connect'] = [strand[0], strand[-1]]
86 graph = HvacGraph(gen_circuit)
87 return graph, flags
89 def get_setup_straits_with_distributor(self):
90 """distributor wit two connected straits"""
91 flags = {}
92 with self.flag_manager(flags):
93 # generator circuit
94 strand1 = [self.element_generator(
95 hvac.Pipe, length=100, diameter=30) for i in range(2)]
96 strand2 = [self.element_generator(
97 hvac.Pipe, length=200, diameter=50) for i in range(2)]
98 distributor = self.element_generator(hvac.Distributor, flags=['distributor'])
100 # connect
101 self.connect_strait([*strand1, distributor, *strand2])
103 # full system
104 gen_circuit = [
105 *strand1,
106 distributor,
107 *strand2
108 ]
110 graph = HvacGraph(gen_circuit)
111 return graph, flags
113 def get_setup_cross(self):
114 """two crossing strands"""
115 flags = {}
116 with self.flag_manager(flags):
117 # generator circuit
118 strand1 = [self.element_generator(
119 hvac.Pipe, flags=['strand1'], length=100, diameter=30) for i in range(4)]
120 strand2 = [self.element_generator(
121 hvac.Pipe, flags=['strand2'], length=100, diameter=30) for i in range(4)]
122 strand3 = [self.element_generator(
123 hvac.Pipe, flags=['strand3'], length=100, diameter=30) for i in range(4)]
124 strand4 = [self.element_generator(
125 hvac.Pipe, flags=['strand4'], length=100, diameter=30) for i in range(4)]
126 cross = self.element_generator(hvac.PipeFitting, n_ports=4, flags='cross')
128 # connect
129 self.connect_strait(strand1)
130 self.connect_strait(strand2)
131 self.connect_strait(strand3)
132 self.connect_strait(strand4)
134 cross.ports[0].connect(strand1[0].ports[0])
135 cross.ports[1].connect(strand2[0].ports[0])
136 cross.ports[2].connect(strand3[0].ports[0])
137 cross.ports[3].connect(strand4[0].ports[0])
139 # full system
140 gen_circuit = [
141 *strand1,
142 *strand2,
143 *strand3,
144 *strand4,
145 cross
146 ]
148 graph = HvacGraph(gen_circuit)
149 return graph, flags
151 def get_setup_system(self):
152 """System (Kessel - Pumpe - Heizung - Absperrventil - T-Stück - Druckausgleichgefäß)"""
153 flags = {}
154 with self.flag_manager(flags):
155 # generator circuit
156 boiler = self.element_generator(hvac.Boiler, rated_power=200)
157 strand1 = [self.element_generator(hvac.Pipe, flags=['strand1'], length=100, diameter=40) for i in range(3)]
158 h_pump = self.element_generator(hvac.Pump, rated_power=2.2, rated_height=12, rated_volume_flow=8)
159 strand2 = [self.element_generator(hvac.Pipe, flags=['strand2'], length=100, diameter=40) for i in range(5)]
160 spaceheater = self.element_generator(hvac.SpaceHeater, flags=['spaceheater']) # , volume=80
161 strand3a = [self.element_generator(hvac.Pipe, flags=['strand3'], length=100, diameter=40) for i in range(4)]
162 valve = self.element_generator(hvac.Valve, flags=['valve'])
163 strand3b = [self.element_generator(hvac.Pipe, flags=['strand3'], length=100, diameter=40) for i in range(4)]
164 fitting = self.element_generator(hvac.PipeFitting, n_ports=3, diameter=40, length=60)
165 strand4 = [self.element_generator(hvac.Pipe, flags=['strand4'], length=100, diameter=40) for i in range(4)]
166 strand5 = [
167 self.element_generator(hvac.Pipe, flags=['strand5'], length=100, diameter=40) for i in range(4)]
168 tank = self.element_generator(hvac.Storage, n_ports=1)
170 # connect
171 circuit = [
172 boiler, *strand1, h_pump, *strand2, spaceheater,
173 *strand3a, valve, *strand3b, fitting, *strand4, boiler
174 ]
175 self.connect_strait(circuit)
176 self.connect_strait([*strand5, tank])
177 fitting.ports[2].connect(strand5[0].ports[0])
179 # full system
180 gen_circuit = [
181 *circuit, *strand5, tank
182 ]
184 graph = HvacGraph(gen_circuit)
185 return graph, flags
187 def get_setup_loop(self):
188 """Circular strand with diagonal connected strand"""
189 flags = {}
190 with self.flag_manager(flags):
191 # generator circuit
192 strand1 = [self.element_generator(
193 hvac.Pipe, flags=['strand1'], length=100, diameter=30) for i in range(6)]
194 strand2 = [self.element_generator(
195 hvac.Pipe, flags=['strand2'], length=100, diameter=30) for i in range(6)]
196 strand3 = [self.element_generator(
197 hvac.Pipe, flags=['strand3'], length=100, diameter=30) for i in range(4)]
198 cross1 = self.element_generator(hvac.PipeFitting, n_ports=3, flags='cross')
199 cross2 = self.element_generator(hvac.PipeFitting, n_ports=3, flags='cross')
201 # connect
202 self.connect_strait([cross1, *strand1, cross2])
203 self.connect_strait([cross2, *strand2, cross1])
204 self.connect_strait(strand3)
205 cross1.ports[2].connect(strand3[0].ports[0])
206 cross2.ports[2].connect(strand3[-1].ports[1])
208 # full system
209 gen_circuit = [
210 *strand1,
211 *strand2,
212 *strand3,
213 cross1,
214 cross2
215 ]
217 graph = HvacGraph(gen_circuit)
218 return graph, flags
221class TestPipeStrand(unittest.TestCase):
223 helper = None
225 @classmethod
226 def setUpClass(cls):
227 cls.helper = StrandHelper()
229 def tearDown(self) -> None:
230 self.helper.reset()
232 def test_strait_strand(self):
233 """Test calculation of aggregated length"""
234 graph, flags = self.helper.get_setup_strand1()
235 ele = graph.elements
237 matches, meta = bim2sim.elements.aggregation.hvac_aggregations.PipeStrand.find_matches(graph)
238 self.assertEqual(1, len(matches))
239 agg = bim2sim.elements.aggregation.hvac_aggregations.PipeStrand(graph, matches[0], **meta[0])
241 exp_length = sum([e.length for e in ele])
242 self.assertAlmostEqual(exp_length, agg.length)
244 self.assertAlmostEqual(30 * ureg.millimeter, agg.diameter)
246 def test_strait_strand_variable(self):
247 """Test calculation of aggregated length and diameter"""
248 graph, flags = self.helper.get_setup_strand2()
249 ele = graph.elements
251 matches, meta = bim2sim.elements.aggregation.hvac_aggregations.PipeStrand.find_matches(graph)
252 self.assertEqual(1, len(matches))
253 agg = bim2sim.elements.aggregation.hvac_aggregations.PipeStrand(graph, matches[0], **meta[0])
255 exp_length = sum([e.length for e in ele])
256 self.assertAlmostEqual(exp_length, agg.length)
258 exp_diameter = sum([e.length * e.diameter for e in ele]) / exp_length
259 self.assertAlmostEqual(exp_diameter, agg.diameter)
261 def test_distributor_with_strands(self):
262 """ Test calculation of aggregated length and diameter."""
263 graph, flags = self.helper.get_setup_straits_with_distributor()
265 matches, meta = bim2sim.elements.aggregation.hvac_aggregations.PipeStrand.find_matches(graph)
266 self.assertEqual(2, len(matches))
268 with self.assertRaises(AssertionError,
269 msg="Pipestrand aggregation over a distributor"
270 " should fail"):
271 # pass full graph
272 agg = bim2sim.elements.aggregation.hvac_aggregations.PipeStrand(graph, graph, **{})
274 @unittest.skip(
275 "PipeStrand aggregation with inert elements not implemented")
276 def test_strait_strand_valve(self):
277 """ Test calculation of aggregated length and diameter."""
278 graph, flags = self.helper.get_setup_strait_with_valve()
280 matches, meta = bim2sim.elements.aggregation.hvac_aggregations.PipeStrand.find_matches(graph)
281 self.assertEqual(1, len(matches))
282 agg = bim2sim.elements.aggregation.hvac_aggregations.PipeStrand(graph, matches[0], **meta[0])
284 exp_length = sum([e.length for e in flags['pipes']])
285 self.assertAlmostEqual(exp_length, agg.length)
287 self.assertAlmostEqual(30 * ureg.millimeter, agg.diameter)
289 def test_filter_strand(self):
290 """Test filter for strait strand"""
291 graph, flags = self.helper.get_setup_strand1()
292 ele = graph.elements
294 matches, meta = bim2sim.elements.aggregation.hvac_aggregations.PipeStrand.find_matches(graph)
295 self.assertEqual(1, len(matches))
297 self.assertSetEqual(set(ele), set(matches[0].elements))
299 def test_filter_cross(self):
300 """Test filter for crossing strands"""
301 graph, flags = self.helper.get_setup_cross()
302 ele = (flags['strand1'] + flags['strand2'] + flags['strand3']
303 + flags['strand4'])
305 matches, meta = bim2sim.elements.aggregation.hvac_aggregations.PipeStrand.find_matches(graph)
306 self.assertEqual(4, len(matches))
308 self.assertSetEqual(set(ele),
309 set(sum(
310 [list(match.elements) for match in matches],
311 [])))
313 def test_filter_system(self):
314 """Test filter for crossing strands"""
315 graph, flags = self.helper.get_setup_system()
316 ele = (flags['strand1'] + flags['strand2'] + flags['strand3']
317 + flags['strand4'] + flags['strand5'] + flags['valve'])
319 matches, meta = bim2sim.elements.aggregation.hvac_aggregations.PipeStrand.find_matches(graph)
320 self.assertEqual(5, len(matches))
322 self.assertSetEqual(set(ele),
323 set(sum(
324 [list(match.elements) for match in matches],
325 [])))
327 def test_filter_circular(self):
328 """Test filter for crossing strands"""
329 graph, flags = self.helper.get_setup_loop()
330 ele = flags['strand1'] + flags['strand2'] + flags['strand3']
332 matches, meta = bim2sim.elements.aggregation.hvac_aggregations.PipeStrand.find_matches(graph)
333 self.assertEqual(len(matches), 3)
335 self.assertSetEqual(set(ele),
336 set(sum(
337 [list(match.elements) for match in matches],
338 [])))
340 def test_pipestrand1(self):
341 """Test calculation of aggregated length and diameter"""
342 graph, flags = self.helper.get_setup_simple_boiler()
343 elements = flags['strand1']
344 match_graph = graph.subgraph_from_elements(elements)
346 matches, meta = bim2sim.elements.aggregation.hvac_aggregations.PipeStrand.find_matches(match_graph)
347 self.assertEqual(1, len(matches))
348 agg = bim2sim.elements.aggregation.hvac_aggregations.PipeStrand(graph, matches[0], **meta[0])
350 exp_length = sum([e.length for e in elements])
351 self.assertAlmostEqual(agg.length, exp_length)
353 self.assertAlmostEqual(40 * ureg.millimeter, agg.diameter)
355 def test_pipestrand2(self):
356 """Test calculation of aggregated length and diameter"""
358 graph, flags = self.helper.get_setup_simple_boiler()
359 elements = flags['strand2']
360 match_graph = graph.subgraph_from_elements(elements)
362 matches, metas = bim2sim.elements.aggregation.hvac_aggregations.PipeStrand.find_matches(match_graph)
363 self.assertEqual(1, len(matches))
364 aggregations = []
365 for match, meta in zip(matches, metas):
366 agg = bim2sim.elements.aggregation.hvac_aggregations.PipeStrand(graph, match, **meta)
367 aggregations.append(agg)
368 graph.merge(
369 mapping=agg.get_replacement_mapping(),
370 inner_connections=agg.inner_connections)
371 exp_length = sum([e.length for e in elements])
372 self.assertAlmostEqual(exp_length, agg.length)
374 self.assertAlmostEqual(15 * ureg.millimeter, agg.diameter)
376 def test_basics(self):
377 graph, flags = self.helper.get_setup_simple_boiler()
378 elements = flags['strand1']
379 # match_graph = graph.element_graph.subgraph(elements)
380 # match_graph = graph.subgraph(
381 # (port for ele in elements for port in ele.ports))
382 match = graph.subgraph_from_elements(elements)
384 agg = bim2sim.elements.aggregation.hvac_aggregations.PipeStrand(graph, match)
386 self.assertTrue(self.helper.elements_in_agg(agg))
388 def test_detection(self):
389 graph, flags = self.helper.get_setup_simple_boiler()
391 matches, meta = bim2sim.elements.aggregation.hvac_aggregations.PipeStrand.find_matches(graph)
393 self.assertEqual(
394 len(matches), 5,
395 "There are 5 cases for PipeStrand but 'find_matches' returned %d"
396 % len(matches))
398 def test_get_edge_ports_pipe_strand(self):
399 """ Test the get_edge_ports method for a pipe strand."""
400 graph, flags = self.helper.get_setup_strand1()
402 matches, metas = bim2sim.elements.aggregation.hvac_aggregations.PipeStrand.find_matches(graph)
403 agg = bim2sim.elements.aggregation.hvac_aggregations.PipeStrand(graph, matches[0], metas[0])
404 edge_ports = [edge_port.originals[0] for edge_port in agg.get_ports()]
405 self.assertEqual(set(flags['edge_ports']), set(edge_ports))
408if __name__ == '__main__':
409 unittest.main()