Skip to content

Commit baa3eec

Browse files
committed
Clean up solar.py to pass flake8 (Issue #528)
1 parent 2873ee6 commit baa3eec

File tree

1 file changed

+251
-0
lines changed
  • Downloads/basemap-develop/packages/basemap/src/mpl_toolkits/basemap

1 file changed

+251
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
"""Simple functions to calculate solar position and day-night terminator."""
2+
# pylint: disable=invalid-name
3+
from __future__ import division
4+
5+
import numpy as np
6+
7+
8+
def JulianDayFromDate(date, calendar="standard"):
9+
"""Return Julian day from a :class:`datetime.datetime` object.
10+
11+
Algorithm:
12+
13+
Meeus, Jean (1998) Astronomical Algorithms (2nd Edition).
14+
Willmann-Bell, Virginia. p. 63
15+
16+
Paramaters
17+
---------
18+
19+
date : datetime.datetime
20+
a :class:`datetime.datetime` object
21+
22+
calendar : {'standard', 'gregorian', 'proleptic_gregorian',
23+
'julian'}, optional
24+
if 'standard' or 'gregorian', Julian day follows the Julian
25+
calendar on and before 1582-10-05, and the Gregorian calendar
26+
after 1582-10-15; if 'proleptic_gregorian', Julian day follows
27+
the Gregorian calendar; if 'julian', Julian day follows the
28+
Julian calendar
29+
30+
Returns
31+
-------
32+
33+
jd : float
34+
the Julian day, with resolution of 1 second
35+
"""
36+
37+
# Based on `redate.py` by David Finlayson.
38+
year, month, day = date.year, date.month, date.day
39+
hour, minute, second = date.hour, date.minute, date.second
40+
41+
# Convert time to fractions of a day.
42+
day = day + hour / 24.0 + minute / 1440.0 + second / 86400.0
43+
44+
# Start Meeus algorithm (variables are in his notation).
45+
if month < 3:
46+
month = month + 12
47+
year = year - 1
48+
A = int(year / 100)
49+
jd = (
50+
int(365.25 * (year + 4716)) +
51+
int(30.6001 * (month + 1)) +
52+
day - 1524.5
53+
)
54+
55+
# Optionally adjust `jd` for the switch from Julian to Gregorian calendar.
56+
# Here assumed to have occurred the day after 1582 October 4
57+
if calendar in ["standard", "gregorian"]:
58+
if jd >= 2299170.5:
59+
# 1582 October 15 (Gregorian Calendar).
60+
B = 2 - A + int(A / 4)
61+
elif jd < 2299160.5:
62+
# 1582 October 5 (Julian Calendar).
63+
B = 0
64+
else:
65+
raise ValueError("impossible date (falls in gap between end of "
66+
"Julian calendar and start of Gregorian calendar")
67+
elif calendar == "proleptic_gregorian":
68+
B = 2 - A + int(A / 4)
69+
elif calendar == "julian":
70+
B = 0
71+
else:
72+
raise ValueError("unknown calendar '{0}' (must be one of 'standard', "
73+
"'gregorian',"
74+
" 'proleptic_gregorian' or 'julian'".format(calendar))
75+
76+
# Adjust for Julian calendar if necessary.
77+
jd = jd + B
78+
79+
return jd
80+
81+
82+
def epem(date):
83+
"""Return the Greenwich hour angle.
84+
85+
Parameters
86+
----------
87+
88+
date : datetime.datetime
89+
a :class:`datetime.datetime` object (assumed UTC)
90+
91+
Returns
92+
-------
93+
94+
gha : float
95+
Greenwich hour angle, i.e. the angle between the Greenwich
96+
meridian and the meridian containing the subsolar point.
97+
98+
dec : float
99+
solar declination
100+
"""
101+
102+
dg2rad = np.pi / 180.
103+
rad2dg = 1. / dg2rad
104+
105+
# Compute Julian day from UTC `datetime.datetime` object (note that
106+
# `datetime.datetime` objects use proleptic Gregorian calendar).
107+
jday = JulianDayFromDate(date, calendar="proleptic_gregorian")
108+
jd = np.floor(jday) # Truncate to integer.
109+
110+
# Compute UTC hour.
111+
ut = date.hour + date.minute / 60. + date.second / 3600.
112+
113+
# Calculate number of centuries from J2000.
114+
t = (jd + (ut / 24.) - 2451545.0) / 36525.
115+
116+
# Mean longitude corrected for aberration.
117+
l = (280.460 + 36000.770 * t) % 360 # noqa: E741
118+
119+
# Mean anomaly.
120+
g = 357.528 + 35999.050 * t
121+
122+
# Ecliptic longitude.
123+
lm = l + 1.915 * np.sin(g * dg2rad) + 0.020 * np.sin(2 * g * dg2rad)
124+
125+
# Obliquity of the ecliptic.
126+
ep = 23.4393 - 0.01300 * t
127+
128+
# Equation of time.
129+
eqtime = (
130+
-1.915 * np.sin(g * dg2rad)
131+
- 0.020 * np.sin(2 * g * dg2rad)
132+
+ 2.466 * np.sin(2 * lm * dg2rad)
133+
- 0.053 * np.sin(4 * lm * dg2rad)
134+
)
135+
136+
# Greenwich hour angle.
137+
gha = 15 * ut - 180 + eqtime
138+
139+
# Declination of Sun.
140+
dec = np.arcsin(np.sin(ep * dg2rad) * np.sin(lm * dg2rad)) * rad2dg
141+
142+
return gha, dec
143+
144+
145+
def daynight_terminator(date, delta, lonmin, lonmax):
146+
"""Return the day-night terminator.
147+
148+
Parameters
149+
----------
150+
151+
date : datetime.datetime
152+
a :class:`datetime.datetime` object (assumed UTC)
153+
154+
delta : float
155+
input longitude grid step in degrees used to compute the
156+
day-night terminator
157+
158+
lonmin : float
159+
minimum input longitude in degrees
160+
161+
lonmax : float
162+
maximum input longitude in degrees
163+
164+
Returns
165+
-------
166+
167+
lons : array-like
168+
array of longitudes of the day-night terminator
169+
170+
lats : array-like
171+
array of latitudes of the day-night terminator
172+
173+
tau : float
174+
Greenwich hour angle for the input datetime
175+
176+
dec : float
177+
solar declination for the input datetime
178+
"""
179+
180+
dg2rad = np.pi / 180.0
181+
lons = np.arange(
182+
lonmin,
183+
lonmax + 0.5 * delta,
184+
delta,
185+
dtype=np.float32
186+
)
187+
188+
# Compute Greenwich hour angle and solar declination.
189+
tau, dec = epem(date)
190+
191+
# Compute day-night terminator from Greenwich hour angle and declination.
192+
longitude = lons + tau
193+
lats = (
194+
np.arctan(-np.cos(longitude * dg2rad) / np.tan(dec * dg2rad)) / dg2rad
195+
)
196+
197+
return lons, lats, tau, dec
198+
199+
200+
def daynight_grid(date, delta, lonmin, lonmax):
201+
"""Return day-night mask array.
202+
203+
Parameters
204+
----------
205+
206+
date : datetime.datetime
207+
a :class:`datetime.datetime` object (assumed UTC)
208+
209+
delta : float
210+
input longitude grid step in degrees used to compute the
211+
day-night terminator
212+
213+
lonmin : float
214+
minimum input longitude in degrees
215+
216+
lonmax : float
217+
maximum input longitude in degrees
218+
219+
Returns
220+
-------
221+
222+
lons2 : array-like
223+
meshgrid of longitudes of the day-night mask array
224+
225+
lats2 : array-like
226+
meshgrid of latitudes of the day-night mask array
227+
228+
daynight : ~numpy.ma.MaskedArray
229+
day-night mask array (masked for day, 1 for night)
230+
"""
231+
232+
lons, lats, _, dec = daynight_terminator(date, delta, lonmin, lonmax)
233+
234+
# Create meshgrid of longitudes and latitudes.
235+
lats2 = np.arange(-90, 90 + 0.5 * delta, delta, dtype=np.float32)
236+
lons2, lats2 = np.meshgrid(lons, lats2)
237+
238+
# Create day-night grid (0 for day, 1 for night).
239+
nlats, nlons = len(lats2), len(lons)
240+
lats = lats[np.newaxis, :] * np.ones((nlats, nlons), dtype=np.float32)
241+
daynight = np.ones(lons2.shape, np.int8)
242+
if dec > 0: # NH summer
243+
daynight = np.where(lats2 > lats, 0, daynight)
244+
else: # NH winter
245+
daynight = np.where(lats2 < lats, 0, daynight)
246+
247+
# Create day-night masked array (with day areas masked).
248+
daynight_mask = 1 - daynight
249+
daynight = np.ma.array(daynight, mask=daynight_mask)
250+
251+
return lons2, lats2, daynight

0 commit comments

Comments
 (0)