3 - Single Axis Tracking Hourly#

Example demonstrating the use of doing hourly smiulations with Radiance gendaylit for 1-axis tracking. This is a medium level example because it also explores a couple subtopics:

Subtopics: * The structure of the tracker dictionary “trackerDict”. * How to calculate GCR * How to make a cell-level module * Various methods to use the trackerdictionary for analysis.

Doing full year simulations with gendaylit:

Performing the simulation hour by hour requires either a good computer or some patience, since there are ~4000 daylight-hours in the year. With a 32GB RAM, Windows 10 i7-8700 CPU @ 3.2GHz with 6 cores this takes 1 day. The code also allows for multiple cores or HPC use – there is documentation/examples inside the software at the moment, but that is an advanced topic. The procedure can be broken into shorter steps for one day or a single timestamp simulation which is exemplified below.

Steps: 1. Load bifacial_radiance 2. Define all your system variables 3. Create Radiance Object, Set Albedo and Weather 4. Make Module: Cell Level Module Example 5. Calculate GCR 6. Set Tracking Angles 7. Generate the Sky 8. Make Scene 1axis 9. Make Oct and AnalyzE 1 HOUR 10. Make Oct and Analye Range of Hours 11. Make Oct and Analyze All Tracking Dictionary

And finally: Condensed Version: All Tracking Dictionary

1. Load bifacial_radiance#

Pay attention: different importing method:

So far we’ve used “from bifacial_radiance import *” to import all the bifacial_radiance files into our working space in jupyter. For this journal we will do a “import bifacial_radiance” . This method of importing requires a different call for some functions as you’ll see below. For example, instead of calling demo = RadianceObj(path = testfolder) as on Tutorial 2, in this case we will neeed to do demo = bifacial_radiance.RadianceObj(path = testfolder).

[1]:
import bifacial_radiance
import numpy as np
import os # this operative system to do teh relative-path testfolder for this example.
import pprint    # We will be pretty-printing the trackerdictionary throughout to show its structure.
from pathlib import Path

2. Define all your system variables#

Just like in the condensed version show at the end of Tutorial 2, for this tutorial we will be starting all of our system variables from the beginning of the jupyter journal, instead than throughout the different cells (for the most part)

[2]:
testfolder = Path().resolve().parent.parent / 'bifacial_radiance' / 'TEMP' / 'Tutorial_03'
if not os.path.exists(testfolder):
    os.makedirs(testfolder)


simulationName = 'tutorial_03'    # For adding a simulation name when defning RadianceObj. This is optional.
moduletype = 'test-module'    # We will define the parameters for this below in Step 4.
albedo = "litesoil"      # this is one of the options on ground.rad
lat = 37.5
lon = -77.6

# Scene variables
nMods = 20
nRows = 7
hub_height = 2.3 # meters
pitch = 10 # meters      # We will be using pitch instead of GCR for this example.

# Traking parameters
cumulativesky = False
limit_angle = 45 # tracker rotation limit angle
angledelta = 0.01 # we will be doing hourly simulation, we want the angle to be as close to real tracking as possible.
backtrack = True

#makeModule parameters
# x and y will be defined later on Step 4 for this tutorial!!
xgap = 0.01
ygap = 0.10
zgap = 0.05
numpanels = 2
axisofrotation = True  #  the scene will rotate around the torque tube, and not the middle of the bottom surface of the module
diameter = 0.1
tubetype = 'Oct'    # This will make an octagonal torque tube.
material = 'black'   # Torque tube of this material (0% reflectivity)


3. Create Radiance Object, Set Albedo and Weather#

Same steps as previous two tutorials, so condensing it into one step. You hopefully have this down by now! :)

Notice that we are doing bifacial_radiance.RadianceObj because we change the import method for this example!

We now constrain the days of our analysis in the readWeatherFile import step. For this example we are doing just two days in January. Format has to be a ‘MM_DD’ or ‘YYYY-MM-DD_HHMM’

[3]:
demo = bifacial_radiance.RadianceObj(simulationName, path = str(testfolder))  # Adding a simulation name. This is optional.
demo.setGround(albedo)
epwfile = demo.getEPW(lat=lat, lon=lon)

starttime = '01_13';  endtime = '01_14'
metdata = demo.readWeatherFile(weatherFile=epwfile, starttime=starttime, endtime=endtime)

