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
« 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
9class PostprocessingUtils:
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
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
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
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')
64 return res_df
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
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
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()
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()
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 )
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 }