示例#1
0
    def test_calcVincentyInverse2(self):
        """
        Test calc_vincenty_inverse() method with test data from Geocentric
        Datum of Australia. (see http://www.icsm.gov.au/gda/gdatm/gdav2.3.pdf)
        """
        # test data:
        # Point 1: Flinders Peak, Point 2: Buninyong
        lat1 = -(37 + (57 / 60.) + (3.72030 / 3600.))
        lon1 = 144 + (25 / 60.) + (29.52440 / 3600.)
        lat2 = -(37 + (39 / 60.) + (10.15610 / 3600.))
        lon2 = 143 + (55 / 60.) + (35.38390 / 3600.)
        dist = 54972.271
        alpha12 = 306 + (52 / 60.) + (5.37 / 3600.)
        alpha21 = 127 + (10 / 60.) + (25.07 / 3600.)

        # calculate result
        calc_dist, calc_alpha12, calc_alpha21 = calc_vincenty_inverse(
            lat1, lon1, lat2, lon2)

        # calculate deviations from test data
        dist_err_rel = abs(dist - calc_dist) / dist
        alpha12_err = abs(alpha12 - calc_alpha12)
        alpha21_err = abs(alpha21 - calc_alpha21)

        self.assertEqual(dist_err_rel < 1.0e-5, True)
        self.assertEqual(alpha12_err < 1.0e-5, True)
        self.assertEqual(alpha21_err < 1.0e-5, True)

        # calculate result with +- 360 for lon values
        dist, alpha12, alpha21 = calc_vincenty_inverse(
            lat1, lon1 + 360, lat2, lon2 - 720)
        self.assertAlmostEqual(dist, calc_dist)
        self.assertAlmostEqual(alpha12, calc_alpha12)
        self.assertAlmostEqual(alpha21, calc_alpha21)
示例#2
0
    def test_calc_vincenty_inverse_2(self):
        """
        Test calc_vincenty_inverse() method with test data from Geocentric
        Datum of Australia. (see http://www.icsm.gov.au/gda/gdatm/gdav2.3.pdf)
        """
        # test data:
        # Point 1: Flinders Peak, Point 2: Buninyong
        lat1 = -(37 + (57 / 60.) + (3.72030 / 3600.))
        lon1 = 144 + (25 / 60.) + (29.52440 / 3600.)
        lat2 = -(37 + (39 / 60.) + (10.15610 / 3600.))
        lon2 = 143 + (55 / 60.) + (35.38390 / 3600.)
        dist = 54972.271
        alpha12 = 306 + (52 / 60.) + (5.37 / 3600.)
        alpha21 = 127 + (10 / 60.) + (25.07 / 3600.)

        # calculate result
        calc_dist, calc_alpha12, calc_alpha21 = calc_vincenty_inverse(
            lat1, lon1, lat2, lon2)

        # calculate deviations from test data
        dist_err_rel = abs(dist - calc_dist) / dist
        alpha12_err = abs(alpha12 - calc_alpha12)
        alpha21_err = abs(alpha21 - calc_alpha21)

        self.assertEqual(dist_err_rel < 1.0e-5, True)
        self.assertEqual(alpha12_err < 1.0e-5, True)
        self.assertEqual(alpha21_err < 1.0e-5, True)

        # calculate result with +- 360 for lon values
        dist, alpha12, alpha21 = calc_vincenty_inverse(lat1, lon1 + 360, lat2,
                                                       lon2 - 720)
        self.assertAlmostEqual(dist, calc_dist)
        self.assertAlmostEqual(alpha12, calc_alpha12)
        self.assertAlmostEqual(alpha21, calc_alpha21)
示例#3
0
 def test_calc_vincenty_inverse(self):
     """
     Tests for the Vincenty's Inverse formulae.
     """
     # the following will raise StopIteration exceptions because of two
     # nearly antipodal points
     self.assertRaises(StopIteration, calc_vincenty_inverse, 15.26804251,
                       2.93007342, -14.80522806, -177.2299081)
     self.assertRaises(StopIteration, calc_vincenty_inverse, 27.3562106,
                       72.2382356, -27.55995499, -107.78571981)
     self.assertRaises(StopIteration, calc_vincenty_inverse, 27.4675551,
                       17.28133229, -27.65771704, -162.65420626)
     self.assertRaises(StopIteration, calc_vincenty_inverse, 27.4675551,
                       17.28133229, -27.65771704, -162.65420626)
     self.assertRaises(StopIteration, calc_vincenty_inverse, 0, 0, 0, 13)
     # working examples
     res = calc_vincenty_inverse(0, 0.2, 0, 20)
     self.assertAlmostEqual(res[0], 2204125.9174282863)
     self.assertAlmostEqual(res[1], 90.0)
     self.assertAlmostEqual(res[2], 270.0)
     res = calc_vincenty_inverse(0, 0, 0, 10)
     self.assertAlmostEqual(res[0], 1113194.9077920639)
     self.assertAlmostEqual(res[1], 90.0)
     self.assertAlmostEqual(res[2], 270.0)
     res = calc_vincenty_inverse(0, 0, 0, 17)
     self.assertAlmostEqual(res[0], 1892431.3432465086)
     self.assertAlmostEqual(res[1], 90.0)
     self.assertAlmostEqual(res[2], 270.0)
     # out of bounds
     self.assertRaises(ValueError, calc_vincenty_inverse, 91, 0, 0, 0)
     self.assertRaises(ValueError, calc_vincenty_inverse, -91, 0, 0, 0)
     self.assertRaises(ValueError, calc_vincenty_inverse, 0, 0, 91, 0)
     self.assertRaises(ValueError, calc_vincenty_inverse, 0, 0, -91, 0)
示例#4
0
 def test_calcVincentyInverse(self):
     """
     Tests for the Vincenty's Inverse formulae.
     """
     # the following will raise StopIteration exceptions because of two
     # nearly antipodal points
     self.assertRaises(StopIteration, calc_vincenty_inverse,
                       15.26804251, 2.93007342, -14.80522806, -177.2299081)
     self.assertRaises(StopIteration, calc_vincenty_inverse,
                       27.3562106, 72.2382356, -27.55995499, -107.78571981)
     self.assertRaises(StopIteration, calc_vincenty_inverse,
                       27.4675551, 17.28133229, -27.65771704, -162.65420626)
     self.assertRaises(StopIteration, calc_vincenty_inverse,
                       27.4675551, 17.28133229, -27.65771704, -162.65420626)
     self.assertRaises(StopIteration, calc_vincenty_inverse, 0, 0, 0, 13)
     # working examples
     res = calc_vincenty_inverse(0, 0.2, 0, 20)
     self.assertAlmostEqual(res[0], 2204125.9174282863)
     self.assertAlmostEqual(res[1], 90.0)
     self.assertAlmostEqual(res[2], 270.0)
     res = calc_vincenty_inverse(0, 0, 0, 10)
     self.assertAlmostEqual(res[0], 1113194.9077920639)
     self.assertAlmostEqual(res[1], 90.0)
     self.assertAlmostEqual(res[2], 270.0)
     res = calc_vincenty_inverse(0, 0, 0, 17)
     self.assertAlmostEqual(res[0], 1892431.3432465086)
     self.assertAlmostEqual(res[1], 90.0)
     self.assertAlmostEqual(res[2], 270.0)
     # out of bounds
     self.assertRaises(ValueError, calc_vincenty_inverse, 91, 0, 0, 0)
     self.assertRaises(ValueError, calc_vincenty_inverse, -91, 0, 0, 0)
     self.assertRaises(ValueError, calc_vincenty_inverse, 0, 0, 91, 0)
     self.assertRaises(ValueError, calc_vincenty_inverse, 0, 0, -91, 0)
def user_func(config, sta_info, origin, obsd_tr, synt_tr):

    npts = synt_tr.stats.npts

    base_water_level = config.stalta_waterlevel
    base_cc = config.cc_acceptance_level
    base_tshift = config.tshift_acceptance_level
    base_dlna = config.dlna_acceptance_level
    base_s2n = config.s2n_limit

    # turn parameters into arrays
    stalta_waterlevel = np.ones(npts) * base_water_level
    cc = np.ones(npts) * base_cc
    tshift = np.ones(npts) * base_tshift
    dlna = np.ones(npts) * base_dlna
    s2n = np.ones(npts) * base_s2n

    trace_info = sta_info.get_coordinates(synt_tr.id[:-1]+"Z")

    times = get_time_array(synt_tr, origin)
    dist_km = calc_vincenty_inverse(
        origin.latitude, origin.longitude,
        trace_info["latitude"], trace_info["longitude"])[0] / 1000

    # rayleigh
    r_vel = 3.2
    r_time = dist_km/r_vel
    r_index = None

    # Find index in time array of Rayleigh wave arrival
    r_index = (np.abs(times - r_time)).argmin() + 1
    s2n[r_index:] = 10 * base_s2n
    cc[r_index:] = 0.95
    tshift[r_index:] = base_tshift/3.0
    dlna[r_index:] = base_dlna/3.0
    stalta_waterlevel[r_index:] = base_water_level * 2.0

    # Check event depth
    # origin.depth is in meters
    if origin.depth > 70000 and origin.depth < 300000:  # intermediate
        tshift[:] = base_tshift * 1.4
    elif origin.depth > 300000:  # deep
        tshift[:] = base_tshift * 1.7

    # replace config vars
    new_config = copy.deepcopy(config)
    new_config.stalta_waterlevel = stalta_waterlevel
    new_config.tshift_acceptance_level = tshift
    new_config.dlna_acceptance_level = dlna
    new_config.cc_acceptance_level = cc
    new_config.s2n_limit = s2n
    new_config.signal_end_index = r_index

    return new_config
def get_dist_in_km(station, event, obsd):
    """
    Returns distance in km
    """
    stats = obsd.stats
    station_coor = station.get_coordinates(".".join([stats.network,
                                                     stats.station,
                                                     stats.location,
                                                     stats.channel[:-1]+"Z"]))

    evlat = event.events[0].origins[0].latitude
    evlon = event.events[0].origins[0].longitude

    dist = calc_vincenty_inverse(station_coor["latitude"],
                                 station_coor["longitude"],
                                 evlat, evlon)[0] / 1000

    return dist
