reV Resource File Format#
Prerequisites:
Required: None
Recommended: None
Introduction#
In this tutorial, we will explore the reV
resource HDF5 file format. The goal is to familiarize ourselves with the file structure and be able to create new resource files using custom weather or resource data.
Let’s get started!
File structure#
reV
-compliant resource files like the WIND Toolkit (WTK) or the National Solar Radiation Database (NSRDB) are HDF5 files that contain spatiotemporal data. All core datasets in the HDF5 file are composed of two dimensions: time along the first axis and space along the second axis.
In order to define these dimensions, each HDF5 file comes equipped with a time_index
dataset and a meta
dataset. Both of these are 1D datasets, and both encode information about the dimension they represent. The time_index
dataset is a pandas DatetimeIndex
, while meta
is a pandas DataFrame
where each row represents one location.
Every subsequent dataset contained within reV
-compliant resource files is of the shape (len(time_index), len(meta))
and typically contains some information about the renewable resource. If you were to look inside a WTK file, for example, it would look something like this:
$ h5ls wtk_conus_2007.h5
meta Dataset {2488136}
pressure_0m Dataset {8760, 2488136}
pressure_100m Dataset {8760, 2488136}
pressure_200m Dataset {8760, 2488136}
relativehumidity_2m Dataset {8760, 2488136}
temperature_100m Dataset {8760, 2488136}
temperature_10m Dataset {8760, 2488136}
temperature_120m Dataset {8760, 2488136}
temperature_140m Dataset {8760, 2488136}
temperature_160m Dataset {8760, 2488136}
temperature_200m Dataset {8760, 2488136}
temperature_2m Dataset {8760, 2488136}
temperature_40m Dataset {8760, 2488136}
temperature_60m Dataset {8760, 2488136}
temperature_80m Dataset {8760, 2488136}
time_index Dataset {8760}
winddirection_100m Dataset {8760, 2488136}
winddirection_10m Dataset {8760, 2488136}
winddirection_120m Dataset {8760, 2488136}
winddirection_140m Dataset {8760, 2488136}
winddirection_160m Dataset {8760, 2488136}
winddirection_200m Dataset {8760, 2488136}
winddirection_40m Dataset {8760, 2488136}
winddirection_60m Dataset {8760, 2488136}
winddirection_80m Dataset {8760, 2488136}
windspeed_100m Dataset {8760, 2488136}
windspeed_10m Dataset {8760, 2488136}
windspeed_120m Dataset {8760, 2488136}
windspeed_140m Dataset {8760, 2488136}
windspeed_160m Dataset {8760, 2488136}
windspeed_200m Dataset {8760, 2488136}
windspeed_40m Dataset {8760, 2488136}
windspeed_60m Dataset {8760, 2488136}
windspeed_80m Dataset {8760, 2488136}
We can make several important observations right away:
The data contains 2,488,136 unique locations (the is the shape of the meta and the size of the second dimension for every variable)
The data contains 8760 time steps (i.e. hourly data for a full year ) for each location (the is the size of the first dimension for every variable)
The data contains 5 main variables: pressure, relative humidity, temperature, wind speed, and wind direction
The naming convention is {variable}_{height}m
The variables do not need to be given at the same heights
Based on these observations, we can being putting together custom data.
Custom reV
-compliant resource file#
To create our own reV
-compliant resource file, we need three main things:
A meta
DataFrame
detailing our locationsA
DatetimeIndex
representing our time stepsResource variables for each location and time
Let’s create a minimal resource file (with dummy data) and run it through reV
.
Meta#
We’ll start by creating the meta DataFrame
. At a minimum, this DataFrame
must contain the following columns:
“latitude”: Latitude of the location (degrees)
“longitude”: Longitude of the location (degrees; west is denoted with a negative sign)
“elevation”: Elevation of the location (meters)
“timezone”: Integer representing the UTC offset of the location
The meta can contain any other columns you would want to include to document the location. Typically, information like the county, state, and country are also added as individual columns.
Finally, the name of the index of the DataFrame
must be set to "gid"
. Let’s put together a minimal meta for two locations:
meta = pd.DataFrame(
{
"latitude": [39.7407, 39.7407, 39.75],
"longitude": [-105.1686, -105.1, -105.1],
"elevation": 2900,
"timezone": -6,
}
)
meta.index.name = "gid"
meta
latitude | longitude | elevation | timezone | |
---|---|---|---|---|
gid | ||||
0 | 39.7407 | -105.1686 | 2900 | -6 |
1 | 39.7407 | -105.1000 | 2900 | -6 |
2 | 39.7500 | -105.1000 | 2900 | -6 |
Time index#
Next, we’ll set up the time index. reV
requires at least hourly data (i.e. minimum of 8760 time steps) to work properly, but 30 minute or even 5 minute data works as well. For demonstration purposes, we will stick to hourly data:
year = datetime.datetime.now().year
time_index = pd.date_range(
start=f"1/1/{year}", end=f"1/1/{year + 1}", freq="h", inclusive="left"
)
time_index
DatetimeIndex(['2025-01-01 00:00:00', '2025-01-01 01:00:00',
'2025-01-01 02:00:00', '2025-01-01 03:00:00',
'2025-01-01 04:00:00', '2025-01-01 05:00:00',
'2025-01-01 06:00:00', '2025-01-01 07:00:00',
'2025-01-01 08:00:00', '2025-01-01 09:00:00',
...
'2025-12-31 14:00:00', '2025-12-31 15:00:00',
'2025-12-31 16:00:00', '2025-12-31 17:00:00',
'2025-12-31 18:00:00', '2025-12-31 19:00:00',
'2025-12-31 20:00:00', '2025-12-31 21:00:00',
'2025-12-31 22:00:00', '2025-12-31 23:00:00'],
dtype='datetime64[ns]', length=8760, freq='h')
Resource data#
The most challenging part of putting together reV
-compliant resource files is to get the data into the correct format. For simplicity, we will use randomly generate resource data of the correct shape (and units), since the data-mangling step should be done aon a case-by-case basis.
For wind resource, four main variables are required: windspeed
, winddirection
, pressure
, and temperature
. relativehumidity
is only required for add-on functionality like icing cutoffs. Solar and geothermal have their own minimum requirements (solar requires dni
, dhi
, wind_speed
, and air_temperature
variables, while geothermal requires temperature
and potential_MW
).
wind_speed = np.random.rand(len(time_index), len(meta)) * 15 # m/s
wind_direction = np.random.rand(len(time_index), len(meta)) * 360 # degrees
pressure = np.random.rand(len(time_index), len(meta)) * 20_000 + 90_000 # Pa
temperature = np.random.rand(len(time_index), len(meta)) * 25 - 5 # C
Putting it all together#
Now that we have the three main components (meta, time index, and data variables), we can write the resource file using the Outputs
class available in rex
:
RES_FILE = "sample_wtk.h5"
with Outputs(RES_FILE, "w") as out:
out.meta = meta
out.time_index = time_index
out.write_dataset(
"windspeed_100m",
wind_speed,
dtype="float32",
attrs={"units": "m s-1"}
)
out.write_dataset(
"winddirection_100m",
wind_direction,
dtype="float32",
attrs={"units": "degree"}
)
out.write_dataset(
"pressure_0m",
pressure,
dtype="float32",
attrs={"units": "Pa"},
)
out.write_dataset(
"temperature_0m",
temperature,
dtype="float32",
attrs={"units": "C"},
)
This is the minimum amount of information we need to provide. Let’s make sure this file can be used to run reV
!
Running reV
#
Before we can run reV
, we need to specify some details about the turbine technology in the form of a SAM config:
# Custom power curve
power_curve_wind_speeds = list(range(26))
power_curve_output = [0, 0, 0, 1, 81, 259, 504, 808, 1159, 1426, 1571, 1609]
power_curve_output += [1620] * 13
power_curve_output += [0]
sam_config = {
"wind_turbine_hub_ht": 80,
"wind_turbine_rotor_diameter": 77,
"wind_farm_wake_model": 0,
"wind_farm_xCoordinates": [0],
"wind_farm_yCoordinates": [0],
"wind_resource_shear": 0.14,
"wind_resource_turbulence_coeff": 0.1,
"wind_turbine_powercurve_windspeeds": power_curve_wind_speeds,
"wind_turbine_powercurve_powerout": power_curve_output,
}
Note that we are running a turbine with a hub height of 80m through reV using a wind resource set at 100m. Since we only provided one resource height, reV
will default to just using the wind speeds and directions at 100m. This is confirmed to us via a warning that is thrown during execution:
gen = Gen(
technology="windpower",
project_points=[0, 2], # index values of rows in our meta!
sam_files={"default": sam_config},
resource_file=RES_FILE,
output_request=("cf_mean", "cf_profile")
)
gen.run(max_workers=1)
gen.out["cf_mean"]
/home/runner/work/SitingLab/SitingLab/.pixi/envs/doc/lib/python3.11/site-packages/rex/renewable_resource.py:1179: ResourceWarning: Wind speed is only available at 100m, all variables will be extracted at 100m
warnings.warn('Wind speed is only available at {h}m, '
array([0.5437967 , 0.53954947], dtype=float32)
Despite the warning, everything works as intended!
Adding variables at other heights#
If we want reV
to use more appropriate wind speed heights, we have to add more variables to allow for interpolation:
wind_speed = np.random.rand(len(time_index), len(meta)) * 60 # m/s
wind_direction = np.random.rand(len(time_index), len(meta)) * 360 # degrees
with Outputs(RES_FILE, "a") as out:
out.write_dataset(
"windspeed_60m",
wind_speed,
dtype="float32",
attrs={"units": "m s-1"}
)
out.write_dataset(
"winddirection_60m",
wind_direction,
dtype="float32",
attrs={"units": "degree"}
)
with Resource(RES_FILE) as res:
print(res.datasets)
['meta', 'pressure_0m', 'temperature_0m', 'time_index', 'winddirection_100m', 'winddirection_60m', 'windspeed_100m', 'windspeed_60m']
gen = Gen(
technology="windpower",
project_points=[0, 2],
sam_files={"default": sam_config},
resource_file=RES_FILE,
output_request=("cf_mean", "cf_profile")
)
gen.run(max_workers=1)
gen.out["cf_mean"]
array([0.56369334, 0.5770708 ], dtype=float32)
No more warning, since reV
is interpolating between 60m and 100m to get the wind speed at 80m!
Conclusion#
In this tutorial, we have walked through the basic steps required to create custom reV
-compliant resource files. You should now be able to:
Understand
reV
-complaint resource HDF5 file structureCreate a meta and time index to represent your spatiotemporal data
Create a
reV
-compliant HDF5 file with custom data using theOutputs
class fromrex
Run
reV
on your newly-created resource file