Skip to content

Commit

Permalink
Merge pull request #551 from NREL/438_inifile
Browse files Browse the repository at this point in the history
438 inifile change load.py to include more module inputs
  • Loading branch information
cdeline authored Sep 30, 2024
2 parents 9486645 + 8e069ba commit 5e7fae7
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 49 deletions.
92 changes: 66 additions & 26 deletions bifacial_radiance/load.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,8 +477,10 @@ def readconfigurationinputfile(inifile=None):
trackingParamsDict : Dictionary
torquetubeParamsDict : Dictionary
analysisParamsDict : Dictionary
cellLevelModuleParamsDict : Dictionary
cellModuleDict : Dictionary
frameParamsDict : Dictionary
omegaParamsDict : Dictionary
"""

## #TODO: check if modulename exists on jason and rewrite is set to false, then
Expand All @@ -489,13 +491,17 @@ def readconfigurationinputfile(inifile=None):
import ast

def boolConvert(d):
""" convert strings 'True' and 'False' to boolean
""" convert strings 'True' and 'False' to boolean and convert numbers to float
"""
for key,value in d.items():
if value.lower() == 'true':
d[key] = True
elif value.lower() == 'false':
d[key] = False
try:
d[key] = float(value)
except ValueError:
pass
return d

if inifile is None:
Expand All @@ -520,7 +526,7 @@ def boolConvert(d):

if simulationParamsDict['selectTimes']:
if config.has_section("timeControlParamsDict"):
timeControlParamsDict = boolConvert(confdict['timeControlParamsDict'])
timeControlParamsDict = confdict['timeControlParamsDict']

if simulationParamsDict['getEPW']:
try:
Expand Down Expand Up @@ -578,17 +584,22 @@ def boolConvert(d):
except:
moduleParamsDict['zgap'] = 0.1 #Default
print("Load Warning: moduleParamsDict['zgap'] not specified, setting to default value: %s" % moduleParamsDict['zgap'] )

if 'glass' in moduleParamsDict2:
moduleParamsDict['glass'] = moduleParamsDict2['glass']
if moduleParamsDict2.get('glassEdge'):
moduleParamsDict['glassEdge'] = moduleParamsDict2['glassEdge']
if simulationParamsDict['cellLevelModule']:
if config.has_section("cellLevelModuleParamsDict"):
cellLevelModuleParamsDict = confdict['cellLevelModuleParamsDict']
cellModuleDict = confdict['cellLevelModuleParamsDict']
try: # being lazy so just validating the whole dictionary as a whole. #TODO: validate individually maybe.
cellLevelModuleParamsDict['numcellsx'] = int(cellLevelModuleParamsDict['numcellsx'])
cellLevelModuleParamsDict['numcellsy'] = int(cellLevelModuleParamsDict['numcellsy'])
cellLevelModuleParamsDict['xcell'] = round(float(cellLevelModuleParamsDict['xcell']),3)
cellLevelModuleParamsDict['xcellgap'] = round(float(cellLevelModuleParamsDict['xcellgap']),3)
cellLevelModuleParamsDict['ycell'] = round(float(cellLevelModuleParamsDict['ycell']),3)
cellLevelModuleParamsDict['ycellgap'] = round(float(cellLevelModuleParamsDict['ycellgap']),3)
cellModuleDict['numcellsx'] = int(cellModuleDict['numcellsx'])
cellModuleDict['numcellsy'] = int(cellModuleDict['numcellsy'])
cellModuleDict['xcell'] = round(float(cellModuleDict['xcell']),3)
cellModuleDict['xcellgap'] = round(float(cellModuleDict['xcellgap']),3)
cellModuleDict['ycell'] = round(float(cellModuleDict['ycell']),3)
cellModuleDict['ycellgap'] = round(float(cellModuleDict['ycellgap']),3)
if 'centerJB' in cellModuleDict:
cellModuleDict['centerJB'] = round(float(cellModuleDict['centerJB']),3)
except:
print("Load Warning: celllevelModule set to True,",\
"but celllevelModule parameters are missing/not numbers.")
Expand All @@ -603,12 +614,12 @@ def boolConvert(d):
except:
print("Attempted to load x and y instead of celllevelModule parameters,",\
"Failed, so default values for cellLevelModule will be passed")
cellLevelModuleParamsDict['numcellsx'] = 12
cellLevelModuleParamsDict['numcellsy'] = 6
cellLevelModuleParamsDict['xcell'] = 0.15
cellLevelModuleParamsDict['xcellgap'] = 0.1
cellLevelModuleParamsDict['ycell'] = 0.15
cellLevelModuleParamsDict['ycellgap'] = 0.1
cellModuleDict['numcellsx'] = 12
cellModuleDict['numcellsy'] = 6
cellModuleDict['xcell'] = 0.15
cellModuleDict['xcellgap'] = 0.1
cellModuleDict['ycell'] = 0.15
cellModuleDict['ycellgap'] = 0.1
else: # no cellleveldictionary passed
print("Load Warning: celllevelmodule selected, but no dictionary was passed in input file.",\
"attempting to proceed with regular custom module and setting celllevelmodule to false")
Expand Down Expand Up @@ -673,7 +684,14 @@ def boolConvert(d):


