def set_from_tracks(self, tracks, centroids=None, dist_degree=3, description=''): """Computes rainfield from tracks based on the RCLIPER model. Parallel process. Parameters: tracks (TCTracks): tracks of events centroids (Centroids, optional): Centroids where to model TC. Default: global centroids. disr_degree (int): distance (in degrees) from node within which the rainfield is processed (default 3 deg,~300km) description (str, optional): description of the events """ num_tracks = tracks.size if centroids is None: centroids = Centroids.from_base_grid(res_as=360, land=True) if not centroids.coord.size: centroids.set_meta_to_lat_lon() LOGGER.info('Mapping %s tracks to %s centroids.', str(tracks.size), str(centroids.size)) if self.pool: chunksize = min(num_tracks // self.pool.ncpus, 1000) tc_haz = self.pool.map(self._set_from_track, tracks.data, itertools.repeat(centroids, num_tracks), itertools.repeat(dist_degree, num_tracks), itertools.repeat(self.intensity_thres, num_tracks), chunksize=chunksize) else: tc_haz = list() for track in tracks.data: tc_haz.append( self._set_from_track(track, centroids, dist_degree=dist_degree, intensity=self.intensity_thres)) LOGGER.debug('Append events.') self.concatenate(tc_haz) LOGGER.debug('Compute frequency.') TropCyclone.frequency_from_tracks(self, tracks.data) self.tag.description = description
def test_base_grid(self): """Read new centroids using from_base_grid, then select by extent.""" centroids = Centroids.from_base_grid(land=True, res_as=150) self.assertEqual(centroids.lat.size, 8858035) self.assertTrue(np.all(np.diff(centroids.lat) <= 0)) count_sandwich = np.sum(centroids.region_id == 239) self.assertEqual(count_sandwich, 321) count_sgi = centroids.select( reg_id=239, extent=(-39, -34.7, -55.5, -53.6) # south georgia island ).size self.assertEqual(count_sgi, 296) # test negative latitudinal orientation by testing that northern hemisphere (Russia) # is listed before southern hemisphere (South Africa) russia_max_idx = (centroids.region_id == 643).nonzero()[0].max() safrica_min_idx = (centroids.region_id == 710).nonzero()[0].min() self.assertTrue(russia_max_idx < safrica_min_idx)
def set_from_tracks(self, tracks, centroids=None, description='', model='H08', ignore_distance_to_coast=False, store_windfields=False, metric="equirect"): """ Clear and fill with windfields from specified tracks. This function sets the `TropCyclone.intensity` attribute to contain, for each centroid, the maximum wind speed (1-minute sustained winds at 10 meters above ground) experienced over the whole period of each TC event in m/s. The wind speed is set to 0 if it doesn't exceed the threshold in `TropCyclone.intensity_thres`. The `TropCyclone.category` attribute is set to the value of the `category`-attribute of each of the given track data sets. The `TropCyclone.basin` attribute is set to the genesis basin for each event, which is the first value of the `basin`-variable in each of the given track data sets. Optionally, the time dependent, vectorial winds can be stored using the `store_windfields` function parameter (see below). Parameters ---------- tracks : TCTracks Tracks of storm events. centroids : Centroids, optional Centroids where to model TC. Default: global centroids at 360 arc-seconds resolution. description : str, optional Description of the event set. Default: "". model : str, optional Parametric wind field model to use: one of "H1980" (the prominent Holland 1980 model), "H08" (Holland 1980 with b-value from Holland 2008), or "H10" (Holland et al. 2010). Default: "H08". ignore_distance_to_coast : boolean, optional If True, centroids far from coast are not ignored. Default: False. store_windfields : boolean, optional If True, the Hazard object gets a list `windfields` of sparse matrices. For each track, the full velocity vectors at each centroid and track position are stored in a sparse matrix of shape (npositions, ncentroids * 2) that can be reshaped to a full ndarray of shape (npositions, ncentroids, 2). Default: False. metric : str, optional Specify an approximation method to use for earth distances: * "equirect": Distance according to sinusoidal projection. Fast, but inaccurate for large distances and high latitudes. * "geosphere": Exact spherical distance. Much more accurate at all distances, but slow. Default: "equirect". Raises ------ ValueError """ num_tracks = tracks.size if centroids is None: centroids = Centroids.from_base_grid(res_as=360, land=False) if not centroids.coord.size: centroids.set_meta_to_lat_lon() if ignore_distance_to_coast: # Select centroids with lat < 61 coastal_idx = (np.abs(centroids.lat) < 61).nonzero()[0] else: # Select centroids which are inside INLAND_MAX_DIST_KM and lat < 61 if not centroids.dist_coast.size: centroids.set_dist_coast() coastal_idx = ((centroids.dist_coast < INLAND_MAX_DIST_KM * 1000) & (np.abs(centroids.lat) < 61)).nonzero()[0] # Restrict to coastal centroids within reach of any of the tracks t_lon_min, t_lat_min, t_lon_max, t_lat_max = tracks.get_bounds( deg_buffer=CENTR_NODE_MAX_DIST_DEG) t_mid_lon = 0.5 * (t_lon_min + t_lon_max) coastal_centroids = centroids.coord[coastal_idx] u_coord.lon_normalize(coastal_centroids[:, 1], center=t_mid_lon) coastal_idx = coastal_idx[((t_lon_min <= coastal_centroids[:, 1]) & (coastal_centroids[:, 1] <= t_lon_max) & (t_lat_min <= coastal_centroids[:, 0]) & (coastal_centroids[:, 0] <= t_lat_max))] LOGGER.info('Mapping %s tracks to %s coastal centroids.', str(tracks.size), str(coastal_idx.size)) if self.pool: chunksize = min(num_tracks // self.pool.ncpus, 1000) tc_haz = self.pool.map(self._tc_from_track, tracks.data, itertools.repeat(centroids, num_tracks), itertools.repeat(coastal_idx, num_tracks), itertools.repeat(model, num_tracks), itertools.repeat(store_windfields, num_tracks), itertools.repeat(metric, num_tracks), chunksize=chunksize) else: last_perc = 0 tc_haz = [] for track in tracks.data: perc = 100 * len(tc_haz) / len(tracks.data) if perc - last_perc >= 10: LOGGER.info("Progress: %d%%", perc) last_perc = perc self.append( self._tc_from_track(track, centroids, coastal_idx, model=model, store_windfields=store_windfields, metric=metric)) if last_perc < 100: LOGGER.info("Progress: 100%") LOGGER.debug('Compute frequency.') self.frequency_from_tracks(tracks.data) self.tag.description = description
def set_from_tracks(self, tracks, centroids=None, description='', model='H08', ignore_distance_to_coast=False, store_windfields=False): """Clear and fill with windfields from specified tracks. Parameters: tracks (TCTracks): tracks of events centroids (Centroids, optional): Centroids where to model TC. Default: global centroids. description (str, optional): description of the events model (str, optional): model to compute gust. Default Holland2008. ignore_distance_to_coast (boolean, optional): if True, centroids far from coast are not ignored. Default False store_windfields (boolean, optional): If True, the Hazard object gets a list `windfields` of sparse matrices. For each track, the full velocity vectors at each centroid and track position are stored in a sparse matrix of shape (npositions, ncentroids * 2), that can be reshaped to a full ndarray of shape (npositions, ncentroids, 2). Default: False. Raises: ValueError """ num_tracks = tracks.size if centroids is None: centroids = Centroids.from_base_grid(res_as=360, land=False) if not centroids.coord.size: centroids.set_meta_to_lat_lon() if ignore_distance_to_coast: # Select centroids with lat < 61 coastal_idx = (np.abs(centroids.lat) < 61).nonzero()[0] else: # Select centroids which are inside INLAND_MAX_DIST_KM and lat < 61 if not centroids.dist_coast.size: centroids.set_dist_coast() coastal_idx = ((centroids.dist_coast < INLAND_MAX_DIST_KM * 1000) & (np.abs(centroids.lat) < 61)).nonzero()[0] LOGGER.info('Mapping %s tracks to %s centroids.', str(tracks.size), str(coastal_idx.size)) if self.pool: chunksize = min(num_tracks // self.pool.ncpus, 1000) tc_haz = self.pool.map(self._tc_from_track, tracks.data, itertools.repeat(centroids, num_tracks), itertools.repeat(coastal_idx, num_tracks), itertools.repeat(model, num_tracks), itertools.repeat(store_windfields, num_tracks), chunksize=chunksize) else: last_perc = 0 tc_haz = [] for track in tracks.data: perc = 100 * len(tc_haz) / len(tracks.data) if perc - last_perc >= 10: LOGGER.info("Progress: %d%%", perc) last_perc = perc tc_haz.append( self._tc_from_track(track, centroids, coastal_idx, model=model, store_windfields=store_windfields)) LOGGER.debug('Append events.') self.concatenate(tc_haz) LOGGER.debug('Compute frequency.') self.frequency_from_tracks(tracks.data) self.tag.description = description
def set_from_tracks(self, tracks, centroids=None, description='', model='H08', ignore_distance_to_coast=False, store_windfields=False, metric="equirect"): """Clear and fill with windfields from specified tracks. Parameters ---------- tracks : TCTracks Tracks of storm events. centroids : Centroids, optional Centroids where to model TC. Default: global centroids at 360 arc-seconds resolution. description : str, optional Description of the event set. Default: "". model : str, optional Model to compute gust. Currently only 'H08' is supported for the one implemented in `_stat_holland` according to Greg Holland. Default: "H08". ignore_distance_to_coast : boolean, optional If True, centroids far from coast are not ignored. Default: False. store_windfields : boolean, optional If True, the Hazard object gets a list `windfields` of sparse matrices. For each track, the full velocity vectors at each centroid and track position are stored in a sparse matrix of shape (npositions, ncentroids * 2) that can be reshaped to a full ndarray of shape (npositions, ncentroids, 2). Default: False. metric : str, optional Specify an approximation method to use for earth distances: * "equirect": Distance according to sinusoidal projection. Fast, but inaccurate for large distances and high latitudes. * "geosphere": Exact spherical distance. Much more accurate at all distances, but slow. Default: "equirect". Raises ------ ValueError """ num_tracks = tracks.size if centroids is None: centroids = Centroids.from_base_grid(res_as=360, land=False) if not centroids.coord.size: centroids.set_meta_to_lat_lon() if ignore_distance_to_coast: # Select centroids with lat < 61 coastal_idx = (np.abs(centroids.lat) < 61).nonzero()[0] else: # Select centroids which are inside INLAND_MAX_DIST_KM and lat < 61 if not centroids.dist_coast.size: centroids.set_dist_coast() coastal_idx = ((centroids.dist_coast < INLAND_MAX_DIST_KM * 1000) & (np.abs(centroids.lat) < 61)).nonzero()[0] # Restrict to coastal centroids within reach of any of the tracks t_lon_min, t_lat_min, t_lon_max, t_lat_max = tracks.get_bounds( deg_buffer=CENTR_NODE_MAX_DIST_DEG) t_mid_lon = 0.5 * (t_lon_min + t_lon_max) coastal_centroids = centroids.coord[coastal_idx] u_coord.lon_normalize(coastal_centroids[:, 1], center=t_mid_lon) coastal_idx = coastal_idx[((t_lon_min <= coastal_centroids[:, 1]) & (coastal_centroids[:, 1] <= t_lon_max) & (t_lat_min <= coastal_centroids[:, 0]) & (coastal_centroids[:, 0] <= t_lat_max))] LOGGER.info('Mapping %s tracks to %s coastal centroids.', str(tracks.size), str(coastal_idx.size)) if self.pool: chunksize = min(num_tracks // self.pool.ncpus, 1000) tc_haz = self.pool.map( self._tc_from_track, tracks.data, itertools.repeat(centroids, num_tracks), itertools.repeat(coastal_idx, num_tracks), itertools.repeat(model, num_tracks), itertools.repeat(store_windfields, num_tracks), itertools.repeat(metric, num_tracks), chunksize=chunksize) else: last_perc = 0 tc_haz = [] for track in tracks.data: perc = 100 * len(tc_haz) / len(tracks.data) if perc - last_perc >= 10: LOGGER.info("Progress: %d%%", perc) last_perc = perc tc_haz.append( self._tc_from_track(track, centroids, coastal_idx, model=model, store_windfields=store_windfields, metric=metric)) if last_perc < 100: LOGGER.info("Progress: 100%") LOGGER.debug('Append events.') self.concatenate(tc_haz) LOGGER.debug('Compute frequency.') self.frequency_from_tracks(tracks.data) self.tag.description = description