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

PVEngine needs to use timeseries albedo values #98

Merged
merged 3 commits into from
Nov 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 23 additions & 14 deletions pvfactors/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,46 +195,55 @@ def run_full_mode(self, fn_build_report=None):
pvarray = self.pvarray

# Get the irradiance modeling matrices
# shape = n_surfaces, n_timesteps
# shape = n_surfaces + 1, n_timesteps
irradiance_mat, rho_mat, invrho_mat, _ = \
self.irradiance.get_full_ts_modeling_vectors(pvarray)

# --- Calculate view factors
# shape = n_surfaces, n_surfaces, n_timesteps
# shape = n_surfaces + 1, n_surfaces + 1, n_timesteps
ts_vf_matrix = self.vf_calculator.build_ts_vf_matrix(pvarray)
pvarray.ts_vf_matrix = ts_vf_matrix
# Reshape for broadcasting and inverting
# shape = n_timesteps, n_surfaces, n_surfaces
# shape = n_timesteps, n_surfaces + 1, n_surfaces + 1
ts_vf_matrix_reshaped = np.moveaxis(ts_vf_matrix, -1, 0)

# --- Solve mathematical problem
# Build matrix of inverse reflectivities
# shape = n_surfaces, n_surfaces
invrho_mat = np.diag(invrho_mat[:, 0])
# shape of system = n_timesteps, n_surfaces + 1, n_surfaces + 1
shape_system = ts_vf_matrix_reshaped.shape
# Build 3d matrix of inverse reflectivities: diagonal for each ts
# shape = n_timesteps, n_surfaces + 1, n_surfaces + 1
invrho_ts_diag = np.zeros(shape_system)
for idx_surf in range(shape_system[1]):
invrho_ts_diag[:, idx_surf, idx_surf] = invrho_mat[idx_surf, :]
# Subtract matrices: will rely on broadcasting
# shape = n_timesteps, n_surfaces, n_surfaces
a_mat = invrho_mat - ts_vf_matrix_reshaped
# shape = n_timesteps, n_surfaces + 1, n_surfaces + 1
a_mat = invrho_ts_diag - ts_vf_matrix_reshaped
# Calculate inverse, requires specific shape
# shape = n_timesteps, n_surfaces, n_surfaces
# shape = n_timesteps, n_surfaces + 1, n_surfaces + 1
inv_a_mat = np.linalg.inv(a_mat)
# Use einstein sum to get final timeseries radiosities
# shape = n_surfaces, n_timesteps
# shape = n_surfaces + 1, n_timesteps
q0 = np.einsum('ijk,ki->ji', inv_a_mat, irradiance_mat)
# Calculate incident irradiance: will rely on broadcasting
# shape = n_surfaces, n_timesteps
qinc = np.dot(invrho_mat, q0)
# shape = n_surfaces + 1, n_timesteps
qinc = np.einsum('ijk,ki->ji', invrho_ts_diag, q0)

# --- Derive other irradiance terms
# shape = n_surfaces, n_timesteps
isotropic_mat = ts_vf_matrix[:-1, -1, :] * irradiance_mat[-1, :]
reflection_mat = qinc[:-1, :] - irradiance_mat[:-1, :] - isotropic_mat

# --- Calculate AOI losses and absorbed irradiance
rho_mat = np.tile(rho_mat[:, 0], (rho_mat.shape[0], 1)).T
# Create tiled reflection matrix of
# shape = n_surfaces + 1, n_surfaces + 1, n_timestamps
rho_ts_tiled = np.moveaxis(np.tile(rho_mat.T, (shape_system[1], 1, 1)),
-1, 0)
# Get vf AOI matrix
# shape [n_surfaces + 1, n_surfaces + 1, n_timestamps]
vf_aoi_matrix = (self.vf_calculator
.build_ts_vf_aoi_matrix(pvarray, rho_mat))
.build_ts_vf_aoi_matrix(pvarray, rho_ts_tiled))
pvarray.ts_vf_aoi_matrix = vf_aoi_matrix
# Get absorbed irradiance matrix
# shape [n_surfaces, n_timestamps]
irradiance_abs_mat = (
self.irradiance.get_summed_components(pvarray, absorbed=True))
Expand Down
39 changes: 39 additions & 0 deletions pvfactors/tests/test_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -624,3 +624,42 @@ def test_engine_w_faoi_fn_in_irradiance_vfcalcs(params, pvmodule_canadian):
np.testing.assert_almost_equal(
pvarray.ts_pvrows[1].back.get_param_weighted('qabs'),
[114.2143503])


