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,137 @@
1
+ from opensimula.Message import Message
2
+ from opensimula.Parameters import Parameter_component, Parameter_float, Parameter_variable_list, Parameter_math_exp
3
+ from opensimula.Component import Component
4
+ from opensimula.Variable import Variable
5
+ import psychrolib as sicro
6
+
7
+
8
+ class HVAC_perfect_system(Component):
9
+ def __init__(self, name, project):
10
+ Component.__init__(self, name, project)
11
+ self.parameter("type").value = "HVAC_perfect_system"
12
+ self.parameter("description").value = "HVAC Perfect system for cooling and heating load"
13
+ self.add_parameter(Parameter_component("spaces", "not_defined", ["Space"]))
14
+ self.add_parameter(Parameter_variable_list("input_variables", []))
15
+ self.add_parameter(Parameter_math_exp("outdoor_air_flow", "0", "m³/s"))
16
+ self.add_parameter(Parameter_math_exp("heating_setpoint", "20", "°C"))
17
+ self.add_parameter(Parameter_math_exp("cooling_setpoint", "25", "°C"))
18
+ self.add_parameter(Parameter_math_exp("humidifying_setpoint", "0", "%"))
19
+ self.add_parameter(Parameter_math_exp("dehumidifying_setpoint", "100", "%"))
20
+ self.add_parameter(Parameter_math_exp("system_on_off", "1", "on/off"))
21
+ # Variables
22
+ self.add_variable(Variable("Q_total", unit="W"))
23
+ self.add_variable(Variable("Q_sensible", unit="W"))
24
+ self.add_variable(Variable("Q_latent", unit="W"))
25
+ self.add_variable(Variable("outdoor_air_flow", unit="m³/s"))
26
+ self.add_variable(Variable("heating_setpoint", unit="°C"))
27
+ self.add_variable(Variable("cooling_setpoint", unit="°C"))
28
+ self.add_variable(Variable("humidifying_setpoint", unit="%"))
29
+ self.add_variable(Variable("dehumidifying_setpoint", unit="%"))
30
+ self.add_variable(Variable("state", unit="flag")) # 0: 0ff, 1: Heating, -1: Cooling, 3: Venting
31
+
32
+ def check(self):
33
+ errors = super().check()
34
+ # Test space defined
35
+ if self.parameter("spaces").value == "not_defined":
36
+ msg =f"{self.parameter('name').value}, must define its space."
37
+ errors.append(Message(msg, "ERROR"))
38
+ # Test file_met defined
39
+ if self.project().parameter("simulation_file_met").value == "not_defined":
40
+ msg = f"{self.parameter('name').value}, file_met must be defined in the project 'simulation_file_met'."
41
+ errors.append(Message(msg, "ERROR"))
42
+ return errors
43
+
44
+ def pre_simulation(self, n_time_steps, delta_t):
45
+ super().pre_simulation(n_time_steps, delta_t)
46
+ self._space = self.parameter("spaces").component
47
+ self._file_met = self.project().parameter("simulation_file_met").component
48
+ self.props = self._sim_.props
49
+
50
+ def pre_iteration(self, time_index, date, daylight_saving):
51
+ super().pre_iteration(time_index, date, daylight_saving)
52
+ # variables dictonary
53
+ var_dic = self.get_parameter_variable_dictionary(time_index)
54
+
55
+ # outdoor air flow
56
+ self._outdoor_air_flow = self.parameter("outdoor_air_flow").evaluate(var_dic)
57
+ self.variable("outdoor_air_flow").values[time_index] = self._outdoor_air_flow
58
+ # setpoints
59
+ self.variable("heating_setpoint").values[time_index] = self.parameter("heating_setpoint").evaluate(var_dic)
60
+ self.variable("cooling_setpoint").values[time_index] = self.parameter("cooling_setpoint").evaluate(var_dic)
61
+ self.variable("humidifying_setpoint").values[time_index] = self.parameter("humidifying_setpoint").evaluate(var_dic)
62
+ self.variable("dehumidifying_setpoint").values[time_index] = self.parameter("dehumidifying_setpoint").evaluate(var_dic)
63
+ # on/off
64
+ self._on_off = self.parameter("system_on_off").evaluate(var_dic)
65
+ if self._on_off == 0:
66
+ self.variable("state").values[time_index] = 0
67
+ self._on_off = False
68
+ else:
69
+ self._on_off = True
70
+
71
+ self._T_odb = self._file_met.variable("temperature").values[time_index]
72
+ self._w_o = self._file_met.variable("abs_humidity").values[time_index]
73
+ self._outdoor_rho = 1/sicro.GetMoistAirVolume(self._T_odb,self._w_o/1000,self.props["ATM_PRESSURE"])
74
+ self._T_cool_sp = self.variable("cooling_setpoint").values[time_index]
75
+ self._T_heat_sp = self.variable("heating_setpoint").values[time_index]
76
+ self._HR_min = self.variable("humidifying_setpoint").values[time_index]
77
+ self._HR_max = self.variable("dehumidifying_setpoint").values[time_index]
78
+
79
+ def iteration(self, time_index, date, daylight_saving, n_iter):
80
+ super().iteration(time_index, date, daylight_saving, n_iter)
81
+ self._control_system = {"M_a": 0, "T_a": 0, "w_a":0, "Q_s":0, "M_w":0 }
82
+ if self._on_off:
83
+ self._calculate_required_Q()
84
+ self._calculate_required_M()
85
+ self._control_system["Q_s"] = self._Q_spa
86
+ self._control_system["M_w"] = self._M_spa
87
+ self._space.set_control_system(self._control_system)
88
+ return True
89
+
90
+ def _calculate_required_Q(self):
91
+ K_t,F_t = self._space.get_thermal_equation(False)
92
+ K_ts = K_t + self._outdoor_air_flow * self._outdoor_rho * self.props["C_PA"]
93
+ F_ts = F_t + self._outdoor_air_flow * self._outdoor_rho * self.props["C_PA"] * self._T_odb
94
+ self._T_space = F_ts/K_ts
95
+ if self._T_space > self._T_cool_sp:
96
+ self._T_space = self._T_cool_sp
97
+ self._Q_sys = K_ts * self._T_space - F_ts
98
+ elif self._T_space < self._T_heat_sp:
99
+ self._T_space = self._T_heat_sp
100
+ self._Q_sys = K_ts * self._T_space - F_ts
101
+ else:
102
+ self._Q_sys = 0
103
+ self._Q_spa = K_t * self._T_space - F_t
104
+
105
+ def _calculate_required_M(self):
106
+ K_h,F_h = self._space.get_humidity_equation(False)
107
+ K_hs = K_h + self._outdoor_air_flow * self._outdoor_rho
108
+ F_hs = F_h + self._outdoor_air_flow * self._outdoor_rho * self._w_o
109
+ self._w_space = F_hs/K_hs
110
+ if self._w_space < 0:
111
+ self._w_space = 0
112
+ hr_space = sicro.GetRelHumFromHumRatio(self._T_space, self._w_space/1000, self.props["ATM_PRESSURE"])*100
113
+ if hr_space < self._HR_min:
114
+ self._w_space = sicro.GetHumRatioFromRelHum(self._T_space, self._HR_min/100, self.props["ATM_PRESSURE"])*1000
115
+ self._M_sys = K_hs * self._w_space - F_hs
116
+ elif hr_space > self._HR_max:
117
+ self._w_space = sicro.GetHumRatioFromRelHum(self._T_space, self._HR_max/100, self.props["ATM_PRESSURE"])*1000
118
+ self._M_sys = K_hs * self._w_space - F_hs
119
+ else:
120
+ self._M_sys = 0
121
+ self._M_spa = K_h * self._w_space - F_h
122
+
123
+
124
+ def post_iteration(self, time_index, date, daylight_saving, converged):
125
+ super().post_iteration(time_index, date, daylight_saving, converged)
126
+ if self._on_off:
127
+ self.variable("Q_sensible").values[time_index] = self._Q_sys
128
+ self.variable("Q_latent").values[time_index] = self._M_sys * self.props["LAMBDA"]
129
+ self.variable("Q_total").values[time_index] = self._Q_sys + self._M_sys * self.props["LAMBDA"]
130
+ if self._Q_sys > 0: # Heating, Cooling or Venting
131
+ self.variable("state").values[time_index] = 1
132
+ elif self._Q_sys < 0:
133
+ self.variable("state").values[time_index] = -1
134
+ else:
135
+ self.variable("state").values[time_index] = 3
136
+
137
+
@@ -0,0 +1,14 @@
1
+ from opensimula.Parameters import Parameter_boolean, Parameter_float
2
+ from opensimula.Component import Component
3
+
4
+
5
+ class Material(Component):
6
+ def __init__(self, name, project):
7
+ Component.__init__(self, name, project)
8
+ self.parameter("type").value = "Material"
9
+ self.parameter("description").value = "Material layer properties"
10
+ self.add_parameter(Parameter_float("conductivity", 1, "W/(m·K)", min=0))
11
+ self.add_parameter(Parameter_float("density", 1000, "kg/m³", min=0.001))
12
+ self.add_parameter(Parameter_float("specific_heat", 1000, "J/(kg·K)", min=0.001))
13
+ self.add_parameter(Parameter_boolean("use_resistance", False))
14
+ self.add_parameter(Parameter_float("thermal_resistance", 1, "(m²·K)/W", min=0))
@@ -0,0 +1,409 @@
1
+ import math
2
+ from opensimula.Component import Component
3
+ from opensimula.Message import Message
4
+ from opensimula.Parameters import (
5
+ Parameter_component,
6
+ Parameter_float,
7
+ Parameter_float_list,
8
+ Parameter_options,
9
+ )
10
+ from opensimula.Variable import Variable
11
+ from shapely.geometry import Polygon
12
+ from opensimula.visual_3D.Polygon_3D import Polygon_3D
13
+
14
+
15
+ class Opening(Component):
16
+ def __init__(self, name, project):
17
+ Component.__init__(self, name, project)
18
+ # Parameters
19
+ self.parameter("type").value = "Opening"
20
+ self.parameter("description").value = (
21
+ "Openings (windows/doors) in building surfaces"
22
+ )
23
+ self.add_parameter(
24
+ Parameter_component("surface", "not_defined", ["Building_surface"])
25
+ )
26
+ self.add_parameter(
27
+ Parameter_component("opening_type", "not_defined", ["Opening_type"])
28
+ )
29
+ self.add_parameter(
30
+ Parameter_options("shape", "RECTANGLE", ["RECTANGLE", "POLYGON"])
31
+ )
32
+ self.add_parameter(Parameter_float_list("ref_point", [0, 0], "m"))
33
+ self.add_parameter(Parameter_float("width", 1, "m", min=0.0))
34
+ self.add_parameter(Parameter_float("height", 1, "m", min=0.0))
35
+ self.add_parameter(
36
+ Parameter_float_list("x_polygon", [0, 10, 10, 0], "m", min=float("-inf"))
37
+ )
38
+ self.add_parameter(
39
+ Parameter_float_list("y_polygon", [0, 0, 10, 10], "m", min=float("-inf"))
40
+ )
41
+ self.add_parameter(
42
+ Parameter_float("setback", 0, "m", min=0.0)
43
+ ) # Only for rectangular openings
44
+ self.add_parameter(Parameter_float_list("h_cv", [19.3, 2], "W/m²K", min=0))
45
+
46
+ self.H_RD = 5.705 # 4*sigma*(293^3)
47
+ # Variables
48
+ self.add_variable(Variable("T_s0", "°C"))
49
+ self.add_variable(Variable("T_s1", "°C"))
50
+ self.add_variable(Variable("T_rm", "°C"))
51
+ self.add_variable(Variable("E_dir_sunny", "W/m²"))
52
+ self.add_variable(Variable("E_dir", "W/m²"))
53
+ self.add_variable(Variable("E_dif_sunny", "W/m²"))
54
+ self.add_variable(Variable("E_dif", "W/m²"))
55
+ self.add_variable(Variable("E_dir_tra", "W/m²"))
56
+ self.add_variable(Variable("E_dif_tra", "W/m²"))
57
+ self.add_variable(Variable("theta_sun", "°"))
58
+ self.add_variable(Variable("E_ref", "W/m²"))
59
+ self.add_variable(Variable("E_ref_tra", "W/m²"))
60
+ self.add_variable(Variable("q_cv0", "W/m²"))
61
+ self.add_variable(Variable("q_cv1", "W/m²"))
62
+ self.add_variable(Variable("q_cd", "W/m²"))
63
+ self.add_variable(Variable("q_sol0", "W/m²"))
64
+ self.add_variable(Variable("q_sol1", "W/m²"))
65
+ self.add_variable(Variable("q_swig0", "W/m²"))
66
+ self.add_variable(Variable("q_swig1", "W/m²"))
67
+ self.add_variable(Variable("q_lwig0", "W/m²"))
68
+ self.add_variable(Variable("q_lwig1", "W/m²"))
69
+ self.add_variable(Variable("q_lwt0", "W/m²"))
70
+ self.add_variable(Variable("q_lwt1", "W/m²"))
71
+ self.add_variable(Variable("debug_f", ""))
72
+
73
+ def check(self):
74
+ errors = super().check()
75
+ # Test surface
76
+ if self.parameter("surface").value == "not_defined":
77
+ msg = f"{self.parameter('name').value}, its surface must be defined."
78
+ errors.append(Message(msg, "ERROR"))
79
+ # TODO: Test surface_type EXTERIOR or INTERIOR
80
+ # Test opening_type defined
81
+ if self.parameter("opening_type").value == "not_defined":
82
+ msg = (
83
+ f"{self.parameter('name').value}, opening must define its Opening_type."
84
+ )
85
+ errors.append(Message(msg, "ERROR"))
86
+ # Test if Polygon shape that x_polygon and y_polygon has the same size
87
+ if self.parameter("shape").value == "POLYGON":
88
+ if len(self.parameter("x_polygon").value) != len(
89
+ self.parameter("y_polygon").value
90
+ ):
91
+ msg = f"{self.parameter('name').value}, x_polygo and y_polygon must have the same size."
92
+ errors.append(Message(msg, "ERROR"))
93
+ return errors
94
+
95
+ def get_building(self):
96
+ return self.get_surface().get_building()
97
+
98
+ def get_space(self, side=0):
99
+ return self.get_surface().get_space(side)
100
+
101
+ def get_surface(self):
102
+ return self.parameter("surface").component
103
+
104
+ def is_exterior(self):
105
+ return (self.get_surface().parameter("surface_type").value == "EXTERIOR")
106
+
107
+ # _______ pre_simulation _______
108
+ def pre_simulation(self, n_time_steps, delta_t):
109
+ super().pre_simulation(n_time_steps, delta_t)
110
+ self._file_met = self.project().parameter("simulation_file_met").component
111
+ self._calculate_K_()
112
+ self.f_dif_setback = self._f_diffuse_setback_()
113
+ if self.is_exterior():
114
+ self._sunny_index = self.project().env_3D.get_sunny_index(
115
+ self.parameter("name").value
116
+ )
117
+ else:
118
+ self._sunny_index = None
119
+
120
+ def _calculate_K_(self):
121
+ self.k = [0, 0]
122
+ self.k[0] = self.area * (
123
+ -self.parameter("h_cv").value[0]
124
+ - self.H_RD * self.radiant_property("alpha", "long_wave", 0)
125
+ - 1 / self.parameter("opening_type").component.thermal_resistance()
126
+ )
127
+ self.k[1] = self.area * (
128
+ -1 / self.parameter("opening_type").component.thermal_resistance()
129
+ - self.parameter("h_cv").value[1]
130
+ )
131
+ self.k_01 = (
132
+ self.area / self.parameter("opening_type").component.thermal_resistance()
133
+ )
134
+
135
+ def _f_diffuse_setback_(self):
136
+ if (
137
+ self.parameter("shape").value == "POLYGON"
138
+ or self.parameter("setback").value == 0
139
+ ):
140
+ return 1
141
+ else:
142
+ X = self.parameter("width").value / self.parameter("setback").value
143
+ Y = self.parameter("height").value / self.parameter("setback").value
144
+ F = (
145
+ 2
146
+ / (math.pi * X * Y)
147
+ * (
148
+ math.log(((1 + X**2) * (1 + Y**2) / (1 + X**2 + Y**2)) ** 0.5)
149
+ + X * ((1 + Y**2) ** 0.5) * math.atan(X / ((1 + Y**2) ** 0.5))
150
+ + Y * ((1 + X**2)) ** 0.5 * math.atan(Y / ((1 + X**2)) ** 0.5)
151
+ - X * math.atan(X)
152
+ - Y * math.atan(Y)
153
+ )
154
+ )
155
+ return 1 - F
156
+
157
+ # _______ pre_iteration _______
158
+ def pre_iteration(self, time_index, date, daylight_saving):
159
+ super().pre_iteration(time_index, date, daylight_saving)
160
+ if self.is_exterior():
161
+ self._calculate_exterior_variables_pre_iteration_(time_index)
162
+
163
+ def _calculate_exterior_variables_pre_iteration_(self, time_i):
164
+ self._T_ext = self._file_met.variable("temperature").values[time_i]
165
+ # Solar radiation from the surface where the opening is located
166
+ surface = self.get_surface()
167
+ # Diffuse solar radiation
168
+ E_dif_sunny = surface.variable("E_dif_sunny").values[time_i]
169
+ self.variable("E_dif_sunny").values[time_i] = E_dif_sunny
170
+ diffuse_sunny_fraction = self.project().env_3D.get_diffuse_sunny_fraction(
171
+ self._sunny_index
172
+ )
173
+ E_dif = E_dif_sunny * diffuse_sunny_fraction
174
+ self.variable("E_dif").values[time_i] = E_dif
175
+
176
+ # Direct solar radiation
177
+ E_dir_sunny = surface.variable("E_dir_sunny").values[time_i]
178
+ self.variable("E_dir_sunny").values[time_i] = E_dir_sunny
179
+ # Setback shadow
180
+ theta = self._file_met.solar_surface_angle(
181
+ time_i,
182
+ surface.orientation_angle("azimuth", 0),
183
+ surface.orientation_angle("altitude", 0),
184
+ )
185
+ self.variable("theta_sun").values[time_i] = theta
186
+ if (
187
+ theta is not None
188
+ and self.parameter("shape").value == "RECTANGLE"
189
+ and self.parameter("setback").value > 0
190
+ ):
191
+ f_setback = self._f_setback_(
192
+ time_i,
193
+ surface.orientation_angle("azimuth", 0),
194
+ surface.orientation_angle("altitude", 0),
195
+ )
196
+ else:
197
+ f_setback = 1
198
+ E_dir = E_dir_sunny * self._calculate_direct_sunny_fraction_(time_i) * f_setback
199
+ self.variable("E_dir").values[time_i] = E_dir
200
+
201
+ q_sol0 = self.radiant_property("alpha", "solar_diffuse", 0) * E_dif
202
+ q_sol1 = self.radiant_property("alpha_other_side", "solar_diffuse", 0) * E_dif
203
+ E_dif_tra = self.radiant_property("tau", "solar_diffuse", 0) * E_dif
204
+ if theta is not None:
205
+ q_sol0 += self.radiant_property("alpha", "solar_direct", 0, theta) * E_dir
206
+ q_sol1 += (
207
+ self.radiant_property("alpha_other_side", "solar_direct", 0, theta)
208
+ * E_dir
209
+ )
210
+ E_dir_tra = self.radiant_property("tau", "solar_direct", 0, theta) * E_dir
211
+ else:
212
+ E_dir_tra = 0
213
+
214
+ self.variable("q_sol0").values[time_i] = q_sol0
215
+ self.variable("q_sol1").values[time_i] = q_sol1
216
+ self.variable("E_dif_tra").values[time_i] = E_dif_tra
217
+ self.variable("E_dir_tra").values[time_i] = E_dir_tra
218
+
219
+ T_rm = surface.variable("T_rm").values[time_i]
220
+ self.variable("T_rm").values[time_i] = T_rm
221
+ h_rd = self.H_RD * self.radiant_property("alpha", "long_wave", 0)
222
+ self.f_0 = self.area * (
223
+ -self.parameter("h_cv").value[0] * self._T_ext - h_rd * T_rm
224
+ )
225
+ # q_sol0 will be corrected by the building
226
+
227
+ def _calculate_direct_sunny_fraction_(self, time_i):
228
+ if self.project().parameter("shadow_calculation").value == "INSTANT":
229
+ direct_sunny_fraction = self.project().env_3D.get_direct_sunny_fraction(
230
+ self._sunny_index
231
+ )
232
+ elif self.project().parameter("shadow_calculation").value == "INTERPOLATION":
233
+ azi = self._file_met.variable("sol_azimuth").values[time_i]
234
+ alt = self._file_met.variable("sol_altitude").values[time_i]
235
+ if not math.isnan(alt):
236
+ direct_sunny_fraction = (
237
+ self.project().env_3D.get_direct_interpolated_sunny_fraction(
238
+ self._sunny_index, azi, alt
239
+ )
240
+ )
241
+ else:
242
+ direct_sunny_fraction = 1
243
+ elif self.project().parameter("shadow_calculation").value == "NO":
244
+ direct_sunny_fraction = 1
245
+ return direct_sunny_fraction
246
+
247
+ def _f_setback_(self, time_i, azimuth_sur, altitude_sur):
248
+ theta_h = math.fabs(
249
+ self._file_met.variable("sol_azimuth").values[time_i] - azimuth_sur
250
+ )
251
+ f_shadow_h = (
252
+ self.parameter("setback").value
253
+ * math.tan(math.radians(theta_h))
254
+ / self.parameter("width").value
255
+ )
256
+ if f_shadow_h > 1:
257
+ f_shadow_h = 1
258
+ theta_v = math.fabs(
259
+ self._file_met.variable("sol_altitude").values[time_i] - altitude_sur
260
+ )
261
+ f_shadow_v = (
262
+ self.parameter("setback").value
263
+ * math.tan(math.radians(theta_v))
264
+ / self.parameter("height").value
265
+ )
266
+ if f_shadow_v > 1:
267
+ f_shadow_v = 1
268
+ return (1 - f_shadow_h) * (1 - f_shadow_v)
269
+
270
+ # _______ post_iteration _______
271
+ def post_iteration(self, time_index, date, daylight_saving, converged):
272
+ super().post_iteration(time_index, date, daylight_saving, converged)
273
+ if self.is_exterior():
274
+ self._calculate_T_s0_(time_index)
275
+ self._calculate_heat_fluxes_(time_index)
276
+
277
+ def _calculate_T_s0_(self, time_i):
278
+ T_s0 = (
279
+ self.f_0
280
+ - (
281
+ self.variable("q_sol0").values[time_i]
282
+ + self.variable("q_swig0").values[time_i]
283
+ )
284
+ * self.area
285
+ - self.k_01 * self.variable("T_s1").values[time_i]
286
+ ) / self.k[0]
287
+ self.variable("T_s0").values[time_i] = T_s0
288
+
289
+ def _calculate_heat_fluxes_(self, time_i):
290
+ q_cd0 = (
291
+ self.variable("T_s1").values[time_i] - self.variable("T_s0").values[time_i]
292
+ ) / self.parameter("opening_type").component.thermal_resistance()
293
+ self.variable("q_cd").values[time_i] = q_cd0
294
+ if self.is_exterior():
295
+ self.variable("q_cv0").values[time_i] = self.parameter("h_cv").value[0] * (
296
+ self._T_ext - self.variable("T_s0").values[time_i]
297
+ )
298
+ T_z = self.get_surface().get_space().variable("temperature").values[time_i]
299
+ self.variable("q_cv1").values[time_i] = self.parameter("h_cv").value[1] * (
300
+ T_z - self.variable("T_s1").values[time_i]
301
+ )
302
+ h_rd = self.H_RD * self.radiant_property("alpha", "long_wave", 0)
303
+ self.variable("q_lwt0").values[time_i] = h_rd * (
304
+ self.variable("T_rm").values[time_i]
305
+ - self.variable("T_s0").values[time_i]
306
+ )
307
+ self.variable("q_lwt1").values[time_i] = (
308
+ +self.variable("q_cd").values[time_i]
309
+ - self.variable("q_cv1").values[time_i]
310
+ - self.variable("q_sol1").values[time_i]
311
+ - self.variable("q_swig1").values[time_i]
312
+ - self.variable("q_lwig1").values[time_i]
313
+ )
314
+ else: # interior
315
+ self.variable("q_cv0").values[time_i] = self.parameter("h_cv").value[0] * (
316
+ self.get_space(0).variable("temperature").values[time_i]
317
+ - self.variable("T_s0").values[time_i]
318
+ )
319
+ self.variable("q_cv1").values[time_i] = self.parameter("h_cv").value[1] * (
320
+ self.get_space(1).variable("temperature").values[time_i]
321
+ - self.variable("T_s1").values[time_i]
322
+ )
323
+ self.variable("q_lwt0").values[time_i] = (
324
+ -self.variable("q_cd").values[time_i]
325
+ - self.variable("q_cv0").values[time_i]
326
+ - self.variable("q_sol0").values[time_i]
327
+ - self.variable("q_swig0").values[time_i]
328
+ - self.variable("q_lwig0").values[time_i]
329
+ )
330
+ self.variable("q_lwt1").values[time_i] = (
331
+ + self.variable("q_cd").values[time_i]
332
+ - self.variable("q_cv1").values[time_i]
333
+ - self.variable("q_sol1").values[time_i]
334
+ - self.variable("q_swig1").values[time_i]
335
+ - self.variable("q_lwig1").values[time_i]
336
+ )
337
+
338
+ @property
339
+ def area(self):
340
+ if self.parameter("shape").value == "RECTANGLE":
341
+ return self.parameter("width").value * self.parameter("height").value
342
+ elif self.parameter("shape").value == "POLYGON":
343
+ polygon = []
344
+ n = len(self.parameter("x_polygon").value)
345
+ for i in range(0, n):
346
+ polygon.append(
347
+ [
348
+ self.parameter("x_polygon").value[i],
349
+ self.parameter("y_polygon").value[i],
350
+ ]
351
+ )
352
+ return Polygon(polygon).area
353
+
354
+ def radiant_property(self, prop, radiation_type, side, theta=0):
355
+ return self.parameter("opening_type").component.radiant_property(
356
+ prop, radiation_type, side, theta
357
+ )
358
+
359
+ def orientation_angle(self, angle, side, coordinate_system="global"):
360
+ return self.get_surface().orientation_angle(angle, side, coordinate_system)
361
+
362
+ def get_origin(self, coordinate_system="global"):
363
+ return self.get_surface().get_origin(coordinate_system)
364
+
365
+ def get_polygon_2D(self): # Get polygon_2D
366
+ ref = self.parameter("ref_point").value
367
+ if self.parameter("shape").value == "RECTANGLE":
368
+ w = self.parameter("width").value
369
+ h = self.parameter("height").value
370
+ return [
371
+ [ref[0], ref[1]],
372
+ [ref[0] + w, ref[1]],
373
+ [ref[0] + w, ref[1] + h],
374
+ [ref[0], ref[1] + h],
375
+ ]
376
+ elif self.parameter("shape").value == "POLYGON":
377
+ polygon2D = []
378
+ n = len(self.parameter("x_polygon").value)
379
+ for i in range(0, n):
380
+ polygon2D.append(
381
+ [
382
+ self.parameter("x_polygon").value[i] + ref[0],
383
+ self.parameter("y_polygon").value[i] + ref[1],
384
+ ]
385
+ )
386
+ return polygon2D
387
+
388
+ def get_polygon_3D(self):
389
+ azimuth = self.orientation_angle("azimuth", 0, "global")
390
+ altitude = self.orientation_angle("altitude", 0, "global")
391
+ origin = self.get_origin("global")
392
+ pol_2D = self.get_polygon_2D()
393
+ name = self.parameter("name").value
394
+ if self.is_exterior():
395
+ return Polygon_3D(
396
+ name, origin, azimuth, altitude, pol_2D, color="blue", opacity=0.6
397
+ )
398
+ else:
399
+ return Polygon_3D(
400
+ name,
401
+ origin,
402
+ azimuth,
403
+ altitude,
404
+ pol_2D,
405
+ color="blue",
406
+ opacity=0.6,
407
+ shading=False,
408
+ calculate_shadows=False,
409
+ )
@@ -0,0 +1,90 @@
1
+ from opensimula.Component import Component
2
+ from opensimula.Message import Message
3
+ from opensimula.Parameters import Parameter_float, Parameter_component
4
+
5
+
6
+ class Opening_type(Component):
7
+ def __init__(self, name, project):
8
+ Component.__init__(self, name, project)
9
+ self.parameter("type").value = "Opening_type"
10
+ self.parameter(
11
+ "description").value = "Window or doors with glazing, construction, frame and shading."
12
+
13
+ self.add_parameter(Parameter_component(
14
+ "glazing", "not_defined", "Glazing"))
15
+ self.add_parameter(Parameter_component(
16
+ "frame", "not_defined", "Frame"))
17
+ self.add_parameter(Parameter_component(
18
+ "construction", "not_defined", "Construction"))
19
+ self.add_parameter(Parameter_float(
20
+ "glazing_fraction", 0.9, "frac", min=0, max=1))
21
+ self.add_parameter(Parameter_float(
22
+ "frame_fraction", 0.1, "frac", min=0, max=1))
23
+
24
+ def check(self):
25
+ errors = super().check()
26
+ # Test glazing defined
27
+ if self.parameter("glazing").value == "not_defined" and self.parameter("glazing_fraction").value > 0:
28
+ msg = f"{self.parameter('name').value}, glazing must be defined."
29
+ errors.append(Message(msg, "ERROR"))
30
+ # Test frame defined
31
+ if self.parameter("frame").value == "not_defined" and self.parameter("frame_fraction").value > 0:
32
+ msg = f"{self.parameter('name').value}, frame must be defined."
33
+ errors.append(Message(msg, "ERROR"))
34
+ # Test construction defined
35
+ self.construction_fraction = 1 - \
36
+ self.parameter("glazing_fraction").value - \
37
+ self.parameter("frame_fraction").value
38
+ if self.parameter("construction").value == "not_defined" and self.construction_fraction > 0:
39
+ msg = f"{self.parameter('name').value}, construction must be defined."
40
+ errors.append(Message(msg, "ERROR"))
41
+ return errors
42
+
43
+ def pre_simulation(self, n_time_steps, delta_t):
44
+ super().pre_simulation(n_time_steps, delta_t)
45
+ self._calc_thermal_resistance()
46
+
47
+ def _calc_thermal_resistance(self):
48
+ f_glazing = self.parameter("glazing_fraction").value
49
+ f_frame = self.parameter("frame_fraction").value
50
+ f_construction = 1 - f_glazing - f_frame
51
+ r_glazing = 0
52
+ r_frame = 0
53
+ r_construction = 0
54
+
55
+ if (f_glazing > 0):
56
+ r_glazing = self.parameter(
57
+ "glazing").component.thermal_resistance()
58
+ if (f_frame > 0):
59
+ r_frame = self.parameter("frame").component.parameter(
60
+ "thermal_resistance").value
61
+ if (f_construction > 0):
62
+ r_construction = self.parameter(
63
+ "construction").component.thermal_resistance()
64
+
65
+ self._thermal_resistance = r_glazing*f_glazing + \
66
+ r_frame*f_frame + r_construction*f_construction
67
+
68
+ def thermal_resistance(self):
69
+ return self._thermal_resistance
70
+
71
+ def radiant_property(self, prop, radiation_type, side, theta=0):
72
+ f_glazing = self.parameter("glazing_fraction").value
73
+ f_frame = self.parameter("frame_fraction").value
74
+ f_construction = 1 - f_glazing - f_frame
75
+
76
+ value = 0
77
+ if (f_glazing > 0):
78
+ value += f_glazing * \
79
+ self.parameter("glazing").component.radiant_property(
80
+ prop, radiation_type, side, theta)
81
+ if (f_frame > 0):
82
+ value += f_frame * \
83
+ self.parameter("frame").component.radiant_property(
84
+ prop, radiation_type, side, theta)
85
+ if (f_construction > 0):
86
+ value += f_construction * \
87
+ self.parameter("construction").component.radiant_property(
88
+ prop, radiation_type, side, theta)
89
+
90
+ return value