def test_dist_mat_km(self):
     """Test spacial clustering."""
     from eqcorrscan.utils.clustering import dist_mat_km
     from obspy.clients.fdsn import Client
     from obspy import UTCDateTime
     client = Client("IRIS")
     starttime = UTCDateTime("2002-01-01")
     endtime = UTCDateTime("2002-01-02")
     cat = client.get_events(starttime=starttime, endtime=endtime,
                             minmagnitude=6, catalog="ISC")
     dist_mat = dist_mat_km(cat)
     self.assertEqual(len(dist_mat), len(cat))
Exemple #2
0
 def test_dist_mat_km(self):
     """Test spacial clustering."""
     dist_mat = dist_mat_km(self.cat)
     self.assertEqual(len(dist_mat), len(self.cat))
     # Diagonal should be zeros
     self.assertTrue(np.all(dist_mat.diagonal() == 0))
     # Should be symmetric
     for i in range(len(self.cat)):
         for j in range(len(self.cat)):
             self.assertEqual(dist_mat[i, j], dist_mat[j, i])
             master_ori = (self.cat[i].preferred_origin()
                           or self.cat[i].origins[0])
             slave_ori = (self.cat[j].preferred_origin()
                          or self.cat[j].origins[0])
             self.assertAlmostEqual(
                 dist_mat[i, j],
                 dist_calc((master_ori.latitude, master_ori.longitude,
                            master_ori.depth / 1000),
                           (slave_ori.latitude, slave_ori.longitude,
                            slave_ori.depth / 1000)), 6)
Exemple #3
0
def compute_differential_times(catalog,
                               correlation,
                               stream_dict=None,
                               event_id_mapper=None,
                               max_sep=8.,
                               min_link=8,
                               min_cc=None,
                               extract_len=None,
                               pre_pick=None,
                               shift_len=None,
                               interpolate=False,
                               max_workers=None,
                               *args,
                               **kwargs):
    """
    Generate groups of differential times for a catalog.

    :type catalog: `obspy.core.event.Catalog`
    :param catalog: Catalog of events to get differential times for
    :type correlation: bool
    :param correlation:
        If True will generate cross-correlation derived differential-times for
        a dt.cc file. If false, will generate catalog times for a dt.ct file.
    :type stream_dict: dict
    :param stream_dict:
        Dictionary of streams keyed by event-id (the event.resource_id.id,
        NOT the hypoDD event-id)
    :type event_id_mapper: dict
    :param event_id_mapper:
        Dictionary mapping event resource id to an integer event id for hypoDD.
        If this is None, or missing events then the dictionary will be updated
        to include appropriate event-ids. This should be of the form
        {event.resource_id.id: integer_id}
    :type max_sep: float
    :param max_sep: Maximum hypocentral separation in km to link events
    :type min_link: int
    :param min_link: Minimum shared phase observations to link events
    :type min_cc: float
    :param min_cc: Threshold to include cross-correlation results.
    :type extract_len: float
    :param extract_len: Length in seconds to extract around the pick
    :type pre_pick: float
    :param pre_pick: Time before the pick to start the correlation window
    :type shift_len: float
    :param shift_len:
        Time (+/-) to allow pick to vary in seconds. e.g. if shift_len
        is set to 1s, the pick will be allowed to shift between
        pick_time - 1 and pick_time + 1.
    :type interpolate: bool
    :param interpolate:
        Whether to interpolate correlations or not. Allows subsample accuracy
    :type max_workers: int
    :param max_workers:
        Maximum number of workers for parallel processing. If None then all
        threads will be used - only used if correlation = True

    :rtype: dict
    :return: Dictionary of differential times keyed by event id.
    :rtype: dict
    :return: Dictionary of event_id_mapper

    .. note::
        The arguments min_cc, stream_dict, extract_len, pre_pick, shift_len
        and interpolate are only required if correlation=True.
    """
    include_master = kwargs.get("include_master", False)
    correlation_kwargs = dict(min_cc=min_cc,
                              stream_dict=stream_dict,
                              extract_len=extract_len,
                              pre_pick=pre_pick,
                              shift_len=shift_len,
                              interpolate=interpolate,
                              max_workers=max_workers)
    if correlation:
        for arg, name in correlation_kwargs.items():
            assert arg is not None, "{0} is required for correlation".format(
                name)
    # Ensure all events have locations and picks.
    event_id_mapper = _generate_event_id_mapper(
        catalog=catalog, event_id_mapper=event_id_mapper)
    distances = dist_mat_km(catalog)
    distance_filter = distances <= max_sep
    if not include_master:
        np.fill_diagonal(distance_filter, 0)
        # Do not match events to themselves - this is the default,
        # only included for testing

    additional_args = dict(min_link=min_link, event_id_mapper=event_id_mapper)
    if correlation:
        differential_times = {}
        additional_args.update(correlation_kwargs)
        n = len(catalog)
        for i, master in enumerate(catalog):
            master_id = master.resource_id.id
            sub_catalog = [
                ev for j, ev in enumerate(catalog) if distance_filter[i][j]
            ]
            if master_id not in additional_args["stream_dict"].keys():
                Logger.warning(f"{master_id} not in waveforms, skipping")
                continue
            differential_times.update({
                master_id:
                _compute_dt_correlations(sub_catalog, master,
                                         **additional_args)
            })
            Logger.info(f"Completed correlations for core event {i} of {n}")
    else:
        # Reformat catalog to sparse catalog
        sparse_catalog = [_make_sparse_event(ev) for ev in catalog]

        sub_catalogs = ([
            ev for i, ev in enumerate(sparse_catalog) if master_filter[i]
        ] for master_filter in distance_filter)
        differential_times = {
            master.resource_id: _compute_dt(sub_catalog, master,
                                            **additional_args)
            for master, sub_catalog in zip(sparse_catalog, sub_catalogs)
        }

    # Remove Nones
    for key, value in differential_times.items():
        differential_times.update({key: [v for v in value if v is not None]})
    return differential_times, event_id_mapper
