pvlib 0.11.0a1__py3-none-any.whl → 0.11.2__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.
- pvlib/_deprecation.py +73 -0
- pvlib/atmosphere.py +236 -1
- pvlib/bifacial/__init__.py +4 -4
- pvlib/bifacial/loss_models.py +163 -0
- pvlib/clearsky.py +53 -51
- pvlib/data/pvgis_tmy_meta.json +32 -93
- pvlib/data/pvgis_tmy_test.csv +8761 -0
- pvlib/data/tmy_45.000_8.000_2005_2023.csv +8789 -0
- pvlib/data/tmy_45.000_8.000_2005_2023.epw +8768 -0
- pvlib/data/tmy_45.000_8.000_2005_2023.json +1 -0
- pvlib/data/tmy_45.000_8.000_2005_2023.txt +8761 -0
- pvlib/data/tmy_45.000_8.000_userhorizon.json +1 -1
- pvlib/iam.py +4 -4
- pvlib/iotools/midc.py +1 -1
- pvlib/iotools/pvgis.py +39 -13
- pvlib/irradiance.py +237 -173
- pvlib/ivtools/sdm.py +75 -52
- pvlib/location.py +5 -5
- pvlib/modelchain.py +1 -1
- pvlib/pvsystem.py +134 -86
- pvlib/shading.py +8 -8
- pvlib/singlediode.py +1 -1
- pvlib/solarposition.py +101 -80
- pvlib/spa.py +28 -24
- pvlib/spectrum/__init__.py +9 -4
- pvlib/spectrum/irradiance.py +273 -0
- pvlib/spectrum/mismatch.py +118 -508
- pvlib/spectrum/response.py +280 -0
- pvlib/spectrum/spectrl2.py +18 -17
- pvlib/temperature.py +49 -3
- pvlib/tests/bifacial/test_losses_models.py +54 -0
- pvlib/tests/iotools/test_pvgis.py +58 -12
- pvlib/tests/ivtools/test_sdm.py +23 -1
- pvlib/tests/spectrum/__init__.py +0 -0
- pvlib/tests/spectrum/conftest.py +40 -0
- pvlib/tests/spectrum/test_irradiance.py +138 -0
- pvlib/tests/{test_spectrum.py → spectrum/test_mismatch.py} +32 -306
- pvlib/tests/spectrum/test_response.py +124 -0
- pvlib/tests/spectrum/test_spectrl2.py +72 -0
- pvlib/tests/test__deprecation.py +97 -0
- pvlib/tests/test_atmosphere.py +218 -0
- pvlib/tests/test_clearsky.py +44 -26
- pvlib/tests/test_conftest.py +0 -44
- pvlib/tests/test_irradiance.py +62 -16
- pvlib/tests/test_pvsystem.py +17 -1
- pvlib/tests/test_solarposition.py +117 -36
- pvlib/tests/test_spa.py +30 -1
- pvlib/tools.py +26 -2
- pvlib/tracking.py +53 -47
- {pvlib-0.11.0a1.dist-info → pvlib-0.11.2.dist-info}/METADATA +34 -31
- {pvlib-0.11.0a1.dist-info → pvlib-0.11.2.dist-info}/RECORD +55 -47
- {pvlib-0.11.0a1.dist-info → pvlib-0.11.2.dist-info}/WHEEL +1 -1
- pvlib/data/aod550_tcwv_20121101_test.nc +0 -0
- pvlib/data/pvgis_tmy_test.dat +0 -8761
- pvlib/data/tmy_45.000_8.000_2005_2016.csv +0 -8789
- pvlib/data/tmy_45.000_8.000_2005_2016.epw +0 -8768
- pvlib/data/tmy_45.000_8.000_2005_2016.json +0 -1
- pvlib/data/tmy_45.000_8.000_2005_2016.txt +0 -8761
- pvlib/data/variables_style_rules.csv +0 -55
- {pvlib-0.11.0a1.dist-info → pvlib-0.11.2.dist-info}/AUTHORS.md +0 -0
- {pvlib-0.11.0a1.dist-info → pvlib-0.11.2.dist-info}/LICENSE +0 -0
- {pvlib-0.11.0a1.dist-info → pvlib-0.11.2.dist-info}/top_level.txt +0 -0
pvlib/solarposition.py
CHANGED
|
@@ -22,16 +22,15 @@ import numpy as np
|
|
|
22
22
|
import pandas as pd
|
|
23
23
|
import scipy.optimize as so
|
|
24
24
|
import warnings
|
|
25
|
-
import datetime
|
|
26
25
|
|
|
27
|
-
from pvlib import atmosphere
|
|
26
|
+
from pvlib import atmosphere, tools
|
|
28
27
|
from pvlib.tools import datetime_to_djd, djd_to_datetime
|
|
29
28
|
|
|
30
29
|
|
|
31
30
|
def get_solarposition(time, latitude, longitude,
|
|
32
31
|
altitude=None, pressure=None,
|
|
33
32
|
method='nrel_numpy',
|
|
34
|
-
temperature=12, **kwargs):
|
|
33
|
+
temperature=12.0, **kwargs):
|
|
35
34
|
"""
|
|
36
35
|
A convenience wrapper for the solar position calculators.
|
|
37
36
|
|
|
@@ -126,8 +125,8 @@ def get_solarposition(time, latitude, longitude,
|
|
|
126
125
|
return ephem_df
|
|
127
126
|
|
|
128
127
|
|
|
129
|
-
def spa_c(time, latitude, longitude, pressure=101325
|
|
130
|
-
temperature=12
|
|
128
|
+
def spa_c(time, latitude, longitude, pressure=101325., altitude=0.,
|
|
129
|
+
temperature=12., delta_t=67.0,
|
|
131
130
|
raw_spa_output=False):
|
|
132
131
|
r"""
|
|
133
132
|
Calculate the solar position using the C implementation of the NREL
|
|
@@ -150,11 +149,11 @@ def spa_c(time, latitude, longitude, pressure=101325, altitude=0,
|
|
|
150
149
|
longitude : float
|
|
151
150
|
Longitude in decimal degrees. Positive east of prime meridian,
|
|
152
151
|
negative to west.
|
|
153
|
-
pressure : float, default 101325
|
|
152
|
+
pressure : float, default 101325.0
|
|
154
153
|
Pressure in Pascals
|
|
155
|
-
altitude : float, default 0
|
|
154
|
+
altitude : float, default 0.0
|
|
156
155
|
Height above sea level. [m]
|
|
157
|
-
temperature : float, default 12
|
|
156
|
+
temperature : float, default 12.0
|
|
158
157
|
Temperature in C
|
|
159
158
|
delta_t : float, default 67.0
|
|
160
159
|
Difference between terrestrial time and UT1.
|
|
@@ -200,11 +199,7 @@ def spa_c(time, latitude, longitude, pressure=101325, altitude=0,
|
|
|
200
199
|
raise ImportError('Could not import built-in SPA calculator. ' +
|
|
201
200
|
'You may need to recompile the SPA code.')
|
|
202
201
|
|
|
203
|
-
|
|
204
|
-
try:
|
|
205
|
-
time_utc = time.tz_convert('UTC')
|
|
206
|
-
except TypeError:
|
|
207
|
-
time_utc = time
|
|
202
|
+
time_utc = tools._pandas_to_utc(time)
|
|
208
203
|
|
|
209
204
|
spa_out = []
|
|
210
205
|
|
|
@@ -284,7 +279,7 @@ def _datetime_to_unixtime(dtindex):
|
|
|
284
279
|
|
|
285
280
|
|
|
286
281
|
def spa_python(time, latitude, longitude,
|
|
287
|
-
altitude=0
|
|
282
|
+
altitude=0., pressure=101325., temperature=12., delta_t=67.0,
|
|
288
283
|
atmos_refract=None, how='numpy', numthreads=4):
|
|
289
284
|
"""
|
|
290
285
|
Calculate the solar position using a python implementation of the
|
|
@@ -307,19 +302,17 @@ def spa_python(time, latitude, longitude,
|
|
|
307
302
|
longitude : float
|
|
308
303
|
Longitude in decimal degrees. Positive east of prime meridian,
|
|
309
304
|
negative to west.
|
|
310
|
-
altitude : float, default 0
|
|
305
|
+
altitude : float, default 0.0
|
|
311
306
|
Distance above sea level.
|
|
312
|
-
pressure : int or float, optional, default 101325
|
|
307
|
+
pressure : int or float, optional, default 101325.0
|
|
313
308
|
avg. yearly air pressure in Pascals.
|
|
314
|
-
temperature : int or float, optional, default 12
|
|
309
|
+
temperature : int or float, optional, default 12.0
|
|
315
310
|
avg. yearly air temperature in degrees C.
|
|
316
|
-
delta_t : float, optional, default 67.0
|
|
311
|
+
delta_t : float or array, optional, default 67.0
|
|
317
312
|
Difference between terrestrial time and UT1.
|
|
318
313
|
If delta_t is None, uses spa.calculate_deltat
|
|
319
314
|
using time.year and time.month from pandas.DatetimeIndex.
|
|
320
315
|
For most simulations the default delta_t is sufficient.
|
|
321
|
-
*Note: delta_t = None will break code using nrel_numba,
|
|
322
|
-
this will be fixed in a future version.*
|
|
323
316
|
The USNO has historical and forecasted delta_t [3]_.
|
|
324
317
|
atmos_refrac : float, optional
|
|
325
318
|
The approximate atmospheric refraction (in degrees)
|
|
@@ -379,7 +372,9 @@ def spa_python(time, latitude, longitude,
|
|
|
379
372
|
|
|
380
373
|
spa = _spa_python_import(how)
|
|
381
374
|
|
|
382
|
-
|
|
375
|
+
if delta_t is None:
|
|
376
|
+
time_utc = tools._pandas_to_utc(time)
|
|
377
|
+
delta_t = spa.calculate_deltat(time_utc.year, time_utc.month)
|
|
383
378
|
|
|
384
379
|
app_zenith, zenith, app_elevation, elevation, azimuth, eot = \
|
|
385
380
|
spa.solar_position(unixtime, lat, lon, elev, pressure, temperature,
|
|
@@ -419,13 +414,11 @@ def sun_rise_set_transit_spa(times, latitude, longitude, how='numpy',
|
|
|
419
414
|
Options are 'numpy' or 'numba'. If numba >= 0.17.0
|
|
420
415
|
is installed, how='numba' will compile the spa functions
|
|
421
416
|
to machine code and run them multithreaded.
|
|
422
|
-
delta_t : float, optional, default 67.0
|
|
417
|
+
delta_t : float or array, optional, default 67.0
|
|
423
418
|
Difference between terrestrial time and UT1.
|
|
424
419
|
If delta_t is None, uses spa.calculate_deltat
|
|
425
420
|
using times.year and times.month from pandas.DatetimeIndex.
|
|
426
421
|
For most simulations the default delta_t is sufficient.
|
|
427
|
-
*Note: delta_t = None will break code using nrel_numba,
|
|
428
|
-
this will be fixed in a future version.*
|
|
429
422
|
numthreads : int, optional, default 4
|
|
430
423
|
Number of threads to use if how == 'numba'.
|
|
431
424
|
|
|
@@ -453,12 +446,13 @@ def sun_rise_set_transit_spa(times, latitude, longitude, how='numpy',
|
|
|
453
446
|
raise ValueError('times must be localized')
|
|
454
447
|
|
|
455
448
|
# must convert to midnight UTC on day of interest
|
|
456
|
-
|
|
457
|
-
unixtime = _datetime_to_unixtime(
|
|
449
|
+
times_utc = times.tz_convert('UTC')
|
|
450
|
+
unixtime = _datetime_to_unixtime(times_utc.normalize())
|
|
458
451
|
|
|
459
452
|
spa = _spa_python_import(how)
|
|
460
453
|
|
|
461
|
-
|
|
454
|
+
if delta_t is None:
|
|
455
|
+
delta_t = spa.calculate_deltat(times_utc.year, times_utc.month)
|
|
462
456
|
|
|
463
457
|
transit, sunrise, sunset = spa.transit_sunrise_sunset(
|
|
464
458
|
unixtime, lat, lon, delta_t, numthreads)
|
|
@@ -513,9 +507,9 @@ def _ephem_setup(latitude, longitude, altitude, pressure, temperature,
|
|
|
513
507
|
|
|
514
508
|
def sun_rise_set_transit_ephem(times, latitude, longitude,
|
|
515
509
|
next_or_previous='next',
|
|
516
|
-
altitude=0
|
|
517
|
-
pressure=101325
|
|
518
|
-
temperature=12
|
|
510
|
+
altitude=0.,
|
|
511
|
+
pressure=101325.,
|
|
512
|
+
temperature=12., horizon='0:00'):
|
|
519
513
|
"""
|
|
520
514
|
Calculate the next sunrise and sunset times using the PyEphem package.
|
|
521
515
|
|
|
@@ -529,11 +523,11 @@ def sun_rise_set_transit_ephem(times, latitude, longitude,
|
|
|
529
523
|
Longitude in degrees, positive east of prime meridian, negative to west
|
|
530
524
|
next_or_previous : str
|
|
531
525
|
'next' or 'previous' sunrise and sunset relative to time
|
|
532
|
-
altitude : float, default 0
|
|
526
|
+
altitude : float, default 0.0
|
|
533
527
|
distance above sea level in meters.
|
|
534
|
-
pressure : int or float, optional, default 101325
|
|
528
|
+
pressure : int or float, optional, default 101325.0
|
|
535
529
|
air pressure in Pascals.
|
|
536
|
-
temperature : int or float, optional, default 12
|
|
530
|
+
temperature : int or float, optional, default 12.0
|
|
537
531
|
air temperature in degrees C.
|
|
538
532
|
horizon : string, format +/-X:YY
|
|
539
533
|
arc degrees:arc minutes from geometrical horizon for sunrise and
|
|
@@ -582,12 +576,11 @@ def sun_rise_set_transit_ephem(times, latitude, longitude,
|
|
|
582
576
|
sunrise = []
|
|
583
577
|
sunset = []
|
|
584
578
|
trans = []
|
|
585
|
-
for thetime in times:
|
|
586
|
-
thetime = thetime.to_pydatetime()
|
|
579
|
+
for thetime in tools._pandas_to_utc(times):
|
|
587
580
|
# older versions of pyephem ignore timezone when converting to its
|
|
588
581
|
# internal datetime format, so convert to UTC here to support
|
|
589
582
|
# all versions. GH #1449
|
|
590
|
-
obs.date = ephem.Date(thetime
|
|
583
|
+
obs.date = ephem.Date(thetime)
|
|
591
584
|
sunrise.append(_ephem_to_timezone(rising(sun), tzinfo))
|
|
592
585
|
sunset.append(_ephem_to_timezone(setting(sun), tzinfo))
|
|
593
586
|
trans.append(_ephem_to_timezone(transit(sun), tzinfo))
|
|
@@ -597,8 +590,8 @@ def sun_rise_set_transit_ephem(times, latitude, longitude,
|
|
|
597
590
|
'transit': trans})
|
|
598
591
|
|
|
599
592
|
|
|
600
|
-
def pyephem(time, latitude, longitude, altitude=0
|
|
601
|
-
temperature=12
|
|
593
|
+
def pyephem(time, latitude, longitude, altitude=0., pressure=101325.,
|
|
594
|
+
temperature=12., horizon='+0:00'):
|
|
602
595
|
"""
|
|
603
596
|
Calculate the solar position using the PyEphem package.
|
|
604
597
|
|
|
@@ -612,11 +605,11 @@ def pyephem(time, latitude, longitude, altitude=0, pressure=101325,
|
|
|
612
605
|
longitude : float
|
|
613
606
|
Longitude in decimal degrees. Positive east of prime meridian,
|
|
614
607
|
negative to west.
|
|
615
|
-
altitude : float, default 0
|
|
608
|
+
altitude : float, default 0.0
|
|
616
609
|
Height above sea level in meters. [m]
|
|
617
|
-
pressure : int or float, optional, default 101325
|
|
610
|
+
pressure : int or float, optional, default 101325.0
|
|
618
611
|
air pressure in Pascals.
|
|
619
|
-
temperature : int or float, optional, default 12
|
|
612
|
+
temperature : int or float, optional, default 12.0
|
|
620
613
|
air temperature in degrees C.
|
|
621
614
|
horizon : string, optional, default '+0:00'
|
|
622
615
|
arc degrees:arc minutes from geometrical horizon for sunrise and
|
|
@@ -645,11 +638,7 @@ def pyephem(time, latitude, longitude, altitude=0, pressure=101325,
|
|
|
645
638
|
except ImportError:
|
|
646
639
|
raise ImportError('PyEphem must be installed')
|
|
647
640
|
|
|
648
|
-
|
|
649
|
-
try:
|
|
650
|
-
time_utc = time.tz_convert('UTC')
|
|
651
|
-
except TypeError:
|
|
652
|
-
time_utc = time
|
|
641
|
+
time_utc = tools._pandas_to_utc(time)
|
|
653
642
|
|
|
654
643
|
sun_coords = pd.DataFrame(index=time)
|
|
655
644
|
|
|
@@ -690,7 +679,7 @@ def pyephem(time, latitude, longitude, altitude=0, pressure=101325,
|
|
|
690
679
|
return sun_coords
|
|
691
680
|
|
|
692
681
|
|
|
693
|
-
def ephemeris(time, latitude, longitude, pressure=101325, temperature=12):
|
|
682
|
+
def ephemeris(time, latitude, longitude, pressure=101325.0, temperature=12.0):
|
|
694
683
|
"""
|
|
695
684
|
Python-native solar position calculator.
|
|
696
685
|
The accuracy of this code is not guaranteed.
|
|
@@ -706,9 +695,9 @@ def ephemeris(time, latitude, longitude, pressure=101325, temperature=12):
|
|
|
706
695
|
longitude : float
|
|
707
696
|
Longitude in decimal degrees. Positive east of prime meridian,
|
|
708
697
|
negative to west.
|
|
709
|
-
pressure : float or Series, default 101325
|
|
698
|
+
pressure : float or Series, default 101325.0
|
|
710
699
|
Ambient pressure (Pascals)
|
|
711
|
-
temperature : float or Series, default 12
|
|
700
|
+
temperature : float or Series, default 12.0
|
|
712
701
|
Ambient temperature (C)
|
|
713
702
|
|
|
714
703
|
Returns
|
|
@@ -718,11 +707,11 @@ def ephemeris(time, latitude, longitude, pressure=101325, temperature=12):
|
|
|
718
707
|
|
|
719
708
|
* apparent_elevation : apparent sun elevation accounting for
|
|
720
709
|
atmospheric refraction.
|
|
710
|
+
This is the complement of the apparent zenith angle.
|
|
721
711
|
* elevation : actual elevation (not accounting for refraction)
|
|
722
712
|
of the sun in decimal degrees, 0 = on horizon.
|
|
723
713
|
The complement of the zenith angle.
|
|
724
714
|
* azimuth : Azimuth of the sun in decimal degrees East of North.
|
|
725
|
-
This is the complement of the apparent zenith angle.
|
|
726
715
|
* apparent_zenith : apparent sun zenith accounting for atmospheric
|
|
727
716
|
refraction.
|
|
728
717
|
* zenith : Solar zenith angle
|
|
@@ -766,11 +755,7 @@ def ephemeris(time, latitude, longitude, pressure=101325, temperature=12):
|
|
|
766
755
|
# the SPA algorithm needs time to be expressed in terms of
|
|
767
756
|
# decimal UTC hours of the day of the year.
|
|
768
757
|
|
|
769
|
-
|
|
770
|
-
try:
|
|
771
|
-
time_utc = time.tz_convert('UTC')
|
|
772
|
-
except TypeError:
|
|
773
|
-
time_utc = time
|
|
758
|
+
time_utc = tools._pandas_to_utc(time)
|
|
774
759
|
|
|
775
760
|
# strip out the day of the year and calculate the decimal hour
|
|
776
761
|
DayOfYear = time_utc.dayofyear
|
|
@@ -871,8 +856,8 @@ def ephemeris(time, latitude, longitude, pressure=101325, temperature=12):
|
|
|
871
856
|
|
|
872
857
|
|
|
873
858
|
def calc_time(lower_bound, upper_bound, latitude, longitude, attribute, value,
|
|
874
|
-
altitude=0, pressure=101325, temperature=12
|
|
875
|
-
xtol=1.0e-12):
|
|
859
|
+
altitude=0.0, pressure=101325.0, temperature=12.0,
|
|
860
|
+
horizon='+0:00', xtol=1.0e-12):
|
|
876
861
|
"""
|
|
877
862
|
Calculate the time between lower_bound and upper_bound
|
|
878
863
|
where the attribute is equal to value. Uses PyEphem for
|
|
@@ -894,12 +879,12 @@ def calc_time(lower_bound, upper_bound, latitude, longitude, attribute, value,
|
|
|
894
879
|
and 'az' (which must be given in radians).
|
|
895
880
|
value : int or float
|
|
896
881
|
The value of the attribute to solve for
|
|
897
|
-
altitude : float, default 0
|
|
882
|
+
altitude : float, default 0.0
|
|
898
883
|
Distance above sea level.
|
|
899
|
-
pressure : int or float, optional, default 101325
|
|
884
|
+
pressure : int or float, optional, default 101325.0
|
|
900
885
|
Air pressure in Pascals. Set to 0 for no
|
|
901
886
|
atmospheric correction.
|
|
902
|
-
temperature : int or float, optional, default 12
|
|
887
|
+
temperature : int or float, optional, default 12.0
|
|
903
888
|
Air temperature in degrees C.
|
|
904
889
|
horizon : string, optional, default '+0:00'
|
|
905
890
|
arc degrees:arc minutes from geometrical horizon for sunrise and
|
|
@@ -957,7 +942,10 @@ def pyephem_earthsun_distance(time):
|
|
|
957
942
|
|
|
958
943
|
sun = ephem.Sun()
|
|
959
944
|
earthsun = []
|
|
960
|
-
for thetime in time:
|
|
945
|
+
for thetime in tools._pandas_to_utc(time):
|
|
946
|
+
# older versions of pyephem ignore timezone when converting to its
|
|
947
|
+
# internal datetime format, so convert to UTC here to support
|
|
948
|
+
# all versions. GH #1449
|
|
961
949
|
sun.compute(ephem.Date(thetime))
|
|
962
950
|
earthsun.append(sun.earth_distance)
|
|
963
951
|
|
|
@@ -981,13 +969,11 @@ def nrel_earthsun_distance(time, how='numpy', delta_t=67.0, numthreads=4):
|
|
|
981
969
|
is installed, how='numba' will compile the spa functions
|
|
982
970
|
to machine code and run them multithreaded.
|
|
983
971
|
|
|
984
|
-
delta_t : float, optional, default 67.0
|
|
972
|
+
delta_t : float or array, optional, default 67.0
|
|
985
973
|
Difference between terrestrial time and UT1.
|
|
986
974
|
If delta_t is None, uses spa.calculate_deltat
|
|
987
975
|
using time.year and time.month from pandas.DatetimeIndex.
|
|
988
976
|
For most simulations the default delta_t is sufficient.
|
|
989
|
-
*Note: delta_t = None will break code using nrel_numba,
|
|
990
|
-
this will be fixed in a future version.*
|
|
991
977
|
|
|
992
978
|
numthreads : int, optional, default 4
|
|
993
979
|
Number of threads to use if how == 'numba'.
|
|
@@ -1014,7 +1000,9 @@ def nrel_earthsun_distance(time, how='numpy', delta_t=67.0, numthreads=4):
|
|
|
1014
1000
|
|
|
1015
1001
|
spa = _spa_python_import(how)
|
|
1016
1002
|
|
|
1017
|
-
|
|
1003
|
+
if delta_t is None:
|
|
1004
|
+
time_utc = tools._pandas_to_utc(time)
|
|
1005
|
+
delta_t = spa.calculate_deltat(time_utc.year, time_utc.month)
|
|
1018
1006
|
|
|
1019
1007
|
dist = spa.earthsun_distance(unixtime, delta_t, numthreads)
|
|
1020
1008
|
|
|
@@ -1361,6 +1349,12 @@ def hour_angle(times, longitude, equation_of_time):
|
|
|
1361
1349
|
times : :class:`pandas.DatetimeIndex`
|
|
1362
1350
|
Corresponding timestamps, must be localized to the timezone for the
|
|
1363
1351
|
``longitude``.
|
|
1352
|
+
|
|
1353
|
+
A `pytz.exceptions.AmbiguousTimeError` will be raised if any of the
|
|
1354
|
+
given times are on a day when the local daylight savings transition
|
|
1355
|
+
happens at midnight. If you're working with such a timezone,
|
|
1356
|
+
consider converting to a non-DST timezone (e.g. GMT-4) before
|
|
1357
|
+
calling this function.
|
|
1364
1358
|
longitude : numeric
|
|
1365
1359
|
Longitude in degrees
|
|
1366
1360
|
equation_of_time : numeric
|
|
@@ -1387,22 +1381,26 @@ def hour_angle(times, longitude, equation_of_time):
|
|
|
1387
1381
|
equation_of_time_spencer71
|
|
1388
1382
|
equation_of_time_pvcdrom
|
|
1389
1383
|
"""
|
|
1384
|
+
|
|
1385
|
+
# times must be localized
|
|
1386
|
+
if not times.tz:
|
|
1387
|
+
raise ValueError('times must be localized')
|
|
1388
|
+
|
|
1390
1389
|
# hours - timezone = (times - normalized_times) - (naive_times - times)
|
|
1391
|
-
if times.tz is None:
|
|
1392
|
-
times = times.tz_localize('utc')
|
|
1393
1390
|
tzs = np.array([ts.utcoffset().total_seconds() for ts in times]) / 3600
|
|
1394
1391
|
|
|
1395
|
-
hrs_minus_tzs = (times
|
|
1392
|
+
hrs_minus_tzs = _times_to_hours_after_local_midnight(times) - tzs
|
|
1396
1393
|
|
|
1397
|
-
|
|
1398
|
-
return np.asarray(
|
|
1399
|
-
15. * (hrs_minus_tzs - 12.) + longitude + equation_of_time / 4.)
|
|
1394
|
+
return 15. * (hrs_minus_tzs - 12.) + longitude + equation_of_time / 4.
|
|
1400
1395
|
|
|
1401
1396
|
|
|
1402
1397
|
def _hour_angle_to_hours(times, hourangle, longitude, equation_of_time):
|
|
1403
1398
|
"""converts hour angles in degrees to hours as a numpy array"""
|
|
1404
|
-
|
|
1405
|
-
|
|
1399
|
+
|
|
1400
|
+
# times must be localized
|
|
1401
|
+
if not times.tz:
|
|
1402
|
+
raise ValueError('times must be localized')
|
|
1403
|
+
|
|
1406
1404
|
tzs = np.array([ts.utcoffset().total_seconds() for ts in times]) / 3600
|
|
1407
1405
|
hours = (hourangle - longitude - equation_of_time / 4.) / 15. + 12. + tzs
|
|
1408
1406
|
return np.asarray(hours)
|
|
@@ -1412,18 +1410,36 @@ def _local_times_from_hours_since_midnight(times, hours):
|
|
|
1412
1410
|
"""
|
|
1413
1411
|
converts hours since midnight from an array of floats to localized times
|
|
1414
1412
|
"""
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1413
|
+
|
|
1414
|
+
# times must be localized
|
|
1415
|
+
if not times.tz:
|
|
1416
|
+
raise ValueError('times must be localized')
|
|
1417
|
+
|
|
1418
|
+
# normalize local times to previous local midnight and add the hours until
|
|
1418
1419
|
# sunrise, sunset, and transit
|
|
1419
|
-
return pd.
|
|
1420
|
-
naive_times.normalize() + pd.to_timedelta(hours, unit='h'), tz=tz_info)
|
|
1420
|
+
return times.normalize() + pd.to_timedelta(hours, unit='h')
|
|
1421
1421
|
|
|
1422
1422
|
|
|
1423
1423
|
def _times_to_hours_after_local_midnight(times):
|
|
1424
1424
|
"""convert local pandas datetime indices to array of hours as floats"""
|
|
1425
|
-
|
|
1426
|
-
|
|
1425
|
+
|
|
1426
|
+
# times must be localized
|
|
1427
|
+
if not times.tz:
|
|
1428
|
+
raise ValueError('times must be localized')
|
|
1429
|
+
|
|
1430
|
+
# Some timezones have a DST shift at midnight:
|
|
1431
|
+
# 11:59pm -> 1:00am - results in a nonexistent midnight
|
|
1432
|
+
# 12:59am -> 12:00am - results in an ambiguous midnight
|
|
1433
|
+
# We remove the timezone before normalizing for this reason.
|
|
1434
|
+
naive_normalized_times = times.tz_localize(None).normalize()
|
|
1435
|
+
|
|
1436
|
+
# Use Pandas functionality for shifting nonexistent times forward
|
|
1437
|
+
normalized_times = naive_normalized_times.tz_localize(
|
|
1438
|
+
times.tz, nonexistent='shift_forward', ambiguous='raise')
|
|
1439
|
+
|
|
1440
|
+
hrs = (times - normalized_times) / pd.Timedelta('1h')
|
|
1441
|
+
|
|
1442
|
+
# ensure array return instead of a version-dependent pandas <T>Index
|
|
1427
1443
|
return np.array(hrs)
|
|
1428
1444
|
|
|
1429
1445
|
|
|
@@ -1469,6 +1485,11 @@ def sun_rise_set_transit_geometric(times, latitude, longitude, declination,
|
|
|
1469
1485
|
CRC Press (2012)
|
|
1470
1486
|
|
|
1471
1487
|
"""
|
|
1488
|
+
|
|
1489
|
+
# times must be localized
|
|
1490
|
+
if not times.tz:
|
|
1491
|
+
raise ValueError('times must be localized')
|
|
1492
|
+
|
|
1472
1493
|
latitude_rad = np.radians(latitude) # radians
|
|
1473
1494
|
sunset_angle_rad = np.arccos(-np.tan(declination) * np.tan(latitude_rad))
|
|
1474
1495
|
sunset_angle = np.degrees(sunset_angle_rad) # degrees
|
pvlib/spa.py
CHANGED
|
@@ -413,8 +413,10 @@ def julian_day_dt(year, month, day, hour, minute, second, microsecond):
|
|
|
413
413
|
frac_of_day = (microsecond / 1e6 + (second + minute * 60 + hour * 3600)
|
|
414
414
|
) * 1.0 / (3600*24)
|
|
415
415
|
d = day + frac_of_day
|
|
416
|
-
jd =
|
|
417
|
-
|
|
416
|
+
jd = int(365.25 * (year + 4716)) + int(30.6001 * (month + 1)) + d - 1524.5
|
|
417
|
+
if jd > 2299160.0:
|
|
418
|
+
jd += b
|
|
419
|
+
|
|
418
420
|
return jd
|
|
419
421
|
|
|
420
422
|
|
|
@@ -835,24 +837,24 @@ def equation_of_time(sun_mean_longitude, geocentric_sun_right_ascension,
|
|
|
835
837
|
return E
|
|
836
838
|
|
|
837
839
|
|
|
838
|
-
@jcompile('void(float64[:], float64[:], float64[:,:])',
|
|
839
|
-
nogil=True)
|
|
840
|
-
def solar_position_loop(unixtime, loc_args, out):
|
|
840
|
+
@jcompile('void(float64[:], float64[:], float64[:], float64[:,:])',
|
|
841
|
+
nopython=True, nogil=True)
|
|
842
|
+
def solar_position_loop(unixtime, delta_t, loc_args, out):
|
|
841
843
|
"""Loop through the time array and calculate the solar position"""
|
|
842
844
|
lat = loc_args[0]
|
|
843
845
|
lon = loc_args[1]
|
|
844
846
|
elev = loc_args[2]
|
|
845
847
|
pressure = loc_args[3]
|
|
846
848
|
temp = loc_args[4]
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
esd = loc_args[8]
|
|
849
|
+
atmos_refract = loc_args[5]
|
|
850
|
+
sst = loc_args[6]
|
|
851
|
+
esd = loc_args[7]
|
|
851
852
|
|
|
852
853
|
for i in range(unixtime.shape[0]):
|
|
853
854
|
utime = unixtime[i]
|
|
855
|
+
dT = delta_t[i]
|
|
854
856
|
jd = julian_day(utime)
|
|
855
|
-
jde = julian_ephemeris_day(jd,
|
|
857
|
+
jde = julian_ephemeris_day(jd, dT)
|
|
856
858
|
jc = julian_century(jd)
|
|
857
859
|
jce = julian_ephemeris_century(jde)
|
|
858
860
|
jme = julian_ephemeris_millennium(jce)
|
|
@@ -920,8 +922,11 @@ def solar_position_numba(unixtime, lat, lon, elev, pressure, temp, delta_t,
|
|
|
920
922
|
and multiple threads. Very slow if functions are not numba compiled.
|
|
921
923
|
"""
|
|
922
924
|
# these args are the same for each thread
|
|
923
|
-
loc_args = np.array([lat, lon, elev, pressure, temp,
|
|
924
|
-
atmos_refract, sst, esd])
|
|
925
|
+
loc_args = np.array([lat, lon, elev, pressure, temp,
|
|
926
|
+
atmos_refract, sst, esd], dtype=np.float64)
|
|
927
|
+
|
|
928
|
+
# turn delta_t into an array if it isn't already
|
|
929
|
+
delta_t = np.full_like(unixtime, delta_t, dtype=np.float64)
|
|
925
930
|
|
|
926
931
|
# construct dims x ulength array to put the results in
|
|
927
932
|
ulength = unixtime.shape[0]
|
|
@@ -937,18 +942,20 @@ def solar_position_numba(unixtime, lat, lon, elev, pressure, temp, delta_t,
|
|
|
937
942
|
unixtime = unixtime.astype(np.float64)
|
|
938
943
|
|
|
939
944
|
if ulength < numthreads:
|
|
940
|
-
warnings.warn('The number of threads is more than the length of '
|
|
941
|
-
'the time array. Only using %s threads.'.format(ulength))
|
|
942
945
|
numthreads = ulength
|
|
943
946
|
|
|
944
947
|
if numthreads <= 1:
|
|
945
|
-
solar_position_loop(unixtime, loc_args, result)
|
|
948
|
+
solar_position_loop(unixtime, delta_t, loc_args, result)
|
|
946
949
|
return result
|
|
947
950
|
|
|
948
951
|
# split the input and output arrays into numthreads chunks
|
|
949
952
|
split0 = np.array_split(unixtime, numthreads)
|
|
953
|
+
split1 = np.array_split(delta_t, numthreads)
|
|
950
954
|
split2 = np.array_split(result, numthreads, axis=1)
|
|
951
|
-
chunks = [
|
|
955
|
+
chunks = [
|
|
956
|
+
[a0, a1, loc_args, a2]
|
|
957
|
+
for a0, a1, a2 in zip(split0, split1, split2)
|
|
958
|
+
]
|
|
952
959
|
# Spawn one thread per chunk
|
|
953
960
|
threads = [threading.Thread(target=solar_position_loop, args=chunk)
|
|
954
961
|
for chunk in chunks]
|
|
@@ -1035,7 +1042,7 @@ def solar_position(unixtime, lat, lon, elev, pressure, temp, delta_t,
|
|
|
1035
1042
|
unixtime : numpy array
|
|
1036
1043
|
Array of unix/epoch timestamps to calculate solar position for.
|
|
1037
1044
|
Unixtime is the number of seconds since Jan. 1, 1970 00:00:00 UTC.
|
|
1038
|
-
A pandas.DatetimeIndex is easily converted using .
|
|
1045
|
+
A pandas.DatetimeIndex is easily converted using .view(np.int64)/10**9
|
|
1039
1046
|
lat : float
|
|
1040
1047
|
Latitude to calculate solar position for
|
|
1041
1048
|
lon : float
|
|
@@ -1048,7 +1055,7 @@ def solar_position(unixtime, lat, lon, elev, pressure, temp, delta_t,
|
|
|
1048
1055
|
temp : int or float
|
|
1049
1056
|
avg. yearly temperature at location in
|
|
1050
1057
|
degrees C; used for atmospheric correction
|
|
1051
|
-
delta_t : float
|
|
1058
|
+
delta_t : float or array
|
|
1052
1059
|
Difference between terrestrial time and UT1.
|
|
1053
1060
|
atmos_refrac : float
|
|
1054
1061
|
The approximate atmospheric refraction (in degrees)
|
|
@@ -1113,7 +1120,7 @@ def transit_sunrise_sunset(dates, lat, lon, delta_t, numthreads):
|
|
|
1113
1120
|
Latitude of location to perform calculation for
|
|
1114
1121
|
lon : float
|
|
1115
1122
|
Longitude of location
|
|
1116
|
-
delta_t : float
|
|
1123
|
+
delta_t : float or array
|
|
1117
1124
|
Difference between terrestrial time and UT. USNO has tables.
|
|
1118
1125
|
numthreads : int
|
|
1119
1126
|
Number to threads to use for calculation (if using numba)
|
|
@@ -1214,8 +1221,8 @@ def earthsun_distance(unixtime, delta_t, numthreads):
|
|
|
1214
1221
|
unixtime : numpy array
|
|
1215
1222
|
Array of unix/epoch timestamps to calculate solar position for.
|
|
1216
1223
|
Unixtime is the number of seconds since Jan. 1, 1970 00:00:00 UTC.
|
|
1217
|
-
A pandas.DatetimeIndex is easily converted using .
|
|
1218
|
-
delta_t : float
|
|
1224
|
+
A pandas.DatetimeIndex is easily converted using .view(np.int64)/10**9
|
|
1225
|
+
delta_t : float or array
|
|
1219
1226
|
Difference between terrestrial time and UT. USNO has tables.
|
|
1220
1227
|
numthreads : int
|
|
1221
1228
|
Number to threads to use for calculation (if using numba)
|
|
@@ -1242,9 +1249,6 @@ def calculate_deltat(year, month):
|
|
|
1242
1249
|
"""Calculate the difference between Terrestrial Dynamical Time (TD)
|
|
1243
1250
|
and Universal Time (UT).
|
|
1244
1251
|
|
|
1245
|
-
Note: This function is not yet compatible for calculations using
|
|
1246
|
-
Numba.
|
|
1247
|
-
|
|
1248
1252
|
Equations taken from http://eclipse.gsfc.nasa.gov/SEcat5/deltatpoly.html
|
|
1249
1253
|
"""
|
|
1250
1254
|
|
pvlib/spectrum/__init__.py
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
from pvlib.spectrum.spectrl2 import spectrl2 # noqa: F401
|
|
2
2
|
from pvlib.spectrum.mismatch import ( # noqa: F401
|
|
3
3
|
calc_spectral_mismatch_field,
|
|
4
|
-
get_am15g,
|
|
5
|
-
get_reference_spectra,
|
|
6
|
-
get_example_spectral_response,
|
|
7
4
|
spectral_factor_caballero,
|
|
8
5
|
spectral_factor_firstsolar,
|
|
9
6
|
spectral_factor_sapm,
|
|
10
7
|
spectral_factor_pvspec,
|
|
11
8
|
spectral_factor_jrc,
|
|
9
|
+
)
|
|
10
|
+
from pvlib.spectrum.irradiance import ( # noqa: F401
|
|
11
|
+
get_am15g,
|
|
12
|
+
get_reference_spectra,
|
|
13
|
+
average_photon_energy,
|
|
14
|
+
)
|
|
15
|
+
from pvlib.spectrum.response import ( # noqa: F401
|
|
16
|
+
get_example_spectral_response,
|
|
12
17
|
sr_to_qe,
|
|
13
|
-
qe_to_sr
|
|
18
|
+
qe_to_sr,
|
|
14
19
|
)
|