Skip to content

Commit bcab0bf

Browse files
authored
Merge pull request #565 from NREL/v0_4_4_Release
V0 4 4 release
2 parents 0b1c9d4 + f341da2 commit bcab0bf

26 files changed

+401
-336
lines changed

.github/workflows/deploy.yaml

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ jobs:
1010
runs-on: ubuntu-latest
1111

1212
steps:
13-
- uses: actions/checkout@v2
13+
- uses: actions/checkout@v4
1414
- name: Set up Python
15-
uses: actions/setup-python@v2
15+
uses: actions/setup-python@v5
1616
with:
17-
python-version: '3.7'
17+
python-version: '3.10'
1818
- name: Install dependencies
1919
run: |
2020
python -m pip install --upgrade pip
@@ -26,7 +26,7 @@ jobs:
2626
run: |
2727
python setup.py sdist bdist_wheel
2828
twine upload dist/*
29-
- uses: actions/upload-artifact@v2
29+
- uses: actions/upload-artifact@v4
3030
with:
3131
name: dist
3232
path: |

.github/workflows/pytest.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ jobs:
1818
'-r requirements.txt .[all]',
1919
'--upgrade --upgrade-strategy=eager .[all]'
2020
]
21+
include:
22+
- python-version: "3.12"
23+
env: '--upgrade --upgrade-strategy=eager .[all]'
24+
2125

2226
steps:
2327
- uses: actions/checkout@v4

bifacial_radiance/gui.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,11 @@ def save_inputfile(savetitle=None):
371371
if savetitle is None:
372372
savetitle = inputvariablefile
373373

374-
bifacial_radiance.load.savedictionariestoConfigurationIniFile(simulationParamsDict, sceneParamsDict, timeControlParamsDict, moduleParamsDict, trackingParamsDict, torquetubeParamsDict, analysisParamsDict, cellModuleDict, inifilename=savetitle)
374+
bifacial_radiance.load.savedictionariestoConfigurationIniFile(simulationParamsDict, sceneParamsDict,
375+
timeControlParamsDict, moduleParamsDict,
376+
trackingParamsDict, torquetubeParamsDict,
377+
analysisParamsDict, cellModuleDict,
378+
inifilename=savetitle)
375379
print("Saved all Values to %s " % savetitle)
376380

377381

bifacial_radiance/load.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -660,8 +660,8 @@ def boolConvert(d):
660660
else:
661661
print("Load Warning: no valid time to restrict weather data passed"
662662
"Simulating default day 06/21 at noon")
663-
timeControlParamsDict['starttime']='06_21_12_00'
664-
timeControlParamsDict['endtime']='06_21_12_00'
663+
timeControlParamsDict['starttime']='06_21_12'
664+
timeControlParamsDict['endtime']='06_21_12'
665665

666666
#NEEDED sceneParamsDict parameters
667667
sceneParamsDict={}
@@ -751,11 +751,11 @@ def boolConvert(d):
751751
if config.has_section("analysisParamsDict"):
752752
analysisParamsDict = boolConvert(confdict['analysisParamsDict'])
753753
try:
754-
analysisParamsDict['sensorsy']=ast.literal_eval(analysisParamsDict['sensorsy'])
755-
except:
754+
analysisParamsDict['sensorsy']=ast.literal_eval(str(analysisParamsDict['sensorsy']))
755+
except ValueError:
756+
print("Load Warning: improper analysisParamsDict['sensorsy']"
757+
" passed: %s, setting to default value: 9" % analysisParamsDict['sensorsy'] )
756758
analysisParamsDict['sensorsy'] = 9 #Default
757-
print("Load Warning: improper or no analysisParamsDict['sensorsy']"
758-
" passed, setting to default value: %s" % analysisParamsDict['sensorsy'] )
759759
try:
760760
analysisParamsDict['modWanted']=int(analysisParamsDict['modWanted'])
761761
except:
@@ -794,13 +794,13 @@ def boolConvert(d):
794794
try: cellModuleDict
795795
except: cellModuleDict = None
796796

797-
#returnParams = Params(simulationParamsDict, sceneParamsDict, timeControlParamsDict, moduleParamsDict, trackingParamsDict, torquetubeParamsDict, analysisParamsDict, cellModuleDict)
798-
#return returnParams
797+
# end readconfigurationinputfile
799798
return (simulationParamsDict, sceneParamsDict, timeControlParamsDict,
800799
moduleParamsDict, trackingParamsDict, torquetubeParamsDict,
801800
analysisParamsDict, cellModuleDict, frameParamsDict, omegaParamsDict)
802801

803802

803+
804804
def savedictionariestoConfigurationIniFile(simulationParamsDict, sceneParamsDict,
805805
timeControlParamsDict=None, moduleParamsDict=None,
806806
trackingParamsDict=None, torquetubeParamsDict=None,

bifacial_radiance/main.py

+28-15
Original file line numberDiff line numberDiff line change
@@ -283,8 +283,8 @@ def _subhourlydatatoGencumskyformat(gencumskydata, label='right'):
283283
tzinfo = gencumskydata.index.tzinfo
284284
padstart = pd.to_datetime('%s-%s-%s %s:%s' % (gencumskydata.index.year[0],1,1,1,0 ) ).tz_localize(tzinfo)
285285
padend = pd.to_datetime('%s-%s-%s %s:%s' % (gencumskydata.index.year[0]+1,1,1,0,0) ).tz_localize(tzinfo)
286-
gencumskydata.iloc[0] = 0 # set first datapt to zero to forward fill w zeros
287-
gencumskydata.iloc[-1] = 0 # set last datapt to zero to forward fill w zeros
286+
#gencumskydata.iloc[0] = 0 # set first datapt to zero to forward fill w zeros
287+
#gencumskydata.iloc[-1] = 0 # set last datapt to zero to forward fill w zeros
288288
# check if index exists. I'm sure there is a way to do this backwards.
289289
if any(gencumskydata.index.isin([padstart])):
290290
print("Data starts on Jan. 01")
@@ -2747,8 +2747,8 @@ def __init__(self, materialOrAlbedo=None, material_file=None, silent=False):
27472747
f'{self._nonzeromean(self.ReflAvg):0.3f} avg\n'
27482748
f'{self.ReflAvg[self.ReflAvg != 0].__len__()} nonzero albedo values.')
27492749
except IndexError as e:
2750-
print('albedo.shape should be 3 column (N x 3)')
2751-
raise e
2750+
raise Exception('albedo.shape needs to be 3 column (N x 3)')
2751+
27522752

27532753
def printGroundMaterials(self, materialString=None):
27542754
"""
@@ -3529,7 +3529,7 @@ def _getTrackingAngles(self, azimuth=180, limit_angle=45,
35293529
def _roundArbitrary(x, base=angledelta):
35303530
# round to nearest 'base' value.
35313531
# mask NaN's to avoid rounding error message
3532-
return base * (x/float(base)).round()
3532+
return base * (x/float(base)).round() + 0 #remove negative zeros
35333533

35343534
if angledelta == 0:
35353535
raise ZeroDivisionError('Angledelta = 0. Use None instead')
@@ -4151,11 +4151,12 @@ def _checkSensors(sensors):
41514151
else:
41524152
print ("Module's z not set on sceneDict internal dictionary. Setting to default")
41534153
modulez = 0.02
4154-
4155-
if frontsurfaceoffset is None:
4156-
frontsurfaceoffset = 0.001
4157-
if backsurfaceoffset is None:
4158-
backsurfaceoffset = 0.001
4154+
4155+
# cdeline 20241014 remove this check - extraneous
4156+
#if frontsurfaceoffset is None:
4157+
# frontsurfaceoffset = 0.001
4158+
#if backsurfaceoffset is None:
4159+
# backsurfaceoffset = 0.001
41594160

41604161
# The Sensor routine below needs a "hub-height", not a clearance height.
41614162
# The below complicated check checks to see if height (deprecated) is passed,
@@ -4228,7 +4229,7 @@ def _checkSensors(sensors):
42284229

42294230
xstartfront = x1 + x2 + x3 + originx
42304231
xstartback = x1 + x2 + x4 + originx
4231-
4232+
42324233
ystartfront = y1 + y2 + y3 + originy
42334234
ystartback = y1 + y2 + y4 + originy
42344235

@@ -4291,10 +4292,22 @@ def _checkSensors(sensors):
42914292

42924293
firstsensorxstartfront = xstartfront+xinc_front
42934294
firstsensorxstartback = xstartback+xinc_back
4294-
firstsensorystartfront = ystartfront+yinc_front
4295-
firstsensorystartback = ystartback+yinc_back
4296-
firstsensorzstartfront = zstartfront + zinc_front
4297-
firstsensorzstartback = zstartback + zinc_back
4295+
# check to make sure sensorsy don't line up with gaps in between cellModule
4296+
if ((getattr(scene.module, 'cellModule', None)) and
4297+
(sensorsy_front == scene.module.cellModule.numcellsy-1)):
4298+
firstsensorystartfront = ystartfront+yinc_front/2
4299+
firstsensorzstartfront = zstartfront + zinc_front/2
4300+
else:
4301+
firstsensorystartfront = ystartfront+yinc_front
4302+
firstsensorzstartfront = zstartfront + zinc_front
4303+
if ((getattr(scene.module, 'cellModule', None)) and
4304+
(sensorsy_back == scene.module.cellModule.numcellsy-1)):
4305+
firstsensorystartback = ystartback+yinc_back/2
4306+
firstsensorzstartback = zstartback + zinc_back/2
4307+
else:
4308+
firstsensorystartback = ystartback+yinc_back
4309+
firstsensorzstartback = zstartback + zinc_back
4310+
42984311

42994312
## Correct positions for sensorsx other than 1
43004313
# TODO: At some point, this equations can include the case where

bifacial_radiance/modelchain.py

+8-11
Original file line numberDiff line numberDiff line change
@@ -113,20 +113,17 @@ def runModelChain(simulationParamsDict, sceneParamsDict, timeControlParamsDict=N
113113
'axisofrotationTorqueTube']
114114
"""
115115
kwargs = moduleParamsDict
116+
kwargs['rewriteModulefile'] = simulationParamsDict['rewriteModule']
116117
if torquetubeParamsDict:
117118
if not 'visible' in torquetubeParamsDict:
118119
torquetubeParamsDict['visible'] = simulationParamsDict['torqueTube']
119120
if 'axisofrotationTorqueTube' in simulationParamsDict:
120121
torquetubeParamsDict['axisofrotation'] = simulationParamsDict[
121122
'axisofrotationTorqueTube']
122123

123-
if simulationParamsDict['moduletype'] in A:
124-
if simulationParamsDict['rewriteModule'] is True:
125-
126-
module = demo.makeModule(name=simulationParamsDict['moduletype'],
127-
tubeParams=torquetubeParamsDict,
128-
cellModule=cellModule, **kwargs)
124+
if (simulationParamsDict['moduletype'] in A) and not (kwargs['rewriteModulefile']):
129125

126+
module = simulationParamsDict['moduletype']
130127
print("\nUsing Pre-determined Module Type: %s " %
131128
simulationParamsDict['moduletype'])
132129
else:
@@ -142,14 +139,14 @@ def runModelChain(simulationParamsDict, sceneParamsDict, timeControlParamsDict=N
142139

143140
if simulationParamsDict['tracking'] == False and simulationParamsDict['cumulativeSky'] == True:
144141
# Fixed gencumsky condition
145-
scene = demo.makeScene(module=simulationParamsDict['moduletype'],
142+
scene = demo.makeScene(module=module,
146143
sceneDict=sceneParamsDict)
147144
demo.genCumSky(demo.gencumsky_metfile)
148145
octfile = demo.makeOct(demo.getfilelist())
149146
analysis = bifacial_radiance.AnalysisObj(octfile, demo.name)
150-
frontscan, backscan = analysis.moduleAnalysis(scene, analysisParamsDict['modWanted'],
151-
analysisParamsDict['rowWanted'],
152-
analysisParamsDict['sensorsy'])
147+
frontscan, backscan = analysis.moduleAnalysis(scene, modWanted=analysisParamsDict['modWanted'],
148+
rowWanted=analysisParamsDict['rowWanted'],
149+
sensorsy=analysisParamsDict['sensorsy'])
153150
analysis.analysis(octfile, demo.name, frontscan, backscan)
154151
print('Bifacial ratio yearly average: %0.3f' %
155152
(np.mean(analysis.Wm2Back) / np.mean(analysis.Wm2Front)))
@@ -182,7 +179,7 @@ def runModelChain(simulationParamsDict, sceneParamsDict, timeControlParamsDict=N
182179
trackerdict = demo.gendaylit1axis()
183180

184181
trackerdict = demo.makeScene1axis(trackerdict=trackerdict,
185-
module=simulationParamsDict['moduletype'],
182+
module=module,
186183
sceneDict=sceneParamsDict,
187184
cumulativesky=simulationParamsDict['cumulativeSky'])
188185

docs/sphinx/source/conf.py

+11-8
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def __getattr__(cls, name):
112112

113113
# General information about the project.
114114
project = u'bifacial_radiance'
115-
copyright = u'2019, NREL'
115+
copyright = u'2024, NREL'
116116

117117
# The version info for the project you're documenting, acts as replacement for
118118
# |version| and |release|, also used in various other places throughout the
@@ -145,10 +145,7 @@ def __getattr__(cls, name):
145145
# https://pydata-sphinx-theme.rtfd.io/en/latest/user_guide/configuring.html
146146
html_theme_options = {
147147
"github_url": "https://github.com/NREL/bifacial_radiance",
148-
"sphinx-favicon": [
149-
{"rel": "icon", "sizes": "16x16", "href": "favicon-16x16.png"},
150-
{"rel": "icon", "sizes": "32x32", "href": "favicon-32x32.png"},
151-
],
148+
152149
"icon_links": [
153150
{
154151
"name": "StackOverflow",
@@ -163,9 +160,15 @@ def __getattr__(cls, name):
163160
],
164161
#"use_edit_page_button": True,
165162
"show_toc_level": 1,
166-
"footer_start": ["copyright", "sphinx-version", "sidebar-ethical-ads"],
167-
#"left_sidebar_end": [],
163+
#"footer_start": ["copyright"],
164+
#"footer_center": ["sphinx-version"],
168165
}
166+
# Add favicons from extension sphinx_favicon
167+
favicons = [
168+
{"rel": "icon", "sizes": "16x16", "href": "favicon-16x16.png"},
169+
{"rel": "icon", "sizes": "32x32", "href": "favicon-32x32.png"},
170+
]
171+
169172

170173
# The name of an image file (relative to this directory) to place at the top
171174
# of the sidebar.
@@ -196,7 +199,7 @@ def __getattr__(cls, name):
196199
'tutorials/6 - Exploring Trackerdict Structure': '_images/bifacial_radiance.png',
197200
'tutorials/7 - Multiple Scene Objects':'_images/MultipleSceneObject_AnalysingSceneObj2_Row1_Module4.PNG',
198201
'tutorials/8 - Electrical Mismatch Method':'_images/Mismatch_Definition_Example.PNG',
199-
'tutorials/9 - Torquetube Shading':'_images/tutorials_9_-_Torquetube_Shading_23_1.png',
202+
'tutorials/9 - Torquetube Shading':'_images/tutorials_9_-_Torquetube_Shading_24_1.png',
200203
'tutorials/11 - AgriPV Systems': '_images/AgriPV_2.PNG',
201204
'tutorials/13 - Modeling Modules with Glass': '_images/Glass_tilted_reflection.PNG',
202205
'tutorials/14 - Cement Racking Albedo Improvements': '_images/Pavers.PNG',

docs/sphinx/source/manualapi.rst

+2
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ Mismatch
129129
:toctree: generated/
130130
:caption: Mismatch Analysis
131131

132+
mismatch.mad_fn
133+
mismatch.mismatch_fit2
132134
mismatch.analysisIrradianceandPowerMismatch
133135

134136
Support

docs/sphinx/source/user_guide/installation.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ Alternative Installation: Windows Subsystem for Linux:
116116

117117
PYTHON
118118
-------
119-
You will need python installed to run bifacial_radiance. We suggest using the latest release of `Anaconda with Python 3.9 <https://www.anaconda.com/distribution/>`_ (Python 3.7 is still supported but in the process of being deprecated). Anaconda will install ``Spyder`` to work with the python scripts, and also it will install ``Jupyter``, which is the tool we use for our `tutorial trainings <https://github.com/NREL/bifacial_radiance/tree/master/docs/tutorials>`_
119+
You will need python installed to run bifacial_radiance. We suggest using the latest release of `Anaconda with Python 3.11 <https://www.anaconda.com/download/>`_ . Anaconda will install ``Spyder`` to work with the python scripts, and also it will install ``Jupyter``, which is the tool we use for our `tutorial trainings <https://github.com/NREL/bifacial_radiance/tree/master/docs/tutorials>`_
120120

121121

122122
Alternative Installation: Windows Subsystem for Linux:

docs/sphinx/source/whatsnew/v0.4.3.rst

+11-11
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,42 @@
22

33
v0.4.3 (Aug 27 2024)
44
------------------------
5-
Bugfix Release ...
5+
Bugfix Release
66

77

88
API Changes
99
~~~~~~~~~~~~
10-
* A new function can now be called to compile results and report out final irradiance and performance data: :func:`bifacial_radiance.RadianceObj.compileResults`. (This is a temporary function soon to be deprecated)
10+
* A new function can now be called to compile results and report out final irradiance and performance data: ``RadianceObj.compileResults``. (This is a temporary function soon to be deprecated)
1111
* Multiple modules and rows can now be selected in a single analysis scan. ``modWanted`` and ``rowWanted`` inputs in :py:class:`~bifacial_radiance.RadianceObj.analysis1axis` can now be a list, to select multiple rows and modules for scans. (:issue:`405`)(:pull:`408`)
12-
* To support multiple modules and row scans for 1axis simulations, outputs like Wm2Front are now stored in ``trackerdict``.``Results`` (:issue:`405`)(:pull:`408`)
13-
* :func:`.mismatch.mad_fn` has new functionality and input parameter `axis`. If a 2D matrix or dataframe is passed in as data, MAD is calculated along the row (default) or along the columns by passing 'axis=1'
14-
* :func:`bifacial_radiance.mismatch.mismatch_fit3` has been deprecated in favour of :func:`bifacial_radiance.mismatch.mismatch_fit2` which has a greater agreement with anual energy yield data (:issue:`520`)
12+
* To support multiple modules and row scans for 1axis simulations, outputs like Wm2Front are now stored in ``trackerdict.Results`` (:issue:`405`)(:pull:`408`)
13+
* ``mismatch.mismatch.mad_fn`` has new functionality and input parameter ``axis``. If a 2D matrix or dataframe is passed in as data, MAD is calculated along the row (default) or along the columns by passing 'axis=1'
14+
* ``mismatch.mismatch_fit3`` has been deprecated in favour of ``mismatch.mismatch_fit2`` which has a greater agreement with anual energy yield data (:issue:`520`)
1515

1616
Enhancements
1717
~~~~~~~~~~~~
18-
* Added :func:`bifacial_radiance.mismatch.mismatch_fit2`, similar to :func:`bifacial_radiance.mismatch.mismatch_fit3`, with the recommended coefficients of the original publication. (:pull:`520`)
18+
* Added ``mismatch.mismatch_fit2``, similar to ``mismatch.mismatch_fit3``, with the recommended coefficients of the original publication. (:pull:`520`)
1919
* Including `pyRadiance` as a requirement to help streamline RADIANCE installation and calls in a future release. (:pull:`532`)
2020

2121
Bug fixes
2222
~~~~~~~~~
23-
* Fixed error passing all of `sceneDict` into :func:`~bifacial_radiance.RadianceObj.makeScene1axis`. (:issue:`502`)
24-
* Fixed Pandas 2.0 errors by re-factoring :func:`.mismatch.mad_fn` (:issue:`449`)
23+
* Fixed error passing all of ``sceneDict`` into py:class:`~bifacial_radiance.RadianceObj.makeScene1axis`. (:issue:`502`)
24+
* Fixed Pandas 2.0 errors by re-factoring py:class:`bifacial_radiance.mismatch.mad_fn` (:issue:`449`)
2525
* Switch from un-supported Versioneer to setuptools_scm (:issue:`519`)
2626
* Numpy 2.0 compatibility bug (:issue:`521`)
27-
* Fixed bug in :func:`bifacial_radiance.mismatch.mismatch_fit3` where the function was not returning the correct values. It has also been deprecated in favour of :func:`bifacial_radiance.mismatch.mismatch_fit2` which has a greater agreement with anual energy yield data (:issue:`520`)
27+
* Fixed bug in ``mismatch.mismatch_fit3`` where the function was not returning the correct values. It has also been deprecated in favour of ``mismatch.mismatch_fit2`` which has a greater agreement with anual energy yield data (:issue:`520`)
2828
* Updated Github Actions to use Node20: checkout@v4, setup-python@v5, coactions/setup-xvfb, setup-buildx-action@v3 (:pull:`517`)
2929
* Updated Github Actions to make Coveralls fail silently if it has an internal server error (:pull:`517`)
3030
* Fix PerformanceWarning and SettingWithCopyWarning (:issue:`515`)
3131
* Switch from Versioneer to setuptools_scm (:pull:`522`)
32-
* Enable `coerce_year`=None if the TMYfile is all the same year (:issue:`526`)
32+
* Enable ``coerce_year=None`` if the TMYfile is all the same year (:issue:`526`)
3333

3434
Documentation
3535
~~~~~~~~~~~~~~
3636
* Edge effects evaluation tutorial 23, with the new functionality of multiple modules/rows on the same analysis scan.
3737
* Updates to example notebooks
3838
* Reduce number of digits in makeScene .rad file titles. (:pull:`503`)
3939
* Reduce number of digits saved to files in \results (:pull:`534`)
40-
* In the sceneDict reported in the trackerdict, save both `clearance_height` and `hub_height` parameters. (:pull:`503`)
40+
* In the sceneDict reported in the trackerdict, save both ``clearance_height`` and ``hub_height`` parameters. (:pull:`503`)
4141

4242
Contributors
4343
~~~~~~~~~~~~

0 commit comments

Comments
 (0)