示例#7
0
def select_windows(
    data_trace,
    synthetic_trace,
    stf_trace,
    event_latitude,
    event_longitude,
    station_latitude,
    station_longitude,
    minimum_period,
    maximum_period,
    min_cc=0.10,
    max_noise=0.10,
    max_noise_window=0.4,
    min_velocity=2.4,
    threshold_shift=0.30,
    threshold_correlation=0.75,
    min_length_period=1.5,
    min_peaks_troughs=2,
    max_energy_ratio=10.0,
    min_envelope_similarity=0.2,
    global_inversion=False,
    window_everything=False,
    verbose=False,
    plot=False,

):
    """
    Window selection algorithm for picking windows suitable for misfit
    calculation based on phase differences.

    Returns a list of windows which might be empty due to various reasons.

    This function is really long and a lot of things. For a more detailed
    description, please see the LASIF paper.

    :param data_trace: The data trace.
    :type data_trace: :class:`~obspy.core.trace.Trace`
    :param synthetic_trace: The synthetic trace.
    :type synthetic_trace: :class:`~obspy.core.trace.Trace`
    :param stf_trace: The stf trace.
    :type stf_trace: :class:`~obspy.core.trace.Trace`
    :param event_latitude: The event latitude.
    :type event_latitude: float
    :param event_longitude: The event longitude.
    :type event_longitude: float
    :param station_latitude: The station latitude.
    :type station_latitude: float
    :param station_longitude: The station longitude.
    :type station_longitude: float
    :param minimum_period: The minimum period of the data in seconds.
    :type minimum_period: float
    :param maximum_period: The maximum period of the data in seconds.
    :type maximum_period: float
    :param min_cc: Minimum normalised correlation coefficient of the
        complete traces.
    :type min_cc: float
    :param max_noise: Maximum relative noise level for the whole trace.
        Measured from maximum amplitudes before and after the first arrival.
    :type max_noise: float
    :param max_noise_window: Maximum relative noise level for individual
        windows.
    :type max_noise_window: float
    :param min_velocity: All arrivals later than those corresponding to the
        threshold velocity [km/s] will be excluded.
    :type min_velocity: float
    :param threshold_shift: Maximum allowable time shift within a window,
        as a fraction of the minimum period.
    :type threshold_shift: float
    :param threshold_correlation: Minimum normalised correlation coeeficient
        within a window.
    :type threshold_correlation: float
    :param min_length_period: Minimum length of the time windows relative to
        the minimum period.
    :type min_length_period: float
    :param min_peaks_troughs: Minimum number of extrema in an individual
        time window (excluding the edges).
    :type min_peaks_troughs: float
    :param max_energy_ratio: Maximum energy ratio between data and
        synthetics within a time window. Don't make this too small!
    :type max_energy_ratio: float
    :param min_envelope_similarity: The minimum similarity of the envelopes of
        both data and synthetics. This essentially assures that the
        amplitudes of data and synthetics can not diverge too much within a
        window. It is a bit like the inverse of the ratio of both envelopes
        so a value of 0.2 makes sure neither amplitude can be more then 5
        times larger than the other.
    :type min_envelope_similarity: float
    :param global_inversion: Don't perform any traveltime elimination at the
    end of the trace if set to True.
    :param global_inversion: bool
    :param window_everything: If set to True, windows the whole trace,
    if global acception criteria are met, such as the noise level in the trace.
    :type window_everything: bool
    :param verbose: No output by default.
    :type verbose: bool
    :param plot: Create a plot of the algortihm while it does its work.
    :type plot: bool
    """
    # Shortcuts to frequently accessed variables.
    data_starttime = data_trace.stats.starttime
    data_delta = data_trace.stats.delta
    dt = data_trace.stats.delta
    npts = data_trace.stats.npts
    synth = synthetic_trace.data
    data = data_trace.data
    times = data_trace.times()

    # Don't return any windows if there is a NaN
    if np.sum(np.isnan(data)) > 0 or np.sum(np.isnan(synth)) > 0:
        return []

    # -------------------------------------------------------------------------
    # Geographical calculations and the time of the first arrival.
    # -------------------------------------------------------------------------
    dist_in_km = (
        geodetics.calc_vincenty_inverse(
            station_latitude,
            station_longitude,
            event_latitude,
            event_longitude,
        )[0]
        / 1000.0
    )

    # -------------------------------------------------------------------------
    # Window settings
    # -------------------------------------------------------------------------
    # Number of samples in the sliding window. Currently, the length of the
    # window is set to a multiple of the dominant period of the synthetics.
    # Make sure it is an uneven number; just to have a trivial midpoint
    # definition and one sample does not matter much in any case.
    window_length = int(round(float(2 * minimum_period) / dt))
    if not window_length % 2:
        window_length += 1

    # Use a Hanning window. No particular reason for it but its a well-behaved
    # window and has nice spectral properties.
    taper = np.hanning(window_length)

    # =========================================================================
    # check if whole seismograms are sufficiently correlated and estimate
    # noise level
    # =========================================================================

    # Overall Correlation coefficient.
    norm = np.sqrt(np.sum(data ** 2)) * np.sqrt(np.sum(synth ** 2))
    cc = np.sum(data * synth) / norm
    if verbose:
        _log_window_selection(
            data_trace.id, "Correlation Coefficient: %.4f" % cc
        )

    first_tt_arrival = np.where(np.abs(synth) > 5e-3 * np.max(np.abs(synth)))[0][0]
    idx_end = int(0.9 * first_tt_arrival)
    idx_end = max(idx_end, 1) # ensure at least 1 sample is available
    idx_start = 0

    if idx_start >= idx_end:
        idx_start = max(0, idx_end - 10)

    abs_data = np.abs(data)

    # Return empty window when no data is available
    if np.max(abs_data) == 0.0 or np.max(np.abs(synth)) == 0.0:
        return []

    noise_absolute = abs_data[idx_start:idx_end].max()
    noise_relative = noise_absolute / abs_data.max()

    if verbose:
        _log_window_selection(
            data_trace.id, "Absolute Noise Level: %e" % noise_absolute
        )
        _log_window_selection(
            data_trace.id, "Relative Noise Level: %e" % noise_relative
        )

    # Basic global rejection criteria.
    accept_traces = True
    if (cc < min_cc) and (noise_relative > max_noise / 3.0):
        msg = "Correlation %.4f is below threshold of %.4f" % (cc, min_cc)
        if verbose:
            _log_window_selection(data_trace.id, msg)
        accept_traces = msg

    if noise_relative > max_noise:
        msg = "Noise level %.3f is above threshold of %.3f" % (
            noise_relative,
            max_noise,
        )
        if verbose:
            _log_window_selection(data_trace.id, msg)
        accept_traces = msg

    minimum_distance = 2 * minimum_period * min_velocity
    if dist_in_km < minimum_distance:
        msg = "Source - Receiver distance %.3f is below threshold of %.3f" % (
            dist_in_km,
            minimum_distance,
        )
        if verbose:
            _log_window_selection(data_trace.id, msg)
        accept_traces = msg

    # Calculate the envelope of both data and synthetics. This is to make sure
    # that the amplitude of both is not too different over time and is
    # used as another selector. Only calculated if the trace is generally
    # accepted as it is fairly slow.
    if accept_traces is True:
        data_env = obspy.signal.filter.envelope(data)
        synth_env = obspy.signal.filter.envelope(synth)

    # -------------------------------------------------------------------------
    # Initial Plot setup.
    # -------------------------------------------------------------------------
    # All the plot calls are interleaved. I realize this is really ugly but
    # the alternative would be to either have two functions (one with plots,
    # one without) or split the plotting function in various subfunctions,
    # neither of which are acceptable in my opinion. The impact on
    # performance is minimal if plotting is turned off: all imports are lazy
    # and a couple of conditionals are cheap.
    if plot:
        import matplotlib.pylab as plt  # NOQA
        import matplotlib.patheffects as PathEffects  # NOQA

        if accept_traces is True:
            plt.figure(figsize=(18, 12))
            plt.subplots_adjust(
                left=0.05,
                bottom=0.05,
                right=0.98,
                top=0.95,
                wspace=None,
                hspace=0.0,
            )
            grid = (31, 1)

            # Axes showing the data.
            data_plot = plt.subplot2grid(grid, (0, 0), rowspan=8)
        else:
            # Only show one axes it the traces are not accepted.
            plt.figure(figsize=(18, 3))

        # Plot envelopes if needed.
        if accept_traces is True:
            plt.plot(
                times,
                data_env,
                color="black",
                alpha=0.5,
                lw=0.4,
                label="data envelope",
            )
            plt.plot(
                synthetic_trace.times(),
                synth_env,
                color="#e41a1c",
                alpha=0.4,
                lw=0.5,
                label="synthetics envelope",
            )

        plt.plot(times, data, color="black", label="data", lw=1.5)
        plt.plot(
            synthetic_trace.times(),
            synth,
            color="#e41a1c",
            label="synthetics",
            lw=1.5,
        )

        # Symmetric around y axis.
        middle = data.mean()
        d_max, d_min = data.max(), data.min()
        r = max(d_max - middle, middle - d_min) * 1.1
        ylim = (middle - r, middle + r)
        xlim = (times[0], times[-1])
        plt.ylim(*ylim)
        plt.xlim(*xlim)

        offset = (xlim[1] - xlim[0]) * 0.005
        plt.vlines(first_tt_arrival, ylim[0], ylim[1], colors="#ff7f00", lw=2)
        plt.text(
            first_tt_arrival + offset,
            ylim[1] - (ylim[1] - ylim[0]) * 0.02,
            "first arrival",
            verticalalignment="top",
            horizontalalignment="left",
            color="#ee6e00",
            path_effects=[
                PathEffects.withStroke(linewidth=3, foreground="white")
            ],
        )

        plt.vlines(
            first_tt_arrival - minimum_period / 2.0,
            ylim[0],
            ylim[1],
            colors="#ff7f00",
            lw=2,
        )
        plt.text(
            first_tt_arrival - minimum_period / 2.0 - offset,
            ylim[0] + (ylim[1] - ylim[0]) * 0.02,
            "first arrival - min period / 2",
            verticalalignment="bottom",
            horizontalalignment="right",
            color="#ee6e00",
            path_effects=[
                PathEffects.withStroke(linewidth=3, foreground="white")
            ],
        )

        for velocity in [6, 5, 4, 3, min_velocity]:
            tt = dist_in_km / velocity
            plt.vlines(tt, ylim[0], ylim[1], colors="gray", lw=2)
            if velocity == min_velocity:
                hal = "right"
                o_s = -1.0 * offset
            else:
                hal = "left"
                o_s = offset
            plt.text(
                tt + o_s,
                ylim[0] + (ylim[1] - ylim[0]) * 0.02,
                str(velocity) + " km/s",
                verticalalignment="bottom",
                horizontalalignment=hal,
                color="0.15",
            )
        plt.vlines(
            dist_in_km / min_velocity + minimum_period / 2.0,
            ylim[0],
            ylim[1],
            colors="gray",
            lw=2,
        )
        plt.text(
            dist_in_km / min_velocity + minimum_period / 2.0 - offset,
            ylim[1] - (ylim[1] - ylim[0]) * 0.02,
            "min surface velocity + min period / 2",
            verticalalignment="top",
            horizontalalignment="right",
            color="0.15",
            path_effects=[
                PathEffects.withStroke(linewidth=3, foreground="white")
            ],
        )

        plt.hlines(
            noise_absolute, xlim[0], xlim[1], linestyle="--", color="gray"
        )
        plt.hlines(
            -noise_absolute, xlim[0], xlim[1], linestyle="--", color="gray"
        )
        plt.text(
            offset,
            noise_absolute + (ylim[1] - ylim[0]) * 0.01,
            "noise level",
            verticalalignment="bottom",
            horizontalalignment="left",
            color="0.15",
            path_effects=[
                PathEffects.withStroke(linewidth=3, foreground="white")
            ],
        )
        plt.legend(
            loc="lower right", fancybox=True, framealpha=0.5, fontsize="small"
        )
        plt.gca().xaxis.set_ticklabels([])

        # Plot the basic global information.
        ax = plt.gca()
        txt = (
            "Total CC Coeff: %.4f\nAbsolute Noise: %e\nRelative Noise: %.3f"
            % (cc, noise_absolute, noise_relative,)
        )
        ax.text(
            0.01,
            0.95,
            txt,
            transform=ax.transAxes,
            fontdict=dict(fontsize="small", ha="left", va="top"),
            bbox=dict(boxstyle="round", fc="w", alpha=0.8),
        )
        plt.suptitle("Channel %s" % data_trace.id, fontsize="larger")

        # Show plot and return if not accepted.
        if accept_traces is not True:
            txt = "Rejected: %s" % (accept_traces)
            ax.text(
                0.99,
                0.95,
                txt,
                transform=ax.transAxes,
                fontdict=dict(fontsize="small", ha="right", va="top"),
                bbox=dict(boxstyle="round", fc="red", alpha=1.0),
            )
            plt.show()
    if accept_traces is not True:
        return []

    # Initialise masked arrays. The mask will be set to True where no
    # windows are chosen.
    time_windows = np.ma.ones(npts)
    time_windows.mask = False
    if plot:
        old_time_windows = time_windows.copy()

    # Elimination Stage 1: Eliminate everything half a period before or
    # after the minimum and maximum travel times, respectively.
    # theoretical arrival as positive.
    # Account for delays in the source time functions as well
    min_idx = first_tt_arrival - int(minimum_period / dt)
    min_idx = max(0, min_idx)

    if global_inversion:
        max_idx = len(synth)
    else:
        stf_env = obspy.signal.filter.envelope(stf_trace)
        max_env_amplitude_idx = np.argmax(stf_env.data)
        threshold = 0.5 * np.max(stf_env.data)
        max_idx = int(
            math.ceil((dist_in_km / min_velocity + minimum_period / 2.0) / dt)
        )
        max_idx += int(
            np.argmax(stf_env[max_env_amplitude_idx:] < threshold)
            + np.argmax(stf_env.data)
        )

    if window_everything and accept_traces is True:
        windows = [(data_starttime + dt * min_idx,
                    data_starttime + max_idx * dt, 1.0)]
        return windows

    time_windows.mask[: min_idx + 1] = True
    time_windows.mask[max_idx:] = True

    if plot:
        plt.subplot2grid(grid, (8, 0), rowspan=1)
        _plot_mask(
            time_windows, old_time_windows, name="TRAVELTIME ELIMINATION"
        )
        old_time_windows = time_windows.copy()

    # -------------------------------------------------------------------------
    # Compute sliding time shifts and correlation coefficients for time
    # frames that passed the traveltime elimination stage.
    # -------------------------------------------------------------------------
    # Allocate arrays to collect the time dependent values.
    sliding_time_shift = np.ma.zeros(npts, dtype="float32")
    sliding_time_shift.mask = True
    max_cc_coeff = np.ma.zeros(npts, dtype="float32")
    max_cc_coeff.mask = True

    # Compute the amount of indices by which to shift the sliding windows
    # for long seismograms this otherwise gets unnecessarily expensive
    window_shift = int(0.05 * window_length)
    if not window_shift % 2:
        window_shift += 1
    window_shift = max(window_shift, 1)

    for start_idx, end_idx, midpoint_idx in _window_generator(
        npts, window_length, window_shift
    ):
        if not min_idx < midpoint_idx < max_idx:
            continue

        # Slice windows. Create a copy to be able to taper without affecting
        # the original time series.
        data_window = data[start_idx:end_idx].copy() * taper
        synthetic_window = synth[start_idx:end_idx].copy() * taper

        # Elimination Stage 2: Skip windows that have essentially no energy
        # to avoid instabilities. No windows can be picked in these.
        sw_start_idx = int(midpoint_idx - ((window_shift - 1) / 2))
        sw_end_idx = int(midpoint_idx + ((window_shift - 1) / 2) + 1)

        if synthetic_window.ptp() < synth.ptp() * 0.001:
            time_windows.mask[sw_start_idx:sw_end_idx] = True
            continue

        # Calculate the time shift. Here this is defined as the shift of the
        # synthetics relative to the data. So a value of 2, for instance, means
        # that the synthetics are 2 timesteps later then the data.
        cc = np.correlate(data_window, synthetic_window, mode="full")

        time_shift = cc.argmax() - window_length + 1
        # Express the time shift in fraction of the minimum period.
        sliding_time_shift[sw_start_idx:sw_end_idx] = (
            time_shift * dt
        ) / minimum_period

        # Normalized cross correlation.
        max_cc_value = cc.max() / np.sqrt(
            (synthetic_window ** 2).sum() * (data_window ** 2).sum()
        )
        max_cc_coeff[sw_start_idx:sw_end_idx] = max_cc_value

    if plot:
        plt.subplot2grid(grid, (9, 0), rowspan=1)
        _plot_mask(
            time_windows, old_time_windows, name="NO ENERGY IN CC WINDOW"
        )
        # Axes with the CC coeffs
        plt.subplot2grid(grid, (15, 0), rowspan=4)
        plt.hlines(0, xlim[0], xlim[1], color="lightgray")
        plt.hlines(
            -threshold_shift, xlim[0], xlim[1], color="gray", linestyle="--"
        )
        plt.hlines(
            threshold_shift, xlim[0], xlim[1], color="gray", linestyle="--"
        )
        plt.text(
            5,
            -threshold_shift - (2) * 0.03,
            "threshold",
            verticalalignment="top",
            horizontalalignment="left",
            color="0.15",
            path_effects=[
                PathEffects.withStroke(linewidth=3, foreground="white")
            ],
        )
        plt.plot(
            times,
            sliding_time_shift,
            color="#377eb8",
            label="Time shift in fraction of minimum period",
            lw=1.5,
        )
        ylim = plt.ylim()
        plt.yticks([-0.75, 0, 0.75])
        plt.xticks([300, 600, 900, 1200, 1500, 1800])
        plt.ylim(ylim[0], ylim[1] + ylim[1] - ylim[0])
        plt.ylim(-1.0, 1.0)
        plt.xlim(xlim)
        plt.gca().xaxis.set_ticklabels([])
        plt.legend(
            loc="lower right", fancybox=True, framealpha=0.5, fontsize="small"
        )

        plt.subplot2grid(grid, (10, 0), rowspan=4)
        plt.hlines(
            threshold_correlation,
            xlim[0],
            xlim[1],
            color="0.15",
            linestyle="--",
        )
        plt.hlines(1, xlim[0], xlim[1], color="lightgray")
        plt.hlines(0, xlim[0], xlim[1], color="lightgray")
        plt.text(
            5,
            threshold_correlation + (1.4) * 0.01,
            "threshold",
            verticalalignment="bottom",
            horizontalalignment="left",
            color="0.15",
            path_effects=[
                PathEffects.withStroke(linewidth=3, foreground="white")
            ],
        )
        plt.plot(
            times,
            max_cc_coeff,
            color="#4daf4a",
            label="Maximum CC coefficient",
            lw=1.5,
        )
        plt.ylim(-0.2, 1.2)
        plt.yticks([0, 0.5, 1])
        plt.xticks([300, 600, 900, 1200, 1500, 1800])
        plt.xlim(xlim)
        plt.gca().xaxis.set_ticklabels([])
        plt.legend(
            loc="lower right", fancybox=True, framealpha=0.5, fontsize="small"
        )

    # Elimination Stage 3: Mark all areas where the normalized cross
    # correlation coefficient is under threshold_correlation as negative
    if plot:
        old_time_windows = time_windows.copy()
    time_windows.mask[max_cc_coeff < threshold_correlation] = True
    if plot:
        plt.subplot2grid(grid, (14, 0), rowspan=1)
        _plot_mask(
            time_windows,
            old_time_windows,
            name="CORRELATION COEFF THRESHOLD ELIMINATION",
        )

    # Elimination Stage 4: Mark everything with an absolute travel time
    # shift of more than # threshold_shift times the dominant period as
    # negative
    if plot:
        old_time_windows = time_windows.copy()
    time_windows.mask[np.ma.abs(sliding_time_shift) > threshold_shift] = True
    if plot:
        plt.subplot2grid(grid, (19, 0), rowspan=1)
        _plot_mask(
            time_windows,
            old_time_windows,
            name="TIME SHIFT THRESHOLD ELIMINATION",
        )

    # Elimination Stage 5: Mark the area around every "travel time shift
    # jump" (based on the traveltime time difference) negative. The width of
    # the area is currently chosen to be a tenth of a dominant period to
    # each side.
    if plot:
        old_time_windows = time_windows.copy()
    sample_buffer = int(np.ceil(minimum_period / dt * 0.1))
    indices = np.ma.where(np.ma.abs(np.ma.diff(sliding_time_shift)) > 0.1)[0]
    for index in indices:
        time_windows.mask[index - sample_buffer : index + sample_buffer] = True
    if plot:
        plt.subplot2grid(grid, (20, 0), rowspan=1)
        _plot_mask(
            time_windows, old_time_windows, name="TIME SHIFT JUMPS ELIMINATION"
        )

    # Clip both to avoid large numbers by division.
    stacked = np.vstack(
        [
            np.ma.clip(
                synth_env,
                synth_env.max() * min_envelope_similarity * 0.5,
                synth_env.max(),
            ),
            np.ma.clip(
                data_env,
                data_env.max() * min_envelope_similarity * 0.5,
                data_env.max(),
            ),
        ]
    )
    # Ratio.
    ratio = stacked.min(axis=0) / stacked.max(axis=0)

    # Elimination Stage 6: Make sure the amplitudes of both don't vary too
    # much.
    if plot:
        old_time_windows = time_windows.copy()
    time_windows.mask[ratio < min_envelope_similarity] = True
    if plot:
        plt.subplot2grid(grid, (25, 0), rowspan=1)
        _plot_mask(
            time_windows,
            old_time_windows,
            name="ENVELOPE AMPLITUDE SIMILARITY ELIMINATION",
        )

    if plot:
        plt.subplot2grid(grid, (21, 0), rowspan=4)
        plt.hlines(
            min_envelope_similarity,
            xlim[0],
            xlim[1],
            color="gray",
            linestyle="--",
        )
        plt.text(
            5,
            min_envelope_similarity + (2) * 0.03,
            "threshold",
            verticalalignment="bottom",
            horizontalalignment="left",
            color="0.15",
            path_effects=[
                PathEffects.withStroke(linewidth=3, foreground="white")
            ],
        )
        plt.plot(
            times,
            ratio,
            color="#9B59B6",
            label="Envelope amplitude similarity",
            lw=1.5,
        )
        plt.yticks([0, 0.2, 0.4, 0.6, 0.8, 1.0])
        plt.ylim(0.05, 1.05)
        plt.xticks([300, 600, 900, 1200, 1500, 1800])
        plt.xlim(xlim)
        plt.gca().xaxis.set_ticklabels([])
        plt.legend(
            loc="lower right", fancybox=True, framealpha=0.5, fontsize="small"
        )

    # First minimum window length elimination stage. This is cheap and if
    # not done it can easily destabilize the peak-and-trough marching stage
    # which would then have to deal with way more edge cases.
    if plot:
        old_time_windows = time_windows.copy()
    min_length = min(
        minimum_period / dt * min_length_period, maximum_period / dt
    )
    for i in flatnotmasked_contiguous(time_windows):
        # Step 7: Throw away all windows with a length of less then
        # min_length_period the dominant period.
        if (i.stop - i.start) < min_length:
            time_windows.mask[i.start : i.stop] = True
    if plot:
        plt.subplot2grid(grid, (26, 0), rowspan=1)
        _plot_mask(
            time_windows,
            old_time_windows,
            name="MINIMUM WINDOW LENGTH ELIMINATION 1",
        )

    # -------------------------------------------------------------------------
    # Peak and trough marching algorithm
    # -------------------------------------------------------------------------
    final_windows = []
    for i in flatnotmasked_contiguous(time_windows):
        # Cut respective windows.
        window_npts = i.stop - i.start
        synthetic_window = synth[i.start : i.stop]
        data_window = data[i.start : i.stop]

        # Find extrema in the data and the synthetics.
        data_p, data_t = find_local_extrema(data_window)
        synth_p, synth_t = find_local_extrema(synthetic_window)

        window_mask = np.ones(window_npts, dtype="bool")

        # sometimes, no local extrema are found and the below fails
        # in that case dont crash, but return the windows that did not fail.
        try:
            closest_peaks = find_closest(data_p, synth_p)
            diffs = np.diff(closest_peaks)

            for idx in np.where(diffs == 1)[0]:
                if idx > 0:
                    start = synth_p[idx - 1]
                else:
                    start = 0
                if idx < (len(synth_p) - 1):
                    end = synth_p[idx + 1]
                else:
                    end = -1
                window_mask[start:end] = False

            closest_troughs = find_closest(data_t, synth_t)
            diffs = np.diff(closest_troughs)

            for idx in np.where(diffs == 1)[0]:
                if idx > 0:
                    start = synth_t[idx - 1]
                else:
                    start = 0
                if idx < (len(synth_t) - 1):
                    end = synth_t[idx + 1]
                else:
                    end = -1
                window_mask[start:end] = False
        except Exception as e:
            print(e)
            continue

        window_mask = np.ma.masked_array(window_mask, mask=window_mask)

        if window_mask.mask.all():
            continue

        for j in flatnotmasked_contiguous(window_mask):
            final_windows.append((i.start + j.start, i.start + j.stop))

    if plot:
        old_time_windows = time_windows.copy()
    time_windows.mask[:] = True
    for start, stop in final_windows:
        time_windows.mask[start:stop] = False
    if plot:
        plt.subplot2grid(grid, (27, 0), rowspan=1)
        _plot_mask(
            time_windows,
            old_time_windows,
            name="PEAK AND TROUGH MARCHING ELIMINATION",
        )

    # Loop through all the time windows, remove windows not satisfying the
    # minimum number of peaks and troughs per window. Acts mainly as a
    # safety guard.
    old_time_windows = time_windows.copy()
    for i in flatnotmasked_contiguous(old_time_windows):
        synthetic_window = synth[i.start : i.stop]
        data_window = data[i.start : i.stop]
        data_p, data_t = find_local_extrema(data_window)
        synth_p, synth_t = find_local_extrema(synthetic_window)
        if (
            np.min([len(synth_p), len(synth_t), len(data_p), len(data_t)])
            < min_peaks_troughs
        ):
            time_windows.mask[i.start : i.stop] = True
    if plot:
        plt.subplot2grid(grid, (28, 0), rowspan=1)
        _plot_mask(
            time_windows,
            old_time_windows,
            name="PEAK/TROUGH COUNT ELIMINATION",
        )

    # Second minimum window length elimination stage.
    if plot:
        old_time_windows = time_windows.copy()
    min_length = min(
        minimum_period / dt * min_length_period, maximum_period / dt
    )
    for i in flatnotmasked_contiguous(time_windows):
        # Step 7: Throw away all windows with a length of less then
        # min_length_period the dominant period.
        if (i.stop - i.start) < min_length:
            time_windows.mask[i.start : i.stop] = True
    if plot:
        plt.subplot2grid(grid, (29, 0), rowspan=1)
        _plot_mask(
            time_windows,
            old_time_windows,
            name="MINIMUM WINDOW LENGTH ELIMINATION 2",
        )

    # Final step, eliminating windows with little energy.
    final_windows = []
    for j in flatnotmasked_contiguous(time_windows):
        # Again assert a certain minimal length.
        if (j.stop - j.start) < min_length:
            continue

        # Compare the energy in the data window and the synthetic window.
        data_energy = (data[j.start : j.stop] ** 2).sum()
        synth_energy = (synth[j.start : j.stop] ** 2).sum()
        energies = sorted([data_energy, synth_energy])
        if energies[1] > max_energy_ratio * energies[0]:
            if verbose:
                _log_window_selection(
                    data_trace.id,
                    "Deselecting window due to energy ratio between "
                    "data and synthetics.",
                )
            continue

        # Check that amplitudes in the data are above the noise
        if noise_absolute / data[j.start : j.stop].ptp() > max_noise_window:
            if verbose:
                _log_window_selection(
                    data_trace.id,
                    "Deselecting window due having no amplitude above the "
                    "signal to noise ratio.",
                )
        final_windows.append((j.start, j.stop))

    if plot:
        old_time_windows = time_windows.copy()
    time_windows.mask[:] = True
    for start, stop in final_windows:
        time_windows.mask[start:stop] = False

    if plot:
        plt.subplot2grid(grid, (30, 0), rowspan=1)
        _plot_mask(
            time_windows, old_time_windows, name="LITTLE ENERGY ELIMINATION"
        )

    if verbose:
        _log_window_selection(
            data_trace.id, "Done, Selected %i window(s)" % len(final_windows)
        )

    # Final step is to convert the index value windows to actual times.
    windows = []
    for start, stop in final_windows:
        start = data_starttime + start * data_delta
        stop = data_starttime + stop * data_delta
        weight = 1.0
        windows.append((start, stop, weight))

    if plot:
        # Plot the final windows to the data axes.
        import matplotlib.transforms as mtransforms  # NOQA

        ax = data_plot
        trans = mtransforms.blended_transform_factory(
            ax.transData, ax.transAxes
        )
        for start, stop in final_windows:
            ax.fill_between(
                [start * data_delta, stop * data_delta],
                0,
                1,
                facecolor="#CDDC39",
                alpha=0.5,
                transform=trans,
            )

        plt.show()

    return windows