path = C:\Users\sayala\Documents\GitHub\bifacial_radiance\bifacial_radiance\TEMP\Tutorial_03
Making path: images
Making path: objects
Making path: results
Making path: skies
Making path: EPWs
Making path: materials
Loading albedo, 1 value(s), 0.213 avg
1 nonzero albedo values.
Getting weather file: USA_VA_Richmond.724010_TMY2.epw
 ... OK!
8760 line in WeatherFile. Assuming this is a standard hourly WeatherFile for the year for purposes of saving Gencumulativesky temporary weather files in EPW folder.
Coercing year to 2021
Filtering dates
Saving file EPWs\metdata_temp.csv, # points: 8760
Calculating Sun position for Metdata that is right-labeled  with a delta of -30 mins. i.e. 12 is 11:30 sunpos

4. Make Module: Cell Level Module Example#

Instead of doing a opaque, flat single-surface module, in this tutorial we will create a module made up by cells. We can define variuos parameters to make a cell-level module, such as cell size and spacing between cells. To do this, we will pass a dicitonary with the needed parameters to makeModule, as shown below.

NOTE: in v0.4.0 some keywords and methods for doing a CellModule and Torquetube simulation were changed.

Since we are making a cell-level module, the dimensions for x and y of the module will be calculated by the software – dummy values can be initially passed just to get started, but these values are overwritten by addCellModule()

[4]:
numcellsx = 6
numcellsy = 12
xcell = 0.156
ycell = 0.156
xcellgap = 0.02
ycellgap = 0.02


mymodule = demo.makeModule(name=moduletype,  x=1, y=1, xgap=xgap, ygap=ygap,
                           zgap=zgap, numpanels=numpanels)
mymodule.addTorquetube(diameter=diameter, material=material,
                       axisofrotation=axisofrotation, tubetype=tubetype)
mymodule.addCellModule(numcellsx=numcellsx, numcellsy=numcellsy,
                       xcell=xcell, ycell=ycell, xcellgap=xcellgap, ycellgap=ycellgap)

print(f'New module created. x={mymodule.x}m,  y={mymodule.y}m')
print(f'Cell-module parameters: {mymodule.cellModule}')

Module Name: test-module
Module test-module updated in module.json
Module test-module updated in module.json
Pre-existing .rad file objects\test-module.rad will be overwritten

Module was shifted by 0.078 in X to avoid sensors on air
This is a Cell-Level detailed module with Packaging Factor of 0.81 %
Module test-module updated in module.json
Pre-existing .rad file objects\test-module.rad will be overwritten

New module created. x=1.036m,  y=2.092m
Cell-module parameters: {'numcellsx': 6, 'numcellsy': 12, 'xcell': 0.156, 'ycell': 0.156, 'xcellgap': 0.02, 'ycellgap': 0.02, 'centerJB': None}

5. Calculate GCR#

In this example we passed the parameter “pitch”. Pitch is the spacing between rows (for example, between hub-posts) in a field. To calculate Ground Coverage Ratio (GCR), we must relate the pitch to the collector-width by:

GCR = CW / pitch

The collector width for our system must consider the number of panels and the y-gap:

CW

Collector Width gets saved in your module parameters (and later on your scene and trackerdict) as “sceney”. You can calculate your collector width with the equation, or you can use this method to know your GCR:

[5]:
# For more options on makemodule, see the help description of the function.
# Details about the module are stored in the new ModuleObj
CW = mymodule.sceney
gcr = CW / pitch
print ("The GCR is :", gcr)
print(f"\nModuleObj data keys: {mymodule.keys}")
The GCR is : 0.4284

ModuleObj data keys: ['x', 'y', 'z', 'modulematerial', 'scenex', 'sceney', 'scenez', 'numpanels', 'bifi', 'text', 'modulefile', 'glass', 'offsetfromaxis', 'xgap', 'ygap', 'zgap']

6. Set Tracking Angles#

This function will read the weather file, and based on the sun position it will calculate the angle the tracker should be at for each hour. It will create metdata files for each of the tracker angles considered.

For doing hourly simulations, remember to set cumulativesky = False here!

[6]:
trackerdict = demo.set1axis(metdata=metdata, limit_angle=limit_angle, backtrack=backtrack,
                            gcr=gcr, cumulativesky=False)
