def test_get_absolute_airmass(): # input am relative_am = np.array([nan, 40, 2, .999]) # call without pressure kwarg out = atmosphere.get_absolute_airmass(relative_am) expected = np.array([nan, 40., 2., 0.999]) assert_allclose(out, expected, equal_nan=True, atol=0.001) # call with pressure kwarg out = atmosphere.get_absolute_airmass(relative_am, pressure=90000) expected = np.array([nan, 35.529, 1.776, 0.887]) assert_allclose(out, expected, equal_nan=True, atol=0.001)
def _air_mass(zenith, pressure): """ Returns the absolute air mass. """ # Methods from PvLib rel_am = get_relative_airmass(zenith=zenith) abs_am = get_absolute_airmass(rel_am, pressure=pressure) return abs_am
def get_airmass(self, times=None, solar_position=None, model='kastenyoung1989'): """ Calculate the relative and absolute airmass. Automatically chooses zenith or apparant zenith depending on the selected model. Parameters ---------- times : None or DatetimeIndex, default None Only used if solar_position is not provided. solar_position : None or DataFrame, default None DataFrame with with columns 'apparent_zenith', 'zenith'. model : str, default 'kastenyoung1989' Relative airmass model. See :py:func:`pvlib.atmosphere.get_relative_airmass` for a list of available models. Returns ------- airmass : DataFrame Columns are 'airmass_relative', 'airmass_absolute' See also -------- pvlib.atmosphere.get_relative_airmass """ if solar_position is None: solar_position = self.get_solarposition(times) if model in atmosphere.APPARENT_ZENITH_MODELS: zenith = solar_position['apparent_zenith'] elif model in atmosphere.TRUE_ZENITH_MODELS: zenith = solar_position['zenith'] else: raise ValueError(f'{model} is not a valid airmass model') airmass_relative = atmosphere.get_relative_airmass(zenith, model) pressure = atmosphere.alt2pres(self.altitude) airmass_absolute = atmosphere.get_absolute_airmass( airmass_relative, pressure) airmass = pd.DataFrame(index=solar_position.index) airmass['airmass_relative'] = airmass_relative airmass['airmass_absolute'] = airmass_absolute return airmass
def get_airmass(self, times=None, solar_position=None, model='kastenyoung1989'): """ Calculate the relative and absolute airmass. Automatically chooses zenith or apparant zenith depending on the selected model. Parameters ---------- times : None or DatetimeIndex, default None Only used if solar_position is not provided. solar_position : None or DataFrame, default None DataFrame with with columns 'apparent_zenith', 'zenith'. model : str, default 'kastenyoung1989' Relative airmass model Returns ------- airmass : DataFrame Columns are 'airmass_relative', 'airmass_absolute' """ if solar_position is None: solar_position = self.get_solarposition(times) if model in atmosphere.APPARENT_ZENITH_MODELS: zenith = solar_position['apparent_zenith'] elif model in atmosphere.TRUE_ZENITH_MODELS: zenith = solar_position['zenith'] else: raise ValueError('{} is not a valid airmass model'.format(model)) airmass_relative = atmosphere.get_relative_airmass(zenith, model) pressure = atmosphere.alt2pres(self.altitude) airmass_absolute = atmosphere.get_absolute_airmass(airmass_relative, pressure) airmass = pd.DataFrame(index=solar_position.index) airmass['airmass_relative'] = airmass_relative airmass['airmass_absolute'] = airmass_absolute return airmass
def generate_clearsky_sequence(time, location, sun_position=None, p_0=101325.0, model="ineichen"): """ Generate clear-sky irradiance sequence :param time: :param location: pvlib.location.Location object :param sun_position: :param p_0: sea level pressure :param model: {'ineichen', 'solis'} #TODO: implement solis clearsky model :return: """ if sun_position is None: sun_position = get_solar_position(time, location.latitude, location.longitude, location.altitude) # Altitude corrected (King et al. 1997; Rigollier et al. 2000) pressure = p_0 * np.exp(-0.0001184 * location.altitude) # Relative airmass am = get_relative_airmass(sun_position["zenith"]) # Absolute airmass am_a = get_absolute_airmass(am, pressure) # Linke turbidity linke_turbidity = lookup_linke_turbidity(time, location.latitude, location.longitude) if model == "ineichen": return ineichen(sun_position["apparent_zenith"], am_a, linke_turbidity)["ghi"] elif model == "solis": pass
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 basic_chain(times, latitude, longitude, module_parameters, inverter_parameters, irradiance=None, weather=None, surface_tilt=None, surface_azimuth=None, orientation_strategy=None, transposition_model='haydavies', solar_position_method='nrel_numpy', airmass_model='kastenyoung1989', altitude=None, pressure=None, **kwargs): """ An experimental function that computes all of the modeling steps necessary for calculating power or energy for a PV system at a given location. Parameters ---------- times : DatetimeIndex Times at which to evaluate the model. latitude : float. Positive is north of the equator. Use decimal degrees notation. longitude : float. Positive is east of the prime meridian. Use decimal degrees notation. module_parameters : None, dict or Series Module parameters as defined by the SAPM. inverter_parameters : None, dict or Series Inverter parameters as defined by the CEC. irradiance : None or DataFrame, default None If None, calculates clear sky data. Columns must be 'dni', 'ghi', 'dhi'. weather : None or DataFrame, default None If None, assumes air temperature is 20 C and wind speed is 0 m/s. Columns must be 'wind_speed', 'temp_air'. surface_tilt : None, float or Series, default None Surface tilt angles in decimal degrees. The tilt angle is defined as degrees from horizontal (e.g. surface facing up = 0, surface facing horizon = 90) surface_azimuth : None, float or Series, default None Surface azimuth angles in decimal degrees. The azimuth convention is defined as degrees east of north (North=0, South=180, East=90, West=270). orientation_strategy : None or str, default None The strategy for aligning the modules. If not None, sets the ``surface_azimuth`` and ``surface_tilt`` properties of the ``system``. Allowed strategies include 'flat', 'south_at_latitude_tilt'. Ignored for SingleAxisTracker systems. transposition_model : str, default 'haydavies' Passed to system.get_irradiance. solar_position_method : str, default 'nrel_numpy' Passed to solarposition.get_solarposition. airmass_model : str, default 'kastenyoung1989' Passed to atmosphere.relativeairmass. altitude : None or float, default None If None, computed from pressure. Assumed to be 0 m if pressure is also None. pressure : None or float, default None If None, computed from altitude. Assumed to be 101325 Pa if altitude is also None. **kwargs Arbitrary keyword arguments. See code for details. Returns ------- output : (dc, ac) Tuple of DC power (with SAPM parameters) (DataFrame) and AC power (Series). """ # use surface_tilt and surface_azimuth if provided, # otherwise set them using the orientation_strategy if surface_tilt is not None and surface_azimuth is not None: pass elif orientation_strategy is not None: surface_tilt, surface_azimuth = \ get_orientation(orientation_strategy, latitude=latitude) else: raise ValueError('orientation_strategy or surface_tilt and ' 'surface_azimuth must be provided') times = times if altitude is None and pressure is None: altitude = 0. pressure = 101325. elif altitude is None: altitude = atmosphere.pres2alt(pressure) elif pressure is None: pressure = atmosphere.alt2pres(altitude) solar_position = solarposition.get_solarposition( times, latitude, longitude, altitude=altitude, pressure=pressure, method=solar_position_method, **kwargs) # possible error with using apparent zenith with some models airmass = atmosphere.get_relative_airmass( solar_position['apparent_zenith'], model=airmass_model) airmass = atmosphere.get_absolute_airmass(airmass, pressure) dni_extra = pvlib.irradiance.get_extra_radiation(solar_position.index) aoi = pvlib.irradiance.aoi(surface_tilt, surface_azimuth, solar_position['apparent_zenith'], solar_position['azimuth']) if irradiance is None: linke_turbidity = clearsky.lookup_linke_turbidity( solar_position.index, latitude, longitude) irradiance = clearsky.ineichen(solar_position['apparent_zenith'], airmass, linke_turbidity, altitude=altitude, dni_extra=dni_extra) total_irrad = pvlib.irradiance.get_total_irradiance( surface_tilt, surface_azimuth, solar_position['apparent_zenith'], solar_position['azimuth'], irradiance['dni'], irradiance['ghi'], irradiance['dhi'], model=transposition_model, dni_extra=dni_extra) if weather is None: weather = {'wind_speed': 0, 'temp_air': 20} temps = pvsystem.sapm_celltemp(total_irrad['poa_global'], weather['wind_speed'], weather['temp_air']) effective_irradiance = pvsystem.sapm_effective_irradiance( total_irrad['poa_direct'], total_irrad['poa_diffuse'], airmass, aoi, module_parameters) dc = pvsystem.sapm(effective_irradiance, temps['temp_cell'], module_parameters) ac = pvsystem.snlinverter(dc['v_mp'], dc['p_mp'], inverter_parameters) return dc, ac
def basic_chain(times, latitude, longitude, module_parameters, inverter_parameters, irradiance=None, weather=None, surface_tilt=None, surface_azimuth=None, orientation_strategy=None, transposition_model='haydavies', solar_position_method='nrel_numpy', airmass_model='kastenyoung1989', altitude=None, pressure=None, **kwargs): """ An experimental function that computes all of the modeling steps necessary for calculating power or energy for a PV system at a given location. Parameters ---------- times : DatetimeIndex Times at which to evaluate the model. latitude : float. Positive is north of the equator. Use decimal degrees notation. longitude : float. Positive is east of the prime meridian. Use decimal degrees notation. module_parameters : None, dict or Series Module parameters as defined by the SAPM. inverter_parameters : None, dict or Series Inverter parameters as defined by the CEC. irradiance : None or DataFrame, default None If None, calculates clear sky data. Columns must be 'dni', 'ghi', 'dhi'. weather : None or DataFrame, default None If None, assumes air temperature is 20 C and wind speed is 0 m/s. Columns must be 'wind_speed', 'temp_air'. surface_tilt : None, float or Series, default None Surface tilt angles in decimal degrees. The tilt angle is defined as degrees from horizontal (e.g. surface facing up = 0, surface facing horizon = 90) surface_azimuth : None, float or Series, default None Surface azimuth angles in decimal degrees. The azimuth convention is defined as degrees east of north (North=0, South=180, East=90, West=270). orientation_strategy : None or str, default None The strategy for aligning the modules. If not None, sets the ``surface_azimuth`` and ``surface_tilt`` properties of the ``system``. Allowed strategies include 'flat', 'south_at_latitude_tilt'. Ignored for SingleAxisTracker systems. transposition_model : str, default 'haydavies' Passed to system.get_irradiance. solar_position_method : str, default 'nrel_numpy' Passed to solarposition.get_solarposition. airmass_model : str, default 'kastenyoung1989' Passed to atmosphere.relativeairmass. altitude : None or float, default None If None, computed from pressure. Assumed to be 0 m if pressure is also None. pressure : None or float, default None If None, computed from altitude. Assumed to be 101325 Pa if altitude is also None. **kwargs Arbitrary keyword arguments. See code for details. Returns ------- output : (dc, ac) Tuple of DC power (with SAPM parameters) (DataFrame) and AC power (Series). """ # use surface_tilt and surface_azimuth if provided, # otherwise set them using the orientation_strategy if surface_tilt is not None and surface_azimuth is not None: pass elif orientation_strategy is not None: surface_tilt, surface_azimuth = \ get_orientation(orientation_strategy, latitude=latitude) else: raise ValueError('orientation_strategy or surface_tilt and ' 'surface_azimuth must be provided') if altitude is None and pressure is None: altitude = 0. pressure = 101325. elif altitude is None: altitude = atmosphere.pres2alt(pressure) elif pressure is None: pressure = atmosphere.alt2pres(altitude) solar_position = solarposition.get_solarposition( times, latitude, longitude, altitude=altitude, pressure=pressure, method=solar_position_method, **kwargs) # possible error with using apparent zenith with some models airmass = atmosphere.get_relative_airmass( solar_position['apparent_zenith'], model=airmass_model) airmass = atmosphere.get_absolute_airmass(airmass, pressure) dni_extra = pvlib.irradiance.get_extra_radiation(solar_position.index) aoi = pvlib.irradiance.aoi(surface_tilt, surface_azimuth, solar_position['apparent_zenith'], solar_position['azimuth']) if irradiance is None: linke_turbidity = clearsky.lookup_linke_turbidity( solar_position.index, latitude, longitude) irradiance = clearsky.ineichen( solar_position['apparent_zenith'], airmass, linke_turbidity, altitude=altitude, dni_extra=dni_extra ) total_irrad = pvlib.irradiance.get_total_irradiance( surface_tilt, surface_azimuth, solar_position['apparent_zenith'], solar_position['azimuth'], irradiance['dni'], irradiance['ghi'], irradiance['dhi'], model=transposition_model, dni_extra=dni_extra) if weather is None: weather = {'wind_speed': 0, 'temp_air': 20} temps = pvsystem.sapm_celltemp(total_irrad['poa_global'], weather['wind_speed'], weather['temp_air']) effective_irradiance = pvsystem.sapm_effective_irradiance( total_irrad['poa_direct'], total_irrad['poa_diffuse'], airmass, aoi, module_parameters) dc = pvsystem.sapm(effective_irradiance, temps['temp_cell'], module_parameters) ac = pvsystem.snlinverter(dc['v_mp'], dc['p_mp'], inverter_parameters) return dc, ac
def test_get_absolute_airmass_nan(): np.testing.assert_equal(np.nan, atmosphere.get_absolute_airmass(np.nan))
def test_get_absolute_airmass_numeric(): atmosphere.get_absolute_airmass(2)
def test_get_absolute_airmass(): relative_am = atmosphere.get_relative_airmass(ephem_data['zenith'], 'simple') atmosphere.get_absolute_airmass(relative_am) atmosphere.get_absolute_airmass(relative_am, pressure=100000)