-
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 14 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 |
---|---|---|
@@ -0,0 +1,135 @@ | ||
""" | ||
The ``bifacial`` module contains functions for modeling back surface | ||
plane-of-array irradiance under various conditions. | ||
""" | ||
|
||
import pandas as pd | ||
from pvlib.tools import enforce_numpy_arrays | ||
|
||
|
||
@enforce_numpy_arrays | ||
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: array of :class:datetime.datetime objects | ||
cwhanse marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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 all the detailed outputs and elements calculated | ||
for every timestamp of the simulation. Please refer to pvfactors | ||
documentation for more details | ||
|
||
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. | ||
""" | ||
|
||
# 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, | ||
'surface_azimuth': surface_azimuth[0], # not necessary | ||
cwhanse marked this conversation as resolved.
Show resolved
Hide resolved
|
||
'surface_tilt': surface_tilt[0], # not necessary | ||
'gcr': gcr, | ||
'solar_zenith': solar_zenith[0], # not necessary | ||
'solar_azimuth': solar_azimuth[0], # not necessary | ||
'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']].values | ||
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. perhaps only a question because I'm not familiar enough with 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. I just believed that having a 1D numpy array was simpler for these results, but I can adjust it to |
||
|
||
ipoa_back = df_outputs.loc[:, idx_slice[index_observed_pvrow, | ||
'back', 'qinc']].values | ||
|
||
return ipoa_front, ipoa_back, df_registries |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import numpy as np | ||
from datetime import datetime | ||
from pvlib.bifacial import pvfactors_timeseries | ||
from conftest import (requires_pvfactors, requires_future, requires_shapely, | ||
anomam marked this conversation as resolved.
Show resolved
Hide resolved
|
||
requires_scipy) | ||
|
||
|
||
@requires_scipy | ||
@requires_shapely | ||
@requires_future | ||
cwhanse marked this conversation as resolved.
Show resolved
Hide resolved
|
||
@requires_pvfactors | ||
def test_pvfactors_timeseries(): | ||
""" Test that pvfactors is functional, using the TLDR section inputs of the | ||
package github repo README.md file""" | ||
|
||
# Create some inputs | ||
timestamps = np.array([datetime(2017, 8, 31, 11), | ||
datetime(2017, 8, 31, 12)]) | ||
solar_zenith = np.array([20., 10.]) | ||
solar_azimuth = np.array([110., 140.]) | ||
surface_tilt = np.array([10., 0.]) | ||
surface_azimuth = np.array([90., 90.]) | ||
dni = np.array([1000., 300.]) | ||
dhi = np.array([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 = [1034.96216923, 795.4423259] | ||
expected_ipoa_back = [92.11871485, 70.39404124] | ||
tolerance = 1e-6 | ||
|
||
# Test serial calculations | ||
ipoa_front, ipoa_back, _ = 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) | ||
|
||
np.testing.assert_allclose(ipoa_front, expected_ipoa_front, | ||
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. This should use the pandas test functions if we adopt the always return a Series approach |
||
atol=0, rtol=tolerance) | ||
np.testing.assert_allclose(ipoa_back, expected_ipoa_back, | ||
atol=0, rtol=tolerance) | ||
|
||
# Run calculations in parallel | ||
ipoa_front, ipoa_back, _ = 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) | ||
|
||
np.testing.assert_allclose(ipoa_front, expected_ipoa_front, | ||
atol=0, rtol=tolerance) | ||
np.testing.assert_allclose(ipoa_back, expected_ipoa_back, | ||
atol=0, rtol=tolerance) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
enforce_numpy_arrays
section is outdated.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, done in 55dd3a6