From 38f67790f7e681dc7066873729f57891a72c41ff Mon Sep 17 00:00:00 2001 From: cdeline Date: Thu, 9 Nov 2023 14:47:24 -0700 Subject: [PATCH 1/8] Only re-initialize trackerdict[index][Results] if it's empty --- bifacial_radiance/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bifacial_radiance/main.py b/bifacial_radiance/main.py index c83907d5..66ebf1df 100644 --- a/bifacial_radiance/main.py +++ b/bifacial_radiance/main.py @@ -2827,7 +2827,8 @@ def analysis1axis(self, trackerdict=None, singleindex=None, accuracy='low', name = '1axis_%s%s'%(index,customname) octfile = trackerdict[index]['octfile'] scene = trackerdict[index]['scene'] - trackerdict[index]['Results'] = [] + if not trackerdict[index].get('Results'): + trackerdict[index]['Results'] = [] if octfile is None: continue # don't run analysis if the octfile is none # loop over rowWanted and modWanted. Need to listify it first From 4551a8bb093398e7e94758424f2ed343192dbfd0 Mon Sep 17 00:00:00 2001 From: cdeline Date: Thu, 9 Nov 2023 15:58:46 -0700 Subject: [PATCH 2/8] add customname to keys of trackerdict['Results'] --- bifacial_radiance/main.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bifacial_radiance/main.py b/bifacial_radiance/main.py index 66ebf1df..29b55948 100644 --- a/bifacial_radiance/main.py +++ b/bifacial_radiance/main.py @@ -2299,6 +2299,7 @@ def printModules(self): print('Available module names: {}'.format([str(x) for x in modulenames])) return modulenames + def addPiles(self, spacingPiles=6, pile_lenx=0.2, pile_leny=0.2, pile_height=None): ''' Function to add support piles at determined intervals throughout the rows. @@ -2387,7 +2388,7 @@ def addPiles(self, spacingPiles=6, pile_lenx=0.2, pile_leny=0.2, pile_height=Non return - + def makeScene(self, module=None, sceneDict=None, radname=None, moduletype=None, appendtoScene=None): @@ -2838,6 +2839,7 @@ def analysis1axis(self, trackerdict=None, singleindex=None, accuracy='low', row_mod_pairs = list(itertools.product(rowWanted,modWanted)) for (r,m) in row_mod_pairs: Results = {'rowWanted':r,'modWanted':m} + if customname: Results['customname'] = customname try: # look for missing data analysis = AnalysisObj(octfile,name) name = '1axis_%s%s'%(index,customname,) From 35f6f6b2d98ed4eabbe04539c84306756bbce4f6 Mon Sep 17 00:00:00 2001 From: cdeline Date: Thu, 9 Nov 2023 21:30:41 -0700 Subject: [PATCH 3/8] convert self.scene into self.scenes (list) and add _getradfiles() which extracts scene.radfiles from each scene in the list. Tests are passing --- bifacial_radiance/main.py | 60 ++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/bifacial_radiance/main.py b/bifacial_radiance/main.py index 29b55948..9d6adaec 100644 --- a/bifacial_radiance/main.py +++ b/bifacial_radiance/main.py @@ -343,7 +343,8 @@ def __init__(self, name=None, path=None, hpc=False): #self.filelist = [] # list of files to include in the oconv self.materialfiles = [] # material files for oconv self.skyfiles = [] # skyfiles for oconv - self.radfiles = [] # scene rad files for oconv + #self.radfiles = [] # scene rad files for oconv, compiled from self.scenes + self.scenes = [] # array of scenefiles to be compiled self.octfile = [] #octfile name for analysis self.Wm2Front = 0 # cumulative tabulation of front W/m2 self.Wm2Back = 0 # cumulative tabulation of rear W/m2 @@ -421,8 +422,23 @@ def getfilelist(self): Return concat of matfiles, radfiles and skyfiles """ - return self.materialfiles + self.skyfiles + self.radfiles + return self.materialfiles + self.skyfiles + self._getradfiles() + + def _getradfiles(self): + """ + iterate over self.scenes to get the radfiles + Returns + ------- + None. + + """ + a = [] + for scene in self.scenes: + for f in scene.radfiles: + a.append(f) + return a + def save(self, savefile=None): """ Pickle the radiance object for further use. @@ -2299,7 +2315,6 @@ def printModules(self): print('Available module names: {}'.format([str(x) for x in modulenames])) return modulenames - def addPiles(self, spacingPiles=6, pile_lenx=0.2, pile_leny=0.2, pile_height=None): ''' Function to add support piles at determined intervals throughout the rows. @@ -2321,7 +2336,8 @@ def addPiles(self, spacingPiles=6, pile_lenx=0.2, pile_leny=0.2, pile_height=Non None ''' - + raise Exception ('ERROR: addPiles still needs to be re-factored to work ' + 'in SceneObj instead of RadianceObj and is currently unusable') nMods = self.scene.sceneDict['nMods'] nRows = self.scene.sceneDict['nRows'] module = self.module @@ -2389,12 +2405,12 @@ def addPiles(self, spacingPiles=6, pile_lenx=0.2, pile_leny=0.2, pile_height=Non return - def makeScene(self, module=None, sceneDict=None, radname=None, moduletype=None, appendtoScene=None): """ Create a SceneObj which contains details of the PV system configuration including - tilt, row pitch, height, nMods per row, nRows in the system... + tilt, row pitch, height, nMods per row, nRows in the system. Append to + self.scenes list Parameters ---------- @@ -2435,13 +2451,15 @@ def makeScene(self, module=None, sceneDict=None, radname=None, 'Available moduletypes: ' ) self.printModules() #print available module types return - self.scene = SceneObj(module) - self.scene.hpc = self.hpc #pass HPC mode from parent + scene = SceneObj(module, hpc=self.hpc, name=f'Scene{self.scenes.__len__()}') + if self.scenes.__len__() >=1: + print(f"Additional scene {scene.name} created! See list of names with RadianceObj.scenes") if sceneDict is None: print('makeScene(moduletype, sceneDict, nMods, nRows). '+\ 'sceneDict inputs: .tilt .clearance_height .pitch .azimuth') - return self.scene + self.scenes.append(scene) + return scene if 'azimuth' not in sceneDict: sceneDict['azimuth'] = 180 @@ -2462,9 +2480,10 @@ def makeScene(self, module=None, sceneDict=None, radname=None, #self.nMods = sceneDict['nMods'] #self.nRows = sceneDict['nRows'] - sceneRAD = self.scene._makeSceneNxR(sceneDict=sceneDict, + sceneRAD = scene._makeSceneNxR(sceneDict=sceneDict, radname=radname) + # TODO: move appendRadfile logic to SceneObj... if 'appendRadfile' not in sceneDict: appendRadfile = False else: @@ -2473,29 +2492,32 @@ def makeScene(self, module=None, sceneDict=None, radname=None, if appendRadfile: debug = False try: - self.radfiles.append(sceneRAD) + scene.radfiles.append(sceneRAD) if debug: print( "Radfile APPENDED!") except: #TODO: Manage situation where radfile was created with #appendRadfile to False first.. - self.radfiles=[] - self.radfiles.append(sceneRAD) + scene.radfiles=[] + scene.radfiles.append(sceneRAD) if debug: print( "Radfile APPENDAGE created!") else: - self.radfiles = [sceneRAD] + scene.radfiles = [sceneRAD] if appendtoScene is not None: - self.appendtoScene(self.radfiles[0], customObject = appendtoScene) - - return self.scene + self.appendtoScene(scene.radfiles[0], customObject = appendtoScene) + + self.scenes.append(scene) + return scene def appendtoScene(self, radfile=None, customObject=None): """ Appends to the `Scene radfile` in folder `\objects` the text command in Radiance lingo created by the user. Useful when using addCustomObject to the scene. + + TODO: move this to SceneObj Parameters ---------- @@ -3340,7 +3362,7 @@ class SceneObj: ''' def __repr__(self): return str(self.__dict__) - def __init__(self, module=None, name=None): + def __init__(self, module=None, name=None, hpc=False): ''' initialize SceneObj ''' from bifacial_radiance import ModuleObj @@ -3360,7 +3382,7 @@ def __init__(self, module=None, name=None): #self.offsetfromaxis = self.moduleDict['offsetfromaxis'] self.modulefile = self.module.modulefile - self.hpc = False #default False. Set True by makeScene after sceneobj created. + self.hpc = hpc #default False. Set True by makeScene after sceneobj created. if name is None: self.name = 'Scene0' else: From bd3c73c1b5fe4935a020284f54f0c5db0da50f10 Mon Sep 17 00:00:00 2001 From: cdeline Date: Thu, 9 Nov 2023 22:33:00 -0700 Subject: [PATCH 4/8] add scene.appendtoScene, which is basically a duplicate of radianceObj.appendtoScene. Update runs of tutorials 7 and 19, which are working. --- bifacial_radiance/main.py | 48 +++++++++++++++- .../19 - East & West Facing Sheds.ipynb | 36 +++++++----- .../19 - East & West Facing Sheds.py | 10 ++-- .../7 - Multiple Scene Objects.ipynb | 56 ++++++++++++------- docs/tutorials/7 - Multiple Scene Objects.py | 8 ++- 5 files changed, 114 insertions(+), 44 deletions(-) diff --git a/bifacial_radiance/main.py b/bifacial_radiance/main.py index 9d6adaec..e6476368 100644 --- a/bifacial_radiance/main.py +++ b/bifacial_radiance/main.py @@ -662,6 +662,9 @@ def returnMaterialFiles(self, material_path=None): self.materialfiles = materialfilelist return materialfilelist + def sceneNames(self): + return [scene.name for scene in self.scenes] + def setGround(self, material=None, material_file=None): """ Use GroundObj constructor class and return a ground object @@ -2304,7 +2307,7 @@ def makeCustomObject(self, name=None, text=None): f.write(text.encode('ascii')) print("\nCustom Object Name", customradfile) - self.customradfile = customradfile + #self.customradfile = customradfile return customradfile @@ -2453,7 +2456,7 @@ def makeScene(self, module=None, sceneDict=None, radname=None, return scene = SceneObj(module, hpc=self.hpc, name=f'Scene{self.scenes.__len__()}') if self.scenes.__len__() >=1: - print(f"Additional scene {scene.name} created! See list of names with RadianceObj.scenes") + print(f"Additional scene {scene.name} created! See list of names with RadianceObj.scenes and sceneNames") if sceneDict is None: print('makeScene(moduletype, sceneDict, nMods, nRows). '+\ @@ -3557,6 +3560,47 @@ def _makeSceneNxR(self, modulename=None, sceneDict=None, radname=None): # self.hub_height = hubheight return radfile + def appendtoScene(self, radfile=None, customObject=None): + """ + Appends to the `Scene radfile` in folder `\objects` the text command in Radiance + lingo created by the user. + Useful when using addCustomObject to the scene. + + Parameters + ---------- + customObject : str + Directory and name of custom object .rad file is stored, and any geometry + modifications needed for it. + + + Returns + ------- + Nothing, the radfile must already be created and assigned when running this. + + """ + + #TODO: Add a custom name and replace radfile name + + # py2 and 3 compatible: binary write, encode text first + + if radfile: #append radfile to list + if type(self.radfiles) == list: + self.radfiles.append(radfile) + else: + self.radfiles = [self.radfiles, radfile] + else: + radfile = self.radfiles + + if customObject: + text2 = '\n!xform -rx 0 ' + customObject + + debug = False + if debug: + print (text2) + + with open(radfile, 'a+') as f: + f.write(text2) + def showScene(self): """ diff --git a/docs/tutorials/19 - East & West Facing Sheds.ipynb b/docs/tutorials/19 - East & West Facing Sheds.ipynb index 0da7096a..3e5cff2d 100644 --- a/docs/tutorials/19 - East & West Facing Sheds.ipynb +++ b/docs/tutorials/19 - East & West Facing Sheds.ipynb @@ -40,7 +40,7 @@ { "data": { "text/plain": [ - "'0.3.4+406.g49eb243.dirty'" + "'0.4.2+191.g35f6f6b.dirty'" ] }, "execution_count": 2, @@ -62,7 +62,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "path = C:\\Users\\sayala\\Documents\\GitHub\\bifacial_radiance\\bifacial_radiance\\Tutorial_01\n", + "path = C:\\Users\\cdeline\\Documents\\Python Scripts\\Bifacial_Radiance\\bifacial_radiance\\Tutorial_01\n", "Making path: images\n", "Making path: objects\n", "Making path: results\n", @@ -200,7 +200,15 @@ "execution_count": 7, "id": "baefeae4", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Additional scene Scene1 created! See list of names with RadianceObj.scenes and sceneNames\n" + ] + } + ], "source": [ "sceneDict = {'tilt':tilt,'pitch':pitch,'clearance_height':clearance_height,'azimuth':90, 'nMods': nMods, 'nRows': nRows, \n", " 'appendRadfile':True} \n", @@ -253,12 +261,12 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 12, "id": "30db75b0", "metadata": {}, "outputs": [], "source": [ - "#!rvu -vf views\\front.vp -e .01 -pe 0.3 -vp 1 -45 40 -vd 0 0.7 -0.7 MultipleObj.oct" + "#!rvu -vf views\\front.vp -e .01 -pe 0.3 -vp 1 -45 40 -vd 0 0.7 -0.7 tutorial_19.oct" ] }, { @@ -271,12 +279,12 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "id": "e8f92da0", "metadata": {}, "outputs": [], "source": [ - "# !rvu -vf views\\front.vp -e .01 -pe 0.3 -vp -4 -29 3.5 -vd 0 1 0 MultipleObj.oct" + "# !rvu -vf views\\front.vp -e .01 -pe 0.3 -vp -4 -29 3.5 -vd 0 1 0 tutorial_19.oct" ] }, { @@ -291,7 +299,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 13, "id": "b07a3e03", "metadata": {}, "outputs": [ @@ -299,12 +307,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "Linescan in process: EastFacingShed_Front\n", - "Linescan in process: EastFacingShed_Back\n", - "Saved: results\\irr_EastFacingShed.csv\n", - "Linescan in process: WestFacingShed_Front\n", - "Linescan in process: WestFacingShed_Back\n", - "Saved: results\\irr_WestFacingShed.csv\n" + "Linescan in process: EastFacingShed_Row4_Module11_Front\n", + "Linescan in process: EastFacingShed_Row4_Module11_Back\n", + "Saved: results\\irr_EastFacingShed_Row4_Module11.csv\n", + "Linescan in process: WestFacingShed_Row4_Module11_Front\n", + "Linescan in process: WestFacingShed_Row4_Module11_Back\n", + "Saved: results\\irr_WestFacingShed_Row4_Module11.csv\n" ] } ], diff --git a/docs/tutorials/19 - East & West Facing Sheds.py b/docs/tutorials/19 - East & West Facing Sheds.py index 47c9f777..9d3e200d 100644 --- a/docs/tutorials/19 - East & West Facing Sheds.py +++ b/docs/tutorials/19 - East & West Facing Sheds.py @@ -116,25 +116,25 @@ # # Top view: -# In[9]: +# In[12]: -#!rvu -vf views\front.vp -e .01 -pe 0.3 -vp 1 -45 40 -vd 0 0.7 -0.7 MultipleObj.oct +#!rvu -vf views\front.vp -e .01 -pe 0.3 -vp 1 -45 40 -vd 0 0.7 -0.7 tutorial_19.oct # another view, close up: -# In[10]: +# In[11]: -# !rvu -vf views\front.vp -e .01 -pe 0.3 -vp -4 -29 3.5 -vd 0 1 0 MultipleObj.oct +# !rvu -vf views\front.vp -e .01 -pe 0.3 -vp -4 -29 3.5 -vd 0 1 0 tutorial_19.oct # ## Analysis # # We have to analyze the East and the West shed independently. -# In[11]: +# In[13]: sensorsy=4 # 1 per module. consider increasing the number but be careful with sensors in the space between modules. diff --git a/docs/tutorials/7 - Multiple Scene Objects.ipynb b/docs/tutorials/7 - Multiple Scene Objects.ipynb index 4af5739c..980f1c22 100644 --- a/docs/tutorials/7 - Multiple Scene Objects.ipynb +++ b/docs/tutorials/7 - Multiple Scene Objects.ipynb @@ -50,7 +50,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Your simulation will be stored in C:\\Users\\sayala\\Documents\\GitHub\\bifacial_radiance\\bifacial_radiance\\TEMP\\Tutorial_07\n" + "Your simulation will be stored in C:\\Users\\cdeline\\Documents\\Python Scripts\\Bifacial_Radiance\\bifacial_radiance\\TEMP\\Tutorial_07\n" ] } ], @@ -96,7 +96,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "path = C:\\Users\\sayala\\Documents\\GitHub\\bifacial_radiance\\bifacial_radiance\\TEMP\\Tutorial_07\n", + "path = C:\\Users\\cdeline\\Documents\\Python Scripts\\Bifacial_Radiance\\bifacial_radiance\\TEMP\\Tutorial_07\n", "Loading albedo, 1 value(s), 0.620 avg\n", "1 nonzero albedo values.\n", "Getting weather file: USA_VA_Richmond.724010_TMY2.epw\n", @@ -107,7 +107,9 @@ "Calculating Sun position for Metdata that is right-labeled with a delta of -30 mins. i.e. 12 is 11:30 sunpos\n", "\n", "Module Name: test-moduleA\n", - "Module test-moduleA updated in module.json\n" + "Module test-moduleA updated in module.json\n", + "Pre-existing .rad file objects\\test-moduleA.rad will be overwritten\n", + "\n" ] } ], @@ -121,7 +123,7 @@ "demo.gendaylit(timestamp) \n", "module_type = 'test-moduleA' \n", "mymodule = demo.makeModule(name=module_type,y=1,x=1.7)\n", - "sceneDict = {'tilt':10,'pitch':1.5,'clearance_height':0.2,'azimuth':180, 'nMods': 5, 'nRows': 2, 'appendRadfile':True} \n", + "sceneDict = {'tilt':10,'pitch':1.5,'clearance_height':0.2,'azimuth':180, 'nMods': 5, 'nRows': 2} \n", "sceneObj1 = demo.makeScene(mymodule, sceneDict) " ] }, @@ -142,7 +144,7 @@ "output_type": "stream", "text": [ "SceneObj1 modulefile: objects\\test-moduleA.rad\n", - "SceneObj1 SceneFile: objects\\test-moduleA_C_0.20000_rtr_1.50000_tilt_10.00000_5modsx2rows_origin0,0.rad\n", + "SceneObj1 SceneFile: ['objects\\\\test-moduleA_C_0.20000_rtr_1.50000_tilt_10.00000_5modsx2rows_origin0,0.rad']\n", "SceneObj1 GCR: 0.67\n", "FileLists: \n", " ['materials\\\\ground.rad', 'skies\\\\sky2_37.5_-77.33_2001-06-17_1300.rad', 'objects\\\\test-moduleA_C_0.20000_rtr_1.50000_tilt_10.00000_5modsx2rows_origin0,0.rad']\n" @@ -184,8 +186,21 @@ "text": [ "\n", "Module Name: test-moduleB\n", - "Module test-moduleB updated in module.json\n" + "Module test-moduleB updated in module.json\n", + "Pre-existing .rad file objects\\test-moduleB.rad will be overwritten\n", + "\n", + "Additional scene Scene1 created! See list of names with RadianceObj.scenes and sceneNames\n" ] + }, + { + "data": { + "text/plain": [ + "['Scene0', 'Scene1']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ @@ -193,7 +208,9 @@ " 'nMods': 5, 'nRows': 1, 'originx': 0, 'originy': 3.5, 'appendRadfile':True} \n", "module_type2='test-moduleB'\n", "mymodule2 = demo.makeModule(name=module_type2,x=1,y=1.6, numpanels=2, ygap=0.15)\n", - "sceneObj2 = demo.makeScene(mymodule2, sceneDict2) \n" + "sceneObj2 = demo.makeScene(mymodule2, sceneDict2) \n", + "\n", + "demo.sceneNames()" ] }, { @@ -206,11 +223,11 @@ "output_type": "stream", "text": [ "SceneObj1 modulefile: objects\\test-moduleA.rad\n", - "SceneObj1 SceneFile: objects\\test-moduleA_C_0.20000_rtr_1.50000_tilt_10.00000_5modsx2rows_origin0,0.rad\n", + "SceneObj1 SceneFile: ['objects\\\\test-moduleA_C_0.20000_rtr_1.50000_tilt_10.00000_5modsx2rows_origin0,0.rad']\n", "SceneObj1 GCR: 0.67\n", "\n", "SceneObj2 modulefile: objects\\test-moduleB.rad\n", - "SceneObj2 SceneFile: objects\\test-moduleB_C_1.00000_rtr_5.00000_tilt_30.00000_5modsx1rows_origin0,3.5.rad\n", + "SceneObj2 SceneFile: ['objects\\\\test-moduleB_C_1.00000_rtr_5.00000_tilt_30.00000_5modsx1rows_origin0,3.5.rad']\n", "SceneObj2 GCR: 0.67\n", "NEW FileLists: \n", " ['materials\\\\ground.rad', 'skies\\\\sky2_37.5_-77.33_2001-06-17_1300.rad', 'objects\\\\test-moduleA_C_0.20000_rtr_1.50000_tilt_10.00000_5modsx2rows_origin0,0.rad', 'objects\\\\test-moduleB_C_1.00000_rtr_5.00000_tilt_30.00000_5modsx1rows_origin0,3.5.rad']\n" @@ -271,8 +288,8 @@ "# NOTE: offsetting translation by 0.1 so the center of the marker (with sides of 0.2) is at the desired coordinate.\n", "name='Post1'\n", "text='! genbox black originMarker 0.2 0.2 1 | xform -t -0.1 -0.1 0'\n", - "customObject = demo.makeCustomObject(name,text)\n", - "demo.appendtoScene(sceneObj1.radfiles, customObject, '!xform -rz 0')" + "customRadfile = demo.makeCustomObject(name,text)\n", + "sceneObj1.appendtoScene(customRadfile)" ] }, { @@ -370,7 +387,6 @@ " 'azimuth': 180,\n", " 'nMods': 5,\n", " 'nRows': 2,\n", - " 'appendRadfile': True,\n", " 'axis_tilt': 0,\n", " 'originx': 0,\n", " 'originy': 0}" @@ -423,10 +439,10 @@ "name": "stdout", "output_type": "stream", "text": [ - "Linescan in process: FirstObj_Front\n", - "Linescan in process: FirstObj_Back\n", - "Saved: results\\irr_FirstObj.csv\n", - "Annual bifacial ratio First Set of Panels: 0.129 \n" + "Linescan in process: FirstObj_Row1_Module3_Front\n", + "Linescan in process: FirstObj_Row1_Module3_Back\n", + "Saved: results\\irr_FirstObj_Row1_Module3.csv\n", + "Annual bifacial ratio First Set of Panels: 0.130 \n" ] } ], @@ -486,10 +502,10 @@ "name": "stdout", "output_type": "stream", "text": [ - "Linescan in process: SecondObj_Front\n", - "Linescan in process: SecondObj_Back\n", - "Saved: results\\irr_SecondObj.csv\n", - "Annual bifacial ratio Second Set of Panels: 0.292 \n" + "Linescan in process: SecondObj_Row1_Module4_Front\n", + "Linescan in process: SecondObj_Row1_Module4_Back\n", + "Saved: results\\irr_SecondObj_Row1_Module4.csv\n", + "Annual bifacial ratio Second Set of Panels: 0.293 \n" ] } ], diff --git a/docs/tutorials/7 - Multiple Scene Objects.py b/docs/tutorials/7 - Multiple Scene Objects.py index 93ef8d62..1698f9a3 100644 --- a/docs/tutorials/7 - Multiple Scene Objects.py +++ b/docs/tutorials/7 - Multiple Scene Objects.py @@ -64,7 +64,7 @@ demo.gendaylit(timestamp) module_type = 'test-moduleA' mymodule = demo.makeModule(name=module_type,y=1,x=1.7) -sceneDict = {'tilt':10,'pitch':1.5,'clearance_height':0.2,'azimuth':180, 'nMods': 5, 'nRows': 2, 'appendRadfile':True} +sceneDict = {'tilt':10,'pitch':1.5,'clearance_height':0.2,'azimuth':180, 'nMods': 5, 'nRows': 2} sceneObj1 = demo.makeScene(mymodule, sceneDict) @@ -96,6 +96,8 @@ mymodule2 = demo.makeModule(name=module_type2,x=1,y=1.6, numpanels=2, ygap=0.15) sceneObj2 = demo.makeScene(mymodule2, sceneDict2) +demo.sceneNames() + # In[5]: @@ -130,8 +132,8 @@ # NOTE: offsetting translation by 0.1 so the center of the marker (with sides of 0.2) is at the desired coordinate. name='Post1' text='! genbox black originMarker 0.2 0.2 1 | xform -t -0.1 -0.1 0' -customObject = demo.makeCustomObject(name,text) -demo.appendtoScene(sceneObj1.radfiles, customObject, '!xform -rz 0') +customRadfile = demo.makeCustomObject(name,text) +sceneObj1.appendtoScene(customRadfile) # From 2132affd5bb0a5e7933bf22d1839df7ceb8364a0 Mon Sep 17 00:00:00 2001 From: cdeline Date: Fri, 10 Nov 2023 08:58:38 -0700 Subject: [PATCH 5/8] Initial commit - update trackerdict[scene] to [scenes] (list). Initial tests are passing, still need modelchain updates.. --- bifacial_radiance/main.py | 71 +++++++++++++++++++++------------ bifacial_radiance/modelchain.py | 8 ++-- 2 files changed, 50 insertions(+), 29 deletions(-) diff --git a/bifacial_radiance/main.py b/bifacial_radiance/main.py index e6476368..0e9e4507 100644 --- a/bifacial_radiance/main.py +++ b/bifacial_radiance/main.py @@ -424,7 +424,7 @@ def getfilelist(self): return self.materialfiles + self.skyfiles + self._getradfiles() - def _getradfiles(self): + def _getradfiles(self, scenelist=None): """ iterate over self.scenes to get the radfiles @@ -433,8 +433,10 @@ def _getradfiles(self): None. """ + if scenelist is None: + scenelist = self.scenes a = [] - for scene in self.scenes: + for scene in scenelist: for f in scene.radfiles: a.append(f) return a @@ -662,8 +664,9 @@ def returnMaterialFiles(self, material_path=None): self.materialfiles = materialfilelist return materialfilelist - def sceneNames(self): - return [scene.name for scene in self.scenes] + def sceneNames(self, scenes=None): + if scenes is None: scenes = self.scenes + return [scene.name for scene in scenes] def setGround(self, material=None, material_file=None): """ @@ -2191,8 +2194,8 @@ def makeOct1axis(self, trackerdict=None, singleindex=None, customname=None): print('\nMaking {} octfiles in root directory.'.format(indexlist.__len__())) for index in sorted(indexlist): # run through either entire key list of trackerdict, or just a single value - try: - filelist = self.materialfiles + [trackerdict[index]['skyfile'], trackerdict[index]['radfile']] + try: #TODO: check if this works + filelist = self.materialfiles + trackerdict[index]['skyfile'] + self._getradfiles(trackerdict[index]['scenes']) octname = '1axis_%s%s'%(index, customname) trackerdict[index]['octfile'] = self.makeOct(filelist, octname) except KeyError as e: @@ -2579,8 +2582,6 @@ def makeScene1axis(self, trackerdict=None, module=None, sceneDict=None, -------- trackerdict Append the following keys - 'radfile' - directory where .rad scene file is stored 'scene' SceneObj for each tracker theta 'clearance_height' @@ -2660,7 +2661,7 @@ def makeScene1axis(self, trackerdict=None, module=None, sceneDict=None, if cumulativesky is True: # cumulativesky workflow print('\nMaking .rad files for cumulativesky 1-axis workflow') for theta in trackerdict: - scene = SceneObj(module) + scene = SceneObj(module, hpc=self.hpc) if trackerdict[theta]['surf_azm'] >= 180: trackerdict[theta]['surf_azm'] = trackerdict[theta]['surf_azm']-180 trackerdict[theta]['surf_tilt'] = trackerdict[theta]['surf_tilt']*-1 @@ -2693,8 +2694,14 @@ def makeScene1axis(self, trackerdict=None, module=None, sceneDict=None, radfile = scene._makeSceneNxR(sceneDict=sceneDict2, radname=radname) - trackerdict[theta]['radfile'] = radfile - trackerdict[theta]['scene'] = scene + #trackerdict[theta]['radfile'] = radfile + # TODO: determine radfiles dynamically from scenes + try: + name=f"Scene{trackerdict[theta]['scenes'].__len__()}" + scene.name = name + trackerdict[theta]['scenes'].append(scene) + except IndexError: + trackerdict[theta]['scenes'] = [scene] print('{} Radfiles created in /objects/'.format(trackerdict.__len__())) @@ -2702,7 +2709,7 @@ def makeScene1axis(self, trackerdict=None, module=None, sceneDict=None, print('\nMaking ~%s .rad files for gendaylit 1-axis workflow (this takes a minute..)' % (len(trackerdict))) count = 0 for time in trackerdict: - scene = SceneObj(module) + scene = SceneObj(module, hpc=self.hpc) if trackerdict[time]['surf_azm'] >= 180: trackerdict[time]['surf_azm'] = trackerdict[time]['surf_azm']-180 @@ -2737,15 +2744,23 @@ def makeScene1axis(self, trackerdict=None, module=None, sceneDict=None, radfile = scene._makeSceneNxR(sceneDict=sceneDict2, radname=radname) - trackerdict[time]['radfile'] = radfile - trackerdict[time]['scene'] = scene + + #trackerdict[time]['radfile'] = radfile + # TODO: determine radfiles dynamically from scenes + try: + name=f"Scene{trackerdict[time]['scenes'].__len__()}" + scene.name = name + trackerdict[time]['scenes'].append(scene) + except IndexError: + trackerdict[time]['scenes'] = [scene] count+=1 print('{} Radfiles created in /objects/'.format(count)) if appendtoScene is not None: for key in trackerdict: - self.appendtoScene(trackerdict[key]['radfile'], customObject = appendtoScene) + #TODO: test if this actually works + self.appendtoScene(trackerdict[key]['scenes'][0].radfiles, customObject = appendtoScene) self.trackerdict = trackerdict #self.nMods = sceneDict['nMods'] #assign nMods and nRows to RadianceObj @@ -2759,7 +2774,7 @@ def analysis1axis(self, trackerdict=None, singleindex=None, accuracy='low', customname=None, modWanted=None, rowWanted=None, sensorsy=9, sensorsx=1, modscanfront = None, modscanback = None, relative=False, - debug=False ): + debug=False, sceneNum=0 ): """ Loop through trackerdict and runs linescans for each scene and scan in there. @@ -2808,6 +2823,8 @@ def analysis1axis(self, trackerdict=None, singleindex=None, accuracy='low', Default is absolute value (relative=False) debug : Bool Activates internal printing of the function to help debugging. + sceneNum : int + Index of the scene number in the list of scenes per trackerdict. default 0 Returns @@ -2841,9 +2858,9 @@ def analysis1axis(self, trackerdict=None, singleindex=None, accuracy='low', trackerkeys = [singleindex] if modWanted == None: - modWanted = round(trackerdict[trackerkeys[0]]['scene'].sceneDict['nMods'] / 1.99) + modWanted = round(trackerdict[trackerkeys[0]]['scenes'][sceneNum].sceneDict['nMods'] / 1.99) if rowWanted == None: - rowWanted = round(trackerdict[trackerkeys[0]]['scene'].sceneDict['nRows'] / 1.99) + rowWanted = round(trackerdict[trackerkeys[0]]['scenes'][sceneNum].sceneDict['nRows'] / 1.99) #frontWm2 = 0 # container for tracking front irradiance across module chord. Dynamically size based on first analysis run @@ -2852,7 +2869,7 @@ def analysis1axis(self, trackerdict=None, singleindex=None, accuracy='low', for index in trackerkeys: # either full list of trackerdict keys, or single index name = '1axis_%s%s'%(index,customname) octfile = trackerdict[index]['octfile'] - scene = trackerdict[index]['scene'] + scene = trackerdict[index]['scenes'][sceneNum] if not trackerdict[index].get('Results'): trackerdict[index]['Results'] = [] if octfile is None: @@ -2863,7 +2880,7 @@ def analysis1axis(self, trackerdict=None, singleindex=None, accuracy='low', row_mod_pairs = list(itertools.product(rowWanted,modWanted)) for (r,m) in row_mod_pairs: - Results = {'rowWanted':r,'modWanted':m} + Results = {'rowWanted':r,'modWanted':m, 'sceneNum':sceneNum} if customname: Results['customname'] = customname try: # look for missing data analysis = AnalysisObj(octfile,name) @@ -2904,7 +2921,8 @@ def calculateResults(self, CECMod=None, glassglass=False, bifacialityfactor=None considering electrical mismatch, using PVLib. Cell temperature is calculated - TODO: move into AnalysisObj? + TODO: move into AnalysisObj so it works on a specific scene!!! Or + alternatively run multiple times, enabling to select a specific sceneNum... Parameters ---------- @@ -2946,8 +2964,9 @@ def calculateResults(self, CECMod=None, glassglass=False, bifacialityfactor=None keys = list(trackerdict.keys()) # Search for module object bifaciality + # TODO: move into analysisObj so it works on a specific scene and can iterate over them. if bifacialityfactor is None: - bifacialityfactor = trackerdict[keys[0]]['scene'].module.bifi + bifacialityfactor = trackerdict[keys[0]]['scenes'][0].module.bifi print("Bifaciality factor of module stored is ", bifacialityfactor) # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1``34 # TODO IMPORTANT: ADD CUMULATIVE CHEck AND WHOLE OTHER PROCESSING OPTION @@ -2965,6 +2984,7 @@ def calculateResults(self, CECMod=None, glassglass=False, bifacialityfactor=None frontMat = [] rowWanted = [] modWanted = [] + sceneNum = [] keys_all = [] dni = [] dhi = [] @@ -2978,7 +2998,8 @@ def calculateResults(self, CECMod=None, glassglass=False, bifacialityfactor=None frontMat.append(row_mod['AnalysisObj'].mattype) rearMat.append(row_mod['AnalysisObj'].rearMat) rowWanted.append(row_mod['AnalysisObj'].rowWanted) - modWanted.append(row_mod['AnalysisObj'].modWanted) + modWanted.append(row_mod['AnalysisObj'].modWanted) + sceneNum.append(row_mod['AnalysisObj'].sceneNum) if self.cumulativesky is False: temp_air.append(trackerdict[key]['temp_air']) wind_speed.append(trackerdict[key]['wind_speed']) @@ -2988,9 +3009,9 @@ def calculateResults(self, CECMod=None, glassglass=False, bifacialityfactor=None # trackerdict[key]['effective_irradiance'] = eff_irrad - data= pd.DataFrame(zip(keys_all, rowWanted, modWanted, + data= pd.DataFrame(zip(keys_all, rowWanted, modWanted, sceneNum, Wm2Front, Wm2Back, frontMat, rearMat), - columns=('timestamp', 'rowNum','ModNumber', + columns=('timestamp', 'rowNum','ModNumber', 'sceneNum', 'Wm2Front', 'Wm2Back', 'mattype', 'rearMat')) diff --git a/bifacial_radiance/modelchain.py b/bifacial_radiance/modelchain.py index afbf1f2d..4b0ee3c2 100644 --- a/bifacial_radiance/modelchain.py +++ b/bifacial_radiance/modelchain.py @@ -250,11 +250,11 @@ def runModelChain(simulationParamsDict, sceneParamsDict, timeControlParamsDict=N if simulationParamsDict.get('saveImage'): if hasattr(demo, 'trackerdict'): bestkey = _getDesiredIndex(demo.trackerdict) - scene = demo.trackerdict[bestkey]['scene'] + scene = demo.trackerdict[bestkey]['scenes'][0] #TODO: select which sceneNum chosen? imagefilename = f'scene_{bestkey}' viewfile = None # just use default value for now. Improve later.. - elif hasattr(demo, 'scene'): - scene = demo.scene + elif hasattr(demo, 'scenes'): + scene = demo.scenes[0] viewfile = None # just use default value for now. Improve later.. imagefilename = 'scene0' try: @@ -287,7 +287,7 @@ def _getDesiredIndex(trackerdict): df = pd.DataFrame.from_dict(trackerdict, orient='index') try: - df = df[df['scene'].notna()] + df = df[df['scenes'][0].notna()] #TODO: select which sceneNum except KeyError: print('Error in _getDesiredIndex - trackerdict has no scene defined.') return df.index[-1] From 90f8f803f76a1b77cea4cdc693f36cde5a110bb9 Mon Sep 17 00:00:00 2001 From: cdeline Date: Fri, 10 Nov 2023 10:09:25 -0700 Subject: [PATCH 6/8] load._exportTrackerDict updated to iterate on sceneNum. _getradfiles bug fixed. tests fixed, new functionality tested in test_1axis_gencumSky --- bifacial_radiance/load.py | 105 ++++++++++++++++---------------- bifacial_radiance/main.py | 15 +++-- bifacial_radiance/modelchain.py | 2 +- tests/test_bifacial_radiance.py | 16 ++--- 4 files changed, 72 insertions(+), 66 deletions(-) diff --git a/bifacial_radiance/load.py b/bifacial_radiance/load.py index f3151c75..65113c02 100644 --- a/bifacial_radiance/load.py +++ b/bifacial_radiance/load.py @@ -333,7 +333,7 @@ def _exportTrackerDict(trackerdict, savefile, reindex=False, monthlyyearly=False # add trackerdict Results (not all simulations will have results) try: results = pd.concat([df(data=value['Results'],index=[key]*len(value['Results'])) for (key,value) in trackerdict.items()]) - results = results[['rowWanted','modWanted','Wm2Front','Wm2Back']] + results = results[['rowWanted','modWanted','sceneNum','Wm2Front','Wm2Back']] d = results.join(d) except KeyError: pass @@ -357,57 +357,58 @@ def _exportTrackerDict(trackerdict, savefile, reindex=False, monthlyyearly=False D4join = pd.DataFrame() for rownum in d['rowWanted'].unique(): for modnum in d['modWanted'].unique(): - mask = (d['rowWanted']==rownum) & (d['modWanted']==modnum) - print(modnum) - # Gfront_mean.append(filledFront[mask].sum(axis=0).mean()) - D2 = d[mask].copy() - D2['timestamp'] = pd.to_datetime(D2['measdatetime'], format="%Y-%m-%d_%H%M") - D2 = D2.set_index('timestamp') - # D2 = D2.set_index(D2['timestamp']) - - # Determine if data is sub-hourly - if len(D2) > 1: - if (D2.index[1]-D2.index[0]).total_seconds() / 60 < 60.0: - # Subhourly to hourly data averages, doesn't sum - # So we get average hourly irradiance as well as Wh on - # results of power. - D2b = D2.copy() - D2b = D2b.groupby(pd.PeriodIndex(D2b.index, freq="H")).mean().reset_index() - D2b['BGG'] = D2b['Grear_mean']*100/D2b['Gfront_mean'] - D2b['BGE'] = (D2b['Pout']-D2b['Pout_Gfront'])*100/D2b['Pout'] - D2b['Mismatch'] = (D2b['Pout_raw']-D2b['Pout'])*100/D2b['Pout_raw'] - D2b['rowWanted'] = rownum - D2b['modWanted'] = modnum - D2b.drop(columns=['theta', 'surf_tilt', 'surf_azm'], inplace=True) - D2b=D2b.reset_index() - D2join = pd.concat([D2join, D2b], ignore_index=True, sort=False) - - D3 = D2.groupby(pd.PeriodIndex(D2.index, freq="M")).sum().reset_index() - D3['BGG'] = D3['Grear_mean']*100/D3['Gfront_mean'] - D3['BGE'] = (D3['Pout']-D3['Pout_Gfront'])*100/D3['Pout'] - D3['Mismatch'] = (D3['Pout_raw']-D3['Pout'])*100/D3['Pout_raw'] - D3['rowWanted'] = rownum - D3['modWanted'] = modnum - D3m = D2.groupby(pd.PeriodIndex(D2.index, freq="M")).mean().reset_index() - D3['temp_air'] = D3m['temp_air'] - D3['wind_speed'] = D3m['wind_speed'] - D3.drop(columns=['theta', 'surf_tilt', 'surf_azm'], inplace=True) - - D4 = D2.groupby(pd.PeriodIndex(D2.index, freq="Y")).sum().reset_index() - D4['BGG'] = D4['Grear_mean']*100/D4['Gfront_mean'] - D4['BGE'] = (D4['Pout']-D4['Pout_Gfront'])*100/D4['Pout'] - D4['Mismatch'] = (D4['Pout_raw']-D4['Pout'])*100/D4['Pout_raw'] - D4['rowWanted'] = rownum - D4['modWanted'] = modnum - D4m = D2.groupby(pd.PeriodIndex(D2.index, freq="Y")).mean().reset_index() - D4['temp_air'] = D4m['temp_air'] - D4['wind_speed'] = D4m['wind_speed'] - D4.drop(columns=['theta', 'surf_tilt', 'surf_azm'], inplace=True) - - D3=D3.reset_index() - D4=D4.reset_index() - D3join = pd.concat([D3join, D3], ignore_index=True, sort=False) - D4join = pd.concat([D4join, D4], ignore_index=True, sort=False) + for sceneNum in d['sceneNum'].unique():#TODO: is sceneNum iteration required here? + mask = (d['rowWanted']==rownum) & (d['modWanted']==modnum) & (d['sceneNum']==sceneNum) + print(modnum) + # Gfront_mean.append(filledFront[mask].sum(axis=0).mean()) + D2 = d[mask].copy() + D2['timestamp'] = pd.to_datetime(D2['measdatetime'], format="%Y-%m-%d_%H%M") + D2 = D2.set_index('timestamp') + # D2 = D2.set_index(D2['timestamp']) + + # Determine if data is sub-hourly + if len(D2) > 1: + if (D2.index[1]-D2.index[0]).total_seconds() / 60 < 60.0: + # Subhourly to hourly data averages, doesn't sum + # So we get average hourly irradiance as well as Wh on + # results of power. + D2b = D2.copy() + D2b = D2b.groupby(pd.PeriodIndex(D2b.index, freq="H")).mean().reset_index() + D2b['BGG'] = D2b['Grear_mean']*100/D2b['Gfront_mean'] + D2b['BGE'] = (D2b['Pout']-D2b['Pout_Gfront'])*100/D2b['Pout'] + D2b['Mismatch'] = (D2b['Pout_raw']-D2b['Pout'])*100/D2b['Pout_raw'] + D2b['rowWanted'] = rownum + D2b['modWanted'] = modnum + D2b.drop(columns=['theta', 'surf_tilt', 'surf_azm'], inplace=True) + D2b=D2b.reset_index() + D2join = pd.concat([D2join, D2b], ignore_index=True, sort=False) + + D3 = D2.groupby(pd.PeriodIndex(D2.index, freq="M")).sum().reset_index() + D3['BGG'] = D3['Grear_mean']*100/D3['Gfront_mean'] + D3['BGE'] = (D3['Pout']-D3['Pout_Gfront'])*100/D3['Pout'] + D3['Mismatch'] = (D3['Pout_raw']-D3['Pout'])*100/D3['Pout_raw'] + D3['rowWanted'] = rownum + D3['modWanted'] = modnum + D3m = D2.groupby(pd.PeriodIndex(D2.index, freq="M")).mean().reset_index() + D3['temp_air'] = D3m['temp_air'] + D3['wind_speed'] = D3m['wind_speed'] + D3.drop(columns=['theta', 'surf_tilt', 'surf_azm'], inplace=True) + + D4 = D2.groupby(pd.PeriodIndex(D2.index, freq="Y")).sum().reset_index() + D4['BGG'] = D4['Grear_mean']*100/D4['Gfront_mean'] + D4['BGE'] = (D4['Pout']-D4['Pout_Gfront'])*100/D4['Pout'] + D4['Mismatch'] = (D4['Pout_raw']-D4['Pout'])*100/D4['Pout_raw'] + D4['rowWanted'] = rownum + D4['modWanted'] = modnum + D4m = D2.groupby(pd.PeriodIndex(D2.index, freq="Y")).mean().reset_index() + D4['temp_air'] = D4m['temp_air'] + D4['wind_speed'] = D4m['wind_speed'] + D4.drop(columns=['theta', 'surf_tilt', 'surf_azm'], inplace=True) + + D3=D3.reset_index() + D4=D4.reset_index() + D3join = pd.concat([D3join, D3], ignore_index=True, sort=False) + D4join = pd.concat([D4join, D4], ignore_index=True, sort=False) savefile2 = savefile[:-4]+'_Hourly.csv' savefile3 = savefile[:-4]+'_Monthly.csv' diff --git a/bifacial_radiance/main.py b/bifacial_radiance/main.py index 0e9e4507..5eab160b 100644 --- a/bifacial_radiance/main.py +++ b/bifacial_radiance/main.py @@ -437,8 +437,11 @@ def _getradfiles(self, scenelist=None): scenelist = self.scenes a = [] for scene in scenelist: - for f in scene.radfiles: - a.append(f) + if type(scene.radfiles) == list: + for f in scene.radfiles: + a.append(f) + else: + a.append(scene.radfiles) return a def save(self, savefile=None): @@ -2195,7 +2198,7 @@ def makeOct1axis(self, trackerdict=None, singleindex=None, customname=None): print('\nMaking {} octfiles in root directory.'.format(indexlist.__len__())) for index in sorted(indexlist): # run through either entire key list of trackerdict, or just a single value try: #TODO: check if this works - filelist = self.materialfiles + trackerdict[index]['skyfile'] + self._getradfiles(trackerdict[index]['scenes']) + filelist = self.materialfiles + [trackerdict[index]['skyfile']] + self._getradfiles(trackerdict[index]['scenes']) octname = '1axis_%s%s'%(index, customname) trackerdict[index]['octfile'] = self.makeOct(filelist, octname) except KeyError as e: @@ -2700,7 +2703,7 @@ def makeScene1axis(self, trackerdict=None, module=None, sceneDict=None, name=f"Scene{trackerdict[theta]['scenes'].__len__()}" scene.name = name trackerdict[theta]['scenes'].append(scene) - except IndexError: + except KeyError: #either KeyError or maybe IndexError? trackerdict[theta]['scenes'] = [scene] print('{} Radfiles created in /objects/'.format(trackerdict.__len__())) @@ -2751,7 +2754,7 @@ def makeScene1axis(self, trackerdict=None, module=None, sceneDict=None, name=f"Scene{trackerdict[time]['scenes'].__len__()}" scene.name = name trackerdict[time]['scenes'].append(scene) - except IndexError: + except KeyError: #either KeyError or maybe IndexError? trackerdict[time]['scenes'] = [scene] count+=1 print('{} Radfiles created in /objects/'.format(count)) @@ -2999,7 +3002,7 @@ def calculateResults(self, CECMod=None, glassglass=False, bifacialityfactor=None rearMat.append(row_mod['AnalysisObj'].rearMat) rowWanted.append(row_mod['AnalysisObj'].rowWanted) modWanted.append(row_mod['AnalysisObj'].modWanted) - sceneNum.append(row_mod['AnalysisObj'].sceneNum) + sceneNum.append(row_mod['sceneNum']) if self.cumulativesky is False: temp_air.append(trackerdict[key]['temp_air']) wind_speed.append(trackerdict[key]['wind_speed']) diff --git a/bifacial_radiance/modelchain.py b/bifacial_radiance/modelchain.py index 4b0ee3c2..236832f2 100644 --- a/bifacial_radiance/modelchain.py +++ b/bifacial_radiance/modelchain.py @@ -287,7 +287,7 @@ def _getDesiredIndex(trackerdict): df = pd.DataFrame.from_dict(trackerdict, orient='index') try: - df = df[df['scenes'][0].notna()] #TODO: select which sceneNum + df = df[df['scenes'].notna()] except KeyError: print('Error in _getDesiredIndex - trackerdict has no scene defined.') return df.index[-1] diff --git a/tests/test_bifacial_radiance.py b/tests/test_bifacial_radiance.py index c6f3e692..dbd1fdbc 100644 --- a/tests/test_bifacial_radiance.py +++ b/tests/test_bifacial_radiance.py @@ -147,8 +147,8 @@ def test_Radiance_1axis_gendaylit_modelchains(): #V 0.2.5 fixed the gcr passed to set1axis. (since gcr was not being passd to set1axis, gcr was default 0.33 default). assert(demo2.CompiledResults.Gfront_mean[0] == pytest.approx(205.0, 0.01) ) # was 214 in v0.2.3 # was 205 in early v0.2.4 assert(demo2.CompiledResults.Grear_mean[0] == pytest.approx(43.0, 0.1) ) - assert demo2.trackerdict['2001-01-01_1100']['scene'].text.__len__() == 132 - assert demo2.trackerdict['2001-01-01_1100']['scene'].text[23:28] == " 2.0 " + assert demo2.trackerdict['2001-01-01_1100']['scenes'][0].text.__len__() == 132 + assert demo2.trackerdict['2001-01-01_1100']['scenes'][0].text[23:28] == " 2.0 " demo2.exportTrackerDict(savefile = 'results\exportedTrackerDict.csv', reindex=True) """ @@ -217,7 +217,7 @@ def test_1axis_gencumSky(): # Removing all of this other tests for hub_height and height since it's ben identified that # a new module to handle hub_height and height in sceneDict needs to be implemented # instead of checking inside of makeScene, makeSceneNxR, and makeScene1axis - assert trackerdict[-5.0]['radfile'][0:7] == 'objects' # 'objects\\1axis-5.0_1.825_11.42_5.0_10x3_origin0,0.rad' + assert trackerdict[-5.0]['scenes'][0].radfiles[0:7] == 'objects' # 'objects\\1axis-5.0_1.825_11.42_5.0_10x3_origin0,0.rad' sceneDict = {'pitch': pitch,'clearance_height':hub_height, 'nMods':10, 'nRows':3} # testing height filter too trackerdict = demo.makeScene1axis(sceneDict=sceneDict, module = 'test-module') @@ -230,18 +230,20 @@ def test_1axis_gencumSky(): # assert trackerdict[-5.0]['radfile'] == 'objects\\1axis-5.0_1.825_11.42_5.0_10x3_origin0,0.rad' sceneDict = {'pitch': pitch,'height':hub_height, 'hub_height':hub_height, 'nMods':10, 'nRows':3} # testing height filter too trackerdict = demo.makeScene1axis(sceneDict=sceneDict, module = 'test-module') + assert trackerdict[-5.0]['scenes'].__len__() == 5 + demo.exportTrackerDict(trackerdict, savefile = 'results\exportedTrackerDict2.csv') - assert trackerdict[-5.0]['radfile'][0:7] == 'objects' + assert trackerdict[-5.0]['scenes'][4].radfiles[0:7] == 'objects' #assert trackerdict[-5.0]['radfile'] == 'objects\\1axis-5.0_1.825_11.42_5.0_10x3_origin0,0.rad' minitrackerdict = {} minitrackerdict[list(trackerdict)[0]] = trackerdict[list(trackerdict.keys())[0]] trackerdict = demo.makeOct1axis(trackerdict=minitrackerdict) # just run this for one timestep: Jan 1 11am - trackerdict = demo.analysis1axis(trackerdict=trackerdict, modWanted=7, rowWanted=3, sensorsy=2) + trackerdict = demo.analysis1axis(trackerdict=trackerdict, modWanted=7, rowWanted=3, sensorsy=2, sceneNum=4) assert trackerdict[-5.0]['Results'][0]['AnalysisObj'].x[0] == -10.76304 modscanfront = {} modscanfront = {'xstart': -5} - trackerdict = demo.analysis1axis(trackerdict=trackerdict, modWanted=7, rowWanted=3, sensorsy=2, modscanfront=modscanfront ) - assert trackerdict[-5.0]['Results'][0]['AnalysisObj'].x[0] == -5 + trackerdict = demo.analysis1axis(trackerdict=trackerdict, modWanted=7, rowWanted=3, sensorsy=2, modscanfront=modscanfront, sceneNum=4) + assert trackerdict[-5.0]['Results'][1]['AnalysisObj'].x[0] == -5 From a97f89d99b914b891de3b2f93007f28567505edb Mon Sep 17 00:00:00 2001 From: cdeline Date: Fri, 10 Nov 2023 11:41:48 -0700 Subject: [PATCH 7/8] update whatsnew/pending.rst --- docs/sphinx/source/whatsnew/pending.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/sphinx/source/whatsnew/pending.rst b/docs/sphinx/source/whatsnew/pending.rst index c487c41e..b339748e 100644 --- a/docs/sphinx/source/whatsnew/pending.rst +++ b/docs/sphinx/source/whatsnew/pending.rst @@ -12,10 +12,12 @@ API Changes *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`) *To support multiple modules and row scans for 1axis simulations, outputs like Wm2Front are now stored in ``trackerdict``.``Results`` (:issue:`405`)(:pull:`408`) * ``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' +* ``scene.appendtoscene`` functionality added (add more detail here, fix hyperlinks) + Enhancements ~~~~~~~~~~~~ - +* multiple sceneObjects are tracked by the RadianceObj now. New function :py:class:`~bifacial_radiance.RadianceObj.sceneNames` will return the list of scenes being tracked. From fd15425bfddb618957452dec7d37763cd1150da7 Mon Sep 17 00:00:00 2001 From: cdeline Date: Mon, 27 Nov 2023 10:52:06 -0700 Subject: [PATCH 8/8] Update todo items --- bifacial_radiance/main.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bifacial_radiance/main.py b/bifacial_radiance/main.py index 5eab160b..c720d3e8 100644 --- a/bifacial_radiance/main.py +++ b/bifacial_radiance/main.py @@ -2492,7 +2492,8 @@ def makeScene(self, module=None, sceneDict=None, radname=None, sceneRAD = scene._makeSceneNxR(sceneDict=sceneDict, radname=radname) - # TODO: move appendRadfile logic to SceneObj... + # TODO: deprecate this section in favor of multiple sceneObjs + # if 'appendRadfile' not in sceneDict: appendRadfile = False else: @@ -2513,10 +2514,12 @@ def makeScene(self, module=None, sceneDict=None, radname=None, print( "Radfile APPENDAGE created!") else: scene.radfiles = [sceneRAD] - + #TODO: change appendtoScene kwarg to customObject kwarg. keep appendtoScene as deprecated input if appendtoScene is not None: self.appendtoScene(scene.radfiles[0], customObject = appendtoScene) + # TODO: what's the desired default behavior here? + # Do we append a new scene by default, or overwrite? self.scenes.append(scene) return scene