Skip to content
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

Add retrieval function for BSRN data #1254

Merged
merged 33 commits into from
Jul 30, 2021
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
837872d
Initial commit
AdamRJensen Jul 5, 2021
f546c77
Fix typo in doc string
AdamRJensen Jul 5, 2021
324644f
Fix stickler
AdamRJensen Jul 5, 2021
d010d51
Update api.rst, __init__.py, and whatsnew
AdamRJensen Jul 7, 2021
66cc5bb
Major refactoring
AdamRJensen Jul 7, 2021
c68cf2c
Coverage for test_bsrn
AdamRJensen Jul 7, 2021
6346319
Coverage for Warnings in case of no files avaiable
AdamRJensen Jul 7, 2021
595abc2
Fix stickler
AdamRJensen Jul 7, 2021
c49c051
Correct test_get_bsrn_bad_station test
AdamRJensen Jul 7, 2021
540fde3
Specify warning category
AdamRJensen Jul 7, 2021
3353bd6
Update dates used in test_get_bsrn_no_files
AdamRJensen Jul 9, 2021
5c37ecb
Add secret credentials for testing
AdamRJensen Jul 9, 2021
2fe7a50
Documentation updates
AdamRJensen Jul 9, 2021
aa983d7
Move line_no_dict 7 lines down
AdamRJensen Jul 10, 2021
90e162b
Add requires_bsrn_credentials to conftest.py
AdamRJensen Jul 12, 2021
428f028
Add parsing of logical records 0300 and 0500
AdamRJensen Jul 19, 2021
66ddd74
Merge remote-tracking branch 'upstream/master' into get_bsrn
AdamRJensen Jul 19, 2021
7f4be47
Raise os.environ as ValueError for debugging
AdamRJensen Jul 19, 2021
14a4376
Export BSRN credentials in conda_linux.yml
AdamRJensen Jul 19, 2021
7c40574
Add parse_bsrn
AdamRJensen Jul 20, 2021
cf245c8
Fix stickler and minor doc changes
AdamRJensen Jul 20, 2021
b6b8df6
Coverage for additional logical records
AdamRJensen Jul 20, 2021
2503d97
Refactor warnings in get_bsrn
AdamRJensen Jul 20, 2021
8494f6b
Add Hint section
AdamRJensen Jul 20, 2021
cc7369c
Add function for empty dataframe and restructure data docs
AdamRJensen Jul 22, 2021
12791cd
Add gri to list of variables
AdamRJensen Jul 22, 2021
9289760
Coverage for records not found
AdamRJensen Jul 22, 2021
735666d
Coverage for no logical records found
AdamRJensen Jul 22, 2021
ac018dd
Formatting of data columns table
AdamRJensen Jul 22, 2021
6a4e75c
Merge read_ and get_bsrn in whatsnew
AdamRJensen Jul 22, 2021
f96b39b
Changes from review by kandersol-nrel
AdamRJensen Jul 22, 2021
4ca69f6
Add lat/lon ISO 19115 convention to metadata
AdamRJensen Jul 22, 2021
2f2cda5
Add bio.seek(0) to get_bsrn()
AdamRJensen Jul 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ci/azure/conda_linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ jobs:
- script: |
source activate test_env
export NREL_API_KEY=$(nrelApiKey)
export BSRN_FTP_USERNAME=$(BSRN_FTP_USERNAME)
export BSRN_FTP_PASSWORD=$(BSRN_FTP_PASSWORD)
pytest pvlib --remote-data --junitxml=junit/test-results.xml --cov --cov-report=xml --cov-report=html
displayName: 'pytest'
- task: PublishTestResults@2
Expand Down
2 changes: 2 additions & 0 deletions docs/sphinx/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,9 @@ of sources and file formats relevant to solar energy modeling.
iotools.read_pvgis_tmy
iotools.get_pvgis_hourly
iotools.read_pvgis_hourly
iotools.get_bsrn
iotools.read_bsrn
iotools.parse_bsrn
iotools.get_cams
iotools.read_cams
iotools.parse_cams
Expand Down
3 changes: 3 additions & 0 deletions docs/sphinx/source/whatsnew/v0.9.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ Deprecations

