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,338 @@
1
+ from opensimula.Message import Message
2
+ from opensimula.Parameters import Parameter_component, Parameter_float, Parameter_variable_list, Parameter_math_exp, Parameter_options
3
+ from opensimula.Component import Component
4
+ from opensimula.Variable import Variable
5
+ import psychrolib as sicro
6
+
7
+ class HVAC_SZW_system(Component): # HVAC Single Zone Water system
8
+ def __init__(self, name, project):
9
+ Component.__init__(self, name, project)
10
+ self.parameter("type").value = "HVAC_SZW_system"
11
+ self.parameter("description").value = "HVAC Single Zone Water system"
12
+ self.add_parameter(Parameter_component("spaces", "not_defined", ["Space"])) # Space
13
+ self.add_parameter(Parameter_component("cooling_coil", "not_defined", ["HVAC_coil_equipment"]))
14
+ self.add_parameter(Parameter_component("heating_coil", "not_defined", ["HVAC_coil_equipment"]))
15
+ self.add_parameter(Parameter_component("supply_fan", "not_defined", ["HVAC_fan_equipment"]))
16
+ self.add_parameter(Parameter_component("return_fan", "not_defined", ["HVAC_fan_equipment"]))
17
+ self.add_parameter(Parameter_float("air_flow", 1, "m³/s", min=0))
18
+ self.add_parameter(Parameter_float("return_air_flow", 1, "m³/s", min=0)) # Not used when return fan is not defined
19
+ self.add_parameter(Parameter_math_exp("outdoor_air_fraction", "0", "frac"))
20
+ self.add_parameter(Parameter_variable_list("input_variables", []))
21
+ self.add_parameter(Parameter_math_exp("heating_setpoint", "20", "°C"))
22
+ self.add_parameter(Parameter_math_exp("cooling_setpoint", "25", "°C"))
23
+ self.add_parameter(Parameter_math_exp("system_on_off", "1", "on/off"))
24
+ self.add_parameter(Parameter_options("fan_operation", "CONTINUOUS", ["CONTINUOUS", "CYCLING"]))
25
+ self.add_parameter(Parameter_options("water_source", "UNKNOWN", ["UNKNOWN", "WATER_LOOP"]))
26
+ self.add_parameter(Parameter_float("cooling_water_flow", 1, "m³/s", min=0))
27
+ self.add_parameter(Parameter_float("heating_water_flow", 1, "m³/s", min=0))
28
+ self.add_parameter(Parameter_float("inlet_cooling_water_temp", 7, "ºC"))
29
+ self.add_parameter(Parameter_float("inlet_heating_water_temp", 50, "ºC"))
30
+ self.add_parameter(Parameter_options("water_flow_control", "ON_OFF", ["ON_OFF", "PROPORTIONAL"]))
31
+ self.add_parameter(Parameter_options("economizer", "NO", ["NO", "TEMPERATURE","TEMPERATURE_NOT_INTEGRATED","ENTHALPY","ENTHALPY_LIMITED"]))
32
+ self.add_parameter(Parameter_float("economizer_DT", 0, "ºC", min=0))
33
+ self.add_parameter(Parameter_float("economizer_enthalpy_limit", 0, "kJ/kg", min=0))
34
+
35
+ # Variables
36
+ self.add_variable(Variable("state", unit="flag")) # 0: 0ff, 1: Heating, 2: Heating max cap, -1:Cooling, -2:Cooling max cap, 3: Venting
37
+ self.add_variable(Variable("T_OA", unit="°C"))
38
+ self.add_variable(Variable("T_OAwb", unit="°C"))
39
+ self.add_variable(Variable("T_MA", unit="°C"))
40
+ self.add_variable(Variable("T_MAwb", unit="°C"))
41
+ self.add_variable(Variable("F_load", unit="frac"))
42
+ self.add_variable(Variable("outdoor_air_fraction", unit="frac"))
43
+ self.add_variable(Variable("m_air_flow", unit="kg/s"))
44
+ self.add_variable(Variable("T_SA", unit="°C"))
45
+ self.add_variable(Variable("w_SA", unit="g/kg"))
46
+ self.add_variable(Variable("T_CA", unit="°C"))
47
+ self.add_variable(Variable("w_CA", unit="g/kg"))
48
+ self.add_variable(Variable("Q_sensible", unit="W"))
49
+ self.add_variable(Variable("Q_latent", unit="W"))
50
+ self.add_variable(Variable("Q_total", unit="W"))
51
+ self.add_variable(Variable("supply_fan_power", unit="W"))
52
+ self.add_variable(Variable("return_fan_power", unit="W"))
53
+ self.add_variable(Variable("heating_setpoint", unit="°C"))
54
+ self.add_variable(Variable("cooling_setpoint", unit="°C"))
55
+ self.add_variable(Variable("epsilon", unit="frac"))
56
+ self.add_variable(Variable("epsilon_adp", unit="frac"))
57
+ self.add_variable(Variable("T_iw", unit="°C"))
58
+ self.add_variable(Variable("T_ow", unit="°C"))
59
+ self.add_variable(Variable("T_ADP", unit="°C"))
60
+ self.add_variable(Variable("T_RA", unit="°C")) # Return air temperature
61
+ def check(self):
62
+ errors = super().check()
63
+ # Test space defined
64
+ if self.parameter("spaces").value == "not_defined":
65
+ msg = f"{self.parameter('name').value}, must define its space."
66
+ errors.append(Message(msg, "ERROR"))
67
+ # Test coil defined
68
+ if self.parameter("cooling_coil").value == "not_defined" and self.parameter("heating_coil").value == "not_defined":
69
+ msg = f"{self.parameter('name').value}, must define one coil equipment."
70
+ errors.append(Message(msg, "ERROR"))
71
+ # Test supply fan defined
72
+ if self.parameter("supply_fan").value == "not_defined":
73
+ msg = f"{self.parameter('name').value}, must define its supply fan equipment."
74
+ errors.append(Message(msg, "ERROR"))
75
+ # Test file_met defined
76
+ if self.project().parameter("simulation_file_met").value == "not_defined":
77
+ msg = f"{self.parameter('name').value}, file_met must be defined in the project 'simulation_file_met'."
78
+ errors.append(Message(msg, "ERROR"))
79
+ return errors
80
+
81
+ def pre_simulation(self, n_time_steps, delta_t):
82
+ super().pre_simulation(n_time_steps, delta_t)
83
+ # Sicro
84
+ sicro.SetUnitSystem(sicro.SI)
85
+ self.props = self._sim_.props
86
+ self.file_met = self.project().parameter("simulation_file_met").component
87
+
88
+ # Parameters
89
+ self.space = self.parameter("spaces").component
90
+ self.c_coil = self.parameter("cooling_coil").component
91
+ self.h_coil = self.parameter("heating_coil").component
92
+ self.supply_fan = self.parameter("supply_fan").component
93
+ self.return_fan = self.parameter("return_fan").component
94
+ self.air_flow = self.parameter("air_flow").value
95
+ self.return_air_flow = self.parameter("return_air_flow").value
96
+
97
+ # Water flows and temperatures
98
+ self.cooling_water_flow = self.parameter("cooling_water_flow").value
99
+ self.heating_water_flow = self.parameter("heating_water_flow").value
100
+ if self.c_coil:
101
+ self.cooling_F_water = self.cooling_water_flow/self.c_coil.parameter("nominal_cooling_water_flow").value
102
+ if self.h_coil:
103
+ self.heating_F_water = self.heating_water_flow/self.h_coil.parameter("nominal_heating_water_flow").value
104
+ self.cooling_water_temp = self.parameter("inlet_cooling_water_temp").value
105
+ self.heating_water_temp = self.parameter("inlet_heating_water_temp").value
106
+ self.rho_MA = self.props["RHO_A"]
107
+ # Fan operation
108
+ self.fan_operation = self.parameter("fan_operation").value
109
+ # adp model
110
+ self.water_flow_control = self.parameter("water_flow_control").value
111
+
112
+ def pre_iteration(self, time_index, date, daylight_saving):
113
+ super().pre_iteration(time_index, date, daylight_saving)
114
+ # Outdoor air
115
+ self.T_OA = self.file_met.variable("temperature").values[time_index]
116
+ self.T_OAwb = self.file_met.variable("wet_bulb_temp").values[time_index]
117
+ self.w_OA = self.file_met.variable("abs_humidity").values[time_index]
118
+ self.variable("T_OA").values[time_index] = self.T_OA
119
+ self.variable("T_OAwb").values[time_index] = self.T_OAwb
120
+ self.rho_OA = 1/sicro.GetMoistAirVolume(self.T_OA,self.w_OA/1000,self.props["ATM_PRESSURE"])
121
+
122
+ # variables dictonary
123
+ var_dic = self.get_parameter_variable_dictionary(time_index)
124
+ # outdoor air fraction
125
+ self.F_OA_min = self.parameter("outdoor_air_fraction").evaluate(var_dic)
126
+ self.F_OA = self.F_OA_min
127
+ # setpoints
128
+ self.T_heat_sp = self.parameter("heating_setpoint").evaluate(var_dic)
129
+ self.variable("heating_setpoint").values[time_index] = self.T_heat_sp
130
+ self.T_cool_sp = self.parameter("cooling_setpoint").evaluate(var_dic)
131
+ self.variable("cooling_setpoint").values[time_index] = self.T_cool_sp
132
+ # on/off
133
+ self.on_off = self.parameter("system_on_off").evaluate(var_dic)
134
+ if self.on_off == 0:
135
+ self.state = 0
136
+ self.variable("state").values[time_index] = 0
137
+ self.on_off = False
138
+ else:
139
+ self.on_off = True
140
+ # Starting with the system venting
141
+ self.F_load = 0
142
+ self.epsilon = 0
143
+ self.epsilon_adp = 0
144
+
145
+ def iteration(self, time_index, date, daylight_saving, n_iter):
146
+ super().iteration(time_index, date, daylight_saving, n_iter)
147
+ if self.on_off:
148
+ self._calculate_return_air(time_index)
149
+ self._calculate_required_Q()
150
+ if (self.parameter("economizer").value != "NO"):
151
+ self._simulate_economizer() # Calculation of new F_OA
152
+ self._calculate_required_Q()
153
+ self._calculate_mixed_air()
154
+ self._simulate_system()
155
+ air_flow = {"M_a": self.air_flow * self.F_OA * self.rho_MA,
156
+ "T_a": self.T_OA,
157
+ "w_a": self.w_OA,
158
+ "Q_s": self.Q_eq,
159
+ "M_w": self.M_w }
160
+ self.space.set_control_system(air_flow)
161
+ return True
162
+
163
+ def _calculate_return_air(self, time_index):
164
+ self.T_ZA = self.space.variable("temperature").values[time_index]
165
+ self.w_ZA = self.space.variable("abs_humidity").values[time_index]
166
+ self.w_RA = self.w_ZA
167
+ if self.return_fan is None: # No return fan
168
+ self.T_RA =self.T_ZA
169
+ self.Q_return_fan_required = 0
170
+ else:
171
+ Q_return_fan = self._get_fan_power("return",self.F_load)
172
+ self.Q_return_fan_required = Q_return_fan * self.air_flow * (1-self.F_OA)/ self.return_air_flow
173
+ mrhocp = self.return_air_flow * self.rho_MA * self.props["C_PA"]
174
+ if mrhocp > 0:
175
+ self.T_RA = self.T_ZA + Q_return_fan/mrhocp
176
+
177
+ def _calculate_required_Q(self):
178
+ K_t,F_t = self.space.get_thermal_equation(False)
179
+ Q_supply_fan = self._get_fan_power("supply",self.F_load)
180
+ m_cp_oa = self.air_flow * self.F_OA * self.rho_MA * self.props["C_PA"]
181
+ K_ts = K_t + m_cp_oa
182
+ F_ts = F_t + m_cp_oa * self.T_OA + Q_supply_fan + self.Q_return_fan_required
183
+ T_flo = F_ts/K_ts
184
+ if T_flo > self.T_cool_sp:
185
+ self.Q_required = K_ts * self.T_cool_sp - F_ts
186
+ elif T_flo < self.T_heat_sp:
187
+ self.Q_required = K_ts * self.T_heat_sp - F_ts
188
+ else:
189
+ self.Q_required = 0
190
+ if abs(self.Q_required) < 0.0001: # Problems with convergence
191
+ self.Q_required = 0
192
+
193
+ def _get_fan_power(self, fan, F_load):
194
+ if fan == "supply":
195
+ if self.fan_operation == "CONTINUOUS":
196
+ return self.supply_fan.get_power(self.air_flow)
197
+ elif self.fan_operation == "CYCLING":
198
+ return self.supply_fan.get_power(self.air_flow)*F_load
199
+ elif fan == "return":
200
+ if self.return_fan is None: # No return fan
201
+ return 0
202
+ else:
203
+ if self.fan_operation == "CONTINUOUS":
204
+ return self.return_fan.get_power(self.return_air_flow)
205
+ elif self.fan_operation == "CYCLING":
206
+ return self.return_fan.get_power(self.return_air_flow)*F_load
207
+
208
+ def _calculate_mixed_air(self):
209
+ # Mixed air
210
+ self.T_MA, self.w_MA, self.T_MAwb = self._mix_air(self.F_OA, self.T_OA, self.w_OA, self.T_RA, self.w_RA)
211
+ self.rho_MA = 1/sicro.GetMoistAirVolume(self.T_MA,self.w_MA/1000,self.props["ATM_PRESSURE"])
212
+
213
+ def _mix_air(self, f, T1, w1, T2, w2):
214
+ T = f * T1 + (1-f)*T2
215
+ w = f * w1 + (1-f)*w2
216
+ if (T > 100):
217
+ T_wb = 50 # Inventado
218
+ else:
219
+ T_wb = sicro.GetTWetBulbFromHumRatio(T,w/1000,self.props["ATM_PRESSURE"])
220
+ return (T,w,T_wb)
221
+
222
+ def _simulate_economizer(self):
223
+ if (self.parameter("economizer").value == "TEMPERATURE" or self.parameter("economizer").value == "TEMPERATURE_NOT_INTEGRATED"):
224
+ on_economizer = self.T_OA < self.T_RA - self.parameter("economizer_DT").value
225
+ elif (self.parameter("economizer").value == "ENTHALPY"):
226
+ h_OA = sicro.GetMoistAirEnthalpy(self.T_OA,self.w_OA/1000)
227
+ h_RA = sicro.GetMoistAirEnthalpy(self.T_RA,self.w_RA/1000)
228
+ on_economizer = h_OA < h_RA
229
+ elif (self.parameter("economizer").value == "ENTHALPY_LIMITED"):
230
+ h_OA = sicro.GetMoistAirEnthalpy(self.T_OA,self.w_OA/1000)
231
+ on_economizer = h_OA < self.parameter("economizer_enthalpy_limit").value * 1000
232
+
233
+ if (on_economizer):
234
+ if (self.Q_required < 0):
235
+ mrhocp = self.air_flow * self.props["C_PA"]* self.rho_OA
236
+ Q_rest_oa = mrhocp * (1-self.F_OA) * (self.T_OA - self.T_ZA)
237
+ if Q_rest_oa < self.Q_required:
238
+ self.F_OA += self.Q_required/(mrhocp * (self.T_OA-self.T_ZA))
239
+ self.Q_required = 0
240
+ else:
241
+ if (self.parameter("economizer").value == "TEMPERATURE_NOT_INTEGRATED"):
242
+ self.F_OA = self.F_OA_min
243
+ else:
244
+ self.F_OA = 1
245
+ elif (self.Q_required > 0): # Heating
246
+ self.F_OA = self.F_OA_min
247
+ else:
248
+ self.F_OA = self.F_OA_min
249
+
250
+ def _simulate_system(self):
251
+ if self.h_coil is not None and self.Q_required > 0: # Heating
252
+ self._simulate_heating()
253
+ elif self.c_coil is not None and self.Q_required < 0: # Cooling
254
+ self._simulate_cooling()
255
+ else: # Venting
256
+ self.state = 3
257
+ self.F_load = 0
258
+ self.Q_coil = 0
259
+ self.Q_eq = self._get_fan_power("supply", 0) + self.Q_return_fan_required
260
+ self.M_w = 0
261
+
262
+ def _simulate_heating(self):
263
+ capacity, self.epsilon = self.h_coil.get_heating_capacity(self.T_MA, self.T_MAwb, self.heating_water_temp,self.air_flow,self.heating_water_flow)
264
+ self.M_w = 0 # No latent load in heating
265
+ # Q_required is only the coil capacity
266
+ if capacity < self.Q_required: # Coil capacity is not enough
267
+ self.F_load = 1
268
+ self.Q_coil = capacity
269
+ self.Q_eq = capacity + self._get_fan_power("supply",1) + self.Q_return_fan_required
270
+ self.state = 2
271
+ else:
272
+ self.Q_coil = self.Q_required
273
+ self.F_load = self.Q_coil / capacity
274
+ self.Q_eq = self.Q_required + self._get_fan_power("supply", self.F_load) + self.Q_return_fan_required
275
+ self.state = 1
276
+
277
+ def _simulate_cooling(self):
278
+ capacity_sen, capacity_lat, self.T_ADP, self.epsilon, self.epsilon_adp = self.c_coil.get_cooling_capacity(self.T_MA, self.T_MAwb,self.cooling_water_temp,self.air_flow,self.cooling_water_flow)
279
+ Q_required = -self.Q_required
280
+ # Q_required is only the coil capacity
281
+ if capacity_sen < Q_required: # Coil capacity is not enough
282
+ self.state = -2
283
+ self.F_load = 1
284
+ self.Q_coil = - capacity_sen
285
+ self.Q_eq = self._get_fan_power("supply",1) + self.Q_return_fan_required - capacity_sen
286
+ self.M_w = - (capacity_lat) / self.props["LAMBDA"]
287
+ else:
288
+ self.state = -1
289
+ self.Q_coil = - Q_required
290
+ self.F_load = Q_required / capacity_sen
291
+ self.Q_eq = - Q_required + self._get_fan_power("supply", self.F_load) +self.Q_return_fan_required
292
+ if self.water_flow_control == "ON_OFF":
293
+ self.M_w = - (capacity_lat*self.F_load) / self.props["LAMBDA"]
294
+ elif self.water_flow_control == "PROPORTIONAL":
295
+ mrhocp = self.air_flow * self.rho_MA * self.props["C_PA"]
296
+ T_CA = self.T_MA - (Q_required) / mrhocp
297
+ Q_lat, self.T_ADP,self.epsilon_adp = self.c_coil.get_latent_cooling_load(self.T_MA, self.T_MAwb, self.cooling_water_temp, self.air_flow, self.cooling_water_flow, T_CA)
298
+ self.M_w = - Q_lat / self.props["LAMBDA"]
299
+
300
+ def post_iteration(self, time_index, date, daylight_saving, converged):
301
+ super().post_iteration(time_index, date, daylight_saving, converged)
302
+ self.variable("state").values[time_index] = self.state
303
+ if self.state != 0 : # on
304
+ self.variable("T_MA").values[time_index] = self.T_MA
305
+ self.variable("T_MAwb").values[time_index] = self.T_MAwb
306
+ m_supply = self.air_flow * self.rho_MA
307
+ self.variable("m_air_flow").values[time_index] = m_supply
308
+ self.variable("outdoor_air_fraction").values[time_index] = self.F_OA
309
+ # Density of air at the fan inlet
310
+ T_CA = self.Q_coil/(m_supply*self.props["C_PA"]) + self.T_MA
311
+ w_CA = self.M_w/m_supply +self.w_MA
312
+ self.variable("T_CA").values[time_index] = T_CA
313
+ self.variable("w_CA").values[time_index] = w_CA
314
+ self.variable("T_SA").values[time_index] = self._get_fan_power("supply",self.F_load)/(m_supply*self.props["C_PA"]) + T_CA
315
+ self.variable("w_SA").values[time_index] = w_CA
316
+ self.variable("T_RA").values[time_index] =self.T_RA
317
+ self.variable("F_load").values[time_index] = self.F_load
318
+ self.variable("supply_fan_power").values[time_index] = self._get_fan_power("supply", self.F_load)
319
+ self.variable("return_fan_power").values[time_index] = self._get_fan_power("return", self.F_load)
320
+ if self.state == 1 or self.state == 2: # Heating
321
+ Q_sys = self.Q_coil
322
+ self.variable("Q_sensible").values[time_index] = Q_sys
323
+ self.variable("Q_total").values[time_index] = Q_sys
324
+ self.variable("T_iw").values[time_index] = self.heating_water_temp
325
+ 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))
326
+ self.variable("T_ADP").values[time_index] = 0
327
+ self.variable("epsilon").values[time_index] = self.epsilon
328
+ elif self.state == -1 or self.state == -2: #Cooling
329
+ Q_s = -self.Q_coil
330
+ Q_l = -self.M_w * self.props["LAMBDA"]
331
+ self.variable("Q_sensible").values[time_index] = Q_s
332
+ self.variable("Q_latent").values[time_index] = Q_l
333
+ self.variable("Q_total").values[time_index] = Q_s
334
+ self.variable("T_iw").values[time_index] = self.cooling_water_temp
335
+ 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))
336
+ self.variable("T_ADP").values[time_index] = self.T_ADP
337
+ self.variable("epsilon").values[time_index] = self.epsilon
338
+ self.variable("epsilon_adp").values[time_index] = self.epsilon_adp
@@ -0,0 +1,206 @@
1
+ from opensimula.Message import Message
2
+ from opensimula.Parameters import Parameter_float, Parameter_float_list, Parameter_math_exp, Parameter_options, Parameter_boolean
3
+ from opensimula.Component import Component
4
+ from scipy.optimize import fsolve
5
+ import psychrolib as sicro
6
+
7
+ class HVAC_coil_equipment(Component):
8
+ def __init__(self, name, project):
9
+ Component.__init__(self, name, project)
10
+ self.parameter("type").value = "HVAC_coil_equipment"
11
+ self.parameter("description").value = "HVAC coil equipment manufacturer information"
12
+ self.add_parameter(Parameter_float("nominal_air_flow", 1, "m³/s", min=0))
13
+ self.add_parameter(Parameter_float("nominal_cooling_water_flow", 1, "m³/s", min=0))
14
+ self.add_parameter(Parameter_float("nominal_total_cooling_capacity", 0, "W", min=0))
15
+ self.add_parameter(Parameter_float("nominal_sensible_cooling_capacity", 0, "W", min=0))
16
+ self.add_parameter(Parameter_float_list("nominal_cooling_conditions", [27, 19, 7], "ºC"))
17
+ self.add_parameter(Parameter_float("nominal_heating_water_flow", 1, "m³/s", min=0))
18
+ self.add_parameter(Parameter_float("nominal_heating_capacity", 0, "W", min=0))
19
+ self.add_parameter(Parameter_float_list("nominal_heating_conditions", [20, 15, 50], "ºC"))
20
+ self.add_parameter(Parameter_math_exp("heating_epsilon_expression", "1", "frac"))
21
+ self.add_parameter(Parameter_math_exp("cooling_epsilon_expression", "1", "frac"))
22
+ self.add_parameter(Parameter_math_exp("cooling_adp_epsilon_expression", "1", "frac"))
23
+ self.add_parameter(Parameter_float_list("expression_max_values", [60,30,99,2,2], "-"))
24
+ self.add_parameter(Parameter_float_list("expression_min_values", [-30,-30,0,0,0], "-"))
25
+
26
+ def check(self):
27
+ errors = super().check()
28
+ # Test Cooling and Heating conditions: 3, 3 values (Entering air and water)
29
+ if len(self.parameter("nominal_cooling_conditions").value)!= 3:
30
+ msg = f"{self.parameter('name').value}, nominal_cooling_conditions size must be 3"
31
+ errors.append(Message(msg, "ERROR"))
32
+ if len(self.parameter("nominal_heating_conditions").value)!= 3:
33
+ msg = f"{self.parameter('name').value}, nominal_heating_conditions size must be 3"
34
+ errors.append(Message(msg, "ERROR"))
35
+ return errors
36
+
37
+ def pre_simulation(self, n_time_steps, delta_t):
38
+ super().pre_simulation(n_time_steps, delta_t)
39
+ # Sicro
40
+ sicro.SetUnitSystem(sicro.SI)
41
+ self.props = self._sim_.props
42
+
43
+ # Parameters
44
+ self._nominal_air_flow = self.parameter("nominal_air_flow").value
45
+ # Heating
46
+ self._nominal_heating_capacity = self.parameter("nominal_heating_capacity").value
47
+ self._nominal_heating_water_flow = self.parameter("nominal_heating_water_flow").value
48
+ self._T_idb_HN = self.parameter("nominal_heating_conditions").value[0]
49
+ self._T_iwb_HN = self.parameter("nominal_heating_conditions").value[1]
50
+ self._T_iw_HN = self.parameter("nominal_heating_conditions").value[2]
51
+ # Cooling
52
+ self._nominal_total_cooling_capacity = self.parameter("nominal_total_cooling_capacity").value
53
+ self._nominal_sensible_cooling_capacity = self.parameter("nominal_sensible_cooling_capacity").value
54
+ self._nominal_cooling_water_flow = self.parameter("nominal_cooling_water_flow").value
55
+ self._T_idb_CN = self.parameter("nominal_cooling_conditions").value[0]
56
+ self._T_iwb_CN = self.parameter("nominal_cooling_conditions").value[1]
57
+ self._T_iw_CN = self.parameter("nominal_cooling_conditions").value[2]
58
+
59
+ self.calculate_nominal_effectiveness()
60
+
61
+ def calculate_nominal_effectiveness(self):
62
+ # Heating
63
+ if self._nominal_heating_capacity > 0:
64
+ w = sicro.GetHumRatioFromTWetBulb(self._T_iw_HN,self._T_iwb_HN,101325)
65
+ rho = 1/sicro.GetMoistAirVolume(self._T_idb_HN,w,101325)
66
+ C_min = min( self._nominal_air_flow * rho * self.props["C_PA"], self._nominal_heating_water_flow * self.props["RHOCP_W"](self._T_iw_HN))
67
+ Q_max = C_min * (self._T_iw_HN - self._T_idb_HN)
68
+ self._nominal_heating_epsilon = self._nominal_heating_capacity/Q_max
69
+ if self._nominal_heating_epsilon > 1:
70
+ self._sim_.message(Message(f"{self.parameter('name').value} : Nominal heating effectiveness > 1","ERROR"))
71
+ else:
72
+ self._nominal_heating_epsilon = 0
73
+
74
+ # Cooling
75
+ if self._nominal_total_cooling_capacity > 0:
76
+ T_ri =sicro.GetTDewPointFromTWetBulb(self._T_idb_CN,self._T_iwb_CN,101325)
77
+ if T_ri < self._T_iw_CN:
78
+ self._sim_.message(Message(f"{self.parameter('name').value} : Nominal dry coil, inlet water temperature must be less than inlet dew point temperature","ERROR"))
79
+ w_i = sicro.GetHumRatioFromTWetBulb(self._T_idb_CN,self._T_iwb_CN,101325)
80
+ rho = 1/sicro.GetMoistAirVolume(self._T_idb_CN,w_i,101325)
81
+ h_ia = sicro.GetMoistAirEnthalpy(self._T_idb_CN,w_i)
82
+ h_iw = sicro.GetMoistAirEnthalpy(self._T_iw_CN,sicro.GetHumRatioFromRelHum(self._T_iw_CN,1,101325))
83
+ self._nominal_enthalpy_epsilon = self._nominal_total_cooling_capacity / (self._nominal_air_flow * rho * (h_ia-h_iw))
84
+ if (self._nominal_enthalpy_epsilon > 1):
85
+ self._sim_.message(Message(f"{self.parameter('name').value} : Nominal cooling effectiveness > 1","ERROR"))
86
+ h_oa = h_ia - self._nominal_total_cooling_capacity/(self._nominal_air_flow * rho)
87
+ T_odb = self._T_idb_CN - self._nominal_sensible_cooling_capacity/(self._nominal_air_flow * rho * self.props["C_PA"])
88
+ w_o = sicro.GetHumRatioFromEnthalpyAndTDryBulb(h_oa,T_odb)
89
+ # Calculate ADP
90
+ self._nominal_T_adp = self.calculate_ADP(self._T_idb_CN,w_i,T_odb,w_o,101325)
91
+ self._nominal_cooling_adp_epsilon = (self._T_idb_CN - T_odb)/(self._T_idb_CN - self._nominal_T_adp)
92
+ if (self._nominal_cooling_adp_epsilon > 1):
93
+ self._sim_.message(Message(f"{self.parameter('name').value} : Nominal cooling ADP effectiveness > 1","ERROR"))
94
+ else:
95
+ self._nominal_enthalpy_epsilon = 0
96
+ self._nominal_cooling_adp_epsilon = 0
97
+
98
+ def calculate_ADP(self,T_i,w_i,T_o,w_o,p):
99
+ def func(x):
100
+ w_adp = sicro.GetHumRatioFromRelHum(x,1,p)
101
+ w_adp2 = w_i - (T_i -x) * (w_i - w_o)/(T_i-T_o)
102
+ return w_adp - w_adp2
103
+ solucion = fsolve(func, x0=T_o -1,xtol=1e-3)
104
+ return solucion[0]
105
+
106
+ def get_heating_capacity(self,T_idb,T_iwb,T_iw,air_flow,water_flow):
107
+ if self._nominal_heating_capacity > 0:
108
+ # variables dictonary
109
+ F_air = air_flow/ self._nominal_air_flow
110
+ F_water = water_flow/ self._nominal_heating_water_flow
111
+ var_dic = self._var_state_dic([T_idb, T_iwb,T_iw,F_air,F_water])
112
+ w_i = sicro.GetHumRatioFromTWetBulb(T_idb,T_iwb,self.props["ATM_PRESSURE"])
113
+ rho_i = 1/sicro.GetMoistAirVolume(T_idb,w_i,self.props["ATM_PRESSURE"])
114
+
115
+ # Capacity
116
+ epsilon = self._nominal_heating_epsilon * self.parameter("heating_epsilon_expression").evaluate(var_dic)
117
+ C_min = min(self._nominal_air_flow * F_air * rho_i * self.props["C_PA"], self._nominal_heating_water_flow*F_water*self.props["RHOCP_W"](T_iw))
118
+ capacity = epsilon * C_min * (T_iw - T_idb)
119
+ return capacity, epsilon
120
+ else:
121
+ return 0, 0
122
+
123
+ def get_cooling_capacity(self,T_idb,T_iwb,T_iw,air_flow,water_flow):
124
+ Q_sen = 0
125
+ Q_lat = 0
126
+ T_adp = 0
127
+ epsilon = 0
128
+ adp_epsilon = 0
129
+ if self._nominal_total_cooling_capacity > 0:
130
+ # variables dictonary
131
+ F_air = air_flow/ self._nominal_air_flow
132
+ F_water = water_flow/ self._nominal_cooling_water_flow
133
+ var_dic = self._var_state_dic([T_idb, T_iwb,T_iw,F_air, F_water])
134
+ # epsilon
135
+ epsilon = self._nominal_enthalpy_epsilon * self.parameter("cooling_epsilon_expression").evaluate(var_dic)
136
+ adp_epsilon = self._nominal_cooling_adp_epsilon * self.parameter("cooling_adp_epsilon_expression").evaluate(var_dic)
137
+ T_idp =sicro.GetTDewPointFromTWetBulb(T_idb,T_iwb,self.props["ATM_PRESSURE"])
138
+ w_i = sicro.GetHumRatioFromTWetBulb(T_idb,T_iwb,self.props["ATM_PRESSURE"])
139
+ h_i = sicro.GetMoistAirEnthalpy(T_idb,w_i)
140
+ rho_i = 1/sicro.GetMoistAirVolume(T_idb,w_i,self.props["ATM_PRESSURE"])
141
+ mrho = self._nominal_air_flow * F_air * rho_i
142
+ mrhocp = mrho * self.props["C_PA"]
143
+ if T_idp < T_iw: # Dry coil
144
+ Q_lat = 0
145
+ Q_sen = epsilon * mrhocp * (T_idb - T_iw)
146
+ T_adp = T_idp
147
+ else: # Wet coil
148
+ h_iw = sicro.GetMoistAirEnthalpy(T_iw,sicro.GetHumRatioFromRelHum(T_iw,1,self.props["ATM_PRESSURE"]))
149
+ Q_tot = epsilon * mrho * (h_i - h_iw)
150
+ h_o = h_i - Q_tot/mrho
151
+ h_adp = h_i - (h_i -h_o)/adp_epsilon
152
+ T_adp = self.get_T_adp_from_h_adp(h_adp,T_iw + 4)
153
+ Q_sen = adp_epsilon * mrhocp * (T_idb - T_adp)
154
+ if (Q_sen > Q_tot):
155
+ Q_sen = Q_tot
156
+ Q_lat = Q_tot - Q_sen
157
+ return Q_sen, Q_lat, T_adp, epsilon, adp_epsilon
158
+
159
+ def get_latent_cooling_load(self,T_idb,T_iwb,T_iw,air_flow,water_flow,T_odb):
160
+ # variables dictonary
161
+ F_air = air_flow/ self._nominal_air_flow
162
+ F_water = water_flow/ self._nominal_cooling_water_flow
163
+ var_dic = self._var_state_dic([T_idb, T_iwb,T_iw,F_air, F_water])
164
+ # epsilon
165
+ adp_epsilon = self._nominal_cooling_adp_epsilon * self.parameter("cooling_adp_epsilon_expression").evaluate(var_dic)
166
+ T_adp = T_idb - (T_idb - T_odb)/ adp_epsilon
167
+ T_idp =sicro.GetTDewPointFromTWetBulb(T_idb,T_iwb,self.props["ATM_PRESSURE"])
168
+ w_i = sicro.GetHumRatioFromTWetBulb(T_idb,T_iwb,self.props["ATM_PRESSURE"])
169
+ h_i = sicro.GetMoistAirEnthalpy(T_idb,w_i)
170
+ rho_i = 1/sicro.GetMoistAirVolume(T_idb,w_i,self.props["ATM_PRESSURE"])
171
+ mrho = self._nominal_air_flow * F_air * rho_i
172
+ Q_sen = mrho * self.props["C_PA"] * (T_idb - T_odb)
173
+ if T_adp < T_idp:
174
+ w_adp = sicro.GetHumRatioFromRelHum(T_adp,1,self.props["ATM_PRESSURE"])
175
+ h_adp = sicro.GetMoistAirEnthalpy(T_adp,w_adp)
176
+ cap_tot = adp_epsilon * mrho * (h_i - h_adp)
177
+ Q_lat = cap_tot - Q_sen
178
+ else:
179
+ Q_lat = 0
180
+ T_adp = T_idp
181
+ return Q_lat, T_adp, adp_epsilon
182
+
183
+ def get_T_adp_from_h_adp(self,h_adp,T_ini):
184
+ def func(x):
185
+ return (h_adp - sicro.GetSatAirEnthalpy(x,self.props["ATM_PRESSURE"]))
186
+ solucion = fsolve(func, x0=T_ini,xtol=1e-3)
187
+ return solucion[0]
188
+
189
+ def _var_state_dic(self, values):
190
+ max = self.parameter("expression_max_values").value
191
+ min = self.parameter("expression_min_values").value
192
+ for i in range(len(values)):
193
+ if (values[i] > max[i]):
194
+ values[i] = max[i]
195
+ elif (values[i] < min[i]):
196
+ values[i] = min[i]
197
+ return {"T_idb":values[0],
198
+ "T_iwb":values[1],
199
+ "T_iw":values[2],
200
+ "F_air":values[3],
201
+ "F_water":values[4]}
202
+
203
+
204
+
205
+
206
+
@@ -0,0 +1,44 @@
1
+ from opensimula.Parameters import Parameter_float, Parameter_math_exp
2
+ from opensimula.Component import Component
3
+
4
+ class HVAC_fan_equipment(Component):
5
+ def __init__(self, name, project):
6
+ Component.__init__(self, name, project)
7
+ self.parameter("type").value = "HVAC_fan_equipment"
8
+ self.parameter("description").value = "HVAC Fan equipment manufacturer information"
9
+ self.add_parameter(Parameter_float("nominal_air_flow", 1, "m³/s", min=0))
10
+ self.add_parameter(Parameter_float("nominal_pressure", 1, "Pa", min=0))
11
+ self.add_parameter(Parameter_float("nominal_power", 1, "W", min=0))
12
+ self.add_parameter(Parameter_math_exp("pressure_expression", "1", "frac"))
13
+ self.add_parameter(Parameter_math_exp("power_expression", "1", "frac"))
14
+
15
+ def check(self):
16
+ errors = super().check()
17
+ return errors
18
+
19
+ def pre_simulation(self, n_time_steps, delta_t):
20
+ # Parameters
21
+ self._nominal_air_flow = self.parameter("nominal_air_flow").value
22
+ self._nominal_pressure = self.parameter("nominal_pressure").value
23
+ self._nominal_power = self.parameter("nominal_power").value
24
+
25
+ def get_pressure(self,air_flow):
26
+ # variables dictonary
27
+ var_dic = {"F_air":air_flow/self._nominal_air_flow}
28
+ # Pressure
29
+ pressure = self._nominal_pressure * self.parameter("pressure_expression").evaluate(var_dic)
30
+ return pressure
31
+
32
+ def get_power(self,air_flow):
33
+ # variables dictonary
34
+ var_dic = {"F_air":air_flow/self._nominal_air_flow}
35
+ # Power
36
+ power = self._nominal_power * self.parameter("power_expression").evaluate(var_dic)
37
+ return power
38
+
39
+
40
+
41
+
42
+
43
+
44
+