11class WeatherModelMapping :
2- """Class to map the weather model variables to the variables used in the
3- Environment class.
2+ """Map provider-specific variable names to RocketPy weather fields.
3+
4+ RocketPy reads forecast/reanalysis/ensemble datasets using canonical keys
5+ such as ``time``, ``latitude``, ``longitude``, ``level``, ``temperature``,
6+ ``geopotential_height``, ``geopotential``, ``u_wind`` and ``v_wind``.
7+ Each dictionary in this class maps those canonical keys to the actual
8+ variable names in a specific data provider format.
9+
10+ Mapping families
11+ ----------------
12+ - Base names (for example ``GFS``, ``NAM``, ``RAP``) represent the current
13+ default mappings used by the latest-model shortcuts and THREDDS-style
14+ datasets.
15+ - ``*_LEGACY`` names represent older NOMADS-style variable naming
16+ conventions (for example ``lev``, ``tmpprs``, ``ugrdprs`` and
17+ ``vgrdprs``) and are intended for archived or previously downloaded files.
18+
19+ Notes
20+ -----
21+ - Mappings can also include optional keys such as ``projection`` for
22+ projected grids and ``ensemble`` for member dimensions.
23+ - The :meth:`get` method is case-insensitive, so ``"gfs_legacy"`` and
24+ ``"GFS_LEGACY"`` are equivalent.
425 """
526
627 GFS = {
28+ "time" : "time" ,
29+ "latitude" : "lat" ,
30+ "longitude" : "lon" ,
31+ "level" : "isobaric" ,
32+ "temperature" : "Temperature_isobaric" ,
33+ "surface_geopotential_height" : "Geopotential_height_surface" ,
34+ "geopotential_height" : "Geopotential_height_isobaric" ,
35+ "geopotential" : None ,
36+ "u_wind" : "u-component_of_wind_isobaric" ,
37+ "v_wind" : "v-component_of_wind_isobaric" ,
38+ }
39+ GFS_LEGACY = {
740 "time" : "time" ,
841 "latitude" : "lat" ,
942 "longitude" : "lon" ,
@@ -16,6 +49,19 @@ class WeatherModelMapping:
1649 "v_wind" : "vgrdprs" ,
1750 }
1851 NAM = {
52+ "time" : "time" ,
53+ "latitude" : "y" ,
54+ "longitude" : "x" ,
55+ "projection" : "LambertConformal_Projection" ,
56+ "level" : "isobaric" ,
57+ "temperature" : "Temperature_isobaric" ,
58+ "surface_geopotential_height" : None ,
59+ "geopotential_height" : "Geopotential_height_isobaric" ,
60+ "geopotential" : None ,
61+ "u_wind" : "u-component_of_wind_isobaric" ,
62+ "v_wind" : "v-component_of_wind_isobaric" ,
63+ }
64+ NAM_LEGACY = {
1965 "time" : "time" ,
2066 "latitude" : "lat" ,
2167 "longitude" : "lon" ,
@@ -54,6 +100,18 @@ class WeatherModelMapping:
54100 "v_wind" : "v" ,
55101 }
56102 NOAA = {
103+ "time" : "time" ,
104+ "latitude" : "lat" ,
105+ "longitude" : "lon" ,
106+ "level" : "isobaric" ,
107+ "temperature" : "Temperature_isobaric" ,
108+ "surface_geopotential_height" : "Geopotential_height_surface" ,
109+ "geopotential_height" : "Geopotential_height_isobaric" ,
110+ "geopotential" : None ,
111+ "u_wind" : "u-component_of_wind_isobaric" ,
112+ "v_wind" : "v-component_of_wind_isobaric" ,
113+ }
114+ NOAA_LEGACY = {
57115 "time" : "time" ,
58116 "latitude" : "lat" ,
59117 "longitude" : "lon" ,
@@ -66,6 +124,19 @@ class WeatherModelMapping:
66124 "v_wind" : "vgrdprs" ,
67125 }
68126 RAP = {
127+ "time" : "time" ,
128+ "latitude" : "y" ,
129+ "longitude" : "x" ,
130+ "projection" : "LambertConformal_Projection" ,
131+ "level" : "isobaric" ,
132+ "temperature" : "Temperature_isobaric" ,
133+ "surface_geopotential_height" : None ,
134+ "geopotential_height" : "Geopotential_height_isobaric" ,
135+ "geopotential" : None ,
136+ "u_wind" : "u-component_of_wind_isobaric" ,
137+ "v_wind" : "v-component_of_wind_isobaric" ,
138+ }
139+ RAP_LEGACY = {
69140 "time" : "time" ,
70141 "latitude" : "lat" ,
71142 "longitude" : "lon" ,
@@ -90,6 +161,19 @@ class WeatherModelMapping:
90161 "u_wind" : "ugrdprs" ,
91162 "v_wind" : "vgrdprs" ,
92163 }
164+ CMC_LEGACY = {
165+ "time" : "time" ,
166+ "latitude" : "lat" ,
167+ "longitude" : "lon" ,
168+ "level" : "lev" ,
169+ "ensemble" : "ens" ,
170+ "temperature" : "tmpprs" ,
171+ "surface_geopotential_height" : None ,
172+ "geopotential_height" : "hgtprs" ,
173+ "geopotential" : None ,
174+ "u_wind" : "ugrdprs" ,
175+ "v_wind" : "vgrdprs" ,
176+ }
93177 GEFS = {
94178 "time" : "time" ,
95179 "latitude" : "lat" ,
@@ -103,6 +187,19 @@ class WeatherModelMapping:
103187 "u_wind" : "ugrdprs" ,
104188 "v_wind" : "vgrdprs" ,
105189 }
190+ GEFS_LEGACY = {
191+ "time" : "time" ,
192+ "latitude" : "lat" ,
193+ "longitude" : "lon" ,
194+ "level" : "lev" ,
195+ "ensemble" : "ens" ,
196+ "temperature" : "tmpprs" ,
197+ "surface_geopotential_height" : None ,
198+ "geopotential_height" : "hgtprs" ,
199+ "geopotential" : None ,
200+ "u_wind" : "ugrdprs" ,
201+ "v_wind" : "vgrdprs" ,
202+ }
106203 HIRESW = {
107204 "time" : "time" ,
108205 "latitude" : "lat" ,
@@ -114,6 +211,17 @@ class WeatherModelMapping:
114211 "u_wind" : "ugrdprs" ,
115212 "v_wind" : "vgrdprs" ,
116213 }
214+ HIRESW_LEGACY = {
215+ "time" : "time" ,
216+ "latitude" : "lat" ,
217+ "longitude" : "lon" ,
218+ "level" : "lev" ,
219+ "temperature" : "tmpprs" ,
220+ "surface_geopotential_height" : "hgtsfc" ,
221+ "geopotential_height" : "hgtprs" ,
222+ "u_wind" : "ugrdprs" ,
223+ "v_wind" : "vgrdprs" ,
224+ }
117225 MERRA2 = {
118226 "time" : "time" ,
119227 "latitude" : "lat" ,
@@ -127,29 +235,78 @@ class WeatherModelMapping:
127235 "u_wind" : "U" ,
128236 "v_wind" : "V" ,
129237 }
238+ MERRA2_LEGACY = {
239+ "time" : "time" ,
240+ "latitude" : "lat" ,
241+ "longitude" : "lon" ,
242+ "level" : "lev" ,
243+ "temperature" : "T" ,
244+ "surface_geopotential_height" : None ,
245+ "surface_geopotential" : "PHIS" ,
246+ "geopotential_height" : "H" ,
247+ "geopotential" : None ,
248+ "u_wind" : "U" ,
249+ "v_wind" : "V" ,
250+ }
130251
131252 def __init__ (self ):
132- """Initialize the class, creates a dictionary with all the weather models
133- available and their respective dictionaries with the variables."""
253+ """Build the lookup table with default and legacy mapping aliases."""
134254
135255 self .all_dictionaries = {
136256 "GFS" : self .GFS ,
257+ "GFS_LEGACY" : self .GFS_LEGACY ,
137258 "NAM" : self .NAM ,
259+ "NAM_LEGACY" : self .NAM_LEGACY ,
138260 "ECMWF_v0" : self .ECMWF_v0 ,
139261 "ECMWF" : self .ECMWF ,
140262 "NOAA" : self .NOAA ,
263+ "NOAA_LEGACY" : self .NOAA_LEGACY ,
141264 "RAP" : self .RAP ,
265+ "RAP_LEGACY" : self .RAP_LEGACY ,
142266 "CMC" : self .CMC ,
267+ "CMC_LEGACY" : self .CMC_LEGACY ,
143268 "GEFS" : self .GEFS ,
269+ "GEFS_LEGACY" : self .GEFS_LEGACY ,
144270 "HIRESW" : self .HIRESW ,
271+ "HIRESW_LEGACY" : self .HIRESW_LEGACY ,
145272 "MERRA2" : self .MERRA2 ,
273+ "MERRA2_LEGACY" : self .MERRA2_LEGACY ,
146274 }
147275
148276 def get (self , model ):
277+ """Return a mapping dictionary by model alias (case-insensitive).
278+
279+ Parameters
280+ ----------
281+ model : str
282+ Mapping alias name, such as ``"GFS"`` or ``"GFS_LEGACY"``.
283+
284+ Returns
285+ -------
286+ dict
287+ Dictionary mapping RocketPy canonical weather keys to dataset
288+ variable names.
289+
290+ Raises
291+ ------
292+ KeyError
293+ If ``model`` is unknown or not a string.
294+ """
295+ if not isinstance (model , str ):
296+ raise KeyError (
297+ f"Model { model } not found in the WeatherModelMapping. "
298+ f"The available models are: { self .all_dictionaries .keys ()} "
299+ )
300+
149301 try :
150302 return self .all_dictionaries [model ]
151- except KeyError as e :
303+ except KeyError as exc :
304+ model_casefold = model .casefold ()
305+ for key , value in self .all_dictionaries .items ():
306+ if key .casefold () == model_casefold :
307+ return value
308+
152309 raise KeyError (
153310 f"Model { model } not found in the WeatherModelMapping. "
154311 f"The available models are: { self .all_dictionaries .keys ()} "
155- ) from e
312+ ) from exc
0 commit comments