Skip to content

Commit 4bfff5a

Browse files
author
dacoex
committed
Merge remote-tracking branch 'wholmgren/pvsystem' into origin/pvsystem
2 parents e5d77d5 + df389aa commit 4bfff5a

15 files changed

+754
-155
lines changed

docs/sphinx/source/index.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ and
4242

4343
The GitHub wiki also has a page on `Projects and publications that use pvlib python <https://github.com/pvlib/pvlib-python/wiki/Projects-and-publications-that-use-pvlib-python>`_ for inspiration and listing of your application.
4444

45+
There is a :ref:`variable naming convention <variables_style_rules>` to ensure consistency throughout the library.
46+
4547
Installation
4648
============
4749

@@ -59,10 +61,11 @@ Contents
5961

6062
self
6163
package_overview
64+
whatsnew
6265
modules
6366
classes
6467
comparison_pvlib_matlab
65-
whatsnew
68+
variables_style_rules
6669

6770

6871
Indices and tables

docs/sphinx/source/package_overview.rst

Lines changed: 87 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ is well-tested procedural code that implements PV system models.
2020
pvlib-python also provides a collection of classes for users
2121
that prefer object-oriented programming.
2222
These classes can help users keep track of data in a more organized way,
23-
and can help to simplify the modeling process.
24-
The classes do not add any functionality beyond the procedural code.
25-
Most of the object methods are simple wrappers around the
26-
corresponding procedural code.
23+
provide some "smart" functions with more flexible inputs,
24+
and simplify the modeling process for common situations.
25+
The classes do not add any algorithms beyond what's available
26+
in the procedural code, and most of the object methods
27+
are simple wrappers around the corresponding procedural code.
2728

2829
Let's use each of these pvlib modeling paradigms
2930
to calculate the yearly energy yield for a given hardware
@@ -33,23 +34,31 @@ configuration at a handful of sites listed below.
3334
3435
import pandas as pd
3536
import matplotlib.pyplot as plt
37+
38+
# seaborn makes the plots look nicer
3639
import seaborn as sns
3740
sns.set_color_codes()
3841
3942
times = pd.DatetimeIndex(start='2015', end='2016', freq='1h')
4043
4144
# very approximate
42-
coordinates = [(30, -110, 'Tucson'),
43-
(35, -105, 'Albuquerque'),
44-
(40, -120, 'San Francisco'),
45-
(50, 10, 'Berlin')]
45+
# latitude, longitude, name, altitude
46+
coordinates = [(30, -110, 'Tucson', 700),
47+
(35, -105, 'Albuquerque', 1500),
48+
(40, -120, 'San Francisco', 10),
49+
(50, 10, 'Berlin', 34)]
4650
4751
import pvlib
4852
53+
# get the module and inverter specifications from SAM
4954
sandia_modules = pvlib.pvsystem.retrieve_sam('SandiaMod')
5055
sapm_inverters = pvlib.pvsystem.retrieve_sam('sandiainverter')
5156
module = sandia_modules['Canadian_Solar_CS5P_220M___2009_']
5257
inverter = sapm_inverters['ABB__MICRO_0_25_I_OUTD_US_208_208V__CEC_2014_']
58+
59+
# specify constant ambient air temp and wind for simplicity
60+
temp_air = 20
61+
wind_speed = 0
5362
5463
5564
Procedural
@@ -67,13 +76,15 @@ to accomplish our system modeling goal:
6776
'surface_azimuth': 180}
6877
6978
energies = {}
70-
for latitude, longitude, name in coordinates:
79+
for latitude, longitude, name, altitude in coordinates:
7180
system['surface_tilt'] = latitude
72-
cs = pvlib.clearsky.ineichen(times, latitude, longitude)
81+
cs = pvlib.clearsky.ineichen(times, latitude, longitude, altitude=altitude)
7382
solpos = pvlib.solarposition.get_solarposition(times, latitude, longitude)
7483
dni_extra = pvlib.irradiance.extraradiation(times)
7584
dni_extra = pd.Series(dni_extra, index=times)
7685
airmass = pvlib.atmosphere.relativeairmass(solpos['apparent_zenith'])
86+
pressure = pvlib.atmosphere.alt2pres(altitude)
87+
am_abs = pvlib.atmosphere.absoluteairmass(airmass, pressure)
7788
aoi = pvlib.irradiance.aoi(system['surface_tilt'], system['surface_azimuth'],
7889
solpos['apparent_zenith'], solpos['azimuth'])
7990
total_irrad = pvlib.irradiance.total_irrad(system['surface_tilt'],
@@ -83,10 +94,11 @@ to accomplish our system modeling goal:
8394
cs['dni'], cs['ghi'], cs['dhi'],
8495
dni_extra=dni_extra,
8596
model='haydavies')
86-
temps = pvlib.pvsystem.sapm_celltemp(total_irrad['poa_global'], 0, 20)
97+
temps = pvlib.pvsystem.sapm_celltemp(total_irrad['poa_global'],
98+
wind_speed, temp_air)
8799
dc = pvlib.pvsystem.sapm(module, total_irrad['poa_direct'],
88100
total_irrad['poa_diffuse'], temps['temp_cell'],
89-
airmass, aoi)
101+
am_abs, aoi)
90102
ac = pvlib.pvsystem.snlinverter(inverter, dc['v_mp'], dc['p_mp'])
91103
annual_energy = ac.sum()
92104
energies[name] = annual_energy
@@ -105,11 +117,11 @@ Object oriented (Location, PVSystem, ModelChain)
105117
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
106118

