Skip to content

Commit

Permalink
Merge pull request #260 from Breakthrough-Energy/daniel/hifld_wind_pr…
Browse files Browse the repository at this point in the history
…ofiles

feat: generate wind profiles during HIFLD grid-building
  • Loading branch information
danielolsen committed Mar 14, 2022
2 parents f2ccac7 + 74ac5f3 commit 86a61d7
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 6 deletions.
43 changes: 43 additions & 0 deletions prereise/gather/griddata/hifld/data_process/profiles.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import datetime as dt

from prereise.gather.griddata.hifld import const
from prereise.gather.griddata.hifld.data_access.load import get_eia_form_860
from prereise.gather.solardata.nsrdb.sam import retrieve_data_individual
from prereise.gather.winddata.hrrr.calculations import calculate_pout_individual
from prereise.gather.winddata.hrrr.hrrr import retrieve_data


def floatify(x):
Expand Down Expand Up @@ -57,3 +61,42 @@ def build_solar(nrel_email, nrel_api_key, solar_plants, **solar_kwargs):
**solar_kwargs,
)
return profiles


def build_wind(wind_plants, download_directory, year):
"""Use plant-level data to build wind profiles.
:param pandas.DataFrame wind_plants: data frame of wind farms.
:param str download_directory: location to download wind speed data to.
:param int/str year: year of weather data to use for generating profiles.
:return: (*pandas.DataFrame*) -- data frame of normalized power profiles. The index
is hourly timestamps for the profile year, the columns are plant IDs, the values
are floats.
"""
default_hub_height = 262.467 # (262.467 ft = 80m)
# Load raw 'extra' table data, join on plant & generating unit, re-establish index
extra_wind_data = get_eia_form_860(const.blob_paths["eia_form860_2019_wind"])
full_data = wind_plants.merge(
extra_wind_data, on=["Plant Code", "Generator ID"], suffixes=(None, "_extra")
)
full_data.index = wind_plants.index
# Process data to expected types for profile generation
full_data["Turbine Hub Height (Feet)"] = (
full_data["Turbine Hub Height (Feet)"].map(floatify).fillna(default_hub_height)
)
full_data["Predominant Turbine Manufacturer"] = (
full_data["Predominant Turbine Manufacturer"].astype("string").fillna("")
)
full_data["Predominant Turbine Model Number"] = (
full_data["Predominant Turbine Model Number"].astype("string").fillna("")
)
start_dt = dt.datetime.fromisoformat(f"{year}-01-01-00")
end_dt = dt.datetime.fromisoformat(f"{year}-12-31-23")
retrieve_data(start_dt=start_dt, end_dt=end_dt, directory=download_directory)
profiles = calculate_pout_individual(
wind_farms=full_data,
start_dt=start_dt,
end_dt=end_dt,
directory=download_directory,
)
return profiles
39 changes: 34 additions & 5 deletions prereise/gather/griddata/hifld/orchestration.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,37 @@
from prereise.gather.griddata.hifld.const import powersimdata_column_defaults
from prereise.gather.griddata.hifld.data_process.demand import assign_demand_to_buses
from prereise.gather.griddata.hifld.data_process.generators import build_plant
from prereise.gather.griddata.hifld.data_process.profiles import build_solar
from prereise.gather.griddata.hifld.data_process.profiles import build_solar, build_wind
from prereise.gather.griddata.hifld.data_process.transmission import build_transmission


def create_csvs(output_folder, nrel_email, nrel_api_key, solar_kwargs={}):
def create_csvs(
output_folder,
wind_directory,
year,
nrel_email,
nrel_api_key,
solar_kwargs={},
):
"""Process HIFLD source data to CSVs compatible with PowerSimData.
:param str output_folder: directory to write CSVs to.
:param str wind_directory: directory to save wind speed data to.
:param int/str year: weather year to use to generate profiles.
:param str nrel_email: email used to`sign up <https://developer.nrel.gov/signup/>`_.
:param str nrel_api_key: API key.
:param dict solar_kwargs: keyword arguments to pass to
:func:`prereise.gather.solardata.nsrdb.sam.retrieve_data_individual`.
"""
full_tables = create_grid(output_folder)
create_profiles(
full_tables["plant"], nrel_email, nrel_api_key, output_folder, solar_kwargs
full_tables["plant"],
year,
nrel_email,
nrel_api_key,
wind_directory,
output_folder,
solar_kwargs,
)


Expand Down Expand Up @@ -86,14 +101,22 @@ def create_grid(output_folder=None):


def create_profiles(
plants, nrel_email, nrel_api_key, output_folder=None, solar_kwargs={}
plants,
year,
nrel_email,
nrel_api_key,
wind_directory,
output_folder=None,
solar_kwargs={},
):
"""Process a table of plant data to produce profile CSVs compatible with
PowerSimData.
:param pandas.DataFrame plants: table of plant data.
:param int/str year: weather year to use to generate profiles.
:param str nrel_email: email used to`sign up <https://developer.nrel.gov/signup/>`_.
:param str nrel_api_key: API key.
:param str wind_directory: directory to save wind speed data to.
:param str output_folder: directory to write CSVs to. If None, CSVs will not be
written (just returned).
:param dict solar_kwargs: keyword arguments to pass to
Expand All @@ -102,12 +125,18 @@ def create_profiles(
indexed by timestamp, with plant IDs as columns.
"""
# Use plant data to build profiles
full_solar_kwargs = {**solar_kwargs, **{"year": year}}
profiles = {
"solar": build_solar(
nrel_email,
nrel_api_key,
plants.query("type == 'solar'"),
**solar_kwargs,
**full_solar_kwargs,
),
"wind": build_wind(
plants.query("type == 'wind'"),
wind_directory,
year,
),
}
if output_folder is not None:
Expand Down
4 changes: 3 additions & 1 deletion prereise/gather/winddata/hrrr/hrrr_api.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import os

import requests
from pandas import date_range
from tqdm import tqdm
Expand Down Expand Up @@ -83,7 +85,7 @@ def download_meteorological_data(
)
)

with open(directory + filename, "ab") as f:
with open(os.path.join(directory, filename), "ab") as f:
for grib_record_information in grib_record_information_list:
try:
self.downloader.download(
Expand Down

0 comments on commit 86a61d7

Please sign in to comment.