Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gallery example for bifacial modeling with pvfactors #1394

Merged
merged 14 commits into from
Feb 28, 2022
3 changes: 3 additions & 0 deletions docs/examples/bifacial/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Bifacial Modeling
-----------------

120 changes: 120 additions & 0 deletions docs/examples/bifacial/plot_bifi_model_mc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
"""
Bifacial Modeling - modelchain
spaneja marked this conversation as resolved.
Show resolved Hide resolved
==============================

Example of bifacial modeling using the modelchain
spaneja marked this conversation as resolved.
Show resolved Hide resolved
"""

# %%
# This example shows how to complete a bifacial modeling example using the
# :py:class:`pvlib.modelchain.ModelChain` with the
# :py:func:`pvlib.bifacial.pvfactors.pvfactors_timeseries` function
# to transpose GHI data to both front and rear Plane of Array (POA) irradiance.
#
# Unfortunately ``ModelChain`` does not yet support bifacial simulation
# directly so we have to do the bifacial irradiance simulation ourselves.
# Once the combined front + rear irradiance is known, we can pass that
# to ``ModelChain`` and proceed as usual.
#
# Future versions of pvlib may make it easier to do bifacial modeling
# with ``ModelChain``.

import pandas as pd
from pvlib import pvsystem
from pvlib import location
from pvlib import modelchain
from pvlib.temperature import TEMPERATURE_MODEL_PARAMETERS as PARAMS
from pvlib.bifacial.pvfactors import pvfactors_timeseries
import warnings

# supressing shapely warnings that occur on import of pvfactors
warnings.filterwarnings(action='ignore', module='pvfactors')

# create site location and times characteristics
lat, lon = 36.084, -79.817
tz = 'Etc/GMT+5'
times = pd.date_range('2021-06-21', '2021-6-22', freq='1T', tz=tz)

# create site system characteristics
axis_tilt = 0
axis_azimuth = 180
gcr = 0.35
max_angle = 60
pvrow_height = 3
pvrow_width = 4
albedo = 0.2
bifaciality = 0.75

# load temperature parameters and module/inverter specifications
temp_model_parameters = PARAMS['sapm']['open_rack_glass_glass']
cec_modules = pvsystem.retrieve_sam('CECMod')
cec_module = cec_modules['Trina_Solar_TSM_300DEG5C_07_II_']
cec_inverters = pvsystem.retrieve_sam('cecinverter')
cec_inverter = cec_inverters['ABB__MICRO_0_25_I_OUTD_US_208__208V_']

# create a location for site, and get solar position and clearsky data
site_location = location.Location(lat, lon, tz=tz, name='Greensboro, NC')
solar_position = site_location.get_solarposition(times)
cs = site_location.get_clearsky(times)

# load solar position and tracker orientation for use in pvsystem object
sat_mount = pvsystem.SingleAxisTrackerMount(axis_tilt=axis_tilt,
axis_azimuth=axis_azimuth,
max_angle=max_angle,
backtrack=True,
gcr=gcr)

# created for use in pvfactors timeseries
orientation = sat_mount.get_orientation(solar_position['apparent_zenith'],
solar_position['azimuth'])

# get rear and front side irradiance from pvfactors transposition engine
# explicity simulate on pvarray with 3 rows, with sensor placed in middle row
# users may select different values depending on needs
irrad = pvfactors_timeseries(solar_position['azimuth'],
solar_position['apparent_zenith'],
orientation['surface_azimuth'],
orientation['surface_tilt'],
axis_azimuth,
times,
cs['dni'],
cs['dhi'],
gcr,
pvrow_height,
pvrow_width,
albedo,
n_pvrows=3,
index_observed_pvrow=1
)

# turn into pandas DataFrame
irrad = pd.concat(irrad, axis=1)

# create bifacial effective irradiance using aoi-corrected timeseries values
irrad['effective_irradiance'] = (
irrad['total_abs_front'] + (irrad['total_abs_back'] * bifaciality)
)

# %%
# With effective irradiance, we can pass data to ModelChain for
# bifacial simulation.

# dc arrays
array = pvsystem.Array(mount=sat_mount,
module_parameters=cec_module,
temperature_model_parameters=temp_model_parameters)

# create system object
system = pvsystem.PVSystem(arrays=[array],
inverter_parameters=cec_inverter)

# ModelChain requires the parameter aoi_loss to have a value. pvfactors
# applies surface reflection models in the calculation of front and back
# irradiance, so assign aoi_model='no_loss' to avoid double counting
# reflections.
mc_bifi = modelchain.ModelChain(system, site_location, aoi_model='no_loss')
kandersolar marked this conversation as resolved.
Show resolved Hide resolved
mc_bifi.run_model_from_effective_irradiance(irrad)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a small inelegance that specifying aoi_model is necessary for a ModelChain that only uses run_model_from_effective_irradiance. I don't see a way around it, so I don't think there's anything to be done in this PR, just thinking out loud about the ModelChain design.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could default to None but then we'd need to check for a valid model in other run_model methods.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Converted to #1411


# plot results
mc_bifi.results.ac.plot(title='Bifacial Simulation on June Solstice',
ylabel='AC Power')
115 changes: 115 additions & 0 deletions docs/examples/bifacial/plot_bifi_model_pvwatts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
"""
Bifacial Modeling - procedural
==============================

Example of bifacial modeling using procedural method
spaneja marked this conversation as resolved.
Show resolved Hide resolved
"""

