88from herbie import Herbie
99from pyproj import CRS , Transformer
1010from shapely .geometry import Polygon , box
11+ from typing import Optional , Union , List , Tuple
1112
1213from RAiDER .logger import logger
14+ from RAiDER .models .customExceptions import NoWeatherModelData
1315from RAiDER .models .model_levels import LEVELS_50_HEIGHTS
1416from RAiDER .models .weatherModel import TIME_RES , WeatherModel
1517from RAiDER .utilFcns import round_date
2527AK_GEO = gpd .read_file (Path (__file__ ).parent / 'data' / 'alaska.geojson.zip' ).geometry .unary_union
2628
2729
28- def check_hrrr_dataset_availability (datetime : dt .datetime ) -> bool :
30+ def check_hrrr_dataset_availability (datetime : dt .datetime , model = 'hrrr' ) -> bool :
2931 """Note a file could still be missing within the models valid range."""
3032 herbie = Herbie (
3133 datetime ,
32- model = 'hrrr' ,
34+ model = model ,
3335 product = 'nat' ,
3436 fxx = 0 ,
3537 )
@@ -87,11 +89,17 @@ def download_hrrr_file(ll_bounds, DATE, out, model='hrrr', product='nat', fxx=0,
8789 raise RuntimeError ('Herbie did not obtain an HRRR dataset with the expected layers and coordinates' )
8890
8991 # subset the full file by AOI
90- x_min , x_max , y_min , y_max = get_bounds_indices (
91- ll_bounds ,
92- ds_out .latitude .to_numpy (),
93- ds_out .longitude .to_numpy (),
94- )
92+ try :
93+ x_min , x_max , y_min , y_max = get_bounds_indices (
94+ ll_bounds ,
95+ ds_out .latitude .to_numpy (),
96+ ds_out .longitude .to_numpy (),
97+ )
98+ except NoWeatherModelData as e :
99+ logger .error (e )
100+ logger .error ('lat/lon bounds: %s' , ll_bounds )
101+ logger .error ('Weather model is {}' .format (model ))
102+ raise
95103
96104 # bookkeepping
97105 ds_out = ds_out .rename ({'gh' : 'z' , coord : 'levels' })
@@ -104,8 +112,15 @@ def download_hrrr_file(ll_bounds, DATE, out, model='hrrr', product='nat', fxx=0,
104112 ds_out [var ].attrs ['grid_mapping' ] = 'proj'
105113
106114 # pull the grid information
107- proj = CRS .from_cf (ds_out ['proj' ].attrs )
115+ if model == 'hrrr' :
116+ proj = CRS .from_cf (ds_out ['proj' ].attrs )
117+ elif model == 'hrrrak' :
118+ proj = HRRR_AK_PROJ
119+ else :
120+ raise ValueError ('Model not recognized. Please use either hrrr or hrrrak' )
121+
108122 t = Transformer .from_crs (4326 , proj , always_xy = True )
123+
109124 xl , yl = t .transform (ds_out ['longitude' ].values , ds_out ['latitude' ].values )
110125 W , E , S , N = np .nanmin (xl ), np .nanmax (xl ), np .nanmin (yl ), np .nanmax (yl )
111126
@@ -139,7 +154,7 @@ def get_bounds_indices(SNWE, lats, lons):
139154 W , E = np .mod ([W , E ], 360 )
140155 m1 = (S <= lats ) & (N >= lats ) & (W <= lons ) & (E >= lons )
141156 if np .sum (m1 ) == 0 :
142- raise RuntimeError ('Area of Interest has no overlap with the HRRR model available extent' )
157+ raise NoWeatherModelData ('Area of Interest has no overlap with the HRRR model available extent' )
143158
144159 # Y extent
145160 shp = lats .shape
@@ -266,6 +281,23 @@ def _fetch(self, out) -> None:
266281
267282 download_hrrr_file (bounds , corrected_DT , out , 'hrrr' , self ._model_level_type )
268283
284+ def _cast_to_hrrrak (self ) -> None :
285+ """
286+ Update the weather model to HRRR-AK if the bounding box is in Alaska.
287+ """
288+ self .__class__ = HRRRAK
289+ self ._dataset = 'hrrrak'
290+ self ._valid_bounds = HRRR_AK_COVERAGE_POLYGON
291+ self ._proj = HRRR_AK_PROJ
292+ self ._Name = 'HRRR-AK'
293+ self ._time_res = TIME_RES ['HRRR-AK' ]
294+ self ._valid_range = (
295+ dt .datetime (2018 , 7 , 13 ).replace (tzinfo = dt .timezone (offset = dt .timedelta ())),
296+ dt .datetime .now (dt .timezone .utc ),
297+ )
298+ self .setLevelType ('nat' )
299+
300+
269301 def load_weather (self , f = None , * args , ** kwargs ) -> None :
270302 """
271303 Load a weather model into a python weatherModel object, from self.files if no
@@ -294,7 +326,7 @@ def checkValidBounds(self, ll_bounds: np.ndarray) -> None:
294326 (i.e., intersects with the model domain at all).
295327
296328 Args:
297- ll_bounds : np.ndarray
329+ ll_bounds : np.ndarray SNWE bounding box
298330 """
299331 S , N , W , E = ll_bounds
300332 aoi = box (W , S , E , N )
@@ -306,13 +338,18 @@ def checkValidBounds(self, ll_bounds: np.ndarray) -> None:
306338 logger .critical ('The HRRR weather model extent does not completely cover your AOI!' )
307339
308340 else :
341+ logger .info ('The HRRR weather model extent does not include your AOI!' )
342+ logger .info ('Checking the HRRR-AK model.' )
309343 Mod = HRRRAK ()
310344 # valid bounds are in 0->360 to account for dateline crossing
311345 W , E = np .mod ([W , E ], 360 )
312346 aoi = box (W , S , E , N )
313347 if Mod ._valid_bounds .contains (aoi ):
314- pass
348+ self ._cast_to_hrrrak ()
349+ logger .info ('Casting self to the HRRR-AK weather model.' )
315350 elif aoi .intersects (Mod ._valid_bounds ):
351+ self ._cast_to_hrrrak ()
352+ logger .info ('Casting self to the HRRR-AK weather model.' )
316353 logger .critical ('The HRRR-AK weather model extent does not completely cover your AOI!' )
317354
318355 else :
@@ -391,3 +428,4 @@ def load_weather(self, f=None, *args, **kwargs) -> None:
391428 self ._lats = _lats
392429 self ._lons = _lons
393430 self ._proj = proj
431+
0 commit comments