Skip to content

Commit ee32772

Browse files
committed
add basic_chain to modelchain
1 parent ab6063f commit ee32772

File tree

2 files changed

+267
-56
lines changed

2 files changed

+267
-56
lines changed

pvlib/modelchain.py

Lines changed: 201 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,157 @@
11
"""
2-
Stub documentation for the module.
2+
The ``modelchain`` module contains functions and classes that combine
3+
many of the PV power modeling steps. These tools make it easy to
4+
get started with pvlib and demonstrate standard ways to use the
5+
library. With great power comes great responsibility: users should take
6+
the time to read the source code for the module.
37
"""
48

9+
import pandas as pd
10+
11+
from pvlib import solarposition, pvsystem, clearsky, atmosphere
12+
import pvlib.irradiance # avoid name conflict with full import
13+
14+
15+
def basic_chain(times, latitude, longitude,
16+
module_parameters, inverter_parameters,
17+
irradiance=None, weather=None,
18+
surface_tilt=None, surface_azimuth=None,
19+
orientation_strategy=None,
20+
transposition_model='haydavies',
21+
solar_position_method='nrel_numpy',
22+
airmass_model='kastenyoung1989',
23+
**kwargs):
24+
"""
25+
A function that computes all of the modeling steps necessary for
26+
calculating power or energy for a PV system at a given location.
27+
28+
Parameters
29+
----------
30+
system : dict
31+
The connected set of modules, inverters, etc.
32+
keys must include latitude, longitude, module_parameters
33+
34+
location : dict
35+
The physical location at which to evaluate the model.
36+
37+
times : DatetimeIndex
38+
Times at which to evaluate the model.
39+
40+
orientation_strategy : None or str
41+
The strategy for aligning the modules.
42+
If not None, sets the ``surface_azimuth`` and ``surface_tilt``
43+
properties of the ``system``.
44+
45+
clearsky_model : str
46+
Passed to location.get_clearsky.
47+
48+
transposition_model : str
49+
Passed to system.get_irradiance.
50+
51+
solar_position_method : str
52+
Passed to location.get_solarposition.
53+
54+
**kwargs
55+
Arbitrary keyword arguments.
56+
See code for details.
57+
"""
58+
59+
# use surface_tilt and surface_azimuth if provided,
60+
# otherwise set them using the orientation_strategy
61+
if surface_tilt is not None and surface_azimuth is not None:
62+
pass
63+
elif orientation_strategy is not None:
64+
surface_tilt, surface_azimuth = \
65+
get_orientation(orientation_strategy, latitude=latitude)
66+
else:
67+
raise ValueError('orientation_strategy or surface_tilt and ' +
68+
'surface_azimuth must be provided')
69+
70+
times = times
71+
72+
solar_position = solarposition.get_solarposition(times, latitude,
73+
longitude, **kwargs)
74+
75+
# possible error with using apparent zenith with some models
76+
airmass = atmosphere.relativeairmass(solar_position['apparent_zenith'],
77+
model=airmass_model)
78+
airmass = atmosphere.absoluteairmass(airmass,
79+
kwargs.get('pressure', 101325.))
80+
dni_extra = pvlib.irradiance.extraradiation(solar_position.index)
81+
dni_extra = pd.Series(dni_extra, index=solar_position.index)
82+
83+
aoi = pvlib.irradiance.aoi(surface_tilt, surface_azimuth,
84+
solar_position['apparent_zenith'],
85+
solar_position['azimuth'])
86+
87+
if irradiance is None:
88+
irradiance = clearsky.ineichen(
89+
solar_position.index,
90+
latitude,
91+
longitude,
92+
zenith_data=solar_position['apparent_zenith'],
93+
airmass_data=airmass)
94+
95+
total_irrad = pvlib.irradiance.total_irrad(
96+
surface_tilt,
97+
surface_azimuth,
98+
solar_position['apparent_zenith'],
99+
solar_position['azimuth'],
100+
irradiance['dni'],
101+
irradiance['ghi'],
102+
irradiance['dhi'],
103+
model=transposition_model,
104+
dni_extra=dni_extra)
105+
106+
if weather is None:
107+
weather = {'wind_speed': 0, 'temp_air': 20}
108+
109+
temps = pvsystem.sapm_celltemp(total_irrad['poa_global'],
110+
weather['wind_speed'],
111+
weather['temp_air'])
112+
113+
dc = pvsystem.sapm(module_parameters, total_irrad['poa_direct'],
114+
total_irrad['poa_diffuse'],
115+
temps['temp_cell'],
116+
airmass,
117+
aoi)
118+
119+
ac = pvsystem.snlinverter(inverter_parameters, dc['v_mp'], dc['p_mp'])
120+
121+
return dc, ac
122+
123+
124+
def get_orientation(strategy, **kwargs):
125+
"""
126+
Determine a PV system's surface tilt and surface azimuth
127+
using a named strategy.
128+
129+
Parameters
130+
----------
131+
strategy: str
132+
The orientation strategy.
133+
Allowed strategies include 'flat', 'south_at_latitude_tilt'.
134+
**kwargs:
135+
Strategy-dependent keyword arguments. See code for details.
136+
137+
Returns
138+
-------
139+
surface_tilt, surface_azimuth
140+
"""
141+
142+
if strategy == 'south_at_latitude_tilt':
143+
surface_azimuth = 180
144+
surface_tilt = kwargs['latitude']
145+
elif strategy == 'flat':
146+
surface_azimuth = 180
147+
surface_tilt = 0
148+
else:
149+
raise ValueError('invalid orientation strategy. strategy must ' +
150+
'be one of south_at_latitude, flat,')
151+
152+
return surface_tilt, surface_azimuth
153+
154+
5155
class ModelChain(object):
6156
"""
7157
A class that represents all of the modeling steps necessary for
@@ -24,6 +174,7 @@ class ModelChain(object):
24174
The strategy for aligning the modules.
25175
If not None, sets the ``surface_azimuth`` and ``surface_tilt``
26176
properties of the ``system``.
177+
Allowed strategies include 'flat', 'south_at_latitude_tilt'.
27178
28179
clearsky_model : str
29180
Passed to location.get_clearsky.
@@ -58,36 +209,29 @@ def __init__(self, system, location,
58209
self.transposition_model = transposition_model
59210
self.solar_position_method = solar_position_method
60211
self.airmass_model = airmass_model
61-
212+
62213
# calls setter
63214
self.orientation_strategy = orientation_strategy
64-
215+
65216
@property
66217
def orientation_strategy(self):
67218
return self._orientation_strategy
68-
69-
219+
70220
@orientation_strategy.setter
71221
def orientation_strategy(self, strategy):
72-
if strategy is None or strategy == 'None':
73-
pass
74-
elif strategy == 'south_at_latitude_tilt':
75-
self.system.surface_azimuth = 180
76-
self.system.surface_tilt = self.location.latitude
77-
elif strategy == 'flat':
78-
self.system.surface_azimuth = 180
79-
self.system.surface_tilt = 0
80-
else:
81-
raise ValueError('invalid orientation strategy. strategy must ' +
82-
'be one of south_at_latitude, flat,')
222+
if strategy == 'None':
223+
strategy = None
224+
225+
if strategy is not None:
226+
self.system.surface_tilt, self.system.surface_azimuth = \
227+
get_orientation(strategy, latitude=self.location.latitude)
83228

84229
self._orientation_strategy = strategy
85-
86230

87231
def run_model(self, times, irradiance=None, weather=None):
88232
"""
89233
Run the model.
90-
234+
91235
Parameters
92236
----------
93237
times : DatetimeIndex
@@ -103,57 +247,65 @@ def run_model(self, times, irradiance=None, weather=None):
103247
-------
104248
output : DataFrame
105249
Some combination of AC power, DC power, POA irrad, etc.
250+
251+
Assigns attributes: times, solar_position, airmass, irradiance,
252+
total_irrad, weather, temps, aoi, dc, ac
106253
"""
107-
solar_position = self.location.get_solarposition(times)
108-
109-
airmass = self.location.get_airmass(solar_position=solar_position,
110-
model=self.airmass_model)
254+
self.times = times
255+
256+
self.solar_position = self.location.get_solarposition(self.times)
257+
258+
self.airmass = self.location.get_airmass(
259+
solar_position=self.solar_position, model=self.airmass_model)
111260

112261
if irradiance is None:
113-
irradiance = self.location.get_clearsky(solar_position.index,
114-
self.clearsky_model,
115-
zenith_data=solar_position['apparent_zenith'],
116-
airmass_data=airmass['airmass_absolute'])
117-
118-
total_irrad = self.system.get_irradiance(solar_position['apparent_zenith'],
119-
solar_position['azimuth'],
120-
irradiance['dni'],
121-
irradiance['ghi'],
122-
irradiance['dhi'],
123-
model=self.transposition_model)
262+
irradiance = self.location.get_clearsky(
263+
self.solar_position.index, self.clearsky_model,
264+
zenith_data=self.solar_position['apparent_zenith'],
265+
airmass_data=self.airmass['airmass_absolute'])
266+
self.irradiance = irradiance
267+
268+
self.total_irrad = self.system.get_irradiance(
269+
self.solar_position['apparent_zenith'],
270+
self.solar_position['azimuth'],
271+
self.irradiance['dni'],
272+
self.irradiance['ghi'],
273+
self.irradiance['dhi'],
274+
model=self.transposition_model)
124275

125276
if weather is None:
126277
weather = {'wind_speed': 0, 'temp_air': 20}
278+
self.weather = weather
127279

128-
temps = self.system.sapm_celltemp(total_irrad['poa_global'],
129-
weather['wind_speed'],
130-
weather['temp_air'])
280+
self.temps = self.system.sapm_celltemp(self.total_irrad['poa_global'],
281+
self.weather['wind_speed'],
282+
self.weather['temp_air'])
131283

132-
aoi = self.system.get_aoi(solar_position['apparent_zenith'],
133-
solar_position['azimuth'])
284+
self.aoi = self.system.get_aoi(self.solar_position['apparent_zenith'],
285+
self.solar_position['azimuth'])
134286

135-
dc = self.system.sapm(total_irrad['poa_direct'],
136-
total_irrad['poa_diffuse'],
137-
temps['temp_cell'],
138-
airmass['airmass_absolute'],
139-
aoi)
287+
self.dc = self.system.sapm(self.total_irrad['poa_direct'],
288+
self.total_irrad['poa_diffuse'],
289+
self.temps['temp_cell'],
290+
self.airmass['airmass_absolute'],
291+
self.aoi)
140292

141-
ac = self.system.snlinverter(dc['v_mp'], dc['p_mp'])
293+
self.ac = self.system.snlinverter(self.dc['v_mp'], self.dc['p_mp'])
142294

143-
return dc, ac
295+
return self.dc, self.ac
144296

145297

146298
def model_system(self):
147299
"""
148300
Model the system?
149-
301+
150302
I'm just copy/pasting example code...
151-
303+
152304
Returns
153305
-------
154306
???
155307
"""
156-
308+
157309
final_output = self.run_model()
158310
input = self.prettify_input()
159311
modeling_steps = self.get_modeling_steps()
@@ -166,7 +318,7 @@ class MoreSpecificModelChain(ModelChain):
166318
"""
167319
def __init__(self, *args, **kwargs):
168320
super(MoreSpecificModelChain, self).__init__(**kwargs)
169-
321+
170322
def run_model(self):
171323
# overrides the parent ModelChain method
172324
pass

0 commit comments

Comments
 (0)