Coverage for teaser/logic/buildingobjects/calculation/aixlib.py: 96%

101 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2025-04-29 16:01 +0000

1"""This module includes AixLib calculation class.""" 

2 

3import teaser.logic.utilities as utilities 

4from itertools import cycle, islice 

5import os 

6import pandas as pd 

7 

8 

9class AixLib(object): 

10 """Class to calculate parameters for AixLib output. 

11 

12 This class holds functions to sort and partly rewrite zone and building 

13 attributes specific for AixLib MultizoneEquipped 

14 simulation. This includes the export of boundary conditions and AHU 

15 operation values. 

16 

17 Parameters 

18 ---------- 

19 parent: Building() 

20 The parent class of this object, the Building the attributes are 

21 calculated for. (default: None) 

22 

23 

24 Attributes 

25 ---------- 

26 file_set_t : str 

27 Filename for set temperature file 

28 file_ahu : str 

29 Filename for AHU boundary conditions file 

30 file_internal_gains : str 

31 Filename for internal gains file 

32 version : str 

33 Used AixLib version, default should always be current main version 

34 of GitHub 

35 besmod_version : str 

36 Used BESMod version vor export_besmod, default should always be current main version 

37 of GitHub 

38 total_surface_area : float [m2] 

39 This is the total surface area of the building for interior and 

40 exterior surfaces. That includes: OuterWalls, Rooftops, GroundFloors, 

41 Windows for exterior surfaces, and InnerWalls, Ceilings, Floors for 

42 interior walls. 

43 consider_heat_capacity : bool 

44 decides whether air capacity is considered or not for all thermal 

45 zones in the building. Default is True, you need to export your 

46 model again if changing this value 

47 use_set_back : bool 

48 True if night set back should be used. In this case the function 

49 considers heating_time and temp_set_back defined in 

50 use_conditions of zone. Default is True, you need to export your 

51 model again if changing this value 

52 use_set_point_temperature_profile_heating : bool 

53 Standard is False. True if the set_point temperature profile heating 

54 should be used for the export. Then, the night set back and everything 

55 except the set point profile will be ignored. 

56 

57 """ 

58 

59 def __init__(self, parent): 

60 """Construct AixLib.""" 

61 self.parent = parent 

62 

63 self.file_set_t_heat = "TsetHeat_" + self.parent.name + ".txt" 

64 self.file_set_t_cool = "TsetCool_" + self.parent.name + ".txt" 

65 self.file_ahu = "AHU_" + self.parent.name + ".txt" 

66 self.file_internal_gains = "InternalGains_" + self.parent.name + ".txt" 

67 self.version = "2.1.1" 

68 self.besmod_version = "0.6.0" 

69 self.total_surface_area = None 

70 self.consider_heat_capacity = True 

71 self.use_set_back = True 

72 self.use_set_point_temperature_profile_heating = False 

73 self.use_set_back_cool = False 

74 

75 def calc_auxiliary_attr(self): 

76 """Call function to calculate all auxiliary attributes for AixLib.""" 

77 self._calc_surface_area() 

78 

79 def _calc_surface_area(self): 

80 """Calculate the total surface area of all surfaces.""" 

81 surf_area_temp = 0.0 

82 for zone in self.parent.thermal_zones: 

83 if type(zone.model_attr).__name__ == "OneElement": 

84 surf_area_temp += zone.model_attr.area_ow + zone.model_attr.area_win 

85 elif type(zone.model_attr).__name__ == "TwoElement": 

86 surf_area_temp += ( 

87 zone.model_attr.area_ow 

88 + zone.model_attr.area_iw 

89 + zone.model_attr.area_win 

90 ) 

91 elif type(zone.model_attr).__name__ == "ThreeElement": 

92 surf_area_temp += ( 

93 zone.model_attr.area_ow 

94 + zone.model_attr.area_iw 

95 + zone.model_attr.area_gf 

96 + zone.model_attr.area_win 

97 ) 

98 elif type(zone.model_attr).__name__ == "FourElement": 

99 surf_area_temp += ( 

100 zone.model_attr.area_ow 

101 + zone.model_attr.area_iw 

102 + zone.model_attr.area_gf 

103 + zone.model_attr.area_rt 

104 + zone.model_attr.area_win 

105 ) 

