Esempio n. 1
0
def retrieve_data_blended(
    email,
    api_key,
    grid=None,
    solar_plant=None,
    interconnect_to_state_abvs=None,
    year="2016",
    rate_limit=0.5,
    cache_dir=None,
):
    """Retrieves irradiance data from NSRDB and calculate the power output using
    the System Adviser Model (SAM). Either a Grid object needs to be passed to ``grid``,
    or (a data frame needs to be passed to ``solar_plant`` and a dictionary needs to be
    passed to ``interconnect_to_state_abvs``).

    :param str email: email used to`sign up <https://developer.nrel.gov/signup/>`_.
    :param str api_key: API key.
    :param powersimdata.input.grid.Grid: grid instance.
    :param pandas.DataFrame solar_plant: plant data frame.
    :param dict/pandas.Series interconnect_to_state_abvs: mapping of interconnection
        name to state abbreviations, used to look up average parameters by interconnect
        when average parameters by state are not available.
    :param int/str year: year.
    :param int/float rate_limit: minimum seconds to wait between requests to NREL
    :param str cache_dir: directory to cache downloaded data. If None, don't cache.
    :return: (*pandas.DataFrame*) -- data frame with *'Pout'*, *'plant_id'*,
        *'ts'* and *'ts_id'* as columns. Values are power output for a 1MW generator.
    """
    xor_err_msg = (
        "Either grid xor (solar_plant and interconnect_to_state_abvs) must be defined"
    )
    if grid is None:
        if solar_plant is None or interconnect_to_state_abvs is None:
            raise TypeError(xor_err_msg)
        if not {"state_abv", "interconnect"} <= set(solar_plant.columns):
            raise ValueError(
                "solar_plant needs 'state_abv' and 'interconnect' columns")
        # Create mappings from other inputs
        zone_id_to_state_abv = {
            i: group["state_abv"].unique()[0]
            for i, group in solar_plant.groupby("zone_id")
        }
        zone_id_to_interconnect = {
            i: group["interconnect"].unique()[0]
            for i, group in solar_plant.groupby("zone_id")
        }
    else:
        if solar_plant is not None or interconnect_to_state_abvs is not None:
            raise TypeError(xor_err_msg)
        solar_plant = grid.plant.query("type == 'solar'").copy()
        # Use existing mappings found in the Grid object
        interconnect_to_state_abvs = grid.model_immutables.zones[
            "interconnect2abv"]
        zone_id_to_state_abv = grid.model_immutables.zones["id2abv"]
        zone_id_to_interconnect = {
            z: grid.model_immutables.zones["abv2interconnect"][
                zone_id_to_state_abv[z]]
            for z in solar_plant["zone_id"].unique()
        }

    real_dates = pd.date_range(start=f"{year}-01-01-00",
                               end=f"{year}-12-31-23",
                               freq="H")
    sam_dates, leap_day = generate_timestamps_without_leap_day(year)

    # PV tracking ratios
    # By state and by interconnect when EIA data do not have any solar PV in the state
    pv_info = get_pv_tracking_data()
    zone_id = solar_plant.zone_id.unique()
    frac = {}
    for zone in zone_id:
        state = zone_id_to_state_abv[zone]
        frac[zone] = get_pv_tracking_ratio_state(pv_info, [state])
        if frac[zone] is None:
            interconnect = zone_id_to_interconnect[zone]
            states_in_interconnect = list(
                interconnect_to_state_abvs[interconnect])
            frac[zone] = get_pv_tracking_ratio_state(pv_info,
                                                     states_in_interconnect)

    # Inverter Loading Ratio
    ilr = 1.25
    api = NrelApi(email, api_key, rate_limit)

    # Identify unique location
    coord = get_plant_id_unique_location(solar_plant)

    data = {}
    for key, plants in tqdm(coord.items(), total=len(coord)):
        lat, lon = key[1], key[0]
        solar_data = api.get_psm3_at(
            lat,
            lon,
            attributes="dhi,dni,wind_speed,air_temperature",
            year=year,
            leap_day=False,
            dates=sam_dates,
            cache_dir=cache_dir,
        ).to_dict()

        for i, plant_id in enumerate(plants):
            if i == 0:
                # Calculate power for the first plant at each location
                first_plant_id = plant_id
                tracking_ratios = frac[solar_plant.loc[plant_id].zone_id]
                power = 0
                for j, axis in enumerate([0, 2, 4]):
                    plant_pv_dict = {
                        "system_capacity": ilr,
                        "dc_ac_ratio": ilr,
                        "array_type": axis,
                    }
                    pv_dict = {**default_pv_parameters, **plant_pv_dict}
                    power += tracking_ratios[j] * calculate_power(
                        solar_data, pv_dict)
                if leap_day is not None:
                    power = np.insert(power, leap_day,
                                      power[leap_day - 24:leap_day])
            else:
                # For every other plant, look up power from first plant at the location
                power = data[first_plant_id]
            data[plant_id] = power

    return pd.DataFrame(data, index=real_dates).sort_index(axis="columns")
