diff --git a/lib/cartopy/feature/nightshade.py b/lib/cartopy/feature/nightshade.py index b8a613474c..e5f24c5f80 100644 --- a/lib/cartopy/feature/nightshade.py +++ b/lib/cartopy/feature/nightshade.py @@ -77,8 +77,12 @@ def __init__(self, date=None, delta=0.1, refraction=-0.83, # Solve the generalized equation for omega0, which is the # angle of sunrise/sunset from solar noon - omega0 = np.rad2deg(np.arccos(np.sin(np.deg2rad(refraction)) / - np.cos(np.deg2rad(y)))) + # We need to clip the input to arccos to [-1, 1] due to floating + # point precision and arccos creating nans for values outside + # of the domain + arccos_tmp = np.clip(np.sin(np.deg2rad(refraction)) / + np.cos(np.deg2rad(y)), -1, 1) + omega0 = np.rad2deg(np.arccos(arccos_tmp)) # Fill the longitude values from the offset for midnight. # This needs to be a closed loop to fill the polygon. @@ -89,7 +93,6 @@ def __init__(self, date=None, delta=0.1, refraction=-0.83, kwargs.setdefault('facecolor', color) kwargs.setdefault('alpha', alpha) - geom = sgeom.Polygon(np.column_stack((x, y))) return super().__init__( [geom], rotated_pole, **kwargs) diff --git a/lib/cartopy/tests/feature/test_nightshade.py b/lib/cartopy/tests/feature/test_nightshade.py index 8764943df1..062f91eabc 100644 --- a/lib/cartopy/tests/feature/test_nightshade.py +++ b/lib/cartopy/tests/feature/test_nightshade.py @@ -8,7 +8,7 @@ import pytest -from cartopy.feature.nightshade import _julian_day, _solar_position +from cartopy.feature.nightshade import _julian_day, _solar_position, Nightshade def test_julian_day(): @@ -44,3 +44,12 @@ def test_solar_position(dt, true_lat, true_lon): lat, lon = _solar_position(dt) assert pytest.approx(true_lat, 0.1) == lat assert pytest.approx(true_lon, 0.1) == lon + + +def test_nightshade_floating_point(): + # Smoke test for clipping nightshade floating point values + date = datetime(1999, 12, 31, 12) + + # This can cause an error with floating point precision if it is + # set to exactly -6 and arccos input is not clipped to [-1, 1] + Nightshade(date, refraction=-6.0, color='none')