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,318 @@
1
+ import math
2
+ from opensimula.Message import Message
3
+ from opensimula.components.Surface import Surface
4
+ from opensimula.Parameters import Parameter_component, Parameter_float_list, Parameter_options, Parameter_component_list
5
+ from opensimula.Variable import Variable
6
+ from opensimula.visual_3D.Polygon_3D import Polygon_3D
7
+
8
+
9
+ class Building_surface(Surface):
10
+ def __init__(self, name, project):
11
+ Surface.__init__(self, name, project)
12
+ # Parameters
13
+ self.parameter("type").value = "Building_surface"
14
+ self.parameter("description").value = "Building surface"
15
+ self.add_parameter(Parameter_component("construction", "not_defined", ["Construction"]))
16
+ self.add_parameter(Parameter_component_list("spaces", ["not_defined", "not_defined"], ["Space"]))
17
+ self.add_parameter(Parameter_options("surface_type", "EXTERIOR", ["EXTERIOR", "INTERIOR", "UNDERGROUND", "VIRTUAL"]))
18
+ self.add_parameter(Parameter_float_list("h_cv", [19.3, 2], "W/m²K", min=0))
19
+
20
+ # Constants
21
+ self.H_RD = 5.705 # 4*sigma*(293^3)
22
+ # Variables
23
+ self.add_variable(Variable("T_s0", "°C"))
24
+ self.add_variable(Variable("T_s1", "°C"))
25
+ self.add_variable(Variable("q_cd0", "W/m²"))
26
+ self.add_variable(Variable("q_cd1", "W/m²"))
27
+ self.add_variable(Variable("p_0", "W/m²"))
28
+ self.add_variable(Variable("p_1", "W/m²"))
29
+ self.add_variable(Variable("q_cv0", "W/m²"))
30
+ self.add_variable(Variable("q_cv1", "W/m²"))
31
+ self.add_variable(Variable("q_sol0", "W/m²"))
32
+ self.add_variable(Variable("q_sol1", "W/m²"))
33
+ self.add_variable(Variable("q_swig0", "W/m²"))
34
+ self.add_variable(Variable("q_swig1", "W/m²"))
35
+ self.add_variable(Variable("q_lwig0", "W/m²"))
36
+ self.add_variable(Variable("q_lwig1", "W/m²"))
37
+ self.add_variable(Variable("q_lwt0", "W/m²"))
38
+ self.add_variable(Variable("q_lwt1", "W/m²"))
39
+ # For exterior surface
40
+ self.add_variable(Variable("T_rm", "°C"))
41
+
42
+ # k values must be calculated by each subclass
43
+ self.k = [1.0, 2.0]
44
+ self.k_01 = -1
45
+
46
+ def check(self):
47
+ errors = super().check()
48
+ # Test space defined
49
+ surface_type = self.parameter("surface_type").value
50
+ if surface_type == "EXTERIOR" or surface_type == "UNDERGROUND":
51
+ if self.parameter("spaces").value[0] == "not_defined":
52
+ msg = f"{self.parameter('name').value}, must define its space."
53
+ errors.append(Message(msg, "ERROR"))
54
+ elif surface_type == "INTERIOR" or surface_type == "VIRTUAL":
55
+ if (
56
+ self.parameter("spaces").value[0] == "not_defined"
57
+ or self.parameter("spaces").value[1] == "not_defined"
58
+ ):
59
+ msg = f"{self.parameter('name').value}, must define two spaces."
60
+ errors.append(Message(msg, "ERROR"))
61
+ # Test construction defined for non-virtual surfaces
62
+ if surface_type != "VIRTUAL" and self.parameter("construction").value == "not_defined":
63
+ msg = f"{self.parameter('name').value}, Building surfaces must define its construction."
64
+ errors.append(Message(msg, "ERROR"))
65
+ self._surface_type_ = self.parameter("surface_type").value
66
+ if self._surface_type_ == "EXTERIOR" or self._surface_type_ == "INTERIOR":
67
+ self._create_openings_list_()
68
+ return errors
69
+
70
+ def get_building(self):
71
+ return self.parameter("spaces").component[0].get_building()
72
+
73
+ def get_space(self,side=0):
74
+ return self.parameter("spaces").component[side]
75
+
76
+ def radiant_property(self, prop, radiation_type, side, theta=0):
77
+ if self.parameter("surface_type").value == "VIRTUAL":
78
+ if prop == "tau":
79
+ return 1
80
+ else:
81
+ return 0
82
+ else:
83
+ return self.parameter("construction").component.radiant_property(prop, radiation_type, side, theta)
84
+
85
+ # ____________ pre_simulation ____________
86
+ def pre_simulation(self, n_time_steps, delta_t):
87
+ super().pre_simulation(n_time_steps, delta_t)
88
+ self._file_met = self.project().parameter("simulation_file_met").component
89
+ self._albedo = self.project().parameter("albedo").value
90
+ self._T_ini = self.get_building().parameter("initial_temperature").value
91
+ self._F_sky = (1 + math.sin(math.radians(self.parameter("altitude").value))) / 2
92
+ self._surface_type_ = self.parameter("surface_type").value
93
+ if self._surface_type_ == "EXTERIOR" or self._surface_type_ == "INTERIOR":
94
+ self._create_openings_list_()
95
+ if self._surface_type_ != "VIRTUAL":
96
+ self._calculate_K_()
97
+ if self._surface_type_ == "EXTERIOR":
98
+ self._sunny_index_ = self.project().env_3D.get_sunny_index(self.parameter("name").value)
99
+
100
+ def _create_openings_list_(self):
101
+ project_openings_list = self.project().component_list(comp_type="Opening")
102
+ self.openings = []
103
+ for opening in project_openings_list:
104
+ if opening.parameter("surface").component == self:
105
+ self.openings.append(opening)
106
+
107
+ def _calculate_K_(self):
108
+ self.a_0, self.a_1, self.a_01 = self.parameter("construction").component.get_A()
109
+ self.k_01 = self.area * self.a_01
110
+ surface_type = self.parameter("surface_type").value
111
+ if surface_type == "EXTERIOR":
112
+ self.k[0] = self.area * (self.a_0
113
+ - self.parameter("h_cv").value[0]
114
+ - self.H_RD * self.radiant_property("alpha", "long_wave", 0)
115
+ )
116
+ self.k[1] = self.area * (self.a_1 - self.parameter("h_cv").value[1])
117
+ elif surface_type == "INTERIOR":
118
+ # interior
119
+ self.k[0] = self.area * (self.a_0 - self.parameter("h_cv").value[0])
120
+ self.k[1] = self.area * (self.a_1 - self.parameter("h_cv").value[1])
121
+ elif surface_type == "UNDERGROUND":
122
+ # Underground
123
+ self.k[0] = 1 # not used
124
+ self.k[1] = self.area * (self.a_1 - self.parameter("h_cv").value[0]) # only one defined
125
+
126
+
127
+ #________ pre_iteration ____________
128
+ def pre_iteration(self, time_i, date, daylight_saving):
129
+ super().pre_iteration(time_i, date, daylight_saving)
130
+ # Meterological data
131
+ self._T_ext = self._file_met.variable("temperature").values[time_i]
132
+ if self._surface_type_ != "VIRTUAL":
133
+ # Trasient part
134
+ self._p_0_, self._p_1_ = self.parameter("construction").component.get_P(
135
+ time_i,
136
+ self.variable("T_s0").values,
137
+ self.variable("T_s1").values,
138
+ self.variable("q_cd0").values,
139
+ self.variable("q_cd1").values,
140
+ self._T_ini)
141
+ self.variable("p_0").values[time_i] = self._p_0_
142
+ self.variable("p_1").values[time_i] = self._p_1_
143
+ if self._surface_type_ == "EXTERIOR":
144
+ self._pre_iteration_exterior_(time_i)
145
+ elif self._surface_type_ == "UNDERGROUND":
146
+ self.variable("T_s0").values[time_i] = self._file_met.variable("underground_temperature").values[time_i]
147
+
148
+ def _pre_iteration_exterior_(self, time_i):
149
+ # Meterological data
150
+ hor_sol_dif = self._file_met.variable("sol_diffuse").values[time_i]
151
+ hor_sol_dir = self._file_met.variable("sol_direct").values[time_i]
152
+ T_sky = self._file_met.variable("sky_temperature").values[time_i]
153
+
154
+ # Diffuse solar radiation
155
+ E_dif_sunny = self._file_met.solar_diffuse_rad(
156
+ time_i,
157
+ self.orientation_angle("azimuth", 0),
158
+ self.orientation_angle("altitude", 0),
159
+ )
160
+ E_dif_sunny = E_dif_sunny + (1 - self._F_sky) * self._albedo * (hor_sol_dif + hor_sol_dir)
161
+ self.variable("E_dif_sunny").values[time_i] = E_dif_sunny
162
+ diffuse_sunny_fraction = self.project().env_3D.get_diffuse_sunny_fraction(self._sunny_index_)
163
+ E_dif = E_dif_sunny * diffuse_sunny_fraction
164
+ self.variable("E_dif").values[time_i] = E_dif
165
+ # Direct solar radiation
166
+ E_dir_sunny = self._file_met.solar_direct_rad(
167
+ time_i,
168
+ self.orientation_angle("azimuth", 0),
169
+ self.orientation_angle("altitude", 0),
170
+ )
171
+ self.variable("E_dir_sunny").values[time_i] = E_dir_sunny
172
+ E_dir = E_dir_sunny * self._calculate_direct_sunny_fraction_(time_i)
173
+ self.variable("E_dir").values[time_i] = E_dir
174
+ q_sol0 = self.radiant_property("alpha", "solar_diffuse", 0) * (E_dif + E_dir)
175
+ self.variable("q_sol0").values[time_i] = q_sol0
176
+ # Mean radiant temperature
177
+ T_rm = self._F_sky * T_sky + (1 - self._F_sky) * self._T_ext
178
+ self.variable("T_rm").values[time_i] = T_rm
179
+ # f_0
180
+ h_rd = self.H_RD * self.radiant_property("alpha", "long_wave", 0)
181
+ self.f_0 = self.area * (
182
+ -self._p_0_ - self.parameter("h_cv").value[0] * self._T_ext - h_rd * T_rm - q_sol0
183
+ )
184
+
185
+ def _calculate_direct_sunny_fraction_(self, time_i):
186
+ if self.project().parameter("shadow_calculation").value == "INSTANT":
187
+ direct_sunny_fraction = self.project().env_3D.get_direct_sunny_fraction(
188
+ self._sunny_index_
189
+ )
190
+ elif self.project().parameter("shadow_calculation").value == "INTERPOLATION":
191
+ azi = self._file_met.variable("sol_azimuth").values[time_i]
192
+ alt = self._file_met.variable("sol_altitude").values[time_i]
193
+ if not math.isnan(alt):
194
+ direct_sunny_fraction = (
195
+ self.project().env_3D.get_direct_interpolated_sunny_fraction(
196
+ self._sunny_index_, azi, alt
197
+ )
198
+ )
199
+ else:
200
+ direct_sunny_fraction = 1
201
+ elif self.project().parameter("shadow_calculation").value == "NO":
202
+ direct_sunny_fraction = 1
203
+ return direct_sunny_fraction
204
+
205
+
206
+ #________ post_iteration ____________
207
+ def post_iteration(self, time_index, date, daylight_saving, converged):
208
+ super().post_iteration(time_index, date, daylight_saving, converged)
209
+ if self._surface_type_ == "EXTERIOR":
210
+ self._calculate_exterior_T_s0_(time_index)
211
+ if self._surface_type_ != "VIRTUAL":
212
+ self._calculate_heat_fluxes_(time_index)
213
+
214
+ def _calculate_exterior_T_s0_(self, time_i):
215
+ T_s0 = (self.f_0 - self.k_01 * self.variable("T_s1").values[time_i]) / self.k[0]
216
+ self.variable("T_s0").values[time_i] = T_s0
217
+
218
+ def _calculate_heat_fluxes_(self, time_i):
219
+ self.variable("q_cd0").values[time_i] = (
220
+ self.a_0 * self.variable("T_s0").values[time_i]
221
+ + self.a_01 * self.variable("T_s1").values[time_i]
222
+ + self.variable("p_0").values[time_i]
223
+ )
224
+ self.variable("q_cd1").values[time_i] = (
225
+ self.a_01 * self.variable("T_s0").values[time_i]
226
+ + self.a_1 * self.variable("T_s1").values[time_i]
227
+ + self.variable("p_1").values[time_i]
228
+ )
229
+ if self._surface_type_ == "EXTERIOR":
230
+ self.variable("q_cv0").values[time_i] = self.parameter("h_cv").value[0] * (
231
+ self._T_ext - self.variable("T_s0").values[time_i]
232
+ )
233
+ self.variable("q_cv1").values[time_i] = self.parameter("h_cv").value[1] * (
234
+ self.get_space().variable("temperature").values[time_i]
235
+ - self.variable("T_s1").values[time_i]
236
+ )
237
+ h_rd = self.H_RD * self.radiant_property("alpha", "long_wave", 0)
238
+ self.variable("q_lwt0").values[time_i] = h_rd * (
239
+ self.variable("T_rm").values[time_i] - self.variable("T_s0").values[time_i]
240
+ )
241
+ self.variable("q_lwt1").values[time_i] = (
242
+ -self.variable("q_cd1").values[time_i]
243
+ - self.variable("q_cv1").values[time_i]
244
+ - self.variable("q_sol1").values[time_i]
245
+ - self.variable("q_swig1").values[time_i]
246
+ - self.variable("q_lwig1").values[time_i]
247
+ )
248
+ elif self._surface_type_ == "INTERIOR":
249
+ self.variable("q_cv0").values[time_i] = self.parameter("h_cv").value[0] * (
250
+ self.get_space(0).variable("temperature").values[time_i]
251
+ - self.variable("T_s0").values[time_i]
252
+ )
253
+ self.variable("q_cv1").values[time_i] = self.parameter("h_cv").value[1] * (
254
+ self.get_space(1).variable("temperature").values[time_i]
255
+ - self.variable("T_s1").values[time_i]
256
+ )
257
+ self.variable("q_lwt0").values[time_i] = (
258
+ -self.variable("q_cd0").values[time_i]
259
+ - self.variable("q_cv0").values[time_i]
260
+ - self.variable("q_sol0").values[time_i]
261
+ - self.variable("q_swig0").values[time_i]
262
+ - self.variable("q_lwig0").values[time_i]
263
+ )
264
+ self.variable("q_lwt1").values[time_i] = (
265
+ -self.variable("q_cd1").values[time_i]
266
+ - self.variable("q_cv1").values[time_i]
267
+ - self.variable("q_sol1").values[time_i]
268
+ - self.variable("q_swig1").values[time_i]
269
+ - self.variable("q_lwig1").values[time_i]
270
+ )
271
+ elif self._surface_type_ == "UNDERGROUND":
272
+ self.variable("q_cv0").values[time_i] = -self.variable("q_cd0").values[time_i]
273
+ self.variable("q_cv1").values[time_i] = self.parameter("h_cv").value * (
274
+ self.get_space().variable("temperature").values[time_i]
275
+ - self.variable("T_s1").values[time_i]
276
+ )
277
+ self.variable("q_lwt1").values[time_i] = (
278
+ -self.variable("q_cd1").values[time_i]
279
+ - self.variable("q_cv1").values[time_i]
280
+ - self.variable("q_sol1").values[time_i]
281
+ - self.variable("q_swig1").values[time_i]
282
+ - self.variable("q_lwig1").values[time_i]
283
+ )
284
+
285
+ @property
286
+ def area(self):
287
+ area = super().area
288
+ if self._surface_type_ == "EXTERIOR" or self._surface_type_ == "INTERIOR":
289
+ for opening in self.openings:
290
+ area -= opening.area
291
+ return area
292
+
293
+ def get_polygon_3D(self):
294
+ azimuth = self.orientation_angle("azimuth", 0, "global")
295
+ altitude = self.orientation_angle("altitude", 0, "global")
296
+ origin = self.get_origin("global")
297
+ pol_2D = self.get_polygon_2D()
298
+ name = self.parameter("name").value
299
+ holes_2D = []
300
+ if self._surface_type_ == "EXTERIOR" or self._surface_type_ == "INTERIOR":
301
+ for opening in self.openings:
302
+ holes_2D.append(opening.get_polygon_2D())
303
+ if self._surface_type_ == "EXTERIOR":
304
+ return Polygon_3D(
305
+ name, origin, azimuth, altitude, pol_2D, holes_2D, color="white"
306
+ )
307
+ elif self._surface_type_ == "INTERIOR":
308
+ return Polygon_3D(
309
+ name, origin, azimuth, altitude, pol_2D, holes_2D, color="green", shading=False, calculate_shadows=False
310
+ )
311
+ elif self._surface_type_ == "UNDERGROUND":
312
+ return Polygon_3D(
313
+ name, origin, azimuth, altitude, pol_2D, holes_2D, color="brown", shading=False, calculate_shadows=False
314
+ )
315
+ elif self._surface_type_ == "VIRTUAL":
316
+ return Polygon_3D(
317
+ name, origin, azimuth, altitude, pol_2D, color="green", opacity=0.4, shading=False, calculate_shadows=False
318
+ )
@@ -0,0 +1,51 @@
1
+ from opensimula.Component import Component
2
+ from opensimula.Message import Message
3
+ from opensimula.Parameters import Parameter_variable_list, Parameter_math_exp_list, Parameter_string_list
4
+ from opensimula.Variable import Variable
5
+
6
+ class Calculator(Component):
7
+ def __init__(self, name, project):
8
+ Component.__init__(self, name, project)
9
+ self.parameter("type").value = "Calculator"
10
+ self.parameter(
11
+ "description").value = "Component to perform calculations with variables from other components."
12
+ # Parameters
13
+ self.add_parameter(Parameter_variable_list("input_variables", []))
14
+ self.add_parameter(Parameter_string_list("output_variables", []))
15
+ self.add_parameter(Parameter_string_list("output_units", []))
16
+ self.add_parameter(Parameter_math_exp_list("output_expressions", []))
17
+
18
+ def check(self):
19
+ self._variables_ = {} # Delete all the variables
20
+ errors = super().check()
21
+ if (
22
+ len(self.parameter("output_variables").value)
23
+ != len(self.parameter("output_expressions").value) or len(self.parameter("output_variables").value)
24
+ != len(self.parameter("output_units").value)
25
+ ):
26
+ msg = Message(f"Error: {self.parameter('name').value}, output_variables, output_units and output_expressions size must be equal","ERROR")
27
+ errors.append(msg)
28
+ else:
29
+ # Create output variables
30
+ for i in range(len(self.parameter("output_variables").value)):
31
+ name = self.parameter("output_variables").value[i]
32
+ unit = self.parameter("output_units").value[i]
33
+ desc = self.parameter("output_expressions").value[i]
34
+ self.add_variable(Variable(name, unit, desc))
35
+
36
+ return errors
37
+
38
+ def pre_simulation(self, n_time_steps, delta_t):
39
+ super().pre_simulation(n_time_steps, delta_t)
40
+
41
+ def pre_iteration(self, time_index, date, daylight_saving):
42
+ super().pre_iteration(time_index, date, daylight_saving)
43
+ # variables dictonary
44
+ var_dic = self.get_parameter_variable_dictionary(time_index)
45
+
46
+ # Output variables
47
+ for i in range(len(self.parameter("output_variables").value)):
48
+ calculated_value = self.parameter(
49
+ "output_expressions").evaluate(i, var_dic)
50
+ name = self.parameter("output_variables").value[i]
51
+ self.variable(name).values[time_index] = calculated_value
@@ -0,0 +1,309 @@
1
+ import math
2
+ import numpy as np
3
+ from scipy.optimize import brentq
4
+ from opensimula.Message import Message
5
+ from opensimula.Parameters import Parameter_component_list, Parameter_float_list
6
+ from opensimula.Component import Component
7
+
8
+ class Construction(Component):
9
+ def __init__(self, name, project):
10
+ Component.__init__(self, name, project)
11
+ self.parameter("type").value = "Construction"
12
+ self.parameter(
13
+ "description").value = "Construction using layers of material"
14
+
15
+ self.add_parameter(Parameter_float_list(
16
+ "solar_alpha", [0.8, 0.8], "frac", min=0, max=1))
17
+ self.add_parameter(Parameter_float_list(
18
+ "lw_epsilon", [0.9, 0.9], "frac", min=0, max=1))
19
+ self.add_parameter(Parameter_component_list(
20
+ "materials", [], "Material"))
21
+ self.add_parameter(Parameter_float_list("thicknesses", [], "m", min=0))
22
+
23
+ def check(self):
24
+ errors = super().check()
25
+ # Test if materials an thicknesses size are equals
26
+ if len(self.parameter("materials").value) != len(self.parameter("thicknesses").value):
27
+ msg =f"Error: {self.parameter('name').value}, material and thicknesses parameters must have same length"
28
+ errors.append(Message(msg, "error"))
29
+ return errors
30
+
31
+ # Functions for Transfer Function Calculation
32
+
33
+ def pre_simulation(self, n_time_steps, delta_t):
34
+ super().pre_simulation(n_time_steps, delta_t)
35
+ self._calc_trans_fun_(delta_t)
36
+
37
+ def get_T_step_fluxes(self):
38
+ n_q = len(self._coef_Q)
39
+ n_t = len(self._coef_T_a)
40
+ Q_old_1 = np.zeros(n_q)
41
+ Q_old_2 = np.zeros(n_q)
42
+ T_old = np.ones(n_t)
43
+ # T_old[0] = 0
44
+ q_2 = 1
45
+ Q_2 = []
46
+ Q_1 = []
47
+ n = 0
48
+ while n <= 1 or math.fabs(q_2) > 1e-15:
49
+ q_2 = np.dot(
50
+ self._coef_T_a - self._coef_T_b, T_old.transpose()
51
+ ) - np.dot(self._coef_Q, Q_old_2.transpose())
52
+ q_1 = np.dot(
53
+ self._coef_T_b - self._coef_T_c, T_old.transpose()
54
+ ) - np.dot(self._coef_Q, Q_old_1.transpose())
55
+ Q_2.append(q_2)
56
+ Q_1.append(q_1)
57
+ Q_old_2 = np.roll(Q_old_2, 1)
58
+ Q_old_2[0] = 0
59
+ Q_old_2[1] = q_2
60
+ Q_old_1 = np.roll(Q_old_1, 1)
61
+ Q_old_1[0] = 0
62
+ Q_old_1[1] = q_1
63
+ T_old = np.roll(T_old, 1)
64
+ T_old[0] = 0
65
+ n = n + 1
66
+ return (Q_1, Q_2)
67
+
68
+ def thermal_resistance(self):
69
+ resis_tot = 0
70
+ for i in range(len(self.parameter("materials").value)):
71
+ resis_tot = resis_tot + self._resis_layer_(i)
72
+ return resis_tot
73
+
74
+ def radiant_property(self, prop, radiation_type, side, theta=0):
75
+ if (radiation_type == "solar_diffuse" or radiation_type == "solar_direct"):
76
+ if (prop == "rho"):
77
+ return 1-self.parameter("solar_alpha").value[side]
78
+ elif (prop == "tau"):
79
+ return 0
80
+ elif (prop == "alpha"):
81
+ return self.parameter("solar_alpha").value[side]
82
+ elif (prop == "alpha_other_side"):
83
+ return 0
84
+ elif (radiation_type == "long_wave"):
85
+ if (prop == "rho"):
86
+ return 1-self.parameter("lw_epsilon").value[side]
87
+ elif (prop == "tau"):
88
+ return 0
89
+ elif (prop == "alpha"):
90
+ return self.parameter("lw_epsilon").value[side]
91
+
92
+ def get_A(self):
93
+ """
94
+ Conduction actual time coefficients
95
+ Returns:
96
+ (a_0, a_1, a_01):
97
+ """
98
+ return (-self._coef_T_c[0], -self._coef_T_a[0], self._coef_T_b[0])
99
+
100
+ def get_P(self, time_i, T_s0, T_s1, q_cd0, q_cd1, T_ini):
101
+ """
102
+ Conduction P for one time instant
103
+ Returns:
104
+ (p_0, p_1):
105
+ """
106
+ p0 = 0
107
+ p1 = 0
108
+ for i in range(1, len(self._coef_T_a)):
109
+ j = time_i - i
110
+ if j < 0:
111
+ T_0 = T_ini
112
+ T_1 = T_ini
113
+ else:
114
+ T_0 = T_s0[j]
115
+ T_1 = T_s1[j]
116
+ p0 += -self._coef_T_c[i] * T_0 + self._coef_T_b[i] * T_1
117
+ p1 += -self._coef_T_a[i] * T_1 + self._coef_T_b[i] * T_0
118
+ for i in range(1, len(self._coef_Q)):
119
+ j = time_i - i
120
+ if j < 0:
121
+ q_0 = 0
122
+ q_1 = 0
123
+ else:
124
+ q_0 = q_cd0[j]
125
+ q_1 = q_cd1[j]
126
+ p0 += -self._coef_Q[i] * q_0
127
+ p1 += -self._coef_Q[i] * q_1
128
+ return (p0, p1)
129
+
130
+ def _resis_layer_(self, layer):
131
+ material = self.parameter("materials").component[layer]
132
+ resis_def = material.parameter("use_resistance").value
133
+ if resis_def:
134
+ return material.parameter("thermal_resistance").value
135
+ else:
136
+ return (
137
+ self.parameter("thicknesses").value[layer]
138
+ / material.parameter("conductivity").value
139
+ )
140
+
141
+ def _alpha_layer_(self, layer):
142
+ material = self.parameter("materials").component[layer]
143
+ resis_def = material.parameter("use_resistance").value
144
+ if resis_def:
145
+ return (
146
+ self.parameter("thicknesses").value[layer]
147
+ / material.parameter("thermal_resistance").value
148
+ ) / (
149
+ material.parameter("density").value
150
+ * material.parameter("specific_heat").value
151
+ )
152
+ else:
153
+ return material.parameter("conductivity").value / (
154
+ material.parameter("density").value
155
+ * material.parameter("specific_heat").value
156
+ )
157
+
158
+ def _tau_layer_(self, layer):
159
+ L = self.parameter("thicknesses").value[layer]
160
+ return L * L / self._alpha_layer_(layer)
161
+
162
+ def _H_Matrix_Layer_(self, s, layer):
163
+ # Calculate H Matrix for one layer
164
+ resis = self._resis_layer_(layer)
165
+ tau = self._tau_layer_(layer)
166
+ aux = math.sqrt(tau * s)
167
+
168
+ A = math.cos(aux)
169
+ if s == 0:
170
+ B = resis
171
+ C = 0
172
+ else:
173
+ B = resis / aux * math.sin(aux)
174
+ C = -aux * math.sin(aux) / resis
175
+ return np.array([[A, B], [C, A]])
176
+
177
+ def _dH_Matrix_Layer_(self, s, layer):
178
+ # Calculate dif H Matrix for one layer
179
+ resis = self._resis_layer_(layer)
180
+ tau = self._tau_layer_(layer)
181
+ aux = math.sqrt(tau * s)
182
+
183
+ if s == 0:
184
+ A = tau / 2
185
+ B = (resis * tau) / 6
186
+ C = tau / resis
187
+ else:
188
+ A = (tau / 2) * math.sin(aux) / aux
189
+ B = (resis / (2 * s)) * (math.sin(aux) / aux - math.cos(aux))
190
+ C = (tau / (2 * resis)) * ((math.sin(aux) / aux) + math.cos(aux))
191
+ return np.array([[A, B], [C, A]])
192
+
193
+ def _H_Matrix_(self, s):
194
+ H = np.eye(2)
195
+ for i in range(len(self.parameter("materials").value)):
196
+ H = np.dot(H, self._H_Matrix_Layer_(s, i))
197
+ return H
198
+
199
+ def _dH_Matrix_(self, s):
200
+ H = np.zeros((2, 2))
201
+ n = len(self.parameter("materials").value)
202
+ for i in range(n):
203
+ P1 = np.eye(2)
204
+ for j in range(i):
205
+ P1 = np.dot(P1, self._H_Matrix_Layer_(s, j))
206
+ P2 = np.eye(2)
207
+ for j in range(i + 1, n):
208
+ P2 = np.dot(P2, self._H_Matrix_Layer_(s, j))
209
+ H = H + np.dot(P1, np.dot(self._dH_Matrix_Layer_(s, i), P2))
210
+ return H
211
+
212
+ def _B_roots_(self, delta_t):
213
+ def func(s):
214
+ B = self._H_Matrix_(s)[0, 1]
215
+ return B
216
+
217
+ delta_s = 1e-6
218
+ a = 1e-15
219
+ B_a = func(a)
220
+ b = delta_s
221
+ roots = []
222
+ exp = 1
223
+ while exp > 1e-10:
224
+ B_b = func(b)
225
+ if B_a * B_b <= 0: # Signo contrario o un cero
226
+ bisec = brentq(func, a, b)
227
+ roots.append(bisec)
228
+ exp = math.exp(-bisec * delta_t)
229
+ a = b
230
+ B_a = B_b
231
+ b = b + delta_s
232
+
233
+ return roots
234
+
235
+ def _calc_trans_fun_(self, delta_t):
236
+ min_coef = 1e-10
237
+ dH_0 = self._dH_Matrix_(0)
238
+ H_0 = self._H_Matrix_(0)
239
+ C0 = H_0[0, 0] / H_0[0, 1]
240
+ C1x = (dH_0[0, 0] * H_0[0, 1] - H_0[0, 0] * dH_0[0, 1]) / (
241
+ H_0[0, 1] * H_0[0, 1]
242
+ )
243
+ C1y = (-dH_0[0, 1]) / (H_0[0, 1] * H_0[0, 1])
244
+ C1z = (dH_0[1, 1] * H_0[0, 1] - dH_0[0, 1]) / (H_0[0, 1] * H_0[0, 1])
245
+
246
+ # e_coef
247
+ roots = self._B_roots_(delta_t)
248
+ n_coef = len(roots) + 1
249
+ ex = []
250
+ ey = []
251
+ ez = []
252
+ h = []
253
+ for root in roots:
254
+ H = self._H_Matrix_(root)
255
+ dH = self._dH_Matrix_(root)
256
+ ex.append(H[0, 0] / (root * root * dH[0, 1]))
257
+ ey.append(1 / (root * root * dH[0, 1]))
258
+ ez.append(H[1, 1] / (root * root * dH[0, 1]))
259
+ h.append(math.exp(-root * delta_t))
260
+ d = [1, -h[0]]
261
+ for i in range(1, len(roots)):
262
+ u = [1, -h[i]]
263
+ d = np.convolve(d, u)
264
+
265
+ ox = []
266
+ oy = []
267
+ oz = []
268
+ for i in range(1, n_coef):
269
+ sum_exp_x = 0
270
+ sum_exp_y = 0
271
+ sum_exp_z = 0
272
+ for j in range(len(roots)):
273
+ exp = math.exp(-(i) * roots[j] * delta_t)
274
+ sum_exp_x = sum_exp_x + ex[j] * exp
275
+ sum_exp_y = sum_exp_y + ey[j] * exp
276
+ sum_exp_z = sum_exp_z + ez[j] * exp
277
+ ox.append(C1x + i * C0 * delta_t + sum_exp_x)
278
+ oy.append(C1y + i * C0 * delta_t + sum_exp_y)
279
+ oz.append(C1z + i * C0 * delta_t + sum_exp_z)
280
+
281
+ ramp = [1 / delta_t, -2 / delta_t, 1 / delta_t]
282
+ g = np.convolve(ramp, d)
283
+ a = np.convolve(g, ox)
284
+ b = np.convolve(g, oy)
285
+ c = np.convolve(g, oz)
286
+ # Cut d coefficients
287
+ for i in range(len(d)):
288
+ if math.fabs(d[i]) < min_coef:
289
+ d = d[0: i+1]
290
+ break
291
+ # Cut number of coeficients, se producen coeficientes extraños para muros ligeros a partir del n. de roots
292
+ a = np.resize(a, n_coef-1)
293
+ b = np.resize(b, n_coef-1)
294
+ c = np.resize(c, n_coef-1)
295
+ # Cut a, b, c coefficients
296
+ for i in range(len(a)):
297
+ if (
298
+ math.fabs(a[i]) < min_coef
299
+ and math.fabs(b[i]) < min_coef
300
+ and math.fabs(c[i]) < min_coef
301
+ ):
302
+ a = a[0: i+1]
303
+ b = b[0: i+1]
304
+ c = c[0: i+1]
305
+ break
306
+ self._coef_T_a = a
307
+ self._coef_T_b = b
308
+ self._coef_T_c = c
309
+ self._coef_Q = d