Exemple #4
0
 def test_dist_mat_km(self):
     """Test spacial clustering."""
     dist_mat = dist_mat_km(self.cat)
     self.assertEqual(len(dist_mat), len(self.cat))
Exemple #5
0
def decluster_distance_time(peaks,
                            index,
                            trig_int,
                            catalog,
                            hypocentral_separation,
                            threshold=0):
    """
    Decluster based on time between peaks, and distance between events.

    Peaks, index and catalog must all be sorted the same way, e.g. peak[i]
    corresponds to index[i] and catalog[i]. Peaks that are within the time
    threshold of one-another, but correspond to events separated by more than
    the hypocentral_separation threshold will not be removed.

    :type peaks: np.array
    :param peaks: array of peak values
    :type index: np.ndarray
    :param index: locations of peaks
    :type trig_int: int
    :param trig_int: Minimum trigger interval in samples
    :type catalog: obspy.core.event.Catalog
    :param catalog:
        Catalog of events with origins to use to measure inter-event distances
    :type hypocentral_separation: float
    :param hypocentral_separation:
        Maximum inter-event distance to decluster over in km
    :type threshold: float
    :param threshold: Minimum absolute peak value to retain it

    :return: list of tuples of (value, sample)
    """
    utilslib = _load_cdll('libutils')

    length = peaks.shape[0]
    trig_int = int(trig_int)

    for var in [index.max(), trig_int]:
        if var == ctypes.c_long(var).value:
            long_type = ctypes.c_long
            func = utilslib.decluster_dist_time
        elif var == ctypes.c_longlong(var).value:
            long_type = ctypes.c_longlong
            func = utilslib.decluster_dist_time_ll
        else:
            raise OverflowError("Maximum index larger than internal long long")

    func.argtypes = [
        np.ctypeslib.ndpointer(dtype=np.float32,
                               shape=(length, ),
                               flags=native_str('C_CONTIGUOUS')),
        np.ctypeslib.ndpointer(dtype=long_type,
                               shape=(length, ),
                               flags=native_str('C_CONTIGUOUS')),
        np.ctypeslib.ndpointer(dtype=np.float32,
                               shape=(length * length, ),
                               flags=native_str('C_CONTIGUOUS')), long_type,
        ctypes.c_float, long_type, ctypes.c_float,
        np.ctypeslib.ndpointer(dtype=np.uint32,
                               shape=(length, ),
                               flags=native_str('C_CONTIGUOUS'))
    ]
    func.restype = ctypes.c_int

    sorted_inds = np.abs(peaks).argsort()
    # Sort everything in the same way.
    arr = peaks[sorted_inds[::-1]]
    inds = index[sorted_inds[::-1]]
    sorted_events = [catalog[i] for i in sorted_inds[::-1]]
    distance_matrix = dist_mat_km(catalog=sorted_events)

    arr = np.ascontiguousarray(arr, dtype=np.float32)
    inds = np.ascontiguousarray(inds, dtype=long_type)
    distance_matrix = np.ascontiguousarray(distance_matrix.flatten(order="C"),
                                           dtype=np.float32)
    out = np.zeros(len(arr), dtype=np.uint32)

    ret = func(arr, inds, distance_matrix, long_type(length),
               np.float32(threshold), long_type(trig_int),
               hypocentral_separation, out)
    if ret != 0:
        raise MemoryError("Issue with c-routine, returned %i" % ret)

    peaks_out = list(zip(arr[out.astype(bool)], inds[out.astype(bool)]))
    return peaks_out