-
Notifications
You must be signed in to change notification settings - Fork 1.1k
pvfactors limited implementation for bifacial calculations #635
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
Changes from all commits
80f910f
8acfd58
2e982d0
199ad02
397c850
2168e91
1c976e3
a340c20
fd3adf3
6435ce3
381000c
74b20af
89bad6c
81b8887
418ca72
e93c460
ef203f0
7b62e4a
330660a
7cd7cf9
cff21dd
160419a
bd5078b
cbc7434
9829b81
9970179
608863f
78756cd
55dd3a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,3 +19,4 @@ dependencies: | |
- pip: | ||
- coveralls | ||
- pytest-timeout | ||
- pvfactors==0.1.5 | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,3 +19,4 @@ dependencies: | |
- pip: | ||
- coveralls | ||
- pytest-timeout | ||
- pvfactors==0.1.5 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,3 +18,4 @@ dependencies: | |
- nose | ||
- pip: | ||
- coveralls | ||
- pvfactors==0.1.5 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,3 +18,4 @@ dependencies: | |
- nose | ||
- pip: | ||
- coveralls | ||
- pvfactors==0.1.5 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
""" | ||
The ``bifacial`` module contains functions for modeling back surface | ||
plane-of-array irradiance under various conditions. | ||
""" | ||
|
||
import pandas as pd | ||
|
||
|
||
def pvfactors_timeseries( | ||
solar_azimuth, solar_zenith, surface_azimuth, surface_tilt, | ||
timestamps, dni, dhi, gcr, pvrow_height, pvrow_width, albedo, | ||
n_pvrows=3, index_observed_pvrow=1, | ||
rho_front_pvrow=0.03, rho_back_pvrow=0.05, | ||
horizon_band_angle=15., | ||
Comment on lines
+13
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @anomam do you happen to remember why you chose this particular default value for There are now some small differences between this wrapper and pvfactors itself in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hey @kanderso-nrel ! It was a long time ago so I'm not entirely sure anymore, but what I remember is that these values might have needed a bit of tuning to match the measurements depending on the sites etc. I think for the horizon band it might be safe to check what the Perez paper says about what value to use. |
||
run_parallel_calculations=True, n_workers_for_parallel_calcs=None): | ||
""" | ||
Calculate front and back surface plane-of-array irradiance on | ||
a fixed tilt or single-axis tracker PV array configuration, and using | ||
the open-source "pvfactors" package. | ||
Please refer to pvfactors online documentation for more details: | ||
https://sunpower.github.io/pvfactors/ | ||
|
||
Inputs | ||
------ | ||
solar_azimuth: numeric | ||
Sun's azimuth angles using pvlib's azimuth convention (deg) | ||
solar_zenith: numeric | ||
Sun's zenith angles (deg) | ||
surface_azimuth: numeric | ||
Azimuth angle of the front surface of the PV modules, using pvlib's | ||
convention (deg) | ||
surface_tilt: numeric | ||
Tilt angle of the PV modules, going from 0 to 180 (deg) | ||
timestamps: datetime or DatetimeIndex | ||
List of simulation timestamps | ||
dni: numeric | ||
Direct normal irradiance (W/m2) | ||
dhi: numeric | ||
Diffuse horizontal irradiance (W/m2) | ||
gcr: float | ||
Ground coverage ratio of the pv array | ||
pvrow_height: float | ||
Height of the pv rows, measured at their center (m) | ||
pvrow_width: float | ||
Width of the pv rows in the considered 2D plane (m) | ||
albedo: float | ||
Ground albedo | ||
n_pvrows: int, default 3 | ||
Number of PV rows to consider in the PV array | ||
index_observed_pvrow: int, default 1 | ||
Index of the PV row whose incident irradiance will be returned. Indices | ||
of PV rows go from 0 to n_pvrows-1. | ||
rho_front_pvrow: float, default 0.03 | ||
Front surface reflectivity of PV rows | ||
rho_back_pvrow: float, default 0.05 | ||
Back surface reflectivity of PV rows | ||
horizon_band_angle: float, default 15 | ||
Elevation angle of the sky dome's diffuse horizon band (deg) | ||
run_parallel_calculations: bool, default True | ||
pvfactors is capable of using multiprocessing. Use this flag to decide | ||
to run calculations in parallel (recommended) or not. | ||
n_workers_for_parallel_calcs: int, default None | ||
Number of workers to use in the case of parallel calculations. The | ||
default value of 'None' will lead to using a value equal to the number | ||
of CPU's on the machine running the model. | ||
|
||
Returns | ||
------- | ||
front_poa_irradiance: numeric | ||
cwhanse marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Calculated incident irradiance on the front surface of the PV modules | ||
(W/m2) | ||
back_poa_irradiance: numeric | ||
Calculated incident irradiance on the back surface of the PV modules | ||
(W/m2) | ||
df_registries: pandas DataFrame | ||
DataFrame containing detailed outputs of the simulation; for | ||
instance the shapely geometries, the irradiance components incident on | ||
all surfaces of the PV array (for all timestamps), etc. | ||
In the pvfactors documentation, this is refered to as the "surface | ||
registry". | ||
|
||
References | ||
---------- | ||
.. [1] Anoma, Marc Abou, et al. "View Factor Model and Validation for | ||
Bifacial PV and Diffuse Shade on Single-Axis Trackers." 44th IEEE | ||
Photovoltaic Specialist Conference. 2017. | ||
""" | ||
|
||
# Convert pandas Series inputs to numpy arrays | ||
if isinstance(solar_azimuth, pd.Series): | ||
solar_azimuth = solar_azimuth.values | ||
if isinstance(solar_zenith, pd.Series): | ||
solar_zenith = solar_zenith.values | ||
if isinstance(surface_azimuth, pd.Series): | ||
surface_azimuth = surface_azimuth.values | ||
if isinstance(surface_tilt, pd.Series): | ||
surface_tilt = surface_tilt.values | ||
if isinstance(dni, pd.Series): | ||
dni = dni.values | ||
if isinstance(dhi, pd.Series): | ||
dhi = dhi.values | ||
|
||
# Import pvfactors functions for timeseries calculations. | ||
from pvfactors.timeseries import (calculate_radiosities_parallel_perez, | ||
calculate_radiosities_serially_perez, | ||
get_average_pvrow_outputs) | ||
idx_slice = pd.IndexSlice | ||
|
||
# Build up pv array configuration parameters | ||
pvarray_parameters = { | ||
'n_pvrows': n_pvrows, | ||
'pvrow_height': pvrow_height, | ||
'pvrow_width': pvrow_width, | ||
'gcr': gcr, | ||
'rho_ground': albedo, | ||
'rho_front_pvrow': rho_front_pvrow, | ||
'rho_back_pvrow': rho_back_pvrow, | ||
'horizon_band_angle': horizon_band_angle | ||
} | ||
|
||
# Run pvfactors calculations: either in parallel or serially | ||
if run_parallel_calculations: | ||
df_registries, df_custom_perez = calculate_radiosities_parallel_perez( | ||
pvarray_parameters, timestamps, solar_zenith, solar_azimuth, | ||
surface_tilt, surface_azimuth, dni, dhi, | ||
n_processes=n_workers_for_parallel_calcs) | ||
else: | ||
inputs = (pvarray_parameters, timestamps, solar_zenith, solar_azimuth, | ||
surface_tilt, surface_azimuth, dni, dhi) | ||
df_registries, df_custom_perez = calculate_radiosities_serially_perez( | ||
inputs) | ||
|
||
# Get the average surface outputs | ||
df_outputs = get_average_pvrow_outputs(df_registries, | ||
values=['qinc'], | ||
include_shading=True) | ||
|
||
# Select the calculated outputs from the pvrow to observe | ||
ipoa_front = df_outputs.loc[:, idx_slice[index_observed_pvrow, | ||
'front', 'qinc']] | ||
|
||
ipoa_back = df_outputs.loc[:, idx_slice[index_observed_pvrow, | ||
'back', 'qinc']] | ||
|
||
# Set timestamps as index of df_registries for consistency of outputs | ||
df_registries = df_registries.set_index('timestamps') | ||
|
||
return ipoa_front, ipoa_back, df_registries |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import pandas as pd | ||
from datetime import datetime | ||
from pvlib.bifacial import pvfactors_timeseries | ||
from conftest import requires_pvfactors | ||
|
||
|
||
@requires_pvfactors | ||
def test_pvfactors_timeseries(): | ||
""" Test that pvfactors is functional, using the TLDR section inputs of the | ||
package github repo README.md file: | ||
https://github.com/SunPower/pvfactors/blob/master/README.md#tldr---quick-start""" | ||
|
||
# Create some inputs | ||
timestamps = pd.DatetimeIndex([datetime(2017, 8, 31, 11), | ||
datetime(2017, 8, 31, 12)] | ||
).set_names('timestamps') | ||
solar_zenith = [20., 10.] | ||
solar_azimuth = [110., 140.] | ||
surface_tilt = [10., 0.] | ||
surface_azimuth = [90., 90.] | ||
dni = [1000., 300.] | ||
dhi = [50., 500.] | ||
gcr = 0.4 | ||
pvrow_height = 1.75 | ||
pvrow_width = 2.44 | ||
albedo = 0.2 | ||
n_pvrows = 3 | ||
index_observed_pvrow = 1 | ||
rho_front_pvrow = 0.03 | ||
rho_back_pvrow = 0.05 | ||
horizon_band_angle = 15. | ||
|
||
# Expected values | ||
expected_ipoa_front = pd.Series([1034.96216923, 795.4423259], | ||
index=timestamps, | ||
name=(1, 'front', 'qinc')) | ||
expected_ipoa_back = pd.Series([92.11871485, 70.39404124], | ||
index=timestamps, | ||
name=(1, 'back', 'qinc')) | ||
|
||
# Test serial calculations | ||
ipoa_front, ipoa_back, df_registries = pvfactors_timeseries( | ||
solar_azimuth, solar_zenith, surface_azimuth, surface_tilt, | ||
timestamps, dni, dhi, gcr, pvrow_height, pvrow_width, albedo, | ||
n_pvrows=n_pvrows, index_observed_pvrow=index_observed_pvrow, | ||
rho_front_pvrow=rho_front_pvrow, rho_back_pvrow=rho_back_pvrow, | ||
horizon_band_angle=horizon_band_angle, | ||
run_parallel_calculations=False, n_workers_for_parallel_calcs=None) | ||
|
||
pd.testing.assert_series_equal(ipoa_front, expected_ipoa_front) | ||
pd.testing.assert_series_equal(ipoa_back, expected_ipoa_back) | ||
pd.testing.assert_index_equal(timestamps, df_registries.index.unique()) | ||
|
||
# Run calculations in parallel | ||
ipoa_front, ipoa_back, df_registries = pvfactors_timeseries( | ||
solar_azimuth, solar_zenith, surface_azimuth, surface_tilt, | ||
timestamps, dni, dhi, gcr, pvrow_height, pvrow_width, albedo, | ||
n_pvrows=n_pvrows, index_observed_pvrow=index_observed_pvrow, | ||
rho_front_pvrow=rho_front_pvrow, rho_back_pvrow=rho_back_pvrow, | ||
horizon_band_angle=horizon_band_angle, | ||
run_parallel_calculations=True, n_workers_for_parallel_calcs=None) | ||
|
||
pd.testing.assert_series_equal(ipoa_front, expected_ipoa_front) | ||
pd.testing.assert_series_equal(ipoa_back, expected_ipoa_back) | ||
pd.testing.assert_index_equal(timestamps, df_registries.index.unique()) | ||
|
||
|
||
@requires_pvfactors | ||
def test_pvfactors_timeseries_pandas_inputs(): | ||
""" Test that pvfactors is functional, using the TLDR section inputs of the | ||
package github repo README.md file, but converted to pandas Series: | ||
https://github.com/SunPower/pvfactors/blob/master/README.md#tldr---quick-start""" | ||
|
||
# Create some inputs | ||
timestamps = pd.DatetimeIndex([datetime(2017, 8, 31, 11), | ||
datetime(2017, 8, 31, 12)] | ||
).set_names('timestamps') | ||
solar_zenith = pd.Series([20., 10.]) | ||
solar_azimuth = pd.Series([110., 140.]) | ||
surface_tilt = pd.Series([10., 0.]) | ||
surface_azimuth = pd.Series([90., 90.]) | ||
dni = pd.Series([1000., 300.]) | ||
dhi = pd.Series([50., 500.]) | ||
gcr = 0.4 | ||
pvrow_height = 1.75 | ||
pvrow_width = 2.44 | ||
albedo = 0.2 | ||
n_pvrows = 3 | ||
index_observed_pvrow = 1 | ||
rho_front_pvrow = 0.03 | ||
rho_back_pvrow = 0.05 | ||
horizon_band_angle = 15. | ||
|
||
# Expected values | ||
expected_ipoa_front = pd.Series([1034.96216923, 795.4423259], | ||
index=timestamps, | ||
name=(1, 'front', 'qinc')) | ||
expected_ipoa_back = pd.Series([92.11871485, 70.39404124], | ||
index=timestamps, | ||
name=(1, 'back', 'qinc')) | ||
|
||
# Test serial calculations | ||
ipoa_front, ipoa_back, df_registries = pvfactors_timeseries( | ||
solar_azimuth, solar_zenith, surface_azimuth, surface_tilt, | ||
timestamps, dni, dhi, gcr, pvrow_height, pvrow_width, albedo, | ||
n_pvrows=n_pvrows, index_observed_pvrow=index_observed_pvrow, | ||
rho_front_pvrow=rho_front_pvrow, rho_back_pvrow=rho_back_pvrow, | ||
horizon_band_angle=horizon_band_angle, | ||
run_parallel_calculations=False, n_workers_for_parallel_calcs=None) | ||
|
||
pd.testing.assert_series_equal(ipoa_front, expected_ipoa_front) | ||
pd.testing.assert_series_equal(ipoa_back, expected_ipoa_back) | ||
pd.testing.assert_index_equal(timestamps, df_registries.index.unique()) | ||
|
||
# Run calculations in parallel | ||
ipoa_front, ipoa_back, df_registries = pvfactors_timeseries( | ||
solar_azimuth, solar_zenith, surface_azimuth, surface_tilt, | ||
timestamps, dni, dhi, gcr, pvrow_height, pvrow_width, albedo, | ||
n_pvrows=n_pvrows, index_observed_pvrow=index_observed_pvrow, | ||
rho_front_pvrow=rho_front_pvrow, rho_back_pvrow=rho_back_pvrow, | ||
horizon_band_angle=horizon_band_angle, | ||
run_parallel_calculations=True, n_workers_for_parallel_calcs=None) | ||
|
||
pd.testing.assert_series_equal(ipoa_front, expected_ipoa_front) | ||
pd.testing.assert_series_equal(ipoa_back, expected_ipoa_back) | ||
pd.testing.assert_index_equal(timestamps, df_registries.index.unique()) |
Uh oh!
There was an error while loading. Please reload this page.