Skip to content

Commit e2ddc45

Browse files
authored
ENH: add AIGFS and HRRR Models to Forecast (#951)
* ENH: Add AIGFS and HRRR dataset fetchers * ENH: Update documentation for atmospheric models and add AIGFS and HRRR support * TST: Add tests for new models
1 parent dbfe5d8 commit e2ddc45

9 files changed

Lines changed: 318 additions & 72 deletions

File tree

docs/user/environment/1-atm-models/ensemble.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ Global Ensemble Forecast System (GEFS)
2525

2626
.. danger::
2727

28-
**GEFS shortcut unavailable**: ``file="GEFS"`` is currently disabled in
29-
RocketPy because NOMADS OPeNDAP is deactivated for this endpoint.
28+
**GEFS unavailable**: ``file="GEFS"`` is currently disabled in
29+
RocketPy because NOMADS OPeNDAP has been deactivated.
3030

3131
.. note::
3232

docs/user/environment/1-atm-models/forecast.rst

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ Forecasts
66
Weather forecasts can be used to set the atmospheric model in RocketPy.
77

88
Here, we will showcase how to import global forecasts such as GFS, as well as
9-
local forecasts like NAM and RAP for North America, all available through
10-
OPeNDAP on the `NOAA's NCEP NOMADS <http://nomads.ncep.noaa.gov/>`_ website.
9+
local forecasts like NAM, RAP and HRRR for North America, all available through
10+
OPeNDAP on the `UCAR THREDDS <https://thredds.ucar.edu/>`_ server.
1111
Other generic forecasts can also be imported.
1212

1313
.. important::
@@ -22,6 +22,10 @@ Other generic forecasts can also be imported.
2222
Global Forecast System (GFS)
2323
----------------------------
2424

25+
GFS is NOAA's global numerical weather prediction model. It provides worldwide
26+
atmospheric forecasts and is usually a good default choice when you need broad
27+
coverage, consistent availability, and launch planning several days ahead.
28+
2529
Using the latest forecast from GFS is simple.
2630
Set the atmospheric model to ``forecast`` and specify that GFS is the file you want.
2731
Note that since data is downloaded from a remote OPeNDAP server, this line of code can
@@ -48,9 +52,34 @@ take longer than usual.
4852
`GFS overview page <https://www.emc.ncep.noaa.gov/emc/pages/numerical_forecast_systems/gfs.php>`_.
4953

5054

55+
Artificial Intelligence Global Forecast System (AIGFS)
56+
------------------------------------------------------
57+
58+
AIGFS is a global AI-based forecast product distributed through the same THREDDS
59+
ecosystem used by other RocketPy forecast inputs. It is useful when you want a
60+
global forecast alternative to traditional physics-only models.
61+
62+
RocketPy supports the latest AIGFS global forecast through THREDDS.
63+
64+
.. jupyter-execute::
65+
66+
env_aigfs = Environment(date=tomorrow)
67+
env_aigfs.set_atmospheric_model(type="forecast", file="AIGFS")
68+
env_aigfs.plots.atmospheric_model()
69+
70+
.. note::
71+
72+
AIGFS is currently available as a global 0.25 degree forecast product on
73+
UCAR THREDDS.
74+
75+
5176
North American Mesoscale Forecast System (NAM)
5277
----------------------------------------------
5378

79+
NAM is a regional forecast model focused on North America. It is best suited
80+
for launches inside its coverage area when you want finer regional detail than
81+
global models typically provide.
82+
5483
You can also request the latest forecasts from NAM.
5584
Since this is a regional model for North America, you need to specify latitude
5685
and longitude points within North America.
@@ -78,6 +107,10 @@ We will use **SpacePort America** for this, represented by coordinates
78107
Rapid Refresh (RAP)
79108
-------------------
80109

110+
RAP is a short-range, high-frequency regional model for North America. It is
111+
especially useful for near-term operations, where fast update cycles are more
112+
important than long forecast horizon.
113+
81114
The Rapid Refresh (RAP) model is another regional model for North America.
82115
It is similar to NAM, but with a higher resolution and a shorter forecast range.
83116
The same coordinates for SpacePort America will be used.
@@ -111,6 +144,17 @@ The same coordinates for SpacePort America will be used.
111144
High Resolution Window (HIRESW)
112145
-------------------------------
113146

147+
HIRESW is a convection-allowing, high-resolution regional system designed to
148+
resolve local weather structure better than coarser grids. It is most useful
149+
for short-range, local analysis where small-scale wind and weather features
150+
matter.
151+
152+
The High Resolution Window (HIRESW) model is a sophisticated weather forecasting
153+
system that operates at a high spatial resolution of approximately 3 km.
154+
It utilizes two main dynamical cores: the Advanced Research WRF (WRF-ARW) and
155+
the Finite Volume Cubed Sphere (FV3), each designed to enhance the accuracy of
156+
weather predictions.
157+
114158
.. danger::
115159

116160
**HIRESW shortcut unavailable**: ``file="HIRESW"`` is currently disabled in
@@ -121,6 +165,33 @@ you can still load it explicitly by passing the path/URL in ``file`` and an
121165
appropriate mapping in ``dictionary``.
122166

123167

168+
High-Resolution Rapid Refresh (HRRR)
169+
------------------------------------
170+
171+
HRRR is a high-resolution, short-range forecast model for North America with
172+
hourly updates. It is generally best for day-of-launch weather assessment and
173+
rapidly changing local conditions.
174+
175+
RocketPy supports HRRR through a dedicated THREDDS shortcut.
176+
Like NAM and RAP, HRRR is a regional model over North America.
177+
178+
If you have a HIRESW-compatible dataset from another provider (or a local copy),
179+
you can still load it explicitly by passing the path/URL in ``file`` and an
180+
appropriate mapping in ``dictionary``.
181+
182+
env_hrrr = Environment(
183+
date=now_plus_twelve,
184+
latitude=32.988528,
185+
longitude=-106.975056,
186+
)
187+
env_hrrr.set_atmospheric_model(type="forecast", file="HRRR")
188+
env_hrrr.plots.atmospheric_model()
189+
190+
.. note::
191+
192+
HRRR is a high-resolution regional model with approximately 2.5 km grid
193+
spacing over CONUS. Availability depends on upstream THREDDS data services.
194+
124195

125196
Using Windy Atmosphere
126197
----------------------
@@ -154,6 +225,10 @@ to EuRoC's launch area in Portugal.
154225
ECMWF
155226
^^^^^
156227

228+
ECMWF (HRES) is a global, high-skill forecast model known for strong
229+
medium-range performance. It is often a good choice for mission planning when
230+
you need reliable synoptic-scale forecasts several days ahead.
231+
157232
We can use the ``ECMWF`` model from Windy.com.
158233

159234
.. jupyter-execute::
@@ -173,6 +248,10 @@ We can use the ``ECMWF`` model from Windy.com.
173248
GFS
174249
^^^
175250

251+
Windy's GFS option provides NOAA's global model through Windy's interface. It
252+
is a practical baseline for global coverage and for comparing against other
253+
models when assessing forecast uncertainty.
254+
176255
The ``GFS`` model is also available on Windy.com. This is the same model as
177256
described in the :ref:`global-forecast-system` section.
178257

@@ -186,6 +265,10 @@ described in the :ref:`global-forecast-system` section.
186265
ICON
187266
^^^^
188267

268+
ICON is DWD's global weather model, available in Windy for broad-scale
269+
forecasting. It is useful as an independent global model source to cross-check
270+
wind and temperature trends against GFS or ECMWF.
271+
189272
The ICON model is a global weather forecasting model already available on Windy.com.
190273

191274
.. jupyter-execute::
@@ -203,6 +286,10 @@ The ICON model is a global weather forecasting model already available on Windy.
203286
ICON-EU
204287
^^^^^^^
205288

289+
ICON-EU is the regional European configuration of ICON, with higher spatial
290+
detail over Europe than ICON-Global. It is best for European launch sites when
291+
regional structure is important.
292+
206293
The ICON-EU model is a regional weather forecasting model available on Windy.com.
207294

208295
.. code-block:: python
@@ -228,4 +315,4 @@ Also, the servers may be down or may face high traffic.
228315
.. seealso::
229316

230317
To browse available NCEP model collections on UCAR THREDDS, visit
231-
`THREDDS NCEP Catalog <https://thredds.ucar.edu/thredds/catalog/grib/NCEP/GFS/Global_0p25deg/catalog.html>`_.
318+
`THREDDS NCEP Catalog <https://thredds.ucar.edu/thredds/catalog/grib/NCEP/GFS/Global_0p25deg/catalog.html>`_.

docs/user/environment/1-atm-models/soundings.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ Integrated Global Radiosonde Archive (IGRA).
5959

6060
These options can be retrieved as a text file in GSD format. However,
6161
RocketPy no longer provides a dedicated ``set_atmospheric_model`` type for
62-
NOAA RUC Soundings.
62+
NOAA RUC Soundings, since NOAA has discontinued the OPENDAP service.
6363

6464
.. note::
6565

docs/user/environment/3-further/other_apis.rst

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,10 @@ Instead of a custom dictionary, you can pass a built-in mapping name in the
8989
- ``"ECMWF_v0"``
9090
- ``"NOAA"``
9191
- ``"GFS"``
92+
- ``"AIGFS"``
9293
- ``"NAM"``
9394
- ``"RAP"``
95+
- ``"HRRR"``
9496
- ``"HIRESW"`` (mapping available; latest-model shortcut currently disabled)
9597
- ``"GEFS"`` (mapping available; latest-model shortcut currently disabled)
9698
- ``"MERRA2"``
@@ -116,10 +118,7 @@ legacy aliases:
116118
- ``"NAM_LEGACY"``
117119
- ``"NOAA_LEGACY"``
118120
- ``"RAP_LEGACY"``
119-
- ``"CMC_LEGACY"``
120121
- ``"GEFS_LEGACY"``
121-
- ``"HIRESW_LEGACY"``
122-
- ``"MERRA2_LEGACY"``
123122

124123
Legacy aliases primarily cover older variable naming patterns such as
125124
``lev``, ``tmpprs``, ``hgtprs``, ``ugrdprs`` and ``vgrdprs``.

rocketpy/environment/environment.py

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
import pytz
1212

1313
from rocketpy.environment.fetchers import (
14+
fetch_aigfs_file_return_dataset,
1415
fetch_atmospheric_data_from_windy,
1516
fetch_gefs_ensemble,
1617
fetch_gfs_file_return_dataset,
1718
fetch_hiresw_file_return_dataset,
19+
fetch_hrrr_file_return_dataset,
1820
fetch_nam_file_return_dataset,
1921
fetch_open_elevation,
2022
fetch_rap_file_return_dataset,
@@ -369,9 +371,11 @@ def __initialize_constants(self):
369371
self.__weather_model_map = WeatherModelMapping()
370372
self.__atm_type_file_to_function_map = {
371373
"forecast": {
374+
"AIGFS": fetch_aigfs_file_return_dataset,
372375
"GFS": fetch_gfs_file_return_dataset,
373376
"NAM": fetch_nam_file_return_dataset,
374377
"RAP": fetch_rap_file_return_dataset,
378+
"HRRR": fetch_hrrr_file_return_dataset,
375379
"HIRESW": fetch_hiresw_file_return_dataset,
376380
},
377381
"ensemble": {
@@ -665,9 +669,11 @@ def __resolve_dictionary_for_dataset(self, dictionary, dataset):
665669
def __validate_dictionary(self, file, dictionary):
666670
# removed CMC until it is fixed.
667671
available_models = [
672+
"AIGFS",
668673
"GFS",
669674
"NAM",
670675
"RAP",
676+
"HRRR",
671677
"HIRESW",
672678
"GEFS",
673679
"ERA5",
@@ -1132,8 +1138,9 @@ def set_atmospheric_model( # pylint: disable=too-many-statements
11321138
- ``"windy"``: one of ``"ECMWF"``, ``"GFS"``, ``"ICON"`` or
11331139
``"ICONEU"``.
11341140
- ``"forecast"``: local path, OPeNDAP URL, open
1135-
``netCDF4.Dataset``, or one of ``"GFS"``, ``"NAM"`` or ``"RAP"``
1136-
for the latest available forecast.
1141+
``netCDF4.Dataset``, or one of ``"AIGFS"``, ``"GFS"``,
1142+
``"NAM"``, ``"RAP"``, ``"HRRR"`` or ``"HIRESW"`` for the
1143+
latest available forecast.
11371144
- ``"reanalysis"``: local path, OPeNDAP URL, or open
11381145
``netCDF4.Dataset``.
11391146
- ``"ensemble"``: local path, OPeNDAP URL, open
@@ -1143,8 +1150,9 @@ def set_atmospheric_model( # pylint: disable=too-many-statements
11431150
Variable-name mapping for ``"forecast"``, ``"reanalysis"`` and
11441151
``"ensemble"``. It may be a custom dictionary or a built-in
11451152
mapping name (for example: ``"ECMWF"``, ``"ECMWF_v0"``,
1146-
``"NOAA"``, ``"GFS"``, ``"NAM"``, ``"RAP"``, ``"HIRESW"``,
1147-
``"GEFS"``, ``"MERRA2"`` or ``"CMC"``).
1153+
``"NOAA"``, ``"AIGFS"``, ``"GFS"``, ``"NAM"``, ``"RAP"``,
1154+
``"HRRR"``, ``"HIRESW"``, ``"GEFS"``, ``"MERRA2"`` or
1155+
``"CMC"``).
11481156
11491157
If ``dictionary`` is omitted and ``file`` is one of RocketPy's
11501158
latest-model shortcuts, the matching built-in mapping is selected
@@ -1761,13 +1769,17 @@ def process_forecast_reanalysis(self, file, dictionary): # pylint: disable=too-
17611769
# Some THREDDS datasets use projected x/y coordinates.
17621770
if dictionary.get("projection") is not None:
17631771
projection_variable = data.variables[dictionary["projection"]]
1764-
x_units = getattr(lon_array, "units", "m")
1765-
target_lon, target_lat = geodesic_to_lambert_conformal(
1766-
self.latitude,
1767-
self.longitude,
1768-
projection_variable,
1769-
x_units=x_units,
1770-
)
1772+
if dictionary.get("projection") == "LambertConformal_Projection":
1773+
x_units = getattr(lon_array, "units", "m")
1774+
target_lon, target_lat = geodesic_to_lambert_conformal(
1775+
self.latitude,
1776+
self.longitude,
1777+
projection_variable,
1778+
x_units=x_units,
1779+
)
1780+
else:
1781+
target_lon = self.longitude
1782+
target_lat = self.latitude
17711783
else:
17721784
target_lon = self.longitude
17731785
target_lat = self.latitude
@@ -2065,13 +2077,17 @@ class for some dictionary examples.
20652077
# coordinate system before locating the nearest grid cell.
20662078
if dictionary.get("projection") is not None:
20672079
projection_variable = data.variables[dictionary["projection"]]
2068-
x_units = getattr(lon_array, "units", "m")
2069-
target_lon, target_lat = geodesic_to_lambert_conformal(
2070-
self.latitude,
2071-
self.longitude,
2072-
projection_variable,
2073-
x_units=x_units,
2074-
)
2080+
if dictionary.get("projection") == "LambertConformal_Projection":
2081+
x_units = getattr(lon_array, "units", "m")
2082+
target_lon, target_lat = geodesic_to_lambert_conformal(
2083+
self.latitude,
2084+
self.longitude,
2085+
projection_variable,
2086+
x_units=x_units,
2087+
)
2088+
else:
2089+
target_lon = self.longitude
2090+
target_lat = self.latitude
20752091
else:
20762092
target_lon = self.longitude
20772093
target_lat = self.latitude

0 commit comments

Comments
 (0)