From e1ac5a3b91e176d879199c1f47a648611af11a6d Mon Sep 17 00:00:00 2001 From: cdeline Date: Tue, 3 Sep 2024 10:31:23 -0600 Subject: [PATCH] check for weird CECMod DataFrame orientation; more pytests --- bifacial_radiance/data/module.json | 65 ++++++++++++------------------ bifacial_radiance/module.py | 15 +++++-- tests/test_module.py | 31 ++++++++++---- tests/test_performance.py | 19 ++++++--- 4 files changed, 74 insertions(+), 56 deletions(-) diff --git a/bifacial_radiance/data/module.json b/bifacial_radiance/data/module.json index f75b3954..61c80902 100644 --- a/bifacial_radiance/data/module.json +++ b/bifacial_radiance/data/module.json @@ -62,51 +62,38 @@ "z": 0.02, "zgap": 0.1 }, + "test": { + "bifi": 1, + "glass": false, + "modulefile": "objects\\test.rad", + "modulematerial": "black", + "numpanels": 1, + "offsetfromaxis": 0, + "scenex": 1.6, + "sceney": 0.95, + "scenez": 0.1, + "text": "! genbox black test 1.59 0.95 0.02 | xform -t -0.795 -0.475 0 -a 1 -t 0 0.95 0", + "x": 1.59, + "xgap": 0.01, + "y": 0.95, + "ygap": 0.0, + "z": 0.02, + "zgap": 0.1 + }, "test-module": { "bifi": 1, - "cellModule": { - "centerJB": null, - "numcellsx": 6, - "numcellsy": 10, - "xcell": 0.156, - "xcellgap": 0.02, - "ycell": 0.156, - "ycellgap": 0.02 - }, - "frameParams": { - "frame_material": "Metal_Grey", - "frame_thickness": 0.003, - "frame_width": 0.05, - "frame_z": 0.03, - "nSides_frame": 4 - }, - "glass": true, + "glass": false, "modulefile": "objects\\test-module.rad", "modulematerial": "black", "numpanels": 1, - "offsetfromaxis": 0.18, - "omegaParams": { - "inverted": true, - "mod_overlap": 0.003, - "omega_material": "Metal_Grey", - "omega_thickness": 0.004, - "x_omega1": 0.005, - "x_omega3": 0.0015, - "y_omega": 0.5 - }, - "scenex": 1.046, - "sceney": 1.74, - "scenez": 0.15, - "text": "! genbox black cellPVmodule 0.156 0.156 0.02 | xform -t -0.44 -0.87 0.18 -a 6 -t 0.176 0 0 -a 10 -t 0 0.176 0 -a 1 -t 0 1.74 0\r\n! genrev Metal_Grey tube1 t*1.046 0.05 32 | xform -ry 90 -t -0.445 0 0\r\n! genbox stock_glass test-module_Glass 1.046 1.75 0.01 | xform -t -0.445 -0.875 0.175 -a 1 -t 0 1.74 0\r\n! genbox Metal_Grey frameside 0.003 1.74 0.03 | xform -t -0.518 -0.87 0.145 -a 1 -t 0 1.74 0 | xform -rz 0\r\n! genbox Metal_Grey frameleg 0.047 1.74 0.003 | xform -t -0.515 -0.87 0.145 -a 1 -t 0 1.74 0 | xform -rz 0\r\n! genbox Metal_Grey frameside 0.003 1.74 0.03 | xform -t 0.515 -0.87 0.145 -a 1 -t 0 1.74 0 | xform -rz 0\r\n! genbox Metal_Grey frameleg 0.047 1.74 0.003 | xform -t 0.468 -0.87 0.145 -a 1 -t 0 1.74 0 | xform -rz 0\r\n! genbox Metal_Grey frameside 1.03 0.003 0.027 | xform -t -0.515 0.867 0.148 -a 1 -t 0 1.74 0\r\n! genbox Metal_Grey frameleg 0.936 0.05 0.003 | xform -t -0.468 0.82 0.145 -a 1 -t 0 1.74 0\r\n! genbox Metal_Grey frameside 1.03 0.003 0.027 | xform -t -0.515 -0.87 0.148 -a 1 -t 0 1.74 0\r\n! genbox Metal_Grey frameleg 0.936 0.05 0.003 | xform -t -0.468 -0.87 0.145 -a 1 -t 0 1.74 0\r\n! genbox Metal_Grey mod_adj 0.005 0.5 0.004 | xform -t 0.515 -0.25 0.141\r\n! genbox Metal_Grey verti 0.004 0.5 0.1 | xform -t 0.5150000000000001 -0.25 0.04499999999999999\r\n! genbox Metal_Grey tt_adj 0.0015 0.5 0.004 | xform -t 0.5135000000000002 -0.25 0.04499999999999999\r\n! genbox Metal_Grey mod_adj 0.005 0.5 0.004 | xform -t -0.52 -0.25 0.141\r\n! genbox Metal_Grey verti 0.004 0.5 0.1 | xform -t -0.5190000000000001 -0.25 0.04499999999999999\r\n! genbox Metal_Grey tt_adj 0.0015 0.5 0.004 | xform -t -0.5150000000000001 -0.25 0.04499999999999999", - "torquetube": { - "diameter": 0.1, - "material": "Metal_Grey", - "tubetype": "Round", - "visible": true - }, - "x": 1.036, + "offsetfromaxis": 0, + "scenex": 1.01, + "sceney": 2.0, + "scenez": 0.1, + "text": "! genbox black test-module 1 2 0.02 | xform -t -0.5 -1.0 0 -a 1 -t 0 2.0 0", + "x": 1, "xgap": 0.01, - "y": 1.74, + "y": 2, "ygap": 0.0, "z": 0.02, "zgap": 0.1 diff --git a/bifacial_radiance/module.py b/bifacial_radiance/module.py index 7be28f14..6c514f2c 100644 --- a/bifacial_radiance/module.py +++ b/bifacial_radiance/module.py @@ -214,7 +214,9 @@ def compileText(self, rewriteModulefile=True, json=True): if hasattr(self,'omega'): saveDict = {**saveDict, 'omegaParams':self.omega.getDataDict()} if hasattr(self,'frame'): - saveDict = {**saveDict, 'frameParams':self.frame.getDataDict()} + saveDict = {**saveDict, 'frameParams':self.frame.getDataDict()} + if getattr(self, 'CECMod', None) is not None: + saveDict = {**saveDict, 'CECMod':self.CECMod.getDataDict()} self._makeModuleFromDict(**saveDict) @@ -710,8 +712,12 @@ def addCEC(self, CECMod, glassglass=False, bifi=None): self.glassglass = glassglass if bifi: self.bifi = bifi + if type(CECMod) == pd.DataFrame: + # Check for attributes along the index and transpose + if 'alpha_sc' in CECMod.index: + CECMod = CECMod.T if len(CECMod) > 1: print('Warning: DataFrame with multiple rows passed to module.addCEC. '\ 'Taking the first entry') @@ -725,9 +731,12 @@ def addCEC(self, CECMod, glassglass=False, bifi=None): elif type(CECMod) == dict: CECModDict = CECMod elif type(CECMod) == str: - print('Error: string-based module selection is not yet enabled. '\ + raise Exception('Error: string-based module selection is not yet enabled. '\ 'Try back later!') return + elif CECMod is None: + self.CECMod = None + return else: raise Exception(f"Unrecognized type '{type(CECMod)}' passed into addCEC ") @@ -780,7 +789,7 @@ def calculatePerformance(self, effective_irradiance, CECMod=None, db = pd.read_csv(url, index_col=0) # Reading this might take 1 min or so, the database is big. modfilter2 = db.index.str.startswith('Pr') & db.index.str.endswith('BHC72-400') CECMod = db[modfilter2] - self.CECMod = CECMod + self.addCEC(CECMod) if hasattr(self, 'glassglass') and glassglass is None: glassglass = self.glassglass diff --git a/tests/test_module.py b/tests/test_module.py index a974b51d..1b9ebb1a 100644 --- a/tests/test_module.py +++ b/tests/test_module.py @@ -149,14 +149,29 @@ def test_moduleFrameandOmegas(): assert backscan['xstart'] == pytest.approx(0.792) def test_CECmodule(): - # Test adding CEC module - # TODO: test passing CECMod as a DF. update to module.calcPerformance... - # todo: test unknown type passed exception. test missing required key passed - #p_mp_celltemp2 = bifacial_radiance.performance.calculatePerformance(s1, pd.DataFrame([CECMod]),temp_cell=s2) - #p_mp_celltemp3 = bifacial_radiance.performance.calculatePerformance(s1, pd.DataFrame([CECMod, CECMod]),temp_cell=s2) - #assert p_mp_celltemp3.all()==p_mp_celltemp2.all()==p_mp_celltemp.all() + # Test adding CEC module in various ways CECMod1 = pd.read_csv(os.path.join(TESTDIR, 'Canadian_Solar_Inc__CS5P_220M.csv'), - index_col=0).iloc[:,0] + index_col=0) #1D dataframe + CECMod2 = CECMod1.iloc[:,0] #pd.Series + CECMod3 = CECMod2.to_dict() + CECMod4 = pd.concat([CECMod1.T, CECMod1.T]) module = bifacial_radiance.ModuleObj(name='test-module',x=2, y=1, CECMod=CECMod1 ) - + module.addCEC(CECMod2) + module3 = bifacial_radiance.ModuleObj(name='test-module',x=2, y=1, CECMod=CECMod3 ) + module4 = bifacial_radiance.ModuleObj(name='test-module',x=2, y=1, CECMod=CECMod4 ) + assert module4.CECMod.name=='Canadian_Solar_Inc__CS5P_220M' + # check for exceptions + with pytest.raises(Exception): + CECMod3.pop('alpha_sc') + module.addCEC(CECMod3) + with pytest.raises(Exception): #when module search function is enabled, this can be updated.. + module.addCEC('Canadian_Solar_Inc__CS5P_220M') + with pytest.raises(Exception): + module.addCEC(1) + # check that CECMod is loaded in from module.json + module2 = bifacial_radiance.ModuleObj(name='test-module' ) + assert module.CECMod.alpha_sc == module2.CECMod.alpha_sc == module3.CECMod.alpha_sc == module4.CECMod.alpha_sc + +def test_modulePerformance(): + module = bifacial_radiance.ModuleObj(name='test-module',x=2, y=1) \ No newline at end of file diff --git a/tests/test_performance.py b/tests/test_performance.py index 0f8adf8e..0bf1af6f 100644 --- a/tests/test_performance.py +++ b/tests/test_performance.py @@ -32,6 +32,7 @@ # TODO: write test sequence for RadianceObj.calculateResults1axis # TODO: write test sequence for performance.calculateResults # TODO: write test sequence for performance.calculateResultsGencumsky1axis +# TODO: write for line 317-333 and 429 if csvfile is not None: def test_calculatePerformance(): @@ -47,15 +48,21 @@ def test_calculatePerformance(): #CECMODS = pvlib.pvsystem.retrieve_sam(name='CECMod') #CECMod = CECMODS['Canadian_Solar_Inc__CS5P_220M'] CECMod = pd.read_csv(os.path.join(TESTDIR, 'Canadian_Solar_Inc__CS5P_220M.csv'), - index_col=0).iloc[:,0] - module = bifacial_radiance.ModuleObj('test-module') - module.addCEC(CECMod = CECMod) + index_col=0) + module = bifacial_radiance.ModuleObj('test-module', x=1, y=2) + # check default Prism data p_mp_celltemp = module.calculatePerformance(s1, temp_cell=s2) - - assert p_mp_celltemp[0] == pytest.approx(219.96093865) + assert module.CECMod.name == 'Prism Solar Technologies Inc. BHC72-400' + assert module.CECMod.I_L_ref == '10.5308' + assert p_mp_celltemp[0] == pytest.approx(400.000, abs=0.001) + + module.addCEC(CECMod=CECMod) + p_mp_celltemp = module.calculatePerformance(s1, temp_cell=s2) + assert module.CECMod.name == 'Canadian_Solar_Inc__CS5P_220M' + assert p_mp_celltemp[0] == pytest.approx(219.9609, abs=0.0001) p_mp_tamb = module.calculatePerformance(s1, temp_air=s3, wind_speed=1, glassglass=True) assert p_mp_tamb[0] == pytest.approx(190.4431, abs=.0001) - module.addCEC(CECMod = None) + module.addCEC(CECMod = None) # default Prism data assert module.calculatePerformance(s1, temp_cell=s2)[0] == pytest.approx(399.99, abs = 0.03)