Skip to content

Commit d7d27b7

Browse files
committed
Merge remote-tracking branch 'pvlib/master' into singleaxisarray
2 parents 07e47ec + b666520 commit d7d27b7

File tree

10 files changed

+618
-285
lines changed

10 files changed

+618
-285
lines changed

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
@@ -629,8 +630,8 @@ ModelChain model definitions.
629630
modelchain.ModelChain.desoto
630631
modelchain.ModelChain.pvsyst
631632
modelchain.ModelChain.pvwatts_dc
632-
modelchain.ModelChain.snlinverter
633-
modelchain.ModelChain.adrinverter
633+
modelchain.ModelChain.sandia_inverter
634+
modelchain.ModelChain.adr_inverter
634635
modelchain.ModelChain.pvwatts_inverter
635636
modelchain.ModelChain.ashrae_aoi_loss
636637
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: 15 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
~~~~~~~~~~~~
@@ -76,9 +80,9 @@ Enhancements
7680
* Support for :py:func:`~pvlib.inverter.sandia_multi` and
7781
:py:func:`~pvlib.inverter.pvwatts_multi` added to
7882
:py:class:`~pvlib.pvsystem.PVSystem` and
79-
:py:class:`~pvlib.modelchain.ModelChain` (as ``ac_model='sandia_multi'``
80-
and ``ac_model='pvwatts_multi'``).
81-
(:pull:`1076`, :issue:`1067`, :pull:`1132`, :issue:`1117`)
83+
:py:class:`~pvlib.modelchain.ModelChain` (as ``ac_model='sandia'``
84+
and ``ac_model='pvwatts'``).
85+
(:pull:`1076`, :issue:`1067`, :pull:`1132`, :issue:`1117`, :pull:`1150`)
8286
* :py:class:`~pvlib.modelchain.ModelChain` 'run_model' methods now
8387
automatically switch to using ``'effective_irradiance'`` (if available) for
8488
cell temperature models, when ``'poa_global'`` is not provided in input
@@ -87,19 +91,26 @@ Enhancements
8791
by ``pvsystem.PVSystem.modules_per_strings`` and
8892
``pvsystem.PVSystem.strings_per_inverter``. Note that both attributes still
8993
default to 1. (:pull:`1138`)
94+
* :py:meth:`~pvlib.pvsystem.PVSystem.get_ac` is added to calculate AC power
95+
from DC power. Use parameter ``model`` to specify which inverter model to use.
96+
(:pull:`1147`, :issue:`998`, :pull:`1150`)
9097

9198
Bug fixes
9299
~~~~~~~~~
93100
* Pass weather data to solar position calculations in
94101
:ref:meth:`~pvlib.modelchain.ModelChain.prepare_inputs_from_poa`.
95102
(:issue:`1065`, :pull:`1140`)
96-
103+
* Reindl model fixed to generate sky_diffuse=0 when GHI=0.
104+
(:issue:`1153`, :pull:`1154`)
97105
Testing
98106
~~~~~~~
99107

100108
Documentation
101109
~~~~~~~~~~~~~
102110

111+
* Update intro tutorial to highlight the use of historical meteorological data
112+
and to make the procedural and OO results match exactly.
113+
103114
Requirements
104115
~~~~~~~~~~~~
105116
* ``dataclasses`` is required for python 3.6

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)