Coverage for bim2sim/plugins/PluginEnergyPlus/bim2sim_energyplus/task/ep_idf_postprocessing.py: 0%

76 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-03-12 17:09 +0000

1import json 

2from pathlib import Path 

3 

4import pandas as pd 

5from geomeppy import IDF 

6 

7from bim2sim.elements.bps_elements import ThermalZone 

8from bim2sim.tasks.base import ITask 

9from bim2sim.utilities.common_functions import filter_elements 

10 

11 

12class IdfPostprocessing(ITask): 

13 """Idf Postprocessin task. 

14 

15 See run function for further details. """ 

16 reads = ('elements', 'idf', 'ifc_files', 'sim_results_path') 

17 

18 def run(self, elements: dict, idf: IDF, ifc_files: list, 

19 sim_results_path: Path): 

20 """EnergyPlus postprocessing for further evaluation and debugging. 

21 

22 This task holds export functions for further evaluation and 

23 debugging. Information on spaces and space boundaries are exported 

24 and the zone names are exported in json format. 

25 

26 Args: 

27 elements (dict): dictionary in the format dict[guid: element], 

28 holds preprocessed elements including space boundaries. 

29 idf (IDF): eppy idf, EnergyPlus input file. 

30 ifc_files (list): list of ifc files used in this project 

31 sim_results_path (Path): path to simulation results. 

32 """ 

33 

34 self.logger.info("IDF Postprocessing started...") 

35 

36 self._export_surface_areas(elements, idf) 

37 self._export_space_info(elements, idf) 

38 self._export_boundary_report(elements, idf, ifc_files) 

39 self.write_zone_names(idf, elements, 

40 sim_results_path / self.prj_name) 

41 self.logger.info("IDF Postprocessing finished!") 

42 

43 

44 @staticmethod 

45 def write_zone_names(idf, elements, exportpath: Path): 

46 """ 

47 Write a dictionary of the bim2sim ThermalZone names and usages. 

48 

49 This method creates a dict and exports it to a json file ( 

50 zone_dict.json) to the path defined in exportpath. This dict 

51 includes the zone name and the selected usage within bim2sim. All 

52 zones are considered that are created within the bim2sim elements. 

53 

54 Args: 

55 idf: eppy idf 

56 elements: bim2sim elements 

57 exportpath: base path to place the resulting zone_dict.json 

58 

59 """ 

60 zones = idf.idfobjects['ZONE'] 

61 zone_dict = {} 

62 ifc_zones = filter_elements(elements, ThermalZone) 

63 for zone in zones: 

64 usage = [z.usage for z in ifc_zones if z.guid == zone.Name] 

65 zone_dict.update({zone.Name: usage[0]}) 

66 

67 with open(exportpath / 'zone_dict.json', 'w+') as file: 

68 json.dump(zone_dict, file, indent=4) 

69 

70 def _export_surface_areas(self, elements, idf): 

71 """ combines sets of area sums and exports to csv """ 

72 area_df = pd.DataFrame( 

73 columns=["granularity", "ID", "long_name", "out_bound_cond", 

74 "area_wall", "area_ceiling", "area_floor", 

75 "area_roof", "area_window", "area_door", 

76 "total_surface_area", "total_opening_area"]) 

77 surf = [s for s in idf.idfobjects['BuildingSurface:Detailed'.upper()] 

78 if s.Construction_Name != 'Air Wall'] 

79 glazing = [g for g in idf.idfobjects[ 

80 'FenestrationSurface:Detailed'.upper()]] 

81 area_df = self._append_set_of_area_sum(area_df, granularity="GLOBAL", 

82 guid="GLOBAL", 

83 long_name="GLOBAL", 

84 surface=surf, glazing=glazing) 

85 zones = [z for z in idf.idfobjects['zone'.upper()]] 

86 zone_names = [z.Name for z in zones] 

87 

88 for z_name in zone_names: 

89 surf_zone = [s for s in surf if s.Zone_Name == z_name] 

90 surf_names = [s.Name for s in surf_zone] 

91 long_name = elements[z_name].ifc.LongName 

92 glazing_zone = [g for g in glazing for s_name in surf_names if 

93 g.Building_Surface_Name == s_name] 

94 area_df = self._append_set_of_area_sum(area_df, granularity="ZONE", 

95 guid=z_name, 

96 long_name=long_name, 

97 surface=surf_zone, 

98 glazing=glazing_zone) 

99 area_df.to_csv(path_or_buf=str(self.paths.export) + "/area.csv") 

100 

101 def _append_set_of_area_sum(self, area_df, granularity, guid, long_name, 

102 surface, glazing): 