示例#8
0
    def test_calc_vincenty_inverse_tabulated(self):
        """ Tabulated results for Vincenty Inverse

        Table II of Vincenty's paper (T. Vincenty 1975, "Direct and inverse
        solutions of geodesics on the ellipsoid with application of nested
        equations" Survey Review XXII pp.88-93) has five test examples for
        the forward and inverse problem (with results rounded to 0.00001
        seconds of arc and 1 mm). The inverse versions of these are implemented
        here. Note the non-standard (old) ellipsoid usage. Here we test that
        we match these examples for the inverse problem. """
        # Row "A"
        # NB: for this case there seems to be a typo in
        #     the tabulated data. Tabulated data is commented
        #     out and values from geographiclib are used in their place
        # dist = 14110526.170
        dist = 14039003.954192352
        # azi1 = dms2dec(96.0, 36.0, 8.79960)
        azi1 = 95.88145755849257
        # azi2 = dms2dec(137.0, 52.0, 22.01454)
        azi2 = 138.30481836546775
        bazi = azi2 + 180.0
        lat1 = dms2dec(55.0, 45.0, 0.0)
        lat2 = dms2dec(-33.0, 26.0, 0.0)
        lon2 = dms2dec(108.0, 13.0, 0.0)
        a = 6377397.155
        f = 1.0 / 299.1528128
        calc_dist, calc_azi1, calc_bazi = calc_vincenty_inverse(
            lat1, 0.0, lat2, lon2, a, f)
        self.assertAlmostEqual(dist, calc_dist, 2)
        self.assertAlmostEqual(azi1, calc_azi1, 5)
        self.assertAlmostEqual(bazi, calc_bazi, 5)

        # Row "B"
        dist = 4085966.703
        azi1 = dms2dec(95.0, 27.0, 59.63089)
        azi2 = dms2dec(118, 5.0, 58.96161)
        bazi = azi2 + 180.0
        lat1 = dms2dec(37.0, 19.0, 54.95367)
        lat2 = dms2dec(26.0, 7.0, 42.83946)
        lon2 = dms2dec(41.0, 28.0, 35.50729)
        a = 6378388.000
        f = 1.0 / 297.0
        calc_dist, calc_azi1, calc_bazi = calc_vincenty_inverse(
            lat1, 0.0, lat2, lon2, a, f)
        self.assertAlmostEqual(dist, calc_dist, 2)
        self.assertAlmostEqual(azi1, calc_azi1, 5)
        self.assertAlmostEqual(bazi, calc_bazi, 5)

        # Row "C"
        dist = 8084823.839
        azi1 = dms2dec(15.0, 44.0, 23.74850)
        azi2 = dms2dec(144.0, 55.0, 39.92147)
        bazi = azi2 + 180.0
        lat1 = dms2dec(35.0, 16.0, 11.24862)
        lat2 = dms2dec(67.0, 22.0, 14.77638)
        lon2 = dms2dec(137.0, 47.0, 28.31435)
        a = 6378388.000
        f = 1.0 / 297.0
        calc_dist, calc_azi1, calc_bazi = calc_vincenty_inverse(
            lat1, 0.0, lat2, lon2, a, f)
        self.assertAlmostEqual(dist, calc_dist, 2)
        self.assertAlmostEqual(azi1, calc_azi1, 5)
        self.assertAlmostEqual(bazi, calc_bazi, 5)