Esempio n. 2
0
def retrieve_data(solar_plant, email, api_key, year="2016", rate_limit=0.5):
    """Retrieves irradiance data from NSRDB and calculate the power output using
    the System Adviser Model (SAM).

    :param pandas.DataFrame solar_plant: plant data frame.
    :param str email: email used to`sign up <https://developer.nrel.gov/signup/>`_.
    :param str api_key: API key.
    :param str year: year.
    :param int/float rate_limit: minimum seconds to wait between requests to NREL
    :return: (*pandas.DataFrame*) -- data frame with *'Pout'*, *'plant_id'*,
        *'ts'* and *'ts_id'* as columns. Values are power output for a 1MW generator.
    """

    # SAM only takes 365 days.
    try:
        leap_day = (pd.Timestamp("%s-02-29-00" % year).dayofyear - 1) * 24
        is_leap_year = True
        dates = pd.date_range(start="%s-01-01-00" % 2015,
                              freq="H",
                              periods=365 * 24)
        dates = dates.map(lambda t: t.replace(year=int(year)))
    except ValueError:
        leap_day = None
        is_leap_year = False
        dates = pd.date_range(start="%s-01-01-00" % year,
                              freq="H",
                              periods=365 * 24)

    # Identify unique location
    coord = get_plant_id_unique_location(solar_plant)

    data = pd.DataFrame({"Pout": [], "plant_id": [], "ts": [], "ts_id": []})

    # PV tracking ratios
    # By state and by interconnect when EIA data do not have any solar PV in
    # the state
    pv_info = get_pv_tracking_data()
    zone_id = solar_plant.zone_id.unique()
    frac = {}
    for i in zone_id:
        state = id2abv[i]
        frac[i] = get_pv_tracking_ratio_state(pv_info, [state])
        if frac[i] is None:
            frac[i] = get_pv_tracking_ratio_state(
                pv_info, list(interconnect2abv[abv2interconnect[state]]))

    # Inverter Loading Ratio
    ilr = 1.25
    api = NrelApi(email, api_key, rate_limit)

    for key in tqdm(coord.keys(), total=len(coord)):
        lat, lon = key[1], key[0]
        solar_data = api.get_psm3_at(
            lat,
            lon,
            attributes="dhi,dni,wind_speed,air_temperature",
            year=year,
            leap_day=False,
            dates=dates,
        ).to_dict()

        for i in coord[key]:
            data_site = pd.DataFrame({
                "ts":
                pd.date_range(start="%s-01-01-00" % year,
                              end="%s-12-31-23" % year,
                              freq="H")
            })
            data_site["ts_id"] = range(1, len(data_site) + 1)
            data_site["plant_id"] = i

            power = 0
            for j, axis in enumerate([0, 2, 4]):
                pv_dict = {
                    "system_capacity": ilr,
                    "dc_ac_ratio": ilr,
                    "tilt": 30,
                    "azimuth": 180,
                    "inv_eff": 94,
                    "losses": 14,
                    "array_type": axis,
                    "gcr": 0.4,
                    "adjust:constant": 0,
                }

                pv_dat = pssc.dict_to_ssc_table(pv_dict, "pvwattsv7")
                pv = PVWatts.wrap(pv_dat)
                pv.SolarResource.assign({"solar_resource_data": solar_data})
                pv.execute()

                ratio = frac[solar_plant.loc[i].zone_id][j]
                power += ratio * np.array(pv.Outputs.gen)

            if is_leap_year is True:
                data_site["Pout"] = np.insert(power, leap_day,
                                              power[leap_day - 24:leap_day])
            else:
                data_site["Pout"] = power

            data = data.append(data_site, ignore_index=True, sort=False)

    data["plant_id"] = data["plant_id"].astype(np.int32)
    data["ts_id"] = data["ts_id"].astype(np.int32)

    data.sort_values(by=["ts_id", "plant_id"], inplace=True)
    data.reset_index(inplace=True, drop=True)

    return data
Esempio n. 3
0
def test_ratio_state_with_multiple_plants_and_tracking_systems():
    state = ["CA"]
    ratio = get_pv_tracking_ratio_state(pv_info, state)
    assert ratio == (1.0 / 10, 6.0 / 10, 3.0 / 10)
Esempio n. 4
0
def test_state_type():
    state = "AZ"
    with pytest.raises(TypeError, match="state must be a list"):
        get_pv_tracking_ratio_state(pv_info, state)
Esempio n. 5
0
def test_ratio_state_with_single_plant_and_unique_tracking():
    state = ["UT"]
    ratio = get_pv_tracking_ratio_state(pv_info, state)
    assert ratio[0] == 0
    assert ratio[1] == 0
    assert ratio[2] == 1
Esempio n. 6
0
def test_ratio_state_with_single_plant_and_multiple_tracking():
    state = ["WA"]
    ratio = get_pv_tracking_ratio_state(pv_info, state)
    assert ratio[0] == 0.5
    assert ratio[1] == 0.5
    assert ratio[2] == 0
Esempio n. 7
0
def test_sum_ratio_state_with_multiple_plants_and_tracking_systems():
    state = ["CA"]
    ratio = get_pv_tracking_ratio_state(pv_info, state)
    assert sum(ratio) == 1
Esempio n. 8
0
def test_sum_ratio_state_with_single_plant_and_tracking_system():
    state = ["UT"]
    ratio = get_pv_tracking_ratio_state(pv_info, state)
    assert sum(ratio) == 1
Esempio n. 9
0
def test_state_with_solar_return_3ple():
    state = ["UT"]
    ratio = get_pv_tracking_ratio_state(pv_info, state)
    assert type(ratio) is tuple
    assert len(ratio) == 3
Esempio n. 10
0
def test_state_without_no_solar_return_none():
    state = ["MT"]
    assert get_pv_tracking_ratio_state(pv_info, state) is None
Esempio n. 11
0
def test_state_exists():
    state = ["Tatooine"]
    with pytest.raises(ValueError, match="Invalid State"):
        get_pv_tracking_ratio_state(pv_info, state)