From 5be94add6c54b8a92e559fc030b0a87c8f6d85cf Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Mon, 28 Dec 2020 15:57:30 -0700 Subject: [PATCH 01/14] add 2.0.5 changelog --- docs/sphinx/source/changelog/v2.0.5.rst | 33 +++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 docs/sphinx/source/changelog/v2.0.5.rst diff --git a/docs/sphinx/source/changelog/v2.0.5.rst b/docs/sphinx/source/changelog/v2.0.5.rst new file mode 100644 index 00000000..bb0df36c --- /dev/null +++ b/docs/sphinx/source/changelog/v2.0.5.rst @@ -0,0 +1,33 @@ +************************** +v2.0.5 (December 28, 2020) +************************** + + + +API Changes +----------- + +Deprecations +------------ + +Enhancements +------------ + +Bug fixes +--------- + +Testing +------- + +Documentation +------------- + +Requirements +------------ + +Example Updates +--------------- + + +Contributors +------------ From 2ac2278704c08bcb813f8d9e86e9bb1ecc197a1e Mon Sep 17 00:00:00 2001 From: Kevin Anderson <57452607+kanderso-nrel@users.noreply.github.com> Date: Tue, 29 Dec 2020 11:09:40 -0700 Subject: [PATCH 02/14] Fix pandas 1.2.0 test suite errors (#251) * fix test_soiling_srr_negative_step error * changelog --- docs/sphinx/source/changelog/v2.0.5.rst | 1 + rdtools/test/soiling_test.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/sphinx/source/changelog/v2.0.5.rst b/docs/sphinx/source/changelog/v2.0.5.rst index bb0df36c..2d1ac725 100644 --- a/docs/sphinx/source/changelog/v2.0.5.rst +++ b/docs/sphinx/source/changelog/v2.0.5.rst @@ -18,6 +18,7 @@ Bug fixes Testing ------- +* Fix test suite error raised when using pandas 1.2.0 (:pull:`251`) Documentation ------------- diff --git a/rdtools/test/soiling_test.py b/rdtools/test/soiling_test.py index 1be4eb9e..2b1e6f01 100644 --- a/rdtools/test/soiling_test.py +++ b/rdtools/test/soiling_test.py @@ -204,7 +204,7 @@ def test_soiling_srr_recenter_false(normalized_daily, insolation): def test_soiling_srr_negative_step(normalized_daily, insolation): stepped_daily = normalized_daily.copy() - stepped_daily.iloc[37:] = stepped_daily.iloc[25:] - 0.1 + stepped_daily.iloc[37:] = stepped_daily.iloc[37:] - 0.1 np.random.seed(1977) sr, sr_ci, soiling_info = soiling_srr(stepped_daily, insolation, reps=10) From 36a894606fa342f61dba1e9c0e85546faddec647 Mon Sep 17 00:00:00 2001 From: Kevin Anderson <57452607+kanderso-nrel@users.noreply.github.com> Date: Tue, 29 Dec 2020 11:18:29 -0700 Subject: [PATCH 03/14] add project urls for pypi (#248) Co-authored-by: Michael Deceglie --- setup.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/setup.py b/setup.py index 55107a98..307810bd 100644 --- a/setup.py +++ b/setup.py @@ -88,6 +88,12 @@ 'PV' ] +PROJECT_URLS = { + "Bug Tracker": "https://github.com/NREL/rdtools/issues", + "Documentation": "https://rdtools.readthedocs.io/", + "Source Code": "https://github.com/NREL/rdtools", +} + setuptools_kwargs = { 'zip_safe': False, 'scripts': [], @@ -114,5 +120,6 @@ maintainer_email=MAINTAINER_EMAIL, license=LICENSE, url=URL, + project_urls=PROJECT_URLS, classifiers=CLASSIFIERS, **setuptools_kwargs) From f94d993ac8fe04b2c37b37b6c5b6d111a315f72e Mon Sep 17 00:00:00 2001 From: Kevin Anderson <57452607+kanderso-nrel@users.noreply.github.com> Date: Tue, 29 Dec 2020 12:10:05 -0700 Subject: [PATCH 04/14] Add python 3.9 to test matrix (#249) * add 3.9 to test matrix * fix config * update requirements.txt to use versions with wheels available for 3.6 and 3.9 for numpy, scipy, pandas, statsmodels * enable requirements.txt py3.9 check * changelog * bring in wheel package too * add 3.9 metadata tag to setup.py * bump h5py version too Co-authored-by: Michael Deceglie --- .github/workflows/pytest.yaml | 6 ++++-- docs/sphinx/source/changelog/v2.0.5.rst | 5 +++++ requirements.txt | 10 +++++----- setup.py | 1 + 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.github/workflows/pytest.yaml b/.github/workflows/pytest.yaml index 703954ab..a4618bd9 100644 --- a/.github/workflows/pytest.yaml +++ b/.github/workflows/pytest.yaml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.6, 3.7, 3.8] + python-version: [3.6, 3.7, 3.8, 3.9] env: [ '-r requirements.txt .[test]', '-r requirements-min.txt .[test]', @@ -19,6 +19,8 @@ jobs: env: '-r requirements-min.txt .[test]' - python-version: 3.8 env: '-r requirements-min.txt .[test]' + - python-version: 3.9 + env: '-r requirements-min.txt .[test]' steps: - uses: actions/checkout@v2 @@ -28,7 +30,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install ${{ matrix.env }} run: | - python -m pip install --upgrade pip + python -m pip install --upgrade pip wheel pip install ${{ matrix.env }} - name: Test with pytest ${{ matrix.env }} run: | diff --git a/docs/sphinx/source/changelog/v2.0.5.rst b/docs/sphinx/source/changelog/v2.0.5.rst index 2d1ac725..2d810b1c 100644 --- a/docs/sphinx/source/changelog/v2.0.5.rst +++ b/docs/sphinx/source/changelog/v2.0.5.rst @@ -18,13 +18,18 @@ Bug fixes Testing ------- +* Add Python 3.9 to CI testing (:pull:`249`) * Fix test suite error raised when using pandas 1.2.0 (:pull:`251`) + Documentation ------------- Requirements ------------ +* Update ``requirements.txt`` versions for numpy, scipy, pandas, h5py + and statsmodels to versions that have wheels available for python + 3.6-3.9. Note that the minimum versions are unchanged. (:pull:`249`). Example Updates --------------- diff --git a/requirements.txt b/requirements.txt index d7d0590e..284c8c7d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,14 +1,14 @@ cycler==0.10.0 -h5py==2.10.0 +h5py==3.1.0 kiwisolver==1.2.0 matplotlib==3.3.2 -numpy==1.17.3 -pandas==1.1.0 +numpy==1.19.4 +pandas==1.1.3 patsy==0.5.1 pvlib==0.7.1 pyparsing==2.4.7 python-dateutil==2.8.1 pytz==2019.3 -scipy==1.3.2 +scipy==1.5.4 six==1.14.0 -statsmodels==0.11.1 +statsmodels==0.12.1 diff --git a/setup.py b/setup.py index 307810bd..08ff5b25 100644 --- a/setup.py +++ b/setup.py @@ -75,6 +75,7 @@ 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Scientific/Engineering', ] From 6454cc82eb03eb3113e84f351f69ba8a8ea564b0 Mon Sep 17 00:00:00 2001 From: Kevin Anderson <57452607+kanderso-nrel@users.noreply.github.com> Date: Tue, 29 Dec 2020 12:20:22 -0700 Subject: [PATCH 05/14] flake8 compliance; flake8 GH Actions workflow (#231) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add flake8 config * bulk flake8 fixes * add linting github workflow * update GH workflow * update lint workflow job name * add flake8 to extras_require * add code style section in docs * fix unrelated docs rendering issue * tabs to spaces * whatsnew * only run on PR diffs instead of entire package * fetch all branches in the flake8 workflow * gh actions bugfix, maybe * more maybe bugfix * introduce a pep8 violation to test the flake8 check * Revert "introduce a pep8 violation to test the flake8 check" This reverts commit c78dc681524ac6f58c0e201e23b135afc6c1615d. * add flake8 config * bulk flake8 fixes * add linting github workflow * update GH workflow * update lint workflow job name * add flake8 to extras_require * add code style section in docs * fix unrelated docs rendering issue * tabs to spaces * whatsnew * only run on PR diffs instead of entire package * fetch all branches in the flake8 workflow * gh actions bugfix, maybe * more maybe bugfix * introduce a pep8 violation to test the flake8 check * Revert "introduce a pep8 violation to test the flake8 check" This reverts commit c78dc681524ac6f58c0e201e23b135afc6c1615d. * Model chains (#117) * Add normalized_filter() function to replace the mannual filter in example * Initial working system analysis class * system analysis version that reproduces notebook results Works for both sensor and clearsky workflows * Improve underlying analysis These improvements slightly change the clearsky results relative to the existing version of the notebook. * Allow poa, temperature, and temperature_coefficient to be None This leaves room for BYO modeled PV perofmrance in the future * Add system_analysis to rdtools namespace * Basic example of system_analysis() use * Update degradation_and_soiling_example.ipynb 1) Use apparent zenith in irradiance calculations instead of zenith 2) Apply clearsky filter based on poa irradiance rather than insolation 3) Include ground diffuse in irradiance transposition calculations * Update system_analysis_example notebook Update notes and change initial poa calculation to include ground diffuse * Add a plotting module * Update notebook to use plotting module * Add plotting methods * update system_analysis example notebook * add docstrings * Delete model chain dev notes * add matplotlib to setup.py and update requirements * change matplotlib version * Move docstring to class * renormalization bug fix * Update temperature input interface (Also fix merge bug in plotting) * update docstring for new temperature interface * Remove __init__ docstring * update class name to CamelCase * update kwarg explanatations in docstrings * remove model parameter from calc_clearsky_poa() It is still addressable through kwargs passed to pvlib * Update SystemAnalysis_example.ipynb * Reformat dosctrings to numpy style * command style docstrings * Remove duplicate line * Update plotting docstrings to numpy style * Format normalized_filter docstring according to numpy style Other docstrings in this module have been updated in #125 * Add an ad hoc filter example to the notebook * Fixes system_analysis bug #132 when pv_nameplate is passed into syste… (#133) * Fixes system_analysis bug #132 when pv_nameplate is passed into system_analysis object. * typo fix Co-Authored-By: Kevin Anderson <57452607+kanderso-nrel@users.noreply.github.com> * add bins parameter to plotting.degradation_summary_plot from #132 (cherry picked from commit efcbe2e89b64d1309ab0f3c5f21910d24c04e88d) * plotting bug fix * Drop py2.7 and add 3.7 and 3.8 to testing (#135) * Drop 2.7 and add 3.7 and 3.8 to testing, update docs. * creating DatetimeIndex directly is deprecated, switch to pd.date_range * require pandas < 1.0.0 * bump requirements.txt numpy to 1.17.3 for testing on py3.8 * more requirements.txt updates for py3.8 wheel availability * Update v2.0.0.rst * add matplotlib to requirements * matplotlib 3.1 * matplotlib * merge pytests and jupyter example * PVLib > 0.7 changes to cell_temp calculation * Modelchain pytests (#196) * pytests for system_analysis. coverage: 91%. * rename system_analysis.py to analysis.py. Rename class to RdAnalysis. Update pvwatts_kws to match Master updates * Allow temp_model_params to either be string or dict with 'a','b', 'deltaT' keys * update calc_cell_temperature for pvlib > 0.6.3, use energy_normalized in normalize_with_pvwatts * Warn if temp coefficient not passed into normalize_with_Pvwatts instead of exit with error. * Add tables=3.6.1 to requirements.txt to allow clearsky analysis * add tables to setup.py since it appears to be a required pvlib for the clearsky workflow and not installed by default. * Add RdAnalysis notebook for pvdaq4 system * add max_timedelta=15T and clearsky poa calculation update to pvdaq4 standard notebook example * Sphinx release notes for 2.1.0 updated and API update Co-authored-by: Michael Deceglie Co-authored-by: Kevin Anderson <57452607+kanderso-nrel@users.noreply.github.com> * Update tests, include tables in setup.py * suppress import warnings for soiling module. * Change warning suppression from warnings.resetwarnings to with warnings.catch_warnings(). Re-run notebooks * Model chains exp energy (#232) * enable normalize_with_expected_energy. * Update RdAnalysis_example.ipynb with manually defined power_expected option. * Add post-filter error check for < 2 yrs data per kanderson * Remove error message for no thermal model if power_expected is passed in. * remove tcell_filter from filter list if power_expected is passed in but not cell_temperature * pep8 compliance * more robust frequency check * shorten long lines * Model chains set clearsky (#233) * Move CS inputs to new set_clearsky function: pvlib_location ,pv_tilt, pv_azimuth, clearsky_poa, clearsky temp, albedo * Explicit error message if set_clearsky not run prior to clearsky_analysis. * remove Py2.7 check in block 3 of RdAnalysis_example.ipynb * boost analysis.py test coverage to 94% * add pv_energy pytest case. Change to ValueError rather than basic Exception when set_clearsky hasn't been run. Co-authored-by: Kevin Anderson <57452607+kanderso-nrel@users.noreply.github.com> * improve index equality conditional * pep8 cleanup * change dict key syntax * Clarify behavior when pv_nameplate is omitted * Useful errors for plotting methods * update requreiments for tables * reduce minimum version of tables * Delete RdAnalysis_example.ipynb * Remove max_timedelta parameter use in PVDAQ example * Move sun position calculation to clearsky section of example This brings the clearsky results into better allignement with the objected oriented example, now sun position is calculated after interpolation on both * Update chage log version number * Allow warning for experimental modules * pep8 analysis_test.py * Change module and class names * Update example with new module/class name * Fix outdated ref to system_analysis * Update api.rst with analysis chains module name * Fix changelog underline length * update index.rst with TrendAnalysis info * poa -> poa_global * cell_temperature -> temperature_cell * ambient_temperature->temperature_ambient * temperature_coefficient->gamma_pdc * temperature_model docstring * pv_nameplate->power_dc_rated * clearsky_poa->poa_global_clearsky * clearsky_temperature_cell->temperature_cell_clearsky * clearsky_temperature_ambient->temperature_ambient_clearsky * Align yoy and srr parameters with functional API * Use `case` in plotting methods * Change notebook kernel * weakly privatize some methods * Update rdtools/analysis_chains.py Co-authored-by: Kevin Anderson <57452607+kanderso-nrel@users.noreply.github.com> * Interpolate windspeed * Update rdtools/analysis_chains.py Co-authored-by: Kevin Anderson <57452607+kanderso-nrel@users.noreply.github.com> * implement review suggestions * more TrendAnalysis tests to improve coverage * cleanup * Fix copy/paste error in notebook * change _calc_cell_temeprature parameter order * More elegant error if filtering results in empty series * Changelog consolidation * change log update Co-authored-by: cdeline Co-authored-by: Kevin Anderson <57452607+kanderso-nrel@users.noreply.github.com> Co-authored-by: Kevin Anderson * flake8 and pytest fixes * add beta version to change log * add missing parenthesis * revert all the development stuff * move changelog entries to 2.0.5.rst; delete pending.rst * include 2.0.5 instead of pending * Remove pending changelog Co-authored-by: Michael Deceglie Co-authored-by: cdeline --- .flake8 | 11 + .github/workflows/flake8.yaml | 34 ++++ docs/sphinx/source/changelog.rst | 1 + docs/sphinx/source/changelog/v2.0.5.rst | 4 + docs/sphinx/source/conf.py | 12 +- docs/sphinx/source/developer_notes.rst | 20 ++ rdtools/degradation.py | 6 +- rdtools/normalization.py | 15 +- rdtools/plotting.py | 1 + rdtools/soiling.py | 41 ++-- rdtools/test/availability_test.py | 103 +--------- rdtools/test/clearsky_temperature_test.py | 15 +- rdtools/test/conftest.py | 141 +++++++++++++ rdtools/test/degradation_test.py | 10 +- rdtools/test/energy_from_power_test.py | 3 +- rdtools/test/filtering_test.py | 4 +- rdtools/test/interpolate_test.py | 4 +- rdtools/test/normalization_pvwatts_test.py | 1 - .../normalize_with_expected_power_test.py | 2 - rdtools/test/plotting_test.py | 15 -- rdtools/test/soiling_test.py | 192 ++++++++---------- setup.py | 2 +- 22 files changed, 363 insertions(+), 274 deletions(-) create mode 100644 .flake8 create mode 100644 .github/workflows/flake8.yaml diff --git a/.flake8 b/.flake8 new file mode 100644 index 00000000..c89afb78 --- /dev/null +++ b/.flake8 @@ -0,0 +1,11 @@ +# flake8 linter configurations +# see https://flake8.pycqa.org/en/latest/user/options.html + +[flake8] +max-line-length = 99 +max-doc-length = 99 +per-file-ignores = + # rdtools.x.y imported but unused + __init__.py:F401 + # invalid escape sequence '\s' + versioneer.py:W605 diff --git a/.github/workflows/flake8.yaml b/.github/workflows/flake8.yaml new file mode 100644 index 00000000..286cece7 --- /dev/null +++ b/.github/workflows/flake8.yaml @@ -0,0 +1,34 @@ +name: flake8 + +# since we're only checking PR diffs, only trigger on the pull_request event type. +# note: the pull_request event happens on opened, reopened, and synchronize activities; +# synchronize includes commits being pushed to the PR branch. +# https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#pull_request +on: [pull_request] + +jobs: + lint: + + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.8] + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 # fetch all branches, needed so we can diff against the target branch + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install flake8 + run: | + python -m pip install --upgrade pip + pip install flake8 + - name: List changed files + run: | + git diff --compact-summary "origin/$GITHUB_BASE_REF" + - name: Run linter on changed files + run: | + git diff "origin/$GITHUB_BASE_REF" -- "*.py" | flake8 . --config=.flake8 --diff --count --statistics --show-source diff --git a/docs/sphinx/source/changelog.rst b/docs/sphinx/source/changelog.rst index 305034ff..959fba82 100644 --- a/docs/sphinx/source/changelog.rst +++ b/docs/sphinx/source/changelog.rst @@ -1,6 +1,7 @@ RdTools Change Log ================== +.. include:: changelog/v2.0.5.rst .. include:: changelog/v2.0.4.rst .. include:: changelog/v2.0.3.rst .. include:: changelog/v2.0.2.rst diff --git a/docs/sphinx/source/changelog/v2.0.5.rst b/docs/sphinx/source/changelog/v2.0.5.rst index 2d810b1c..640fd14f 100644 --- a/docs/sphinx/source/changelog/v2.0.5.rst +++ b/docs/sphinx/source/changelog/v2.0.5.rst @@ -18,6 +18,9 @@ Bug fixes Testing ------- +* Add a flake8 code style check to the continuous integration checks (:pull:`231`) +* Moved several pytest fixtures from ``soiling_test.py`` and ``availability_test.py`` to ``conftest.py`` + so that they are shared across test files (:pull:`231`) * Add Python 3.9 to CI testing (:pull:`249`) * Fix test suite error raised when using pandas 1.2.0 (:pull:`251`) @@ -37,3 +40,4 @@ Example Updates Contributors ------------ +* Kevin Anderson (:ghuser:`kanderso-nrel`) \ No newline at end of file diff --git a/docs/sphinx/source/conf.py b/docs/sphinx/source/conf.py index 12e9c8e9..6249f447 100644 --- a/docs/sphinx/source/conf.py +++ b/docs/sphinx/source/conf.py @@ -26,7 +26,7 @@ author = 'kwhanalytics, Alliance for Sustainable Energy, LLC, and SunPower' # The full version, including alpha/beta/rc tags -import rdtools +import rdtools # noqa: E402 release = version = rdtools.__version__ @@ -84,6 +84,8 @@ smartquotes = False master_doc = 'index' + + # A workaround for the responsive tables always having annoying scrollbars. def setup(app): app.add_stylesheet("no_scrollbars.css") @@ -150,7 +152,7 @@ def make_github_url(pagename): rtd_version = os.environ.get('READTHEDOCS_VERSION', None) version_map = { 'stable': 'master', - 'latest': 'development', + 'latest': 'development', } try: branch = version_map[rtd_version] @@ -185,7 +187,7 @@ def make_github_url(pagename): # is the the changelog page? elif pagename == "changelog": target_url = URL_BASE + "docs/sphinx/source/changelog" - + # Just a normal source RST page else: target_url = URL_BASE + "docs/sphinx/source/" + pagename + ".rst" @@ -193,7 +195,7 @@ def make_github_url(pagename): display_text = "View on github/" + branch link_info = { 'url': target_url, - 'text': display_text + 'text': display_text } return link_info @@ -202,4 +204,4 @@ def make_github_url(pagename): # _templates/breadcrumbs.html html_context = { 'make_github_url': make_github_url, -} \ No newline at end of file +} diff --git a/docs/sphinx/source/developer_notes.rst b/docs/sphinx/source/developer_notes.rst index 360941bf..eca0c346 100644 --- a/docs/sphinx/source/developer_notes.rst +++ b/docs/sphinx/source/developer_notes.rst @@ -131,6 +131,26 @@ function isn't tested or a branch inside a function isn't tested. To get specific details, you can run ``coverage html`` to generate a detailed HTML report at ``htmlcov/index.html`` to view in a browser. + +Checking for code style +----------------------- + +RdTools uses `flake8 `_ to validate +code style. To run this check locally you'll need to have flake8 installed +(see :ref:`installing-optional-dependencies`). Then navigate to the git repo +folder and run + +:: + + flake8 + +Or, for a more detailed report: + +:: + + flake8 --count --statistics --show-source + + Building documentation locally ------------------------------ diff --git a/rdtools/degradation.py b/rdtools/degradation.py index 6489e997..c83d4807 100644 --- a/rdtools/degradation.py +++ b/rdtools/degradation.py @@ -244,8 +244,7 @@ def degradation_year_on_year(energy_normalized, recenter=True, energy_normalized = energy_normalized.reset_index() energy_normalized['energy'] = energy_normalized['energy'] / renorm - energy_normalized['dt_shifted'] = energy_normalized.dt + \ - pd.DateOffset(years=1) + energy_normalized['dt_shifted'] = energy_normalized.dt + pd.DateOffset(years=1) # Merge with what happened one year ago, use tolerance of 8 days to allow # for weekly aggregated data @@ -255,8 +254,7 @@ def degradation_year_on_year(energy_normalized, recenter=True, tolerance=pd.Timedelta('8D') ) - df['time_diff_years'] = (df.dt - df.dt_right).astype('timedelta64[h]') / \ - 8760.0 + df['time_diff_years'] = (df.dt - df.dt_right).astype('timedelta64[h]') / 8760.0 df['yoy'] = 100.0 * (df.energy - df.energy_right) / (df.time_diff_years) df.index = df.dt diff --git a/rdtools/normalization.py b/rdtools/normalization.py index 1f8d8219..73998611 100644 --- a/rdtools/normalization.py +++ b/rdtools/normalization.py @@ -170,7 +170,8 @@ def normalize_with_pvwatts(energy, pvwatts_kws): power_dc = pvwatts_dc_power(**pvwatts_kws) irrad = pvwatts_kws['poa_global'] - energy_normalized, insolation = normalize_with_expected_power(energy, power_dc, irrad, pv_input='energy') + energy_normalized, insolation = normalize_with_expected_power(energy, power_dc, irrad, + pv_input='energy') return energy_normalized, insolation @@ -291,7 +292,8 @@ def normalize_with_sapm(energy, sapm_kws): power_dc, irrad = sapm_dc_power(**sapm_kws) - energy_normalized, insolation = normalize_with_expected_power(energy, power_dc, irrad, pv_input='energy') + energy_normalized, insolation = normalize_with_expected_power(energy, power_dc, irrad, + pv_input='energy') return energy_normalized, insolation @@ -471,7 +473,8 @@ def _t_step_nanoseconds(time_series): return t_steps -def energy_from_power(power, target_frequency=None, max_timedelta=None, power_type='right_labeled'): +def energy_from_power(power, target_frequency=None, max_timedelta=None, + power_type='right_labeled'): ''' Returns a regular right-labeled energy time series in units of Wh per interval from a power time series. For instantaneous timeseries, a @@ -487,7 +490,7 @@ def energy_from_power(power, target_frequency=None, max_timedelta=None, power_ty target_frequency : DatetimeOffset or frequency string, default None The frequency of the energy time series to be returned. If omitted, use the median timestep of ``power``, or if ``power`` has - fewer than two elements, use ``power.index.freq`. + fewer than two elements, use ``power.index.freq``. max_timedelta : pd.Timedelta, default None The maximum allowed gap between power measurements. If the gap between consecutive power measurements exceeds ``max_timedelta``, NaN will be @@ -795,13 +798,13 @@ def interpolate(time_series, target, max_timedelta=None, warning_threshold=0.1): if isinstance(time_series, pd.Series): out = _interpolate_series(time_series, target_index, max_timedelta, - warning_threshold) + warning_threshold) elif isinstance(time_series, pd.DataFrame): out_list = [] for col in time_series.columns: ts = time_series[col] series = _interpolate_series(ts, target_index, max_timedelta, - warning_threshold) + warning_threshold) out_list.append(series) out = pd.concat(out_list, axis=1) else: diff --git a/rdtools/plotting.py b/rdtools/plotting.py index ec71f3f1..20791cea 100644 --- a/rdtools/plotting.py +++ b/rdtools/plotting.py @@ -4,6 +4,7 @@ import numpy as np import warnings + def degradation_summary_plots(yoy_rd, yoy_ci, yoy_info, normalized_yield, hist_xmin=None, hist_xmax=None, bins=None, scatter_ymin=None, scatter_ymax=None, diff --git a/rdtools/soiling.py b/rdtools/soiling.py index f62ccfc0..39f065d3 100644 --- a/rdtools/soiling.py +++ b/rdtools/soiling.py @@ -17,6 +17,7 @@ 'and PATCH releases) as the code matures.' ) + # Custom exception class NoValidIntervalError(Exception): '''raised when no valid rows appear in the result dataframe''' @@ -456,7 +457,10 @@ def _calc_monte(self, monte, method='half_norm_clean'): df_rand['soil_insol'] = df_rand.loss * df_rand.insol - monte_losses.append(df_rand.soil_insol.sum() / df_rand.insol[~df_rand.soil_insol.isnull()].sum()) + soiling_ratio = ( + df_rand.soil_insol.sum() / df_rand.insol[~df_rand.soil_insol.isnull()].sum() + ) + monte_losses.append(soiling_ratio) random_profile = df_rand['loss'].copy() random_profile.name = 'stochastic_soiling_profile' random_profiles.append(random_profile) @@ -842,9 +846,10 @@ def annual_soiling_ratios(stochastic_soiling_profiles, insolation_daily, confide all_profiles = all_profiles.dropna() if not all_profiles.index.isin(insolation_daily.index).all(): - warnings.warn('The indexes of stochastic_soiling_profiles are not entirely contained ' - 'within the index of insolation_daily. Every day in stochastic_soiling_profiles ' - 'should be represented in insolation_daily. This may cause erroneous results.') + warnings.warn( + 'The indexes of stochastic_soiling_profiles are not entirely contained ' + 'within the index of insolation_daily. Every day in stochastic_soiling_profiles ' + 'should be represented in insolation_daily. This may cause erroneous results.') insolation_daily = insolation_daily.reindex(all_profiles.index) @@ -853,7 +858,7 @@ def annual_soiling_ratios(stochastic_soiling_profiles, insolation_daily, confide # Compute the insolation-weighted soiling ratio (IWSR) for each realization annual_insolation = insolation_daily.groupby(insolation_daily.index.year).sum() - all_annual_weighted_sums = all_profiles_weighted.groupby(all_profiles_weighted.index.year).sum() + all_annual_weighted_sums = all_profiles_weighted.groupby(all_profiles_weighted.index.year).sum() # noqa: E501 all_annual_iwsr = all_annual_weighted_sums.multiply(1/annual_insolation, axis=0) annual_soiling = pd.DataFrame({ @@ -936,12 +941,15 @@ def monthly_soiling_rates(soiling_interval_summary, min_interval_length=14, ''' # filter to intervals of interest - rel_error = 100 * abs((soiling_interval_summary['soiling_rate_high'] - - soiling_interval_summary['soiling_rate_low']) / soiling_interval_summary['soiling_rate']) - intervals = soiling_interval_summary[(soiling_interval_summary['length'] >= min_interval_length) & - (soiling_interval_summary['valid']) & - (rel_error <= max_relative_slope_error) - ].copy() + high = soiling_interval_summary['soiling_rate_high'] + low = soiling_interval_summary['soiling_rate_low'] + rate = soiling_interval_summary['soiling_rate'] + rel_error = 100 * abs((high - low) / rate) + intervals = soiling_interval_summary[ + (soiling_interval_summary['length'] >= min_interval_length) & + (soiling_interval_summary['valid']) & + (rel_error <= max_relative_slope_error) + ].copy() # count the overlap of each interval with each month month_counts = [] @@ -951,12 +959,13 @@ def monthly_soiling_rates(soiling_interval_summary, min_interval_length=14, # divy up the monte carlo reps based on overlap for month in range(1, 13): days_in_month = np.array([x[month] for x in month_counts]) + sample_col = f'samples_for_month_{month}' if days_in_month.sum() > 0: - intervals[f'samples_for_month_{month}'] = np.ceil( + intervals[sample_col] = np.ceil( days_in_month / days_in_month.sum() * reps) else: - intervals[f'samples_for_month_{month}'] = 0 - intervals[f'samples_for_month_{month}'] = intervals[f'samples_for_month_{month}'].astype(int) + intervals[sample_col] = 0 + intervals[sample_col] = intervals[sample_col].astype(int) # perform the monte carlo month by month ci_quantiles = [0.5 - confidence_level/2/100, 0.5 + confidence_level/2/100] @@ -983,7 +992,9 @@ def monthly_soiling_rates(soiling_interval_summary, min_interval_length=14, # make a dataframe out of the results monthly_soiling_df = pd.DataFrame(data=monthly_rate_data, - columns=['soiling_rate_median', 'soiling_rate_low', 'soiling_rate_high']) + columns=['soiling_rate_median', + 'soiling_rate_low', + 'soiling_rate_high']) monthly_soiling_df.insert(0, 'month', range(1, 13)) monthly_soiling_df['interval_count'] = relevant_interval_count diff --git a/rdtools/test/availability_test.py b/rdtools/test/availability_test.py index 9af3bd12..7197608f 100644 --- a/rdtools/test/availability_test.py +++ b/rdtools/test/availability_test.py @@ -12,7 +12,6 @@ import pandas as pd import numpy as np import itertools -import datetime import matplotlib.pyplot as plt # Values to parametrize power tests across. One test will be run for each @@ -189,6 +188,7 @@ def difficult_data(): return df, meter_power, expected_power, relative_sizes + def test_calc_loss_subsystem_relative_sizes(difficult_data): # test that manually passing in relative_sizes improves the results # for pathological datasets with tons of downtime @@ -214,91 +214,6 @@ def test_calc_loss_subsystem_relative_sizes(difficult_data): # %% -ENERGY_PARAMETER_SPACE = list(itertools.product( - [0, np.nan], # outage value for power - [0, np.nan, None], # value for cumulative energy (None means real value) - [0, 0.25, 0.5, 0.75, 1.0], # fraction of comms outage that is power outage -)) -# display names for the test cases. default is just 0..N -ENERGY_PARAMETER_IDS = ["_".join(map(str, p)) for p in ENERGY_PARAMETER_SPACE] - - -def _generate_energy_data(power_value, energy_value, outage_fraction): - """ - Generate an artificial mixed communication/power outage. - """ - # a few days of clearsky irradiance for creating a plausible power signal - times = pd.date_range('2019-01-01', '2019-01-15 23:59', freq='15min', - tz='US/Eastern') - location = pvlib.location.Location(40, -80) - # use haurwitz to avoid dependency on `tables` - clearsky = location.get_clearsky(times, model='haurwitz') - - # just set base inverter power = ghi+clipping for simplicity - base_power = clearsky['ghi'].clip(upper=0.8*clearsky['ghi'].max()) - - inverter_power = pd.DataFrame({ - 'inv0': base_power, - 'inv1': base_power*0.7, - 'inv2': base_power*1.3, - }) - expected_power = inverter_power.sum(axis=1) - # dawn/dusk points - expected_power[expected_power < 10] = 0 - # add noise and bias to the expected power signal - np.random.seed(2020) - expected_power *= 1.05 + np.random.normal(0, scale=0.05, size=len(times)) - - # calculate what part of the comms outage is a power outage - comms_outage = slice('2019-01-03 00:00', '2019-01-06 00:00') - start = times.get_loc(comms_outage.start) - stop = times.get_loc(comms_outage.stop) - power_outage = slice(start, int(start + outage_fraction * (stop-start))) - expected_loss = inverter_power.iloc[power_outage, :].sum().sum() / 4 - inverter_power.iloc[power_outage, :] = 0 - meter_power = inverter_power.sum(axis=1) - meter_energy = meter_power.cumsum() / 4 - # add an offset because in practice cumulative meter data never - # actually starts at 0: - meter_energy += 100 - - meter_power[comms_outage] = power_value - if energy_value is not None: - meter_energy[comms_outage] = energy_value - inverter_power.loc[comms_outage, :] = power_value - - expected_type = 'real' if outage_fraction > 0 else 'comms' - - return (meter_power, - meter_energy, - inverter_power, - expected_power, - expected_loss, - expected_type) - - -@pytest.fixture(params=ENERGY_PARAMETER_SPACE, ids=ENERGY_PARAMETER_IDS) -def energy_data(request): - # fixture sweeping across the entire parameter space - power_value, energy_value, outage_fraction = request.param - return _generate_energy_data(power_value, energy_value, outage_fraction) - - -@pytest.fixture -def energy_data_outage_single(): - # fixture only using a single parameter combination, for simpler tests. - # has one real outage. - outage_value, outage_fraction = np.nan, 0.25 - return _generate_energy_data(outage_value, outage_value, outage_fraction) - - -@pytest.fixture -def energy_data_comms_single(): - # fixture only using a single parameter combination, for simpler tests. - # has one comms outage. - outage_value, outage_fraction = np.nan, 0 - return _generate_energy_data(outage_value, outage_value, outage_fraction) - def test__calc_loss_system(energy_data): # test single outage @@ -408,20 +323,6 @@ def test__calc_loss_system_quantiles(energy_data_comms_single): # %% plotting -@pytest.fixture -def availability_analysis_object(energy_data_outage_single): - (meter_power, - meter_energy, - inverter_power, - expected_power, - _, _) = energy_data_outage_single - - aa = AvailabilityAnalysis(meter_power, inverter_power, meter_energy, - expected_power) - aa.run() - return aa - - def test_plot(availability_analysis_object): result = availability_analysis_object.plot() assert_isinstance(result, plt.Figure) @@ -458,7 +359,7 @@ def test_availability_analysis_index_mismatch(energy_data_outage_single): value_shortened = value.iloc[1:] kwargs[key] = value_shortened with pytest.raises(ValueError, match='timeseries indexes must match'): - aa = AvailabilityAnalysis(**kwargs) + _ = AvailabilityAnalysis(**kwargs) def test_availability_analysis_doublecount_loss(availability_analysis_object): diff --git a/rdtools/test/clearsky_temperature_test.py b/rdtools/test/clearsky_temperature_test.py index 2ee89bc2..550d77cb 100644 --- a/rdtools/test/clearsky_temperature_test.py +++ b/rdtools/test/clearsky_temperature_test.py @@ -1,6 +1,5 @@ import unittest import pandas as pd -from datetime import datetime from rdtools.clearsky_temperature import get_clearsky_tamb @@ -10,19 +9,18 @@ class ClearSkyTemperatureTestCase(unittest.TestCase): def setUp(self): - dt = pd.date_range(datetime(2015,1,1), datetime(2015,2,1), freq='15min', tz = 'Asia/Shanghai') + dt = pd.date_range('2015-01-01', '2015-02-01', freq='15min', tz='Asia/Shanghai') self.china_west = get_clearsky_tamb(dt, 37.951721, 80.609843) self.china_east = get_clearsky_tamb(dt, 36.693692, 117.699686) - #self.china_west.to_csv("west.csv") - #self.china_east.to_csv("east.csv") - + # self.china_west.to_csv("west.csv") + # self.china_east.to_csv("east.csv") # Test for shifting temperature peak with longitude for same timezone def test_hour_offset(self): - df = pd.DataFrame(index = self.china_west.index) + df = pd.DataFrame(index=self.china_west.index) df['west'] = self.china_west df['east'] = self.china_east df['hour'] = df.index.hour @@ -30,15 +28,12 @@ def test_hour_offset(self): west_hottest_hour = df.sort_values(by='west', ascending=False)['hour'].iloc[0] east_hottest_hour = df.sort_values(by='east', ascending=False)['hour'].iloc[0] - #print west_hottest_hour , east_hottest_hour + # print west_hottest_hour , east_hottest_hour self.assertTrue(west_hottest_hour > 12) self.assertTrue(east_hottest_hour > 12) self.assertTrue(west_hottest_hour > east_hottest_hour) -# TODO: -# Test irradiance_rescale - if __name__ == '__main__': unittest.main() diff --git a/rdtools/test/conftest.py b/rdtools/test/conftest.py index 93c785ef..9aa3b80c 100644 --- a/rdtools/test/conftest.py +++ b/rdtools/test/conftest.py @@ -1,6 +1,10 @@ from pkg_resources import parse_version import pytest from functools import wraps +import numpy as np +import pandas as pd +import itertools +import pvlib import rdtools @@ -32,3 +36,140 @@ def inner(*args, **kwargs): def assert_isinstance(obj, klass): assert isinstance(obj, klass), f'got {type(obj)}, expected {klass}' + + +# %% Soiling fixtures + +@pytest.fixture() +def soiling_times(): + tz = 'Etc/GMT+7' + times = pd.date_range('2019/01/01', '2019/03/16', freq='D', tz=tz) + return times + + +@pytest.fixture() +def soiling_normalized_daily(soiling_times): + interval_1 = 1 - 0.005 * np.arange(0, 25, 1) + interval_2 = 1 - 0.002 * np.arange(0, 25, 1) + interval_3 = 1 - 0.001 * np.arange(0, 25, 1) + profile = np.concatenate((interval_1, interval_2, interval_3)) + np.random.seed(1977) + noise = 0.01 * np.random.rand(75) + normalized_daily = pd.Series(data=profile, index=soiling_times) + normalized_daily = normalized_daily + noise + + return normalized_daily + + +@pytest.fixture() +def soiling_insolation(soiling_times): + insolation = np.empty((75,)) + insolation[:30] = 8000 + insolation[30:45] = 6000 + insolation[45:] = 7000 + + insolation = pd.Series(data=insolation, index=soiling_times) + + return insolation + + +# %% Availability fixtures + +ENERGY_PARAMETER_SPACE = list(itertools.product( + [0, np.nan], # outage value for power + [0, np.nan, None], # value for cumulative energy (None means real value) + [0, 0.25, 0.5, 0.75, 1.0], # fraction of comms outage that is power outage +)) +# display names for the test cases. default is just 0..N +ENERGY_PARAMETER_IDS = ["_".join(map(str, p)) for p in ENERGY_PARAMETER_SPACE] + + +def _generate_energy_data(power_value, energy_value, outage_fraction): + """ + Generate an artificial mixed communication/power outage. + """ + # a few days of clearsky irradiance for creating a plausible power signal + times = pd.date_range('2019-01-01', '2019-01-15 23:59', freq='15min', + tz='US/Eastern') + location = pvlib.location.Location(40, -80) + # use haurwitz to avoid dependency on `tables` + clearsky = location.get_clearsky(times, model='haurwitz') + + # just set base inverter power = ghi+clipping for simplicity + base_power = clearsky['ghi'].clip(upper=0.8*clearsky['ghi'].max()) + + inverter_power = pd.DataFrame({ + 'inv0': base_power, + 'inv1': base_power*0.7, + 'inv2': base_power*1.3, + }) + expected_power = inverter_power.sum(axis=1) + # dawn/dusk points + expected_power[expected_power < 10] = 0 + # add noise and bias to the expected power signal + np.random.seed(2020) + expected_power *= 1.05 + np.random.normal(0, scale=0.05, size=len(times)) + + # calculate what part of the comms outage is a power outage + comms_outage = slice('2019-01-03 00:00', '2019-01-06 00:00') + start = times.get_loc(comms_outage.start) + stop = times.get_loc(comms_outage.stop) + power_outage = slice(start, int(start + outage_fraction * (stop-start))) + expected_loss = inverter_power.iloc[power_outage, :].sum().sum() / 4 + inverter_power.iloc[power_outage, :] = 0 + meter_power = inverter_power.sum(axis=1) + meter_energy = meter_power.cumsum() / 4 + # add an offset because in practice cumulative meter data never + # actually starts at 0: + meter_energy += 100 + + meter_power[comms_outage] = power_value + if energy_value is not None: + meter_energy[comms_outage] = energy_value + inverter_power.loc[comms_outage, :] = power_value + + expected_type = 'real' if outage_fraction > 0 else 'comms' + + return (meter_power, + meter_energy, + inverter_power, + expected_power, + expected_loss, + expected_type) + + +@pytest.fixture(params=ENERGY_PARAMETER_SPACE, ids=ENERGY_PARAMETER_IDS) +def energy_data(request): + # fixture sweeping across the entire parameter space + power_value, energy_value, outage_fraction = request.param + return _generate_energy_data(power_value, energy_value, outage_fraction) + + +@pytest.fixture +def energy_data_outage_single(): + # fixture only using a single parameter combination, for simpler tests. + # has one real outage. + outage_value, outage_fraction = np.nan, 0.25 + return _generate_energy_data(outage_value, outage_value, outage_fraction) + + +@pytest.fixture +def energy_data_comms_single(): + # fixture only using a single parameter combination, for simpler tests. + # has one comms outage. + outage_value, outage_fraction = np.nan, 0 + return _generate_energy_data(outage_value, outage_value, outage_fraction) + + +@pytest.fixture +def availability_analysis_object(energy_data_outage_single): + (meter_power, + meter_energy, + inverter_power, + expected_power, + _, _) = energy_data_outage_single + + aa = rdtools.availability.AvailabilityAnalysis(meter_power, inverter_power, meter_energy, + expected_power) + aa.run() + return aa diff --git a/rdtools/test/degradation_test.py b/rdtools/test/degradation_test.py index 97b3bab3..31c8db20 100644 --- a/rdtools/test/degradation_test.py +++ b/rdtools/test/degradation_test.py @@ -16,7 +16,7 @@ class DegradationTestCase(unittest.TestCase): @classmethod def get_corr_energy(cls, rd, input_freq): - #lock seed to make test deterministic + # lock seed to make test deterministic np.random.seed(0) daily_rd = rd / 365.0 @@ -137,10 +137,10 @@ def test_confidence_intervals(self): r1 = func(self.test_corr_energy[input_freq], confidence_level=ci1) r2 = func(self.test_corr_energy[input_freq], confidence_level=ci2) - logging.debug("func: {}, ci: {}, ({}) {} ({})"\ - .format(str(func).split(' ')[1], ci1, r1[1][0], r1[0], r1[1][1])) - logging.debug("func: {}, ci: {}, ({}) {} ({})"\ - .format(str(func).split(' ')[1], ci2, r2[1][0], r2[0], r2[1][1])) + logging.debug("func: {}, ci: {}, ({}) {} ({})" + .format(str(func).split(' ')[1], ci1, r1[1][0], r1[0], r1[1][1])) + logging.debug("func: {}, ci: {}, ({}) {} ({})" + .format(str(func).split(' ')[1], ci2, r2[1][0], r2[0], r2[1][1])) # lower limit is lower than median and upper limit is higher than median self.assertTrue(r1[0] > r1[1][0] and r1[0] < r1[1][1]) diff --git a/rdtools/test/energy_from_power_test.py b/rdtools/test/energy_from_power_test.py index a833aab4..761823d9 100644 --- a/rdtools/test/energy_from_power_test.py +++ b/rdtools/test/energy_from_power_test.py @@ -88,7 +88,8 @@ def test_energy_from_power_single_value_input_no_freq(): def test_energy_from_power_single_value_instantaneous(): power = pd.Series([1], pd.date_range('2019-01-01', periods=1, freq='15T')) power.index.freq = None - match = "power_type='instantaneous' is incompatible with single element power. Use power_type='right-labeled'" + match = ("power_type='instantaneous' is incompatible with single element power. " + "Use power_type='right-labeled'") with pytest.raises(ValueError, match=match): energy_from_power(power, power_type='instantaneous') diff --git a/rdtools/test/filtering_test.py b/rdtools/test/filtering_test.py index be03a512..58aad3e0 100644 --- a/rdtools/test/filtering_test.py +++ b/rdtools/test/filtering_test.py @@ -87,8 +87,10 @@ def test_normalized_filter_default(): energy_normalized_high=1), pd.Series([False, False])) - pd.testing.assert_series_equal(normalized_filter(pd.Series([0.01 - 1e-16, 0.01 + 1e-16, 1e308])), + eps = 1e-16 + pd.testing.assert_series_equal(normalized_filter(pd.Series([0.01 - eps, 0.01 + eps, 1e308])), pd.Series([False, True, True])) + if __name__ == '__main__': unittest.main() diff --git a/rdtools/test/interpolate_test.py b/rdtools/test/interpolate_test.py index e4826a8e..1cac37b9 100644 --- a/rdtools/test/interpolate_test.py +++ b/rdtools/test/interpolate_test.py @@ -55,8 +55,8 @@ def df_expected_result(df_target_index, test_df): def test_interpolate_freq_specification(time_series, target_index, expected_series): # test the string specification - interpolated = interpolate(time_series, target_index.freq.freqstr, pd.to_timedelta('15 minutes'), - warning_threshold=0.21) + interpolated = interpolate(time_series, target_index.freq.freqstr, + pd.to_timedelta('15 minutes'), warning_threshold=0.21) pd.testing.assert_series_equal(interpolated, expected_series) # test the DateOffset specification diff --git a/rdtools/test/normalization_pvwatts_test.py b/rdtools/test/normalization_pvwatts_test.py index e67f581a..263ce492 100644 --- a/rdtools/test/normalization_pvwatts_test.py +++ b/rdtools/test/normalization_pvwatts_test.py @@ -1,7 +1,6 @@ """ Energy Normalization with PVWatts Unit Tests. """ import unittest -import pytest import pandas as pd import numpy as np diff --git a/rdtools/test/normalize_with_expected_power_test.py b/rdtools/test/normalize_with_expected_power_test.py index 79d6ded4..746e062d 100644 --- a/rdtools/test/normalize_with_expected_power_test.py +++ b/rdtools/test/normalize_with_expected_power_test.py @@ -1,8 +1,6 @@ import pandas as pd import pytest from rdtools.normalization import normalize_with_expected_power -from pandas import Timestamp -import numpy as np @pytest.fixture() diff --git a/rdtools/test/plotting_test.py b/rdtools/test/plotting_test.py index 3062b696..43b55437 100644 --- a/rdtools/test/plotting_test.py +++ b/rdtools/test/plotting_test.py @@ -1,9 +1,7 @@ import pandas as pd import numpy as np -import rdtools from rdtools.degradation import degradation_year_on_year from rdtools.soiling import soiling_srr -from rdtools.normalization import energy_from_power from rdtools.plotting import ( degradation_summary_plots, soiling_monte_carlo_plot, @@ -16,18 +14,6 @@ from conftest import assert_isinstance -# bring in soiling pytest fixtures -from soiling_test import ( - times, # can't rename this or else the others can't find it - normalized_daily as soiling_normalized_daily, - insolation as soiling_insolation, -) - -# availability pytest fixture -from availability_test import ( - energy_data_outage_single, - availability_analysis_object -) # can't import degradation fixtures because it's a unittest file. # roll our own here instead: @@ -188,4 +174,3 @@ def test_availability_summary_plots_empty(availability_analysis_object): aa.energy_cumulative, aa.energy_expected_rescaled, empty) assert_isinstance(result, plt.Figure) - diff --git a/rdtools/test/soiling_test.py b/rdtools/test/soiling_test.py index 2b1e6f01..1fc15cbe 100644 --- a/rdtools/test/soiling_test.py +++ b/rdtools/test/soiling_test.py @@ -8,44 +8,11 @@ import pytest -@pytest.fixture() -def times(): - tz = 'Etc/GMT+7' - times = pd.date_range('2019/01/01', '2019/03/16', freq='D', tz=tz) - return times - - -@pytest.fixture() -def normalized_daily(times): - interval_1 = 1 - 0.005 * np.arange(0, 25, 1) - interval_2 = 1 - 0.002 * np.arange(0, 25, 1) - interval_3 = 1 - 0.001 * np.arange(0, 25, 1) - profile = np.concatenate((interval_1, interval_2, interval_3)) - np.random.seed(1977) - noise = 0.01 * np.random.rand(75) - normalized_daily = pd.Series(data=profile, index=times) - normalized_daily = normalized_daily + noise - - return normalized_daily - - -@pytest.fixture() -def insolation(times): - insolation = np.empty((75,)) - insolation[:30] = 8000 - insolation[30:45] = 6000 - insolation[45:] = 7000 - - insolation = pd.Series(data=insolation, index=times) - - return insolation - - -def test_soiling_srr(normalized_daily, insolation, times): +def test_soiling_srr(soiling_normalized_daily, soiling_insolation, soiling_times): reps = 10 np.random.seed(1977) - sr, sr_ci, soiling_info = soiling_srr(normalized_daily, insolation, reps=reps) + sr, sr_ci, soiling_info = soiling_srr(soiling_normalized_daily, soiling_insolation, reps=reps) assert 0.963133 == pytest.approx(sr, abs=1e-6),\ 'Soiling ratio different from expected value' assert np.array([0.961054, 0.964019]) == pytest.approx(sr_ci, abs=1e-6),\ @@ -60,16 +27,17 @@ def test_soiling_srr(normalized_daily, insolation, times): 'soiling_info["stochastic_soiling_profiles"] is not a list' # Check soiling_info['soiling_interval_summary'] - expected_summary_columns = ['start', 'end', 'soiling_rate', 'soiling_rate_low', 'soiling_rate_high', - 'inferred_start_loss', 'inferred_end_loss', 'length', 'valid'] + expected_summary_columns = ['start', 'end', 'soiling_rate', 'soiling_rate_low', + 'soiling_rate_high', 'inferred_start_loss', 'inferred_end_loss', + 'length', 'valid'] actual_summary_columns = soiling_info['soiling_interval_summary'].columns.values for x in actual_summary_columns: assert x in expected_summary_columns,\ - "'{}' not an expected column in soiling_info['soiling_interval_summary']".format(x) + f"'{x}' not an expected column in soiling_info['soiling_interval_summary']" for x in expected_summary_columns: assert x in actual_summary_columns,\ - "'{}' was expected as a column, but not in soiling_info['soiling_interval_summary']".format(x) + f"'{x}' was expected as a column, but not in soiling_info['soiling_interval_summary']" assert isinstance(soiling_info['soiling_interval_summary'], pd.DataFrame),\ 'soiling_info["soiling_interval_summary"] not a dataframe' expected_means = pd.Series({'soiling_rate': -0.002617290, @@ -86,15 +54,17 @@ def test_soiling_srr(normalized_daily, insolation, times): check_exact=False, check_less_precise=6) # Check soiling_info['soiling_ratio_perfect_clean'] - pd.testing.assert_index_equal(soiling_info['soiling_ratio_perfect_clean'].index, times, check_names=False) - assert 0.967170 == pytest.approx(soiling_info['soiling_ratio_perfect_clean'].mean(), abs=1e-6),\ + pd.testing.assert_index_equal(soiling_info['soiling_ratio_perfect_clean'].index, soiling_times, + check_names=False) + sr_mean = soiling_info['soiling_ratio_perfect_clean'].mean() + assert 0.967170 == pytest.approx(sr_mean, abs=1e-6),\ "The mean of soiling_info['soiling_ratio_perfect_clean'] differs from expected" assert isinstance(soiling_info['soiling_ratio_perfect_clean'], pd.Series),\ 'soiling_info["soiling_ratio_perfect_clean"] not a pandas series' -def test_soiling_srr_with_precip(normalized_daily, insolation, times): - precip = pd.Series(index=times, data=0) +def test_soiling_srr_with_precip(soiling_normalized_daily, soiling_insolation, soiling_times): + precip = pd.Series(index=soiling_times, data=0) precip['2019-01-18 00:00:00-07:00'] = 1 precip['2019-02-20 00:00:00-07:00'] = 1 @@ -103,60 +73,64 @@ def test_soiling_srr_with_precip(normalized_daily, insolation, times): 'precipitation_daily': precip } np.random.seed(1977) - sr, sr_ci, soiling_info = soiling_srr(normalized_daily, insolation, clean_criterion='precip_and_shift', **kwargs) + sr, sr_ci, soiling_info = soiling_srr(soiling_normalized_daily, soiling_insolation, + clean_criterion='precip_and_shift', **kwargs) assert 0.983270 == pytest.approx(sr, abs=1e-6),\ "Soiling ratio with clean_criterion='precip_and_shift' different from expected" np.random.seed(1977) - sr, sr_ci, soiling_info = soiling_srr(normalized_daily, insolation, clean_criterion='precip_or_shift', **kwargs) + sr, sr_ci, soiling_info = soiling_srr(soiling_normalized_daily, soiling_insolation, + clean_criterion='precip_or_shift', **kwargs) assert 0.973228 == pytest.approx(sr, abs=1e-6),\ "Soiling ratio with clean_criterion='precip_or_shift' different from expected" np.random.seed(1977) - sr, sr_ci, soiling_info = soiling_srr(normalized_daily, insolation, clean_criterion='precip', **kwargs) + sr, sr_ci, soiling_info = soiling_srr(soiling_normalized_daily, soiling_insolation, + clean_criterion='precip', **kwargs) assert 0.976196 == pytest.approx(sr, abs=1e-6),\ "Soiling ratio with clean_criterion='precip' different from expected" np.random.seed(1977) - sr, sr_ci, soiling_info = soiling_srr(normalized_daily, insolation, clean_criterion='shift', **kwargs) + sr, sr_ci, soiling_info = soiling_srr(soiling_normalized_daily, soiling_insolation, + clean_criterion='shift', **kwargs) assert 0.963133 == pytest.approx(sr, abs=1e-6),\ "Soiling ratio with clean_criterion='shift' different from expected" -def test_soiling_srr_confidence_levels(normalized_daily, insolation): +def test_soiling_srr_confidence_levels(soiling_normalized_daily, soiling_insolation): 'Tests SRR with different confidence level settingsf from above' np.random.seed(1977) - sr, sr_ci, soiling_info = soiling_srr(normalized_daily, insolation, confidence_level=95, reps=10, - exceedance_prob=80.0) + sr, sr_ci, soiling_info = soiling_srr(soiling_normalized_daily, soiling_insolation, + confidence_level=95, reps=10, exceedance_prob=80.0) assert np.array([0.957272, 0.964763]) == pytest.approx(sr_ci, abs=1e-6),\ 'Confidence interval with confidence_level=95 different than expected' assert 0.961285 == pytest.approx(soiling_info['exceedance_level'], abs=1e-6),\ 'soiling_info["exceedance_level"] different than expected when exceedance_prob=80' -def test_soiling_srr_dayscale(normalized_daily, insolation): +def test_soiling_srr_dayscale(soiling_normalized_daily, soiling_insolation): 'Test that a long dayscale can prevent valid intervals from being found' with pytest.raises(NoValidIntervalError): np.random.seed(1977) - sr, sr_ci, soiling_info = soiling_srr(normalized_daily, insolation, confidence_level=68.2, - reps=10, day_scale=90) + sr, sr_ci, soiling_info = soiling_srr(soiling_normalized_daily, soiling_insolation, + confidence_level=68.2, reps=10, day_scale=90) -def test_soiling_srr_clean_threshold(normalized_daily, insolation): +def test_soiling_srr_clean_threshold(soiling_normalized_daily, soiling_insolation): '''Test that clean test_soiling_srr_clean_threshold works with a float and can cause no soiling intervals to be found''' np.random.seed(1977) - sr, sr_ci, soiling_info = soiling_srr(normalized_daily, insolation, reps=10, + sr, sr_ci, soiling_info = soiling_srr(soiling_normalized_daily, soiling_insolation, reps=10, clean_threshold=0.01) assert 0.963133 == pytest.approx(sr, abs=1e-6),\ 'Soiling ratio with specified clean_threshold different from expected value' with pytest.raises(NoValidIntervalError): np.random.seed(1977) - sr, sr_ci, soiling_info = soiling_srr(normalized_daily, insolation, reps=10, - clean_threshold=0.1) + sr, sr_ci, soiling_info = soiling_srr(soiling_normalized_daily, soiling_insolation, + reps=10, clean_threshold=0.1) -def test_soiling_srr_trim(normalized_daily, insolation): +def test_soiling_srr_trim(soiling_normalized_daily, soiling_insolation): np.random.seed(1977) - sr, sr_ci, soiling_info = soiling_srr(normalized_daily, insolation, reps=10, + sr, sr_ci, soiling_info = soiling_srr(soiling_normalized_daily, soiling_insolation, reps=10, trim=True) assert 0.978369 == pytest.approx(sr, abs=1e-6),\ @@ -165,36 +139,36 @@ def test_soiling_srr_trim(normalized_daily, insolation): 'Wrong number of soiling intervals found with trim=True' -def test_soiling_srr_method(normalized_daily, insolation): +def test_soiling_srr_method(soiling_normalized_daily, soiling_insolation): np.random.seed(1977) - sr, sr_ci, soiling_info = soiling_srr(normalized_daily, insolation, reps=10, + sr, sr_ci, soiling_info = soiling_srr(soiling_normalized_daily, soiling_insolation, reps=10, method='random_clean') assert 0.918767 == pytest.approx(sr, abs=1e-6),\ 'Soiling ratio with method="random_clean" different from expected value' np.random.seed(1977) - sr, sr_ci, soiling_info = soiling_srr(normalized_daily, insolation, reps=10, + sr, sr_ci, soiling_info = soiling_srr(soiling_normalized_daily, soiling_insolation, reps=10, method='perfect_clean') assert 0.965653 == pytest.approx(sr, abs=1e-6),\ 'Soiling ratio with method="perfect_clean" different from expected value' -def test_soiling_srr_min_interval_length(normalized_daily, insolation): +def test_soiling_srr_min_interval_length(soiling_normalized_daily, soiling_insolation): 'Test that a long minimum interval length prevents finding shorter intervals' with pytest.raises(NoValidIntervalError): np.random.seed(1977) # normalized_daily intervals are 25 days long, so min=26 should fail: - _ = soiling_srr(normalized_daily, insolation, confidence_level=68.2, + _ = soiling_srr(soiling_normalized_daily, soiling_insolation, confidence_level=68.2, reps=10, min_interval_length=26) # but min=24 should be fine: - _ = soiling_srr(normalized_daily, insolation, confidence_level=68.2, + _ = soiling_srr(soiling_normalized_daily, soiling_insolation, confidence_level=68.2, reps=10, min_interval_length=24) -def test_soiling_srr_recenter_false(normalized_daily, insolation): +def test_soiling_srr_recenter_false(soiling_normalized_daily, soiling_insolation): np.random.seed(1977) - sr, sr_ci, soiling_info = soiling_srr(normalized_daily, insolation, reps=10, + sr, sr_ci, soiling_info = soiling_srr(soiling_normalized_daily, soiling_insolation, reps=10, recenter=False) assert 1 == soiling_info['renormalizing_factor'],\ 'Renormalizing factor != 1 with recenter=False' @@ -202,24 +176,24 @@ def test_soiling_srr_recenter_false(normalized_daily, insolation): 'Soiling ratio different than expected when recenter=False' -def test_soiling_srr_negative_step(normalized_daily, insolation): - stepped_daily = normalized_daily.copy() +def test_soiling_srr_negative_step(soiling_normalized_daily, soiling_insolation): + stepped_daily = soiling_normalized_daily.copy() stepped_daily.iloc[37:] = stepped_daily.iloc[37:] - 0.1 np.random.seed(1977) - sr, sr_ci, soiling_info = soiling_srr(stepped_daily, insolation, reps=10) + sr, sr_ci, soiling_info = soiling_srr(stepped_daily, soiling_insolation, reps=10) assert list(soiling_info['soiling_interval_summary']['valid'].values) == [True, False, True],\ 'Soiling interval validity differs from expected when a large negative step\ is incorporated into the data' assert 0.934927 == pytest.approx(sr, abs=1e-6),\ - 'Soiling ratio different from expected when a large negative step is incorporated into the data' + 'Soiling ratio different from expected when a large negative step is incorporated into the data' # noqa: E501 -def test_soiling_srr_max_negative_slope_error(normalized_daily, insolation): +def test_soiling_srr_max_negative_slope_error(soiling_normalized_daily, soiling_insolation): np.random.seed(1977) - sr, sr_ci, soiling_info = soiling_srr(normalized_daily, insolation, reps=10, + sr, sr_ci, soiling_info = soiling_srr(soiling_normalized_daily, soiling_insolation, reps=10, max_relative_slope_error=50.0) assert list(soiling_info['soiling_interval_summary']['valid'].values) == [True, True, False],\ @@ -229,21 +203,21 @@ def test_soiling_srr_max_negative_slope_error(normalized_daily, insolation): 'Soiling ratio different from expected when max_relative_slope_error=50.0' -def test_soiling_srr_with_nan_interval(normalized_daily, insolation, times): +def test_soiling_srr_with_nan_interval(soiling_normalized_daily, soiling_insolation): ''' Previous versions had a bug which would have raised an error when an entire interval was NaN. See https://github.com/NREL/rdtools/issues/129 ''' reps = 10 - normalized_corrupt = normalized_daily.copy() + normalized_corrupt = soiling_normalized_daily.copy() normalized_corrupt[26:50] = np.nan np.random.seed(1977) - sr, sr_ci, soiling_info = soiling_srr(normalized_corrupt, insolation, reps=reps) + sr, sr_ci, soiling_info = soiling_srr(normalized_corrupt, soiling_insolation, reps=reps) assert 0.947416 == pytest.approx(sr, abs=1e-6),\ 'Soiling ratio different from expected value when an entire interval was NaN' -def test_soiling_srr_kwargs(monkeypatch, normalized_daily, insolation): +def test_soiling_srr_kwargs(monkeypatch, soiling_normalized_daily, soiling_insolation): ''' Make sure that all soiling_srr parameters get passed on to SRRAnalysis and SRRAnalysis.run(), i.e. all necessary inputs to SRRAnalysis are provided by @@ -253,7 +227,7 @@ def test_soiling_srr_kwargs(monkeypatch, normalized_daily, insolation): # the __defaults__ attr is the tuple of default values in py3 monkeypatch.delattr(SRRAnalysis.__init__, "__defaults__") monkeypatch.delattr(SRRAnalysis.run, "__defaults__") - _ = soiling_srr(normalized_daily, insolation, reps=10) + _ = soiling_srr(soiling_normalized_daily, soiling_insolation, reps=10) # ########################### @@ -277,11 +251,12 @@ def multi_year_profiles(): def test_annual_soiling_ratios(multi_year_profiles): expected_data = np.array([[2018, 4.5, 1.431, 7.569], - [2019, 14.5, 11.431, 17.569]]) + [2019, 14.5, 11.431, 17.569]]) expected = pd.DataFrame(data=expected_data, - columns=['year', 'soiling_ratio_median', 'soiling_ratio_low', 'soiling_ratio_high']) + columns=['year', 'soiling_ratio_median', 'soiling_ratio_low', + 'soiling_ratio_high']) expected['year'] = expected['year'].astype(int) - + srr_profiles, insolation = multi_year_profiles result = annual_soiling_ratios(srr_profiles, insolation) @@ -290,9 +265,10 @@ def test_annual_soiling_ratios(multi_year_profiles): def test_annual_soiling_ratios_confidence_interval(multi_year_profiles): expected_data = np.array([[2018, 4.5, 0.225, 8.775], - [2019, 14.5, 10.225, 18.775]]) + [2019, 14.5, 10.225, 18.775]]) expected = pd.DataFrame(data=expected_data, - columns=['year', 'soiling_ratio_median', 'soiling_ratio_low', 'soiling_ratio_high']) + columns=['year', 'soiling_ratio_median', 'soiling_ratio_low', + 'soiling_ratio_high']) expected['year'] = expected['year'].astype(int) srr_profiles, insolation = multi_year_profiles @@ -308,7 +284,7 @@ def test_annual_soiling_ratios_warning(multi_year_profiles): 'within the index of insolation_daily. Every day in stochastic_soiling_profiles ' 'should be represented in insolation_daily. This may cause erroneous results.') with pytest.warns(UserWarning, match=match): - result = annual_soiling_ratios(srr_profiles, insolation) + _ = annual_soiling_ratios(srr_profiles, insolation) # ########################### @@ -350,7 +326,8 @@ def _build_monthly_summary(top_rows): all_rows = np.vstack((top_rows, [[1, np.nan, np.nan, np.nan, 0]]*8)) df = pd.DataFrame(data=all_rows, - columns=['month', 'soiling_rate_median', 'soiling_rate_low', 'soiling_rate_high', 'interval_count']) + columns=['month', 'soiling_rate_median', 'soiling_rate_low', + 'soiling_rate_high', 'interval_count']) df['month'] = range(1, 13) return df @@ -360,10 +337,11 @@ def test_monthly_soiling_rates(soiling_interval_summary): np.random.seed(1977) result = monthly_soiling_rates(soiling_interval_summary) - expected = np.array([[1.00000000e+00, -2.42103810e-03, -5.00912766e-03, -7.68551806e-04, 2.00000000e+00], - [2.00000000e+00, -1.25092837e-03, -2.10091842e-03, -3.97354321e-04, 1.00000000e+00], - [3.00000000e+00, -2.00313359e-03, -2.68359541e-03, -1.31927678e-03, 1.00000000e+00], - [4.00000000e+00, -1.99729563e-03, -2.68067699e-03, -1.31667446e-03, 1.00000000e+00]]) + expected = np.array([ + [1.00000000e+00, -2.42103810e-03, -5.00912766e-03, -7.68551806e-04, 2.00000000e+00], + [2.00000000e+00, -1.25092837e-03, -2.10091842e-03, -3.97354321e-04, 1.00000000e+00], + [3.00000000e+00, -2.00313359e-03, -2.68359541e-03, -1.31927678e-03, 1.00000000e+00], + [4.00000000e+00, -1.99729563e-03, -2.68067699e-03, -1.31667446e-03, 1.00000000e+00]]) expected = _build_monthly_summary(expected) pd.testing.assert_frame_equal(result, expected, check_dtype=False) @@ -373,10 +351,11 @@ def test_monthly_soiling_rates_min_interval_length(soiling_interval_summary): np.random.seed(1977) result = monthly_soiling_rates(soiling_interval_summary, min_interval_length=20) - expected = np.array([[1.00000000e+00, -1.24851539e-03, -2.10394564e-03, -3.98358211e-04, 1.00000000e+00], - [2.00000000e+00, -1.25092837e-03, -2.10091842e-03, -3.97330424e-04, 1.00000000e+00], - [3.00000000e+00, -2.00309454e-03, -2.68359541e-03, -1.31927678e-03, 1.00000000e+00], - [4.00000000e+00, -1.99729563e-03, -2.68067699e-03, -1.31667446e-03, 1.00000000e+00]]) + expected = np.array([ + [1.00000000e+00, -1.24851539e-03, -2.10394564e-03, -3.98358211e-04, 1.00000000e+00], + [2.00000000e+00, -1.25092837e-03, -2.10091842e-03, -3.97330424e-04, 1.00000000e+00], + [3.00000000e+00, -2.00309454e-03, -2.68359541e-03, -1.31927678e-03, 1.00000000e+00], + [4.00000000e+00, -1.99729563e-03, -2.68067699e-03, -1.31667446e-03, 1.00000000e+00]]) expected = _build_monthly_summary(expected) pd.testing.assert_frame_equal(result, expected, check_dtype=False) @@ -386,10 +365,11 @@ def test_monthly_soiling_rates_max_slope_err(soiling_interval_summary): np.random.seed(1977) result = monthly_soiling_rates(soiling_interval_summary, max_relative_slope_error=120) - expected = np.array([[1.00000000e+00, -4.74910923e-03, -5.26236739e-03, -4.23901493e-03, 1.00000000e+00], - [2.00000000e+00, np.nan, np.nan, np.nan, 0.00000000e+00], - [3.00000000e+00, -2.00074270e-03, -2.68073474e-03, -1.31786434e-03, 1.00000000e+00], - [4.00000000e+00, -2.00309454e-03, -2.68359541e-03, -1.31927678e-03, 1.00000000e+00]]) + expected = np.array([ + [1.00000000e+00, -4.74910923e-03, -5.26236739e-03, -4.23901493e-03, 1.00000000e+00], + [2.00000000e+00, np.nan, np.nan, np.nan, 0.00000000e+00], + [3.00000000e+00, -2.00074270e-03, -2.68073474e-03, -1.31786434e-03, 1.00000000e+00], + [4.00000000e+00, -2.00309454e-03, -2.68359541e-03, -1.31927678e-03, 1.00000000e+00]]) expected = _build_monthly_summary(expected) pd.testing.assert_frame_equal(result, expected, check_dtype=False) @@ -399,10 +379,11 @@ def test_monthly_soiling_rates_confidence_level(soiling_interval_summary): np.random.seed(1977) result = monthly_soiling_rates(soiling_interval_summary, confidence_level=95) - expected = np.array([[1.00000000e+00, -2.42103810e-03, -5.42313113e-03, -1.21156562e-04, 2.00000000e+00], - [2.00000000e+00, -1.25092837e-03, -2.43731574e-03, -6.23842627e-05, 1.00000000e+00], - [3.00000000e+00, -2.00313359e-03, -2.94998476e-03, -1.04988760e-03, 1.00000000e+00], - [4.00000000e+00, -1.99729563e-03, -2.95063841e-03, -1.04869949e-03, 1.00000000e+00]]) + expected = np.array([ + [1.00000000e+00, -2.42103810e-03, -5.42313113e-03, -1.21156562e-04, 2.00000000e+00], + [2.00000000e+00, -1.25092837e-03, -2.43731574e-03, -6.23842627e-05, 1.00000000e+00], + [3.00000000e+00, -2.00313359e-03, -2.94998476e-03, -1.04988760e-03, 1.00000000e+00], + [4.00000000e+00, -1.99729563e-03, -2.95063841e-03, -1.04869949e-03, 1.00000000e+00]]) expected = _build_monthly_summary(expected) @@ -413,10 +394,11 @@ def test_monthly_soiling_rates_reps(soiling_interval_summary): np.random.seed(1977) result = monthly_soiling_rates(soiling_interval_summary, reps=3) - expected = np.array([[1.00000000e+00, -2.88594088e-03, -5.03736679e-03, -6.47391131e-04, 2.00000000e+00], - [2.00000000e+00, -1.67359565e-03, -2.00504171e-03, -1.33240044e-03, 1.00000000e+00], - [3.00000000e+00, -1.22306993e-03, -2.19274892e-03, -1.11793240e-03, 1.00000000e+00], - [4.00000000e+00, -1.94675549e-03, -2.42574164e-03, -1.54850795e-03, 1.00000000e+00]]) + expected = np.array([ + [1.00000000e+00, -2.88594088e-03, -5.03736679e-03, -6.47391131e-04, 2.00000000e+00], + [2.00000000e+00, -1.67359565e-03, -2.00504171e-03, -1.33240044e-03, 1.00000000e+00], + [3.00000000e+00, -1.22306993e-03, -2.19274892e-03, -1.11793240e-03, 1.00000000e+00], + [4.00000000e+00, -1.94675549e-03, -2.42574164e-03, -1.54850795e-03, 1.00000000e+00]]) expected = _build_monthly_summary(expected) diff --git a/setup.py b/setup.py index 08ff5b25..943be5c2 100644 --- a/setup.py +++ b/setup.py @@ -55,11 +55,11 @@ 'pvlib==0.7.1', 'sphinx_rtd_theme==0.4.3', 'ipython' - ], 'test': [ 'pytest', 'coverage', + 'flake8', ] } EXTRAS_REQUIRE['all'] = sorted(set(sum(EXTRAS_REQUIRE.values(), []))) From 425a89492b7903596cb8ea7263a79379c5c10eae Mon Sep 17 00:00:00 2001 From: Kevin Anderson <57452607+kanderso-nrel@users.noreply.github.com> Date: Tue, 29 Dec 2020 16:21:44 -0700 Subject: [PATCH 06/14] Display example notebooks in a gallery on RTD (#240) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * first cut * add a comment * add missing comma * move comments to fix broken link * Model chains (#117) * Add normalized_filter() function to replace the mannual filter in example * Initial working system analysis class * system analysis version that reproduces notebook results Works for both sensor and clearsky workflows * Improve underlying analysis These improvements slightly change the clearsky results relative to the existing version of the notebook. * Allow poa, temperature, and temperature_coefficient to be None This leaves room for BYO modeled PV perofmrance in the future * Add system_analysis to rdtools namespace * Basic example of system_analysis() use * Update degradation_and_soiling_example.ipynb 1) Use apparent zenith in irradiance calculations instead of zenith 2) Apply clearsky filter based on poa irradiance rather than insolation 3) Include ground diffuse in irradiance transposition calculations * Update system_analysis_example notebook Update notes and change initial poa calculation to include ground diffuse * Add a plotting module * Update notebook to use plotting module * Add plotting methods * update system_analysis example notebook * add docstrings * Delete model chain dev notes * add matplotlib to setup.py and update requirements * change matplotlib version * Move docstring to class * renormalization bug fix * Update temperature input interface (Also fix merge bug in plotting) * update docstring for new temperature interface * Remove __init__ docstring * update class name to CamelCase * update kwarg explanatations in docstrings * remove model parameter from calc_clearsky_poa() It is still addressable through kwargs passed to pvlib * Update SystemAnalysis_example.ipynb * Reformat dosctrings to numpy style * command style docstrings * Remove duplicate line * Update plotting docstrings to numpy style * Format normalized_filter docstring according to numpy style Other docstrings in this module have been updated in #125 * Add an ad hoc filter example to the notebook * Fixes system_analysis bug #132 when pv_nameplate is passed into syste… (#133) * Fixes system_analysis bug #132 when pv_nameplate is passed into system_analysis object. * typo fix Co-Authored-By: Kevin Anderson <57452607+kanderso-nrel@users.noreply.github.com> * add bins parameter to plotting.degradation_summary_plot from #132 (cherry picked from commit efcbe2e89b64d1309ab0f3c5f21910d24c04e88d) * plotting bug fix * Drop py2.7 and add 3.7 and 3.8 to testing (#135) * Drop 2.7 and add 3.7 and 3.8 to testing, update docs. * creating DatetimeIndex directly is deprecated, switch to pd.date_range * require pandas < 1.0.0 * bump requirements.txt numpy to 1.17.3 for testing on py3.8 * more requirements.txt updates for py3.8 wheel availability * Update v2.0.0.rst * add matplotlib to requirements * matplotlib 3.1 * matplotlib * merge pytests and jupyter example * PVLib > 0.7 changes to cell_temp calculation * Modelchain pytests (#196) * pytests for system_analysis. coverage: 91%. * rename system_analysis.py to analysis.py. Rename class to RdAnalysis. Update pvwatts_kws to match Master updates * Allow temp_model_params to either be string or dict with 'a','b', 'deltaT' keys * update calc_cell_temperature for pvlib > 0.6.3, use energy_normalized in normalize_with_pvwatts * Warn if temp coefficient not passed into normalize_with_Pvwatts instead of exit with error. * Add tables=3.6.1 to requirements.txt to allow clearsky analysis * add tables to setup.py since it appears to be a required pvlib for the clearsky workflow and not installed by default. * Add RdAnalysis notebook for pvdaq4 system * add max_timedelta=15T and clearsky poa calculation update to pvdaq4 standard notebook example * Sphinx release notes for 2.1.0 updated and API update Co-authored-by: Michael Deceglie Co-authored-by: Kevin Anderson <57452607+kanderso-nrel@users.noreply.github.com> * Update tests, include tables in setup.py * suppress import warnings for soiling module. * Change warning suppression from warnings.resetwarnings to with warnings.catch_warnings(). Re-run notebooks * Model chains exp energy (#232) * enable normalize_with_expected_energy. * Update RdAnalysis_example.ipynb with manually defined power_expected option. * Add post-filter error check for < 2 yrs data per kanderson * Remove error message for no thermal model if power_expected is passed in. * remove tcell_filter from filter list if power_expected is passed in but not cell_temperature * pep8 compliance * more robust frequency check * shorten long lines * Model chains set clearsky (#233) * Move CS inputs to new set_clearsky function: pvlib_location ,pv_tilt, pv_azimuth, clearsky_poa, clearsky temp, albedo * Explicit error message if set_clearsky not run prior to clearsky_analysis. * remove Py2.7 check in block 3 of RdAnalysis_example.ipynb * boost analysis.py test coverage to 94% * add pv_energy pytest case. Change to ValueError rather than basic Exception when set_clearsky hasn't been run. Co-authored-by: Kevin Anderson <57452607+kanderso-nrel@users.noreply.github.com> * improve index equality conditional * pep8 cleanup * change dict key syntax * Clarify behavior when pv_nameplate is omitted * Useful errors for plotting methods * update requreiments for tables * reduce minimum version of tables * Delete RdAnalysis_example.ipynb * Remove max_timedelta parameter use in PVDAQ example * Move sun position calculation to clearsky section of example This brings the clearsky results into better allignement with the objected oriented example, now sun position is calculated after interpolation on both * Update chage log version number * Allow warning for experimental modules * pep8 analysis_test.py * Change module and class names * Update example with new module/class name * Fix outdated ref to system_analysis * Update api.rst with analysis chains module name * Fix changelog underline length * update index.rst with TrendAnalysis info * poa -> poa_global * cell_temperature -> temperature_cell * ambient_temperature->temperature_ambient * temperature_coefficient->gamma_pdc * temperature_model docstring * pv_nameplate->power_dc_rated * clearsky_poa->poa_global_clearsky * clearsky_temperature_cell->temperature_cell_clearsky * clearsky_temperature_ambient->temperature_ambient_clearsky * Align yoy and srr parameters with functional API * Use `case` in plotting methods * Change notebook kernel * weakly privatize some methods * Update rdtools/analysis_chains.py Co-authored-by: Kevin Anderson <57452607+kanderso-nrel@users.noreply.github.com> * Interpolate windspeed * Update rdtools/analysis_chains.py Co-authored-by: Kevin Anderson <57452607+kanderso-nrel@users.noreply.github.com> * implement review suggestions * more TrendAnalysis tests to improve coverage * cleanup * Fix copy/paste error in notebook * change _calc_cell_temeprature parameter order * More elegant error if filtering results in empty series * Changelog consolidation * change log update Co-authored-by: cdeline Co-authored-by: Kevin Anderson <57452607+kanderso-nrel@users.noreply.github.com> Co-authored-by: Kevin Anderson * add new TrendAnalysis notebook to gallery * changelog * add beta version to change log * add missing parenthesis * revert all the development stuff * move changelog entry to 2.0.5.rst; delete pending.rst * lint Co-authored-by: Michael Deceglie Co-authored-by: cdeline --- ...radation_and_soiling_example_pvdaq_4.ipynb | 2 +- docs/sphinx/source/changelog/v2.0.5.rst | 5 ++-- docs/sphinx/source/conf.py | 26 +++++++++---------- docs/sphinx/source/examples.rst | 26 +++++++++++++++++++ ...adation_and_soiling_example_pvdaq_4.nblink | 3 +++ .../system_availability_example.nblink | 3 +++ docs/sphinx/source/index.rst | 13 ++++------ docs/sphinx/source/rd_example.nblink | 3 --- .../source/system_availability_example.nblink | 3 --- docs/system_availability_example.ipynb | 6 ++++- setup.py | 7 +++-- 11 files changed, 63 insertions(+), 34 deletions(-) create mode 100644 docs/sphinx/source/examples.rst create mode 100644 docs/sphinx/source/examples/degradation_and_soiling_example_pvdaq_4.nblink create mode 100644 docs/sphinx/source/examples/system_availability_example.nblink delete mode 100644 docs/sphinx/source/rd_example.nblink delete mode 100644 docs/sphinx/source/system_availability_example.nblink diff --git a/docs/degradation_and_soiling_example_pvdaq_4.ipynb b/docs/degradation_and_soiling_example_pvdaq_4.ipynb index 0e8bdafd..61d36e4c 100644 --- a/docs/degradation_and_soiling_example_pvdaq_4.ipynb +++ b/docs/degradation_and_soiling_example_pvdaq_4.ipynb @@ -303,7 +303,7 @@ { "cell_type": "code", "execution_count": 8, - "metadata": {}, + "metadata": {"tags": ["nbsphinx-thumbnail"]}, "outputs": [ { "data": { diff --git a/docs/sphinx/source/changelog/v2.0.5.rst b/docs/sphinx/source/changelog/v2.0.5.rst index 640fd14f..e43a13ed 100644 --- a/docs/sphinx/source/changelog/v2.0.5.rst +++ b/docs/sphinx/source/changelog/v2.0.5.rst @@ -1,5 +1,5 @@ ************************** -v2.0.5 (December 28, 2020) +v2.0.5 (December 29, 2020) ************************** @@ -27,6 +27,7 @@ Testing Documentation ------------- +* Organized example notebooks into a sphinx gallery (:pull:`240`) Requirements ------------ @@ -40,4 +41,4 @@ Example Updates Contributors ------------ -* Kevin Anderson (:ghuser:`kanderso-nrel`) \ No newline at end of file +* Kevin Anderson (:ghuser:`kanderso-nrel`) diff --git a/docs/sphinx/source/conf.py b/docs/sphinx/source/conf.py index 6249f447..2e71f2c8 100644 --- a/docs/sphinx/source/conf.py +++ b/docs/sphinx/source/conf.py @@ -42,6 +42,7 @@ 'sphinx.ext.autosummary', 'nbsphinx', 'nbsphinx_link', + 'sphinx_gallery.load_style', ] autosummary_generate = True @@ -150,24 +151,20 @@ def make_github_url(pagename): # RTD automatically sets READTHEDOCS_VERSION to the version being built. rtd_version = os.environ.get('READTHEDOCS_VERSION', None) + if rtd_version is None: + # for other builds (PRs, local builds etc), it's unclear where to link + return None + version_map = { 'stable': 'master', 'latest': 'development', } - try: - branch = version_map[rtd_version] - except KeyError: - # for other builds (PRs, local builds etc), it's unclear where to link - return None + # for versions other than stable and latest, just use the version number. + # either a branch name or a git tag will work for the URL + branch = version_map.get(rtd_version, rtd_version) URL_BASE = "https://github.com/nrel/rdtools/blob/{}/".format(branch) - # map notebook pagenames to source files on github - notebook_map = { - 'rd_example': 'degradation_and_soiling_example_pvdaq_4.ipynb', - 'system_availability_example': 'system_availability_example.ipynb', - } - # is it an API autogen page? if pagename.startswith("generated/"): # pagename looks like "generated/rdtools.degradation.degradation_ols" @@ -181,8 +178,9 @@ def make_github_url(pagename): target_url += '#L{}-L{}'.format(start, end) # is it an example notebook? - elif pagename in notebook_map: - target_url = URL_BASE + "docs/" + notebook_map[pagename] + elif pagename.startswith('examples/'): + notebook_name = pagename.split("/")[-1] + target_url = URL_BASE + "docs/" + notebook_name + ".ipynb" # is the the changelog page? elif pagename == "changelog": @@ -192,7 +190,7 @@ def make_github_url(pagename): else: target_url = URL_BASE + "docs/sphinx/source/" + pagename + ".rst" - display_text = "View on github/" + branch + display_text = "View on github@" + branch link_info = { 'url': target_url, 'text': display_text diff --git a/docs/sphinx/source/examples.rst b/docs/sphinx/source/examples.rst new file mode 100644 index 00000000..6b6de544 --- /dev/null +++ b/docs/sphinx/source/examples.rst @@ -0,0 +1,26 @@ +.. _examples: + +Examples +======== + +This page shows example usage of the RdTools analysis functions. + + +.. Note that the entries in the list below are nblink filenames, not notebook filenames! + +.. There is a limitation in sphinx that I don't understand, but it means that + you cannot directly access files outside the source directory unless you use + something like nbsphinx_link, which is what we do here. + To add a notebook to the gallery, create a .nblink file and add it to the list below. + Note: the make_github_url() function in conf.py assumes that the name of the .nblink file + is the same as the notebook it points to! + +.. To select a thumbnail image, you need to edit the metadata of the cell with the + desired image to include a special tags value: + "metadata": {"tags": ["nbsphinx-thumbnail"]}, + + +.. nbgallery:: + + examples/degradation_and_soiling_example_pvdaq_4 + examples/system_availability_example diff --git a/docs/sphinx/source/examples/degradation_and_soiling_example_pvdaq_4.nblink b/docs/sphinx/source/examples/degradation_and_soiling_example_pvdaq_4.nblink new file mode 100644 index 00000000..b909a7ca --- /dev/null +++ b/docs/sphinx/source/examples/degradation_and_soiling_example_pvdaq_4.nblink @@ -0,0 +1,3 @@ +{ + "path": "../../../degradation_and_soiling_example_pvdaq_4.ipynb" +} \ No newline at end of file diff --git a/docs/sphinx/source/examples/system_availability_example.nblink b/docs/sphinx/source/examples/system_availability_example.nblink new file mode 100644 index 00000000..2bdf702e --- /dev/null +++ b/docs/sphinx/source/examples/system_availability_example.nblink @@ -0,0 +1,3 @@ +{ + "path": "../../../system_availability_example.ipynb" +} \ No newline at end of file diff --git a/docs/sphinx/source/index.rst b/docs/sphinx/source/index.rst index af40e60b..964aa378 100644 --- a/docs/sphinx/source/index.rst +++ b/docs/sphinx/source/index.rst @@ -22,8 +22,7 @@ analyze systems for system- and subsystem-level availability. RdTools can handle both high frequency (hourly or better) or low frequency (daily, weekly, etc.) datasets. Best results are obtained with higher frequency data. -Full examples are worked out in the example notebooks in the -`example notebook`_. +Full examples are worked out in the example notebooks in the :ref:`examples`. To report issues, contribute code, or suggest improvements to this documentation, visit the RdTools development repository on `github`_. @@ -43,7 +42,7 @@ supported. A typical analysis of soiling and degradation contains the following: soiling loss Steps 1 and 2 may be accomplished with the clearsky workflow (see the -`example notebook`_) which can help eliminate problems from irradiance sensor +:ref:`examples`) which can help eliminate problems from irradiance sensor drift. .. image:: _images/RdTools_workflows.png @@ -58,7 +57,7 @@ The YOY calculation yields in a distribution of degradation rates, the central tendency of which is the most representative of the true degradation. The width of the distribution provides information about the uncertainty in the estimate via a bootstrap calculation. The -`example notebook`_ uses the output of +:ref:`examples` uses the output of :py:func:`.degradation.degradation_year_on_year` to visualize the calculation. .. image:: _images/Clearsky_result_updated.png @@ -144,7 +143,7 @@ RdTools currently is tested on Python 3.6+. Usage and examples ------------------ -Full workflow examples are found in the notebooks in `example notebook`_. +Full workflow examples are found in the notebooks in :ref:`examples`. The examples are designed to work with python 3.7. For a consistent experience, we recommend installing the packages and versions documented in ``docs/notebook_requirements.txt``. This can be achieved in your @@ -284,8 +283,7 @@ Documentation Contents .. toctree:: :maxdepth: 2 - Degradation and Soiling - Inverter Downtime + Examples API Reference Change Log Developer Notes @@ -300,6 +298,5 @@ Indices and tables .. links and references -.. _example notebook: rd_example.nblink .. _release: https://github.com/NREL/rdtools/releases .. _github: https://github.com/NREL/rdtools diff --git a/docs/sphinx/source/rd_example.nblink b/docs/sphinx/source/rd_example.nblink deleted file mode 100644 index 45348257..00000000 --- a/docs/sphinx/source/rd_example.nblink +++ /dev/null @@ -1,3 +0,0 @@ -{ - "path": "../../degradation_and_soiling_example_pvdaq_4.ipynb" -} \ No newline at end of file diff --git a/docs/sphinx/source/system_availability_example.nblink b/docs/sphinx/source/system_availability_example.nblink deleted file mode 100644 index dba44bc5..00000000 --- a/docs/sphinx/source/system_availability_example.nblink +++ /dev/null @@ -1,3 +0,0 @@ -{ - "path": "../../system_availability_example.ipynb" -} \ No newline at end of file diff --git a/docs/system_availability_example.ipynb b/docs/system_availability_example.ipynb index 428e5653..eb6d8170 100644 --- a/docs/system_availability_example.ipynb +++ b/docs/system_availability_example.ipynb @@ -221,7 +221,11 @@ { "cell_type": "code", "execution_count": 5, - "metadata": {}, + "metadata": { + "tags": [ + "nbsphinx-thumbnail" + ] + }, "outputs": [ { "name": "stderr", diff --git a/setup.py b/setup.py index 943be5c2..645e5dd8 100644 --- a/setup.py +++ b/setup.py @@ -49,12 +49,15 @@ EXTRAS_REQUIRE = { 'doc': [ 'sphinx==1.8.5', - 'nbsphinx==0.5.0', + 'nbsphinx==0.6.0', 'nbsphinx-link==1.3.0', 'pandas==0.23.0', 'pvlib==0.7.1', 'sphinx_rtd_theme==0.4.3', - 'ipython' + 'ipython', + # sphinx-gallery used indirectly for nbsphinx thumbnail galleries; see: + # https://nbsphinx.readthedocs.io/en/0.6.0/subdir/gallery.html#Creating-Thumbnail-Galleries + 'sphinx-gallery==0.8.1', ], 'test': [ 'pytest', From 7a3aee5bef21e1c66f90185b642ecbd5d48c6357 Mon Sep 17 00:00:00 2001 From: Kevin Anderson <57452607+kanderso-nrel@users.noreply.github.com> Date: Wed, 30 Dec 2020 09:38:20 -0700 Subject: [PATCH 07/14] fix typos (#253) --- docs/sphinx/source/developer_notes.rst | 10 +++++----- docs/sphinx/source/index.rst | 2 +- docs/system_availability_example.ipynb | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/sphinx/source/developer_notes.rst b/docs/sphinx/source/developer_notes.rst index eca0c346..8aea9a50 100644 --- a/docs/sphinx/source/developer_notes.rst +++ b/docs/sphinx/source/developer_notes.rst @@ -79,21 +79,21 @@ Optional dependencies can be installed with the special :: pip install rdtools[test] # test suite dependencies - pip install rdtools[doc] # documentation dependecies + pip install rdtools[doc] # documentation dependencies Or, if your local repository has an updated dependencies list: :: pip install .[test] # test suite dependencies - pip install .[doc] # documentation dependecies + pip install .[doc] # documentation dependencies Running the test suite ---------------------- RdTools uses `pytest `_ to run its test -suite. If you haven't already, install the testing depencencies +suite. If you haven't already, install the testing dependencies (:ref:`installing-optional-dependencies`). To run the entire test suite, navigate to the git repo folder and run @@ -155,7 +155,7 @@ Building documentation locally ------------------------------ RdTools uses `Sphinx `_ to build its documentation. -If you haven't already, install the documentation depencencies +If you haven't already, install the documentation dependencies (:ref:`installing-optional-dependencies`). Once the required packages are installed, change your console's working @@ -213,7 +213,7 @@ Community participation is welcome! New contributions should be based on the RdTools follows the `PEP 8 `_ style guide. We recommend setting up your text editor to automatically highlight style -violations because it's easy to miss some isses (trailing whitespace, etc) otherwise. +violations because it's easy to miss some issues (trailing whitespace, etc) otherwise. Additionally, our documentation is built in part from docstrings in the source code. These docstrings must be in `NumpyDoc format `_ diff --git a/docs/sphinx/source/index.rst b/docs/sphinx/source/index.rst index 964aa378..6420ee70 100644 --- a/docs/sphinx/source/index.rst +++ b/docs/sphinx/source/index.rst @@ -57,7 +57,7 @@ The YOY calculation yields in a distribution of degradation rates, the central tendency of which is the most representative of the true degradation. The width of the distribution provides information about the uncertainty in the estimate via a bootstrap calculation. The -:ref:`examples` uses the output of +:ref:`examples` use the output of :py:func:`.degradation.degradation_year_on_year` to visualize the calculation. .. image:: _images/Clearsky_result_updated.png diff --git a/docs/system_availability_example.ipynb b/docs/system_availability_example.ipynb index eb6d8170..6d608bf2 100644 --- a/docs/system_availability_example.ipynb +++ b/docs/system_availability_example.ipynb @@ -62,7 +62,7 @@ " An \"expected\" power signal for this hypothetical PV system, simulating a\n", " modeled power from satellite weather data or some other method.\n", " \n", - " (This function creates instananeous data. SystemAvailability is technically designed\n", + " (This function creates instantaneous data. SystemAvailability is technically designed\n", " to work with right-labeled averages. However, for the purposes of the example, the\n", " approximation is suitable.)\n", " \"\"\"\n", From a451f76b899be2d352a8f8f9df3f120b337a158d Mon Sep 17 00:00:00 2001 From: Michael Deceglie Date: Wed, 30 Dec 2020 12:21:54 -0700 Subject: [PATCH 08/14] Update docs --- docs/sphinx/source/changelog/v2.0.5.rst | 22 +++------------------- docs/sphinx/source/index.rst | 2 +- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/docs/sphinx/source/changelog/v2.0.5.rst b/docs/sphinx/source/changelog/v2.0.5.rst index e43a13ed..75117507 100644 --- a/docs/sphinx/source/changelog/v2.0.5.rst +++ b/docs/sphinx/source/changelog/v2.0.5.rst @@ -2,20 +2,6 @@ v2.0.5 (December 29, 2020) ************************** - - -API Changes ------------ - -Deprecations ------------- - -Enhancements ------------- - -Bug fixes ---------- - Testing ------- * Add a flake8 code style check to the continuous integration checks (:pull:`231`) @@ -24,21 +10,19 @@ Testing * Add Python 3.9 to CI testing (:pull:`249`) * Fix test suite error raised when using pandas 1.2.0 (:pull:`251`) - Documentation ------------- * Organized example notebooks into a sphinx gallery (:pull:`240`) Requirements ------------ +* Add support for python 3.9 (:pull:`249`) * Update ``requirements.txt`` versions for numpy, scipy, pandas, h5py and statsmodels to versions that have wheels available for python 3.6-3.9. Note that the minimum versions are unchanged. (:pull:`249`). -Example Updates ---------------- - - Contributors ------------ * Kevin Anderson (:ghuser:`kanderso-nrel`) +* Michael Deceglie (:ghuser:`mdeceglie`) +* Chris Deline (:ghuser:`cdeline`) diff --git a/docs/sphinx/source/index.rst b/docs/sphinx/source/index.rst index 6420ee70..ef8f4d10 100644 --- a/docs/sphinx/source/index.rst +++ b/docs/sphinx/source/index.rst @@ -22,7 +22,7 @@ analyze systems for system- and subsystem-level availability. RdTools can handle both high frequency (hourly or better) or low frequency (daily, weekly, etc.) datasets. Best results are obtained with higher frequency data. -Full examples are worked out in the example notebooks in the :ref:`examples`. +Full examples are worked out in the notebooks shown in :ref:`examples`. To report issues, contribute code, or suggest improvements to this documentation, visit the RdTools development repository on `github`_. From e7e635468f22279bda1720032c501b6aa0128e7c Mon Sep 17 00:00:00 2001 From: Michael Deceglie Date: Wed, 30 Dec 2020 14:57:34 -0700 Subject: [PATCH 09/14] Update release date --- docs/sphinx/source/changelog/v2.0.5.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/source/changelog/v2.0.5.rst b/docs/sphinx/source/changelog/v2.0.5.rst index 75117507..0742276a 100644 --- a/docs/sphinx/source/changelog/v2.0.5.rst +++ b/docs/sphinx/source/changelog/v2.0.5.rst @@ -1,5 +1,5 @@ ************************** -v2.0.5 (December 29, 2020) +v2.0.5 (December 30, 2020) ************************** Testing From 4909898fbfeef92b0eb44fe4ac9d29ebf3e86a46 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Wed, 30 Dec 2020 16:29:07 -0700 Subject: [PATCH 10/14] add TrendAnalysis notebook to gallery --- docs/TrendAnalysis_example_pvdaq4.ipynb | 2 +- docs/sphinx/source/TrendAnalysis_example.nblink | 3 --- docs/sphinx/source/examples.rst | 1 + .../sphinx/source/examples/TrendAnalysis_example_pvdaq4.nblink | 3 +++ 4 files changed, 5 insertions(+), 4 deletions(-) delete mode 100644 docs/sphinx/source/TrendAnalysis_example.nblink create mode 100644 docs/sphinx/source/examples/TrendAnalysis_example_pvdaq4.nblink diff --git a/docs/TrendAnalysis_example_pvdaq4.ipynb b/docs/TrendAnalysis_example_pvdaq4.ipynb index 3d917971..aff85c18 100644 --- a/docs/TrendAnalysis_example_pvdaq4.ipynb +++ b/docs/TrendAnalysis_example_pvdaq4.ipynb @@ -394,7 +394,7 @@ { "cell_type": "code", "execution_count": 17, - "metadata": {}, + "metadata": {"tags": ["nbsphinx-thumbnail"]}, "outputs": [ { "data": { diff --git a/docs/sphinx/source/TrendAnalysis_example.nblink b/docs/sphinx/source/TrendAnalysis_example.nblink deleted file mode 100644 index 2d628fd6..00000000 --- a/docs/sphinx/source/TrendAnalysis_example.nblink +++ /dev/null @@ -1,3 +0,0 @@ -{ - "path": "../../TrendAnalysis_example_pvdaq4.ipynb" -} \ No newline at end of file diff --git a/docs/sphinx/source/examples.rst b/docs/sphinx/source/examples.rst index 6b6de544..3d7b3a58 100644 --- a/docs/sphinx/source/examples.rst +++ b/docs/sphinx/source/examples.rst @@ -23,4 +23,5 @@ This page shows example usage of the RdTools analysis functions. .. nbgallery:: examples/degradation_and_soiling_example_pvdaq_4 + examples/TrendAnalysis_example_pvdaq4 examples/system_availability_example diff --git a/docs/sphinx/source/examples/TrendAnalysis_example_pvdaq4.nblink b/docs/sphinx/source/examples/TrendAnalysis_example_pvdaq4.nblink new file mode 100644 index 00000000..4e582ad3 --- /dev/null +++ b/docs/sphinx/source/examples/TrendAnalysis_example_pvdaq4.nblink @@ -0,0 +1,3 @@ +{ + "path": "../../../TrendAnalysis_example_pvdaq4.ipynb" +} \ No newline at end of file From 6815cba9e76cdcff1fa0a7b71547f3baf51b0a24 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Wed, 30 Dec 2020 16:30:39 -0700 Subject: [PATCH 11/14] good merging gone bad --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d0740017..0f076396 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,5 +12,4 @@ pytz==2019.3 scipy==1.5.4 six==1.14.0 statsmodels==0.12.1 -statsmodels==0.11.1 tables==3.6.1 From ff02a5e13dd58db168bed5754047f9a078331ba9 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Wed, 30 Dec 2020 16:47:13 -0700 Subject: [PATCH 12/14] fix analysis_chains_test.py --- rdtools/test/analysis_chains_test.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/rdtools/test/analysis_chains_test.py b/rdtools/test/analysis_chains_test.py index a4013db4..dbb9577b 100644 --- a/rdtools/test/analysis_chains_test.py +++ b/rdtools/test/analysis_chains_test.py @@ -1,6 +1,5 @@ from rdtools import TrendAnalysis, normalization -from soiling_test import normalized_daily, times -from plotting_test import assert_isinstance +from conftest import assert_isinstance import pytest import pvlib import pandas as pd @@ -236,9 +235,9 @@ def test_no_set_clearsky(clearsky_parameters): @pytest.fixture -def soiling_parameters(basic_parameters, normalized_daily, cs_input): +def soiling_parameters(basic_parameters, soiling_normalized_daily, cs_input): # parameters for soiling analysis with TrendAnalysis - power = normalized_daily.resample('1h').interpolate() + power = soiling_normalized_daily.resample('1h').interpolate() return dict( pv=power, poa_global=power * 0 + 1000, From 90932409fa35dd53bbacf3d97d47a6d65278865a Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Thu, 31 Dec 2020 11:26:37 -0700 Subject: [PATCH 13/14] pin numexpr to 2.7.1 in requirements-min.txt --- requirements-min.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements-min.txt b/requirements-min.txt index ab6c55c4..11ffd35e 100644 --- a/requirements-min.txt +++ b/requirements-min.txt @@ -5,4 +5,5 @@ pandas==0.23.0 pvlib==0.7.0 scipy==0.19.1 statsmodels==0.8.0 -tables == 3.4.2 \ No newline at end of file +tables == 3.4.2 +numexpr==2.7.1 # https://github.com/pydata/numexpr/issues/369 \ No newline at end of file From ff9c446cac9d9f4170b6e30a5b85509fb9ea3d32 Mon Sep 17 00:00:00 2001 From: Michael Deceglie Date: Fri, 29 Jan 2021 13:31:42 -0700 Subject: [PATCH 14/14] Update changelog with beta release --- docs/sphinx/source/changelog/v2.0.5.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/sphinx/source/changelog/v2.0.5.rst b/docs/sphinx/source/changelog/v2.0.5.rst index 0742276a..bb95c5a2 100644 --- a/docs/sphinx/source/changelog/v2.0.5.rst +++ b/docs/sphinx/source/changelog/v2.0.5.rst @@ -1,6 +1,6 @@ -************************** -v2.0.5 (December 30, 2020) -************************** +************************************************** +v2.0.5 (2020-12-30) and v2.1.0-beta.2 (2021-01-29) +************************************************** Testing -------