Skip to content

Commit 45035ef

Browse files
committed
Merge remote-tracking branch 'upstream/master'
2 parents 4db55be + 8b98768 commit 45035ef

File tree

12 files changed

+625
-288
lines changed

12 files changed

+625
-288
lines changed

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
BSD 3-Clause License
22

3-
Copyright (c) 2013-2020, Sandia National Laboratories and pvlib python Development Team
3+
Copyright (c) 2013-2021, Sandia National Laboratories and pvlib python Development Team
44
All rights reserved.
55

66
Redistribution and use in source and binary forms, with or without modification,

docs/sphinx/source/api.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ Inverter models (DC to AC conversion)
292292
.. autosummary::
293293
:toctree: generated/
294294

295+
pvsystem.PVSystem.get_ac
295296
inverter.sandia
296297
inverter.sandia_multi
297298
inverter.adr
@@ -630,8 +631,8 @@ ModelChain model definitions.
630631
modelchain.ModelChain.desoto
631632
modelchain.ModelChain.pvsyst
632633
modelchain.ModelChain.pvwatts_dc
633-
modelchain.ModelChain.snlinverter
634-
modelchain.ModelChain.adrinverter
634+
modelchain.ModelChain.sandia_inverter
635+
modelchain.ModelChain.adr_inverter
635636
modelchain.ModelChain.pvwatts_inverter
636637
modelchain.ModelChain.ashrae_aoi_loss
637638
modelchain.ModelChain.physical_aoi_loss

docs/sphinx/source/introtutorial.rst

Lines changed: 97 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,17 @@ configuration at a handful of sites listed below.
2727

