Skip to content

Add PVSystem pvsyst_celltemp methods #636

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jan 17, 2019
3 changes: 3 additions & 0 deletions docs/sphinx/source/whatsnew/v0.6.1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Enhancements
* Add option for :py:func:`pvlib.irradiance.disc` to use relative airmass
by supplying `pressure=None`. (:issue:`449`)
* Created :py:func:`pvlib.pvsystem.pvsyst_celltemp` to implement PVsyst's cell temperature model. (:issue:`552`)
* Add `PVSystem` class method :py:func:`~pvlib.pvsystem.PVSystem.pvsyst_celltemp` (:issue:`633`)


Bug fixes
Expand All @@ -73,6 +74,8 @@ Bug fixes
* Fix documentation errors when using IPython >= 7.0.
* Fix error in :func:`pvlib.modelchain.ModelChain.infer_spectral_model` (:issue:`619`)
* Fix error in ``pvlib.spa`` when using Python 3.7 on some platforms.
* Fix error in :func:`pvlib.irradiance._delta_kt_prime_dirint` (:issue:`637`). The error affects
the first and last values of DNI calculated by the function :func:`pvlib.irradiance.dirint`


Testing
Expand Down
14 changes: 10 additions & 4 deletions pvlib/irradiance.py
Original file line number Diff line number Diff line change
Expand Up @@ -1558,14 +1558,20 @@ def _dirint_from_dni_ktprime(dni, kt_prime, solar_zenith, use_delta_kt_prime,

def _delta_kt_prime_dirint(kt_prime, use_delta_kt_prime, times):
"""
Calculate delta kt prime (Perez eqn 2), or return a default value
Calculate delta_kt_prime (Perez eqn 2 and eqn 3), or return a default value
for use with :py:func:`_dirint_bins`.
"""
if use_delta_kt_prime:
# Perez eqn 2
delta_kt_prime = 0.5*((kt_prime - kt_prime.shift(1)).abs().add(
(kt_prime - kt_prime.shift(-1)).abs(),
fill_value=0))
kt_next = kt_prime.shift(-1)
kt_previous = kt_prime.shift(1)
# replace nan with values that implement Perez Eq 3 for first and last
# positions. Use kt_previous and kt_next to handle series of length 1
kt_next.iloc[-1] = kt_previous.iloc[-1]
kt_previous.iloc[0] = kt_next.iloc[0]
delta_kt_prime = 0.5 * ((kt_prime - kt_next).abs().add(
(kt_prime - kt_previous).abs(),
fill_value=0))
else:
# do not change unless also modifying _dirint_bins
delta_kt_prime = pd.Series(-1, index=times)
Expand Down
41 changes: 31 additions & 10 deletions pvlib/pvsystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@
}


TEMP_MODELS = {
'sapm': {'open_rack_cell_glassback': (-3.47, -.0594, 3),
'roof_mount_cell_glassback': (-2.98, -.0471, 1),
'open_rack_cell_polymerback': (-3.56, -.0750, 3),
'insulated_back_polymerback': (-2.81, -.0455, 0),
'open_rack_polymer_thinfilm_steel': (-3.58, -.113, 3),
'22x_concentrator_tracker': (-3.23, -.130, 13)},
'pvsyst': {'freestanding': (29.0, 0), 'insulated': (15.0, 0)}
}

# not sure if this belongs in the pvsystem module.
# maybe something more like core.py? It may eventually grow to
# import a lot more functionality from other modules.
Expand Down Expand Up @@ -511,6 +521,23 @@ def sapm_effective_irradiance(self, poa_direct, poa_diffuse,
poa_direct, poa_diffuse, airmass_absolute, aoi,
self.module_parameters, reference_irradiance=reference_irradiance)

def pvsyst_celltemp(self, poa_global, wind_speed, temp_air):
"""Uses :py:func:`pvsyst_celltemp` to calculate module temperatures
based on ``self.racking_model`` and the input parameters.

Parameters
----------
See pvsystem.pvsyst_celltemp for details

Returns
-------
See pvsystem.pvsyst_celltemp for details
"""
kwargs = _build_kwargs(['eta_m', 'alpha_absorption'],
self.module_parameters)
return pvsyst_celltemp(poa_global, wind_speed, temp_air,
temp_model=self.racking_model, **kwargs)

def first_solar_spectral_loss(self, pw, airmass_absolute):

"""
Expand Down Expand Up @@ -1860,13 +1887,7 @@ def sapm_celltemp(poa_global, wind_speed, temp_air,
sapm
'''

temp_models = {'open_rack_cell_glassback': [-3.47, -.0594, 3],
'roof_mount_cell_glassback': [-2.98, -.0471, 1],
'open_rack_cell_polymerback': [-3.56, -.0750, 3],
'insulated_back_polymerback': [-2.81, -.0455, 0],
'open_rack_polymer_thinfilm_steel': [-3.58, -.113, 3],
'22x_concentrator_tracker': [-3.23, -.130, 13]
}
temp_models = TEMP_MODELS['sapm']

if isinstance(model, str):
model = temp_models[model.lower()]
Expand All @@ -1880,9 +1901,9 @@ def sapm_celltemp(poa_global, wind_speed, temp_air,

E0 = 1000. # Reference irradiance

temp_module = pd.Series(poa_global*np.exp(a + b*wind_speed) + temp_air)
temp_module = pd.Series(poa_global * np.exp(a + b * wind_speed) + temp_air)

temp_cell = temp_module + (poa_global / E0)*(deltaT)
temp_cell = temp_module + (poa_global / E0) * (deltaT)

return pd.DataFrame({'temp_cell': temp_cell, 'temp_module': temp_module})

Expand Down Expand Up @@ -1944,7 +1965,7 @@ def pvsyst_celltemp(poa_global, wind_speed, temp_air, eta_m=0.1,
photovoltaic modules." Progress in Photovoltaics 16(4): 307-315.
"""