[7]:
print ("Trackerdict created by set1axis: %s " % (len(demo.trackerdict)))
Trackerdict created by set1axis: 20

set1axis initializes the trackerdictionary Trackerdict. Trackerdict contains all hours selected from the weatherfile as keys. For example: trackerdict[‘2021-01-13_1200’]. It is a return variable on many of the 1axis functions, but it is also stored inside of your Radiance Obj (i.e. demo.trackerdict). In this journal we are storing it as a variable to mute the option (otherwise it prints the returned trackerdict contents every time)

[8]:
pprint.pprint(trackerdict['2021-01-13_1200'])

{'dhi': 200, 'ghi': 249, 'surf_azm': 90.0, 'surf_tilt': 21.2, 'theta': -21.2}

All of the following functions add up elements to trackerdictionary to keep track (ba-dum tupzz) of the Scene and simulation parameters. In advanced journals we will explore the inner structure of trackerdict. For now, just now it exists :)

7. Generate the Sky#

We will create skies for each hour we want to model with the function gendaylit1axis.

For this example we are doing just two days in January. The ability to limit the time using gendaylit1axis is deprecated. Use readWeatherFile instead.

[9]:
trackerdict = demo.gendaylit1axis()
Creating ~20 skyfiles.
Created 19 skyfiles in /skies/

Since we passed startdate and enddate to gendaylit, it will prune our trackerdict to only the desired days. Let’s explore our trackerdict:

[10]:
trackerkeys = sorted(trackerdict.keys())
print ("Trackerdict option of hours are: ", trackerkeys)
print ("")
print ("Contents of trackerdict for sample hour:")
pprint.pprint(trackerdict[trackerkeys[0]])
Trackerdict option of hours are:  ['2021-01-13_0800', '2021-01-13_0900', '2021-01-13_1000', '2021-01-13_1100', '2021-01-13_1200', '2021-01-13_1300', '2021-01-13_1400', '2021-01-13_1500', '2021-01-13_1600', '2021-01-13_1700', '2021-01-14_0800', '2021-01-14_0900', '2021-01-14_1000', '2021-01-14_1100', '2021-01-14_1200', '2021-01-14_1300', '2021-01-14_1400', '2021-01-14_1500', '2021-01-14_1600']

Contents of trackerdict for sample hour:
{'dhi': 22,
 'ghi': 23,
 'skyfile': 'skies\\sky2_37.5_-77.33_2021-01-13_0800.rad',
 'surf_azm': 90.0,
 'surf_tilt': 3.74,
 'theta': -3.74}

8. Make Scene 1axis#

We can use gcr or pitch fo our scene dictionary.

[11]:
sceneDict = {'pitch': pitch,'hub_height':hub_height, 'nMods':nMods, 'nRows': nRows}

# making the different scenes for the 1-axis tracking for the dates in trackerdict2.
trackerdict = demo.makeScene1axis(trackerdict=trackerdict, module=mymodule, sceneDict=sceneDict)

Making ~19 .rad files for gendaylit 1-axis workflow (this takes a minute..)
19 Radfiles created in /objects/

The scene parameteres are now stored in the trackerdict. To view them and to access them:

