prompt: pvlib.irradiance.reindl() model generates NaNs when GHI = 0
  **Describe the bug**
  The reindl function should give zero sky diffuse when GHI is zero. Instead it generates NaN or Inf values due to "term3" having a quotient that divides by GHI.  
  
  **Expected behavior**
  The reindl function should result in zero sky diffuse when GHI is zero.
  
  
  pvlib.irradiance.reindl() model generates NaNs when GHI = 0
  **Describe the bug**
  The reindl function should give zero sky diffuse when GHI is zero. Instead it generates NaN or Inf values due to "term3" having a quotient that divides by GHI.  
  
  **Expected behavior**
  The reindl function should result in zero sky diffuse when GHI is zero.
  
  
  
instance: {"FAIL_TO_PASS": "[\"pvlib/tests/test_irradiance.py::test_reindl\"]", "PASS_TO_PASS": "[\"pvlib/tests/test_irradiance.py::test_get_extra_radiation[asce-300-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[asce-300.0-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[asce-testval2-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[asce-testval3-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[asce-testval4-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[asce-testval5-expected5]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[asce-testval6-expected6]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[asce-testval7-expected7]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[asce-testval8-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[spencer-300-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[spencer-300.0-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[spencer-testval2-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[spencer-testval3-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[spencer-testval4-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[spencer-testval5-expected5]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[spencer-testval6-expected6]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[spencer-testval7-expected7]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[spencer-testval8-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[nrel-300-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[nrel-300.0-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[nrel-testval2-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[nrel-testval3-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[nrel-testval4-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[nrel-testval5-expected5]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[nrel-testval6-expected6]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[nrel-testval7-expected7]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[nrel-testval8-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[pyephem-300-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[pyephem-300.0-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[pyephem-testval2-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[pyephem-testval3-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[pyephem-testval4-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[pyephem-testval5-expected5]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[pyephem-testval6-expected6]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[pyephem-testval7-expected7]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation[pyephem-testval8-1383.636203]\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation_epoch_year\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation_nrel_numba\", \"pvlib/tests/test_irradiance.py::test_get_extra_radiation_invalid\", \"pvlib/tests/test_irradiance.py::test_grounddiffuse_simple_float\", \"pvlib/tests/test_irradiance.py::test_grounddiffuse_simple_series\", \"pvlib/tests/test_irradiance.py::test_grounddiffuse_albedo_0\", \"pvlib/tests/test_irradiance.py::test_grounddiffuse_albedo_invalid_surface\", \"pvlib/tests/test_irradiance.py::test_grounddiffuse_albedo_surface\", \"pvlib/tests/test_irradiance.py::test_isotropic_float\", \"pvlib/tests/test_irradiance.py::test_isotropic_series\", \"pvlib/tests/test_irradiance.py::test_klucher_series_float\", \"pvlib/tests/test_irradiance.py::test_klucher_series\", \"pvlib/tests/test_irradiance.py::test_haydavies\", \"pvlib/tests/test_irradiance.py::test_king\", \"pvlib/tests/test_irradiance.py::test_perez\", \"pvlib/tests/test_irradiance.py::test_perez_components\", \"pvlib/tests/test_irradiance.py::test_perez_arrays\", \"pvlib/tests/test_irradiance.py::test_perez_scalar\", \"pvlib/tests/test_irradiance.py::test_sky_diffuse_zenith_close_to_90[isotropic]\", \"pvlib/tests/test_irradiance.py::test_sky_diffuse_zenith_close_to_90[klucher]\", \"pvlib/tests/test_irradiance.py::test_sky_diffuse_zenith_close_to_90[haydavies]\", \"pvlib/tests/test_irradiance.py::test_sky_diffuse_zenith_close_to_90[reindl]\", \"pvlib/tests/test_irradiance.py::test_sky_diffuse_zenith_close_to_90[king]\", \"pvlib/tests/test_irradiance.py::test_sky_diffuse_zenith_close_to_90[perez]\", \"pvlib/tests/test_irradiance.py::test_get_sky_diffuse_invalid\", \"pvlib/tests/test_irradiance.py::test_campbell_norman\", \"pvlib/tests/test_irradiance.py::test_get_total_irradiance\", \"pvlib/tests/test_irradiance.py::test_get_total_irradiance_scalars[isotropic]\", \"pvlib/tests/test_irradiance.py::test_get_total_irradiance_scalars[klucher]\", \"pvlib/tests/test_irradiance.py::test_get_total_irradiance_scalars[haydavies]\", \"pvlib/tests/test_irradiance.py::test_get_total_irradiance_scalars[reindl]\", \"pvlib/tests/test_irradiance.py::test_get_total_irradiance_scalars[king]\", \"pvlib/tests/test_irradiance.py::test_get_total_irradiance_scalars[perez]\", \"pvlib/tests/test_irradiance.py::test_poa_components\", \"pvlib/tests/test_irradiance.py::test_disc_value[93193-expected0]\", \"pvlib/tests/test_irradiance.py::test_disc_value[None-expected1]\", \"pvlib/tests/test_irradiance.py::test_disc_value[101325-expected2]\", \"pvlib/tests/test_irradiance.py::test_disc_overirradiance\", \"pvlib/tests/test_irradiance.py::test_disc_min_cos_zenith_max_zenith\", \"pvlib/tests/test_irradiance.py::test_dirint_value\", \"pvlib/tests/test_irradiance.py::test_dirint_nans\", \"pvlib/tests/test_irradiance.py::test_dirint_tdew\", \"pvlib/tests/test_irradiance.py::test_dirint_no_delta_kt\", \"pvlib/tests/test_irradiance.py::test_dirint_coeffs\", \"pvlib/tests/test_irradiance.py::test_dirint_min_cos_zenith_max_zenith\", \"pvlib/tests/test_irradiance.py::test_gti_dirint\", \"pvlib/tests/test_irradiance.py::test_erbs\", \"pvlib/tests/test_irradiance.py::test_erbs_min_cos_zenith_max_zenith\", \"pvlib/tests/test_irradiance.py::test_erbs_all_scalar\", \"pvlib/tests/test_irradiance.py::test_dirindex\", \"pvlib/tests/test_irradiance.py::test_dirindex_min_cos_zenith_max_zenith\", \"pvlib/tests/test_irradiance.py::test_dni\", \"pvlib/tests/test_irradiance.py::test_aoi_and_aoi_projection[0-0-0-0-0-1]\", \"pvlib/tests/test_irradiance.py::test_aoi_and_aoi_projection[30-180-30-180-0-1]\", \"pvlib/tests/test_irradiance.py::test_aoi_and_aoi_projection[30-180-150-0-180--1]\", \"pvlib/tests/test_irradiance.py::test_aoi_and_aoi_projection[90-0-30-60-75.5224878-0.25]\", \"pvlib/tests/test_irradiance.py::test_aoi_and_aoi_projection[90-0-30-170-119.4987042--0.4924038]\", \"pvlib/tests/test_irradiance.py::test_kt_kt_prime_factor\", \"pvlib/tests/test_irradiance.py::test_clearsky_index\", \"pvlib/tests/test_irradiance.py::test_clearness_index\", \"pvlib/tests/test_irradiance.py::test_clearness_index_zenith_independent\"]", "base_commit": "0b8f24c265d76320067a5ee908a57d475cd1bb24", "created_at": "2021-01-29T20:53:24Z", "environment_setup_commit": "ef8ad2fee9840a77d14b0dfd17fc489dd85c9b91", "hints_text": "Verified. Looks like an easy fix.\nVerified. Looks like an easy fix.", "instance_id": "pvlib__pvlib-python-1154", "patch": "diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py\n--- a/pvlib/irradiance.py\n+++ b/pvlib/irradiance.py\n@@ -886,8 +886,9 @@ def reindl(surface_tilt, surface_azimuth, dhi, dni, ghi, dni_extra,\n     # these are the () and [] sub-terms of the second term of eqn 8\n     term1 = 1 - AI\n     term2 = 0.5 * (1 + tools.cosd(surface_tilt))\n-    term3 = 1 + np.sqrt(HB / ghi) * (tools.sind(0.5 * surface_tilt) ** 3)\n-\n+    with np.errstate(invalid='ignore', divide='ignore'):\n+        hb_to_ghi = np.where(ghi == 0, 0, np.divide(HB, ghi))\n+    term3 = 1 + np.sqrt(hb_to_ghi) * (tools.sind(0.5 * surface_tilt)**3)\n     sky_diffuse = dhi * (AI * Rb + term1 * term2 * term3)\n     sky_diffuse = np.maximum(sky_diffuse, 0)\n \n", "problem_statement": "pvlib.irradiance.reindl() model generates NaNs when GHI = 0\n**Describe the bug**\r\nThe reindl function should give zero sky diffuse when GHI is zero. Instead it generates NaN or Inf values due to \"term3\" having a quotient that divides by GHI.  \r\n\r\n**Expected behavior**\r\nThe reindl function should result in zero sky diffuse when GHI is zero.\r\n\r\n\npvlib.irradiance.reindl() model generates NaNs when GHI = 0\n**Describe the bug**\r\nThe reindl function should give zero sky diffuse when GHI is zero. Instead it generates NaN or Inf values due to \"term3\" having a quotient that divides by GHI.  \r\n\r\n**Expected behavior**\r\nThe reindl function should result in zero sky diffuse when GHI is zero.\r\n\r\n\n", "repo": "pvlib/pvlib-python", "test_patch": "diff --git a/pvlib/tests/test_irradiance.py b/pvlib/tests/test_irradiance.py\n--- a/pvlib/tests/test_irradiance.py\n+++ b/pvlib/tests/test_irradiance.py\n@@ -203,7 +203,7 @@ def test_reindl(irrad_data, ephem_data, dni_et):\n         40, 180, irrad_data['dhi'], irrad_data['dni'], irrad_data['ghi'],\n         dni_et, ephem_data['apparent_zenith'], ephem_data['azimuth'])\n     # values from matlab 1.4 code\n-    assert_allclose(result, [np.nan, 27.9412, 104.1317, 34.1663], atol=1e-4)\n+    assert_allclose(result, [0., 27.9412, 104.1317, 34.1663], atol=1e-4)\n \n \n def test_king(irrad_data, ephem_data):\n", "version": "0.8"}
parsed_commit_content: {"file_diffs":[{"old_file_content":"\"\"\"\nThe ``irradiance`` module contains functions for modeling global\nhorizontal irradiance, direct normal irradiance, diffuse horizontal\nirradiance, and total irradiance under various conditions.\n\"\"\"\n\nimport datetime\nfrom collections import OrderedDict\nfrom functools import partial\n\nimport numpy as np\nimport pandas as pd\n\nfrom pvlib import atmosphere, solarposition, tools\n\n\n# see References section of grounddiffuse function\nSURFACE_ALBEDOS = {'urban': 0.18,\n                   'grass': 0.20,\n                   'fresh grass': 0.26,\n                   'soil': 0.17,\n                   'sand': 0.40,\n                   'snow': 0.65,\n                   'fresh snow': 0.75,\n                   'asphalt': 0.12,\n                   'concrete': 0.30,\n                   'aluminum': 0.85,\n                   'copper': 0.74,\n                   'fresh steel': 0.35,\n                   'dirty steel': 0.08,\n                   'sea': 0.06}\n\n\ndef get_extra_radiation(datetime_or_doy, solar_constant=1366.1,\n                        method='spencer', epoch_year=2014, **kwargs):\n    \"\"\"\n    Determine extraterrestrial radiation from day of year.\n\n    Parameters\n    ----------\n    datetime_or_doy : numeric, array, date, datetime, Timestamp, DatetimeIndex\n        Day of year, array of days of year, or datetime-like object\n\n    solar_constant : float, default 1366.1\n        The solar constant.\n\n    method : string, default 'spencer'\n        The method by which the ET radiation should be calculated.\n        Options include ``'pyephem', 'spencer', 'asce', 'nrel'``.\n\n    epoch_year : int, default 2014\n        The year in which a day of year input will be calculated. Only\n        applies to day of year input used with the pyephem or nrel\n        methods.\n\n    kwargs :\n        Passed to solarposition.nrel_earthsun_distance\n\n    Returns\n    -------\n    dni_extra : float, array, or Series\n        The extraterrestrial radiation present in watts per square meter\n        on a surface which is normal to the sun. Pandas Timestamp and\n        DatetimeIndex inputs will yield a Pandas TimeSeries. All other\n        inputs will yield a float or an array of floats.\n\n    References\n    ----------\n    .. [1] M. Reno, C. Hansen, and J. Stein, \"Global Horizontal Irradiance\n       Clear Sky Models: Implementation and Analysis\", Sandia National\n       Laboratories, SAND2012-2389, 2012.\n\n    .. [2] <http://solardat.uoregon.edu/SolarRadiationBasics.html>, Eqs.\n       SR1 and SR2\n\n    .. [3] Partridge, G. W. and Platt, C. M. R. 1976. Radiative Processes\n       in Meteorology and Climatology.\n\n    .. [4] Duffie, J. A. and Beckman, W. A. 1991. Solar Engineering of\n       Thermal Processes, 2nd edn. J. Wiley and Sons, New York.\n\n    .. [5] ASCE, 2005. The ASCE Standardized Reference Evapotranspiration\n       Equation, Environmental and Water Resources Institute of the American\n       Civil Engineers, Ed. R. G. Allen et al.\n    \"\"\"\n\n    to_doy, to_datetimeindex, to_output = \\\n        _handle_extra_radiation_types(datetime_or_doy, epoch_year)\n\n    # consider putting asce and spencer methods in their own functions\n    method = method.lower()\n    if method == 'asce':\n        B = solarposition._calculate_simple_day_angle(to_doy(datetime_or_doy),\n                                                      offset=0)\n        RoverR0sqrd = 1 + 0.033 * np.cos(B)\n    elif method == 'spencer':\n        B = solarposition._calculate_simple_day_angle(to_doy(datetime_or_doy))\n        RoverR0sqrd = (1.00011 + 0.034221 * np.cos(B) + 0.00128 * np.sin(B) +\n                       0.000719 * np.cos(2 * B) + 7.7e-05 * np.sin(2 * B))\n    elif method == 'pyephem':\n        times = to_datetimeindex(datetime_or_doy)\n        RoverR0sqrd = solarposition.pyephem_earthsun_distance(times) ** (-2)\n    elif method == 'nrel':\n        times = to_datetimeindex(datetime_or_doy)\n        RoverR0sqrd = \\\n            solarposition.nrel_earthsun_distance(times, **kwargs) ** (-2)\n    else:\n        raise ValueError('Invalid method: %s', method)\n\n    Ea = solar_constant * RoverR0sqrd\n\n    Ea = to_output(Ea)\n\n    return Ea\n\n\ndef _handle_extra_radiation_types(datetime_or_doy, epoch_year):\n    # This block will set the functions that can be used to convert the\n    # inputs to either day of year or pandas DatetimeIndex, and the\n    # functions that will yield the appropriate output type. It's\n    # complicated because there are many day-of-year-like input types,\n    # and the different algorithms need different types. Maybe you have\n    # a better way to do it.\n    if isinstance(datetime_or_doy, pd.DatetimeIndex):\n        to_doy = tools._pandas_to_doy  # won't be evaluated unless necessary\n        def to_datetimeindex(x): return x                       # noqa: E306\n        to_output = partial(pd.Series, index=datetime_or_doy)\n    elif isinstance(datetime_or_doy, pd.Timestamp):\n        to_doy = tools._pandas_to_doy\n        to_datetimeindex = \\\n            tools._datetimelike_scalar_to_datetimeindex\n        to_output = tools._scalar_out\n    elif isinstance(datetime_or_doy,\n                    (datetime.date, datetime.datetime, np.datetime64)):\n        to_doy = tools._datetimelike_scalar_to_doy\n        to_datetimeindex = \\\n            tools._datetimelike_scalar_to_datetimeindex\n        to_output = tools._scalar_out\n    elif np.isscalar(datetime_or_doy):  # ints and floats of various types\n        def to_doy(x): return x                                 # noqa: E306\n        to_datetimeindex = partial(tools._doy_to_datetimeindex,\n                                   epoch_year=epoch_year)\n        to_output = tools._scalar_out\n    else:  # assume that we have an array-like object of doy\n        def to_doy(x): return x                                 # noqa: E306\n        to_datetimeindex = partial(tools._doy_to_datetimeindex,\n                                   epoch_year=epoch_year)\n        to_output = tools._array_out\n\n    return to_doy, to_datetimeindex, to_output\n\n\ndef aoi_projection(surface_tilt, surface_azimuth, solar_zenith, solar_azimuth):\n    \"\"\"\n    Calculates the dot product of the sun position unit vector and the surface\n    normal unit vector; in other words, the cosine of the angle of incidence.\n\n    Usage note: When the sun is behind the surface the value returned is\n    negative.  For many uses negative values must be set to zero.\n\n    Input all angles in degrees.\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Panel tilt from horizontal.\n    surface_azimuth : numeric\n        Panel azimuth from north.\n    solar_zenith : numeric\n        Solar zenith angle.\n    solar_azimuth : numeric\n        Solar azimuth angle.\n\n    Returns\n    -------\n    projection : numeric\n        Dot product of panel normal and solar angle.\n    \"\"\"\n\n    projection = (\n        tools.cosd(surface_tilt) * tools.cosd(solar_zenith) +\n        tools.sind(surface_tilt) * tools.sind(solar_zenith) *\n        tools.cosd(solar_azimuth - surface_azimuth))\n\n    try:\n        projection.name = 'aoi_projection'\n    except AttributeError:\n        pass\n\n    return projection\n\n\ndef aoi(surface_tilt, surface_azimuth, solar_zenith, solar_azimuth):\n    \"\"\"\n    Calculates the angle of incidence of the solar vector on a surface.\n    This is the angle between the solar vector and the surface normal.\n\n    Input all angles in degrees.\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Panel tilt from horizontal.\n    surface_azimuth : numeric\n        Panel azimuth from north.\n    solar_zenith : numeric\n        Solar zenith angle.\n    solar_azimuth : numeric\n        Solar azimuth angle.\n\n    Returns\n    -------\n    aoi : numeric\n        Angle of incidence in degrees.\n    \"\"\"\n\n    projection = aoi_projection(surface_tilt, surface_azimuth,\n                                solar_zenith, solar_azimuth)\n    aoi_value = np.rad2deg(np.arccos(projection))\n\n    try:\n        aoi_value.name = 'aoi'\n    except AttributeError:\n        pass\n\n    return aoi_value\n\n\ndef poa_horizontal_ratio(surface_tilt, surface_azimuth,\n                         solar_zenith, solar_azimuth):\n    \"\"\"\n    Calculates the ratio of the beam components of the plane of array\n    irradiance and the horizontal irradiance.\n\n    Input all angles in degrees.\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Panel tilt from horizontal.\n    surface_azimuth : numeric\n        Panel azimuth from north.\n    solar_zenith : numeric\n        Solar zenith angle.\n    solar_azimuth : numeric\n        Solar azimuth angle.\n\n    Returns\n    -------\n    ratio : numeric\n        Ratio of the plane of array irradiance to the horizontal plane\n        irradiance\n    \"\"\"\n\n    cos_poa_zen = aoi_projection(surface_tilt, surface_azimuth,\n                                 solar_zenith, solar_azimuth)\n\n    cos_solar_zenith = tools.cosd(solar_zenith)\n\n    # ratio of tilted and horizontal beam irradiance\n    ratio = cos_poa_zen / cos_solar_zenith\n\n    try:\n        ratio.name = 'poa_ratio'\n    except AttributeError:\n        pass\n\n    return ratio\n\n\ndef beam_component(surface_tilt, surface_azimuth, solar_zenith, solar_azimuth,\n                   dni):\n    \"\"\"\n    Calculates the beam component of the plane of array irradiance.\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Panel tilt from horizontal.\n    surface_azimuth : numeric\n        Panel azimuth from north.\n    solar_zenith : numeric\n        Solar zenith angle.\n    solar_azimuth : numeric\n        Solar azimuth angle.\n    dni : numeric\n        Direct Normal Irradiance\n\n    Returns\n    -------\n    beam : numeric\n        Beam component\n    \"\"\"\n    beam = dni * aoi_projection(surface_tilt, surface_azimuth,\n                                solar_zenith, solar_azimuth)\n    beam = np.maximum(beam, 0)\n\n    return beam\n\n\ndef get_total_irradiance(surface_tilt, surface_azimuth,\n                         solar_zenith, solar_azimuth,\n                         dni, ghi, dhi, dni_extra=None, airmass=None,\n                         albedo=.25, surface_type=None,\n                         model='isotropic',\n                         model_perez='allsitescomposite1990', **kwargs):\n    r\"\"\"\n    Determine total in-plane irradiance and its beam, sky diffuse and ground\n    reflected components, using the specified sky diffuse irradiance model.\n\n    .. math::\n\n       I_{tot} = I_{beam} + I_{sky diffuse} + I_{ground}\n\n    Sky diffuse models include:\n        * isotropic (default)\n        * klucher\n        * haydavies\n        * reindl\n        * king\n        * perez\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Panel tilt from horizontal.\n    surface_azimuth : numeric\n        Panel azimuth from north.\n    solar_zenith : numeric\n        Solar zenith angle.\n    solar_azimuth : numeric\n        Solar azimuth angle.\n    dni : numeric\n        Direct Normal Irradiance\n    ghi : numeric\n        Global horizontal irradiance\n    dhi : numeric\n        Diffuse horizontal irradiance\n    dni_extra : None or numeric, default None\n        Extraterrestrial direct normal irradiance\n    airmass : None or numeric, default None\n        Airmass\n    albedo : numeric, default 0.25\n        Surface albedo\n    surface_type : None or String, default None\n        Surface type. See grounddiffuse.\n    model : String, default 'isotropic'\n        Irradiance model.\n    model_perez : String, default 'allsitescomposite1990'\n        Used only if model='perez'. See :py:func:`perez`.\n\n    Returns\n    -------\n    total_irrad : OrderedDict or DataFrame\n        Contains keys/columns ``'poa_global', 'poa_direct', 'poa_diffuse',\n        'poa_sky_diffuse', 'poa_ground_diffuse'``.\n    \"\"\"\n    poa_sky_diffuse = get_sky_diffuse(\n        surface_tilt, surface_azimuth, solar_zenith, solar_azimuth,\n        dni, ghi, dhi, dni_extra=dni_extra, airmass=airmass, model=model,\n        model_perez=model_perez)\n\n    poa_ground_diffuse = get_ground_diffuse(surface_tilt, ghi, albedo,\n                                            surface_type)\n    aoi_ = aoi(surface_tilt, surface_azimuth, solar_zenith, solar_azimuth)\n    irrads = poa_components(aoi_, dni, poa_sky_diffuse, poa_ground_diffuse)\n    return irrads\n\n\ndef get_sky_diffuse(surface_tilt, surface_azimuth,\n                    solar_zenith, solar_azimuth,\n                    dni, ghi, dhi, dni_extra=None, airmass=None,\n                    model='isotropic',\n                    model_perez='allsitescomposite1990'):\n    r\"\"\"\n    Determine in-plane sky diffuse irradiance component\n    using the specified sky diffuse irradiance model.\n\n    Sky diffuse models include:\n        * isotropic (default)\n        * klucher\n        * haydavies\n        * reindl\n        * king\n        * perez\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Panel tilt from horizontal.\n    surface_azimuth : numeric\n        Panel azimuth from north.\n    solar_zenith : numeric\n        Solar zenith angle.\n    solar_azimuth : numeric\n        Solar azimuth angle.\n    dni : numeric\n        Direct Normal Irradiance\n    ghi : numeric\n        Global horizontal irradiance\n    dhi : numeric\n        Diffuse horizontal irradiance\n    dni_extra : None or numeric, default None\n        Extraterrestrial direct normal irradiance\n    airmass : None or numeric, default None\n        Airmass\n    model : String, default 'isotropic'\n        Irradiance model.\n    model_perez : String, default 'allsitescomposite1990'\n        See perez.\n\n    Returns\n    -------\n    poa_sky_diffuse : numeric\n    \"\"\"\n\n    model = model.lower()\n    if model == 'isotropic':\n        sky = isotropic(surface_tilt, dhi)\n    elif model == 'klucher':\n        sky = klucher(surface_tilt, surface_azimuth, dhi, ghi,\n                      solar_zenith, solar_azimuth)\n    elif model == 'haydavies':\n        sky = haydavies(surface_tilt, surface_azimuth, dhi, dni, dni_extra,\n                        solar_zenith, solar_azimuth)\n    elif model == 'reindl':\n        sky = reindl(surface_tilt, surface_azimuth, dhi, dni, ghi, dni_extra,\n                     solar_zenith, solar_azimuth)\n    elif model == 'king':\n        sky = king(surface_tilt, dhi, ghi, solar_zenith)\n    elif model == 'perez':\n        sky = perez(surface_tilt, surface_azimuth, dhi, dni, dni_extra,\n                    solar_zenith, solar_azimuth, airmass,\n                    model=model_perez)\n    else:\n        raise ValueError(f'invalid model selection {model}')\n\n    return sky\n\n\ndef poa_components(aoi, dni, poa_sky_diffuse, poa_ground_diffuse):\n    r'''\n    Determine in-plane irradiance components.\n\n    Combines DNI with sky diffuse and ground-reflected irradiance to calculate\n    total, direct and diffuse irradiance components in the plane of array.\n\n    Parameters\n    ----------\n    aoi : numeric\n        Angle of incidence of solar rays with respect to the module\n        surface, from :func:`aoi`.\n\n    dni : numeric\n        Direct normal irradiance (W/m^2), as measured from a TMY file or\n        calculated with a clearsky model.\n\n    poa_sky_diffuse : numeric\n        Diffuse irradiance (W/m^2) in the plane of the modules, as\n        calculated by a diffuse irradiance translation function\n\n    poa_ground_diffuse : numeric\n        Ground reflected irradiance (W/m^2) in the plane of the modules,\n        as calculated by an albedo model (eg. :func:`grounddiffuse`)\n\n    Returns\n    -------\n    irrads : OrderedDict or DataFrame\n        Contains the following keys:\n\n        * ``poa_global`` : Total in-plane irradiance (W/m^2)\n        * ``poa_direct`` : Total in-plane beam irradiance (W/m^2)\n        * ``poa_diffuse`` : Total in-plane diffuse irradiance (W/m^2)\n        * ``poa_sky_diffuse`` : In-plane diffuse irradiance from sky (W/m^2)\n        * ``poa_ground_diffuse`` : In-plane diffuse irradiance from ground\n          (W/m^2)\n\n    Notes\n    ------\n    Negative beam irradiation due to aoi :math:`> 90^{\\circ}` or AOI\n    :math:`< 0^{\\circ}` is set to zero.\n    '''\n\n    poa_direct = np.maximum(dni * np.cos(np.radians(aoi)), 0)\n    poa_diffuse = poa_sky_diffuse + poa_ground_diffuse\n    poa_global = poa_direct + poa_diffuse\n\n    irrads = OrderedDict()\n    irrads['poa_global'] = poa_global\n    irrads['poa_direct'] = poa_direct\n    irrads['poa_diffuse'] = poa_diffuse\n    irrads['poa_sky_diffuse'] = poa_sky_diffuse\n    irrads['poa_ground_diffuse'] = poa_ground_diffuse\n\n    if isinstance(poa_direct, pd.Series):\n        irrads = pd.DataFrame(irrads)\n\n    return irrads\n\n\ndef get_ground_diffuse(surface_tilt, ghi, albedo=.25, surface_type=None):\n    '''\n    Estimate diffuse irradiance from ground reflections given\n    irradiance, albedo, and surface tilt\n\n    Function to determine the portion of irradiance on a tilted surface\n    due to ground reflections. Any of the inputs may be DataFrames or\n    scalars.\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Surface tilt angles in decimal degrees. Tilt must be >=0 and\n        <=180. The tilt angle is defined as degrees from horizontal\n        (e.g. surface facing up = 0, surface facing horizon = 90).\n\n    ghi : numeric\n        Global horizontal irradiance in W/m^2.\n\n    albedo : numeric, default 0.25\n        Ground reflectance, typically 0.1-0.4 for surfaces on Earth\n        (land), may increase over snow, ice, etc. May also be known as\n        the reflection coefficient. Must be >=0 and <=1. Will be\n        overridden if surface_type is supplied.\n\n    surface_type: None or string, default None\n        If not None, overrides albedo. String can be one of 'urban',\n        'grass', 'fresh grass', 'snow', 'fresh snow', 'asphalt', 'concrete',\n        'aluminum', 'copper', 'fresh steel', 'dirty steel', 'sea'.\n\n    Returns\n    -------\n    grounddiffuse : numeric\n        Ground reflected irradiances in W/m^2.\n\n\n    References\n    ----------\n    .. [1] Loutzenhiser P.G. et. al. \"Empirical validation of models to compute\n       solar irradiance on inclined surfaces for building energy simulation\"\n       2007, Solar Energy vol. 81. pp. 254-267.\n\n    The calculation is the last term of equations 3, 4, 7, 8, 10, 11, and 12.\n\n    .. [2] albedos from:\n       http://files.pvsyst.com/help/albedo.htm\n       and\n       http://en.wikipedia.org/wiki/Albedo\n       and\n       https://doi.org/10.1175/1520-0469(1972)029<0959:AOTSS>2.0.CO;2\n    '''\n\n    if surface_type is not None:\n        albedo = SURFACE_ALBEDOS[surface_type]\n\n    diffuse_irrad = ghi * albedo * (1 - np.cos(np.radians(surface_tilt))) * 0.5\n\n    try:\n        diffuse_irrad.name = 'diffuse_ground'\n    except AttributeError:\n        pass\n\n    return diffuse_irrad\n\n\ndef isotropic(surface_tilt, dhi):\n    r'''\n    Determine diffuse irradiance from the sky on a tilted surface using\n    the isotropic sky model.\n\n    .. math::\n\n       I_{d} = DHI \\frac{1 + \\cos\\beta}{2}\n\n    Hottel and Woertz's model treats the sky as a uniform source of\n    diffuse irradiance. Thus the diffuse irradiance from the sky (ground\n    reflected irradiance is not included in this algorithm) on a tilted\n    surface can be found from the diffuse horizontal irradiance and the\n    tilt angle of the surface.\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Surface tilt angle in decimal degrees. Tilt must be >=0 and\n        <=180. The tilt angle is defined as degrees from horizontal\n        (e.g. surface facing up = 0, surface facing horizon = 90)\n\n    dhi : numeric\n        Diffuse horizontal irradiance in W/m^2. DHI must be >=0.\n\n    Returns\n    -------\n    diffuse : numeric\n        The sky diffuse component of the solar radiation.\n\n    References\n    ----------\n    .. [1] Loutzenhiser P.G. et. al. \"Empirical validation of models to\n       compute solar irradiance on inclined surfaces for building energy\n       simulation\" 2007, Solar Energy vol. 81. pp. 254-267\n\n    .. [2] Hottel, H.C., Woertz, B.B., 1942. Evaluation of flat-plate solar\n       heat collector. Trans. ASME 64, 91.\n    '''\n\n    sky_diffuse = dhi * (1 + tools.cosd(surface_tilt)) * 0.5\n\n    return sky_diffuse\n\n\ndef klucher(surface_tilt, surface_azimuth, dhi, ghi, solar_zenith,\n            solar_azimuth):\n    r'''\n    Determine diffuse irradiance from the sky on a tilted surface\n    using Klucher's 1979 model\n\n    .. math::\n\n       I_{d} = DHI \\frac{1 + \\cos\\beta}{2} (1 + F' \\sin^3(\\beta/2))\n       (1 + F' \\cos^2\\theta\\sin^3\\theta_z)\n\n    where\n\n    .. math::\n\n       F' = 1 - (I_{d0} / GHI)^2\n\n    Klucher's 1979 model determines the diffuse irradiance from the sky\n    (ground reflected irradiance is not included in this algorithm) on a\n    tilted surface using the surface tilt angle, surface azimuth angle,\n    diffuse horizontal irradiance, direct normal irradiance, global\n    horizontal irradiance, extraterrestrial irradiance, sun zenith\n    angle, and sun azimuth angle.\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Surface tilt angles in decimal degrees. surface_tilt must be >=0\n        and <=180. The tilt angle is defined as degrees from horizontal\n        (e.g. surface facing up = 0, surface facing horizon = 90)\n\n    surface_azimuth : numeric\n        Surface azimuth angles in decimal degrees. surface_azimuth must\n        be >=0 and <=360. The Azimuth convention is defined as degrees\n        east of north (e.g. North = 0, South=180 East = 90, West = 270).\n\n    dhi : numeric\n        Diffuse horizontal irradiance in W/m^2. DHI must be >=0.\n\n    ghi : numeric\n        Global irradiance in W/m^2. DNI must be >=0.\n\n    solar_zenith : numeric\n        Apparent (refraction-corrected) zenith angles in decimal\n        degrees. solar_zenith must be >=0 and <=180.\n\n    solar_azimuth : numeric\n        Sun azimuth angles in decimal degrees. solar_azimuth must be >=0\n        and <=360. The Azimuth convention is defined as degrees east of\n        north (e.g. North = 0, East = 90, West = 270).\n\n    Returns\n    -------\n    diffuse : numeric\n        The sky diffuse component of the solar radiation.\n\n    References\n    ----------\n    .. [1] Loutzenhiser P.G. et. al. \"Empirical validation of models to compute\n       solar irradiance on inclined surfaces for building energy simulation\"\n       2007, Solar Energy vol. 81. pp. 254-267\n\n    .. [2] Klucher, T.M., 1979. Evaluation of models to predict insolation on\n       tilted surfaces. Solar Energy 23 (2), 111-114.\n    '''\n\n    # zenith angle with respect to panel normal.\n    cos_tt = aoi_projection(surface_tilt, surface_azimuth,\n                            solar_zenith, solar_azimuth)\n    cos_tt = np.maximum(cos_tt, 0)  # GH 526\n\n    # silence warning from 0 / 0\n    with np.errstate(invalid='ignore'):\n        F = 1 - ((dhi / ghi) ** 2)\n\n    try:\n        # fails with single point input\n        F.fillna(0, inplace=True)\n    except AttributeError:\n        F = np.where(np.isnan(F), 0, F)\n\n    term1 = 0.5 * (1 + tools.cosd(surface_tilt))\n    term2 = 1 + F * (tools.sind(0.5 * surface_tilt) ** 3)\n    term3 = 1 + F * (cos_tt ** 2) * (tools.sind(solar_zenith) ** 3)\n\n    sky_diffuse = dhi * term1 * term2 * term3\n\n    return sky_diffuse\n\n\ndef haydavies(surface_tilt, surface_azimuth, dhi, dni, dni_extra,\n              solar_zenith=None, solar_azimuth=None, projection_ratio=None):\n    r'''\n    Determine diffuse irradiance from the sky on a tilted surface using\n    Hay & Davies' 1980 model\n\n    .. math::\n        I_{d} = DHI ( A R_b + (1 - A) (\\frac{1 + \\cos\\beta}{2}) )\n\n    Hay and Davies' 1980 model determines the diffuse irradiance from\n    the sky (ground reflected irradiance is not included in this\n    algorithm) on a tilted surface using the surface tilt angle, surface\n    azimuth angle, diffuse horizontal irradiance, direct normal\n    irradiance, extraterrestrial irradiance, sun zenith angle, and sun\n    azimuth angle.\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Surface tilt angles in decimal degrees. The tilt angle is\n        defined as degrees from horizontal (e.g. surface facing up = 0,\n        surface facing horizon = 90)\n\n    surface_azimuth : numeric\n        Surface azimuth angles in decimal degrees. The azimuth\n        convention is defined as degrees east of north (e.g. North=0,\n        South=180, East=90, West=270).\n\n    dhi : numeric\n        Diffuse horizontal irradiance in W/m^2.\n\n    dni : numeric\n        Direct normal irradiance in W/m^2.\n\n    dni_extra : numeric\n        Extraterrestrial normal irradiance in W/m^2.\n\n    solar_zenith : None or numeric, default None\n        Solar apparent (refraction-corrected) zenith angles in decimal\n        degrees. Must supply ``solar_zenith`` and ``solar_azimuth`` or\n        supply ``projection_ratio``.\n\n    solar_azimuth : None or numeric, default None\n        Solar azimuth angles in decimal degrees. Must supply\n        ``solar_zenith`` and ``solar_azimuth`` or supply\n        ``projection_ratio``.\n\n    projection_ratio : None or numeric, default None\n        Ratio of angle of incidence projection to solar zenith angle\n        projection. Must supply ``solar_zenith`` and ``solar_azimuth``\n        or supply ``projection_ratio``.\n\n    Returns\n    --------\n    sky_diffuse : numeric\n        The sky diffuse component of the solar radiation.\n\n    References\n    -----------\n    .. [1] Loutzenhiser P.G. et. al. \"Empirical validation of models to\n       compute solar irradiance on inclined surfaces for building energy\n       simulation\" 2007, Solar Energy vol. 81. pp. 254-267\n\n    .. [2] Hay, J.E., Davies, J.A., 1980. Calculations of the solar\n       radiation incident on an inclined surface. In: Hay, J.E., Won, T.K.\n       (Eds.), Proc. of First Canadian Solar Radiation Data Workshop, 59.\n       Ministry of Supply and Services, Canada.\n    '''\n\n    # if necessary, calculate ratio of titled and horizontal beam irradiance\n    if projection_ratio is None:\n        cos_tt = aoi_projection(surface_tilt, surface_azimuth,\n                                solar_zenith, solar_azimuth)\n        cos_tt = np.maximum(cos_tt, 0)  # GH 526\n        cos_solar_zenith = tools.cosd(solar_zenith)\n        Rb = cos_tt / np.maximum(cos_solar_zenith, 0.01745)  # GH 432\n    else:\n        Rb = projection_ratio\n\n    # Anisotropy Index\n    AI = dni / dni_extra\n\n    # these are the () and [] sub-terms of the second term of eqn 7\n    term1 = 1 - AI\n    term2 = 0.5 * (1 + tools.cosd(surface_tilt))\n\n    sky_diffuse = dhi * (AI * Rb + term1 * term2)\n    sky_diffuse = np.maximum(sky_diffuse, 0)\n\n    return sky_diffuse\n\n\ndef reindl(surface_tilt, surface_azimuth, dhi, dni, ghi, dni_extra,\n           solar_zenith, solar_azimuth):\n    r'''\n    Determine diffuse irradiance from the sky on a tilted surface using\n    Reindl's 1990 model\n\n    .. math::\n\n       I_{d} = DHI (A R_b + (1 - A) (\\frac{1 + \\cos\\beta}{2})\n       (1 + \\sqrt{\\frac{I_{hb}}{I_h}} \\sin^3(\\beta/2)) )\n\n    Reindl's 1990 model determines the diffuse irradiance from the sky\n    (ground reflected irradiance is not included in this algorithm) on a\n    tilted surface using the surface tilt angle, surface azimuth angle,\n    diffuse horizontal irradiance, direct normal irradiance, global\n    horizontal irradiance, extraterrestrial irradiance, sun zenith\n    angle, and sun azimuth angle.\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Surface tilt angles in decimal degrees. The tilt angle is\n        defined as degrees from horizontal (e.g. surface facing up = 0,\n        surface facing horizon = 90)\n\n    surface_azimuth : numeric\n        Surface azimuth angles in decimal degrees. The azimuth\n        convention is defined as degrees east of north (e.g. North = 0,\n        South=180 East = 90, West = 270).\n\n    dhi : numeric\n        diffuse horizontal irradiance in W/m^2.\n\n    dni : numeric\n        direct normal irradiance in W/m^2.\n\n    ghi: numeric\n        Global irradiance in W/m^2.\n\n    dni_extra : numeric\n        Extraterrestrial normal irradiance in W/m^2.\n\n    solar_zenith : numeric\n        Apparent (refraction-corrected) zenith angles in decimal degrees.\n\n    solar_azimuth : numeric\n        Sun azimuth angles in decimal degrees. The azimuth convention is\n        defined as degrees east of north (e.g. North = 0, East = 90,\n        West = 270).\n\n    Returns\n    -------\n    poa_sky_diffuse : numeric\n        The sky diffuse component of the solar radiation.\n\n    Notes\n    -----\n    The poa_sky_diffuse calculation is generated from the Loutzenhiser et al.\n    (2007) paper, equation 8. Note that I have removed the beam and ground\n    reflectance portion of the equation and this generates ONLY the diffuse\n    radiation from the sky and circumsolar, so the form of the equation\n    varies slightly from equation 8.\n\n    References\n    ----------\n    .. [1] Loutzenhiser P.G. et. al. \"Empirical validation of models to\n       compute solar irradiance on inclined surfaces for building energy\n       simulation\" 2007, Solar Energy vol. 81. pp. 254-267\n\n    .. [2] Reindl, D.T., Beckmann, W.A., Duffie, J.A., 1990a. Diffuse\n       fraction correlations. Solar Energy 45(1), 1-7.\n\n    .. [3] Reindl, D.T., Beckmann, W.A., Duffie, J.A., 1990b. Evaluation of\n       hourly tilted surface radiation models. Solar Energy 45(1), 9-17.\n    '''\n\n    cos_tt = aoi_projection(surface_tilt, surface_azimuth,\n                            solar_zenith, solar_azimuth)\n    cos_tt = np.maximum(cos_tt, 0)  # GH 526\n\n    # do not apply cos(zen) limit here (needed for HB below)\n    cos_solar_zenith = tools.cosd(solar_zenith)\n\n    # ratio of titled and horizontal beam irradiance\n    Rb = cos_tt / np.maximum(cos_solar_zenith, 0.01745)  # GH 432\n\n    # Anisotropy Index\n    AI = dni / dni_extra\n\n    # DNI projected onto horizontal\n    HB = dni * cos_solar_zenith\n    HB = np.maximum(HB, 0)\n\n    # these are the () and [] sub-terms of the second term of eqn 8\n    term1 = 1 - AI\n    term2 = 0.5 * (1 + tools.cosd(surface_tilt))\n    term3 = 1 + np.sqrt(HB / ghi) * (tools.sind(0.5 * surface_tilt) ** 3)\n\n    sky_diffuse = dhi * (AI * Rb + term1 * term2 * term3)\n    sky_diffuse = np.maximum(sky_diffuse, 0)\n\n    return sky_diffuse\n\n\ndef king(surface_tilt, dhi, ghi, solar_zenith):\n    '''\n    Determine diffuse irradiance from the sky on a tilted surface using\n    the King model.\n\n    King's model determines the diffuse irradiance from the sky (ground\n    reflected irradiance is not included in this algorithm) on a tilted\n    surface using the surface tilt angle, diffuse horizontal irradiance,\n    global horizontal irradiance, and sun zenith angle. Note that this\n    model is not well documented and has not been published in any\n    fashion (as of January 2012).\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Surface tilt angles in decimal degrees. The tilt angle is\n        defined as degrees from horizontal (e.g. surface facing up = 0,\n        surface facing horizon = 90)\n\n    dhi : numeric\n        Diffuse horizontal irradiance in W/m^2.\n\n    ghi : numeric\n        Global horizontal irradiance in W/m^2.\n\n    solar_zenith : numeric\n        Apparent (refraction-corrected) zenith angles in decimal degrees.\n\n    Returns\n    --------\n    poa_sky_diffuse : numeric\n        The diffuse component of the solar radiation.\n    '''\n\n    sky_diffuse = (dhi * (1 + tools.cosd(surface_tilt)) / 2 + ghi *\n                   (0.012 * solar_zenith - 0.04) *\n                   (1 - tools.cosd(surface_tilt)) / 2)\n    sky_diffuse = np.maximum(sky_diffuse, 0)\n\n    return sky_diffuse\n\n\ndef perez(surface_tilt, surface_azimuth, dhi, dni, dni_extra,\n          solar_zenith, solar_azimuth, airmass,\n          model='allsitescomposite1990', return_components=False):\n    '''\n    Determine diffuse irradiance from the sky on a tilted surface using\n    one of the Perez models.\n\n    Perez models determine the diffuse irradiance from the sky (ground\n    reflected irradiance is not included in this algorithm) on a tilted\n    surface using the surface tilt angle, surface azimuth angle, diffuse\n    horizontal irradiance, direct normal irradiance, extraterrestrial\n    irradiance, sun zenith angle, sun azimuth angle, and relative (not\n    pressure-corrected) airmass. Optionally a selector may be used to\n    use any of Perez's model coefficient sets.\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Surface tilt angles in decimal degrees. surface_tilt must be >=0\n        and <=180. The tilt angle is defined as degrees from horizontal\n        (e.g. surface facing up = 0, surface facing horizon = 90)\n\n    surface_azimuth : numeric\n        Surface azimuth angles in decimal degrees. surface_azimuth must\n        be >=0 and <=360. The azimuth convention is defined as degrees\n        east of north (e.g. North = 0, South=180 East = 90, West = 270).\n\n    dhi : numeric\n        Diffuse horizontal irradiance in W/m^2. DHI must be >=0.\n\n    dni : numeric\n        Direct normal irradiance in W/m^2. DNI must be >=0.\n\n    dni_extra : numeric\n        Extraterrestrial normal irradiance in W/m^2.\n\n    solar_zenith : numeric\n        apparent (refraction-corrected) zenith angles in decimal\n        degrees. solar_zenith must be >=0 and <=180.\n\n    solar_azimuth : numeric\n        Sun azimuth angles in decimal degrees. solar_azimuth must be >=0\n        and <=360. The azimuth convention is defined as degrees east of\n        north (e.g. North = 0, East = 90, West = 270).\n\n    airmass : numeric\n        Relative (not pressure-corrected) airmass values. If AM is a\n        DataFrame it must be of the same size as all other DataFrame\n        inputs. AM must be >=0 (careful using the 1/sec(z) model of AM\n        generation)\n\n    model : string (optional, default='allsitescomposite1990')\n        A string which selects the desired set of Perez coefficients. If\n        model is not provided as an input, the default, '1990' will be\n        used. All possible model selections are:\n\n        * '1990'\n        * 'allsitescomposite1990' (same as '1990')\n        * 'allsitescomposite1988'\n        * 'sandiacomposite1988'\n        * 'usacomposite1988'\n        * 'france1988'\n        * 'phoenix1988'\n        * 'elmonte1988'\n        * 'osage1988'\n        * 'albuquerque1988'\n        * 'capecanaveral1988'\n        * 'albany1988'\n\n    return_components: bool (optional, default=False)\n        Flag used to decide whether to return the calculated diffuse components\n        or not.\n\n    Returns\n    --------\n    numeric, OrderedDict, or DataFrame\n        Return type controlled by `return_components` argument.\n        If ``return_components=False``, `sky_diffuse` is returned.\n        If ``return_components=True``, `diffuse_components` is returned.\n\n    sky_diffuse : numeric\n        The sky diffuse component of the solar radiation on a tilted\n        surface.\n\n    diffuse_components : OrderedDict (array input) or DataFrame (Series input)\n        Keys/columns are:\n            * sky_diffuse: Total sky diffuse\n            * isotropic\n            * circumsolar\n            * horizon\n\n\n    References\n    ----------\n    .. [1] Loutzenhiser P.G. et. al. \"Empirical validation of models to\n       compute solar irradiance on inclined surfaces for building energy\n       simulation\" 2007, Solar Energy vol. 81. pp. 254-267\n\n    .. [2] Perez, R., Seals, R., Ineichen, P., Stewart, R., Menicucci, D.,\n       1987. A new simplified version of the Perez diffuse irradiance model\n       for tilted surfaces. Solar Energy 39(3), 221-232.\n\n    .. [3] Perez, R., Ineichen, P., Seals, R., Michalsky, J., Stewart, R.,\n       1990. Modeling daylight availability and irradiance components from\n       direct and global irradiance. Solar Energy 44 (5), 271-289.\n\n    .. [4] Perez, R. et. al 1988. \"The Development and Verification of the\n       Perez Diffuse Radiation Model\". SAND88-7030\n    '''\n\n    kappa = 1.041  # for solar_zenith in radians\n    z = np.radians(solar_zenith)  # convert to radians\n\n    # delta is the sky's \"brightness\"\n    delta = dhi * airmass / dni_extra\n\n    # epsilon is the sky's \"clearness\"\n    with np.errstate(invalid='ignore'):\n        eps = ((dhi + dni) / dhi + kappa * (z ** 3)) / (1 + kappa * (z ** 3))\n\n    # numpy indexing below will not work with a Series\n    if isinstance(eps, pd.Series):\n        eps = eps.values\n\n    # Perez et al define clearness bins according to the following\n    # rules. 1 = overcast ... 8 = clear (these names really only make\n    # sense for small zenith angles, but...) these values will\n    # eventually be used as indicies for coeffecient look ups\n    ebin = np.digitize(eps, (0., 1.065, 1.23, 1.5, 1.95, 2.8, 4.5, 6.2))\n    ebin = np.array(ebin)  # GH 642\n    ebin[np.isnan(eps)] = 0\n\n    # correct for 0 indexing in coeffecient lookup\n    # later, ebin = -1 will yield nan coefficients\n    ebin -= 1\n\n    # The various possible sets of Perez coefficients are contained\n    # in a subfunction to clean up the code.\n    F1c, F2c = _get_perez_coefficients(model)\n\n    # results in invalid eps (ebin = -1) being mapped to nans\n    nans = np.array([np.nan, np.nan, np.nan])\n    F1c = np.vstack((F1c, nans))\n    F2c = np.vstack((F2c, nans))\n\n    F1 = (F1c[ebin, 0] + F1c[ebin, 1] * delta + F1c[ebin, 2] * z)\n    F1 = np.maximum(F1, 0)\n\n    F2 = (F2c[ebin, 0] + F2c[ebin, 1] * delta + F2c[ebin, 2] * z)\n    F2 = np.maximum(F2, 0)\n\n    A = aoi_projection(surface_tilt, surface_azimuth,\n                       solar_zenith, solar_azimuth)\n    A = np.maximum(A, 0)\n\n    B = tools.cosd(solar_zenith)\n    B = np.maximum(B, tools.cosd(85))\n\n    # Calculate Diffuse POA from sky dome\n    term1 = 0.5 * (1 - F1) * (1 + tools.cosd(surface_tilt))\n    term2 = F1 * A / B\n    term3 = F2 * tools.sind(surface_tilt)\n\n    sky_diffuse = np.maximum(dhi * (term1 + term2 + term3), 0)\n\n    # we've preserved the input type until now, so don't ruin it!\n    if isinstance(sky_diffuse, pd.Series):\n        sky_diffuse[np.isnan(airmass)] = 0\n    else:\n        sky_diffuse = np.where(np.isnan(airmass), 0, sky_diffuse)\n\n    if return_components:\n        diffuse_components = OrderedDict()\n        diffuse_components['sky_diffuse'] = sky_diffuse\n\n        # Calculate the different components\n        diffuse_components['isotropic'] = dhi * term1\n        diffuse_components['circumsolar'] = dhi * term2\n        diffuse_components['horizon'] = dhi * term3\n\n        # Set values of components to 0 when sky_diffuse is 0\n        mask = sky_diffuse == 0\n        if isinstance(sky_diffuse, pd.Series):\n            diffuse_components = pd.DataFrame(diffuse_components)\n            diffuse_components.loc[mask] = 0\n        else:\n            diffuse_components = {k: np.where(mask, 0, v) for k, v in\n                                  diffuse_components.items()}\n        return diffuse_components\n    else:\n        return sky_diffuse\n\n\ndef clearsky_index(ghi, clearsky_ghi, max_clearsky_index=2.0):\n    \"\"\"\n    Calculate the clearsky index.\n\n    The clearsky index is the ratio of global to clearsky global irradiance.\n    Negative and non-finite clearsky index values will be truncated to zero.\n\n    Parameters\n    ----------\n    ghi : numeric\n        Global horizontal irradiance in W/m^2.\n\n    clearsky_ghi : numeric\n        Modeled clearsky GHI\n\n    max_clearsky_index : numeric, default 2.0\n        Maximum value of the clearsky index. The default, 2.0, allows\n        for over-irradiance events typically seen in sub-hourly data.\n\n    Returns\n    -------\n    clearsky_index : numeric\n        Clearsky index\n    \"\"\"\n    clearsky_index = ghi / clearsky_ghi\n    # set +inf, -inf, and nans to zero\n    clearsky_index = np.where(~np.isfinite(clearsky_index), 0,\n                              clearsky_index)\n    # but preserve nans in the input arrays\n    input_is_nan = ~np.isfinite(ghi) | ~np.isfinite(clearsky_ghi)\n    clearsky_index = np.where(input_is_nan, np.nan, clearsky_index)\n\n    clearsky_index = np.maximum(clearsky_index, 0)\n    clearsky_index = np.minimum(clearsky_index, max_clearsky_index)\n\n    # preserve input type\n    if isinstance(ghi, pd.Series):\n        clearsky_index = pd.Series(clearsky_index, index=ghi.index)\n\n    return clearsky_index\n\n\ndef clearness_index(ghi, solar_zenith, extra_radiation, min_cos_zenith=0.065,\n                    max_clearness_index=2.0):\n    \"\"\"\n    Calculate the clearness index.\n\n    The clearness index is the ratio of global to extraterrestrial\n    irradiance on a horizontal plane [1]_.\n\n    Parameters\n    ----------\n    ghi : numeric\n        Global horizontal irradiance in W/m^2.\n\n    solar_zenith : numeric\n        True (not refraction-corrected) solar zenith angle in decimal\n        degrees.\n\n    extra_radiation : numeric\n        Irradiance incident at the top of the atmosphere\n\n    min_cos_zenith : numeric, default 0.065\n        Minimum value of cos(zenith) to allow when calculating global\n        clearness index `kt`. Equivalent to zenith = 86.273 degrees.\n\n    max_clearness_index : numeric, default 2.0\n        Maximum value of the clearness index. The default, 2.0, allows\n        for over-irradiance events typically seen in sub-hourly data.\n        NREL's SRRL Fortran code used 0.82 for hourly data.\n\n    Returns\n    -------\n    kt : numeric\n        Clearness index\n\n    References\n    ----------\n    .. [1] Maxwell, E. L., \"A Quasi-Physical Model for Converting Hourly\n           Global Horizontal to Direct Normal Insolation\", Technical\n           Report No. SERI/TR-215-3087, Golden, CO: Solar Energy Research\n           Institute, 1987.\n    \"\"\"\n    cos_zenith = tools.cosd(solar_zenith)\n    I0h = extra_radiation * np.maximum(cos_zenith, min_cos_zenith)\n    # consider adding\n    # with np.errstate(invalid='ignore', divide='ignore'):\n    # to kt calculation, but perhaps it's good to allow these\n    # warnings to the users that override min_cos_zenith\n    kt = ghi / I0h\n    kt = np.maximum(kt, 0)\n    kt = np.minimum(kt, max_clearness_index)\n    return kt\n\n\ndef clearness_index_zenith_independent(clearness_index, airmass,\n                                       max_clearness_index=2.0):\n    \"\"\"\n    Calculate the zenith angle independent clearness index.\n\n    See [1]_ for details.\n\n    Parameters\n    ----------\n    clearness_index : numeric\n        Ratio of global to extraterrestrial irradiance on a horizontal\n        plane\n\n    airmass : numeric\n        Airmass\n\n    max_clearness_index : numeric, default 2.0\n        Maximum value of the clearness index. The default, 2.0, allows\n        for over-irradiance events typically seen in sub-hourly data.\n        NREL's SRRL Fortran code used 0.82 for hourly data.\n\n    Returns\n    -------\n    kt_prime : numeric\n        Zenith independent clearness index\n\n    References\n    ----------\n    .. [1] Perez, R., P. Ineichen, E. Maxwell, R. Seals and A. Zelenka,\n           (1992). \"Dynamic Global-to-Direct Irradiance Conversion Models\".\n           ASHRAE Transactions-Research Series, pp. 354-369\n    \"\"\"\n    # Perez eqn 1\n    kt_prime = clearness_index / _kt_kt_prime_factor(airmass)\n    kt_prime = np.maximum(kt_prime, 0)\n    kt_prime = np.minimum(kt_prime, max_clearness_index)\n    return kt_prime\n\n\ndef _kt_kt_prime_factor(airmass):\n    \"\"\"\n    Calculate the conversion factor between kt and kt prime.\n    Function is useful because DIRINT and GTI-DIRINT both use this.\n    \"\"\"\n    # consider adding\n    # airmass = np.maximum(airmass, 12)  # GH 450\n    return 1.031 * np.exp(-1.4 / (0.9 + 9.4 / airmass)) + 0.1\n\n\ndef disc(ghi, solar_zenith, datetime_or_doy, pressure=101325,\n         min_cos_zenith=0.065, max_zenith=87, max_airmass=12):\n    \"\"\"\n    Estimate Direct Normal Irradiance from Global Horizontal Irradiance\n    using the DISC model.\n\n    The DISC algorithm converts global horizontal irradiance to direct\n    normal irradiance through empirical relationships between the global\n    and direct clearness indices.\n\n    The pvlib implementation limits the clearness index to 1.\n\n    The original report describing the DISC model [1]_ uses the\n    relative airmass rather than the absolute (pressure-corrected)\n    airmass. However, the NREL implementation of the DISC model [2]_\n    uses absolute airmass. PVLib Matlab also uses the absolute airmass.\n    pvlib python defaults to absolute airmass, but the relative airmass\n    can be used by supplying `pressure=None`.\n\n    Parameters\n    ----------\n    ghi : numeric\n        Global horizontal irradiance in W/m^2.\n\n    solar_zenith : numeric\n        True (not refraction-corrected) solar zenith angles in decimal\n        degrees.\n\n    datetime_or_doy : int, float, array, pd.DatetimeIndex\n        Day of year or array of days of year e.g.\n        pd.DatetimeIndex.dayofyear, or pd.DatetimeIndex.\n\n    pressure : None or numeric, default 101325\n        Site pressure in Pascal. If None, relative airmass is used\n        instead of absolute (pressure-corrected) airmass.\n\n    min_cos_zenith : numeric, default 0.065\n        Minimum value of cos(zenith) to allow when calculating global\n        clearness index `kt`. Equivalent to zenith = 86.273 degrees.\n\n    max_zenith : numeric, default 87\n        Maximum value of zenith to allow in DNI calculation. DNI will be\n        set to 0 for times with zenith values greater than `max_zenith`.\n\n    max_airmass : numeric, default 12\n        Maximum value of the airmass to allow in Kn calculation.\n        Default value (12) comes from range over which Kn was fit\n        to airmass in the original paper.\n\n    Returns\n    -------\n    output : OrderedDict or DataFrame\n        Contains the following keys:\n\n        * ``dni``: The modeled direct normal irradiance\n          in W/m^2 provided by the\n          Direct Insolation Simulation Code (DISC) model.\n        * ``kt``: Ratio of global to extraterrestrial\n          irradiance on a horizontal plane.\n        * ``airmass``: Airmass\n\n    References\n    ----------\n    .. [1] Maxwell, E. L., \"A Quasi-Physical Model for Converting Hourly\n       Global Horizontal to Direct Normal Insolation\", Technical\n       Report No. SERI/TR-215-3087, Golden, CO: Solar Energy Research\n       Institute, 1987.\n\n    .. [2] Maxwell, E. \"DISC Model\", Excel Worksheet.\n       https://www.nrel.gov/grid/solar-resource/disc.html\n\n    See Also\n    --------\n    dirint\n    \"\"\"\n\n    # this is the I0 calculation from the reference\n    # SSC uses solar constant = 1367.0 (checked 2018 08 15)\n    I0 = get_extra_radiation(datetime_or_doy, 1370., 'spencer')\n\n    kt = clearness_index(ghi, solar_zenith, I0, min_cos_zenith=min_cos_zenith,\n                         max_clearness_index=1)\n\n    am = atmosphere.get_relative_airmass(solar_zenith, model='kasten1966')\n    if pressure is not None:\n        am = atmosphere.get_absolute_airmass(am, pressure)\n\n    Kn, am = _disc_kn(kt, am, max_airmass=max_airmass)\n    dni = Kn * I0\n\n    bad_values = (solar_zenith > max_zenith) | (ghi < 0) | (dni < 0)\n    dni = np.where(bad_values, 0, dni)\n\n    output = OrderedDict()\n    output['dni'] = dni\n    output['kt'] = kt\n    output['airmass'] = am\n\n    if isinstance(datetime_or_doy, pd.DatetimeIndex):\n        output = pd.DataFrame(output, index=datetime_or_doy)\n\n    return output\n\n\ndef _disc_kn(clearness_index, airmass, max_airmass=12):\n    \"\"\"\n    Calculate Kn for `disc`\n\n    Parameters\n    ----------\n    clearness_index : numeric\n    airmass : numeric\n    max_airmass : float\n        airmass > max_airmass is set to max_airmass before being used\n        in calculating Kn.\n\n    Returns\n    -------\n    Kn : numeric\n    am : numeric\n        airmass used in the calculation of Kn. am <= max_airmass.\n    \"\"\"\n    # short names for equations\n    kt = clearness_index\n    am = airmass\n\n    am = np.minimum(am, max_airmass)  # GH 450\n\n    # powers of kt will be used repeatedly, so compute only once\n    kt2 = kt * kt  # about the same as kt ** 2\n    kt3 = kt2 * kt  # 5-10x faster than kt ** 3\n\n    bools = (kt <= 0.6)\n    a = np.where(bools,\n                 0.512 - 1.56*kt + 2.286*kt2 - 2.222*kt3,\n                 -5.743 + 21.77*kt - 27.49*kt2 + 11.56*kt3)\n    b = np.where(bools,\n                 0.37 + 0.962*kt,\n                 41.4 - 118.5*kt + 66.05*kt2 + 31.9*kt3)\n    c = np.where(bools,\n                 -0.28 + 0.932*kt - 2.048*kt2,\n                 -47.01 + 184.2*kt - 222.0*kt2 + 73.81*kt3)\n\n    delta_kn = a + b * np.exp(c*am)\n\n    Knc = 0.866 - 0.122*am + 0.0121*am**2 - 0.000653*am**3 + 1.4e-05*am**4\n    Kn = Knc - delta_kn\n    return Kn, am\n\n\ndef dirint(ghi, solar_zenith, times, pressure=101325., use_delta_kt_prime=True,\n           temp_dew=None, min_cos_zenith=0.065, max_zenith=87):\n    \"\"\"\n    Determine DNI from GHI using the DIRINT modification of the DISC\n    model.\n\n    Implements the modified DISC model known as \"DIRINT\" introduced in\n    [1]. DIRINT predicts direct normal irradiance (DNI) from measured\n    global horizontal irradiance (GHI). DIRINT improves upon the DISC\n    model by using time-series GHI data and dew point temperature\n    information. The effectiveness of the DIRINT model improves with\n    each piece of information provided.\n\n    The pvlib implementation limits the clearness index to 1.\n\n    Parameters\n    ----------\n    ghi : array-like\n        Global horizontal irradiance in W/m^2.\n\n    solar_zenith : array-like\n        True (not refraction-corrected) solar_zenith angles in decimal\n        degrees.\n\n    times : DatetimeIndex\n\n    pressure : float or array-like, default 101325.0\n        The site pressure in Pascal. Pressure may be measured or an\n        average pressure may be calculated from site altitude.\n\n    use_delta_kt_prime : bool, default True\n        If True, indicates that the stability index delta_kt_prime is\n        included in the model. The stability index adjusts the estimated\n        DNI in response to dynamics in the time series of GHI. It is\n        recommended that delta_kt_prime is not used if the time between\n        GHI points is 1.5 hours or greater. If use_delta_kt_prime=True,\n        input data must be Series.\n\n    temp_dew : None, float, or array-like, default None\n        Surface dew point temperatures, in degrees C. Values of temp_dew\n        may be numeric or NaN. Any single time period point with a\n        temp_dew=NaN does not have dew point improvements applied. If\n        temp_dew is not provided, then dew point improvements are not\n        applied.\n\n    min_cos_zenith : numeric, default 0.065\n        Minimum value of cos(zenith) to allow when calculating global\n        clearness index `kt`. Equivalent to zenith = 86.273 degrees.\n\n    max_zenith : numeric, default 87\n        Maximum value of zenith to allow in DNI calculation. DNI will be\n        set to 0 for times with zenith values greater than `max_zenith`.\n\n    Returns\n    -------\n    dni : array-like\n        The modeled direct normal irradiance in W/m^2 provided by the\n        DIRINT model.\n\n    Notes\n    -----\n    DIRINT model requires time series data (ie. one of the inputs must\n    be a vector of length > 2).\n\n    References\n    ----------\n    .. [1] Perez, R., P. Ineichen, E. Maxwell, R. Seals and A. Zelenka,\n       (1992). \"Dynamic Global-to-Direct Irradiance Conversion Models\".\n       ASHRAE Transactions-Research Series, pp. 354-369\n\n    .. [2] Maxwell, E. L., \"A Quasi-Physical Model for Converting Hourly\n       Global Horizontal to Direct Normal Insolation\", Technical Report No.\n       SERI/TR-215-3087, Golden, CO: Solar Energy Research Institute, 1987.\n    \"\"\"\n\n    disc_out = disc(ghi, solar_zenith, times, pressure=pressure,\n                    min_cos_zenith=min_cos_zenith, max_zenith=max_zenith)\n    airmass = disc_out['airmass']\n    kt = disc_out['kt']\n\n    kt_prime = clearness_index_zenith_independent(\n        kt, airmass, max_clearness_index=1)\n    delta_kt_prime = _delta_kt_prime_dirint(kt_prime, use_delta_kt_prime,\n                                            times)\n    w = _temp_dew_dirint(temp_dew, times)\n\n    dirint_coeffs = _dirint_coeffs(times, kt_prime, solar_zenith, w,\n                                   delta_kt_prime)\n\n    # Perez eqn 5\n    dni = disc_out['dni'] * dirint_coeffs\n\n    return dni\n\n\ndef _dirint_from_dni_ktprime(dni, kt_prime, solar_zenith, use_delta_kt_prime,\n                             temp_dew):\n    \"\"\"\n    Calculate DIRINT DNI from supplied DISC DNI and Kt'.\n\n    Supports :py:func:`gti_dirint`\n    \"\"\"\n    times = dni.index\n    delta_kt_prime = _delta_kt_prime_dirint(kt_prime, use_delta_kt_prime,\n                                            times)\n    w = _temp_dew_dirint(temp_dew, times)\n    dirint_coeffs = _dirint_coeffs(times, kt_prime, solar_zenith, w,\n                                   delta_kt_prime)\n    dni_dirint = dni * dirint_coeffs\n    return dni_dirint\n\n\ndef _delta_kt_prime_dirint(kt_prime, use_delta_kt_prime, times):\n    \"\"\"\n    Calculate delta_kt_prime (Perez eqn 2 and eqn 3), or return a default value\n    for use with :py:func:`_dirint_bins`.\n    \"\"\"\n    if use_delta_kt_prime:\n        # Perez eqn 2\n        kt_next = kt_prime.shift(-1)\n        kt_previous = kt_prime.shift(1)\n        # replace nan with values that implement Perez Eq 3 for first and last\n        # positions. Use kt_previous and kt_next to handle series of length 1\n        kt_next.iloc[-1] = kt_previous.iloc[-1]\n        kt_previous.iloc[0] = kt_next.iloc[0]\n        delta_kt_prime = 0.5 * ((kt_prime - kt_next).abs().add(\n                                (kt_prime - kt_previous).abs(),\n                                fill_value=0))\n    else:\n        # do not change unless also modifying _dirint_bins\n        delta_kt_prime = pd.Series(-1, index=times)\n    return delta_kt_prime\n\n\ndef _temp_dew_dirint(temp_dew, times):\n    \"\"\"\n    Calculate precipitable water from surface dew point temp (Perez eqn 4),\n    or return a default value for use with :py:func:`_dirint_bins`.\n    \"\"\"\n    if temp_dew is not None:\n        # Perez eqn 4\n        w = pd.Series(np.exp(0.07 * temp_dew - 0.075), index=times)\n    else:\n        # do not change unless also modifying _dirint_bins\n        w = pd.Series(-1, index=times)\n    return w\n\n\ndef _dirint_coeffs(times, kt_prime, solar_zenith, w, delta_kt_prime):\n    \"\"\"\n    Determine the DISC to DIRINT multiplier `dirint_coeffs`.\n\n    dni = disc_out['dni'] * dirint_coeffs\n\n    Parameters\n    ----------\n    times : pd.DatetimeIndex\n    kt_prime : Zenith-independent clearness index\n    solar_zenith : Solar zenith angle\n    w : precipitable water estimated from surface dew-point temperature\n    delta_kt_prime : stability index\n\n    Returns\n    -------\n    dirint_coeffs : array-like\n    \"\"\"\n    kt_prime_bin, zenith_bin, w_bin, delta_kt_prime_bin = \\\n        _dirint_bins(times, kt_prime, solar_zenith, w, delta_kt_prime)\n\n    # get the coefficients\n    coeffs = _get_dirint_coeffs()\n\n    # subtract 1 to account for difference between MATLAB-style bin\n    # assignment and Python-style array lookup.\n    dirint_coeffs = coeffs[kt_prime_bin-1, zenith_bin-1,\n                           delta_kt_prime_bin-1, w_bin-1]\n\n    # convert unassigned bins to nan\n    dirint_coeffs = np.where((kt_prime_bin == 0) | (zenith_bin == 0) |\n                             (w_bin == 0) | (delta_kt_prime_bin == 0),\n                             np.nan, dirint_coeffs)\n    return dirint_coeffs\n\n\ndef _dirint_bins(times, kt_prime, zenith, w, delta_kt_prime):\n    \"\"\"\n    Determine the bins for the DIRINT coefficients.\n\n    Parameters\n    ----------\n    times : pd.DatetimeIndex\n    kt_prime : Zenith-independent clearness index\n    zenith : Solar zenith angle\n    w : precipitable water estimated from surface dew-point temperature\n    delta_kt_prime : stability index\n\n    Returns\n    -------\n    tuple of kt_prime_bin, zenith_bin, w_bin, delta_kt_prime_bin\n    \"\"\"\n    # @wholmgren: the following bin assignments use MATLAB's 1-indexing.\n    # Later, we'll subtract 1 to conform to Python's 0-indexing.\n\n    # Create kt_prime bins\n    kt_prime_bin = pd.Series(0, index=times, dtype=np.int64)\n    kt_prime_bin[(kt_prime >= 0) & (kt_prime < 0.24)] = 1\n    kt_prime_bin[(kt_prime >= 0.24) & (kt_prime < 0.4)] = 2\n    kt_prime_bin[(kt_prime >= 0.4) & (kt_prime < 0.56)] = 3\n    kt_prime_bin[(kt_prime >= 0.56) & (kt_prime < 0.7)] = 4\n    kt_prime_bin[(kt_prime >= 0.7) & (kt_prime < 0.8)] = 5\n    kt_prime_bin[(kt_prime >= 0.8) & (kt_prime <= 1)] = 6\n\n    # Create zenith angle bins\n    zenith_bin = pd.Series(0, index=times, dtype=np.int64)\n    zenith_bin[(zenith >= 0) & (zenith < 25)] = 1\n    zenith_bin[(zenith >= 25) & (zenith < 40)] = 2\n    zenith_bin[(zenith >= 40) & (zenith < 55)] = 3\n    zenith_bin[(zenith >= 55) & (zenith < 70)] = 4\n    zenith_bin[(zenith >= 70) & (zenith < 80)] = 5\n    zenith_bin[(zenith >= 80)] = 6\n\n    # Create the bins for w based on dew point temperature\n    w_bin = pd.Series(0, index=times, dtype=np.int64)\n    w_bin[(w >= 0) & (w < 1)] = 1\n    w_bin[(w >= 1) & (w < 2)] = 2\n    w_bin[(w >= 2) & (w < 3)] = 3\n    w_bin[(w >= 3)] = 4\n    w_bin[(w == -1)] = 5\n\n    # Create delta_kt_prime binning.\n    delta_kt_prime_bin = pd.Series(0, index=times, dtype=np.int64)\n    delta_kt_prime_bin[(delta_kt_prime >= 0) & (delta_kt_prime < 0.015)] = 1\n    delta_kt_prime_bin[(delta_kt_prime >= 0.015) &\n                       (delta_kt_prime < 0.035)] = 2\n    delta_kt_prime_bin[(delta_kt_prime >= 0.035) & (delta_kt_prime < 0.07)] = 3\n    delta_kt_prime_bin[(delta_kt_prime >= 0.07) & (delta_kt_prime < 0.15)] = 4\n    delta_kt_prime_bin[(delta_kt_prime >= 0.15) & (delta_kt_prime < 0.3)] = 5\n    delta_kt_prime_bin[(delta_kt_prime >= 0.3) & (delta_kt_prime <= 1)] = 6\n    delta_kt_prime_bin[delta_kt_prime == -1] = 7\n\n    return kt_prime_bin, zenith_bin, w_bin, delta_kt_prime_bin\n\n\ndef dirindex(ghi, ghi_clearsky, dni_clearsky, zenith, times, pressure=101325.,\n             use_delta_kt_prime=True, temp_dew=None, min_cos_zenith=0.065,\n             max_zenith=87):\n    \"\"\"\n    Determine DNI from GHI using the DIRINDEX model.\n\n    The DIRINDEX model [1] modifies the DIRINT model implemented in\n    :py:func:``pvlib.irradiance.dirint`` by taking into account information\n    from a clear sky model. It is recommended that ``ghi_clearsky`` be\n    calculated using the Ineichen clear sky model\n    :py:func:``pvlib.clearsky.ineichen`` with ``perez_enhancement=True``.\n\n    The pvlib implementation limits the clearness index to 1.\n\n    Parameters\n    ----------\n    ghi : array-like\n        Global horizontal irradiance in W/m^2.\n\n    ghi_clearsky : array-like\n        Global horizontal irradiance from clear sky model, in W/m^2.\n\n    dni_clearsky : array-like\n        Direct normal irradiance from clear sky model, in W/m^2.\n\n    zenith : array-like\n        True (not refraction-corrected) zenith angles in decimal\n        degrees. If Z is a vector it must be of the same size as all\n        other vector inputs. Z must be >=0 and <=180.\n\n    times : DatetimeIndex\n\n    pressure : float or array-like, default 101325.0\n        The site pressure in Pascal. Pressure may be measured or an\n        average pressure may be calculated from site altitude.\n\n    use_delta_kt_prime : bool, default True\n        If True, indicates that the stability index delta_kt_prime is\n        included in the model. The stability index adjusts the estimated\n        DNI in response to dynamics in the time series of GHI. It is\n        recommended that delta_kt_prime is not used if the time between\n        GHI points is 1.5 hours or greater. If use_delta_kt_prime=True,\n        input data must be Series.\n\n    temp_dew : None, float, or array-like, default None\n        Surface dew point temperatures, in degrees C. Values of temp_dew\n        may be numeric or NaN. Any single time period point with a\n        temp_dew=NaN does not have dew point improvements applied. If\n        temp_dew is not provided, then dew point improvements are not\n        applied.\n\n    min_cos_zenith : numeric, default 0.065\n        Minimum value of cos(zenith) to allow when calculating global\n        clearness index `kt`. Equivalent to zenith = 86.273 degrees.\n\n    max_zenith : numeric, default 87\n        Maximum value of zenith to allow in DNI calculation. DNI will be\n        set to 0 for times with zenith values greater than `max_zenith`.\n\n    Returns\n    -------\n    dni : array-like\n        The modeled direct normal irradiance in W/m^2.\n\n    Notes\n    -----\n    DIRINDEX model requires time series data (ie. one of the inputs must\n    be a vector of length > 2).\n\n    References\n    ----------\n    .. [1] Perez, R., Ineichen, P., Moore, K., Kmiecik, M., Chain, C., George,\n       R., & Vignola, F. (2002). A new operational model for satellite-derived\n       irradiances: description and validation. Solar Energy, 73(5), 307-317.\n    \"\"\"\n\n    dni_dirint = dirint(ghi, zenith, times, pressure=pressure,\n                        use_delta_kt_prime=use_delta_kt_prime,\n                        temp_dew=temp_dew, min_cos_zenith=min_cos_zenith,\n                        max_zenith=max_zenith)\n\n    dni_dirint_clearsky = dirint(ghi_clearsky, zenith, times,\n                                 pressure=pressure,\n                                 use_delta_kt_prime=use_delta_kt_prime,\n                                 temp_dew=temp_dew,\n                                 min_cos_zenith=min_cos_zenith,\n                                 max_zenith=max_zenith)\n\n    dni_dirindex = dni_clearsky * dni_dirint / dni_dirint_clearsky\n\n    dni_dirindex[dni_dirindex < 0] = 0.\n\n    return dni_dirindex\n\n\ndef gti_dirint(poa_global, aoi, solar_zenith, solar_azimuth, times,\n               surface_tilt, surface_azimuth, pressure=101325.,\n               use_delta_kt_prime=True, temp_dew=None, albedo=.25,\n               model='perez', model_perez='allsitescomposite1990',\n               calculate_gt_90=True, max_iterations=30):\n    \"\"\"\n    Determine GHI, DNI, DHI from POA global using the GTI DIRINT model.\n\n    The GTI DIRINT model is described in [1]_.\n\n    .. warning::\n\n        Model performance is poor for AOI greater than approximately\n        80 degrees `and` plane of array irradiance greater than\n        approximately 200 W/m^2.\n\n    Parameters\n    ----------\n    poa_global : array-like\n        Plane of array global irradiance in W/m^2.\n\n    aoi : array-like\n        Angle of incidence of solar rays with respect to the module\n        surface normal.\n\n    solar_zenith : array-like\n        True (not refraction-corrected) solar zenith angles in decimal\n        degrees.\n\n    solar_azimuth : array-like\n        Solar azimuth angles in decimal degrees.\n\n    times : DatetimeIndex\n        Time indices for the input array-like data.\n\n    surface_tilt : numeric\n        Surface tilt angles in decimal degrees. Tilt must be >=0 and\n        <=180. The tilt angle is defined as degrees from horizontal\n        (e.g. surface facing up = 0, surface facing horizon = 90).\n\n    surface_azimuth : numeric\n        Surface azimuth angles in decimal degrees. surface_azimuth must\n        be >=0 and <=360. The Azimuth convention is defined as degrees\n        east of north (e.g. North = 0, South=180 East = 90, West = 270).\n\n    pressure : numeric, default 101325.0\n        The site pressure in Pascal. Pressure may be measured or an\n        average pressure may be calculated from site altitude.\n\n    use_delta_kt_prime : bool, default True\n        If True, indicates that the stability index delta_kt_prime is\n        included in the model. The stability index adjusts the estimated\n        DNI in response to dynamics in the time series of GHI. It is\n        recommended that delta_kt_prime is not used if the time between\n        GHI points is 1.5 hours or greater. If use_delta_kt_prime=True,\n        input data must be Series.\n\n    temp_dew : None, float, or array-like, default None\n        Surface dew point temperatures, in degrees C. Values of temp_dew\n        may be numeric or NaN. Any single time period point with a\n        temp_dew=NaN does not have dew point improvements applied. If\n        temp_dew is not provided, then dew point improvements are not\n        applied.\n\n    albedo : numeric, default 0.25\n        Surface albedo\n\n    model : String, default 'isotropic'\n        Irradiance model.\n\n    model_perez : String, default 'allsitescomposite1990'\n        Used only if model='perez'. See :py:func:`perez`.\n\n    calculate_gt_90 : bool, default True\n        Controls if the algorithm evaluates inputs with AOI >= 90 degrees.\n        If False, returns nan for AOI >= 90 degrees. Significant speed ups\n        can be achieved by setting this parameter to False.\n\n    max_iterations : int, default 30\n        Maximum number of iterations for the aoi < 90 deg algorithm.\n\n    Returns\n    -------\n    data : OrderedDict or DataFrame\n        Contains the following keys/columns:\n\n            * ``ghi``: the modeled global horizontal irradiance in W/m^2.\n            * ``dni``: the modeled direct normal irradiance in W/m^2.\n            * ``dhi``: the modeled diffuse horizontal irradiance in\n              W/m^2.\n\n    References\n    ----------\n    .. [1] B. Marion, A model for deriving the direct normal and\n           diffuse horizontal irradiance from the global tilted\n           irradiance, Solar Energy 122, 1037-1046.\n           :doi:`10.1016/j.solener.2015.10.024`\n    \"\"\"\n\n    aoi_lt_90 = aoi < 90\n\n    # for AOI less than 90 degrees\n    ghi, dni, dhi, kt_prime = _gti_dirint_lt_90(\n        poa_global, aoi, aoi_lt_90, solar_zenith, solar_azimuth, times,\n        surface_tilt, surface_azimuth, pressure=pressure,\n        use_delta_kt_prime=use_delta_kt_prime, temp_dew=temp_dew,\n        albedo=albedo, model=model, model_perez=model_perez,\n        max_iterations=max_iterations)\n\n    # for AOI greater than or equal to 90 degrees\n    if calculate_gt_90:\n        ghi_gte_90, dni_gte_90, dhi_gte_90 = _gti_dirint_gte_90(\n            poa_global, aoi, solar_zenith, solar_azimuth,\n            surface_tilt, times, kt_prime,\n            pressure=pressure, temp_dew=temp_dew, albedo=albedo)\n    else:\n        ghi_gte_90, dni_gte_90, dhi_gte_90 = np.nan, np.nan, np.nan\n\n    # put the AOI < 90 and AOI >= 90 conditions together\n    output = OrderedDict()\n    output['ghi'] = ghi.where(aoi_lt_90, ghi_gte_90)\n    output['dni'] = dni.where(aoi_lt_90, dni_gte_90)\n    output['dhi'] = dhi.where(aoi_lt_90, dhi_gte_90)\n\n    output = pd.DataFrame(output, index=times)\n\n    return output\n\n\ndef _gti_dirint_lt_90(poa_global, aoi, aoi_lt_90, solar_zenith, solar_azimuth,\n                      times, surface_tilt, surface_azimuth, pressure=101325.,\n                      use_delta_kt_prime=True, temp_dew=None, albedo=.25,\n                      model='perez', model_perez='allsitescomposite1990',\n                      max_iterations=30):\n    \"\"\"\n    GTI-DIRINT model for AOI < 90 degrees. See Marion 2015 Section 2.1.\n\n    See gti_dirint signature for parameter details.\n    \"\"\"\n    I0 = get_extra_radiation(times, 1370, 'spencer')\n    cos_zenith = tools.cosd(solar_zenith)\n    # I0h as in Marion 2015 eqns 1, 3\n    I0h = I0 * np.maximum(0.065, cos_zenith)\n\n    airmass = atmosphere.get_relative_airmass(solar_zenith, model='kasten1966')\n    airmass = atmosphere.get_absolute_airmass(airmass, pressure)\n\n    # these coeffs and diff variables and the loop below\n    # implement figure 1 of Marion 2015\n\n    # make coeffs that is at least 30 elements long so that all\n    # coeffs can be assigned as specified in Marion 2015.\n    # slice below will limit iterations if necessary\n    coeffs = np.empty(max(30, max_iterations))\n    coeffs[0:3] = 1\n    coeffs[3:10] = 0.5\n    coeffs[10:20] = 0.25\n    coeffs[20:] = 0.125\n    coeffs = coeffs[:max_iterations]  # covers case where max_iterations < 30\n\n    # initialize diff\n    diff = pd.Series(9999, index=times)\n    best_diff = diff\n\n    # initialize poa_global_i\n    poa_global_i = poa_global\n\n    for iteration, coeff in enumerate(coeffs):\n\n        # test if difference between modeled GTI and\n        # measured GTI (poa_global) is less than 1 W/m^2\n        # only test for aoi less than 90 deg\n        best_diff_lte_1 = best_diff <= 1\n        best_diff_lte_1_lt_90 = best_diff_lte_1[aoi_lt_90]\n        if best_diff_lte_1_lt_90.all():\n            # all aoi < 90 points have a difference <= 1, so break loop\n            break\n\n        # calculate kt and DNI from GTI\n        kt = clearness_index(poa_global_i, aoi, I0)  # kt from Marion eqn 2\n        disc_dni = np.maximum(_disc_kn(kt, airmass)[0] * I0, 0)\n        kt_prime = clearness_index_zenith_independent(kt, airmass)\n        # dirint DNI in Marion eqn 3\n        dni = _dirint_from_dni_ktprime(disc_dni, kt_prime, solar_zenith,\n                                       use_delta_kt_prime, temp_dew)\n\n        # calculate DHI using Marion eqn 3 (identify 1st term on RHS as GHI)\n        # I0h has a minimum zenith projection, but multiplier of DNI does not\n        ghi = kt * I0h                  # Kt * I0 * max(0.065, cos(zen))\n        dhi = ghi - dni * cos_zenith    # no cos(zen) restriction here\n\n        # following SSC code\n        dni = np.maximum(dni, 0)\n        ghi = np.maximum(ghi, 0)\n        dhi = np.maximum(dhi, 0)\n\n        # use DNI and DHI to model GTI\n        # GTI-DIRINT uses perez transposition model, but we allow for\n        # any model here\n        all_irrad = get_total_irradiance(\n            surface_tilt, surface_azimuth, solar_zenith, solar_azimuth,\n            dni, ghi, dhi, dni_extra=I0, airmass=airmass,\n            albedo=albedo, model=model, model_perez=model_perez)\n\n        gti_model = all_irrad['poa_global']\n\n        # calculate new diff\n        diff = gti_model - poa_global\n\n        # determine if the new diff is smaller in magnitude\n        # than the old diff\n        diff_abs = diff.abs()\n        smallest_diff = diff_abs < best_diff\n\n        # save the best differences\n        best_diff = diff_abs.where(smallest_diff, best_diff)\n\n        # on first iteration, the best values are the only values\n        if iteration == 0:\n            best_ghi = ghi\n            best_dni = dni\n            best_dhi = dhi\n            best_kt_prime = kt_prime\n        else:\n            # save new DNI, DHI, DHI if they provide the best consistency\n            # otherwise use the older values.\n            best_ghi = ghi.where(smallest_diff, best_ghi)\n            best_dni = dni.where(smallest_diff, best_dni)\n            best_dhi = dhi.where(smallest_diff, best_dhi)\n            best_kt_prime = kt_prime.where(smallest_diff, best_kt_prime)\n\n        # calculate adjusted inputs for next iteration. Marion eqn 4\n        poa_global_i = np.maximum(1.0, poa_global_i - coeff * diff)\n    else:\n        # we are here because we ran out of coeffs to loop over and\n        # therefore we have exceeded max_iterations\n        import warnings\n        failed_points = best_diff[aoi_lt_90][~best_diff_lte_1_lt_90]\n        warnings.warn(\n            ('%s points failed to converge after %s iterations. best_diff:\\n%s'\n             % (len(failed_points), max_iterations, failed_points)),\n            RuntimeWarning)\n\n    # return the best data, whether or not the solution converged\n    return best_ghi, best_dni, best_dhi, best_kt_prime\n\n\ndef _gti_dirint_gte_90(poa_global, aoi, solar_zenith, solar_azimuth,\n                       surface_tilt, times, kt_prime,\n                       pressure=101325., temp_dew=None, albedo=.25):\n    \"\"\"\n    GTI-DIRINT model for AOI >= 90 degrees. See Marion 2015 Section 2.2.\n\n    See gti_dirint signature for parameter details.\n    \"\"\"\n    kt_prime_gte_90 = _gti_dirint_gte_90_kt_prime(aoi, solar_zenith,\n                                                  solar_azimuth, times,\n                                                  kt_prime)\n\n    I0 = get_extra_radiation(times, 1370, 'spencer')\n    airmass = atmosphere.get_relative_airmass(solar_zenith, model='kasten1966')\n    airmass = atmosphere.get_absolute_airmass(airmass, pressure)\n    kt = kt_prime_gte_90 * _kt_kt_prime_factor(airmass)\n    disc_dni = np.maximum(_disc_kn(kt, airmass)[0] * I0, 0)\n\n    dni_gte_90 = _dirint_from_dni_ktprime(disc_dni, kt_prime, solar_zenith,\n                                          False, temp_dew)\n\n    dni_gte_90_proj = dni_gte_90 * tools.cosd(solar_zenith)\n    cos_surface_tilt = tools.cosd(surface_tilt)\n\n    # isotropic sky plus ground diffuse\n    dhi_gte_90 = (\n        (2 * poa_global - dni_gte_90_proj * albedo * (1 - cos_surface_tilt)) /\n        (1 + cos_surface_tilt + albedo * (1 - cos_surface_tilt)))\n\n    ghi_gte_90 = dni_gte_90_proj + dhi_gte_90\n\n    return ghi_gte_90, dni_gte_90, dhi_gte_90\n\n\ndef _gti_dirint_gte_90_kt_prime(aoi, solar_zenith, solar_azimuth, times,\n                                kt_prime):\n    \"\"\"\n    Determine kt' values to be used in GTI-DIRINT AOI >= 90 deg case.\n    See Marion 2015 Section 2.2.\n\n    For AOI >= 90 deg: average of the kt_prime values for 65 < AOI < 80\n    in each day's morning and afternoon. Morning and afternoon are treated\n    separately.\n\n    For AOI < 90 deg: NaN.\n\n    See gti_dirint signature for parameter details.\n\n    Returns\n    -------\n    kt_prime_gte_90 : Series\n        Index is `times`.\n    \"\"\"\n    # kt_prime values from DIRINT calculation for AOI < 90 case\n    # set the kt_prime from sunrise to AOI=90 to be equal to\n    # the kt_prime for 65 < AOI < 80 during the morning.\n    # similar for the afternoon. repeat for every day.\n    aoi_gte_90 = aoi >= 90\n    aoi_65_80 = (aoi > 65) & (aoi < 80)\n    zenith_lt_90 = solar_zenith < 90\n    morning = solar_azimuth < 180\n    afternoon = solar_azimuth > 180\n    aoi_65_80_morning = aoi_65_80 & morning\n    aoi_65_80_afternoon = aoi_65_80 & afternoon\n    zenith_lt_90_aoi_gte_90_morning = zenith_lt_90 & aoi_gte_90 & morning\n    zenith_lt_90_aoi_gte_90_afternoon = zenith_lt_90 & aoi_gte_90 & afternoon\n\n    kt_prime_gte_90 = []\n    for date, data in kt_prime.groupby(times.date):\n        kt_prime_am_avg = data[aoi_65_80_morning].mean()\n        kt_prime_pm_avg = data[aoi_65_80_afternoon].mean()\n\n        kt_prime_by_date = pd.Series(np.nan, index=data.index)\n        kt_prime_by_date[zenith_lt_90_aoi_gte_90_morning] = kt_prime_am_avg\n        kt_prime_by_date[zenith_lt_90_aoi_gte_90_afternoon] = kt_prime_pm_avg\n        kt_prime_gte_90.append(kt_prime_by_date)\n    kt_prime_gte_90 = pd.concat(kt_prime_gte_90)\n\n    return kt_prime_gte_90\n\n\ndef erbs(ghi, zenith, datetime_or_doy, min_cos_zenith=0.065, max_zenith=87):\n    r\"\"\"\n    Estimate DNI and DHI from GHI using the Erbs model.\n\n    The Erbs model [1]_ estimates the diffuse fraction DF from global\n    horizontal irradiance through an empirical relationship between DF\n    and the ratio of GHI to extraterrestrial irradiance, Kt. The\n    function uses the diffuse fraction to compute DHI as\n\n    .. math::\n\n        DHI = DF \\times GHI\n\n    DNI is then estimated as\n\n    .. math::\n\n        DNI = (GHI - DHI)/\\cos(Z)\n\n    where Z is the zenith angle.\n\n    Parameters\n    ----------\n    ghi: numeric\n        Global horizontal irradiance in W/m^2.\n    zenith: numeric\n        True (not refraction-corrected) zenith angles in decimal degrees.\n    datetime_or_doy : int, float, array, pd.DatetimeIndex\n        Day of year or array of days of year e.g.\n        pd.DatetimeIndex.dayofyear, or pd.DatetimeIndex.\n    min_cos_zenith : numeric, default 0.065\n        Minimum value of cos(zenith) to allow when calculating global\n        clearness index `kt`. Equivalent to zenith = 86.273 degrees.\n    max_zenith : numeric, default 87\n        Maximum value of zenith to allow in DNI calculation. DNI will be\n        set to 0 for times with zenith values greater than `max_zenith`.\n\n    Returns\n    -------\n    data : OrderedDict or DataFrame\n        Contains the following keys/columns:\n\n            * ``dni``: the modeled direct normal irradiance in W/m^2.\n            * ``dhi``: the modeled diffuse horizontal irradiance in\n              W/m^2.\n            * ``kt``: Ratio of global to extraterrestrial irradiance\n              on a horizontal plane.\n\n    References\n    ----------\n    .. [1] D. G. Erbs, S. A. Klein and J. A. Duffie, Estimation of the\n       diffuse radiation fraction for hourly, daily and monthly-average\n       global radiation, Solar Energy 28(4), pp 293-302, 1982. Eq. 1\n\n    See also\n    --------\n    dirint\n    disc\n    \"\"\"\n\n    dni_extra = get_extra_radiation(datetime_or_doy)\n\n    kt = clearness_index(ghi, zenith, dni_extra, min_cos_zenith=min_cos_zenith,\n                         max_clearness_index=1)\n\n    # For Kt <= 0.22, set the diffuse fraction\n    df = 1 - 0.09*kt\n\n    # For Kt > 0.22 and Kt <= 0.8, set the diffuse fraction\n    df = np.where((kt > 0.22) & (kt <= 0.8),\n                  0.9511 - 0.1604*kt + 4.388*kt**2 -\n                  16.638*kt**3 + 12.336*kt**4,\n                  df)\n\n    # For Kt > 0.8, set the diffuse fraction\n    df = np.where(kt > 0.8, 0.165, df)\n\n    dhi = df * ghi\n\n    dni = (ghi - dhi) / tools.cosd(zenith)\n    bad_values = (zenith > max_zenith) | (ghi < 0) | (dni < 0)\n    dni = np.where(bad_values, 0, dni)\n    # ensure that closure relationship remains valid\n    dhi = np.where(bad_values, ghi, dhi)\n\n    data = OrderedDict()\n    data['dni'] = dni\n    data['dhi'] = dhi\n    data['kt'] = kt\n\n    if isinstance(datetime_or_doy, pd.DatetimeIndex):\n        data = pd.DataFrame(data, index=datetime_or_doy)\n\n    return data\n\n\ndef campbell_norman(zenith, transmittance, pressure=101325.0,\n                    dni_extra=1367.0):\n    '''\n    Determine DNI, DHI, GHI from extraterrestrial flux, transmittance,\n    and atmospheric pressure.\n\n    Parameters\n    ----------\n    zenith: pd.Series\n        True (not refraction-corrected) zenith angles in decimal\n        degrees. If Z is a vector it must be of the same size as all\n        other vector inputs. Z must be >=0 and <=180.\n\n    transmittance: float\n        Atmospheric transmittance between 0 and 1.\n\n    pressure: float, default 101325.0\n        Air pressure\n\n    dni_extra: float, default 1367.0\n        Direct irradiance incident at the top of the atmosphere.\n\n    Returns\n    -------\n    irradiance: DataFrame\n        Modeled direct normal irradiance, direct horizontal irradiance,\n        and global horizontal irradiance in W/m^2\n\n    References\n    ----------\n    .. [1] Campbell, G. S., J. M. Norman (1998) An Introduction to\n       Environmental Biophysics. 2nd Ed. New York: Springer.\n    '''\n\n    tau = transmittance\n\n    airmass = atmosphere.get_relative_airmass(zenith, model='simple')\n    airmass = atmosphere.get_absolute_airmass(airmass, pressure=pressure)\n    dni = dni_extra*tau**airmass\n    cos_zen = tools.cosd(zenith)\n    dhi = 0.3 * (1.0 - tau**airmass) * dni_extra * cos_zen\n    ghi = dhi + dni * cos_zen\n\n    irrads = OrderedDict()\n    irrads['ghi'] = ghi\n    irrads['dni'] = dni\n    irrads['dhi'] = dhi\n\n    if isinstance(ghi, pd.Series):\n        irrads = pd.DataFrame(irrads)\n\n    return irrads\n\n\ndef _liujordan(zenith, transmittance, airmass, dni_extra=1367.0):\n    '''\n    Determine DNI, DHI, GHI from extraterrestrial flux, transmittance,\n    and optical air mass number.\n\n    Liu and Jordan, 1960, developed a simplified direct radiation model.\n    DHI is from an empirical equation for diffuse radiation from Liu and\n    Jordan, 1960.\n\n    Parameters\n    ----------\n    zenith: pd.Series\n        True (not refraction-corrected) zenith angles in decimal\n        degrees. If Z is a vector it must be of the same size as all\n        other vector inputs. Z must be >=0 and <=180.\n\n    transmittance: float\n        Atmospheric transmittance between 0 and 1.\n\n    pressure: float, default 101325.0\n        Air pressure\n\n    dni_extra: float, default 1367.0\n        Direct irradiance incident at the top of the atmosphere.\n\n    Returns\n    -------\n    irradiance: DataFrame\n        Modeled direct normal irradiance, direct horizontal irradiance,\n        and global horizontal irradiance in W/m^2\n\n    References\n    ----------\n    .. [1] Campbell, G. S., J. M. Norman (1998) An Introduction to\n       Environmental Biophysics. 2nd Ed. New York: Springer.\n\n    .. [2] Liu, B. Y., R. C. Jordan, (1960). \"The interrelationship and\n       characteristic distribution of direct, diffuse, and total solar\n       radiation\".  Solar Energy 4:1-19\n    '''\n\n    tau = transmittance\n\n    dni = dni_extra*tau**airmass\n    dhi = 0.3 * (1.0 - tau**airmass) * dni_extra * np.cos(np.radians(zenith))\n    ghi = dhi + dni * np.cos(np.radians(zenith))\n\n    irrads = OrderedDict()\n    irrads['ghi'] = ghi\n    irrads['dni'] = dni\n    irrads['dhi'] = dhi\n\n    if isinstance(ghi, pd.Series):\n        irrads = pd.DataFrame(irrads)\n\n    return irrads\n\n\ndef _get_perez_coefficients(perezmodel):\n    '''\n    Find coefficients for the Perez model\n\n    Parameters\n    ----------\n\n    perezmodel : string (optional, default='allsitescomposite1990')\n\n          a character string which selects the desired set of Perez\n          coefficients. If model is not provided as an input, the default,\n          '1990' will be used.\n\n    All possible model selections are:\n\n          * '1990'\n          * 'allsitescomposite1990' (same as '1990')\n          * 'allsitescomposite1988'\n          * 'sandiacomposite1988'\n          * 'usacomposite1988'\n          * 'france1988'\n          * 'phoenix1988'\n          * 'elmonte1988'\n          * 'osage1988'\n          * 'albuquerque1988'\n          * 'capecanaveral1988'\n          * 'albany1988'\n\n    Returns\n    --------\n    F1coeffs, F2coeffs : (array, array)\n          F1 and F2 coefficients for the Perez model\n\n    References\n    ----------\n    .. [1] Loutzenhiser P.G. et. al. \"Empirical validation of models to\n       compute solar irradiance on inclined surfaces for building energy\n       simulation\" 2007, Solar Energy vol. 81. pp. 254-267\n\n    .. [2] Perez, R., Seals, R., Ineichen, P., Stewart, R., Menicucci, D.,\n       1987. A new simplified version of the Perez diffuse irradiance model\n       for tilted surfaces. Solar Energy 39(3), 221-232.\n\n    .. [3] Perez, R., Ineichen, P., Seals, R., Michalsky, J., Stewart, R.,\n       1990. Modeling daylight availability and irradiance components from\n       direct and global irradiance. Solar Energy 44 (5), 271-289.\n\n    .. [4] Perez, R. et. al 1988. \"The Development and Verification of the\n       Perez Diffuse Radiation Model\". SAND88-7030\n\n    '''\n    coeffdict = {\n        'allsitescomposite1990': [\n            [-0.0080,    0.5880,   -0.0620,   -0.0600,    0.0720,   -0.0220],\n            [0.1300,    0.6830,   -0.1510,   -0.0190,    0.0660,   -0.0290],\n            [0.3300,    0.4870,   -0.2210,    0.0550,   -0.0640,   -0.0260],\n            [0.5680,    0.1870,   -0.2950,    0.1090,   -0.1520,   -0.0140],\n            [0.8730,   -0.3920,   -0.3620,    0.2260,   -0.4620,    0.0010],\n            [1.1320,   -1.2370,   -0.4120,    0.2880,   -0.8230,    0.0560],\n            [1.0600,   -1.6000,   -0.3590,    0.2640,   -1.1270,    0.1310],\n            [0.6780,   -0.3270,   -0.2500,    0.1560,   -1.3770,    0.2510]],\n        'allsitescomposite1988': [\n            [-0.0180,    0.7050,   -0.071,   -0.0580,    0.1020,   -0.0260],\n            [0.1910,    0.6450,   -0.1710,    0.0120,    0.0090,   -0.0270],\n            [0.4400,    0.3780,   -0.2560,    0.0870,   -0.1040,   -0.0250],\n            [0.7560,   -0.1210,   -0.3460,    0.1790,   -0.3210,   -0.0080],\n            [0.9960,   -0.6450,   -0.4050,    0.2600,   -0.5900,    0.0170],\n            [1.0980,   -1.2900,   -0.3930,    0.2690,   -0.8320,    0.0750],\n            [0.9730,   -1.1350,   -0.3780,    0.1240,   -0.2580,    0.1490],\n            [0.6890,   -0.4120,   -0.2730,    0.1990,   -1.6750,    0.2370]],\n        'sandiacomposite1988': [\n            [-0.1960,    1.0840,   -0.0060,   -0.1140,    0.1800,   -0.0190],\n            [0.2360,    0.5190,   -0.1800,   -0.0110,    0.0200,   -0.0380],\n            [0.4540,    0.3210,   -0.2550,    0.0720,   -0.0980,   -0.0460],\n            [0.8660,   -0.3810,   -0.3750,    0.2030,   -0.4030,   -0.0490],\n            [1.0260,   -0.7110,   -0.4260,    0.2730,   -0.6020,   -0.0610],\n            [0.9780,   -0.9860,   -0.3500,    0.2800,   -0.9150,   -0.0240],\n            [0.7480,   -0.9130,   -0.2360,    0.1730,   -1.0450,    0.0650],\n            [0.3180,   -0.7570,    0.1030,    0.0620,   -1.6980,    0.2360]],\n        'usacomposite1988': [\n            [-0.0340,    0.6710,   -0.0590,   -0.0590,    0.0860,   -0.0280],\n            [0.2550,    0.4740,   -0.1910,    0.0180,   -0.0140,   -0.0330],\n            [0.4270,    0.3490,   -0.2450,    0.0930,   -0.1210,   -0.0390],\n            [0.7560,   -0.2130,   -0.3280,    0.1750,   -0.3040,   -0.0270],\n            [1.0200,   -0.8570,   -0.3850,    0.2800,   -0.6380,   -0.0190],\n            [1.0500,   -1.3440,   -0.3480,    0.2800,   -0.8930,    0.0370],\n            [0.9740,   -1.5070,   -0.3700,    0.1540,   -0.5680,    0.1090],\n            [0.7440,   -1.8170,   -0.2560,    0.2460,   -2.6180,    0.2300]],\n        'france1988': [\n            [0.0130,    0.7640,   -0.1000,   -0.0580,    0.1270,   -0.0230],\n            [0.0950,    0.9200,   -0.1520,         0,    0.0510,   -0.0200],\n            [0.4640,    0.4210,   -0.2800,    0.0640,   -0.0510,   -0.0020],\n            [0.7590,   -0.0090,   -0.3730,    0.2010,   -0.3820,    0.0100],\n            [0.9760,   -0.4000,   -0.4360,    0.2710,   -0.6380,    0.0510],\n            [1.1760,   -1.2540,   -0.4620,    0.2950,   -0.9750,    0.1290],\n            [1.1060,   -1.5630,   -0.3980,    0.3010,   -1.4420,    0.2120],\n            [0.9340,   -1.5010,   -0.2710,    0.4200,   -2.9170,    0.2490]],\n        'phoenix1988': [\n            [-0.0030,    0.7280,   -0.0970,   -0.0750,    0.1420,   -0.0430],\n            [0.2790,    0.3540,   -0.1760,    0.0300,   -0.0550,   -0.0540],\n            [0.4690,    0.1680,   -0.2460,    0.0480,   -0.0420,   -0.0570],\n            [0.8560,   -0.5190,   -0.3400,    0.1760,   -0.3800,   -0.0310],\n            [0.9410,   -0.6250,   -0.3910,    0.1880,   -0.3600,   -0.0490],\n            [1.0560,   -1.1340,   -0.4100,    0.2810,   -0.7940,   -0.0650],\n            [0.9010,   -2.1390,   -0.2690,    0.1180,   -0.6650,    0.0460],\n            [0.1070,    0.4810,    0.1430,   -0.1110,   -0.1370,    0.2340]],\n        'elmonte1988': [\n            [0.0270,    0.7010,   -0.1190,   -0.0580,    0.1070,  -0.0600],\n            [0.1810,    0.6710,   -0.1780,   -0.0790,    0.1940,  -0.0350],\n            [0.4760,    0.4070,   -0.2880,    0.0540,   -0.0320,  -0.0550],\n            [0.8750,   -0.2180,   -0.4030,    0.1870,   -0.3090,  -0.0610],\n            [1.1660,   -1.0140,   -0.4540,    0.2110,   -0.4100,  -0.0440],\n            [1.1430,   -2.0640,   -0.2910,    0.0970,   -0.3190,   0.0530],\n            [1.0940,   -2.6320,   -0.2590,    0.0290,   -0.4220,   0.1470],\n            [0.1550,    1.7230,    0.1630,   -0.1310,   -0.0190,   0.2770]],\n        'osage1988': [\n            [-0.3530,    1.4740,   0.0570,   -0.1750,    0.3120,   0.0090],\n            [0.3630,    0.2180,  -0.2120,    0.0190,   -0.0340,  -0.0590],\n            [-0.0310,    1.2620,  -0.0840,   -0.0820,    0.2310,  -0.0170],\n            [0.6910,    0.0390,  -0.2950,    0.0910,   -0.1310,  -0.0350],\n            [1.1820,   -1.3500,  -0.3210,    0.4080,   -0.9850,  -0.0880],\n            [0.7640,    0.0190,  -0.2030,    0.2170,   -0.2940,  -0.1030],\n            [0.2190,    1.4120,   0.2440,    0.4710,   -2.9880,   0.0340],\n            [3.5780,   22.2310, -10.7450,    2.4260,    4.8920,  -5.6870]],\n        'albuquerque1988': [\n            [0.0340,    0.5010,  -0.0940,   -0.0630,    0.1060,  -0.0440],\n            [0.2290,    0.4670,  -0.1560,   -0.0050,   -0.0190,  -0.0230],\n            [0.4860,    0.2410,  -0.2530,    0.0530,   -0.0640,  -0.0220],\n            [0.8740,   -0.3930,  -0.3970,    0.1810,   -0.3270,  -0.0370],\n            [1.1930,   -1.2960,  -0.5010,    0.2810,   -0.6560,  -0.0450],\n            [1.0560,   -1.7580,  -0.3740,    0.2260,   -0.7590,   0.0340],\n            [0.9010,   -4.7830,  -0.1090,    0.0630,   -0.9700,   0.1960],\n            [0.8510,   -7.0550,  -0.0530,    0.0600,   -2.8330,   0.3300]],\n        'capecanaveral1988': [\n            [0.0750,    0.5330,   -0.1240,  -0.0670,   0.0420,  -0.0200],\n            [0.2950,    0.4970,   -0.2180,  -0.0080,   0.0030,  -0.0290],\n            [0.5140,    0.0810,   -0.2610,   0.0750,  -0.1600,  -0.0290],\n            [0.7470,   -0.3290,   -0.3250,   0.1810,  -0.4160,  -0.0300],\n            [0.9010,   -0.8830,   -0.2970,   0.1780,  -0.4890,   0.0080],\n            [0.5910,   -0.0440,   -0.1160,   0.2350,  -0.9990,   0.0980],\n            [0.5370,   -2.4020,    0.3200,   0.1690,  -1.9710,   0.3100],\n            [-0.8050,    4.5460,    1.0720,  -0.2580,  -0.9500,    0.7530]],\n        'albany1988': [\n            [0.0120,    0.5540,   -0.0760, -0.0520,   0.0840,  -0.0290],\n            [0.2670,    0.4370,   -0.1940,  0.0160,   0.0220,  -0.0360],\n            [0.4200,    0.3360,   -0.2370,  0.0740,  -0.0520,  -0.0320],\n            [0.6380,   -0.0010,   -0.2810,  0.1380,  -0.1890,  -0.0120],\n            [1.0190,   -1.0270,   -0.3420,  0.2710,  -0.6280,   0.0140],\n            [1.1490,   -1.9400,   -0.3310,  0.3220,  -1.0970,   0.0800],\n            [1.4340,   -3.9940,   -0.4920,  0.4530,  -2.3760,   0.1170],\n            [1.0070,   -2.2920,   -0.4820,  0.3900,  -3.3680,   0.2290]], }\n\n    array = np.array(coeffdict[perezmodel])\n\n    F1coeffs = array[:, 0:3]\n    F2coeffs = array[:, 3:7]\n\n    return F1coeffs, F2coeffs\n\n\ndef _get_dirint_coeffs():\n    \"\"\"\n    A place to stash the dirint coefficients.\n\n    Returns\n    -------\n    np.array with shape ``(6, 6, 7, 5)``.\n    Ordering is ``[kt_prime_bin, zenith_bin, delta_kt_prime_bin, w_bin]``\n    \"\"\"\n\n    # To allow for maximum copy/paste from the MATLAB 1-indexed code,\n    # we create and assign values to an oversized array.\n    # Then, we return the [1:, 1:, :, :] slice.\n\n    coeffs = np.zeros((7, 7, 7, 5))\n\n    coeffs[1, 1, :, :] = [\n        [0.385230, 0.385230, 0.385230, 0.462880, 0.317440],\n        [0.338390, 0.338390, 0.221270, 0.316730, 0.503650],\n        [0.235680, 0.235680, 0.241280, 0.157830, 0.269440],\n        [0.830130, 0.830130, 0.171970, 0.841070, 0.457370],\n        [0.548010, 0.548010, 0.478000, 0.966880, 1.036370],\n        [0.548010, 0.548010, 1.000000, 3.012370, 1.976540],\n        [0.582690, 0.582690, 0.229720, 0.892710, 0.569950]]\n\n    coeffs[1, 2, :, :] = [\n        [0.131280, 0.131280, 0.385460, 0.511070, 0.127940],\n        [0.223710, 0.223710, 0.193560, 0.304560, 0.193940],\n        [0.229970, 0.229970, 0.275020, 0.312730, 0.244610],\n        [0.090100, 0.184580, 0.260500, 0.687480, 0.579440],\n        [0.131530, 0.131530, 0.370190, 1.380350, 1.052270],\n        [1.116250, 1.116250, 0.928030, 3.525490, 2.316920],\n        [0.090100, 0.237000, 0.300040, 0.812470, 0.664970]]\n\n    coeffs[1, 3, :, :] = [\n        [0.587510, 0.130000, 0.400000, 0.537210, 0.832490],\n        [0.306210, 0.129830, 0.204460, 0.500000, 0.681640],\n        [0.224020, 0.260620, 0.334080, 0.501040, 0.350470],\n        [0.421540, 0.753970, 0.750660, 3.706840, 0.983790],\n        [0.706680, 0.373530, 1.245670, 0.864860, 1.992630],\n        [4.864400, 0.117390, 0.265180, 0.359180, 3.310820],\n        [0.392080, 0.493290, 0.651560, 1.932780, 0.898730]]\n\n    coeffs[1, 4, :, :] = [\n        [0.126970, 0.126970, 0.126970, 0.126970, 0.126970],\n        [0.810820, 0.810820, 0.810820, 0.810820, 0.810820],\n        [3.241680, 2.500000, 2.291440, 2.291440, 2.291440],\n        [4.000000, 3.000000, 2.000000, 0.975430, 1.965570],\n        [12.494170, 12.494170, 8.000000, 5.083520, 8.792390],\n        [21.744240, 21.744240, 21.744240, 21.744240, 21.744240],\n        [3.241680, 12.494170, 1.620760, 1.375250, 2.331620]]\n\n    coeffs[1, 5, :, :] = [\n        [0.126970, 0.126970, 0.126970, 0.126970, 0.126970],\n        [0.810820, 0.810820, 0.810820, 0.810820, 0.810820],\n        [3.241680, 2.500000, 2.291440, 2.291440, 2.291440],\n        [4.000000, 3.000000, 2.000000, 0.975430, 1.965570],\n        [12.494170, 12.494170, 8.000000, 5.083520, 8.792390],\n        [21.744240, 21.744240, 21.744240, 21.744240, 21.744240],\n        [3.241680, 12.494170, 1.620760, 1.375250, 2.331620]]\n\n    coeffs[1, 6, :, :] = [\n        [0.126970, 0.126970, 0.126970, 0.126970, 0.126970],\n        [0.810820, 0.810820, 0.810820, 0.810820, 0.810820],\n        [3.241680, 2.500000, 2.291440, 2.291440, 2.291440],\n        [4.000000, 3.000000, 2.000000, 0.975430, 1.965570],\n        [12.494170, 12.494170, 8.000000, 5.083520, 8.792390],\n        [21.744240, 21.744240, 21.744240, 21.744240, 21.744240],\n        [3.241680, 12.494170, 1.620760, 1.375250, 2.331620]]\n\n    coeffs[2, 1, :, :] = [\n        [0.337440, 0.337440, 0.969110, 1.097190, 1.116080],\n        [0.337440, 0.337440, 0.969110, 1.116030, 0.623900],\n        [0.337440, 0.337440, 1.530590, 1.024420, 0.908480],\n        [0.584040, 0.584040, 0.847250, 0.914940, 1.289300],\n        [0.337440, 0.337440, 0.310240, 1.435020, 1.852830],\n        [0.337440, 0.337440, 1.015010, 1.097190, 2.117230],\n        [0.337440, 0.337440, 0.969110, 1.145730, 1.476400]]\n\n    coeffs[2, 2, :, :] = [\n        [0.300000, 0.300000, 0.700000, 1.100000, 0.796940],\n        [0.219870, 0.219870, 0.526530, 0.809610, 0.649300],\n        [0.386650, 0.386650, 0.119320, 0.576120, 0.685460],\n        [0.746730, 0.399830, 0.470970, 0.986530, 0.785370],\n        [0.575420, 0.936700, 1.649200, 1.495840, 1.335590],\n        [1.319670, 4.002570, 1.276390, 2.644550, 2.518670],\n        [0.665190, 0.678910, 1.012360, 1.199940, 0.986580]]\n\n    coeffs[2, 3, :, :] = [\n        [0.378870, 0.974060, 0.500000, 0.491880, 0.665290],\n        [0.105210, 0.263470, 0.407040, 0.553460, 0.582590],\n        [0.312900, 0.345240, 1.144180, 0.854790, 0.612280],\n        [0.119070, 0.365120, 0.560520, 0.793720, 0.802600],\n        [0.781610, 0.837390, 1.270420, 1.537980, 1.292950],\n        [1.152290, 1.152290, 1.492080, 1.245370, 2.177100],\n        [0.424660, 0.529550, 0.966910, 1.033460, 0.958730]]\n\n    coeffs[2, 4, :, :] = [\n        [0.310590, 0.714410, 0.252450, 0.500000, 0.607600],\n        [0.975190, 0.363420, 0.500000, 0.400000, 0.502800],\n        [0.175580, 0.196250, 0.476360, 1.072470, 0.490510],\n        [0.719280, 0.698620, 0.657770, 1.190840, 0.681110],\n        [0.426240, 1.464840, 0.678550, 1.157730, 0.978430],\n        [2.501120, 1.789130, 1.387090, 2.394180, 2.394180],\n        [0.491640, 0.677610, 0.685610, 1.082400, 0.735410]]\n\n    coeffs[2, 5, :, :] = [\n        [0.597000, 0.500000, 0.300000, 0.310050, 0.413510],\n        [0.314790, 0.336310, 0.400000, 0.400000, 0.442460],\n        [0.166510, 0.460440, 0.552570, 1.000000, 0.461610],\n        [0.401020, 0.559110, 0.403630, 1.016710, 0.671490],\n        [0.400360, 0.750830, 0.842640, 1.802600, 1.023830],\n        [3.315300, 1.510380, 2.443650, 1.638820, 2.133990],\n        [0.530790, 0.745850, 0.693050, 1.458040, 0.804500]]\n\n    coeffs[2, 6, :, :] = [\n        [0.597000, 0.500000, 0.300000, 0.310050, 0.800920],\n        [0.314790, 0.336310, 0.400000, 0.400000, 0.237040],\n        [0.166510, 0.460440, 0.552570, 1.000000, 0.581990],\n        [0.401020, 0.559110, 0.403630, 1.016710, 0.898570],\n        [0.400360, 0.750830, 0.842640, 1.802600, 3.400390],\n        [3.315300, 1.510380, 2.443650, 1.638820, 2.508780],\n        [0.204340, 1.157740, 2.003080, 2.622080, 1.409380]]\n\n    coeffs[3, 1, :, :] = [\n        [1.242210, 1.242210, 1.242210, 1.242210, 1.242210],\n        [0.056980, 0.056980, 0.656990, 0.656990, 0.925160],\n        [0.089090, 0.089090, 1.040430, 1.232480, 1.205300],\n        [1.053850, 1.053850, 1.399690, 1.084640, 1.233340],\n        [1.151540, 1.151540, 1.118290, 1.531640, 1.411840],\n        [1.494980, 1.494980, 1.700000, 1.800810, 1.671600],\n        [1.018450, 1.018450, 1.153600, 1.321890, 1.294670]]\n\n    coeffs[3, 2, :, :] = [\n        [0.700000, 0.700000, 1.023460, 0.700000, 0.945830],\n        [0.886300, 0.886300, 1.333620, 0.800000, 1.066620],\n        [0.902180, 0.902180, 0.954330, 1.126690, 1.097310],\n        [1.095300, 1.075060, 1.176490, 1.139470, 1.096110],\n        [1.201660, 1.201660, 1.438200, 1.256280, 1.198060],\n        [1.525850, 1.525850, 1.869160, 1.985410, 1.911590],\n        [1.288220, 1.082810, 1.286370, 1.166170, 1.119330]]\n\n    coeffs[3, 3, :, :] = [\n        [0.600000, 1.029910, 0.859890, 0.550000, 0.813600],\n        [0.604450, 1.029910, 0.859890, 0.656700, 0.928840],\n        [0.455850, 0.750580, 0.804930, 0.823000, 0.911000],\n        [0.526580, 0.932310, 0.908620, 0.983520, 0.988090],\n        [1.036110, 1.100690, 0.848380, 1.035270, 1.042380],\n        [1.048440, 1.652720, 0.900000, 2.350410, 1.082950],\n        [0.817410, 0.976160, 0.861300, 0.974780, 1.004580]]\n\n    coeffs[3, 4, :, :] = [\n        [0.782110, 0.564280, 0.600000, 0.600000, 0.665740],\n        [0.894480, 0.680730, 0.541990, 0.800000, 0.669140],\n        [0.487460, 0.818950, 0.841830, 0.872540, 0.709040],\n        [0.709310, 0.872780, 0.908480, 0.953290, 0.844350],\n        [0.863920, 0.947770, 0.876220, 1.078750, 0.936910],\n        [1.280350, 0.866720, 0.769790, 1.078750, 0.975130],\n        [0.725420, 0.869970, 0.868810, 0.951190, 0.829220]]\n\n    coeffs[3, 5, :, :] = [\n        [0.791750, 0.654040, 0.483170, 0.409000, 0.597180],\n        [0.566140, 0.948990, 0.971820, 0.653570, 0.718550],\n        [0.648710, 0.637730, 0.870510, 0.860600, 0.694300],\n        [0.637630, 0.767610, 0.925670, 0.990310, 0.847670],\n        [0.736380, 0.946060, 1.117590, 1.029340, 0.947020],\n        [1.180970, 0.850000, 1.050000, 0.950000, 0.888580],\n        [0.700560, 0.801440, 0.961970, 0.906140, 0.823880]]\n\n    coeffs[3, 6, :, :] = [\n        [0.500000, 0.500000, 0.586770, 0.470550, 0.629790],\n        [0.500000, 0.500000, 1.056220, 1.260140, 0.658140],\n        [0.500000, 0.500000, 0.631830, 0.842620, 0.582780],\n        [0.554710, 0.734730, 0.985820, 0.915640, 0.898260],\n        [0.712510, 1.205990, 0.909510, 1.078260, 0.885610],\n        [1.899260, 1.559710, 1.000000, 1.150000, 1.120390],\n        [0.653880, 0.793120, 0.903320, 0.944070, 0.796130]]\n\n    coeffs[4, 1, :, :] = [\n        [1.000000, 1.000000, 1.050000, 1.170380, 1.178090],\n        [0.960580, 0.960580, 1.059530, 1.179030, 1.131690],\n        [0.871470, 0.871470, 0.995860, 1.141910, 1.114600],\n        [1.201590, 1.201590, 0.993610, 1.109380, 1.126320],\n        [1.065010, 1.065010, 0.828660, 0.939970, 1.017930],\n        [1.065010, 1.065010, 0.623690, 1.119620, 1.132260],\n        [1.071570, 1.071570, 0.958070, 1.114130, 1.127110]]\n\n    coeffs[4, 2, :, :] = [\n        [0.950000, 0.973390, 0.852520, 1.092200, 1.096590],\n        [0.804120, 0.913870, 0.980990, 1.094580, 1.042420],\n        [0.737540, 0.935970, 0.999940, 1.056490, 1.050060],\n        [1.032980, 1.034540, 0.968460, 1.032080, 1.015780],\n        [0.900000, 0.977210, 0.945960, 1.008840, 0.969960],\n        [0.600000, 0.750000, 0.750000, 0.844710, 0.899100],\n        [0.926800, 0.965030, 0.968520, 1.044910, 1.032310]]\n\n    coeffs[4, 3, :, :] = [\n        [0.850000, 1.029710, 0.961100, 1.055670, 1.009700],\n        [0.818530, 0.960010, 0.996450, 1.081970, 1.036470],\n        [0.765380, 0.953500, 0.948260, 1.052110, 1.000140],\n        [0.775610, 0.909610, 0.927800, 0.987800, 0.952100],\n        [1.000990, 0.881880, 0.875950, 0.949100, 0.893690],\n        [0.902370, 0.875960, 0.807990, 0.942410, 0.917920],\n        [0.856580, 0.928270, 0.946820, 1.032260, 0.972990]]\n\n    coeffs[4, 4, :, :] = [\n        [0.750000, 0.857930, 0.983800, 1.056540, 0.980240],\n        [0.750000, 0.987010, 1.013730, 1.133780, 1.038250],\n        [0.800000, 0.947380, 1.012380, 1.091270, 0.999840],\n        [0.800000, 0.914550, 0.908570, 0.999190, 0.915230],\n        [0.778540, 0.800590, 0.799070, 0.902180, 0.851560],\n        [0.680190, 0.317410, 0.507680, 0.388910, 0.646710],\n        [0.794920, 0.912780, 0.960830, 1.057110, 0.947950]]\n\n    coeffs[4, 5, :, :] = [\n        [0.750000, 0.833890, 0.867530, 1.059890, 0.932840],\n        [0.979700, 0.971470, 0.995510, 1.068490, 1.030150],\n        [0.858850, 0.987920, 1.043220, 1.108700, 1.044900],\n        [0.802400, 0.955110, 0.911660, 1.045070, 0.944470],\n        [0.884890, 0.766210, 0.885390, 0.859070, 0.818190],\n        [0.615680, 0.700000, 0.850000, 0.624620, 0.669300],\n        [0.835570, 0.946150, 0.977090, 1.049350, 0.979970]]\n\n    coeffs[4, 6, :, :] = [\n        [0.689220, 0.809600, 0.900000, 0.789500, 0.853990],\n        [0.854660, 0.852840, 0.938200, 0.923110, 0.955010],\n        [0.938600, 0.932980, 1.010390, 1.043950, 1.041640],\n        [0.843620, 0.981300, 0.951590, 0.946100, 0.966330],\n        [0.694740, 0.814690, 0.572650, 0.400000, 0.726830],\n        [0.211370, 0.671780, 0.416340, 0.297290, 0.498050],\n        [0.843540, 0.882330, 0.911760, 0.898420, 0.960210]]\n\n    coeffs[5, 1, :, :] = [\n        [1.054880, 1.075210, 1.068460, 1.153370, 1.069220],\n        [1.000000, 1.062220, 1.013470, 1.088170, 1.046200],\n        [0.885090, 0.993530, 0.942590, 1.054990, 1.012740],\n        [0.920000, 0.950000, 0.978720, 1.020280, 0.984440],\n        [0.850000, 0.908500, 0.839940, 0.985570, 0.962180],\n        [0.800000, 0.800000, 0.810080, 0.950000, 0.961550],\n        [1.038590, 1.063200, 1.034440, 1.112780, 1.037800]]\n\n    coeffs[5, 2, :, :] = [\n        [1.017610, 1.028360, 1.058960, 1.133180, 1.045620],\n        [0.920000, 0.998970, 1.033590, 1.089030, 1.022060],\n        [0.912370, 0.949930, 0.979770, 1.020420, 0.981770],\n        [0.847160, 0.935300, 0.930540, 0.955050, 0.946560],\n        [0.880260, 0.867110, 0.874130, 0.972650, 0.883420],\n        [0.627150, 0.627150, 0.700000, 0.774070, 0.845130],\n        [0.973700, 1.006240, 1.026190, 1.071960, 1.017240]]\n\n    coeffs[5, 3, :, :] = [\n        [1.028710, 1.017570, 1.025900, 1.081790, 1.024240],\n        [0.924980, 0.985500, 1.014100, 1.092210, 0.999610],\n        [0.828570, 0.934920, 0.994950, 1.024590, 0.949710],\n        [0.900810, 0.901330, 0.928830, 0.979570, 0.913100],\n        [0.761030, 0.845150, 0.805360, 0.936790, 0.853460],\n        [0.626400, 0.546750, 0.730500, 0.850000, 0.689050],\n        [0.957630, 0.985480, 0.991790, 1.050220, 0.987900]]\n\n    coeffs[5, 4, :, :] = [\n        [0.992730, 0.993880, 1.017150, 1.059120, 1.017450],\n        [0.975610, 0.987160, 1.026820, 1.075440, 1.007250],\n        [0.871090, 0.933190, 0.974690, 0.979840, 0.952730],\n        [0.828750, 0.868090, 0.834920, 0.905510, 0.871530],\n        [0.781540, 0.782470, 0.767910, 0.764140, 0.795890],\n        [0.743460, 0.693390, 0.514870, 0.630150, 0.715660],\n        [0.934760, 0.957870, 0.959640, 0.972510, 0.981640]]\n\n    coeffs[5, 5, :, :] = [\n        [0.965840, 0.941240, 0.987100, 1.022540, 1.011160],\n        [0.988630, 0.994770, 0.976590, 0.950000, 1.034840],\n        [0.958200, 1.018080, 0.974480, 0.920000, 0.989870],\n        [0.811720, 0.869090, 0.812020, 0.850000, 0.821050],\n        [0.682030, 0.679480, 0.632450, 0.746580, 0.738550],\n        [0.668290, 0.445860, 0.500000, 0.678920, 0.696510],\n        [0.926940, 0.953350, 0.959050, 0.876210, 0.991490]]\n\n    coeffs[5, 6, :, :] = [\n        [0.948940, 0.997760, 0.850000, 0.826520, 0.998470],\n        [1.017860, 0.970000, 0.850000, 0.700000, 0.988560],\n        [1.000000, 0.950000, 0.850000, 0.606240, 0.947260],\n        [1.000000, 0.746140, 0.751740, 0.598390, 0.725230],\n        [0.922210, 0.500000, 0.376800, 0.517110, 0.548630],\n        [0.500000, 0.450000, 0.429970, 0.404490, 0.539940],\n        [0.960430, 0.881630, 0.775640, 0.596350, 0.937680]]\n\n    coeffs[6, 1, :, :] = [\n        [1.030000, 1.040000, 1.000000, 1.000000, 1.049510],\n        [1.050000, 0.990000, 0.990000, 0.950000, 0.996530],\n        [1.050000, 0.990000, 0.990000, 0.820000, 0.971940],\n        [1.050000, 0.790000, 0.880000, 0.820000, 0.951840],\n        [1.000000, 0.530000, 0.440000, 0.710000, 0.928730],\n        [0.540000, 0.470000, 0.500000, 0.550000, 0.773950],\n        [1.038270, 0.920180, 0.910930, 0.821140, 1.034560]]\n\n    coeffs[6, 2, :, :] = [\n        [1.041020, 0.997520, 0.961600, 1.000000, 1.035780],\n        [0.948030, 0.980000, 0.900000, 0.950360, 0.977460],\n        [0.950000, 0.977250, 0.869270, 0.800000, 0.951680],\n        [0.951870, 0.850000, 0.748770, 0.700000, 0.883850],\n        [0.900000, 0.823190, 0.727450, 0.600000, 0.839870],\n        [0.850000, 0.805020, 0.692310, 0.500000, 0.788410],\n        [1.010090, 0.895270, 0.773030, 0.816280, 1.011680]]\n\n    coeffs[6, 3, :, :] = [\n        [1.022450, 1.004600, 0.983650, 1.000000, 1.032940],\n        [0.943960, 0.999240, 0.983920, 0.905990, 0.978150],\n        [0.936240, 0.946480, 0.850000, 0.850000, 0.930320],\n        [0.816420, 0.885000, 0.644950, 0.817650, 0.865310],\n        [0.742960, 0.765690, 0.561520, 0.700000, 0.827140],\n        [0.643870, 0.596710, 0.474460, 0.600000, 0.651200],\n        [0.971740, 0.940560, 0.714880, 0.864380, 1.001650]]\n\n    coeffs[6, 4, :, :] = [\n        [0.995260, 0.977010, 1.000000, 1.000000, 1.035250],\n        [0.939810, 0.975250, 0.939980, 0.950000, 0.982550],\n        [0.876870, 0.879440, 0.850000, 0.900000, 0.917810],\n        [0.873480, 0.873450, 0.751470, 0.850000, 0.863040],\n        [0.761470, 0.702360, 0.638770, 0.750000, 0.783120],\n        [0.734080, 0.650000, 0.600000, 0.650000, 0.715660],\n        [0.942160, 0.919100, 0.770340, 0.731170, 0.995180]]\n\n    coeffs[6, 5, :, :] = [\n        [0.952560, 0.916780, 0.920000, 0.900000, 1.005880],\n        [0.928620, 0.994420, 0.900000, 0.900000, 0.983720],\n        [0.913070, 0.850000, 0.850000, 0.800000, 0.924280],\n        [0.868090, 0.807170, 0.823550, 0.600000, 0.844520],\n        [0.769570, 0.719870, 0.650000, 0.550000, 0.733500],\n        [0.580250, 0.650000, 0.600000, 0.500000, 0.628850],\n        [0.904770, 0.852650, 0.708370, 0.493730, 0.949030]]\n\n    coeffs[6, 6, :, :] = [\n        [0.911970, 0.800000, 0.800000, 0.800000, 0.956320],\n        [0.912620, 0.682610, 0.750000, 0.700000, 0.950110],\n        [0.653450, 0.659330, 0.700000, 0.600000, 0.856110],\n        [0.648440, 0.600000, 0.641120, 0.500000, 0.695780],\n        [0.570000, 0.550000, 0.598800, 0.400000, 0.560150],\n        [0.475230, 0.500000, 0.518640, 0.339970, 0.520230],\n        [0.743440, 0.592190, 0.603060, 0.316930, 0.794390]]\n\n    return coeffs[1:, 1:, :, :]\n\n\ndef dni(ghi, dhi, zenith, clearsky_dni=None, clearsky_tolerance=1.1,\n        zenith_threshold_for_zero_dni=88.0,\n        zenith_threshold_for_clearsky_limit=80.0):\n    \"\"\"\n    Determine DNI from GHI and DHI.\n\n    When calculating the DNI from GHI and DHI the calculated DNI may be\n    unreasonably high or negative for zenith angles close to 90 degrees\n    (sunrise/sunset transitions). This function identifies unreasonable DNI\n    values and sets them to NaN. If the clearsky DNI is given unreasonably high\n    values are cut off.\n\n    Parameters\n    ----------\n    ghi : Series\n        Global horizontal irradiance.\n\n    dhi : Series\n        Diffuse horizontal irradiance.\n\n    zenith : Series\n        True (not refraction-corrected) zenith angles in decimal\n        degrees. Angles must be >=0 and <=180.\n\n    clearsky_dni : None or Series, default None\n        Clearsky direct normal irradiance.\n\n    clearsky_tolerance : float, default 1.1\n        If 'clearsky_dni' is given this parameter can be used to allow a\n        tolerance by how much the calculated DNI value can be greater than\n        the clearsky value before it is identified as an unreasonable value.\n\n    zenith_threshold_for_zero_dni : float, default 88.0\n        Non-zero DNI values for zenith angles greater than or equal to\n        'zenith_threshold_for_zero_dni' will be set to NaN.\n\n    zenith_threshold_for_clearsky_limit : float, default 80.0\n        DNI values for zenith angles greater than or equal to\n        'zenith_threshold_for_clearsky_limit' and smaller the\n        'zenith_threshold_for_zero_dni' that are greater than the clearsky DNI\n        (times allowed tolerance) will be corrected. Only applies if\n        'clearsky_dni' is not None.\n\n    Returns\n    -------\n    dni : Series\n        The modeled direct normal irradiance.\n    \"\"\"\n\n    # calculate DNI\n    dni = (ghi - dhi) / tools.cosd(zenith)\n\n    # cutoff negative values\n    dni[dni < 0] = float('nan')\n\n    # set non-zero DNI values for zenith angles >=\n    # zenith_threshold_for_zero_dni to NaN\n    dni[(zenith >= zenith_threshold_for_zero_dni) & (dni != 0)] = float('nan')\n\n    # correct DNI values for zenith angles greater or equal to the\n    # zenith_threshold_for_clearsky_limit and smaller than the\n    # upper_cutoff_zenith that are greater than the clearsky DNI (times\n    # clearsky_tolerance)\n    if clearsky_dni is not None:\n        max_dni = clearsky_dni * clearsky_tolerance\n        dni[(zenith >= zenith_threshold_for_clearsky_limit) &\n            (zenith < zenith_threshold_for_zero_dni) &\n            (dni > max_dni)] = max_dni\n    return dni\n","new_file_content":"\"\"\"\nThe ``irradiance`` module contains functions for modeling global\nhorizontal irradiance, direct normal irradiance, diffuse horizontal\nirradiance, and total irradiance under various conditions.\n\"\"\"\n\nimport datetime\nfrom collections import OrderedDict\nfrom functools import partial\n\nimport numpy as np\nimport pandas as pd\n\nfrom pvlib import atmosphere, solarposition, tools\n\n\n# see References section of grounddiffuse function\nSURFACE_ALBEDOS = {'urban': 0.18,\n                   'grass': 0.20,\n                   'fresh grass': 0.26,\n                   'soil': 0.17,\n                   'sand': 0.40,\n                   'snow': 0.65,\n                   'fresh snow': 0.75,\n                   'asphalt': 0.12,\n                   'concrete': 0.30,\n                   'aluminum': 0.85,\n                   'copper': 0.74,\n                   'fresh steel': 0.35,\n                   'dirty steel': 0.08,\n                   'sea': 0.06}\n\n\ndef get_extra_radiation(datetime_or_doy, solar_constant=1366.1,\n                        method='spencer', epoch_year=2014, **kwargs):\n    \"\"\"\n    Determine extraterrestrial radiation from day of year.\n\n    Parameters\n    ----------\n    datetime_or_doy : numeric, array, date, datetime, Timestamp, DatetimeIndex\n        Day of year, array of days of year, or datetime-like object\n\n    solar_constant : float, default 1366.1\n        The solar constant.\n\n    method : string, default 'spencer'\n        The method by which the ET radiation should be calculated.\n        Options include ``'pyephem', 'spencer', 'asce', 'nrel'``.\n\n    epoch_year : int, default 2014\n        The year in which a day of year input will be calculated. Only\n        applies to day of year input used with the pyephem or nrel\n        methods.\n\n    kwargs :\n        Passed to solarposition.nrel_earthsun_distance\n\n    Returns\n    -------\n    dni_extra : float, array, or Series\n        The extraterrestrial radiation present in watts per square meter\n        on a surface which is normal to the sun. Pandas Timestamp and\n        DatetimeIndex inputs will yield a Pandas TimeSeries. All other\n        inputs will yield a float or an array of floats.\n\n    References\n    ----------\n    .. [1] M. Reno, C. Hansen, and J. Stein, \"Global Horizontal Irradiance\n       Clear Sky Models: Implementation and Analysis\", Sandia National\n       Laboratories, SAND2012-2389, 2012.\n\n    .. [2] <http://solardat.uoregon.edu/SolarRadiationBasics.html>, Eqs.\n       SR1 and SR2\n\n    .. [3] Partridge, G. W. and Platt, C. M. R. 1976. Radiative Processes\n       in Meteorology and Climatology.\n\n    .. [4] Duffie, J. A. and Beckman, W. A. 1991. Solar Engineering of\n       Thermal Processes, 2nd edn. J. Wiley and Sons, New York.\n\n    .. [5] ASCE, 2005. The ASCE Standardized Reference Evapotranspiration\n       Equation, Environmental and Water Resources Institute of the American\n       Civil Engineers, Ed. R. G. Allen et al.\n    \"\"\"\n\n    to_doy, to_datetimeindex, to_output = \\\n        _handle_extra_radiation_types(datetime_or_doy, epoch_year)\n\n    # consider putting asce and spencer methods in their own functions\n    method = method.lower()\n    if method == 'asce':\n        B = solarposition._calculate_simple_day_angle(to_doy(datetime_or_doy),\n                                                      offset=0)\n        RoverR0sqrd = 1 + 0.033 * np.cos(B)\n    elif method == 'spencer':\n        B = solarposition._calculate_simple_day_angle(to_doy(datetime_or_doy))\n        RoverR0sqrd = (1.00011 + 0.034221 * np.cos(B) + 0.00128 * np.sin(B) +\n                       0.000719 * np.cos(2 * B) + 7.7e-05 * np.sin(2 * B))\n    elif method == 'pyephem':\n        times = to_datetimeindex(datetime_or_doy)\n        RoverR0sqrd = solarposition.pyephem_earthsun_distance(times) ** (-2)\n    elif method == 'nrel':\n        times = to_datetimeindex(datetime_or_doy)\n        RoverR0sqrd = \\\n            solarposition.nrel_earthsun_distance(times, **kwargs) ** (-2)\n    else:\n        raise ValueError('Invalid method: %s', method)\n\n    Ea = solar_constant * RoverR0sqrd\n\n    Ea = to_output(Ea)\n\n    return Ea\n\n\ndef _handle_extra_radiation_types(datetime_or_doy, epoch_year):\n    # This block will set the functions that can be used to convert the\n    # inputs to either day of year or pandas DatetimeIndex, and the\n    # functions that will yield the appropriate output type. It's\n    # complicated because there are many day-of-year-like input types,\n    # and the different algorithms need different types. Maybe you have\n    # a better way to do it.\n    if isinstance(datetime_or_doy, pd.DatetimeIndex):\n        to_doy = tools._pandas_to_doy  # won't be evaluated unless necessary\n        def to_datetimeindex(x): return x                       # noqa: E306\n        to_output = partial(pd.Series, index=datetime_or_doy)\n    elif isinstance(datetime_or_doy, pd.Timestamp):\n        to_doy = tools._pandas_to_doy\n        to_datetimeindex = \\\n            tools._datetimelike_scalar_to_datetimeindex\n        to_output = tools._scalar_out\n    elif isinstance(datetime_or_doy,\n                    (datetime.date, datetime.datetime, np.datetime64)):\n        to_doy = tools._datetimelike_scalar_to_doy\n        to_datetimeindex = \\\n            tools._datetimelike_scalar_to_datetimeindex\n        to_output = tools._scalar_out\n    elif np.isscalar(datetime_or_doy):  # ints and floats of various types\n        def to_doy(x): return x                                 # noqa: E306\n        to_datetimeindex = partial(tools._doy_to_datetimeindex,\n                                   epoch_year=epoch_year)\n        to_output = tools._scalar_out\n    else:  # assume that we have an array-like object of doy\n        def to_doy(x): return x                                 # noqa: E306\n        to_datetimeindex = partial(tools._doy_to_datetimeindex,\n                                   epoch_year=epoch_year)\n        to_output = tools._array_out\n\n    return to_doy, to_datetimeindex, to_output\n\n\ndef aoi_projection(surface_tilt, surface_azimuth, solar_zenith, solar_azimuth):\n    \"\"\"\n    Calculates the dot product of the sun position unit vector and the surface\n    normal unit vector; in other words, the cosine of the angle of incidence.\n\n    Usage note: When the sun is behind the surface the value returned is\n    negative.  For many uses negative values must be set to zero.\n\n    Input all angles in degrees.\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Panel tilt from horizontal.\n    surface_azimuth : numeric\n        Panel azimuth from north.\n    solar_zenith : numeric\n        Solar zenith angle.\n    solar_azimuth : numeric\n        Solar azimuth angle.\n\n    Returns\n    -------\n    projection : numeric\n        Dot product of panel normal and solar angle.\n    \"\"\"\n\n    projection = (\n        tools.cosd(surface_tilt) * tools.cosd(solar_zenith) +\n        tools.sind(surface_tilt) * tools.sind(solar_zenith) *\n        tools.cosd(solar_azimuth - surface_azimuth))\n\n    try:\n        projection.name = 'aoi_projection'\n    except AttributeError:\n        pass\n\n    return projection\n\n\ndef aoi(surface_tilt, surface_azimuth, solar_zenith, solar_azimuth):\n    \"\"\"\n    Calculates the angle of incidence of the solar vector on a surface.\n    This is the angle between the solar vector and the surface normal.\n\n    Input all angles in degrees.\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Panel tilt from horizontal.\n    surface_azimuth : numeric\n        Panel azimuth from north.\n    solar_zenith : numeric\n        Solar zenith angle.\n    solar_azimuth : numeric\n        Solar azimuth angle.\n\n    Returns\n    -------\n    aoi : numeric\n        Angle of incidence in degrees.\n    \"\"\"\n\n    projection = aoi_projection(surface_tilt, surface_azimuth,\n                                solar_zenith, solar_azimuth)\n    aoi_value = np.rad2deg(np.arccos(projection))\n\n    try:\n        aoi_value.name = 'aoi'\n    except AttributeError:\n        pass\n\n    return aoi_value\n\n\ndef poa_horizontal_ratio(surface_tilt, surface_azimuth,\n                         solar_zenith, solar_azimuth):\n    \"\"\"\n    Calculates the ratio of the beam components of the plane of array\n    irradiance and the horizontal irradiance.\n\n    Input all angles in degrees.\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Panel tilt from horizontal.\n    surface_azimuth : numeric\n        Panel azimuth from north.\n    solar_zenith : numeric\n        Solar zenith angle.\n    solar_azimuth : numeric\n        Solar azimuth angle.\n\n    Returns\n    -------\n    ratio : numeric\n        Ratio of the plane of array irradiance to the horizontal plane\n        irradiance\n    \"\"\"\n\n    cos_poa_zen = aoi_projection(surface_tilt, surface_azimuth,\n                                 solar_zenith, solar_azimuth)\n\n    cos_solar_zenith = tools.cosd(solar_zenith)\n\n    # ratio of tilted and horizontal beam irradiance\n    ratio = cos_poa_zen / cos_solar_zenith\n\n    try:\n        ratio.name = 'poa_ratio'\n    except AttributeError:\n        pass\n\n    return ratio\n\n\ndef beam_component(surface_tilt, surface_azimuth, solar_zenith, solar_azimuth,\n                   dni):\n    \"\"\"\n    Calculates the beam component of the plane of array irradiance.\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Panel tilt from horizontal.\n    surface_azimuth : numeric\n        Panel azimuth from north.\n    solar_zenith : numeric\n        Solar zenith angle.\n    solar_azimuth : numeric\n        Solar azimuth angle.\n    dni : numeric\n        Direct Normal Irradiance\n\n    Returns\n    -------\n    beam : numeric\n        Beam component\n    \"\"\"\n    beam = dni * aoi_projection(surface_tilt, surface_azimuth,\n                                solar_zenith, solar_azimuth)\n    beam = np.maximum(beam, 0)\n\n    return beam\n\n\ndef get_total_irradiance(surface_tilt, surface_azimuth,\n                         solar_zenith, solar_azimuth,\n                         dni, ghi, dhi, dni_extra=None, airmass=None,\n                         albedo=.25, surface_type=None,\n                         model='isotropic',\n                         model_perez='allsitescomposite1990', **kwargs):\n    r\"\"\"\n    Determine total in-plane irradiance and its beam, sky diffuse and ground\n    reflected components, using the specified sky diffuse irradiance model.\n\n    .. math::\n\n       I_{tot} = I_{beam} + I_{sky diffuse} + I_{ground}\n\n    Sky diffuse models include:\n        * isotropic (default)\n        * klucher\n        * haydavies\n        * reindl\n        * king\n        * perez\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Panel tilt from horizontal.\n    surface_azimuth : numeric\n        Panel azimuth from north.\n    solar_zenith : numeric\n        Solar zenith angle.\n    solar_azimuth : numeric\n        Solar azimuth angle.\n    dni : numeric\n        Direct Normal Irradiance\n    ghi : numeric\n        Global horizontal irradiance\n    dhi : numeric\n        Diffuse horizontal irradiance\n    dni_extra : None or numeric, default None\n        Extraterrestrial direct normal irradiance\n    airmass : None or numeric, default None\n        Airmass\n    albedo : numeric, default 0.25\n        Surface albedo\n    surface_type : None or String, default None\n        Surface type. See grounddiffuse.\n    model : String, default 'isotropic'\n        Irradiance model.\n    model_perez : String, default 'allsitescomposite1990'\n        Used only if model='perez'. See :py:func:`perez`.\n\n    Returns\n    -------\n    total_irrad : OrderedDict or DataFrame\n        Contains keys/columns ``'poa_global', 'poa_direct', 'poa_diffuse',\n        'poa_sky_diffuse', 'poa_ground_diffuse'``.\n    \"\"\"\n    poa_sky_diffuse = get_sky_diffuse(\n        surface_tilt, surface_azimuth, solar_zenith, solar_azimuth,\n        dni, ghi, dhi, dni_extra=dni_extra, airmass=airmass, model=model,\n        model_perez=model_perez)\n\n    poa_ground_diffuse = get_ground_diffuse(surface_tilt, ghi, albedo,\n                                            surface_type)\n    aoi_ = aoi(surface_tilt, surface_azimuth, solar_zenith, solar_azimuth)\n    irrads = poa_components(aoi_, dni, poa_sky_diffuse, poa_ground_diffuse)\n    return irrads\n\n\ndef get_sky_diffuse(surface_tilt, surface_azimuth,\n                    solar_zenith, solar_azimuth,\n                    dni, ghi, dhi, dni_extra=None, airmass=None,\n                    model='isotropic',\n                    model_perez='allsitescomposite1990'):\n    r\"\"\"\n    Determine in-plane sky diffuse irradiance component\n    using the specified sky diffuse irradiance model.\n\n    Sky diffuse models include:\n        * isotropic (default)\n        * klucher\n        * haydavies\n        * reindl\n        * king\n        * perez\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Panel tilt from horizontal.\n    surface_azimuth : numeric\n        Panel azimuth from north.\n    solar_zenith : numeric\n        Solar zenith angle.\n    solar_azimuth : numeric\n        Solar azimuth angle.\n    dni : numeric\n        Direct Normal Irradiance\n    ghi : numeric\n        Global horizontal irradiance\n    dhi : numeric\n        Diffuse horizontal irradiance\n    dni_extra : None or numeric, default None\n        Extraterrestrial direct normal irradiance\n    airmass : None or numeric, default None\n        Airmass\n    model : String, default 'isotropic'\n        Irradiance model.\n    model_perez : String, default 'allsitescomposite1990'\n        See perez.\n\n    Returns\n    -------\n    poa_sky_diffuse : numeric\n    \"\"\"\n\n    model = model.lower()\n    if model == 'isotropic':\n        sky = isotropic(surface_tilt, dhi)\n    elif model == 'klucher':\n        sky = klucher(surface_tilt, surface_azimuth, dhi, ghi,\n                      solar_zenith, solar_azimuth)\n    elif model == 'haydavies':\n        sky = haydavies(surface_tilt, surface_azimuth, dhi, dni, dni_extra,\n                        solar_zenith, solar_azimuth)\n    elif model == 'reindl':\n        sky = reindl(surface_tilt, surface_azimuth, dhi, dni, ghi, dni_extra,\n                     solar_zenith, solar_azimuth)\n    elif model == 'king':\n        sky = king(surface_tilt, dhi, ghi, solar_zenith)\n    elif model == 'perez':\n        sky = perez(surface_tilt, surface_azimuth, dhi, dni, dni_extra,\n                    solar_zenith, solar_azimuth, airmass,\n                    model=model_perez)\n    else:\n        raise ValueError(f'invalid model selection {model}')\n\n    return sky\n\n\ndef poa_components(aoi, dni, poa_sky_diffuse, poa_ground_diffuse):\n    r'''\n    Determine in-plane irradiance components.\n\n    Combines DNI with sky diffuse and ground-reflected irradiance to calculate\n    total, direct and diffuse irradiance components in the plane of array.\n\n    Parameters\n    ----------\n    aoi : numeric\n        Angle of incidence of solar rays with respect to the module\n        surface, from :func:`aoi`.\n\n    dni : numeric\n        Direct normal irradiance (W/m^2), as measured from a TMY file or\n        calculated with a clearsky model.\n\n    poa_sky_diffuse : numeric\n        Diffuse irradiance (W/m^2) in the plane of the modules, as\n        calculated by a diffuse irradiance translation function\n\n    poa_ground_diffuse : numeric\n        Ground reflected irradiance (W/m^2) in the plane of the modules,\n        as calculated by an albedo model (eg. :func:`grounddiffuse`)\n\n    Returns\n    -------\n    irrads : OrderedDict or DataFrame\n        Contains the following keys:\n\n        * ``poa_global`` : Total in-plane irradiance (W/m^2)\n        * ``poa_direct`` : Total in-plane beam irradiance (W/m^2)\n        * ``poa_diffuse`` : Total in-plane diffuse irradiance (W/m^2)\n        * ``poa_sky_diffuse`` : In-plane diffuse irradiance from sky (W/m^2)\n        * ``poa_ground_diffuse`` : In-plane diffuse irradiance from ground\n          (W/m^2)\n\n    Notes\n    ------\n    Negative beam irradiation due to aoi :math:`> 90^{\\circ}` or AOI\n    :math:`< 0^{\\circ}` is set to zero.\n    '''\n\n    poa_direct = np.maximum(dni * np.cos(np.radians(aoi)), 0)\n    poa_diffuse = poa_sky_diffuse + poa_ground_diffuse\n    poa_global = poa_direct + poa_diffuse\n\n    irrads = OrderedDict()\n    irrads['poa_global'] = poa_global\n    irrads['poa_direct'] = poa_direct\n    irrads['poa_diffuse'] = poa_diffuse\n    irrads['poa_sky_diffuse'] = poa_sky_diffuse\n    irrads['poa_ground_diffuse'] = poa_ground_diffuse\n\n    if isinstance(poa_direct, pd.Series):\n        irrads = pd.DataFrame(irrads)\n\n    return irrads\n\n\ndef get_ground_diffuse(surface_tilt, ghi, albedo=.25, surface_type=None):\n    '''\n    Estimate diffuse irradiance from ground reflections given\n    irradiance, albedo, and surface tilt\n\n    Function to determine the portion of irradiance on a tilted surface\n    due to ground reflections. Any of the inputs may be DataFrames or\n    scalars.\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Surface tilt angles in decimal degrees. Tilt must be >=0 and\n        <=180. The tilt angle is defined as degrees from horizontal\n        (e.g. surface facing up = 0, surface facing horizon = 90).\n\n    ghi : numeric\n        Global horizontal irradiance in W/m^2.\n\n    albedo : numeric, default 0.25\n        Ground reflectance, typically 0.1-0.4 for surfaces on Earth\n        (land), may increase over snow, ice, etc. May also be known as\n        the reflection coefficient. Must be >=0 and <=1. Will be\n        overridden if surface_type is supplied.\n\n    surface_type: None or string, default None\n        If not None, overrides albedo. String can be one of 'urban',\n        'grass', 'fresh grass', 'snow', 'fresh snow', 'asphalt', 'concrete',\n        'aluminum', 'copper', 'fresh steel', 'dirty steel', 'sea'.\n\n    Returns\n    -------\n    grounddiffuse : numeric\n        Ground reflected irradiances in W/m^2.\n\n\n    References\n    ----------\n    .. [1] Loutzenhiser P.G. et. al. \"Empirical validation of models to compute\n       solar irradiance on inclined surfaces for building energy simulation\"\n       2007, Solar Energy vol. 81. pp. 254-267.\n\n    The calculation is the last term of equations 3, 4, 7, 8, 10, 11, and 12.\n\n    .. [2] albedos from:\n       http://files.pvsyst.com/help/albedo.htm\n       and\n       http://en.wikipedia.org/wiki/Albedo\n       and\n       https://doi.org/10.1175/1520-0469(1972)029<0959:AOTSS>2.0.CO;2\n    '''\n\n    if surface_type is not None:\n        albedo = SURFACE_ALBEDOS[surface_type]\n\n    diffuse_irrad = ghi * albedo * (1 - np.cos(np.radians(surface_tilt))) * 0.5\n\n    try:\n        diffuse_irrad.name = 'diffuse_ground'\n    except AttributeError:\n        pass\n\n    return diffuse_irrad\n\n\ndef isotropic(surface_tilt, dhi):\n    r'''\n    Determine diffuse irradiance from the sky on a tilted surface using\n    the isotropic sky model.\n\n    .. math::\n\n       I_{d} = DHI \\frac{1 + \\cos\\beta}{2}\n\n    Hottel and Woertz's model treats the sky as a uniform source of\n    diffuse irradiance. Thus the diffuse irradiance from the sky (ground\n    reflected irradiance is not included in this algorithm) on a tilted\n    surface can be found from the diffuse horizontal irradiance and the\n    tilt angle of the surface.\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Surface tilt angle in decimal degrees. Tilt must be >=0 and\n        <=180. The tilt angle is defined as degrees from horizontal\n        (e.g. surface facing up = 0, surface facing horizon = 90)\n\n    dhi : numeric\n        Diffuse horizontal irradiance in W/m^2. DHI must be >=0.\n\n    Returns\n    -------\n    diffuse : numeric\n        The sky diffuse component of the solar radiation.\n\n    References\n    ----------\n    .. [1] Loutzenhiser P.G. et. al. \"Empirical validation of models to\n       compute solar irradiance on inclined surfaces for building energy\n       simulation\" 2007, Solar Energy vol. 81. pp. 254-267\n\n    .. [2] Hottel, H.C., Woertz, B.B., 1942. Evaluation of flat-plate solar\n       heat collector. Trans. ASME 64, 91.\n    '''\n\n    sky_diffuse = dhi * (1 + tools.cosd(surface_tilt)) * 0.5\n\n    return sky_diffuse\n\n\ndef klucher(surface_tilt, surface_azimuth, dhi, ghi, solar_zenith,\n            solar_azimuth):\n    r'''\n    Determine diffuse irradiance from the sky on a tilted surface\n    using Klucher's 1979 model\n\n    .. math::\n\n       I_{d} = DHI \\frac{1 + \\cos\\beta}{2} (1 + F' \\sin^3(\\beta/2))\n       (1 + F' \\cos^2\\theta\\sin^3\\theta_z)\n\n    where\n\n    .. math::\n\n       F' = 1 - (I_{d0} / GHI)^2\n\n    Klucher's 1979 model determines the diffuse irradiance from the sky\n    (ground reflected irradiance is not included in this algorithm) on a\n    tilted surface using the surface tilt angle, surface azimuth angle,\n    diffuse horizontal irradiance, direct normal irradiance, global\n    horizontal irradiance, extraterrestrial irradiance, sun zenith\n    angle, and sun azimuth angle.\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Surface tilt angles in decimal degrees. surface_tilt must be >=0\n        and <=180. The tilt angle is defined as degrees from horizontal\n        (e.g. surface facing up = 0, surface facing horizon = 90)\n\n    surface_azimuth : numeric\n        Surface azimuth angles in decimal degrees. surface_azimuth must\n        be >=0 and <=360. The Azimuth convention is defined as degrees\n        east of north (e.g. North = 0, South=180 East = 90, West = 270).\n\n    dhi : numeric\n        Diffuse horizontal irradiance in W/m^2. DHI must be >=0.\n\n    ghi : numeric\n        Global irradiance in W/m^2. DNI must be >=0.\n\n    solar_zenith : numeric\n        Apparent (refraction-corrected) zenith angles in decimal\n        degrees. solar_zenith must be >=0 and <=180.\n\n    solar_azimuth : numeric\n        Sun azimuth angles in decimal degrees. solar_azimuth must be >=0\n        and <=360. The Azimuth convention is defined as degrees east of\n        north (e.g. North = 0, East = 90, West = 270).\n\n    Returns\n    -------\n    diffuse : numeric\n        The sky diffuse component of the solar radiation.\n\n    References\n    ----------\n    .. [1] Loutzenhiser P.G. et. al. \"Empirical validation of models to compute\n       solar irradiance on inclined surfaces for building energy simulation\"\n       2007, Solar Energy vol. 81. pp. 254-267\n\n    .. [2] Klucher, T.M., 1979. Evaluation of models to predict insolation on\n       tilted surfaces. Solar Energy 23 (2), 111-114.\n    '''\n\n    # zenith angle with respect to panel normal.\n    cos_tt = aoi_projection(surface_tilt, surface_azimuth,\n                            solar_zenith, solar_azimuth)\n    cos_tt = np.maximum(cos_tt, 0)  # GH 526\n\n    # silence warning from 0 / 0\n    with np.errstate(invalid='ignore'):\n        F = 1 - ((dhi / ghi) ** 2)\n\n    try:\n        # fails with single point input\n        F.fillna(0, inplace=True)\n    except AttributeError:\n        F = np.where(np.isnan(F), 0, F)\n\n    term1 = 0.5 * (1 + tools.cosd(surface_tilt))\n    term2 = 1 + F * (tools.sind(0.5 * surface_tilt) ** 3)\n    term3 = 1 + F * (cos_tt ** 2) * (tools.sind(solar_zenith) ** 3)\n\n    sky_diffuse = dhi * term1 * term2 * term3\n\n    return sky_diffuse\n\n\ndef haydavies(surface_tilt, surface_azimuth, dhi, dni, dni_extra,\n              solar_zenith=None, solar_azimuth=None, projection_ratio=None):\n    r'''\n    Determine diffuse irradiance from the sky on a tilted surface using\n    Hay & Davies' 1980 model\n\n    .. math::\n        I_{d} = DHI ( A R_b + (1 - A) (\\frac{1 + \\cos\\beta}{2}) )\n\n    Hay and Davies' 1980 model determines the diffuse irradiance from\n    the sky (ground reflected irradiance is not included in this\n    algorithm) on a tilted surface using the surface tilt angle, surface\n    azimuth angle, diffuse horizontal irradiance, direct normal\n    irradiance, extraterrestrial irradiance, sun zenith angle, and sun\n    azimuth angle.\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Surface tilt angles in decimal degrees. The tilt angle is\n        defined as degrees from horizontal (e.g. surface facing up = 0,\n        surface facing horizon = 90)\n\n    surface_azimuth : numeric\n        Surface azimuth angles in decimal degrees. The azimuth\n        convention is defined as degrees east of north (e.g. North=0,\n        South=180, East=90, West=270).\n\n    dhi : numeric\n        Diffuse horizontal irradiance in W/m^2.\n\n    dni : numeric\n        Direct normal irradiance in W/m^2.\n\n    dni_extra : numeric\n        Extraterrestrial normal irradiance in W/m^2.\n\n    solar_zenith : None or numeric, default None\n        Solar apparent (refraction-corrected) zenith angles in decimal\n        degrees. Must supply ``solar_zenith`` and ``solar_azimuth`` or\n        supply ``projection_ratio``.\n\n    solar_azimuth : None or numeric, default None\n        Solar azimuth angles in decimal degrees. Must supply\n        ``solar_zenith`` and ``solar_azimuth`` or supply\n        ``projection_ratio``.\n\n    projection_ratio : None or numeric, default None\n        Ratio of angle of incidence projection to solar zenith angle\n        projection. Must supply ``solar_zenith`` and ``solar_azimuth``\n        or supply ``projection_ratio``.\n\n    Returns\n    --------\n    sky_diffuse : numeric\n        The sky diffuse component of the solar radiation.\n\n    References\n    -----------\n    .. [1] Loutzenhiser P.G. et. al. \"Empirical validation of models to\n       compute solar irradiance on inclined surfaces for building energy\n       simulation\" 2007, Solar Energy vol. 81. pp. 254-267\n\n    .. [2] Hay, J.E., Davies, J.A., 1980. Calculations of the solar\n       radiation incident on an inclined surface. In: Hay, J.E., Won, T.K.\n       (Eds.), Proc. of First Canadian Solar Radiation Data Workshop, 59.\n       Ministry of Supply and Services, Canada.\n    '''\n\n    # if necessary, calculate ratio of titled and horizontal beam irradiance\n    if projection_ratio is None:\n        cos_tt = aoi_projection(surface_tilt, surface_azimuth,\n                                solar_zenith, solar_azimuth)\n        cos_tt = np.maximum(cos_tt, 0)  # GH 526\n        cos_solar_zenith = tools.cosd(solar_zenith)\n        Rb = cos_tt / np.maximum(cos_solar_zenith, 0.01745)  # GH 432\n    else:\n        Rb = projection_ratio\n\n    # Anisotropy Index\n    AI = dni / dni_extra\n\n    # these are the () and [] sub-terms of the second term of eqn 7\n    term1 = 1 - AI\n    term2 = 0.5 * (1 + tools.cosd(surface_tilt))\n\n    sky_diffuse = dhi * (AI * Rb + term1 * term2)\n    sky_diffuse = np.maximum(sky_diffuse, 0)\n\n    return sky_diffuse\n\n\ndef reindl(surface_tilt, surface_azimuth, dhi, dni, ghi, dni_extra,\n           solar_zenith, solar_azimuth):\n    r'''\n    Determine diffuse irradiance from the sky on a tilted surface using\n    Reindl's 1990 model\n\n    .. math::\n\n       I_{d} = DHI (A R_b + (1 - A) (\\frac{1 + \\cos\\beta}{2})\n       (1 + \\sqrt{\\frac{I_{hb}}{I_h}} \\sin^3(\\beta/2)) )\n\n    Reindl's 1990 model determines the diffuse irradiance from the sky\n    (ground reflected irradiance is not included in this algorithm) on a\n    tilted surface using the surface tilt angle, surface azimuth angle,\n    diffuse horizontal irradiance, direct normal irradiance, global\n    horizontal irradiance, extraterrestrial irradiance, sun zenith\n    angle, and sun azimuth angle.\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Surface tilt angles in decimal degrees. The tilt angle is\n        defined as degrees from horizontal (e.g. surface facing up = 0,\n        surface facing horizon = 90)\n\n    surface_azimuth : numeric\n        Surface azimuth angles in decimal degrees. The azimuth\n        convention is defined as degrees east of north (e.g. North = 0,\n        South=180 East = 90, West = 270).\n\n    dhi : numeric\n        diffuse horizontal irradiance in W/m^2.\n\n    dni : numeric\n        direct normal irradiance in W/m^2.\n\n    ghi: numeric\n        Global irradiance in W/m^2.\n\n    dni_extra : numeric\n        Extraterrestrial normal irradiance in W/m^2.\n\n    solar_zenith : numeric\n        Apparent (refraction-corrected) zenith angles in decimal degrees.\n\n    solar_azimuth : numeric\n        Sun azimuth angles in decimal degrees. The azimuth convention is\n        defined as degrees east of north (e.g. North = 0, East = 90,\n        West = 270).\n\n    Returns\n    -------\n    poa_sky_diffuse : numeric\n        The sky diffuse component of the solar radiation.\n\n    Notes\n    -----\n    The poa_sky_diffuse calculation is generated from the Loutzenhiser et al.\n    (2007) paper, equation 8. Note that I have removed the beam and ground\n    reflectance portion of the equation and this generates ONLY the diffuse\n    radiation from the sky and circumsolar, so the form of the equation\n    varies slightly from equation 8.\n\n    References\n    ----------\n    .. [1] Loutzenhiser P.G. et. al. \"Empirical validation of models to\n       compute solar irradiance on inclined surfaces for building energy\n       simulation\" 2007, Solar Energy vol. 81. pp. 254-267\n\n    .. [2] Reindl, D.T., Beckmann, W.A., Duffie, J.A., 1990a. Diffuse\n       fraction correlations. Solar Energy 45(1), 1-7.\n\n    .. [3] Reindl, D.T., Beckmann, W.A., Duffie, J.A., 1990b. Evaluation of\n       hourly tilted surface radiation models. Solar Energy 45(1), 9-17.\n    '''\n\n    cos_tt = aoi_projection(surface_tilt, surface_azimuth,\n                            solar_zenith, solar_azimuth)\n    cos_tt = np.maximum(cos_tt, 0)  # GH 526\n\n    # do not apply cos(zen) limit here (needed for HB below)\n    cos_solar_zenith = tools.cosd(solar_zenith)\n\n    # ratio of titled and horizontal beam irradiance\n    Rb = cos_tt / np.maximum(cos_solar_zenith, 0.01745)  # GH 432\n\n    # Anisotropy Index\n    AI = dni / dni_extra\n\n    # DNI projected onto horizontal\n    HB = dni * cos_solar_zenith\n    HB = np.maximum(HB, 0)\n\n    # these are the () and [] sub-terms of the second term of eqn 8\n    term1 = 1 - AI\n    term2 = 0.5 * (1 + tools.cosd(surface_tilt))\n    with np.errstate(invalid='ignore', divide='ignore'):\n        hb_to_ghi = np.where(ghi == 0, 0, np.divide(HB, ghi))\n    term3 = 1 + np.sqrt(hb_to_ghi) * (tools.sind(0.5 * surface_tilt)**3)\n    sky_diffuse = dhi * (AI * Rb + term1 * term2 * term3)\n    sky_diffuse = np.maximum(sky_diffuse, 0)\n\n    return sky_diffuse\n\n\ndef king(surface_tilt, dhi, ghi, solar_zenith):\n    '''\n    Determine diffuse irradiance from the sky on a tilted surface using\n    the King model.\n\n    King's model determines the diffuse irradiance from the sky (ground\n    reflected irradiance is not included in this algorithm) on a tilted\n    surface using the surface tilt angle, diffuse horizontal irradiance,\n    global horizontal irradiance, and sun zenith angle. Note that this\n    model is not well documented and has not been published in any\n    fashion (as of January 2012).\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Surface tilt angles in decimal degrees. The tilt angle is\n        defined as degrees from horizontal (e.g. surface facing up = 0,\n        surface facing horizon = 90)\n\n    dhi : numeric\n        Diffuse horizontal irradiance in W/m^2.\n\n    ghi : numeric\n        Global horizontal irradiance in W/m^2.\n\n    solar_zenith : numeric\n        Apparent (refraction-corrected) zenith angles in decimal degrees.\n\n    Returns\n    --------\n    poa_sky_diffuse : numeric\n        The diffuse component of the solar radiation.\n    '''\n\n    sky_diffuse = (dhi * (1 + tools.cosd(surface_tilt)) / 2 + ghi *\n                   (0.012 * solar_zenith - 0.04) *\n                   (1 - tools.cosd(surface_tilt)) / 2)\n    sky_diffuse = np.maximum(sky_diffuse, 0)\n\n    return sky_diffuse\n\n\ndef perez(surface_tilt, surface_azimuth, dhi, dni, dni_extra,\n          solar_zenith, solar_azimuth, airmass,\n          model='allsitescomposite1990', return_components=False):\n    '''\n    Determine diffuse irradiance from the sky on a tilted surface using\n    one of the Perez models.\n\n    Perez models determine the diffuse irradiance from the sky (ground\n    reflected irradiance is not included in this algorithm) on a tilted\n    surface using the surface tilt angle, surface azimuth angle, diffuse\n    horizontal irradiance, direct normal irradiance, extraterrestrial\n    irradiance, sun zenith angle, sun azimuth angle, and relative (not\n    pressure-corrected) airmass. Optionally a selector may be used to\n    use any of Perez's model coefficient sets.\n\n    Parameters\n    ----------\n    surface_tilt : numeric\n        Surface tilt angles in decimal degrees. surface_tilt must be >=0\n        and <=180. The tilt angle is defined as degrees from horizontal\n        (e.g. surface facing up = 0, surface facing horizon = 90)\n\n    surface_azimuth : numeric\n        Surface azimuth angles in decimal degrees. surface_azimuth must\n        be >=0 and <=360. The azimuth convention is defined as degrees\n        east of north (e.g. North = 0, South=180 East = 90, West = 270).\n\n    dhi : numeric\n        Diffuse horizontal irradiance in W/m^2. DHI must be >=0.\n\n    dni : numeric\n        Direct normal irradiance in W/m^2. DNI must be >=0.\n\n    dni_extra : numeric\n        Extraterrestrial normal irradiance in W/m^2.\n\n    solar_zenith : numeric\n        apparent (refraction-corrected) zenith angles in decimal\n        degrees. solar_zenith must be >=0 and <=180.\n\n    solar_azimuth : numeric\n        Sun azimuth angles in decimal degrees. solar_azimuth must be >=0\n        and <=360. The azimuth convention is defined as degrees east of\n        north (e.g. North = 0, East = 90, West = 270).\n\n    airmass : numeric\n        Relative (not pressure-corrected) airmass values. If AM is a\n        DataFrame it must be of the same size as all other DataFrame\n        inputs. AM must be >=0 (careful using the 1/sec(z) model of AM\n        generation)\n\n    model : string (optional, default='allsitescomposite1990')\n        A string which selects the desired set of Perez coefficients. If\n        model is not provided as an input, the default, '1990' will be\n        used. All possible model selections are:\n\n        * '1990'\n        * 'allsitescomposite1990' (same as '1990')\n        * 'allsitescomposite1988'\n        * 'sandiacomposite1988'\n        * 'usacomposite1988'\n        * 'france1988'\n        * 'phoenix1988'\n        * 'elmonte1988'\n        * 'osage1988'\n        * 'albuquerque1988'\n        * 'capecanaveral1988'\n        * 'albany1988'\n\n    return_components: bool (optional, default=False)\n        Flag used to decide whether to return the calculated diffuse components\n        or not.\n\n    Returns\n    --------\n    numeric, OrderedDict, or DataFrame\n        Return type controlled by `return_components` argument.\n        If ``return_components=False``, `sky_diffuse` is returned.\n        If ``return_components=True``, `diffuse_components` is returned.\n\n    sky_diffuse : numeric\n        The sky diffuse component of the solar radiation on a tilted\n        surface.\n\n    diffuse_components : OrderedDict (array input) or DataFrame (Series input)\n        Keys/columns are:\n            * sky_diffuse: Total sky diffuse\n            * isotropic\n            * circumsolar\n            * horizon\n\n\n    References\n    ----------\n    .. [1] Loutzenhiser P.G. et. al. \"Empirical validation of models to\n       compute solar irradiance on inclined surfaces for building energy\n       simulation\" 2007, Solar Energy vol. 81. pp. 254-267\n\n    .. [2] Perez, R., Seals, R., Ineichen, P., Stewart, R., Menicucci, D.,\n       1987. A new simplified version of the Perez diffuse irradiance model\n       for tilted surfaces. Solar Energy 39(3), 221-232.\n\n    .. [3] Perez, R., Ineichen, P., Seals, R., Michalsky, J., Stewart, R.,\n       1990. Modeling daylight availability and irradiance components from\n       direct and global irradiance. Solar Energy 44 (5), 271-289.\n\n    .. [4] Perez, R. et. al 1988. \"The Development and Verification of the\n       Perez Diffuse Radiation Model\". SAND88-7030\n    '''\n\n    kappa = 1.041  # for solar_zenith in radians\n    z = np.radians(solar_zenith)  # convert to radians\n\n    # delta is the sky's \"brightness\"\n    delta = dhi * airmass / dni_extra\n\n    # epsilon is the sky's \"clearness\"\n    with np.errstate(invalid='ignore'):\n        eps = ((dhi + dni) / dhi + kappa * (z ** 3)) / (1 + kappa * (z ** 3))\n\n    # numpy indexing below will not work with a Series\n    if isinstance(eps, pd.Series):\n        eps = eps.values\n\n    # Perez et al define clearness bins according to the following\n    # rules. 1 = overcast ... 8 = clear (these names really only make\n    # sense for small zenith angles, but...) these values will\n    # eventually be used as indicies for coeffecient look ups\n    ebin = np.digitize(eps, (0., 1.065, 1.23, 1.5, 1.95, 2.8, 4.5, 6.2))\n    ebin = np.array(ebin)  # GH 642\n    ebin[np.isnan(eps)] = 0\n\n    # correct for 0 indexing in coeffecient lookup\n    # later, ebin = -1 will yield nan coefficients\n    ebin -= 1\n\n    # The various possible sets of Perez coefficients are contained\n    # in a subfunction to clean up the code.\n    F1c, F2c = _get_perez_coefficients(model)\n\n    # results in invalid eps (ebin = -1) being mapped to nans\n    nans = np.array([np.nan, np.nan, np.nan])\n    F1c = np.vstack((F1c, nans))\n    F2c = np.vstack((F2c, nans))\n\n    F1 = (F1c[ebin, 0] + F1c[ebin, 1] * delta + F1c[ebin, 2] * z)\n    F1 = np.maximum(F1, 0)\n\n    F2 = (F2c[ebin, 0] + F2c[ebin, 1] * delta + F2c[ebin, 2] * z)\n    F2 = np.maximum(F2, 0)\n\n    A = aoi_projection(surface_tilt, surface_azimuth,\n                       solar_zenith, solar_azimuth)\n    A = np.maximum(A, 0)\n\n    B = tools.cosd(solar_zenith)\n    B = np.maximum(B, tools.cosd(85))\n\n    # Calculate Diffuse POA from sky dome\n    term1 = 0.5 * (1 - F1) * (1 + tools.cosd(surface_tilt))\n    term2 = F1 * A / B\n    term3 = F2 * tools.sind(surface_tilt)\n\n    sky_diffuse = np.maximum(dhi * (term1 + term2 + term3), 0)\n\n    # we've preserved the input type until now, so don't ruin it!\n    if isinstance(sky_diffuse, pd.Series):\n        sky_diffuse[np.isnan(airmass)] = 0\n    else:\n        sky_diffuse = np.where(np.isnan(airmass), 0, sky_diffuse)\n\n    if return_components:\n        diffuse_components = OrderedDict()\n        diffuse_components['sky_diffuse'] = sky_diffuse\n\n        # Calculate the different components\n        diffuse_components['isotropic'] = dhi * term1\n        diffuse_components['circumsolar'] = dhi * term2\n        diffuse_components['horizon'] = dhi * term3\n\n        # Set values of components to 0 when sky_diffuse is 0\n        mask = sky_diffuse == 0\n        if isinstance(sky_diffuse, pd.Series):\n            diffuse_components = pd.DataFrame(diffuse_components)\n            diffuse_components.loc[mask] = 0\n        else:\n            diffuse_components = {k: np.where(mask, 0, v) for k, v in\n                                  diffuse_components.items()}\n        return diffuse_components\n    else:\n        return sky_diffuse\n\n\ndef clearsky_index(ghi, clearsky_ghi, max_clearsky_index=2.0):\n    \"\"\"\n    Calculate the clearsky index.\n\n    The clearsky index is the ratio of global to clearsky global irradiance.\n    Negative and non-finite clearsky index values will be truncated to zero.\n\n    Parameters\n    ----------\n    ghi : numeric\n        Global horizontal irradiance in W/m^2.\n\n    clearsky_ghi : numeric\n        Modeled clearsky GHI\n\n    max_clearsky_index : numeric, default 2.0\n        Maximum value of the clearsky index. The default, 2.0, allows\n        for over-irradiance events typically seen in sub-hourly data.\n\n    Returns\n    -------\n    clearsky_index : numeric\n        Clearsky index\n    \"\"\"\n    clearsky_index = ghi / clearsky_ghi\n    # set +inf, -inf, and nans to zero\n    clearsky_index = np.where(~np.isfinite(clearsky_index), 0,\n                              clearsky_index)\n    # but preserve nans in the input arrays\n    input_is_nan = ~np.isfinite(ghi) | ~np.isfinite(clearsky_ghi)\n    clearsky_index = np.where(input_is_nan, np.nan, clearsky_index)\n\n    clearsky_index = np.maximum(clearsky_index, 0)\n    clearsky_index = np.minimum(clearsky_index, max_clearsky_index)\n\n    # preserve input type\n    if isinstance(ghi, pd.Series):\n        clearsky_index = pd.Series(clearsky_index, index=ghi.index)\n\n    return clearsky_index\n\n\ndef clearness_index(ghi, solar_zenith, extra_radiation, min_cos_zenith=0.065,\n                    max_clearness_index=2.0):\n    \"\"\"\n    Calculate the clearness index.\n\n    The clearness index is the ratio of global to extraterrestrial\n    irradiance on a horizontal plane [1]_.\n\n    Parameters\n    ----------\n    ghi : numeric\n        Global horizontal irradiance in W/m^2.\n\n    solar_zenith : numeric\n        True (not refraction-corrected) solar zenith angle in decimal\n        degrees.\n\n    extra_radiation : numeric\n        Irradiance incident at the top of the atmosphere\n\n    min_cos_zenith : numeric, default 0.065\n        Minimum value of cos(zenith) to allow when calculating global\n        clearness index `kt`. Equivalent to zenith = 86.273 degrees.\n\n    max_clearness_index : numeric, default 2.0\n        Maximum value of the clearness index. The default, 2.0, allows\n        for over-irradiance events typically seen in sub-hourly data.\n        NREL's SRRL Fortran code used 0.82 for hourly data.\n\n    Returns\n    -------\n    kt : numeric\n        Clearness index\n\n    References\n    ----------\n    .. [1] Maxwell, E. L., \"A Quasi-Physical Model for Converting Hourly\n           Global Horizontal to Direct Normal Insolation\", Technical\n           Report No. SERI/TR-215-3087, Golden, CO: Solar Energy Research\n           Institute, 1987.\n    \"\"\"\n    cos_zenith = tools.cosd(solar_zenith)\n    I0h = extra_radiation * np.maximum(cos_zenith, min_cos_zenith)\n    # consider adding\n    # with np.errstate(invalid='ignore', divide='ignore'):\n    # to kt calculation, but perhaps it's good to allow these\n    # warnings to the users that override min_cos_zenith\n    kt = ghi / I0h\n    kt = np.maximum(kt, 0)\n    kt = np.minimum(kt, max_clearness_index)\n    return kt\n\n\ndef clearness_index_zenith_independent(clearness_index, airmass,\n                                       max_clearness_index=2.0):\n    \"\"\"\n    Calculate the zenith angle independent clearness index.\n\n    See [1]_ for details.\n\n    Parameters\n    ----------\n    clearness_index : numeric\n        Ratio of global to extraterrestrial irradiance on a horizontal\n        plane\n\n    airmass : numeric\n        Airmass\n\n    max_clearness_index : numeric, default 2.0\n        Maximum value of the clearness index. The default, 2.0, allows\n        for over-irradiance events typically seen in sub-hourly data.\n        NREL's SRRL Fortran code used 0.82 for hourly data.\n\n    Returns\n    -------\n    kt_prime : numeric\n        Zenith independent clearness index\n\n    References\n    ----------\n    .. [1] Perez, R., P. Ineichen, E. Maxwell, R. Seals and A. Zelenka,\n           (1992). \"Dynamic Global-to-Direct Irradiance Conversion Models\".\n           ASHRAE Transactions-Research Series, pp. 354-369\n    \"\"\"\n    # Perez eqn 1\n    kt_prime = clearness_index / _kt_kt_prime_factor(airmass)\n    kt_prime = np.maximum(kt_prime, 0)\n    kt_prime = np.minimum(kt_prime, max_clearness_index)\n    return kt_prime\n\n\ndef _kt_kt_prime_factor(airmass):\n    \"\"\"\n    Calculate the conversion factor between kt and kt prime.\n    Function is useful because DIRINT and GTI-DIRINT both use this.\n    \"\"\"\n    # consider adding\n    # airmass = np.maximum(airmass, 12)  # GH 450\n    return 1.031 * np.exp(-1.4 / (0.9 + 9.4 / airmass)) + 0.1\n\n\ndef disc(ghi, solar_zenith, datetime_or_doy, pressure=101325,\n         min_cos_zenith=0.065, max_zenith=87, max_airmass=12):\n    \"\"\"\n    Estimate Direct Normal Irradiance from Global Horizontal Irradiance\n    using the DISC model.\n\n    The DISC algorithm converts global horizontal irradiance to direct\n    normal irradiance through empirical relationships between the global\n    and direct clearness indices.\n\n    The pvlib implementation limits the clearness index to 1.\n\n    The original report describing the DISC model [1]_ uses the\n    relative airmass rather than the absolute (pressure-corrected)\n    airmass. However, the NREL implementation of the DISC model [2]_\n    uses absolute airmass. PVLib Matlab also uses the absolute airmass.\n    pvlib python defaults to absolute airmass, but the relative airmass\n    can be used by supplying `pressure=None`.\n\n    Parameters\n    ----------\n    ghi : numeric\n        Global horizontal irradiance in W/m^2.\n\n    solar_zenith : numeric\n        True (not refraction-corrected) solar zenith angles in decimal\n        degrees.\n\n    datetime_or_doy : int, float, array, pd.DatetimeIndex\n        Day of year or array of days of year e.g.\n        pd.DatetimeIndex.dayofyear, or pd.DatetimeIndex.\n\n    pressure : None or numeric, default 101325\n        Site pressure in Pascal. If None, relative airmass is used\n        instead of absolute (pressure-corrected) airmass.\n\n    min_cos_zenith : numeric, default 0.065\n        Minimum value of cos(zenith) to allow when calculating global\n        clearness index `kt`. Equivalent to zenith = 86.273 degrees.\n\n    max_zenith : numeric, default 87\n        Maximum value of zenith to allow in DNI calculation. DNI will be\n        set to 0 for times with zenith values greater than `max_zenith`.\n\n    max_airmass : numeric, default 12\n        Maximum value of the airmass to allow in Kn calculation.\n        Default value (12) comes from range over which Kn was fit\n        to airmass in the original paper.\n\n    Returns\n    -------\n    output : OrderedDict or DataFrame\n        Contains the following keys:\n\n        * ``dni``: The modeled direct normal irradiance\n          in W/m^2 provided by the\n          Direct Insolation Simulation Code (DISC) model.\n        * ``kt``: Ratio of global to extraterrestrial\n          irradiance on a horizontal plane.\n        * ``airmass``: Airmass\n\n    References\n    ----------\n    .. [1] Maxwell, E. L., \"A Quasi-Physical Model for Converting Hourly\n       Global Horizontal to Direct Normal Insolation\", Technical\n       Report No. SERI/TR-215-3087, Golden, CO: Solar Energy Research\n       Institute, 1987.\n\n    .. [2] Maxwell, E. \"DISC Model\", Excel Worksheet.\n       https://www.nrel.gov/grid/solar-resource/disc.html\n\n    See Also\n    --------\n    dirint\n    \"\"\"\n\n    # this is the I0 calculation from the reference\n    # SSC uses solar constant = 1367.0 (checked 2018 08 15)\n    I0 = get_extra_radiation(datetime_or_doy, 1370., 'spencer')\n\n    kt = clearness_index(ghi, solar_zenith, I0, min_cos_zenith=min_cos_zenith,\n                         max_clearness_index=1)\n\n    am = atmosphere.get_relative_airmass(solar_zenith, model='kasten1966')\n    if pressure is not None:\n        am = atmosphere.get_absolute_airmass(am, pressure)\n\n    Kn, am = _disc_kn(kt, am, max_airmass=max_airmass)\n    dni = Kn * I0\n\n    bad_values = (solar_zenith > max_zenith) | (ghi < 0) | (dni < 0)\n    dni = np.where(bad_values, 0, dni)\n\n    output = OrderedDict()\n    output['dni'] = dni\n    output['kt'] = kt\n    output['airmass'] = am\n\n    if isinstance(datetime_or_doy, pd.DatetimeIndex):\n        output = pd.DataFrame(output, index=datetime_or_doy)\n\n    return output\n\n\ndef _disc_kn(clearness_index, airmass, max_airmass=12):\n    \"\"\"\n    Calculate Kn for `disc`\n\n    Parameters\n    ----------\n    clearness_index : numeric\n    airmass : numeric\n    max_airmass : float\n        airmass > max_airmass is set to max_airmass before being used\n        in calculating Kn.\n\n    Returns\n    -------\n    Kn : numeric\n    am : numeric\n        airmass used in the calculation of Kn. am <= max_airmass.\n    \"\"\"\n    # short names for equations\n    kt = clearness_index\n    am = airmass\n\n    am = np.minimum(am, max_airmass)  # GH 450\n\n    # powers of kt will be used repeatedly, so compute only once\n    kt2 = kt * kt  # about the same as kt ** 2\n    kt3 = kt2 * kt  # 5-10x faster than kt ** 3\n\n    bools = (kt <= 0.6)\n    a = np.where(bools,\n                 0.512 - 1.56*kt + 2.286*kt2 - 2.222*kt3,\n                 -5.743 + 21.77*kt - 27.49*kt2 + 11.56*kt3)\n    b = np.where(bools,\n                 0.37 + 0.962*kt,\n                 41.4 - 118.5*kt + 66.05*kt2 + 31.9*kt3)\n    c = np.where(bools,\n                 -0.28 + 0.932*kt - 2.048*kt2,\n                 -47.01 + 184.2*kt - 222.0*kt2 + 73.81*kt3)\n\n    delta_kn = a + b * np.exp(c*am)\n\n    Knc = 0.866 - 0.122*am + 0.0121*am**2 - 0.000653*am**3 + 1.4e-05*am**4\n    Kn = Knc - delta_kn\n    return Kn, am\n\n\ndef dirint(ghi, solar_zenith, times, pressure=101325., use_delta_kt_prime=True,\n           temp_dew=None, min_cos_zenith=0.065, max_zenith=87):\n    \"\"\"\n    Determine DNI from GHI using the DIRINT modification of the DISC\n    model.\n\n    Implements the modified DISC model known as \"DIRINT\" introduced in\n    [1]. DIRINT predicts direct normal irradiance (DNI) from measured\n    global horizontal irradiance (GHI). DIRINT improves upon the DISC\n    model by using time-series GHI data and dew point temperature\n    information. The effectiveness of the DIRINT model improves with\n    each piece of information provided.\n\n    The pvlib implementation limits the clearness index to 1.\n\n    Parameters\n    ----------\n    ghi : array-like\n        Global horizontal irradiance in W/m^2.\n\n    solar_zenith : array-like\n        True (not refraction-corrected) solar_zenith angles in decimal\n        degrees.\n\n    times : DatetimeIndex\n\n    pressure : float or array-like, default 101325.0\n        The site pressure in Pascal. Pressure may be measured or an\n        average pressure may be calculated from site altitude.\n\n    use_delta_kt_prime : bool, default True\n        If True, indicates that the stability index delta_kt_prime is\n        included in the model. The stability index adjusts the estimated\n        DNI in response to dynamics in the time series of GHI. It is\n        recommended that delta_kt_prime is not used if the time between\n        GHI points is 1.5 hours or greater. If use_delta_kt_prime=True,\n        input data must be Series.\n\n    temp_dew : None, float, or array-like, default None\n        Surface dew point temperatures, in degrees C. Values of temp_dew\n        may be numeric or NaN. Any single time period point with a\n        temp_dew=NaN does not have dew point improvements applied. If\n        temp_dew is not provided, then dew point improvements are not\n        applied.\n\n    min_cos_zenith : numeric, default 0.065\n        Minimum value of cos(zenith) to allow when calculating global\n        clearness index `kt`. Equivalent to zenith = 86.273 degrees.\n\n    max_zenith : numeric, default 87\n        Maximum value of zenith to allow in DNI calculation. DNI will be\n        set to 0 for times with zenith values greater than `max_zenith`.\n\n    Returns\n    -------\n    dni : array-like\n        The modeled direct normal irradiance in W/m^2 provided by the\n        DIRINT model.\n\n    Notes\n    -----\n    DIRINT model requires time series data (ie. one of the inputs must\n    be a vector of length > 2).\n\n    References\n    ----------\n    .. [1] Perez, R., P. Ineichen, E. Maxwell, R. Seals and A. Zelenka,\n       (1992). \"Dynamic Global-to-Direct Irradiance Conversion Models\".\n       ASHRAE Transactions-Research Series, pp. 354-369\n\n    .. [2] Maxwell, E. L., \"A Quasi-Physical Model for Converting Hourly\n       Global Horizontal to Direct Normal Insolation\", Technical Report No.\n       SERI/TR-215-3087, Golden, CO: Solar Energy Research Institute, 1987.\n    \"\"\"\n\n    disc_out = disc(ghi, solar_zenith, times, pressure=pressure,\n                    min_cos_zenith=min_cos_zenith, max_zenith=max_zenith)\n    airmass = disc_out['airmass']\n    kt = disc_out['kt']\n\n    kt_prime = clearness_index_zenith_independent(\n        kt, airmass, max_clearness_index=1)\n    delta_kt_prime = _delta_kt_prime_dirint(kt_prime, use_delta_kt_prime,\n                                            times)\n    w = _temp_dew_dirint(temp_dew, times)\n\n    dirint_coeffs = _dirint_coeffs(times, kt_prime, solar_zenith, w,\n                                   delta_kt_prime)\n\n    # Perez eqn 5\n    dni = disc_out['dni'] * dirint_coeffs\n\n    return dni\n\n\ndef _dirint_from_dni_ktprime(dni, kt_prime, solar_zenith, use_delta_kt_prime,\n                             temp_dew):\n    \"\"\"\n    Calculate DIRINT DNI from supplied DISC DNI and Kt'.\n\n    Supports :py:func:`gti_dirint`\n    \"\"\"\n    times = dni.index\n    delta_kt_prime = _delta_kt_prime_dirint(kt_prime, use_delta_kt_prime,\n                                            times)\n    w = _temp_dew_dirint(temp_dew, times)\n    dirint_coeffs = _dirint_coeffs(times, kt_prime, solar_zenith, w,\n                                   delta_kt_prime)\n    dni_dirint = dni * dirint_coeffs\n    return dni_dirint\n\n\ndef _delta_kt_prime_dirint(kt_prime, use_delta_kt_prime, times):\n    \"\"\"\n    Calculate delta_kt_prime (Perez eqn 2 and eqn 3), or return a default value\n    for use with :py:func:`_dirint_bins`.\n    \"\"\"\n    if use_delta_kt_prime:\n        # Perez eqn 2\n        kt_next = kt_prime.shift(-1)\n        kt_previous = kt_prime.shift(1)\n        # replace nan with values that implement Perez Eq 3 for first and last\n        # positions. Use kt_previous and kt_next to handle series of length 1\n        kt_next.iloc[-1] = kt_previous.iloc[-1]\n        kt_previous.iloc[0] = kt_next.iloc[0]\n        delta_kt_prime = 0.5 * ((kt_prime - kt_next).abs().add(\n                                (kt_prime - kt_previous).abs(),\n                                fill_value=0))\n    else:\n        # do not change unless also modifying _dirint_bins\n        delta_kt_prime = pd.Series(-1, index=times)\n    return delta_kt_prime\n\n\ndef _temp_dew_dirint(temp_dew, times):\n    \"\"\"\n    Calculate precipitable water from surface dew point temp (Perez eqn 4),\n    or return a default value for use with :py:func:`_dirint_bins`.\n    \"\"\"\n    if temp_dew is not None:\n        # Perez eqn 4\n        w = pd.Series(np.exp(0.07 * temp_dew - 0.075), index=times)\n    else:\n        # do not change unless also modifying _dirint_bins\n        w = pd.Series(-1, index=times)\n    return w\n\n\ndef _dirint_coeffs(times, kt_prime, solar_zenith, w, delta_kt_prime):\n    \"\"\"\n    Determine the DISC to DIRINT multiplier `dirint_coeffs`.\n\n    dni = disc_out['dni'] * dirint_coeffs\n\n    Parameters\n    ----------\n    times : pd.DatetimeIndex\n    kt_prime : Zenith-independent clearness index\n    solar_zenith : Solar zenith angle\n    w : precipitable water estimated from surface dew-point temperature\n    delta_kt_prime : stability index\n\n    Returns\n    -------\n    dirint_coeffs : array-like\n    \"\"\"\n    kt_prime_bin, zenith_bin, w_bin, delta_kt_prime_bin = \\\n        _dirint_bins(times, kt_prime, solar_zenith, w, delta_kt_prime)\n\n    # get the coefficients\n    coeffs = _get_dirint_coeffs()\n\n    # subtract 1 to account for difference between MATLAB-style bin\n    # assignment and Python-style array lookup.\n    dirint_coeffs = coeffs[kt_prime_bin-1, zenith_bin-1,\n                           delta_kt_prime_bin-1, w_bin-1]\n\n    # convert unassigned bins to nan\n    dirint_coeffs = np.where((kt_prime_bin == 0) | (zenith_bin == 0) |\n                             (w_bin == 0) | (delta_kt_prime_bin == 0),\n                             np.nan, dirint_coeffs)\n    return dirint_coeffs\n\n\ndef _dirint_bins(times, kt_prime, zenith, w, delta_kt_prime):\n    \"\"\"\n    Determine the bins for the DIRINT coefficients.\n\n    Parameters\n    ----------\n    times : pd.DatetimeIndex\n    kt_prime : Zenith-independent clearness index\n    zenith : Solar zenith angle\n    w : precipitable water estimated from surface dew-point temperature\n    delta_kt_prime : stability index\n\n    Returns\n    -------\n    tuple of kt_prime_bin, zenith_bin, w_bin, delta_kt_prime_bin\n    \"\"\"\n    # @wholmgren: the following bin assignments use MATLAB's 1-indexing.\n    # Later, we'll subtract 1 to conform to Python's 0-indexing.\n\n    # Create kt_prime bins\n    kt_prime_bin = pd.Series(0, index=times, dtype=np.int64)\n    kt_prime_bin[(kt_prime >= 0) & (kt_prime < 0.24)] = 1\n    kt_prime_bin[(kt_prime >= 0.24) & (kt_prime < 0.4)] = 2\n    kt_prime_bin[(kt_prime >= 0.4) & (kt_prime < 0.56)] = 3\n    kt_prime_bin[(kt_prime >= 0.56) & (kt_prime < 0.7)] = 4\n    kt_prime_bin[(kt_prime >= 0.7) & (kt_prime < 0.8)] = 5\n    kt_prime_bin[(kt_prime >= 0.8) & (kt_prime <= 1)] = 6\n\n    # Create zenith angle bins\n    zenith_bin = pd.Series(0, index=times, dtype=np.int64)\n    zenith_bin[(zenith >= 0) & (zenith < 25)] = 1\n    zenith_bin[(zenith >= 25) & (zenith < 40)] = 2\n    zenith_bin[(zenith >= 40) & (zenith < 55)] = 3\n    zenith_bin[(zenith >= 55) & (zenith < 70)] = 4\n    zenith_bin[(zenith >= 70) & (zenith < 80)] = 5\n    zenith_bin[(zenith >= 80)] = 6\n\n    # Create the bins for w based on dew point temperature\n    w_bin = pd.Series(0, index=times, dtype=np.int64)\n    w_bin[(w >= 0) & (w < 1)] = 1\n    w_bin[(w >= 1) & (w < 2)] = 2\n    w_bin[(w >= 2) & (w < 3)] = 3\n    w_bin[(w >= 3)] = 4\n    w_bin[(w == -1)] = 5\n\n    # Create delta_kt_prime binning.\n    delta_kt_prime_bin = pd.Series(0, index=times, dtype=np.int64)\n    delta_kt_prime_bin[(delta_kt_prime >= 0) & (delta_kt_prime < 0.015)] = 1\n    delta_kt_prime_bin[(delta_kt_prime >= 0.015) &\n                       (delta_kt_prime < 0.035)] = 2\n    delta_kt_prime_bin[(delta_kt_prime >= 0.035) & (delta_kt_prime < 0.07)] = 3\n    delta_kt_prime_bin[(delta_kt_prime >= 0.07) & (delta_kt_prime < 0.15)] = 4\n    delta_kt_prime_bin[(delta_kt_prime >= 0.15) & (delta_kt_prime < 0.3)] = 5\n    delta_kt_prime_bin[(delta_kt_prime >= 0.3) & (delta_kt_prime <= 1)] = 6\n    delta_kt_prime_bin[delta_kt_prime == -1] = 7\n\n    return kt_prime_bin, zenith_bin, w_bin, delta_kt_prime_bin\n\n\ndef dirindex(ghi, ghi_clearsky, dni_clearsky, zenith, times, pressure=101325.,\n             use_delta_kt_prime=True, temp_dew=None, min_cos_zenith=0.065,\n             max_zenith=87):\n    \"\"\"\n    Determine DNI from GHI using the DIRINDEX model.\n\n    The DIRINDEX model [1] modifies the DIRINT model implemented in\n    :py:func:``pvlib.irradiance.dirint`` by taking into account information\n    from a clear sky model. It is recommended that ``ghi_clearsky`` be\n    calculated using the Ineichen clear sky model\n    :py:func:``pvlib.clearsky.ineichen`` with ``perez_enhancement=True``.\n\n    The pvlib implementation limits the clearness index to 1.\n\n    Parameters\n    ----------\n    ghi : array-like\n        Global horizontal irradiance in W/m^2.\n\n    ghi_clearsky : array-like\n        Global horizontal irradiance from clear sky model, in W/m^2.\n\n    dni_clearsky : array-like\n        Direct normal irradiance from clear sky model, in W/m^2.\n\n    zenith : array-like\n        True (not refraction-corrected) zenith angles in decimal\n        degrees. If Z is a vector it must be of the same size as all\n        other vector inputs. Z must be >=0 and <=180.\n\n    times : DatetimeIndex\n\n    pressure : float or array-like, default 101325.0\n        The site pressure in Pascal. Pressure may be measured or an\n        average pressure may be calculated from site altitude.\n\n    use_delta_kt_prime : bool, default True\n        If True, indicates that the stability index delta_kt_prime is\n        included in the model. The stability index adjusts the estimated\n        DNI in response to dynamics in the time series of GHI. It is\n        recommended that delta_kt_prime is not used if the time between\n        GHI points is 1.5 hours or greater. If use_delta_kt_prime=True,\n        input data must be Series.\n\n    temp_dew : None, float, or array-like, default None\n        Surface dew point temperatures, in degrees C. Values of temp_dew\n        may be numeric or NaN. Any single time period point with a\n        temp_dew=NaN does not have dew point improvements applied. If\n        temp_dew is not provided, then dew point improvements are not\n        applied.\n\n    min_cos_zenith : numeric, default 0.065\n        Minimum value of cos(zenith) to allow when calculating global\n        clearness index `kt`. Equivalent to zenith = 86.273 degrees.\n\n    max_zenith : numeric, default 87\n        Maximum value of zenith to allow in DNI calculation. DNI will be\n        set to 0 for times with zenith values greater than `max_zenith`.\n\n    Returns\n    -------\n    dni : array-like\n        The modeled direct normal irradiance in W/m^2.\n\n    Notes\n    -----\n    DIRINDEX model requires time series data (ie. one of the inputs must\n    be a vector of length > 2).\n\n    References\n    ----------\n    .. [1] Perez, R., Ineichen, P., Moore, K., Kmiecik, M., Chain, C., George,\n       R., & Vignola, F. (2002). A new operational model for satellite-derived\n       irradiances: description and validation. Solar Energy, 73(5), 307-317.\n    \"\"\"\n\n    dni_dirint = dirint(ghi, zenith, times, pressure=pressure,\n                        use_delta_kt_prime=use_delta_kt_prime,\n                        temp_dew=temp_dew, min_cos_zenith=min_cos_zenith,\n                        max_zenith=max_zenith)\n\n    dni_dirint_clearsky = dirint(ghi_clearsky, zenith, times,\n                                 pressure=pressure,\n                                 use_delta_kt_prime=use_delta_kt_prime,\n                                 temp_dew=temp_dew,\n                                 min_cos_zenith=min_cos_zenith,\n                                 max_zenith=max_zenith)\n\n    dni_dirindex = dni_clearsky * dni_dirint / dni_dirint_clearsky\n\n    dni_dirindex[dni_dirindex < 0] = 0.\n\n    return dni_dirindex\n\n\ndef gti_dirint(poa_global, aoi, solar_zenith, solar_azimuth, times,\n               surface_tilt, surface_azimuth, pressure=101325.,\n               use_delta_kt_prime=True, temp_dew=None, albedo=.25,\n               model='perez', model_perez='allsitescomposite1990',\n               calculate_gt_90=True, max_iterations=30):\n    \"\"\"\n    Determine GHI, DNI, DHI from POA global using the GTI DIRINT model.\n\n    The GTI DIRINT model is described in [1]_.\n\n    .. warning::\n\n        Model performance is poor for AOI greater than approximately\n        80 degrees `and` plane of array irradiance greater than\n        approximately 200 W/m^2.\n\n    Parameters\n    ----------\n    poa_global : array-like\n        Plane of array global irradiance in W/m^2.\n\n    aoi : array-like\n        Angle of incidence of solar rays with respect to the module\n        surface normal.\n\n    solar_zenith : array-like\n        True (not refraction-corrected) solar zenith angles in decimal\n        degrees.\n\n    solar_azimuth : array-like\n        Solar azimuth angles in decimal degrees.\n\n    times : DatetimeIndex\n        Time indices for the input array-like data.\n\n    surface_tilt : numeric\n        Surface tilt angles in decimal degrees. Tilt must be >=0 and\n        <=180. The tilt angle is defined as degrees from horizontal\n        (e.g. surface facing up = 0, surface facing horizon = 90).\n\n    surface_azimuth : numeric\n        Surface azimuth angles in decimal degrees. surface_azimuth must\n        be >=0 and <=360. The Azimuth convention is defined as degrees\n        east of north (e.g. North = 0, South=180 East = 90, West = 270).\n\n    pressure : numeric, default 101325.0\n        The site pressure in Pascal. Pressure may be measured or an\n        average pressure may be calculated from site altitude.\n\n    use_delta_kt_prime : bool, default True\n        If True, indicates that the stability index delta_kt_prime is\n        included in the model. The stability index adjusts the estimated\n        DNI in response to dynamics in the time series of GHI. It is\n        recommended that delta_kt_prime is not used if the time between\n        GHI points is 1.5 hours or greater. If use_delta_kt_prime=True,\n        input data must be Series.\n\n    temp_dew : None, float, or array-like, default None\n        Surface dew point temperatures, in degrees C. Values of temp_dew\n        may be numeric or NaN. Any single time period point with a\n        temp_dew=NaN does not have dew point improvements applied. If\n        temp_dew is not provided, then dew point improvements are not\n        applied.\n\n    albedo : numeric, default 0.25\n        Surface albedo\n\n    model : String, default 'isotropic'\n        Irradiance model.\n\n    model_perez : String, default 'allsitescomposite1990'\n        Used only if model='perez'. See :py:func:`perez`.\n\n    calculate_gt_90 : bool, default True\n        Controls if the algorithm evaluates inputs with AOI >= 90 degrees.\n        If False, returns nan for AOI >= 90 degrees. Significant speed ups\n        can be achieved by setting this parameter to False.\n\n    max_iterations : int, default 30\n        Maximum number of iterations for the aoi < 90 deg algorithm.\n\n    Returns\n    -------\n    data : OrderedDict or DataFrame\n        Contains the following keys/columns:\n\n            * ``ghi``: the modeled global horizontal irradiance in W/m^2.\n            * ``dni``: the modeled direct normal irradiance in W/m^2.\n            * ``dhi``: the modeled diffuse horizontal irradiance in\n              W/m^2.\n\n    References\n    ----------\n    .. [1] B. Marion, A model for deriving the direct normal and\n           diffuse horizontal irradiance from the global tilted\n           irradiance, Solar Energy 122, 1037-1046.\n           :doi:`10.1016/j.solener.2015.10.024`\n    \"\"\"\n\n    aoi_lt_90 = aoi < 90\n\n    # for AOI less than 90 degrees\n    ghi, dni, dhi, kt_prime = _gti_dirint_lt_90(\n        poa_global, aoi, aoi_lt_90, solar_zenith, solar_azimuth, times,\n        surface_tilt, surface_azimuth, pressure=pressure,\n        use_delta_kt_prime=use_delta_kt_prime, temp_dew=temp_dew,\n        albedo=albedo, model=model, model_perez=model_perez,\n        max_iterations=max_iterations)\n\n    # for AOI greater than or equal to 90 degrees\n    if calculate_gt_90:\n        ghi_gte_90, dni_gte_90, dhi_gte_90 = _gti_dirint_gte_90(\n            poa_global, aoi, solar_zenith, solar_azimuth,\n            surface_tilt, times, kt_prime,\n            pressure=pressure, temp_dew=temp_dew, albedo=albedo)\n    else:\n        ghi_gte_90, dni_gte_90, dhi_gte_90 = np.nan, np.nan, np.nan\n\n    # put the AOI < 90 and AOI >= 90 conditions together\n    output = OrderedDict()\n    output['ghi'] = ghi.where(aoi_lt_90, ghi_gte_90)\n    output['dni'] = dni.where(aoi_lt_90, dni_gte_90)\n    output['dhi'] = dhi.where(aoi_lt_90, dhi_gte_90)\n\n    output = pd.DataFrame(output, index=times)\n\n    return output\n\n\ndef _gti_dirint_lt_90(poa_global, aoi, aoi_lt_90, solar_zenith, solar_azimuth,\n                      times, surface_tilt, surface_azimuth, pressure=101325.,\n                      use_delta_kt_prime=True, temp_dew=None, albedo=.25,\n                      model='perez', model_perez='allsitescomposite1990',\n                      max_iterations=30):\n    \"\"\"\n    GTI-DIRINT model for AOI < 90 degrees. See Marion 2015 Section 2.1.\n\n    See gti_dirint signature for parameter details.\n    \"\"\"\n    I0 = get_extra_radiation(times, 1370, 'spencer')\n    cos_zenith = tools.cosd(solar_zenith)\n    # I0h as in Marion 2015 eqns 1, 3\n    I0h = I0 * np.maximum(0.065, cos_zenith)\n\n    airmass = atmosphere.get_relative_airmass(solar_zenith, model='kasten1966')\n    airmass = atmosphere.get_absolute_airmass(airmass, pressure)\n\n    # these coeffs and diff variables and the loop below\n    # implement figure 1 of Marion 2015\n\n    # make coeffs that is at least 30 elements long so that all\n    # coeffs can be assigned as specified in Marion 2015.\n    # slice below will limit iterations if necessary\n    coeffs = np.empty(max(30, max_iterations))\n    coeffs[0:3] = 1\n    coeffs[3:10] = 0.5\n    coeffs[10:20] = 0.25\n    coeffs[20:] = 0.125\n    coeffs = coeffs[:max_iterations]  # covers case where max_iterations < 30\n\n    # initialize diff\n    diff = pd.Series(9999, index=times)\n    best_diff = diff\n\n    # initialize poa_global_i\n    poa_global_i = poa_global\n\n    for iteration, coeff in enumerate(coeffs):\n\n        # test if difference between modeled GTI and\n        # measured GTI (poa_global) is less than 1 W/m^2\n        # only test for aoi less than 90 deg\n        best_diff_lte_1 = best_diff <= 1\n        best_diff_lte_1_lt_90 = best_diff_lte_1[aoi_lt_90]\n        if best_diff_lte_1_lt_90.all():\n            # all aoi < 90 points have a difference <= 1, so break loop\n            break\n\n        # calculate kt and DNI from GTI\n        kt = clearness_index(poa_global_i, aoi, I0)  # kt from Marion eqn 2\n        disc_dni = np.maximum(_disc_kn(kt, airmass)[0] * I0, 0)\n        kt_prime = clearness_index_zenith_independent(kt, airmass)\n        # dirint DNI in Marion eqn 3\n        dni = _dirint_from_dni_ktprime(disc_dni, kt_prime, solar_zenith,\n                                       use_delta_kt_prime, temp_dew)\n\n        # calculate DHI using Marion eqn 3 (identify 1st term on RHS as GHI)\n        # I0h has a minimum zenith projection, but multiplier of DNI does not\n        ghi = kt * I0h                  # Kt * I0 * max(0.065, cos(zen))\n        dhi = ghi - dni * cos_zenith    # no cos(zen) restriction here\n\n        # following SSC code\n        dni = np.maximum(dni, 0)\n        ghi = np.maximum(ghi, 0)\n        dhi = np.maximum(dhi, 0)\n\n        # use DNI and DHI to model GTI\n        # GTI-DIRINT uses perez transposition model, but we allow for\n        # any model here\n        all_irrad = get_total_irradiance(\n            surface_tilt, surface_azimuth, solar_zenith, solar_azimuth,\n            dni, ghi, dhi, dni_extra=I0, airmass=airmass,\n            albedo=albedo, model=model, model_perez=model_perez)\n\n        gti_model = all_irrad['poa_global']\n\n        # calculate new diff\n        diff = gti_model - poa_global\n\n        # determine if the new diff is smaller in magnitude\n        # than the old diff\n        diff_abs = diff.abs()\n        smallest_diff = diff_abs < best_diff\n\n        # save the best differences\n        best_diff = diff_abs.where(smallest_diff, best_diff)\n\n        # on first iteration, the best values are the only values\n        if iteration == 0:\n            best_ghi = ghi\n            best_dni = dni\n            best_dhi = dhi\n            best_kt_prime = kt_prime\n        else:\n            # save new DNI, DHI, DHI if they provide the best consistency\n            # otherwise use the older values.\n            best_ghi = ghi.where(smallest_diff, best_ghi)\n            best_dni = dni.where(smallest_diff, best_dni)\n            best_dhi = dhi.where(smallest_diff, best_dhi)\n            best_kt_prime = kt_prime.where(smallest_diff, best_kt_prime)\n\n        # calculate adjusted inputs for next iteration. Marion eqn 4\n        poa_global_i = np.maximum(1.0, poa_global_i - coeff * diff)\n    else:\n        # we are here because we ran out of coeffs to loop over and\n        # therefore we have exceeded max_iterations\n        import warnings\n        failed_points = best_diff[aoi_lt_90][~best_diff_lte_1_lt_90]\n        warnings.warn(\n            ('%s points failed to converge after %s iterations. best_diff:\\n%s'\n             % (len(failed_points), max_iterations, failed_points)),\n            RuntimeWarning)\n\n    # return the best data, whether or not the solution converged\n    return best_ghi, best_dni, best_dhi, best_kt_prime\n\n\ndef _gti_dirint_gte_90(poa_global, aoi, solar_zenith, solar_azimuth,\n                       surface_tilt, times, kt_prime,\n                       pressure=101325., temp_dew=None, albedo=.25):\n    \"\"\"\n    GTI-DIRINT model for AOI >= 90 degrees. See Marion 2015 Section 2.2.\n\n    See gti_dirint signature for parameter details.\n    \"\"\"\n    kt_prime_gte_90 = _gti_dirint_gte_90_kt_prime(aoi, solar_zenith,\n                                                  solar_azimuth, times,\n                                                  kt_prime)\n\n    I0 = get_extra_radiation(times, 1370, 'spencer')\n    airmass = atmosphere.get_relative_airmass(solar_zenith, model='kasten1966')\n    airmass = atmosphere.get_absolute_airmass(airmass, pressure)\n    kt = kt_prime_gte_90 * _kt_kt_prime_factor(airmass)\n    disc_dni = np.maximum(_disc_kn(kt, airmass)[0] * I0, 0)\n\n    dni_gte_90 = _dirint_from_dni_ktprime(disc_dni, kt_prime, solar_zenith,\n                                          False, temp_dew)\n\n    dni_gte_90_proj = dni_gte_90 * tools.cosd(solar_zenith)\n    cos_surface_tilt = tools.cosd(surface_tilt)\n\n    # isotropic sky plus ground diffuse\n    dhi_gte_90 = (\n        (2 * poa_global - dni_gte_90_proj * albedo * (1 - cos_surface_tilt)) /\n        (1 + cos_surface_tilt + albedo * (1 - cos_surface_tilt)))\n\n    ghi_gte_90 = dni_gte_90_proj + dhi_gte_90\n\n    return ghi_gte_90, dni_gte_90, dhi_gte_90\n\n\ndef _gti_dirint_gte_90_kt_prime(aoi, solar_zenith, solar_azimuth, times,\n                                kt_prime):\n    \"\"\"\n    Determine kt' values to be used in GTI-DIRINT AOI >= 90 deg case.\n    See Marion 2015 Section 2.2.\n\n    For AOI >= 90 deg: average of the kt_prime values for 65 < AOI < 80\n    in each day's morning and afternoon. Morning and afternoon are treated\n    separately.\n\n    For AOI < 90 deg: NaN.\n\n    See gti_dirint signature for parameter details.\n\n    Returns\n    -------\n    kt_prime_gte_90 : Series\n        Index is `times`.\n    \"\"\"\n    # kt_prime values from DIRINT calculation for AOI < 90 case\n    # set the kt_prime from sunrise to AOI=90 to be equal to\n    # the kt_prime for 65 < AOI < 80 during the morning.\n    # similar for the afternoon. repeat for every day.\n    aoi_gte_90 = aoi >= 90\n    aoi_65_80 = (aoi > 65) & (aoi < 80)\n    zenith_lt_90 = solar_zenith < 90\n    morning = solar_azimuth < 180\n    afternoon = solar_azimuth > 180\n    aoi_65_80_morning = aoi_65_80 & morning\n    aoi_65_80_afternoon = aoi_65_80 & afternoon\n    zenith_lt_90_aoi_gte_90_morning = zenith_lt_90 & aoi_gte_90 & morning\n    zenith_lt_90_aoi_gte_90_afternoon = zenith_lt_90 & aoi_gte_90 & afternoon\n\n    kt_prime_gte_90 = []\n    for date, data in kt_prime.groupby(times.date):\n        kt_prime_am_avg = data[aoi_65_80_morning].mean()\n        kt_prime_pm_avg = data[aoi_65_80_afternoon].mean()\n\n        kt_prime_by_date = pd.Series(np.nan, index=data.index)\n        kt_prime_by_date[zenith_lt_90_aoi_gte_90_morning] = kt_prime_am_avg\n        kt_prime_by_date[zenith_lt_90_aoi_gte_90_afternoon] = kt_prime_pm_avg\n        kt_prime_gte_90.append(kt_prime_by_date)\n    kt_prime_gte_90 = pd.concat(kt_prime_gte_90)\n\n    return kt_prime_gte_90\n\n\ndef erbs(ghi, zenith, datetime_or_doy, min_cos_zenith=0.065, max_zenith=87):\n    r\"\"\"\n    Estimate DNI and DHI from GHI using the Erbs model.\n\n    The Erbs model [1]_ estimates the diffuse fraction DF from global\n    horizontal irradiance through an empirical relationship between DF\n    and the ratio of GHI to extraterrestrial irradiance, Kt. The\n    function uses the diffuse fraction to compute DHI as\n\n    .. math::\n\n        DHI = DF \\times GHI\n\n    DNI is then estimated as\n\n    .. math::\n\n        DNI = (GHI - DHI)/\\cos(Z)\n\n    where Z is the zenith angle.\n\n    Parameters\n    ----------\n    ghi: numeric\n        Global horizontal irradiance in W/m^2.\n    zenith: numeric\n        True (not refraction-corrected) zenith angles in decimal degrees.\n    datetime_or_doy : int, float, array, pd.DatetimeIndex\n        Day of year or array of days of year e.g.\n        pd.DatetimeIndex.dayofyear, or pd.DatetimeIndex.\n    min_cos_zenith : numeric, default 0.065\n        Minimum value of cos(zenith) to allow when calculating global\n        clearness index `kt`. Equivalent to zenith = 86.273 degrees.\n    max_zenith : numeric, default 87\n        Maximum value of zenith to allow in DNI calculation. DNI will be\n        set to 0 for times with zenith values greater than `max_zenith`.\n\n    Returns\n    -------\n    data : OrderedDict or DataFrame\n        Contains the following keys/columns:\n\n            * ``dni``: the modeled direct normal irradiance in W/m^2.\n            * ``dhi``: the modeled diffuse horizontal irradiance in\n              W/m^2.\n            * ``kt``: Ratio of global to extraterrestrial irradiance\n              on a horizontal plane.\n\n    References\n    ----------\n    .. [1] D. G. Erbs, S. A. Klein and J. A. Duffie, Estimation of the\n       diffuse radiation fraction for hourly, daily and monthly-average\n       global radiation, Solar Energy 28(4), pp 293-302, 1982. Eq. 1\n\n    See also\n    --------\n    dirint\n    disc\n    \"\"\"\n\n    dni_extra = get_extra_radiation(datetime_or_doy)\n\n    kt = clearness_index(ghi, zenith, dni_extra, min_cos_zenith=min_cos_zenith,\n                         max_clearness_index=1)\n\n    # For Kt <= 0.22, set the diffuse fraction\n    df = 1 - 0.09*kt\n\n    # For Kt > 0.22 and Kt <= 0.8, set the diffuse fraction\n    df = np.where((kt > 0.22) & (kt <= 0.8),\n                  0.9511 - 0.1604*kt + 4.388*kt**2 -\n                  16.638*kt**3 + 12.336*kt**4,\n                  df)\n\n    # For Kt > 0.8, set the diffuse fraction\n    df = np.where(kt > 0.8, 0.165, df)\n\n    dhi = df * ghi\n\n    dni = (ghi - dhi) / tools.cosd(zenith)\n    bad_values = (zenith > max_zenith) | (ghi < 0) | (dni < 0)\n    dni = np.where(bad_values, 0, dni)\n    # ensure that closure relationship remains valid\n    dhi = np.where(bad_values, ghi, dhi)\n\n    data = OrderedDict()\n    data['dni'] = dni\n    data['dhi'] = dhi\n    data['kt'] = kt\n\n    if isinstance(datetime_or_doy, pd.DatetimeIndex):\n        data = pd.DataFrame(data, index=datetime_or_doy)\n\n    return data\n\n\ndef campbell_norman(zenith, transmittance, pressure=101325.0,\n                    dni_extra=1367.0):\n    '''\n    Determine DNI, DHI, GHI from extraterrestrial flux, transmittance,\n    and atmospheric pressure.\n\n    Parameters\n    ----------\n    zenith: pd.Series\n        True (not refraction-corrected) zenith angles in decimal\n        degrees. If Z is a vector it must be of the same size as all\n        other vector inputs. Z must be >=0 and <=180.\n\n    transmittance: float\n        Atmospheric transmittance between 0 and 1.\n\n    pressure: float, default 101325.0\n        Air pressure\n\n    dni_extra: float, default 1367.0\n        Direct irradiance incident at the top of the atmosphere.\n\n    Returns\n    -------\n    irradiance: DataFrame\n        Modeled direct normal irradiance, direct horizontal irradiance,\n        and global horizontal irradiance in W/m^2\n\n    References\n    ----------\n    .. [1] Campbell, G. S., J. M. Norman (1998) An Introduction to\n       Environmental Biophysics. 2nd Ed. New York: Springer.\n    '''\n\n    tau = transmittance\n\n    airmass = atmosphere.get_relative_airmass(zenith, model='simple')\n    airmass = atmosphere.get_absolute_airmass(airmass, pressure=pressure)\n    dni = dni_extra*tau**airmass\n    cos_zen = tools.cosd(zenith)\n    dhi = 0.3 * (1.0 - tau**airmass) * dni_extra * cos_zen\n    ghi = dhi + dni * cos_zen\n\n    irrads = OrderedDict()\n    irrads['ghi'] = ghi\n    irrads['dni'] = dni\n    irrads['dhi'] = dhi\n\n    if isinstance(ghi, pd.Series):\n        irrads = pd.DataFrame(irrads)\n\n    return irrads\n\n\ndef _liujordan(zenith, transmittance, airmass, dni_extra=1367.0):\n    '''\n    Determine DNI, DHI, GHI from extraterrestrial flux, transmittance,\n    and optical air mass number.\n\n    Liu and Jordan, 1960, developed a simplified direct radiation model.\n    DHI is from an empirical equation for diffuse radiation from Liu and\n    Jordan, 1960.\n\n    Parameters\n    ----------\n    zenith: pd.Series\n        True (not refraction-corrected) zenith angles in decimal\n        degrees. If Z is a vector it must be of the same size as all\n        other vector inputs. Z must be >=0 and <=180.\n\n    transmittance: float\n        Atmospheric transmittance between 0 and 1.\n\n    pressure: float, default 101325.0\n        Air pressure\n\n    dni_extra: float, default 1367.0\n        Direct irradiance incident at the top of the atmosphere.\n\n    Returns\n    -------\n    irradiance: DataFrame\n        Modeled direct normal irradiance, direct horizontal irradiance,\n        and global horizontal irradiance in W/m^2\n\n    References\n    ----------\n    .. [1] Campbell, G. S., J. M. Norman (1998) An Introduction to\n       Environmental Biophysics. 2nd Ed. New York: Springer.\n\n    .. [2] Liu, B. Y., R. C. Jordan, (1960). \"The interrelationship and\n       characteristic distribution of direct, diffuse, and total solar\n       radiation\".  Solar Energy 4:1-19\n    '''\n\n    tau = transmittance\n\n    dni = dni_extra*tau**airmass\n    dhi = 0.3 * (1.0 - tau**airmass) * dni_extra * np.cos(np.radians(zenith))\n    ghi = dhi + dni * np.cos(np.radians(zenith))\n\n    irrads = OrderedDict()\n    irrads['ghi'] = ghi\n    irrads['dni'] = dni\n    irrads['dhi'] = dhi\n\n    if isinstance(ghi, pd.Series):\n        irrads = pd.DataFrame(irrads)\n\n    return irrads\n\n\ndef _get_perez_coefficients(perezmodel):\n    '''\n    Find coefficients for the Perez model\n\n    Parameters\n    ----------\n\n    perezmodel : string (optional, default='allsitescomposite1990')\n\n          a character string which selects the desired set of Perez\n          coefficients. If model is not provided as an input, the default,\n          '1990' will be used.\n\n    All possible model selections are:\n\n          * '1990'\n          * 'allsitescomposite1990' (same as '1990')\n          * 'allsitescomposite1988'\n          * 'sandiacomposite1988'\n          * 'usacomposite1988'\n          * 'france1988'\n          * 'phoenix1988'\n          * 'elmonte1988'\n          * 'osage1988'\n          * 'albuquerque1988'\n          * 'capecanaveral1988'\n          * 'albany1988'\n\n    Returns\n    --------\n    F1coeffs, F2coeffs : (array, array)\n          F1 and F2 coefficients for the Perez model\n\n    References\n    ----------\n    .. [1] Loutzenhiser P.G. et. al. \"Empirical validation of models to\n       compute solar irradiance on inclined surfaces for building energy\n       simulation\" 2007, Solar Energy vol. 81. pp. 254-267\n\n    .. [2] Perez, R., Seals, R., Ineichen, P., Stewart, R., Menicucci, D.,\n       1987. A new simplified version of the Perez diffuse irradiance model\n       for tilted surfaces. Solar Energy 39(3), 221-232.\n\n    .. [3] Perez, R., Ineichen, P., Seals, R., Michalsky, J., Stewart, R.,\n       1990. Modeling daylight availability and irradiance components from\n       direct and global irradiance. Solar Energy 44 (5), 271-289.\n\n    .. [4] Perez, R. et. al 1988. \"The Development and Verification of the\n       Perez Diffuse Radiation Model\". SAND88-7030\n\n    '''\n    coeffdict = {\n        'allsitescomposite1990': [\n            [-0.0080,    0.5880,   -0.0620,   -0.0600,    0.0720,   -0.0220],\n            [0.1300,    0.6830,   -0.1510,   -0.0190,    0.0660,   -0.0290],\n            [0.3300,    0.4870,   -0.2210,    0.0550,   -0.0640,   -0.0260],\n            [0.5680,    0.1870,   -0.2950,    0.1090,   -0.1520,   -0.0140],\n            [0.8730,   -0.3920,   -0.3620,    0.2260,   -0.4620,    0.0010],\n            [1.1320,   -1.2370,   -0.4120,    0.2880,   -0.8230,    0.0560],\n            [1.0600,   -1.6000,   -0.3590,    0.2640,   -1.1270,    0.1310],\n            [0.6780,   -0.3270,   -0.2500,    0.1560,   -1.3770,    0.2510]],\n        'allsitescomposite1988': [\n            [-0.0180,    0.7050,   -0.071,   -0.0580,    0.1020,   -0.0260],\n            [0.1910,    0.6450,   -0.1710,    0.0120,    0.0090,   -0.0270],\n            [0.4400,    0.3780,   -0.2560,    0.0870,   -0.1040,   -0.0250],\n            [0.7560,   -0.1210,   -0.3460,    0.1790,   -0.3210,   -0.0080],\n            [0.9960,   -0.6450,   -0.4050,    0.2600,   -0.5900,    0.0170],\n            [1.0980,   -1.2900,   -0.3930,    0.2690,   -0.8320,    0.0750],\n            [0.9730,   -1.1350,   -0.3780,    0.1240,   -0.2580,    0.1490],\n            [0.6890,   -0.4120,   -0.2730,    0.1990,   -1.6750,    0.2370]],\n        'sandiacomposite1988': [\n            [-0.1960,    1.0840,   -0.0060,   -0.1140,    0.1800,   -0.0190],\n            [0.2360,    0.5190,   -0.1800,   -0.0110,    0.0200,   -0.0380],\n            [0.4540,    0.3210,   -0.2550,    0.0720,   -0.0980,   -0.0460],\n            [0.8660,   -0.3810,   -0.3750,    0.2030,   -0.4030,   -0.0490],\n            [1.0260,   -0.7110,   -0.4260,    0.2730,   -0.6020,   -0.0610],\n            [0.9780,   -0.9860,   -0.3500,    0.2800,   -0.9150,   -0.0240],\n            [0.7480,   -0.9130,   -0.2360,    0.1730,   -1.0450,    0.0650],\n            [0.3180,   -0.7570,    0.1030,    0.0620,   -1.6980,    0.2360]],\n        'usacomposite1988': [\n            [-0.0340,    0.6710,   -0.0590,   -0.0590,    0.0860,   -0.0280],\n            [0.2550,    0.4740,   -0.1910,    0.0180,   -0.0140,   -0.0330],\n            [0.4270,    0.3490,   -0.2450,    0.0930,   -0.1210,   -0.0390],\n            [0.7560,   -0.2130,   -0.3280,    0.1750,   -0.3040,   -0.0270],\n            [1.0200,   -0.8570,   -0.3850,    0.2800,   -0.6380,   -0.0190],\n            [1.0500,   -1.3440,   -0.3480,    0.2800,   -0.8930,    0.0370],\n            [0.9740,   -1.5070,   -0.3700,    0.1540,   -0.5680,    0.1090],\n            [0.7440,   -1.8170,   -0.2560,    0.2460,   -2.6180,    0.2300]],\n        'france1988': [\n            [0.0130,    0.7640,   -0.1000,   -0.0580,    0.1270,   -0.0230],\n            [0.0950,    0.9200,   -0.1520,         0,    0.0510,   -0.0200],\n            [0.4640,    0.4210,   -0.2800,    0.0640,   -0.0510,   -0.0020],\n            [0.7590,   -0.0090,   -0.3730,    0.2010,   -0.3820,    0.0100],\n            [0.9760,   -0.4000,   -0.4360,    0.2710,   -0.6380,    0.0510],\n            [1.1760,   -1.2540,   -0.4620,    0.2950,   -0.9750,    0.1290],\n            [1.1060,   -1.5630,   -0.3980,    0.3010,   -1.4420,    0.2120],\n            [0.9340,   -1.5010,   -0.2710,    0.4200,   -2.9170,    0.2490]],\n        'phoenix1988': [\n            [-0.0030,    0.7280,   -0.0970,   -0.0750,    0.1420,   -0.0430],\n            [0.2790,    0.3540,   -0.1760,    0.0300,   -0.0550,   -0.0540],\n            [0.4690,    0.1680,   -0.2460,    0.0480,   -0.0420,   -0.0570],\n            [0.8560,   -0.5190,   -0.3400,    0.1760,   -0.3800,   -0.0310],\n            [0.9410,   -0.6250,   -0.3910,    0.1880,   -0.3600,   -0.0490],\n            [1.0560,   -1.1340,   -0.4100,    0.2810,   -0.7940,   -0.0650],\n            [0.9010,   -2.1390,   -0.2690,    0.1180,   -0.6650,    0.0460],\n            [0.1070,    0.4810,    0.1430,   -0.1110,   -0.1370,    0.2340]],\n        'elmonte1988': [\n            [0.0270,    0.7010,   -0.1190,   -0.0580,    0.1070,  -0.0600],\n            [0.1810,    0.6710,   -0.1780,   -0.0790,    0.1940,  -0.0350],\n            [0.4760,    0.4070,   -0.2880,    0.0540,   -0.0320,  -0.0550],\n            [0.8750,   -0.2180,   -0.4030,    0.1870,   -0.3090,  -0.0610],\n            [1.1660,   -1.0140,   -0.4540,    0.2110,   -0.4100,  -0.0440],\n            [1.1430,   -2.0640,   -0.2910,    0.0970,   -0.3190,   0.0530],\n            [1.0940,   -2.6320,   -0.2590,    0.0290,   -0.4220,   0.1470],\n            [0.1550,    1.7230,    0.1630,   -0.1310,   -0.0190,   0.2770]],\n        'osage1988': [\n            [-0.3530,    1.4740,   0.0570,   -0.1750,    0.3120,   0.0090],\n            [0.3630,    0.2180,  -0.2120,    0.0190,   -0.0340,  -0.0590],\n            [-0.0310,    1.2620,  -0.0840,   -0.0820,    0.2310,  -0.0170],\n            [0.6910,    0.0390,  -0.2950,    0.0910,   -0.1310,  -0.0350],\n            [1.1820,   -1.3500,  -0.3210,    0.4080,   -0.9850,  -0.0880],\n            [0.7640,    0.0190,  -0.2030,    0.2170,   -0.2940,  -0.1030],\n            [0.2190,    1.4120,   0.2440,    0.4710,   -2.9880,   0.0340],\n            [3.5780,   22.2310, -10.7450,    2.4260,    4.8920,  -5.6870]],\n        'albuquerque1988': [\n            [0.0340,    0.5010,  -0.0940,   -0.0630,    0.1060,  -0.0440],\n            [0.2290,    0.4670,  -0.1560,   -0.0050,   -0.0190,  -0.0230],\n            [0.4860,    0.2410,  -0.2530,    0.0530,   -0.0640,  -0.0220],\n            [0.8740,   -0.3930,  -0.3970,    0.1810,   -0.3270,  -0.0370],\n            [1.1930,   -1.2960,  -0.5010,    0.2810,   -0.6560,  -0.0450],\n            [1.0560,   -1.7580,  -0.3740,    0.2260,   -0.7590,   0.0340],\n            [0.9010,   -4.7830,  -0.1090,    0.0630,   -0.9700,   0.1960],\n            [0.8510,   -7.0550,  -0.0530,    0.0600,   -2.8330,   0.3300]],\n        'capecanaveral1988': [\n            [0.0750,    0.5330,   -0.1240,  -0.0670,   0.0420,  -0.0200],\n            [0.2950,    0.4970,   -0.2180,  -0.0080,   0.0030,  -0.0290],\n            [0.5140,    0.0810,   -0.2610,   0.0750,  -0.1600,  -0.0290],\n            [0.7470,   -0.3290,   -0.3250,   0.1810,  -0.4160,  -0.0300],\n            [0.9010,   -0.8830,   -0.2970,   0.1780,  -0.4890,   0.0080],\n            [0.5910,   -0.0440,   -0.1160,   0.2350,  -0.9990,   0.0980],\n            [0.5370,   -2.4020,    0.3200,   0.1690,  -1.9710,   0.3100],\n            [-0.8050,    4.5460,    1.0720,  -0.2580,  -0.9500,    0.7530]],\n        'albany1988': [\n            [0.0120,    0.5540,   -0.0760, -0.0520,   0.0840,  -0.0290],\n            [0.2670,    0.4370,   -0.1940,  0.0160,   0.0220,  -0.0360],\n            [0.4200,    0.3360,   -0.2370,  0.0740,  -0.0520,  -0.0320],\n            [0.6380,   -0.0010,   -0.2810,  0.1380,  -0.1890,  -0.0120],\n            [1.0190,   -1.0270,   -0.3420,  0.2710,  -0.6280,   0.0140],\n            [1.1490,   -1.9400,   -0.3310,  0.3220,  -1.0970,   0.0800],\n            [1.4340,   -3.9940,   -0.4920,  0.4530,  -2.3760,   0.1170],\n            [1.0070,   -2.2920,   -0.4820,  0.3900,  -3.3680,   0.2290]], }\n\n    array = np.array(coeffdict[perezmodel])\n\n    F1coeffs = array[:, 0:3]\n    F2coeffs = array[:, 3:7]\n\n    return F1coeffs, F2coeffs\n\n\ndef _get_dirint_coeffs():\n    \"\"\"\n    A place to stash the dirint coefficients.\n\n    Returns\n    -------\n    np.array with shape ``(6, 6, 7, 5)``.\n    Ordering is ``[kt_prime_bin, zenith_bin, delta_kt_prime_bin, w_bin]``\n    \"\"\"\n\n    # To allow for maximum copy/paste from the MATLAB 1-indexed code,\n    # we create and assign values to an oversized array.\n    # Then, we return the [1:, 1:, :, :] slice.\n\n    coeffs = np.zeros((7, 7, 7, 5))\n\n    coeffs[1, 1, :, :] = [\n        [0.385230, 0.385230, 0.385230, 0.462880, 0.317440],\n        [0.338390, 0.338390, 0.221270, 0.316730, 0.503650],\n        [0.235680, 0.235680, 0.241280, 0.157830, 0.269440],\n        [0.830130, 0.830130, 0.171970, 0.841070, 0.457370],\n        [0.548010, 0.548010, 0.478000, 0.966880, 1.036370],\n        [0.548010, 0.548010, 1.000000, 3.012370, 1.976540],\n        [0.582690, 0.582690, 0.229720, 0.892710, 0.569950]]\n\n    coeffs[1, 2, :, :] = [\n        [0.131280, 0.131280, 0.385460, 0.511070, 0.127940],\n        [0.223710, 0.223710, 0.193560, 0.304560, 0.193940],\n        [0.229970, 0.229970, 0.275020, 0.312730, 0.244610],\n        [0.090100, 0.184580, 0.260500, 0.687480, 0.579440],\n        [0.131530, 0.131530, 0.370190, 1.380350, 1.052270],\n        [1.116250, 1.116250, 0.928030, 3.525490, 2.316920],\n        [0.090100, 0.237000, 0.300040, 0.812470, 0.664970]]\n\n    coeffs[1, 3, :, :] = [\n        [0.587510, 0.130000, 0.400000, 0.537210, 0.832490],\n        [0.306210, 0.129830, 0.204460, 0.500000, 0.681640],\n        [0.224020, 0.260620, 0.334080, 0.501040, 0.350470],\n        [0.421540, 0.753970, 0.750660, 3.706840, 0.983790],\n        [0.706680, 0.373530, 1.245670, 0.864860, 1.992630],\n        [4.864400, 0.117390, 0.265180, 0.359180, 3.310820],\n        [0.392080, 0.493290, 0.651560, 1.932780, 0.898730]]\n\n    coeffs[1, 4, :, :] = [\n        [0.126970, 0.126970, 0.126970, 0.126970, 0.126970],\n        [0.810820, 0.810820, 0.810820, 0.810820, 0.810820],\n        [3.241680, 2.500000, 2.291440, 2.291440, 2.291440],\n        [4.000000, 3.000000, 2.000000, 0.975430, 1.965570],\n        [12.494170, 12.494170, 8.000000, 5.083520, 8.792390],\n        [21.744240, 21.744240, 21.744240, 21.744240, 21.744240],\n        [3.241680, 12.494170, 1.620760, 1.375250, 2.331620]]\n\n    coeffs[1, 5, :, :] = [\n        [0.126970, 0.126970, 0.126970, 0.126970, 0.126970],\n        [0.810820, 0.810820, 0.810820, 0.810820, 0.810820],\n        [3.241680, 2.500000, 2.291440, 2.291440, 2.291440],\n        [4.000000, 3.000000, 2.000000, 0.975430, 1.965570],\n        [12.494170, 12.494170, 8.000000, 5.083520, 8.792390],\n        [21.744240, 21.744240, 21.744240, 21.744240, 21.744240],\n        [3.241680, 12.494170, 1.620760, 1.375250, 2.331620]]\n\n    coeffs[1, 6, :, :] = [\n        [0.126970, 0.126970, 0.126970, 0.126970, 0.126970],\n        [0.810820, 0.810820, 0.810820, 0.810820, 0.810820],\n        [3.241680, 2.500000, 2.291440, 2.291440, 2.291440],\n        [4.000000, 3.000000, 2.000000, 0.975430, 1.965570],\n        [12.494170, 12.494170, 8.000000, 5.083520, 8.792390],\n        [21.744240, 21.744240, 21.744240, 21.744240, 21.744240],\n        [3.241680, 12.494170, 1.620760, 1.375250, 2.331620]]\n\n    coeffs[2, 1, :, :] = [\n        [0.337440, 0.337440, 0.969110, 1.097190, 1.116080],\n        [0.337440, 0.337440, 0.969110, 1.116030, 0.623900],\n        [0.337440, 0.337440, 1.530590, 1.024420, 0.908480],\n        [0.584040, 0.584040, 0.847250, 0.914940, 1.289300],\n        [0.337440, 0.337440, 0.310240, 1.435020, 1.852830],\n        [0.337440, 0.337440, 1.015010, 1.097190, 2.117230],\n        [0.337440, 0.337440, 0.969110, 1.145730, 1.476400]]\n\n    coeffs[2, 2, :, :] = [\n        [0.300000, 0.300000, 0.700000, 1.100000, 0.796940],\n        [0.219870, 0.219870, 0.526530, 0.809610, 0.649300],\n        [0.386650, 0.386650, 0.119320, 0.576120, 0.685460],\n        [0.746730, 0.399830, 0.470970, 0.986530, 0.785370],\n        [0.575420, 0.936700, 1.649200, 1.495840, 1.335590],\n        [1.319670, 4.002570, 1.276390, 2.644550, 2.518670],\n        [0.665190, 0.678910, 1.012360, 1.199940, 0.986580]]\n\n    coeffs[2, 3, :, :] = [\n        [0.378870, 0.974060, 0.500000, 0.491880, 0.665290],\n        [0.105210, 0.263470, 0.407040, 0.553460, 0.582590],\n        [0.312900, 0.345240, 1.144180, 0.854790, 0.612280],\n        [0.119070, 0.365120, 0.560520, 0.793720, 0.802600],\n        [0.781610, 0.837390, 1.270420, 1.537980, 1.292950],\n        [1.152290, 1.152290, 1.492080, 1.245370, 2.177100],\n        [0.424660, 0.529550, 0.966910, 1.033460, 0.958730]]\n\n    coeffs[2, 4, :, :] = [\n        [0.310590, 0.714410, 0.252450, 0.500000, 0.607600],\n        [0.975190, 0.363420, 0.500000, 0.400000, 0.502800],\n        [0.175580, 0.196250, 0.476360, 1.072470, 0.490510],\n        [0.719280, 0.698620, 0.657770, 1.190840, 0.681110],\n        [0.426240, 1.464840, 0.678550, 1.157730, 0.978430],\n        [2.501120, 1.789130, 1.387090, 2.394180, 2.394180],\n        [0.491640, 0.677610, 0.685610, 1.082400, 0.735410]]\n\n    coeffs[2, 5, :, :] = [\n        [0.597000, 0.500000, 0.300000, 0.310050, 0.413510],\n        [0.314790, 0.336310, 0.400000, 0.400000, 0.442460],\n        [0.166510, 0.460440, 0.552570, 1.000000, 0.461610],\n        [0.401020, 0.559110, 0.403630, 1.016710, 0.671490],\n        [0.400360, 0.750830, 0.842640, 1.802600, 1.023830],\n        [3.315300, 1.510380, 2.443650, 1.638820, 2.133990],\n        [0.530790, 0.745850, 0.693050, 1.458040, 0.804500]]\n\n    coeffs[2, 6, :, :] = [\n        [0.597000, 0.500000, 0.300000, 0.310050, 0.800920],\n        [0.314790, 0.336310, 0.400000, 0.400000, 0.237040],\n        [0.166510, 0.460440, 0.552570, 1.000000, 0.581990],\n        [0.401020, 0.559110, 0.403630, 1.016710, 0.898570],\n        [0.400360, 0.750830, 0.842640, 1.802600, 3.400390],\n        [3.315300, 1.510380, 2.443650, 1.638820, 2.508780],\n        [0.204340, 1.157740, 2.003080, 2.622080, 1.409380]]\n\n    coeffs[3, 1, :, :] = [\n        [1.242210, 1.242210, 1.242210, 1.242210, 1.242210],\n        [0.056980, 0.056980, 0.656990, 0.656990, 0.925160],\n        [0.089090, 0.089090, 1.040430, 1.232480, 1.205300],\n        [1.053850, 1.053850, 1.399690, 1.084640, 1.233340],\n        [1.151540, 1.151540, 1.118290, 1.531640, 1.411840],\n        [1.494980, 1.494980, 1.700000, 1.800810, 1.671600],\n        [1.018450, 1.018450, 1.153600, 1.321890, 1.294670]]\n\n    coeffs[3, 2, :, :] = [\n        [0.700000, 0.700000, 1.023460, 0.700000, 0.945830],\n        [0.886300, 0.886300, 1.333620, 0.800000, 1.066620],\n        [0.902180, 0.902180, 0.954330, 1.126690, 1.097310],\n        [1.095300, 1.075060, 1.176490, 1.139470, 1.096110],\n        [1.201660, 1.201660, 1.438200, 1.256280, 1.198060],\n        [1.525850, 1.525850, 1.869160, 1.985410, 1.911590],\n        [1.288220, 1.082810, 1.286370, 1.166170, 1.119330]]\n\n    coeffs[3, 3, :, :] = [\n        [0.600000, 1.029910, 0.859890, 0.550000, 0.813600],\n        [0.604450, 1.029910, 0.859890, 0.656700, 0.928840],\n        [0.455850, 0.750580, 0.804930, 0.823000, 0.911000],\n        [0.526580, 0.932310, 0.908620, 0.983520, 0.988090],\n        [1.036110, 1.100690, 0.848380, 1.035270, 1.042380],\n        [1.048440, 1.652720, 0.900000, 2.350410, 1.082950],\n        [0.817410, 0.976160, 0.861300, 0.974780, 1.004580]]\n\n    coeffs[3, 4, :, :] = [\n        [0.782110, 0.564280, 0.600000, 0.600000, 0.665740],\n        [0.894480, 0.680730, 0.541990, 0.800000, 0.669140],\n        [0.487460, 0.818950, 0.841830, 0.872540, 0.709040],\n        [0.709310, 0.872780, 0.908480, 0.953290, 0.844350],\n        [0.863920, 0.947770, 0.876220, 1.078750, 0.936910],\n        [1.280350, 0.866720, 0.769790, 1.078750, 0.975130],\n        [0.725420, 0.869970, 0.868810, 0.951190, 0.829220]]\n\n    coeffs[3, 5, :, :] = [\n        [0.791750, 0.654040, 0.483170, 0.409000, 0.597180],\n        [0.566140, 0.948990, 0.971820, 0.653570, 0.718550],\n        [0.648710, 0.637730, 0.870510, 0.860600, 0.694300],\n        [0.637630, 0.767610, 0.925670, 0.990310, 0.847670],\n        [0.736380, 0.946060, 1.117590, 1.029340, 0.947020],\n        [1.180970, 0.850000, 1.050000, 0.950000, 0.888580],\n        [0.700560, 0.801440, 0.961970, 0.906140, 0.823880]]\n\n    coeffs[3, 6, :, :] = [\n        [0.500000, 0.500000, 0.586770, 0.470550, 0.629790],\n        [0.500000, 0.500000, 1.056220, 1.260140, 0.658140],\n        [0.500000, 0.500000, 0.631830, 0.842620, 0.582780],\n        [0.554710, 0.734730, 0.985820, 0.915640, 0.898260],\n        [0.712510, 1.205990, 0.909510, 1.078260, 0.885610],\n        [1.899260, 1.559710, 1.000000, 1.150000, 1.120390],\n        [0.653880, 0.793120, 0.903320, 0.944070, 0.796130]]\n\n    coeffs[4, 1, :, :] = [\n        [1.000000, 1.000000, 1.050000, 1.170380, 1.178090],\n        [0.960580, 0.960580, 1.059530, 1.179030, 1.131690],\n        [0.871470, 0.871470, 0.995860, 1.141910, 1.114600],\n        [1.201590, 1.201590, 0.993610, 1.109380, 1.126320],\n        [1.065010, 1.065010, 0.828660, 0.939970, 1.017930],\n        [1.065010, 1.065010, 0.623690, 1.119620, 1.132260],\n        [1.071570, 1.071570, 0.958070, 1.114130, 1.127110]]\n\n    coeffs[4, 2, :, :] = [\n        [0.950000, 0.973390, 0.852520, 1.092200, 1.096590],\n        [0.804120, 0.913870, 0.980990, 1.094580, 1.042420],\n        [0.737540, 0.935970, 0.999940, 1.056490, 1.050060],\n        [1.032980, 1.034540, 0.968460, 1.032080, 1.015780],\n        [0.900000, 0.977210, 0.945960, 1.008840, 0.969960],\n        [0.600000, 0.750000, 0.750000, 0.844710, 0.899100],\n        [0.926800, 0.965030, 0.968520, 1.044910, 1.032310]]\n\n    coeffs[4, 3, :, :] = [\n        [0.850000, 1.029710, 0.961100, 1.055670, 1.009700],\n        [0.818530, 0.960010, 0.996450, 1.081970, 1.036470],\n        [0.765380, 0.953500, 0.948260, 1.052110, 1.000140],\n        [0.775610, 0.909610, 0.927800, 0.987800, 0.952100],\n        [1.000990, 0.881880, 0.875950, 0.949100, 0.893690],\n        [0.902370, 0.875960, 0.807990, 0.942410, 0.917920],\n        [0.856580, 0.928270, 0.946820, 1.032260, 0.972990]]\n\n    coeffs[4, 4, :, :] = [\n        [0.750000, 0.857930, 0.983800, 1.056540, 0.980240],\n        [0.750000, 0.987010, 1.013730, 1.133780, 1.038250],\n        [0.800000, 0.947380, 1.012380, 1.091270, 0.999840],\n        [0.800000, 0.914550, 0.908570, 0.999190, 0.915230],\n        [0.778540, 0.800590, 0.799070, 0.902180, 0.851560],\n        [0.680190, 0.317410, 0.507680, 0.388910, 0.646710],\n        [0.794920, 0.912780, 0.960830, 1.057110, 0.947950]]\n\n    coeffs[4, 5, :, :] = [\n        [0.750000, 0.833890, 0.867530, 1.059890, 0.932840],\n        [0.979700, 0.971470, 0.995510, 1.068490, 1.030150],\n        [0.858850, 0.987920, 1.043220, 1.108700, 1.044900],\n        [0.802400, 0.955110, 0.911660, 1.045070, 0.944470],\n        [0.884890, 0.766210, 0.885390, 0.859070, 0.818190],\n        [0.615680, 0.700000, 0.850000, 0.624620, 0.669300],\n        [0.835570, 0.946150, 0.977090, 1.049350, 0.979970]]\n\n    coeffs[4, 6, :, :] = [\n        [0.689220, 0.809600, 0.900000, 0.789500, 0.853990],\n        [0.854660, 0.852840, 0.938200, 0.923110, 0.955010],\n        [0.938600, 0.932980, 1.010390, 1.043950, 1.041640],\n        [0.843620, 0.981300, 0.951590, 0.946100, 0.966330],\n        [0.694740, 0.814690, 0.572650, 0.400000, 0.726830],\n        [0.211370, 0.671780, 0.416340, 0.297290, 0.498050],\n        [0.843540, 0.882330, 0.911760, 0.898420, 0.960210]]\n\n    coeffs[5, 1, :, :] = [\n        [1.054880, 1.075210, 1.068460, 1.153370, 1.069220],\n        [1.000000, 1.062220, 1.013470, 1.088170, 1.046200],\n        [0.885090, 0.993530, 0.942590, 1.054990, 1.012740],\n        [0.920000, 0.950000, 0.978720, 1.020280, 0.984440],\n        [0.850000, 0.908500, 0.839940, 0.985570, 0.962180],\n        [0.800000, 0.800000, 0.810080, 0.950000, 0.961550],\n        [1.038590, 1.063200, 1.034440, 1.112780, 1.037800]]\n\n    coeffs[5, 2, :, :] = [\n        [1.017610, 1.028360, 1.058960, 1.133180, 1.045620],\n        [0.920000, 0.998970, 1.033590, 1.089030, 1.022060],\n        [0.912370, 0.949930, 0.979770, 1.020420, 0.981770],\n        [0.847160, 0.935300, 0.930540, 0.955050, 0.946560],\n        [0.880260, 0.867110, 0.874130, 0.972650, 0.883420],\n        [0.627150, 0.627150, 0.700000, 0.774070, 0.845130],\n        [0.973700, 1.006240, 1.026190, 1.071960, 1.017240]]\n\n    coeffs[5, 3, :, :] = [\n        [1.028710, 1.017570, 1.025900, 1.081790, 1.024240],\n        [0.924980, 0.985500, 1.014100, 1.092210, 0.999610],\n        [0.828570, 0.934920, 0.994950, 1.024590, 0.949710],\n        [0.900810, 0.901330, 0.928830, 0.979570, 0.913100],\n        [0.761030, 0.845150, 0.805360, 0.936790, 0.853460],\n        [0.626400, 0.546750, 0.730500, 0.850000, 0.689050],\n        [0.957630, 0.985480, 0.991790, 1.050220, 0.987900]]\n\n    coeffs[5, 4, :, :] = [\n        [0.992730, 0.993880, 1.017150, 1.059120, 1.017450],\n        [0.975610, 0.987160, 1.026820, 1.075440, 1.007250],\n        [0.871090, 0.933190, 0.974690, 0.979840, 0.952730],\n        [0.828750, 0.868090, 0.834920, 0.905510, 0.871530],\n        [0.781540, 0.782470, 0.767910, 0.764140, 0.795890],\n        [0.743460, 0.693390, 0.514870, 0.630150, 0.715660],\n        [0.934760, 0.957870, 0.959640, 0.972510, 0.981640]]\n\n    coeffs[5, 5, :, :] = [\n        [0.965840, 0.941240, 0.987100, 1.022540, 1.011160],\n        [0.988630, 0.994770, 0.976590, 0.950000, 1.034840],\n        [0.958200, 1.018080, 0.974480, 0.920000, 0.989870],\n        [0.811720, 0.869090, 0.812020, 0.850000, 0.821050],\n        [0.682030, 0.679480, 0.632450, 0.746580, 0.738550],\n        [0.668290, 0.445860, 0.500000, 0.678920, 0.696510],\n        [0.926940, 0.953350, 0.959050, 0.876210, 0.991490]]\n\n    coeffs[5, 6, :, :] = [\n        [0.948940, 0.997760, 0.850000, 0.826520, 0.998470],\n        [1.017860, 0.970000, 0.850000, 0.700000, 0.988560],\n        [1.000000, 0.950000, 0.850000, 0.606240, 0.947260],\n        [1.000000, 0.746140, 0.751740, 0.598390, 0.725230],\n        [0.922210, 0.500000, 0.376800, 0.517110, 0.548630],\n        [0.500000, 0.450000, 0.429970, 0.404490, 0.539940],\n        [0.960430, 0.881630, 0.775640, 0.596350, 0.937680]]\n\n    coeffs[6, 1, :, :] = [\n        [1.030000, 1.040000, 1.000000, 1.000000, 1.049510],\n        [1.050000, 0.990000, 0.990000, 0.950000, 0.996530],\n        [1.050000, 0.990000, 0.990000, 0.820000, 0.971940],\n        [1.050000, 0.790000, 0.880000, 0.820000, 0.951840],\n        [1.000000, 0.530000, 0.440000, 0.710000, 0.928730],\n        [0.540000, 0.470000, 0.500000, 0.550000, 0.773950],\n        [1.038270, 0.920180, 0.910930, 0.821140, 1.034560]]\n\n    coeffs[6, 2, :, :] = [\n        [1.041020, 0.997520, 0.961600, 1.000000, 1.035780],\n        [0.948030, 0.980000, 0.900000, 0.950360, 0.977460],\n        [0.950000, 0.977250, 0.869270, 0.800000, 0.951680],\n        [0.951870, 0.850000, 0.748770, 0.700000, 0.883850],\n        [0.900000, 0.823190, 0.727450, 0.600000, 0.839870],\n        [0.850000, 0.805020, 0.692310, 0.500000, 0.788410],\n        [1.010090, 0.895270, 0.773030, 0.816280, 1.011680]]\n\n    coeffs[6, 3, :, :] = [\n        [1.022450, 1.004600, 0.983650, 1.000000, 1.032940],\n        [0.943960, 0.999240, 0.983920, 0.905990, 0.978150],\n        [0.936240, 0.946480, 0.850000, 0.850000, 0.930320],\n        [0.816420, 0.885000, 0.644950, 0.817650, 0.865310],\n        [0.742960, 0.765690, 0.561520, 0.700000, 0.827140],\n        [0.643870, 0.596710, 0.474460, 0.600000, 0.651200],\n        [0.971740, 0.940560, 0.714880, 0.864380, 1.001650]]\n\n    coeffs[6, 4, :, :] = [\n        [0.995260, 0.977010, 1.000000, 1.000000, 1.035250],\n        [0.939810, 0.975250, 0.939980, 0.950000, 0.982550],\n        [0.876870, 0.879440, 0.850000, 0.900000, 0.917810],\n        [0.873480, 0.873450, 0.751470, 0.850000, 0.863040],\n        [0.761470, 0.702360, 0.638770, 0.750000, 0.783120],\n        [0.734080, 0.650000, 0.600000, 0.650000, 0.715660],\n        [0.942160, 0.919100, 0.770340, 0.731170, 0.995180]]\n\n    coeffs[6, 5, :, :] = [\n        [0.952560, 0.916780, 0.920000, 0.900000, 1.005880],\n        [0.928620, 0.994420, 0.900000, 0.900000, 0.983720],\n        [0.913070, 0.850000, 0.850000, 0.800000, 0.924280],\n        [0.868090, 0.807170, 0.823550, 0.600000, 0.844520],\n        [0.769570, 0.719870, 0.650000, 0.550000, 0.733500],\n        [0.580250, 0.650000, 0.600000, 0.500000, 0.628850],\n        [0.904770, 0.852650, 0.708370, 0.493730, 0.949030]]\n\n    coeffs[6, 6, :, :] = [\n        [0.911970, 0.800000, 0.800000, 0.800000, 0.956320],\n        [0.912620, 0.682610, 0.750000, 0.700000, 0.950110],\n        [0.653450, 0.659330, 0.700000, 0.600000, 0.856110],\n        [0.648440, 0.600000, 0.641120, 0.500000, 0.695780],\n        [0.570000, 0.550000, 0.598800, 0.400000, 0.560150],\n        [0.475230, 0.500000, 0.518640, 0.339970, 0.520230],\n        [0.743440, 0.592190, 0.603060, 0.316930, 0.794390]]\n\n    return coeffs[1:, 1:, :, :]\n\n\ndef dni(ghi, dhi, zenith, clearsky_dni=None, clearsky_tolerance=1.1,\n        zenith_threshold_for_zero_dni=88.0,\n        zenith_threshold_for_clearsky_limit=80.0):\n    \"\"\"\n    Determine DNI from GHI and DHI.\n\n    When calculating the DNI from GHI and DHI the calculated DNI may be\n    unreasonably high or negative for zenith angles close to 90 degrees\n    (sunrise/sunset transitions). This function identifies unreasonable DNI\n    values and sets them to NaN. If the clearsky DNI is given unreasonably high\n    values are cut off.\n\n    Parameters\n    ----------\n    ghi : Series\n        Global horizontal irradiance.\n\n    dhi : Series\n        Diffuse horizontal irradiance.\n\n    zenith : Series\n        True (not refraction-corrected) zenith angles in decimal\n        degrees. Angles must be >=0 and <=180.\n\n    clearsky_dni : None or Series, default None\n        Clearsky direct normal irradiance.\n\n    clearsky_tolerance : float, default 1.1\n        If 'clearsky_dni' is given this parameter can be used to allow a\n        tolerance by how much the calculated DNI value can be greater than\n        the clearsky value before it is identified as an unreasonable value.\n\n    zenith_threshold_for_zero_dni : float, default 88.0\n        Non-zero DNI values for zenith angles greater than or equal to\n        'zenith_threshold_for_zero_dni' will be set to NaN.\n\n    zenith_threshold_for_clearsky_limit : float, default 80.0\n        DNI values for zenith angles greater than or equal to\n        'zenith_threshold_for_clearsky_limit' and smaller the\n        'zenith_threshold_for_zero_dni' that are greater than the clearsky DNI\n        (times allowed tolerance) will be corrected. Only applies if\n        'clearsky_dni' is not None.\n\n    Returns\n    -------\n    dni : Series\n        The modeled direct normal irradiance.\n    \"\"\"\n\n    # calculate DNI\n    dni = (ghi - dhi) / tools.cosd(zenith)\n\n    # cutoff negative values\n    dni[dni < 0] = float('nan')\n\n    # set non-zero DNI values for zenith angles >=\n    # zenith_threshold_for_zero_dni to NaN\n    dni[(zenith >= zenith_threshold_for_zero_dni) & (dni != 0)] = float('nan')\n\n    # correct DNI values for zenith angles greater or equal to the\n    # zenith_threshold_for_clearsky_limit and smaller than the\n    # upper_cutoff_zenith that are greater than the clearsky DNI (times\n    # clearsky_tolerance)\n    if clearsky_dni is not None:\n        max_dni = clearsky_dni * clearsky_tolerance\n        dni[(zenith >= zenith_threshold_for_clearsky_limit) &\n            (zenith < zenith_threshold_for_zero_dni) &\n            (dni > max_dni)] = max_dni\n    return dni\n","header":{"file":{"path":"pvlib/irradiance.py"},"misc_line":null},"index_line":null,"is_binary_file":false,"binary_line":null,"minus_file":{"path":"a/pvlib/irradiance.py"},"plus_file":{"path":"b/pvlib/irradiance.py"},"hunks":[{"descriptor":{"old_range":{"start":886,"length":8},"new_range":{"start":886,"length":9},"section":"def reindl(surface_tilt, surface_azimuth, dhi, dni, ghi, dni_extra,"},"line_group":{"all_lines":[{"content":"    # these are the () and [] sub-terms of the second term of eqn 8","type":"context"},{"content":"    term1 = 1 - AI","type":"context"},{"content":"    term2 = 0.5 * (1 + tools.cosd(surface_tilt))","type":"context"},{"content":"    term3 = 1 + np.sqrt(HB / ghi) * (tools.sind(0.5 * surface_tilt) ** 3)","type":"deleted"},{"content":"","type":"deleted"},{"content":"    with np.errstate(invalid='ignore', divide='ignore'):","type":"added"},{"content":"        hb_to_ghi = np.where(ghi == 0, 0, np.divide(HB, ghi))","type":"added"},{"content":"    term3 = 1 + np.sqrt(hb_to_ghi) * (tools.sind(0.5 * surface_tilt)**3)","type":"added"},{"content":"    sky_diffuse = dhi * (AI * Rb + term1 * term2 * term3)","type":"context"},{"content":"    sky_diffuse = np.maximum(sky_diffuse, 0)","type":"context"},{"content":"","type":"context"},{"content":"","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]}]}],"old_commit_hash":"0b8f24c265d76320067a5ee908a57d475cd1bb24","new_commit_hash":"d88e3bb6d6b2a1aa88c12789feee93e0ffb10d26","commit_message":"formatting","commit_date":"2021-02-02T13:40:17-07:00","metadata":{}}