From 4665276522d217731b2f17ddc0c8ed80ca2b595c Mon Sep 17 00:00:00 2001 From: "Sara A. Miskovich" Date: Wed, 8 May 2024 12:11:01 -0700 Subject: [PATCH 01/15] clear depr and future warnings --- solardatatools/algorithms/loss_factor_analysis.py | 2 +- solardatatools/matrix_embedding.py | 4 ++-- solardatatools/time_axis_manipulation.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/solardatatools/algorithms/loss_factor_analysis.py b/solardatatools/algorithms/loss_factor_analysis.py index c0dcc22b..fe7bbba9 100644 --- a/solardatatools/algorithms/loss_factor_analysis.py +++ b/solardatatools/algorithms/loss_factor_analysis.py @@ -3,7 +3,7 @@ This module is for estimation of degradation and soiling losses from unlabeled daily energy production data. Model is of the form -y_t = x_t * d_t * s_t * c_t * w_t, for t \in K +y_t = x_t * d_t * s_t * c_t * w_t, for t in K where y_t [kWh] is the measured real daily energy on each day, x_t [kWh] is an ideal yearly baseline of performance, and d_t, s_t, and w_t are the loss factors for degradation, soiling, capacity changes, and weather respectively. K is diff --git a/solardatatools/matrix_embedding.py b/solardatatools/matrix_embedding.py index 6116f855..0dd40db1 100644 --- a/solardatatools/matrix_embedding.py +++ b/solardatatools/matrix_embedding.py @@ -38,7 +38,7 @@ def make_2d( if df is not None: days = df.resample("D").first().index try: - n_steps = int(24 * 60 * 60 / df.index.freq.delta.seconds) + n_steps = int(24 * 60 * 60 / df.index.to_series().diff().median().seconds) except AttributeError: # No frequency defined for index. Attempt to infer freq_ns = np.median(df.index[1:] - df.index[:-1]) @@ -56,7 +56,7 @@ def make_2d( # Trim leading or trailing missing days, which can occur when data frame # contains data from multiple sources or sensors that have missing # values at different times. - empty_days = np.alltrue(np.isnan(D), axis=0) + empty_days = np.all(np.isnan(D), axis=0) i, j = find_start_end(empty_days) D = D[:, i:j] day_axis = pd.date_range(start=start, end=end, freq="1D") diff --git a/solardatatools/time_axis_manipulation.py b/solardatatools/time_axis_manipulation.py index f6ce9787..56ace69d 100644 --- a/solardatatools/time_axis_manipulation.py +++ b/solardatatools/time_axis_manipulation.py @@ -143,13 +143,13 @@ def standardize_time_axis( avg_day /= np.max(avg_day) # find sunrise and sunset times idxs = np.arange(len(avg_day)) - if avg_day[0] >= thresh: + if avg_day.iloc[0] >= thresh: sr_loc = [idxs[0]] else: sr_loc = idxs[ np.r_[[False], np.diff((avg_day.values >= thresh).astype(float)) == 1] ] - if avg_day[-1] >= thresh: + if avg_day.iloc[-1] >= thresh: ss_loc = [idxs[-1]] else: ss_loc = idxs[ From d88899b3ac63ab961202991a354cc5fcbd502659 Mon Sep 17 00:00:00 2001 From: "Sara A. Miskovich" Date: Wed, 8 May 2024 12:15:53 -0700 Subject: [PATCH 02/15] plot clipped data in polar transforms module --- solardatatools/polar_transform.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/solardatatools/polar_transform.py b/solardatatools/polar_transform.py index 9dc9391c..c7f48fbf 100644 --- a/solardatatools/polar_transform.py +++ b/solardatatools/polar_transform.py @@ -109,5 +109,6 @@ def plot_transformation( if ax is None: fig = plt.figure(figsize=figsize) ax = fig.add_subplot(111) - sns.heatmap(self.transformed_data, ax=ax, cbar=cbar, cmap=cmap, alpha=alpha) + # Plot clipped (non-neg) data + sns.heatmap(np.clip(self.transformed_data, 0, np.inf), ax=ax, cbar=cbar, cmap=cmap, alpha=alpha) return plt.gcf() From 5befbb4a4aa192061886889224c27d507a7adf62 Mon Sep 17 00:00:00 2001 From: "Sara A. Miskovich" Date: Wed, 8 May 2024 12:31:20 -0700 Subject: [PATCH 03/15] add explicit solver (ECOS instead of future CLARABEL default) for tests --- pvsystemprofiler/algorithms/longitude/fitting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvsystemprofiler/algorithms/longitude/fitting.py b/pvsystemprofiler/algorithms/longitude/fitting.py index b89b1d9c..e4cfcabb 100644 --- a/pvsystemprofiler/algorithms/longitude/fitting.py +++ b/pvsystemprofiler/algorithms/longitude/fitting.py @@ -18,5 +18,5 @@ def fit_longitude(eot, solarnoon, days, gmt_offset, loss='l2'): cost = cost_func(sn_h[use_days] - solarnoon[use_days]) objective = cvx.Minimize(cost) problem = cvx.Problem(objective) - problem.solve() + problem.solve(solver=cvx.ECOS) return lon.value.item() From b32737a987828c5127f327654ca76cb6f781c5c5 Mon Sep 17 00:00:00 2001 From: "Sara A. Miskovich" Date: Wed, 8 May 2024 12:49:45 -0700 Subject: [PATCH 04/15] add future deprecation warning to statistical clear sky package --- statistical_clear_sky/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/statistical_clear_sky/__init__.py b/statistical_clear_sky/__init__.py index 9e20e9f3..7ba30ff1 100644 --- a/statistical_clear_sky/__init__.py +++ b/statistical_clear_sky/__init__.py @@ -1,2 +1,6 @@ from statistical_clear_sky.algorithm.iterative_fitting import IterativeFitting from statistical_clear_sky.algorithm.iterative_fitting import IterativeFitting as SCSF + +from warnings import warn + +warn("Starting in Solar Data Tools 1.5.0, the Statistical Clear Sky package will be deprecated.", FutureWarning) \ No newline at end of file From b502a5e4d85345474800e1a67698e60e732d4f94 Mon Sep 17 00:00:00 2001 From: Duncan Ragsdale <88173870+Thistleman@users.noreply.github.com> Date: Fri, 17 May 2024 14:02:21 -0700 Subject: [PATCH 05/15] Update test-build.yml adding clean to test for build failures and identify clobber issues --- .github/workflows/test-build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index a09d3b58..98e989c4 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -50,7 +50,9 @@ jobs: conda config --set always_yes yes --set auto_update_conda false conda update conda conda install -n base conda-libmamba-solver + conda clean --all conda install python=3.10 conda-build colorama pip ruamel ruamel.yaml rich jsonschema -c conda-forge + conda clean --all git fetch --prune --unshallow --tags pip install -e . @@ -62,6 +64,7 @@ jobs: id: condabuild run: | conda install anaconda-client + conda clean --all conda config --set anaconda_upload no --set solver libmamba VERSION_FROM_GIT_TAG=$(git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-)test conda build . -c mosek -c anaconda -c pvlib -c slacgismo -c conda-forge -c stanfordcvxgrp echo "gitversion=$(git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-)" >> $GITHUB_OUTPUT From afc3be48983fc750727d4989f3179536b98bc329 Mon Sep 17 00:00:00 2001 From: Duncan Ragsdale <88173870+Thistleman@users.noreply.github.com> Date: Fri, 17 May 2024 14:10:30 -0700 Subject: [PATCH 06/15] Update test-build.yml conda-forge and anaconda conflicts causing clobber warnings, test remove anaconda channel --- .github/workflows/test-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 98e989c4..aa43d760 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -66,5 +66,5 @@ jobs: conda install anaconda-client conda clean --all conda config --set anaconda_upload no --set solver libmamba - VERSION_FROM_GIT_TAG=$(git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-)test conda build . -c mosek -c anaconda -c pvlib -c slacgismo -c conda-forge -c stanfordcvxgrp + VERSION_FROM_GIT_TAG=$(git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-)test conda build . -c mosek -c pvlib -c slacgismo -c conda-forge -c stanfordcvxgrp echo "gitversion=$(git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-)" >> $GITHUB_OUTPUT From 4f8ce636be7d6096994adcc5934ae9644e6bfcd3 Mon Sep 17 00:00:00 2001 From: Duncan Ragsdale <88173870+Thistleman@users.noreply.github.com> Date: Fri, 17 May 2024 14:28:17 -0700 Subject: [PATCH 07/15] Update test-build.yml update actions versions --- .github/workflows/test-build.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index aa43d760..fca3ca4a 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: @@ -38,8 +38,7 @@ jobs: python-version: "3.10" # Much better than manual installation, original version Miniconda2-4.7.10-Linux-x86_64.sh is broken - - name: Install Miniconda - uses: conda-incubator/setup-miniconda@v2 + - uses: conda-incubator/setup-miniconda@v3 with: auto-activate-base: true activate-environment: "" From 40a86fce95acdb6d3a78c2c246394563facf1c66 Mon Sep 17 00:00:00 2001 From: Duncan Ragsdale <88173870+Thistleman@users.noreply.github.com> Date: Fri, 17 May 2024 14:31:30 -0700 Subject: [PATCH 08/15] Update test-build.yml simultaneous run to confirm packages --- .github/workflows/test-build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index fca3ca4a..70f8b85d 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -65,5 +65,8 @@ jobs: conda install anaconda-client conda clean --all conda config --set anaconda_upload no --set solver libmamba + echo "Listing all the conda packages. --Thistleman" + conda --list + echo "End of list. --Thistleman" VERSION_FROM_GIT_TAG=$(git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-)test conda build . -c mosek -c pvlib -c slacgismo -c conda-forge -c stanfordcvxgrp echo "gitversion=$(git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-)" >> $GITHUB_OUTPUT From fa731ed743eebd0ba11814df7e3da2676b7000f8 Mon Sep 17 00:00:00 2001 From: Duncan Ragsdale <88173870+Thistleman@users.noreply.github.com> Date: Fri, 17 May 2024 14:36:12 -0700 Subject: [PATCH 09/15] Update test-build.yml hmmmmm --- .github/workflows/test-build.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 70f8b85d..b09067ac 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -65,8 +65,6 @@ jobs: conda install anaconda-client conda clean --all conda config --set anaconda_upload no --set solver libmamba - echo "Listing all the conda packages. --Thistleman" - conda --list - echo "End of list. --Thistleman" + pip install cvxpy VERSION_FROM_GIT_TAG=$(git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-)test conda build . -c mosek -c pvlib -c slacgismo -c conda-forge -c stanfordcvxgrp echo "gitversion=$(git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-)" >> $GITHUB_OUTPUT From 8a483de4e7c29d7f3f710109b688d550c1718735 Mon Sep 17 00:00:00 2001 From: Duncan Ragsdale <88173870+Thistleman@users.noreply.github.com> Date: Fri, 17 May 2024 14:46:38 -0700 Subject: [PATCH 10/15] Update test-build.yml leggooo --- .github/workflows/test-build.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index b09067ac..39db3ba6 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -65,6 +65,8 @@ jobs: conda install anaconda-client conda clean --all conda config --set anaconda_upload no --set solver libmamba - pip install cvxpy + pip check + pip install --upgrade --force-reinstall cvxpy + pip check VERSION_FROM_GIT_TAG=$(git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-)test conda build . -c mosek -c pvlib -c slacgismo -c conda-forge -c stanfordcvxgrp echo "gitversion=$(git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-)" >> $GITHUB_OUTPUT From 48850042a2d545faac3d3caf832e1e033866510a Mon Sep 17 00:00:00 2001 From: Duncan Ragsdale <88173870+Thistleman@users.noreply.github.com> Date: Fri, 17 May 2024 17:47:32 -0700 Subject: [PATCH 11/15] Update test-build.yml removed testing changes, left actions updates and kept anaconda channel removed due to migration to condaforge --- .github/workflows/test-build.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 39db3ba6..9230e07e 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -49,9 +49,7 @@ jobs: conda config --set always_yes yes --set auto_update_conda false conda update conda conda install -n base conda-libmamba-solver - conda clean --all conda install python=3.10 conda-build colorama pip ruamel ruamel.yaml rich jsonschema -c conda-forge - conda clean --all git fetch --prune --unshallow --tags pip install -e . @@ -65,8 +63,5 @@ jobs: conda install anaconda-client conda clean --all conda config --set anaconda_upload no --set solver libmamba - pip check - pip install --upgrade --force-reinstall cvxpy - pip check VERSION_FROM_GIT_TAG=$(git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-)test conda build . -c mosek -c pvlib -c slacgismo -c conda-forge -c stanfordcvxgrp echo "gitversion=$(git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-)" >> $GITHUB_OUTPUT From 1dfdb51500495b694ab573c152fe228b4022f006 Mon Sep 17 00:00:00 2001 From: "Sara A. Miskovich" Date: Thu, 23 May 2024 20:49:10 -0700 Subject: [PATCH 12/15] Update meta.yaml to comment out pip check for now --- conda_recipe/meta.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conda_recipe/meta.yaml b/conda_recipe/meta.yaml index 06ef92b0..ac308af1 100644 --- a/conda_recipe/meta.yaml +++ b/conda_recipe/meta.yaml @@ -42,8 +42,8 @@ requirements: test: imports: - solardatatools - commands: - - pip check + # commands: + # - pip check # until cvxpy issue #2447 is resolved requires: - pip From b37d0e94933fa583e303edcb71c5e69cb2c2329d Mon Sep 17 00:00:00 2001 From: "Sara A. Miskovich" Date: Thu, 23 May 2024 21:13:17 -0700 Subject: [PATCH 13/15] adjust deprecation warning for scs and make cvx default solver in long fitting --- pvsystemprofiler/algorithms/longitude/fitting.py | 2 +- statistical_clear_sky/__init__.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pvsystemprofiler/algorithms/longitude/fitting.py b/pvsystemprofiler/algorithms/longitude/fitting.py index e4cfcabb..e51640ac 100644 --- a/pvsystemprofiler/algorithms/longitude/fitting.py +++ b/pvsystemprofiler/algorithms/longitude/fitting.py @@ -18,5 +18,5 @@ def fit_longitude(eot, solarnoon, days, gmt_offset, loss='l2'): cost = cost_func(sn_h[use_days] - solarnoon[use_days]) objective = cvx.Minimize(cost) problem = cvx.Problem(objective) - problem.solve(solver=cvx.ECOS) + problem.solve("CLARABEL") return lon.value.item() diff --git a/statistical_clear_sky/__init__.py b/statistical_clear_sky/__init__.py index 7ba30ff1..6a6f4324 100644 --- a/statistical_clear_sky/__init__.py +++ b/statistical_clear_sky/__init__.py @@ -3,4 +3,8 @@ from warnings import warn -warn("Starting in Solar Data Tools 1.5.0, the Statistical Clear Sky package will be deprecated.", FutureWarning) \ No newline at end of file +warn( + "The Statistical Clear Sky package is deprecated. Starting in Solar Data Tools 2.0, it will be removed.", + DeprecationWarning, + stacklevel=2 +) \ No newline at end of file From 4b3aa9fbb59cb06ed13b2086520c7369258d5868 Mon Sep 17 00:00:00 2001 From: "Sara A. Miskovich" Date: Thu, 23 May 2024 21:14:34 -0700 Subject: [PATCH 14/15] remove old data and ci dirs --- .oldcircle/config.yml | 103 -- .scripts/ci-utilities.sh | 142 --- .scripts/release.sh | 74 -- data/README.md | 1 - data/selected_sites.txt | 62 - dataviewer/DataViewer-MASTER.ipynb | 1746 ---------------------------- 6 files changed, 2128 deletions(-) delete mode 100644 .oldcircle/config.yml delete mode 100755 .scripts/ci-utilities.sh delete mode 100755 .scripts/release.sh delete mode 100644 data/README.md delete mode 100644 data/selected_sites.txt delete mode 100644 dataviewer/DataViewer-MASTER.ipynb diff --git a/.oldcircle/config.yml b/.oldcircle/config.yml deleted file mode 100644 index a8516a57..00000000 --- a/.oldcircle/config.yml +++ /dev/null @@ -1,103 +0,0 @@ -version: 2 - -368_config: &368_config - docker: - - image: circleci/python:3.7 - -jobs: - build: - <<: *368_config - steps: - - checkout - - run: - name: Install Dependencies - command: | - sudo pip install -r requirements.txt - sudo pip install awscli coverage - - run: - name: Setup Mosek License File - command: | - sudo mkdir /root/mosek - mkdir $HOME/mosek - aws s3 cp s3://slac.gismo.ci.artifacts/mosek.license/mosek.lic $HOME/mosek/mosek.lic - sudo cp $HOME/mosek/mosek.lic /root/mosek/mosek.lic - - - run: - name: Run Unit Tests - command: | - sudo coverage run -m unittest - - deploy-pypi: - <<: *368_config - steps: - - checkout - - run: - name: Install twine - command: sudo pip install twine - - - run: - name: Create the distribution - command: sudo python setup.py sdist bdist_wheel - - - run: - name: Push to PyPI - command: sudo twine upload -u $PYPI_USERNAME -p $PYPI_PASSWORD dist/* - - deploy-conda: - <<: *368_config - steps: - - checkout - - run: - name: Install the Conda Dependencies - command: | - wget https://repo.anaconda.com/miniconda/Miniconda3-4.7.10-Linux-x86_64.sh -O miniconda.sh - bash miniconda.sh -b -p "$HOME"/miniconda - source /home/circleci/miniconda/etc/profile.d/conda.sh - conda activate base - conda config --set always_yes yes --set auto_update_conda false - conda update conda - conda install conda-build - - - run: - name: Build the Anaconda Package - command: | - source /home/circleci/miniconda/etc/profile.d/conda.sh - conda activate base - conda install anaconda-client - conda config --set anaconda_upload no - anaconda login --username $ANACONDA_CLOUD_USERNAME --password $ANACONDA_CLOUD_PASSWORD - VERSION_FROM_GIT_TAG=`git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-` conda build . -c conda-forge --numpy 1.16.4 - - - run: - name: Get the output path and upload the package - command: | - source /home/circleci/miniconda/etc/profile.d/conda.sh - conda activate base - VERSION_FROM_GIT_TAG=`git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-` - anaconda upload -u slacgismo /home/circleci/miniconda/conda-bld/noarch/solar-data-tools-$VERSION_FROM_GIT_TAG-*.tar.bz2 - - -workflows: - version: 2 - build-and-deploy: - jobs: - - build: - filters: - tags: - only: /.*/ - - deploy-pypi: - requires: - - build - filters: - tags: - only: /^v\d+\.\d+\.\d+$/ - branches: - ignore: /.*/ - - deploy-conda: - requires: - - build - filters: - tags: - only: /^v\d+\.\d+\.\d+$/ - branches: - ignore: /.*/ diff --git a/.scripts/ci-utilities.sh b/.scripts/ci-utilities.sh deleted file mode 100755 index ddc9b85b..00000000 --- a/.scripts/ci-utilities.sh +++ /dev/null @@ -1,142 +0,0 @@ -#!/bin/bash -eu - -######################################## -# Report Stylings -######################################## -sr=$(printf "\\033[;31m") # red -sg=$(printf "\\033[;32m") # green -sy=$(printf "\\033[;33m") # yellow -sm=$(printf "\\033[;35m") # magenta -sw=$(printf "\\033[;37m") # white -sb=$(printf "\\033[1m") # bold -sn=$(printf "\\033[0;0m") # reset - -######################################## -# Helper function for error reporting -######################################## -function error_trap { - echo "${1:-"unknown error"} exit code: $?" -} - -######################################## -# Demarcations -######################################## -function start_section { - local message="${1}" - echo - echo "${sg}${sb}> ${sw}${message}${sn}" -} - -######################################## -# Makes sure things are equal or fail. -# It requires bash -e flag to cause exit on return -######################################## -function assert_equal { - local x="${1}" - local y="${2}" - if [[ ${x} == "${y}" ]] ; then - echo "Assert: ${x} == ${y}" - else - echo "Assertion failed: ${x} == ${y}" - echo "File ${0}" # Give name of file. - return 1 - fi -} - -######################################## -# Did you really mean that? Like really though? -######################################## -function assert_user_confirmation { - echo "Are you sure you want to do this?" - echo " In order to proceed type yes" - read confirmation - if [[ $confirmation == "yes" ]] ; then - echo "confirmed" - else - echo "canceling" - return 1 - fi -} - -######################################## -# Makes sure its a version -######################################## -function assert_version { - local x="${1}" - if [[ ${x} =~ ^[0-9]*\.[0-9]*\.[0-9]*$ ]] ; then - echo "Assert: ${x} == version" - else - echo "Assertion failed: ${x} == version" - echo "File ${0}" - return 1 - fi -} - -######################################## -# Make sure that the second arg is a -# descendent of the first arg or GAME OVER -######################################## -function assert_merged { - local possible_ancestor="${1}" - local target="${2}" - if git merge-base --is-ancestor "${possible_ancestor}" "${target}" ; then - echo "Assert: ${possible_ancestor} has been merged into ${target}" - else - echo "Assertion failed: ${possible_ancestor} merged to ${target}" - echo "File ${0}" - return 1 - fi -} - -######################################## -# Git sanity verification -######################################## -function assert_tree_unchanged { - start_section "Veriyfing current branch is unchanged" - if git diff-index --quiet HEAD; then - echo "No changes pending, we are good to go." - else - echo "========================================" - echo "${sr}TREE NOT PRISTINE${sn}" - echo "====================" - git status - echo "====================" - git diff-index HEAD - echo "====================" - git diff-index -p HEAD - echo "====================" - echo "This may be caused by a number of factors. If this condition occurs please get help." - echo "========================================" - return 1 - fi -} - -######################################## -# Calculate new version -######################################## -function bump_version { - local version=$(echo ${1} | cut -d 'v' -f 2) - local type=${2} - - IFS='.' read -r -a ver_pieces <<< "$version" - major="${ver_pieces[0]}" - minor="${ver_pieces[1]}" - micro="${ver_pieces[2]}" - - if [[ $type == "MAJOR" ]]; then - major=$((major+1)) - minor=0 - micro=0 - fi - - if [[ $type == "MINOR" ]]; then - minor=$((minor+1)) - micro=0 - fi - - if [[ $type == "MICRO" ]]; then - micro=$((micro+1)) - fi - - echo "${major}.${minor}.${micro}" -} diff --git a/.scripts/release.sh b/.scripts/release.sh deleted file mode 100755 index 60e7d07a..00000000 --- a/.scripts/release.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/bash -eu -set -o errtrace - -######################################## -# Cache the root dir and the latest git -# tag and commit hash -######################################## -BUILD_ROOT=$(git rev-parse --show-toplevel) -LAST_RELEASE_TAG="$(git tag --list "v*[0-9]" --sort=version:refname | tail -1 )" -LAST_RELEASE_COMMIT="$(git rev-list -n 1 "${LAST_RELEASE_TAG}")" - -# import release utilities -source "$BUILD_ROOT"/.scripts/ci-utilities.sh - -# facility for error reporting -trap 'error_trap "$0 line $LINENO"' ERR - -######################################## -# Increment the version, cut the tag and push it -######################################## -function push_release_tag { - local version - version=$LAST_RELEASE_TAG - new_version=$(bump_version $version $BUMP_TYPE) - - start_section "Tagging master with v${new_version}" - assert_user_confirmation - git tag -a "v${new_version}" -m "perform-release on v${new_version}" - git push origin "v${new_version}" -} - -######################################## -# Release a new version of the code by -# tagging the latest commit in master with -# bump in major, minor or micro version -######################################## -function main { - start_section "Validating SEMVER Cut" - if [ "$#" == 0 ]; then - echo "No version specified. Please specify the version bump with either major, minor or micro." - exit - fi - - BUMP_TYPE=$(printf '%s\n' "$1" | awk '{ print toupper($0) }') - - if [ "$BUMP_TYPE" == "MAJOR" ]; then - echo "Releasing a new MAJOR version" - elif [ "$BUMP_TYPE" == "MINOR" ]; then - echo "Releasing a new MINOR version" - elif [ "$BUMP_TYPE" == "MICRO" ]; then - echo "Releasing a new MICRO version" - else - echo "Invalid bump type. Please use either major, micro or minor" - exit - fi - - export BUMP_TYPE - - start_section "Latest information" - echo "Last Release Tag: ${LAST_RELEASE_TAG}" - echo "Last Release Commit: ${LAST_RELEASE_COMMIT}" - - start_section "Validating that you are on master" - pushd "$BUILD_ROOT" - assert_equal $(git rev-parse --abbrev-ref HEAD) master - git pull - assert_tree_unchanged - assert_merged "${LAST_RELEASE_COMMIT}" origin/master - popd - - push_release_tag -} - -main "$@" diff --git a/data/README.md b/data/README.md deleted file mode 100644 index 1b79a1e0..00000000 --- a/data/README.md +++ /dev/null @@ -1 +0,0 @@ -This is where the data should reside. Actual data files will not be tracked. Note: site locations and data are under NDA. diff --git a/data/selected_sites.txt b/data/selected_sites.txt deleted file mode 100644 index fe32d8e9..00000000 --- a/data/selected_sites.txt +++ /dev/null @@ -1,62 +0,0 @@ -TADBC1078163 -TABLC1013976 -TABE01001626 -TABF01113630 -TAEEC1003466 -TADBC1078041 -TADBC1076739 -TADCC1097422 -TABD01110568 -TADKC1042879 -TADKC1042851 -TADKC1017785 -TADKC1018267 -TABG01055993 -TADAC1023097 -TACHC1020772 -TACIC1066981 -TABA01148077 -TACHC1022171 -TABD01110011 -TACFC1070726 -TACGC1087514 -TAEAC1031314 -TACHC1020295 -TADCC1019626 -TAEAC1006600 -TABJC1001537 -TACHC1021312 -TABGC1043841 -TABF01112766 -TADHC1009872 -TABG01081601 -TADBC1078055 -TADBC1078234 -TADBC1078277 -TADBC1077912 -TABA01148025 -TADHC1036570 -TABC01142903 -TADKC1043032 -TAAJ01021775 -TACIC1038743 -TABJC1001611 -TABG01015320 -TADKC1095539 -TACLC1036521 -TADBC1076792 -TACHC1088059 -TADBC1077995 -TABA01148163 -TABJC1027266 -TABE01026346 -TAEAC1007532 -TABC01142170 -TABJC1067952 -TADKC1018154 -TABGC1044151 -TACIC1067142 -TABJC1002203 -TABF01017766 -TAAI01129193 -TACHC1087696 diff --git a/dataviewer/DataViewer-MASTER.ipynb b/dataviewer/DataViewer-MASTER.ipynb deleted file mode 100644 index 11cdd14d..00000000 --- a/dataviewer/DataViewer-MASTER.ipynb +++ /dev/null @@ -1,1746 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Instructions\n", - "\n", - "- Run all cells to initialize app (`Menu Bar > Kernel > Restart & Run All`)\n", - "- Select a system ID with data picker, text input, or key selection (see below)\n", - "- When ready, run SCSF algorithm by clicked red button (caution: this could take a few minutes to complete)\n", - "- Re-run last cell of notebook (`view_ts` function) after SCSF algorithm completes to look at close up of of 5 days in data set" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib notebook\n", - "from sys import path\n", - "path.append('..')\n", - "from clearsky.dataviewer import PointBrowser, load_results, load_sys, view_ts\n", - "df = load_results()" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "df = load_results()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Year over year degradation analysis: results data viewer\n", - "\n", - "The SCSF algorithm can be used to estimate the YOY degradation of a PV system from historical data, without the need for a physical system model. NREL also provides the [RdTools](https://www.nrel.gov/pv/rdtools.html) for estimating YOY degradation rates, which takes the classic approach, using a physical system model. Approximately 300 systems from around the US had their historical power data analysed by both tools. The applet presented here investigates these results, plotting the SCSF estimate versus the RdTools estimate for each system. When a point is selected in the top-left frame, the record for the two estimates is shown in the upper right. Each record has the following fields:\n", - "\n", - "- `rd`: the RdTools YOY degradation estimate\n", - "- `deg`: the SCSF YOY degradation estimate\n", - "- `difference`: the difference between the RdTools estimate and the SCSF estimate\n", - "- `rd_range`: RdTools also provides quantile estimates on the YOY deg value. This is the P95 minus to P5 values. A larger range indicates larger uncertainty in the RdTools estimate.\n", - "- `res-median`: the median of the residuals between the SCSF clear sky estimate and the raw data\n", - "- `res-var`: the variance of the residuals between the SCSF clear sky estimate and the raw data\n", - "- `res-L0norm`: L0 refers to the first column vector in the L matrix of the GLR model. If the model is a good fit for the data, we expect this vector to look similar to the first left singular vector of the SVD of the data matrix. This field is the norm of the residual between the L0 vector and the first left singular vector. If it is small, these two vectors are similar, and if it large, they are dissimilar.\n", - "- `rd_low`: the P5 value of the RdTools estimate\n", - "- `rd_high`: the P95 value of the RdTools estimate\n", - "- `all-pass`: SCSF algorithm passed all three internal solver checks (should be `True` for all data presented here)\n", - "- `fix-ts`: this is `True` if the SCSF initialization method detected and fixed a timestamp shift issue\n", - "- `num-days`: the number of days available in that system's data set\n", - "- `num-days-used`: the number of days selected by the SCSF algorithm\n", - "- `use-frac`: the fraction of available days used by the algorithm\n", - "\n", - "In the data selector pane, the orange points have one or more of the three SCSF residual metrics (`res-median`, `res-var`, and `res-L0norm`) in the top fifth percentile over all the data (i.e., at least one of the metrics is an outlier).\n", - "\n", - "### Data selection\n", - "\n", - "Individual systems may be selected by the following ways:\n", - "\n", - "- click a point in the upper left plot\n", - "- enter a system ID number in the text box (applet pickes nearest used ID number)\n", - "- cycle through systems in descending order (from currently selected) with `a` key\n", - "- cycle through systems in ascending order (from currently selected) with `s` key\n", - "\n", - "Once a system ID is selected, the raw time series power data is retreived from GISMo's servers and displayed in the second row. This data is cached in memory after retrieval, making repeated queries speedier.\n", - "\n", - "Some interesting system IDs to check out:\n", - "\n", - "- `31195` : a very clean, well-behaved system\n", - "- `29890` : jump in apparent capacity in first year, SCSF approach shows robustness\n", - "- `15386` : apparent \"recovery\" in year 4 (look at days `1150` through `1155` in particular)\n", - "- `21167` : time shift in data, automatically detected and corrected by SCSF\n", - "-   `5429` : tree growth on west side of PV system\n", - "- `18613` : an interesting shade pattern\n", - "- `34369` : another interesting shade pattern\n", - "-   `1533` : almost no winter power output\n", - "-   `2912` : very poor quality data\n", - "- `27133` : large inverter clipping, fit by SCSF (`clear_day_start=20`)\n", - "- `28532` : small inverter clipping, missed by SCSF (`clear_day_start=70`)\n", - "- `29757` : star patterns\n", - "\n", - "### Run SCSF Algorithm\n", - "\n", - "After a system's data is loaded, you may press the red \"run SCSF\" button to execute the SCSF algorithm. The algorithm typically completes in 2-5 minutes, but occaisionally can take upwards of 10. Updates from the algorithm will be printed in the third row. This is replaced with a heatmap view of the clear sky estimate after the algorithm completes.\n", - "\n", - "As soon as the algorithm is initialized (but before the minimization process) the daily energy and selected days are displayed in the bottom row. After the algorithm completes, this plot is updated with the estimated clear sky daily energy." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "window.mpl = {};\n", - "\n", - "\n", - "mpl.get_websocket_type = function() {\n", - " if (typeof(WebSocket) !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof(MozWebSocket) !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert('Your browser does not have WebSocket support.' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.');\n", - " };\n", - "}\n", - "\n", - "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = (this.ws.binaryType != undefined);\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById(\"mpl-warnings\");\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent = (\n", - " \"This browser does not support binary websocket messages. \" +\n", - " \"Performance may be slow.\");\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = $('
');\n", - " this._root_extra_style(this.root)\n", - " this.root.attr('style', 'display: inline-block');\n", - "\n", - " $(parent_element).append(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", - " fig.send_message(\"send_image_mode\", {});\n", - " if (mpl.ratio != 1) {\n", - " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", - " }\n", - " fig.send_message(\"refresh\", {});\n", - " }\n", - "\n", - " this.imageObj.onload = function() {\n", - " if (fig.image_mode == 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function() {\n", - " fig.ws.close();\n", - " }\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "}\n", - "\n", - "mpl.figure.prototype._init_header = function() {\n", - " var titlebar = $(\n", - " '
');\n", - " var titletext = $(\n", - " '
');\n", - " titlebar.append(titletext)\n", - " this.root.append(titlebar);\n", - " this.header = titletext[0];\n", - "}\n", - "\n", - "\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", - "\n", - "}\n", - "\n", - "\n", - "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", - "\n", - "}\n", - "\n", - "mpl.figure.prototype._init_canvas = function() {\n", - " var fig = this;\n", - "\n", - " var canvas_div = $('
');\n", - "\n", - " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", - "\n", - " function canvas_keyboard_event(event) {\n", - " return fig.key_event(event, event['data']);\n", - " }\n", - "\n", - " canvas_div.keydown('key_press', canvas_keyboard_event);\n", - " canvas_div.keyup('key_release', canvas_keyboard_event);\n", - " this.canvas_div = canvas_div\n", - " this._canvas_extra_style(canvas_div)\n", - " this.root.append(canvas_div);\n", - "\n", - " var canvas = $('');\n", - " canvas.addClass('mpl-canvas');\n", - " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", - "\n", - " this.canvas = canvas[0];\n", - " this.context = canvas[0].getContext(\"2d\");\n", - "\n", - " var backingStore = this.context.backingStorePixelRatio ||\n", - "\tthis.context.webkitBackingStorePixelRatio ||\n", - "\tthis.context.mozBackingStorePixelRatio ||\n", - "\tthis.context.msBackingStorePixelRatio ||\n", - "\tthis.context.oBackingStorePixelRatio ||\n", - "\tthis.context.backingStorePixelRatio || 1;\n", - "\n", - " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband = $('');\n", - " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", - "\n", - " var pass_mouse_events = true;\n", - "\n", - " canvas_div.resizable({\n", - " start: function(event, ui) {\n", - " pass_mouse_events = false;\n", - " },\n", - " resize: function(event, ui) {\n", - " fig.request_resize(ui.size.width, ui.size.height);\n", - " },\n", - " stop: function(event, ui) {\n", - " pass_mouse_events = true;\n", - " fig.request_resize(ui.size.width, ui.size.height);\n", - " },\n", - " });\n", - "\n", - " function mouse_event_fn(event) {\n", - " if (pass_mouse_events)\n", - " return fig.mouse_event(event, event['data']);\n", - " }\n", - "\n", - " rubberband.mousedown('button_press', mouse_event_fn);\n", - " rubberband.mouseup('button_release', mouse_event_fn);\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband.mousemove('motion_notify', mouse_event_fn);\n", - "\n", - " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", - " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", - "\n", - " canvas_div.on(\"wheel\", function (event) {\n", - " event = event.originalEvent;\n", - " event['data'] = 'scroll'\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " mouse_event_fn(event);\n", - " });\n", - "\n", - " canvas_div.append(canvas);\n", - " canvas_div.append(rubberband);\n", - "\n", - " this.rubberband = rubberband;\n", - " this.rubberband_canvas = rubberband[0];\n", - " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", - " this.rubberband_context.strokeStyle = \"#000000\";\n", - "\n", - " this._resize_canvas = function(width, height) {\n", - " // Keep the size of the canvas, canvas container, and rubber band\n", - " // canvas in synch.\n", - " canvas_div.css('width', width)\n", - " canvas_div.css('height', height)\n", - "\n", - " canvas.attr('width', width * mpl.ratio);\n", - " canvas.attr('height', height * mpl.ratio);\n", - " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", - "\n", - " rubberband.attr('width', width);\n", - " rubberband.attr('height', height);\n", - " }\n", - "\n", - " // Set the figure to an initial 600x600px, this will subsequently be updated\n", - " // upon first draw.\n", - " this._resize_canvas(600, 600);\n", - "\n", - " // Disable right mouse context menu.\n", - " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", - " return false;\n", - " });\n", - "\n", - " function set_focus () {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "}\n", - "\n", - "mpl.figure.prototype._init_toolbar = function() {\n", - " var fig = this;\n", - "\n", - " var nav_element = $('
')\n", - " nav_element.attr('style', 'width: 100%');\n", - " this.root.append(nav_element);\n", - "\n", - " // Define a callback function for later on.\n", - " function toolbar_event(event) {\n", - " return fig.toolbar_button_onclick(event['data']);\n", - " }\n", - " function toolbar_mouse_event(event) {\n", - " return fig.toolbar_button_onmouseover(event['data']);\n", - " }\n", - "\n", - " for(var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " // put a spacer in here.\n", - " continue;\n", - " }\n", - " var button = $('');\n", - " button.click(method_name, toolbar_event);\n", - " button.mouseover(tooltip, toolbar_mouse_event);\n", - " nav_element.append(button);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = $('');\n", - " nav_element.append(status_bar);\n", - " this.message = status_bar[0];\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = $('
');\n", - " var button = $('');\n", - " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", - " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", - " buttongrp.append(button);\n", - " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", - " titlebar.prepend(buttongrp);\n", - "}\n", - "\n", - "mpl.figure.prototype._root_extra_style = function(el){\n", - " var fig = this\n", - " el.on(\"remove\", function(){\n", - "\tfig.close_ws(fig, {});\n", - " });\n", - "}\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function(el){\n", - " // this is important to make the div 'focusable\n", - " el.attr('tabindex', 0)\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " }\n", - " else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "\n", - "}\n", - "\n", - "mpl.figure.prototype._key_event_extra = function(event, name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager)\n", - " manager = IPython.keyboard_manager;\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which == 13) {\n", - " this.canvas_div.blur();\n", - " event.shiftKey = false;\n", - " // Send a \"J\" for go to next cell\n", - " event.which = 74;\n", - " event.keyCode = 74;\n", - " manager.command_mode();\n", - " manager.handle_keydown(event);\n", - " }\n", - "}\n", - "\n", - "mpl.figure.prototype.handle_save = function(fig, msg) {\n", - " fig.ondownload(fig, null);\n", - "}\n", - "\n", - "\n", - "mpl.find_output_cell = function(html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] == html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "}\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel != null) {\n", - " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", - "}\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "if browser.ics is not None:\n", - " _ = browser.ics.plot_LR(figsize=(10, 4))" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.0" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} From 5159a306d51e39758cf99c045d57f2e78e401c05 Mon Sep 17 00:00:00 2001 From: "Sara A. Miskovich" Date: Wed, 29 May 2024 13:35:58 -0700 Subject: [PATCH 15/15] Update meta.yaml since cvxpy issue is resolved --- conda_recipe/meta.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conda_recipe/meta.yaml b/conda_recipe/meta.yaml index ac308af1..06ef92b0 100644 --- a/conda_recipe/meta.yaml +++ b/conda_recipe/meta.yaml @@ -42,8 +42,8 @@ requirements: test: imports: - solardatatools - # commands: - # - pip check # until cvxpy issue #2447 is resolved + commands: + - pip check requires: - pip