[12]:
pprint.pprint(trackerdict[trackerkeys[0]])
{'clearance_height': 2.166802445305938,
 'dhi': 22,
 'ghi': 23,
 'radfile': 'objects\\1axis2021-01-13_0800__C_2.16680_rtr_10.00000_tilt_3.74000_20modsx7rows_origin0,0.rad',
 'scene': {'module': {'x': 1.036, 'y': 2.092, 'z': 0.02, 'modulematerial': 'black', 'scenex': 1.046, 'sceney': 4.284, 'scenez': 0.1, 'numpanels': 2, 'bifi': 1, 'text': '! genbox black cellPVmodule 0.156 0.156 0.02 | xform -t -0.44 -2.142 0.1 -a 6 -t 0.176 0 0 -a 12 -t 0 0.176 0 -a 2 -t 0 2.192 0\r\n! genbox black octtube1a 1.046 0.04142135623730951 0.1 | xform -t -0.523 -0.020710678118654756 -0.05\r\n! genbox black octtube1b 1.046 0.04142135623730951 0.1 | xform -t -0.445 -0.020710678118654756 -0.05 -rx 45 -t 0 0 0\r\n! genbox black octtube1c 1.046 0.04142135623730951 0.1 | xform -t -0.445 -0.020710678118654756 -0.05 -rx 90 -t 0 0 0\r\n! genbox black octtube1d 1.046 0.04142135623730951 0.1 | xform -t -0.445 -0.020710678118654756 -0.05 -rx 135 -t 0 0 0 ', 'modulefile': 'objects\\test-module.rad', 'glass': False, 'offsetfromaxis': 0.1, 'xgap': 0.01, 'ygap': 0.1, 'zgap': 0.05}, 'modulefile': 'objects\\test-module.rad', 'hpc': False, 'gcr': 0.4284, 'text': '!xform -rx 3.74 -t 0 0 2.3 -a 20 -t 1.046 0 0 -a 7 -t 0 10 0 -i 1 -t -9.414 -30.0 0 -rz 90.0 -t 0 0 0 objects\\test-module.rad', 'radfiles': 'objects\\1axis2021-01-13_0800__C_2.16680_rtr_10.00000_tilt_3.74000_20modsx7rows_origin0,0.rad', 'sceneDict': {'tilt': 3.74, 'pitch': 10, 'clearance_height': 2.166802445305938, 'azimuth': 90.0, 'nMods': 20, 'nRows': 7, 'modulez': 0.02, 'axis_tilt': 0, 'originx': 0, 'originy': 0}},
 'skyfile': 'skies\\sky2_37.5_-77.33_2021-01-13_0800.rad',
 'surf_azm': 90.0,
 'surf_tilt': 3.74,
 'theta': -3.74}
[13]:
pprint.pprint(demo.trackerdict[trackerkeys[5]]['scene'].__dict__)
{'gcr': 0.4284,
 'hpc': False,
 'module': {'x': 1.036, 'y': 2.092, 'z': 0.02, 'modulematerial': 'black', 'scenex': 1.046, 'sceney': 4.284, 'scenez': 0.1, 'numpanels': 2, 'bifi': 1, 'text': '! genbox black cellPVmodule 0.156 0.156 0.02 | xform -t -0.44 -2.142 0.1 -a 6 -t 0.176 0 0 -a 12 -t 0 0.176 0 -a 2 -t 0 2.192 0\r\n! genbox black octtube1a 1.046 0.04142135623730951 0.1 | xform -t -0.523 -0.020710678118654756 -0.05\r\n! genbox black octtube1b 1.046 0.04142135623730951 0.1 | xform -t -0.445 -0.020710678118654756 -0.05 -rx 45 -t 0 0 0\r\n! genbox black octtube1c 1.046 0.04142135623730951 0.1 | xform -t -0.445 -0.020710678118654756 -0.05 -rx 90 -t 0 0 0\r\n! genbox black octtube1d 1.046 0.04142135623730951 0.1 | xform -t -0.445 -0.020710678118654756 -0.05 -rx 135 -t 0 0 0 ', 'modulefile': 'objects\\test-module.rad', 'glass': False, 'offsetfromaxis': 0.1, 'xgap': 0.01, 'ygap': 0.1, 'zgap': 0.05},
 'modulefile': 'objects\\test-module.rad',
 'radfiles': 'objects\\1axis2021-01-13_1300__C_2.11102_rtr_10.00000_tilt_-5.31000_20modsx7rows_origin0,0.rad',
 'sceneDict': {'axis_tilt': 0,
               'azimuth': 90.0,
               'clearance_height': 2.111024390776987,
               'modulez': 0.02,
               'nMods': 20,
               'nRows': 7,
               'originx': 0,
               'originy': 0,
               'pitch': 10,
               'tilt': -5.31},
 'text': '!xform -rx -5.31 -t 0 0 2.3 -a 20 -t 1.046 0 0 -a 7 -t 0 10 0 -i 1 '
         '-t -9.414 -30.0 0 -rz 90.0 -t 0 0 0 objects\\test-module.rad'}

9. Make Oct and Analyze#

A. Make Oct and Analyze 1Hour#

There are various options now to analyze the trackerdict hours we have defined. We will start by doing just one hour, because it’s the fastest. Make sure to select an hour that exists in your trackerdict!

Options of hours:

