forked from pvlib/pvlib-python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathepw.py
312 lines (274 loc) · 16.9 KB
/
epw.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
"""
Import functions for EPW data files.
"""
import io
from urllib.request import urlopen, Request
import pandas as pd
def read_epw(filename, coerce_year=None):
r'''
Read an EPW file in to a pandas dataframe.
Note that values contained in the metadata dictionary are unchanged
from the EPW file.
EPW files are commonly used by building simulation professionals
and are widely available on the web. For example via:
https://energyplus.net/weather , http://climate.onebuilding.org or
http://www.ladybug.tools/epwmap/
Parameters
----------
filename : String
Can be a relative file path, absolute file path, or url.
coerce_year : int, optional
If supplied, the year of the data will be set to this value. This can
be a useful feature because EPW data is composed of data from
different years.
Warning: EPW files always have 365*24 = 8760 data rows;
be careful with the use of leap years.
Returns
-------
data : DataFrame
A pandas dataframe with the columns described in the table
below. For more detailed descriptions of each component, please
consult the EnergyPlus Auxiliary Programs documentation [1]_
metadata : dict
The site metadata available in the file.
See Also
--------
pvlib.iotools.parse_epw
Notes
-----
The returned structures have the following fields.
=============== ====== =========================================
key format description
=============== ====== =========================================
loc String default identifier, not used
city String site loccation
state-prov String state, province or region (if available)
country String site country code
data_type String type of original data source
WMO_code String WMO identifier
latitude Float site latitude
longitude Float site longitude
TZ Float UTC offset
altitude Float site elevation
=============== ====== =========================================
+-------------------------------+-----------------------------------------+
| EPWData field | description |
+===============================+=========================================+
| index | A pandas datetime index. NOTE, times are|
| | set to local standard time (daylight |
| | savings is not included). Days run from |
| | 0-23h to comply with PVLIB's convention.|
+-------------------------------+-----------------------------------------+
| year | Year, from original EPW file. Can be |
| | overwritten using coerce function. |
+-------------------------------+-----------------------------------------+
| month | Month, from original EPW file. |
+-------------------------------+-----------------------------------------+
| day | Day of the month, from original EPW |
| | file. |
+-------------------------------+-----------------------------------------+
| hour | Hour of the day from original EPW file. |
| | Note that EPW's convention of 1-24h is |
| | not taken over in the index dataframe |
| | used in PVLIB. |
+-------------------------------+-----------------------------------------+
| minute | Minute, from original EPW file. Not |
| | used. |
+-------------------------------+-----------------------------------------+
| data_source_unct | Data source and uncertainty flags. See |
| | [1]_, chapter 2.13 |
+-------------------------------+-----------------------------------------+
| temp_air | Dry bulb temperature at the time |
| | indicated, deg C |
+-------------------------------+-----------------------------------------+
| temp_dew | Dew-point temperature at the time |
| | indicated, deg C |
+-------------------------------+-----------------------------------------+
| relative_humidity | Relative humidity at the time indicated,|
| | percent |
+-------------------------------+-----------------------------------------+
| atmospheric_pressure | Station pressure at the time indicated, |
| | Pa |
+-------------------------------+-----------------------------------------+
| etr | Extraterrestrial horizontal radiation |
| | recv'd during 60 minutes prior to |
| | timestamp, Wh/m^2 |
+-------------------------------+-----------------------------------------+
| etrn | Extraterrestrial normal radiation recv'd|
| | during 60 minutes prior to timestamp, |
| | Wh/m^2 |
+-------------------------------+-----------------------------------------+
| ghi_infrared | Horizontal infrared radiation recv'd |
| | during 60 minutes prior to timestamp, |
| | Wh/m^2 |
+-------------------------------+-----------------------------------------+
| ghi | Direct and diffuse horizontal radiation |
| | recv'd during 60 minutes prior to |
| | timestamp, Wh/m^2 |
+-------------------------------+-----------------------------------------+
| dni | Amount of direct normal radiation |
| | (modeled) recv'd during 60 minutes prior|
| | to timestamp, Wh/m^2 |
+-------------------------------+-----------------------------------------+
| dhi | Amount of diffuse horizontal radiation |
| | recv'd during 60 minutes prior to |
| | timestamp, Wh/m^2 |
+-------------------------------+-----------------------------------------+
| global_hor_illum | Avg. total horizontal illuminance recv'd|
| | during the 60 minutes prior to |
| | timestamp, lx |
+-------------------------------+-----------------------------------------+
| direct_normal_illum | Avg. direct normal illuminance recv'd |
| | during the 60 minutes prior to |
| | timestamp, lx |
+-------------------------------+-----------------------------------------+
| diffuse_horizontal_illum | Avg. horizontal diffuse illuminance |
| | recv'd during the 60 minutes prior to |
| | timestamp, lx |
+-------------------------------+-----------------------------------------+
| zenith_luminance | Avg. luminance at the sky's zenith |
| | during the 60 minutes prior to |
| | timestamp, cd/m^2 |
+-------------------------------+-----------------------------------------+
| wind_direction | Wind direction at time indicated, |
| | degrees from north (360 = north; 0 = |
| | undefined,calm) |
+-------------------------------+-----------------------------------------+
| wind_speed | Wind speed at the time indicated, m/s |
+-------------------------------+-----------------------------------------+
| total_sky_cover | Amount of sky dome covered by clouds or |
| | obscuring phenomena at time stamp, |
| | tenths of sky |
+-------------------------------+-----------------------------------------+
| opaque_sky_cover | Amount of sky dome covered by clouds or |
| | obscuring phenomena that prevent |
| | observing the sky at time stamp, tenths |
| | of sky |
+-------------------------------+-----------------------------------------+
| visibility | Horizontal visibility at the time |
| | indicated, km |
+-------------------------------+-----------------------------------------+
| ceiling_height | Height of cloud base above local terrain|
| | (7777=unlimited), meter |
+-------------------------------+-----------------------------------------+
| present_weather_observation | Indicator for remaining fields: If 0, |
| | then the observed weather codes are |
| | taken from the following field. If 9, |
| | then missing weather is assumed. |
+-------------------------------+-----------------------------------------+
| present_weather_codes | Present weather code, see [1], chapter |
| | 2.9.1.28 |
+-------------------------------+-----------------------------------------+
| precipitable_water | Total precipitable water contained in a |
| | column of unit cross section from earth |
| | to top of atmosphere, cm. Note that some|
| | old \*_TMY3.epw files may have incorrect|
| | unit if it was retrieved from |
| | www.energyplus.net. |
+-------------------------------+-----------------------------------------+
| aerosol_optical_depth | The broadband aerosol optical depth per |
| | unit of air mass due to extinction by |
| | aerosol component of atmosphere, |
| | unitless |
+-------------------------------+-----------------------------------------+
| snow_depth | Snow depth in centimeters on the day |
| | indicated, (999 = missing data) |
+-------------------------------+-----------------------------------------+
| days_since_last_snowfall | Number of days since last snowfall |
| | (maximum value of 88, where 88 = 88 or |
| | greater days; 99 = missing data) |
+-------------------------------+-----------------------------------------+
| albedo | The ratio of reflected solar irradiance |
| | to global horizontal irradiance, |
| | unitless |
+-------------------------------+-----------------------------------------+
| liquid_precipitation_depth | The amount of liquid precipitation |
| | observed at indicated time for the |
| | period indicated in the liquid |
| | precipitation quantity field, |
| | millimeter |
+-------------------------------+-----------------------------------------+
| liquid_precipitation_quantity | The period of accumulation for the |
| | liquid precipitation depth field, hour |
+-------------------------------+-----------------------------------------+
References
----------
.. [1] `EnergyPlus documentation, Auxiliary Programs
<https://energyplus.net/documentation>`_
'''
if str(filename).startswith('http'):
# Attempts to download online EPW file
# See comments above for possible online sources
request = Request(filename, headers={'User-Agent': (
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) '
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 '
'Safari/537.36')})
response = urlopen(request)
with io.StringIO(response.read().decode(errors='ignore')) as csvdata:
data, meta = parse_epw(csvdata, coerce_year)
else:
# Assume it's accessible via the file system
with open(str(filename), 'r') as csvdata:
data, meta = parse_epw(csvdata, coerce_year)
return data, meta
def parse_epw(csvdata, coerce_year=None):
"""
Given a file-like buffer with data in Energy Plus Weather (EPW) format,
parse the data into a dataframe.
Parameters
----------
csvdata : file-like buffer
a file-like buffer containing data in the EPW format
coerce_year : int, optional
If supplied, the year of the data will be set to this value. This can
be a useful feature because EPW data is composed of data from
different years.
Warning: EPW files always have 365*24 = 8760 data rows;
be careful with the use of leap years.
Returns
-------
data : DataFrame
A pandas dataframe with the columns described in the table
below. For more detailed descriptions of each component, please
consult the EnergyPlus Auxiliary Programs documentation
available at: https://energyplus.net/documentation.
metadata : dict
The site metadata available in the file.
See Also
--------
pvlib.iotools.read_epw
"""
# Read line with metadata
firstline = csvdata.readline()
head = ['loc', 'city', 'state-prov', 'country', 'data_type', 'WMO_code',
'latitude', 'longitude', 'TZ', 'altitude']
meta = dict(zip(head, firstline.rstrip('\n').split(",")))
meta['altitude'] = float(meta['altitude'])
meta['latitude'] = float(meta['latitude'])
meta['longitude'] = float(meta['longitude'])
meta['TZ'] = float(meta['TZ'])
colnames = ['year', 'month', 'day', 'hour', 'minute', 'data_source_unct',
'temp_air', 'temp_dew', 'relative_humidity',
'atmospheric_pressure', 'etr', 'etrn', 'ghi_infrared', 'ghi',
'dni', 'dhi', 'global_hor_illum', 'direct_normal_illum',
'diffuse_horizontal_illum', 'zenith_luminance',
'wind_direction', 'wind_speed', 'total_sky_cover',
'opaque_sky_cover', 'visibility', 'ceiling_height',
'present_weather_observation', 'present_weather_codes',
'precipitable_water', 'aerosol_optical_depth', 'snow_depth',
'days_since_last_snowfall', 'albedo',
'liquid_precipitation_depth', 'liquid_precipitation_quantity']
# We only have to skip 6 rows instead of 7 because we have already used
# the realine call above.
data = pd.read_csv(csvdata, skiprows=6, header=0, names=colnames)
# Change to single year if requested
if coerce_year is not None:
data["year"] = coerce_year
# create index that supplies correct date and time zone information
dts = data[['month', 'day']].astype(str).apply(lambda x: x.str.zfill(2))
hrs = (data['hour'] - 1).astype(str).str.zfill(2)
dtscat = data['year'].astype(str) + dts['month'] + dts['day'] + hrs
idx = pd.to_datetime(dtscat, format='%Y%m%d%H')
idx = idx.dt.tz_localize(int(meta['TZ'] * 3600))
data.index = idx
return data, meta