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
opensimula/Project.py ADDED
@@ -0,0 +1,674 @@
1
+ import json
2
+ import datetime as dt
3
+ import numpy as np
4
+ import pandas as pd
5
+ from dash import Dash, callback, Input, Output, html, State
6
+ import dash_ag_grid as dag
7
+ import dash_bootstrap_components as dbc
8
+ import psychrolib as sicro
9
+ from tqdm import trange
10
+ from opensimula.Message import Message
11
+ from opensimula.Parameter_container import Parameter_container
12
+ from opensimula.Parameters import (
13
+ Parameter_component,
14
+ Parameter_int,
15
+ Parameter_string,
16
+ Parameter_string_list,
17
+ Parameter_boolean,
18
+ Parameter_options,
19
+ Parameter_float
20
+ )
21
+ from opensimula.components import *
22
+ from opensimula.visual_3D.Environment_3D import Environment_3D
23
+
24
+
25
+ class Project(Parameter_container):
26
+ """Project has the following features:
27
+
28
+ - It is included in the Simulation environment
29
+ - Contain a list of components
30
+ - Contains parameters for its definition
31
+ - Contains Environment_3D for 3D representation of the project
32
+ """
33
+
34
+ def __init__(self, name, sim):
35
+ """Create new project
36
+
37
+ Args:
38
+ sim (Simulation): parent Simulation environment
39
+ """
40
+ Parameter_container.__init__(self, sim)
41
+ self.parameter("name").value = name
42
+ self.parameter("description").value = "Description of the project"
43
+ self.add_parameter(Parameter_int("time_step", 3600, "s", min=1))
44
+ self.add_parameter(Parameter_int("n_time_steps", 8760, min=1))
45
+ self.add_parameter(Parameter_string("initial_time", "01/01/2001 00:00:00"))
46
+ self.add_parameter(Parameter_boolean("daylight_saving", False))
47
+ self.add_parameter(
48
+ Parameter_string("daylight_saving_start_time", "25/03/2001 02:00:00")
49
+ )
50
+ self.add_parameter(
51
+ Parameter_string("daylight_saving_end_time", "28/10/2001 02:00:00")
52
+ )
53
+ self.add_parameter(Parameter_int("n_max_iteration", 1000, min=1))
54
+ self.add_parameter(
55
+ Parameter_string_list("simulation_order", DEFAULT_COMPONENTS_ORDER)
56
+ )
57
+ self.add_parameter(
58
+ Parameter_component("simulation_file_met", "not_defined", ["File_met"])
59
+ )
60
+ self.add_parameter(
61
+ Parameter_options(
62
+ "shadow_calculation", "INSTANT", ["NO", "INSTANT", "INTERPOLATION"]
63
+ )
64
+ )
65
+ self.add_parameter(Parameter_float("albedo", 0.2, "frac", min=0, max=1))
66
+
67
+ self._sim_ = sim
68
+ self._components_ = []
69
+ sicro.SetUnitSystem(sicro.SI)
70
+ atm_p = sicro.GetStandardAtmPressure(0)
71
+ w_50 = sicro.GetHumRatioFromRelHum(22.5, 0.5, atm_p)
72
+
73
+ def rhocp_water(T):
74
+ """
75
+ Returns: Liquid water rho*c_p at 1 atm (J/(m^3·K)), Cubic adjustment
76
+
77
+ Parameters:
78
+ T: water temperature (ºC)
79
+ """
80
+ return (
81
+ -6.5515e-08 * T**3 + 7.6219e-06 * T**2 - 1.8564e-03 * T + 4.2125
82
+ ) * 1e6
83
+
84
+ # Set simulation properties
85
+ self._sim_.props = {
86
+ "C_PA": 1006, # J/kg·K
87
+ "C_P_FURNITURE": 1000, # J/kg·K
88
+ "LAMBDA": 2501, # J/g Latent heat of water at 0ºC
89
+ "ALTITUDE": 0, # m
90
+ "ATM_PRESSURE": atm_p,
91
+ "W_50": w_50,
92
+ "RHO_A": sicro.GetMoistAirDensity(22.5, w_50, atm_p),
93
+ "RHOCP_W": rhocp_water,
94
+ }
95
+
96
+ def del_component(self, component):
97
+ """Delete component from Project
98
+
99
+ Args:
100
+ component (Component): Component to be removed from the project
101
+ """
102
+ self._components_.remove(component)
103
+
104
+ def component(self, name):
105
+ """Find and return component with its name
106
+
107
+ Args:
108
+ name (string): name of the component
109
+
110
+ Returns:
111
+ component (Component): component found, None if not found.
112
+ """
113
+ for comp in self._components_:
114
+ if comp.parameter("name").value == name:
115
+ return comp
116
+ return None
117
+
118
+ def component_list(self, comp_type="all"):
119
+ """Components list in the project
120
+
121
+ Returns:
122
+ components (Components list): List of components.
123
+ """
124
+ comp_list = []
125
+ for comp in self._components_:
126
+ if comp_type == "all":
127
+ comp_list.append(comp)
128
+ else:
129
+ if comp.parameter("type").value == comp_type:
130
+ comp_list.append(comp)
131
+ return comp_list
132
+
133
+ def component_dataframe(self, comp_type="all", string_format=False):
134
+ data = pd.DataFrame()
135
+ comp_list = self.component_list(comp_type)
136
+ if len(comp_list) > 0:
137
+ parameters = ["name", "type", "description"]
138
+ if comp_type != "all":
139
+ for key, par in comp_list[0]._parameters_.items():
140
+ if key != "name" and key != "type" and key != "description":
141
+ parameters.append(key)
142
+ for param in parameters:
143
+ param_array = []
144
+ for comp in comp_list:
145
+ if string_format:
146
+ param_array.append(str(comp.parameter(param).value))
147
+ else:
148
+ param_array.append(comp.parameter(param).value)
149
+ data[param] = param_array
150
+ return data
151
+
152
+ def new_component(self, comp_type, name):
153
+ try:
154
+ clase = globals()[comp_type]
155
+ comp = clase(name, self)
156
+ self._components_.append(comp)
157
+ return comp
158
+ except KeyError:
159
+ return None
160
+
161
+ def _get_error_header_(self):
162
+ return f'Project "{self.parameter("name").value}". '
163
+
164
+ def _load_from_dict_(self, dic):
165
+ for key, value in dic.items():
166
+ if key == "components": # Lista de componentes
167
+ for component in value:
168
+ if "type" in component:
169
+ name = component["type"] + "_X"
170
+ if "name" in component:
171
+ name = component["name"]
172
+ comp = self.new_component(component["type"], name)
173
+ if comp is None:
174
+ msg = (
175
+ self._get_error_header_()
176
+ + f'Component type {component["type"]} does not exist.'
177
+ )
178
+ self._sim_.message(Message(msg, "ERROR"))
179
+ else:
180
+ comp.set_parameters(component)
181
+ else:
182
+ msg = (
183
+ self._get_error_header_()
184
+ + f'Component does not contain "type" parameter {component}'
185
+ )
186
+ self._sim_.message(Message(msg, "ERROR"))
187
+ else:
188
+ if key in self._parameters_:
189
+ self.parameter(key).value = value
190
+ else:
191
+ msg = self._get_error_header_() + f"Parameter {key} does not exist."
192
+ self._sim_.message(Message(msg, "ERROR"))
193
+
194
+ def read_dict(self, dict):
195
+ """Load paramaters an components from dictionary
196
+
197
+ Args:
198
+ dic (dictionary): dictonary with the parameters and componenets to be loaded in the project
199
+
200
+ """
201
+ self._sim_.message(Message("Reading project data from dictonary", "CONSOLE"))
202
+ self._load_from_dict_(dict)
203
+ self._sim_.message(Message("Reading completed.", "CONSOLE"))
204
+ self.check()
205
+
206
+ def write_dict(self):
207
+ """Write dictionary with the definition of the project
208
+
209
+ Return:
210
+ dic (dictionary): dictonary with the parameters and componenets that define the project
211
+
212
+ """
213
+ dict = {"components": []}
214
+ for key, param in self.parameter_dict().items():
215
+ dict[key] = param.value
216
+ for comp in self._components_:
217
+ comp_dict = {}
218
+ for key, param in comp.parameter_dict().items():
219
+ comp_dict[key] = param.value
220
+ dict["components"].append(comp_dict)
221
+
222
+ return dict
223
+
224
+ def read_json(self, json_file):
225
+ """Read paramaters an components from dictionary in a json file
226
+
227
+ Args:
228
+ json_file (string): file name that contains dictonary with the parameters and componenets to be loaded in the project
229
+
230
+ """
231
+ try:
232
+ f = open(json_file, "r")
233
+ except OSError:
234
+ msg = self._get_error_header_() + f"Could not open/read file: {json_file}."
235
+ self._sim_.message(Message(msg, "ERROR"))
236
+ return False
237
+ with f:
238
+ json_dict = json.load(f)
239
+ self._sim_.message(
240
+ Message("Reading project data from file: " + json_file, "CONSOLE")
241
+ )
242
+ self._load_from_dict_(json_dict)
243
+ self._sim_.message(Message("Reading completed.", "CONSOLE"))
244
+ self.check()
245
+
246
+ def write_json(self, json_file):
247
+ """Write project definition to json file
248
+
249
+ Args:
250
+ json_file (string): file name
251
+
252
+ """
253
+ try:
254
+ f = open(json_file, "w")
255
+ except OSError:
256
+ msg = self._get_error_header_() + f"Could not write file: {json_file}."
257
+ self._sim_.message(Message(msg, "ERROR"))
258
+ return False
259
+ with f:
260
+ self._sim_.message(
261
+ Message("Writing project data to file: " + json_file, "CONSOLE")
262
+ )
263
+ dict = self.write_dict()
264
+ json.dump(dict, f)
265
+ self._sim_.message(Message("Writing completed.", "CONSOLE"))
266
+
267
+ def _read_excel_(self, excel_file):
268
+ """Read paramaters an components from excel file
269
+
270
+ Args:
271
+ excel_file (string): excel file path
272
+ """
273
+ try:
274
+ xls_file = pd.ExcelFile(excel_file)
275
+ self._sim_.message(
276
+ Message("Reading project data from file: " + excel_file, "CONSOLE")
277
+ )
278
+ json_dict = self._excel_to_json_(xls_file)
279
+ self._load_from_dict_(json_dict)
280
+ self._sim_.message(Message("Reading completed.", "CONSOLE"))
281
+ self.check()
282
+ except Exception as e:
283
+ msg = self._get_error_header_() + f"Reading file: {excel_file} -> {e}."
284
+ self._sim_.message(Message(msg, "ERROR"))
285
+ return False
286
+
287
+ def _excel_to_json_(self, xls_file):
288
+ json = {"components": []}
289
+ sheets = xls_file.sheet_names
290
+ # project sheet
291
+ project_df = xls_file.parse(sheet_name="project")
292
+ for index, row in project_df.iterrows():
293
+ json[row["key"]] = self._value_to_json_(row["value"])
294
+ # rest of sheets
295
+ for sheet in sheets:
296
+ if sheet != "project":
297
+ comp_df = xls_file.parse(sheet_name=sheet)
298
+ column_names = comp_df.columns.values.tolist()
299
+ for index, row in comp_df.iterrows():
300
+ j = 0
301
+ comp_json = {}
302
+ comp_json["type"] = sheet
303
+ for cell in row:
304
+ comp_json[column_names[j]] = self._value_to_json_(cell)
305
+ j += 1
306
+ json["components"].append(comp_json)
307
+ return json
308
+
309
+ def _value_to_json_(self, value):
310
+ if isinstance(value, str):
311
+ if value[0] == "[":
312
+ return value[1:-1].split(",")
313
+ else:
314
+ return value
315
+ else:
316
+ return value
317
+
318
+ # ____________________
319
+
320
+ def _set_ordered_component_list_(self):
321
+ all_comp_list = []
322
+ # Add referenced components
323
+ for comp in self.component_list():
324
+ components = comp.get_all_referenced_components()
325
+ for comp_i in components:
326
+ if comp_i not in all_comp_list:
327
+ all_comp_list.append(comp_i)
328
+ # order components
329
+ self._ordered_component_list_ = all_comp_list.copy()
330
+ # Remove components and at the end
331
+ for comp_type in self.parameter("simulation_order").value:
332
+ for comp in all_comp_list:
333
+ if comp.parameter("type").value == comp_type:
334
+ self._ordered_component_list_.remove(comp)
335
+ for comp in all_comp_list:
336
+ if comp.parameter("type").value == comp_type:
337
+ self._ordered_component_list_.append(comp)
338
+
339
+ def check(self):
340
+ """Check if all is correct, for the project and all its components
341
+
342
+ Prints all errors found
343
+
344
+ Returns:
345
+ errors (string list): List of errors
346
+ """
347
+ self._sim_.message(
348
+ Message("Checking project: " + self.parameter("name").value, "CONSOLE")
349
+ )
350
+ errors = self.check_parameters() # Parameters
351
+ names = []
352
+ # Check initial time
353
+ try:
354
+ dt.datetime.strptime(
355
+ self.parameter("initial_time").value, "%d/%m/%Y %H:%M:%S"
356
+ )
357
+ except ValueError:
358
+ msg = (
359
+ self._get_error_header_()
360
+ + f"Initial_time: {self.parameter('initial_time').value} does not match format (dd/mm/yyyy HH:MM:SS)"
361
+ )
362
+ errors.append(Message(msg, "ERROR"))
363
+ # Check daylight saving dates
364
+ if self.parameter("daylight_saving").value:
365
+ try:
366
+ dt.datetime.strptime(
367
+ self.parameter("daylight_saving_start_time").value,
368
+ "%d/%m/%Y %H:%M:%S",
369
+ )
370
+ except ValueError:
371
+ msg = (
372
+ self._get_error_header_()
373
+ + f"Initial_time: {self.parameter('daylight_saving_start_time').value} does not match format (dd/mm/yyyy HH:MM:SS)"
374
+ )
375
+ errors.append(Message(msg, "ERROR"))
376
+ try:
377
+ dt.datetime.strptime(
378
+ self.parameter("daylight_saving_end_time").value,
379
+ "%d/%m/%Y %H:%M:%S",
380
+ )
381
+ except ValueError:
382
+ error = (
383
+ self._get_error_header_()
384
+ + f"Initial_time: {self.parameter('daylight_saving_end_time').value} does not match format (dd/mm/yyyy HH:MM:SS)"
385
+ )
386
+ errors.append(Message(msg, "ERROR"))
387
+
388
+ self._set_ordered_component_list_()
389
+ list = self._ordered_component_list_
390
+ for comp in list:
391
+ error_comp = comp.check()
392
+ if len(error_comp) > 0:
393
+ for e in error_comp:
394
+ errors.append(e)
395
+ if comp.parameter("name").value in names:
396
+ msg = (
397
+ self._get_error_header_()
398
+ + f"'{comp.parameter('name').value}' is used by two or more components as name"
399
+ )
400
+ errors.append(Message(msg, "ERROR"))
401
+ else:
402
+ names.append(comp.parameter("name").value)
403
+
404
+ if len(errors) == 0:
405
+ self._sim_.message(Message("Checking completed.", "CONSOLE"))
406
+ else:
407
+ for error in errors:
408
+ self._sim_.message(error)
409
+
410
+ return errors
411
+
412
+ def simulate(self):
413
+ """Project Time Simulation"""
414
+ n = self.parameter("n_time_steps").value
415
+ date = dt.datetime.strptime(
416
+ self.parameter("initial_time").value, "%d/%m/%Y %H:%M:%S"
417
+ )
418
+ delta_t = self.parameter("time_step").value
419
+ date = date + dt.timedelta(0, delta_t / 2) # Centered in the interval
420
+ if self.parameter("daylight_saving").value:
421
+ date_dls_start = dt.datetime.strptime(
422
+ self.parameter("daylight_saving_start_time").value, "%d/%m/%Y %H:%M:%S"
423
+ )
424
+ date_dls_end = dt.datetime.strptime(
425
+ self.parameter("daylight_saving_end_time").value, "%d/%m/%Y %H:%M:%S"
426
+ )
427
+
428
+ # Update props
429
+ if self.parameter("simulation_file_met").value != "not_defined":
430
+ met_file = self.component(self.parameter("simulation_file_met").value)
431
+ else:
432
+ met_file = None
433
+ try:
434
+ if met_file is not None:
435
+ altitude = met_file.altitude
436
+ atm_p = sicro.GetStandardAtmPressure(altitude)
437
+ w_50 = sicro.GetHumRatioFromRelHum(22.5, 0.5, atm_p)
438
+ self._sim_.props["ATM_PRESSURE"] = atm_p
439
+ self._sim_.props["ALTITUDE"] = altitude
440
+ self._sim_.props["W_50"] = w_50
441
+ self._sim_.props["RHO_A"] = sicro.GetMoistAirDensity(22.5, w_50, atm_p)
442
+ except Exception as e:
443
+ msg = (self._get_error_header_()
444
+ + f"Error reading file: {self.parameter('simulation_file_met').value} -> {e}")
445
+ self._sim_.message(Message(msg, "ERROR"))
446
+
447
+ self._set_ordered_component_list_()
448
+
449
+ # Initialize 3D environment
450
+ self.env_3D = Environment_3D()
451
+ if self.parameter("shadow_calculation").value != "NO":
452
+ self.create_3D_environment(self.env_3D)
453
+ self._sim_.message(Message("Calculating solar direct shadows ...", "CONSOLE"))
454
+ self.env_3D.calculate_solar_tables()
455
+ self._pre_simulation_(n, delta_t)
456
+ self._sim_df = pd.DataFrame({"dates": self.dates()})
457
+ self._sim_df["n_iterations"] = 0
458
+ self._sim_df["last_component"] = "None"
459
+ self._sim_df["converged"] = True
460
+
461
+ self._sim_.message(
462
+ Message(f"Simulating {self.parameter('name').value}: ...", "CONSOLE")
463
+ )
464
+
465
+ tq = trange(n, unit="step", colour="blue")
466
+ for i in tq:
467
+ daylight_saving = False
468
+ if self.parameter("daylight_saving").value:
469
+ if date > date_dls_start and date < date_dls_end:
470
+ daylight_saving = True
471
+
472
+ # Update Shadows
473
+ if self.parameter("shadow_calculation").value == "INSTANT" and met_file is not None:
474
+ cos = met_file.sun_cosines(date)
475
+ if len(cos) == 3:
476
+ self.env_3D.calculate_shadows(cos,create_polygons=False)
477
+ else:
478
+ self.env_3D.delete_shadows()
479
+
480
+ self._pre_iteration_(i, date, daylight_saving)
481
+ converge = False
482
+ n_iter = 0
483
+ while not converge and n_iter < self.parameter("n_max_iteration").value:
484
+ if self._iteration_(i, date, daylight_saving, n_iter):
485
+ converge = True
486
+ n_iter += 1
487
+ tq.set_postfix(n_iter=n_iter)
488
+ self._sim_df.at[i, "n_iterations"] = n_iter
489
+ self._sim_df.at[i, "converged"] = converge
490
+ self._post_iteration_(i, date, daylight_saving, converge)
491
+ date = date + dt.timedelta(0, delta_t)
492
+
493
+ n_not_converged = (
494
+ len(self._sim_df["converged"]) - self._sim_df["converged"].sum()
495
+ )
496
+ if n_not_converged > 0:
497
+ self._sim_.message(
498
+ Message(f"{n_not_converged} time steps did not converge.", "WARNING")
499
+ )
500
+ self._post_simulation_()
501
+
502
+ def _pre_simulation_(self, n_time_steps, delta_t):
503
+ for comp in self._ordered_component_list_:
504
+ comp.pre_simulation(n_time_steps, delta_t)
505
+
506
+ def _post_simulation_(self):
507
+ for comp in self._ordered_component_list_:
508
+ comp.post_simulation()
509
+
510
+ def _pre_iteration_(self, time_index, date, dayligth_saving):
511
+ for comp in self._ordered_component_list_:
512
+ comp.pre_iteration(time_index, date, dayligth_saving)
513
+
514
+ def _iteration_(self, time_index, date, dayligth_saving, n_iter):
515
+ converge = True
516
+ for comp in self._ordered_component_list_:
517
+ if not comp.iteration(time_index, date, dayligth_saving, n_iter):
518
+ self._sim_df.at[time_index, "last_component"] = comp.parameter(
519
+ "name"
520
+ ).value
521
+ converge = False
522
+ return converge
523
+
524
+ def _post_iteration_(self, time_index, date, dayligth_saving, converged):
525
+ for comp in self._ordered_component_list_:
526
+ comp.post_iteration(time_index, date, dayligth_saving, converged)
527
+
528
+ def dates(self):
529
+ n = self.parameter("n_time_steps").value
530
+ date = dt.datetime.strptime(
531
+ self.parameter("initial_time").value, "%d/%m/%Y %H:%M:%S"
532
+ )
533
+ delta_t = self.parameter("time_step").value
534
+ date = date + +dt.timedelta(0, delta_t / 2) # Centered in the interval
535
+ array = np.empty(n, dtype=object)
536
+
537
+ for i in range(n):
538
+ array[i] = date
539
+ date = date + dt.timedelta(0, delta_t)
540
+
541
+ return array
542
+
543
+ def _repr_html_(self):
544
+ html = f"<h3>Project: {self.parameter('name').value}</h3><p>{self.parameter('description').value}</p>"
545
+ html += "<strong>Parameters:</strong>"
546
+ html += self.parameter_dataframe().to_html()
547
+ html += "<br/><strong>Components list:</strong>"
548
+ html += self.component_dataframe().to_html()
549
+ return html
550
+
551
+ def simulation_dataframe(self):
552
+ return self._sim_df
553
+
554
+ def component_editor(self, comp_type="all"):
555
+ editor = Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
556
+ df = self.component_dataframe(comp_type=comp_type, string_format=True)
557
+ self._n_clicks_new_comp_ = 0
558
+ self._n_clicks_del_comp_ = 0
559
+ disabled_new = False
560
+ if comp_type == "all":
561
+ disabled_new = True
562
+
563
+ column_definition = [
564
+ {
565
+ "field": "name",
566
+ "checkboxSelection": True,
567
+ "headerCheckboxSelection": True,
568
+ }
569
+ ]
570
+ for i in df.columns:
571
+ if i != "name":
572
+ column_definition.append({"field": i})
573
+
574
+ editor.layout = html.Div(
575
+ [
576
+ dbc.Label("Components editor:"),
577
+ html.Br(),
578
+ dbc.Button(
579
+ "New component",
580
+ id="btn-new-comp",
581
+ disabled=disabled_new,
582
+ n_clicks=0,
583
+ ),
584
+ dbc.Button(
585
+ "Delete selected components",
586
+ id="btn-del-comp",
587
+ n_clicks=0,
588
+ style={"margin-left": "15px"},
589
+ ),
590
+ html.Br(),
591
+ html.Br(),
592
+ dag.AgGrid(
593
+ id="comp-table",
594
+ rowData=df.to_dict("records"),
595
+ columnDefs=column_definition,
596
+ columnSize="sizeToFit",
597
+ defaultColDef={"filter": True, "editable": True},
598
+ style={"height": "500px"},
599
+ dashGridOptions={
600
+ "rowSelection": "multiple",
601
+ "suppressRowClickSelection": True,
602
+ "pagination": True,
603
+ },
604
+ ),
605
+ ]
606
+ )
607
+
608
+ @callback(
609
+ Output("comp-table", "rowData"),
610
+ Input("comp-table", "cellValueChanged"),
611
+ Input("btn-new-comp", "n_clicks"),
612
+ Input("btn-del-comp", "n_clicks"),
613
+ State("comp-table", "selectedRows"),
614
+ prevent_initial_call=True,
615
+ )
616
+ def update_data(changed, n_clicks_new, n_clicks_del, selectedRows):
617
+ if self._n_clicks_new_comp_ < n_clicks_new:
618
+ self.new_component(comp_type, "new_comp_" + str(n_clicks_new))
619
+ self._n_clicks_new_comp_ = n_clicks_new
620
+ elif self._n_clicks_del_comp_ < n_clicks_del:
621
+ for row in selectedRows:
622
+ self.del_component(self.component(row["name"]))
623
+ self._n_clicks_del_comp_ = n_clicks_del
624
+ else:
625
+ if changed is not None:
626
+ if changed[0]["colId"] == "name":
627
+ self.component(changed[0]["oldValue"]).parameter(
628
+ "name"
629
+ ).value = changed[0]["value"]
630
+ else:
631
+ self.component(changed[0]["data"]["name"]).parameter(
632
+ changed[0]["colId"]
633
+ ).value = changed[0]["value"]
634
+ df_end = self.component_dataframe(comp_type=comp_type, string_format=True)
635
+ return df_end.to_dict("records")
636
+
637
+ editor.run(jupyter_height=600)
638
+
639
+ def create_3D_environment(self, env_3D):
640
+ for component in self.component_list("all"):
641
+ if hasattr(component, "get_polygon_3D"):
642
+ env_3D.add_polygon_3D(component.get_polygon_3D())
643
+
644
+ def show_3D(self):
645
+ env_3D = Environment_3D()
646
+ self.create_3D_environment(env_3D)
647
+ env_3D.show(polygons_type="initial")
648
+
649
+ def show_3D_shadows(self, date):
650
+ env_3D = Environment_3D()
651
+ self.create_3D_environment(env_3D)
652
+ file_met = self.parameter("simulation_file_met").component
653
+ cos = file_met.sun_cosines(date)
654
+ if len(cos) == 3:
655
+ env_3D.calculate_shadows(cos)
656
+ env_3D.show(polygons_type="Building_shadows")
657
+ else:
658
+ self._sim_.message(Message(date.strftime("%H:%M, %d/%m/%Y") + " is night", "WARNING"))
659
+
660
+ def show_3D_shadows_animation(self, date):
661
+ env_3D = Environment_3D()
662
+ self.create_3D_environment(env_3D)
663
+ file_met = self.parameter("simulation_file_met").component
664
+ texts = []
665
+ cosines = []
666
+ for hour in range(24):
667
+ new_date = date.replace(hour=hour, minute=0, second=0)
668
+ cos = file_met.sun_cosines(new_date)
669
+ if len(cos) == 3: # Day time
670
+ texts.append(new_date.strftime("%H:%M, %d/%m/%Y"))
671
+ cosines.append(cos)
672
+ env_3D.show_animation(texts, cosines, polygons_type="Building_shadows")
673
+
674
+