def test_perez(): AM = atmosphere.relativeairmass(ephem_data['apparent_zenith']) irradiance.perez(40, 180, irrad_data['DHI'], irrad_data['DNI'], dni_et, ephem_data['apparent_zenith'], ephem_data['apparent_azimuth'], AM)
def test_perez_components(irrad_data, ephem_data, dni_et, relative_airmass): dni = irrad_data['dni'].copy() dni.iloc[2] = np.nan out = irradiance.perez(40, 180, irrad_data['dhi'], dni, dni_et, ephem_data['apparent_zenith'], ephem_data['azimuth'], relative_airmass, return_components=True) expected = pd.DataFrame( np.array([[0., 31.46046871, np.nan, 45.45539877], [0., 26.84138589, np.nan, 31.72696071], [0., 0., np.nan, 4.47966439], [0., 4.62212181, np.nan, 9.25316454]]).T, columns=['sky_diffuse', 'isotropic', 'circumsolar', 'horizon'], index=irrad_data.index) expected_for_sum = expected['sky_diffuse'].copy() expected_for_sum.iloc[2] = 0 sum_components = out.iloc[:, 1:].sum(axis=1) sum_components.name = 'sky_diffuse' assert_frame_equal(out, expected, check_less_precise=2) assert_series_equal(sum_components, expected_for_sum, check_less_precise=2)
def test_perez_components(): am = atmosphere.relativeairmass(ephem_data['apparent_zenith']) dni = irrad_data['dni'].copy() dni.iloc[2] = np.nan out, df_components = irradiance.perez(40, 180, irrad_data['dhi'], dni, dni_et, ephem_data['apparent_zenith'], ephem_data['azimuth'], am, return_components=True) expected = pd.Series(np.array([0., 31.46046871, np.nan, 45.45539877]), index=times) expected_components = pd.DataFrame( np.array([[0., 26.84138589, np.nan, 31.72696071], [0., 0., np.nan, 4.47966439], [0., 4.62212181, np.nan, 9.25316454]]).T, columns=['isotropic', 'circumsolar', 'horizon'], index=times) sum_components = df_components.sum(axis=1) assert_series_equal(out, expected, check_less_precise=2) assert_frame_equal(df_components, expected_components) assert_series_equal(sum_components, expected, check_less_precise=2)
def test_perez_components(): am = atmosphere.relativeairmass(ephem_data['apparent_zenith']) dni = irrad_data['dni'].copy() dni.iloc[2] = np.nan out, df_components = irradiance.perez(40, 180, irrad_data['dhi'], dni, dni_et, ephem_data['apparent_zenith'], ephem_data['azimuth'], am, return_components=True) expected = pd.Series(np.array( [ 0. , 31.46046871, np.nan, 45.45539877]), index=times) expected_components = pd.DataFrame( np.array([[ 0. , 26.84138589, np.nan, 31.72696071], [ 0. , 0. , np.nan, 4.47966439], [ 0. , 4.62212181, np.nan, 9.25316454]]).T, columns=['isotropic', 'circumsolar', 'horizon'], index=times ) if pandas_0_22(): expected_for_sum = expected.copy() expected_for_sum.iloc[2] = 0 else: expected_for_sum = expected sum_components = df_components.sum(axis=1) assert_series_equal(out, expected, check_less_precise=2) assert_frame_equal(df_components, expected_components) assert_series_equal(sum_components, expected_for_sum, check_less_precise=2)
def test_perez_components(irrad_data, ephem_data, dni_et, relative_airmass): dni = irrad_data['dni'].copy() dni.iloc[2] = np.nan out = irradiance.perez(40, 180, irrad_data['dhi'], dni, dni_et, ephem_data['apparent_zenith'], ephem_data['azimuth'], relative_airmass, return_components=True) expected = pd.DataFrame(np.array( [[ 0. , 31.46046871, np.nan, 45.45539877], [ 0. , 26.84138589, np.nan, 31.72696071], [ 0. , 0. , np.nan, 4.47966439], [ 0. , 4.62212181, np.nan, 9.25316454]]).T, columns=['sky_diffuse', 'isotropic', 'circumsolar', 'horizon'], index=irrad_data.index ) if pandas_0_22(): expected_for_sum = expected['sky_diffuse'].copy() expected_for_sum.iloc[2] = 0 else: expected_for_sum = expected['sky_diffuse'] sum_components = out.iloc[:, 1:].sum(axis=1) sum_components.name = 'sky_diffuse' assert_frame_equal(out, expected, check_less_precise=2) assert_series_equal(sum_components, expected_for_sum, check_less_precise=2)
def test_perez_scalar(): # copied values from fixtures out = irradiance.perez(40, 180, 118.45831879, 939.95469881, 1321.1655834833093, 10.56413562, 144.76567754, 1.01688136) # this will fail. out is ndarry with ndim == 0. fix in future version. # assert np.isscalar(out) assert_allclose(out, 109.084332)
def test_perez_arrays(): am = atmosphere.relativeairmass(ephem_data['apparent_zenith']) dni = irrad_data['dni'].copy() dni.iloc[2] = np.nan out = irradiance.perez(40, 180, irrad_data['dhi'].values, dni.values, dni_et, ephem_data['apparent_zenith'].values, ephem_data['azimuth'].values, am.values) expected = np.array([0., 31.46046871, np.nan, 45.45539877]) assert_allclose(out, expected, atol=1e-2)
def test_perez(irrad_data, ephem_data, dni_et, relative_airmass): dni = irrad_data['dni'].copy() dni.iloc[2] = np.nan out = irradiance.perez(40, 180, irrad_data['dhi'], dni, dni_et, ephem_data['apparent_zenith'], ephem_data['azimuth'], relative_airmass) expected = pd.Series(np.array([0., 31.46046871, np.nan, 45.45539877]), index=irrad_data.index) assert_series_equal(out, expected, check_less_precise=2)
def test_perez_arrays(): am = atmosphere.relativeairmass(ephem_data['apparent_zenith']) dni = irrad_data['dni'].copy() dni.iloc[2] = np.nan out = irradiance.perez(40, 180, irrad_data['dhi'].values, dni.values, dni_et, ephem_data['apparent_zenith'].values, ephem_data['azimuth'].values, am.values) expected = np.array( [ 0. , 31.46046871, np.nan, 45.45539877]) assert_allclose(out, expected, atol=1e-2)
def test_perez(irrad_data, ephem_data, dni_et, relative_airmass): dni = irrad_data['dni'].copy() dni.iloc[2] = np.nan out = irradiance.perez(40, 180, irrad_data['dhi'], dni, dni_et, ephem_data['apparent_zenith'], ephem_data['azimuth'], relative_airmass) expected = pd.Series(np.array( [ 0. , 31.46046871, np.nan, 45.45539877]), index=irrad_data.index) assert_series_equal(out, expected, check_less_precise=2)
def test_perez_arrays(irrad_data, ephem_data, dni_et, relative_airmass): dni = irrad_data['dni'].copy() dni.iloc[2] = np.nan out = irradiance.perez(40, 180, irrad_data['dhi'].values, dni.values, dni_et, ephem_data['apparent_zenith'].values, ephem_data['azimuth'].values, relative_airmass.values) expected = np.array([0., 31.46046871, np.nan, 45.45539877]) assert_allclose(out, expected, atol=1e-2) assert isinstance(out, np.ndarray)
def test_perez_arrays(irrad_data, ephem_data, dni_et, relative_airmass): dni = irrad_data['dni'].copy() dni.iloc[2] = np.nan out = irradiance.perez(40, 180, irrad_data['dhi'].values, dni.values, dni_et, ephem_data['apparent_zenith'].values, ephem_data['azimuth'].values, relative_airmass.values) expected = np.array( [ 0. , 31.46046871, np.nan, 45.45539877]) assert_allclose(out, expected, atol=1e-2) assert isinstance(out, np.ndarray)
def test_globalinplane(): aoi = irradiance.aoi(40, 180, ephem_data['apparent_zenith'], ephem_data['azimuth']) airmass = atmosphere.relativeairmass(ephem_data['apparent_zenith']) gr_sand = irradiance.grounddiffuse(40, ghi, surface_type='sand') diff_perez = irradiance.perez( 40, 180, irrad_data['dhi'], irrad_data['dni'], dni_et, ephem_data['apparent_zenith'], ephem_data['azimuth'], airmass) irradiance.globalinplane( aoi=aoi, dni=irrad_data['dni'], poa_sky_diffuse=diff_perez, poa_ground_diffuse=gr_sand)
def test_globalinplane(): AOI = irradiance.aoi(40, 180, ephem_data['apparent_zenith'], ephem_data['apparent_azimuth']) AM = atmosphere.relativeairmass(ephem_data['apparent_zenith']) gr_sand = irradiance.grounddiffuse(40, ghi, surface_type='sand') diff_perez = irradiance.perez( 40, 180, irrad_data['DHI'], irrad_data['DNI'], dni_et, ephem_data['apparent_zenith'], ephem_data['apparent_azimuth'], AM) irradiance.globalinplane( AOI=AOI, DNI=irrad_data['DNI'], In_Plane_SkyDiffuse=diff_perez, GR=gr_sand)
def test_globalinplane(): aoi = irradiance.aoi(40, 180, ephem_data['apparent_zenith'], ephem_data['apparent_azimuth']) airmass = atmosphere.relativeairmass(ephem_data['apparent_zenith']) gr_sand = irradiance.grounddiffuse(40, ghi, surface_type='sand') diff_perez = irradiance.perez( 40, 180, irrad_data['dhi'], irrad_data['dni'], dni_et, ephem_data['apparent_zenith'], ephem_data['apparent_azimuth'], airmass) irradiance.globalinplane( aoi=aoi, dni=irrad_data['dni'], poa_sky_diffuse=diff_perez, poa_ground_diffuse=gr_sand)
def test_globalinplane(): AOI = irradiance.aoi(40, 180, ephem_data['apparent_zenith'], ephem_data['apparent_azimuth']) AM = atmosphere.relativeairmass(ephem_data['apparent_zenith']) gr_sand = irradiance.grounddiffuse(40, ghi, surface_type='sand') diff_perez = irradiance.perez(40, 180, irrad_data['DHI'], irrad_data['DNI'], dni_et, ephem_data['apparent_zenith'], ephem_data['apparent_azimuth'], AM) irradiance.globalinplane(AOI=AOI, DNI=irrad_data['DNI'], In_Plane_SkyDiffuse=diff_perez, GR=gr_sand)
def test_perez_negative_horizon(): times = pd.date_range(start='20190101 11:30:00', freq='1H', periods=5, tz='US/Central') # Avoid test dependencies on functionality not being tested by hard-coding # the inputs. This data corresponds to Goodwin Creek in the afternoon on # 1/1/2019. # dni_e is slightly rounded from irradiance.get_extra_radiation # airmass from atmosphere.get_relative_airmas inputs = pd.DataFrame( np.array([[158, 19, 1, 0, 0], [249, 165, 136, 93, 50], [57.746951, 57.564205, 60.813841, 66.989435, 75.353368], [171.003315, 187.346924, 202.974357, 216.725599, 228.317233], [1414, 1414, 1414, 1414, 1414], [1.869315, 1.859981, 2.044429, 2.544943, 3.900136]]).T, columns=[ 'dni', 'dhi', 'solar_zenith', 'solar_azimuth', 'dni_extra', 'airmass' ], index=times) out = irradiance.perez(34, 180, inputs['dhi'], inputs['dni'], inputs['dni_extra'], inputs['solar_zenith'], inputs['solar_azimuth'], inputs['airmass'], model='allsitescomposite1990', return_components=True) # sky_diffuse can be less than isotropic under certain conditions as # horizon goes negative expected = pd.DataFrame( np.array([[281.410185, 152.20879, 123.867898, 82.836412, 43.517015], [166.785419, 142.24475, 119.173875, 83.525150, 45.725931], [113.548755, 16.09757, 9.956174, 3.142467, 0], [1.076010, -6.13353, -5.262151, -3.831230, -2.208923]]).T, columns=['sky_diffuse', 'isotropic', 'circumsolar', 'horizon'], index=times) expected_for_sum = expected['sky_diffuse'].copy() sum_components = out.iloc[:, 1:].sum(axis=1) sum_components.name = 'sky_diffuse' assert_frame_equal(out, expected, check_less_precise=2) assert_series_equal(sum_components, expected_for_sum, check_less_precise=2)
def test_poa_components(irrad_data, ephem_data, dni_et, relative_airmass): aoi = irradiance.aoi(40, 180, ephem_data['apparent_zenith'], ephem_data['azimuth']) gr_sand = irradiance.get_ground_diffuse(40, irrad_data['ghi'], surface_type='sand') diff_perez = irradiance.perez( 40, 180, irrad_data['dhi'], irrad_data['dni'], dni_et, ephem_data['apparent_zenith'], ephem_data['azimuth'], relative_airmass) out = irradiance.poa_components( aoi, irrad_data['dni'], diff_perez, gr_sand) expected = pd.DataFrame(np.array( [[ 0. , -0. , 0. , 0. , 0. ], [ 35.19456561, 0. , 35.19456561, 31.4635077 , 3.73105791], [956.18253696, 798.31939281, 157.86314414, 109.08433162, 48.77881252], [ 90.99624896, 33.50143401, 57.49481495, 45.45978964, 12.03502531]]), columns=['poa_global', 'poa_direct', 'poa_diffuse', 'poa_sky_diffuse', 'poa_ground_diffuse'], index=irrad_data.index) assert_frame_equal(out, expected)
def test_poa_components(irrad_data, ephem_data, dni_et, relative_airmass): aoi = irradiance.aoi(40, 180, ephem_data['apparent_zenith'], ephem_data['azimuth']) gr_sand = irradiance.get_ground_diffuse(40, irrad_data['ghi'], surface_type='sand') diff_perez = irradiance.perez(40, 180, irrad_data['dhi'], irrad_data['dni'], dni_et, ephem_data['apparent_zenith'], ephem_data['azimuth'], relative_airmass) out = irradiance.poa_components(aoi, irrad_data['dni'], diff_perez, gr_sand) expected = pd.DataFrame(np.array( [[0., -0., 0., 0., 0.], [35.19456561, 0., 35.19456561, 31.4635077, 3.73105791], [956.18253696, 798.31939281, 157.86314414, 109.08433162, 48.77881252], [90.99624896, 33.50143401, 57.49481495, 45.45978964, 12.03502531]]), columns=[ 'poa_global', 'poa_direct', 'poa_diffuse', 'poa_sky_diffuse', 'poa_ground_diffuse' ], index=irrad_data.index) assert_frame_equal(out, expected)
def test_perez(): AM = atmosphere.relativeairmass(ephem_data['apparent_zenith']) irradiance.perez(40, 180, irrad_data['dhi'], irrad_data['dni'], dni_et, ephem_data['apparent_zenith'], ephem_data['apparent_azimuth'], AM)
def test_perez(): am = atmosphere.relativeairmass(ephem_data['apparent_zenith']) out = irradiance.perez(40, 180, irrad_data['dhi'], irrad_data['dni'], dni_et, ephem_data['apparent_zenith'], ephem_data['azimuth'], am) assert not out.isnull().any()
def perez_diffuse_luminance(timestamps, surface_tilt, surface_azimuth, solar_zenith, solar_azimuth, dni, dhi): """Function used to calculate the luminance and the view factor terms from the Perez diffuse light transposition model, as implemented in the ``pvlib-python`` library. This function was custom made to allow the calculation of the circumsolar component on the back surface as well. Otherwise, the ``pvlib`` implementation would ignore it. Parameters ---------- timestamps : array-like simulation timestamps surface_tilt : array-like Surface tilt angles in decimal degrees. surface_tilt must be >=0 and <=180. The tilt angle is defined as degrees from horizontal (e.g. surface facing up = 0, surface facing horizon = 90) surface_azimuth : array-like The azimuth of the rotated panel, determined by projecting the vector normal to the panel's surface to the earth's surface [degrees]. solar_zenith : array-like solar zenith angles solar_azimuth : array-like solar azimuth angles dni : array-like values for direct normal irradiance dhi : array-like values for diffuse horizontal irradiance Returns ------- df_inputs : `pandas.DataFrame` Dataframe with the following columns: ['solar_zenith', 'solar_azimuth', 'surface_tilt', 'surface_azimuth', 'dhi', 'dni', 'vf_horizon', 'vf_circumsolar', 'vf_isotropic', 'luminance_horizon', 'luminance_circuqmsolar', 'luminance_isotropic', 'poa_isotropic', 'poa_circumsolar', 'poa_horizon', 'poa_total_diffuse'] """ # Create a dataframe to help filtering on all arrays df_inputs = pd.DataFrame( { 'surface_tilt': surface_tilt, 'surface_azimuth': surface_azimuth, 'solar_zenith': solar_zenith, 'solar_azimuth': solar_azimuth, 'dni': dni, 'dhi': dhi }, index=pd.DatetimeIndex(timestamps)) dni_et = irradiance.get_extra_radiation(df_inputs.index.dayofyear) am = atmosphere.get_relative_airmass(df_inputs.solar_zenith) # Need to treat the case when the sun is hitting the back surface of pvrow aoi_proj = irradiance.aoi_projection(df_inputs.surface_tilt, df_inputs.surface_azimuth, df_inputs.solar_zenith, df_inputs.solar_azimuth) sun_hitting_back_surface = ((aoi_proj < 0) & (df_inputs.solar_zenith <= 90)) df_inputs_back_surface = df_inputs.loc[sun_hitting_back_surface].copy() # Reverse the surface normal to switch to back-surface circumsolar calc df_inputs_back_surface.loc[:, 'surface_azimuth'] = ( df_inputs_back_surface.loc[:, 'surface_azimuth'] - 180.) df_inputs_back_surface.loc[:, 'surface_azimuth'] = np.mod( df_inputs_back_surface.loc[:, 'surface_azimuth'], 360.) df_inputs_back_surface.loc[:, 'surface_tilt'] = ( 180. - df_inputs_back_surface.surface_tilt) if df_inputs_back_surface.shape[0] > 0: # Use recursion to calculate circumsolar luminance for back surface df_inputs_back_surface = perez_diffuse_luminance( *breakup_df_inputs(df_inputs_back_surface)) # Calculate Perez diffuse components components = irradiance.perez(df_inputs.surface_tilt, df_inputs.surface_azimuth, df_inputs.dhi, df_inputs.dni, dni_et, df_inputs.solar_zenith, df_inputs.solar_azimuth, am, return_components=True) # Calculate Perez view factors: a = irradiance.aoi_projection(df_inputs.surface_tilt, df_inputs.surface_azimuth, df_inputs.solar_zenith, df_inputs.solar_azimuth) a = np.maximum(a, 0) b = cosd(df_inputs.solar_zenith) b = np.maximum(b, cosd(85)) vf_perez = pd.DataFrame( { 'vf_horizon': sind(df_inputs.surface_tilt), 'vf_circumsolar': a / b, 'vf_isotropic': (1. + cosd(df_inputs.surface_tilt)) / 2. }, index=df_inputs.index) # Calculate diffuse luminance luminance = pd.DataFrame(np.array([ components['horizon'] / vf_perez['vf_horizon'], components['circumsolar'] / vf_perez['vf_circumsolar'], components['isotropic'] / vf_perez['vf_isotropic'] ]).T, index=df_inputs.index, columns=[ 'luminance_horizon', 'luminance_circumsolar', 'luminance_isotropic' ]) luminance.loc[components['sky_diffuse'] == 0, :] = 0. # Format components column names components = components.rename( columns={ 'isotropic': 'poa_isotropic', 'circumsolar': 'poa_circumsolar', 'horizon': 'poa_horizon' }) df_inputs = pd.concat([df_inputs, components, vf_perez, luminance], axis=1, join='outer') df_inputs = df_inputs.rename(columns={'sky_diffuse': 'poa_total_diffuse'}) # Adjust the circumsolar luminance when it hits the back surface if df_inputs_back_surface.shape[0] > 0: df_inputs.loc[sun_hitting_back_surface, 'luminance_circumsolar'] = ( df_inputs_back_surface.loc[:, 'luminance_circumsolar']) return df_inputs
def perez_diffuse_luminance(timestamps, array_tilt, array_azimuth, solar_zenith, solar_azimuth, dni, dhi): """ Function used to calculate the luminance and the view factor terms from the Perez diffuse light transposition model, as implemented in the ``pvlib-python`` library. This function was custom made to allow the calculation of the circumsolar component on the back surface as well. Otherwise, the ``pvlib`` implementation would ignore it. :param array-like timestamps: simulation timestamps :param array-like array_tilt: pv module tilt angles :param array-like array_azimuth: pv array azimuth angles :param array-like solar_zenith: solar zenith angles :param array-like solar_azimuth: solar azimuth angles :param array-like dni: values for direct normal irradiance :param array-like dhi: values for diffuse horizontal irradiance :return: ``df_inputs``, dataframe with the following columns: ['solar_zenith', 'solar_azimuth', 'array_tilt', 'array_azimuth', 'dhi', 'dni', 'vf_horizon', 'vf_circumsolar', 'vf_isotropic', 'luminance_horizon', 'luminance_circumsolar', 'luminance_isotropic', 'poa_isotropic', 'poa_circumsolar', 'poa_horizon', 'poa_total_diffuse'] :rtype: class:`pandas.DataFrame` """ # Create a dataframe to help filtering on all arrays df_inputs = pd.DataFrame( { 'array_tilt': array_tilt, 'array_azimuth': array_azimuth, 'solar_zenith': solar_zenith, 'solar_azimuth': solar_azimuth, 'dni': dni, 'dhi': dhi }, index=pd.DatetimeIndex(timestamps)) dni_et = irradiance.extraradiation(df_inputs.index.dayofyear) am = atmosphere.relativeairmass(df_inputs.solar_zenith) # Need to treat the case when the sun is hitting the back surface of pvrow aoi_proj = aoi_projection(df_inputs.array_tilt, df_inputs.array_azimuth, df_inputs.solar_zenith, df_inputs.solar_azimuth) sun_hitting_back_surface = ((aoi_proj < 0) & (df_inputs.solar_zenith <= 90)) df_inputs_back_surface = df_inputs.loc[sun_hitting_back_surface] # Reverse the surface normal to switch to back-surface circumsolar calc df_inputs_back_surface.loc[:, 'array_azimuth'] -= 180. df_inputs_back_surface.loc[:, 'array_azimuth'] = np.mod( df_inputs_back_surface.loc[:, 'array_azimuth'], 360.) df_inputs_back_surface.loc[:, 'array_tilt'] = ( 180. - df_inputs_back_surface.array_tilt) if df_inputs_back_surface.shape[0] > 0: # Use recursion to calculate circumsolar luminance for back surface df_inputs_back_surface = perez_diffuse_luminance( *breakup_df_inputs(df_inputs_back_surface)) # Calculate Perez diffuse components diffuse_poa, components = irradiance.perez(df_inputs.array_tilt, df_inputs.array_azimuth, df_inputs.dhi, df_inputs.dni, dni_et, df_inputs.solar_zenith, df_inputs.solar_azimuth, am, return_components=True) # Calculate Perez view factors: a = aoi_projection(df_inputs.array_tilt, df_inputs.array_azimuth, df_inputs.solar_zenith, df_inputs.solar_azimuth) a = np.maximum(a, 0) b = cosd(df_inputs.solar_zenith) b = np.maximum(b, cosd(85)) vf_perez = pd.DataFrame( np.array([ sind(df_inputs.array_tilt), a / b, (1. + cosd(df_inputs.array_tilt)) / 2. ]).T, index=df_inputs.index, columns=['vf_horizon', 'vf_circumsolar', 'vf_isotropic']) # Calculate diffuse luminance luminance = pd.DataFrame(np.array([ components['horizon'] / vf_perez['vf_horizon'], components['circumsolar'] / vf_perez['vf_circumsolar'], components['isotropic'] / vf_perez['vf_isotropic'] ]).T, index=df_inputs.index, columns=[ 'luminance_horizon', 'luminance_circumsolar', 'luminance_isotropic' ]) luminance.loc[diffuse_poa == 0, :] = 0. # Format components column names components = components.rename( columns={ 'isotropic': 'poa_isotropic', 'circumsolar': 'poa_circumsolar', 'horizon': 'poa_horizon' }) df_inputs = pd.concat( [df_inputs, components, vf_perez, luminance, diffuse_poa], axis=1, join='outer') df_inputs = df_inputs.rename(columns={0: 'poa_total_diffuse'}) # Adjust the circumsolar luminance when it hits the back surface if df_inputs_back_surface.shape[0] > 0: df_inputs.loc[sun_hitting_back_surface, 'luminance_circumsolar'] = ( df_inputs_back_surface.loc[:, 'luminance_circumsolar']) return df_inputs
def test_perez_scalar(): # copied values from fixtures out = irradiance.perez(40, 180, 118.45831879, 939.95469881, 1321.1655834833093, 10.56413562, 144.76567754, 1.01688136) assert_allclose(out, 109.084332)
def perez_diffuse_luminance(df_inputs): """ Function used to calculate the luminance and the view factor terms from the Perez diffuse light transposition model, as implemented in the ``pvlib-python`` library. :param df_inputs: class:`pandas.DataFrame` with following columns: ['solar_zenith', 'solar_azimuth', 'array_tilt', 'array_azimuth', 'dhi', 'dni']. Units are: ['deg', 'deg', 'deg', 'deg', 'W/m2', 'W/m2'] :return: class:`pandas.DataFrame` with the following columns: ['solar_zenith', 'solar_azimuth', 'array_tilt', 'array_azimuth', 'dhi', 'dni', 'vf_horizon', 'vf_circumsolar', 'vf_isotropic', 'luminance_horizon', 'luminance_circumsolar', 'luminance_isotropic', 'poa_isotropic', 'poa_circumsolar', 'poa_horizon', 'poa_total_diffuse'] """ dni_et = irradiance.extraradiation(df_inputs.index.dayofyear) am = atmosphere.relativeairmass(df_inputs.solar_zenith) # Need to treat the case when the sun is hitting the back surface of pvrow aoi_proj = aoi_projection(df_inputs.array_tilt, df_inputs.array_azimuth, df_inputs.solar_zenith, df_inputs.solar_azimuth) sun_hitting_back_surface = ((aoi_proj < 0) & (df_inputs.solar_zenith <= 90)) df_inputs_back_surface = df_inputs.loc[sun_hitting_back_surface] # Reverse the surface normal to switch to back-surface circumsolar calc df_inputs_back_surface.loc[:, 'array_azimuth'] -= 180. df_inputs_back_surface.loc[:, 'array_azimuth'] = np.mod( df_inputs_back_surface.loc[:, 'array_azimuth'], 360. ) df_inputs_back_surface.loc[:, 'array_tilt'] = ( 180. - df_inputs_back_surface.array_tilt) if df_inputs_back_surface.shape[0] > 0: # Use recursion to calculate circumsolar luminance for back surface df_inputs_back_surface = perez_diffuse_luminance( df_inputs_back_surface) # Calculate Perez diffuse components diffuse_poa, components = irradiance.perez(df_inputs.array_tilt, df_inputs.array_azimuth, df_inputs.dhi, df_inputs.dni, dni_et, df_inputs.solar_zenith, df_inputs.solar_azimuth, am, return_components=True) # Calculate Perez view factors: a = aoi_projection(df_inputs.array_tilt, df_inputs.array_azimuth, df_inputs.solar_zenith, df_inputs.solar_azimuth) a = np.maximum(a, 0) b = cosd(df_inputs.solar_zenith) b = np.maximum(b, cosd(85)) vf_perez = pd.DataFrame( np.array([ sind(df_inputs.array_tilt), a / b, (1. + cosd(df_inputs.array_tilt)) / 2. ]).T, index=df_inputs.index, columns=['vf_horizon', 'vf_circumsolar', 'vf_isotropic'] ) # Calculate diffuse luminance luminance = pd.DataFrame( np.array([ components['horizon'] / vf_perez['vf_horizon'], components['circumsolar'] / vf_perez['vf_circumsolar'], components['isotropic'] / vf_perez['vf_isotropic'] ]).T, index=df_inputs.index, columns=['luminance_horizon', 'luminance_circumsolar', 'luminance_isotropic'] ) luminance.loc[diffuse_poa == 0, :] = 0. # Format components column names components = components.rename(columns={'isotropic': 'poa_isotropic', 'circumsolar': 'poa_circumsolar', 'horizon': 'poa_horizon'}) df_inputs = pd.concat([df_inputs, components, vf_perez, luminance, diffuse_poa], axis=1, join='outer') df_inputs = df_inputs.rename(columns={0: 'poa_total_diffuse'}) # Adjust the circumsolar luminance when it hits the back surface if df_inputs_back_surface.shape[0] > 0: df_inputs.loc[sun_hitting_back_surface, 'luminance_circumsolar'] = ( df_inputs_back_surface.loc[:, 'luminance_circumsolar'] ) return df_inputs