Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collect wind power related NWP parameters+levels for wind reference forecasts #803

Open
williamhobbs opened this issue Jan 6, 2023 · 0 comments

Comments

@williamhobbs
Copy link

williamhobbs commented Jan 6, 2023

If NWP-based reference forecasts are going to be in future feature additions, it might be helpful to go ahead and add relevant NWP data to solarforecastarbiter/io/fetch/nwp.py. That way, anyone that is already fetching and archiving NWP data will have a useful historical dataset.

For example, 0.25 degree GFS has temperature, pressure, and u- and v- components of wind at 80 meters above ground (https://www.nco.ncep.noaa.gov/pmb/products/gfs/gfs.t00z.pgrb2.0p25.f003.shtml). It also includes u- and v- wind at other levels. I would recommend at least grabbing 100 meter (the highest), maybe 50 meter as well (next one below 80 m).

Anecdotally, I've heard of GFS being used for wind forecasts, and if only one NWP is added, it might be the best "catch-all". HRRR is reportedly relevant in wind as well (https://research.noaa.gov/article/ArtMID/587/ArticleID/2876/NOAA-wind-forecasts-result-in-150-million-in-energy-savings-every-year) so it would be #2 on my (subjective) list.

I would be willing to work on this for a pull request, but I'd be interesting in a few bits of feedback first:

  1. Is adding NWP-based wind reference forecasts in current scope/plans?
  2. If adding wind-related data to the fetch process is worthwhile, should it be enabled by default, or added as some form of option for the fetchnwp CLI function? In the case of GFS, I think it would add 4-8 new values in addition to the existing 9 (?), so 50-100% increase in resulting data volume (I'm assuming it increases final netCDF file size by about that much as well). [edit: We could also create new model maps that are called from solararbiter fetchnwp, e.g., gfs_0p25_wind as an alternative to gfs_0p25]
  3. Related, how do we decide which parameters/levels to add?

For reference (no pun intended), I think all the changes would be in the code linked below. For GFS_0P25_1HR, as an example, I think we would only need to add the following lines [edit: plus modify NC_TBL and maybe other minor changes]:

'lev_50_m_above_ground': 'on',
'lev_80_m_above_ground': 'on',
'lev_100_m_above_ground': 'on',
'var_PRES=on'

GFS_0P25_1HR = {'endpoint': 'filter_gfs_0p25_1hr.pl',
'file': 'gfs.t{init_hr:02d}z.pgrb2.0p25.f{valid_hr:03d}',
# /atmos added to dir with March 22, 2021, 1200Z GFS upgrade
'dir': '/gfs.{init_date}/{init_hr}/atmos',
'lev_2_m_above_ground': 'on',
'lev_10_m_above_ground': 'on',
'lev_entire_atmosphere': 'on',
'lev_surface': 'on',
'var_DSWRF': 'on',
'var_TCDC': 'on',
'var_TMP': 'on',
'var_UGRD': 'on',
'var_VGRD': 'on',
'update_freq': '6h',
'valid_hr_gen': lambda x: chain(range(120), range(120, 240, 3),
range(240, 385, 12)),
'time_between_fcst_hrs': 60,
'delay_to_first_forecast': '200min',
'avg_max_run_length': '100min',
'filename': 'gfs_0p25.nc'}
NAM_CONUS = {'endpoint': 'filter_nam.pl',
'file': 'nam.t{init_hr:02d}z.awphys{valid_hr:02d}.tm00.grib2',
'dir': '/nam.{init_date}',
'lev_2_m_above_ground': 'on',
'lev_10_m_above_ground': 'on',
'lev_entire_atmosphere_\\(considered_as_a_single_layer\\)': 'on',
'lev_surface': 'on',
'var_DSWRF': 'on',
'var_TCDC': 'on',
'var_TMP': 'on',
'var_UGRD': 'on',
'var_VGRD': 'on',
'update_freq': '6h',
'valid_hr_gen': lambda x: chain(range(36), range(36, 85, 3)),
'time_between_fcst_hrs': 60,
'delay_to_first_forecast': '90min',
'avg_max_run_length': '80min',
'filename': 'nam_12km.nc'}
# should be able to use RANGE requests and get data directly from grib files
# like https://www.cpc.ncep.noaa.gov/products/wesley/fast_downloading_grib.html
# so we can get DSWRF for RAP
RAP = {'endpoint': 'filter_rap.pl',
'file': 'rap.t{init_hr:02d}z.awp130pgrbf{valid_hr:02d}.grib2',
'dir': '/rap.{init_date}',
'lev_2_m_above_ground': 'on',
'lev_10_m_above_ground': 'on',
'lev_entire_atmosphere': 'on',
'lev_surface': 'on',
'var_TCDC': 'on',
'var_TMP': 'on',
'var_UGRD': 'on',
'var_VGRD': 'on',
'update_freq': '1h',
'valid_hr_gen': (
lambda x: range(40) if x in (3, 9, 15, 21) else range(22)),
'time_between_fcst_hrs': 60,
'delay_to_first_forecast': '50min',
'avg_max_run_length': '30min',
'filename': 'rap.nc'}
HRRR_HOURLY = {
'endpoint': 'filter_hrrr_2d.pl',
'file': 'hrrr.t{init_hr:02d}z.wrfsfcf{valid_hr:02d}.grib2',
'dir': '/hrrr.{init_date}/conus',
'lev_2_m_above_ground': 'on',
'lev_10_m_above_ground': 'on',
'lev_entire_atmosphere': 'on',
'lev_surface': 'on',
'var_DSWRF': 'on',
'var_VBDSF': 'on',
'var_VDDSF': 'on',
'var_TCDC': 'on',
'var_TMP': 'on',
'var_UGRD': 'on',
'var_VGRD': 'on',
'update_freq': '1h',
'valid_hr_gen': (
lambda x: range(37) if x in (0, 6, 12, 18) else range(19)),
'time_between_fcst_hrs': 120,
'delay_to_first_forecast': '45min',
'avg_max_run_length': '70min',
'filename': 'hrrr_hourly.nc'}
HRRR_SUBHOURLY = {
'endpoint': 'filter_hrrr_sub.pl',
'file': 'hrrr.t{init_hr:02d}z.wrfsubhf{valid_hr:02d}.grib2',
'dir': '/hrrr.{init_date}/conus',
'lev_2_m_above_ground': 'on',
'lev_10_m_above_ground': 'on',
'lev_entire_atmosphere': 'on',
'lev_surface': 'on',
'var_DSWRF': 'on',
'var_VBDSF': 'on',
'var_VDDSF': 'on',
'var_TMP': 'on',
'var_WIND': 'on',
'update_freq': '1h',
'valid_hr_gen': (lambda x: range(19)),
'time_between_fcst_hrs': 120,
'delay_to_first_forecast': '45min',
'avg_max_run_length': '50min',
'filename': 'hrrr_subhourly.nc'}
# each GEFS stat_or_member is treated separately
# really makes use of async capabilities
GEFS_0P50_RAW = {'endpoint': 'filter_gefs_atmos_0p50a.pl',
'file': 'ge{stat_or_member}.t{init_hr:02d}z.pgrb2a.0p50.f{valid_hr:03d}', # NOQA
'dir': '/gefs.{init_date}/{init_hr}/atmos/pgrb2ap5',
'lev_2_m_above_ground': 'on',
'lev_10_m_above_ground': 'on',
'lev_entire_atmosphere': 'on',
'lev_surface': 'on',
'var_DSWRF': 'on',
'var_TCDC': 'on',
'var_TMP': 'on',
'var_UGRD': 'on',
'var_VGRD': 'on',
'update_freq': '6h',
'valid_hr_gen': lambda x: chain(range(0, 240, 3),
range(240, 385, 6)),
'time_between_fcst_hrs': 60,
'delay_to_first_forecast': '280min',
'avg_max_run_length': '60min',
'filename': 'gefs_{stat_or_member}.nc',
'members': (['avg', 'c00', 'spr'] +
[f'p{r:02d}' for r in range(1, 21)]),
'check_url_name': 'gens'}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant