Coverage for teaser/data/output/aixlib_output.py: 93%
100 statements
« prev ^ index » next coverage.py v7.4.4, created at 2025-04-29 16:01 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2025-04-29 16:01 +0000
1"""This module contains function for AixLib model generation"""
3import os
4import warnings
5import shutil
6from mako.template import Template
7from mako.lookup import TemplateLookup
8import teaser.logic.utilities as utilities
9import teaser.data.output.modelica_output as modelica_output
12def export_multizone(
13 buildings,
14 prj,
15 path=None,
16 use_postprocessing_calc=False,
17 export_vars=None,
18 custom_multizone_template_path=None):
19 """Exports models for AixLib library
21 Exports a building for
22 AixLib.ThermalZones.ReducedOrder.Multizone.MultizoneEquipped models
23 using the ThermalZoneEquipped and supporting models, like tables and weather
24 model. Depending on chosen calculation method the parameter set to 1,2,
25 3 or 4 element model. By default it uses the correction for solar
26 glazing (corG) and decoupled heat conduction through windows (
27 merge_windows=False). In contrast to versions < 0.5 TEASER now does not
28 support any other model options, as we observed no need, since single
29 ThermalZones are identical with IBPSA models. If you miss one of the
30 old options please contact us.
32 This function uses Mako Templates specified in
33 data.output.modelicatemplates.AixLib
35 Parameters
36 ----------
38 buildings : list of instances of Building
39 list of TEASER instances of a Building that is exported to a AixLib
40 MultizoneEquipped models. If you want to export a single building,
41 please pass it over as a list containing only that building.
42 prj : instance of Project
43 Instance of TEASER Project object to access Project related
44 information, e.g. name or version of used libraries
45 path : string
46 if the Files should not be stored in default output path of TEASER,
47 an alternative path can be specified as a full path
48 use_postprocessing_calc : bool
49 If activated the exported model will use the multizonePostProcessing
50 to calculate common outputs for simulation time like total heating
51 demands. Only supported for Aixlib. Default is False.
52 export_vars : str
53 Holds the string about which variables to export following the
54 __Dymola_selection syntax.
55 custom_multizone_template_path : str
56 if a custom template for writing the multizone model should be used,
57 its path can be specified as a full path
59 Attributes
60 ----------
62 lookup : TemplateLookup object
63 Instance of mako.TemplateLookup to store general functions for templates
64 zone_template_1 : Template object
65 Template for ThermalZoneRecord using 1 element model
66 zone_template_2 : Template object
67 Template for ThermalZoneRecord using 2 element model
68 zone_template_3 : Template object
69 Template for ThermalZoneRecord using 3 element model
70 zone_template_4 : Template object
71 Template for ThermalZoneRecord using 4 element model
72 zone_template_5 : Template object
73 Template for ThermalZoneRecord using 5 element model
74 model_template : Template object
75 Template for MultiZone model
76 """
78 if path is None:
79 path = utilities.get_full_path("")
81 lookup = TemplateLookup(directories=[utilities.get_full_path(
82 os.path.join('data', 'output', 'modelicatemplate'))])
83 zone_template_1 = Template(
84 filename=utilities.get_full_path(
85 "data/output/modelicatemplate/AixLib"
86 "/AixLib_ThermalZoneRecord_OneElement"),
87 lookup=lookup)
88 zone_template_2 = Template(
89 filename=utilities.get_full_path(
90 "data/output/modelicatemplate/AixLib"
91 "/AixLib_ThermalZoneRecord_TwoElement"),
92 lookup=lookup)
93 zone_template_3 = Template(
94 filename=utilities.get_full_path(
95 "data/output/modelicatemplate/AixLib"
96 "/AixLib_ThermalZoneRecord_ThreeElement"),
97 lookup=lookup)
98 zone_template_4 = Template(
99 filename=utilities.get_full_path(
100 "data/output/modelicatemplate/AixLib"
101 "/AixLib_ThermalZoneRecord_FourElement"),
102 lookup=lookup)
103 zone_template_5 = Template(
104 filename=utilities.get_full_path(
105 "data/output/modelicatemplate/AixLib"
106 "/AixLib_ThermalZoneRecord_FiveElement"),
107 lookup=lookup)
108 if custom_multizone_template_path:
109 model_template = Template(
110 filename=custom_multizone_template_path,
111 lookup=lookup)
112 else:
113 model_template = Template(
114 filename=utilities.get_full_path(
115 "data/output/modelicatemplate/AixLib/AixLib_Multizone"),
116 lookup=lookup)
117 test_script_template = Template(
118 filename=utilities.get_full_path(
119 "data/output/modelicatemplate/modelica_test_script"),
120 lookup=lookup)
122 dir_resources = utilities.create_path(os.path.join(path, "Resources"))
123 dir_scripts = utilities.create_path(os.path.join(dir_resources, "Scripts"))
124 dir_dymola = utilities.create_path(os.path.join(dir_scripts, "Dymola"))
126 uses = [
127 'Modelica(version="' + prj.modelica_info.version + '")',
128 'AixLib(version="' + prj.buildings[-1].library_attr.version + '")']
129 modelica_output.create_package(
130 path=path,
131 name=prj.name,
132 uses=uses)
133 modelica_output.create_package_order(
134 path=path,
135 package_list=buildings,
136 extra=None)
137 if not prj.weather_file_path.startswith("modelica:"):
138 modelica_output.copy_weather_data(prj.weather_file_path, path)
139 if prj.t_soil_mode == 3:
140 if not prj.t_soil_file_path.startswith("modelica:"):
141 modelica_output.copy_weather_data(prj.t_soil_file_path, path)
143 for i, bldg in enumerate(buildings):
145 ass_error = "You chose IBPSA calculation, " \
146 "but want to export AixLib models, " \
147 "this is not possible"
149 assert bldg.used_library_calc == 'AixLib', ass_error
151 bldg_path = os.path.join(path, bldg.name)
152 utilities.create_path(bldg_path)
153 utilities.create_path(os.path.join(bldg_path, bldg.name + "_DataBase"))
154 bldg.library_attr.modelica_set_temp(path=bldg_path)
155 bldg.library_attr.modelica_set_temp_cool(path=bldg_path)
156 bldg.library_attr.modelica_AHU_boundary(
157 path=bldg_path)
158 bldg.library_attr.modelica_gains_boundary(
159 path=bldg_path)
161 modelica_output.create_package(path=bldg_path, name=bldg.name, within=bldg.parent.name)
162 modelica_output.create_package_order(
163 path=bldg_path,
164 package_list=[bldg],
165 extra=[bldg.name + "_DataBase"])
167 if bldg.building_id is None:
168 bldg.building_id = i
169 else:
170 try:
171 bldg.building_id = int(bldg.building_id)
172 except UserWarning:
173 warnings.warn("Cannot convert building_id to integer, "
174 "is set to ", i, "which is the enumeration "
175 "number of the building in "
176 "the project list.")
177 bldg.building_id = i
178 with open(os.path.join(bldg_path, bldg.name + ".mo"), 'w') as out_file:
180 out_file.write(model_template.render_unicode(
181 bldg=bldg,
182 weather=bldg.parent.weather_file_path,
183 modelica_info=bldg.parent.modelica_info,
184 use_postprocessing_calc=use_postprocessing_calc,
185 export_vars=export_vars))
186 out_file.close()
188 _help_test_script(bldg, dir_dymola, test_script_template)
190 zone_path = os.path.join(bldg_path, bldg.name + "_DataBase")
192 for zone in bldg.thermal_zones:
194 with open(os.path.join(zone_path, bldg.name + '_' + zone.name + '.mo'),
195 'w') as out_file:
196 if type(zone.model_attr).__name__ == "OneElement":
197 out_file.write(zone_template_1.render_unicode(zone=zone))
198 elif type(zone.model_attr).__name__ == "TwoElement":
199 out_file.write(zone_template_2.render_unicode(zone=zone))
200 elif type(zone.model_attr).__name__ == "ThreeElement":
201 out_file.write(zone_template_3.render_unicode(zone=zone))
202 elif type(zone.model_attr).__name__ == "FourElement":
203 out_file.write(zone_template_4.render_unicode(zone=zone))
204 elif type(zone.model_attr).__name__ == "FiveElement":
205 out_file.write(zone_template_5.render_unicode(zone=zone))
207 out_file.close()
209 modelica_output.create_package(
210 path=zone_path,
211 name=bldg.name + '_DataBase',
212 within=prj.name + '.' + bldg.name)
213 modelica_output.create_package_order(
214 path=zone_path,
215 package_list=bldg.thermal_zones,
216 addition=bldg.name + "_",
217 extra=None)
219 _copy_script_unit_tests(os.path.join(dir_scripts, "runUnitTests.py"))
220 _copy_reference_results(dir_resources, prj)
222 print("Exports can be found here:")
223 print(path)
226def _copy_reference_results(dir_resources, prj):
227 """Copy reference results to modelica output.
229 Parameters
230 ----------
231 dir_resources : str
232 Resources directory of the modelica output
233 prj : teaser.project.Project
234 Project to be exported
235 """
237 if prj.dir_reference_results is not None:
238 dir_ref_out = os.path.join(dir_resources, "ReferenceResults")
239 if not os.path.exists(dir_ref_out):
240 os.mkdir(dir_ref_out)
241 dir_ref_out_dymola = os.path.join(dir_ref_out, "Dymola")
242 if not os.path.exists(dir_ref_out_dymola):
243 os.mkdir(dir_ref_out_dymola)
244 for filename in os.listdir(prj.dir_reference_results):
245 if filename.endswith(".txt"):
246 shutil.copy2(
247 os.path.join(prj.dir_reference_results, filename),
248 os.path.join(dir_ref_out_dymola, filename)
249 )
252def _help_test_script(bldg, dir_dymola, test_script_template):
253 """Create a test script for regression testing with BuildingsPy
255 Parameters
256 ----------
257 bldg : teaser.logic.buildingobjects.building.Building
258 Building for which test script is created
259 dir_dymola : str
260 Output directory for Dymola scripts
261 test_script_template : mako.template.Template
262 Template for the test script
264 Returns
265 -------
266 dir_scripts : str
267 Path to the scripts directory
268 """
270 dir_building = os.path.join(dir_dymola, bldg.name)
271 if not os.path.exists(dir_building):
272 os.mkdir(dir_building)
273 with open(os.path.join(dir_building, bldg.name + ".mos"), 'w') as out_file:
275 names_variables = []
276 for i, zone in enumerate(bldg.thermal_zones):
277 names_variables.append(f"multizone.PHeater[{i+1}]")
278 names_variables.append(f"multizone.PCooler[{i+1}]")
279 names_variables.append(f"multizone.TAir[{i+1}]")
280 out_file.write(test_script_template.render_unicode(
281 project=bldg.parent,
282 bldg=bldg,
283 stop_time=3600 * 24 * 365,
284 names_variables=names_variables,
285 ))
286 out_file.close()
289def _copy_script_unit_tests(destination_path):
290 """Copies the script to run the unit tests.
292 Parameters
293 ----------
294 destination_path : str
295 path of where the weather file should be placed
296 """
298 source_path = utilities.get_full_path("data/output/runUnitTests.py")
299 shutil.copy2(source_path, destination_path)