def test_bird_hulstrom80_aod_bb(): """Test Bird_Hulstrom broadband AOD.""" aod380, aod500 = 0.22072480948195175, 0.1614279181106312 bird_hulstrom = atmosphere.bird_hulstrom80_aod_bb(aod380, aod500) assert np.isclose(0.11738229553812768, bird_hulstrom)
def bird(zenith, airmass_relative, aod380, aod500, precipitable_water, ozone=0.3, pressure=101325., dni_extra=1364., asymmetry=0.85, albedo=0.2): """ Bird Simple Clear Sky Broadband Solar Radiation Model Based on NREL Excel implementation by Daryl R. Myers [1, 2]. Bird and Hulstrom define the zenith as the "angle between a line to the sun and the local zenith". There is no distinction in the paper between solar zenith and apparent (or refracted) zenith, but the relative airmass is defined using the Kasten 1966 expression, which requires apparent zenith. Although the formulation for calculated zenith is never explicitly defined in the report, since the purpose was to compare existing clear sky models with "rigorous radiative transfer models" (RTM) it is possible that apparent zenith was obtained as output from the RTM. However, the implentation presented in PVLIB is tested against the NREL Excel implementation by Daryl Myers which uses an analytical expression for solar zenith instead of apparent zenith. Parameters ---------- zenith : numeric Solar or apparent zenith angle in degrees - see note above airmass_relative : numeric Relative airmass aod380 : numeric Aerosol optical depth [cm] measured at 380[nm] aod500 : numeric Aerosol optical depth [cm] measured at 500[nm] precipitable_water : numeric Precipitable water [cm] ozone : numeric Atmospheric ozone [cm], defaults to 0.3[cm] pressure : numeric Ambient pressure [Pa], defaults to 101325[Pa] dni_extra : numeric Extraterrestrial radiation [W/m^2], defaults to 1364[W/m^2] asymmetry : numeric Asymmetry factor, defaults to 0.85 albedo : numeric Albedo, defaults to 0.2 Returns ------- clearsky : DataFrame (if Series input) or OrderedDict of arrays DataFrame/OrderedDict contains the columns/keys ``'dhi', 'dni', 'ghi', 'direct_horizontal'`` in [W/m^2]. See also -------- pvlib.atmosphere.bird_hulstrom80_aod_bb pvlib.atmosphere.relativeairmass References ---------- [1] R. E. Bird and R. L Hulstrom, "A Simplified Clear Sky model for Direct and Diffuse Insolation on Horizontal Surfaces" SERI Technical Report SERI/TR-642-761, Feb 1981. Solar Energy Research Institute, Golden, CO. [2] Daryl R. Myers, "Solar Radiation: Practical Modeling for Renewable Energy Applications", pp. 46-51 CRC Press (2013) `NREL Bird Clear Sky Model <http://rredc.nrel.gov/solar/models/clearsky/>`_ `SERI/TR-642-761 <http://rredc.nrel.gov/solar/pubs/pdfs/tr-642-761.pdf>`_ `Error Reports <http://rredc.nrel.gov/solar/models/clearsky/error_reports.html>`_ """ etr = dni_extra # extraradiation ze_rad = np.deg2rad(zenith) # zenith in radians airmass = airmass_relative # Bird clear sky model am_press = atmosphere.get_absolute_airmass(airmass, pressure) t_rayleigh = ( np.exp(-0.0903 * am_press ** 0.84 * ( 1.0 + am_press - am_press ** 1.01 )) ) am_o3 = ozone*airmass t_ozone = ( 1.0 - 0.1611 * am_o3 * (1.0 + 139.48 * am_o3) ** -0.3034 - 0.002715 * am_o3 / (1.0 + 0.044 * am_o3 + 0.0003 * am_o3 ** 2.0) ) t_gases = np.exp(-0.0127 * am_press ** 0.26) am_h2o = airmass * precipitable_water t_water = ( 1.0 - 2.4959 * am_h2o / ( (1.0 + 79.034 * am_h2o) ** 0.6828 + 6.385 * am_h2o ) ) bird_huldstrom = atmosphere.bird_hulstrom80_aod_bb(aod380, aod500) t_aerosol = np.exp( -(bird_huldstrom ** 0.873) * (1.0 + bird_huldstrom - bird_huldstrom ** 0.7088) * airmass ** 0.9108 ) taa = 1.0 - 0.1 * (1.0 - airmass + airmass ** 1.06) * (1.0 - t_aerosol) rs = 0.0685 + (1.0 - asymmetry) * (1.0 - t_aerosol / taa) id_ = 0.9662 * etr * t_aerosol * t_water * t_gases * t_ozone * t_rayleigh ze_cos = np.where(zenith < 90, np.cos(ze_rad), 0.0) id_nh = id_ * ze_cos ias = ( etr * ze_cos * 0.79 * t_ozone * t_gases * t_water * taa * (0.5 * (1.0 - t_rayleigh) + asymmetry * (1.0 - (t_aerosol / taa))) / ( 1.0 - airmass + airmass ** 1.02 ) ) gh = (id_nh + ias) / (1.0 - albedo * rs) diffuse_horiz = gh - id_nh # TODO: be DRY, use decorator to wrap methods that need to return either # OrderedDict or DataFrame instead of repeating this boilerplate code irrads = OrderedDict() irrads['direct_horizontal'] = id_nh irrads['ghi'] = gh irrads['dni'] = id_ irrads['dhi'] = diffuse_horiz if isinstance(irrads['dni'], pd.Series): irrads = pd.DataFrame.from_dict(irrads) return irrads
def test_bird_hulstrom80_aod_bb(): """Test Bird_Hulstrom broadband AOD.""" aod380, aod500 = 0.22072480948195175, 0.1614279181106312 bird_hulstrom = atmosphere.bird_hulstrom80_aod_bb(aod380, aod500) assert np.isclose(0.11738229553812768, bird_hulstrom)