Skip to content

Commit

Permalink
Revert fixed_tilt_azimuth input parameter. Minor docs cleanup. (#330)
Browse files Browse the repository at this point in the history
* Revert fixed_tilt_azimuth input parameter.  

* deprecate axis_azimuth in set1axis. Replace calls to axis_azimuth with azimuth in _set1axis and _getTrackingAngles
  • Loading branch information
cdeline committed Sep 17, 2021
1 parent facb106 commit 90d4da2
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 74 deletions.
117 changes: 51 additions & 66 deletions bifacial_radiance/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1244,8 +1244,8 @@ def _readSOLARGIS(self, solargisfile=None, label = 'center'):


def getSingleTimestampTrackerAngle(self, metdata, timeindex, gcr=None,
axis_azimuth=180, axis_tilt=0,
limit_angle=60, backtrack=True):
azimuth=180, axis_tilt=0,
limit_angle=45, backtrack=True):
"""
Helper function to calculate a tracker's angle for use with the
fixed tilt routines of bifacial_radiance. It calculates tracker angle for
Expand All @@ -1262,7 +1262,7 @@ def getSingleTimestampTrackerAngle(self, metdata, timeindex, gcr=None,
Index between 0 to 8760 indicating hour to simulate.
gcr : float
Ground coverage ratio for calculation backtracking. Defualt [1.0/3.0]
axis_azimuth : float or int
azimuth : float or int
Orientation axis of tracker torque tube. Default North-South (180 deg)
axis_tilt : float or int
Default 0. Axis tilt -- not implemented in sensors locations so it's pointless
Expand All @@ -1287,7 +1287,7 @@ def getSingleTimestampTrackerAngle(self, metdata, timeindex, gcr=None,
sunaz = float(solpos.azimuth) # not substracting the 180

trackingdata = pvlib.tracking.singleaxis(sunzen, sunaz,
axis_tilt, axis_azimuth,
axis_tilt, azimuth,
limit_angle, backtrack, gcr)

tracker_theta = float(np.round(trackingdata['tracker_theta'],2))
Expand Down Expand Up @@ -1587,9 +1587,9 @@ def genCumSky(self, temp_metdatafile=None, savefile=None):

return skyname

def set1axis(self, metdata=None, axis_azimuth=180, limit_angle=45,
def set1axis(self, metdata=None, azimuth=180, limit_angle=45,
angledelta=5, backtrack=True, gcr=1.0 / 3, cumulativesky=True,
fixed_tilt_angle=None, fixed_tilt_azimuth=None):
fixed_tilt_angle=None, axis_azimuth=None):
"""
Set up geometry for 1-axis tracking. Pull in tracking angle details from
pvlib, create multiple 8760 metdata sub-files where datetime of met data
Expand All @@ -1603,8 +1603,9 @@ def set1axis(self, metdata=None, axis_azimuth=180, limit_angle=45,
Meterological object to set up geometry. Usually set automatically by
`bifacial_radiance` after running :py:class:`bifacial_radiance.readepw`.
Default = self.metdata
axis_azimuth : numeric
Orientation axis of tracker torque tube. Default North-South (180 deg)
azimuth : numeric
Orientation axis of tracker torque tube. Default North-South (180 deg).
For fixed-tilt configuration, input is fixed azimuth (180 is south)
limit_angle : numeric
Limit angle (+/-) of the 1-axis tracker in degrees. Default 45
angledelta : numeric
Expand All @@ -1620,14 +1621,11 @@ def set1axis(self, metdata=None, axis_azimuth=180, limit_angle=45,
created with constant tilt angle for the cumulativesky approach.
if false, the gendaylit tracking approach must be used.
fixed_tilt_angle : numeric
If passed, this changes to a fixed tilt
simulation where each hour uses fixed_tilt_angle
and axis_azimuth as the tilt and azimuth
fixed_tilt_azimuth : numeric
If fixed_tilt_angle passed, this sets the azimuth angle of the
modules' surface for a fixed tilt simulation. South = 180.
If passed, this changes to a fixed tilt simulation where each hour
uses fixed_tilt_angle and axis_azimuth as the tilt and azimuth
axis_azimuth : numeric
DEPRECATED. returns deprecation warning. Pass the tracker
axis_azimuth through to azimuth input instead.
Returns
-------
Expand All @@ -1646,6 +1644,7 @@ def set1axis(self, metdata=None, axis_azimuth=180, limit_angle=45,
# metdata.surface_azimuth list of tracker azimuth data
# metdata.surface_tilt list of tracker surface tilt data
# metdata.tracker_theta list of tracker tilt angle
import warnings

if metdata == None:
metdata = self.metdata
Expand All @@ -1654,25 +1653,27 @@ def set1axis(self, metdata=None, axis_azimuth=180, limit_angle=45,
raise Exception("metdata doesnt exist yet. "+
"Run RadianceObj.readWeatherFile() ")


if axis_azimuth:
azimuth = axis_azimuth
warnings.warn("axis_azimuth is deprecated in set1axis; use azimuth "
"input instead.", DeprecationWarning)

#backtrack = True # include backtracking support in later version
#gcr = 1.0/3.0 # default value - not used if backtrack = False.


# get 1-axis tracker angles for this location, rounded to nearest 'angledelta'
trackerdict = metdata._set1axis(cumulativesky=cumulativesky,
axis_azimuth=axis_azimuth,
azimuth=azimuth,
limit_angle=limit_angle,
angledelta=angledelta,
backtrack=backtrack,
gcr=gcr,
fixed_tilt_angle=fixed_tilt_angle,
fixed_tilt_azimuth = fixed_tilt_azimuth
fixed_tilt_angle=fixed_tilt_angle
)
self.trackerdict = trackerdict
self.cumulativesky = cumulativesky


return trackerdict

def gendaylit1axis(self, metdata=None, trackerdict=None, startdate=None,
Expand Down Expand Up @@ -1711,7 +1712,7 @@ def gendaylit1axis(self, metdata=None, trackerdict=None, startdate=None,
print('No trackerdict value passed or available in self')

if startdate is not None or enddate is not None:
print("Deprecation WArning: gendyalit1axis no longer downselects"+
print("Deprecation Warning: gendyalit1axis no longer downselects"+
"Entries by stardate and enddate. Downselect your data"+
"when loading with readWeatherFile")

Expand Down Expand Up @@ -3579,12 +3580,10 @@ def _makeSceneNxR(self, moduletype=None, sceneDict=None, radname=None, hpc=False
Separation between rows
tilt : numeric
Valid input ranges -90 to 90 degrees
axis_azimuth : numeric
azimuth : numeric
A value denoting the compass direction along which the
axis of rotation lies. Measured in decimal degrees East
of North. [0 to 180) possible.
If azimuth is passed, a warning is given and Axis Azimuth and
tilt are re-calculated.
nMods : int
Number of modules per row (default = 20)
nRows : int
Expand Down Expand Up @@ -3904,12 +3903,12 @@ def __init__(self, tmydata, metadata, label = 'right'):

self.solpos = pvlib.irradiance.solarposition.get_solarposition(sunup['corrected_timestamp'],lat,lon,elev)
self.sunrisesetdata=sunup
def _set1axis(self, axis_azimuth=180, limit_angle=45, angledelta=None,


def _set1axis(self, azimuth=180, limit_angle=45, angledelta=None,
backtrack=True, gcr = 1.0/3.0, cumulativesky=True,
fixed_tilt_angle=None, fixed_tilt_azimuth=None,
axis_tilt = 0):
fixed_tilt_angle=None, axis_tilt = 0):

"""
Set up geometry for 1-axis tracking cumulativesky. Solpos data
already stored in `metdata.solpos`. Pull in tracking angle details from
Expand All @@ -3922,12 +3921,11 @@ def _set1axis(self, axis_azimuth=180, limit_angle=45, angledelta=None,
Whether individual csv files are created
with constant tilt angle for the cumulativesky approach.
if false, the gendaylit tracking approach must be used.
axis_azimuth : numerical
azimuth : numerical
orientation axis of tracker torque tube. Default North-South (180 deg)
For fixed tilt simulations (angledelta=0) this is the orientation azimuth
For fixed tilt simulations this is the orientation azimuth
limit_angle : numerical
+/- limit angle of the 1-axis tracker in degrees. Default 45
For fixed tilt simulations (angledelta=0) this is the tilt angle
angledelta : numerical
Degree of rotation increment to parse irradiance bins.
Default 5 degrees (0.4 % error for DNI).
Expand All @@ -3942,12 +3940,8 @@ def _set1axis(self, axis_azimuth=180, limit_angle=45, angledelta=None,
the scene geometry creation of the trackers does not support tilte
axis_trackers yet (but can be done manuallyish. See Tutorials)
fixed_tilt_angle : numeric
If passed, this changes to a fixed tilt
simulation where each hour uses fixed_tilt_angle
and axis_azimuth as the tilt and azimuth
fixed_tilt_azimuth : numeric
If fixed_tilt_angle passed, this sets the azimuth angle of the
modules' surface for a fixed tilt simulation. South = 180.
If passed, this changes to a fixed tilt simulation where each hour
uses fixed_tilt_angle and azimuth as the tilt and azimuth
Returns
-------
Expand All @@ -3956,7 +3950,7 @@ def _set1axis(self, axis_azimuth=180, limit_angle=45, angledelta=None,
list of csv metfile, and datetimes at that angle
trackerdict[angle]['csvfile';'surf_azm';'surf_tilt';'UTCtime']
metdata.solpos : dataframe
Pandas dataframe with output from pvlib solar position for each timestep
Dataframe with output from pvlib solar position for each timestep
metdata.sunrisesetdata :
Pandas dataframe with sunrise, sunset and adjusted time data.
metdata.tracker_theta : list
Expand All @@ -3975,14 +3969,13 @@ def _set1axis(self, axis_azimuth=180, limit_angle=45, angledelta=None,

# get 1-axis tracker angles for this location,
# round to nearest 'angledelta'
trackingdata = self._getTrackingAngles(axis_azimuth,
trackingdata = self._getTrackingAngles(azimuth,
limit_angle,
angledelta,
axis_tilt = axis_tilt,
backtrack = backtrack,
gcr = gcr,
fixed_tilt_angle=fixed_tilt_angle,
fixed_tilt_azimuth=fixed_tilt_azimuth)
fixed_tilt_angle=fixed_tilt_angle)

# get list of unique rounded tracker angles
theta_list = trackingdata.dropna()['theta_round'].unique()
Expand Down Expand Up @@ -4012,10 +4005,9 @@ def _set1axis(self, axis_azimuth=180, limit_angle=45, angledelta=None,
return trackerdict


def _getTrackingAngles(self, axis_azimuth=180, limit_angle=45,
def _getTrackingAngles(self, azimuth=180, limit_angle=45,
angledelta=None, axis_tilt=0, backtrack=True,
gcr = 1.0/3.0, fixed_tilt_angle=None,
fixed_tilt_azimuth=None):
gcr = 1.0/3.0, fixed_tilt_angle=None):
'''
Helper subroutine to return 1-axis tracker tilt and azimuth data.
Expand All @@ -4027,26 +4019,23 @@ def _getTrackingAngles(self, axis_azimuth=180, limit_angle=45,
cumulativesky simulations. Other input options: None (no
rounding of tracker angle)
fixed_tilt_angle : (Optional) degrees
This changes to a fixed tilt simulation where each hour uses fixed_tilt_angle
and axis_azimuth as the tilt and azimuth
fixed_tilt_azimuth : numeric
If fixed_tilt_angle passed, this sets the azimuth angle of the
modules' surface for a fixed tilt simulation. South = 180.
This changes to a fixed tilt simulation where each hour uses
fixed_tilt_angle and azimuth as the tilt and azimuth
Returns
-------
DataFrame with the following columns:
* tracker_theta: The rotation angle of the tracker.
tracker_theta = 0 is horizontal, and positive rotation angles are
clockwise.
tracker_theta = 0 is horizontal, and positive rotation angles
are clockwise.
* aoi: The angle-of-incidence of direct irradiance onto the
rotated panel surface.
* surface_tilt: The angle between the panel surface and the earth
surface, accounting for panel rotation.
* surface_azimuth: The azimuth of the rotated panel, determined by
projecting the vector normal to the panel's surface to the earth's
surface.
* 'theta_round' : tracker_theta rounded to the nearest 'angledelta'.
projecting the vector normal to the panel's surface to the
earth's surface.
* 'theta_round' : tracker_theta rounded to the nearest 'angledelta'
If no angledelta is specified, it is rounded to the nearest degree.
'''
import pvlib
Expand All @@ -4059,22 +4048,18 @@ def _getTrackingAngles(self, axis_azimuth=180, limit_angle=45,
#New as of 0.3.2: pass fixed_tilt_angle and switches to FIXED TILT mode

if fixed_tilt_angle is not None:
if fixed_tilt_azimuth is None:
print("No Azimuth passed for fixed tilt routine in TrackerDict"+
"Setting module surface to South azimuth (180)")
fixed_tilt_azimuth = 180
# fixed tilt system with tilt = fixed_tilt_angle and
# azimuth = axis_azimuth
# azimuth = azimuth

pvsystem = pvlib.pvsystem.PVSystem(arrays=None,
surface_tilt=fixed_tilt_angle,
surface_azimuth=axis_azimuth)
surface_azimuth=azimuth)
# trackingdata keys: 'tracker_theta', 'aoi', 'surface_azimuth', 'surface_tilt'
trackingdata = pd.DataFrame({'tracker_theta':fixed_tilt_angle,
'aoi':pvsystem.get_aoi(
solpos['zenith'],
solpos['azimuth']),
'surface_azimuth':fixed_tilt_azimuth,
'surface_azimuth':azimuth,
'surface_tilt':fixed_tilt_angle})
else:
# get 1-axis tracker tracker_theta, surface_tilt and surface_azimuth
Expand All @@ -4083,7 +4068,7 @@ def _getTrackingAngles(self, axis_azimuth=180, limit_angle=45,
trackingdata = pvlib.tracking.singleaxis(solpos['zenith'],
solpos['azimuth'],
axis_tilt,
axis_azimuth,
azimuth,
limit_angle,
backtrack,
gcr)
Expand Down Expand Up @@ -4585,8 +4570,8 @@ def moduleAnalysis(self, scene, modWanted=None, rowWanted=None,
sensorsy_back=None, sensorsy_front=None,
sensorsx_back=1.0, sensorsx_front=None,
frontsurfaceoffset=0.001, backsurfaceoffset=0.001,
modscanfront=None, modscanback=None, relative=False, debug=False,
sensorsy=None):
modscanfront=None, modscanback=None, relative=False,
debug=False, sensorsy=None):

"""
Handler function that decides how to handle different number of front
Expand Down
13 changes: 7 additions & 6 deletions bifacial_radiance/modelchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,14 @@ def runModelChain(simulationParamsDict, sceneParamsDict, timeControlParamsDict=N
trackerdict = demo.set1axis(metdata,
cumulativesky=simulationParamsDict["cumulativeSky"],
fixed_tilt_angle=sceneParamsDict['tilt'],
fixed_tilt_azimuth=sceneParamsDict['azimuth'])
azimuth=sceneParamsDict['azimuth'])
else:
trackerdict = demo.set1axis(metdata, gcr=sceneParamsDict['gcr'],
limit_angle=trackingParamsDict['limit_angle'],
angledelta=trackingParamsDict['angle_delta'],
backtrack=trackingParamsDict['backtrack'],
cumulativesky=simulationParamsDict["cumulativeSky"])
azimuth=sceneParamsDict['axis_azimuth'],
limit_angle=trackingParamsDict['limit_angle'],
angledelta=trackingParamsDict['angle_delta'],
backtrack=trackingParamsDict['backtrack'],
cumulativesky=simulationParamsDict["cumulativeSky"])



Expand All @@ -168,7 +169,7 @@ def runModelChain(simulationParamsDict, sceneParamsDict, timeControlParamsDict=N
sceneDict=sceneParamsDict,
cumulativesky=simulationParamsDict['cumulativeSky'])

trackerdict = demo.makeOct1axis(trackerdict=trackerdict,)
trackerdict = demo.makeOct1axis(trackerdict=trackerdict)

trackerdict = demo.analysis1axis(trackerdict=trackerdict,
modWanted=analysisParamsDict['modWanted'],
Expand Down
4 changes: 2 additions & 2 deletions tests/test_bifacial_radiance.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,13 @@ def test_RadianceObj_1axis_gendaylit_end_to_end():
demo = bifacial_radiance.RadianceObj(name) # Create a RadianceObj 'object'
demo.setGround(albedo) # input albedo number or material name like 'concrete'. To see options, run this without any input.
metdata = demo.readWeatherFile(MET_FILENAME, starttime='01_01_01_01_00', endtime = '01_01_01_23_00', coerce_year = 2001) # read in the weather data from above
metdata = demo.readWeatherFile(MET_FILENAME, starttime='2001-01-01_0100', endtime = '2001-01-01_2300', coerce_year = 2001) # read in the weather data from above
#metdata = demo.readEPW(MET_FILENAME, starttime='01_01_01', endtime = '01_01_23') # read in the EPW weather data from above
# set module type to be used and passed into makeScene1axis
# test modules with gap and rear tube
moduleDict=demo.makeModule(name='test',x=0.984,y=1.95,torquetube = True, numpanels = 2, ygap = 0.1)
sceneDict = {'pitch': np.round(moduleDict['sceney'] / gcr,3),'height':hub_height, 'nMods':10, 'nRows':3}
key = '01_01_01_11_00'
key = '2001-01-01_1100'
# create metdata files for each condition. keys are timestamps for gendaylit workflow
trackerdict = demo.set1axis(cumulativesky = False, gcr=gcr)
# create the skyfiles needed for 1-axis tracking
Expand Down

0 comments on commit 90d4da2

Please sign in to comment.