Coverage for bim2sim/plugins/PluginEnergyPlus/bim2sim_energyplus/utils/utils_postprocessing.py: 0%

133 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-10-01 10:24 +0000

1import pandas as pd 

2from matplotlib import pyplot as plt 

3import datetime as dt 

4from eppy.function_helpers import azimuth 

5from eppy.geometry import surface as g_surface 

6 

7 

8 

9class PostprocessingUtils: 

10 

11 @staticmethod 

12 def _string_to_datetime(date_str): 

13 """ 

14 Converts a date string in the format MM:DD hh:mm:ss into a datetime 

15 object. 

16 :param date_str: A date string in the specified format. 

17 :return: The converted datetime object. 

18 """ 

19 date_str = date_str.strip() 

20 # datetime_df = None 

21 

22 if date_str[7:9] != '24': 

23 timestamp = pd.to_datetime(date_str, format='%m/%d %H:%M:%S') 

24 else: 

25 # If the time is 24, set it to 0 and increment day by 1 

26 date_str = date_str[0:7] + '00' + date_str[9:] 

27 timestamp = pd.to_datetime(date_str, format='%m/%d %H:%M:%S') +\ 

28 pd.Timedelta(days=1) 

29 return timestamp 

30 

31 @staticmethod 

32 def _extract_cols_from_df(df, col_name_part): 

33 """ 

34 extract columns from an energyplus result dataframe based on parts 

35 of the column name 

36 """ 

37 col = [col for col in df.columns if col_name_part in col] 

38 return_df = df[col].copy() 

39 return_df["Date/Time"] = df["Date/Time"].copy() 

40 return_df = return_df.set_index("Date/Time", drop=True).dropna() 

41 return return_df 

42 

43 @staticmethod 

44 def read_csv_and_format_datetime(csv_name): 

45 res_df = pd.read_csv(csv_name) 

46 res_df["Date/Time"] = res_df["Date/Time"].apply( 

47 PostprocessingUtils._string_to_datetime) 

48 # correct the year based on the length to something useful. This is 

49 # needed to make plotting easier in the later processes 

50 if len(res_df["Date/Time"]) > 8761: 

51 new_year = 2020 

52 else: 

53 new_year = 2021 

54 original_year = res_df["Date/Time"][0].year 

55 res_df["Date/Time"] = res_df["Date/Time"].map( 

56 lambda x: x.replace(year=new_year) if x.year == original_year 

57 else x.replace(year=new_year+1) 

58 ) 

59 # set the index 

60 res_df = res_df.set_index('Date/Time', drop=True) 

61 # drops the year and reformats 

62 # res_df['Date/Time'] = res_df['Date/Time'].dt.strftime('%m/%d-%H:%M:%S') 

63 

64 return res_df 

65 

66 @staticmethod 

67 def shift_dataframe_to_midnight(df): 

68 # Shift the datetime index backward by one hour 

69 df.index = df.index - pd.DateOffset(hours=1) 

70 return df 

71 

72 @staticmethod 

73 def export_df_for_webtool(csv_name): 

74 res_df = pd.read_csv(csv_name) 

75 res_df["Date/Time"] = res_df["Date/Time"].apply( 

76 PostprocessingUtils._string_to_datetime) 

77 res_df['Date/Time'] = res_df['Date/Time'].dt.strftime('%m-%d ' 

78 '%H:%M:%S') # drops the year 

79 export_df = pd.DataFrame(index=res_df['Date/Time']) 

80 zone_cooling_rates_W = PostprocessingUtils._extract_cols_from_df( 

81 res_df, 'Zone Ideal Loads Zone Total Cooling Rate [W]') 

82 zone_heating_rates_W = PostprocessingUtils._extract_cols_from_df( 

83 res_df, 'Zone Ideal Loads Zone Total Heating Rate [W]') 

84 export_df['heat_demand_kW'] = zone_heating_rates_W.sum(axis=1) / 1000 

85 export_df['cooling_demand_kW'] = zone_cooling_rates_W.sum(axis=1) / \ 

86 1000 

87 return export_df 

88 

89 @staticmethod 

90 def _visualize_results(csv_name, period="week", number=28, date=False): 

91 """ 

92 Plot Zone Mean Air Temperature (Hourly) vs Outdoor Temperature per 

93 zone and as an overview on all zones. 

94 :param csv_name: path to energyplus outputs (eplusout.csv) 

95 :param period: choose plotting period ( 

96 "year"/"month"/"week"/"day"/"date") 

97 :param number: choose number of day or week (0...365 (day) or 0...52 

98 (week)) 

99 :param date: only required if period == date. enter date in format 

100 date=[int(month), int(day)] 

101 :return: 

102 """ 

103 res_df = pd.read_csv(csv_name) 

104 res_df["Date/Time"] = res_df["Date/Time"].apply( 

105 PostprocessingUtils._string_to_datetime) 

106 # df = res_df.loc[:, ~res_df.columns.str.contains('Surface Inside 

107 # Face Temperature'] 

108 zone_mean_air = PostprocessingUtils._extract_cols_from_df(res_df, 

109 "Zone Mean " 

110 "Air " 

111 "Temperature") 

112 ideal_loads = PostprocessingUtils._extract_cols_from_df(res_df, 

113 "IDEAL LOADS " 

114 "AIR " 

115 "SYSTEM:Zone " 

116 "Ideal Loads " 

117 "Zone " 

118 "Sensible") 

119 equip_rate = PostprocessingUtils._extract_cols_from_df(res_df, 

120 "Zone " 

121 "Electric " 

122 "Equipment " 

123 "Convective " 

124 "Heating Rate") 