106 elif type(zone.model_attr).__name__ == "FiveElement": 

107 surf_area_temp += ( 

108 zone.model_attr.area_ow 

109 + zone.model_attr.area_iw 

110 + zone.model_attr.area_gf 

111 + zone.model_attr.area_rt 

112 + zone.model_attr.area_win 

113 + sum(zone.model_attr.area_nzb) 

114 ) 

115 

116 self.total_surface_area = surf_area_temp 

117 

118 def modelica_set_temp(self, path=None): 

119 """Create .txt file for set temperatures for heating. 

120 

121 This function creates a txt for set temperatures of each 

122 zone, that are all saved into one matrix. 

123 

124 Parameters 

125 ---------- 

126 path : str 

127 optional path, when matfile is exported separately 

128 

129 """ 

130 if path is None: 

131 path = utilities.get_default_path() 

132 else: 

133 pass 

134 

135 utilities.create_path(path) 

136 path = os.path.join(path, self.file_set_t_heat) 

137 

138 export = pd.DataFrame( 

139 index=pd.date_range("2019-01-01 00:00:00", periods=8760, freq="h") 

140 .to_series() 

141 .dt.strftime("%m-%d %H:%M:%S"), 

142 columns=[zone.name for zone in self.parent.thermal_zones], 

143 ) 

144 

145 for zone_count in self.parent.thermal_zones: 

146 export[zone_count.name] = zone_count.use_conditions.schedules[ 

147 "heating_profile" 

148 ] 

149 

150 export.index = [(i + 1) * 3600 for i in range(8760)] 

151 self._delete_file(path=path) 

152 with open(path, "a") as f: 

153 f.write("#1\n") 

154 f.write( 

155 "double Tset({}, {})\n".format(8760, len(self.parent.thermal_zones) + 1) 

156 ) 

157 export.to_csv(f, sep="\t", header=False, index_label=False) 

158 

159 def modelica_set_temp_cool(self, path=None): 

160 """Create .txt file for set temperatures cooling. 

161 

162 This function creates a txt for set temperatures for cooling 

163 of each zone, that are all saved into one matrix. 

164 

165 

166 Parameters 

167 ---------- 

168 path : str 

169 optional path, when matfile is exported separately 

170 

171 """ 

172 if path is None: 

173 path = utilities.get_default_path() 

174 else: 

175 pass 

176 

177 utilities.create_path(path) 

178 path = os.path.join(path, self.file_set_t_cool) 

179 

180 export = pd.DataFrame( 

181 index=pd.date_range("2019-01-01 00:00:00", periods=8760, freq="h") 

182 .to_series() 

183 .dt.strftime("%m-%d %H:%M:%S"), 

184 columns=[zone.name for zone in self.parent.thermal_zones], 

185 ) 

186 

187 for zone_count in self.parent.thermal_zones: 

188 export[zone_count.name] = zone_count.use_conditions.schedules[ 

189 "cooling_profile" 

190 ] 

191 

192 export.index = [(i + 1) * 3600 for i in range(8760)] 

193 self._delete_file(path=path) 

194 with open(path, "a") as f: 

195 f.write("#1\n") 

196 f.write( 

197 "double Tset({}, {})\n".format(8760, len(self.parent.thermal_zones) + 1) 

198 ) 

199 export.to_csv(f, sep="\t", header=False, index_label=False) 

200 

201 def modelica_AHU_boundary(self, path=None): 

202 """Create .txt file for AHU boundary conditions (building). 

203 

204 This function creates a txt for building AHU boundary 

205 conditions 

206 

207 1. Column : time step 

208 2. Column : desired AHU profile temperature 

209 3. Column : Desired minimal relative humidity 

210 4. Column : desired maximal relative humidity 

211 5. Column : AHU status (On/Off) 

212 

213 Parameters 

214 ---------- 

215 path : str 

216 optional path, when matfile is exported separately 

217 

218 Attributes 

219 ---------- 

220 temperature_profile : [float] 

221 timeline of temperatures requirements for AHU simulation 

222 min_relative_humidity_profile : [float] 

223 timeline of relative humidity requirements for AHU simulation 

224 max_relative_humidity_profile : [float] 

225 timeline of relative humidity requirements for AHU simulation 

226 v_flow_profile : [int] 

227 timeline of desired relative v_flow of the AHU simulation (0..1) 

228 

229 """ 