示例#9
0
s_pick_time = []
window = []
channel_list = []

# selecting events within distance threshold
cntEv=0
f = open(eventFileOut,'w')
outStr=('year,month,day,hour,minute,second,magnitude,latitude,longitude,id\n')
f.write(outStr)
for ev_num, event_id in enumerate(df_event.id):
#    print(event_id + ' (' + str(ev_num + 1) + '/' + str(len(df_event.id)) + ')')
    lonEv=df_event.longitude[ev_num]
    latEv=df_event.latitude[ev_num]
    magEv=df_event.magnitude[ev_num]
#    calc_vincenty_inverse(lat1, lon1, lat2, lon2, a=6378137.0, f=0.0033528106647474805)[source]
    dist_m,az,baz=calc_vincenty_inverse(latEv, lonEv, latCenter, lonCenter, a=6378137.0, f=0.0033528106647474805)
    dist_km=dist_m/1000
    if (dist_km < distEv and magEv>=minMag):
#        print('Event within distance threshold: ',dist_km,'(',lonEv,latEv,')')
#        outStr=('year,month,day,hour,minute,second,magnitude,latitude,longitude,id\n')
        outStr=(str(df_event.year[ev_num])+','+str(format2(df_event.month[ev_num]))+','+str(format2(df_event.day[ev_num]))+','+str(format2(df_event.hour[ev_num]))+','+str(format2(df_event.minute[ev_num]))+','+str(format2(df_event.second[ev_num]))+','+str(df_event.magnitude[ev_num])+','+str(df_event.latitude[ev_num])+','+str(df_event.longitude[ev_num])+','+str(df_event.id[ev_num])+'\n')
        f.write(outStr)
        cntEv +=1