[14]:
pprint.pprint(trackerkeys)
['2021-01-13_0800',
 '2021-01-13_0900',
 '2021-01-13_1000',
 '2021-01-13_1100',
 '2021-01-13_1200',
 '2021-01-13_1300',
 '2021-01-13_1400',
 '2021-01-13_1500',
 '2021-01-13_1600',
 '2021-01-13_1700',
 '2021-01-14_0800',
 '2021-01-14_0900',
 '2021-01-14_1000',
 '2021-01-14_1100',
 '2021-01-14_1200',
 '2021-01-14_1300',
 '2021-01-14_1400',
 '2021-01-14_1500',
 '2021-01-14_1600']
[15]:
demo.makeOct1axis(singleindex='2021-01-13_0800')
results = demo.analysis1axis(singleindex='2021-01-13_0800')
print('\n\nHourly bifi gain: {:0.3}'.format(sum(demo.Wm2Back) / sum(demo.Wm2Front)))

Making 1 octfiles in root directory.
Created 1axis_2021-01-13_0800.oct
Linescan in process: 1axis_2021-01-13_0800_Front
Linescan in process: 1axis_2021-01-13_0800_Back
Saved: results\irr_1axis_2021-01-13_0800.csv
Index: 2021-01-13_0800. Wm2Front: 23.57971333333333. Wm2Back: 2.8340437777777776


Hourly bifi gain: 0.12

The trackerdict now contains information about the octfile, as well as the Analysis Object results

