Coverage for bim2sim/plugins/PluginAixLib/bim2sim_aixlib/models/__init__.py: 31%
222 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
1"""Package for Python representations of AixLib models"""
2from bim2sim.elements.aggregation import hvac_aggregations
3from bim2sim.export import modelica
4from bim2sim.elements import hvac_elements as hvac
5from bim2sim.elements.mapping.units import ureg
6from bim2sim.export.modelica import check_numeric
8MEDIUM_WATER = 'AixLib.Media.Water'
11class AixLib(modelica.ModelicaElement):
12 library = "AixLib"
15class Boiler(AixLib):
16 # TODO: The model BoilerGeneric does not exist in AixLib
17 path = "AixLib.Fluid.BoilerCHP.BoilerGeneric"
18 represents = [hvac.Boiler]
20 def __init__(self, element):
21 super().__init__(element)
22 self._set_parameter(name='redeclare package Medium',
23 unit=None,
24 required=False,
25 value=MEDIUM_WATER)
26 self._set_parameter(name='dTWaterNom',
27 unit=ureg.kelvin,
28 required=True,
29 attributes=['dT_water'],
30 check=check_numeric(min_value=0 * ureg.kelvin))
31 self._set_parameter(name='TRetNom',
32 unit=ureg.kelvin,
33 required=True,
34 attributes=['return_temperature'],
35 check=check_numeric(min_value=0 * ureg.kelvin))
36 self._set_parameter(name='QNom',
37 unit=ureg.watt,
38 required=True,
39 attributes=['rated_power'],
40 check=check_numeric(min_value=0 * ureg.watt))
41 self._set_parameter(name='PLRMin',
42 unit=ureg.dimensionless,
43 required=True,
44 attributes=['min_PLR'],
45 check=check_numeric(
46 min_value=0 * ureg.dimensionless))
48 def get_port_name(self, port):
49 if port.verbose_flow_direction == 'SINK':
50 return 'port_a'
51 if port.verbose_flow_direction == 'SOURCE':
52 return 'port_b'
53 else:
54 return super().get_port_name(port) # ToDo: Gas connection
57class Radiator(AixLib):
58 path = "AixLib.Fluid.HeatExchangers.Radiators.RadiatorEN442_2"
59 represents = [hvac.SpaceHeater]
61 def __init__(self, element):
62 super().__init__(element)
63 self._set_parameter(name='redeclare package Medium',
64 unit=None,
65 required=False,
66 value=MEDIUM_WATER)
67 self._set_parameter(name='Q_flow_nominal',
68 unit=ureg.watt,
69 required=True,
70 attributes=['rated_power'],
71 check=check_numeric(min_value=0 * ureg.watt))
72 self._set_parameter(name='T_a_nominal',
73 unit=ureg.celsius,
74 required=True,
75 check=check_numeric(min_value=0 * ureg.celsius),
76 attributes=['flow_temperature'])
77 self._set_parameter(name='T_b_nominal',
78 unit=ureg.celsius,
79 required=True,
80 check=check_numeric(min_value=0 * ureg.celsius),
81 attributes=['return_temperature'])
83 def get_port_name(self, port):
84 if port.verbose_flow_direction == 'SINK':
85 return 'port_a'
86 if port.verbose_flow_direction == 'SOURCE':
87 return 'port_b'
88 else:
89 return super().get_port_name(port)
92class Pump(AixLib):
93 path = "AixLib.Fluid.Movers.SpeedControlled_y"
94 represents = [hvac.Pump]
96 def __init__(self, element):
97 super().__init__(element)
98 self._set_parameter(name='redeclare package Medium',
99 unit=None,
100 required=False,
101 value=MEDIUM_WATER)
102 self._set_parameter(name='V_flow',
103 unit=ureg.m ** 3 / ureg.s,
104 required=True,
105 export=False,
106 function=lambda rated_volume_flow:
107 [0 * rated_volume_flow,
108 1 * rated_volume_flow,
109 2 * rated_volume_flow])
110 self._set_parameter(name='dp',
111 unit=ureg.pascal,
112 required=True,
113 export=False,
114 function=lambda rated_pressure_difference:
115 [2 * rated_pressure_difference,
116 1 * rated_pressure_difference,
117 0 * rated_pressure_difference])
118 self._set_parameter(name='per',
119 unit=None,
120 required=False,
121 value={'pressure': {
122 'V_flow': self.parameters['V_flow'],
123 'dp': self.parameters['dp']}})
125 def get_port_name(self, port):
126 if port.verbose_flow_direction == 'SINK':
127 return 'port_a'
128 if port.verbose_flow_direction == 'SOURCE':
129 return 'port_b'
130 else:
131 return super().get_port_name(port)
134class Consumer(AixLib):
135 path = "AixLib.Systems.HydraulicModules.SimpleConsumer"
136 represents = [hvac_aggregations.Consumer]
138 def __init__(self, element):
139 super().__init__(element)
140 self._set_parameter(name='redeclare package Medium_con',
141 unit=None,
142 required=False,
143 value=MEDIUM_WATER)
144 self._set_parameter(name='capacity',
145 unit=ureg.joule / ureg.kelvin,
146 required=False,
147 check=check_numeric(
148 min_value=0 * ureg.joule / ureg.kelvin),
149 attributes=['heat_capacity'])
150 self._set_parameter(name='V',
151 unit=ureg.meter ** 3,
152 required=False,
153 check=check_numeric(min_value=0 * ureg.meter ** 3),
154 attributes=['volume'])
155 self._set_parameter(name='Q_flow_fixed',
156 unit=ureg.watt,
157 required=False,
158 check=check_numeric(min_value=0 * ureg.watt),
159 attributes=['rated_power'])
160 self._set_parameter(name='V_flow_nominal',
161 unit=ureg.meter ** 3 / ureg.s,
162 required=True,
163 export=False,
164 check=check_numeric(
165 min_value=0 * ureg.meter ** 3 / ureg.s),
166 attributes=['rated_volume_flow'])
167 self._set_parameter(name='m_flow_nominal',
168 unit=ureg.kg / ureg.s,
169 required=False,
170 function=lambda:
171 (self.parameters['V_flow_nominal'].value * 998
172 * ureg.kg / ureg.meter ** 3))
174 def get_port_name(self, port):
175 if port.verbose_flow_direction == 'SINK':
176 return 'port_a'
177 if port.verbose_flow_direction == 'SOURCE':
178 return 'port_b'
179 else:
180 return super().get_port_name(port)
183class ConsumerHeatingDistributorModule(AixLib):
184 # TODO: the model does not exists in AiLib
185 path = ("AixLib.Systems.ModularEnergySystems.Modules.ModularConsumer."
186 "ConsumerDistributorModule")
187 represents = [hvac_aggregations.ConsumerHeatingDistributorModule]
189 def __init__(self,
190 element: hvac_aggregations.ConsumerHeatingDistributorModule):
191 super().__init__(element)
192 n_consumers = len(element.whitelist_elements)
193 self._set_parameter(name='redeclare package Medium_con',
194 unit=None,
195 required=False,
196 value=MEDIUM_WATER)
197 self._set_parameter(name='T_start',
198 unit=ureg.kelvin,
199 required=False,
200 check=check_numeric(min_value=0 * ureg.kelvin),
201 attributes=['return_temperature'])
202 self._set_parameter(name='n_consumers',
203 unit=ureg.dimensionless,
204 required=False,
205 value=n_consumers)
206 self._set_parameter(name='functionality',
207 unit=None,
208 required=False,
209 value='Q_flow_fixed')
210 self._set_parameter(name='demandType',
211 unit=None,
212 required=False,
213 attributes=['demand_type'])
214 self._set_parameter(name='capacity',
215 unit=ureg.joule / ureg.kelvin,
216 required=False,
217 check=check_numeric(
218 min_value=0 * ureg.joule / ureg.kelvin),
219 attributes=['heat_capacity'])
220 self._set_parameter(name='Q_flow_nom',
221 unit=ureg.watt,
222 required=False,
223 check=check_numeric(min_value=0 * ureg.watt),
224 attributes=['rated_power'])
225 self._set_parameter(name='dT_nom',
226 unit=ureg.kelvin,
227 required=False,
228 check=check_numeric(min_value=0 * ureg.kelvin),
229 attributes=['dT_water'])
230 self._set_parameter(name='hasFeedback',
231 unit=None,
232 required=False,
233 attributes=['t_control'])
234 self._set_parameter(name='TInSetSou',
235 unit=None,
236 required=False,
237 value=("AixLib.Systems.ModularEnergySystems."
238 "Modules.ModularConsumer.Types."
239 "InputTypeConstant"))
240 self._set_parameter(name='TInSet',
241 unit=ureg.kelvin,
242 required=False,
243 check=check_numeric(min_value=0 * ureg.kelvin),
244 attributes=['flow_temperature'])
245 self._set_parameter(name='k_ControlConsumerValve',
246 unit=None,
247 required=False,
248 value=0.1 * n_consumers)
249 self._set_parameter(name='Ti_ControlConsumerValve',
250 unit=None,
251 required=False,
252 value=10 * n_consumers)
253 self._set_parameter(name='dp_Valve',
254 unit=ureg.pascal,
255 required=False,
256 value=1000 * n_consumers)
257 self._set_parameter(name='hasPump',
258 unit=None,
259 required=False,
260 attributes=['has_pump'])
261 self._set_parameter(name='TOutSet',
262 unit=ureg.kelvin,
263 required=False,
264 check=check_numeric(min_value=0 * ureg.kelvin),
265 attributes=['return_temperature'])
266 self._set_parameter(name='TOutSetSou',
267 unit=None,
268 required=False,
269 value=("AixLib.Systems.ModularEnergySystems."
270 "Modules.ModularConsumer.Types.InputType."
271 "Constant"))
272 self._set_parameter(name='k_ControlConsumerPump',
273 unit=None,
274 required=False,
275 value=0.1 * n_consumers)
276 self._set_parameter(name='Ti_ControlConsumerPump',
277 unit=None,
278 required=False,
279 value=10 * n_consumers)
280 self._set_parameter(name='dp_nominalConPump',
281 unit=ureg.pascal,
282 required=False,
283 value=10000 * n_consumers)
285 def get_port_name(self, port):
286 if port.verbose_flow_direction == 'SINK':
287 return 'port_a'
288 if port.verbose_flow_direction == 'SOURCE':
289 return 'port_b'
290 else:
291 return super().get_port_name(port)
294class BoilerAggregation(AixLib):
295 # TODO: the model does not exists in AiLib
296 """Modelica AixLib representation of the GeneratorOneFluid aggregation."""
297 path = "AixLib.Systems.ModularEnergySystems.Modules.ModularBoiler." \
298 "ModularBoiler"
299 represents = [hvac_aggregations.GeneratorOneFluid]
301 def __init__(self, element):
302 super().__init__(element)
303 self._set_parameter(name='redeclare package Medium',
304 unit=None,
305 required=False,
306 value=MEDIUM_WATER)
307 self._set_parameter(name='hasPump',
308 unit=None,
309 required=False,
310 attributes=['has_pump'])
311 self._set_parameter(name='hasFeedback',
312 unit=None,
313 required=False,
314 attributes=['has_bypass'])
315 self._set_parameter(name='QNom',
316 unit=ureg.watt,
317 required=False,
318 check=check_numeric(min_value=0 * ureg.watt),
319 attributes=['rated_power'])
320 self._set_parameter(name='PLRMin',
321 unit=ureg.dimensionless,
322 required=False,
323 check=check_numeric(
324 min_value=0 * ureg.dimensionless),
325 attributes=['min_PLR'])
326 self._set_parameter(name='TRetNom',
327 unit=ureg.kelvin,
328 required=False,
329 check=check_numeric(
330 min_value=0 * ureg.kelvin),
331 attributes=['return_temperature'])
332 self._set_parameter(name='dTWaterNom',
333 unit=ureg.kelvin,
334 required=False,
335 check=check_numeric(min_value=0 * ureg.kelvin),
336 attributes=['dT_water'])
337 self._set_parameter(name='dp_Valve',
338 unit=ureg.pascal,
339 required=False,
340 value=10000)
342 def get_port_name(self, port):
343 if port.verbose_flow_direction == 'SINK':
344 return 'port_a'
345 if port.verbose_flow_direction == 'SOURCE':
346 return 'port_b'
347 else:
348 return super().get_port_name(port)
351class Distributor(AixLib):
352 path = "AixLib.Fluid.HeatExchangers.ActiveWalls.Distributor"
353 represents = [hvac.Distributor]
355 def __init__(self, element: hvac.Distributor):
356 super().__init__(element)
357 n_ports = self.get_n_ports()
358 self._set_parameter(name='redeclare package Medium',
359 unit=None,
360 required=False,
361 value=MEDIUM_WATER)
362 self._set_parameter(name='n',
363 unit=None,
364 required=False,
365 value=n_ports)
366 self._set_parameter(name='m_flow_nominal',
367 unit=ureg.kg / ureg.s,
368 required=False,
369 check=check_numeric(min_value=0 * ureg.kg / ureg.s),
370 attributes=['rated_mass_flow'])
372 def get_n_ports(self):
373 ports = {port.guid: port for port in self.element.ports if
374 port.connection}
375 return len(ports) / 2 - 1
377 def get_port_name(self, port):
378 try:
379 index = self.element.ports.index(port)
380 except ValueError:
381 # unknown port
382 index = -1
383 if (index % 2) == 0:
384 return "port_a_consumer"
385 elif (index % 2) == 1:
386 return "port_b_consumer"
387 else:
388 return super().get_port_name(port)
390 @staticmethod
391 def get_new_port_name(distributor, other_inst, distributor_port,
392 other_port, distributors_n, distributors_ports):
393 if distributor not in distributors_n:
394 distributors_n[distributor] = 0
395 distributors_ports[distributor] = {}
396 distributors_n[distributor] += 1
397 if type(other_inst.element) is hvac_aggregations.GeneratorOneFluid:
398 list_name = distributor_port.split('.')[:-1] + \
399 ['mainReturn' if 'port_a' in other_port
400 else 'mainFlow']
401 else:
402 port_key = other_port.split('.')[-1]
403 if port_key not in distributors_ports[distributor]:
404 distributors_ports[distributor][port_key] = 0
405 distributors_ports[distributor][port_key] += 1
406 n = distributors_ports[distributor][port_key]
407 list_name = distributor_port.split('.')[:-1] + \
408 ['flowPorts[%d]' % n if 'port_a' in other_port
409 else 'returnPorts[%d]' % n]
410 return '.'.join(list_name)
413class ThreeWayValve(AixLib):
414 path = "AixLib.Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear"
415 represents = [hvac.ThreeWayValve]
417 def __init__(self, element):
418 super().__init__(element)
419 self._set_parameter(name='redeclare package Medium_con',
420 unit=None,
421 required=False,
422 value=MEDIUM_WATER)
423 self._set_parameter(name='m_flow_nominal',
424 unit=ureg.kg / ureg.s,
425 required=True,
426 check=check_numeric(
427 min_value=0 * ureg.kg / ureg.s),
428 attributes=['nominal_mass_flow_rate'])
429 self._set_parameter(name='dpValve_nominal',
430 unit=ureg.pascal,
431 required=True,
432 check=check_numeric(min_value=0 * ureg.pascal),
433 attributes=['nominal_pressure_difference'])
435 def get_port_name(self, port):
436 try:
437 index = self.element.ports.index(port)
438 except ValueError:
439 # unknown port
440 index = -1
441 if index == 0:
442 return "port_1"
443 elif index == 1:
444 return "port_2"
445 elif index == 2:
446 return "port_3"
447 else:
448 return super().get_port_name(port)
451class Heatpump(AixLib):
452 path = "AixLib.Fluid.HeatPumps.HeatPump"
453 represents = [hvac.HeatPump]
455 def __init__(self, element):
456 super().__init__(element)
457 self._set_parameter(name='redeclare package Medium_con',
458 unit=None,
459 required=False,
460 value=MEDIUM_WATER)
461 self._set_parameter(name='redeclare Medium_eva Medium_con',
462 unit=None,
463 required=False,
464 value=MEDIUM_WATER)
465 self._set_parameter(name='Q_useNominal',
466 unit=ureg.watt,
467 required=False,
468 check=check_numeric(min_value=0 * ureg.watt),
469 attributes=['rated_power'])
471 def get_port_name(self, port):
472 # TODO: heat pumps might have 4 ports (if source is modeled in BIM)
473 if port.verbose_flow_direction == 'SINK':
474 return 'port_a'
475 if port.verbose_flow_direction == 'SOURCE':
476 return 'port_b'
477 else:
478 return super().get_port_name(port)
481class Chiller(AixLib):
482 path = "AixLib.Fluid.Chillers.Chiller"
483 represents = [hvac.Chiller]
485 def __init__(self, element):
486 super().__init__(element)
487 self._set_parameter(name='redeclare package Medium_con',
488 unit=None,
489 required=False,
490 value=MEDIUM_WATER)
491 self._set_parameter(name='redeclare Medium_eva Medium_con',
492 unit=None,
493 required=False,
494 value=MEDIUM_WATER)
495 self._set_parameter(name='Q_useNominal',
496 unit=ureg.watt,
497 required=False,
498 check=check_numeric(min_value=0 * ureg.watt),
499 attributes=['rated_power'])
501 def get_port_name(self, port):
502 # TODO heat pumps might have 4 ports (if source is modeld in BIM)
503 if port.verbose_flow_direction == 'SINK':
504 return 'port_a'
505 if port.verbose_flow_direction == 'SOURCE':
506 return 'port_b'
507 else:
508 return super().get_port_name(port)
511class CHP(AixLib):
512 path = "AixLib.Fluid.BoilerCHP.CHPNoControl"
513 represents = [hvac.CHP]
515 def __init__(self, element):
516 super().__init__(element)
517 self._set_parameter(name='redeclare package Medium',
518 unit=None,
519 required=False,
520 value=MEDIUM_WATER)
523class Storage(AixLib):
524 path = "AixLib.Fluid.Storage.BufferStorage"
525 represents = [hvac.Storage]
527 def __init__(self, element):
528 super().__init__(element)
529 self._set_parameter(name='redeclare package Medium',
530 unit=None,
531 required=False,
532 value=MEDIUM_WATER)
533 self._set_parameter(name='hTank',
534 unit=ureg.meter,
535 required=True,
536 export=False,
537 check=check_numeric(min_value=0 * ureg.meter),
538 attributes=['height'])
539 self._set_parameter(name='dTank',
540 unit=ureg.meter,
541 required=True,
542 export=False,
543 check=check_numeric(min_value=0 * ureg.meter),
544 attributes=['diameter'])
545 self._set_parameter(name='data',
546 unit=None,
547 required=False,
548 value={'hTank': self.parameters['hTank'],
549 "dTank": self.parameters['dTank']})