# list number of events selected and close file
print('  Number of events within distance threshold of ',distEv,'km =',cntEv)
f.close()

# reference start and end times from input to parameter file
# first-available data is from event 20130801
#t_start = UTCDateTime('2009'+'-'+'01'+'-'+'01'+'T00:00:00.000')
t_start = UTCDateTime('2013'+'-'+'08'+'-'+'01'+'T00:00:00.000')
示例#10
0
# Read station data
with open("STATIONS") as f:
    for line in f:
        sta, net, sta_lat, sta_lon, _, _ = line.split()
        sta_lat = float(sta_lat)
        sta_lon = float(sta_lon)
        break


# In[5]:


# Read synthetic data
synts = obspy.read("seis/AA.A0001.MX*.sem.sac")
# Calculate distance, azimuth, backazimuth
dist_m, az, baz = calc_vincenty_inverse(event_lat, event_lon, sta_lat, sta_lon)
# Rotate seismograms
synts.rotate("NE->RT", back_azimuth=baz)
# Select transverse component and bandpass filter 40-250 s
synt = synts.select(channel="*T")[0]
synt.filter("bandpass", freqmin=1.0/250, freqmax=1.0/40, zerophase=True)
# Copy synt trace to get "observed" data
obsd = synt.copy()
# "observed" data is shifted by 3 seconds and have 0.9 amplitude of the synt
shift = int(round(3.0/synt.stats.delta))
obsd.data[:-shift] = obsd.data[shift:]
obsd.data[-shift:] = 0
obsd.data *= 0.9

# Plot the data
fig, ax = plt.subplots(figsize=(20, 5))
示例#11
0
    def test_calc_vincenty_inverse_tabulated(self):
        """ Tabulated results for Vincenty Inverse

        Table II of Vincenty's paper (T. Vincenty 1975, "Direct and inverse
        solutions of geodesics on the ellipsoid with application of nested
        equations" Survey Review XXII pp.88-93) has five test examples for
        the forward and inverse problem (with results rounded to 0.00001
        seconds of arc and 1 mm). The inverse versions of these are implemented
        here. Note the non-standard (old) ellipsoid usage. Here we test that
        we match these examples for the inverse problem. """
        # Row "A"
        # NB: for this case there seems to be a typo in
        #     the tabulated data. Tabulated data is commented
        #     out and values from geographiclib are used in their place
        # dist = 14110526.170
        dist = 14039003.954192352
        # azi1 = dms2dec(96.0, 36.0, 8.79960)
        azi1 = 95.88145755849257
        # azi2 = dms2dec(137.0, 52.0, 22.01454)
        azi2 = 138.30481836546775
        bazi = azi2 + 180.0
        lat1 = dms2dec(55.0, 45.0, 0.0)
        lat2 = dms2dec(-33.0, 26.0, 0.0)
        lon2 = dms2dec(108.0, 13.0, 0.0)
        a = 6377397.155
        f = 1.0/299.1528128
        calc_dist, calc_azi1, calc_bazi = calc_vincenty_inverse(
            lat1, 0.0, lat2, lon2, a, f)
        self.assertAlmostEqual(dist, calc_dist, 2)
        self.assertAlmostEqual(azi1, calc_azi1, 5)
        self.assertAlmostEqual(bazi, calc_bazi, 5)

        # Row "B"
        dist = 4085966.703
        azi1 = dms2dec(95.0, 27.0, 59.63089)
        azi2 = dms2dec(118, 5.0, 58.96161)
        bazi = azi2 + 180.0
        lat1 = dms2dec(37.0, 19.0, 54.95367)
        lat2 = dms2dec(26.0, 7.0, 42.83946)
        lon2 = dms2dec(41.0, 28.0, 35.50729)
        a = 6378388.000
        f = 1.0/297.0
        calc_dist, calc_azi1, calc_bazi = calc_vincenty_inverse(
            lat1, 0.0, lat2, lon2, a, f)
        self.assertAlmostEqual(dist, calc_dist, 2)
        self.assertAlmostEqual(azi1, calc_azi1, 5)
        self.assertAlmostEqual(bazi, calc_bazi, 5)

        # Row "C"
        dist = 8084823.839
        azi1 = dms2dec(15.0, 44.0, 23.74850)
        azi2 = dms2dec(144.0, 55.0, 39.92147)
        bazi = azi2 + 180.0
        lat1 = dms2dec(35.0, 16.0, 11.24862)
        lat2 = dms2dec(67.0, 22.0, 14.77638)
        lon2 = dms2dec(137.0, 47.0, 28.31435)
        a = 6378388.000
        f = 1.0/297.0
        calc_dist, calc_azi1, calc_bazi = calc_vincenty_inverse(
            lat1, 0.0, lat2, lon2, a, f)
        self.assertAlmostEqual(dist, calc_dist, 2)
        self.assertAlmostEqual(azi1, calc_azi1, 5)
        self.assertAlmostEqual(bazi, calc_bazi, 5)
