OpenSimula 0.5.1__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.
Files changed (44) hide show
  1. opensimula/Child.py +19 -0
  2. opensimula/Component.py +214 -0
  3. opensimula/Iterative_process.py +47 -0
  4. opensimula/Message.py +19 -0
  5. opensimula/Parameter_container.py +80 -0
  6. opensimula/Parameters.py +755 -0
  7. opensimula/Project.py +674 -0
  8. opensimula/Simulation.py +212 -0
  9. opensimula/Variable.py +37 -0
  10. opensimula/__init__.py +8 -0
  11. opensimula/components/Building.py +511 -0
  12. opensimula/components/Building_surface.py +318 -0
  13. opensimula/components/Calculator.py +51 -0
  14. opensimula/components/Construction.py +309 -0
  15. opensimula/components/Day_schedule.py +64 -0
  16. opensimula/components/File_data.py +117 -0
  17. opensimula/components/File_met.py +1035 -0
  18. opensimula/components/Frame.py +35 -0
  19. opensimula/components/Glazing.py +122 -0
  20. opensimula/components/HVAC_DX_equipment.py +210 -0
  21. opensimula/components/HVAC_DX_system.py +254 -0
  22. opensimula/components/HVAC_MZW_system.py +554 -0
  23. opensimula/components/HVAC_SZW_system.py +338 -0
  24. opensimula/components/HVAC_coil_equipment.py +206 -0
  25. opensimula/components/HVAC_fan_equipment.py +44 -0
  26. opensimula/components/HVAC_perfect_system.py +137 -0
  27. opensimula/components/Material.py +14 -0
  28. opensimula/components/Opening.py +409 -0
  29. opensimula/components/Opening_type.py +90 -0
  30. opensimula/components/Solar_surface.py +114 -0
  31. opensimula/components/Space.py +388 -0
  32. opensimula/components/Space_type.py +81 -0
  33. opensimula/components/Surface.py +129 -0
  34. opensimula/components/Test_component.py +76 -0
  35. opensimula/components/Week_schedule.py +30 -0
  36. opensimula/components/Year_schedule.py +65 -0
  37. opensimula/components/__init__.py +40 -0
  38. opensimula/visual_3D/Environment_3D.py +257 -0
  39. opensimula/visual_3D/Polygon_3D.py +262 -0
  40. opensimula-0.5.1.dist-info/METADATA +49 -0
  41. opensimula-0.5.1.dist-info/RECORD +44 -0
  42. opensimula-0.5.1.dist-info/WHEEL +5 -0
  43. opensimula-0.5.1.dist-info/licenses/LICENSE +21 -0
  44. opensimula-0.5.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,554 @@
