Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions docs/source/refraction.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,25 @@
Refraction correction algorithms
================================

Methods of calculating the effect of atmospheric refraction on solar elevation.
Methods for calculating the effect of atmospheric refraction on solar elevation.
Some methods account for secondary effects from temperature and pressure.

The following refraction correction algorithms estimate refraction from the
true solar (unrefracted) elevation angle:

.. autosummary::
:toctree: generated/

refraction.archer
refraction.bennett
refraction.hughes
refraction.michalsky
refraction.sg2
refraction.spa

The following refraction correction algorithm calculates refraction from the
apparent (refracted) solar elevation:

.. autosummary::
:toctree: generated/

refraction.bennett
8 changes: 8 additions & 0 deletions docs/source/whatsnew.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0
1.0.2 - upcoming
----------------

Bug fix
^^^^^^^
* Change the input parameter ``elevation`` to ``apparent_elevation`` in
:py:func:`solposx.refraction.bennett`, reflecting that Bennett's
refraction correction is calculated from apparent elevation.
(:pull:`166`)

Changed
^^^^^^^
* matplotlib is now an optional ``doc`` dependency instead of a required
Expand All @@ -26,6 +33,7 @@ Testing
* The test values for the skyfield solar position function were updated to
match skyfield version 1.54. (:issue:`148`, :pull:`150`)


1.0.1 - 2025-11-09
-------------------

Expand Down
23 changes: 15 additions & 8 deletions src/solposx/refraction/bennett.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@
from pvlib.tools import tand


def bennett(elevation, pressure=101325.0, temperature=12.0):
def bennett(apparent_elevation, pressure=101325.0, temperature=12.0):
Comment thread
AdamRJensen marked this conversation as resolved.
Resolved
r"""
Atmospheric refraction correction based on the Bennett algorithm.

Calculation of atmospheric refraction correction of the solar
elevation angle using the method developed by Bennett [1]_.
Calculation of atmospheric refraction correction based on the
apparent solar elevation angle using the method developed by
Bennett [1]_.

Parameters
----------
elevation : array-like
True solar elevation angle (not accounting for refraction). [degrees]
apparent_elevation : array-like
Apparent solar elevation angle (accounting for refraction). [degrees]
pressure : numeric, default 101325
Annual average atmospheric pressure. [Pascal]
temperature : numeric, default 12
Expand All @@ -24,16 +25,22 @@ def bennett(elevation, pressure=101325.0, temperature=12.0):
np.array or pd.Series
Atmospheric refraction angle. [degrees]

Warning
-------
The Bennet refraction algorithm calculates refraction from the apparent
solar elevation angle, in contrast to most refraction algorithms, which
calculate refraction from the unrefracted true solar elevation angle.

Notes
-----
The equation to calculate the refraction correction is given by:

.. math::

ref = \frac{0.28*P}{T+273} \cdot \frac{0.016667}{\text{tan}(el + 7.31 / (el+4.4))}
ref = \frac{0.28*P}{T+273} \cdot \frac{0.016667}{\text{tan}(el_a + 7.31 / (el_a+4.4))}

where :math:`P` is the local air pressure, :math:`T` is the local air
temperature, and :math:`el` is the true (uncorrected) solar elevation angle.
temperature, and :math:`el_a` is the apparent (corrected) solar elevation angle.

References
----------
Expand All @@ -44,7 +51,7 @@ def bennett(elevation, pressure=101325.0, temperature=12.0):

pressure = pressure / 100 # convert to hPa

r = 0.016667 / tand(elevation + 7.31 / (elevation + 4.4))
r = 0.016667 / tand(apparent_elevation + 7.31 / (apparent_elevation + 4.4))

d = r * (0.28 * pressure / (temperature + 273.0))

Expand Down
5 changes: 3 additions & 2 deletions tests/test_refraction.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def expected_spa():

@pytest.mark.parametrize('algorithm,expected,kwargs', [
(archer, expected_archer, {}),
# For the Bennet algorithm, the input is apparent elevation
(bennett, expected_bennett, {}),
(bennett, expected_bennett, {'pressure': 101325., 'temperature': 12.}),
(hughes, expected_hughes, {}),
Expand All @@ -71,14 +72,14 @@ def expected_spa():
])
def test_algorithm(algorithm, expected, kwargs, test_elevation_angles):
# numpy array input
result = algorithm(elevation=test_elevation_angles, **kwargs)
result = algorithm(test_elevation_angles, **kwargs)
np.testing.assert_almost_equal(expected(), result)

# pandas series input
series_index = pd.date_range('2020-01-01', periods=len(test_elevation_angles), freq='1h')
test_elevation_angles_series = pd.Series(test_elevation_angles, index=series_index)
expected_series = pd.Series(expected(), index=series_index)
result_series = algorithm(elevation=test_elevation_angles_series, **kwargs)
result_series = algorithm(test_elevation_angles_series, **kwargs)
pd.testing.assert_series_equal(expected_series, result_series)


Expand Down
Loading