@@ -1270,8 +1270,8 @@ def chavas_2025_Pc(data: DataFrame):
12701270 """
12711271
12721272 fo2 = OMEGA * numpy .sin (numpy .deg2rad (data .latitude )) # half coriolis [1/s]
1273- Vmax = (
1274- data .max_sustained_wind_speed * 0.5144 - 0.55 * data .speed
1273+ Vmax = 0.5144 * (
1274+ data .max_sustained_wind_speed - 0.55 * data .speed
12751275 ) # azimuthal mean Vmax [m/s]
12761276 isotach_radii = data [
12771277 [
@@ -1299,6 +1299,52 @@ def chavas_2025_Pc(data: DataFrame):
12991299 return data .background_pressure + 2 + deltaP # Pc
13001300
13011301
1302+ def courtney_knaff_2009_Pc (data : DataFrame ):
1303+ """
1304+ perform the Courtney & Knaff (2009) regression method for filling in central pressure
1305+ Ref:
1306+ Courtney, J. & Knaff, J. (2009).
1307+ Adapting the Knaff and Zehr wind-pressure relationship for operational use in Tropical Cyclone Warning Centers.
1308+ Australian Meteorological and Oceanographic Journal, 58, 167-179.
1309+ https://connectsci.au/es/article/58/3/167/264593/Adapting-the-Knaff-and-Zehr-wind-pressure
1310+
1311+ :param data: data frame of track with missing entries
1312+ :return: central pressure values
1313+ """
1314+
1315+ Vmax = data .max_sustained_wind_speed # Vmax [kt]
1316+ Vsrm = Vmax - 1.5 * data .speed ** 0.63 # azimuthal mean Vmax [kt]
1317+ isotach_radii = data [
1318+ [
1319+ "isotach_radius_for_NEQ" ,
1320+ "isotach_radius_for_SEQ" ,
1321+ "isotach_radius_for_NWQ" ,
1322+ "isotach_radius_for_SWQ" ,
1323+ ]
1324+ ]
1325+ # make any 0 value NaN
1326+ isotach_radii [isotach_radii == 0 ] = pandas .NA
1327+ R34 = 0.85 * isotach_radii .mean (axis = 1 ) # average R34 radius [n mi]
1328+ # forward fill to fill in 50-kt and 64-kt rows with the R34 value as
1329+ R34 [data .isotach_radius > 35 ] = pandas .NA
1330+ R34 [data .isotach_radius > 35 ] = R34 .ffill ()[data .isotach_radius > 35 ]
1331+ V500 = R34 / 9 - 3 # wind speed at 500 km radius
1332+ lat = data .latitude # latitude [deg]
1333+ x = 0.1147 + 0.0055 * Vmax - 0.001 * (lat - 25 )
1334+ Rmax = 66.785 - 0.09102 * Vmax + 1.0619 * (lat - 25 )
1335+ V500c = Vmax * (Rmax / 500 ) ** x # climatological wind speed at 500 km radius
1336+ S = V500 / V500c # normalized storm size
1337+ S [(S < 0.4 ) | (S .isna ())] = 0.4 # lower bound/default value of 0.4
1338+ # equation for lat >= 18 deg
1339+ deltaP = (
1340+ 23.286 - 0.483 * Vsrm - (Vsrm / 24.524 ) ** 2 - 12.587 * S - 0.483 * lat
1341+ ) # [hPa]
1342+ # equation for lat < 18 deg
1343+ deltaP_lo = 5.962 - 0.267 * Vsrm - (Vsrm / 18.26 ) ** 2 - 6.8 * S # [hPa]
1344+ deltaP [lat < 18 ] = deltaP_lo [lat < 18 ]
1345+ return data .background_pressure + 2 + deltaP # Pc
1346+
1347+
13021348def separate_tracks (data : DataFrame ) -> Dict [str , Dict [str , DataFrame ]]:
13031349 """
13041350 separate the given track data frame into advisories and tracks (forecasts / hindcasts)
@@ -1539,6 +1585,11 @@ def movingmean(dff):
15391585 forecast .loc [mslp_missing , "central_pressure" ] = chavas_2025_Pc (
15401586 forecast .loc [mslp_missing , :]
15411587 )
1588+ elif pc_fill == PcFillMethod .regression_courtney_knaff_2009 :
1589+ # use the Courtney & Knaff (2009) regression method
1590+ forecast .loc [mslp_missing , "central_pressure" ] = courtney_knaff_2009_Pc (
1591+ forecast .loc [mslp_missing , :]
1592+ )
15421593
15431594 corr_ofcl_tracks [initial_time ] = forecast
15441595
0 commit comments