Skip to content

Commit f9cd50d

Browse files
add wind speed selection
1 parent fea61a2 commit f9cd50d

File tree

2 files changed

+70
-34
lines changed

2 files changed

+70
-34
lines changed

climada/hazard/tc_tracks.py

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2873,54 +2873,77 @@ def _zlib_from_dataarray(data_var: xr.DataArray) -> bool:
28732873
def compute_track_density(
28742874
tc_track: TCTracks,
28752875
res: int = 5,
2876-
time_step: float = 1,
28772876
density: bool = False,
28782877
filter_tracks: bool = True,
2878+
wind_min: float = None,
2879+
wind_max: float = None,
28792880
) -> tuple[np.ndarray, tuple]:
2880-
"""Compute absolute and normalized tropical cyclone track density. First, the function ensure
2881-
the same temporal resolution of all tracks by calling :py:meth:`equal_timestep`. Second, it
2882-
creates 2D bins of the specified resolution (e.g. 1° x 1°). Third, since tracks are not lines
2883-
but a series of points, it counts the number of points per bin. Lastly, it returns the absolute
2884-
or normalized count per bin. This function works under the hood of :py:meth:`plot_track_density`
2885-
but can be used separtly as input data for more sophisticated track density plots.
2886-
If filter track is True, only a maximum of one point is added to each grid cell for every track.
2887-
Hence, the resulting density will represent the number of differt tracksper grid cell.
2881+
"""Compute absolute and normalized tropical cyclone track density. Before using this function,
2882+
apply the same temporal resolution to all tracks by calling :py:meth:`equal_timestep` on the
2883+
TCTrack object. Due to the computational cost of the this function, it is not recommended to
2884+
use a grid resolution higher tha 0.1°. This function it creates 2D bins of the specified
2885+
resolution (e.g. 1° x 1°). Second, since tracks are not lines but a series of points, it counts
2886+
the number of points per bin. Lastly, it returns the absolute or normalized count per bin.
2887+
To plot the output of this function use :py:meth:`plot_track_density`.
28882888
28892889
Parameters:
28902890
----------
28912891
res: int (optional) Default: 5°
28922892
resolution in degrees of the grid bins in which the density will be computed
2893-
time_step: float (optional) default: 1h
2894-
temporal resolution in hours to be apllied to the tracks, to ensure that every track
2895-
will have the same resolution.
28962893
density: bool (optional) default: False
28972894
If False it returns the number of samples in each bin. If True, returns the
28982895
probability density function at each bin computed as count_bin / tot_count.
28992896
filter_tracks: bool (optional) default: True
29002897
If True the track density is computed as the number of different tracks crossing a grid
29012898
cell. If False, the track density takes into account how long the track stayed in each
29022899
grid cell. Hence slower tracks increase the density if the parameter is set to False.
2903-
2900+
wind_min: float (optional) default: None
2901+
Minimum wind speed above which to select tracks.
2902+
wind_max: float (optional) default: None
2903+
Maximal wind speed below which to select tracks.
29042904
Returns:
29052905
-------
2906-
hist: 2D np.ndarray
2906+
hist: 2D np.ndwind_speeday
29072907
2D matrix containing the track density
29082908
"""
29092909

2910-
# ensure equal time step
2911-
# tc_track.equal_timestep(time_step_h=time_step)
2910+
limit_ratio = 1.12 * 1.1 # record tc speed 112km/h -> 1.12°/h + 10% margin
2911+
2912+
if tc_track.data[0].time_step[0].item() > res / limit_ratio:
2913+
warnings.warn(
2914+
f"The time step is too big. For the desired resolution, apply a time step \n"
2915+
"of {res/limit_ratio}h."
2916+
)
2917+
elif res < 0.01:
2918+
warnings.warn(
2919+
"The resolution is too high. The computation might take several minutes \n"
2920+
"to hours. Consider using a resolution below 0.1°."
2921+
)
29122922

2913-
# Define grid resolution and bounds for density computation
2923+
# define grid resolution and bounds for density computation
29142924
lat_bins = np.linspace(-90, 90, int(180 / res))
29152925
lon_bins = np.linspace(-180, 180, int(360 / res))
2916-
2917-
# Compute 2D density
2926+
# compute 2D density
29182927
hist_count = csr_matrix((len(lat_bins) - 1, len(lon_bins) - 1))
29192928
for track in tc_track.data:
29202929

2921-
# Compute 2D density
2930+
# select according to wind speed
2931+
wind_speed = track.max_sustained_wind.values
2932+
if wind_min and wind_max:
2933+
index = np.where((wind_speed >= wind_min) & (wind_speed <= wind_max))[0]
2934+
elif wind_min and not wind_max:
2935+
index = np.where(wind_speed >= wind_min)[0]
2936+
elif wind_max and not wind_min:
2937+
index = np.where(wind_speed <= wind_max)[0]
2938+
else:
2939+
index = slice(None) # select all the track
2940+
2941+
# compute 2D density
29222942
hist_new, _, _ = np.histogram2d(
2923-
track.lat.values, track.lon.values, bins=[lat_bins, lon_bins], density=False
2943+
track.lat.values[index],
2944+
track.lon.values[index],
2945+
bins=[lat_bins, lon_bins],
2946+
density=False,
29242947
)
29252948
hist_new = csr_matrix(hist_new)
29262949
hist_new[hist_new > 1] = 1 if filter_tracks else hist_new

climada/hazard/test/test_tc_tracks.py

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,15 +1203,15 @@ def test_track_land_params(self):
12031203
)
12041204

12051205
def test_compute_density_tracks(self):
1206-
"""Test :py:meth:`compute_track_density` to ensure proper density count."""
1206+
"""Test `compute_track_density` to ensure proper density count."""
12071207
# create track
12081208
track = xr.Dataset(
12091209
{
12101210
"time_step": ("time", np.timedelta64(1, "h") * np.arange(4)),
1211-
"max_sustained_wind": ("time", [3600, 3600, 3600, 3600]),
1212-
"central_pressure": ("time", [3600, 3600, 3600, 3600]),
1213-
"radius_max_wind": ("time", [3600, 3600, 3600, 3600]),
1214-
"environnmental_pressure": ("time", [3600, 3600, 3600, 3600]),
1211+
"max_sustained_wind": ("time", [10, 20, 30, 20]),
1212+
"central_pressure": ("time", [1, 1, 1, 1]),
1213+
"radius_max_wind": ("time", [1, 1, 1, 1]),
1214+
"environnmental_pressure": ("time", [1, 1, 1, 1]),
12151215
"basin": ("time", ["NA", "NA", "NA", "NA"]),
12161216
},
12171217
coords={
@@ -1233,23 +1233,36 @@ def test_compute_density_tracks(self):
12331233

12341234
tc_tracks = tc.TCTracks([track])
12351235

1236-
hist_abs, lat_bins, lon_bins = tc.compute_track_density(
1237-
tc_tracks, time_step=1, res=10, density=False
1236+
hist_abs, *_ = tc.compute_track_density(
1237+
tc_tracks,
1238+
res=10,
1239+
density=False,
12381240
)
1239-
hist_norm, lat_bins, lon_bins = tc.compute_track_density(
1240-
tc_tracks, time_step=1, res=10, density=True
1241+
hist_norm, *_ = tc.compute_track_density(tc_tracks, res=10, density=True)
1242+
hist_wind_min, *_ = tc.compute_track_density(
1243+
tc_tracks, res=10, density=False, wind_min=11, wind_max=None
1244+
)
1245+
hist_wind_max, *_ = tc.compute_track_density(
1246+
tc_tracks, res=10, density=False, wind_min=None, wind_max=30
1247+
)
1248+
hist_wind_max, *_ = tc.compute_track_density(
1249+
tc_tracks, res=10, density=False, wind_min=None, wind_max=30
1250+
)
1251+
hist_wind_both, *_ = tc.compute_track_density(
1252+
tc_tracks, res=10, density=False, wind_min=11, wind_max=29
12411253
)
12421254
self.assertEqual(hist_abs.shape, (17, 35))
12431255
self.assertEqual(hist_norm.shape, (17, 35))
12441256
self.assertEqual(hist_abs.sum(), 4)
12451257
self.assertEqual(hist_norm.sum(), 1)
1258+
self.assertEqual(hist_wind_min.sum(), 3)
1259+
self.assertEqual(hist_wind_max.sum(), 4)
1260+
self.assertEqual(hist_wind_both.sum(), 2)
12461261
# the track above occupy positions [0,0:4] of hist
1247-
np.testing.assert_array_equal(
1248-
hist_abs.toarray()[0, 0:4], [1, 1, 1, 1]
1249-
) # .toarray()
1262+
np.testing.assert_array_equal(hist_abs.toarray()[0, 0:4], [1, 1, 1, 1])
12501263
np.testing.assert_array_equal(
12511264
hist_norm.toarray()[0, 0:4], [0.25, 0.25, 0.25, 0.25]
1252-
) # .toarray()
1265+
)
12531266

12541267

12551268
# Execute Tests

0 commit comments

Comments
 (0)