pvlib 0.9.4a1__py3-none-any.whl → 0.10.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. pvlib/__init__.py +3 -2
  2. pvlib/atmosphere.py +23 -173
  3. pvlib/bifacial/infinite_sheds.py +88 -277
  4. pvlib/bifacial/utils.py +270 -28
  5. pvlib/data/adr-library-cec-inverters-2019-03-05.csv +5009 -0
  6. pvlib/data/precise_iv_curves1.json +10251 -0
  7. pvlib/data/precise_iv_curves2.json +10251 -0
  8. pvlib/data/precise_iv_curves_parameter_sets1.csv +33 -0
  9. pvlib/data/precise_iv_curves_parameter_sets2.csv +33 -0
  10. pvlib/data/test_psm3_2017.csv +17521 -17521
  11. pvlib/data/test_psm3_2019_5min.csv +288 -288
  12. pvlib/data/test_read_psm3.csv +17522 -17522
  13. pvlib/data/test_read_pvgis_horizon.csv +49 -0
  14. pvlib/data/variables_style_rules.csv +3 -0
  15. pvlib/iam.py +207 -51
  16. pvlib/inverter.py +6 -1
  17. pvlib/iotools/__init__.py +7 -2
  18. pvlib/iotools/acis.py +516 -0
  19. pvlib/iotools/midc.py +4 -4
  20. pvlib/iotools/psm3.py +59 -42
  21. pvlib/iotools/pvgis.py +84 -28
  22. pvlib/iotools/sodapro.py +8 -6
  23. pvlib/iotools/srml.py +121 -18
  24. pvlib/iotools/surfrad.py +2 -2
  25. pvlib/iotools/tmy.py +146 -102
  26. pvlib/irradiance.py +270 -15
  27. pvlib/ivtools/sde.py +14 -20
  28. pvlib/ivtools/sdm.py +31 -20
  29. pvlib/ivtools/utils.py +127 -6
  30. pvlib/location.py +3 -2
  31. pvlib/modelchain.py +67 -70
  32. pvlib/pvarray.py +225 -0
  33. pvlib/pvsystem.py +169 -539
  34. pvlib/shading.py +43 -2
  35. pvlib/singlediode.py +216 -66
  36. pvlib/snow.py +36 -15
  37. pvlib/soiling.py +3 -3
  38. pvlib/spa.py +327 -368
  39. pvlib/spectrum/__init__.py +8 -2
  40. pvlib/spectrum/mismatch.py +335 -0
  41. pvlib/temperature.py +124 -13
  42. pvlib/tests/bifacial/test_infinite_sheds.py +44 -106
  43. pvlib/tests/bifacial/test_utils.py +102 -5
  44. pvlib/tests/conftest.py +0 -31
  45. pvlib/tests/iotools/test_acis.py +213 -0
  46. pvlib/tests/iotools/test_midc.py +6 -6
  47. pvlib/tests/iotools/test_psm3.py +7 -5
  48. pvlib/tests/iotools/test_pvgis.py +21 -14
  49. pvlib/tests/iotools/test_sodapro.py +1 -1
  50. pvlib/tests/iotools/test_srml.py +71 -6
  51. pvlib/tests/iotools/test_tmy.py +43 -8
  52. pvlib/tests/ivtools/test_sde.py +19 -17
  53. pvlib/tests/ivtools/test_sdm.py +9 -4
  54. pvlib/tests/ivtools/test_utils.py +96 -1
  55. pvlib/tests/test_atmosphere.py +8 -64
  56. pvlib/tests/test_clearsky.py +0 -1
  57. pvlib/tests/test_iam.py +74 -1
  58. pvlib/tests/test_irradiance.py +56 -2
  59. pvlib/tests/test_location.py +1 -1
  60. pvlib/tests/test_modelchain.py +33 -76
  61. pvlib/tests/test_pvarray.py +46 -0
  62. pvlib/tests/test_pvsystem.py +366 -201
  63. pvlib/tests/test_shading.py +35 -0
  64. pvlib/tests/test_singlediode.py +306 -29
  65. pvlib/tests/test_snow.py +84 -1
  66. pvlib/tests/test_soiling.py +8 -7
  67. pvlib/tests/test_solarposition.py +7 -7
  68. pvlib/tests/test_spa.py +6 -7
  69. pvlib/tests/test_spectrum.py +145 -1
  70. pvlib/tests/test_temperature.py +29 -11
  71. pvlib/tests/test_tools.py +41 -0
  72. pvlib/tests/test_tracking.py +0 -149
  73. pvlib/tools.py +49 -25
  74. pvlib/tracking.py +1 -269
  75. pvlib-0.10.0.dist-info/AUTHORS.md +35 -0
  76. {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/LICENSE +5 -2
  77. {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/METADATA +3 -13
  78. {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/RECORD +80 -75
  79. {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/WHEEL +1 -1
  80. pvlib/data/adr-library-2013-10-01.csv +0 -1762
  81. pvlib/forecast.py +0 -1211
  82. pvlib/iotools/ecmwf_macc.py +0 -312
  83. pvlib/tests/iotools/test_ecmwf_macc.py +0 -162
  84. pvlib/tests/test_forecast.py +0 -228
  85. pvlib-0.9.4a1.dist-info/AUTHORS.md +0 -32
  86. {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/top_level.txt +0 -0
pvlib/spa.py CHANGED
@@ -43,248 +43,237 @@ else:
43
43
  USE_NUMBA = False
44
44
 
45
45
 
46
- TABLE_1_DICT = {
47
- 'L0': np.array(
48
- [[175347046.0, 0.0, 0.0],
49
- [3341656.0, 4.6692568, 6283.07585],
50
- [34894.0, 4.6261, 12566.1517],
51
- [3497.0, 2.7441, 5753.3849],
52
- [3418.0, 2.8289, 3.5231],
53
- [3136.0, 3.6277, 77713.7715],
54
- [2676.0, 4.4181, 7860.4194],
55
- [2343.0, 6.1352, 3930.2097],
56
- [1324.0, 0.7425, 11506.7698],
57
- [1273.0, 2.0371, 529.691],
58
- [1199.0, 1.1096, 1577.3435],
59
- [990.0, 5.233, 5884.927],
60
- [902.0, 2.045, 26.298],
61
- [857.0, 3.508, 398.149],
62
- [780.0, 1.179, 5223.694],
63
- [753.0, 2.533, 5507.553],
64
- [505.0, 4.583, 18849.228],
65
- [492.0, 4.205, 775.523],
66
- [357.0, 2.92, 0.067],
67
- [317.0, 5.849, 11790.629],
68
- [284.0, 1.899, 796.298],
69
- [271.0, 0.315, 10977.079],
70
- [243.0, 0.345, 5486.778],
71
- [206.0, 4.806, 2544.314],
72
- [205.0, 1.869, 5573.143],
73
- [202.0, 2.458, 6069.777],
74
- [156.0, 0.833, 213.299],
75
- [132.0, 3.411, 2942.463],
76
- [126.0, 1.083, 20.775],
77
- [115.0, 0.645, 0.98],
78
- [103.0, 0.636, 4694.003],
79
- [102.0, 0.976, 15720.839],
80
- [102.0, 4.267, 7.114],
81
- [99.0, 6.21, 2146.17],
82
- [98.0, 0.68, 155.42],
83
- [86.0, 5.98, 161000.69],
84
- [85.0, 1.3, 6275.96],
85
- [85.0, 3.67, 71430.7],
86
- [80.0, 1.81, 17260.15],
87
- [79.0, 3.04, 12036.46],
88
- [75.0, 1.76, 5088.63],
89
- [74.0, 3.5, 3154.69],
90
- [74.0, 4.68, 801.82],
91
- [70.0, 0.83, 9437.76],
92
- [62.0, 3.98, 8827.39],
93
- [61.0, 1.82, 7084.9],
94
- [57.0, 2.78, 6286.6],
95
- [56.0, 4.39, 14143.5],
96
- [56.0, 3.47, 6279.55],
97
- [52.0, 0.19, 12139.55],
98
- [52.0, 1.33, 1748.02],
99
- [51.0, 0.28, 5856.48],
100
- [49.0, 0.49, 1194.45],
101
- [41.0, 5.37, 8429.24],
102
- [41.0, 2.4, 19651.05],
103
- [39.0, 6.17, 10447.39],
104
- [37.0, 6.04, 10213.29],
105
- [37.0, 2.57, 1059.38],
106
- [36.0, 1.71, 2352.87],
107
- [36.0, 1.78, 6812.77],
108
- [33.0, 0.59, 17789.85],
109
- [30.0, 0.44, 83996.85],
110
- [30.0, 2.74, 1349.87],
111
- [25.0, 3.16, 4690.48]]),
112
- 'L1': np.array(
113
- [[628331966747.0, 0.0, 0.0],
114
- [206059.0, 2.678235, 6283.07585],
115
- [4303.0, 2.6351, 12566.1517],
116
- [425.0, 1.59, 3.523],
117
- [119.0, 5.796, 26.298],
118
- [109.0, 2.966, 1577.344],
119
- [93.0, 2.59, 18849.23],
120
- [72.0, 1.14, 529.69],
121
- [68.0, 1.87, 398.15],
122
- [67.0, 4.41, 5507.55],
123
- [59.0, 2.89, 5223.69],
124
- [56.0, 2.17, 155.42],
125
- [45.0, 0.4, 796.3],
126
- [36.0, 0.47, 775.52],
127
- [29.0, 2.65, 7.11],
128
- [21.0, 5.34, 0.98],
129
- [19.0, 1.85, 5486.78],
130
- [19.0, 4.97, 213.3],
131
- [17.0, 2.99, 6275.96],
132
- [16.0, 0.03, 2544.31],
133
- [16.0, 1.43, 2146.17],
134
- [15.0, 1.21, 10977.08],
135
- [12.0, 2.83, 1748.02],
136
- [12.0, 3.26, 5088.63],
137
- [12.0, 5.27, 1194.45],
138
- [12.0, 2.08, 4694.0],
139
- [11.0, 0.77, 553.57],
140
- [10.0, 1.3, 6286.6],
141
- [10.0, 4.24, 1349.87],
142
- [9.0, 2.7, 242.73],
143
- [9.0, 5.64, 951.72],
144
- [8.0, 5.3, 2352.87],
145
- [6.0, 2.65, 9437.76],
146
- [6.0, 4.67, 4690.48]]),
147
- 'L2': np.array(
148
- [[52919.0, 0.0, 0.0],
149
- [8720.0, 1.0721, 6283.0758],
150
- [309.0, 0.867, 12566.152],
151
- [27.0, 0.05, 3.52],
152
- [16.0, 5.19, 26.3],
153
- [16.0, 3.68, 155.42],
154
- [10.0, 0.76, 18849.23],
155
- [9.0, 2.06, 77713.77],
156
- [7.0, 0.83, 775.52],
157
- [5.0, 4.66, 1577.34],
158
- [4.0, 1.03, 7.11],
159
- [4.0, 3.44, 5573.14],
160
- [3.0, 5.14, 796.3],
161
- [3.0, 6.05, 5507.55],
162
- [3.0, 1.19, 242.73],
163
- [3.0, 6.12, 529.69],
164
- [3.0, 0.31, 398.15],
165
- [3.0, 2.28, 553.57],
166
- [2.0, 4.38, 5223.69],
167
- [2.0, 3.75, 0.98]]),
168
- 'L3': np.array(
169
- [[289.0, 5.844, 6283.076],
170
- [35.0, 0.0, 0.0],
171
- [17.0, 5.49, 12566.15],
172
- [3.0, 5.2, 155.42],
173
- [1.0, 4.72, 3.52],
174
- [1.0, 5.3, 18849.23],
175
- [1.0, 5.97, 242.73]]),
176
- 'L4': np.array(
177
- [[114.0, 3.142, 0.0],
178
- [8.0, 4.13, 6283.08],
179
- [1.0, 3.84, 12566.15]]),
180
- 'L5': np.array(
181
- [[1.0, 3.14, 0.0]]),
182
- 'B0': np.array(
183
- [[280.0, 3.199, 84334.662],
184
- [102.0, 5.422, 5507.553],
185
- [80.0, 3.88, 5223.69],
186
- [44.0, 3.7, 2352.87],
187
- [32.0, 4.0, 1577.34]]),
188
- 'B1': np.array(
189
- [[9.0, 3.9, 5507.55],
190
- [6.0, 1.73, 5223.69]]),
191
- 'R0': np.array(
192
- [[100013989.0, 0.0, 0.0],
193
- [1670700.0, 3.0984635, 6283.07585],
194
- [13956.0, 3.05525, 12566.1517],
195
- [3084.0, 5.1985, 77713.7715],
196
- [1628.0, 1.1739, 5753.3849],
197
- [1576.0, 2.8469, 7860.4194],
198
- [925.0, 5.453, 11506.77],
199
- [542.0, 4.564, 3930.21],
200
- [472.0, 3.661, 5884.927],
201
- [346.0, 0.964, 5507.553],
202
- [329.0, 5.9, 5223.694],
203
- [307.0, 0.299, 5573.143],
204
- [243.0, 4.273, 11790.629],
205
- [212.0, 5.847, 1577.344],
206
- [186.0, 5.022, 10977.079],
207
- [175.0, 3.012, 18849.228],
208
- [110.0, 5.055, 5486.778],
209
- [98.0, 0.89, 6069.78],
210
- [86.0, 5.69, 15720.84],
211
- [86.0, 1.27, 161000.69],
212
- [65.0, 0.27, 17260.15],
213
- [63.0, 0.92, 529.69],
214
- [57.0, 2.01, 83996.85],
215
- [56.0, 5.24, 71430.7],
216
- [49.0, 3.25, 2544.31],
217
- [47.0, 2.58, 775.52],
218
- [45.0, 5.54, 9437.76],
219
- [43.0, 6.01, 6275.96],
220
- [39.0, 5.36, 4694.0],
221
- [38.0, 2.39, 8827.39],
222
- [37.0, 0.83, 19651.05],
223
- [37.0, 4.9, 12139.55],
224
- [36.0, 1.67, 12036.46],
225
- [35.0, 1.84, 2942.46],
226
- [33.0, 0.24, 7084.9],
227
- [32.0, 0.18, 5088.63],
228
- [32.0, 1.78, 398.15],
229
- [28.0, 1.21, 6286.6],
230
- [28.0, 1.9, 6279.55],
231
- [26.0, 4.59, 10447.39]]),
232
- 'R1': np.array(
233
- [[103019.0, 1.10749, 6283.07585],
234
- [1721.0, 1.0644, 12566.1517],
235
- [702.0, 3.142, 0.0],
236
- [32.0, 1.02, 18849.23],
237
- [31.0, 2.84, 5507.55],
238
- [25.0, 1.32, 5223.69],
239
- [18.0, 1.42, 1577.34],
240
- [10.0, 5.91, 10977.08],
241
- [9.0, 1.42, 6275.96],
242
- [9.0, 0.27, 5486.78]]),
243
- 'R2': np.array(
244
- [[4359.0, 5.7846, 6283.0758],
245
- [124.0, 5.579, 12566.152],
246
- [12.0, 3.14, 0.0],
247
- [9.0, 3.63, 77713.77],
248
- [6.0, 1.87, 5573.14],
249
- [3.0, 5.47, 18849.23]]),
250
- 'R3': np.array(
251
- [[145.0, 4.273, 6283.076],
252
- [7.0, 3.92, 12566.15]]),
253
- 'R4': np.array(
254
- [[4.0, 2.56, 6283.08]])
255
- }
256
-
257
- resize_mapping = {
258
- 'L1': (64, 3), 'L2': (64, 3), 'L3': (64, 3), 'L4': (64, 3), 'L5': (64, 3),
259
- 'B1': (5, 3), 'R1': (40, 3), 'R2': (40, 3), 'R3': (40, 3), 'R4': (40, 3)}
260
-
261
- # make arrays uniform size for efficient broadcasting in numba, fill with 0s
262
- # np.resize does not work because it fills with repeated copies
263
- for key, dims in resize_mapping.items():
264
- new_rows = dims[0] - TABLE_1_DICT[key].shape[0]
265
- TABLE_1_DICT[key] = np.append(TABLE_1_DICT[key], np.zeros((new_rows, 3)),
266
- axis=0)
267
-
268
-
269
- HELIO_LONG_TABLE = np.array([TABLE_1_DICT['L0'],
270
- TABLE_1_DICT['L1'],
271
- TABLE_1_DICT['L2'],
272
- TABLE_1_DICT['L3'],
273
- TABLE_1_DICT['L4'],
274
- TABLE_1_DICT['L5']])
275
-
276
-
277
- HELIO_LAT_TABLE = np.array([TABLE_1_DICT['B0'],
278
- TABLE_1_DICT['B1']])
279
-
280
-
281
- HELIO_RADIUS_TABLE = np.array([TABLE_1_DICT['R0'],
282
- TABLE_1_DICT['R1'],
283
- TABLE_1_DICT['R2'],
284
- TABLE_1_DICT['R3'],
285
- TABLE_1_DICT['R4']])
46
+ # heliocentric longitude coefficients
47
+ L0 = np.array([
48
+ [175347046.0, 0.0, 0.0],
49
+ [3341656.0, 4.6692568, 6283.07585],
50
+ [34894.0, 4.6261, 12566.1517],
51
+ [3497.0, 2.7441, 5753.3849],
52
+ [3418.0, 2.8289, 3.5231],
53
+ [3136.0, 3.6277, 77713.7715],
54
+ [2676.0, 4.4181, 7860.4194],
55
+ [2343.0, 6.1352, 3930.2097],
56
+ [1324.0, 0.7425, 11506.7698],
57
+ [1273.0, 2.0371, 529.691],
58
+ [1199.0, 1.1096, 1577.3435],
59
+ [990.0, 5.233, 5884.927],
60
+ [902.0, 2.045, 26.298],
61
+ [857.0, 3.508, 398.149],
62
+ [780.0, 1.179, 5223.694],
63
+ [753.0, 2.533, 5507.553],
64
+ [505.0, 4.583, 18849.228],
65
+ [492.0, 4.205, 775.523],
66
+ [357.0, 2.92, 0.067],
67
+ [317.0, 5.849, 11790.629],
68
+ [284.0, 1.899, 796.298],
69
+ [271.0, 0.315, 10977.079],
70
+ [243.0, 0.345, 5486.778],
71
+ [206.0, 4.806, 2544.314],
72
+ [205.0, 1.869, 5573.143],
73
+ [202.0, 2.458, 6069.777],
74
+ [156.0, 0.833, 213.299],
75
+ [132.0, 3.411, 2942.463],
76
+ [126.0, 1.083, 20.775],
77
+ [115.0, 0.645, 0.98],
78
+ [103.0, 0.636, 4694.003],
79
+ [102.0, 0.976, 15720.839],
80
+ [102.0, 4.267, 7.114],
81
+ [99.0, 6.21, 2146.17],
82
+ [98.0, 0.68, 155.42],
83
+ [86.0, 5.98, 161000.69],
84
+ [85.0, 1.3, 6275.96],
85
+ [85.0, 3.67, 71430.7],
86
+ [80.0, 1.81, 17260.15],
87
+ [79.0, 3.04, 12036.46],
88
+ [75.0, 1.76, 5088.63],
89
+ [74.0, 3.5, 3154.69],
90
+ [74.0, 4.68, 801.82],
91
+ [70.0, 0.83, 9437.76],
92
+ [62.0, 3.98, 8827.39],
93
+ [61.0, 1.82, 7084.9],
94
+ [57.0, 2.78, 6286.6],
95
+ [56.0, 4.39, 14143.5],
96
+ [56.0, 3.47, 6279.55],
97
+ [52.0, 0.19, 12139.55],
98
+ [52.0, 1.33, 1748.02],
99
+ [51.0, 0.28, 5856.48],
100
+ [49.0, 0.49, 1194.45],
101
+ [41.0, 5.37, 8429.24],
102
+ [41.0, 2.4, 19651.05],
103
+ [39.0, 6.17, 10447.39],
104
+ [37.0, 6.04, 10213.29],
105
+ [37.0, 2.57, 1059.38],
106
+ [36.0, 1.71, 2352.87],
107
+ [36.0, 1.78, 6812.77],
108
+ [33.0, 0.59, 17789.85],
109
+ [30.0, 0.44, 83996.85],
110
+ [30.0, 2.74, 1349.87],
111
+ [25.0, 3.16, 4690.48]
112
+ ])
113
+ L1 = np.array([
114
+ [628331966747.0, 0.0, 0.0],
115
+ [206059.0, 2.678235, 6283.07585],
116
+ [4303.0, 2.6351, 12566.1517],
117
+ [425.0, 1.59, 3.523],
118
+ [119.0, 5.796, 26.298],
119
+ [109.0, 2.966, 1577.344],
120
+ [93.0, 2.59, 18849.23],
121
+ [72.0, 1.14, 529.69],
122
+ [68.0, 1.87, 398.15],
123
+ [67.0, 4.41, 5507.55],
124
+ [59.0, 2.89, 5223.69],
125
+ [56.0, 2.17, 155.42],
126
+ [45.0, 0.4, 796.3],
127
+ [36.0, 0.47, 775.52],
128
+ [29.0, 2.65, 7.11],
129
+ [21.0, 5.34, 0.98],
130
+ [19.0, 1.85, 5486.78],
131
+ [19.0, 4.97, 213.3],
132
+ [17.0, 2.99, 6275.96],
133
+ [16.0, 0.03, 2544.31],
134
+ [16.0, 1.43, 2146.17],
135
+ [15.0, 1.21, 10977.08],
136
+ [12.0, 2.83, 1748.02],
137
+ [12.0, 3.26, 5088.63],
138
+ [12.0, 5.27, 1194.45],
139
+ [12.0, 2.08, 4694.0],
140
+ [11.0, 0.77, 553.57],
141
+ [10.0, 1.3, 6286.6],
142
+ [10.0, 4.24, 1349.87],
143
+ [9.0, 2.7, 242.73],
144
+ [9.0, 5.64, 951.72],
145
+ [8.0, 5.3, 2352.87],
146
+ [6.0, 2.65, 9437.76],
147
+ [6.0, 4.67, 4690.48]
148
+ ])
149
+ L2 = np.array([
150
+ [52919.0, 0.0, 0.0],
151
+ [8720.0, 1.0721, 6283.0758],
152
+ [309.0, 0.867, 12566.152],
153
+ [27.0, 0.05, 3.52],
154
+ [16.0, 5.19, 26.3],
155
+ [16.0, 3.68, 155.42],
156
+ [10.0, 0.76, 18849.23],
157
+ [9.0, 2.06, 77713.77],
158
+ [7.0, 0.83, 775.52],
159
+ [5.0, 4.66, 1577.34],
160
+ [4.0, 1.03, 7.11],
161
+ [4.0, 3.44, 5573.14],
162
+ [3.0, 5.14, 796.3],
163
+ [3.0, 6.05, 5507.55],
164
+ [3.0, 1.19, 242.73],
165
+ [3.0, 6.12, 529.69],
166
+ [3.0, 0.31, 398.15],
167
+ [3.0, 2.28, 553.57],
168
+ [2.0, 4.38, 5223.69],
169
+ [2.0, 3.75, 0.98]
170
+ ])
171
+ L3 = np.array([
172
+ [289.0, 5.844, 6283.076],
173
+ [35.0, 0.0, 0.0],
174
+ [17.0, 5.49, 12566.15],
175
+ [3.0, 5.2, 155.42],
176
+ [1.0, 4.72, 3.52],
177
+ [1.0, 5.3, 18849.23],
178
+ [1.0, 5.97, 242.73]
179
+ ])
180
+ L4 = np.array([
181
+ [114.0, 3.142, 0.0],
182
+ [8.0, 4.13, 6283.08],
183
+ [1.0, 3.84, 12566.15]
184
+ ])
185
+ L5 = np.array([
186
+ [1.0, 3.14, 0.0]
187
+ ])
188
+
189
+
190
+ # heliocentric latitude coefficients
191
+ B0 = np.array([
192
+ [280.0, 3.199, 84334.662],
193
+ [102.0, 5.422, 5507.553],
194
+ [80.0, 3.88, 5223.69],
195
+ [44.0, 3.7, 2352.87],
196
+ [32.0, 4.0, 1577.34]
197
+ ])
198
+ B1 = np.array([
199
+ [9.0, 3.9, 5507.55],
200
+ [6.0, 1.73, 5223.69]
201
+ ])
286
202
 
287
203
 
204
+ # heliocentric radius coefficients
205
+ R0 = np.array([
206
+ [100013989.0, 0.0, 0.0],
207
+ [1670700.0, 3.0984635, 6283.07585],
208
+ [13956.0, 3.05525, 12566.1517],
209
+ [3084.0, 5.1985, 77713.7715],
210
+ [1628.0, 1.1739, 5753.3849],
211
+ [1576.0, 2.8469, 7860.4194],
212
+ [925.0, 5.453, 11506.77],
213
+ [542.0, 4.564, 3930.21],
214
+ [472.0, 3.661, 5884.927],
215
+ [346.0, 0.964, 5507.553],
216
+ [329.0, 5.9, 5223.694],
217
+ [307.0, 0.299, 5573.143],
218
+ [243.0, 4.273, 11790.629],
219
+ [212.0, 5.847, 1577.344],
220
+ [186.0, 5.022, 10977.079],
221
+ [175.0, 3.012, 18849.228],
222
+ [110.0, 5.055, 5486.778],
223
+ [98.0, 0.89, 6069.78],
224
+ [86.0, 5.69, 15720.84],
225
+ [86.0, 1.27, 161000.69],
226
+ [65.0, 0.27, 17260.15],
227
+ [63.0, 0.92, 529.69],
228
+ [57.0, 2.01, 83996.85],
229
+ [56.0, 5.24, 71430.7],
230
+ [49.0, 3.25, 2544.31],
231
+ [47.0, 2.58, 775.52],
232
+ [45.0, 5.54, 9437.76],
233
+ [43.0, 6.01, 6275.96],
234
+ [39.0, 5.36, 4694.0],
235
+ [38.0, 2.39, 8827.39],
236
+ [37.0, 0.83, 19651.05],
237
+ [37.0, 4.9, 12139.55],
238
+ [36.0, 1.67, 12036.46],
239
+ [35.0, 1.84, 2942.46],
240
+ [33.0, 0.24, 7084.9],
241
+ [32.0, 0.18, 5088.63],
242
+ [32.0, 1.78, 398.15],
243
+ [28.0, 1.21, 6286.6],
244
+ [28.0, 1.9, 6279.55],
245
+ [26.0, 4.59, 10447.39]
246
+ ])
247
+ R1 = np.array([
248
+ [103019.0, 1.10749, 6283.07585],
249
+ [1721.0, 1.0644, 12566.1517],
250
+ [702.0, 3.142, 0.0],
251
+ [32.0, 1.02, 18849.23],
252
+ [31.0, 2.84, 5507.55],
253
+ [25.0, 1.32, 5223.69],
254
+ [18.0, 1.42, 1577.34],
255
+ [10.0, 5.91, 10977.08],
256
+ [9.0, 1.42, 6275.96],
257
+ [9.0, 0.27, 5486.78]
258
+ ])
259
+ R2 = np.array([
260
+ [4359.0, 5.7846, 6283.0758],
261
+ [124.0, 5.579, 12566.152],
262
+ [12.0, 3.14, 0.0],
263
+ [9.0, 3.63, 77713.77],
264
+ [6.0, 1.87, 5573.14],
265
+ [3.0, 5.47, 18849.23]
266
+ ])
267
+ R3 = np.array([
268
+ [145.0, 4.273, 6283.076],
269
+ [7.0, 3.92, 12566.15]
270
+ ])
271
+ R4 = np.array([
272
+ [4.0, 2.56, 6283.08]
273
+ ])
274
+
275
+
276
+ # longitude and obliquity nutation coefficients
288
277
  NUTATION_ABCD_ARRAY = np.array([
289
278
  [-171996, -174.2, 92025, 8.9],
290
279
  [-13187, -1.6, 5736, -3.1],
@@ -351,7 +340,6 @@ NUTATION_ABCD_ARRAY = np.array([
351
340
  [-3, 0, 0, 0],
352
341
  ])
353
342
 
354
-
355
343
  NUTATION_YTERM_ARRAY = np.array([
356
344
  [0, 0, 0, 0, 1],
357
345
  [-2, 0, 0, 2, 2],
@@ -468,60 +456,35 @@ def julian_ephemeris_millennium(julian_ephemeris_century):
468
456
  return jme
469
457
 
470
458
 
459
+ # omit type signature here; specifying read-only arrays requires use of the
460
+ # numba.types API, meaning numba must be available to import.
461
+ # https://github.com/numba/numba/issues/4511
462
+ @jcompile(nopython=True)
463
+ def sum_mult_cos_add_mult(arr, x):
464
+ # shared calculation used for heliocentric longitude, latitude, and radius
465
+ s = 0.
466
+ for row in range(arr.shape[0]):
467
+ s += arr[row, 0] * np.cos(arr[row, 1] + arr[row, 2] * x)
468
+ return s
469
+
471
470
  @jcompile('float64(float64)', nopython=True)
472
471
  def heliocentric_longitude(jme):
473
- l0 = 0.0
474
- l1 = 0.0
475
- l2 = 0.0
476
- l3 = 0.0
477
- l4 = 0.0
478
- l5 = 0.0
479
-
480
- for row in range(HELIO_LONG_TABLE.shape[1]):
481
- l0 += (HELIO_LONG_TABLE[0, row, 0]
482
- * np.cos(HELIO_LONG_TABLE[0, row, 1]
483
- + HELIO_LONG_TABLE[0, row, 2] * jme)
484
- )
485
- l1 += (HELIO_LONG_TABLE[1, row, 0]
486
- * np.cos(HELIO_LONG_TABLE[1, row, 1]
487
- + HELIO_LONG_TABLE[1, row, 2] * jme)
488
- )
489
- l2 += (HELIO_LONG_TABLE[2, row, 0]
490
- * np.cos(HELIO_LONG_TABLE[2, row, 1]
491
- + HELIO_LONG_TABLE[2, row, 2] * jme)
492
- )
493
- l3 += (HELIO_LONG_TABLE[3, row, 0]
494
- * np.cos(HELIO_LONG_TABLE[3, row, 1]
495
- + HELIO_LONG_TABLE[3, row, 2] * jme)
496
- )
497
- l4 += (HELIO_LONG_TABLE[4, row, 0]
498
- * np.cos(HELIO_LONG_TABLE[4, row, 1]
499
- + HELIO_LONG_TABLE[4, row, 2] * jme)
500
- )
501
- l5 += (HELIO_LONG_TABLE[5, row, 0]
502
- * np.cos(HELIO_LONG_TABLE[5, row, 1]
503
- + HELIO_LONG_TABLE[5, row, 2] * jme)
504
- )
472
+ l0 = sum_mult_cos_add_mult(L0, jme)
473
+ l1 = sum_mult_cos_add_mult(L1, jme)
474
+ l2 = sum_mult_cos_add_mult(L2, jme)
475
+ l3 = sum_mult_cos_add_mult(L3, jme)
476
+ l4 = sum_mult_cos_add_mult(L4, jme)
477
+ l5 = sum_mult_cos_add_mult(L5, jme)
505
478
 
506
479
  l_rad = (l0 + l1 * jme + l2 * jme**2 + l3 * jme**3 + l4 * jme**4 +
507
480
  l5 * jme**5)/10**8
508
481
  l = np.rad2deg(l_rad)
509
482
  return l % 360
510
483
 
511
-
512
484
  @jcompile('float64(float64)', nopython=True)
513
485
  def heliocentric_latitude(jme):
514
- b0 = 0.0
515
- b1 = 0.0
516
- for row in range(HELIO_LAT_TABLE.shape[1]):
517
- b0 += (HELIO_LAT_TABLE[0, row, 0]
518
- * np.cos(HELIO_LAT_TABLE[0, row, 1]
519
- + HELIO_LAT_TABLE[0, row, 2] * jme)
520
- )
521
- b1 += (HELIO_LAT_TABLE[1, row, 0]
522
- * np.cos(HELIO_LAT_TABLE[1, row, 1]
523
- + HELIO_LAT_TABLE[1, row, 2] * jme)
524
- )
486
+ b0 = sum_mult_cos_add_mult(B0, jme)
487
+ b1 = sum_mult_cos_add_mult(B1, jme)
525
488
 
526
489
  b_rad = (b0 + b1 * jme)/10**8
527
490
  b = np.rad2deg(b_rad)
@@ -530,32 +493,11 @@ def heliocentric_latitude(jme):
530
493
 
531
494
  @jcompile('float64(float64)', nopython=True)
532
495
  def heliocentric_radius_vector(jme):
533
- r0 = 0.0
534
- r1 = 0.0
535
- r2 = 0.0
536
- r3 = 0.0
537
- r4 = 0.0
538
- for row in range(HELIO_RADIUS_TABLE.shape[1]):
539
- r0 += (HELIO_RADIUS_TABLE[0, row, 0]
540
- * np.cos(HELIO_RADIUS_TABLE[0, row, 1]
541
- + HELIO_RADIUS_TABLE[0, row, 2] * jme)
542
- )
543
- r1 += (HELIO_RADIUS_TABLE[1, row, 0]
544
- * np.cos(HELIO_RADIUS_TABLE[1, row, 1]
545
- + HELIO_RADIUS_TABLE[1, row, 2] * jme)
546
- )
547
- r2 += (HELIO_RADIUS_TABLE[2, row, 0]
548
- * np.cos(HELIO_RADIUS_TABLE[2, row, 1]
549
- + HELIO_RADIUS_TABLE[2, row, 2] * jme)
550
- )
551
- r3 += (HELIO_RADIUS_TABLE[3, row, 0]
552
- * np.cos(HELIO_RADIUS_TABLE[3, row, 1]
553
- + HELIO_RADIUS_TABLE[3, row, 2] * jme)
554
- )
555
- r4 += (HELIO_RADIUS_TABLE[4, row, 0]
556
- * np.cos(HELIO_RADIUS_TABLE[4, row, 1]
557
- + HELIO_RADIUS_TABLE[4, row, 2] * jme)
558
- )
496
+ r0 = sum_mult_cos_add_mult(R0, jme)
497
+ r1 = sum_mult_cos_add_mult(R1, jme)
498
+ r2 = sum_mult_cos_add_mult(R2, jme)
499
+ r3 = sum_mult_cos_add_mult(R3, jme)
500
+ r4 = sum_mult_cos_add_mult(R4, jme)
559
501
 
560
502
  r = (r0 + r1 * jme + r2 * jme**2 + r3 * jme**3 + r4 * jme**4)/10**8
561
503
  return r
@@ -618,40 +560,36 @@ def moon_ascending_longitude(julian_ephemeris_century):
618
560
  return x4
619
561
 
620
562
 
621
- @jcompile('float64(float64, float64, float64, float64, float64, float64)',
622
- nopython=True)
623
- def longitude_nutation(julian_ephemeris_century, x0, x1, x2, x3, x4):
624
- delta_psi_sum = 0
563
+ @jcompile(
564
+ 'void(float64, float64, float64, float64, float64, float64, float64[:])',
565
+ nopython=True)
566
+ def longitude_obliquity_nutation(julian_ephemeris_century, x0, x1, x2, x3, x4,
567
+ out):
568
+ delta_psi_sum = 0.0
569
+ delta_eps_sum = 0.0
625
570
  for row in range(NUTATION_YTERM_ARRAY.shape[0]):
626
571
  a = NUTATION_ABCD_ARRAY[row, 0]
627
572
  b = NUTATION_ABCD_ARRAY[row, 1]
628
- argsin = (NUTATION_YTERM_ARRAY[row, 0]*x0 +
629
- NUTATION_YTERM_ARRAY[row, 1]*x1 +
630
- NUTATION_YTERM_ARRAY[row, 2]*x2 +
631
- NUTATION_YTERM_ARRAY[row, 3]*x3 +
632
- NUTATION_YTERM_ARRAY[row, 4]*x4)
633
- term = (a + b * julian_ephemeris_century) * np.sin(np.radians(argsin))
634
- delta_psi_sum += term
635
- delta_psi = delta_psi_sum*1.0/36000000
636
- return delta_psi
637
-
638
-
639
- @jcompile('float64(float64, float64, float64, float64, float64, float64)',
640
- nopython=True)
641
- def obliquity_nutation(julian_ephemeris_century, x0, x1, x2, x3, x4):
642
- delta_eps_sum = 0.0
643
- for row in range(NUTATION_YTERM_ARRAY.shape[0]):
644
573
  c = NUTATION_ABCD_ARRAY[row, 2]
645
574
  d = NUTATION_ABCD_ARRAY[row, 3]
646
- argcos = (NUTATION_YTERM_ARRAY[row, 0]*x0 +
647
- NUTATION_YTERM_ARRAY[row, 1]*x1 +
648
- NUTATION_YTERM_ARRAY[row, 2]*x2 +
649
- NUTATION_YTERM_ARRAY[row, 3]*x3 +
650
- NUTATION_YTERM_ARRAY[row, 4]*x4)
651
- term = (c + d * julian_ephemeris_century) * np.cos(np.radians(argcos))
652
- delta_eps_sum += term
575
+ arg = np.radians(
576
+ NUTATION_YTERM_ARRAY[row, 0]*x0 +
577
+ NUTATION_YTERM_ARRAY[row, 1]*x1 +
578
+ NUTATION_YTERM_ARRAY[row, 2]*x2 +
579
+ NUTATION_YTERM_ARRAY[row, 3]*x3 +
580
+ NUTATION_YTERM_ARRAY[row, 4]*x4
581
+ )
582
+ delta_psi_sum += (a + b * julian_ephemeris_century) * np.sin(arg)
583
+ delta_eps_sum += (c + d * julian_ephemeris_century) * np.cos(arg)
584
+ delta_psi = delta_psi_sum*1.0/36000000
653
585
  delta_eps = delta_eps_sum*1.0/36000000
654
- return delta_eps
586
+ # seems like we ought to be able to return a tuple here instead
587
+ # of resorting to `out`, but returning a UniTuple from this
588
+ # function caused calculations elsewhere to give the wrong result.
589
+ # very difficult to investigate since it did not occur when using
590
+ # object mode. issue was observed on numba 0.56.4
591
+ out[0] = delta_psi
592
+ out[1] = delta_eps
655
593
 
656
594
 
657
595
  @jcompile('float64(float64)', nopython=True)
@@ -704,22 +642,27 @@ def apparent_sidereal_time(mean_sidereal_time, longitude_nutation,
704
642
  def geocentric_sun_right_ascension(apparent_sun_longitude,
705
643
  true_ecliptic_obliquity,
706
644
  geocentric_latitude):
707
- num = (np.sin(np.radians(apparent_sun_longitude))
708
- * np.cos(np.radians(true_ecliptic_obliquity))
645
+ true_ecliptic_obliquity_rad = np.radians(true_ecliptic_obliquity)
646
+ apparent_sun_longitude_rad = np.radians(apparent_sun_longitude)
647
+
648
+ num = (np.sin(apparent_sun_longitude_rad)
649
+ * np.cos(true_ecliptic_obliquity_rad)
709
650
  - np.tan(np.radians(geocentric_latitude))
710
- * np.sin(np.radians(true_ecliptic_obliquity)))
711
- alpha = np.degrees(np.arctan2(num, np.cos(
712
- np.radians(apparent_sun_longitude))))
651
+ * np.sin(true_ecliptic_obliquity_rad))
652
+ alpha = np.degrees(np.arctan2(num, np.cos(apparent_sun_longitude_rad)))
713
653
  return alpha % 360
714
654
 
715
655
 
716
656
  @jcompile('float64(float64, float64, float64)', nopython=True)
717
657
  def geocentric_sun_declination(apparent_sun_longitude, true_ecliptic_obliquity,
718
658
  geocentric_latitude):
719
- delta = np.degrees(np.arcsin(np.sin(np.radians(geocentric_latitude)) *
720
- np.cos(np.radians(true_ecliptic_obliquity)) +
721
- np.cos(np.radians(geocentric_latitude)) *
722
- np.sin(np.radians(true_ecliptic_obliquity)) *
659
+ geocentric_latitude_rad = np.radians(geocentric_latitude)
660
+ true_ecliptic_obliquity_rad = np.radians(true_ecliptic_obliquity)
661
+
662
+ delta = np.degrees(np.arcsin(np.sin(geocentric_latitude_rad) *
663
+ np.cos(true_ecliptic_obliquity_rad) +
664
+ np.cos(geocentric_latitude_rad) *
665
+ np.sin(true_ecliptic_obliquity_rad) *
723
666
  np.sin(np.radians(apparent_sun_longitude))))
724
667
  return delta
725
668
 
@@ -761,11 +704,15 @@ def yterm(u, observer_latitude, observer_elevation):
761
704
  @jcompile('float64(float64, float64,float64, float64)', nopython=True)
762
705
  def parallax_sun_right_ascension(xterm, equatorial_horizontal_parallax,
763
706
  local_hour_angle, geocentric_sun_declination):
764
- num = (-xterm * np.sin(np.radians(equatorial_horizontal_parallax))
765
- * np.sin(np.radians(local_hour_angle)))
707
+ equatorial_horizontal_parallax_rad = \
708
+ np.radians(equatorial_horizontal_parallax)
709
+ local_hour_angle_rad = np.radians(local_hour_angle)
710
+
711
+ num = (-xterm * np.sin(equatorial_horizontal_parallax_rad)
712
+ * np.sin(local_hour_angle_rad))
766
713
  denom = (np.cos(np.radians(geocentric_sun_declination))
767
- - xterm * np.sin(np.radians(equatorial_horizontal_parallax))
768
- * np.cos(np.radians(local_hour_angle)))
714
+ - xterm * np.sin(equatorial_horizontal_parallax_rad)
715
+ * np.cos(local_hour_angle_rad))
769
716
  delta_alpha = np.degrees(np.arctan2(num, denom))
770
717
  return delta_alpha
771
718
 
@@ -783,11 +730,15 @@ def topocentric_sun_declination(geocentric_sun_declination, xterm, yterm,
783
730
  equatorial_horizontal_parallax,
784
731
  parallax_sun_right_ascension,
785
732
  local_hour_angle):
786
- num = ((np.sin(np.radians(geocentric_sun_declination)) - yterm
787
- * np.sin(np.radians(equatorial_horizontal_parallax)))
733
+ geocentric_sun_declination_rad = np.radians(geocentric_sun_declination)
734
+ equatorial_horizontal_parallax_rad = \
735
+ np.radians(equatorial_horizontal_parallax)
736
+
737
+ num = ((np.sin(geocentric_sun_declination_rad) - yterm
738
+ * np.sin(equatorial_horizontal_parallax_rad))
788
739
  * np.cos(np.radians(parallax_sun_right_ascension)))
789
- denom = (np.cos(np.radians(geocentric_sun_declination)) - xterm
790
- * np.sin(np.radians(equatorial_horizontal_parallax))
740
+ denom = (np.cos(geocentric_sun_declination_rad) - xterm
741
+ * np.sin(equatorial_horizontal_parallax_rad)
791
742
  * np.cos(np.radians(local_hour_angle)))
792
743
  delta = np.degrees(np.arctan2(num, denom))
793
744
  return delta
@@ -805,11 +756,13 @@ def topocentric_elevation_angle_without_atmosphere(observer_latitude,
805
756
  topocentric_sun_declination,
806
757
  topocentric_local_hour_angle
807
758
  ):
759
+ observer_latitude_rad = np.radians(observer_latitude)
760
+ topocentric_sun_declination_rad = np.radians(topocentric_sun_declination)
808
761
  e0 = np.degrees(np.arcsin(
809
- np.sin(np.radians(observer_latitude))
810
- * np.sin(np.radians(topocentric_sun_declination))
811
- + np.cos(np.radians(observer_latitude))
812
- * np.cos(np.radians(topocentric_sun_declination))
762
+ np.sin(observer_latitude_rad)
763
+ * np.sin(topocentric_sun_declination_rad)
764
+ + np.cos(observer_latitude_rad)
765
+ * np.cos(topocentric_sun_declination_rad)
813
766
  * np.cos(np.radians(topocentric_local_hour_angle))))
814
767
  return e0
815
768
 
@@ -847,11 +800,13 @@ def topocentric_zenith_angle(topocentric_elevation_angle):
847
800
  def topocentric_astronomers_azimuth(topocentric_local_hour_angle,
848
801
  topocentric_sun_declination,
849
802
  observer_latitude):
850
- num = np.sin(np.radians(topocentric_local_hour_angle))
851
- denom = (np.cos(np.radians(topocentric_local_hour_angle))
852
- * np.sin(np.radians(observer_latitude))
803
+ topocentric_local_hour_angle_rad = np.radians(topocentric_local_hour_angle)
804
+ observer_latitude_rad = np.radians(observer_latitude)
805
+ num = np.sin(topocentric_local_hour_angle_rad)
806
+ denom = (np.cos(topocentric_local_hour_angle_rad)
807
+ * np.sin(observer_latitude_rad)
853
808
  - np.tan(np.radians(topocentric_sun_declination))
854
- * np.cos(np.radians(observer_latitude)))
809
+ * np.cos(observer_latitude_rad))
855
810
  gamma = np.degrees(np.arctan2(num, denom))
856
811
  return gamma % 360
857
812
 
@@ -922,8 +877,10 @@ def solar_position_loop(unixtime, loc_args, out):
922
877
  x2 = mean_anomaly_moon(jce)
923
878
  x3 = moon_argument_latitude(jce)
924
879
  x4 = moon_ascending_longitude(jce)
925
- delta_psi = longitude_nutation(jce, x0, x1, x2, x3, x4)
926
- delta_epsilon = obliquity_nutation(jce, x0, x1, x2, x3, x4)
880
+ l_o_nutation = np.empty((2,))
881
+ longitude_obliquity_nutation(jce, x0, x1, x2, x3, x4, l_o_nutation)
882
+ delta_psi = l_o_nutation[0]
883
+ delta_epsilon = l_o_nutation[1]
927
884
  epsilon0 = mean_ecliptic_obliquity(jme)
928
885
  epsilon = true_ecliptic_obliquity(epsilon0, delta_epsilon)
929
886
  delta_tau = aberration_correction(R)
@@ -1034,8 +991,10 @@ def solar_position_numpy(unixtime, lat, lon, elev, pressure, temp, delta_t,
1034
991
  x2 = mean_anomaly_moon(jce)
1035
992
  x3 = moon_argument_latitude(jce)
1036
993
  x4 = moon_ascending_longitude(jce)
1037
- delta_psi = longitude_nutation(jce, x0, x1, x2, x3, x4)
1038
- delta_epsilon = obliquity_nutation(jce, x0, x1, x2, x3, x4)
994
+ l_o_nutation = np.empty((2, len(x0)))
995
+ longitude_obliquity_nutation(jce, x0, x1, x2, x3, x4, l_o_nutation)
996
+ delta_psi = l_o_nutation[0]
997
+ delta_epsilon = l_o_nutation[1]
1039
998
  epsilon0 = mean_ecliptic_obliquity(jme)
1040
999
  epsilon = true_ecliptic_obliquity(epsilon0, delta_epsilon)
1041
1000
  delta_tau = aberration_correction(R)