1010
1111import datetime
1212from collections import OrderedDict
13+ from functools import partial
1314
1415import numpy as np
1516import pandas as pd
3637
3738
3839def extraradiation (datetime_or_doy , solar_constant = 1366.1 , method = 'spencer' ,
39- ** kwargs ):
40+ epoch_year = 2014 , ** kwargs ):
4041 """
4142 Determine extraterrestrial radiation from day of year.
4243
4344 Parameters
4445 ----------
45- datetime_or_doy : int, float, array, pd.DatetimeIndex
46- Day of year, array of days of year e.g.
47- pd.DatetimeIndex.dayofyear, or pd.DatetimeIndex.
46+ datetime_or_doy : int, float, array, date, datetime, datetime64,
47+ Timestamp, DatetimeIndex
48+ Day of year, array of days of year, or datetime-like object
4849
4950 solar_constant : float
5051 The solar constant.
@@ -53,132 +54,93 @@ def extraradiation(datetime_or_doy, solar_constant=1366.1, method='spencer',
5354 The method by which the ET radiation should be calculated.
5455 Options include ``'pyephem', 'spencer', 'asce', 'nrel'``.
5556
57+ epoch_year : int
58+ The year in which a day of year input will be calculated. Only
59+ applies to day of year input used with the pyephem or nrel
60+ methods.
61+
5662 kwargs :
5763 Passed to solarposition.nrel_earthsun_distance
5864
5965 Returns
6066 -------
6167 dni_extra : float, array, or Series
6268 The extraterrestrial radiation present in watts per square meter
63- on a surface which is normal to the sun. Ea is of the same size
64- as the input doy.
65-
66- 'pyephem' and 'nrel' always return a Series.
67-
68- Notes
69- -----
70- The Spencer method contains a minus sign discrepancy between
71- equation 12 of [1]. It's unclear what the correct formula is.
69+ on a surface which is normal to the sun. Pandas Timestamp and
70+ DatetimeIndex inputs will yield a Pandas TimeSeries. All other
71+ inputs will yield a float or an array of floats.
7272
7373 References
7474 ----------
7575 [1] M. Reno, C. Hansen, and J. Stein, "Global Horizontal Irradiance
7676 Clear Sky Models: Implementation and Analysis", Sandia National
7777 Laboratories, SAND2012-2389, 2012.
7878
79- [2] <http://solardat.uoregon.edu/SolarRadiationBasics.html>,
80- Eqs. SR1 and SR2
81-
82- [3] Partridge, G. W. and Platt, C. M. R. 1976.
83- Radiative Processes in Meteorology and Climatology.
79+ [2] <http://solardat.uoregon.edu/SolarRadiationBasics.html>, Eqs.
80+ SR1 and SR2
8481
85- [4] Duffie, J. A. and Beckman, W. A. 1991.
86- Solar Engineering of Thermal Processes,
87- 2nd edn. J. Wiley and Sons, New York.
82+ [3] Partridge, G. W. and Platt, C. M. R. 1976. Radiative Processes
83+ in Meteorology and Climatology.
8884
89- See Also
90- --------
91- pvlib.clearsky.disc
85+ [4] Duffie, J. A. and Beckman, W. A. 1991. Solar Engineering of
86+ Thermal Processes, 2nd edn. J. Wiley and Sons, New York.
9287 """
9388
94- pvl_logger .debug ('irradiance.extraradiation()' )
95-
96- method = method .lower ()
97-
89+ # This block will set the functions that can be used to convert the
90+ # inputs to either day of year or pandas DatetimeIndex, and the
91+ # functions that will yield the appropriate output type. It's
92+ # complicated because there are many day-of-year-like input types,
93+ # and the different algorithms need different types. Maybe you have
94+ # a better way to do it.
9895 if isinstance (datetime_or_doy , pd .DatetimeIndex ):
99- doy = datetime_or_doy .dayofyear
100- input_to_datetimeindex = lambda x : datetime_or_doy
101- elif isinstance (datetime_or_doy , (int , float )):
102- doy = datetime_or_doy
103- input_to_datetimeindex = _scalar_to_datetimeindex
104- else : # assume that we have an array-like object of doy. danger?
105- doy = datetime_or_doy
106- input_to_datetimeindex = _array_to_datetimeindex
107-
108- B = (2. * np .pi / 365. ) * (doy - 1 )
96+ to_doy = tools ._pandas_to_doy # won't be evaluated unless necessary
97+ to_datetimeindex = lambda x : datetime_or_doy
98+ to_output = partial (pd .Series , index = datetime_or_doy )
99+ elif isinstance (datetime_or_doy , pd .Timestamp ):
100+ to_doy = tools ._pandas_to_doy
101+ to_datetimeindex = \
102+ tools ._datetimelike_scalar_to_datetimeindex
103+ to_output = tools ._scalar_out
104+ elif isinstance (datetime_or_doy ,
105+ (datetime .date , datetime .datetime , np .datetime64 )):
106+ to_doy = tools ._datetimelike_scalar_to_doy
107+ to_datetimeindex = \
108+ tools ._datetimelike_scalar_to_datetimeindex
109+ to_output = tools ._scalar_out
110+ elif np .isscalar (datetime_or_doy ): # ints and floats of various types
111+ to_doy = lambda x : datetime_or_doy
112+ to_datetimeindex = partial (tools ._doy_to_datetimeindex ,
113+ epoch_year = epoch_year )
114+ to_output = tools ._scalar_out
115+ else : # assume that we have an array-like object of doy
116+ to_doy = lambda x : datetime_or_doy
117+ to_datetimeindex = partial (tools ._doy_to_datetimeindex ,
118+ epoch_year = epoch_year )
119+ to_output = tools ._array_out
109120
110121 method = method .lower ()
111122 if method == 'asce' :
112- pvl_logger . debug ( 'Calculating ET rad using ASCE method' )
123+ B = solarposition . _calculate_simple_day_angle ( to_doy ( datetime_or_doy ) )
113124 RoverR0sqrd = 1 + 0.033 * np .cos (B )
114125 elif method == 'spencer' :
115- pvl_logger . debug ( 'Calculating ET rad using Spencer method' )
126+ B = solarposition . _calculate_simple_day_angle ( to_doy ( datetime_or_doy ) )
116127 RoverR0sqrd = (1.00011 + 0.034221 * np .cos (B ) + 0.00128 * np .sin (B ) +
117128 0.000719 * np .cos (2 * B ) + 7.7e-05 * np .sin (2 * B ))
118129 elif method == 'pyephem' :
119- pvl_logger .debug ('Calculating ET rad using pyephem method' )
120- times = input_to_datetimeindex (datetime_or_doy )
130+ times = to_datetimeindex (datetime_or_doy )
121131 RoverR0sqrd = solarposition .pyephem_earthsun_distance (times ) ** (- 2 )
122132 elif method == 'nrel' :
123- times = input_to_datetimeindex (datetime_or_doy )
133+ times = to_datetimeindex (datetime_or_doy )
124134 RoverR0sqrd = \
125135 solarposition .nrel_earthsun_distance (times , ** kwargs ) ** (- 2 )
126136 else :
127137 raise ValueError ('Invalid method: %s' , method )
128138
129139 Ea = solar_constant * RoverR0sqrd
130140
131- return Ea
132-
133-
134- def _scalar_to_datetimeindex (doy_scalar ):
135- """
136- Convert a scalar day of year number to a pd.DatetimeIndex.
141+ Ea = to_output (Ea )
137142
138- Parameters
139- ----------
140- doy_array : int or float
141- Contains days of the year
142-
143- Returns
144- -------
145- pd.DatetimeIndex
146- """
147- return pd .DatetimeIndex ([_doy_to_timestamp (doy_scalar )])
148-
149-
150- def _array_to_datetimeindex (doy_array ):
151- """
152- Convert an array of day of year numbers to a pd.DatetimeIndex.
153-
154- Parameters
155- ----------
156- doy_array : Iterable
157- Contains days of the year
158-
159- Returns
160- -------
161- pd.DatetimeIndex
162- """
163- return pd .DatetimeIndex (list (map (_doy_to_timestamp , doy_array )))
164-
165-
166- def _doy_to_timestamp (doy , epoch = '2013-12-31' ):
167- """
168- Convert a numeric day of the year to a pd.Timestamp.
169-
170- Parameters
171- ----------
172- doy : int or float.
173- Numeric day of year.
174- epoch : pd.Timestamp compatible object.
175- Date to which to add the day of year to.
176-
177- Returns
178- -------
179- pd.Timestamp
180- """
181- return pd .Timestamp ('2013-12-31' ) + datetime .timedelta (days = float (doy ))
143+ return Ea
182144
183145
184146def aoi_projection (surface_tilt , surface_azimuth , solar_zenith , solar_azimuth ):
0 commit comments