-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Surfrad data reader #595
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Surfrad data reader #595
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
e2f093b
surfrad reader
lboeman 6e741de
minor updates
lboeman 2fde993
coding style fixes
lboeman af2aeaf
DatetimeIndex updates for compatibility with pandas 0.14.0
lboeman eef034c
documentation updates
lboeman 62b0021
Doc updates, addition to what's new and api
lboeman 3b34e38
bump min pandas version to 0.15.0, update tests and docs, add map_var…
lboeman d844203
style fix
lboeman 756fa56
typo in whatsnew/doc update
lboeman ecc9896
rebase, small fix to pvsystems.py
lboeman c2eaecd
remove whitespace
lboeman 5c2e4ed
fix duplicate whatsnew entry after rebase
lboeman File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
""" | ||
Import functions for NOAA SURFRAD Data. | ||
""" | ||
import io | ||
|
||
try: | ||
# python 2 compatibility | ||
from urllib2 import urlopen, Request | ||
except ImportError: | ||
from urllib.request import urlopen, Request | ||
|
||
import pandas as pd | ||
import numpy as np | ||
|
||
SURFRAD_COLUMNS = [ | ||
'year', 'jday', 'month', 'day', 'hour', 'minute', 'dt', 'zen', | ||
'dw_solar', 'dw_solar_flag', 'uw_solar', 'uw_solar_flag', 'direct_n', | ||
'direct_n_flag', 'diffuse', 'diffuse_flag', 'dw_ir', 'dw_ir_flag', | ||
'dw_casetemp', 'dw_casetemp_flag', 'dw_dometemp', 'dw_dometemp_flag', | ||
'uw_ir', 'uw_ir_flag', 'uw_casetemp', 'uw_casetemp_flag', 'uw_dometemp', | ||
'uw_dometemp_flag', 'uvb', 'uvb_flag', 'par', 'par_flag', 'netsolar', | ||
'netsolar_flag', 'netir', 'netir_flag', 'totalnet', 'totalnet_flag', | ||
'temp', 'temp_flag', 'rh', 'rh_flag', 'windspd', 'windspd_flag', | ||
'winddir', 'winddir_flag', 'pressure', 'pressure_flag'] | ||
|
||
lboeman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# Dictionary mapping surfrad variables to pvlib names | ||
VARIABLE_MAP = { | ||
'zen': 'solar_zenith', | ||
'dw_solar': 'ghi', | ||
'dw_solar_flag': 'ghi_flag', | ||
'direct_n': 'dni', | ||
'direct_n_flag': 'dni_flag', | ||
'diffuse': 'dhi', | ||
'diffuse_flag': 'dhi_flag', | ||
'temp': 'temp_air', | ||
'temp_flag': 'temp_air_flag', | ||
'windspd': 'wind_speed', | ||
'windspd_flag': 'wind_speed_flag', | ||
'winddir': 'wind_direction', | ||
'winddir_flag': 'wind_direction_flag', | ||
'rh': 'relative_humidity', | ||
'rh_flag': 'relative_humidity_flag' | ||
} | ||
|
||
|
||
def read_surfrad(filename, map_variables=True): | ||
"""Read in a daily NOAA SURFRAD[1] file. | ||
|
||
Parameters | ||
---------- | ||
filename: str | ||
Filepath or url. | ||
map_variables: bool | ||
When true, renames columns of the Dataframe to pvlib variable names | ||
where applicable. See variable SURFRAD_COLUMNS. | ||
|
||
Returns | ||
------- | ||
Tuple of the form (data, metadata). | ||
|
||
data: Dataframe | ||
Dataframe with the fields found below. | ||
metadata: dict | ||
Site metadata included in the file. | ||
|
||
Notes | ||
----- | ||
Metadata dictionary includes the following fields: | ||
|
||
=============== ====== =============== | ||
Key Format Description | ||
=============== ====== =============== | ||
station String site name | ||
latitude Float site latitude | ||
longitude Float site longitude | ||
elevation Int site elevation | ||
surfrad_version Int surfrad version | ||
tz String Timezone (UTC) | ||
=============== ====== =============== | ||
|
||
Dataframe includes the following fields: | ||
|
||
======================= ====== ========================================== | ||
raw, mapped Format Description | ||
======================= ====== ========================================== | ||
**Mapped field names are returned when the map_variables argument is True** | ||
--------------------------------------------------------------------------- | ||
year int year as 4 digit int | ||
jday int day of year 1-365(or 366) | ||
month int month (1-12) | ||
day int day of month(1-31) | ||
hour int hour (0-23) | ||
minute int minute (0-59) | ||
dt float decimal time i.e. 23.5 = 2330 | ||
zen, solar_zenith float solar zenith angle (deg) | ||
**Fields below have associated qc flags labeled <field>_flag.** | ||
--------------------------------------------------------------------------- | ||
dw_solar, ghi float downwelling global solar(W/m^2) | ||
uw_solar float updownwelling global solar(W/m^2) | ||
direct_n, dni float direct normal solar (W/m^2) | ||
diffuse, dhi float downwelling diffuse solar (W/m^2) | ||
dw_ir float downwelling thermal infrared (W/m^2) | ||
dw_casetemp float downwelling IR case temp (K) | ||
dw_dometemp float downwelling IR dome temp (K) | ||
uw_ir float upwelling thermal infrared (W/m^2) | ||
uw_casetemp float upwelling IR case temp (K) | ||
uw_dometemp float upwelling IR case temp (K) | ||
uvb float global uvb (miliWatts/m^2) | ||
par float photosynthetically active radiation(W/m^2) | ||
netsolar float net solar (dw_solar - uw_solar) (W/m^2) | ||
netir float net infrared (dw_ir - uw_ir) (W/m^2) | ||
totalnet float net radiation (netsolar+netir) (W/m^2) | ||
temp, temp_air float 10-meter air temperature (?C) | ||
rh, relative_humidity float relative humidity (%) | ||
windspd, wind_speed float wind speed (m/s) | ||
winddir, wind_direction float wind direction (deg, clockwise from north) | ||
pressure float station pressure (mb) | ||
======================= ====== ========================================== | ||
|
||
See README files located in the station directories in the SURFRAD | ||
data archives[2] for details on SURFRAD daily data files. | ||
|
||
References | ||
---------- | ||
[1] NOAA Earth System Research Laboratory Surface Radiation Budget Network | ||
`SURFRAD Homepage <https://www.esrl.noaa.gov/gmd/grad/surfrad/>`_ | ||
[2] NOAA SURFRAD Data Archive | ||
`SURFRAD Archive <ftp://aftp.cmdl.noaa.gov/data/radiation/surfrad/>`_ | ||
""" | ||
if filename.startswith('ftp'): | ||
req = Request(filename) | ||
response = urlopen(req) | ||
file_buffer = io.StringIO(response.read().decode(errors='ignore')) | ||
else: | ||
file_buffer = open(filename, 'r') | ||
|
||
# Read and parse the first two lines to build the metadata dict. | ||
station = file_buffer.readline() | ||
file_metadata = file_buffer.readline() | ||
|
||
metadata_list = file_metadata.split() | ||
metadata = {} | ||
metadata['name'] = station.strip() | ||
metadata['latitude'] = float(metadata_list[0]) | ||
metadata['longitude'] = float(metadata_list[1]) | ||
metadata['elevation'] = float(metadata_list[2]) | ||
metadata['surfrad_version'] = int(metadata_list[-1]) | ||
metadata['tz'] = 'UTC' | ||
|
||
data = pd.read_csv(file_buffer, delim_whitespace=True, | ||
header=None, names=SURFRAD_COLUMNS) | ||
file_buffer.close() | ||
|
||
data = format_index(data) | ||
missing = data == -9999.9 | ||
data = data.where(~missing, np.NaN) | ||
|
||
if map_variables: | ||
data.rename(columns=VARIABLE_MAP, inplace=True) | ||
return data, metadata | ||
|
||
|
||
def format_index(data): | ||
"""Create UTC localized DatetimeIndex for the dataframe. | ||
|
||
Parameters | ||
---------- | ||
data: Dataframe | ||
Must contain columns 'year', 'jday', 'hour' and | ||
'minute'. | ||
|
||
Return | ||
------ | ||
data: Dataframe | ||
Dataframe with a DatetimeIndex localized to UTC. | ||
""" | ||
year = data.year.apply(str) | ||
jday = data.jday.apply(lambda x: '{:03d}'.format(x)) | ||
hours = data.hour.apply(lambda x: '{:02d}'.format(x)) | ||
minutes = data.minute.apply(lambda x: '{:02d}'.format(x)) | ||
index = pd.to_datetime(year + jday + hours + minutes, format="%Y%j%H%M") | ||
data.index = index | ||
data = data.tz_localize('UTC') | ||
return data |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import inspect | ||
import os | ||
|
||
from pandas import Timestamp, DatetimeIndex | ||
from pandas.util.testing import network | ||
|
||
from pvlib.iotools import surfrad | ||
|
||
test_dir = os.path.dirname( | ||
os.path.abspath(inspect.getfile(inspect.currentframe()))) | ||
testfile = os.path.join(test_dir, '../data/surfrad-slv16001.dat') | ||
network_testfile = ('ftp://aftp.cmdl.noaa.gov/data/radiation/surfrad/' | ||
'Alamosa_CO/2016/slv16001.dat') | ||
|
||
|
||
@network | ||
def test_read_surfrad_network(): | ||
# If this test begins failing, SURFRAD's data structure or data | ||
# archive may have changed. | ||
local_data, _ = surfrad.read_surfrad(testfile) | ||
network_data, _ = surfrad.read_surfrad(network_testfile) | ||
assert local_data.equals(network_data) | ||
|
||
|
||
def test_read_surfrad_columns_no_map(): | ||
data, _ = surfrad.read_surfrad(testfile, map_variables=False) | ||
assert 'zen' in data.columns | ||
assert 'temp' in data.columns | ||
assert 'par' in data.columns | ||
assert 'pressure' in data.columns | ||
lboeman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
def test_read_surfrad_columns_map(): | ||
data, _ = surfrad.read_surfrad(testfile) | ||
assert 'solar_zenith' in data.columns | ||
assert 'ghi' in data.columns | ||
assert 'ghi_flag' in data.columns | ||
assert 'dni' in data.columns | ||
assert 'dni_flag' in data.columns | ||
assert 'dhi' in data.columns | ||
assert 'dhi_flag' in data.columns | ||
assert 'wind_direction' in data.columns | ||
assert 'wind_direction_flag' in data.columns | ||
assert 'wind_speed' in data.columns | ||
assert 'wind_speed_flag' in data.columns | ||
assert 'temp_air' in data.columns | ||
assert 'temp_air_flag' in data.columns | ||
|
||
|
||
def test_format_index(): | ||
start = Timestamp('20160101 00:00') | ||
expected = DatetimeIndex(start=start, periods=1440, freq='1min', tz='UTC') | ||
actual, _ = surfrad.read_surfrad(testfile) | ||
assert actual.index.equals(expected) | ||
|
||
|
||
def test_read_surfrad_metadata(): | ||
expected = {'name': 'Alamosa', | ||
'latitude': 37.70, | ||
'longitude': 105.92, | ||
'elevation': 2317, | ||
'surfrad_version': 1, | ||
'tz': 'UTC'} | ||
_, metadata = surfrad.read_surfrad(testfile) | ||
assert metadata == expected |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lboeman your rebase introduced duplicate entries here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Fixed.