5
5
6
6
from __future__ import division
7
7
8
- import logging
9
- logger = logging .getLogger ('pvlib' )
10
-
11
8
import os
12
9
from collections import OrderedDict
13
10
14
11
import numpy as np
15
12
import pandas as pd
16
13
17
14
from pvlib import tools
18
- from pvlib import irradiance
19
- from pvlib import atmosphere
20
- from pvlib import solarposition
21
15
22
16
23
- def ineichen (time , latitude , longitude , altitude = 0 , linke_turbidity = None ,
24
- solarposition_method = 'nrel_numpy' , zenith_data = None ,
25
- airmass_model = 'young1994' , airmass_data = None ,
26
- interp_turbidity = True ):
17
+ def ineichen (apparent_zenith , airmass_absolute , linke_turbidity ,
18
+ altitude = 0 , dni_extra = 1364. ):
27
19
'''
28
- Determine clear sky GHI, DNI, and DHI from Ineichen/Perez model
20
+ Determine clear sky GHI, DNI, and DHI from Ineichen/Perez model.
29
21
30
- Implements the Ineichen and Perez clear sky model for global horizontal
31
- irradiance (GHI), direct normal irradiance (DNI), and calculates
32
- the clear-sky diffuse horizontal (DHI) component as the difference
33
- between GHI and DNI*cos(zenith) as presented in [1, 2]. A report on clear
34
- sky models found the Ineichen/Perez model to have excellent performance
35
- with a minimal input data set [3].
22
+ Implements the Ineichen and Perez clear sky model for global
23
+ horizontal irradiance (GHI), direct normal irradiance (DNI), and
24
+ calculates the clear-sky diffuse horizontal (DHI) component as the
25
+ difference between GHI and DNI*cos(zenith) as presented in [1, 2]. A
26
+ report on clear sky models found the Ineichen/Perez model to have
27
+ excellent performance with a minimal input data set [3].
36
28
37
- Default values for montly Linke turbidity provided by SoDa [4, 5].
29
+ Default values for monthly Linke turbidity provided by SoDa [4, 5].
38
30
39
31
Parameters
40
32
-----------
41
- time : pandas.DatetimeIndex
42
-
43
- latitude : float
44
-
45
- longitude : float
46
-
47
- altitude : float
48
-
49
- linke_turbidity : None or float
50
- If None, uses ``LinkeTurbidities.mat`` lookup table.
33
+ apparent_zenith: numeric
34
+ Refraction corrected solar zenith angle in degrees.
51
35
52
- solarposition_method : string
53
- Sets the solar position algorithm.
54
- See solarposition.get_solarposition()
36
+ airmass_absolute: numeric
37
+ Pressure corrected airmass.
55
38
56
- zenith_data : None or Series
57
- If None, ephemeris data will be calculated using ``solarposition_method`` .
39
+ linke_turbidity: numeric
40
+ Linke Turbidity .
58
41
59
- airmass_model : string
60
- See pvlib.airmass.relativeairmass() .
42
+ altitude: numeric
43
+ Altitude above sea level in meters .
61
44
62
- airmass_data : None or Series
63
- If None, absolute air mass data will be calculated using
64
- ``airmass_model`` and location.alitude.
65
-
66
- interp_turbidity : bool
67
- If ``True``, interpolates the monthly Linke turbidity values
68
- found in ``LinkeTurbidities.mat`` to daily values.
45
+ dni_extra: numeric
46
+ Extraterrestrial irradiance. The units of ``dni_extra``
47
+ determine the units of the output.
69
48
70
49
Returns
71
- --------
72
- DataFrame with the following columns: ``ghi, dni, dhi``.
50
+ -------
51
+ clearsky : DataFrame (if Series input) or OrderedDict of arrays
52
+ DataFrame/OrderedDict contains the columns/keys
53
+ ``'dhi', 'dni', 'ghi'``.
73
54
74
- Notes
75
- -----
76
- If you are using this function
77
- in a loop, it may be faster to load LinkeTurbidities.mat outside of
78
- the loop and feed it in as a keyword argument, rather than
79
- having the function open and process the file each time it is called.
55
+ See also
56
+ --------
57
+ lookup_linke_turbidity
58
+ pvlib.location.Location.get_clearsky
80
59
81
60
References
82
61
----------
83
-
84
62
[1] P. Ineichen and R. Perez, "A New airmass independent formulation for
85
- the Linke turbidity coefficient", Solar Energy, vol 73, pp. 151-157, 2002.
63
+ the Linke turbidity coefficient", Solar Energy, vol 73, pp. 151-157,
64
+ 2002.
86
65
87
66
[2] R. Perez et. al., "A New Operational Model for Satellite-Derived
88
67
Irradiances: Description and Validation", Solar Energy, vol 73, pp.
@@ -98,97 +77,76 @@ def ineichen(time, latitude, longitude, altitude=0, linke_turbidity=None,
98
77
[5] J. Remund, et. al., "Worldwide Linke Turbidity Information", Proc.
99
78
ISES Solar World Congress, June 2003. Goteborg, Sweden.
100
79
'''
101
- # Initial implementation of this algorithm by Matthew Reno.
102
- # Ported to python by Rob Andrews
103
- # Added functionality by Will Holmgren (@wholmgren)
104
-
105
- I0 = irradiance .extraradiation (time .dayofyear )
106
-
107
- if zenith_data is None :
108
- ephem_data = solarposition .get_solarposition (time ,
109
- latitude = latitude ,
110
- longitude = longitude ,
111
- altitude = altitude ,
112
- method = solarposition_method )
113
- time = ephem_data .index # fixes issue with time possibly not being tz-aware
114
- try :
115
- ApparentZenith = ephem_data ['apparent_zenith' ]
116
- except KeyError :
117
- ApparentZenith = ephem_data ['zenith' ]
118
- logger .warning ('could not find apparent_zenith. using zenith' )
119
- else :
120
- ApparentZenith = zenith_data
121
- #ApparentZenith[ApparentZenith >= 90] = 90 # can cause problems in edge cases
122
-
123
-
124
- if linke_turbidity is None :
125
- TL = lookup_linke_turbidity (time , latitude , longitude ,
126
- interp_turbidity = interp_turbidity )
127
- else :
128
- TL = linke_turbidity
129
-
130
- # Get the absolute airmass assuming standard local pressure (per
131
- # alt2pres) using Kasten and Young's 1989 formula for airmass.
132
80
133
- if airmass_data is None :
134
- AMabsolute = atmosphere .absoluteairmass (airmass_relative = atmosphere .relativeairmass (ApparentZenith , airmass_model ),
135
- pressure = atmosphere .alt2pres (altitude ))
136
- else :
137
- AMabsolute = airmass_data
81
+ # Dan's note on the TL correction: By my reading of the publication
82
+ # on pages 151-157, Ineichen and Perez introduce (among other
83
+ # things) three things. 1) Beam model in eqn. 8, 2) new turbidity
84
+ # factor in eqn 9 and appendix A, and 3) Global horizontal model in
85
+ # eqn. 11. They do NOT appear to use the new turbidity factor (item
86
+ # 2 above) in either the beam or GHI models. The phrasing of
87
+ # appendix A seems as if there are two separate corrections, the
88
+ # first correction is used to correct the beam/GHI models, and the
89
+ # second correction is used to correct the revised turibidity
90
+ # factor. In my estimation, there is no need to correct the
91
+ # turbidity factor used in the beam/GHI models.
92
+
93
+ # Create the corrected TL for TL < 2
94
+ # TLcorr = TL;
95
+ # TLcorr(TL < 2) = TLcorr(TL < 2) - 0.25 .* (2-TLcorr(TL < 2)) .^ (0.5);
96
+
97
+ # This equation is found in Solar Energy 73, pg 311. Full ref: Perez
98
+ # et. al., Vol. 73, pp. 307-317 (2002). It is slightly different
99
+ # than the equation given in Solar Energy 73, pg 156. We used the
100
+ # equation from pg 311 because of the existence of known typos in
101
+ # the pg 156 publication (notably the fh2-(TL-1) should be fh2 *
102
+ # (TL-1)).
103
+
104
+ # The NaN handling is a little subtle. The AM input is likely to
105
+ # have NaNs that we'll want to map to 0s in the output. However, we
106
+ # want NaNs in other inputs to propagate through to the output. This
107
+ # is accomplished by judicious use and placement of np.maximum,
108
+ # np.minimum, and np.fmax
109
+
110
+ # use max so that nighttime values will result in 0s instead of
111
+ # negatives. propagates nans.
112
+ cos_zenith = np .maximum (tools .cosd (apparent_zenith ), 0 )
113
+
114
+ tl = linke_turbidity
138
115
139
116
fh1 = np .exp (- altitude / 8000. )
140
117
fh2 = np .exp (- altitude / 1250. )
141
118
cg1 = 5.09e-05 * altitude + 0.868
142
119
cg2 = 3.92e-05 * altitude + 0.0387
143
- logger .debug ('fh1=%s, fh2=%s, cg1=%s, cg2=%s' , fh1 , fh2 , cg1 , cg2 )
144
-
145
- # Dan's note on the TL correction: By my reading of the publication on
146
- # pages 151-157, Ineichen and Perez introduce (among other things) three
147
- # things. 1) Beam model in eqn. 8, 2) new turbidity factor in eqn 9 and
148
- # appendix A, and 3) Global horizontal model in eqn. 11. They do NOT appear
149
- # to use the new turbidity factor (item 2 above) in either the beam or GHI
150
- # models. The phrasing of appendix A seems as if there are two separate
151
- # corrections, the first correction is used to correct the beam/GHI models,
152
- # and the second correction is used to correct the revised turibidity
153
- # factor. In my estimation, there is no need to correct the turbidity
154
- # factor used in the beam/GHI models.
155
-
156
- # Create the corrected TL for TL < 2
157
- # TLcorr = TL;
158
- # TLcorr(TL < 2) = TLcorr(TL < 2) - 0.25 .* (2-TLcorr(TL < 2)) .^ (0.5);
159
-
160
- # This equation is found in Solar Energy 73, pg 311.
161
- # Full ref: Perez et. al., Vol. 73, pp. 307-317 (2002).
162
- # It is slightly different than the equation given in Solar Energy 73, pg 156.
163
- # We used the equation from pg 311 because of the existence of known typos
164
- # in the pg 156 publication (notably the fh2-(TL-1) should be fh2 * (TL-1)).
165
-
166
- cos_zenith = tools .cosd (ApparentZenith )
167
-
168
- clearsky_GHI = ( cg1 * I0 * cos_zenith *
169
- np .exp (- cg2 * AMabsolute * (fh1 + fh2 * (TL - 1 ))) *
170
- np .exp (0.01 * AMabsolute ** 1.8 ) )
171
- clearsky_GHI [clearsky_GHI < 0 ] = 0
172
-
173
- # BncI == "normal beam clear sky radiation"
120
+
121
+ ghi = (np .exp (- cg2 * airmass_absolute * (fh1 + fh2 * (tl - 1 ))) *
122
+ np .exp (0.01 * airmass_absolute ** 1.8 ))
123
+ # use fmax to map airmass nans to 0s. multiply and divide by tl to
124
+ # reinsert tl nans
125
+ ghi = cg1 * dni_extra * cos_zenith * tl / tl * np .fmax (ghi , 0 )
126
+
127
+ # BncI = "normal beam clear sky radiation"
174
128
b = 0.664 + 0.163 / fh1
175
- BncI = b * I0 * np .exp ( - 0.09 * AMabsolute * (TL - 1 ) )
176
- logger . debug ( 'b=%s' , b )
129
+ bnci = b * np .exp (- 0.09 * airmass_absolute * (tl - 1 ))
130
+ bnci = dni_extra * np . fmax ( bnci , 0 )
177
131
178
132
# "empirical correction" SE 73, 157 & SE 73, 312.
179
- BncI_2 = ( clearsky_GHI *
180
- ( 1 - ( 0.1 - 0.2 * np . exp ( - TL )) / ( 0.1 + 0.882 / fh1 ) ) /
181
- cos_zenith )
133
+ bnci_2 = (( 1 - ( 0.1 - 0.2 * np . exp ( - tl )) / ( 0.1 + 0.882 / fh1 )) /
134
+ cos_zenith )
135
+ bnci_2 = ghi * np . fmin ( np . fmax ( bnci_2 , 0 ), 1e20 )
182
136
183
- clearsky_DNI = np .minimum (BncI , BncI_2 )
137
+ dni = np .minimum (bnci , bnci_2 )
184
138
185
- clearsky_DHI = clearsky_GHI - clearsky_DNI * cos_zenith
139
+ dhi = ghi - dni * cos_zenith
140
+
141
+ irrads = OrderedDict ()
142
+ irrads ['ghi' ] = ghi
143
+ irrads ['dni' ] = dni
144
+ irrads ['dhi' ] = dhi
186
145
187
- df_out = pd .DataFrame ({'ghi' :clearsky_GHI , 'dni' :clearsky_DNI ,
188
- 'dhi' :clearsky_DHI })
189
- df_out .fillna (0 , inplace = True )
146
+ if isinstance (dni , pd .Series ):
147
+ irrads = pd .DataFrame .from_dict (irrads )
190
148
191
- return df_out
149
+ return irrads
192
150
193
151
194
152
def lookup_linke_turbidity (time , latitude , longitude , filepath = None ,
@@ -242,14 +200,17 @@ def lookup_linke_turbidity(time, latitude, longitude, filepath=None,
242
200
mat = scipy .io .loadmat (filepath )
243
201
linke_turbidity_table = mat ['LinkeTurbidity' ]
244
202
245
- latitude_index = np .around (_linearly_scale (latitude , 90 , - 90 , 1 , 2160 )).astype (np .int64 )
246
- longitude_index = np .around (_linearly_scale (longitude , - 180 , 180 , 1 , 4320 )).astype (np .int64 )
203
+ latitude_index = (
204
+ np .around (_linearly_scale (latitude , 90 , - 90 , 1 , 2160 ))
205
+ .astype (np .int64 ))
206
+ longitude_index = (
207
+ np .around (_linearly_scale (longitude , - 180 , 180 , 1 , 4320 ))
208
+ .astype (np .int64 ))
247
209
248
210
g = linke_turbidity_table [latitude_index ][longitude_index ]
249
211
250
212
if interp_turbidity :
251
- logger .info ('interpolating turbidity to the day' )
252
- # Cata covers 1 year.
213
+ # Data covers 1 year.
253
214
# Assume that data corresponds to the value at
254
215
# the middle of each month.
255
216
# This means that we need to add previous Dec and next Jan
@@ -262,10 +223,9 @@ def lookup_linke_turbidity(time, latitude, longitude, filepath=None,
262
223
linke_turbidity = pd .Series (np .interp (time .dayofyear , days , g2 ),
263
224
index = time )
264
225
else :
265
- logger .info ('using monthly turbidity' )
266
- apply_month = lambda x : g [x [0 ]- 1 ]
267
226
linke_turbidity = pd .DataFrame (time .month , index = time )
268
- linke_turbidity = linke_turbidity .apply (apply_month , axis = 1 )
227
+ # apply monthly data
228
+ linke_turbidity = linke_turbidity .apply (lambda x : g [x [0 ]- 1 ], axis = 1 )
269
229
270
230
linke_turbidity /= 20.
271
231
@@ -312,11 +272,11 @@ def haurwitz(apparent_zenith):
312
272
313
273
cos_zenith = tools .cosd (apparent_zenith )
314
274
315
- clearsky_GHI = 1098.0 * cos_zenith * np .exp (- 0.059 / cos_zenith )
275
+ clearsky_ghi = 1098.0 * cos_zenith * np .exp (- 0.059 / cos_zenith )
316
276
317
- clearsky_GHI [ clearsky_GHI < 0 ] = 0
277
+ clearsky_ghi [ clearsky_ghi < 0 ] = 0
318
278
319
- df_out = pd .DataFrame ({'ghi' :clearsky_GHI })
279
+ df_out = pd .DataFrame ({'ghi' : clearsky_ghi })
320
280
321
281
return df_out
322
282
@@ -326,8 +286,8 @@ def _linearly_scale(inputmatrix, inputmin, inputmax, outputmin, outputmax):
326
286
327
287
inputrange = inputmax - inputmin
328
288
outputrange = outputmax - outputmin
329
- OutputMatrix = (inputmatrix - inputmin ) * outputrange / inputrange + outputmin
330
- return OutputMatrix
289
+ outputmatrix = (inputmatrix - inputmin ) * outputrange / inputrange + outputmin
290
+ return outputmatrix
331
291
332
292
333
293
def simplified_solis (apparent_elevation , aod700 = 0.1 , precipitable_water = 1. ,
@@ -360,16 +320,15 @@ def simplified_solis(apparent_elevation, aod700=0.1, precipitable_water=1.,
360
320
or 101325 and 41000 Pascals.
361
321
362
322
dni_extra: numeric
363
- Extraterrestrial irradiance.
323
+ Extraterrestrial irradiance. The units of ``dni_extra``
324
+ determine the units of the output.
364
325
365
326
Returns
366
- --------
327
+ -------
367
328
clearsky : DataFrame (if Series input) or OrderedDict of arrays
368
329
DataFrame/OrderedDict contains the columns/keys
369
330
``'dhi', 'dni', 'ghi'``.
370
331
371
- The units of ``dni_extra`` determine the units of the output.
372
-
373
332
References
374
333
----------
375
334
.. [1] P. Ineichen, "A broadband simplified version of the
0 commit comments