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,114 @@
1
+ import math
2
+ from opensimula.Message import Message
3
+ from opensimula.components.Surface import Surface
4
+ from opensimula.Parameters import Parameter_component, Parameter_options, Parameter_boolean
5
+ from opensimula.visual_3D.Polygon_3D import Polygon_3D
6
+
7
+
8
+ class Solar_surface(Surface):
9
+ def __init__(self, name, project):
10
+ Surface.__init__(self, name, project)
11
+ # Parameters
12
+ self.parameter("type").value = "Solar_surface"
13
+ self.parameter("description").value = "Solar surface"
14
+ self.add_parameter(Parameter_options("coordinate_system", "BUILDING", ["BUILDING", "GLOBAL"]))
15
+ self.add_parameter(Parameter_component("building", "not_defined", ["Building"]))
16
+ self.add_parameter(Parameter_boolean("cast_shadows", True))
17
+ self.add_parameter(Parameter_boolean("calculate_solar_radiation", False))
18
+
19
+ # Variables
20
+
21
+ def check(self):
22
+ errors = super().check()
23
+ # Test building is defined
24
+ if self.parameter("coordinate_system").value == "BUILDING" and self.parameter("building").value == "not_defined":
25
+ msg = f"{self.parameter('name').value}, must define its building."
26
+ errors.append(Message(msg, "ERROR"))
27
+ return errors
28
+
29
+ def get_building(self):
30
+ if self.parameter("coordinate_system").value == "BUILDING":
31
+ return self.parameter("building").component
32
+ else:
33
+ return None
34
+
35
+ # ____________ pre_simulation ____________
36
+ def pre_simulation(self, n_time_steps, delta_t):
37
+ super().pre_simulation(n_time_steps, delta_t)
38
+ if self.parameter("calculate_solar_radiation").value:
39
+ self._file_met = self.project().parameter("simulation_file_met").component
40
+ self._sunny_index_ = self.project().env_3D.get_sunny_index(self.parameter("name").value)
41
+ self._albedo = self.project().parameter("albedo").value
42
+ self._F_sky = (1 + math.sin(math.radians(self.parameter("altitude").value))) / 2
43
+
44
+
45
+ def pre_iteration(self, time_i, date, daylight_saving):
46
+ super().pre_iteration(time_i, date, daylight_saving)
47
+ if self.parameter("calculate_solar_radiation").value:
48
+ # Meterological data
49
+ hor_sol_dif = self._file_met.variable("sol_diffuse").values[time_i]
50
+ hor_sol_dir = self._file_met.variable("sol_direct").values[time_i]
51
+
52
+ # Diffuse solar radiation
53
+ E_dif_sunny = self._file_met.solar_diffuse_rad(
54
+ time_i,
55
+ self.orientation_angle("azimuth", 0),
56
+ self.orientation_angle("altitude", 0),
57
+ )
58
+ E_dif_sunny = E_dif_sunny + (1 - self._F_sky) * self._albedo * (hor_sol_dif + hor_sol_dir)
59
+ self.variable("E_dif_sunny").values[time_i] = E_dif_sunny
60
+ diffuse_sunny_fraction = self.project().env_3D.get_diffuse_sunny_fraction(self._sunny_index_)
61
+ E_dif = E_dif_sunny * diffuse_sunny_fraction
62
+ self.variable("E_dif").values[time_i] = E_dif
63
+ # Direct solar radiation
64
+ E_dir_sunny = self._file_met.solar_direct_rad(
65
+ time_i,
66
+ self.orientation_angle("azimuth", 0),
67
+ self.orientation_angle("altitude", 0),
68
+ )
69
+ self.variable("E_dir_sunny").values[time_i] = E_dir_sunny
70
+ E_dir = E_dir_sunny * self._calculate_direct_sunny_fraction_(time_i)
71
+ self.variable("E_dir").values[time_i] = E_dir
72
+
73
+ def _calculate_direct_sunny_fraction_(self, time_i):
74
+ if self.project().parameter("shadow_calculation").value == "INSTANT":
75
+ direct_sunny_fraction = self.project().env_3D.get_direct_sunny_fraction(
76
+ self._sunny_index_
77
+ )
78
+ elif self.project().parameter("shadow_calculation").value == "INTERPOLATION":
79
+ azi = self._file_met.variable("sol_azimuth").values[time_i]
80
+ alt = self._file_met.variable("sol_altitude").values[time_i]
81
+ if not math.isnan(alt):
82
+ direct_sunny_fraction = (
83
+ self.project().env_3D.get_direct_interpolated_sunny_fraction(
84
+ self._sunny_index_, azi, alt
85
+ )
86
+ )
87
+ else:
88
+ direct_sunny_fraction = 1
89
+ elif self.project().parameter("shadow_calculation").value == "NO":
90
+ direct_sunny_fraction = 1
91
+ return direct_sunny_fraction
92
+
93
+ def get_polygon_3D(self):
94
+ if self.parameter("coordinate_system").value == "BUILDING":
95
+ coord_system = "global"
96
+ else:
97
+ coord_system = "local"
98
+ azimuth = self.orientation_angle("azimuth", 0, coord_system)
99
+ altitude = self.orientation_angle("altitude", 0, coord_system)
100
+ origin = self.get_origin(coord_system)
101
+ pol_2D = self.get_polygon_2D()
102
+ name = self.parameter("name").value
103
+ shading = self.parameter("cast_shadows").value
104
+ calculate_shadows = self.parameter("calculate_solar_radiation").value
105
+ return Polygon_3D(
106
+ name,
107
+ origin,
108
+ azimuth,
109
+ altitude,
110
+ pol_2D,
111
+ color="cyan",
112
+ shading=shading,
113
+ calculate_shadows=calculate_shadows,
114
+ )
@@ -0,0 +1,388 @@
1
+ from opensimula.Component import Component
2
+ from opensimula.Message import Message
3
+ from opensimula.Parameters import Parameter_component, Parameter_float
4
+ from opensimula.Variable import Variable
5
+ from opensimula.Iterative_process import Iterative_process
6
+ import numpy as np
7
+ import psychrolib as sicro
8
+ import math
9
+
10
+
11
+ class Space(Component):
12
+ def __init__(self, name, project):
13
+ Component.__init__(self, name, project)
14
+ self.parameter("type").value = "Space"
15
+ self.parameter("description").value = "Indoor building space"
16
+ # Parameters
17
+ self.add_parameter(Parameter_component("spaces_type", "not_defined", ["Space_type"]))
18
+ self.add_parameter(Parameter_component("building", "not_defined", ["Building"]))
19
+ self.add_parameter(Parameter_float("floor_area", 1, "m²", min=0.0))
20
+ self.add_parameter(Parameter_float("volume", 1, "m³", min=0.0))
21
+ self.add_parameter(Parameter_float("furniture_weight", 10, "kg/m²", min=0.0))
22
+ self.add_parameter(Parameter_float("convergence_DT", 0.01, "°C", min=0.0))
23
+ self.add_parameter(Parameter_float("convergence_Dw", 0.01, "g/kg", min=0.0))
24
+
25
+ # Variables
26
+ self.add_variable(Variable("temperature", unit="°C"))
27
+ self.add_variable(Variable("abs_humidity", unit="g/kg"))
28
+ self.add_variable(Variable("rel_humidity", unit="%"))
29
+ self.add_variable(Variable("people_convective", unit="W"))
30
+ self.add_variable(Variable("people_radiant", unit="W"))
31
+ self.add_variable(Variable("people_latent", unit="W"))
32
+ self.add_variable(Variable("light_convective", unit="W"))
33
+ self.add_variable(Variable("light_radiant", unit="W"))
34
+ self.add_variable(Variable("other_gains_convective", unit="W"))
35
+ self.add_variable(Variable("other_gains_radiant", unit="W"))
36
+ self.add_variable(Variable("other_gains_latent", unit="W"))
37
+ self.add_variable(Variable("solar_direct_gains", unit="W"))
38
+ self.add_variable(Variable("infiltration_flow", unit="m³/s"))
39
+ self.add_variable(Variable("surfaces_convective", unit="W"))
40
+ self.add_variable(Variable("delta_int_energy", unit="W"))
41
+ self.add_variable(Variable("infiltration_sensible_heat", unit="W"))
42
+ self.add_variable(Variable("infiltration_latent_heat", unit="W"))
43
+ self.add_variable(Variable("system_sensible_heat", unit="W"))
44
+ self.add_variable(Variable("system_latent_heat", unit="W"))
45
+ self.add_variable(Variable("u_system_sensible_heat", unit="W"))
46
+ self.add_variable(Variable("u_system_latent_heat", unit="W"))
47
+
48
+ def get_building(self):
49
+ return self.parameter("building").component
50
+
51
+ def check(self):
52
+ errors = super().check()
53
+ # Test building is defined
54
+ if self.parameter("building").value == "not_defined":
55
+ msg = f"{self.parameter('name').value}, must define its building."
56
+ errors.append(Message(msg, "ERROR"))
57
+ # Test space_type defined
58
+ if self.parameter("spaces_type").value == "not_defined":
59
+ msg = f"{self.parameter('name').value}, must define its Space_type."
60
+ errors.append(Message(msg, "ERROR"))
61
+ self._create_surfaces_list()
62
+ return errors
63
+
64
+ def pre_simulation(self, n_time_steps, delta_t):
65
+ super().pre_simulation(n_time_steps, delta_t)
66
+ sicro.SetUnitSystem(sicro.SI)
67
+ self._file_met = self.project().parameter("simulation_file_met").component
68
+ self.props = self._sim_.props
69
+ self._space_type_comp = self.parameter("spaces_type").component
70
+ self._area = self.parameter("floor_area").value
71
+ self._volume = self.parameter("volume").value
72
+ self._m_furniture = self._area * self.parameter("furniture_weight").value
73
+ self._Dt = self.project().parameter("time_step").value
74
+ self._create_surfaces_list() # surfaces, sides
75
+ self._create_ff_matrix() # ff_matrix
76
+ self._create_dist_vectors() # dsr_dist_vector, ig_dist_vector
77
+ self.uncontrol_systems = []
78
+ self.control_system = {"M_a": 0, "T_a": 0, "w_a":0, "Q_s": 0, "M_w": 0} # M_a (kg/s), T_a (°C), w_a (g/kg), Q_s (W), M_w (g H2O/s)
79
+
80
+ def _create_surfaces_list(self):
81
+ self.surfaces = []
82
+ self.sides = []
83
+ # Exterior
84
+ surfaces_list = self.project().component_list("Building_surface")
85
+ for surface in surfaces_list:
86
+ surface_type = surface.parameter("surface_type").value
87
+ if surface_type == "EXTERIOR" :
88
+ if surface.get_space() == self:
89
+ self.surfaces.append(surface)
90
+ self.sides.append(1)
91
+ for opening in surface.openings:
92
+ self.surfaces.append(opening)
93
+ self.sides.append(1)
94
+ elif surface_type == "UNDERGROUND":
95
+ if surface.get_space() == self:
96
+ self.surfaces.append(surface)
97
+ self.sides.append(1)
98
+ elif surface_type == "INTERIOR":
99
+ if surface.get_space(0) == self:
100
+ self.surfaces.append(surface)
101
+ self.sides.append(0)
102
+ for opening in surface.openings:
103
+ self.surfaces.append(opening)
104
+ self.sides.append(0)
105
+ elif surface.get_space(1) == self:
106
+ self.surfaces.append(surface)
107
+ self.sides.append(1)
108
+ for opening in surface.openings:
109
+ self.surfaces.append(opening)
110
+ self.sides.append(1)
111
+ elif surface_type == "VIRTUAL":
112
+ if surface.get_space(0) == self:
113
+ self.surfaces.append(surface)
114
+ self.sides.append(0)
115
+ elif surface.get_space(1) == self:
116
+ self.surfaces.append(surface)
117
+ self.sides.append(1)
118
+
119
+ def _coplanar(self, surf1, side1, surf2, side2):
120
+ az_1 = surf1.orientation_angle("azimuth", side1)
121
+ az_2 = surf2.orientation_angle("azimuth", side2)
122
+ alt_1 = surf1.orientation_angle("altitude", side1)
123
+ alt_2 = surf2.orientation_angle("altitude", side2)
124
+ if alt_1 == 90 and alt_2 == 90: # Two Floors
125
+ return True
126
+ elif alt_1 == -90 and alt_2 == -90: # Two Roofs
127
+ return True
128
+ else:
129
+ if alt_1 == alt_2 and az_1 == az_2:
130
+ return True
131
+ else:
132
+ return False
133
+
134
+ def _create_ff_matrix(self):
135
+ n = len(self.surfaces)
136
+ total_area = 0
137
+ for surf in self.surfaces:
138
+ total_area += surf.area
139
+ self.ff_matrix = np.zeros((n, n))
140
+ seven = np.zeros((n, n))
141
+ for i in range(n):
142
+ for j in range(n):
143
+ if self._coplanar(self.surfaces[i], self.sides[i], self.surfaces[j], self.sides[j]):
144
+ seven[i][j] = 0
145
+ else:
146
+ seven[i][j] = 1
147
+ self.ff_matrix[i][j] = seven[i][j] * \
148
+ self.surfaces[j].area / total_area
149
+ # iteración
150
+ EPSILON = 1.e-4
151
+ N_MAX_ITER = 500
152
+ n_iter = 0
153
+ residuos = np.ones(n)
154
+ while True:
155
+ n_iter += 1
156
+ residuo_tot = 0
157
+ corregir = False
158
+ for i in range(n):
159
+ residuos[i] = 1.
160
+ for j in range(n):
161
+ residuos[i] -= self.ff_matrix[i][j]
162
+ if (residuos[i] == 0):
163
+ residuos[i] = EPSILON/100
164
+ if (math.fabs(residuos[i]) > EPSILON):
165
+ corregir = True
166
+ residuo_tot += math.fabs(residuos[i])
167
+ if corregir:
168
+ for i in range(n):
169
+ for j in range(n):
170
+ self.ff_matrix[i][j] *= 1 + residuos[i]*residuos[j] * \
171
+ seven[i][j] / (math.fabs(residuos[i]) +
172
+ math.fabs(residuos[j]))
173
+ else:
174
+ break
175
+ if (n_iter > N_MAX_ITER):
176
+ break
177
+
178
+ def _create_dist_vectors(self): # W/m^2 for each surface
179
+ n = len(self.surfaces)
180
+ total_area = 0
181
+ floor_area = 0
182
+ for i in range(n):
183
+ total_area += self.surfaces[i].area
184
+ # Floor
185
+ if self.surfaces[i].orientation_angle("altitude", self.sides[i]) == 90:
186
+ floor_area += self.surfaces[i].area
187
+ self.dsr_dist_vector = np.zeros(n)
188
+ self.ig_dist_vector = np.zeros(n)
189
+ for i in range(n):
190
+ if floor_area > 0:
191
+ # Floor
192
+ if self.surfaces[i].orientation_angle("altitude", self.sides[i]) == 90:
193
+ self.dsr_dist_vector[i] = 1/floor_area
194
+ else:
195
+ 0
196
+ else:
197
+ self.dsr_dist_vector[i] = 1/total_area
198
+ self.ig_dist_vector[i] = 1/total_area
199
+
200
+ def pre_iteration(self, time_index, date, daylight_saving):
201
+ super().pre_iteration(time_index, date, daylight_saving)
202
+ #self._first_iteration = True
203
+ # People
204
+ exp = self._space_type_comp.variable("people_convective").values[time_index]
205
+ self.variable("people_convective").values[time_index] = self._area * exp
206
+ exp = self._space_type_comp.variable("people_latent").values[time_index]
207
+ self.variable("people_latent").values[time_index] = self._area * exp
208
+ exp = self._space_type_comp.variable("people_radiant").values[time_index]
209
+ self.variable("people_radiant").values[time_index] = self._area * exp
210
+ # Light
211
+ exp = self._space_type_comp.variable("light_convective").values[time_index]
212
+ self.variable("light_convective").values[time_index] = self._area * exp
213
+ exp = self._space_type_comp.variable("light_radiant").values[time_index]
214
+ self.variable("light_radiant").values[time_index] = self._area * exp
215
+ # Other gains
216
+ exp = self._space_type_comp.variable("other_gains_convective").values[time_index]
217
+ self.variable("other_gains_convective").values[time_index] = self._area * exp
218
+ exp = self._space_type_comp.variable("other_gains_latent").values[time_index]
219
+ self.variable("other_gains_latent").values[time_index] = self._area * exp
220
+ exp = self._space_type_comp.variable("other_gains_radiant").values[time_index]
221
+ self.variable("other_gains_radiant").values[time_index] = self._area * exp
222
+ # Infiltration
223
+ exp = self._space_type_comp.variable("infiltration_rate").values[time_index]
224
+ V_inf = self._volume * exp / 3600
225
+ self.variable("infiltration_flow").values[time_index] = V_inf
226
+ # Usar inicialmente el mismo sistema del instante anterior
227
+ # Systems air flows
228
+ self.uncontrol_systems = []
229
+ self.control_system = {"M_a": 0, "T_a": 0, "w_a":0, "Q_s": 0, "M_w": 0}
230
+ # Initial values
231
+ self._estimate_T_w(time_index)
232
+ # Iterative Process
233
+ self.itera_T = Iterative_process(self._T,tol=self.parameter("convergence_DT").value,n_ini_relax=3,rel_vel=0.8)
234
+ self.itera_w = Iterative_process(self._w,tol=self.parameter("convergence_Dw").value,n_ini_relax=3,rel_vel=0.8)
235
+
236
+ # Humidity balance
237
+ self._K_hum = self.props["RHO_A"] * (self._volume / self._Dt + V_inf)
238
+ self._F_hum = (self.variable("people_latent").values[time_index] + self.variable("other_gains_latent").values[time_index])/self.props["LAMBDA"]
239
+ self._F_hum += self.props["RHO_A"] * self._volume / self._Dt * self._w_pre + self.props["RHO_A"] * V_inf * self._file_met.variable("abs_humidity").values[time_index]
240
+
241
+
242
+ def _estimate_T_w(self, time_i):
243
+ if time_i == 0:
244
+ self._T_pre = self.get_building().parameter("initial_temperature").value
245
+ self._w_pre = self.get_building().parameter("initial_humidity").value
246
+ else:
247
+ self._T_pre = self.variable("temperature").values[time_i-1]
248
+ self._w_pre = self.variable("abs_humidity").values[time_i-1]
249
+ self.variable("temperature").values[time_i] = self._T_pre
250
+ self.variable("abs_humidity").values[time_i] = self._w_pre
251
+ self._T = self._T_pre
252
+ self._w = self._w_pre
253
+
254
+ def iteration(self, time_index, date, daylight_saving, n_iter):
255
+ super().iteration(time_index, date, daylight_saving, n_iter)
256
+
257
+ # Calculate temperature
258
+ K_tot,F_tot = self.get_thermal_equation(True)
259
+ T = F_tot/K_tot
260
+ self.variable("temperature").values[time_index] = self.itera_T.estimate_next_x(T)
261
+
262
+ # Calculate humidity
263
+ K_hum, F_hum = self.get_humidity_equation(True)
264
+ w = F_hum/K_hum
265
+ if (w < 0):
266
+ w = 0
267
+ if (T< 100): # Sicro limits
268
+ max_hum = sicro.GetHumRatioFromRelHum(T, 1, self.props["ATM_PRESSURE"])*1000
269
+ if (w > max_hum):
270
+ w = max_hum
271
+
272
+ self.variable("abs_humidity").values[time_index] = self.itera_w.estimate_next_x(w)
273
+
274
+ # Test convergence
275
+ converged = self.itera_T.converged() and self.itera_w.converged()
276
+ return converged
277
+
278
+ def calculate_solar_direct(self, time_i):
279
+ solar_gain = 0
280
+ for surf in self.surfaces:
281
+ if surf.parameter("type").value == "Opening":
282
+ if surf.is_exterior():
283
+ solar_gain += surf.area * surf.variable("E_dir_tra").values[time_i]
284
+ self.variable("solar_direct_gains").values[time_i] = solar_gain
285
+
286
+ def update_K_F(self, K_F):
287
+ self.K_F = K_F
288
+
289
+ def _acumulate_u_systems(self):
290
+ self._M_a_u_systems = 0
291
+ self._M_T_a_u_systems = 0
292
+ self._M_w_a_u_systems = 0
293
+ self._Q_s_u_systems = 0
294
+ self._M_w_u_systems = 0
295
+ for system in self.uncontrol_systems:
296
+ self._M_a_u_systems += system["M_a"]
297
+ self._M_T_a_u_systems += system["M_a"]*system["T_a"]
298
+ self._M_w_a_u_systems += system["M_a"]*system["w_a"]
299
+ self._Q_s_u_systems += system["Q_s"]
300
+ self._M_w_u_systems += system["M_w"]
301
+
302
+ def get_thermal_equation(self, include_control_system):
303
+ self._acumulate_u_systems()
304
+ # F_OS may be updated by the building in each iteration
305
+ F_tot = self.K_F["F"]+self.K_F["F_OS"] + self._M_T_a_u_systems * self.props["C_PA"] + self._Q_s_u_systems
306
+ K_tot = self.K_F["K"] + self._M_a_u_systems * self.props["C_PA"]
307
+ if include_control_system:
308
+ K_tot += self.control_system["M_a"] * self.props["C_PA"]
309
+ F_tot += self.control_system["M_a"] * self.props["C_PA"] * self.control_system["T_a"] + self.control_system["Q_s"]
310
+ return (K_tot, F_tot)
311
+
312
+ def get_humidity_equation(self, include_control_system):
313
+ self._acumulate_u_systems()
314
+ K_hum = self._K_hum + self._M_a_u_systems
315
+ F_hum = self._F_hum + self._M_w_a_u_systems + self._M_w_u_systems
316
+ if include_control_system:
317
+ K_hum += self.control_system["M_a"]
318
+ F_hum += self.control_system["M_a"] * self.control_system["w_a"] + self.control_system["M_w"]
319
+ return (K_hum, F_hum)
320
+
321
+ def get_Q_required(self, T_cool_sp, T_heat_sp):
322
+ K_tot, F_tot = self.get_thermal_equation(False)
323
+ T = F_tot/K_tot
324
+ if T > T_cool_sp:
325
+ return K_tot * T_cool_sp - F_tot
326
+ elif T < T_heat_sp:
327
+ return K_tot * T_heat_sp - F_tot
328
+ else:
329
+ return 0
330
+
331
+ def get_M_required(self,HR_min, HR_max):
332
+ K_hum, F_hum= self.get_humidity_equation(False)
333
+ w = F_hum/K_hum
334
+ if w < 0:
335
+ w = 0
336
+ hr = sicro.GetRelHumFromHumRatio(self._T,w/1000, self.props["ATM_PRESSURE"])*100
337
+ if hr < HR_min:
338
+ w_min = sicro.GetHumRatioFromRelHum(self._T, HR_min/100, self.props["ATM_PRESSURE"])*1000
339
+ return K_hum * w_min - F_hum
340
+ elif hr > HR_max:
341
+ w_max = sicro.GetHumRatioFromRelHum(self._T, HR_max/100, self.props["ATM_PRESSURE"])*1000
342
+ return K_hum * w_max - F_hum
343
+ else:
344
+ return 0
345
+
346
+ def add_uncontrol_system(self,system_dic):
347
+ # Delete if exist
348
+ self.uncontrol_systems = [air for air in self.uncontrol_systems if air['name'] != system_dic["name"] ]
349
+ # Append
350
+ self.uncontrol_systems.append(system_dic)
351
+
352
+ def set_control_system(self,system_dic):
353
+ self.control_system = system_dic
354
+
355
+ def post_iteration(self, time_index, date, daylight_saving, converged):
356
+ super().post_iteration(time_index, date, daylight_saving, converged)
357
+ if (self._T < 100): # Sicro limit
358
+ rh = sicro.GetRelHumFromHumRatio(self._T, self._w/1000, self.props["ATM_PRESSURE"])*100
359
+ self.variable("rel_humidity").values[time_index] = rh
360
+ self._calculate_heat_fluxes(time_index)
361
+
362
+ def _calculate_heat_fluxes(self, time_i):
363
+ V_inf = self.variable("infiltration_flow").values[time_i]
364
+ T_ext = self._file_met.variable("temperature").values[time_i]
365
+ w_ext = self._file_met.variable("abs_humidity").values[time_i]
366
+
367
+ # Sensibles
368
+ self.variable("delta_int_energy").values[time_i] = ( self._volume * self.props["RHO_A"] * self.props["C_PA"] + self._m_furniture * self.props["C_P_FURNITURE"]) * (self._T - self._T_pre) / self._Dt
369
+ self.variable("infiltration_sensible_heat").values[time_i] = V_inf * self.props["RHO_A"] * self.props["C_PA"] * (T_ext - self._T)
370
+ self.variable("u_system_sensible_heat").values[time_i] = self.props["C_PA"] * (self._M_T_a_u_systems - self._M_a_u_systems * self._T)
371
+ Q = self.control_system["M_a"] * self.props["C_PA"] * (self.control_system["T_a"] - self._T) + self.control_system["Q_s"]
372
+ self.variable("system_sensible_heat").values[time_i] = Q
373
+
374
+ Q_rest = self.variable("delta_int_energy").values[time_i]
375
+ - self.variable("people_convective").values[time_i]
376
+ - self.variable("light_convective").values[time_i]
377
+ - self.variable("other_gains_convective").values[time_i]
378
+ - self.variable("infiltration_sensible_heat").values[time_i]
379
+ - self.variable("u_system_sensible_heat").values[time_i]
380
+ - Q
381
+
382
+ self.variable("surfaces_convective").values[time_i] = Q_rest
383
+
384
+ # Latents
385
+ self.variable("infiltration_latent_heat").values[time_i] = V_inf * self.props["RHO_A"] * self.props["LAMBDA"] * (w_ext - self._w)
386
+ self.variable("u_system_latent_heat").values[time_i] = self.props["LAMBDA"] * (self._M_w_a_u_systems - self._M_a_u_systems * self._w)
387
+ self.variable("system_latent_heat").values[time_i] = self.control_system["M_a"] * self.props["LAMBDA"] * (self.control_system["w_a"] - self._w) + self.control_system["M_w"] * self.props["LAMBDA"]
388
+
@@ -0,0 +1,81 @@
1
+ from opensimula.Component import Component
2
+ from opensimula.Parameters import Parameter_float, Parameter_math_exp, Parameter_variable_list
3
+ from opensimula.Variable import Variable
4
+
5
+
6
+ class Space_type(Component):
7
+ def __init__(self, name, project):
8
+ Component.__init__(self, name, project)
9
+ self.parameter("type").value = "Space_type"
10
+ self.parameter(
11
+ "description").value = "Type of space, internal gains definition"
12
+ # Parameters
13
+ self.add_parameter(Parameter_variable_list("input_variables", []))
14
+ self.add_parameter(Parameter_math_exp("people_density", "0.1", "p/m²"))
15
+ self.add_parameter(Parameter_float(
16
+ "people_sensible", 70, "W/p", min=0))
17
+ self.add_parameter(Parameter_float("people_latent", 35, "W/p", min=0))
18
+ self.add_parameter(Parameter_float(
19
+ "people_radiant_fraction", 0.6, "frac", min=0, max=1))
20
+ self.add_parameter(Parameter_math_exp("light_density", "10", "W/m²"))
21
+ self.add_parameter(Parameter_float(
22
+ "light_radiant_fraction", 0.6, "frac", min=0, max=1))
23
+ self.add_parameter(Parameter_math_exp(
24
+ "other_gains_density", "10", "W/m²"))
25
+ self.add_parameter(Parameter_float(
26
+ "other_gains_latent_fraction", 0.0, "frac", min=0, max=1))
27
+ self.add_parameter(Parameter_float(
28
+ "other_gains_radiant_fraction", 0.5, "frac", min=0, max=1))
29
+ self.add_parameter(Parameter_math_exp("infiltration", "1", "1/h"))
30
+
31
+ # Variables
32
+ self.add_variable(Variable("people_convective", unit="W/m²"))
33
+ self.add_variable(Variable("people_radiant", unit="W/m²"))
34
+ self.add_variable(Variable("people_latent", unit="W/m²"))
35
+ self.add_variable(Variable("light_convective", unit="W/m²"))
36
+ self.add_variable(Variable("light_radiant", unit="W/m²"))
37
+ self.add_variable(Variable("other_gains_convective", unit="W/m²"))
38
+ self.add_variable(Variable("other_gains_radiant", unit="W/m²"))
39
+ self.add_variable(Variable("other_gains_latent", unit="W/m²"))
40
+ self.add_variable(Variable("infiltration_rate", unit="1/h"))
41
+
42
+ def pre_simulation(self, n_time_steps, delta_t):
43
+ super().pre_simulation(n_time_steps, delta_t)
44
+
45
+ def pre_iteration(self, time_index, date, daylight_saving):
46
+ super().pre_iteration(time_index, date, daylight_saving)
47
+ # variables dictonary
48
+ var_dic = self.get_parameter_variable_dictionary(time_index)
49
+
50
+ # People
51
+ people = self.parameter("people_density").evaluate(var_dic)
52
+ self.variable("people_convective").values[time_index] = (people * self.parameter(
53
+ "people_sensible").value * (1 - self.parameter("people_radiant_fraction").value))
54
+ self.variable("people_radiant").values[time_index] = (people * self.parameter(
55
+ "people_sensible").value * self.parameter("people_radiant_fraction").value)
56
+ self.variable("people_latent").values[time_index] = (
57
+ people * self.parameter("people_latent").value)
58
+
59
+ # Light
60
+ light = self.parameter("light_density").evaluate(var_dic)
61
+ self.variable("light_convective").values[time_index] = light * (
62
+ 1 - self.parameter("light_radiant_fraction").value)
63
+ self.variable("light_radiant").values[time_index] = light * \
64
+ self.parameter("light_radiant_fraction").value
65
+
66
+ # Other gains
67
+ other = self.parameter("other_gains_density").evaluate(var_dic)
68
+ self.variable("other_gains_convective").values[time_index] = other * (1 - self.parameter(
69
+ "other_gains_latent_fraction").value) * (1 - self.parameter("other_gains_radiant_fraction").value)
70
+
71
+ self.variable("other_gains_radiant").values[time_index] = other * (1 - self.parameter(
72
+ "other_gains_latent_fraction").value) * self.parameter("other_gains_radiant_fraction").value
73
+
74
+ self.variable("other_gains_latent").values[time_index] = other * self.parameter(
75
+ "other_gains_latent_fraction").value
76
+
77
+ # Infiltration
78
+ self.variable("infiltration_rate").values[time_index] = self.parameter(
79
+ "infiltration").evaluate(var_dic)
80
+
81
+