def test_engine_variable_albedo(params, df_inputs_clearsky_8760):
"""Run PV engine calcs with variable albedo"""

irradiance_model = HybridPerezOrdered()
pvarray = OrderedPVArray.init_from_dict(params)
eng = PVEngine(pvarray, irradiance_model=irradiance_model)

# Manage timeseries inputs
df_inputs = df_inputs_clearsky_8760

# Get MET data
timestamps = df_inputs.index
dni = df_inputs.dni.values
dhi = df_inputs.dhi.values
solar_zenith = df_inputs.solar_zenith.values
solar_azimuth = df_inputs.solar_azimuth.values
surface_tilt = df_inputs.surface_tilt.values
surface_azimuth = df_inputs.surface_azimuth.values
albedo = np.linspace(0, 1, num=8760)

# Fit engine
eng.fit(timestamps, dni, dhi, solar_zenith, solar_azimuth,
surface_tilt, surface_azimuth, albedo)

# Run timestep
pvarray = eng.run_full_mode(fn_build_report=lambda pvarray: pvarray)
# Check the bifacial gain values
pvrow = pvarray.ts_pvrows[1]
bfg = (np.nansum(pvrow.back.get_param_weighted('qinc'))
/ np.nansum(pvrow.front.get_param_weighted('qinc'))) * 100.
bfg_after_aoi = (np.nansum(pvrow.back.get_param_weighted('qabs'))
/ np.nansum(pvrow.front.get_param_weighted('qabs'))
) * 100.
expected_bfg = 16.441664
expected_bfg_after_aoi = 16.109509
np.testing.assert_allclose(bfg, expected_bfg)
np.testing.assert_allclose(bfg_after_aoi, expected_bfg_after_aoi)
4 changes: 2 additions & 2 deletions pvfactors/tests/test_viewfactors/test_calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ def test_vfcalculator_no_aoi_functions(params):
assert np.sum(vfcalculator.vf_matrix) > 0
# Compute reflectivity
rho_mat = np.tile([0.03] * (pvarray.n_ts_surfaces + 1),
(pvarray.n_ts_surfaces + 1, 1)).T
(1, pvarray.n_ts_surfaces + 1, 1)).T
assert rho_mat.shape == (pvarray.n_ts_surfaces + 1,
pvarray.n_ts_surfaces + 1)
pvarray.n_ts_surfaces + 1, 1)
vf_aoi_matrix = vfcalculator.build_ts_vf_aoi_matrix(pvarray, rho_mat)

# Check that correct size
Expand Down
7 changes: 3 additions & 4 deletions pvfactors/viewfactors/calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ def build_ts_vf_aoi_matrix(self, pvarray, rho_mat):
PV array whose timeseries view factor AOI matrix to calculate
rho_mat : np.ndarray
2D matrix of reflectivity values for all the surfaces in the
PV array + sky. Shape = [n_ts_surfaces + 1, n_ts_surfaces + 1]
PV array + sky.
Shape = [n_ts_surfaces + 1, n_ts_surfaces + 1, n_timestamps]

Returns
-------
Expand All @@ -161,9 +162,7 @@ def build_ts_vf_aoi_matrix(self, pvarray, rho_mat):
if self.vf_aoi_methods is None:
# The reflection losses will be considered all diffuse.
faoi_diffuse = 1. - rho_mat
# use broadcasting
vf_aoi_matrix = faoi_diffuse * np.moveaxis(vf_aoi_matrix, -1, 0)
vf_aoi_matrix = np.moveaxis(vf_aoi_matrix, 0, -1)
vf_aoi_matrix = faoi_diffuse * vf_aoi_matrix
else:
# Calculate vf_aoi between pvrow and ground surfaces
self.vf_aoi_methods.vf_aoi_pvrow_to_gnd(ts_pvrows, ts_ground,
Expand Down