• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

CalebBell / fluids / 18620884630

18 Oct 2025 08:58PM UTC coverage: 86.155% (+0.5%) from 85.696%
18620884630

push

github

web-flow
More cleanups (#81)

* Typos

* Typos

* Doc updates

* .

* .

* .

* Typos

* .

* .

* .

* .

* typos

* More fixes

* Typos

* misc

* .

* .

* isort of __all__

* .

* ruff fixes

* .

* Quotes :(

* .

* Remove old 3.7

* .

* .

* .

* .

* ruff

* lint

* lint

* explore graalpy

* Merge in type hints at this point

* Making mypy and numba both happy is pretty nasty

* run ruff on the type hints that were merged in - nice!

* hook?

* check json, yaml, toml on git commit also

* .

* .

* .

* psd

* .

* .

* .

* .

* .

* docs

* sphinx needs to be updated to work on python 3.13

* .

* Typing progress

* mdformat

* Check

* x

* link

* json

* fixes

* .

* fixes

* format

* .

* .

* .

* .

* Another

* .

* .

* .

* Try again

* .

* note about numba

* Experiment with a micropython

* Again

* .

* .

* Fix sphinx issue

* ,m

* .

* .

* Updates

* .

4328 of 5740 branches covered (75.4%)

2015 of 2363 new or added lines in 38 files covered. (85.27%)

11 existing lines in 6 files now uncovered.

12309 of 14287 relevant lines covered (86.16%)

15.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.12
/fluids/optional/spa.py
1
"""
2
irradiance.py from pvlib
3
========================
4
Stripped down, vendorized version from:
5
https://github.com/pvlib/pvlib-python/
6

7
Calculate the solar position using the NREL SPA algorithm either using
8
numpy arrays or compiling the code to machine language with numba.
9

10
The rational for not including this library as a strict dependency is to avoid
11
including a dependency on pandas, keeping load time low, and PyPy compatibility
12

13
Created by Tony Lorenzo (@alorenzo175), Univ. of Arizona, 2015
14

15
For a full list of contributors to this file, see the `pvlib` repository.
16

17
The copyright notice (BSD-3 clause) is as follows:
18

19
BSD 3-Clause License
20

21
Copyright (c) 2013-2018, Sandia National Laboratories and pvlib python
22
Development Team
23
All rights reserved.
24

25
Redistribution and use in source and binary forms, with or without modification,
26
are permitted provided that the following conditions are met:
27

28
  Redistributions of source code must retain the above copyright notice, this
29
  list of conditions and the following disclaimer.
30

31
  Redistributions in binary form must reproduce the above copyright notice, this
32
  list of conditions and the following disclaimer in the documentation and/or
33
  other materials provided with the distribution.
34

35
  Neither the name of the {organization} nor the names of its
36
  contributors may be used to endorse or promote products derived from
37
  this software without specific prior written permission.
38

39
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
40
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
41
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
42
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
43
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
44
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
46
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
47
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
48
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49
"""
50

51

52
from math import acos, asin, atan, atan2, cos, degrees, radians, sin, tan
18✔
53

54
from fluids.constants import deg2rad, rad2deg
18✔
55
from fluids.numerics import sincos
18✔
56

57
__all__ = [
18✔
58
    "aberration_correction",
59
    "apparent_sidereal_time",
60
    "apparent_sun_longitude",
61
    "atmospheric_refraction_correction",
62
    "calculate_deltat",
63
    "equation_of_time",
64
    "equatorial_horizontal_parallax",
65
    "geocentric_latitude",
66
    "geocentric_longitude",
67
    "geocentric_sun_declination",
68
    "geocentric_sun_right_ascension",
69
    "heliocentric_latitude",
70
    "heliocentric_longitude",
71
    "heliocentric_radius_vector",
72
    "julian_century",
73
    "julian_day",
74
    "julian_day_dt",
75
    "julian_ephemeris_century",
76
    "julian_ephemeris_day",
77
    "julian_ephemeris_millennium",
78
    "local_hour_angle",
79
    "longitude_nutation",
80
    "longitude_obliquity_nutation",
81
    "mean_anomaly_moon",
82
    "mean_anomaly_sun",
83
    "mean_ecliptic_obliquity",
84
    "mean_elongation",
85
    "mean_sidereal_time",
86
    "moon_argument_latitude",
87
    "moon_ascending_longitude",
88
    "obliquity_nutation",
89
    "parallax_sun_right_ascension",
90
    "sun_mean_longitude",
91
    "topocentric_astronomers_azimuth",
92
    "topocentric_azimuth_angle",
93
    "topocentric_elevation_angle",
94
    "topocentric_elevation_angle_without_atmosphere",
95
    "topocentric_local_hour_angle",
96
    "topocentric_sun_declination",
97
    "topocentric_sun_right_ascension",
98
    "topocentric_zenith_angle",
99
    "transit_sunrise_sunset",
100
    "true_ecliptic_obliquity",
101
    "uterm",
102
    "xterm",
103
    "yterm",
104
]
105
nan = float("nan")
18✔
106

107

108
HELIO_RADIUS_TABLE_LIST_0 = [[100013989.0, 0.0, 0.0],
18✔
109
 [1670700.0, 3.0984635, 6283.07585],
110
 [13956.0, 3.05525, 12566.1517],
111
 [3084.0, 5.1985, 77713.7715],
112
 [1628.0, 1.1739, 5753.3849],
113
 [1576.0, 2.8469, 7860.4194],
114
 [925.0, 5.453, 11506.77],
115
 [542.0, 4.564, 3930.21],
116
 [472.0, 3.661, 5884.927],
117
 [346.0, 0.964, 5507.553],
118
 [329.0, 5.9, 5223.694],
119
 [307.0, 0.299, 5573.143],
120
 [243.0, 4.273, 11790.629],
121
 [212.0, 5.847, 1577.344],
122
 [186.0, 5.022, 10977.079],
123
 [175.0, 3.012, 18849.228],
124
 [110.0, 5.055, 5486.778],
125
 [98.0, 0.89, 6069.78],
126
 [86.0, 5.69, 15720.84],
127
 [86.0, 1.27, 161000.69],
128
 [65.0, 0.27, 17260.15],
129
 [63.0, 0.92, 529.69],
130
 [57.0, 2.01, 83996.85],
131
 [56.0, 5.24, 71430.7],
132
 [49.0, 3.25, 2544.31],
133
 [47.0, 2.58, 775.52],
134
 [45.0, 5.54, 9437.76],
135
 [43.0, 6.01, 6275.96],
136
 [39.0, 5.36, 4694.0],
137
 [38.0, 2.39, 8827.39],
138
 [37.0, 0.83, 19651.05],
139
 [37.0, 4.9, 12139.55],
140
 [36.0, 1.67, 12036.46],
141
 [35.0, 1.84, 2942.46],
142
 [33.0, 0.24, 7084.9],
143
 [32.0, 0.18, 5088.63],
144
 [32.0, 1.78, 398.15],
145
 [28.0, 1.21, 6286.6],
146
 [28.0, 1.9, 6279.55],
147
 [26.0, 4.59, 10447.39]]
148

149
HELIO_RADIUS_TABLE_LIST_1 = [[103019.0, 1.10749, 6283.07585],
18✔
150
 [1721.0, 1.0644, 12566.1517],
151
 [702.0, 3.142, 0.0],
152
 [32.0, 1.02, 18849.23],
153
 [31.0, 2.84, 5507.55],
154
 [25.0, 1.32, 5223.69],
155
 [18.0, 1.42, 1577.34],
156
 [10.0, 5.91, 10977.08],
157
 [9.0, 1.42, 6275.96],
158
 [9.0, 0.27, 5486.78],
159
]
160
HELIO_RADIUS_TABLE_LIST_2 = [[4359.0, 5.7846, 6283.0758],
18✔
161
 [124.0, 5.579, 12566.152],
162
 [12.0, 3.14, 0.0],
163
 [9.0, 3.63, 77713.77],
164
 [6.0, 1.87, 5573.14],
165
 [3.0, 5.47, 18849.23]]
166
HELIO_RADIUS_TABLE_LIST_3 = [[145.0, 4.273, 6283.076],
18✔
167
 [7.0, 3.92, 12566.15]]
168
HELIO_RADIUS_TABLE_LIST_4 = [[4.0, 2.56, 6283.08]]
18✔
169

170
NUTATION_YTERM_LIST_0 = [0.0, -2.0, 0.0, 0.0, 0.0, 0.0, -2.0, 0.0, 0.0, -2.0, -2.0, -2.0, 0.0, 2.0, 0.0, 2.0, 0.0, 0.0, -2.0, 0.0, 2.0, 0.0, 0.0, -2.0, 0.0, -2.0, 0.0, 0.0, 2.0, -2.0, 0.0, -2.0, 0.0, 0.0, 2.0, 2.0, 0.0, -2.0, 0.0, 2.0, 2.0, -2.0, -2.0, 2.0, 2.0, 0.0, -2.0, -2.0, 0.0, -2.0, -2.0, 0.0, -1.0, -2.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, 2.0, 0.0, 2.0]
18✔
171
NUTATION_YTERM_LIST_1 = [0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 2.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0, 1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, -1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.0, 1.0, -1.0, -1.0, 0.0, -1.0]
18✔
172
NUTATION_YTERM_LIST_2 = [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, -1.0, -1.0, 1.0, 2.0, -2.0, 0.0, 2.0, 2.0, 1.0, 0.0, 0.0, -1.0, 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 2.0, -1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 2.0, 1.0, -2.0, 0.0, 1.0, 0.0, 0.0, 2.0, 2.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, -2.0, 1.0, 1.0, 1.0, -1.0, 3.0, 0.0]
18✔
173
NUTATION_YTERM_LIST_3 = [0.0, 2.0, 2.0, 0.0, 0.0, 0.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 0.0, 0.0, 2.0, 0.0, 2.0, 0.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, -2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 0.0, 2.0, 2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 2.0, 0.0, 2.0, -2.0, 0.0, 0.0, 0.0, 2.0, 2.0, 0.0, 0.0, 2.0, 2.0, 2.0, 2.0]
18✔
174
NUTATION_YTERM_LIST_4 = [1.0, 2.0, 2.0, 2.0, 0.0, 0.0, 2.0, 1.0, 2.0, 2.0, 0.0, 1.0, 2.0, 0.0, 1.0, 2.0, 1.0, 1.0, 0.0, 1.0, 2.0, 2.0, 0.0, 2.0, 0.0, 0.0, 1.0, 0.0, 1.0, 2.0, 1.0, 1.0, 1.0, 0.0, 1.0, 2.0, 2.0, 0.0, 2.0, 1.0, 0.0, 2.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 2.0, 2.0, 2.0, 2.0]
18✔
175

176
NUTATION_ABCD_LIST = [[-171996.0, -174.2, 92025.0, 8.9],
18✔
177
 [-13187.0, -1.6, 5736.0, -3.1],
178
 [-2274.0, -0.2, 977.0, -0.5],
179
 [2062.0, 0.2, -895.0, 0.5],
180
 [1426.0, -3.4, 54.0, -0.1],
181
 [712.0, 0.1, -7.0, 0.0],
182
 [-517.0, 1.2, 224.0, -0.6],
183
 [-386.0, -0.4, 200.0, 0.0],
184
 [-301.0, 0.0, 129.0, -0.1],
185
 [217.0, -0.5, -95.0, 0.3],
186
 [-158.0, 0.0, 0.0, 0.0],
187
 [129.0, 0.1, -70.0, 0.0],
188
 [123.0, 0.0, -53.0, 0.0],
189
 [63.0, 0.0, 0.0, 0.0],
190
 [63.0, 0.1, -33.0, 0.0],
191
 [-59.0, 0.0, 26.0, 0.0],
192
 [-58.0, -0.1, 32.0, 0.0],
193
 [-51.0, 0.0, 27.0, 0.0],
194
 [48.0, 0.0, 0.0, 0.0],
195
 [46.0, 0.0, -24.0, 0.0],
196
 [-38.0, 0.0, 16.0, 0.0],
197
 [-31.0, 0.0, 13.0, 0.0],
198
 [29.0, 0.0, 0.0, 0.0],
199
 [29.0, 0.0, -12.0, 0.0],
200
 [26.0, 0.0, 0.0, 0.0],
201
 [-22.0, 0.0, 0.0, 0.0],
202
 [21.0, 0.0, -10.0, 0.0],
203
 [17.0, -0.1, 0.0, 0.0],
204
 [16.0, 0.0, -8.0, 0.0],
205
 [-16.0, 0.1, 7.0, 0.0],
206
 [-15.0, 0.0, 9.0, 0.0],
207
 [-13.0, 0.0, 7.0, 0.0],
208
 [-12.0, 0.0, 6.0, 0.0],
209
 [11.0, 0.0, 0.0, 0.0],
210
 [-10.0, 0.0, 5.0, 0.0],
211
 [-8.0, 0.0, 3.0, 0.0],
212
 [7.0, 0.0, -3.0, 0.0],
213
 [-7.0, 0.0, 0.0, 0.0],
214
 [-7.0, 0.0, 3.0, 0.0],
215
 [-7.0, 0.0, 3.0, 0.0],
216
 [6.0, 0.0, 0.0, 0.0],
217
 [6.0, 0.0, -3.0, 0.0],
218
 [6.0, 0.0, -3.0, 0.0],
219
 [-6.0, 0.0, 3.0, 0.0],
220
 [-6.0, 0.0, 3.0, 0.0],
221
 [5.0, 0.0, 0.0, 0.0],
222
 [-5.0, 0.0, 3.0, 0.0],
223
 [-5.0, 0.0, 3.0, 0.0],
224
 [-5.0, 0.0, 3.0, 0.0],
225
 [4.0, 0.0, 0.0, 0.0],
226
 [4.0, 0.0, 0.0, 0.0],
227
 [4.0, 0.0, 0.0, 0.0],
228
 [-4.0, 0.0, 0.0, 0.0],
229
 [-4.0, 0.0, 0.0, 0.0],
230
 [-4.0, 0.0, 0.0, 0.0],
231
 [3.0, 0.0, 0.0, 0.0],
232
 [-3.0, 0.0, 0.0, 0.0],
233
 [-3.0, 0.0, 0.0, 0.0],
234
 [-3.0, 0.0, 0.0, 0.0],
235
 [-3.0, 0.0, 0.0, 0.0],
236
 [-3.0, 0.0, 0.0, 0.0],
237
 [-3.0, 0.0, 0.0, 0.0],
238
 [-3.0, 0.0, 0.0, 0.0]]
239

240
HELIO_LAT_TABLE_LIST_0 = [[280.0, 3.199, 84334.662],
18✔
241
 [102.0, 5.422, 5507.553],
242
 [80.0, 3.88, 5223.69],
243
 [44.0, 3.7, 2352.87],
244
 [32.0, 4.0, 1577.34]]
245

246
HELIO_LAT_TABLE_LIST_1 = [[9.0, 3.9, 5507.55],
18✔
247
 [6.0, 1.73, 5223.69]]
248

249
#HELIO_LONG_TABLE_LIST = HELIO_LONG_TABLE.tolist()
250
HELIO_LONG_TABLE_LIST_0 = [[175347046.0, 0.0, 0.0],
18✔
251
 [3341656.0, 4.6692568, 6283.07585],
252
 [34894.0, 4.6261, 12566.1517],
253
 [3497.0, 2.7441, 5753.3849],
254
 [3418.0, 2.8289, 3.5231],
255
 [3136.0, 3.6277, 77713.7715],
256
 [2676.0, 4.4181, 7860.4194],
257
 [2343.0, 6.1352, 3930.2097],
258
 [1324.0, 0.7425, 11506.7698],
259
 [1273.0, 2.0371, 529.691],
260
 [1199.0, 1.1096, 1577.3435],
261
 [990.0, 5.233, 5884.927],
262
 [902.0, 2.045, 26.298],
263
 [857.0, 3.508, 398.149],
264
 [780.0, 1.179, 5223.694],
265
 [753.0, 2.533, 5507.553],
266
 [505.0, 4.583, 18849.228],
267
 [492.0, 4.205, 775.523],
268
 [357.0, 2.92, 0.067],
269
 [317.0, 5.849, 11790.629],
270
 [284.0, 1.899, 796.298],
271
 [271.0, 0.315, 10977.079],
272
 [243.0, 0.345, 5486.778],
273
 [206.0, 4.806, 2544.314],
274
 [205.0, 1.869, 5573.143],
275
 [202.0, 2.458, 6069.777],
276
 [156.0, 0.833, 213.299],
277
 [132.0, 3.411, 2942.463],
278
 [126.0, 1.083, 20.775],
279
 [115.0, 0.645, 0.98],
280
 [103.0, 0.636, 4694.003],
281
 [102.0, 0.976, 15720.839],
282
 [102.0, 4.267, 7.114],
283
 [99.0, 6.21, 2146.17],
284
 [98.0, 0.68, 155.42],
285
 [86.0, 5.98, 161000.69],
286
 [85.0, 1.3, 6275.96],
287
 [85.0, 3.67, 71430.7],
288
 [80.0, 1.81, 17260.15],
289
 [79.0, 3.04, 12036.46],
290
 [75.0, 1.76, 5088.63],
291
 [74.0, 3.5, 3154.69],
292
 [74.0, 4.68, 801.82],
293
 [70.0, 0.83, 9437.76],
294
 [62.0, 3.98, 8827.39],
295
 [61.0, 1.82, 7084.9],
296
 [57.0, 2.78, 6286.6],
297
 [56.0, 4.39, 14143.5],
298
 [56.0, 3.47, 6279.55],
299
 [52.0, 0.19, 12139.55],
300
 [52.0, 1.33, 1748.02],
301
 [51.0, 0.28, 5856.48],
302
 [49.0, 0.49, 1194.45],
303
 [41.0, 5.37, 8429.24],
304
 [41.0, 2.4, 19651.05],
305
 [39.0, 6.17, 10447.39],
306
 [37.0, 6.04, 10213.29],
307
 [37.0, 2.57, 1059.38],
308
 [36.0, 1.71, 2352.87],
309
 [36.0, 1.78, 6812.77],
310
 [33.0, 0.59, 17789.85],
311
 [30.0, 0.44, 83996.85],
312
 [30.0, 2.74, 1349.87],
313
 [25.0, 3.16, 4690.48]]
314
HELIO_LONG_TABLE_LIST_1 = [[628331966747.0, 0.0, 0.0],
18✔
315
 [206059.0, 2.678235, 6283.07585],
316
 [4303.0, 2.6351, 12566.1517],
317
 [425.0, 1.59, 3.523],
318
 [119.0, 5.796, 26.298],
319
 [109.0, 2.966, 1577.344],
320
 [93.0, 2.59, 18849.23],
321
 [72.0, 1.14, 529.69],
322
 [68.0, 1.87, 398.15],
323
 [67.0, 4.41, 5507.55],
324
 [59.0, 2.89, 5223.69],
325
 [56.0, 2.17, 155.42],
326
 [45.0, 0.4, 796.3],
327
 [36.0, 0.47, 775.52],
328
 [29.0, 2.65, 7.11],
329
 [21.0, 5.34, 0.98],
330
 [19.0, 1.85, 5486.78],
331
 [19.0, 4.97, 213.3],
332
 [17.0, 2.99, 6275.96],
333
 [16.0, 0.03, 2544.31],
334
 [16.0, 1.43, 2146.17],
335
 [15.0, 1.21, 10977.08],
336
 [12.0, 2.83, 1748.02],
337
 [12.0, 3.26, 5088.63],
338
 [12.0, 5.27, 1194.45],
339
 [12.0, 2.08, 4694.0],
340
 [11.0, 0.77, 553.57],
341
 [10.0, 1.3, 6286.6],
342
 [10.0, 4.24, 1349.87],
343
 [9.0, 2.7, 242.73],
344
 [9.0, 5.64, 951.72],
345
 [8.0, 5.3, 2352.87],
346
 [6.0, 2.65, 9437.76],
347
 [6.0, 4.67, 4690.48],
348
 ]
349
HELIO_LONG_TABLE_LIST_2 = [[52919.0, 0.0, 0.0],
18✔
350
 [8720.0, 1.0721, 6283.0758],
351
 [309.0, 0.867, 12566.152],
352
 [27.0, 0.05, 3.52],
353
 [16.0, 5.19, 26.3],
354
 [16.0, 3.68, 155.42],
355
 [10.0, 0.76, 18849.23],
356
 [9.0, 2.06, 77713.77],
357
 [7.0, 0.83, 775.52],
358
 [5.0, 4.66, 1577.34],
359
 [4.0, 1.03, 7.11],
360
 [4.0, 3.44, 5573.14],
361
 [3.0, 5.14, 796.3],
362
 [3.0, 6.05, 5507.55],
363
 [3.0, 1.19, 242.73],
364
 [3.0, 6.12, 529.69],
365
 [3.0, 0.31, 398.15],
366
 [3.0, 2.28, 553.57],
367
 [2.0, 4.38, 5223.69],
368
 [2.0, 3.75, 0.98]]
369

370
HELIO_LONG_TABLE_LIST_3 = [[289.0, 5.844, 6283.076],
18✔
371
 [35.0, 0.0, 0.0],
372
 [17.0, 5.49, 12566.15],
373
 [3.0, 5.2, 155.42],
374
 [1.0, 4.72, 3.52],
375
 [1.0, 5.3, 18849.23],
376
 [1.0, 5.97, 242.73]
377
 ]
378
HELIO_LONG_TABLE_LIST_4 = [[114.0, 3.142, 0.0],
18✔
379
 [8.0, 4.13, 6283.08],
380
 [1.0, 3.84, 12566.15]]
381

382

383

384
def julian_day_dt(year, month, day, hour, minute, second, microsecond):
18✔
385
    """This is the original way to calculate the julian day from the NREL paper.
386

387
    However, it is much faster to convert to unix/epoch time and then convert to
388
    julian day. Note that the date must be UTC.
389
    """
390
    # Not used anywhere!
391
    if month <= 2:
17!
392
        year = year-1
×
393
        month = month+12
×
394
    a = int(year/100)
17✔
395
    b = 2 - a + int(a * 0.25)
17✔
396
    frac_of_day = (microsecond + (second + minute * 60 + hour * 3600)
17✔
397
                   ) * 1.0 / (3600*24)
398
    d = day + frac_of_day
17✔
399
    jd = (int(365.25 * (year + 4716)) + int(30.6001 * (month + 1)) + d +
17✔
400
          b - 1524.5)
401
    return jd
17✔
402

403

404
def julian_day(unixtime):
18✔
405
    jd = unixtime*1.1574074074074073e-05 + 2440587.5
18✔
406
#    jd = unixtime/86400.0 + 2440587.5
407
    return jd
18✔
408

409

410
def julian_ephemeris_day(julian_day, delta_t):
18✔
411
    jde = julian_day + delta_t*1.1574074074074073e-05
18✔
412
#    jde = julian_day + delta_t * 1.0 / 86400.0
413
    return jde
18✔
414

415

416
def julian_century(julian_day):
18✔
417
    jc = (julian_day - 2451545.0)*2.7378507871321012e-05# * 1.0 / 36525
18✔
418
    return jc
18✔
419

420

421
def julian_ephemeris_century(julian_ephemeris_day):
18✔
422
#    1/36525.0 =  2.7378507871321012e-05
423
    jce = (julian_ephemeris_day - 2451545.0)*2.7378507871321012e-05
18✔
424
    return jce
18✔
425

426

427
def julian_ephemeris_millennium(julian_ephemeris_century):
18✔
428
    jme = julian_ephemeris_century*0.1
18✔
429
    return jme
18✔
430

431

432
def heliocentric_longitude(jme):
18✔
433
    # Might be able to replace this with a pade approximation?
434
    # Looping over rows is probably still faster than (a, b, c)
435
    # Maximum optimization
436
    l0 = 0.0
18✔
437
    l1 = 0.0
18✔
438
    l2 = 0.0
18✔
439
    l3 = 0.0
18✔
440
    l4 = 0.0
18✔
441
    l5 = 0.0
18✔
442
    for row in range(64):
18✔
443
        HELIO_LONG_TABLE_LIST_0_ROW = HELIO_LONG_TABLE_LIST_0[row]
18✔
444
        l0 += (HELIO_LONG_TABLE_LIST_0_ROW[0]
18✔
445
               * cos(HELIO_LONG_TABLE_LIST_0_ROW[1]
446
                        + HELIO_LONG_TABLE_LIST_0_ROW[2] * jme)
447
               )
448
    for row in range(34):
18✔
449
        HELIO_LONG_TABLE_LIST_1_ROW = HELIO_LONG_TABLE_LIST_1[row]
18✔
450
        l1 += (HELIO_LONG_TABLE_LIST_1_ROW[0]
18✔
451
               * cos(HELIO_LONG_TABLE_LIST_1_ROW[1]
452
                        + HELIO_LONG_TABLE_LIST_1_ROW[2] * jme)
453
               )
454
    for row in range(20):
18✔
455
        HELIO_LONG_TABLE_LIST_2_ROW = HELIO_LONG_TABLE_LIST_2[row]
18✔
456
        l2 += (HELIO_LONG_TABLE_LIST_2_ROW[0]
18✔
457
               * cos(HELIO_LONG_TABLE_LIST_2_ROW[1]
458
                        + HELIO_LONG_TABLE_LIST_2_ROW[2] * jme)
459
               )
460

461
    for row in range(7):
18✔
462
        HELIO_LONG_TABLE_LIST_3_ROW = HELIO_LONG_TABLE_LIST_3[row]
18✔
463
        l3 += (HELIO_LONG_TABLE_LIST_3_ROW[0]
18✔
464
               * cos(HELIO_LONG_TABLE_LIST_3_ROW[1]
465
                        + HELIO_LONG_TABLE_LIST_3_ROW[2] * jme)
466
               )
467
    for row in range(3):
18✔
468
        HELIO_LONG_TABLE_LIST_4_ROW = HELIO_LONG_TABLE_LIST_4[row]
18✔
469
        l4 += (HELIO_LONG_TABLE_LIST_4_ROW[0]
18✔
470
               * cos(HELIO_LONG_TABLE_LIST_4_ROW[1]
471
                        + HELIO_LONG_TABLE_LIST_4_ROW[2] * jme)
472
               )
473
#    l5 = (HELIO_LONG_TABLE_LIST_5[0][0]*cos(HELIO_LONG_TABLE_LIST_5[0][1]))
474
    l5 = -0.9999987317275395
18✔
475
    l_rad = (jme*(jme*(jme*(jme*(jme*l5 + l4) + l3) + l2) + l1) + l0)*1E-8
18✔
476
    l = rad2deg*l_rad
18✔
477
    return l % 360
18✔
478

479

480
def heliocentric_latitude(jme):
18✔
481
    b0 = 0.0
18✔
482
    b1 = 0.0
18✔
483
    for row in range(5):
18✔
484
        HELIO_LAT_TABLE_LIST_0_ROW = HELIO_LAT_TABLE_LIST_0[row]
18✔
485
        b0 += (HELIO_LAT_TABLE_LIST_0_ROW[0]
18✔
486
               * cos(HELIO_LAT_TABLE_LIST_0_ROW[1]
487
                        + HELIO_LAT_TABLE_LIST_0_ROW[2] * jme)
488
               )
489
    HELIO_LAT_TABLE_LIST_1_ROW = HELIO_LAT_TABLE_LIST_1[0]
18✔
490
    b1 += (HELIO_LAT_TABLE_LIST_1_ROW[0]
18✔
491
           * cos(HELIO_LAT_TABLE_LIST_1_ROW[1]
492
                    + HELIO_LAT_TABLE_LIST_1_ROW[2] * jme))
493

494
    HELIO_LAT_TABLE_LIST_1_ROW = HELIO_LAT_TABLE_LIST_1[1]
18✔
495
    b1 += (HELIO_LAT_TABLE_LIST_1_ROW[0]
18✔
496
           * cos(HELIO_LAT_TABLE_LIST_1_ROW[1]
497
                    + HELIO_LAT_TABLE_LIST_1_ROW[2] * jme))
498
    b_rad = (b0 + b1 * jme)*1E-8
18✔
499
    b = rad2deg*b_rad
18✔
500
    return b
18✔
501

502

503
def heliocentric_radius_vector(jme):
18✔
504
    # no optimizations can be thought of
505
    r0 = 0.0
18✔
506
    r1 = 0.0
18✔
507
    r2 = 0.0
18✔
508
    r3 = 0.0
18✔
509
    r4 = 0.0
18✔
510
    # Would be possible to save a few multiplies of table1row[2]*jme, table1row[1]*jme as they are dups
511
    for row in range(40):
18✔
512
        table0row = HELIO_RADIUS_TABLE_LIST_0[row]
18✔
513
        r0 += (table0row[0]*cos(table0row[1] + table0row[2]*jme))
18✔
514
    for row in range(10):
18✔
515
        table1row = HELIO_RADIUS_TABLE_LIST_1[row]
18✔
516
        r1 += (table1row[0]*cos(table1row[1] + table1row[2]*jme))
18✔
517
    for row in range(6):
18✔
518
        table2row = HELIO_RADIUS_TABLE_LIST_2[row]
18✔
519
        r2 += (table2row[0]*cos(table2row[1] + table2row[2]*jme))
18✔
520

521
    table3row = HELIO_RADIUS_TABLE_LIST_3[0]
18✔
522
    r3 += (table3row[0]*cos(table3row[1] + table3row[2]*jme))
18✔
523
    table3row = HELIO_RADIUS_TABLE_LIST_3[1]
18✔
524
    r3 += (table3row[0]*cos(table3row[1] + table3row[2]*jme))
18✔
525

526
#    table4row = HELIO_RADIUS_TABLE_LIST_4[0]
527
#    r4 = (table4row[0]*cos(table4row[1] + table4row[2]*jme))
528
    r4 = (4.0*cos(2.56 + 6283.08*jme))
18✔
529
    return (jme*(jme*(jme*(jme*r4 + r3) + r2) + r1) + r0)*1E-8
18✔
530

531

532
def geocentric_longitude(heliocentric_longitude):
18✔
533
    theta = heliocentric_longitude + 180.0
18✔
534
    return theta % 360
18✔
535

536

537
def geocentric_latitude(heliocentric_latitude):
18✔
538
    beta = -heliocentric_latitude
18✔
539
    return beta
18✔
540

541

542
def mean_elongation(julian_ephemeris_century):
18✔
543
    return (julian_ephemeris_century*(julian_ephemeris_century
18✔
544
            *(5.27776898149614e-6*julian_ephemeris_century - 0.0019142)
545
            + 445267.11148) + 297.85036)
546
#    x0 = (297.85036
547
#          + 445267.111480 * julian_ephemeris_century
548
#          - 0.0019142 * julian_ephemeris_century**2
549
#          + julian_ephemeris_century**3 / 189474.0)
550
#    return x0
551

552

553
def mean_anomaly_sun(julian_ephemeris_century):
18✔
554
    return (julian_ephemeris_century*(julian_ephemeris_century*(
18✔
555
            -3.33333333333333e-6*julian_ephemeris_century - 0.0001603)
556
            + 35999.05034) + 357.52772)
557
#    x1 = (357.52772
558
#          + 35999.050340 * julian_ephemeris_century
559
#          - 0.0001603 * julian_ephemeris_century**2
560
#          - julian_ephemeris_century**3 / 300000.0)
561
#    return x1
562

563

564
def mean_anomaly_moon(julian_ephemeris_century):
18✔
565
    return (julian_ephemeris_century*(julian_ephemeris_century*(
18✔
566
            1.77777777777778e-5*julian_ephemeris_century + 0.0086972)
567
        + 477198.867398) + 134.96298)
568
#    x2 = (134.96298
569
#          + 477198.867398 * julian_ephemeris_century
570
#          + 0.0086972 * julian_ephemeris_century**2
571
#          + julian_ephemeris_century**3 / 56250)
572
#    return x2
573

574

575
def moon_argument_latitude(julian_ephemeris_century):
18✔
576
    return julian_ephemeris_century*(julian_ephemeris_century*(
18✔
577
            3.05558101873071e-6*julian_ephemeris_century - 0.0036825)
578
        + 483202.017538) + 93.27191
579
#    x3 = (93.27191
580
#          + 483202.017538 * julian_ephemeris_century
581
#          - 0.0036825 * julian_ephemeris_century**2
582
#          + julian_ephemeris_century**3 / 327270)
583
#    return x3
584

585

586
def moon_ascending_longitude(julian_ephemeris_century):
18✔
587
    return (julian_ephemeris_century*(julian_ephemeris_century*(
18✔
588
            2.22222222222222e-6*julian_ephemeris_century + 0.0020708)
589
            - 1934.136261) + 125.04452)
590
#    x4 = (125.04452
591
#          - 1934.136261 * julian_ephemeris_century
592
#          + 0.0020708 * julian_ephemeris_century**2
593
#          + julian_ephemeris_century**3 / 450000)
594
#    return x4
595

596

597
def longitude_obliquity_nutation(julian_ephemeris_century, x0, x1, x2, x3, x4):
18✔
598
    x0, x1, x2, x3, x4 = deg2rad*x0, deg2rad*x1, deg2rad*x2, deg2rad*x3, deg2rad*x4
18✔
599
    delta_psi_sum = 0.0
18✔
600
    delta_eps_sum = 0.0
18✔
601
    # If the sincos formulation is used, the speed up is ~8% with numba.
602
    for row in range(63):
18✔
603
        arg = (NUTATION_YTERM_LIST_0[row]*x0 +
18✔
604
               NUTATION_YTERM_LIST_1[row]*x1 +
605
               NUTATION_YTERM_LIST_2[row]*x2 +
606
               NUTATION_YTERM_LIST_3[row]*x3 +
607
               NUTATION_YTERM_LIST_4[row]*x4)
608
        arr = NUTATION_ABCD_LIST[row]
18✔
609
        sinarg, cosarg = sincos(arg)
18✔
610
#        sinarg = sin(arg)
611
#        cosarg = sqrt(1.0 - sinarg*sinarg)
612
        t0 = (arr[0] + julian_ephemeris_century*arr[1])
18✔
613
        delta_psi_sum += t0*sinarg
18✔
614
#        delta_psi_sum += t0*sin(arg)
615
        t0 = (arr[2] + julian_ephemeris_century*arr[3])
18✔
616
        delta_eps_sum += t0*cosarg
18✔
617
#        delta_eps_sum += t0*cos(arg)
618
    delta_psi = delta_psi_sum/36000000.0
18✔
619
    delta_eps = delta_eps_sum/36000000.0
18✔
620
    res = [0.0]*2
18✔
621
    res[0] = delta_psi
18✔
622
    res[1] = delta_eps
18✔
623
    return res
18✔
624

625
def longitude_nutation(julian_ephemeris_century, x0, x1, x2, x3, x4):
18✔
626
    x0, x1, x2, x3, x4 = deg2rad*x0, deg2rad*x1, deg2rad*x2, deg2rad*x3, deg2rad*x4
17✔
627
    delta_psi_sum = 0.0
17✔
628
    for row in range(63):
17✔
629
#       # None can be skipped but the multiplies can be with effort -2 to 2 with dict - just might be slower
630
        argsin = (NUTATION_YTERM_LIST_0[row]*x0 +
17✔
631
                  NUTATION_YTERM_LIST_1[row]*x1 +
632
                  NUTATION_YTERM_LIST_2[row]*x2 +
633
                  NUTATION_YTERM_LIST_3[row]*x3 +
634
                  NUTATION_YTERM_LIST_4[row]*x4)
635
        term = (NUTATION_ABCD_LIST[row][0] + NUTATION_ABCD_LIST[row][1]
17✔
636
                * julian_ephemeris_century)*sin(argsin)
637
        delta_psi_sum += term
17✔
638
    delta_psi = delta_psi_sum/36000000.0
17✔
639
    return delta_psi
17✔
640

641

642
def obliquity_nutation(julian_ephemeris_century, x0, x1, x2, x3, x4):
18✔
643
    delta_eps_sum = 0.0
17✔
644
    x0, x1, x2, x3, x4 = deg2rad*x0, deg2rad*x1, deg2rad*x2, deg2rad*x3, deg2rad*x4
17✔
645
    for row in range(63):
17✔
646
        argcos = (NUTATION_YTERM_LIST_0[row]*x0 +
17✔
647
                  NUTATION_YTERM_LIST_1[row]*x1 +
648
                  NUTATION_YTERM_LIST_2[row]*x2 +
649
                  NUTATION_YTERM_LIST_3[row]*x3 +
650
                  NUTATION_YTERM_LIST_4[row]*x4)
651
        term = (NUTATION_ABCD_LIST[row][2]
17✔
652
               + NUTATION_ABCD_LIST[row][3]*julian_ephemeris_century)*cos(argcos)
653
        delta_eps_sum += term
17✔
654
    delta_eps = delta_eps_sum/36000000.0
17✔
655
    return delta_eps
17✔
656

657

658
def mean_ecliptic_obliquity(julian_ephemeris_millennium):
18✔
659
    U = 0.1*julian_ephemeris_millennium
18✔
660
    e0 =  (U*(U*(U*(U*(U*(U*(U*(U*(U*(2.45*U + 5.79) + 27.87) + 7.12) - 39.05)
18✔
661
           - 249.67) - 51.38) + 1999.25) - 1.55) - 4680.93) + 84381.448)
662
    return e0
18✔
663

664

665
def true_ecliptic_obliquity(mean_ecliptic_obliquity, obliquity_nutation):
18✔
666
#    e0 = mean_ecliptic_obliquity
667
#    deleps = obliquity_nutation
668
    return mean_ecliptic_obliquity*0.0002777777777777778  + obliquity_nutation
18✔
669
#    e = e0/3600.0 + deleps
670
#    return e
671

672

673
def aberration_correction(earth_radius_vector):
18✔
674
    # -20.4898 / (3600)
675
    deltau = -0.005691611111111111/earth_radius_vector
18✔
676
    return deltau
18✔
677

678

679
def apparent_sun_longitude(geocentric_longitude, longitude_nutation,
18✔
680
                           aberration_correction):
681
    lamd = geocentric_longitude + longitude_nutation + aberration_correction
18✔
682
    return lamd
18✔
683

684

685
def mean_sidereal_time(julian_day, julian_century):
18✔
686
    julian_century2 = julian_century*julian_century
18✔
687
    v0 = (280.46061837 + 360.98564736629*(julian_day - 2451545.0)
18✔
688
          + 0.000387933*julian_century2
689
          - julian_century2*julian_century/38710000.0)
690
    return v0 % 360.0
18✔
691

692

693
def apparent_sidereal_time(mean_sidereal_time, longitude_nutation,
18✔
694
                           true_ecliptic_obliquity):
695
    v = mean_sidereal_time + longitude_nutation*cos(deg2rad*true_ecliptic_obliquity)
18✔
696
    return v
18✔
697

698

699
def geocentric_sun_right_ascension(apparent_sun_longitude,
18✔
700
                                   true_ecliptic_obliquity,
701
                                   geocentric_latitude):
702
    num = (sin(deg2rad*apparent_sun_longitude)
18✔
703
           * cos(deg2rad*true_ecliptic_obliquity)
704
           - tan(deg2rad*geocentric_latitude)
705
           * sin(deg2rad*true_ecliptic_obliquity))
706
    alpha = degrees(atan2(num, cos(
18✔
707
        deg2rad*apparent_sun_longitude)))
708
    return alpha % 360
18✔
709

710

711
def geocentric_sun_declination(apparent_sun_longitude, true_ecliptic_obliquity,
18✔
712
                               geocentric_latitude):
713
    delta = degrees(asin(sin(deg2rad*geocentric_latitude) *
18✔
714
                                 cos(deg2rad*true_ecliptic_obliquity) +
715
                                 cos(deg2rad*geocentric_latitude) *
716
                                 sin(deg2rad*true_ecliptic_obliquity) *
717
                                 sin(deg2rad*apparent_sun_longitude)))
718
    return delta
18✔
719

720

721
def local_hour_angle(apparent_sidereal_time, observer_longitude,
18✔
722
                     sun_right_ascension):
723
    """Measured westward from south."""
724
    H = apparent_sidereal_time + observer_longitude - sun_right_ascension
18✔
725
    return H % 360
18✔
726

727

728
def equatorial_horizontal_parallax(earth_radius_vector):
18✔
729
    return 8.794 / (3600.0 * earth_radius_vector)
18✔
730

731

732
def uterm(observer_latitude):
18✔
733
    u = atan(0.99664719*tan(deg2rad*observer_latitude))
18✔
734
    return u
18✔
735

736

737
def xterm(u, observer_latitude, observer_elevation):
18✔
738
    # 1/6378140.0 = const
739
    x = (cos(u) + observer_elevation*1.5678552054360676e-07*cos(deg2rad*observer_latitude))
18✔
740
    return x
18✔
741

742

743
def yterm(u, observer_latitude, observer_elevation):
18✔
744
    # 1/6378140.0 = const
745
    y = (0.99664719 * sin(u) + observer_elevation*1.5678552054360676e-07
18✔
746
         * sin(deg2rad*observer_latitude))
747
    return y
18✔
748

749

750
def parallax_sun_right_ascension(xterm, equatorial_horizontal_parallax,
18✔
751
                                 local_hour_angle, geocentric_sun_declination):
752
    x0 = sin(deg2rad*equatorial_horizontal_parallax)
18✔
753
    x1 = deg2rad*local_hour_angle
18✔
754
    num = -xterm*x0*sin(x1)
18✔
755
    denom = (cos(deg2rad*geocentric_sun_declination) - xterm*x0 * cos(x1))
18✔
756
    delta_alpha = degrees(atan2(num, denom))
18✔
757
    return delta_alpha
18✔
758

759

760
def topocentric_sun_right_ascension(geocentric_sun_right_ascension,
18✔
761
                                    parallax_sun_right_ascension):
762
    alpha_prime = geocentric_sun_right_ascension + parallax_sun_right_ascension
17✔
763
    return alpha_prime
17✔
764

765

766
def topocentric_sun_declination(geocentric_sun_declination, xterm, yterm,
18✔
767
                                equatorial_horizontal_parallax,
768
                                parallax_sun_right_ascension,
769
                                local_hour_angle):
770
    x0 = sin(deg2rad*equatorial_horizontal_parallax)
18✔
771
    num = ((sin(deg2rad*geocentric_sun_declination) - yterm
18✔
772
            * x0)
773
           * cos(deg2rad*parallax_sun_right_ascension))
774
    denom = (cos(deg2rad*geocentric_sun_declination) - xterm
18✔
775
             * x0
776
             * cos(deg2rad*local_hour_angle))
777
    delta = degrees(atan2(num, denom))
18✔
778
    return delta
18✔
779

780

781
def topocentric_local_hour_angle(local_hour_angle,
18✔
782
                                 parallax_sun_right_ascension):
783
    H_prime = local_hour_angle - parallax_sun_right_ascension
18✔
784
    return H_prime
18✔
785

786

787
def topocentric_elevation_angle_without_atmosphere(observer_latitude,
18✔
788
                                                   topocentric_sun_declination,
789
                                                   topocentric_local_hour_angle
790
                                                   ):
791

792
    r_observer_latitude = deg2rad*observer_latitude
18✔
793
    r_topocentric_sun_declination = deg2rad*topocentric_sun_declination
18✔
794
    e0 = degrees(asin(
18✔
795
        sin(r_observer_latitude)
796
        * sin(r_topocentric_sun_declination)
797
        + cos(r_observer_latitude)
798
        * cos(r_topocentric_sun_declination)
799
        * cos(deg2rad*topocentric_local_hour_angle)))
800

801
    return e0
18✔
802

803

804
def atmospheric_refraction_correction(local_pressure, local_temp,
18✔
805
                                      topocentric_elevation_angle_wo_atmosphere,
806
                                      atmos_refract):
807
    # switch sets delta_e when the sun is below the horizon
808
    switch = topocentric_elevation_angle_wo_atmosphere >= -1.0 * (
18✔
809
        0.26667 + atmos_refract)
810
    delta_e = ((local_pressure / 1010.0) * (283.0 / (273.0 + local_temp))
18✔
811
               * 1.02 / (60.0 * tan(deg2rad*(
812
                   topocentric_elevation_angle_wo_atmosphere
813
                   + 10.3 / (topocentric_elevation_angle_wo_atmosphere
814
                             + 5.11))))) * switch
815
    return delta_e
18✔
816

817

818
def topocentric_elevation_angle(topocentric_elevation_angle_without_atmosphere,
18✔
819
                                atmospheric_refraction_correction):
820
    e = (topocentric_elevation_angle_without_atmosphere
18✔
821
         + atmospheric_refraction_correction)
822
    return e
18✔
823

824

825
def topocentric_zenith_angle(topocentric_elevation_angle):
18✔
826
    theta = 90.0 - topocentric_elevation_angle
18✔
827
    return theta
18✔
828

829

830
def topocentric_astronomers_azimuth(topocentric_local_hour_angle,
18✔
831
                                    topocentric_sun_declination,
832
                                    observer_latitude):
833
    num = sin(deg2rad*topocentric_local_hour_angle)
18✔
834
    denom = (cos(deg2rad*topocentric_local_hour_angle)
18✔
835
             * sin(deg2rad*observer_latitude)
836
             - tan(deg2rad*topocentric_sun_declination)
837
             * cos(deg2rad*observer_latitude))
838
    gamma = degrees(atan2(num, denom))
18✔
839

840
    return gamma % 360.0
18✔
841

842

843
def topocentric_azimuth_angle(topocentric_astronomers_azimuth):
18✔
844
    phi = topocentric_astronomers_azimuth + 180.0
18✔
845
    return phi % 360.0
18✔
846

847

848
def sun_mean_longitude(julian_ephemeris_millennium):
18✔
849
    M = julian_ephemeris_millennium*(julian_ephemeris_millennium*(
18✔
850
            julian_ephemeris_millennium*(julian_ephemeris_millennium*(
851
                    -5.0e-7*julian_ephemeris_millennium - 6.5359477124183e-5)
852
        + 2.00276381406341e-5) + 0.03032028) + 360007.6982779) + 280.4664567
853
    return M
18✔
854

855

856
#@jcompile('float64(float64, float64, float64, float64)', nopython=True)
857
def equation_of_time(sun_mean_longitude, geocentric_sun_right_ascension,
18✔
858
                     longitude_nutation, true_ecliptic_obliquity):
859
    term = cos(deg2rad*true_ecliptic_obliquity)
18✔
860
    E = (sun_mean_longitude - 0.0057183 - geocentric_sun_right_ascension +
18✔
861
         longitude_nutation * term)
862
    # limit between 0 and 360
863
    E = E % 360
18✔
864
    # convert to minutes
865
    E *= 4.0
18✔
866
    greater = E > 20.0
18✔
867
    less = E < -20.0
18✔
868
    other = (E <= 20.0) & (E >= -20.0)
18✔
869
    E = greater * (E - 1440.0) + less * (E + 1440.0) + other * E
18✔
870
    return E
18✔
871

872

873
def earthsun_distance(unixtime, delta_t):
18✔
874
    """Calculates the distance from the earth to the sun using the NREL SPA
875
    algorithm described in [1].
876

877
    Parameters
878
    ----------
879
    unixtime : numpy array
880
        Array of unix/epoch timestamps to calculate solar position for.
881
        Unixtime is the number of seconds since Jan. 1, 1970 00:00:00 UTC.
882
        A pandas.DatetimeIndex is easily converted using .astype(np.int64)/10**9
883
    delta_t : float
884
        Difference between terrestrial time and UT. USNO has tables.
885

886
    Returns
887
    -------
888
    R : array
889
        Earth-Sun distance in AU.
890

891
    References
892
    ----------
893
    [1] Reda, I., Andreas, A., 2003. Solar position algorithm for solar
894
    radiation applications. Technical report: NREL/TP-560- 34302. Golden,
895
    USA, http://www.nrel.gov.
896
    """
897
    jd = julian_day(unixtime)
18✔
898
    jde = julian_ephemeris_day(jd, delta_t)
18✔
899
    jce = julian_ephemeris_century(jde)
18✔
900
    jme = julian_ephemeris_millennium(jce)
18✔
901
    R = heliocentric_radius_vector(jme)
18✔
902
    return R
18✔
903

904

905
def solar_position(unixtime, lat, lon, elev, pressure, temp, delta_t,
18✔
906
                   atmos_refract, sst=False):
907
    """Calculate the solar position using the NREL SPA algorithm described in
908
    [1].
909

910
    If numba is installed, the functions can be compiled
911
    and the code runs quickly. If not, the functions
912
    still evaluate but use numpy instead.
913

914
    Parameters
915
    ----------
916
    unixtime : numpy array
917
        Array of unix/epoch timestamps to calculate solar position for.
918
        Unixtime is the number of seconds since Jan. 1, 1970 00:00:00 UTC.
919
        A pandas.DatetimeIndex is easily converted using .astype(np.int64)/10**9
920
    lat : float
921
        Latitude to calculate solar position for
922
    lon : float
923
        Longitude to calculate solar position for
924
    elev : float
925
        Elevation of location in meters
926
    pressure : int or float
927
        avg. yearly pressure at location in millibars;
928
        used for atmospheric correction
929
    temp : int or float
930
        avg. yearly temperature at location in
931
        degrees C; used for atmospheric correction
932
    delta_t : float, optional
933
        If delta_t is None, uses spa.calculate_deltat
934
        using time.year and time.month from pandas.DatetimeIndex.
935
        For most simulations specifying delta_t is sufficient.
936
        Difference between terrestrial time and UT1.
937
        *Note: delta_t = None will break code using nrel_numba,
938
        this will be fixed in a future version.
939
        By default, use USNO historical data and predictions
940
    atmos_refrac : float, optional
941
        The approximate atmospheric refraction (in degrees)
942
        at sunrise and sunset.
943
    numthreads: int, optional, default None
944
        Number of threads to use for computation if numba>=0.17
945
        is installed.
946
    sst : bool, default False
947
        If True, return only data needed for sunrise, sunset, and transit
948
        calculations.
949

950
    Returns
951
    -------
952
    list with elements:
953
        apparent zenith,
954
        zenith,
955
        elevation,
956
        apparent_elevation,
957
        azimuth,
958
        equation_of_time
959

960
    References
961
    ----------
962
    .. [1] I. Reda and A. Andreas, Solar position algorithm for solar radiation
963
    applications. Solar Energy, vol. 76, no. 5, pp. 577-589, 2004.
964
    .. [2] I. Reda and A. Andreas, Corrigendum to Solar position algorithm for
965
    solar radiation applications. Solar Energy, vol. 81, no. 6, p. 838, 2007.
966
    """
967
    jd = julian_day(unixtime)
18✔
968
    jde = julian_ephemeris_day(jd, delta_t)
18✔
969
    jc = julian_century(jd)
18✔
970
    jce = julian_ephemeris_century(jde)
18✔
971
    jme = julian_ephemeris_millennium(jce)
18✔
972
    R = heliocentric_radius_vector(jme)
18✔
973
    L = heliocentric_longitude(jme)
18✔
974
    B = heliocentric_latitude(jme)
18✔
975
    Theta = geocentric_longitude(L)
18✔
976
    beta = geocentric_latitude(B)
18✔
977
    x0 = mean_elongation(jce)
18✔
978
    x1 = mean_anomaly_sun(jce)
18✔
979
    x2 = mean_anomaly_moon(jce)
18✔
980
    x3 = moon_argument_latitude(jce)
18✔
981
    x4 = moon_ascending_longitude(jce)
18✔
982
    delta_psi, delta_epsilon = longitude_obliquity_nutation(jce, x0, x1, x2, x3, x4)
18✔
983

984
    epsilon0 = mean_ecliptic_obliquity(jme)
18✔
985
    epsilon = true_ecliptic_obliquity(epsilon0, delta_epsilon)
18✔
986
    delta_tau = aberration_correction(R)
18✔
987
    lamd = apparent_sun_longitude(Theta, delta_psi, delta_tau)
18✔
988
    v0 = mean_sidereal_time(jd, jc)
18✔
989
    v = apparent_sidereal_time(v0, delta_psi, epsilon)
18✔
990
    alpha = geocentric_sun_right_ascension(lamd, epsilon, beta)
18✔
991
    delta = geocentric_sun_declination(lamd, epsilon, beta)
18✔
992
    if sst: # numba: delete
18✔
993
        return v, alpha, delta # numba: delete
18✔
994

995
    m = sun_mean_longitude(jme)
18✔
996
    eot = equation_of_time(m, alpha, delta_psi, epsilon)
18✔
997
    H = local_hour_angle(v, lon, alpha)
18✔
998
    xi = equatorial_horizontal_parallax(R)
18✔
999
    u = uterm(lat)
18✔
1000
    x = xterm(u, lat, elev)
18✔
1001
    y = yterm(u, lat, elev)
18✔
1002
    delta_alpha = parallax_sun_right_ascension(x, xi, H, delta)
18✔
1003
    delta_prime = topocentric_sun_declination(delta, x, y, xi, delta_alpha, H)
18✔
1004
    H_prime = topocentric_local_hour_angle(H, delta_alpha)
18✔
1005
    e0 = topocentric_elevation_angle_without_atmosphere(lat, delta_prime,
18✔
1006
                                                        H_prime)
1007
    delta_e = atmospheric_refraction_correction(pressure, temp, e0,
18✔
1008
                                                atmos_refract)
1009
    e = topocentric_elevation_angle(e0, delta_e)
18✔
1010
    theta = topocentric_zenith_angle(e)
18✔
1011
    theta0 = topocentric_zenith_angle(e0)
18✔
1012
    gamma = topocentric_astronomers_azimuth(H_prime, delta_prime, lat)
18✔
1013
    phi = topocentric_azimuth_angle(gamma)
18✔
1014
    return [theta, theta0, e, e0, phi, eot]
18✔
1015

1016
IS_NUMBA = "IS_NUMBA" in globals()
18✔
1017
if IS_NUMBA:
18✔
1018
    import threading
17✔
1019

1020
    import numba
17✔
1021
    import numpy as np
17✔
1022
    # This is 3x slower without nogil
1023
    @numba.njit(nogil=True)
17✔
1024
    def solar_position_loop(unixtime, loc_args, out):
17✔
1025
        """Loop through the time array and calculate the solar position."""
NEW
1026
        lat = loc_args[0]
×
NEW
1027
        lon = loc_args[1]
×
NEW
1028
        elev = loc_args[2]
×
NEW
1029
        pressure = loc_args[3]
×
NEW
1030
        temp = loc_args[4]
×
NEW
1031
        delta_t = loc_args[5]
×
NEW
1032
        atmos_refract = loc_args[6]
×
NEW
1033
        sst = loc_args[7]
×
NEW
1034
        esd = loc_args[8]
×
1035

NEW
1036
        for i in range(len(unixtime)):
×
NEW
1037
            utime = unixtime[i]
×
NEW
1038
            jd = julian_day(utime)
×
NEW
1039
            jde = julian_ephemeris_day(jd, delta_t)
×
NEW
1040
            jc = julian_century(jd)
×
NEW
1041
            jce = julian_ephemeris_century(jde)
×
NEW
1042
            jme = julian_ephemeris_millennium(jce)
×
NEW
1043
            R = heliocentric_radius_vector(jme)
×
NEW
1044
            L = heliocentric_longitude(jme)
×
NEW
1045
            B = heliocentric_latitude(jme)
×
1046

NEW
1047
            Theta = geocentric_longitude(L)
×
NEW
1048
            beta = geocentric_latitude(B)
×
NEW
1049
            x0 = mean_elongation(jce)
×
NEW
1050
            x1 = mean_anomaly_sun(jce)
×
NEW
1051
            x2 = mean_anomaly_moon(jce)
×
NEW
1052
            x3 = moon_argument_latitude(jce)
×
NEW
1053
            x4 = moon_ascending_longitude(jce)
×
1054
#                delta_psi = longitude_nutation(jce, x0, x1, x2, x3, x4)
1055
#                delta_epsilon = obliquity_nutation(jce, x0, x1, x2, x3, x4)
NEW
1056
            delta_psi, delta_epsilon = longitude_obliquity_nutation(jce, x0, x1, x2, x3, x4)
×
NEW
1057
            epsilon0 = mean_ecliptic_obliquity(jme)
×
NEW
1058
            epsilon = true_ecliptic_obliquity(epsilon0, delta_epsilon)
×
NEW
1059
            delta_tau = aberration_correction(R)
×
NEW
1060
            lamd = apparent_sun_longitude(Theta, delta_psi, delta_tau)
×
NEW
1061
            v0 = mean_sidereal_time(jd, jc)
×
NEW
1062
            v = apparent_sidereal_time(v0, delta_psi, epsilon)
×
NEW
1063
            alpha = geocentric_sun_right_ascension(lamd, epsilon, beta)
×
NEW
1064
            delta = geocentric_sun_declination(lamd, epsilon, beta)
×
1065
#                if sst:
1066
#                    out[0, i] = v
1067
#                    out[1, i] = alpha
1068
#                    out[2, i] = delta
1069
#                    continue
NEW
1070
            m = sun_mean_longitude(jme)
×
NEW
1071
            eot = equation_of_time(m, alpha, delta_psi, epsilon)
×
NEW
1072
            H = local_hour_angle(v, lon, alpha)
×
NEW
1073
            xi = equatorial_horizontal_parallax(R)
×
NEW
1074
            u = uterm(lat)
×
NEW
1075
            x = xterm(u, lat, elev)
×
NEW
1076
            y = yterm(u, lat, elev)
×
NEW
1077
            delta_alpha = parallax_sun_right_ascension(x, xi, H, delta)
×
NEW
1078
            delta_prime = topocentric_sun_declination(delta, x, y, xi, delta_alpha,
×
1079
                                                        H)
NEW
1080
            H_prime = topocentric_local_hour_angle(H, delta_alpha)
×
NEW
1081
            e0 = topocentric_elevation_angle_without_atmosphere(lat, delta_prime,
×
1082
                                                                H_prime)
NEW
1083
            delta_e = atmospheric_refraction_correction(pressure, temp, e0,
×
1084
                                                        atmos_refract)
NEW
1085
            e = topocentric_elevation_angle(e0, delta_e)
×
NEW
1086
            theta = topocentric_zenith_angle(e)
×
NEW
1087
            theta0 = topocentric_zenith_angle(e0)
×
NEW
1088
            gamma = topocentric_astronomers_azimuth(H_prime, delta_prime, lat)
×
NEW
1089
            phi = topocentric_azimuth_angle(gamma)
×
NEW
1090
            out[0, i] = theta
×
NEW
1091
            out[1, i] = theta0
×
NEW
1092
            out[2, i] = e
×
NEW
1093
            out[3, i] = e0
×
NEW
1094
            out[4, i] = phi
×
NEW
1095
            out[5, i] = eot
×
1096

1097

1098
    def solar_position_numba(unixtime, lat, lon, elev, pressure, temp, delta_t,
17✔
1099
                                atmos_refract, numthreads, sst=False, esd=False):
1100
        """Calculate the solar position using the numba compiled functions
1101
        and multiple threads.
1102

1103
        Very slow if functions are not numba compiled.
1104
        """
1105
        # these args are the same for each thread
NEW
1106
        loc_args = np.array([lat, lon, elev, pressure, temp, delta_t,
×
1107
                                atmos_refract, sst, esd])
1108

1109
        # construct dims x ulength array to put the results in
NEW
1110
        ulength = unixtime.shape[0]
×
NEW
1111
        if sst:
×
NEW
1112
            dims = 3
×
NEW
1113
        elif esd:
×
NEW
1114
            dims = 1
×
1115
        else:
NEW
1116
            dims = 6
×
NEW
1117
        result = np.empty((dims, ulength), dtype=np.float64)
×
1118

NEW
1119
        if unixtime.dtype != np.float64:
×
NEW
1120
            unixtime = unixtime.astype(np.float64)
×
1121

NEW
1122
        if ulength < numthreads:
×
NEW
1123
            numthreads = ulength
×
1124

NEW
1125
        if numthreads <= 1:
×
NEW
1126
            solar_position_loop(unixtime, loc_args, result)
×
UNCOV
1127
            return result
×
1128

1129
        # split the input and output arrays into numthreads chunks
NEW
1130
        split0 = np.array_split(unixtime, numthreads)
×
NEW
1131
        split2 = np.array_split(result, numthreads, axis=1)
×
NEW
1132
        chunks = [[a0, loc_args, split2[i]] for i, a0 in enumerate(split0)]
×
1133
        # Spawn one thread per chunk
NEW
1134
        threads = [threading.Thread(target=solar_position_loop, args=chunk)
×
1135
                    for chunk in chunks]
NEW
1136
        for thread in threads:
×
NEW
1137
            thread.start()
×
NEW
1138
        for thread in threads:
×
NEW
1139
            thread.join()
×
NEW
1140
        return result
×
1141

1142

1143
def transit_sunrise_sunset(dates, lat, lon, delta_t):
18✔
1144
    """Calculate the sun transit, sunrise, and sunset for a set of dates at a
1145
    given location.
1146

1147
    Parameters
1148
    ----------
1149
    dates : array
1150
        Numpy array of ints/floats corresponding to the Unix time
1151
        for the dates of interest, must be midnight UTC (00:00+00:00)
1152
        on the day of interest.
1153
    lat : float
1154
        Latitude of location to perform calculation for
1155
    lon : float
1156
        Longitude of location
1157
    delta_t : float
1158
        Difference between terrestrial time and UT. USNO has tables.
1159

1160
    Returns
1161
    -------
1162
    tuple : (transit, sunrise, sunset) localized to UTC
1163

1164
    >>> transit_sunrise_sunset(1523836800, 51.0486, -114.07, 70.68302220312503)
1165
    (1523907360.3863413, 1523882341.570479, 1523932345.7781625)
1166
    """
1167
    condition = (dates % 86400) != 0.0
18✔
1168
    if condition:
18!
NEW
1169
        raise ValueError("Input dates must be at 00:00 UTC")
×
1170

1171
    utday = (dates // 86400) * 86400
18✔
1172
    ttday0 = utday - delta_t
18✔
1173
    ttdayn1 = ttday0 - 86400.0
18✔
1174
    ttdayp1 = ttday0 + 86400.0
18✔
1175

1176
    # index 0 is v, 1 is alpha, 2 is delta
1177
    utday_res = solar_position(utday, 0, 0, 0, 0, 0, delta_t,
18✔
1178
                               0, sst=True)
1179
    v = utday_res[0]
18✔
1180

1181
    ttday0_res = solar_position(ttday0, 0, 0, 0, 0, 0, delta_t,
18✔
1182
                                0, sst=True)
1183
    ttdayn1_res = solar_position(ttdayn1, 0, 0, 0, 0, 0, delta_t,
18✔
1184
                                 0, sst=True)
1185
    ttdayp1_res = solar_position(ttdayp1, 0, 0, 0, 0, 0, delta_t,
18✔
1186
                                 0, sst=True)
1187
    m0 = (ttday0_res[1] - lon - v) / 360
18✔
1188
    cos_arg = ((-0.014543315936696236 - sin(radians(lat)) # sin(radians(-0.8333)) = -0.0145...
18✔
1189
               * sin(radians(ttday0_res[2]))) /
1190
               (cos(radians(lat)) * cos(radians(ttday0_res[2]))))
1191
    if abs(cos_arg) > 1:
18!
1192
        cos_arg = nan
×
1193

1194
    H0 = degrees(acos(cos_arg)) % 180
18✔
1195

1196
    m = [0.0]*3
18✔
1197
    m[0] = m0 % 1
18✔
1198
    m[1] = (m[0] - H0 / 360.0)
18✔
1199
    m[2] = (m[0] + H0 / 360.0)
18✔
1200

1201
    # need to account for fractions of day that may be the next or previous
1202
    # day in UTC
1203
    add_a_day = m[2] >= 1
18✔
1204
    sub_a_day = m[1] < 0
18✔
1205
    m[1] = m[1] % 1
18✔
1206
    m[2] = m[2] % 1
18✔
1207
    vs = [0.0]*3
18✔
1208
    for i in range(3):
18✔
1209
        vs[i] = v + 360.985647*m[i]
18✔
1210
    n = [0.0]*3
18✔
1211
    for i in range(3):
18✔
1212
        n[i] = m[i] + delta_t / 86400.0
18✔
1213

1214
    a = ttday0_res[1] - ttdayn1_res[1]
18✔
1215

1216
    if abs(a) > 2:
18!
1217
        a = a %1
×
1218
    ap = ttday0_res[2] - ttdayn1_res[2]
18✔
1219
    if (abs(ap) > 2):
18!
1220
        ap = ap % 1
×
1221
    b = ttdayp1_res[1] - ttday0_res[1]
18✔
1222
    if (abs(b) > 2):
18!
1223
        b = b % 1
×
1224
    bp = ttdayp1_res[2] - ttday0_res[2]
18✔
1225
    if abs(bp) > 2:
18!
1226
        bp = bp % 1
×
1227

1228

1229
    c = b - a
18✔
1230
    cp = bp - ap
18✔
1231

1232
    alpha_prime = [0.0]*3
18✔
1233
    delta_prime = [0.0]*3
18✔
1234
    Hp = [0.0]*3
18✔
1235
    for i in range(3):
18✔
1236
        alpha_prime[i] = ttday0_res[1] + (n[i] * (a + b + c * n[i]))*0.5
18✔
1237
        delta_prime[i] = ttday0_res[2] + (n[i] * (ap + bp + cp * n[i]))*0.5
18✔
1238
        Hp[i] = (vs[i] + lon - alpha_prime[i]) % 360
18✔
1239
        if Hp[i] >= 180.0:
18✔
1240
            Hp[i] = Hp[i] - 360.0
18✔
1241

1242

1243
    #alpha_prime = ttday0_res[1] + (n * (a + b + c * n)) / 2 # this is vect
1244
    #delta_prime = ttday0_res[2] + (n * (ap + bp + cp * n)) / 2 # this is vect
1245
    #Hp = (vs + lon - alpha_prime) % 360
1246
    #Hp[Hp >= 180] = Hp[Hp >= 180] - 360
1247
    x1 = sin(radians(lat))
18✔
1248
    x2 = cos(radians(lat))
18✔
1249

1250
    h = [0.0]*3
18✔
1251
    for i in range(3):
18✔
1252
        h[i] = degrees(asin(x1*sin(radians(delta_prime[i])) + x2 * cos(radians(delta_prime[i])) * cos(radians(Hp[i]))))
18✔
1253

1254
    T = float((m[0] - Hp[0] / 360.0) * 86400.0)
18✔
1255
    R = float((m[1] + (h[1] + 0.8333) / (360.0 * cos(radians(delta_prime[1])) *
18✔
1256
                                   cos(radians(lat)) *
1257
                                   sin(radians(Hp[1])))) * 86400.0)
1258
    S = float((m[2] + (h[2] + 0.8333) / (360.0 * cos(radians(delta_prime[2])) *
18✔
1259
                                   cos(radians(lat)) *
1260
                                   sin(radians(Hp[2])))) * 86400.0)
1261

1262
    if add_a_day:
18✔
1263
        S += 86400.0
18✔
1264
    if sub_a_day:
18✔
1265
        R -= 86400.0
17✔
1266

1267
    transit = T + utday
18✔
1268
    sunrise = R + utday
18✔
1269
    sunset = S + utday
18✔
1270

1271
    return transit, sunrise, sunset
18✔
1272

1273

1274
def calculate_deltat(year, month):
18✔
1275
    y = year + (month - 0.5)/12
18✔
1276
    if (2005 <= year) & (year < 2050):
18✔
1277
        t1 = (y-2000.0)
18✔
1278
        deltat = (62.92+0.32217*t1 + 0.005589*t1*t1)
18✔
1279
    elif  (1986 <= year) & (year < 2005):
18✔
1280
        t1 = y - 2000.0
18✔
1281
        deltat = (63.86+0.3345*t1
18✔
1282
                      - 0.060374*t1**2
1283
                      + 0.0017275*t1**3
1284
                      + 0.000651814*t1**4
1285
                      + 0.00002373599*t1**5)
1286
    elif (2050 <= year) & (year < 2150):
17!
1287
        deltat = (-20+32*((y-1820)/100)**2
×
1288
                      - 0.5628*(2150-y))
1289
    elif year < -500.0:
17!
1290
        deltat = -20.0 + 32*(0.01*(y-1820.0))**2
×
1291

1292
    elif (-500 <= year) & (year < 500):
17✔
1293
        t1 = y/100
17✔
1294
        deltat = (10583.6-1014.41*(y/100)
17✔
1295
                      + 33.78311*(y/100)**2
1296
                      - 5.952053*(y/100)**3
1297
                      - 0.1798452*(y/100)**4
1298
                      + 0.022174192*(y/100)**5
1299
                      + 0.0090316521*(y/100)**6)
1300
    elif (500 <= year) & (year < 1600):
17✔
1301
        t1 = (y-1000)/100
17✔
1302
        deltat = (1574.2-556.01*((y-1000)/100)
17✔
1303
                      + 71.23472*((y-1000)/100)**2
1304
                      + 0.319781*((y-1000)/100)**3
1305
                      - 0.8503463*((y-1000)/100)**4
1306
                      - 0.005050998*((y-1000)/100)**5
1307
                      + 0.0083572073*((y-1000)/100)**6)
1308
    elif (1600 <= year) & (year < 1700):
17!
1309
        t1 = (y-1600.0)
×
1310
        deltat = (120-0.9808*(y-1600)
×
1311
                      - 0.01532*(y-1600)**2
1312
                      + (y-1600)**3/7129)
1313
    elif (1700 <= year) & (year < 1800):
17!
1314
        t1 = (y - 1700.0)
×
1315
        deltat = (8.83+0.1603*(y-1700)
×
1316
                      - 0.0059285*(y-1700)**2
1317
                      + 0.00013336*(y-1700)**3
1318
                      - (y-1700)**4/1174000)
1319
    elif (1800 <= year) & (year < 1860):
17✔
1320
        t1 = y - 1800.0
17✔
1321
        deltat = (13.72-0.332447*(y-1800)
17✔
1322
                      + 0.0068612*(y-1800)**2
1323
                      + 0.0041116*(y-1800)**3
1324
                      - 0.00037436*(y-1800)**4
1325
                      + 0.0000121272*(y-1800)**5
1326
                      - 0.0000001699*(y-1800)**6
1327
                      + 0.000000000875*(y-1800)**7)
1328
    elif (1860 <= year) & (year < 1900):
17!
1329
        t1 = y-1860.0
×
1330
        deltat = (7.62+0.5737*(y-1860)
×
1331
                      - 0.251754*(y-1860)**2
1332
                      + 0.01680668*(y-1860)**3
1333
                      - 0.0004473624*(y-1860)**4
1334
                      + (y-1860)**5/233174)
1335
    elif (1900 <= year) & (year < 1920):
17✔
1336
        t1 = y - 1900.0
17✔
1337
        deltat = (-2.79+1.494119*(y-1900)
17✔
1338
                      - 0.0598939*(y-1900)**2
1339
                      + 0.0061966*(y-1900)**3
1340
                      - 0.000197*(y-1900)**4)
1341
    elif (1920 <= year) & (year < 1941):
17!
1342
        t1 = y - 1920.0
×
1343
        deltat = (21.20+0.84493*(y-1920)
×
1344
                      - 0.076100*(y-1920)**2
1345
                      + 0.0020936*(y-1920)**3)
1346
    elif (1941 <= year) & (year < 1961):
17✔
1347
        t1 = y - 1950.0
17✔
1348
        deltat = (29.07+0.407*(y-1950)
17✔
1349
                      - (y-1950)**2/233
1350
                      + (y-1950)**3/2547)
1351
    elif (1961 <= year) & (year < 1986):
17!
1352
        t1 = y-1975
17✔
1353
        deltat = (45.45+1.067*(y-1975)
17✔
1354
                      - (y-1975)**2/260
1355
                      - (y-1975)**3/718)
1356

1357
    elif year >= 2150:
×
1358
        deltat = -20+32*((y-1820)/100)**2
×
1359

1360

1361
    return deltat
18✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc