9
9
import pandas as pd
10
10
import pytz
11
11
12
- from pvlib import solarposition
13
- from pvlib import clearsky
14
- from pvlib import atmosphere
12
+ from pvlib import solarposition , clearsky , atmosphere , irradiance
15
13
16
14
17
15
class Location (object ):
18
16
"""
19
17
Location objects are convenient containers for latitude, longitude,
20
- timezone, and altitude data associated with a particular
18
+ timezone, and altitude data associated with a particular
21
19
geographic location. You can also assign a name to a location object.
22
-
23
- Location objects have two timezone attributes:
24
-
20
+
21
+ Location objects have two timezone attributes:
22
+
25
23
* ``tz`` is a IANA timezone string.
26
24
* ``pytz`` is a pytz timezone object.
27
-
25
+
28
26
Location objects support the print method.
29
-
27
+
30
28
Parameters
31
29
----------
32
30
latitude : float.
33
31
Positive is north of the equator.
34
32
Use decimal degrees notation.
35
-
36
- longitude : float.
33
+
34
+ longitude : float.
37
35
Positive is east of the prime meridian.
38
36
Use decimal degrees notation.
39
-
40
- tz : str, int, float, or pytz.timezone.
41
- See
37
+
38
+ tz : str, int, float, or pytz.timezone.
39
+ See
42
40
http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
43
41
for a list of valid time zones.
44
42
pytz.timezone objects will be converted to strings.
45
43
ints and floats must be in hours from UTC.
46
-
47
- alitude : float.
44
+
45
+ alitude : float.
48
46
Altitude from sea level in meters.
49
-
50
- name : None or string.
47
+
48
+ name : None or string.
51
49
Sets the name attribute of the Location object.
52
-
50
+
53
51
**kwargs
54
52
Arbitrary keyword arguments.
55
53
Included for compatibility, but not used.
56
-
54
+
57
55
See also
58
56
--------
59
57
pvsystem.PVSystem
60
58
"""
61
-
59
+
62
60
def __init__ (self , latitude , longitude , tz = 'UTC' , altitude = 0 ,
63
61
name = None , ** kwargs ):
64
-
62
+
65
63
self .latitude = latitude
66
64
self .longitude = longitude
67
-
65
+
68
66
if isinstance (tz , str ):
69
67
self .tz = tz
70
68
self .pytz = pytz .timezone (tz )
@@ -76,65 +74,63 @@ def __init__(self, latitude, longitude, tz='UTC', altitude=0,
76
74
self .pytz = pytz .FixedOffset (tz * 60 )
77
75
else :
78
76
raise TypeError ('Invalid tz specification' )
79
-
77
+
80
78
self .altitude = altitude
81
-
79
+
82
80
self .name = name
83
-
81
+
84
82
# needed for tying together Location and PVSystem in LocalizedPVSystem
85
83
# if LocalizedPVSystem signature is reversed
86
84
# super(Location, self).__init__(**kwargs)
87
-
88
-
89
-
85
+
90
86
def __repr__ (self ):
91
87
return ('{}: latitude={}, longitude={}, tz={}, altitude={}'
92
- .format (self .name , self .latitude , self .longitude ,
88
+ .format (self .name , self .latitude , self .longitude ,
93
89
self .tz , self .altitude ))
94
-
95
-
90
+
91
+
96
92
@classmethod
97
93
def from_tmy (cls , tmy_metadata , tmy_data = None , ** kwargs ):
98
94
"""
99
- Create an object based on a metadata
95
+ Create an object based on a metadata
100
96
dictionary from tmy2 or tmy3 data readers.
101
-
97
+
102
98
Parameters
103
99
----------
104
100
tmy_metadata : dict
105
101
Returned from tmy.readtmy2 or tmy.readtmy3
106
102
tmy_data : None or DataFrame
107
103
Optionally attach the TMY data to this object.
108
-
104
+
109
105
Returns
110
106
-------
111
107
Location object (or the child class of Location that you
112
108
called this method from).
113
109
"""
114
110
# not complete, but hopefully you get the idea.
115
111
# might need code to handle the difference between tmy2 and tmy3
116
-
112
+
117
113
# determine if we're dealing with TMY2 or TMY3 data
118
114
tmy2 = tmy_metadata .get ('City' , False )
119
-
115
+
120
116
latitude = tmy_metadata ['latitude' ]
121
117
longitude = tmy_metadata ['longitude' ]
122
-
118
+
123
119
if tmy2 :
124
120
name = tmy_metadata ['City' ]
125
- else :
121
+ else :
126
122
name = tmy_metadata ['Name' ]
127
-
123
+
128
124
tz = tmy_metadata ['TZ' ]
129
125
altitude = tmy_metadata ['altitude' ]
130
126
131
127
new_object = cls (latitude , longitude , tz = tz , altitude = altitude ,
132
128
name = name , ** kwargs )
133
-
129
+
134
130
# not sure if this should be assigned regardless of input.
135
131
if tmy_data is not None :
136
132
new_object .tmy_data = tmy_data
137
-
133
+
138
134
return new_object
139
135
140
136
@@ -143,7 +139,7 @@ def get_solarposition(self, times, pressure=None, temperature=12,
143
139
"""
144
140
Uses the :py:func:`solarposition.get_solarposition` function
145
141
to calculate the solar zenith, azimuth, etc. at this location.
146
-
142
+
147
143
Parameters
148
144
----------
149
145
times : DatetimeIndex
@@ -153,7 +149,7 @@ def get_solarposition(self, times, pressure=None, temperature=12,
153
149
temperature : None, float, or array-like
154
150
155
151
kwargs passed to :py:func:`solarposition.get_solarposition`
156
-
152
+
157
153
Returns
158
154
-------
159
155
solar_position : DataFrame
@@ -175,22 +171,24 @@ def get_clearsky(self, times, model='ineichen', **kwargs):
175
171
"""
176
172
Calculate the clear sky estimates of GHI, DNI, and/or DHI
177
173
at this location.
178
-
174
+
179
175
Parameters
180
176
----------
181
177
times : DatetimeIndex
182
-
178
+
183
179
model : str
184
- The clear sky model to use.
185
-
186
- kwargs passed to the relevant function(s).
187
-
180
+ The clear sky model to use. Must be one of
181
+ 'ineichen', 'haurwitz', 'simplified_solis'.
182
+
183
+ kwargs passed to the relevant functions. Climatological values
184
+ are assumed in many cases. See code for details.
185
+
188
186
Returns
189
187
-------
190
188
clearsky : DataFrame
191
189
Column names are: ``ghi, dni, dhi``.
192
190
"""
193
-
191
+
194
192
if model == 'ineichen' :
195
193
cs = clearsky .ineichen (times , latitude = self .latitude ,
196
194
longitude = self .longitude ,
@@ -199,18 +197,42 @@ def get_clearsky(self, times, model='ineichen', **kwargs):
199
197
elif model == 'haurwitz' :
200
198
solpos = self .get_solarposition (times , ** kwargs )
201
199
cs = clearsky .haurwitz (solpos ['apparent_zenith' ])
200
+ elif model == 'simplified_solis' :
201
+
202
+ # these try/excepts define default values that are only
203
+ # evaluated if necessary. ineichen does some of this internally
204
+ try :
205
+ dni_extra = kwargs .pop ('dni_extra' )
206
+ except KeyError :
207
+ dni_extra = irradiance .extraradiation (times .dayofyear )
208
+
209
+ try :
210
+ pressure = kwargs .pop ('pressure' )
211
+ except KeyError :
212
+ pressure = atmosphere .alt2pres (self .altitude )
213
+
214
+ try :
215
+ apparent_elevation = kwargs .pop ('apparent_elevation' )
216
+ except KeyError :
217
+ solpos = self .get_solarposition (
218
+ times , pressure = pressure , ** kwargs )
219
+ apparent_elevation = solpos ['apparent_elevation' ]
220
+
221
+ cs = clearsky .simplified_solis (
222
+ apparent_elevation , pressure = pressure , dni_extra = dni_extra ,
223
+ ** kwargs )
202
224
else :
203
225
raise ValueError ('{} is not a valid clear sky model'
204
226
.format (model ))
205
227
206
228
return cs
207
-
208
-
229
+
230
+
209
231
def get_airmass (self , times = None , solar_position = None ,
210
232
model = 'kastenyoung1989' ):
211
233
"""
212
234
Calculate the relative and absolute airmass.
213
-
235
+
214
236
Automatically chooses zenith or apparant zenith
215
237
depending on the selected model.
216
238
@@ -222,7 +244,7 @@ def get_airmass(self, times=None, solar_position=None,
222
244
DataFrame with with columns 'apparent_zenith', 'zenith'.
223
245
model : str
224
246
Relative airmass model
225
-
247
+
226
248
Returns
227
249
-------
228
250
airmass : DataFrame
@@ -250,4 +272,3 @@ def get_airmass(self, times=None, solar_position=None,
250
272
airmass ['airmass_absolute' ] = airmass_absolute
251
273
252
274
return airmass
253
-
0 commit comments