if simulationParamsDict['tracking']:
sceneParamsDict['axis_azimuth']=round(float(sceneParamsDict2['axis_azimuth']),2)
if 'axis_aziumth' in sceneParamsDict2:
azimuth = sceneParamsDict2['axis_azimuth']
elif sceneParamsDict2.get('azimuth'):
azimuth = sceneParamsDict2.get('azimuth')
else:
raise Exception(f'Neither "axis_azimuth" or "azimuth" in .inifile {inifile}' )

sceneParamsDict['azimuth']=round(float(azimuth),2)
sceneParamsDict['hub_height']=round(float(sceneParamsDict2['hub_height']),2)

if config.has_section("trackingParamsDict"):
Expand Down Expand Up @@ -743,6 +761,14 @@ def boolConvert(d):
analysisParamsDict['rowWanted'] = None #Default
print("analysisParamsDict['rowWanted'] set to middle row by default" )

if "frameParamsDict" in confdict:
frameParamsDict = boolConvert(confdict['frameParamsDict'])
else:
frameParamsDict = None
if "omegaParamsDict" in confdict:
omegaParamsDict = boolConvert(confdict['omegaParamsDict'])
else:
omegaParamsDict = None
# Creating None dictionaries for those empty ones
try: timeControlParamsDict
except: timeControlParamsDict = None
Expand All @@ -759,15 +785,21 @@ def boolConvert(d):
try: analysisParamsDict
except: analysisParamsDict = None

try: cellLevelModuleParamsDict
except: cellLevelModuleParamsDict = None
try: cellModuleDict
except: cellModuleDict = None

#returnParams = Params(simulationParamsDict, sceneParamsDict, timeControlParamsDict, moduleParamsDict, trackingParamsDict, torquetubeParamsDict, analysisParamsDict, cellLevelModuleParamsDict)
#returnParams = Params(simulationParamsDict, sceneParamsDict, timeControlParamsDict, moduleParamsDict, trackingParamsDict, torquetubeParamsDict, analysisParamsDict, cellModuleDict)
#return returnParams
return simulationParamsDict, sceneParamsDict, timeControlParamsDict, moduleParamsDict, trackingParamsDict, torquetubeParamsDict, analysisParamsDict, cellLevelModuleParamsDict
return (simulationParamsDict, sceneParamsDict, timeControlParamsDict,
moduleParamsDict, trackingParamsDict, torquetubeParamsDict,
analysisParamsDict, cellModuleDict, frameParamsDict, omegaParamsDict)