103 """ generate set of area sums for a given granularity for outdoor, 

104 surface and adiabatic boundary conditions. 

105 Appends set to a given dataframe. 

106 """ 

107 surf_outdoors = [s for s in surface if s.Outside_Boundary_Condition == 

108 "Outdoors" or s.Outside_Boundary_Condition == "Ground"] 

109 surf_surface = [s for s in surface if s.Outside_Boundary_Condition == 

110 "Surface"] 

111 surf_adiabatic = [s for s in surface if s.Outside_Boundary_Condition == 

112 "Adiabatic"] 

113 glazing_outdoors = [g for g in glazing if 

114 g.Outside_Boundary_Condition_Object == ""] 

115 glazing_surface = [g for g in glazing if 

116 g.Outside_Boundary_Condition_Object != ""] 

117 glazing_adiabatic = [] 

118 

119 area_df = pd.concat([area_df, pd.DataFrame.from_records([ 

120 self._sum_of_surface_area( 

121 granularity=granularity, guid=guid, long_name=long_name, 

122 out_bound_cond="ALL", surface=surface, glazing=glazing), 

123 self._sum_of_surface_area( 

124 granularity=granularity, guid=guid, long_name=long_name, 

125 out_bound_cond="Outdoors",surface=surf_outdoors, 

126 glazing=glazing_outdoors), 

127 self._sum_of_surface_area( 

128 granularity=granularity, guid=guid, long_name=long_name, 

129 out_bound_cond="Surface", surface=surf_surface, 

130 glazing=glazing_surface), 

131 self._sum_of_surface_area( 

132 granularity=granularity, guid=guid, long_name=long_name, 

133 out_bound_cond="Adiabatic", surface=surf_adiabatic, 

134 glazing=glazing_adiabatic) 

135 ])], 

136 ignore_index=True) 

137 return area_df 

138 

139 @staticmethod 

140 def _sum_of_surface_area(granularity, guid, long_name, out_bound_cond, 

141 surface, glazing): 

142 """ generate row with sum of surface and opening areas to be appended 

143 to larger dataframe""" 

144 row = { 

145 "granularity": granularity, 

146 "ID": guid, 

147 "long_name": long_name, 

148 "out_bound_cond": out_bound_cond, 

149 "area_wall": sum(s.area for s in surface if s.Surface_Type == 

150 "Wall"), 

151 "area_ceiling": sum(s.area for s in surface if s.Surface_Type == 

152 "Ceiling"), 

153 "area_floor": sum(s.area for s in surface if s.Surface_Type == 

154 "Floor"), 

155 "area_roof": sum(s.area for s in surface if s.Surface_Type == 

156 "Roof"), 

157 "area_window": sum(g.area for g in glazing if g.Surface_Type == 

158 "Window"), 

159 "area_door": sum(g.area for g in glazing if g.Surface_Type == 

160 "Door"), 

161 "total_surface_area": sum(s.area for s in surface), 

162 "total_opening_area": sum(g.area for g in glazing) 

163 } 

164 return row 

165 

166 def _export_space_info(self, elements, idf): 

167 space_df = pd.DataFrame( 

168 columns=["ID", "long_name", "space_center", "space_volume"]) 

169 spaces = filter_elements(elements, 'ThermalZone') 

170 for space in spaces: 

171 space_df = pd.concat([space_df, pd.DataFrame.from_records([{ 

172 "ID": space.guid, 

173 "long_name": space.ifc.LongName, 

174 "space_center": space.space_center.XYZ().Coord(), 

175 "space_volume": space.space_shape_volume.m 

176 }])], 

177 ignore_index=True) 

178 space_df.to_csv(path_or_buf=str(self.paths.export) + "/space.csv") 

179 

180 def _export_boundary_report(self, elements, idf, ifc_files): 