107119
The first object oriented paradigm uses a model where
108-
a :class:`PVSystem <pvlib.pvsystem.PVSystem>` object represents an
120+
a :py:class:`~pvlib.pvsystem.PVSystem` object represents an
109121
assembled collection of modules, inverters, etc.,
110-
a :class:`Location <pvlib.location.Location>` object represents a
122+
a :py:class:`~pvlib.location.Location` object represents a
111123
particular place on the planet,
112-
and a :class:`ModelChain <pvlib.modelchain.ModelChain>` object describes
124+
and a :py:class:`~pvlib.modelchain.ModelChain` object describes
113125
the modeling chain used to calculate PV output at that Location.
114126
This can be a useful paradigm if you prefer to think about
115127
the PV system and its location as separate concepts or if
@@ -118,9 +130,9 @@ It can also be helpful if you make extensive use of Location-specific
118130
methods for other calculations.
119131

120132
The following code demonstrates how to use
121-
:class:`Location <pvlib.location.Location>`,
122-
:class:`PVSystem <pvlib.pvsystem.PVSystem>`, and
123-
:class:`ModelChain <pvlib.modelchain.ModelChain>`
133+
:py:class:`~pvlib.location.Location`,
134+
:py:class:`~pvlib.pvsystem.PVSystem`, and
135+
:py:class:`~pvlib.modelchain.ModelChain`
124136
objects to accomplish our system modeling goal:
125137

126138
.. ipython:: python
@@ -129,57 +141,86 @@ objects to accomplish our system modeling goal:
129141
from pvlib.location import Location
130142
from pvlib.modelchain import ModelChain
131143
132-
system = PVSystem(module, inverter, **other_params)
144+
system = PVSystem(module_parameters=module,
145+
inverter_parameters=inverter)
133146
134147
energies = {}
135-
for latitude, longitude, name in coordinates:
136-
location = Location(latitude, longitude)
137-
# not yet clear what, exactly, goes into ModelChain(s)
138-
mc = ModelChain(system, location, times,
139-
'south_at_latitude', **other_modelchain_params)
140-
output = mc.run_model()
141-
annual_energy = output['power'].sum()
148+
for latitude, longitude, name, altitude in coordinates:
149+
location = Location(latitude, longitude, name=name, altitude=altitude)
150+
# very experimental
151+
mc = ModelChain(system, location,
152+
orientation_strategy='south_at_latitude_tilt')
153+
# optional parameters for irradiance and weather data
154+
dc, ac = mc.run_model(times)
155+
annual_energy = ac.sum()
142156
energies[name] = annual_energy
143157
144-
#energies = pd.DataFrame(energies)
145-
#energies.plot()
158+
energies = pd.Series(energies)
159+
160+
# based on the parameters specified above, these are in W*hrs
161+
print(energies.round(0))
162+
163+
energies.plot(kind='bar', rot=0)
164+
@savefig modelchain-energies.png width=6in
165+
plt.ylabel('Yearly energy yield (W hr)')
146166
147167
148168
Object oriented (LocalizedPVSystem)
149169
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
150170

151171
The second object oriented paradigm uses a model where a
152-
:class:`LocalizedPVSystem <pvlib.pvsystem.LocalizedPVSystem>` represents a
172+
:py:class:`~pvlib.pvsystem.LocalizedPVSystem` represents a
153173
PV system at a particular place on the planet.
154174
This can be a useful paradigm if you're thinking about
155175
a power plant that already exists.
156176

