diff --git a/ci/requirements-py3.10.yml b/ci/requirements-py3.10.yml index eaeaf9d496..61c0e02400 100644 --- a/ci/requirements-py3.10.yml +++ b/ci/requirements-py3.10.yml @@ -25,4 +25,4 @@ dependencies: - statsmodels - pip: - nrel-pysam>=2.0 - - pvfactors==1.5.2 + - solarfactors diff --git a/ci/requirements-py3.11.yml b/ci/requirements-py3.11.yml index c3eead957c..703ce9197a 100644 --- a/ci/requirements-py3.11.yml +++ b/ci/requirements-py3.11.yml @@ -25,4 +25,4 @@ dependencies: - statsmodels - pip: - nrel-pysam>=2.0 - - pvfactors==1.5.2 + - solarfactors diff --git a/ci/requirements-py3.7.yml b/ci/requirements-py3.7.yml index 0b9d4dd961..eb3ddbb9cc 100644 --- a/ci/requirements-py3.7.yml +++ b/ci/requirements-py3.7.yml @@ -25,4 +25,4 @@ dependencies: - statsmodels - pip: - nrel-pysam>=2.0 - - pvfactors==1.5.2 + - solarfactors diff --git a/ci/requirements-py3.8.yml b/ci/requirements-py3.8.yml index cdfd574117..91365f37fb 100644 --- a/ci/requirements-py3.8.yml +++ b/ci/requirements-py3.8.yml @@ -25,4 +25,4 @@ dependencies: - statsmodels - pip: - nrel-pysam>=2.0 - - pvfactors==1.5.2 + - solarfactors diff --git a/ci/requirements-py3.9.yml b/ci/requirements-py3.9.yml index 4b9c3c7614..947da05a4d 100644 --- a/ci/requirements-py3.9.yml +++ b/ci/requirements-py3.9.yml @@ -25,4 +25,4 @@ dependencies: - statsmodels - pip: - nrel-pysam>=2.0 - - pvfactors==1.5.2 + - solarfactors \ No newline at end of file diff --git a/docs/examples/bifacial/plot_bifi_model_mc.py b/docs/examples/bifacial/plot_bifi_model_mc.py index caa5cf7ce4..679ff22921 100644 --- a/docs/examples/bifacial/plot_bifi_model_mc.py +++ b/docs/examples/bifacial/plot_bifi_model_mc.py @@ -18,6 +18,13 @@ # # Future versions of pvlib may make it easier to do bifacial modeling # with ``ModelChain``. +# +# .. attention:: +# To run this example, the ``solarfactors`` package (an implementation +# of the pvfactors model) must be installed. It can be installed with +# either ``pip install solarfactors`` or ``pip install pvlib[optional]``, +# which installs all of pvlib's optional dependencies. + import pandas as pd from pvlib import pvsystem diff --git a/docs/examples/bifacial/plot_bifi_model_pvwatts.py b/docs/examples/bifacial/plot_bifi_model_pvwatts.py index 3a0a7674a6..76a813fd4c 100644 --- a/docs/examples/bifacial/plot_bifi_model_pvwatts.py +++ b/docs/examples/bifacial/plot_bifi_model_pvwatts.py @@ -10,6 +10,12 @@ # :py:func:`pvlib.pvsystem.pvwatts_dc` with the # :py:func:`pvlib.bifacial.pvfactors.pvfactors_timeseries` function to # transpose GHI data to both front and rear Plane of Array (POA) irradiance. +# +# .. attention:: +# To run this example, the ``solarfactors`` package (an implementation +# of the pvfactors model) must be installed. It can be installed with +# either ``pip install solarfactors`` or ``pip install pvlib[optional]``, +# which installs all of pvlib's optional dependencies. import pandas as pd from pvlib import location diff --git a/docs/examples/bifacial/plot_pvfactors_fixed_tilt.py b/docs/examples/bifacial/plot_pvfactors_fixed_tilt.py index 5525c49453..63d7db902a 100644 --- a/docs/examples/bifacial/plot_pvfactors_fixed_tilt.py +++ b/docs/examples/bifacial/plot_pvfactors_fixed_tilt.py @@ -11,6 +11,12 @@ # fixed-tilt systems correctly. # This example shows how to model rear-side irradiance on a fixed-tilt # array using :py:func:`pvlib.bifacial.pvfactors.pvfactors_timeseries`. +# +# .. attention:: +# To run this example, the ``solarfactors`` package (an implementation +# of the pvfactors model) must be installed. It can be installed with +# either ``pip install solarfactors`` or ``pip install pvlib[optional]``, +# which installs all of pvlib's optional dependencies. import pandas as pd from pvlib import location diff --git a/docs/sphinx/source/conf.py b/docs/sphinx/source/conf.py index cd2d6b379d..cadadcd963 100644 --- a/docs/sphinx/source/conf.py +++ b/docs/sphinx/source/conf.py @@ -297,7 +297,8 @@ def setup(app): 'pull': ('https://github.com/pvlib/pvlib-python/pull/%s', 'GH'), 'wiki': ('https://github.com/pvlib/pvlib-python/wiki/%s', 'wiki '), 'doi': ('http://dx.doi.org/%s', 'DOI: '), - 'ghuser': ('https://github.com/%s', '@') + 'ghuser': ('https://github.com/%s', '@'), + 'discuss': ('https://github.com/pvlib/pvlib-python/discussions/%s', 'GH'), } # -- Options for manual page output --------------------------------------- diff --git a/docs/sphinx/source/user_guide/bifacial.rst b/docs/sphinx/source/user_guide/bifacial.rst index 695f8b6d89..0b1b0736a0 100644 --- a/docs/sphinx/source/user_guide/bifacial.rst +++ b/docs/sphinx/source/user_guide/bifacial.rst @@ -15,7 +15,7 @@ surfaces. pvlib-python provides two groups of functions for estimating front and back irradiance: -1. a wrapper for convenient use of the pvfactors package: +1. a wrapper for convenient use of the pvfactors model: :py:func:`~pvlib.bifacial.pvfactors.pvfactors_timeseries` 2. the infinite sheds bifacial model: @@ -26,12 +26,25 @@ irradiance: pvfactors --------- -The `pvfactors `_ package calculates +The pvfactors model calculates incident irradiance on the front and back surfaces of an array. pvfactors uses a 2D geometry which assumes that the array is made up of long, regular rows. Irradiance is calculated in the middle of a row; end-of-row effects are not included. pvfactors can model arrays in fixed racking or on single-axis -trackers. +trackers with a user-configurable number of rows. + +Prior to pvlib version 0.10.1, pvlib used the original SunPower implementation +of the model via the `pvfactors `_ +package. Starting in version 0.10.1, pvlib instead uses +`solarfactors `_, a drop-in +replacement implementation maintained by the pvlib community. +This switch was made when the original ``pvfactors`` package became +difficult to install in modern python environments. +``solarfactors`` implements the same model as ``pvfactors`` and is kept +up to date and working over time. Note that "solarfactors" is only the name +on PyPI (meaning it is installed via ``pip install solarfactors``); +after installation, Python code still accesses it as "pvfactors" +(e.g. ``import pvfactors``). Infinite Sheds diff --git a/docs/sphinx/source/whatsnew.rst b/docs/sphinx/source/whatsnew.rst index 4a91218e1b..75831e6a48 100644 --- a/docs/sphinx/source/whatsnew.rst +++ b/docs/sphinx/source/whatsnew.rst @@ -6,6 +6,7 @@ What's New These are new features and improvements of note in each release. +.. include:: whatsnew/v0.10.1.rst .. include:: whatsnew/v0.10.0.rst .. include:: whatsnew/v0.9.5.rst .. include:: whatsnew/v0.9.4.rst diff --git a/docs/sphinx/source/whatsnew/v0.10.1.rst b/docs/sphinx/source/whatsnew/v0.10.1.rst index fda67c7465..42d709c808 100644 --- a/docs/sphinx/source/whatsnew/v0.10.1.rst +++ b/docs/sphinx/source/whatsnew/v0.10.1.rst @@ -1,34 +1,12 @@ .. _whatsnew_01010: -v0.10.1 (Anticipated September, 2023) -------------------------------------- - - -Deprecations -~~~~~~~~~~~~ - - -Enhancements -~~~~~~~~~~~~ - - -Bug fixes -~~~~~~~~~ - - -Testing -~~~~~~~ - - -Documentation -~~~~~~~~~~~~~ - - -Requirements -~~~~~~~~~~~~ - - -Contributors -~~~~~~~~~~~~ +v0.10.1 (July 3, 2023) +---------------------- + +To resolve an installation issue with ``pvfactors`` and ``shapely``, +this release drops the optional ``pvfactors`` dependency and replaces +it with ``solarfactors``, a fork of ``pvfactors`` maintained by the +pvlib community. This change should not affect any user code. +(:issue:`1796`, :pull:`1797`, :discuss:`1657`) diff --git a/docs/sphinx/source/whatsnew/v0.10.2.rst b/docs/sphinx/source/whatsnew/v0.10.2.rst new file mode 100644 index 0000000000..f95f0bd93d --- /dev/null +++ b/docs/sphinx/source/whatsnew/v0.10.2.rst @@ -0,0 +1,38 @@ +.. _whatsnew_01020: + + +v0.10.2 (Anticipated September, 2023) +------------------------------------- + + +Deprecations +~~~~~~~~~~~~ + + +Enhancements +~~~~~~~~~~~~ +* Added support for dates to be specified as strings in the iotools get functions: + :py:func:`pvlib.iotools.get_pvgis_hourly`, :py:func:`pvlib.iotools.get_cams`, + :py:func:`pvlib.iotools.get_bsrn`, and :py:func:`pvlib.iotools.read_midc_raw_data_from_nrel`. + (:pull:`1800`) + + +Bug fixes +~~~~~~~~~ + + +Testing +~~~~~~~ + + +Documentation +~~~~~~~~~~~~~ + + +Requirements +~~~~~~~~~~~~ + + +Contributors +~~~~~~~~~~~~ +* Adam R. Jensen (:ghuser:`AdamRJensen`) diff --git a/pvlib/bifacial/pvfactors.py b/pvlib/bifacial/pvfactors.py index ed09879a21..05e3807658 100644 --- a/pvlib/bifacial/pvfactors.py +++ b/pvlib/bifacial/pvfactors.py @@ -1,6 +1,7 @@ """ The ``bifacial.pvfactors`` module contains functions for modeling back surface -plane-of-array irradiance using the pvfactors package. +plane-of-array irradiance using an external implementaton of the pvfactors +model (either ``solarfactors`` or the original ``pvfactors``). """ import pandas as pd @@ -15,11 +16,15 @@ def pvfactors_timeseries( horizon_band_angle=15.): """ Calculate front and back surface plane-of-array irradiance on - a fixed tilt or single-axis tracker PV array configuration, and using - the open-source "pvfactors" package. pvfactors implements the model - described in [1]_. - Please refer to pvfactors online documentation for more details: - https://sunpower.github.io/pvfactors/ + a fixed tilt or single-axis tracker PV array configuration using + the pvfactors model. + + The pvfactors bifacial irradiance model is described in [1]_. + + .. versionchanged:: 0.10.1 + It is now recommended to install the ``solarfactors`` package + (``pip install solarfactors``) instead of ``pvfactors`` for this + function. For more information, see :ref:`bifacial`. Parameters ---------- diff --git a/pvlib/iotools/bsrn.py b/pvlib/iotools/bsrn.py index b9292b41ae..c9ed8394cd 100644 --- a/pvlib/iotools/bsrn.py +++ b/pvlib/iotools/bsrn.py @@ -154,6 +154,10 @@ def get_bsrn(station, start, end, username, password, # The FTP server uses lowercase station abbreviations station = station.lower() + # Use pd.to_datetime so that strings (e.g. '2021-01-01') are accepted + start = pd.to_datetime(start) + end = pd.to_datetime(end) + # Generate list files to download based on start/end (SSSMMYY.dat.gz) filenames = pd.date_range( start, end.replace(day=1) + pd.DateOffset(months=1), freq='1M')\ diff --git a/pvlib/iotools/midc.py b/pvlib/iotools/midc.py index 75cc5609a7..c554dd1d1f 100644 --- a/pvlib/iotools/midc.py +++ b/pvlib/iotools/midc.py @@ -215,9 +215,9 @@ def read_midc_raw_data_from_nrel(site, start, end, variable_map={}, ---------- site: string The MIDC station id. - start: datetime + start: datetime-like Start date for requested data. - end: datetime + end: datetime-like End date for requested data. variable_map: dict A dictionary mapping MIDC field names to pvlib names. Used to @@ -247,8 +247,8 @@ def read_midc_raw_data_from_nrel(site, start, end, variable_map={}, for more details and considerations. """ args = {'site': site, - 'begin': start.strftime('%Y%m%d'), - 'end': end.strftime('%Y%m%d')} + 'begin': pd.to_datetime(start).strftime('%Y%m%d'), + 'end': pd.to_datetime(end).strftime('%Y%m%d')} url = 'https://midcdmz.nrel.gov/apps/data_api.pl' # NOTE: just use requests.get(url, params=args) to build querystring # number of header columns and data columns do not always match, diff --git a/pvlib/iotools/pvgis.py b/pvlib/iotools/pvgis.py index da238898a8..ca1371d4a1 100644 --- a/pvlib/iotools/pvgis.py +++ b/pvlib/iotools/pvgis.py @@ -217,9 +217,9 @@ def get_pvgis_hourly(latitude, longitude, start=None, end=None, if raddatabase is not None: params['raddatabase'] = raddatabase if start is not None: - params['startyear'] = start if isinstance(start, int) else start.year + params['startyear'] = start if isinstance(start, int) else pd.to_datetime(start).year # noqa: E501 if end is not None: - params['endyear'] = end if isinstance(end, int) else end.year + params['endyear'] = end if isinstance(end, int) else pd.to_datetime(end).year # noqa: E501 if peakpower is not None: params['peakpower'] = peakpower diff --git a/pvlib/iotools/sodapro.py b/pvlib/iotools/sodapro.py index 9fb4602e09..95d6ffd866 100644 --- a/pvlib/iotools/sodapro.py +++ b/pvlib/iotools/sodapro.py @@ -47,8 +47,9 @@ def get_cams(latitude, longitude, start, end, email, identifier='mcclear', altitude=None, time_step='1h', time_ref='UT', verbose=False, integrated=False, label=None, map_variables=True, server=URL, timeout=30): - """ - Retrieve time-series of radiation and/or clear-sky global, beam, and + """Retrieve irradiance and clear-sky time series from CAMS. + + Time-series of radiation and/or clear-sky global, beam, and diffuse radiation from CAMS (see [1]_). Data is retrieved from SoDa [2]_. Time coverage: 2004-01-01 to two days ago @@ -65,9 +66,9 @@ def get_cams(latitude, longitude, start, end, email, identifier='mcclear', in decimal degrees, between -90 and 90, north is positive (ISO 19115) longitude : float in decimal degrees, between -180 and 180, east is positive (ISO 19115) - start: datetime like + start: datetime-like First day of the requested period - end: datetime like + end: datetime-like Last day of the requested period email: str Email address linked to a SoDa account @@ -177,8 +178,8 @@ def get_cams(latitude, longitude, start, end, email, identifier='mcclear', altitude = -999 # Start and end date should be in the format: yyyy-mm-dd - start = start.strftime('%Y-%m-%d') - end = end.strftime('%Y-%m-%d') + start = pd.to_datetime(start).strftime('%Y-%m-%d') + end = pd.to_datetime(end).strftime('%Y-%m-%d') email = email.replace('@', '%2540') # Format email address identifier = 'get_{}'.format(identifier.lower()) # Format identifier str diff --git a/pvlib/iotools/srml.py b/pvlib/iotools/srml.py index 81b61556a0..01b835da6d 100644 --- a/pvlib/iotools/srml.py +++ b/pvlib/iotools/srml.py @@ -243,9 +243,9 @@ def get_srml(station, start, end, filetype='PO', map_variables=True, ---------- station : str Two letter station abbreviation. - start : datetime like + start : datetime-like First day of the requested period - end : datetime like + end : datetime-like Last day of the requested period filetype : string, default: 'PO' SRML file type to gather. See notes for explanation. diff --git a/setup.py b/setup.py index 1e7ad4bedd..3d2b64444b 100755 --- a/setup.py +++ b/setup.py @@ -47,11 +47,11 @@ 'pytest-remotedata'] EXTRAS_REQUIRE = { 'optional': ['cython', 'ephem', 'nrel-pysam', 'numba', - 'pvfactors', 'statsmodels'], + 'solarfactors', 'statsmodels'], 'doc': ['ipython', 'matplotlib', 'sphinx == 4.5.0', 'pydata-sphinx-theme == 0.8.1', 'sphinx-gallery', 'docutils == 0.15.2', 'pillow', - 'sphinx-toggleprompt >= 0.0.5', 'pvfactors'], + 'sphinx-toggleprompt >= 0.0.5', 'solarfactors'], 'test': TESTS_REQUIRE } EXTRAS_REQUIRE['all'] = sorted(set(sum(EXTRAS_REQUIRE.values(), [])))