181 """Export a report on the number of space boundaries. 

182 Creates a report as a DataFrame and exports it to csv. 

183 

184 Columns: 

185 IFC_SB_all: Number of IfcRelSpaceBoundary elements included in 

186 the given IFC files, 

187 IFC_SB_2a: Number of IfcRelSpaceBoundary elements included in 

188 the given IFC files of type 2a, 

189 IFC_SB_2b: Number of IfcRelSpaceBoundary elements included in 

190 the given IFC files of type 2b, 

191 BIM2SIM_SB_2b: Number of SpaceBoundary elements created within 

192 the bim2sim tool generated from gaps within the IfcSpaces, 

193 IDF_all: Total number of FENESTRATIONSURFACE:DETAILED and 

194 BUILDINGSURFACE:DETAILED elements in the resulting IDF, 

195 IDF_all_B: Total number of BUILDINGSURFACE:DETAILED elements in 

196 the resulting IDF, 

197 IDF_ADB: Number of BUILDINGSURFACE:DETAILED elements with 

198 adiabatic boundary conditions, 

199 IDF_SFB: Number of BUILDINGSURFACE:DETAILED elements with 

200 "surface" boundary conditions, 

201 IDF_ODB: Number of BUILDINGSURFACE:DETAILED elements with 

202 outdoor boundary conditions, 

203 IDF_GDB: Number of BUILDINGSURFACE:DETAILED elements with 

204 ground boundary conditions, 

205 IDF_VTB: Number of BUILDINGSURFACE:DETAILED elements with 

206 an air wall construction, 

207 IDF_all_F: Total number of FENESTRATIONSURFACE:DETAILED elements in 

208 the resulting IDF, 

209 IDF_ODF: Number of FENESTRATIONSURFACE:DETAILED elements in 

210 the resulting IDF without outside boundary condition object, 

211 IDF_INF: Total number of FENESTRATIONSURFACE:DETAILED elements in 

212 the resulting IDF with an outside boundary condition object. 

213 """ 

214 bound_count = pd.DataFrame( 

215 columns=["IFC_SB_all", "IFC_SB_2a", "IFC_SB_2b", "BIM2SIM_SB_2b", 

216 "IDF_all", "IDF_all_B", "IDF_ADB", "IDF_SFB", 

217 "IDF_ODB", "IDF_GDB", "IDF_VTB", "IDF_all_F", 

218 "IDF_ODF", "IDF_INF"]) 

219 ifc_bounds = [] 

220 for ifc in ifc_files: 

221 ifc_bounds.extend(ifc.file.by_type('IfcRelSpaceBoundary')) 

222 bounds_2b = filter_elements(elements, 'SpaceBoundary2B') 

223 idf_all_b = [s for s in idf.idfobjects["BUILDINGSURFACE:DETAILED"]] 

224 idf_adb = [s for s in idf.idfobjects["BUILDINGSURFACE:DETAILED"] 

225 if s.Outside_Boundary_Condition == "Adiabatic"] 

226 idf_sfb = [s for s in idf.idfobjects["BUILDINGSURFACE:DETAILED"] 

227 if s.Outside_Boundary_Condition == "Surface"] 

228 idf_odb = [s for s in idf.idfobjects["BUILDINGSURFACE:DETAILED"] 

229 if s.Outside_Boundary_Condition == "Outdoors"] 

230 idf_gdb = [s for s in idf.idfobjects["BUILDINGSURFACE:DETAILED"] 

231 if s.Outside_Boundary_Condition == "Ground"] 

232 idf_vtb = [s for s in idf.idfobjects["BUILDINGSURFACE:DETAILED"] 

233 if s.Construction_Name == "Air Wall"] 

234 idf_all_f = [f for f in idf.idfobjects["FENESTRATIONSURFACE:DETAILED"]] 

235 idf_odf = [f for f in idf.idfobjects["FENESTRATIONSURFACE:DETAILED"] if 

236 f.Outside_Boundary_Condition_Object == ''] 

237 idf_inf = [f for f in idf.idfobjects["FENESTRATIONSURFACE:DETAILED"] if 

238 f.Outside_Boundary_Condition_Object != ''] 

239 

240 bound_count = pd.concat([bound_count, pd.DataFrame.from_records([{ 

241 "IFC_SB_all": len(ifc_bounds), 

242 "IFC_SB_2a": len([b for b in ifc_bounds if b.Description == 

243 "2a"]), 

244 "IFC_SB_2b": len([b for b in ifc_bounds if b.Description == "2b"]), 

245 "BIM2SIM_SB_2b": len(bounds_2b), 

246 "IDF_all": len(idf_all_b) + len(idf_all_f), 

247 "IDF_all_B": len(idf_all_b), 

248 "IDF_ADB": len(idf_adb), 

249 "IDF_SFB": len(idf_sfb), 

250 "IDF_ODB": len(idf_odb), 

251 "IDF_GDB": len(idf_gdb), 

252 "IDF_VTB": len(idf_vtb), 

253 "IDF_all_F": len(idf_all_f), 

254 "IDF_ODF": len(idf_odf), 

255 "IDF_INF": len(idf_inf) 

256 }])], 

257 ignore_index=True) 

258 bound_count.to_csv( 

259 path_or_buf=str(self.paths.export) + "/bound_count.csv")