temp_models = {"freestanding": (29.0, 0), "insulated": (15.0, 0)}
temp_models = TEMP_MODELS['pvsyst']

if isinstance(temp_model, str):
natural_convenction_coeff, forced_convection_coeff = temp_models[
Expand Down
18 changes: 9 additions & 9 deletions pvlib/test/test_irradiance.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,13 +466,13 @@ def test_dirint_value():
pressure = 93193.
dirint_data = irradiance.dirint(ghi, zenith, times, pressure=pressure)
assert_almost_equal(dirint_data.values,
np.array([ 888. , 683.7]), 1)
np.array([868.8, 699.7]), 1)


def test_dirint_nans():
times = pd.DatetimeIndex(start='2014-06-24T12-0700', periods=5, freq='6H')
ghi = pd.Series([np.nan, 1038.62, 1038.62, 1038.62, 1038.62], index=times)
zenith = pd.Series([10.567, np.nan, 10.567, 10.567, 10.567,], index=times)
zenith = pd.Series([10.567, np.nan, 10.567, 10.567, 10.567], index=times)
pressure = pd.Series([93193., 93193., np.nan, 93193., 93193.], index=times)
temp_dew = pd.Series([10, 10, 10, np.nan, 10], index=times)
dirint_data = irradiance.dirint(ghi, zenith, times, pressure=pressure,
Expand All @@ -489,7 +489,7 @@ def test_dirint_tdew():
dirint_data = irradiance.dirint(ghi, zenith, times, pressure=pressure,
temp_dew=10)
assert_almost_equal(dirint_data.values,
np.array([892.9, 636.5]), 1)
np.array([882.1, 672.6]), 1)


def test_dirint_no_delta_kt():
Expand Down Expand Up @@ -559,7 +559,7 @@ def test_gti_dirint():
expected = pd.DataFrame(array(
[[ 21.05796198, 0. , 21.05796198],
[ 288.22574368, 60.59964218, 245.37532576],
[ 930.85454521, 695.8504884 , 276.96897609]]),
[ 931.04078010, 695.94965324, 277.06172442]]),
columns=expected_col_order, index=times)

assert_frame_equal(output, expected)
Expand All @@ -583,7 +583,7 @@ def test_gti_dirint():
expected = pd.DataFrame(array(
[[ 21.05796198, 0. , 21.05796198],
[ 289.81109139, 60.52460392, 247.01373353],
[ 932.22047435, 647.68716072, 323.59362885]]),
[ 932.46756378, 648.05001357, 323.49974813]]),
columns=expected_col_order, index=times)

assert_frame_equal(output, expected)
Expand All @@ -595,9 +595,9 @@ def test_gti_dirint():
albedo=albedo)

expected = pd.DataFrame(array(
[[ 21.3592591 , 0. , 21.3592591 ],
[ 292.5162373 , 64.42628826, 246.95997198],
[ 941.47847463, 727.07261187, 258.25370648]]),
[[ 21.3592591, 0. , 21.3592591 ],
[ 292.5162373, 64.42628826, 246.95997198],
[ 941.6753031, 727.16311901, 258.36548605]]),
columns=expected_col_order, index=times)

assert_frame_equal(output, expected)
Expand All @@ -611,7 +611,7 @@ def test_gti_dirint():
expected = pd.DataFrame(array(
[[ 21.05796198, 0. , 21.05796198],
[ 292.40468994, 36.79559287, 266.3862767 ],
[ 930.72198876, 712.36063132, 261.32196017]]),
[ 931.79627208, 689.81549269, 283.5817439]]),
columns=expected_col_order, index=times)

assert_frame_equal(output, expected)
Expand Down
20 changes: 20 additions & 0 deletions pvlib/test/test_pvsystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,26 @@ def test_pvsyst_celltemp_with_index():
assert_series_equal(expected, pvtemps)


def test_PVSystem_pvsyst_celltemp(mocker):
racking_model = 'insulated'
alpha_absorption = 0.85
eta_m = 0.17
module_parameters = {}
module_parameters['alpha_absorption'] = alpha_absorption
module_parameters['eta_m'] = eta_m
system = pvsystem.PVSystem(racking_model=racking_model,
module_parameters=module_parameters)
mocker.spy(pvsystem, 'pvsyst_celltemp')
irrad = 800
temp = 45
wind = 0.5
out = system.pvsyst_celltemp(irrad, wind, temp)
pvsystem.pvsyst_celltemp.assert_called_once_with(
irrad, wind, temp, eta_m, alpha_absorption, racking_model)
assert isinstance(out, float)
assert out < 90 and out > 70


def test_adrinverter(sam_data):
inverters = sam_data['adrinverter']
testinv = 'Ablerex_Electronics_Co___Ltd___' \
Expand Down