Skip to content

Commit 5eada5e

Browse files
committed
adding the Courtney Knaff 2009 regression method for filling Pc, changing the assunption on translation speed units to kts, this needs revisiting to be sure
1 parent c9ee79b commit 5eada5e

File tree

3 files changed

+72
-3
lines changed

3 files changed

+72
-3
lines changed

stormevents/nhc/const.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ class PcFillMethod(Enum):
1616
none = None
1717
persistent_holland_b = auto()
1818
regression_chavas_2025 = auto()
19+
regression_courtney_knaff_2009 = auto()
1920

2021

21-
# constants for the regression Pc fill method
22+
# constants for the Chavas et al. (2025) regression Pc fill method
2223
OMEGA = 7.292e-5 # [1/s]
2324
BETA_00 = -6.60
2425
BETA_V20 = -0.0127

stormevents/nhc/track.py

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
13021348
def 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

tests/test_nhc.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,3 +566,20 @@ def test_pc_fill_method_regression_chavas_2025():
566566
"central_pressure"
567567
]
568568
assert len(pc.unique()) == 11
569+
570+
571+
def test_pc_fill_method_regression_courtney_knaff_2009():
572+
tr_florence2018 = VortexTrack.from_storm_name(
573+
"Florence",
574+
2018,
575+
file_deck="a",
576+
advisories=["OFCL"],
577+
pc_fill=PcFillMethod.regression_courtney_knaff_2009,
578+
)
579+
assert tr_florence2018.pc_fill == PcFillMethod.regression_courtney_knaff_2009
580+
data = tr_florence2018.data
581+
i_uq_row = 40
582+
pc = data.loc[data.track_start_time == data.track_start_time.unique()[i_uq_row]][
583+
"central_pressure"
584+
]
585+
assert len(pc.unique()) == 11

0 commit comments

Comments
 (0)