# %%
# This example shows how to complete a bifacial modeling example using the
# :py:func:`pvlib.pvsystem.pvwatts_dc` with the
# :py:func:`pvlib.bifacial.pvfactors.pvfactors_timeseries` function to
# transpose GHI data to both front and rear Plane of Array (POA) irradiance.

import pandas as pd
from pvlib import location
from pvlib import tracking
from pvlib.bifacial.pvfactors import pvfactors_timeseries
from pvlib import temperature
from pvlib import pvsystem
import matplotlib.pyplot as plt
import warnings

# supressing shapely warnings that occur on import of pvfactors
warnings.filterwarnings(action='ignore', module='pvfactors')

# using Greensboro, NC for this example
lat, lon = 36.084, -79.817
tz = 'Etc/GMT+5'
times = pd.date_range('2021-06-21', '2021-06-22', freq='1T', tz=tz)

# create location object and get clearsky data
site_location = location.Location(lat, lon, tz=tz, name='Greensboro, NC')
cs = site_location.get_clearsky(times)

# get solar position data
solar_position = site_location.get_solarposition(times)

# set ground coverage ratio and max_angle to
# pull orientation data for a single-axis tracker
gcr = 0.35
max_phi = 60
orientation = tracking.singleaxis(solar_position['apparent_zenith'],
solar_position['azimuth'],
max_angle=max_phi,
backtrack=True,
gcr=gcr
)

# set axis_azimuth, albedo, pvrow width and height, and use
# the pvfactors engine for both front and rear-side absorbed irradiance
axis_azimuth = 180
pvrow_height = 3
pvrow_width = 4
albedo = 0.2

# explicity simulate on pvarray with 3 rows, with sensor placed in middle row
# users may select different values depending on needs
irrad = pvfactors_timeseries(solar_position['azimuth'],
solar_position['apparent_zenith'],
orientation['surface_azimuth'],
orientation['surface_tilt'],
axis_azimuth,
cs.index,
cs['dni'],
cs['dhi'],
gcr,
pvrow_height,
pvrow_width,
albedo,
n_pvrows=3,
index_observed_pvrow=1
)

# turn into pandas DataFrame
irrad = pd.concat(irrad, axis=1)

# using bifaciality factor and pvfactors results, create effective irradiance
bifaciality = 0.75
effective_irrad_bifi = irrad['total_abs_front'] + (irrad['total_abs_back']
* bifaciality)

# get cell temperature using the Faiman model
temp_cell = temperature.faiman(effective_irrad_bifi, temp_air=25,
wind_speed=1)

# using the pvwatts_dc model and parameters detailed above,
# set pdc0 and return DC power for both bifacial and monofacial
pdc0 = 1
gamma_pdc = -0.0043
pdc_bifi = pvsystem.pvwatts_dc(effective_irrad_bifi,
temp_cell,
pdc0,
gamma_pdc=gamma_pdc
).fillna(0)
pdc_bifi.plot(title='Bifacial Simulation on June Solstice', ylabel='DC Power')

# %%
# For illustration, perform monofacial simulation using pvfactors front-side
# irradiance (AOI-corrected), and plot along with bifacial results.

effective_irrad_mono = irrad['total_abs_front']
pdc_mono = pvsystem.pvwatts_dc(effective_irrad_mono,
temp_cell,
pdc0,
gamma_pdc=gamma_pdc
).fillna(0)

# plot monofacial results
plt.figure()
plt.title('Bifacial vs Monofacial Simulation - June Solstice')
pdc_bifi.plot(label='Bifacial')
pdc_mono.plot(label='Monofacial')
plt.ylabel('DC Power')
plt.legend()
# sphinx_gallery_thumbnail_number = 2
6 changes: 5 additions & 1 deletion docs/sphinx/source/whatsnew/v0.9.1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ Documentation
~~~~~~~~~~~~~
* Fix documentation return error in :py:meth:`pvlib.forecast.ForecastModel.cloud_cover_to_transmittance_linear`
(:issue:`1367`, :pull:`1370`)

* Add gallery example illustrating bifacial simulation using :py:class:`pvlib.modelchain.ModelChain`
and the :py:func:`pvlib.bifacial.pvfactors_timeseries` function (:pull:`1394`)
* Add gallery example illustrating bifacial simulation using procedural functions
and the :py:func:`pvlib.bifacial.pvfactors_timeseries` function (:pull:`1394`)
spaneja marked this conversation as resolved.
Show resolved Hide resolved

Requirements
~~~~~~~~~~~~
Expand All @@ -69,3 +72,4 @@ Contributors
* Kevin Anderson (:ghuser:`kanderso-nrel`)
* Adam R. Jensen (:ghuser:`AdamRJensen`)
* Johann Loux (:ghuser:`JoLo90`)
* Saurabh Aneja (:ghuser:`spaneja`)
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
'doc': ['ipython', 'matplotlib', 'sphinx == 3.1.2',
'pydata-sphinx-theme == 0.8.0', 'sphinx-gallery',
'docutils == 0.15.2', 'pillow', 'netcdf4', 'siphon',
'sphinx-toggleprompt >= 0.0.5'],
'sphinx-toggleprompt >= 0.0.5', 'pvfactors'],
'test': TESTS_REQUIRE
}
EXTRAS_REQUIRE['all'] = sorted(set(sum(EXTRAS_REQUIRE.values(), [])))
Expand Down