157177
The following code demonstrates how to use a
158-
:class:`LocalizedPVSystem <pvlib.pvsystem.LocalizedPVSystem>`
178+
:py:class:`~pvlib.pvsystem.LocalizedPVSystem`
159179
object to accomplish our modeling goal:
160180

161181
.. ipython:: python
162182
163-
from pvlib.pvsystem import PVSystem, LocalizedPVSystem
164-
165-
module =
166-
inverter =
167-
other_system_params = {} # sometime helpful to break apart
168-
base_system = PVSystem(module, inverter, **other_system_params)
183+
from pvlib.pvsystem import LocalizedPVSystem
169184
170185
energies = {}
171-
for latitude, longitude, name in coordinates:
172-
localized_system = base_system.localize(latitude, longitude, name=name)
173-
localized_system.surface_tilt = latitude
174-
cs = localized_system.get_clearsky(times)
175-
solpos = localized_system.get_solarposition(times)
176-
total_irrad = localized_system.get_irradiance(times, **solpos, **cs)
177-
power = localized_system.get_power(stuff)
178-
annual_energy = power.sum()
186+
for latitude, longitude, name, altitude in coordinates:
187+
localized_system = LocalizedPVSystem(module_parameters=module,
188+
inverter_parameters=inverter,
189+
surface_tilt=latitude,
190+
surface_azimuth=180,
191+
latitude=latitude,
192+
longitude=longitude,
193+
name=name,
194+
altitude=altitude)
195+
clearsky = localized_system.get_clearsky(times)
196+
solar_position = localized_system.get_solarposition(times)
197+
total_irrad = localized_system.get_irradiance(solar_position['apparent_zenith'],
198+
solar_position['azimuth'],
199+
clearsky['dni'],
200+
clearsky['ghi'],
201+
clearsky['dhi'])
202+
temps = localized_system.sapm_celltemp(total_irrad['poa_global'],
203+
wind_speed, temp_air)
204+
aoi = localized_system.get_aoi(solar_position['apparent_zenith'],
205+
solar_position['azimuth'])
206+
airmass = localized_system.get_airmass(solar_position=solar_position)
207+
dc = localized_system.sapm(total_irrad['poa_direct'],
208+
total_irrad['poa_diffuse'],
209+
temps['temp_cell'],
210+
airmass['airmass_absolute'],
211+
aoi)
212+
ac = localized_system.snlinverter(dc['v_mp'], dc['p_mp'])
213+
annual_energy = ac.sum()
179214
energies[name] = annual_energy
180215
181-
#energies = pd.DataFrame(energies)
182-
#energies.plot()
216+
energies = pd.Series(energies)
217+
218+
# based on the parameters specified above, these are in W*hrs
219+
print(energies.round(0))
220+
221+
energies.plot(kind='bar', rot=0)
222+
@savefig localized-pvsystem-energies.png width=6in
223+
plt.ylabel('Yearly energy yield (W hr)')
183224
184225
185226
User extensions
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
.. _variables_style_rules:
2+
3+
Variables and Symbols
4+
=====================
5+
6+
There is a convention on consistent variable names throughout the library:
7+
8+
.. csv-table:: List of used Variables and Parameters
9+
:file: ../../../pvlib/data/variables_style_rules.csv
10+
:delim: ;
11+
:header-rows: 1
12+
:widths: 5, 5
13+
:stub-columns: 1
14+
15+
For a definition and further explanation on the variables, common symbols and units refer to the following sources:
16+
17+
18+
* `Reference Variable List by PVPMC <https://pvpmc.sandia.gov/resources/variable-list/>`_
19+
* `IEC 61724:1998 -- Photovoltaic system performance monitoring - Guidelines for measurement, data exchange and analysis <https://webstore.iec.ch/publication/5733>`_ ; the Indian Standard referencing the global IEC standard is available online: `IS/IEC 61724 (1998) <https://law.resource.org/pub/in/bis/S05/is.iec.61724.1998.pdf>`_
20+
* Explanation of Solar irradiation and solar geometry by `SoDa Service <http://www.soda-pro.com/home>`_
21+
22+
* `Acronyms, Terminology and Units <http://www.soda-pro.com/help/general/acronyms-terminology-and-units>`_
23+
* `Plane orientations and radiation components <http://www.soda-pro.com/help/general/plane-orientations-and-radiation-components>`_
24+
* `Time references <http://www.soda-pro.com/help/general/time-references>`_
25+
* `Units and conversion tool <http://www.soda-is.com/eng/education/units.html>`_
26+
* `Terminology: definitions of the main quantities. <http://www.soda-is.com/eng/education/terminology.html>`_
27+
* `Acronyms in solar radiation <http://www.soda-is.com/eng/education/acronymes.html>`_ (more extensive list)
28+
29+
.. note:: These further references might not use the same terminology as *pvlib*. But the physical process referred to is the same.