Enhancements
~~~~~~~~~~~~
* Add :func:`~pvlib.iotools.get_bsrn` and :func:`~pvlib.iotools.read_bsrn`
for retrieving and reading BSRN solar radiation data files.
(:pull:`1254`, :pull:`1145`, :issue:`1015`)
AdamRJensen marked this conversation as resolved.
Show resolved Hide resolved
* Added :func:`~pvlib.iotools.read_pvgis_hourly` and
:func:`~pvlib.iotools.get_pvgis_hourly` for reading and retrieving hourly
solar radiation data and PV power output from PVGIS. (:pull:`1186`,
Expand Down
1 change: 1 addition & 0 deletions pvlib/data/variables_style_rules.csv
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ dni_extra;direct normal irradiance at top of atmosphere (extraterrestrial)
dhi;diffuse horizontal irradiance
bhi;beam/direct horizontal irradiance
ghi;global horizontal irradiance
gri;ground-reflected irradiance
aoi;angle of incidence between :math:`90\deg` and :math:`90\deg`
aoi_projection;cos(aoi)
airmass;airmass
Expand Down
2 changes: 2 additions & 0 deletions pvlib/iotools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
from pvlib.iotools.pvgis import get_pvgis_tmy, read_pvgis_tmy # noqa: F401
from pvlib.iotools.pvgis import read_pvgis_hourly # noqa: F401
from pvlib.iotools.pvgis import get_pvgis_hourly # noqa: F401
from pvlib.iotools.bsrn import get_bsrn # noqa: F401
from pvlib.iotools.bsrn import read_bsrn # noqa: F401
from pvlib.iotools.bsrn import parse_bsrn # noqa: F401
from pvlib.iotools.sodapro import get_cams # noqa: F401
from pvlib.iotools.sodapro import read_cams # noqa: F401
from pvlib.iotools.sodapro import parse_cams # noqa: F401
486 changes: 398 additions & 88 deletions pvlib/iotools/bsrn.py

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions pvlib/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import warnings

import pandas as pd
import os
from pkg_resources import parse_version
import pytest
from functools import wraps
Expand Down Expand Up @@ -82,6 +83,18 @@ def assert_frame_equal(left, right, **kwargs):
reason='does not run on windows')


try:
# Attempt to load BSRN credentials used for testing pvlib.iotools.get_bsrn
bsrn_username = os.environ["BSRN_FTP_USERNAME"]
bsrn_password = os.environ["BSRN_FTP_PASSWORD"]
has_bsrn_credentials = True
except KeyError:
has_bsrn_credentials = False

requires_bsrn_credentials = pytest.mark.skipif(
not has_bsrn_credentials, reason='requires bsrn credentials')


try:
import statsmodels # noqa: F401
has_statsmodels = True
Expand Down
116 changes: 107 additions & 9 deletions pvlib/tests/iotools/test_bsrn.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,123 @@
tests for :mod:`pvlib.iotools.bsrn`
"""


import pandas as pd
import pytest
import os
from pvlib.iotools import read_bsrn, get_bsrn
from ..conftest import (DATA_DIR, RERUNS, RERUNS_DELAY, assert_index_equal,
requires_bsrn_credentials)


@pytest.fixture(scope="module")
def bsrn_credentials():
"""Supplies the BSRN FTP credentials for testing purposes.