示例#12
0
def select_windows(data_trace, synthetic_trace, event_latitude,
                   event_longitude, event_depth_in_km,
                   station_latitude, station_longitude, minimum_period,
                   maximum_period,
                   min_cc=0.10, max_noise=0.10, max_noise_window=0.4,
                   min_velocity=2.4, threshold_shift=0.30,
                   threshold_correlation=0.75, min_length_period=1.5,
                   min_peaks_troughs=2, max_energy_ratio=10.0,
                   min_envelope_similarity=0.2,
                   verbose=False, plot=False):
    """
    Window selection algorithm for picking windows suitable for misfit
    calculation based on phase differences.

    Returns a list of windows which might be empty due to various reasons.

    This function is really long and a lot of things. For a more detailed
    description, please see the LASIF paper.

    :param data_trace: The data trace.
    :type data_trace: :class:`~obspy.core.trace.Trace`
    :param synthetic_trace: The synthetic trace.
    :type synthetic_trace: :class:`~obspy.core.trace.Trace`
    :param event_latitude: The event latitude.
    :type event_latitude: float
    :param event_longitude: The event longitude.
    :type event_longitude: float
    :param event_depth_in_km: The event depth in km.
    :type event_depth_in_km: float
    :param station_latitude: The station latitude.
    :type station_latitude: float
    :param station_longitude: The station longitude.
    :type station_longitude: float
    :param minimum_period: The minimum period of the data in seconds.
    :type minimum_period: float
    :param maximum_period: The maximum period of the data in seconds.
    :type maximum_period: float
    :param min_cc: Minimum normalised correlation coefficient of the
        complete traces.
    :type min_cc: float
    :param max_noise: Maximum relative noise level for the whole trace.
        Measured from maximum amplitudes before and after the first arrival.
    :type max_noise: float
    :param max_noise_window: Maximum relative noise level for individual
        windows.
    :type max_noise_window: float
    :param min_velocity: All arrivals later than those corresponding to the
        threshold velocity [km/s] will be excluded.
    :type min_velocity: float
    :param threshold_shift: Maximum allowable time shift within a window,
        as a fraction of the minimum period.
    :type threshold_shift: float
    :param threshold_correlation: Minimum normalised correlation coeeficient
        within a window.
    :type threshold_correlation: float
    :param min_length_period: Minimum length of the time windows relative to
        the minimum period.
    :type min_length_period: float
    :param min_peaks_troughs: Minimum number of extrema in an individual
        time window (excluding the edges).
    :type min_peaks_troughs: float
    :param max_energy_ratio: Maximum energy ratio between data and
        synthetics within a time window. Don't make this too small!
    :type max_energy_ratio: float
    :param min_envelope_similarity: The minimum similarity of the envelopes of
        both data and synthetics. This essentially assures that the
        amplitudes of data and synthetics can not diverge too much within a
        window. It is a bit like the inverse of the ratio of both envelopes
        so a value of 0.2 makes sure neither amplitude can be more then 5
        times larger than the other.
    :type min_envelope_similarity: float
    :param verbose: No output by default.
    :type verbose: bool
    :param plot: Create a plot of the algortihm while it does its work.
    :type plot: bool
    """
    # Shortcuts to frequently accessed variables.
    data_starttime = data_trace.stats.starttime
    data_delta = data_trace.stats.delta
    dt = data_trace.stats.delta
    npts = data_trace.stats.npts
    synth = synthetic_trace.data
    data = data_trace.data
    times = data_trace.times()

    # Fill cache if necessary.
    if not TAUPY_MODEL_CACHE:
        from obspy.taup import TauPyModel  # NOQA
        TAUPY_MODEL_CACHE["model"] = TauPyModel("AK135")
    model = TAUPY_MODEL_CACHE["model"]

    # -------------------------------------------------------------------------
    # Geographical calculations and the time of the first arrival.
    # -------------------------------------------------------------------------
    dist_in_deg = geodetics.locations2degrees(station_latitude,
                                              station_longitude,
                                              event_latitude, event_longitude)
    dist_in_km = geodetics.calc_vincenty_inverse(
        station_latitude, station_longitude, event_latitude,
        event_longitude)[0] / 1000.0

    # Get only a couple of P phases which should be the first arrival
    # for every epicentral distance. Its quite a bit faster than calculating
    # the arrival times for every phase.
    # Assumes the first sample is the centroid time of the event.
    tts = model.get_travel_times(source_depth_in_km=event_depth_in_km,
                                 distance_in_degree=dist_in_deg,
                                 phase_list=["ttp"])
    # Sort just as a safety measure.
    tts = sorted(tts, key=lambda x: x.time)
    first_tt_arrival = tts[0].time

    # -------------------------------------------------------------------------
    # Window settings
    # -------------------------------------------------------------------------
    # Number of samples in the sliding window. Currently, the length of the
    # window is set to a multiple of the dominant period of the synthetics.
    # Make sure it is an uneven number; just to have a trivial midpoint
    # definition and one sample does not matter much in any case.
    window_length = int(round(float(2 * minimum_period) / dt))
    if not window_length % 2:
        window_length += 1

    # Use a Hanning window. No particular reason for it but its a well-behaved
    # window and has nice spectral properties.
    taper = np.hanning(window_length)

    # =========================================================================
    # check if whole seismograms are sufficiently correlated and estimate
    # noise level
    # =========================================================================

    # Overall Correlation coefficient.
    norm = np.sqrt(np.sum(data ** 2)) * np.sqrt(np.sum(synth ** 2))
    cc = np.sum(data * synth) / norm
    if verbose:
        _log_window_selection(data_trace.id,
                              "Correlation Coefficient: %.4f" % cc)

    # Estimate noise level from waveforms prior to the first arrival.
    idx_end = int(np.ceil((first_tt_arrival - 0.5 * minimum_period) / dt))
    idx_end = max(10, idx_end)
    idx_start = int(np.ceil((first_tt_arrival - 2.5 * minimum_period) / dt))
    idx_start = max(10, idx_start)

    if idx_start >= idx_end:
        idx_start = max(0, idx_end - 10)

    abs_data = np.abs(data)
    noise_absolute = abs_data[idx_start:idx_end].max()
    noise_relative = noise_absolute / abs_data.max()

    if verbose:
        _log_window_selection(data_trace.id,
                              "Absolute Noise Level: %e" % noise_absolute)
        _log_window_selection(data_trace.id,
                              "Relative Noise Level: %e" % noise_relative)

    # Basic global rejection criteria.
    accept_traces = True
    if (cc < min_cc) and (noise_relative > max_noise / 3.0):
        msg = "Correlation %.4f is below threshold of %.4f" % (cc, min_cc)
        if verbose:
            _log_window_selection(data_trace.id, msg)
        accept_traces = msg

    if noise_relative > max_noise:
        msg = "Noise level %.3f is above threshold of %.3f" % (
            noise_relative, max_noise)
        if verbose:
            _log_window_selection(
                data_trace.id, msg)
        accept_traces = msg

    # Calculate the envelope of both data and synthetics. This is to make sure
    # that the amplitude of both is not too different over time and is
    # used as another selector. Only calculated if the trace is generally
    # accepted as it is fairly slow.
    if accept_traces is True:
        data_env = obspy.signal.filter.envelope(data)
        synth_env = obspy.signal.filter.envelope(synth)

    # -------------------------------------------------------------------------
    # Initial Plot setup.
    # -------------------------------------------------------------------------
    # All the plot calls are interleaved. I realize this is really ugly but
    # the alternative would be to either have two functions (one with plots,
    # one without) or split the plotting function in various subfunctions,
    # neither of which are acceptable in my opinion. The impact on
    # performance is minimal if plotting is turned off: all imports are lazy
    # and a couple of conditionals are cheap.
    if plot:
        import matplotlib.pylab as plt  # NOQA
        import matplotlib.patheffects as PathEffects  # NOQA

        if accept_traces is True:
            plt.figure(figsize=(18, 12))
            plt.subplots_adjust(left=0.05, bottom=0.05, right=0.98, top=0.95,
                                wspace=None, hspace=0.0)
            grid = (31, 1)

            # Axes showing the data.
            data_plot = plt.subplot2grid(grid, (0, 0), rowspan=8)
        else:
            # Only show one axes it the traces are not accepted.
            plt.figure(figsize=(18, 3))

        # Plot envelopes if needed.
        if accept_traces is True:
            plt.plot(times, data_env, color="black", alpha=0.5, lw=0.4,
                     label="data envelope")
            plt.plot(synthetic_trace.times(), synth_env, color="#e41a1c",
                     alpha=0.4, lw=0.5, label="synthetics envelope")

        plt.plot(times, data, color="black", label="data", lw=1.5)
        plt.plot(synthetic_trace.times(), synth, color="#e41a1c",
                 label="synthetics",  lw=1.5)

        # Symmetric around y axis.
        middle = data.mean()
        d_max, d_min = data.max(), data.min()
        r = max(d_max - middle, middle - d_min) * 1.1
        ylim = (middle - r, middle + r)
        xlim = (times[0], times[-1])
        plt.ylim(*ylim)
        plt.xlim(*xlim)

        offset = (xlim[1] - xlim[0]) * 0.005
        plt.vlines(first_tt_arrival, ylim[0], ylim[1], colors="#ff7f00", lw=2)
        plt.text(first_tt_arrival + offset,
                 ylim[1] - (ylim[1] - ylim[0]) * 0.02,
                 "first arrival", verticalalignment="top",
                 horizontalalignment="left", color="#ee6e00",
                 path_effects=[
                     PathEffects.withStroke(linewidth=3, foreground="white")])

        plt.vlines(first_tt_arrival - minimum_period / 2.0, ylim[0], ylim[1],
                   colors="#ff7f00", lw=2)
        plt.text(first_tt_arrival - minimum_period / 2.0 - offset,
                 ylim[0] + (ylim[1] - ylim[0]) * 0.02,
                 "first arrival - min period / 2", verticalalignment="bottom",
                 horizontalalignment="right", color="#ee6e00",
                 path_effects=[
                     PathEffects.withStroke(linewidth=3, foreground="white")])

        for velocity in [6, 5, 4, 3, min_velocity]:
            tt = dist_in_km / velocity
            plt.vlines(tt, ylim[0], ylim[1], colors="gray", lw=2)
            if velocity == min_velocity:
                hal = "right"
                o_s = -1.0 * offset
            else:
                hal = "left"
                o_s = offset
            plt.text(tt + o_s, ylim[0] + (ylim[1] - ylim[0]) * 0.02,
                     str(velocity) + " km/s", verticalalignment="bottom",
                     horizontalalignment=hal, color="0.15")
        plt.vlines(dist_in_km / min_velocity + minimum_period / 2.0,
                   ylim[0], ylim[1], colors="gray", lw=2)
        plt.text(dist_in_km / min_velocity + minimum_period / 2.0 - offset,
                 ylim[1] - (ylim[1] - ylim[0]) * 0.02,
                 "min surface velocity + min period / 2",
                 verticalalignment="top",
                 horizontalalignment="right", color="0.15", path_effects=[
                     PathEffects.withStroke(linewidth=3, foreground="white")])

        plt.hlines(noise_absolute, xlim[0], xlim[1], linestyle="--",
                   color="gray")
        plt.hlines(-noise_absolute, xlim[0], xlim[1], linestyle="--",
                   color="gray")
        plt.text(offset, noise_absolute + (ylim[1] - ylim[0]) * 0.01,
                 "noise level", verticalalignment="bottom",
                 horizontalalignment="left", color="0.15",
                 path_effects=[
                     PathEffects.withStroke(linewidth=3, foreground="white")])
        plt.legend(loc="lower right", fancybox=True, framealpha=0.5,
                   fontsize="small")
        plt.gca().xaxis.set_ticklabels([])

        # Plot the basic global information.
        ax = plt.gca()
        txt = (
            "Total CC Coeff: %.4f\nAbsolute Noise: %e\nRelative Noise: %.3f"
            % (cc, noise_absolute, noise_relative))
        ax.text(0.01, 0.95, txt, transform=ax.transAxes,
                fontdict=dict(fontsize="small", ha='left', va='top'),
                bbox=dict(boxstyle="round", fc="w", alpha=0.8))
        plt.suptitle("Channel %s" % data_trace.id, fontsize="larger")

    # Show plot and return if not accepted.
        if accept_traces is not True:
            txt = "Rejected: %s" % (accept_traces)
            ax.text(0.99, 0.95, txt, transform=ax.transAxes,
                    fontdict=dict(fontsize="small", ha='right', va='top'),
                    bbox=dict(boxstyle="round", fc="red", alpha=1.0))
            plt.show()
    if accept_traces is not True:
        return []

    # Initialise masked arrays. The mask will be set to True where no
    # windows are chosen.
    time_windows = np.ma.ones(npts)
    time_windows.mask = False
    if plot:
        old_time_windows = time_windows.copy()

    # Elimination Stage 1: Eliminate everything half a period before or
    # after the minimum and maximum travel times, respectively.
    # theoretical arrival as positive.
    min_idx = int((first_tt_arrival - (minimum_period / 2.0)) / dt)
    max_idx = int(math.ceil((
        dist_in_km / min_velocity + minimum_period / 2.0) / dt))
    time_windows.mask[:min_idx + 1] = True
    time_windows.mask[max_idx:] = True
    if plot:
        plt.subplot2grid(grid, (8, 0), rowspan=1)
        _plot_mask(time_windows, old_time_windows,
                   name="TRAVELTIME ELIMINATION")
        old_time_windows = time_windows.copy()

    # -------------------------------------------------------------------------
    # Compute sliding time shifts and correlation coefficients for time
    # frames that passed the traveltime elimination stage.
    # -------------------------------------------------------------------------
    # Allocate arrays to collect the time dependent values.
    sliding_time_shift = np.ma.zeros(npts, dtype="float32")
    sliding_time_shift.mask = True
    max_cc_coeff = np.ma.zeros(npts, dtype="float32")
    max_cc_coeff.mask = True

    for start_idx, end_idx, midpoint_idx in _window_generator(npts,
                                                              window_length):
        if not min_idx < midpoint_idx < max_idx:
            continue

        # Slice windows. Create a copy to be able to taper without affecting
        # the original time series.
        data_window = data[start_idx: end_idx].copy() * taper
        synthetic_window = \
            synth[start_idx: end_idx].copy() * taper

        # Elimination Stage 2: Skip windows that have essentially no energy
        # to avoid instabilities. No windows can be picked in these.
        if synthetic_window.ptp() < synth.ptp() * 0.001:
            time_windows.mask[midpoint_idx] = True
            continue

        # Calculate the time shift. Here this is defined as the shift of the
        # synthetics relative to the data. So a value of 2, for instance, means
        # that the synthetics are 2 timesteps later then the data.
        cc = np.correlate(data_window, synthetic_window, mode="full")

        time_shift = cc.argmax() - window_length + 1
        # Express the time shift in fraction of the minimum period.
        sliding_time_shift[midpoint_idx] = (time_shift * dt) / minimum_period

        # Normalized cross correlation.
        max_cc_value = cc.max() / np.sqrt((synthetic_window ** 2).sum() *
                                          (data_window ** 2).sum())
        max_cc_coeff[midpoint_idx] = max_cc_value

    if plot:
        plt.subplot2grid(grid, (9, 0), rowspan=1)
        _plot_mask(time_windows, old_time_windows,
                   name="NO ENERGY IN CC WINDOW")
        # Axes with the CC coeffs
        plt.subplot2grid(grid, (15, 0), rowspan=4)
        plt.hlines(0, xlim[0], xlim[1], color="lightgray")
        plt.hlines(-threshold_shift, xlim[0], xlim[1], color="gray",
                   linestyle="--")
        plt.hlines(threshold_shift, xlim[0], xlim[1], color="gray",
                   linestyle="--")
        plt.text(5, -threshold_shift - (2) * 0.03,
                 "threshold", verticalalignment="top",
                 horizontalalignment="left", color="0.15",
                 path_effects=[
                     PathEffects.withStroke(linewidth=3, foreground="white")])
        plt.plot(times, sliding_time_shift, color="#377eb8",
                 label="Time shift in fraction of minimum period", lw=1.5)
        ylim = plt.ylim()
        plt.yticks([-0.75, 0, 0.75])
        plt.xticks([300, 600, 900, 1200, 1500, 1800])
        plt.ylim(ylim[0], ylim[1] + ylim[1] - ylim[0])
        plt.ylim(-1.0, 1.0)
        plt.xlim(xlim)
        plt.gca().xaxis.set_ticklabels([])
        plt.legend(loc="lower right", fancybox=True, framealpha=0.5,
                   fontsize="small")

        plt.subplot2grid(grid, (10, 0), rowspan=4)
        plt.hlines(threshold_correlation, xlim[0], xlim[1], color="0.15",
                   linestyle="--")
        plt.hlines(1, xlim[0], xlim[1], color="lightgray")
        plt.hlines(0, xlim[0], xlim[1], color="lightgray")
        plt.text(5, threshold_correlation + (1.4) * 0.01,
                 "threshold", verticalalignment="bottom",
                 horizontalalignment="left", color="0.15",
                 path_effects=[
                     PathEffects.withStroke(linewidth=3, foreground="white")])
        plt.plot(times, max_cc_coeff, color="#4daf4a",
                 label="Maximum CC coefficient", lw=1.5)
        plt.ylim(-0.2, 1.2)
        plt.yticks([0, 0.5, 1])
        plt.xticks([300, 600, 900, 1200, 1500, 1800])
        plt.xlim(xlim)
        plt.gca().xaxis.set_ticklabels([])
        plt.legend(loc="lower right", fancybox=True, framealpha=0.5,
                   fontsize="small")

    # Elimination Stage 3: Mark all areas where the normalized cross
    # correlation coefficient is under threshold_correlation as negative
    if plot:
        old_time_windows = time_windows.copy()
    time_windows.mask[max_cc_coeff < threshold_correlation] = True
    if plot:
        plt.subplot2grid(grid, (14, 0), rowspan=1)
        _plot_mask(time_windows, old_time_windows,
                   name="CORRELATION COEFF THRESHOLD ELIMINATION")

    # Elimination Stage 4: Mark everything with an absolute travel time
    # shift of more than # threshold_shift times the dominant period as
    # negative
    if plot:
        old_time_windows = time_windows.copy()
    time_windows.mask[np.ma.abs(sliding_time_shift) > threshold_shift] = True
    if plot:
        plt.subplot2grid(grid, (19, 0), rowspan=1)
        _plot_mask(time_windows, old_time_windows,
                   name="TIME SHIFT THRESHOLD ELIMINATION")

    # Elimination Stage 5: Mark the area around every "travel time shift
    # jump" (based on the traveltime time difference) negative. The width of
    # the area is currently chosen to be a tenth of a dominant period to
    # each side.
    if plot:
        old_time_windows = time_windows.copy()
    sample_buffer = int(np.ceil(minimum_period / dt * 0.1))
    indices = np.ma.where(np.ma.abs(np.ma.diff(sliding_time_shift)) > 0.1)[0]
    for index in indices:
        time_windows.mask[index - sample_buffer: index + sample_buffer] = True
    if plot:
        plt.subplot2grid(grid, (20, 0), rowspan=1)
        _plot_mask(time_windows, old_time_windows,
                   name="TIME SHIFT JUMPS ELIMINATION")

    # Clip both to avoid large numbers by division.
    stacked = np.vstack([
        np.ma.clip(synth_env, synth_env.max() * min_envelope_similarity * 0.5,
                   synth_env.max()),
        np.ma.clip(data_env, data_env.max() * min_envelope_similarity * 0.5,
                   data_env.max())])
    # Ratio.
    ratio = stacked.min(axis=0) / stacked.max(axis=0)

    # Elimination Stage 6: Make sure the amplitudes of both don't vary too
    # much.
    if plot:
        old_time_windows = time_windows.copy()
    time_windows.mask[ratio < min_envelope_similarity] = True
    if plot:
        plt.subplot2grid(grid, (25, 0), rowspan=1)
        _plot_mask(time_windows, old_time_windows,
                   name="ENVELOPE AMPLITUDE SIMILARITY ELIMINATION")

    if plot:
        plt.subplot2grid(grid, (21, 0), rowspan=4)
        plt.hlines(min_envelope_similarity, xlim[0], xlim[1], color="gray",
                   linestyle="--")
        plt.text(5, min_envelope_similarity + (2) * 0.03,
                 "threshold", verticalalignment="bottom",
                 horizontalalignment="left", color="0.15",
                 path_effects=[
                 PathEffects.withStroke(linewidth=3, foreground="white")])
        plt.plot(times, ratio, color="#9B59B6",
                 label="Envelope amplitude similarity", lw=1.5)
        plt.yticks([0, 0.2, 0.4, 0.6, 0.8, 1.0])
        plt.ylim(0.05, 1.05)
        plt.xticks([300, 600, 900, 1200, 1500, 1800])
        plt.xlim(xlim)
        plt.gca().xaxis.set_ticklabels([])
        plt.legend(loc="lower right", fancybox=True, framealpha=0.5,
                   fontsize="small")

    # First minimum window length elimination stage. This is cheap and if
    # not done it can easily destabilize the peak-and-trough marching stage
    # which would then have to deal with way more edge cases.
    if plot:
        old_time_windows = time_windows.copy()
    min_length = \
        min(minimum_period / dt * min_length_period, maximum_period / dt)
    for i in flatnotmasked_contiguous(time_windows):
        # Step 7: Throw away all windows with a length of less then
        # min_length_period the dominant period.
        if (i.stop - i.start) < min_length:
            time_windows.mask[i.start: i.stop] = True
    if plot:
        plt.subplot2grid(grid, (26, 0), rowspan=1)
        _plot_mask(time_windows, old_time_windows,
                   name="MINIMUM WINDOW LENGTH ELIMINATION 1")

    # -------------------------------------------------------------------------
    # Peak and trough marching algorithm
    # -------------------------------------------------------------------------
    final_windows = []
    for i in flatnotmasked_contiguous(time_windows):
        # Cut respective windows.
        window_npts = i.stop - i.start
        synthetic_window = synth[i.start: i.stop]
        data_window = data[i.start: i.stop]

        # Find extrema in the data and the synthetics.
        data_p, data_t = find_local_extrema(data_window)
        synth_p, synth_t = find_local_extrema(synthetic_window)

        window_mask = np.ones(window_npts, dtype="bool")

        closest_peaks = find_closest(data_p, synth_p)
        diffs = np.diff(closest_peaks)

        for idx in np.where(diffs == 1)[0]:
            if idx > 0:
                start = synth_p[idx - 1]
            else:
                start = 0
            if idx < (len(synth_p) - 1):
                end = synth_p[idx + 1]
            else:
                end = -1
            window_mask[start: end] = False

        closest_troughs = find_closest(data_t, synth_t)
        diffs = np.diff(closest_troughs)

        for idx in np.where(diffs == 1)[0]:
            if idx > 0:
                start = synth_t[idx - 1]
            else:
                start = 0
            if idx < (len(synth_t) - 1):
                end = synth_t[idx + 1]
            else:
                end = -1
            window_mask[start: end] = False

        window_mask = np.ma.masked_array(window_mask,
                                         mask=window_mask)

        if window_mask.mask.all():
            continue

        for j in flatnotmasked_contiguous(window_mask):
            final_windows.append((i.start + j.start, i.start + j.stop))

    if plot:
        old_time_windows = time_windows.copy()
    time_windows.mask[:] = True
    for start, stop in final_windows:
        time_windows.mask[start:stop] = False
    if plot:
        plt.subplot2grid(grid, (27, 0), rowspan=1)
        _plot_mask(time_windows, old_time_windows,
                   name="PEAK AND TROUGH MARCHING ELIMINATION")

    # Loop through all the time windows, remove windows not satisfying the
    # minimum number of peaks and troughs per window. Acts mainly as a
    # safety guard.
    old_time_windows = time_windows.copy()
    for i in flatnotmasked_contiguous(old_time_windows):
        synthetic_window = synth[i.start: i.stop]
        data_window = data[i.start: i.stop]
        data_p, data_t = find_local_extrema(data_window)
        synth_p, synth_t = find_local_extrema(synthetic_window)
        if np.min([len(synth_p), len(synth_t), len(data_p), len(data_t)]) < \
                min_peaks_troughs:
            time_windows.mask[i.start: i.stop] = True
    if plot:
        plt.subplot2grid(grid, (28, 0), rowspan=1)
        _plot_mask(time_windows, old_time_windows,
                   name="PEAK/TROUGH COUNT ELIMINATION")

    # Second minimum window length elimination stage.
    if plot:
        old_time_windows = time_windows.copy()
    min_length = \
        min(minimum_period / dt * min_length_period, maximum_period / dt)
    for i in flatnotmasked_contiguous(time_windows):
        # Step 7: Throw away all windows with a length of less then
        # min_length_period the dominant period.
        if (i.stop - i.start) < min_length:
            time_windows.mask[i.start: i.stop] = True
    if plot:
        plt.subplot2grid(grid, (29, 0), rowspan=1)
        _plot_mask(time_windows, old_time_windows,
                   name="MINIMUM WINDOW LENGTH ELIMINATION 2")

    # Final step, eliminating windows with little energy.
    final_windows = []
    for j in flatnotmasked_contiguous(time_windows):
        # Again assert a certain minimal length.
        if (j.stop - j.start) < min_length:
            continue

        # Compare the energy in the data window and the synthetic window.
        data_energy = (data[j.start: j.stop] ** 2).sum()
        synth_energy = (synth[j.start: j.stop] ** 2).sum()
        energies = sorted([data_energy, synth_energy])
        if energies[1] > max_energy_ratio * energies[0]:
            if verbose:
                _log_window_selection(
                    data_trace.id,
                    "Deselecting window due to energy ratio between "
                    "data and synthetics.")
            continue

        # Check that amplitudes in the data are above the noise
        if noise_absolute / data[j.start: j.stop].ptp() > \
                max_noise_window:
            if verbose:
                _log_window_selection(
                    data_trace.id,
                    "Deselecting window due having no amplitude above the "
                    "signal to noise ratio.")
        final_windows.append((j.start, j.stop))

    if plot:
        old_time_windows = time_windows.copy()
    time_windows.mask[:] = True
    for start, stop in final_windows:
        time_windows.mask[start:stop] = False

    if plot:
        plt.subplot2grid(grid, (30, 0), rowspan=1)
        _plot_mask(time_windows, old_time_windows,
                   name="LITTLE ENERGY ELIMINATION")

    if verbose:
        _log_window_selection(
            data_trace.id,
            "Done, Selected %i window(s)" % len(final_windows))

    # Final step is to convert the index value windows to actual times.
    windows = []
    for start, stop in final_windows:
        start = data_starttime + start * data_delta
        stop = data_starttime + stop * data_delta
        windows.append((start, stop))

    if plot:
        # Plot the final windows to the data axes.
        import matplotlib.transforms as mtransforms  # NOQA
        ax = data_plot
        trans = mtransforms.blended_transform_factory(ax.transData,
                                                      ax.transAxes)
        for start, stop in final_windows:
            ax.fill_between([start * data_delta, stop * data_delta], 0, 1,
                            facecolor="#CDDC39", alpha=0.5, transform=trans)

        plt.show()

    return windows
示例#13
0
size_t = 100
size_amp = 0.1

stations = []
for filename in glob.glob("./seismic_data/*.HGZ.SAC"):
    tr = obspy.read(filename, format="SAC")[0]

    for _ in range(2):
        tr.detrend("demean")
        tr.detrend("linear")
        tr.taper(0.05)
        tr.integrate()

    tr_len = len(tr.data)
    tr_plot, = ax.plot([], [], "r", zorder=100, transform=ccrs.Geodetic())
    dist_m, _, _ = calc_vincenty_inverse(evla, evlo, tr.stats.sac.stla,
                                         tr.stats.sac.stlo)
    p_arrival = dist_m / 1000 / vp

    stations.append({
        "name": tr.id,
        "lat": tr.stats.sac.stla,
        "lon": tr.stats.sac.stlo,
        "trace": tr,
        "length": tr_len,
        "plot": tr_plot,
        "amp_scale": size_amp / np.abs(tr.data).max(),
        "time_scale": size_t / tr_len,
        "t_offset": p_arrival - tr.stats.sac.a,
    })

ax.scatter(
示例#14
0
 def test_calc_vincenty_inverse(self):
     """
     Tests for the Vincenty's Inverse formulae.
     """
     # the following will raise StopIteration exceptions because of two
     # nearly antipodal points
     with pytest.raises(StopIteration):
         calc_vincenty_inverse(
             15.26804251,
             2.93007342,
             -14.80522806,
             -177.2299081,
         )
     with pytest.raises(StopIteration):
         calc_vincenty_inverse(
             27.3562106,
             72.2382356,
             -27.55995499,
             -107.78571981,
         )
     with pytest.raises(StopIteration):
         calc_vincenty_inverse(
             27.4675551,
             17.28133229,
             -27.65771704,
             -162.65420626,
         )
     with pytest.raises(StopIteration):
         calc_vincenty_inverse(
             27.4675551,
             17.28133229,
             -27.65771704,
             -162.65420626,
         )
     # working examples
     res = calc_vincenty_inverse(0, 0.2, 0, 20)
     assert round(abs(res[0] - 2204125.9174282863), 7) == 0
     assert round(abs(res[1] - 90.0), 7) == 0
     assert round(abs(res[2] - 270.0), 7) == 0
     res = calc_vincenty_inverse(0, 0, 0, 10)
     assert round(abs(res[0] - 1113194.9077920639), 7) == 0
     assert round(abs(res[1] - 90.0), 7) == 0
     assert round(abs(res[2] - 270.0), 7) == 0
     res = calc_vincenty_inverse(0, 0, 0, 13)
     assert round(abs(res[0] - 1447153.3801296828), 7) == 0
     assert round(abs(res[1] - 90.0), 7) == 0
     assert round(abs(res[2] - 270.0), 7) == 0
     res = calc_vincenty_inverse(0, 0, 0, 17)
     assert round(abs(res[0] - 1892431.3432465086), 7) == 0
     assert round(abs(res[1] - 90.0), 7) == 0
     assert round(abs(res[2] - 270.0), 7) == 0
     # out of bounds
     with pytest.raises(ValueError):
         calc_vincenty_inverse(91, 0, 0, 0)
     with pytest.raises(ValueError):
         calc_vincenty_inverse(-91, 0, 0, 0)
     with pytest.raises(ValueError):
         calc_vincenty_inverse(0, 0, 91, 0)
     with pytest.raises(ValueError):
         calc_vincenty_inverse(0, 0, -91, 0)
示例#15
0
    return fig, axes, selectors


# In[10]:


dists = {}
res = plot_pick_and_find_dist(st, dists, (0, 200))
plt.show()


# In[11]:


coords = inv.get_coordinates("KO.ELL..BHZ")
dist, az, baz = calc_vincenty_inverse(coords["latitude"], coords["longitude"], origin.latitude, origin.longitude)
print("Iris çözümü için uzaklık: {:.2f} km".format(dist/1000))
print("Bulunan uzaklık: {:.2f} km".format(dists["KO.ELL..BHZ"]))


# In[12]:


def plot_find_amps(st, amps, trange=None):
    if trange is None:
        trange = [st[0].times()[0], st[0].times()[-1]]
    nsta = len(st)
    fig, axes = plt.subplots(nrows=nsta, sharex=True, figsize=(9, 2*nsta))
    st_axes = defaultdict(list)
    for i, tr in enumerate(st):
        axes[i].plot(tr.times(), tr.data, "k", label=tr.id)