2828
.. ipython:: python
2929
30+
import pvlib
3031
import pandas as pd
3132
import matplotlib.pyplot as plt
3233
33-
naive_times = pd.date_range(start='2015', end='2016', freq='1h')
34-
35-
# very approximate
3634
# latitude, longitude, name, altitude, timezone
37-
coordinates = [(30, -110, 'Tucson', 700, 'Etc/GMT+7'),
38-
(35, -105, 'Albuquerque', 1500, 'Etc/GMT+7'),
39-
(40, -120, 'San Francisco', 10, 'Etc/GMT+8'),
40-
(50, 10, 'Berlin', 34, 'Etc/GMT-1')]
41-
42-
import pvlib
35+
coordinates = [
36+
(32.2, -111.0, 'Tucson', 700, 'Etc/GMT+7'),
37+
(35.1, -106.6, 'Albuquerque', 1500, 'Etc/GMT+7'),
38+
(37.8, -122.4, 'San Francisco', 10, 'Etc/GMT+8'),
39+
(52.5, 13.4, 'Berlin', 34, 'Etc/GMT-1'),
40+
]
4341
4442
# get the module and inverter specifications from SAM
4543
sandia_modules = pvlib.pvsystem.retrieve_sam('SandiaMod')
@@ -48,9 +46,32 @@ configuration at a handful of sites listed below.
4846
inverter = sapm_inverters['ABB__MICRO_0_25_I_OUTD_US_208__208V_']
4947
temperature_model_parameters = pvlib.temperature.TEMPERATURE_MODEL_PARAMETERS['sapm']['open_rack_glass_glass']
5048
51-
# specify constant ambient air temp and wind for simplicity
52-
temp_air = 20
53-
wind_speed = 0
49+
50+
In order to retrieve meteorological data for the simulation, we can make use of
51+
the :ref:`iotools` module. In this example we will be using PVGIS, one of the
52+
data sources available, to retrieve a Typical Meteorological Year (TMY) which
53+
includes irradiation, temperature and wind speed.
54+
55+
.. note:: PVGIS uses different naming conventions, so it is required to rename
56+
the weather data variables before using them. Data is already UTC-localized,
57+
so conversion to local timezone is optional.
58+
59+
.. ipython:: python
60+
61+
variables_translation = {
62+
"Gb(n)": "dni",
63+
"G(h)": "ghi",
64+
"Gd(h)": "dhi",
65+
"T2m": "temp_air",
66+
"WS10m": "wind_speed",
67+
}
68+
tmys = []
69+
for location in coordinates:
70+
latitude, longitude, name, altitude, timezone = location
71+
weather = pvlib.iotools.get_pvgis_tmy(latitude, longitude)[0]
72+
weather = weather.rename(columns=variables_translation)
73+
weather.index.name = "utc_time"
74+
tmys.append(weather)
5475
5576
5677
Procedural
@@ -69,41 +90,60 @@ to accomplish our system modeling goal:
6990
7091
energies = {}
7192
72-
for latitude, longitude, name, altitude, timezone in coordinates:
73-
times = naive_times.tz_localize(timezone)
93+
for location, weather in zip(coordinates, tmys):
94+
latitude, longitude, name, altitude, timezone = location
7495
system['surface_tilt'] = latitude
75-
solpos = pvlib.solarposition.get_solarposition(times, latitude, longitude)
76-
dni_extra = pvlib.irradiance.get_extra_radiation(times)
96+
solpos = pvlib.solarposition.get_solarposition(
97+
time=weather.index,
98+
latitude=latitude,
99+
longitude=longitude,
100+
altitude=altitude,
101+
temperature=weather["temp_air"],
102+
pressure=pvlib.atmosphere.alt2pres(altitude),
103+
)
104+
dni_extra = pvlib.irradiance.get_extra_radiation(weather.index)
77105
airmass = pvlib.atmosphere.get_relative_airmass(solpos['apparent_zenith'])
78106
pressure = pvlib.atmosphere.alt2pres(altitude)
79107
am_abs = pvlib.atmosphere.get_absolute_airmass(airmass, pressure)
80-
tl = pvlib.clearsky.lookup_linke_turbidity(times, latitude, longitude)
81-
cs = pvlib.clearsky.ineichen(solpos['apparent_zenith'], am_abs, tl,
82-
dni_extra=dni_extra, altitude=altitude)
83-
aoi = pvlib.irradiance.aoi(system['surface_tilt'], system['surface_azimuth'],
84-
solpos['apparent_zenith'], solpos['azimuth'])
85-
total_irrad = pvlib.irradiance.get_total_irradiance(system['surface_tilt'],
86-
system['surface_azimuth'],
87-
solpos['apparent_zenith'],
88-
solpos['azimuth'],
89-
cs['dni'], cs['ghi'], cs['dhi'],
90-
dni_extra=dni_extra,
91-
model='haydavies')
92-
tcell = pvlib.temperature.sapm_cell(total_irrad['poa_global'],
93-
temp_air, wind_speed,
94-
**temperature_model_parameters)
108+
aoi = pvlib.irradiance.aoi(
109+
system['surface_tilt'],
110+
system['surface_azimuth'],
111+
solpos["apparent_zenith"],
112+
solpos["azimuth"],
113+
)
114+
total_irradiance = pvlib.irradiance.get_total_irradiance(
115+
system['surface_tilt'],
116+
system['surface_azimuth'],
117+
solpos['apparent_zenith'],
118+
solpos['azimuth'],
119+
weather['dni'],
120+
weather['ghi'],
121+
weather['dhi'],
122+
dni_extra=dni_extra,
123+
model='haydavies',
124+
)
125+
cell_temperature = pvlib.temperature.sapm_cell(
126+
total_irradiance['poa_global'],
127+
weather["temp_air"],
128+
weather["wind_speed"],
129+
**temperature_model_parameters,
130+
)
95131
effective_irradiance = pvlib.pvsystem.sapm_effective_irradiance(
96-
total_irrad['poa_direct'], total_irrad['poa_diffuse'],
97-
am_abs, aoi, module)
98-
dc = pvlib.pvsystem.sapm(effective_irradiance, tcell, module)
132+
total_irradiance['poa_direct'],
133+
total_irradiance['poa_diffuse'],
134+
am_abs,
135+
aoi,
136+
module,
137+
)
138+
dc = pvlib.pvsystem.sapm(effective_irradiance, cell_temperature, module)
99139
ac = pvlib.inverter.sandia(dc['v_mp'], dc['p_mp'], inverter)
100140
annual_energy = ac.sum()
101141
energies[name] = annual_energy
102142
103143
energies = pd.Series(energies)
104144
105145
# based on the parameters specified above, these are in W*hrs
106-
print(energies.round(0))
146+
print(energies)
107147
108148
energies.plot(kind='bar', rot=0)
109149
@savefig proc-energies.png width=6in
@@ -150,28 +190,35 @@ by examining the parameters defined for the module.
150190
from pvlib.location import Location
151191
from pvlib.modelchain import ModelChain
152192
153-
system = PVSystem(module_parameters=module,
154-
inverter_parameters=inverter,
155-
temperature_model_parameters=temperature_model_parameters)
193+
system = PVSystem(
194+
module_parameters=module,
195+
inverter_parameters=inverter,
196+
temperature_model_parameters=temperature_model_parameters,
197+
)
156198
157199
energies = {}
158-
for latitude, longitude, name, altitude, timezone in coordinates:
159-
times = naive_times.tz_localize(timezone)
160-
location = Location(latitude, longitude, name=name, altitude=altitude,
161-
tz=timezone)
162-
weather = location.get_clearsky(times)
163-
mc = ModelChain(system, location,
164-
orientation_strategy='south_at_latitude_tilt')
165-
# model results (ac, dc) and intermediates (aoi, temps, etc.)
166-
# assigned as mc object attributes
167-
mc.run_model(weather)
168-
annual_energy = mc.results.ac.sum()
200+
for location, weather in zip(coordinates, tmys):
201+
latitude, longitude, name, altitude, timezone = location
202+
location = Location(
203+
latitude,
204+
longitude,
205+
name=name,
206+
altitude=altitude,
207+
tz=timezone,
208+
)
209+
mc = ModelChain(
210+
system,
211+
location,
212+
orientation_strategy='south_at_latitude_tilt',
213+
)
214+
results = mc.run_model(weather)
215+
annual_energy = results.ac.sum()
169216
energies[name] = annual_energy
170217
171218
energies = pd.Series(energies)
172219
173220
# based on the parameters specified above, these are in W*hrs
174-
print(energies.round(0))
221+
print(energies)
175222
176223
energies.plot(kind='bar', rot=0)
177224
@savefig modelchain-energies.png width=6in