docs/sphinx/source/whatsnew/v0.3.0.txt

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,49 @@ This is a major release from 0.2.2.
77
We recommend that all users upgrade to this version after testing
88
their code for compatibility and updating as necessary.
99

10+
1011
Enhancements
1112
~~~~~~~~~~~~
1213

13-
* Adds ``PVSystem`` and ``SingleAxisTracker`` classes. (:issue:`17`)
14+
* Adds ``PVSystem``, ``LocalizedPVSystem``, ``ModelChain``,
15+
and ``SingleAxisTracker`` classes. (:issue:`17`)
1416
* Replaces ``location`` arguments with ``latitude``, ``longitude``,
1517
``altitude``, and ``tz`` as appropriate.
1618
This separates the object-oriented API from the procedural API.
1719
(:issue:`17`)
18-
20+
* ``Location`` classes can be created from TMY2/TMY3 metadata
21+
using the ``from_tmy`` constructor.
22+
* ``Location`` classes gain the ``get_solarposition``, ``get_clearsky``,
23+
and ``get_airmass`` functions.
24+
* Add Package Overview and Classes pages to documentation.
25+
* Adds support for Appveyor, a Windows continuous integration service.
26+
(:issue:`111`)
27+
* The readthedocs documentation build now uses conda packages
28+
instead of mock packages. This enables code to be run
29+
and figures to be generated during the documentation builds.
30+
(:issue:`104`)
31+
* Reconfigures TravisCI builds and adds e.g. ``has_numba`` decorators
32+
to the test suite. The result is that the TravisCI test suite runs
33+
almost 10x faster and users do not have to install all optional
34+
dependencies to run the test suite. (:issue:`109`)
35+
* Adds more unit tests that test that the return values are
36+
actually correct.
37+
* Add ``atmosphere.APPARENT_ZENITH_MODELS`` and
38+
``atmosphere.TRUE_ZENITH_MODELS`` to enable code that can
39+
automatically determine which type of zenith data to use
40+
e.g. ``Location.get_airmass``.
41+
* Change default ``Location`` timezone to ``'UTC'``.
1942

2043
Bug fixes
2144
~~~~~~~~~
2245

46+
* ``pvsystem.sapm_celltemp`` argument names now follow the
47+
variable conventions.
48+
* ``irradiance.total_irrad`` now follows the variable conventions.
49+
(:issue:`105`)
50+
* Fixed the metadata key specification in documentation of the
51+
readtmy2 function.
52+
2353

2454
Contributors
2555
~~~~~~~~~~~~

pvlib/atmosphere.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111

1212
import numpy as np
1313

14-
AIRMASS_MODELS = ['kastenyoung1989', 'kasten1966', 'simple',
15-
'pickering2002', 'youngirvine1967', 'young1994',
16-
'gueymard1993']
17-
14+
APPARENT_ZENITH_MODELS = ('simple', 'kasten1966', 'kastenyoung1989',
15+
'gueymard1993', 'pickering2002')
16+
TRUE_ZENITH_MODELS = ('youngirvine1967', 'young1994')
17+
AIRMASS_MODELS = APPARENT_ZENITH_MODELS + TRUE_ZENITH_MODELS
18+
1819

1920
def pres2alt(pressure):
2021
'''
@@ -143,12 +144,12 @@ def absoluteairmass(airmass_relative, pressure=101325.):
143144

144145
def relativeairmass(zenith, model='kastenyoung1989'):
145146
'''
146-
Gives the relative (not pressure-corrected) airmass
147+
Gives the relative (not pressure-corrected) airmass.
147148
148-
Gives the airmass at sea-level when given a sun zenith angle, z (in
149-
degrees).
150-
The "model" variable allows selection of different airmass models
151-
(described below). "model" must be a valid string. If "model" is not
149+
Gives the airmass at sea-level when given a sun zenith angle
150+
(in degrees).
151+
The ``model`` variable allows selection of different airmass models
152+
(described below). If ``model`` is not
152153
included or is not valid, the default model is 'kastenyoung1989'.
153154
154155
Parameters

0 commit comments

Comments
 (0)