230 if path is None: 

231 path = utilities.get_default_path() 

232 else: 

233 pass 

234 

235 utilities.create_path(path) 

236 path = os.path.join(path, self.file_ahu) 

237 

238 if self.parent.with_ahu is True: 

239 export = self.parent.central_ahu.schedules 

240 else: # Dummy values for Input Table 

241 export = pd.DataFrame( 

242 index=pd.date_range("2019-01-01 00:00:00", periods=8760, freq="h") 

243 .to_series() 

244 .dt.strftime("%m-%d %H:%M:%S") 

245 ) 

246 

247 export["temperature_profile"] = list(islice(cycle([293.15, 293.15]), 8760)) 

248 export["min_relative_humidity_profile"] = list(islice(cycle([0, 0]), 8760)) 

249 export["max_relative_humidity_profile"] = list(islice(cycle([1, 1]), 8760)) 

250 export["v_flow_profile"] = list(islice(cycle([0, 1]), 8760)) 

251 

252 export.index = [(i + 1) * 3600 for i in range(8760)] 

253 self._delete_file(path=path) 

254 with open(path, "a") as f: 

255 f.write("#1\n") 

256 f.write("double AHU({}, {})\n".format(8760, 5)) 

257 export.to_csv(f, sep="\t", header=False, index_label=False) 

258 

259 def modelica_gains_boundary(self, path=None): 

260 """Create .txt file for internal gains boundary conditions. 

261 

262 This function creates a matfile (-v4) for building internal gains 

263 boundary conditions. It collects all internal gain profiles of the 

264 zones and stores them into one file. The file is extended for each 

265 zone. Only applicable if zones are defined 

266 

267 1. Column : time step 

268 2,5,8,... Column : profile_persons 

269 3,6,9,... Column : profile_machines 

270 4,7,10,... Column : profile_lighting 

271 

272 Notes 

273 ----- 

274 When time line is created, we need to add a 0 to first element of 

275 all boundaries. This is due to to expected format in Modelica. 

276 

277 Parameters 

278 ---------- 

279 path : str 

280 optional path, when matfile is exported separately 

281 

282 """ 

283 if path is None: 

284 path = utilities.get_default_path() 

285 else: 

286 pass 

287 

288 utilities.create_path(path) 

289 path = os.path.join(path, self.file_internal_gains) 

290 

291 export = pd.DataFrame( 

292 index=pd.date_range("2019-01-01 00:00:00", periods=8760, freq="h") 

293 .to_series() 

294 .dt.strftime("%m-%d %H:%M:%S") 

295 ) 

296 

297 for zone_count in self.parent.thermal_zones: 

298 export[ 

299 "person_{}".format(zone_count.name) 

300 ] = zone_count.use_conditions.schedules["persons_profile"] 

301 export[ 

302 "machines_{}".format(zone_count.name) 

303 ] = zone_count.use_conditions.schedules["machines_profile"] 

304 export[ 

305 "lighting_{}".format(zone_count.name) 

306 ] = zone_count.use_conditions.schedules["lighting_profile"] 

307 

308 export.index = [(i + 1) * 3600 for i in range(8760)] 

309 self._delete_file(path=path) 

310 with open(path, "a") as f: 

311 f.write("#1\n") 

312 f.write( 

313 "double Internals({}, {})\n".format( 

314 8760, (len(self.parent.thermal_zones) * 3 + 1) 

315 ) 

316 ) 

317 export.to_csv(f, sep="\t", header=False, index_label=False) 

318 

319 def _delete_file(self, path): 

320 """Delete a file before new information is written to it. 

321 

322 If a building with the exact name and project name is generated, we need to make 

323 sure to delete the old information in the text files. This helper function is a 

324 wrapper to delete a file with given filepath. 

325 

326 Parameters: 

327 ----------- 

328 path : str 

329 Absolute path to the file to be deleted. 

330 

331 """ 

332 try: 

333 os.remove(path) 

334 except OSError: 

335 pass