[16]:
print ("\n Contents of trackerdict for sample hour after analysis1axis: ")
pprint.pprint(trackerdict[trackerkeys[0]])


 Contents of trackerdict for sample hour after analysis1axis:
{'AnalysisObj': {'octfile': '1axis_2021-01-13_0800.oct', 'name': '1axis_2021-01-13_0800', 'hpc': False, 'x': [1.717843, 1.290356, 0.862868, 0.4353804, 0.007892705, -0.4195949, -0.8470826, -1.27457, -1.702058], 'y': [1.051876e-16, 7.90115e-17, 5.283543e-17, 2.665936e-17, 4.832888e-19, -2.569278e-17, -5.186885e-17, -7.804492e-17, -1.04221e-16], 'z': [2.308966, 2.33691, 2.364854, 2.392798, 2.420742, 2.448686, 2.47663, 2.504575, 2.532519], 'rearZ': [2.287013, 2.314957, 2.342901, 2.370845, 2.398789, 2.426733, 2.454677, 2.482621, 2.510566], 'mattype': ['a9.3.a2.2.0.cellPVmodule.6457', 'a9.3.a2.4.0.cellPVmodule.6457', 'a9.3.a2.7.0.cellPVmodule.6457', 'a9.3.a2.9.0.cellPVmodule.6457', 'a9.3.octtube1a.6457', 'a9.3.a2.2.1.cellPVmodule.6457', 'a9.3.a2.4.1.cellPVmodule.6457', 'a9.3.a2.7.1.cellPVmodule.6457', 'a9.3.a2.9.1.cellPVmodule.6457'], 'rearMat': ['a9.3.a2.2.0.cellPVmodule.2310', 'a9.3.a2.4.0.cellPVmodule.2310', 'a9.3.a2.7.0.cellPVmodule.2310', 'a9.3.a2.9.0.cellPVmodule.2310', 'sky', 'a9.3.a2.2.1.cellPVmodule.2310', 'a9.3.a2.4.1.cellPVmodule.2310', 'a9.3.a2.7.1.cellPVmodule.2310', 'a9.3.a2.9.1.cellPVmodule.2310'], 'Wm2Front': [23.725776666666665, 23.73493666666667, 23.743613333333332, 23.761876666666666, 22.463893333333335, 23.74101333333333, 23.68344, 23.68229, 23.680580000000003], 'Wm2Back': [2.9397776666666666, 2.89124, 2.837168333333333, 2.7395723333333333, 2.990579, 2.6973613333333333, 2.7764156666666664, 2.804555, 2.829724666666667], 'Back/FrontRatio': [0.12390126598176772, 0.12180854880946343, 0.11948681974746833, 0.11528790776313137, 0.1331223325045834, 0.11361131406435063, 0.11722530347631889, 0.11841914700195792, 0.1194905351191376], 'backRatio': [0.12390126598176772, 0.12180854880946343, 0.11948681974746833, 0.11528790776313137, 0.1331223325045834, 0.11361131406435063, 0.11722530347631889, 0.11841914700195792, 0.1194905351191376], 'rearX': [1.716408, 1.288921, 0.861433, 0.4339453, 0.006457668, -0.42103, -0.8485176, -1.276005, -1.703493], 'rearY': [1.050997e-16, 7.892362e-17, 5.274756e-17, 2.657149e-17, 3.954181e-19, -2.578065e-17, -5.195672e-17, -7.813279e-17, -1.043089e-16]},
 'Wm2Back': [2.9397776666666666,
             2.89124,
             2.837168333333333,
             2.7395723333333333,
             2.990579,
             2.6973613333333333,
             2.7764156666666664,
             2.804555,
             2.829724666666667],
 'Wm2Front': [23.725776666666665,
              23.73493666666667,
              23.743613333333332,
              23.761876666666666,
              22.463893333333335,
              23.74101333333333,
              23.68344,
              23.68229,
              23.680580000000003],
 'backRatio': [0.12390126598176772,
               0.12180854880946343,
               0.11948681974746833,
               0.11528790776313137,
               0.1331223325045834,
               0.11361131406435063,
               0.11722530347631889,
               0.11841914700195792,
               0.1194905351191376],
 'clearance_height': 2.166802445305938,
 'dhi': 22,
 'ghi': 23,
 'octfile': '1axis_2021-01-13_0800.oct',
 'radfile': 'objects\\1axis2021-01-13_0800__C_2.16680_rtr_10.00000_tilt_3.74000_20modsx7rows_origin0,0.rad',
 'scene': {'module': {'x': 1.036, 'y': 2.092, 'z': 0.02, 'modulematerial': 'black', 'scenex': 1.046, 'sceney': 4.284, 'scenez': 0.1, 'numpanels': 2, 'bifi': 1, 'text': '! genbox black cellPVmodule 0.156 0.156 0.02 | xform -t -0.44 -2.142 0.1 -a 6 -t 0.176 0 0 -a 12 -t 0 0.176 0 -a 2 -t 0 2.192 0\r\n! genbox black octtube1a 1.046 0.04142135623730951 0.1 | xform -t -0.523 -0.020710678118654756 -0.05\r\n! genbox black octtube1b 1.046 0.04142135623730951 0.1 | xform -t -0.445 -0.020710678118654756 -0.05 -rx 45 -t 0 0 0\r\n! genbox black octtube1c 1.046 0.04142135623730951 0.1 | xform -t -0.445 -0.020710678118654756 -0.05 -rx 90 -t 0 0 0\r\n! genbox black octtube1d 1.046 0.04142135623730951 0.1 | xform -t -0.445 -0.020710678118654756 -0.05 -rx 135 -t 0 0 0 ', 'modulefile': 'objects\\test-module.rad', 'glass': False, 'offsetfromaxis': 0.1, 'xgap': 0.01, 'ygap': 0.1, 'zgap': 0.05}, 'modulefile': 'objects\\test-module.rad', 'hpc': False, 'gcr': 0.4284, 'text': '!xform -rx 3.74 -t 0 0 2.3 -a 20 -t 1.046 0 0 -a 7 -t 0 10 0 -i 1 -t -9.414 -30.0 0 -rz 90.0 -t 0 0 0 objects\\test-module.rad', 'radfiles': 'objects\\1axis2021-01-13_0800__C_2.16680_rtr_10.00000_tilt_3.74000_20modsx7rows_origin0,0.rad', 'sceneDict': {'tilt': 3.74, 'pitch': 10, 'clearance_height': 2.166802445305938, 'azimuth': 90.0, 'nMods': 20, 'nRows': 7, 'modulez': 0.02, 'axis_tilt': 0, 'originx': 0, 'originy': 0}},
 'skyfile': 'skies\\sky2_37.5_-77.33_2021-01-13_0800.rad',
 'surf_azm': 90.0,
 'surf_tilt': 3.74,
 'theta': -3.74}