125 people_rate = PostprocessingUtils._extract_cols_from_df(res_df, 

126 "Zone People " 

127 "Convective " 

128 "Heating Rate") 

129 rad_dir = PostprocessingUtils._extract_cols_from_df(res_df, 

130 "Site Direct " 

131 "Solar Radiation " 

132 "Rate per Area") 

133 # rad_dir_h = rad_dir.resample('1h').mean() 

134 temp = PostprocessingUtils._extract_cols_from_df(res_df, 

135 "Outdoor Air " 

136 "Drybulb " 

137 "Temperature [C](" 

138 "Hourly)") 

139 t_mean = temp.resample('24h').mean() 

140 zone_id_list = [] 

141 for col in zone_mean_air.columns: 

142 z_id = col.partition(':') 

143 if z_id[0] not in zone_id_list: 

144 zone_id_list.append(z_id[0]) 

145 if period == "year": 

146 for col in zone_mean_air.columns: 

147 ax = zone_mean_air.plot(y=[col], figsize=(10, 5), grid=True) 

148 # temp.plot(ax=ax) 

149 t_mean.plot(ax=ax) 

150 plt.show() 

151 axc = zone_mean_air.iloc[:].plot(figsize=(10, 5), grid=True) 

152 t_mean.iloc[:].plot(ax=axc) 

153 plt.show() 

154 return 

155 elif period == "month": 

156 for col in zone_mean_air.columns: 

157 ax = zone_mean_air[zone_mean_air.index.month == number].plot( 

158 y=[col], figsize=(10, 5), grid=True) 

159 # temp.plot(ax=ax) 

160 temp[temp.index.month == number].plot(ax=ax) 

161 plt.show() 

162 axc = zone_mean_air[zone_mean_air.index.month == number].plot( 

163 figsize=(10, 5), grid=True) 

164 temp[temp.index.month == number].plot(ax=axc) 

165 plt.show() 

166 return 

167 elif period == "date": 

168 month = date[0] 

169 day = date[1] 

170 for col in zone_mean_air.columns: 

171 ax = zone_mean_air.loc[ 

172 ((zone_mean_air.index.month == month) 

173 & (zone_mean_air.index.day == day))] \ 

174 .plot(y=[col], figsize=(10, 5), grid=True) 

175 # temp.plot(ax=ax) 

176 temp.loc[((temp.index.month == month) 

177 & (temp.index.day == day))].plot(ax=ax) 

178 plt.show() 

179 axc = zone_mean_air.loc[((zone_mean_air.index.month == month) 

180 & (zone_mean_air.index.day == day))] \ 

181 .plot(figsize=(10, 5), grid=True) 

182 temp.loc[((temp.index.month == month) 

183 & (temp.index.day == day))].plot(ax=axc) 

184 plt.show() 

185 return 

186 elif period == "week": 

187 min = number * 168 

188 max = (number + 1) * 168 

189 elif period == "day": 

190 min = number * 24 

191 max = (number + 1) * 24 

192 for col in zone_mean_air.columns: 

193 ax = zone_mean_air.iloc[min:max].plot(y=[col], figsize=(10, 

194 5), grid=True) 

195 # temp.plot(ax=ax) 

196 temp.iloc[min:max].plot(ax=ax) 

197 plt.show() 

198 axc = zone_mean_air.iloc[min:max].plot(figsize=(10, 5), grid=True) 

199 temp.iloc[min:max].plot(ax=axc) 

200 plt.show() 

201 

202 for zid in zone_id_list: 

203 fig, (ax1, ax2) = plt.subplots(2, sharex=True, figsize=(10, 8)) 

204 fig.suptitle("Zone " + zid, y=1.00) 

205 z_col = [col for col in ideal_loads.columns if zid in col] 

206 zma_col = [col for col in zone_mean_air.columns if zid in col] 

207 ideal_loads[z_col].iloc[min:max].plot(ax=ax1, grid=True) 

208 # ax1b = ax1.twinx() 

209 # rad_dir_h.iloc[min:max].plot(ax=ax1b) 

210 zone_mean_air[zma_col].iloc[min:max].plot(ax=ax2, grid=True, 

211 color='green') 

212 temp.iloc[min:max].plot(ax=ax2, color='black') 

213 ax1.set_title("Loads") 

214 ax2.set_title("Temperatures") 

215 ax1.autoscale() 

216 ax2.autoscale() 

217 fig.tight_layout(rect=[0, 0.03, 1, 0.8]) 

218 plt.show() 

219 

220 @staticmethod 

221 def true_azimuth(ddtt): 

222 """true azimuth of the surface""" 

223 idf = ddtt.theidf 

224 coord_system = idf.idfobjects["GlobalGeometryRules".upper()][0].Coordinate_System 

225 if coord_system.lower() == "relative": 

226 zone_name = ddtt.Zone_Name 

227 bldg_north = idf.idfobjects["Building".upper()][0].North_Axis 

228 zone_rel_north = idf.getobject("Zone".upper(), 

229 zone_name).Direction_of_Relative_North 

230 surf_azimuth = azimuth(ddtt) 

231 return g_surface.true_azimuth(bldg_north, zone_rel_north, surf_azimuth) 

232 elif coord_system.lower() in ("world", "absolute"): 

233 # NOTE: "absolute" is not supported in v9.3.0 

234 return azimuth(ddtt) 

235 else: 

236 raise ValueError( 

237 "'{:s}' is no valid value for 'Coordinate System'".format(coord_system) 

238 ) 

239 

240 azimuth_orientations = { 

241 0: 'N', 

242 45: 'NE', 

243 90: 'E', 

244 135: 'SE', 

245 180: 'S', 

246 225: 'SW', 

247 270: 'W', 

248 315: 'NW' 

249 }