Skip to content

Commit

Permalink
Fix irradiance models for fast mode shaded surfaces (#73)
Browse files Browse the repository at this point in the history
* Updated irr model names + now shaded pvrows can also get dni + circ

* dependent on module spacing and transparency

* Perez circumsolar shouldn't reach shaded surfaces in fast mode

* Added tests to make sure fix of transparency and spacing works
  • Loading branch information
anomam authored Sep 13, 2019
1 parent 1107234 commit 1a5ceab
Show file tree
Hide file tree
Showing 4 changed files with 258 additions and 61 deletions.
120 changes: 91 additions & 29 deletions pvfactors/irradiance/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ class IsotropicOrdered(BaseModel):
it to the PV array."""

params = ['rho', 'inv_rho', 'direct', 'isotropic', 'reflection']
cats = ['ground', 'front_pvrow', 'back_pvrow']
cats = ['ground_illum', 'ground_shaded', 'front_illum_pvrow',
'back_illum_pvrow', 'front_shaded_pvrow', 'back_shaded_pvrow']
irradiance_comp = ['direct']

def __init__(self, rho_front=0.01, rho_back=0.03, module_transparency=0.,
Expand Down Expand Up @@ -127,11 +128,32 @@ def fit(self, timestamps, DNI, DHI, solar_zenith, solar_azimuth,

# DNI seen by pvrow illuminated surfaces
front_is_illum = aoi_front_pvrow <= 90
self.direct['front_pvrow'] = np.where(
# direct
self.direct['front_illum_pvrow'] = np.where(
front_is_illum, DNI * cosd(aoi_front_pvrow), 0.)
self.direct['back_pvrow'] = np.where(
self.direct['front_shaded_pvrow'] = (
# Direct light through PV modules spacing
self.direct['front_illum_pvrow'] * self.module_spacing_ratio
# Direct light through PV modules, by transparency
+ self.direct['front_illum_pvrow']
* (1. - self.module_spacing_ratio)
* self.module_transparency)
self.direct['back_illum_pvrow'] = np.where(
~front_is_illum, DNI * cosd(aoi_back_pvrow), 0.)
self.total_perez['front_pvrow'] = perez_front_pvrow['poa_global']
self.direct['back_shaded_pvrow'] = (
# Direct light through PV modules spacing
self.direct['back_illum_pvrow'] * self.module_spacing_ratio
# Direct light through PV modules, by transparency
+ self.direct['back_illum_pvrow']
* (1. - self.module_spacing_ratio)
* self.module_transparency)
# perez
self.total_perez['front_illum_pvrow'] = perez_front_pvrow['poa_global']
self.total_perez['front_shaded_pvrow'] = (
self.total_perez['front_illum_pvrow']
- self.direct['front_illum_pvrow'])
self.total_perez['ground_shaded'] = (self.DHI
+ self.direct['ground_shaded'])

def transform(self, pvarray):
"""Apply calculated irradiance values to PV array timeseries
Expand Down Expand Up @@ -166,24 +188,24 @@ def transform(self, pvarray):
# Front
for ts_seg in ts_pvrow.front.list_segments:
ts_seg.illum.update_params(
{'direct': self.direct['front_pvrow'],
{'direct': self.direct['front_illum_pvrow'],
'rho': rho_front,
'inv_rho': inv_rho_front,
'total_perez': self.pvrow_illum})
ts_seg.shaded.update_params(
{'direct': np.zeros(n_steps),
{'direct': self.direct['front_shaded_pvrow'],
'rho': rho_front,
'inv_rho': inv_rho_front,
'total_perez': self.pvrow_shaded})
# Back
for ts_seg in ts_pvrow.back.list_segments:
ts_seg.illum.update_params(
{'direct': self.direct['back_pvrow'],
{'direct': self.direct['back_illum_pvrow'],
'rho': rho_back,
'inv_rho': inv_rho_back,
'total_perez': np.zeros(n_steps)})
ts_seg.shaded.update_params(
{'direct': np.zeros(n_steps),
{'direct': self.direct['back_shaded_pvrow'],
'rho': rho_back,
'inv_rho': inv_rho_back,
'total_perez': np.zeros(n_steps)})
Expand Down Expand Up @@ -228,7 +250,7 @@ def get_full_modeling_vectors(self, pvarray, idx):
@property
def gnd_shaded(self):
"""Total timeseries irradiance incident on ground shaded areas"""
return self.DHI + self.direct['ground_shaded']
return self.total_perez['ground_shaded']

@property
def gnd_illum(self):
Expand All @@ -239,13 +261,13 @@ def gnd_illum(self):
def pvrow_shaded(self):
"""Total timeseries irradiance incident on PV row's front illuminated
areas and calculated by Perez transposition"""
return self.pvrow_illum - self.direct['front_pvrow']
return self.total_perez['front_shaded_pvrow']

@property
def pvrow_illum(self):
"""Total timeseries irradiance incident on PV row's front shaded
areas and calculated by Perez transposition"""
return self.total_perez['front_pvrow']
return self.total_perez['front_illum_pvrow']

@property
def sky_luminance(self):
Expand All @@ -263,7 +285,8 @@ class HybridPerezOrdered(BaseModel):

params = ['rho', 'inv_rho', 'direct', 'isotropic', 'circumsolar',
'horizon', 'reflection']
cats = ['ground', 'front_pvrow', 'back_pvrow']
cats = ['ground_illum', 'ground_shaded', 'front_illum_pvrow',
'back_illum_pvrow', 'front_shaded_pvrow', 'back_shaded_pvrow']
irradiance_comp = ['direct', 'circumsolar', 'horizon']

def __init__(self, horizon_band_angle=DEFAULT_HORIZON_BAND_ANGLE,
Expand Down Expand Up @@ -399,20 +422,61 @@ def fit(self, timestamps, DNI, DHI, solar_zenith, solar_azimuth,

# PV row surfaces
front_is_illum = aoi_front_pvrow <= 90
self.direct['front_pvrow'] = np.where(
# direct
self.direct['front_illum_pvrow'] = np.where(
front_is_illum, DNI * cosd(aoi_front_pvrow), 0.)
self.direct['back_pvrow'] = np.where(
self.direct['front_shaded_pvrow'] = (
# Direct light through PV modules spacing
self.direct['front_illum_pvrow'] * self.module_spacing_ratio
# Direct light through PV modules, by transparency
+ self.direct['front_illum_pvrow']
* (1. - self.module_spacing_ratio)
* self.module_transparency)
self.direct['back_illum_pvrow'] = np.where(
~front_is_illum, DNI * cosd(aoi_back_pvrow), 0.)
self.circumsolar['front_pvrow'] = np.where(
self.direct['back_shaded_pvrow'] = (
# Direct light through PV modules spacing
self.direct['back_illum_pvrow'] * self.module_spacing_ratio
# Direct light through PV modules, by transparency
+ self.direct['back_illum_pvrow']
* (1. - self.module_spacing_ratio)
* self.module_transparency)
# circumsolar
self.circumsolar['front_illum_pvrow'] = np.where(
front_is_illum, poa_circumsolar_front, 0.)
self.circumsolar['back_pvrow'] = np.where(
self.circumsolar['front_shaded_pvrow'] = (
# Direct light through PV modules spacing
self.circumsolar['front_illum_pvrow'] * self.module_spacing_ratio
# Direct light through PV modules, by transparency
+ self.circumsolar['front_illum_pvrow']
* (1. - self.module_spacing_ratio)
* self.module_transparency)
self.circumsolar['back_illum_pvrow'] = np.where(
~front_is_illum, poa_circumsolar_back, 0.)
self.circumsolar['back_shaded_pvrow'] = (
# Direct light through PV modules spacing
self.circumsolar['back_illum_pvrow'] * self.module_spacing_ratio
# Direct light through PV modules, by transparency
+ self.circumsolar['back_illum_pvrow']
* (1. - self.module_spacing_ratio)
* self.module_transparency)
# horizon
self.horizon['front_pvrow'] = poa_horizon
self.horizon['back_pvrow'] = poa_horizon
# perez
self.total_perez['front_illum_pvrow'] = total_perez_front_pvrow
self.total_perez['front_shaded_pvrow'] = (
total_perez_front_pvrow - self.direct['front_pvrow'])
self.total_perez['ground_shaded'] = DHI
total_perez_front_pvrow
- self.direct['front_illum_pvrow']
- self.circumsolar['front_illum_pvrow']
+ self.direct['front_shaded_pvrow']
+ self.circumsolar['front_shaded_pvrow']
)
self.total_perez['ground_shaded'] = (
DHI
- self.circumsolar['ground_illum']
+ self.circumsolar['ground_shaded']
+ self.direct['ground_shaded'])
self.total_perez['ground_illum'] = GHI
self.total_perez['sky'] = luminance_isotropic

Expand Down Expand Up @@ -456,15 +520,15 @@ def transform(self, pvarray):
# Front
for ts_seg in ts_pvrow.front.list_segments:
ts_seg.illum.update_params({
'direct': self.direct['front_pvrow'],
'circumsolar': self.circumsolar['front_pvrow'],
'direct': self.direct['front_illum_pvrow'],
'circumsolar': self.circumsolar['front_illum_pvrow'],
'horizon': self.horizon['front_pvrow'],
'rho': rho_front,
'inv_rho': inv_rho_front,
'total_perez': self.pvrow_illum})
ts_seg.shaded.update_params({
'direct': np.zeros(n_steps),
'circumsolar': np.zeros(n_steps),
'direct': self.direct['front_shaded_pvrow'],
'circumsolar': self.circumsolar['front_shaded_pvrow'],
'horizon': self.horizon['front_pvrow'],
'rho': rho_front,
'inv_rho': inv_rho_front,
Expand All @@ -477,8 +541,8 @@ def transform(self, pvarray):
ts_pvrows, centroid_illum, idx_pvrow, tilted_to_left,
is_back_side=True)
ts_seg.illum.update_params({
'direct': self.direct['back_pvrow'],
'circumsolar': self.circumsolar['back_pvrow'],
'direct': self.direct['back_illum_pvrow'],
'circumsolar': self.circumsolar['back_illum_pvrow'],
'horizon': self.horizon['back_pvrow'] *
(1. - hor_shd_pct_illum / 100.),
'horizon_unshaded': self.horizon['back_pvrow'],
Expand All @@ -492,8 +556,8 @@ def transform(self, pvarray):
ts_pvrows, centroid_shaded, idx_pvrow, tilted_to_left,
is_back_side=True)
ts_seg.shaded.update_params({
'direct': np.zeros(n_steps),
'circumsolar': np.zeros(n_steps),
'direct': self.direct['back_shaded_pvrow'],
'circumsolar': self.circumsolar['back_shaded_pvrow'],
'horizon': self.horizon['back_pvrow'] *
(1. - hor_shd_pct_shaded / 100.),
'horizon_unshaded': self.horizon['back_pvrow'],
Expand Down Expand Up @@ -543,9 +607,7 @@ def get_full_modeling_vectors(self, pvarray, idx):
@property
def gnd_shaded(self):
"""Total timeseries irradiance incident on ground shaded areas"""
return (self.total_perez['ground_shaded']
+ self.direct['ground_shaded']
+ self.circumsolar['ground_shaded'])
return self.total_perez['ground_shaded']

@property
def gnd_illum(self):
Expand Down
Loading

0 comments on commit 1a5ceab

Please sign in to comment.