[17]:
pprint.pprint(trackerdict[trackerkeys[0]]['AnalysisObj'].__dict__)
{'Back/FrontRatio': [0.12390126598176772,
                     0.12180854880946343,
                     0.11948681974746833,
                     0.11528790776313137,
                     0.1331223325045834,
                     0.11361131406435063,
                     0.11722530347631889,
                     0.11841914700195792,
                     0.1194905351191376],
 'Wm2Back': [2.9397776666666666,
             2.89124,
             2.837168333333333,
             2.7395723333333333,
             2.990579,
             2.6973613333333333,
             2.7764156666666664,
             2.804555,
             2.829724666666667],
 'Wm2Front': [23.725776666666665,
              23.73493666666667,
              23.743613333333332,
              23.761876666666666,
              22.463893333333335,
              23.74101333333333,
              23.68344,
              23.68229,
              23.680580000000003],
 'backRatio': [0.12390126598176772,
               0.12180854880946343,
               0.11948681974746833,
               0.11528790776313137,
               0.1331223325045834,
               0.11361131406435063,
               0.11722530347631889,
               0.11841914700195792,
               0.1194905351191376],
 'hpc': False,
 'mattype': ['a9.3.a2.2.0.cellPVmodule.6457',
             'a9.3.a2.4.0.cellPVmodule.6457',
             'a9.3.a2.7.0.cellPVmodule.6457',
             'a9.3.a2.9.0.cellPVmodule.6457',
             'a9.3.octtube1a.6457',
             'a9.3.a2.2.1.cellPVmodule.6457',
             'a9.3.a2.4.1.cellPVmodule.6457',
             'a9.3.a2.7.1.cellPVmodule.6457',
             'a9.3.a2.9.1.cellPVmodule.6457'],
 'name': '1axis_2021-01-13_0800',
 'octfile': '1axis_2021-01-13_0800.oct',
 'rearMat': ['a9.3.a2.2.0.cellPVmodule.2310',
             'a9.3.a2.4.0.cellPVmodule.2310',
             'a9.3.a2.7.0.cellPVmodule.2310',
             'a9.3.a2.9.0.cellPVmodule.2310',
             'sky',
             'a9.3.a2.2.1.cellPVmodule.2310',
             'a9.3.a2.4.1.cellPVmodule.2310',
             'a9.3.a2.7.1.cellPVmodule.2310',
             'a9.3.a2.9.1.cellPVmodule.2310'],
 'rearX': [1.716408,
           1.288921,
           0.861433,
           0.4339453,
           0.006457668,
           -0.42103,
           -0.8485176,
           -1.276005,
           -1.703493],
 'rearY': [1.050997e-16,
           7.892362e-17,
           5.274756e-17,
           2.657149e-17,
           3.954181e-19,
           -2.578065e-17,
           -5.195672e-17,
           -7.813279e-17,
           -1.043089e-16],
 'rearZ': [2.287013,
           2.314957,
           2.342901,
           2.370845,
           2.398789,
           2.426733,
           2.454677,
           2.482621,
           2.510566],
 'x': [1.717843,
       1.290356,
       0.862868,
       0.4353804,
       0.007892705,
       -0.4195949,
       -0.8470826,
       -1.27457,
       -1.702058],
 'y': [1.051876e-16,
       7.90115e-17,
       5.283543e-17,
       2.665936e-17,
       4.832888e-19,
       -2.569278e-17,
       -5.186885e-17,
       -7.804492e-17,
       -1.04221e-16],
 'z': [2.308966,
       2.33691,
       2.364854,
       2.392798,
       2.420742,
       2.448686,
       2.47663,
       2.504575,
       2.532519]}

B. Make Oct and Analye Range of Hours#

You could do a list of indices following a similar procedure:

[18]:
for time in ['2021-01-13_0900','2021-01-13_1300']:
    demo.makeOct1axis(singleindex=time)
    results=demo.analysis1axis(singleindex=time)

print('Accumulated hourly bifi gain: {:0.3}'.format(sum(demo.Wm2Back) / sum(demo.Wm2Front)))

Making 1 octfiles in root directory.
Created 1axis_2021-01-13_0900.oct
Linescan in process: 1axis_2021-01-13_0900_Front
Linescan in process: 1axis_2021-01-13_0900_Back
Saved: results\irr_1axis_2021-01-13_0900.csv
Index: 2021-01-13_0900. Wm2Front: 94.6692262962963. Wm2Back: 7.361564111111111

Making 1 octfiles in root directory.
Created 1axis_2021-01-13_1300.oct
Linescan in process: 1axis_2021-01-13_1300_Front
Linescan in process: 1axis_2021-01-13_1300_Back
Saved: results\irr_1axis_2021-01-13_1300.csv
Index: 2021-01-13_1300. Wm2Front: 218.49475185185187. Wm2Back: 31.17798148148148
Accumulated hourly bifi gain: 0.123

