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(), [])))