docs/sphinx/source/whatsnew/v0.9.0.rst

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ Breaking changes
3636
* ``irradiance.liujordan`` and ``ForecastModel.cloud_cover_to_irradiance_liujordan``
3737
have been removed. (:pull:`1136`)
3838

39+
* ``ModelChain.snlinverter`` changed to ``ModelChain.sandia_inverter``.
40+
``ModelChain.adrinverter`` changed to ``ModelChain.adr_inverter``.
41+
(:pull:`1150`)
42+
3943

4044
Deprecations
4145
~~~~~~~~~~~~
@@ -78,9 +82,9 @@ Enhancements
7882
* Support for :py:func:`~pvlib.inverter.sandia_multi` and
7983
:py:func:`~pvlib.inverter.pvwatts_multi` added to
8084
:py:class:`~pvlib.pvsystem.PVSystem` and
81-
:py:class:`~pvlib.modelchain.ModelChain` (as ``ac_model='sandia_multi'``
82-
and ``ac_model='pvwatts_multi'``).
83-
(:pull:`1076`, :issue:`1067`, :pull:`1132`, :issue:`1117`)
85+
:py:class:`~pvlib.modelchain.ModelChain` (as ``ac_model='sandia'``
86+
and ``ac_model='pvwatts'``).
87+
(:pull:`1076`, :issue:`1067`, :pull:`1132`, :issue:`1117`, :pull:`1150`)
8488
* :py:class:`~pvlib.modelchain.ModelChain` 'run_model' methods now
8589
automatically switch to using ``'effective_irradiance'`` (if available) for
8690
cell temperature models, when ``'poa_global'`` is not provided in input
@@ -89,19 +93,28 @@ Enhancements
8993
by ``pvsystem.PVSystem.modules_per_strings`` and
9094
``pvsystem.PVSystem.strings_per_inverter``. Note that both attributes still
9195
default to 1. (:pull:`1138`)
96+
* :py:meth:`~pvlib.pvsystem.PVSystem.get_ac` is added to calculate AC power
97+
from DC power. Use parameter ``model`` to specify which inverter model to use.
98+
(:pull:`1147`, :issue:`998`, :pull:`1150`)
9299

