def get_DNI(self): """ Extract DNI from METPV-11 data. Daily METPV-11 data records. The raw data in METPV-11 is the incidence on the horizontal plane, that is, DNI*cos(d). d is the incidence anlge. :return: a dataframe that contains the DNI """ ngo = Location(latitude=self.latitude, longitude=self.longitude, altitude=0, tz='Japan') solar_pos = ngo.get_solarposition( pd.DatetimeIndex(self.hour_df['avg_time'])) cosd = aoi_projection(surface_tilt=0, surface_azimuth=0, solar_zenith=solar_pos['apparent_zenith'], solar_azimuth=solar_pos['azimuth']) dni_arr = self.hour_df['DHI'] / cosd dni_arr = np.maximum(dni_arr, 0) return dni_arr
def test_aoi_and_aoi_projection(surface_tilt, surface_azimuth, solar_zenith, solar_azimuth, aoi_expected, aoi_proj_expected): aoi = irradiance.aoi(surface_tilt, surface_azimuth, solar_zenith, solar_azimuth) assert_allclose(aoi, aoi_expected, atol=1e-6) aoi_projection = irradiance.aoi_projection( surface_tilt, surface_azimuth, solar_zenith, solar_azimuth) assert_allclose(aoi_projection, aoi_proj_expected, atol=1e-6)
def test_aoi_and_aoi_projection(surface_tilt, surface_azimuth, solar_zenith, solar_azimuth, aoi_expected, aoi_proj_expected): aoi = irradiance.aoi(surface_tilt, surface_azimuth, solar_zenith, solar_azimuth) assert_allclose(aoi, aoi_expected, atol=1e-6) aoi_projection = irradiance.aoi_projection(surface_tilt, surface_azimuth, solar_zenith, solar_azimuth) assert_allclose(aoi_projection, aoi_proj_expected, atol=1e-6)
def test_aoi_projection_precision(): # GH 1185 -- test that aoi_projection does not exceed 1.0, and when # given identical inputs, the returned projection is very close to 1.0 # scalars zenith = 89.26778228223463 azimuth = 60.932028605997004 projection = irradiance.aoi_projection(zenith, azimuth, zenith, azimuth) assert projection <= 1 assert np.isclose(projection, 1) # arrays zeniths = np.array([zenith]) azimuths = np.array([azimuth]) projections = irradiance.aoi_projection(zeniths, azimuths, zeniths, azimuths) assert all(projections <= 1) assert all(np.isclose(projections, 1)) assert projections.dtype == np.dtype('float64')
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 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 time_aoi_projection(self): irradiance.aoi_projection(self.tilt, self.azimuth, self.solar_position.apparent_zenith, self.solar_position.azimuth)
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