From 696a7e6ae4ef1f96b53a208c5b559d850a6207c1 Mon Sep 17 00:00:00 2001 From: Silvana Ovaitt Date: Wed, 21 Aug 2024 09:43:44 -0600 Subject: [PATCH 1/5] removing idle comments --- bifacial_radiance/module.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/bifacial_radiance/module.py b/bifacial_radiance/module.py index fc615a18..7b747eea 100644 --- a/bifacial_radiance/module.py +++ b/bifacial_radiance/module.py @@ -619,11 +619,6 @@ def _makeModuleFromDict(self, x=None, y=None, z=None, xgap=None, ygap=None, else: omegatext = '' - # Defining scenex if it was not defined by the Omegas, - # after the module has been created in case it is a - # cell-level Module, in which the "x" gets calculated internally. - # Also sanity check in case omega-to-omega distance is smaller - # than module. #if torquetube_bool is True: if hasattr(self,'torquetube'): @@ -631,8 +626,6 @@ def _makeModuleFromDict(self, x=None, y=None, z=None, xgap=None, ygap=None, text += self.torquetube._makeTorqueTube(cc=_cc, zgap=zgap, z_inc=_zinc, scenex=self.scenex) - # TODO: should there be anything updated here like scenez? - # YES. if self.glass: edge = 0.01 text = text+'\r\n! genbox stock_glass {} {} {} {} '.format(self.name+'_Glass',x+edge, y+edge, zglass) From 5287eb9fbd8a1eb507518c5e1574b061c2b146f7 Mon Sep 17 00:00:00 2001 From: Silvana Ovaitt Date: Wed, 21 Aug 2024 10:11:50 -0600 Subject: [PATCH 2/5] glass edge #513 adds glass edge as an input to function (and some documentation linting) --- bifacial_radiance/module.py | 120 ++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 66 deletions(-) diff --git a/bifacial_radiance/module.py b/bifacial_radiance/module.py index 7b747eea..35204084 100644 --- a/bifacial_radiance/module.py +++ b/bifacial_radiance/module.py @@ -28,10 +28,11 @@ class ModuleObj(SuperClass): """ - def __init__(self, name=None, x=None, y=None, z=None, bifi=1, modulefile=None, - text=None, customtext='', xgap=0.01, ygap=0.0, zgap=0.1, - numpanels=1, rewriteModulefile=True, cellModule=None, - glass=False, modulematerial='black', tubeParams=None, + def __init__(self, name=None, x=None, y=None, z=None, bifi=1, + modulefile=None, text=None, customtext='', xgap=0.01, + ygap=0.0, zgap=0.1, numpanels=1, rewriteModulefile=True, + cellModule=None, glass=False, glassEdge=0.01, + modulematerial='black', tubeParams=None, frameParams=None, omegaParams=None, hpc=False): """ Add module details to the .JSON module config file module.json @@ -39,7 +40,7 @@ def __init__(self, name=None, x=None, y=None, z=None, bifi=1, modulefile=None, Module definitions assume that the module .rad file is defined with zero tilt, centered along the x-axis and y-axis for the center of rotation of the module (+X/2, -X/2, +Y/2, -Y/2 on each side). - Tip: to define a module that is in 'portrait' mode, y > x. + Tip: to define a module that is in 'portrait' mode, y > x. Parameters ------------ @@ -49,11 +50,16 @@ def __init__(self, name=None, x=None, y=None, z=None, bifi=1, modulefile=None, Width of module along the axis of the torque tube or rack. (meters) y : numeric Length of module (meters) + z : numeric + Thickness of the module (meters), or of the glass if glass = True, + in which case absorber thickness will be 0.002 and glass whatever + thickness is given, with absorber in the middle of the glass. bifi : numeric - Bifaciality of the panel (not currently used). Between 0 (monofacial) - and 1, default 1. + Bifaciality of the panel (not currently used). Between 0 + (monofacial) and 1, default 1. modulefile : str - Existing radfile location in \objects. Otherwise a default value is used + Existing radfile location in \\objects. Otherwise a default value + is used text : str Text used in the radfile to generate the module. Manually passing this value will overwrite module definition @@ -65,41 +71,47 @@ def __init__(self, name=None, x=None, y=None, z=None, bifi=1, modulefile=None, Default True. Will rewrite module file each time makeModule is run. numpanels : int Number of modules arrayed in the Y-direction. e.g. - 1-up or 2-up, etc. (supports any number for carport/Mesa simulations) + 1-up or 2-up, etc. (supports any number for carport/Mesa + simulations) xgap : float Panel space in X direction. Separation between modules in a row. ygap : float Gap between modules arrayed in the Y-direction if any. zgap : float - Distance behind the modules in the z-direction to the edge of the tube (m) + Distance behind the modules in the z-direction to the edge of the + torquetube (m) glass : bool Add 5mm front and back glass to the module (glass/glass). Warning: glass increases the analysis variability. Recommend setting accuracy='high' in AnalysisObj.analysis() + glassEdge: float + Difference in space between module size and absorber part of the + module (or if cell-level module, full cell-level module size; + value will be applied as extra glass 1/2 to each side on x and y. cellModule : dict Dictionary with input parameters for creating a cell-level module. Shortcut for ModuleObj.addCellModule() tubeParams : dict - Dictionary with input parameters for creating a torque tube as part of the - module. Shortcut for ModuleObj.addTorquetube() + Dictionary with input parameters for creating a torque tube as + part of the module. Shortcut for ModuleObj.addTorquetube() frameParams : dict - Dictionary with input parameters for creating a frame as part of the module. - Shortcut for ModuleObj.addFrame() + Dictionary with input parameters for creating a frame as part of + the module. Shortcut for ModuleObj.addFrame() omegaParams : dict - Dictionary with input parameters for creating a omega or module support - structure. Shortcut for ModuleObj.addOmega() + Dictionary with input parameters for creating a omega or module + support structure. Shortcut for ModuleObj.addOmega() hpc : bool (default False) - Set up module in HPC mode. Namely turn off read/write to module.json - and just pass along the details in the module object. Note that - calling e.g. addTorquetube() after this will tend to write to the - module.json so pass all geometry parameters at once in to makeModule - for best response. - - + Set up module in HPC mode. Namely turn off read/write to + module.json and just pass along the details in the module object. + Note that calling e.g. addTorquetube() after this will tend to + write to the module.json so pass all geometry parameters at once + in to makeModule for best response. + + '""" - self.keys = ['x', 'y', 'z', 'modulematerial', 'scenex','sceney', - 'scenez','numpanels','bifi','text','modulefile', 'glass', - 'offsetfromaxis','xgap','ygap','zgap' ] + self.keys = ['x', 'y', 'z', 'modulematerial', 'scenex', 'sceney', + 'scenez', 'numpanels', 'bifi', 'text', 'modulefile', 'glass', + 'glassEdge', 'offsetfromaxis', 'xgap', 'ygap', 'zgap' ] #replace whitespace with underlines. what about \n and other weird characters? # TODO: Address above comment? @@ -160,7 +172,8 @@ def __init__(self, name=None, x=None, y=None, z=None, bifi=1, modulefile=None, self.modulefile = os.path.join('objects', self.name + '.rad') print("\nModule Name:", self.name) - + + # @Chris 8/24 should this be a radObj check for hpc value? if hpc: self.compileText(rewriteModulefile, json=False) else: @@ -229,6 +242,8 @@ def readModule(self, name=None): moduleDict['modulematerial'] = 'black' if not 'glass' in moduleDict: moduleDict['glass'] = False + if not 'glassEdge' in moduleDict: + moduleDict['glassEdge'] = 0.01 if not 'z' in moduleDict: moduleDict['z'] = 0.02 # set ModuleObj attributes from moduleDict @@ -515,22 +530,7 @@ def _makeModuleFromDict(self, x=None, y=None, z=None, xgap=None, ygap=None, self.offsetfromaxis = np.round(zgap + diam/2.0,8) if hasattr(self, 'frame'): self.offsetfromaxis = self.offsetfromaxis + self.frame.frame_z - # TODO: make sure the above is consistent with old version below - """ - if torquetube: - diam = torquetube['diameter'] - torquetube_bool = torquetube['bool'] - else: - diam=0 - torquetube_bool = False - if self.axisofrotationTorqueTube == True: - if torquetube_bool == True: - self.offsetfromaxis = np.round(zgap + diam/2.0,8) - else: - self.offsetfromaxis = zgap - if hasattr(self, 'frame'): - self.offsetfromaxis = self.offsetfromaxis + self.frame.frame_z - """ + # Adding the option to replace the module thickess if self.glass: zglass = 0.01 @@ -599,23 +599,6 @@ def _makeModuleFromDict(self, x=None, y=None, z=None, xgap=None, ygap=None, offsetfromaxis=self.offsetfromaxis) if omega2omega_x > self.scenex: self.scenex = omega2omega_x - - # TODO: is the above line better than below? - # I think this causes it's own set of problems, need to check. - """ - if self.scenex Date: Sun, 8 Sep 2024 09:37:10 -0600 Subject: [PATCH 3/5] New pytests for desired makeModule behavior (1mm absorber and z = glass thickness) --- bifacial_radiance/module.py | 5 ++--- docs/sphinx/source/whatsnew/pending.rst | 3 ++- tests/test_module.py | 18 +++++++++++++++++- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/bifacial_radiance/module.py b/bifacial_radiance/module.py index 9ec3f968..6f863ca8 100644 --- a/bifacial_radiance/module.py +++ b/bifacial_radiance/module.py @@ -53,7 +53,7 @@ def __init__(self, name=None, x=None, y=None, z=None, bifi=1, Length of module (meters) z : numeric Thickness of the module (meters), or of the glass if glass = True, - in which case absorber thickness will be 0.002 and glass whatever + in which case absorber thickness will be 0.001 and glass whatever thickness is given, with absorber in the middle of the glass. bifi : numeric Bifaciality of the panel (not currently used). Between 0 @@ -173,8 +173,7 @@ def __init__(self, name=None, x=None, y=None, z=None, bifi=1, self.modulefile = os.path.join('objects', self.name + '.rad') print("\nModule Name:", self.name) - - # @Chris 8/24 should this be a radObj check for hpc value? + if hpc: self.compileText(rewriteModulefile, json=False) else: diff --git a/docs/sphinx/source/whatsnew/pending.rst b/docs/sphinx/source/whatsnew/pending.rst index 8ebb8014..6482cb5c 100644 --- a/docs/sphinx/source/whatsnew/pending.rst +++ b/docs/sphinx/source/whatsnew/pending.rst @@ -7,7 +7,8 @@ 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. Enhancements ~~~~~~~~~~~~ diff --git a/tests/test_module.py b/tests/test_module.py index ba17d9f1..66cc53c1 100644 --- a/tests/test_module.py +++ b/tests/test_module.py @@ -147,4 +147,20 @@ def test_moduleFrameandOmegas(): scene = demo.makeScene(module, sceneDict) analysis = bifacial_radiance.AnalysisObj() # return an analysis object including the scan dimensions for back irradiance frontscan, backscan = analysis.moduleAnalysis(scene, sensorsy=10) # Gives us the dictionaries with coordinates - assert backscan['xstart'] == pytest.approx(0.792) \ No newline at end of file + assert backscan['xstart'] == pytest.approx(0.792) + +def test_GlassModule(): + # test the cell-level module generation + name = "_test_GlassModule" + # default glass=True with .001 absorber and 0.01 glass + demo = bifacial_radiance.RadianceObj(name) # Create a RadianceObj 'object' + module = demo.makeModule(name='test-module', rewriteModulefile=True, glass=True, x=1, y=2) + assert module.text == '! genbox black test-module 1 2 0.001 | xform -t -0.5 -1.0 0 -a 1 -t 0 2.0' +\ + ' 0\r\n! genbox stock_glass test-module_Glass 1.01 2.01 0.01 | xform -t -0.505 -1.005 -0.005 -a 1 -t 0 2.0 0' + # custom glass=True with .001 absorber and 0.005 glass + module = demo.makeModule(name='test-module', glass=True, x=1, y=2, z=0.005) + assert module.text == '! genbox black test-module 1 2 0.001 | xform -t -0.5 -1.0 0 -a 1 -t 0 2.0' +\ + ' 0\r\n! genbox stock_glass test-module_Glass 1.01 2.01 0.005 | xform -t -0.505 -1.005 -0.0025 -a 1 -t 0 2.0 0' + + + \ No newline at end of file From 711323be2a508691117eb49f2aee8e865bfa5e22 Mon Sep 17 00:00:00 2001 From: cdeline Date: Wed, 18 Sep 2024 14:29:07 -0600 Subject: [PATCH 4/5] Update glass creation logic - now it's working as intended. --- bifacial_radiance/module.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/bifacial_radiance/module.py b/bifacial_radiance/module.py index 6f863ca8..b15a9689 100644 --- a/bifacial_radiance/module.py +++ b/bifacial_radiance/module.py @@ -533,16 +533,18 @@ def _makeModuleFromDict(self, x=None, y=None, z=None, xgap=None, ygap=None, # Adding the option to replace the module thickess if self.glass: - zglass = 0.01 print("\nWarning: module glass increases analysis variability. " "Recommend setting `accuracy='high'` in AnalysisObj.analysis().\n") - else: - zglass = 0.0 - - if z is None: - if self.glass: + if z is None: + zglass = 0.01 z = 0.001 else: + zglass = z + z = 0.001 + + else: # no glass + zglass = 0.0 + if z is None: z = 0.020 self.z = z From c502f1952d1dfdc21a766e69d26eb12627557736 Mon Sep 17 00:00:00 2001 From: cdeline Date: Fri, 20 Sep 2024 16:40:39 -0600 Subject: [PATCH 5/5] more pytests --- tests/test_module.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/test_module.py b/tests/test_module.py index 66cc53c1..baae3227 100644 --- a/tests/test_module.py +++ b/tests/test_module.py @@ -144,6 +144,9 @@ def test_moduleFrameandOmegas(): # test cellModulescan (sensorsy = numellsy) module.glass=True module.addCellModule(**cellParams) + # re-load the module to make sure all of the params are the same + module2 = bifacial_radiance.ModuleObj(name='test-module') + assert module.text == module2.text scene = demo.makeScene(module, sceneDict) analysis = bifacial_radiance.AnalysisObj() # return an analysis object including the scan dimensions for back irradiance frontscan, backscan = analysis.moduleAnalysis(scene, sensorsy=10) # Gives us the dictionaries with coordinates @@ -157,10 +160,9 @@ def test_GlassModule(): module = demo.makeModule(name='test-module', rewriteModulefile=True, glass=True, x=1, y=2) assert module.text == '! genbox black test-module 1 2 0.001 | xform -t -0.5 -1.0 0 -a 1 -t 0 2.0' +\ ' 0\r\n! genbox stock_glass test-module_Glass 1.01 2.01 0.01 | xform -t -0.505 -1.005 -0.005 -a 1 -t 0 2.0 0' - # custom glass=True with .001 absorber and 0.005 glass - module = demo.makeModule(name='test-module', glass=True, x=1, y=2, z=0.005) + # custom glass=True with .001 absorber and 0.005 glass and 0.02 glass edge + module = demo.makeModule(name='test-module', glass=True, x=1, y=2, z=0.005, glassEdge=0.02) assert module.text == '! genbox black test-module 1 2 0.001 | xform -t -0.5 -1.0 0 -a 1 -t 0 2.0' +\ - ' 0\r\n! genbox stock_glass test-module_Glass 1.01 2.01 0.005 | xform -t -0.505 -1.005 -0.0025 -a 1 -t 0 2.0 0' - + ' 0\r\n! genbox stock_glass test-module_Glass 1.02 2.02 0.005 | xform -t -0.51 -1.01 -0.0025 -a 1 -t 0 2.0 0' \ No newline at end of file