Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 19 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,24 @@ Please see the [Contributing page](http://pvlib-python.readthedocs.io/en/stable/
The long-term success of pvlib-python requires substantial community support.


License
=======
Citing
======

If you use pvlib-python in a published work, please cite:

William F. Holmgren, Clifford W. Hansen, and Mark A. Mikofski.
"pvlib python: a python package for modeling solar energy systems."
Journal of Open Source Software, 3(29), 884, (2018).
https://doi.org/10.21105/joss.00884

BSD 3-clause
Please also cite the DOI corresponding to the specific version of
pvlib-python that you used. pvlib-python DOIs are listed at
[Zenodo.org](https://zenodo.org/search?page=1&size=20&q=conceptrecid:593284&all_versions&sort=-version)

If you use pvlib-python in a commercial or publicly-available application, please
consider displaying one of the "powered by pvlib" logos:

<img src="docs/sphinx/source/_images/pvlib_powered_logo_vert.png" width="300"><img src="docs/sphinx/source/_images/pvlib_powered_logo_horiz.png" width="300">

Getting support
===============
Expand All @@ -133,19 +146,12 @@ change something about pvlib, then please make an issue on our
[GitHub issues page](https://github.com/pvlib/pvlib-python/issues).


Citing
======

If you use pvlib-python in a published work, please cite:
License
=======

William F. Holmgren, Clifford W. Hansen, and Mark A. Mikofski.
"pvlib python: a python package for modeling solar energy systems."
Journal of Open Source Software, 3(29), 884, (2018).
https://doi.org/10.21105/joss.00884
BSD 3-clause.

Please also cite the DOI corresponding to the specific version of
pvlib-python that you used. pvlib-python DOIs are listed at
[Zenodo.org](https://zenodo.org/search?page=1&size=20&q=conceptrecid:593284&all_versions&sort=-version)

NumFOCUS
========
Expand Down
2 changes: 1 addition & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
vmImage: ubuntu-16.04


- template: ci/azure/posix.yml
- template: ci/azure/posix_no_39.yml
parameters:
name: Test_bare_macOS
vmImage: macOS-10.14
Expand Down
39 changes: 39 additions & 0 deletions ci/azure/posix_no_39.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
parameters:
name: ''
vmImage: ''

jobs:
- job: ${{ parameters.name }}
pool:
vmImage: ${{ parameters.vmImage }}
strategy:
matrix:
Python36:
python.version: '3.6'
Python37:
python.version: '3.7'
Python38:
python.version: '3.8'

steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '$(python.version)'

- script: |
pip install pytest pytest-cov pytest-mock requests-mock pytest-timeout pytest-azurepipelines pytest-rerunfailures pytest-remotedata
pip install -e .
pytest pvlib --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html
displayName: 'Test with pytest'

- task: PublishTestResults@2
condition: succeededOrFailed()
inputs:
testResultsFiles: '**/test-*.xml'
testRunTitle: 'Publish test results for Python $(python.version)'

- task: PublishCodeCoverageResults@1
inputs:
codeCoverageTool: Cobertura
summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/coverage.xml'
reportDirectory: '$(System.DefaultWorkingDirectory)/**/htmlcov'
2 changes: 2 additions & 0 deletions ci/requirements-py36-min.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ dependencies:
- coveralls
- nose
- pip
- pytables # tables when using pip+PyPI
- pytest
- pytest-cov
- pytest-mock
Expand All @@ -20,3 +21,4 @@ dependencies:
- pytest-rerunfailures # conda version is >3.6
- pytest-remotedata # conda package is 0.3.0, needs > 0.3.1
- requests-mock
- numexpr==2.6.2 # needed for tables, but newest version is not compatible with numpy 1.12
1 change: 1 addition & 0 deletions ci/requirements-py36.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ channels:
- defaults
- conda-forge
dependencies:
- blosc=1.14.3 # newest version breaks tables (pytables) on windows
- coveralls
- cython
- ephem
Expand Down
1 change: 1 addition & 0 deletions ci/requirements-py37.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ channels:
- defaults
- conda-forge
dependencies:
- blosc=1.14.3 # newest version breaks tables (pytables) on windows
- coveralls
- cython
- ephem
Expand Down
89 changes: 89 additions & 0 deletions docs/examples/plot_discontinuous_tracking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"""
Discontinuous Tracking
======================

Example of a custom Mount class.
"""

# %%
# Many real-world tracking arrays adjust their position in discrete steps
# rather than through continuous movement. This example shows how to model
# this discontinuous tracking by implementing a custom Mount class.

from pvlib import tracking, pvsystem, location, modelchain
from pvlib.temperature import TEMPERATURE_MODEL_PARAMETERS
import matplotlib.pyplot as plt
import pandas as pd


# %%
# We'll define our custom Mount by extending
# :py:class:`~pvlib.pvsystem.SingleAxisTrackerMount` for convenience.
# Another approach would be to extend ``AbstractMount`` directly; see
# the source code of :py:class:`~pvlib.pvsystem.SingleAxisTrackerMount`
# and :py:class:`~pvlib.pvsystem.FixedMount` for how that is done.


class DiscontinuousTrackerMount(pvsystem.SingleAxisTrackerMount):
# inherit from SingleAxisTrackerMount so that we get the
# constructor and tracking attributes (axis_tilt etc) automatically

def get_orientation(self, solar_zenith, solar_azimuth):
# Different trackers update at different rates; in this example we'll
# assume a relatively slow update interval of 15 minutes to make the
# effect more visually apparent.
zenith_subset = solar_zenith.resample('15min').first()
azimuth_subset = solar_azimuth.resample('15min').first()

tracking_data_15min = tracking.singleaxis(
zenith_subset, azimuth_subset,
self.axis_tilt, self.axis_azimuth,
self.max_angle, self.backtrack,
self.gcr, self.cross_axis_tilt
)
# propagate the 15-minute positions to 1-minute stair-stepped values:
tracking_data_1min = tracking_data_15min.reindex(solar_zenith.index,
method='ffill')
return tracking_data_1min


# %%
# Let's take a look at the tracker rotation curve it produces:

times = pd.date_range('2019-06-01', '2019-06-02', freq='1min', tz='US/Eastern')
loc = location.Location(40, -80)
solpos = loc.get_solarposition(times)
mount = DiscontinuousTrackerMount(axis_azimuth=180, gcr=0.4)
tracker_data = mount.get_orientation(solpos.apparent_zenith, solpos.azimuth)
tracker_data['tracker_theta'].plot()
plt.ylabel('Tracker Rotation [degree]')
plt.show()

# %%
# With our custom tracking logic defined, we can create the corresponding
# Array and PVSystem, and then run a ModelChain as usual:

module_parameters = {'pdc0': 1, 'gamma_pdc': -0.004, 'b': 0.05}
temp_params = TEMPERATURE_MODEL_PARAMETERS['sapm']['open_rack_glass_polymer']
array = pvsystem.Array(mount=mount, module_parameters=module_parameters,
temperature_model_parameters=temp_params)
system = pvsystem.PVSystem(arrays=[array], inverter_parameters={'pdc0': 1})
mc = modelchain.ModelChain(system, loc, spectral_model='no_loss')

# simple simulated weather, just to show the effect of discrete tracking
weather = loc.get_clearsky(times)
weather['temp_air'] = 25
weather['wind_speed'] = 1
mc.run_model(weather)

fig, axes = plt.subplots(2, 1, sharex=True)
mc.results.effective_irradiance.plot(ax=axes[0])
axes[0].set_ylabel('Effective Irradiance [W/m^2]')
mc.results.ac.plot(ax=axes[1])
axes[1].set_ylabel('AC Power')
fig.show()

# %%
# The effect of discontinuous tracking creates a "jagged" effect in the
# simulated plane-of-array irradiance, which then propagates through to
# the AC power output.
44 changes: 44 additions & 0 deletions docs/examples/plot_dual_axis_tracking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""
Dual-Axis Tracking
==================

Example of a custom Mount class.
"""

# %%
# Dual-axis trackers can track the sun in two dimensions across the sky dome
# instead of just one like single-axis trackers. This example shows how to
# model a simple dual-axis tracking system using ModelChain with a custom
# Mount class.

from pvlib import pvsystem, location, modelchain
import pandas as pd
import matplotlib.pyplot as plt

# %%
# New Mount classes should extend ``pvlib.pvsystem.AbstractMount``
# and must implement a ``get_orientation(solar_zenith, solar_azimuth)`` method:


class DualAxisTrackerMount(pvsystem.AbstractMount):
def get_orientation(self, solar_zenith, solar_azimuth):
# no rotation limits, no backtracking
return {'surface_tilt': solar_zenith, 'surface_azimuth': solar_azimuth}


loc = location.Location(40, -80)
array = pvsystem.Array(
mount=DualAxisTrackerMount(),
module_parameters=dict(pdc0=1, gamma_pdc=-0.004, b=0.05),
temperature_model_parameters=dict(a=-3.56, b=-0.075, deltaT=3))
system = pvsystem.PVSystem(arrays=[array], inverter_parameters=dict(pdc0=3))
mc = modelchain.ModelChain(system, loc, spectral_model='no_loss')

times = pd.date_range('2019-01-01 06:00', '2019-01-01 18:00', freq='5min',
tz='Etc/GMT+5')
weather = loc.get_clearsky(times)
mc.run_model(weather)

mc.results.ac.plot()
plt.ylabel('Output Power')
plt.show()
49 changes: 49 additions & 0 deletions docs/examples/plot_mixed_orientation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""
Mixed Orientation
=================

Using multiple Arrays in a single PVSystem.
"""

# %%
# Residential and Commercial systems often have fixed-tilt arrays
# installed at different azimuths. This can be modeled by using
# multiple :py:class:`~pvlib.pvsystem.Array` objects (one for each
# orientation) with a single :py:class:`~pvlib.pvsystem.PVSystem` object.
#
# This particular example has one east-facing array (azimuth=90) and one
# west-facing array (azimuth=270), which aside from orientation are identical.


from pvlib import pvsystem, modelchain, location
import pandas as pd
import matplotlib.pyplot as plt

array_kwargs = dict(
module_parameters=dict(pdc0=1, gamma_pdc=-0.004),
temperature_model_parameters=dict(a=-3.56, b=-0.075, deltaT=3)
)

arrays = [
pvsystem.Array(pvsystem.FixedMount(30, 270), name='West-Facing Array',
**array_kwargs),
pvsystem.Array(pvsystem.FixedMount(30, 90), name='East-Facing Array',
**array_kwargs),
]
loc = location.Location(40, -80)
system = pvsystem.PVSystem(arrays=arrays, inverter_parameters=dict(pdc0=3))
mc = modelchain.ModelChain(system, loc, aoi_model='physical',
spectral_model='no_loss')

times = pd.date_range('2019-01-01 06:00', '2019-01-01 18:00', freq='5min',
tz='Etc/GMT+5')
weather = loc.get_clearsky(times)
mc.run_model(weather)

fig, ax = plt.subplots()
for array, pdc in zip(system.arrays, mc.results.dc):
pdc.plot(label=f'{array.name}')
mc.results.ac.plot(label='Inverter')
plt.ylabel('System Output')
plt.legend()
plt.show()
Loading