1
+ from opensimula.Message import Message
2
+ from opensimula.Parameters import (
3
+ Parameter_component,
4
+ Parameter_component_list,
5
+ Parameter_float,
6
+ Parameter_float_list,
7
+ Parameter_variable_list,
8
+ Parameter_math_exp,
9
+ Parameter_math_exp_list,
10
+ Parameter_options
11
+ )
12
+ from opensimula.Component import Component
13
+ from opensimula.Variable import Variable
14
+ import psychrolib as sicro
15
+
16
+
17
+ class HVAC_MZW_system(Component): # HVAC Multizone Water system
18
+ def __init__(self, name, project):
19
+ Component.__init__(self, name, project)
20
+ self.parameter("type").value = "HVAC_MZW_system"
21
+ self.parameter("description").value = "HVAC Multizone Water system"
22
+ self.add_parameter(
23
+ Parameter_component_list(
24
+ "spaces", ["not_defined", "not_defined"], ["Space"]
25
+ )
26
+ )
27
+ self.add_parameter(
28
+ Parameter_float_list(
29
+ "air_flow_fractions", [0.5, 0.5], min=0, max=1, unit="frac"
30
+ )
31
+ )
32
+ self.add_parameter(
33
+ Parameter_component("cooling_coil", "not_defined", ["HVAC_coil_equipment"])
34
+ )
35
+ self.add_parameter(
36
+ Parameter_component("heating_coil", "not_defined", ["HVAC_coil_equipment"])
37
+ )
38
+ self.add_parameter(
39
+ Parameter_component("supply_fan", "not_defined", ["HVAC_fan_equipment"])
40
+ )
41
+ self.add_parameter(
42
+ Parameter_component("return_fan", "not_defined", ["HVAC_fan_equipment"])
43
+ )
44
+ self.add_parameter(Parameter_float("air_flow", 1, "m³/s", min=0))
45
+ self.add_parameter(
46
+ Parameter_float("return_air_flow", 1, "m³/s", min=0)
47
+ ) # Not used when return fan is not defined
48
+ self.add_parameter(
49
+ Parameter_float_list(
50
+ "return_air_flow_fractions", [0.5, 0.5], min=0, max=1, unit="frac"
51
+ )
52
+ )
53
+ self.add_parameter(Parameter_math_exp("outdoor_air_fraction", "0", "frac"))
54
+ self.add_parameter(Parameter_variable_list("input_variables", []))
55
+ self.add_parameter(Parameter_math_exp("supply_heating_setpoint", "10", "°C"))
56
+ self.add_parameter(Parameter_math_exp("supply_cooling_setpoint", "15", "°C"))
57
+ self.add_parameter(Parameter_math_exp_list("spaces_setpoint", ["20","20"], "°C"))
58
+ self.add_parameter(Parameter_math_exp("system_on_off", "1", "on/off"))
59
+ self.add_parameter(
60
+ Parameter_options("fan_operation", "CONTINUOUS", ["CONTINUOUS", "CYCLING"])
61
+ )
62
+ self.add_parameter(
63
+ Parameter_options("water_source", "UNKNOWN", ["UNKNOWN", "WATER_LOOP"])
64
+ )
65
+ self.add_parameter(Parameter_float("cooling_water_flow", 1, "m³/s", min=0))
66
+ self.add_parameter(Parameter_float("heating_water_flow", 1, "m³/s", min=0))
67
+ self.add_parameter(Parameter_float("inlet_cooling_water_temp", 7, "ºC"))
68
+ self.add_parameter(Parameter_float("inlet_heating_water_temp", 50, "ºC"))
69
+ self.add_parameter(
70
+ Parameter_options(
71
+ "water_flow_control", "ON_OFF", ["ON_OFF", "PROPORTIONAL"]
72
+ )
73
+ )
74
+ self.add_parameter(
75
+ Parameter_options(
76
+ "economizer",
77
+ "NO",
78
+ [
79
+ "NO",
80
+ "TEMPERATURE",
81
+ "TEMPERATURE_NOT_INTEGRATED",
82
+ "ENTHALPY",
83
+ "ENTHALPY_LIMITED",
84
+ ],
85
+ )
86
+ )
87
+ self.add_parameter(Parameter_float("economizer_DT", 0, "ºC", min=0))
88
+ self.add_parameter(
89
+ Parameter_float("economizer_enthalpy_limit", 0, "kJ/kg", min=0)
90
+ )
91
+ self.add_parameter(
92
+ Parameter_options("terminal_units", "NO", ["NO", "REHEAT_COILS", "VAV_DAMPERS"])
93
+ )
94
+ self.add_parameter(
95
+ Parameter_component_list(
96
+ "reheat_coils", ["not_defined", "not_defined"], ["HVAC_coil_equipment"]
97
+ )
98
+ )
99
+
100
+ # Variables
101
+ self.add_variable(
102
+ Variable("state", unit="flag")
103
+ ) # 0: 0ff, 1: Heating, 2: Heating max cap, -1:Cooling, -2:Cooling max cap, 3: Venting
104
+ self.add_variable(Variable("T_OA", unit="°C"))
105
+ self.add_variable(Variable("T_OAwb", unit="°C"))
106
+ self.add_variable(Variable("T_MA", unit="°C"))
107
+ self.add_variable(Variable("T_MAwb", unit="°C"))
108
+ self.add_variable(Variable("F_load", unit="frac"))
109
+ self.add_variable(Variable("outdoor_air_fraction", unit="frac"))
110
+ self.add_variable(Variable("m_air_flow", unit="kg/s"))
111
+ self.add_variable(Variable("T_SA", unit="°C"))
112
+ self.add_variable(Variable("w_SA", unit="g/kg"))
113
+ self.add_variable(Variable("T_CA", unit="°C"))
114
+ self.add_variable(Variable("w_CA", unit="g/kg"))
115
+ self.add_variable(Variable("Q_sensible", unit="W"))
116
+ self.add_variable(Variable("Q_latent", unit="W"))
117
+ self.add_variable(Variable("Q_total", unit="W"))
118
+ self.add_variable(Variable("supply_fan_power", unit="W"))
119
+ self.add_variable(Variable("return_fan_power", unit="W"))
120
+ self.add_variable(Variable("supply_heating_setpoint", unit="°C"))
121
+ self.add_variable(Variable("supply_cooling_setpoint", unit="°C"))
122
+ self.add_variable(Variable("epsilon", unit="frac"))
123
+ self.add_variable(Variable("epsilon_adp", unit="frac"))
124
+ self.add_variable(Variable("T_iw", unit="°C"))
125
+ self.add_variable(Variable("T_ow", unit="°C"))
126
+ self.add_variable(Variable("T_ADP", unit="°C"))
127
+ self.add_variable(Variable("T_ZA", unit="°C")) # Return air temperature, zone mixture
128
+ self.add_variable(Variable("T_RA", unit="°C")) # Return air temperature, after fan
129
+ self.add_variable(Variable("w_RA", unit="g/kg"))
130
+
131
+ def check(self):
132
+ errors = super().check()
133
+ # Test spaces
134
+ if len(self.parameter("spaces").value) == 0 or any(
135
+ x == "not_defined" for x in self.parameter("spaces").value
136
+ ):
137
+ msg = "spaces have not been correctly defined"
138
+ errors.append(Message(msg, "ERROR"))
139
+ # Test air fractions
140
+ if len(self.parameter("air_flow_fractions").value) != len(
141
+ self.parameter("spaces").value
142
+ ):
143
+ msg = "air_flow_fractions must have the same number of elements as spaces"
144
+ errors.append(Message(msg, "ERROR"))
145
+ # Test air fractions sum equal to 1
146
+ if abs(sum(self.parameter("air_flow_fractions").value) - 1) > 0.0001:
147
+ msg = "air_flow_fractions must sum equal to 1"
148
+ errors.append(Message(msg, "ERROR"))
149
+ # Test return air fractions
150
+ if len(self.parameter("return_air_flow_fractions").value) != len(
151
+ self.parameter("spaces").value
152
+ ):
153
+ msg = "return_air_flow_fractions must have the same number of elements as spaces"
154
+ errors.append(Message(msg, "ERROR"))
155
+ # Test air fractions sum equal to 1
156
+ if abs(sum(self.parameter("return_air_flow_fractions").value) - 1) > 0.0001:
157
+ msg = "return_air_flow_fractions must sum equal to 1"
158
+ errors.append(Message(msg, "ERROR"))
159
+ # Test supply fan defined
160
+ if self.parameter("supply_fan").value == "not_defined":
161
+ msg = (
162
+ f"{self.parameter('name').value}, must define its supply fan equipment."
163
+ )
164
+ errors.append(Message(msg, "ERROR"))
165
+ # Test file_met defined
166
+ if self.project().parameter("simulation_file_met").value == "not_defined":
167
+ msg = f"{self.parameter('name').value}, file_met must be defined in the project 'simulation_file_met'."
168
+ errors.append(Message(msg, "ERROR"))
169
+ # Add variables
170
+ for i in range(len(self.parameter("spaces").value)):
171
+ self.add_variable(Variable(f"m_air_flow_{i}", unit="kg/s"))
172
+ if self.parameter("terminal_units").value == "REHEAT_COILS":
173
+ self.add_variable(Variable(f"Q_reheat_{i}", unit="W"))
174
+ self.add_variable(Variable(f"T_SA_{i}", unit="°C"))
175
+ self.add_variable(Variable(f"spaces_setpoint_{i}", unit="°C"))
176
+ return errors
177
+
178
+
179
+ def pre_simulation(self, n_time_steps, delta_t):
180
+ super().pre_simulation(n_time_steps, delta_t)
181
+ # Sicro
182
+ sicro.SetUnitSystem(sicro.SI)
183
+ self.props = self._sim_.props
184
+ self.file_met = self.project().parameter("simulation_file_met").component
185
+
186
+ # Parameters
187
+ self.spaces = self.parameter("spaces").component
188
+ self.air_flow_fractions = self.parameter("air_flow_fractions").value
189
+ self.return_air_flow_fractions = self.parameter(
190
+ "return_air_flow_fractions"
191
+ ).value
192
+ self.c_coil = self.parameter("cooling_coil").component
193
+ self.h_coil = self.parameter("heating_coil").component
194
+ self.supply_fan = self.parameter("supply_fan").component
195
+ self.return_fan = self.parameter("return_fan").component
196
+ self.air_flow = self.parameter("air_flow").value
197
+ self.return_air_flow = self.parameter("return_air_flow").value
198
+ self.reheat_coils = self.parameter("reheat_coils").component
199
+
200
+ # Water flows and temperatures
201
+ self.cooling_water_flow = self.parameter("cooling_water_flow").value
202
+ self.heating_water_flow = self.parameter("heating_water_flow").value
203
+ if self.c_coil:
204
+ self._cooling_F_water = (
205
+ self.cooling_water_flow
206
+ / self.c_coil.parameter("nominal_cooling_water_flow").value
207
+ )
208
+ if self.h_coil:
209
+ self._heating_F_water = (
210
+ self.heating_water_flow
211
+ / self.h_coil.parameter("nominal_heating_water_flow").value
212
+ )
213
+ self.cooling_water_temp = self.parameter("inlet_cooling_water_temp").value
214
+ self.heating_water_temp = self.parameter("inlet_heating_water_temp").value
215
+ self.rho_MA = self.props["RHO_A"]
216
+ # Fan operation
217
+ self.fan_operation = self.parameter("fan_operation").value
218
+ # adp model
219
+ self.water_flow_control = self.parameter("water_flow_control").value
220
+
221
+ def pre_iteration(self, time_index, date, daylight_saving):
222
+ super().pre_iteration(time_index, date, daylight_saving)
223
+ # Outdoor air
224
+ self.T_OA = self.file_met.variable("temperature").values[time_index]
225
+ self.T_OAwb = self.file_met.variable("wet_bulb_temp").values[time_index]
226
+ self.w_OA = self.file_met.variable("abs_humidity").values[time_index]
227
+ self.variable("T_OA").values[time_index] = self.T_OA
228
+ self.variable("T_OAwb").values[time_index] = self.T_OAwb
229
+ self.rho_OA = 1 / sicro.GetMoistAirVolume(
230
+ self.T_OA, self.w_OA / 1000, self.props["ATM_PRESSURE"]
231
+ )
232
+
233
+ # variables dictonary
234
+ var_dic = self.get_parameter_variable_dictionary(time_index)
235
+ # outdoor air fraction
236
+ self.F_OA_min = self.parameter("outdoor_air_fraction").evaluate(var_dic)
237
+ self.F_OA = self.F_OA_min
238
+ # setpoints
239
+ self.T_heat_sp = self.parameter("supply_heating_setpoint").evaluate(var_dic)
240
+ self.variable("supply_heating_setpoint").values[time_index] = self.T_heat_sp
241
+ self.T_cool_sp = self.parameter("supply_cooling_setpoint").evaluate(var_dic)
242
+ self.variable("supply_cooling_setpoint").values[time_index] = self.T_cool_sp
243
+ if self.parameter("terminal_units").value == "REHEAT_COILS":
244
+ self.T_space_sp = []
245
+ for i in range(len(self.parameter("spaces").value)):
246
+ val = self.parameter("spaces_setpoint").evaluate(i,var_dic)
247
+ self.T_space_sp.append(val)
248
+ self.variable(f"spaces_setpoint_{i}").values[time_index] = val
249
+ # on/off
250
+ self.on_off = self.parameter("system_on_off").evaluate(var_dic)
251
+ if self.on_off == 0:
252
+ self.state = 0
253
+ self.variable("state").values[time_index] = 0
254
+ self.on_off = False
255
+ else:
256
+ self.on_off = True
257
+ # Starting with the system venting
258
+ self.F_load = 0
259
+ self.epsilon = 0
260
+ self.epsilon_adp = 0
261
+
262
+ def iteration(self, time_index, date, daylight_saving, n_iter):
263
+ super().iteration(time_index, date, daylight_saving, n_iter)
264
+ if self.on_off:
265
+ self._calculate_return_air(time_index)
266
+ self._calculate_mixed_air()
267
+ self._calculate_required_Q()
268
+ if self.parameter("economizer").value != "NO":
269
+ self._simulate_economizer() # Calculation of new f_oa
270
+ self._calculate_mixed_air()
271
+ self._calculate_required_Q()
272
+ self._simulate_system()
273
+ self._send_air_to_spaces(time_index)
274
+ return True
275
+
276
+ def _calculate_return_air(self, time_index):
277
+ # Return fan
278
+ if self.return_fan is None: # No return fan
279
+ self.m_return = self.air_flow * (1 - self.F_OA) * self.rho_MA
280
+ else:
281
+ self.m_return = self.return_air_flow * self.rho_MA
282
+ Q_return_fan = self._get_fan_power("return", self.F_load)
283
+ self.T_RA = 0
284
+ self.T_ZA = 0
285
+ self.w_RA = 0
286
+ for i in range(len(self.spaces)):
287
+ space = self.spaces[i]
288
+ f_return = self.return_air_flow_fractions[i]
289
+ self.T_ZA += f_return * space.variable("temperature").values[time_index]
290
+ self.w_RA += f_return * space.variable("abs_humidity").values[time_index]
291
+ if Q_return_fan > 0 and self.m_return > 0:
292
+ self.T_RA = Q_return_fan / (self.m_return * self.props["C_PA"]) + self.T_ZA
293
+ else:
294
+ self.T_RA = self.T_ZA
295
+
296
+ def _calculate_mixed_air(self):
297
+ # Mixed air
298
+ self.T_MA, self.w_MA, self.T_MAwb = self._mix_air(
299
+ self.F_OA, self.T_OA, self.w_OA, self.T_RA, self.w_RA
300
+ )
301
+ self.rho_MA = 1 / sicro.GetMoistAirVolume(
302
+ self.T_MA, self.w_MA / 1000, self.props["ATM_PRESSURE"]
303
+ )
304
+
305
+ def _mix_air(self, f, T1, w1, T2, w2):
306
+ T = f * T1 + (1 - f) * T2
307
+ w = f * w1 + (1 - f) * w2
308
+ if T > 100:
309
+ T_wb = 50 # Inventado
310
+ else:
311
+ T_wb = sicro.GetTWetBulbFromHumRatio(
312
+ T, w / 1000, self.props["ATM_PRESSURE"]
313
+ )
314
+ return (T, w, T_wb)
315
+
316
+ def _calculate_required_Q(self):
317
+ # Calculate the required Q to mantain the supply air temperature
318
+ m_cp = self.air_flow * self.rho_MA * self.props["C_PA"]
319
+ T_with_fan = self._get_fan_power("supply", self.F_load) / m_cp + self.T_MA
320
+ if T_with_fan < self.T_heat_sp:
321
+ self.Q_required = m_cp * (self.T_heat_sp - T_with_fan)
322
+ elif T_with_fan > self.T_cool_sp:
323
+ self.Q_required = m_cp * (self.T_cool_sp - T_with_fan)
324
+ else:
325
+ self.Q_required = 0
326
+ if abs(self.Q_required) < 0.0001: # Problems with convergence
327
+ self.Q_required = 0
328
+
329
+ def _get_fan_power(self, fan, f_load):
330
+ if fan == "supply":
331
+ if self.fan_operation == "CONTINUOUS":
332
+ return self.supply_fan.get_power(self.air_flow)
333
+ elif self.fan_operation == "CYCLING":
334
+ return self.supply_fan.get_power(self.air_flow) * f_load
335
+ elif fan == "return":
336
+ if self.return_fan is None: # No return fan
337
+ return 0
338
+ else:
339
+ if self.fan_operation == "CONTINUOUS":
340
+ return self.return_fan.get_power(self.return_air_flow)
341
+ elif self.fan_operation == "CYCLING":
342
+ return self.return_fan.get_power(self.return_air_flow) * f_load
343
+
344
+ def _simulate_economizer(self):
345
+ if (
346
+ self.parameter("economizer").value == "TEMPERATURE"
347
+ or self.parameter("economizer").value == "TEMPERATURE_NOT_INTEGRATED"
348
+ ):
349
+ on_economizer = (
350
+ self.T_OA < self.T_RA - self.parameter("economizer_DT").value
351
+ )
352
+ elif self.parameter("economizer").value == "ENTHALPY":
353
+ h_OA = sicro.GetMoistAirEnthalpy(self.T_OA, self.w_OA / 1000)
354
+ h_RA = sicro.GetMoistAirEnthalpy(self.T_RA, self.w_RA / 1000)
355
+ on_economizer = h_OA < h_RA
356
+ elif self.parameter("economizer").value == "ENTHALPY_LIMITED":
357
+ h_OA = sicro.GetMoistAirEnthalpy(self.T_OA, self.w_OA / 1000)
358
+ on_economizer = (
359
+ h_OA < self.parameter("economizer_enthalpy_limit").value * 1000
360
+ )
361
+
362
+ if on_economizer:
363
+ if self.Q_required < 0:
364
+ mrhocp = self.air_flow * self.props["C_PA"] * self.rho_OA
365
+ Q_rest_oa = mrhocp * (1 - self.F_OA) * (self.T_OA - self.T_cool_sp)
366
+ if Q_rest_oa < self.Q_required:
367
+ self.F_OA += self.Q_required / (
368
+ mrhocp * (self.T_OA - self.T_cool_sp)
369
+ )
370
+ self._Q_required = 0
371
+ else:
372
+ if (
373
+ self.parameter("economizer").value
374
+ == "TEMPERATURE_NOT_INTEGRATED"
375
+ ):
376
+ self.F_OA = self.F_OA_min
377
+ else:
378
+ self.F_OA = 1
379
+ elif self.Q_required > 0: # Heating
380
+ self.F_OA = self.F_OA_min
381
+ else:
382
+ self.F_OA = self.F_OA_min
383
+
384
+ def _simulate_system(self):
385
+ if self.h_coil is not None and self.Q_required > 0: # Heating
386
+ self._simulate_heating()
387
+ elif self.c_coil is not None and self.Q_required < 0: # Cooling
388
+ self._simulate_cooling()
389
+ else: # Venting
390
+ self.state = 3
391
+ self.F_load = 0
392
+ self.Q_coil = 0
393
+ self.T_CA = self.T_MA
394
+ self.w_CA = self.w_MA
395
+
396
+ def _simulate_heating(self):
397
+ capacity, self.epsilon = self.h_coil.get_heating_capacity(
398
+ self.T_MA,
399
+ self.T_MAwb,
400
+ self.heating_water_temp,
401
+ self.air_flow,
402
+ self.heating_water_flow,
403
+ )
404
+ self.M_w = 0 # No latent load in heating
405
+ # Q_required is only the coil capacity
406
+ if capacity < self.Q_required: # Coil capacity is not enough
407
+ self.F_load = 1
408
+ self.Q_coil = capacity
409
+ self.state = 2
410
+ else:
411
+ self.Q_coil = self.Q_required
412
+ self.F_load = self.Q_coil / capacity
413
+ self.state = 1
414
+ self.T_CA = self.T_MA + self.Q_coil / (
415
+ self.air_flow * self.rho_MA * self.props["C_PA"]
416
+ )
417
+ self.w_CA = self.w_MA
418
+
419
+ def _simulate_cooling(self):
420
+ capacity_sen, capacity_lat, self.T_ADP, self.epsilon, self.epsilon_adp = (
421
+ self.c_coil.get_cooling_capacity(
422
+ self.T_MA,
423
+ self.T_MAwb,
424
+ self.cooling_water_temp,
425
+ self.air_flow,
426
+ self.cooling_water_flow,
427
+ )
428
+ )
429
+ Q_required = -self.Q_required
430
+ # Q_required is only the coil capacity
431
+ if capacity_sen < Q_required: # Coil capacity is not enough
432
+ self.state = -2
433
+ self.F_load = 1
434
+ self.Q_coil = -capacity_sen
435
+ self.M_w = -(capacity_lat) / self.props["LAMBDA"]
436
+ else:
437
+ self.state = -1
438
+ self.Q_coil = -Q_required
439
+ self.F_load = Q_required / capacity_sen
440
+ if self.water_flow_control == "ON_OFF":
441
+ self.M_w = -(capacity_lat * self.F_load) / self.props["LAMBDA"]
442
+ elif self.water_flow_control == "PROPORTIONAL":
443
+ mrhocp = self.air_flow * self.rho_MA * self.props["C_PA"]
444
+ T_CA = self.T_MA - (Q_required) / mrhocp
445
+ Q_lat, self.T_ADP, self.epsilon_adp = (
446
+ self.c_coil.get_latent_cooling_load(
447
+ self.T_MA,
448
+ self.T_MAwb,
449
+ self.cooling_water_temp,
450
+ self.air_flow,
451
+ self.cooling_water_flow,
452
+ T_CA,
453
+ )
454
+ )
455
+ self.M_w = -Q_lat / self.props["LAMBDA"]
456
+ self.T_CA = self.T_MA + self.Q_coil / (
457
+ self.air_flow * self.rho_MA * self.props["C_PA"]
458
+ )
459
+ self.w_CA = self.w_MA + self.M_w / (self.air_flow * self.rho_MA)
460
+
461
+ def _send_air_to_spaces(self, time_index): # Revisar esto
462
+ self.Q_reheat = []
463
+ for i in range(len(self.spaces)):
464
+ space = self.spaces[i]
465
+ f_air_flow = self.air_flow_fractions[i]
466
+ m_air_flow = self.air_flow * self.rho_MA
467
+ self.T_SA = self.T_CA + self._get_fan_power("supply", self.F_load) / (
468
+ m_air_flow * self.props["C_PA"]
469
+ )
470
+ self.w_SA = self.w_CA
471
+ self.T_SAwb = sicro.GetTWetBulbFromHumRatio(self.T_SA,self.w_SA/1000, self.props["ATM_PRESSURE"])
472
+
473
+ air_flow = {
474
+ "name": self.parameter("name").value,
475
+ "M_a": m_air_flow * f_air_flow,
476
+ "T_a": self.T_SA,
477
+ "w_a": self.w_SA,
478
+ "Q_s": 0,
479
+ "M_w": 0,
480
+ }
481
+ space.add_uncontrol_system(air_flow)
482
+
483
+ if self.parameter("terminal_units").value == "REHEAT_COILS":
484
+ self.Q_reheat.append(0)
485
+ reheat_coil = self.reheat_coils[i]
486
+ if reheat_coil is not None:
487
+ # Reheat coil
488
+ water_flow = reheat_coil.parameter("nominal_heating_water_flow").value
489
+ capacity, epsilon = reheat_coil.get_heating_capacity(
490
+ self.T_SA,
491
+ self.T_SAwb,
492
+ self.heating_water_temp,
493
+ self.air_flow * f_air_flow,
494
+ water_flow,
495
+ )
496
+ Q_reheat_required = self._get_Q_reheat_required(i, space)
497
+ if capacity > Q_reheat_required:
498
+ self.Q_reheat[i]= Q_reheat_required
499
+ else:
500
+ self.Q_reheat[i]= capacity
501
+ space.set_control_system({"M_a": 0,"T_a": 0,"w_a": 0,"Q_s": self.Q_reheat[i],"M_w": 0})
502
+
503
+ def _get_Q_reheat_required(self, i, space):
504
+ K_t,F_t = space.get_thermal_equation(False)
505
+ T_flo = F_t/K_t
506
+ if T_flo < self.T_space_sp[i]:
507
+ Q_reheat = K_t * self.T_space_sp[i] - F_t
508
+ else:
509
+ Q_reheat = 0
510
+ return Q_reheat
511
+
512
+ def post_iteration(self, time_index, date, daylight_saving, converged):
513
+ super().post_iteration(time_index, date, daylight_saving, converged)
514
+ self.variable("state").values[time_index] = self.state
515
+ if self.state != 0 : # on
516
+ self.variable("T_MA").values[time_index] = self.T_MA
517
+ self.variable("T_MAwb").values[time_index] = self.T_MAwb
518
+ m_supply = self.air_flow * self.rho_MA
519
+ self.variable("m_air_flow").values[time_index] = m_supply
520
+ for i in range(len(self.parameter("spaces").value)):
521
+ self.variable(f"m_air_flow_{i}").values[time_index] = m_supply * self.air_flow_fractions[i]
522
+ if self.parameter("terminal_units").value == "REHEAT_COILS":
523
+ self.variable(f"Q_reheat_{i}").values[time_index] = self.Q_reheat[i]
524
+ self.variable(f"T_SA_{i}").values[time_index] = self.T_SA + self.Q_reheat[i]/(m_supply * self.air_flow_fractions[i]* self.props["C_PA"])
525
+ self.variable("outdoor_air_fraction").values[time_index] = self.F_OA
526
+ self.variable("T_CA").values[time_index] = self.T_CA
527
+ self.variable("w_CA").values[time_index] = self.w_CA
528
+ self.variable("T_SA").values[time_index] = self.T_SA
529
+ self.variable("w_SA").values[time_index] = self.w_SA
530
+ self.variable("T_ZA").values[time_index] =self.T_ZA
531
+ self.variable("T_RA").values[time_index] =self.T_RA
532
+ self.variable("w_RA").values[time_index] =self.w_RA
533
+ self.variable("F_load").values[time_index] = self.F_load
534
+ self.variable("supply_fan_power").values[time_index] = self._get_fan_power("supply", self.F_load)
535
+ self.variable("return_fan_power").values[time_index] = self._get_fan_power("return", self.F_load)
536
+ if self.state == 1 or self.state == 2: # Heating
537
+ Q_sys = self.Q_coil
538
+ self.variable("Q_sensible").values[time_index] = Q_sys
539
+ self.variable("Q_total").values[time_index] = Q_sys
540
+ self.variable("T_iw").values[time_index] = self.heating_water_temp
541
+ self.variable("T_ow").values[time_index] = self.heating_water_temp - Q_sys/(self.heating_water_flow * self.props["RHOCP_W"](self.heating_water_temp))
542
+ self.variable("T_ADP").values[time_index] = 0
543
+ self.variable("epsilon").values[time_index] = self.epsilon
544
+ elif self.state == -1 or self.state == -2: #Cooling
545
+ Q_s = -self.Q_coil
546
+ Q_l = -self.M_w * self.props["LAMBDA"]
547
+ self.variable("Q_sensible").values[time_index] = Q_s
548
+ self.variable("Q_latent").values[time_index] = Q_l
549
+ self.variable("Q_total").values[time_index] = Q_s
550
+ self.variable("T_iw").values[time_index] = self.cooling_water_temp
551
+ self.variable("T_ow").values[time_index] = self.cooling_water_temp + (Q_s+Q_l)/(self.cooling_water_flow * self.props["RHOCP_W"](self.cooling_water_temp))
552
+ self.variable("T_ADP").values[time_index] = self.T_ADP
553
+ self.variable("epsilon").values[time_index] = self.epsilon
554
+ self.variable("epsilon_adp").values[time_index] = self.epsilon_adp