def savedictionariestoConfigurationIniFile(simulationParamsDict, sceneParamsDict, timeControlParamsDict=None, moduleParamsDict=None, trackingParamsDict=None, torquetubeParamsDict=None, analysisParamsDict=None, cellLevelModuleParamsDict=None, inifilename=None):
def savedictionariestoConfigurationIniFile(simulationParamsDict, sceneParamsDict,
timeControlParamsDict=None, moduleParamsDict=None,
trackingParamsDict=None, torquetubeParamsDict=None,
analysisParamsDict=None, cellModuleDict=None,
frameParamsDict=None, omegaParamsDict=None, inifilename=None):
"""
Saves dictionaries from working memory into a Configuration File
with extension format .ini.
Expand All @@ -786,7 +818,7 @@ def savedictionariestoConfigurationIniFile(simulationParamsDict, sceneParamsDict
Default None
analysisParamsDict
Default None,
cellLevelModuleParamsDict
cellModuleDict
Default None
Returns
Expand Down Expand Up @@ -817,9 +849,17 @@ def savedictionariestoConfigurationIniFile(simulationParamsDict, sceneParamsDict
try: config['analysisParamsDict'] = analysisParamsDict
except: pass

try: config['cellLevelModuleParamsDict'] = cellLevelModuleParamsDict
try: config['cellLevelModuleParamsDict'] = cellModuleDict
except: pass

if frameParamsDict:
try: config['frameParamsDict'] = frameParamsDict
except: pass

if omegaParamsDict:
try: config['omegaParamsDict'] = omegaParamsDict
except: pass

if inifilename is None:
inifilename = 'example.ini'

Expand Down
20 changes: 14 additions & 6 deletions bifacial_radiance/modelchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ def _append_dicts(x, y):

def runModelChain(simulationParamsDict, sceneParamsDict, timeControlParamsDict=None,
moduleParamsDict=None, trackingParamsDict=None, torquetubeParamsDict=None,
analysisParamsDict=None, cellModuleDict=None):
analysisParamsDict=None, cellModuleDict=None, frameParamsDict=None,
omegaParamsDict=None):
"""
This calls config.py values, which are arranged into dictionaries,
and runs all the respective processes based on the variables in the config.py.
Expand Down Expand Up @@ -55,16 +56,19 @@ def runModelChain(simulationParamsDict, sceneParamsDict, timeControlParamsDict=N
demo = bifacial_radiance.RadianceObj(
simulationParamsDict['simulationname'], path=testfolder) # Create a RadianceObj 'object'


# Save INIFILE in folder
inifilename = os.path.join(
simulationParamsDict['testfolder'], 'simulation.ini')
bifacial_radiance.load.savedictionariestoConfigurationIniFile(simulationParamsDict, sceneParamsDict, timeControlParamsDict,
moduleParamsDict, trackingParamsDict, torquetubeParamsDict, analysisParamsDict, cellModuleDict, inifilename)
moduleParamsDict, trackingParamsDict, torquetubeParamsDict,
analysisParamsDict, cellModuleDict, frameParamsDict, omegaParamsDict,
inifilename)

# re-load configuration file to make sure all booleans are converted
(simulationParamsDict, sceneParamsDict, timeControlParamsDict,
moduleParamsDict, trackingParamsDict,torquetubeParamsDict,
analysisParamsDict,cellModuleDict) = \
analysisParamsDict, cellModuleDict, frameParamsDict, omegaParamsDict) = \
bifacial_radiance.load.readconfigurationinputfile(inifilename)

# Load weatherfile
Expand Down Expand Up @@ -121,14 +125,15 @@ def runModelChain(simulationParamsDict, sceneParamsDict, timeControlParamsDict=N

module = demo.makeModule(name=simulationParamsDict['moduletype'],
tubeParams=torquetubeParamsDict,
cellModule=cellModule, **kwargs)
cellModule=cellModule, **kwargs)

