def decluster(self, catalogue, config): """ :param catalogue: Catalogue of earthquakes :type catalogue: Dictionary :param config: Configation parameters :type config: Dictionary :returns: **vcl vector** indicating cluster number, **vmain_shock catalog** containing non-clustered events, **flagvector** indicating which eq events belong to a cluster :rtype: numpy.ndarray """ # Get relevent parameters neq = len(catalogue['magnitude']) # Number of earthquakes # Get decimal year (needed for time windows) year_dec = decimal_year( catalogue['year'], catalogue['month'], catalogue['day']) # Get space and time windows corresponding to each event sw_space, sw_time = \ time_dist_windows[config['window_opt']].\ calc(catalogue['magnitude']) eqid = np.arange(0, neq, 1) # Initial Position Identifier # Pre-allocate cluster index vectors vcl = np.zeros(neq, dtype=int) #print catalogue['magnitude'], year_dec # Sort magnitudes into descending order id0 = np.flipud(np.argsort(catalogue['magnitude'], kind='heapsort')) #m = m[id0] #catalog_matrix = catalog_matrix[id0, :] mag = catalogue['magnitude'][id0] longitude = catalogue['longitude'][id0] latitude = catalogue['latitude'][id0] sw_space = sw_space[id0] sw_time = sw_time[id0] year_dec = year_dec[id0] eqid = eqid[id0] flagvector = np.zeros(neq, dtype=int) #Begin cluster identification clust_index = 0 for i in range(0, neq - 1): if vcl[i] == 0: #print vcl[i], mag, neq # Find Events inside both fore- and aftershock time windows dt = year_dec - year_dec[i] vsel = np.logical_and( dt >= (-sw_time[i] * config['fs_time_prop']), dt <= sw_time[i], flagvector == 0) # Of those events inside time window, find those inside distance # window vsel1 = haversine(longitude, latitude, longitude[i], latitude[i]) <= sw_space[i] vsel[vsel] = vsel1 temp_vsel = np.copy(vsel) temp_vsel[i] = False if any(temp_vsel): # Allocate a cluster number vcl[vsel] = clust_index + 1 flagvector[vsel] = 1 # For those events in the cluster before the main event, # flagvector is equal to -1 temp_vsel[dt >= 0.0] = False flagvector[temp_vsel] = -1 flagvector[i] = 0 clust_index += 1 # Re-sort the catalog_matrix into original order id1 = np.argsort(eqid, kind='heapsort') eqid = eqid[id1] #catalog_matrix = catalog_matrix[id1, :] vcl = vcl[id1] flagvector = flagvector[id1] return vcl, flagvector
def decluster(self, catalogue, config): '''catalogue_matrix, window_opt=TDW_GARDNERKNOPOFF, time_window=60.): :param catalog_matrix: eq catalog in a matrix format with these columns in order: `year`, `month`, `day`, `longitude`, `latitude`, `Mw` :type catalog_matrix: numpy.ndarray :keyword window_opt: method used in calculating distance and time windows :type window_opt: string :keyword time_window: Length (in days) of moving time window :type time_window: positive float :returns: **vcl vector** indicating cluster number, **vmain_shock catalog** containing non-clustered events, **flagvector** indicating which eq events belong to a cluster :rtype: numpy.ndarray ''' #Convert time window from days to decimal years time_window = config['time_window'] / 365. # Pre-processing steps are the same as for Gardner & Knopoff # Get relevent parameters mag = catalogue['magnitude'] neq = np.shape(magnitude)[0] # Number of earthquakes # Get decimal year (needed for time windows) year_dec = decimal_year(catalogue['year'], catalogue['month'], catalogue['day']) # Get space windows corresponding to each event sw_space = time_dist_windows[config['window_opt']].calc(mag)[0] eqid = np.arange(0, neq, 1) # Initial Position Identifier # Pre-allocate cluster index vectors vcl = np.zeros((neq, 1), dtype=int) flagvector = np.zeros((neq, 1), dtype=int) # Sort magnitudes into descending order id0 = np.flipud(np.argsort(mag, kind='heapsort')) mag = mag[id0] #catalogue_matrix = catalogue_matrix[id0, :] longitude = catalogue['longitude'][id0] latitude = catalogue['latitude'][id0] sw_space = sw_space[id0] year_dec = year_dec[id0] eqid = eqid[id0] i = 0 clust_index = 0 while i < neq: if vcl[i] == 0: # Earthquake not allocated to cluster - perform calculation # Perform distance calculation mdist = haversine(longitude, latitude, longitude[i], latitude[i]) # Select earthquakes inside distance window and not in cluster vsel = np.logical_and(mdist <= sw_space[i], vcl == 0).flatten() dtime = year_dec[vsel] - year_dec[i] nval = np.shape(dtime)[0] #Number of events inside valid window # Pre-allocate boolean array (all True) vsel1 = self._find_aftershocks(dtime, nval, time_window) vsel2 = self._find_foreshocks(dtime, nval, time_window, vsel1) temp_vsel = np.copy(vsel) temp_vsel[vsel] = np.logical_or(vsel1, vsel2) if np.shape(np.nonzero(temp_vsel)[0])[0] > 1: # Contains clustered events - allocate a cluster index vcl[temp_vsel] = clust_index + 1 # Remove mainshock from cluster vsel1[0] = False # Assign markers to aftershocks and foreshocks temp_vsel = np.copy(vsel) temp_vsel[vsel] = vsel1 flagvector[temp_vsel] = 1 vsel[vsel] = vsel2 flagvector[vsel] = -1 clust_index += 1 i += 1 # Now have events - re-sort array back into chronological order # Re-sort the data into original order id1 = np.argsort(eqid, kind='heapsort') eqid = eqid[id1] #catalogue_matrix = catalogue_matrix[id1, :] vcl = vcl[id1] flagvector = flagvector[id1] return vcl.flatten(), flagvector.flatten()
def afteran_decluster( catalogue_matrix, window_opt=TDW_GARDNERKNOPOFF, time_window=60.): '''AFTERAN declustering algorithm. ||(Musson, 1999, "Probabilistic Seismic Hazard Maps for the North Balkan region", Annali di Geofisica, 42(6), 1109 - 1124) || :param catalog_matrix: eq catalog in a matrix format with these columns in order: `year`, `month`, `day`, `longitude`, `latitude`, `Mw` :type catalog_matrix: numpy.ndarray :keyword window_opt: method used in calculating distance and time windows :type window_opt: string :keyword time_window: Length (in days) of moving time window :type time_window: positive float :returns: **vcl vector** indicating cluster number, **vmain_shock catalog** containing non-clustered events, **flagvector** indicating which eq events belong to a cluster :rtype: numpy.ndarray ''' #Convert time window from days to decimal years time_window = time_window / 365. # Pre-processing steps are the same as for Gardner & Knopoff # Get relevent parameters mag = catalogue_matrix[:, 5] neq = np.shape(catalogue_matrix)[0] # Number of earthquakes # Get decimal year (needed for time windows) year_dec = decimal_year(catalogue_matrix[:, 0], catalogue_matrix[:, 1], catalogue_matrix[:, 2]) # Get space windows corresponding to each event sw_space = time_dist_windows[window_opt].calc(mag)[0] eqid = np.arange(0, neq, 1) # Initial Position Identifier # Pre-allocate cluster index vectors vcl = np.zeros((neq, 1), dtype=int) flagvector = np.zeros((neq, 1), dtype=int) # Sort magnitudes into descending order id0 = np.flipud(np.argsort(mag, kind='heapsort')) mag = mag[id0] catalogue_matrix = catalogue_matrix[id0, :] sw_space = sw_space[id0] year_dec = year_dec[id0] eqid = eqid[id0] i = 0 clust_index = 0 while i < neq: if vcl[i] == 0: # Earthquake not allocated to cluster - perform calculation # Perform distance calculation mdist = haversine(catalogue_matrix[:, 3], catalogue_matrix[:, 4], catalogue_matrix[i, 3], catalogue_matrix[i, 4]) # Select earthquakes inside distance window and not in cluster vsel = np.logical_and(mdist <= sw_space[i], vcl == 0).flatten() dtime = year_dec[vsel] - year_dec[i] nval = np.shape(dtime)[0] # Number of events inside valid window # Pre-allocate boolean array (all True) vsel1 = _find_aftershocks(dtime, nval, time_window) vsel2 = _find_foreshocks(dtime, nval, time_window, vsel1) temp_vsel = np.copy(vsel) temp_vsel[vsel] = np.logical_or(vsel1, vsel2) if np.shape(np.nonzero(temp_vsel)[0])[0] > 1: # Contains clustered events - allocate a cluster index vcl[temp_vsel] = clust_index + 1 # Remove mainshock from cluster vsel1[0] = False # Assign markers to aftershocks and foreshocks temp_vsel = np.copy(vsel) temp_vsel[vsel] = vsel1 flagvector[temp_vsel] = 1 vsel[vsel] = vsel2 flagvector[vsel] = -1 clust_index += 1 i += 1 # Now have events - re-sort array back into chronological order # Re-sort the data into original order id1 = np.argsort(eqid, kind='heapsort') eqid = eqid[id1] catalogue_matrix = catalogue_matrix[id1, :] vcl = vcl[id1] flagvector = flagvector[id1] # Now to produce a catalogue with aftershocks purged vmain_shock = catalogue_matrix[np.nonzero(flagvector == 0)[0], :] return vcl.flatten(), vmain_shock, flagvector.flatten()