From 4c3f770ca3c198d4cec1059cd1161eb481ddb44c Mon Sep 17 00:00:00 2001 From: Aman Srivastava Date: Mon, 9 Feb 2026 17:51:16 +0530 Subject: [PATCH 1/6] created plot_modelchain_model_variations.py file --- docs/examples/system-models/plot_modelchain_model_variations.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/examples/system-models/plot_modelchain_model_variations.py diff --git a/docs/examples/system-models/plot_modelchain_model_variations.py b/docs/examples/system-models/plot_modelchain_model_variations.py new file mode 100644 index 0000000000..e69de29bb2 From c78d2c148270086ee81f65c916fdf422d427f544 Mon Sep 17 00:00:00 2001 From: Aman Srivastava Date: Mon, 9 Feb 2026 23:12:13 +0530 Subject: [PATCH 2/6] add ModelChain temperature comparison example to system-models gallery --- .../plot_modelchain_model_variations.py | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) diff --git a/docs/examples/system-models/plot_modelchain_model_variations.py b/docs/examples/system-models/plot_modelchain_model_variations.py index e69de29bb2..c63da90da7 100644 --- a/docs/examples/system-models/plot_modelchain_model_variations.py +++ b/docs/examples/system-models/plot_modelchain_model_variations.py @@ -0,0 +1,168 @@ +""" +Varying Model Components in ModelChain +====================================== + +This example demonstrates how changing modeling components +within ``pvlib.modelchain.ModelChain`` affects simulation results. + +Using the same PV system and weather data, we create two +ModelChain instances that differ only in their temperature +model. By comparing the resulting cell temperature and AC +power output, we can see how changing a single modeling +component affects overall system behavior. +""" + +# %% +# Varying ModelChain components +# ------------------------------ +# +# Below, we create two ModelChain objects with identical system +# definitions and weather inputs. The only difference between them +# is the selected temperature model. This highlights how individual +# modeling components in ``ModelChain`` can be swapped while keeping +# the overall workflow unchanged. + +import pvlib +import pandas as pd +import matplotlib.pyplot as plt + +# %% +# Define location +# --------------- +# +# We select Tucson, Arizona, a location frequently used in pvlib +# examples due to its strong solar resource and available TMY data. +latitude = 32.2 +longitude = -110.9 +location = pvlib.location.Location(latitude, longitude) + +# %% +# Create simple synthetic weather data +# ------------------------------------- +# +# To keep this example lightweight and fully reproducible, +# we generate a small synthetic weather dataset instead of +# downloading data from an external source. +# +# The weather values are kept constant so that any differences +# in results arise solely from the chosen temperature model. + +times = pd.date_range( + "2019-06-01 00:00", + "2019-06-07 23:00", + freq="1h", + tz="Etc/GMT+7", +) + +weather_subset = pd.DataFrame({ + "ghi": 800, + "dni": 600, + "dhi": 200, + "temp_air": 25, + "wind_speed": 1, +}, index=times) + +# %% +# Define a simple PV system +# ------------------------- +# +# To keep the focus on the temperature model comparison, +# we define a minimal PV system using the PVWatts DC and AC models. +# These models require only a few high-level parameters. +# +# The module DC rating (pdc0) represents the array capacity at +# reference conditions, and gamma_pdc describes the power +# temperature coefficient. +# +# For the temperature model parameters, we use the sapm values +# for an open-rack, glass-glass module configuration. These +# parameters describe how heat is transferred from the module +# to the surrounding environment. +module_parameters = dict(pdc0=5000, gamma_pdc=-0.003) +inverter_parameters = dict(pdc0=4000) + +temperature_model_parameters = ( + pvlib.temperature.TEMPERATURE_MODEL_PARAMETERS["sapm"] + ["open_rack_glass_glass"] +) + +system = pvlib.pvsystem.PVSystem( + surface_tilt=30, + surface_azimuth=180, + module_parameters=module_parameters, + inverter_parameters=inverter_parameters, + temperature_model_parameters=temperature_model_parameters, +) + +# %% +# ModelChain using the sapm temperature model +# -------------------------------------------- +# +# First, we construct a ModelChain that uses the sapm +# temperature model. All other modeling components remain +# identical between simulations. +# +# This ensures that any differences in the results arise +# solely from the temperature model choice. +mc_sapm = pvlib.modelchain.ModelChain( + system, + location, + dc_model="pvwatts", + ac_model="pvwatts", + temperature_model="sapm", +) + +mc_sapm.run_model(weather_subset) + +# %% +# ModelChain using the Faiman temperature model +# ---------------------------------------------- +# +# Next, we repeat the same simulation but replace the +# temperature model with the Faiman model. +# +# No other system or weather parameters are changed. +# This illustrates how individual components within +# ModelChain can be varied independently. +mc_faiman = pvlib.modelchain.ModelChain( + system, + location, + dc_model="pvwatts", + ac_model="pvwatts", + temperature_model="faiman", +) + +mc_faiman.run_model(weather_subset) + +# %% +# Compare modeled cell temperature +# --------------------------------- +# +# Since module temperature directly affects DC power +# through the temperature coefficient, differences +# between temperature models can propagate into +# performance results. +fig, ax = plt.subplots(figsize=(10, 4)) +mc_sapm.results.cell_temperature.plot(ax=ax, label="SAPM") +mc_faiman.results.cell_temperature.plot(ax=ax, label="Faiman") + +ax.set_ylabel("Cell Temperature (°C)") +ax.set_title("Comparison of Temperature Models") +ax.legend() +plt.tight_layout() + +# %% +# Compare AC power output +# ------------------------ +# +# Finally, we compare the resulting AC power. Even small +# differences in temperature modeling can lead to noticeable +# differences in predicted energy production. +fig, ax = plt.subplots(figsize=(10, 4)) +mc_sapm.results.ac.plot(ax=ax, label="SAPM") +mc_faiman.results.ac.plot(ax=ax, label="Faiman") + +ax.set_ylabel("AC Power (W)") +ax.set_title("AC Output with Different Temperature Models") +ax.legend() +plt.tight_layout() From b49cd1ce513d5300e606fd107b92f06544091856 Mon Sep 17 00:00:00 2001 From: Aman Srivastava Date: Tue, 10 Feb 2026 01:48:06 +0530 Subject: [PATCH 3/6] fixing temperature model consistency and display figures --- .../plot_modelchain_model_variations.py | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/docs/examples/system-models/plot_modelchain_model_variations.py b/docs/examples/system-models/plot_modelchain_model_variations.py index c63da90da7..c62967fdef 100644 --- a/docs/examples/system-models/plot_modelchain_model_variations.py +++ b/docs/examples/system-models/plot_modelchain_model_variations.py @@ -104,12 +104,26 @@ # # This ensures that any differences in the results arise # solely from the temperature model choice. +temperature_model_parameters_sapm = ( + pvlib.temperature.TEMPERATURE_MODEL_PARAMETERS["sapm"] + ["open_rack_glass_glass"] +) + +system_sapm = pvlib.pvsystem.PVSystem( + surface_tilt=30, + surface_azimuth=180, + module_parameters=module_parameters, + inverter_parameters=inverter_parameters, + temperature_model_parameters=temperature_model_parameters_sapm, +) + mc_sapm = pvlib.modelchain.ModelChain( - system, + system_sapm, location, dc_model="pvwatts", ac_model="pvwatts", temperature_model="sapm", + aoi_model="no_loss", ) mc_sapm.run_model(weather_subset) @@ -124,12 +138,23 @@ # No other system or weather parameters are changed. # This illustrates how individual components within # ModelChain can be varied independently. +temperature_model_parameters_faiman = dict(u0=25, u1=6.84) + +system_faiman = pvlib.pvsystem.PVSystem( + surface_tilt=30, + surface_azimuth=180, + module_parameters=module_parameters, + inverter_parameters=inverter_parameters, + temperature_model_parameters=temperature_model_parameters_faiman, +) + mc_faiman = pvlib.modelchain.ModelChain( - system, + system_faiman, location, dc_model="pvwatts", ac_model="pvwatts", temperature_model="faiman", + aoi_model="no_loss", ) mc_faiman.run_model(weather_subset) @@ -150,6 +175,7 @@ ax.set_title("Comparison of Temperature Models") ax.legend() plt.tight_layout() +plt.show() # %% # Compare AC power output @@ -166,3 +192,4 @@ ax.set_title("AC Output with Different Temperature Models") ax.legend() plt.tight_layout() +plt.show() From 7360834513c4597a13a87f3fa0573bbc58be18ef Mon Sep 17 00:00:00 2001 From: Aman Srivastava Date: Tue, 10 Feb 2026 21:01:29 +0530 Subject: [PATCH 4/6] enable execution of system-models examples in Sphinx Gallery --- .../plot_modelchain_model_variations.py | 37 ++++++++++--------- docs/sphinx/source/conf.py | 2 +- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/docs/examples/system-models/plot_modelchain_model_variations.py b/docs/examples/system-models/plot_modelchain_model_variations.py index c62967fdef..1cfa01bf4d 100644 --- a/docs/examples/system-models/plot_modelchain_model_variations.py +++ b/docs/examples/system-models/plot_modelchain_model_variations.py @@ -24,6 +24,7 @@ import pvlib import pandas as pd +import numpy as np import matplotlib.pyplot as plt # %% @@ -37,16 +38,12 @@ location = pvlib.location.Location(latitude, longitude) # %% -# Create simple synthetic weather data -# ------------------------------------- +# Generate clear-sky weather data +# -------------------------------- # -# To keep this example lightweight and fully reproducible, -# we generate a small synthetic weather dataset instead of -# downloading data from an external source. -# -# The weather values are kept constant so that any differences -# in results arise solely from the chosen temperature model. - +# We generate clear-sky irradiance using pvlib and create a +# varying air temperature profile instead of using constant +# values. times = pd.date_range( "2019-06-01 00:00", "2019-06-07 23:00", @@ -54,13 +51,15 @@ tz="Etc/GMT+7", ) -weather_subset = pd.DataFrame({ - "ghi": 800, - "dni": 600, - "dhi": 200, - "temp_air": 25, - "wind_speed": 1, -}, index=times) +# Clear-sky irradiance +clearsky = location.get_clearsky(times) + +# Create a simple daily temperature cycle +temp_air = 20 + 10 * np.sin(2 * np.pi * (times.hour - 6) / 24) + +weather_subset = clearsky.copy() +weather_subset["temp_air"] = temp_air +weather_subset["wind_speed"] = 1 # %% # Define a simple PV system @@ -167,6 +166,8 @@ # through the temperature coefficient, differences # between temperature models can propagate into # performance results. + +#%% fig, ax = plt.subplots(figsize=(10, 4)) mc_sapm.results.cell_temperature.plot(ax=ax, label="SAPM") mc_faiman.results.cell_temperature.plot(ax=ax, label="Faiman") @@ -175,7 +176,6 @@ ax.set_title("Comparison of Temperature Models") ax.legend() plt.tight_layout() -plt.show() # %% # Compare AC power output @@ -184,6 +184,8 @@ # Finally, we compare the resulting AC power. Even small # differences in temperature modeling can lead to noticeable # differences in predicted energy production. + +#%% fig, ax = plt.subplots(figsize=(10, 4)) mc_sapm.results.ac.plot(ax=ax, label="SAPM") mc_faiman.results.ac.plot(ax=ax, label="Faiman") @@ -192,4 +194,3 @@ ax.set_title("AC Output with Different Temperature Models") ax.legend() plt.tight_layout() -plt.show() diff --git a/docs/sphinx/source/conf.py b/docs/sphinx/source/conf.py index 0415acb644..bedfd4c0ce 100644 --- a/docs/sphinx/source/conf.py +++ b/docs/sphinx/source/conf.py @@ -389,7 +389,7 @@ def setup(app): 'examples_dirs': ['../../examples'], # location of gallery scripts 'gallery_dirs': ['gallery'], # location of generated output # execute all scripts except for ones in the "system-models" directory: - 'filename_pattern': '^((?!system-models).)*$', + 'filename_pattern': 'plot_', # directory where function/class granular galleries are stored 'backreferences_dir': 'reference/generated/gallery_backreferences', From eb1e810dc6e494c967e66d969dda3a7620d09ed1 Mon Sep 17 00:00:00 2001 From: Aman Srivastava Date: Tue, 10 Feb 2026 21:05:06 +0530 Subject: [PATCH 5/6] fixing flake8 --- .../system-models/plot_modelchain_model_variations.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/examples/system-models/plot_modelchain_model_variations.py b/docs/examples/system-models/plot_modelchain_model_variations.py index 1cfa01bf4d..ba05fac73f 100644 --- a/docs/examples/system-models/plot_modelchain_model_variations.py +++ b/docs/examples/system-models/plot_modelchain_model_variations.py @@ -41,8 +41,8 @@ # Generate clear-sky weather data # -------------------------------- # -# We generate clear-sky irradiance using pvlib and create a -# varying air temperature profile instead of using constant +# We generate clear-sky irradiance using pvlib and create a +# varying air temperature profile instead of using constant # values. times = pd.date_range( "2019-06-01 00:00", @@ -167,7 +167,7 @@ # between temperature models can propagate into # performance results. -#%% +# %% fig, ax = plt.subplots(figsize=(10, 4)) mc_sapm.results.cell_temperature.plot(ax=ax, label="SAPM") mc_faiman.results.cell_temperature.plot(ax=ax, label="Faiman") @@ -185,7 +185,7 @@ # differences in temperature modeling can lead to noticeable # differences in predicted energy production. -#%% +# %% fig, ax = plt.subplots(figsize=(10, 4)) mc_sapm.results.ac.plot(ax=ax, label="SAPM") mc_faiman.results.ac.plot(ax=ax, label="Faiman") From be72481c622c9ac912c2c0e31e880d38c6e2a0b8 Mon Sep 17 00:00:00 2001 From: Aman Srivastava Date: Tue, 10 Feb 2026 21:17:27 +0530 Subject: [PATCH 6/6] changing conf.py to allow files to run --- docs/sphinx/source/conf.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/sphinx/source/conf.py b/docs/sphinx/source/conf.py index bedfd4c0ce..ead0150b8e 100644 --- a/docs/sphinx/source/conf.py +++ b/docs/sphinx/source/conf.py @@ -388,9 +388,12 @@ def setup(app): sphinx_gallery_conf = { 'examples_dirs': ['../../examples'], # location of gallery scripts 'gallery_dirs': ['gallery'], # location of generated output - # execute all scripts except for ones in the "system-models" directory: + # execute only files starting with plot_ 'filename_pattern': 'plot_', + # ignore ONLY the OEDI example + 'ignore_pattern': 'plot_oedi_9068.py', + # directory where function/class granular galleries are stored 'backreferences_dir': 'reference/generated/gallery_backreferences',