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,65 @@ 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
+
86
+
87
+
90
88
def __str__ (self ):
91
89
return ('{}: latitude={}, longitude={}, tz={}, altitude={}'
92
- .format (self .name , self .latitude , self .longitude ,
90
+ .format (self .name , self .latitude , self .longitude ,
93
91
self .tz , self .altitude ))
94
-
95
-
92
+
93
+
96
94
@classmethod
97
95
def from_tmy (cls , tmy_metadata , tmy_data = None , ** kwargs ):
98
96
"""
99
- Create an object based on a metadata
97
+ Create an object based on a metadata
100
98
dictionary from tmy2 or tmy3 data readers.
101
-
99
+
102
100
Parameters
103
101
----------
104
102
tmy_metadata : dict
105
103
Returned from tmy.readtmy2 or tmy.readtmy3
106
104
tmy_data : None or DataFrame
107
105
Optionally attach the TMY data to this object.
108
-
106
+
109
107
Returns
110
108
-------
111
109
Location object (or the child class of Location that you
112
110
called this method from).
113
111
"""
114
112
# not complete, but hopefully you get the idea.
115
113
# might need code to handle the difference between tmy2 and tmy3
116
-
114
+
117
115
# determine if we're dealing with TMY2 or TMY3 data
118
116
tmy2 = tmy_metadata .get ('City' , False )
119
-
117
+
120
118
latitude = tmy_metadata ['latitude' ]
121
119
longitude = tmy_metadata ['longitude' ]
122
-
120
+
123
121
if tmy2 :
124
122
name = tmy_metadata ['City' ]
125
- else :
123
+ else :
126
124
name = tmy_metadata ['Name' ]
127
-
125
+
128
126
tz = tmy_metadata ['TZ' ]
129
127
altitude = tmy_metadata ['altitude' ]
130
128
131
129
new_object = cls (latitude , longitude , tz = tz , altitude = altitude ,
132
130
name = name , ** kwargs )
133
-
131
+
134
132
# not sure if this should be assigned regardless of input.
135
133
if tmy_data is not None :
136
134
new_object .tmy_data = tmy_data
137
-
135
+
138
136
return new_object
139
137
140
138
@@ -143,7 +141,7 @@ def get_solarposition(self, times, pressure=None, temperature=12,
143
141
"""
144
142
Uses the :py:func:`solarposition.get_solarposition` function
145
143
to calculate the solar zenith, azimuth, etc. at this location.
146
-
144
+
147
145
Parameters
148
146
----------
149
147
times : DatetimeIndex
@@ -153,7 +151,7 @@ def get_solarposition(self, times, pressure=None, temperature=12,
153
151
temperature : None, float, or array-like
154
152
155
153
kwargs passed to :py:func:`solarposition.get_solarposition`
156
-
154
+
157
155
Returns
158
156
-------
159
157
solar_position : DataFrame
@@ -175,22 +173,24 @@ def get_clearsky(self, times, model='ineichen', **kwargs):
175
173
"""
176
174
Calculate the clear sky estimates of GHI, DNI, and/or DHI
177
175
at this location.
178
-
176
+
179
177
Parameters
180
178
----------
181
179
times : DatetimeIndex
182
-
180
+
183
181
model : str
184
- The clear sky model to use.
185
-
186
- kwargs passed to the relevant function(s).
187
-
182
+ The clear sky model to use. Must be one of
183
+ 'ineichen', 'haurwitz', 'simplified_solis'.
184
+
185
+ kwargs passed to the relevant functions. Climatological values
186
+ are assumed in many cases. See code for details.
187
+
188
188
Returns
189
189
-------
190
190
clearsky : DataFrame
191
191
Column names are: ``ghi, dni, dhi``.
192
192
"""
193
-
193
+
194
194
if model == 'ineichen' :
195
195
cs = clearsky .ineichen (times , latitude = self .latitude ,
196
196
longitude = self .longitude ,
@@ -199,18 +199,42 @@ def get_clearsky(self, times, model='ineichen', **kwargs):
199
199
elif model == 'haurwitz' :
200
200
solpos = self .get_solarposition (times , ** kwargs )
201
201
cs = clearsky .haurwitz (solpos ['apparent_zenith' ])
202
+ elif model == 'simplified_solis' :
203
+
204
+ # these try/excepts define default values that are only
205
+ # evaluated if necessary. ineichen does some of this internally
206
+ try :
207
+ dni_extra = kwargs .pop ('dni_extra' )
208
+ except KeyError :
209
+ dni_extra = irradiance .extraradiation (times .dayofyear )
210
+
211
+ try :
212
+ pressure = kwargs .pop ('pressure' )
213
+ except KeyError :
214
+ pressure = atmosphere .alt2pres (self .altitude )
215
+
216
+ try :
217
+ apparent_elevation = kwargs .pop ('apparent_elevation' )
218
+ except KeyError :
219
+ solpos = self .get_solarposition (
220
+ times , pressure = pressure , ** kwargs )
221
+ apparent_elevation = solpos ['apparent_elevation' ]
222
+
223
+ cs = clearsky .simplified_solis (
224
+ apparent_elevation , pressure = pressure , dni_extra = dni_extra ,
225
+ ** kwargs )
202
226
else :
203
227
raise ValueError ('{} is not a valid clear sky model'
204
228
.format (model ))
205
229
206
230
return cs
207
-
208
-
231
+
232
+
209
233
def get_airmass (self , times = None , solar_position = None ,
210
234
model = 'kastenyoung1989' ):
211
235
"""
212
236
Calculate the relative and absolute airmass.
213
-
237
+
214
238
Automatically chooses zenith or apparant zenith
215
239
depending on the selected model.
216
240
@@ -222,7 +246,7 @@ def get_airmass(self, times=None, solar_position=None,
222
246
DataFrame with with columns 'apparent_zenith', 'zenith'.
223
247
model : str
224
248
Relative airmass model
225
-
249
+
226
250
Returns
227
251
-------
228
252
airmass : DataFrame
@@ -250,4 +274,3 @@ def get_airmass(self, times=None, solar_position=None,
250
274
airmass ['airmass_absolute' ] = airmass_absolute
251
275
252
276
return airmass
253
-
0 commit comments