Skip to content

Commit 74df8b6

Browse files
cwhansewholmgren
andauthored
Convert irradiance.liujordan to irradiance.campbell_norman (#1104)
* initial campbellnormal * formatting, add deprecation test * review * format * traceable deprecation * api.rst * change to campbell_normal in forecast.py * remove stub for deprecation test in forecast.py * remove unused import * Update docs/sphinx/source/api.rst correct misspelling Co-authored-by: Will Holmgren <[email protected]> Co-authored-by: Will Holmgren <[email protected]>
1 parent 6e5148f commit 74df8b6

File tree

6 files changed

+143
-14
lines changed

6 files changed

+143
-14
lines changed

docs/sphinx/source/api.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ DNI estimation models
181181
irradiance.dirint
182182
irradiance.dirindex
183183
irradiance.erbs
184-
irradiance.liujordan
184+
irradiance.campbell_norman
185185
irradiance.gti_dirint
186186

187187
Clearness index models
@@ -520,7 +520,7 @@ Processing data
520520
forecast.ForecastModel.cloud_cover_to_ghi_linear
521521
forecast.ForecastModel.cloud_cover_to_irradiance_clearsky_scaling
522522
forecast.ForecastModel.cloud_cover_to_transmittance_linear
523-
forecast.ForecastModel.cloud_cover_to_irradiance_liujordan
523+
forecast.ForecastModel.cloud_cover_to_irradiance_campbell_norman
524524
forecast.ForecastModel.cloud_cover_to_irradiance
525525
forecast.ForecastModel.kelvin_to_celsius
526526
forecast.ForecastModel.isobaric_to_ambient_temperature

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Breaking changes
99

1010
Deprecations
1111
~~~~~~~~~~~~
12-
12+
* ``pvlib.irradiance.liujordan`` is deprecated.
1313

1414
Enhancements
1515
~~~~~~~~~~~~
@@ -21,6 +21,12 @@ Enhancements
2121
multiple MPPTs (:issue:`457`, :pull:`1085`)
2222
* Added optional ``attributes`` parameter to :py:func:`pvlib.iotools.get_psm3`
2323
and added the option of fetching 5- and 15-minute PSM3 data. (:pull:`1086`)
24+
* Added :py:func:`pvlib.irradiance.campbell_norman` for estimating DNI, DHI and GHI
25+
from extraterrestrial irradiance. This function replaces ``pvlib.irradiance.liujordan``;
26+
users of ``pvlib.irradiance.liujordan`` should note that :py:func:`pvlib.irradiance.campbell_norman`
27+
expects different parameters.
28+
* :py:meth:`pvlib.forecast.Forecast.cloud_cover_to_irradiance_campbell_norman`
29+
replaces ``pvlib.forecast.Forecast.cloud_cover_to_irradiance_liujordan``.
2430

2531
Bug fixes
2632
~~~~~~~~~

pvlib/forecast.py

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@
99
from xml.etree.ElementTree import ParseError
1010

1111
from pvlib.location import Location
12-
from pvlib.irradiance import liujordan, get_extra_radiation, disc
12+
from pvlib.irradiance import campbell_norman, get_extra_radiation, disc
13+
from pvlib.irradiance import _liujordan
1314
from siphon.catalog import TDSCatalog
1415
from siphon.ncss import NCSS
1516

1617
import warnings
18+
from pvlib._deprecation import deprecated
19+
1720

1821
warnings.warn(
1922
'The forecast module algorithms and features are highly experimental. '
@@ -526,8 +529,48 @@ def cloud_cover_to_transmittance_linear(self, cloud_cover, offset=0.75,
526529

527530
return transmittance
528531

532+
def cloud_cover_to_irradiance_campbell_norman(self, cloud_cover, **kwargs):
533+
"""
534+
Estimates irradiance from cloud cover in the following steps:
535+
536+
1. Determine transmittance using a function of cloud cover e.g.
537+
:py:meth:`~ForecastModel.cloud_cover_to_transmittance_linear`
538+
2. Calculate GHI, DNI, DHI using the
539+
:py:func:`pvlib.irradiance.campbell_norman` model
540+
541+
Parameters
542+
----------
543+
cloud_cover : Series
544+
545+
Returns
546+
-------
547+
irradiance : DataFrame
548+
Columns include ghi, dni, dhi
549+
"""
550+
# in principle, get_solarposition could use the forecast
551+
# pressure, temp, etc., but the cloud cover forecast is not
552+
# accurate enough to justify using these minor corrections
553+
solar_position = self.location.get_solarposition(cloud_cover.index)
554+
dni_extra = get_extra_radiation(cloud_cover.index)
555+
556+
transmittance = self.cloud_cover_to_transmittance_linear(cloud_cover,
557+
**kwargs)
558+
559+
irrads = campbell_norman(solar_position['apparent_zenith'],
560+
transmittance, dni_extra=dni_extra)
561+
irrads = irrads.fillna(0)
562+
563+
return irrads
564+
565+
@deprecated(
566+
'0.8',
567+
alternative='Forecast.cloud_cover_to_irradiance_campbell_norman',
568+
name='Forecast.cloud_cover_to_irradiance_liujordan',
569+
removal='0.9')
529570
def cloud_cover_to_irradiance_liujordan(self, cloud_cover, **kwargs):
530571
"""
572+
Deprecated. Use cloud_cover_to_irradiance_campbell_norman instead.
573+
531574
Estimates irradiance from cloud cover in the following steps:
532575
533576
1. Determine transmittance using a function of cloud cover e.g.
@@ -554,9 +597,9 @@ def cloud_cover_to_irradiance_liujordan(self, cloud_cover, **kwargs):
554597
transmittance = self.cloud_cover_to_transmittance_linear(cloud_cover,
555598
**kwargs)
556599

557-
irrads = liujordan(solar_position['apparent_zenith'],
558-
transmittance, airmass['airmass_absolute'],
559-
dni_extra=dni_extra)
600+
irrads = _liujordan(solar_position['apparent_zenith'],
601+
transmittance, airmass['airmass_absolute'],
602+
dni_extra=dni_extra)
560603
irrads = irrads.fillna(0)
561604

562605
return irrads
@@ -571,7 +614,8 @@ def cloud_cover_to_irradiance(self, cloud_cover, how='clearsky_scaling',
571614
cloud_cover : Series
572615
how : str, default 'clearsky_scaling'
573616
Selects the method for conversion. Can be one of
574-
clearsky_scaling or liujordan.
617+
clearsky_scaling or campbell_norman. Method liujordan is
618+
deprecated.
575619
**kwargs
576620
Passed to the selected method.
577621
@@ -585,6 +629,9 @@ def cloud_cover_to_irradiance(self, cloud_cover, how='clearsky_scaling',
585629
if how == 'clearsky_scaling':
586630
irrads = self.cloud_cover_to_irradiance_clearsky_scaling(
587631
cloud_cover, **kwargs)
632+
elif how == 'campbell_norman':
633+
irrads = self.cloud_cover_to_irradiance_campbell_norman(
634+
cloud_cover, **kwargs)
588635
elif how == 'liujordan':
589636
irrads = self.cloud_cover_to_irradiance_liujordan(
590637
cloud_cover, **kwargs)

pvlib/irradiance.py

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414
from pvlib import atmosphere, solarposition, tools
1515

16+
from pvlib._deprecation import deprecated
17+
18+
1619
# see References section of grounddiffuse function
1720
SURFACE_ALBEDOS = {'urban': 0.18,
1821
'grass': 0.20,
@@ -2184,7 +2187,61 @@ def erbs(ghi, zenith, datetime_or_doy, min_cos_zenith=0.065, max_zenith=87):
21842187
return data
21852188

21862189

2187-
def liujordan(zenith, transmittance, airmass, dni_extra=1367.0):
2190+
def campbell_norman(zenith, transmittance, pressure=101325.0,
2191+
dni_extra=1367.0):
2192+
'''
2193+
Determine DNI, DHI, GHI from extraterrestrial flux, transmittance,
2194+
and atmospheric pressure.
2195+
2196+
Parameters
2197+
----------
2198+
zenith: pd.Series
2199+
True (not refraction-corrected) zenith angles in decimal
2200+
degrees. If Z is a vector it must be of the same size as all
2201+
other vector inputs. Z must be >=0 and <=180.
2202+
2203+
transmittance: float
2204+
Atmospheric transmittance between 0 and 1.
2205+
2206+
pressure: float, default 101325.0
2207+
Air pressure
2208+
2209+
dni_extra: float, default 1367.0
2210+
Direct irradiance incident at the top of the atmosphere.
2211+
2212+
Returns
2213+
-------
2214+
irradiance: DataFrame
2215+
Modeled direct normal irradiance, direct horizontal irradiance,
2216+
and global horizontal irradiance in W/m^2
2217+
2218+
References
2219+
----------
2220+
.. [1] Campbell, G. S., J. M. Norman (1998) An Introduction to
2221+
Environmental Biophysics. 2nd Ed. New York: Springer.
2222+
'''
2223+
2224+
tau = transmittance
2225+
2226+
airmass = atmosphere.get_relative_airmass(zenith, model='simple')
2227+
airmass = atmosphere.get_absolute_airmass(airmass, pressure=pressure)
2228+
dni = dni_extra*tau**airmass
2229+
cos_zen = tools.cosd(zenith)
2230+
dhi = 0.3 * (1.0 - tau**airmass) * dni_extra * cos_zen
2231+
ghi = dhi + dni * cos_zen
2232+
2233+
irrads = OrderedDict()
2234+
irrads['ghi'] = ghi
2235+
irrads['dni'] = dni
2236+
irrads['dhi'] = dhi
2237+
2238+
if isinstance(ghi, pd.Series):
2239+
irrads = pd.DataFrame(irrads)
2240+
2241+
return irrads
2242+
2243+
2244+
def _liujordan(zenith, transmittance, airmass, dni_extra=1367.0):
21882245
'''
21892246
Determine DNI, DHI, GHI from extraterrestrial flux, transmittance,
21902247
and optical air mass number.
@@ -2242,6 +2299,10 @@ def liujordan(zenith, transmittance, airmass, dni_extra=1367.0):
22422299
return irrads
22432300

22442301

2302+
liujordan = deprecated('0.8', alternative='campbellnormam',
2303+
name='liujordan', removal='0.9')(_liujordan)
2304+
2305+
22452306
def _get_perez_coefficients(perezmodel):
22462307
'''
22472308
Find coefficients for the Perez model

pvlib/tests/test_forecast.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
requires_siphon,
1111
has_siphon,
1212
skip_windows,
13-
requires_recent_cftime,
13+
requires_recent_cftime
1414
)
1515
from conftest import RERUNS, RERUNS_DELAY
1616

@@ -69,7 +69,7 @@ def model(request):
6969
@pytest.mark.remote_data
7070
@pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
7171
def test_process_data(model):
72-
for how in ['liujordan', 'clearsky_scaling']:
72+
for how in ['campbell_norman', 'clearsky_scaling']:
7373
if model.raw_data.empty:
7474
warnings.warn('Could not test {} process_data with how={} '
7575
'because raw_data was empty'.format(model, how))

pvlib/tests/test_irradiance.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313

1414
from pvlib import irradiance
1515

16-
from conftest import requires_ephem, requires_numba
16+
from conftest import requires_ephem, requires_numba, fail_on_pvlib_version
17+
from pvlib._deprecation import pvlibDeprecationWarning
1718

1819

1920
# fixtures create realistic test input data
@@ -285,13 +286,27 @@ def test_get_sky_diffuse_invalid():
285286
model='invalid')
286287

287288

289+
@fail_on_pvlib_version('0.9')
288290
def test_liujordan():
289291
expected = pd.DataFrame(np.array(
290292
[[863.859736967, 653.123094076, 220.65905025]]),
291293
columns=['ghi', 'dni', 'dhi'],
292294
index=[0])
293-
out = irradiance.liujordan(
294-
pd.Series([10]), pd.Series([0.5]), pd.Series([1.1]), dni_extra=1400)
295+
with pytest.warns(pvlibDeprecationWarning):
296+
out = irradiance.liujordan(
297+
pd.Series([10]), pd.Series([0.5]), pd.Series([1.1]),
298+
dni_extra=1400)
299+
assert_frame_equal(out, expected)
300+
301+
302+
def test_campbell_norman():
303+
expected = pd.DataFrame(np.array(
304+
[[863.859736967, 653.123094076, 220.65905025]]),
305+
columns=['ghi', 'dni', 'dhi'],
306+
index=[0])
307+
out = irradiance.campbell_norman(
308+
pd.Series([10]), pd.Series([0.5]), pd.Series([109764.21013135818]),
309+
dni_extra=1400)
295310
assert_frame_equal(out, expected)
296311

297312

0 commit comments

Comments
 (0)