Skip to content

Commit 2602596

Browse files
ModelChain model variation example to system-models (pvlib#2691)
* created plot_modelchain_model_variations.py file * add ModelChain temperature comparison example to system-models gallery * fixing temperature model consistency and display figures * enable execution of system-models examples in Sphinx Gallery * fixing flake8 * changing conf.py to allow files to run * prevent oedi example from executing during docs build by renaming file * Apply suggestions from code review Co-authored-by: Cliff Hansen <cwhanse@sandia.gov> --------- Co-authored-by: Cliff Hansen <cwhanse@sandia.gov>
1 parent 010cff7 commit 2602596

3 files changed

Lines changed: 198 additions & 2 deletions

File tree

File renamed without changes.
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
"""
2+
Varying Model Components in ModelChain
3+
======================================
4+
5+
This example demonstrates how changing modeling components
6+
within ``pvlib.modelchain.ModelChain`` affects simulation results.
7+
8+
Using the same PV system and weather data, we create two
9+
ModelChain instances that differ only in their temperature
10+
model. By comparing the resulting cell temperature and AC
11+
power output, we can see how changing a single modeling
12+
component affects overall system behavior.
13+
"""
14+
15+
# %%
16+
# Varying ModelChain components
17+
# ------------------------------
18+
#
19+
# Below, we create two ModelChain objects with identical system
20+
# definitions and weather inputs. The only difference between them
21+
# is the selected temperature model. This highlights how individual
22+
# modeling components in ``ModelChain`` can be swapped while keeping
23+
# the overall workflow unchanged.
24+
25+
import pvlib
26+
import pandas as pd
27+
import numpy as np
28+
import matplotlib.pyplot as plt
29+
30+
# %%
31+
# Define location
32+
# ---------------
33+
#
34+
# We select Tucson, Arizona, a location frequently used in pvlib
35+
# examples due to its strong solar resource and available TMY data.
36+
latitude = 32.2
37+
longitude = -110.9
38+
location = pvlib.location.Location(latitude, longitude)
39+
40+
# %%
41+
# Generate clear-sky weather data
42+
# --------------------------------
43+
#
44+
# We generate clear-sky irradiance using pvlib and create a
45+
# varying air temperature profile instead of using constant
46+
# values.
47+
times = pd.date_range(
48+
"2019-06-01 00:00",
49+
"2019-06-07 23:00",
50+
freq="1h",
51+
tz="Etc/GMT+7",
52+
)
53+
54+
# Clear-sky irradiance
55+
clearsky = location.get_clearsky(times)
56+
57+
# Create a simple daily temperature cycle
58+
temp_air = 20 + 10 * np.sin(2 * np.pi * (times.hour - 6) / 24)
59+
60+
weather_subset = clearsky.copy()
61+
weather_subset["temp_air"] = temp_air
62+
weather_subset["wind_speed"] = 1
63+
64+
# %%
65+
# Define a simple PV system
66+
# -------------------------
67+
#
68+
# To keep the focus on the temperature model comparison,
69+
# we define a minimal PV system using the PVWatts DC and AC models.
70+
# These models require only a few high-level parameters.
71+
#
72+
# The module DC rating (pdc0) represents the array capacity at
73+
# reference conditions, and gamma_pdc describes the power
74+
# temperature coefficient.
75+
#
76+
# For the temperature model parameters, we use the sapm values
77+
# for an open-rack, glass-glass module configuration. These
78+
# parameters describe how heat is transferred from the module
79+
# to the surrounding environment.
80+
module_parameters = dict(pdc0=5000, gamma_pdc=-0.003)
81+
inverter_parameters = dict(pdc0=4000)
82+
83+
temperature_model_parameters = (
84+
pvlib.temperature.TEMPERATURE_MODEL_PARAMETERS["sapm"]
85+
["open_rack_glass_glass"]
86+
)
87+
88+
system = pvlib.pvsystem.PVSystem(
89+
surface_tilt=30,
90+
surface_azimuth=180,
91+
module_parameters=module_parameters,
92+
inverter_parameters=inverter_parameters,
93+
temperature_model_parameters=temperature_model_parameters,
94+
)
95+
96+
# %%
97+
# ModelChain using the sapm temperature model
98+
# --------------------------------------------
99+
#
100+
# First, we construct a ModelChain that uses the sapm
101+
# temperature model. All other modeling components remain
102+
# identical between simulations.
103+
#
104+
# This ensures that any differences in the results arise
105+
# solely from the temperature model choice.
106+
temperature_model_parameters_sapm = (
107+
pvlib.temperature.TEMPERATURE_MODEL_PARAMETERS["sapm"]
108+
["open_rack_glass_glass"]
109+
)
110+
111+
system_sapm = pvlib.pvsystem.PVSystem(
112+
surface_tilt=30,
113+
surface_azimuth=180,
114+
module_parameters=module_parameters,
115+
inverter_parameters=inverter_parameters,
116+
temperature_model_parameters=temperature_model_parameters_sapm,
117+
)
118+
119+
mc_sapm = pvlib.modelchain.ModelChain(
120+
system_sapm,
121+
location,
122+
dc_model="pvwatts",
123+
ac_model="pvwatts",
124+
temperature_model="sapm",
125+
aoi_model="no_loss",
126+
)
127+
128+
mc_sapm.run_model(weather_subset)
129+
130+
# %%
131+
# ModelChain using the Faiman temperature model
132+
# ----------------------------------------------
133+
#
134+
# Next, we repeat the same simulation but replace the
135+
# temperature model with the Faiman model.
136+
#
137+
# No other system or weather parameters are changed.
138+
# This illustrates how individual components within
139+
# ModelChain can be varied independently.
140+
temperature_model_parameters_faiman = dict(u0=25, u1=6.84)
141+
142+
system_faiman = pvlib.pvsystem.PVSystem(
143+
surface_tilt=30,
144+
surface_azimuth=180,
145+
module_parameters=module_parameters,
146+
inverter_parameters=inverter_parameters,
147+
temperature_model_parameters=temperature_model_parameters_faiman,
148+
)
149+
150+
mc_faiman = pvlib.modelchain.ModelChain(
151+
system_faiman,
152+
location,
153+
dc_model="pvwatts",
154+
ac_model="pvwatts",
155+
temperature_model="faiman",
156+
aoi_model="no_loss",
157+
)
158+
159+
mc_faiman.run_model(weather_subset)
160+
161+
# %%
162+
# Compare modeled cell temperature
163+
# ---------------------------------
164+
#
165+
# Since module temperature directly affects DC power
166+
# through the temperature coefficient, differences
167+
# between temperature models can propagate into
168+
# performance results.
169+
170+
# %%
171+
fig, ax = plt.subplots(figsize=(10, 4))
172+
mc_sapm.results.cell_temperature.plot(ax=ax, label="SAPM")
173+
mc_faiman.results.cell_temperature.plot(ax=ax, label="Faiman")
174+
175+
ax.set_ylabel("Cell Temperature (°C)")
176+
ax.set_title("Comparison of Cell Temperature")
177+
ax.legend()
178+
plt.tight_layout()
179+
180+
# %%
181+
# Compare AC power output
182+
# ------------------------
183+
#
184+
# Finally, we compare the resulting AC power. In this case, the
185+
# differences in temperature modeling lead to small
186+
# differences in predicted energy production.
187+
188+
# %%
189+
fig, ax = plt.subplots(figsize=(10, 4))
190+
mc_sapm.results.ac.plot(ax=ax, label="SAPM")
191+
mc_faiman.results.ac.plot(ax=ax, label="Faiman")
192+
193+
ax.set_ylabel("AC Power (W)")
194+
ax.set_title("AC Output with Different Temperature Models")
195+
ax.legend()
196+
plt.tight_layout()

docs/sphinx/source/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,8 @@ def setup(app):
388388
sphinx_gallery_conf = {
389389
'examples_dirs': ['../../examples'], # location of gallery scripts
390390
'gallery_dirs': ['gallery'], # location of generated output
391-
# execute all scripts except for ones in the "system-models" directory:
392-
'filename_pattern': '^((?!system-models).)*$',
391+
# execute only files starting with plot_
392+
'filename_pattern': 'plot_',
393393

394394
# directory where function/class granular galleries are stored
395395
'backreferences_dir': 'reference/generated/gallery_backreferences',

0 commit comments

Comments
 (0)