print("\nUsing Pre-determined Module Type: %s " %
simulationParamsDict['moduletype'])
else:
module = demo.makeModule(name=simulationParamsDict['moduletype'],
tubeParams=torquetubeParamsDict,
cellModule=cellModule, **kwargs)
cellModule=cellModule, frameParams=frameParamsDict,
omegaParams=omegaParamsDict, **kwargs)


if 'gcr' not in sceneParamsDict: # didn't get gcr passed - need to calculate it
Expand All @@ -152,6 +157,9 @@ def runModelChain(simulationParamsDict, sceneParamsDict, timeControlParamsDict=N

else:
# Run everything through TrackerDict.
# check for deprecated axis_azimuth
if (sceneParamsDict.get('axis_azimuth') is not None) and (sceneParamsDict.get('azimuth') is None):
sceneParamsDict['azimuth'] = sceneParamsDict['axis_azimuth']

if simulationParamsDict['tracking'] == False:
trackerdict = demo.set1axis(metdata,
Expand All @@ -160,7 +168,7 @@ def runModelChain(simulationParamsDict, sceneParamsDict, timeControlParamsDict=N
azimuth=sceneParamsDict['azimuth'])
else:
trackerdict = demo.set1axis(metdata, gcr=sceneParamsDict['gcr'],
azimuth=sceneParamsDict['axis_azimuth'],
azimuth=sceneParamsDict['azimuth'],
limit_angle=trackingParamsDict['limit_angle'],
angledelta=trackingParamsDict['angle_delta'],
backtrack=trackingParamsDict['backtrack'],
Expand Down
11 changes: 7 additions & 4 deletions bifacial_radiance/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,11 @@ def __init__(self, name=None, x=None, y=None, z=None, bifi=1,
except AttributeError:
self.axisofrotationTorqueTube = False
"""

# set data object attributes from datakey list.
for key in self.keys:
setattr(self, key, eval(key))

if tubeParams:
if 'bool' in tubeParams: # backward compatible with pre-0.4
tubeParams['visible'] = tubeParams.pop('bool')
Expand All @@ -165,9 +170,7 @@ def __init__(self, name=None, x=None, y=None, z=None, bifi=1,
f'generated: {self._manual_text}')


# set data object attributes from datakey list.
for key in self.keys:
setattr(self, key, eval(key))


if self.modulefile is None:
self.modulefile = os.path.join('objects',
Expand Down Expand Up @@ -438,7 +441,7 @@ def addOmega(self, omega_material='Metal_Grey', omega_thickness=0.004,
recompile : Bool Rewrite .rad file and module.json file (default True)
"""
self.omega = Omega(self, omega_material=omega_material,
self.omega = Omega(module=self, omega_material=omega_material,
omega_thickness=omega_thickness,
inverted=inverted, x_omega1=x_omega1,
x_omega3=x_omega3, y_omega=y_omega,
Expand Down
11 changes: 8 additions & 3 deletions docs/sphinx/source/whatsnew/pending.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,27 @@ Bugfix Release ...

API Changes
~~~~~~~~~~~~
* New input parameter to :py:class:`~bifacial_radiance.ModuleObj and :py:class:`~bifacial_radiance.RadianceObj.makeModule`: `glassEdge`. If :py:class:`~bifacial_radiance.RadianceObj.makeModule` `glass` = True, then this extends the glass past the absorber edge by this total amount (half in each x and y direction). Default 10mm.
* Module glass thickness can be changed. In :py:class:`~bifacial_radiance.RadianceObj.makeModule`, if `glass` = True, then setting the `z` parameter will indicate the total (front + back) glass thickness with the 1mm absorber in the middle. The default is z = 10mm.
* New input parameter to :py:class:`~bifacial_radiance.ModuleObj and :py:func:`~bifacial_radiance.RadianceObj.makeModule`: `glassEdge`. If :py:class:`~bifacial_radiance.RadianceObj.makeModule` `glass` = True, then this extends the glass past the absorber edge by this total amount (half in each x and y direction). Default 10mm.
* Module glass thickness can be changed. In :py:func:`~bifacial_radiance.RadianceObj.makeModule`, if `glass` = True, then setting the `z` parameter will indicate the total (front + back) glass thickness with the 1mm absorber in the middle. The default is z = 10mm.

Enhancements
~~~~~~~~~~~~
* Conduct an automated check for proper radiance RAYPATH setting (:issue:`525`)(:pull:`537`)


Deprecations
~~~~~~~~~~~~~~
* .ini files loaded with :py:func:`bifacial_radiance.load.readconfigurationinputfile` use `azimuth` key instead of `axis_azimuth` (:issue:`438`)(:pull:`551`)

Bug fixes
~~~~~~~~~
* Fixed a major error with indexing the irradiance conditions with :py:func:`~bifacial_radiance.RadianceObj.gendaylit1axis`. This could result in the trackerdict entry being mismatched from the metdata resource. (:issue:`441`)
* versioning with setuptools_scm- set fallback_version to bifirad v0.4.3 to prevent crashes if git is not present (:issue:`535`)(:pull:`539`)
* :py:func:`bifacial_radiance.load.readconfigurationinputfile` now properly handles loading moduleObj parameters from .ini files: `glass`, `glassEdge`, `frameParamsDict`, `omegaParamsDict` (:pull:`551`)

Documentation
~~~~~~~~~~~~~~
* No longer provide a warning message when both `hub_height` and `clearance_height` are passed to :py:class:`~bifacial_radiance.AnalysisObj.moduleAnalysis` (:pull:`540`)
* No longer provide a warning message when both `hub_height` and `clearance_height` are passed to :py:func:`~bifacial_radiance.AnalysisObj.moduleAnalysis` (:pull:`540`)
* More useful __repr__ output in :py:class:`~bifacial_radiance.AnalysisObj and :py:class:`~bifacial_radiance.MetObj (:issue:`471`)

Contributors
Expand Down
2 changes: 1 addition & 1 deletion tests/ini_1axis.ini
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ albedo = 0.3
nMods = 10
nRows = 3
hub_height = 2.0
axis_azimuth = 180.0
azimuth = 180.0

[timeControlParamsDict]
starttime: 2001-01-01_1100
Expand Down
1 change: 0 additions & 1 deletion tests/ini_cell_level_module.ini
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ azimuth = 180.0
tilt = 10.0
clearance_height = 0.8
hub_height = 0.9
axis_azimuth = 180.0

[timeControlParamsDict]
starttime: 06_21_11_00
Expand Down
15 changes: 8 additions & 7 deletions tests/ini_soltec.ini
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ getEPW: True
simulationname: Demo1
moduletype: Longi
rewriteModule: True
cellLevelModule: False
cellLevelModule: True
axisofrotationTorqueTube: False
torqueTube: True
tracking: True
Expand Down Expand Up @@ -43,10 +43,13 @@ trackerAnglesFile: C:\Users\cdeline\Documents\Python Scripts\Test2.csv
numpanels: 2
x: 0.98
y: 1.980
z: 0.010
bifi: 0.90
xgap: 0.020
ygap: 0.150
zgap: 0.100
glass: True
glassEdge: 0.02

[cellLevelModuleParamsDict]
numcellsx: 12
Expand All @@ -64,7 +67,7 @@ frame_z: 0.02
frame_width: 0.02
nSides_frame: 4

[omegaParams]
[omegaParamsDict]
omega_material: Metal_Grey
x_omega1: 0.05
mod_overlap: 0.04
Expand All @@ -78,13 +81,11 @@ diameter: 0.10
tubetype: Hex

[analysisParamsDict]
fullRow: False
modWanted: 10
rowWanted: 3
sensorsy_back: 9
sensorsy_front: 9
sensorsx_back: 1
sensorsx_front: 1
sensorsy: 9
sensorsx: 1


[Posts]
spacingPost: 6
Expand Down
Loading

0 comments on commit 5e7fae7

Please sign in to comment.