from pvlib.iotools import bsrn
from ..conftest import DATA_DIR, assert_index_equal
Users should obtain there own credentials as described in the `read_bsrn`
AdamRJensen marked this conversation as resolved.
Show resolved Hide resolved
documentation."""
bsrn_username = os.environ["BSRN_FTP_USERNAME"]
bsrn_password = os.environ["BSRN_FTP_PASSWORD"]
return bsrn_username, bsrn_password


@pytest.mark.parametrize('testfile,expected_index', [
('bsrn-pay0616.dat.gz',
pd.date_range(start='20160601', periods=43200, freq='1min', tz='UTC')),
('bsrn-lr0100-pay0616.dat',
pd.date_range(start='20160601', periods=43200, freq='1min', tz='UTC')),
@pytest.fixture
def expected_index():
return pd.date_range(start='20160601', periods=43200, freq='1min',
tz='UTC')


@pytest.mark.parametrize('testfile', [
('bsrn-pay0616.dat.gz'),
('bsrn-lr0100-pay0616.dat'),
])
def test_read_bsrn(testfile, expected_index):
data = bsrn.read_bsrn(DATA_DIR / testfile)
data, metadata = read_bsrn(DATA_DIR / testfile)
assert_index_equal(expected_index, data.index)
assert 'ghi' in data.columns
assert 'dni_std' in data.columns
assert 'dhi_min' in data.columns
assert 'lwd_max' in data.columns
assert 'relative_humidity' in data.columns


def test_read_bsrn_logical_records(expected_index):
# Test if logical records 0300 and 0500 are correct parsed
# and that 0100 is not passed when not specified
data, metadata = read_bsrn(DATA_DIR / 'bsrn-pay0616.dat.gz',
logical_records=['0300', '0500'])
assert_index_equal(expected_index, data.index)
assert 'lwu' in data.columns
assert 'uva_global' in data.columns
assert 'uvb_reflected_std' in data.columns
assert 'ghi' not in data.columns


def test_read_bsrn_bad_logical_record():
# Test if ValueError is raised if an unsupported logical record is passed
with pytest.raises(ValueError, match='not in'):
read_bsrn(DATA_DIR / 'bsrn-lr0100-pay0616.dat',
logical_records=['dummy'])


def test_read_bsrn_logical_records_not_found():
# Test if an empty dataframe is returned if specified LRs are not present
AdamRJensen marked this conversation as resolved.
Show resolved Hide resolved
data, metadata = read_bsrn(DATA_DIR / 'bsrn-lr0100-pay0616.dat',
logical_records=['0300', '0500'])
assert_index_equal(pd.DataFrame().index, data.index)
assert 'uva_global' in data.columns
assert 'uvb_reflected_std' in data.columns
assert 'uva_global_max' in data.columns
assert 'dni' not in data.columns
assert 'day' not in data.columns


@requires_bsrn_credentials
@pytest.mark.remote_data
@pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
def test_get_bsrn(expected_index, bsrn_credentials):
# Retrieve irradiance data from the BSRN FTP server
# the TAM station is chosen due to its small file sizes
username, password = bsrn_credentials
data, metadata = get_bsrn(
start=pd.Timestamp(2016, 6, 1),
end=pd.Timestamp(2016, 6, 29),
station='tam',
username=username,
password=password,
local_path='')
assert_index_equal(expected_index, data.index)
assert 'ghi' in data.columns
assert 'dni_std' in data.columns
assert 'dhi_min' in data.columns
assert 'lwd_max' in data.columns
assert 'relative_humidity' in data.columns


@requires_bsrn_credentials
@pytest.mark.remote_data
@pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
def test_get_bsrn_bad_station(bsrn_credentials):
# Test if KeyError is raised if a bad station name is passed
username, password = bsrn_credentials
with pytest.raises(KeyError, match='sub-directory does not exist'):
get_bsrn(
start=pd.Timestamp(2016, 6, 1),
end=pd.Timestamp(2016, 6, 29),
station='not_a_station_name',
username=username,
password=password)


@requires_bsrn_credentials
@pytest.mark.remote_data
@pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
def test_get_bsrn_no_files(bsrn_credentials):
username, password = bsrn_credentials
# Test if Warning is given if no files are found for the entire time frame
with pytest.warns(UserWarning, match='No files'):
get_bsrn(
start=pd.Timestamp(1990, 6, 1),
end=pd.Timestamp(1990, 6, 29),
station='tam',
username=username,
password=password)