93100
Bug fixes
94101
~~~~~~~~~
95102
* Pass weather data to solar position calculations in
96-
:ref:meth:`~pvlib.modelchain.ModelChain.prepare_inputs_from_poa`.
103+
:py:meth:`~pvlib.modelchain.ModelChain.prepare_inputs_from_poa`.
97104
(:issue:`1065`, :pull:`1140`)
105+
* Reindl model fixed to generate sky_diffuse=0 when GHI=0.
106+
(:issue:`1153`, :pull:`1154`)
98107

99108
Testing
100109
~~~~~~~
101110

102111
Documentation
103112
~~~~~~~~~~~~~
104113

114+
* Update intro tutorial to highlight the use of historical meteorological data
115+
and to make the procedural and object oriented results match exactly.
116+
* Update documentation links in :py:func:`pvlib.iotools.get_psm3`
117+
105118
Requirements
106119
~~~~~~~~~~~~
107120
* ``dataclasses`` is required for python 3.6
@@ -116,3 +129,5 @@ Contributors
116129
* Nate Croft (:ghuser:`ncroft-b4`)
117130
* Kevin Anderson (:ghuser:`kanderso-nrel`)
118131
* Adam R. Jensen (:ghuser:`AdamRJensen`)
132+
* Joshua Stein (:ghuser:`jsstein`)
133+
* Tony Lorenzo (:ghuser:`alorenzo175`)

pvlib/iotools/psm3.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,9 @@ def get_psm3(latitude, longitude, api_key, email, names='tmy', interval=60,
112112
.. [1] `NREL National Solar Radiation Database (NSRDB)
113113
<https://nsrdb.nrel.gov/>`_
114114
.. [2] `Physical Solar Model (PSM) v3
115-
<https://developer.nrel.gov/docs/solar/nsrdb/psm3_data_download/>`_
115+
<https://developer.nrel.gov/docs/solar/nsrdb/psm3-download/>`_
116116
.. [3] `Physical Solar Model (PSM) v3 TMY
117-
<https://developer.nrel.gov/docs/solar/nsrdb/psm3_tmy_data_download/>`_
117+
<https://developer.nrel.gov/docs/solar/nsrdb/psm3-tmy-download/>`_
118118
.. [4] `Physical Solar Model (PSM) v3 - Five Minute Temporal Resolution
119119
<https://developer.nrel.gov/docs/solar/nsrdb/psm3-5min-download/>`_
120120
"""

pvlib/irradiance.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -886,8 +886,9 @@ def reindl(surface_tilt, surface_azimuth, dhi, dni, ghi, dni_extra,
886886
# these are the () and [] sub-terms of the second term of eqn 8
887887
term1 = 1 - AI
888888
term2 = 0.5 * (1 + tools.cosd(surface_tilt))
889-
term3 = 1 + np.sqrt(HB / ghi) * (tools.sind(0.5 * surface_tilt) ** 3)
890-
889+
with np.errstate(invalid='ignore', divide='ignore'):
890+
hb_to_ghi = np.where(ghi == 0, 0, np.divide(HB, ghi))
891+
term3 = 1 + np.sqrt(hb_to_ghi) * (tools.sind(0.5 * surface_tilt)**3)
891892
sky_diffuse = dhi * (AI * Rb + term1 * term2 * term3)
892893
sky_diffuse = np.maximum(sky_diffuse, 0)
893894

0 commit comments

Comments
 (0)