138
138
track parameters"""
139
139
140
140
NEGLECT_LANDFALL_DURATION_HOUR = 4.5
141
- """Minimum landfall duration in hours from which to correct intensity. Perturbed systems
141
+ """Minimum landfall duration in hours from which to correct intensity. Perturbed systems
142
142
spending less time than this over land will not be adjusted for landfall effects"""
143
143
144
144
TRACK_EXTENSION_PARS = {
@@ -320,9 +320,9 @@ def calc_perturbed_trajectories(
320
320
max_sustained_wind) should be modelled. One of 'explicit',
321
321
'legacy_decay', or 'none'.
322
322
For 'explicit', intensity as well as radius_oci (outermost closed isobar)
323
- and radius_max_wind are statistically modelled depending on landfalls in
324
- historical and synthetic tracks (track intensification, peak intensity
325
- duration as well as intensity decay over the ocean and over land are
323
+ and radius_max_wind are statistically modelled depending on landfalls in
324
+ historical and synthetic tracks (track intensification, peak intensity
325
+ duration as well as intensity decay over the ocean and over land are
326
326
explicitly modelled).
327
327
For 'legacy_decay', a landfall decay is applied when a synthetic track
328
328
reached land; however when a synthetic track is over the ocean while its
@@ -366,12 +366,12 @@ def calc_perturbed_trajectories(
366
366
adjust_intensity = 'legacy_decay'
367
367
else :
368
368
LOGGER .warning ('decay is set to False - this sets adjust_intensity to "none" (as a string)' )
369
- adjust_intensity = 'none'
369
+ adjust_intensity = 'none'
370
370
if adjust_intensity is None :
371
371
adjust_intensity = 'explicit'
372
372
if adjust_intensity not in ['explicit' , 'legacy_decay' , 'none' ]:
373
373
raise ValueError ("adjust_intensity should be one of 'explicit', 'legacy_decay', 'none', or None" )
374
-
374
+
375
375
LOGGER .info ('Computing %s synthetic tracks.' , nb_synth_tracks * tracks .size )
376
376
377
377
pool = tracks .pool if pool is None else pool
@@ -554,7 +554,7 @@ def calc_perturbed_trajectories(
554
554
(
555
555
ocean_modelled_tracks ,
556
556
sid_extended_tracks_intensity ,
557
- sid_outside_lat_range ,
557
+ sid_outside_lat_range ,
558
558
sid_outside_intensity_range
559
559
) = _model_synth_tc_intensity (
560
560
tracks_list = tracks_list ,
@@ -744,7 +744,7 @@ def _get_random_trajectories_perts(tracks,
744
744
autocorr_dspeed ,
745
745
decay_ddirection_hourly ):
746
746
"""Generate random numbers for random walk
747
-
747
+
748
748
Parameters
749
749
----------
750
750
tracks : List
@@ -873,7 +873,7 @@ def _apply_random_walk_pert(track: xr.Dataset,
873
873
# apply initial location shift
874
874
new_lon [0 ] = track .lon .values [0 ] + xy_ini [0 ]
875
875
new_lat [0 ] = track .lat .values [0 ] + xy_ini [1 ]
876
-
876
+
877
877
# apply perturbations along the track segments
878
878
for i in range (n_seg ):
879
879
new_lon [i + 1 ], new_lat [i + 1 ] = \
@@ -1147,9 +1147,9 @@ def _get_shift_idx_start(on_land_hist, on_land_synth, time_step_h, shift_values_
1147
1147
first_sea_hist = np .where (~ on_land_hist )[0 ][0 ]
1148
1148
first_sea_synth = np .where (~ on_land_synth )[0 ][0 ]
1149
1149
if on_land_synth [0 ] and on_land_hist [0 ]:
1150
-
1150
+
1151
1151
# 0) Both tracks start over land: shift values such as to match first point over the ocean.
1152
-
1152
+
1153
1153
shift_first_sea = first_sea_synth - first_sea_hist
1154
1154
# no modelling needed before first synth landfall or first hist landfall.
1155
1155
idx_start_model_hist = idx_lf_hist [0 ]
@@ -1257,7 +1257,7 @@ def _get_shift_idx_start(on_land_hist, on_land_synth, time_step_h, shift_values_
1257
1257
# else:
1258
1258
# idx_start_model = ftr_hist -
1259
1259
# np.floor(TIME_MODEL_BEFORE_HIST_LF_H/time_step_h)
1260
-
1260
+
1261
1261
# account for shift and buffer for historical landfall
1262
1262
if idx_start_model_hist < nts :
1263
1263
idx_start_model_hist = max (0 , min (
@@ -1320,7 +1320,7 @@ def _create_raw_track_extension(track,
1320
1320
time_step_h ,
1321
1321
values_df : pd .DataFrame = None ):
1322
1322
"""Append new time steps to a track.
1323
-
1323
+
1324
1324
For a TC track, create a new track starting at the end of the original
1325
1325
track, with a given number of time steps and optionally some variables
1326
1326
values set. Longitude/Latitude are all constant and set to the last values
@@ -1732,7 +1732,7 @@ def _add_fits_to_track(track: xr.Dataset, central_pressure_pert: float):
1732
1732
attributes to track.
1733
1733
1734
1734
The input 'track' is modified in-place!
1735
-
1735
+
1736
1736
The following variables are fitted: Maximum sustained wind, radius of
1737
1737
maximum winds and radius of outmost closed isobar.
1738
1738
@@ -1745,11 +1745,11 @@ def _add_fits_to_track(track: xr.Dataset, central_pressure_pert: float):
1745
1745
A single TC track.
1746
1746
central_pressure_pert : float
1747
1747
Maximum perturbations in central pressure. Used to determine the range
1748
- of pressure values over which to fit data.
1748
+ of pressure values over which to fit data.
1749
1749
1750
1750
Returns
1751
1751
-------
1752
- track : xr.Dataset
1752
+ track : xr.Dataset
1753
1753
Same as input parameter track but with additional attributes 'fit_intens' and
1754
1754
'fit_decay' (see _get_fit_single_phase). If intensification and/or decay
1755
1755
consist of less than 3 data points, the corresponding attribute is not set.
@@ -1765,7 +1765,7 @@ def _add_fits_to_track(track: xr.Dataset, central_pressure_pert: float):
1765
1765
track .attrs ['fit_intens' ] = fit_attrs_intens
1766
1766
if warning_slope_intens is not None :
1767
1767
warning_slope += ["%s intensification %s" % (track .sid , warning_slope_intens )]
1768
- if where_max_intensity [- 1 ] < len (pcen ) - 4 :
1768
+ if where_max_intensity [- 1 ] < len (pcen ) - 4 :
1769
1769
track_decay = track [dict (time = slice (where_max_intensity [- 1 ],None ))]
1770
1770
fit_attrs_decay , warning_slope_decay = _get_fit_single_phase (track_decay , central_pressure_pert )
1771
1771
track .attrs ['fit_decay' ] = fit_attrs_decay
@@ -1780,7 +1780,7 @@ def _add_fits_to_track(track: xr.Dataset, central_pressure_pert: float):
1780
1780
def _get_fit_single_phase (track_sub , central_pressure_pert ):
1781
1781
"""Calculate order and fit of variables to be modelled for a temporal subset
1782
1782
of a track.
1783
-
1783
+
1784
1784
The following variables are fitted: Maximum sustained wind, radius of
1785
1785
maximum winds and radius of outmost closed isobar.
1786
1786
@@ -1793,7 +1793,7 @@ def _get_fit_single_phase(track_sub, central_pressure_pert):
1793
1793
A temporal subset of a single TC track.
1794
1794
central_pressure_pert : float
1795
1795
Maximum perturbations in central pressure. Used to determine the range
1796
- of pressure values over which to fit data.
1796
+ of pressure values over which to fit data.
1797
1797
1798
1798
Returns
1799
1799
-------
@@ -2334,7 +2334,7 @@ def _add_id_synth_chunks_shift_init(track: xr.Dataset,
2334
2334
2335
2335
Returns
2336
2336
-------
2337
- track : xr.Dataset
2337
+ track : xr.Dataset
2338
2338
as input parameter track but with additional variable 'id_chunk'
2339
2339
(ID of chunks value per track point) and, if shift_values_init is True,
2340
2340
with variables shifted in time if the first track point over the ocean
@@ -2432,7 +2432,7 @@ def _one_model_synth_tc_intensity(track: xr.Dataset,
2432
2432
Sequentially moves over each unique track["id_chunk"] and applies the following:
2433
2433
* If id_chunk is negative, i.e. over land, applies landfall decay logic
2434
2434
* if id_chunk is positive, i.e. over sea, applies intensification/peak duration/decay logic
2435
-
2435
+
2436
2436
# TODO update docstring
2437
2437
2438
2438
Parameters
@@ -2463,15 +2463,15 @@ def _one_model_synth_tc_intensity(track: xr.Dataset,
2463
2463
check_id_chunk (track ['id_chunk' ].values , track .sid , allow_missing = False )
2464
2464
if np .all (track ['id_chunk' ] == 0 ):
2465
2465
return track , values_ext_df
2466
-
2466
+
2467
2467
# organise chunks to be processed in temporal sequence
2468
2468
chunk_index = np .unique (track .id_chunk .values , return_index = True )[1 ]
2469
2469
id_chunk_sorted = [track .id_chunk .values [index ] for index in sorted (chunk_index )]
2470
2470
# track_orig = track.copy()
2471
2471
2472
2472
last_pcen = track .central_pressure .values [- 1 ]
2473
2473
track_orig = track .copy (deep = True )
2474
-
2474
+
2475
2475
for id_chunk in id_chunk_sorted :
2476
2476
if id_chunk == 0 :
2477
2477
continue
@@ -2539,7 +2539,7 @@ def _model_synth_tc_intensity(tracks_list,
2539
2539
for (track ,_ ) in tracks_intensified
2540
2540
]
2541
2541
return (
2542
- new_tracks_list ,
2542
+ new_tracks_list ,
2543
2543
sid_extended_tracks ,
2544
2544
sid_outside_lat_range ,
2545
2545
sid_outside_intensity_range
@@ -2581,7 +2581,7 @@ def _model_synth_tc_intensity(tracks_list,
2581
2581
if track .orig_event_flag :
2582
2582
tracks_intensified_new2 .append (track )
2583
2583
continue
2584
-
2584
+
2585
2585
if np .sum (np .isnan (track ['id_chunk' ].values )) == 0 :
2586
2586
# no track extension
2587
2587
_estimate_params_track (track )
@@ -2637,7 +2637,7 @@ def _model_synth_tc_intensity(tracks_list,
2637
2637
f'Central pressure: { pcen_extend [- 1 ]} .'
2638
2638
)
2639
2639
_estimate_params_track (track )
2640
-
2640
+
2641
2641
# cutoff track end?
2642
2642
extended_cat = np .array ([
2643
2643
climada .hazard .tc_tracks .set_category (
@@ -2647,7 +2647,7 @@ def _model_synth_tc_intensity(tracks_list,
2647
2647
for idx in range (track .time .size )
2648
2648
])
2649
2649
2650
- if np .any (extended_cat >= 0 ):
2650
+ if np .any (extended_cat >= 0 ):
2651
2651
# Kill the extended track 12 hours after dropping below Cat 1
2652
2652
buffer_frames = int (np .ceil (12 / time_step_h ))
2653
2653
cutoff_idx = min (np .where (extended_cat >= 0 )[0 ][- 1 ] + buffer_frames , extended_cat .size - 1 )
@@ -2662,7 +2662,7 @@ def _model_synth_tc_intensity(tracks_list,
2662
2662
track = track .isel (time = slice (None , advisory_range_et_idx ))
2663
2663
sid_outside_intensity_range .append (track .sid )
2664
2664
sid_outside_intensity_range = list (set (sid_outside_intensity_range ))
2665
-
2665
+
2666
2666
# If the child storm weakens below the parent's final strength, kill it
2667
2667
intensityrange_out_idx = _get_finalintensity_idx (track , original_track = tracks_list [i ])
2668
2668
intensityrange_out_idx = max (original_size , intensityrange_out_idx )
@@ -2671,13 +2671,13 @@ def _model_synth_tc_intensity(tracks_list,
2671
2671
track = track .isel (time = slice (None , intensityrange_out_idx ))
2672
2672
sid_outside_intensity_range .append (track .sid )
2673
2673
sid_outside_intensity_range = list (set (sid_outside_intensity_range ))
2674
-
2674
+
2675
2675
tracks_intensified_new2 .append (track )
2676
2676
tracks_intensified_new2 [i ].attrs ['category' ] = climada .hazard .tc_tracks .set_category (
2677
2677
tracks_intensified_new2 [i ].max_sustained_wind .values ,
2678
2678
tracks_intensified_new2 [i ].max_sustained_wind_unit
2679
2679
)
2680
-
2680
+
2681
2681
LOGGER .debug ('dropping temporary variables' )
2682
2682
new_tracks_list = [
2683
2683
drop_temporary_variables (track , track_vars_attrs )
@@ -2760,11 +2760,11 @@ def intensity_evolution_sea(track, id_chunk, central_pressure_pert, rnd_pars_i):
2760
2760
track ['central_pressure' ][in_chunk ] = track ['central_pressure' ].values [in_chunk - 1 ]
2761
2761
return pcen_extend
2762
2762
track_stage_end = 'intens'
2763
-
2763
+
2764
2764
# taking last value before the chunk as a starting point from where to model intensity
2765
2765
if in_chunk [0 ] > 0 :
2766
2766
in_chunk = np .append (in_chunk [0 ]- 1 , in_chunk )
2767
-
2767
+
2768
2768
track_chunk = track .isel (time = in_chunk )
2769
2769
pcen = track_chunk .central_pressure .values
2770
2770
time_days = np .append (0 , np .cumsum (track_chunk .time_step .values [1 :] / 24 ))
@@ -2773,7 +2773,7 @@ def intensity_evolution_sea(track, id_chunk, central_pressure_pert, rnd_pars_i):
2773
2773
# perturb target central pressure: truncated normal distribution
2774
2774
target_peak_pert = central_pressure_pert / 2 * scipy .stats .truncnorm .ppf (rnd_pars_i [0 ], - 2 , 2 )
2775
2775
target_peak = track_chunk .target_central_pressure .values [0 ] + target_peak_pert
2776
-
2776
+
2777
2777
if os .getenv ('TRACKGEN_TEST_BIAS_TARGET_PRESSURE' ):
2778
2778
target_pressure_bias = float (os .getenv ('TRACKGEN_TEST_BIAS_TARGET_PRESSURE' ))
2779
2779
if target_pressure_bias > 0 :
@@ -3083,7 +3083,7 @@ def intensity_evolution_land(track, id_chunk, v_rel, p_rel, s_rel):
3083
3083
pcen_extend = p_landfall * p_decay_extend
3084
3084
3085
3085
# correct limits
3086
- np . warnings .filterwarnings ('ignore' )
3086
+ warnings .filterwarnings ('ignore' )
3087
3087
cor_p = track_chunk .central_pressure .values > track_chunk .environmental_pressure .values
3088
3088
track_chunk .central_pressure [cor_p ] = track_chunk .environmental_pressure [cor_p ]
3089
3089
track_chunk .max_sustained_wind [track_chunk .max_sustained_wind < 0 ] = 0
@@ -3179,7 +3179,7 @@ def _get_peak_idx(pcen):
3179
3179
3180
3180
def _get_outside_lat_idx (track ):
3181
3181
"""Get the index of the first track point located too poleward or equatorward
3182
-
3182
+
3183
3183
A track point with unrealistically high wind speed for its latitude is
3184
3184
considered to be too poleward or too equatorward.
3185
3185
@@ -3219,9 +3219,9 @@ def _get_outside_lat_idx(track):
3219
3219
return latrange_out_idx
3220
3220
3221
3221
def _get_finalintensity_idx (track , original_track ):
3222
- '''Get the index of the frame where the synthetic track's central
3223
- pressure first goes above source track's final central pressure (or
3224
- the source track's maximum pressure reacheed after its minimum pressure,
3222
+ '''Get the index of the frame where the synthetic track's central
3223
+ pressure first goes above source track's final central pressure (or
3224
+ the source track's maximum pressure reacheed after its minimum pressure,
3225
3225
whichever is higher). This is usually the last frame.'''
3226
3226
original_pres = original_track .central_pressure .values
3227
3227
min_idx = np .where (original_pres == np .min (original_pres ))[0 ][- 1 ]
0 commit comments