@@ -1287,6 +1287,55 @@ def correct_ofcl_based_on_carq_n_hollandb(
12871287 def clamp (n , minn , maxn ):
12881288 return max (min (maxn , n ), minn )
12891289
1290+ def movingmean (dff ):
1291+ fcsthr_index = dff ["forecast_hours" ].drop_duplicates ().index
1292+ df_temp = dff .loc [fcsthr_index ].copy ()
1293+ # make sure 60, 84, and 108 are added
1294+ fcsthrs_12hr = numpy .unique (
1295+ numpy .append (df_temp ["forecast_hours" ].values , [60 , 84 , 108 ])
1296+ )
1297+ rmw_12hr = numpy .interp (
1298+ fcsthrs_12hr ,
1299+ df_temp ["forecast_hours" ],
1300+ df_temp ["radius_of_maximum_winds" ],
1301+ )
1302+ dt_12hr = pandas .to_datetime (
1303+ fcsthrs_12hr , unit = "h" , origin = df_temp ["datetime" ].iloc [0 ]
1304+ )
1305+ df_temp = DataFrame (
1306+ data = {
1307+ "forecast_hours" : fcsthrs_12hr ,
1308+ "radius_of_maximum_winds" : rmw_12hr ,
1309+ },
1310+ index = dt_12hr ,
1311+ )
1312+ rmw_rolling = df_temp .rolling (window = "24h1min" , center = True , min_periods = 1 )[
1313+ "radius_of_maximum_winds"
1314+ ].mean ()
1315+ for valid_time , rmw in rmw_rolling .items ():
1316+ valid_index = dff ["datetime" ] == valid_time
1317+ if (
1318+ valid_index .sum () == 0
1319+ or dff .loc [valid_index , "forecast_hours" ].iloc [0 ] == 0
1320+ ):
1321+ continue
1322+ # make sure rolling rmw is not larger than the maximum radii of the strongest isotach
1323+ # this problem usually comes from the rolling average
1324+ max_isotach_radii = isotach_radii .loc [valid_index ].iloc [- 1 ].max ()
1325+ if rmw < max_isotach_radii or numpy .isnan (max_isotach_radii ):
1326+ dff .loc [valid_index , "radius_of_maximum_winds" ] = rmw
1327+ # in case it does not come from rolling average just set to be Vr/Vmax ratio of max_isotach_radii
1328+ if (
1329+ dff .loc [valid_index , "radius_of_maximum_winds" ].iloc [- 1 ]
1330+ > max_isotach_radii
1331+ ):
1332+ dff .loc [valid_index , "radius_of_maximum_winds" ] = (
1333+ max_isotach_radii
1334+ * dff .loc [valid_index , "isotach_radius" ].iloc [- 1 ]
1335+ / dff .loc [valid_index , "max_sustained_wind_speed" ].iloc [- 1 ]
1336+ )
1337+ return dff
1338+
12901339 ofcl_tracks = tracks ["OFCL" ]
12911340 carq_tracks = tracks ["CARQ" ]
12921341
@@ -1327,7 +1376,10 @@ def clamp(n, minn, maxn):
13271376 "radius_of_maximum_winds"
13281377 ]
13291378
1330- elif rmw_fill == RMWFillMethod .regression_penny_2023 :
1379+ elif (
1380+ rmw_fill == RMWFillMethod .regression_penny_2023_with_smoothing
1381+ or rmw_fill == RMWFillMethod .regression_penny_2023_no_smoothing
1382+ ):
13311383 # fill OFCL maximum wind radius based on regression method from
13321384 # Penny et al. (2023). https://doi.org/10.1175/WAF-D-22-0209.1
13331385 isotach_radii = forecast [
@@ -1383,52 +1435,8 @@ def clamp(n, minn, maxn):
13831435 rmw_ , 5.0 , max (120.0 , rmw0 )
13841436 )
13851437 # apply 24-HR moving mean to unique datetimes
1386- fcsthr_index = forecast ["forecast_hours" ].drop_duplicates ().index
1387- df_temp = forecast .loc [fcsthr_index ].copy ()
1388- # make sure 60, 84, and 108 are added
1389- fcsthrs_12hr = numpy .unique (
1390- numpy .append (df_temp ["forecast_hours" ].values , [60 , 84 , 108 ])
1391- )
1392- rmw_12hr = numpy .interp (
1393- fcsthrs_12hr ,
1394- df_temp ["forecast_hours" ],
1395- df_temp ["radius_of_maximum_winds" ],
1396- )
1397- dt_12hr = pandas .to_datetime (
1398- fcsthrs_12hr , unit = "h" , origin = df_temp ["datetime" ].iloc [0 ]
1399- )
1400- df_temp = DataFrame (
1401- data = {
1402- "forecast_hours" : fcsthrs_12hr ,
1403- "radius_of_maximum_winds" : rmw_12hr ,
1404- },
1405- index = dt_12hr ,
1406- )
1407- rmw_rolling = df_temp .rolling (window = "24.01 h" , center = True , min_periods = 1 )[
1408- "radius_of_maximum_winds"
1409- ].mean ()
1410- for valid_time , rmw in rmw_rolling .items ():
1411- valid_index = forecast ["datetime" ] == valid_time
1412- if (
1413- valid_index .sum () == 0
1414- or forecast .loc [valid_index , "forecast_hours" ].iloc [0 ] == 0
1415- ):
1416- continue
1417- # make sure rolling rmw is not larger than the maximum radii of the strongest isotach
1418- # this problem usually comes from the rolling average
1419- max_isotach_radii = isotach_radii .loc [valid_index ].iloc [- 1 ].max ()
1420- if rmw < max_isotach_radii or numpy .isnan (max_isotach_radii ):
1421- forecast .loc [valid_index , "radius_of_maximum_winds" ] = rmw
1422- # in case it does not come from rolling average just set to be Vr/Vmax ratio of max_isotach_radii
1423- if (
1424- forecast .loc [valid_index , "radius_of_maximum_winds" ].iloc [- 1 ]
1425- > max_isotach_radii
1426- ):
1427- forecast .loc [valid_index , "radius_of_maximum_winds" ] = (
1428- max_isotach_radii
1429- * forecast .loc [valid_index , "isotach_radius" ].iloc [- 1 ]
1430- / forecast .loc [valid_index , "max_sustained_wind_speed" ].iloc [- 1 ]
1431- )
1438+ if rmw_fill == RMWFillMethod .regression_penny_2023_with_smoothing :
1439+ forecast = movingmean (forecast )
14321440
14331441 # fill OFCL background pressure with the first entry from 0-hr CARQ background pressure (at sea level)
14341442 forecast .loc [radp_missing , "background_pressure" ] = carq_ref [
0 commit comments