NREL products & behaviour — TMY and bbox point grids (live)¶
The quickstart covered the default hourly NSRDB
product and the WIND Toolkit. This notebook demonstrates two further
capabilities of the nrel backend:
- the Typical Meteorological Year product (
nsrdb-tmy), and - sampling a bounding box to a point grid (one keyed call per
(point, year), throttled to the NREL rate limit).
It also explains why the backend rejects an aggregate= argument.
import os
import tempfile
from earthlens.core import EarthLens
from earthlens.nrel import Catalog
API_KEY = os.environ["NREL_API_KEY"]
EMAIL = os.environ["NREL_EMAIL"]
OUT = tempfile.mkdtemp()
The catalog: three products¶
Catalog().available() lists the curated products; each row carries the source
archive, the CSV endpoint, the default attributes, and the value columns.
catalog = Catalog()
print(catalog.available())
{pid: catalog.get(pid).source for pid in catalog.available()}
Typical Meteorological Year (nsrdb-tmy)¶
Select the TMY product with product="nsrdb-tmy". TMY is a single synthetic
year, so the start/end window is collapsed to one names=tmy call and the
year column is tagged "tmy".
tmy = EarthLens(
data_source="nrel",
product="nsrdb-tmy",
variables=["ghi", "dni", "air_temperature"],
start="2020-01-01",
end="2020-12-31",
point=(39.74, -105.18),
api_key=API_KEY,
email=EMAIL,
path=OUT,
).download(progress_bar=False)
print(tmy.shape, "| year tag:", tmy["year"].unique().tolist())
tmy.head()
A bounding box becomes a point grid¶
Pass lat_lim / lon_lim (instead of point=) and the box is sampled at
spacing_deg; each grid point is one keyed call per year. Here a 0.5 degree
box at 0.5 degree spacing yields a 2x2 grid (4 points) x 1 year = 4 throttled
calls. The returned frame stacks one block of hourly rows per point.
grid = EarthLens(
data_source="nrel",
variables=["ghi"],
start="2020-01-01",
end="2020-12-31",
lat_lim=[39.5, 40.0],
lon_lim=[-105.5, -105.0],
spacing_deg=0.5,
api_key=API_KEY,
email=EMAIL,
path=OUT,
).download(progress_bar=False)
print("rows:", len(grid))
grid.groupby(["lat", "lon"]).size().rename("hours")
A large box at a fine spacing_deg, or a wide year range, fans out into many
calls — the backend throttles to <=1 request/second (5000/day) and raises a
ValueError past max_requests (default 500), so a country-scale request never
silently fires thousands of calls. Coarsen spacing_deg or narrow the years to
keep the count down.
Why aggregate= is rejected¶
nrel is a tabular backend: it already returns the resolved hourly / TMY
series, so there is no gridded raster to reduce. The EarthLens facade rejects
a non-None aggregate= for a tabular backend with NotImplementedError. To
get a coarser cadence, resample the returned frame in pandas instead:
daily_mean_ghi = (
grid[grid["lon"] == grid["lon"].iloc[0]]
.set_index("time")["GHI"]
.resample("1D")
.mean()
)
daily_mean_ghi.head()
Takeaway¶
The same download() shape serves the hourly, TMY, and gridded cases: pick the
product with product= (or the nsrdb / wind-toolkit aliases), pick the
attributes with variables=, and pass either a point= or a bbox. The result
is always a long-format pandas.DataFrame you resample or pivot in pandas.