Note that the bifacial gain printed above is for the accumulated irradiance between the hours modeled so far. That is, demo.Wm2Back and demo.Wm2Front are for January 13, 8AM, 9AM and 1 PM. Compare demo.Wm2back below with what we had before:

[19]:
demo.Wm2Back
[19]:
array([38.12009667, 36.835678  , 35.30221533, 33.89088167, 84.072514  ,
       34.04756533, 35.405451  , 36.69546633, 37.992436  ])

To print the specific bifacial gain for a specific hour, you can use the following:

[20]:
sum(trackerdict['2021-01-13_1300']['AnalysisObj'].Wm2Back) / sum(trackerdict['2021-01-13_1300']['AnalysisObj'].Wm2Front)
[20]:
0.14269441813696923

C. Make Oct and Analyze All Tracking Dictionary#

This takes considerably more time, depending on the number of entries on the trackerdictionary. If no starttime and endtime were specified on STEP readWeatherFile, this will run ALL of the hours in the year (~4000 hours).

[ ]:
demo.makeOct1axis()
results = demo.analysis1axis()
print('Accumulated hourly bifi gain for all the trackerdict: {:0.3}'.format(sum(demo.Wm2Back) / sum(demo.Wm2Front)))


Making 19 octfiles in root directory.
Created 1axis_2021-01-13_0800.oct
Created 1axis_2021-01-13_0900.oct
Created 1axis_2021-01-13_1000.oct
Created 1axis_2021-01-13_1100.oct
Created 1axis_2021-01-13_1200.oct
Created 1axis_2021-01-13_1300.oct
Created 1axis_2021-01-13_1400.oct
Created 1axis_2021-01-13_1500.oct
Created 1axis_2021-01-13_1600.oct

Remember you should clean your results first! This will have torquetube and sky results if performed this way so don’t trust this simplistic bifacial_gain examples.

Condensed Version: All Tracking Dictionary#

This is the summarized version to run gendaylit for each entry in the trackingdictionary.

[ ]:
import bifacial_radiance
import os

simulationName = 'Tutorial 3'
moduletype = 'Custom Cell-Level Module'
testfolder = os.path.abspath(r'..\..\bifacial_radiance\TEMP')
albedo = "litesoil"
lat = 37.5
lon = -77.6

# Scene variables
nMods = 20
nRows = 7
hub_height = 2.3 # meters
pitch = 10 # meters

# Traking parameters
cumulativesky = False
limit_angle = 45 # degrees
angledelta = 0.01 #
backtrack = True

#makeModule parameters
# x and y will do not need to be defined as they are calculated internally for cell-level modules
xgap = 0.01
ygap = 0.10
zgap = 0.05
numpanels = 2

cellModuleParams = {'numcellsx': 6,
'numcellsy': 12,
'xcell': 0.156,
'ycell': 0.156,
'xcellgap': 0.02,
'ycellgap': 0.02}



torquetube = True
axisofrotation = True  # the scene will rotate around the torque tube, and not the middle of the bottom surface of the module
diameter = 0.1
tubetype = 'Oct'    # This will make an octagonal torque tube.
material = 'black'   # Torque tube material (0% reflectivity)
tubeParams = {'diameter':diameter,
              'tubetype':tubetype,
              'material':material,
              'axisofrotation':axisofrotation}

startdate = '11_06'
enddate = '11_06'
demo = bifacial_radiance.RadianceObj(simulationName, path=testfolder)
demo.setGround(albedo)
epwfile = demo.getEPW(lat,lon)
metdata = demo.readWeatherFile(epwfile, starttime=startdate, endtime=enddate)
mymodule = bifacial_radiance.ModuleObj(name=moduletype, xgap=xgap, ygap=ygap,
                zgap=zgap, numpanels=numpanels,cellModule=cellModuleParams, tubeParams=tubeParams)
sceneDict = {'pitch':pitch,'hub_height':hub_height, 'nMods': nMods, 'nRows': nRows}
demo.set1axis(limit_angle = limit_angle, backtrack = backtrack, gcr = gcr, cumulativesky = cumulativesky)
demo.gendaylit1axis()
demo.makeScene1axis(module=mymodule,sceneDict=sceneDict) #makeScene creates a .rad file with 20 modules per row, 7 rows.
demo.makeOct1axis()
demo.analysis1axis()