|
5 | 5 | from urllib.request import urlopen, Request |
6 | 6 | import pandas as pd |
7 | 7 | import numpy as np |
| 8 | +import warnings |
| 9 | +import urllib.error |
| 10 | + |
8 | 11 |
|
9 | 12 | SURFRAD_COLUMNS = [ |
10 | 13 | 'year', 'jday', 'month', 'day', 'hour', 'minute', 'dt', 'zen', |
@@ -181,3 +184,99 @@ def _format_index(data): |
181 | 184 | data.index = index |
182 | 185 | data = data.tz_localize('UTC') |
183 | 186 | return data |
| 187 | + |
| 188 | + |
| 189 | +def get_surfrad(station, start, end, map_variables=True, |
| 190 | + url="https://gml.noaa.gov/aftp/data/radiation/surfrad/"): |
| 191 | + """ |
| 192 | + Request data from NOAA SURFRAD and read it into a DataFrame. |
| 193 | +
|
| 194 | + The SURFRAD network is described in [1]_. The README files are located in |
| 195 | + the station directories in the SURFRAD data archives [2]_. In addition to |
| 196 | + the FTP server, the SURFRAD files are also available via HTTP access [3]_. |
| 197 | +
|
| 198 | + Data is returned for complete days, including ``start`` and ``end``. |
| 199 | +
|
| 200 | + Parameters |
| 201 | + ---------- |
| 202 | + station : str |
| 203 | + Three-letter SURFRAD station abbreviation. |
| 204 | + start : datetime-like |
| 205 | + First day of the requested period. |
| 206 | + end : datetime-like |
| 207 | + Last day of the requested period. |
| 208 | + map_variables : bool, default True |
| 209 | + Passed through to :py:func:`~pvlib.iotools.read_surfrad`: |
| 210 | + whether to rename columns to pvlib variable names |
| 211 | + (e.g. ``'dw_solar'`` -> ``'ghi'``). |
| 212 | + url : str, default 'https://gml.noaa.gov/aftp/data/radiation/surfrad/' |
| 213 | + Base URL of the SURFRAD archive. |
| 214 | +
|
| 215 | + Returns |
| 216 | + ------- |
| 217 | + data : pd.DataFrame |
| 218 | + Dataframe with data from SURFRAD. |
| 219 | + meta : dict |
| 220 | + Metadata. |
| 221 | +
|
| 222 | + See Also |
| 223 | + -------- |
| 224 | + pvlib.iotools.read_surfrad |
| 225 | +
|
| 226 | + Notes |
| 227 | + ----- |
| 228 | + Missing days (e.g. before a station's operational start date, or gaps |
| 229 | + in the archive) are skipped with a warning rather than raising an error. |
| 230 | +
|
| 231 | + Examples |
| 232 | + -------- |
| 233 | + >>> data, meta = pvlib.iotools.get_surfrad( |
| 234 | + ... station='bon', start='2020-01-01', end='2020-01-31') |
| 235 | +
|
| 236 | + References |
| 237 | + ---------- |
| 238 | + .. [1] NOAA Earth System Research Laboratory Surface Radiation Budget |
| 239 | + Network |
| 240 | + `SURFRAD Homepage <https://www.esrl.noaa.gov/gmd/grad/surfrad/>`_ |
| 241 | + .. [2] NOAA SURFRAD Data Archive |
| 242 | + `SURFRAD Archive <ftp://aftp.cmdl.noaa.gov/data/radiation/surfrad/>`_ |
| 243 | + .. [3] `NOAA SURFRAD HTTP Index |
| 244 | + <https://gml.noaa.gov/aftp/data/radiation/surfrad/>`_ |
| 245 | + """ |
| 246 | + start = pd.to_datetime(start) |
| 247 | + end = pd.to_datetime(end) |
| 248 | + |
| 249 | + dates = pd.date_range(start.floor('D'), end, freq='D') |
| 250 | + station = station.lower() |
| 251 | + |
| 252 | + filenames = [ |
| 253 | + f"{station}/{d.year}/{station}{d.strftime('%y')}{d.dayofyear:03}.dat" # noqa: E231,E501 |
| 254 | + for d in dates |
| 255 | + ] |
| 256 | + |
| 257 | + dfs = [] |
| 258 | + file_metadata = None |
| 259 | + for f in filenames: |
| 260 | + try: |
| 261 | + dfi, file_metadata = read_surfrad(url + f, |
| 262 | + map_variables=VARIABLE_MAP) |
| 263 | + dfs.append(dfi) |
| 264 | + |
| 265 | + except urllib.error.HTTPError: |
| 266 | + warnings.warn(f"The following file was not found: {f}") |
| 267 | + |
| 268 | + if not dfs: |
| 269 | + raise ValueError( |
| 270 | + f"No data retrieved for station '{station}' between " |
| 271 | + f"{start.date()} and {end.date()}. Check the station code " |
| 272 | + "and date range." |
| 273 | + ) |
| 274 | + |
| 275 | + data = pd.concat(dfs, axis='rows') |
| 276 | + meta = { |
| 277 | + 'station': station, |
| 278 | + 'filenames': filenames, |
| 279 | + # all files should share metadata, so just take it from the last one |
| 280 | + **file_metadata, |
| 281 | + } |
| 282 | + return data, meta |
0 commit comments