Source code for bifacialvf.vf

# -*- coding: utf-8 -*-
"""
ViewFactor module - VF calculation helper files for bifacial-viewfactor
    
@author Bill Marion
@translated to python by sayala 06/09/17

"""

# ensure python3 compatible division and printing
from __future__ import division, print_function, absolute_import
import math
import numpy as np
from .sun import solarPos, sunIncident, perezComp, aOIcorrection
import logging

# TODO: set level or add formatters if more advanced logging required
LOGGER = logging.getLogger(__name__)  # only used to raise errors
DTOR = math.pi / 180.0  # Factor for converting from degrees to radians


[docs]def getBackSurfaceIrradiances(rowType, maxShadow, PVbackSurface, beta, sazm, dni, dhi, C, D, albedo, zen, azm, cellRows, pvBackSH, rearGroundGHI, frontGroundGHI, frontReflected, offset=0): """ This method calculates the AOI corrected irradiance on the back of the PV module/panel. 11/19/2015 Added rowType and other changes to distinguish between types of rows. 4/19/2016 Added input of offset of reference cell from PV module back (in PV panel slope lengths) for modeling Sara's reference cell measurements, should be set to zero for PV module cell irradiances. Added while loop so projected Xs aren't too negative causing array index problems (<0) 12/13/2016:: while (projectedX1 < -100.0 || projectedX2 < -100.0): # Offset so array indexes are >= -100.0 12/13/2016 projectedX1 += 100.0; projectedX2 += 100.0; Parameters ---------- rowType : str Type of row: "first", "interior", "last", or "single" maxShadow Maximum shadow length projected to the front(-) or rear (+) from the front of the module PVbackSurface PV module back surface material type, either "glass" or "ARglass" beta Tilt from horizontal of the PV modules/panels (deg) (for front surface) sazm Surface azimuth of PV panels (deg) (for front surface) dni Direct normal irradiance (W/m2) dhi Diffuse horizontal irradiance (W/m2) C Ground clearance of PV panel (in PV panel slope lengths) D Horizontal distance between rows of PV panels (in PV panel slope lengths) albedo Ground albedo zen Sun zenith (in radians) azm Sun azimuth (in radians) pvBackSH Decimal fraction of the back surface of the PV panel that is shaded, 0.0 to 1.0 rearGroundGHI : array of size [100] Global horizontal irradiance for each of 100 ground segments (W/m2) frontGroundGHI : array of size [100] Global horizontal irradiance for each of 100 ground segments (W/m2) frontReflected : array of size [cellRows] Irradiance reflected from the front of the PV module/panel (W/m2) in the row behind the one of interest offset Offset of reference cell from PV module back (in PV panel slope lengths), set to zero for PV module cell irradiances Returns ------- backGTI : array of size [cellRows] AOI corrected irradiance on back side of PV module/panel, one for each cell row (W/m2) aveGroundGHI : numeric Average GHI on ground under PV array Notes ----- 1-degree hemispherical segment AOI correction factor for glass (index=0) and ARglass (index=1) """ backGTI = [] SegAOIcor = [ [0.057563, 0.128570, 0.199651, 0.265024, 0.324661, 0.378968, 0.428391, 0.473670, 0.514788, 0.552454, 0.586857, 0.618484, 0.647076, 0.673762, 0.698029, 0.720118, 0.740726, 0.759671, 0.776946, 0.792833, 0.807374, 0.821010, 0.833534, 0.845241, 0.855524, 0.865562, 0.874567, 0.882831, 0.890769, 0.897939, 0.904373, 0.910646, 0.916297, 0.921589, 0.926512, 0.930906, 0.935179, 0.939074, 0.942627, 0.946009, 0.949096, 0.952030, 0.954555, 0.957157, 0.959669, 0.961500, 0.963481, 0.965353, 0.967387, 0.968580, 0.970311, 0.971567, 0.972948, 0.974114, 0.975264, 0.976287, 0.977213, 0.978142, 0.979057, 0.979662, 0.980460, 0.981100, 0.981771, 0.982459, 0.982837, 0.983199, 0.983956, 0.984156, 0.984682, 0.985026, 0.985364, 0.985645, 0.985954, 0.986241, 0.986484, 0.986686, 0.986895, 0.987043, 0.987287, 0.987388, 0.987541, 0.987669, 0.987755, 0.987877, 0.987903, 0.987996, 0.988022, 0.988091, 0.988104, 0.988114, 0.988114, 0.988104, 0.988091, 0.988022, 0.987996, 0.987903, 0.987877, 0.987755, 0.987669, 0.987541, 0.987388, 0.987287, 0.987043, 0.986895, 0.986686, 0.986484, 0.986240, 0.985954, 0.985645, 0.985364, 0.985020, 0.984676, 0.984156, 0.983956, 0.983199, 0.982837, 0.982459, 0.981771, 0.981100, 0.980460, 0.979662, 0.979057, 0.978142, 0.977213, 0.976287, 0.975264, 0.974114, 0.972947, 0.971567, 0.970311, 0.968580, 0.967387, 0.965353, 0.963481, 0.961501, 0.959671, 0.957157, 0.954555, 0.952030, 0.949096, 0.946009, 0.942627, 0.939074, 0.935179, 0.930906, 0.926512, 0.921589, 0.916297, 0.910646, 0.904373, 0.897939, 0.890769, 0.882831, 0.874567, 0.865562, 0.855524, 0.845241, 0.833534, 0.821010, 0.807374, 0.792833, 0.776946, 0.759671, 0.740726, 0.720118, 0.698029, 0.673762, 0.647076, 0.618484, 0.586857, 0.552454, 0.514788, 0.473670, 0.428391, 0.378968, 0.324661, 0.265024, 0.199651, 0.128570, 0.057563], [0.062742, 0.139913, 0.216842, 0.287226, 0.351055, 0.408796, 0.460966, 0.508397, 0.551116, 0.589915, 0.625035, 0.657029, 0.685667, 0.712150, 0.735991, 0.757467, 0.777313, 0.795374, 0.811669, 0.826496, 0.839932, 0.852416, 0.863766, 0.874277, 0.883399, 0.892242, 0.900084, 0.907216, 0.914023, 0.920103, 0.925504, 0.930744, 0.935424, 0.939752, 0.943788, 0.947313, 0.950768, 0.953860, 0.956675, 0.959339, 0.961755, 0.964039, 0.965984, 0.967994, 0.969968, 0.971283, 0.972800, 0.974223, 0.975784, 0.976647, 0.977953, 0.978887, 0.979922, 0.980773, 0.981637, 0.982386, 0.983068, 0.983759, 0.984436, 0.984855, 0.985453, 0.985916, 0.986417, 0.986934, 0.987182, 0.987435, 0.988022, 0.988146, 0.988537, 0.988792, 0.989043, 0.989235, 0.989470, 0.989681, 0.989857, 0.990006, 0.990159, 0.990263, 0.990455, 0.990515, 0.990636, 0.990731, 0.990787, 0.990884, 0.990900, 0.990971, 0.990986, 0.991042, 0.991048, 0.991057, 0.991057, 0.991048, 0.991042, 0.990986, 0.990971, 0.990900, 0.990884, 0.990787, 0.990731, 0.990636, 0.990515, 0.990455, 0.990263, 0.990159, 0.990006, 0.989857, 0.989681, 0.989470, 0.989235, 0.989043, 0.988787, 0.988532, 0.988146, 0.988022, 0.987435, 0.987182, 0.986934, 0.986417, 0.985916, 0.985453, 0.984855, 0.984436, 0.983759, 0.983068, 0.982386, 0.981637, 0.980773, 0.979920, 0.978887, 0.977953, 0.976647, 0.975784, 0.974223, 0.972800, 0.971284, 0.969970, 0.967994, 0.965984, 0.964039, 0.961755, 0.959339, 0.956675, 0.953860, 0.950768, 0.947313, 0.943788, 0.939752, 0.935424, 0.930744, 0.925504, 0.920103, 0.914023, 0.907216, 0.900084, 0.892242, 0.883399, 0.874277, 0.863766, 0.852416, 0.839932, 0.826496, 0.811669, 0.795374, 0.777313, 0.757467, 0.735991, 0.712150, 0.685667, 0.657029, 0.625035, 0.589915, 0.551116, 0.508397, 0.460966, 0.408796, 0.351055, 0.287226, 0.216842, 0.139913, 0.062742]] # Tilt from horizontal of the PV modules/panels, in radians beta = beta * DTOR sazm = sazm * DTOR # Surface azimuth of PV module/panels, in radians # 1. Calculate and assign various paramters to be used for modeling # irradiances # For calling PerezComp to break diffuse into components for zero tilt # (horizontal) iso_dif = 0.0; circ_dif = 0.0; horiz_dif = 0.0; grd_dif = 0.0; beam = 0.0 # Call to get iso_dif for horizontal surface ghi, iso_dif, circ_dif, horiz_dif, grd_dif, beam = perezComp( dni, dhi, albedo, zen, 0.0, zen) # Isotropic irradiance from sky on horizontal surface, used later for # determining isotropic sky component iso_sky_dif = iso_dif # For calling PerezComp to break diffuse into components for 90 degree tilt # (vertical) inc, tiltr, sazmr = sunIncident(0, 90.0, 180.0, 45.0, zen, azm) # Call to get horiz_dif for vertical surface vti, iso_dif, circ_dif, horiz_dif, grd_dif, beam = perezComp( dni, dhi, albedo, inc, tiltr, zen) # Horizon diffuse irradiance on a vertical surface, used later for # determining horizon brightening irradiance component F2DHI = horiz_dif index = -99 n2 = -99.9 if (PVbackSurface == "glass"): # Index to use with 1-degree hemispherical segment AOI correction # factor array index = 0 n2 = 1.526 # Index of refraction for glass elif (PVbackSurface == "ARglass"): # Index to use with 1-degree hemispherical segment AOI correction # factor array index = 1 n2 = 1.300 # Index of refraction for ARglass else: raise Exception( "Incorrect text input for PVbackSurface." " Must be glass or ARglass.") # Reflectance at normal incidence, Duffie and Beckman p217 Ro = math.pow((n2 - 1.0) / (n2 + 1.0), 2.0) # Average GHI on ground under PV array for cases when x projection exceed # 2*rtr aveGroundGHI = 0.0 for i in range(0,100): aveGroundGHI += rearGroundGHI[i] / 100.0 # Calculate x,y coordinates of bottom and top edges of PV row in back of desired PV row so that portions of sky and ground viewed by the # PV cell may be determined. Origin of x-y axis is the ground pobelow the lower front edge of the desired PV row. The row in back of # the desired row is in the positive x direction. h = math.sin(beta); # Vertical height of sloped PV panel (in PV panel slope lengths) x1 = math.cos(beta); # Horizontal distance from front of panel to rear of panel (in PV panel slope lengths) rtr = D + x1; # Row-to-row distance (in PV panel slope lengths) PbotX = rtr; # x value for poon bottom egde of PV module/panel of row in back of (in PV panel slope lengths) PbotY = C; # y value for poon bottom egde of PV module/panel of row in back of (in PV panel slope lengths) PtopX = rtr + x1; # x value for poon top egde of PV module/panel of row in back of (in PV panel slope lengths) PtopY = h + C; # y value for poon top egde of PV module/panel of row in back of (in PV panel slope lengths) # 2. Calculate diffuse and direct component irradiances for each cell row for i in range (0, cellRows): # Calculate diffuse irradiances and reflected amounts for each cell row over it's field of view of 180 degrees, # beginning with the angle providing the upper most view of the sky (j=0) #PcellX = x1 * (i + 0.5) / ((double)cellRows); # x value for location of PV cell #PcellY = C + h * (i + 0.5) / ((double)cellRows); # y value for location of PV cell PcellX = x1 * (i + 0.5) / (cellRows) + offset * math.sin(beta); # x value for location of PV cell with OFFSET FOR SARA REFERENCE CELLS 4/26/2016 PcellY = C + h * (i + 0.5) / (cellRows) - offset * math.cos(beta); # y value for location of PV cell with OFFSET FOR SARA REFERENCE CELLS 4/26/2016 elvUP = math.atan((PtopY - PcellY) / (PtopX - PcellX)); # Elevation angle up from PV cell to top of PV module/panel, radians elvDOWN = math.atan((PcellY - PbotY) / (PbotX - PcellX)); # Elevation angle down from PV cell to bottom of PV module/panel, radians if (rowType == "last" or rowType == "single"): # 4/19/16 No array to the rear for these cases elvUP = 0.0; elvDOWN = 0.0; #Console.WriteLine("ElvUp = 0", elvUP / DTOR); #if (i == 0) # Console.WriteLine("ElvDown = 0", elvDOWN / DTOR); #123 #iStopIso = Convert.ToInt32((beta - elvUP) / DTOR); # Last whole degree in arc range that sees sky, first is 0 #Console.WriteLine("iStopIso = 0", iStopIso); #iHorBright = Convert.ToInt32(max(0.0, 6.0 - elvUP / DTOR)); # Number of whole degrees for which horizon brightening occurs #iStartGrd = Convert.ToInt32((beta + elvDOWN) / DTOR); # First whole degree in arc range that sees ground, last is 180 iStopIso = int(round((beta - elvUP) / DTOR)); # Last whole degree in arc range that sees sky, first is 0 #Console.WriteLine("iStopIso = 0", iStopIso); iHorBright = int(round(max(0.0, 6.0 - elvUP / DTOR))); # Number of whole degrees for which horizon brightening occurs iStartGrd = int(round((beta + elvDOWN) / DTOR)); # First whole degree in arc range that sees ground, last is 180 backGTI.append(0.0) # Initialtize front GTI for j in range (0, iStopIso): # Add sky diffuse component and horizon brightening if present backGTI[i] += 0.5 * (math.cos(j * DTOR) - math.cos((j + 1) * DTOR)) * SegAOIcor[index][j] * iso_sky_dif; # Sky radiation # backGTI[i] += 0.5 * (math.cos(j * DTOR) - math.cos((j + 1) * DTOR)) * iso_sky_dif; # Sky radiation if ((iStopIso - j) <= iHorBright): # Add horizon brightening term if seen backGTI[i] += 0.5 * (math.cos(j * DTOR) - math.cos((j + 1) * DTOR)) * SegAOIcor[index][j] * F2DHI / 0.052264; # 0.052246 = 0.5 * [cos(84) - cos(90)] #backGTI[i] += 0.5 * (math.cos(j * DTOR) - math.cos((j + 1) * DTOR)) * F2DHI / 0.052264; # 0.052246 = 0.5 * [cos(84) - cos(90)] if (rowType == "interior" or rowType == "first"): # 4/19/16 Only add reflections from PV modules for these cases for j in range (iStopIso, iStartGrd): #j = iStopIso; j < iStartGrd; j++) # Add relections from PV module front surfaces L = (PbotX - PcellX) / math.cos(elvDOWN); # Diagonal distance from cell to bottom of module in row behind startAlpha = -(j - iStopIso) * DTOR + elvUP + elvDOWN; stopAlpha = -(j + 1 - iStopIso) * DTOR + elvUP + elvDOWN; m = L * math.sin(startAlpha); theta = math.pi - elvDOWN - (math.pi / 2.0 - startAlpha) - beta; projectedX2 = m / math.cos(theta); # Projected distance on sloped PV module m = L * math.sin(stopAlpha); theta = math.pi - elvDOWN - (math.pi / 2.0 - stopAlpha) - beta; projectedX1 = m / math.cos(theta); # Projected distance on sloped PV module projectedX1 = max(0.0, projectedX1); #Console.WriteLine("j= 0 projected X1 = 1,6:0.000 projected X2 = 2,6:0.000", j, projectedX1, projectedX2); PVreflectedIrr = 0.0; # Irradiance from PV module front cover reflections deltaCell = 1.0 / cellRows; # Length of cell in sloped direction in module/panel units (dimensionless) for k in range (0, cellRows): # Determine which cells in behind row are seen, and their reflected irradiance cellBot = k * deltaCell; # Position of bottom of cell along PV module/panel cellTop = (k + 1) * deltaCell; # Position of top of cell along PV module/panel cellLengthSeen = 0.0; # Length of cell seen for this row, start with zero if (cellBot >= projectedX1 and cellTop <= projectedX2): cellLengthSeen = cellTop - cellBot; # Sees the whole cell elif (cellBot <= projectedX1 and cellTop >= projectedX2): cellLengthSeen = projectedX2 - projectedX1; # Sees portion in the middle of cell elif (cellBot >= projectedX1 and projectedX2 > cellBot and cellTop >= projectedX2): cellLengthSeen = projectedX2 - cellBot; # Sees bottom of cell elif (cellBot <= projectedX1 and projectedX1 < cellTop and cellTop <= projectedX2): cellLengthSeen = cellTop - projectedX1; # Sees top of cell #Console.WriteLine("cell= 0 cellBot = 1,5:0.00 cellTop = 2,5:0.00 Cell length seen = 3,5:0.00", k, cellBot, cellTop, cellLengthSeen); PVreflectedIrr += cellLengthSeen * frontReflected[k]; # Add reflected radiation for this PV cell, if seen, weight by cell length seen PVreflectedIrr /= projectedX2 - projectedX1; # Reflected irradiance from PV modules (W/m2) backGTI[i] += 0.5 * (math.cos(j * DTOR) - math.cos((j + 1) * DTOR)) * SegAOIcor[index][j] * PVreflectedIrr; # Radiation reflected from PV module surfaces onto back surface of module # End of adding reflections from PV module surfaces #Console.WriteLine(""); #if (i == 0) #Console.WriteLine("iStartGrd = 0", iStartGrd); for j in range (iStartGrd, 180): # Add ground reflected component startElvDown = (j - iStartGrd) * DTOR + elvDOWN; # Start and ending down elevations for this j loop stopElvDown = (j + 1 - iStartGrd) * DTOR + elvDOWN; projectedX2 = PcellX + np.float64(PcellY) / math.tan(startElvDown); # Projection of ElvDown to ground in +x direction (X1 and X2 opposite nomenclature for front irradiance method) projectedX1 = PcellX + PcellY / math.tan(stopElvDown); actualGroundGHI = 0.0; # Actuall ground GHI from summing array values #if (i == 0) # Console.WriteLine("j= 0 projected X1 = 1,6:0.0", j, 100 * projectedX1 / rtr); if (abs(projectedX1 - projectedX2) > 0.99 * rtr): if (rowType == "last" or rowType == "single"): # 4/19/16 No array to rear for these cases actualGroundGHI = ghi; # Use total value if projection approximates the rtr else: actualGroundGHI = aveGroundGHI; # Use average value if projection approximates the rtr else: projectedX1 = 100.0 * projectedX1 / rtr; # Normalize projections and multiply by 100 projectedX2 = 100.0 * projectedX2 / rtr; #Console.WriteLine("projectedX1 = 0 projectedX2 = 1", projectedX1, projectedX2); if ((rowType == "last" or rowType == "single") and (abs(projectedX1) > 99.0 or abs(projectedX2) > 99.0)): #4/19/2016 actualGroundGHI = ghi; # Use total value if projection > rtr for "last" or "single" else: while (projectedX1 >= 100.0 or projectedX2 >= 100.0): # Offset so array indexes are less than 100 projectedX1 -= 100.0; projectedX2 -= 100.0; while (projectedX1 < -100.0 or projectedX2 < -100.0): # Offset so array indexes are >= -100.0 12/13/2016 projectedX1 += 100.0; projectedX2 += 100.0; #Console.WriteLine("projectedX1 = 0 projectedX2 = 1", projectedX1, projectedX2); index1 = (int)(projectedX1 + 100.0) - 100; # Determine indexes for use with rearGroundGHI array and frontGroundGHI array(truncates values) index2 = (int)(projectedX2 + 100.0) - 100; # (int)(1.9) = 1 and (int)(-1.9) = -1; (int)(1.9+100) - 100 = 1 and (int)(-1.9+100) - 100 = -2 #Console.WriteLine("index1=0 index2=1", index1, index2); if (index1 == index2): if (index1 < 0): actualGroundGHI = frontGroundGHI[index1 + 100]; #actualGroundGHI = 0.0; else: actualGroundGHI = rearGroundGHI[index1]; # x projections in same groundGHI element THIS SEEMS TO ADD HICCUP 4/26/2016 *************************** #actualGroundGHI = 0.0; else: for k in range (index1, index2+1): #for (k = index1; k <= index2; k++) # Sum the irradiances on the ground if projections are in different groundGHI elements if (k == index1): if (k < 0): actualGroundGHI += frontGroundGHI[k + 100] * (k + 1.0 - projectedX1); else: actualGroundGHI += rearGroundGHI[k] * (k + 1.0 - projectedX1); elif (k == index2): if (k < 0): actualGroundGHI += frontGroundGHI[k + 100] * (projectedX2 - k); else: actualGroundGHI += rearGroundGHI[k] * (projectedX2 - k); else: if (k < 0): actualGroundGHI += frontGroundGHI[k + 100]; else: actualGroundGHI += rearGroundGHI[k]; actualGroundGHI /= projectedX2 - projectedX1; # Irradiance on ground in the 1 degree field of view #if (i == 0) # Console.WriteLine("j=0 index1=1 index2=2 projectX1=3,5:0.0 projectX2=4,5:0.0 actualGrdGHI=5,6:0.0", j, index1, index2, projectedX1, projectedX2, actualGroundGHI); # End of if looping to determine actualGroundGHI backGTI[i] += 0.5 * (math.cos(j * DTOR) - math.cos((j + 1) * DTOR)) * SegAOIcor[index][j] * actualGroundGHI * albedo; # Add ground reflected component #Console.WriteLine("actualGroundGHI = 0,6:0.0 inputGHI = 1,6:0.0 aveArrayGroundGHI = 2,6:0.0", actualGroundGHI, dhi + dni * math.cos(zen), aveGroundGHI); # End of j loop for adding ground reflected componenet # Calculate and add direct and circumsolar irradiance components inc, tiltr, sazmr = sunIncident(0, 180-beta / DTOR, sazm / DTOR - 180, 45.0, zen, azm) # For calling PerezComp to break diffuse into components for downward facing tilt gtiAllpc, iso_dif, circ_dif, horiz_dif, grd_dif, beam = perezComp(dni, dhi, albedo, inc, tiltr, zen) # Call to get components for the tilt cellShade = pvBackSH * cellRows - i; if (cellShade > 1.0): # Fully shaded if > 1, no shade if < 0, otherwise fractionally shaded cellShade = 1.0; elif (cellShade < 0.0): cellShade = 0.0; if (cellShade < 1.0 and inc < math.pi / 2.0): # Cell not shaded entirely and inc < 90 deg cor = aOIcorrection(n2, inc); # Get AOI correction for beam and circumsolar backGTI[i] += (1.0 - cellShade) * (beam + circ_dif) * cor; # Add beam and circumsolar radiation # End of for i = 0; i < cellRows loop return backGTI, aveGroundGHI;
# End of GetBackSurfaceIrradiances
[docs]def getFrontSurfaceIrradiances(rowType, maxShadow, PVfrontSurface, beta, sazm, dni, dhi, C, D, albedo, zen, azm, cellRows, pvFrontSH, frontGroundGHI): """ This method calculates the AOI corrected irradiance on the front of the PV module/panel and the irradiance reflected from the the front of the PV module/panel. 11/12/2015 Added row type and MaxShadow and changed code to accommodate 4/19/2015 Parameters ---------- rowType : str Type of row: "first", "interior", "last", or "single" maxShadow Maximum shadow length projected to the front (-) or rear (+) from the front of the module row (in PV panel slope lengths), only used for `rowTypes` other than "interior" PVfrontSurface PV module front surface material type, either "glass" or "ARglass" beta Tilt from horizontal of the PV modules/panels (deg) sazm Surface azimuth of PV panels (deg) dni Direct normal irradiance (W/m2) dhi Diffuse horizontal irradiance (W/m2) C Ground clearance of PV panel (in PV panel slope lengths) D Horizontal distance between rows of PV panels (in PV panel slope lengths) albedo Ground albedo zen Sun zenith (in radians) azm Sun azimuth (in radians) pvFrontSH Decimal fraction of the front surface of the PV panel that is shaded, 0.0 to 1.0 froutGroundGHI : array of size [100] Global horizontal irradiance for each of 100 ground segments in front of the module row Returns ------- frontGTI : array of size [cellRows] AOI corrected irradiance on front side of PV module/panel, one for each cell row (W/m2) frontReflected : array of size [cellRows] Irradiance reflected from the front of the PV module/panel (W/m2) aveGroundGHI : numeric Average GHI on the ground (includes effects of shading by array) from the array frontGroundGHI[100] Notes ----- 1-degree hemispherical segment AOI correction factor for glass (index=0) and ARglass (index=1). Creates a list containing 5 lists, each of 8 items, all set to 0 """ frontGTI = [] frontReflected = [] #w, h = 2, 180; #SegAOIcor = [[0 for x in range(w)] for y in range(h)] SegAOIcor = ([[0.057563, 0.128570, 0.199651, 0.265024, 0.324661, 0.378968, 0.428391, 0.473670, 0.514788, 0.552454, 0.586857, 0.618484, 0.647076, 0.673762, 0.698029, 0.720118, 0.740726, 0.759671, 0.776946, 0.792833, 0.807374, 0.821010, 0.833534, 0.845241, 0.855524, 0.865562, 0.874567, 0.882831, 0.890769, 0.897939, 0.904373, 0.910646, 0.916297, 0.921589, 0.926512, 0.930906, 0.935179, 0.939074, 0.942627, 0.946009, 0.949096, 0.952030, 0.954555, 0.957157, 0.959669, 0.961500, 0.963481, 0.965353, 0.967387, 0.968580, 0.970311, 0.971567, 0.972948, 0.974114, 0.975264, 0.976287, 0.977213, 0.978142, 0.979057, 0.979662, 0.980460, 0.981100, 0.981771, 0.982459, 0.982837, 0.983199, 0.983956, 0.984156, 0.984682, 0.985026, 0.985364, 0.985645, 0.985954, 0.986241, 0.986484, 0.986686, 0.986895, 0.987043, 0.987287, 0.987388, 0.987541, 0.987669, 0.987755, 0.987877, 0.987903, 0.987996, 0.988022, 0.988091, 0.988104, 0.988114, 0.988114, 0.988104, 0.988091, 0.988022, 0.987996, 0.987903, 0.987877, 0.987755, 0.987669, 0.987541, 0.987388, 0.987287, 0.987043, 0.986895, 0.986686, 0.986484, 0.986240, 0.985954, 0.985645, 0.985364, 0.985020, 0.984676, 0.984156, 0.983956, 0.983199, 0.982837, 0.982459, 0.981771, 0.981100, 0.980460, 0.979662, 0.979057, 0.978142, 0.977213, 0.976287, 0.975264, 0.974114, 0.972947, 0.971567, 0.970311, 0.968580, 0.967387, 0.965353, 0.963481, 0.961501, 0.959671, 0.957157, 0.954555, 0.952030, 0.949096, 0.946009, 0.942627, 0.939074, 0.935179, 0.930906, 0.926512, 0.921589, 0.916297, 0.910646, 0.904373, 0.897939, 0.890769, 0.882831, 0.874567, 0.865562, 0.855524, 0.845241, 0.833534, 0.821010, 0.807374, 0.792833, 0.776946, 0.759671, 0.740726, 0.720118, 0.698029, 0.673762, 0.647076, 0.618484, 0.586857, 0.552454, 0.514788, 0.473670, 0.428391, 0.378968, 0.324661, 0.265024, 0.199651, 0.128570, 0.057563], [0.062742, 0.139913, 0.216842, 0.287226, 0.351055, 0.408796, 0.460966, 0.508397, 0.551116, 0.589915, 0.625035, 0.657029, 0.685667, 0.712150, 0.735991, 0.757467, 0.777313, 0.795374, 0.811669, 0.826496, 0.839932, 0.852416, 0.863766, 0.874277, 0.883399, 0.892242, 0.900084, 0.907216, 0.914023, 0.920103, 0.925504, 0.930744, 0.935424, 0.939752, 0.943788, 0.947313, 0.950768, 0.953860, 0.956675, 0.959339, 0.961755, 0.964039, 0.965984, 0.967994, 0.969968, 0.971283, 0.972800, 0.974223, 0.975784, 0.976647, 0.977953, 0.978887, 0.979922, 0.980773, 0.981637, 0.982386, 0.983068, 0.983759, 0.984436, 0.984855, 0.985453, 0.985916, 0.986417, 0.986934, 0.987182, 0.987435, 0.988022, 0.988146, 0.988537, 0.988792, 0.989043, 0.989235, 0.989470, 0.989681, 0.989857, 0.990006, 0.990159, 0.990263, 0.990455, 0.990515, 0.990636, 0.990731, 0.990787, 0.990884, 0.990900, 0.990971, 0.990986, 0.991042, 0.991048, 0.991057, 0.991057, 0.991048, 0.991042, 0.990986, 0.990971, 0.990900, 0.990884, 0.990787, 0.990731, 0.990636, 0.990515, 0.990455, 0.990263, 0.990159, 0.990006, 0.989857, 0.989681, 0.989470, 0.989235, 0.989043, 0.988787, 0.988532, 0.988146, 0.988022, 0.987435, 0.987182, 0.986934, 0.986417, 0.985916, 0.985453, 0.984855, 0.984436, 0.983759, 0.983068, 0.982386, 0.981637, 0.980773, 0.979920, 0.978887, 0.977953, 0.976647, 0.975784, 0.974223, 0.972800, 0.971284, 0.969970, 0.967994, 0.965984, 0.964039, 0.961755, 0.959339, 0.956675, 0.953860, 0.950768, 0.947313, 0.943788, 0.939752, 0.935424, 0.930744, 0.925504, 0.920103, 0.914023, 0.907216, 0.900084, 0.892242, 0.883399, 0.874277, 0.863766, 0.852416, 0.839932, 0.826496, 0.811669, 0.795374, 0.777313, 0.757467, 0.735991, 0.712150, 0.685667, 0.657029, 0.625035, 0.589915, 0.551116, 0.508397, 0.460966, 0.408796, 0.351055, 0.287226, 0.216842, 0.139913, 0.062742]]); beta = beta * DTOR # Tilt from horizontal of the PV modules/panels, in radians sazm = sazm * DTOR # Surface azimuth of PV module/panels, in radians # 1. Calculate and assign various paramters to be used for modeling irradiances iso_dif = 0.0; circ_dif = 0.0; horiz_dif = 0.0; grd_dif = 0.0; beam = 0.0; # For calling PerezComp to break diffuse into components for zero tilt (horizontal) ghi, iso_dif, circ_dif, horiz_dif, grd_dif, beam = perezComp(dni, dhi, albedo, zen, 0.0, zen) # Call to get iso_dif for horizontal surface # print "PEREZCOMP1 = " # print "ghi = ", ghi # print "iso_dif = ", iso_dif # print "circ_dif = ", circ_dif # print "horiz_dif = ", horiz_dif # print "grd_dif = ", grd_dif # print "beam = ", beam iso_sky_dif = iso_dif; # Isotropic irradiance from sky on horizontal surface, used later for determining isotropic sky component inc, tiltr, sazmr = sunIncident(0, 90.0, 180.0, 45.0, zen, azm) # For calling PerezComp to break diffuse into components for 90 degree tilt (vertical) # print "sunIncident 1." # print "inc = ", inc # print "tiltr = ", tiltr # print "sazmr = ", sazmr vti, iso_dif, circ_dif, horiz_dif, grd_dif, beam = perezComp(dni, dhi, albedo, inc, tiltr, zen) # Call to get horiz_dif for vertical surface # print "PEREZCOMP1 = " # print "vti = ", vti # print "iso_dif = ", iso_dif # print "circ_dif = ", circ_dif # print "horiz_dif = ", horiz_dif # print "grd_dif = ", grd_dif # print "beam = ", beam F2DHI = horiz_dif; # Horizon diffuse irradiance on a vertical surface, used later for determining horizon brightening irradiance component index = -99; n2 = -99.9; if (PVfrontSurface == "glass"): index = 0; # Index to use with 1-degree hemispherical segment AOI correction factor array n2 = 1.526; # Index of refraction for glass elif (PVfrontSurface == "ARglass"): index = 1; # Index to use with 1-degree hemispherical segment AOI correction factor array n2 = 1.300; # Index of refraction for ARglass else: raise Exception("Incorrect text input for PVfrontSurface. Must be glass or ARglass.") Ro = math.pow((n2 - 1.0) / (n2 + 1.0), 2.0); # Reflectance at normal incidence, Duffie and Beckman p217 aveGroundGHI = 0.0; # Average GHI on ground under PV array for cases when x projection exceed 2*rtr for i in range (0,100): aveGroundGHI += frontGroundGHI[i] / 100.0; # Calculate x,y coordinates of bottom and top edges of PV row in front of desired PV row so that portions of sky and ground viewed by the # PV cell may be determined. Origin of x-y axis is the ground pobelow the lower front edge of the desired PV row. The row in front of # the desired row is in the negative x direction. h = math.sin(beta); # Vertical height of sloped PV panel (in PV panel slope lengths) x1 = math.cos(beta); # Horizontal distance from front of panel to rear of panel (in PV panel slope lengths) rtr = D + x1; # Row-to-row distance (in PV panel slope lengths) PbotX = -rtr; # x value for poon bottom egde of PV module/panel of row in front of (in PV panel slope lengths) PbotY = C; # y value for poon bottom egde of PV module/panel of row in front of (in PV panel slope lengths) PtopX = -D; # x value for poon top egde of PV module/panel of row in front of (in PV panel slope lengths) PtopY = h + C; # y value for poon top egde of PV module/panel of row in front of (in PV panel slope lengths) # 2. Calculate diffuse and direct component irradiances for each cell row for i in range (0, cellRows): # Calculate diffuse irradiances and reflected amounts for each cell row over it's field of view of 180 degrees, # beginning with the angle providing the upper most view of the sky (j=0) PcellX = x1 * (i + 0.5) / (cellRows); # x value for location of PV cell PcellY = C + h * (i + 0.5) / (cellRows); # y value for location of PV cell elvUP = math.atan((PtopY - PcellY) / (PcellX - PtopX)); # Elevation angle up from PV cell to top of PV module/panel, radians elvDOWN = math.atan((PcellY - PbotY) / (PcellX - PbotX)); # Elevation angle down from PV cell to bottom of PV module/panel, radians if (rowType == "first" or rowType == "single"): # 4/19/16 No array in front for these cases elvUP = 0.0; elvDOWN = 0.0; #Console.WriteLine("ElvUp = 0", elvUP / DTOR); #if (i == 0) # Console.WriteLine("ElvDown = 0", elvDOWN / DTOR); if math.isnan(beta): print( "Beta is Nan") if math.isnan(elvUP): print( "elvUP is Nan") if math.isnan((math.pi - beta - elvUP) / DTOR): print( "division is Nan") iStopIso = int(round(np.float64((math.pi - beta - elvUP)) / DTOR)) # Last whole degree in arc range that sees sky, first is 0 #Console.WriteLine("iStopIso = 0", iStopIso); iHorBright = int(round(max(0.0, 6.0 - elvUP / DTOR))); # Number of whole degrees for which horizon brightening occurs iStartGrd = int(round((math.pi - beta + elvDOWN) / DTOR)); # First whole degree in arc range that sees ground, last is 180 # print "iStopIso = ", iStopIso # print "iHorBright = ", iHorBright # print "iStartGrd = ", iStartGrd frontGTI.append(0.0) # Initialtize front GTI frontReflected.append(0.0); # Initialize reflected amount from front for j in range (0, iStopIso): # Add sky diffuse component and horizon brightening if present #for (j = 0; j < iStopIso; j++) frontGTI[i] += 0.5 * (math.cos(j * DTOR) - math.cos((j + 1) * DTOR)) * SegAOIcor[index][j] * iso_sky_dif; # Sky radiation frontReflected[i] += 0.5 * (math.cos(j * DTOR) - math.cos((j + 1) * DTOR)) * iso_sky_dif * (1.0 - SegAOIcor[index][j] * (1.0 - Ro)); # Reflected radiation from module if ((iStopIso - j) <= iHorBright): # Add horizon brightening term if seen frontGTI[i] += 0.5 * (math.cos(j * DTOR) - math.cos((j + 1) * DTOR)) * SegAOIcor[index][j] * F2DHI / 0.052264; # 0.052246 = 0.5 * [cos(84) - cos(90)] frontReflected[i] += 0.5 * (math.cos(j * DTOR) - math.cos((j + 1) * DTOR)) * (F2DHI / 0.052264) * (1.0 - SegAOIcor[index][j] * (1.0 - Ro)); # Reflected radiation from module #if (i == 0) # Console.WriteLine("iStartGrd = 0", iStartGrd); for j in range (iStartGrd, 180): # Add ground reflected component #(j = iStartGrd; j < 180; j++) startElvDown = (j - iStartGrd) * DTOR + elvDOWN; # Start and ending down elevations for this j loop stopElvDown = (j + 1 - iStartGrd) * DTOR + elvDOWN; projectedX1 = PcellX - np.float64(PcellY) / math.tan(startElvDown); # Projection of ElvDown to ground in -x direction projectedX2 = PcellX - PcellY / math.tan(stopElvDown); actualGroundGHI = 0.0; # Actuall ground GHI from summing array values #if (i == 0) # Console.WriteLine("j= 0 projected X1 = 1,6:0.0", j, 100 * projectedX1 / rtr); if (abs(projectedX1 - projectedX2) > 0.99 * rtr): if (rowType == "first" or rowType == "single"): # 4/19/16 No array in front for these cases actualGroundGHI = ghi; # Use total value if projection approximates the rtr else: actualGroundGHI = aveGroundGHI; # Use average value if projection approximates the rtr else: projectedX1 = 100.0 * projectedX1 / rtr; # Normalize projections and multiply by 100 projectedX2 = 100.0 * projectedX2 / rtr; if ((rowType == "first" or rowType == "single") and (abs(projectedX1) > rtr or abs(projectedX2) > rtr)): #4/19/2016 actualGroundGHI = ghi; # Use total value if projection > rtr for "first" or "single" else: while (projectedX1 < 0.0 or projectedX2 < 0.0): # Offset so array indexes are positive projectedX1 += 100.0; projectedX2 += 100.0; index1 = int(projectedX1); # Determine indexes for use with groundGHI array (truncates values) index2 = int(projectedX2); if (index1 == index2): actualGroundGHI = frontGroundGHI[index1]; # x projections in same groundGHI element else: for k in range (index1, index2+1): # Sum the irradiances on the ground if projections are in different groundGHI elements #for (k = index1; k <= index2; k++) #Console.WriteLine("index1=0 index2=1", index1,index2); if (k == index1): actualGroundGHI += frontGroundGHI[k] * (k + 1.0 - projectedX1); elif (k == index2): if (k < 100): actualGroundGHI += frontGroundGHI[k] * (projectedX2 - k); else: actualGroundGHI += frontGroundGHI[k - 100] * (projectedX2 - k); else: if (k < 100): actualGroundGHI += frontGroundGHI[k]; else: actualGroundGHI += frontGroundGHI[k - 100]; actualGroundGHI /= projectedX2 - projectedX1; # Irradiance on ground in the 1 degree field of view #if (i == 0) # Console.WriteLine("j=0 index1=1 index2=2 projectX1=3,5:0.0 projectX2=4,5:0.0 actualGrdGHI=5,6:0.0", j, index1, index2, projectedX1, projectedX2, actualGroundGHI); frontGTI[i] += 0.5 * (math.cos(j * DTOR) - math.cos((j + 1) * DTOR)) * SegAOIcor[index][j] * actualGroundGHI * albedo; # Add ground reflected component frontReflected[i] += 0.5 * (math.cos(j * DTOR) - math.cos((j + 1) * DTOR)) * actualGroundGHI * albedo * (1.0 - SegAOIcor[index][j] * (1.0 - Ro)); # Reflected ground radiation from module #Console.WriteLine("actualGroundGHI = 0,6:0.0 inputGHI = 1,6:0.0 aveArrayGroundGHI = 2,6:0.0", actualGroundGHI, dhi + dni * math.cos(zen), aveGroundGHI); # End of j loop for adding ground reflected componenet # Calculate and add direct and circumsolar irradiance components inc, tiltr, sazmr = sunIncident(0, beta / DTOR, sazm / DTOR, 45.0, zen, azm) # For calling PerezComp to break diffuse into components for 90 degree tilt (vertical) # print "sunIncident 2." # print "inc = ", inc # print "tiltr = ", tiltr # print "sazmr = ", sazmr # print " INCIDENT REALY NEEDED for AOI ", inc gtiAllpc, iso_dif, circ_dif, horiz_dif, grd_dif, beam = perezComp(dni, dhi, albedo, inc, tiltr, zen) # Call to get components for the tilt # print "PEREZCOMP 2 = " # print "gtiAllpc = ", vti # print "iso_dif = ", iso_dif # print "circ_dif = ", circ_dif # print "horiz_dif = ", horiz_dif # print "grd_dif = ", grd_dif # print "beam = ", beam cellShade = pvFrontSH * cellRows - i; if (cellShade > 1.0): # Fully shaded if > 1, no shade if < 0, otherwise fractionally shaded cellShade = 1.0; elif (cellShade < 0.0): cellShade = 0.0; if (cellShade < 1.0 and inc < math.pi / 2.0): # Cell not shaded entirely and inc < 90 deg cor = aOIcorrection(n2, inc); # Get AOI correction for beam and circumsolar frontGTI[i] += (1.0 - cellShade) * (beam + circ_dif) * cor; # Add beam and circumsolar radiation #frontReflected[i] += (1.0 - cellShade) * (beam + circ_dif) * (1.0 - cor * (1.0 - Ro)); # Reflected beam and circumsolar radiation from module # End of for i = 0; i < cellRows loop return aveGroundGHI, frontGTI, frontReflected;
# End of GetFrontSurfaceIrradiances
[docs]def getGroundShadeFactors(rowType, beta, C, D, elv, azm, sazm): """ This method determines if the ground is shaded from direct beam radiation for points on the ground from the leading edge of one row of PV panels to the leading edge of the next row of PV panels behind it. This row-to-row dimension is divided into 100 ground segments and a ground shade factor is returned for each ground segment, with values of 1 for shaded segments and values of 0 for non shaded segments. The fractional amounts of shading of the front and back surfaces of the PV panel are also returned. 8/20/2015 4/18/2016 - Modified to account for different row types. Because the ground factors may now be different depending on row, they are calculated for the row-to-row dimension to the rear of the leading module edge and to the front of the leading edge. Also returned is the maximum shadow length projected to the front or rear from the front of the module row Parameters ---------- rowType : str "first", "interior", "last", or "single" beta Tilt from horizontal of the PV modules/panels (deg) C Ground clearance of PV panel (in PV panel slope lengths) D Horizontal distance between rows of PV panels (in PV panel slope lengths) elv Sun elevation (in radians) azm Sun azimuth (in radians) sazm Surface azimuth of PV panels (deg) Returns ------- pvFrontSH : numeric Decimal fraction of the front surface of the PV panel that is shaded, 0.0 to 1.0 pvBackSH : numeric Decimal fraction of the back surface of the PV panel that is shaded, 0.0 to 1.0 rearGroundSH : array of size [100] Ground shade factors for ground segments to the rear, 0 = not shaded, 1 = shaded frontGroundSH : array of size [100] Ground shade factors for ground segments to the front, 0 = not shaded, 1 = shaded maxShadow : numeric Maximum shadow length projected to the front(-) or rear (+) from the front of the module row (in PV panel slope lengths), only used later for rowTypes other than "interior" """ rearGroundSH = [] frontGroundSH = [] beta = beta * DTOR # Tilt from horizontal of the PV modules/panels, in radians sazm = sazm * DTOR # Surface azimuth of PV module/pamels, in radians h = math.sin(beta); # Vertical height of sloped PV panel (in PV panel slope lengths) x1 = math.cos(beta); # Horizontal distance from front of panel to rear of panel (in PV panel slope lengths) rtr = D + x1; # Row-to-row distance (in PV panel slope lengths) # Divide the row-to-row spacing into 100 intervals for calculating ground shade factors delta = rtr / 100.0; x = -delta / 2.0; # Initialize horizontal dimension x to provide midpoof intervals Lh = (h / math.tan(elv)) * math.cos(sazm - azm); # Horizontal length of shadow perpindicular to row from top of module to bottom of module Lhc = ((h + C) / math.tan(elv)) * math.cos(sazm - azm); # Horizontal length of shadow perpindicular to row from top of module to ground level Lc = (C / math.tan(elv)) * math.cos(sazm - azm); # Horizontal length of shadow perpindicular to row from bottom of module to ground level ss1 = 0.0; se1 = 0.0; ss2 = 0.0; se2 = 0.0; # Initialize shading start (s) and end (e) to zeros for two potential shading segments pvFrontSH = 0.0; pvBackSH = 0.0; if (rowType == "interior"): if (Lh > D): # Front side of PV module partially shaded, back completely shaded, ground completely shaded pvFrontSH = (Lh - D) / (Lh + x1); pvBackSH = 1.0; ss1 = 0.0; # Ground shaded from 0.0 to rtr se1 = rtr; elif (Lh < -(rtr + x1)): # Back side of PV module partially shaded, front completely shaded, ground completely shaded pvFrontSH = 1.0; pvBackSH = (Lh + rtr + x1) / (Lh + x1); ss1 = 0.0; # Ground shaded from 0.0 to rtr se1 = rtr; else: # Ground is partially shaded (I assume) if (Lhc >= 0.0): # Shadow to rear of row, module front unshaded, back shaded pvFrontSH = 0.0; pvBackSH = 1.0; Ss = Lc; # Shadow starts at Lc Se = Lhc + x1; # Shadow ends here while (Ss > rtr): Ss -= rtr; # Put shadow in correct rtr space if needed Se -= rtr; ss1 = Ss; se1 = Se; if (se1 > rtr): # then need to use two shade areas se1 = rtr; ss2 = 0.0; se2 = Se - rtr; if (se2 > ss1): # This would mean ground completely shaded, does this occur? ss1 = 0.0; # Ground shaded from 0.0 to rtr se1 = rtr; else: # Shadow to front of row, either front or back might be shaded, depending on tilt and other factors Ss = 0.0; # Shadow starts at Lc, initialize Se = 0.0; # Shadow ends here, initialize if (Lc < Lhc + x1): pvFrontSH = 0.0; pvBackSH = 1.0; Ss = Lc; # Shadow starts at Lc Se = Lhc + x1; # Shadow ends here else: pvFrontSH = 1.0; pvBackSH = 0.0; Ss = Lhc + x1; # Shadow starts at Lhc + x1 Se = Lc; # Shadow ends here while (Ss < 0.0): Ss += rtr; # Put shadow in correct rtr space if needed Se += rtr; ss1 = Ss; se1 = Se; if (se1 > rtr): # then need to use two shade areas se1 = rtr; ss2 = 0.0; se2 = Se - rtr; if (se2 > ss1): # This would mean ground completely shaded, does this occur? ss1 = 0.0; # Ground shaded from 0.0 to rtr se1 = rtr; # End of if (Lh > D) else branching delta = rtr / 100.0; x = -delta / 2.0; # Initialize horizontal dimension x to provide midpoof intervals #for (i = 0; i <= 99; i++) for i in range(0,100): x += delta; #if ((x >= ss1 && x < se1) || (x >= ss2 && x < se2)): if ((x >= ss1 and x < se1) or (x >= ss2 and x < se2)): rearGroundSH.append(1); # x within a shaded interval, set groundSH to 1 to indicate shaded frontGroundSH.append(1); # same for both front and rear else: rearGroundSH.append(0); # x not within a shaded interval, set groundSH to 0 to indicated not shaded, i.e. sunny frontGroundSH.append(0); # same for both front and rear #Console.WriteLine("x = 0,6:0.0000 groundSH = 1", x, groundSH[i]); # End of if row type == "interior" elif (rowType == "first"): if (Lh > 0.0): # Sun is on front side of PV module pvFrontSH = 0.0; pvBackSH = 1.0; ss1 = Lc; # Ground shaded from shadow of lower edge se1 = x1 + Lhc; # to shadow of upper edge # End of if sun on front side of PV module elif (Lh < -(rtr + x1)): # Back side of PV module partially shaded from row to rear, front completely shaded, ground completely shaded pvFrontSH = 1.0; pvBackSH = (Lh + rtr + x1) / (Lh + x1); ss1 = -rtr; # Ground shaded from -rtr to rtr se1 = rtr; # End of if back side of PV module partially shaded, front completely shaded, ground completely shaded else: # Shadow to frontside of row, either front or back might be shaded, depending on tilt and other factors if (Lc < Lhc + x1): pvFrontSH = 0.0; pvBackSH = 1.0; ss1 = Lc; # Shadow starts at Lc se1 = Lhc + x1; # Shadow ends here else: pvFrontSH = 1.0; pvBackSH = 0.0; ss1 = Lhc + x1; # Shadow starts at Lhc + x1 se1 = Lc; # Shadow ends here # End of shadow to front of row delta = rtr / 100.0; x = -delta / 2.0; # Initialize horizontal dimension x to provide midpoof intervals for i in range(0,100): x += delta; if (x >= ss1 and x < se1): rearGroundSH.append(1) # x within a shaded interval, set groundSH to 1 to indicate shaded else: rearGroundSH.append(0) # x not within a shaded interval, set groundSH to 0 to indicated not shaded, i.e. sunny x = -rtr - delta / 2.0; # Initialize horizontal dimension x to provide midpoof intervals for front interval for i in range(0,100): x += delta; if (x >= ss1 and x < se1): frontGroundSH.append(1) # x within a shaded interval, set groundSH to 1 to indicate shaded else: frontGroundSH.append(0) # x not within a shaded interval, set groundSH to 0 to indicated not shaded, i.e. sunny # End of if row type == "first" elif (rowType == "last"): if (Lh > D): # Front side of PV module partially shaded, back completely shaded, ground completely shaded pvFrontSH = (Lh - D) / (Lh + x1); pvBackSH = 1.0; ss1 = -rtr; # Ground shaded from -rtr to rtr se1 = rtr; else: # Shadow to frontside of row, either front or back might be shaded, depending on tilt and other factors if (Lc < Lhc + x1): pvFrontSH = 0.0; pvBackSH = 1.0; ss1 = Lc; # Shadow starts at Lc se1 = Lhc + x1; # Shadow ends here else: pvFrontSH = 1.0; pvBackSH = 0.0; ss1 = Lhc + x1; # Shadow starts at Lhc + x1 se1 = Lc; # Shadow ends here # End of shadow to front of row delta = rtr / 100.0; x = -delta / 2.0; # Initialize horizontal dimension x to provide midpoof intervals for i in range(0,100): x += delta; if (x >= ss1 and x < se1): rearGroundSH.append(1); # x within a shaded interval, set groundSH to 1 to indicate shaded else: rearGroundSH.append(0); # x not within a shaded interval, set groundSH to 0 to indicated not shaded, i.e. sunny x = -rtr - delta / 2.0; # Initialize horizontal dimension x to provide midpoof intervals for front interval for i in range(0,100): x += delta; if (x >= ss1 and x < se1): frontGroundSH.append(1); # x within a shaded interval, set groundSH to 1 to indicate shaded else: frontGroundSH.append(0); # x not within a shaded interval, set groundSH to 0 to indicated not shaded, i.e. sunny # End of if row type == "last" elif (rowType == "single"): if (Lh > 0.0): # Shadow to the rear pvFrontSH = 0.0; pvBackSH = 1.0; ss1 = Lc; # Ground shaded from shadow of lower edge se1 = x1 + Lhc; # to shadow of upper edge # End of if sun on front side of PV module else: # Shadow to frontside of row, either front or back might be shaded, depending on tilt and other factors if (Lc < Lhc + x1): pvFrontSH = 0.0; pvBackSH = 1.0; ss1 = Lc; # Shadow starts at Lc se1 = Lhc + x1; # Shadow ends here else: pvFrontSH = 1.0; pvBackSH = 0.0; ss1 = Lhc + x1; # Shadow starts at Lhc + x1 se1 = Lc; # Shadow ends here # End of shadow to front of row delta = rtr / 100.0; x = -delta / 2.0; # Initialize horizontal dimension x to provide midpoof intervals for i in range(0,100): x += delta; if (x >= ss1 and x < se1): rearGroundSH.append(1); # x within a shaded interval, set groundSH to 1 to indicate shaded else: rearGroundSH.append(0); # x not within a shaded interval, set groundSH to 0 to indicated not shaded, i.e. sunny x = -rtr - delta / 2.0; # Initialize horizontal dimension x to provide midpoof intervals for front interval for i in range(0,100): x += delta; if (x >= ss1 and x < se1): frontGroundSH.append(1); # x within a shaded interval, set groundSH to 1 to indicate shaded else: frontGroundSH.append(0); # x not within a shaded interval, set groundSH to 0 to indicated not shaded, i.e. sunny # End of if row type == "single" else: print ("ERROR: Incorrect row type not passed to function GetGroundShadedFactors "); if (abs(ss1) > abs(se1)): # Maximum shadow length projected from the front of the PV module row maxShadow = ss1; else: maxShadow = se1; #Console.WriteLine("elv = 0,6:0.00 azm = 1,6:0.00 sazm = 2,6:0.00", elv * 180.0 / math.pi, azm * 180.0 / math.pi, sazm * 180.0 / math.pi); #Console.WriteLine("ss1 = 0,6:0.0000 se1 = 1,6:0.0000 ss2 = 2,6:0.0000 se2 = 3,6:0.0000 rtr = 4,6:0.000", ss1, se1, ss2, se2, rtr); #Console.WriteLine("pvFrontSH = 0,6:0.00 pvBackSH = 1,6:0.00", pvFrontSH, pvBackSH); # End of GetGroundShadedFactors #print "rearGroundSH", rearGroundSH[0] return pvFrontSH, pvBackSH, maxShadow, rearGroundSH, frontGroundSH;
# End of getGroundShadeFactors
[docs]def getSkyConfigurationFactors(rowType, beta, C, D): """ This method determines the sky configuration factors for points on the ground from the leading edge of one row of PV panels to the leading edge of the next row of PV panels behind it. This row-to-row dimension is divided into 100 ground segments and a sky configuration factor is returned for each ground segment. The sky configuration factor represents the fraction of the isotropic diffuse sky radiation (unobstructed) that is present on the ground when partially obstructed by the rows of PV panels. The equations follow that on pages in the notebook dated 8/12/2015. 8/20/2015 4/15/2016 Modifed for calculations other than just the interior rows. Row type is identified with the string `rowType`, with the possilbe values: * first = first row of the array * interior = interior row of array * last = last row of the array * single = a single row array Because the sky configuration factors may now be different depending on row, they are calculated for the row-to-row dimension to the rear of the leading module edge and to the front of the leading edge. Parameters ---------- rowType : str "first", "interior", "last", or "single" beta : float Tilt from horizontal of the PV modules/panels (deg) C : float Ground clearance of PV panel (in PV module/panel slope lengths) D : float Horizontal distance between rows of PV panels (in PV module/panel slope lengths) Returns ------- rearSkyConfigFactors : array of size [100] Sky configuration factors to rear of leading PVmodule edge (decimal fraction) frontSkyConfigFactors : array of size [100] Sky configuration factors to rear of leading PVmodule edge (decimal fraction) Notes ----- The horizontal distance between rows, `D`, is from the back edge of one row to the front edge of the next, and it is not the row-to-row spacing. """ rearSkyConfigFactors = [] frontSkyConfigFactors = [] # Tilt from horizontal of the PV modules/panels, in radians beta = beta * DTOR # Vertical height of sloped PV panel (in PV panel slope lengths) h = math.sin(beta) # Horizontal distance from front of panel to rear of panel (in PV panel # slope lengths) x1 = math.cos(beta) rtr = D + x1 # Row-to-row distance (in PV panel slope lengths) # Forced fix for case of C = 0 # FIXME: for some reason the Config Factors go from 1 to 2 and not 0 to 1. # TODO: investigate why this is happening in the code. if C==0: C=0.0000000001 if C < 0: LOGGER.error( "Height is below ground level. Function GetSkyConfigurationFactors" " will continue but results might be unreliable") # Divide the row-to-row spacing into 100 intervals and calculate # configuration factors delta = rtr / 100.0 if (rowType == "interior"): # Initialize horizontal dimension x to provide midpoint of intervals x = -delta / 2.0 for i in range(0,100): x += delta # <--rtr=x1+D--><--rtr=x1+D--><--rtr=x1+D--> # |\ |\ |\ |\ # | \ ` | \ | \ /| \ # h \ ` h \ h \ / h \ # | \ ` | \ | \ / | \ # |_x1_\____D__`|_x1_\____D___|_x1_\_/_D____|_x1_\_ # | ` <------x-----/| # C ` / # | angA ` / angB # *------------------------`-/--------------------- # x # use ATAN2: 4-quadrant tangent instead of ATAN # check 2 rows away angA = math.atan2(h + C, (2.0 * rtr + x1 - x)) angB = math.atan2(C, (2.0 * rtr - x)) beta1 = max(angA, angB) # check 1 rows away angA = math.atan2(h + C, (rtr + x1 - x)) angB = math.atan2(C, (rtr - x)) beta2 = min(angA, angB) # check 0 rows away beta3 = max(angA, angB) beta4 = math.atan2(h + C, (x1 - x)) beta5 = math.atan2(C, (-x)) beta6 = math.atan2(h + C, (-D - x)) sky1 =0; sky2 =0; sky3 =0 if (beta2 > beta1): sky1 = 0.5 * (math.cos(beta1) - math.cos(beta2)) if (beta4 > beta3): sky2 = 0.5 * (math.cos(beta3) - math.cos(beta4)) if (beta6 > beta5): sky3 = 0.5 * (math.cos(beta5) - math.cos(beta6)) skyAll = sky1 + sky2 + sky3 # Save as arrays of values, same for both to the rear and front rearSkyConfigFactors.append(skyAll) frontSkyConfigFactors.append(skyAll) # End of if "interior" elif (rowType == "first"): # RearSkyConfigFactors don't have a row in front, calculation of sky3 # changed, beta6 = 180 degrees x = -delta / 2.0; # Initialize horizontal dimension x to provide midpoint of intervals for i in range(0,100): x += delta; angA = math.atan((h + C) / (2.0 * rtr + x1 - x)); if (angA < 0.0): angA += math.pi; angB = math.atan(C / (2.0 * rtr - x)); if (angB < 0.0): angB += math.pi; beta1 = max(angA, angB); angA = math.atan((h + C) / (rtr + x1 - x)); if (angA < 0.0): angA += math.pi; angB = math.atan(C / (rtr - x)); if (angB < 0.0): angB += math.pi; beta2 = min(angA, angB); beta3 = max(angA, angB); beta4 = math.atan((h + C) / (x1 - x)); if (beta4 < 0.0): beta4 += math.pi; beta5 = math.atan(C / (-x)); if (beta5 < 0.0): beta5 += math.pi; beta6 = math.pi; sky1 = 0.0; sky2 = 0.0; sky3 = 0.0; if (beta2 > beta1): sky1 = 0.5 * (math.cos(beta1) - math.cos(beta2)); if (beta4 > beta3): sky2 = 0.5 * (math.cos(beta3) - math.cos(beta4)); if (beta6 > beta5): sky3 = 0.5 * (math.cos(beta5) - math.cos(beta6)); skyAll = sky1 + sky2 + sky3; rearSkyConfigFactors.append(skyAll); # Save as arrays of values #Console.WriteLine("0,5:0.000,1,5:0.000,2,5:0.000,3,5:0.000,4,5:0.000", x, sky1, sky2, sky3, skyAll); #sw.WriteLine("0,5:0.000,1,5:0.000,2,5:0.000,3,5:0.000,4,5:0.000", x, sky1, sky2, sky3, skyAll); # frontSkyConfigFactors don't have a row in front, calculation of sky3 included as part of revised sky2, # beta 4 set to 180 degrees x = -delta / 2.0; # Initialize horizontal dimension x to provide midpoint of intervals for i in range(0,100): x += delta; angA = math.atan((h + C) / (2.0 * rtr + x1 - x)); if (angA < 0.0): angA += math.pi; angB = math.atan(C / (2.0 * rtr - x)); if (angB < 0.0): angB += math.pi; beta1 = max(angA, angB); angA = math.atan((h + C) / (rtr + x1 - x)); if (angA < 0.0): angA += math.pi; angB = math.atan(C / (rtr - x)); if (angB < 0.0): angB += math.pi; beta2 = min(angA, angB); beta3 = max(angA, angB); beta4 = math.pi; sky1 = 0.0; sky2 = 0.0; if (beta2 > beta1): sky1 = 0.5 * (math.cos(beta1) - math.cos(beta2)); if (beta4 > beta3): sky2 = 0.5 * (math.cos(beta3) - math.cos(beta4)); skyAll = sky1 + sky2; frontSkyConfigFactors.append(skyAll); # Save as arrays of values #Console.WriteLine("0,5:0.000,1,5:0.000,2,5:0.000,3,5:0.000,4,5:0.000", x, sky1, sky2, sky3, skyAll); #sw.WriteLine("0,5:0.000,1,5:0.000,2,5:0.000,3,5:0.000,4,5:0.000", x, sky1, sky2, sky3, skyAll); # End of if "first" elif (rowType == "last"): # RearSkyConfigFactors don't have a row to the rear, combine sky1 into sky 2, set beta 3 = 0.0 x = -delta / 2.0; # Initialize horizontal dimension x to provide midpoint of intervals for i in range(0,100): x += delta; beta3 = 0.0; beta4 = math.atan((h + C) / (x1 - x)); if (beta4 < 0.0): beta4 += math.pi; beta5 = math.atan(C / (-x)); if (beta5 < 0.0): beta5 += math.pi; beta6 = math.atan((h + C) / (-D - x)); if (beta6 < 0.0): beta6 += math.pi; sky2 = 0.0; sky3 = 0.0; if (beta4 > beta3): sky2 = 0.5 * (math.cos(beta3) - math.cos(beta4)); if (beta6 > beta5): sky3 = 0.5 * (math.cos(beta5) - math.cos(beta6)); skyAll = sky2 + sky3; rearSkyConfigFactors.append(skyAll); # Save as arrays of values #Console.WriteLine("0,5:0.000,1,5:0.000,2,5:0.000,3,5:0.000,4,5:0.000", x, sky1, sky2, sky3, skyAll); #sw.WriteLine("0,5:0.000,1,5:0.000,2,5:0.000,3,5:0.000,4,5:0.000", x, sky1, sky2, sky3, skyAll); # FrontSkyConfigFactors have beta1 = 0.0 x = -delta / 2.0; # Initialize horizontal dimension x to provide midpoint of intervals for i in range(0,100): x += delta; angA = math.atan((h + C) / (2.0 * rtr + x1 - x)); if (angA < 0.0): angA += math.pi; angB = math.atan(C / (2.0 * rtr - x)); if (angB < 0.0): angB += math.pi; beta1 = max(angA, angB); beta1 = 0.0; angA = math.atan((h + C) / (rtr + x1 - x)); if (angA < 0.0): angA += math.pi; angB = math.atan(C / (rtr - x)); if (angB < 0.0): angB += math.pi; beta2 = min(angA, angB); beta3 = max(angA, angB); beta4 = math.atan((h + C) / (x1 - x)); if (beta4 < 0.0): beta4 += math.pi; beta5 = math.atan(C / (-x)); if (beta5 < 0.0): beta5 += math.pi; beta6 = math.atan((h + C) / (-D - x)); if (beta6 < 0.0): beta6 += math.pi; sky1 = 0.0; sky2 = 0.0; sky3 = 0.0; if (beta2 > beta1): sky1 = 0.5 * (math.cos(beta1) - math.cos(beta2)); if (beta4 > beta3): sky2 = 0.5 * (math.cos(beta3) - math.cos(beta4)); if (beta6 > beta5): sky3 = 0.5 * (math.cos(beta5) - math.cos(beta6)); skyAll = sky1 + sky2 + sky3; frontSkyConfigFactors.append(skyAll); # Save as arrays of values, #Console.WriteLine("0,5:0.000,1,5:0.000,2,5:0.000,3,5:0.000,4,5:0.000", x, sky1, sky2, sky3, skyAll); #sw.WriteLine("0,5:0.000,1,5:0.000,2,5:0.000,3,5:0.000,4,5:0.000", x, sky1, sky2, sky3, skyAll); # End of if "last" row elif (rowType == "single"): # RearSkyConfigFactors don't have a row to the rear ir front, combine sky1 into sky 2, set beta 3 = 0.0, # for sky3, beta6 = 180.0. x = -delta / 2.0; # Initialize horizontal dimension x to provide midpoint of intervals for i in range(0,100): x += delta; beta3 = 0.0; beta4 = math.atan((h + C) / (x1 - x)); if (beta4 < 0.0): beta4 += math.pi; beta5 = math.atan(C / (-x)); if (beta5 < 0.0): beta5 += math.pi; beta6 = math.pi; sky2 = 0.0; sky3 = 0.0; if (beta4 > beta3): sky2 = 0.5 * (math.cos(beta3) - math.cos(beta4)); if (beta6 > beta5): sky3 = 0.5 * (math.cos(beta5) - math.cos(beta6)); skyAll = sky2 + sky3; rearSkyConfigFactors.append(skyAll); # Save as arrays of values #Console.WriteLine("0,5:0.000,1,5:0.000,2,5:0.000,3,5:0.000,4,5:0.000", x, sky1, sky2, sky3, skyAll); #sw.WriteLine("0,5:0.000,1,5:0.000,2,5:0.000,3,5:0.000,4,5:0.000", x, sky1, sky2, sky3, skyAll); # FrontSkyConfigFactors have only a row to the rear, combine sky3 into sky2, set beta1 = 0, beta4 = 180 x = -delta / 2.0; # Initialize horizontal dimension x to provide midpoint of intervals for i in range(0,100): x += delta; angA = math.atan((h + C) / (2.0 * rtr + x1 - x)); if (angA < 0.0): angA += math.pi; angB = math.atan(C / (2.0 * rtr - x)); if (angB < 0.0): angB += math.pi; beta1 = max(angA, angB); beta1 = 0.0; angA = math.atan((h + C) / (rtr + x1 - x)); if (angA < 0.0): angA += math.pi; angB = math.atan(C / (rtr - x)); if (angB < 0.0): angB += math.pi; beta2 = min(angA, angB); beta3 = max(angA, angB); beta4 = math.pi; sky1 = 0.0; sky2 = 0.0; if (beta2 > beta1): sky1 = 0.5 * (math.cos(beta1) - math.cos(beta2)); if (beta4 > beta3): sky2 = 0.5 * (math.cos(beta3) - math.cos(beta4)); skyAll = sky1 + sky2; frontSkyConfigFactors.append(skyAll); # Save as arrays of values #Console.WriteLine("0,5:0.000,1,5:0.000,2,5:0.000,3,5:0.000,4,5:0.000", x, sky1, sky2, sky3, skyAll); #sw.WriteLine("0,5:0.000,1,5:0.000,2,5:0.000,3,5:0.000,4,5:0.000", x, sky1, sky2, sky3, skyAll); # End of if "single" else: print("ERROR: Incorrect row type not passed to function GetSkyConfigurationFactors "); return rearSkyConfigFactors, frontSkyConfigFactors;
# End of GetSkyConfigurationFactors
[docs]def rowSpacing(beta, sazm, lat, lng, tz, hour, minute): """ This method determines the horizontal distance D between rows of PV panels (in PV module/panel slope lengths) for no shading on December 21 (north hemisphere) June 21 (south hemisphere) for a module tilt angle beta and surface azimuth sazm, and a given latitude, longitude, and time zone and for the time passed to the method (typically 9 am). (Ref: the row-to-row spacing is then ``D + cos(beta)``) 8/21/2015 Parameters ---------- beta : double Tilt from horizontal of the PV modules/panels (deg) sazm : double Surface azimuth of the PV modules/panels (deg) lat : double Site latitude (deg) lng : double Site longitude (deg) tz : double Time zone (hrs) hour : int hour for no shading criteria minute: double minute for no shading Returns ------- D : numeric Horizontal distance between rows of PV panels (in PV panel slope lengths) """ beta = beta * DTOR # Tilt from horizontal of the PV modules/panels, in radians sazm = sazm * DTOR # Surface azimuth of PV module/pamels, in radians if lat >= 0: [azm, zen, elv, dec, sunrise, sunset, Eo, tst] = solarPos (2014, 12, 21, hour, minute, lat, lng, tz) else: [azm, zen, elv, dec, sunrise, sunset, Eo, tst] = solarPos (2014, 6, 21, hour, minute, lat, lng, tz) tst = 8.877 ##DLL Forced value minute -= 60.0 * (tst - hour); # Adjust minute so sun position is calculated for a tst equal to the # time passed to the function if lat >= 0: [azm, zen, elv, dec, sunrise, sunset, Eo, tst] = solarPos(2014, 12, 21, hour, minute, lat, lng, tz) else: [azm, zen, elv, dec, sunrise, sunset, Eo, tst] = solarPos(2014, 6, 21, hour, minute, lat, lng, tz) # Console.WriteLine("tst = {0} azm = {1} elv = {2}", tst, azm * 180.0 / Math.PI, elv * 180.0 / Math.PI); D = math.cos(sazm - azm) * math.sin(beta) / math.tan(elv) return D
# End of RowSpacing
[docs]def trackingBFvaluescalculator(beta, hub_height, r2r): ''' 1-axis tracking helper file Parameters ---------- beta : series of floats, or float Tilt from horizontal of the PV modules/panels, in radians hub_height : float tracker hub height r2r : float Row-to-row distance (in PV panel slope lengths) Returns ------- C : float ground clearance of PV panel D : float row-to-row distance (each in PV panel slope lengths) ''' beta = beta * DTOR # Tilt from horizontal of the PV modules/panels, in radians try: x1 = beta.apply(math.cos) # Horizontal distance from front of panel to rear of panel (in PV panel slope lengths) D = r2r - x1 # Calculates D DistanceBetweenRows(panel slope lengths) hm = beta.apply(math.sin)*0.5 # vertical distance from bottom of panel to top of panel (in PV panel slope lengths) #C = 0.5+Cv-hm # Ground clearance of PV panel (in PV panel slope lengths). C = hub_height - hm #Adding a 0.5 for half a panel slope length, since it is assumed the panel is rotating around its middle axis except: # in case only one value is passed x1 = math.cos(beta); # Horizontal distance from front of panel to rear of panel (in PV panel slope lengths) #rtr = D + x1; # Row-to-row distance (in PV panel slope lengths) D = r2r - x1; # Calculates D DistanceBetweenRows(panel slope lengths) hm = 0.5*math.sin(beta); # vertical distance from bottom of panel to top of panel (in PV panel slope lengths) #C = 0.5+Cv-hm # Ground clearance of PV panel (in PV panel slope lengths). C = hub_height - hm #Adding a 0.5 for half a panel slope length, since it is assumed the panel is rotating around its middle axis return C, D